aui-agent-builder 0.3.155 → 0.3.157

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 (48) hide show
  1. package/README.md +1 -2
  2. package/dist/commands/account.d.ts +11 -4
  3. package/dist/commands/account.d.ts.map +1 -1
  4. package/dist/commands/account.js +76 -59
  5. package/dist/commands/account.js.map +1 -1
  6. package/dist/commands/agents.d.ts +0 -1
  7. package/dist/commands/agents.d.ts.map +1 -1
  8. package/dist/commands/agents.js +80 -15
  9. package/dist/commands/agents.js.map +1 -1
  10. package/dist/commands/import-agent.d.ts +7 -0
  11. package/dist/commands/import-agent.d.ts.map +1 -1
  12. package/dist/commands/import-agent.js +27 -14
  13. package/dist/commands/import-agent.js.map +1 -1
  14. package/dist/commands/init.d.ts.map +1 -1
  15. package/dist/commands/init.js +58 -15
  16. package/dist/commands/init.js.map +1 -1
  17. package/dist/commands/integration-mcp-test.d.ts +13 -7
  18. package/dist/commands/integration-mcp-test.d.ts.map +1 -1
  19. package/dist/commands/integration-mcp-test.js +35 -51
  20. package/dist/commands/integration-mcp-test.js.map +1 -1
  21. package/dist/commands/integration-mcp-url.d.ts +40 -0
  22. package/dist/commands/integration-mcp-url.d.ts.map +1 -0
  23. package/dist/commands/integration-mcp-url.js +162 -0
  24. package/dist/commands/integration-mcp-url.js.map +1 -0
  25. package/dist/commands/integration.d.ts +51 -9
  26. package/dist/commands/integration.d.ts.map +1 -1
  27. package/dist/commands/integration.js +231 -66
  28. package/dist/commands/integration.js.map +1 -1
  29. package/dist/commands/version.d.ts.map +1 -1
  30. package/dist/commands/version.js +6 -1
  31. package/dist/commands/version.js.map +1 -1
  32. package/dist/errors/index.d.ts.map +1 -1
  33. package/dist/errors/index.js +10 -3
  34. package/dist/errors/index.js.map +1 -1
  35. package/dist/index.js +125 -33
  36. package/dist/index.js.map +1 -1
  37. package/dist/services/agents.service.d.ts.map +1 -1
  38. package/dist/services/agents.service.js +5 -2
  39. package/dist/services/agents.service.js.map +1 -1
  40. package/dist/services/integration.service.d.ts +282 -7
  41. package/dist/services/integration.service.d.ts.map +1 -1
  42. package/dist/services/integration.service.js +366 -29
  43. package/dist/services/integration.service.js.map +1 -1
  44. package/dist/ui/views/IntegrationView.d.ts +3 -1
  45. package/dist/ui/views/IntegrationView.d.ts.map +1 -1
  46. package/dist/ui/views/IntegrationView.js +2 -2
  47. package/dist/ui/views/IntegrationView.js.map +1 -1
  48. package/package.json +1 -1
@@ -25,21 +25,142 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
25
25
  * `--json` implies non-interactive and emits machine-readable output via
26
26
  * `outputJson` / `outputJsonError`.
27
27
  *
28
- * Composio (native) settings: `settings.user_id` is the agent's `network_id`
29
- * (per MCP_SCHEMA_CHANGES IntegrationComposioMCPSettingsView), so each
30
- * agent owns its own Composio user namespace.
28
+ * Composio (native) settings: `settings.composio.user_id` is the agent's
29
+ * `network_id` (per backend `ComposioIntegrationSchema`
30
+ * `IntegrationMCPSettings`), so each agent owns its own Composio user
31
+ * namespace. The MCP server is provisioned once on create; its caller-
32
+ * stable id is persisted at `settings.composio.server_id` and the
33
+ * provisioned HTTP URL is persisted at `settings.server_url` so the
34
+ * runtime can hit the MCP endpoint without round-tripping Composio.
31
35
  */
