@controllerai/cli 0.2.0

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 (96) hide show
  1. package/README.md +180 -0
  2. package/dist/api/client.js +330 -0
  3. package/dist/api/client.js.map +1 -0
  4. package/dist/appLinks.js +99 -0
  5. package/dist/appLinks.js.map +1 -0
  6. package/dist/argv.js +124 -0
  7. package/dist/argv.js.map +1 -0
  8. package/dist/commands/agent.js +813 -0
  9. package/dist/commands/agent.js.map +1 -0
  10. package/dist/commands/auth.js +327 -0
  11. package/dist/commands/auth.js.map +1 -0
  12. package/dist/commands/branch.js +441 -0
  13. package/dist/commands/branch.js.map +1 -0
  14. package/dist/commands/connect.js +148 -0
  15. package/dist/commands/connect.js.map +1 -0
  16. package/dist/commands/connection.js +148 -0
  17. package/dist/commands/connection.js.map +1 -0
  18. package/dist/commands/data.js +441 -0
  19. package/dist/commands/data.js.map +1 -0
  20. package/dist/commands/deps.js +63 -0
  21. package/dist/commands/deps.js.map +1 -0
  22. package/dist/commands/doctor.js +102 -0
  23. package/dist/commands/doctor.js.map +1 -0
  24. package/dist/commands/events.js +72 -0
  25. package/dist/commands/events.js.map +1 -0
  26. package/dist/commands/exec.js +306 -0
  27. package/dist/commands/exec.js.map +1 -0
  28. package/dist/commands/expr.js +346 -0
  29. package/dist/commands/expr.js.map +1 -0
  30. package/dist/commands/flow.js +447 -0
  31. package/dist/commands/flow.js.map +1 -0
  32. package/dist/commands/integration.js +102 -0
  33. package/dist/commands/integration.js.map +1 -0
  34. package/dist/commands/node.js +885 -0
  35. package/dist/commands/node.js.map +1 -0
  36. package/dist/commands/organize.js +234 -0
  37. package/dist/commands/organize.js.map +1 -0
  38. package/dist/commands/run.js +437 -0
  39. package/dist/commands/run.js.map +1 -0
  40. package/dist/commands/schema.js +269 -0
  41. package/dist/commands/schema.js.map +1 -0
  42. package/dist/commands/skills.js +1156 -0
  43. package/dist/commands/skills.js.map +1 -0
  44. package/dist/commands/trigger.js +992 -0
  45. package/dist/commands/trigger.js.map +1 -0
  46. package/dist/commands/workflow.js +503 -0
  47. package/dist/commands/workflow.js.map +1 -0
  48. package/dist/config.js +74 -0
  49. package/dist/config.js.map +1 -0
  50. package/dist/context.js +39 -0
  51. package/dist/context.js.map +1 -0
  52. package/dist/errors.js +59 -0
  53. package/dist/errors.js.map +1 -0
  54. package/dist/index.js +125 -0
  55. package/dist/index.js.map +1 -0
  56. package/dist/jsSource.js +32 -0
  57. package/dist/jsSource.js.map +1 -0
  58. package/dist/nodeProps.js +177 -0
  59. package/dist/nodeProps.js.map +1 -0
  60. package/dist/output.js +85 -0
  61. package/dist/output.js.map +1 -0
  62. package/dist/version.js +7 -0
  63. package/dist/version.js.map +1 -0
  64. package/package.json +41 -0
  65. package/skills/controllerai-agents/SKILL.md +169 -0
  66. package/skills/controllerai-agents/agents/openai.yaml +4 -0
  67. package/skills/controllerai-agents/references/instructions-and-versioning.md +76 -0
  68. package/skills/controllerai-ai-nodes/SKILL.md +83 -0
  69. package/skills/controllerai-ai-nodes/agents/openai.yaml +4 -0
  70. package/skills/controllerai-ai-nodes/references/selection-and-testing.md +46 -0
  71. package/skills/controllerai-data/SKILL.md +121 -0
  72. package/skills/controllerai-data/agents/openai.yaml +4 -0
  73. package/skills/controllerai-data/references/data-rails.md +46 -0
  74. package/skills/controllerai-expressions/SKILL.md +115 -0
  75. package/skills/controllerai-expressions/agents/openai.yaml +4 -0
  76. package/skills/controllerai-expressions/references/dsl-and-recipes.md +120 -0
  77. package/skills/controllerai-flow-control/SKILL.md +132 -0
  78. package/skills/controllerai-flow-control/agents/openai.yaml +4 -0
  79. package/skills/controllerai-flow-control/references/patterns.md +61 -0
  80. package/skills/controllerai-integration-actions/SKILL.md +95 -0
  81. package/skills/controllerai-integration-actions/agents/openai.yaml +4 -0
  82. package/skills/controllerai-node-config/SKILL.md +138 -0
  83. package/skills/controllerai-node-config/agents/openai.yaml +4 -0
  84. package/skills/controllerai-node-config/references/prop-and-readiness.md +72 -0
  85. package/skills/controllerai-runs/SKILL.md +109 -0
  86. package/skills/controllerai-runs/agents/openai.yaml +4 -0
  87. package/skills/controllerai-runs/references/debugging.md +53 -0
  88. package/skills/controllerai-start/SKILL.md +44 -0
  89. package/skills/controllerai-start/agents/openai.yaml +4 -0
  90. package/skills/controllerai-triggers/SKILL.md +174 -0
  91. package/skills/controllerai-triggers/agents/openai.yaml +4 -0
  92. package/skills/controllerai-triggers/references/lifecycle.md +54 -0
  93. package/skills/controllerai-workflows/SKILL.md +86 -0
  94. package/skills/controllerai-workflows/agents/openai.yaml +4 -0
  95. package/skills/controllerai-workflows/references/command-map.md +64 -0
  96. package/skills/manifest.json +248 -0
