aui-agent-builder 0.3.121 → 0.3.123

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.
@@ -0,0 +1,77 @@
1
+ /**
2
+ * `aui integration test` — live-call an integration endpoint from the CLI.
3
+ *
4
+ * Thin, fully non-interactive wrapper over the Apollo integration test
5
+ * endpoint:
6
+ *
7
+ * POST /apollo-api/v1/integrations/test
8
+ *
9
+ * It makes the REAL HTTP call described by the request body (the same body
10
+ * you'd hand-write for `curl`), then returns:
11
+ *
12
+ * - `test_data` — the RAW response the endpoint returned.
13
+ * - `parsed_test_response` — that raw response after the JS
14
+ * `response_parser` snippet runs against it
15
+ * (i.e. exactly what the agent's `json_ry`
16
+ * parser would extract at runtime).
17
+ *
18
+ * This is the programmatic replacement for running `curl` by hand against
19
+ * every endpoint while authoring an integration — and it shows, in one
20
+ * call, both the raw payload and what the configured parser pulls out of
21
+ * it.
22
+ *
23
+ * ─── Design ──────────────────────────────────────────────────────────────
24
+ *
25
+ * - **Always JSON.** The payload is meant to be consumed by tooling (and by
26
+ * coding agents like Claude/Cursor), so output is ALWAYS a JSON envelope —
27
+ * the `--json` flag is implied. Errors are JSON too.
28
+ * - **Fully non-interactive.** Every input is a flag; no prompts, ever. Safe
29
+ * to run inside the E2B sandbox (`agent-builder-bff`).
30
+ * - **`--raw`** returns ONLY the raw endpoint response (`test_data`),
31
+ * skipping the parsed projection — handy when you just want the upstream
32
+ * payload.
33
+ * - **Auth.** Uses the normal CLI session (access token + org headers); the
34
+ * gateway validates it and forwards Apollo's `x-api-key` + `x-aui-*`
35
+ * claims — see `api-client/apollo-client.ts`.
36
+ *
37
+ * ─── Input ───────────────────────────────────────────────────────────────
38
+ *
39
+ * The request body matches the integration's own configuration (the fields
40
+ * the user edits in the local `.aui.json` integration file): `url`,
41
+ * `method`, `request_body`, `authentication`, `response_parser`. Provide it
42
+ * either as one JSON blob via `--params` (recommended — copy it straight
43
+ * from the integration file) or piecemeal via the granular flags, which
44
+ * override matching keys from `--params`.
45
+ *
46
+ * Examples:
47
+ * aui integration test --params '{"url":"https://api.perplexity.ai/chat/completions","method":"POST","request_body":{...},"authentication":{"type":"BEARER_TOKEN","token":"pplx-..."},"response_parser":"..."}'
48
+ * aui integration test --params-file ./body.json
49
+ * aui integration test --url https://api.example.com/v1/search --method POST \
50
+ * --request-body '{"q":"tokyo"}' --auth-type BEARER_TOKEN --auth-token sk-... --raw
51
+ */
52
+ export interface IntegrationTestOptions {
53
+ /** Full request body as a JSON string (url/method/request_body/…). */
54
+ params?: string;
55
+ /** Path to a file containing the request body JSON. */
56
+ paramsFile?: string;
57
+ /** Integration endpoint URL (overrides params.url). */
58
+ url?: string;
59
+ /** HTTP method (overrides params.method). */
60
+ method?: string;
61
+ /** Request body JSON string (overrides params.request_body). */
62
+ requestBody?: string;
63
+ /** Query params JSON string (overrides params.query_params). */
64
+ queryParams?: string;
65
+ /** Extra headers JSON string (overrides params.headers). */
66
+ headers?: string;
67
+ /** Authentication scheme, e.g. BEARER_TOKEN, API_KEY, BASIC, NONE. */
68
+ authType?: string;
69
+ /** Authentication token (used with --auth-type BEARER_TOKEN / API_KEY). */
70
+ authToken?: string;
71
+ /** JS response-parser snippet (overrides params.response_parser). */
72
+ responseParser?: string;
73
+ /** Return only the raw endpoint response (test_data). */
74
+ raw?: boolean;
75
+ }
76
+ export declare function integrationTest(options?: IntegrationTestOptions): Promise<void>;
77
+ //# sourceMappingURL=integration-test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integration-test.d.ts","sourceRoot":"","sources":["../../src/commands/integration-test.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AA6BH,MAAM,WAAW,sBAAsB;IACrC,sEAAsE;IACtE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uDAAuD;IACvD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uDAAuD;IACvD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gEAAgE;IAChE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gEAAgE;IAChE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4DAA4D;IAC5D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qEAAqE;IACrE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,yDAAyD;IACzD,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAkHD,wBAAsB,eAAe,CACnC,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,IAAI,CAAC,CAyEf"}
@@ -0,0 +1,207 @@
1
+ /**
2
+ * `aui integration test` — live-call an integration endpoint from the CLI.
3
+ *
4
+ * Thin, fully non-interactive wrapper over the Apollo integration test
5
+ * endpoint:
6
+ *
7
+ * POST /apollo-api/v1/integrations/test
8
+ *
9
+ * It makes the REAL HTTP call described by the request body (the same body
10
+ * you'd hand-write for `curl`), then returns:
11
+ *
12
+ * - `test_data` — the RAW response the endpoint returned.
13
+ * - `parsed_test_response` — that raw response after the JS
14
+ * `response_parser` snippet runs against it
15
+ * (i.e. exactly what the agent's `json_ry`
16
+ * parser would extract at runtime).
17
+ *
18
+ * This is the programmatic replacement for running `curl` by hand against
19
+ * every endpoint while authoring an integration — and it shows, in one
20
+ * call, both the raw payload and what the configured parser pulls out of
21
+ * it.
22
+ *
23
+ * ─── Design ──────────────────────────────────────────────────────────────
24
+ *
25
+ * - **Always JSON.** The payload is meant to be consumed by tooling (and by
26
+ * coding agents like Claude/Cursor), so output is ALWAYS a JSON envelope —
27
+ * the `--json` flag is implied. Errors are JSON too.
28
+ * - **Fully non-interactive.** Every input is a flag; no prompts, ever. Safe
29
+ * to run inside the E2B sandbox (`agent-builder-bff`).
30
+ * - **`--raw`** returns ONLY the raw endpoint response (`test_data`),
31
+ * skipping the parsed projection — handy when you just want the upstream
32
+ * payload.
33
+ * - **Auth.** Uses the normal CLI session (access token + org headers); the
34
+ * gateway validates it and forwards Apollo's `x-api-key` + `x-aui-*`
35
+ * claims — see `api-client/apollo-client.ts`.
36
+ *
37
+ * ─── Input ───────────────────────────────────────────────────────────────
38
+ *
39
+ * The request body matches the integration's own configuration (the fields
40
+ * the user edits in the local `.aui.json` integration file): `url`,
41
+ * `method`, `request_body`, `authentication`, `response_parser`. Provide it
42
+ * either as one JSON blob via `--params` (recommended — copy it straight
43
+ * from the integration file) or piecemeal via the granular flags, which
44
+ * override matching keys from `--params`.
45
+ *
46
+ * Examples:
47
+ * aui integration test --params '{"url":"https://api.perplexity.ai/chat/completions","method":"POST","request_body":{...},"authentication":{"type":"BEARER_TOKEN","token":"pplx-..."},"response_parser":"..."}'
48
+ * aui integration test --params-file ./body.json
49
+ * aui integration test --url https://api.example.com/v1/search --method POST \
50
+ * --request-body '{"q":"tokyo"}' --auth-type BEARER_TOKEN --auth-token sk-... --raw
51
+ */
52
+ import { getConfig, loadSession, loadProjectConfig, findProjectRoot, } from "../config/index.js";
53
+ import { ApolloClient, } from "../api-client/apollo-client.js";
54
+ import { getTracer, SpanStatusCode, } from "../telemetry.js";
55
+ import { AuthenticationError, ConfigError, ValidationError, } from "../errors/index.js";
56
+ import { outputJson, setJsonMode, stderrLog, } from "../utils/json-output.js";
57
+ function parseJsonOption(value, flag) {
58
+ if (value === undefined)
59
+ return undefined;
60
+ try {
61
+ return JSON.parse(value);
62
+ }
63
+ catch (e) {
64
+ throw new ValidationError(`Invalid JSON passed to ${flag}: ${e instanceof Error ? e.message : String(e)}`, {
65
+ suggestion: `Pass valid JSON to ${flag}. Wrap it in single quotes so your shell doesn't mangle it.`,
66
+ });
67
+ }
68
+ }
69
+ /** Build the ApolloClient from the current session + project scope. */
70
+ function buildClient() {
71
+ const projectRoot = findProjectRoot() || undefined;
72
+ const projectConfig = loadProjectConfig(projectRoot);
73
+ const config = getConfig(projectRoot);
74
+ const session = loadSession();
75
+ if (!config.authToken) {
76
+ throw new AuthenticationError("Not logged in.", {
77
+ suggestion: "Run `aui login` first.",
78
+ });
79
+ }
80
+ const organizationId = projectConfig?.organization_id || config.organizationId;
81
+ if (!organizationId) {
82
+ throw new ConfigError("No organization could be resolved.", {
83
+ suggestion: "Run `aui login` (and select an organization), or run inside an imported agent project so .auirc carries organization_id.",
84
+ });
85
+ }
86
+ return new ApolloClient({
87
+ authToken: config.authToken,
88
+ organizationId,
89
+ accountId: projectConfig?.account_id || config.accountId || "",
90
+ userId: session?.user_id,
91
+ environment: config.environment,
92
+ });
93
+ }
94
+ /**
95
+ * Assemble the test request body from `--params` (base) plus any granular
96
+ * flags (which take precedence). Validates that a URL is present.
97
+ */
98
+ function assembleBody(options, fileContents) {
99
+ // Base: --params-file wins over --params if both are given (file is the
100
+ // more explicit source); granular flags then override individual keys.
101
+ const baseRaw = fileContents ?? options.params;
102
+ const base = parseJsonOption(baseRaw, fileContents ? "--params-file" : "--params") ?? {};
103
+ if (typeof base !== "object" || Array.isArray(base)) {
104
+ throw new ValidationError("The request body must be a JSON object.", { suggestion: 'Example: --params \'{"url":"https://...","method":"POST"}\'' });
105
+ }
106
+ const body = { ...base };
107
+ if (options.url)
108
+ body.url = options.url;
109
+ if (options.method)
110
+ body.method = options.method;
111
+ if (options.requestBody !== undefined) {
112
+ body.request_body = parseJsonOption(options.requestBody, "--request-body");
113
+ }
114
+ if (options.queryParams !== undefined) {
115
+ body.query_params = parseJsonOption(options.queryParams, "--query-params");
116
+ }
117
+ if (options.headers !== undefined) {
118
+ body.headers = parseJsonOption(options.headers, "--headers");
119
+ }
120
+ if (options.authType) {
121
+ body.authentication = {
122
+ ...(typeof body.authentication === "object" && body.authentication
123
+ ? body.authentication
124
+ : {}),
125
+ type: options.authType,
126
+ ...(options.authToken ? { token: options.authToken } : {}),
127
+ };
128
+ }
129
+ else if (options.authToken && body.authentication) {
130
+ body.authentication = { ...body.authentication, token: options.authToken };
131
+ }
132
+ if (options.responseParser !== undefined) {
133
+ body.response_parser = options.responseParser;
134
+ }
135
+ if (!body.url || typeof body.url !== "string") {
136
+ throw new ValidationError("Missing required value: url.", {
137
+ suggestion: 'Provide it via --params \'{"url":"https://..."}\' or --url <endpoint>.',
138
+ });
139
+ }
140
+ if (!body.method)
141
+ body.method = "GET";
142
+ return body;
143
+ }
144
+ export async function integrationTest(options = {}) {
145
+ // JSON-only command: its payload (raw + parsed endpoint response) is meant
146
+ // for tooling / coding agents, not a TTY. Force JSON mode so output is
147
+ // always a JSON envelope, regardless of whether `--json` was passed.
148
+ setJsonMode(true);
149
+ const tracer = getTracer();
150
+ await tracer.startActiveSpan("aui.integration.test", async (span) => {
151
+ try {
152
+ let fileContents;
153
+ if (options.paramsFile) {
154
+ const fs = await import("node:fs");
155
+ try {
156
+ fileContents = fs.readFileSync(options.paramsFile, "utf-8");
157
+ }
158
+ catch (e) {
159
+ throw new ValidationError(`Could not read --params-file: ${options.paramsFile}`, {
160
+ suggestion: `Check the path exists and is readable (${e instanceof Error ? e.message : String(e)}).`,
161
+ });
162
+ }
163
+ }
164
+ const body = assembleBody(options, fileContents);
165
+ span.setAttribute("integration.url", body.url);
166
+ span.setAttribute("integration.method", body.method || "GET");
167
+ span.setAttribute("integration.has_parser", !!body.response_parser);
168
+ span.setAttribute("integration.raw", !!options.raw);
169
+ const client = buildClient();
170
+ stderrLog(`Calling integration endpoint: ${body.method} ${body.url} ...`);
171
+ const result = await client.testIntegration(body);
172
+ span.setStatus({ code: SpanStatusCode.OK });
173
+ if (options.raw) {
174
+ // Only the raw upstream response. Fall back to the whole envelope if
175
+ // the endpoint didn't split it out under `test_data`.
176
+ const rawData = result && typeof result === "object" && "test_data" in result
177
+ ? result.test_data
178
+ : result;
179
+ outputJson({
180
+ url: body.url,
181
+ method: body.method,
182
+ raw: true,
183
+ test_data: rawData,
184
+ });
185
+ return;
186
+ }
187
+ // Default: both the raw response and the parser projection, mirroring
188
+ // the endpoint's own shape so callers can compare them.
189
+ outputJson({
190
+ url: body.url,
191
+ method: body.method,
192
+ test_data: result?.test_data ?? null,
193
+ parsed_test_response: result?.parsed_test_response ?? null,
194
+ });
195
+ }
196
+ catch (error) {
197
+ const msg = error instanceof Error ? error.message : String(error);
198
+ span.setStatus({ code: SpanStatusCode.ERROR, message: msg });
199
+ span.recordException(error instanceof Error ? error : new Error(msg));
200
+ throw error;
201
+ }
202
+ finally {
203
+ span.end();
204
+ }
205
+ });
206
+ }
207
+ //# sourceMappingURL=integration-test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integration-test.js","sourceRoot":"","sources":["../../src/commands/integration-test.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * `aui integration toolkits` — list native (Composio) toolkits.
3
+ *
4
+ * Wraps the same endpoint the Composio dashboard hits:
5
+ * GET https://backend.composio.dev/api/v3.1/toolkits?sort_by=usage&limit=<n>
6
+ *
7
+ * Designed to be safely consumed from the E2B sandbox (`agent-builder-bff`)
8
+ * as well as from a developer's terminal:
9
+ *
10
+ * - Fully non-interactive: no prompts, no Ink layouts that block on input.
11
+ * - `--json` emits the canonical structured envelope and exits with the
12
+ * standard CLI exit code (0 success, 2 validation, 1 runtime).
13
+ * - `--all` follows the pagination cursor and returns every toolkit in one
14
+ * call (otherwise a single page is returned).
15
+ * - The Composio API key is the same one already used for native MCP
16
+ * integrations. Resolution precedence:
17
+ * 1. `--composio-api-key <key>`
18
+ * 2. `COMPOSIO_API_KEY` env var
19
+ * 3. Backend-issued key fetched via `fetchComposioApiKey` (requires
20
+ * an authenticated AUI session)
21
+ *
22
+ * Examples:
23
+ * aui integration toolkits
24
+ * aui integration toolkits --search notion --json
25
+ * aui integration toolkits --all --json
26
+ */
27
+ export interface IntegrationToolkitsOptions {
28
+ search?: string;
29
+ limit?: string;
30
+ cursor?: string;
31
+ composioApiKey?: string;
32
+ all?: boolean;
33
+ }
34
+ export declare function integrationToolkits(options?: IntegrationToolkitsOptions): Promise<void>;
35
+ //# sourceMappingURL=integration-toolkits.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integration-toolkits.d.ts","sourceRoot":"","sources":["../../src/commands/integration-toolkits.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAyBH,MAAM,WAAW,0BAA0B;IACzC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAOD,wBAAsB,mBAAmB,CACvC,OAAO,GAAE,0BAA+B,GACvC,OAAO,CAAC,IAAI,CAAC,CA0Ff"}
@@ -0,0 +1,101 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { render, Box, Text } from "ink";
3
+ import { getAuthenticatedSession, fetchComposioApiKey, listComposioToolkits, } from "../services/integration.service.js";
4
+ import { Header, Section, StatusLine, KeyValue, Spinner, } from "../ui/components/index.js";
5
+ import { colors } from "../ui/theme.js";
6
+ import { isJsonMode, outputJson, stderrLog, } from "../utils/json-output.js";
7
+ import { ValidationError, ConfigError, CLIError } from "../errors/index.js";
8
+ function log(node) {
9
+ const { unmount } = render(node);
10
+ unmount();
11
+ }
12
+ export async function integrationToolkits(options = {}) {
13
+ const limit = options.limit ? parseInt(options.limit, 10) : 50;
14
+ if (Number.isNaN(limit) || limit <= 0) {
15
+ throw new ValidationError("Invalid --limit value", {
16
+ suggestion: "Pass a positive integer (e.g. --limit 100).",
17
+ });
18
+ }
19
+ const search = options.search?.trim() || undefined;
20
+ // ── Resolve API key ──
21
+ let apiKey = (options.composioApiKey && options.composioApiKey.trim()) ||
22
+ process.env.COMPOSIO_API_KEY ||
23
+ "";
24
+ if (!apiKey) {
25
+ if (isJsonMode()) {
26
+ stderrLog("Fetching integration configuration...");
27
+ }
28
+ const session = await getAuthenticatedSession();
29
+ const fetched = await fetchComposioApiKey(session);
30
+ if (fetched)
31
+ apiKey = fetched;
32
+ }
33
+ if (!apiKey) {
34
+ throw new ConfigError("Composio API key not available.", {
35
+ suggestion: "Pass --composio-api-key, set COMPOSIO_API_KEY, or have your administrator configure it on the backend.",
36
+ });
37
+ }
38
+ // ── Fetch ──
39
+ if (isJsonMode()) {
40
+ stderrLog(`Fetching toolkits from Composio${search ? ` (search="${search}")` : ""}${options.all ? " [all pages]" : ""}...`);
41
+ }
42
+ let spinner = null;
43
+ if (!isJsonMode()) {
44
+ spinner = render(_jsx(Spinner, { label: "Fetching toolkits from Composio..." }));
45
+ }
46
+ try {
47
+ const toolkits = [];
48
+ let nextCursor = options.cursor;
49
+ do {
50
+ const result = await listComposioToolkits(apiKey, {
51
+ search,
52
+ limit,
53
+ cursor: nextCursor,
54
+ });
55
+ toolkits.push(...result.items);
56
+ nextCursor = result.nextCursor;
57
+ } while (options.all && nextCursor);
58
+ spinner?.unmount();
59
+ if (isJsonMode()) {
60
+ outputJson({
61
+ search: search ?? null,
62
+ count: toolkits.length,
63
+ next_cursor: options.all ? null : (nextCursor ?? null),
64
+ toolkits: toolkits.map((tk) => ({
65
+ slug: tk.slug,
66
+ name: tk.name,
67
+ description: tk.description ?? null,
68
+ tools_count: tk.toolsCount ?? null,
69
+ no_auth: tk.isNoAuth ?? null,
70
+ auth_schemes: tk.authSchemes ?? [],
71
+ })),
72
+ });
73
+ return;
74
+ }
75
+ renderToolkitsView(toolkits, search, options.all ? undefined : nextCursor);
76
+ }
77
+ catch (err) {
78
+ spinner?.unmount();
79
+ if (err instanceof CLIError)
80
+ throw err;
81
+ throw new CLIError(`Failed to fetch Composio toolkits: ${err instanceof Error ? err.message : String(err)}`, {
82
+ code: "API_CLIENT_ERROR",
83
+ cause: err,
84
+ suggestion: "Verify the Composio API key has access to the toolkit directory.",
85
+ });
86
+ }
87
+ }
88
+ function renderToolkitsView(toolkits, search, nextCursor) {
89
+ log(_jsx(Box, { flexDirection: "column", paddingX: 1, children: _jsx(Header, { title: "Composio Toolkits", subtitle: `${toolkits.length} toolkit(s)${search ? ` · search="${search}"` : ""}` }) }));
90
+ if (toolkits.length === 0) {
91
+ log(_jsx(StatusLine, { kind: "warning", label: search
92
+ ? `No toolkits found matching "${search}".`
93
+ : "No toolkits returned." }));
94
+ return;
95
+ }
96
+ log(_jsx(Box, { flexDirection: "column", paddingX: 1, children: _jsx(Section, { title: `Toolkits (${toolkits.length})`, children: toolkits.map((tk, i) => (_jsxs(Box, { flexDirection: "column", marginBottom: i < toolkits.length - 1 ? 1 : 0, children: [_jsx(Text, { bold: true, color: colors.brand, children: tk.slug }), tk.name && tk.name !== tk.slug && (_jsx(KeyValue, { label: "Name", value: tk.name })), tk.toolsCount !== undefined && (_jsx(KeyValue, { label: "Tools", value: String(tk.toolsCount) })), tk.isNoAuth !== undefined && (_jsx(KeyValue, { label: "Auth", value: tk.isNoAuth ? "none" : "required" })), tk.description && (_jsx(Box, { marginLeft: 2, children: _jsx(Text, { color: colors.muted, children: tk.description }) }))] }, tk.slug || `toolkit-${i}`))) }) }));
97
+ if (nextCursor) {
98
+ log(_jsx(Box, { paddingX: 1, children: _jsx(StatusLine, { kind: "info", label: `More toolkits available — pass --all to fetch everything, or --cursor ${nextCursor}.` }) }));
99
+ }
100
+ }
101
+ //# sourceMappingURL=integration-toolkits.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"integration-toolkits.js","sourceRoot":"","sources":["../../src/commands/integration-toolkits.tsx"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -24,11 +24,14 @@ import { addIntegration } from "./commands/add-integration.js";
24
24
  import { apolloMenu, apolloCreateTask, apolloSendMessage, apolloRerun, apolloTrace, } from "./commands/apollo.js";
