@fodx/codelens 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/README.md +212 -0
  2. package/adapters/pi/codelens.extension.ts +280 -0
  3. package/adapters/pi/extension.json +10 -0
  4. package/build/src/cli.js +265 -0
  5. package/build/src/cli.js.map +1 -0
  6. package/build/src/context/schema.sql +23 -0
  7. package/build/src/context/store.js +91 -0
  8. package/build/src/context/store.js.map +1 -0
  9. package/build/src/db/db.js +65 -0
  10. package/build/src/db/db.js.map +1 -0
  11. package/build/src/db/migrations.js +88 -0
  12. package/build/src/db/migrations.js.map +1 -0
  13. package/build/src/db/schema.js +11 -0
  14. package/build/src/db/schema.js.map +1 -0
  15. package/build/src/db/schema.sql +111 -0
  16. package/build/src/git/scope.js +68 -0
  17. package/build/src/git/scope.js.map +1 -0
  18. package/build/src/graph/edges.js +76 -0
  19. package/build/src/graph/edges.js.map +1 -0
  20. package/build/src/graph/grammars.js +57 -0
  21. package/build/src/graph/grammars.js.map +1 -0
  22. package/build/src/graph/query.js +52 -0
  23. package/build/src/graph/query.js.map +1 -0
  24. package/build/src/graph/resolve.js +68 -0
  25. package/build/src/graph/resolve.js.map +1 -0
  26. package/build/src/graph/symbols.js +84 -0
  27. package/build/src/graph/symbols.js.map +1 -0
  28. package/build/src/graph/tests.js +73 -0
  29. package/build/src/graph/tests.js.map +1 -0
  30. package/build/src/index/autoprune.js +29 -0
  31. package/build/src/index/autoprune.js.map +1 -0
  32. package/build/src/index/deny.js +40 -0
  33. package/build/src/index/deny.js.map +1 -0
  34. package/build/src/index/freshness.js +60 -0
  35. package/build/src/index/freshness.js.map +1 -0
  36. package/build/src/index/fts.js +125 -0
  37. package/build/src/index/fts.js.map +1 -0
  38. package/build/src/index/identity.js +21 -0
  39. package/build/src/index/identity.js.map +1 -0
  40. package/build/src/index/indexer.js +32 -0
  41. package/build/src/index/indexer.js.map +1 -0
  42. package/build/src/index/manager.js +48 -0
  43. package/build/src/index/manager.js.map +1 -0
  44. package/build/src/index/queue.js +47 -0
  45. package/build/src/index/queue.js.map +1 -0
  46. package/build/src/index/recovery.js +51 -0
  47. package/build/src/index/recovery.js.map +1 -0
  48. package/build/src/index/reindex.js +70 -0
  49. package/build/src/index/reindex.js.map +1 -0
  50. package/build/src/index/scanner.js +147 -0
  51. package/build/src/index/scanner.js.map +1 -0
  52. package/build/src/index/ttl.js +87 -0
  53. package/build/src/index/ttl.js.map +1 -0
  54. package/build/src/index/watcher.js +74 -0
  55. package/build/src/index/watcher.js.map +1 -0
  56. package/build/src/installer/agents.js +440 -0
  57. package/build/src/installer/agents.js.map +1 -0
  58. package/build/src/obs/doctor.js +53 -0
  59. package/build/src/obs/doctor.js.map +1 -0
  60. package/build/src/obs/stats.js +28 -0
  61. package/build/src/obs/stats.js.map +1 -0
  62. package/build/src/obs/usage.js +136 -0
  63. package/build/src/obs/usage.js.map +1 -0
  64. package/build/src/search/rank.js +70 -0
  65. package/build/src/search/rank.js.map +1 -0
  66. package/build/src/search/snippet.js +66 -0
  67. package/build/src/search/snippet.js.map +1 -0
  68. package/build/src/server.js +126 -0
  69. package/build/src/server.js.map +1 -0
  70. package/build/src/tools/current.js +32 -0
  71. package/build/src/tools/current.js.map +1 -0
  72. package/build/src/tools/expand.js +54 -0
  73. package/build/src/tools/expand.js.map +1 -0
  74. package/build/src/tools/prune.js +46 -0
  75. package/build/src/tools/prune.js.map +1 -0
  76. package/build/src/tools/refresh.js +14 -0
  77. package/build/src/tools/refresh.js.map +1 -0
  78. package/build/src/tools/registry.js +176 -0
  79. package/build/src/tools/registry.js.map +1 -0
  80. package/build/src/tools/related.js +28 -0
  81. package/build/src/tools/related.js.map +1 -0
  82. package/build/src/tools/save.js +15 -0
  83. package/build/src/tools/save.js.map +1 -0
  84. package/build/src/tools/search.js +124 -0
  85. package/build/src/tools/search.js.map +1 -0
  86. package/build/src/upgrade.js +74 -0
  87. package/build/src/upgrade.js.map +1 -0
  88. package/build/src/util/hash.js +15 -0
  89. package/build/src/util/hash.js.map +1 -0
  90. package/build/src/util/paths.js +67 -0
  91. package/build/src/util/paths.js.map +1 -0
  92. package/build/src/version.js +27 -0
  93. package/build/src/version.js.map +1 -0
  94. package/docs/agent-guide.md +47 -0
  95. package/docs/codelens-preview.png +0 -0
  96. package/docs/routing.md +59 -0
  97. package/docs/tools.md +53 -0
  98. package/package.json +103 -0