32
36
  import { readFileSync } from "fs";
33
37
  import { render, Box, Text } from "ink";
34
38
  import inquirer from "inquirer";
35
39
  import chalk from "chalk";
36
- import { getAuthenticatedSession, discoverMCPTools, discoverComposioTools, saveIntegration as saveIntegrationSvc, resolveScopeIds, resolveNetworkCategoryId, listComposioToolkits, connectComposioToolkit, waitForComposioConnection, resetComposioClient, fetchComposioApiKey, getComposioToolkitAuthInfo, } from "../services/integration.service.js";
40
+ import { getAuthenticatedSession, discoverMCPTools, discoverComposioTools, saveIntegration as saveIntegrationSvc, resolveScopeIds, resolveNetworkCategoryId, listComposioToolkits, connectComposioToolkit, waitForComposioConnection, resetComposioClient, fetchComposioApiKey, getComposioToolkitAuthInfo, getComposioServerUrl, buildAuthFromFlags, parseTransportType, } from "../services/integration.service.js";
37
41
  import { MCPToolList, IntegrationCreatedView, NativeIntegrationCreatedView, } from "../ui/views/IntegrationView.js";
38
42
  import { Header, Spinner, StatusLine, ErrorDisplay, } from "../ui/components/index.js";
39
43
  import { AUIClient } from "../api-client/index.js";
40
44
  import { getConfig, loadProjectConfig, loadSession, saveSession, } from "../config/index.js";
41
45
  import { isJsonMode, outputJson, outputJsonError, stderrLog } from "../utils/json-output.js";
42
46
  import open from "open";
47
+ // NOTE: `buildAuthFromFlags`, `parseTransportType`, and `MCPAuthFlags`
48
+ // live in `../services/integration.service.ts` so all MCP commands
49
+ // (`create`, `discover`, `mcp-test`) share one parser → one canonical
50
+ // `MCPAuthentication` shape. See the JSDoc on `buildAuthFromFlags` for
51
+ // the legacy `token` alias, the `bearer_token` header default, and the
52
+ // `oauth_client_credentials` flag-set.
53
+ // ─── Shared interactive DIRECT MCP auth prompt ───
54
+ /**
55
+ * Inquirer-driven picker for DIRECT MCP authentication. Covers the full
56
+ * canonical `MCPAuthenticationType` surface — `none`, `bearer_token`,
57
+ * `api_key`, `oauth_client_credentials` — and returns the canonical
58
+ * shape so callers can pass it straight to `discoverMCPTools`,
59
+ * `saveIntegration`, or the Apollo MCP-test endpoint without reshaping.
60
+ *
61
+ * Exported so `integration-mcp-test.tsx` can share the same prompt UX
62
+ * (single source of truth for what auth modes the CLI surfaces). The
63
+ * legacy `--auth-type token` alias is NOT offered here on purpose —
64
+ * interactive users get the canonical names; only flag invocations keep
65
+ * the alias for backwards compat.
66
+ */
67
+ export async function promptDirectMCPAuth() {
68
+ const { authMethod } = await inquirer.prompt([
69
+ {
70
+ type: "list",
71
+ name: "authMethod",
72
+ message: "Authentication method:",
73
+ choices: [
74
+ { name: "None", value: "none" },
75
+ { name: "Bearer token", value: "bearer_token" },
76
+ { name: "API key (custom header)", value: "api_key" },
77
+ { name: "OAuth client credentials", value: "oauth_client_credentials" },
78
+ ],
79
+ },
80
+ ]);
81
+ if (authMethod === "none")
82
+ return { type: "none" };
83
+ if (authMethod === "bearer_token") {
84
+ const { token } = await inquirer.prompt([
85
+ {
86
+ type: "password",
87
+ name: "token",
88
+ message: "Bearer token:",
89
+ mask: "*",
90
+ validate: (v) => v.trim().length > 0 || "Token is required",
91
+ },
92
+ ]);
93
+ return {
94
+ type: "bearer_token",
95
+ value: token.trim(),
96
+ };
97
+ }
98
+ if (authMethod === "api_key") {
99
+ const { headerName, apiKey } = await inquirer.prompt([
100
+ {
101
+ type: "input",
102
+ name: "headerName",
103
+ message: "Header name (e.g. X-API-Key):",
104
+ validate: (v) => v.trim().length > 0 || "Header name is required",
105
+ },
106
+ {
107
+ type: "password",
108
+ name: "apiKey",
109
+ message: "API key value:",
110
+ mask: "*",
111
+ validate: (v) => v.trim().length > 0 || "API key is required",
112
+ },
113
+ ]);
114
+ return {
115
+ type: "api_key",
116
+ value: apiKey.trim(),
117
+ header_name: headerName.trim(),
118
+ };
119
+ }
120
+ // oauth_client_credentials — collect the token-endpoint + client credentials.
121
+ const { url, clientId, clientSecret } = await inquirer.prompt([
122
+ {
123
+ type: "input",
124
+ name: "url",
125
+ message: "OAuth token endpoint URL:",
126
+ validate: (v) => {
127
+ const t = v.trim();
128
+ if (!t)
129
+ return "URL is required";
130
+ try {
131
+ new URL(t);
132
+ return true;
133
+ }
134
+ catch {
135
+ return "Must be a valid URL";
136
+ }
137
+ },
138
+ },
139
+ {
140
+ type: "input",
141
+ name: "clientId",
142
+ message: "OAuth client ID:",
143
+ validate: (v) => v.trim().length > 0 || "Client ID is required",
144
+ },
145
+ {
146
+ type: "password",
147
+ name: "clientSecret",
148
+ message: "OAuth client secret:",
149
+ mask: "*",
150
+ validate: (v) => v.trim().length > 0 || "Client secret is required",
151
+ },
152
+ ]);
153
+ return {
154
+ type: "oauth_client_credentials",
155
+ oauth_client_credentials: {
156
+ url: url.trim(),
157
+ method: "POST",
158
+ client_id: clientId.trim(),
159
+ client_secret: clientSecret.trim(),
160
+ grant_type: "client_credentials",
161
+ },
162
+ };
163
+ }
43
164
  // ─── BYO Credentials File Loader ───
