* Handle codegraph_files - get project file structure from the index
(args: Record<string, unknown>)
| 4178 | * Handle codegraph_files - get project file structure from the index |
| 4179 | */ |
| 4180 | private async handleFiles(args: Record<string, unknown>): Promise<ToolResult> { |
| 4181 | const cg = this.getCodeGraph(args.projectPath as string | undefined); |
| 4182 | const pathFilter = args.path as string | undefined; |
| 4183 | const pattern = args.pattern as string | undefined; |
| 4184 | const format = (args.format as 'tree' | 'flat' | 'grouped') || 'tree'; |
| 4185 | const includeMetadata = args.includeMetadata !== false; |
| 4186 | const maxDepth = args.maxDepth != null ? clamp(args.maxDepth as number, 1, 20) : undefined; |
| 4187 | |
| 4188 | // Get all files from the index |
| 4189 | const allFiles = cg.getFiles(); |
| 4190 | |
| 4191 | if (allFiles.length === 0) { |
| 4192 | return this.textResult('No files indexed. Run `codegraph index` first.'); |
| 4193 | } |
| 4194 | |
| 4195 | // Filter by path prefix. Stored paths are project-relative POSIX (e.g. |
| 4196 | // "src/foo.ts"), but agents commonly pass project-root variants like "/", |
| 4197 | // ".", "./", "" or Windows-style "src\foo" — and prefixes with leading |
| 4198 | // "/", "./" or "\". Normalize all of those before matching so the agent |
| 4199 | // gets results instead of falling back to Read/Glob (see #426). |
| 4200 | const normalizedFilter = pathFilter |
| 4201 | ? pathFilter |
| 4202 | .replace(/\\/g, '/') |
| 4203 | .replace(/^(?:\.?\/+)+/, '') |
| 4204 | .replace(/^\.$/, '') |
| 4205 | .replace(/\/+$/, '') |
| 4206 | : ''; |
| 4207 | let files = normalizedFilter |
| 4208 | ? allFiles.filter(f => f.path === normalizedFilter || f.path.startsWith(normalizedFilter + '/')) |
| 4209 | : allFiles; |
| 4210 | |
| 4211 | // Filter by glob pattern |
| 4212 | if (pattern) { |
| 4213 | const regex = this.globToRegex(pattern); |
| 4214 | files = files.filter(f => regex.test(f.path)); |
| 4215 | } |
| 4216 | |
| 4217 | if (files.length === 0) { |
| 4218 | return this.textResult(`No files found matching the criteria.`); |
| 4219 | } |
| 4220 | |
| 4221 | // Format output |
| 4222 | let output: string; |
| 4223 | switch (format) { |
| 4224 | case 'flat': |
| 4225 | output = this.formatFilesFlat(files, includeMetadata); |
| 4226 | break; |
| 4227 | case 'grouped': |
| 4228 | output = this.formatFilesGrouped(files, includeMetadata); |
| 4229 | break; |
| 4230 | case 'tree': |
| 4231 | default: |
| 4232 | output = this.formatFilesTree(files, includeMetadata, maxDepth); |
| 4233 | break; |
| 4234 | } |
| 4235 | |
| 4236 | return this.textResult(this.truncateOutput(output)); |
| 4237 | } |
no test coverage detected