Skip to content

Commit 832d8f8

Browse files
authored
fix(skills): reopen DB after boot-time Turso close (#413)
SkillsManager kept a stale Turso handle when migrators called closeConnection on skills.db, breaking registerDbSkills. Detect stale handles via getConnection identity and reset on lifecycle close. Fixes #412
1 parent 552825f commit 832d8f8

3 files changed

Lines changed: 37 additions & 0 deletions

File tree

‎src/services/skills/skills-manager.ts‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,16 @@ export class SkillsManager {
7676

7777
private async getDb(): Promise<TursoDb> {
7878
await this.initialize();
79+
// Connection manager is authoritative: boot migrators may close/replace
80+
// skills.db underneath a cached TursoDb handle (encryption/engine rewrite).
81+
if (this.db) {
82+
const current = await tursoConnectionManager.getConnection(this.dbPath);
83+
if (current === this.db) {
84+
return this.db;
85+
}
86+
this.reset();
87+
await this.initialize();
88+
}
7989
if (!this.db) throw new Error("Skills database not initialized");
8090
return this.db;
8191
}

‎src/services/turso/lifecycle.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { resetTursoReady } from "./ready.js";
44
import { userPromptManager } from "../user-prompt/user-prompt-manager.js";
55
import { userProfileManager } from "../user-profile/user-profile-manager.js";
66
import { aiSessionManager } from "../ai/session/ai-session-manager.js";
7+
import { skillsManager } from "../skills/skills-manager.js";
78

89
export async function closeTursoAndInvalidateCaches(): Promise<void> {
910
await tursoConnectionManager.closeAll();
@@ -12,4 +13,5 @@ export async function closeTursoAndInvalidateCaches(): Promise<void> {
1213
userPromptManager.reset();
1314
userProfileManager.reset();
1415
aiSessionManager.reset();
16+
skillsManager.reset();
1517
}

‎tests/skills-manager.test.ts‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,4 +132,29 @@ describe("SkillsManager", () => {
132132
stop();
133133
expect(hits).toBe(3);
134134
});
135+
136+
it("reopens after closeTursoAndInvalidateCaches", async () => {
137+
const mgr = await makeManager();
138+
await mgr.create({ id: "keep-me", name: "Keep", content: "body" });
139+
expect(await mgr.list({ enabledOnly: true })).toHaveLength(1);
140+
141+
const { closeTursoAndInvalidateCaches } = await import("../src/services/turso/lifecycle.js");
142+
await closeTursoAndInvalidateCaches();
143+
144+
const listed = await mgr.list({ enabledOnly: true });
145+
expect(listed).toHaveLength(1);
146+
expect(listed[0]?.id).toBe("keep-me");
147+
});
148+
149+
it("reopens after closeConnection on skills.db without lifecycle reset", async () => {
150+
const mgr = await makeManager();
151+
await mgr.create({ id: "stale-guard", name: "Stale", content: "body" });
152+
expect(await mgr.list({ enabledOnly: true })).toHaveLength(1);
153+
154+
await tursoConnectionManager.closeConnection(join(tmpDir, "skills.db"));
155+
156+
const listed = await mgr.list({ enabledOnly: true });
157+
expect(listed).toHaveLength(1);
158+
expect(listed[0]?.id).toBe("stale-guard");
159+
});
135160
});

0 commit comments

Comments
 (0)