From 4dd533753e55d068bdebbffd4133fbad63b2200f Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Thu, 18 Jun 2026 02:39:10 -0700 Subject: [PATCH] FN-6626: close cached CLI extension task stores Close cached TaskStore handles so CLI extension task-tool tests shut down cleanly.\n\n- Add deterministic cached-store shutdown for the CLI extension and invoke it from extension teardown.\n- Expose the shutdown helper for tests and call it after canonical-project-root task-tool cases.\n- Add a patch changeset for the published @runfusion/fusion package.\n\nFiles changed:\n .changeset/fn-6626-close-cached-stores.md | 5 +++++\n .../cli/src/__tests__/extension-task-tools.test.ts | 8 ++++++++\n packages/cli/src/extension.ts | 19 ++++++++++++++++++-\n 3 files changed, 31 insertions(+), 1 deletion(-) Fusion-Task-Id: FN-6626 Fusion-Task-Lineage: 65791502-8992-4037-8ca0-fe21c8283506 --- .changeset/fn-6626-close-cached-stores.md | 5 +++++ .../__tests__/extension-task-tools.test.ts | 8 ++++++++ packages/cli/src/extension.ts | 19 ++++++++++++++++++- 3 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 .changeset/fn-6626-close-cached-stores.md diff --git a/.changeset/fn-6626-close-cached-stores.md b/.changeset/fn-6626-close-cached-stores.md new file mode 100644 index 0000000000..5ec4c478ac --- /dev/null +++ b/.changeset/fn-6626-close-cached-stores.md @@ -0,0 +1,5 @@ +--- +"@runfusion/fusion": patch +--- + +Close cached CLI extension TaskStore instances on session shutdown so task-tool runs do not leave SQLite handles behind. diff --git a/packages/cli/src/__tests__/extension-task-tools.test.ts b/packages/cli/src/__tests__/extension-task-tools.test.ts index e76b7a43ab..d517332342 100644 --- a/packages/cli/src/__tests__/extension-task-tools.test.ts +++ b/packages/cli/src/__tests__/extension-task-tools.test.ts @@ -6,6 +6,9 @@ Keep this worktree-root regression slice fast by relying on module resets and bo FNXC:CliTests 2026-06-15-07:44: FN-6486 rescues this load-only timeout by closing each real TaskStore before removing its temp root and by using non-hoisted mock cleanup. The suite keeps the worktree-root regression coverage without widening timeouts, adding retries, or changing package worker settings. + +FNXC:CliTests 2026-06-17-23:58: +FN-6626 requires these canonical-project-root tool tests to close the extension module's cached TaskStore instances after every case, because fixture-store cleanup alone does not close the second store opened by fn_task_show/fn_task_list. */ import { mkdtemp, mkdir, rm, writeFile } from "node:fs/promises"; import { tmpdir } from "node:os"; @@ -17,8 +20,11 @@ function makeCtx(cwd: string) { return { cwd } as any; } +let closeLoadedExtensionStores: (() => void) | undefined; + async function loadExtension() { const mod = await import("../extension.js"); + closeLoadedExtensionStores = mod.closeCachedStores; return mod.default; } @@ -32,6 +38,8 @@ describe("extension task tools resolve repo root from worktrees", () => { }); afterEach(() => { + closeLoadedExtensionStores?.(); + closeLoadedExtensionStores = undefined; vi.restoreAllMocks(); vi.doUnmock("@fusion/core"); }); diff --git a/packages/cli/src/extension.ts b/packages/cli/src/extension.ts index 708dc9c446..c3fc2d4aba 100644 --- a/packages/cli/src/extension.ts +++ b/packages/cli/src/extension.ts @@ -152,6 +152,23 @@ async function getStore(cwd: string): Promise { return store; } +/** @internal Exposed so tests and the extension shutdown hook can close cached stores deterministically; not a public CLI API contract. */ +export function closeCachedStores(): void { + /* + FNXC:CliTests 2026-06-17-23:58: + FN-6626 found the CLI extension cache cleared real TaskStore instances without closing them, leaving SQLite/WAL handles to survive module resets and making canonical-project-root task-tool tests timeout under suite load. + Close every cached store deterministically on extension shutdown and in tests; do not appease the load-sensitive seam with timeouts, retries, or worker changes. + */ + for (const store of storeCache.values()) { + try { + store.close(); + } catch (error) { + console.warn("[fusion-extension] cached TaskStore close skipped", error); + } + } + storeCache.clear(); +} + function getFusionDir(cwd: string): string { return join(resolveProjectRoot(cwd), ".fusion"); } @@ -4572,6 +4589,6 @@ export default function kbExtension(pi: ExtensionAPI) { dashboardProcess = null; dashboardPort = null; } - storeCache.clear(); + closeCachedStores(); }); }