diff --git a/apps/server/src/services/file_index.ts b/apps/server/src/services/file_index.ts index c4273b7..fb3ef38 100644 --- a/apps/server/src/services/file_index.ts +++ b/apps/server/src/services/file_index.ts @@ -15,6 +15,9 @@ interface CacheEntry { const cache = new Map(); // keyed by projectId +// Concurrent calls with a cold/stale cache may both spawn rg. The result is +// deterministic so they overwrite identically — no data corruption, just a +// rare extra subprocess. Acceptable for single-user mode. export async function getProjectFiles(projectId: string, projectRoot: string): Promise { const current = await snapMtimes(projectRoot); const cached = cache.get(projectId); diff --git a/apps/server/src/services/file_ops.ts b/apps/server/src/services/file_ops.ts index 41a55fd..2ec0790 100644 --- a/apps/server/src/services/file_ops.ts +++ b/apps/server/src/services/file_ops.ts @@ -1,7 +1,6 @@ import { readFile, readdir, stat } from 'node:fs/promises'; import { resolve, relative } from 'node:path'; import { spawn } from 'node:child_process'; -import type { Stats } from 'node:fs'; import { pathGuard, PathScopeError } from './path_guard.js'; const MAX_FILE_BYTES = 5 * 1024 * 1024; @@ -48,9 +47,6 @@ export interface FindFilesResult { truncated: boolean; } -// Suppress unused import warning — Stats is part of the public API surface -void (undefined as unknown as Stats); - export async function listDir(projectRoot: string, relPath: string): Promise { const real = await pathGuard(projectRoot, relPath); const s = await stat(real); @@ -224,6 +220,8 @@ export async function findFiles( const line = buf.slice(0, idx); buf = buf.slice(idx + 1); if (!line) continue; + // Keep counting after limit to report accurate `total` to the caller. + // grep kills early since the LLM doesn't need a total; this differs intentionally. total++; if (files.length < limit) { files.push(relative(projectRoot, line) || line);