ctxloom-pro 1.5.6 → 1.7.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.
@@ -1,3 +1,7 @@
1
+ import {
2
+ EMBEDDING_DIMENSION,
3
+ EMBEDDING_MODEL_ID
4
+ } from "./chunk-6FGTNOCP.js";
1
5
  import {
2
6
  logger
3
7
  } from "./chunk-TYDMSHV7.js";
@@ -34,8 +38,12 @@ var VectorStore = class {
34
38
  fs.mkdirSync(dir, { recursive: true });
35
39
  }
36
40
  const lancedb = await import("@lancedb/lancedb");
41
+ const lanceModule = lancedb.default ?? lancedb;
42
+ const lance = lanceModule;
37
43
  const { makeArrowTable } = lancedb;
38
- this.db = await lancedb.default.connect(this.dbPath);
44
+ this.db = await lance.connect(this.dbPath);
45
+ const markerPath = path.join(path.dirname(this.dbPath), "embedding-model.json");
46
+ this.assertModelCompatibility(markerPath);
39
47
  const existingTables = await this.db.tableNames();
40
48
  if (existingTables.includes("code_embeddings")) {
41
49
  this.table = await this.db.openTable("code_embeddings");
@@ -44,7 +52,7 @@ var VectorStore = class {
44
52
  {
45
53
  id: "__seed__",
46
54
  filePath: "__seed__",
47
- vector: new Array(384).fill(0),
55
+ vector: new Array(EMBEDDING_DIMENSION).fill(0),
48
56
  content: ""
49
57
  }
50
58
  ]);
@@ -53,6 +61,47 @@ var VectorStore = class {
53
61
  }
54
62
  this.initialized = true;
55
63
  }
