@agentteams/cli 0.1.76 → 0.1.78

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.
Files changed (101) hide show
  1. package/.eslintcache +1 -1
  2. package/dist/api/convention.d.ts +11 -0
  3. package/dist/api/convention.d.ts.map +1 -0
  4. package/dist/api/convention.js +26 -0
  5. package/dist/api/convention.js.map +1 -0
  6. package/dist/api/document.d.ts +1 -1
  7. package/dist/api/document.d.ts.map +1 -1
  8. package/dist/api/document.js.map +1 -1
  9. package/dist/commands/agentConfig.d.ts.map +1 -1
  10. package/dist/commands/agentConfig.js +2 -1
  11. package/dist/commands/agentConfig.js.map +1 -1
  12. package/dist/commands/convention.d.ts.map +1 -1
  13. package/dist/commands/convention.js +9 -10
  14. package/dist/commands/convention.js.map +1 -1
  15. package/dist/commands/dependency.d.ts.map +1 -1
  16. package/dist/commands/dependency.js +2 -1
  17. package/dist/commands/dependency.js.map +1 -1
  18. package/dist/commands/index.d.ts.map +1 -1
  19. package/dist/commands/index.js +1 -19
  20. package/dist/commands/index.js.map +1 -1
  21. package/dist/commands/init.d.ts.map +1 -1
  22. package/dist/commands/init.js +2 -1
  23. package/dist/commands/init.js.map +1 -1
  24. package/dist/commands/mcp.d.ts +13 -0
  25. package/dist/commands/mcp.d.ts.map +1 -0
  26. package/dist/commands/mcp.js +13 -0
  27. package/dist/commands/mcp.js.map +1 -0
  28. package/dist/commands/search.d.ts.map +1 -1
  29. package/dist/commands/search.js +8 -35
  30. package/dist/commands/search.js.map +1 -1
  31. package/dist/index.js +71 -0
  32. package/dist/index.js.map +1 -1
  33. package/dist/mcp/context.d.ts +15 -0
  34. package/dist/mcp/context.d.ts.map +1 -0
  35. package/dist/mcp/context.js +47 -0
  36. package/dist/mcp/context.js.map +1 -0
  37. package/dist/mcp/resources.d.ts +17 -0
  38. package/dist/mcp/resources.d.ts.map +1 -0
  39. package/dist/mcp/resources.js +50 -0
  40. package/dist/mcp/resources.js.map +1 -0
  41. package/dist/mcp/server.d.ts +20 -0
  42. package/dist/mcp/server.d.ts.map +1 -0
  43. package/dist/mcp/server.js +107 -0
  44. package/dist/mcp/server.js.map +1 -0
  45. package/dist/mcp/tools.d.ts +12 -0
  46. package/dist/mcp/tools.d.ts.map +1 -0
  47. package/dist/mcp/tools.js +54 -0
  48. package/dist/mcp/tools.js.map +1 -0
  49. package/dist/mcp-registration/atomicWrite.d.ts +26 -0
  50. package/dist/mcp-registration/atomicWrite.d.ts.map +1 -0
  51. package/dist/mcp-registration/atomicWrite.js +58 -0
  52. package/dist/mcp-registration/atomicWrite.js.map +1 -0
  53. package/dist/mcp-registration/clients.d.ts +5 -0
  54. package/dist/mcp-registration/clients.d.ts.map +1 -0
  55. package/dist/mcp-registration/clients.js +300 -0
  56. package/dist/mcp-registration/clients.js.map +1 -0
  57. package/dist/mcp-registration/detect.d.ts +23 -0
  58. package/dist/mcp-registration/detect.d.ts.map +1 -0
  59. package/dist/mcp-registration/detect.js +48 -0
  60. package/dist/mcp-registration/detect.js.map +1 -0
  61. package/dist/mcp-registration/index.d.ts +50 -0
  62. package/dist/mcp-registration/index.d.ts.map +1 -0
  63. package/dist/mcp-registration/index.js +205 -0
  64. package/dist/mcp-registration/index.js.map +1 -0
  65. package/dist/mcp-registration/install.d.ts +66 -0
  66. package/dist/mcp-registration/install.d.ts.map +1 -0
  67. package/dist/mcp-registration/install.js +244 -0
  68. package/dist/mcp-registration/install.js.map +1 -0
  69. package/dist/mcp-registration/jsonc.d.ts +44 -0
  70. package/dist/mcp-registration/jsonc.d.ts.map +1 -0
  71. package/dist/mcp-registration/jsonc.js +266 -0
  72. package/dist/mcp-registration/jsonc.js.map +1 -0
  73. package/dist/mcp-registration/render.d.ts +18 -0
  74. package/dist/mcp-registration/render.d.ts.map +1 -0
  75. package/dist/mcp-registration/render.js +91 -0
  76. package/dist/mcp-registration/render.js.map +1 -0
  77. package/dist/mcp-registration/serverSpec.d.ts +31 -0
  78. package/dist/mcp-registration/serverSpec.d.ts.map +1 -0
  79. package/dist/mcp-registration/serverSpec.js +29 -0
  80. package/dist/mcp-registration/serverSpec.js.map +1 -0
  81. package/dist/mcp-registration/types.d.ts +98 -0
  82. package/dist/mcp-registration/types.d.ts.map +1 -0
  83. package/dist/mcp-registration/types.js +12 -0
  84. package/dist/mcp-registration/types.js.map +1 -0
  85. package/dist/mcp-registration/vendorCommand.d.ts +18 -0
  86. package/dist/mcp-registration/vendorCommand.d.ts.map +1 -0
  87. package/dist/mcp-registration/vendorCommand.js +27 -0
  88. package/dist/mcp-registration/vendorCommand.js.map +1 -0
  89. package/dist/utils/apiContext.d.ts +22 -0
  90. package/dist/utils/apiContext.d.ts.map +1 -0
  91. package/dist/utils/apiContext.js +39 -0
  92. package/dist/utils/apiContext.js.map +1 -0
  93. package/dist/utils/entityId.d.ts +12 -0
  94. package/dist/utils/entityId.d.ts.map +1 -1
  95. package/dist/utils/entityId.js +2 -4
  96. package/dist/utils/entityId.js.map +1 -1
  97. package/dist/utils/searchParams.d.ts +22 -0
  98. package/dist/utils/searchParams.d.ts.map +1 -0
  99. package/dist/utils/searchParams.js +32 -0
  100. package/dist/utils/searchParams.js.map +1 -0
  101. package/package.json +9 -3
