Merge pull request 'fix(cli): race condition in thread rm + flaky test' (#266) from fix/265-flaky-thread-rm into main

This commit is contained in:
2026-05-15 00:21:16 +00:00
2 changed files with 10 additions and 7 deletions
@@ -180,6 +180,9 @@ describe("cli thread commands", () => {
} }
expect(threads.value.some((l) => l.includes(threadId))).toBe(true); expect(threads.value.some((l) => l.includes(threadId))).toBe(true);
const runningPath = join(storageRoot, "logs", added.value.hash, `${threadId}.running`);
await waitUntilRunningFileAbsent(runningPath, 120);
const shown = await cmdThreadShow(storageRoot, threadId); const shown = await cmdThreadShow(storageRoot, threadId);
expect(shown.ok).toBe(true); expect(shown.ok).toBe(true);
if (!shown.ok) { if (!shown.ok) {
@@ -18,13 +18,13 @@ export async function cmdThreadRemove(
return err(`thread not found: ${threadId}`); return err(`thread not found: ${threadId}`);
} }
if (resolved.source === "active") { // Always clear both stores: between resolve and delete the worker may finish and
await removeThreadEntry(resolved.bundleDir, threadId); // move the thread from threads.json into history; branching only on resolved.source
} else { // would skip history removal and leave a dangling row.
const hist = await removeThreadHistoryEntries(resolved.bundleDir, threadId); await removeThreadEntry(resolved.bundleDir, threadId);
if (!hist.ok) { const hist = await removeThreadHistoryEntries(resolved.bundleDir, threadId);
return hist; if (!hist.ok) {
} return hist;
} }
const infoPath = join(storageRoot, "logs", resolved.bundleHash, `${threadId}.info.jsonl`); const infoPath = join(storageRoot, "logs", resolved.bundleHash, `${threadId}.info.jsonl`);