25
25
  import { integration, integrationCreate, integrationDiscover, } from "./commands/integration.js";
26
26
  import { integrationTools } from "./commands/integration-tools.js";
27
+ import { integrationToolkits } from "./commands/integration-toolkits.js";
28
+ import { integrationTest } from "./commands/integration-test.js";
27
29
  import { curl } from "./commands/curl.js";
28
30
  import { versionMenu, versionList, versionCreate, versionGet, versionPublish, versionActivate, versionArchive, versionUpdate, } from "./commands/version.js";
29
31
  import { versionSnapshotMenu, versionSnapshotList, versionSnapshotGet, versionSnapshotDiff, } from "./commands/version-snapshot.js";
30
32
  import { initUpdateCheck, printUpdateBannerOnExit, } from "./utils/update-notifier.js";
31
- import { setJsonMode } from "./utils/json-output.js";
33
+ import { setJsonMode, outputJson } from "./utils/json-output.js";
34
+ import { serializeCommand, resolveCommandFromArgv, } from "./utils/help-json.js";
32
35
  import { enableCapture, flushCapture } from "./utils/request-capture.js";
33
36
  import { createRequire } from "module";
34
37
  import { randomUUID } from "node:crypto";
@@ -179,15 +182,38 @@ program
179
182
  \x1b[31m\x1b[1m Widgets\x1b[0m
180
183
  widget generate <TOOL> Create or modify a tool's widget
181
184
 
185
+ \x1b[36m\x1b[1m Integrations — MCP (manual) & Composio (native)\x1b[0m
186
+ integration Interactive menu (create / discover)
187
+ add-integration Guided add of an integration (API, RAG, or MCP)
188
+
189
+ \x1b[1mDiscovery (non-interactive, --json)\x1b[0m
190
+ integration toolkits List native Composio toolkits
191
+ [--search <q>] [--all] [--limit <n>] [--cursor <c>] [--json]
192
+ integration tools --slugs <A,B> Fetch Composio tool descriptors by slug
193
+ [--toolkit-versions <v>] [--limit <n>] [--cursor <c>] [--json]
194
+ integration discover --url <url> Discover tools from a manual MCP server
195
+ [--auth-type token --auth-token <tok>] [--json]
196
+
197
+ \x1b[1mCreate (fully non-interactive with --full)\x1b[0m
198
+ integration create --full --name <n> --url <mcp-url> --all-tools
199
+ Manual MCP integration (your own server)
200
+ [--auth-type token --auth-token <tok>] [--tools a,b]
201
+ integration create --full --name <n> --toolkit <slug> --all-tools
202
+ Native Composio integration (toolkit from the directory)
203
+ [--composio-api-key <key>] [--tools a,b]
204
+ (scope: [--organization-id] [--account-id] [--network-id] [--version-id])
205
+
206
+ \x1b[1mTest (always JSON, non-interactive)\x1b[0m
207
+ integration test --params '<json>'
208
+ Live-call an endpoint → raw response + parser projection
209
+ --params has url/method/request_body/authentication/response_parser
210
+ (or use --url/--method/--request-body/--auth-type/--auth-token/--response-parser)
211
+ [--raw] returns only the raw response (test_data)
212
+
182
213
  \x1b[34m\x1b[1m Configuration\x1b[0m
183
214
  account Manage accounts (projects)
184
215
  env [environment] Show or switch environment
185
216
  pull-schema Fetch domain schemas from backend
186
- add-integration Add an integration (API, RAG, or MCP)
187
- integration Create/manage MCP integrations
188
- integration create Create MCP integration (manual or native)
189
- integration discover Discover tools from an MCP server
190
- integration tools Fetch Composio tool descriptors by slug (non-interactive, supports --json)
191
217
  rag Manage RAG knowledge bases and files
192
218
 
193
219
  \x1b[37m\x1b[1m Tools\x1b[0m
@@ -464,7 +490,7 @@ program
464
490
  const integrationCmd = program
465
491
  .command("integration")
466
492
  .alias("integrations")
467
- .description("Create and manage MCP integrations — create, discover, tools")
493
+ .description("Create and manage MCP integrations — create, discover, tools, toolkits, test")
468
494
  .action(async () => {
469
495
  try {
470
496
  await integration();
@@ -473,6 +499,46 @@ const integrationCmd = program
473
499
  await handleError(e);
474
500
  }
475
501
  });
502
+ // The CLI's custom root `formatHelp` only renders usage/description/options,
503
+ // so subcommands wouldn't otherwise appear under `aui integration --help`.
504
+ // Append a detailed, flag-level listing (Commander concatenates it after the
505
+ // formatted help, same mechanism the root + apollo help use).
506
+ integrationCmd.addHelpText("after", `
507
+ \x1b[1mCommands\x1b[0m
508
+
509
+ \x1b[1mDiscovery (non-interactive, --json)\x1b[0m
510
+ toolkits List native (Composio) toolkits
511
+ [--search <q>] [--all] [--limit <n>] [--cursor <c>] [--composio-api-key <key>] [--json]
512
+ tools Fetch Composio tool descriptors by slug
513
+ --slugs <SLUG_A,SLUG_B> [--toolkit-versions <v>] [--limit <n>] [--cursor <c>] [--composio-api-key <key>] [--json]
514
+ discover Discover tools exposed by a manual MCP server
515
+ --url <mcp-url> [--auth-type none|token] [--auth-token <tok>]
516
+ [--organization-id <id>] [--account-id <id>] [--network-id <id>] [--json]
517
+
518
+ \x1b[1mCreate (fully non-interactive with --full)\x1b[0m
519
+ create Create an MCP integration. Manual (your own MCP server) or native (Composio toolkit).
520
+ Manual: --name <n> --url <mcp-url> (--tools a,b | --all-tools) --full
521
+ [--auth-type token --auth-token <tok>] [--description <d>]
522
+ Native: --name <n> --toolkit <slug> (--tools a,b | --all-tools) --full
523
+ [--composio-api-key <key>]
524
+ Scope: [--organization-id <id>] [--account-id <id>] [--network-id <id>]
525
+ [--network-category-id <id>] [--version-id <id>]
526
+ --full makes it skip every prompt (org/account/agent + confirm); missing
527
+ required flags fail with a JSON validation error instead of prompting.
528
+ Native auth (OAuth) still opens a browser unless the toolkit is no-auth.
529
+
530
+ \x1b[1mTest (always JSON, non-interactive)\x1b[0m
531
+ test Live-call an integration endpoint: real HTTP request → returns the RAW
532
+ response (test_data) AND what the response_parser extracts (parsed_test_response).
533
+ --params '<json>' (full body: url, method, request_body, authentication, response_parser)
534
+ --params-file <path>
535
+ or granular: --url <u> --method <M> --request-body '<json>'
536
+ --auth-type BEARER_TOKEN --auth-token <tok> --response-parser '<js>'
537
+ [--query-params '<json>'] [--headers '<json>'] [--raw]
538
+ --raw returns ONLY the raw response (test_data). Replaces hand-running curl per endpoint.
539
+
540
+ \x1b[90m Run aui integration <command> --help for the full options of each command.\x1b[0m
541
+ `);
476
542
  integrationCmd
477
543
  .command("create")
478
544
  .description("Create a new MCP integration (interactive or non-interactive)")
@@ -538,6 +604,47 @@ integrationCmd
538
604
  await handleError(e);
539
605
  }
540
606
  });
607
+ integrationCmd
608
+ .command("toolkits")
609
+ .description("List native (Composio) toolkits (fully non-interactive; supports --json)")
610
+ .option("--search <query>", "Filter toolkits by search term")
611
+ .option("--all", "Follow pagination and return every toolkit (otherwise a single page)")
612
+ .option("--limit <n>", "Page size (default: 50)", "50")
613
+ .option("--cursor <cursor>", "Pagination cursor")
614
+ .option("--composio-api-key <key>", "Override Composio API key (otherwise: COMPOSIO_API_KEY env var or backend-issued key)")
615
+ .action(async (options) => {
616
+ try {
617
+ await integrationToolkits(options);
618
+ }
619
+ catch (e) {
620
+ await handleError(e);
621
+ }
622
+ });
623
+ integrationCmd
624
+ .command("test")
625
+ .description("Live-call an integration endpoint and return the raw response + the parser projection (always JSON; fully non-interactive)")
626
+ // Plain `--option` (not requiredOption) so a missing/invalid body surfaces
627
+ // through our ValidationError → JSON error envelope instead of Commander's
628
+ // pre-action exit. Same rationale as `integration tools` / `apollo send-message`.
629
+ .option("--params <json>", 'Full request body as a JSON string — the integration\'s own config fields: {"url","method","request_body","authentication","response_parser"}. Copy it straight from the integration .aui.json file.')
630
+ .option("--params-file <path>", "Read the request body JSON from a file instead of --params (file wins if both are given).")
631
+ .option("--url <url>", "Integration endpoint URL (overrides params.url)")
632
+ .option("--method <method>", "HTTP method: GET, POST, PATCH, … (overrides params.method; default GET)")
633
+ .option("--request-body <json>", "Request body as a JSON string (overrides params.request_body)")
634
+ .option("--query-params <json>", "Query params as a JSON string (overrides params.query_params)")
635
+ .option("--headers <json>", "Extra request headers as a JSON string (overrides params.headers)")
636
+ .option("--auth-type <type>", "Auth scheme: BEARER_TOKEN, API_KEY, BASIC, NONE (overrides params.authentication.type)")
637
+ .option("--auth-token <token>", "Auth token/secret used with --auth-type")
638
+ .option("--response-parser <js>", "JS snippet run against `response` (overrides params.response_parser)")
639
+ .option("--raw", "Return ONLY the raw endpoint response (test_data), skipping the parser projection")
640
+ .action(async (options) => {
641
+ try {
642
+ await integrationTest(options);
643
+ }
644
+ catch (e) {
645
+ await handleError(e);
646
+ }
647
+ });
541
648
  // ─── apollo (runtime messaging) ───
542
649
  //
543
650
  // Four commands wrapping the Apollo runtime endpoints (create task / send
@@ -998,6 +1105,24 @@ process.on("beforeExit", shutdown);
998
1105
  // no-op; commands hang
999
1106
  // straight off the session.
1000
1107
  // So `aui login` and `aui --version` keep working exactly as before.
1108
+ // `aui --help --json` (and `aui <command> --help --json`): emit the command
1109
+ // tree as a structured JSON envelope instead of the human help text. Handled
1110
+ // BEFORE `program.parse()` because Commander prints its own help and exits on
1111
+ // `--help`/`-h`, which would otherwise pre-empt this. Scoped to the deepest
1112
+ // command named in argv so subcommand help is JSON-serializable too.
1113
+ const argvTokens = process.argv.slice(2);
1114
+ const wantsHelp = argvTokens.includes("--help") || argvTokens.includes("-h");
1115
+ const wantsJson = argvTokens.includes("--json");
1116
+ if (wantsHelp && wantsJson) {
1117
+ setJsonMode(true);
1118
+ const target = resolveCommandFromArgv(program, argvTokens);
1119
+ outputJson({
1120
+ name: program.name(),
1121
+ version: pkg.version,
1122
+ command: serializeCommand(target),
1123
+ });
1124
+ process.exit(0);
1125
+ }
1001
1126
  withSessionContext(() => withAgentContext(() => program.parse()));
1002
1127
  // Register exit handler AFTER parse so it fires after ink's cleanup.
1003
1128
  // The banner appears below all command output via process.stdout.write().