@ulpi/codemap 0.3.8 → 0.3.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
@@ -363,6 +363,46 @@ Add to `~/.config/zed/settings.json`:
363
363
  }
364
364
  ```
365
365
 
366
+ ### Multi-Project Setup
367
+
368
+ You can register multiple CodeMap MCP servers — one per codebase — so your AI agent can search across your frontend, backend, shared libraries, or any other project simultaneously. Each server indexes and serves its own project independently.
369
+
370
+ First, index each project:
371
+
372
+ ```bash
373
+ codemap init && codemap index # current project
374
+ cd /path/to/frontend && codemap init && codemap index # another project
375
+ ```
376
+
377
+ Then register them as MCP servers. The current project uses `codemap serve` with no extra arguments. Other projects use `--cwd` to point to their location:
378
+
379
+ #### Claude Code
380
+
381
+ Add to `.mcp.json` in your project root:
382
+
383
+ ```json
384
+ {
385
+ "mcpServers": {
386
+ "codemap": {
387
+ "command": "codemap",
388
+ "args": ["serve"]
389
+ },
390
+ "codemap-frontend": {
391
+ "command": "codemap",
392
+ "args": ["serve", "--cwd", "/path/to/frontend"]
393
+ }
394
+ }
395
+ }
396
+ ```
397
+
398
+ `"codemap"` serves the current project automatically. `"codemap-frontend"` serves a different codebase via `--cwd`. Add as many as you need — each gets its own set of 12 tools (`search_code`, `get_dependencies`, etc.) scoped to that project.
399
+
400
+ #### Other Editors
401
+
402
+ The same pattern works in any editor — add one entry with no `--cwd` for the local project, and additional entries with `--cwd` for other codebases. Use unique names (e.g. `codemap-api`, `codemap-shared`) so your AI agent can tell them apart.
403
+
404
+ Your AI agent will then have access to tools like `search_code`, `get_dependencies`, and `search_symbols` across all registered projects, making it easy to trace connections across your stack.
405
+
366
406
  ## MCP Tools Reference
367
407
 
368
408
  | Tool | Description |
package/dist/index.js CHANGED
@@ -7029,13 +7029,14 @@ import path13 from "path";
7029
7029
  import { homedir as homedir3 } from "os";
7030
7030
 
7031
7031
  // src/commands/statusline-script.ts
7032
- function buildStatuslineScript(originalScript) {
7033
- const body = originalScript.replace(/^#!\/.*\n/, "").trim();
7032
+ function buildStatuslineScript(originalCommand) {
7033
+ const escapedCmd = originalCommand.replace(/'/g, "'\\''");
7034
+ const originalSection = originalCommand ? `ORIGINAL_CMD='${escapedCmd}'
7035
+ echo "$SESSION_JSON" | eval "$ORIGINAL_CMD" 2>/dev/null || true` : "# (none)";
7034
7036
  return `#!/bin/bash
7035
7037
  # CodeMap statusline for Claude Code
7036
7038
  # Generated by: codemap statusline
7037
7039
  # Do not edit \u2014 re-run \`codemap statusline\` to regenerate.
7038
- # Original script backed up to statusline-command.sh.bak
7039
7040
 
7040
7041
  set -euo pipefail
7041
7042
 
@@ -7043,9 +7044,7 @@ set -euo pipefail
7043
7044
  SESSION_JSON=$(cat)
7044
7045
 
7045
7046
  # --- Original statusline ---
7046
- ${body ? `(
7047
- ${body}
7048
- ) <<< "$SESSION_JSON"` : "# (none)"}
7047
+ ${originalSection}
7049
7048
 
7050
7049
  # --- CodeMap status ---
7051
7050
  # Resolve the working directory from session JSON
@@ -7061,7 +7060,7 @@ fi
7061
7060
  # Parse fields
7062
7061
  stats_null=$(echo "$cm_json" | ${jsonExtract("stats")} 2>/dev/null || echo "null")
7063
7062
  if [ "$stats_null" = "null" ] || [ -z "$stats_null" ]; then
7064
- echo "CM: \u2014 no index"
7063
+ echo "CM: \u2014 no index (run: codemap index)"
7065
7064
  exit 0
7066
7065
  fi
7067
7066
 
@@ -7183,31 +7182,13 @@ function install() {
7183
7182
  } catch {
7184
7183
  }
7185
7184
  }
