directory_tree outputs JSON

This commit is contained in:
lamemind 2024-12-09 21:06:10 +01:00
commit 188cd7653c

View file

@ -376,11 +376,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
{ {
name: "directory_tree", name: "directory_tree",
description: description:
"Get a recursive tree view of files and directories starting from a specified path. " + "Get a recursive tree view of files and directories as a JSON structure. " +
"Results are formatted in a hierarchical ASCII tree structure with proper indentation " + "Each entry includes 'name', 'type' (file/directory), and 'children' for directories. " +
"using pipes and dashes (│ ├ └ ─). Files and directories are distinguished " + "Files have no children array, while directories always have a children array (which may be empty). " +
"with [F] and [D] prefixes. This tool provides a comprehensive visualization of nested " + "The output is formatted with 2-space indentation for readability. Only works within allowed directories.",
"directory structures. Only works within allowed directories.",
inputSchema: zodToJsonSchema(DirectoryTreeArgsSchema) as ToolInput, inputSchema: zodToJsonSchema(DirectoryTreeArgsSchema) as ToolInput,
}, },
{ {
@ -518,36 +517,45 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
} }
case "directory_tree": { case "directory_tree": {
const parsed = ListDirectoryArgsSchema.safeParse(args); const parsed = DirectoryTreeArgsSchema.safeParse(args);
if (!parsed.success) { if (!parsed.success) {
throw new Error(`Invalid arguments for directory_tree: ${parsed.error}`); throw new Error(`Invalid arguments for directory_tree: ${parsed.error}`);
} }
async function buildTree(currentPath: string, prefix = ""): Promise<string> { interface TreeEntry {
name: string;
type: 'file' | 'directory';
children?: TreeEntry[];
}
async function buildTree(currentPath: string): Promise<TreeEntry[]> {
const validPath = await validatePath(currentPath); const validPath = await validatePath(currentPath);
const entries = await fs.readdir(validPath, {withFileTypes: true}); const entries = await fs.readdir(validPath, {withFileTypes: true});
let result = ""; const result: TreeEntry[] = [];
for (let i = 0; i < entries.length; i++) { for (const entry of entries) {
const entry = entries[i]; const entryData: TreeEntry = {
const isLast = i === entries.length - 1; name: entry.name,
const connector = isLast ? "└── " : "├── "; type: entry.isDirectory() ? 'directory' : 'file'
const newPrefix = prefix + (isLast ? " " : "│ "); };
result += `${prefix}${connector}${entry.isDirectory() ? "[D]" : "[F]"} ${entry.name}\n`;
if (entry.isDirectory()) { if (entry.isDirectory()) {
const subPath = path.join(currentPath, entry.name); const subPath = path.join(currentPath, entry.name);
result += await buildTree(subPath, newPrefix); entryData.children = await buildTree(subPath);
} }
result.push(entryData);
} }
return result; return result;
} }
const treeOutput = await buildTree(parsed.data.path); const treeData = await buildTree(parsed.data.path);
return { return {
content: [{type: "text", text: treeOutput}], content: [{
type: "text",
text: JSON.stringify(treeData, null, 2)
}],
}; };
} }