import { stat } from "node:fs/promises"; import { relative, sep } from "node:path"; import picomatch from "picomatch"; import type { Tool } from "@magiccode/core"; import { displayPath, optStr, resolvePath, str } from "./helpers"; import { walkFiles } from "./walk"; const MAX_RESULTS = 100; export const globTool: Tool = { spec: { name: "Glob", description: 'Trouve des fichiers par motif glob (ex. "**/*.ts", "src/**/*.test.ts", "*.json"). ' + "Le motif est relatif au dossier de recherche. Résultats triés par date de modification " + "(les plus récents d'abord), limités à 100. Ignore .git, node_modules et les fichiers exclus par .gitignore.", inputSchema: { type: "object", properties: { pattern: { type: "string", description: "Motif glob à rechercher" }, path: { type: "string", description: "Dossier de recherche : complet ou relatif au dossier de lancement (défaut : ce dossier).", }, }, required: ["pattern"], }, }, permission: "auto", describe: (i) => `${String(i.pattern ?? "")}${i.path ? ` dans ${String(i.path)}` : ""}`, async execute(input, ctx) { const pattern = str(input, "pattern"); const root = resolvePath(ctx.cwd, optStr(input, "path") ?? "."); try { if (!(await stat(root)).isDirectory()) throw new Error(); } catch { throw new Error(`Dossier de recherche introuvable : ${root}`); } const isMatch = picomatch(pattern, { dot: true }); const matched: string[] = []; for await (const abs of walkFiles(root, ctx.signal)) { if (isMatch(relative(root, abs).split(sep).join("/"))) matched.push(abs); } if (matched.length === 0) return `Aucun fichier ne correspond au motif "${pattern}"`; const withTime = await Promise.all( matched.map(async (abs) => ({ abs, mtime: await stat(abs).then((s) => s.mtimeMs, () => 0), })), ); withTime.sort((a, b) => b.mtime - a.mtime); const shown = withTime.slice(0, MAX_RESULTS).map((f) => displayPath(ctx.cwd, f.abs)); const extra = withTime.length - shown.length; return extra > 0 ? `${shown.join("\n")}\n(${extra} résultat(s) supplémentaire(s) non affiché(s) : affinez le motif)` : shown.join("\n"); }, };