mcpick 0.0.18 → 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 (77) hide show
  1. package/.vscode/settings.json +5 -0
  2. package/CHANGELOG.md +7 -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 -305
  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/clone.js +0 -108
  42. package/dist/cli/commands/dev.js +0 -167
  43. package/dist/cli/commands/disable.js +0 -36
  44. package/dist/cli/commands/enable.js +0 -39
  45. package/dist/cli/commands/get.js +0 -45
  46. package/dist/cli/commands/hooks.js +0 -314
  47. package/dist/cli/commands/list.js +0 -64
  48. package/dist/cli/commands/marketplace.js +0 -211
  49. package/dist/cli/commands/plugins.js +0 -265
  50. package/dist/cli/commands/profile.js +0 -134
  51. package/dist/cli/commands/reload.js +0 -36
  52. package/dist/cli/commands/remove.js +0 -35
  53. package/dist/cli/commands/reset-project-choices.js +0 -32
  54. package/dist/cli/commands/restore.js +0 -105
  55. package/dist/cli/index.js +0 -29
  56. package/dist/cli/output.js +0 -21
  57. package/dist/commands/add-server.js +0 -310
  58. package/dist/commands/backup.js +0 -60
  59. package/dist/commands/edit-config.js +0 -109
  60. package/dist/commands/edit-plugins.js +0 -201
  61. package/dist/commands/manage-cache.js +0 -155
  62. package/dist/commands/manage-hooks.js +0 -99
  63. package/dist/commands/manage-marketplace.js +0 -293
  64. package/dist/commands/restore.js +0 -118
  65. package/dist/core/config.js +0 -200
  66. package/dist/core/dev-override.js +0 -155
  67. package/dist/core/hook-state.js +0 -220
  68. package/dist/core/plugin-cache.js +0 -506
  69. package/dist/core/profile.js +0 -94
  70. package/dist/core/registry.js +0 -121
  71. package/dist/core/settings.js +0 -243
  72. package/dist/core/validation.js +0 -49
  73. package/dist/types.js +0 -2
  74. package/dist/utils/atomic-write.js +0 -27
  75. package/dist/utils/claude-cli.js +0 -485
  76. package/dist/utils/paths.js +0 -114
  77. package/dist/utils/redact.js +0 -28
