ctxloom-pro 1.7.2 → 1.7.3

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.1`) 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.3`) 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.1
386
+ - run: npm install -g ctxloom-pro@1.7.3
387
387
  - run: ctxloom index
388
388
  - run: ctxloom rules check --json
389
389
  ```
@@ -2909,7 +2909,7 @@ var CallGraphIndex = class _CallGraphIndex {
2909
2909
  var TS_EXTENSIONS2 = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".vue"]);
2910
2910
  var PY_EXTENSIONS = /* @__PURE__ */ new Set([".py", ".ipynb"]);
2911
2911
  var AST_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".py", ".go", ".rs", ".java", ".cs", ".rb", ".kt", ".kts", ".swift", ".ipynb", ".php", ".dart"]);
2912
- var CTXLOOM_VERSION = "1.7.2".length > 0 ? "1.7.2" : "dev";
2912
+ var CTXLOOM_VERSION = "1.7.3".length > 0 ? "1.7.3" : "dev";
2913
2913
  var SNAPSHOT_SCHEMA_VERSION = 2;
2914
2914
  function compareCtxloomVersions(snapshotVer, currentVer) {
2915
2915
  if (snapshotVer === currentVer) return "same";
@@ -12141,7 +12141,7 @@ function resolveTelemetryLevel() {
12141
12141
  }
12142
12142
  var TELEMETRY_LEVEL = resolveTelemetryLevel();
12143
12143
  var TELEMETRY_DISABLED = TELEMETRY_LEVEL === "off";
12144
- var CTXLOOM_VERSION2 = "1.7.2".length > 0 ? "1.7.2" : "dev";
12144
+ var CTXLOOM_VERSION2 = "1.7.3".length > 0 ? "1.7.3" : "dev";
12145
12145
  var POSTHOG_HOST = "https://eu.i.posthog.com";
12146
12146
  var POSTHOG_KEY = process.env["POSTHOG_API_KEY"] ?? (true ? "phc_CiDkmFLcZ2K6uCpcoSUQLmFrnnUvsyXGhSxopX5TVKE6" : "");
12147
12147
  var SENTRY_DSN = process.env["SENTRY_DSN"] ?? (true ? "https://81c94a0f04a8e242dee493ac1e17f733@o4508531702497280.ingest.de.sentry.io/4511256875368528" : "");
@@ -12382,12 +12382,17 @@ those instead of guessing.
12382
12382
  | \`ctx_architecture_overview\` | High-level codebase map |
12383
12383
  | \`ctx_refactor_preview\` / \`ctx_apply_refactor\` | Plan a rename |
12384
12384
 
12385
- ### Hooks keep the graph fresh
12386
-
12387
- \`ctxloom init\` installed a PostToolUse hook on \`Write|Edit\` that
12388
- runs \`ctxloom update --incremental --quiet\` \u2014 so the graph is
12389
- always up to date when you query it. No "did the index update yet?"
12390
- guessing.`;
12385
+ ### How the graph stays fresh
12386
+
12387
+ The ctxloom MCP server's built-in \`FileWatcher\` (chokidar with 200ms
12388
+ debounce) keeps the graph + vectors in sync in real time as you edit
12389
+ files \u2014 no manual reindex needed. A belt-and-suspenders PostToolUse
12390
+ hook (\`ctxloom update --incremental --quiet\`) is also installed; in
12391
+ v1.7.3+ it's a no-op that exits cleanly. In earlier versions the
12392
+ \`update\` subcommand silently didn't exist, which made the hook spawn
12393
+ orphan MCP servers and accumulate LanceDB fragments \u2014 if you ever see
12394
+ \`ctx_search\` stalling for minutes, run \`ctxloom vectors-cleanup\`
12395
+ to fix.`;
12391
12396
  var SESSION_START_HEADER = `#!/usr/bin/env bash
12392
12397
  # ctxloom \u2014 agent-harness session-start hook
12393
12398
  # Generated by \`ctxloom init\`. Re-run \`ctxloom init\` to update.
@@ -2705,7 +2705,7 @@ var CallGraphIndex = class _CallGraphIndex {
2705
2705
  var TS_EXTENSIONS2 = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".vue"]);
2706
2706
  var PY_EXTENSIONS = /* @__PURE__ */ new Set([".py", ".ipynb"]);
2707
2707
  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.2".length > 0 ? "1.7.2" : "dev";
2708
+ var CTXLOOM_VERSION = "1.7.3".length > 0 ? "1.7.3" : "dev";
2709
2709
  var SNAPSHOT_SCHEMA_VERSION = 2;
2710
2710
  function compareCtxloomVersions(snapshotVer, currentVer) {
2711
2711
  if (snapshotVer === currentVer) return "same";
@@ -10959,7 +10959,7 @@ var TELEMETRY_DISABLED = TELEMETRY_LEVEL === "off";
10959
10959
  function getTelemetryLevel() {
10960
10960
  return TELEMETRY_LEVEL;
10961
10961
  }
10962
- var CTXLOOM_VERSION2 = "1.7.2".length > 0 ? "1.7.2" : "dev";
10962
+ var CTXLOOM_VERSION2 = "1.7.3".length > 0 ? "1.7.3" : "dev";
10963
10963
  var POSTHOG_HOST = "https://eu.i.posthog.com";
10964
10964
  var POSTHOG_KEY = process.env["POSTHOG_API_KEY"] ?? (true ? "phc_CiDkmFLcZ2K6uCpcoSUQLmFrnnUvsyXGhSxopX5TVKE6" : "");
10965
10965
  var SENTRY_DSN = process.env["SENTRY_DSN"] ?? (true ? "https://81c94a0f04a8e242dee493ac1e17f733@o4508531702497280.ingest.de.sentry.io/4511256875368528" : "");
@@ -11670,12 +11670,17 @@ those instead of guessing.
11670
11670
  | \`ctx_architecture_overview\` | High-level codebase map |
11671
11671
  | \`ctx_refactor_preview\` / \`ctx_apply_refactor\` | Plan a rename |
11672
11672
 
11673
- ### Hooks keep the graph fresh
11674
-
11675
- \`ctxloom init\` installed a PostToolUse hook on \`Write|Edit\` that
11676
- runs \`ctxloom update --incremental --quiet\` \u2014 so the graph is
11677
- always up to date when you query it. No "did the index update yet?"
11678
- guessing.`;
11673
+ ### How the graph stays fresh
11674
+
11675
+ The ctxloom MCP server's built-in \`FileWatcher\` (chokidar with 200ms
11676
+ debounce) keeps the graph + vectors in sync in real time as you edit
11677
+ files \u2014 no manual reindex needed. A belt-and-suspenders PostToolUse
11678
+ hook (\`ctxloom update --incremental --quiet\`) is also installed; in
11679
+ v1.7.3+ it's a no-op that exits cleanly. In earlier versions the
11680
+ \`update\` subcommand silently didn't exist, which made the hook spawn
11681
+ orphan MCP servers and accumulate LanceDB fragments \u2014 if you ever see
11682
+ \`ctx_search\` stalling for minutes, run \`ctxloom vectors-cleanup\`
11683
+ to fix.`;
11679
11684
  var SESSION_START_HEADER = `#!/usr/bin/env bash
11680
11685
  # ctxloom \u2014 agent-harness session-start hook
11681
11686
  # Generated by \`ctxloom init\`. Re-run \`ctxloom init\` to update.
@@ -12635,4 +12640,4 @@ export {
12635
12640
  skillFilePath,
12636
12641
  installHarness
12637
12642
  };
12638
- //# sourceMappingURL=chunk-QL5UJTQL.js.map
12643
+ //# sourceMappingURL=chunk-KQ5CQLIA.js.map
package/dist/index.js CHANGED
@@ -47,7 +47,7 @@ import {
47
47
  validateDefaultRoot,
48
48
  wrapWithIndexingEnvelope,
49
49
  writeCODEOWNERS
50
- } from "./chunk-QL5UJTQL.js";
50
+ } from "./chunk-KQ5CQLIA.js";
51
51
  import {
52
52
  addCtxloomToConfig,
53
53
  detectInstalledClients
@@ -56,6 +56,7 @@ import {
56
56
  VectorStore
57
57
  } from "./chunk-7S2ELKNU.js";
58
58
  import {
59
+ collectFiles,
59
60
  generateEmbedding,
60
61
  indexDirectory
61
62
  } from "./chunk-6FGTNOCP.js";
@@ -435,6 +436,33 @@ async function startServer(opts = {}) {
435
436
  }
436
437
  } catch {
437
438
  }
439
+ if (PROJECT_ROOT) {
440
+ try {
441
+ const fragCounts = inspectVectorsDb(PROJECT_ROOT);
442
+ const fragTotal = fragCounts.txn + fragCounts.manifest + fragCounts.lance;
443
+ if (fragTotal > 500) {
444
+ const sourceFileCount = collectFiles(PROJECT_ROOT).length;
445
+ const FRAGMENT_RATIO_THRESHOLD = 50;
446
+ if (sourceFileCount > 0 && fragTotal > sourceFileCount * FRAGMENT_RATIO_THRESHOLD) {
447
+ const mb = (fragCounts.totalBytes / 1024 / 1024).toFixed(0);
448
+ logger.warn(
449
+ "LanceDB fragment count is pathological \u2014 MCP tools may stall for minutes on first call. Run `ctxloom vectors-cleanup` (close other ctxloom MCP servers first) to fix.",
450
+ {
451
+ sourceFiles: sourceFileCount,
452
+ fragments: fragTotal,
453
+ ratio: Math.round(fragTotal / sourceFileCount),
454
+ ratioThreshold: FRAGMENT_RATIO_THRESHOLD,
455
+ sizeMB: Number(mb),
456
+ txn: fragCounts.txn,
457
+ manifest: fragCounts.manifest,
458
+ lance: fragCounts.lance
459
+ }
460
+ );
461
+ }
462
+ }
463
+ } catch {
464
+ }
465
+ }
438
466
  if (!ctx.noDefaultMode) {
439
467
  Promise.all([ctx.getGraph(), generateEmbedding("warmup")]).then(async ([graph]) => {
440
468
  logger.info("Ready", { edges: graph.edgeCount() });
@@ -1039,7 +1067,7 @@ try {
1039
1067
  } catch {
1040
1068
  }
1041
1069
  var args = process.argv.slice(2);
1042
- var ctxloomVersion = "1.7.2".length > 0 ? "1.7.2" : "dev";
1070
+ var ctxloomVersion = "1.7.3".length > 0 ? "1.7.3" : "dev";
1043
1071
  if (args.includes("--version") || args.includes("-v")) {
1044
1072
  process.stdout.write(`ctxloom ${ctxloomVersion}
1045
1073
  `);
@@ -1107,12 +1135,34 @@ function buildActivityFromOverlay(store) {
1107
1135
  lastCommitTimestamp
1108
1136
  }));
1109
1137
  }
1110
- var LICENSE_GATE_BYPASS_COMMANDS = /* @__PURE__ */ new Set(["trial", "activate", "deactivate", "status", "budget-stats", "--help"]);
1138
+ var LICENSE_GATE_BYPASS_COMMANDS = /* @__PURE__ */ new Set(["trial", "activate", "deactivate", "status", "budget-stats", "--help", "update"]);
1139
+ var KNOWN_COMMANDS = /* @__PURE__ */ new Set([
1140
+ "trial",
1141
+ "activate",
1142
+ "deactivate",
1143
+ "status",
1144
+ "init",
1145
+ "index",
1146
+ "setup",
1147
+ "install-pr-bot",
1148
+ "register",
1149
+ "repos",
1150
+ "grammars",
1151
+ "vectors-cleanup",
1152
+ "budget-stats",
1153
+ "dashboard",
1154
+ "review-suggest",
1155
+ "authors-sync",
1156
+ "rules",
1157
+ "update",
1158
+ "--help",
1159
+ "-h"
1160
+ ]);
1111
1161
  async function checkLicense() {
1112
1162
  if (command !== void 0 && LICENSE_GATE_BYPASS_COMMANDS.has(command)) return;
1113
1163
  const ciKey = process.env["CTXLOOM_LICENSE_KEY"];
1114
1164
  if (ciKey) {
1115
- const { ApiClient } = await import("./src-GTPLDFUS.js");
1165
+ const { ApiClient } = await import("./src-Y4TTG5HV.js");
1116
1166
  const client = new ApiClient(process.env["CTXLOOM_API_BASE"]);
1117
1167
  try {
1118
1168
  const result = await client.validate(ciKey, "ci-ephemeral");
@@ -1339,8 +1389,23 @@ async function main() {
1339
1389
  if (command !== void 0 && shouldEmitInstallCompleted()) {
1340
1390
  track("install_completed", { command });
1341
1391
  }
1392
+ if (command !== void 0 && !KNOWN_COMMANDS.has(command)) {
1393
+ process.stderr.write(
1394
+ `${error(`Unknown command: ${style.bold(String(command))}`)}
1395
+
1396
+ Run ${style.highlight("ctxloom --help")} for the list of available commands.
1397
+ To start the MCP server, run ${style.highlight("ctxloom")} with no arguments.
1398
+
1399
+ `
1400
+ );
1401
+ process.exit(1);
1402
+ }
1342
1403
  await checkLicense();
1343
1404
  switch (command) {
1405
+ case void 0: {
1406
+ await startServer({ withGit, gitWindowDays });
1407
+ break;
1408
+ }
1344
1409
  case "trial": {
1345
1410
  await runTrial();
1346
1411
  break;
@@ -1490,7 +1555,7 @@ async function main() {
1490
1555
  }
1491
1556
  if (!skipHarness) {
1492
1557
  process.stdout.write("\n");
1493
- const { installHarness } = await import("./src-GTPLDFUS.js");
1558
+ const { installHarness } = await import("./src-Y4TTG5HV.js");
1494
1559
  const h = installHarness({ cwd: initRoot, dryRun, force, extraHosts });
1495
1560
  const harnessFiles = [
1496
1561
  h.claudeMd,
@@ -1553,7 +1618,7 @@ async function main() {
1553
1618
  process.exit(1);
1554
1619
  }
1555
1620
  if (alias !== void 0) {
1556
- const { validateAlias } = await import("./src-GTPLDFUS.js");
1621
+ const { validateAlias } = await import("./src-Y4TTG5HV.js");
1557
1622
  const v = validateAlias(alias);
1558
1623
  if (!v.ok) {
1559
1624
  console.error(`[ctxloom] Invalid alias: ${v.reason}`);
@@ -1912,7 +1977,7 @@ Suggested reviewers for ${files.length} file(s):`);
1912
1977
  process.stderr.write("[ctxloom] --limit must be a non-negative integer (0 for unlimited)\n");
