ctxloom-pro 1.7.7 → 1.7.9

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.
package/README.md CHANGED
@@ -69,7 +69,7 @@ The full first-run flow is **one install + one trial + one init per project.** E
69
69
  npm install -g ctxloom-pro
70
70
  ```
71
71
 
72
- > **For local trial / dev use the unpinned command above is fine.** For unattended CI usage, pin to the exact version (`ctxloom-pro@1.7.7`) so future CLI releases don't silently desync your agent-spec coverage — see the workflow example below.
72
+ > **For local trial / dev use the unpinned command above is fine.** For unattended CI usage, pin to the exact version (`ctxloom-pro@1.7.9`) so future CLI releases don't silently desync your agent-spec coverage — see the workflow example below.
73
73
 
74
74
  ### 2 — Start your free trial (once per email)
75
75
 
@@ -383,7 +383,7 @@ jobs:
383
383
  # Exact pin (not `@^1`) so future CLI releases that add/remove MCP
384
384
  # tools don't silently desync your reviewer-agent specs. Bump on
385
385
  # every release; see CHANGELOG.md for the live version table.
386
- - run: npm install -g ctxloom-pro@1.7.7
386
+ - run: npm install -g ctxloom-pro@1.7.9
387
387
  - run: ctxloom index
388
388
  - run: ctxloom rules check --json
389
389
  ```
@@ -2929,7 +2929,7 @@ var CallGraphIndex = class _CallGraphIndex {
2929
2929
  var TS_EXTENSIONS2 = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".vue"]);
2930
2930
  var PY_EXTENSIONS = /* @__PURE__ */ new Set([".py", ".ipynb"]);
2931
2931
  var AST_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".py", ".go", ".rs", ".java", ".cs", ".rb", ".kt", ".kts", ".swift", ".ipynb", ".php", ".dart"]);
2932
- var CTXLOOM_VERSION = "1.7.7".length > 0 ? "1.7.7" : "dev";
2932
+ var CTXLOOM_VERSION = "1.7.9".length > 0 ? "1.7.9" : "dev";
2933
2933
  var SNAPSHOT_SCHEMA_VERSION = 2;
2934
2934
  function compareCtxloomVersions(snapshotVer, currentVer) {
2935
2935
  if (snapshotVer === currentVer) return "same";
@@ -9113,6 +9113,9 @@ var NEVER = INVALID;
9113
9113
  var PROJECT_ROOT_DESCRIPTION = "Absolute path or registered alias of the project to operate on. Falls back to CTXLOOM_ROOT env, then server cwd. Register aliases with `ctxloom register <path> --alias <name>`.";
9114
9114
  var ProjectRootField = external_exports.string().optional().describe(PROJECT_ROOT_DESCRIPTION);
9115
9115
 
9116
+ // ../../packages/core/src/tools/status.ts
9117
+ init_VectorStore();
9118
+
9116
9119
  // ../../packages/core/src/tools/registry.ts
9117
9120
  init_logger();
9118
9121
 
@@ -12335,7 +12338,7 @@ function resolveTelemetryLevel() {
12335
12338
  }
12336
12339
  var TELEMETRY_LEVEL = resolveTelemetryLevel();
12337
12340
  var TELEMETRY_DISABLED = TELEMETRY_LEVEL === "off";
12338
- var CTXLOOM_VERSION2 = "1.7.7".length > 0 ? "1.7.7" : "dev";
12341
+ var CTXLOOM_VERSION2 = "1.7.9".length > 0 ? "1.7.9" : "dev";
12339
12342
  var POSTHOG_HOST = "https://eu.i.posthog.com";
12340
12343
  var POSTHOG_KEY = process.env["POSTHOG_API_KEY"] ?? (true ? "phc_CiDkmFLcZ2K6uCpcoSUQLmFrnnUvsyXGhSxopX5TVKE6" : "");
12341
12344
  var SENTRY_DSN = process.env["SENTRY_DSN"] ?? (true ? "https://81c94a0f04a8e242dee493ac1e17f733@o4508531702497280.ingest.de.sentry.io/4511256875368528" : "");
@@ -0,0 +1,11 @@
1
+ import {
2
+ VectorStore,
3
+ isCorruptionError
4
+ } from "./chunk-UWQKNIZO.js";
5
+ import "./chunk-XJJHX227.js";
6
+ import "./chunk-TYDMSHV7.js";
7
+ export {
8
+ VectorStore,
9
+ isCorruptionError
10
+ };
11
+ //# sourceMappingURL=VectorStore-ZA4EEL6C.js.map
@@ -1,11 +1,12 @@
1
1
  import {
2
- VectorStore
3
- } from "./chunk-XQEQLXY5.js";
2
+ VectorStore,
3
+ isCorruptionError
4
+ } from "./chunk-UWQKNIZO.js";
4
5
  import {
5
6
  collectFiles,
6
7
  generateEmbedding,
7
8
  isIgnoredDir
8
- } from "./chunk-JZOJC3S7.js";
9
+ } from "./chunk-XJJHX227.js";
9
10
  import {
10
11
  diskSink,
11
12
  readEvents
@@ -2705,7 +2706,7 @@ var CallGraphIndex = class _CallGraphIndex {
2705
2706
  var TS_EXTENSIONS2 = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".vue"]);
