* List files with optional fuzzy search (supports subdirectories)
(params: ListFilesParams)
| 1197 | * List files with optional fuzzy search (supports subdirectories) |
| 1198 | */ |
| 1199 | async function handleListFiles(params: ListFilesParams): Promise<ListFilesResponse> { |
| 1200 | const startTime = Date.now() |
| 1201 | logger.info("[Git:listFiles] Listing files", JSON.stringify({ |
| 1202 | repoDir: params.repoDir, |
| 1203 | workTreeId: params.workTreeId, |
| 1204 | hasQuery: !!params.query, |
| 1205 | limit: params.limit, |
| 1206 | })) |
| 1207 | |
| 1208 | try { |
| 1209 | validateRepoDir(params.repoDir) |
| 1210 | |
| 1211 | let targetDir = params.repoDir |
| 1212 | if (params.workTreeId) { |
| 1213 | validateWorkTreeId(params.workTreeId) |
| 1214 | targetDir = getWorktreePath(params.workTreeId) |
| 1215 | if (!fs.existsSync(targetDir)) { |
| 1216 | throw new Error(`Worktree does not exist: ${targetDir}`) |
| 1217 | } |
| 1218 | } |
| 1219 | |
| 1220 | // Resolve git info (handles subdirectories) |
| 1221 | const { repoRoot, relativePath } = await resolveGitInfo(targetDir) |
| 1222 | logger.info("[Git:listFiles] Resolved git info", JSON.stringify({ targetDir, repoRoot, relativePath: relativePath || "(root)" })) |
| 1223 | |
| 1224 | // Get tracked files from repo root |
| 1225 | const lsFilesResult = await execGit(["ls-files"], repoRoot) |
| 1226 | if (!lsFilesResult.success) { |
| 1227 | throw new Error(`Failed to list files: ${lsFilesResult.stderr}`) |
| 1228 | } |
| 1229 | |
| 1230 | let files = lsFilesResult.stdout |
| 1231 | .split("\n") |
| 1232 | .map((f) => f.trim()) |
| 1233 | .filter((f) => f.length > 0) |
| 1234 | |
| 1235 | // Filter to only files in the subdirectory if not at root |
| 1236 | if (relativePath) { |
| 1237 | const prefix = relativePath + "/" |
| 1238 | files = files.filter((f) => f.startsWith(prefix)).map((f) => f.slice(prefix.length)) |
| 1239 | logger.info("[Git:listFiles] Filtered to subdirectory", JSON.stringify({ relativePath, count: files.length })) |
| 1240 | } |
| 1241 | |
| 1242 | logger.info("[Git:listFiles] Files retrieved", JSON.stringify({ count: files.length })) |
| 1243 | |
| 1244 | // Apply fuzzy search if query provided |
| 1245 | if (params.query && params.query.trim()) { |
| 1246 | const fuzzyResults = fuzzysort.go(params.query, files) |
| 1247 | files = fuzzyResults.map((result) => result.target) |
| 1248 | logger.info("[Git:listFiles] Fuzzy search applied", JSON.stringify({ query: params.query, matchCount: files.length })) |
| 1249 | } |
| 1250 | |
| 1251 | // Apply limit |
| 1252 | const limit = params.limit || 100 |
| 1253 | const maxLimit = 1000 |
| 1254 | const actualLimit = Math.min(limit, maxLimit) |
| 1255 | const truncated = files.length > actualLimit |
| 1256 | if (truncated) { |
no test coverage detected