( limit?: number, )
| 3976 | } |
| 3977 | |
| 3978 | async function loadAllProjectsMessageLogsFull( |
| 3979 | limit?: number, |
| 3980 | ): Promise<LogOption[]> { |
| 3981 | const projectsDir = getProjectsDir() |
| 3982 | |
| 3983 | let dirents: Dirent[] |
| 3984 | try { |
| 3985 | dirents = await readdir(projectsDir, { withFileTypes: true }) |
| 3986 | } catch { |
| 3987 | return [] |
| 3988 | } |
| 3989 | |
| 3990 | const projectDirs = dirents |
| 3991 | .filter(dirent => dirent.isDirectory()) |
| 3992 | .map(dirent => join(projectsDir, dirent.name)) |
| 3993 | |
| 3994 | const logsPerProject = await Promise.all( |
| 3995 | projectDirs.map(projectDir => getLogsWithoutIndex(projectDir, limit)), |
| 3996 | ) |
| 3997 | const allLogs = logsPerProject.flat() |
| 3998 | |
| 3999 | // Deduplicate — same session+leaf can appear in multiple project dirs. |
| 4000 | // This path creates one LogOption per leaf, so use sessionId+leafUuid key. |
| 4001 | const deduped = new Map<string, LogOption>() |
| 4002 | for (const log of allLogs) { |
| 4003 | const key = `${log.sessionId ?? ''}:${log.leafUuid ?? ''}` |
| 4004 | const existing = deduped.get(key) |
| 4005 | if (!existing || log.modified.getTime() > existing.modified.getTime()) { |
| 4006 | deduped.set(key, log) |
| 4007 | } |
| 4008 | } |
| 4009 | |
| 4010 | // deduped values are fresh from getLogsWithoutIndex — safe to mutate |
| 4011 | const sorted = sortLogs([...deduped.values()]) |
| 4012 | sorted.forEach((log, i) => { |
| 4013 | log.value = i |
| 4014 | }) |
| 4015 | return sorted |
| 4016 | } |
| 4017 | |
| 4018 | export async function loadAllProjectsMessageLogsProgressive( |
| 4019 | limit?: number, |
no test coverage detected