mcpick 0.0.17 → 0.0.19

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 (75) hide show
  1. package/.vscode/settings.json +5 -0
  2. package/CHANGELOG.md +15 -0
  3. package/dist/add-B9nVyh8T.js +113 -0
  4. package/dist/add-json-CXNDl3al.js +58 -0
  5. package/dist/atomic-write-BqEykHp9.js +26 -0
  6. package/dist/backup-DSDhHI5f.js +64 -0
  7. package/dist/cache-D6kd7qE8.js +226 -0
  8. package/dist/claude-cli-BeA-bmoW.js +394 -0
  9. package/dist/cli-DNNZjJYL.js +84 -0
  10. package/dist/clone-DLFLewBY.js +88 -0
  11. package/dist/config-DijVdEFn.js +176 -0
  12. package/dist/dev-DRJRNp7y.js +265 -0
  13. package/dist/disable-BA8tXPJN.js +39 -0
  14. package/dist/enable-Bdnnn_Cq.js +40 -0
  15. package/dist/get-BPjMXTMc.js +41 -0
  16. package/dist/hook-state-Di8lUsPr.js +171 -0
  17. package/dist/hooks-Bmn7pUZa.js +280 -0
  18. package/dist/index.js +1230 -303
  19. package/dist/list-B8YeDWt6.js +64 -0
  20. package/dist/marketplace-Br89Tg-Z.js +168 -0
  21. package/dist/output-BchYq0mR.js +15 -0
  22. package/dist/paths-BPISiJi4.js +124 -0
  23. package/dist/plugin-cache-Bby9Dxm9.js +405 -0
  24. package/dist/plugins-DHYJF5CP.js +212 -0
  25. package/dist/profile-CX97sMGp.js +120 -0
  26. package/dist/profile-DkY_lBEm.js +70 -0
  27. package/dist/redact-O35tjnRD.js +26 -0
  28. package/dist/registry-CfUKT7_C.js +92 -0
  29. package/dist/reload-CYDhkCVZ.js +31 -0
  30. package/dist/remove-DIPWYMpk.js +31 -0
  31. package/dist/reset-project-choices-DRM5KByw.js +28 -0
  32. package/dist/restore-DdMfUljI.js +84 -0
  33. package/dist/rolldown-runtime-CiIaOW0V.js +13 -0
  34. package/dist/settings-DEcWtzLE.js +201 -0
  35. package/dist/validation-xMlbgGCF.js +44 -0
  36. package/package.json +20 -19
  37. package/dist/cli/commands/add-json.js +0 -60
  38. package/dist/cli/commands/add.js +0 -135
  39. package/dist/cli/commands/backup.js +0 -83
  40. package/dist/cli/commands/cache.js +0 -296
  41. package/dist/cli/commands/dev.js +0 -161
  42. package/dist/cli/commands/disable.js +0 -36
  43. package/dist/cli/commands/enable.js +0 -39
  44. package/dist/cli/commands/get.js +0 -45
  45. package/dist/cli/commands/hooks.js +0 -314
  46. package/dist/cli/commands/list.js +0 -63
  47. package/dist/cli/commands/marketplace.js +0 -211
  48. package/dist/cli/commands/plugins.js +0 -265
  49. package/dist/cli/commands/profile.js +0 -134
  50. package/dist/cli/commands/reload.js +0 -36
  51. package/dist/cli/commands/remove.js +0 -35
  52. package/dist/cli/commands/reset-project-choices.js +0 -32
  53. package/dist/cli/commands/restore.js +0 -105
  54. package/dist/cli/index.js +0 -28
  55. package/dist/cli/output.js +0 -21
  56. package/dist/commands/add-server.js +0 -310
  57. package/dist/commands/backup.js +0 -60
  58. package/dist/commands/edit-config.js +0 -109
  59. package/dist/commands/edit-plugins.js +0 -201
  60. package/dist/commands/manage-cache.js +0 -155
  61. package/dist/commands/manage-hooks.js +0 -99
  62. package/dist/commands/manage-marketplace.js +0 -293
  63. package/dist/commands/restore.js +0 -118
  64. package/dist/core/config.js +0 -146
  65. package/dist/core/dev-override.js +0 -210
  66. package/dist/core/hook-state.js +0 -220
  67. package/dist/core/plugin-cache.js +0 -506
  68. package/dist/core/profile.js +0 -94
  69. package/dist/core/registry.js +0 -121
  70. package/dist/core/settings.js +0 -243
  71. package/dist/core/validation.js +0 -49
  72. package/dist/types.js +0 -2
  73. package/dist/utils/atomic-write.js +0 -27
  74. package/dist/utils/claude-cli.js +0 -483
  75. package/dist/utils/paths.js +0 -114
