* Gets stat-only logs for worktree paths (no file reads).
( worktreePaths: string[], limit?: number, )
| 4334 | * Gets stat-only logs for worktree paths (no file reads). |
| 4335 | */ |
| 4336 | async function getStatOnlyLogsForWorktrees( |
| 4337 | worktreePaths: string[], |
| 4338 | limit?: number, |
| 4339 | ): Promise<LogOption[]> { |
| 4340 | const projectsDir = getProjectsDir() |
| 4341 | |
| 4342 | if (worktreePaths.length <= 1) { |
| 4343 | const cwd = getOriginalCwd() |
| 4344 | const projectDir = getProjectDir(cwd) |
| 4345 | return getSessionFilesLite(projectDir, undefined, cwd) |
| 4346 | } |
| 4347 | |
| 4348 | // On Windows, drive letter case can differ between git worktree list |
| 4349 | // output (e.g. C:/Users/...) and how paths were stored in project |
| 4350 | // directories (e.g. c:/Users/...). Use case-insensitive comparison. |
| 4351 | const caseInsensitive = process.platform === 'win32' |
| 4352 | |
| 4353 | // Sort worktree paths by sanitized prefix length (longest first) so |
| 4354 | // more specific matches take priority over shorter ones. Without this, |
| 4355 | // a short prefix like -code-myrepo could match -code-myrepo-worktree1 |
| 4356 | // before the longer, more specific prefix gets a chance. |
| 4357 | const indexed = worktreePaths.map(wt => { |
| 4358 | const sanitized = sanitizePath(wt) |
| 4359 | return { |
| 4360 | path: wt, |
| 4361 | prefix: caseInsensitive ? sanitized.toLowerCase() : sanitized, |
| 4362 | } |
| 4363 | }) |
| 4364 | indexed.sort((a, b) => b.prefix.length - a.prefix.length) |
| 4365 | |
| 4366 | const allLogs: LogOption[] = [] |
| 4367 | const seenDirs = new Set<string>() |
| 4368 | |
| 4369 | let allDirents: Dirent[] |
| 4370 | try { |
| 4371 | allDirents = await readdir(projectsDir, { withFileTypes: true }) |
| 4372 | } catch (e) { |
| 4373 | // Fall back to current project |
| 4374 | logForDebugging( |
| 4375 | `Failed to read projects dir ${projectsDir}, falling back to current project: ${e}`, |
| 4376 | ) |
| 4377 | const projectDir = getProjectDir(getOriginalCwd()) |
| 4378 | return getSessionFilesLite(projectDir, limit, getOriginalCwd()) |
| 4379 | } |
| 4380 | |
| 4381 | for (const dirent of allDirents) { |
| 4382 | if (!dirent.isDirectory()) continue |
| 4383 | const dirName = caseInsensitive ? dirent.name.toLowerCase() : dirent.name |
| 4384 | if (seenDirs.has(dirName)) continue |
| 4385 | |
| 4386 | for (const { path: wtPath, prefix } of indexed) { |
| 4387 | if (dirName === prefix || dirName.startsWith(prefix + '-')) { |
| 4388 | seenDirs.add(dirName) |
| 4389 | allLogs.push( |
| 4390 | ...(await getSessionFilesLite( |
| 4391 | join(projectsDir, dirent.name), |
| 4392 | undefined, |
| 4393 | wtPath, |
no test coverage detected