ctxloom-pro 1.0.24 → 1.0.26

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
@@ -10,70 +10,70 @@ No cloud indexing. No Python. Everything runs on your machine.
10
10
 
11
11
  **Prerequisites:** Node.js 20+ and an MCP-compatible AI tool (Claude Code, Cursor, Windsurf, etc.)
12
12
 
13
- ### 1 Install
13
+ The full first-run flow is **one install + one trial + one init per project.** Each step is a single command.
14
+
15
+ ### 1 — Install (once per machine)
14
16
 
15
17
  ```bash
16
- # 1. Install globally
17
18
  npm install -g ctxloom-pro
18
-
19
- # 2. Auto-configure your AI tools (one-time)
20
- ctxloom setup
21
-
22
- # 3. Index your project (once per project)
23
- cd /path/to/your/project
24
- ctxloom index
25
19
  ```
26
20
 
27
- ### 2 — Start your free trial
21
+ ### 2 — Start your free trial (once per email)
28
22
 
29
23
  ```bash
30
24
  ctxloom trial
31
25
  # Enter your email — a checkout link opens in your browser.
32
- # No credit card. After checkout, Polar emails you a license key.
26
+ # No credit card required. After checkout, you receive a license key by email.
33
27
  ```
34
28
 
35
29
  Already have a key?
36
30
 
37
31
  ```bash
38
- ctxloom activate ctxl_pro_<your-key>
32
+ ctxloom activate <your-key>
39
33
  ```
40
34
 
41
- ### 3 — Auto-configure your AI tools
35
+ ### 3 — Configure your AI tools (once per machine)
42
36
 
43
37
  ```bash
44
- ctxloom setup # detects Claude Code, Cursor, Windsurf, etc.
38
+ ctxloom setup
39
+ # Detects Claude Code, Cursor, Windsurf, Claude Desktop, Codex,
40
+ # Kimi, Continue, Aider, Augment, Kilo, Qwen, JetBrains, VS Code —
41
+ # writes the global MCP entry for each one you have installed.
45
42
  ```
46
43
 
47
- ### 4 — Index your project
44
+ ### 4 — Bootstrap each project (once per project)
48
45
 
49
46
  ```bash
50
47
  cd /path/to/your/project
48
+ ctxloom init # writes .mcp.json + appends .ctxloom/ to .gitignore
51
49
  ctxloom index # builds vector + graph + git overlay
52
50
  ```
53
51
 
54
- Your AI assistant now has full structural context. Ask it anything about the codebase.
52
+ `ctxloom init` is the piece that pins ctxloom to **this** project. Without it, MCP clients (notably Claude Code) launch the global MCP server with cwd inherited from wherever the IDE was first opened — and **do not relaunch on project switch** — so a single Claude Code session ends up serving graph queries from the wrong codebase. The `.mcp.json` produced by `init` carries an explicit `CTXLOOM_ROOT` and short-circuits that ambiguity.
53
+
54
+ After `init` + `index`, reopen your AI tool in the project directory. Your assistant now has full structural context.
55
55
 
56
56
  ### License commands
57
57
 
58
58
  ```bash
59
- ctxloom status # show tier, expiry, last validation
59
+ ctxloom status # tier, expiry, last validation
60
60
  ctxloom deactivate # release this machine's seat (to move to a new machine)
61
61
  ```
62
62
 
63
63
  ### CI / headless environments
64
64
 
65
65
  ```bash
66
- CTXLOOM_LICENSE_KEY=ctxl_pro_<key> ctxloom index
66
+ CTXLOOM_LICENSE_KEY=<your-key> ctxloom index
67
67
  ```
68
68
 
69
69
  Set `CTXLOOM_LICENSE_KEY` in your CI secrets. The key is validated on every run — no local state written to the runner.
70
70
 
71
- ### Manual MCP Configuration
71
+ ### Manual MCP configuration (if you skip `ctxloom setup`)
72
72
 
73
- This is what `ctxloom setup` writes for you. Match it by hand if you prefer:
73
+ Global MCP entry match this in your client's config file by hand:
74
74
 