@@ -0,0 +1,48 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { delimiter, join } from 'node:path';
3
+ import { MCP_CLIENTS } from './clients.js';
4
+ function defaultSuffixes(platform) {
5
+ return platform === 'win32' ? ['', '.cmd', '.exe', '.bat', '.ps1'] : [''];
6
+ }
7
+ function resolveExecutable(client, dependencies) {
8
+ const { context, fileExists } = dependencies;
9
+ const suffixes = dependencies.executableSuffixes ?? defaultSuffixes(process.platform);
10
+ const pathDirs = (context.env.PATH ?? '').split(delimiter).filter((entry) => entry.length > 0);
11
+ const extraDirs = client.extraBinDirs ? client.extraBinDirs(context) : [];
12
+ for (const directory of [...pathDirs, ...extraDirs]) {
13
+ for (const executable of client.executables) {
14
+ for (const suffix of suffixes) {
15
+ const candidate = join(directory, `${executable}${suffix}`);
16
+ if (fileExists(candidate))
17
+ return candidate;
18
+ }
19
+ }
20
+ }
21
+ return null;
22
+ }
23
+ /**
24
+ * Config traces and an executable are independent signals: a client counts as a
25
+ * candidate when either one is present. Reporting *which* signal fired is what
26
+ * lets a user tell "installed but never configured" apart from "config left
27
+ * behind by an uninstall".
28
+ */
29
+ export function detectClients(dependencies) {
30
+ const fileExists = dependencies.fileExists ?? existsSync;
31
+ const resolved = { ...dependencies, fileExists };
32
+ return MCP_CLIENTS.map((client) => {
33
+ const configPaths = client.configSignals(dependencies.context).filter((path) => fileExists(path));
34
+ const executablePath = resolveExecutable(client, resolved);
35
+ const hasConfig = configPaths.length > 0;
36
+ const hasExecutable = executablePath !== null;
37
+ const evidence = hasConfig && hasExecutable ? 'both' : hasConfig ? 'configured' : hasExecutable ? 'executable' : 'none';
38
+ return {
39
+ clientId: client.id,
40
+ label: client.label,
41
+ evidence,
42
+ executablePath,
43
+ configPaths,
44
+ detected: hasConfig || hasExecutable,
45
+ };
46
+ });
47
+ }
48
+ //# sourceMappingURL=detect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect.js","sourceRoot":"","sources":["../../src/mcp-registration/detect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAmB3C,SAAS,eAAe,CAAC,QAAgB;IACvC,OAAO,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAC5E,CAAC;AAED,SAAS,iBAAiB,CACxB,MAA2B,EAC3B,YAAyF;IAEzF,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,YAAY,CAAC;IAC7C,MAAM,QAAQ,GAAG,YAAY,CAAC,kBAAkB,IAAI,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACtF,MAAM,QAAQ,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC/F,MAAM,SAAS,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAE1E,KAAK,MAAM,SAAS,IAAI,CAAC,GAAG,QAAQ,EAAE,GAAG,SAAS,CAAC,EAAE,CAAC;QACpD,KAAK,MAAM,UAAU,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;YAC5C,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;gBAC9B,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,EAAE,GAAG,UAAU,GAAG,MAAM,EAAE,CAAC,CAAC;gBAC5D,IAAI,UAAU,CAAC,SAAS,CAAC;oBAAE,OAAO,SAAS,CAAC;YAC9C,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,YAAmC;IAC/D,MAAM,UAAU,GAAG,YAAY,CAAC,UAAU,IAAI,UAAU,CAAC;IACzD,MAAM,QAAQ,GAAG,EAAE,GAAG,YAAY,EAAE,UAAU,EAAE,CAAC;IAEjD,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;QAChC,MAAM,WAAW,GAAG,MAAM,CAAC,aAAa,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;QAClG,MAAM,cAAc,GAAG,iBAAiB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAE3D,MAAM,SAAS,GAAG,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC;QACzC,MAAM,aAAa,GAAG,cAAc,KAAK,IAAI,CAAC;QAC9C,MAAM,QAAQ,GACZ,SAAS,IAAI,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC;QAEzG,OAAO;YACL,QAAQ,EAAE,MAAM,CAAC,EAAE;YACnB,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,QAAQ;YACR,cAAc;YACd,WAAW;YACX,QAAQ,EAAE,SAAS,IAAI,aAAa;SACrC,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,50 @@
1
+ import type { DetectionDependencies } from './detect.js';
2
+ import { type McpCredentials } from './serverSpec.js';
3
+ import type { McpPathContext } from './types.js';
4
+ import type { VendorRunner } from './vendorCommand.js';
5
+ export { MCP_CLIENTS, findClient, listClientIds } from './clients.js';
6
+ export { detectClients } from './detect.js';
7
+ export { buildBatchPlan, installClient, resolveInstallExitCode, runBatchInstall } from './install.js';
8
+ export { renderConfigSnippet, renderVendorCommandLine, redactSecrets } from './render.js';
9
+ export { buildServerSpec, MCP_SERVER_NAME, CREDENTIAL_ENV_KEYS } from './serverSpec.js';
10
+ export type { McpCredentials } from './serverSpec.js';
11
+ export * from './types.js';
12
+ declare const MCP_CLIENT_ID_LIST: ("claude-code" | "codex" | "copilot-cli" | "opencode" | "amp" | "cursor-cli" | "kimi-cli" | "antigravity")[];
13
+ export { MCP_CLIENT_ID_LIST };
14
+ export interface McpRegistrationCommandOptions {
15
+ client?: string;
16
+ scope?: string;
17
+ serverEntry?: string;
18
+ yes?: boolean;
19
+ apiKey?: string;
20
+ apiUrl?: string;
21
+ projectId?: string;
22
+ teamId?: string;
23
+ }
24
+ /** Injection seams so tests drive a temporary HOME/cwd and a fake vendor CLI. */
25
+ export interface McpRegistrationDependencies {
26
+ context?: Partial<McpPathContext>;
27
+ credentials?: McpCredentials;
28
+ vendorRunner?: VendorRunner;
29
+ detectionDependencies?: Omit<DetectionDependencies, 'context'>;
30
+ }
31
+ export interface CommandOutput {
32
+ text: string;
33
+ json: unknown;
34
+ exitCode: number;
35
+ }
36
+ /**
37
+ * `config` is the escape hatch: it renders the exact fragment each client
38
+ * expects and never touches a file, a vendor CLI or the network. The API key is
39
+ * always emitted with the target client's environment-reference contract so
40
+ * the output stays safe to paste into a terminal, an issue or a code review.
41
+ */
42
+ export declare function runMcpConfigCommand(options: McpRegistrationCommandOptions, dependencies?: McpRegistrationDependencies): CommandOutput;
43
+ /**
44
+ * `install` has two modes:
45
+ * - `--client <id>`: apply a single client/scope (project scope allowed here).
46
+ * - no `--client`: detect local clients and print the plan. Only `--yes` turns
47
+ * that plan into writes, and only at user scope.
48
+ */
49
+ export declare function runMcpInstallCommand(options: McpRegistrationCommandOptions, dependencies?: McpRegistrationDependencies): CommandOutput;
50
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp-registration/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAGzD,OAAO,EAAoC,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACxF,OAAO,KAAK,EAA8B,cAAc,EAAY,MAAM,YAAY,CAAC;AACvF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACtE,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,sBAAsB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACtG,OAAO,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC1F,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACxF,YAAY,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,cAAc,YAAY,CAAC;AAE3B,QAAA,MAAM,kBAAkB,8GAAkB,CAAC;AAE3C,OAAO,EAAE,kBAAkB,EAAE,CAAC;AAE9B,MAAM,WAAW,6BAA6B;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,iFAAiF;AACjF,MAAM,WAAW,2BAA2B;IAC1C,OAAO,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;IAClC,WAAW,CAAC,EAAE,cAAc,CAAC;IAC7B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,qBAAqB,CAAC,EAAE,IAAI,CAAC,qBAAqB,EAAE,SAAS,CAAC,CAAC;CAChE;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAwCD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,6BAA6B,EACtC,YAAY,CAAC,EAAE,2BAA2B,GACzC,aAAa,CA2Cf;AAyBD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,6BAA6B,EACtC,YAAY,CAAC,EAAE,2BAA2B,GACzC,aAAa,CA0Ff"}
@@ -0,0 +1,205 @@
1
+ import { homedir } from 'node:os';
2
+ import { getConfigurationNotFoundMessage, loadConfig } from '../utils/config.js';
3
+ import { buildConfigOverrides } from '../utils/apiContext.js';
4
+ import { findClient, listClientIds } from './clients.js';
5
+ import { buildBatchPlan, installClient, resolveInstallExitCode, runBatchInstall } from './install.js';
6
+ import { renderConfigSnippet, renderVendorCommandLine } from './render.js';
7
+ import { buildServerSpec, MCP_SERVER_NAME } from './serverSpec.js';
8
+ export { MCP_CLIENTS, findClient, listClientIds } from './clients.js';
9
+ export { detectClients } from './detect.js';
10
+ export { buildBatchPlan, installClient, resolveInstallExitCode, runBatchInstall } from './install.js';
11
+ export { renderConfigSnippet, renderVendorCommandLine, redactSecrets } from './render.js';
12
+ export { buildServerSpec, MCP_SERVER_NAME, CREDENTIAL_ENV_KEYS } from './serverSpec.js';
13
+ export * from './types.js';
14
+ const MCP_CLIENT_ID_LIST = listClientIds();
15
+ export { MCP_CLIENT_ID_LIST };
16
+ function resolveCredentials(options, dependencies) {
17
+ if (dependencies?.credentials)
18
+ return dependencies.credentials;
19
+ const config = loadConfig(buildConfigOverrides(options));
20
+ if (!config)
21
+ throw new Error(getConfigurationNotFoundMessage());
22
+ return {
23
+ apiKey: config.apiKey,
24
+ projectId: config.projectId,
25
+ teamId: config.teamId,
26
+ apiUrl: config.apiUrl,
27
+ };
28
+ }
29
+ function resolvePathContext(overrides) {
30
+ return {
31
+ homeDir: overrides?.homeDir ?? homedir(),
32
+ cwd: overrides?.cwd ?? process.cwd(),
33
+ env: overrides?.env ?? process.env,
34
+ };
35
+ }
36
+ function parseScope(value) {
37
+ if (value === undefined || value === null || value === '')
38
+ return 'user';
39
+ if (value === 'user' || value === 'project')
40
+ return value;
41
+ throw new Error(`Unsupported scope: ${String(value)}. Use "user" or "project".`);
42
+ }
43
+ function parseClientId(value) {
44
+ const client = findClient(value);
45
+ if (!client) {
46
+ throw new Error(`Unknown client: ${value}. Supported clients: ${MCP_CLIENT_ID_LIST.join(', ')}.`);
47
+ }
48
+ return client.id;
49
+ }
50
+ /**
51
+ * `config` is the escape hatch: it renders the exact fragment each client
52
+ * expects and never touches a file, a vendor CLI or the network. The API key is
53
+ * always emitted with the target client's environment-reference contract so
54
+ * the output stays safe to paste into a terminal, an issue or a code review.
55
+ */
56
+ export function runMcpConfigCommand(options, dependencies) {
57
+ const credentials = resolveCredentials(options, dependencies);
58
+ const context = resolvePathContext(dependencies?.context);
59
+ const scope = parseScope(options.scope);
60
+ const clientIds = options.client ? [parseClientId(options.client)] : MCP_CLIENT_ID_LIST;
61
+ const spec = buildServerSpec({ credentials, secretMode: 'reference', serverEntry: options.serverEntry });
62
+ const sections = clientIds.map((clientId) => {
63
+ const client = findClient(clientId);
64
+ if (!client)
65
+ throw new Error(`Unknown client: ${clientId}`);
66
+ const definition = client.scopes[scope];
67
+ return {
68
+ clientId,
69
+ label: client.label,
70
+ scope,
71
+ configPath: definition.configPath(context),
72
+ format: definition.format,
73
+ strategy: definition.strategy,
74
+ docsUrl: client.docsUrl,
75
+ verifiedAt: client.verifiedAt,
76
+ snippet: renderConfigSnippet(client, scope, spec, MCP_SERVER_NAME),
77
+ vendorCommand: renderVendorCommandLine(client, scope, spec, MCP_SERVER_NAME),
78
+ configOnlyReason: definition.configOnlyReason ?? null,
79
+ };
80
+ });
81
+ const lines = [
82
+ `AgentTeams MCP config (${scope} scope) — project ${credentials.projectId}, team ${credentials.teamId}`,
83
+ 'The API key is rendered with the selected client’s environment-reference syntax. Export AGENTTEAMS_API_KEY before the client starts.',
84
+ ];
85
+ for (const section of sections) {
86
+ lines.push('');
87
+ lines.push(`## ${section.label} (${section.clientId})`);
88
+ lines.push(`File: ${section.configPath}`);
89
+ if (section.configOnlyReason)
90
+ lines.push(`Note: ${section.configOnlyReason}`);
91
+ if (section.vendorCommand)
92
+ lines.push(`Command: ${section.vendorCommand}`);
93
+ lines.push(section.snippet);
94
+ lines.push(`Docs: ${section.docsUrl} (verified ${section.verifiedAt})`);
95
+ }
96
+ return { text: lines.join('\n'), json: { scope, clients: sections }, exitCode: 0 };
97
+ }
98
+ function formatDetectionEvidence(entry) {
99
+ if (entry.evidence === 'none')
100
+ return 'not detected';
101
+ const parts = [];
102
+ if (entry.executablePath)
103
+ parts.push(`executable ${entry.executablePath}`);
104
+ if (entry.configPaths.length > 0)
105
+ parts.push(`config ${entry.configPaths[0]}`);
106
+ return `${entry.evidence} (${parts.join(', ')})`;
107
+ }
108
+ function renderResultLine(result) {
109
+ return `- ${result.clientId} [${result.outcome}] ${result.detail}`;
110
+ }
111
+ function summarize(results) {
112
+ return {
113
+ applied: results.filter((r) => r.outcome === 'INSTALLED' || r.outcome === 'ALREADY_REGISTERED').length,
114
+ skipped: results.filter((r) => r.outcome === 'SKIPPED_CONFIG_ONLY' || r.outcome === 'SKIPPED_NOT_DETECTED').length,
115
+ failed: results.filter((r) => r.outcome === 'FAILED').length,
116
+ };
117
+ }
118
+ const USER_SCOPE_BINDING_WARNING = 'Warning: a user-scope registration is machine-wide. If this client already has an "agentteams" server pointing at a different AgentTeams project, applying this plan re-points it.';
119
+ /**
120
+ * `install` has two modes:
121
+ * - `--client <id>`: apply a single client/scope (project scope allowed here).
122
+ * - no `--client`: detect local clients and print the plan. Only `--yes` turns
123
+ * that plan into writes, and only at user scope.
124
+ */
125
+ export function runMcpInstallCommand(options, dependencies) {
126
+ const credentials = resolveCredentials(options, dependencies);
127
+ const context = resolvePathContext(dependencies?.context);
128
+ const scope = parseScope(options.scope);
129
+ if (options.client) {
130
+ const client = findClient(parseClientId(options.client));
131
+ if (!client)
132
+ throw new Error(`Unknown client: ${options.client}`);
133
+ const result = installClient({
134
+ client,
135
+ scope,
136
+ credentials,
137
+ context,
138
+ serverEntry: options.serverEntry,
139
+ vendorRunner: dependencies?.vendorRunner,
140
+ });
141
+ const lines = [
142
+ `AgentTeams MCP install — ${client.label} (${scope} scope)`,
143
+ `Project ${credentials.projectId}, team ${credentials.teamId}`,
144
+ ];
145
+ if (scope === 'user')
146
+ lines.push(USER_SCOPE_BINDING_WARNING);
147
+ lines.push(renderResultLine(result));
148
+ if (result.backupPath)
149
+ lines.push(`Backup: ${result.backupPath}`);
150
+ if (result.manualSnippet) {
151
+ lines.push('Manual fallback:');
152
+ lines.push(result.manualSnippet);
153
+ }
154
+ return {
155
+ text: lines.join('\n'),
156
+ json: { scope, results: [result], summary: summarize([result]) },
157
+ exitCode: resolveInstallExitCode([result]),
158
+ };
159
+ }
160
+ if (scope === 'project') {
161
+ throw new Error('Batch install does not support --scope project: project files are repository state and must be chosen per client. Re-run with --client <id> --scope project.');
162
+ }
163
+ if (!options.yes) {
164
+ const plan = buildBatchPlan({
165
+ context,
166
+ credentials,
167
+ detectionDependencies: dependencies?.detectionDependencies,
168
+ });
169
+ const lines = [
170
+ 'AgentTeams MCP install — dry run (no files were changed)',
171
+ `Plan: register "${MCP_SERVER_NAME}" at user scope for project ${plan.binding.projectId}, team ${plan.binding.teamId}`,
172
+ USER_SCOPE_BINDING_WARNING,
173
+ '',
174
+ ];
175
+ for (const entry of plan.entries) {
176
+ lines.push(`- ${entry.clientId} [${entry.applicable ? 'will apply' : 'skip'}] ${formatDetectionEvidence(entry)}`);
177
+ lines.push(` target: ${entry.targetPath} via ${entry.strategy}`);
178
+ if (entry.reason)
179
+ lines.push(` reason: ${entry.reason}`);
180
+ }
181
+ lines.push('');
182
+ lines.push('Re-run with --yes to apply, or use `agentteams mcp config --client <id>` for a manual snippet.');
183
+ return { text: lines.join('\n'), json: { scope: 'user', dryRun: true, plan }, exitCode: 0 };
184
+ }
185
+ const { plan, results } = runBatchInstall({
186
+ context,
187
+ credentials,
188
+ serverEntry: options.serverEntry,
189
+ vendorRunner: dependencies?.vendorRunner,
190
+ detectionDependencies: dependencies?.detectionDependencies,
191
+ });
192
+ const summary = summarize(results);
193
+ const lines = [
194
+ `AgentTeams MCP install — applied at user scope for project ${plan.binding.projectId}, team ${plan.binding.teamId}`,
195
+ ...results.map(renderResultLine),
196
+ '',
197
+ `Summary: ${summary.applied} registered, ${summary.skipped} skipped, ${summary.failed} failed.`,
198
+ ];
199
+ return {
200
+ text: lines.join('\n'),
201
+ json: { scope: 'user', dryRun: false, plan, results, summary },
202
+ exitCode: resolveInstallExitCode(results),
203
+ };
204
+ }
205
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mcp-registration/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ import { type DetectionDependencies } from './detect.js';
2
+ import { renderConfigSnippet, renderVendorCommandLine } from './render.js';
3
+ import { type McpCredentials } from './serverSpec.js';
4
+ import type { DetectionSignal, InstallResult, McpClientDefinition, McpPathContext, McpScope } from './types.js';
5
+ import { type VendorRunner } from './vendorCommand.js';
6
+ export interface InstallClientOptions {
7
+ client: McpClientDefinition;
8
+ scope: McpScope;
9
+ credentials: McpCredentials;
10
+ context: McpPathContext;
11
+ serverEntry?: string;
12
+ serverName?: string;
13
+ vendorRunner?: VendorRunner;
14
+ }
15
+ /** Apply (or explicitly decline to apply) the AgentTeams entry for one client/scope. */
16
+ export declare function installClient(options: InstallClientOptions): InstallResult;
17
+ export interface BatchPlanEntry {
18
+ clientId: McpClientDefinition['id'];
19
+ label: string;
20
+ evidence: DetectionSignal['evidence'];
21
+ executablePath: string | null;
22
+ configPaths: string[];
23
+ scope: McpScope;
24
+ strategy: McpClientDefinition['scopes'][McpScope]['strategy'];
25
+ targetPath: string;
26
+ applicable: boolean;
27
+ reason?: string;
28
+ }
29
+ export interface BatchPlan {
30
+ scope: McpScope;
31
+ entries: BatchPlanEntry[];
32
+ /** A single user-scope registration binds the client to one AgentTeams project. */
33
+ binding: {
34
+ projectId: string;
35
+ teamId: string;
36
+ };
37
+ }
38
+ export interface BuildBatchPlanOptions {
39
+ context: McpPathContext;
40
+ credentials: McpCredentials;
41
+ detection?: DetectionSignal[];
42
+ detectionDependencies?: Omit<DetectionDependencies, 'context'>;
43
+ }
44
+ /**
45
+ * Detection plan for the no-argument `install`. Nothing here touches the
46
+ * filesystem — the caller prints it and stops unless `--yes` was passed.
47
+ */
48
+ export declare function buildBatchPlan(options: BuildBatchPlanOptions): BatchPlan;
49
+ export interface RunBatchInstallOptions extends BuildBatchPlanOptions {
50
+ serverEntry?: string;
51
+ serverName?: string;
52
+ vendorRunner?: VendorRunner;
53
+ }
54
+ /**
55
+ * Apply the plan client by client. One client's failure must not strand the
56
+ * rest, so every entry is attempted and the caller derives the exit code from
57
+ * the collected outcomes.
58
+ */
59
+ export declare function runBatchInstall(options: RunBatchInstallOptions): {
60
+ plan: BatchPlan;
61
+ results: InstallResult[];
62
+ };
63
+ /** Non-zero exit only for real failures; "config only" and "not detected" are expected states. */
64
+ export declare function resolveInstallExitCode(results: InstallResult[]): number;
65
+ export { renderConfigSnippet, renderVendorCommandLine };
66
+ //# sourceMappingURL=install.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../src/mcp-registration/install.ts"],"names":[],"mappings":"AAGA,OAAO,EAAiB,KAAK,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAExE,OAAO,EAAkC,mBAAmB,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAC3G,OAAO,EAAoC,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACxF,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,mBAAmB,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAChH,OAAO,EAAoB,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEzE,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,mBAAmB,CAAC;IAC5B,KAAK,EAAE,QAAQ,CAAC;IAChB,WAAW,EAAE,cAAc,CAAC;IAC5B,OAAO,EAAE,cAAc,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B;AA4JD,wFAAwF;AACxF,wBAAgB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,aAAa,CA8B1E;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,mBAAmB,CAAC,IAAI,CAAC,CAAC;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,eAAe,CAAC,UAAU,CAAC,CAAC;IACtC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,KAAK,EAAE,QAAQ,CAAC;IAChB,QAAQ,EAAE,mBAAmB,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC,CAAC;IAC9D,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,QAAQ,CAAC;IAChB,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,mFAAmF;IACnF,OAAO,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAChD;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,cAAc,CAAC;IACxB,WAAW,EAAE,cAAc,CAAC;IAC5B,SAAS,CAAC,EAAE,eAAe,EAAE,CAAC;IAC9B,qBAAqB,CAAC,EAAE,IAAI,CAAC,qBAAqB,EAAE,SAAS,CAAC,CAAC;CAChE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,SAAS,CAiCxE;AAED,MAAM,WAAW,sBAAuB,SAAQ,qBAAqB;IACnE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,aAAa,EAAE,CAAA;CAAE,CAkC9G;AAED,kGAAkG;AAClG,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,aAAa,EAAE,GAAG,MAAM,CAEvE;AAED,OAAO,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,CAAC"}
@@ -0,0 +1,244 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { PROJECT_SCOPE_FILE_MODE, USER_SCOPE_FILE_MODE, writeConfigFileAtomically } from './atomicWrite.js';
3
+ import { findClient, MCP_CLIENTS } from './clients.js';
4
+ import { detectClients } from './detect.js';
5
+ import { McpConfigParseError, upsertContainerEntry } from './jsonc.js';
6
+ import { buildEntryValue, redactSecrets, renderConfigSnippet, renderVendorCommandLine } from './render.js';
7
+ import { buildServerSpec, MCP_SERVER_NAME } from './serverSpec.js';
8
+ import { runVendorCommand } from './vendorCommand.js';
9
+ function firstLines(text, limit = 4) {
10
+ return text
11
+ .split('\n')
12
+ .map((line) => line.trim())
13
+ .filter((line) => line.length > 0)
14
+ .slice(0, limit)
15
+ .join(' / ');
16
+ }
17
+ function installViaVendorCommand(options, configPath, manualSnippet) {
18
+ const { client, scope, context } = options;
19
+ const serverName = options.serverName ?? MCP_SERVER_NAME;
20
+ const definition = client.scopes[scope];
21
+ const vendor = definition.vendor;
22
+ if (!vendor)
23
+ throw new Error(`No vendor command configured for ${client.id}/${scope}`);
24
+ const spec = buildServerSpec({
25
+ credentials: options.credentials,
26
+ secretMode: scope === 'user' ? 'literal' : 'reference',
27
+ serverEntry: options.serverEntry,
28
+ });
29
+ const executable = client.executables[0];
30
+ const runner = options.vendorRunner ?? runVendorCommand;
31
+ const outcome = runner(executable, vendor.buildArgs(spec, serverName), { cwd: context.cwd, env: context.env });
32
+ const base = { clientId: client.id, scope, strategy: definition.strategy, configPath };
33
+ if (outcome.spawnError) {
34
+ return {
35
+ ...base,
36
+ outcome: 'FAILED',
37
+ detail: `Could not run \`${executable}\`: ${outcome.spawnError}`,
38
+ manualSnippet,
39
+ };
40
+ }
41
+ // Vendor CLIs echo their own argv on failure, and user-scope argv carries the
42
+ // API key, so nothing reaches the caller before passing through redaction.
43
+ const combined = redactSecrets(`${outcome.stdout}\n${outcome.stderr}`, [options.credentials.apiKey]);
44
+ const alreadyRegistered = (vendor.alreadyRegisteredPatterns ?? []).some((pattern) => pattern.test(combined));
45
+ if (alreadyRegistered) {
46
+ return {
47
+ ...base,
48
+ outcome: 'ALREADY_REGISTERED',
49
+ detail: `\`${executable}\` reports "${serverName}" is already registered and refuses to overwrite it. Remove it with the client's own \`mcp remove\` command and re-run, or apply the snippet manually.`,
50
+ manualSnippet,
51
+ };
52
+ }
53
+ if (outcome.status === 0) {
54
+ return {
55
+ ...base,
56
+ outcome: 'INSTALLED',
57
+ detail: vendor.rerunBehavior === 'update'
58
+ ? `Registered "${serverName}" via \`${executable} mcp add\` (re-running updates the entry in place).`
59
+ : `Registered "${serverName}" via \`${executable} mcp add\`.`,
60
+ };
61
+ }
62
+ return {
63
+ ...base,
64
+ outcome: 'FAILED',
65
+ detail: `\`${executable} mcp add\` exited with code ${String(outcome.status)}: ${firstLines(combined) || 'no output'}`,
66
+ manualSnippet,
67
+ };
68
+ }
69
+ function installViaJsonMerge(options, configPath, manualSnippet) {
70
+ const { client, scope } = options;
71
+ const serverName = options.serverName ?? MCP_SERVER_NAME;
72
+ const definition = client.scopes[scope];
73
+ const containerKey = definition.containerKey;
74
+ if (!containerKey)
75
+ throw new Error(`No container key configured for ${client.id}/${scope}`);
76
+ const base = { clientId: client.id, scope, strategy: definition.strategy, configPath };
77
+ const spec = buildServerSpec({
78
+ credentials: options.credentials,
79
+ // Project files are committable, so they never receive a literal key.
80
+ secretMode: scope === 'user' ? 'literal' : 'reference',
81
+ serverEntry: options.serverEntry,
82
+ });
83
+ let source = '';
84
+ if (existsSync(configPath)) {
85
+ try {
86
+ source = readFileSync(configPath, 'utf-8');
87
+ }
88
+ catch (error) {
89
+ return {
90
+ ...base,
91
+ outcome: 'FAILED',
92
+ detail: `Could not read ${configPath}: ${error instanceof Error ? error.message : String(error)}`,
93
+ manualSnippet,
94
+ };
95
+ }
96
+ }
97
+ let edited;
98
+ try {
99
+ edited = upsertContainerEntry(source, {
100
+ containerKey,
101
+ entryKey: serverName,
102
+ entryValue: buildEntryValue(definition.entryShape ?? 'plain', spec, client.secretReference),
103
+ });
104
+ }
105
+ catch (error) {
106
+ const reason = error instanceof McpConfigParseError ? error.message : String(error);
107
+ return {
108
+ ...base,
109
+ outcome: 'FAILED',
110
+ detail: `${configPath} could not be parsed (${reason}). The file was left unchanged — fix it or apply the snippet manually.`,
111
+ manualSnippet,
112
+ };
113
+ }
114
+ if (edited.unchanged) {
115
+ return {
116
+ ...base,
117
+ outcome: 'ALREADY_REGISTERED',
118
+ detail: `"${serverName}" is already present in ${configPath} with identical settings; nothing was written.`,
119
+ };
120
+ }
121
+ try {
122
+ const written = writeConfigFileAtomically(configPath, edited.text, scope === 'user' ? USER_SCOPE_FILE_MODE : PROJECT_SCOPE_FILE_MODE, scope === 'user' ? USER_SCOPE_FILE_MODE : undefined);
123
+ return {
124
+ ...base,
125
+ outcome: 'INSTALLED',
126
+ detail: edited.existed
127
+ ? `Updated the "${serverName}" entry in ${configPath}.`
128
+ : `Added "${serverName}" to ${configPath}.`,
129
+ backupPath: written.backupPath ?? undefined,
130
+ };
131
+ }
132
+ catch (error) {
133
+ return {
134
+ ...base,
135
+ outcome: 'FAILED',
136
+ detail: `Could not write ${configPath}: ${error instanceof Error ? error.message : String(error)}. The original file was left unchanged.`,
137
+ manualSnippet,
138
+ };
139
+ }
140
+ }
141
+ /** Apply (or explicitly decline to apply) the AgentTeams entry for one client/scope. */
142
+ export function installClient(options) {
143
+ const { client, scope } = options;
144
+ const serverName = options.serverName ?? MCP_SERVER_NAME;
145
+ const definition = client.scopes[scope];
146
+ const configPath = definition.configPath(options.context);
147
+ const displaySpec = buildServerSpec({
148
+ credentials: options.credentials,
149
+ secretMode: 'reference',
150
+ serverEntry: options.serverEntry,
151
+ });
152
+ const manualSnippet = renderConfigSnippet(client, scope, displaySpec, serverName);
153
+ if (definition.strategy === 'configOnly') {
154
+ return {
155
+ clientId: client.id,
156
+ scope,
157
+ strategy: 'configOnly',
158
+ configPath,
159
+ outcome: 'SKIPPED_CONFIG_ONLY',
160
+ detail: definition.configOnlyReason ?? 'No safe automated write path for this client/scope.',
161
+ manualSnippet,
162
+ };
163
+ }
164
+ if (definition.strategy === 'vendorCommand') {
165
+ return installViaVendorCommand(options, configPath, manualSnippet);
166
+ }
167
+ return installViaJsonMerge(options, configPath, manualSnippet);
168
+ }
169
+ /**
170
+ * Detection plan for the no-argument `install`. Nothing here touches the
171
+ * filesystem — the caller prints it and stops unless `--yes` was passed.
172
+ */
173
+ export function buildBatchPlan(options) {
174
+ const detection = options.detection ?? detectClients({ context: options.context, ...(options.detectionDependencies ?? {}) });
175
+ const entries = MCP_CLIENTS.map((client) => {
176
+ const signal = detection.find((candidate) => candidate.clientId === client.id);
177
+ const definition = client.scopes.user;
178
+ const detected = signal?.detected ?? false;
179
+ const applicable = detected && definition.strategy !== 'configOnly';
180
+ let reason;
181
+ if (!detected)
182
+ reason = 'Not detected on this machine.';
183
+ else if (definition.strategy === 'configOnly')
184
+ reason = definition.configOnlyReason;
185
+ return {
186
+ clientId: client.id,
187
+ label: client.label,
188
+ evidence: signal?.evidence ?? 'none',
189
+ executablePath: signal?.executablePath ?? null,
190
+ configPaths: signal?.configPaths ?? [],
191
+ scope: 'user',
192
+ strategy: definition.strategy,
193
+ targetPath: definition.configPath(options.context),
194
+ applicable,
195
+ reason,
196
+ };
197
+ });
198
+ return {
199
+ scope: 'user',
200
+ entries,
201
+ binding: { projectId: options.credentials.projectId, teamId: options.credentials.teamId },
202
+ };
203
+ }
204
+ /**
205
+ * Apply the plan client by client. One client's failure must not strand the
206
+ * rest, so every entry is attempted and the caller derives the exit code from
207
+ * the collected outcomes.
208
+ */
209
+ export function runBatchInstall(options) {
210
+ const plan = buildBatchPlan(options);
211
+ const results = [];
212
+ for (const entry of plan.entries) {
213
+ const client = findClient(entry.clientId);
214
+ if (!client)
215
+ continue;
216
+ if (!entry.applicable) {
217
+ results.push({
218
+ clientId: entry.clientId,
219
+ scope: 'user',
220
+ strategy: entry.strategy,
221
+ configPath: entry.targetPath,
222
+ outcome: entry.strategy === 'configOnly' ? 'SKIPPED_CONFIG_ONLY' : 'SKIPPED_NOT_DETECTED',
223
+ detail: entry.reason ?? 'Skipped.',
224
+ });
225
+ continue;
226
+ }
227
+ results.push(installClient({
228
+ client,
229
+ scope: 'user',
230
+ credentials: options.credentials,
231
+ context: options.context,
232
+ serverEntry: options.serverEntry,
233
+ serverName: options.serverName,
234
+ vendorRunner: options.vendorRunner,
235
+ }));
236
+ }
237
+ return { plan, results };
238
+ }
239
+ /** Non-zero exit only for real failures; "config only" and "not detected" are expected states. */
240
+ export function resolveInstallExitCode(results) {
241
+ return results.some((result) => result.outcome === 'FAILED') ? 1 : 0;
242
+ }
243
+ export { renderConfigSnippet, renderVendorCommandLine };
244
+ //# sourceMappingURL=install.js.map