ctxloom-pro 1.5.5 → 1.5.6

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.
@@ -114,9 +114,17 @@ var VectorStore = class {
114
114
  if (!this.table) return;
115
115
  try {
116
116
  const optimizable = this.table;
117
- await optimizable.optimize?.({
117
+ const result = await optimizable.optimize?.({
118
118
  cleanupOlderThan: new Date(Date.now() - this.cleanupOlderThanMs)
119
119
  });
120
+ if (result) {
121
+ logger.info("VectorStore.compact", {
122
+ fragmentsRemoved: result.compaction?.fragmentsRemoved ?? 0,
123
+ fragmentsAdded: result.compaction?.fragmentsAdded ?? 0,
124
+ oldVersionsRemoved: result.prune?.oldVersionsRemoved ?? 0,
125
+ bytesRemoved: result.prune?.bytesRemoved ?? 0
126
+ });
127
+ }
120
128
  } catch (err) {
121
129
  logger.warn("VectorStore.compact failed (non-fatal)", {
122
130
  detail: err instanceof Error ? err.message : String(err)
@@ -179,4 +187,4 @@ var VectorStore = class {
179
187
  export {
180
188
  VectorStore
181
189
  };
182
- //# sourceMappingURL=chunk-R56D54Y7.js.map
190
+ //# sourceMappingURL=chunk-JULFFD7O.js.map
@@ -158,7 +158,7 @@ function collectFiles(dir, results = []) {
158
158
  return results;
159
159
  }
160
160
  async function indexDirectory(rootDir, onProgress) {
161
- const { VectorStore } = await import("./VectorStore-4VWT2ZMW.js");
161
+ const { VectorStore } = await import("./VectorStore-2LVECRTY.js");
162
162
  const store = new VectorStore(path.join(rootDir, ".ctxloom", "vectors.lancedb"));
163
163
  await store.init();
164
164
  const files = collectFiles(rootDir);
@@ -211,4 +211,4 @@ export {
211
211
  collectFiles,
212
212
  indexDirectory
213
213
  };
214
- //# sourceMappingURL=chunk-COH5WYZS.js.map
214
+ //# sourceMappingURL=chunk-WDX4PJGL.js.map
@@ -3,7 +3,7 @@ import {
3
3
  collectFiles,
4
4
  generateEmbedding,
5
5
  indexDirectory
6
- } from "./chunk-COH5WYZS.js";
6
+ } from "./chunk-WDX4PJGL.js";
7
7
  import "./chunk-TYDMSHV7.js";
8
8
  export {
9
9
  EMBEDDING_DIMENSION,
@@ -11,4 +11,4 @@ export {
11
11
  generateEmbedding,
12
12
  indexDirectory
13
13
  };
14
- //# sourceMappingURL=embedder-7YOG4DFN.js.map
14
+ //# sourceMappingURL=embedder-3AE4CSR7.js.map
package/dist/index.js CHANGED
@@ -22,6 +22,7 @@ import {
22
22
  activateLicense,
23
23
  aliasNotFoundError,
24
24
  captureError,
25
+ cleanupVectors,
25
26
  createToolRegistry,
26
27
  deactivateLicense,
27
28
  ensureVectorsInitialized,
@@ -29,6 +30,7 @@ import {
29
30
  getLicenseInfo,
30
31
  getTelemetryLevel,
31
32
  hashProjectRoot,
33
+ inspectVectorsDb,
32
34
  isActive,
33
35
  loadReviewConfig,
34
36
  noDefaultProjectError,
@@ -45,18 +47,18 @@ import {
45
47
  validateDefaultRoot,
46
48
  wrapWithIndexingEnvelope,
47
49
  writeCODEOWNERS
48
- } from "./chunk-5R4P7VEE.js";
50
+ } from "./chunk-FPMNXF4D.js";
49
51
  import {
50
52
  addCtxloomToConfig,
51
53
  detectInstalledClients
52
54
  } from "./chunk-II2DPYRJ.js";
53
55
  import {
54
56
  VectorStore
55
- } from "./chunk-R56D54Y7.js";
57
+ } from "./chunk-JULFFD7O.js";
56
58
  import {
57
59
  generateEmbedding,
58
60
  indexDirectory
59
- } from "./chunk-COH5WYZS.js";
61
+ } from "./chunk-WDX4PJGL.js";
60
62
  import "./chunk-5I6CJITG.js";
61
63
  import {
62
64
  logger
@@ -535,19 +537,36 @@ async function startServer(opts = {}) {
535
537
  });
536
538
  watcher.start();
537
539
  logger.info("File watcher active");
538
- process.on("SIGINT", () => {
539
- if (overlayRefreshTimer) clearTimeout(overlayRefreshTimer);
540
- watcher.stop();
541
- process.exit(0);
542
- });
543
- process.on("SIGTERM", () => {
544
- if (overlayRefreshTimer) clearTimeout(overlayRefreshTimer);
545
- watcher.stop();
540
+ const shutdown = (signal) => {
541
+ const forceExit = setTimeout(() => {
542
+ logger.warn("Shutdown timeout reached, force-exiting", { signal });
543
+ process.exit(1);
544
+ }, 5e3);
545
+ forceExit.unref();
546
+ try {
547
+ if (overlayRefreshTimer) clearTimeout(overlayRefreshTimer);
548
+ watcher.stop();
549
+ } catch (err) {
550
+ logger.warn("Shutdown step failed (non-fatal)", {
551
+ signal,
552
+ detail: err instanceof Error ? err.message : String(err)
553
+ });
554
+ }
546
555
  process.exit(0);
547
- });
556
+ };
557
+ process.on("SIGINT", () => shutdown("SIGINT"));
558
+ process.on("SIGTERM", () => shutdown("SIGTERM"));
548
559
  } else {
549
- process.on("SIGINT", () => process.exit(0));
550
- process.on("SIGTERM", () => process.exit(0));
560
+ const shutdown = (signal) => {
561
+ const forceExit = setTimeout(() => {
562
+ logger.warn("Shutdown timeout reached, force-exiting", { signal });
563
+ process.exit(1);
564
+ }, 5e3);
565
+ forceExit.unref();
566
+ process.exit(0);
567
+ };
568
+ process.on("SIGINT", () => shutdown("SIGINT"));
569
+ process.on("SIGTERM", () => shutdown("SIGTERM"));
551
570
  }
552
571
  }
553
572
 
@@ -1020,7 +1039,7 @@ try {
1020
1039
  } catch {
1021
1040
  }
1022
1041
  var args = process.argv.slice(2);
1023
- var ctxloomVersion = "1.5.5".length > 0 ? "1.5.5" : "dev";
1042
+ var ctxloomVersion = "1.5.6".length > 0 ? "1.5.6" : "dev";
1024
1043
  if (args.includes("--version") || args.includes("-v")) {
1025
1044
  process.stdout.write(`ctxloom ${ctxloomVersion}
1026
1045
  `);
@@ -1093,7 +1112,7 @@ async function checkLicense() {
1093
1112
  if (command !== void 0 && LICENSE_GATE_BYPASS_COMMANDS.has(command)) return;
1094
1113
  const ciKey = process.env["CTXLOOM_LICENSE_KEY"];
1095
1114
  if (ciKey) {
1096
- const { ApiClient } = await import("./src-QMDQDATD.js");
1115
+ const { ApiClient } = await import("./src-DL44T55H.js");
1097
1116
  const client = new ApiClient(process.env["CTXLOOM_API_BASE"]);
1098
1117
  try {
1099
1118
  const result = await client.validate(ciKey, "ci-ephemeral");
@@ -1471,7 +1490,7 @@ async function main() {
1471
1490
  }
1472
1491
  if (!skipHarness) {
1473
1492
  process.stdout.write("\n");
1474
- const { installHarness } = await import("./src-QMDQDATD.js");
1493
+ const { installHarness } = await import("./src-DL44T55H.js");
1475
1494
  const h = installHarness({ cwd: initRoot, dryRun, force, extraHosts });
1476
1495
  const harnessFiles = [
1477
1496
  h.claudeMd,
@@ -1534,7 +1553,7 @@ async function main() {
1534
1553
  process.exit(1);
1535
1554
  }
1536
1555
  if (alias !== void 0) {
1537
- const { validateAlias } = await import("./src-QMDQDATD.js");
1556
+ const { validateAlias } = await import("./src-DL44T55H.js");
1538
1557
  const v = validateAlias(alias);
1539
1558
  if (!v.ok) {
1540
1559
  console.error(`[ctxloom] Invalid alias: ${v.reason}`);
@@ -1607,6 +1626,101 @@ async function main() {
1607
1626
  }
1608
1627
  break;
1609
1628
  }
1629
+ case "vectors-cleanup": {
1630
+ const root = process.cwd();
1631
+ const dryRun = hasFlag("--dry-run");
1632
+ const force = hasFlag("--force");
1633
+ const before = inspectVectorsDb(root);
1634
+ if (before.txn + before.manifest + before.lance === 0) {
1635
+ process.stdout.write(` ${success("No vectors.lancedb to clean up \u2014 nothing to do.")}
1636
+ `);
1637
+ break;
1638
+ }
1639
+ const mb = (before.totalBytes / (1024 * 1024)).toFixed(1);
1640
+ process.stdout.write(header("Vectors cleanup"));
1641
+ process.stdout.write(` ${style.dim("Root:")} ${root}
1642
+ `);
1643
+ process.stdout.write(` ${style.dim("On-disk state:")}
1644
+ `);
1645
+ process.stdout.write(` ${style.bold(String(before.txn).padStart(6))} .txn files
1646
+ `);
1647
+ process.stdout.write(` ${style.bold(String(before.manifest).padStart(6))} .manifest files
1648
+ `);
1649
+ process.stdout.write(` ${style.bold(String(before.lance).padStart(6))} .lance fragments
1650
+ `);
1651
+ process.stdout.write(` ${style.bold(mb.padStart(6))} MB total
1652
+
1653
+ `);
1654
+ const activePids = [];
1655
+ if (!force) {
1656
+ try {
1657
+ const dbPath = `${root}/.ctxloom/vectors.lancedb`;
1658
+ const out = execSync(`lsof +D "${dbPath}" -F p 2>/dev/null || true`, {
1659
+ encoding: "utf-8"
1660
+ });
1661
+ for (const line of out.split("\n")) {
1662
+ if (line.startsWith("p")) {
1663
+ const pid = parseInt(line.slice(1), 10);
1664
+ if (Number.isFinite(pid) && pid !== process.pid) activePids.push(pid);
1665
+ }
1666
+ }
1667
+ } catch {
1668
+ }
1669
+ }
1670
+ if (activePids.length > 0) {
1671
+ const uniq = [...new Set(activePids)];
1672
+ process.stdout.write(
1673
+ ` ${warn(`Refusing to clean \u2014 ${uniq.length} process(es) have files open:`)}
1674
+ `
1675
+ );
1676
+ for (const pid of uniq) {
1677
+ process.stdout.write(` PID ${pid}
1678
+ `);
1679
+ }
1680
+ process.stdout.write(
1681
+ `
1682
+ ${style.dim("Stop those ctxloom MCP servers first (close Claude Code windows or `kill <pid>`),")}
1683
+ `
1684
+ );
1685
+ process.stdout.write(
1686
+ ` ${style.dim("then re-run. Use --force to override (not recommended \u2014 may corrupt the DB).")}
1687
+ `
1688
+ );
1689
+ process.exitCode = 1;
1690
+ break;
1691
+ }
1692
+ const result = cleanupVectors({ rootDir: root, dryRun }, force ? [] : activePids);
1693
+ if (!result.cleaned) {
1694
+ process.stdout.write(` ${warn(`Cleanup skipped: ${result.reason ?? "unknown"}`)}
1695
+ `);
1696
+ break;
1697
+ }
1698
+ if (dryRun) {
1699
+ process.stdout.write(
1700
+ ` ${success(`Dry run \u2014 would have freed ${mb} MB across ${before.txn + before.manifest + before.lance} files.`)}
1701
+ `
1702
+ );
1703
+ process.stdout.write(` ${style.dim("Re-run without --dry-run to actually clean up.")}
1704
+ `);
1705
+ } else {
1706
+ process.stdout.write(` ${success(`Cleanup complete \u2014 freed ${mb} MB.`)}
1707
+ `);
1708
+ if (result.backupPath) {
1709
+ process.stdout.write(` ${style.dim(`Backup: ${result.backupPath}`)}
1710
+ `);
1711
+ process.stdout.write(
1712
+ ` ${style.dim("Delete the backup with `rm -rf` once you confirm the next index works.")}
1713
+ `
1714
+ );
1715
+ }
1716
+ process.stdout.write(
1717
+ `
1718
+ ${style.dim("Next ctxloom run will rebuild embeddings (~30-60s on a mid-sized repo).")}
1719
+ `
1720
+ );
1721
+ }
1722
+ break;
1723
+ }
1610
1724
  case "budget-stats": {
1611
1725
  const windowArg = args.find((a) => a.startsWith("--window="))?.split("=")[1] ?? "14d";
1612
1726
  const toolArg = args.find((a) => a.startsWith("--tool="))?.split("=")[1];
@@ -1798,7 +1912,7 @@ Suggested reviewers for ${files.length} file(s):`);
1798
1912
  process.stderr.write("[ctxloom] --limit must be a non-negative integer (0 for unlimited)\n");
1799
1913
  process.exit(2);
1800
1914
  }
1801
- const { loadRulesConfig, RulesChecker, formatText, formatJson, RulesConfigError } = await import("./src-QMDQDATD.js");
1915
+ const { loadRulesConfig, RulesChecker, formatText, formatJson, RulesConfigError } = await import("./src-DL44T55H.js");
1802
1916
  let config;
1803
1917
  try {
1804
1918
  config = await loadRulesConfig(root);
@@ -1822,7 +1936,7 @@ Suggested reviewers for ${files.length} file(s):`);
1822
1936
  }
1823
1937
  let graph;
1824
1938
  if (useSnapshot) {
1825
- const { DependencyGraph: DG } = await import("./src-QMDQDATD.js");
1939
+ const { DependencyGraph: DG } = await import("./src-DL44T55H.js");
1826
1940
  graph = new DG();
1827
1941
  const loaded = await graph.loadSnapshotOnly(root);
1828
1942
  if (!loaded) {
@@ -1831,7 +1945,7 @@ Suggested reviewers for ${files.length} file(s):`);
1831
1945
  }
1832
1946
  } else {
1833
1947
  process.stderr.write("[ctxloom] Building dependency graph...\n");
1834
- const { ASTParser: ASTParser2, DependencyGraph: DependencyGraph2 } = await import("./src-QMDQDATD.js");
1948
+ const { ASTParser: ASTParser2, DependencyGraph: DependencyGraph2 } = await import("./src-DL44T55H.js");
1835
1949
  let parser;
1836
1950
  try {
1837
1951
  parser = new ASTParser2();
@@ -1892,6 +2006,9 @@ Usage:
1892
2006
  ctxloom rules check --json Output violations as JSON
1893
2007
  ctxloom rules check --use-snapshot Fast mode: use existing graph snapshot
1894
2008
  ctxloom rules check --limit=N Show first N violations (default 50, 0=unlimited)
2009
+ ctxloom vectors-cleanup Clear accumulated LanceDB version state to free FDs
2010
+ (use --dry-run to preview, --force to skip the
2011
+ active-process safety check)
1895
2012
  ctxloom --version Print installed version and exit
1896
2013
  ctxloom --help Show this help
1897
2014
 
@@ -61,6 +61,7 @@ import {
61
61
  buildBlastRadiusXml,
62
62
  buildCodeownersBlock,
63
63
  captureError,
64
+ cleanupVectors,
64
65
  computeBlockHmac,
65
66
  computeRiskBreakdown,
66
67
  computeRiskCaps,
@@ -89,6 +90,7 @@ import {
89
90
  getTaskBudgetTracker,
90
91
  getTelemetryLevel,
91
92
  hashProjectRoot,
93
+ inspectVectorsDb,
92
94
  installHarness,
93
95
  isActive,
94
96
  isSiloed,
@@ -129,16 +131,16 @@ import {
129
131
  wrapBlock,
130
132
  wrapWithIndexingEnvelope,
131
133
  writeCODEOWNERS
132
- } from "./chunk-5R4P7VEE.js";
134
+ } from "./chunk-FPMNXF4D.js";
133
135
  import {
134
136
  VectorStore
135
- } from "./chunk-R56D54Y7.js";
137
+ } from "./chunk-JULFFD7O.js";
136
138
  import {
137
139
  EMBEDDING_DIMENSION,
138
140
  collectFiles,
139
141
  generateEmbedding,
140
142
  indexDirectory
141
- } from "./chunk-COH5WYZS.js";
143
+ } from "./chunk-WDX4PJGL.js";
142
144
  import {
143
145
  filenameForDate,
144
146
  readEvents,
@@ -216,6 +218,7 @@ export {
216
218
  buildBlastRadiusXml,
217
219
  buildCodeownersBlock,
218
220
  captureError,
221
+ cleanupVectors,
219
222
  collectFiles,
220
223
  computeBlockHmac,
221
224
  computeRiskBreakdown,
@@ -248,6 +251,7 @@ export {
248
251
  getTelemetryLevel,
249
252
  hashProjectRoot,
250
253
  indexDirectory,
254
+ inspectVectorsDb,
251
255
  installHarness,
252
256
  isActive,
253
257
  isSiloed,
@@ -294,4 +298,4 @@ export {
294
298
  wrapWithIndexingEnvelope,
295
299
  writeCODEOWNERS
296
300
  };
297
- //# sourceMappingURL=src-QMDQDATD.js.map
301
+ //# sourceMappingURL=src-DL44T55H.js.map
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  VectorStore
3
- } from "../chunk-R56D54Y7.js";
3
+ } from "../chunk-JULFFD7O.js";
4
4
  import {
5
5
  generateEmbedding
6
- } from "../chunk-COH5WYZS.js";
6
+ } from "../chunk-WDX4PJGL.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.5.5",
3
+ "version": "1.5.6",
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",