@@ -1,310 +0,0 @@
1
- import { confirm, log, note, select, text } from '@clack/prompts';
2
- import { add_server_to_registry } from '../core/registry.js';
3
- import { validate_mcp_server } from '../core/validation.js';
4
- import { add_mcp_via_cli, check_claude_cli, get_scope_options, get_scope_description, } from '../utils/claude-cli.js';
5
- function format_server_details(server) {
6
- const details = [`Name: ${server.name}`];
7
- if ('command' in server) {
8
- details.push(`Command: ${server.command} ${(server.args || []).join(' ')}`);
9
- }
10
- if ('url' in server) {
11
- details.push(`URL: ${server.url}`);
12
- }
13
- details.push(`Description: ${server.description || 'None'}`);
14
- if (server.type) {
15
- details.push(`Transport: ${server.type}`);
16
- }
17
- if (server.env) {
18
- details.push(`Environment: ${Object.keys(server.env).length} variables`);
19
- }
20
- if ('headers' in server && server.headers) {
21
- details.push(`Headers: ${Object.keys(server.headers).length} headers`);
22
- }
23
- return details;
24
- }
25
- export async function add_server() {
26
- try {
27
- // Check if Claude CLI is available
28
- const cli_available = await check_claude_cli();
29
- // First, ask where to install the server (scope)
30
- const scope = await select({
31
- message: 'Where should this server be installed?',
32
- options: get_scope_options(),
33
- initialValue: 'local',
34
- });
35
- if (typeof scope === 'symbol')
36
- return;
37
- // Then ask how they want to configure the server
38
- const config_method = await select({
39
- message: 'How would you like to add the server?',
40
- options: [
41
- {
42
- value: 'json',
43
- label: 'Paste JSON configuration',
44
- hint: 'Paste complete server config as JSON',
45
- },
46
- {
47
- value: 'form',
48
- label: 'Step-by-step form',
49
- hint: 'Fill out fields one by one',
50
- },
51
- ],
52
- initialValue: 'json',
53
- });
54
- if (typeof config_method === 'symbol')
55
- return;
56
- if (config_method === 'json') {
57
- return await add_server_from_json(scope, cli_available);
58
- }
59
- const name = await text({
60
- message: 'Server name:',
61
- placeholder: 'e.g., mcp-sqlite-tools',
62
- validate: (value) => {
63
- if (!value || value.trim().length === 0) {
64
- return 'Server name is required';
65
- }
66
- return undefined;
67
- },
68
- });
69
- if (typeof name === 'symbol')
70
- return;
71
- const command = await text({
72
- message: 'Command to run:',
73
- placeholder: 'e.g., uvx, npx, node',
74
- validate: (value) => {
75
- if (!value || value.trim().length === 0) {
76
- return 'Command is required';
77
- }
78
- return undefined;
79
- },
80
- });
81
- if (typeof command === 'symbol')
82
- return;
83
- const args_input = await text({
84
- message: 'Arguments (comma-separated):',
85
- placeholder: 'e.g., mcp-sqlite-tools, --port, 3000',
86
- defaultValue: '',
87
- });
88
- if (typeof args_input === 'symbol')
89
- return;
90
- const args = args_input
91
- .split(',')
92
- .map((arg) => arg.trim())
93
- .filter((arg) => arg.length > 0);
94
- const description = await text({
95
- message: 'Description (optional):',
96
- placeholder: 'Brief description of what this server provides',
97
- });
98
- if (typeof description === 'symbol')
99
- return;
100
- // Advanced configuration
101
- const configure_advanced = await confirm({
102
- message: 'Configure advanced settings (env variables, transport, etc.)?',
103
- initialValue: false,
104
- });
105
- if (typeof configure_advanced === 'symbol')
106
- return;
107
- let server_data = {
108
- name: name.trim(),
109
- type: 'stdio',
110
- command: command.trim(),
111
- args,
112
- ...(description &&
113
- description.trim() && { description: description.trim() }),
114
- };
115
- if (configure_advanced) {
116
- // Transport type
117
- const transport_type = await select({
118
- message: 'Transport type:',
119
- options: [
120
- {
121
- value: 'stdio',
122
- label: 'stdio (default)',
123
- hint: 'Standard input/output',
124
- },
125
- { value: 'sse', label: 'sse', hint: 'Server-sent events' },
126
- { value: 'http', label: 'http', hint: 'HTTP transport' },
127
- ],
128
- initialValue: 'stdio',
129
- });
130
- if (typeof transport_type === 'symbol')
131
- return;
132
- server_data.type = transport_type;
133
- // URL for non-stdio transports
134
- if (transport_type === 'sse' || transport_type === 'http') {
135
- // Remove stdio-specific fields
136
- delete server_data.command;
137
- delete server_data.args;
138
- const url = await text({
139
- message: 'Server URL:',
140
- placeholder: 'e.g., http://localhost:3000',
141
- validate: (value) => {
142
- if (!value || value.trim().length === 0) {
143
- return 'URL is required for non-stdio transport';
144
- }
145
- return undefined;
146
- },
147
- });
148
- if (typeof url === 'symbol')
149
- return;
150
- server_data.url = url.trim();
151
- }
152
- // Environment variables
153
- const env_input = await text({
154
- message: 'Environment variables (KEY=value, comma-separated):',
155
- placeholder: 'e.g., API_KEY=abc123, TIMEOUT=30',
156
- });
157
- if (typeof env_input === 'symbol')
158
- return;
159
- if (env_input && env_input.trim()) {
160
- const env = {};
161
- env_input.split(',').forEach((pair) => {
162
- const [key, ...valueParts] = pair.split('=');
163
- if (key && valueParts.length > 0) {
164
- env[key.trim()] = valueParts.join('=').trim();
165
- }
166
- });
167
- if (Object.keys(env).length > 0) {
168
- server_data.env = env;
169
- }
170
- }
171
- // Headers for HTTP transport
172
- if (transport_type === 'http') {
173
- const headers_input = await text({
174
- message: 'HTTP headers (KEY=value, comma-separated):',
175
- placeholder: 'e.g., Authorization=Bearer token, Content-Type=application/json',
176
- });
177
- if (typeof headers_input === 'symbol')
178
- return;
179
- if (headers_input && headers_input.trim()) {
180
- const headers = {};
181
- headers_input.split(',').forEach((pair) => {
182
- const [key, ...valueParts] = pair.split('=');
183
- if (key && valueParts.length > 0) {
184
- headers[key.trim()] = valueParts.join('=').trim();
185
- }
186
- });
187
- if (Object.keys(headers).length > 0) {
188
- server_data.headers = headers;
189
- }
190
- }
191
- }
192
- }
193
- const validated_server = validate_mcp_server(server_data);
194
- const details = format_server_details(validated_server);
195
- details.push(`Scope: ${get_scope_description(scope)}`);
196
- note(`Server to add:\n${details.join('\n')}`);
197
- const should_add = await confirm({
198
- message: 'Add this server?',
199
- });
200
- if (typeof should_add === 'symbol' || !should_add) {
201
- return;
202
- }
203
- // Always add to registry for profile/backup management
204
- await add_server_to_registry(validated_server);
205
- // Install via Claude CLI if available
206
- if (cli_available) {
207
- const result = await add_mcp_via_cli(validated_server, scope);
208
- if (result.success) {
209
- note(`Server "${validated_server.name}" installed successfully!\n` +
210
- `Scope: ${get_scope_description(scope)}\n` +
211
- `Also added to mcpick registry for profile management.`);
212
- }
213
- else {
214
- log.warn(`CLI installation failed: ${result.error}\n` +
215
- `Server added to registry only. Use 'claude mcp add' manually.`);
216
- }
217
- }
218
- else {
219
- log.warn(`Claude CLI not found. Server added to registry only.\n` +
220
- `Install Claude Code CLI and run 'claude mcp add' to activate.`);
221
- }
222
- }
223
- catch (error) {
224
- throw new Error(`Failed to add server: ${error instanceof Error ? error.message : 'Unknown error'}`);
225
- }
226
- }
227
- async function add_server_from_json(scope, cli_available) {
228
- const json_input = await text({
229
- message: 'Paste JSON configuration:',
230
- placeholder: '{ "name": "mcp-sqlite-tools", "command": "npx", "args": ["-y", "mcp-sqlite-tools"] }',
231
- validate: (value) => {
232
- if (!value || value.trim().length === 0) {
233
- return 'JSON configuration is required';
234
- }
235
- let jsonString = value.trim();
236
- // If it doesn't start with {, wrap it in braces
237
- if (!jsonString.startsWith('{')) {
238
- jsonString = `{${jsonString}}`;
239
- }
240
- try {
241
- const parsed = JSON.parse(jsonString);
242
- if (typeof parsed !== 'object' || parsed === null) {
243
- return 'JSON must be an object';
244
- }
245
- if (!parsed.command) {
246
- return 'Server configuration must include a "command" field';
247
- }
248
- }
249
- catch (error) {
250
- return 'Invalid JSON format';
251
- }
252
- return undefined;
253
- },
254
- });
255
- if (typeof json_input === 'symbol')
256
- return;
257
- try {
258
- let jsonString = json_input.trim();
259
- // If it doesn't start with {, wrap it in braces
260
- if (!jsonString.startsWith('{')) {
261
- jsonString = `{${jsonString}}`;
262
- }
263
- const parsed = JSON.parse(jsonString);
264
- const server_data = parsed;
265
- // Normalize the data to match schema expectations
266
- if (!server_data.type && server_data.command) {
267
- server_data.type = 'stdio';
268
- }
269
- if (server_data.type !== 'stdio') {
270
- delete server_data.command;
271
- delete server_data.args;
272
- }
273
- if (server_data.command && !server_data.args) {
274
- server_data.args = [];
275
- }
276
- const validated_server = validate_mcp_server(server_data);
277
- const details = format_server_details(validated_server);
278
- details.push(`Scope: ${get_scope_description(scope)}`);
279
- note(`Server to add:\n${details.join('\n')}`);
280
- const should_add = await confirm({
281
- message: 'Add this server?',
282
- });
283
- if (typeof should_add === 'symbol' || !should_add) {
284
- return;
285
- }
286
- // Always add to registry for profile/backup management
287
- await add_server_to_registry(validated_server);
288
- // Install via Claude CLI if available
289
- if (cli_available) {
290
- const result = await add_mcp_via_cli(validated_server, scope);
291
- if (result.success) {
292
- note(`Server "${validated_server.name}" installed successfully!\n` +
293
- `Scope: ${get_scope_description(scope)}\n` +
294
- `Also added to mcpick registry for profile management.`);
295
- }
296
- else {
297
- log.warn(`CLI installation failed: ${result.error}\n` +
298
- `Server added to registry only. Use 'claude mcp add' manually.`);
299
- }
300
- }
301
- else {
302
- log.warn(`Claude CLI not found. Server added to registry only.\n` +
303
- `Install Claude Code CLI and run 'claude mcp add' to activate.`);
304
- }
305
- }
306
- catch (error) {
307
- throw new Error(`Failed to parse or validate JSON: ${error instanceof Error ? error.message : 'Unknown error'}`);
308
- }
309
- }
310
- //# sourceMappingURL=add-server.js.map
@@ -1,60 +0,0 @@
1
- import { note } from '@clack/prompts';
2
- import { readdir, unlink, writeFile } from 'node:fs/promises';
3
- import { join } from 'node:path';
4
- import { read_claude_config } from '../core/config.js';
5
- import { read_claude_settings } from '../core/settings.js';
6
- import { ensure_directory_exists, get_backup_filename, get_backups_dir, get_plugin_backup_filename, } from '../utils/paths.js';
7
- const MAX_BACKUPS = 10;
8
- export async function backup_config() {
9
- try {
10
- const current_config = await read_claude_config();
11
- const current_settings = await read_claude_settings();
12
- const backups_dir = get_backups_dir();
13
- await ensure_directory_exists(backups_dir);
14
- // Backup MCP servers
15
- const mcp_filename = get_backup_filename();
16
- const mcp_path = join(backups_dir, mcp_filename);
17
- const mcp_backup = {
18
- mcpServers: current_config.mcpServers || {},
19
- };
20
- await writeFile(mcp_path, JSON.stringify(mcp_backup, null, 2), 'utf-8');
21
- // Backup plugins
22
- const plugins = current_settings.enabledPlugins || {};
23
- const plugin_count = Object.keys(plugins).length;
24
- let plugin_msg = '';
25
- if (plugin_count > 0) {
26
- const plugin_filename = get_plugin_backup_filename();
27
- const plugin_path = join(backups_dir, plugin_filename);
28
- const plugin_backup = { enabledPlugins: plugins };
29
- await writeFile(plugin_path, JSON.stringify(plugin_backup, null, 2), 'utf-8');
30
- plugin_msg = `\nPlugins backup: ${plugin_path}\n(${plugin_count} plugins backed up)`;
31
- }
32
- await cleanup_old_backups('mcp-servers-');
33
- await cleanup_old_backups('plugins-');
34
- const server_count = Object.keys(current_config.mcpServers || {}).length;
35
- note(`MCP servers backup: ${mcp_path}\n(${server_count} servers backed up)${plugin_msg}`);
36
- }
37
- catch (error) {
38
- throw new Error(`Failed to create backup: ${error instanceof Error ? error.message : 'Unknown error'}`);
39
- }
40
- }
41
- async function cleanup_old_backups(prefix) {
42
- try {
43
- const backups_dir = get_backups_dir();
44
- const files = await readdir(backups_dir);
45
- const backup_files = files
46
- .filter((file) => file.startsWith(prefix) && file.endsWith('.json'))
47
- .sort()
48
- .reverse();
49
- if (backup_files.length > MAX_BACKUPS) {
50
- const files_to_delete = backup_files.slice(MAX_BACKUPS);
51
- for (const file of files_to_delete) {
52
- await unlink(join(backups_dir, file));
53
- }
54
- }
55
- }
56
- catch {
57
- // Cleanup is best-effort
58
- }
59
- }
60
- //# sourceMappingURL=backup.js.map
@@ -1,109 +0,0 @@
1
- import { log, multiselect, note, select } from '@clack/prompts';
2
- import { create_config_from_servers, get_enabled_servers, get_enabled_servers_for_scope, read_claude_config, write_claude_config, } from '../core/config.js';
3
- import { get_all_available_servers, sync_servers_to_registry, } from '../core/registry.js';
4
- import { add_mcp_via_cli, check_claude_cli, get_scope_description, get_scope_options, remove_mcp_via_cli, } from '../utils/claude-cli.js';
5
- export async function edit_config() {
6
- try {
7
- // Check if Claude CLI is available
8
- const cli_available = await check_claude_cli();
9
- // Ask which scope to edit
10
- const scope = await select({
11
- message: 'Which configuration do you want to edit?',
12
- options: get_scope_options(),
13
- initialValue: 'local',
14
- });
15
- if (typeof scope === 'symbol')
16
- return;
17
- const current_config = await read_claude_config();
18
- // If registry is empty but .claude.json has servers, populate registry from config
19
- let all_servers = await get_all_available_servers();
20
- if (all_servers.length === 0 && current_config.mcpServers) {
21
- const current_servers = get_enabled_servers(current_config);
22
- if (current_servers.length > 0) {
23
- await sync_servers_to_registry(current_servers);
24
- all_servers = current_servers;
25
- note(`Imported ${current_servers.length} servers from your .claude.json file into registry.`);
26
- }
27
- }
28
- if (all_servers.length === 0) {
29
- note('No MCP servers found in .claude.json or registry. Add servers first.');
30
- return;
31
- }
32
- // Get currently enabled servers for the selected scope
33
- const currently_enabled = await get_enabled_servers_for_scope(scope);
34
- const server_choices = all_servers.map((server) => ({
35
- value: server.name,
36
- label: server.name,
37
- hint: server.description || '',
38
- }));
39
- const selected_server_names = await multiselect({
40
- message: `Select MCP servers for ${get_scope_description(scope)}:`,
41
- options: server_choices,
42
- initialValues: currently_enabled,
43
- required: false,
44
- });
45
- if (typeof selected_server_names === 'symbol') {
46
- return;
47
- }
48
- const selected_servers = all_servers.filter((server) => selected_server_names.includes(server.name));
49
- // Determine which servers to add and remove
50
- const servers_to_add = selected_server_names.filter((name) => !currently_enabled.includes(name));
51
- const servers_to_remove = currently_enabled.filter((name) => !selected_server_names.includes(name));
52
- // If CLI is available, use it for add/remove operations
53
- if (cli_available && (scope === 'local' || scope === 'project')) {
54
- let success_count = 0;
55
- let error_count = 0;
56
- // Add new servers
57
- for (const name of servers_to_add) {
58
- const server = all_servers.find((s) => s.name === name);
59
- if (server) {
60
- const result = await add_mcp_via_cli(server, scope);
61
- if (result.success) {
62
- success_count++;
63
- }
64
- else {
65
- error_count++;
66
- log.warn(`Failed to add ${name}: ${result.error}`);
67
- }
68
- }
69
- }
70
- // Remove servers
71
- for (const name of servers_to_remove) {
72
- const result = await remove_mcp_via_cli(name);
73
- if (result.success) {
74
- success_count++;
75
- }
76
- else {
77
- error_count++;
78
- log.warn(`Failed to remove ${name}: ${result.error}`);
79
- }
80
- }
81
- await sync_servers_to_registry(selected_servers);
82
- if (error_count > 0) {
83
- note(`Configuration updated with ${error_count} errors.\n` +
84
- `Scope: ${get_scope_description(scope)}\n` +
85
- `Added: ${servers_to_add.length}, Removed: ${servers_to_remove.length}`);
86
- }
87
- else {
88
- note(`Configuration updated!\n` +
89
- `Scope: ${get_scope_description(scope)}\n` +
90
- `Enabled servers: ${selected_servers.length}`);
91
- }
92
- }
93
- else {
94
- // Fallback to direct file writing (user scope or no CLI)
95
- const new_config = create_config_from_servers(selected_servers);
96
- await write_claude_config(new_config);
97
- await sync_servers_to_registry(selected_servers);
98
- if (!cli_available && scope !== 'user') {
99
- log.warn(`Claude CLI not available. Changes written to ~/.claude.json (user scope) instead of ${scope} scope.`);
100
- }
101
- note(`Configuration updated!\n` +
102
- `Enabled servers: ${selected_servers.length}`);
103
- }
104
- }
105
- catch (error) {
106
- throw new Error(`Failed to edit configuration: ${error instanceof Error ? error.message : 'Unknown error'}`);
107
- }
108
- }
109
- //# sourceMappingURL=edit-config.js.map
@@ -1,201 +0,0 @@
1
- import { confirm, isCancel, log, multiselect, note, select, text, } from '@clack/prompts';
2
- import { build_enabled_plugins, get_all_plugins, read_claude_settings, write_claude_settings, } from '../core/settings.js';
3
- import { install_plugin_via_cli, uninstall_plugin_via_cli, update_plugin_via_cli, } from '../utils/claude-cli.js';
4
- async function handle_toggle() {
5
- const settings = await read_claude_settings();
6
- const plugins = get_all_plugins(settings);
7
- if (plugins.length === 0) {
8
- note('No plugins found in ~/.claude/settings.json.\n' +
9
- 'Install plugins via Claude Code: /plugin');
10
- return;
11
- }
12
- const plugin_choices = plugins.map((plugin) => ({
13
- value: `${plugin.name}@${plugin.marketplace}`,
14
- label: plugin.name,
15
- hint: plugin.marketplace,
16
- }));
17
- const currently_enabled = plugins
18
- .filter((p) => p.enabled)
19
- .map((p) => `${p.name}@${p.marketplace}`);
20
- const selected = await multiselect({
21
- message: 'Select plugins to enable:',
22
- options: plugin_choices,
23
- initialValues: currently_enabled,
24
- required: false,
25
- });
26
- if (typeof selected === 'symbol')
27
- return;
28
- const selected_set = new Set(selected);
29
- const updated_plugins = plugins.map((plugin) => ({
30
- ...plugin,
31
- enabled: selected_set.has(`${plugin.name}@${plugin.marketplace}`),
32
- }));
33
- const enabled_plugins = build_enabled_plugins(updated_plugins);
34
- await write_claude_settings({ enabledPlugins: enabled_plugins });
35
- const enabled_count = updated_plugins.filter((p) => p.enabled).length;
36
- const disabled_count = updated_plugins.filter((p) => !p.enabled).length;
37
- note(`Plugins updated!\n` +
38
- `Enabled: ${enabled_count}, Disabled: ${disabled_count}`);
39
- const newly_enabled = updated_plugins.filter((p) => p.enabled &&
40
- !currently_enabled.includes(`${p.name}@${p.marketplace}`));
41
- const newly_disabled = updated_plugins.filter((p) => !p.enabled &&
42
- currently_enabled.includes(`${p.name}@${p.marketplace}`));
43
- if (newly_enabled.length > 0) {
44
- log.success(`Enabled: ${newly_enabled.map((p) => p.name).join(', ')}`);
45
- }
46
- if (newly_disabled.length > 0) {
47
- log.warn(`Disabled: ${newly_disabled.map((p) => p.name).join(', ')}`);
48
- }
49
- }
50
- async function handle_install() {
51
- const key = await text({
52
- message: 'Plugin to install (name@marketplace):',
53
- placeholder: 'e.g. commit-commands@claude-plugins-official',
54
- validate: (value) => {
55
- if (!value || value.trim().length === 0) {
56
- return 'Plugin key is required';
57
- }
58
- if (!value.includes('@')) {
59
- return 'Format: plugin-name@marketplace-name';
60
- }
61
- },
62
- });
63
- if (isCancel(key))
64
- return;
65
- const scope = await select({
66
- message: 'Installation scope:',
67
- options: [
68
- { value: 'user', label: 'User', hint: 'Global (default)' },
69
- {
70
- value: 'project',
71
- label: 'Project',
72
- hint: 'Shared with team',
73
- },
74
- {
75
- value: 'local',
76
- label: 'Local',
77
- hint: 'This project only (gitignored)',
78
- },
79
- ],
80
- });
81
- if (isCancel(scope))
82
- return;
83
- const result = await install_plugin_via_cli(key, scope);
84
- if (result.success) {
85
- log.success(`Installed '${key}' (scope: ${scope})`);
86
- }
87
- else {
88
- log.error(result.error ?? 'Unknown error');
89
- }
90
- }
91
- async function handle_uninstall() {
92
- const settings = await read_claude_settings();
93
- const plugins = get_all_plugins(settings);
94
- if (plugins.length === 0) {
95
- log.info('No plugins installed.');
96
- return;
97
- }
98
- const selected = await select({
99
- message: 'Select plugin to uninstall:',
100
- options: plugins.map((p) => ({
101
- value: `${p.name}@${p.marketplace}`,
102
- label: p.name,
103
- hint: p.marketplace,
104
- })),
105
- });
106
- if (isCancel(selected))
107
- return;
108
- const should_uninstall = await confirm({
109
- message: `Uninstall '${selected}'?`,
110
- });
111
- if (isCancel(should_uninstall) || !should_uninstall)
112
- return;
113
- const result = await uninstall_plugin_via_cli(selected);
114
- if (result.success) {
115
- log.success(`Uninstalled '${selected}'`);
116
- }
117
- else {
118
- log.error(result.error ?? 'Unknown error');
119
- }
120
- }
121
- async function handle_update() {
122
- const settings = await read_claude_settings();
123
- const plugins = get_all_plugins(settings);
124
- if (plugins.length === 0) {
125
- log.info('No plugins installed.');
126
- return;
127
- }
128
- const selected = await select({
129
- message: 'Select plugin to update:',
130
- options: plugins.map((p) => ({
131
- value: `${p.name}@${p.marketplace}`,
132
- label: p.name,
133
- hint: p.marketplace,
134
- })),
135
- });
136
- if (isCancel(selected))
137
- return;
138
- const result = await update_plugin_via_cli(selected);
139
- if (result.success) {
140
- log.success(`Updated '${selected}'`);
141
- }
142
- else {
143
- log.error(result.error ?? 'Unknown error');
144
- }
145
- }
146
- export async function edit_plugins() {
147
- while (true) {
148
- const action = await select({
149
- message: 'Plugin management:',
150
- options: [
151
- {
152
- value: 'toggle',
153
- label: 'Enable / Disable plugins',
154
- hint: 'Toggle plugins on/off',
155
- },
156
- {
157
- value: 'install',
158
- label: 'Install plugin',
159
- hint: 'Install from a marketplace',
160
- },
161
- {
162
- value: 'uninstall',
163
- label: 'Uninstall plugin',
164
- hint: 'Remove a plugin entirely',
165
- },
166
- {
167
- value: 'update',
168
- label: 'Update plugin',
169
- hint: 'Update to latest version',
170
- },
171
- {
172
- value: 'back',
173
- label: 'Back',
174
- hint: 'Return to main menu',
175
- },
176
- ],
177
- });
178
- if (isCancel(action) || action === 'back')
179
- return;
180
- try {
181
- switch (action) {
182
- case 'toggle':
183
- await handle_toggle();
184
- break;
185
- case 'install':
186
- await handle_install();
187
- break;
188
- case 'uninstall':
189
- await handle_uninstall();
190
- break;
191
- case 'update':
192
- await handle_update();
193
- break;
194
- }
195
- }
196
- catch (err) {
197
- log.error(err instanceof Error ? err.message : 'Unknown error');
198
- }
199
- }
200
- }
201
- //# sourceMappingURL=edit-plugins.js.map