From f2bcd049aee2f96fef7469ba65ce3d1962389c12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Hovad=C3=ADk?= <35649784+SlanyCukr@users.noreply.github.com> Date: Fri, 20 Mar 2026 17:27:04 +0100 Subject: [PATCH] fix: lazy-open GSD database on first tool call in manual sessions (#1606) In manual sessions (no auto-mode), bootstrapAutoSession never runs, so the GSD database is never opened. This causes gsd_save_decision, gsd_update_requirement, and gsd_save_summary tools to always fail with 'GSD database is not available'. Add ensureDbOpen() helper that checks isDbAvailable() first, then tries to open the DB from the expected .gsd/gsd.db path if it exists. All three tool handlers now use this helper instead of the check-only pattern. The fix is backward-compatible: in auto-mode the DB is already open, so ensureDbOpen() returns true immediately on the isDbAvailable() check. --- src/resources/extensions/gsd/index.ts | 37 +++++++++++++++------------ 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/src/resources/extensions/gsd/index.ts b/src/resources/extensions/gsd/index.ts index 2ef65a2cf..4114639cc 100644 --- a/src/resources/extensions/gsd/index.ts +++ b/src/resources/extensions/gsd/index.ts @@ -92,6 +92,23 @@ function warnDeprecatedAgentInstructions(): void { // ── Depth verification state ────────────────────────────────────────────── let depthVerificationDone = false; +// ── DB lazy-open helper ─────────────────────────────────────────────────── +// In manual sessions (no auto-mode), the DB is never opened by bootstrapAutoSession. +// This helper ensures the DB is lazily opened on first tool call that needs it. +async function ensureDbOpen(): Promise { + try { + const db = await import("./gsd-db.js"); + if (db.isDbAvailable()) return true; + const dbPath = join(process.cwd(), ".gsd", "gsd.db"); + if (existsSync(dbPath)) { + return db.openDatabase(dbPath); + } + return false; + } catch { + return false; + } +} + // ── Queue phase tracking ────────────────────────────────────────────────── // When true, the LLM is in a queue flow writing CONTEXT.md files. // The write-gate applies during queue flows just like discussion flows. @@ -300,12 +317,8 @@ export default function (pi: ExtensionAPI) { when_context: Type.Optional(Type.String({ description: "When/context for the decision (e.g. milestone ID)" })), }), async execute(_toolCallId, params, _signal, _onUpdate, _ctx) { - // Check DB availability - let dbAvailable = false; - try { - const db = await import("./gsd-db.js"); - dbAvailable = db.isDbAvailable(); - } catch { /* dynamic import failed */ } + // Ensure DB is open (lazy-open on first tool call in manual sessions) + const dbAvailable = await ensureDbOpen(); if (!dbAvailable) { return { @@ -367,11 +380,7 @@ export default function (pi: ExtensionAPI) { supporting_slices: Type.Optional(Type.String({ description: "Supporting slices" })), }), async execute(_toolCallId, params, _signal, _onUpdate, _ctx) { - let dbAvailable = false; - try { - const db = await import("./gsd-db.js"); - dbAvailable = db.isDbAvailable(); - } catch { /* dynamic import failed */ } + const dbAvailable = await ensureDbOpen(); if (!dbAvailable) { return { @@ -441,11 +450,7 @@ export default function (pi: ExtensionAPI) { content: Type.String({ description: "The full markdown content of the artifact" }), }), async execute(_toolCallId, params, _signal, _onUpdate, _ctx) { - let dbAvailable = false; - try { - const db = await import("./gsd-db.js"); - dbAvailable = db.isDbAvailable(); - } catch { /* dynamic import failed */ } + const dbAvailable = await ensureDbOpen(); if (!dbAvailable) { return {