75
75
  ```jsonc
76
- // Claude Code: ~/.claude.json
76
+ // Claude Code: ~/.claude.json or .mcp.json in the project
77
77
  // Cursor: ~/.cursor/mcp.json
78
78
  // Codex CLI: ~/.codex/mcp.json
79
79
  // Kimi: ~/.kimi/mcp.json
@@ -88,9 +88,9 @@ This is what `ctxloom setup` writes for you. Match it by hand if you prefer:
88
88
  }
89
89
  ```
90
90
 
91
- The MCP server inherits cwd from the host. Claude Code, Cursor, Codex, and Kimi all spawn it with the open project as cwd, so the right project is indexed automatically no `CTXLOOM_ROOT` needed.
91
+ Then run `ctxloom init` inside each project — it writes a `.mcp.json` in the project root with `env.CTXLOOM_ROOT` set, which overrides the global entry on a per-project basis (Claude Code, Cursor, and the other MCP-aware clients merge per-project config over global automatically).
92
92
 
93
- For hosts without a project concept (Claude Desktop, CI), set the root explicitly:
93
+ If you have a single fixed project (e.g. a CI runner or a Claude Desktop session with no project concept), pin the global entry directly:
94
94
 
95
95
  ```jsonc
96
96
  {
@@ -103,8 +103,8 @@ For hosts without a project concept (Claude Desktop, CI), set the root explicitl
103
103
  }
104
104
  }
105
105
  ```
