mcpman 0.3.0 → 0.4.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.js CHANGED
@@ -1,7 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ computeTrustScore
4
+ } from "./chunk-RGKHLY5G.js";
5
+ import {
6
+ getConfigPath,
3
7
  getInstalledClients
4
- } from "./chunk-QY22QTBR.js";
8
+ } from "./chunk-RMMEBP2J.js";
5
9
  import {
6
10
  getMasterPassword,
7
11
  getSecretsForServer,
@@ -11,7 +15,7 @@ import {
11
15
  } from "./chunk-6X6Q6UZC.js";
12
16
 
13
17
  // src/index.ts
14
- import { defineCommand as defineCommand10, runMain } from "citty";
18
+ import { defineCommand as defineCommand14, runMain } from "citty";
15
19
 
16
20
  // src/commands/audit.ts
17
21
  import { defineCommand } from "citty";
@@ -193,8 +197,8 @@ async function scanServer(name, entry) {
193
197
  fetchNpmMetadata(name),
194
198
  fetchVulnerabilities(name, entry.version)
195
199
  ]);
196
- const { computeTrustScore } = await import("./trust-scorer-LYC6KZCD.js");
197
- const { score, riskLevel } = computeTrustScore(metadata, vulnerabilities);
200
+ const { computeTrustScore: computeTrustScore2 } = await import("./trust-scorer-G74WK25Q.js");
201
+ const { score, riskLevel } = computeTrustScore2(metadata, vulnerabilities);
198
202
  const report = {
199
203
  server: name,
200
204
  source: "npm",
@@ -211,11 +215,11 @@ async function scanAllServers(servers, concurrency = 3) {
211
215
  const results = [];
212
216
  const executing = /* @__PURE__ */ new Set();
213
217
  for (const [name, entry] of entries) {
214
- const p10 = scanServer(name, entry).then((r) => {
218
+ const p11 = scanServer(name, entry).then((r) => {
215
219
  results.push(r);
216
- executing.delete(p10);
220
+ executing.delete(p11);
217
221
  });
218
- executing.add(p10);
222
+ executing.add(p11);
219
223
  if (executing.size >= concurrency) await Promise.race(executing);
220
224
  }
221
225
  await Promise.all(executing);
@@ -329,11 +333,11 @@ async function checkAllVersions(lockfile) {
329
333
  const results = [];
330
334
  const executing = /* @__PURE__ */ new Set();
331
335
  for (const [name, entry] of entries) {
332
- const p10 = checkVersion(name, entry).then((r) => {
336
+ const p11 = checkVersion(name, entry).then((r) => {
333
337
  results.push(r);
334
- executing.delete(p10);
338
+ executing.delete(p11);
335
339
  });
336
- executing.add(p10);
340
+ executing.add(p11);
337
341
  if (executing.size >= 5) {
338
342
  await Promise.race(executing);
339
343
  }
@@ -671,7 +675,7 @@ var audit_default = defineCommand({
671
675
  });
672
676
  async function loadClients() {
673
677
  try {
674
- const mod = await import("./client-detector-SUIJSIYM.js");
678
+ const mod = await import("./client-detector-UAP2EYZA.js");
675
679
  return mod.getInstalledClients();
676
680
  } catch {
677
681
  return [];
@@ -770,9 +774,156 @@ async function runAuditFix(reports, servers, skipConfirm) {
770
774
  `);
771
775
  }
772
776
 
773
- // src/commands/doctor.ts
777
+ // src/commands/config.ts
774
778
  import { defineCommand as defineCommand2 } from "citty";
775
779
  import pc2 from "picocolors";
780
+ import * as p2 from "@clack/prompts";
781
+
782
+ // src/core/config-service.ts
783
+ import fs3 from "fs";
784
+ import path3 from "path";
785
+ var VALID_KEYS = /* @__PURE__ */ new Set([
786
+ "defaultClient",
787
+ "updateCheckInterval",
788
+ "preferredRegistry",
789
+ "vaultTimeout"
790
+ ]);
791
+ function readConfig(configPath = getConfigPath()) {
792
+ try {
793
+ const raw = fs3.readFileSync(configPath, "utf-8");
794
+ const parsed = JSON.parse(raw);
795
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
796
+ return {};
797
+ }
798
+ return parsed;
799
+ } catch {
800
+ return {};
801
+ }
802
+ }
803
+ function writeConfig(data, configPath = getConfigPath()) {
804
+ const dir = path3.dirname(configPath);
805
+ fs3.mkdirSync(dir, { recursive: true });
806
+ const tmp = `${configPath}.tmp`;
807
+ fs3.writeFileSync(tmp, JSON.stringify(data, null, 2), { encoding: "utf-8" });
808
+ fs3.renameSync(tmp, configPath);
809
+ }
810
+ function getConfigValue(key, configPath = getConfigPath()) {
811
+ const data = readConfig(configPath);
812
+ if (!VALID_KEYS.has(key)) return void 0;
813
+ return data[key];
814
+ }
815
+ function setConfigValue(key, value, configPath = getConfigPath()) {
816
+ const data = readConfig(configPath);
817
+ if (!VALID_KEYS.has(key)) {
818
+ throw new Error(`Unknown config key: "${key}". Valid keys: ${[...VALID_KEYS].join(", ")}`);
819
+ }
820
+ data[key] = value;
821
+ writeConfig(data, configPath);
822
+ }
823
+
824
+ // src/commands/config.ts
825
+ function coerceValue(raw) {
826
+ if (raw === "true") return true;
827
+ if (raw === "false") return false;
828
+ const num = Number(raw);
829
+ if (!Number.isNaN(num) && raw.trim() !== "") return num;
830
+ return raw;
831
+ }
832
+ var setCommand = defineCommand2({
833
+ meta: { name: "set", description: "Set a config value" },
834
+ args: {
835
+ key: {
836
+ type: "positional",
837
+ description: "Config key (e.g. defaultClient)",
838
+ required: true
839
+ },
840
+ value: {
841
+ type: "positional",
842
+ description: "Value to set",
843
+ required: true
844
+ }
845
+ },
846
+ run({ args }) {
847
+ try {
848
+ const coerced = coerceValue(args.value);
849
+ setConfigValue(args.key, coerced);
850
+ console.log(
851
+ `${pc2.green("\u2713")} Set ${pc2.bold(args.key)} = ${pc2.cyan(String(coerced))}`
852
+ );
853
+ } catch (err) {
854
+ console.error(`${pc2.red("\u2717")} ${String(err)}`);
855
+ process.exit(1);
856
+ }
857
+ }
858
+ });
859
+ var getCommand = defineCommand2({
860
+ meta: { name: "get", description: "Get a config value" },
861
+ args: {
862
+ key: {
863
+ type: "positional",
864
+ description: "Config key to read",
865
+ required: true
866
+ }
867
+ },
868
+ run({ args }) {
869
+ const val = getConfigValue(args.key);
870
+ if (val === void 0) {
871
+ console.log(pc2.dim(`${args.key}: (not set)`));
872
+ } else {
873
+ console.log(`${pc2.bold(args.key)}: ${pc2.cyan(String(val))}`);
874
+ }
875
+ }
876
+ });
877
+ var listCommand = defineCommand2({
878
+ meta: { name: "list", description: "List all config values" },
879
+ run() {
880
+ const data = readConfig();
881
+ const entries = Object.entries(data);
882
+ if (entries.length === 0) {
883
+ console.log(pc2.dim("No config values set. Use `mcpman config set <key> <value>`."));
884
+ return;
885
+ }
886
+ console.log("");
887
+ console.log(pc2.bold("mcpman config:"));
888
+ console.log("");
889
+ for (const [key, val] of entries) {
890
+ console.log(` ${pc2.green("\u25CF")} ${pc2.bold(key)} ${pc2.cyan(String(val))}`);
891
+ }
892
+ console.log("");
893
+ console.log(pc2.dim(` ${entries.length} key${entries.length !== 1 ? "s" : ""} configured`));
894
+ }
895
+ });
896
+ var resetCommand = defineCommand2({
897
+ meta: { name: "reset", description: "Reset config to defaults (removes config file)" },
898
+ async run() {
899
+ const confirmed = await p2.confirm({
900
+ message: "Reset all config values to defaults?",
901
+ initialValue: false
902
+ });
903
+ if (p2.isCancel(confirmed) || !confirmed) {
904
+ p2.cancel("Cancelled.");
905
+ return;
906
+ }
907
+ writeConfig({});
908
+ console.log(`${pc2.green("\u2713")} Config reset to defaults.`);
909
+ }
910
+ });
911
+ var config_default = defineCommand2({
912
+ meta: {
913
+ name: "config",
914
+ description: "Manage mcpman CLI configuration"
915
+ },
916
+ subCommands: {
917
+ set: setCommand,
918
+ get: getCommand,
919
+ list: listCommand,
920
+ reset: resetCommand
921
+ }
922
+ });
923
+
924
+ // src/commands/doctor.ts
925
+ import { defineCommand as defineCommand3 } from "citty";
926
+ import pc3 from "picocolors";
776
927
 
777
928
  // src/core/server-inventory.ts
778
929
  async function getInstalledServers(clientFilter) {
@@ -1036,12 +1187,12 @@ async function quickHealthProbe(config, timeoutMs = 3e3) {
1036
1187
 
1037
1188
  // src/commands/doctor.ts
1038
1189
  var CHECK_ICON = {
1039
- pass: pc2.green("\u2713"),
1040
- fail: pc2.red("\u2717"),
1041
- skip: pc2.dim("-"),
1042
- warn: pc2.yellow("\u26A0")
1190
+ pass: pc3.green("\u2713"),
1191
+ fail: pc3.red("\u2717"),
1192
+ skip: pc3.dim("-"),
1193
+ warn: pc3.yellow("\u26A0")
1043
1194
  };
1044
- var doctor_default = defineCommand2({
1195
+ var doctor_default = defineCommand3({
1045
1196
  meta: {
1046
1197
  name: "doctor",
1047
1198
  description: "Check MCP server health and configuration"
@@ -1054,10 +1205,10 @@ var doctor_default = defineCommand2({
1054
1205
  }
1055
1206
  },
1056
1207
  async run({ args }) {
1057
- console.log(pc2.bold("\n mcpman doctor\n"));
1208
+ console.log(pc3.bold("\n mcpman doctor\n"));
1058
1209
  const servers = await getInstalledServers();
1059
1210
  if (servers.length === 0) {
1060
- console.log(pc2.dim(" No MCP servers installed. Run mcpman install <server> to get started."));
1211
+ console.log(pc3.dim(" No MCP servers installed. Run mcpman install <server> to get started."));
1061
1212
  return;
1062
1213
  }
1063
1214
  const tasks = servers.map((s) => () => checkServerHealth(s.name, s.config));
@@ -1069,14 +1220,14 @@ var doctor_default = defineCommand2({
1069
1220
  if (result.status === "healthy") passed++;
1070
1221
  else failed++;
1071
1222
  }
1072
- console.log(pc2.dim(" " + "\u2500".repeat(50)));
1223
+ console.log(pc3.dim(" " + "\u2500".repeat(50)));
1073
1224
  const parts = [];
1074
- if (passed > 0) parts.push(pc2.green(`${passed} healthy`));
1075
- if (failed > 0) parts.push(pc2.red(`${failed} unhealthy`));
1225
+ if (passed > 0) parts.push(pc3.green(`${passed} healthy`));
1226
+ if (failed > 0) parts.push(pc3.red(`${failed} unhealthy`));
1076
1227
  console.log(` Summary: ${parts.join(", ")}`);
1077
1228
  if (failed > 0) {
1078
1229
  if (!args.fix) {
1079
- console.log(pc2.dim(` Run ${pc2.cyan("mcpman doctor --fix")} for fix suggestions.
1230
+ console.log(pc3.dim(` Run ${pc3.cyan("mcpman doctor --fix")} for fix suggestions.
1080
1231
  `));
1081
1232
  }
1082
1233
  process.exit(1);
@@ -1085,13 +1236,13 @@ var doctor_default = defineCommand2({
1085
1236
  }
1086
1237
  });
1087
1238
  function printServerResult(result, showFix) {
1088
- const icon = result.status === "healthy" ? pc2.green("\u25CF") : pc2.red("\u25CF");
1089
- console.log(` ${icon} ${pc2.bold(result.serverName)}`);
1239
+ const icon = result.status === "healthy" ? pc3.green("\u25CF") : pc3.red("\u25CF");
1240
+ console.log(` ${icon} ${pc3.bold(result.serverName)}`);
1090
1241
  for (const check of result.checks) {
1091
1242
  const checkIcon = check.skipped ? CHECK_ICON.skip : check.passed ? CHECK_ICON.pass : CHECK_ICON.fail;
1092
1243
  console.log(` ${checkIcon} ${check.name}: ${check.message}`);
1093
1244
  if (showFix && !check.passed && !check.skipped && check.fix) {
1094
- console.log(` ${pc2.yellow("\u2192")} Fix: ${pc2.cyan(check.fix)}`);
1245
+ console.log(` ${pc3.yellow("\u2192")} Fix: ${pc3.cyan(check.fix)}`);
1095
1246
  }
1096
1247
  }
1097
1248
  console.log();
@@ -1100,11 +1251,11 @@ async function runParallel(tasks, concurrency) {
1100
1251
  const results = [];
1101
1252
  const executing = /* @__PURE__ */ new Set();
1102
1253
  for (const task of tasks) {
1103
- const p10 = task().then((r) => {
1254
+ const p11 = task().then((r) => {
1104
1255
  results.push(r);
1105
- executing.delete(p10);
1256
+ executing.delete(p11);
1106
1257
  });
1107
- executing.add(p10);
1258
+ executing.add(p11);
1108
1259
  if (executing.size >= concurrency) {
1109
1260
  await Promise.race(executing);
1110
1261
  }
@@ -1113,11 +1264,173 @@ async function runParallel(tasks, concurrency) {
1113
1264
  return results;
1114
1265
  }
1115
1266
 
1267
+ // src/commands/info.ts
1268
+ import { defineCommand as defineCommand4 } from "citty";
1269
+ import pc4 from "picocolors";
1270
+ import { createSpinner as createSpinner2 } from "nanospinner";
1271
+
1272
+ // src/core/package-info.ts
1273
+ async function buildInfo(name, entry, source = "npm") {
1274
+ const resolvedSource = entry?.source ?? source;
1275
+ let weeklyDownloads = 0;
1276
+ let maintainerCount = 0;
1277
+ let packageAge = 0;
1278
+ let lastPublish = "";
1279
+ let deprecated = false;
1280
+ let trustScore = null;
1281
+ let riskLevel = "UNKNOWN";
1282
+ if (resolvedSource === "npm") {
1283
+ const metadata = await fetchNpmMetadata(name);
1284
+ if (!metadata && !entry) {
1285
+ return null;
1286
+ }
1287
+ if (metadata) {
1288
+ weeklyDownloads = metadata.weeklyDownloads;
1289
+ maintainerCount = metadata.maintainerCount;
1290
+ packageAge = metadata.packageAge;
1291
+ lastPublish = metadata.lastPublish;
1292
+ deprecated = metadata.deprecated;
1293
+ const scored = computeTrustScore(metadata, []);
1294
+ trustScore = scored.score;
1295
+ riskLevel = scored.riskLevel;
1296
+ }
1297
+ }
1298
+ return {
1299
+ name,
1300
+ version: entry?.version ?? "unknown",
1301
+ description: "",
1302
+ source: resolvedSource,
1303
+ runtime: entry?.runtime ?? "node",
1304
+ envVars: entry?.envVars ?? [],
1305
+ weeklyDownloads,
1306
+ maintainerCount,
1307
+ packageAge,
1308
+ lastPublish,
1309
+ deprecated,
1310
+ trustScore,
1311
+ riskLevel,
1312
+ installedClients: entry?.clients ?? [],
1313
+ isInstalled: entry !== null
1314
+ };
1315
+ }
1316
+ async function getPackageInfo(serverName) {
1317
+ const lockfile = readLockfile();
1318
+ const entry = lockfile.servers[serverName] ?? null;
1319
+ return buildInfo(serverName, entry);
1320
+ }
1321
+
1322
+ // src/commands/info.ts
1323
+ function colorRisk2(score, riskLevel) {
1324
+ const label = score !== null ? `${score}/100 (${riskLevel})` : riskLevel;
1325
+ if (riskLevel === "LOW") return pc4.green(label);
1326
+ if (riskLevel === "MEDIUM") return pc4.yellow(label);
1327
+ if (riskLevel === "HIGH") return pc4.red(label);
1328
+ if (riskLevel === "CRITICAL") return pc4.bold(pc4.red(label));
1329
+ return pc4.dim(label);
1330
+ }
1331
+ function formatDaysAgo(isoDate) {
1332
+ if (!isoDate) return "unknown";
1333
+ const days = Math.floor((Date.now() - new Date(isoDate).getTime()) / 864e5);
1334
+ if (days === 0) return "today";
1335
+ if (days === 1) return "1 day ago";
1336
+ return `${days} days ago`;
1337
+ }
1338
+ function printInfo(info2) {
1339
+ const installedBadge = info2.isInstalled ? pc4.green(" [installed]") : pc4.dim(" [not installed]");
1340
+ console.log();
1341
+ console.log(pc4.bold(` ${info2.name}@${info2.version}`) + installedBadge);
1342
+ console.log(pc4.dim(" " + "\u2500".repeat(60)));
1343
+ console.log(` ${pc4.dim("Source:")} ${info2.source}`);
1344
+ console.log(` ${pc4.dim("Runtime:")} ${info2.runtime}`);
1345
+ if (info2.description) {
1346
+ console.log(` ${pc4.dim("Description:")} ${info2.description}`);
1347
+ }
1348
+ if (info2.deprecated) {
1349
+ console.log(` ${pc4.red("[DEPRECATED]")} This package is deprecated`);
1350
+ }
1351
+ console.log();
1352
+ console.log(` ${pc4.bold("Trust & Security")}`);
1353
+ console.log(` ${pc4.dim("Trust score:")} ${colorRisk2(info2.trustScore, info2.riskLevel)}`);
1354
+ if (info2.source === "npm") {
1355
+ console.log(
1356
+ ` ${pc4.dim("Downloads:")} ${info2.weeklyDownloads.toLocaleString()}/week ${pc4.dim("|")} ${pc4.dim("Age:")} ${info2.packageAge}d ${pc4.dim("|")} ${pc4.dim("Maintainers:")} ${info2.maintainerCount}`
1357
+ );
1358
+ if (info2.lastPublish) {
1359
+ console.log(` ${pc4.dim("Last publish:")} ${formatDaysAgo(info2.lastPublish)}`);
1360
+ }
1361
+ } else {
1362
+ console.log(pc4.dim(" (Trust data available for npm packages only)"));
1363
+ }
1364
+ console.log();
1365
+ console.log(` ${pc4.bold("Environment Variables")}`);
1366
+ if (info2.envVars.length > 0) {
1367
+ for (const env of info2.envVars) {
1368
+ console.log(` ${pc4.cyan("\u2022")} ${env}`);
1369
+ }
1370
+ } else {
1371
+ console.log(pc4.dim(" none required"));
1372
+ }
1373
+ console.log();
1374
+ console.log(` ${pc4.bold("Installed Clients")}`);
1375
+ if (info2.installedClients.length > 0) {
1376
+ for (const client of info2.installedClients) {
1377
+ console.log(` ${pc4.green("\u2713")} ${client}`);
1378
+ }
1379
+ } else {
1380
+ console.log(pc4.dim(" Not installed in any client"));
1381
+ }
1382
+ console.log();
1383
+ console.log(pc4.dim(" " + "\u2500".repeat(60)));
1384
+ console.log();
1385
+ }
1386
+ var info_default = defineCommand4({
1387
+ meta: {
1388
+ name: "info",
1389
+ description: "Show detailed metadata for an MCP server (installed or from registry)"
1390
+ },
1391
+ args: {
1392
+ server: {
1393
+ type: "positional",
1394
+ description: "Server name (e.g. @modelcontextprotocol/server-filesystem)",
1395
+ required: true
1396
+ },
1397
+ json: {
1398
+ type: "boolean",
1399
+ description: "Output results as JSON",
1400
+ default: false
1401
+ }
1402
+ },
1403
+ async run({ args }) {
1404
+ const spinner5 = createSpinner2(`Fetching info for ${args.server}...`).start();
1405
+ let info2;
1406
+ try {
1407
+ info2 = await getPackageInfo(args.server);
1408
+ } catch (err) {
1409
+ spinner5.error({ text: "Failed to fetch package info" });
1410
+ console.error(pc4.red(String(err)));
1411
+ process.exit(1);
1412
+ }
1413
+ if (!info2) {
1414
+ spinner5.error({ text: `Package not found: ${args.server}` });
1415
+ console.log(pc4.dim(`
1416
+ "${args.server}" was not found in the npm registry or your lockfile.
1417
+ `));
1418
+ process.exit(1);
1419
+ }
1420
+ spinner5.success({ text: `Found ${args.server}` });
1421
+ if (args.json) {
1422
+ console.log(JSON.stringify(info2, null, 2));
1423
+ return;
1424
+ }
1425
+ printInfo(info2);
1426
+ }
1427
+ });
1428
+
1116
1429
  // src/commands/init.ts
1117
- import { defineCommand as defineCommand3 } from "citty";
1118
- import * as p2 from "@clack/prompts";
1119
- import path3 from "path";
1120
- var init_default = defineCommand3({
1430
+ import { defineCommand as defineCommand5 } from "citty";
1431
+ import * as p3 from "@clack/prompts";
1432
+ import path4 from "path";
1433
+ var init_default = defineCommand5({
1121
1434
  meta: {
1122
1435
  name: "init",
1123
1436
  description: "Initialize mcpman.lock in the current project"
@@ -1132,27 +1445,27 @@ var init_default = defineCommand3({
1132
1445
  },
1133
1446
  async run({ args }) {
1134
1447
  const nonInteractive = args.yes || !process.stdout.isTTY;
1135
- p2.intro("mcpman init");
1136
- const targetPath = path3.join(process.cwd(), LOCKFILE_NAME);
1448
+ p3.intro("mcpman init");
1449
+ const targetPath = path4.join(process.cwd(), LOCKFILE_NAME);
1137
1450
  const existing = findLockfile();
1138
1451
  if (existing) {
1139
1452
  if (nonInteractive) {
1140
- p2.log.warn(`Lockfile already exists: ${existing} \u2014 overwriting (non-interactive).`);
1453
+ p3.log.warn(`Lockfile already exists: ${existing} \u2014 overwriting (non-interactive).`);
1141
1454
  } else {
1142
- p2.log.warn(`Lockfile already exists: ${existing}`);
1143
- const overwrite = await p2.confirm({ message: "Overwrite?" });
1144
- if (p2.isCancel(overwrite) || !overwrite) {
1145
- p2.outro("Cancelled.");
1455
+ p3.log.warn(`Lockfile already exists: ${existing}`);
1456
+ const overwrite = await p3.confirm({ message: "Overwrite?" });
1457
+ if (p3.isCancel(overwrite) || !overwrite) {
1458
+ p3.outro("Cancelled.");
1146
1459
  return;
1147
1460
  }
1148
1461
  }
1149
1462
  }
1150
1463
  let clients = [];
1151
1464
  try {
1152
- const mod = await import("./client-detector-SUIJSIYM.js");
1465
+ const mod = await import("./client-detector-UAP2EYZA.js");
1153
1466
  clients = await mod.getInstalledClients();
1154
1467
  } catch {
1155
- p2.log.warn("Could not detect AI clients \u2014 creating empty lockfile.");
1468
+ p3.log.warn("Could not detect AI clients \u2014 creating empty lockfile.");
1156
1469
  }
1157
1470
  const clientServers = [];
1158
1471
  for (const client of clients) {
@@ -1166,26 +1479,26 @@ var init_default = defineCommand3({
1166
1479
  }
1167
1480
  createEmptyLockfile(targetPath);
1168
1481
  if (clientServers.length === 0) {
1169
- p2.log.info("No existing servers found in any client config.");
1170
- p2.outro(`Created ${LOCKFILE_NAME} \u2014 add it to version control!`);
1482
+ p3.log.info("No existing servers found in any client config.");
1483
+ p3.outro(`Created ${LOCKFILE_NAME} \u2014 add it to version control!`);
1171
1484
  return;
1172
1485
  }
1173
1486
  let selected;
1174
1487
  if (nonInteractive) {
1175
1488
  selected = clientServers.map((cs) => cs.client.type);
1176
- p2.log.info(`Non-interactive mode: importing all ${clientServers.length} client(s).`);
1489
+ p3.log.info(`Non-interactive mode: importing all ${clientServers.length} client(s).`);
1177
1490
  } else {
1178
1491
  const options = clientServers.map((cs) => ({
1179
1492
  value: cs.client.type,
1180
1493
  label: `${cs.client.displayName} (${Object.keys(cs.servers).length} servers)`
1181
1494
  }));
1182
- const toImport = await p2.multiselect({
1495
+ const toImport = await p3.multiselect({
1183
1496
  message: "Import existing servers into lockfile?",
1184
1497
  options,
1185
1498
  required: false
1186
1499
  });
1187
- if (p2.isCancel(toImport)) {
1188
- p2.outro(`Created empty ${LOCKFILE_NAME}`);
1500
+ if (p3.isCancel(toImport)) {
1501
+ p3.outro(`Created empty ${LOCKFILE_NAME}`);
1189
1502
  return;
1190
1503
  }
1191
1504
  selected = toImport;
@@ -1211,20 +1524,20 @@ var init_default = defineCommand3({
1211
1524
  importCount++;
1212
1525
  }
1213
1526
  }
1214
- p2.outro(
1527
+ p3.outro(
1215
1528
  `Created ${LOCKFILE_NAME} with ${importCount} server(s) \u2014 commit to version control!`
1216
1529
  );
1217
1530
  }
1218
1531
  });
1219
1532
 
1220
1533
  // src/commands/install.ts
1221
- import { defineCommand as defineCommand4 } from "citty";
1534
+ import { defineCommand as defineCommand6 } from "citty";
1222
1535
 
1223
1536
  // src/core/installer.ts
1224
- import * as p4 from "@clack/prompts";
1537
+ import * as p5 from "@clack/prompts";
1225
1538
 
1226
1539
  // src/core/installer-vault-helpers.ts
1227
- import * as p3 from "@clack/prompts";
1540
+ import * as p4 from "@clack/prompts";
1228
1541
  async function tryLoadVaultSecrets(serverName) {
1229
1542
  try {
1230
1543
  const entries = listSecrets(serverName);
@@ -1241,67 +1554,67 @@ async function offerVaultSave(serverName, newVars, yes) {
1241
1554
  if (Object.keys(newVars).length === 0) return;
1242
1555
  if (yes) return;
1243
1556
  try {
1244
- const save = await p3.confirm({
1557
+ const save = await p4.confirm({
1245
1558
  message: `Save ${Object.keys(newVars).length} env var(s) to encrypted vault for future installs?`
1246
1559
  });
1247
- if (p3.isCancel(save) || !save) return;
1560
+ if (p4.isCancel(save) || !save) return;
1248
1561
  const password = await getMasterPassword();
1249
1562
  for (const [key, value] of Object.entries(newVars)) {
1250
1563
  setSecret(serverName, key, value, password);
1251
1564
  }
1252
- p3.log.success(`Credentials saved to vault for '${serverName}'`);
1565
+ p4.log.success(`Credentials saved to vault for '${serverName}'`);
1253
1566
  } catch (err) {
1254
- p3.log.warn(`Could not save to vault: ${err instanceof Error ? err.message : String(err)}`);
1567
+ p4.log.warn(`Could not save to vault: ${err instanceof Error ? err.message : String(err)}`);
1255
1568
  }
1256
1569
  }
1257
1570
 
1258
1571
  // src/core/installer.ts
1259
1572
  async function loadClients2() {
1260
1573
  try {
1261
- const mod = await import("./client-detector-SUIJSIYM.js");
1574
+ const mod = await import("./client-detector-UAP2EYZA.js");
1262
1575
  return mod.getInstalledClients();
1263
1576
  } catch {
1264
1577
  return [];
1265
1578
  }
1266
1579
  }
1267
1580
  async function installServer(input, options = {}) {
1268
- p4.intro("mcpman install");
1269
- const spinner5 = p4.spinner();
1581
+ p5.intro("mcpman install");
1582
+ const spinner5 = p5.spinner();
1270
1583
  spinner5.start("Resolving server...");
1271
1584
  let metadata;
1272
1585
  try {
1273
1586
  metadata = await resolveServer(input);
1274
1587
  } catch (err) {
1275
1588
  spinner5.stop("Resolution failed");
1276
- p4.log.error(err instanceof Error ? err.message : String(err));
1589
+ p5.log.error(err instanceof Error ? err.message : String(err));
1277
1590
  process.exit(1);
1278
1591
  }
1279
1592
  spinner5.stop(`Found: ${metadata.name}@${metadata.version}`);
1280
1593
  const clients = await loadClients2();
1281
1594
  if (clients.length === 0) {
1282
- p4.log.warn("No supported AI clients detected on this machine.");
1283
- p4.log.info("Supported: Claude Desktop, Cursor, VS Code, Windsurf");
1595
+ p5.log.warn("No supported AI clients detected on this machine.");
1596
+ p5.log.info("Supported: Claude Desktop, Cursor, VS Code, Windsurf");
1284
1597
  process.exit(1);
1285
1598
  }
1286
1599
  let selectedClients;
1287
1600
  if (options.client) {
1288
1601
  const found = clients.find((c) => c.type === options.client || c.displayName.toLowerCase() === options.client?.toLowerCase());
1289
1602
  if (!found) {
1290
- p4.log.error(`Client '${options.client}' not found or not installed.`);
1291
- p4.log.info(`Available: ${clients.map((c) => c.type).join(", ")}`);
1603
+ p5.log.error(`Client '${options.client}' not found or not installed.`);
1604
+ p5.log.info(`Available: ${clients.map((c) => c.type).join(", ")}`);
1292
1605
  process.exit(1);
1293
1606
  }
1294
1607
  selectedClients = [found];
1295
1608
  } else if (options.yes || clients.length === 1) {
1296
1609
  selectedClients = clients;
1297
1610
  } else {
1298
- const chosen = await p4.multiselect({
1611
+ const chosen = await p5.multiselect({
1299
1612
  message: "Install to which client(s)?",
1300
1613
  options: clients.map((c) => ({ value: c.type, label: c.displayName })),
1301
1614
  required: true
1302
1615
  });
1303
- if (p4.isCancel(chosen)) {
1304
- p4.outro("Cancelled.");
1616
+ if (p5.isCancel(chosen)) {
1617
+ p5.outro("Cancelled.");
1305
1618
  process.exit(0);
1306
1619
  }
1307
1620
  selectedClients = clients.filter((c) => chosen.includes(c.type));
@@ -1316,13 +1629,13 @@ async function installServer(input, options = {}) {
1316
1629
  collectedEnv[envVar.name] = envVar.default;
1317
1630
  continue;
1318
1631
  }
1319
- const val = await p4.text({
1632
+ const val = await p5.text({
1320
1633
  message: `${envVar.name}${envVar.description ? ` \u2014 ${envVar.description}` : ""}`,
1321
1634
  placeholder: envVar.default ?? "",
1322
1635
  validate: (v) => envVar.required && !v ? "Required" : void 0
1323
1636
  });
1324
- if (p4.isCancel(val)) {
1325
- p4.outro("Cancelled.");
1637
+ if (p5.isCancel(val)) {
1638
+ p5.outro("Cancelled.");
1326
1639
  process.exit(0);
1327
1640
  }
1328
1641
  collectedEnv[envVar.name] = val;
@@ -1341,7 +1654,7 @@ async function installServer(input, options = {}) {
1341
1654
  clientTypes.push(client.type);
1342
1655
  } catch (err) {
1343
1656
  spinner5.stop("Partial failure");
1344
- p4.log.warn(`Failed to write to ${client.displayName}: ${err instanceof Error ? err.message : String(err)}`);
1657
+ p5.log.warn(`Failed to write to ${client.displayName}: ${err instanceof Error ? err.message : String(err)}`);
1345
1658
  }
1346
1659
  }
1347
1660
  spinner5.stop("Config written");
@@ -1360,13 +1673,13 @@ async function installServer(input, options = {}) {
1360
1673
  clients: clientTypes
1361
1674
  });
1362
1675
  const lockPath = findLockfile() ?? "mcpman.lock (global)";
1363
- p4.log.success(`Lockfile updated: ${lockPath}`);
1676
+ p5.log.success(`Lockfile updated: ${lockPath}`);
1364
1677
  await offerVaultSave(metadata.name, newlyEnteredVars, options.yes ?? false);
1365
- p4.outro(`${metadata.name}@${metadata.version} installed to ${clientTypes.join(", ")}`);
1678
+ p5.outro(`${metadata.name}@${metadata.version} installed to ${clientTypes.join(", ")}`);
1366
1679
  }
1367
1680
 
1368
1681
  // src/utils/logger.ts
1369
- import pc3 from "picocolors";
1682
+ import pc5 from "picocolors";
1370
1683
  var noColor = process.env.NO_COLOR !== void 0 || process.argv.includes("--no-color");
1371
1684
  var isVerbose = process.argv.includes("--verbose");
1372
1685
  var isJson = process.argv.includes("--json");
@@ -1375,19 +1688,19 @@ function colorize(fn, text2) {
1375
1688
  }
1376
1689
  function info(message) {
1377
1690
  if (isJson) return;
1378
- console.log(`${colorize(pc3.cyan, "i")} ${message}`);
1691
+ console.log(`${colorize(pc5.cyan, "i")} ${message}`);
1379
1692
  }
1380
1693
  function error(message) {
1381
1694
  if (isJson) return;
1382
- console.error(`${colorize(pc3.red, "\u2717")} ${message}`);
1695
+ console.error(`${colorize(pc5.red, "\u2717")} ${message}`);
1383
1696
  }
1384
1697
  function json(data) {
1385
1698
  console.log(JSON.stringify(data, null, 2));
1386
1699
  }
1387
1700
 
1388
1701
  // src/commands/install.ts
1389
- import * as p5 from "@clack/prompts";
1390
- var install_default = defineCommand4({
1702
+ import * as p6 from "@clack/prompts";
1703
+ var install_default = defineCommand6({
1391
1704
  meta: {
1392
1705
  name: "install",
1393
1706
  description: "Install an MCP server into one or more AI clients"
@@ -1436,8 +1749,8 @@ async function restoreFromLockfile() {
1436
1749
  info("Lockfile is empty \u2014 nothing to restore.");
1437
1750
  return;
1438
1751
  }
1439
- p5.intro(`mcpman install (restore from ${lockPath})`);
1440
- p5.log.info(`Restoring ${entries.length} server(s)...`);
1752
+ p6.intro(`mcpman install (restore from ${lockPath})`);
1753
+ p6.log.info(`Restoring ${entries.length} server(s)...`);
1441
1754
  for (const [name, entry] of entries) {
1442
1755
  const input = entry.source === "smithery" ? `smithery:${name}` : entry.source === "github" ? entry.resolved : name;
1443
1756
  await installServer(input, {
@@ -1445,18 +1758,18 @@ async function restoreFromLockfile() {
1445
1758
  yes: true
1446
1759
  });
1447
1760
  }
1448
- p5.outro("Restore complete.");
1761
+ p6.outro("Restore complete.");
1449
1762
  }
1450
1763
 
1451
1764
  // src/commands/list.ts
1452
- import { defineCommand as defineCommand5 } from "citty";
1453
- import pc4 from "picocolors";
1765
+ import { defineCommand as defineCommand7 } from "citty";
1766
+ import pc6 from "picocolors";
1454
1767
  var STATUS_ICON = {
1455
- healthy: pc4.green("\u25CF"),
1456
- unhealthy: pc4.red("\u25CF"),
1457
- unknown: pc4.dim("\u25CB")
1768
+ healthy: pc6.green("\u25CF"),
1769
+ unhealthy: pc6.red("\u25CF"),
1770
+ unknown: pc6.dim("\u25CB")
1458
1771
  };
1459
- var list_default = defineCommand5({
1772
+ var list_default = defineCommand7({
1460
1773
  meta: {
1461
1774
  name: "list",
1462
1775
  description: "List installed MCP servers"
@@ -1476,7 +1789,7 @@ var list_default = defineCommand5({
1476
1789
  const servers = await getInstalledServers(args.client);
1477
1790
  if (servers.length === 0) {
1478
1791
  const filter = args.client ? ` for client "${args.client}"` : "";
1479
- console.log(pc4.dim(`No MCP servers installed${filter}. Run ${pc4.cyan("mcpman install <server>")} to get started.`));
1792
+ console.log(pc6.dim(`No MCP servers installed${filter}. Run ${pc6.cyan("mcpman install <server>")} to get started.`));
1480
1793
  return;
1481
1794
  }
1482
1795
  const withStatus = await Promise.all(
@@ -1500,8 +1813,8 @@ var list_default = defineCommand5({
1500
1813
  const nameWidth = Math.max(4, ...withStatus.map((s) => s.name.length));
1501
1814
  const clientsWidth = Math.max(7, ...withStatus.map((s) => formatClients(s.clients).length));
1502
1815
  const header = ` ${pad("NAME", nameWidth)} ${pad("CLIENT(S)", clientsWidth)} ${pad("COMMAND", 20)} STATUS`;
1503
- console.log(pc4.dim(header));
1504
- console.log(pc4.dim(` ${"-".repeat(nameWidth)} ${"-".repeat(clientsWidth)} ${"-".repeat(20)} ------`));
1816
+ console.log(pc6.dim(header));
1817
+ console.log(pc6.dim(` ${"-".repeat(nameWidth)} ${"-".repeat(clientsWidth)} ${"-".repeat(20)} ------`));
1505
1818
  for (const s of withStatus) {
1506
1819
  const icon = STATUS_ICON[s.status];
1507
1820
  const clientsStr = formatClients(s.clients);
@@ -1509,7 +1822,7 @@ var list_default = defineCommand5({
1509
1822
  console.log(` ${pad(s.name, nameWidth)} ${pad(clientsStr, clientsWidth)} ${pad(cmdStr, 20)} ${icon} ${s.status}`);
1510
1823
  }
1511
1824
  const clientSet = new Set(withStatus.flatMap((s) => s.clients));
1512
- console.log(pc4.dim(`
1825
+ console.log(pc6.dim(`
1513
1826
  ${withStatus.length} server${withStatus.length !== 1 ? "s" : ""} \xB7 ${clientSet.size} client${clientSet.size !== 1 ? "s" : ""}`));
1514
1827
  }
1515
1828
  });
@@ -1530,9 +1843,9 @@ function formatClients(clients) {
1530
1843
  }
1531
1844
 
1532
1845
  // src/commands/remove.ts
1533
- import { defineCommand as defineCommand6 } from "citty";
1534
- import * as p6 from "@clack/prompts";
1535
- import pc5 from "picocolors";
1846
+ import { defineCommand as defineCommand8 } from "citty";
1847
+ import * as p7 from "@clack/prompts";
1848
+ import pc7 from "picocolors";
1536
1849
  var CLIENT_DISPLAY2 = {
1537
1850
  "claude-desktop": "Claude",
1538
1851
  cursor: "Cursor",
@@ -1542,7 +1855,7 @@ var CLIENT_DISPLAY2 = {
1542
1855
  function clientDisplayName(type) {
1543
1856
  return CLIENT_DISPLAY2[type] ?? type;
1544
1857
  }
1545
- var remove_default = defineCommand6({
1858
+ var remove_default = defineCommand8({
1546
1859
  meta: {
1547
1860
  name: "remove",
1548
1861
  description: "Remove an MCP server from one or more AI clients"
@@ -1569,17 +1882,17 @@ var remove_default = defineCommand6({
1569
1882
  }
1570
1883
  },
1571
1884
  async run({ args }) {
1572
- p6.intro(pc5.bold("mcpman remove"));
1885
+ p7.intro(pc7.bold("mcpman remove"));
1573
1886
  const serverName = args.server;
1574
1887
  const servers = await getInstalledServers();
1575
1888
  const match = servers.find((s) => s.name === serverName);
1576
1889
  if (!match) {
1577
- p6.log.warn(`Server "${serverName}" is not installed.`);
1890
+ p7.log.warn(`Server "${serverName}" is not installed.`);
1578
1891
  const similar = servers.filter((s) => s.name.includes(serverName) || serverName.includes(s.name));
1579
1892
  if (similar.length > 0) {
1580
- p6.log.info(`Did you mean: ${similar.map((s) => pc5.cyan(s.name)).join(", ")}?`);
1893
+ p7.log.info(`Did you mean: ${similar.map((s) => pc7.cyan(s.name)).join(", ")}?`);
1581
1894
  }
1582
- p6.outro("Nothing to remove.");
1895
+ p7.outro("Nothing to remove.");
1583
1896
  return;
1584
1897
  }
1585
1898
  let targetClients;
@@ -1587,15 +1900,15 @@ var remove_default = defineCommand6({
1587
1900
  targetClients = match.clients;
1588
1901
  } else if (args.client) {
1589
1902
  if (!match.clients.includes(args.client)) {
1590
- p6.log.warn(`Server "${serverName}" is not installed in client "${args.client}".`);
1591
- p6.outro("Nothing to remove.");
1903
+ p7.log.warn(`Server "${serverName}" is not installed in client "${args.client}".`);
1904
+ p7.outro("Nothing to remove.");
1592
1905
  return;
1593
1906
  }
1594
1907
  targetClients = [args.client];
1595
1908
  } else if (match.clients.length === 1) {
1596
1909
  targetClients = match.clients;
1597
1910
  } else {
1598
- const selected = await p6.multiselect({
1911
+ const selected = await p7.multiselect({
1599
1912
  message: `Remove "${serverName}" from which clients?`,
1600
1913
  options: match.clients.map((c) => ({
1601
1914
  value: c,
@@ -1603,19 +1916,19 @@ var remove_default = defineCommand6({
1603
1916
  })),
1604
1917
  required: true
1605
1918
  });
1606
- if (p6.isCancel(selected)) {
1607
- p6.outro("Cancelled.");
1919
+ if (p7.isCancel(selected)) {
1920
+ p7.outro("Cancelled.");
1608
1921
  process.exit(0);
1609
1922
  }
1610
1923
  targetClients = selected;
1611
1924
  }
1612
1925
  if (!args.yes) {
1613
1926
  const clientNames = targetClients.map(clientDisplayName).join(", ");
1614
- const confirmed = await p6.confirm({
1615
- message: `Remove ${pc5.cyan(serverName)} from ${pc5.yellow(clientNames)}?`
1927
+ const confirmed = await p7.confirm({
1928
+ message: `Remove ${pc7.cyan(serverName)} from ${pc7.yellow(clientNames)}?`
1616
1929
  });
1617
- if (p6.isCancel(confirmed) || !confirmed) {
1618
- p6.outro("Cancelled.");
1930
+ if (p7.isCancel(confirmed) || !confirmed) {
1931
+ p7.outro("Cancelled.");
1619
1932
  return;
1620
1933
  }
1621
1934
  }
@@ -1629,25 +1942,268 @@ var remove_default = defineCommand6({
1629
1942
  }
1630
1943
  try {
1631
1944
  await handler.removeServer(serverName);
1632
- p6.log.success(`Removed from ${clientDisplayName(clientType)}`);
1945
+ p7.log.success(`Removed from ${clientDisplayName(clientType)}`);
1633
1946
  } catch (err) {
1634
1947
  const msg = err instanceof Error ? err.message : String(err);
1635
1948
  errors.push(`${clientDisplayName(clientType)}: ${msg}`);
1636
1949
  }
1637
1950
  }
1638
1951
  if (errors.length > 0) {
1639
- for (const e of errors) p6.log.error(e);
1640
- p6.outro(pc5.red("Completed with errors."));
1952
+ for (const e of errors) p7.log.error(e);
1953
+ p7.outro(pc7.red("Completed with errors."));
1954
+ process.exit(1);
1955
+ }
1956
+ p7.outro(pc7.green(`Removed "${serverName}" successfully.`));
1957
+ }
1958
+ });
1959
+
1960
+ // src/commands/run.ts
1961
+ import { defineCommand as defineCommand9 } from "citty";
1962
+ import { spawn as spawn2 } from "child_process";
1963
+ import pc8 from "picocolors";
1964
+ var run_default = defineCommand9({
1965
+ meta: {
1966
+ name: "run",
1967
+ description: "Run an installed MCP server with vault secrets injected"
1968
+ },
1969
+ args: {
1970
+ server: {
1971
+ type: "positional",
1972
+ description: "Server name to run (as installed in lockfile)",
1973
+ required: true
1974
+ },
1975
+ env: {
1976
+ type: "string",
1977
+ description: "Override env var KEY=VAL (repeatable)",
1978
+ alias: "e"
1979
+ }
1980
+ },
1981
+ async run({ args }) {
1982
+ const serverName = args.server;
1983
+ const lockfile = readLockfile();
1984
+ const entry = lockfile.servers[serverName];
1985
+ if (!entry) {
1986
+ console.error(pc8.red(` Error: Server '${serverName}' is not installed.`));
1987
+ console.error(pc8.dim(` Run ${pc8.cyan("mcpman install <server>")} to install it first.`));
1988
+ process.exit(1);
1989
+ }
1990
+ const lockfileEnv = parseEnvFlags(entry.envVars);
1991
+ const vaultEnv = await loadVaultSecrets(serverName);
1992
+ const cliEnv = parseEnvFlags(args.env);
1993
+ const finalEnv = {
1994
+ ...process.env,
1995
+ ...lockfileEnv,
1996
+ ...vaultEnv,
1997
+ ...cliEnv
1998
+ };
1999
+ console.log(pc8.dim(` Running ${pc8.cyan(serverName)}...`));
2000
+ const child = spawn2(entry.command, entry.args, {
2001
+ env: finalEnv,
2002
+ stdio: "inherit"
2003
+ });
2004
+ const forwardSignal = (signal) => {
2005
+ if (!child.killed) {
2006
+ child.kill(signal);
2007
+ }
2008
+ };
2009
+ process.on("SIGINT", () => forwardSignal("SIGINT"));
2010
+ process.on("SIGTERM", () => forwardSignal("SIGTERM"));
2011
+ await new Promise((resolve) => {
2012
+ child.on("close", (code) => {
2013
+ process.exit(code ?? 0);
2014
+ resolve();
2015
+ });
2016
+ child.on("error", (err) => {
2017
+ console.error(pc8.red(` Failed to start '${serverName}': ${err.message}`));
2018
+ process.exit(1);
2019
+ resolve();
2020
+ });
2021
+ });
2022
+ }
2023
+ });
2024
+ async function loadVaultSecrets(serverName) {
2025
+ try {
2026
+ const entries = listSecrets(serverName);
2027
+ if (entries.length === 0 || entries[0].keys.length === 0) {
2028
+ return {};
2029
+ }
2030
+ const password = await getMasterPassword();
2031
+ return getSecretsForServer(serverName, password);
2032
+ } catch {
2033
+ console.warn(pc8.yellow(" Warning: Could not load vault secrets, continuing without them."));
2034
+ return {};
2035
+ }
2036
+ }
2037
+
2038
+ // src/commands/search.ts
2039
+ import { defineCommand as defineCommand10 } from "citty";
2040
+ import pc9 from "picocolors";
2041
+ import { createSpinner as createSpinner3 } from "nanospinner";
2042
+
2043
+ // src/core/registry-search.ts
2044
+ var SEARCH_TIMEOUT_MS = 1e4;
2045
+ async function searchNpm(query, limit = 20) {
2046
+ const cap = Math.min(limit, 100);
2047
+ const url = `https://registry.npmjs.org/-/v1/search?text=mcp+${encodeURIComponent(query)}&size=${cap}`;
2048
+ try {
2049
+ const res = await fetch(url, { signal: AbortSignal.timeout(SEARCH_TIMEOUT_MS) });
2050
+ if (!res.ok) return [];
2051
+ const data = await res.json();
2052
+ const objects = Array.isArray(data["objects"]) ? data["objects"] : [];
2053
+ return objects.map((obj) => {
2054
+ const pkg = obj["package"] ?? {};
2055
+ const dl = obj["downloads"];
2056
+ return {
2057
+ name: typeof pkg["name"] === "string" ? pkg["name"] : "",
2058
+ description: typeof pkg["description"] === "string" ? pkg["description"] : "",
2059
+ version: typeof pkg["version"] === "string" ? pkg["version"] : "",
2060
+ date: typeof pkg["date"] === "string" ? pkg["date"] : "",
2061
+ downloads: typeof dl?.["weekly"] === "number" ? dl["weekly"] : 0,
2062
+ keywords: Array.isArray(pkg["keywords"]) ? pkg["keywords"] : []
2063
+ };
2064
+ }).filter((r) => r.name !== "");
2065
+ } catch {
2066
+ return [];
2067
+ }
2068
+ }
2069
+ async function searchSmithery(query, limit = 20) {
2070
+ const cap = Math.min(limit, 100);
2071
+ const url = `https://api.smithery.ai/v1/servers?q=${encodeURIComponent(query)}&limit=${cap}`;
2072
+ try {
2073
+ const res = await fetch(url, { signal: AbortSignal.timeout(SEARCH_TIMEOUT_MS) });
2074
+ if (!res.ok) return [];
2075
+ const data = await res.json();
2076
+ const servers = Array.isArray(data["servers"]) ? data["servers"] : [];
2077
+ return servers.map((s) => ({
2078
+ name: typeof s["name"] === "string" ? s["name"] : "",
2079
+ description: typeof s["description"] === "string" ? s["description"] : "",
2080
+ version: typeof s["version"] === "string" ? s["version"] : "latest",
2081
+ runtime: typeof s["runtime"] === "string" ? s["runtime"] : "node"
2082
+ })).filter((r) => r.name !== "");
2083
+ } catch {
2084
+ return [];
2085
+ }
2086
+ }
2087
+
2088
+ // src/commands/search.ts
2089
+ function truncate2(s, max) {
2090
+ return s.length > max ? s.slice(0, max - 1) + "\u2026" : s;
2091
+ }
2092
+ function pad2(s, width) {
2093
+ return s.length >= width ? s : s + " ".repeat(width - s.length);
2094
+ }
2095
+ function highlightMatch(name, query) {
2096
+ const idx = name.toLowerCase().indexOf(query.toLowerCase());
2097
+ if (idx === -1) return name;
2098
+ return name.slice(0, idx) + pc9.yellow(name.slice(idx, idx + query.length)) + name.slice(idx + query.length);
2099
+ }
2100
+ function formatDownloads(n) {
2101
+ if (!n) return pc9.dim("\u2014");
2102
+ if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
2103
+ if (n >= 1e3) return `${(n / 1e3).toFixed(1)}k`;
2104
+ return String(n);
2105
+ }
2106
+ function printNpmResults(results, query) {
2107
+ const nameWidth = Math.max(4, ...results.map((r) => r.name.length), 20);
2108
+ const verWidth = Math.max(7, ...results.map((r) => r.version.length));
2109
+ const dlWidth = 9;
2110
+ const descMax = 50;
2111
+ const header = ` ${pad2("NAME", nameWidth)} ${pad2("VERSION", verWidth)} ${pad2("DOWNLOADS", dlWidth)} DESCRIPTION`;
2112
+ console.log(pc9.dim(header));
2113
+ console.log(pc9.dim(` ${"-".repeat(nameWidth)} ${"-".repeat(verWidth)} ${"-".repeat(dlWidth)} ${"-".repeat(descMax)}`));
2114
+ for (const r of results) {
2115
+ const name = highlightMatch(pad2(r.name, nameWidth), query);
2116
+ const ver = pad2(r.version, verWidth);
2117
+ const dl = pad2(formatDownloads(r.downloads), dlWidth);
2118
+ const desc = truncate2(r.description || pc9.dim("(no description)"), descMax);
2119
+ console.log(` ${name} ${pc9.dim(ver)} ${dl} ${desc}`);
2120
+ }
2121
+ }
2122
+ function printSmitheryResults(results, query) {
2123
+ const nameWidth = Math.max(4, ...results.map((r) => r.name.length), 20);
2124
+ const verWidth = Math.max(7, ...results.map((r) => r.version.length));
2125
+ const descMax = 50;
2126
+ const header = ` ${pad2("NAME", nameWidth)} ${pad2("VERSION", verWidth)} DESCRIPTION`;
2127
+ console.log(pc9.dim(header));
2128
+ console.log(pc9.dim(` ${"-".repeat(nameWidth)} ${"-".repeat(verWidth)} ${"-".repeat(descMax)}`));
2129
+ for (const r of results) {
2130
+ const name = highlightMatch(pad2(r.name, nameWidth), query);
2131
+ const ver = pad2(r.version, verWidth);
2132
+ const desc = truncate2(r.description || pc9.dim("(no description)"), descMax);
2133
+ console.log(` ${name} ${pc9.dim(ver)} ${desc}`);
2134
+ }
2135
+ }
2136
+ var search_default = defineCommand10({
2137
+ meta: {
2138
+ name: "search",
2139
+ description: "Search for MCP servers on npm or Smithery registry"
2140
+ },
2141
+ args: {
2142
+ query: {
2143
+ type: "positional",
2144
+ description: "Search query",
2145
+ required: true
2146
+ },
2147
+ registry: {
2148
+ type: "string",
2149
+ description: "Registry to search: npm or smithery (default: npm)",
2150
+ default: "npm"
2151
+ },
2152
+ limit: {
2153
+ type: "string",
2154
+ description: "Maximum number of results (default: 20, max: 100)",
2155
+ default: "20"
2156
+ }
2157
+ },
2158
+ async run({ args }) {
2159
+ const query = args.query;
2160
+ const registry = args.registry.toLowerCase();
2161
+ const limit = Math.min(Math.max(1, Number.parseInt(args.limit, 10) || 20), 100);
2162
+ if (registry !== "npm" && registry !== "smithery") {
2163
+ console.error(pc9.red(` Unknown registry "${registry}". Use "npm" or "smithery".`));
1641
2164
  process.exit(1);
1642
2165
  }
1643
- p6.outro(pc5.green(`Removed "${serverName}" successfully.`));
2166
+ const spinner5 = createSpinner3(`Searching ${registry} for "${query}"...`).start();
2167
+ if (registry === "npm") {
2168
+ const results2 = await searchNpm(query, limit);
2169
+ spinner5.stop();
2170
+ if (results2.length === 0) {
2171
+ console.log(pc9.dim(`
2172
+ No results found for "${query}" on npm.
2173
+ `));
2174
+ return;
2175
+ }
2176
+ console.log(pc9.bold(`
2177
+ mcpman search \u2014 npm (${results2.length} result${results2.length !== 1 ? "s" : ""})
2178
+ `));
2179
+ printNpmResults(results2, query);
2180
+ console.log(pc9.dim(`
2181
+ Install with: mcpman install <name>
2182
+ `));
2183
+ return;
2184
+ }
2185
+ const results = await searchSmithery(query, limit);
2186
+ spinner5.stop();
2187
+ if (results.length === 0) {
2188
+ console.log(pc9.dim(`
2189
+ No results found for "${query}" on Smithery.
2190
+ `));
2191
+ return;
2192
+ }
2193
+ console.log(pc9.bold(`
2194
+ mcpman search \u2014 Smithery (${results.length} result${results.length !== 1 ? "s" : ""})
2195
+ `));
2196
+ printSmitheryResults(results, query);
2197
+ console.log(pc9.dim(`
2198
+ Install with: mcpman install <name>
2199
+ `));
1644
2200
  }
1645
2201
  });
1646
2202
 
1647
2203
  // src/commands/secrets.ts
1648
- import { defineCommand as defineCommand7 } from "citty";
1649
- import pc6 from "picocolors";
1650
- import * as p7 from "@clack/prompts";
2204
+ import { defineCommand as defineCommand11 } from "citty";
2205
+ import pc10 from "picocolors";
2206
+ import * as p8 from "@clack/prompts";
1651
2207
  function maskValue(value) {
1652
2208
  if (value.length <= 8) return "***";
1653
2209
  return `${value.slice(0, 4)}***${value.slice(-3)}`;
@@ -1657,7 +2213,7 @@ function parseKeyValue(input) {
1657
2213
  if (idx <= 0) return null;
1658
2214
  return { key: input.slice(0, idx), value: input.slice(idx + 1) };
1659
2215
  }
1660
- var setCommand = defineCommand7({
2216
+ var setCommand2 = defineCommand11({
1661
2217
  meta: { name: "set", description: "Store an encrypted secret for a server" },
1662
2218
  args: {
1663
2219
  server: {
@@ -1674,30 +2230,30 @@ var setCommand = defineCommand7({
1674
2230
  async run({ args }) {
1675
2231
  const parsed = parseKeyValue(args.keyvalue);
1676
2232
  if (!parsed) {
1677
- console.error(pc6.red("\u2717") + " Invalid format. Expected KEY=VALUE");
2233
+ console.error(pc10.red("\u2717") + " Invalid format. Expected KEY=VALUE");
1678
2234
  process.exit(1);
1679
2235
  }
1680
- p7.intro(pc6.cyan("mcpman secrets set"));
2236
+ p8.intro(pc10.cyan("mcpman secrets set"));
1681
2237
  const isNew = listSecrets(args.server).length === 0 || !listSecrets(args.server)[0]?.keys.includes(parsed.key);
1682
2238
  const vaultPath = (await import("./vault-service-UTZAV6N6.js")).getVaultPath();
1683
2239
  const vaultExists = (await import("fs")).existsSync(vaultPath);
1684
2240
  const password = await getMasterPassword(!vaultExists && isNew);
1685
- const spin = p7.spinner();
2241
+ const spin = p8.spinner();
1686
2242
  spin.start("Encrypting secret...");
1687
2243
  try {
1688
2244
  setSecret(args.server, parsed.key, parsed.value, password);
1689
2245
  spin.stop(
1690
- `${pc6.green("\u2713")} Stored ${pc6.bold(parsed.key)} for ${pc6.cyan(args.server)}`
2246
+ `${pc10.green("\u2713")} Stored ${pc10.bold(parsed.key)} for ${pc10.cyan(args.server)}`
1691
2247
  );
1692
2248
  } catch (err) {
1693
- spin.stop(pc6.red("\u2717") + " Failed to store secret");
1694
- console.error(pc6.dim(String(err)));
2249
+ spin.stop(pc10.red("\u2717") + " Failed to store secret");
2250
+ console.error(pc10.dim(String(err)));
1695
2251
  process.exit(1);
1696
2252
  }
1697
- p7.outro(pc6.dim("Secret encrypted and saved to vault."));
2253
+ p8.outro(pc10.dim("Secret encrypted and saved to vault."));
1698
2254
  }
1699
2255
  });
1700
- var listCommand = defineCommand7({
2256
+ var listCommand2 = defineCommand11({
1701
2257
  meta: { name: "list", description: "List secret keys stored in the vault" },
1702
2258
  args: {
1703
2259
  server: {
@@ -1709,23 +2265,23 @@ var listCommand = defineCommand7({
1709
2265
  async run({ args }) {
1710
2266
  const results = listSecrets(args.server || void 0);
1711
2267
  if (results.length === 0) {
1712
- const filter = args.server ? ` for ${pc6.cyan(args.server)}` : "";
1713
- console.log(pc6.dim(`No secrets stored${filter}.`));
2268
+ const filter = args.server ? ` for ${pc10.cyan(args.server)}` : "";
2269
+ console.log(pc10.dim(`No secrets stored${filter}.`));
1714
2270
  return;
1715
2271
  }
1716
2272
  console.log("");
1717
2273
  for (const { server, keys } of results) {
1718
- console.log(pc6.bold(pc6.cyan(server)));
2274
+ console.log(pc10.bold(pc10.cyan(server)));
1719
2275
  for (const key of keys) {
1720
- console.log(` ${pc6.green("\u25CF")} ${pc6.bold(key)} ${pc6.dim(maskValue("\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022"))}`);
2276
+ console.log(` ${pc10.green("\u25CF")} ${pc10.bold(key)} ${pc10.dim(maskValue("\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022"))}`);
1721
2277
  }
1722
2278
  console.log("");
1723
2279
  }
1724
2280
  const total = results.reduce((n, r) => n + r.keys.length, 0);
1725
- console.log(pc6.dim(` ${total} secret${total !== 1 ? "s" : ""} in ${results.length} server${results.length !== 1 ? "s" : ""}`));
2281
+ console.log(pc10.dim(` ${total} secret${total !== 1 ? "s" : ""} in ${results.length} server${results.length !== 1 ? "s" : ""}`));
1726
2282
  }
1727
2283
  });
1728
- var removeCommand = defineCommand7({
2284
+ var removeCommand = defineCommand11({
1729
2285
  meta: { name: "remove", description: "Delete a secret from the vault" },
1730
2286
  args: {
1731
2287
  server: {
@@ -1740,40 +2296,40 @@ var removeCommand = defineCommand7({
1740
2296
  }
1741
2297
  },
1742
2298
  async run({ args }) {
1743
- const confirmed = await p7.confirm({
1744
- message: `Remove ${pc6.bold(args.key)} from ${pc6.cyan(args.server)}?`,
2299
+ const confirmed = await p8.confirm({
2300
+ message: `Remove ${pc10.bold(args.key)} from ${pc10.cyan(args.server)}?`,
1745
2301
  initialValue: false
1746
2302
  });
1747
- if (p7.isCancel(confirmed) || !confirmed) {
1748
- p7.cancel("Cancelled.");
2303
+ if (p8.isCancel(confirmed) || !confirmed) {
2304
+ p8.cancel("Cancelled.");
1749
2305
  return;
1750
2306
  }
1751
2307
  try {
1752
2308
  removeSecret(args.server, args.key);
1753
- console.log(`${pc6.green("\u2713")} Removed ${pc6.bold(args.key)} from ${pc6.cyan(args.server)}`);
2309
+ console.log(`${pc10.green("\u2713")} Removed ${pc10.bold(args.key)} from ${pc10.cyan(args.server)}`);
1754
2310
  } catch (err) {
1755
- console.error(pc6.red("\u2717") + " Failed to remove secret");
1756
- console.error(pc6.dim(String(err)));
2311
+ console.error(pc10.red("\u2717") + " Failed to remove secret");
2312
+ console.error(pc10.dim(String(err)));
1757
2313
  process.exit(1);
1758
2314
  }
1759
2315
  }
1760
2316
  });
1761
- var secrets_default = defineCommand7({
2317
+ var secrets_default = defineCommand11({
1762
2318
  meta: {
1763
2319
  name: "secrets",
1764
2320
  description: "Manage encrypted secrets for MCP servers"
1765
2321
  },
1766
2322
  subCommands: {
1767
- set: setCommand,
1768
- list: listCommand,
2323
+ set: setCommand2,
2324
+ list: listCommand2,
1769
2325
  remove: removeCommand
1770
2326
  }
1771
2327
  });
1772
2328
 
1773
2329
  // src/commands/sync.ts
1774
- import { defineCommand as defineCommand8 } from "citty";
1775
- import * as p8 from "@clack/prompts";
1776
- import pc7 from "picocolors";
2330
+ import { defineCommand as defineCommand12 } from "citty";
2331
+ import * as p9 from "@clack/prompts";
2332
+ import pc11 from "picocolors";
1777
2333
 
1778
2334
  // src/core/config-diff.ts
1779
2335
  function reconstructServerEntry(lockEntry) {
@@ -1923,7 +2479,7 @@ var CLIENT_DISPLAY3 = {
1923
2479
  vscode: "VS Code",
1924
2480
  windsurf: "Windsurf"
1925
2481
  };
1926
- var sync_default = defineCommand8({
2482
+ var sync_default = defineCommand12({
1927
2483
  meta: {
1928
2484
  name: "sync",
1929
2485
  description: "Sync MCP server configs across all detected AI clients"
@@ -1950,28 +2506,28 @@ var sync_default = defineCommand8({
1950
2506
  }
1951
2507
  },
1952
2508
  async run({ args }) {
1953
- p8.intro(`${pc7.cyan("mcpman sync")}`);
2509
+ p9.intro(`${pc11.cyan("mcpman sync")}`);
1954
2510
  const sourceClient = args.source;
1955
2511
  if (sourceClient && !VALID_CLIENTS.includes(sourceClient)) {
1956
- p8.log.error(`Invalid --source "${sourceClient}". Must be one of: ${VALID_CLIENTS.join(", ")}`);
2512
+ p9.log.error(`Invalid --source "${sourceClient}". Must be one of: ${VALID_CLIENTS.join(", ")}`);
1957
2513
  process.exit(1);
1958
2514
  }
1959
- const spinner5 = p8.spinner();
2515
+ const spinner5 = p9.spinner();
1960
2516
  spinner5.start("Detecting clients and reading configs...");
1961
2517
  const { configs, handlers } = await getClientConfigs();
1962
2518
  spinner5.stop(`Found ${configs.size} client(s)`);
1963
2519
  if (configs.size === 0) {
1964
- p8.log.warn("No AI clients detected. Install Claude Desktop, Cursor, VS Code, or Windsurf first.");
2520
+ p9.log.warn("No AI clients detected. Install Claude Desktop, Cursor, VS Code, or Windsurf first.");
1965
2521
  process.exit(0);
1966
2522
  }
1967
2523
  const diffOptions = { remove: args.remove };
1968
2524
  let actions;
1969
2525
  if (sourceClient) {
1970
2526
  if (!configs.has(sourceClient)) {
1971
- p8.log.error(`Source client "${sourceClient}" is not detected or its config is unreadable.`);
2527
+ p9.log.error(`Source client "${sourceClient}" is not detected or its config is unreadable.`);
1972
2528
  process.exit(1);
1973
2529
  }
1974
- p8.log.info(`Using ${CLIENT_DISPLAY3[sourceClient]} as source of truth`);
2530
+ p9.log.info(`Using ${CLIENT_DISPLAY3[sourceClient]} as source of truth`);
1975
2531
  actions = computeDiffFromClient(sourceClient, configs, diffOptions);
1976
2532
  } else {
1977
2533
  const lockfile = readLockfile();
@@ -1982,32 +2538,32 @@ var sync_default = defineCommand8({
1982
2538
  const extraCount = actions.filter((a) => a.action === "extra").length;
1983
2539
  const removeCount = actions.filter((a) => a.action === "remove").length;
1984
2540
  if (addCount === 0 && removeCount === 0 && extraCount === 0) {
1985
- p8.outro(pc7.green("All clients are in sync."));
2541
+ p9.outro(pc11.green("All clients are in sync."));
1986
2542
  process.exit(0);
1987
2543
  }
1988
2544
  const parts = [];
1989
- if (addCount > 0) parts.push(pc7.green(`${addCount} to add`));
1990
- if (removeCount > 0) parts.push(pc7.red(`${removeCount} to remove`));
1991
- if (extraCount > 0) parts.push(pc7.yellow(`${extraCount} extra (informational)`));
1992
- p8.log.info(parts.join(" \xB7 "));
2545
+ if (addCount > 0) parts.push(pc11.green(`${addCount} to add`));
2546
+ if (removeCount > 0) parts.push(pc11.red(`${removeCount} to remove`));
2547
+ if (extraCount > 0) parts.push(pc11.yellow(`${extraCount} extra (informational)`));
2548
+ p9.log.info(parts.join(" \xB7 "));
1993
2549
  if (args["dry-run"]) {
1994
- p8.outro(pc7.dim("Dry run \u2014 no changes applied."));
2550
+ p9.outro(pc11.dim("Dry run \u2014 no changes applied."));
1995
2551
  process.exit(1);
1996
2552
  }
1997
2553
  if (addCount === 0 && removeCount === 0) {
1998
- p8.outro(pc7.dim("No additions needed. Extra servers left untouched."));
2554
+ p9.outro(pc11.dim("No additions needed. Extra servers left untouched."));
1999
2555
  process.exit(1);
2000
2556
  }
2001
2557
  if (!args.yes) {
2002
2558
  const actionParts = [];
2003
2559
  if (addCount > 0) actionParts.push(`${addCount} addition(s)`);
2004
2560
  if (removeCount > 0) actionParts.push(`${removeCount} removal(s)`);
2005
- const confirmed = await p8.confirm({
2561
+ const confirmed = await p9.confirm({
2006
2562
  message: `Apply ${actionParts.join(" and ")} to client configs?`,
2007
2563
  initialValue: true
2008
2564
  });
2009
- if (p8.isCancel(confirmed) || !confirmed) {
2010
- p8.outro(pc7.dim("Cancelled \u2014 no changes applied."));
2565
+ if (p9.isCancel(confirmed) || !confirmed) {
2566
+ p9.outro(pc11.dim("Cancelled \u2014 no changes applied."));
2011
2567
  process.exit(0);
2012
2568
  }
2013
2569
  }
@@ -2015,72 +2571,72 @@ var sync_default = defineCommand8({
2015
2571
  const result = await applySyncActions(actions, handlers);
2016
2572
  spinner5.stop("Done");
2017
2573
  if (result.applied > 0) {
2018
- p8.log.success(`Added ${result.applied} server(s) to client configs.`);
2574
+ p9.log.success(`Added ${result.applied} server(s) to client configs.`);
2019
2575
  }
2020
2576
  if (result.removed > 0) {
2021
- p8.log.success(`Removed ${result.removed} server(s) from client configs.`);
2577
+ p9.log.success(`Removed ${result.removed} server(s) from client configs.`);
2022
2578
  }
2023
2579
  if (result.failed > 0) {
2024
2580
  for (const e of result.errors) {
2025
- p8.log.error(`Failed to sync "${e.server}" on ${e.client}: ${e.error}`);
2581
+ p9.log.error(`Failed to sync "${e.server}" on ${e.client}: ${e.error}`);
2026
2582
  }
2027
2583
  }
2028
- p8.outro(result.failed === 0 ? pc7.green("Sync complete.") : pc7.yellow("Sync complete with errors."));
2584
+ p9.outro(result.failed === 0 ? pc11.green("Sync complete.") : pc11.yellow("Sync complete with errors."));
2029
2585
  process.exit(result.failed > 0 ? 1 : 0);
2030
2586
  }
2031
2587
  });
2032
2588
  function printDiffTable(actions) {
2033
2589
  if (actions.length === 0) {
2034
- p8.log.info("No actions to display.");
2590
+ p9.log.info("No actions to display.");
2035
2591
  return;
2036
2592
  }
2037
2593
  const nameWidth = Math.max(6, ...actions.map((a) => a.server.length));
2038
2594
  const clientWidth = Math.max(6, ...actions.map((a) => CLIENT_DISPLAY3[a.client]?.length ?? a.client.length));
2039
- const header = ` ${pad2("SERVER", nameWidth)} ${pad2("CLIENT", clientWidth)} STATUS`;
2040
- console.log(pc7.dim(header));
2041
- console.log(pc7.dim(` ${"-".repeat(nameWidth)} ${"-".repeat(clientWidth)} ------`));
2595
+ const header = ` ${pad3("SERVER", nameWidth)} ${pad3("CLIENT", clientWidth)} STATUS`;
2596
+ console.log(pc11.dim(header));
2597
+ console.log(pc11.dim(` ${"-".repeat(nameWidth)} ${"-".repeat(clientWidth)} ------`));
2042
2598
  for (const action of actions) {
2043
2599
  const clientDisplay = CLIENT_DISPLAY3[action.client] ?? action.client;
2044
2600
  const [icon, statusText] = formatAction(action.action);
2045
- console.log(` ${pad2(action.server, nameWidth)} ${pad2(clientDisplay, clientWidth)} ${icon} ${statusText}`);
2601
+ console.log(` ${pad3(action.server, nameWidth)} ${pad3(clientDisplay, clientWidth)} ${icon} ${statusText}`);
2046
2602
  }
2047
2603
  console.log("");
2048
2604
  }
2049
2605
  function formatAction(action) {
2050
2606
  switch (action) {
2051
2607
  case "add":
2052
- return [pc7.green("+"), pc7.green("missing \u2014 will add")];
2608
+ return [pc11.green("+"), pc11.green("missing \u2014 will add")];
2053
2609
  case "extra":
2054
- return [pc7.yellow("?"), pc7.yellow("extra (not in lockfile)")];
2610
+ return [pc11.yellow("?"), pc11.yellow("extra (not in lockfile)")];
2055
2611
  case "remove":
2056
- return [pc7.red("\u2013"), pc7.red("extra \u2014 will remove")];
2612
+ return [pc11.red("\u2013"), pc11.red("extra \u2014 will remove")];
2057
2613
  case "ok":
2058
- return [pc7.dim("\xB7"), pc7.dim("in sync")];
2614
+ return [pc11.dim("\xB7"), pc11.dim("in sync")];
2059
2615
  }
2060
2616
  }
2061
- function pad2(s, width) {
2617
+ function pad3(s, width) {
2062
2618
  return s.length >= width ? s : s + " ".repeat(width - s.length);
2063
2619
  }
2064
2620
 
2065
2621
  // src/commands/update.ts
2066
- import { defineCommand as defineCommand9 } from "citty";
2067
- import * as p9 from "@clack/prompts";
2068
- import pc9 from "picocolors";
2622
+ import { defineCommand as defineCommand13 } from "citty";
2623
+ import * as p10 from "@clack/prompts";
2624
+ import pc13 from "picocolors";
2069
2625
 
2070
2626
  // src/core/update-notifier.ts
2071
- import fs3 from "fs";
2072
- import path4 from "path";
2627
+ import fs4 from "fs";
2628
+ import path5 from "path";
2073
2629
  import os3 from "os";
2074
- import pc8 from "picocolors";
2075
- var CACHE_FILE = path4.join(os3.homedir(), ".mcpman", ".update-check");
2630
+ import pc12 from "picocolors";
2631
+ var CACHE_FILE = path5.join(os3.homedir(), ".mcpman", ".update-check");
2076
2632
  var TTL_MS = 24 * 60 * 60 * 1e3;
2077
2633
  function writeUpdateCache(data) {
2078
2634
  try {
2079
- const dir = path4.dirname(CACHE_FILE);
2080
- if (!fs3.existsSync(dir)) fs3.mkdirSync(dir, { recursive: true });
2635
+ const dir = path5.dirname(CACHE_FILE);
2636
+ if (!fs4.existsSync(dir)) fs4.mkdirSync(dir, { recursive: true });
2081
2637
  const tmp = `${CACHE_FILE}.tmp`;
2082
- fs3.writeFileSync(tmp, JSON.stringify(data, null, 2), "utf-8");
2083
- fs3.renameSync(tmp, CACHE_FILE);
2638
+ fs4.writeFileSync(tmp, JSON.stringify(data, null, 2), "utf-8");
2639
+ fs4.renameSync(tmp, CACHE_FILE);
2084
2640
  } catch {
2085
2641
  }
2086
2642
  }
@@ -2088,7 +2644,7 @@ function writeUpdateCache(data) {
2088
2644
  // src/commands/update.ts
2089
2645
  async function loadClients3() {
2090
2646
  try {
2091
- const mod = await import("./client-detector-SUIJSIYM.js");
2647
+ const mod = await import("./client-detector-UAP2EYZA.js");
2092
2648
  return mod.getInstalledClients();
2093
2649
  } catch {
2094
2650
  return [];
@@ -2103,19 +2659,19 @@ function printTable(updates) {
2103
2659
  "LATEST".padEnd(VER_W),
2104
2660
  "STATUS"
2105
2661
  ].join(" ");
2106
- console.log(pc9.bold(`
2662
+ console.log(pc13.bold(`
2107
2663
  ${header}`));
2108
- console.log(pc9.dim(` ${"\u2500".repeat(NAME_W + VER_W * 2 + 20)}`));
2664
+ console.log(pc13.dim(` ${"\u2500".repeat(NAME_W + VER_W * 2 + 20)}`));
2109
2665
  for (const u of updates) {
2110
2666
  const nameCol = u.server.slice(0, NAME_W).padEnd(NAME_W);
2111
2667
  const curCol = u.currentVersion.padEnd(VER_W);
2112
2668
  const latCol = u.latestVersion.padEnd(VER_W);
2113
- const statusCol = u.hasUpdate ? pc9.yellow(`Update available${u.updateType ? ` [${u.updateType}]` : ""}`) : pc9.green("Up to date");
2669
+ const statusCol = u.hasUpdate ? pc13.yellow(`Update available${u.updateType ? ` [${u.updateType}]` : ""}`) : pc13.green("Up to date");
2114
2670
  console.log(` ${nameCol} ${curCol} ${latCol} ${statusCol}`);
2115
2671
  }
2116
2672
  console.log();
2117
2673
  }
2118
- var update_default = defineCommand9({
2674
+ var update_default = defineCommand13({
2119
2675
  meta: {
2120
2676
  name: "update",
2121
2677
  description: "Check for and apply updates to installed MCP servers"
@@ -2154,7 +2710,7 @@ var update_default = defineCommand9({
2154
2710
  }
2155
2711
  process.exit(1);
2156
2712
  }
2157
- const spinner5 = p9.spinner();
2713
+ const spinner5 = p10.spinner();
2158
2714
  spinner5.start("Checking versions...");
2159
2715
  let updates;
2160
2716
  try {
@@ -2176,27 +2732,27 @@ var update_default = defineCommand9({
2176
2732
  printTable(updates);
2177
2733
  const outdated = updates.filter((u) => u.hasUpdate);
2178
2734
  if (outdated.length === 0) {
2179
- console.log(pc9.green(" All servers are up to date."));
2735
+ console.log(pc13.green(" All servers are up to date."));
2180
2736
  return;
2181
2737
  }
2182
2738
  if (args.check) {
2183
- console.log(pc9.yellow(` ${outdated.length} update(s) available. Run mcpman update to apply.`));
2739
+ console.log(pc13.yellow(` ${outdated.length} update(s) available. Run mcpman update to apply.`));
2184
2740
  return;
2185
2741
  }
2186
2742
  if (!args.yes) {
2187
- const confirmed = await p9.confirm({
2743
+ const confirmed = await p10.confirm({
2188
2744
  message: `Apply ${outdated.length} update(s)?`,
2189
2745
  initialValue: true
2190
2746
  });
2191
- if (p9.isCancel(confirmed) || !confirmed) {
2192
- p9.outro("Cancelled.");
2747
+ if (p10.isCancel(confirmed) || !confirmed) {
2748
+ p10.outro("Cancelled.");
2193
2749
  return;
2194
2750
  }
2195
2751
  }
2196
2752
  const clients = await loadClients3();
2197
2753
  let successCount = 0;
2198
2754
  for (const update of outdated) {
2199
- const s = p9.spinner();
2755
+ const s = p10.spinner();
2200
2756
  s.start(`Updating ${update.server}...`);
2201
2757
  const result = await applyServerUpdate(
2202
2758
  update.server,
@@ -2204,22 +2760,22 @@ var update_default = defineCommand9({
2204
2760
  clients
2205
2761
  );
2206
2762
  if (result.success) {
2207
- s.stop(`${pc9.green("\u2713")} ${update.server}: ${result.fromVersion} \u2192 ${result.toVersion}`);
2763
+ s.stop(`${pc13.green("\u2713")} ${update.server}: ${result.fromVersion} \u2192 ${result.toVersion}`);
2208
2764
  successCount++;
2209
2765
  } else {
2210
- s.stop(`${pc9.red("\u2717")} ${update.server}: ${result.error}`);
2766
+ s.stop(`${pc13.red("\u2717")} ${update.server}: ${result.error}`);
2211
2767
  }
2212
2768
  }
2213
2769
  const freshLockfile = readLockfile(resolveLockfilePath());
2214
2770
  const freshUpdates = await checkAllVersions(freshLockfile);
2215
2771
  writeUpdateCache({ lastCheck: (/* @__PURE__ */ new Date()).toISOString(), updates: freshUpdates });
2216
- p9.outro(`${successCount} of ${outdated.length} server(s) updated.`);
2772
+ p10.outro(`${successCount} of ${outdated.length} server(s) updated.`);
2217
2773
  }
2218
2774
  });
2219
2775
 
2220
2776
  // src/utils/constants.ts
2221
2777
  var APP_NAME = "mcpman";
2222
- var APP_VERSION = "0.3.0";
2778
+ var APP_VERSION = "0.4.0";
2223
2779
  var APP_DESCRIPTION = "The package manager for MCP servers";
2224
2780
 
2225
2781
  // src/index.ts
@@ -2227,7 +2783,7 @@ process.on("SIGINT", () => {
2227
2783
  console.log("\nAborted.");
2228
2784
  process.exit(130);
2229
2785
  });
2230
- var main = defineCommand10({
2786
+ var main = defineCommand14({
2231
2787
  meta: {
2232
2788
  name: APP_NAME,
2233
2789
  version: APP_VERSION,
@@ -2242,7 +2798,11 @@ var main = defineCommand10({
2242
2798
  secrets: secrets_default,
2243
2799
  sync: sync_default,
2244
2800
  audit: audit_default,
2245
- update: update_default
2801
+ update: update_default,
2802
+ config: config_default,
2803
+ search: search_default,
2804
+ info: info_default,
2805
+ run: run_default
2246
2806
  }
2247
2807
  });
2248
2808
  runMain(main);