mcpick 0.0.22 → 0.0.24

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 (45) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +4 -0
  3. package/dist/add-Qzd8i-5k.js +184 -0
  4. package/dist/add-json-DGmsjB0O.js +115 -0
  5. package/dist/{backup-bdg6dvsb.js → backup-C7fvikFw.js} +5 -5
  6. package/dist/{cache-CSUcGdZP.js → cache-D3jjh5dD.js} +3 -3
  7. package/dist/{cli-avr5R1LO.js → cli-CZOlaqoZ.js} +22 -21
  8. package/dist/{clients-CSQgqHzb.js → clients-Bh93TGP4.js} +3 -3
  9. package/dist/{clone-CQ0skkT6.js → clone-MI8jJhTz.js} +6 -6
  10. package/dist/{config-BhX4eAgg.js → config-DE58Fik_.js} +4 -4
  11. package/dist/{dev-CTDg5g-c.js → dev-51esdZG9.js} +6 -6
  12. package/dist/disable-csYAn2Vk.js +106 -0
  13. package/dist/dry-run-XQ32fxPT.js +20 -0
  14. package/dist/enable-B5GbmhL-.js +107 -0
  15. package/dist/{get-l-eAJhBy.js → get-DacRZmwv.js} +3 -3
  16. package/dist/{hooks-BWZ_Kgx3.js → hooks-C_x49qap.js} +3 -4
  17. package/dist/index.js +717 -116
  18. package/dist/{list-By--kltj.js → list-BeBtsiae.js} +5 -5
  19. package/dist/{marketplace-DdiKDDKK.js → marketplace-BDC2YtvT.js} +4 -4
  20. package/dist/{output-BgN9Uuxf.js → output-HtT5HCof.js} +2 -2
  21. package/dist/{paths-6wrIM8yh.js → paths-BPISiJi4.js} +1 -1
  22. package/dist/{plugin-cache-DKcW8LGV.js → plugin-cache-DmLbh89d.js} +35 -16
  23. package/dist/{plugins-CsXE8AH4.js → plugins-Bkw-SKkZ.js} +4 -5
  24. package/dist/profile-DwJTVXiz.js +161 -0
  25. package/dist/{redact-Dltz2gde.js → redact-wBMtzbno.js} +1 -1
  26. package/dist/{reload-C29-vuvy.js → reload-Bl1mYK1I.js} +2 -2
  27. package/dist/remove-BSHgva79.js +107 -0
  28. package/dist/{reset-project-choices-Dhh4CxIC.js → reset-project-choices-BNLus9J9.js} +3 -3
  29. package/dist/{restore-BI8aiszM.js → restore-YisgARhc.js} +5 -6
  30. package/dist/rollback-GR1RkpXW.js +55 -0
  31. package/dist/{skills-DPBDmION.js → skills-rDTDqqZA.js} +3 -3
  32. package/dist/{validation-qWlF51fw.js → validation-xMlbgGCF.js} +1 -1
  33. package/package.json +4 -4
  34. package/.github/copilot-instructions.md +0 -50
  35. package/.github/workflows/ci.yml +0 -26
  36. package/.vscode/settings.json +0 -5
  37. package/CONTEXT.md +0 -49
  38. package/dist/add-Bok0qbXi.js +0 -112
  39. package/dist/add-json-C44vy2A_.js +0 -58
  40. package/dist/atomic-write-4lANmzsO.js +0 -26
  41. package/dist/disable-DLlOj7sc.js +0 -38
  42. package/dist/enable-CGFYYC2A.js +0 -39
  43. package/dist/profile-DzGPsdsl.js +0 -120
  44. package/dist/remove-B5q4rQRU.js +0 -30
  45. package/dist/settings-CZR8bVfh.js +0 -201
@@ -1,7 +1,7 @@
1
- import { o as get_enabled_servers_for_scope } from "./config-BhX4eAgg.js";
2
- import { a as redact_url, n as redact_server, t as redact_portable_server } from "./redact-Dltz2gde.js";
3
- import { A as get_client_adapter, T as get_all_available_servers } from "./index.js";
4
- import { n as output, t as error } from "./output-BgN9Uuxf.js";
1
+ import { o as get_enabled_servers_for_scope } from "./config-DE58Fik_.js";
2
+ import { a as redact_url, n as redact_server, t as redact_portable_server } from "./redact-wBMtzbno.js";
3
+ import { I as get_client_adapter, k as get_all_available_servers } from "./index.js";
4
+ import { n as output, t as error } from "./output-HtT5HCof.js";
5
5
  import { defineCommand } from "citty";