106
- >
107
- > Pricing: **Pro** €9.90/mo or €99/yr (1 machine) · **Team** €19.90/mo or €199/yr (3 machines) · [ctxloom.com/pricing](https://ctxloom.com/pricing)
106
+
107
+ > Pricing: **Pro** €9.90/mo or €99/yr (1 seat) · **Team** €29.90/mo or €299/yr (5 seats) · [ctxloom.com/pricing](https://ctxloom.com/pricing)
108
108
 
109
109
  ---
110
110
 
@@ -82,17 +82,24 @@ import fs3 from "fs";
82
82
  import path3 from "path";
83
83
  function collectFiles(dir, results = []) {
84
84
  const IGNORED_DIRS = /* @__PURE__ */ new Set([
85
+ // Build artifacts + dependency caches
85
86
  "node_modules",
86
- ".git",
87
87
  "dist",
88
88
  "build",
89
- ".ctxloom",
89
+ "out",
90
+ "target",
90
91
  "coverage",
92
+ ".cache",
93
+ ".turbo",
91
94
  ".next",
92
95
  ".nuxt",
93
- "out",
94
- ".cache",
95
- ".turbo"
96
+ // Version control + ctxloom state
97
+ ".git",
98
+ ".ctxloom",
99
+ // Other tools' working state (often contains duplicated source)
100
+ ".claude",
101
+ ".code-review-graph",
102
+ ".vscode-test"
96
103
  ]);
97
104
  const SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([
98
105
  ".ts",
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  collectFiles,
6
6
  generateEmbedding
7
- } from "./chunk-TVQ7CBWU.js";
7
+ } from "./chunk-NYBVAPM3.js";
8
8
  import {
9
9
  logger
10
10
  } from "./chunk-TYDMSHV7.js";
@@ -6583,7 +6583,7 @@ function registerFullTextSearchTool(registry, ctx) {
6583
6583
  const { query, mode, case_sensitive, limit, context_lines } = Schema22.parse(args);
6584
6584
  if (mode === "semantic") {
6585
6585
  try {
6586
- const { generateEmbedding: generateEmbedding2 } = await import("./embedder-VHOY4L6L.js");
6586
+ const { generateEmbedding: generateEmbedding2 } = await import("./embedder-ZGEKFHHK.js");
6587
6587
  const store = await ctx.getStore();
6588
6588
  const embedding = await generateEmbedding2(query);
6589
6589
  const results = await store.search(embedding, limit);
@@ -6620,7 +6620,7 @@ function registerFullTextSearchTool(registry, ctx) {
6620
6620
  let merged = keywordResults.slice(0, limit);
6621
6621
  if (mode === "hybrid") {
6622
6622
  try {
6623
- const { generateEmbedding: generateEmbedding2 } = await import("./embedder-VHOY4L6L.js");
6623
+ const { generateEmbedding: generateEmbedding2 } = await import("./embedder-ZGEKFHHK.js");
6624
6624
  const store = await ctx.getStore();
6625
6625
  const embedding = await generateEmbedding2(query);
6626
6626
  const vectorResults = await store.search(embedding, Math.ceil(limit / 2));
@@ -8741,4 +8741,4 @@ export {
8741
8741
  track,
8742
8742
  captureError
8743
8743
  };
8744
- //# sourceMappingURL=chunk-O4TQWLH6.js.map
8744
+ //# sourceMappingURL=chunk-GI354NTO.js.map
@@ -63,17 +63,24 @@ async function generateEmbedding(text) {
63
63
  }
64
64
  function collectFiles(dir, results = []) {
65
65
  const IGNORED_DIRS = /* @__PURE__ */ new Set([
66
+ // Build artifacts + dependency caches
66
67
  "node_modules",
67
- ".git",
68
68
  "dist",
69
69
  "build",
70
- ".ctxloom",
70
+ "out",
71
+ "target",
71
72
  "coverage",
73
+ ".cache",
74
+ ".turbo",
72
75
  ".next",
73
76
  ".nuxt",
74
- "out",
75
- ".cache",
76
- ".turbo"
77
+ // Version control + ctxloom state
78
+ ".git",
79
+ ".ctxloom",
80
+ // Other tools' working state (often contains duplicated source)
81
+ ".claude",
82
+ ".code-review-graph",
83
+ ".vscode-test"
77
84
  ]);
78
85
  const SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([
79
86
  ".ts",
@@ -173,4 +180,4 @@ export {
173
180
  collectFiles,
174
181
  indexDirectory
175
182
  };
176
- //# sourceMappingURL=chunk-TVQ7CBWU.js.map
183
+ //# sourceMappingURL=chunk-NYBVAPM3.js.map
@@ -3,7 +3,7 @@ import {
3
3
  collectFiles,
4
4
  generateEmbedding,
5
5
  indexDirectory
6
- } from "./chunk-TVQ7CBWU.js";
6
+ } from "./chunk-NYBVAPM3.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-VHOY4L6L.js.map
14
+ //# sourceMappingURL=embedder-ZGEKFHHK.js.map
package/dist/index.js CHANGED
@@ -34,14 +34,14 @@ import {
34
34
  startTrial,
35
35
  track,
36
36
  writeCODEOWNERS
37
- } from "./chunk-O4TQWLH6.js";
37
+ } from "./chunk-GI354NTO.js";
38
38
  import {
39
39
  VectorStore
40
40
  } from "./chunk-NEHYSE2Y.js";
41
41
  import {
42
42
  generateEmbedding,
43
43
  indexDirectory
44
- } from "./chunk-TVQ7CBWU.js";
44
+ } from "./chunk-NYBVAPM3.js";
45
45
  import {
46
46
  logger
47
47
  } from "./chunk-TYDMSHV7.js";
@@ -423,13 +423,114 @@ function printNextSteps() {
423
423
  console.log(` ${C.bold}Next steps:${C.reset}`);
424
424
  console.log("");
425
425
  console.log(` 1. ${C.cyan}cd /path/to/your/project${C.reset}`);
426
- console.log(` 2. ${C.cyan}ctxloom index${C.reset} ${C.dim}# Index your codebase${C.reset}`);
427
- console.log(` 3. ${C.dim}Open your AI tool and start coding \u2014 ctxloom provides context automatically${C.reset}`);
426
+ console.log(` 2. ${C.cyan}ctxloom init${C.reset} ${C.dim}# Pin ctxloom to this project (.mcp.json + .gitignore)${C.reset}`);
427
+ console.log(` 3. ${C.cyan}ctxloom index${C.reset} ${C.dim}# Build the dependency graph${C.reset}`);
428
+ console.log(` 4. ${C.dim}Open your AI tool in this directory \u2014 ctxloom provides context automatically${C.reset}`);
428
429
  console.log("");
429
430
  console.log(` ${C.dim}Documentation: https://ctxloom.dev/docs${C.reset}`);
430
431
  console.log("");
431
432
  }
432
433
 
434
+ // src/setup/init.ts
435
+ import fs2 from "fs";
436
+ import path2 from "path";
437
+ function runInit(cwd = process.cwd()) {
438
+ const root = path2.resolve(cwd);
439
+ const stat = fs2.statSync(root);
440
+ if (!stat.isDirectory()) {
441
+ throw new Error(`ctxloom init: ${root} is not a directory`);
442
+ }
443
+ const warnings = [];
444
+ if (!fs2.existsSync(path2.join(root, ".git"))) {
445
+ warnings.push(
446
+ "No .git directory found here. ctxloom init still works, but most graph features (git coupling, risk overlay, churn) require git history."
447
+ );
448
+ }
449
+ const mcpJson = writeMcpJson(root);
450
+ const gitignore = appendGitignore(root);
451
+ return { cwd: root, mcpJson, gitignore, warnings };
452
+ }
453
+ function buildCtxloomEntry(projectRoot) {
454
+ return {
455
+ command: "ctxloom",
456
+ args: [],
457
+ env: { CTXLOOM_ROOT: projectRoot }
458
+ };
459
+ }
460
+ function writeMcpJson(projectRoot) {
461
+ const mcpPath = path2.join(projectRoot, ".mcp.json");
462
+ const entry = buildCtxloomEntry(projectRoot);
463
+ if (!fs2.existsSync(mcpPath)) {
464
+ const payload = { mcpServers: { ctxloom: entry } };
465
+ fs2.writeFileSync(mcpPath, JSON.stringify(payload, null, 2) + "\n", "utf-8");
466
+ return { path: mcpPath, created: true, merged: false, alreadyCorrect: false };
467
+ }
468
+ const raw = fs2.readFileSync(mcpPath, "utf-8");
469
+ let parsed2;
470
+ try {
471
+ parsed2 = JSON.parse(raw);
472
+ } catch {
473
+ throw new Error(
474
+ `ctxloom init: ${mcpPath} is not valid JSON. Fix the file and re-run, or remove it and re-run init to regenerate.`
475
+ );
476
+ }
477
+ if (!parsed2.mcpServers || typeof parsed2.mcpServers !== "object") {
478
+ parsed2.mcpServers = {};
479
+ }
480
+ const servers = parsed2.mcpServers;
481
+ const existing = servers["ctxloom"];
482
+ const sameRoot = existing && typeof existing === "object" && existing.env && typeof existing.env === "object" && existing.env.CTXLOOM_ROOT === projectRoot;
483
+ if (sameRoot) {
484
+ return { path: mcpPath, created: false, merged: false, alreadyCorrect: true };
485
+ }
486
+ servers["ctxloom"] = entry;
487
+ fs2.writeFileSync(mcpPath, JSON.stringify(parsed2, null, 2) + "\n", "utf-8");
488
+ return { path: mcpPath, created: false, merged: true, alreadyCorrect: false };
489
+ }
490
+ var GITIGNORE_BANNER = "# ctxloom local index (machine-specific, do not commit)";
491
+ var GITIGNORE_PATTERN = ".ctxloom/";
492
+ function appendGitignore(projectRoot) {
493
+ const gitignorePath = path2.join(projectRoot, ".gitignore");
494
+ if (!fs2.existsSync(gitignorePath)) {
495
+ const content = `${GITIGNORE_BANNER}
496
+ ${GITIGNORE_PATTERN}
497
+ `;
498
+ fs2.writeFileSync(gitignorePath, content, "utf-8");
499
+ return {
500
+ path: gitignorePath,
501
+ created: true,
502
+ appended: true,
503
+ alreadyPresent: false
504
+ };
505
+ }
506
+ const raw = fs2.readFileSync(gitignorePath, "utf-8");
507
+ const alreadyPresent = raw.split("\n").some((line) => {
508
+ const trimmed = line.trim();
509
+ if (trimmed.startsWith("#") || trimmed.startsWith("!")) return false;
510
+ return trimmed === ".ctxloom" || trimmed === ".ctxloom/" || trimmed === "/.ctxloom" || trimmed === "/.ctxloom/";
511
+ });
512
+ if (alreadyPresent) {
513
+ return {
514
+ path: gitignorePath,
515
+ created: false,
516
+ appended: false,
517
+ alreadyPresent: true
518
+ };
519
+ }
520
+ const sep = raw.endsWith("\n") ? "" : "\n";
521
+ const addition = `${sep}
522
+ ${GITIGNORE_BANNER}
523
+ ${GITIGNORE_PATTERN}
524
+ `;
525
+ fs2.appendFileSync(gitignorePath, addition, "utf-8");
526
+ return {
527
+ path: gitignorePath,
528
+ created: false,
529
+ appended: true,
530
+ alreadyPresent: false
531
+ };
532
+ }
533
+
433
534
  // src/cli/format.ts
434
535
  import pc from "picocolors";
435
536
  var isTTY = process.stdout.isTTY === true;
@@ -501,7 +602,7 @@ ${body}
501
602
  import { execSync } from "child_process";
502
603
  import * as readline from "readline";
503
604
  import os from "os";
504
- import path2 from "path";
605
+ import path3 from "path";
505
606
  try {
506
607
  const proc = process;
507
608
  if (typeof proc.getrlimit === "function" && typeof proc.setrlimit === "function") {
@@ -512,7 +613,7 @@ try {
512
613
  } catch {
513
614
  }
514
615
  var args = process.argv.slice(2);
515
- var ctxloomVersion = "1.0.24".length > 0 ? "1.0.24" : "dev";
616
+ var ctxloomVersion = "1.0.26".length > 0 ? "1.0.26" : "dev";
516
617
  if (args.includes("--version") || args.includes("-v")) {
517
618
  process.stdout.write(`ctxloom ${ctxloomVersion}
518
619
  `);
@@ -585,7 +686,7 @@ async function checkLicense() {
585
686
  if (command !== void 0 && LICENSE_GATE_BYPASS_COMMANDS.has(command)) return;
586
687
  const ciKey = process.env["CTXLOOM_LICENSE_KEY"];
587
688
  if (ciKey) {
588
- const { ApiClient } = await import("./src-BYFMDHDZ.js");
689
+ const { ApiClient } = await import("./src-BRXQZ22F.js");
589
690
  const client = new ApiClient(process.env["CTXLOOM_API_BASE"]);
590
691
  try {
591
692
  const result = await client.validate(ciKey, "ci-ephemeral");
@@ -878,9 +979,43 @@ async function main() {
878
979
  await runSetupWizard();
879
980
  break;
880
981
  }
982
+ case "init": {
983
+ process.stdout.write(header("Init"));
984
+ const initRoot = process.cwd();
985
+ process.stdout.write(` ${style.dim("Root:")} ${initRoot}
986
+
987
+ `);
988
+ try {
989
+ const result = runInit(initRoot);
990
+ const mcpLabel = result.mcpJson.created ? `${style.bold("Created")} ${result.mcpJson.path}` : result.mcpJson.merged ? `${style.bold("Merged ctxloom entry into")} ${result.mcpJson.path}` : `${style.dim("Already up to date:")} ${result.mcpJson.path}`;
991
+ process.stdout.write(` ${success(mcpLabel)}
992
+ `);
993
+ const giLabel = result.gitignore.created ? `${style.bold("Created")} ${result.gitignore.path} (added .ctxloom/)` : result.gitignore.appended ? `${style.bold("Appended .ctxloom/ to")} ${result.gitignore.path}` : `${style.dim(".ctxloom/ already in")} ${result.gitignore.path}`;
994
+ process.stdout.write(` ${success(giLabel)}
995
+ `);
996
+ for (const w of result.warnings) {
997
+ process.stdout.write(` ${warn(w)}
998
+ `);
999
+ }
1000
+ process.stdout.write("\n");
1001
+ process.stdout.write(nextStep("Build the index", "ctxloom index"));
1002
+ process.stdout.write(
1003
+ ` ${style.dim("Then reopen your AI tool in this directory to pick up the new .mcp.json.")}
1004
+
1005
+ `
1006
+ );
1007
+ } catch (err) {
1008
+ process.stdout.write(`
1009
+ ${error(String(err instanceof Error ? err.message : err))}
1010
+
1011
+ `);
1012
+ process.exit(1);
1013
+ }
1014
+ break;
1015
+ }
881
1016
  case "register": {
882
1017
  const repoPath = process.argv[3] ?? ".";
883
- const absPath = path2.resolve(repoPath);
1018
+ const absPath = path3.resolve(repoPath);
884
1019
  try {
885
1020
  const stat = await import("fs").then((m) => m.statSync(absPath));
886
1021
  if (!stat.isDirectory()) {
@@ -891,8 +1026,8 @@ async function main() {
891
1026
  console.error(`[ctxloom] Path does not exist: ${absPath}`);
892
1027
  process.exit(1);
893
1028
  }
894
- const dbPath = path2.join(absPath, ".ctxloom", "vectors.lancedb");
895
- const registryPath = path2.join(os.homedir(), ".ctxloom", "repos.json");
1029
+ const dbPath = path3.join(absPath, ".ctxloom", "vectors.lancedb");
1030
+ const registryPath = path3.join(os.homedir(), ".ctxloom", "repos.json");
896
1031
  const reg = new RepoRegistry(registryPath);
897
1032
  reg.register(absPath, dbPath);
898
1033
  console.log(`[ctxloom] Registered repo: ${absPath}`);
@@ -901,7 +1036,7 @@ async function main() {
901
1036
  break;
902
1037
  }
903
1038
  case "repos": {
904
- const registryPath = path2.join(os.homedir(), ".ctxloom", "repos.json");
1039
+ const registryPath = path3.join(os.homedir(), ".ctxloom", "repos.json");
905
1040
  const reg = new RepoRegistry(registryPath);
906
1041
  const repos = reg.list();
907
1042
  if (repos.length === 0) {
@@ -953,7 +1088,7 @@ async function main() {
953
1088
  }
954
1089
  case "review-suggest": {
955
1090
  const root = process.cwd();
956
- const ctxloomDir = path2.join(root, ".ctxloom");
1091
+ const ctxloomDir = path3.join(root, ".ctxloom");
957
1092
  const max = parseInt(getFlagValue("--max=") ?? "3", 10);
958
1093
  if (isNaN(max) || max <= 0) {
959
1094
  console.error("[ctxloom] --max must be a positive integer.");
@@ -987,7 +1122,7 @@ async function main() {
987
1122
  const allFiles = store.ownership.allNodes();
988
1123
  const ruleMap = /* @__PURE__ */ new Map();
989
1124
  for (const file of allFiles) {
990
- const dir = path2.dirname(file);
1125
+ const dir = path3.dirname(file);
991
1126
  const stats = store.ownership.statsFor(file);
992
1127
  if (!stats) continue;
993
1128
  const topOwners = stats.owners.filter((o) => o.share >= minShare).slice(0, 2);
@@ -1001,7 +1136,7 @@ async function main() {
1001
1136
  }
1002
1137
  }
1003
1138
  const rules = Array.from(ruleMap.entries()).map(([pattern, handles]) => ({ pattern, handles: Array.from(handles) })).sort((a, b) => a.pattern.localeCompare(b.pattern));
1004
- const codeownersPath = path2.join(root, ".github", "CODEOWNERS");
1139
+ const codeownersPath = path3.join(root, ".github", "CODEOWNERS");
1005
1140
  const content = await generateCODEOWNERS(codeownersPath, rules);
1006
1141
  if (writeFlag) {
1007
1142
  await writeCODEOWNERS(codeownersPath, content);
@@ -1057,7 +1192,7 @@ Suggested reviewers for ${files.length} file(s):`);
1057
1192
  }
1058
1193
  case "authors-sync": {
1059
1194
  const root = process.cwd();
1060
- const ctxloomDir = path2.join(root, ".ctxloom");
1195
+ const ctxloomDir = path3.join(root, ".ctxloom");
1061
1196
  const token = process.env.GITHUB_TOKEN;
1062
1197
  if (!token) {
1063
1198
  console.error("[ctxloom] GITHUB_TOKEN env var required for authors-sync.");
@@ -1112,7 +1247,7 @@ Suggested reviewers for ${files.length} file(s):`);
1112
1247
  process.stderr.write("[ctxloom] --limit must be a non-negative integer (0 for unlimited)\n");
1113
1248
  process.exit(2);
1114
1249
  }
1115
- const { loadRulesConfig, RulesChecker, formatText, formatJson, RulesConfigError } = await import("./src-BYFMDHDZ.js");
1250
+ const { loadRulesConfig, RulesChecker, formatText, formatJson, RulesConfigError } = await import("./src-BRXQZ22F.js");
1116
1251
  let config;
1117
1252
  try {
1118
1253
  config = await loadRulesConfig(root);
@@ -1136,7 +1271,7 @@ Suggested reviewers for ${files.length} file(s):`);
1136
1271
  }
1137
1272
  let graph;
1138
1273
  if (useSnapshot) {
1139
- const { DependencyGraph: DG } = await import("./src-BYFMDHDZ.js");
1274
+ const { DependencyGraph: DG } = await import("./src-BRXQZ22F.js");
1140
1275
  graph = new DG();
1141
1276
  const loaded = await graph.loadSnapshotOnly(root);
1142
1277
  if (!loaded) {
@@ -1145,7 +1280,7 @@ Suggested reviewers for ${files.length} file(s):`);
1145
1280
  }
1146
1281
  } else {
1147
1282
  process.stderr.write("[ctxloom] Building dependency graph...\n");
1148
- const { ASTParser: ASTParser2, DependencyGraph: DependencyGraph2 } = await import("./src-BYFMDHDZ.js");
1283
+ const { ASTParser: ASTParser2, DependencyGraph: DependencyGraph2 } = await import("./src-BRXQZ22F.js");
1149
1284
  let parser;
1150
1285
  try {
1151
1286
  parser = new ASTParser2();
@@ -1185,8 +1320,9 @@ Usage:
1185
1320
  ctxloom activate <KEY> Activate a purchased license key on this machine
1186
1321
  ctxloom deactivate Release this machine's license seat
1187
1322
  ctxloom status Show current license status
1323
+ ctxloom init Scaffold .mcp.json + .gitignore for this project
1188
1324
  ctxloom index Index the current directory and build dependency graph
1189
- ctxloom setup Detect and configure MCP-compatible AI tools
1325
+ ctxloom setup Detect and configure MCP-compatible AI tools (global)
1190
1326
  ctxloom grammars Show grammar cache status
1191
1327
  ctxloom grammars --download Pre-download all language grammars
1192
1328
  ctxloom register [path] Register a repo for cross-repo search (defaults to cwd)
@@ -36,7 +36,10 @@ if (unconfigured.length > 0) {
36
36
  console.log(` ${C.dim}No MCP-compatible AI tools detected.${C.reset}`);
37
37
  }
38
38
  console.log("");
39
- console.log(` Quick start: ${C.cyan}ctxloom index${C.reset} ${C.dim}# Index your project${C.reset}`);
40
- console.log(` Setup: ${C.cyan}ctxloom setup${C.reset} ${C.dim}# Configure AI tools${C.reset}`);
39
+ console.log(` Quick start (run from your project directory):`);
40
+ console.log(` ${C.cyan}ctxloom init${C.reset} ${C.dim}# Pin ctxloom to this project${C.reset}`);
41
+ console.log(` ${C.cyan}ctxloom index${C.reset} ${C.dim}# Build the dependency graph${C.reset}`);
42
+ console.log("");
43
+ console.log(` Configure AI tools (one-time, global): ${C.cyan}ctxloom setup${C.reset}`);
41
44
  console.log("");
42
45
  //# sourceMappingURL=postinstall.js.map
@@ -80,7 +80,7 @@ import {
80
80
  startTrial,
81
81
  track,
82
82
  writeCODEOWNERS
83
- } from "./chunk-O4TQWLH6.js";
83
+ } from "./chunk-GI354NTO.js";
84
84
  import {
85
85
  VectorStore
86
86
  } from "./chunk-NEHYSE2Y.js";
@@ -89,7 +89,7 @@ import {
89
89
  collectFiles,
90
90
  generateEmbedding,
91
91
  indexDirectory
92
- } from "./chunk-TVQ7CBWU.js";
92
+ } from "./chunk-NYBVAPM3.js";
93
93
  import {
94
94
  logger
95
95
  } from "./chunk-TYDMSHV7.js";
@@ -182,4 +182,4 @@ export {
182
182
  track,
183
183
  writeCODEOWNERS
184
184
  };
185
- //# sourceMappingURL=src-BYFMDHDZ.js.map
185
+ //# sourceMappingURL=src-BRXQZ22F.js.map
@@ -3,7 +3,7 @@ import {
3
3
  } from "../chunk-NEHYSE2Y.js";
4
4
  import {
5
5
  generateEmbedding
6
- } from "../chunk-TVQ7CBWU.js";
6
+ } from "../chunk-NYBVAPM3.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.0.24",
3
+ "version": "1.0.26",
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",