@darkiceinteractive/mcp-conductor 3.0.0-beta.2 → 3.1.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.
Files changed (129) hide show
  1. package/README.md +168 -286
  2. package/dist/bin/cli.d.ts +2 -2
  3. package/dist/bin/cli.js +37 -14
  4. package/dist/bin/cli.js.map +1 -1
  5. package/dist/bridge/http-server.d.ts.map +1 -1
  6. package/dist/bridge/http-server.js +11 -5
  7. package/dist/bridge/http-server.js.map +1 -1
  8. package/dist/cache/disk.d.ts.map +1 -1
  9. package/dist/cache/disk.js +36 -3
  10. package/dist/cache/disk.js.map +1 -1
  11. package/dist/cli/clients/adapter.d.ts +103 -0
  12. package/dist/cli/clients/adapter.d.ts.map +1 -0
  13. package/dist/cli/clients/adapter.js +24 -0
  14. package/dist/cli/clients/adapter.js.map +1 -0
  15. package/dist/cli/clients/claude-code.d.ts +15 -0
  16. package/dist/cli/clients/claude-code.d.ts.map +1 -0
  17. package/dist/cli/clients/claude-code.js +110 -0
  18. package/dist/cli/clients/claude-code.js.map +1 -0
  19. package/dist/cli/clients/claude-desktop.d.ts +26 -0
  20. package/dist/cli/clients/claude-desktop.d.ts.map +1 -0
  21. package/dist/cli/clients/claude-desktop.js +118 -0
  22. package/dist/cli/clients/claude-desktop.js.map +1 -0
  23. package/dist/cli/clients/cline.d.ts +40 -0
  24. package/dist/cli/clients/cline.d.ts.map +1 -0
  25. package/dist/cli/clients/cline.js +134 -0
  26. package/dist/cli/clients/cline.js.map +1 -0
  27. package/dist/cli/clients/codex.d.ts +30 -0
  28. package/dist/cli/clients/codex.d.ts.map +1 -0
  29. package/dist/cli/clients/codex.js +176 -0
  30. package/dist/cli/clients/codex.js.map +1 -0
  31. package/dist/cli/clients/continue.d.ts +41 -0
  32. package/dist/cli/clients/continue.d.ts.map +1 -0
  33. package/dist/cli/clients/continue.js +150 -0
  34. package/dist/cli/clients/continue.js.map +1 -0
  35. package/dist/cli/clients/cursor.d.ts +20 -0
  36. package/dist/cli/clients/cursor.d.ts.map +1 -0
  37. package/dist/cli/clients/cursor.js +110 -0
  38. package/dist/cli/clients/cursor.js.map +1 -0
  39. package/dist/cli/clients/gemini-cli.d.ts +42 -0
  40. package/dist/cli/clients/gemini-cli.d.ts.map +1 -0
  41. package/dist/cli/clients/gemini-cli.js +169 -0
  42. package/dist/cli/clients/gemini-cli.js.map +1 -0
  43. package/dist/cli/clients/index.d.ts +28 -0
  44. package/dist/cli/clients/index.d.ts.map +1 -0
  45. package/dist/cli/clients/index.js +44 -0
  46. package/dist/cli/clients/index.js.map +1 -0
  47. package/dist/cli/clients/kimi-code.d.ts +33 -0
  48. package/dist/cli/clients/kimi-code.d.ts.map +1 -0
  49. package/dist/cli/clients/kimi-code.js +177 -0
  50. package/dist/cli/clients/kimi-code.js.map +1 -0
  51. package/dist/cli/clients/opencode.d.ts +21 -0
  52. package/dist/cli/clients/opencode.d.ts.map +1 -0
  53. package/dist/cli/clients/opencode.js +150 -0
  54. package/dist/cli/clients/opencode.js.map +1 -0
  55. package/dist/cli/clients/registry.d.ts +51 -0
  56. package/dist/cli/clients/registry.d.ts.map +1 -0
  57. package/dist/cli/clients/registry.js +169 -0
  58. package/dist/cli/clients/registry.js.map +1 -0
  59. package/dist/cli/clients/zed.d.ts +41 -0
  60. package/dist/cli/clients/zed.d.ts.map +1 -0
  61. package/dist/cli/clients/zed.js +171 -0
  62. package/dist/cli/clients/zed.js.map +1 -0
  63. package/dist/cli/commands/doctor.d.ts +27 -0
  64. package/dist/cli/commands/doctor.d.ts.map +1 -1
  65. package/dist/cli/commands/doctor.js +71 -0
  66. package/dist/cli/commands/doctor.js.map +1 -1
  67. package/dist/cli/commands/export-servers.d.ts +60 -0
  68. package/dist/cli/commands/export-servers.d.ts.map +1 -1
  69. package/dist/cli/commands/export-servers.js +85 -1
  70. package/dist/cli/commands/export-servers.js.map +1 -1
  71. package/dist/cli/commands/import-servers.d.ts +13 -2
  72. package/dist/cli/commands/import-servers.d.ts.map +1 -1
  73. package/dist/cli/commands/import-servers.js +42 -5
  74. package/dist/cli/commands/import-servers.js.map +1 -1
  75. package/dist/cli/wizard/setup.d.ts +29 -3
  76. package/dist/cli/wizard/setup.d.ts.map +1 -1
  77. package/dist/cli/wizard/setup.js +204 -7
  78. package/dist/cli/wizard/setup.js.map +1 -1
  79. package/dist/config/defaults.d.ts.map +1 -1
  80. package/dist/config/defaults.js +1 -0
  81. package/dist/config/defaults.js.map +1 -1
  82. package/dist/config/loader.d.ts +10 -1
  83. package/dist/config/loader.d.ts.map +1 -1
  84. package/dist/config/loader.js +14 -24
  85. package/dist/config/loader.js.map +1 -1
  86. package/dist/config/schema.d.ts +7 -0
  87. package/dist/config/schema.d.ts.map +1 -1
  88. package/dist/daemon/client.d.ts.map +1 -1
  89. package/dist/daemon/client.js +14 -6
  90. package/dist/daemon/client.js.map +1 -1
  91. package/dist/daemon/server.d.ts +9 -0
  92. package/dist/daemon/server.d.ts.map +1 -1
  93. package/dist/daemon/server.js +80 -9
  94. package/dist/daemon/server.js.map +1 -1
  95. package/dist/metrics/index.d.ts +1 -1
  96. package/dist/metrics/index.d.ts.map +1 -1
  97. package/dist/metrics/index.js +1 -1
  98. package/dist/metrics/index.js.map +1 -1
  99. package/dist/metrics/metrics-collector.d.ts +120 -0
  100. package/dist/metrics/metrics-collector.d.ts.map +1 -1
  101. package/dist/metrics/metrics-collector.js +136 -0
  102. package/dist/metrics/metrics-collector.js.map +1 -1
  103. package/dist/runtime/pool/recycle.d.ts +8 -2
  104. package/dist/runtime/pool/recycle.d.ts.map +1 -1
  105. package/dist/runtime/pool/recycle.js.map +1 -1
  106. package/dist/runtime/pool/worker-pool.d.ts.map +1 -1
  107. package/dist/runtime/pool/worker-pool.js +17 -10
  108. package/dist/runtime/pool/worker-pool.js.map +1 -1
  109. package/dist/runtime/pool/worker.d.ts +7 -1
  110. package/dist/runtime/pool/worker.d.ts.map +1 -1
  111. package/dist/runtime/pool/worker.js +9 -1
  112. package/dist/runtime/pool/worker.js.map +1 -1
  113. package/dist/server/mcp-server.d.ts +15 -3
  114. package/dist/server/mcp-server.d.ts.map +1 -1
  115. package/dist/server/mcp-server.js +81 -7
  116. package/dist/server/mcp-server.js.map +1 -1
  117. package/dist/utils/backup.d.ts +24 -0
  118. package/dist/utils/backup.d.ts.map +1 -0
  119. package/dist/utils/backup.js +40 -0
  120. package/dist/utils/backup.js.map +1 -0
  121. package/dist/utils/tokenize.d.ts +8 -0
  122. package/dist/utils/tokenize.d.ts.map +1 -1
  123. package/dist/utils/tokenize.js +8 -0
  124. package/dist/utils/tokenize.js.map +1 -1
  125. package/dist/version.d.ts +3 -3
  126. package/dist/version.d.ts.map +1 -1
  127. package/dist/version.js +3 -3
  128. package/dist/version.js.map +1 -1
  129. package/package.json +23 -2
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/clients/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,OAAO,EAAE,uBAAuB,EAAE,MAAM,eAAe,CAAC;AAaxD,gFAAgF;AAChF,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAExC,8EAA8E;AAC9E,wBAAwB;AACxB,8EAA8E;AAC9E,uEAAuE;AACvE,yEAAyE;AACzE,wEAAwE;AACxE,8BAA8B;AAE9B,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,kBAAkB,CAAC;AAC1B,OAAO,qBAAqB,CAAC;AAC7B,OAAO,YAAY,CAAC;AACpB,OAAO,aAAa,CAAC;AACrB,OAAO,iBAAiB,CAAC;AACzB,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEnD,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;AACjC,QAAQ,CAAC,GAAG,CAAC,UAAU,EAAE,gBAAgB,CAAC,CAAC;AAC3C,QAAQ,CAAC,GAAG,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;AACrC,QAAQ,CAAC,GAAG,CAAC,UAAU,EAAE,gBAAgB,CAAC,CAAC;AAC3C,QAAQ,CAAC,GAAG,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAC"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * MCPClientAdapter for Kimi Code (Moonshot AI).
3
+ *
4
+ * Kimi Code stores MCP server definitions in a JSON file whose location varies
5
+ * by platform (see registry.ts). The config uses the Anthropic-compatible
6
+ * `mcpServers` shape, so entries are either stdio (`{command, args, env}`) or
7
+ * HTTP (`{url, headers}`).
8
+ *
9
+ * HTTP entries cannot be proxied through conductor's stdio process. They are
10
+ * skipped during normalisation and flagged with a logged warning so the caller
11
+ * can surface actionable guidance to the user.
12
+ *
13
+ * The CLI also accepts `--mcp-config-file <path>` so users may point it at an
14
+ * arbitrary Anthropic-format config (e.g. a symlink to a Claude config). This
15
+ * adapter works with any path that carries an `mcpServers` top-level key.
16
+ *
17
+ * 4-fact preamble:
18
+ * 1. Config format: JSON with top-level `mcpServers` key.
19
+ * 2. Stdio shape: `{ command, args?, env? }` — Anthropic-compatible.
20
+ * 3. HTTP shape: `{ url, headers? }` — skipped with warning; carried in `raw`.
21
+ * 4. Backup: `.bak.YYYYMMDDHHMMSS` written before every serialize() call.
22
+ *
23
+ * @module cli/clients/kimi-code
24
+ */
25
+ import type { MCPClientAdapter } from './adapter.js';
26
+ /**
27
+ * MCPClientAdapter for Kimi Code.
28
+ *
29
+ * Exported as a named constant (singleton object literal) — stateless, so no
30
+ * class instance overhead is needed.
31
+ */
32
+ export declare const KIMI_CODE_ADAPTER: MCPClientAdapter;
33
+ //# sourceMappingURL=kimi-code.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kimi-code.d.ts","sourceRoot":"","sources":["../../../src/cli/clients/kimi-code.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAIH,OAAO,KAAK,EACV,gBAAgB,EAIjB,MAAM,cAAc,CAAC;AA2DtB;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,EAAE,gBAkH/B,CAAC"}
@@ -0,0 +1,177 @@
1
+ /**
2
+ * MCPClientAdapter for Kimi Code (Moonshot AI).
3
+ *
4
+ * Kimi Code stores MCP server definitions in a JSON file whose location varies
5
+ * by platform (see registry.ts). The config uses the Anthropic-compatible
6
+ * `mcpServers` shape, so entries are either stdio (`{command, args, env}`) or
7
+ * HTTP (`{url, headers}`).
8
+ *
9
+ * HTTP entries cannot be proxied through conductor's stdio process. They are
10
+ * skipped during normalisation and flagged with a logged warning so the caller
11
+ * can surface actionable guidance to the user.
12
+ *
13
+ * The CLI also accepts `--mcp-config-file <path>` so users may point it at an
14
+ * arbitrary Anthropic-format config (e.g. a symlink to a Claude config). This
15
+ * adapter works with any path that carries an `mcpServers` top-level key.
16
+ *
17
+ * 4-fact preamble:
18
+ * 1. Config format: JSON with top-level `mcpServers` key.
19
+ * 2. Stdio shape: `{ command, args?, env? }` — Anthropic-compatible.
20
+ * 3. HTTP shape: `{ url, headers? }` — skipped with warning; carried in `raw`.
21
+ * 4. Backup: `.bak.YYYYMMDDHHMMSS` written before every serialize() call.
22
+ *
23
+ * @module cli/clients/kimi-code
24
+ */
25
+ import { existsSync, readFileSync, writeFileSync, copyFileSync } from 'node:fs';
26
+ import { logger } from '../../utils/logger.js';
27
+ // ---------------------------------------------------------------------------
28
+ // Type guards
29
+ // ---------------------------------------------------------------------------
30
+ function isHttpEntry(entry) {
31
+ return typeof entry.url === 'string';
32
+ }
33
+ function isStdioEntry(entry) {
34
+ return typeof entry.command === 'string';
35
+ }
36
+ // ---------------------------------------------------------------------------
37
+ // Backup helper (mirrors writeBackup in import-servers.ts)
38
+ //
39
+ // Writes a `.bak.YYYYMMDDHHMMSS` file next to the original. A random 4-char
40
+ // hex suffix guards against sub-second collisions on repeat calls.
41
+ // ---------------------------------------------------------------------------
42
+ function writeBackup(filePath) {
43
+ const ts = new Date().toISOString().replace(/\D/g, '').slice(0, 14);
44
+ let backupPath = `${filePath}.bak.${ts}`;
45
+ if (existsSync(backupPath)) {
46
+ const salt = Math.floor(Math.random() * 0xffff).toString(16).padStart(4, '0');
47
+ backupPath = `${backupPath}.${salt}`;
48
+ }
49
+ copyFileSync(filePath, backupPath);
50
+ return backupPath;
51
+ }
52
+ // ---------------------------------------------------------------------------
53
+ // Adapter implementation
54
+ // ---------------------------------------------------------------------------
55
+ /**
56
+ * MCPClientAdapter for Kimi Code.
57
+ *
58
+ * Exported as a named constant (singleton object literal) — stateless, so no
59
+ * class instance overhead is needed.
60
+ */
61
+ export const KIMI_CODE_ADAPTER = {
62
+ client: 'kimi-code',
63
+ /**
64
+ * Parse the Kimi Code config at `path`.
65
+ *
66
+ * - Returns `null` when the file does not exist, cannot be read, or contains
67
+ * no `mcpServers` key.
68
+ * - HTTP entries are warned about and excluded from `servers` but their raw
69
+ * data remains accessible via `config.raw` for diagnostics.
70
+ */
71
+ parse(path) {
72
+ if (!existsSync(path)) {
73
+ logger.debug('kimi-code: config file not found', { path });
74
+ return null;
75
+ }
76
+ let raw;
77
+ try {
78
+ const text = readFileSync(path, 'utf-8');
79
+ raw = JSON.parse(text);
80
+ }
81
+ catch (err) {
82
+ logger.warn('kimi-code: failed to parse config file', {
83
+ path,
84
+ error: err instanceof Error ? err.message : String(err),
85
+ });
86
+ return null;
87
+ }
88
+ if (!raw.mcpServers || Object.keys(raw.mcpServers).length === 0) {
89
+ logger.debug('kimi-code: config contains no mcpServers', { path });
90
+ return null;
91
+ }
92
+ const servers = {};
93
+ for (const [name, entry] of Object.entries(raw.mcpServers)) {
94
+ if (isHttpEntry(entry)) {
95
+ // HTTP entries cannot be proxied via conductor's stdio transport.
96
+ logger.warn('kimi-code: skipping HTTP entry — conductor cannot proxy HTTP MCP servers via stdio; ' +
97
+ 'remove or migrate this entry to a stdio server', { server: name, url: entry.url });
98
+ // Entry stays in `raw` so serialize() preserves it for the user.
99
+ continue;
100
+ }
101
+ if (isStdioEntry(entry)) {
102
+ servers[name] = {
103
+ command: entry.command,
104
+ args: entry.args ?? [],
105
+ env: entry.env ?? {},
106
+ };
107
+ continue;
108
+ }
109
+ // Unknown shape — skip silently with a debug note.
110
+ logger.debug('kimi-code: unrecognised server entry shape, skipping', { server: name });
111
+ }
112
+ return { servers, raw };
113
+ },
114
+ /**
115
+ * Write the (possibly modified) config back to disk.
116
+ *
117
+ * Algorithm:
118
+ * 1. Write a `.bak.YYYYMMDDHHMMSS` backup if the file currently exists.
119
+ * 2. Start from `config.raw` to preserve all non-MCP top-level keys.
120
+ * 3. If `keepOnlyConductor` is set, replace `mcpServers` with only the
121
+ * conductor entry — all other server entries (including HTTP ones) are
122
+ * dropped.
123
+ * 4. Otherwise merge the normalised servers back in. HTTP entries that were
124
+ * in the original raw remain intact because they live in `raw.mcpServers`
125
+ * and are not deleted during normalisation.
126
+ * 5. Upsert `options.conductorEntry` under the `"mcp-conductor"` key.
127
+ */
128
+ serialize(path, config, options) {
129
+ // Step 1: backup existing file before any mutation.
130
+ if (existsSync(path)) {
131
+ const backupPath = writeBackup(path);
132
+ logger.debug('kimi-code: backup written', { backup: backupPath });
133
+ }
134
+ // Step 2: clone raw to avoid mutating the caller's object.
135
+ const output = { ...config.raw };
136
+ if (options.keepOnlyConductor) {
137
+ // Step 3: replace mcpServers entirely — only the conductor entry survives.
138
+ output['mcpServers'] = {
139
+ 'mcp-conductor': buildStdioEntry(options.conductorEntry),
140
+ };
141
+ }
142
+ else {
143
+ // Step 4: merge normalised servers into the existing raw mcpServers map.
144
+ // Raw already contains HTTP entries; we overwrite/add stdio entries from
145
+ // config.servers and then upsert the conductor entry.
146
+ const merged = {
147
+ ...(config.raw.mcpServers ?? {}),
148
+ };
149
+ for (const [name, entry] of Object.entries(config.servers)) {
150
+ merged[name] = buildStdioEntry(entry);
151
+ }
152
+ // Step 5: upsert conductor entry.
153
+ merged['mcp-conductor'] = buildStdioEntry(options.conductorEntry);
154
+ output['mcpServers'] = merged;
155
+ }
156
+ writeFileSync(path, JSON.stringify(output, null, 2), 'utf-8');
157
+ logger.debug('kimi-code: config written', { path });
158
+ },
159
+ };
160
+ // ---------------------------------------------------------------------------
161
+ // Private helpers
162
+ // ---------------------------------------------------------------------------
163
+ /**
164
+ * Build a KimiStdioEntry from a NormalisedServerEntry, omitting optional
165
+ * fields when they are empty so the written JSON stays clean.
166
+ */
167
+ function buildStdioEntry(entry) {
168
+ const result = { command: entry.command };
169
+ if (entry.args !== undefined && entry.args.length > 0) {
170
+ result.args = entry.args;
171
+ }
172
+ if (entry.env !== undefined && Object.keys(entry.env).length > 0) {
173
+ result.env = entry.env;
174
+ }
175
+ return result;
176
+ }
177
+ //# sourceMappingURL=kimi-code.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kimi-code.js","sourceRoot":"","sources":["../../../src/cli/clients/kimi-code.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * MCPClientAdapter implementation for OpenCode.
3
+ *
4
+ * Key divergences from the Claude-family adapters:
5
+ *
6
+ * 1. MCP key is `mcp` (NOT `mcpServers`).
7
+ * 2. Every server entry carries a required `type` field — either `"local"` or
8
+ * `"remote"`. Remote entries are not importable (skipped with a warning).
9
+ * 3. An optional `enabled` boolean may be present; disabled entries are still
10
+ * importable but the flag is preserved in `raw` so round-trip writes retain it.
11
+ *
12
+ * Config file locations (verified against OpenCode v0.1.x):
13
+ * - Global (macOS / Linux): `~/.config/opencode/opencode.json`
14
+ * - Global (Windows): `%APPDATA%\opencode\opencode.json`
15
+ * - Project-local: `./opencode.json`
16
+ *
17
+ * @module cli/clients/opencode
18
+ */
19
+ import type { MCPClientAdapter } from './adapter.js';
20
+ export declare const OPENCODE_ADAPTER: MCPClientAdapter;
21
+ //# sourceMappingURL=opencode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opencode.d.ts","sourceRoot":"","sources":["../../../src/cli/clients/opencode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,OAAO,KAAK,EACV,gBAAgB,EAIjB,MAAM,cAAc,CAAC;AAmDtB,eAAO,MAAM,gBAAgB,EAAE,gBA4H9B,CAAC"}
@@ -0,0 +1,150 @@
1
+ /**
2
+ * MCPClientAdapter implementation for OpenCode.
3
+ *
4
+ * Key divergences from the Claude-family adapters:
5
+ *
6
+ * 1. MCP key is `mcp` (NOT `mcpServers`).
7
+ * 2. Every server entry carries a required `type` field — either `"local"` or
8
+ * `"remote"`. Remote entries are not importable (skipped with a warning).
9
+ * 3. An optional `enabled` boolean may be present; disabled entries are still
10
+ * importable but the flag is preserved in `raw` so round-trip writes retain it.
11
+ *
12
+ * Config file locations (verified against OpenCode v0.1.x):
13
+ * - Global (macOS / Linux): `~/.config/opencode/opencode.json`
14
+ * - Global (Windows): `%APPDATA%\opencode\opencode.json`
15
+ * - Project-local: `./opencode.json`
16
+ *
17
+ * @module cli/clients/opencode
18
+ */
19
+ import { existsSync, readFileSync, writeFileSync, copyFileSync } from 'node:fs';
20
+ import { safeJsonParse } from '../../utils/index.js';
21
+ // ---------------------------------------------------------------------------
22
+ // Backup helper (mirrors writeBackup pattern from import-servers.ts)
23
+ // ---------------------------------------------------------------------------
24
+ /**
25
+ * Write a `.bak.YYYYMMDDHHMMSS` backup alongside `filePath`.
26
+ * A random 4-char hex suffix is appended on sub-second collision.
27
+ */
28
+ function writeBackup(filePath) {
29
+ const ts = new Date().toISOString().replace(/\D/g, '').slice(0, 14);
30
+ let backupPath = `${filePath}.bak.${ts}`;
31
+ if (existsSync(backupPath)) {
32
+ const salt = Math.floor(Math.random() * 0xffff).toString(16).padStart(4, '0');
33
+ backupPath = `${backupPath}.${salt}`;
34
+ }
35
+ copyFileSync(filePath, backupPath);
36
+ return backupPath;
37
+ }
38
+ // ---------------------------------------------------------------------------
39
+ // Adapter implementation
40
+ // ---------------------------------------------------------------------------
41
+ export const OPENCODE_ADAPTER = {
42
+ client: 'opencode',
43
+ /**
44
+ * Parse an OpenCode config file into the normalised shape.
45
+ *
46
+ * - Iterates `mcp.*` (note: key is `mcp`, not `mcpServers`).
47
+ * - Skips `type: "remote"` entries with a console.warn (not importable).
48
+ * - `type: "local"` entries are normalised to `{command, args, env}`.
49
+ * - `enabled: false` is preserved in the underlying `raw` object so
50
+ * serialize() can round-trip it faithfully without touching NormalisedServerEntry.
51
+ */
52
+ parse(path) {
53
+ if (!existsSync(path))
54
+ return null;
55
+ let content;
56
+ try {
57
+ content = readFileSync(path, 'utf-8');
58
+ }
59
+ catch {
60
+ return null;
61
+ }
62
+ const raw = safeJsonParse(content, {});
63
+ const mcpMap = raw.mcp;
64
+ if (!mcpMap || typeof mcpMap !== 'object') {
65
+ return null;
66
+ }
67
+ const servers = {};
68
+ let localCount = 0;
69
+ for (const [name, entry] of Object.entries(mcpMap)) {
70
+ if (entry.type === 'remote') {
71
+ console.warn(`[opencode adapter] Skipping "${name}": type "remote" entries cannot be imported (only "local" is supported).`);
72
+ continue;
73
+ }
74
+ if (entry.type === 'local') {
75
+ localCount++;
76
+ servers[name] = {
77
+ command: entry.command,
78
+ ...(entry.args !== undefined ? { args: entry.args } : {}),
79
+ ...(entry.env !== undefined ? { env: entry.env } : {}),
80
+ };
81
+ // enabled flag stays in raw — not copied into NormalisedServerEntry to
82
+ // avoid changing the shared interface. serialize() reads it back from raw.
83
+ }
84
+ }
85
+ // Return null when there were no local entries at all (nothing importable).
86
+ if (localCount === 0) {
87
+ return null;
88
+ }
89
+ return { servers, raw };
90
+ },
91
+ /**
92
+ * Write a (potentially modified) OpenCode config back to disk.
93
+ *
94
+ * Rules:
95
+ * 1. Always injects `type: "local"` on every serialised entry.
96
+ * 2. Ensures `mcp-conductor` is present with `conductorEntry`.
97
+ * 3. If `keepOnlyConductor` is true, replaces `mcp` with a single entry.
98
+ * 4. Preserves all other top-level OpenCode keys from `config.raw`.
99
+ * 5. Preserves `enabled: false` from the original raw entry on round-trip.
100
+ * 6. Writes a `.bak.YYYYMMDDHHMMSS` backup before overwriting.
101
+ */
102
+ serialize(path, config, options) {
103
+ // Write backup first if file already exists.
104
+ if (existsSync(path)) {
105
+ writeBackup(path);
106
+ }
107
+ const existingRaw = config.raw ?? {};
108
+ // Build the mcp map to write.
109
+ let mcpToWrite;
110
+ if (options.keepOnlyConductor) {
111
+ mcpToWrite = {
112
+ 'mcp-conductor': {
113
+ type: 'local',
114
+ command: options.conductorEntry.command,
115
+ ...(options.conductorEntry.args !== undefined ? { args: options.conductorEntry.args } : {}),
116
+ ...(options.conductorEntry.env !== undefined ? { env: options.conductorEntry.env } : {}),
117
+ },
118
+ };
119
+ }
120
+ else {
121
+ mcpToWrite = {};
122
+ // Carry through existing normalised servers, injecting type: "local".
123
+ for (const [name, entry] of Object.entries(config.servers)) {
124
+ // Retrieve the enabled flag from raw if present so it survives round-trip.
125
+ const rawEntry = existingRaw.mcp?.[name];
126
+ mcpToWrite[name] = {
127
+ type: 'local',
128
+ command: entry.command,
129
+ ...(entry.args !== undefined ? { args: entry.args } : {}),
130
+ ...(entry.env !== undefined ? { env: entry.env } : {}),
131
+ ...(rawEntry?.enabled === false ? { enabled: false } : {}),
132
+ };
133
+ }
134
+ // Ensure conductor entry is present / updated.
135
+ mcpToWrite['mcp-conductor'] = {
136
+ type: 'local',
137
+ command: options.conductorEntry.command,
138
+ ...(options.conductorEntry.args !== undefined ? { args: options.conductorEntry.args } : {}),
139
+ ...(options.conductorEntry.env !== undefined ? { env: options.conductorEntry.env } : {}),
140
+ };
141
+ }
142
+ // Merge into a copy of raw, preserving all non-mcp top-level keys.
143
+ const output = {
144
+ ...existingRaw,
145
+ mcp: mcpToWrite,
146
+ };
147
+ writeFileSync(path, JSON.stringify(output, null, 2), 'utf-8');
148
+ },
149
+ };
150
+ //# sourceMappingURL=opencode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opencode.js","sourceRoot":"","sources":["../../../src/cli/clients/opencode.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Multi-client MCP configuration discovery registry.
3
+ *
4
+ * Provides typed location records for every known MCP-capable client on the
5
+ * current machine. The list covers macOS, Linux, and Windows search paths
6
+ * from the v3.1.1 verified client table.
7
+ *
8
+ * @module cli/clients/registry
9
+ */
10
+ export type MCPClientId = 'claude-code' | 'claude-desktop' | 'codex' | 'gemini-cli' | 'cursor' | 'cline' | 'zed' | 'continue' | 'opencode' | 'kimi-code';
11
+ export type ConfigFormat = 'json' | 'toml' | 'yaml';
12
+ export interface MCPClientConfigLocation {
13
+ /** Stable identifier for the client. */
14
+ client: MCPClientId;
15
+ /** Human-readable label shown in UI / logs. */
16
+ displayName: string;
17
+ /** Absolute path to the config file (may or may not exist). */
18
+ path: string;
19
+ /** Serialisation format of the config file. */
20
+ format: ConfigFormat;
21
+ /**
22
+ * Key (or key path) inside the config that holds the server map.
23
+ * - JSON clients: `"mcpServers"` | `"mcp"` | `"context_servers"`
24
+ * - TOML clients: `"[mcp_servers.*]"` (section prefix)
25
+ */
26
+ mcpKey: string;
27
+ /** Whether the file exists on disk at discovery time. */
28
+ exists: boolean;
29
+ /** Whether this is a user-global config or a project-local config. */
30
+ scope: 'global' | 'project';
31
+ }
32
+ export interface GetMCPClientConfigPathsOptions {
33
+ /**
34
+ * When `true`, also include project-local config locations resolved from
35
+ * `process.cwd()`. Defaults to `false`.
36
+ */
37
+ includeProject?: boolean;
38
+ }
39
+ /**
40
+ * Discover every MCP client config location on this machine.
41
+ *
42
+ * Returns all known locations regardless of whether the file currently exists;
43
+ * callers should filter on `exists` when they only want present files.
44
+ *
45
+ * Platform coverage:
46
+ * - macOS (darwin)
47
+ * - Linux (via XDG / home-relative paths)
48
+ * - Windows (via APPDATA / LOCALAPPDATA)
49
+ */
50
+ export declare function getMCPClientConfigPaths(opts?: GetMCPClientConfigPathsOptions): MCPClientConfigLocation[];
51
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/cli/clients/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAUH,MAAM,MAAM,WAAW,GACnB,aAAa,GACb,gBAAgB,GAChB,OAAO,GACP,YAAY,GACZ,QAAQ,GACR,OAAO,GACP,KAAK,GACL,UAAU,GACV,UAAU,GACV,WAAW,CAAC;AAEhB,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAEpD,MAAM,WAAW,uBAAuB;IACtC,wCAAwC;IACxC,MAAM,EAAE,WAAW,CAAC;IACpB,+CAA+C;IAC/C,WAAW,EAAE,MAAM,CAAC;IACpB,+DAA+D;IAC/D,IAAI,EAAE,MAAM,CAAC;IACb,+CAA+C;IAC/C,MAAM,EAAE,YAAY,CAAC;IACrB;;;;OAIG;IACH,MAAM,EAAE,MAAM,CAAC;IACf,yDAAyD;IACzD,MAAM,EAAE,OAAO,CAAC;IAChB,sEAAsE;IACtE,KAAK,EAAE,QAAQ,GAAG,SAAS,CAAC;CAC7B;AAED,MAAM,WAAW,8BAA8B;IAC7C;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAwBD;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,GAAE,8BAAmC,GACxC,uBAAuB,EAAE,CA2J3B"}
@@ -0,0 +1,169 @@
1
+ /**
2
+ * Multi-client MCP configuration discovery registry.
3
+ *
4
+ * Provides typed location records for every known MCP-capable client on the
5
+ * current machine. The list covers macOS, Linux, and Windows search paths
6
+ * from the v3.1.1 verified client table.
7
+ *
8
+ * @module cli/clients/registry
9
+ */
10
+ import { existsSync } from 'node:fs';
11
+ import { homedir } from 'node:os';
12
+ import { join } from 'node:path';
13
+ // ---------------------------------------------------------------------------
14
+ // Internal helpers
15
+ // ---------------------------------------------------------------------------
16
+ /**
17
+ * Build a location record, resolving `exists` at call time.
18
+ */
19
+ function loc(client, displayName, path, format, mcpKey, scope = 'global') {
20
+ return { client, displayName, path, format, mcpKey, exists: existsSync(path), scope };
21
+ }
22
+ // ---------------------------------------------------------------------------
23
+ // Discovery function
24
+ // ---------------------------------------------------------------------------
25
+ /**
26
+ * Discover every MCP client config location on this machine.
27
+ *
28
+ * Returns all known locations regardless of whether the file currently exists;
29
+ * callers should filter on `exists` when they only want present files.
30
+ *
31
+ * Platform coverage:
32
+ * - macOS (darwin)
33
+ * - Linux (via XDG / home-relative paths)
34
+ * - Windows (via APPDATA / LOCALAPPDATA)
35
+ */
36
+ export function getMCPClientConfigPaths(opts = {}) {
37
+ const home = homedir();
38
+ const platform = process.platform;
39
+ const appData = process.env['APPDATA'] ?? '';
40
+ const localAppData = process.env['LOCALAPPDATA'] ?? '';
41
+ const isWin = platform === 'win32';
42
+ const isMac = platform === 'darwin';
43
+ const results = [];
44
+ // -------------------------------------------------------------------------
45
+ // Claude Code
46
+ // -------------------------------------------------------------------------
47
+ // macOS / Linux global
48
+ results.push(loc('claude-code', 'Claude Code', join(home, '.claude', 'settings.json'), 'json', 'mcpServers'));
49
+ results.push(loc('claude-code', 'Claude Code', join(home, '.claude.json'), 'json', 'mcpServers'));
50
+ // macOS application support
51
+ if (isMac) {
52
+ results.push(loc('claude-code', 'Claude Code', join(home, 'Library', 'Application Support', 'Claude Code', 'claude_code_config.json'), 'json', 'mcpServers'));
53
+ results.push(loc('claude-code', 'Claude Code', join(home, 'Library', 'Application Support', 'Claude', 'claude_code_config.json'), 'json', 'mcpServers'));
54
+ }
55
+ // Linux XDG
56
+ if (!isWin) {
57
+ results.push(loc('claude-code', 'Claude Code', join(home, '.config', 'Claude Code', 'claude_code_config.json'), 'json', 'mcpServers'));
58
+ }
59
+ // Windows
60
+ if (isWin && appData) {
61
+ results.push(loc('claude-code', 'Claude Code', join(appData, 'Claude Code', 'claude_code_config.json'), 'json', 'mcpServers'));
62
+ }
63
+ // -------------------------------------------------------------------------
64
+ // Claude Desktop
65
+ // -------------------------------------------------------------------------
66
+ if (isMac) {
67
+ results.push(loc('claude-desktop', 'Claude Desktop', join(home, 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json'), 'json', 'mcpServers'));
68
+ }
69
+ // Linux
70
+ if (!isWin) {
71
+ results.push(loc('claude-desktop', 'Claude Desktop', join(home, '.config', 'claude', 'claude_desktop_config.json'), 'json', 'mcpServers'));
72
+ }
73
+ // Windows
74
+ if (isWin && appData) {
75
+ results.push(loc('claude-desktop', 'Claude Desktop', join(appData, 'Claude', 'claude_desktop_config.json'), 'json', 'mcpServers'));
76
+ }
77
+ // -------------------------------------------------------------------------
78
+ // OpenAI Codex CLI
79
+ // -------------------------------------------------------------------------
80
+ // ~/.codex/config.toml (all platforms — Codex uses TOML, not JSON)
81
+ results.push(loc('codex', 'Codex CLI', join(home, '.codex', 'config.toml'), 'toml', '[mcp_servers.*]'));
82
+ // -------------------------------------------------------------------------
83
+ // Gemini CLI
84
+ // -------------------------------------------------------------------------
85
+ // ~/.gemini/settings.json (all platforms)
86
+ results.push(loc('gemini-cli', 'Gemini CLI', join(home, '.gemini', 'settings.json'), 'json', 'mcpServers'));
87
+ // -------------------------------------------------------------------------
88
+ // Cursor
89
+ // -------------------------------------------------------------------------
90
+ if (isMac) {
91
+ results.push(loc('cursor', 'Cursor', join(home, 'Library', 'Application Support', 'Cursor', 'User', 'settings.json'), 'json', 'mcp'));
92
+ }
93
+ if (!isWin && !isMac) {
94
+ results.push(loc('cursor', 'Cursor', join(home, '.config', 'Cursor', 'User', 'settings.json'), 'json', 'mcp'));
95
+ }
96
+ if (isWin && appData) {
97
+ results.push(loc('cursor', 'Cursor', join(appData, 'Cursor', 'User', 'settings.json'), 'json', 'mcp'));
98
+ }
99
+ // Global cursor MCP config
100
+ results.push(loc('cursor', 'Cursor', join(home, '.cursor', 'mcp.json'), 'json', 'mcpServers'));
101
+ // -------------------------------------------------------------------------
102
+ // Cline (VS Code extension)
103
+ // -------------------------------------------------------------------------
104
+ // Cline stores its MCP config in the VS Code globalStorage area
105
+ if (isMac) {
106
+ results.push(loc('cline', 'Cline', join(home, 'Library', 'Application Support', 'Code', 'User', 'globalStorage', 'saoudrizwan.claude-dev', 'settings', 'cline_mcp_settings.json'), 'json', 'mcpServers'));
107
+ }
108
+ if (!isWin && !isMac) {
109
+ results.push(loc('cline', 'Cline', join(home, '.config', 'Code', 'User', 'globalStorage', 'saoudrizwan.claude-dev', 'settings', 'cline_mcp_settings.json'), 'json', 'mcpServers'));
110
+ }
111
+ if (isWin && appData) {
112
+ results.push(loc('cline', 'Cline', join(appData, 'Code', 'User', 'globalStorage', 'saoudrizwan.claude-dev', 'settings', 'cline_mcp_settings.json'), 'json', 'mcpServers'));
113
+ }
114
+ // -------------------------------------------------------------------------
115
+ // Zed
116
+ // -------------------------------------------------------------------------
117
+ if (isMac) {
118
+ results.push(loc('zed', 'Zed', join(home, 'Library', 'Application Support', 'Zed', 'settings.json'), 'json', 'context_servers'));
119
+ }
120
+ if (!isWin && !isMac) {
121
+ results.push(loc('zed', 'Zed', join(home, '.config', 'zed', 'settings.json'), 'json', 'context_servers'));
122
+ }
123
+ if (isWin && localAppData) {
124
+ results.push(loc('zed', 'Zed', join(localAppData, 'Zed', 'settings.json'), 'json', 'context_servers'));
125
+ }
126
+ // -------------------------------------------------------------------------
127
+ // Continue.dev (VS Code / JetBrains extension)
128
+ // -------------------------------------------------------------------------
129
+ results.push(loc('continue', 'Continue.dev', join(home, '.continue', 'config.yaml'), 'yaml', 'mcpServers'));
130
+ // -------------------------------------------------------------------------
131
+ // OpenCode (uses 'mcp' key not 'mcpServers'; file is opencode.json)
132
+ // -------------------------------------------------------------------------
133
+ results.push(loc('opencode', 'OpenCode', join(home, '.config', 'opencode', 'opencode.json'), 'json', 'mcp'));
134
+ if (isWin && appData) {
135
+ results.push(loc('opencode', 'OpenCode', join(appData, 'opencode', 'opencode.json'), 'json', 'mcp'));
136
+ }
137
+ // -------------------------------------------------------------------------
138
+ // Kimi Code (Moonshot AI)
139
+ // -------------------------------------------------------------------------
140
+ if (isMac) {
141
+ results.push(loc('kimi-code', 'Kimi Code', join(home, 'Library', 'Application Support', 'Kimi Code', 'mcp_settings.json'), 'json', 'mcpServers'));
142
+ }
143
+ if (!isWin && !isMac) {
144
+ results.push(loc('kimi-code', 'Kimi Code', join(home, '.config', 'kimi-code', 'mcp_settings.json'), 'json', 'mcpServers'));
145
+ }
146
+ if (isWin && appData) {
147
+ results.push(loc('kimi-code', 'Kimi Code', join(appData, 'Kimi Code', 'mcp_settings.json'), 'json', 'mcpServers'));
148
+ }
149
+ // -------------------------------------------------------------------------
150
+ // Project-local paths (opt-in)
151
+ // -------------------------------------------------------------------------
152
+ if (opts.includeProject) {
153
+ const cwd = process.cwd();
154
+ // Claude Code project-local
155
+ results.push(loc('claude-code', 'Claude Code', join(cwd, '.claude', 'settings.json'), 'json', 'mcpServers', 'project'));
156
+ results.push(loc('claude-code', 'Claude Code', join(cwd, 'claude_code_config.json'), 'json', 'mcpServers', 'project'));
157
+ results.push(loc('claude-code', 'Claude Code', join(cwd, '.mcp.json'), 'json', 'mcpServers', 'project'));
158
+ // Claude Desktop project-local
159
+ results.push(loc('claude-desktop', 'Claude Desktop', join(cwd, 'claude_desktop_config.json'), 'json', 'mcpServers', 'project'));
160
+ // Continue.dev project-local
161
+ results.push(loc('continue', 'Continue.dev', join(cwd, '.continue', 'config.json'), 'json', 'mcpServers', 'project'));
162
+ // OpenCode project-local
163
+ results.push(loc('opencode', 'OpenCode', join(cwd, 'opencode.json'), 'json', 'mcp', 'project'));
164
+ // Codex project-local
165
+ results.push(loc('codex', 'Codex CLI', join(cwd, '.codex', 'config.toml'), 'toml', '[mcp_servers.*]', 'project'));
166
+ }
167
+ return results;
168
+ }
169
+ //# sourceMappingURL=registry.js.map