* Gets stat-only logs for worktree paths (no file reads).
( worktreePaths: string[], limit?: number, )
| 4219 | * Gets stat-only logs for worktree paths (no file reads). |
| 4220 | */ |
| 4221 | async function getStatOnlyLogsForWorktrees( |
| 4222 | worktreePaths: string[], |
| 4223 | limit?: number, |
| 4224 | ): Promise<LogOption[]> { |
| 4225 | const projectsDir = getProjectsDir() |
| 4226 | |
| 4227 | if (worktreePaths.length <= 1) { |
| 4228 | const cwd = getOriginalCwd() |
| 4229 | const projectDir = getProjectDir(cwd) |
| 4230 | return getSessionFilesLite(projectDir, undefined, cwd) |
| 4231 | } |
| 4232 | |
| 4233 | // On Windows, drive letter case can differ between git worktree list |
| 4234 | // output (e.g. C:/Users/...) and how paths were stored in project |
| 4235 | // directories (e.g. c:/Users/...). Use case-insensitive comparison. |
| 4236 | const caseInsensitive = process.platform === 'win32' |
| 4237 | |
| 4238 | // Sort worktree paths by sanitized prefix length (longest first) so |
| 4239 | // more specific matches take priority over shorter ones. Without this, |
| 4240 | // a short prefix like -code-myrepo could match -code-myrepo-worktree1 |
| 4241 | // before the longer, more specific prefix gets a chance. |
| 4242 | const indexed = worktreePaths.map(wt => { |
| 4243 | const sanitized = sanitizePath(wt) |
| 4244 | return { |
| 4245 | path: wt, |
| 4246 | prefix: caseInsensitive ? sanitized.toLowerCase() : sanitized, |
| 4247 | } |
| 4248 | }) |
| 4249 | indexed.sort((a, b) => b.prefix.length - a.prefix.length) |
| 4250 | |
| 4251 | const allLogs: LogOption[] = [] |
| 4252 | const seenDirs = new Set<string>() |
| 4253 | |
| 4254 | let allDirents: Dirent[] |
| 4255 | try { |
| 4256 | allDirents = await readdir(projectsDir, { withFileTypes: true }) |
| 4257 | } catch (e) { |
| 4258 | // Fall back to current project |
| 4259 | logForDebugging( |
| 4260 | `Failed to read projects dir ${projectsDir}, falling back to current project: ${e}`, |
| 4261 | ) |
| 4262 | const projectDir = getProjectDir(getOriginalCwd()) |
| 4263 | return getSessionFilesLite(projectDir, limit, getOriginalCwd()) |
| 4264 | } |
| 4265 | |
| 4266 | for (const dirent of allDirents) { |
| 4267 | if (!dirent.isDirectory()) continue |
| 4268 | const dirName = caseInsensitive ? dirent.name.toLowerCase() : dirent.name |
| 4269 | if (seenDirs.has(dirName)) continue |
| 4270 | |
| 4271 | for (const { path: wtPath, prefix } of indexed) { |
| 4272 | if (dirName === prefix || dirName.startsWith(prefix + '-')) { |
| 4273 | seenDirs.add(dirName) |
| 4274 | allLogs.push( |
| 4275 | ...(await getSessionFilesLite( |
| 4276 | join(projectsDir, dirent.name), |
| 4277 | undefined, |
| 4278 | wtPath, |
no test coverage detected