@@ -0,0 +1,394 @@
1
+ import { exec } from "node:child_process";
2
+ import { promisify } from "node:util";
3
+ //#region src/utils/claude-cli.ts
4
+ const execAsync = promisify(exec);
5
+ /**
6
+ * Check if Claude CLI is available
7
+ */
8
+ async function check_claude_cli() {
9
+ try {
10
+ await execAsync("claude --version");
11
+ return true;
12
+ } catch {
13
+ return false;
14
+ }
15
+ }
16
+ /**
17
+ * Escape a string for shell usage
18
+ */
19
+ function shell_escape(str) {
20
+ return `'${str.replace(/'/g, "'\\''")}'`;
21
+ }
22
+ /**
23
+ * Validate environment variable key
24
+ * Must start with letter or underscore, contain only alphanumeric and underscores
25
+ */
26
+ function is_valid_env_key(key) {
27
+ return /^[A-Za-z_][A-Za-z0-9_]*$/.test(key);
28
+ }
29
+ /**
30
+ * Build the claude mcp add command for a server
31
+ */
32
+ function build_add_command(server, scope) {
33
+ const parts = [
34
+ "claude",
35
+ "mcp",
36
+ "add"
37
+ ];
38
+ parts.push(shell_escape(server.name));
39
+ const transport = server.type || "stdio";
40
+ if (transport !== "stdio") parts.push("--transport", transport);
41
+ parts.push("--scope", scope);
42
+ if (transport === "stdio") {
43
+ if (server.env) {
44
+ for (const [key, value] of Object.entries(server.env)) if (is_valid_env_key(key)) parts.push("-e", `${key}=${shell_escape(value)}`);
45
+ }
46
+ if ("command" in server && server.command) {
47
+ parts.push("--");
48
+ parts.push(shell_escape(server.command));
49
+ if (server.args && server.args.length > 0) parts.push(...server.args.map((arg) => shell_escape(arg)));
50
+ }
51
+ } else {
52
+ if ("url" in server && server.url) parts.push(shell_escape(server.url));
53
+ if ("headers" in server && server.headers) for (const [key, value] of Object.entries(server.headers)) parts.push("-H", shell_escape(`${key}: ${value}`));
54
+ }
55
+ return parts.join(" ");
56
+ }
57
+ /**
58
+ * Add an MCP server using Claude CLI
59
+ */
60
+ async function add_mcp_via_cli(server, scope) {
61
+ if (!await check_claude_cli()) return {
62
+ success: false,
63
+ error: "Claude CLI not found. Please install Claude Code CLI."
64
+ };
65
+ const command = build_add_command(server, scope);
66
+ try {
67
+ await execAsync(command);
68
+ return { success: true };
69
+ } catch (error) {
70
+ return {
71
+ success: false,
72
+ error: `Failed to add server via CLI: ${error instanceof Error ? error.message : "Unknown error"}`
73
+ };
74
+ }
75
+ }
76
+ /**
77
+ * Remove an MCP server using Claude CLI
78
+ */
79
+ async function remove_mcp_via_cli(name) {
80
+ if (!await check_claude_cli()) return {
81
+ success: false,
82
+ error: "Claude CLI not found. Please install Claude Code CLI."
83
+ };
84
+ try {
85
+ await execAsync(`claude mcp remove ${shell_escape(name)}`);
86
+ return { success: true };
87
+ } catch (error) {
88
+ return {
89
+ success: false,
90
+ error: `Failed to remove server via CLI: ${error instanceof Error ? error.message : "Unknown error"}`
91
+ };
92
+ }
93
+ }
94
+ /**
95
+ * Install a plugin via Claude CLI
96
+ */
97
+ async function install_plugin_via_cli(key, scope = "user") {
98
+ if (!await check_claude_cli()) return {
99
+ success: false,
100
+ error: "Claude CLI not found. Please install Claude Code CLI."
101
+ };
102
+ try {
103
+ await execAsync(`claude plugin install ${shell_escape(key)} --scope ${scope}`);
104
+ return { success: true };
105
+ } catch (error) {
106
+ return {
107
+ success: false,
108
+ error: `Failed to install plugin: ${error instanceof Error ? error.message : "Unknown error"}`
109
+ };
110
+ }
111
+ }
112
+ /**
113
+ * Uninstall a plugin via Claude CLI
114
+ */
115
+ async function uninstall_plugin_via_cli(key, scope = "user") {
116
+ if (!await check_claude_cli()) return {
117
+ success: false,
118
+ error: "Claude CLI not found. Please install Claude Code CLI."
119
+ };
120
+ try {
121
+ await execAsync(`claude plugin uninstall ${shell_escape(key)} --scope ${scope}`);
122
+ return { success: true };
123
+ } catch (error) {
124
+ return {
125
+ success: false,
126
+ error: `Failed to uninstall plugin: ${error instanceof Error ? error.message : "Unknown error"}`
127
+ };
128
+ }
129
+ }
130
+ /**
131
+ * Update a plugin via Claude CLI
132
+ */
133
+ async function update_plugin_via_cli(key, scope = "user") {
134
+ if (!await check_claude_cli()) return {
135
+ success: false,
136
+ error: "Claude CLI not found. Please install Claude Code CLI."
137
+ };
138
+ try {
139
+ await execAsync(`claude plugin update ${shell_escape(key)} --scope ${scope}`);
140
+ return { success: true };
141
+ } catch (error) {
142
+ return {
143
+ success: false,
144
+ error: `Failed to update plugin: ${error instanceof Error ? error.message : "Unknown error"}`
145
+ };
146
+ }
147
+ }
148
+ /**
149
+ * Add a marketplace via Claude CLI
150
+ */
151
+ /**
152
+ * Extract GitHub owner/repo from various source formats.
153
+ * Returns null if not a recognizable GitHub reference.
154
+ */
155
+ function parse_github_repo(source) {
156
+ const https_match = source.match(/^https?:\/\/github\.com\/([^/]+)\/([^/.]+)(?:\.git)?$/);
157
+ if (https_match) return {
158
+ owner: https_match[1],
159
+ repo: https_match[2]
160
+ };
161
+ const ssh_match = source.match(/^git@github\.com:([^/]+)\/([^/.]+)(?:\.git)?$/);
162
+ if (ssh_match) return {
163
+ owner: ssh_match[1],
164
+ repo: ssh_match[2]
165
+ };
166
+ const shorthand_match = source.match(/^([^/\s]+)\/([^/\s]+)$/);
167
+ if (shorthand_match) return {
168
+ owner: shorthand_match[1],
169
+ repo: shorthand_match[2]
170
+ };
171
+ return null;
172
+ }
173
+ /**
174
+ * Validate that a GitHub repository exists and is accessible.
175
+ * Returns an error message if validation fails, null if OK.
176
+ */
177
+ async function validate_github_repo(owner, repo) {
178
+ try {
179
+ const response = await fetch(`https://api.github.com/repos/${owner}/${repo}`, {
180
+ method: "GET",
181
+ headers: { Accept: "application/vnd.github.v3+json" }
182
+ });
183
+ if (response.status === 200) return null;
184
+ if (response.status === 404) return `Repository '${owner}/${repo}' not found on GitHub. Check the name or ensure it's not private.`;
185
+ if (response.status === 403) return `Access denied for '${owner}/${repo}'. The repository may be private — configure a GitHub token or use SSH.`;
186
+ return `GitHub API returned status ${response.status} for '${owner}/${repo}'.`;
187
+ } catch {
188
+ return null;
189
+ }
190
+ }
191
+ async function marketplace_add_via_cli(source) {
192
+ if (!await check_claude_cli()) return {
193
+ success: false,
194
+ error: "Claude CLI not found. Please install Claude Code CLI."
195
+ };
196
+ const gh = parse_github_repo(source);
197
+ const is_shorthand = gh && !source.startsWith("http") && !source.startsWith("git@");
198
+ if (gh && is_shorthand) {
199
+ const validation_error = await validate_github_repo(gh.owner, gh.repo);
200
+ if (validation_error) return {
201
+ success: false,
202
+ error: validation_error
203
+ };
204
+ }
205
+ try {
206
+ await execAsync(`claude plugin marketplace add ${shell_escape(source)}`);
207
+ return { success: true };
208
+ } catch (error) {
209
+ const message = error instanceof Error ? error.message : "Unknown error";
210
+ if (message.includes("SSH") || message.includes("Permission denied (publickey)")) return {
211
+ success: false,
212
+ error: `SSH authentication failed for '${source}'. Either:\n - Configure SSH keys: https://docs.github.com/en/authentication/connecting-to-github-with-ssh\n - Use HTTPS URL instead: https://github.com/${gh ? `${gh.owner}/${gh.repo}` : source}`
213
+ };
214
+ if (message.includes("not found") || message.includes("does not exist")) return {
215
+ success: false,
216
+ error: `Repository '${source}' not found. Check the name and your access permissions.`
217
+ };
218
+ return {
219
+ success: false,
220
+ error: `Failed to add marketplace: ${message}`
221
+ };
222
+ }
223
+ }
224
+ /**
225
+ * Remove a marketplace via Claude CLI
226
+ */
227
+ async function marketplace_remove_via_cli(name) {
228
+ if (!await check_claude_cli()) return {
229
+ success: false,
230
+ error: "Claude CLI not found. Please install Claude Code CLI."
231
+ };
232
+ try {
233
+ await execAsync(`claude plugin marketplace remove ${shell_escape(name)}`);
234
+ return { success: true };
235
+ } catch (error) {
236
+ return {
237
+ success: false,
238
+ error: `Failed to remove marketplace: ${error instanceof Error ? error.message : "Unknown error"}`
239
+ };
240
+ }
241
+ }
242
+ /**
243
+ * Update marketplace(s) via Claude CLI
244
+ */
245
+ async function marketplace_update_via_cli(name) {
246
+ if (!await check_claude_cli()) return {
247
+ success: false,
248
+ error: "Claude CLI not found. Please install Claude Code CLI."
249
+ };
250
+ try {
251
+ await execAsync(name ? `claude plugin marketplace update ${shell_escape(name)}` : "claude plugin marketplace update");
252
+ return { success: true };
253
+ } catch (error) {
254
+ return {
255
+ success: false,
256
+ error: `Failed to update marketplace: ${error instanceof Error ? error.message : "Unknown error"}`
257
+ };
258
+ }
259
+ }
260
+ /**
261
+ * List marketplaces via Claude CLI
262
+ */
263
+ async function marketplace_list_via_cli() {
264
+ if (!await check_claude_cli()) return {
265
+ success: false,
266
+ error: "Claude CLI not found. Please install Claude Code CLI."
267
+ };
268
+ try {
269
+ const { stdout } = await execAsync("claude plugin marketplace list");
270
+ return {
271
+ success: true,
272
+ stdout: stdout.trim()
273
+ };
274
+ } catch (error) {
275
+ return {
276
+ success: false,
277
+ error: `Failed to list marketplaces: ${error instanceof Error ? error.message : "Unknown error"}`
278
+ };
279
+ }
280
+ }
281
+ /**
282
+ * Get the scope description for display
283
+ */
284
+ function get_scope_description(scope) {
285
+ switch (scope) {
286
+ case "local": return "This project only (default)";
287
+ case "project": return "Shared via .mcp.json (version controlled)";
288
+ case "user": return "Global - all projects";
289
+ }
290
+ }
291
+ /**
292
+ * Validate a plugin or marketplace manifest via Claude CLI
293
+ */
294
+ async function validate_plugin_via_cli(path) {
295
+ if (!await check_claude_cli()) return {
296
+ success: false,
297
+ error: "Claude CLI not found. Please install Claude Code CLI."
298
+ };
299
+ try {
300
+ const { stdout } = await execAsync(`claude plugin validate ${shell_escape(path)}`);
301
+ return {
302
+ success: true,
303
+ stdout: stdout.trim()
304
+ };
305
+ } catch (error) {
306
+ return {
307
+ success: false,
308
+ error: `Validation failed: ${error instanceof Error ? error.message : "Unknown error"}`
309
+ };
310
+ }
311
+ }
312
+ /**
313
+ * Get details about an MCP server via Claude CLI
314
+ */
315
+ async function mcp_get_via_cli(name) {
316
+ if (!await check_claude_cli()) return {
317
+ success: false,
318
+ error: "Claude CLI not found. Please install Claude Code CLI."
319
+ };
320
+ try {
321
+ const { stdout } = await execAsync(`claude mcp get ${shell_escape(name)}`);
322
+ return {
323
+ success: true,
324
+ stdout: stdout.trim()
325
+ };
326
+ } catch (error) {
327
+ return {
328
+ success: false,
329
+ error: `Failed to get server details: ${error instanceof Error ? error.message : "Unknown error"}`
330
+ };
331
+ }
332
+ }
333
+ /**
334
+ * Add an MCP server from raw JSON via Claude CLI
335
+ */
336
+ async function mcp_add_json_via_cli(name, json, scope = "local") {
337
+ if (!await check_claude_cli()) return {
338
+ success: false,
339
+ error: "Claude CLI not found. Please install Claude Code CLI."
340
+ };
341
+ try {
342
+ await execAsync(`claude mcp add-json ${shell_escape(name)} ${shell_escape(json)} --scope ${scope}`);
343
+ return { success: true };
344
+ } catch (error) {
345
+ return {
346
+ success: false,
347
+ error: `Failed to add server from JSON: ${error instanceof Error ? error.message : "Unknown error"}`
348
+ };
349
+ }
350
+ }
351
+ /**
352
+ * Reset project-scoped MCP server choices via Claude CLI
353
+ */
354
+ async function mcp_reset_project_choices_via_cli() {
355
+ if (!await check_claude_cli()) return {
356
+ success: false,
357
+ error: "Claude CLI not found. Please install Claude Code CLI."
358
+ };
359
+ try {
360
+ await execAsync("claude mcp reset-project-choices");
361
+ return { success: true };
362
+ } catch (error) {
363
+ return {
364
+ success: false,
365
+ error: `Failed to reset project choices: ${error instanceof Error ? error.message : "Unknown error"}`
366
+ };
367
+ }
368
+ }
369
+ /**
370
+ * Get scope options for select prompt
371
+ */
372
+ function get_scope_options() {
373
+ return [
374
+ {
375
+ value: "local",
376
+ label: "Local",
377
+ hint: "This project only (default)"
378
+ },
379
+ {
380
+ value: "project",
381
+ label: "Project",
382
+ hint: "Shared via .mcp.json (git)"
383
+ },
384
+ {
385
+ value: "user",
386
+ label: "User (Global)",
387
+ hint: "Available in all projects"
388
+ }
389
+ ];
390
+ }
391
+ //#endregion
392
+ export { install_plugin_via_cli as a, marketplace_remove_via_cli as c, mcp_get_via_cli as d, mcp_reset_project_choices_via_cli as f, validate_plugin_via_cli as g, update_plugin_via_cli as h, get_scope_options as i, marketplace_update_via_cli as l, uninstall_plugin_via_cli as m, check_claude_cli as n, marketplace_add_via_cli as o, remove_mcp_via_cli as p, get_scope_description as r, marketplace_list_via_cli as s, add_mcp_via_cli as t, mcp_add_json_via_cli as u };
393
+
394
+ //# sourceMappingURL=claude-cli-BeA-bmoW.js.map
@@ -0,0 +1,84 @@
1
+ import { defineCommand, renderUsage, runMain } from "citty";
2
+ //#region src/cli/index.ts
3
+ const main = defineCommand({
4
+ meta: {
5
+ name: "mcpick",
6
+ description: "Claude Code extension manager — MCP servers, plugins (skills, hooks, agents), and marketplaces"
7
+ },
8
+ subCommands: {
9
+ list: () => import("./list-B8YeDWt6.js").then((m) => m.default),
10
+ enable: () => import("./enable-Bdnnn_Cq.js").then((m) => m.default),
11
+ disable: () => import("./disable-BA8tXPJN.js").then((m) => m.default),
12
+ remove: () => import("./remove-DIPWYMpk.js").then((m) => m.default),
13
+ add: () => import("./add-B9nVyh8T.js").then((m) => m.default),
14
+ "add-json": () => import("./add-json-CXNDl3al.js").then((m) => m.default),
15
+ clone: () => import("./clone-DLFLewBY.js").then((m) => m.default),
16
+ get: () => import("./get-BPjMXTMc.js").then((m) => m.default),
17
+ "reset-project-choices": () => import("./reset-project-choices-DRM5KByw.js").then((m) => m.default),
18
+ backup: () => import("./backup-DSDhHI5f.js").then((m) => m.default),
19
+ restore: () => import("./restore-DdMfUljI.js").then((m) => m.default),
20
+ profile: () => import("./profile-CX97sMGp.js").then((m) => m.default),
21
+ plugins: () => import("./plugins-DHYJF5CP.js").then((m) => m.default),
22
+ hooks: () => import("./hooks-Bmn7pUZa.js").then((m) => m.default),
23
+ cache: () => import("./cache-D6kd7qE8.js").then((m) => m.default),
24
+ dev: () => import("./dev-DRJRNp7y.js").then((m) => m.default),
25
+ marketplace: () => import("./marketplace-Br89Tg-Z.js").then((m) => m.default),
26
+ reload: () => import("./reload-CYDhkCVZ.js").then((m) => m.default)
27
+ }
28
+ });
29
+ /**
30
+ * Custom help renderer that appends workflow guidance and examples
31
+ * after citty's standard help output. This is critical for LLM agents
32
+ * that rely on --help output to understand multi-step workflows.
33
+ */
34
+ async function show_usage_with_examples(cmd, parent) {
35
+ const base = await renderUsage(cmd, parent);
36
+ if ((await (typeof cmd.meta === "function" ? cmd.meta() : cmd.meta))?.name === "mcpick") console.log(base + "\n" + WORKFLOW_SECTION + "\n" + CONCEPTS_SECTION + "\n" + EXAMPLES_SECTION + "\n");
37
+ else console.log(base + "\n");
38
+ }
39
+ const WORKFLOW_SECTION = `
40
+ \x1b[4m\x1b[1mWORKFLOW\x1b[22m\x1b[24m Marketplaces contain plugins. Plugins contain skills (/slash-commands), hooks, agents, and MCP servers.
41
+
42
+ To install skills from a marketplace, follow these steps:
43
+
44
+ 1. Add a marketplace: mcpick marketplace add <source>
45
+ 2. Install a plugin: mcpick plugins install <name>@<marketplace>
46
+ 3. Skills are now available as /slash-commands in Claude Code`;
47
+ const CONCEPTS_SECTION = `
48
+ \x1b[4m\x1b[1mCONCEPTS\x1b[22m\x1b[24m
49
+
50
+ Marketplace A catalog of plugins, hosted on GitHub, GitLab, or locally
51
+ Plugin A bundle containing any mix of: skills, hooks, agents, MCP servers
52
+ Skill A SKILL.md file that extends Claude's behaviour, invocable as /slash-command
53
+ MCP server A tool server providing external capabilities to Claude Code
54
+ Hook An event handler that runs on tool use, session start, etc.
55
+ Profile A saved snapshot of your MCP server and plugin configuration`;
56
+ const EXAMPLES_SECTION = `
57
+ \x1b[4m\x1b[1mEXAMPLES\x1b[22m\x1b[24m
58
+
59
+ Add a marketplace from GitHub (owner/repo):
60
+ mcpick marketplace add spences10/claude-code-toolkit
61
+
62
+ Add a marketplace from a full URL:
63
+ mcpick marketplace add https://github.com/spences10/claude-code-toolkit
64
+
65
+ Install a plugin from a marketplace:
66
+ mcpick plugins install my-plugin@claude-code-toolkit
67
+
68
+ List all installed plugins and their status:
69
+ mcpick plugins list
70
+
71
+ Toggle an MCP server on or off:
72
+ mcpick enable my-server
73
+ mcpick disable my-server
74
+
75
+ List all MCP servers:
76
+ mcpick list
77
+
78
+ All commands support --json for machine-readable output.
79
+ Run without arguments to launch the interactive TUI (not suitable for LLM agents).`;
80
+ const run = () => runMain(main, { showUsage: show_usage_with_examples });
81
+ //#endregion
82
+ export { run };
83
+
84
+ //# sourceMappingURL=cli-DNNZjJYL.js.map
@@ -0,0 +1,88 @@
1
+ import { n as validate_mcp_server } from "./validation-xMlbgGCF.js";
2
+ import { t as add_server_to_registry } from "./registry-CfUKT7_C.js";
3
+ import { t as add_mcp_via_cli } from "./claude-cli-BeA-bmoW.js";
4
+ import { i as find_server_in_scope, r as detect_server_scope } from "./config-DijVdEFn.js";
5
+ import { n as output, t as error } from "./output-BchYq0mR.js";
6
+ import { t as redact_server } from "./redact-O35tjnRD.js";
7
+ import { defineCommand } from "citty";
8
+ //#region src/cli/commands/clone.ts
9
+ var clone_default = defineCommand({
10
+ meta: {
11
+ name: "clone",
12
+ description: "Clone an existing MCP server config with a new name, optionally overriding command/args"
13
+ },
14
+ args: {
15
+ source: {
16
+ type: "positional",
17
+ description: "Source server name to clone from",
18
+ required: true
19
+ },
20
+ name: {
21
+ type: "positional",
22
+ description: "New server name",
23
+ required: true
24
+ },
25
+ command: {
26
+ type: "string",
27
+ description: "Override command (e.g. \"node\" for local dev)"
28
+ },
29
+ args: {
30
+ type: "string",
31
+ description: "Override comma-separated arguments"
32
+ },
33
+ scope: {
34
+ type: "string",
35
+ description: "Scope for new server (default: same as source)"
36
+ },
37
+ json: {
38
+ type: "boolean",
39
+ description: "Output as JSON",
40
+ default: false
41
+ }
42
+ },
43
+ async run({ args }) {
44
+ if (args.scope && ![
45
+ "local",
46
+ "project",
47
+ "user"
48
+ ].includes(args.scope)) error(`Invalid scope: ${args.scope}. Use local, project, or user.`);
49
+ const scope = args.scope;
50
+ let found;
51
+ if (scope) found = await find_server_in_scope(args.source, scope);
52
+ else found = await detect_server_scope(args.source);
53
+ if (!found) error(`Server '${args.source}' not found${scope ? ` in ${scope} scope` : " in any scope"}`);
54
+ const target_scope = args.scope || found.scope;
55
+ const cloned = {
56
+ ...found.server,
57
+ name: args.name
58
+ };
59
+ if (args.command) {
60
+ cloned.command = args.command;
61
+ delete cloned.url;
62
+ if (cloned.type === "sse" || cloned.type === "http") delete cloned.type;
63
+ }
64
+ if (args.args) cloned.args = args.args.split(",");
65
+ let server;
66
+ try {
67
+ server = validate_mcp_server(cloned);
68
+ } catch (err) {
69
+ error(`Invalid cloned config: ${err instanceof Error ? err.message : "validation failed"}`);
70
+ }
71
+ await add_server_to_registry(server);
72
+ const result = await add_mcp_via_cli(server, target_scope);
73
+ if (args.json) output({
74
+ cloned: server.name,
75
+ from: args.source,
76
+ scope: target_scope,
77
+ server: redact_server(server),
78
+ cli: result.success,
79
+ error: result.error
80
+ }, true);
81
+ else if (result.success) console.log(`Cloned '${args.source}' → '${server.name}' (scope: ${target_scope})`);
82
+ else console.log(`Cloned '${args.source}' → '${server.name}' to registry but CLI failed: ${result.error}`);
83
+ }
84
+ });
85
+ //#endregion
86
+ export { clone_default as default };
87
+
88
+ //# sourceMappingURL=clone-DLFLewBY.js.map