mcpick 0.0.25 → 0.0.26

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 (36) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/{add-7mhUpbrt.js → add-DwUPxD5U.js} +4 -5
  3. package/dist/{add-json-BMM2L4hv.js → add-json-Dk3C8QSR.js} +4 -4
  4. package/dist/atomic-write-9pfXia-x.js +22 -0
  5. package/dist/{backup-C-YJmgps.js → backup-Ber7st-_.js} +4 -5
  6. package/dist/{cache-BOYZhUF6.js → cache-BVNAOxqk.js} +3 -3
  7. package/dist/{cli-sOeHH4CK.js → cli-Dfein2li.js} +22 -22
  8. package/dist/{clients-D5KAuQ5U.js → clients-C1mWlnsn.js} +3 -3
  9. package/dist/{clone-BRJA55js.js → clone-BE904ik7.js} +3 -6
  10. package/dist/{dev-B-WlQSqY.js → dev-BW_2JDPM.js} +5 -6
  11. package/dist/{disable-Br0aVG3u.js → disable-CVwuJLhT.js} +4 -4
  12. package/dist/{enable-DUolKCEH.js → enable-BEi8TUd1.js} +4 -4
  13. package/dist/{get-D-6Cl_CO.js → get-eDOm6sRK.js} +3 -3
  14. package/dist/{hooks-BKPmZViU.js → hooks-DzGBYYId.js} +4 -3
  15. package/dist/index.js +306 -265
  16. package/dist/{list-DMcaHDfM.js → list-CvpW_mNZ.js} +3 -5
  17. package/dist/{marketplace-DTW7Ys8k.js → marketplace-BKGJ3UGr.js} +4 -4
  18. package/dist/{mutation-ukRPw3qM.js → mutation-BBMIFB8H.js} +2 -2
  19. package/dist/{output-BS1TMOWt.js → output-DGPi2IWN.js} +2 -2
  20. package/dist/{plugin-cache-Dw1I2YuO.js → plugin-cache-Dj-lS1mA.js} +169 -21
  21. package/dist/{plugins-BzLD4og0.js → plugins-elIQYM38.js} +4 -4
  22. package/dist/{profile-CmIWUJH_.js → profile-NVbTnJKI.js} +4 -4
  23. package/dist/{reload-Di28s_rY.js → reload-BkVtWaf0.js} +2 -2
  24. package/dist/{remove-B32EuYRC.js → remove-BC2vomi_.js} +4 -4
  25. package/dist/{reset-project-choices-DX4TnZ2i.js → reset-project-choices-DhJsWQx2.js} +3 -3
  26. package/dist/{restore-ByS4xi0y.js → restore-CeYSOFt8.js} +3 -5
  27. package/dist/{rollback-DdDJrA8y.js → rollback-g-WX6b3o.js} +3 -3
  28. package/dist/safe-apply-B5flt8QC.js +185 -0
  29. package/dist/{skills-pvyQ17XU.js → skills-zuQ5kCL1.js} +2 -2
  30. package/package.json +6 -6
  31. package/pnpm-workspace.yaml +1 -0
  32. package/dist/config-Bzh374VP.js +0 -167
  33. package/dist/paths-BPISiJi4.js +0 -124
  34. package/dist/redact-wBMtzbno.js +0 -88
  35. package/dist/rolldown-runtime-CiIaOW0V.js +0 -13
  36. package/dist/validation-CfPAjPJ5.js +0 -63
@@ -1,7 +1,5 @@
1
- import { a as get_enabled_servers_for_scope } from "./config-Bzh374VP.js";
2
- import { a as redact_url, n as redact_server, t as redact_portable_server } from "./redact-wBMtzbno.js";
3
- import { D as get_all_available_servers, P as get_client_adapter } from "./index.js";
4
- import { n as output, t as error } from "./output-BS1TMOWt.js";
1
+ import { F as get_client_adapter, O as get_all_available_servers, S as redact_server, T as redact_url, Y as get_enabled_servers_for_scope, x as redact_portable_server } from "./index.js";
2
+ import { n as output, t as error } from "./output-DGPi2IWN.js";
5
3
  import { defineCommand } from "citty";
6
4
  //#region src/cli/commands/list.ts
