diff --git a/src/resources/extensions/gsd/commands/handlers/core.ts b/src/resources/extensions/gsd/commands/handlers/core.ts index d7adce661..6fdb8eba7 100644 --- a/src/resources/extensions/gsd/commands/handlers/core.ts +++ b/src/resources/extensions/gsd/commands/handlers/core.ts @@ -71,6 +71,9 @@ export function showHelp(ctx: ExtensionCommandContext): void { export async function handleStatus(ctx: ExtensionCommandContext): Promise { const basePath = projectRoot(); + // Open DB in cold sessions so status uses DB-backed state, not filesystem fallback (#3385) + const { ensureDbOpen } = await import("../../bootstrap/dynamic-tools.js"); + await ensureDbOpen(); const state = await deriveState(basePath); if (state.registry.length === 0) { diff --git a/src/resources/extensions/gsd/quick.ts b/src/resources/extensions/gsd/quick.ts index aa83a5553..ad513e46d 100644 --- a/src/resources/extensions/gsd/quick.ts +++ b/src/resources/extensions/gsd/quick.ts @@ -192,28 +192,33 @@ export async function handleQuick( const taskDirRel = `.gsd/quick/${taskNum}-${slug}`; const date = new Date().toISOString().split("T")[0]; - // Create git branch for the quick task + // Create git branch for the quick task (unless isolation:none — #3337) const gitPrefs = loadEffectiveGSDPreferences()?.preferences?.git ?? {}; const git = new GitServiceImpl(basePath, gitPrefs); const branchName = `gsd/quick/${taskNum}-${slug}`; let originalBranch = git.getCurrentBranch(); - let branchCreated = false; - try { - const current = originalBranch; - if (current !== branchName) { - // Auto-commit any dirty state before switching - try { - git.autoCommit("quick-task", `Q${taskNum}`, []); - } catch { /* nothing to commit — fine */ } + const { getIsolationMode } = await import("./preferences.js"); + const usesBranch = getIsolationMode() !== "none"; - runGit(basePath, ["checkout", "-b", branchName]); - branchCreated = true; + let branchCreated = false; + if (usesBranch) { + try { + const current = originalBranch; + if (current !== branchName) { + // Auto-commit any dirty state before switching + try { + git.autoCommit("quick-task", `Q${taskNum}`, []); + } catch { /* nothing to commit — fine */ } + + runGit(basePath, ["checkout", "-b", branchName]); + branchCreated = true; + } + } catch (err) { + // Branch creation failed — continue on current branch + const message = err instanceof Error ? err.message : String(err); + ctx.ui.notify(`Could not create branch ${branchName}: ${message}. Working on current branch.`, "warning"); } - } catch (err) { - // Branch creation failed — continue on current branch - const message = err instanceof Error ? err.message : String(err); - ctx.ui.notify(`Could not create branch ${branchName}: ${message}. Working on current branch.`, "warning"); } const actualBranch = branchCreated ? branchName : git.getCurrentBranch(); diff --git a/src/resources/extensions/gsd/tests/status-db-open.test.ts b/src/resources/extensions/gsd/tests/status-db-open.test.ts new file mode 100644 index 000000000..1fbd1aeb4 --- /dev/null +++ b/src/resources/extensions/gsd/tests/status-db-open.test.ts @@ -0,0 +1,47 @@ +/** + * Regression test for #3691 — /gsd status opens DB before deriveState + * + * In cold sessions the DB was not opened before deriveState, causing + * status to fall back to filesystem-only state. The fix adds an + * ensureDbOpen() call before deriveState in handleStatus. + * + * Also verifies that quick.ts checks getIsolationMode before branching. + */ + +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 coreSrc = readFileSync( + join(__dirname, '..', 'commands', 'handlers', 'core.ts'), + 'utf-8', +); +const quickSrc = readFileSync( + join(__dirname, '..', 'quick.ts'), + 'utf-8', +); + +describe('status opens DB before deriveState (#3691)', () => { + test('handleStatus calls ensureDbOpen before deriveState', () => { + const ensureIdx = coreSrc.indexOf('ensureDbOpen'); + const deriveIdx = coreSrc.indexOf('deriveState(basePath)'); + assert.ok(ensureIdx > -1, 'ensureDbOpen call should exist in core.ts'); + assert.ok(deriveIdx > -1, 'deriveState(basePath) call should exist in core.ts'); + assert.ok( + ensureIdx < deriveIdx, + 'ensureDbOpen must appear before deriveState so DB is ready', + ); + }); + + test('quick.ts checks getIsolationMode before branching', () => { + assert.match(quickSrc, /getIsolationMode\(\)/, + 'quick.ts should call getIsolationMode()'); + assert.match(quickSrc, /getIsolationMode\(\)\s*!==\s*"none"/, + 'quick.ts should compare isolation mode against "none"'); + }); +});