diff --git a/src/server/workspaces/fileSuggestions.test.ts b/src/server/workspaces/fileSuggestions.test.ts index 6027527..cda4bb3 100644 --- a/src/server/workspaces/fileSuggestions.test.ts +++ b/src/server/workspaces/fileSuggestions.test.ts @@ -76,6 +76,37 @@ describe("file suggestions", () => { ]); }); + it("waits for both git probes before falling back in all-file scope", async () => { + let releaseUntracked: (() => void) | undefined; + let resolved = false; + const deps: FileSuggestionDependencies = { + execFile: (file, args) => { + if (file === "git" && args.join(" ") === "ls-files -z") return Promise.reject(new Error("not a git repository")); + if (file === "git" && args.join(" ") === "ls-files --others --exclude-standard -z") { + return new Promise<{ stdout: string }>((resolve) => { + releaseUntracked = () => { + resolve({ stdout: "" }); + }; + }); + } + if (file === "rg") return Promise.resolve({ stdout: "sdk.md\n" }); + return Promise.reject(new Error(`unexpected command: ${file} ${args.join(" ")}`)); + }, + }; + + const suggestions = listFileSuggestions("/repo", "sdk", { scope: "all" }, deps).then((value) => { + resolved = true; + return value; + }); + await Promise.resolve(); + + expect(resolved).toBe(false); + expect(releaseUntracked).toBeDefined(); + + releaseUntracked?.(); + await expect(suggestions).resolves.toEqual([{ path: "sdk.md", kind: "other" }]); + }); + it("keeps git untracked files in all-file scope when the broad scan misses them", async () => { const deps: FileSuggestionDependencies = { execFile: (file, args) => { diff --git a/src/server/workspaces/fileSuggestions.ts b/src/server/workspaces/fileSuggestions.ts index 441babe..fd0f9a9 100644 --- a/src/server/workspaces/fileSuggestions.ts +++ b/src/server/workspaces/fileSuggestions.ts @@ -253,13 +253,16 @@ async function listTrackedFiles(cwd: string, exec: CommandRunner): Promise { - const [tracked, untracked] = await Promise.all([ + const [trackedResult, untrackedResult] = await Promise.allSettled([ git(cwd, ["ls-files", "-z"], exec), git(cwd, ["ls-files", "--others", "--exclude-standard", "-z"], exec), - ]); + ] as const); + if (trackedResult.status === "rejected") throw trackedResult.reason; + if (untrackedResult.status === "rejected") throw untrackedResult.reason; + return [ - ...withDirectories(nulRecords(tracked), "tracked"), - ...withDirectories(nulRecords(untracked), "untracked"), + ...withDirectories(nulRecords(trackedResult.value), "tracked"), + ...withDirectories(nulRecords(untrackedResult.value), "untracked"), ]; }