* Handle codegraph_files - get project file structure from the index
(args: Record<string, unknown>)
| 4415 | * Handle codegraph_files - get project file structure from the index |
| 4416 | */ |
| 4417 | private async handleFiles(args: Record<string, unknown>): Promise<ToolResult> { |
| 4418 | const cg = this.getCodeGraph(args.projectPath as string | undefined); |
| 4419 | const pathFilter = args.path as string | undefined; |
| 4420 | const pattern = args.pattern as string | undefined; |
| 4421 | const format = (args.format as 'tree' | 'flat' | 'grouped') || 'tree'; |
| 4422 | const includeMetadata = args.includeMetadata !== false; |
| 4423 | const maxDepth = args.maxDepth != null ? clamp(args.maxDepth as number, 1, 20) : undefined; |
| 4424 | |
| 4425 | // Get all files from the index |
| 4426 | const allFiles = cg.getFiles(); |
| 4427 | |
| 4428 | if (allFiles.length === 0) { |
| 4429 | return this.textResult('No files indexed. Run `codegraph index` first.'); |
| 4430 | } |
| 4431 | |
| 4432 | // Filter by path prefix. Stored paths are project-relative POSIX (e.g. |
| 4433 | // "src/foo.ts"), but agents commonly pass project-root variants like "/", |
| 4434 | // ".", "./", "" or Windows-style "src\foo" — and prefixes with leading |
| 4435 | // "/", "./" or "\". Normalize all of those before matching so the agent |
| 4436 | // gets results instead of falling back to Read/Glob (see #426). |
| 4437 | const normalizedFilter = pathFilter |
| 4438 | ? pathFilter |
| 4439 | .replace(/\\/g, '/') |
| 4440 | .replace(/^(?:\.?\/+)+/, '') |
| 4441 | .replace(/^\.$/, '') |
| 4442 | .replace(/\/+$/, '') |
| 4443 | : ''; |
| 4444 | let files = normalizedFilter |
| 4445 | ? allFiles.filter(f => f.path === normalizedFilter || f.path.startsWith(normalizedFilter + '/')) |
| 4446 | : allFiles; |
| 4447 | |
| 4448 | // Filter by glob pattern |
| 4449 | if (pattern) { |
| 4450 | const regex = this.globToRegex(pattern); |
| 4451 | files = files.filter(f => regex.test(f.path)); |
| 4452 | } |
| 4453 | |
| 4454 | if (files.length === 0) { |
| 4455 | return this.textResult(`No files found matching the criteria.`); |
| 4456 | } |
| 4457 | |
| 4458 | // Format output |
| 4459 | let output: string; |
| 4460 | switch (format) { |
| 4461 | case 'flat': |
| 4462 | output = this.formatFilesFlat(files, includeMetadata); |
| 4463 | break; |
| 4464 | case 'grouped': |
| 4465 | output = this.formatFilesGrouped(files, includeMetadata); |
| 4466 | break; |
| 4467 | case 'tree': |
| 4468 | default: |
| 4469 | output = this.formatFilesTree(files, includeMetadata, maxDepth); |
| 4470 | break; |
| 4471 | } |
| 4472 | |
| 4473 | return this.textResult(this.truncateOutput(output)); |
| 4474 | } |
no test coverage detected