package/README.md ADDED
@@ -0,0 +1,180 @@
1
+ # Controller AI CLI
2
+
3
+ Build, test, and operate Controller AI workflows and agents from the coding
4
+ agent you already use.
5
+
6
+ ## Install and connect
7
+
8
+ Node.js 20 or newer is required. Use the durable setup command:
9
+
10
+ ```sh
11
+ npm install -g @controllerai/cli && cai connect
12
+ ```
13
+
14
+ `cai connect` fetches and verifies the current Agent Skills. When the hosted
15
+ source is unavailable, it retains an intact current or newer managed set and
16
+ installs the bundled version only where skills are missing, older, or broken.
17
+ Invalid manifests, incompatible versions, unsafe redirects, and integrity
18
+ failures stop setup instead of silently falling back. It then opens browser
19
+ authorization and verifies the credential and API connection. Its
20
+ final output includes the exact `controllerai-start/SKILL.md` path the
21
+ current coding-agent session should read. Running `npx
22
+ @controllerai/cli connect` is useful for a trial, but it does not guarantee that
23
+ the `cai` binary remains available after that process exits.
24
+
25
+ On a remote or headless machine, run `cai connect --no-open`. Open the printed
26
+ authorization URL in any browser and leave the terminal running until approval
27
+ completes. Linux sessions without a desktop display use this manual path
28
+ automatically.
29
+
30
+ The browser flow stores a revocable `cai_` credential in
31
+ `~/.config/cai/config.json` with owner-only permissions. It receives the full
32
+ CLI capability set displayed on the approval screen; narrower scope selection
33
+ is not available yet. A CLI credential cannot mint a legacy API key.
34
+
35
+ ## Start building
36
+
37
+ For an agent, first decide whether each capability is one ready integration
38
+ action or needs a workflow. A direct action does not require workflow context:
39
+
40
+ ```sh
41
+ cai integration search "send a Slack message"
42
+ cai integration actions <integrationSlug> --search "send message"
43
+ cai connection list --integration <integrationSlug>
44
+ cai connection connect <integrationSlug> --wait
45
+ cai agent create --name "Support agent" --instructions-file instructions.md
46
+ cai agent add-action <agentId> \
47
+ --integration <integrationSlug> \
48
+ --action <actionKey> \
49
+ --connection <connectionId>
50
+ cai agent tools <agentId>
51
+ ```
52
+
53
+ Ready actions run without per-call approval by default. Add
54
+ `--require-confirmation` when the operation sends communications, writes or
55
+ deletes data, changes permissions, or can incur spend. Make this a deliberate
56
+ per-action decision.
57
+
58
+ Use a workflow when the behavior needs multiple steps, transformations,
59
+ branches, loops, triggers, durable data, or a custom typed contract:
60
+
61
+ ```sh
62
+ cai workflow list
63
+ cai workflow create --name "Lead intake"
64
+ cai use <workflowId>
65
+ cai node find "send a Slack message"
66
+ cai node component --node <nodeSlug> --key <nodeKey>
67
+ cai node init --flow <flowId> --key <nodeKey>
68
+ cai node status <nodeId>
69
+ ```
70
+
71
+ For expressions, use the guarded write path. It reads prop metadata, compiles
72
+ against the real node context, lets the backend select the correct storage
73
+ field, and verifies the persisted expression:
74
+
75
+ ```sh
76
+ cai expr context <nodeId> --prop <prop>
77
+ cai expr set <nodeId> --prop <prop> --js '<expression>'
78
+ ```
79
+
80
+ Test before publishing:
81
+
82
+ ```sh
83
+ cai run node <nodeId> --inputs values.json
84
+ cai run flow <flowId> --inputs values.json
85
+ cai workflow publish
86
+ ```
87
+
88
+ Agent Test and Live modes are separate:
89
+
90
+ | | Test / draft | Live / shared |
91
+ | --- | --- | --- |
92
+ | Agent | Current mutable draft; owner only | Latest published immutable version; shared users never see draft |
93
+ | Workflow tools | Current development heads | Each workflow's latest live release |
94
+ | Reference files | Current draft knowledge | Knowledge frozen at agent publish |
95
+ | Runtime files | Live files overlaid by development/test files at the same path | Current live files only |
96
+
97
+ Publishing an agent snapshots its name, instructions, tool identities,
98
+ descriptions and approval policies, and knowledge files, then moves existing
99
+ live conversations to that version. To update those fields in Live: edit the
100
+ draft, verify Test, publish the agent, and verify Live.
101
+
102
+ Workflow releases are not pinned to agent versions. Publishing an attached
103
+ workflow changes every live agent that follows it without another agent publish.
104
+ A direct action's connection and authorization grant are live security bindings:
105
+ rebinding can redirect Live, while breakage, revocation, or detachment can block
106
+ Live immediately without another agent publish. Detachment also changes the
107
+ draft tool list; publish afterward to remove that unavailable tool from the
108
+ published list.
109
+
110
+ Direct actions run inline in the hosted conversation; they do not create
111
+ workflow execution IDs:
112
+
113
+ ```sh
114
+ cai agent create --name "Support agent" --instructions-file instructions.md
115
+ cai agent add-action <agentId> --integration <slug> --action <key> --connection <id>
116
+ # Or, for orchestrated behavior:
117
+ cai agent add-workflow <agentId> --workflow-id <workflowId> --flow <flowId>
118
+ cai agent test <agentId> --draft --message "Handle this sample request"
119
+ cai workflow status
120
+ cai workflow publish --name "Support workflow v1"
121
+ cai agent publish-preflight <agentId>
122
+ cai agent publish <agentId>
123
+ cai agent test <agentId> --live --message "Handle this sample request"
124
+ ```
125
+
126
+ Skip the workflow publish when live already matches the tested development
127
+ state, and skip it entirely for an agent with only direct actions. Publishing a
128
+ workflow already used by another live agent changes that agent immediately.
129
+
130
+ Organization-shared agents run direct actions through the agent owner's
131
+ connected external account. Controller AI usage draws from the organization's
132
+ shared usage pool. The connection is live-bound: rebinding or revoking it can
133
+ immediately affect a published agent, and detaching the grant can block the
134
+ published tool before the agent is republished.
135
+
136
+ Use `cai <command> --help` for the complete command surface and `--json` for a
137
+ stable machine-readable envelope.
138
+
139
+ ## Skill targets
140
+
141
+ `cai skills update` verifies the hosted manifest, file sizes, and SHA-256
142
+ digests before replacing any managed copy. `cai skills status` reports current,
143
+ stale, modified, incomplete, and unmanaged installations. `cai skills install`
144
+ uses the offline copy bundled with the installed CLI.
145
+
146
+ Skill commands auto-detect installed hosts. Explicit targets include
147
+ `agents`, `codex`, `claude`, `cursor`, `copilot`, `all`, and the open-standard
148
+ project location `.agents/skills` via `--target project`. Codex and the generic
149
+ Agent Skills target use `$CODEX_HOME/skills` (default `~/.codex/skills`) and
150
+ `~/.agents/skills`, respectively; Claude uses `~/.claude/skills`.
151
+
152
+ The installer replaces only Controller-AI-managed copies by default. It refuses
153
+ to overwrite an unmanaged folder with the same skill name unless `--force` is
154
+ explicitly supplied. Skill-set versions are immutable: changing source bytes
155
+ requires a version bump, and both the build and runtime installers reject
156
+ different contents that claim an existing version.
157
+
158
+ ## Configuration
159
+
160
+ Environment overrides:
161
+
162
+ - `CAI_API_URL`
163
+ - `CAI_APP_URL`
164
+ - `CAI_TOKEN`
165
+ - `CAI_WORKFLOW`
166
+ - `CAI_CONFIG`
167
+
168
+ `CAI_API_URL`, `CAI_APP_URL`, and `--api-url` are transient process overrides. Authentication,
169
+ workflow creation, and `cai use` do not copy them into the saved config. Pass the
170
+ override again when needed; `cai doctor --api-url <url>` verifies that backend.
171
+
172
+ The CLI derives product links when the API host has the `https://api.<host>`
173
+ shape. For local or custom deployments, set `CAI_APP_URL` or add an `appUrl`
174
+ field to the config file; when no safe app base is known, link fields are omitted.
175
+
176
+ For local manifest integration tests only, `CAI_SKILLS_MANIFEST_URL` can point
177
+ to HTTPS or a loopback HTTP URL. Hosted file URLs must share its origin.
178
+
179
+ Run `cai doctor` to verify Node.js, authentication, API access, installed skills,
180
+ and credential-file permissions.
@@ -0,0 +1,330 @@
1
+ import { CaiError, EXIT, SCRUBBED_HINT, authError, exitCodeForStatus, isScrubbed, networkError, userError, } from '../errors.js';
2
+ const DEFAULT_TIMEOUT = 120_000;
3
+ /**
4
+ * A CLI credential is a bearer secret. Never send it over cleartext to a
5
+ * remote host, or to a URL containing userinfo/query fragments that can make
6
+ * the configured destination misleading. Local HTTP remains available for
7
+ * isolated development stacks.
8
+ */
9
+ export const assertSafeApiUrl = (value) => {
10
+ let url;
11
+ try {
12
+ url = new URL(value);
13
+ }
14
+ catch {
15
+ throw userError(`Invalid Controller API URL: ${value}`, 'BAD_API_URL');
16
+ }
17
+ const localHosts = new Set(['localhost', '127.0.0.1', '[::1]', '::1']);
18
+ const secureTransport = url.protocol === 'https:' || (url.protocol === 'http:' && localHosts.has(url.hostname));
19
+ if (!secureTransport) {
20
+ throw userError('Controller API URLs must use HTTPS; HTTP is allowed only for localhost or loopback.', 'UNSAFE_API_URL');
21
+ }
22
+ if (url.username || url.password || url.search || url.hash) {
23
+ throw userError('Controller API URL must not contain credentials, a query string, or a fragment.', 'UNSAFE_API_URL');
24
+ }
25
+ return value.replace(/\/+$/, '');
26
+ };
27
+ /**
28
+ * Build the auth header. The backend reads ZERO cookies — a login JWT and a raw
29
+ * `sk-…` API key both travel on `Authorization: Bearer`, so there is exactly one
30
+ * shape to get right.
31
+ */
32
+ export const authHeaders = (token) => {
33
+ if (!token)
34
+ return {};
35
+ return { Authorization: `Bearer ${token}` };
36
+ };
37
+ export class ApiClient {
38
+ apiUrl;
39
+ token;
40
+ /** Every MCP tool call made this process, for `--debug`. */
41
+ trace = [];
42
+ constructor(config) {
43
+ this.apiUrl = assertSafeApiUrl(config.apiUrl);
44
+ this.token = config.token;
45
+ }
46
+ get hasToken() {
47
+ return Boolean(this.token);
48
+ }
49
+ requireToken() {
50
+ if (!this.token) {
51
+ throw authError('No credential. Run `cai auth login` or set CAI_TOKEN.', 'NO_TOKEN');
52
+ }
53
+ return this.token;
54
+ }
55
+ /** Raw fetch with timeout, translating transport failures into exit code 4. */
56
+ async raw(path, opts, withAuth) {
57
+ const url = `${this.apiUrl}${path}`;
58
+ const controller = new AbortController();
59
+ const timer = setTimeout(() => controller.abort(), opts.timeoutMs ?? DEFAULT_TIMEOUT);
60
+ try {
61
+ return await fetch(url, {
62
+ method: opts.method ?? 'GET',
63
+ headers: {
64
+ 'Content-Type': 'application/json',
65
+ ...(withAuth ? authHeaders(this.requireToken()) : {}),
66
+ },
67
+ ...(opts.body !== undefined ? { body: JSON.stringify(opts.body) } : {}),
68
+ signal: controller.signal,
69
+ });
70
+ }
71
+ catch (error) {
72
+ if (error instanceof CaiError)
73
+ throw error;
74
+ const reason = error instanceof Error ? error.message : String(error);
75
+ throw networkError(`Cannot reach backend at ${url}: ${reason}`);
76
+ }
77
+ finally {
78
+ clearTimeout(timer);
79
+ }
80
+ }
81
+ /**
82
+ * A plain REST call against the pre-existing surface (workflow CRUD,
83
+ * connections, execution reads). Unwraps the `{statusCode,error,data}`
84
+ * envelope and prints the backend message verbatim on failure.
85
+ */
86
+ async rest(path, opts = {}) {
87
+ const started = Date.now();
88
+ const response = await this.raw(path, opts, !opts.anonymous);
89
+ this.trace.push({
90
+ kind: 'rest',
91
+ target: `${opts.method ?? 'GET'} ${path}`,
92
+ ms: Date.now() - started,
93
+ });
94
+ const text = await response.text();
95
+ let parsed;
96
+ try {
97
+ parsed = text ? JSON.parse(text) : undefined;
98
+ }
99
+ catch {
100
+ // Koa returns bare text for unmatched routes ("Not Found"), not JSON.
101
+ if (!response.ok) {
102
+ throw new CaiError(`${response.status} ${text.trim() || response.statusText}`, {
103
+ exitCode: exitCodeForStatus(response.status),
104
+ code: 'HTTP_ERROR',
105
+ });
106
+ }
107
+ throw new CaiError(`Unparseable response from ${path}: ${text.slice(0, 200)}`, {
108
+ exitCode: EXIT.network,
109
+ code: 'BAD_RESPONSE',
110
+ });
111
+ }
112
+ const backendMessage = parsed?.error?.message ?? '';
113
+ const backendCode = parsed?.error?.code;
114
+ if (!response.ok || parsed?.error) {
115
+ const status = parsed?.statusCode ?? response.status;
116
+ const scrubbed = isScrubbed(status, backendMessage || response.statusText);
117
+ throw new CaiError(backendMessage || `${status} ${response.statusText}`, {
118
+ exitCode: exitCodeForStatus(status, backendCode),
119
+ code: backendCode ?? 'HTTP_ERROR',
120
+ scrubbed,
121
+ detail: scrubbed
122
+ ? { hint: SCRUBBED_HINT, route: `${opts.method ?? 'GET'} ${path}` }
123
+ : undefined,
124
+ });
125
+ }
126
+ return parsed?.data;
127
+ }
128
+ /**
129
+ * Multipart POST. Only the CSV record import needs it, and it cannot reuse
130
+ * `rest()`: that always sets `Content-Type: application/json`, which would
131
+ * suppress the boundary `undici` generates for a FormData body and make the
132
+ * server see an unparseable part.
133
+ */
134
+ async upload(path, form, timeoutMs = DEFAULT_TIMEOUT) {
135
+ const url = `${this.apiUrl}${path}`;
136
+ const controller = new AbortController();
137
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
138
+ const started = Date.now();
139
+ let response;
140
+ try {
141
+ response = await fetch(url, {
142
+ method: 'POST',
143
+ headers: authHeaders(this.requireToken()),
144
+ body: form,
145
+ signal: controller.signal,
146
+ });
147
+ }
148
+ catch (error) {
149
+ if (error instanceof CaiError)
150
+ throw error;
151
+ const reason = error instanceof Error ? error.message : String(error);
152
+ throw networkError(`Cannot reach backend at ${url}: ${reason}`);
153
+ }
154
+ finally {
155
+ clearTimeout(timer);
156
+ }
157
+ this.trace.push({ kind: 'rest', target: `POST ${path}`, ms: Date.now() - started });
158
+ const text = await response.text();
159
+ const parsed = safeJson(text);
160
+ const backendMessage = parsed?.error?.message ?? '';
161
+ if (!response.ok || parsed?.error) {
162
+ const status = parsed?.statusCode ?? response.status;
163
+ const scrubbed = isScrubbed(status, backendMessage || response.statusText);
164
+ throw new CaiError(backendMessage || `${status} ${text.trim() || response.statusText}`, {
165
+ exitCode: exitCodeForStatus(status, parsed?.error?.code),
166
+ code: parsed?.error?.code ?? 'HTTP_ERROR',
167
+ scrubbed,
168
+ detail: scrubbed ? { hint: SCRUBBED_HINT, route: `POST ${path}` } : undefined,
169
+ });
170
+ }
171
+ return parsed?.data;
172
+ }
173
+ /**
174
+ * Call a tool on the persisting builder surface: `POST /agent-mcp/:workflowId`,
175
+ * JSON-RPC 2.0.
176
+ *
177
+ * THIS IS THE ONLY TRANSPORT THAT WRITES. The sibling REST routes under
178
+ * `/workflow-agent/*` compute an operation and broadcast it to a connected
179
+ * builder client over a socket — with no browser attached they can return
180
+ * `{success:true}` without persisting anything.
181
+ */
182
+ async tool(workflowId, name, args = {}) {
183
+ const started = Date.now();
184
+ const response = await this.raw(`/agent-mcp/${workflowId}`, {
185
+ method: 'POST',
186
+ body: { jsonrpc: '2.0', id: 1, method: 'tools/call', params: { name, arguments: args } },
187
+ }, true);
188
+ this.trace.push({ kind: 'mcp', target: name, ms: Date.now() - started });
189
+ const text = await response.text();
190
+ // A rejected token never reaches the JSON-RPC layer: the auth middleware
191
+ // answers with an OAuth-shaped body ({error, error_description}) and a bare
192
+ // 401, so the HTTP status has to be classified before parsing a JSON-RPC
193
+ // envelope that is not there.
194
+ if (!response.ok) {
195
+ const body = safeJson(text);
196
+ // The MCP surface also answers some rejections (unknown workflow, ACL)
197
+ // with a proper JSON-RPC error envelope AND a non-2xx status.
198
+ if (typeof body?.error?.message === 'string') {
199
+ throw toolError(body.error.message, name, body.error.data);
200
+ }
201
+ const message = body?.error_description ?? body?.error ?? text.trim() ?? response.statusText;
202
+ const readable = typeof message === 'string' ? message : JSON.stringify(message);
203
+ const scrubbed = isScrubbed(response.status, readable);
204
+ throw new CaiError(readable || `${response.status} ${response.statusText}`, {
205
+ exitCode: exitCodeForStatus(response.status),
206
+ code: typeof body?.error === 'string' ? body.error : 'HTTP_ERROR',
207
+ scrubbed,
208
+ detail: scrubbed ? { hint: SCRUBBED_HINT, tool: name } : { tool: name },
209
+ });
210
+ }
211
+ let parsed;
212
+ try {
213
+ parsed = JSON.parse(text);
214
+ }
215
+ catch {
216
+ throw new CaiError(`Unparseable MCP response for ${name}: ${text.slice(0, 200)}`, {
217
+ exitCode: EXIT.network,
218
+ code: 'BAD_RESPONSE',
219
+ });
220
+ }
221
+ if (parsed.error) {
222
+ throw toolError(parsed.error.message, name, parsed.error.data);
223
+ }
224
+ const content = parsed.result?.content ?? [];
225
+ const payload = content.map(c => c.text ?? '').join('');
226
+ if (parsed.result?.isError) {
227
+ throw toolError(payload || 'Tool reported an error', name);
228
+ }
229
+ if (!payload)
230
+ return undefined;
231
+ try {
232
+ return JSON.parse(payload);
233
+ }
234
+ catch {
235
+ // Some tools return prose rather than JSON; pass it through as-is.
236
+ return payload;
237
+ }
238
+ }
239
+ /**
240
+ * Graph mutation wrapper. Reads the current dev head, runs the mutation, and
241
+ * on a state conflict retries EXACTLY ONCE before failing loudly.
242
+ *
243
+ * Current backends serialize `latestStateId` with a structured conflict, so
244
+ * that exact head is reused. Older backends are supported by re-fetching it.
245
+ */
246
+ async mutate(workflowId, run) {
247
+ let head = await this.head(workflowId).catch(() => null);
248
+ try {
249
+ return await run(head);
250
+ }
251
+ catch (error) {
252
+ if (!(error instanceof CaiError) || error.exitCode !== EXIT.conflict)
253
+ throw error;
254
+ const latestStateId = conflictLatestStateId(error);
255
+ head =
256
+ latestStateId !== undefined ? latestStateId : await this.head(workflowId).catch(() => null);
257
+ try {
258
+ return await run(head);
259
+ }
260
+ catch (retryError) {
261
+ if (retryError instanceof CaiError && retryError.exitCode === EXIT.conflict) {
262
+ throw new CaiError(`${retryError.message}\nRetried once against head ${head ?? '(unknown)'} and still ` +
263
+ 'conflicted. Another writer is active on this workflow — stop it and retry.', { exitCode: EXIT.conflict, code: 'STATE_CONFLICT' });
264
+ }
265
+ throw retryError;
266
+ }
267
+ }
268
+ }
269
+ /** Current development-version head (workflowVersionState id), or null. */
270
+ async head(workflowId) {
271
+ const state = await this.rest(`/workflow-agent/development-version-state/${workflowId}`);
272
+ return state?.id ?? null;
273
+ }
274
+ }
275
+ const safeJson = (text) => {
276
+ try {
277
+ return JSON.parse(text);
278
+ }
279
+ catch {
280
+ return null;
281
+ }
282
+ };
283
+ const conflictLatestStateId = (error) => {
284
+ if (!error.detail || typeof error.detail !== 'object')
285
+ return undefined;
286
+ const value = error.detail.latestStateId;
287
+ if (value === null)
288
+ return null;
289
+ return typeof value === 'number' && Number.isSafeInteger(value) ? value : undefined;
290
+ };
291
+ /**
292
+ * MCP transport errors arrive as JSON-RPC -32603. Current backends include a
293
+ * structured application code in `error.data`; older ones only provide the
294
+ * thrown message, so text classification remains as a compatibility fallback.
295
+ */
296
+ export const toolError = (message, tool, data) => {
297
+ const text = (message ?? '').trim();
298
+ const errorData = data && typeof data === 'object' ? data : undefined;
299
+ if (errorData?.code === 'STATE_CONFLICT') {
300
+ const value = errorData.latestStateId;
301
+ const latestStateId = value === null || (typeof value === 'number' && Number.isSafeInteger(value))
302
+ ? value
303
+ : undefined;
304
+ return new CaiError(text || 'State conflict', {
305
+ exitCode: EXIT.conflict,
306
+ code: 'STATE_CONFLICT',
307
+ detail: { tool, ...(latestStateId !== undefined ? { latestStateId } : {}) },
308
+ });
309
+ }
310
+ if (/STATE_CONFLICT|state conflict|baseStateId/i.test(text)) {
311
+ return new CaiError(text, { exitCode: EXIT.conflict, code: 'STATE_CONFLICT', detail: { tool } });
312
+ }
313
+ if (/unauthor|forbidden|do not have access|not authenticated/i.test(text)) {
314
+ return new CaiError(text, { exitCode: EXIT.auth, code: 'UNAUTHORIZED', detail: { tool } });
315
+ }
316
+ if (isScrubbed(500, text)) {
317
+ return new CaiError(text, {
318
+ exitCode: EXIT.network,
319
+ code: 'INTERNAL_SERVER_ERROR',
320
+ scrubbed: true,
321
+ detail: { hint: SCRUBBED_HINT, tool },
322
+ });
323
+ }
324
+ return new CaiError(text || `Tool ${tool} failed`, {
325
+ exitCode: EXIT.user,
326
+ code: 'TOOL_ERROR',
327
+ detail: { tool },
328
+ });
329
+ };
330
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,99 @@
1
+ import { loadConfig } from './config.js';
2
+ const normalizedExplicitBase = (value) => {
3
+ const trimmed = value.trim();
4
+ if (!trimmed)
5
+ return null;
6
+ let url;
7
+ try {
8
+ url = new URL(trimmed);
9
+ }
10
+ catch {
11
+ return null;
12
+ }
13
+ if (!['http:', 'https:'].includes(url.protocol))
14
+ return null;
15
+ if (url.username || url.password || url.search || url.hash)
16
+ return null;
17
+ return url.toString().replace(/\/+$/, '');
18
+ };
19
+ /** Resolve the product frontend without inventing a link for unknown API shapes. */
20
+ export const appBaseUrl = (config) => {
21
+ if (process.env.CAI_APP_URL !== undefined) {
22
+ return normalizedExplicitBase(process.env.CAI_APP_URL);
23
+ }
24
+ if (config.appUrl !== undefined) {
25
+ return typeof config.appUrl === 'string' ? normalizedExplicitBase(config.appUrl) : null;
26
+ }
27
+ let apiUrl;
28
+ try {
29
+ apiUrl = new URL(config.apiUrl);
30
+ }
31
+ catch {
32
+ return null;
33
+ }
34
+ if (apiUrl.protocol !== 'https:' ||
35
+ apiUrl.username ||
36
+ apiUrl.password ||
37
+ apiUrl.search ||
38
+ apiUrl.hash ||
39
+ (apiUrl.pathname !== '' && apiUrl.pathname !== '/') ||
40
+ !apiUrl.hostname.startsWith('api.')) {
41
+ return null;
42
+ }
43
+ const hostname = apiUrl.hostname.slice('api.'.length);
44
+ if (!hostname ||
45
+ ['localhost', '127.0.0.1', '[::1]', '::1'].includes(hostname) ||
46
+ hostname.endsWith('.localhost')) {
47
+ return null;
48
+ }
49
+ return `https://${hostname}${apiUrl.port ? `:${apiUrl.port}` : ''}`;
50
+ };
51
+ const resolvedBase = (source) => typeof source === 'string'
52
+ ? normalizedExplicitBase(source)
53
+ : source === null
54
+ ? null
55
+ : appBaseUrl(source);
56
+ const routeUrl = (base, segments) => base === null
57
+ ? null
58
+ : `${base}/${segments.map(segment => encodeURIComponent(String(segment))).join('/')}`;
59
+ export function workflowBuilderUrl(sourceOrWorkflowId, workflowIdOrVersionId, maybeVersionId) {
60
+ const implicitConfig = maybeVersionId === undefined;
61
+ const base = implicitConfig
62
+ ? appBaseUrl(loadConfig())
63
+ : resolvedBase(sourceOrWorkflowId);
64
+ const workflowId = implicitConfig ? sourceOrWorkflowId : workflowIdOrVersionId;
65
+ const versionId = implicitConfig ? workflowIdOrVersionId : maybeVersionId;
66
+ return routeUrl(base, ['workflows', workflowId, 'versions', versionId]);
67
+ }
68
+ export function runUrl(sourceOrWorkflowId, workflowIdOrVersionId, versionIdOrExecutionId, maybeExecutionId) {
69
+ const implicitConfig = maybeExecutionId === undefined;
70
+ const base = implicitConfig
71
+ ? appBaseUrl(loadConfig())
72
+ : resolvedBase(sourceOrWorkflowId);
73
+ const workflowId = implicitConfig ? sourceOrWorkflowId : workflowIdOrVersionId;
74
+ const versionId = implicitConfig ? workflowIdOrVersionId : versionIdOrExecutionId;
75
+ const executionId = implicitConfig ? versionIdOrExecutionId : maybeExecutionId;
76
+ return routeUrl(base, ['workflows', workflowId, 'versions', versionId, 'runs', executionId]);
77
+ }
78
+ export function agentUrl(sourceOrAgentId, maybeAgentId) {
79
+ const implicitConfig = maybeAgentId === undefined;
80
+ const base = implicitConfig
81
+ ? appBaseUrl(loadConfig())
82
+ : resolvedBase(sourceOrAgentId);
83
+ const agentId = implicitConfig ? sourceOrAgentId : maybeAgentId;
84
+ return routeUrl(base, ['agents', agentId]);
85
+ }
86
+ export function conversationUrl(sourceOrAgentId, agentIdOrConversationId, maybeConversationId) {
87
+ const implicitConfig = maybeConversationId === undefined;
88
+ const base = implicitConfig
89
+ ? appBaseUrl(loadConfig())
90
+ : resolvedBase(sourceOrAgentId);
91
+ const agentId = implicitConfig ? sourceOrAgentId : agentIdOrConversationId;
92
+ const conversationId = implicitConfig ? agentIdOrConversationId : maybeConversationId;
93
+ return routeUrl(base, ['agents', agentId, 'conversations', conversationId]);
94
+ }
95
+ export function connectionsUrl(source) {
96
+ const base = source === undefined ? appBaseUrl(loadConfig()) : resolvedBase(source);
97
+ return routeUrl(base, ['connections']);
98
+ }
99
+ //# sourceMappingURL=appLinks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"appLinks.js","sourceRoot":"","sources":["../src/appLinks.ts"],"names":[],"mappings":"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"}