add-mcp 1.9.1 → 1.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,10 +1,34 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ agents,
4
+ buildAgentSelectionChoices,
5
+ buildServerConfig,
6
+ detectGlobalAgents,
7
+ detectProjectAgents,
8
+ findMatchingServers,
9
+ getAgentTypes,
10
+ getConfigPath,
11
+ getFindRegistries,
12
+ getLastSelectedAgents,
13
+ getProjectCapableAgents,
14
+ installServer,
15
+ installServerForAgent,
16
+ isRemoteSource,
17
+ isTransportSupported,
18
+ listInstalledServers,
19
+ parseSource,
20
+ removeServerFromConfig,
21
+ saveFindRegistries,
22
+ selectAgentsInteractive,
23
+ supportsProjectConfig,
24
+ updateGitignoreWithPaths
25
+ } from "./chunk-B27GVIBZ.js";
2
26
 
3
27
  // src/index.ts
4
28
  import { program } from "commander";
5
- import * as p3 from "@clack/prompts";
29
+ import * as p2 from "@clack/prompts";
6
30
  import chalk from "chalk";
7
- import { homedir as homedir3 } from "os";
31
+ import { homedir } from "os";
8
32
 
9
33
  // src/types.ts
10
34
  var agentAliases = {
@@ -13,809 +37,8 @@ var agentAliases = {
13
37
  "github-copilot": "vscode"
14
38
  };
15
39
 
16
- // src/agents.ts
17
- import * as p from "@clack/prompts";
18
- import { homedir as homedir2 } from "os";
19
- import { dirname as dirname2, join as join2 } from "path";
20
- import { existsSync } from "fs";
21
-
22
- // src/config.ts
23
- import { readFile, writeFile, mkdir, rm } from "fs/promises";
24
- import { dirname, join } from "path";
25
- import { homedir } from "os";
26
- var CONFIG_DIR = "add-mcp";
27
- var CONFIG_FILE = "config.json";
28
- var CURRENT_VERSION = 1;
29
- var LEGACY_AGENTS_DIR = ".agents";
30
- var LEGACY_LOCK_FILE = ".mcp-lock.json";
31
- function getXdgConfigHome() {
32
- return process.env.XDG_CONFIG_HOME || join(homedir(), ".config");
33
- }
34
- function getConfigPath() {
35
- return join(getXdgConfigHome(), CONFIG_DIR, CONFIG_FILE);
36
- }
37
- function getLegacyConfigPath() {
38
- return join(homedir(), LEGACY_AGENTS_DIR, LEGACY_LOCK_FILE);
39
- }
40
- async function readConfig() {
41
- const configPath = getConfigPath();
42
- try {
43
- const content = await readFile(configPath, "utf-8");
44
- const parsed = JSON.parse(content);
45
- if (typeof parsed.version !== "number") {
46
- return createEmptyConfig();
47
- }
48
- if (parsed.version < CURRENT_VERSION) {
49
- return createEmptyConfig();
50
- }
51
- return parsed;
52
- } catch {
53
- }
54
- const legacyPath = getLegacyConfigPath();
55
- try {
56
- const content = await readFile(legacyPath, "utf-8");
57
- const parsed = JSON.parse(content);
58
- if (typeof parsed.version !== "number" || parsed.version < CURRENT_VERSION) {
59
- return createEmptyConfig();
60
- }
61
- await writeConfig(parsed);
62
- await cleanupLegacyConfig();
63
- return parsed;
64
- } catch {
65
- return createEmptyConfig();
66
- }
67
- }
68
- async function writeConfig(config) {
69
- const configPath = getConfigPath();
70
- await mkdir(dirname(configPath), { recursive: true });
71
- const content = JSON.stringify(config, null, 2);
72
- await writeFile(configPath, content, "utf-8");
73
- }
74
- async function cleanupLegacyConfig() {
75
- const legacyPath = getLegacyConfigPath();
76
- try {
77
- await rm(legacyPath, { force: true });
78
- } catch {
79
- }
80
- }
81
- async function getLastSelectedAgents() {
82
- const config = await readConfig();
83
- return config.lastSelectedAgents;
84
- }
85
- async function saveSelectedAgents(agents2) {
86
- const config = await readConfig();
87
- config.lastSelectedAgents = agents2;
88
- await writeConfig(config);
89
- }
90
- async function getFindRegistries() {
91
- const config = await readConfig();
92
- if (!config.findRegistries) return [];
93
- return config.findRegistries.map(normalizeFindRegistryEntry);
94
- }
95
- function normalizeFindRegistryEntry(raw) {
96
- const legacy = raw;
97
- const url = legacy.url ?? legacy.serversUrl;
98
- if (!url || typeof url !== "string") {
99
- throw new Error("Registry entry missing url");
100
- }
101
- return {
102
- url,
103
- ...legacy.label ? { label: legacy.label } : {}
104
- };
105
- }
106
- async function saveFindRegistries(registries) {
107
- const config = await readConfig();
108
- config.findRegistries = registries;
109
- await writeConfig(config);
110
- }
111
- function createEmptyConfig() {
112
- return {
113
- version: CURRENT_VERSION
114
- };
115
- }
116
-
117
- // src/agents.ts
118
- var home = homedir2();
119
- function shortenPath(fullPath) {
120
- if (fullPath.startsWith(home)) {
121
- return fullPath.replace(home, "~");
122
- }
123
- return fullPath;
124
- }
125
- function getPlatformPaths() {
126
- const platform = process.platform;
127
- if (platform === "win32") {
128
- const appData = process.env.APPDATA || join2(home, "AppData", "Roaming");
129
- return {
130
- appSupport: appData,
131
- vscodePath: join2(appData, "Code", "User"),
132
- gooseConfigPath: join2(appData, "Block", "goose", "config", "config.yaml")
133
- };
134
- } else if (platform === "darwin") {
135
- return {
136
- appSupport: join2(home, "Library", "Application Support"),
137
- vscodePath: join2(home, "Library", "Application Support", "Code", "User"),
138
- gooseConfigPath: join2(home, ".config", "goose", "config.yaml")
139
- };
140
- } else {
141
- const configDir = process.env.XDG_CONFIG_HOME || join2(home, ".config");
142
- return {
143
- appSupport: configDir,
144
- vscodePath: join2(configDir, "Code", "User"),
145
- gooseConfigPath: join2(configDir, "goose", "config.yaml")
146
- };
147
- }
148
- }
149
- var { appSupport, vscodePath, gooseConfigPath } = getPlatformPaths();
150
- var antigravityConfigPath = join2(
151
- home,
152
- ".gemini",
153
- "antigravity",
154
- "mcp_config.json"
155
- );
156
- var clineCliConfigPath = join2(
157
- process.env.CLINE_DIR || join2(home, ".cline"),
158
- "data",
159
- "settings",
160
- "cline_mcp_settings.json"
161
- );
162
- var clineExtensionConfigPath = join2(
163
- vscodePath,
164
- "globalStorage",
165
- "saoudrizwan.claude-dev",
166
- "settings",
167
- "cline_mcp_settings.json"
168
- );
169
- var copilotConfigPath = join2(
170
- process.env.XDG_CONFIG_HOME || join2(home, ".copilot"),
171
- "mcp-config.json"
172
- );
173
- function transformGooseConfig(serverName, config) {
174
- if (config.url) {
175
- const gooseType = config.type === "sse" ? "sse" : "streamable_http";
176
- return {
177
- name: serverName,
178
- description: "",
179
- type: gooseType,
180
- uri: config.url,
181
- headers: config.headers || {},
182
- enabled: true,
183
- timeout: 300
184
- };
185
- }
186
- return {
187
- name: serverName,
188
- description: "",
189
- cmd: config.command,
190
- args: config.args || [],
191
- enabled: true,
192
- envs: config.env || {},
193
- type: "stdio",
194
- timeout: 300
195
- };
196
- }
197
- function transformZedConfig(_serverName, config) {
198
- if (config.url) {
199
- return {
200
- source: "custom",
201
- type: config.type || "http",
202
- url: config.url,
203
- headers: config.headers || {}
204
- };
205
- }
206
- return {
207
- source: "custom",
208
- command: config.command,
209
- args: config.args || [],
210
- env: config.env || {}
211
- };
212
- }
213
- function transformOpenCodeConfig(_serverName, config) {
214
- if (config.url) {
215
- return {
216
- type: "remote",
217
- url: config.url,
218
- enabled: true,
219
- headers: config.headers
220
- };
221
- }
222
- return {
223
- type: "local",
224
- command: [config.command, ...config.args || []],
225
- enabled: true,
226
- environment: config.env || {}
227
- };
228
- }
229
- function transformCodexConfig(_serverName, config) {
230
- if (config.url) {
231
- const remoteConfig = {
232
- type: config.type || "http",
233
- url: config.url
234
- };
235
- if (config.headers && Object.keys(config.headers).length > 0) {
236
- remoteConfig.http_headers = config.headers;
237
- }
238
- return remoteConfig;
239
- }
240
- return {
241
- command: config.command,
242
- args: config.args || [],
243
- env: config.env
244
- };
245
- }
246
- function transformCursorConfig(_serverName, config) {
247
- if (config.url) {
248
- const remoteConfig = {
249
- url: config.url
250
- };
251
- if (config.headers && Object.keys(config.headers).length > 0) {
252
- remoteConfig.headers = config.headers;
253
- }
254
- return remoteConfig;
255
- }
256
- return config;
257
- }
258
- function transformClineConfig(_serverName, config) {
259
- if (config.url) {
260
- const remoteConfig = {
261
- url: config.url,
262
- type: config.type === "sse" ? "sse" : "streamableHttp",
263
- disabled: false
264
- };
265
- if (config.headers && Object.keys(config.headers).length > 0) {
266
- remoteConfig.headers = config.headers;
267
- }
268
- return remoteConfig;
269
- }
270
- const localConfig = {
271
- command: config.command,
272
- args: config.args || [],
273
- disabled: false
274
- };
275
- if (config.env && Object.keys(config.env).length > 0) {
276
- localConfig.env = config.env;
277
- }
278
- return localConfig;
279
- }
280
- function transformAntigravityConfig(_serverName, config) {
281
- if (config.url) {
282
- const remoteConfig = {
283
- serverUrl: config.url
284
- };
285
- if (config.headers && Object.keys(config.headers).length > 0) {
286
- remoteConfig.headers = config.headers;
287
- }
288
- return remoteConfig;
289
- }
290
- const localConfig = {
291
- command: config.command,
292
- args: config.args || []
293
- };
294
- if (config.env && Object.keys(config.env).length > 0) {
295
- localConfig.env = config.env;
296
- }
297
- return localConfig;
298
- }
299
- function transformGitHubCopilotCliConfig(_serverName, config, context) {
300
- if (context?.local) {
301
- return config;
302
- }
303
- if (config.url) {
304
- const remoteConfig = {
305
- type: config.type || "http",
306
- url: config.url,
307
- tools: ["*"]
308
- };
309
- if (config.headers && Object.keys(config.headers).length > 0) {
310
- remoteConfig.headers = config.headers;
311
- }
312
- return remoteConfig;
313
- }
314
- const localConfig = {
315
- type: "stdio",
316
- command: config.command,
317
- args: config.args || [],
318
- tools: ["*"]
319
- };
320
- if (config.env && Object.keys(config.env).length > 0) {
321
- localConfig.env = config.env;
322
- }
323
- return localConfig;
324
- }
325
- function resolveMcporterConfigPath(agent, options) {
326
- if (options.local && agent.localConfigPath) {
327
- return join2(options.cwd, agent.localConfigPath);
328
- }
329
- const globalJsonPath = agent.configPath;
330
- const globalJsoncPath = join2(dirname2(globalJsonPath), "mcporter.jsonc");
331
- if (existsSync(globalJsonPath)) {
332
- return globalJsonPath;
333
- }
334
- if (existsSync(globalJsoncPath)) {
335
- return globalJsoncPath;
336
- }
337
- return globalJsonPath;
338
- }
339
- var agents = {
340
- antigravity: {
341
- name: "antigravity",
342
- displayName: "Antigravity",
343
- configPath: antigravityConfigPath,
344
- projectDetectPaths: [],
345
- // Global only - no project support
346
- configKey: "mcpServers",
347
- format: "json",
348
- supportedTransports: ["stdio", "http", "sse"],
349
- detectGlobalInstall: async () => {
350
- return existsSync(join2(home, ".gemini"));
351
- },
352
- transformConfig: transformAntigravityConfig
353
- },
354
- cline: {
355
- name: "cline",
356
- displayName: "Cline VSCode Extension",
357
- configPath: clineExtensionConfigPath,
358
- projectDetectPaths: [],
359
- // Global only - no project support
360
- configKey: "mcpServers",
361
- format: "json",
362
- supportedTransports: ["stdio", "http", "sse"],
363
- detectGlobalInstall: async () => {
364
- return existsSync(dirname2(clineExtensionConfigPath));
365
- },
366
- transformConfig: transformClineConfig
367
- },
368
- "cline-cli": {
369
- name: "cline-cli",
370
- displayName: "Cline CLI",
371
- configPath: clineCliConfigPath,
372
- projectDetectPaths: [],
373
- // Global only - no project support
374
- configKey: "mcpServers",
375
- format: "json",
376
- supportedTransports: ["stdio", "http", "sse"],
377
- detectGlobalInstall: async () => {
378
- return existsSync(dirname2(clineCliConfigPath));
379
- },
380
- transformConfig: transformClineConfig
381
- },
382
- "claude-code": {
383
- name: "claude-code",
384
- displayName: "Claude Code",
385
- configPath: join2(home, ".claude.json"),
386
- localConfigPath: ".mcp.json",
387
- projectDetectPaths: [".mcp.json", ".claude"],
388
- configKey: "mcpServers",
389
- format: "json",
390
- supportedTransports: ["stdio", "http", "sse"],
391
- detectGlobalInstall: async () => {
392
- return existsSync(join2(home, ".claude"));
393
- }
394
- },
395
- "claude-desktop": {
396
- name: "claude-desktop",
397
- displayName: "Claude Desktop",
398
- configPath: join2(appSupport, "Claude", "claude_desktop_config.json"),
399
- projectDetectPaths: [],
400
- // Global only - no project support
401
- configKey: "mcpServers",
402
- format: "json",
403
- supportedTransports: ["stdio"],
404
- unsupportedTransportMessage: "Claude Desktop only supports local (stdio) servers via its config file. Add remote servers through Settings \u2192 Connectors in the app instead.",
405
- detectGlobalInstall: async () => {
406
- return existsSync(join2(appSupport, "Claude"));
407
- }
408
- },
409
- codex: {
410
- name: "codex",
411
- displayName: "Codex",
412
- configPath: join2(
413
- process.env.CODEX_HOME || join2(home, ".codex"),
414
- "config.toml"
415
- ),
416
- localConfigPath: ".codex/config.toml",
417
- projectDetectPaths: [".codex"],
418
- configKey: "mcp_servers",
419
- format: "toml",
420
- supportedTransports: ["stdio", "http", "sse"],
421
- detectGlobalInstall: async () => {
422
- return existsSync(join2(home, ".codex"));
423
- },
424
- transformConfig: transformCodexConfig
425
- },
426
- cursor: {
427
- name: "cursor",
428
- displayName: "Cursor",
429
- configPath: join2(home, ".cursor", "mcp.json"),
430
- localConfigPath: ".cursor/mcp.json",
431
- projectDetectPaths: [".cursor"],
432
- configKey: "mcpServers",
433
- format: "json",
434
- supportedTransports: ["stdio", "http", "sse"],
435
- detectGlobalInstall: async () => {
436
- return existsSync(join2(home, ".cursor"));
437
- },
438
- transformConfig: transformCursorConfig
439
- },
440
- "gemini-cli": {
441
- name: "gemini-cli",
442
- displayName: "Gemini CLI",
443
- configPath: join2(home, ".gemini", "settings.json"),
444
- localConfigPath: ".gemini/settings.json",
445
- projectDetectPaths: [".gemini"],
446
- configKey: "mcpServers",
447
- format: "json",
448
- supportedTransports: ["stdio", "http", "sse"],
449
- detectGlobalInstall: async () => {
450
- return existsSync(join2(home, ".gemini"));
451
- }
452
- },
453
- goose: {
454
- name: "goose",
455
- displayName: "Goose",
456
- configPath: gooseConfigPath,
457
- projectDetectPaths: [],
458
- // Global only - no project support
459
- configKey: "extensions",
460
- format: "yaml",
461
- supportedTransports: ["stdio", "http", "sse"],
462
- detectGlobalInstall: async () => {
463
- return existsSync(gooseConfigPath);
464
- },
465
- transformConfig: transformGooseConfig
466
- },
467
- "github-copilot-cli": {
468
- name: "github-copilot-cli",
469
- displayName: "GitHub Copilot CLI",
470
- configPath: copilotConfigPath,
471
- localConfigPath: ".vscode/mcp.json",
472
- projectDetectPaths: [".vscode"],
473
- configKey: "mcpServers",
474
- localConfigKey: "servers",
475
- format: "json",
476
- supportedTransports: ["stdio", "http", "sse"],
477
- detectGlobalInstall: async () => {
478
- return existsSync(dirname2(copilotConfigPath));
479
- },
480
- transformConfig: transformGitHubCopilotCliConfig
481
- },
482
- mcporter: {
483
- name: "mcporter",
484
- displayName: "MCPorter",
485
- configPath: join2(home, ".mcporter", "mcporter.json"),
486
- localConfigPath: "config/mcporter.json",
487
- projectDetectPaths: ["config/mcporter.json"],
488
- configKey: "mcpServers",
489
- format: "json",
490
- supportedTransports: ["stdio", "http", "sse"],
491
- detectGlobalInstall: async () => {
492
- return existsSync(join2(home, ".mcporter"));
493
- },
494
- resolveConfigPath: resolveMcporterConfigPath
495
- },
496
- opencode: {
497
- name: "opencode",
498
- displayName: "OpenCode",
499
- configPath: join2(home, ".config", "opencode", "opencode.json"),
500
- localConfigPath: "opencode.json",
501
- projectDetectPaths: ["opencode.json", ".opencode"],
502
- configKey: "mcp",
503
- format: "json",
504
- supportedTransports: ["stdio", "http", "sse"],
505
- detectGlobalInstall: async () => {
506
- return existsSync(join2(home, ".config", "opencode"));
507
- },
508
- transformConfig: transformOpenCodeConfig
509
- },
510
- vscode: {
511
- name: "vscode",
512
- displayName: "VS Code",
513
- configPath: join2(vscodePath, "mcp.json"),
514
- localConfigPath: ".vscode/mcp.json",
515
- projectDetectPaths: [".vscode"],
516
- configKey: "servers",
517
- format: "json",
518
- supportedTransports: ["stdio", "http", "sse"],
519
- detectGlobalInstall: async () => {
520
- return existsSync(vscodePath);
521
- }
522
- },
523
- zed: {
524
- name: "zed",
525
- displayName: "Zed",
526
- configPath: process.platform === "darwin" || process.platform === "win32" ? join2(appSupport, "Zed", "settings.json") : join2(appSupport, "zed", "settings.json"),
527
- localConfigPath: ".zed/settings.json",
528
- projectDetectPaths: [".zed"],
529
- configKey: "context_servers",
530
- format: "json",
531
- supportedTransports: ["stdio", "http", "sse"],
532
- detectGlobalInstall: async () => {
533
- const configDir = process.platform === "darwin" || process.platform === "win32" ? join2(appSupport, "Zed") : join2(appSupport, "zed");
534
- return existsSync(configDir);
535
- },
536
- transformConfig: transformZedConfig
537
- }
538
- };
539
- function getAgentTypes() {
540
- return Object.keys(agents);
541
- }
542
- function supportsProjectConfig(agentType) {
543
- return agents[agentType].localConfigPath !== void 0;
544
- }
545
- function getProjectCapableAgents() {
546
- return Object.keys(agents).filter(
547
- (type) => supportsProjectConfig(type)
548
- );
549
- }
550
- function detectProjectAgents(cwd) {
551
- const dir = cwd || process.cwd();
552
- const detected = [];
553
- for (const [type, config] of Object.entries(agents)) {
554
- if (!config.localConfigPath) continue;
555
- for (const detectPath of config.projectDetectPaths) {
556
- if (existsSync(join2(dir, detectPath))) {
557
- detected.push(type);
558
- break;
559
- }
560
- }
561
- }
562
- return detected;
563
- }
564
- async function detectAllGlobalAgents() {
565
- const detected = [];
566
- for (const [type, config] of Object.entries(agents)) {
567
- if (await config.detectGlobalInstall()) {
568
- detected.push(type);
569
- }
570
- }
571
- return detected;
572
- }
573
- function isTransportSupported(agentType, transport) {
574
- return agents[agentType].supportedTransports.includes(transport);
575
- }
576
- function buildAgentSelectionChoices(options) {
577
- const { availableAgents, detectedAgents, agentRouting, lastSelected } = options;
578
- const detectedSet = new Set(detectedAgents);
579
- const validLastSelected = lastSelected?.filter(
580
- (agent) => availableAgents.includes(agent) && !detectedSet.has(agent)
581
- ) ?? [];
582
- const remainingAgents = availableAgents.filter(
583
- (agent) => !detectedSet.has(agent) && !validLastSelected.includes(agent)
584
- );
585
- const orderedAgents = [
586
- ...detectedAgents,
587
- ...validLastSelected,
588
- ...remainingAgents
589
- ];
590
- const choices = orderedAgents.map((agentType) => {
591
- const routing = agentRouting.get(agentType);
592
- const baseHint = routing === "local" ? "project" : routing === "global" ? "global" : shortenPath(agents[agentType].configPath);
593
- const lastSelectedHint = validLastSelected.includes(agentType) ? "selected last time" : "";
594
- const hint = lastSelectedHint ? `${baseHint} \xB7 ${lastSelectedHint}` : baseHint;
595
- return {
596
- value: agentType,
597
- label: agents[agentType].displayName,
598
- hint
599
- };
600
- });
601
- return { choices, initialValues: detectedAgents };
602
- }
603
- async function promptForAgents(message, choices, defaultToAll = false) {
604
- let lastSelected;
605
- try {
606
- lastSelected = await getLastSelectedAgents();
607
- } catch {
608
- }
609
- const validAgents = choices.map((c) => c.value);
610
- let initialValues;
611
- if (lastSelected && lastSelected.length > 0) {
612
- initialValues = lastSelected.filter(
613
- (a) => validAgents.includes(a)
614
- );
615
- if (initialValues.length === 0 && defaultToAll) {
616
- initialValues = validAgents;
617
- }
618
- } else {
619
- initialValues = defaultToAll ? validAgents : [];
620
- }
621
- const selected = await p.multiselect({
622
- message,
623
- options: choices,
624
- required: true,
625
- initialValues
626
- });
627
- if (!p.isCancel(selected)) {
628
- try {
629
- await saveSelectedAgents(selected);
630
- } catch {
631
- }
632
- }
633
- return selected;
634
- }
635
- async function selectAgentsInteractive(availableAgents, options) {
636
- let lastSelected;
637
- try {
638
- lastSelected = await getLastSelectedAgents();
639
- } catch {
640
- }
641
- const validLastSelected = lastSelected?.filter(
642
- (a) => availableAgents.includes(a)
643
- );
644
- const selectOptions = [];
645
- const hasPrevious = validLastSelected && validLastSelected.length > 0;
646
- if (hasPrevious) {
647
- const agentNames = validLastSelected.map((a) => agents[a].displayName).join(", ");
648
- selectOptions.push({
649
- value: "previous",
650
- label: "Same as last time",
651
- hint: agentNames
652
- });
653
- }
654
- selectOptions.push({
655
- value: "all",
656
- label: hasPrevious ? "All available agents" : "All available agents",
657
- hint: `Install to all ${availableAgents.length} available agents`
658
- });
659
- selectOptions.push({
660
- value: "select",
661
- label: "Select specific agents",
662
- hint: "Choose which agents to install to"
663
- });
664
- const installChoice = await p.select({
665
- message: "Install to",
666
- options: selectOptions
667
- });
668
- if (p.isCancel(installChoice)) {
669
- return installChoice;
670
- }
671
- if (installChoice === "all") {
672
- return availableAgents;
673
- }
674
- if (installChoice === "previous" && validLastSelected) {
675
- return validLastSelected;
676
- }
677
- const agentChoices = availableAgents.map((agentType) => {
678
- const localPath = agents[agentType].localConfigPath;
679
- const hint = options.global ? shortenPath(agents[agentType].configPath) : localPath ?? shortenPath(agents[agentType].configPath);
680
- return {
681
- value: agentType,
682
- label: agents[agentType].displayName,
683
- hint
684
- };
685
- });
686
- return promptForAgents("Select agents to install to", agentChoices, false);
687
- }
688
-
689
- // src/source-parser.ts
690
- function isUrl(input) {
691
- return input.startsWith("http://") || input.startsWith("https://");
692
- }
693
- function isCommand(input) {
694
- if (input.includes(" ")) {
695
- return true;
696
- }
697
- if (input.startsWith("npx ") || input.startsWith("node ") || input.startsWith("python ")) {
698
- return true;
699
- }
700
- return false;
701
- }
702
- function isPackageName(input) {
703
- if (input.startsWith("@") && input.includes("/")) {
704
- return true;
705
- }
706
- if (/^[a-z0-9][\w.-]*(@[\w.-]+)?$/i.test(input)) {
707
- return true;
708
- }
709
- return false;
710
- }
711
- var commonTlds = /* @__PURE__ */ new Set([
712
- "com",
713
- "org",
714
- "net",
715
- "io",
716
- "dev",
717
- "ai",
718
- "tech",
719
- "co",
720
- "app",
721
- "cloud",
722
- "sh",
723
- "run"
724
- ]);
725
- function extractBrandFromHostname(hostname) {
726
- const parts = hostname.split(".");
727
- const meaningfulParts = parts.filter((part) => {
728
- const lower = part.toLowerCase();
729
- if (commonTlds.has(lower)) return false;
730
- if (lower === "mcp" || lower === "api" || lower === "www") return false;
731
- return true;
732
- });
733
- if (meaningfulParts.length > 0) {
734
- return meaningfulParts[0];
735
- }
736
- if (parts.length >= 2) {
737
- return parts[parts.length - 2];
738
- }
739
- return "mcp-server";
740
- }
741
- function inferName(input, type) {
742
- if (type === "remote") {
743
- try {
744
- const url = new URL(input);
745
- return extractBrandFromHostname(url.hostname);
746
- } catch {
747
- return "mcp-server";
748
- }
749
- }
750
- if (type === "command") {
751
- const parts = input.split(" ");
752
- let startIndex = 0;
753
- if (parts[0] === "npx" || parts[0] === "node" || parts[0] === "python") {
754
- startIndex = 1;
755
- }
756
- for (let i = startIndex; i < parts.length; i++) {
757
- const part = parts[i];
758
- if (part && !part.startsWith("-")) {
759
- return extractPackageName(part);
760
- }
761
- }
762
- return "mcp-server";
763
- }
764
- return extractPackageName(input);
765
- }
766
- function extractPackageName(input) {
767
- let name = input;
768
- const atIndex = name.lastIndexOf("@");
769
- if (atIndex > 0 && !name.startsWith("@")) {
770
- name = name.slice(0, atIndex);
771
- } else if (name.startsWith("@") && name.indexOf("@", 1) > 0) {
772
- const secondAt = name.indexOf("@", 1);
773
- name = name.slice(0, secondAt);
774
- }
775
- if (name.startsWith("@") && name.includes("/")) {
776
- const parts = name.split("/");
777
- name = parts[1] || name;
778
- }
779
- name = name.replace(/^mcp-server-/, "");
780
- name = name.replace(/^server-/, "");
781
- name = name.replace(/-mcp$/, "");
782
- return name || "mcp-server";
783
- }
784
- function parseSource(input) {
785
- const trimmed = input.trim();
786
- if (isUrl(trimmed)) {
787
- return {
788
- type: "remote",
789
- value: trimmed,
790
- inferredName: inferName(trimmed, "remote")
791
- };
792
- }
793
- if (isCommand(trimmed)) {
794
- return {
795
- type: "command",
796
- value: trimmed,
797
- inferredName: inferName(trimmed, "command")
798
- };
799
- }
800
- if (isPackageName(trimmed)) {
801
- return {
802
- type: "package",
803
- value: trimmed,
804
- inferredName: inferName(trimmed, "package")
805
- };
806
- }
807
- return {
808
- type: "package",
809
- value: trimmed,
810
- inferredName: inferName(trimmed, "package")
811
- };
812
- }
813
- function isRemoteSource(parsed) {
814
- return parsed.type === "remote";
815
- }
816
-
817
40
  // src/find.ts
818
- import * as p2 from "@clack/prompts";
41
+ import * as p from "@clack/prompts";
819
42
 
820
43
  // src/template.ts
821
44
  var TEMPLATE_PATTERN = /\$\{([^}]+)\}/g;
