@wuyax/mcps 0.1.0-beta.2 → 0.1.0-beta.3

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
@@ -34,17 +34,23 @@ __export(src_exports, {
34
34
  DEFAULT_REMOTE_TRANSPORT: () => DEFAULT_REMOTE_TRANSPORT,
35
35
  NPX_COMMAND: () => NPX_COMMAND,
36
36
  NPX_DASH_Y: () => NPX_DASH_Y,
37
+ SECRET_HEADER_PATTERN: () => SECRET_HEADER_PATTERN,
38
+ SECRET_KEY_PATTERN: () => SECRET_KEY_PATTERN,
37
39
  add: () => installMcpServer,
38
40
  agentConfigStore: () => agentConfigStore,
41
+ buildLinkedAgentChoices: () => buildLinkedAgentChoices,
39
42
  buildMcpServerConfig: () => buildMcpServerConfig,
40
43
  createAgentTransform: () => createAgentTransform,
41
44
  detectGloballyInstalledMcpAgents: () => detectGloballyInstalledMcpAgents,
42
45
  detectProjectInstalledMcpAgents: () => detectProjectInstalledMcpAgents,
46
+ detectUpdateTransition: () => detectUpdateTransition,
43
47
  displayServerDetails: () => displayServerDetails,
44
48
  extractPackageName: () => extractPackageName,
45
49
  formatArgsString: () => formatArgsString,
46
50
  formatEnvText: () => formatEnvText,
47
51
  formatHeadersText: () => formatHeadersText,
52
+ getCandidateAgentsForScope: () => getCandidateAgentsForScope,
53
+ getCoHostedAgents: () => getCoHostedAgents,
48
54
  getMcpAgentConfig: () => getMcpAgentConfig,
49
55
  getMcpAgentTypes: () => getMcpAgentTypes,
50
56
  getMcpAgentsSupportingProjectScope: () => getMcpAgentsSupportingProjectScope,
@@ -53,11 +59,13 @@ __export(src_exports, {
53
59
  installMcpServer: () => installMcpServer,
54
60
  installMcpServerForAgent: () => installMcpServerForAgent,
55
61
  installMcpServerForAgents: () => installMcpServerForAgents,
62
+ installToCompatibleAgents: () => installToCompatibleAgents,
56
63
  isMcpAgentType: () => isMcpAgentType,
57
64
  isMcpTransportSupported: () => isMcpTransportSupported,
58
65
  isRemoteMcpSource: () => isRemoteMcpSource,
59
66
  isRemoteServerConfig: () => isRemoteServerConfig,
60
67
  isStdioServerConfig: () => isStdioServerConfig,
68
+ linkedCheckbox: () => linkedCheckbox,
61
69
  list: () => listInstalledMcpServers,
62
70
  listInstalledMcpServers: () => listInstalledMcpServers,
63
71
  listServersInConfigFile: () => listServersInConfigFile,
@@ -83,18 +91,25 @@ __export(src_exports, {
83
91
  promptHeadersConfig: () => promptHeadersConfig,
84
92
  promptScope: () => promptScope,
85
93
  promptScopeAndAgents: () => promptScopeAndAgents,
94
+ promptSwitchServerType: () => promptSwitchServerType,
86
95
  readConfigFile: () => readConfigFile,
87
96
  remove: () => removeMcpServer,
88
97
  removeMcpServer: () => removeMcpServer,
89
98
  removeMcpServerFromAgent: () => removeMcpServerFromAgent,
90
99
  removeServerFromConfigFile: () => removeServerFromConfigFile,
100
+ resolveConfigClusters: () => resolveConfigClusters,
91
101
  resolveMcpAgentAlias: () => resolveMcpAgentAlias,
92
102
  resolveMcpConfigTarget: () => resolveMcpConfigTarget,
93
103
  resolveTargetAgents: () => resolveTargetAgents,
104
+ resolveTransport: () => resolveTransport,
105
+ sanitizeUpdatedServerConfig: () => sanitizeUpdatedServerConfig,
106
+ sortAgentsWithClusters: () => sortAgentsWithClusters,
107
+ toRemoteServerConfig: () => toRemoteServerConfig,
108
+ toStdioServerConfig: () => toStdioServerConfig,
94
109
  transformServerConfig: () => transformServerConfig,
95
110
  transformServerConfigForAgent: () => transformServerConfigForAgent,
96
- updateMcpServerForAgent: () => installMcpServerForAgent,
97
- updateMcpServerForAgents: () => installMcpServerForAgents,
111
+ update: () => updateMcpServer,
112
+ updateMcpServer: () => updateMcpServer,
98
113
  wizardAdd: () => wizardAdd,
99
114
  wizardManage: () => wizardManage,
100
115
  wizardRemove: () => wizardRemove,
@@ -1069,6 +1084,74 @@ var agentConfigStore = new AgentConfigStore();
1069
1084
  // src/utils/to-error-message.ts
1070
1085
  var toErrorMessage = (error, fallback = "Unknown error") => error instanceof Error ? error.message : fallback;
1071
1086
 
1087
+ // src/resolve-config-clusters.ts
1088
+ var getCandidateAgentsForScope = (options = {}) => {
1089
+ return options.global ? getMcpAgentTypes() : getMcpAgentsSupportingProjectScope();
1090
+ };
1091
+ var getCoHostedAgents = (agentType, options = {}) => {
1092
+ const currentAgent = getMcpAgentConfig(agentType);
1093
+ const currentTarget = resolveMcpConfigTarget(currentAgent, options);
1094
+ const candidates = getCandidateAgentsForScope(options);
1095
+ const coHosted = [];
1096
+ for (const candidateType of candidates) {
1097
+ if (candidateType === agentType) continue;
1098
+ const candidateConfig = getMcpAgentConfig(candidateType);
1099
+ const candidateTarget = resolveMcpConfigTarget(candidateConfig, options);
1100
+ if (candidateTarget.configPath === currentTarget.configPath && candidateTarget.configKey === currentTarget.configKey) {
1101
+ coHosted.push(candidateType);
1102
+ }
1103
+ }
1104
+ return coHosted;
1105
+ };
1106
+ var resolveConfigClusters = (agentTypes, options = {}) => {
1107
+ const clustersByPath = /* @__PURE__ */ new Map();
1108
+ for (const agentType of agentTypes) {
1109
+ const agentConfig = getMcpAgentConfig(agentType);
1110
+ const target = resolveMcpConfigTarget(agentConfig, options);
1111
+ let keyMap = clustersByPath.get(target.configPath);
1112
+ if (!keyMap) {
1113
+ keyMap = /* @__PURE__ */ new Map();
1114
+ clustersByPath.set(target.configPath, keyMap);
1115
+ }
1116
+ let cluster = keyMap.get(target.configKey);
1117
+ if (!cluster) {
1118
+ const allCoHosted = getCoHostedAgents(agentType, options);
1119
+ cluster = {
1120
+ configPath: target.configPath,
1121
+ configKey: target.configKey,
1122
+ targetAgents: [],
1123
+ coHostedAgents: allCoHosted
1124
+ };
1125
+ keyMap.set(target.configKey, cluster);
1126
+ }
1127
+ if (!cluster.targetAgents.includes(agentType)) {
1128
+ cluster.targetAgents.push(agentType);
1129
+ }
1130
+ }
1131
+ const clusters = [];
1132
+ for (const keyMap of clustersByPath.values()) {
1133
+ for (const cluster of keyMap.values()) {
1134
+ cluster.coHostedAgents = cluster.coHostedAgents.filter(
1135
+ (co) => !cluster.targetAgents.includes(co)
1136
+ );
1137
+ clusters.push(cluster);
1138
+ }
1139
+ }
1140
+ return clusters;
1141
+ };
1142
+ var sortAgentsWithClusters = (agentTypes, options = {}) => {
1143
+ const clusters = resolveConfigClusters(agentTypes, options);
1144
+ const sorted = [];
1145
+ for (const cluster of clusters) {
1146
+ for (const agent of cluster.targetAgents) {
1147
+ if (!sorted.includes(agent)) {
1148
+ sorted.push(agent);
1149
+ }
1150
+ }
1151
+ }
1152
+ return sorted;
1153
+ };
1154
+
1072
1155
  // src/transforms/index.ts
1073
1156
  var DIALECT_PRESETS = {
1074
1157
  vscode: {
@@ -1284,12 +1367,18 @@ var installMcpServerForAgent = (serverName, serverConfig, agentType, options = {
1284
1367
  const agent = getMcpAgentConfig(agentType);
1285
1368
  const isGlobal = options.global ?? false;
1286
1369
  const { target } = agentConfigStore.resolveTarget(agent, options);
1370
+ const coHosted = getCoHostedAgents(agentType, options);
1287
1371
  try {
1288
1372
  const transformed = transformServerConfigForAgent(agent, serverName, serverConfig, {
1289
1373
  global: isGlobal
1290
1374
  });
1291
1375
  agentConfigStore.writeServer(agent, serverName, transformed, options);
1292
- return { agent: agentType, success: true, path: target.configPath };
1376
+ return {
1377
+ agent: agentType,
1378
+ success: true,
1379
+ path: target.configPath,
1380
+ coConfiguredAgents: coHosted.length > 0 ? coHosted : void 0
1381
+ };
1293
1382
  } catch (error) {
1294
1383
  return {
1295
1384
  agent: agentType,
@@ -1299,9 +1388,62 @@ var installMcpServerForAgent = (serverName, serverConfig, agentType, options = {
1299
1388
  };
1300
1389
  }
1301
1390
  };
1302
- var installMcpServerForAgents = (serverName, serverConfig, agentTypes, options = {}) => agentTypes.map(
1303
- (agentType) => installMcpServerForAgent(serverName, serverConfig, agentType, options)
1304
- );
1391
+ var installMcpServerForAgents = (serverName, serverConfig, agentTypes, options = {}) => {
1392
+ const clusters = resolveConfigClusters(agentTypes, options);
1393
+ const resultsByAgent = /* @__PURE__ */ new Map();
1394
+ const isGlobal = options.global ?? false;
1395
+ for (const cluster of clusters) {
1396
+ const primaryAgentType = cluster.targetAgents[0];
1397
+ const primaryAgent = getMcpAgentConfig(primaryAgentType);
1398
+ try {
1399
+ const transformed = transformServerConfigForAgent(primaryAgent, serverName, serverConfig, {
1400
+ global: isGlobal
1401
+ });
1402
+ agentConfigStore.writeServer(primaryAgent, serverName, transformed, options);
1403
+ for (const agentType of cluster.targetAgents) {
1404
+ resultsByAgent.set(agentType, {
1405
+ agent: agentType,
1406
+ success: true,
1407
+ path: cluster.configPath,
1408
+ coConfiguredAgents: cluster.coHostedAgents.length > 0 ? cluster.coHostedAgents : void 0
1409
+ });
1410
+ }
1411
+ } catch (error) {
1412
+ const errorMsg = toErrorMessage(error);
1413
+ for (const agentType of cluster.targetAgents) {
1414
+ resultsByAgent.set(agentType, {
1415
+ agent: agentType,
1416
+ success: false,
1417
+ path: cluster.configPath,
1418
+ error: errorMsg
1419
+ });
1420
+ }
1421
+ }
1422
+ }
1423
+ return agentTypes.map((agentType) => resultsByAgent.get(agentType));
1424
+ };
1425
+ var installToCompatibleAgents = (serverName, serverConfig, options) => {
1426
+ const { allAgents, incompatible = [], global: isGlobal, cwd } = options;
1427
+ const incompatibleMap = new Map(incompatible.map((item) => [item.agent, item.reason]));
1428
+ const compatibleAgents = allAgents.filter((a) => !incompatibleMap.has(a));
1429
+ const installedResults = installMcpServerForAgents(serverName, serverConfig, compatibleAgents, {
1430
+ global: isGlobal,
1431
+ cwd
1432
+ });
1433
+ const installedMap = new Map(installedResults.map((r) => [r.agent, r]));
1434
+ return allAgents.map((agentType) => {
1435
+ const incompatibleReason = incompatibleMap.get(agentType);
1436
+ if (incompatibleReason) {
1437
+ return {
1438
+ agent: agentType,
1439
+ success: false,
1440
+ path: "",
1441
+ error: incompatibleReason
1442
+ };
1443
+ }
1444
+ return installedMap.get(agentType);
1445
+ });
1446
+ };
1305
1447
 
1306
1448
  // src/utils/parse-mcp-agent-list.ts
1307
1449
  var parseMcpAgentList = (input7) => {
@@ -1505,18 +1647,11 @@ var installMcpServer = (options) => {
1505
1647
  cwd,
1506
1648
  transport: requestedTransport
1507
1649
  });
1508
- const incompatibleMap = new Map(incompatible.map((item) => [item.agent, item.reason]));
1509
- const results = allAgents.map((agentType) => {
1510
- const incompatibleReason = incompatibleMap.get(agentType);
1511
- if (incompatibleReason) {
1512
- return {
1513
- agent: agentType,
1514
- success: false,
1515
- path: "",
1516
- error: incompatibleReason
1517
- };
1518
- }
1519
- return installMcpServerForAgent(serverName, serverConfig, agentType, { global: isGlobal, cwd });
1650
+ const results = installToCompatibleAgents(serverName, serverConfig, {
1651
+ allAgents,
1652
+ incompatible,
1653
+ global: isGlobal,
1654
+ cwd
1520
1655
  });
1521
1656
  return { serverName, config: serverConfig, results };
1522
1657
  };
@@ -1546,9 +1681,15 @@ var listInstalledMcpServers = (options = {}) => {
1546
1681
  var removeMcpServerFromAgent = (serverName, agentType, options = {}) => {
1547
1682
  const agent = getMcpAgentConfig(agentType);
1548
1683
  const { target } = agentConfigStore.resolveTarget(agent, options);
1684
+ const coHosted = getCoHostedAgents(agentType, options);
1549
1685
  try {
1550
1686
  const { removed } = agentConfigStore.removeServer(agent, serverName, options);
1551
- return { agent: agentType, path: target.configPath, removed };
1687
+ return {
1688
+ agent: agentType,
1689
+ path: target.configPath,
1690
+ removed,
1691
+ coAffectedAgents: removed && coHosted.length > 0 ? coHosted : void 0
1692
+ };
1552
1693
  } catch (error) {
1553
1694
  return {
1554
1695
  agent: agentType,
@@ -1565,24 +1706,153 @@ var removeMcpServer = (options) => {
1565
1706
  global: options.global,
1566
1707
  cwd: options.cwd
1567
1708
  });
1709
+ const clusters = resolveConfigClusters(allAgents, {
1710
+ global: options.global,
1711
+ cwd: options.cwd
1712
+ });
1568
1713
  const results = [];
1569
- for (const agentType of allAgents) {
1570
- const result = removeMcpServerFromAgent(options.name, agentType, {
1571
- global: options.global,
1572
- cwd: options.cwd
1573
- });
1574
- if (result.removed || result.error) results.push(result);
1714
+ for (const cluster of clusters) {
1715
+ const primaryAgentType = cluster.targetAgents[0];
1716
+ const primaryAgent = getMcpAgentConfig(primaryAgentType);
1717
+ try {
1718
+ const { removed } = agentConfigStore.removeServer(primaryAgent, options.name, {
1719
+ global: options.global,
1720
+ cwd: options.cwd
1721
+ });
1722
+ if (removed) {
1723
+ for (const agentType of cluster.targetAgents) {
1724
+ results.push({
1725
+ agent: agentType,
1726
+ path: cluster.configPath,
1727
+ removed: true,
1728
+ coAffectedAgents: cluster.coHostedAgents.length > 0 ? cluster.coHostedAgents : void 0
1729
+ });
1730
+ }
1731
+ }
1732
+ } catch (error) {
1733
+ const errorMsg = toErrorMessage(error);
1734
+ for (const agentType of cluster.targetAgents) {
1735
+ results.push({
1736
+ agent: agentType,
1737
+ path: cluster.configPath,
1738
+ removed: false,
1739
+ error: errorMsg
1740
+ });
1741
+ }
1742
+ }
1575
1743
  }
1576
1744
  return results;
1577
1745
  };
1578
1746
 
1747
+ // src/update-mcp-server.ts
1748
+ var toRemoteServerConfig = (config, defaultTransport = "http") => {
1749
+ const {
1750
+ command: _droppedCommand,
1751
+ args: _droppedArgs,
1752
+ env: _droppedEnv,
1753
+ ...remoteConfig
1754
+ } = config;
1755
+ return {
1756
+ ...remoteConfig,
1757
+ type: remoteConfig.type ?? defaultTransport
1758
+ };
1759
+ };
1760
+ var toStdioServerConfig = (config) => {
1761
+ const {
1762
+ url: _droppedUrl,
1763
+ type: _droppedType,
1764
+ headers: _droppedHeaders,
1765
+ ...stdioConfig
1766
+ } = config;
1767
+ return stdioConfig;
1768
+ };
1769
+ var detectUpdateTransition = (incoming, previous) => {
1770
+ if (!previous) {
1771
+ return incoming.url ? "switch-to-remote" : "switch-to-stdio";
1772
+ }
1773
+ if (incoming.url && !incoming.command) {
1774
+ return "switch-to-remote";
1775
+ }
1776
+ if (incoming.command && !incoming.url) {
1777
+ return "switch-to-stdio";
1778
+ }
1779
+ if (incoming.url || !incoming.command && previous.url) {
1780
+ return "merge-remote";
1781
+ }
1782
+ return "merge-stdio";
1783
+ };
1784
+ var sanitizeUpdatedServerConfig = (incoming, previous) => {
1785
+ const transition = detectUpdateTransition(incoming, previous);
1786
+ const targetTransport = incoming.type ?? previous?.type ?? "http";
1787
+ switch (transition) {
1788
+ case "switch-to-remote": {
1789
+ const cleanBase = previous ? toRemoteServerConfig(previous, targetTransport) : {};
1790
+ return toRemoteServerConfig({ ...cleanBase, ...incoming }, targetTransport);
1791
+ }
1792
+ case "switch-to-stdio": {
1793
+ const cleanBase = previous ? toStdioServerConfig(previous) : {};
1794
+ return toStdioServerConfig({ ...cleanBase, ...incoming });
1795
+ }
1796
+ case "merge-remote": {
1797
+ return toRemoteServerConfig({ ...previous, ...incoming }, targetTransport);
1798
+ }
1799
+ case "merge-stdio": {
1800
+ return toStdioServerConfig({ ...previous, ...incoming });
1801
+ }
1802
+ }
1803
+ };
1804
+ var updateMcpServer = (options) => {
1805
+ const isGlobal = options.global ?? false;
1806
+ const cwd = options.cwd ?? process.cwd();
1807
+ let previousConfig = options.previousConfig;
1808
+ if (!previousConfig) {
1809
+ const existing = listInstalledMcpServers({
1810
+ global: isGlobal,
1811
+ cwd,
1812
+ agents: options.agents
1813
+ });
1814
+ const found = existing.find((s) => s.serverName === options.serverName && s.serverConfig);
1815
+ if (found) {
1816
+ previousConfig = found.serverConfig;
1817
+ }
1818
+ }
1819
+ const serverConfig = sanitizeUpdatedServerConfig(options.config, previousConfig);
1820
+ let targetAgents = options.agents;
1821
+ if (!targetAgents || targetAgents.length === 0) {
1822
+ const existing = listInstalledMcpServers({ global: isGlobal, cwd });
1823
+ targetAgents = existing.filter((s) => s.serverName === options.serverName).map((s) => s.agent);
1824
+ }
1825
+ const requestedTransport = serverConfig.url ? serverConfig.type ?? "http" : "stdio";
1826
+ const { allAgents, incompatible } = resolveTargetAgents({
1827
+ requested: targetAgents,
1828
+ global: isGlobal,
1829
+ cwd,
1830
+ transport: requestedTransport
1831
+ });
1832
+ const results = installToCompatibleAgents(options.serverName, serverConfig, {
1833
+ allAgents,
1834
+ incompatible,
1835
+ global: isGlobal,
1836
+ cwd
1837
+ });
1838
+ return {
1839
+ serverName: options.serverName,
1840
+ config: serverConfig,
1841
+ results,
1842
+ incompatible
1843
+ };
1844
+ };
1845
+
1579
1846
  // src/interactive/main-menu.ts
1580
- var import_prompts11 = require("@inquirer/prompts");
1581
- var import_picocolors11 = __toESM(require("picocolors"), 1);
1847
+ var import_prompts10 = require("@inquirer/prompts");
1848
+ var import_picocolors15 = __toESM(require("picocolors"), 1);
1582
1849
 
1583
1850
  // src/interactive/wizard-add.ts
1584
- var import_prompts8 = require("@inquirer/prompts");
1585
- var import_picocolors8 = __toESM(require("picocolors"), 1);
1851
+ var import_prompts7 = require("@inquirer/prompts");
1852
+ var import_picocolors11 = __toESM(require("picocolors"), 1);
1853
+
1854
+ // src/utils/co-hosted-feedback.ts
1855
+ var import_picocolors2 = __toESM(require("picocolors"), 1);
1586
1856
 
1587
1857
  // src/utils/logger.ts
1588
1858
  var import_picocolors = __toESM(require("picocolors"), 1);
@@ -1601,13 +1871,269 @@ var logger = {
1601
1871
  }
1602
1872
  };
1603
1873
 
1874
+ // src/utils/co-hosted-feedback.ts
1875
+ var formatCoHostedBadge = (kind, agents) => {
1876
+ if (!agents || agents.length === 0) return "";
1877
+ const label = kind === "configured" ? "co-configured" : "co-affected";
1878
+ return ` ${import_picocolors2.default.yellow(`(${label}: ${agents.join(", ")})`)}`;
1879
+ };
1880
+ var logCoHostedNotice = (kind, agents) => {
1881
+ if (!agents || agents.length === 0) return;
1882
+ const actionText = kind === "configured" ? "Also configured for" : "Also affects";
1883
+ logger.info(
1884
+ ` ${import_picocolors2.default.dim("Note:")} ${actionText} co-hosted agent(s): ${import_picocolors2.default.yellow(agents.join(", "))}`
1885
+ );
1886
+ };
1887
+
1604
1888
  // src/interactive/prompts/agents.ts
1605
- var import_prompts2 = require("@inquirer/prompts");
1889
+ var import_picocolors6 = __toESM(require("picocolors"), 1);
1890
+
1891
+ // src/interactive/utils/build-linked-agent-choices.ts
1606
1892
  var import_picocolors3 = __toESM(require("picocolors"), 1);
1893
+ var buildLinkedAgentChoices = (options) => {
1894
+ const { agents, checkedAgents, detectedAgents = [], scopeOptions = {} } = options;
1895
+ const alignedCheckedSet = new Set(checkedAgents);
1896
+ for (const agent of checkedAgents) {
1897
+ const coHosted = getCoHostedAgents(agent, scopeOptions);
1898
+ for (const co of coHosted) {
1899
+ if (agents.includes(co)) {
1900
+ alignedCheckedSet.add(co);
1901
+ }
1902
+ }
1903
+ }
1904
+ return agents.map((agent) => {
1905
+ const config = getMcpAgentConfig(agent);
1906
+ const displayName = config?.displayName ?? agent;
1907
+ const isDetected = detectedAgents.includes(agent);
1908
+ const coHosted = getCoHostedAgents(agent, scopeOptions).filter(
1909
+ (co) => agents.includes(co)
1910
+ );
1911
+ const detectedBadge = isDetected ? import_picocolors3.default.green(" [detected]") : "";
1912
+ const sharedBadge = coHosted.length > 0 ? import_picocolors3.default.dim(` [shared: ${coHosted.join(", ")}]`) : "";
1913
+ const label = `${displayName} ${import_picocolors3.default.dim(`(${agent})`)}${detectedBadge}${sharedBadge}`;
1914
+ return {
1915
+ name: label,
1916
+ value: agent,
1917
+ checked: alignedCheckedSet.has(agent),
1918
+ linkedValues: coHosted,
1919
+ description: coHosted.length > 0 ? `Linked with ${coHosted.map((a) => getMcpAgentConfig(a).displayName).join(", ")} (shared configuration)` : void 0
1920
+ };
1921
+ });
1922
+ };
1923
+
1924
+ // src/interactive/prompts/linked-checkbox.ts
1925
+ var import_core = require("@inquirer/core");
1926
+ var import_picocolors4 = __toESM(require("picocolors"), 1);
1927
+ var defaultTheme = {
1928
+ icon: {
1929
+ checked: import_picocolors4.default.green("[x]"),
1930
+ unchecked: import_picocolors4.default.dim("[ ]"),
1931
+ cursor: import_picocolors4.default.cyan(">"),
1932
+ disabledChecked: import_picocolors4.default.dim("[x]"),
1933
+ disabledUnchecked: import_picocolors4.default.dim("[-]")
1934
+ },
1935
+ style: {
1936
+ disabled: (text) => import_picocolors4.default.dim(text),
1937
+ renderSelectedChoices: (selectedChoices) => selectedChoices.map((choice) => choice.short).join(", "),
1938
+ description: (text) => import_picocolors4.default.cyan(text),
1939
+ keysHelpTip: (keys) => keys.map(([key, action]) => `${import_picocolors4.default.bold(key)} ${import_picocolors4.default.dim(action)}`).join(import_picocolors4.default.dim(" | ")),
1940
+ highlight: (text) => import_picocolors4.default.cyan(text)
1941
+ },
1942
+ i18n: {
1943
+ disabledError: "This option is disabled and cannot be toggled."
1944
+ }
1945
+ };
1946
+ function isSelectable(item) {
1947
+ return !import_core.Separator.isSeparator(item) && !item.disabled;
1948
+ }
1949
+ function isNavigable(item) {
1950
+ return !import_core.Separator.isSeparator(item);
1951
+ }
1952
+ function isChecked(item) {
1953
+ return !import_core.Separator.isSeparator(item) && item.checked;
1954
+ }
1955
+ function normalizeChoices(choices) {
1956
+ return choices.map((choice) => {
1957
+ if (import_core.Separator.isSeparator(choice)) {
1958
+ return choice;
1959
+ }
1960
+ if (typeof choice !== "object" || choice === null || !("value" in choice)) {
1961
+ const name2 = String(choice);
1962
+ return {
1963
+ value: choice,
1964
+ name: name2,
1965
+ short: name2,
1966
+ checkedName: name2,
1967
+ disabled: false,
1968
+ checked: false,
1969
+ linkedValues: []
1970
+ };
1971
+ }
1972
+ const name = choice.name ?? String(choice.value);
1973
+ return {
1974
+ value: choice.value,
1975
+ name,
1976
+ short: choice.short ?? name,
1977
+ checkedName: choice.checkedName ?? name,
1978
+ description: choice.description,
1979
+ disabled: choice.disabled ?? false,
1980
+ checked: choice.checked ?? false,
1981
+ linkedValues: choice.linkedValues ?? []
1982
+ };
1983
+ });
1984
+ }
1985
+ var linkedCheckbox = (0, import_core.createPrompt)(
1986
+ (config, done) => {
1987
+ const { pageSize = 10, loop = true, required, validate = () => true } = config;
1988
+ const theme = (0, import_core.makeTheme)(defaultTheme, config.theme);
1989
+ const [status, setStatus] = (0, import_core.useState)("idle");
1990
+ const prefix = (0, import_core.usePrefix)({ status, theme });
1991
+ const [items, setItems] = (0, import_core.useState)(() => normalizeChoices(config.choices));
1992
+ const bounds = (0, import_core.useMemo)(() => {
1993
+ const first = items.findIndex(isNavigable);
1994
+ let last = -1;
1995
+ for (let i = items.length - 1; i >= 0; i--) {
1996
+ if (isNavigable(items[i])) {
1997
+ last = i;
1998
+ break;
1999
+ }
2000
+ }
2001
+ if (first === -1 || last === -1) {
2002
+ throw new import_core.ValidationError("[linkedCheckbox prompt] No selectable choices.");
2003
+ }
2004
+ return { first, last };
2005
+ }, [items]);
2006
+ const [active, setActive] = (0, import_core.useState)(bounds.first);
2007
+ const [errorMsg, setError] = (0, import_core.useState)();
2008
+ const toggleWithLinked = (targetIndex) => {
2009
+ const targetItem = items[targetIndex];
2010
+ if (!targetItem || import_core.Separator.isSeparator(targetItem) || targetItem.disabled) {
2011
+ return;
2012
+ }
2013
+ const nextChecked = !targetItem.checked;
2014
+ const targetValue = targetItem.value;
2015
+ const linked = new Set(targetItem.linkedValues);
2016
+ setItems(
2017
+ (prevItems) => prevItems.map((item) => {
2018
+ if (import_core.Separator.isSeparator(item) || item.disabled) {
2019
+ return item;
2020
+ }
2021
+ const isTargetOrLinked = item.value === targetValue || linked.has(item.value) || item.linkedValues.includes(targetValue);
2022
+ if (isTargetOrLinked) {
2023
+ return { ...item, checked: nextChecked };
2024
+ }
2025
+ return item;
2026
+ })
2027
+ );
2028
+ };
2029
+ (0, import_core.useKeypress)(async (key) => {
2030
+ if ((0, import_core.isEnterKey)(key)) {
2031
+ const selection = items.filter(isChecked);
2032
+ const isValid = await validate([...selection]);
2033
+ if (required && selection.length === 0) {
2034
+ setError("At least one choice must be selected");
2035
+ } else if (isValid === true) {
2036
+ setStatus("done");
2037
+ done(selection.map((choice) => choice.value));
2038
+ } else {
2039
+ setError(typeof isValid === "string" ? isValid : "You must select a valid value");
2040
+ }
2041
+ } else if ((0, import_core.isUpKey)(key) || (0, import_core.isDownKey)(key)) {
2042
+ if (errorMsg) setError(void 0);
2043
+ if (loop || (0, import_core.isUpKey)(key) && active !== bounds.first || (0, import_core.isDownKey)(key) && active !== bounds.last) {
2044
+ const offset = (0, import_core.isUpKey)(key) ? -1 : 1;
2045
+ let next = active;
2046
+ do {
2047
+ next = (next + offset + items.length) % items.length;
2048
+ } while (!isNavigable(items[next]));
2049
+ setActive(next);
2050
+ }
2051
+ } else if ((0, import_core.isSpaceKey)(key)) {
2052
+ const activeItem = items[active];
2053
+ if (activeItem && !import_core.Separator.isSeparator(activeItem)) {
2054
+ if (activeItem.disabled) {
2055
+ setError(theme.i18n.disabledError);
2056
+ } else {
2057
+ setError(void 0);
2058
+ toggleWithLinked(active);
2059
+ }
2060
+ }
2061
+ } else if (key.name === "a") {
2062
+ const hasUnchecked = items.some((choice) => isSelectable(choice) && !choice.checked);
2063
+ setItems(
2064
+ (prevItems) => prevItems.map((item) => isSelectable(item) ? { ...item, checked: hasUnchecked } : item)
2065
+ );
2066
+ } else if ((0, import_core.isNumberKey)(key)) {
2067
+ const selectedIndex = Number(key.name) - 1;
2068
+ let selectableIndex = -1;
2069
+ const position = items.findIndex((item) => {
2070
+ if (import_core.Separator.isSeparator(item)) return false;
2071
+ selectableIndex++;
2072
+ return selectableIndex === selectedIndex;
2073
+ });
2074
+ const selectedItem = items[position];
2075
+ if (selectedItem && isSelectable(selectedItem)) {
2076
+ setActive(position);
2077
+ setError(void 0);
2078
+ toggleWithLinked(position);
2079
+ }
2080
+ }
2081
+ });
2082
+ const message = theme.style.message(config.message, status);
2083
+ let description;
2084
+ const page = (0, import_core.usePagination)({
2085
+ items,
2086
+ active,
2087
+ renderItem({ item, isActive }) {
2088
+ if (import_core.Separator.isSeparator(item)) {
2089
+ return ` ${item.separator}`;
2090
+ }
2091
+ const cursor = isActive ? theme.icon.cursor : " ";
2092
+ if (item.disabled) {
2093
+ const disabledLabel = typeof item.disabled === "string" ? item.disabled : "(disabled)";
2094
+ const checkbox2 = item.checked ? theme.icon.disabledChecked : theme.icon.disabledUnchecked;
2095
+ return theme.style.disabled(`${cursor} ${checkbox2} ${item.name} ${disabledLabel}`);
2096
+ }
2097
+ if (isActive) {
2098
+ description = item.description;
2099
+ }
2100
+ const checkbox = item.checked ? theme.icon.checked : theme.icon.unchecked;
2101
+ const name = item.checked ? item.checkedName : item.name;
2102
+ const color = isActive ? theme.style.highlight : (x) => x;
2103
+ return color(`${cursor} ${checkbox} ${name}`);
2104
+ },
2105
+ pageSize,
2106
+ loop
2107
+ });
2108
+ if (status === "done") {
2109
+ const selection = items.filter(isChecked);
2110
+ const answer = theme.style.answer(theme.style.renderSelectedChoices(selection, items));
2111
+ return [prefix, message, answer].filter(Boolean).join(" ");
2112
+ }
2113
+ const helpLine = theme.style.keysHelpTip([
2114
+ ["up/down", "navigate"],
2115
+ ["space", "toggle"],
2116
+ ["a", "all"],
2117
+ ["enter", "submit"]
2118
+ ]);
2119
+ const lines = [
2120
+ [prefix, message].filter(Boolean).join(" "),
2121
+ page,
2122
+ helpLine
2123
+ ];
2124
+ if (description) {
2125
+ lines.push(theme.style.description(description));
2126
+ }
2127
+ if (errorMsg) {
2128
+ lines.push(theme.style.error(errorMsg));
2129
+ }
2130
+ return lines.join("\n");
2131
+ }
2132
+ );
1607
2133
 
1608
2134
  // src/interactive/prompts/scope.ts
1609
2135
  var import_prompts = require("@inquirer/prompts");
1610
- var import_picocolors2 = __toESM(require("picocolors"), 1);
2136
+ var import_picocolors5 = __toESM(require("picocolors"), 1);
1611
2137
  var promptScope = async (options = {}) => {
1612
2138
  const initialGlobal = options.defaultGlobal ?? options.global;
1613
2139
  if (initialGlobal !== void 0) {
@@ -1618,11 +2144,11 @@ var promptScope = async (options = {}) => {
1618
2144
  message: options.message ?? "Select MCP scope:",
1619
2145
  choices: [
1620
2146
  {
1621
- name: `Current Project - ${import_picocolors2.default.dim(cwd)}`,
2147
+ name: `Current Project - ${import_picocolors5.default.dim(cwd)}`,
1622
2148
  value: false
1623
2149
  },
1624
2150
  {
1625
- name: `Global User Config - ${import_picocolors2.default.dim("applies across all projects")}`,
2151
+ name: `Global User Config - ${import_picocolors5.default.dim("applies across all projects")}`,
1626
2152
  value: true
1627
2153
  }
1628
2154
  ]
@@ -1642,26 +2168,23 @@ var promptScopeAndAgents = async (options = {}) => {
1642
2168
  cwd
1643
2169
  });
1644
2170
  const detected = resolution.detected;
1645
- const availableAgentTypes = isGlobal ? getMcpAgentTypes() : getMcpAgentsSupportingProjectScope();
2171
+ const rawAvailable = isGlobal ? getMcpAgentTypes() : getMcpAgentsSupportingProjectScope();
2172
+ const availableAgentTypes = sortAgentsWithClusters(rawAvailable, { global: isGlobal, cwd });
1646
2173
  if (detected.length > 0) {
1647
2174
  logger.info(
1648
- `Detected configured agents: ${import_picocolors3.default.cyan(detected.map((a) => getMcpAgentConfig(a).displayName).join(", "))}`
2175
+ `Detected configured agents: ${import_picocolors6.default.cyan(detected.map((a) => getMcpAgentConfig(a).displayName).join(", "))}`
1649
2176
  );
1650
2177
  } else {
1651
2178
  logger.warn(`No active ${isGlobal ? "global" : "project"} agents detected`);
1652
2179
  }
1653
2180
  const defaultChecked = options.defaultAgents && options.defaultAgents.length > 0 ? options.defaultAgents : detected;
1654
- const choices = availableAgentTypes.map((agentType) => {
1655
- const config = getMcpAgentConfig(agentType);
1656
- const isDetected = detected.includes(agentType);
1657
- const label = `${config.displayName} ${import_picocolors3.default.dim(`(${agentType})`)}${isDetected ? import_picocolors3.default.green(" [detected]") : ""}`;
1658
- return {
1659
- name: label,
1660
- value: agentType,
1661
- checked: defaultChecked.includes(agentType)
1662
- };
2181
+ const choices = buildLinkedAgentChoices({
2182
+ agents: availableAgentTypes,
2183
+ checkedAgents: defaultChecked,
2184
+ detectedAgents: detected,
2185
+ scopeOptions: { global: isGlobal, cwd }
1663
2186
  });
1664
- const selectedAgents = await (0, import_prompts2.checkbox)({
2187
+ const selectedAgents = await linkedCheckbox({
1665
2188
  message: "Select target agents (Space to select, Enter to confirm):",
1666
2189
  choices,
1667
2190
  validate: (chosen) => {
@@ -1678,7 +2201,7 @@ var promptScopeAndAgents = async (options = {}) => {
1678
2201
  };
1679
2202
 
1680
2203
  // src/interactive/prompts/args.ts
1681
- var import_prompts3 = require("@inquirer/prompts");
2204
+ var import_prompts2 = require("@inquirer/prompts");
1682
2205
  var parseArgsString = (rawText) => {
1683
2206
  const matches = rawText.match(/(?:[^\s"']+|"[^"]*"|'[^']*')+/g);
1684
2207
  if (!matches) return [];
@@ -1693,14 +2216,14 @@ var promptArgsConfig = async (initialArgs = []) => {
1693
2216
  if (initialArgs.length > 0) {
1694
2217
  return initialArgs;
1695
2218
  }
1696
- const needArgs = await (0, import_prompts3.confirm)({
2219
+ const needArgs = await (0, import_prompts2.confirm)({
1697
2220
  message: "Configure command arguments (e.g. file paths, connection strings)?",
1698
2221
  default: false
1699
2222
  });
1700
2223
  if (!needArgs) {
1701
2224
  return [];
1702
2225
  }
1703
- const raw = await (0, import_prompts3.input)({
2226
+ const raw = await (0, import_prompts2.input)({
1704
2227
  message: "Enter command arguments (space-separated, wrap paths with spaces in quotes):",
1705
2228
  validate: (val) => val.trim() ? true : "Arguments cannot be empty"
1706
2229
  });
@@ -1711,7 +2234,7 @@ var formatArgsString = (args) => {
1711
2234
  };
1712
2235
  var promptEditArgs = async (currentArgs = []) => {
1713
2236
  const defaultStr = formatArgsString(currentArgs);
1714
- const raw = await (0, import_prompts3.input)({
2237
+ const raw = await (0, import_prompts2.input)({
1715
2238
  message: "Edit command arguments (space-separated, wrap paths with spaces in quotes, leave empty to clear):",
1716
2239
  default: defaultStr
1717
2240
  });
@@ -1723,17 +2246,37 @@ var promptEditArgs = async (currentArgs = []) => {
1723
2246
  };
1724
2247
 
1725
2248
  // src/interactive/prompts/env.ts
1726
- var import_prompts6 = require("@inquirer/prompts");
1727
- var import_picocolors6 = __toESM(require("picocolors"), 1);
2249
+ var import_prompts5 = require("@inquirer/prompts");
2250
+ var import_picocolors9 = __toESM(require("picocolors"), 1);
2251
+
2252
+ // src/utils/mask-secret.ts
2253
+ var SECRET_KEY_PATTERN = /(token|key|secret|password|passwd|auth|credential)/i;
2254
+ var maskSecretValue = (key, value) => {
2255
+ if (!SECRET_KEY_PATTERN.test(key) || value.length <= 4) {
2256
+ return value;
2257
+ }
2258
+ return `${value.slice(0, 2)}***${value.slice(-2)}`;
2259
+ };
2260
+ var SECRET_HEADER_PATTERN = /(authorization|token|key|secret|auth)/i;
2261
+ var maskSecretHeader = (key, value) => {
2262
+ if (!SECRET_HEADER_PATTERN.test(key) || value.length <= 8) {
2263
+ return value;
2264
+ }
2265
+ return `${value.slice(0, 4)}***${value.slice(-3)}`;
2266
+ };
2267
+
2268
+ // src/interactive/prompts/kv.ts
2269
+ var import_prompts4 = require("@inquirer/prompts");
2270
+ var import_picocolors8 = __toESM(require("picocolors"), 1);
1728
2271
 
1729
2272
  // src/interactive/prompts/multiline.ts
1730
2273
  var import_node_readline = require("readline");
1731
- var import_prompts4 = require("@inquirer/prompts");
1732
- var import_picocolors4 = __toESM(require("picocolors"), 1);
2274
+ var import_prompts3 = require("@inquirer/prompts");
2275
+ var import_picocolors7 = __toESM(require("picocolors"), 1);
1733
2276
  var readMultilineTextFromTerminal = async (message, endHint = "When done pasting, enter END on a new line or press Enter twice to finish") => {
1734
- console.log(import_picocolors4.default.cyan(`
2277
+ console.log(import_picocolors7.default.cyan(`
1735
2278
  ${message}`));
1736
- console.log(import_picocolors4.default.dim(` (Hint: ${endHint})
2279
+ console.log(import_picocolors7.default.dim(` (Hint: ${endHint})
1737
2280
  `));
1738
2281
  return new Promise((resolve) => {
1739
2282
  const rl = (0, import_node_readline.createInterface)({
@@ -1777,7 +2320,7 @@ ${message}`));
1777
2320
  };
1778
2321
  var promptEditorText = async (options) => {
1779
2322
  try {
1780
- return await (0, import_prompts4.editor)({
2323
+ return await (0, import_prompts3.editor)({
1781
2324
  message: options.message,
1782
2325
  default: options.defaultText ?? "",
1783
2326
  postfix: options.postfix
@@ -1788,24 +2331,22 @@ var promptEditorText = async (options) => {
1788
2331
  };
1789
2332
 
1790
2333
  // src/interactive/prompts/kv.ts
1791
- var import_prompts5 = require("@inquirer/prompts");
1792
- var import_picocolors5 = __toESM(require("picocolors"), 1);
1793
2334
  var promptEditKeyValueConfig = async (currentItems = {}, options) => {
1794
2335
  let items = { ...currentItems };
1795
2336
  while (true) {
1796
2337
  const keys = Object.keys(items);
1797
2338
  console.log();
1798
2339
  if (keys.length === 0) {
1799
- console.log(import_picocolors5.default.dim(` No ${options.itemsNoun} configured.`));
2340
+ console.log(import_picocolors8.default.dim(` No ${options.itemsNoun} configured.`));
1800
2341
  } else {
1801
- console.log(import_picocolors5.default.cyan(import_picocolors5.default.bold(` Configured ${options.title} (${keys.length}):`)));
2342
+ console.log(import_picocolors8.default.cyan(import_picocolors8.default.bold(` Configured ${options.title} (${keys.length}):`)));
1802
2343
  for (const [k, v] of Object.entries(items)) {
1803
2344
  const sep = options.separator === "=" ? "=" : ": ";
1804
- console.log(` ${import_picocolors5.default.bold(k)}${sep}${import_picocolors5.default.dim(options.maskValue(k, v))}`);
2345
+ console.log(` ${import_picocolors8.default.bold(k)}${sep}${import_picocolors8.default.dim(options.maskValue(k, v))}`);
1805
2346
  }
1806
2347
  }
1807
2348
  console.log();
1808
- const choice = await (0, import_prompts5.select)({
2349
+ const choice = await (0, import_prompts4.select)({
1809
2350
  message: `Manage ${options.itemsNoun}:`,
1810
2351
  choices: [
1811
2352
  {
@@ -1852,7 +2393,7 @@ var promptEditKeyValueConfig = async (currentItems = {}, options) => {
1852
2393
  items = parsed;
1853
2394
  logger.success(`${options.title} updated (${Object.keys(items).length} total)`);
1854
2395
  } else if (choice === "upsert") {
1855
- const key = await (0, import_prompts5.input)({
2396
+ const key = await (0, import_prompts4.input)({
1856
2397
  message: options.keyPromptMessage,
1857
2398
  validate: (val) => {
1858
2399
  const trimmed = val.trim();
@@ -1866,7 +2407,7 @@ var promptEditKeyValueConfig = async (currentItems = {}, options) => {
1866
2407
  const isSecret = options.isSecretKey(trimmedKey);
1867
2408
  let newVal;
1868
2409
  if (isSecret) {
1869
- newVal = await (0, import_prompts5.password)({
2410
+ newVal = await (0, import_prompts4.password)({
1870
2411
  message: existingVal !== void 0 ? `New value for (${trimmedKey}) [leave empty to keep current]:` : `${options.valuePromptMessage} for (${trimmedKey}) [sensitive content masked]:`,
1871
2412
  mask: "*"
1872
2413
  });
@@ -1874,15 +2415,15 @@ var promptEditKeyValueConfig = async (currentItems = {}, options) => {
1874
2415
  newVal = existingVal;
1875
2416
  }
1876
2417
  } else {
1877
- newVal = await (0, import_prompts5.input)({
2418
+ newVal = await (0, import_prompts4.input)({
1878
2419
  message: `${options.valuePromptMessage} for (${trimmedKey}):`,
1879
2420
  default: existingVal
1880
2421
  });
1881
2422
  }
1882
2423
  items[trimmedKey] = newVal;
1883
- logger.success(`${existingVal !== void 0 ? "Updated" : "Added"}: ${import_picocolors5.default.cyan(trimmedKey)}`);
2424
+ logger.success(`${existingVal !== void 0 ? "Updated" : "Added"}: ${import_picocolors8.default.cyan(trimmedKey)}`);
1884
2425
  } else if (choice === "delete") {
1885
- const toDelete = await (0, import_prompts5.select)({
2426
+ const toDelete = await (0, import_prompts4.select)({
1886
2427
  message: `Select ${options.itemNoun} to delete:`,
1887
2428
  choices: [
1888
2429
  ...keys.map((k) => ({ name: k, value: k })),
@@ -1891,7 +2432,7 @@ var promptEditKeyValueConfig = async (currentItems = {}, options) => {
1891
2432
  });
1892
2433
  if (toDelete !== "__cancel__") {
1893
2434
  delete items[toDelete];
1894
- logger.success(`Deleted: ${import_picocolors5.default.cyan(toDelete)}`);
2435
+ logger.success(`Deleted: ${import_picocolors8.default.cyan(toDelete)}`);
1895
2436
  }
1896
2437
  } else if (choice === "paste") {
1897
2438
  const pasted = await readMultilineTextFromTerminal(options.pasteMessage);
@@ -1901,7 +2442,7 @@ var promptEditKeyValueConfig = async (currentItems = {}, options) => {
1901
2442
  logger.warn(`No valid ${options.itemsNoun} recognized`);
1902
2443
  } else {
1903
2444
  if (keys.length > 0) {
1904
- const pasteMode = await (0, import_prompts5.select)({
2445
+ const pasteMode = await (0, import_prompts4.select)({
1905
2446
  message: `How to apply pasted ${options.itemsNoun}?`,
1906
2447
  choices: [
1907
2448
  { name: `Merge with existing ${options.itemsNoun}`, value: "merge" },
@@ -1916,10 +2457,10 @@ var promptEditKeyValueConfig = async (currentItems = {}, options) => {
1916
2457
  } else {
1917
2458
  items = parsed;
1918
2459
  }
1919
- logger.success(`Successfully applied ${import_picocolors5.default.cyan(String(count))} ${options.itemsNoun}`);
2460
+ logger.success(`Successfully applied ${import_picocolors8.default.cyan(String(count))} ${options.itemsNoun}`);
1920
2461
  }
1921
2462
  } else if (choice === "clear") {
1922
- const confirmClear = await (0, import_prompts5.confirm)({
2463
+ const confirmClear = await (0, import_prompts4.confirm)({
1923
2464
  message: `Are you sure you want to clear all ${options.itemsNoun}?`,
1924
2465
  default: false
1925
2466
  });
@@ -1932,13 +2473,6 @@ var promptEditKeyValueConfig = async (currentItems = {}, options) => {
1932
2473
  };
1933
2474
 
1934
2475
  // src/interactive/prompts/env.ts
1935
- var SECRET_KEY_PATTERN = /(token|key|secret|password|passwd|auth|credential)/i;
1936
- var maskSecretValue = (key, value) => {
1937
- if (!SECRET_KEY_PATTERN.test(key) || value.length <= 4) {
1938
- return value;
1939
- }
1940
- return `${value.slice(0, 2)}***${value.slice(-2)}`;
1941
- };
1942
2476
  var formatEnvText = (env) => {
1943
2477
  return Object.entries(env).map(([key, value]) => {
1944
2478
  if (/[\s"']/.test(value)) {
@@ -1972,9 +2506,9 @@ var promptEnvConfig = async (initialEnv = {}) => {
1972
2506
  const env = { ...initialEnv };
1973
2507
  const initialCount = Object.keys(env).length;
1974
2508
  if (initialCount > 0) {
1975
- logger.info(`Includes ${import_picocolors6.default.cyan(String(initialCount))} preset environment variables`);
2509
+ logger.info(`Includes ${import_picocolors9.default.cyan(String(initialCount))} preset environment variables`);
1976
2510
  }
1977
- const mode = await (0, import_prompts6.select)({
2511
+ const mode = await (0, import_prompts5.select)({
1978
2512
  message: "Configure environment variables?",
1979
2513
  choices: [
1980
2514
  {
@@ -2010,16 +2544,16 @@ var promptEnvConfig = async (initialEnv = {}) => {
2010
2544
  logger.warn("No valid KEY=VALUE pairs recognized");
2011
2545
  } else {
2012
2546
  Object.assign(env, parsed);
2013
- logger.success(`Successfully parsed ${import_picocolors6.default.cyan(String(count))} environment variables:`);
2547
+ logger.success(`Successfully parsed ${import_picocolors9.default.cyan(String(count))} environment variables:`);
2014
2548
  for (const [k, v] of Object.entries(parsed)) {
2015
- console.log(` ${import_picocolors6.default.bold(k)}=${import_picocolors6.default.dim(maskSecretValue(k, v))}`);
2549
+ console.log(` ${import_picocolors9.default.bold(k)}=${import_picocolors9.default.dim(maskSecretValue(k, v))}`);
2016
2550
  }
2017
2551
  }
2018
2552
  return env;
2019
2553
  }
2020
2554
  logger.info("Entering environment variables (leave key empty and press enter to finish):");
2021
2555
  while (true) {
2022
- const key = await (0, import_prompts6.input)({
2556
+ const key = await (0, import_prompts5.input)({
2023
2557
  message: "Variable name (Key, leave empty to finish):",
2024
2558
  validate: (val2) => {
2025
2559
  const trimmed = val2.trim();
@@ -2033,17 +2567,17 @@ var promptEnvConfig = async (initialEnv = {}) => {
2033
2567
  const isSecret = SECRET_KEY_PATTERN.test(trimmedKey);
2034
2568
  let val;
2035
2569
  if (isSecret) {
2036
- val = await (0, import_prompts6.password)({
2570
+ val = await (0, import_prompts5.password)({
2037
2571
  message: `Value for (${trimmedKey}) [secret masked]:`,
2038
2572
  mask: "*"
2039
2573
  });
2040
2574
  } else {
2041
- val = await (0, import_prompts6.input)({
2575
+ val = await (0, import_prompts5.input)({
2042
2576
  message: `Value for (${trimmedKey}):`
2043
2577
  });
2044
2578
  }
2045
2579
  env[trimmedKey] = val;
2046
- logger.success(`Added: ${import_picocolors6.default.cyan(trimmedKey)}`);
2580
+ logger.success(`Added: ${import_picocolors9.default.cyan(trimmedKey)}`);
2047
2581
  }
2048
2582
  return env;
2049
2583
  };
@@ -2064,15 +2598,8 @@ var promptEditEnvConfig = async (currentEnv = {}) => promptEditKeyValueConfig(cu
2064
2598
  });
2065
2599
 
2066
2600
  // src/interactive/prompts/headers.ts
2067
- var import_prompts7 = require("@inquirer/prompts");
2068
- var import_picocolors7 = __toESM(require("picocolors"), 1);
2069
- var SECRET_HEADER_PATTERN = /(authorization|token|key|secret|auth)/i;
2070
- var maskSecretHeader = (key, value) => {
2071
- if (!SECRET_HEADER_PATTERN.test(key) || value.length <= 8) {
2072
- return value;
2073
- }
2074
- return `${value.slice(0, 4)}***${value.slice(-3)}`;
2075
- };
2601
+ var import_prompts6 = require("@inquirer/prompts");
2602
+ var import_picocolors10 = __toESM(require("picocolors"), 1);
2076
2603
  var formatHeadersText = (headers) => {
2077
2604
  return Object.entries(headers).map(([key, value]) => `${key}: ${value}`).join("\n");
2078
2605
  };
@@ -2105,7 +2632,7 @@ var parseHeadersText = (rawText) => {
2105
2632
  };
2106
2633
  var promptHeadersConfig = async (initialHeaders = {}) => {
2107
2634
  const headers = { ...initialHeaders };
2108
- const mode = await (0, import_prompts7.select)({
2635
+ const mode = await (0, import_prompts6.select)({
2109
2636
  message: "Select HTTP headers configuration method:",
2110
2637
  choices: [
2111
2638
  {
@@ -2142,16 +2669,16 @@ var promptHeadersConfig = async (initialHeaders = {}) => {
2142
2669
  logger.warn("No valid Key: Value pairs recognized");
2143
2670
  } else {
2144
2671
  Object.assign(headers, parsed);
2145
- logger.success(`Successfully parsed ${import_picocolors7.default.cyan(String(count))} headers:`);
2672
+ logger.success(`Successfully parsed ${import_picocolors10.default.cyan(String(count))} headers:`);
2146
2673
  for (const [k, v] of Object.entries(parsed)) {
2147
- console.log(` ${import_picocolors7.default.bold(k)}: ${import_picocolors7.default.dim(maskSecretHeader(k, v))}`);
2674
+ console.log(` ${import_picocolors10.default.bold(k)}: ${import_picocolors10.default.dim(maskSecretHeader(k, v))}`);
2148
2675
  }
2149
2676
  }
2150
2677
  return headers;
2151
2678
  }
2152
2679
  logger.info("Entering HTTP headers (leave header name empty and press enter to finish):");
2153
2680
  while (true) {
2154
- const name = await (0, import_prompts7.input)({
2681
+ const name = await (0, import_prompts6.input)({
2155
2682
  message: "Header name (e.g. Authorization, leave empty to finish):",
2156
2683
  validate: (val2) => {
2157
2684
  const trimmed = val2.trim();
@@ -2165,17 +2692,17 @@ var promptHeadersConfig = async (initialHeaders = {}) => {
2165
2692
  const isSecret = SECRET_HEADER_PATTERN.test(trimmedName);
2166
2693
  let val;
2167
2694
  if (isSecret) {
2168
- val = await (0, import_prompts7.password)({
2695
+ val = await (0, import_prompts6.password)({
2169
2696
  message: `Header value for (${trimmedName}) [sensitive content masked]:`,
2170
2697
  mask: "*"
2171
2698
  });
2172
2699
  } else {
2173
- val = await (0, import_prompts7.input)({
2700
+ val = await (0, import_prompts6.input)({
2174
2701
  message: `Header value for (${trimmedName}):`
2175
2702
  });
2176
2703
  }
2177
2704
  headers[trimmedName] = val;
2178
- logger.success(`Added: ${import_picocolors7.default.cyan(trimmedName)}`);
2705
+ logger.success(`Added: ${import_picocolors10.default.cyan(trimmedName)}`);
2179
2706
  }
2180
2707
  return headers;
2181
2708
  };
@@ -2197,10 +2724,10 @@ var promptEditHeadersConfig = async (currentHeaders = {}) => promptEditKeyValueC
2197
2724
  // src/interactive/wizard-add.ts
2198
2725
  var wizardAdd = async (initial = {}) => {
2199
2726
  const cwd = initial.cwd ?? process.cwd();
2200
- logger.info(import_picocolors8.default.bold("Welcome to the MCP interactive add wizard"));
2727
+ logger.info(import_picocolors11.default.bold("Welcome to the MCP interactive add wizard"));
2201
2728
  let source = initial.source;
2202
2729
  if (!source) {
2203
- const sourceType = await (0, import_prompts8.select)({
2730
+ const sourceType = await (0, import_prompts7.select)({
2204
2731
  message: "Select MCP server type:",
2205
2732
  choices: [
2206
2733
  {
@@ -2218,12 +2745,12 @@ var wizardAdd = async (initial = {}) => {
2218
2745
  ]
2219
2746
  });
2220
2747
  if (sourceType === "npm") {
2221
- source = await (0, import_prompts8.input)({
2748
+ source = await (0, import_prompts7.input)({
2222
2749
  message: "Enter npm package name (e.g. @modelcontextprotocol/server-postgres):",
2223
2750
  validate: (val) => val.trim() ? true : "Package name cannot be empty"
2224
2751
  });
2225
2752
  } else if (sourceType === "remote") {
2226
- source = await (0, import_prompts8.input)({
2753
+ source = await (0, import_prompts7.input)({
2227
2754
  message: "Enter remote server URL (e.g. https://mcp.example.com/sse):",
2228
2755
  validate: (val) => {
2229
2756
  const trimmed = val.trim();
@@ -2233,7 +2760,7 @@ var wizardAdd = async (initial = {}) => {
2233
2760
  }
2234
2761
  });
2235
2762
  } else {
2236
- source = await (0, import_prompts8.input)({
2763
+ source = await (0, import_prompts7.input)({
2237
2764
  message: "Enter command and arguments (e.g. python -m my_mcp_server or docker run ...):",
2238
2765
  validate: (val) => val.trim() ? true : "Command cannot be empty"
2239
2766
  });
@@ -2243,7 +2770,7 @@ var wizardAdd = async (initial = {}) => {
2243
2770
  const parsed = parseMcpSource(source);
2244
2771
  let serverName = initial.name;
2245
2772
  if (!serverName) {
2246
- serverName = await (0, import_prompts8.input)({
2773
+ serverName = await (0, import_prompts7.input)({
2247
2774
  message: "MCP server name:",
2248
2775
  default: parsed.inferredName,
2249
2776
  validate: (val) => val.trim() ? true : "Server name cannot be empty"
@@ -2255,7 +2782,7 @@ var wizardAdd = async (initial = {}) => {
2255
2782
  if (parsed.type === "remote") {
2256
2783
  if (!transport) {
2257
2784
  const isSseUrl = /\/sse\b/i.test(parsed.value);
2258
- transport = await (0, import_prompts8.select)({
2785
+ transport = await (0, import_prompts7.select)({
2259
2786
  message: "Select remote transport protocol:",
2260
2787
  choices: [
2261
2788
  { name: "HTTP", value: "http" },
@@ -2265,7 +2792,7 @@ var wizardAdd = async (initial = {}) => {
2265
2792
  });
2266
2793
  }
2267
2794
  if (Object.keys(headers).length === 0) {
2268
- const needHeader = await (0, import_prompts8.confirm)({
2795
+ const needHeader = await (0, import_prompts7.confirm)({
2269
2796
  message: "Configure HTTP headers (e.g. Authorization Bearer token)?",
2270
2797
  default: false
2271
2798
  });
@@ -2287,28 +2814,28 @@ var wizardAdd = async (initial = {}) => {
2287
2814
  if (parsed.type !== "remote") {
2288
2815
  env = await promptEnvConfig(env);
2289
2816
  }
2290
- console.log("\n" + import_picocolors8.default.cyan(import_picocolors8.default.bold("Configuration Preview:")));
2291
- console.log(` ${import_picocolors8.default.bold("Server Name:")} ${import_picocolors8.default.green(serverName)}`);
2292
- console.log(` ${import_picocolors8.default.bold("Server Type:")} ${import_picocolors8.default.magenta(parsed.type)}`);
2293
- console.log(` ${import_picocolors8.default.bold("Source/Command:")} ${import_picocolors8.default.dim(source)}`);
2294
- console.log(` ${import_picocolors8.default.bold("Scope:")} ${isGlobal ? import_picocolors8.default.yellow("Global") : import_picocolors8.default.blue("Project")}`);
2295
- console.log(` ${import_picocolors8.default.bold("Target Agents:")} ${import_picocolors8.default.cyan(selectedAgents.join(", "))}`);
2817
+ console.log("\n" + import_picocolors11.default.cyan(import_picocolors11.default.bold("Configuration Preview:")));
2818
+ console.log(` ${import_picocolors11.default.bold("Server Name:")} ${import_picocolors11.default.green(serverName)}`);
2819
+ console.log(` ${import_picocolors11.default.bold("Server Type:")} ${import_picocolors11.default.magenta(parsed.type)}`);
2820
+ console.log(` ${import_picocolors11.default.bold("Source/Command:")} ${import_picocolors11.default.dim(source)}`);
2821
+ console.log(` ${import_picocolors11.default.bold("Scope:")} ${isGlobal ? import_picocolors11.default.yellow("Global") : import_picocolors11.default.blue("Project")}`);
2822
+ console.log(` ${import_picocolors11.default.bold("Target Agents:")} ${import_picocolors11.default.cyan(selectedAgents.join(", "))}`);
2296
2823
  if (args.length > 0) {
2297
- console.log(` ${import_picocolors8.default.bold("Arguments:")} ${import_picocolors8.default.dim(args.join(" "))}`);
2824
+ console.log(` ${import_picocolors11.default.bold("Arguments:")} ${import_picocolors11.default.dim(args.join(" "))}`);
2298
2825
  }
2299
2826
  if (transport) {
2300
- console.log(` ${import_picocolors8.default.bold("Transport:")} ${import_picocolors8.default.magenta(transport)}`);
2827
+ console.log(` ${import_picocolors11.default.bold("Transport:")} ${import_picocolors11.default.magenta(transport)}`);
2301
2828
  }
2302
2829
  const envKeys = Object.keys(env);
2303
2830
  if (envKeys.length > 0) {
2304
- console.log(` ${import_picocolors8.default.bold("Environment Variables:")} ${import_picocolors8.default.dim(envKeys.join(", "))} (${envKeys.length})`);
2831
+ console.log(` ${import_picocolors11.default.bold("Environment Variables:")} ${import_picocolors11.default.dim(envKeys.join(", "))} (${envKeys.length})`);
2305
2832
  }
2306
2833
  const headerKeys = Object.keys(headers);
2307
2834
  if (headerKeys.length > 0) {
2308
- console.log(` ${import_picocolors8.default.bold("Headers:")} ${import_picocolors8.default.dim(headerKeys.join(", "))} (${headerKeys.length})`);
2835
+ console.log(` ${import_picocolors11.default.bold("Headers:")} ${import_picocolors11.default.dim(headerKeys.join(", "))} (${headerKeys.length})`);
2309
2836
  }
2310
2837
  console.log();
2311
- const proceed = await (0, import_prompts8.confirm)({
2838
+ const proceed = await (0, import_prompts7.confirm)({
2312
2839
  message: "Confirm installation with this configuration?",
2313
2840
  default: true
2314
2841
  });
@@ -2328,103 +2855,162 @@ var wizardAdd = async (initial = {}) => {
2328
2855
  env
2329
2856
  });
2330
2857
  logger.info(
2331
- `Writing ${import_picocolors8.default.bold(result.serverName)} to ${import_picocolors8.default.cyan(String(result.results.length))} agent config files...`
2858
+ `Writing ${import_picocolors11.default.bold(result.serverName)} to ${import_picocolors11.default.cyan(String(result.results.length))} agent config files...`
2332
2859
  );
2333
2860
  let allSuccess = true;
2334
2861
  for (const record of result.results) {
2335
2862
  if (record.success) {
2336
- logger.success(`${import_picocolors8.default.cyan(record.agent)}: Successfully written to ${import_picocolors8.default.dim(record.path)}`);
2863
+ logger.success(
2864
+ `${import_picocolors11.default.cyan(record.agent)}: Successfully written to ${import_picocolors11.default.dim(record.path)}${formatCoHostedBadge("configured", record.coConfiguredAgents)}`
2865
+ );
2337
2866
  } else {
2338
2867
  allSuccess = false;
2339
- logger.error(`${import_picocolors8.default.cyan(record.agent)}: Failed to write - ${record.error}`);
2868
+ logger.error(`${import_picocolors11.default.cyan(record.agent)}: Failed to write - ${record.error}`);
2340
2869
  }
2341
2870
  }
2342
2871
  if (allSuccess) {
2343
- logger.success(import_picocolors8.default.bold(`MCP server "${serverName}" configured successfully!`));
2872
+ logger.success(import_picocolors11.default.bold(`MCP server "${serverName}" configured successfully!`));
2344
2873
  }
2345
2874
  return allSuccess;
2346
2875
  };
2347
2876
 
2348
2877
  // src/interactive/wizard-manage.ts
2349
- var import_prompts9 = require("@inquirer/prompts");
2350
- var import_picocolors9 = __toESM(require("picocolors"), 1);
2351
-
2352
- // src/interactive/utils/group-installed-servers.ts
2353
- var normalizeServerConfig = parseServerConfig;
2354
- var groupInstalledServersByName = (installed) => {
2355
- const grouped = /* @__PURE__ */ new Map();
2356
- for (const item of installed) {
2357
- let entry = grouped.get(item.serverName);
2358
- if (!entry) {
2359
- entry = {
2360
- serverName: item.serverName,
2361
- agents: [],
2362
- paths: [],
2363
- config: normalizeServerConfig(item.config)
2364
- };
2365
- grouped.set(item.serverName, entry);
2366
- }
2367
- if (!entry.agents.includes(item.agent)) {
2368
- entry.agents.push(item.agent);
2369
- }
2370
- if (!entry.paths.includes(item.path)) {
2371
- entry.paths.push(item.path);
2372
- }
2373
- }
2374
- return grouped;
2375
- };
2878
+ var import_prompts8 = require("@inquirer/prompts");
2879
+ var import_picocolors13 = __toESM(require("picocolors"), 1);
2376
2880
 
2377
- // src/interactive/wizard-manage.ts
2881
+ // src/utils/display-server-details.ts
2882
+ var import_picocolors12 = __toESM(require("picocolors"), 1);
2378
2883
  var displayServerDetails = ({
2379
2884
  serverName,
2380
2885
  config,
2381
2886
  agents,
2382
- isGlobal,
2887
+ hasDivergence,
2888
+ global: isGlobal,
2383
2889
  titlePrefix = "MCP Server Details"
2384
2890
  }) => {
2385
- console.log("\n" + import_picocolors9.default.cyan(import_picocolors9.default.bold(`${titlePrefix}: [${serverName}]`)));
2891
+ console.log("\n" + import_picocolors12.default.cyan(import_picocolors12.default.bold(`${titlePrefix}: [${serverName}]`)));
2386
2892
  if (isGlobal !== void 0) {
2387
- console.log(` ${import_picocolors9.default.bold("Scope:")} ${isGlobal ? "Global" : "Project"}`);
2893
+ console.log(` ${import_picocolors12.default.bold("Scope:")} ${isGlobal ? "Global" : "Project"}`);
2388
2894
  }
2389
2895
  if (agents && agents.length > 0) {
2390
2896
  console.log(
2391
- ` ${import_picocolors9.default.bold("Configured Agents:")} ${import_picocolors9.default.green(agents.map((a) => getMcpAgentConfig(a).displayName).join(", "))}`
2897
+ ` ${import_picocolors12.default.bold("Configured Agents:")} ${import_picocolors12.default.green(agents.map((a) => getMcpAgentConfig(a).displayName).join(", "))}`
2898
+ );
2899
+ }
2900
+ if (hasDivergence) {
2901
+ console.log(
2902
+ ` ${import_picocolors12.default.yellow(import_picocolors12.default.bold("Notice:"))} ${import_picocolors12.default.yellow("Configurations differ across installed agents. Showing configuration from the first agent.")}`
2392
2903
  );
2393
2904
  }
2394
2905
  const isRemote = Boolean(config.url && config.url.length > 0);
2395
2906
  if (isRemote) {
2396
- console.log(` ${import_picocolors9.default.bold("Transport:")} ${import_picocolors9.default.magenta(config.type ?? "http")}`);
2397
- console.log(` ${import_picocolors9.default.bold("URL:")} ${import_picocolors9.default.dim(config.url ?? "")}`);
2907
+ console.log(` ${import_picocolors12.default.bold("Transport:")} ${import_picocolors12.default.magenta(config.type ?? "http")}`);
2908
+ console.log(` ${import_picocolors12.default.bold("URL:")} ${import_picocolors12.default.dim(config.url ?? "")}`);
2398
2909
  const headerKeys = Object.keys(config.headers ?? {});
2399
2910
  if (headerKeys.length > 0) {
2400
- console.log(` ${import_picocolors9.default.bold("Headers:")} ${import_picocolors9.default.cyan(String(headerKeys.length))}`);
2911
+ console.log(` ${import_picocolors12.default.bold("Headers:")} ${import_picocolors12.default.cyan(String(headerKeys.length))}`);
2401
2912
  for (const [k, v] of Object.entries(config.headers ?? {})) {
2402
- console.log(` ${import_picocolors9.default.bold(k)}: ${import_picocolors9.default.dim(maskSecretHeader(k, v))}`);
2913
+ console.log(` ${import_picocolors12.default.bold(k)}: ${import_picocolors12.default.dim(maskSecretHeader(k, v))}`);
2403
2914
  }
2404
2915
  } else {
2405
- console.log(` ${import_picocolors9.default.bold("Headers:")} ${import_picocolors9.default.dim("(none)")}`);
2916
+ console.log(` ${import_picocolors12.default.bold("Headers:")} ${import_picocolors12.default.dim("(none)")}`);
2406
2917
  }
2407
2918
  } else {
2408
- console.log(` ${import_picocolors9.default.bold("Command:")} ${import_picocolors9.default.magenta(config.command ?? "")}`);
2919
+ console.log(` ${import_picocolors12.default.bold("Command:")} ${import_picocolors12.default.magenta(config.command ?? "")}`);
2409
2920
  const argsStr = config.args && config.args.length > 0 ? config.args.join(" ") : "(none)";
2410
- console.log(` ${import_picocolors9.default.bold("Arguments:")} ${import_picocolors9.default.dim(argsStr)}`);
2921
+ console.log(` ${import_picocolors12.default.bold("Arguments:")} ${import_picocolors12.default.dim(argsStr)}`);
2411
2922
  const envKeys = Object.keys(config.env ?? {});
2412
2923
  if (envKeys.length > 0) {
2413
- console.log(` ${import_picocolors9.default.bold("Environment Variables:")} ${import_picocolors9.default.cyan(String(envKeys.length))}`);
2924
+ console.log(` ${import_picocolors12.default.bold("Environment Variables:")} ${import_picocolors12.default.cyan(String(envKeys.length))}`);
2414
2925
  for (const [k, v] of Object.entries(config.env ?? {})) {
2415
- console.log(` ${import_picocolors9.default.bold(k)}=${import_picocolors9.default.dim(maskSecretValue(k, v))}`);
2926
+ console.log(` ${import_picocolors12.default.bold(k)}=${import_picocolors12.default.dim(maskSecretValue(k, v))}`);
2416
2927
  }
2417
2928
  } else {
2418
- console.log(` ${import_picocolors9.default.bold("Environment Variables:")} ${import_picocolors9.default.dim("(none)")}`);
2929
+ console.log(` ${import_picocolors12.default.bold("Environment Variables:")} ${import_picocolors12.default.dim("(none)")}`);
2419
2930
  }
2420
2931
  }
2421
2932
  console.log();
2422
2933
  };
2423
- var handleEditServerConfig = async ({
2424
- targetGroup,
2425
- isGlobal,
2426
- cwd
2427
- }) => {
2934
+
2935
+ // src/interactive/utils/group-installed-servers.ts
2936
+ var normalizeServerConfig = parseServerConfig;
2937
+ var groupInstalledServersByName = (installed) => {
2938
+ const grouped = /* @__PURE__ */ new Map();
2939
+ for (const item of installed) {
2940
+ const itemConfig = normalizeServerConfig(item.config);
2941
+ let entry = grouped.get(item.serverName);
2942
+ if (!entry) {
2943
+ entry = {
2944
+ serverName: item.serverName,
2945
+ agents: [],
2946
+ paths: [],
2947
+ config: itemConfig,
2948
+ hasDivergence: false
2949
+ };
2950
+ grouped.set(item.serverName, entry);
2951
+ } else if (!entry.hasDivergence) {
2952
+ if (JSON.stringify(entry.config) !== JSON.stringify(itemConfig)) {
2953
+ entry.hasDivergence = true;
2954
+ }
2955
+ }
2956
+ if (!entry.agents.includes(item.agent)) {
2957
+ entry.agents.push(item.agent);
2958
+ }
2959
+ if (!entry.paths.includes(item.path)) {
2960
+ entry.paths.push(item.path);
2961
+ }
2962
+ }
2963
+ return grouped;
2964
+ };
2965
+
2966
+ // src/interactive/wizard-manage.ts
2967
+ var promptSwitchServerType = async (currentConfig, serverName) => {
2968
+ const isRemote = Boolean(currentConfig.url && currentConfig.url.length > 0);
2969
+ if (isRemote) {
2970
+ const newCmd = await (0, import_prompts8.input)({
2971
+ message: "Executable command (e.g. node, npx):",
2972
+ validate: (val) => val.trim() ? true : "Command cannot be empty"
2973
+ });
2974
+ const newArgs = await promptEditArgs([]);
2975
+ const newEnv = await promptEditEnvConfig({});
2976
+ logger.success(`Switched [${serverName}] configuration to stdio mode`);
2977
+ return {
2978
+ command: newCmd.trim(),
2979
+ args: newArgs.length > 0 ? newArgs : void 0,
2980
+ env: Object.keys(newEnv).length > 0 ? newEnv : void 0
2981
+ };
2982
+ }
2983
+ const newUrl = await (0, import_prompts8.input)({
2984
+ message: "Remote server URL:",
2985
+ validate: (val) => {
2986
+ const trimmed = val.trim();
2987
+ if (!trimmed) return "URL cannot be empty";
2988
+ if (!/^https?:\/\//i.test(trimmed)) {
2989
+ return "Please enter a valid URL starting with http:// or https://";
2990
+ }
2991
+ return true;
2992
+ }
2993
+ });
2994
+ const transport = await (0, import_prompts8.select)({
2995
+ message: "Select remote transport protocol:",
2996
+ choices: [
2997
+ { name: "HTTP", value: "http" },
2998
+ { name: "SSE (Server-Sent Events)", value: "sse" }
2999
+ ],
3000
+ default: "http"
3001
+ });
3002
+ const newHeaders = await promptEditHeadersConfig({});
3003
+ logger.success(`Switched [${serverName}] configuration to remote mode`);
3004
+ return {
3005
+ url: newUrl.trim(),
3006
+ type: transport,
3007
+ headers: Object.keys(newHeaders).length > 0 ? newHeaders : void 0
3008
+ };
3009
+ };
3010
+ var handleEditServerConfig = async (options) => {
3011
+ const { targetGroup } = options;
3012
+ const isGlobal = options.global ?? false;
3013
+ const cwd = options.cwd ?? process.cwd();
2428
3014
  const serverName = targetGroup.serverName;
2429
3015
  let workingConfig = {
2430
3016
  ...targetGroup.config,
@@ -2443,6 +3029,7 @@ var handleEditServerConfig = async ({
2443
3029
  { name: "Edit HTTP Headers (headers)", value: "headers" },
2444
3030
  { name: "Edit Remote URL (url)", value: "url" },
2445
3031
  { name: "Edit Transport Protocol (type)", value: "transport" },
3032
+ { name: "Switch to local command (stdio)", value: "switch_type" },
2446
3033
  { name: "Reset changes to original", value: "reset" },
2447
3034
  { name: "Save and apply changes", value: "save" },
2448
3035
  { name: "Cancel (discard changes)", value: "cancel" }
@@ -2450,11 +3037,12 @@ var handleEditServerConfig = async ({
2450
3037
  { name: "Edit Environment Variables (env)", value: "env" },
2451
3038
  { name: "Edit Command Arguments (args)", value: "args" },
2452
3039
  { name: "Edit Executable Command (command)", value: "command" },
3040
+ { name: "Switch to remote server (HTTP/SSE)", value: "switch_type" },
2453
3041
  { name: "Reset changes to original", value: "reset" },
2454
3042
  { name: "Save and apply changes", value: "save" },
2455
3043
  { name: "Cancel (discard changes)", value: "cancel" }
2456
3044
  ];
2457
- const editAction = await (0, import_prompts9.select)({
3045
+ const editAction = await (0, import_prompts8.select)({
2458
3046
  message: `What would you like to modify in [${serverName}]?`,
2459
3047
  choices: editChoices
2460
3048
  });
@@ -2472,12 +3060,16 @@ var handleEditServerConfig = async ({
2472
3060
  logger.info("Configuration reset to original");
2473
3061
  continue;
2474
3062
  }
3063
+ if (editAction === "switch_type") {
3064
+ workingConfig = await promptSwitchServerType(workingConfig, serverName);
3065
+ continue;
3066
+ }
2475
3067
  if (editAction === "env") {
2476
3068
  workingConfig.env = await promptEditEnvConfig(workingConfig.env ?? {});
2477
3069
  } else if (editAction === "args") {
2478
3070
  workingConfig.args = await promptEditArgs(workingConfig.args ?? []);
2479
3071
  } else if (editAction === "command") {
2480
- const newCmd = await (0, import_prompts9.input)({
3072
+ const newCmd = await (0, import_prompts8.input)({
2481
3073
  message: "Executable command:",
2482
3074
  default: workingConfig.command,
2483
3075
  validate: (val) => val.trim() ? true : "Command cannot be empty"
@@ -2486,7 +3078,7 @@ var handleEditServerConfig = async ({
2486
3078
  } else if (editAction === "headers") {
2487
3079
  workingConfig.headers = await promptEditHeadersConfig(workingConfig.headers ?? {});
2488
3080
  } else if (editAction === "url") {
2489
- const newUrl = await (0, import_prompts9.input)({
3081
+ const newUrl = await (0, import_prompts8.input)({
2490
3082
  message: "Remote server URL:",
2491
3083
  default: workingConfig.url,
2492
3084
  validate: (val) => {
@@ -2500,7 +3092,7 @@ var handleEditServerConfig = async ({
2500
3092
  });
2501
3093
  workingConfig.url = newUrl.trim();
2502
3094
  } else if (editAction === "transport") {
2503
- workingConfig.type = await (0, import_prompts9.select)({
3095
+ workingConfig.type = await (0, import_prompts8.select)({
2504
3096
  message: "Select remote transport protocol:",
2505
3097
  choices: [
2506
3098
  { name: "HTTP", value: "http" },
@@ -2511,42 +3103,46 @@ var handleEditServerConfig = async ({
2511
3103
  } else if (editAction === "save") {
2512
3104
  let targetAgents = targetGroup.agents;
2513
3105
  if (targetGroup.agents.length > 1) {
2514
- targetAgents = await (0, import_prompts9.checkbox)({
3106
+ const sortedAgents = sortAgentsWithClusters(targetGroup.agents, { global: isGlobal, cwd });
3107
+ const choices = buildLinkedAgentChoices({
3108
+ agents: sortedAgents,
3109
+ checkedAgents: sortedAgents,
3110
+ scopeOptions: { global: isGlobal, cwd }
3111
+ });
3112
+ targetAgents = await linkedCheckbox({
2515
3113
  message: "Select agents to update configuration (Space to toggle):",
2516
- choices: targetGroup.agents.map((a) => ({
2517
- name: `${getMcpAgentConfig(a).displayName} (${a})`,
2518
- value: a,
2519
- checked: true
2520
- })),
3114
+ choices,
2521
3115
  loop: false,
2522
3116
  validate: (ans) => ans.length === 0 ? "Please select at least one agent" : true
2523
3117
  });
2524
- }
2525
- const requestedTransport = workingConfig.url ? workingConfig.type ?? "http" : "stdio";
2526
- const compatibleAgents = [];
2527
- const incompatibleAgents = [];
2528
- for (const agent of targetAgents) {
2529
- const agentConfig = getMcpAgentConfig(agent);
2530
- if (isMcpTransportSupported(agentConfig, requestedTransport)) {
2531
- compatibleAgents.push(agent);
2532
- } else {
2533
- const reason = agentConfig.unsupportedTransportMessage ?? `Agent does not support ${requestedTransport} transport`;
2534
- incompatibleAgents.push({ agent, reason });
3118
+ if (targetAgents.length < targetGroup.agents.length) {
3119
+ const unselected = targetGroup.agents.filter((a) => !targetAgents.includes(a));
3120
+ const unselectedNames = unselected.map((a) => getMcpAgentConfig(a).displayName).join(", ");
3121
+ logger.info(
3122
+ `Note: Updating only a subset of agents. Server configurations will diverge from: ${unselectedNames}.`
3123
+ );
2535
3124
  }
2536
3125
  }
2537
- if (incompatibleAgents.length > 0) {
2538
- for (const item of incompatibleAgents) {
2539
- logger.warn(`Skipping ${import_picocolors9.default.cyan(item.agent)}: ${item.reason}`);
3126
+ const requestedTransport = workingConfig.url ? workingConfig.type ?? "http" : "stdio";
3127
+ const resolution = resolveTargetAgents({
3128
+ requested: targetAgents,
3129
+ global: isGlobal,
3130
+ cwd,
3131
+ transport: requestedTransport
3132
+ });
3133
+ if (resolution.incompatible.length > 0) {
3134
+ for (const item of resolution.incompatible) {
3135
+ logger.warn(`Skipping ${import_picocolors13.default.cyan(item.agent)}: ${item.reason}`);
2540
3136
  }
2541
3137
  }
2542
- if (compatibleAgents.length === 0) {
3138
+ if (resolution.compatibleAgents.length === 0) {
2543
3139
  logger.error(
2544
3140
  `None of the selected agents support ${requestedTransport} transport. Cannot update.`
2545
3141
  );
2546
3142
  continue;
2547
3143
  }
2548
- const agentNames = compatibleAgents.map((a) => getMcpAgentConfig(a).displayName).join(", ");
2549
- const confirmed = await (0, import_prompts9.confirm)({
3144
+ const agentNames = resolution.compatibleAgents.map((a) => getMcpAgentConfig(a).displayName).join(", ");
3145
+ const confirmed = await (0, import_prompts8.confirm)({
2550
3146
  message: `Confirm updating configuration for [${serverName}] across: ${agentNames}?`,
2551
3147
  default: true
2552
3148
  });
@@ -2554,22 +3150,32 @@ var handleEditServerConfig = async ({
2554
3150
  logger.warn("Update cancelled");
2555
3151
  continue;
2556
3152
  }
2557
- for (const targetAgent of compatibleAgents) {
2558
- const res = installMcpServerForAgent(serverName, workingConfig, targetAgent, {
2559
- global: isGlobal,
2560
- cwd
2561
- });
3153
+ const updateResult = updateMcpServer({
3154
+ serverName,
3155
+ config: workingConfig,
3156
+ previousConfig: targetGroup.config,
3157
+ agents: resolution.compatibleAgents,
3158
+ global: isGlobal,
3159
+ cwd
3160
+ });
3161
+ let updatedAny = false;
3162
+ const succeededAgents = [];
3163
+ for (const res of updateResult.results) {
2562
3164
  if (res.success) {
3165
+ updatedAny = true;
3166
+ succeededAgents.push(res.agent);
2563
3167
  logger.success(
2564
- `${import_picocolors9.default.cyan(targetAgent)}: Successfully updated configuration in ${import_picocolors9.default.dim(res.path)}`
3168
+ `${import_picocolors13.default.cyan(res.agent)}: Successfully updated configuration in ${import_picocolors13.default.dim(res.path)}${formatCoHostedBadge("configured", res.coConfiguredAgents)}`
2565
3169
  );
2566
3170
  } else {
2567
- logger.error(`${import_picocolors9.default.cyan(targetAgent)}: Update failed - ${res.error}`);
3171
+ logger.error(`${import_picocolors13.default.cyan(res.agent)}: Update failed - ${res.error}`);
2568
3172
  }
2569
3173
  }
2570
- targetGroup.config = workingConfig;
2571
- logger.success(`Configuration for [${serverName}] updated successfully!`);
2572
- return;
3174
+ if (updatedAny) {
3175
+ targetGroup.config = updateResult.config;
3176
+ logger.success(`Configuration for [${serverName}] updated successfully!`);
3177
+ return;
3178
+ }
2573
3179
  }
2574
3180
  }
2575
3181
  };
@@ -2587,6 +3193,14 @@ var wizardManage = async (options = {}) => {
2587
3193
  }
2588
3194
  const grouped = groupInstalledServersByName(installed);
2589
3195
  let pendingServerName = options.serverName;
3196
+ const refreshGroupedServers = () => {
3197
+ const freshInstalled = listInstalledMcpServers({ global: isGlobal, cwd });
3198
+ const freshGrouped = groupInstalledServersByName(freshInstalled);
3199
+ grouped.clear();
3200
+ for (const [name, grp] of freshGrouped) {
3201
+ grouped.set(name, grp);
3202
+ }
3203
+ };
2590
3204
  while (true) {
2591
3205
  let chosenServerName;
2592
3206
  if (pendingServerName && grouped.has(pendingServerName)) {
@@ -2597,7 +3211,7 @@ var wizardManage = async (options = {}) => {
2597
3211
  const choices = Array.from(grouped.values()).map((g) => {
2598
3212
  const agentNames = g.agents.map((a) => getMcpAgentConfig(a).displayName).join(", ");
2599
3213
  return {
2600
- name: `${import_picocolors9.default.bold(g.serverName)} ${import_picocolors9.default.dim(`(configured in: ${agentNames})`)}`,
3214
+ name: `${import_picocolors13.default.bold(g.serverName)} ${import_picocolors13.default.dim(`(configured in: ${agentNames})`)}`,
2601
3215
  value: g.serverName
2602
3216
  };
2603
3217
  });
@@ -2605,7 +3219,7 @@ var wizardManage = async (options = {}) => {
2605
3219
  name: `Back`,
2606
3220
  value: "__back__"
2607
3221
  });
2608
- chosenServerName = await (0, import_prompts9.select)({
3222
+ chosenServerName = await (0, import_prompts8.select)({
2609
3223
  message: "Select MCP server to manage or sync:",
2610
3224
  choices
2611
3225
  });
@@ -2619,9 +3233,10 @@ var wizardManage = async (options = {}) => {
2619
3233
  serverName: chosenServerName,
2620
3234
  config: targetGroup.config,
2621
3235
  agents: targetGroup.agents,
2622
- isGlobal
3236
+ global: isGlobal,
3237
+ hasDivergence: targetGroup.hasDivergence
2623
3238
  });
2624
- const action = await (0, import_prompts9.select)({
3239
+ const action = await (0, import_prompts8.select)({
2625
3240
  message: `What would you like to do with [${chosenServerName}]?`,
2626
3241
  choices: [
2627
3242
  {
@@ -2642,31 +3257,34 @@ var wizardManage = async (options = {}) => {
2642
3257
  if (action === "edit") {
2643
3258
  await handleEditServerConfig({
2644
3259
  targetGroup,
2645
- isGlobal,
3260
+ global: isGlobal,
2646
3261
  cwd
2647
3262
  });
3263
+ refreshGroupedServers();
2648
3264
  continue;
2649
3265
  }
2650
3266
  if (action === "sync") {
2651
3267
  const allAllowedAgents = isGlobal ? getMcpAgentTypes() : getMcpAgentsSupportingProjectScope();
2652
- const candidateAgents = allAllowedAgents.filter((a) => !targetGroup.agents.includes(a));
2653
- if (candidateAgents.length === 0) {
3268
+ const rawCandidateAgents = allAllowedAgents.filter((a) => !targetGroup.agents.includes(a));
3269
+ if (rawCandidateAgents.length === 0) {
2654
3270
  logger.info(
2655
3271
  "All supported agents in this scope already have this MCP server configured; no sync needed"
2656
3272
  );
2657
3273
  continue;
2658
3274
  }
2659
- const selectedToSync = await (0, import_prompts9.checkbox)({
3275
+ const candidateAgents = sortAgentsWithClusters(rawCandidateAgents, { global: isGlobal, cwd });
3276
+ const choices = buildLinkedAgentChoices({
3277
+ agents: candidateAgents,
3278
+ checkedAgents: [],
3279
+ scopeOptions: { global: isGlobal, cwd }
3280
+ });
3281
+ const selectedToSync = await linkedCheckbox({
2660
3282
  message: "Select target agents to sync to (Space to select):",
2661
- choices: candidateAgents.map((a) => ({
2662
- name: `${getMcpAgentConfig(a).displayName} (${a})`,
2663
- value: a,
2664
- checked: false
2665
- })),
3283
+ choices,
2666
3284
  loop: false,
2667
3285
  validate: (ans) => ans.length === 0 ? "Please select at least one agent" : true
2668
3286
  });
2669
- const confirmed = await (0, import_prompts9.confirm)({
3287
+ const confirmed = await (0, import_prompts8.confirm)({
2670
3288
  message: `Confirm syncing configuration of [${chosenServerName}] to: ${selectedToSync.join(", ")}?`,
2671
3289
  default: true
2672
3290
  });
@@ -2674,25 +3292,37 @@ var wizardManage = async (options = {}) => {
2674
3292
  logger.warn("Sync cancelled");
2675
3293
  continue;
2676
3294
  }
2677
- for (const targetAgent of selectedToSync) {
2678
- const res = installMcpServerForAgent(chosenServerName, targetGroup.config, targetAgent, {
2679
- global: isGlobal,
2680
- cwd
2681
- });
3295
+ const syncResult = updateMcpServer({
3296
+ serverName: chosenServerName,
3297
+ config: targetGroup.config,
3298
+ agents: selectedToSync,
3299
+ global: isGlobal,
3300
+ cwd
3301
+ });
3302
+ for (const item of syncResult.incompatible) {
3303
+ logger.warn(`Skipping ${import_picocolors13.default.cyan(item.agent)}: ${item.reason}`);
3304
+ }
3305
+ for (const res of syncResult.results) {
3306
+ if (syncResult.incompatible.some((i) => i.agent === res.agent)) {
3307
+ continue;
3308
+ }
2682
3309
  if (res.success) {
2683
- logger.success(`${import_picocolors9.default.cyan(targetAgent)}: Successfully synced to ${import_picocolors9.default.dim(res.path)}`);
2684
- targetGroup.agents.push(targetAgent);
3310
+ logger.success(
3311
+ `${import_picocolors13.default.cyan(res.agent)}: Successfully synced to ${import_picocolors13.default.dim(res.path)}${formatCoHostedBadge("configured", res.coConfiguredAgents)}`
3312
+ );
3313
+ targetGroup.agents.push(res.agent);
2685
3314
  } else {
2686
- logger.error(`${import_picocolors9.default.cyan(targetAgent)}: Sync failed - ${res.error}`);
3315
+ logger.error(`${import_picocolors13.default.cyan(res.agent)}: Sync failed - ${res.error}`);
2687
3316
  }
2688
3317
  }
3318
+ refreshGroupedServers();
2689
3319
  }
2690
3320
  }
2691
3321
  };
2692
3322
 
2693
3323
  // src/interactive/wizard-remove.ts
2694
- var import_prompts10 = require("@inquirer/prompts");
2695
- var import_picocolors10 = __toESM(require("picocolors"), 1);
3324
+ var import_prompts9 = require("@inquirer/prompts");
3325
+ var import_picocolors14 = __toESM(require("picocolors"), 1);
2696
3326
  var wizardRemove = async (options = {}) => {
2697
3327
  const cwd = options.cwd ?? process.cwd();
2698
3328
  const isGlobal = await promptScope({
@@ -2709,29 +3339,30 @@ var wizardRemove = async (options = {}) => {
2709
3339
  let serverName = options.name;
2710
3340
  if (!serverName) {
2711
3341
  const choices = Array.from(serverMap.values()).map((g) => ({
2712
- name: `${import_picocolors10.default.bold(g.serverName)} ${import_picocolors10.default.dim(`(installed in: ${g.agents.map((a) => getMcpAgentConfig(a).displayName).join(", ")})`)}`,
3342
+ name: `${import_picocolors14.default.bold(g.serverName)} ${import_picocolors14.default.dim(`(installed in: ${g.agents.map((a) => getMcpAgentConfig(a).displayName).join(", ")})`)}`,
2713
3343
  value: g.serverName
2714
3344
  }));
2715
- serverName = await (0, import_prompts10.select)({
3345
+ serverName = await (0, import_prompts9.select)({
2716
3346
  message: "Select MCP server to remove:",
2717
3347
  choices
2718
3348
  });
2719
3349
  }
2720
- const installedAgents = serverMap.get(serverName)?.agents || [];
2721
- if (installedAgents.length === 0) {
3350
+ const rawInstalledAgents = serverMap.get(serverName)?.agents || [];
3351
+ if (rawInstalledAgents.length === 0) {
2722
3352
  logger.warn(`No agents found with [${serverName}] installed`);
2723
3353
  return false;
2724
3354
  }
3355
+ const installedAgents = sortAgentsWithClusters(rawInstalledAgents, { global: isGlobal, cwd });
2725
3356
  let targetAgents = options.agents;
2726
3357
  if (!targetAgents || targetAgents.length === 0) {
2727
- targetAgents = await (0, import_prompts10.checkbox)({
3358
+ const choices = buildLinkedAgentChoices({
3359
+ agents: installedAgents,
3360
+ checkedAgents: installedAgents,
3361
+ scopeOptions: { global: isGlobal, cwd }
3362
+ });
3363
+ targetAgents = await linkedCheckbox({
2728
3364
  message: `Select agents to remove [${serverName}] from:`,
2729
- choices: installedAgents.map((agent) => ({
2730
- name: `${getMcpAgentConfig(agent)?.displayName ?? agent} (${agent})`,
2731
- value: agent,
2732
- checked: true
2733
- })),
2734
- loop: false,
3365
+ choices,
2735
3366
  validate: (ans) => ans.length === 0 ? "Please select at least one agent" : true
2736
3367
  });
2737
3368
  } else {
@@ -2742,7 +3373,7 @@ var wizardRemove = async (options = {}) => {
2742
3373
  }
2743
3374
  targetAgents = validAgents;
2744
3375
  }
2745
- const confirmed = await (0, import_prompts10.confirm)({
3376
+ const confirmed = await (0, import_prompts9.confirm)({
2746
3377
  message: `Confirm removing MCP server [${serverName}] from ${targetAgents.join(", ")}?`,
2747
3378
  default: true
2748
3379
  });
@@ -2759,10 +3390,12 @@ var wizardRemove = async (options = {}) => {
2759
3390
  let removedCount = 0;
2760
3391
  for (const res of results) {
2761
3392
  if (res.removed) {
2762
- logger.success(`${import_picocolors10.default.cyan(res.agent)}: Successfully removed from ${import_picocolors10.default.dim(res.path)}`);
3393
+ logger.success(
3394
+ `${import_picocolors14.default.cyan(res.agent)}: Successfully removed from ${import_picocolors14.default.dim(res.path)}${formatCoHostedBadge("affected", res.coAffectedAgents)}`
3395
+ );
2763
3396
  removedCount++;
2764
3397
  } else if (res.error) {
2765
- logger.error(`${import_picocolors10.default.cyan(res.agent)}: Failed to remove - ${res.error}`);
3398
+ logger.error(`${import_picocolors14.default.cyan(res.agent)}: Failed to remove - ${res.error}`);
2766
3399
  }
2767
3400
  }
2768
3401
  if (removedCount > 0) {
@@ -2776,12 +3409,12 @@ var wizardRemove = async (options = {}) => {
2776
3409
  // src/interactive/main-menu.ts
2777
3410
  var mainMenu = async () => {
2778
3411
  console.log();
2779
- console.log(import_picocolors11.default.bold(import_picocolors11.default.cyan("mcps - Cross-Platform MCP Manager for AI Coding Agents")));
2780
- console.log(import_picocolors11.default.dim("Cross-platform MCP server configuration & synchronization tool"));
3412
+ console.log(import_picocolors15.default.bold(import_picocolors15.default.cyan("mcps - Cross-Platform MCP Manager for AI Coding Agents")));
3413
+ console.log(import_picocolors15.default.dim("Cross-platform MCP server configuration & synchronization tool"));
2781
3414
  console.log();
2782
3415
  while (true) {
2783
3416
  try {
2784
- const action = await (0, import_prompts11.select)({
3417
+ const action = await (0, import_prompts10.select)({
2785
3418
  message: "Select an action:",
2786
3419
  choices: [
2787
3420
  {
@@ -2803,7 +3436,7 @@ var mainMenu = async () => {
2803
3436
  ]
2804
3437
  });
2805
3438
  if (action === "exit") {
2806
- console.log(import_picocolors11.default.dim("Goodbye!"));
3439
+ console.log(import_picocolors15.default.dim("Goodbye!"));
2807
3440
  break;
2808
3441
  }
2809
3442
  if (action === "add") {
@@ -2816,7 +3449,7 @@ var mainMenu = async () => {
2816
3449
  console.log();
2817
3450
  } catch (error) {
2818
3451
  if (error?.name === "ExitPromptError") {
2819
- console.log("\n" + import_picocolors11.default.dim("Exited."));
3452
+ console.log("\n" + import_picocolors15.default.dim("Exited."));
2820
3453
  break;
2821
3454
  }
2822
3455
  throw error;
@@ -2824,9 +3457,16 @@ var mainMenu = async () => {
2824
3457
  }
2825
3458
  };
2826
3459
 
3460
+ // src/utils/resolve-transport.ts
3461
+ var resolveTransport = (input7) => {
3462
+ if (!input7) return void 0;
3463
+ if (input7 === "http" || input7 === "sse") return input7;
3464
+ throw new Error(`Unsupported transport "${input7}" (expected: http, sse)`);
3465
+ };
3466
+
2827
3467
  // src/cli/manage.ts
2828
3468
  var import_commander = require("commander");
2829
- var import_picocolors12 = __toESM(require("picocolors"), 1);
3469
+ var import_picocolors16 = __toESM(require("picocolors"), 1);
2830
3470
 
2831
3471
  // src/utils/parse-key-value-list.ts
2832
3472
  var parseKeyValueList = (entries, separator) => {
@@ -2846,72 +3486,124 @@ var parseKeyValueList = (entries, separator) => {
2846
3486
  };
2847
3487
 
2848
3488
  // src/cli/manage.ts
2849
- var resolveTransport = (input7) => {
2850
- if (!input7) return void 0;
2851
- if (input7 === "http" || input7 === "sse") return input7;
2852
- throw new Error(`Unsupported transport "${input7}" (expected: http, sse)`);
3489
+ var requireTargetServerGroup = (serverName, scope) => {
3490
+ const installed = listInstalledMcpServers(scope);
3491
+ const grouped = groupInstalledServersByName(installed);
3492
+ const targetGroup = grouped.get(serverName);
3493
+ if (!targetGroup) {
3494
+ logger.error(
3495
+ `MCP server "${serverName}" is not configured in ${scope.global ? "global" : "project"} scope.`
3496
+ );
3497
+ process.exitCode = 1;
3498
+ return void 0;
3499
+ }
3500
+ return targetGroup;
2853
3501
  };
2854
- var mcpManageCommand = new import_commander.Command("manage").description("Inspect, modify, and sync installed MCP servers across coding agents").argument("[server-name]", "Optional server name to inspect or manage").option("-a, --agent <agents...>", "Target specific agents for update").option("-g, --global", "Manage global scope servers instead of project").option("-t, --transport <type>", "Transport type for remote servers (http or sse)").option("--header <header...>", "HTTP header (Header: Value), repeatable").option("--env <env...>", "Env var for stdio servers (KEY=VALUE), repeatable").option("--args <args...>", "CLI arguments for stdio/package servers").option("--command <command>", "Executable command for stdio servers").option("--url <url>", "Remote endpoint URL").option("-y, --yes", "Skip interactive prompts").action(async (serverName, options) => {
3502
+ var mcpManageCommand = new import_commander.Command("manage").description("Inspect, modify, and sync installed MCP servers across coding agents").argument("[server-name]", "Optional server name to inspect or manage").option("-a, --agent <agents...>", "Target specific agents for update").option("-g, --global", "Manage global scope servers instead of project").option("-t, --transport <type>", "Transport type for remote servers (http or sse)").option("--header <header...>", "HTTP header (Header: Value), repeatable").option("--clear-headers", "Clear all HTTP headers for remote servers").option("--env <env...>", "Env var for stdio servers (KEY=VALUE), repeatable").option("--clear-env", "Clear all environment variables for stdio servers").option("--args <args...>", "CLI arguments for stdio/package servers").option("--clear-args", "Clear all arguments for stdio/package servers").option("--command <command>", "Executable command for stdio servers").option("--url <url>", "Remote endpoint URL").option("-y, --yes", "Skip interactive prompts").action(async (serverName, options) => {
2855
3503
  try {
2856
3504
  const cwd = process.cwd();
2857
3505
  const isGlobal = Boolean(options.global);
2858
- const hasModifications = options.command !== void 0 || options.args !== void 0 || options.env !== void 0 || options.header !== void 0 || options.url !== void 0 || options.transport !== void 0;
3506
+ const hasModifications = options.command !== void 0 || options.args !== void 0 || Boolean(options.clearArgs) || options.env !== void 0 || Boolean(options.clearEnv) || options.header !== void 0 || Boolean(options.clearHeaders) || options.url !== void 0 || options.transport !== void 0;
2859
3507
  const isInteractive = Boolean(process.stdin.isTTY && !options.yes);
2860
3508
  if (hasModifications) {
3509
+ if (options.url !== void 0 && options.command !== void 0) {
3510
+ logger.error('Cannot specify both "--url" (remote) and "--command" (stdio) simultaneously.');
3511
+ process.exitCode = 1;
3512
+ return;
3513
+ }
2861
3514
  if (!serverName) {
2862
3515
  logger.error('Missing required argument: "server-name" when passing modification flags.');
2863
3516
  process.exitCode = 1;
2864
3517
  return;
2865
3518
  }
2866
- const installed = listInstalledMcpServers({ global: isGlobal, cwd });
2867
- const grouped = groupInstalledServersByName(installed);
2868
- const targetGroup = grouped.get(serverName);
3519
+ const targetGroup = requireTargetServerGroup(serverName, { global: isGlobal, cwd });
2869
3520
  if (!targetGroup) {
2870
- logger.error(
2871
- `MCP server "${serverName}" is not configured in ${isGlobal ? "global" : "project"} scope.`
2872
- );
2873
- process.exitCode = 1;
2874
3521
  return;
2875
3522
  }
2876
- const updatedConfig = {
2877
- ...targetGroup.config,
2878
- args: targetGroup.config.args ? [...targetGroup.config.args] : void 0,
2879
- env: targetGroup.config.env ? { ...targetGroup.config.env } : void 0,
2880
- headers: targetGroup.config.headers ? { ...targetGroup.config.headers } : void 0
2881
- };
3523
+ const isCurrentRemote = Boolean(targetGroup.config.url && targetGroup.config.url.length > 0);
3524
+ const willBeRemote = options.url !== void 0 ? true : options.command !== void 0 ? false : isCurrentRemote;
3525
+ if (willBeRemote) {
3526
+ const ignoredStdioFlags = [];
3527
+ if (options.env !== void 0) ignoredStdioFlags.push("--env");
3528
+ if (options.clearEnv) ignoredStdioFlags.push("--clear-env");
3529
+ if (options.args !== void 0) ignoredStdioFlags.push("--args");
3530
+ if (options.clearArgs) ignoredStdioFlags.push("--clear-args");
3531
+ if (ignoredStdioFlags.length > 0) {
3532
+ const hint = options.url !== void 0 ? "When configuring a remote server, stdio flags are ignored." : "Use --command to switch to stdio mode.";
3533
+ logger.warn(
3534
+ `Server "${serverName}" is a remote server. The following stdio flags will be ignored: ${ignoredStdioFlags.join(", ")}. ${hint}`
3535
+ );
3536
+ }
3537
+ } else {
3538
+ const ignoredRemoteFlags = [];
3539
+ if (options.header !== void 0) ignoredRemoteFlags.push("--header");
3540
+ if (options.clearHeaders) ignoredRemoteFlags.push("--clear-headers");
3541
+ if (options.transport !== void 0) ignoredRemoteFlags.push("--transport");
3542
+ if (ignoredRemoteFlags.length > 0) {
3543
+ const hint = options.command !== void 0 ? "When configuring a stdio server, remote flags are ignored." : "Use --url to switch to remote mode.";
3544
+ logger.warn(
3545
+ `Server "${serverName}" is a stdio server. The following remote flags will be ignored: ${ignoredRemoteFlags.join(", ")}. ${hint}`
3546
+ );
3547
+ }
3548
+ }
3549
+ const incomingDelta = {};
2882
3550
  if (options.command !== void 0) {
2883
- updatedConfig.command = options.command;
3551
+ incomingDelta.command = options.command;
3552
+ }
3553
+ if (options.clearArgs) {
3554
+ incomingDelta.args = void 0;
2884
3555
  }
2885
3556
  if (options.args !== void 0) {
2886
- updatedConfig.args = options.args;
3557
+ incomingDelta.args = options.args;
2887
3558
  }
2888
3559
  if (options.url !== void 0) {
2889
- updatedConfig.url = options.url;
3560
+ incomingDelta.url = options.url;
2890
3561
  }
2891
3562
  if (options.transport !== void 0) {
2892
- updatedConfig.type = resolveTransport(options.transport);
3563
+ incomingDelta.type = resolveTransport(options.transport);
3564
+ }
3565
+ if (options.clearEnv) {
3566
+ incomingDelta.env = void 0;
2893
3567
  }
2894
3568
  if (options.env !== void 0) {
2895
3569
  const parsedEnv = parseKeyValueList(options.env, "=");
2896
- updatedConfig.env = { ...updatedConfig.env ?? {}, ...parsedEnv };
3570
+ const baseEnv = options.clearEnv ? {} : targetGroup.config.env ?? {};
3571
+ incomingDelta.env = { ...baseEnv, ...parsedEnv };
3572
+ }
3573
+ if (options.clearHeaders) {
3574
+ incomingDelta.headers = void 0;
2897
3575
  }
2898
3576
  if (options.header !== void 0) {
2899
3577
  const parsedHeaders = parseKeyValueList(options.header, ":");
2900
- updatedConfig.headers = { ...updatedConfig.headers ?? {}, ...parsedHeaders };
2901
- }
2902
- const targetAgents = options.agent ? parseMcpAgentList(options.agent) ?? targetGroup.agents : targetGroup.agents;
2903
- const requestedTransport = updatedConfig.url ? updatedConfig.type ?? "http" : "stdio";
2904
- const compatibleAgents = [];
2905
- for (const agent of targetAgents) {
2906
- const agentConfig = getMcpAgentConfig(agent);
2907
- if (isMcpTransportSupported(agentConfig, requestedTransport)) {
2908
- compatibleAgents.push(agent);
2909
- } else {
2910
- const reason = agentConfig.unsupportedTransportMessage ?? `Agent does not support ${requestedTransport} transport`;
2911
- logger.warn(`Skipping ${import_picocolors12.default.cyan(agent)}: ${reason}`);
3578
+ const baseHeaders = options.clearHeaders ? {} : targetGroup.config.headers ?? {};
3579
+ incomingDelta.headers = { ...baseHeaders, ...parsedHeaders };
3580
+ }
3581
+ let targetAgents = targetGroup.agents;
3582
+ if (options.agent !== void 0) {
3583
+ const parsed = parseMcpAgentList(options.agent);
3584
+ if (!parsed || parsed.length === 0) {
3585
+ logger.error(`No valid agents recognized from: "${options.agent.join(", ")}".`);
3586
+ process.exitCode = 1;
3587
+ return;
2912
3588
  }
3589
+ targetAgents = parsed;
3590
+ }
3591
+ const updateResult = updateMcpServer({
3592
+ serverName,
3593
+ config: incomingDelta,
3594
+ previousConfig: targetGroup.config,
3595
+ agents: targetAgents,
3596
+ global: isGlobal,
3597
+ cwd
3598
+ });
3599
+ for (const item of updateResult.incompatible) {
3600
+ logger.warn(`Skipping ${import_picocolors16.default.cyan(item.agent)}: ${item.reason}`);
2913
3601
  }
2914
- if (compatibleAgents.length === 0) {
3602
+ const attemptedResults = updateResult.results.filter(
3603
+ (r) => !updateResult.incompatible.some((i) => i.agent === r.agent)
3604
+ );
3605
+ if (attemptedResults.length === 0) {
3606
+ const requestedTransport = updateResult.config.url ? updateResult.config.type ?? "http" : "stdio";
2915
3607
  logger.error(
2916
3608
  `None of the target agents support ${requestedTransport} transport. Update aborted.`
2917
3609
  );
@@ -2919,19 +3611,16 @@ var mcpManageCommand = new import_commander.Command("manage").description("Inspe
2919
3611
  return;
2920
3612
  }
2921
3613
  logger.info(
2922
- `Updating ${import_picocolors12.default.bold(serverName)} across ${import_picocolors12.default.cyan(String(compatibleAgents.length))} agent(s)...`
3614
+ `Updating ${import_picocolors16.default.bold(serverName)} across ${import_picocolors16.default.cyan(String(attemptedResults.length))} agent(s)...`
2923
3615
  );
2924
3616
  let allSuccess = true;
2925
- for (const agent of compatibleAgents) {
2926
- const res = installMcpServerForAgent(serverName, updatedConfig, agent, {
2927
- global: isGlobal,
2928
- cwd
2929
- });
3617
+ for (const res of attemptedResults) {
2930
3618
  if (res.success) {
2931
- logger.success(`${import_picocolors12.default.cyan(agent)}: Successfully updated in ${import_picocolors12.default.dim(res.path)}`);
3619
+ logger.success(`${import_picocolors16.default.cyan(res.agent)}: Successfully updated in ${import_picocolors16.default.dim(res.path)}`);
3620
+ logCoHostedNotice("configured", res.coConfiguredAgents);
2932
3621
  } else {
2933
3622
  allSuccess = false;
2934
- logger.error(`${import_picocolors12.default.cyan(agent)}: Update failed - ${res.error}`);
3623
+ logger.error(`${import_picocolors16.default.cyan(res.agent)}: Update failed - ${res.error}`);
2935
3624
  }
2936
3625
  }
2937
3626
  if (!allSuccess) {
@@ -2947,21 +3636,16 @@ var mcpManageCommand = new import_commander.Command("manage").description("Inspe
2947
3636
  process.exitCode = 1;
2948
3637
  return;
2949
3638
  }
2950
- const installed = listInstalledMcpServers({ global: isGlobal, cwd });
2951
- const grouped = groupInstalledServersByName(installed);
2952
- const targetGroup = grouped.get(serverName);
3639
+ const targetGroup = requireTargetServerGroup(serverName, { global: isGlobal, cwd });
2953
3640
  if (!targetGroup) {
2954
- logger.error(
2955
- `MCP server "${serverName}" is not configured in ${isGlobal ? "global" : "project"} scope.`
2956
- );
2957
- process.exitCode = 1;
2958
3641
  return;
2959
3642
  }
2960
3643
  displayServerDetails({
2961
3644
  serverName,
2962
3645
  config: targetGroup.config,
2963
3646
  agents: targetGroup.agents,
2964
- isGlobal
3647
+ global: isGlobal,
3648
+ hasDivergence: targetGroup.hasDivergence
2965
3649
  });
2966
3650
  return;
2967
3651
  }
@@ -2983,17 +3667,23 @@ var mcpManageCommand = new import_commander.Command("manage").description("Inspe
2983
3667
  DEFAULT_REMOTE_TRANSPORT,
2984
3668
  NPX_COMMAND,
2985
3669
  NPX_DASH_Y,
3670
+ SECRET_HEADER_PATTERN,
3671
+ SECRET_KEY_PATTERN,
2986
3672
  add,
2987
3673
  agentConfigStore,
3674
+ buildLinkedAgentChoices,
2988
3675
  buildMcpServerConfig,
2989
3676
  createAgentTransform,
2990
3677
  detectGloballyInstalledMcpAgents,
2991
3678
  detectProjectInstalledMcpAgents,
3679
+ detectUpdateTransition,
2992
3680
  displayServerDetails,
2993
3681
  extractPackageName,
2994
3682
  formatArgsString,
2995
3683
  formatEnvText,
2996
3684
  formatHeadersText,
3685
+ getCandidateAgentsForScope,
3686
+ getCoHostedAgents,
2997
3687
  getMcpAgentConfig,
2998
3688
  getMcpAgentTypes,
2999
3689
  getMcpAgentsSupportingProjectScope,
@@ -3002,11 +3692,13 @@ var mcpManageCommand = new import_commander.Command("manage").description("Inspe
3002
3692
  installMcpServer,
3003
3693
  installMcpServerForAgent,
3004
3694
  installMcpServerForAgents,
3695
+ installToCompatibleAgents,
3005
3696
  isMcpAgentType,
3006
3697
  isMcpTransportSupported,
3007
3698
  isRemoteMcpSource,
3008
3699
  isRemoteServerConfig,
3009
3700
  isStdioServerConfig,
3701
+ linkedCheckbox,
3010
3702
  list,
3011
3703
  listInstalledMcpServers,
3012
3704
  listServersInConfigFile,
@@ -3032,18 +3724,25 @@ var mcpManageCommand = new import_commander.Command("manage").description("Inspe
3032
3724
  promptHeadersConfig,
3033
3725
  promptScope,
3034
3726
  promptScopeAndAgents,
3727
+ promptSwitchServerType,
3035
3728
  readConfigFile,
3036
3729
  remove,
3037
3730
  removeMcpServer,
3038
3731
  removeMcpServerFromAgent,
3039
3732
  removeServerFromConfigFile,
3733
+ resolveConfigClusters,
3040
3734
  resolveMcpAgentAlias,
3041
3735
  resolveMcpConfigTarget,
3042
3736
  resolveTargetAgents,
3737
+ resolveTransport,
3738
+ sanitizeUpdatedServerConfig,
3739
+ sortAgentsWithClusters,
3740
+ toRemoteServerConfig,
3741
+ toStdioServerConfig,
3043
3742
  transformServerConfig,
3044
3743
  transformServerConfigForAgent,
3045
- updateMcpServerForAgent,
3046
- updateMcpServerForAgents,
3744
+ update,
3745
+ updateMcpServer,
3047
3746
  wizardAdd,
3048
3747
  wizardManage,
3049
3748
  wizardRemove,