mcpman 0.7.0 → 0.8.0

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/dist/index.cjs CHANGED
@@ -37,6 +37,166 @@ var init_cjs_shims = __esm({
37
37
  }
38
38
  });
39
39
 
40
+ // src/utils/paths.ts
41
+ function getHomedir() {
42
+ return import_node_os.default.homedir();
43
+ }
44
+ function getMcpmanDir() {
45
+ return import_node_path.default.join(import_node_os.default.homedir(), ".mcpman");
46
+ }
47
+ function getConfigPath() {
48
+ return import_node_path.default.join(getMcpmanDir(), "config.json");
49
+ }
50
+ function getPluginDir() {
51
+ return import_node_path.default.join(getMcpmanDir(), "plugins");
52
+ }
53
+ function getProfilesDir() {
54
+ return import_node_path.default.join(getMcpmanDir(), "profiles");
55
+ }
56
+ function getEnvDir() {
57
+ return import_node_path.default.join(getMcpmanDir(), "env");
58
+ }
59
+ function getGroupsFile() {
60
+ return import_node_path.default.join(getMcpmanDir(), "groups.json");
61
+ }
62
+ function getPinsFile() {
63
+ return import_node_path.default.join(getMcpmanDir(), "pins.json");
64
+ }
65
+ function getRollbackDir() {
66
+ return import_node_path.default.join(getMcpmanDir(), "rollback");
67
+ }
68
+ function getAppDataDir() {
69
+ const home = getHomedir();
70
+ if (process.platform === "darwin") {
71
+ return import_node_path.default.join(home, "Library", "Application Support");
72
+ }
73
+ if (process.platform === "win32") {
74
+ return process.env.APPDATA ?? import_node_path.default.join(home, "AppData", "Roaming");
75
+ }
76
+ return process.env.XDG_CONFIG_HOME ?? import_node_path.default.join(home, ".config");
77
+ }
78
+ function resolveConfigPath(client) {
79
+ const appData = getAppDataDir();
80
+ const home = getHomedir();
81
+ switch (client) {
82
+ case "claude-desktop":
83
+ return import_node_path.default.join(appData, "Claude", "claude_desktop_config.json");
84
+ case "cursor":
85
+ return import_node_path.default.join(appData, "Cursor", "User", "globalStorage", "cursor.mcp", "mcp.json");
86
+ case "windsurf":
87
+ return import_node_path.default.join(
88
+ appData,
89
+ "Windsurf",
90
+ "User",
91
+ "globalStorage",
92
+ "windsurf.mcpConfigJson",
93
+ "mcp.json"
94
+ );
95
+ case "vscode":
96
+ if (process.platform === "darwin") {
97
+ return import_node_path.default.join(appData, "Code", "User", "settings.json");
98
+ }
99
+ if (process.platform === "win32") {
100
+ return import_node_path.default.join(appData, "Code", "User", "settings.json");
101
+ }
102
+ return import_node_path.default.join(home, ".config", "Code", "User", "settings.json");
103
+ }
104
+ }
105
+ var import_node_os, import_node_path;
106
+ var init_paths = __esm({
107
+ "src/utils/paths.ts"() {
108
+ "use strict";
109
+ init_cjs_shims();
110
+ import_node_os = __toESM(require("os"), 1);
111
+ import_node_path = __toESM(require("path"), 1);
112
+ }
113
+ });
114
+
115
+ // src/core/rollback-service.ts
116
+ function ensureDir(dir) {
117
+ if (!import_node_fs.default.existsSync(dir)) import_node_fs.default.mkdirSync(dir, { recursive: true });
118
+ }
119
+ function listSnapshotFiles(dir) {
120
+ if (!import_node_fs.default.existsSync(dir)) return [];
121
+ return import_node_fs.default.readdirSync(dir).filter((f) => f.endsWith(".json")).sort();
122
+ }
123
+ function snapshotBeforeWrite(content, rollbackDir) {
124
+ const dir = rollbackDir ?? getRollbackDir();
125
+ ensureDir(dir);
126
+ const existing = listSnapshotFiles(dir);
127
+ if (existing.length > 0) {
128
+ const latest = existing[existing.length - 1];
129
+ try {
130
+ const prev = import_node_fs.default.readFileSync(import_node_path2.default.join(dir, latest), "utf-8");
131
+ if (prev === content) return;
132
+ } catch {
133
+ }
134
+ }
135
+ const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
136
+ const filename = `${ts}.json`;
137
+ import_node_fs.default.writeFileSync(import_node_path2.default.join(dir, filename), content, "utf-8");
138
+ evictOldSnapshots(dir);
139
+ }
140
+ function evictOldSnapshots(rollbackDir) {
141
+ const dir = rollbackDir ?? getRollbackDir();
142
+ const files = listSnapshotFiles(dir);
143
+ const excess = files.length - MAX_SNAPSHOTS;
144
+ for (let i = 0; i < excess; i++) {
145
+ try {
146
+ import_node_fs.default.unlinkSync(import_node_path2.default.join(dir, files[i]));
147
+ } catch {
148
+ }
149
+ }
150
+ }
151
+ function listSnapshots(rollbackDir) {
152
+ const dir = rollbackDir ?? getRollbackDir();
153
+ const files = listSnapshotFiles(dir).reverse();
154
+ return files.map((filename, index) => {
155
+ const filepath = import_node_path2.default.join(dir, filename);
156
+ let sizeBytes = 0;
157
+ let createdAt = "";
158
+ try {
159
+ const stat = import_node_fs.default.statSync(filepath);
160
+ sizeBytes = stat.size;
161
+ createdAt = stat.mtime.toISOString();
162
+ } catch {
163
+ }
164
+ return { index, filename, createdAt, sizeBytes };
165
+ });
166
+ }
167
+ function readSnapshot(index, rollbackDir) {
168
+ const dir = rollbackDir ?? getRollbackDir();
169
+ const files = listSnapshotFiles(dir).reverse();
170
+ const filename = files[index];
171
+ if (!filename) return null;
172
+ try {
173
+ return import_node_fs.default.readFileSync(import_node_path2.default.join(dir, filename), "utf-8");
174
+ } catch {
175
+ return null;
176
+ }
177
+ }
178
+ function restoreSnapshot(index, targetPath, rollbackDir) {
179
+ const content = readSnapshot(index, rollbackDir);
180
+ if (content === null) return null;
181
+ const dir = import_node_path2.default.dirname(targetPath);
182
+ if (!import_node_fs.default.existsSync(dir)) import_node_fs.default.mkdirSync(dir, { recursive: true });
183
+ const tmp = `${targetPath}.tmp`;
184
+ import_node_fs.default.writeFileSync(tmp, content, "utf-8");
185
+ import_node_fs.default.renameSync(tmp, targetPath);
186
+ return content;
187
+ }
188
+ var import_node_fs, import_node_path2, MAX_SNAPSHOTS;
189
+ var init_rollback_service = __esm({
190
+ "src/core/rollback-service.ts"() {
191
+ "use strict";
192
+ init_cjs_shims();
193
+ import_node_fs = __toESM(require("fs"), 1);
194
+ import_node_path2 = __toESM(require("path"), 1);
195
+ init_paths();
196
+ MAX_SNAPSHOTS = 5;
197
+ }
198
+ });
199
+
40
200
  // src/core/lockfile.ts
41
201
  var lockfile_exports = {};
