codesift-mcp 0.11.0 → 0.13.1

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 (112) hide show
  1. package/README.md +44 -1
  2. package/dist/cli/commands.d.ts.map +1 -1
  3. package/dist/cli/commands.js +80 -8
  4. package/dist/cli/commands.js.map +1 -1
  5. package/dist/cli/embed-child.js +3 -0
  6. package/dist/cli/embed-child.js.map +1 -1
  7. package/dist/cli/help.d.ts.map +1 -1
  8. package/dist/cli/help.js +25 -2
  9. package/dist/cli/help.js.map +1 -1
  10. package/dist/cli/orphan-guard.d.ts +34 -0
  11. package/dist/cli/orphan-guard.d.ts.map +1 -0
  12. package/dist/cli/orphan-guard.js +52 -0
  13. package/dist/cli/orphan-guard.js.map +1 -0
  14. package/dist/cli/owner-only-file.d.ts +51 -0
  15. package/dist/cli/owner-only-file.d.ts.map +1 -0
  16. package/dist/cli/owner-only-file.js +121 -0
  17. package/dist/cli/owner-only-file.js.map +1 -0
  18. package/dist/cli/service.d.ts +17 -1
  19. package/dist/cli/service.d.ts.map +1 -1
  20. package/dist/cli/service.js +28 -12
  21. package/dist/cli/service.js.map +1 -1
  22. package/dist/cli/setup/codex.d.ts.map +1 -1
  23. package/dist/cli/setup/codex.js +14 -7
  24. package/dist/cli/setup/codex.js.map +1 -1
  25. package/dist/cli/setup/fs.d.ts +12 -0
  26. package/dist/cli/setup/fs.d.ts.map +1 -1
  27. package/dist/cli/setup/fs.js +17 -2
  28. package/dist/cli/setup/fs.js.map +1 -1
  29. package/dist/cli/setup/mcp.d.ts +37 -1
  30. package/dist/cli/setup/mcp.d.ts.map +1 -1
  31. package/dist/cli/setup/mcp.js +78 -3
  32. package/dist/cli/setup/mcp.js.map +1 -1
  33. package/dist/cli/setup/types.d.ts +24 -0
  34. package/dist/cli/setup/types.d.ts.map +1 -1
  35. package/dist/register-tool-groups/handler-wrappers.d.ts.map +1 -1
  36. package/dist/register-tool-groups/handler-wrappers.js +20 -6
  37. package/dist/register-tool-groups/handler-wrappers.js.map +1 -1
  38. package/dist/register-tools/runtime.d.ts +18 -9
  39. package/dist/register-tools/runtime.d.ts.map +1 -1
  40. package/dist/register-tools/runtime.js +54 -20
  41. package/dist/register-tools/runtime.js.map +1 -1
  42. package/dist/register-tools.d.ts +1 -1
  43. package/dist/register-tools.d.ts.map +1 -1
  44. package/dist/register-tools.js +12 -6
  45. package/dist/register-tools.js.map +1 -1
  46. package/dist/server-helpers/repo-resolution.d.ts.map +1 -1
  47. package/dist/server-helpers/repo-resolution.js +22 -1
  48. package/dist/server-helpers/repo-resolution.js.map +1 -1
  49. package/dist/server-helpers/request-context.d.ts +59 -0
  50. package/dist/server-helpers/request-context.d.ts.map +1 -0
  51. package/dist/server-helpers/request-context.js +31 -0
  52. package/dist/server-helpers/request-context.js.map +1 -0
  53. package/dist/server-helpers/response-hints.d.ts.map +1 -1
  54. package/dist/server-helpers/response-hints.js +2 -1
  55. package/dist/server-helpers/response-hints.js.map +1 -1
  56. package/dist/server.d.ts +1 -11
  57. package/dist/server.d.ts.map +1 -1
  58. package/dist/server.js +124 -76
  59. package/dist/server.js.map +1 -1
  60. package/dist/storage/embedding-store.d.ts +26 -6
  61. package/dist/storage/embedding-store.d.ts.map +1 -1
  62. package/dist/storage/embedding-store.js +85 -4
  63. package/dist/storage/embedding-store.js.map +1 -1
  64. package/dist/storage/index-store.d.ts +31 -0
  65. package/dist/storage/index-store.d.ts.map +1 -1
  66. package/dist/storage/index-store.js +293 -10
  67. package/dist/storage/index-store.js.map +1 -1
  68. package/dist/storage/shared-embedding-cache.d.ts +29 -0
  69. package/dist/storage/shared-embedding-cache.d.ts.map +1 -0
  70. package/dist/storage/shared-embedding-cache.js +120 -0
  71. package/dist/storage/shared-embedding-cache.js.map +1 -0
  72. package/dist/storage/sqlite-index-store.d.ts +89 -0
  73. package/dist/storage/sqlite-index-store.d.ts.map +1 -0
  74. package/dist/storage/sqlite-index-store.js +593 -0
  75. package/dist/storage/sqlite-index-store.js.map +1 -0
  76. package/dist/tools/index-tools/file-indexer.js +19 -19
  77. package/dist/tools/index-tools/file-indexer.js.map +1 -1
  78. package/dist/tools/index-tools/folder-indexer.d.ts.map +1 -1
  79. package/dist/tools/index-tools/folder-indexer.js +29 -1
  80. package/dist/tools/index-tools/folder-indexer.js.map +1 -1
  81. package/dist/tools/index-tools/folder-merge.d.ts.map +1 -1
  82. package/dist/tools/index-tools/folder-merge.js +47 -1
  83. package/dist/tools/index-tools/folder-merge.js.map +1 -1
  84. package/dist/tools/index-tools/parse.d.ts.map +1 -1
  85. package/dist/tools/index-tools/parse.js +10 -3
  86. package/dist/tools/index-tools/parse.js.map +1 -1
  87. package/dist/tools/index-tools/registry.d.ts.map +1 -1
  88. package/dist/tools/index-tools/registry.js +47 -1
  89. package/dist/tools/index-tools/registry.js.map +1 -1
  90. package/dist/tools/index-tools/types.d.ts +7 -0
  91. package/dist/tools/index-tools/types.d.ts.map +1 -1
  92. package/dist/tools/search-tools/ripgrep.d.ts.map +1 -1
  93. package/dist/tools/search-tools/ripgrep.js +32 -2
  94. package/dist/tools/search-tools/ripgrep.js.map +1 -1
  95. package/dist/tools/status-tools.d.ts +10 -0
  96. package/dist/tools/status-tools.d.ts.map +1 -1
  97. package/dist/tools/status-tools.js +57 -16
  98. package/dist/tools/status-tools.js.map +1 -1
  99. package/dist/tools/workspace-scope-helper.d.ts.map +1 -1
  100. package/dist/tools/workspace-scope-helper.js +8 -1
  101. package/dist/tools/workspace-scope-helper.js.map +1 -1
  102. package/dist/tools/workspace-tools.d.ts.map +1 -1
  103. package/dist/tools/workspace-tools.js +9 -1
  104. package/dist/tools/workspace-tools.js.map +1 -1
  105. package/dist/utils/loopback.d.ts +23 -0
  106. package/dist/utils/loopback.d.ts.map +1 -0
  107. package/dist/utils/loopback.js +71 -0
  108. package/dist/utils/loopback.js.map +1 -0
  109. package/dist/utils/walk/filters.d.ts.map +1 -1
  110. package/dist/utils/walk/filters.js +22 -1
  111. package/dist/utils/walk/filters.js.map +1 -1
  112. package/package.json +4 -1
