mcpick 0.0.13 → 0.0.14

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # mcpick
2
2
 
3
+ ## 0.0.14
4
+
5
+ ### Patch Changes
6
+
7
+ - 0170ea0: Add local dev workflow: mcpick dev + cache link/unlink
8
+
3
9
  ## 0.0.13
4
10
 
5
11
  ### Patch Changes
@@ -1,5 +1,5 @@
1
1
  import { defineCommand } from 'citty';
2
- import { clean_orphaned_versions, clear_plugin_caches, get_cached_plugins_info, read_installed_plugins, refresh_all_marketplaces, } from '../../core/plugin-cache.js';
2
+ import { clean_orphaned_versions, clear_plugin_caches, get_cached_plugins_info, link_local_plugin, list_linked_plugins, read_installed_plugins, refresh_all_marketplaces, unlink_local_plugin, } from '../../core/plugin-cache.js';
3
3
  import { error, output } from '../output.js';
4
4
  const status = defineCommand({
5
5
  meta: {
@@ -166,6 +166,111 @@ const refresh = defineCommand({
166
166
  }
167
167
  },
168
168
  });
169
+ const link = defineCommand({
170
+ meta: {
171
+ name: 'link',
172
+ description: 'Symlink a local directory into the plugin cache for dev',
173
+ },
174
+ args: {
175
+ path: {
176
+ type: 'positional',
177
+ description: 'Local path to the plugin/marketplace directory',
178
+ required: true,
179
+ },
180
+ as: {
181
+ type: 'string',
182
+ description: 'Plugin key (name@marketplace) for the cache entry',
183
+ required: true,
184
+ },
185
+ json: {
186
+ type: 'boolean',
187
+ description: 'Output as JSON',
188
+ default: false,
189
+ },
190
+ },
191
+ async run({ args }) {
192
+ if (!args.as) {
193
+ error('--as is required. Specify plugin key as name@marketplace.');
194
+ }
195
+ if (!args.as.includes('@')) {
196
+ error('Plugin key must be in name@marketplace format (e.g. my-plugin@my-marketplace)');
197
+ }
198
+ const result = await link_local_plugin(args.path, args.as);
199
+ if (args.json) {
200
+ output(result, true);
201
+ }
202
+ else if (result.success) {
203
+ console.log(`Linked: ${result.key}`);
204
+ console.log(` ${result.symlinkPath} → ${result.targetPath}`);
205
+ console.log('\nRun /reload-plugins in Claude Code or restart your session.');
206
+ }
207
+ else {
208
+ error(result.error || 'Unknown error');
209
+ }
210
+ },
211
+ });
212
+ const unlink = defineCommand({
213
+ meta: {
214
+ name: 'unlink',
215
+ description: 'Remove a symlink from the plugin cache',
216
+ },
217
+ args: {
218
+ key: {
219
+ type: 'positional',
220
+ description: 'Plugin key (name@marketplace)',
221
+ required: true,
222
+ },
223
+ json: {
224
+ type: 'boolean',
225
+ description: 'Output as JSON',
226
+ default: false,
227
+ },
228
+ },
229
+ async run({ args }) {
230
+ const result = await unlink_local_plugin(args.key);
231
+ if (args.json) {
232
+ output(result, true);
233
+ }
234
+ else if (result.success) {
235
+ console.log(`Unlinked: ${args.key}`);
236
+ if (result.restored) {
237
+ console.log(' Original cache directory restored from backup.');
238
+ }
239
+ console.log('\nRun /reload-plugins in Claude Code or restart your session.');
240
+ }
241
+ else {
242
+ error(result.error || 'Unknown error');
243
+ }
244
+ },
245
+ });
246
+ const links = defineCommand({
247
+ meta: {
248
+ name: 'links',
249
+ description: 'List all symlinked plugin cache entries',
250
+ },
251
+ args: {
252
+ json: {
253
+ type: 'boolean',
254
+ description: 'Output as JSON',
255
+ default: false,
256
+ },
257
+ },
258
+ async run({ args }) {
259
+ const linked = await list_linked_plugins();
260
+ if (args.json) {
261
+ output(linked, true);
262
+ return;
263
+ }
264
+ if (linked.length === 0) {
265
+ console.log('No linked plugins.');
266
+ return;
267
+ }
268
+ for (const l of linked) {
269
+ console.log(`${l.key}`);
270
+ console.log(` ${l.symlinkPath} → ${l.targetPath}`);
271
+ }
272
+ },
273
+ });
169
274
  export default defineCommand({
170
275
  meta: {
171
276
  name: 'cache',
@@ -176,6 +281,9 @@ export default defineCommand({
176
281
  clear,
177
282
  'clean-orphaned': clean_orphaned,
178
283
  refresh,
284
+ link,
285
+ unlink,
286
+ links,
179
287
  },
180
288
  });
181
289
  //# sourceMappingURL=cache.js.map
@@ -0,0 +1,162 @@
1
+ import { defineCommand } from 'citty';
2
+ import { apply_dev_override, list_dev_overrides, restore_all_dev_overrides, restore_dev_override, } from '../../core/dev-override.js';
3
+ import { error, output } from '../output.js';
4
+ const apply = defineCommand({
5
+ meta: {
6
+ name: 'apply',
7
+ description: 'Override an MCP server with a local dev command',
8
+ },
9
+ args: {
10
+ name: {
11
+ type: 'positional',
12
+ description: 'Server name to override',
13
+ required: true,
14
+ },
15
+ command: {
16
+ type: 'string',
17
+ description: 'Local command to run',
18
+ required: true,
19
+ },
20
+ args: {
21
+ type: 'string',
22
+ description: 'Comma-separated arguments',
23
+ },
24
+ scope: {
25
+ type: 'string',
26
+ description: 'Scope to search: local, project, or user (default: auto-detect)',
27
+ },
28
+ json: {
29
+ type: 'boolean',
30
+ description: 'Output as JSON',
31
+ default: false,
32
+ },
33
+ },
34
+ async run({ args }) {
35
+ const scope = args.scope;
36
+ if (scope && !['local', 'project', 'user'].includes(scope)) {
37
+ error(`Invalid scope: ${scope}. Use local, project, or user.`);
38
+ }
39
+ const cmd_args = args.args
40
+ ? args.args.split(',')
41
+ : [];
42
+ const result = await apply_dev_override(args.name, args.command, cmd_args, scope);
43
+ if (args.json) {
44
+ output(result, true);
45
+ }
46
+ else if (result.success) {
47
+ console.log(`Dev override applied for '${args.name}' (scope: ${result.scope})`);
48
+ console.log(` command: ${args.command}${cmd_args.length > 0 ? ` ${cmd_args.join(' ')}` : ''}`);
49
+ console.log('\nRestart Claude Code or run /reload-plugins to pick up changes.');
50
+ }
51
+ else {
52
+ error(result.error || 'Unknown error');
53
+ }
54
+ },
55
+ });
56
+ const restore = defineCommand({
57
+ meta: {
58
+ name: 'restore',
59
+ description: 'Restore original server config from dev override',
60
+ },
61
+ args: {
62
+ name: {
63
+ type: 'positional',
64
+ description: 'Server name to restore (omit with --all to restore all)',
65
+ required: false,
66
+ },
67
+ all: {
68
+ type: 'boolean',
69
+ description: 'Restore all dev overrides',
70
+ default: false,
71
+ },
72
+ json: {
73
+ type: 'boolean',
74
+ description: 'Output as JSON',
75
+ default: false,
76
+ },
77
+ },
78
+ async run({ args }) {
79
+ if (args.all) {
80
+ const result = await restore_all_dev_overrides();
81
+ if (args.json) {
82
+ output(result, true);
83
+ }
84
+ else {
85
+ if (result.restored.length === 0 && result.errors.length === 0) {
86
+ console.log('No dev overrides to restore.');
87
+ }
88
+ else {
89
+ for (const name of result.restored) {
90
+ console.log(`Restored: ${name}`);
91
+ }
92
+ for (const err of result.errors) {
93
+ console.error(`Error: ${err}`);
94
+ }
95
+ }
96
+ }
97
+ return;
98
+ }
99
+ if (!args.name) {
100
+ error('Specify a server name or use --all. Run "mcpick dev list" to see active overrides.');
101
+ }
102
+ const result = await restore_dev_override(args.name);
103
+ if (args.json) {
104
+ output(result, true);
105
+ }
106
+ else if (result.success) {
107
+ console.log(`Restored original config for '${args.name}'`);
108
+ console.log('\nRestart Claude Code or run /reload-plugins to pick up changes.');
109
+ }
110
+ else {
111
+ error(result.error || 'Unknown error');
112
+ }
113
+ },
114
+ });
115
+ const list = defineCommand({
116
+ meta: {
117
+ name: 'list',
118
+ description: 'List active dev overrides',
119
+ },
120
+ args: {
121
+ json: {
122
+ type: 'boolean',
123
+ description: 'Output as JSON',
124
+ default: false,
125
+ },
126
+ },
127
+ async run({ args }) {
128
+ const overrides = await list_dev_overrides();
129
+ if (args.json) {
130
+ output(overrides, true);
131
+ return;
132
+ }
133
+ if (overrides.length === 0) {
134
+ console.log('No active dev overrides.');
135
+ return;
136
+ }
137
+ for (const o of overrides) {
138
+ const orig = o.original;
139
+ const dev = o.dev;
140
+ const original_cmd = orig.command
141
+ ? `${orig.command}${orig.args ? ' ' + orig.args.join(' ') : ''}`
142
+ : orig.url || '?';
143
+ const dev_cmd = `${dev.command}${dev.args ? ' ' + dev.args.join(' ') : ''}`;
144
+ console.log(`${o.name} (scope: ${o.scope})`);
145
+ console.log(` original: ${original_cmd}`);
146
+ console.log(` dev: ${dev_cmd}`);
147
+ console.log(` since: ${o.createdAt}`);
148
+ }
149
+ },
150
+ });
151
+ export default defineCommand({
152
+ meta: {
153
+ name: 'dev',
154
+ description: 'MCP server local development workflow',
155
+ },
156
+ subCommands: {
157
+ apply,
158
+ restore,
159
+ list,
160
+ },
161
+ });
162
+ //# sourceMappingURL=dev.js.map
package/dist/cli/index.js CHANGED
@@ -15,6 +15,7 @@ const main = defineCommand({
15
15
  profile: () => import('./commands/profile.js').then((m) => m.default),
16
16
  plugins: () => import('./commands/plugins.js').then((m) => m.default),
17
17
  cache: () => import('./commands/cache.js').then((m) => m.default),
18
+ dev: () => import('./commands/dev.js').then((m) => m.default),
18
19
  },
19
20
  });
20
21
  export const run = () => runMain(main);
@@ -0,0 +1,210 @@
1
+ import { access, readFile } from 'node:fs/promises';
2
+ import { atomic_json_write } from '../utils/atomic-write.js';
3
+ import { get_claude_config_path, get_current_project_path, get_dev_overrides_path, get_project_mcp_json_path, } from '../utils/paths.js';
4
+ const EMPTY_OVERRIDES = {
5
+ version: 1,
6
+ overrides: {},
7
+ };
8
+ export async function read_dev_overrides() {
9
+ try {
10
+ const content = await readFile(get_dev_overrides_path(), 'utf-8');
11
+ return JSON.parse(content);
12
+ }
13
+ catch {
14
+ return { ...EMPTY_OVERRIDES, overrides: {} };
15
+ }
16
+ }
17
+ async function write_dev_overrides(data) {
18
+ await atomic_json_write(get_dev_overrides_path(), () => data);
19
+ }
20
+ /**
21
+ * Read full config for a given scope and return the server entry if found.
22
+ * Returns { config, server, scope } or null.
23
+ */
24
+ async function find_server_in_scope(name, scope) {
25
+ if (scope === 'user' || scope === 'local') {
26
+ const config_path = get_claude_config_path();
27
+ try {
28
+ await access(config_path);
29
+ const content = await readFile(config_path, 'utf-8');
30
+ const parsed = JSON.parse(content);
31
+ if (scope === 'user') {
32
+ const server = parsed.mcpServers?.[name];
33
+ if (server)
34
+ return { server, scope: 'user' };
35
+ }
36
+ else {
37
+ // local scope: projects[cwd].mcpServers
38
+ const cwd = get_current_project_path();
39
+ const server = parsed.projects?.[cwd]?.mcpServers?.[name];
40
+ if (server)
41
+ return { server, scope: 'local' };
42
+ }
43
+ }
44
+ catch {
45
+ // File doesn't exist
46
+ }
47
+ }
48
+ else if (scope === 'project') {
49
+ const mcp_path = get_project_mcp_json_path();
50
+ try {
51
+ await access(mcp_path);
52
+ const content = await readFile(mcp_path, 'utf-8');
53
+ const parsed = JSON.parse(content);
54
+ const server = parsed.mcpServers?.[name];
55
+ if (server)
56
+ return { server, scope: 'project' };
57
+ }
58
+ catch {
59
+ // File doesn't exist
60
+ }
61
+ }
62
+ return null;
63
+ }
64
+ /**
65
+ * Auto-detect which scope a server lives in.
66
+ * Searches local → project → user.
67
+ */
68
+ async function detect_server_scope(name) {
69
+ for (const scope of ['local', 'project', 'user']) {
70
+ const result = await find_server_in_scope(name, scope);
71
+ if (result)
72
+ return result;
73
+ }
74
+ return null;
75
+ }
76
+ /**
77
+ * Write a server config into the appropriate scope config file.
78
+ */
79
+ async function write_server_to_scope(name, server, scope) {
80
+ if (scope === 'user') {
81
+ await atomic_json_write(get_claude_config_path(), (existing) => {
82
+ if (!existing.mcpServers) {
83
+ existing.mcpServers = {};
84
+ }
85
+ existing.mcpServers[name] =
86
+ server;
87
+ return existing;
88
+ });
89
+ }
90
+ else if (scope === 'local') {
91
+ const cwd = get_current_project_path();
92
+ await atomic_json_write(get_claude_config_path(), (existing) => {
93
+ if (!existing.projects) {
94
+ existing.projects = {};
95
+ }
96
+ const projects = existing.projects;
97
+ if (!projects[cwd]) {
98
+ projects[cwd] = {};
99
+ }
100
+ if (!projects[cwd].mcpServers) {
101
+ projects[cwd].mcpServers = {};
102
+ }
103
+ projects[cwd].mcpServers[name] = server;
104
+ return existing;
105
+ });
106
+ }
107
+ else if (scope === 'project') {
108
+ await atomic_json_write(get_project_mcp_json_path(), (existing) => {
109
+ if (!existing.mcpServers) {
110
+ existing.mcpServers = {};
111
+ }
112
+ existing.mcpServers[name] =
113
+ server;
114
+ return existing;
115
+ });
116
+ }
117
+ }
118
+ /**
119
+ * Apply a dev override: store original config, swap in local dev command.
120
+ */
121
+ export async function apply_dev_override(name, command, args, scope) {
122
+ // Find the server
123
+ let found;
124
+ if (scope) {
125
+ found = await find_server_in_scope(name, scope);
126
+ }
127
+ else {
128
+ found = await detect_server_scope(name);
129
+ }
130
+ if (!found) {
131
+ return {
132
+ success: false,
133
+ scope: scope || 'local',
134
+ error: `Server '${name}' not found${scope ? ` in ${scope} scope` : ' in any scope'}`,
135
+ };
136
+ }
137
+ // Check not already overridden
138
+ const overrides = await read_dev_overrides();
139
+ if (overrides.overrides[name]) {
140
+ return {
141
+ success: false,
142
+ scope: found.scope,
143
+ error: `Server '${name}' already has a dev override. Run 'mcpick dev --restore ${name}' first.`,
144
+ };
145
+ }
146
+ // Build dev server config
147
+ const dev_server = {
148
+ command,
149
+ ...(args.length > 0 ? { args } : {}),
150
+ };
151
+ // Store original
152
+ overrides.overrides[name] = {
153
+ original: found.server,
154
+ dev: dev_server,
155
+ scope: found.scope,
156
+ createdAt: new Date().toISOString(),
157
+ };
158
+ await write_dev_overrides(overrides);
159
+ // Write dev config
160
+ await write_server_to_scope(name, dev_server, found.scope);
161
+ return { success: true, scope: found.scope };
162
+ }
163
+ /**
164
+ * Restore original server config from dev override.
165
+ */
166
+ export async function restore_dev_override(name) {
167
+ const overrides = await read_dev_overrides();
168
+ const entry = overrides.overrides[name];
169
+ if (!entry) {
170
+ return {
171
+ success: false,
172
+ error: `No dev override found for '${name}'`,
173
+ };
174
+ }
175
+ // Write original config back
176
+ await write_server_to_scope(name, entry.original, entry.scope);
177
+ // Remove override entry
178
+ delete overrides.overrides[name];
179
+ await write_dev_overrides(overrides);
180
+ return { success: true };
181
+ }
182
+ /**
183
+ * Restore all dev overrides.
184
+ */
185
+ export async function restore_all_dev_overrides() {
186
+ const overrides = await read_dev_overrides();
187
+ const restored = [];
188
+ const errors = [];
189
+ for (const name of Object.keys(overrides.overrides)) {
190
+ const result = await restore_dev_override(name);
191
+ if (result.success) {
192
+ restored.push(name);
193
+ }
194
+ else {
195
+ errors.push(`${name}: ${result.error}`);
196
+ }
197
+ }
198
+ return { restored, errors };
199
+ }
200
+ /**
201
+ * List all active dev overrides.
202
+ */
203
+ export async function list_dev_overrides() {
204
+ const overrides = await read_dev_overrides();
205
+ return Object.entries(overrides.overrides).map(([name, entry]) => ({
206
+ name,
207
+ ...entry,
208
+ }));
209
+ }
210
+ //# sourceMappingURL=dev-override.js.map
@@ -1,9 +1,9 @@
1
1
  import { exec } from 'node:child_process';
2
- import { readdir, readFile, rm } from 'node:fs/promises';
2
+ import { lstat, readdir, readFile, readlink, rename, rm, symlink } from 'node:fs/promises';
3
3
  import { join, resolve } from 'node:path';
4
4
  import { promisify } from 'node:util';
5
5
  import { atomic_json_write } from '../utils/atomic-write.js';
6
- import { get_installed_plugins_path, get_known_marketplaces_path, get_marketplace_manifest_path, get_plugin_cache_dir, } from '../utils/paths.js';
6
+ import { ensure_directory_exists, get_installed_plugins_path, get_known_marketplaces_path, get_marketplace_manifest_path, get_plugin_cache_dir, } from '../utils/paths.js';
7
7
  const execAsync = promisify(exec);
8
8
  const EMPTY_INSTALLED = {
9
9
  version: 2,
@@ -99,7 +99,7 @@ async function find_orphaned_versions(marketplace, plugin_name) {
99
99
  return orphaned;
100
100
  }
101
101
  // --- Staleness analysis ---
102
- function parse_plugin_key(key) {
102
+ export function parse_plugin_key(key) {
103
103
  const at_index = key.lastIndexOf('@');
104
104
  return {
105
105
  name: at_index > 0 ? key.substring(0, at_index) : key,
@@ -257,4 +257,160 @@ export async function clean_orphaned_versions() {
257
257
  }
258
258
  return { cleaned: cleaned_paths.length, paths: cleaned_paths };
259
259
  }
260
+ // --- Cache linking ---
261
+ /**
262
+ * Symlink a local directory into the plugin cache.
263
+ * Backs up existing cache directory if present.
264
+ */
265
+ export async function link_local_plugin(local_path, key) {
266
+ const resolved_path = resolve(local_path);
267
+ const { name, marketplace } = parse_plugin_key(key);
268
+ // Validate local path exists
269
+ try {
270
+ const stat = await lstat(resolved_path);
271
+ if (!stat.isDirectory()) {
272
+ return {
273
+ success: false,
274
+ key,
275
+ symlinkPath: '',
276
+ targetPath: resolved_path,
277
+ error: `Path is not a directory: ${resolved_path}`,
278
+ };
279
+ }
280
+ }
281
+ catch {
282
+ return {
283
+ success: false,
284
+ key,
285
+ symlinkPath: '',
286
+ targetPath: resolved_path,
287
+ error: `Path does not exist: ${resolved_path}`,
288
+ };
289
+ }
290
+ const cache_dir = get_plugin_cache_dir();
291
+ const plugin_dir = join(cache_dir, marketplace, name);
292
+ // Ensure parent directory exists
293
+ await ensure_directory_exists(join(cache_dir, marketplace));
294
+ // If plugin_dir exists and is not a symlink, back it up
295
+ try {
296
+ const stat = await lstat(plugin_dir);
297
+ if (stat.isSymbolicLink()) {
298
+ // Already a symlink — remove it
299
+ await rm(plugin_dir);
300
+ }
301
+ else if (stat.isDirectory()) {
302
+ // Back up existing directory
303
+ const backup_path = `${plugin_dir}.backup`;
304
+ await rename(plugin_dir, backup_path);
305
+ }
306
+ }
307
+ catch {
308
+ // Doesn't exist — fine
309
+ }
310
+ // Create symlink
311
+ try {
312
+ await symlink(resolved_path, plugin_dir, 'dir');
313
+ }
314
+ catch (err) {
315
+ const msg = err instanceof Error ? err.message : 'Unknown error';
316
+ return {
317
+ success: false,
318
+ key,
319
+ symlinkPath: plugin_dir,
320
+ targetPath: resolved_path,
321
+ error: `Failed to create symlink: ${msg}`,
322
+ };
323
+ }
324
+ return {
325
+ success: true,
326
+ key,
327
+ symlinkPath: plugin_dir,
328
+ targetPath: resolved_path,
329
+ };
330
+ }
331
+ /**
332
+ * Remove a symlink from the plugin cache and restore backup if present.
333
+ */
334
+ export async function unlink_local_plugin(key) {
335
+ const { name, marketplace } = parse_plugin_key(key);
336
+ const cache_dir = get_plugin_cache_dir();
337
+ const plugin_dir = join(cache_dir, marketplace, name);
338
+ // Verify it's actually a symlink
339
+ try {
340
+ const stat = await lstat(plugin_dir);
341
+ if (!stat.isSymbolicLink()) {
342
+ return {
343
+ success: false,
344
+ key,
345
+ restored: false,
346
+ error: `'${key}' is not a symlink — nothing to unlink`,
347
+ };
348
+ }
349
+ }
350
+ catch {
351
+ return {
352
+ success: false,
353
+ key,
354
+ restored: false,
355
+ error: `'${key}' not found in cache`,
356
+ };
357
+ }
358
+ // Remove symlink
359
+ await rm(plugin_dir);
360
+ // Restore backup if present
361
+ const backup_path = `${plugin_dir}.backup`;
362
+ let restored = false;
363
+ try {
364
+ await lstat(backup_path);
365
+ await rename(backup_path, plugin_dir);
366
+ restored = true;
367
+ }
368
+ catch {
369
+ // No backup to restore
370
+ }
371
+ return { success: true, key, restored };
372
+ }
373
+ /**
374
+ * List all symlinked entries in the plugin cache.
375
+ */
376
+ export async function list_linked_plugins() {
377
+ const cache_dir = get_plugin_cache_dir();
378
+ const links = [];
379
+ try {
380
+ const marketplaces = await readdir(cache_dir, { withFileTypes: true });
381
+ for (const mkt of marketplaces) {
382
+ if (!mkt.isDirectory() && !mkt.isSymbolicLink())
383
+ continue;
384
+ const mkt_path = join(cache_dir, mkt.name);
385
+ let entries;
386
+ try {
387
+ entries = await readdir(mkt_path, { withFileTypes: true });
388
+ }
389
+ catch {
390
+ continue;
391
+ }
392
+ for (const entry of entries) {
393
+ const entry_path = join(mkt_path, entry.name);
394
+ try {
395
+ const stat = await lstat(entry_path);
396
+ if (stat.isSymbolicLink()) {
397
+ const target = await readlink(entry_path);
398
+ links.push({
399
+ key: `${entry.name}@${mkt.name}`,
400
+ symlinkPath: entry_path,
401
+ targetPath: resolve(join(cache_dir, mkt.name), target),
402
+ });
403
+ }
404
+ }
405
+ catch {
406
+ // Skip on error
407
+ }
408
+ }
409
+ }
410
+ }
411
+ catch {
412
+ // Cache dir doesn't exist
413
+ }
414
+ return links;
415
+ }
260
416
  //# sourceMappingURL=plugin-cache.js.map
package/dist/index.js CHANGED
@@ -281,6 +281,7 @@ const SUBCOMMANDS = new Set([
281
281
  'profile',
282
282
  'plugins',
283
283
  'cache',
284
+ 'dev',
284
285
  ]);
285
286
  const arg = process.argv[2];
286
287
  if ((arg && SUBCOMMANDS.has(arg)) ||
@@ -31,6 +31,9 @@ export function get_claude_settings_path() {
31
31
  export function get_mcpick_dir() {
32
32
  return join(get_base_dir().baseDir, 'mcpick');
33
33
  }
34
+ export function get_dev_overrides_path() {
35
+ return join(get_mcpick_dir(), 'dev-overrides.json');
36
+ }
34
37
  export function get_server_registry_path() {
35
38
  return join(get_mcpick_dir(), 'servers.json');
36
39
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcpick",
3
- "version": "0.0.13",
3
+ "version": "0.0.14",
4
4
  "description": "Dynamic MCP server and plugin configuration manager for Claude Code",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",