6
6
  //#region src/cli/commands/list.ts
7
7
  var list_default = defineCommand({
@@ -97,4 +97,4 @@ async function list_client_servers(client, scope, json) {
97
97
  //#endregion
98
98
  export { list_default as default };
99
99
 
100
- //# sourceMappingURL=list-By--kltj.js.map
100
+ //# sourceMappingURL=list-BeBtsiae.js.map
@@ -1,6 +1,6 @@
1
- import { u as read_marketplace_manifest } from "./plugin-cache-DKcW8LGV.js";
2
- import { g as marketplace_update_via_cli, h as marketplace_remove_via_cli, m as marketplace_list_via_cli, o as check_restored_hooks, p as marketplace_add_via_cli, u as redisable_restored_hooks } from "./index.js";
3
- import { n as output, t as error } from "./output-BgN9Uuxf.js";
1
+ import { u as read_marketplace_manifest } from "./plugin-cache-DmLbh89d.js";
2
+ import { _ as marketplace_add_via_cli, b as marketplace_update_via_cli, d as redisable_restored_hooks, s as check_restored_hooks, v as marketplace_list_via_cli, y as marketplace_remove_via_cli } from "./index.js";
3
+ import { n as output, t as error } from "./output-HtT5HCof.js";
4
4
  import { defineCommand } from "citty";
5
5
  //#region src/cli/commands/marketplace.ts
6
6
  const list = defineCommand({
@@ -164,4 +164,4 @@ var marketplace_default = defineCommand({
164
164
  //#endregion
165
165
  export { marketplace_default as default };
166
166
 
167
- //# sourceMappingURL=marketplace-DdiKDDKK.js.map
167
+ //# sourceMappingURL=marketplace-BDC2YtvT.js.map
@@ -1,4 +1,4 @@
1
- import { i as redact_text, o as redact_value } from "./redact-Dltz2gde.js";
1
+ import { i as redact_text, o as redact_value } from "./redact-wBMtzbno.js";
2
2
  //#region src/cli/output.ts
3
3
  function output(data, json) {
4
4
  const safe_data = redact_value(data);
@@ -14,4 +14,4 @@ function error(message) {
14
14
  //#endregion
15
15
  export { output as n, error as t };
16
16
 
17
- //# sourceMappingURL=output-BgN9Uuxf.js.map
17
+ //# sourceMappingURL=output-HtT5HCof.js.map
@@ -121,4 +121,4 @@ function get_marketplace_manifest_path(name) {
121
121
  //#endregion
122
122
  export { get_profiles_dir as _, get_claude_settings_path as a, paths_exports as b, get_disabled_hooks_path as c, get_marketplace_manifest_path as d, get_marketplaces_dir as f, get_profile_path as g, get_plugin_cache_dir as h, get_claude_config_path as i, get_installed_plugins_path as l, get_plugin_backup_filename as m, get_backup_filename as n, get_current_project_path as o, get_mcpick_dir as p, get_backups_dir as r, get_dev_overrides_path as s, ensure_directory_exists as t, get_known_marketplaces_path as u, get_project_mcp_json_path as v, get_server_registry_path as y };
123
123
 
124
- //# sourceMappingURL=paths-6wrIM8yh.js.map
124
+ //# sourceMappingURL=paths-BPISiJi4.js.map
@@ -1,9 +1,9 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-CiIaOW0V.js";
2
- import { t as atomic_json_write } from "./atomic-write-4lANmzsO.js";
3
- import { d as get_marketplace_manifest_path, h as get_plugin_cache_dir, l as get_installed_plugins_path, t as ensure_directory_exists, u as get_known_marketplaces_path } from "./paths-6wrIM8yh.js";
2
+ import { d as get_marketplace_manifest_path, h as get_plugin_cache_dir, l as get_installed_plugins_path, t as ensure_directory_exists, u as get_known_marketplaces_path } from "./paths-BPISiJi4.js";
3
+ import { et as atomic_json_write } from "./index.js";
4
4
  import { lstat, readFile, readdir, readlink, rename, rm, symlink } from "node:fs/promises";
5
5
  import { join, resolve } from "node:path";
6
- import { exec } from "node:child_process";
6
+ import { execFile } from "node:child_process";
7
7
  import { promisify } from "node:util";
8
8
  //#region src/core/plugin-cache.ts
9
9
  var plugin_cache_exports = /* @__PURE__ */ __exportAll({
@@ -22,7 +22,14 @@ var plugin_cache_exports = /* @__PURE__ */ __exportAll({
22
22
  unlink_local_plugin: () => unlink_local_plugin,
23
23
  write_installed_plugins: () => write_installed_plugins
24
24
  });
25
- const execAsync = promisify(exec);
25
+ const execFileAsync = promisify(execFile);
26
+ function git(dir, args, timeout) {
27
+ return execFileAsync("git", [
28
+ "-C",
29
+ dir,
30
+ ...args
31
+ ], { timeout });
32
+ }
26
33
  const EMPTY_INSTALLED = {
27
34
  version: 2,
28
35
  plugins: {}
@@ -59,8 +66,8 @@ async function read_marketplace_manifest(name) {
59
66
  }
60
67
  async function get_marketplace_head_sha(marketplace_path) {
61
68
  try {
62
- const { stdout } = await execAsync(`git -C ${JSON.stringify(marketplace_path)} rev-parse HEAD`, { timeout: 1e4 });
63
- return stdout.trim() || null;
69
+ const { stdout } = await git(marketplace_path, ["rev-parse", "HEAD"], 1e4);
70
+ return String(stdout).trim() || null;
64
71
  } catch {
65
72
  return null;
66
73
  }
@@ -70,25 +77,37 @@ async function get_marketplace_head_sha(marketplace_path) {
70
77
  * Resets the fetch refspec, fetches all branches, and checks out the default branch.
71
78
  */
72
79
  async function recover_deleted_branch(dir) {
73
- const q = JSON.stringify(dir);
74
80
  try {
75
- await execAsync(`git -C ${q} remote set-branches origin '*'`, { timeout: 1e4 });
76
- await execAsync(`git -C ${q} fetch origin`, { timeout: 3e4 });
81
+ await git(dir, [
82
+ "remote",
83
+ "set-branches",
84
+ "origin",
85
+ "*"
86
+ ], 1e4);
87
+ await git(dir, ["fetch", "origin"], 3e4);
77
88
  let default_branch = "main";
78
89
  try {
79
- const { stdout } = await execAsync(`git -C ${q} symbolic-ref refs/remotes/origin/HEAD`, { timeout: 5e3 });
80
- const match = stdout.trim().match(/refs\/remotes\/origin\/(.+)/);
90
+ const { stdout } = await git(dir, ["symbolic-ref", "refs/remotes/origin/HEAD"], 5e3);
91
+ const match = String(stdout).trim().match(/refs\/remotes\/origin\/(.+)/);
81
92
  if (match) default_branch = match[1];
82
93
  } catch {
83
94
  try {
84
- await execAsync(`git -C ${q} rev-parse --verify origin/main`, { timeout: 5e3 });
95
+ await git(dir, [
96
+ "rev-parse",
97
+ "--verify",
98
+ "origin/main"
99
+ ], 5e3);
85
100
  default_branch = "main";
86
101
  } catch {
87
102
  default_branch = "master";
88
103
  }
89
104
  }
90
- await execAsync(`git -C ${q} checkout ${default_branch}`, { timeout: 1e4 });
91
- await execAsync(`git -C ${q} reset --hard origin/${default_branch}`, { timeout: 1e4 });
105
+ await git(dir, ["checkout", default_branch], 1e4);
106
+ await git(dir, [
107
+ "reset",
108
+ "--hard",
109
+ `origin/${default_branch}`
110
+ ], 1e4);
92
111
  return { recovered: true };
93
112
  } catch (err) {
94
113
  return {
@@ -100,7 +119,7 @@ async function recover_deleted_branch(dir) {
100
119
  async function refresh_marketplace(name, marketplace) {
101
120
  const dir = marketplace.installLocation;
102
121
  try {
103
- await execAsync(`git -C ${JSON.stringify(dir)} pull --ff-only`, { timeout: 3e4 });
122
+ await git(dir, ["pull", "--ff-only"], 3e4);
104
123
  return { success: true };
105
124
  } catch {
106
125
  const recovery = await recover_deleted_branch(dir);
@@ -402,4 +421,4 @@ async function list_linked_plugins() {
402
421
  //#endregion
403
422
  export { list_linked_plugins as a, read_installed_plugins as c, refresh_all_marketplaces as d, scan_all_cache_keys as f, link_local_plugin as i, read_known_marketplaces as l, clear_plugin_caches as n, parse_plugin_key as o, unlink_local_plugin as p, get_cached_plugins_info as r, plugin_cache_exports as s, clean_orphaned_versions as t, read_marketplace_manifest as u };
404
423
 
405
- //# sourceMappingURL=plugin-cache-DKcW8LGV.js.map
424
+ //# sourceMappingURL=plugin-cache-DmLbh89d.js.map
@@ -1,7 +1,6 @@
1
- import { a as read_claude_settings, i as get_all_plugins, n as build_enabled_plugins, s as write_claude_settings } from "./settings-CZR8bVfh.js";
2
- import { l as read_known_marketplaces, o as parse_plugin_key } from "./plugin-cache-DKcW8LGV.js";
3
- import { C as validate_plugin_via_cli, S as update_plugin_via_cli, f as install_plugin_via_cli, x as uninstall_plugin_via_cli } from "./index.js";
4
- import { n as output, t as error } from "./output-BgN9Uuxf.js";
1
+ import { l as read_known_marketplaces, o as parse_plugin_key } from "./plugin-cache-DmLbh89d.js";
2
+ import { $ as write_claude_settings, D as validate_plugin_via_cli, E as update_plugin_via_cli, J as build_enabled_plugins, T as uninstall_plugin_via_cli, X as get_all_plugins, Z as read_claude_settings, g as install_plugin_via_cli } from "./index.js";
3
+ import { n as output, t as error } from "./output-HtT5HCof.js";
5
4
  import { defineCommand } from "citty";
6
5
  var plugins_default = defineCommand({
7
6
  meta: {
@@ -209,4 +208,4 @@ var plugins_default = defineCommand({
209
208
  //#endregion
210
209
  export { plugins_default as default };
211
210
 
212
- //# sourceMappingURL=plugins-CsXE8AH4.js.map
211
+ //# sourceMappingURL=plugins-Bkw-SKkZ.js.map
@@ -0,0 +1,161 @@
1
+ import { a as get_claude_settings_path, g as get_profile_path, i as get_claude_config_path } from "./paths-BPISiJi4.js";
2
+ import { s as read_claude_config } from "./config-DE58Fik_.js";
3
+ import { K as build_json_change_preview, Z as read_claude_settings, i as save_current_claude_profile, n as list_profiles, r as load_profile, t as apply_profile_to_claude } from "./index.js";
4
+ import { n as output, t as error } from "./output-HtT5HCof.js";
5
+ import { t as print_dry_run } from "./dry-run-XQ32fxPT.js";
6
+ import { defineCommand } from "citty";
7
+ var profile_default = defineCommand({
8
+ meta: {
9
+ name: "profile",
10
+ description: "Manage profiles (MCP servers + plugins)"
11
+ },
12
+ subCommands: {
13
+ list: defineCommand({
14
+ meta: {
15
+ name: "list",
16
+ description: "List all saved profiles"
17
+ },
18
+ args: { json: {
19
+ type: "boolean",
20
+ description: "Output as JSON",
21
+ default: false
22
+ } },
23
+ async run({ args }) {
24
+ const profiles = await list_profiles();
25
+ if (args.json) output(profiles, true);
26
+ else {
27
+ if (profiles.length === 0) {
28
+ console.log("No profiles found.");
29
+ return;
30
+ }
31
+ for (const p of profiles) {
32
+ const parts = [`${p.serverCount} servers`];
33
+ if (p.pluginCount > 0) parts.push(`${p.pluginCount} plugins`);
34
+ console.log(`${p.name} (${parts.join(", ")})`);
35
+ }
36
+ }
37
+ }
38
+ }),
39
+ load: defineCommand({
40
+ meta: {
41
+ name: "load",
42
+ description: "Load and apply a saved profile"
43
+ },
44
+ args: {
45
+ name: {
46
+ type: "positional",
47
+ description: "Profile name",
48
+ required: true
49
+ },
50
+ dryRun: {
51
+ type: "boolean",
52
+ description: "Preview changes without writing",
53
+ default: false
54
+ },
55
+ json: {
56
+ type: "boolean",
57
+ description: "Output as JSON",
58
+ default: false
59
+ }
60
+ },
61
+ async run({ args }) {
62
+ try {
63
+ if (args.dryRun) {
64
+ const profile = await load_profile(args.name);
65
+ const previews = [build_json_change_preview({
66
+ operation: "profile-load",
67
+ client: "claude-code",
68
+ scope: "user",
69
+ location: get_claude_config_path(),
70
+ before: await read_claude_config(),
71
+ after: profile.config
72
+ })];
73
+ if (profile.enabledPlugins) previews.push(build_json_change_preview({
74
+ operation: "profile-load-plugins",
75
+ client: "claude-code",
76
+ scope: "user",
77
+ location: get_claude_settings_path(),
78
+ before: await read_claude_settings(),
79
+ after: { enabledPlugins: profile.enabledPlugins }
80
+ }));
81
+ if (args.json) output(previews, true);
82
+ else for (const preview of previews) print_dry_run(preview, false);
83
+ return;
84
+ }
85
+ const result = await apply_profile_to_claude(args.name);
86
+ if (args.json) output({
87
+ profile: result.profile,
88
+ servers: result.serverCount,
89
+ plugins: result.pluginCount
90
+ }, true);
91
+ else {
92
+ const parts = [`${result.serverCount} servers`];
93
+ if (result.pluginCount > 0) parts.push(`${result.pluginCount} plugins`);
94
+ console.log(`Profile '${result.profile}' applied (${parts.join(", ")})`);
95
+ }
96
+ } catch (err) {
97
+ error(err instanceof Error ? err.message : "Failed to load profile");
98
+ }
99
+ }
100
+ }),
101
+ save: defineCommand({
102
+ meta: {
103
+ name: "save",
104
+ description: "Save current config as a profile"
105
+ },
106
+ args: {
107
+ name: {
108
+ type: "positional",
109
+ description: "Profile name",
110
+ required: true
111
+ },
112
+ dryRun: {
113
+ type: "boolean",
114
+ description: "Preview changes without writing",
115
+ default: false
116
+ },
117
+ json: {
118
+ type: "boolean",
119
+ description: "Output as JSON",
120
+ default: false
121
+ }
122
+ },
123
+ async run({ args }) {
124
+ try {
125
+ if (args.dryRun) {
126
+ const config = await read_claude_config();
127
+ const settings = await read_claude_settings();
128
+ const profile_data = { mcpServers: config.mcpServers || {} };
129
+ if (settings.enabledPlugins) profile_data.enabledPlugins = settings.enabledPlugins;
130
+ print_dry_run(build_json_change_preview({
131
+ operation: "profile-save",
132
+ client: "claude-code",
133
+ scope: "user",
134
+ location: get_profile_path(args.name),
135
+ before: {},
136
+ after: profile_data
137
+ }), args.json);
138
+ return;
139
+ }
140
+ const result = await save_current_claude_profile(args.name);
141
+ if (args.json) output({
142
+ profile: result.profile,
143
+ servers: result.serverCount,
144
+ plugins: result.pluginCount
145
+ }, true);
146
+ else {
147
+ const parts = [`${result.serverCount} servers`];
148
+ if (result.pluginCount > 0) parts.push(`${result.pluginCount} plugins`);
149
+ console.log(`Profile '${result.profile}' saved (${parts.join(", ")})`);
150
+ }
151
+ } catch (err) {
152
+ error(err instanceof Error ? err.message : "Failed to save profile");
153
+ }
154
+ }
155
+ })
156
+ }
157
+ });
158
+ //#endregion
159
+ export { profile_default as default };
160
+
161
+ //# sourceMappingURL=profile-DwJTVXiz.js.map
@@ -85,4 +85,4 @@ function redact_record(record) {
85
85
  //#endregion
86
86
  export { redact_url as a, redact_text as i, redact_server as n, redact_value as o, redact_server_base as r, redact_portable_server as t };
87
87
 
88
- //# sourceMappingURL=redact-Dltz2gde.js.map
88
+ //# sourceMappingURL=redact-wBMtzbno.js.map
@@ -1,4 +1,4 @@
1
- import { n as output } from "./output-BgN9Uuxf.js";
1
+ import { n as output } from "./output-HtT5HCof.js";
2
2
  import { defineCommand } from "citty";
3
3
  //#region src/cli/commands/reload.ts
4
4
  var reload_default = defineCommand({
@@ -28,4 +28,4 @@ var reload_default = defineCommand({
28
28
  //#endregion
29
29
  export { reload_default as default };
30
30
 
31
- //# sourceMappingURL=reload-C29-vuvy.js.map
31
+ //# sourceMappingURL=reload-Bl1mYK1I.js.map
@@ -0,0 +1,107 @@
1
+ import { B as preview_remove_client_server, G as build_command_preview, H as remove_client_server, I as get_client_adapter, M as read_server_registry, N as write_server_registry, U as resolve_client_location, h as build_remove_args, k as get_all_available_servers, w as remove_mcp_via_cli } from "./index.js";
2
+ import { n as output, t as error } from "./output-HtT5HCof.js";
3
+ import { t as print_dry_run } from "./dry-run-XQ32fxPT.js";
4
+ import { defineCommand } from "citty";
5
+ //#region src/cli/commands/remove.ts
6
+ var remove_default = defineCommand({
7
+ meta: {
8
+ name: "remove",
9
+ description: "Remove an MCP server from the registry and disable it"
10
+ },
11
+ args: {
12
+ server: {
13
+ type: "positional",
14
+ description: "Server name to remove",
15
+ required: true
16
+ },
17
+ client: {
18
+ type: "string",
19
+ description: "Client to edit: claude-code, gemini-cli, vscode, cursor, windsurf, opencode, or pi",
20
+ default: "claude-code"
21
+ },
22
+ scope: {
23
+ type: "string",
24
+ description: "Scope: local, project, or user"
25
+ },
26
+ location: {
27
+ type: "string",
28
+ description: "Exact config path when a client has multiple matching locations"
29
+ },
30
+ dryRun: {
31
+ type: "boolean",
32
+ description: "Preview changes without writing",
33
+ default: false
34
+ },
35
+ json: {
36
+ type: "boolean",
37
+ description: "Output as JSON",
38
+ default: false
39
+ }
40
+ },
41
+ async run({ args }) {
42
+ if (args.client && args.client !== "claude-code") {
43
+ await remove_from_client(args.client, args.server, args.scope, args.location, args.json, args.dryRun);
44
+ return;
45
+ }
46
+ const scope = args.scope || "local";
47
+ if (![
48
+ "local",
49
+ "project",
50
+ "user"
51
+ ].includes(scope)) error(`Invalid scope: ${scope}. Use local, project, or user.`);
52
+ if (!(await get_all_available_servers()).find((s) => s.name === args.server)) error(`Server '${args.server}' not found. Run 'mcpick list' to see available servers.`);
53
+ if (args.dryRun) {
54
+ print_dry_run(build_command_preview({
55
+ operation: "remove-server",
56
+ client: "claude-code",
57
+ scope,
58
+ location: "Claude Code CLI + mcpick registry",
59
+ command: ["claude", ...build_remove_args(args.server, scope)]
60
+ }), args.json);
61
+ return;
62
+ }
63
+ const registry = await read_server_registry();
64
+ const index = registry.servers.findIndex((s) => s.name === args.server);
65
+ if (index >= 0) {
66
+ registry.servers.splice(index, 1);
67
+ await write_server_registry(registry);
68
+ }
69
+ await remove_mcp_via_cli(args.server, scope);
70
+ if (args.json) output({
71
+ removed: args.server,
72
+ client: "claude-code",
73
+ scope
74
+ }, true);
75
+ else console.log(`Removed '${args.server}'`);
76
+ }
77
+ });
78
+ async function remove_from_client(client, server, scope, location_path, json, dry_run) {
79
+ const adapter = get_client_adapter(client);
80
+ if (!adapter) error(`Invalid client: ${client}. Use claude-code, gemini-cli, vscode, cursor, windsurf, opencode, or pi.`);
81
+ if (scope && ![
82
+ "local",
83
+ "project",
84
+ "user"
85
+ ].includes(scope)) error(`Invalid scope: ${scope}. Use local, project, or user.`);
86
+ try {
87
+ const location = resolve_client_location(adapter, scope, location_path);
88
+ if (dry_run) {
89
+ print_dry_run(await preview_remove_client_server(adapter, location, server), json);
90
+ return;
91
+ }
92
+ await remove_client_server(adapter, location, server);
93
+ if (json) output({
94
+ removed: server,
95
+ client: adapter.id,
96
+ scope: location.scope,
97
+ location: location.path
98
+ }, true);
99
+ else console.log(`Removed '${server}' (${adapter.id}:${location.scope})`);
100
+ } catch (err) {
101
+ error(err instanceof Error ? err.message : "Failed to remove server");
102
+ }
103
+ }
104
+ //#endregion
105
+ export { remove_default as default };
106
+
107
+ //# sourceMappingURL=remove-BSHgva79.js.map
@@ -1,5 +1,5 @@
1
- import { y as mcp_reset_project_choices_via_cli } from "./index.js";
2
- import { n as output, t as error } from "./output-BgN9Uuxf.js";
1
+ import { C as mcp_reset_project_choices_via_cli } from "./index.js";
2
+ import { n as output, t as error } from "./output-HtT5HCof.js";
3
3
  import { defineCommand } from "citty";
4
4
  //#region src/cli/commands/reset-project-choices.ts
5
5
  var reset_project_choices_default = defineCommand({
@@ -25,4 +25,4 @@ var reset_project_choices_default = defineCommand({
25
25
  //#endregion
26
26
  export { reset_project_choices_default as default };
27
27
 
28
- //# sourceMappingURL=reset-project-choices-Dhh4CxIC.js.map
28
+ //# sourceMappingURL=reset-project-choices-BNLus9J9.js.map
@@ -1,8 +1,7 @@
1
- import { t as validate_claude_config } from "./validation-qWlF51fw.js";
2
- import { c as write_claude_config } from "./config-BhX4eAgg.js";
3
- import { s as write_claude_settings } from "./settings-CZR8bVfh.js";
4
- import { D as list_plugin_backups, E as list_backups } from "./index.js";
5
- import { n as output, t as error } from "./output-BgN9Uuxf.js";
1
+ import { t as validate_claude_config } from "./validation-xMlbgGCF.js";
2
+ import { c as write_claude_config } from "./config-DE58Fik_.js";
3
+ import { $ as write_claude_settings, A as list_backups, j as list_plugin_backups } from "./index.js";
4
+ import { n as output, t as error } from "./output-HtT5HCof.js";
6
5
  import { readFile } from "node:fs/promises";
7
6
  import { defineCommand } from "citty";
8
7
  //#region src/cli/commands/restore.ts
@@ -81,4 +80,4 @@ var restore_default = defineCommand({
81
80
  //#endregion
82
81
  export { restore_default as default };
83
82
 
84
- //# sourceMappingURL=restore-BI8aiszM.js.map
83
+ //# sourceMappingURL=restore-YisgARhc.js.map
@@ -0,0 +1,55 @@
1
+ import { nt as restore_config_backup, tt as list_config_backups } from "./index.js";
2
+ import { n as output, t as error } from "./output-HtT5HCof.js";
3
+ import { defineCommand } from "citty";
4
+ //#region src/cli/commands/rollback.ts
5
+ var rollback_default = defineCommand({
6
+ meta: {
7
+ name: "rollback",
8
+ description: "List or restore automatic config backups created before safe writes"
9
+ },
10
+ args: {
11
+ file: {
12
+ type: "positional",
13
+ description: "Config backup filename or path. Defaults to latest backup.",
14
+ required: false
15
+ },
16
+ list: {
17
+ type: "boolean",
18
+ description: "List available config rollback backups",
19
+ default: false
20
+ },
21
+ json: {
22
+ type: "boolean",
23
+ description: "Output as JSON",
24
+ default: false
25
+ }
26
+ },
27
+ async run({ args }) {
28
+ try {
29
+ const backups = await list_config_backups();
30
+ if (args.list) {
31
+ if (args.json) {
32
+ output(backups, true);
33
+ return;
34
+ }
35
+ if (backups.length === 0) {
36
+ console.log("No config rollback backups found.");
37
+ return;
38
+ }
39
+ for (const backup of backups) console.log(`${backup.created_at} ${backup.path} -> ${backup.original_path}`);
40
+ return;
41
+ }
42
+ const backup_path = args.file || backups[0]?.path;
43
+ if (!backup_path) error("No config rollback backups found.");
44
+ const restored = await restore_config_backup(backup_path);
45
+ if (args.json) output({ restored }, true);
46
+ else console.log(`Restored ${restored.original_path} from ${restored.path}`);
47
+ } catch (err) {
48
+ error(err instanceof Error ? err.message : "Rollback failed");
49
+ }
50
+ }
51
+ });
52
+ //#endregion
53
+ export { rollback_default as default };
54
+
55
+ //# sourceMappingURL=rollback-GR1RkpXW.js.map
@@ -1,5 +1,5 @@
1
- import { a as split_cli_list, i as run_skills_cli } from "./index.js";
2
- import { n as output, t as error } from "./output-BgN9Uuxf.js";
1
+ import { a as run_skills_cli, o as split_cli_list } from "./index.js";
2
+ import { n as output, t as error } from "./output-HtT5HCof.js";
3
3
  import { defineCommand } from "citty";
4
4
  //#region src/cli/commands/skills.ts
5
5
  function add_agent_args(cli_args, agent) {
@@ -213,4 +213,4 @@ var skills_default = defineCommand({
213
213
  //#endregion
214
214
  export { skills_default as default };
215
215
 
216
- //# sourceMappingURL=skills-DPBDmION.js.map
216
+ //# sourceMappingURL=skills-rDTDqqZA.js.map
@@ -41,4 +41,4 @@ function validate_server_registry(data) {
41
41
  //#endregion
42
42
  export { validate_mcp_server as n, validate_server_registry as r, validate_claude_config as t };
43
43
 
44
- //# sourceMappingURL=validation-qWlF51fw.js.map
44
+ //# sourceMappingURL=validation-xMlbgGCF.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcpick",
3
- "version": "0.0.22",
3
+ "version": "0.0.24",
4
4
  "description": "Vendor-neutral MCP configuration manager with first-class Claude Code support",
5
5
  "keywords": [
6
6
  "claude",
@@ -20,7 +20,7 @@
20
20
  "url": "https://github.com/spences10/mcpick/issues"
21
21
  },
22
22
  "license": "MIT",
23
- "author": "",
23
+ "author": "spences10 <spences10apps@gmail.com>",
24
24
  "repository": {
25
25
  "type": "git",
26
26
  "url": "git+https://github.com/spences10/mcpick.git"
@@ -31,14 +31,14 @@
31
31
  "type": "module",
32
32
  "main": "./dist/index.js",
33
33
  "dependencies": {
34
- "@clack/prompts": "^1.2.0",
34
+ "@clack/prompts": "^1.3.0",
35
35
  "citty": "^0.2.2",
36
36
  "valibot": "^1.3.1"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@changesets/cli": "^2.31.0",
40
40
  "@types/node": "^25.6.0",
41
- "vite-plus": "^0.1.19",
41
+ "vite-plus": "^0.1.20",
42
42
  "vitest": "^4.1.5"
43
43
  },
44
44
  "engines": {
@@ -1,50 +0,0 @@
1
- # MCPick Development Instructions
2
-
3
- ## Project shape
4
-
5
- MCPick is a vendor-neutral MCP configuration manager with first-class
6
- Claude Code support.
7
-
8
- - Keep MCP server functionality client-neutral where possible.
9
- - Keep Claude Code plugins, hooks, marketplaces, and cache commands
10
- clearly Claude-specific.
11
- - Prefer CLI flows that work well for LLM agents: non-interactive
12
- flags, `--json`, useful help text, and redacted output.
13
-
14
- ## Prerequisites
15
-
16
- - Node.js >=22.0.0
17
- - pnpm
18
-
19
- ## Common commands
20
-
21
- ```bash
22
- pnpm install
23
- pnpm test
24
- pnpm run check
25
- pnpm build
26
- ```
27
-
28
- ## Validation before finishing
29
-
30
- Always run:
31
-
32
- ```bash
33
- pnpm run check
34
- pnpm test
35
- pnpm build
36
- ```
37
-
38
- `pnpm run check` validates formatting, lint, and types through
39
- vite-plus.
40
-
41
- ## Changesets
42
-
43
- For user-facing changes, add a changeset:
44
-
45
- ```bash
46
- pnpm changeset
47
- ```
48
-
49
- Use a short message prefixed with `feat`, `fix`, `chore`, or
50
- `breaking`.