7
5
  var list_default = defineCommand({
@@ -97,4 +95,4 @@ async function list_client_servers(client, scope, json) {
97
95
  //#endregion
98
96
  export { list_default as default };
99
97
 
100
- //# sourceMappingURL=list-DMcaHDfM.js.map
98
+ //# sourceMappingURL=list-CvpW_mNZ.js.map
@@ -1,6 +1,6 @@
1
- import { u as read_marketplace_manifest } from "./plugin-cache-Dw1I2YuO.js";
2
- import { _ as marketplace_remove_via_cli, c as check_restored_hooks, f as redisable_restored_hooks, g as marketplace_list_via_cli, h as marketplace_add_via_cli, v as marketplace_update_via_cli } from "./index.js";
3
- import { n as output, t as error } from "./output-BS1TMOWt.js";
1
+ import { _ as redisable_restored_hooks, l as read_marketplace_manifest, p as check_restored_hooks } from "./plugin-cache-Dj-lS1mA.js";
2
+ import { d as marketplace_list_via_cli, f as marketplace_remove_via_cli, p as marketplace_update_via_cli, u as marketplace_add_via_cli } from "./index.js";
3
+ import { n as output, t as error } from "./output-DGPi2IWN.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-DTW7Ys8k.js.map
167
+ //# sourceMappingURL=marketplace-BKGJ3UGr.js.map
@@ -1,4 +1,4 @@
1
- import { i as get_claude_config_path, v as get_project_mcp_json_path } from "./paths-BPISiJi4.js";
1
+ import { s as get_claude_config_path, x as get_project_mcp_json_path } from "./safe-apply-B5flt8QC.js";
2
2
  //#region src/cli/mutation.ts
3
3
  function claude_mutation_context(operation, scope, servers) {
4
4
  return {
@@ -16,4 +16,4 @@ function print_mutation_details(input) {
16
16
  //#endregion
17
17
  export { print_mutation_details as n, claude_mutation_context as t };
18
18
 
19
- //# sourceMappingURL=mutation-ukRPw3qM.js.map
19
+ //# sourceMappingURL=mutation-BBMIFB8H.js.map
@@ -1,4 +1,4 @@
1
- import { i as redact_text, o as redact_value } from "./redact-wBMtzbno.js";
1
+ import { E as redact_value, w as redact_text } from "./index.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-BS1TMOWt.js.map
17
+ //# sourceMappingURL=output-DGPi2IWN.js.map
@@ -1,27 +1,175 @@
1
- import { t as __exportAll } from "./rolldown-runtime-CiIaOW0V.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 { K as atomic_json_write, c as check_restored_hooks, f as redisable_restored_hooks } from "./index.js";
1
+ import { d as get_disabled_hooks_path, f as get_installed_plugins_path, g as get_mcpick_dir, h as get_marketplaces_dir, i as ensure_directory_exists, m as get_marketplace_manifest_path, p as get_known_marketplaces_path, r as safe_json_write, v as get_plugin_cache_dir } from "./safe-apply-B5flt8QC.js";
2
+ import { t as atomic_json_write } from "./atomic-write-9pfXia-x.js";
4
3
  import { lstat, readFile, readdir, readlink, rename, rm, symlink } from "node:fs/promises";
5
4
  import { join, resolve } from "node:path";
6
5
  import { execFile } from "node:child_process";
7
6
  import { promisify } from "node:util";
7
+ //#region src/core/hook-state.ts
8
+ async function read_disabled_hooks() {
9
+ try {
10
+ const content = await readFile(get_disabled_hooks_path(), "utf-8");
11
+ return JSON.parse(content);
12
+ } catch {
13
+ return [];
14
+ }
15
+ }
16
+ async function write_disabled_hooks(entries) {
17
+ await ensure_directory_exists(get_mcpick_dir());
18
+ await safe_json_write(get_disabled_hooks_path(), entries, " ");
19
+ }
20
+ /**
21
+ * Remove a specific hook handler from a hooks.json file by matching the handler.
22
+ * Returns true if the hook was found and removed.
23
+ */
24
+ async function remove_hook_from_file(hooks_path, event, handler) {
25
+ let content;
26
+ try {
27
+ content = await readFile(hooks_path, "utf-8");
28
+ } catch {
29
+ return false;
30
+ }
31
+ const hooks_data = JSON.parse(content);
32
+ const hooks_obj = hooks_data.hooks || hooks_data;
33
+ const matchers = hooks_obj[event];
34
+ if (!matchers) return false;
35
+ let removed = false;
36
+ for (const m of matchers) {
37
+ const idx = m.hooks?.findIndex((h) => h.type === handler.type && h.command === handler.command && h.url === handler.url && h.prompt === handler.prompt);
38
+ if (idx !== void 0 && idx >= 0) {
39
+ m.hooks.splice(idx, 1);
40
+ removed = true;
41
+ if (m.hooks.length === 0) matchers.splice(matchers.indexOf(m), 1);
42
+ break;
43
+ }
44
+ }
45
+ if (!removed) return false;
46
+ if (matchers.length === 0) delete hooks_obj[event];
47
+ await safe_json_write(hooks_path, hooks_data, " ");
48
+ return true;
49
+ }
50
+ /**
51
+ * Get all hooks.json paths for a plugin (cache + marketplace source).
52
+ */
53
+ function get_all_hooks_paths(plugin_key, primary_path) {
54
+ const paths = [primary_path];
55
+ const at_index = plugin_key.lastIndexOf("@");
56
+ if (at_index > 0) {
57
+ const plugin_name = plugin_key.substring(0, at_index);
58
+ const marketplace_name = plugin_key.substring(at_index + 1);
59
+ paths.push(join(get_marketplaces_dir(), marketplace_name, "plugins", plugin_name, "hooks", "hooks.json"));
60
+ }
61
+ return [...new Set(paths)];
62
+ }
63
+ /**
64
+ * Disable a specific hook from a plugin.
65
+ * Removes from both cache and marketplace source hooks.json files.
66
+ */
67
+ async function disable_plugin_hook(entry) {
68
+ if (!entry.hooks_json_path || !entry.plugin_key) throw new Error("Not a plugin hook");
69
+ const disabled = await read_disabled_hooks();
70
+ disabled.push({
71
+ plugin_key: entry.plugin_key,
72
+ hooks_json_path: entry.hooks_json_path,
73
+ event: entry.event,
74
+ matcher: entry.matcher,
75
+ matcher_index: entry.matcher_index,
76
+ hook_index: entry.hook_index,
77
+ original_handler: entry.handler,
78
+ disabled_at: (/* @__PURE__ */ new Date()).toISOString()
79
+ });
80
+ await write_disabled_hooks(disabled);
81
+ const all_paths = get_all_hooks_paths(entry.plugin_key, entry.hooks_json_path);
82
+ for (const hooks_path of all_paths) await remove_hook_from_file(hooks_path, entry.event, entry.handler);
83
+ }
84
+ /**
85
+ * Add a hook handler back into a hooks.json file.
86
+ */
87
+ async function add_hook_to_file(hooks_path, event, matcher_pattern, handler) {
88
+ let hooks_data;
89
+ try {
90
+ const content = await readFile(hooks_path, "utf-8");
91
+ hooks_data = JSON.parse(content);
92
+ } catch {
93
+ hooks_data = { hooks: {} };
94
+ }
95
+ const hooks_obj = hooks_data.hooks || (hooks_data.hooks = {});
96
+ if (!hooks_obj[event]) hooks_obj[event] = [];
97
+ const matchers = hooks_obj[event];
98
+ let matcher = matchers.find((m) => (m.matcher || void 0) === matcher_pattern);
99
+ if (!matcher) {
100
+ matcher = { hooks: [] };
101
+ if (matcher_pattern) matcher.matcher = matcher_pattern;
102
+ matchers.push(matcher);
103
+ }
104
+ if (matcher.hooks.some((h) => h.type === handler.type && h.command === handler.command && h.url === handler.url && h.prompt === handler.prompt)) return;
105
+ matcher.hooks.push(handler);
106
+ await safe_json_write(hooks_path, hooks_data, " ");
107
+ }
108
+ /**
109
+ * Re-enable a previously disabled plugin hook.
110
+ * Restores to both cache and marketplace source hooks.json files.
111
+ */
112
+ async function enable_plugin_hook(disabled_entry) {
113
+ const all_paths = get_all_hooks_paths(disabled_entry.plugin_key, disabled_entry.hooks_json_path);
114
+ for (const hooks_path of all_paths) await add_hook_to_file(hooks_path, disabled_entry.event, disabled_entry.matcher, disabled_entry.original_handler);
115
+ await write_disabled_hooks((await read_disabled_hooks()).filter((d) => !(d.plugin_key === disabled_entry.plugin_key && d.event === disabled_entry.event && d.disabled_at === disabled_entry.disabled_at)));
116
+ }
117
+ /**
118
+ * Check if any previously disabled hooks have been restored (e.g. by marketplace update).
119
+ * Returns entries that were re-added and need to be re-disabled.
120
+ */
121
+ async function check_restored_hooks() {
122
+ const disabled = await read_disabled_hooks();
123
+ if (disabled.length === 0) return [];
124
+ const restored = [];
125
+ for (const entry of disabled) {
126
+ const all_paths = get_all_hooks_paths(entry.plugin_key, entry.hooks_json_path);
127
+ let found = false;
128
+ for (const hooks_path of all_paths) {
129
+ let hooks_data;
130
+ try {
131
+ const content = await readFile(hooks_path, "utf-8");
132
+ hooks_data = JSON.parse(content);
133
+ } catch {
134
+ continue;
135
+ }
136
+ const matchers = (hooks_data.hooks || hooks_data)[entry.event];
137
+ if (!matchers) continue;
138
+ for (const m of matchers) {
139
+ if ((m.matcher || void 0) !== entry.matcher) continue;
140
+ if (m.hooks?.some((h) => h.type === entry.original_handler.type && (h.command === entry.original_handler.command || h.url === entry.original_handler.url || h.prompt === entry.original_handler.prompt))) {
141
+ found = true;
142
+ break;
143
+ }
144
+ }
145
+ if (found) break;
146
+ }
147
+ if (found) restored.push(entry);
148
+ }
149
+ return restored;
150
+ }
151
+ /**
152
+ * Re-disable hooks that were restored by a marketplace update.
153
+ */
154
+ async function redisable_restored_hooks(restored) {
155
+ let success = 0;
156
+ let failed = 0;
157
+ for (const entry of restored) try {
158
+ const all_paths = get_all_hooks_paths(entry.plugin_key, entry.hooks_json_path);
159
+ let any_removed = false;
160
+ for (const hooks_path of all_paths) if (await remove_hook_from_file(hooks_path, entry.event, entry.original_handler)) any_removed = true;
161
+ if (any_removed) success++;
162
+ else failed++;
163
+ } catch {
164
+ failed++;
165
+ }
166
+ return {
167
+ success,
168
+ failed
169
+ };
170
+ }
171
+ //#endregion
8
172
  //#region src/core/plugin-cache.ts
9
- var plugin_cache_exports = /* @__PURE__ */ __exportAll({
10
- clean_orphaned_versions: () => clean_orphaned_versions,
11
- clear_plugin_caches: () => clear_plugin_caches,
12
- get_cached_plugins_info: () => get_cached_plugins_info,
13
- link_local_plugin: () => link_local_plugin,
14
- list_linked_plugins: () => list_linked_plugins,
15
- parse_plugin_key: () => parse_plugin_key,
16
- read_installed_plugins: () => read_installed_plugins,
17
- read_known_marketplaces: () => read_known_marketplaces,
18
- read_marketplace_manifest: () => read_marketplace_manifest,
19
- refresh_all_marketplaces: () => refresh_all_marketplaces,
20
- refresh_marketplace: () => refresh_marketplace,
21
- scan_all_cache_keys: () => scan_all_cache_keys,
22
- unlink_local_plugin: () => unlink_local_plugin,
23
- write_installed_plugins: () => write_installed_plugins
24
- });
25
173
  const execFileAsync = promisify(execFile);
26
174
  function git(dir, args, timeout) {
27
175
  return execFileAsync("git", [
@@ -426,6 +574,6 @@ async function list_linked_plugins() {
426
574
  return links;
427
575
  }
428
576
  //#endregion
429
- 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 };
577
+ export { redisable_restored_hooks as _, list_linked_plugins as a, read_known_marketplaces as c, scan_all_cache_keys as d, unlink_local_plugin as f, read_disabled_hooks as g, enable_plugin_hook as h, link_local_plugin as i, read_marketplace_manifest as l, disable_plugin_hook as m, clear_plugin_caches as n, parse_plugin_key as o, check_restored_hooks as p, get_cached_plugins_info as r, read_installed_plugins as s, clean_orphaned_versions as t, refresh_all_marketplaces as u };
430
578
 
431
- //# sourceMappingURL=plugin-cache-Dw1I2YuO.js.map
579
+ //# sourceMappingURL=plugin-cache-Dj-lS1mA.js.map
@@ -1,6 +1,6 @@
1
- import { l as read_known_marketplaces, o as parse_plugin_key } from "./plugin-cache-Dw1I2YuO.js";
2
- import { B as build_enabled_plugins, C as uninstall_plugin_via_cli, G as write_claude_settings, H as get_all_plugins, T as validate_plugin_via_cli, U as read_claude_settings, m as install_plugin_via_cli, w as update_plugin_via_cli } from "./index.js";
3
- import { n as output, t as error } from "./output-BS1TMOWt.js";
1
+ import { c as read_known_marketplaces, o as parse_plugin_key } from "./plugin-cache-Dj-lS1mA.js";
2
+ import { K as write_claude_settings, U as get_all_plugins, V as build_enabled_plugins, W as read_claude_settings, b as validate_plugin_via_cli, l as install_plugin_via_cli, v as uninstall_plugin_via_cli, y as update_plugin_via_cli } from "./index.js";
3
+ import { n as output, t as error } from "./output-DGPi2IWN.js";
4
4
  import { defineCommand } from "citty";
5
5
  var plugins_default = defineCommand({
6
6
  meta: {
@@ -208,4 +208,4 @@ var plugins_default = defineCommand({
208
208
  //#endregion
209
209
  export { plugins_default as default };
210
210
 
211
- //# sourceMappingURL=plugins-BzLD4og0.js.map
211
+ //# sourceMappingURL=plugins-elIQYM38.js.map
@@ -1,6 +1,6 @@
1
- import { L as resolve_client_location, P as get_client_adapter, a as save_profile_for_client, i as save_current_claude_profile, n as apply_profile_to_client, r as list_profiles, t as apply_profile_to_claude } from "./index.js";
2
- import { n as print_mutation_details } from "./mutation-ukRPw3qM.js";
3
- import { n as output, t as error } from "./output-BS1TMOWt.js";
1
+ import { F as get_client_adapter, R as resolve_client_location, a as save_profile_for_client, i as save_current_claude_profile, n as apply_profile_to_client, r as list_profiles, t as apply_profile_to_claude } from "./index.js";
2
+ import { n as print_mutation_details } from "./mutation-BBMIFB8H.js";
3
+ import { n as output, t as error } from "./output-DGPi2IWN.js";
4
4
  import { defineCommand } from "citty";
5
5
  //#region src/cli/commands/profile.ts
6
6
  const CLIENTS = "claude-code, gemini-cli, vscode, cursor, windsurf, opencode, or pi";
@@ -160,4 +160,4 @@ var profile_default = defineCommand({
160
160
  //#endregion
161
161
  export { profile_default as default };
162
162
 
163
- //# sourceMappingURL=profile-CmIWUJH_.js.map
163
+ //# sourceMappingURL=profile-NVbTnJKI.js.map
@@ -1,4 +1,4 @@
1
- import { n as output } from "./output-BS1TMOWt.js";
1
+ import { n as output } from "./output-DGPi2IWN.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-Di28s_rY.js.map
31
+ //# sourceMappingURL=reload-BkVtWaf0.js.map
@@ -1,6 +1,6 @@
1
- import { A as read_server_registry, D as get_all_available_servers, I as remove_client_server, L as resolve_client_location, P as get_client_adapter, S as remove_mcp_via_cli, j as write_server_registry } from "./index.js";
2
- import { n as print_mutation_details, t as claude_mutation_context } from "./mutation-ukRPw3qM.js";
3
- import { n as output, t as error } from "./output-BS1TMOWt.js";
1
+ import { F as get_client_adapter, L as remove_client_server, M as write_server_registry, O as get_all_available_servers, R as resolve_client_location, _ as remove_mcp_via_cli, j as read_server_registry } from "./index.js";
2
+ import { n as print_mutation_details, t as claude_mutation_context } from "./mutation-BBMIFB8H.js";
3
+ import { n as output, t as error } from "./output-DGPi2IWN.js";
4
4
  import { defineCommand } from "citty";
5
5
  //#region src/cli/commands/remove.ts
6
6
  var remove_default = defineCommand({
@@ -89,4 +89,4 @@ async function remove_from_client(client, server, scope, location_path, json) {
89
89
  //#endregion
90
90
  export { remove_default as default };
91
91
 
92
- //# sourceMappingURL=remove-B32EuYRC.js.map
92
+ //# sourceMappingURL=remove-BC2vomi_.js.map
@@ -1,5 +1,5 @@
1
- import { x as mcp_reset_project_choices_via_cli } from "./index.js";
2
- import { n as output, t as error } from "./output-BS1TMOWt.js";
1
+ import { g as mcp_reset_project_choices_via_cli } from "./index.js";
2
+ import { n as output, t as error } from "./output-DGPi2IWN.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-DX4TnZ2i.js.map
28
+ //# sourceMappingURL=reset-project-choices-DhJsWQx2.js.map
@@ -1,7 +1,5 @@
1
- import { t as validate_claude_config } from "./validation-CfPAjPJ5.js";
2
- import { s as write_claude_config } from "./config-Bzh374VP.js";
3
- import { G as write_claude_settings, O as list_backups, k as list_plugin_backups } from "./index.js";
4
- import { n as output, t as error } from "./output-BS1TMOWt.js";
1
+ import { A as list_plugin_backups, K as write_claude_settings, Q as validate_claude_config, Z as write_claude_config, k as list_backups } from "./index.js";
2
+ import { n as output, t as error } from "./output-DGPi2IWN.js";
5
3
  import { readFile } from "node:fs/promises";
6
4
  import { defineCommand } from "citty";
7
5
  //#region src/cli/commands/restore.ts
@@ -80,4 +78,4 @@ var restore_default = defineCommand({
80
78
  //#endregion
81
79
  export { restore_default as default };
82
80
 
83
- //# sourceMappingURL=restore-ByS4xi0y.js.map
81
+ //# sourceMappingURL=restore-CeYSOFt8.js.map
@@ -1,5 +1,5 @@
1
- import { J as restore_config_backup, q as list_config_backups } from "./index.js";
2
- import { n as output, t as error } from "./output-BS1TMOWt.js";
1
+ import { n as restore_config_backup, t as list_config_backups } from "./safe-apply-B5flt8QC.js";
2
+ import { n as output, t as error } from "./output-DGPi2IWN.js";
3
3
  import { defineCommand } from "citty";
4
4
  //#region src/cli/commands/rollback.ts
5
5
  var rollback_default = defineCommand({
@@ -52,4 +52,4 @@ var rollback_default = defineCommand({
52
52
  //#endregion
53
53
  export { rollback_default as default };
54
54
 
55
- //# sourceMappingURL=rollback-DdDJrA8y.js.map
55
+ //# sourceMappingURL=rollback-g-WX6b3o.js.map
@@ -0,0 +1,185 @@
1
+ import { access, mkdir, readFile, readdir, rename, rm, writeFile } from "node:fs/promises";
2
+ import { basename, dirname, join } from "node:path";
3
+ import { createHash, randomUUID } from "node:crypto";
4
+ import { existsSync } from "node:fs";
5
+ import { homedir } from "node:os";
6
+ //#region src/utils/paths.ts
7
+ function get_base_dir() {
8
+ const configDir = process.env.CLAUDE_CONFIG_DIR;
9
+ if (configDir && configDir.length > 0 && existsSync(configDir)) return {
10
+ baseDir: configDir,
11
+ parentDir: dirname(configDir),
12
+ coLocatedConfig: true
13
+ };
14
+ const defaultDir = join(homedir(), ".claude");
15
+ return {
16
+ baseDir: defaultDir,
17
+ parentDir: dirname(defaultDir),
18
+ coLocatedConfig: false
19
+ };
20
+ }
21
+ function get_claude_config_path() {
22
+ const { baseDir, parentDir, coLocatedConfig } = get_base_dir();
23
+ if (coLocatedConfig) return join(baseDir, ".claude.json");
24
+ return join(parentDir, ".claude.json");
25
+ }
26
+ function get_claude_settings_path() {
27
+ return join(get_base_dir().baseDir, "settings.json");
28
+ }
29
+ function get_mcpick_dir() {
30
+ return join(get_base_dir().baseDir, "mcpick");
31
+ }
32
+ function get_dev_overrides_path() {
33
+ return join(get_mcpick_dir(), "dev-overrides.json");
34
+ }
35
+ function get_server_registry_path() {
36
+ return join(get_mcpick_dir(), "servers.json");
37
+ }
38
+ function get_backups_dir() {
39
+ return join(get_mcpick_dir(), "backups");
40
+ }
41
+ function get_profiles_dir() {
42
+ return join(get_mcpick_dir(), "profiles");
43
+ }
44
+ function get_profile_path(name) {
45
+ const filename = name.endsWith(".json") ? name : `${name}.json`;
46
+ return join(get_profiles_dir(), filename);
47
+ }
48
+ function format_backup_timestamp() {
49
+ const now = /* @__PURE__ */ new Date();
50
+ return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}-${String(now.getHours()).padStart(2, "0")}${String(now.getMinutes()).padStart(2, "0")}${String(now.getSeconds()).padStart(2, "0")}`;
51
+ }
52
+ function get_backup_filename() {
53
+ return `mcp-servers-${format_backup_timestamp()}.json`;
54
+ }
55
+ function get_plugin_backup_filename() {
56
+ return `plugins-${format_backup_timestamp()}.json`;
57
+ }
58
+ async function ensure_directory_exists(dir_path) {
59
+ try {
60
+ await access(dir_path);
61
+ } catch {
62
+ await mkdir(dir_path, { recursive: true });
63
+ }
64
+ }
65
+ /**
66
+ * Get the current working directory (project path)
67
+ */
68
+ function get_current_project_path() {
69
+ return process.cwd();
70
+ }
71
+ /**
72
+ * Get the path to .mcp.json in the current project directory (project scope)
73
+ */
74
+ function get_project_mcp_json_path() {
75
+ return join(get_current_project_path(), ".mcp.json");
76
+ }
77
+ function get_plugins_dir() {
78
+ return join(get_base_dir().baseDir, "plugins");
79
+ }
80
+ function get_installed_plugins_path() {
81
+ return join(get_plugins_dir(), "installed_plugins.json");
82
+ }
83
+ function get_known_marketplaces_path() {
84
+ return join(get_plugins_dir(), "known_marketplaces.json");
85
+ }
86
+ function get_plugin_cache_dir() {
87
+ return join(get_plugins_dir(), "cache");
88
+ }
89
+ function get_marketplaces_dir() {
90
+ return join(get_plugins_dir(), "marketplaces");
91
+ }
92
+ function get_disabled_hooks_path() {
93
+ return join(get_mcpick_dir(), "disabled-hooks.json");
94
+ }
95
+ function get_marketplace_manifest_path(name) {
96
+ return join(get_marketplaces_dir(), name, ".claude-plugin", "marketplace.json");
97
+ }
98
+ //#endregion
99
+ //#region src/utils/safe-apply.ts
100
+ async function file_exists(path) {
101
+ try {
102
+ await access(path);
103
+ return true;
104
+ } catch {
105
+ return false;
106
+ }
107
+ }
108
+ function backup_name(path) {
109
+ const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z");
110
+ const hash = createHash("sha256").update(path).digest("hex").slice(0, 10);
111
+ return `config-${basename(path).replace(/[^A-Za-z0-9._-]/g, "_")}-${stamp}-${hash}.json`;
112
+ }
113
+ async function create_backup(path, content) {
114
+ const backups_dir = get_backups_dir();
115
+ await ensure_directory_exists(backups_dir);
116
+ const backup_path = join(backups_dir, backup_name(path));
117
+ await writeFile(backup_path, content, "utf-8");
118
+ await writeFile(`${backup_path}.meta.json`, JSON.stringify({
119
+ original_path: path,
120
+ created_at: (/* @__PURE__ */ new Date()).toISOString()
121
+ }, null, 2), "utf-8");
122
+ return backup_path;
123
+ }
124
+ /**
125
+ * Safely replace a JSON file: backup existing content, write via temp+rename,
126
+ * verify the result parses, and restore the original content on failure.
127
+ */
128
+ async function safe_json_write(path, data, indent = 2) {
129
+ await mkdir(dirname(path), { recursive: true });
130
+ const original_content = await file_exists(path) ? await readFile(path, "utf-8") : void 0;
131
+ const backup_path = original_content !== void 0 ? await create_backup(path, original_content) : void 0;
132
+ const tmp_path = join(dirname(path), `.${basename(path)}.${process.pid}.${Date.now()}.${randomUUID()}.tmp`);
133
+ const next_content = JSON.stringify(data, null, indent);
134
+ try {
135
+ await writeFile(tmp_path, next_content, "utf-8");
136
+ await rename(tmp_path, path);
137
+ const written = await readFile(path, "utf-8");
138
+ JSON.parse(written);
139
+ return {
140
+ path,
141
+ ...backup_path ? { backup_path } : {}
142
+ };
143
+ } catch (error) {
144
+ await rm(tmp_path, { force: true }).catch(() => void 0);
145
+ if (original_content !== void 0) await writeFile(path, original_content, "utf-8");
146
+ else await rm(path, { force: true }).catch(() => void 0);
147
+ throw error;
148
+ }
149
+ }
150
+ async function list_config_backups() {
151
+ const backups_dir = get_backups_dir();
152
+ try {
153
+ const files = await readdir(backups_dir);
154
+ const backups = [];
155
+ for (const file of files) {
156
+ if (!file.startsWith("config-") || !file.endsWith(".json")) continue;
157
+ if (file.endsWith(".meta.json")) continue;
158
+ const backup_path = join(backups_dir, file);
159
+ try {
160
+ const meta = JSON.parse(await readFile(`${backup_path}.meta.json`, "utf-8"));
161
+ if (typeof meta.original_path !== "string" || typeof meta.created_at !== "string") continue;
162
+ backups.push({
163
+ path: backup_path,
164
+ original_path: meta.original_path,
165
+ created_at: meta.created_at
166
+ });
167
+ } catch {}
168
+ }
169
+ return backups.sort((a, b) => b.created_at.localeCompare(a.created_at));
170
+ } catch {
171
+ return [];
172
+ }
173
+ }
174
+ async function restore_config_backup(backup_path) {
175
+ const backup = (await list_config_backups()).find((candidate) => candidate.path === backup_path || basename(candidate.path) === backup_path);
176
+ if (!backup) throw new Error(`Config backup '${backup_path}' not found.`);
177
+ const content = await readFile(backup.path, "utf-8");
178
+ const parsed = JSON.parse(content);
179
+ await safe_json_write(backup.original_path, parsed);
180
+ return backup;
181
+ }
182
+ //#endregion
183
+ export { get_server_registry_path as S, get_plugin_backup_filename as _, get_backup_filename as a, get_profiles_dir as b, get_claude_settings_path as c, get_disabled_hooks_path as d, get_installed_plugins_path as f, get_mcpick_dir as g, get_marketplaces_dir as h, ensure_directory_exists as i, get_current_project_path as l, get_marketplace_manifest_path as m, restore_config_backup as n, get_backups_dir as o, get_known_marketplaces_path as p, safe_json_write as r, get_claude_config_path as s, list_config_backups as t, get_dev_overrides_path as u, get_plugin_cache_dir as v, get_project_mcp_json_path as x, get_profile_path as y };
184
+
185
+ //# sourceMappingURL=safe-apply-B5flt8QC.js.map
@@ -1,5 +1,5 @@
1
1
  import { o as run_skills_cli, s as split_cli_list } from "./index.js";
2
- import { n as output, t as error } from "./output-BS1TMOWt.js";
2
+ import { n as output, t as error } from "./output-DGPi2IWN.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-pvyQ17XU.js.map
216
+ //# sourceMappingURL=skills-zuQ5kCL1.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcpick",
3
- "version": "0.0.25",
3
+ "version": "0.0.26",
4
4
  "description": "Vendor-neutral MCP configuration manager with first-class Claude Code support",
5
5
  "keywords": [
6
6
  "claude",
@@ -31,15 +31,15 @@
31
31
  "type": "module",
32
32
  "main": "./dist/index.js",
33
33
  "dependencies": {
34
- "@clack/prompts": "^1.3.0",
34
+ "@clack/prompts": "^1.4.0",
35
35
  "citty": "^0.2.2",
36
- "valibot": "^1.3.1"
36
+ "valibot": "^1.4.0"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@changesets/cli": "^2.31.0",
40
- "@types/node": "^25.6.0",
41
- "vite-plus": "^0.1.20",
42
- "vitest": "^4.1.5"
40
+ "@types/node": "^25.9.0",
41
+ "vite-plus": "^0.2.0",
42
+ "vitest": "^4.1.6"
43
43
  },
44
44
  "engines": {
45
45
  "node": ">=22.0.0"
@@ -0,0 +1 @@
1
+ minimumReleaseAge: 2880