perf(recent-projects): stream codex session discovery

This commit is contained in:
777genius 2026-05-26 16:08:25 +03:00
parent 031e5eda2f
commit 72633daa6e
2 changed files with 33 additions and 13 deletions

View file

@ -345,32 +345,50 @@ async function listRecentJsonlFiles(
if (!hasBudget()) { if (!hasBudget()) {
return; return;
} }
let entries; let directoryHandle;
try { try {
entries = await fs.readdir(directory, { withFileTypes: true, encoding: 'utf8' }); directoryHandle = await fs.opendir(directory, { encoding: 'utf8' });
} catch { } catch {
return; return;
} }
directoriesVisited += 1; directoriesVisited += 1;
const filePaths: string[] = []; const fileBatch: string[] = [];
const childDirectories: string[] = []; const childDirectories: string[] = [];
const flushFileBatch = async (): Promise<void> => {
if (!fileBatch.length) {
return;
}
const batch = fileBatch.splice(0, fileBatch.length);
await collectFileStats(batch);
};
for (const entry of entries) { try {
const entryPath = path.join(directory, entry.name); for await (const entry of directoryHandle) {
if (entry.isDirectory()) { if (!hasBudget()) {
if (depth < maxDepth) { return;
childDirectories.push(entryPath);
} }
continue;
}
if (entry.isFile() && entry.name.endsWith('.jsonl')) { const entryPath = path.join(directory, entry.name);
filePaths.push(entryPath); if (entry.isDirectory()) {
if (depth < maxDepth) {
childDirectories.push(entryPath);
}
continue;
}
if (entry.isFile() && entry.name.endsWith('.jsonl')) {
fileBatch.push(entryPath);
if (fileBatch.length >= CODEX_SESSION_FILE_DISCOVERY_STAT_BATCH_SIZE) {
await flushFileBatch();
}
}
} }
} catch {
return;
} }
await collectFileStats(filePaths); await flushFileBatch();
for (const childDirectory of childDirectories) { for (const childDirectory of childDirectories) {
if (!hasBudget()) { if (!hasBudget()) {

View file

@ -742,6 +742,7 @@ describe('CodexSessionFileRecentProjectsSourceAdapter', () => {
) )
) )
); );
const readdirSpy = vi.spyOn(fs, 'readdir');
const adapter = new CodexSessionFileRecentProjectsSourceAdapter({ const adapter = new CodexSessionFileRecentProjectsSourceAdapter({
getActiveContext: () => ({ type: 'local', id: 'local-1' }) as never, getActiveContext: () => ({ type: 'local', id: 'local-1' }) as never,
@ -767,6 +768,7 @@ describe('CodexSessionFileRecentProjectsSourceAdapter', () => {
skippedUncached: 340, skippedUncached: 340,
}) })
); );
expect(readdirSpy).not.toHaveBeenCalled();
}); });
it('skips non-interactive and ephemeral sessions', async () => { it('skips non-interactive and ephemeral sessions', async () => {