42
202
  __export(lockfile_exports, {
@@ -54,27 +214,27 @@ __export(lockfile_exports, {
54
214
  function findLockfile() {
55
215
  let dir = process.cwd();
56
216
  while (true) {
57
- const candidate = import_node_path.default.join(dir, LOCKFILE_NAME);
58
- if (import_node_fs.default.existsSync(candidate)) return candidate;
59
- const parent = import_node_path.default.dirname(dir);
217
+ const candidate = import_node_path3.default.join(dir, LOCKFILE_NAME);
218
+ if (import_node_fs2.default.existsSync(candidate)) return candidate;
219
+ const parent = import_node_path3.default.dirname(dir);
60
220
  if (parent === dir) break;
61
221
  dir = parent;
62
222
  }
63
223
  return null;
64
224
  }
65
225
  function getGlobalLockfilePath() {
66
- return import_node_path.default.join(import_node_os.default.homedir(), ".mcpman", LOCKFILE_NAME);
226
+ return import_node_path3.default.join(import_node_os2.default.homedir(), ".mcpman", LOCKFILE_NAME);
67
227
  }
68
228
  function resolveLockfilePath() {
69
229
  return findLockfile() ?? getGlobalLockfilePath();
70
230
  }
71
231
  function readLockfile(filePath) {
72
232
  const target = filePath ?? resolveLockfilePath();
73
- if (!import_node_fs.default.existsSync(target)) {
233
+ if (!import_node_fs2.default.existsSync(target)) {
74
234
  return { lockfileVersion: 1, servers: {} };
75
235
  }
76
236
  try {
77
- const raw = import_node_fs.default.readFileSync(target, "utf-8");
237
+ const raw = import_node_fs2.default.readFileSync(target, "utf-8");
78
238
  return JSON.parse(raw);
79
239
  } catch {
80
240
  return { lockfileVersion: 1, servers: {} };
@@ -92,13 +252,21 @@ function serialize(data) {
92
252
  }
93
253
  function writeLockfile(data, filePath) {
94
254
  const target = filePath ?? resolveLockfilePath();
95
- const dir = import_node_path.default.dirname(target);
96
- if (!import_node_fs.default.existsSync(dir)) {
97
- import_node_fs.default.mkdirSync(dir, { recursive: true });
255
+ const dir = import_node_path3.default.dirname(target);
256
+ if (!import_node_fs2.default.existsSync(dir)) {
257
+ import_node_fs2.default.mkdirSync(dir, { recursive: true });
258
+ }
259
+ const serialized = serialize(data);
260
+ if (import_node_fs2.default.existsSync(target)) {
261
+ try {
262
+ const current = import_node_fs2.default.readFileSync(target, "utf-8");
263
+ snapshotBeforeWrite(current);
264
+ } catch {
265
+ }
98
266
  }
99
267
  const tmp = `${target}.tmp`;
100
- import_node_fs.default.writeFileSync(tmp, serialize(data), "utf-8");
101
- import_node_fs.default.renameSync(tmp, target);
268
+ import_node_fs2.default.writeFileSync(tmp, serialized, "utf-8");
269
+ import_node_fs2.default.renameSync(tmp, target);
102
270
  }
103
271
  function addEntry(name, entry, filePath) {
104
272
  const data = readLockfile(filePath);
@@ -119,14 +287,15 @@ function getLockedVersion(name, filePath) {
119
287
  function createEmptyLockfile(filePath) {
120
288
  writeLockfile({ lockfileVersion: 1, servers: {} }, filePath);
121
289
  }
122
- var import_node_fs, import_node_os, import_node_path, LOCKFILE_NAME;
290
+ var import_node_fs2, import_node_os2, import_node_path3, LOCKFILE_NAME;
123
291
  var init_lockfile = __esm({
124
292
  "src/core/lockfile.ts"() {
125
293
  "use strict";
126
294
  init_cjs_shims();
127
- import_node_fs = __toESM(require("fs"), 1);
128
- import_node_os = __toESM(require("os"), 1);
129
- import_node_path = __toESM(require("path"), 1);
295
+ import_node_fs2 = __toESM(require("fs"), 1);
296
+ import_node_os2 = __toESM(require("os"), 1);
297
+ import_node_path3 = __toESM(require("path"), 1);
298
+ init_rollback_service();
130
299
  LOCKFILE_NAME = "mcpman.lock";
131
300
  }
132
301
  });
@@ -215,69 +384,6 @@ var init_trust_scorer = __esm({
215
384
  }
216
385
  });
217
386
 
218
- // src/utils/paths.ts
219
- function getHomedir() {
220
- return import_node_os3.default.homedir();
221
- }
222
- function getMcpmanDir() {
223
- return import_node_path3.default.join(import_node_os3.default.homedir(), ".mcpman");
224
- }
225
- function getConfigPath() {
226
- return import_node_path3.default.join(getMcpmanDir(), "config.json");
227
- }
228
- function getPluginDir() {
229
- return import_node_path3.default.join(getMcpmanDir(), "plugins");
230
- }
231
- function getProfilesDir() {
232
- return import_node_path3.default.join(getMcpmanDir(), "profiles");
233
- }
234
- function getAppDataDir() {
235
- const home = getHomedir();
236
- if (process.platform === "darwin") {
237
- return import_node_path3.default.join(home, "Library", "Application Support");
238
- }
239
- if (process.platform === "win32") {
240
- return process.env.APPDATA ?? import_node_path3.default.join(home, "AppData", "Roaming");
241
- }
242
- return process.env.XDG_CONFIG_HOME ?? import_node_path3.default.join(home, ".config");
243
- }
244
- function resolveConfigPath(client) {
245
- const appData = getAppDataDir();
246
- const home = getHomedir();
247
- switch (client) {
248
- case "claude-desktop":
249
- return import_node_path3.default.join(appData, "Claude", "claude_desktop_config.json");
250
- case "cursor":
251
- return import_node_path3.default.join(appData, "Cursor", "User", "globalStorage", "cursor.mcp", "mcp.json");
252
- case "windsurf":
253
- return import_node_path3.default.join(
254
- appData,
255
- "Windsurf",
256
- "User",
257
- "globalStorage",
258
- "windsurf.mcpConfigJson",
259
- "mcp.json"
260
- );
261
- case "vscode":
262
- if (process.platform === "darwin") {
263
- return import_node_path3.default.join(appData, "Code", "User", "settings.json");
264
- }
265
- if (process.platform === "win32") {
266
- return import_node_path3.default.join(appData, "Code", "User", "settings.json");
267
- }
268
- return import_node_path3.default.join(home, ".config", "Code", "User", "settings.json");
269
- }
270
- }
271
- var import_node_os3, import_node_path3;
272
- var init_paths = __esm({
273
- "src/utils/paths.ts"() {
274
- "use strict";
275
- init_cjs_shims();
276
- import_node_os3 = __toESM(require("os"), 1);
277
- import_node_path3 = __toESM(require("path"), 1);
278
- }
279
- });
280
-
281
387
  // src/clients/types.ts
282
388
  var ConfigParseError, ConfigWriteError;
283
389
  var init_types = __esm({
@@ -305,43 +411,43 @@ var init_types = __esm({
305
411
  async function atomicWrite(filePath, content) {
306
412
  const tmpPath = `${filePath}.tmp`;
307
413
  try {
308
- await import_node_fs5.default.promises.mkdir(import_node_path6.default.dirname(filePath), { recursive: true });
309
- await import_node_fs5.default.promises.writeFile(tmpPath, content, { encoding: "utf-8", mode: 384 });
310
- await import_node_fs5.default.promises.rename(tmpPath, filePath);
414
+ await import_node_fs7.default.promises.mkdir(import_node_path7.default.dirname(filePath), { recursive: true });
415
+ await import_node_fs7.default.promises.writeFile(tmpPath, content, { encoding: "utf-8", mode: 384 });
416
+ await import_node_fs7.default.promises.rename(tmpPath, filePath);
311
417
  } catch (err) {
312
418
  try {
313
- await import_node_fs5.default.promises.unlink(tmpPath);
419
+ await import_node_fs7.default.promises.unlink(tmpPath);
314
420
  } catch {
315
421
  }
316
422
  throw err;
317
423
  }
318
424
  }
319
- async function pathExists(p13) {
425
+ async function pathExists(p14) {
320
426
  try {
321
- await import_node_fs5.default.promises.access(p13);
427
+ await import_node_fs7.default.promises.access(p14);
322
428
  return true;
323
429
  } catch {
324
430
  return false;
325
431
  }
326
432
  }
327
- var import_node_fs5, import_node_path6, BaseClientHandler;
433
+ var import_node_fs7, import_node_path7, BaseClientHandler;
328
434
  var init_base_client_handler = __esm({
329
435
  "src/clients/base-client-handler.ts"() {
330
436
  "use strict";
331
437
  init_cjs_shims();
332
- import_node_fs5 = __toESM(require("fs"), 1);
333
- import_node_path6 = __toESM(require("path"), 1);
438
+ import_node_fs7 = __toESM(require("fs"), 1);
439
+ import_node_path7 = __toESM(require("path"), 1);
334
440
  init_types();
335
441
  BaseClientHandler = class {
336
442
  async isInstalled() {
337
- const dir = import_node_path6.default.dirname(this.getConfigPath());
443
+ const dir = import_node_path7.default.dirname(this.getConfigPath());
338
444
  return pathExists(dir);
339
445
  }
340
446
  /** Read raw JSON from disk, return empty object if file missing */
341
447
  async readRaw() {
342
448
  const configPath = this.getConfigPath();
343
449
  try {
344
- const raw = await import_node_fs5.default.promises.readFile(configPath, "utf-8");
450
+ const raw = await import_node_fs7.default.promises.readFile(configPath, "utf-8");
345
451
  return JSON.parse(raw);
346
452
  } catch (err) {
347
453
  if (err.code === "ENOENT") {
@@ -531,12 +637,12 @@ __export(vault_service_exports, {
531
637
  writeVault: () => writeVault
532
638
  });
533
639
  function getVaultPath() {
534
- return import_node_path10.default.join(import_node_os5.default.homedir(), ".mcpman", "vault.enc");
640
+ return import_node_path12.default.join(import_node_os5.default.homedir(), ".mcpman", "vault.enc");
535
641
  }
536
642
  function readVault(vaultPath = getVaultPath()) {
537
643
  const empty = { version: 1, servers: {} };
538
644
  try {
539
- const raw = import_node_fs8.default.readFileSync(vaultPath, "utf-8");
645
+ const raw = import_node_fs11.default.readFileSync(vaultPath, "utf-8");
540
646
  const parsed = JSON.parse(raw);
541
647
  if (parsed.version !== 1 || typeof parsed.servers !== "object") return empty;
542
648
  return parsed;
@@ -545,16 +651,16 @@ function readVault(vaultPath = getVaultPath()) {
545
651
  }
546
652
  }
547
653
  function writeVault(data, vaultPath = getVaultPath()) {
548
- const dir = import_node_path10.default.dirname(vaultPath);
549
- import_node_fs8.default.mkdirSync(dir, { recursive: true });
654
+ const dir = import_node_path12.default.dirname(vaultPath);
655
+ import_node_fs11.default.mkdirSync(dir, { recursive: true });
550
656
  const tmp = `${vaultPath}.tmp`;
551
- import_node_fs8.default.writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 384 });
657
+ import_node_fs11.default.writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 384 });
552
658
  if (process.platform !== "win32") {
553
- import_node_fs8.default.chmodSync(tmp, 384);
659
+ import_node_fs11.default.chmodSync(tmp, 384);
554
660
  }
555
- import_node_fs8.default.renameSync(tmp, vaultPath);
661
+ import_node_fs11.default.renameSync(tmp, vaultPath);
556
662
  if (process.platform !== "win32") {
557
- import_node_fs8.default.chmodSync(vaultPath, 384);
663
+ import_node_fs11.default.chmodSync(vaultPath, 384);
558
664
  }
559
665
  }
560
666
  function encrypt(value, password2) {
@@ -581,7 +687,7 @@ function decrypt(entry, password2) {
581
687
  ]);
582
688
  return decrypted.toString("utf-8");
583
689
  }
584
- async function getMasterPassword(confirm10 = false) {
690
+ async function getMasterPassword(confirm11 = false) {
585
691
  if (_cachedPassword) return _cachedPassword;
586
692
  const password2 = await p3.password({
587
693
  message: "Enter vault master password:",
@@ -591,7 +697,7 @@ async function getMasterPassword(confirm10 = false) {
591
697
  p3.cancel("Vault access cancelled.");
592
698
  process.exit(0);
593
699
  }
594
- if (confirm10) {
700
+ if (confirm11) {
595
701
  const confirm22 = await p3.password({ message: "Confirm master password:" });
596
702
  if (p3.isCancel(confirm22) || confirm22 !== password2) {
597
703
  p3.cancel("Passwords do not match.");
@@ -644,15 +750,15 @@ function listSecrets(server, vaultPath = getVaultPath()) {
644
750
  keys: Object.keys(keys)
645
751
  }));
646
752
  }
647
- var import_node_crypto2, import_node_fs8, import_node_os5, import_node_path10, p3, _cachedPassword;
753
+ var import_node_crypto2, import_node_fs11, import_node_os5, import_node_path12, p3, _cachedPassword;
648
754
  var init_vault_service = __esm({
649
755
  "src/core/vault-service.ts"() {
650
756
  "use strict";
651
757
  init_cjs_shims();
652
758
  import_node_crypto2 = __toESM(require("crypto"), 1);
653
- import_node_fs8 = __toESM(require("fs"), 1);
759
+ import_node_fs11 = __toESM(require("fs"), 1);
654
760
  import_node_os5 = __toESM(require("os"), 1);
655
- import_node_path10 = __toESM(require("path"), 1);
761
+ import_node_path12 = __toESM(require("path"), 1);
656
762
  p3 = __toESM(require("@clack/prompts"), 1);
657
763
  _cachedPassword = null;
658
764
  process.on("exit", () => {
@@ -663,7 +769,7 @@ var init_vault_service = __esm({
663
769
 
664
770
  // src/index.ts
665
771
  init_cjs_shims();
666
- var import_citty27 = require("citty");
772
+ var import_citty33 = require("citty");
667
773
 
668
774
  // src/commands/audit.ts
669
775
  init_cjs_shims();
@@ -675,25 +781,25 @@ init_lockfile();
675
781
 
676
782
  // src/core/security-scanner.ts
677
783
  init_cjs_shims();
678
- var import_node_fs2 = __toESM(require("fs"), 1);
679
- var import_node_os2 = __toESM(require("os"), 1);
680
- var import_node_path2 = __toESM(require("path"), 1);
681
- var CACHE_PATH = import_node_path2.default.join(import_node_os2.default.homedir(), ".mcpman", ".audit-cache.json");
784
+ var import_node_fs3 = __toESM(require("fs"), 1);
785
+ var import_node_os3 = __toESM(require("os"), 1);
786
+ var import_node_path4 = __toESM(require("path"), 1);
787
+ var CACHE_PATH = import_node_path4.default.join(import_node_os3.default.homedir(), ".mcpman", ".audit-cache.json");
682
788
  var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
683
789
  function readCache() {
684
790
  try {
685
- if (!import_node_fs2.default.existsSync(CACHE_PATH)) return {};
686
- return JSON.parse(import_node_fs2.default.readFileSync(CACHE_PATH, "utf-8"));
791
+ if (!import_node_fs3.default.existsSync(CACHE_PATH)) return {};
792
+ return JSON.parse(import_node_fs3.default.readFileSync(CACHE_PATH, "utf-8"));
687
793
  } catch {
688
794
  return {};
689
795
  }
690
796
  }
691
797
  function writeCache(cache) {
692
- const dir = import_node_path2.default.dirname(CACHE_PATH);
693
- if (!import_node_fs2.default.existsSync(dir)) import_node_fs2.default.mkdirSync(dir, { recursive: true });
798
+ const dir = import_node_path4.default.dirname(CACHE_PATH);
799
+ if (!import_node_fs3.default.existsSync(dir)) import_node_fs3.default.mkdirSync(dir, { recursive: true });
694
800
  const tmp = `${CACHE_PATH}.tmp`;
695
- import_node_fs2.default.writeFileSync(tmp, JSON.stringify(cache, null, 2), "utf-8");
696
- import_node_fs2.default.renameSync(tmp, CACHE_PATH);
801
+ import_node_fs3.default.writeFileSync(tmp, JSON.stringify(cache, null, 2), "utf-8");
802
+ import_node_fs3.default.renameSync(tmp, CACHE_PATH);
697
803
  }
698
804
  function getCachedReport(name, version) {
699
805
  const cache = readCache();
@@ -804,11 +910,11 @@ async function scanAllServers(servers, concurrency = 3) {
804
910
  const results = [];
805
911
  const executing = /* @__PURE__ */ new Set();
806
912
  for (const [name, entry] of entries) {
807
- const p13 = scanServer(name, entry).then((r) => {
913
+ const p14 = scanServer(name, entry).then((r) => {
808
914
  results.push(r);
809
- executing.delete(p13);
915
+ executing.delete(p14);
810
916
  });
811
- executing.add(p13);
917
+ executing.add(p14);
812
918
  if (executing.size >= concurrency) await Promise.race(executing);
813
919
  }
814
920
  await Promise.all(executing);
@@ -932,15 +1038,15 @@ init_cjs_shims();
932
1038
  // src/core/plugin-loader.ts
933
1039
  init_cjs_shims();
934
1040
  var import_node_child_process = require("child_process");
935
- var import_node_fs4 = __toESM(require("fs"), 1);
1041
+ var import_node_fs5 = __toESM(require("fs"), 1);
936
1042
  var import_node_module = require("module");
937
- var import_node_path5 = __toESM(require("path"), 1);
1043
+ var import_node_path6 = __toESM(require("path"), 1);
938
1044
  init_paths();
939
1045
 
940
1046
  // src/core/config-service.ts
941
1047
  init_cjs_shims();
942
- var import_node_fs3 = __toESM(require("fs"), 1);
943
- var import_node_path4 = __toESM(require("path"), 1);
1048
+ var import_node_fs4 = __toESM(require("fs"), 1);
1049
+ var import_node_path5 = __toESM(require("path"), 1);
944
1050
  init_paths();
945
1051
  var VALID_KEYS = /* @__PURE__ */ new Set([
946
1052
  "defaultClient",
@@ -951,7 +1057,7 @@ var VALID_KEYS = /* @__PURE__ */ new Set([
951
1057
  ]);
952
1058
  function readConfig(configPath = getConfigPath()) {
953
1059
  try {
954
- const raw = import_node_fs3.default.readFileSync(configPath, "utf-8");
1060
+ const raw = import_node_fs4.default.readFileSync(configPath, "utf-8");
955
1061
  const parsed = JSON.parse(raw);
956
1062
  if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
957
1063
  return {};
@@ -962,11 +1068,11 @@ function readConfig(configPath = getConfigPath()) {
962
1068
  }
963
1069
  }
964
1070
  function writeConfig(data, configPath = getConfigPath()) {
965
- const dir = import_node_path4.default.dirname(configPath);
966
- import_node_fs3.default.mkdirSync(dir, { recursive: true });
1071
+ const dir = import_node_path5.default.dirname(configPath);
1072
+ import_node_fs4.default.mkdirSync(dir, { recursive: true });
967
1073
  const tmp = `${configPath}.tmp`;
968
- import_node_fs3.default.writeFileSync(tmp, JSON.stringify(data, null, 2), { encoding: "utf-8" });
969
- import_node_fs3.default.renameSync(tmp, configPath);
1074
+ import_node_fs4.default.writeFileSync(tmp, JSON.stringify(data, null, 2), { encoding: "utf-8" });
1075
+ import_node_fs4.default.renameSync(tmp, configPath);
970
1076
  }
971
1077
  function getConfigValue(key, configPath = getConfigPath()) {
972
1078
  const data = readConfig(configPath);
@@ -985,13 +1091,13 @@ function setConfigValue(key, value, configPath = getConfigPath()) {
985
1091
  // src/core/plugin-loader.ts
986
1092
  function isValidPlugin(obj) {
987
1093
  if (typeof obj !== "object" || obj === null) return false;
988
- const p13 = obj;
989
- return typeof p13.name === "string" && typeof p13.prefix === "string" && typeof p13.resolve === "function";
1094
+ const p14 = obj;
1095
+ return typeof p14.name === "string" && typeof p14.prefix === "string" && typeof p14.resolve === "function";
990
1096
  }
991
1097
  function loadPlugin(pkg, pluginDir = getPluginDir()) {
992
1098
  try {
993
- const requirePath = import_node_path5.default.join(pluginDir, "node_modules", pkg);
994
- const pluginRequire = (0, import_node_module.createRequire)(import_node_path5.default.join(pluginDir, "index.js"));
1099
+ const requirePath = import_node_path6.default.join(pluginDir, "node_modules", pkg);
1100
+ const pluginRequire = (0, import_node_module.createRequire)(import_node_path6.default.join(pluginDir, "index.js"));
995
1101
  const mod = pluginRequire(requirePath);
996
1102
  const exported = mod?.default ?? mod;
997
1103
  if (isValidPlugin(exported)) return exported;
@@ -1011,10 +1117,10 @@ function loadAllPlugins(pluginDir = getPluginDir()) {
1011
1117
  return plugins;
1012
1118
  }
1013
1119
  function installPluginPackage(name, pluginDir = getPluginDir()) {
1014
- import_node_fs4.default.mkdirSync(pluginDir, { recursive: true });
1015
- const pkgJsonPath = import_node_path5.default.join(pluginDir, "package.json");
1016
- if (!import_node_fs4.default.existsSync(pkgJsonPath)) {
1017
- import_node_fs4.default.writeFileSync(
1120
+ import_node_fs5.default.mkdirSync(pluginDir, { recursive: true });
1121
+ const pkgJsonPath = import_node_path6.default.join(pluginDir, "package.json");
1122
+ if (!import_node_fs5.default.existsSync(pkgJsonPath)) {
1123
+ import_node_fs5.default.writeFileSync(
1018
1124
  pkgJsonPath,
1019
1125
  JSON.stringify({ name: "mcpman-plugins", private: true }, null, 2)
1020
1126
  );
@@ -1040,7 +1146,7 @@ function removePluginPackage(name, pluginDir = getPluginDir()) {
1040
1146
  }
1041
1147
  const config = readConfig();
1042
1148
  const plugins = config.plugins ?? [];
1043
- config.plugins = plugins.filter((p13) => p13 !== name);
1149
+ config.plugins = plugins.filter((p14) => p14 !== name);
1044
1150
  writeConfig(config);
1045
1151
  }
1046
1152
  function listPluginPackages() {
@@ -1089,7 +1195,7 @@ async function resolveServer(input) {
1089
1195
  if (source.type.startsWith("plugin:")) {
1090
1196
  const pluginName = source.type.slice(7);
1091
1197
  const plugins = loadAllPlugins();
1092
- const plugin = plugins.find((p13) => p13.name === pluginName);
1198
+ const plugin = plugins.find((p14) => p14.name === pluginName);
1093
1199
  if (plugin) {
1094
1200
  const resolved = await plugin.resolve(source.input);
1095
1201
  return resolved;
@@ -1145,6 +1251,51 @@ async function applyServerUpdate(serverName, lockEntry, clients) {
1145
1251
 
1146
1252
  // src/core/version-checker.ts
1147
1253
  init_cjs_shims();
1254
+
1255
+ // src/core/pin-service.ts
1256
+ init_cjs_shims();
1257
+ var import_node_fs6 = __toESM(require("fs"), 1);
1258
+ init_paths();
1259
+ function readPins(file) {
1260
+ const target = file ?? getPinsFile();
1261
+ if (!import_node_fs6.default.existsSync(target)) return {};
1262
+ try {
1263
+ return JSON.parse(import_node_fs6.default.readFileSync(target, "utf-8"));
1264
+ } catch {
1265
+ return {};
1266
+ }
1267
+ }
1268
+ function writePins(store, file) {
1269
+ const target = file ?? getPinsFile();
1270
+ const dir = target.slice(0, target.lastIndexOf("/"));
1271
+ if (dir && !import_node_fs6.default.existsSync(dir)) {
1272
+ import_node_fs6.default.mkdirSync(dir, { recursive: true });
1273
+ }
1274
+ import_node_fs6.default.writeFileSync(target, JSON.stringify(store, null, 2), "utf-8");
1275
+ }
1276
+ function pinServer(server, version, file) {
1277
+ const store = readPins(file);
1278
+ store[server] = version;
1279
+ writePins(store, file);
1280
+ }
1281
+ function unpinServer(server, file) {
1282
+ const store = readPins(file);
1283
+ if (!(server in store)) return;
1284
+ delete store[server];
1285
+ writePins(store, file);
1286
+ }
1287
+ function getPinnedVersion(server, file) {
1288
+ return readPins(file)[server] ?? null;
1289
+ }
1290
+ function isPinned(server, file) {
1291
+ return server in readPins(file);
1292
+ }
1293
+ function listPins(file) {
1294
+ const store = readPins(file);
1295
+ return Object.entries(store).sort(([a], [b]) => a.localeCompare(b)).map(([server, version]) => ({ server, version }));
1296
+ }
1297
+
1298
+ // src/core/version-checker.ts
1148
1299
  function compareVersions(a, b) {
1149
1300
  const aParts = a.replace(/^v/, "").split(".").map(Number);
1150
1301
  const bParts = b.replace(/^v/, "").split(".").map(Number);
@@ -1245,11 +1396,12 @@ async function checkAllVersions(lockfile) {
1245
1396
  const results = [];
1246
1397
  const executing = /* @__PURE__ */ new Set();
1247
1398
  for (const [name, entry] of entries) {
1248
- const p13 = checkVersion(name, entry).then((r) => {
1399
+ if (isPinned(name)) continue;
1400
+ const p14 = checkVersion(name, entry).then((r) => {
1249
1401
  results.push(r);
1250
- executing.delete(p13);
1402
+ executing.delete(p14);
1251
1403
  });
1252
- executing.add(p13);
1404
+ executing.add(p14);
1253
1405
  if (executing.size >= 5) {
1254
1406
  await Promise.race(executing);
1255
1407
  }
@@ -1503,57 +1655,258 @@ async function runAuditFix(reports, servers, skipConfirm) {
1503
1655
  `);
1504
1656
  }
1505
1657
 
1506
- // src/commands/completions.ts
1658
+ // src/commands/bench.ts
1507
1659
  init_cjs_shims();
1508
- var import_node_fs6 = __toESM(require("fs"), 1);
1509
- var import_node_os4 = __toESM(require("os"), 1);
1510
- var import_node_path7 = __toESM(require("path"), 1);
1511
1660
  var import_citty2 = require("citty");
1512
1661
  var import_picocolors2 = __toESM(require("picocolors"), 1);
1513
1662
 
1514
- // src/core/completion-generator.ts
1663
+ // src/core/bench-service.ts
1515
1664
  init_cjs_shims();
1516
- init_lockfile();
1517
- function getCommandList() {
1518
- return [
1519
- "install",
1520
- "list",
1521
- "remove",
1522
- "doctor",
1523
- "init",
1524
- "secrets",
1525
- "sync",
1526
- "audit",
1527
- "update",
1528
- "upgrade",
1529
- "config",
1530
- "search",
1531
- "info",
1532
- "run",
1533
- "logs",
1534
- "test",
1535
- "profiles",
1536
- "plugin",
1537
- "export",
1538
- "import",
1539
- "create",
1540
- "link",
1541
- "watch",
1542
- "registry",
1543
- "completions",
1544
- "why"
1545
- ];
1665
+ var import_node_child_process2 = require("child_process");
1666
+ var DEFAULT_TIMEOUT_MS = 1e4;
1667
+ function measureOneRun(command, args, env, timeoutMs) {
1668
+ return new Promise((resolve, reject) => {
1669
+ const start = Date.now();
1670
+ let settled = false;
1671
+ let stdout = "";
1672
+ const child = (0, import_node_child_process2.spawn)(command, args, {
1673
+ env: { ...process.env, ...env },
1674
+ stdio: ["pipe", "pipe", "pipe"]
1675
+ });
1676
+ const finish = (err) => {
1677
+ if (settled) return;
1678
+ settled = true;
1679
+ try {
1680
+ child.kill("SIGTERM");
1681
+ } catch {
1682
+ }
1683
+ if (err) reject(err);
1684
+ else resolve(Date.now() - start);
1685
+ };
1686
+ const timer = setTimeout(() => {
1687
+ finish(new Error("Timeout waiting for initialize response"));
1688
+ }, timeoutMs);
1689
+ child.on("error", (err) => {
1690
+ clearTimeout(timer);
1691
+ finish(err);
1692
+ });
1693
+ child.on("exit", (code) => {
1694
+ clearTimeout(timer);
1695
+ if (!settled) finish(new Error(`Process exited with code ${code}`));
1696
+ });
1697
+ child.stdout?.on("data", (chunk) => {
1698
+ stdout += chunk.toString();
1699
+ for (const line of stdout.split("\n")) {
1700
+ const trimmed = line.trim();
1701
+ if (!trimmed) continue;
1702
+ try {
1703
+ const msg = JSON.parse(trimmed);
1704
+ if (msg.jsonrpc === "2.0" && msg.id === 1) {
1705
+ clearTimeout(timer);
1706
+ finish();
1707
+ }
1708
+ } catch {
1709
+ }
1710
+ }
1711
+ });
1712
+ const initReq = JSON.stringify({
1713
+ jsonrpc: "2.0",
1714
+ id: 1,
1715
+ method: "initialize",
1716
+ params: {
1717
+ protocolVersion: "2024-11-05",
1718
+ capabilities: {},
1719
+ clientInfo: { name: "mcpman-bench", version: "0.8.0" }
1720
+ }
1721
+ });
1722
+ child.stdin?.write(`${initReq}
1723
+ `);
1724
+ });
1546
1725
  }
1547
- var SERVER_ARG_COMMANDS = [
1548
- "run",
1549
- "test",
1550
- "logs",
1551
- "watch",
1552
- "remove",
1553
- "update",
1554
- "info",
1555
- "audit",
1556
- "link",
1726
+ function percentile(sorted, p14) {
1727
+ if (sorted.length === 0) return 0;
1728
+ const idx = Math.ceil(p14 / 100 * sorted.length) - 1;
1729
+ return sorted[Math.max(0, idx)];
1730
+ }
1731
+ async function benchServer(command, args, env, runs = 5, timeoutMs = DEFAULT_TIMEOUT_MS) {
1732
+ const allTimes = [];
1733
+ for (let i = 0; i < runs; i++) {
1734
+ try {
1735
+ const ms = await measureOneRun(command, args, env, timeoutMs);
1736
+ allTimes.push(ms);
1737
+ } catch (err) {
1738
+ return {
1739
+ runs,
1740
+ min: 0,
1741
+ max: 0,
1742
+ avg: 0,
1743
+ p50: 0,
1744
+ p95: 0,
1745
+ allTimes,
1746
+ error: String(err instanceof Error ? err.message : err)
1747
+ };
1748
+ }
1749
+ }
1750
+ const sorted = [...allTimes].sort((a, b) => a - b);
1751
+ const sum = allTimes.reduce((a, b) => a + b, 0);
1752
+ return {
1753
+ runs,
1754
+ min: sorted[0] ?? 0,
1755
+ max: sorted[sorted.length - 1] ?? 0,
1756
+ avg: Math.round(sum / allTimes.length),
1757
+ p50: percentile(sorted, 50),
1758
+ p95: percentile(sorted, 95),
1759
+ allTimes
1760
+ };
1761
+ }
1762
+
1763
+ // src/commands/bench.ts
1764
+ init_lockfile();
1765
+ var bench_default = (0, import_citty2.defineCommand)({
1766
+ meta: {
1767
+ name: "bench",
1768
+ description: "Benchmark MCP server latency (JSON-RPC initialize)"
1769
+ },
1770
+ args: {
1771
+ server: {
1772
+ type: "positional",
1773
+ description: "Server name as stored in lockfile",
1774
+ required: true
1775
+ },
1776
+ runs: {
1777
+ type: "string",
1778
+ description: "Number of benchmark runs (default: 5)",
1779
+ default: "5"
1780
+ },
1781
+ timeout: {
1782
+ type: "string",
1783
+ description: "Per-run timeout in ms (default: 10000)",
1784
+ default: "10000"
1785
+ },
1786
+ json: {
1787
+ type: "boolean",
1788
+ description: "Output results as JSON",
1789
+ default: false
1790
+ }
1791
+ },
1792
+ async run({ args }) {
1793
+ const lockfile = readLockfile();
1794
+ const entry = lockfile.servers[args.server];
1795
+ if (!entry) {
1796
+ console.error(`${import_picocolors2.default.red("\u2717")} Server "${args.server}" not found in lockfile.`);
1797
+ console.error(import_picocolors2.default.dim("Run `mcpman list` to see installed servers."));
1798
+ process.exit(1);
1799
+ }
1800
+ const runs = Math.max(1, Number.parseInt(args.runs, 10) || 5);
1801
+ const timeoutMs = Math.max(1e3, Number.parseInt(args.timeout, 10) || 1e4);
1802
+ if (!args.json) {
1803
+ console.log(`
1804
+ ${import_picocolors2.default.cyan("mcpman bench")} \u2014 ${import_picocolors2.default.bold(args.server)}`);
1805
+ console.log(import_picocolors2.default.dim(` Command: ${entry.command} ${(entry.args ?? []).join(" ")}`));
1806
+ console.log(import_picocolors2.default.dim(` Runs: ${runs} Timeout: ${timeoutMs}ms
1807
+ `));
1808
+ process.stdout.write(import_picocolors2.default.dim(" Running"));
1809
+ }
1810
+ const env = {};
1811
+ for (const ev of entry.envVars ?? []) {
1812
+ const idx = ev.indexOf("=");
1813
+ if (idx > 0) env[ev.slice(0, idx)] = ev.slice(idx + 1);
1814
+ }
1815
+ const result = await benchServer(entry.command, entry.args ?? [], env, runs, timeoutMs);
1816
+ if (!args.json) process.stdout.write("\n");
1817
+ if (result.error) {
1818
+ if (args.json) {
1819
+ console.log(JSON.stringify({ server: args.server, error: result.error }));
1820
+ } else {
1821
+ console.error(`
1822
+ ${import_picocolors2.default.red("\u2717")} Benchmark failed: ${result.error}`);
1823
+ }
1824
+ process.exit(1);
1825
+ }
1826
+ if (args.json) {
1827
+ console.log(JSON.stringify({ server: args.server, ...result }, null, 2));
1828
+ if (result.p95 > timeoutMs) process.exit(1);
1829
+ return;
1830
+ }
1831
+ const pad4 = (s, w) => s.padEnd(w);
1832
+ const ms = (n) => `${n}ms`;
1833
+ console.log(`
1834
+ ${import_picocolors2.default.bold("Latency statistics")} for ${import_picocolors2.default.cyan(args.server)}`);
1835
+ console.log(import_picocolors2.default.dim(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
1836
+ console.log(` ${pad4("min", 8)} ${import_picocolors2.default.green(ms(result.min))}`);
1837
+ console.log(` ${pad4("avg", 8)} ${ms(result.avg)}`);
1838
+ console.log(` ${pad4("p50", 8)} ${ms(result.p50)}`);
1839
+ console.log(
1840
+ ` ${pad4("p95", 8)} ${result.p95 > timeoutMs ? import_picocolors2.default.red(ms(result.p95)) : import_picocolors2.default.yellow(ms(result.p95))}`
1841
+ );
1842
+ console.log(` ${pad4("max", 8)} ${ms(result.max)}`);
1843
+ console.log(` ${pad4("runs", 8)} ${result.runs}`);
1844
+ console.log("");
1845
+ if (result.p95 > timeoutMs) {
1846
+ console.error(import_picocolors2.default.red(` \u2717 p95 (${result.p95}ms) exceeds timeout (${timeoutMs}ms)`));
1847
+ process.exit(1);
1848
+ }
1849
+ console.log(import_picocolors2.default.green(" \u2713 Benchmark complete"));
1850
+ }
1851
+ });
1852
+
1853
+ // src/commands/completions.ts
1854
+ init_cjs_shims();
1855
+ var import_node_fs8 = __toESM(require("fs"), 1);
1856
+ var import_node_os4 = __toESM(require("os"), 1);
1857
+ var import_node_path8 = __toESM(require("path"), 1);
1858
+ var import_citty3 = require("citty");
1859
+ var import_picocolors3 = __toESM(require("picocolors"), 1);
1860
+
1861
+ // src/core/completion-generator.ts
1862
+ init_cjs_shims();
1863
+ init_lockfile();
1864
+ function getCommandList() {
1865
+ return [
1866
+ "install",
1867
+ "list",
1868
+ "remove",
1869
+ "doctor",
1870
+ "init",
1871
+ "secrets",
1872
+ "sync",
1873
+ "audit",
1874
+ "update",
1875
+ "upgrade",
1876
+ "config",
1877
+ "search",
1878
+ "info",
1879
+ "run",
1880
+ "logs",
1881
+ "test",
1882
+ "profiles",
1883
+ "plugin",
1884
+ "export",
1885
+ "import",
1886
+ "create",
1887
+ "link",
1888
+ "watch",
1889
+ "registry",
1890
+ "completions",
1891
+ "why",
1892
+ "env",
1893
+ "bench",
1894
+ "diff",
1895
+ "group",
1896
+ "pin",
1897
+ "rollback"
1898
+ ];
1899
+ }
1900
+ var SERVER_ARG_COMMANDS = [
1901
+ "run",
1902
+ "test",
1903
+ "logs",
1904
+ "watch",
1905
+ "remove",
1906
+ "update",
1907
+ "info",
1908
+ "audit",
1909
+ "link",
1557
1910
  "why"
1558
1911
  ];
1559
1912
  function getServerNames(lockfilePath) {
@@ -1666,7 +2019,7 @@ complete -c mcpman -l runtime -s r \\
1666
2019
  }
1667
2020
 
1668
2021
  // src/commands/completions.ts
1669
- var completions_default = (0, import_citty2.defineCommand)({
2022
+ var completions_default = (0, import_citty3.defineCommand)({
1670
2023
  meta: {
1671
2024
  name: "completions",
1672
2025
  description: "Generate shell completion scripts (bash, zsh, fish)"
@@ -1716,24 +2069,24 @@ var completions_default = (0, import_citty2.defineCommand)({
1716
2069
  await installCompletion();
1717
2070
  break;
1718
2071
  default:
1719
- console.error(import_picocolors2.default.red(` Error: Unknown shell '${shell}'. Use: bash, zsh, or fish.`));
2072
+ console.error(import_picocolors3.default.red(` Error: Unknown shell '${shell}'. Use: bash, zsh, or fish.`));
1720
2073
  process.exit(1);
1721
2074
  }
1722
2075
  }
1723
2076
  });
1724
2077
  function printUsage() {
1725
- console.log(import_picocolors2.default.bold("\n mcpman completions \u2014 Shell completion setup\n"));
2078
+ console.log(import_picocolors3.default.bold("\n mcpman completions \u2014 Shell completion setup\n"));
1726
2079
  console.log(" Usage:");
1727
- console.log(` ${import_picocolors2.default.cyan("mcpman completions bash")} Output bash completion script`);
1728
- console.log(` ${import_picocolors2.default.cyan("mcpman completions zsh")} Output zsh completion script`);
1729
- console.log(` ${import_picocolors2.default.cyan("mcpman completions fish")} Output fish completion script`);
1730
- console.log(` ${import_picocolors2.default.cyan("mcpman completions install")} Auto-detect shell and install
2080
+ console.log(` ${import_picocolors3.default.cyan("mcpman completions bash")} Output bash completion script`);
2081
+ console.log(` ${import_picocolors3.default.cyan("mcpman completions zsh")} Output zsh completion script`);
2082
+ console.log(` ${import_picocolors3.default.cyan("mcpman completions fish")} Output fish completion script`);
2083
+ console.log(` ${import_picocolors3.default.cyan("mcpman completions install")} Auto-detect shell and install
1731
2084
  `);
1732
2085
  console.log(" Quick setup:");
1733
- console.log(` ${import_picocolors2.default.dim("# bash")}`);
1734
- console.log(` ${import_picocolors2.default.cyan("source <(mcpman completions bash)")}`);
1735
- console.log(` ${import_picocolors2.default.dim("# zsh")}`);
1736
- console.log(` ${import_picocolors2.default.cyan("source <(mcpman completions zsh)")}
2086
+ console.log(` ${import_picocolors3.default.dim("# bash")}`);
2087
+ console.log(` ${import_picocolors3.default.cyan("source <(mcpman completions bash)")}`);
2088
+ console.log(` ${import_picocolors3.default.dim("# zsh")}`);
2089
+ console.log(` ${import_picocolors3.default.cyan("source <(mcpman completions zsh)")}
1737
2090
  `);
1738
2091
  }
1739
2092
  async function installCompletion() {
@@ -1743,50 +2096,50 @@ async function installCompletion() {
1743
2096
  else if (shellBin.includes("fish")) detectedShell = "fish";
1744
2097
  else if (shellBin.includes("bash")) detectedShell = "bash";
1745
2098
  if (!detectedShell) {
1746
- console.error(import_picocolors2.default.red(" Could not detect shell from $SHELL. Run manually:"));
1747
- console.error(import_picocolors2.default.dim(" source <(mcpman completions bash|zsh|fish)"));
2099
+ console.error(import_picocolors3.default.red(" Could not detect shell from $SHELL. Run manually:"));
2100
+ console.error(import_picocolors3.default.dim(" source <(mcpman completions bash|zsh|fish)"));
1748
2101
  process.exit(1);
1749
2102
  }
1750
2103
  const home = import_node_os4.default.homedir();
1751
2104
  let rcFile;
1752
2105
  let script;
1753
2106
  if (detectedShell === "zsh") {
1754
- rcFile = import_node_path7.default.join(home, ".zshrc");
2107
+ rcFile = import_node_path8.default.join(home, ".zshrc");
1755
2108
  script = generateZshCompletion();
1756
2109
  } else if (detectedShell === "fish") {
1757
- const fishDir = import_node_path7.default.join(home, ".config", "fish", "completions");
1758
- import_node_fs6.default.mkdirSync(fishDir, { recursive: true });
1759
- rcFile = import_node_path7.default.join(fishDir, "mcpman.fish");
1760
- import_node_fs6.default.writeFileSync(rcFile, generateFishCompletion(), "utf-8");
1761
- console.log(import_picocolors2.default.green(` Installed fish completions to ${rcFile}`));
2110
+ const fishDir = import_node_path8.default.join(home, ".config", "fish", "completions");
2111
+ import_node_fs8.default.mkdirSync(fishDir, { recursive: true });
2112
+ rcFile = import_node_path8.default.join(fishDir, "mcpman.fish");
2113
+ import_node_fs8.default.writeFileSync(rcFile, generateFishCompletion(), "utf-8");
2114
+ console.log(import_picocolors3.default.green(` Installed fish completions to ${rcFile}`));
1762
2115
  return;
1763
2116
  } else {
1764
- rcFile = import_node_path7.default.join(home, ".bashrc");
2117
+ rcFile = import_node_path8.default.join(home, ".bashrc");
1765
2118
  script = generateBashCompletion();
1766
2119
  }
1767
2120
  const marker = "# mcpman completions";
1768
2121
  let existing = "";
1769
2122
  try {
1770
- existing = import_node_fs6.default.readFileSync(rcFile, "utf-8");
2123
+ existing = import_node_fs8.default.readFileSync(rcFile, "utf-8");
1771
2124
  } catch {
1772
2125
  }
1773
2126
  if (existing.includes(marker)) {
1774
- console.log(import_picocolors2.default.yellow(` Completions already installed in ${rcFile}. Skipping.`));
2127
+ console.log(import_picocolors3.default.yellow(` Completions already installed in ${rcFile}. Skipping.`));
1775
2128
  return;
1776
2129
  }
1777
- import_node_fs6.default.appendFileSync(rcFile, `
2130
+ import_node_fs8.default.appendFileSync(rcFile, `
1778
2131
  ${marker}
1779
2132
  source <(mcpman completions ${detectedShell})
1780
2133
  `);
1781
- console.log(import_picocolors2.default.green(` Installed ${detectedShell} completions in ${rcFile}`));
1782
- console.log(import_picocolors2.default.dim(` Restart your shell or run: source ${rcFile}`));
2134
+ console.log(import_picocolors3.default.green(` Installed ${detectedShell} completions in ${rcFile}`));
2135
+ console.log(import_picocolors3.default.dim(` Restart your shell or run: source ${rcFile}`));
1783
2136
  }
1784
2137
 
1785
2138
  // src/commands/config.ts
1786
2139
  init_cjs_shims();
1787
2140
  var p2 = __toESM(require("@clack/prompts"), 1);
1788
- var import_citty3 = require("citty");
1789
- var import_picocolors3 = __toESM(require("picocolors"), 1);
2141
+ var import_citty4 = require("citty");
2142
+ var import_picocolors4 = __toESM(require("picocolors"), 1);
1790
2143
  function coerceValue(raw) {
1791
2144
  if (raw === "true") return true;
1792
2145
  if (raw === "false") return false;
@@ -1794,7 +2147,7 @@ function coerceValue(raw) {
1794
2147
  if (!Number.isNaN(num) && raw.trim() !== "") return num;
1795
2148
  return raw;
1796
2149
  }
1797
- var setCommand = (0, import_citty3.defineCommand)({
2150
+ var setCommand = (0, import_citty4.defineCommand)({
1798
2151
  meta: { name: "set", description: "Set a config value" },
1799
2152
  args: {
1800
2153
  key: {
@@ -1812,14 +2165,14 @@ var setCommand = (0, import_citty3.defineCommand)({
1812
2165
  try {
1813
2166
  const coerced = coerceValue(args.value);
1814
2167
  setConfigValue(args.key, coerced);
1815
- console.log(`${import_picocolors3.default.green("\u2713")} Set ${import_picocolors3.default.bold(args.key)} = ${import_picocolors3.default.cyan(String(coerced))}`);
2168
+ console.log(`${import_picocolors4.default.green("\u2713")} Set ${import_picocolors4.default.bold(args.key)} = ${import_picocolors4.default.cyan(String(coerced))}`);
1816
2169
  } catch (err) {
1817
- console.error(`${import_picocolors3.default.red("\u2717")} ${String(err)}`);
2170
+ console.error(`${import_picocolors4.default.red("\u2717")} ${String(err)}`);
1818
2171
  process.exit(1);
1819
2172
  }
1820
2173
  }
1821
2174
  });
1822
- var getCommand = (0, import_citty3.defineCommand)({
2175
+ var getCommand = (0, import_citty4.defineCommand)({
1823
2176
  meta: { name: "get", description: "Get a config value" },
1824
2177
  args: {
1825
2178
  key: {
@@ -1831,32 +2184,32 @@ var getCommand = (0, import_citty3.defineCommand)({
1831
2184
  run({ args }) {
1832
2185
  const val = getConfigValue(args.key);
1833
2186
  if (val === void 0) {
1834
- console.log(import_picocolors3.default.dim(`${args.key}: (not set)`));
2187
+ console.log(import_picocolors4.default.dim(`${args.key}: (not set)`));
1835
2188
  } else {
1836
- console.log(`${import_picocolors3.default.bold(args.key)}: ${import_picocolors3.default.cyan(String(val))}`);
2189
+ console.log(`${import_picocolors4.default.bold(args.key)}: ${import_picocolors4.default.cyan(String(val))}`);
1837
2190
  }
1838
2191
  }
1839
2192
  });
1840
- var listCommand = (0, import_citty3.defineCommand)({
2193
+ var listCommand = (0, import_citty4.defineCommand)({
1841
2194
  meta: { name: "list", description: "List all config values" },
1842
2195
  run() {
1843
2196
  const data = readConfig();
1844
2197
  const entries = Object.entries(data);
1845
2198
  if (entries.length === 0) {
1846
- console.log(import_picocolors3.default.dim("No config values set. Use `mcpman config set <key> <value>`."));
2199
+ console.log(import_picocolors4.default.dim("No config values set. Use `mcpman config set <key> <value>`."));
1847
2200
  return;
1848
2201
  }
1849
2202
  console.log("");
1850
- console.log(import_picocolors3.default.bold("mcpman config:"));
2203
+ console.log(import_picocolors4.default.bold("mcpman config:"));
1851
2204
  console.log("");
1852
2205
  for (const [key, val] of entries) {
1853
- console.log(` ${import_picocolors3.default.green("\u25CF")} ${import_picocolors3.default.bold(key)} ${import_picocolors3.default.cyan(String(val))}`);
2206
+ console.log(` ${import_picocolors4.default.green("\u25CF")} ${import_picocolors4.default.bold(key)} ${import_picocolors4.default.cyan(String(val))}`);
1854
2207
  }
1855
2208
  console.log("");
1856
- console.log(import_picocolors3.default.dim(` ${entries.length} key${entries.length !== 1 ? "s" : ""} configured`));
2209
+ console.log(import_picocolors4.default.dim(` ${entries.length} key${entries.length !== 1 ? "s" : ""} configured`));
1857
2210
  }
1858
2211
  });
1859
- var resetCommand = (0, import_citty3.defineCommand)({
2212
+ var resetCommand = (0, import_citty4.defineCommand)({
1860
2213
  meta: { name: "reset", description: "Reset config to defaults (removes config file)" },
1861
2214
  async run() {
1862
2215
  const confirmed = await p2.confirm({
@@ -1868,10 +2221,10 @@ var resetCommand = (0, import_citty3.defineCommand)({
1868
2221
  return;
1869
2222
  }
1870
2223
  writeConfig({});
1871
- console.log(`${import_picocolors3.default.green("\u2713")} Config reset to defaults.`);
2224
+ console.log(`${import_picocolors4.default.green("\u2713")} Config reset to defaults.`);
1872
2225
  }
1873
2226
  });
1874
- var config_default = (0, import_citty3.defineCommand)({
2227
+ var config_default = (0, import_citty4.defineCommand)({
1875
2228
  meta: {
1876
2229
  name: "config",
1877
2230
  description: "Manage mcpman CLI configuration"
@@ -1886,14 +2239,14 @@ var config_default = (0, import_citty3.defineCommand)({
1886
2239
 
1887
2240
  // src/commands/create.ts
1888
2241
  init_cjs_shims();
1889
- var import_node_path9 = __toESM(require("path"), 1);
1890
- var import_citty4 = require("citty");
1891
- var import_picocolors4 = __toESM(require("picocolors"), 1);
2242
+ var import_node_path10 = __toESM(require("path"), 1);
2243
+ var import_citty5 = require("citty");
2244
+ var import_picocolors5 = __toESM(require("picocolors"), 1);
1892
2245
 
1893
2246
  // src/core/scaffold-service.ts
1894
2247
  init_cjs_shims();
1895
- var import_node_fs7 = __toESM(require("fs"), 1);
1896
- var import_node_path8 = __toESM(require("path"), 1);
2248
+ var import_node_fs9 = __toESM(require("fs"), 1);
2249
+ var import_node_path9 = __toESM(require("path"), 1);
1897
2250
  function sanitizeName(name) {
1898
2251
  return name.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
1899
2252
  }
@@ -2045,22 +2398,22 @@ if __name__ == "__main__":
2045
2398
  };
2046
2399
  }
2047
2400
  function writeScaffold(dir, files) {
2048
- if (import_node_fs7.default.existsSync(dir)) {
2049
- const existing = import_node_fs7.default.readdirSync(dir);
2401
+ if (import_node_fs9.default.existsSync(dir)) {
2402
+ const existing = import_node_fs9.default.readdirSync(dir);
2050
2403
  if (existing.length > 0) {
2051
2404
  throw new Error(`Directory '${dir}' already exists and is not empty.`);
2052
2405
  }
2053
2406
  }
2054
2407
  for (const [relativePath, content] of Object.entries(files)) {
2055
- const fullPath = import_node_path8.default.join(dir, relativePath);
2056
- const parentDir = import_node_path8.default.dirname(fullPath);
2057
- import_node_fs7.default.mkdirSync(parentDir, { recursive: true });
2058
- import_node_fs7.default.writeFileSync(fullPath, content, "utf-8");
2408
+ const fullPath = import_node_path9.default.join(dir, relativePath);
2409
+ const parentDir = import_node_path9.default.dirname(fullPath);
2410
+ import_node_fs9.default.mkdirSync(parentDir, { recursive: true });
2411
+ import_node_fs9.default.writeFileSync(fullPath, content, "utf-8");
2059
2412
  }
2060
2413
  }
2061
2414
 
2062
2415
  // src/commands/create.ts
2063
- var create_default = (0, import_citty4.defineCommand)({
2416
+ var create_default = (0, import_citty5.defineCommand)({
2064
2417
  meta: {
2065
2418
  name: "create",
2066
2419
  description: "Scaffold a new MCP server project"
@@ -2098,7 +2451,7 @@ var create_default = (0, import_citty4.defineCommand)({
2098
2451
  const readline = await import("readline");
2099
2452
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
2100
2453
  projectName = await new Promise((resolve) => {
2101
- rl.question(import_picocolors4.default.cyan(" Project name: "), (answer) => {
2454
+ rl.question(import_picocolors5.default.cyan(" Project name: "), (answer) => {
2102
2455
  rl.close();
2103
2456
  resolve(answer.trim());
2104
2457
  });
@@ -2108,7 +2461,7 @@ var create_default = (0, import_citty4.defineCommand)({
2108
2461
  const readline = await import("readline");
2109
2462
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
2110
2463
  projectDescription = await new Promise((resolve) => {
2111
- rl.question(import_picocolors4.default.cyan(" Description (optional): "), (answer) => {
2464
+ rl.question(import_picocolors5.default.cyan(" Description (optional): "), (answer) => {
2112
2465
  rl.close();
2113
2466
  resolve(answer.trim());
2114
2467
  });
@@ -2118,7 +2471,7 @@ var create_default = (0, import_citty4.defineCommand)({
2118
2471
  const readline = await import("readline");
2119
2472
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
2120
2473
  const answer = await new Promise((resolve) => {
2121
- rl.question(import_picocolors4.default.cyan(" Runtime [node/python] (default: node): "), (a) => {
2474
+ rl.question(import_picocolors5.default.cyan(" Runtime [node/python] (default: node): "), (a) => {
2122
2475
  rl.close();
2123
2476
  resolve(a.trim() || "node");
2124
2477
  });
@@ -2127,16 +2480,16 @@ var create_default = (0, import_citty4.defineCommand)({
2127
2480
  }
2128
2481
  }
2129
2482
  if (!projectName) {
2130
- console.error(import_picocolors4.default.red(" Error: Project name is required."));
2483
+ console.error(import_picocolors5.default.red(" Error: Project name is required."));
2131
2484
  process.exit(1);
2132
2485
  }
2133
2486
  const sanitized = sanitizeName(projectName);
2134
2487
  if (!sanitized) {
2135
- console.error(import_picocolors4.default.red(` Error: Invalid project name '${projectName}'.`));
2488
+ console.error(import_picocolors5.default.red(` Error: Invalid project name '${projectName}'.`));
2136
2489
  process.exit(1);
2137
2490
  }
2138
2491
  if (runtime !== "node" && runtime !== "python") {
2139
- console.error(import_picocolors4.default.red(` Error: Unknown runtime '${runtime}'. Use node or python.`));
2492
+ console.error(import_picocolors5.default.red(` Error: Unknown runtime '${runtime}'. Use node or python.`));
2140
2493
  process.exit(1);
2141
2494
  }
2142
2495
  const options = {
@@ -2146,54 +2499,218 @@ var create_default = (0, import_citty4.defineCommand)({
2146
2499
  transport: "stdio"
2147
2500
  };
2148
2501
  const files = runtime === "python" ? generatePythonProject(options) : generateNodeProject(options);
2149
- const targetDir = import_node_path9.default.resolve(sanitized);
2502
+ const targetDir = import_node_path10.default.resolve(sanitized);
2150
2503
  try {
2151
2504
  writeScaffold(targetDir, files);
2152
2505
  } catch (err) {
2153
- console.error(import_picocolors4.default.red(` Error: ${err instanceof Error ? err.message : String(err)}`));
2506
+ console.error(import_picocolors5.default.red(` Error: ${err instanceof Error ? err.message : String(err)}`));
2154
2507
  process.exit(1);
2155
2508
  }
2156
- console.log(import_picocolors4.default.green(`
2157
- Created ${import_picocolors4.default.bold(sanitized)}/
2509
+ console.log(import_picocolors5.default.green(`
2510
+ Created ${import_picocolors5.default.bold(sanitized)}/
2158
2511
  `));
2159
- console.log(import_picocolors4.default.dim(" Files generated:"));
2512
+ console.log(import_picocolors5.default.dim(" Files generated:"));
2160
2513
  for (const file of Object.keys(files)) {
2161
- console.log(` ${import_picocolors4.default.cyan(file)}`);
2514
+ console.log(` ${import_picocolors5.default.cyan(file)}`);
2162
2515
  }
2163
2516
  console.log("\n Next steps:");
2164
2517
  if (runtime === "node") {
2165
- console.log(` ${import_picocolors4.default.bold(`cd ${sanitized}`)}`);
2166
- console.log(` ${import_picocolors4.default.bold("npm install")}`);
2167
- console.log(` ${import_picocolors4.default.bold("mcpman link .")}`);
2518
+ console.log(` ${import_picocolors5.default.bold(`cd ${sanitized}`)}`);
2519
+ console.log(` ${import_picocolors5.default.bold("npm install")}`);
2520
+ console.log(` ${import_picocolors5.default.bold("mcpman link .")}`);
2168
2521
  } else {
2169
- console.log(` ${import_picocolors4.default.bold(`cd ${sanitized}`)}`);
2170
- console.log(` ${import_picocolors4.default.bold("pip install -e .")}`);
2171
- console.log(` ${import_picocolors4.default.bold("mcpman link .")}`);
2522
+ console.log(` ${import_picocolors5.default.bold(`cd ${sanitized}`)}`);
2523
+ console.log(` ${import_picocolors5.default.bold("pip install -e .")}`);
2524
+ console.log(` ${import_picocolors5.default.bold("mcpman link .")}`);
2172
2525
  }
2173
2526
  console.log();
2174
2527
  }
2175
2528
  });
2176
2529
 
2530
+ // src/commands/diff.ts
2531
+ init_cjs_shims();
2532
+ var import_citty6 = require("citty");
2533
+ var import_picocolors6 = __toESM(require("picocolors"), 1);
2534
+
2535
+ // src/core/config-differ.ts
2536
+ init_cjs_shims();
2537
+ function entryDiffs(a, b) {
2538
+ const diffs = [];
2539
+ if (a.command !== b.command) {
2540
+ diffs.push(`command: ${a.command} \u2192 ${b.command}`);
2541
+ }
2542
+ const aArgs = JSON.stringify(a.args ?? []);
2543
+ const bArgs = JSON.stringify(b.args ?? []);
2544
+ if (aArgs !== bArgs) {
2545
+ diffs.push(`args: ${aArgs} \u2192 ${bArgs}`);
2546
+ }
2547
+ const aEnv = JSON.stringify(a.env ?? {});
2548
+ const bEnv = JSON.stringify(b.env ?? {});
2549
+ if (aEnv !== bEnv) {
2550
+ diffs.push(`env: ${aEnv} \u2192 ${bEnv}`);
2551
+ }
2552
+ return diffs;
2553
+ }
2554
+ function diffClientConfigs(configA, configB) {
2555
+ const results = [];
2556
+ const serversA = configA.servers;
2557
+ const serversB = configB.servers;
2558
+ for (const name of Object.keys(serversB)) {
2559
+ if (!(name in serversA)) {
2560
+ results.push({ server: name, change: "added" });
2561
+ }
2562
+ }
2563
+ for (const name of Object.keys(serversA)) {
2564
+ if (!(name in serversB)) {
2565
+ results.push({ server: name, change: "removed" });
2566
+ }
2567
+ }
2568
+ for (const name of Object.keys(serversA)) {
2569
+ if (name in serversB) {
2570
+ const details = entryDiffs(serversA[name], serversB[name]);
2571
+ if (details.length > 0) {
2572
+ results.push({ server: name, change: "changed", details });
2573
+ }
2574
+ }
2575
+ }
2576
+ const order = { removed: 0, added: 1, changed: 2 };
2577
+ results.sort((a, b) => {
2578
+ const orderDiff = order[a.change] - order[b.change];
2579
+ return orderDiff !== 0 ? orderDiff : a.server.localeCompare(b.server);
2580
+ });
2581
+ return results;
2582
+ }
2583
+ async function loadClientConfig(type) {
2584
+ try {
2585
+ const { getClient: getClient2 } = await Promise.resolve().then(() => (init_client_detector(), client_detector_exports));
2586
+ const handler = getClient2(type);
2587
+ return await handler.readConfig();
2588
+ } catch {
2589
+ return null;
2590
+ }
2591
+ }
2592
+
2593
+ // src/commands/diff.ts
2594
+ var VALID_CLIENTS = ["claude-desktop", "cursor", "vscode", "windsurf"];
2595
+ var CLIENT_DISPLAY = {
2596
+ "claude-desktop": "Claude Desktop",
2597
+ cursor: "Cursor",
2598
+ vscode: "VS Code",
2599
+ windsurf: "Windsurf"
2600
+ };
2601
+ var diff_default = (0, import_citty6.defineCommand)({
2602
+ meta: {
2603
+ name: "diff",
2604
+ description: "Show config diff between two AI clients"
2605
+ },
2606
+ args: {
2607
+ clientA: {
2608
+ type: "positional",
2609
+ description: `Source client (${VALID_CLIENTS.join("|")})`,
2610
+ required: true
2611
+ },
2612
+ clientB: {
2613
+ type: "positional",
2614
+ description: `Target client (${VALID_CLIENTS.join("|")})`,
2615
+ required: true
2616
+ },
2617
+ json: {
2618
+ type: "boolean",
2619
+ description: "Output results as JSON",
2620
+ default: false
2621
+ }
2622
+ },
2623
+ async run({ args }) {
2624
+ const clientA = args.clientA;
2625
+ const clientB = args.clientB;
2626
+ if (!VALID_CLIENTS.includes(clientA)) {
2627
+ console.error(
2628
+ `${import_picocolors6.default.red("\u2717")} Unknown client "${clientA}". Valid: ${VALID_CLIENTS.join(", ")}`
2629
+ );
2630
+ process.exit(1);
2631
+ }
2632
+ if (!VALID_CLIENTS.includes(clientB)) {
2633
+ console.error(
2634
+ `${import_picocolors6.default.red("\u2717")} Unknown client "${clientB}". Valid: ${VALID_CLIENTS.join(", ")}`
2635
+ );
2636
+ process.exit(1);
2637
+ }
2638
+ if (clientA === clientB) {
2639
+ console.error(`${import_picocolors6.default.red("\u2717")} clientA and clientB must be different.`);
2640
+ process.exit(1);
2641
+ }
2642
+ const [configA, configB] = await Promise.all([
2643
+ loadClientConfig(clientA),
2644
+ loadClientConfig(clientB)
2645
+ ]);
2646
+ if (!configA) {
2647
+ console.error(`${import_picocolors6.default.red("\u2717")} Could not read config for ${CLIENT_DISPLAY[clientA]}.`);
2648
+ process.exit(1);
2649
+ }
2650
+ if (!configB) {
2651
+ console.error(`${import_picocolors6.default.red("\u2717")} Could not read config for ${CLIENT_DISPLAY[clientB]}.`);
2652
+ process.exit(1);
2653
+ }
2654
+ const diffs = diffClientConfigs(configA, configB);
2655
+ if (args.json) {
2656
+ console.log(JSON.stringify({ clientA, clientB, diffs }, null, 2));
2657
+ return;
2658
+ }
2659
+ const labelA = CLIENT_DISPLAY[clientA];
2660
+ const labelB = CLIENT_DISPLAY[clientB];
2661
+ console.log(`
2662
+ ${import_picocolors6.default.bold("mcpman diff")} ${import_picocolors6.default.cyan(labelA)} \u2192 ${import_picocolors6.default.cyan(labelB)}
2663
+ `);
2664
+ if (diffs.length === 0) {
2665
+ console.log(import_picocolors6.default.green(" \u2713 No differences \u2014 configs are identical."));
2666
+ console.log("");
2667
+ return;
2668
+ }
2669
+ for (const d of diffs) {
2670
+ if (d.change === "added") {
2671
+ console.log(` ${import_picocolors6.default.green("+")} ${import_picocolors6.default.bold(d.server)} ${import_picocolors6.default.dim(`(only in ${labelB})`)}`);
2672
+ } else if (d.change === "removed") {
2673
+ console.log(` ${import_picocolors6.default.red("-")} ${import_picocolors6.default.bold(d.server)} ${import_picocolors6.default.dim(`(only in ${labelA})`)}`);
2674
+ } else {
2675
+ console.log(` ${import_picocolors6.default.yellow("~")} ${import_picocolors6.default.bold(d.server)} ${import_picocolors6.default.dim("(changed)")}`);
2676
+ for (const detail of d.details ?? []) {
2677
+ console.log(` ${import_picocolors6.default.dim(detail)}`);
2678
+ }
2679
+ }
2680
+ }
2681
+ const added = diffs.filter((d) => d.change === "added").length;
2682
+ const removed = diffs.filter((d) => d.change === "removed").length;
2683
+ const changed = diffs.filter((d) => d.change === "changed").length;
2684
+ const parts = [];
2685
+ if (added > 0) parts.push(import_picocolors6.default.green(`+${added} added`));
2686
+ if (removed > 0) parts.push(import_picocolors6.default.red(`-${removed} removed`));
2687
+ if (changed > 0) parts.push(import_picocolors6.default.yellow(`~${changed} changed`));
2688
+ console.log(`
2689
+ ${parts.join(" ")}
2690
+ `);
2691
+ }
2692
+ });
2693
+
2177
2694
  // src/commands/doctor.ts
2178
2695
  init_cjs_shims();
2179
- var import_citty5 = require("citty");
2180
- var import_picocolors5 = __toESM(require("picocolors"), 1);
2696
+ var import_citty7 = require("citty");
2697
+ var import_picocolors7 = __toESM(require("picocolors"), 1);
2181
2698
 
2182
2699
  // src/core/health-checker.ts
2183
2700
  init_cjs_shims();
2184
2701
 
2185
2702
  // src/core/diagnostics.ts
2186
2703
  init_cjs_shims();
2187
- var import_node_child_process3 = require("child_process");
2704
+ var import_node_child_process4 = require("child_process");
2188
2705
  var import_node_util = require("util");
2189
2706
 
2190
2707
  // src/core/mcp-process-checks.ts
2191
2708
  init_cjs_shims();
2192
- var import_node_child_process2 = require("child_process");
2709
+ var import_node_child_process3 = require("child_process");
2193
2710
  async function checkProcessSpawn(command, args, env, timeoutMs = 3e3) {
2194
2711
  return new Promise((resolve) => {
2195
2712
  let settled = false;
2196
- const child = (0, import_node_child_process2.spawn)(command, args, {
2713
+ const child = (0, import_node_child_process3.spawn)(command, args, {
2197
2714
  env: { ...process.env, ...env },
2198
2715
  stdio: ["pipe", "pipe", "pipe"]
2199
2716
  });
@@ -2239,7 +2756,7 @@ async function checkMcpHandshake(command, args, env, timeoutMs = 5e3) {
2239
2756
  let settled = false;
2240
2757
  const start = Date.now();
2241
2758
  let stdout = "";
2242
- const child = (0, import_node_child_process2.spawn)(command, args, {
2759
+ const child = (0, import_node_child_process3.spawn)(command, args, {
2243
2760
  env: { ...process.env, ...env },
2244
2761
  stdio: ["pipe", "pipe", "pipe"]
2245
2762
  });
@@ -2296,7 +2813,7 @@ async function checkMcpHandshake(command, args, env, timeoutMs = 5e3) {
2296
2813
  }
2297
2814
 
2298
2815
  // src/core/diagnostics.ts
2299
- var execAsync = (0, import_node_util.promisify)(import_node_child_process3.exec);
2816
+ var execAsync = (0, import_node_util.promisify)(import_node_child_process4.exec);
2300
2817
  async function checkRuntime(command) {
2301
2818
  const cmd = process.platform === "win32" ? "where" : "which";
2302
2819
  const runtimeCmd = command === "npx" ? "node" : command === "uvx" ? "python3" : command;
@@ -2530,12 +3047,12 @@ async function getInstalledServers(clientFilter) {
2530
3047
 
2531
3048
  // src/commands/doctor.ts
2532
3049
  var CHECK_ICON = {
2533
- pass: import_picocolors5.default.green("\u2713"),
2534
- fail: import_picocolors5.default.red("\u2717"),
2535
- skip: import_picocolors5.default.dim("-"),
2536
- warn: import_picocolors5.default.yellow("\u26A0")
3050
+ pass: import_picocolors7.default.green("\u2713"),
3051
+ fail: import_picocolors7.default.red("\u2717"),
3052
+ skip: import_picocolors7.default.dim("-"),
3053
+ warn: import_picocolors7.default.yellow("\u26A0")
2537
3054
  };
2538
- var doctor_default = (0, import_citty5.defineCommand)({
3055
+ var doctor_default = (0, import_citty7.defineCommand)({
2539
3056
  meta: {
2540
3057
  name: "doctor",
2541
3058
  description: "Check MCP server health and configuration"
@@ -2548,11 +3065,11 @@ var doctor_default = (0, import_citty5.defineCommand)({
2548
3065
  }
2549
3066
  },
2550
3067
  async run({ args }) {
2551
- console.log(import_picocolors5.default.bold("\n mcpman doctor\n"));
3068
+ console.log(import_picocolors7.default.bold("\n mcpman doctor\n"));
2552
3069
  const servers = await getInstalledServers();
2553
3070
  if (servers.length === 0) {
2554
3071
  console.log(
2555
- import_picocolors5.default.dim(" No MCP servers installed. Run mcpman install <server> to get started.")
3072
+ import_picocolors7.default.dim(" No MCP servers installed. Run mcpman install <server> to get started.")
2556
3073
  );
2557
3074
  return;
2558
3075
  }
@@ -2569,20 +3086,20 @@ var doctor_default = (0, import_citty5.defineCommand)({
2569
3086
  if (pluginSummary.total > 0) {
2570
3087
  printPluginSection(pluginSummary);
2571
3088
  }
2572
- console.log(import_picocolors5.default.dim(` ${"\u2500".repeat(50)}`));
3089
+ console.log(import_picocolors7.default.dim(` ${"\u2500".repeat(50)}`));
2573
3090
  const parts = [];
2574
- if (passed > 0) parts.push(import_picocolors5.default.green(`${passed} healthy`));
2575
- if (failed > 0) parts.push(import_picocolors5.default.red(`${failed} unhealthy`));
3091
+ if (passed > 0) parts.push(import_picocolors7.default.green(`${passed} healthy`));
3092
+ if (failed > 0) parts.push(import_picocolors7.default.red(`${failed} unhealthy`));
2576
3093
  console.log(` Summary: ${parts.join(", ")}`);
2577
3094
  if (pluginSummary.total > 0) {
2578
3095
  const pParts = [];
2579
- if (pluginSummary.healthy > 0) pParts.push(import_picocolors5.default.green(`${pluginSummary.healthy} ok`));
2580
- if (pluginSummary.unhealthy > 0) pParts.push(import_picocolors5.default.red(`${pluginSummary.unhealthy} broken`));
3096
+ if (pluginSummary.healthy > 0) pParts.push(import_picocolors7.default.green(`${pluginSummary.healthy} ok`));
3097
+ if (pluginSummary.unhealthy > 0) pParts.push(import_picocolors7.default.red(`${pluginSummary.unhealthy} broken`));
2581
3098
  console.log(` Plugins: ${pParts.join(", ")}`);
2582
3099
  }
2583
3100
  if (failed > 0 || pluginSummary.unhealthy > 0) {
2584
3101
  if (!args.fix) {
2585
- console.log(import_picocolors5.default.dim(` Run ${import_picocolors5.default.cyan("mcpman doctor --fix")} for fix suggestions.
3102
+ console.log(import_picocolors7.default.dim(` Run ${import_picocolors7.default.cyan("mcpman doctor --fix")} for fix suggestions.
2586
3103
  `));
2587
3104
  }
2588
3105
  process.exit(1);
@@ -2591,26 +3108,26 @@ var doctor_default = (0, import_citty5.defineCommand)({
2591
3108
  }
2592
3109
  });
2593
3110
  function printPluginSection(summary) {
2594
- console.log(import_picocolors5.default.bold(` Plugins (${summary.total})`));
3111
+ console.log(import_picocolors7.default.bold(` Plugins (${summary.total})`));
2595
3112
  for (const r of summary.results) {
2596
- const icon = r.loadable && r.prefixUnique && r.resolvable ? import_picocolors5.default.green("\u2713") : import_picocolors5.default.red("\u2717");
3113
+ const icon = r.loadable && r.prefixUnique && r.resolvable ? import_picocolors7.default.green("\u2713") : import_picocolors7.default.red("\u2717");
2597
3114
  const label = r.pluginName ? `${r.packageName} (${r.pluginName})` : r.packageName;
2598
- const prefix = r.prefix ? import_picocolors5.default.dim(` [${r.prefix}]`) : "";
3115
+ const prefix = r.prefix ? import_picocolors7.default.dim(` [${r.prefix}]`) : "";
2599
3116
  console.log(` ${icon} ${label}${prefix}`);
2600
3117
  if (r.error) {
2601
- console.log(` ${import_picocolors5.default.yellow("\u2192")} ${r.error}`);
3118
+ console.log(` ${import_picocolors7.default.yellow("\u2192")} ${r.error}`);
2602
3119
  }
2603
3120
  }
2604
3121
  console.log();
2605
3122
  }
2606
3123
  function printServerResult(result, showFix) {
2607
- const icon = result.status === "healthy" ? import_picocolors5.default.green("\u25CF") : import_picocolors5.default.red("\u25CF");
2608
- console.log(` ${icon} ${import_picocolors5.default.bold(result.serverName)}`);
3124
+ const icon = result.status === "healthy" ? import_picocolors7.default.green("\u25CF") : import_picocolors7.default.red("\u25CF");
3125
+ console.log(` ${icon} ${import_picocolors7.default.bold(result.serverName)}`);
2609
3126
  for (const check of result.checks) {
2610
3127
  const checkIcon = check.skipped ? CHECK_ICON.skip : check.passed ? CHECK_ICON.pass : CHECK_ICON.fail;
2611
3128
  console.log(` ${checkIcon} ${check.name}: ${check.message}`);
2612
3129
  if (showFix && !check.passed && !check.skipped && check.fix) {
2613
- console.log(` ${import_picocolors5.default.yellow("\u2192")} Fix: ${import_picocolors5.default.cyan(check.fix)}`);
3130
+ console.log(` ${import_picocolors7.default.yellow("\u2192")} Fix: ${import_picocolors7.default.cyan(check.fix)}`);
2614
3131
  }
2615
3132
  }
2616
3133
  console.log();
@@ -2619,11 +3136,11 @@ async function runParallel(tasks, concurrency) {
2619
3136
  const results = [];
2620
3137
  const executing = /* @__PURE__ */ new Set();
2621
3138
  for (const task of tasks) {
2622
- const p13 = task().then((r) => {
3139
+ const p14 = task().then((r) => {
2623
3140
  results.push(r);
2624
- executing.delete(p13);
3141
+ executing.delete(p14);
2625
3142
  });
2626
- executing.add(p13);
3143
+ executing.add(p14);
2627
3144
  if (executing.size >= concurrency) {
2628
3145
  await Promise.race(executing);
2629
3146
  }
@@ -2632,21 +3149,194 @@ async function runParallel(tasks, concurrency) {
2632
3149
  return results;
2633
3150
  }
2634
3151
 
2635
- // src/commands/export-command.ts
3152
+ // src/commands/env.ts
3153
+ init_cjs_shims();
3154
+ var import_citty8 = require("citty");
3155
+ var import_picocolors8 = __toESM(require("picocolors"), 1);
3156
+
3157
+ // src/core/env-manager.ts
2636
3158
  init_cjs_shims();
2637
3159
  var import_node_fs10 = __toESM(require("fs"), 1);
2638
3160
  var import_node_path11 = __toESM(require("path"), 1);
2639
- var import_citty6 = require("citty");
2640
- var import_picocolors6 = __toESM(require("picocolors"), 1);
3161
+ init_paths();
3162
+ function envFilePath(server, dir) {
3163
+ const base = dir ?? getEnvDir();
3164
+ const safe = server.replace(/[/@]/g, "_");
3165
+ return import_node_path11.default.join(base, `${safe}.json`);
3166
+ }
3167
+ function readStore(server, dir) {
3168
+ const file = envFilePath(server, dir);
3169
+ if (!import_node_fs10.default.existsSync(file)) return {};
3170
+ try {
3171
+ return JSON.parse(import_node_fs10.default.readFileSync(file, "utf-8"));
3172
+ } catch {
3173
+ return {};
3174
+ }
3175
+ }
3176
+ function writeStore(server, store, dir) {
3177
+ const base = dir ?? getEnvDir();
3178
+ if (!import_node_fs10.default.existsSync(base)) {
3179
+ import_node_fs10.default.mkdirSync(base, { recursive: true });
3180
+ }
3181
+ const file = envFilePath(server, dir);
3182
+ import_node_fs10.default.writeFileSync(file, JSON.stringify(store, null, 2), "utf-8");
3183
+ }
3184
+ function setEnv(server, key, value, dir) {
3185
+ const store = readStore(server, dir);
3186
+ store[key] = value;
3187
+ writeStore(server, store, dir);
3188
+ }
3189
+ function getEnv(server, key, dir) {
3190
+ const store = readStore(server, dir);
3191
+ return key in store ? store[key] : null;
3192
+ }
3193
+ function listEnv(server, dir) {
3194
+ return readStore(server, dir);
3195
+ }
3196
+ function deleteEnv(server, key, dir) {
3197
+ const store = readStore(server, dir);
3198
+ if (!(key in store)) return;
3199
+ delete store[key];
3200
+ writeStore(server, store, dir);
3201
+ }
3202
+ function clearEnv(server, dir) {
3203
+ const file = envFilePath(server, dir);
3204
+ if (import_node_fs10.default.existsSync(file)) {
3205
+ import_node_fs10.default.unlinkSync(file);
3206
+ }
3207
+ }
3208
+ function listEnvServers(dir) {
3209
+ const base = dir ?? getEnvDir();
3210
+ if (!import_node_fs10.default.existsSync(base)) return [];
3211
+ return import_node_fs10.default.readdirSync(base).filter((f) => f.endsWith(".json")).map((f) => f.slice(0, -5));
3212
+ }
3213
+
3214
+ // src/commands/env.ts
3215
+ var setCmd = (0, import_citty8.defineCommand)({
3216
+ meta: { name: "set", description: "Set env var(s) for a server" },
3217
+ args: {
3218
+ server: { type: "positional", description: "Server name", required: true },
3219
+ pairs: { type: "positional", description: "KEY=VALUE pair(s)", required: true }
3220
+ },
3221
+ run({ args }) {
3222
+ const pairs = Array.isArray(args.pairs) ? args.pairs : [args.pairs];
3223
+ for (const pair of pairs) {
3224
+ const idx = pair.indexOf("=");
3225
+ if (idx <= 0) {
3226
+ console.error(`${import_picocolors8.default.red("\u2717")} Invalid format: "${pair}". Expected KEY=VALUE`);
3227
+ process.exit(1);
3228
+ }
3229
+ const key = pair.slice(0, idx);
3230
+ const value = pair.slice(idx + 1);
3231
+ setEnv(args.server, key, value);
3232
+ console.log(
3233
+ `${import_picocolors8.default.green("\u2713")} Set ${import_picocolors8.default.bold(key)}=${import_picocolors8.default.dim(value)} for ${import_picocolors8.default.cyan(args.server)}`
3234
+ );
3235
+ }
3236
+ }
3237
+ });
3238
+ var getCmd = (0, import_citty8.defineCommand)({
3239
+ meta: { name: "get", description: "Get an env var for a server" },
3240
+ args: {
3241
+ server: { type: "positional", description: "Server name", required: true },
3242
+ key: { type: "positional", description: "Variable name", required: true }
3243
+ },
3244
+ run({ args }) {
3245
+ const value = getEnv(args.server, args.key);
3246
+ if (value === null) {
3247
+ console.error(`${import_picocolors8.default.red("\u2717")} No env var "${args.key}" for ${import_picocolors8.default.cyan(args.server)}`);
3248
+ process.exit(1);
3249
+ }
3250
+ console.log(value);
3251
+ }
3252
+ });
3253
+ var listCmd = (0, import_citty8.defineCommand)({
3254
+ meta: { name: "list", description: "List env vars for a server (or all servers)" },
3255
+ args: {
3256
+ server: { type: "positional", description: "Server name (optional)", required: false }
3257
+ },
3258
+ run({ args }) {
3259
+ if (args.server) {
3260
+ const store = listEnv(args.server);
3261
+ const keys = Object.keys(store);
3262
+ if (keys.length === 0) {
3263
+ console.log(import_picocolors8.default.dim(`No env vars for ${import_picocolors8.default.cyan(args.server)}.`));
3264
+ return;
3265
+ }
3266
+ console.log(`
3267
+ ${import_picocolors8.default.bold(import_picocolors8.default.cyan(args.server))}`);
3268
+ for (const [k, v] of Object.entries(store)) {
3269
+ console.log(` ${import_picocolors8.default.green("\u25CF")} ${import_picocolors8.default.bold(k)}=${import_picocolors8.default.dim(v)}`);
3270
+ }
3271
+ console.log("");
3272
+ } else {
3273
+ const servers = listEnvServers();
3274
+ if (servers.length === 0) {
3275
+ console.log(import_picocolors8.default.dim("No env vars stored."));
3276
+ return;
3277
+ }
3278
+ for (const srv of servers) {
3279
+ const store = listEnv(srv);
3280
+ console.log(`
3281
+ ${import_picocolors8.default.bold(import_picocolors8.default.cyan(srv))}`);
3282
+ for (const [k, v] of Object.entries(store)) {
3283
+ console.log(` ${import_picocolors8.default.green("\u25CF")} ${import_picocolors8.default.bold(k)}=${import_picocolors8.default.dim(v)}`);
3284
+ }
3285
+ }
3286
+ console.log("");
3287
+ }
3288
+ }
3289
+ });
3290
+ var delCmd = (0, import_citty8.defineCommand)({
3291
+ meta: { name: "del", description: "Delete an env var for a server" },
3292
+ args: {
3293
+ server: { type: "positional", description: "Server name", required: true },
3294
+ key: { type: "positional", description: "Variable name to delete", required: true }
3295
+ },
3296
+ run({ args }) {
3297
+ deleteEnv(args.server, args.key);
3298
+ console.log(`${import_picocolors8.default.green("\u2713")} Deleted ${import_picocolors8.default.bold(args.key)} from ${import_picocolors8.default.cyan(args.server)}`);
3299
+ }
3300
+ });
3301
+ var clearCmd = (0, import_citty8.defineCommand)({
3302
+ meta: { name: "clear", description: "Clear all env vars for a server" },
3303
+ args: {
3304
+ server: { type: "positional", description: "Server name", required: true }
3305
+ },
3306
+ run({ args }) {
3307
+ clearEnv(args.server);
3308
+ console.log(`${import_picocolors8.default.green("\u2713")} Cleared all env vars for ${import_picocolors8.default.cyan(args.server)}`);
3309
+ }
3310
+ });
3311
+ var env_default = (0, import_citty8.defineCommand)({
3312
+ meta: {
3313
+ name: "env",
3314
+ description: "Manage per-server environment variables (non-sensitive)"
3315
+ },
3316
+ subCommands: {
3317
+ set: setCmd,
3318
+ get: getCmd,
3319
+ list: listCmd,
3320
+ del: delCmd,
3321
+ clear: clearCmd
3322
+ }
3323
+ });
3324
+
3325
+ // src/commands/export-command.ts
3326
+ init_cjs_shims();
3327
+ var import_node_fs13 = __toESM(require("fs"), 1);
3328
+ var import_node_path13 = __toESM(require("path"), 1);
3329
+ var import_citty9 = require("citty");
3330
+ var import_picocolors9 = __toESM(require("picocolors"), 1);
2641
3331
 
2642
3332
  // src/core/export-import-service.ts
2643
3333
  init_cjs_shims();
2644
- var import_node_fs9 = __toESM(require("fs"), 1);
3334
+ var import_node_fs12 = __toESM(require("fs"), 1);
2645
3335
 
2646
3336
  // src/utils/constants.ts
2647
3337
  init_cjs_shims();
2648
3338
  var APP_NAME = "mcpman";
2649
- var APP_VERSION = "0.7.0";
3339
+ var APP_VERSION = "0.8.0";
2650
3340
  var APP_DESCRIPTION = "The package manager for MCP servers";
2651
3341
 
2652
3342
  // src/core/export-import-service.ts
@@ -2664,7 +3354,7 @@ function createExportBundle(opts = {}) {
2664
3354
  };
2665
3355
  if (includeVault) {
2666
3356
  const vaultPath = getVaultPath();
2667
- if (import_node_fs9.default.existsSync(vaultPath)) {
3357
+ if (import_node_fs12.default.existsSync(vaultPath)) {
2668
3358
  bundle.vault = readVault();
2669
3359
  }
2670
3360
  }
@@ -2730,7 +3420,7 @@ function importBundle(bundle, opts = {}) {
2730
3420
 
2731
3421
  // src/commands/export-command.ts
2732
3422
  var DEFAULT_OUTPUT = "mcpman-export.json";
2733
- var export_command_default = (0, import_citty6.defineCommand)({
3423
+ var export_command_default = (0, import_citty9.defineCommand)({
2734
3424
  meta: {
2735
3425
  name: "export",
2736
3426
  description: "Export mcpman config, lockfile, vault, and plugins to a portable JSON file"
@@ -2753,31 +3443,245 @@ var export_command_default = (0, import_citty6.defineCommand)({
2753
3443
  }
2754
3444
  },
2755
3445
  run({ args }) {
2756
- const outputFile = args.output || DEFAULT_OUTPUT;
2757
- const outputPath = import_node_path11.default.resolve(outputFile);
2758
- const bundle = createExportBundle({
2759
- includeVault: !args["no-vault"],
2760
- includePlugins: !args["no-plugins"]
3446
+ const outputFile = args.output || DEFAULT_OUTPUT;
3447
+ const outputPath = import_node_path13.default.resolve(outputFile);
3448
+ const bundle = createExportBundle({
3449
+ includeVault: !args["no-vault"],
3450
+ includePlugins: !args["no-plugins"]
3451
+ });
3452
+ const serverCount = Object.keys(bundle.lockfile.servers).length;
3453
+ const configKeys = Object.keys(bundle.config).length;
3454
+ import_node_fs13.default.writeFileSync(outputPath, JSON.stringify(bundle, null, 2), "utf-8");
3455
+ console.log(`${import_picocolors9.default.green("\u2713")} Exported to ${import_picocolors9.default.bold(outputFile)}`);
3456
+ console.log(import_picocolors9.default.dim(` Config keys: ${configKeys}`));
3457
+ console.log(import_picocolors9.default.dim(` Servers: ${serverCount}`));
3458
+ console.log(import_picocolors9.default.dim(` Vault: ${bundle.vault ? "included" : "excluded"}`));
3459
+ console.log(import_picocolors9.default.dim(` Plugins: ${bundle.plugins?.length ?? 0}`));
3460
+ }
3461
+ });
3462
+
3463
+ // src/commands/group.ts
3464
+ init_cjs_shims();
3465
+ var import_node_child_process5 = require("child_process");
3466
+ var import_citty10 = require("citty");
3467
+ var import_picocolors10 = __toESM(require("picocolors"), 1);
3468
+
3469
+ // src/core/group-manager.ts
3470
+ init_cjs_shims();
3471
+ var import_node_fs14 = __toESM(require("fs"), 1);
3472
+ init_paths();
3473
+ function readGroups(file) {
3474
+ const target = file ?? getGroupsFile();
3475
+ if (!import_node_fs14.default.existsSync(target)) return {};
3476
+ try {
3477
+ return JSON.parse(import_node_fs14.default.readFileSync(target, "utf-8"));
3478
+ } catch {
3479
+ return {};
3480
+ }
3481
+ }
3482
+ function writeGroups(store, file) {
3483
+ const target = file ?? getGroupsFile();
3484
+ const dir = target.slice(0, target.lastIndexOf("/"));
3485
+ if (dir && !import_node_fs14.default.existsSync(dir)) {
3486
+ import_node_fs14.default.mkdirSync(dir, { recursive: true });
3487
+ }
3488
+ import_node_fs14.default.writeFileSync(target, JSON.stringify(store, null, 2), "utf-8");
3489
+ }
3490
+ function addToGroup(group, servers, file) {
3491
+ const store = readGroups(file);
3492
+ const existing = new Set(store[group] ?? []);
3493
+ for (const s of servers) existing.add(s);
3494
+ store[group] = [...existing].sort();
3495
+ writeGroups(store, file);
3496
+ }
3497
+ function removeFromGroup(group, servers, file) {
3498
+ const store = readGroups(file);
3499
+ if (!store[group]) return;
3500
+ const toRemove = new Set(servers);
3501
+ store[group] = store[group].filter((s) => !toRemove.has(s));
3502
+ if (store[group].length === 0) delete store[group];
3503
+ writeGroups(store, file);
3504
+ }
3505
+ function getGroup(group, file) {
3506
+ return readGroups(file)[group] ?? [];
3507
+ }
3508
+ function listGroups(file) {
3509
+ return Object.keys(readGroups(file)).sort();
3510
+ }
3511
+ function deleteGroup(group, file) {
3512
+ const store = readGroups(file);
3513
+ if (!(group in store)) return;
3514
+ delete store[group];
3515
+ writeGroups(store, file);
3516
+ }
3517
+ function groupExists(group, file) {
3518
+ return group in readGroups(file);
3519
+ }
3520
+
3521
+ // src/commands/group.ts
3522
+ init_lockfile();
3523
+ var addCmd = (0, import_citty10.defineCommand)({
3524
+ meta: { name: "add", description: "Add servers to a group" },
3525
+ args: {
3526
+ name: { type: "positional", description: "Group name", required: true },
3527
+ servers: { type: "positional", description: "Server name(s)", required: true }
3528
+ },
3529
+ run({ args }) {
3530
+ const servers = Array.isArray(args.servers) ? args.servers : [args.servers];
3531
+ addToGroup(args.name, servers);
3532
+ console.log(`${import_picocolors10.default.green("\u2713")} Added ${servers.join(", ")} to group ${import_picocolors10.default.cyan(args.name)}`);
3533
+ }
3534
+ });
3535
+ var rmCmd = (0, import_citty10.defineCommand)({
3536
+ meta: { name: "rm", description: "Remove servers from a group" },
3537
+ args: {
3538
+ name: { type: "positional", description: "Group name", required: true },
3539
+ servers: { type: "positional", description: "Server name(s)", required: true }
3540
+ },
3541
+ run({ args }) {
3542
+ const servers = Array.isArray(args.servers) ? args.servers : [args.servers];
3543
+ removeFromGroup(args.name, servers);
3544
+ console.log(`${import_picocolors10.default.green("\u2713")} Removed ${servers.join(", ")} from group ${import_picocolors10.default.cyan(args.name)}`);
3545
+ }
3546
+ });
3547
+ var listCmd2 = (0, import_citty10.defineCommand)({
3548
+ meta: { name: "list", description: "List all groups (or members of a group)" },
3549
+ args: {
3550
+ name: { type: "positional", description: "Group name (optional)", required: false }
3551
+ },
3552
+ run({ args }) {
3553
+ if (args.name) {
3554
+ const members = getGroup(args.name);
3555
+ if (members.length === 0) {
3556
+ console.log(import_picocolors10.default.dim(`Group "${args.name}" is empty or does not exist.`));
3557
+ return;
3558
+ }
3559
+ console.log(`
3560
+ ${import_picocolors10.default.bold(import_picocolors10.default.cyan(args.name))}`);
3561
+ for (const s of members) console.log(` ${import_picocolors10.default.green("\u25CF")} ${s}`);
3562
+ console.log("");
3563
+ } else {
3564
+ const groups = listGroups();
3565
+ if (groups.length === 0) {
3566
+ console.log(import_picocolors10.default.dim("No groups defined. Use `mcpman group add <name> <server>`."));
3567
+ return;
3568
+ }
3569
+ console.log("");
3570
+ for (const g of groups) {
3571
+ const members = getGroup(g);
3572
+ console.log(
3573
+ ` ${import_picocolors10.default.cyan(import_picocolors10.default.bold(g))} ${import_picocolors10.default.dim(`(${members.length} server${members.length !== 1 ? "s" : ""})`)}`
3574
+ );
3575
+ for (const s of members) console.log(` ${import_picocolors10.default.dim("\xB7")} ${s}`);
3576
+ }
3577
+ console.log("");
3578
+ }
3579
+ }
3580
+ });
3581
+ var deleteCmd = (0, import_citty10.defineCommand)({
3582
+ meta: { name: "delete", description: "Delete an entire group" },
3583
+ args: {
3584
+ name: { type: "positional", description: "Group name", required: true }
3585
+ },
3586
+ run({ args }) {
3587
+ if (!groupExists(args.name)) {
3588
+ console.error(`${import_picocolors10.default.red("\u2717")} Group "${args.name}" does not exist.`);
3589
+ process.exit(1);
3590
+ }
3591
+ deleteGroup(args.name);
3592
+ console.log(`${import_picocolors10.default.green("\u2713")} Deleted group ${import_picocolors10.default.cyan(args.name)}`);
3593
+ }
3594
+ });
3595
+ var installCmd = (0, import_citty10.defineCommand)({
3596
+ meta: { name: "install", description: "Install all servers in a group" },
3597
+ args: {
3598
+ name: { type: "positional", description: "Group name", required: true }
3599
+ },
3600
+ async run({ args }) {
3601
+ const members = getGroup(args.name);
3602
+ if (members.length === 0) {
3603
+ console.error(`${import_picocolors10.default.red("\u2717")} Group "${args.name}" is empty or does not exist.`);
3604
+ process.exit(1);
3605
+ }
3606
+ console.log(
3607
+ `${import_picocolors10.default.cyan("Installing")} group ${import_picocolors10.default.bold(args.name)} (${members.length} servers)...`
3608
+ );
3609
+ for (const server of members) {
3610
+ console.log(`
3611
+ ${import_picocolors10.default.dim("\u2192")} Installing ${import_picocolors10.default.bold(server)}...`);
3612
+ await runInstall(server);
3613
+ }
3614
+ console.log(`
3615
+ ${import_picocolors10.default.green("\u2713")} Group install complete.`);
3616
+ }
3617
+ });
3618
+ var runCmd = (0, import_citty10.defineCommand)({
3619
+ meta: { name: "run", description: "Run all servers in a group concurrently" },
3620
+ args: {
3621
+ name: { type: "positional", description: "Group name", required: true }
3622
+ },
3623
+ run({ args }) {
3624
+ const members = getGroup(args.name);
3625
+ if (members.length === 0) {
3626
+ console.error(`${import_picocolors10.default.red("\u2717")} Group "${args.name}" is empty or does not exist.`);
3627
+ process.exit(1);
3628
+ }
3629
+ const lockfile = readLockfile();
3630
+ console.log(
3631
+ `${import_picocolors10.default.cyan("Spawning")} group ${import_picocolors10.default.bold(args.name)} (${members.length} servers)...
3632
+ `
3633
+ );
3634
+ for (const server of members) {
3635
+ const entry = lockfile.servers[server];
3636
+ if (!entry) {
3637
+ console.warn(` ${import_picocolors10.default.yellow("!")} ${server} not in lockfile \u2014 skipping`);
3638
+ continue;
3639
+ }
3640
+ const child = (0, import_node_child_process5.spawn)(entry.command, entry.args ?? [], {
3641
+ env: process.env,
3642
+ stdio: "inherit",
3643
+ detached: false
3644
+ });
3645
+ child.on("error", (err) => {
3646
+ console.error(` ${import_picocolors10.default.red("\u2717")} ${server}: ${err.message}`);
3647
+ });
3648
+ console.log(` ${import_picocolors10.default.green("\u2713")} Spawned ${import_picocolors10.default.bold(server)} (pid ${child.pid ?? "?"})`);
3649
+ }
3650
+ }
3651
+ });
3652
+ function runInstall(server) {
3653
+ return new Promise((resolve, reject) => {
3654
+ const child = (0, import_node_child_process5.spawn)("mcpman", ["install", server], { stdio: "inherit" });
3655
+ child.on("close", (code) => {
3656
+ if (code === 0) resolve();
3657
+ else reject(new Error(`install exited with code ${code}`));
2761
3658
  });
2762
- const serverCount = Object.keys(bundle.lockfile.servers).length;
2763
- const configKeys = Object.keys(bundle.config).length;
2764
- import_node_fs10.default.writeFileSync(outputPath, JSON.stringify(bundle, null, 2), "utf-8");
2765
- console.log(`${import_picocolors6.default.green("\u2713")} Exported to ${import_picocolors6.default.bold(outputFile)}`);
2766
- console.log(import_picocolors6.default.dim(` Config keys: ${configKeys}`));
2767
- console.log(import_picocolors6.default.dim(` Servers: ${serverCount}`));
2768
- console.log(import_picocolors6.default.dim(` Vault: ${bundle.vault ? "included" : "excluded"}`));
2769
- console.log(import_picocolors6.default.dim(` Plugins: ${bundle.plugins?.length ?? 0}`));
3659
+ child.on("error", reject);
3660
+ });
3661
+ }
3662
+ var group_default = (0, import_citty10.defineCommand)({
3663
+ meta: {
3664
+ name: "group",
3665
+ description: "Manage named server groups"
3666
+ },
3667
+ subCommands: {
3668
+ add: addCmd,
3669
+ rm: rmCmd,
3670
+ list: listCmd2,
3671
+ delete: deleteCmd,
3672
+ install: installCmd,
3673
+ run: runCmd
2770
3674
  }
2771
3675
  });
2772
3676
 
2773
3677
  // src/commands/import-command.ts
2774
3678
  init_cjs_shims();
2775
- var import_node_fs11 = __toESM(require("fs"), 1);
2776
- var import_node_path12 = __toESM(require("path"), 1);
3679
+ var import_node_fs15 = __toESM(require("fs"), 1);
3680
+ var import_node_path14 = __toESM(require("path"), 1);
2777
3681
  var p4 = __toESM(require("@clack/prompts"), 1);
2778
- var import_citty7 = require("citty");
2779
- var import_picocolors7 = __toESM(require("picocolors"), 1);
2780
- var import_command_default = (0, import_citty7.defineCommand)({
3682
+ var import_citty11 = require("citty");
3683
+ var import_picocolors11 = __toESM(require("picocolors"), 1);
3684
+ var import_command_default = (0, import_citty11.defineCommand)({
2781
3685
  meta: {
2782
3686
  name: "import",
2783
3687
  description: "Import mcpman config, lockfile, vault, and plugins from an export file"
@@ -2800,21 +3704,21 @@ var import_command_default = (0, import_citty7.defineCommand)({
2800
3704
  }
2801
3705
  },
2802
3706
  async run({ args }) {
2803
- const filePath = import_node_path12.default.resolve(args.file);
2804
- if (!import_node_fs11.default.existsSync(filePath)) {
2805
- console.error(`${import_picocolors7.default.red("\u2717")} File not found: ${filePath}`);
3707
+ const filePath = import_node_path14.default.resolve(args.file);
3708
+ if (!import_node_fs15.default.existsSync(filePath)) {
3709
+ console.error(`${import_picocolors11.default.red("\u2717")} File not found: ${filePath}`);
2806
3710
  process.exit(1);
2807
3711
  }
2808
3712
  let raw;
2809
3713
  try {
2810
- raw = JSON.parse(import_node_fs11.default.readFileSync(filePath, "utf-8"));
3714
+ raw = JSON.parse(import_node_fs15.default.readFileSync(filePath, "utf-8"));
2811
3715
  } catch {
2812
- console.error(`${import_picocolors7.default.red("\u2717")} Invalid JSON in ${filePath}`);
3716
+ console.error(`${import_picocolors11.default.red("\u2717")} Invalid JSON in ${filePath}`);
2813
3717
  process.exit(1);
2814
3718
  }
2815
3719
  const error2 = validateBundle(raw);
2816
3720
  if (error2) {
2817
- console.error(`${import_picocolors7.default.red("\u2717")} Invalid export bundle: ${error2}`);
3721
+ console.error(`${import_picocolors11.default.red("\u2717")} Invalid export bundle: ${error2}`);
2818
3722
  process.exit(1);
2819
3723
  }
2820
3724
  const bundle = raw;
@@ -2824,16 +3728,16 @@ var import_command_default = (0, import_citty7.defineCommand)({
2824
3728
  const hasVault = !!bundle.vault;
2825
3729
  const isDryRun = !!args["dry-run"];
2826
3730
  console.log("");
2827
- console.log(import_picocolors7.default.bold("Import summary:"));
2828
- console.log(import_picocolors7.default.dim(` Source version: mcpman ${bundle.mcpmanVersion}`));
2829
- console.log(import_picocolors7.default.dim(` Exported at: ${bundle.exportedAt}`));
2830
- console.log(` Config keys: ${import_picocolors7.default.cyan(String(configKeys))}`);
2831
- console.log(` Servers: ${import_picocolors7.default.cyan(String(serverCount))}`);
2832
- console.log(` Vault: ${hasVault ? import_picocolors7.default.green("included") : import_picocolors7.default.dim("not included")}`);
2833
- console.log(` Plugins: ${import_picocolors7.default.cyan(String(pluginCount))}`);
3731
+ console.log(import_picocolors11.default.bold("Import summary:"));
3732
+ console.log(import_picocolors11.default.dim(` Source version: mcpman ${bundle.mcpmanVersion}`));
3733
+ console.log(import_picocolors11.default.dim(` Exported at: ${bundle.exportedAt}`));
3734
+ console.log(` Config keys: ${import_picocolors11.default.cyan(String(configKeys))}`);
3735
+ console.log(` Servers: ${import_picocolors11.default.cyan(String(serverCount))}`);
3736
+ console.log(` Vault: ${hasVault ? import_picocolors11.default.green("included") : import_picocolors11.default.dim("not included")}`);
3737
+ console.log(` Plugins: ${import_picocolors11.default.cyan(String(pluginCount))}`);
2834
3738
  console.log("");
2835
3739
  if (isDryRun) {
2836
- console.log(import_picocolors7.default.yellow(" [dry-run] No changes applied."));
3740
+ console.log(import_picocolors11.default.yellow(" [dry-run] No changes applied."));
2837
3741
  return;
2838
3742
  }
2839
3743
  if (!args.yes) {
@@ -2847,19 +3751,19 @@ var import_command_default = (0, import_citty7.defineCommand)({
2847
3751
  }
2848
3752
  }
2849
3753
  const summary = importBundle(bundle, { dryRun: false });
2850
- console.log(`${import_picocolors7.default.green("\u2713")} Import complete`);
2851
- console.log(import_picocolors7.default.dim(` Config keys restored: ${summary.configKeys}`));
2852
- console.log(import_picocolors7.default.dim(` Servers restored: ${summary.servers}`));
2853
- console.log(import_picocolors7.default.dim(` Vault: ${summary.vaultImported ? "restored" : "skipped"}`));
2854
- console.log(import_picocolors7.default.dim(` Plugins installed: ${summary.pluginsInstalled}`));
3754
+ console.log(`${import_picocolors11.default.green("\u2713")} Import complete`);
3755
+ console.log(import_picocolors11.default.dim(` Config keys restored: ${summary.configKeys}`));
3756
+ console.log(import_picocolors11.default.dim(` Servers restored: ${summary.servers}`));
3757
+ console.log(import_picocolors11.default.dim(` Vault: ${summary.vaultImported ? "restored" : "skipped"}`));
3758
+ console.log(import_picocolors11.default.dim(` Plugins installed: ${summary.pluginsInstalled}`));
2855
3759
  }
2856
3760
  });
2857
3761
 
2858
3762
  // src/commands/info.ts
2859
3763
  init_cjs_shims();
2860
- var import_citty8 = require("citty");
3764
+ var import_citty12 = require("citty");
2861
3765
  var import_nanospinner2 = require("nanospinner");
2862
- var import_picocolors8 = __toESM(require("picocolors"), 1);
3766
+ var import_picocolors12 = __toESM(require("picocolors"), 1);
2863
3767
 
2864
3768
  // src/core/package-info.ts
2865
3769
  init_cjs_shims();
@@ -2917,11 +3821,11 @@ async function getPackageInfo(serverName) {
2917
3821
  // src/commands/info.ts
2918
3822
  function colorRisk2(score, riskLevel) {
2919
3823
  const label = score !== null ? `${score}/100 (${riskLevel})` : riskLevel;
2920
- if (riskLevel === "LOW") return import_picocolors8.default.green(label);
2921
- if (riskLevel === "MEDIUM") return import_picocolors8.default.yellow(label);
2922
- if (riskLevel === "HIGH") return import_picocolors8.default.red(label);
2923
- if (riskLevel === "CRITICAL") return import_picocolors8.default.bold(import_picocolors8.default.red(label));
2924
- return import_picocolors8.default.dim(label);
3824
+ if (riskLevel === "LOW") return import_picocolors12.default.green(label);
3825
+ if (riskLevel === "MEDIUM") return import_picocolors12.default.yellow(label);
3826
+ if (riskLevel === "HIGH") return import_picocolors12.default.red(label);
3827
+ if (riskLevel === "CRITICAL") return import_picocolors12.default.bold(import_picocolors12.default.red(label));
3828
+ return import_picocolors12.default.dim(label);
2925
3829
  }
2926
3830
  function formatDaysAgo(isoDate) {
2927
3831
  if (!isoDate) return "unknown";
@@ -2931,54 +3835,54 @@ function formatDaysAgo(isoDate) {
2931
3835
  return `${days} days ago`;
2932
3836
  }
2933
3837
  function printInfo(info2) {
2934
- const installedBadge = info2.isInstalled ? import_picocolors8.default.green(" [installed]") : import_picocolors8.default.dim(" [not installed]");
3838
+ const installedBadge = info2.isInstalled ? import_picocolors12.default.green(" [installed]") : import_picocolors12.default.dim(" [not installed]");
2935
3839
  console.log();
2936
- console.log(import_picocolors8.default.bold(` ${info2.name}@${info2.version}`) + installedBadge);
2937
- console.log(import_picocolors8.default.dim(` ${"\u2500".repeat(60)}`));
2938
- console.log(` ${import_picocolors8.default.dim("Source:")} ${info2.source}`);
2939
- console.log(` ${import_picocolors8.default.dim("Runtime:")} ${info2.runtime}`);
3840
+ console.log(import_picocolors12.default.bold(` ${info2.name}@${info2.version}`) + installedBadge);
3841
+ console.log(import_picocolors12.default.dim(` ${"\u2500".repeat(60)}`));
3842
+ console.log(` ${import_picocolors12.default.dim("Source:")} ${info2.source}`);
3843
+ console.log(` ${import_picocolors12.default.dim("Runtime:")} ${info2.runtime}`);
2940
3844
  if (info2.description) {
2941
- console.log(` ${import_picocolors8.default.dim("Description:")} ${info2.description}`);
3845
+ console.log(` ${import_picocolors12.default.dim("Description:")} ${info2.description}`);
2942
3846
  }
2943
3847
  if (info2.deprecated) {
2944
- console.log(` ${import_picocolors8.default.red("[DEPRECATED]")} This package is deprecated`);
3848
+ console.log(` ${import_picocolors12.default.red("[DEPRECATED]")} This package is deprecated`);
2945
3849
  }
2946
3850
  console.log();
2947
- console.log(` ${import_picocolors8.default.bold("Trust & Security")}`);
2948
- console.log(` ${import_picocolors8.default.dim("Trust score:")} ${colorRisk2(info2.trustScore, info2.riskLevel)}`);
3851
+ console.log(` ${import_picocolors12.default.bold("Trust & Security")}`);
3852
+ console.log(` ${import_picocolors12.default.dim("Trust score:")} ${colorRisk2(info2.trustScore, info2.riskLevel)}`);
2949
3853
  if (info2.source === "npm") {
2950
3854
  console.log(
2951
- ` ${import_picocolors8.default.dim("Downloads:")} ${info2.weeklyDownloads.toLocaleString()}/week ${import_picocolors8.default.dim("|")} ${import_picocolors8.default.dim("Age:")} ${info2.packageAge}d ${import_picocolors8.default.dim("|")} ${import_picocolors8.default.dim("Maintainers:")} ${info2.maintainerCount}`
3855
+ ` ${import_picocolors12.default.dim("Downloads:")} ${info2.weeklyDownloads.toLocaleString()}/week ${import_picocolors12.default.dim("|")} ${import_picocolors12.default.dim("Age:")} ${info2.packageAge}d ${import_picocolors12.default.dim("|")} ${import_picocolors12.default.dim("Maintainers:")} ${info2.maintainerCount}`
2952
3856
  );
2953
3857
  if (info2.lastPublish) {
2954
- console.log(` ${import_picocolors8.default.dim("Last publish:")} ${formatDaysAgo(info2.lastPublish)}`);
3858
+ console.log(` ${import_picocolors12.default.dim("Last publish:")} ${formatDaysAgo(info2.lastPublish)}`);
2955
3859
  }
2956
3860
  } else {
2957
- console.log(import_picocolors8.default.dim(" (Trust data available for npm packages only)"));
3861
+ console.log(import_picocolors12.default.dim(" (Trust data available for npm packages only)"));
2958
3862
  }
2959
3863
  console.log();
2960
- console.log(` ${import_picocolors8.default.bold("Environment Variables")}`);
3864
+ console.log(` ${import_picocolors12.default.bold("Environment Variables")}`);
2961
3865
  if (info2.envVars.length > 0) {
2962
3866
  for (const env of info2.envVars) {
2963
- console.log(` ${import_picocolors8.default.cyan("\u2022")} ${env}`);
3867
+ console.log(` ${import_picocolors12.default.cyan("\u2022")} ${env}`);
2964
3868
  }
2965
3869
  } else {
2966
- console.log(import_picocolors8.default.dim(" none required"));
3870
+ console.log(import_picocolors12.default.dim(" none required"));
2967
3871
  }
2968
3872
  console.log();
2969
- console.log(` ${import_picocolors8.default.bold("Installed Clients")}`);
3873
+ console.log(` ${import_picocolors12.default.bold("Installed Clients")}`);
2970
3874
  if (info2.installedClients.length > 0) {
2971
3875
  for (const client of info2.installedClients) {
2972
- console.log(` ${import_picocolors8.default.green("\u2713")} ${client}`);
3876
+ console.log(` ${import_picocolors12.default.green("\u2713")} ${client}`);
2973
3877
  }
2974
3878
  } else {
2975
- console.log(import_picocolors8.default.dim(" Not installed in any client"));
3879
+ console.log(import_picocolors12.default.dim(" Not installed in any client"));
2976
3880
  }
2977
3881
  console.log();
2978
- console.log(import_picocolors8.default.dim(` ${"\u2500".repeat(60)}`));
3882
+ console.log(import_picocolors12.default.dim(` ${"\u2500".repeat(60)}`));
2979
3883
  console.log();
2980
3884
  }
2981
- var info_default = (0, import_citty8.defineCommand)({
3885
+ var info_default = (0, import_citty12.defineCommand)({
2982
3886
  meta: {
2983
3887
  name: "info",
2984
3888
  description: "Show detailed metadata for an MCP server (installed or from registry)"
@@ -3002,13 +3906,13 @@ var info_default = (0, import_citty8.defineCommand)({
3002
3906
  info2 = await getPackageInfo(args.server);
3003
3907
  } catch (err) {
3004
3908
  spinner5.error({ text: "Failed to fetch package info" });
3005
- console.error(import_picocolors8.default.red(String(err)));
3909
+ console.error(import_picocolors12.default.red(String(err)));
3006
3910
  process.exit(1);
3007
3911
  }
3008
3912
  if (!info2) {
3009
3913
  spinner5.error({ text: `Package not found: ${args.server}` });
3010
3914
  console.log(
3011
- import_picocolors8.default.dim(`
3915
+ import_picocolors12.default.dim(`
3012
3916
  "${args.server}" was not found in the npm registry or your lockfile.
3013
3917
  `)
3014
3918
  );
@@ -3025,11 +3929,11 @@ var info_default = (0, import_citty8.defineCommand)({
3025
3929
 
3026
3930
  // src/commands/init.ts
3027
3931
  init_cjs_shims();
3028
- var import_node_path13 = __toESM(require("path"), 1);
3932
+ var import_node_path15 = __toESM(require("path"), 1);
3029
3933
  var p5 = __toESM(require("@clack/prompts"), 1);
3030
- var import_citty9 = require("citty");
3934
+ var import_citty13 = require("citty");
3031
3935
  init_lockfile();
3032
- var init_default = (0, import_citty9.defineCommand)({
3936
+ var init_default = (0, import_citty13.defineCommand)({
3033
3937
  meta: {
3034
3938
  name: "init",
3035
3939
  description: "Initialize mcpman.lock in the current project"
@@ -3045,7 +3949,7 @@ var init_default = (0, import_citty9.defineCommand)({
3045
3949
  async run({ args }) {
3046
3950
  const nonInteractive = args.yes || !process.stdout.isTTY;
3047
3951
  p5.intro("mcpman init");
3048
- const targetPath = import_node_path13.default.join(process.cwd(), LOCKFILE_NAME);
3952
+ const targetPath = import_node_path15.default.join(process.cwd(), LOCKFILE_NAME);
3049
3953
  const existing = findLockfile();
3050
3954
  if (existing) {
3051
3955
  if (nonInteractive) {
@@ -3130,7 +4034,7 @@ var init_default = (0, import_citty9.defineCommand)({
3130
4034
  // src/commands/install.ts
3131
4035
  init_cjs_shims();
3132
4036
  var p8 = __toESM(require("@clack/prompts"), 1);
3133
- var import_citty10 = require("citty");
4037
+ var import_citty14 = require("citty");
3134
4038
 
3135
4039
  // src/core/installer.ts
3136
4040
  init_cjs_shims();
@@ -3290,7 +4194,7 @@ init_lockfile();
3290
4194
 
3291
4195
  // src/utils/logger.ts
3292
4196
  init_cjs_shims();
3293
- var import_picocolors9 = __toESM(require("picocolors"), 1);
4197
+ var import_picocolors13 = __toESM(require("picocolors"), 1);
3294
4198
  var noColor = process.env.NO_COLOR !== void 0 || process.argv.includes("--no-color");
3295
4199
  var isVerbose = process.argv.includes("--verbose");
3296
4200
  var isJson = process.argv.includes("--json");
@@ -3299,18 +4203,18 @@ function colorize(fn, text2) {
3299
4203
  }
3300
4204
  function info(message) {
3301
4205
  if (isJson) return;
3302
- console.log(`${colorize(import_picocolors9.default.cyan, "i")} ${message}`);
4206
+ console.log(`${colorize(import_picocolors13.default.cyan, "i")} ${message}`);
3303
4207
  }
3304
4208
  function error(message) {
3305
4209
  if (isJson) return;
3306
- console.error(`${colorize(import_picocolors9.default.red, "\u2717")} ${message}`);
4210
+ console.error(`${colorize(import_picocolors13.default.red, "\u2717")} ${message}`);
3307
4211
  }
3308
4212
  function json(data) {
3309
4213
  console.log(JSON.stringify(data, null, 2));
3310
4214
  }
3311
4215
 
3312
4216
  // src/commands/install.ts
3313
- var install_default = (0, import_citty10.defineCommand)({
4217
+ var install_default = (0, import_citty14.defineCommand)({
3314
4218
  meta: {
3315
4219
  name: "install",
3316
4220
  description: "Install an MCP server into one or more AI clients"
@@ -3373,26 +4277,26 @@ async function restoreFromLockfile() {
3373
4277
 
3374
4278
  // src/commands/link.ts
3375
4279
  init_cjs_shims();
3376
- var import_node_path15 = __toESM(require("path"), 1);
3377
- var import_citty11 = require("citty");
3378
- var import_picocolors10 = __toESM(require("picocolors"), 1);
4280
+ var import_node_path17 = __toESM(require("path"), 1);
4281
+ var import_citty15 = require("citty");
4282
+ var import_picocolors14 = __toESM(require("picocolors"), 1);
3379
4283
  init_client_detector();
3380
4284
 
3381
4285
  // src/core/link-service.ts
3382
4286
  init_cjs_shims();
3383
- var import_node_fs12 = __toESM(require("fs"), 1);
3384
- var import_node_path14 = __toESM(require("path"), 1);
4287
+ var import_node_fs16 = __toESM(require("fs"), 1);
4288
+ var import_node_path16 = __toESM(require("path"), 1);
3385
4289
  init_lockfile();
3386
4290
  function detectLocalServer(dir) {
3387
- if (!import_node_fs12.default.existsSync(dir)) {
4291
+ if (!import_node_fs16.default.existsSync(dir)) {
3388
4292
  throw new Error(`Directory does not exist: ${dir}`);
3389
4293
  }
3390
- const pkgPath = import_node_path14.default.join(dir, "package.json");
3391
- if (import_node_fs12.default.existsSync(pkgPath)) {
4294
+ const pkgPath = import_node_path16.default.join(dir, "package.json");
4295
+ if (import_node_fs16.default.existsSync(pkgPath)) {
3392
4296
  return detectNodeServer(dir, pkgPath);
3393
4297
  }
3394
- const pyprojectPath = import_node_path14.default.join(dir, "pyproject.toml");
3395
- if (import_node_fs12.default.existsSync(pyprojectPath)) {
4298
+ const pyprojectPath = import_node_path16.default.join(dir, "pyproject.toml");
4299
+ if (import_node_fs16.default.existsSync(pyprojectPath)) {
3396
4300
  return detectPythonServer(dir, pyprojectPath);
3397
4301
  }
3398
4302
  throw new Error(
@@ -3400,28 +4304,28 @@ function detectLocalServer(dir) {
3400
4304
  );
3401
4305
  }
3402
4306
  function detectNodeServer(dir, pkgPath) {
3403
- const raw = import_node_fs12.default.readFileSync(pkgPath, "utf-8");
4307
+ const raw = import_node_fs16.default.readFileSync(pkgPath, "utf-8");
3404
4308
  const pkg = JSON.parse(raw);
3405
- const name = String(pkg.name ?? import_node_path14.default.basename(dir));
4309
+ const name = String(pkg.name ?? import_node_path16.default.basename(dir));
3406
4310
  const version = String(pkg.version ?? "0.0.0");
3407
4311
  let entryPoint = null;
3408
4312
  if (pkg.bin) {
3409
4313
  if (typeof pkg.bin === "string") {
3410
- entryPoint = import_node_path14.default.resolve(dir, pkg.bin);
4314
+ entryPoint = import_node_path16.default.resolve(dir, pkg.bin);
3411
4315
  } else if (typeof pkg.bin === "object" && pkg.bin !== null) {
3412
4316
  const binObj = pkg.bin;
3413
4317
  const firstBin = Object.values(binObj)[0];
3414
- if (firstBin) entryPoint = import_node_path14.default.resolve(dir, firstBin);
4318
+ if (firstBin) entryPoint = import_node_path16.default.resolve(dir, firstBin);
3415
4319
  }
3416
4320
  }
3417
4321
  if (!entryPoint && pkg.main) {
3418
- entryPoint = import_node_path14.default.resolve(dir, String(pkg.main));
4322
+ entryPoint = import_node_path16.default.resolve(dir, String(pkg.main));
3419
4323
  }
3420
4324
  if (!entryPoint) {
3421
4325
  const candidates = ["src/index.ts", "src/index.js", "index.ts", "index.js"];
3422
4326
  for (const c of candidates) {
3423
- const candidate = import_node_path14.default.join(dir, c);
3424
- if (import_node_fs12.default.existsSync(candidate)) {
4327
+ const candidate = import_node_path16.default.join(dir, c);
4328
+ if (import_node_fs16.default.existsSync(candidate)) {
3425
4329
  entryPoint = candidate;
3426
4330
  break;
3427
4331
  }
@@ -3446,20 +4350,20 @@ function detectNodeServer(dir, pkgPath) {
3446
4350
  return { name, version, command, args, envVars, absolutePath: dir, runtime: "node" };
3447
4351
  }
3448
4352
  function detectPythonServer(dir, pyprojectPath) {
3449
- const raw = import_node_fs12.default.readFileSync(pyprojectPath, "utf-8");
3450
- const name = extractTomlValue(raw, "name") ?? import_node_path14.default.basename(dir);
4353
+ const raw = import_node_fs16.default.readFileSync(pyprojectPath, "utf-8");
4354
+ const name = extractTomlValue(raw, "name") ?? import_node_path16.default.basename(dir);
3451
4355
  const version = extractTomlValue(raw, "version") ?? "0.0.0";
3452
4356
  let pythonCmd = "python3";
3453
- const venvPython = import_node_path14.default.join(dir, ".venv", "bin", "python");
3454
- if (import_node_fs12.default.existsSync(venvPython)) {
4357
+ const venvPython = import_node_path16.default.join(dir, ".venv", "bin", "python");
4358
+ if (import_node_fs16.default.existsSync(venvPython)) {
3455
4359
  pythonCmd = venvPython;
3456
4360
  }
3457
4361
  const entryCandidate = [
3458
- import_node_path14.default.join(dir, "main.py"),
3459
- import_node_path14.default.join(dir, name.replace(/-/g, "_"), "main.py"),
3460
- import_node_path14.default.join(dir, "__main__.py")
3461
- ].find((p13) => import_node_fs12.default.existsSync(p13));
3462
- const entryPoint = entryCandidate ?? import_node_path14.default.join(dir, "main.py");
4362
+ import_node_path16.default.join(dir, "main.py"),
4363
+ import_node_path16.default.join(dir, name.replace(/-/g, "_"), "main.py"),
4364
+ import_node_path16.default.join(dir, "__main__.py")
4365
+ ].find((p14) => import_node_fs16.default.existsSync(p14));
4366
+ const entryPoint = entryCandidate ?? import_node_path16.default.join(dir, "main.py");
3463
4367
  return {
3464
4368
  name,
3465
4369
  version,
@@ -3507,7 +4411,7 @@ async function registerLinkedServer(linkResult, clients, lockfilePath, nameOverr
3507
4411
  }
3508
4412
 
3509
4413
  // src/commands/link.ts
3510
- var link_default = (0, import_citty11.defineCommand)({
4414
+ var link_default = (0, import_citty15.defineCommand)({
3511
4415
  meta: {
3512
4416
  name: "link",
3513
4417
  description: "Register a local MCP server directory with AI clients"
@@ -3533,42 +4437,42 @@ var link_default = (0, import_citty11.defineCommand)({
3533
4437
  const dirArg = args.dir ?? ".";
3534
4438
  const clientFilter = args.client;
3535
4439
  const nameOverride = args.name;
3536
- const absoluteDir = import_node_path15.default.resolve(dirArg);
4440
+ const absoluteDir = import_node_path17.default.resolve(dirArg);
3537
4441
  let linkResult;
3538
4442
  try {
3539
4443
  linkResult = detectLocalServer(absoluteDir);
3540
4444
  } catch (err) {
3541
- console.error(import_picocolors10.default.red(` Error: ${err instanceof Error ? err.message : String(err)}`));
4445
+ console.error(import_picocolors14.default.red(` Error: ${err instanceof Error ? err.message : String(err)}`));
3542
4446
  process.exit(1);
3543
4447
  }
3544
4448
  const serverName = nameOverride ?? linkResult.name;
3545
- console.log(import_picocolors10.default.dim(`
3546
- Detected: ${import_picocolors10.default.cyan(serverName)} (${linkResult.runtime})`));
3547
- console.log(import_picocolors10.default.dim(` Path: ${absoluteDir}`));
3548
- console.log(import_picocolors10.default.dim(` Command: ${linkResult.command} ${linkResult.args.join(" ")}`));
4449
+ console.log(import_picocolors14.default.dim(`
4450
+ Detected: ${import_picocolors14.default.cyan(serverName)} (${linkResult.runtime})`));
4451
+ console.log(import_picocolors14.default.dim(` Path: ${absoluteDir}`));
4452
+ console.log(import_picocolors14.default.dim(` Command: ${linkResult.command} ${linkResult.args.join(" ")}`));
3549
4453
  const allClients = await getInstalledClients();
3550
4454
  const clients = clientFilter ? allClients.filter((c) => c.type === clientFilter) : allClients;
3551
4455
  if (clientFilter && clients.length === 0) {
3552
- console.error(import_picocolors10.default.red(` Error: Unknown client '${clientFilter}'.`));
4456
+ console.error(import_picocolors14.default.red(` Error: Unknown client '${clientFilter}'.`));
3553
4457
  process.exit(1);
3554
4458
  }
3555
4459
  let registered;
3556
4460
  try {
3557
4461
  registered = await registerLinkedServer(linkResult, clients, void 0, nameOverride);
3558
4462
  } catch (err) {
3559
- console.error(import_picocolors10.default.red(` Error: ${err instanceof Error ? err.message : String(err)}`));
4463
+ console.error(import_picocolors14.default.red(` Error: ${err instanceof Error ? err.message : String(err)}`));
3560
4464
  process.exit(1);
3561
4465
  }
3562
4466
  if (registered.length === 0) {
3563
- console.log(import_picocolors10.default.yellow(" Warning: No clients registered. Are any AI clients installed?"));
3564
- console.log(import_picocolors10.default.dim(` Server saved to lockfile with source "local".`));
4467
+ console.log(import_picocolors14.default.yellow(" Warning: No clients registered. Are any AI clients installed?"));
4468
+ console.log(import_picocolors14.default.dim(` Server saved to lockfile with source "local".`));
3565
4469
  } else {
3566
- console.log(import_picocolors10.default.green(`
3567
- Linked ${import_picocolors10.default.bold(serverName)} to: ${registered.join(", ")}
4470
+ console.log(import_picocolors14.default.green(`
4471
+ Linked ${import_picocolors14.default.bold(serverName)} to: ${registered.join(", ")}
3568
4472
  `));
3569
- console.log(import_picocolors10.default.dim(` Run ${import_picocolors10.default.cyan("mcpman list")} to verify.`));
4473
+ console.log(import_picocolors14.default.dim(` Run ${import_picocolors14.default.cyan("mcpman list")} to verify.`));
3570
4474
  console.log(
3571
- import_picocolors10.default.dim(` Run ${import_picocolors10.default.cyan(`mcpman watch ${serverName}`)} to start with auto-restart.`)
4475
+ import_picocolors14.default.dim(` Run ${import_picocolors14.default.cyan(`mcpman watch ${serverName}`)} to start with auto-restart.`)
3572
4476
  );
3573
4477
  }
3574
4478
  console.log();
@@ -3577,14 +4481,14 @@ var link_default = (0, import_citty11.defineCommand)({
3577
4481
 
3578
4482
  // src/commands/list.ts
3579
4483
  init_cjs_shims();
3580
- var import_citty12 = require("citty");
3581
- var import_picocolors11 = __toESM(require("picocolors"), 1);
4484
+ var import_citty16 = require("citty");
4485
+ var import_picocolors15 = __toESM(require("picocolors"), 1);
3582
4486
  var STATUS_ICON = {
3583
- healthy: import_picocolors11.default.green("\u25CF"),
3584
- unhealthy: import_picocolors11.default.red("\u25CF"),
3585
- unknown: import_picocolors11.default.dim("\u25CB")
4487
+ healthy: import_picocolors15.default.green("\u25CF"),
4488
+ unhealthy: import_picocolors15.default.red("\u25CF"),
4489
+ unknown: import_picocolors15.default.dim("\u25CB")
3586
4490
  };
3587
- var list_default = (0, import_citty12.defineCommand)({
4491
+ var list_default = (0, import_citty16.defineCommand)({
3588
4492
  meta: {
3589
4493
  name: "list",
3590
4494
  description: "List installed MCP servers"
@@ -3605,8 +4509,8 @@ var list_default = (0, import_citty12.defineCommand)({
3605
4509
  if (servers.length === 0) {
3606
4510
  const filter = args.client ? ` for client "${args.client}"` : "";
3607
4511
  console.log(
3608
- import_picocolors11.default.dim(
3609
- `No MCP servers installed${filter}. Run ${import_picocolors11.default.cyan("mcpman install <server>")} to get started.`
4512
+ import_picocolors15.default.dim(
4513
+ `No MCP servers installed${filter}. Run ${import_picocolors15.default.cyan("mcpman install <server>")} to get started.`
3610
4514
  )
3611
4515
  );
3612
4516
  return;
@@ -3632,9 +4536,9 @@ var list_default = (0, import_citty12.defineCommand)({
3632
4536
  const nameWidth = Math.max(4, ...withStatus.map((s) => s.name.length));
3633
4537
  const clientsWidth = Math.max(7, ...withStatus.map((s) => formatClients(s.clients).length));
3634
4538
  const header = ` ${pad("NAME", nameWidth)} ${pad("CLIENT(S)", clientsWidth)} ${pad("COMMAND", 20)} STATUS`;
3635
- console.log(import_picocolors11.default.dim(header));
4539
+ console.log(import_picocolors15.default.dim(header));
3636
4540
  console.log(
3637
- import_picocolors11.default.dim(` ${"-".repeat(nameWidth)} ${"-".repeat(clientsWidth)} ${"-".repeat(20)} ------`)
4541
+ import_picocolors15.default.dim(` ${"-".repeat(nameWidth)} ${"-".repeat(clientsWidth)} ${"-".repeat(20)} ------`)
3638
4542
  );
3639
4543
  for (const s of withStatus) {
3640
4544
  const icon = STATUS_ICON[s.status];
@@ -3649,7 +4553,7 @@ var list_default = (0, import_citty12.defineCommand)({
3649
4553
  }
3650
4554
  const clientSet = new Set(withStatus.flatMap((s) => s.clients));
3651
4555
  console.log(
3652
- import_picocolors11.default.dim(
4556
+ import_picocolors15.default.dim(
3653
4557
  `
3654
4558
  ${withStatus.length} server${withStatus.length !== 1 ? "s" : ""} \xB7 ${clientSet.size} client${clientSet.size !== 1 ? "s" : ""}`
3655
4559
  )
@@ -3662,24 +4566,24 @@ function pad(s, width) {
3662
4566
  function truncate(s, max) {
3663
4567
  return s.length > max ? `${s.slice(0, max - 1)}\u2026` : s;
3664
4568
  }
3665
- var CLIENT_DISPLAY = {
4569
+ var CLIENT_DISPLAY2 = {
3666
4570
  "claude-desktop": "Claude",
3667
4571
  cursor: "Cursor",
3668
4572
  vscode: "VS Code",
3669
4573
  windsurf: "Windsurf"
3670
4574
  };
3671
4575
  function formatClients(clients) {
3672
- return clients.map((c) => CLIENT_DISPLAY[c] ?? c).join(", ");
4576
+ return clients.map((c) => CLIENT_DISPLAY2[c] ?? c).join(", ");
3673
4577
  }
3674
4578
 
3675
4579
  // src/commands/logs.ts
3676
4580
  init_cjs_shims();
3677
- var import_node_child_process4 = require("child_process");
3678
- var import_citty13 = require("citty");
3679
- var import_picocolors12 = __toESM(require("picocolors"), 1);
4581
+ var import_node_child_process6 = require("child_process");
4582
+ var import_citty17 = require("citty");
4583
+ var import_picocolors16 = __toESM(require("picocolors"), 1);
3680
4584
  init_lockfile();
3681
4585
  init_vault_service();
3682
- var logs_default = (0, import_citty13.defineCommand)({
4586
+ var logs_default = (0, import_citty17.defineCommand)({
3683
4587
  meta: {
3684
4588
  name: "logs",
3685
4589
  description: "Stream stdout/stderr from an MCP server"
@@ -3702,7 +4606,7 @@ var logs_default = (0, import_citty13.defineCommand)({
3702
4606
  const lockfile = readLockfile();
3703
4607
  const entry = lockfile.servers[serverName];
3704
4608
  if (!entry) {
3705
- console.error(import_picocolors12.default.red(` Error: Server '${serverName}' is not installed.`));
4609
+ console.error(import_picocolors16.default.red(` Error: Server '${serverName}' is not installed.`));
3706
4610
  process.exit(1);
3707
4611
  }
3708
4612
  const lockfileEnv = parseEnvFlags(entry.envVars);
@@ -3712,24 +4616,24 @@ var logs_default = (0, import_citty13.defineCommand)({
3712
4616
  ...lockfileEnv,
3713
4617
  ...vaultEnv
3714
4618
  };
3715
- console.log(import_picocolors12.default.dim(` Streaming logs for ${import_picocolors12.default.cyan(serverName)}... (Ctrl+C to stop)
4619
+ console.log(import_picocolors16.default.dim(` Streaming logs for ${import_picocolors16.default.cyan(serverName)}... (Ctrl+C to stop)
3716
4620
  `));
3717
- const child = (0, import_node_child_process4.spawn)(entry.command, entry.args, {
4621
+ const child = (0, import_node_child_process6.spawn)(entry.command, entry.args, {
3718
4622
  env: finalEnv,
3719
4623
  stdio: ["pipe", "pipe", "pipe"]
3720
4624
  });
3721
4625
  child.stdout?.on("data", (chunk) => {
3722
- process.stdout.write(import_picocolors12.default.dim("[stdout] ") + chunk.toString());
4626
+ process.stdout.write(import_picocolors16.default.dim("[stdout] ") + chunk.toString());
3723
4627
  });
3724
4628
  child.stderr?.on("data", (chunk) => {
3725
- process.stderr.write(import_picocolors12.default.yellow("[stderr] ") + chunk.toString());
4629
+ process.stderr.write(import_picocolors16.default.yellow("[stderr] ") + chunk.toString());
3726
4630
  });
3727
4631
  child.on("error", (err) => {
3728
- console.error(import_picocolors12.default.red(` Failed to start '${serverName}': ${err.message}`));
4632
+ console.error(import_picocolors16.default.red(` Failed to start '${serverName}': ${err.message}`));
3729
4633
  process.exit(1);
3730
4634
  });
3731
4635
  child.on("close", (code) => {
3732
- console.log(import_picocolors12.default.dim(`
4636
+ console.log(import_picocolors16.default.dim(`
3733
4637
  Process exited with code ${code ?? 0}`));
3734
4638
  process.exit(code ?? 0);
3735
4639
  });
@@ -3753,12 +4657,101 @@ async function loadVaultSecrets(serverName) {
3753
4657
  }
3754
4658
  }
3755
4659
 
4660
+ // src/commands/pin.ts
4661
+ init_cjs_shims();
4662
+ var import_citty18 = require("citty");
4663
+ var import_picocolors17 = __toESM(require("picocolors"), 1);
4664
+ init_lockfile();
4665
+ var pin_default = (0, import_citty18.defineCommand)({
4666
+ meta: {
4667
+ name: "pin",
4668
+ description: "Pin a server to a specific version"
4669
+ },
4670
+ args: {
4671
+ server: {
4672
+ type: "positional",
4673
+ description: "Server name to pin/unpin",
4674
+ required: false
4675
+ },
4676
+ version: {
4677
+ type: "positional",
4678
+ description: "Version to pin to (defaults to currently installed version)",
4679
+ required: false
4680
+ },
4681
+ unpin: {
4682
+ type: "boolean",
4683
+ description: "Remove the pin for a server",
4684
+ default: false
4685
+ },
4686
+ list: {
4687
+ type: "boolean",
4688
+ description: "List all pinned servers",
4689
+ default: false
4690
+ }
4691
+ },
4692
+ run({ args }) {
4693
+ if (args.list) {
4694
+ const pins = listPins();
4695
+ if (pins.length === 0) {
4696
+ console.log(import_picocolors17.default.dim("No servers are pinned."));
4697
+ return;
4698
+ }
4699
+ console.log(`
4700
+ ${import_picocolors17.default.bold("Pinned servers")}
4701
+ `);
4702
+ for (const { server, version: version2 } of pins) {
4703
+ console.log(` ${import_picocolors17.default.cyan(import_picocolors17.default.bold(server))} ${import_picocolors17.default.dim("@")}${import_picocolors17.default.green(version2)}`);
4704
+ }
4705
+ console.log("");
4706
+ return;
4707
+ }
4708
+ if (args.unpin) {
4709
+ if (!args.server) {
4710
+ console.error(`${import_picocolors17.default.red("\u2717")} Specify a server name to unpin.`);
4711
+ process.exit(1);
4712
+ }
4713
+ if (!isPinned(args.server)) {
4714
+ console.log(import_picocolors17.default.dim(`"${args.server}" is not pinned.`));
4715
+ return;
4716
+ }
4717
+ unpinServer(args.server);
4718
+ console.log(`${import_picocolors17.default.green("\u2713")} Unpinned ${import_picocolors17.default.cyan(args.server)}`);
4719
+ return;
4720
+ }
4721
+ if (!args.server) {
4722
+ console.error(`${import_picocolors17.default.red("\u2717")} Specify a server name to pin. Use --list to see pins.`);
4723
+ process.exit(1);
4724
+ }
4725
+ let version = args.version;
4726
+ if (!version) {
4727
+ const lockfile = readLockfile();
4728
+ version = lockfile.servers[args.server]?.version;
4729
+ if (!version) {
4730
+ console.error(
4731
+ `${import_picocolors17.default.red("\u2717")} "${args.server}" not found in lockfile. Specify a version explicitly.`
4732
+ );
4733
+ process.exit(1);
4734
+ }
4735
+ }
4736
+ pinServer(args.server, version);
4737
+ const prev = getPinnedVersion(args.server);
4738
+ if (prev && prev !== version) {
4739
+ console.log(
4740
+ `${import_picocolors17.default.green("\u2713")} Re-pinned ${import_picocolors17.default.cyan(args.server)} ${import_picocolors17.default.dim(prev)} \u2192 ${import_picocolors17.default.green(version)}`
4741
+ );
4742
+ } else {
4743
+ console.log(`${import_picocolors17.default.green("\u2713")} Pinned ${import_picocolors17.default.cyan(args.server)} @ ${import_picocolors17.default.green(version)}`);
4744
+ }
4745
+ console.log(import_picocolors17.default.dim(" Update notifications will be suppressed for this server."));
4746
+ }
4747
+ });
4748
+
3756
4749
  // src/commands/plugin.ts
3757
4750
  init_cjs_shims();
3758
- var import_citty14 = require("citty");
4751
+ var import_citty19 = require("citty");
3759
4752
  var import_nanospinner3 = require("nanospinner");
3760
- var import_picocolors13 = __toESM(require("picocolors"), 1);
3761
- var addCommand = (0, import_citty14.defineCommand)({
4753
+ var import_picocolors18 = __toESM(require("picocolors"), 1);
4754
+ var addCommand = (0, import_citty19.defineCommand)({
3762
4755
  meta: { name: "add", description: "Install a plugin package" },
3763
4756
  args: {
3764
4757
  package: {
@@ -3776,23 +4769,23 @@ var addCommand = (0, import_citty14.defineCommand)({
3776
4769
  spinner5.stop();
3777
4770
  if (loaded) {
3778
4771
  console.log(
3779
- `${import_picocolors13.default.green("\u2713")} Plugin ${import_picocolors13.default.bold(loaded.name)} installed (prefix: ${import_picocolors13.default.cyan(loaded.prefix)})`
4772
+ `${import_picocolors18.default.green("\u2713")} Plugin ${import_picocolors18.default.bold(loaded.name)} installed (prefix: ${import_picocolors18.default.cyan(loaded.prefix)})`
3780
4773
  );
3781
4774
  } else {
3782
4775
  console.log(
3783
- `${import_picocolors13.default.yellow("\u26A0")} Package ${import_picocolors13.default.bold(pkg)} installed but does not export a valid mcpman plugin.`
4776
+ `${import_picocolors18.default.yellow("\u26A0")} Package ${import_picocolors18.default.bold(pkg)} installed but does not export a valid mcpman plugin.`
3784
4777
  );
3785
4778
  }
3786
4779
  } catch (err) {
3787
4780
  spinner5.stop();
3788
4781
  console.error(
3789
- `${import_picocolors13.default.red("\u2717")} Failed to install plugin: ${err instanceof Error ? err.message : String(err)}`
4782
+ `${import_picocolors18.default.red("\u2717")} Failed to install plugin: ${err instanceof Error ? err.message : String(err)}`
3790
4783
  );
3791
4784
  process.exit(1);
3792
4785
  }
3793
4786
  }
3794
4787
  });
3795
- var removeCommand = (0, import_citty14.defineCommand)({
4788
+ var removeCommand = (0, import_citty19.defineCommand)({
3796
4789
  meta: { name: "remove", description: "Uninstall a plugin package" },
3797
4790
  args: {
3798
4791
  package: {
@@ -3805,46 +4798,46 @@ var removeCommand = (0, import_citty14.defineCommand)({
3805
4798
  const pkg = args.package;
3806
4799
  const installed = listPluginPackages();
3807
4800
  if (!installed.includes(pkg)) {
3808
- console.log(import_picocolors13.default.dim(`Plugin "${pkg}" is not installed.`));
4801
+ console.log(import_picocolors18.default.dim(`Plugin "${pkg}" is not installed.`));
3809
4802
  return;
3810
4803
  }
3811
4804
  try {
3812
4805
  removePluginPackage(pkg);
3813
- console.log(`${import_picocolors13.default.green("\u2713")} Plugin ${import_picocolors13.default.bold(pkg)} removed.`);
4806
+ console.log(`${import_picocolors18.default.green("\u2713")} Plugin ${import_picocolors18.default.bold(pkg)} removed.`);
3814
4807
  } catch (err) {
3815
4808
  console.error(
3816
- `${import_picocolors13.default.red("\u2717")} Failed to remove plugin: ${err instanceof Error ? err.message : String(err)}`
4809
+ `${import_picocolors18.default.red("\u2717")} Failed to remove plugin: ${err instanceof Error ? err.message : String(err)}`
3817
4810
  );
3818
4811
  process.exit(1);
3819
4812
  }
3820
4813
  }
3821
4814
  });
3822
- var listCommand2 = (0, import_citty14.defineCommand)({
4815
+ var listCommand2 = (0, import_citty19.defineCommand)({
3823
4816
  meta: { name: "list", description: "List installed plugins" },
3824
4817
  run() {
3825
4818
  const packages = listPluginPackages();
3826
4819
  if (packages.length === 0) {
3827
- console.log(import_picocolors13.default.dim("No plugins installed. Use `mcpman plugin add <package>`."));
4820
+ console.log(import_picocolors18.default.dim("No plugins installed. Use `mcpman plugin add <package>`."));
3828
4821
  return;
3829
4822
  }
3830
4823
  console.log("");
3831
- console.log(import_picocolors13.default.bold("Installed plugins:"));
4824
+ console.log(import_picocolors18.default.bold("Installed plugins:"));
3832
4825
  console.log("");
3833
4826
  for (const pkg of packages) {
3834
4827
  const loaded = loadPlugin(pkg);
3835
4828
  if (loaded) {
3836
4829
  console.log(
3837
- ` ${import_picocolors13.default.green("\u25CF")} ${import_picocolors13.default.bold(loaded.name)} prefix: ${import_picocolors13.default.cyan(loaded.prefix)} pkg: ${import_picocolors13.default.dim(pkg)}`
4830
+ ` ${import_picocolors18.default.green("\u25CF")} ${import_picocolors18.default.bold(loaded.name)} prefix: ${import_picocolors18.default.cyan(loaded.prefix)} pkg: ${import_picocolors18.default.dim(pkg)}`
3838
4831
  );
3839
4832
  } else {
3840
- console.log(` ${import_picocolors13.default.yellow("\u25CF")} ${import_picocolors13.default.dim(pkg)} ${import_picocolors13.default.yellow("(failed to load)")}`);
4833
+ console.log(` ${import_picocolors18.default.yellow("\u25CF")} ${import_picocolors18.default.dim(pkg)} ${import_picocolors18.default.yellow("(failed to load)")}`);
3841
4834
  }
3842
4835
  }
3843
4836
  console.log("");
3844
- console.log(import_picocolors13.default.dim(` ${packages.length} plugin${packages.length !== 1 ? "s" : ""} installed`));
4837
+ console.log(import_picocolors18.default.dim(` ${packages.length} plugin${packages.length !== 1 ? "s" : ""} installed`));
3845
4838
  }
3846
4839
  });
3847
- var plugin_default = (0, import_citty14.defineCommand)({
4840
+ var plugin_default = (0, import_citty19.defineCommand)({
3848
4841
  meta: {
3849
4842
  name: "plugin",
3850
4843
  description: "Manage mcpman plugins for custom registries"
@@ -3858,26 +4851,26 @@ var plugin_default = (0, import_citty14.defineCommand)({
3858
4851
 
3859
4852
  // src/commands/profiles.ts
3860
4853
  init_cjs_shims();
3861
- var import_citty15 = require("citty");
3862
- var import_picocolors14 = __toESM(require("picocolors"), 1);
4854
+ var import_citty20 = require("citty");
4855
+ var import_picocolors19 = __toESM(require("picocolors"), 1);
3863
4856
  init_lockfile();
3864
4857
 
3865
4858
  // src/core/profile-service.ts
3866
4859
  init_cjs_shims();
3867
- var import_node_fs13 = __toESM(require("fs"), 1);
3868
- var import_node_path16 = __toESM(require("path"), 1);
4860
+ var import_node_fs17 = __toESM(require("fs"), 1);
4861
+ var import_node_path18 = __toESM(require("path"), 1);
3869
4862
  init_paths();
3870
4863
  init_lockfile();
3871
- function ensureDir(dir = getProfilesDir()) {
3872
- import_node_fs13.default.mkdirSync(dir, { recursive: true });
4864
+ function ensureDir2(dir = getProfilesDir()) {
4865
+ import_node_fs17.default.mkdirSync(dir, { recursive: true });
3873
4866
  }
3874
4867
  function profilePath(name, dir = getProfilesDir()) {
3875
- return import_node_path16.default.join(dir, `${name}.json`);
4868
+ return import_node_path18.default.join(dir, `${name}.json`);
3876
4869
  }
3877
4870
  function createProfile(name, description = "", dir = getProfilesDir()) {
3878
- ensureDir(dir);
4871
+ ensureDir2(dir);
3879
4872
  const filePath = profilePath(name, dir);
3880
- if (import_node_fs13.default.existsSync(filePath)) {
4873
+ if (import_node_fs17.default.existsSync(filePath)) {
3881
4874
  throw new Error(`Profile '${name}' already exists. Delete it first or use a different name.`);
3882
4875
  }
3883
4876
  const lockfile = readLockfile();
@@ -3887,16 +4880,16 @@ function createProfile(name, description = "", dir = getProfilesDir()) {
3887
4880
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
3888
4881
  servers: lockfile.servers
3889
4882
  };
3890
- import_node_fs13.default.writeFileSync(filePath, JSON.stringify(profile, null, 2), "utf-8");
4883
+ import_node_fs17.default.writeFileSync(filePath, JSON.stringify(profile, null, 2), "utf-8");
3891
4884
  return profile;
3892
4885
  }
3893
4886
  function listProfiles(dir = getProfilesDir()) {
3894
- ensureDir(dir);
3895
- const files = import_node_fs13.default.readdirSync(dir).filter((f) => f.endsWith(".json"));
4887
+ ensureDir2(dir);
4888
+ const files = import_node_fs17.default.readdirSync(dir).filter((f) => f.endsWith(".json"));
3896
4889
  const profiles = [];
3897
4890
  for (const file of files) {
3898
4891
  try {
3899
- const raw = import_node_fs13.default.readFileSync(import_node_path16.default.join(dir, file), "utf-8");
4892
+ const raw = import_node_fs17.default.readFileSync(import_node_path18.default.join(dir, file), "utf-8");
3900
4893
  const data = JSON.parse(raw);
3901
4894
  profiles.push(data);
3902
4895
  } catch {
@@ -3906,9 +4899,9 @@ function listProfiles(dir = getProfilesDir()) {
3906
4899
  }
3907
4900
  function loadProfile(name, dir = getProfilesDir()) {
3908
4901
  const filePath = profilePath(name, dir);
3909
- if (!import_node_fs13.default.existsSync(filePath)) return null;
4902
+ if (!import_node_fs17.default.existsSync(filePath)) return null;
3910
4903
  try {
3911
- const raw = import_node_fs13.default.readFileSync(filePath, "utf-8");
4904
+ const raw = import_node_fs17.default.readFileSync(filePath, "utf-8");
3912
4905
  return JSON.parse(raw);
3913
4906
  } catch {
3914
4907
  return null;
@@ -3916,13 +4909,13 @@ function loadProfile(name, dir = getProfilesDir()) {
3916
4909
  }
3917
4910
  function deleteProfile(name, dir = getProfilesDir()) {
3918
4911
  const filePath = profilePath(name, dir);
3919
- if (!import_node_fs13.default.existsSync(filePath)) return false;
3920
- import_node_fs13.default.unlinkSync(filePath);
4912
+ if (!import_node_fs17.default.existsSync(filePath)) return false;
4913
+ import_node_fs17.default.unlinkSync(filePath);
3921
4914
  return true;
3922
4915
  }
3923
4916
 
3924
4917
  // src/commands/profiles.ts
3925
- var profiles_default = (0, import_citty15.defineCommand)({
4918
+ var profiles_default = (0, import_citty20.defineCommand)({
3926
4919
  meta: {
3927
4920
  name: "profiles",
3928
4921
  description: "Manage named server configuration profiles"
@@ -3951,16 +4944,16 @@ var profiles_default = (0, import_citty15.defineCommand)({
3951
4944
  case "create": {
3952
4945
  if (!name) {
3953
4946
  console.error(
3954
- import_picocolors14.default.red(" Error: Profile name required. Usage: mcpman profiles create <name>")
4947
+ import_picocolors19.default.red(" Error: Profile name required. Usage: mcpman profiles create <name>")
3955
4948
  );
3956
4949
  process.exit(1);
3957
4950
  }
3958
4951
  try {
3959
4952
  const profile = createProfile(name, args.description ?? "");
3960
4953
  const count = Object.keys(profile.servers).length;
3961
- console.log(import_picocolors14.default.green(` \u2713 Profile '${name}' created with ${count} server(s).`));
4954
+ console.log(import_picocolors19.default.green(` \u2713 Profile '${name}' created with ${count} server(s).`));
3962
4955
  } catch (err) {
3963
- console.error(import_picocolors14.default.red(` Error: ${err instanceof Error ? err.message : String(err)}`));
4956
+ console.error(import_picocolors19.default.red(` Error: ${err instanceof Error ? err.message : String(err)}`));
3964
4957
  process.exit(1);
3965
4958
  }
3966
4959
  break;
@@ -3968,38 +4961,38 @@ var profiles_default = (0, import_citty15.defineCommand)({
3968
4961
  case "switch": {
3969
4962
  if (!name) {
3970
4963
  console.error(
3971
- import_picocolors14.default.red(" Error: Profile name required. Usage: mcpman profiles switch <name>")
4964
+ import_picocolors19.default.red(" Error: Profile name required. Usage: mcpman profiles switch <name>")
3972
4965
  );
3973
4966
  process.exit(1);
3974
4967
  }
3975
4968
  const profile = loadProfile(name);
3976
4969
  if (!profile) {
3977
- console.error(import_picocolors14.default.red(` Error: Profile '${name}' not found.`));
4970
+ console.error(import_picocolors19.default.red(` Error: Profile '${name}' not found.`));
3978
4971
  process.exit(1);
3979
4972
  }
3980
4973
  const lockData = { lockfileVersion: 1, servers: profile.servers };
3981
4974
  writeLockfile(lockData);
3982
4975
  const count = Object.keys(profile.servers).length;
3983
- console.log(import_picocolors14.default.green(` \u2713 Switched to profile '${name}' (${count} servers).`));
3984
- console.log(import_picocolors14.default.dim(" Run mcpman sync to apply to all clients."));
4976
+ console.log(import_picocolors19.default.green(` \u2713 Switched to profile '${name}' (${count} servers).`));
4977
+ console.log(import_picocolors19.default.dim(" Run mcpman sync to apply to all clients."));
3985
4978
  break;
3986
4979
  }
3987
4980
  case "list": {
3988
4981
  const profiles = listProfiles();
3989
4982
  if (profiles.length === 0) {
3990
4983
  console.log(
3991
- import_picocolors14.default.dim(" No profiles saved. Create one with: mcpman profiles create <name>")
4984
+ import_picocolors19.default.dim(" No profiles saved. Create one with: mcpman profiles create <name>")
3992
4985
  );
3993
4986
  return;
3994
4987
  }
3995
- console.log(import_picocolors14.default.bold(`
4988
+ console.log(import_picocolors19.default.bold(`
3996
4989
  Profiles (${profiles.length})
3997
4990
  `));
3998
- for (const p13 of profiles) {
3999
- const count = Object.keys(p13.servers).length;
4000
- const desc = p13.description ? import_picocolors14.default.dim(` \u2014 ${p13.description}`) : "";
4991
+ for (const p14 of profiles) {
4992
+ const count = Object.keys(p14.servers).length;
4993
+ const desc = p14.description ? import_picocolors19.default.dim(` \u2014 ${p14.description}`) : "";
4001
4994
  console.log(
4002
- ` ${import_picocolors14.default.cyan("\u25CF")} ${import_picocolors14.default.bold(p13.name)} ${import_picocolors14.default.dim(`${count} server(s)`)}${desc}`
4995
+ ` ${import_picocolors19.default.cyan("\u25CF")} ${import_picocolors19.default.bold(p14.name)} ${import_picocolors19.default.dim(`${count} server(s)`)}${desc}`
4003
4996
  );
4004
4997
  }
4005
4998
  console.log();
@@ -4008,22 +5001,22 @@ var profiles_default = (0, import_citty15.defineCommand)({
4008
5001
  case "delete": {
4009
5002
  if (!name) {
4010
5003
  console.error(
4011
- import_picocolors14.default.red(" Error: Profile name required. Usage: mcpman profiles delete <name>")
5004
+ import_picocolors19.default.red(" Error: Profile name required. Usage: mcpman profiles delete <name>")
4012
5005
  );
4013
5006
  process.exit(1);
4014
5007
  }
4015
5008
  const deleted = deleteProfile(name);
4016
5009
  if (deleted) {
4017
- console.log(import_picocolors14.default.green(` \u2713 Profile '${name}' deleted.`));
5010
+ console.log(import_picocolors19.default.green(` \u2713 Profile '${name}' deleted.`));
4018
5011
  } else {
4019
- console.error(import_picocolors14.default.red(` Error: Profile '${name}' not found.`));
5012
+ console.error(import_picocolors19.default.red(` Error: Profile '${name}' not found.`));
4020
5013
  process.exit(1);
4021
5014
  }
4022
5015
  break;
4023
5016
  }
4024
5017
  default:
4025
5018
  console.error(
4026
- import_picocolors14.default.red(` Unknown action '${action}'. Use: create, switch, list, or delete.`)
5019
+ import_picocolors19.default.red(` Unknown action '${action}'. Use: create, switch, list, or delete.`)
4027
5020
  );
4028
5021
  process.exit(1);
4029
5022
  }
@@ -4032,8 +5025,8 @@ var profiles_default = (0, import_citty15.defineCommand)({
4032
5025
 
4033
5026
  // src/commands/registry.ts
4034
5027
  init_cjs_shims();
4035
- var import_citty16 = require("citty");
4036
- var import_picocolors15 = __toESM(require("picocolors"), 1);
5028
+ var import_citty21 = require("citty");
5029
+ var import_picocolors20 = __toESM(require("picocolors"), 1);
4037
5030
 
4038
5031
  // src/core/registry-manager.ts
4039
5032
  init_cjs_shims();
@@ -4104,7 +5097,7 @@ function getDefaultRegistry(configPath) {
4104
5097
  }
4105
5098
 
4106
5099
  // src/commands/registry.ts
4107
- var registry_default = (0, import_citty16.defineCommand)({
5100
+ var registry_default = (0, import_citty21.defineCommand)({
4108
5101
  meta: {
4109
5102
  name: "registry",
4110
5103
  description: "Manage custom registry URLs"
@@ -4134,67 +5127,67 @@ var registry_default = (0, import_citty16.defineCommand)({
4134
5127
  case "list": {
4135
5128
  const registries = getRegistries();
4136
5129
  const defaultName = getDefaultRegistry();
4137
- console.log(import_picocolors15.default.bold("\n Registries\n"));
5130
+ console.log(import_picocolors20.default.bold("\n Registries\n"));
4138
5131
  for (const r of registries) {
4139
5132
  const isDefault = r.name === defaultName;
4140
- const defaultTag = isDefault ? import_picocolors15.default.green(" (default)") : "";
4141
- const builtinTag = r.builtin ? import_picocolors15.default.dim(" [builtin]") : "";
5133
+ const defaultTag = isDefault ? import_picocolors20.default.green(" (default)") : "";
5134
+ const builtinTag = r.builtin ? import_picocolors20.default.dim(" [builtin]") : "";
4142
5135
  console.log(
4143
- ` ${isDefault ? import_picocolors15.default.green("\u25CF") : import_picocolors15.default.dim("\u25CB")} ${import_picocolors15.default.bold(r.name)}${defaultTag}${builtinTag}`
5136
+ ` ${isDefault ? import_picocolors20.default.green("\u25CF") : import_picocolors20.default.dim("\u25CB")} ${import_picocolors20.default.bold(r.name)}${defaultTag}${builtinTag}`
4144
5137
  );
4145
- console.log(` ${import_picocolors15.default.dim(r.url)}`);
5138
+ console.log(` ${import_picocolors20.default.dim(r.url)}`);
4146
5139
  }
4147
5140
  console.log();
4148
5141
  break;
4149
5142
  }
4150
5143
  case "add": {
4151
5144
  if (!name) {
4152
- console.error(import_picocolors15.default.red(" Error: Usage: mcpman registry add <name> <url>"));
5145
+ console.error(import_picocolors20.default.red(" Error: Usage: mcpman registry add <name> <url>"));
4153
5146
  process.exit(1);
4154
5147
  }
4155
5148
  if (!url) {
4156
- console.error(import_picocolors15.default.red(" Error: Usage: mcpman registry add <name> <url>"));
5149
+ console.error(import_picocolors20.default.red(" Error: Usage: mcpman registry add <name> <url>"));
4157
5150
  process.exit(1);
4158
5151
  }
4159
5152
  try {
4160
5153
  addRegistry(name, url);
4161
- console.log(import_picocolors15.default.green(` Added registry '${name}' \u2192 ${url}`));
5154
+ console.log(import_picocolors20.default.green(` Added registry '${name}' \u2192 ${url}`));
4162
5155
  } catch (err) {
4163
- console.error(import_picocolors15.default.red(` Error: ${err instanceof Error ? err.message : String(err)}`));
5156
+ console.error(import_picocolors20.default.red(` Error: ${err instanceof Error ? err.message : String(err)}`));
4164
5157
  process.exit(1);
4165
5158
  }
4166
5159
  break;
4167
5160
  }
4168
5161
  case "remove": {
4169
5162
  if (!name) {
4170
- console.error(import_picocolors15.default.red(" Error: Usage: mcpman registry remove <name>"));
5163
+ console.error(import_picocolors20.default.red(" Error: Usage: mcpman registry remove <name>"));
4171
5164
  process.exit(1);
4172
5165
  }
4173
5166
  try {
4174
5167
  removeRegistry(name);
4175
- console.log(import_picocolors15.default.green(` Removed registry '${name}'.`));
5168
+ console.log(import_picocolors20.default.green(` Removed registry '${name}'.`));
4176
5169
  } catch (err) {
4177
- console.error(import_picocolors15.default.red(` Error: ${err instanceof Error ? err.message : String(err)}`));
5170
+ console.error(import_picocolors20.default.red(` Error: ${err instanceof Error ? err.message : String(err)}`));
4178
5171
  process.exit(1);
4179
5172
  }
4180
5173
  break;
4181
5174
  }
4182
5175
  case "set-default": {
4183
5176
  if (!name) {
4184
- console.error(import_picocolors15.default.red(" Error: Usage: mcpman registry set-default <name>"));
5177
+ console.error(import_picocolors20.default.red(" Error: Usage: mcpman registry set-default <name>"));
4185
5178
  process.exit(1);
4186
5179
  }
4187
5180
  try {
4188
5181
  setDefaultRegistry(name);
4189
- console.log(import_picocolors15.default.green(` Default registry set to '${name}'.`));
5182
+ console.log(import_picocolors20.default.green(` Default registry set to '${name}'.`));
4190
5183
  } catch (err) {
4191
- console.error(import_picocolors15.default.red(` Error: ${err instanceof Error ? err.message : String(err)}`));
5184
+ console.error(import_picocolors20.default.red(` Error: ${err instanceof Error ? err.message : String(err)}`));
4192
5185
  process.exit(1);
4193
5186
  }
4194
5187
  break;
4195
5188
  }
4196
5189
  default:
4197
- console.error(import_picocolors15.default.red(` Unknown action '${action}'. Use: list, add, remove, set-default.`));
5190
+ console.error(import_picocolors20.default.red(` Unknown action '${action}'. Use: list, add, remove, set-default.`));
4198
5191
  process.exit(1);
4199
5192
  }
4200
5193
  }
@@ -4203,19 +5196,19 @@ var registry_default = (0, import_citty16.defineCommand)({
4203
5196
  // src/commands/remove.ts
4204
5197
  init_cjs_shims();
4205
5198
  var p9 = __toESM(require("@clack/prompts"), 1);
4206
- var import_citty17 = require("citty");
4207
- var import_picocolors16 = __toESM(require("picocolors"), 1);
5199
+ var import_citty22 = require("citty");
5200
+ var import_picocolors21 = __toESM(require("picocolors"), 1);
4208
5201
  init_client_detector();
4209
- var CLIENT_DISPLAY2 = {
5202
+ var CLIENT_DISPLAY3 = {
4210
5203
  "claude-desktop": "Claude",
4211
5204
  cursor: "Cursor",
4212
5205
  vscode: "VS Code",
4213
5206
  windsurf: "Windsurf"
4214
5207
  };
4215
5208
  function clientDisplayName(type) {
4216
- return CLIENT_DISPLAY2[type] ?? type;
5209
+ return CLIENT_DISPLAY3[type] ?? type;
4217
5210
  }
4218
- var remove_default = (0, import_citty17.defineCommand)({
5211
+ var remove_default = (0, import_citty22.defineCommand)({
4219
5212
  meta: {
4220
5213
  name: "remove",
4221
5214
  description: "Remove an MCP server from one or more AI clients"
@@ -4242,7 +5235,7 @@ var remove_default = (0, import_citty17.defineCommand)({
4242
5235
  }
4243
5236
  },
4244
5237
  async run({ args }) {
4245
- p9.intro(import_picocolors16.default.bold("mcpman remove"));
5238
+ p9.intro(import_picocolors21.default.bold("mcpman remove"));
4246
5239
  const serverName = args.server;
4247
5240
  const servers = await getInstalledServers();
4248
5241
  const match = servers.find((s) => s.name === serverName);
@@ -4252,7 +5245,7 @@ var remove_default = (0, import_citty17.defineCommand)({
4252
5245
  (s) => s.name.includes(serverName) || serverName.includes(s.name)
4253
5246
  );
4254
5247
  if (similar.length > 0) {
4255
- p9.log.info(`Did you mean: ${similar.map((s) => import_picocolors16.default.cyan(s.name)).join(", ")}?`);
5248
+ p9.log.info(`Did you mean: ${similar.map((s) => import_picocolors21.default.cyan(s.name)).join(", ")}?`);
4256
5249
  }
4257
5250
  p9.outro("Nothing to remove.");
4258
5251
  return;
@@ -4287,7 +5280,7 @@ var remove_default = (0, import_citty17.defineCommand)({
4287
5280
  if (!args.yes) {
4288
5281
  const clientNames = targetClients.map(clientDisplayName).join(", ");
4289
5282
  const confirmed = await p9.confirm({
4290
- message: `Remove ${import_picocolors16.default.cyan(serverName)} from ${import_picocolors16.default.yellow(clientNames)}?`
5283
+ message: `Remove ${import_picocolors21.default.cyan(serverName)} from ${import_picocolors21.default.yellow(clientNames)}?`
4291
5284
  });
4292
5285
  if (p9.isCancel(confirmed) || !confirmed) {
4293
5286
  p9.outro("Cancelled.");
@@ -4312,21 +5305,124 @@ var remove_default = (0, import_citty17.defineCommand)({
4312
5305
  }
4313
5306
  if (errors.length > 0) {
4314
5307
  for (const e of errors) p9.log.error(e);
4315
- p9.outro(import_picocolors16.default.red("Completed with errors."));
5308
+ p9.outro(import_picocolors21.default.red("Completed with errors."));
5309
+ process.exit(1);
5310
+ }
5311
+ p9.outro(import_picocolors21.default.green(`Removed "${serverName}" successfully.`));
5312
+ }
5313
+ });
5314
+
5315
+ // src/commands/rollback.ts
5316
+ init_cjs_shims();
5317
+ var p10 = __toESM(require("@clack/prompts"), 1);
5318
+ var import_citty23 = require("citty");
5319
+ var import_picocolors22 = __toESM(require("picocolors"), 1);
5320
+ init_lockfile();
5321
+ init_rollback_service();
5322
+ var rollback_default = (0, import_citty23.defineCommand)({
5323
+ meta: {
5324
+ name: "rollback",
5325
+ description: "Restore a previous lockfile snapshot"
5326
+ },
5327
+ args: {
5328
+ index: {
5329
+ type: "positional",
5330
+ description: "Snapshot index to restore (0 = most recent). Omit to use --list.",
5331
+ required: false
5332
+ },
5333
+ list: {
5334
+ type: "boolean",
5335
+ description: "List available snapshots",
5336
+ default: false
5337
+ },
5338
+ yes: {
5339
+ type: "boolean",
5340
+ description: "Skip confirmation prompt",
5341
+ default: false
5342
+ }
5343
+ },
5344
+ async run({ args }) {
5345
+ const snapshots = listSnapshots();
5346
+ if (args.list || args.index === void 0) {
5347
+ if (snapshots.length === 0) {
5348
+ console.log(
5349
+ import_picocolors22.default.dim("No snapshots available. Snapshots are created on each lockfile write.")
5350
+ );
5351
+ return;
5352
+ }
5353
+ console.log(
5354
+ `
5355
+ ${import_picocolors22.default.bold("Lockfile snapshots")} ${import_picocolors22.default.dim(`(${snapshots.length} available, 0 = most recent)`)}
5356
+ `
5357
+ );
5358
+ for (const snap2 of snapshots) {
5359
+ const size = `${Math.ceil(snap2.sizeBytes / 1024)}KB`;
5360
+ const date2 = snap2.createdAt ? new Date(snap2.createdAt).toLocaleString() : "unknown";
5361
+ console.log(` ${import_picocolors22.default.cyan(`[${snap2.index}]`)} ${import_picocolors22.default.dim(date2)} ${import_picocolors22.default.dim(size)}`);
5362
+ }
5363
+ console.log("");
5364
+ if (args.index === void 0) return;
5365
+ }
5366
+ const idx = Number.parseInt(String(args.index), 10);
5367
+ if (Number.isNaN(idx) || idx < 0) {
5368
+ console.error(
5369
+ `${import_picocolors22.default.red("\u2717")} Invalid index "${args.index}". Must be a non-negative integer.`
5370
+ );
5371
+ process.exit(1);
5372
+ }
5373
+ const snap = snapshots[idx];
5374
+ if (!snap) {
5375
+ console.error(
5376
+ `${import_picocolors22.default.red("\u2717")} Snapshot [${idx}] does not exist. Use --list to see available snapshots.`
5377
+ );
5378
+ process.exit(1);
5379
+ }
5380
+ const content = readSnapshot(idx);
5381
+ if (!content) {
5382
+ console.error(`${import_picocolors22.default.red("\u2717")} Could not read snapshot [${idx}].`);
5383
+ process.exit(1);
5384
+ }
5385
+ const date = snap.createdAt ? new Date(snap.createdAt).toLocaleString() : "unknown";
5386
+ console.log(`
5387
+ ${import_picocolors22.default.bold("Restoring snapshot")} ${import_picocolors22.default.cyan(`[${idx}]`)} ${import_picocolors22.default.dim(date)}
5388
+ `);
5389
+ try {
5390
+ const parsed = JSON.parse(content);
5391
+ const count = Object.keys(parsed.servers ?? {}).length;
5392
+ console.log(` ${import_picocolors22.default.dim(`Preview: ${count} server(s) in snapshot`)}
5393
+ `);
5394
+ } catch {
5395
+ }
5396
+ const lockfilePath = resolveLockfilePath();
5397
+ if (!args.yes) {
5398
+ const confirmed = await p10.confirm({
5399
+ message: `Restore snapshot [${idx}] to ${lockfilePath}?`,
5400
+ initialValue: false
5401
+ });
5402
+ if (p10.isCancel(confirmed) || !confirmed) {
5403
+ p10.cancel("Cancelled.");
5404
+ return;
5405
+ }
5406
+ }
5407
+ const restored = restoreSnapshot(idx, lockfilePath);
5408
+ if (!restored) {
5409
+ console.error(`${import_picocolors22.default.red("\u2717")} Restore failed.`);
4316
5410
  process.exit(1);
4317
5411
  }
4318
- p9.outro(import_picocolors16.default.green(`Removed "${serverName}" successfully.`));
5412
+ console.log(`
5413
+ ${import_picocolors22.default.green("\u2713")} Lockfile restored from snapshot [${idx}].`);
5414
+ console.log(import_picocolors22.default.dim(` Written to: ${lockfilePath}`));
4319
5415
  }
4320
5416
  });
4321
5417
 
4322
5418
  // src/commands/run.ts
4323
5419
  init_cjs_shims();
4324
- var import_node_child_process5 = require("child_process");
4325
- var import_citty18 = require("citty");
4326
- var import_picocolors17 = __toESM(require("picocolors"), 1);
5420
+ var import_node_child_process7 = require("child_process");
5421
+ var import_citty24 = require("citty");
5422
+ var import_picocolors23 = __toESM(require("picocolors"), 1);
4327
5423
  init_lockfile();
4328
5424
  init_vault_service();
4329
- var run_default = (0, import_citty18.defineCommand)({
5425
+ var run_default = (0, import_citty24.defineCommand)({
4330
5426
  meta: {
4331
5427
  name: "run",
4332
5428
  description: "Run an installed MCP server with vault secrets injected"
@@ -4348,8 +5444,8 @@ var run_default = (0, import_citty18.defineCommand)({
4348
5444
  const lockfile = readLockfile();
4349
5445
  const entry = lockfile.servers[serverName];
4350
5446
  if (!entry) {
4351
- console.error(import_picocolors17.default.red(` Error: Server '${serverName}' is not installed.`));
4352
- console.error(import_picocolors17.default.dim(` Run ${import_picocolors17.default.cyan("mcpman install <server>")} to install it first.`));
5447
+ console.error(import_picocolors23.default.red(` Error: Server '${serverName}' is not installed.`));
5448
+ console.error(import_picocolors23.default.dim(` Run ${import_picocolors23.default.cyan("mcpman install <server>")} to install it first.`));
4353
5449
  process.exit(1);
4354
5450
  }
4355
5451
  const lockfileEnv = parseEnvFlags(entry.envVars);
@@ -4361,8 +5457,8 @@ var run_default = (0, import_citty18.defineCommand)({
4361
5457
  ...vaultEnv,
4362
5458
  ...cliEnv
4363
5459
  };
4364
- console.log(import_picocolors17.default.dim(` Running ${import_picocolors17.default.cyan(serverName)}...`));
4365
- const child = (0, import_node_child_process5.spawn)(entry.command, entry.args, {
5460
+ console.log(import_picocolors23.default.dim(` Running ${import_picocolors23.default.cyan(serverName)}...`));
5461
+ const child = (0, import_node_child_process7.spawn)(entry.command, entry.args, {
4366
5462
  env: finalEnv,
4367
5463
  stdio: "inherit"
4368
5464
  });
@@ -4379,7 +5475,7 @@ var run_default = (0, import_citty18.defineCommand)({
4379
5475
  resolve();
4380
5476
  });
4381
5477
  child.on("error", (err) => {
4382
- console.error(import_picocolors17.default.red(` Failed to start '${serverName}': ${err.message}`));
5478
+ console.error(import_picocolors23.default.red(` Failed to start '${serverName}': ${err.message}`));
4383
5479
  process.exit(1);
4384
5480
  resolve();
4385
5481
  });
@@ -4395,16 +5491,16 @@ async function loadVaultSecrets2(serverName) {
4395
5491
  const password2 = await getMasterPassword();
4396
5492
  return getSecretsForServer(serverName, password2);
4397
5493
  } catch {
4398
- console.warn(import_picocolors17.default.yellow(" Warning: Could not load vault secrets, continuing without them."));
5494
+ console.warn(import_picocolors23.default.yellow(" Warning: Could not load vault secrets, continuing without them."));
4399
5495
  return {};
4400
5496
  }
4401
5497
  }
4402
5498
 
4403
5499
  // src/commands/search.ts
4404
5500
  init_cjs_shims();
4405
- var import_citty19 = require("citty");
5501
+ var import_citty25 = require("citty");
4406
5502
  var import_nanospinner4 = require("nanospinner");
4407
- var import_picocolors18 = __toESM(require("picocolors"), 1);
5503
+ var import_picocolors24 = __toESM(require("picocolors"), 1);
4408
5504
 
4409
5505
  // src/core/registry-search.ts
4410
5506
  init_cjs_shims();
@@ -4478,10 +5574,10 @@ function pad2(s, width) {
4478
5574
  function highlightMatch(name, query) {
4479
5575
  const idx = name.toLowerCase().indexOf(query.toLowerCase());
4480
5576
  if (idx === -1) return name;
4481
- return name.slice(0, idx) + import_picocolors18.default.yellow(name.slice(idx, idx + query.length)) + name.slice(idx + query.length);
5577
+ return name.slice(0, idx) + import_picocolors24.default.yellow(name.slice(idx, idx + query.length)) + name.slice(idx + query.length);
4482
5578
  }
4483
5579
  function formatDownloads(n) {
4484
- if (!n) return import_picocolors18.default.dim("\u2014");
5580
+ if (!n) return import_picocolors24.default.dim("\u2014");
4485
5581
  if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
4486
5582
  if (n >= 1e3) return `${(n / 1e3).toFixed(1)}k`;
4487
5583
  return String(n);
@@ -4492,9 +5588,9 @@ function printNpmResults(results, query) {
4492
5588
  const dlWidth = 9;
4493
5589
  const descMax = 50;
4494
5590
  const header = ` ${pad2("NAME", nameWidth)} ${pad2("VERSION", verWidth)} ${pad2("DOWNLOADS", dlWidth)} DESCRIPTION`;
4495
- console.log(import_picocolors18.default.dim(header));
5591
+ console.log(import_picocolors24.default.dim(header));
4496
5592
  console.log(
4497
- import_picocolors18.default.dim(
5593
+ import_picocolors24.default.dim(
4498
5594
  ` ${"-".repeat(nameWidth)} ${"-".repeat(verWidth)} ${"-".repeat(dlWidth)} ${"-".repeat(descMax)}`
4499
5595
  )
4500
5596
  );
@@ -4502,8 +5598,8 @@ function printNpmResults(results, query) {
4502
5598
  const name = highlightMatch(pad2(r.name, nameWidth), query);
4503
5599
  const ver = pad2(r.version, verWidth);
4504
5600
  const dl = pad2(formatDownloads(r.downloads), dlWidth);
4505
- const desc = truncate2(r.description || import_picocolors18.default.dim("(no description)"), descMax);
4506
- console.log(` ${name} ${import_picocolors18.default.dim(ver)} ${dl} ${desc}`);
5601
+ const desc = truncate2(r.description || import_picocolors24.default.dim("(no description)"), descMax);
5602
+ console.log(` ${name} ${import_picocolors24.default.dim(ver)} ${dl} ${desc}`);
4507
5603
  }
4508
5604
  }
4509
5605
  function printSmitheryResults(results, query) {
@@ -4511,19 +5607,19 @@ function printSmitheryResults(results, query) {
4511
5607
  const usesWidth = 8;
4512
5608
  const descMax = 50;
4513
5609
  const header = ` ${pad2("NAME", nameWidth)} ${pad2("USES", usesWidth)} DESCRIPTION`;
4514
- console.log(import_picocolors18.default.dim(header));
5610
+ console.log(import_picocolors24.default.dim(header));
4515
5611
  console.log(
4516
- import_picocolors18.default.dim(` ${"-".repeat(nameWidth)} ${"-".repeat(usesWidth)} ${"-".repeat(descMax)}`)
5612
+ import_picocolors24.default.dim(` ${"-".repeat(nameWidth)} ${"-".repeat(usesWidth)} ${"-".repeat(descMax)}`)
4517
5613
  );
4518
5614
  for (const r of results) {
4519
5615
  const name = highlightMatch(pad2(r.name, nameWidth), query);
4520
5616
  const uses = pad2(formatDownloads(r.useCount), usesWidth);
4521
- const badge = r.verified ? import_picocolors18.default.green(" \u2713") : "";
4522
- const desc = truncate2(r.description || import_picocolors18.default.dim("(no description)"), descMax);
5617
+ const badge = r.verified ? import_picocolors24.default.green(" \u2713") : "";
5618
+ const desc = truncate2(r.description || import_picocolors24.default.dim("(no description)"), descMax);
4523
5619
  console.log(` ${name}${badge} ${uses} ${desc}`);
4524
5620
  }
4525
5621
  }
4526
- var search_default = (0, import_citty19.defineCommand)({
5622
+ var search_default = (0, import_citty25.defineCommand)({
4527
5623
  meta: {
4528
5624
  name: "search",
4529
5625
  description: "Search for MCP servers on npm or Smithery registry"
@@ -4555,7 +5651,7 @@ var search_default = (0, import_citty19.defineCommand)({
4555
5651
  const registry = args.registry.toLowerCase();
4556
5652
  const limit = Math.min(Math.max(1, Number.parseInt(args.limit, 10) || 20), 100);
4557
5653
  if (registry !== "npm" && registry !== "smithery") {
4558
- console.error(import_picocolors18.default.red(` Unknown registry "${registry}". Use "npm" or "smithery".`));
5654
+ console.error(import_picocolors24.default.red(` Unknown registry "${registry}". Use "npm" or "smithery".`));
4559
5655
  process.exit(1);
4560
5656
  }
4561
5657
  const spinner5 = (0, import_nanospinner4.createSpinner)(`Searching ${registry} for "${query}"...`).start();
@@ -4563,20 +5659,20 @@ var search_default = (0, import_citty19.defineCommand)({
4563
5659
  const results2 = await searchNpm(query, limit);
4564
5660
  spinner5.stop();
4565
5661
  if (results2.length === 0) {
4566
- console.log(import_picocolors18.default.dim(`
5662
+ console.log(import_picocolors24.default.dim(`
4567
5663
  No results found for "${query}" on npm.
4568
5664
  `));
4569
5665
  return;
4570
5666
  }
4571
5667
  console.log(
4572
- import_picocolors18.default.bold(
5668
+ import_picocolors24.default.bold(
4573
5669
  `
4574
5670
  mcpman search \u2014 npm (${results2.length} result${results2.length !== 1 ? "s" : ""})
4575
5671
  `
4576
5672
  )
4577
5673
  );
4578
5674
  printNpmResults(results2, query);
4579
- console.log(import_picocolors18.default.dim("\n Install with: mcpman install <name>\n"));
5675
+ console.log(import_picocolors24.default.dim("\n Install with: mcpman install <name>\n"));
4580
5676
  if (args.all) {
4581
5677
  await printPluginResults(query, limit);
4582
5678
  }
@@ -4585,20 +5681,20 @@ var search_default = (0, import_citty19.defineCommand)({
4585
5681
  const results = await searchSmithery(query, limit);
4586
5682
  spinner5.stop();
4587
5683
  if (results.length === 0) {
4588
- console.log(import_picocolors18.default.dim(`
5684
+ console.log(import_picocolors24.default.dim(`
4589
5685
  No results found for "${query}" on Smithery.
4590
5686
  `));
4591
5687
  return;
4592
5688
  }
4593
5689
  console.log(
4594
- import_picocolors18.default.bold(
5690
+ import_picocolors24.default.bold(
4595
5691
  `
4596
5692
  mcpman search \u2014 Smithery (${results.length} result${results.length !== 1 ? "s" : ""})
4597
5693
  `
4598
5694
  )
4599
5695
  );
4600
5696
  printSmitheryResults(results, query);
4601
- console.log(import_picocolors18.default.dim("\n Install with: mcpman install <name>\n"));
5697
+ console.log(import_picocolors24.default.dim("\n Install with: mcpman install <name>\n"));
4602
5698
  if (args.all) {
4603
5699
  await printPluginResults(query, limit);
4604
5700
  }
@@ -4608,7 +5704,7 @@ async function printPluginResults(query, limit) {
4608
5704
  const pluginResults = await searchPlugins(query, limit);
4609
5705
  if (pluginResults.length === 0) return;
4610
5706
  console.log(
4611
- import_picocolors18.default.bold(
5707
+ import_picocolors24.default.bold(
4612
5708
  `
4613
5709
  Plugins (${pluginResults.length} result${pluginResults.length !== 1 ? "s" : ""})
4614
5710
  `
@@ -4618,23 +5714,23 @@ async function printPluginResults(query, limit) {
4618
5714
  const srcWidth = Math.max(6, ...pluginResults.map((r) => r.source.length));
4619
5715
  const descMax = 50;
4620
5716
  const header = ` ${pad2("NAME", nameWidth)} ${pad2("SOURCE", srcWidth)} DESCRIPTION`;
4621
- console.log(import_picocolors18.default.dim(header));
5717
+ console.log(import_picocolors24.default.dim(header));
4622
5718
  console.log(
4623
- import_picocolors18.default.dim(` ${"-".repeat(nameWidth)} ${"-".repeat(srcWidth)} ${"-".repeat(descMax)}`)
5719
+ import_picocolors24.default.dim(` ${"-".repeat(nameWidth)} ${"-".repeat(srcWidth)} ${"-".repeat(descMax)}`)
4624
5720
  );
4625
5721
  for (const r of pluginResults) {
4626
5722
  const name = highlightMatch(pad2(r.name, nameWidth), query);
4627
5723
  const src = pad2(r.source, srcWidth);
4628
- const desc = truncate2(r.description || import_picocolors18.default.dim("(no description)"), descMax);
4629
- console.log(` ${name} ${import_picocolors18.default.dim(src)} ${desc}`);
5724
+ const desc = truncate2(r.description || import_picocolors24.default.dim("(no description)"), descMax);
5725
+ console.log(` ${name} ${import_picocolors24.default.dim(src)} ${desc}`);
4630
5726
  }
4631
5727
  }
4632
5728
 
4633
5729
  // src/commands/secrets.ts
4634
5730
  init_cjs_shims();
4635
- var p10 = __toESM(require("@clack/prompts"), 1);
4636
- var import_citty20 = require("citty");
4637
- var import_picocolors19 = __toESM(require("picocolors"), 1);
5731
+ var p11 = __toESM(require("@clack/prompts"), 1);
5732
+ var import_citty26 = require("citty");
5733
+ var import_picocolors25 = __toESM(require("picocolors"), 1);
4638
5734
  init_vault_service();
4639
5735
  function maskValue(value) {
4640
5736
  if (value.length <= 8) return "***";
@@ -4645,7 +5741,7 @@ function parseKeyValue(input) {
4645
5741
  if (idx <= 0) return null;
4646
5742
  return { key: input.slice(0, idx), value: input.slice(idx + 1) };
4647
5743
  }
4648
- var setCommand2 = (0, import_citty20.defineCommand)({
5744
+ var setCommand2 = (0, import_citty26.defineCommand)({
4649
5745
  meta: { name: "set", description: "Store an encrypted secret for a server" },
4650
5746
  args: {
4651
5747
  server: {
@@ -4662,28 +5758,28 @@ var setCommand2 = (0, import_citty20.defineCommand)({
4662
5758
  async run({ args }) {
4663
5759
  const parsed = parseKeyValue(args.keyvalue);
4664
5760
  if (!parsed) {
4665
- console.error(`${import_picocolors19.default.red("\u2717")} Invalid format. Expected KEY=VALUE`);
5761
+ console.error(`${import_picocolors25.default.red("\u2717")} Invalid format. Expected KEY=VALUE`);
4666
5762
  process.exit(1);
4667
5763
  }
4668
- p10.intro(import_picocolors19.default.cyan("mcpman secrets set"));
5764
+ p11.intro(import_picocolors25.default.cyan("mcpman secrets set"));
4669
5765
  const isNew = listSecrets(args.server).length === 0 || !listSecrets(args.server)[0]?.keys.includes(parsed.key);
4670
5766
  const vaultPath = (await Promise.resolve().then(() => (init_vault_service(), vault_service_exports))).getVaultPath();
4671
5767
  const vaultExists = (await import("fs")).existsSync(vaultPath);
4672
5768
  const password2 = await getMasterPassword(!vaultExists && isNew);
4673
- const spin = p10.spinner();
5769
+ const spin = p11.spinner();
4674
5770
  spin.start("Encrypting secret...");
4675
5771
  try {
4676
5772
  setSecret(args.server, parsed.key, parsed.value, password2);
4677
- spin.stop(`${import_picocolors19.default.green("\u2713")} Stored ${import_picocolors19.default.bold(parsed.key)} for ${import_picocolors19.default.cyan(args.server)}`);
5773
+ spin.stop(`${import_picocolors25.default.green("\u2713")} Stored ${import_picocolors25.default.bold(parsed.key)} for ${import_picocolors25.default.cyan(args.server)}`);
4678
5774
  } catch (err) {
4679
- spin.stop(`${import_picocolors19.default.red("\u2717")} Failed to store secret`);
4680
- console.error(import_picocolors19.default.dim(String(err)));
5775
+ spin.stop(`${import_picocolors25.default.red("\u2717")} Failed to store secret`);
5776
+ console.error(import_picocolors25.default.dim(String(err)));
4681
5777
  process.exit(1);
4682
5778
  }
4683
- p10.outro(import_picocolors19.default.dim("Secret encrypted and saved to vault."));
5779
+ p11.outro(import_picocolors25.default.dim("Secret encrypted and saved to vault."));
4684
5780
  }
4685
5781
  });
4686
- var listCommand3 = (0, import_citty20.defineCommand)({
5782
+ var listCommand3 = (0, import_citty26.defineCommand)({
4687
5783
  meta: { name: "list", description: "List secret keys stored in the vault" },
4688
5784
  args: {
4689
5785
  server: {
@@ -4695,27 +5791,27 @@ var listCommand3 = (0, import_citty20.defineCommand)({
4695
5791
  async run({ args }) {
4696
5792
  const results = listSecrets(args.server || void 0);
4697
5793
  if (results.length === 0) {
4698
- const filter = args.server ? ` for ${import_picocolors19.default.cyan(args.server)}` : "";
4699
- console.log(import_picocolors19.default.dim(`No secrets stored${filter}.`));
5794
+ const filter = args.server ? ` for ${import_picocolors25.default.cyan(args.server)}` : "";
5795
+ console.log(import_picocolors25.default.dim(`No secrets stored${filter}.`));
4700
5796
  return;
4701
5797
  }
4702
5798
  console.log("");
4703
5799
  for (const { server, keys } of results) {
4704
- console.log(import_picocolors19.default.bold(import_picocolors19.default.cyan(server)));
5800
+ console.log(import_picocolors25.default.bold(import_picocolors25.default.cyan(server)));
4705
5801
  for (const key of keys) {
4706
- console.log(` ${import_picocolors19.default.green("\u25CF")} ${import_picocolors19.default.bold(key)} ${import_picocolors19.default.dim(maskValue("\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022"))}`);
5802
+ console.log(` ${import_picocolors25.default.green("\u25CF")} ${import_picocolors25.default.bold(key)} ${import_picocolors25.default.dim(maskValue("\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022"))}`);
4707
5803
  }
4708
5804
  console.log("");
4709
5805
  }
4710
5806
  const total = results.reduce((n, r) => n + r.keys.length, 0);
4711
5807
  console.log(
4712
- import_picocolors19.default.dim(
5808
+ import_picocolors25.default.dim(
4713
5809
  ` ${total} secret${total !== 1 ? "s" : ""} in ${results.length} server${results.length !== 1 ? "s" : ""}`
4714
5810
  )
4715
5811
  );
4716
5812
  }
4717
5813
  });
4718
- var removeCommand2 = (0, import_citty20.defineCommand)({
5814
+ var removeCommand2 = (0, import_citty26.defineCommand)({
4719
5815
  meta: { name: "remove", description: "Delete a secret from the vault" },
4720
5816
  args: {
4721
5817
  server: {
@@ -4730,25 +5826,25 @@ var removeCommand2 = (0, import_citty20.defineCommand)({
4730
5826
  }
4731
5827
  },
4732
5828
  async run({ args }) {
4733
- const confirmed = await p10.confirm({
4734
- message: `Remove ${import_picocolors19.default.bold(args.key)} from ${import_picocolors19.default.cyan(args.server)}?`,
5829
+ const confirmed = await p11.confirm({
5830
+ message: `Remove ${import_picocolors25.default.bold(args.key)} from ${import_picocolors25.default.cyan(args.server)}?`,
4735
5831
  initialValue: false
4736
5832
  });
4737
- if (p10.isCancel(confirmed) || !confirmed) {
4738
- p10.cancel("Cancelled.");
5833
+ if (p11.isCancel(confirmed) || !confirmed) {
5834
+ p11.cancel("Cancelled.");
4739
5835
  return;
4740
5836
  }
4741
5837
  try {
4742
5838
  removeSecret(args.server, args.key);
4743
- console.log(`${import_picocolors19.default.green("\u2713")} Removed ${import_picocolors19.default.bold(args.key)} from ${import_picocolors19.default.cyan(args.server)}`);
5839
+ console.log(`${import_picocolors25.default.green("\u2713")} Removed ${import_picocolors25.default.bold(args.key)} from ${import_picocolors25.default.cyan(args.server)}`);
4744
5840
  } catch (err) {
4745
- console.error(`${import_picocolors19.default.red("\u2717")} Failed to remove secret`);
4746
- console.error(import_picocolors19.default.dim(String(err)));
5841
+ console.error(`${import_picocolors25.default.red("\u2717")} Failed to remove secret`);
5842
+ console.error(import_picocolors25.default.dim(String(err)));
4747
5843
  process.exit(1);
4748
5844
  }
4749
5845
  }
4750
5846
  });
4751
- var secrets_default = (0, import_citty20.defineCommand)({
5847
+ var secrets_default = (0, import_citty26.defineCommand)({
4752
5848
  meta: {
4753
5849
  name: "secrets",
4754
5850
  description: "Manage encrypted secrets for MCP servers"
@@ -4762,9 +5858,9 @@ var secrets_default = (0, import_citty20.defineCommand)({
4762
5858
 
4763
5859
  // src/commands/sync.ts
4764
5860
  init_cjs_shims();
4765
- var p11 = __toESM(require("@clack/prompts"), 1);
4766
- var import_citty21 = require("citty");
4767
- var import_picocolors20 = __toESM(require("picocolors"), 1);
5861
+ var p12 = __toESM(require("@clack/prompts"), 1);
5862
+ var import_citty27 = require("citty");
5863
+ var import_picocolors26 = __toESM(require("picocolors"), 1);
4768
5864
 
4769
5865
  // src/core/config-diff.ts
4770
5866
  init_cjs_shims();
@@ -4915,14 +6011,14 @@ async function getClientConfigs() {
4915
6011
  }
4916
6012
 
4917
6013
  // src/commands/sync.ts
4918
- var VALID_CLIENTS = ["claude-desktop", "cursor", "vscode", "windsurf"];
4919
- var CLIENT_DISPLAY3 = {
6014
+ var VALID_CLIENTS2 = ["claude-desktop", "cursor", "vscode", "windsurf"];
6015
+ var CLIENT_DISPLAY4 = {
4920
6016
  "claude-desktop": "Claude Desktop",
4921
6017
  cursor: "Cursor",
4922
6018
  vscode: "VS Code",
4923
6019
  windsurf: "Windsurf"
4924
6020
  };
4925
- var sync_default = (0, import_citty21.defineCommand)({
6021
+ var sync_default = (0, import_citty27.defineCommand)({
4926
6022
  meta: {
4927
6023
  name: "sync",
4928
6024
  description: "Sync MCP server configs across all detected AI clients"
@@ -4949,20 +6045,20 @@ var sync_default = (0, import_citty21.defineCommand)({
4949
6045
  }
4950
6046
  },
4951
6047
  async run({ args }) {
4952
- p11.intro(`${import_picocolors20.default.cyan("mcpman sync")}`);
6048
+ p12.intro(`${import_picocolors26.default.cyan("mcpman sync")}`);
4953
6049
  const sourceClient = args.source;
4954
- if (sourceClient && !VALID_CLIENTS.includes(sourceClient)) {
4955
- p11.log.error(
4956
- `Invalid --source "${sourceClient}". Must be one of: ${VALID_CLIENTS.join(", ")}`
6050
+ if (sourceClient && !VALID_CLIENTS2.includes(sourceClient)) {
6051
+ p12.log.error(
6052
+ `Invalid --source "${sourceClient}". Must be one of: ${VALID_CLIENTS2.join(", ")}`
4957
6053
  );
4958
6054
  process.exit(1);
4959
6055
  }
4960
- const spinner5 = p11.spinner();
6056
+ const spinner5 = p12.spinner();
4961
6057
  spinner5.start("Detecting clients and reading configs...");
4962
6058
  const { configs, handlers } = await getClientConfigs();
4963
6059
  spinner5.stop(`Found ${configs.size} client(s)`);
4964
6060
  if (configs.size === 0) {
4965
- p11.log.warn(
6061
+ p12.log.warn(
4966
6062
  "No AI clients detected. Install Claude Desktop, Cursor, VS Code, or Windsurf first."
4967
6063
  );
4968
6064
  process.exit(0);
@@ -4971,10 +6067,10 @@ var sync_default = (0, import_citty21.defineCommand)({
4971
6067
  let actions;
4972
6068
  if (sourceClient) {
4973
6069
  if (!configs.has(sourceClient)) {
4974
- p11.log.error(`Source client "${sourceClient}" is not detected or its config is unreadable.`);
6070
+ p12.log.error(`Source client "${sourceClient}" is not detected or its config is unreadable.`);
4975
6071
  process.exit(1);
4976
6072
  }
4977
- p11.log.info(`Using ${CLIENT_DISPLAY3[sourceClient]} as source of truth`);
6073
+ p12.log.info(`Using ${CLIENT_DISPLAY4[sourceClient]} as source of truth`);
4978
6074
  actions = computeDiffFromClient(sourceClient, configs, diffOptions);
4979
6075
  } else {
4980
6076
  const lockfile = readLockfile();
@@ -4985,32 +6081,32 @@ var sync_default = (0, import_citty21.defineCommand)({
4985
6081
  const extraCount = actions.filter((a) => a.action === "extra").length;
4986
6082
  const removeCount = actions.filter((a) => a.action === "remove").length;
4987
6083
  if (addCount === 0 && removeCount === 0 && extraCount === 0) {
4988
- p11.outro(import_picocolors20.default.green("All clients are in sync."));
6084
+ p12.outro(import_picocolors26.default.green("All clients are in sync."));
4989
6085
  process.exit(0);
4990
6086
  }
4991
6087
  const parts = [];
4992
- if (addCount > 0) parts.push(import_picocolors20.default.green(`${addCount} to add`));
4993
- if (removeCount > 0) parts.push(import_picocolors20.default.red(`${removeCount} to remove`));
4994
- if (extraCount > 0) parts.push(import_picocolors20.default.yellow(`${extraCount} extra (informational)`));
4995
- p11.log.info(parts.join(" \xB7 "));
6088
+ if (addCount > 0) parts.push(import_picocolors26.default.green(`${addCount} to add`));
6089
+ if (removeCount > 0) parts.push(import_picocolors26.default.red(`${removeCount} to remove`));
6090
+ if (extraCount > 0) parts.push(import_picocolors26.default.yellow(`${extraCount} extra (informational)`));
6091
+ p12.log.info(parts.join(" \xB7 "));
4996
6092
  if (args["dry-run"]) {
4997
- p11.outro(import_picocolors20.default.dim("Dry run \u2014 no changes applied."));
6093
+ p12.outro(import_picocolors26.default.dim("Dry run \u2014 no changes applied."));
4998
6094
  process.exit(1);
4999
6095
  }
5000
6096
  if (addCount === 0 && removeCount === 0) {
5001
- p11.outro(import_picocolors20.default.dim("No additions needed. Extra servers left untouched."));
6097
+ p12.outro(import_picocolors26.default.dim("No additions needed. Extra servers left untouched."));
5002
6098
  process.exit(1);
5003
6099
  }
5004
6100
  if (!args.yes) {
5005
6101
  const actionParts = [];
5006
6102
  if (addCount > 0) actionParts.push(`${addCount} addition(s)`);
5007
6103
  if (removeCount > 0) actionParts.push(`${removeCount} removal(s)`);
5008
- const confirmed = await p11.confirm({
6104
+ const confirmed = await p12.confirm({
5009
6105
  message: `Apply ${actionParts.join(" and ")} to client configs?`,
5010
6106
  initialValue: true
5011
6107
  });
5012
- if (p11.isCancel(confirmed) || !confirmed) {
5013
- p11.outro(import_picocolors20.default.dim("Cancelled \u2014 no changes applied."));
6108
+ if (p12.isCancel(confirmed) || !confirmed) {
6109
+ p12.outro(import_picocolors26.default.dim("Cancelled \u2014 no changes applied."));
5014
6110
  process.exit(0);
5015
6111
  }
5016
6112
  }
@@ -5018,37 +6114,37 @@ var sync_default = (0, import_citty21.defineCommand)({
5018
6114
  const result = await applySyncActions(actions, handlers);
5019
6115
  spinner5.stop("Done");
5020
6116
  if (result.applied > 0) {
5021
- p11.log.success(`Added ${result.applied} server(s) to client configs.`);
6117
+ p12.log.success(`Added ${result.applied} server(s) to client configs.`);
5022
6118
  }
5023
6119
  if (result.removed > 0) {
5024
- p11.log.success(`Removed ${result.removed} server(s) from client configs.`);
6120
+ p12.log.success(`Removed ${result.removed} server(s) from client configs.`);
5025
6121
  }
5026
6122
  if (result.failed > 0) {
5027
6123
  for (const e of result.errors) {
5028
- p11.log.error(`Failed to sync "${e.server}" on ${e.client}: ${e.error}`);
6124
+ p12.log.error(`Failed to sync "${e.server}" on ${e.client}: ${e.error}`);
5029
6125
  }
5030
6126
  }
5031
- p11.outro(
5032
- result.failed === 0 ? import_picocolors20.default.green("Sync complete.") : import_picocolors20.default.yellow("Sync complete with errors.")
6127
+ p12.outro(
6128
+ result.failed === 0 ? import_picocolors26.default.green("Sync complete.") : import_picocolors26.default.yellow("Sync complete with errors.")
5033
6129
  );
5034
6130
  process.exit(result.failed > 0 ? 1 : 0);
5035
6131
  }
5036
6132
  });
5037
6133
  function printDiffTable(actions) {
5038
6134
  if (actions.length === 0) {
5039
- p11.log.info("No actions to display.");
6135
+ p12.log.info("No actions to display.");
5040
6136
  return;
5041
6137
  }
5042
6138
  const nameWidth = Math.max(6, ...actions.map((a) => a.server.length));
5043
6139
  const clientWidth = Math.max(
5044
6140
  6,
5045
- ...actions.map((a) => CLIENT_DISPLAY3[a.client]?.length ?? a.client.length)
6141
+ ...actions.map((a) => CLIENT_DISPLAY4[a.client]?.length ?? a.client.length)
5046
6142
  );
5047
6143
  const header = ` ${pad3("SERVER", nameWidth)} ${pad3("CLIENT", clientWidth)} STATUS`;
5048
- console.log(import_picocolors20.default.dim(header));
5049
- console.log(import_picocolors20.default.dim(` ${"-".repeat(nameWidth)} ${"-".repeat(clientWidth)} ------`));
6144
+ console.log(import_picocolors26.default.dim(header));
6145
+ console.log(import_picocolors26.default.dim(` ${"-".repeat(nameWidth)} ${"-".repeat(clientWidth)} ------`));
5050
6146
  for (const action of actions) {
5051
- const clientDisplay = CLIENT_DISPLAY3[action.client] ?? action.client;
6147
+ const clientDisplay = CLIENT_DISPLAY4[action.client] ?? action.client;
5052
6148
  const [icon, statusText] = formatAction(action.action);
5053
6149
  console.log(
5054
6150
  ` ${pad3(action.server, nameWidth)} ${pad3(clientDisplay, clientWidth)} ${icon} ${statusText}`
@@ -5059,13 +6155,13 @@ function printDiffTable(actions) {
5059
6155
  function formatAction(action) {
5060
6156
  switch (action) {
5061
6157
  case "add":
5062
- return [import_picocolors20.default.green("+"), import_picocolors20.default.green("missing \u2014 will add")];
6158
+ return [import_picocolors26.default.green("+"), import_picocolors26.default.green("missing \u2014 will add")];
5063
6159
  case "extra":
5064
- return [import_picocolors20.default.yellow("?"), import_picocolors20.default.yellow("extra (not in lockfile)")];
6160
+ return [import_picocolors26.default.yellow("?"), import_picocolors26.default.yellow("extra (not in lockfile)")];
5065
6161
  case "remove":
5066
- return [import_picocolors20.default.red("\u2013"), import_picocolors20.default.red("extra \u2014 will remove")];
6162
+ return [import_picocolors26.default.red("\u2013"), import_picocolors26.default.red("extra \u2014 will remove")];
5067
6163
  case "ok":
5068
- return [import_picocolors20.default.dim("\xB7"), import_picocolors20.default.dim("in sync")];
6164
+ return [import_picocolors26.default.dim("\xB7"), import_picocolors26.default.dim("in sync")];
5069
6165
  }
5070
6166
  }
5071
6167
  function pad3(s, width) {
@@ -5074,13 +6170,13 @@ function pad3(s, width) {
5074
6170
 
5075
6171
  // src/commands/test-command.ts
5076
6172
  init_cjs_shims();
5077
- var import_citty22 = require("citty");
5078
- var import_picocolors21 = __toESM(require("picocolors"), 1);
6173
+ var import_citty28 = require("citty");
6174
+ var import_picocolors27 = __toESM(require("picocolors"), 1);
5079
6175
  init_lockfile();
5080
6176
 
5081
6177
  // src/core/mcp-tester.ts
5082
6178
  init_cjs_shims();
5083
- var import_node_child_process6 = require("child_process");
6179
+ var import_node_child_process8 = require("child_process");
5084
6180
  var TIMEOUT_MS = 1e4;
5085
6181
  async function testMcpServer(serverName, command, args, env) {
5086
6182
  const start = Date.now();
@@ -5090,7 +6186,7 @@ async function testMcpServer(serverName, command, args, env) {
5090
6186
  let initOk = false;
5091
6187
  let toolsOk = false;
5092
6188
  let tools = [];
5093
- const child = (0, import_node_child_process6.spawn)(command, args, {
6189
+ const child = (0, import_node_child_process8.spawn)(command, args, {
5094
6190
  env: { ...process.env, ...env },
5095
6191
  stdio: ["pipe", "pipe", "pipe"]
5096
6192
  });
@@ -5176,7 +6272,7 @@ async function testMcpServer(serverName, command, args, env) {
5176
6272
 
5177
6273
  // src/commands/test-command.ts
5178
6274
  init_vault_service();
5179
- var test_command_default = (0, import_citty22.defineCommand)({
6275
+ var test_command_default = (0, import_citty28.defineCommand)({
5180
6276
  meta: {
5181
6277
  name: "test",
5182
6278
  description: "Test MCP server connectivity and capabilities"
@@ -5197,10 +6293,10 @@ var test_command_default = (0, import_citty22.defineCommand)({
5197
6293
  const lockfile = readLockfile();
5198
6294
  const serverNames = args.all ? Object.keys(lockfile.servers) : args.server ? [args.server] : [];
5199
6295
  if (serverNames.length === 0) {
5200
- console.error(import_picocolors21.default.red(" Error: Specify a server name or use --all."));
6296
+ console.error(import_picocolors27.default.red(" Error: Specify a server name or use --all."));
5201
6297
  process.exit(1);
5202
6298
  }
5203
- console.log(import_picocolors21.default.bold(`
6299
+ console.log(import_picocolors27.default.bold(`
5204
6300
  mcpman test \u2014 ${serverNames.length} server(s)
5205
6301
  `));
5206
6302
  let passed = 0;
@@ -5208,7 +6304,7 @@ var test_command_default = (0, import_citty22.defineCommand)({
5208
6304
  for (const name of serverNames) {
5209
6305
  const entry = lockfile.servers[name];
5210
6306
  if (!entry) {
5211
- console.log(` ${import_picocolors21.default.red("\u2717")} ${import_picocolors21.default.bold(name)} \u2014 not installed`);
6307
+ console.log(` ${import_picocolors27.default.red("\u2717")} ${import_picocolors27.default.bold(name)} \u2014 not installed`);
5212
6308
  failed++;
5213
6309
  continue;
5214
6310
  }
@@ -5219,27 +6315,27 @@ var test_command_default = (0, import_citty22.defineCommand)({
5219
6315
  if (result.passed) {
5220
6316
  passed++;
5221
6317
  console.log(
5222
- ` ${import_picocolors21.default.green("\u2713")} ${import_picocolors21.default.bold(name)} ${import_picocolors21.default.dim(`(${result.responseTimeMs}ms)`)}`
6318
+ ` ${import_picocolors27.default.green("\u2713")} ${import_picocolors27.default.bold(name)} ${import_picocolors27.default.dim(`(${result.responseTimeMs}ms)`)}`
5223
6319
  );
5224
6320
  if (result.tools.length > 0) {
5225
- console.log(import_picocolors21.default.dim(` Tools: ${result.tools.join(", ")}`));
6321
+ console.log(import_picocolors27.default.dim(` Tools: ${result.tools.join(", ")}`));
5226
6322
  }
5227
6323
  } else {
5228
6324
  failed++;
5229
- console.log(` ${import_picocolors21.default.red("\u2717")} ${import_picocolors21.default.bold(name)} ${import_picocolors21.default.dim(`(${result.responseTimeMs}ms)`)}`);
6325
+ console.log(` ${import_picocolors27.default.red("\u2717")} ${import_picocolors27.default.bold(name)} ${import_picocolors27.default.dim(`(${result.responseTimeMs}ms)`)}`);
5230
6326
  if (result.error) {
5231
- console.log(` ${import_picocolors21.default.red(result.error)}`);
6327
+ console.log(` ${import_picocolors27.default.red(result.error)}`);
5232
6328
  }
5233
6329
  console.log(
5234
- ` ${import_picocolors21.default.dim("initialize:")} ${result.initializeOk ? import_picocolors21.default.green("ok") : import_picocolors21.default.red("fail")} ${import_picocolors21.default.dim("tools/list:")} ${result.toolsListOk ? import_picocolors21.default.green("ok") : import_picocolors21.default.red("fail")}`
6330
+ ` ${import_picocolors27.default.dim("initialize:")} ${result.initializeOk ? import_picocolors27.default.green("ok") : import_picocolors27.default.red("fail")} ${import_picocolors27.default.dim("tools/list:")} ${result.toolsListOk ? import_picocolors27.default.green("ok") : import_picocolors27.default.red("fail")}`
5235
6331
  );
5236
6332
  }
5237
6333
  }
5238
- console.log(import_picocolors21.default.dim(`
6334
+ console.log(import_picocolors27.default.dim(`
5239
6335
  ${"\u2500".repeat(40)}`));
5240
6336
  const parts = [];
5241
- if (passed > 0) parts.push(import_picocolors21.default.green(`${passed} passed`));
5242
- if (failed > 0) parts.push(import_picocolors21.default.red(`${failed} failed`));
6337
+ if (passed > 0) parts.push(import_picocolors27.default.green(`${passed} passed`));
6338
+ if (failed > 0) parts.push(import_picocolors27.default.red(`${failed} failed`));
5243
6339
  console.log(` ${parts.join(", ")}
5244
6340
  `);
5245
6341
  if (failed > 0) process.exit(1);
@@ -5258,26 +6354,26 @@ async function loadVaultSecrets3(serverName) {
5258
6354
 
5259
6355
  // src/commands/update.ts
5260
6356
  init_cjs_shims();
5261
- var p12 = __toESM(require("@clack/prompts"), 1);
5262
- var import_citty23 = require("citty");
5263
- var import_picocolors23 = __toESM(require("picocolors"), 1);
6357
+ var p13 = __toESM(require("@clack/prompts"), 1);
6358
+ var import_citty29 = require("citty");
6359
+ var import_picocolors29 = __toESM(require("picocolors"), 1);
5264
6360
  init_lockfile();
5265
6361
 
5266
6362
  // src/core/update-notifier.ts
5267
6363
  init_cjs_shims();
5268
- var import_node_fs14 = __toESM(require("fs"), 1);
6364
+ var import_node_fs18 = __toESM(require("fs"), 1);
5269
6365
  var import_node_os6 = __toESM(require("os"), 1);
5270
- var import_node_path17 = __toESM(require("path"), 1);
5271
- var import_picocolors22 = __toESM(require("picocolors"), 1);
5272
- var CACHE_FILE = import_node_path17.default.join(import_node_os6.default.homedir(), ".mcpman", ".update-check");
6366
+ var import_node_path19 = __toESM(require("path"), 1);
6367
+ var import_picocolors28 = __toESM(require("picocolors"), 1);
6368
+ var CACHE_FILE = import_node_path19.default.join(import_node_os6.default.homedir(), ".mcpman", ".update-check");
5273
6369
  var TTL_MS = 24 * 60 * 60 * 1e3;
5274
6370
  function writeUpdateCache(data) {
5275
6371
  try {
5276
- const dir = import_node_path17.default.dirname(CACHE_FILE);
5277
- if (!import_node_fs14.default.existsSync(dir)) import_node_fs14.default.mkdirSync(dir, { recursive: true });
6372
+ const dir = import_node_path19.default.dirname(CACHE_FILE);
6373
+ if (!import_node_fs18.default.existsSync(dir)) import_node_fs18.default.mkdirSync(dir, { recursive: true });
5278
6374
  const tmp = `${CACHE_FILE}.tmp`;
5279
- import_node_fs14.default.writeFileSync(tmp, JSON.stringify(data, null, 2), "utf-8");
5280
- import_node_fs14.default.renameSync(tmp, CACHE_FILE);
6375
+ import_node_fs18.default.writeFileSync(tmp, JSON.stringify(data, null, 2), "utf-8");
6376
+ import_node_fs18.default.renameSync(tmp, CACHE_FILE);
5281
6377
  } catch {
5282
6378
  }
5283
6379
  }
@@ -5300,19 +6396,19 @@ function printTable(updates) {
5300
6396
  "LATEST".padEnd(VER_W),
5301
6397
  "STATUS"
5302
6398
  ].join(" ");
5303
- console.log(import_picocolors23.default.bold(`
6399
+ console.log(import_picocolors29.default.bold(`
5304
6400
  ${header}`));
5305
- console.log(import_picocolors23.default.dim(` ${"\u2500".repeat(NAME_W + VER_W * 2 + 20)}`));
6401
+ console.log(import_picocolors29.default.dim(` ${"\u2500".repeat(NAME_W + VER_W * 2 + 20)}`));
5306
6402
  for (const u of updates) {
5307
6403
  const nameCol = u.server.slice(0, NAME_W).padEnd(NAME_W);
5308
6404
  const curCol = u.currentVersion.padEnd(VER_W);
5309
6405
  const latCol = u.latestVersion.padEnd(VER_W);
5310
- const statusCol = u.hasUpdate ? import_picocolors23.default.yellow(`Update available${u.updateType ? ` [${u.updateType}]` : ""}`) : import_picocolors23.default.green("Up to date");
6406
+ const statusCol = u.hasUpdate ? import_picocolors29.default.yellow(`Update available${u.updateType ? ` [${u.updateType}]` : ""}`) : import_picocolors29.default.green("Up to date");
5311
6407
  console.log(` ${nameCol} ${curCol} ${latCol} ${statusCol}`);
5312
6408
  }
5313
6409
  console.log();
5314
6410
  }
5315
- var update_default = (0, import_citty23.defineCommand)({
6411
+ var update_default = (0, import_citty29.defineCommand)({
5316
6412
  meta: {
5317
6413
  name: "update",
5318
6414
  description: "Check for and apply updates to installed MCP servers"
@@ -5351,7 +6447,7 @@ var update_default = (0, import_citty23.defineCommand)({
5351
6447
  }
5352
6448
  process.exit(1);
5353
6449
  }
5354
- const spinner5 = p12.spinner();
6450
+ const spinner5 = p13.spinner();
5355
6451
  spinner5.start("Checking versions...");
5356
6452
  let updates;
5357
6453
  try {
@@ -5373,51 +6469,51 @@ var update_default = (0, import_citty23.defineCommand)({
5373
6469
  printTable(updates);
5374
6470
  const outdated = updates.filter((u) => u.hasUpdate);
5375
6471
  if (outdated.length === 0) {
5376
- console.log(import_picocolors23.default.green(" All servers are up to date."));
6472
+ console.log(import_picocolors29.default.green(" All servers are up to date."));
5377
6473
  return;
5378
6474
  }
5379
6475
  if (args.check) {
5380
6476
  console.log(
5381
- import_picocolors23.default.yellow(` ${outdated.length} update(s) available. Run mcpman update to apply.`)
6477
+ import_picocolors29.default.yellow(` ${outdated.length} update(s) available. Run mcpman update to apply.`)
5382
6478
  );
5383
6479
  return;
5384
6480
  }
5385
6481
  if (!args.yes) {
5386
- const confirmed = await p12.confirm({
6482
+ const confirmed = await p13.confirm({
5387
6483
  message: `Apply ${outdated.length} update(s)?`,
5388
6484
  initialValue: true
5389
6485
  });
5390
- if (p12.isCancel(confirmed) || !confirmed) {
5391
- p12.outro("Cancelled.");
6486
+ if (p13.isCancel(confirmed) || !confirmed) {
6487
+ p13.outro("Cancelled.");
5392
6488
  return;
5393
6489
  }
5394
6490
  }
5395
6491
  const clients = await loadClients3();
5396
6492
  let successCount = 0;
5397
6493
  for (const update of outdated) {
5398
- const s = p12.spinner();
6494
+ const s = p13.spinner();
5399
6495
  s.start(`Updating ${update.server}...`);
5400
6496
  const result = await applyServerUpdate(update.server, servers[update.server], clients);
5401
6497
  if (result.success) {
5402
- s.stop(`${import_picocolors23.default.green("\u2713")} ${update.server}: ${result.fromVersion} \u2192 ${result.toVersion}`);
6498
+ s.stop(`${import_picocolors29.default.green("\u2713")} ${update.server}: ${result.fromVersion} \u2192 ${result.toVersion}`);
5403
6499
  successCount++;
5404
6500
  } else {
5405
- s.stop(`${import_picocolors23.default.red("\u2717")} ${update.server}: ${result.error}`);
6501
+ s.stop(`${import_picocolors29.default.red("\u2717")} ${update.server}: ${result.error}`);
5406
6502
  }
5407
6503
  }
5408
6504
  const freshLockfile = readLockfile(resolveLockfilePath());
5409
6505
  const freshUpdates = await checkAllVersions(freshLockfile);
5410
6506
  writeUpdateCache({ lastCheck: (/* @__PURE__ */ new Date()).toISOString(), updates: freshUpdates });
5411
- p12.outro(`${successCount} of ${outdated.length} server(s) updated.`);
6507
+ p13.outro(`${successCount} of ${outdated.length} server(s) updated.`);
5412
6508
  }
5413
6509
  });
5414
6510
 
5415
6511
  // src/commands/upgrade.ts
5416
6512
  init_cjs_shims();
5417
- var import_node_child_process7 = require("child_process");
5418
- var import_citty24 = require("citty");
5419
- var import_picocolors24 = __toESM(require("picocolors"), 1);
5420
- var upgrade_default = (0, import_citty24.defineCommand)({
6513
+ var import_node_child_process9 = require("child_process");
6514
+ var import_citty30 = require("citty");
6515
+ var import_picocolors30 = __toESM(require("picocolors"), 1);
6516
+ var upgrade_default = (0, import_citty30.defineCommand)({
5421
6517
  meta: {
5422
6518
  name: "upgrade",
5423
6519
  description: "Upgrade mcpman to the latest version"
@@ -5430,30 +6526,30 @@ var upgrade_default = (0, import_citty24.defineCommand)({
5430
6526
  }
5431
6527
  },
5432
6528
  async run({ args }) {
5433
- console.log(import_picocolors24.default.dim(` Current version: ${APP_VERSION}`));
6529
+ console.log(import_picocolors30.default.dim(` Current version: ${APP_VERSION}`));
5434
6530
  let latest;
5435
6531
  try {
5436
- latest = (0, import_node_child_process7.execSync)("npm view mcpman version", { encoding: "utf-8", timeout: 15e3 }).trim();
6532
+ latest = (0, import_node_child_process9.execSync)("npm view mcpman version", { encoding: "utf-8", timeout: 15e3 }).trim();
5437
6533
  } catch {
5438
- console.error(import_picocolors24.default.red(" Error: Could not check latest version from npm."));
6534
+ console.error(import_picocolors30.default.red(" Error: Could not check latest version from npm."));
5439
6535
  process.exit(1);
5440
6536
  }
5441
6537
  if (latest === APP_VERSION) {
5442
- console.log(import_picocolors24.default.green(" \u2713 Already on the latest version."));
6538
+ console.log(import_picocolors30.default.green(" \u2713 Already on the latest version."));
5443
6539
  return;
5444
6540
  }
5445
- console.log(import_picocolors24.default.yellow(` Update available: ${APP_VERSION} \u2192 ${latest}`));
6541
+ console.log(import_picocolors30.default.yellow(` Update available: ${APP_VERSION} \u2192 ${latest}`));
5446
6542
  if (args.check) {
5447
- console.log(import_picocolors24.default.dim(" Run mcpman upgrade to install."));
6543
+ console.log(import_picocolors30.default.dim(" Run mcpman upgrade to install."));
5448
6544
  return;
5449
6545
  }
5450
- console.log(import_picocolors24.default.dim(" Installing..."));
6546
+ console.log(import_picocolors30.default.dim(" Installing..."));
5451
6547
  try {
5452
- (0, import_node_child_process7.execSync)(`npm install -g mcpman@${latest}`, { stdio: "inherit", timeout: 6e4 });
5453
- console.log(import_picocolors24.default.green(`
6548
+ (0, import_node_child_process9.execSync)(`npm install -g mcpman@${latest}`, { stdio: "inherit", timeout: 6e4 });
6549
+ console.log(import_picocolors30.default.green(`
5454
6550
  \u2713 Upgraded to mcpman@${latest}`));
5455
6551
  } catch {
5456
- console.error(import_picocolors24.default.red(" Error: Upgrade failed. Try manually: npm install -g mcpman@latest"));
6552
+ console.error(import_picocolors30.default.red(" Error: Upgrade failed. Try manually: npm install -g mcpman@latest"));
5457
6553
  process.exit(1);
5458
6554
  }
5459
6555
  }
@@ -5461,13 +6557,13 @@ var upgrade_default = (0, import_citty24.defineCommand)({
5461
6557
 
5462
6558
  // src/commands/watch.ts
5463
6559
  init_cjs_shims();
5464
- var import_citty25 = require("citty");
5465
- var import_picocolors25 = __toESM(require("picocolors"), 1);
6560
+ var import_citty31 = require("citty");
6561
+ var import_picocolors31 = __toESM(require("picocolors"), 1);
5466
6562
 
5467
6563
  // src/core/file-watcher-service.ts
5468
6564
  init_cjs_shims();
5469
- var import_node_child_process8 = require("child_process");
5470
- var import_node_fs15 = __toESM(require("fs"), 1);
6565
+ var import_node_child_process10 = require("child_process");
6566
+ var import_node_fs19 = __toESM(require("fs"), 1);
5471
6567
  var IGNORE_PATTERNS = [
5472
6568
  "node_modules",
5473
6569
  ".git",
@@ -5479,7 +6575,7 @@ var IGNORE_PATTERNS = [
5479
6575
  ".tox"
5480
6576
  ];
5481
6577
  function shouldIgnore(filename) {
5482
- return IGNORE_PATTERNS.some((p13) => filename.includes(p13));
6578
+ return IGNORE_PATTERNS.some((p14) => filename.includes(p14));
5483
6579
  }
5484
6580
  function hasWatchedExtension(filename, extensions) {
5485
6581
  return extensions.some((ext) => filename.endsWith(`.${ext}`));
@@ -5505,7 +6601,7 @@ var ServerWatcher = class {
5505
6601
  `);
5506
6602
  this.spawnChild();
5507
6603
  try {
5508
- this.watcher = import_node_fs15.default.watch(options.watchDir, { recursive: true }, (_event, filename) => {
6604
+ this.watcher = import_node_fs19.default.watch(options.watchDir, { recursive: true }, (_event, filename) => {
5509
6605
  if (!filename) return;
5510
6606
  this.onFileChange(filename);
5511
6607
  });
@@ -5540,7 +6636,7 @@ var ServerWatcher = class {
5540
6636
  process.stdout.write("\x1Bc");
5541
6637
  }
5542
6638
  console.log(` [${timestamp()}] Starting ${serverName}...`);
5543
- this.child = (0, import_node_child_process8.spawn)(command, args, { env, stdio: ["pipe", "pipe", "pipe"] });
6639
+ this.child = (0, import_node_child_process10.spawn)(command, args, { env, stdio: ["pipe", "pipe", "pipe"] });
5544
6640
  this.child.stdout?.on("data", (data) => {
5545
6641
  process.stdout.write(` [stdout] ${data.toString().trimEnd()}
5546
6642
  `);
@@ -5606,7 +6702,7 @@ init_lockfile();
5606
6702
  init_vault_service();
5607
6703
  var DEFAULT_EXTENSIONS = ["ts", "js", "json", "py", "mjs", "cjs"];
5608
6704
  var DEFAULT_DEBOUNCE_MS = 300;
5609
- var watch_default = (0, import_citty25.defineCommand)({
6705
+ var watch_default = (0, import_citty31.defineCommand)({
5610
6706
  meta: {
5611
6707
  name: "watch",
5612
6708
  description: "Watch a local MCP server for file changes and auto-restart"
@@ -5645,8 +6741,8 @@ var watch_default = (0, import_citty25.defineCommand)({
5645
6741
  const lockfile = readLockfile();
5646
6742
  const entry = lockfile.servers[serverName];
5647
6743
  if (!entry) {
5648
- console.error(import_picocolors25.default.red(` Error: Server '${serverName}' not found in lockfile.`));
5649
- console.error(import_picocolors25.default.dim(` Run ${import_picocolors25.default.cyan("mcpman link .")} to register a local server.`));
6744
+ console.error(import_picocolors31.default.red(` Error: Server '${serverName}' not found in lockfile.`));
6745
+ console.error(import_picocolors31.default.dim(` Run ${import_picocolors31.default.cyan("mcpman link .")} to register a local server.`));
5650
6746
  process.exit(1);
5651
6747
  }
5652
6748
  let watchDir = args.dir;
@@ -5654,8 +6750,8 @@ var watch_default = (0, import_citty25.defineCommand)({
5654
6750
  if (entry.source === "local" && entry.resolved) {
5655
6751
  watchDir = entry.resolved;
5656
6752
  } else {
5657
- console.error(import_picocolors25.default.red(` Error: Cannot determine watch directory for '${serverName}'.`));
5658
- console.error(import_picocolors25.default.dim(" Use --dir to specify the directory to watch."));
6753
+ console.error(import_picocolors31.default.red(` Error: Cannot determine watch directory for '${serverName}'.`));
6754
+ console.error(import_picocolors31.default.dim(" Use --dir to specify the directory to watch."));
5659
6755
  process.exit(1);
5660
6756
  }
5661
6757
  }
@@ -5702,13 +6798,13 @@ async function loadVaultSecrets4(serverName) {
5702
6798
 
5703
6799
  // src/commands/why.ts
5704
6800
  init_cjs_shims();
5705
- var import_citty26 = require("citty");
5706
- var import_picocolors26 = __toESM(require("picocolors"), 1);
6801
+ var import_citty32 = require("citty");
6802
+ var import_picocolors32 = __toESM(require("picocolors"), 1);
5707
6803
 
5708
6804
  // src/core/why-service.ts
5709
6805
  init_cjs_shims();
5710
- var import_node_fs16 = __toESM(require("fs"), 1);
5711
- var import_node_path18 = __toESM(require("path"), 1);
6806
+ var import_node_fs20 = __toESM(require("fs"), 1);
6807
+ var import_node_path20 = __toESM(require("path"), 1);
5712
6808
  init_paths();
5713
6809
  init_lockfile();
5714
6810
  var ALL_CLIENT_TYPES = ["claude-desktop", "cursor", "vscode", "windsurf"];
@@ -5770,16 +6866,16 @@ async function findOrphanedClients(serverName) {
5770
6866
  }
5771
6867
  function scanProfiles(serverName, profilesDir) {
5772
6868
  const found = [];
5773
- if (!import_node_fs16.default.existsSync(profilesDir)) return found;
6869
+ if (!import_node_fs20.default.existsSync(profilesDir)) return found;
5774
6870
  let files;
5775
6871
  try {
5776
- files = import_node_fs16.default.readdirSync(profilesDir).filter((f) => f.endsWith(".json"));
6872
+ files = import_node_fs20.default.readdirSync(profilesDir).filter((f) => f.endsWith(".json"));
5777
6873
  } catch {
5778
6874
  return found;
5779
6875
  }
5780
6876
  for (const file of files) {
5781
6877
  try {
5782
- const raw = import_node_fs16.default.readFileSync(import_node_path18.default.join(profilesDir, file), "utf-8");
6878
+ const raw = import_node_fs20.default.readFileSync(import_node_path20.default.join(profilesDir, file), "utf-8");
5783
6879
  const profile = JSON.parse(raw);
5784
6880
  if (serverName in (profile.servers ?? {})) {
5785
6881
  found.push(profile.name ?? file.replace(".json", ""));
@@ -5808,8 +6904,8 @@ function formatWhyOutput(result) {
5808
6904
  if (result.profiles.length > 0) {
5809
6905
  lines.push("");
5810
6906
  lines.push(" Profiles:");
5811
- for (const p13 of result.profiles) {
5812
- lines.push(` ${p13}`);
6907
+ for (const p14 of result.profiles) {
6908
+ lines.push(` ${p14}`);
5813
6909
  }
5814
6910
  }
5815
6911
  if (result.envVars.length > 0) {
@@ -5823,7 +6919,7 @@ function formatWhyOutput(result) {
5823
6919
  }
5824
6920
 
5825
6921
  // src/commands/why.ts
5826
- var why_default = (0, import_citty26.defineCommand)({
6922
+ var why_default = (0, import_citty32.defineCommand)({
5827
6923
  meta: {
5828
6924
  name: "why",
5829
6925
  description: "Show why a server is installed (provenance, clients, profiles)"
@@ -5845,15 +6941,15 @@ var why_default = (0, import_citty26.defineCommand)({
5845
6941
  const asJson = args.json;
5846
6942
  const result = await getServerProvenance(serverName);
5847
6943
  if (!result) {
5848
- console.error(import_picocolors26.default.red(` Server '${serverName}' not found in lockfile or any client config.`));
5849
- console.error(import_picocolors26.default.dim(` Run ${import_picocolors26.default.cyan("mcpman list")} to see installed servers.`));
6944
+ console.error(import_picocolors32.default.red(` Server '${serverName}' not found in lockfile or any client config.`));
6945
+ console.error(import_picocolors32.default.dim(` Run ${import_picocolors32.default.cyan("mcpman list")} to see installed servers.`));
5850
6946
  process.exit(1);
5851
6947
  }
5852
6948
  if (result.orphaned) {
5853
- console.log(import_picocolors26.default.yellow(`
6949
+ console.log(import_picocolors32.default.yellow(`
5854
6950
  Server '${serverName}' is orphaned:`));
5855
- console.log(import_picocolors26.default.dim(" Found in client config(s) but not in lockfile."));
5856
- console.log(import_picocolors26.default.dim(` Run ${import_picocolors26.default.cyan("mcpman sync --remove")} to clean up.
6951
+ console.log(import_picocolors32.default.dim(" Found in client config(s) but not in lockfile."));
6952
+ console.log(import_picocolors32.default.dim(` Run ${import_picocolors32.default.cyan("mcpman sync --remove")} to clean up.
5857
6953
  `));
5858
6954
  const registeredClients = result.clients.filter((c) => c.registered).map((c) => c.type);
5859
6955
  if (registeredClients.length > 0) {
@@ -5876,7 +6972,7 @@ process.on("SIGINT", () => {
5876
6972
  console.log("\nAborted.");
5877
6973
  process.exit(130);
5878
6974
  });
5879
- var main = (0, import_citty27.defineCommand)({
6975
+ var main = (0, import_citty33.defineCommand)({
5880
6976
  meta: {
5881
6977
  name: APP_NAME,
5882
6978
  version: APP_VERSION,
@@ -5908,7 +7004,13 @@ var main = (0, import_citty27.defineCommand)({
5908
7004
  watch: watch_default,
5909
7005
  registry: registry_default,
5910
7006
  completions: completions_default,
5911
- why: why_default
7007
+ why: why_default,
7008
+ env: env_default,
7009
+ bench: bench_default,
7010
+ diff: diff_default,
7011
+ group: group_default,
7012
+ pin: pin_default,
7013
+ rollback: rollback_default
5912
7014
  }
5913
7015
  });
5914
- (0, import_citty27.runMain)(main);
7016
+ (0, import_citty33.runMain)(main);