@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.
- package/README.md +180 -0
- package/dist/api/client.js +330 -0
- package/dist/api/client.js.map +1 -0
- package/dist/appLinks.js +99 -0
- package/dist/appLinks.js.map +1 -0
- package/dist/argv.js +124 -0
- package/dist/argv.js.map +1 -0
- package/dist/commands/agent.js +813 -0
- package/dist/commands/agent.js.map +1 -0
- package/dist/commands/auth.js +327 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/branch.js +441 -0
- package/dist/commands/branch.js.map +1 -0
- package/dist/commands/connect.js +148 -0
- package/dist/commands/connect.js.map +1 -0
- package/dist/commands/connection.js +148 -0
- package/dist/commands/connection.js.map +1 -0
- package/dist/commands/data.js +441 -0
- package/dist/commands/data.js.map +1 -0
- package/dist/commands/deps.js +63 -0
- package/dist/commands/deps.js.map +1 -0
- package/dist/commands/doctor.js +102 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/events.js +72 -0
- package/dist/commands/events.js.map +1 -0
- package/dist/commands/exec.js +306 -0
- package/dist/commands/exec.js.map +1 -0
- package/dist/commands/expr.js +346 -0
- package/dist/commands/expr.js.map +1 -0
- package/dist/commands/flow.js +447 -0
- package/dist/commands/flow.js.map +1 -0
- package/dist/commands/integration.js +102 -0
- package/dist/commands/integration.js.map +1 -0
- package/dist/commands/node.js +885 -0
- package/dist/commands/node.js.map +1 -0
- package/dist/commands/organize.js +234 -0
- package/dist/commands/organize.js.map +1 -0
- package/dist/commands/run.js +437 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/commands/schema.js +269 -0
- package/dist/commands/schema.js.map +1 -0
- package/dist/commands/skills.js +1156 -0
- package/dist/commands/skills.js.map +1 -0
- package/dist/commands/trigger.js +992 -0
- package/dist/commands/trigger.js.map +1 -0
- package/dist/commands/workflow.js +503 -0
- package/dist/commands/workflow.js.map +1 -0
- package/dist/config.js +74 -0
- package/dist/config.js.map +1 -0
- package/dist/context.js +39 -0
- package/dist/context.js.map +1 -0
- package/dist/errors.js +59 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.js +125 -0
- package/dist/index.js.map +1 -0
- package/dist/jsSource.js +32 -0
- package/dist/jsSource.js.map +1 -0
- package/dist/nodeProps.js +177 -0
- package/dist/nodeProps.js.map +1 -0
- package/dist/output.js +85 -0
- package/dist/output.js.map +1 -0
- package/dist/version.js +7 -0
- package/dist/version.js.map +1 -0
- package/package.json +41 -0
- package/skills/controllerai-agents/SKILL.md +169 -0
- package/skills/controllerai-agents/agents/openai.yaml +4 -0
- package/skills/controllerai-agents/references/instructions-and-versioning.md +76 -0
- package/skills/controllerai-ai-nodes/SKILL.md +83 -0
- package/skills/controllerai-ai-nodes/agents/openai.yaml +4 -0
- package/skills/controllerai-ai-nodes/references/selection-and-testing.md +46 -0
- package/skills/controllerai-data/SKILL.md +121 -0
- package/skills/controllerai-data/agents/openai.yaml +4 -0
- package/skills/controllerai-data/references/data-rails.md +46 -0
- package/skills/controllerai-expressions/SKILL.md +115 -0
- package/skills/controllerai-expressions/agents/openai.yaml +4 -0
- package/skills/controllerai-expressions/references/dsl-and-recipes.md +120 -0
- package/skills/controllerai-flow-control/SKILL.md +132 -0
- package/skills/controllerai-flow-control/agents/openai.yaml +4 -0
- package/skills/controllerai-flow-control/references/patterns.md +61 -0
- package/skills/controllerai-integration-actions/SKILL.md +95 -0
- package/skills/controllerai-integration-actions/agents/openai.yaml +4 -0
- package/skills/controllerai-node-config/SKILL.md +138 -0
- package/skills/controllerai-node-config/agents/openai.yaml +4 -0
- package/skills/controllerai-node-config/references/prop-and-readiness.md +72 -0
- package/skills/controllerai-runs/SKILL.md +109 -0
- package/skills/controllerai-runs/agents/openai.yaml +4 -0
- package/skills/controllerai-runs/references/debugging.md +53 -0
- package/skills/controllerai-start/SKILL.md +44 -0
- package/skills/controllerai-start/agents/openai.yaml +4 -0
- package/skills/controllerai-triggers/SKILL.md +174 -0
- package/skills/controllerai-triggers/agents/openai.yaml +4 -0
- package/skills/controllerai-triggers/references/lifecycle.md +54 -0
- package/skills/controllerai-workflows/SKILL.md +86 -0
- package/skills/controllerai-workflows/agents/openai.yaml +4 -0
- package/skills/controllerai-workflows/references/command-map.md +64 -0
- 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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"}
|
package/dist/appLinks.js
ADDED
|
@@ -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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"}
|