1913
1978
  process.exit(2);
1914
1979
  }
1915
- const { loadRulesConfig, RulesChecker, formatText, formatJson, RulesConfigError } = await import("./src-GTPLDFUS.js");
1980
+ const { loadRulesConfig, RulesChecker, formatText, formatJson, RulesConfigError } = await import("./src-Y4TTG5HV.js");
1916
1981
  let config;
1917
1982
  try {
1918
1983
  config = await loadRulesConfig(root);
@@ -1936,7 +2001,7 @@ Suggested reviewers for ${files.length} file(s):`);
1936
2001
  }
1937
2002
  let graph;
1938
2003
  if (useSnapshot) {
1939
- const { DependencyGraph: DG } = await import("./src-GTPLDFUS.js");
2004
+ const { DependencyGraph: DG } = await import("./src-Y4TTG5HV.js");
1940
2005
  graph = new DG();
1941
2006
  const loaded = await graph.loadSnapshotOnly(root);
1942
2007
  if (!loaded) {
@@ -1945,7 +2010,7 @@ Suggested reviewers for ${files.length} file(s):`);
1945
2010
  }
1946
2011
  } else {
1947
2012
  process.stderr.write("[ctxloom] Building dependency graph...\n");
1948
- const { ASTParser: ASTParser2, DependencyGraph: DependencyGraph2 } = await import("./src-GTPLDFUS.js");
2013
+ const { ASTParser: ASTParser2, DependencyGraph: DependencyGraph2 } = await import("./src-Y4TTG5HV.js");
1949
2014
  let parser;
1950
2015
  try {
1951
2016
  parser = new ASTParser2();
@@ -2062,10 +2127,23 @@ Tools Exposed:
2062
2127
  `);
2063
2128
  break;
2064
2129
  }
2065
- default: {
2066
- await startServer({ withGit, gitWindowDays });
2130
+ case "update": {
2131
+ const isQuiet = args.includes("--quiet");
2132
+ if (!isQuiet) {
2133
+ process.stdout.write(
2134
+ `${success("ctxloom update: no-op (MCP server FileWatcher handles incremental updates)")}
2135
+ `
2136
+ );
2137
+ }
2067
2138
  break;
2068
2139
  }
2140
+ default: {
2141
+ process.stderr.write(
2142
+ `${error(`Internal error: unhandled command '${String(command)}' reached switch default. This indicates KNOWN_COMMANDS and the switch are out of sync.`)}
2143
+ `
2144
+ );
2145
+ process.exit(1);
2146
+ }
2069
2147
  }
2070
2148
  }
2071
2149
  main().catch((err) => {
@@ -132,7 +132,7 @@ import {
132
132
  wrapBlock,
133
133
  wrapWithIndexingEnvelope,
134
134
  writeCODEOWNERS
135
- } from "./chunk-QL5UJTQL.js";
135
+ } from "./chunk-KQ5CQLIA.js";
136
136
  import {
137
137
  VectorStore
138
138
  } from "./chunk-7S2ELKNU.js";
@@ -300,4 +300,4 @@ export {
300
300
  wrapWithIndexingEnvelope,
301
301
  writeCODEOWNERS
302
302
  };
303
- //# sourceMappingURL=src-GTPLDFUS.js.map
303
+ //# sourceMappingURL=src-Y4TTG5HV.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ctxloom-pro",
3
- "version": "1.7.2",
3
+ "version": "1.7.3",
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",