( limit?: number, )
| 4084 | } |
| 4085 | |
| 4086 | async function loadAllProjectsMessageLogsFull( |
| 4087 | limit?: number, |
| 4088 | ): Promise<LogOption[]> { |
| 4089 | const projectsDir = getProjectsDir() |
| 4090 | |
| 4091 | let dirents: Dirent[] |
| 4092 | try { |
| 4093 | dirents = await readdir(projectsDir, { withFileTypes: true }) |
| 4094 | } catch { |
| 4095 | return [] |
| 4096 | } |
| 4097 | |
| 4098 | const projectDirs = dirents |
| 4099 | .filter(dirent => dirent.isDirectory()) |
| 4100 | .map(dirent => join(projectsDir, dirent.name)) |
| 4101 | |
| 4102 | const logsPerProject = await Promise.all( |
| 4103 | projectDirs.map(projectDir => getLogsWithoutIndex(projectDir, limit)), |
| 4104 | ) |
| 4105 | const allLogs = logsPerProject.flat() |
| 4106 | |
| 4107 | // Deduplicate — same session+leaf can appear in multiple project dirs. |
| 4108 | // This path creates one LogOption per leaf, so use sessionId+leafUuid key. |
| 4109 | const deduped = new Map<string, LogOption>() |
| 4110 | for (const log of allLogs) { |
| 4111 | const key = `${log.sessionId ?? ''}:${log.leafUuid ?? ''}` |
| 4112 | const existing = deduped.get(key) |
| 4113 | if (!existing || log.modified.getTime() > existing.modified.getTime()) { |
| 4114 | deduped.set(key, log) |
| 4115 | } |
| 4116 | } |
| 4117 | |
| 4118 | // deduped values are fresh from getLogsWithoutIndex — safe to mutate |
| 4119 | const sorted = sortLogs([...deduped.values()]) |
| 4120 | sorted.forEach((log, i) => { |
| 4121 | log.value = i |
| 4122 | }) |
| 4123 | return sorted |
| 4124 | } |
| 4125 | |
| 4126 | export async function loadAllProjectsMessageLogsProgressive( |
| 4127 | limit?: number, |
no test coverage detected