2706
2707
  var PY_EXTENSIONS = /* @__PURE__ */ new Set([".py", ".ipynb"]);
2707
2708
  var AST_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".py", ".go", ".rs", ".java", ".cs", ".rb", ".kt", ".kts", ".swift", ".ipynb", ".php", ".dart"]);
2708
- var CTXLOOM_VERSION = "1.7.7".length > 0 ? "1.7.7" : "dev";
2709
+ var CTXLOOM_VERSION = "1.7.9".length > 0 ? "1.7.9" : "dev";
2709
2710
  var SNAPSHOT_SCHEMA_VERSION = 2;
2710
2711
  function compareCtxloomVersions(snapshotVer, currentVer) {
2711
2712
  if (snapshotVer === currentVer) return "same";
@@ -5341,7 +5342,7 @@ var ProjectRootField = z.string().optional().describe(PROJECT_ROOT_DESCRIPTION);
5341
5342
  function escapeXML2(text) {
5342
5343
  return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
5343
5344
  }
5344
- function renderStatusXml(input) {
5345
+ async function renderStatusXml(input) {
5345
5346
  const { defaultRoot, manager, registry } = input;
5346
5347
  const lines = ["<ctx_status>"];
5347
5348
  if (defaultRoot) {
@@ -5361,9 +5362,21 @@ function renderStatusXml(input) {
5361
5362
  const reg = registry.list().find((r) => r.root === s.projectRoot);
5362
5363
  const alias = reg?.alias ? ` alias="${escapeXML2(reg.alias)}"` : "";
5363
5364
  const graphState = s.graphInitialized ? "ready" : s.graphPromise ? "building" : "cold";
5364
- const vectorsState = s.vectorsInitialized ? "ready" : s.storePromise ? "building" : "cold";
5365
+ let vectorsState = s.vectorsInitialized ? "ready" : s.storePromise ? "building" : "cold";
5366
+ let vectorsHint = "";
5367
+ if (s.vectorsInitialized && s.storePromise) {
5368
+ try {
5369
+ const store = await s.storePromise;
5370
+ await store.probe();
5371
+ } catch (probeErr) {
5372
+ if (isCorruptionError(probeErr)) {
5373
+ vectorsState = "corrupt";
5374
+ vectorsHint = ' vectors_hint="run: ctxloom vectors-cleanup &amp;&amp; ctxloom index"';
5375
+ }
5376
+ }
5377
+ }
5365
5378
  lines.push(
5366
- ` <project root="${escapeXML2(s.projectRoot)}"${alias} pinned="${s.pinned}" graph="${graphState}" vectors="${vectorsState}" last_touched_at="${new Date(s.lastTouchedAt).toISOString()}" />`
5379
+ ` <project root="${escapeXML2(s.projectRoot)}"${alias} pinned="${s.pinned}" graph="${graphState}" vectors="${vectorsState}"${vectorsHint} last_touched_at="${new Date(s.lastTouchedAt).toISOString()}" />`
5367
5380
  );
5368
5381
  }
5369
5382
  lines.push(" </active_projects>");
@@ -5394,7 +5407,7 @@ function registerStatusTool(registry, ctx) {
5394
5407
  async (args) => {
5395
5408
  const { project_root } = Schema31.parse(args ?? {});
5396
5409
  void project_root;
5397
- return renderStatusXml({
5410
+ return await renderStatusXml({
5398
5411
  defaultRoot: ctx.noDefaultMode ? null : ctx.projectRoot,
5399
5412
  manager: ctx.stateManager,
5400
5413
  registry: ctx.registry
@@ -8867,7 +8880,7 @@ function registerFullTextSearchTool(registry, ctx) {
8867
8880
  };
8868
8881
  if (mode === "semantic") {
8869
8882
  try {
8870
- const { generateEmbedding: generateEmbedding2 } = await import("./embedder-4MM7D3UE.js");
8883
+ const { generateEmbedding: generateEmbedding2 } = await import("./embedder-WQMRK5T7.js");
8871
8884
  const store = await ctx.getStore(project_root);
8872
8885
  const embedding = await generateEmbedding2(query);
8873
8886
  const results = await store.search(embedding, limit);
@@ -8905,7 +8918,7 @@ function registerFullTextSearchTool(registry, ctx) {
8905
8918
  let merged = keywordResults.slice(0, limit);
8906
8919
  if (mode === "hybrid") {
8907
8920
  try {
8908
- const { generateEmbedding: generateEmbedding2 } = await import("./embedder-4MM7D3UE.js");
8921
+ const { generateEmbedding: generateEmbedding2 } = await import("./embedder-WQMRK5T7.js");
8909
8922
  const store = await ctx.getStore(project_root);
8910
8923
  const embedding = await generateEmbedding2(query);
8911
8924
  const vectorResults = await store.search(embedding, Math.ceil(limit / 2));
@@ -11142,7 +11155,7 @@ var TELEMETRY_DISABLED = TELEMETRY_LEVEL === "off";
11142
11155
  function getTelemetryLevel() {
11143
11156
  return TELEMETRY_LEVEL;
11144
11157
  }
11145
- var CTXLOOM_VERSION2 = "1.7.7".length > 0 ? "1.7.7" : "dev";
11158
+ var CTXLOOM_VERSION2 = "1.7.9".length > 0 ? "1.7.9" : "dev";
11146
11159
  var POSTHOG_HOST = "https://eu.i.posthog.com";
11147
11160
  var POSTHOG_KEY = process.env["POSTHOG_API_KEY"] ?? (true ? "phc_CiDkmFLcZ2K6uCpcoSUQLmFrnnUvsyXGhSxopX5TVKE6" : "");
11148
11161
  var SENTRY_DSN = process.env["SENTRY_DSN"] ?? (true ? "https://81c94a0f04a8e242dee493ac1e17f733@o4508531702497280.ingest.de.sentry.io/4511256875368528" : "");
@@ -12828,4 +12841,4 @@ export {
12828
12841
  skillFilePath,
12829
12842
  installHarness
12830
12843
  };
12831
- //# sourceMappingURL=chunk-OEDNX3CV.js.map
12844
+ //# sourceMappingURL=chunk-73ZZ6O4B.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  EMBEDDING_DIMENSION,
3
3
  EMBEDDING_MODEL_ID
4
- } from "./chunk-JZOJC3S7.js";
4
+ } from "./chunk-XJJHX227.js";
5
5
  import {
6
6
  logger
7
7
  } from "./chunk-TYDMSHV7.js";
@@ -12,6 +12,11 @@ import fs from "fs";
12
12
  function sanitizeFilterPath(filePath) {
13
13
  return filePath.replace(/[^a-zA-Z0-9/._\- ]/g, "_");
14
14
  }
15
+ var VECTOR_RECOVERY_CMD = "ctxloom vectors-cleanup && ctxloom index";
16
+ function isCorruptionError(err) {
17
+ const msg = err instanceof Error ? err.message : String(err);
18
+ return /not found/i.test(msg) && /\.lance|\.arrow|_deletions|_versions|\/data\//.test(msg);
19
+ }
15
20
  var VectorStore = class {
16
21
  dbPath;
17
22
  db = null;
@@ -26,6 +31,27 @@ var VectorStore = class {
26
31
  upsertsSinceCompact = 0;
27
32
  compactEvery;
28
33
  cleanupOlderThanMs;
34
+ /**
35
+ * Hot-reload bookkeeping (v1.7.8). A live MCP server pins one open
36
+ * LanceDB table handle. When a terminal `ctxloom index` rewrites the
37
+ * store on the same path, the pinned handle keeps serving the OLD
38
+ * version — `ctx_search` returns stale/empty results until restart
39
+ * (the vector analogue of the graph hot-reload shipped in v1.7.5).
40
+ *
41
+ * Fix: before each read we cheaply stat the LanceDB `_versions`
42
+ * directory mtime. If it advanced past the last write WE made, an
43
+ * external writer touched the store → call `table.checkoutLatest()`
44
+ * to re-point the handle at the newest version. The mtime gate makes
45
+ * idle searches free and — critically — prevents the server's OWN
46
+ * continuous upserts (incremental file-watch indexing) from
47
+ * triggering a refresh storm: every own write updates
48
+ * `lastKnownMtime`, so the next read sees no advance.
49
+ *
50
+ * `externalRefreshCount` is exposed for tests + telemetry to prove
51
+ * own-writes don't cause redundant refreshes.
52
+ */
53
+ lastKnownMtimeMs = 0;
54
+ externalRefreshCount = 0;
29
55
  constructor(dbPath, options = {}) {
30
56
  this.dbPath = dbPath ?? path.join(process.cwd(), ".ctxloom", "vectors.lancedb");
31
57
  this.compactEvery = options.compactEvery ?? 200;
@@ -60,6 +86,87 @@ var VectorStore = class {
60
86
  await this.table.delete("id = '__seed__'");
61
87
  }
62
88
  this.initialized = true;
89
+ this.markSynced();
90
+ }
91
+ /**
92
+ * Absolute path to the LanceDB table's `_versions` manifest directory.
93
+ * A new manifest file lands here on every committed write, so the
94
+ * directory's mtime is a cheap external-change signal.
95
+ */
96
+ versionsDir() {
97
+ return path.join(this.dbPath, "code_embeddings.lance", "_versions");
98
+ }
99
+ /**
100
+ * Newest mtime (ms) among the manifest FILES inside `_versions`, or 0
101
+ * if unreadable. We scan files, NOT the directory itself: LanceDB does
102
+ * NOT bump the `_versions` directory's own mtime when it adds a new
103
+ * manifest (verified empirically against @lancedb/lancedb 0.27.x —
104
+ * the dir mtime stays frozen at creation time), so statting the dir is
105
+ * a dead signal. Each committed version writes a fresh manifest file,
106
+ * so max-file-mtime advances monotonically per version and survives
107
+ * compaction (which writes new manifests with current timestamps).
108
+ */
109
+ versionsMtimeMs() {
110
+ const dir = this.versionsDir();
111
+ let newest = 0;
112
+ try {
113
+ for (const name of fs.readdirSync(dir)) {
114
+ if (name.startsWith(".")) continue;
115
+ try {
116
+ const st = fs.statSync(path.join(dir, name));
117
+ if (st.isFile() && st.mtimeMs > newest) newest = st.mtimeMs;
118
+ } catch {
119
+ }
120
+ }
121
+ } catch {
122
+ return 0;
123
+ }
124
+ return newest;
125
+ }
126
+ /**
127
+ * Mark the store as in-sync with the current on-disk state. Called
128
+ * after init and after every mutation WE perform (upsert, upsertBatch,
129
+ * remove, compact) so a subsequent refreshIfStale() does not mistake
130
+ * our own write for an external one.
131
+ */
132
+ markSynced() {
133
+ this.lastKnownMtimeMs = this.versionsMtimeMs();
134
+ }
135
+ /**
136
+ * Re-point the pinned table handle at the newest on-disk version IF an
137
+ * external writer (a terminal `ctxloom index` on the same path) has
138
+ * advanced the store since our last write. Cheap mtime gate first; the
139
+ * LanceDB `checkoutLatest()` call only happens on a real external
140
+ * change. Best-effort — a failed refresh keeps the current handle and
141
+ * logs a warning rather than breaking the read.
142
+ */
143
+ async refreshIfStale() {
144
+ if (!this.table) return;
145
+ const diskMtime = this.versionsMtimeMs();
146
+ if (diskMtime === 0 || diskMtime <= this.lastKnownMtimeMs) return;
147
+ try {
148
+ const table = this.table;
149
+ if (typeof table.checkoutLatest === "function") {
150
+ await table.checkoutLatest();
151
+ }
152
+ this.lastKnownMtimeMs = this.versionsMtimeMs();
153
+ this.externalRefreshCount += 1;
154
+ logger.info("VectorStore: external write detected, handle refreshed", {
155
+ refreshCount: this.externalRefreshCount
156
+ });
157
+ } catch (err) {
158
+ logger.warn("VectorStore.refreshIfStale failed; keeping current handle", {
159
+ detail: err instanceof Error ? err.message : String(err)
160
+ });
161
+ }
162
+ }
163
+ /**
164
+ * Number of times the pinned handle was refreshed due to an EXTERNAL
165
+ * write. Exposed for tests (own-writes must not increment this) and
166
+ * for telemetry. @internal
167
+ */
168
+ getExternalRefreshCount() {
169
+ return this.externalRefreshCount;
63
170
  }
64
171
  /**
65
172
  * Compare the active embedding model against the marker file written
@@ -96,8 +203,7 @@ var VectorStore = class {
96
203
  throw new Error(
97
204
  `Embedding-model mismatch: vector index at ${this.dbPath} was built with "${existing.model}" (${existing.dim}-dim) but the active model is "${active.model}" (${active.dim}-dim). Re-index required:
98
205
 
99
- ctxloom vectors-cleanup --reset
100
- ctxloom index
206
+ ${VECTOR_RECOVERY_CMD}
101
207
 
102
208
  Or revert CTXLOOM_EMBEDDING_MODEL to "${existing.model}" to keep the existing index.`
103
209
  );
@@ -125,6 +231,7 @@ Or revert CTXLOOM_EMBEDDING_MODEL to "${existing.model}" to keep the existing in
125
231
  this.db = null;
126
232
  this.table = null;
127
233
  this.initialized = false;
234
+ this.lastKnownMtimeMs = 0;
128
235
  }
129
236
  /**
130
237
  * Insert or update a code record.
@@ -144,6 +251,7 @@ Or revert CTXLOOM_EMBEDDING_MODEL to "${existing.model}" to keep the existing in
144
251
  content: content.slice(0, 512)
145
252
  };
146
253
  await this.table.add([record]);
254
+ this.markSynced();
147
255
  this.upsertsSinceCompact++;
148
256
  if (this.upsertsSinceCompact >= this.compactEvery) {
149
257
  this.upsertsSinceCompact = 0;
@@ -186,6 +294,7 @@ Or revert CTXLOOM_EMBEDDING_MODEL to "${existing.model}" to keep the existing in
186
294
  content: r.content.slice(0, 512)
187
295
  }));
188
296
  await this.table.add(rows);
297
+ this.markSynced();
189
298
  this.upsertsSinceCompact += records.length;
190
299
  if (this.upsertsSinceCompact >= this.compactEvery) {
191
300
  this.upsertsSinceCompact = 0;
@@ -216,6 +325,7 @@ Or revert CTXLOOM_EMBEDDING_MODEL to "${existing.model}" to keep the existing in
216
325
  bytesRemoved: result.prune?.bytesRemoved ?? 0
217
326
  });
218
327
  }
328
+ this.markSynced();
219
329
  } catch (err) {
220
330
  logger.warn("VectorStore.compact failed (non-fatal)", {
221
331
  detail: err instanceof Error ? err.message : String(err)
@@ -230,6 +340,7 @@ Or revert CTXLOOM_EMBEDDING_MODEL to "${existing.model}" to keep the existing in
230
340
  */
231
341
  async findEmbeddingByPath(filePath) {
232
342
  if (!this.table) throw new Error("VectorStore not initialized. Call init() first.");
343
+ await this.refreshIfStale();
233
344
  try {
234
345
  const safe = sanitizeFilterPath(filePath);
235
346
  const rows = await this.table.query().where(`filePath = '${safe}'`).limit(1).toArray();
@@ -244,6 +355,11 @@ Or revert CTXLOOM_EMBEDDING_MODEL to "${existing.model}" to keep the existing in
244
355
  }
245
356
  return null;
246
357
  } catch (err) {
358
+ if (isCorruptionError(err)) {
359
+ throw new Error(
360
+ `VectorStore corrupt at ${this.dbPath}: manifest references a missing fragment (${err instanceof Error ? err.message : String(err)}). Recover with: ${VECTOR_RECOVERY_CMD}`
361
+ );
362
+ }
247
363
  logger.warn("VectorStore.findEmbeddingByPath failed", {
248
364
  detail: err instanceof Error ? err.message : String(err),
249
365
  filePath
@@ -256,6 +372,7 @@ Or revert CTXLOOM_EMBEDDING_MODEL to "${existing.model}" to keep the existing in
256
372
  */
257
373
  async search(queryEmbedding, limit = 10) {
258
374
  if (!this.table) throw new Error("VectorStore not initialized. Call init() first.");
375
+ await this.refreshIfStale();
259
376
  try {
260
377
  const results = await this.table.vectorSearch(queryEmbedding).limit(limit).toArray();
261
378
  return results.filter((r) => r.id !== "__seed__").map((r) => ({
@@ -264,6 +381,11 @@ Or revert CTXLOOM_EMBEDDING_MODEL to "${existing.model}" to keep the existing in
264
381
  score: Number(r._distance ?? 0)
265
382
  }));
266
383
  } catch (err) {
384
+ if (isCorruptionError(err)) {
385
+ throw new Error(
386
+ `VectorStore corrupt at ${this.dbPath}: manifest references a missing fragment (${err instanceof Error ? err.message : String(err)}). Recover with: ${VECTOR_RECOVERY_CMD}`
387
+ );
388
+ }
267
389
  logger.warn("Search failed, attempting to create index", { detail: String(err) });
268
390
  try {
269
391
  await this.table.createIndex("vector");
@@ -273,7 +395,12 @@ Or revert CTXLOOM_EMBEDDING_MODEL to "${existing.model}" to keep the existing in
273
395
  content: String(r.content ?? ""),
274
396
  score: Number(r._distance ?? 0)
275
397
  }));
276
- } catch {
398
+ } catch (retryErr) {
399
+ if (isCorruptionError(retryErr)) {
400
+ throw new Error(
401
+ `VectorStore corrupt at ${this.dbPath}: manifest references a missing fragment (${retryErr instanceof Error ? retryErr.message : String(retryErr)}). Recover with: ${VECTOR_RECOVERY_CMD}`
402
+ );
403
+ }
277
404
  return [];
278
405
  }
279
406
  }
@@ -286,6 +413,7 @@ Or revert CTXLOOM_EMBEDDING_MODEL to "${existing.model}" to keep the existing in
286
413
  const safe = sanitizeFilterPath(filePath);
287
414
  try {
288
415
  await this.table.delete(`filePath = '${safe}'`);
416
+ this.markSynced();
289
417
  } catch (err) {
290
418
  logger.error("Remove failed", { detail: err instanceof Error ? err.message : String(err) });
291
419
  }
@@ -295,6 +423,7 @@ Or revert CTXLOOM_EMBEDDING_MODEL to "${existing.model}" to keep the existing in
295
423
  */
296
424
  async count() {
297
425
  if (!this.table) return 0;
426
+ await this.refreshIfStale();
298
427
  try {
299
428
  return await this.table.countRows();
300
429
  } catch (err) {
@@ -302,9 +431,22 @@ Or revert CTXLOOM_EMBEDDING_MODEL to "${existing.model}" to keep the existing in
302
431
  return 0;
303
432
  }
304
433
  }
434
+ /**
435
+ * Liveness probe for ctx_status. Performs an actual 1-row READ (not a
436
+ * metadata `count()`, which reads the intact manifest and returns a
437
+ * stale count on a corrupt store). Throws the underlying lance error
438
+ * if a referenced fragment is missing — callers use isCorruptionError()
439
+ * to classify. Resolves silently on a healthy store (including an
440
+ * empty one, which simply yields zero rows). Cheap: a single-row scan.
441
+ */
442
+ async probe() {
443
+ if (!this.table) throw new Error("VectorStore not initialized. Call init() first.");
444
+ await this.table.query().limit(1).toArray();
445
+ }
305
446
  };
306
447
 
307
448
  export {
449
+ isCorruptionError,
308
450
  VectorStore
309
451
  };
310
- //# sourceMappingURL=chunk-XQEQLXY5.js.map
452
+ //# sourceMappingURL=chunk-UWQKNIZO.js.map
@@ -253,7 +253,7 @@ var INDEX_SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([
253
253
  ".ipynb"
254
254
  ]);
255
255
  async function indexDirectory(rootDir, onProgress) {
256
- const { VectorStore } = await import("./VectorStore-5ALWL6XF.js");
256
+ const { VectorStore } = await import("./VectorStore-ZA4EEL6C.js");
257
257
  const store = new VectorStore(path.join(rootDir, ".ctxloom", "vectors.lancedb"));
258
258
  await store.init();
259
259
  let indexed = 0;
@@ -366,4 +366,4 @@ export {
366
366
  EMBEDDING_MODEL_ID,
367
367
  getActiveEmbeddingModel
368
368
  };
369
- //# sourceMappingURL=chunk-JZOJC3S7.js.map
369
+ //# sourceMappingURL=chunk-XJJHX227.js.map
@@ -10,7 +10,7 @@ import {
10
10
  indexDirectory,
11
11
  isIgnoredDir,
12
12
  resolveEmbeddingModel
13
- } from "./chunk-JZOJC3S7.js";
13
+ } from "./chunk-XJJHX227.js";
14
14
  import "./chunk-TYDMSHV7.js";
15
15
  export {
16
16
  EMBEDDING_DIMENSION,
@@ -25,4 +25,4 @@ export {
25
25
  isIgnoredDir,
26
26
  resolveEmbeddingModel
27
27
  };
28
- //# sourceMappingURL=embedder-4MM7D3UE.js.map
28
+ //# sourceMappingURL=embedder-WQMRK5T7.js.map
package/dist/index.js CHANGED
@@ -47,19 +47,19 @@ import {
47
47
  validateDefaultRoot,
48
48
  wrapWithIndexingEnvelope,
49
49
  writeCODEOWNERS
50
- } from "./chunk-OEDNX3CV.js";
50
+ } from "./chunk-73ZZ6O4B.js";
51
51
  import {
52
52
  addCtxloomToConfig,
53
53
  detectInstalledClients
54
54
  } from "./chunk-YHLMQVBV.js";
55
55
  import {
56
56
  VectorStore
57
- } from "./chunk-XQEQLXY5.js";
57
+ } from "./chunk-UWQKNIZO.js";
58
58
  import {
59
59
  collectFiles,
60
60
  generateEmbedding,
61
61
  indexDirectory
62
- } from "./chunk-JZOJC3S7.js";
62
+ } from "./chunk-XJJHX227.js";
63
63
  import "./chunk-5I6CJITG.js";
64
64
  import {
65
65
  logger
@@ -1068,7 +1068,7 @@ try {
1068
1068
  } catch {
1069
1069
  }
1070
1070
  var args = process.argv.slice(2);
1071
- var ctxloomVersion = "1.7.7".length > 0 ? "1.7.7" : "dev";
1071
+ var ctxloomVersion = "1.7.9".length > 0 ? "1.7.9" : "dev";
1072
1072
  if (args.includes("--version") || args.includes("-v")) {
1073
1073
  process.stdout.write(`ctxloom ${ctxloomVersion}
1074
1074
  `);
@@ -1163,7 +1163,7 @@ async function checkLicense() {
1163
1163
  if (command !== void 0 && LICENSE_GATE_BYPASS_COMMANDS.has(command)) return;
1164
1164
  const ciKey = process.env["CTXLOOM_LICENSE_KEY"];
1165
1165
  if (ciKey) {
1166
- const { ApiClient } = await import("./src-HFPCEHYB.js");
1166
+ const { ApiClient } = await import("./src-SNHT3SQF.js");
1167
1167
  const client = new ApiClient(process.env["CTXLOOM_API_BASE"]);
1168
1168
  try {
1169
1169
  const result = await client.validate(ciKey, "ci-ephemeral");
@@ -1556,7 +1556,7 @@ async function main() {
1556
1556
  }
1557
1557
  if (!skipHarness) {
1558
1558
  process.stdout.write("\n");
1559
- const { installHarness } = await import("./src-HFPCEHYB.js");
1559
+ const { installHarness } = await import("./src-SNHT3SQF.js");
1560
1560
  const h = installHarness({ cwd: initRoot, dryRun, force, extraHosts });
1561
1561
  const harnessFiles = [
1562
1562
  h.claudeMd,
@@ -1619,7 +1619,7 @@ async function main() {
1619
1619
  process.exit(1);
1620
1620
  }
1621
1621
  if (alias !== void 0) {
1622
- const { validateAlias } = await import("./src-HFPCEHYB.js");
1622
+ const { validateAlias } = await import("./src-SNHT3SQF.js");
1623
1623
  const v = validateAlias(alias);
1624
1624
  if (!v.ok) {
1625
1625
  console.error(`[ctxloom] Invalid alias: ${v.reason}`);
@@ -1978,7 +1978,7 @@ Suggested reviewers for ${files.length} file(s):`);
1978
1978
  process.stderr.write("[ctxloom] --limit must be a non-negative integer (0 for unlimited)\n");
1979
1979
  process.exit(2);
1980
1980
  }
1981
- const { loadRulesConfig, RulesChecker, formatText, formatJson, RulesConfigError } = await import("./src-HFPCEHYB.js");
1981
+ const { loadRulesConfig, RulesChecker, formatText, formatJson, RulesConfigError } = await import("./src-SNHT3SQF.js");
1982
1982
  let config;
1983
1983
  try {
1984
1984
  config = await loadRulesConfig(root);
@@ -2002,7 +2002,7 @@ Suggested reviewers for ${files.length} file(s):`);
2002
2002
  }
2003
2003
  let graph;
2004
2004
  if (useSnapshot) {
2005
- const { DependencyGraph: DG } = await import("./src-HFPCEHYB.js");
2005
+ const { DependencyGraph: DG } = await import("./src-SNHT3SQF.js");
2006
2006
  graph = new DG();
2007
2007
  const loaded = await graph.loadSnapshotOnly(root);
2008
2008
  if (!loaded) {
@@ -2011,7 +2011,7 @@ Suggested reviewers for ${files.length} file(s):`);
2011
2011
  }
2012
2012
  } else {
2013
2013
  process.stderr.write("[ctxloom] Building dependency graph...\n");
2014
- const { ASTParser: ASTParser2, DependencyGraph: DependencyGraph2 } = await import("./src-HFPCEHYB.js");
2014
+ const { ASTParser: ASTParser2, DependencyGraph: DependencyGraph2 } = await import("./src-SNHT3SQF.js");
2015
2015
  let parser;
2016
2016
  try {
2017
2017
  parser = new ASTParser2();
@@ -132,10 +132,11 @@ import {
132
132
  wrapBlock,
133
133
  wrapWithIndexingEnvelope,
134
134
  writeCODEOWNERS
135
- } from "./chunk-OEDNX3CV.js";
135
+ } from "./chunk-73ZZ6O4B.js";
136
136
  import {
137
- VectorStore
138
- } from "./chunk-XQEQLXY5.js";
137
+ VectorStore,
138
+ isCorruptionError
139
+ } from "./chunk-UWQKNIZO.js";
139
140
  import {
140
141
  EMBEDDING_DIMENSION,
141
142
  INDEXER_IGNORED_DIRS,
@@ -143,7 +144,7 @@ import {
143
144
  generateEmbedding,
144
145
  indexDirectory,
145
146
  isIgnoredDir
146
- } from "./chunk-JZOJC3S7.js";
147
+ } from "./chunk-XJJHX227.js";
147
148
  import {
148
149
  filenameForDate,
149
150
  readEvents,
@@ -259,6 +260,7 @@ export {
259
260
  inspectVectorsDb,
260
261
  installHarness,
261
262
  isActive,
263
+ isCorruptionError,
262
264
  isIgnoredDir,
263
265
  isSiloed,
264
266
  learnSuggestionsFromTelemetry,
@@ -304,4 +306,4 @@ export {
304
306
  wrapWithIndexingEnvelope,
305
307
  writeCODEOWNERS
306
308
  };
307
- //# sourceMappingURL=src-HFPCEHYB.js.map
309
+ //# sourceMappingURL=src-SNHT3SQF.js.map
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  VectorStore
3
- } from "../chunk-XQEQLXY5.js";
3
+ } from "../chunk-UWQKNIZO.js";
4
4
  import {
5
5
  generateEmbedding
6
- } from "../chunk-JZOJC3S7.js";
6
+ } from "../chunk-XJJHX227.js";
7
7
  import "../chunk-TYDMSHV7.js";
8
8
 
9
9
  // packages/core/src/workers/indexerWorker.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ctxloom-pro",
3
- "version": "1.7.7",
3
+ "version": "1.7.9",
4
4
  "description": "ctxloom — The Universal Code Context Engine. A local-first MCP server providing intelligent code context via hybrid Vector + AST + Graph search with Skeletonization (92% token reduction).",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,9 +0,0 @@
1
- import {
2
- VectorStore
3
- } from "./chunk-XQEQLXY5.js";
4
- import "./chunk-JZOJC3S7.js";
5
- import "./chunk-TYDMSHV7.js";
6
- export {
7
- VectorStore
8
- };
9
- //# sourceMappingURL=VectorStore-5ALWL6XF.js.map