sigmap 7.28.0 → 7.29.0

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/CHANGELOG.md CHANGED
@@ -10,6 +10,20 @@ Format: [Semantic Versioning](https://semver.org/)
10
10
 
11
11
  ---
12
12
 
13
+ ## [7.29.0] — 2026-06-23
14
+
15
+ Minor release — **v8.0 E4:** one-command, per-client MCP install so a cold user reaches a working MCP setup fast (the v8.0 <5-minute-quickstart exit gate).
16
+
17
+ ### Added
18
+ - **`sigmap mcp install <client>` (#385):** targeted MCP wiring for a single client — `claude`, `cursor`, `windsurf`, `vscode`, `zed`, `codex`, `gemini`, `opencode`, or portable `mcp` (`.mcp.json`). Unlike `sigmap --setup` (which wires *every* editor at once and only updates configs that already exist), this **creates** the config dir/file when absent, is idempotent (re-running reports already-registered, never duplicates), and emits the correct shape per client — `mcpServers` JSON, Zed `context_servers`, or Codex YAML. `--global` selects the user-level config for clients that have both a project and a global scope (Windsurf, OpenCode). Composed in the zero-dep `src/mcp/install.js` — no system-shell spawns, no install scripts.
19
+ - **`sigmap mcp list` (#385):** lists every supported MCP client and its resolved config path (`--json` for a machine-readable array).
20
+
21
+ ### Changed
22
+ - Regenerated `llms-full.txt` so the published surface lists the new `mcp install`/`mcp list` commands.
23
+
24
+ ### Fixed
25
+ - Hardened two `--ci --min-coverage` integration tests (#385) that were order- and environment-dependent — they hard-coded an "unreachable" 99% threshold, but once the suite generates a full `src/` context the repo's measured coverage reaches 99–100%. They now pin the threshold relative to the actual measured coverage, so the gate-fails-above-achievable property holds deterministically everywhere.
26
+
13
27
  ## [7.28.0] — 2026-06-23
14
28
 
15
29
  Minor release — **v8.0 E3:** a one-shot setup doctor so a cold user reaches a useful answer fast.
package/README.md CHANGED
@@ -91,8 +91,8 @@ Ask → Rank → Context → Validate → Judge → Learn
91
91
 
92
92
  <!--SM:benchmarkBlock-->
93
93
  ```
94
- Benchmark : sigmap-v7.28-main (21 repositories, including R language)
95
- Date : 2026-06-22
94
+ Benchmark : sigmap-v7.29-main (21 repositories, including R language)
95
+ Date : 2026-06-23
96
96
 
97
97
  Hit@5 : 75.6% (baseline 13.6% — 5.6× lift)
98
98
  Token reduction: 97.0% (across 21 repos)
package/gen-context.js CHANGED
@@ -12528,6 +12528,152 @@ __factories["./src/mcp/handlers"] = function(module, exports) {
12528
12528
 
12529
12529
  };
12530
12530
 
12531
+ // ── ./src/mcp/install ──
12532
+ __factories["./src/mcp/install"] = function(module, exports) {
12533
+
12534
+ /**
12535
+ * Per-client MCP install (v8.0 E4).
12536
+ *
12537
+ * `sigmap --setup` wires *every* known editor at once and only touches config
12538
+ * files that already exist (to avoid creating clutter for editors the user does
12539
+ * not use). This module is the targeted counterpart: `sigmap mcp install <client>`
12540
+ * picks one client, and — because the user explicitly asked for it — CREATES the
12541
+ * config dir/file if it is missing. Idempotent: re-running never duplicates the
12542
+ * entry. Zero dependencies; only `fs`/`path`/`os`.
12543
+ */
12544
+
12545
+ const fs = require('fs');
12546
+ const path = require('path');
12547
+ const os = require('os');
12548
+
12549
+ // Config shapes the supported clients use.
12550
+ // - 'json' → { mcpServers: { sigmap: { command, args } } }
12551
+ // - 'zed' → { context_servers: { sigmap: { command: { path, args } } } }
12552
+ // - 'yaml' → Codex CLI ~/.codex/config.yaml (mcpServers block, appended)
12553
+ const CLIENTS = {
12554
+ claude: { label: 'Claude Code', format: 'json', scope: 'project', project: ['.claude', 'settings.json'] },
12555
+ cursor: { label: 'Cursor', format: 'json', scope: 'project', project: ['.cursor', 'mcp.json'] },
12556
+ windsurf: { label: 'Windsurf', format: 'json', scope: 'both',
12557
+ project: ['.windsurf', 'mcp.json'],
12558
+ global: ['.codeium', 'windsurf', 'mcp_config.json'] },
12559
+ vscode: { label: 'VS Code', format: 'json', scope: 'project', project: ['.vscode', 'mcp.json'] },
12560
+ opencode: { label: 'OpenCode', format: 'json', scope: 'both',
12561
+ project: ['opencode.json'],
12562
+ global: ['.config', 'opencode', 'config.json'] },
12563
+ gemini: { label: 'Gemini CLI', format: 'json', scope: 'global', global: ['.gemini', 'settings.json'] },
12564
+ zed: { label: 'Zed', format: 'zed', scope: 'global', global: ['.config', 'zed', 'settings.json'] },
12565
+ codex: { label: 'Codex CLI', format: 'yaml', scope: 'global', global: ['.codex', 'config.yaml'] },
12566
+ mcp: { label: 'Portable (.mcp.json)', format: 'json', scope: 'project', project: ['.mcp.json'] },
12567
+ };
12568
+
12569
+ /** Resolve the absolute config path for a client, honoring `global`. */
12570
+ function resolveTarget(spec, cwd, home, useGlobal) {
12571
+ const wantGlobal = useGlobal || spec.scope === 'global';
12572
+ if (wantGlobal && spec.global) return path.join(home, ...spec.global);
12573
+ if (spec.project) return path.join(cwd, ...spec.project);
12574
+ if (spec.global) return path.join(home, ...spec.global);
12575
+ return null;
12576
+ }
12577
+
12578
+ /** List supported clients with their resolved target paths. */
12579
+ function listClients(opts = {}) {
12580
+ const cwd = opts.cwd || process.cwd();
12581
+ const home = opts.home || os.homedir();
12582
+ return Object.keys(CLIENTS).map((key) => {
12583
+ const spec = CLIENTS[key];
12584
+ return {
12585
+ client: key,
12586
+ label: spec.label,
12587
+ scope: spec.scope,
12588
+ format: spec.format,
12589
+ target: resolveTarget(spec, cwd, home, false),
12590
+ globalTarget: spec.scope === 'both' ? resolveTarget(spec, cwd, home, true) : null,
12591
+ };
12592
+ });
12593
+ }
12594
+
12595
+ function serverArgs(scriptPath) {
12596
+ return [path.resolve(scriptPath), '--mcp'];
12597
+ }
12598
+
12599
+ /** Install into a JSON `mcpServers` config (create file/dir if absent). */
12600
+ function _installJson(filePath, scriptPath) {
12601
+ let settings = {};
12602
+ if (fs.existsSync(filePath)) {
12603
+ try { settings = JSON.parse(fs.readFileSync(filePath, 'utf8')) || {}; }
12604
+ catch (_) { settings = {}; }
12605
+ }
12606
+ if (!settings.mcpServers) settings.mcpServers = {};
12607
+ if (settings.mcpServers.sigmap) return 'already';
12608
+ settings.mcpServers.sigmap = { command: 'node', args: serverArgs(scriptPath) };
12609
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
12610
+ fs.writeFileSync(filePath, JSON.stringify(settings, null, 2) + '\n');
12611
+ return 'installed';
12612
+ }
12613
+
12614
+ /** Install into Zed's `context_servers` config (create file/dir if absent). */
12615
+ function _installZed(filePath, scriptPath) {
12616
+ let settings = {};
12617
+ if (fs.existsSync(filePath)) {
12618
+ try { settings = JSON.parse(fs.readFileSync(filePath, 'utf8')) || {}; }
12619
+ catch (_) { settings = {}; }
12620
+ }
12621
+ if (!settings.context_servers) settings.context_servers = {};
12622
+ if (settings.context_servers.sigmap) return 'already';
12623
+ settings.context_servers.sigmap = { command: { path: 'node', args: serverArgs(scriptPath) } };
12624
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
12625
+ fs.writeFileSync(filePath, JSON.stringify(settings, null, 2) + '\n');
12626
+ return 'installed';
12627
+ }
12628
+
12629
+ /** Install into Codex CLI YAML (append block; create file if absent). */
12630
+ function _installYaml(filePath, scriptPath) {
12631
+ let raw = '';
12632
+ if (fs.existsSync(filePath)) {
12633
+ raw = fs.readFileSync(filePath, 'utf8');
12634
+ if (raw.includes('sigmap')) return 'already';
12635
+ }
12636
+ const block = [
12637
+ 'mcpServers:',
12638
+ ' sigmap:',
12639
+ ' command: node',
12640
+ ' args:',
12641
+ ` - ${path.resolve(scriptPath)}`,
12642
+ ' - --mcp',
12643
+ ].join('\n');
12644
+ const next = raw ? raw.trimEnd() + '\n\n' + block + '\n' : block + '\n';
12645
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
12646
+ fs.writeFileSync(filePath, next);
12647
+ return 'installed';
12648
+ }
12649
+
12650
+ /**
12651
+ * Install the sigmap MCP server for a single client.
12652
+ * @returns { client, label, path, status } where status is
12653
+ * 'installed' | 'already' | 'unknown'.
12654
+ */
12655
+ function installClient(client, opts = {}) {
12656
+ const spec = CLIENTS[client];
12657
+ if (!spec) {
12658
+ return { client, status: 'unknown', valid: Object.keys(CLIENTS) };
12659
+ }
12660
+ const cwd = opts.cwd || process.cwd();
12661
+ const home = opts.home || os.homedir();
12662
+ const scriptPath = opts.scriptPath || path.join(cwd, 'gen-context.js');
12663
+ const filePath = resolveTarget(spec, cwd, home, opts.global);
12664
+
12665
+ let status;
12666
+ if (spec.format === 'zed') status = _installZed(filePath, scriptPath);
12667
+ else if (spec.format === 'yaml') status = _installYaml(filePath, scriptPath);
12668
+ else status = _installJson(filePath, scriptPath);
12669
+
12670
+ return { client, label: spec.label, path: filePath, status };
12671
+ }
12672
+
12673
+ module.exports = { CLIENTS, listClients, installClient, resolveTarget };
12674
+
12675
+ };
12676
+
12531
12677
  // ── ./src/mcp/server ──
12532
12678
  __factories["./src/mcp/server"] = function(module, exports) {
12533
12679
 
@@ -12549,7 +12695,7 @@ __factories["./src/mcp/server"] = function(module, exports) {
12549
12695
 
12550
12696
  const SERVER_INFO = {
12551
12697
  name: 'sigmap',
12552
- version: '7.28.0',
12698
+ version: '7.29.0',
12553
12699
  description: 'SigMap MCP server — code signatures on demand',
12554
12700
  };
12555
12701
 
@@ -16378,7 +16524,7 @@ function __tryGit(args, opts = {}) {
16378
16524
  catch (_) { return ''; }
16379
16525
  }
16380
16526
 
16381
- const VERSION = '7.28.0';
16527
+ const VERSION = '7.29.0';
16382
16528
  const MARKER = '\n\n## Auto-generated signatures\n<!-- Updated by gen-context.js -->\n';
16383
16529
 
16384
16530
  function requireSourceOrBundled(key) {
@@ -18192,6 +18338,8 @@ Usage:
18192
18338
  ${cmd} note List recent notes (also: note --list <N>)
18193
18339
  ${cmd} status Show repo state — branch, dirty files, index freshness, notes
18194
18340
  ${cmd} doctor Diagnose config, index, freshness, coverage, MCP wiring — with fixes (--json; exits 1 on hard failure)
18341
+ ${cmd} mcp list List MCP clients and their config paths (--json)
18342
+ ${cmd} mcp install <client> Wire MCP for one client (claude|cursor|windsurf|vscode|zed|codex|gemini|opencode|mcp); --global for user-level
18195
18343
  ${cmd} --init Write example config + .contextignore scaffold
18196
18344
  ${cmd} --help Show this message
18197
18345
  ${cmd} --version Show version
@@ -19616,6 +19764,56 @@ function main() {
19616
19764
  process.exit(0);
19617
19765
  }
19618
19766
 
19767
+ // `sigmap mcp install <client>` / `sigmap mcp list` — one-command per-client
19768
+ // MCP wiring (v8.0 E4). Unlike `--setup` (wires every editor, only touches
19769
+ // existing configs), this targets one client and creates the config if absent.
19770
+ if (args[0] === 'mcp') {
19771
+ const { listClients, installClient } = requireSourceOrBundled('./src/mcp/install');
19772
+ const sub = args[1];
19773
+
19774
+ if (sub === 'list') {
19775
+ const clients = listClients({ cwd });
19776
+ if (args.includes('--json')) {
19777
+ process.stdout.write(JSON.stringify(clients, null, 2) + '\n');
19778
+ process.exit(0);
19779
+ }
19780
+ console.log('Supported MCP clients:\n');
19781
+ for (const c of clients) {
19782
+ const scope = c.scope === 'both' ? 'project (or --global)' : c.scope;
19783
+ console.log(` ${c.client.padEnd(10)} ${c.label}`);
19784
+ console.log(` ${_displayPath(c.target, cwd)} [${scope}]`);
19785
+ }
19786
+ console.log('\nInstall with: sigmap mcp install <client>');
19787
+ process.exit(0);
19788
+ }
19789
+
19790
+ if (sub === 'install') {
19791
+ const client = args[2];
19792
+ if (!client || client.startsWith('--')) {
19793
+ console.error('[sigmap] usage: sigmap mcp install <client> (see: sigmap mcp list)');
19794
+ process.exit(1);
19795
+ }
19796
+ const result = installClient(client, {
19797
+ cwd,
19798
+ scriptPath,
19799
+ global: args.includes('--global'),
19800
+ });
19801
+ if (result.status === 'unknown') {
19802
+ console.error(`[sigmap] unknown client "${client}". Valid: ${result.valid.join(', ')}`);
19803
+ process.exit(1);
19804
+ }
19805
+ if (result.status === 'already') {
19806
+ console.log(`[sigmap] ${result.label}: sigmap already registered in ${_displayPath(result.path, cwd)}`);
19807
+ } else {
19808
+ console.log(`[sigmap] ${result.label}: registered MCP server in ${_displayPath(result.path, cwd)}`);
19809
+ }
19810
+ process.exit(0);
19811
+ }
19812
+
19813
+ console.error('[sigmap] usage: sigmap mcp install <client> | sigmap mcp list');
19814
+ process.exit(1);
19815
+ }
19816
+
19619
19817
  // `sigmap doctor` — diagnose config, index, freshness, coverage, and MCP
19620
19818
  // wiring; print an actionable fix for anything wrong. Exit 1 on a hard
19621
19819
  // failure (no context file / invalid config) so it is usable in CI.
package/llms-full.txt CHANGED
@@ -9,13 +9,13 @@ the files relevant to the task — cutting tokens ~97% while keeping answers
9
9
  grounded. Deterministic, offline, no embeddings or vector database. Works with
10
10
  Claude, Cursor, GitHub Copilot, Aider, Windsurf, local LLMs, and MCP.
11
11
 
12
- # Version: 7.28.0 | Benchmark: sigmap-v7.28-main (2026-06-22)
12
+ # Version: 7.29.0 | Benchmark: sigmap-v7.29-main (2026-06-23)
13
13
  # Source: auto-generated from package.json, version.json, benchmarks/latest.json, src/mcp/tools.js, src/config/defaults.js
14
14
  # Regenerate: npm run generate:llms | Validate: npm run validate:llms
15
15
 
16
16
  ---
17
17
 
18
- ## Core metrics (benchmark: sigmap-v7.28-main, 2026-06-22)
18
+ ## Core metrics (benchmark: sigmap-v7.29-main, 2026-06-23)
19
19
 
20
20
  | Metric | Without SigMap | With SigMap |
21
21
  |--------|----------------|-------------|
@@ -116,6 +116,8 @@ sigmap note "<text>" Append a note to the cross-session deci
116
116
  sigmap note List recent notes (also: note --list <N>)
117
117
  sigmap status Show repo state — branch, dirty files, index freshness, notes
118
118
  sigmap doctor Diagnose config, index, freshness, coverage, MCP wiring — with fixes (--json; exits 1 on hard failure)
119
+ sigmap mcp list List MCP clients and their config paths (--json)
120
+ sigmap mcp install <client> Wire MCP for one client (claude|cursor|windsurf|vscode|zed|codex|gemini|opencode|mcp); --global for user-level
119
121
  sigmap --init Write example config + .contextignore scaffold
120
122
  sigmap --help Show this message
121
123
  sigmap --version Show version
package/llms.txt CHANGED
@@ -9,7 +9,7 @@ the files relevant to the task — cutting tokens ~97% while keeping answers
9
9
  grounded. Deterministic, offline, no embeddings or vector database. Works with
10
10
  Claude, Cursor, GitHub Copilot, Aider, Windsurf, local LLMs, and MCP.
11
11
 
12
- # Version: 7.28.0 | Benchmark: sigmap-v7.28-main (2026-06-22)
12
+ # Version: 7.29.0 | Benchmark: sigmap-v7.29-main (2026-06-23)
13
13
  # Source: auto-generated from package.json, version.json, benchmarks/latest.json, src/mcp/tools.js, src/config/defaults.js
14
14
  # Regenerate: npm run generate:llms | Validate: npm run validate:llms
15
15
 
@@ -21,7 +21,7 @@ Claude, Cursor, GitHub Copilot, Aider, Windsurf, local LLMs, and MCP.
21
21
  - No blast-radius awareness before editing a hub file — `--impact` shows every file a change touches.
22
22
  - Pasted stack traces, CI logs, and JSON bloat the prompt — `squeeze` minimizes them and enriches the top frame from the symbol index.
23
23
 
24
- ## Core metrics (benchmark: sigmap-v7.28-main, 2026-06-22)
24
+ ## Core metrics (benchmark: sigmap-v7.29-main, 2026-06-23)
25
25
 
26
26
  - hit@5 retrieval: 75.6% vs 13.6% random baseline (5.6× lift)
27
27
  - Token reduction: 97.0% average across benchmark repos
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sigmap",
3
- "version": "7.28.0",
3
+ "version": "7.29.0",
4
4
  "description": "97% token reduction for AI coding. Extracts function & class signatures with TF-IDF ranking to feed only the right files to Claude, Cursor, Copilot, Aider, Windsurf, local LLMs & MCP. Zero dependencies, runs offline via npx.",
5
5
  "main": "packages/core/index.js",
6
6
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sigmap-cli",
3
- "version": "7.28.0",
3
+ "version": "7.29.0",
4
4
  "description": "SigMap CLI wrapper — thin adapter for programmatic CLI invocation",
5
5
  "main": "index.js",
6
6
  "keywords": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sigmap-core",
3
- "version": "7.28.0",
3
+ "version": "7.29.0",
4
4
  "description": "SigMap core library — zero-dependency code signature extraction, retrieval, and security scanning",
5
5
  "main": "index.js",
6
6
  "keywords": [
@@ -0,0 +1,142 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Per-client MCP install (v8.0 E4).
5
+ *
6
+ * `sigmap --setup` wires *every* known editor at once and only touches config
7
+ * files that already exist (to avoid creating clutter for editors the user does
8
+ * not use). This module is the targeted counterpart: `sigmap mcp install <client>`
9
+ * picks one client, and — because the user explicitly asked for it — CREATES the
10
+ * config dir/file if it is missing. Idempotent: re-running never duplicates the
11
+ * entry. Zero dependencies; only `fs`/`path`/`os`.
12
+ */
13
+
14
+ const fs = require('fs');
15
+ const path = require('path');
16
+ const os = require('os');
17
+
18
+ // Config shapes the supported clients use.
19
+ // - 'json' → { mcpServers: { sigmap: { command, args } } }
20
+ // - 'zed' → { context_servers: { sigmap: { command: { path, args } } } }
21
+ // - 'yaml' → Codex CLI ~/.codex/config.yaml (mcpServers block, appended)
22
+ const CLIENTS = {
23
+ claude: { label: 'Claude Code', format: 'json', scope: 'project', project: ['.claude', 'settings.json'] },
24
+ cursor: { label: 'Cursor', format: 'json', scope: 'project', project: ['.cursor', 'mcp.json'] },
25
+ windsurf: { label: 'Windsurf', format: 'json', scope: 'both',
26
+ project: ['.windsurf', 'mcp.json'],
27
+ global: ['.codeium', 'windsurf', 'mcp_config.json'] },
28
+ vscode: { label: 'VS Code', format: 'json', scope: 'project', project: ['.vscode', 'mcp.json'] },
29
+ opencode: { label: 'OpenCode', format: 'json', scope: 'both',
30
+ project: ['opencode.json'],
31
+ global: ['.config', 'opencode', 'config.json'] },
32
+ gemini: { label: 'Gemini CLI', format: 'json', scope: 'global', global: ['.gemini', 'settings.json'] },
33
+ zed: { label: 'Zed', format: 'zed', scope: 'global', global: ['.config', 'zed', 'settings.json'] },
34
+ codex: { label: 'Codex CLI', format: 'yaml', scope: 'global', global: ['.codex', 'config.yaml'] },
35
+ mcp: { label: 'Portable (.mcp.json)', format: 'json', scope: 'project', project: ['.mcp.json'] },
36
+ };
37
+
38
+ /** Resolve the absolute config path for a client, honoring `global`. */
39
+ function resolveTarget(spec, cwd, home, useGlobal) {
40
+ const wantGlobal = useGlobal || spec.scope === 'global';
41
+ if (wantGlobal && spec.global) return path.join(home, ...spec.global);
42
+ if (spec.project) return path.join(cwd, ...spec.project);
43
+ if (spec.global) return path.join(home, ...spec.global);
44
+ return null;
45
+ }
46
+
47
+ /** List supported clients with their resolved target paths. */
48
+ function listClients(opts = {}) {
49
+ const cwd = opts.cwd || process.cwd();
50
+ const home = opts.home || os.homedir();
51
+ return Object.keys(CLIENTS).map((key) => {
52
+ const spec = CLIENTS[key];
53
+ return {
54
+ client: key,
55
+ label: spec.label,
56
+ scope: spec.scope,
57
+ format: spec.format,
58
+ target: resolveTarget(spec, cwd, home, false),
59
+ globalTarget: spec.scope === 'both' ? resolveTarget(spec, cwd, home, true) : null,
60
+ };
61
+ });
62
+ }
63
+
64
+ function serverArgs(scriptPath) {
65
+ return [path.resolve(scriptPath), '--mcp'];
66
+ }
67
+
68
+ /** Install into a JSON `mcpServers` config (create file/dir if absent). */
69
+ function _installJson(filePath, scriptPath) {
70
+ let settings = {};
71
+ if (fs.existsSync(filePath)) {
72
+ try { settings = JSON.parse(fs.readFileSync(filePath, 'utf8')) || {}; }
73
+ catch (_) { settings = {}; }
74
+ }
75
+ if (!settings.mcpServers) settings.mcpServers = {};
76
+ if (settings.mcpServers.sigmap) return 'already';
77
+ settings.mcpServers.sigmap = { command: 'node', args: serverArgs(scriptPath) };
78
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
79
+ fs.writeFileSync(filePath, JSON.stringify(settings, null, 2) + '\n');
80
+ return 'installed';
81
+ }
82
+
83
+ /** Install into Zed's `context_servers` config (create file/dir if absent). */
84
+ function _installZed(filePath, scriptPath) {
85
+ let settings = {};
86
+ if (fs.existsSync(filePath)) {
87
+ try { settings = JSON.parse(fs.readFileSync(filePath, 'utf8')) || {}; }
88
+ catch (_) { settings = {}; }
89
+ }
90
+ if (!settings.context_servers) settings.context_servers = {};
91
+ if (settings.context_servers.sigmap) return 'already';
92
+ settings.context_servers.sigmap = { command: { path: 'node', args: serverArgs(scriptPath) } };
93
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
94
+ fs.writeFileSync(filePath, JSON.stringify(settings, null, 2) + '\n');
95
+ return 'installed';
96
+ }
97
+
98
+ /** Install into Codex CLI YAML (append block; create file if absent). */
99
+ function _installYaml(filePath, scriptPath) {
100
+ let raw = '';
101
+ if (fs.existsSync(filePath)) {
102
+ raw = fs.readFileSync(filePath, 'utf8');
103
+ if (raw.includes('sigmap')) return 'already';
104
+ }
105
+ const block = [
106
+ 'mcpServers:',
107
+ ' sigmap:',
108
+ ' command: node',
109
+ ' args:',
110
+ ` - ${path.resolve(scriptPath)}`,
111
+ ' - --mcp',
112
+ ].join('\n');
113
+ const next = raw ? raw.trimEnd() + '\n\n' + block + '\n' : block + '\n';
114
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
115
+ fs.writeFileSync(filePath, next);
116
+ return 'installed';
117
+ }
118
+
119
+ /**
120
+ * Install the sigmap MCP server for a single client.
121
+ * @returns { client, label, path, status } where status is
122
+ * 'installed' | 'already' | 'unknown'.
123
+ */
124
+ function installClient(client, opts = {}) {
125
+ const spec = CLIENTS[client];
126
+ if (!spec) {
127
+ return { client, status: 'unknown', valid: Object.keys(CLIENTS) };
128
+ }
129
+ const cwd = opts.cwd || process.cwd();
130
+ const home = opts.home || os.homedir();
131
+ const scriptPath = opts.scriptPath || path.join(cwd, 'gen-context.js');
132
+ const filePath = resolveTarget(spec, cwd, home, opts.global);
133
+
134
+ let status;
135
+ if (spec.format === 'zed') status = _installZed(filePath, scriptPath);
136
+ else if (spec.format === 'yaml') status = _installYaml(filePath, scriptPath);
137
+ else status = _installJson(filePath, scriptPath);
138
+
139
+ return { client, label: spec.label, path: filePath, status };
140
+ }
141
+
142
+ module.exports = { CLIENTS, listClients, installClient, resolveTarget };
package/src/mcp/server.js CHANGED
@@ -18,7 +18,7 @@ const { readContext, searchSignatures, getMap, createCheckpoint, getRouting, exp
18
18
 
19
19
  const SERVER_INFO = {
20
20
  name: 'sigmap',
21
- version: '7.28.0',
21
+ version: '7.29.0',
22
22
  description: 'SigMap MCP server — code signatures on demand',
23
23
  };
24
24