@@ -936,8 +159,8 @@ function pushPositionalSegments(out, d, raw) {
936
159
  out.push(raw);
937
160
  return;
938
161
  }
939
- for (const p4 of parts) {
940
- out.push(p4);
162
+ for (const p3 of parts) {
163
+ out.push(p3);
941
164
  }
942
165
  return;
943
166
  }
@@ -1250,7 +473,7 @@ function formatFindResultRow(entry) {
1250
473
  return `${display} (${entry.name}) [${transportLabel(entry)}]`;
1251
474
  }
1252
475
  async function promptValue(field) {
1253
- return p2.text({
476
+ return p.text({
1254
477
  message: `${field.label} ${field.isRequired ? "(required)" : "(optional)"}`,
1255
478
  placeholder: field.placeholder
1256
479
  });
@@ -1259,7 +482,7 @@ async function collectPromptValues(fields, ask) {
1259
482
  const values = {};
1260
483
  for (const field of fields) {
1261
484
  const raw = await ask(field);
1262
- if (p2.isCancel(raw)) {
485
+ if (p.isCancel(raw)) {
1263
486
  return { values, cancelled: true };
1264
487
  }
1265
488
  const value = raw != null && typeof raw === "string" ? raw.trim() : "";
@@ -1356,7 +579,7 @@ function resolveNonInteractivePackage(pkg) {
1356
579
  };
1357
580
  }
1358
581
  async function resolveInteractivePackage(pkg) {
1359
- const promptPackageArg = async (info) => p2.text({
582
+ const promptPackageArg = async (info) => p.text({
1360
583
  message: `${info.label} ${info.isRequired ? "(required)" : "(optional)"}`,
1361
584
  placeholder: info.placeholder
1362
585
  });
@@ -1394,7 +617,7 @@ async function buildInstallPlanForEntry(entry, options) {
1394
617
  if (options.yes) {
1395
618
  mode = "remote";
1396
619
  } else {
1397
- const selected = await p2.select({
620
+ const selected = await p.select({
1398
621
  message: `Install mode for ${entry.name}`,
1399
622
  initialValue: "remote",
1400
623
  options: [
@@ -1406,7 +629,7 @@ async function buildInstallPlanForEntry(entry, options) {
1406
629
  }
1407
630
  ]
1408
631
  });
1409
- if (p2.isCancel(selected)) return null;
632
+ if (p.isCancel(selected)) return null;
1410
633
  mode = selected;
1411
634
  }
1412
635
  } else {
@@ -1443,15 +666,15 @@ async function offerFallbackSearch(query, alreadyQueried) {
1443
666
  let selectedRegistries;
1444
667
  if (candidates.length === 1) {
1445
668
  const candidate = candidates[0];
1446
- const confirmed = await p2.confirm({
669
+ const confirmed = await p.confirm({
1447
670
  message: `Search "${candidate.label ?? candidate.url}" (${candidate.url}) instead?`
1448
671
  });
1449
- if (p2.isCancel(confirmed) || !confirmed) {
672
+ if (p.isCancel(confirmed) || !confirmed) {
1450
673
  return null;
1451
674
  }
1452
675
  selectedRegistries = [candidate];
1453
676
  } else {
1454
- const selected = await p2.multiselect({
677
+ const selected = await p.multiselect({
1455
678
  message: "Search other registries instead?",
1456
679
  options: candidates.map((r) => ({
1457
680
  value: r.url,
@@ -1459,7 +682,7 @@ async function offerFallbackSearch(query, alreadyQueried) {
1459
682
  })),
1460
683
  required: true
1461
684
  });
1462
- if (p2.isCancel(selected)) {
685
+ if (p.isCancel(selected)) {
1463
686
  return null;
1464
687
  }
1465
688
  selectedRegistries = candidates.filter(
@@ -1469,12 +692,12 @@ async function offerFallbackSearch(query, alreadyQueried) {
1469
692
  const fallbackResult = await searchRegistry(query, selectedRegistries);
1470
693
  if (fallbackResult.failedRegistries.length > 0) {
1471
694
  for (const failure of fallbackResult.failedRegistries) {
1472
- p2.log.error(formatRegistryFailure(failure));
695
+ p.log.error(formatRegistryFailure(failure));
1473
696
  }
1474
697
  }
1475
698
  if (fallbackResult.entries.length === 0) {
1476
699
  if (fallbackResult.failedRegistries.length === 0) {
1477
- p2.log.warn(`No MCP servers found for "${query}"`);
700
+ p.log.warn(`No MCP servers found for "${query}"`);
1478
701
  }
1479
702
  return null;
1480
703
  }
@@ -1500,8 +723,8 @@ async function selectEntryWithPagination(visibleEntries, message) {
1500
723
  label: `\u25BC Show more results (${remaining} remaining)`
1501
724
  });
1502
725
  }
1503
- const selected = await p2.select({ message, options });
1504
- if (p2.isCancel(selected)) return null;
726
+ const selected = await p.select({ message, options });
727
+ if (p.isCancel(selected)) return null;
1505
728
  if (selected === LOAD_MORE_SENTINEL) {
1506
729
  page++;
1507
730
  continue;
@@ -1522,12 +745,12 @@ async function runFind(query, options) {
1522
745
  const { failedRegistries } = result;
1523
746
  if (failedRegistries.length > 0 && entries.length > 0) {
1524
747
  for (const failure of failedRegistries) {
1525
- p2.log.warn(formatRegistryFailure(failure));
748
+ p.log.warn(formatRegistryFailure(failure));
1526
749
  }
1527
750
  }
1528
751
  if (entries.length === 0 && failedRegistries.length > 0) {
1529
752
  for (const failure of failedRegistries) {
1530
- p2.log.error(formatRegistryFailure(failure));
753
+ p.log.error(formatRegistryFailure(failure));
1531
754
  }
1532
755
  if (!options.yes && !isBrowseMode) {
1533
756
  const fallbackEntries = await offerFallbackSearch(query, registries);
@@ -1538,7 +761,7 @@ async function runFind(query, options) {
1538
761
  }
1539
762
  if (entries.length === 0) {
1540
763
  if (failedRegistries.length === 0) {
1541
- p2.log.warn(
764
+ p.log.warn(
1542
765
  isBrowseMode ? "No MCP servers found in the configured registries" : `No MCP servers found for "${query}"`
1543
766
  );
1544
767
  }
@@ -1554,542 +777,23 @@ async function runFind(query, options) {
1554
777
  return buildInstallPlanForEntry(entry, options);
1555
778
  }
1556
779
 
1557
- // src/installer.ts
1558
- import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "fs";
1559
- import { join as join3, dirname as dirname6, isAbsolute, relative, sep } from "path";
1560
-
1561
- // src/formats/json.ts
1562
- import { readFileSync, writeFileSync, existsSync as existsSync2, mkdirSync } from "fs";
1563
- import { dirname as dirname3 } from "path";
1564
- import * as jsonc from "jsonc-parser";
1565
-
1566
- // src/formats/utils.ts
1567
- function deepMerge(target, source) {
1568
- const result = { ...target };
1569
- for (const key in source) {
1570
- const sourceValue = source[key];
1571
- const targetValue = result[key];
1572
- if (sourceValue && typeof sourceValue === "object" && !Array.isArray(sourceValue)) {
1573
- result[key] = deepMerge(
1574
- targetValue && typeof targetValue === "object" ? targetValue : {},
1575
- sourceValue
1576
- );
1577
- } else {
1578
- result[key] = sourceValue;
1579
- }
1580
- }
1581
- return result;
1582
- }
1583
- function getNestedValue(obj, path) {
1584
- const keys = path.split(".");
1585
- let current = obj;
1586
- for (const key of keys) {
1587
- if (current && typeof current === "object" && key in current) {
1588
- current = current[key];
1589
- } else {
1590
- return void 0;
1591
- }
1592
- }
1593
- return current;
1594
- }
1595
-
1596
- // src/formats/json.ts
1597
- function detectIndent(text3) {
1598
- let result = null;
1599
- jsonc.visit(text3, {
1600
- onObjectProperty: (_property, offset, _length, startLine, startCharacter) => {
1601
- if (result === null && startLine > 0 && startCharacter > 0) {
1602
- const lineStart = text3.lastIndexOf("\n", offset - 1) + 1;
1603
- const whitespace = text3.slice(lineStart, offset);
1604
- result = {
1605
- tabSize: startCharacter,
1606
- insertSpaces: !whitespace.includes(" ")
1607
- };
1608
- }
1609
- }
1610
- });
1611
- return result || { tabSize: 2, insertSpaces: true };
1612
- }
1613
- function readJsonConfig(filePath) {
1614
- if (!existsSync2(filePath)) {
1615
- return {};
1616
- }
1617
- const content = readFileSync(filePath, "utf-8");
1618
- const parsed = jsonc.parse(content);
1619
- return parsed;
1620
- }
1621
- function writeJsonConfig(filePath, config, configKey) {
1622
- const dir = dirname3(filePath);
1623
- if (!existsSync2(dir)) {
1624
- mkdirSync(dir, { recursive: true });
1625
- }
1626
- let originalContent = "";
1627
- let existingConfig = {};
1628
- if (existsSync2(filePath)) {
1629
- originalContent = readFileSync(filePath, "utf-8");
1630
- existingConfig = jsonc.parse(originalContent);
1631
- }
1632
- const mergedConfig = deepMerge(existingConfig, config);
1633
- if (originalContent) {
1634
- try {
1635
- const configKeyPath = configKey.split(".");
1636
- const newValue = getNestedValue(mergedConfig, configKey);
1637
- const edits = jsonc.modify(originalContent, configKeyPath, newValue, {
1638
- formattingOptions: detectIndent(originalContent)
1639
- });
1640
- const updatedContent = jsonc.applyEdits(originalContent, edits);
1641
- writeFileSync(filePath, updatedContent);
1642
- return;
1643
- } catch {
1644
- }
1645
- }
1646
- writeFileSync(filePath, JSON.stringify(mergedConfig, null, 2));
1647
- }
1648
- function removeJsonConfigKey(filePath, configKey, serverName) {
1649
- if (!existsSync2(filePath)) {
1650
- return;
1651
- }
1652
- const originalContent = readFileSync(filePath, "utf-8");
1653
- const configKeyPath = configKey.split(".");
1654
- try {
1655
- const edits = jsonc.modify(
1656
- originalContent,
1657
- [...configKeyPath, serverName],
1658
- void 0,
1659
- { formattingOptions: detectIndent(originalContent) }
1660
- );
1661
- const updatedContent = jsonc.applyEdits(originalContent, edits);
1662
- writeFileSync(filePath, updatedContent);
1663
- return;
1664
- } catch {
1665
- }
1666
- const parsed = jsonc.parse(originalContent);
1667
- const servers = getNestedValue(parsed, configKey);
1668
- if (servers && typeof servers === "object" && serverName in servers) {
1669
- delete servers[serverName];
1670
- }
1671
- writeFileSync(filePath, JSON.stringify(parsed, null, 2));
1672
- }
1673
- function setNestedValue(obj, path, value) {
1674
- const keys = path.split(".");
1675
- const lastKey = keys.pop();
1676
- if (!lastKey) return;
1677
- let current = obj;
1678
- for (const key of keys) {
1679
- if (!current[key] || typeof current[key] !== "object") {
1680
- current[key] = {};
1681
- }
1682
- current = current[key];
1683
- }
1684
- current[lastKey] = value;
1685
- }
1686
-
1687
- // src/formats/yaml.ts
1688
- import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync as existsSync3, mkdirSync as mkdirSync2 } from "fs";
1689
- import { dirname as dirname4 } from "path";
1690
- import yaml from "js-yaml";
1691
- function readYamlConfig(filePath) {
1692
- if (!existsSync3(filePath)) {
1693
- return {};
1694
- }
1695
- const content = readFileSync2(filePath, "utf-8");
1696
- const parsed = yaml.load(content);
1697
- return parsed || {};
1698
- }
1699
- function removeYamlConfigKey(filePath, configKey, serverName) {
1700
- if (!existsSync3(filePath)) {
1701
- return;
1702
- }
1703
- const existing = readYamlConfig(filePath);
1704
- const keys = configKey.split(".");
1705
- let current = existing;
1706
- for (const key of keys) {
1707
- if (current && typeof current === "object" && key in current) {
1708
- current = current[key];
1709
- } else {
1710
- return;
1711
- }
1712
- }
1713
- if (current && typeof current === "object" && serverName in current) {
1714
- delete current[serverName];
1715
- }
1716
- const content = yaml.dump(existing, {
1717
- indent: 2,
1718
- lineWidth: -1,
1719
- noRefs: true
1720
- });
1721
- writeFileSync2(filePath, content);
1722
- }
1723
- function writeYamlConfig(filePath, config) {
1724
- const dir = dirname4(filePath);
1725
- if (!existsSync3(dir)) {
1726
- mkdirSync2(dir, { recursive: true });
1727
- }
1728
- let existingConfig = {};
1729
- if (existsSync3(filePath)) {
1730
- existingConfig = readYamlConfig(filePath);
1731
- }
1732
- const mergedConfig = deepMerge(existingConfig, config);
1733
- const content = yaml.dump(mergedConfig, {
1734
- indent: 2,
1735
- lineWidth: -1,
1736
- noRefs: true
1737
- });
1738
- writeFileSync2(filePath, content);
1739
- }
1740
-
1741
- // src/formats/toml.ts
1742
- import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, existsSync as existsSync4, mkdirSync as mkdirSync3 } from "fs";
1743
- import { dirname as dirname5 } from "path";
1744
- import * as TOML from "@iarna/toml";
1745
- function readTomlConfig(filePath) {
1746
- if (!existsSync4(filePath)) {
1747
- return {};
1748
- }
1749
- const content = readFileSync3(filePath, "utf-8");
1750
- const parsed = TOML.parse(content);
1751
- return parsed;
1752
- }
1753
- function removeTomlConfigKey(filePath, configKey, serverName) {
1754
- if (!existsSync4(filePath)) {
1755
- return;
1756
- }
1757
- const existing = readTomlConfig(filePath);
1758
- const keys = configKey.split(".");
1759
- let current = existing;
1760
- for (const key of keys) {
1761
- if (current && typeof current === "object" && key in current) {
1762
- current = current[key];
1763
- } else {
1764
- return;
1765
- }
1766
- }
1767
- if (current && typeof current === "object" && serverName in current) {
1768
- delete current[serverName];
1769
- }
1770
- const content = TOML.stringify(existing);
1771
- writeFileSync3(filePath, content);
1772
- }
1773
- function writeTomlConfig(filePath, config) {
1774
- const dir = dirname5(filePath);
1775
- if (!existsSync4(dir)) {
1776
- mkdirSync3(dir, { recursive: true });
1777
- }
1778
- let existingConfig = {};
1779
- if (existsSync4(filePath)) {
1780
- existingConfig = readTomlConfig(filePath);
1781
- }
1782
- const mergedConfig = deepMerge(existingConfig, config);
1783
- const content = TOML.stringify(mergedConfig);
1784
- writeFileSync3(filePath, content);
1785
- }
1786
-
1787
- // src/formats/index.ts
1788
- function readConfig2(filePath, format) {
1789
- switch (format) {
1790
- case "json":
1791
- return readJsonConfig(filePath);
1792
- case "yaml":
1793
- return readYamlConfig(filePath);
1794
- case "toml":
1795
- return readTomlConfig(filePath);
1796
- default:
1797
- throw new Error(`Unsupported config format: ${format}`);
1798
- }
1799
- }
1800
- function removeServerFromConfig(filePath, format, configKey, serverName) {
1801
- switch (format) {
1802
- case "json":
1803
- removeJsonConfigKey(filePath, configKey, serverName);
1804
- break;
1805
- case "yaml":
1806
- removeYamlConfigKey(filePath, configKey, serverName);
1807
- break;
1808
- case "toml":
1809
- removeTomlConfigKey(filePath, configKey, serverName);
1810
- break;
1811
- default:
1812
- throw new Error(`Unsupported config format: ${format}`);
1813
- }
1814
- }
1815
- function writeConfig2(filePath, config, format, configKey) {
1816
- switch (format) {
1817
- case "json":
1818
- writeJsonConfig(filePath, config, configKey);
1819
- break;
1820
- case "yaml":
1821
- writeYamlConfig(filePath, config);
1822
- break;
1823
- case "toml":
1824
- writeTomlConfig(filePath, config);
1825
- break;
1826
- default:
1827
- throw new Error(`Unsupported config format: ${format}`);
1828
- }
1829
- }
1830
- function buildConfigWithKey(configKey, serverName, serverConfig) {
1831
- const config = {};
1832
- const servers = {};
1833
- servers[serverName] = serverConfig;
1834
- setNestedValue(config, configKey, servers);
1835
- return config;
1836
- }
1837
-
1838
- // src/installer.ts
1839
- function buildServerConfig(parsed, options = {}) {
1840
- if (parsed.type === "remote") {
1841
- const config2 = {
1842
- type: options.transport ?? "http",
1843
- url: parsed.value
1844
- };
1845
- if (options.headers && Object.keys(options.headers).length > 0) {
1846
- config2.headers = options.headers;
1847
- }
1848
- return config2;
1849
- }
1850
- if (parsed.type === "command") {
1851
- const parts = parsed.value.split(" ");
1852
- const command = parts[0];
1853
- const args = [...parts.slice(1), ...options.args ?? []];
1854
- const config2 = {
1855
- command,
1856
- args
1857
- };
1858
- if (options.env && Object.keys(options.env).length > 0) {
1859
- config2.env = options.env;
1860
- }
1861
- return config2;
1862
- }
1863
- const config = {
1864
- command: "npx",
1865
- args: ["-y", parsed.value, ...options.args ?? []]
1866
- };
1867
- if (options.env && Object.keys(options.env).length > 0) {
1868
- config.env = options.env;
1869
- }
1870
- return config;
1871
- }
1872
- function updateGitignoreWithPaths(paths, options = {}) {
1873
- const cwd = options.cwd || process.cwd();
1874
- const gitignorePath = join3(cwd, ".gitignore");
1875
- const existingContent = existsSync5(gitignorePath) ? readFileSync4(gitignorePath, "utf-8") : "";
1876
- const existingEntries = new Set(
1877
- existingContent.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0)
1878
- );
1879
- const entriesToAdd = [];
1880
- for (const filePath of paths) {
1881
- const relativePath = isAbsolute(filePath) ? relative(cwd, filePath) : filePath;
1882
- if (!relativePath || relativePath.startsWith("..") || isAbsolute(relativePath)) {
1883
- continue;
1884
- }
1885
- const normalizedPath = relativePath.split(sep).join("/");
1886
- const cleanPath = normalizedPath.startsWith("./") ? normalizedPath.slice(2) : normalizedPath;
1887
- if (!cleanPath || cleanPath === ".gitignore" || existingEntries.has(cleanPath)) {
1888
- continue;
1889
- }
1890
- existingEntries.add(cleanPath);
1891
- entriesToAdd.push(cleanPath);
1892
- }
1893
- if (entriesToAdd.length > 0) {
1894
- let nextContent = existingContent;
1895
- if (nextContent.length > 0 && !nextContent.endsWith("\n")) {
1896
- nextContent += "\n";
1897
- }
1898
- nextContent += `${entriesToAdd.join("\n")}
1899
- `;
1900
- writeFileSync4(gitignorePath, nextContent, "utf-8");
1901
- }
1902
- return {
1903
- path: gitignorePath,
1904
- added: entriesToAdd
1905
- };
1906
- }
1907
- function getConfigPath2(agent, options = {}) {
1908
- const local = Boolean(options.local);
1909
- const cwd = options.cwd || process.cwd();
1910
- if (agent.resolveConfigPath) {
1911
- return agent.resolveConfigPath(agent, { local, cwd });
1912
- }
1913
- if (local && agent.localConfigPath) {
1914
- return join3(cwd, agent.localConfigPath);
1915
- }
1916
- return agent.configPath;
1917
- }
1918
- function getConfigKey(agent, options = {}) {
1919
- if (options.local && agent.localConfigKey) {
1920
- return agent.localConfigKey;
1921
- }
1922
- return agent.configKey;
1923
- }
1924
- function installServerForAgent(serverName, serverConfig, agentType, options = {}) {
1925
- const agent = agents[agentType];
1926
- const configPath = getConfigPath2(agent, options);
1927
- try {
1928
- const dir = dirname6(configPath);
1929
- if (!existsSync5(dir)) {
1930
- mkdirSync4(dir, { recursive: true });
1931
- }
1932
- const transformedConfig = agent.transformConfig ? agent.transformConfig(serverName, serverConfig, {
1933
- local: Boolean(options.local)
1934
- }) : serverConfig;
1935
- const configKey = getConfigKey(agent, options);
1936
- const config = buildConfigWithKey(configKey, serverName, transformedConfig);
1937
- writeConfig2(configPath, config, agent.format, configKey);
1938
- return {
1939
- success: true,
1940
- path: configPath
1941
- };
1942
- } catch (error) {
1943
- return {
1944
- success: false,
1945
- path: configPath,
1946
- error: error instanceof Error ? error.message : "Unknown error"
1947
- };
1948
- }
1949
- }
1950
- function installServer(serverName, serverConfig, agentTypes, options = {}) {
1951
- const results = /* @__PURE__ */ new Map();
1952
- for (const agentType of agentTypes) {
1953
- const routing = options.routing?.get(agentType);
1954
- const installOptions = {
1955
- local: routing === "local",
1956
- cwd: options.cwd
1957
- };
1958
- const result = installServerForAgent(
1959
- serverName,
1960
- serverConfig,
1961
- agentType,
1962
- installOptions
1963
- );
1964
- results.set(agentType, result);
1965
- }
1966
- return results;
1967
- }
1968
-
1969
- // src/reader.ts
1970
- function extractServerIdentity(serverConfig) {
1971
- for (const key of ["url", "uri", "serverUrl"]) {
1972
- const value = serverConfig[key];
1973
- if (typeof value === "string" && value.length > 0) {
1974
- return value;
1975
- }
1976
- }
1977
- const command = typeof serverConfig.command === "string" ? serverConfig.command : typeof serverConfig.cmd === "string" ? serverConfig.cmd : void 0;
1978
- if (!command) {
1979
- return "";
1980
- }
1981
- const rawArgs = Array.isArray(serverConfig.args) ? serverConfig.args.filter((a) => typeof a === "string") : Array.isArray(serverConfig.command) ? serverConfig.command.slice(1).filter((a) => typeof a === "string") : [];
1982
- if (command === "npx" || command === "bunx") {
1983
- const yIndex = rawArgs.indexOf("-y");
1984
- const pkgIndex = yIndex >= 0 ? yIndex + 1 : 0;
1985
- const pkg = rawArgs[pkgIndex];
1986
- if (pkg && !pkg.startsWith("-")) {
1987
- return pkg;
1988
- }
1989
- }
1990
- if (Array.isArray(serverConfig.command)) {
1991
- return serverConfig.command.join(" ");
1992
- }
1993
- if (rawArgs.length > 0) {
1994
- return `${command} ${rawArgs.join(" ")}`;
1995
- }
1996
- return command;
1997
- }
1998
- function readServersForAgent(agentType, options) {
1999
- const agent = agents[agentType];
2000
- const installOptions = {
2001
- local: options.scope === "local",
2002
- cwd: options.cwd
2003
- };
2004
- const configPath = getConfigPath2(agent, installOptions);
2005
- const configKey = getConfigKey(agent, installOptions);
2006
- const fullConfig = readConfig2(configPath, agent.format);
2007
- const serversObj = getNestedValue(fullConfig, configKey);
2008
- const servers = [];
2009
- if (serversObj && typeof serversObj === "object" && !Array.isArray(serversObj)) {
2010
- for (const [serverName, serverConfig] of Object.entries(serversObj)) {
2011
- if (serverConfig && typeof serverConfig === "object") {
2012
- const config = serverConfig;
2013
- servers.push({
2014
- serverName,
2015
- config,
2016
- identity: extractServerIdentity(config),
2017
- agentType,
2018
- scope: options.scope,
2019
- configPath
2020
- });
2021
- }
2022
- }
2023
- }
2024
- return {
2025
- agentType,
2026
- displayName: agent.displayName,
2027
- detected: true,
2028
- scope: options.scope,
2029
- configPath,
2030
- servers
2031
- };
2032
- }
2033
- async function gatherInstalledServers(options) {
2034
- const scope = options.global ? "global" : "local";
2035
- const results = [];
2036
- if (options.agents && options.agents.length > 0) {
2037
- const detectedSet = new Set(
2038
- options.global ? await detectAllGlobalAgents() : detectProjectAgents(options.cwd)
2039
- );
2040
- for (const agentType of options.agents) {
2041
- const detected = detectedSet.has(agentType);
2042
- if (detected) {
2043
- results.push(
2044
- readServersForAgent(agentType, { scope, cwd: options.cwd })
2045
- );
2046
- } else {
2047
- const agent = agents[agentType];
2048
- const installOptions = {
2049
- local: scope === "local",
2050
- cwd: options.cwd
2051
- };
2052
- results.push({
2053
- agentType,
2054
- displayName: agent.displayName,
2055
- detected: false,
2056
- scope,
2057
- configPath: getConfigPath2(agent, installOptions),
2058
- servers: []
2059
- });
2060
- }
2061
- }
2062
- } else {
2063
- const detected = options.global ? await detectAllGlobalAgents() : detectProjectAgents(options.cwd);
2064
- for (const agentType of detected) {
2065
- results.push(readServersForAgent(agentType, { scope, cwd: options.cwd }));
2066
- }
2067
- }
2068
- return results;
2069
- }
2070
- function findMatchingServers(agentServersList, query) {
2071
- const lowerQuery = query.toLowerCase();
2072
- const matches = [];
2073
- for (const agentServers of agentServersList) {
2074
- for (const server of agentServers.servers) {
2075
- const nameMatch = server.serverName.toLowerCase().includes(lowerQuery);
2076
- const identityMatch = server.identity === query;
2077
- if (nameMatch || identityMatch) {
2078
- matches.push(server);
2079
- }
2080
- }
2081
- }
2082
- return matches;
2083
- }
2084
-
2085
780
  // package.json
2086
781
  var package_default = {
2087
782
  name: "add-mcp",
2088
- version: "1.9.1",
783
+ version: "1.10.2",
2089
784
  description: "Add MCP servers to your favorite coding agents with a single command.",
2090
785
  author: "Andre Landgraf <andre@neon.tech>",
2091
786
  license: "Apache-2.0",
2092
787
  type: "module",
788
+ main: "./dist/lib.js",
789
+ types: "./dist/lib.d.ts",
790
+ exports: {
791
+ ".": {
792
+ types: "./dist/lib.d.ts",
793
+ import: "./dist/lib.js"
794
+ },
795
+ "./package.json": "./package.json"
796
+ },
2093
797
  bin: {
2094
798
  "add-mcp": "dist/index.js"
2095
799
  },
@@ -2099,10 +803,10 @@ var package_default = {
2099
803
  ],
2100
804
  scripts: {
2101
805
  fmt: "prettier --write .",
2102
- build: "tsup src/index.ts --format esm --dts --clean",
806
+ build: "tsup src/index.ts src/lib.ts --format esm --dts --clean",
2103
807
  dev: "tsx src/index.ts",
2104
- test: "tsx tests/source-parser.test.ts && tsx tests/agents.test.ts && tsx tests/config.test.ts && tsx tests/installer.test.ts && tsx tests/find.test.ts && tsx tests/package-arguments.test.ts && tsx tests/template.test.ts && tsx tests/reader.test.ts && tsx tests/formats-remove.test.ts && tsx tests/e2e/install.test.ts && tsx tests/e2e/cli.test.ts",
2105
- "test:unit": "tsx tests/source-parser.test.ts && tsx tests/agents.test.ts && tsx tests/config.test.ts && tsx tests/installer.test.ts && tsx tests/find.test.ts && tsx tests/package-arguments.test.ts && tsx tests/template.test.ts && tsx tests/reader.test.ts && tsx tests/formats-remove.test.ts",
808
+ test: "tsx tests/source-parser.test.ts && tsx tests/agents.test.ts && tsx tests/config.test.ts && tsx tests/installer.test.ts && tsx tests/find.test.ts && tsx tests/package-arguments.test.ts && tsx tests/template.test.ts && tsx tests/reader.test.ts && tsx tests/formats-remove.test.ts && tsx tests/lib.test.ts && tsx tests/e2e/install.test.ts && tsx tests/e2e/cli.test.ts",
809
+ "test:unit": "tsx tests/source-parser.test.ts && tsx tests/agents.test.ts && tsx tests/config.test.ts && tsx tests/installer.test.ts && tsx tests/find.test.ts && tsx tests/package-arguments.test.ts && tsx tests/template.test.ts && tsx tests/reader.test.ts && tsx tests/formats-remove.test.ts && tsx tests/lib.test.ts",
2106
810
  "registry:sort": "tsx scripts/sort-registry.ts",
2107
811
  "registry:verify": "tsx scripts/verify-registry.ts",
2108
812
  "test:e2e": "tsx tests/e2e/install.test.ts && tsx tests/e2e/cli.test.ts",
@@ -2187,10 +891,10 @@ function showLogo() {
2187
891
  console.log(`${GRAYS[i]}${line}${RESET}`);
2188
892
  });
2189
893
  }
2190
- function shortenPath2(fullPath) {
2191
- const home2 = homedir3();
2192
- if (fullPath.startsWith(home2)) {
2193
- return fullPath.replace(home2, "~");
894
+ function shortenPath(fullPath) {
895
+ const home = homedir();
896
+ if (fullPath.startsWith(home)) {
897
+ return fullPath.replace(home, "~");
2194
898
  }
2195
899
  return fullPath;
2196
900
  }
@@ -2209,13 +913,13 @@ async function ensureFindRegistriesConfigured(yes) {
2209
913
  if (configured.length > 0) {
2210
914
  return configured;
2211
915
  }
2212
- p3.log.warn("Find requires configuring one or more registries");
916
+ p2.log.warn("Find requires configuring one or more registries");
2213
917
  if (yes) {
2214
- p3.log.error("Re-run without --yes to configure registries for find/search");
918
+ p2.log.error("Re-run without --yes to configure registries for find/search");
2215
919
  return null;
2216
920
  }
2217
921
  const defaults = getDefaultFindRegistries();
2218
- const selected = await p3.multiselect({
922
+ const selected = await p2.multiselect({
2219
923
  message: "[One time] Please select what MCP registries you would like to configure globally for search",
2220
924
  options: defaults.map((registry) => ({
2221
925
  value: registry.url,
@@ -2223,15 +927,15 @@ async function ensureFindRegistriesConfigured(yes) {
2223
927
  })),
2224
928
  required: true
2225
929
  });
2226
- if (p3.isCancel(selected)) {
930
+ if (p2.isCancel(selected)) {
2227
931
  return null;
2228
932
  }
2229
933
  const selectedRegistries = defaults.filter(
2230
934
  (registry) => selected.includes(registry.url)
2231
935
  );
2232
936
  await saveFindRegistries(selectedRegistries);
2233
- p3.log.info(
2234
- `Selection has been saved to ${shortenPath2(getConfigPath())} - you can remove or update it any time.`
937
+ p2.log.info(
938
+ `Selection has been saved to ${shortenPath(getConfigPath())} - you can remove or update it any time.`
2235
939
  );
2236
940
  return selectedRegistries;
2237
941
  }
@@ -2426,7 +1130,7 @@ async function runFindCommand(keyword, rawOptions) {
2426
1130
  const query = (keyword ?? "").trim();
2427
1131
  const registries = await ensureFindRegistriesConfigured(options.yes);
2428
1132
  if (!registries) {
2429
- p3.cancel("Find cancelled");
1133
+ p2.cancel("Find cancelled");
2430
1134
  process.exit(0);
2431
1135
  }
2432
1136
  const installPlan = await runFind(query, {
@@ -2435,7 +1139,7 @@ async function runFindCommand(keyword, rawOptions) {
2435
1139
  preferredTransport: inferFindPreferredTransport(options)
2436
1140
  });
2437
1141
  if (!installPlan) {
2438
- p3.cancel("Find cancelled");
1142
+ p2.cancel("Find cancelled");
2439
1143
  process.exit(0);
2440
1144
  }
2441
1145
  const mergedOptions = {
@@ -2511,13 +1215,13 @@ async function runListCommand(options) {
2511
1215
  showLogo();
2512
1216
  console.log();
2513
1217
  const explicitAgents = resolveAgentFlags(options.agent);
2514
- const agentServersList = await gatherInstalledServers({
1218
+ const agentServersList = await listInstalledServers({
2515
1219
  global: options.global,
2516
1220
  agents: explicitAgents.length > 0 ? explicitAgents : void 0
2517
1221
  });
2518
1222
  if (agentServersList.length === 0) {
2519
1223
  const hint = options.global ? "No agents detected globally. Use -a to target a specific agent." : "No agents detected in this project. Use -g for global or -a to target a specific agent.";
2520
- p3.log.info(hint);
1224
+ p2.log.info(hint);
2521
1225
  console.log();
2522
1226
  return;
2523
1227
  }
@@ -2548,13 +1252,13 @@ async function runRemoveCommand(query, options) {
2548
1252
  showLogo();
2549
1253
  console.log();
2550
1254
  const explicitAgents = resolveAgentFlags(options.agent);
2551
- const agentServersList = await gatherInstalledServers({
1255
+ const agentServersList = await listInstalledServers({
2552
1256
  global: options.global,
2553
1257
  agents: explicitAgents.length > 0 ? explicitAgents : void 0
2554
1258
  });
2555
1259
  const matches = findMatchingServers(agentServersList, query);
2556
1260
  if (matches.length === 0) {
2557
- p3.log.info(`No matching servers found for '${query}'`);
1261
+ p2.log.info(`No matching servers found for '${query}'`);
2558
1262
  console.log();
2559
1263
  return;
2560
1264
  }
@@ -2566,24 +1270,24 @@ async function runRemoveCommand(query, options) {
2566
1270
  let selectedIndices;
2567
1271
  if (options.yes) {
2568
1272
  selectedIndices = matches.map((_, i) => i);
2569
- p3.log.info(
1273
+ p2.log.info(
2570
1274
  `Removing ${matches.length} server${matches.length !== 1 ? "s" : ""} matching '${query}'`
2571
1275
  );
2572
1276
  } else {
2573
- const selected = await p3.multiselect({
1277
+ const selected = await p2.multiselect({
2574
1278
  message: `Select servers to remove (${matches.length} match${matches.length !== 1 ? "es" : ""} found)`,
2575
1279
  options: matchOptions,
2576
1280
  required: false,
2577
1281
  initialValues: matches.map((_, i) => i)
2578
1282
  });
2579
- if (p3.isCancel(selected)) {
2580
- p3.log.info("No changes made");
1283
+ if (p2.isCancel(selected)) {
1284
+ p2.log.info("No changes made");
2581
1285
  console.log();
2582
1286
  return;
2583
1287
  }
2584
1288
  selectedIndices = selected;
2585
1289
  if (selectedIndices.length === 0) {
2586
- p3.log.info("No changes made");
1290
+ p2.log.info("No changes made");
2587
1291
  console.log();
2588
1292
  return;
2589
1293
  }
@@ -2603,13 +1307,13 @@ async function runRemoveCommand(query, options) {
2603
1307
  removedCount++;
2604
1308
  affectedAgents.add(agent.displayName);
2605
1309
  } catch (error) {
2606
- p3.log.error(
1310
+ p2.log.error(
2607
1311
  `Failed to remove ${server.serverName} from ${agent.displayName}: ${error instanceof Error ? error.message : "Unknown error"}`
2608
1312
  );
2609
1313
  }
2610
1314
  }
2611
1315
  if (removedCount > 0) {
2612
- p3.log.success(
1316
+ p2.log.success(
2613
1317
  `Removed ${removedCount} server${removedCount !== 1 ? "s" : ""} from ${affectedAgents.size} agent${affectedAgents.size !== 1 ? "s" : ""}`
2614
1318
  );
2615
1319
  }
@@ -2709,14 +1413,14 @@ function buildSyncGroups(agentServersList) {
2709
1413
  async function runSyncCommand(options) {
2710
1414
  showLogo();
2711
1415
  console.log();
2712
- const agentServersList = await gatherInstalledServers({
1416
+ const agentServersList = await listInstalledServers({
2713
1417
  global: options.global
2714
1418
  });
2715
1419
  const agentsWithServers = agentServersList.filter(
2716
1420
  (a) => a.servers.length > 0
2717
1421
  );
2718
1422
  if (agentServersList.length < 2) {
2719
- p3.log.info("Need at least 2 detected agents to sync");
1423
+ p2.log.info("Need at least 2 detected agents to sync");
2720
1424
  console.log();
2721
1425
  return;
2722
1426
  }
@@ -2747,7 +1451,7 @@ async function runSyncCommand(options) {
2747
1451
  }
2748
1452
  }
2749
1453
  if (renames.length === 0 && additions.length === 0 && skipped.length === 0) {
2750
- p3.log.info("All servers are already in sync");
1454
+ p2.log.info("All servers are already in sync");
2751
1455
  console.log();
2752
1456
  return;
2753
1457
  }
@@ -2775,20 +1479,20 @@ async function runSyncCommand(options) {
2775
1479
  }
2776
1480
  }
2777
1481
  if (renames.length === 0 && additions.length === 0) {
2778
- p3.note(planLines.join("\n"), "Sync Plan");
2779
- p3.log.info(
1482
+ p2.note(planLines.join("\n"), "Sync Plan");
1483
+ p2.log.info(
2780
1484
  "All servers are already in sync (some skipped due to conflicts)"
2781
1485
  );
2782
1486
  console.log();
2783
1487
  return;
2784
1488
  }
2785
- p3.note(planLines.join("\n"), "Sync Plan");
1489
+ p2.note(planLines.join("\n"), "Sync Plan");
2786
1490
  if (!options.yes) {
2787
- const confirmed = await p3.confirm({
1491
+ const confirmed = await p2.confirm({
2788
1492
  message: "Proceed with sync?"
2789
1493
  });
2790
- if (p3.isCancel(confirmed) || !confirmed) {
2791
- p3.log.info("No changes made");
1494
+ if (p2.isCancel(confirmed) || !confirmed) {
1495
+ p2.log.info("No changes made");
2792
1496
  console.log();
2793
1497
  return;
2794
1498
  }
@@ -2806,7 +1510,7 @@ async function runSyncCommand(options) {
2806
1510
  if (result.success) {
2807
1511
  changeCount++;
2808
1512
  } else {
2809
- p3.log.error(
1513
+ p2.log.error(
2810
1514
  `Failed to write ${group.canonicalName} to ${agents[agentType].displayName}: ${result.error}`
2811
1515
  );
2812
1516
  }
@@ -2822,7 +1526,7 @@ async function runSyncCommand(options) {
2822
1526
  if (result.success) {
2823
1527
  changeCount++;
2824
1528
  } else {
2825
- p3.log.error(
1529
+ p2.log.error(
2826
1530
  `Failed to add ${group.canonicalName} to ${agents[agentType].displayName}: ${result.error}`
2827
1531
  );
2828
1532
  }
@@ -2840,12 +1544,12 @@ async function runSyncCommand(options) {
2840
1544
  oldName
2841
1545
  );
2842
1546
  } catch (error) {
2843
- p3.log.error(
1547
+ p2.log.error(
2844
1548
  `Failed to remove old alias ${oldName} from ${agentConfig.displayName}: ${error instanceof Error ? error.message : "Unknown error"}`
2845
1549
  );
2846
1550
  }
2847
1551
  }
2848
- p3.log.success(
1552
+ p2.log.success(
2849
1553
  `Synced ${changeCount} server${changeCount !== 1 ? "s" : ""} across ${detectedAgentTypes.size} agent${detectedAgentTypes.size !== 1 ? "s" : ""}`
2850
1554
  );
2851
1555
  console.log();
@@ -2899,8 +1603,8 @@ function resolveAgentFlags(agentFlags) {
2899
1603
  }
2900
1604
  }
2901
1605
  if (invalid.length > 0) {
2902
- p3.log.error(`Invalid agents: ${invalid.join(", ")}`);
2903
- p3.log.info(`Valid agents: ${getAgentTypes().join(", ")}`);
1606
+ p2.log.error(`Invalid agents: ${invalid.join(", ")}`);
1607
+ p2.log.info(`Valid agents: ${getAgentTypes().join(", ")}`);
2904
1608
  process.exit(1);
2905
1609
  }
2906
1610
  return resolved;
@@ -2982,7 +1686,7 @@ async function main(target, options) {
2982
1686
  process.exit(0);
2983
1687
  }
2984
1688
  console.log();
2985
- const spinner2 = p3.spinner();
1689
+ const spinner2 = p2.spinner();
2986
1690
  spinner2.start("Parsing source...");
2987
1691
  const parsed = parseSource(target);
2988
1692
  const isRemote = isRemoteSource(parsed);
@@ -2992,40 +1696,40 @@ async function main(target, options) {
2992
1696
  const headerResult = parseHeaders(headerValues);
2993
1697
  if (headerResult.invalid.length > 0) {
2994
1698
  const hint = looksLikeEatenShellVar(headerResult.invalid, ":") ? " (looks like your shell expanded a ${VAR} to an empty string; use single quotes: --header 'Key: ${VAR}' to pass the template literally)" : "";
2995
- p3.log.error(
2996
- `Invalid --header value(s): ${headerResult.invalid.join(", ")}. Use "Key: Value" format.${hint}`
1699
+ p2.log.error(
1700
+ `Invalid --header value(s): ${headerResult.invalid.join(", ")}. Use 'Key: Value' format.${hint}`
2997
1701
  );
2998
1702
  process.exit(1);
2999
1703
  }
3000
1704
  const headerKeys = Object.keys(headerResult.headers);
3001
1705
  const hasHeaderValues = headerKeys.length > 0;
3002
1706
  if (hasHeaderValues && !isRemote) {
3003
- p3.log.warn("--header is only used for remote URLs, ignoring");
1707
+ p2.log.warn("--header is only used for remote URLs, ignoring");
3004
1708
  }
3005
1709
  const envValues = options.env ?? [];
3006
1710
  const envResult = parseEnv(envValues);
3007
1711
  if (envResult.invalid.length > 0) {
3008
1712
  const hint = looksLikeEatenShellVar(envResult.invalid, "=") ? " (looks like your shell expanded a ${VAR} to an empty string; use single quotes: --env 'KEY=${VAR}' to pass the template literally)" : "";
3009
- p3.log.error(
3010
- `Invalid --env value(s): ${envResult.invalid.join(", ")}. Use "KEY=VALUE" format.${hint}`
1713
+ p2.log.error(
1714
+ `Invalid --env value(s): ${envResult.invalid.join(", ")}. Use 'KEY=VALUE' format.${hint}`
3011
1715
  );
3012
1716
  process.exit(1);
3013
1717
  }
3014
1718
  const envKeys = Object.keys(envResult.env);
3015
1719
  const hasEnvValues = envKeys.length > 0;
3016
1720
  if (hasEnvValues && isRemote) {
3017
- p3.log.warn(
1721
+ p2.log.warn(
3018
1722
  "--env is only used for local/package/command installs, ignoring"
3019
1723
  );
3020
1724
  }
3021
1725
  const argsValues = options.args ?? [];
3022
1726
  const hasArgsValues = argsValues.length > 0;
3023
1727
  if (hasArgsValues && isRemote) {
3024
- p3.log.warn(
1728
+ p2.log.warn(
3025
1729
  "--args is only used for local/package/command installs, ignoring"
3026
1730
  );
3027
1731
  }
3028
- const promptTemplateVar = (varName) => p3.text({
1732
+ const promptTemplateVar = (varName) => p2.text({
3029
1733
  message: `Enter value for ${varName}`,
3030
1734
  placeholder: `<${varName}>`
3031
1735
  });
@@ -3036,7 +1740,7 @@ async function main(target, options) {
3036
1740
  promptTemplateVar
3037
1741
  );
3038
1742
  if (result.cancelled) {
3039
- p3.cancel("Cancelled");
1743
+ p2.cancel("Cancelled");
3040
1744
  process.exit(0);
3041
1745
  }
3042
1746
  for (const [key, value] of Object.entries(result.resolved)) {
@@ -3049,7 +1753,7 @@ async function main(target, options) {
3049
1753
  promptTemplateVar
3050
1754
  );
3051
1755
  if (result.cancelled) {
3052
- p3.cancel("Cancelled");
1756
+ p2.cancel("Cancelled");
3053
1757
  process.exit(0);
3054
1758
  }
3055
1759
  for (const [key, value] of Object.entries(result.resolved)) {
@@ -3059,7 +1763,7 @@ async function main(target, options) {
3059
1763
  if (!options.yes && hasArgsValues && hasTemplateVars(resolvedArgs)) {
3060
1764
  const result = await resolveArrayTemplates(resolvedArgs, promptTemplateVar);
3061
1765
  if (result.cancelled) {
3062
- p3.cancel("Cancelled");
1766
+ p2.cancel("Cancelled");
3063
1767
  process.exit(0);
3064
1768
  }
3065
1769
  resolvedArgs = result.resolved;
@@ -3068,20 +1772,20 @@ async function main(target, options) {
3068
1772
  const envForConfig = !isRemote && hasEnvValues ? omitEmptyStringValues(envResult.env) : void 0;
3069
1773
  const argsForConfig = !isRemote && hasArgsValues ? resolvedArgs.filter((a) => a.trim().length > 0) : void 0;
3070
1774
  const serverName = options.name || parsed.inferredName;
3071
- p3.log.info(`Server name: ${chalk.cyan(serverName)}`);
1775
+ p2.log.info(`Server name: ${chalk.cyan(serverName)}`);
3072
1776
  const transportValue = options.transport || options.type;
3073
1777
  let resolvedTransport;
3074
1778
  if (transportValue) {
3075
1779
  const validTransports = ["http", "sse"];
3076
1780
  if (!validTransports.includes(transportValue)) {
3077
- p3.log.error(
1781
+ p2.log.error(
3078
1782
  `Invalid transport: ${transportValue}. Valid options: ${validTransports.join(", ")}`
3079
1783
  );
3080
1784
  process.exit(1);
3081
1785
  }
3082
1786
  resolvedTransport = transportValue;
3083
1787
  if (!isRemoteSource(parsed)) {
3084
- p3.log.warn("--transport is only used for remote URLs, ignoring");
1788
+ p2.log.warn("--transport is only used for remote URLs, ignoring");
3085
1789
  }
3086
1790
  }
3087
1791
  const serverConfig = buildServerConfig(parsed, {
@@ -3107,19 +1811,19 @@ async function main(target, options) {
3107
1811
  }
3108
1812
  }
3109
1813
  if (invalid.length > 0) {
3110
- p3.log.error(`Invalid agents: ${invalid.join(", ")}`);
3111
- p3.log.info(`Valid agents: ${allAgentTypes.join(", ")}`);
1814
+ p2.log.error(`Invalid agents: ${invalid.join(", ")}`);
1815
+ p2.log.info(`Valid agents: ${allAgentTypes.join(", ")}`);
3112
1816
  process.exit(1);
3113
1817
  }
3114
1818
  targetAgents = resolved;
3115
1819
  } else if (options.all) {
3116
1820
  targetAgents = allAgentTypes;
3117
- p3.log.info(`Installing to all ${targetAgents.length} agents`);
1821
+ p2.log.info(`Installing to all ${targetAgents.length} agents`);
3118
1822
  } else {
3119
1823
  spinner2.start("Detecting agents...");
3120
1824
  let detectedAgents;
3121
1825
  if (options.global) {
3122
- detectedAgents = await detectAllGlobalAgents();
1826
+ detectedAgents = await detectGlobalAgents();
3123
1827
  for (const agent of detectedAgents) {
3124
1828
  agentRouting.set(agent, "global");
3125
1829
  }
@@ -3140,7 +1844,7 @@ async function main(target, options) {
3140
1844
  for (const agent of targetAgents) {
3141
1845
  agentRouting.set(agent, "global");
3142
1846
  }
3143
- p3.log.info(
1847
+ p2.log.info(
3144
1848
  `Installing to ${targetAgents.length} agents globally (none detected)`
3145
1849
  );
3146
1850
  } else {
@@ -3148,20 +1852,20 @@ async function main(target, options) {
3148
1852
  for (const agent of targetAgents) {
3149
1853
  agentRouting.set(agent, "local");
3150
1854
  }
3151
- p3.log.info(
1855
+ p2.log.info(
3152
1856
  `Installing to ${targetAgents.length} project-capable agents (none detected)`
3153
1857
  );
3154
1858
  }
3155
1859
  } else {
3156
1860
  const availableAgents = options.global ? allAgentTypes : getProjectCapableAgents();
3157
- p3.log.warn(
1861
+ p2.log.warn(
3158
1862
  options.global ? "No coding agents detected." : "No agents detected in this project."
3159
1863
  );
3160
1864
  const selected = await selectAgentsInteractive(availableAgents, {
3161
1865
  global: options.global
3162
1866
  });
3163
- if (p3.isCancel(selected)) {
3164
- p3.cancel("Installation cancelled");
1867
+ if (p2.isCancel(selected)) {
1868
+ p2.cancel("Installation cancelled");
3165
1869
  process.exit(0);
3166
1870
  }
3167
1871
  selectedViaPrompt = true;
@@ -3173,7 +1877,7 @@ async function main(target, options) {
3173
1877
  } else if (options.yes) {
3174
1878
  targetAgents = detectedAgents;
3175
1879
  const agentNames = detectedAgents.map((a) => chalk.cyan(agents[a].displayName)).join(", ");
3176
- p3.log.info(`Installing to: ${agentNames}`);
1880
+ p2.log.info(`Installing to: ${agentNames}`);
3177
1881
  } else {
3178
1882
  const availableAgents = options.global ? allAgentTypes : getProjectCapableAgents();
3179
1883
  let lastSelected;
@@ -3187,14 +1891,14 @@ async function main(target, options) {
3187
1891
  agentRouting,
3188
1892
  lastSelected
3189
1893
  });
3190
- const selected = await p3.multiselect({
1894
+ const selected = await p2.multiselect({
3191
1895
  message: "Select agents to install to",
3192
1896
  options: agentChoices,
3193
1897
  required: true,
3194
1898
  initialValues
3195
1899
  });
3196
- if (p3.isCancel(selected)) {
3197
- p3.cancel("Installation cancelled");
1900
+ if (p2.isCancel(selected)) {
1901
+ p2.cancel("Installation cancelled");
3198
1902
  process.exit(0);
3199
1903
  }
3200
1904
  selectedViaPrompt = true;
@@ -3212,25 +1916,25 @@ async function main(target, options) {
3212
1916
  const unsupportedNames = unsupportedAgents.map((a) => agents[a].displayName).join(", ");
3213
1917
  const hints = unsupportedAgents.map((a) => agents[a].unsupportedTransportMessage).filter(Boolean);
3214
1918
  if (options.all) {
3215
- p3.log.warn(
1919
+ p2.log.warn(
3216
1920
  `Skipping agents that don't support ${requiredTransport} transport: ${unsupportedNames}`
3217
1921
  );
3218
1922
  for (const hint of hints) {
3219
- p3.log.info(hint);
1923
+ p2.log.info(hint);
3220
1924
  }
3221
1925
  targetAgents = targetAgents.filter(
3222
1926
  (a) => isTransportSupported(a, requiredTransport)
3223
1927
  );
3224
1928
  if (targetAgents.length === 0) {
3225
- p3.log.error("No agents support this transport type");
1929
+ p2.log.error("No agents support this transport type");
3226
1930
  process.exit(1);
3227
1931
  }
3228
1932
  } else {
3229
- p3.log.error(
1933
+ p2.log.error(
3230
1934
  `The following agents don't support ${requiredTransport} transport: ${unsupportedNames}`
3231
1935
  );
3232
1936
  for (const hint of hints) {
3233
- p3.log.info(hint);
1937
+ p2.log.info(hint);
3234
1938
  }
3235
1939
  process.exit(1);
3236
1940
  }
@@ -3253,7 +1957,7 @@ async function main(target, options) {
3253
1957
  if (selectedWithLocal.length > 0) {
3254
1958
  let installLocally = true;
3255
1959
  if (!options.yes) {
3256
- const scope = await p3.select({
1960
+ const scope = await p2.select({
3257
1961
  message: "Installation scope",
3258
1962
  options: [
3259
1963
  {
@@ -3268,8 +1972,8 @@ async function main(target, options) {
3268
1972
  }
3269
1973
  ]
3270
1974
  });
3271
- if (p3.isCancel(scope)) {
3272
- p3.cancel("Installation cancelled");
1975
+ if (p2.isCancel(scope)) {
1976
+ p2.cancel("Installation cancelled");
3273
1977
  process.exit(0);
3274
1978
  }
3275
1979
  installLocally = scope;
@@ -3278,7 +1982,7 @@ async function main(target, options) {
3278
1982
  agentRouting.set(agent, installLocally ? "local" : "global");
3279
1983
  }
3280
1984
  } else {
3281
- p3.log.info("Selected agents only support global installation");
1985
+ p2.log.info("Selected agents only support global installation");
3282
1986
  }
3283
1987
  }
3284
1988
  const summaryLines = [];
@@ -3310,13 +2014,13 @@ async function main(target, options) {
3310
2014
  );
3311
2015
  }
3312
2016
  console.log();
3313
- p3.note(summaryLines.join("\n"), "Installation Summary");
2017
+ p2.note(summaryLines.join("\n"), "Installation Summary");
3314
2018
  if (!options.yes) {
3315
- const confirmed = await p3.confirm({
2019
+ const confirmed = await p2.confirm({
3316
2020
  message: "Proceed with installation?"
3317
2021
  });
3318
- if (p3.isCancel(confirmed) || !confirmed) {
3319
- p3.cancel("Installation cancelled");
2022
+ if (p2.isCancel(confirmed) || !confirmed) {
2023
+ p2.cancel("Installation cancelled");
3320
2024
  process.exit(0);
3321
2025
  }
3322
2026
  }
@@ -3332,12 +2036,12 @@ async function main(target, options) {
3332
2036
  const resultLines = [];
3333
2037
  for (const [agentType, result] of successful) {
3334
2038
  const agent = agents[agentType];
3335
- const shortPath = shortenPath2(result.path);
2039
+ const shortPath = shortenPath(result.path);
3336
2040
  resultLines.push(
3337
2041
  `${chalk.green("\u2713")} ${agent.displayName}: ${chalk.dim(shortPath)}`
3338
2042
  );
3339
2043
  }
3340
- p3.note(
2044
+ p2.note(
3341
2045
  resultLines.join("\n"),
3342
2046
  chalk.green(
3343
2047
  `Installed to ${successful.length} agent${successful.length !== 1 ? "s" : ""}`
@@ -3346,33 +2050,33 @@ async function main(target, options) {
3346
2050
  }
3347
2051
  if (failed.length > 0) {
3348
2052
  console.log();
3349
- p3.log.error(
2053
+ p2.log.error(
3350
2054
  chalk.red(
3351
2055
  `Failed to install to ${failed.length} agent${failed.length !== 1 ? "s" : ""}`
3352
2056
  )
3353
2057
  );
3354
2058
  for (const [agentType, result] of failed) {
3355
2059
  const agent = agents[agentType];
3356
- p3.log.message(
2060
+ p2.log.message(
3357
2061
  ` ${chalk.red("\u2717")} ${agent.displayName}: ${chalk.dim(result.error)}`
3358
2062
  );
3359
2063
  }
3360
2064
  }
3361
2065
  if (options.gitignore && options.global) {
3362
- p3.log.warn(
2066
+ p2.log.warn(
3363
2067
  "--gitignore is only supported for project-scoped installations; ignoring."
3364
2068
  );
3365
2069
  } else if (options.gitignore) {
3366
2070
  const successfulPaths = successful.map(([_, result]) => result.path);
3367
2071
  const gitignoreUpdate = updateGitignoreWithPaths(successfulPaths);
3368
2072
  if (gitignoreUpdate.added.length > 0) {
3369
- p3.log.info(
2073
+ p2.log.info(
3370
2074
  `Added ${gitignoreUpdate.added.length} entr${gitignoreUpdate.added.length === 1 ? "y" : "ies"} to .gitignore`
3371
2075
  );
3372
2076
  } else {
3373
- p3.log.info("No new local config paths to add to .gitignore");
2077
+ p2.log.info("No new local config paths to add to .gitignore");
3374
2078
  }
3375
2079
  }
3376
2080
  console.log();
3377
- p3.outro(chalk.green("Done!"));
2081
+ p2.outro(chalk.green("Done!"));
3378
2082
  }