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,171 @@
1
+ import { c as get_disabled_hooks_path, f as get_marketplaces_dir, p as get_mcpick_dir, t as ensure_directory_exists } from "./paths-BPISiJi4.js";
2
+ import { readFile, writeFile } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ //#region src/core/hook-state.ts
5
+ async function read_disabled_hooks() {
6
+ try {
7
+ const content = await readFile(get_disabled_hooks_path(), "utf-8");
8
+ return JSON.parse(content);
9
+ } catch {
10
+ return [];
11
+ }
12
+ }
13
+ async function write_disabled_hooks(entries) {
14
+ await ensure_directory_exists(get_mcpick_dir());
15
+ await writeFile(get_disabled_hooks_path(), JSON.stringify(entries, null, " "), "utf-8");
16
+ }
17
+ /**
18
+ * Remove a specific hook handler from a hooks.json file by matching the handler.
19
+ * Returns true if the hook was found and removed.
20
+ */
21
+ async function remove_hook_from_file(hooks_path, event, handler) {
22
+ let content;
23
+ try {
24
+ content = await readFile(hooks_path, "utf-8");
25
+ } catch {
26
+ return false;
27
+ }
28
+ const hooks_data = JSON.parse(content);
29
+ const hooks_obj = hooks_data.hooks || hooks_data;
30
+ const matchers = hooks_obj[event];
31
+ if (!matchers) return false;
32
+ let removed = false;
33
+ for (const m of matchers) {
34
+ const idx = m.hooks?.findIndex((h) => h.type === handler.type && h.command === handler.command && h.url === handler.url && h.prompt === handler.prompt);
35
+ if (idx !== void 0 && idx >= 0) {
36
+ m.hooks.splice(idx, 1);
37
+ removed = true;
38
+ if (m.hooks.length === 0) matchers.splice(matchers.indexOf(m), 1);
39
+ break;
40
+ }
41
+ }
42
+ if (!removed) return false;
43
+ if (matchers.length === 0) delete hooks_obj[event];
44
+ await writeFile(hooks_path, JSON.stringify(hooks_data, null, " "), "utf-8");
45
+ return true;
46
+ }
47
+ /**
48
+ * Get all hooks.json paths for a plugin (cache + marketplace source).
49
+ */
50
+ function get_all_hooks_paths(plugin_key, primary_path) {
51
+ const paths = [primary_path];
52
+ const at_index = plugin_key.lastIndexOf("@");
53
+ if (at_index > 0) {
54
+ const plugin_name = plugin_key.substring(0, at_index);
55
+ const marketplace_name = plugin_key.substring(at_index + 1);
56
+ paths.push(join(get_marketplaces_dir(), marketplace_name, "plugins", plugin_name, "hooks", "hooks.json"));
57
+ }
58
+ return [...new Set(paths)];
59
+ }
60
+ /**
61
+ * Disable a specific hook from a plugin.
62
+ * Removes from both cache and marketplace source hooks.json files.
63
+ */
64
+ async function disable_plugin_hook(entry) {
65
+ if (!entry.hooks_json_path || !entry.plugin_key) throw new Error("Not a plugin hook");
66
+ const disabled = await read_disabled_hooks();
67
+ disabled.push({
68
+ plugin_key: entry.plugin_key,
69
+ hooks_json_path: entry.hooks_json_path,
70
+ event: entry.event,
71
+ matcher: entry.matcher,
72
+ matcher_index: entry.matcher_index,
73
+ hook_index: entry.hook_index,
74
+ original_handler: entry.handler,
75
+ disabled_at: (/* @__PURE__ */ new Date()).toISOString()
76
+ });
77
+ await write_disabled_hooks(disabled);
78
+ const all_paths = get_all_hooks_paths(entry.plugin_key, entry.hooks_json_path);
79
+ for (const hooks_path of all_paths) await remove_hook_from_file(hooks_path, entry.event, entry.handler);
80
+ }
81
+ /**
82
+ * Add a hook handler back into a hooks.json file.
83
+ */
84
+ async function add_hook_to_file(hooks_path, event, matcher_pattern, handler) {
85
+ let hooks_data;
86
+ try {
87
+ const content = await readFile(hooks_path, "utf-8");
88
+ hooks_data = JSON.parse(content);
89
+ } catch {
90
+ hooks_data = { hooks: {} };
91
+ }
92
+ const hooks_obj = hooks_data.hooks || (hooks_data.hooks = {});
93
+ if (!hooks_obj[event]) hooks_obj[event] = [];
94
+ const matchers = hooks_obj[event];
95
+ let matcher = matchers.find((m) => (m.matcher || void 0) === matcher_pattern);
96
+ if (!matcher) {
97
+ matcher = { hooks: [] };
98
+ if (matcher_pattern) matcher.matcher = matcher_pattern;
99
+ matchers.push(matcher);
100
+ }
101
+ if (matcher.hooks.some((h) => h.type === handler.type && h.command === handler.command && h.url === handler.url && h.prompt === handler.prompt)) return;
102
+ matcher.hooks.push(handler);
103
+ await writeFile(hooks_path, JSON.stringify(hooks_data, null, " "), "utf-8");
104
+ }
105
+ /**
106
+ * Re-enable a previously disabled plugin hook.
107
+ * Restores to both cache and marketplace source hooks.json files.
108
+ */
109
+ async function enable_plugin_hook(disabled_entry) {
110
+ const all_paths = get_all_hooks_paths(disabled_entry.plugin_key, disabled_entry.hooks_json_path);
111
+ for (const hooks_path of all_paths) await add_hook_to_file(hooks_path, disabled_entry.event, disabled_entry.matcher, disabled_entry.original_handler);
112
+ 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)));
113
+ }
114
+ /**
115
+ * Check if any previously disabled hooks have been restored (e.g. by marketplace update).
116
+ * Returns entries that were re-added and need to be re-disabled.
117
+ */
118
+ async function check_restored_hooks() {
119
+ const disabled = await read_disabled_hooks();
120
+ if (disabled.length === 0) return [];
121
+ const restored = [];
122
+ for (const entry of disabled) {
123
+ const all_paths = get_all_hooks_paths(entry.plugin_key, entry.hooks_json_path);
124
+ let found = false;
125
+ for (const hooks_path of all_paths) {
126
+ let hooks_data;
127
+ try {
128
+ const content = await readFile(hooks_path, "utf-8");
129
+ hooks_data = JSON.parse(content);
130
+ } catch {
131
+ continue;
132
+ }
133
+ const matchers = (hooks_data.hooks || hooks_data)[entry.event];
134
+ if (!matchers) continue;
135
+ for (const m of matchers) {
136
+ if ((m.matcher || void 0) !== entry.matcher) continue;
137
+ 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))) {
138
+ found = true;
139
+ break;
140
+ }
141
+ }
142
+ if (found) break;
143
+ }
144
+ if (found) restored.push(entry);
145
+ }
146
+ return restored;
147
+ }
148
+ /**
149
+ * Re-disable hooks that were restored by a marketplace update.
150
+ */
151
+ async function redisable_restored_hooks(restored) {
152
+ let success = 0;
153
+ let failed = 0;
154
+ for (const entry of restored) try {
155
+ const all_paths = get_all_hooks_paths(entry.plugin_key, entry.hooks_json_path);
156
+ let any_removed = false;
157
+ for (const hooks_path of all_paths) if (await remove_hook_from_file(hooks_path, entry.event, entry.original_handler)) any_removed = true;
158
+ if (any_removed) success++;
159
+ else failed++;
160
+ } catch {
161
+ failed++;
162
+ }
163
+ return {
164
+ success,
165
+ failed
166
+ };
167
+ }
168
+ //#endregion
169
+ export { redisable_restored_hooks as a, read_disabled_hooks as i, disable_plugin_hook as n, enable_plugin_hook as r, check_restored_hooks as t };
170
+
171
+ //# sourceMappingURL=hook-state-Di8lUsPr.js.map
@@ -0,0 +1,280 @@
1
+ import { o as remove_hook, r as get_all_hooks, t as add_hook } from "./settings-DEcWtzLE.js";
2
+ import { a as redisable_restored_hooks, i as read_disabled_hooks, n as disable_plugin_hook, r as enable_plugin_hook, t as check_restored_hooks } from "./hook-state-Di8lUsPr.js";
3
+ import { n as output, t as error } from "./output-BchYq0mR.js";
4
+ import { defineCommand } from "citty";
5
+ var hooks_default = defineCommand({
6
+ meta: {
7
+ name: "hooks",
8
+ description: "Manage hooks (settings + plugin). Disable individual plugin hooks, add/remove settings hooks."
9
+ },
10
+ subCommands: {
11
+ list: defineCommand({
12
+ meta: {
13
+ name: "list",
14
+ description: "List all configured hooks (settings + plugins + disabled)"
15
+ },
16
+ args: {
17
+ scope: {
18
+ type: "string",
19
+ description: "Filter by source: user, project, project-local, or plugin"
20
+ },
21
+ json: {
22
+ type: "boolean",
23
+ description: "Output as JSON",
24
+ default: false
25
+ }
26
+ },
27
+ async run({ args }) {
28
+ const hooks = await get_all_hooks();
29
+ const disabled = await read_disabled_hooks();
30
+ const filtered = args.scope ? hooks.filter((h) => h.source === args.scope || h.scope === args.scope) : hooks;
31
+ if (args.json) output({
32
+ active: filtered,
33
+ disabled
34
+ }, true);
35
+ else {
36
+ if (filtered.length === 0 && disabled.length === 0) {
37
+ console.log("No hooks configured.");
38
+ return;
39
+ }
40
+ if (filtered.length > 0) for (let i = 0; i < filtered.length; i++) {
41
+ const h = filtered[i];
42
+ const detail = h.handler.command || h.handler.url || h.handler.prompt || "(unknown)";
43
+ const matcher_str = h.matcher ? ` [${h.matcher}]` : "";
44
+ const source = h.source === "plugin" ? `plugin: ${h.plugin_key}` : h.scope;
45
+ console.log(`${i}: [${source}] ${h.event}${matcher_str} → ${h.handler.type}: ${detail}`);
46
+ }
47
+ if (disabled.length > 0) {
48
+ console.log("\nDisabled:");
49
+ for (let i = 0; i < disabled.length; i++) {
50
+ const d = disabled[i];
51
+ const detail = d.original_handler.command || d.original_handler.url || d.original_handler.prompt || "(unknown)";
52
+ const matcher_str = d.matcher ? ` [${d.matcher}]` : "";
53
+ console.log(`${i}: [${d.plugin_key}] ${d.event}${matcher_str} → ${d.original_handler.type}: ${detail}`);
54
+ }
55
+ }
56
+ }
57
+ }
58
+ }),
59
+ disable: defineCommand({
60
+ meta: {
61
+ name: "disable",
62
+ description: "Disable a hook by index (use \"hooks list\" to see indices)"
63
+ },
64
+ args: {
65
+ index: {
66
+ type: "positional",
67
+ description: "Hook index from \"hooks list\" (0-based)",
68
+ required: true
69
+ },
70
+ json: {
71
+ type: "boolean",
72
+ description: "Output as JSON",
73
+ default: false
74
+ }
75
+ },
76
+ async run({ args }) {
77
+ const hooks = await get_all_hooks();
78
+ const idx = parseInt(args.index, 10);
79
+ if (isNaN(idx) || idx < 0 || idx >= hooks.length) error(`Invalid index: ${args.index}. Run "mcpick hooks list" to see available hooks (0-${hooks.length - 1}).`);
80
+ const entry = hooks[idx];
81
+ if (entry.source === "plugin") {
82
+ await disable_plugin_hook(entry);
83
+ if (args.json) output({
84
+ disabled: true,
85
+ event: entry.event,
86
+ plugin_key: entry.plugin_key
87
+ }, true);
88
+ else {
89
+ console.log(`Disabled: ${entry.event} from ${entry.plugin_key}`);
90
+ console.log("Restart Claude Code for changes to take effect.");
91
+ }
92
+ } else {
93
+ await remove_hook(entry);
94
+ if (args.json) output({
95
+ removed: true,
96
+ event: entry.event,
97
+ scope: entry.scope
98
+ }, true);
99
+ else console.log(`Removed: ${entry.event} (${entry.scope})`);
100
+ }
101
+ }
102
+ }),
103
+ enable: defineCommand({
104
+ meta: {
105
+ name: "enable",
106
+ description: "Re-enable a disabled hook by index (use \"hooks list\" to see disabled hooks)"
107
+ },
108
+ args: {
109
+ index: {
110
+ type: "positional",
111
+ description: "Disabled hook index from \"hooks list\" (0-based)",
112
+ required: true
113
+ },
114
+ json: {
115
+ type: "boolean",
116
+ description: "Output as JSON",
117
+ default: false
118
+ }
119
+ },
120
+ async run({ args }) {
121
+ const disabled = await read_disabled_hooks();
122
+ const idx = parseInt(args.index, 10);
123
+ if (isNaN(idx) || idx < 0 || idx >= disabled.length) error(`Invalid index: ${args.index}. Run "mcpick hooks list" to see disabled hooks (0-${disabled.length - 1}).`);
124
+ const entry = disabled[idx];
125
+ await enable_plugin_hook(entry);
126
+ if (args.json) output({
127
+ enabled: true,
128
+ event: entry.event,
129
+ plugin_key: entry.plugin_key
130
+ }, true);
131
+ else {
132
+ console.log(`Re-enabled: ${entry.event} for ${entry.plugin_key}`);
133
+ console.log("Restart Claude Code for changes to take effect.");
134
+ }
135
+ }
136
+ }),
137
+ add: defineCommand({
138
+ meta: {
139
+ name: "add",
140
+ description: "Add a new settings-based hook"
141
+ },
142
+ args: {
143
+ event: {
144
+ type: "positional",
145
+ description: "Hook event type (e.g. UserPromptSubmit, PreToolUse)",
146
+ required: true
147
+ },
148
+ handler_type: {
149
+ type: "positional",
150
+ description: "Handler type: command, prompt, http, or agent",
151
+ required: true
152
+ },
153
+ value: {
154
+ type: "positional",
155
+ description: "Handler value (command string, prompt text, URL, or agent prompt)",
156
+ required: true
157
+ },
158
+ matcher: {
159
+ type: "string",
160
+ description: "Matcher pattern (e.g. Bash, Edit|Write) — only for tool/session events"
161
+ },
162
+ scope: {
163
+ type: "string",
164
+ description: "Scope: user, project, or project-local (default: user)",
165
+ default: "user"
166
+ },
167
+ json: {
168
+ type: "boolean",
169
+ description: "Output as JSON",
170
+ default: false
171
+ }
172
+ },
173
+ async run({ args }) {
174
+ const scope = args.scope;
175
+ if (![
176
+ "user",
177
+ "project",
178
+ "project-local"
179
+ ].includes(scope)) error(`Invalid scope: ${scope}. Use user, project, or project-local.`);
180
+ const handler_type = args.handler_type;
181
+ if (![
182
+ "command",
183
+ "prompt",
184
+ "http",
185
+ "agent"
186
+ ].includes(handler_type)) error(`Invalid handler type: ${handler_type}. Use command, prompt, http, or agent.`);
187
+ const handler = { type: handler_type };
188
+ if (handler_type === "command") handler.command = args.value;
189
+ else if (handler_type === "prompt") handler.prompt = args.value;
190
+ else if (handler_type === "http") handler.url = args.value;
191
+ else if (handler_type === "agent") handler.prompt = args.value;
192
+ await add_hook(scope, args.event, args.matcher || void 0, handler);
193
+ if (args.json) output({
194
+ added: true,
195
+ event: args.event,
196
+ handler_type,
197
+ scope,
198
+ matcher: args.matcher || null
199
+ }, true);
200
+ else console.log(`Hook added: ${args.event} → ${handler_type} (${scope})`);
201
+ }
202
+ }),
203
+ remove: defineCommand({
204
+ meta: {
205
+ name: "remove",
206
+ description: "Remove a settings hook by index (use \"hooks list\" to see indices)"
207
+ },
208
+ args: {
209
+ index: {
210
+ type: "positional",
211
+ description: "Hook index from \"hooks list\" (0-based)",
212
+ required: true
213
+ },
214
+ json: {
215
+ type: "boolean",
216
+ description: "Output as JSON",
217
+ default: false
218
+ }
219
+ },
220
+ async run({ args }) {
221
+ const settings_hooks = (await get_all_hooks()).filter((h) => h.source !== "plugin");
222
+ const idx = parseInt(args.index, 10);
223
+ if (isNaN(idx) || idx < 0 || idx >= settings_hooks.length) error(`Invalid index: ${args.index}. Use "mcpick hooks list" to see settings hooks.`);
224
+ const entry = settings_hooks[idx];
225
+ await remove_hook(entry);
226
+ if (args.json) output({
227
+ removed: true,
228
+ event: entry.event,
229
+ scope: entry.scope
230
+ }, true);
231
+ else {
232
+ const detail = entry.handler.command || entry.handler.url || entry.handler.prompt || "(unknown)";
233
+ console.log(`Removed: [${entry.scope}] ${entry.event} → ${entry.handler.type}: ${detail}`);
234
+ }
235
+ }
236
+ }),
237
+ check: defineCommand({
238
+ meta: {
239
+ name: "check",
240
+ description: "Check if marketplace updates restored any disabled hooks"
241
+ },
242
+ args: {
243
+ fix: {
244
+ type: "boolean",
245
+ description: "Automatically re-disable restored hooks",
246
+ default: false
247
+ },
248
+ json: {
249
+ type: "boolean",
250
+ description: "Output as JSON",
251
+ default: false
252
+ }
253
+ },
254
+ async run({ args }) {
255
+ const restored = await check_restored_hooks();
256
+ if (args.json) {
257
+ output({
258
+ restored: restored.length,
259
+ hooks: restored
260
+ }, true);
261
+ return;
262
+ }
263
+ if (restored.length === 0) {
264
+ console.log("No disabled hooks were restored. All good.");
265
+ return;
266
+ }
267
+ console.log(`${restored.length} disabled hook(s) were restored:`);
268
+ for (const r of restored) console.log(` ${r.plugin_key}: ${r.event}`);
269
+ if (args.fix) {
270
+ const result = await redisable_restored_hooks(restored);
271
+ console.log(`Re-disabled ${result.success} hook(s).${result.failed > 0 ? ` Failed: ${result.failed}` : ""}`);
272
+ } else console.log("Run with --fix to re-disable, or use \"mcpick hooks disable\".");
273
+ }
274
+ })
275
+ }
276
+ });
277
+ //#endregion
278
+ export { hooks_default as default };
279
+
280
+ //# sourceMappingURL=hooks-Bmn7pUZa.js.map