Merge pull request #3672 from Tibsfox/fix/query-tools-ensure-db-open

fix(gsd): open DB on demand in gsd_milestone_status for non-auto sessions
This commit is contained in:
Jeremy McSpadden 2026-04-07 07:07:47 -05:00 committed by GitHub
commit 24d40788ac
2 changed files with 52 additions and 4 deletions

View file

@ -22,17 +22,18 @@ export function registerQueryTools(pi: ExtensionAPI): void {
}),
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
try {
// Strictly read-only: only use an already-open DB connection.
// Do NOT call ensureDbOpen() — it can create/migrate the DB as a side effect.
// Open the DB if not already open — safe for read-only use since
// ensureDbOpen() only creates/migrates when .gsd/ has content (#3644).
const { ensureDbOpen } = await import("./dynamic-tools.js");
const dbAvailable = await ensureDbOpen();
const {
isDbAvailable,
getMilestone,
getSliceStatusSummary,
getSliceTaskCounts,
_getAdapter,
} = await import("../gsd-db.js");
if (!isDbAvailable()) {
if (!dbAvailable) {
return {
content: [{ type: "text" as const, text: "Error: GSD database is not available." }],
details: { operation: "milestone_status", error: "db_unavailable" } as any,

View file

@ -0,0 +1,47 @@
/**
* Regression test for #3672 query-tools uses ensureDbOpen
*
* gsd_milestone_status previously called isDbAvailable() but never
* ensureDbOpen(), making it always fail outside auto-mode sessions.
* The fix imports ensureDbOpen from dynamic-tools and calls it before
* querying the DB.
*
* This structural test verifies the ensureDbOpen import and usage exist
* in query-tools.ts.
*/
import { describe, test } from 'node:test';
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const source = readFileSync(join(__dirname, '..', 'bootstrap', 'query-tools.ts'), 'utf-8');
describe('query-tools ensureDbOpen usage (#3672)', () => {
test('imports ensureDbOpen from dynamic-tools', () => {
assert.match(source, /ensureDbOpen.*import\(|import.*ensureDbOpen/,
'query-tools should import ensureDbOpen');
});
test('calls ensureDbOpen() before DB queries', () => {
assert.match(source, /await ensureDbOpen\(\)/,
'query-tools should call await ensureDbOpen()');
});
test('no longer imports isDbAvailable in the execute path', () => {
// The old code imported isDbAvailable and checked it; the fix removed that
// The execute function should not destructure isDbAvailable from gsd-db
const executeBlock = source.slice(source.indexOf('async execute('));
assert.doesNotMatch(executeBlock, /isDbAvailable,/,
'execute path should not destructure isDbAvailable (replaced by ensureDbOpen)');
});
test('uses dbAvailable result from ensureDbOpen', () => {
assert.match(source, /dbAvailable\s*=\s*await ensureDbOpen\(\)/,
'should store ensureDbOpen result in dbAvailable');
});
});