diff --git a/src/resources/extensions/gsd/auto-start.ts b/src/resources/extensions/gsd/auto-start.ts index 48521820f..2f5c7961c 100644 --- a/src/resources/extensions/gsd/auto-start.ts +++ b/src/resources/extensions/gsd/auto-start.ts @@ -549,17 +549,17 @@ export async function bootstrapAutoSession( const hasDecisions = existsSync(join(gsdDirPath, "DECISIONS.md")); const hasRequirements = existsSync(join(gsdDirPath, "REQUIREMENTS.md")); const hasMilestones = existsSync(join(gsdDirPath, "milestones")); - if (hasDecisions || hasRequirements || hasMilestones) { - try { - const { openDatabase: openDb } = await import("./gsd-db.js"); + try { + const { openDatabase: openDb } = await import("./gsd-db.js"); + openDb(gsdDbPath); + if (hasDecisions || hasRequirements || hasMilestones) { const { migrateFromMarkdown } = await import("./md-importer.js"); - openDb(gsdDbPath); migrateFromMarkdown(s.basePath); - } catch (err) { - process.stderr.write( - `gsd-migrate: auto-migration failed: ${(err as Error).message}\n`, - ); } + } catch (err) { + process.stderr.write( + `gsd-migrate: auto-migration failed: ${(err as Error).message}\n`, + ); } } if (existsSync(gsdDbPath) && !isDbAvailable()) { diff --git a/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts b/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts index 5ba65210c..ac70406c3 100644 --- a/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +++ b/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts @@ -67,6 +67,9 @@ export async function ensureDbOpen(): Promise { } return opened; } + + // .gsd/ exists but has no Markdown content (fresh project) — create empty DB + return db.openDatabase(dbPath); } return false; diff --git a/src/resources/extensions/gsd/tests/ensure-db-open.test.ts b/src/resources/extensions/gsd/tests/ensure-db-open.test.ts index 5cfb64dd6..d68438cf4 100644 --- a/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +++ b/src/resources/extensions/gsd/tests/ensure-db-open.test.ts @@ -136,9 +136,10 @@ describe('ensure-db-open', () => { // ensureDbOpen returns false for empty .gsd/ (no Markdown, no DB) // ═══════════════════════════════════════════════════════════════════════════ - test('ensureDbOpen: empty .gsd/ returns false', async () => { + test('ensureDbOpen: empty .gsd/ creates empty DB (#2510)', async () => { const tmpDir = makeTmpDir(); - fs.mkdirSync(path.join(tmpDir, '.gsd'), { recursive: true }); + const gsdDir = path.join(tmpDir, '.gsd'); + fs.mkdirSync(gsdDir, { recursive: true }); // .gsd/ exists but no DECISIONS.md, REQUIREMENTS.md, or milestones/ try { closeDatabase(); } catch { /* ok */ } @@ -148,9 +149,12 @@ describe('ensure-db-open', () => { try { const { ensureDbOpen } = await import('../bootstrap/dynamic-tools.ts'); const result = await ensureDbOpen(); - assert.ok(result === false, 'ensureDbOpen should return false for empty .gsd/'); + assert.ok(result === true, 'ensureDbOpen should create empty DB for fresh .gsd/'); + assert.ok(fs.existsSync(path.join(gsdDir, 'gsd.db')), 'DB file should be created'); + assert.ok(isDbAvailable(), 'DB should be available'); } finally { process.cwd = origCwd; + closeDatabase(); cleanupDir(tmpDir); } });