7186
- let originalScript = "";
7187
- if (settings.statusline_command) {
7188
- const currentCommand = settings.statusline_command;
7189
- if (currentCommand.includes(SCRIPT_FILE) || currentCommand.endsWith("statusline-command.sh")) {
7190
- if (fs18.existsSync(SCRIPT_FILE)) {
7191
- originalScript = fs18.readFileSync(SCRIPT_FILE, "utf-8");
7192
- }
7193
- } else if (currentCommand.startsWith("/") || currentCommand.startsWith("~")) {
7194
- const resolved = currentCommand.replace(/^~/, homedir3());
7195
- try {
7196
- originalScript = fs18.readFileSync(resolved, "utf-8");
7197
- } catch {
7198
- originalScript = `#!/bin/bash
7199
- ${currentCommand}`;
7200
- }
7201
- } else {
7202
- originalScript = `#!/bin/bash
7203
- ${currentCommand}`;
7204
- }
7185
+ const originalCommand = settings.statusline_command || "";
7186
+ if (originalCommand && originalCommand !== SCRIPT_FILE) {
7187
+ fs18.mkdirSync(CLAUDE_DIR, { recursive: true });
7188
+ fs18.writeFileSync(BACKUP_FILE, originalCommand);
7189
+ console.log(chalk17.dim(`Saved original statusline command to ${BACKUP_FILE}`));
7205
7190
  }
7206
- if (fs18.existsSync(SCRIPT_FILE)) {
7207
- fs18.copyFileSync(SCRIPT_FILE, BACKUP_FILE);
7208
- console.log(chalk17.dim(`Backed up existing script to ${BACKUP_FILE}`));
7209
- }
7210
- const script = buildStatuslineScript(originalScript);
7191
+ const script = buildStatuslineScript(originalCommand !== SCRIPT_FILE ? originalCommand : "");
7211
7192
  fs18.mkdirSync(CLAUDE_DIR, { recursive: true });
7212
7193
  fs18.writeFileSync(SCRIPT_FILE, script, { mode: 493 });
7213
7194
  if (settings.statusline_command !== SCRIPT_FILE) {
@@ -7217,45 +7198,54 @@ ${currentCommand}`;
7217
7198
  }
7218
7199
  console.log();
7219
7200
  console.log(chalk17.green("CodeMap statusline installed."));
7201
+ if (originalCommand && originalCommand !== SCRIPT_FILE) {
7202
+ console.log(chalk17.dim("Your existing statusline is preserved \u2014 CodeMap appends to it."));
7203
+ }
7220
7204
  console.log();
7221
- console.log("The statusline will show:");
7205
+ console.log("CodeMap will append to the statusline:");
7222
7206
  console.log(chalk17.cyan(" CM: \u25CF 842f 12.4k\u25C6 | 23m ago") + chalk17.dim(" \u2014 watcher running, index fresh"));
7223
7207
  console.log(chalk17.cyan(" CM: \u25CB 842f 12.4k\u25C6 \u26A03 | 2h ago") + chalk17.dim(" \u2014 no watcher, 3 stale files"));
7224
7208
  console.log(chalk17.cyan(" CM: \u25CB 842f 12.4k\u25C6 IDX | 5s ago") + chalk17.dim(" \u2014 indexing in progress"));
7225
- console.log(chalk17.cyan(" CM: \u2014 no index") + chalk17.dim(" \u2014 no stats.json found"));
7209
+ console.log(chalk17.cyan(" CM: \u2014 no index (run: codemap index)") + chalk17.dim(" \u2014 not yet indexed"));
7226
7210
  console.log();
7227
7211
  console.log(chalk17.dim("Restart Claude Code to see the statusline."));
7228
7212
  console.log(chalk17.dim("Run `codemap statusline --uninstall` to remove."));
7213
+ console.log();
7214
+ console.log(chalk17.dim("Tip: Install codemap in multiple projects to give each Claude Code"));
7215
+ console.log(chalk17.dim("session its own code intelligence \u2014 frontend, backend, shared libs."));
7216
+ console.log(chalk17.dim("Run `codemap init` in any project to get started."));
7229
7217
  }
7230
7218
  function uninstall() {
7231
- let restored = false;
7219
+ let originalCommand = "";
7232
7220
  if (fs18.existsSync(BACKUP_FILE)) {
7233
- fs18.copyFileSync(BACKUP_FILE, SCRIPT_FILE);
7234
- fs18.unlinkSync(BACKUP_FILE);
7235
- console.log(chalk17.dim(`Restored original script from backup.`));
7236
- restored = true;
7237
- } else if (fs18.existsSync(SCRIPT_FILE)) {
7221
+ try {
7222
+ originalCommand = fs18.readFileSync(BACKUP_FILE, "utf-8").trim();
7223
+ } catch {
7224
+ }
7225
+ try {
7226
+ fs18.unlinkSync(BACKUP_FILE);
7227
+ } catch {
7228
+ }
7229
+ }
7230
+ if (fs18.existsSync(SCRIPT_FILE)) {
7238
7231
  try {
7239
7232
  const content = fs18.readFileSync(SCRIPT_FILE, "utf-8");
7240
7233
  if (content.includes("Generated by: codemap statusline")) {
7241
7234
  fs18.unlinkSync(SCRIPT_FILE);
7242
- console.log(chalk17.dim(`Removed statusline script.`));
7243
- const settings = readSettings();
7244
- if (settings.statusline_command === SCRIPT_FILE) {
7245
- delete settings.statusline_command;
7246
- writeSettings(settings);
7247
- console.log(chalk17.dim(`Cleared statusline_command from settings.`));
7248
- }
7235
+ console.log(chalk17.dim("Removed statusline script."));
7249
7236
  }
7250
7237
  } catch {
7251
7238
  }
7252
7239
  }
7253
- if (!restored) {
7254
- const settings = readSettings();
7255
- if (settings.statusline_command) {
7256
- delete settings.statusline_command;
7257
- writeSettings(settings);
7258
- }
7240
+ const settings = readSettings();
7241
+ if (originalCommand && originalCommand !== SCRIPT_FILE) {
7242
+ settings.statusline_command = originalCommand;
7243
+ writeSettings(settings);
7244
+ console.log(chalk17.dim(`Restored original statusline command.`));
7245
+ } else if (settings.statusline_command) {
7246
+ delete settings.statusline_command;
7247
+ writeSettings(settings);
7248
+ console.log(chalk17.dim("Cleared statusline_command from settings."));
7259
7249
  }
7260
7250
  console.log();
7261
7251
  console.log(chalk17.green("CodeMap statusline removed."));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ulpi/codemap",
3
- "version": "0.3.8",
3
+ "version": "0.3.9",
4
4
  "type": "module",
5
5
  "description": "Standalone code intelligence CLI — hybrid vector + BM25 search, dependency analysis, PageRank",
6
6
  "bin": {
@@ -10,9 +10,11 @@
10
10
  ".": "./dist/index.js"
11
11
  },
12
12
  "files": [
13
- "dist"
13
+ "dist",
14
+ "scripts/postinstall.js"
14
15
  ],
15
16
  "scripts": {
17
+ "postinstall": "node scripts/postinstall.js",
16
18
  "build": "tsup && node --import tsx scripts/copy-grammars.ts",
17
19
  "typecheck": "tsc --noEmit",
18
20
  "test": "vitest run",
@@ -0,0 +1,36 @@
1
+ // Postinstall welcome message for `npm install -g @ulpi/codemap`
2
+ const cyan = (s) => `\x1b[36m${s}\x1b[0m`;
3
+ const dim = (s) => `\x1b[2m${s}\x1b[0m`;
4
+ const bold = (s) => `\x1b[1m${s}\x1b[0m`;
5
+
6
+ console.log();
7
+ console.log(bold("codemap") + " installed successfully.");
8
+ console.log();
9
+ console.log("Get started:");
10
+ console.log(` ${cyan("codemap init")} ${dim("# Choose embedding provider + model")}`);
11
+ console.log(` ${cyan("codemap index")} ${dim("# Index your project")}`);
12
+ console.log(` ${cyan("codemap search")} ${dim('"query"')} ${dim("# Search your code")}`);
13
+ console.log();
14
+ console.log("Add as an MCP server to give your AI agent code intelligence:");
15
+ console.log(` ${cyan("codemap serve")} ${dim("# Start MCP server (stdio)")}`);
16
+ console.log();
17
+ console.log("Multi-project: Index each codebase, then register one MCP server per project.");
18
+ console.log("Your AI agent gets code intelligence across your entire stack.");
19
+ console.log();
20
+ console.log(` ${dim("# Index each project once:")}`);
21
+ console.log(` ${dim("$")} ${cyan("codemap init")} && ${cyan("codemap index")} ${dim("# current project")}`);
22
+ console.log(` ${dim("$")} cd ~/projects/frontend && ${cyan("codemap init")} && ${cyan("codemap index")}`);
23
+ console.log();
24
+ console.log(` ${dim("# .mcp.json — add to the project where you use your AI agent:")}`);
25
+ console.log(` ${dim("{")}`)
26
+ console.log(` ${dim(' "mcpServers": {')}`);
27
+ console.log(` ${dim(' "codemap": {')}`);
28
+ console.log(` ${dim(' "command": "codemap", "args": ["serve"]')} ${dim("← this project")}`);
29
+ console.log(` ${dim(' },')}`);
30
+ console.log(` ${dim(' "codemap-frontend": {')}`);
31
+ console.log(` ${dim(' "command": "codemap", "args": ["serve", "--cwd",')}`);
32
+ console.log(` ${dim(' "/path/to/frontend"]')} ${dim("← another project")}`);
33
+ console.log(` ${dim(' }')}`);
34
+ console.log(` ${dim(" }")}`);
35
+ console.log(` ${dim("}")}`);
36
+ console.log();