44
165
  function loadCredentialsFile(filePath) {
45
166
  let raw;
@@ -391,10 +512,17 @@ export async function integration(_options = {}) {
391
512
  export async function integrationDiscover(options = {}) {
392
513
  const session = await getAuthenticatedSession();
393
514
  let serverUrl = options.url || "";
394
- let auth = { type: "none" };
395
- if (options.authType === "token" && options.authToken) {
396
- auth = { type: "token", token: options.authToken };
397
- }
515
+ // Canonical MCPAuthentication shape built once in the command layer
516
+ // via the shared service-layer helper and passed straight through to
517
+ // discoverMCPTools (no per-callee reshaping). Handles the canonical
518
+ // surface declared by the backend `MCPAuthentication` schema:
519
+ // none | bearer_token | api_key | oauth_client_credentials
520
+ // (plus the CLI-only `--auth-type token` alias, collapsed to
521
+ // bearer_token inside buildAuthFromFlags before any wire emission).
522
+ let auth = buildAuthFromFlags(options);
523
+ // Validate --transport-type up-front (throws on a bad value). undefined
524
+ // means "let the service apply the schema default of STREAMABLE_HTTP".
525
+ const transportType = parseTransportType(options.transportType);
398
526
  // Resolve scope
399
527
  const scope = resolveScopeIds(session, {
400
528
  organizationId: options.organizationId,
@@ -427,28 +555,13 @@ export async function integrationDiscover(options = {}) {
427
555
  },
428
556
  ]);
429
557
  serverUrl = answers.url.trim();
430
- const { authMethod } = await inquirer.prompt([
431
- {
432
- type: "list",
433
- name: "authMethod",
434
- message: "Authentication method:",
435
- choices: [
436
- { name: "None", value: "none" },
437
- { name: "Token", value: "token" },
438
- ],
439
- },
440
- ]);
441
- if (authMethod === "token") {
442
- const { token } = await inquirer.prompt([
443
- {
444
- type: "password",
445
- name: "token",
446
- message: "Authentication token:",
447
- mask: "*",
448
- validate: (input) => input.trim().length > 0 || "Token is required",
449
- },
450
- ]);
451
- auth = { type: "token", token: token.trim() };
558
+ // Interactive auth picker covers the full canonical surface so users
559
+ // can discover against any MCP server they would also `create` /
560
+ // `mcp-test` against. The prompt only runs when the user didn't pass
561
+ // --auth-type (so flag-driven invocations short-circuit and use the
562
+ // value we already parsed via buildAuthFromFlags).
563
+ if (!options.authType) {
564
+ auth = await promptDirectMCPAuth();
452
565
  }
453
566
  }
454
567
  if (isJsonMode()) {
@@ -458,7 +571,7 @@ export async function integrationDiscover(options = {}) {
458
571
  ? null
459
572
  : startSpinner("Discovering tools from MCP server...");
460
573
  try {
461
- const result = await discoverMCPTools(session, serverUrl, scope, auth);
574
+ const result = await discoverMCPTools(session, serverUrl, scope, auth, transportType);
462
575
  if (isJsonMode()) {
463
576
  outputJson({
464
577
  server_url: serverUrl,
@@ -588,10 +701,15 @@ async function manualIntegrationFlow(session, options, target) {
588
701
  let integrationName = options.name || "";
589
702
  let description = options.description || "";
590
703
  let serverUrl = options.url || "";
591
- let auth = { type: "none" };
592
- if (options.authType === "token" && options.authToken) {
593
- auth = { type: "token", token: options.authToken };
594
- }
704
+ // Canonical MCPAuthentication shape see the discover call site above
705
+ // for the shape rationale; buildAuthFromFlags centralises the parsing.
706
+ let auth = buildAuthFromFlags(options);
707
+ // Validate --transport-type up-front so a bad value fails before the
708
+ // discover spinner. undefined → let the service apply the schema
709
+ // default (STREAMABLE_HTTP). We reuse the parsed value for BOTH the
710
+ // discover call below and the save request further down so the same
711
+ // transport is exercised end-to-end.
712
+ const transportType = parseTransportType(options.transportType);
595
713
  // ── Name & Description ──
596
714
  if (!integrationName) {
597
715
  if (noPrompt) {
@@ -662,30 +780,15 @@ async function manualIntegrationFlow(session, options, target) {
662
780
  serverUrl = urlAnswer.url.trim();
663
781
  }
664
782
  // ── Authentication ──
783
+ //
784
+ // Interactive picker only runs when the caller didn't pass --auth-type
785
+ // — flag invocations short-circuit and use the canonical shape we
786
+ // already built above. The picker covers the full canonical surface
787
+ // (bearer_token / api_key / oauth_client_credentials / none) via the
788
+ // shared `promptDirectMCPAuth` helper, so DIRECT integrations created
789
+ // interactively are no longer limited to the legacy `token` choice.
665
790
  if (!options.authType && !isNonInteractive && !noPrompt) {
666
- const { authMethod } = await inquirer.prompt([
667
- {
668
- type: "list",
669
- name: "authMethod",
670
- message: "Authentication method:",
671
- choices: [
672
- { name: "None", value: "none" },
673
- { name: "Token", value: "token" },
674
- ],
675
- },
676
- ]);
677
- if (authMethod === "token") {
678
- const { token } = await inquirer.prompt([
679
- {
680
- type: "password",
681
- name: "token",
682
- message: "Authentication token:",
683
- mask: "*",
684
- validate: (input) => input.trim().length > 0 || "Token is required",
685
- },
686
- ]);
687
- auth = { type: "token", token: token.trim() };
688
- }
791
+ auth = await promptDirectMCPAuth();
689
792
  }
690
793
  // ── Discover Tools ──
691
794
  if (isJsonMode()) {
@@ -696,7 +799,7 @@ async function manualIntegrationFlow(session, options, target) {
696
799
  : startSpinner("Discovering tools from MCP server...");
697
800
  let discoveredTools;
698
801
  try {
699
- const result = await discoverMCPTools(session, serverUrl, scope, auth);
802
+ const result = await discoverMCPTools(session, serverUrl, scope, auth, transportType);
700
803
  discoveredTools = result.tools;
701
804
  if (discoveredTools.length === 0) {
702
805
  if (isJsonMode()) {
@@ -790,13 +893,17 @@ async function manualIntegrationFlow(session, options, target) {
790
893
  stderrLog("Creating integration...");
791
894
  }
792
895
  const saveSpinner = isJsonMode() ? null : startSpinner("Creating integration...");
896
+ // `transportType` was parsed at the top of this flow so the discovery
897
+ // call exercised the same transport the save body will carry.
793
898
  const request = {
899
+ type: "DIRECT",
794
900
  name: integrationName,
795
901
  display_name: integrationName,
796
902
  description,
797
903
  server_url: serverUrl,
798
904
  authentication: auth,
799
905
  tool_names: selectedToolNames,
906
+ ...(transportType ? { transport_type: transportType } : {}),
800
907
  };
801
908
  try {
802
909
  const result = await saveIntegrationSvc(session, request, scope);
@@ -1221,8 +1328,8 @@ async function nativeIntegrationFlow(session, options, target) {
1221
1328
  // ── Step 6: Connect Toolkit ──
1222
1329
  // The Composio user namespace is scoped to the agent's network_id so every
1223
1330
  // agent maintains its own isolated connection set. This is the same value
1224
- // persisted as `settings.user_id` on the resulting integration
1225
- // (per MCP_SCHEMA_CHANGES: IntegrationComposioMCPSettingsView.user_id).
1331
+ // persisted as `settings.composio.user_id` on the resulting integration
1332
+ // (per backend `ComposioIntegrationSchema.user_id`).
1226
1333
  const composioUserId = scope.networkId;
1227
1334
  if (isJsonMode()) {
1228
1335
  stderrLog("Connecting toolkit...");
@@ -1453,25 +1560,81 @@ async function nativeIntegrationFlow(session, options, target) {
1453
1560
  return;
1454
1561
  }
1455
1562
  }
1456
- // ── Step 11: Save Integration ──
1563
+ // ── Step 11: Provision Composio MCP Server (URL + stable server_id) ──
1564
+ //
1565
+ // The integration record stores both values so downstream consumers
1566
+ // (mcp-test, agent runtime, BFF) can hit the MCP endpoint directly
1567
+ // and so subsequent runs reuse the same server instead of minting a
1568
+ // fresh one. `--server-id` lets callers pin a stable name across
1569
+ // invocations; when omitted, a 30-char UUID prefix is generated by
1570
+ // `getComposioServerUrl` (matching the backend convention).
1571
+ if (isJsonMode()) {
1572
+ stderrLog(`Provisioning Composio MCP server for ${toolkitSlug}...`);
1573
+ }
1574
+ const provisionSpinner = isJsonMode()
1575
+ ? null
1576
+ : startSpinner(`Provisioning MCP server for ${toolkitSlug}...`);
1577
+ let mcpServerUrl;
1578
+ let mcpServerId;
1579
+ try {
1580
+ const provisioned = await getComposioServerUrl(apiKey, {
1581
+ composioUserId,
1582
+ toolkit: toolkitSlug,
1583
+ allowedTools: selectedToolNames,
1584
+ serverId: options.serverId,
1585
+ });
1586
+ mcpServerUrl = provisioned.url;
1587
+ mcpServerId = provisioned.serverId;
1588
+ provisionSpinner?.succeed(`MCP server ready (${mcpServerId})`);
1589
+ }
1590
+ catch (error) {
1591
+ provisionSpinner?.fail("Failed to provision MCP server");
1592
+ if (isJsonMode()) {
1593
+ outputJsonError({
1594
+ code: "API_CLIENT_ERROR",
1595
+ message: `Failed to provision Composio MCP server: ${error instanceof Error ? error.message : String(error)}`,
1596
+ });
1597
+ }
1598
+ else {
1599
+ log(_jsx(ErrorDisplay, { error: error, message: "Failed to provision Composio MCP server.", suggestion: "Re-run with AUI_DEBUG=1 to see the underlying Composio API call." }));
1600
+ }
1601
+ resetComposioClient();
1602
+ return;
1603
+ }
1604
+ // ── Step 12: Save Integration ──
1457
1605
  if (isJsonMode()) {
1458
1606
  stderrLog("Creating integration...");
1459
1607
  }
1460
1608
  const saveSpinner = isJsonMode()
1461
1609
  ? null
1462
1610
  : startSpinner("Creating integration...");
1611
+ // Build the COMPOSIO save body per `IntegrationMCPSettings`:
1612
+ // - the discriminated union forbids the DIRECT-only `authentication`
1613
+ // field here at compile time;
1614
+ // - `server_id` lives inside `composio` (per `ComposioIntegrationSchema`);
1615
+ // - `server_url` is sent in TWO places so consumers don't have to
1616
+ // coordinate: at the top level (`settings.server_url`, per
1617
+ // `IntegrationMCPSettings`) AND inside `composio` (alongside
1618
+ // `server_id`, so the nested payload is self-contained);
1619
+ // - `transport_type` is optional — when omitted the service defaults
1620
+ // it to STREAMABLE_HTTP, which is the only transport Composio MCP
1621
+ // servers currently support. `--transport-type SSE` is accepted for
1622
+ // parity with the canonical schema / manual flow.
1623
+ const nativeTransportType = parseTransportType(options.transportType);
1463
1624
  const request = {
1625
+ type: "COMPOSIO",
1464
1626
  name: integrationName,
1465
1627
  display_name: integrationName,
1466
1628
  description,
1467
- server_url: "",
1468
- authentication: { type: "none" },
1469
- tool_names: selectedToolNames,
1629
+ server_url: mcpServerUrl,
1470
1630
  composio: {
1471
1631
  user_id: scope.networkId,
1472
1632
  toolkits: [toolkitSlug],
1473
1633
  tool_names: selectedToolNames,
1634
+ server_id: mcpServerId,
1635
+ server_url: mcpServerUrl,
1474
1636
  },
1637
+ ...(nativeTransportType ? { transport_type: nativeTransportType } : {}),
1475
1638
  };
1476
1639
  try {
1477
1640
  const result = await saveIntegrationSvc(session, request, scope);
@@ -1493,6 +1656,8 @@ async function nativeIntegrationFlow(session, options, target) {
1493
1656
  toolkit: toolkitSlug,
1494
1657
  tool_names: selectedToolNames,
1495
1658
  tool_count: selectedToolNames.length,
1659
+ server_url: mcpServerUrl,
1660
+ server_id: mcpServerId,
1496
1661
  scope: {
1497
1662
  organization_id: scope.organizationId,
1498
1663
  account_id: scope.accountId,
@@ -1507,7 +1672,7 @@ async function nativeIntegrationFlow(session, options, target) {
1507
1672
  return;
1508
1673
  }
1509
1674
  saveSpinner?.succeed("Integration created");
1510
- log(_jsx(NativeIntegrationCreatedView, { name: integrationName, toolkitSlug: toolkitSlug, toolCount: selectedToolNames.length, toolNames: selectedToolNames }));
1675
+ log(_jsx(NativeIntegrationCreatedView, { name: integrationName, toolkitSlug: toolkitSlug, toolCount: selectedToolNames.length, toolNames: selectedToolNames, serverUrl: mcpServerUrl, serverId: mcpServerId }));
1511
1676
  }
1512
1677
  catch (error) {
1513
1678
  if (isJsonMode()) {