mirror of
https://gitea.toothfairyai.com/ToothFairyAI/tf_code.git
synced 2026-04-02 23:23:45 +00:00
sync
This commit is contained in:
96
packages/opencode/src/tool/ls.ts
Normal file
96
packages/opencode/src/tool/ls.ts
Normal file
@@ -0,0 +1,96 @@
|
||||
import { z } from "zod";
|
||||
import { Tool } from "./tool";
|
||||
import { App } from "../app/app";
|
||||
import * as path from "path";
|
||||
|
||||
const IGNORE_PATTERNS = [
|
||||
"node_modules/",
|
||||
"__pycache__/",
|
||||
".git/",
|
||||
"dist/",
|
||||
"build/",
|
||||
"target/",
|
||||
"vendor/",
|
||||
"bin/",
|
||||
"obj/",
|
||||
".idea/",
|
||||
".vscode/",
|
||||
];
|
||||
|
||||
export const ls = Tool.define({
|
||||
name: "opencode.ls",
|
||||
description: "List directory contents",
|
||||
parameters: z.object({
|
||||
path: z.string().optional(),
|
||||
ignore: z.array(z.string()).optional(),
|
||||
}),
|
||||
async execute(params) {
|
||||
const app = await App.use();
|
||||
const searchPath = path.resolve(app.root, params.path || ".");
|
||||
|
||||
const glob = new Bun.Glob("**/*");
|
||||
const files = [];
|
||||
|
||||
for await (const file of glob.scan({ cwd: searchPath })) {
|
||||
if (file.startsWith(".") || IGNORE_PATTERNS.some((p) => file.includes(p)))
|
||||
continue;
|
||||
if (params.ignore?.some((pattern) => new Bun.Glob(pattern).match(file)))
|
||||
continue;
|
||||
files.push(file);
|
||||
if (files.length >= 1000) break;
|
||||
}
|
||||
|
||||
// Build directory structure
|
||||
const dirs = new Set<string>();
|
||||
const filesByDir = new Map<string, string[]>();
|
||||
|
||||
for (const file of files) {
|
||||
const dir = path.dirname(file);
|
||||
const parts = dir === "." ? [] : dir.split("/");
|
||||
|
||||
// Add all parent directories
|
||||
for (let i = 0; i <= parts.length; i++) {
|
||||
const dirPath = i === 0 ? "." : parts.slice(0, i).join("/");
|
||||
dirs.add(dirPath);
|
||||
}
|
||||
|
||||
// Add file to its directory
|
||||
if (!filesByDir.has(dir)) filesByDir.set(dir, []);
|
||||
filesByDir.get(dir)!.push(path.basename(file));
|
||||
}
|
||||
|
||||
function renderDir(dirPath: string, depth: number): string {
|
||||
const indent = " ".repeat(depth);
|
||||
let output = "";
|
||||
|
||||
if (depth > 0) {
|
||||
output += `${indent}${path.basename(dirPath)}/\n`;
|
||||
}
|
||||
|
||||
const childIndent = " ".repeat(depth + 1);
|
||||
const children = Array.from(dirs)
|
||||
.filter((d) => path.dirname(d) === dirPath && d !== dirPath)
|
||||
.sort();
|
||||
|
||||
// Render subdirectories first
|
||||
for (const child of children) {
|
||||
output += renderDir(child, depth + 1);
|
||||
}
|
||||
|
||||
// Render files
|
||||
const files = filesByDir.get(dirPath) || [];
|
||||
for (const file of files.sort()) {
|
||||
output += `${childIndent}${file}\n`;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
const output = `${searchPath}/\n` + renderDir(".", 0);
|
||||
|
||||
return {
|
||||
metadata: { count: files.length, truncated: files.length >= 1000 },
|
||||
output,
|
||||
};
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user