@@ -0,0 +1,265 @@
1
+ import { createHash } from "node:crypto";
2
+ import { mkdirSync, rmSync } from "node:fs";
3
+ import { homedir } from "node:os";
4
+ import { join, dirname } from "node:path";
5
+ import { openDb } from "./db/db.js";
6
+ import { openContextDb } from "./context/store.js";
7
+ import { detectScope } from "./git/scope.js";
8
+ import { buildIndex } from "./index/indexer.js";
9
+ import { getActiveIndexId } from "./index/manager.js";
10
+ import { ctxSearch } from "./tools/search.js";
11
+ import { ctxRelated } from "./tools/related.js";
12
+ import { gatherStats } from "./obs/stats.js";
13
+ import { runDoctor } from "./obs/doctor.js";
14
+ import { UsageTracker, openGlobalUsageDb } from "./obs/usage.js";
15
+ import { scheduleAutoPrune } from "./index/autoprune.js";
16
+ import { runInstall, runUninstall, printConfig, HOSTS } from "./installer/agents.js";
17
+ import { VERSION } from "./version.js";
18
+ import { checkUpgrade, performUpgrade } from "./upgrade.js";
19
+ import { existsSync } from "node:fs";
20
+ import { fileURLToPath } from "node:url";
21
+ /**
22
+ * Minimal CLI (Gap #9): lets non-MCP users run diagnostics, build the index,
23
+ * and query from the terminal.
24
+ *
25
+ * Usage:
26
+ * codelens current # cl_current
27
+ * codelens index # cl_refresh (build/update current branch)
28
+ * codelens search <query> # cl_search
29
+ * codelens related <path> # cl_related
30
+ * codelens stats # cl_stats
31
+ * codelens doctor # cl_doctor
32
+ * codelens (no args) # start MCP stdio server
33
+ */
34
+ function dbPathFor(repoRoot) {
35
+ const dir = join(homedir(), ".codelens", "indexes");
36
+ mkdirSync(dir, { recursive: true });
37
+ const rid = createHash("sha256").update(repoRoot).digest("hex").slice(0, 16);
38
+ return join(dir, `index-${rid}.db`);
39
+ }
40
+ function openCore(repoRoot) {
41
+ try {
42
+ return openDb(dbPathFor(repoRoot));
43
+ }
44
+ catch {
45
+ // corrupt → remove and rebuild on next index
46
+ try {
47
+ rmSync(dbPathFor(repoRoot));
48
+ }
49
+ catch { /* ignore */ }
50
+ return openDb(dbPathFor(repoRoot));
51
+ }
52
+ }
53
+ function ensureActiveIndex(coreDb, repoRoot) {
54
+ const scope = detectScope(repoRoot);
55
+ if (!scope)
56
+ throw new Error("not inside a git repo (or a directory with files)");
57
+ if (!getActiveIndexId())
58
+ buildIndex(coreDb, scope);
59
+ }
60
+ export async function cli(args) {
61
+ const cmd = args[0];
62
+ const repoRoot = process.cwd();
63
+ if (!cmd || cmd === "--help" || cmd === "-h") {
64
+ console.log("codelens [current|index|search <q>|related <path>|stats|doctor|install|uninstall|upgrade|version]");
65
+ return 0;
66
+ }
67
+ // ── DB-free commands (no repo/index needed) ──────────────────
68
+ if (cmd === "version" || cmd === "-v" || cmd === "--version") {
69
+ console.log(`codelens ${VERSION}`);
70
+ return 0;
71
+ }
72
+ if (cmd === "--print-config") {
73
+ const hostId = args[1];
74
+ const cmdExe = args[2] ?? defaultServerCommand() ?? "codelens";
75
+ if (!hostId) {
76
+ console.error("--print-config requires a host id (one of: " + HOSTS.map((h) => h.id).join(",") + ")");
77
+ return 1;
78
+ }
79
+ const out = printConfig(hostId, cmdExe);
80
+ if (out === null) {
81
+ console.error(`unknown host: ${hostId}`);
82
+ return 1;
83
+ }
84
+ console.log(out);
85
+ return 0;
86
+ }
87
+ if (cmd === "install") {
88
+ const { target, location, yes, command } = parseInstallArgs(args.slice(1));
89
+ const serverCommand = command ?? defaultServerCommand();
90
+ if (!serverCommand) {
91
+ console.error("could not determine the server executable. Run install.sh first, or pass --command <path-to-launcher>.");
92
+ return 1;
93
+ }
94
+ const report = runInstall({ serverCommand, location, target, yes, instructions: true });
95
+ console.log(`Server command: ${serverCommand}`);
96
+ console.log(`Configured (${report.configured.filter((c) => c.wrote).length} written, ${report.configured.filter((c) => c.already).length} already):`);
97
+ for (const c of report.configured)
98
+ console.log(` ${c.host}: ${c.path} ${c.already ? "(already configured)" : c.wrote ? "(written)" : "(no change)"}`);
99
+ if (report.instructions.length)
100
+ console.log("Instructions written: " + report.instructions.map((i) => i.host).join(", "));
101
+ if (report.commands.length)
102
+ console.log("Slash commands written: " + report.commands.map((c) => `${c.host} (${c.wrote})`).join(", "));
103
+ if (report.skipped.length)
104
+ console.log("Skipped: " + report.skipped.join(", "));
105
+ console.log("Restart your agent(s) for the MCP server + commands to load.");
106
+ return 0;
107
+ }
108
+ if (cmd === "uninstall") {
109
+ const { target, location } = parseInstallArgs(args.slice(1));
110
+ const report = runUninstall({ location, target, instructions: true });
111
+ console.log("Removed:");
112
+ for (const c of report.configured)
113
+ if (c.wrote)
114
+ console.log(` ${c.host}: ${c.path}`);
115
+ if (!report.configured.some((c) => c.wrote))
116
+ console.log(" (nothing to remove)");
117
+ return 0;
118
+ }
119
+ if (cmd === "upgrade") {
120
+ const sub = args[1];
121
+ if (sub === "--check") {
122
+ const r = await checkUpgrade();
123
+ console.log(r.message);
124
+ return r.upToDate ? 0 : 0;
125
+ }
126
+ const r = await performUpgrade(args[1]);
127
+ console.log(r.message);
128
+ return r.ok ? 0 : 1;
129
+ }
130
+ const coreDb = openCore(repoRoot);
131
+ const ctxDb = openContextDb(repoRoot);
132
+ void ctxDb;
133
+ scheduleAutoPrune(coreDb);
134
+ try {
135
+ switch (cmd) {
136
+ case "current": {
137
+ const scope = detectScope(repoRoot);
138
+ if (!scope) {
139
+ console.log(JSON.stringify({ inGitRepo: false }));
140
+ break;
141
+ }
142
+ if (!getActiveIndexId())
143
+ buildIndex(coreDb, scope);
144
+ console.log(JSON.stringify({ branch: scope.branch, headSha: scope.headSha, dirtyFiles: scope.dirtyFiles.length }, null, 2));
145
+ break;
146
+ }
147
+ case "index":
148
+ case "refresh": {
149
+ const scope = detectScope(repoRoot);
150
+ if (!scope) {
151
+ console.error("not inside a git repo");
152
+ return 1;
153
+ }
154
+ const r = buildIndex(coreDb, scope);
155
+ console.log(JSON.stringify(r, null, 2));
156
+ break;
157
+ }
158
+ case "search": {
159
+ // support --type code|prose
160
+ const typeIdx = args.indexOf("--type");
161
+ const contentType = typeIdx >= 0 ? args[typeIdx + 1] : undefined;
162
+ const queryArgs = args.slice(1).filter((a) => a !== "--type" && a !== contentType);
163
+ const query = queryArgs.join(" ");
164
+ if (!query) {
165
+ console.error("search requires a query");
166
+ return 1;
167
+ }
168
+ ensureActiveIndex(coreDb, repoRoot);
169
+ const r = ctxSearch(coreDb, query, { scope: detectScope(repoRoot) ?? undefined, contentType });
170
+ for (const h of r.results) {
171
+ console.log(`${h.score.toFixed(3)} ${h.path}:${h.startLine}-${h.endLine} [${h.why?.join(",")}]`);
172
+ }
173
+ break;
174
+ }
175
+ case "related": {
176
+ const path = args[1];
177
+ if (!path) {
178
+ console.error("related requires a path");
179
+ return 1;
180
+ }
181
+ ensureActiveIndex(coreDb, repoRoot);
182
+ const r = ctxRelated(coreDb, path);
183
+ for (const h of r.results)
184
+ console.log(`${h.edgeType} (${h.hops}h) ${h.path}`);
185
+ break;
186
+ }
187
+ case "stats": {
188
+ ensureActiveIndex(coreDb, repoRoot);
189
+ console.log(JSON.stringify(gatherStats(coreDb), null, 2));
190
+ break;
191
+ }
192
+ case "usage": {
193
+ const snap = new UsageTracker(openGlobalUsageDb()).snapshot();
194
+ console.log(`Global usage — calls: ${snap.totals.calls} served: ${fmt(snap.totals.bytes_served)} saved(est): ${fmt(snap.totals.bytes_saved)}`);
195
+ console.log("Per tool:");
196
+ for (const t of snap.perTool)
197
+ console.log(` ${t.tool.padEnd(14)} calls=${t.calls} served=${fmt(t.bytes_served)} saved=${fmt(t.bytes_saved)}`);
198
+ console.log("Per repo:");
199
+ for (const r of snap.perRepo)
200
+ console.log(` ${r.repo_id.slice(0, 8)} calls=${r.calls} served=${fmt(r.bytes_served)} saved=${fmt(r.bytes_saved)}`);
201
+ break;
202
+ }
203
+ case "doctor": {
204
+ console.log(JSON.stringify(runDoctor(coreDb, repoRoot), null, 2));
205
+ break;
206
+ }
207
+ default:
208
+ console.error(`unknown command: ${cmd}`);
209
+ return 1;
210
+ }
211
+ return 0;
212
+ }
213
+ finally {
214
+ coreDb.close();
215
+ }
216
+ }
217
+ function fmt(n) {
218
+ if (n < 1024)
219
+ return `${n}B`;
220
+ if (n < 1024 * 1024)
221
+ return `${(n / 1024).toFixed(1)}KB`;
222
+ return `${(n / 1024 / 1024).toFixed(2)}MB`;
223
+ }
224
+ function defaultServerCommand() {
225
+ // Prefer the launcher the bootstrap installer put on PATH.
226
+ const launcher = join(homedir(), ".local", "bin", "codelens");
227
+ if (existsSync(launcher))
228
+ return launcher;
229
+ // Dev fallback: the currently running server.js (only meaningful for --print-config).
230
+ try {
231
+ const here = dirname(fileURLToPath(import.meta.url));
232
+ const serverJs = join(here, "..", "server.js");
233
+ if (existsSync(serverJs))
234
+ return serverJs;
235
+ }
236
+ catch { /* ignore */ }
237
+ return null;
238
+ }
239
+ function parseInstallArgs(args) {
240
+ let target = "auto";
241
+ let location = "global";
242
+ let yes = false;
243
+ let command;
244
+ const rest = [];
245
+ for (let i = 0; i < args.length; i++) {
246
+ const a = args[i];
247
+ if (a === "--target") {
248
+ const v = args[++i];
249
+ target = v === "all" || v === "auto" || v === "none" ? v : (v ?? "").split(",");
250
+ }
251
+ else if (a === "--location") {
252
+ const v = args[++i];
253
+ if (v === "local" || v === "global")
254
+ location = v;
255
+ }
256
+ else if (a === "--yes" || a === "-y")
257
+ yes = true;
258
+ else if (a === "--command")
259
+ command = args[++i];
260
+ else if (a === "--args")
261
+ rest.push(...(args[++i] ?? "").split(" "));
262
+ }
263
+ return { target, location, yes, command, args: rest };
264
+ }
265
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ -- saved_contexts schema (separate DB file — survives core-index rebuild, Step 21)
2
+
3
+ CREATE TABLE IF NOT EXISTS saved_contexts (
4
+ id TEXT PRIMARY KEY,
5
+ repo_id TEXT NOT NULL, -- hash of repo root (scoping)
6
+ name TEXT NOT NULL,
7
+ notes TEXT,
8
+ pinned INTEGER NOT NULL DEFAULT 0,
9
+ created_at INTEGER NOT NULL,
10
+ last_accessed_at INTEGER NOT NULL,
11
+ UNIQUE (repo_id, name)
12
+ );
13
+
14
+ CREATE TABLE IF NOT EXISTS saved_context_items (
15
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
16
+ context_id TEXT NOT NULL,
17
+ handle TEXT,
18
+ path TEXT,
19
+ symbol_id TEXT,
20
+ chunk_id TEXT
21
+ );
22
+ CREATE INDEX IF NOT EXISTS idx_items_context ON saved_context_items(context_id);
23
+ CREATE UNIQUE INDEX IF NOT EXISTS uq_items ON saved_context_items(context_id, COALESCE(chunk_id, handle), path);
@@ -0,0 +1,91 @@
1
+ import Database from "better-sqlite3";
2
+ import { createHash } from "node:crypto";
3
+ import { readFileSync } from "node:fs";
4
+ import { mkdirSync, existsSync } from "node:fs";
5
+ import { dirname, join } from "node:path";
6
+ import { fileURLToPath } from "node:url";
7
+ import { homedir } from "node:os";
8
+ /**
9
+ * Saved context store (Step 21).
10
+ *
11
+ * Lives in a SEPARATE SQLite DB file (contexts.db) keyed by repo_id, so it
12
+ * survives core-index corruption rebuilds (Step 12) — only the core index DB
13
+ * is rebuilt; saved contexts are untouched. Items reference path+symbol (not
14
+ * chunk_id) so they remain valid across reindexes.
15
+ */
16
+ const SCHEMA = readSchema();
17
+ function readSchema() {
18
+ const here = dirname(fileURLToPath(import.meta.url));
19
+ return readFileSync(join(here, "schema.sql"), "utf-8");
20
+ }
21
+ export function repoId(repoRoot) {
22
+ return createHash("sha256").update(repoRoot).digest("hex").slice(0, 16);
23
+ }
24
+ function contextDbPath(repoRoot) {
25
+ const dir = join(homedir(), ".codelens", "contexts");
26
+ mkdirSync(dir, { recursive: true });
27
+ return join(dir, `contexts-${repoId(repoRoot)}.db`);
28
+ }
29
+ /** Open (or create) the separate contexts DB for a repo. */
30
+ export function openContextDb(repoRoot) {
31
+ const path = contextDbPath(repoRoot);
32
+ const db = new Database(path);
33
+ db.pragma("journal_mode = WAL");
34
+ db.pragma("foreign_keys = ON");
35
+ db.exec(SCHEMA);
36
+ return db;
37
+ }
38
+ /** For tests: open an in-memory contexts DB. */
39
+ export function openMemoryContextDb() {
40
+ const db = new Database(":memory:");
41
+ db.pragma("foreign_keys = ON");
42
+ db.exec(SCHEMA);
43
+ return db;
44
+ }
45
+ export function saveContext(db, repoRoot, name, items, opts) {
46
+ const rid = repoId(repoRoot);
47
+ const now = Date.now();
48
+ const id = "ctx_" + createHash("sha256").update(rid + name).digest("hex").slice(0, 16);
49
+ const tx = db.transaction(() => {
50
+ db.prepare(`INSERT INTO saved_contexts (id, repo_id, name, notes, pinned, created_at, last_accessed_at)
51
+ VALUES (?, ?, ?, ?, ?, ?, ?)
52
+ ON CONFLICT(id) DO UPDATE SET notes=excluded.notes, pinned=excluded.pinned, last_accessed_at=excluded.last_accessed_at`).run(id, rid, name, opts?.notes ?? null, opts?.pinned ? 1 : 0, now, now);
53
+ db.prepare("DELETE FROM saved_context_items WHERE context_id = ?").run(id);
54
+ const ins = db.prepare(`INSERT INTO saved_context_items (context_id, handle, path, symbol_id, chunk_id) VALUES (?, ?, ?, ?, ?)`);
55
+ for (const it of items) {
56
+ ins.run(id, it.handle ?? null, it.path ?? null, it.symbol_id ?? null, it.chunk_id ?? null);
57
+ }
58
+ });
59
+ tx();
60
+ return {
61
+ id, repo_id: rid, name, notes: opts?.notes ?? null,
62
+ pinned: !!opts?.pinned, created_at: now, last_accessed_at: now,
63
+ };
64
+ }
65
+ export function loadContext(db, repoRoot, name) {
66
+ const rid = repoId(repoRoot);
67
+ const ctx = db.prepare("SELECT * FROM saved_contexts WHERE repo_id = ? AND name = ?").get(rid, name);
68
+ if (!ctx)
69
+ return { context: null, items: [] };
70
+ db.prepare("UPDATE saved_contexts SET last_accessed_at = ? WHERE id = ?").run(Date.now(), ctx.id);
71
+ const items = db.prepare("SELECT handle, path, symbol_id, chunk_id FROM saved_context_items WHERE context_id = ?").all(ctx.id);
72
+ return { context: { ...ctx, pinned: !!ctx.pinned }, items };
73
+ }
74
+ export function listContexts(db, repoRoot) {
75
+ const rid = repoId(repoRoot);
76
+ const rows = db.prepare("SELECT * FROM saved_contexts WHERE repo_id = ? ORDER BY last_accessed_at DESC").all(rid);
77
+ return rows.map((r) => ({ ...r, pinned: !!r.pinned }));
78
+ }
79
+ export function deleteContext(db, repoRoot, name) {
80
+ const rid = repoId(repoRoot);
81
+ const ctx = db.prepare("SELECT id FROM saved_contexts WHERE repo_id = ? AND name = ?").get(rid, name);
82
+ if (!ctx)
83
+ return false;
84
+ db.transaction(() => {
85
+ db.prepare("DELETE FROM saved_context_items WHERE context_id = ?").run(ctx.id);
86
+ db.prepare("DELETE FROM saved_contexts WHERE id = ?").run(ctx.id);
87
+ })();
88
+ return true;
89
+ }
90
+ export { contextDbPath, existsSync };
91
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../../src/context/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,65 @@
1
+ import Database from "better-sqlite3";
2
+ import { runMigrations, DbVersionMismatch } from "./migrations.js";
3
+ import { checkIntegrity, isCorruptionError } from "../index/recovery.js";
4
+ /**
5
+ * Open a codelens SQLite database with safe defaults:
6
+ * - WAL journal mode (concurrent readers, single writer — Step 11)
7
+ * - foreign keys ON (cascade deletes scoped by index_id)
8
+ * - busy_timeout to tolerate brief write locks
9
+ * - migrations applied with version guard
10
+ *
11
+ * On `DbVersionMismatch`, the caller (recovery.ts — Step 12) decides whether
12
+ * to rebuild the core index.
13
+ */
14
+ export function openDb(path, opts) {
15
+ let db;
16
+ try {
17
+ db = new Database(path, { readonly: opts?.readonly ?? false });
18
+ db.pragma("journal_mode = WAL");
19
+ db.pragma("foreign_keys = ON");
20
+ db.pragma("busy_timeout = 5000");
21
+ // Quick integrity check on startup (Section 16 risk 6). On corruption the
22
+ // caller may catch CorruptDb and rebuild the core index.
23
+ if (!opts?.skipIntegrityCheck) {
24
+ const integrity = checkIntegrity(db);
25
+ if (!integrity.ok) {
26
+ db.close();
27
+ throw new CorruptDb(integrity.message);
28
+ }
29
+ }
30
+ runMigrations(db, path);
31
+ }
32
+ catch (err) {
33
+ if (err instanceof DbVersionMismatch)
34
+ throw err;
35
+ if (err instanceof CorruptDb)
36
+ throw err;
37
+ if (isCorruptionError(err)) {
38
+ try {
39
+ db?.close();
40
+ }
41
+ catch { /* ignore */ }
42
+ throw new CorruptDb(err instanceof Error ? err.message : String(err));
43
+ }
44
+ try {
45
+ db?.close();
46
+ }
47
+ catch { /* ignore */ }
48
+ throw err;
49
+ }
50
+ return db;
51
+ }
52
+ /** In-memory DB for tests (still applies migrations; no integrity backup path). */
53
+ export function openMemoryDb() {
54
+ const db = new Database(":memory:");
55
+ db.pragma("foreign_keys = ON");
56
+ runMigrations(db);
57
+ return db;
58
+ }
59
+ export class CorruptDb extends Error {
60
+ constructor(message) {
61
+ super(`database corruption detected: ${message}`);
62
+ this.name = "CorruptDb";
63
+ }
64
+ }
65
+ //# sourceMappingURL=db.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.js","sourceRoot":"","sources":["../../../src/db/db.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAEzE;;;;;;;;;GASG;AACH,MAAM,UAAU,MAAM,CAAC,IAAY,EAAE,IAA2D;IAC9F,IAAI,EAAiC,CAAC;IACtC,IAAI,CAAC;QACH,EAAE,GAAG,IAAI,QAAQ,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,IAAI,KAAK,EAAE,CAAC,CAAC;QAC/D,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;QAChC,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC;QAC/B,EAAE,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC;QAEjC,0EAA0E;QAC1E,yDAAyD;QACzD,IAAI,CAAC,IAAI,EAAE,kBAAkB,EAAE,CAAC;YAC9B,MAAM,SAAS,GAAG,cAAc,CAAC,EAAE,CAAC,CAAC;YACrC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,CAAC;gBAClB,EAAE,CAAC,KAAK,EAAE,CAAC;gBACX,MAAM,IAAI,SAAS,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;YACzC,CAAC;QACH,CAAC;QACD,aAAa,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IAC1B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,iBAAiB;YAAE,MAAM,GAAG,CAAC;QAChD,IAAI,GAAG,YAAY,SAAS;YAAE,MAAM,GAAG,CAAC;QACxC,IAAI,iBAAiB,CAAC,GAAG,CAAC,EAAE,CAAC;YAC3B,IAAI,CAAC;gBAAC,EAAE,EAAE,KAAK,EAAE,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;YAC3C,MAAM,IAAI,SAAS,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QACxE,CAAC;QACD,IAAI,CAAC;YAAC,EAAE,EAAE,KAAK,EAAE,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;QAC3C,MAAM,GAAG,CAAC;IACZ,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,YAAY;IAC1B,MAAM,EAAE,GAAG,IAAI,QAAQ,CAAC,UAAU,CAAC,CAAC;IACpC,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC;IAC/B,aAAa,CAAC,EAAE,CAAC,CAAC;IAClB,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,OAAO,SAAU,SAAQ,KAAK;IAClC,YAAY,OAAe;QACzB,KAAK,CAAC,iCAAiC,OAAO,EAAE,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;IAC1B,CAAC;CACF"}
@@ -0,0 +1,88 @@
1
+ import { existsSync } from "node:fs";
2
+ import { SCHEMA_V1 } from "./schema.js";
3
+ import { backupBeforeMigration, restoreBackup } from "../index/recovery.js";
4
+ /**
5
+ * Versioned schema + migration runner.
6
+ *
7
+ * - `runMigrations(db)` applies additive migrations up to CODE_SCHEMA_VERSION.
8
+ * - Version guard: if the DB's applied version > CODE_SCHEMA_VERSION, throw
9
+ * `DbVersionMismatch` (caller must rebuild core index; saved contexts survive
10
+ * in a separate DB — Step 21).
11
+ * - Migrations run inside a single transaction; a pre-migration backup copy is
12
+ * made before the first migration (Step 12 enhances with restore-on-failure).
13
+ */
14
+ export class DbVersionMismatch extends Error {
15
+ dbVersion;
16
+ codeVersion;
17
+ constructor(dbVersion, codeVersion) {
18
+ super(`DB schema version ${dbVersion} is newer than code ${codeVersion}; rebuild required`);
19
+ this.dbVersion = dbVersion;
20
+ this.codeVersion = codeVersion;
21
+ this.name = "DbVersionMismatch";
22
+ }
23
+ }
24
+ /** v1 migration: create the full initial schema. */
25
+ export const MIGRATIONS = [
26
+ { version: 1, description: "initial schema", sql: SCHEMA_V1 },
27
+ ];
28
+ export const CODE_SCHEMA_VERSION = MIGRATIONS.reduce((m, x) => Math.max(m, x.version), 0);
29
+ /** Read the highest applied version from the DB (0 if fresh). */
30
+ function appliedVersion(db) {
31
+ // schema_version may not exist yet on a truly fresh DB.
32
+ const row = db
33
+ .prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='schema_version'")
34
+ .get();
35
+ if (!row?.name)
36
+ return 0;
37
+ const r = db.prepare("SELECT MAX(version) AS v FROM schema_version").get();
38
+ return r.v ?? 0;
39
+ }
40
+ /**
41
+ * Apply pending migrations. Throws DbVersionMismatch if the DB is newer than
42
+ * the code. Each migration runs in its own transaction. For file-backed DBs,
43
+ * a backup copy is made before the first migration; on failure the backup is
44
+ * restored (Section 16 risk 3).
45
+ */
46
+ export function runMigrations(db, dbPath) {
47
+ const current = appliedVersion(db);
48
+ if (current > CODE_SCHEMA_VERSION) {
49
+ throw new DbVersionMismatch(current, CODE_SCHEMA_VERSION);
50
+ }
51
+ const pending = MIGRATIONS.filter((m) => m.version > current);
52
+ if (pending.length === 0)
53
+ return current;
54
+ // Ensure schema_version table exists (v1 migration creates it, but guard).
55
+ db.exec("CREATE TABLE IF NOT EXISTS schema_version (version INTEGER PRIMARY KEY, applied_at INTEGER NOT NULL)");
56
+ // Backup file-backed DB before the first migration so we can restore on failure.
57
+ let backed = false;
58
+ if (dbPath && existsSync(dbPath)) {
59
+ try {
60
+ backupBeforeMigration(dbPath, pending[0].version);
61
+ backed = true;
62
+ }
63
+ catch {
64
+ // best-effort backup; continue without it
65
+ }
66
+ }
67
+ for (const m of pending) {
68
+ try {
69
+ const apply = db.transaction(() => {
70
+ db.exec(m.sql);
71
+ db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (?, ?)").run(m.version, Date.now());
72
+ });
73
+ apply();
74
+ }
75
+ catch (err) {
76
+ // Migration failed: attempt restore from backup.
77
+ if (backed && dbPath) {
78
+ try {
79
+ restoreBackup(dbPath, pending[0].version);
80
+ }
81
+ catch { /* best-effort */ }
82
+ }
83
+ throw err;
84
+ }
85
+ }
86
+ return CODE_SCHEMA_VERSION;
87
+ }
88
+ //# sourceMappingURL=migrations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrations.js","sourceRoot":"","sources":["../../../src/db/migrations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ // Auto-generated from schema.sql — single source of truth for the DB schema.
2
+ // Re-exported so migrations.ts can bundle it without runtime fs reads.
3
+ import { readFileSync } from "node:fs";
4
+ import { dirname, join } from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ const here = dirname(fileURLToPath(import.meta.url));
7
+ // In dev (vitest from src/): here = src/db/. In build: build/src/db/.
8
+ // schema.sql lives alongside this file in src; for the build it is copied by
9
+ // the `build` script (cp src/db/schema.sql build/src/db/schema.sql).
10
+ export const SCHEMA_V1 = readFileSync(join(here, "schema.sql"), "utf-8");
11
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/db/schema.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,uEAAuE;AACvE,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACrD,sEAAsE;AACtE,6EAA6E;AAC7E,qEAAqE;AACrE,MAAM,CAAC,MAAM,SAAS,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,EAAE,OAAO,CAAC,CAAC"}