@@ -1 +1 @@
1
- {"version":3,"file":"embedding-store.d.ts","sourceRoot":"","sources":["../../src/storage/embedding-store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGjD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE9D;AAOD;;;GAGG;AACH,wBAAsB,cAAc,CAClC,aAAa,EAAE,MAAM,EACrB,QAAQ,GAAE,MAAiC,GAC1C,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CA0FpC;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,GACpC,OAAO,CAAC,IAAI,CAAC,CAmCf;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC,IAAI,CAAC,CAGf;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAgB/B;AAeD;;;;;;;;;;;GAWG;AACH,wBAAsB,UAAU,CAC9B,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAChC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,EACnC,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,EACjD,SAAS,EAAE,MAAM,EACjB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CA2CpC"}
1
+ {"version":3,"file":"embedding-store.d.ts","sourceRoot":"","sources":["../../src/storage/embedding-store.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIjD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAE9D;AAkCD,4EAA4E;AAC5E,wBAAgB,oBAAoB,CAAC,aAAa,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAE/E;AAED,wBAAsB,cAAc,CAClC,aAAa,EAAE,MAAM,EACrB,QAAQ,GAAE,MAAiC,GAC1C,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAgGpC;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,EACrC,MAAM,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GACnC,OAAO,CAAC,IAAI,CAAC,CAsCf;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC,IAAI,CAAC,CAGf;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAgB/B;AAeD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAK9F;AAED,gFAAgF;AAChF,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAE9E;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,UAAU,CAC9B,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAChC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,EACnC,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,EACjD,SAAS,EAAE,MAAM,EACjB,QAAQ,CAAC,EAAE,MAAM;AACjB;;;;;;GAMG;AACH,WAAW,CAAC,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAClD,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAwEpC"}
@@ -1,4 +1,5 @@
1
1
  import { readFile } from "node:fs/promises";
2
+ import { loadSharedCache, appendSharedCache, contentKey } from "./shared-embedding-cache.js";
2
3
  import { atomicWriteFile, cleanupOrphanTempFiles } from "./_shared.js";
3
4
  /**
4
5
  * Get the embedding file path from an index path.
@@ -18,8 +19,22 @@ export function getEmbeddingMetaPath(indexPath) {
18
19
  * Load all embeddings from an ndjson file.
19
20
  * Returns a Map of symbolId → Float32Array vector.
20
21
  */
22
+ /**
23
+ * Content hashes read alongside the vectors on the last load of a given path.
24
+ *
25
+ * Keyed by path rather than repo name because that is what the loader knows.
26
+ * Populated as a side effect of `loadEmbeddings` — the data is already on the
27
+ * line, so collecting it costs nothing extra.
28
+ */
29
+ const loadedContentHashes = new Map();
30
+ /** Content hashes that came with the vectors at `embeddingPath`, if any. */
31
+ export function contentHashesForPath(embeddingPath) {
32
+ return loadedContentHashes.get(embeddingPath) ?? new Map();
33
+ }
21
34
  export async function loadEmbeddings(embeddingPath, maxBytes = Number.POSITIVE_INFINITY) {
22
35
  const embeddings = new Map();
36
+ const hashes = new Map();
37
+ loadedContentHashes.set(embeddingPath, hashes);
23
38
  // Stream line-by-line rather than readFile-ing the whole file into one string:
24
39
  // embedding files are GB-scale (e.g. 4.5GB), so a single slurp spikes the heap
25
40
  // by the full file size at load. readline keeps peak memory to one line plus
@@ -86,12 +101,17 @@ export async function loadEmbeddings(embeddingPath, maxBytes = Number.POSITIVE_I
86
101
  if (residentBytes > maxBytes) {
87
102
  overBudget = true;
88
103
  embeddings.clear();
104
+ // Hashes describe vectors we are dropping; keeping them would let
105
+ // batchEmbed believe those symbols are still covered.
106
+ hashes.clear();
89
107
  rl.close();
90
108
  stream.destroy();
91
109
  resolve();
92
110
  return;
93
111
  }
94
112
  embeddings.set(entry.id, vec);
113
+ if (typeof entry.h === "number")
114
+ hashes.set(entry.id, entry.h);
95
115
  }
96
116
  }
97
117
  catch {
@@ -110,7 +130,7 @@ export async function loadEmbeddings(embeddingPath, maxBytes = Number.POSITIVE_I
110
130
  * Save all embeddings to an ndjson file using streaming writes.
111
131
  * Avoids building a single huge string (30K+ symbols × 1536 floats = >300MB).
112
132
  */
113
- export async function saveEmbeddings(embeddingPath, embeddings) {
133
+ export async function saveEmbeddings(embeddingPath, embeddings, hashes) {
114
134
  // Sweep orphans from earlier runs that were killed mid-write. These files are
115
135
  // never overwritten (the name carries a timestamp), so without this they
116
136
  // accumulate indefinitely — see cleanupOrphanTempFiles.
@@ -125,7 +145,8 @@ export async function saveEmbeddings(embeddingPath, embeddings) {
125
145
  for (const [id, vec] of embeddings) {
126
146
  if (streamError)
127
147
  throw streamError;
128
- const line = JSON.stringify({ id, vec: Array.from(vec) }) + "\n";
148
+ const h = hashes?.get(id);
149
+ const line = JSON.stringify(h === undefined ? { id, vec: Array.from(vec) } : { id, vec: Array.from(vec), h }) + "\n";
129
150
  const canContinue = stream.write(line);
130
151
  if (!canContinue) {
131
152
  await new Promise((resolve) => stream.once("drain", resolve));
@@ -187,6 +208,27 @@ function contentHash(text) {
187
208
  }
188
209
  /** Track content hashes so we re-embed when symbol content changes. */
189
210
  const embeddingContentHashes = new Map();
211
+ /**
212
+ * Seed the in-process hash map for `cacheKey` from what was persisted.
213
+ *
214
+ * This map used to start empty on every process, so `hashes.get(id)` was always
215
+ * undefined, every symbol compared as changed, and the entire corpus was
216
+ * re-embedded on each MCP server start — 4.18M symbols across 1,587 repos, and
217
+ * servers restart once per session.
218
+ */
219
+ export function primeContentHashes(cacheKey, hashes) {
220
+ if (hashes.size === 0)
221
+ return;
222
+ const target = embeddingContentHashes.get(cacheKey) ?? new Map();
223
+ for (const [id, h] of hashes)
224
+ if (!target.has(id))
225
+ target.set(id, h);
226
+ embeddingContentHashes.set(cacheKey, target);
227
+ }
228
+ /** Hashes currently known for `cacheKey`, for persisting beside the vectors. */
229
+ export function contentHashesFor(cacheKey) {
230
+ return embeddingContentHashes.get(cacheKey) ?? new Map();
231
+ }
190
232
  /**
191
233
  * Batch-embed symbols using the given provider, appending to existing embeddings.
192
234
  * Skips symbols whose ID exists AND content hash hasn't changed.
@@ -199,7 +241,15 @@ const embeddingContentHashes = new Map();
199
241
  * @param cacheKey - Optional key to track content hashes across calls
200
242
  * @returns Map of symbolId → Float32Array (existing + new)
201
243
  */
202
- export async function batchEmbed(symbolTexts, existing, embedFn, batchSize, cacheKey) {
244
+ export async function batchEmbed(symbolTexts, existing, embedFn, batchSize, cacheKey,
245
+ /**
246
+ * Model identity for the cross-repo cache. A vector is a pure function of
247
+ * (model, dimensions, text), so the same text embedded for a second repo can
248
+ * be looked up instead of recomputed — which is what makes indexing a
249
+ * worktree cheap rather than a full duplicate pass. Omitted (CLI paths,
250
+ * tests) disables the shared lookup and behaves exactly as before.
251
+ */
252
+ sharedModel) {
203
253
  const result = new Map(existing);
204
254
  const hashes = cacheKey ? (embeddingContentHashes.get(cacheKey) ?? new Map()) : new Map();
205
255
  // Find symbols that need embedding (new or content changed)
@@ -212,6 +262,29 @@ export async function batchEmbed(symbolTexts, existing, embedFn, batchSize, cach
212
262
  }
213
263
  hashes.set(id, hash);
214
264
  }
265
+ // Cross-repo lookup before calling the model. Half of the symbols still
266
+ // queued for embedding on this machine live in worktrees or temp copies whose
267
+ // text is byte-identical to a repo already embedded; those become a hash
268
+ // lookup here instead of a model call.
269
+ const shared = sharedModel ? await loadSharedCache() : null;
270
+ const freshlyEmbedded = [];
271
+ const stillToEmbed = [];
272
+ for (const item of toEmbed) {
273
+ if (!shared || !sharedModel) {
274
+ stillToEmbed.push(item);
275
+ continue;
276
+ }
277
+ const key = contentKey(sharedModel.model, sharedModel.dimensions, item.text);
278
+ const hit = shared.get(key);
279
+ if (hit) {
280
+ result.set(item.id, hit);
281
+ }
282
+ else {
283
+ stillToEmbed.push({ ...item, key });
284
+ }
285
+ }
286
+ toEmbed.length = 0;
287
+ toEmbed.push(...stillToEmbed);
215
288
  // Process in batches (only symbols that need embedding)
216
289
  for (let i = 0; i < toEmbed.length; i += batchSize) {
217
290
  const batch = toEmbed.slice(i, i + batchSize);
@@ -221,7 +294,11 @@ export async function batchEmbed(symbolTexts, existing, embedFn, batchSize, cach
221
294
  const entry = batch[j];
222
295
  const vec = vectors[j];
223
296
  if (entry && vec) {
224
- result.set(entry.id, new Float32Array(vec));
297
+ const f32 = new Float32Array(vec);
298
+ result.set(entry.id, f32);
299
+ const key = entry.key;
300
+ if (key)
301
+ freshlyEmbedded.push({ key, vec: f32 });
225
302
  }
226
303
  }
227
304
  }
@@ -234,6 +311,10 @@ export async function batchEmbed(symbolTexts, existing, embedFn, batchSize, cach
234
311
  if (cacheKey) {
235
312
  embeddingContentHashes.set(cacheKey, hashes);
236
313
  }
314
+ // Publish what was computed so the NEXT repo containing this text — a sibling
315
+ // worktree, a temp copy — gets it for free.
316
+ if (sharedModel)
317
+ appendSharedCache(freshlyEmbedded);
237
318
  return result;
238
319
  }
239
320
  //# sourceMappingURL=embedding-store.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"embedding-store.js","sourceRoot":"","sources":["../../src/storage/embedding-store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"embedding-store.js","sourceRoot":"","sources":["../../src/storage/embedding-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAC7F,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAEvE;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,SAAiB;IAChD,OAAO,SAAS,CAAC,OAAO,CAAC,gBAAgB,EAAE,oBAAoB,CAAC,CAAC;AACnE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,SAAiB;IACpD,OAAO,SAAS,CAAC,OAAO,CAAC,gBAAgB,EAAE,uBAAuB,CAAC,CAAC;AACtE,CAAC;AAqBD;;;GAGG;AACH;;;;;;GAMG;AACH,MAAM,mBAAmB,GAAG,IAAI,GAAG,EAA+B,CAAC;AAEnE,4EAA4E;AAC5E,MAAM,UAAU,oBAAoB,CAAC,aAAqB;IACxD,OAAO,mBAAmB,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,IAAI,GAAG,EAAkB,CAAC;AAC7E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,aAAqB,EACrB,QAAQ,GAAW,MAAM,CAAC,iBAAiB;IAE3C,MAAM,UAAU,GAAG,IAAI,GAAG,EAAwB,CAAC;IACnD,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;IACzC,mBAAmB,CAAC,GAAG,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;IAE/C,+EAA+E;IAC/E,+EAA+E;IAC/E,6EAA6E;IAC7E,iCAAiC;IACjC,MAAM,EAAE,gBAAgB,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;IAC3E,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,CAAC;IAE1D,gFAAgF;IAChF,mEAAmE;IACnE,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC;QAAE,OAAO,UAAU,CAAC;IAElD,+EAA+E;IAC/E,gFAAgF;IAChF,gFAAgF;IAChF,iFAAiF;IACjF,uEAAuE;IACvE,EAAE;IACF,iFAAiF;IACjF,iFAAiF;IACjF,+EAA+E;IAC/E,8EAA8E;IAC9E,iFAAiF;IACjF,+EAA+E;IAC/E,6EAA6E;IAC7E,MAAM,sBAAsB,GAAG,CAAC,CAAC;IACjC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC;QAC1C,IAAI,IAAI,GAAG,QAAQ,GAAG,sBAAsB,EAAE,CAAC;YAC7C,OAAO,CAAC,KAAK,CACX,kCAAkC,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ;gBAC/D,GAAG,CAAC,QAAQ,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,6CAA6C;gBAC3E,iDAAiD,CACpD,CAAC;YACF,OAAO,UAAU,CAAC;QACpB,CAAC;IACH,CAAC;IAAC,MAAM,CAAC,CAAC,yEAAyE,CAAC,CAAC;IAErF,+EAA+E;IAC/E,0EAA0E;IAC1E,gFAAgF;IAChF,yEAAyE;IACzE,IAAI,aAAa,GAAG,CAAC,CAAC;IACtB,IAAI,UAAU,GAAG,KAAK,CAAC;IACvB,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;QAClC,IAAI,MAAoC,CAAC;QACzC,IAAI,CAAC;YACH,MAAM,GAAG,gBAAgB,CAAC,aAAa,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;QAClE,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,CAAC;YACV,OAAO;QACT,CAAC;QACD,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,8CAA8C;QACnF,MAAM,EAAE,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC;QACnE,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;QAChC,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;YACrB,IAAI,UAAU;gBAAE,OAAO;YACvB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YAC5B,IAAI,CAAC,OAAO;gBAAE,OAAO;YACrB,IAAI,CAAC;gBACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAkB,CAAC;gBACnD,IAAI,KAAK,CAAC,EAAE,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;oBACzC,MAAM,GAAG,GAAG,IAAI,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;oBACxC,aAAa,IAAI,GAAG,CAAC,UAAU,GAAG,KAAK,CAAC,EAAE,CAAC,MAAM,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,8BAA8B;oBAC1F,IAAI,aAAa,GAAG,QAAQ,EAAE,CAAC;wBAC7B,UAAU,GAAG,IAAI,CAAC;wBAClB,UAAU,CAAC,KAAK,EAAE,CAAC;wBACnB,kEAAkE;wBAClE,sDAAsD;wBACtD,MAAM,CAAC,KAAK,EAAE,CAAC;wBACf,EAAE,CAAC,KAAK,EAAE,CAAC;wBACX,MAAM,CAAC,OAAO,EAAE,CAAC;wBACjB,OAAO,EAAE,CAAC;wBACV,OAAO;oBACT,CAAC;oBACD,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;oBAC9B,IAAI,OAAO,KAAK,CAAC,CAAC,KAAK,QAAQ;wBAAE,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;gBACjE,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,uBAAuB;YACzB,CAAC;QACH,CAAC,CAAC,CAAC;QACH,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CACX,2CAA2C,CAAC,QAAQ,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM;YAC1E,iDAAiD,CACpD,CAAC;IACJ,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,aAAqB,EACrB,UAAqC,EACrC,MAAoC;IAEpC,8EAA8E;IAC9E,yEAAyE;IACzE,wDAAwD;IACxD,MAAM,sBAAsB,CAAC,aAAa,CAAC,CAAC;IAE5C,MAAM,OAAO,GAAG,GAAG,aAAa,QAAQ,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;IACrD,MAAM,EAAE,iBAAiB,EAAE,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;IACtD,MAAM,MAAM,GAAG,iBAAiB,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;IAEjE,uEAAuE;IACvE,IAAI,WAAW,GAAiB,IAAI,CAAC;IACrC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,GAAG,WAAW,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAEpD,IAAI,CAAC;QACH,KAAK,MAAM,CAAC,EAAE,EAAE,GAAG,CAAC,IAAI,UAAU,EAAE,CAAC;YACnC,IAAI,WAAW;gBAAE,MAAM,WAAW,CAAC;YACnC,MAAM,CAAC,GAAG,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;YAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CACzB,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CACjF,GAAG,IAAI,CAAC;YACT,MAAM,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACvC,IAAI,CAAC,WAAW,EAAE,CAAC;gBACjB,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;YACtE,CAAC;QACH,CAAC;QACD,IAAI,WAAW;YAAE,MAAM,WAAW,CAAC;QACnC,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC1C,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;QAClE,CAAC,CAAC,CAAC;QACH,gBAAgB;QAChB,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC;QACpD,MAAM,MAAM,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;IACvC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,8BAA8B;QAC9B,IAAI,CAAC;YAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC;YAAC,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;QAC1G,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,QAAgB,EAChB,IAAmB;IAEnB,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,eAAe,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;AACxC,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,QAAgB;IAEhB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC9C,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAExC,IACE,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI;YAC7C,OAAQ,MAAkC,CAAC,OAAO,CAAC,KAAK,QAAQ;YAChE,OAAQ,MAAkC,CAAC,YAAY,CAAC,KAAK,QAAQ,EACrE,CAAC;YACD,OAAO,MAAuB,CAAC;QACjC,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,gEAAgE;AAChE,SAAS,WAAW,CAAC,IAAY;IAC/B,IAAI,CAAC,GAAG,UAAU,CAAC;IACnB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QACxB,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;IAC/B,CAAC;IACD,OAAO,CAAC,KAAK,CAAC,CAAC;AACjB,CAAC;AAED,uEAAuE;AACvE,MAAM,sBAAsB,GAAG,IAAI,GAAG,EAA+B,CAAC;AAEtE;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAAC,QAAgB,EAAE,MAAmC;IACtF,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO;IAC9B,MAAM,MAAM,GAAG,sBAAsB,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,IAAI,GAAG,EAAkB,CAAC;IACjF,KAAK,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,MAAM;QAAE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;IACrE,sBAAsB,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;AAC/C,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAC/C,OAAO,sBAAsB,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,IAAI,GAAG,EAAkB,CAAC;AAC3E,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,WAAgC,EAChC,QAAmC,EACnC,OAAiD,EACjD,SAAiB,EACjB,QAAiB;AACjB;;;;;;GAMG;AACH,WAAmD;IAEnD,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC;IACjC,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,sBAAsB,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,IAAI,GAAG,EAAkB,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,EAAkB,CAAC;IAE1H,4DAA4D;IAC5D,MAAM,OAAO,GAAwC,EAAE,CAAC;IACxD,KAAK,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI,WAAW,EAAE,CAAC;QACrC,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;QAC/B,MAAM,UAAU,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,KAAK,SAAS,IAAI,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,IAAI,CAAC,CAAC;QAC5F,IAAI,UAAU,EAAE,CAAC;YACf,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7B,CAAC;QACD,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IACvB,CAAC;IAED,wEAAwE;IACxE,8EAA8E;IAC9E,yEAAyE;IACzE,uCAAuC;IACvC,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,MAAM,eAAe,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAC5D,MAAM,eAAe,GAA8C,EAAE,CAAC;IACtE,MAAM,YAAY,GAAsD,EAAE,CAAC;IAC3E,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;QAC3B,IAAI,CAAC,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;YAC5B,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACxB,SAAS;QACX,CAAC;QACD,MAAM,GAAG,GAAG,UAAU,CAAC,WAAW,CAAC,KAAK,EAAE,WAAW,CAAC,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7E,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,GAAG,EAAE,CAAC;YACR,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;QAC3B,CAAC;aAAM,CAAC;YACN,YAAY,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IACD,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;IACnB,OAAO,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,CAAC;IAE9B,wDAAwD;IACxD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,IAAI,SAAS,EAAE,CAAC;QACnD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC;QAC9C,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAEvC,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC;QAErC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACtC,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YACvB,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;YACvB,IAAI,KAAK,IAAI,GAAG,EAAE,CAAC;gBACjB,MAAM,GAAG,GAAG,IAAI,YAAY,CAAC,GAAG,CAAC,CAAC;gBAClC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;gBAC1B,MAAM,GAAG,GAAI,KAA0B,CAAC,GAAG,CAAC;gBAC5C,IAAI,GAAG;oBAAE,eAAe,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;YACnD,CAAC;QACH,CAAC;IACH,CAAC;IAED,mEAAmE;IACnE,MAAM,KAAK,GAAG,CAAC,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IACtE,KAAK,MAAM,EAAE,IAAI,KAAK,EAAE,CAAC;QACvB,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAClB,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACpB,CAAC;IAED,IAAI,QAAQ,EAAE,CAAC;QACb,sBAAsB,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC/C,CAAC;IACD,8EAA8E;IAC9E,4CAA4C;IAC5C,IAAI,WAAW;QAAE,iBAAiB,CAAC,eAAe,CAAC,CAAC;IAEpD,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -1,4 +1,11 @@
1
1
  import type { CodeIndex, CodeSymbol, FileEntry } from "../types.js";
2
+ export type IndexBackend = "json" | "sqlite";
3
+ export declare function resolveIndexBackend(): Promise<IndexBackend>;
4
+ export declare function resetIndexBackendForTesting(): void;
5
+ /** `<hash>.index.json` -> `<hash>.index.db`, so both formats sit side by side and the JSON
6
+ * stays available as the rollback artifact. */
7
+ export declare function sqlitePathFor(indexPath: string): string;
8
+ export declare function resetMigrationCacheForTesting(): void;
2
9
  /**
3
10
  * Save a code index atomically.
4
11
  * Writes to a temp file first, then renames to prevent partial reads.
@@ -15,6 +22,21 @@ export declare function saveIndex(indexPath: string, index: CodeIndex): Promise<
15
22
  * where version enforcement would cause spurious reindexes.
16
23
  */
17
24
  export declare function loadIndex(indexPath: string, currentVersions?: Record<string, string>): Promise<CodeIndex | null>;
25
+ /**
26
+ * One file's `files[]` entry.
27
+ *
28
+ * This is the accessor ADR-003 exists for. `file-indexer` needs a single file's `mtime_ms`
29
+ * and `symbol_count` to decide whether an edit changed anything, and used to obtain them by
30
+ * loading the entire index — a 262 MB parse on tgm-survey-platform, paid on the first touch
31
+ * of every file, in a hook process that exits immediately afterwards and so can never reuse
32
+ * the result. Under SQLite it is one indexed row.
33
+ *
34
+ * The JSON backend keeps the old cost; there is no way to read one record out of a blob.
35
+ */
36
+ export declare function getFileEntry(indexPath: string, filePath: string): Promise<FileEntry | undefined>;
37
+ export declare function resetIndexCacheForTesting(): void;
38
+ export declare function getIndexCacheSizeForTesting(): number;
39
+ export declare function resetStaleRollbackWarningForTesting(): void;
18
40
  /** Discriminated union returned by loadIndexOrStale: distinguishes a healthy
19
41
  * load from a version-mismatch stale-index case. Tools route through this
20
42
  * helper instead of calling loadIndex directly so stale indexes surface as
@@ -23,6 +45,15 @@ export declare function loadIndex(indexPath: string, currentVersions?: Record<st
23
45
  export type IndexOrStaleResult = {
24
46
  status: "ok";
25
47
  index: CodeIndex;
48
+ } | {
49
+ /** The store exists but could not be read — locked, corrupt, unreadable. Distinct from a
50
+ * null return, which means "nothing is indexed here". A caller that treats this as an
51
+ * empty index reports a confident, wrong "no results". */
52
+ status: "unreadable";
53
+ reason: "storage_error";
54
+ /** SQLITE_* / errno code, for operators and for deciding whether a retry is sane. */
55
+ code: string;
56
+ message: string;
26
57
  } | {
27
58
  status: "stale";
28
59
  reason: "extractor_version_mismatch";
@@ -1 +1 @@
1
- {"version":3,"file":"index-store.d.ts","sourceRoot":"","sources":["../../src/storage/index-store.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAMpE;;;GAGG;AACH,wBAAsB,SAAS,CAC7B,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,SAAS,GACf,OAAO,CAAC,IAAI,CAAC,CAGf;AAED;;;;;;;;;GASG;AACH,wBAAsB,SAAS,CAC7B,SAAS,EAAE,MAAM,EACjB,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACvC,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAiB3B;AAED;;;;4BAI4B;AAC5B,MAAM,MAAM,kBAAkB,GAC1B;IAAE,MAAM,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,SAAS,CAAA;CAAE,GAClC;IACE,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,4BAA4B,CAAC;IACrC,+EAA+E;IAC/E,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB;sFACkF;IAClF,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEN,MAAM,MAAM,2BAA2B,GAAG;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;qEAEqE;AACrE,wBAAgB,iCAAiC,CAC/C,KAAK,EAAE,SAAS,EAChB,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACtC,2BAA2B,EAAE,CAmC/B;AAED;;;;;;;;;;;;;;;;wCAgBwC;AACxC,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,MAAM,EACjB,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACtC,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CA8BpC;AAED;;;;;;;;;GASG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,SAAS,EAChB,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACtC,OAAO,CAGT;AAyBD,wBAAgB,4BAA4B,IAAI,MAAM,CAErD;AACD,wBAAgB,8BAA8B,IAAI,IAAI,CAErD;AAoFD;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,UAAU,EAAE,EACxB,SAAS,CAAC,EAAE,SAAS,GACpB,OAAO,CAAC,IAAI,CAAC,CAiBf;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC,CAYf;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAOtE"}
1
+ {"version":3,"file":"index-store.d.ts","sourceRoot":"","sources":["../../src/storage/index-store.ts"],"names":[],"mappings":"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"}
@@ -1,14 +1,100 @@
1
1
  import { readFile } from "node:fs/promises";
2
+ import { statSync } from "node:fs";
2
3
  import { join } from "node:path";
3
4
  import { createHash } from "node:crypto";
4
5
  import { atomicWriteFile } from "./_shared.js";
6
+ import { isSqliteAvailable, loadIndexSqlite, saveIndexSqlite, saveIncrementalSqlite, removeFileFromIndexSqlite, getFileEntrySqlite, getDataVersion, importLegacyIndexIfEmpty, classifyStorageError, IndexStorageError, } from "./sqlite-index-store.js";
5
7
  /** Serialize concurrent writes to the same index path. */
6
8
  const writeLocks = new Map();
9
+ /**
10
+ * Which on-disk format to use.
11
+ *
12
+ * `CODESIFT_INDEX_BACKEND=json` pins the legacy path (the documented rollback);
13
+ * `=sqlite` demands the new one and fails loudly if `node:sqlite` is missing, so a CI run
14
+ * cannot quietly exercise the wrong backend. Unset auto-detects, which is what keeps the
15
+ * `engines: >=20` floor honest: Node 20 has no `node:sqlite` and simply stays on JSON.
16
+ *
17
+ * Read from the environment here rather than `config.ts` because the choice must be
18
+ * resolvable from the short-lived `codesift postindex-file` hook process too, which never
19
+ * builds a full config.
20
+ */
21
+ let backendPromise;
22
+ export async function resolveIndexBackend() {
23
+ backendPromise ??= computeIndexBackend();
24
+ return backendPromise;
25
+ }
26
+ async function computeIndexBackend() {
27
+ const explicit = process.env["CODESIFT_INDEX_BACKEND"];
28
+ if (explicit === "json")
29
+ return "json";
30
+ if (explicit === "sqlite") {
31
+ if (!(await isSqliteAvailable())) {
32
+ throw new Error("CODESIFT_INDEX_BACKEND=sqlite but node:sqlite is unavailable (requires Node >= 22.5)");
33
+ }
34
+ return "sqlite";
35
+ }
36
+ return (await isSqliteAvailable()) ? "sqlite" : "json";
37
+ }
38
+ export function resetIndexBackendForTesting() {
39
+ backendPromise = undefined;
40
+ }
41
+ /** `<hash>.index.json` -> `<hash>.index.db`, so both formats sit side by side and the JSON
42
+ * stays available as the rollback artifact. */
43
+ export function sqlitePathFor(indexPath) {
44
+ return indexPath.endsWith(".json")
45
+ ? `${indexPath.slice(0, -".json".length)}.db`
46
+ : `${indexPath}.db`;
47
+ }
48
+ /** Guards one-time JSON->SQLite migration per index path. */
49
+ const migrations = new Map();
50
+ /**
51
+ * Bring an existing JSON index across on first touch.
52
+ *
53
+ * Deliberately non-destructive: the source `.json` is left in place. Deleting it would make
54
+ * `CODESIFT_INDEX_BACKEND=json` a one-way door, and the whole point of shipping a rollback
55
+ * switch is that it still has something to roll back to.
56
+ */
57
+ async function ensureSqliteMigrated(indexPath, dbPath) {
58
+ const inFlight = migrations.get(dbPath);
59
+ if (inFlight)
60
+ return inFlight;
61
+ const run = (async () => {
62
+ if ((await loadIndexSqlite(dbPath)) !== null)
63
+ return; // already migrated
64
+ const legacy = await loadJsonIndex(indexPath);
65
+ // importLegacyIndexIfEmpty re-checks emptiness under the write lock, so a second
66
+ // process that raced us here imports nothing instead of overwriting our rows.
67
+ if (legacy)
68
+ await importLegacyIndexIfEmpty(dbPath, legacy);
69
+ })();
70
+ migrations.set(dbPath, run);
71
+ try {
72
+ await run;
73
+ }
74
+ catch (err) {
75
+ // A failed migration is retried, not remembered as done — and we do NOT re-read the same
76
+ // failing database to decide that. Probing it again inside a `finally` would hit an
77
+ // already-struggling store a second time AND, if that probe throws too, JS try/finally
78
+ // semantics would replace the original error with the second one.
79
+ migrations.delete(dbPath);
80
+ throw err;
81
+ }
82
+ migrations.set(dbPath, Promise.resolve());
83
+ }
84
+ export function resetMigrationCacheForTesting() {
85
+ migrations.clear();
86
+ }
7
87
  /**
8
88
  * Save a code index atomically.
9
89
  * Writes to a temp file first, then renames to prevent partial reads.
10
90
  */
11
91
  export async function saveIndex(indexPath, index) {
92
+ if ((await resolveIndexBackend()) === "sqlite") {
93
+ const dbPath = sqlitePathFor(indexPath);
94
+ await saveIndexSqlite(dbPath, index);
95
+ invalidateIndexCache(dbPath);
96
+ return;
97
+ }
12
98
  const data = JSON.stringify(index);
13
99
  await atomicWriteFile(indexPath, data);
14
100
  }
@@ -23,19 +109,187 @@ export async function saveIndex(indexPath, index) {
23
109
  * where version enforcement would cause spurious reindexes.
24
110
  */
25
111
  export async function loadIndex(indexPath, currentVersions) {
26
- try {
27
- const raw = await readFile(indexPath, "utf-8");
28
- const parsed = JSON.parse(raw);
29
- if (!isValidIndex(parsed)) {
30
- return null;
112
+ const index = await readIndex(indexPath);
113
+ if (!index)
114
+ return null;
115
+ if (currentVersions && !isExtractorVersionCurrent(index, currentVersions))
116
+ return null;
117
+ return index;
118
+ }
119
+ /**
120
+ * One file's `files[]` entry.
121
+ *
122
+ * This is the accessor ADR-003 exists for. `file-indexer` needs a single file's `mtime_ms`
123
+ * and `symbol_count` to decide whether an edit changed anything, and used to obtain them by
124
+ * loading the entire index — a 262 MB parse on tgm-survey-platform, paid on the first touch
125
+ * of every file, in a hook process that exits immediately afterwards and so can never reuse
126
+ * the result. Under SQLite it is one indexed row.
127
+ *
128
+ * The JSON backend keeps the old cost; there is no way to read one record out of a blob.
129
+ */
130
+ export async function getFileEntry(indexPath, filePath) {
131
+ if ((await resolveIndexBackend()) === "sqlite") {
132
+ const dbPath = sqlitePathFor(indexPath);
133
+ await ensureSqliteMigrated(indexPath, dbPath);
134
+ return getFileEntrySqlite(dbPath, filePath);
135
+ }
136
+ const index = await loadJsonIndex(indexPath);
137
+ return index?.files.find((f) => f.path === filePath);
138
+ }
139
+ /**
140
+ * Bounded, LRU by insertion order. A materialised index is the largest object this process
141
+ * holds — the JSON equivalent is 262 MB on tgm-survey-platform — and `codesift serve` is a
142
+ * long-lived daemon that touches many repos. An unbounded map here would have been the one
143
+ * cache in this codebase without a ceiling, next to an embedding cache that is explicitly
144
+ * RAM-budgeted (`CODESIFT_MAX_EMBEDDING_MEM_MB`); that asymmetry is how the OOM reports
145
+ * documented in CLAUDE.md started.
146
+ */
147
+ // `|| 3` would be wrong here: an operator setting 0 to minimise memory would get 3, because
148
+ // 0 is falsy. Only a non-numeric value should fall back.
149
+ const MAX_CACHED_INDEXES = (() => {
150
+ const raw = process.env["CODESIFT_MAX_CACHED_INDEXES"];
151
+ const parsed = raw === undefined ? 3 : Number(raw);
152
+ return Math.max(1, Number.isNaN(parsed) ? 3 : parsed);
153
+ })();
154
+ const indexCache = new Map();
155
+ function cacheIndex(dbPath, entry) {
156
+ // Re-insert to move to the most-recent end of Map iteration order.
157
+ indexCache.delete(dbPath);
158
+ indexCache.set(dbPath, entry);
159
+ while (indexCache.size > MAX_CACHED_INDEXES) {
160
+ const oldest = indexCache.keys().next();
161
+ if (oldest.done)
162
+ break;
163
+ indexCache.delete(oldest.value);
164
+ }
165
+ }
166
+ /**
167
+ * Detach the two arrays callers actually touch.
168
+ *
169
+ * A bare `{...index}` only stops a caller REASSIGNING `files`/`symbols`; an in-place
170
+ * `push`/`sort`/`splice` would still hit the array the cache holds — and `data_version`
171
+ * cannot see an in-memory mutation, so the corruption would survive every later hit. The
172
+ * elements stay shared (symbols are treated as immutable records); this copies the two
173
+ * array containers, which is the boundary that was actually being crossed.
174
+ */
175
+ function copyIndex(index) {
176
+ return { ...index, files: [...index.files], symbols: [...index.symbols] };
177
+ }
178
+ function invalidateIndexCache(dbPath) {
179
+ indexCache.delete(dbPath);
180
+ }
181
+ export function resetIndexCacheForTesting() {
182
+ indexCache.clear();
183
+ }
184
+ export function getIndexCacheSizeForTesting() {
185
+ return indexCache.size;
186
+ }
187
+ /** Backend-agnostic read, without version enforcement. */
188
+ async function readIndex(indexPath) {
189
+ if ((await resolveIndexBackend()) === "sqlite") {
190
+ const dbPath = sqlitePathFor(indexPath);
191
+ await ensureSqliteMigrated(indexPath, dbPath);
192
+ const dataVersion = await getDataVersion(dbPath);
193
+ const cached = indexCache.get(dbPath);
194
+ if (cached && cached.dataVersion === dataVersion) {
195
+ // Re-insert on HIT too, or the eviction order is FIFO-by-first-load rather than LRU:
196
+ // the hottest repo would be evicted the moment an (N+1)th repo is touched, while a
197
+ // repo read once and never again outlives it. That thrashes exactly the working set
198
+ // the cache exists to keep warm.
199
+ cacheIndex(dbPath, cached);
200
+ return copyIndex(cached.index);
31
201
  }
32
- if (currentVersions && !isExtractorVersionCurrent(parsed, currentVersions)) {
202
+ const index = await loadIndexSqlite(dbPath);
203
+ if (!index)
33
204
  return null;
205
+ cacheIndex(dbPath, { index, dataVersion });
206
+ // Copy on the miss path too: returning the freshly-cached object itself would let the
207
+ // very first caller mutate the entry every later reader is about to be handed.
208
+ return copyIndex(index);
209
+ }
210
+ warnIfRollbackIsStale(indexPath);
211
+ return loadJsonIndex(indexPath);
212
+ }
213
+ /**
214
+ * Warn when the JSON backend is serving a snapshot that SQLite has since moved past.
215
+ *
216
+ * The rollback switch keeps the `.json` untouched, which is what makes rolling back possible
217
+ * — and also means that after a repo has run on SQLite for a while, the JSON is a frozen
218
+ * snapshot from migration day. Falling back to it then answers every query from a stale index
219
+ * with no error and no empty result: the shape is valid, the extractor versions still match,
220
+ * it is simply old. That is the worst failure mode we have (confidently wrong), so it gets a
221
+ * loud one-time line rather than silence.
222
+ */
223
+ const staleRollbackWarned = new Set();
224
+ function warnIfRollbackIsStale(indexPath) {
225
+ if (staleRollbackWarned.has(indexPath))
226
+ return;
227
+ try {
228
+ // Mark only once a real comparison happened. Marking up front would permanently silence
229
+ // the warning for a long-lived JSON-pinned process that read this repo before any `.db`
230
+ // existed — precisely the process that most needs telling when one appears later.
231
+ const dbStat = statSync(sqlitePathFor(indexPath));
232
+ const jsonStat = statSync(indexPath);
233
+ staleRollbackWarned.add(indexPath);
234
+ if (dbStat.mtimeMs <= jsonStat.mtimeMs)
235
+ return;
236
+ const ageHours = Math.round((dbStat.mtimeMs - jsonStat.mtimeMs) / 3_600_000);
237
+ console.error(`[codesift] WARNING: reading the legacy JSON index at ${indexPath}, but a SQLite index ` +
238
+ `updated ~${ageHours}h more recently exists alongside it. Every answer from this repo ` +
239
+ `is from the pre-rollback snapshot. Run index_folder to rebuild the JSON index, or ` +
240
+ `unset CODESIFT_INDEX_BACKEND to go back to SQLite.`);
241
+ }
242
+ catch {
243
+ /* no .db, or unreadable — nothing to compare against, so nothing to warn about */
244
+ }
245
+ }
246
+ export function resetStaleRollbackWarningForTesting() {
247
+ staleRollbackWarned.clear();
248
+ }
249
+ /**
250
+ * Codes that genuinely mean "there is no index file here". Everything else that `readFile` can
251
+ * fail with — EISDIR, ENOTDIR, ENAMETOOLONG, ELOOP, platform-specific I/O errors — describes a
252
+ * path that is wrong or unreadable, not a repo that was never indexed. Reporting those as
253
+ * absence is the same misdiagnosis this change exists to remove, one layer down.
254
+ */
255
+ const ABSENCE_CODES = new Set(["ENOENT", "ENOTDIR_PARENT"]);
256
+ function nonAbsenceReadCode(err) {
257
+ const code = typeof err === "object" && err !== null ? err.code : undefined;
258
+ // No recognisable code at all: this is NOT evidence of absence. Only an explicit ENOENT is.
259
+ // Defaulting the unknown case to "nothing indexed here" is how a real fault becomes a
260
+ // confident empty answer — the whole failure mode being removed.
261
+ if (typeof code !== "string")
262
+ return "UNKNOWN_READ_ERROR";
263
+ return ABSENCE_CODES.has(code) ? null : code;
264
+ }
265
+ /**
266
+ * The legacy path, kept intact: it is both the Node 20 backend and the rollback target.
267
+ *
268
+ * ENOENT is absence and stays `null`; a malformed document is also `null` (an invalid index is
269
+ * rebuildable, which is the historical contract). But EACCES/EIO/EBUSY mean the file exists and
270
+ * we simply could not read it — reporting that as "no index" is how a permissions problem gets
271
+ * misdiagnosed as an unindexed repo.
272
+ */
273
+ async function loadJsonIndex(indexPath) {
274
+ let raw;
275
+ try {
276
+ raw = await readFile(indexPath, "utf-8");
277
+ }
278
+ catch (err) {
279
+ const code = classifyStorageError(err) ?? nonAbsenceReadCode(err);
280
+ if (code !== null) {
281
+ throw new IndexStorageError(`index storage at ${indexPath} is unreadable (${code}): ${err instanceof Error ? err.message : String(err)}`, code, indexPath, { cause: err });
34
282
  }
283
+ return null; // ENOENT and friends: nothing indexed here
284
+ }
285
+ try {
286
+ const parsed = JSON.parse(raw);
287
+ if (!isValidIndex(parsed))
288
+ return null;
35
289
  return parsed;
36
290
  }
37
291
  catch {
38
- return null;
292
+ return null; // malformed JSON is a rebuildable index, not a storage fault
39
293
  }
40
294
  }
41
295
  /** All languages whose stored `extractor_version` entry does not match
@@ -96,10 +350,23 @@ export function collectExtractorVersionMismatches(index, currentVersions) {
96
350
  * to `loadIndex(...)` returning null. Callers must still handle null (no
97
351
  * structured error) for those cases. */
98
352
  export async function loadIndexOrStale(indexPath, currentVersions) {
353
+ let parsed;
99
354
  try {
100
- const raw = await readFile(indexPath, "utf-8");
101
- const parsed = JSON.parse(raw);
102
- if (!isValidIndex(parsed))
355
+ parsed = await readIndex(indexPath);
356
+ }
357
+ catch (err) {
358
+ const code = classifyStorageError(err);
359
+ if (code === null)
360
+ throw err;
361
+ return {
362
+ status: "unreadable",
363
+ reason: "storage_error",
364
+ code,
365
+ message: err instanceof Error ? err.message : String(err),
366
+ };
367
+ }
368
+ try {
369
+ if (!parsed)
103
370
  return null;
104
371
  const mismatches = collectExtractorVersionMismatches(parsed, currentVersions);
105
372
  if (mismatches.length > 0) {
@@ -241,6 +508,15 @@ function enqueueIndexMutation(indexPath, missing, apply) {
241
508
  * Serialized per indexPath to prevent read-modify-write races.
242
509
  */
243
510
  export async function saveIncremental(indexPath, updatedFile, newSymbols, fileEntry) {
511
+ if ((await resolveIndexBackend()) === "sqlite") {
512
+ const dbPath = sqlitePathFor(indexPath);
513
+ await ensureSqliteMigrated(indexPath, dbPath);
514
+ // No mutation batching here on purpose: batching exists to amortise a whole-blob
515
+ // rewrite, and this backend writes one file's rows inside a transaction instead.
516
+ await saveIncrementalSqlite(dbPath, updatedFile, newSymbols, fileEntry);
517
+ invalidateIndexCache(dbPath);
518
+ return;
519
+ }
244
520
  return enqueueIndexMutation(indexPath, "throw", (existing) => {
245
521
  const filtered = existing.symbols.filter((symbol) => symbol.file !== updatedFile);
246
522
  const merged = [...filtered, ...newSymbols];
@@ -261,6 +537,13 @@ export async function saveIncremental(indexPath, updatedFile, newSymbols, fileEn
261
537
  * Serialized per indexPath to prevent read-modify-write races.
262
538
  */
263
539
  export async function removeFileFromIndex(indexPath, deletedFile) {
540
+ if ((await resolveIndexBackend()) === "sqlite") {
541
+ const dbPath = sqlitePathFor(indexPath);
542
+ await ensureSqliteMigrated(indexPath, dbPath);
543
+ await removeFileFromIndexSqlite(dbPath, deletedFile);
544
+ invalidateIndexCache(dbPath);
545
+ return;
546
+ }
264
547
  return enqueueIndexMutation(indexPath, "skip", (existing) => {
265
548
  const hadSymbols = existing.symbols.some((s) => s.file === deletedFile);
266
549
  const hadFile = existing.files.some((f) => f.path === deletedFile);