64
+ /**
65
+ * Compare the active embedding model against the marker file written
66
+ * when the index was first built. Three cases:
67
+ *
68
+ * 1. Marker missing → legacy index (pre-v1.7.0). Assume MiniLM
69
+ * and write the marker so future runs are guarded.
70
+ * 2. Marker matches → proceed silently.
71
+ * 3. Marker differs → throw with a clear migration instruction.
72
+ * We don't auto-wipe — silently dropping a user's index because
73
+ * they set an env var is exactly the footgun the marker exists
74
+ * to prevent.
75
+ */
76
+ assertModelCompatibility(markerPath) {
77
+ const active = { model: EMBEDDING_MODEL_ID, dim: EMBEDDING_DIMENSION };
78
+ let existing = null;
79
+ if (fs.existsSync(markerPath)) {
80
+ try {
81
+ existing = JSON.parse(fs.readFileSync(markerPath, "utf-8"));
82
+ } catch (err) {
83
+ logger.warn("Embedding-model marker is corrupt; treating as missing", {
84
+ path: markerPath,
85
+ detail: err instanceof Error ? err.message : String(err)
86
+ });
87
+ }
88
+ }
89
+ if (!existing) {
90
+ fs.writeFileSync(markerPath, JSON.stringify(active, null, 2));
91
+ return;
92
+ }
93
+ if (existing.model === active.model && existing.dim === active.dim) {
94
+ return;
95
+ }
96
+ throw new Error(
97
+ `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
+
99
+ ctxloom vectors-cleanup --reset
100
+ ctxloom index
101
+
102
+ Or revert CTXLOOM_EMBEDDING_MODEL to "${existing.model}" to keep the existing index.`
103
+ );
104
+ }
56
105
  /**
57
106
  * Release LanceDB resources (file descriptors held by the underlying
58
107
  * connection / table handles). Must be called at the end of long-lived
@@ -101,6 +150,48 @@ var VectorStore = class {
101
150
  await this.compact();
102
151
  }
103
152
  }
153
+ /**
154
+ * Batch upsert — one LanceDB transaction for N file records.
155
+ *
156
+ * Why this exists (v1.7.0 monorepo support): the per-file `upsert()`
157
+ * does 2 LanceDB transactions (delete + add). On a 50k-file repo
158
+ * that's 100k transactions, each writing a manifest + transaction
159
+ * file. Compaction reclaims them every 200 upserts, but during the
160
+ * indexing burst the FD churn is enormous (observed: ~10k FDs/sec
161
+ * peak on Next.js, hitting the 256-default macOS process limit).
162
+ *
163
+ * With BATCH_SIZE=50 callers (the streaming indexer), this drops to
164
+ * ~2k transactions across the same corpus — 50× fewer manifests
165
+ * written, ~5× faster wall time, and the FD ceiling stops mattering.
166
+ *
167
+ * Compaction semantics unchanged: `upsertsSinceCompact` increments by
168
+ * one per RECORD (not per batch), so the compact trigger fires at
169
+ * the same total-record cadence as the per-file path.
170
+ */
171
+ async upsertBatch(records) {
172
+ if (!this.table) throw new Error("VectorStore not initialized. Call init() first.");
173
+ if (records.length === 0) return;
174
+ const filter = records.map((r) => `filePath = '${sanitizeFilterPath(r.filePath)}'`).join(" OR ");
175
+ try {
176
+ await this.table.delete(filter);
177
+ } catch (err) {
178
+ logger.warn("Batch delete before upsert failed, continuing", {
179
+ detail: err instanceof Error ? err.message : String(err)
180
+ });
181
+ }
182
+ const rows = records.map((r) => ({
183
+ id: r.filePath,
184
+ filePath: r.filePath,
185
+ vector: r.embedding,
186
+ content: r.content.slice(0, 512)
187
+ }));
188
+ await this.table.add(rows);
189
+ this.upsertsSinceCompact += records.length;
190
+ if (this.upsertsSinceCompact >= this.compactEvery) {
191
+ this.upsertsSinceCompact = 0;
192
+ await this.compact();
193
+ }
194
+ }
104
195
  /**
105
196
  * Merge fragments and prune old LanceDB versions. Idempotent and safe to
106
197
  * call mid-flight; the Table API serializes writes internally. Called
@@ -131,6 +222,35 @@ var VectorStore = class {
131
222
  });
132
223
  }
133
224
  }
225
+ /**
226
+ * Retrieve the stored embedding for a known file. Returns null if the
227
+ * file isn't indexed. Used by blast-radius semantic-similarity search
228
+ * (v1.6.x) to find files semantically related to a seed without
229
+ * re-embedding the seed at query time.
230
+ */
231
+ async findEmbeddingByPath(filePath) {
232
+ if (!this.table) throw new Error("VectorStore not initialized. Call init() first.");
233
+ try {
234
+ const safe = sanitizeFilterPath(filePath);
235
+ const rows = await this.table.query().where(`filePath = '${safe}'`).limit(1).toArray();
236
+ const first = rows[0];
237
+ if (!first) return null;
238
+ const vec = first.vector;
239
+ if (vec === null || vec === void 0) return null;
240
+ if (Array.isArray(vec)) return vec;
241
+ if (vec instanceof Float32Array) return Array.from(vec);
242
+ if (typeof vec.length === "number") {
243
+ return Array.from(vec);
244
+ }
245
+ return null;
246
+ } catch (err) {
247
+ logger.warn("VectorStore.findEmbeddingByPath failed", {
248
+ detail: err instanceof Error ? err.message : String(err),
249
+ filePath
250
+ });
251
+ return null;
252
+ }
253
+ }
134
254
  /**
135
255
  * Search for the top-K most similar code records using vector search.
136
256
  */
