@nyxa/automation 0.1.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 +559 -0
- package/dist/cancellation.d.ts +1 -0
- package/dist/cancellation.js +5 -0
- package/dist/claude-code.d.ts +19 -0
- package/dist/claude-code.js +182 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +487 -0
- package/dist/codex-output.d.ts +6 -0
- package/dist/codex-output.js +167 -0
- package/dist/codex.d.ts +17 -0
- package/dist/codex.js +228 -0
- package/dist/doctor.d.ts +17 -0
- package/dist/doctor.js +138 -0
- package/dist/errors.d.ts +30 -0
- package/dist/errors.js +51 -0
- package/dist/events.d.ts +55 -0
- package/dist/events.js +51 -0
- package/dist/filesystem.d.ts +2 -0
- package/dist/filesystem.js +13 -0
- package/dist/harness-process.d.ts +39 -0
- package/dist/harness-process.js +359 -0
- package/dist/harness-prompt.d.ts +2 -0
- package/dist/harness-prompt.js +14 -0
- package/dist/harness.d.ts +44 -0
- package/dist/harness.js +68 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +9 -0
- package/dist/init.d.ts +1 -0
- package/dist/init.js +305 -0
- package/dist/json.d.ts +4 -0
- package/dist/json.js +1 -0
- package/dist/kimi-code.d.ts +16 -0
- package/dist/kimi-code.js +299 -0
- package/dist/opencode.d.ts +15 -0
- package/dist/opencode.js +164 -0
- package/dist/run-coordination.d.ts +10 -0
- package/dist/run-coordination.js +96 -0
- package/dist/run-journal.d.ts +14 -0
- package/dist/run-journal.js +129 -0
- package/dist/schema.d.ts +167 -0
- package/dist/schema.js +516 -0
- package/dist/standard-input.d.ts +1 -0
- package/dist/standard-input.js +7 -0
- package/dist/type-utils.d.ts +1 -0
- package/dist/type-utils.js +1 -0
- package/dist/workflow.d.ts +160 -0
- package/dist/workflow.js +530 -0
- package/package.json +51 -0
package/README.md
ADDED
|
@@ -0,0 +1,559 @@
|
|
|
1
|
+
# @nyxa/automation
|
|
2
|
+
|
|
3
|
+
Write trusted TypeScript Workflows and execute them explicitly from Node.js or
|
|
4
|
+
the `automation` CLI. Node.js 22 or later is required.
|
|
5
|
+
|
|
6
|
+
## Security and responsibility
|
|
7
|
+
|
|
8
|
+
A Workflow is trusted local code, not a sandboxed configuration file. It runs
|
|
9
|
+
with the permissions of the process that starts Automation and can use the same
|
|
10
|
+
filesystem, environment, and network access as that process. Only execute
|
|
11
|
+
Workflows whose source you trust, and choose each Run's Access Policy
|
|
12
|
+
deliberately.
|
|
13
|
+
|
|
14
|
+
Automation invokes the user's local Codex, Claude Code, Kimi Code, and OpenCode
|
|
15
|
+
CLIs.
|
|
16
|
+
Their authentication, subscriptions, and quotas remain the user's
|
|
17
|
+
responsibility; Automation does not manage provider accounts, credentials,
|
|
18
|
+
billing, or limits.
|
|
19
|
+
|
|
20
|
+
## Install
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
npm install --save-dev @nyxa/automation
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
The package includes its TypeScript runtime loader. A project does not need a
|
|
27
|
+
global TypeScript or `tsx` installation to run a Workflow.
|
|
28
|
+
|
|
29
|
+
## Initialize an existing project
|
|
30
|
+
|
|
31
|
+
Run `init` from a project that already has a `package.json`. It refuses to
|
|
32
|
+
overwrite the requested Workflow and detects npm, pnpm, or Yarn from the
|
|
33
|
+
project lockfile before offering to add Automation as a development dependency:
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
npx @nyxa/automation init workflows/first.ts
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Choose the Harness explicitly for non-interactive use. `--no-install` only
|
|
40
|
+
generates the Workflow; `--yes` accepts installation and, when `--harness` is
|
|
41
|
+
omitted, selects a Harness only if exactly one local Harness is operational.
|
|
42
|
+
|
|
43
|
+
```sh
|
|
44
|
+
npx @nyxa/automation init workflows/codex.ts --harness codex --yes
|
|
45
|
+
npx @nyxa/automation init workflows/claude.ts --harness claude-code --no-install
|
|
46
|
+
npx @nyxa/automation init workflows/kimi.ts --harness kimi-code --no-install
|
|
47
|
+
npx @nyxa/automation init workflows/opencode.ts --harness opencode --no-install
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The generated Workflow imports only the selected Harness, requests a documented
|
|
51
|
+
structured result, and handles a `needs_input` result with ordinary TypeScript
|
|
52
|
+
control flow.
|
|
53
|
+
|
|
54
|
+
## Diagnose the local environment
|
|
55
|
+
|
|
56
|
+
Run `doctor` before a Workflow to check Node.js, the project-local Automation
|
|
57
|
+
package, and the installed Codex, Claude Code, Kimi Code, and OpenCode
|
|
58
|
+
Harnesses:
|
|
59
|
+
|
|
60
|
+
```sh
|
|
61
|
+
npx automation doctor
|
|
62
|
+
npx automation doctor --harness codex
|
|
63
|
+
npx automation doctor --harness claude-code
|
|
64
|
+
npx automation doctor --harness kimi-code
|
|
65
|
+
npx automation doctor --harness opencode
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
The command checks Harness versions and verifies authentication headlessly.
|
|
69
|
+
For Kimi Code it performs the ACP initialization and authentication handshake;
|
|
70
|
+
it never launches `kimi login`. For OpenCode it reads `opencode auth list` and
|
|
71
|
+
considers authentication verified only when the CLI reports a stored credential
|
|
72
|
+
or authentication environment variable. It does not import a Workflow, change
|
|
73
|
+
project files, install software, or start an interactive authentication flow.
|
|
74
|
+
Without a filter, one fully operational Harness is sufficient and missing
|
|
75
|
+
Harnesses are reported as warnings. With `--harness`, the requested Harness
|
|
76
|
+
must be fully operational.
|
|
77
|
+
|
|
78
|
+
## Define a Workflow
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
// workflow.ts
|
|
82
|
+
import { defineWorkflow } from "@nyxa/automation";
|
|
83
|
+
|
|
84
|
+
const workflow = defineWorkflow({
|
|
85
|
+
async run() {
|
|
86
|
+
return { status: "ready", count: 1 };
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
export default workflow;
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Importing this module only creates an inert Workflow Definition. Execution is
|
|
94
|
+
always explicit:
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
import { executeWorkflow } from "@nyxa/automation";
|
|
98
|
+
import workflow from "./workflow.js";
|
|
99
|
+
|
|
100
|
+
const result = await executeWorkflow(workflow);
|
|
101
|
+
// result is inferred as { status: string; count: number }
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Run Codex
|
|
105
|
+
|
|
106
|
+
Use the local Codex CLI as a Harness. Automation requires Codex CLI 0.144.0 or
|
|
107
|
+
later, performs the version preflight once per resolved executable, and keeps
|
|
108
|
+
the user's existing authentication and local configuration.
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
import { codex, defineWorkflow } from "@nyxa/automation";
|
|
112
|
+
|
|
113
|
+
const workflow = defineWorkflow({
|
|
114
|
+
harness: codex(),
|
|
115
|
+
async run(context) {
|
|
116
|
+
return context.run("Inspect this project and summarize its architecture.", {
|
|
117
|
+
access: "read",
|
|
118
|
+
});
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
export default workflow;
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Runs are headless and require an explicit Access Policy. A Run can replace the
|
|
126
|
+
Workflow's default Harness, and Codex-specific options are only passed when
|
|
127
|
+
declared:
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
const reviewHarness = codex({
|
|
131
|
+
executable: "/opt/codex/bin/codex",
|
|
132
|
+
model: "gpt-test",
|
|
133
|
+
effort: "high",
|
|
134
|
+
profile: "ci",
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
const reviewWorkflow = defineWorkflow({
|
|
138
|
+
async run(context) {
|
|
139
|
+
return context.run("Review the proposed change.", {
|
|
140
|
+
access: "read",
|
|
141
|
+
harness: reviewHarness,
|
|
142
|
+
name: "review",
|
|
143
|
+
});
|
|
144
|
+
},
|
|
145
|
+
});
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Run Claude Code
|
|
149
|
+
|
|
150
|
+
Use `claudeCode()` to run the same Workflow contract with the local Claude Code
|
|
151
|
+
CLI. Automation requires Claude Code 2.1.205 or later. Omitting an option keeps
|
|
152
|
+
the corresponding local Harness configuration; Automation does not require a
|
|
153
|
+
model name or reasoning effort.
|
|
154
|
+
|
|
155
|
+
```ts
|
|
156
|
+
import { claudeCode, defineWorkflow } from "@nyxa/automation";
|
|
157
|
+
|
|
158
|
+
const workflow = defineWorkflow({
|
|
159
|
+
harness: claudeCode({
|
|
160
|
+
model: "claude-test",
|
|
161
|
+
effort: "high",
|
|
162
|
+
fallbackModel: "claude-fallback",
|
|
163
|
+
maxTurns: 8,
|
|
164
|
+
maxBudgetUsd: 2,
|
|
165
|
+
}),
|
|
166
|
+
run: (context) =>
|
|
167
|
+
context.run("Inspect this project and summarize its architecture.", {
|
|
168
|
+
access: "read",
|
|
169
|
+
}),
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
export default workflow;
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Run Kimi Code
|
|
176
|
+
|
|
177
|
+
Use `kimiCode()` with Kimi Code CLI 0.28.1 or later. Automation starts the
|
|
178
|
+
official `kimi acp` server over stdio; ACP remains an adapter-private transport,
|
|
179
|
+
so the portable Workflow, Run, Session, event, and error APIs do not expose
|
|
180
|
+
JSON-RPC details. Install and authenticate Kimi Code separately before running
|
|
181
|
+
the Workflow.
|
|
182
|
+
|
|
183
|
+
```ts
|
|
184
|
+
import { defineWorkflow, kimiCode } from "@nyxa/automation";
|
|
185
|
+
|
|
186
|
+
const workflow = defineWorkflow({
|
|
187
|
+
harness: kimiCode({
|
|
188
|
+
executable: "/opt/kimi/bin/kimi",
|
|
189
|
+
model: "kimi-for-coding",
|
|
190
|
+
effort: "high",
|
|
191
|
+
}),
|
|
192
|
+
run: (context) =>
|
|
193
|
+
context.run("Implement the requested change.", {
|
|
194
|
+
access: "full",
|
|
195
|
+
approval: "deny",
|
|
196
|
+
}),
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
export default workflow;
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Kimi model catalogs declare their own effort levels, so `effort` intentionally
|
|
203
|
+
accepts a string and is checked against the options advertised by the selected
|
|
204
|
+
model. An unsupported model or effort fails with
|
|
205
|
+
`HARNESS_CAPABILITY_UNSUPPORTED`.
|
|
206
|
+
|
|
207
|
+
## Run OpenCode
|
|
208
|
+
|
|
209
|
+
Use `opencode()` with OpenCode CLI 1.18.4 or later. Automation invokes
|
|
210
|
+
`opencode run --format json`, keeps the local OpenCode configuration and
|
|
211
|
+
authentication, exposes completed JSONL records as native events, and resumes
|
|
212
|
+
explicit Sessions with the native OpenCode Session identifier.
|
|
213
|
+
|
|
214
|
+
```ts
|
|
215
|
+
import { defineWorkflow, opencode } from "@nyxa/automation";
|
|
216
|
+
|
|
217
|
+
const workflow = defineWorkflow({
|
|
218
|
+
harness: opencode({
|
|
219
|
+
executable: "/opt/opencode/bin/opencode",
|
|
220
|
+
model: "provider/model",
|
|
221
|
+
effort: "high",
|
|
222
|
+
}),
|
|
223
|
+
run: (context) =>
|
|
224
|
+
context.run("Implement the requested change.", {
|
|
225
|
+
access: "full",
|
|
226
|
+
approval: "deny",
|
|
227
|
+
}),
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
export default workflow;
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
OpenCode calls provider-specific reasoning levels “variants”, so Automation
|
|
234
|
+
maps the typed `effort` option to its native `--variant` flag. The adapter does
|
|
235
|
+
not accept arbitrary CLI arguments or override the locally configured default
|
|
236
|
+
agent.
|
|
237
|
+
|
|
238
|
+
All four factories accept an optional executable path, model, and effort. Codex
|
|
239
|
+
also accepts a local profile; Claude Code also accepts a fallback model, maximum
|
|
240
|
+
turn count, and budget in US dollars. A Run can override the Workflow's default
|
|
241
|
+
Harness without changing the portable Run API.
|
|
242
|
+
|
|
243
|
+
## Continue a Session explicitly
|
|
244
|
+
|
|
245
|
+
Create a lazy Session handle when several sequential Runs should share one
|
|
246
|
+
native Codex, Claude Code, Kimi Code, or OpenCode conversation:
|
|
247
|
+
|
|
248
|
+
```ts
|
|
249
|
+
const workflow = defineWorkflow({
|
|
250
|
+
async run(context) {
|
|
251
|
+
const session = context.session({
|
|
252
|
+
harness: codex({ model: "gpt-test", effort: "high" }),
|
|
253
|
+
cwd: "packages/api",
|
|
254
|
+
env: { REVIEW_MODE: "security" },
|
|
255
|
+
name: "authentication-review",
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
await session.run("Inspect the authentication flow.", { access: "read" });
|
|
259
|
+
return session.run("Propose the smallest safe change.", {
|
|
260
|
+
access: "write-workspace",
|
|
261
|
+
approval: "deny",
|
|
262
|
+
});
|
|
263
|
+
},
|
|
264
|
+
});
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
Creating the handle does not inspect or start the Harness. Its Harness
|
|
268
|
+
configuration, `cwd`, environment overlay, and optional observability `name`
|
|
269
|
+
are fixed at creation. Each `session.run()` keeps its own Access Policy,
|
|
270
|
+
Approval Policy, Run name, and Output Contract, and may override or remove
|
|
271
|
+
variables from the Session environment.
|
|
272
|
+
Runs on one handle are sequential: an overlapping call fails immediately with
|
|
273
|
+
`SESSION_BUSY`.
|
|
274
|
+
|
|
275
|
+
After a clean native completion, later Runs resume the same conversation. If a
|
|
276
|
+
process or protocol failure makes continuity uncertain, the handle becomes
|
|
277
|
+
unavailable and later calls fail with `SESSION_UNAVAILABLE`; Automation never
|
|
278
|
+
silently creates a replacement. Ordinary `context.run()` calls and separate
|
|
279
|
+
Workflow executions always start independent Sessions.
|
|
280
|
+
|
|
281
|
+
## Control Run execution
|
|
282
|
+
|
|
283
|
+
Every Run declares an `access` ceiling: `read`, `write-workspace`, or `full`.
|
|
284
|
+
The Approval Policy defaults to `deny`; `approval: "auto"` uses only a native
|
|
285
|
+
automatic mechanism and fails with `HARNESS_CAPABILITY_UNSUPPORTED` when the
|
|
286
|
+
selected Harness cannot provide one. The v1 API has no human approval mode.
|
|
287
|
+
|
|
288
|
+
```ts
|
|
289
|
+
await context.run("Update the package documentation.", {
|
|
290
|
+
access: "write-workspace",
|
|
291
|
+
approval: "deny",
|
|
292
|
+
cwd: "packages/docs",
|
|
293
|
+
env: {
|
|
294
|
+
CI: "1",
|
|
295
|
+
DEBUG: undefined,
|
|
296
|
+
},
|
|
297
|
+
});
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
`cwd` is resolved from the execution's Workspace root and must remain inside
|
|
301
|
+
it, including after symbolic links are resolved. Harness processes inherit the
|
|
302
|
+
host environment; `env` overlays string values and removes variables assigned
|
|
303
|
+
`undefined`.
|
|
304
|
+
|
|
305
|
+
An execution admits up to four concurrent Runs by default. Set another positive
|
|
306
|
+
integer through the library or CLI when the Workflow should use a different
|
|
307
|
+
global limit:
|
|
308
|
+
|
|
309
|
+
```ts
|
|
310
|
+
await executeWorkflow(workflow, { concurrency: 2 });
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
```sh
|
|
314
|
+
npx automation workflow.ts --concurrency 2
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
Several `read` Runs can share a Workspace within that limit. A
|
|
318
|
+
`write-workspace` or `full` Run requires exclusive access and fails immediately
|
|
319
|
+
with `WORKSPACE_CONCURRENCY_CONFLICT` when another Run is already reading or
|
|
320
|
+
writing the same canonical Workspace root. Automation does not queue that
|
|
321
|
+
conflict or create an isolated Workspace. To run writes in parallel, invoke the
|
|
322
|
+
Workflows with explicitly distinct `workspaceRoot` directories.
|
|
323
|
+
|
|
324
|
+
Each Run has a 30-minute timeout by default. Set `timeout` in milliseconds or
|
|
325
|
+
use `false` for an intentionally unbounded Run. Expiration fails the Run with
|
|
326
|
+
`RUN_TIMED_OUT`, terminates the Harness process tree, and makes an explicit
|
|
327
|
+
Session unavailable because its continuity can no longer be proven.
|
|
328
|
+
|
|
329
|
+
```ts
|
|
330
|
+
await context.run("Perform the long-running review.", {
|
|
331
|
+
access: "read",
|
|
332
|
+
timeout: 5 * 60 * 1_000,
|
|
333
|
+
});
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
Pass an `AbortSignal` to cancel a complete Workflow execution. The Workflow
|
|
337
|
+
Context exposes the execution signal so trusted Workflow logic can stop its own
|
|
338
|
+
non-Run work too. Cancellation fails active Runs with `RUN_CANCELLED` and
|
|
339
|
+
releases their concurrency slots and Workspace access.
|
|
340
|
+
|
|
341
|
+
```ts
|
|
342
|
+
const controller = new AbortController();
|
|
343
|
+
const result = executeWorkflow(workflow, { signal: controller.signal });
|
|
344
|
+
|
|
345
|
+
controller.abort();
|
|
346
|
+
await result;
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
In the CLI, the first Ctrl-C requests cancellation and allows up to five
|
|
350
|
+
seconds for cleanup. A second Ctrl-C forces the Harness process tree to stop
|
|
351
|
+
immediately. User-requested cancellation exits with status `130`; human mode
|
|
352
|
+
does not write a Workflow Result, while `--json` keeps `stdout` as Automation
|
|
353
|
+
Events JSONL only.
|
|
354
|
+
|
|
355
|
+
Codex maps the three access levels to its native sandboxes and rejects
|
|
356
|
+
automatic approval because its headless CLI has no non-human equivalent.
|
|
357
|
+
Claude Code maps the same levels to its permission and sandbox mechanisms and
|
|
358
|
+
uses its native `auto` mode when requested.
|
|
359
|
+
|
|
360
|
+
Kimi Code currently exposes no native ceiling that can guarantee `read` or
|
|
361
|
+
`write-workspace`, so its adapter refuses those Access Policies before starting
|
|
362
|
+
ACP. It supports only `full`: `approval: "deny"` selects ACP `default` mode and
|
|
363
|
+
rejects permission requests, while `approval: "auto"` selects ACP `auto` mode.
|
|
364
|
+
Interactive questions are always cancelled because Runs remain headless.
|
|
365
|
+
|
|
366
|
+
OpenCode also exposes no native shell sandbox that can guarantee `read` or
|
|
367
|
+
`write-workspace`, so those policies fail before the CLI is inspected or
|
|
368
|
+
started. It supports only `full`: with `approval: "deny"`, native permission
|
|
369
|
+
requests are rejected; with `approval: "auto"`, Automation passes OpenCode's
|
|
370
|
+
`--auto` flag. OpenCode's explicit local permission denials remain effective.
|
|
371
|
+
|
|
372
|
+
| Harness | `read` | `write-workspace` | `full` / `deny` | `full` / `auto` |
|
|
373
|
+
| --- | --- | --- | --- | --- |
|
|
374
|
+
| Codex | native read-only sandbox | native workspace sandbox | native full access, approvals denied | unsupported |
|
|
375
|
+
| Claude Code | native plan mode | native edit sandbox | native bypass mode | native auto mode |
|
|
376
|
+
| Kimi Code | unsupported | unsupported | ACP `default`, permissions denied | ACP `auto`, questions cancelled |
|
|
377
|
+
| OpenCode | unsupported | unsupported | full local CLI access, permission requests denied | full local CLI access, native `--auto` |
|
|
378
|
+
|
|
379
|
+
Runs never open an interactive input channel. Automation appends a headless
|
|
380
|
+
instruction to every prompt, and the Claude Code adapter disables its native
|
|
381
|
+
`AskUserQuestion` tool. If missing information is an expected outcome, model it
|
|
382
|
+
as a branch of the Output Contract and handle the typed value with ordinary
|
|
383
|
+
TypeScript control flow:
|
|
384
|
+
|
|
385
|
+
```ts
|
|
386
|
+
const outcome = schema.union([
|
|
387
|
+
schema.object({
|
|
388
|
+
status: schema.literal("completed"),
|
|
389
|
+
result: schema.string(),
|
|
390
|
+
}).describe("Use when the task can be completed."),
|
|
391
|
+
schema.object({
|
|
392
|
+
status: schema.literal("needs_input"),
|
|
393
|
+
question: schema.string(),
|
|
394
|
+
choices: schema.array(schema.string()),
|
|
395
|
+
}).describe("Use when required information is missing."),
|
|
396
|
+
]);
|
|
397
|
+
|
|
398
|
+
const result = await context.run("Choose the deployment target.", {
|
|
399
|
+
access: "read",
|
|
400
|
+
output: outcome,
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
if (result.status === "needs_input") {
|
|
404
|
+
return result;
|
|
405
|
+
}
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
`needs_input` is an ordinary valid business result, not a Run Failure or a
|
|
409
|
+
reserved engine status. Codex and Claude Code receive the generated JSON Schema
|
|
410
|
+
through their native structured-output mechanisms. Kimi Code and OpenCode
|
|
411
|
+
receive the schema in the prompt and must return one JSON value without
|
|
412
|
+
surrounding text; their adapters parse it strictly. In every case Automation
|
|
413
|
+
validates the returned value independently before exposing it to the Workflow.
|
|
414
|
+
|
|
415
|
+
## Observe execution
|
|
416
|
+
|
|
417
|
+
`executeWorkflow()` can deliver an ordered stream of correlated Automation
|
|
418
|
+
Events. Every event carries a Workflow identifier, sequence number, and
|
|
419
|
+
timestamp. Run events also carry technical Run and Session identifiers plus an
|
|
420
|
+
optional non-unique `name`.
|
|
421
|
+
|
|
422
|
+
```ts
|
|
423
|
+
const result = await executeWorkflow(workflow, {
|
|
424
|
+
async onEvent(event) {
|
|
425
|
+
await persistEvent(event);
|
|
426
|
+
|
|
427
|
+
if (event.type === "run.failed") {
|
|
428
|
+
console.error(event.error.code, event.runId);
|
|
429
|
+
}
|
|
430
|
+
},
|
|
431
|
+
});
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
Observers are awaited one at a time. If an observer fails, Automation stops all
|
|
435
|
+
active Harness processes and rejects with `EVENT_OBSERVER_FAILED`. Native
|
|
436
|
+
Harness events are available on `run.native` under an explicitly non-portable
|
|
437
|
+
envelope: `event.native` is `{ portable: false, event: unknown }`.
|
|
438
|
+
|
|
439
|
+
Execution failures use `AutomationError` with a stable `code`, the available
|
|
440
|
+
Workflow, Run, and Session identifiers, the Harness name, and an optional
|
|
441
|
+
native `cause`. Use `isAutomationError()` to narrow unknown failures.
|
|
442
|
+
Authentication refusals use `HARNESS_NOT_AUTHENTICATED`, unsupported
|
|
443
|
+
model-effort combinations use `HARNESS_CAPABILITY_UNSUPPORTED`, and a Run
|
|
444
|
+
Journal that cannot be initialized uses `RUN_JOURNAL_UNAVAILABLE`.
|
|
445
|
+
|
|
446
|
+
## Record executions safely
|
|
447
|
+
|
|
448
|
+
Every execution creates a JSONL Run Journal in the user's private state
|
|
449
|
+
directory, outside the Workspace. By default, the journal contains ordered
|
|
450
|
+
Automation Event metadata, identifiers, names, durations, states, and portable
|
|
451
|
+
errors. It omits Workflow Inputs, prompts, Workflow Results, structured Run
|
|
452
|
+
outputs, native events, and environment values.
|
|
453
|
+
|
|
454
|
+
Use `record: "full"` only when sensitive diagnostic content may be persisted:
|
|
455
|
+
|
|
456
|
+
```ts
|
|
457
|
+
await executeWorkflow(workflow, {
|
|
458
|
+
record: "full",
|
|
459
|
+
});
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
Disable the journal with `record: false` or `--no-record`:
|
|
463
|
+
|
|
464
|
+
```ts
|
|
465
|
+
await executeWorkflow(workflow, { record: false });
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
```sh
|
|
469
|
+
npx automation workflow.ts --no-record
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
On Linux, journals use `$XDG_STATE_HOME/automation/run-journals` when that
|
|
473
|
+
variable contains an absolute path, otherwise
|
|
474
|
+
`~/.local/state/automation/run-journals`. Run Journals are diagnostic only:
|
|
475
|
+
Automation never reads them as a cache or checkpoint, and every invocation
|
|
476
|
+
starts the Workflow again from its Workflow Input. If the configured state
|
|
477
|
+
directory resolves inside the Workspace, Automation refuses to create the
|
|
478
|
+
journal; configure a state directory outside the Workspace or disable
|
|
479
|
+
recording for that invocation.
|
|
480
|
+
|
|
481
|
+
## Validate Workflow boundaries
|
|
482
|
+
|
|
483
|
+
Use the built-in portable schema DSL for Workflow Inputs and Results. Schemas
|
|
484
|
+
also validate values directly with `parse()` or `safeParse()`.
|
|
485
|
+
|
|
486
|
+
```ts
|
|
487
|
+
import { defineWorkflow, executeWorkflow, schema } from "@nyxa/automation";
|
|
488
|
+
|
|
489
|
+
const workflow = defineWorkflow({
|
|
490
|
+
input: schema.object({
|
|
491
|
+
name: schema.string().minLength(1).describe("The person to greet"),
|
|
492
|
+
language: schema.enum(["en", "fr"]).optional(),
|
|
493
|
+
}),
|
|
494
|
+
output: schema.object({ message: schema.string() }),
|
|
495
|
+
run({ input }) {
|
|
496
|
+
return { message: `Hello ${input.name}` };
|
|
497
|
+
},
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
const result = await executeWorkflow(workflow, {
|
|
501
|
+
input: { name: "Nyxa", language: "en" },
|
|
502
|
+
});
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
## Run from the CLI
|
|
506
|
+
|
|
507
|
+
The direct and explicit forms are equivalent:
|
|
508
|
+
|
|
509
|
+
```sh
|
|
510
|
+
npx automation workflow.ts
|
|
511
|
+
npx automation run workflow.ts
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
Provide a declared Workflow Input as inline JSON, from a file, or from standard
|
|
515
|
+
input. These sources are mutually exclusive.
|
|
516
|
+
|
|
517
|
+
```sh
|
|
518
|
+
npx automation workflow.ts --input '{"name":"Nyxa"}'
|
|
519
|
+
npx automation workflow.ts --input-file input.json
|
|
520
|
+
printf '%s' '{"name":"Nyxa"}' | npx automation workflow.ts --input -
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
Use `--json` for a JSONL stream containing only Automation Events on `stdout`.
|
|
524
|
+
The terminal `workflow.completed` event carries the Workflow Result.
|
|
525
|
+
|
|
526
|
+
```sh
|
|
527
|
+
npx automation workflow.ts --json
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
Strings are written to `stdout` as-is, other JSON values are serialized, and
|
|
531
|
+
an absent result writes nothing. Diagnostics use `stderr`; argument and module
|
|
532
|
+
loading errors exit with status `2`, while execution failures exit with status
|
|
533
|
+
`1`, successful execution exits with `0`, and cancelled execution exits with
|
|
534
|
+
`130`. Human-mode Run progress is also written to `stderr`, keeping `stdout`
|
|
535
|
+
reserved for the Workflow Result.
|
|
536
|
+
|
|
537
|
+
## v1 scope
|
|
538
|
+
|
|
539
|
+
The v1 package includes the TypeScript library, CLI, schema DSL, and the Codex,
|
|
540
|
+
Claude Code, Kimi Code, and OpenCode Harness Adapters backed by their local
|
|
541
|
+
CLIs. It supports typed Workflow Inputs and Results, Output Contracts, explicit
|
|
542
|
+
Sessions, headless policies, Automation Events, Run Journals, `init`, and
|
|
543
|
+
`doctor`.
|
|
544
|
+
|
|
545
|
+
The following remain outside the v1 contract:
|
|
546
|
+
|
|
547
|
+
- direct provider API calls and model SDKs;
|
|
548
|
+
- a public plugin API for third-party Harness Adapters;
|
|
549
|
+
- interactive questions or human approvals during a Run;
|
|
550
|
+
- built-in retries, backoff, or idempotency guarantees;
|
|
551
|
+
- transparent resume, checkpoints, or cached Run reuse;
|
|
552
|
+
- automatic creation of isolated Workspaces or worktrees;
|
|
553
|
+
- arbitrary native Harness CLI arguments; and
|
|
554
|
+
- automated real-Harness smoke tests requiring installations, accounts, or
|
|
555
|
+
subscriptions.
|
|
556
|
+
|
|
557
|
+
Retries and repeated Runs must be explicit TypeScript control flow. Run
|
|
558
|
+
Journals are diagnostic records only and never enable transparent execution
|
|
559
|
+
resume.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function throwIfAborted(signal: AbortSignal | undefined): void;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type Harness } from "./harness.js";
|
|
2
|
+
import type { NoExtraKeys } from "./type-utils.js";
|
|
3
|
+
export declare const CLAUDE_CODE_HARNESS_PREFLIGHT: {
|
|
4
|
+
readonly harnessName: "Claude Code";
|
|
5
|
+
readonly minimumVersion: readonly [2, 1, 205];
|
|
6
|
+
readonly unsupportedVersionMessage: "Claude Code CLI 2.1.205 or later is required.";
|
|
7
|
+
readonly versionPattern: RegExp;
|
|
8
|
+
};
|
|
9
|
+
export type ClaudeCodeEffort = "low" | "medium" | "high" | "xhigh" | "max" | "ultracode";
|
|
10
|
+
export interface ClaudeCodeOptions {
|
|
11
|
+
readonly executable?: string;
|
|
12
|
+
readonly model?: string;
|
|
13
|
+
readonly effort?: ClaudeCodeEffort;
|
|
14
|
+
readonly fallbackModel?: string;
|
|
15
|
+
readonly maxTurns?: number;
|
|
16
|
+
readonly maxBudgetUsd?: number;
|
|
17
|
+
}
|
|
18
|
+
export declare function claudeCode(): Harness;
|
|
19
|
+
export declare function claudeCode<const TOptions extends ClaudeCodeOptions>(options: TOptions & NoExtraKeys<TOptions, ClaudeCodeOptions>): Harness;
|