List Workspace Contents
Lists files in skills/sauna and documents for reset preview
Source Code
import fs from "fs";
import path from "path";
const [skillsPath, documentsPath, excludeSkillId] = process.argv.slice(2);
if (!skillsPath || !documentsPath) {
console.error("Usage: skillsPath documentsPath [excludeSkillId]");
process.exit(1);
}
/**
* Recursively get all files and directories
*/
function getContents(dir) {
const results = { files: [], dirs: [], totalSize: 0 };
if (!fs.existsSync(dir)) {
return results;
}
const entries = fs.readdirSync(dir, { withFileTypes: true });
for (const entry of entries) {
const fullPath = path.join(dir, entry.name);
if (entry.isDirectory()) {
results.dirs.push(fullPath);
const subResults = getContents(fullPath);
results.files.push(...subResults.files);
results.dirs.push(...subResults.dirs);
results.totalSize += subResults.totalSize;
} else {
const stats = fs.statSync(fullPath);
results.files.push(fullPath);
results.totalSize += stats.size;
}
}
return results;
}
/**
* Format bytes to human readable
*/
function formatBytes(bytes) {
if (bytes === 0) return "0 B";
const k = 1024;
const sizes = ["B", "KB", "MB", "GB"];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
}
/**
* Get top-level items (skills or files) for summary
*/
function getTopLevelItems(dir) {
if (!fs.existsSync(dir)) {
return [];
}
return fs.readdirSync(dir);
}
try {
console.log("Scanning workspace for reset preview...\n");
// Scan skills/sauna
const skillsContents = getContents(skillsPath);
const skillItems = getTopLevelItems(skillsPath);
// Filter out the skill to preserve
let excludedSkillName = null;
if (excludeSkillId) {
// Extract skill name from ID (e.g., "skill:workspace.reset.manager" -> look for matching folder)
excludedSkillName = excludeSkillId.replace("skill:", "");
}
const skillsToDelete = skillItems.filter((item) => {
if (!excludedSkillName) return true;
// Check if this folder contains the skill we want to preserve
const skillPath = path.join(skillsPath, item);
if (fs.existsSync(skillPath) && fs.statSync(skillPath).isDirectory()) {
const files = fs.readdirSync(skillPath);
return !files.some((f) => f.includes(excludedSkillName));
}
return true;
});
// Scan documents
const documentsContents = getContents(documentsPath);
const documentItems = getTopLevelItems(documentsPath);
// Build summary
console.log("=== WORKSPACE RESET PREVIEW ===\n");
console.log("š skills/sauna:");
if (skillItems.length === 0) {
console.log(" (empty - nothing to delete)");
} else {
console.log(` ${skillsToDelete.length} skill(s) will be deleted:`);
for (const skill of skillsToDelete.slice(0, 10)) {
console.log(` - ${skill}`);
}
if (skillsToDelete.length > 10) {
console.log(` ... and ${skillsToDelete.length - 10} more`);
}
if (excludedSkillName && skillItems.length > skillsToDelete.length) {
console.log(` ā Preserving: ${excludeSkillId}`);
}
}
console.log("\nš documents:");
if (documentItems.length === 0) {
console.log(" (empty - nothing to delete)");
} else {
console.log(` ${documentItems.length} item(s) will be deleted:`);
for (const doc of documentItems.slice(0, 10)) {
console.log(` - ${doc}`);
}
if (documentItems.length > 10) {
console.log(` ... and ${documentItems.length - 10} more`);
}
}
const totalFiles = skillsContents.files.length + documentsContents.files.length;
const totalSize = skillsContents.totalSize + documentsContents.totalSize;
console.log("\nš Summary:");
console.log(` Total files: ${totalFiles}`);
console.log(` Total size: ${formatBytes(totalSize)}`);
// Output structured data for agent
console.log(
JSON.stringify({
success: true,
skills: {
path: skillsPath,
itemCount: skillsToDelete.length,
items: skillsToDelete,
preserved: excludeSkillId || null,
},
documents: {
path: documentsPath,
itemCount: documentItems.length,
items: documentItems,
},
totals: {
files: totalFiles,
sizeBytes: totalSize,
sizeHuman: formatBytes(totalSize),
},
})
);
} catch (error) {
console.error("Error scanning workspace:", error.message);
process.exit(1);
}