@@ -187,4 +307,4 @@ var VectorStore = class {
187
307
  export {
188
308
  VectorStore
189
309
  };
190
- //# sourceMappingURL=chunk-JULFFD7O.js.map
310
+ //# sourceMappingURL=chunk-7S2ELKNU.js.map
@@ -15,6 +15,15 @@ var CTXLOOM_SERVER = {
15
15
  args: ["-y", "ctxloom"],
16
16
  env: {}
17
17
  };
18
+ function tomlString(s) {
19
+ const escaped = s.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t").replace(/[\x00-\x1f\x7f]/g, (c) => `\\u${c.charCodeAt(0).toString(16).padStart(4, "0")}`);
20
+ return `"${escaped}"`;
21
+ }
22
+ function yamlEscape(s) {
23
+ if (/^[A-Za-z0-9_./-][A-Za-z0-9_./@-]*$/.test(s)) return s;
24
+ const escaped = s.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
25
+ return `"${escaped}"`;
26
+ }
18
27
  var _serverEntry;
19
28
  function getServerEntry() {
20
29
  if (_serverEntry) return _serverEntry;
@@ -55,9 +64,16 @@ var MCP_CLIENTS = [
55
64
  id: "cursor",
56
65
  name: "Cursor",
57
66
  description: "Cursor AI code editor",
67
+ // Vendor docs (Cursor team, verified 2026-05) list TWO canonical paths:
68
+ // - `<repo>/.cursor/mcp.json` (project-scoped — the documented default)
69
+ // - `~/.cursor/mcp.json` (user-scoped, applies to every project)
70
+ // The XDG-style paths in the old list were speculative; Cursor never
71
+ // shipped them. Project-root scope goes FIRST so a per-project install
72
+ // matches the canonical workflow before we touch the user-wide config.
58
73
  configPaths: [
59
- path.join(xdgConfig(), "Cursor", "User", "globalStorage", "cursor-mcp", "mcp.json"),
74
+ path.join(process.cwd(), ".cursor", "mcp.json"),
60
75
  path.join(HOME, ".cursor", "mcp.json"),
76
+ path.join(xdgConfig(), "Cursor", "User", "globalStorage", "cursor-mcp", "mcp.json"),
61
77
  path.join(xdgConfig(), "Cursor", "mcp.json")
62
78
  ],
63
79
  cliBinaries: ["cursor"],
@@ -124,23 +140,41 @@ var MCP_CLIENTS = [
124
140
  serversPath: "mcpServers"
125
141
  },
126
142
  // ─── Continue.dev ───────────────────────────────────────
143
+ // v1.7.0 fix: current Continue (2026+) uses **per-server YAML files**
144
+ // at `.continue/mcpServers/<name>.yaml` (workspace-scoped), NOT the
145
+ // old `~/.continue/config.json` with embedded `experimental.mcpServers`.
146
+ // Writing to the old path silently fails on current Continue — the
147
+ // file is parsed but the section is ignored. Verified against
148
+ // docs.continue.dev/customize/deep-dives/mcp (2026-05).
149
+ //
150
+ // The customWriter renders the entire YAML file because each MCP
151
+ // server gets its own file; there's no merge step.
127
152
  {
128
153
  id: "continue",
129
154
  name: "Continue.dev",
130
155
  description: "Continue open-source AI code assistant",
156
+ // Workspace-scoped path FIRST (the canonical/correct path on
157
+ // current Continue). Legacy user-scoped paths kept as detection
158
+ // fallback so we still detect Continue's presence on machines
159
+ // that haven't migrated their config yet.
131
160
  configPaths: [
161
+ path.join(process.cwd(), ".continue", "mcpServers", "ctxloom.yaml"),
132
162
  path.join(HOME, ".continue", "config.json"),
133
163
  path.join(xdgConfig(), "continue", "config.json")
134
164
  ],
135
165
  cliBinaries: ["continue"],
136
166
  appBundles: [],
137
167
  usesMcpServersFormat: false,
138
- serversPath: "experimental.mcpServers",
139
- formatConfig: (entry) => ({
140
- command: entry.command,
141
- args: entry.args,
142
- transport: "stdio"
143
- })
168
+ serversPath: "mcpServers",
169
+ customWriter: (_targetPath, entry, _existingContent) => {
170
+ const envLines = entry.env && Object.keys(entry.env).length > 0 ? "\n env:\n" + Object.entries(entry.env).map(([k, v]) => ` ${k}: ${yamlEscape(v)}`).join("\n") : "";
171
+ const argsLines = entry.args && entry.args.length > 0 ? "\n args:\n" + entry.args.map((a) => ` - ${yamlEscape(a)}`).join("\n") : "\n args: []";
172
+ return `# Generated by \`ctxloom setup\` \u2014 Continue MCP server registration.
173
+ # Format: docs.continue.dev/customize/deep-dives/mcp
174
+ mcpServers:
175
+ - name: ctxloom
176
+ command: ${yamlEscape(entry.command)}` + argsLines + envLines + "\n";
177
+ }
144
178
  },
145
179
  // ─── Aider ──────────────────────────────────────────────
146
180
  {
@@ -157,18 +191,83 @@ var MCP_CLIENTS = [
157
191
  serversPath: "mcpServers"
158
192
  },
159
193
  // ─── Codex CLI (OpenAI) ─────────────────────────────────
194
+ // v1.7.0 fix: current Codex (2026+) uses **TOML at config.toml**,
195
+ // NOT JSON at mcp.json. The schema key is `mcp_servers` (snake_case
196
+ // TOML), NOT `mcpServers`. Writing JSON to the old `.codex/mcp.json`
197
+ // path silently fails on current Codex — the file is never read.
198
+ // Verified against developers.openai.com/codex/config-reference
199
+ // (2026-05).
200
+ //
201
+ // config.toml is SHARED with other Codex settings (model selection,
202
+ // auth, sandbox prefs), so the writer reads existing content,
203
+ // appends/updates ONLY the `[mcp_servers.ctxloom]` block, and
204
+ // preserves everything else. We deliberately avoid pulling in a
205
+ // TOML parser library — the only mutation is a single named-table
206
+ // block, which append-or-replace by string match handles safely.
160
207
  {
161
208
  id: "codex",
162
209
  name: "Codex CLI",
163
210
  description: "OpenAI Codex CLI agent",
211
+ // Workspace path FIRST (canonical per Codex docs); user-scoped
212
+ // path second (preserves detection on machines with Codex
213
+ // installed but no project-local config yet).
164
214
  configPaths: [
215
+ path.join(process.cwd(), ".codex", "config.toml"),
216
+ path.join(HOME, ".codex", "config.toml"),
217
+ // Legacy detection only — won't be written to. Kept so users
218
+ // who created these in earlier ctxloom versions still get
219
+ // detected (they need to migrate, but at least we surface them).
165
220
  path.join(HOME, ".codex", "mcp.json"),
166
221
  path.join(xdgConfig(), "codex", "mcp.json")
167
222
  ],
168
223
  cliBinaries: ["codex"],
169
224
  appBundles: [],
170
- usesMcpServersFormat: true,
171
- serversPath: "mcpServers"
225
+ usesMcpServersFormat: false,
226
+ serversPath: "mcp_servers",
227
+ customInstalledCheck: (target) => {
228
+ try {
229
+ const content = fs.readFileSync(target, "utf-8");
230
+ return /^\s*\[mcp_servers\.ctxloom\]\s*$/m.test(content);
231
+ } catch {
232
+ return false;
233
+ }
234
+ },
235
+ customWriter: (_targetPath, entry, existingContent) => {
236
+ const lines = [
237
+ "# ctxloom \u2014 added by `ctxloom setup`. Safe to edit; the",
238
+ "# installer only ever modifies the [mcp_servers.ctxloom]",
239
+ "# block and never touches the rest of this file.",
240
+ "[mcp_servers.ctxloom]",
241
+ `command = ${tomlString(entry.command)}`,
242
+ `args = [${(entry.args ?? []).map(tomlString).join(", ")}]`
243
+ ];
244
+ if (entry.env && Object.keys(entry.env).length > 0) {
245
+ lines.push("");
246
+ lines.push("[mcp_servers.ctxloom.env]");
247
+ for (const [k, v] of Object.entries(entry.env)) {
248
+ lines.push(`${k} = ${tomlString(v)}`);
249
+ }
250
+ }
251
+ const newBlock = lines.join("\n") + "\n";
252
+ if (!existingContent) {
253
+ return newBlock;
254
+ }
255
+ const blockRegex = /(^|\n)(?:#[^\n]*\n)*\[mcp_servers\.ctxloom\][\s\S]*?(?=\n\[(?!mcp_servers\.ctxloom)|$)/;
256
+ if (blockRegex.test(existingContent)) {
257
+ return existingContent.replace(
258
+ blockRegex,
259
+ (_m, leading) => (leading === "\n" ? "\n" : "") + newBlock.trimEnd()
260
+ );
261
+ }
262
+ const sep = existingContent.endsWith("\n") ? "\n" : "\n\n";
263
+ return existingContent + sep + newBlock;
264
+ },
265
+ customRemove: (existingContent) => {
266
+ const blockWithLeadingComments = /(^|\n)(?:#[^\n]*\n)*\[mcp_servers\.ctxloom\][\s\S]*?(?=\n\[(?!mcp_servers\.ctxloom)|$)/;
267
+ const stripped = existingContent.replace(blockWithLeadingComments, (_m, leading) => leading);
268
+ if (stripped.trim() === "") return null;
269
+ return stripped;
270
+ }
172
271
  },
173
272
  // ─── Kimi ───────────────────────────────────────────────
174
273
  {
@@ -210,6 +309,77 @@ var MCP_CLIENTS = [
210
309
  appBundles: ["com.jetbrains.intellij"],
211
310
  usesMcpServersFormat: true,
212
311
  serversPath: "mcpServers"
312
+ },
313
+ // ─── Zed ────────────────────────────────────────────────
314
+ // Zed's MCP config lives under the main settings.json, NOT a
315
+ // dedicated mcp.json. Critical wrinkle: the key is `context_servers`,
316
+ // not the conventional `mcpServers` — silently ignored otherwise.
317
+ // Verified against zed.dev/docs/ai/mcp (2026-05).
318
+ {
319
+ id: "zed",
320
+ name: "Zed",
321
+ description: "Zed high-performance code editor",
322
+ configPaths: [
323
+ path.join(xdgConfig(), "zed", "settings.json"),
324
+ path.join(HOME, ".config", "zed", "settings.json")
325
+ ],
326
+ cliBinaries: ["zed"],
327
+ appBundles: ["dev.zed.Zed", "dev.zed.Zed-Preview"],
328
+ usesMcpServersFormat: true,
329
+ serversPath: "context_servers"
330
+ },
331
+ // ─── Gemini CLI ─────────────────────────────────────────
332
+ // Google's Gemini CLI tool. Workspace config wins over user config
333
+ // when both exist; we list the workspace path first so a project
334
+ // install lands where the user expects. Schema is standard
335
+ // `mcpServers` per google-gemini/gemini-cli docs/cli/settings.md.
336
+ {
337
+ id: "gemini-cli",
338
+ name: "Gemini CLI",
339
+ description: "Google Gemini command-line AI agent",
340
+ configPaths: [
341
+ path.join(process.cwd(), ".gemini", "settings.json"),
342
+ path.join(HOME, ".gemini", "settings.json")
343
+ ],
344
+ cliBinaries: ["gemini"],
345
+ appBundles: [],
346
+ usesMcpServersFormat: true,
347
+ serversPath: "mcpServers"
348
+ },
349
+ // ─── Kiro ───────────────────────────────────────────────
350
+ // Kiro IDE (kiro.dev). Both workspace + user configs are honored;
351
+ // workspace overrides user per Kiro's docs. Schema is standard
352
+ // `mcpServers`.
353
+ {
354
+ id: "kiro",
355
+ name: "Kiro",
356
+ description: "Kiro AI-first IDE",
357
+ configPaths: [
358
+ path.join(process.cwd(), ".kiro", "settings", "mcp.json"),
359
+ path.join(HOME, ".kiro", "settings", "mcp.json")
360
+ ],
361
+ cliBinaries: ["kiro"],
362
+ appBundles: ["dev.kiro.Kiro"],
363
+ usesMcpServersFormat: true,
364
+ serversPath: "mcpServers"
365
+ },
366
+ // ─── OpenCode ───────────────────────────────────────────
367
+ // Project-root configured. Critical wrinkle: the key is `mcp`
368
+ // (not `mcpServers`) — code-review-graph's PLATFORMS dict had
369
+ // this wrong; verified against opencode.ai/docs/mcp-servers.
370
+ // Supports both .json and .jsonc extensions.
371
+ {
372
+ id: "opencode",
373
+ name: "OpenCode",
374
+ description: "OpenCode agentic coding tool",
375
+ configPaths: [
376
+ path.join(process.cwd(), "opencode.json"),
377
+ path.join(process.cwd(), "opencode.jsonc")
378
+ ],
379
+ cliBinaries: ["opencode"],
380
+ appBundles: [],
381
+ usesMcpServersFormat: true,
382
+ serversPath: "mcp"
213
383
  }
214
384
  ];
215
385
  function detectInstalledClients() {
@@ -224,6 +394,12 @@ function detectInstalledClients() {
224
394
  detected = true;
225
395
  configPath = cp;
226
396
  configExists = true;
397
+ if (client.customWriter) {
398
+ if (cp === client.configPaths[0]) {
399
+ alreadyConfigured = client.customInstalledCheck ? client.customInstalledCheck(cp) : true;
400
+ }
401
+ break;
402
+ }
227
403
  try {
228
404
  const content = fs.readFileSync(cp, "utf-8");
229
405
  const config = JSON.parse(content);
@@ -314,6 +490,20 @@ function addCtxloomToConfig(detected) {
314
490
  if (alreadyConfigured) {
315
491
  return { success: true, message: `ctxloom is already configured in ${client.name}` };
316
492
  }
493
+ if (client.customWriter) {
494
+ const targetPath = client.configPaths[0];
495
+ const serverEntry2 = getServerEntry();
496
+ const existingContent = fs.existsSync(targetPath) ? fs.readFileSync(targetPath, "utf-8") : null;
497
+ const content = client.customWriter(targetPath, serverEntry2, existingContent);
498
+ const dir2 = path.dirname(targetPath);
499
+ if (!fs.existsSync(dir2)) fs.mkdirSync(dir2, { recursive: true });
500
+ try {
501
+ fs.writeFileSync(targetPath, content, "utf-8");
502
+ return { success: true, message: `Added ctxloom to ${client.name} (${targetPath})` };
503
+ } catch (err) {
504
+ return { success: false, message: `Failed to write config at ${targetPath}: ${err}` };
505
+ }
506
+ }
317
507
  let config;
318
508
  if (configExists) {
319
509
  try {
@@ -349,4 +539,4 @@ export {
349
539
  detectInstalledClients,
350
540
  addCtxloomToConfig
351
541
  };
352
- //# sourceMappingURL=chunk-II2DPYRJ.js.map
542
+ //# sourceMappingURL=chunk-YHLMQVBV.js.map
@@ -0,0 +1,26 @@
1
+ import {
2
+ EMBEDDING_DIMENSION,
3
+ EMBEDDING_MODEL_ID,
4
+ INDEXER_IGNORED_DIRS,
5
+ collectFiles,
6
+ collectFilesStream,
7
+ generateEmbedding,
8
+ generateEmbeddingBatch,
9
+ getActiveEmbeddingModel,
10
+ indexDirectory,
11
+ resolveEmbeddingModel
12
+ } from "./chunk-6FGTNOCP.js";
13
+ import "./chunk-TYDMSHV7.js";
14
+ export {
15
+ EMBEDDING_DIMENSION,
16
+ EMBEDDING_MODEL_ID,
17
+ INDEXER_IGNORED_DIRS,
18
+ collectFiles,
19
+ collectFilesStream,
20
+ generateEmbedding,
21
+ generateEmbeddingBatch,
22
+ getActiveEmbeddingModel,
23
+ indexDirectory,
24
+ resolveEmbeddingModel
25
+ };
26
+ //# sourceMappingURL=embedder-2JWDJUE2.js.map
package/dist/index.js CHANGED
@@ -47,18 +47,18 @@ import {
47
47
  validateDefaultRoot,
48
48
  wrapWithIndexingEnvelope,
49
49
  writeCODEOWNERS
50
- } from "./chunk-FPMNXF4D.js";
50
+ } from "./chunk-6W4DFPP2.js";
51
51
  import {
52
52
  addCtxloomToConfig,
53
53
  detectInstalledClients
54
- } from "./chunk-II2DPYRJ.js";
54
+ } from "./chunk-YHLMQVBV.js";
55
55
  import {
56
56
  VectorStore
57
- } from "./chunk-JULFFD7O.js";
57
+ } from "./chunk-7S2ELKNU.js";
58
58
  import {
59
59
  generateEmbedding,
60
60
  indexDirectory
61
- } from "./chunk-WDX4PJGL.js";
61
+ } from "./chunk-6FGTNOCP.js";
62
62
  import "./chunk-5I6CJITG.js";
63
63
  import {
64
64
  logger
@@ -1039,7 +1039,7 @@ try {
1039
1039
  } catch {
1040
1040
  }
1041
1041
  var args = process.argv.slice(2);
1042
- var ctxloomVersion = "1.5.6".length > 0 ? "1.5.6" : "dev";
1042
+ var ctxloomVersion = "1.7.1".length > 0 ? "1.7.1" : "dev";
1043
1043
  if (args.includes("--version") || args.includes("-v")) {
1044
1044
  process.stdout.write(`ctxloom ${ctxloomVersion}
1045
1045
  `);
@@ -1112,7 +1112,7 @@ async function checkLicense() {
1112
1112
  if (command !== void 0 && LICENSE_GATE_BYPASS_COMMANDS.has(command)) return;
1113
1113
  const ciKey = process.env["CTXLOOM_LICENSE_KEY"];
1114
1114
  if (ciKey) {
1115
- const { ApiClient } = await import("./src-DL44T55H.js");
1115
+ const { ApiClient } = await import("./src-FQQOURSD.js");
1116
1116
  const client = new ApiClient(process.env["CTXLOOM_API_BASE"]);
1117
1117
  try {
1118
1118
  const result = await client.validate(ciKey, "ci-ephemeral");
@@ -1490,7 +1490,7 @@ async function main() {
1490
1490
  }
1491
1491
  if (!skipHarness) {
1492
1492
  process.stdout.write("\n");
1493
- const { installHarness } = await import("./src-DL44T55H.js");
1493
+ const { installHarness } = await import("./src-FQQOURSD.js");
1494
1494
  const h = installHarness({ cwd: initRoot, dryRun, force, extraHosts });
1495
1495
  const harnessFiles = [
1496
1496
  h.claudeMd,
@@ -1553,7 +1553,7 @@ async function main() {
1553
1553
  process.exit(1);
1554
1554
  }
1555
1555
  if (alias !== void 0) {
1556
- const { validateAlias } = await import("./src-DL44T55H.js");
1556
+ const { validateAlias } = await import("./src-FQQOURSD.js");
1557
1557
  const v = validateAlias(alias);
1558
1558
  if (!v.ok) {
1559
1559
  console.error(`[ctxloom] Invalid alias: ${v.reason}`);
@@ -1912,7 +1912,7 @@ Suggested reviewers for ${files.length} file(s):`);
1912
1912
  process.stderr.write("[ctxloom] --limit must be a non-negative integer (0 for unlimited)\n");
1913
1913
  process.exit(2);
1914
1914
  }
1915
- const { loadRulesConfig, RulesChecker, formatText, formatJson, RulesConfigError } = await import("./src-DL44T55H.js");
1915
+ const { loadRulesConfig, RulesChecker, formatText, formatJson, RulesConfigError } = await import("./src-FQQOURSD.js");
1916
1916
  let config;
1917
1917
  try {
1918
1918
  config = await loadRulesConfig(root);
@@ -1936,7 +1936,7 @@ Suggested reviewers for ${files.length} file(s):`);
1936
1936
  }
1937
1937
  let graph;
1938
1938
  if (useSnapshot) {
1939
- const { DependencyGraph: DG } = await import("./src-DL44T55H.js");
1939
+ const { DependencyGraph: DG } = await import("./src-FQQOURSD.js");
1940
1940
  graph = new DG();
1941
1941
  const loaded = await graph.loadSnapshotOnly(root);
1942
1942
  if (!loaded) {
@@ -1945,7 +1945,7 @@ Suggested reviewers for ${files.length} file(s):`);
1945
1945
  }
1946
1946
  } else {
1947
1947
  process.stderr.write("[ctxloom] Building dependency graph...\n");
1948
- const { ASTParser: ASTParser2, DependencyGraph: DependencyGraph2 } = await import("./src-DL44T55H.js");
1948
+ const { ASTParser: ASTParser2, DependencyGraph: DependencyGraph2 } = await import("./src-FQQOURSD.js");
1949
1949
  let parser;
1950
1950
  try {
1951
1951
  parser = new ASTParser2();
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  detectInstalledClients
4
- } from "../chunk-II2DPYRJ.js";
4
+ } from "../chunk-YHLMQVBV.js";
5
5
 
6
6
  // src/setup/postinstall.ts
7
7
  var C = {
@@ -65,6 +65,7 @@ import {
65
65
  computeBlockHmac,
66
66
  computeRiskBreakdown,
67
67
  computeRiskCaps,
68
+ computeSemanticSimilar,
68
69
  createProjectState,
69
70
  createToolRegistry,
70
71
  deactivateLicense,
@@ -131,16 +132,16 @@ import {
131
132
  wrapBlock,
132
133
  wrapWithIndexingEnvelope,
133
134
  writeCODEOWNERS
134
- } from "./chunk-FPMNXF4D.js";
135
+ } from "./chunk-6W4DFPP2.js";
135
136
  import {
136
137
  VectorStore
137
- } from "./chunk-JULFFD7O.js";
138
+ } from "./chunk-7S2ELKNU.js";
138
139
  import {
139
140
  EMBEDDING_DIMENSION,
140
141
  collectFiles,
141
142
  generateEmbedding,
142
143
  indexDirectory
143
- } from "./chunk-WDX4PJGL.js";
144
+ } from "./chunk-6FGTNOCP.js";
144
145
  import {
145
146
  filenameForDate,
146
147
  readEvents,
@@ -223,6 +224,7 @@ export {
223
224
  computeBlockHmac,
224
225
  computeRiskBreakdown,
225
226
  computeRiskCaps,
227
+ computeSemanticSimilar,
226
228
  createProjectState,
227
229
  createToolRegistry,
228
230
  deactivateLicense,
@@ -298,4 +300,4 @@ export {
298
300
  wrapWithIndexingEnvelope,
299
301
  writeCODEOWNERS
300
302
  };
301
- //# sourceMappingURL=src-DL44T55H.js.map
303
+ //# sourceMappingURL=src-FQQOURSD.js.map
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  VectorStore
3
- } from "../chunk-JULFFD7O.js";
3
+ } from "../chunk-7S2ELKNU.js";
4
4
  import {
5
5
  generateEmbedding
6
- } from "../chunk-WDX4PJGL.js";
6
+ } from "../chunk-6FGTNOCP.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.6",
3
+ "version": "1.7.1",
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,8 +0,0 @@
1
- import {
2
- VectorStore
3
- } from "./chunk-JULFFD7O.js";
4
- import "./chunk-TYDMSHV7.js";
5
- export {
6
- VectorStore
7
- };
8
- //# sourceMappingURL=VectorStore-2LVECRTY.js.map