acpx 0.6.1 → 0.8.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 (49) hide show
  1. package/README.md +8 -2
  2. package/dist/{cli-Ddxpnz9X.js → cli-BGYGVo3b.js} +35 -10
  3. package/dist/cli-BGYGVo3b.js.map +1 -0
  4. package/dist/cli.d.ts +1 -1
  5. package/dist/cli.d.ts.map +1 -1
  6. package/dist/cli.js +204 -19
  7. package/dist/cli.js.map +1 -1
  8. package/dist/{client-2fTFutRH.d.ts → client-FzXPdgP7.d.ts} +10 -4
  9. package/dist/client-FzXPdgP7.d.ts.map +1 -0
  10. package/dist/{flags-yXzUm7Aq.js → flags-D706STfk.js} +46 -6
  11. package/dist/flags-D706STfk.js.map +1 -0
  12. package/dist/{flows-CDsfbaA2.js → flows-hcjHmU7P.js} +117 -11
  13. package/dist/flows-hcjHmU7P.js.map +1 -0
  14. package/dist/flows.d.ts +19 -3
  15. package/dist/flows.d.ts.map +1 -1
  16. package/dist/flows.js +2 -2
  17. package/dist/{prompt-turn-BY5SwU1F.js → live-checkpoint-B9ctAuqV.js} +1335 -82
  18. package/dist/live-checkpoint-B9ctAuqV.js.map +1 -0
  19. package/dist/output-BL9XRWzS.js +3712 -0
  20. package/dist/output-BL9XRWzS.js.map +1 -0
  21. package/dist/runtime.d.ts +32 -6
  22. package/dist/runtime.d.ts.map +1 -1
  23. package/dist/runtime.js +169 -32
  24. package/dist/runtime.js.map +1 -1
  25. package/dist/{types-CVBeQyi3.d.ts → session-options-BJyG6zEH.d.ts} +56 -3
  26. package/dist/session-options-BJyG6zEH.d.ts.map +1 -0
  27. package/package.json +27 -25
  28. package/skills/acpx/SKILL.md +200 -9
  29. package/dist/cli-Ddxpnz9X.js.map +0 -1
  30. package/dist/client-2fTFutRH.d.ts.map +0 -1
  31. package/dist/flags-yXzUm7Aq.js.map +0 -1
  32. package/dist/flows-CDsfbaA2.js.map +0 -1
  33. package/dist/ipc-BruTG5Fb.js +0 -1241
  34. package/dist/ipc-BruTG5Fb.js.map +0 -1
  35. package/dist/jsonrpc-DSxh2w5R.js +0 -68
  36. package/dist/jsonrpc-DSxh2w5R.js.map +0 -1
  37. package/dist/output-DmHvT8vm.js +0 -807
  38. package/dist/output-DmHvT8vm.js.map +0 -1
  39. package/dist/perf-metrics-C2pXfxvR.js +0 -598
  40. package/dist/perf-metrics-C2pXfxvR.js.map +0 -1
  41. package/dist/prompt-turn-BY5SwU1F.js.map +0 -1
  42. package/dist/render-yqwtaOX4.js +0 -172
  43. package/dist/render-yqwtaOX4.js.map +0 -1
  44. package/dist/rolldown-runtime-CiIaOW0V.js +0 -13
  45. package/dist/session-BwgaPK8-.js +0 -1526
  46. package/dist/session-BwgaPK8-.js.map +0 -1
  47. package/dist/session-options-pCbHn_n7.d.ts +0 -13
  48. package/dist/session-options-pCbHn_n7.d.ts.map +0 -1
  49. package/dist/types-CVBeQyi3.d.ts.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "acpx",
3
- "version": "0.6.1",
3
+ "version": "0.8.0",
4
4
  "description": "Headless CLI client for the Agent Client Protocol (ACP) — talk to coding agents from the command line",
5
5
  "keywords": [
6
6
  "acp",
@@ -36,11 +36,13 @@
36
36
  },
37
37
  "scripts": {
38
38
  "build": "tsdown src/cli.ts src/flows.ts src/runtime.ts --format esm --dts --clean --platform node --target node22 --no-fixedExtension",
39
- "build:test": "node -e \"require('node:fs').rmSync('dist-test',{recursive:true,force:true})\" && tsc -p tsconfig.test.json",
39
+ "build:quiet": "tsdown --logLevel silent src/cli.ts src/flows.ts src/runtime.ts --format esm --dts --clean --platform node --target node22 --no-fixedExtension",
40
+ "build:test": "node -e \"require('node:fs').rmSync('dist-test',{recursive:true,force:true})\" && tsgo -p tsconfig.test.json",
40
41
  "check": "pnpm run format:check && pnpm run typecheck && pnpm run lint && pnpm run build && pnpm run viewer:typecheck && pnpm run viewer:build && pnpm run test:coverage",
41
- "check:docs": "pnpm run format:docs:check && pnpm run lint:docs",
42
+ "check:docs": "pnpm run format:docs:check && pnpm run lint:docs && pnpm run docs:site",
42
43
  "conformance:run": "tsx conformance/runner/run.ts",
43
44
  "dev": "tsx src/cli.ts",
45
+ "docs:site": "node scripts/build-docs-site.mjs",
44
46
  "format": "oxfmt --write",
45
47
  "format:check": "oxfmt --check",
46
48
  "format:diff": "oxfmt --write && git --no-pager diff",
@@ -53,53 +55,53 @@
53
55
  "lint:persisted-key-casing": "tsx scripts/lint-persisted-key-casing.ts",
54
56
  "perf:report": "tsx scripts/perf-report.ts",
55
57
  "precommit": "pnpm exec lint-staged && pnpm run -s build",
56
- "prepack": "pnpm run build",
58
+ "prepack": "tsdown --logLevel silent src/cli.ts src/flows.ts src/runtime.ts --format esm --dts --clean --platform node --target node22 --no-fixedExtension",
57
59
  "prepare": "husky",
58
60
  "test": "pnpm run build:test && node --test dist-test/test/*.test.js",
59
- "test:coverage": "pnpm run build:test && node --experimental-test-coverage --test-coverage-exclude=dist-test/test/**/*.js --test-coverage-lines=83 --test-coverage-branches=76 --test-coverage-functions=86 --test dist-test/test/*.test.js",
61
+ "test:coverage": "pnpm run build:test && node --experimental-test-coverage --test-coverage-exclude=dist-test/test/**/*.js --test-coverage-lines=57 --test-coverage-branches=76 --test-coverage-functions=64 --test dist-test/test/*.test.js",
60
62
  "test:live": "pnpm run build:test && node --test dist-test/test/cursor-live.integration.js",
61
63
  "typecheck": "tsgo --noEmit",
62
- "typecheck:tsc": "tsc --noEmit",
63
- "viewer": "tsx examples/flows/replay-viewer/server.ts start",
64
+ "typecheck:tsc": "tsgo --noEmit",
65
+ "viewer": "tsx examples/flows/replay-viewer/server.ts",
64
66
  "viewer:build": "vite build --config examples/flows/replay-viewer/vite.config.ts",
65
67
  "viewer:dev": "tsx examples/flows/replay-viewer/server.ts start",
66
68
  "viewer:open": "tsx examples/flows/replay-viewer/server.ts start --open",
67
69
  "viewer:preview": "tsx examples/flows/replay-viewer/server.ts start",
68
70
  "viewer:status": "tsx examples/flows/replay-viewer/server.ts status",
69
71
  "viewer:stop": "tsx examples/flows/replay-viewer/server.ts stop",
70
- "viewer:typecheck": "tsc -p examples/flows/replay-viewer/tsconfig.json --noEmit && tsc -p examples/flows/replay-viewer/tsconfig.server.json --noEmit"
72
+ "viewer:typecheck": "tsgo -p examples/flows/replay-viewer/tsconfig.json --noEmit && tsgo -p examples/flows/replay-viewer/tsconfig.server.json --noEmit"
71
73
  },
72
74
  "dependencies": {
73
- "@agentclientprotocol/sdk": "^0.20.0",
75
+ "@agentclientprotocol/sdk": "^0.21.1",
74
76
  "commander": "^14.0.3",
75
77
  "skillflag": "^0.1.4",
76
- "tsx": "^4.21.0",
77
- "zod": "^4.3.6"
78
+ "tsx": "^4.22.0",
79
+ "zod": "^4.4.3"
78
80
  },
79
81
  "devDependencies": {
80
- "@types/node": "^25.6.0",
82
+ "@types/node": "^25.8.0",
81
83
  "@types/react": "^19.2.14",
82
84
  "@types/react-dom": "^19.2.3",
83
85
  "@types/react-test-renderer": "^19.1.0",
84
86
  "@types/ws": "^8.18.1",
85
- "@typescript/native-preview": "7.0.0-dev.20260425.1",
86
- "@vitejs/plugin-react": "^6.0.1",
87
+ "@typescript/native-preview": "7.0.0-dev.20260514.1",
88
+ "@vitejs/plugin-react": "^6.0.2",
87
89
  "@xyflow/react": "^12.10.2",
88
90
  "elkjs": "^0.11.1",
89
91
  "fast-json-patch": "^3.1.1",
90
92
  "husky": "^9.1.7",
91
- "lint-staged": "^16.4.0",
93
+ "lint-staged": "^17.0.4",
92
94
  "markdownlint-cli2": "^0.22.1",
93
- "oxfmt": "^0.46.0",
94
- "oxlint": "^1.61.0",
95
- "oxlint-tsgolint": "^0.22.0",
96
- "react": "^19.2.5",
97
- "react-dom": "^19.2.5",
98
- "react-test-renderer": "^19.2.5",
99
- "tsdown": "^0.21.10",
95
+ "oxfmt": "^0.49.0",
96
+ "oxlint": "^1.64.0",
97
+ "oxlint-tsgolint": "^0.22.1",
98
+ "react": "^19.2.6",
99
+ "react-dom": "^19.2.6",
100
+ "react-test-renderer": "^19.2.6",
101
+ "tsdown": "^0.22.0",
100
102
  "typescript": "^6.0.3",
101
- "vite": "^8.0.10",
102
- "ws": "^8.20.0"
103
+ "vite": "^8.0.13",
104
+ "ws": "^8.20.1"
103
105
  },
104
106
  "lint-staged": {
105
107
  "*.{js,ts}": [
@@ -111,7 +113,7 @@
111
113
  ]
112
114
  },
113
115
  "engines": {
114
- "node": ">=22.12.0"
116
+ "node": ">=22.13.0"
115
117
  },
116
118
  "packageManager": "pnpm@10.33.2"
117
119
  }
@@ -1,13 +1,13 @@
1
1
  ---
2
2
  name: acpx
3
- description: Use acpx as a headless ACP CLI for agent-to-agent communication, including prompt/exec/sessions workflows, session scoping, queueing, permissions, and output formats.
3
+ description: Use acpx as a headless ACP CLI for agent-to-agent communication, including prompt/exec/sessions workflows, session scoping, queueing, permissions, output formats, system-prompt overrides, and multi-agent flows authored with defineFlow/decision/decisionEdge.
4
4
  ---
5
5
 
6
6
  # acpx
7
7
 
8
8
  ## When to use this skill
9
9
 
10
- Use this skill when you need to run coding agents through `acpx`, manage persistent ACP sessions, queue prompts, or consume structured agent output from scripts.
10
+ Use this skill when you need to run coding agents through `acpx`, manage persistent ACP sessions, queue prompts, override the Claude system prompt, prune stale sessions, consume structured agent output from scripts, or compose multi-agent workflows declaratively with `acpx/flows`.
11
11
 
12
12
  ## What acpx is
13
13
 
@@ -18,6 +18,8 @@ Core capabilities:
18
18
  - Persistent multi-turn sessions per repo/cwd
19
19
  - One-shot execution mode (`exec`)
20
20
  - Named parallel sessions (`-s/--session`)
21
+ - Idempotent session creation (`sessions ensure`)
22
+ - Session retention controls (`sessions prune` with age filters and history cleanup)
21
23
  - Queue-aware prompt submission with optional fire-and-forget (`--no-wait`)
22
24
  - Cooperative cancel command (`cancel`) for in-flight turns
23
25
  - Graceful cancellation via ACP `session/cancel` on interrupt
@@ -31,6 +33,10 @@ Core capabilities:
31
33
  - Stable ACP `authenticate` handshake via env/config credentials
32
34
  - Structured streaming output (`text`, `json`, `quiet`) with optional `--suppress-reads`
33
35
  - Built-in agent registry plus raw `--agent` escape hatch
36
+ - Claude system prompt override via `--system-prompt` / `--append-system-prompt`
37
+ - Optional terminal capability disable via `--no-terminal` for review-only flows
38
+ - Tool whitelist (`--allowed-tools`), turn cap (`--max-turns`), retry on transient failures (`--prompt-retries`)
39
+ - Multi-agent flows via `acpx flow run` and the `acpx/flows` authoring API (`defineFlow`, `decision`, `decisionEdge`, `acp`, `action`, `compute`, `checkpoint`)
34
40
 
35
41
  ## Install
36
42
 
@@ -52,8 +58,9 @@ acpx [global_options] cancel [-s <name>]
52
58
  acpx [global_options] set-mode <mode> [-s <name>]
53
59
  acpx [global_options] set <key> <value> [-s <name>]
54
60
  acpx [global_options] status [-s <name>]
55
- acpx [global_options] sessions [list | new [--name <name>] | close [name] | show [name] | history [name] [--limit <count>]]
61
+ acpx [global_options] sessions [list | new [--name <name>] | ensure [--name <name>] | close [name] | show [name] | history [name] [--limit <count>] | prune [--dry-run] [--before <date> | --older-than <days>] [--include-history]]
56
62
  acpx [global_options] config [show | init]
63
+ acpx [global_options] flow run <file> [--input-json '<json>' | --input-file <path>] [--default-agent <name>]
57
64
 
58
65
  acpx [global_options] <agent> [prompt_options] [prompt_text...]
59
66
  acpx [global_options] <agent> prompt [prompt_options] [prompt_text...]
@@ -62,7 +69,7 @@ acpx [global_options] <agent> cancel [-s <name>]
62
69
  acpx [global_options] <agent> set-mode <mode> [-s <name>]
63
70
  acpx [global_options] <agent> set <key> <value> [-s <name>]
64
71
  acpx [global_options] <agent> status [-s <name>]
65
- acpx [global_options] <agent> sessions [list | new [--name <name>] | close [name] | show [name] | history [name] [--limit <count>]]
72
+ acpx [global_options] <agent> sessions [list | new [--name <name>] | ensure [--name <name>] | close [name] | show [name] | history [name] [--limit <count>] | prune [--dry-run] [--before <date> | --older-than <days>] [--include-history]]
66
73
  ```
67
74
 
68
75
  If prompt text is omitted and stdin is piped, `acpx` reads prompt text from stdin.
@@ -166,17 +173,23 @@ acpx sessions
166
173
  acpx sessions list
167
174
  acpx sessions new
168
175
  acpx sessions new --name backend
176
+ acpx sessions ensure
177
+ acpx sessions ensure --name backend
169
178
  acpx sessions close
170
179
  acpx sessions close backend
171
180
  acpx sessions show
172
181
  acpx sessions history --limit 20
182
+ acpx sessions prune --dry-run --older-than 7
183
+ acpx sessions prune --older-than 30 --include-history
173
184
  acpx status
174
185
 
175
186
  acpx codex sessions
176
187
  acpx codex sessions new --name backend
188
+ acpx codex sessions ensure --name backend
177
189
  acpx codex sessions close backend
178
190
  acpx codex sessions show backend
179
191
  acpx codex sessions history backend --limit 20
192
+ acpx codex sessions prune --before 2026-04-01 --include-history
180
193
  acpx codex status
181
194
  ```
182
195
 
@@ -186,10 +199,15 @@ Behavior:
186
199
  - `new` creates a fresh session for the current `(agentCommand, cwd, optional name)` scope
187
200
  - `new --name <name>` targets a named session scope
188
201
  - when `new` replaces an existing open session in that scope, the old one is soft-closed
202
+ - `ensure` returns the nearest matching active session for the scope, or creates one when none is open. Idempotent — safe to call before every prompt in scripts.
189
203
  - `close` targets current cwd default session
190
204
  - `close <name>` targets current cwd named session
191
205
  - `show [name]` prints stored metadata for that scoped session
192
206
  - `history [name]` prints stored turn history previews (default 20, use `--limit`)
207
+ - `prune` deletes closed session records to reclaim disk space
208
+ - `--dry-run` previews what would be deleted without touching disk
209
+ - `--older-than <days>` and `--before <date>` filter by close time, falling back to last-used time when a record was never explicitly closed
210
+ - `--include-history` also removes per-session event stream files (otherwise only the JSON record is removed)
193
211
 
194
212
  ## Global options
195
213
 
@@ -198,15 +216,55 @@ Behavior:
198
216
  - `--approve-all`: auto-approve all permission requests
199
217
  - `--approve-reads`: auto-approve reads/searches, prompt for writes (default mode)
200
218
  - `--deny-all`: deny all permission requests
219
+ - `--non-interactive-permissions <policy>`: when prompting is unavailable, choose `deny` or `fail`
220
+ - `--permission-policy <json-or-file>` / `--policy`: per-tool ACP permission rules (`autoApprove`, `autoDeny`, `escalate`, `defaultAction`)
201
221
  - `--format <fmt>`: output format (`text`, `json`, `quiet`)
222
+ - `--json-strict`: strict JSON mode; requires `--format json` and suppresses non-JSON stderr output
202
223
  - `--suppress-reads`: suppress raw read-file contents while preserving the selected format
203
224
  - `--timeout <seconds>`: max wait time (positive number)
204
225
  - `--ttl <seconds>`: queue owner idle TTL before shutdown (default `300`, `0` disables TTL)
205
226
  - `--model <id>`: request an agent model during session creation; non-Claude agents must advertise ACP models and support `session/set_model`
227
+ - `--system-prompt <text>`: replace the agent system prompt. Forwarded to claude-agent-acp via ACP `_meta.systemPrompt`; persisted in `session_options.system_prompt` so reuse keeps the override. Other agents ignore the field.
228
+ - `--append-system-prompt <text>`: append text to the agent system prompt. Forwarded to claude-agent-acp via ACP `_meta.systemPrompt.append`; same persistence rules as `--system-prompt`.
229
+ - `--allowed-tools <list>`: comma-separated tool whitelist (use `""` for no tools)
230
+ - `--max-turns <count>`: cap session turn count
231
+ - `--prompt-retries <count>`: retry failed prompt turns on transient errors (default `0`)
232
+ - `--no-terminal`: do not advertise the ACP terminal capability — useful for review-only or sandboxed agent invocations
206
233
  - `--verbose`: verbose ACP/debug logs to stderr
207
234
 
208
235
  Permission flags are mutually exclusive.
209
236
 
237
+ ## System prompt override (Claude)
238
+
239
+ `--system-prompt` and `--append-system-prompt` let you specialize a Claude session without leaving lingering one-off state, while still benefiting from persistent session reuse.
240
+
241
+ ```bash
242
+ # Replace the system prompt for a named session, persisted across reuse
243
+ acpx --system-prompt "You are a code reviewer who challenges every implicit assumption." claude -s review
244
+
245
+ # Append a guideline on top of the default system prompt
246
+ acpx --append-system-prompt "Always explain trade-offs before recommending a fix." claude -s impl
247
+ ```
248
+
249
+ The override is forwarded via ACP `_meta.systemPrompt` (or `_meta.systemPrompt.append`) on `session/new` and stored in `session_options.system_prompt`. Subsequent `prompt`/`ensure` calls in the same scope keep the override unless you explicitly create a new session. Non-Claude adapters ignore the field, so the same flag is safe inside cross-agent scripts.
250
+
251
+ ## Sessions cleanup
252
+
253
+ Closed session records accumulate on disk by default. Use `sessions prune` to enforce retention:
254
+
255
+ ```bash
256
+ # Preview what would be deleted (no writes)
257
+ acpx codex sessions prune --dry-run --older-than 7
258
+
259
+ # Remove records closed more than 30 days ago, including their event-stream files
260
+ acpx codex sessions prune --older-than 30 --include-history
261
+
262
+ # Remove everything closed before a date
263
+ acpx codex sessions prune --before 2026-04-01
264
+ ```
265
+
266
+ Without `--include-history`, only the lightweight JSON record is removed; event-stream files are preserved for audit. With it, the per-session event log is also deleted to reclaim disk space.
267
+
210
268
  ## Config files
211
269
 
212
270
  Config files are merged in this order (later wins):
@@ -218,6 +276,7 @@ Supported keys:
218
276
 
219
277
  - `defaultAgent`
220
278
  - `defaultPermissions` (`approve-all`, `approve-reads`, `deny-all`)
279
+ - `nonInteractivePermissions` (`deny`, `fail`)
221
280
  - `ttl` (seconds)
222
281
  - `timeout` (seconds or `null`)
223
282
  - `format` (`text`, `json`, `quiet`)
@@ -244,7 +303,7 @@ Persistence:
244
303
  - Session records are stored in `~/.acpx/sessions/*.json`.
245
304
  - `-s/--session` creates parallel named conversations in the same repo.
246
305
  - Changing `--cwd` changes scope and therefore session lookup.
247
- - closed sessions are retained on disk with `closed: true` and `closedAt`.
306
+ - closed sessions are retained on disk with `closed: true` and `closedAt` until pruned.
248
307
  - auto-resume by scope skips closed sessions.
249
308
 
250
309
  Resume behavior:
@@ -281,6 +340,7 @@ Use `--format <fmt>`:
281
340
  - `json`: NDJSON event stream (good for automation)
282
341
  - `quiet`: final assistant text only
283
342
  - `--suppress-reads`: replace raw read-file contents with `[read output suppressed]` in `text` and `json` output
343
+ - `--json-strict`: pair with `--format json` to suppress non-JSON stderr noise (logs, banners) for downstream consumers
284
344
 
285
345
  Example automation:
286
346
 
@@ -294,9 +354,120 @@ acpx --format json codex exec 'review changed files' \
294
354
  - `--approve-all`: no interactive permission prompts
295
355
  - `--approve-reads` (default): approve reads/searches, prompt for writes
296
356
  - `--deny-all`: deny all permission requests
357
+ - `--non-interactive-permissions <deny|fail>`: chosen behavior when no TTY is available to prompt
358
+ - `--policy <json-or-file>`: match ACP permission requests by tool kind/title; non-interactive escalations add ACP response metadata
297
359
 
298
360
  If every permission request is denied/cancelled and none approved, `acpx` exits with permission-denied status.
299
361
 
362
+ ## Flows (multi-agent workflows)
363
+
364
+ Flows let you declare a multi-agent workflow as a graph of typed nodes connected by edges, executed by the `acpx` runtime. The runtime owns persistence, retries, timeouts, and routing — the flow file declares the shape, not the engine.
365
+
366
+ ### Run a flow
367
+
368
+ ```bash
369
+ acpx flow run ./my-flow.flow.ts --input-file ./flow-input.json
370
+ acpx flow run ./my-flow.flow.ts --input-json '{"task":"FIX: add a regression test"}'
371
+ acpx --approve-all flow run examples/flows/pr-triage/pr-triage.flow.ts \
372
+ --input-json '{"repo":"openclaw/acpx","prNumber":150}'
373
+ acpx flow run ./my-flow.flow.ts --default-agent claude
374
+ ```
375
+
376
+ Run artifacts persist under `~/.acpx/flows/runs/<runId>/`. Default per-step timeout is 15 minutes when `--timeout` is unset; flows that declare permission requirements fail fast before starting.
377
+
378
+ ### Authoring a flow
379
+
380
+ The authoring surface lives in `acpx/flows`. The minimal example:
381
+
382
+ ```ts
383
+ import { acp, decision, decisionEdge, defineFlow, checkpoint, extractJsonObject } from "acpx/flows";
384
+
385
+ const choices = ["bug", "feat", "doc"] as const;
386
+
387
+ export default defineFlow({
388
+ name: "pr-triage",
389
+ startAt: "classify",
390
+ nodes: {
391
+ classify: decision({
392
+ choices,
393
+ question: ({ input }) =>
394
+ `Classify the PR description below. Reply with one of: ${choices.join(", ")}.\n\n${input.description}`,
395
+ }),
396
+ bug_lane: acp({
397
+ prompt: ({ outputs }) =>
398
+ `The PR is a bug. Write a regression test that reproduces it.\n\nDecision context: ${JSON.stringify(outputs.classify)}`,
399
+ parse: (text) => extractJsonObject(text),
400
+ }),
401
+ feat_lane: acp({
402
+ prompt: () => "List acceptance criteria for the feature, one bullet per criterion.",
403
+ }),
404
+ doc_lane: checkpoint({
405
+ summary: "doc change — needs human review",
406
+ run: ({ outputs }) => ({ route: "doc", note: outputs.classify }),
407
+ }),
408
+ },
409
+ edges: [
410
+ decisionEdge({
411
+ from: "classify",
412
+ choices,
413
+ cases: {
414
+ bug: "bug_lane",
415
+ feat: "feat_lane",
416
+ doc: "doc_lane",
417
+ },
418
+ }),
419
+ ],
420
+ });
421
+ ```
422
+
423
+ ### Node types
424
+
425
+ | Type | Purpose |
426
+ | --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
427
+ | `acp({ prompt, parse?, agent?, cwd? })` | Model-driven step. The `prompt` builder receives `{ input, outputs }`. Optional `parse` coerces the raw text (e.g., `extractJsonObject`). |
428
+ | `decision({ choices, question })` | Constrained-choice LLM step. `choices` is a `readonly` tuple; the runtime validates the model's reply against it and TypeScript infers the union from `choices`. |
429
+ | `action(...)` | Runtime-supervised deterministic operation: shell, GitHub API, test execution, comment posting. |
430
+ | `compute(...)` | Pure local data transform: normalization, routing key derivation, signal reduction. |
431
+ | `checkpoint({ summary, run })` | Pause point for human or external trigger. `run` returns the outcome to record while paused. |
432
+
433
+ ### Edge shapes
434
+
435
+ ```ts
436
+ // Linear edge
437
+ { from: "node", to: "next" }
438
+
439
+ // JSONPath switch — non-decision routing
440
+ {
441
+ from: "node",
442
+ switch: {
443
+ on: "$.route",
444
+ cases: { "value-a": "branch_a", "value-b": "branch_b" },
445
+ },
446
+ }
447
+
448
+ // Decision edge — exhaustive at compile time
449
+ decisionEdge({
450
+ from: "classify",
451
+ choices, // same readonly tuple as decision()
452
+ cases: { // every choice must map to a node id
453
+ bug: "bug_lane",
454
+ feat: "feat_lane",
455
+ doc: "doc_lane",
456
+ },
457
+ })
458
+ ```
459
+
460
+ If a `decisionEdge` omits a case from `choices`, the TypeScript compiler refuses to compile — so a flow can't ship with a forgotten branch when new choices are added.
461
+
462
+ ### Why use flows
463
+
464
+ - **Cross-vendor by construction**: classify with `codex`, write code with `claude`, summarize with `gemini` — same flow file, no glue.
465
+ - **Persistence and replay**: every run streams events to disk, replayable via the flow viewer under `~/.acpx/flows/runs/`.
466
+ - **Permission preflight**: flows declaring permission requirements fail before any agent starts, instead of mid-run.
467
+ - **Typed routing**: the LLM is constrained to a literal union, the compiler verifies exhaustivity, the runtime validates the reply.
468
+
469
+ See `examples/flows/` in the repo for working samples (`branch.flow.ts`, `pr-triage/`, `two-turn.flow.ts`, `shell.flow.ts`, `workdir.flow.ts`).
470
+
300
471
  ## Practical workflows
301
472
 
302
473
  Persistent repo assistant:
@@ -313,6 +484,20 @@ acpx codex -s backend 'fix API pagination bug'
313
484
  acpx codex -s docs 'draft changelog entry for release'
314
485
  ```
315
486
 
487
+ Specialized Claude reviewer that survives session reuse:
488
+
489
+ ```bash
490
+ acpx --system-prompt "You are a reviewer who refuses to approve untested changes." claude -s reviewer
491
+ acpx claude -s reviewer 'review the diff in src/auth/'
492
+ ```
493
+
494
+ Idempotent session bootstrap (safe to call before every prompt in scripts):
495
+
496
+ ```bash
497
+ acpx codex sessions ensure -s ci
498
+ acpx codex -s ci 'run the smoke suite and report failures'
499
+ ```
500
+
316
501
  Queue follow-up without waiting:
317
502
 
318
503
  ```bash
@@ -329,7 +514,7 @@ acpx --format quiet exec 'summarize repo purpose in 3 lines'
329
514
  Machine-readable output for orchestration:
330
515
 
331
516
  ```bash
332
- acpx --format json codex 'review current branch changes' > events.ndjson
517
+ acpx --format json --json-strict codex 'review current branch changes' > events.ndjson
333
518
  ```
334
519
 
335
520
  Raw custom adapter command:
@@ -338,11 +523,17 @@ Raw custom adapter command:
338
523
  acpx --agent './bin/custom-acp-server --profile ci' 'run validation checks'
339
524
  ```
340
525
 
341
- Flow run:
526
+ Periodic cleanup:
527
+
528
+ ```bash
529
+ acpx codex sessions prune --dry-run --older-than 14
530
+ acpx codex sessions prune --older-than 30 --include-history
531
+ ```
532
+
533
+ Multi-agent triage flow:
342
534
 
343
535
  ```bash
344
- acpx flow run ./my-flow.ts --input-file ./flow-input.json
345
- acpx flow run examples/flows/branch.flow.ts --input-json '{"task":"FIX: add a regression test"}'
536
+ acpx --approve-all flow run ./pr-triage.flow.ts --input-json '{"prNumber": 842}'
346
537
  ```
347
538
 
348
539
  Repo-scoped review with permissive mode:
@@ -1 +0,0 @@
1
- {"version":3,"file":"cli-Ddxpnz9X.js","names":[],"sources":["../src/flows/cli.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { fileURLToPath, pathToFileURL } from \"node:url\";\nimport { InvalidArgumentError, type Command } from \"commander\";\nimport type { ResolvedAcpxConfig } from \"../cli/config.js\";\nimport {\n hasExplicitPermissionModeFlag,\n resolveAgentInvocation,\n resolveGlobalFlags,\n resolveOutputPolicy,\n resolvePermissionMode,\n type GlobalFlags,\n} from \"../cli/flags.js\";\nimport { type FlowDefinition, FlowRunner } from \"../flows.js\";\nimport { permissionModeSatisfies } from \"../permissions.js\";\nimport type { PermissionMode } from \"../types.js\";\nimport { isDefinedFlow } from \"./authoring.js\";\nimport { validateFlowDefinition } from \"./graph.js\";\n\ntype FlowRunFlags = {\n inputJson?: string;\n inputFile?: string;\n defaultAgent?: string;\n};\n\nconst FLOW_RUNTIME_SPECIFIER = \"acpx/flows\";\nconst TEXT_MODULE_EXTENSIONS = new Set([\".js\", \".mjs\", \".cjs\", \".ts\", \".tsx\", \".mts\", \".cts\"]);\n\nexport async function handleFlowRun(\n flowFile: string,\n flags: FlowRunFlags,\n command: Command,\n config: ResolvedAcpxConfig,\n): Promise<void> {\n const globalFlags = resolveGlobalFlags(command, config);\n const permissionMode = resolvePermissionMode(globalFlags, config.defaultPermissions);\n const outputPolicy = resolveOutputPolicy(globalFlags.format, globalFlags.jsonStrict === true);\n const input = await readFlowInput(flags);\n const flowPath = path.resolve(flowFile);\n const flow = await loadFlowModule(flowPath);\n assertFlowPermissionRequirements(flow, permissionMode, globalFlags);\n\n const runner = new FlowRunner({\n resolveAgent: (profile?: string) => {\n return resolveAgentInvocation(profile ?? flags.defaultAgent, globalFlags, config);\n },\n permissionMode,\n mcpServers: config.mcpServers,\n nonInteractivePermissions: globalFlags.nonInteractivePermissions,\n authCredentials: config.auth,\n authPolicy: globalFlags.authPolicy,\n timeoutMs: globalFlags.timeout,\n ttlMs: globalFlags.ttl,\n verbose: globalFlags.verbose,\n suppressSdkConsoleErrors: outputPolicy.suppressSdkConsoleErrors,\n sessionOptions: {\n model: globalFlags.model,\n allowedTools: globalFlags.allowedTools,\n maxTurns: globalFlags.maxTurns,\n },\n });\n\n const result = await runner.run(flow, input, {\n flowPath,\n });\n\n printFlowRunResult(result, globalFlags);\n}\n\nfunction assertFlowPermissionRequirements(\n flow: FlowDefinition,\n permissionMode: PermissionMode,\n globalFlags: GlobalFlags,\n): void {\n const permissions = flow.permissions;\n if (!permissions) {\n return;\n }\n\n if (permissions.requireExplicitGrant && !hasExplicitPermissionModeFlag(globalFlags)) {\n throw new InvalidArgumentError(\n buildFlowPermissionFailureMessage(flow, permissions.requiredMode, permissions.reason, true),\n );\n }\n\n if (!permissionModeSatisfies(permissionMode, permissions.requiredMode)) {\n throw new InvalidArgumentError(\n buildFlowPermissionFailureMessage(flow, permissions.requiredMode, permissions.reason, false),\n );\n }\n}\n\nfunction buildFlowPermissionFailureMessage(\n flow: FlowDefinition,\n requiredMode: PermissionMode,\n reason?: string,\n explicit = false,\n): string {\n return [\n explicit\n ? `Flow \"${flow.name}\" requires an explicit ${requiredMode} grant.`\n : `Flow \"${flow.name}\" requires permission mode ${requiredMode}.`,\n `Rerun with --${requiredMode}.`,\n ...(reason ? [`Reason: ${reason}`] : []),\n ].join(\" \");\n}\n\nasync function readFlowInput(flags: FlowRunFlags): Promise<unknown> {\n if (flags.inputJson && flags.inputFile) {\n throw new InvalidArgumentError(\"Use only one of --input-json or --input-file\");\n }\n\n if (flags.inputJson) {\n return parseJsonInput(flags.inputJson, \"--input-json\");\n }\n\n if (flags.inputFile) {\n const inputPath = path.resolve(flags.inputFile);\n const payload = await fs.readFile(inputPath, \"utf8\");\n return parseJsonInput(payload, \"--input-file\");\n }\n\n return {};\n}\n\nasync function loadFlowModule(flowPath: string): Promise<FlowDefinition> {\n const extension = path.extname(flowPath).toLowerCase();\n const prepared = await prepareFlowModuleImport(flowPath, extension);\n try {\n const module = await loadFlowRuntimeModule(prepared.flowUrl, extension);\n\n const candidate = findFlowDefinition(module);\n if (!candidate) {\n throw new Error(\n `Flow module must export default defineFlow({...}) from \"acpx/flows\": ${flowPath}`,\n );\n }\n validateFlowDefinition(candidate);\n return candidate;\n } finally {\n await prepared.cleanup?.();\n }\n}\n\nasync function prepareFlowModuleImport(\n flowPath: string,\n extension: string,\n): Promise<{\n flowUrl: string;\n cleanup?: () => Promise<void>;\n}> {\n const flowUrl = pathToFileURL(flowPath).href;\n if (!TEXT_MODULE_EXTENSIONS.has(extension)) {\n return { flowUrl };\n }\n\n const source = await fs.readFile(flowPath, \"utf8\");\n if (!source.includes(FLOW_RUNTIME_SPECIFIER)) {\n return { flowUrl };\n }\n\n const runtimeSpecifier = resolveFlowRuntimeImportSpecifier();\n const rewritten = source.replaceAll(\n /([\"'])acpx\\/flows\\1/g,\n (_match, quote: string) => `${quote}${runtimeSpecifier}${quote}`,\n );\n if (rewritten === source) {\n return { flowUrl };\n }\n\n const tempPath = path.join(path.dirname(flowPath), `.acpx-flow-load-${randomUUID()}${extension}`);\n await fs.writeFile(tempPath, rewritten, \"utf8\");\n return {\n flowUrl: pathToFileURL(tempPath).href,\n cleanup: async () => {\n await fs.rm(tempPath, { force: true });\n },\n };\n}\n\nfunction resolveFlowRuntimeImportSpecifier(): string {\n const selfPath = fileURLToPath(import.meta.url);\n\n if (selfPath.endsWith(`${path.sep}src${path.sep}flows${path.sep}cli.ts`)) {\n return new URL(\"../flows.ts\", import.meta.url).href;\n }\n if (selfPath.endsWith(`${path.sep}src${path.sep}flows${path.sep}cli.js`)) {\n return new URL(\"../flows.js\", import.meta.url).href;\n }\n return new URL(\"./flows.js\", import.meta.url).href;\n}\n\nasync function loadFlowRuntimeModule(\n flowUrl: string,\n extension: string,\n): Promise<{\n default?: unknown;\n \"module.exports\"?: unknown;\n}> {\n if (extension === \".ts\" || extension === \".tsx\" || extension === \".mts\" || extension === \".cts\") {\n const { tsImport } = (await import(\"tsx/esm/api\")) as {\n tsImport: (\n specifier: string,\n parentURL: string,\n ) => Promise<{\n default?: unknown;\n \"module.exports\"?: unknown;\n }>;\n };\n return (await tsImport(flowUrl, import.meta.url)) as {\n default?: unknown;\n \"module.exports\"?: unknown;\n };\n }\n\n return (await import(flowUrl)) as {\n default?: unknown;\n \"module.exports\"?: unknown;\n };\n}\n\nfunction findFlowDefinition(module: {\n default?: unknown;\n \"module.exports\"?: unknown;\n}): FlowDefinition | null {\n const candidates = [\n module.default,\n module[\"module.exports\"],\n getNestedDefault(module.default),\n getNestedDefault(module[\"module.exports\"]),\n ];\n\n for (const candidate of candidates) {\n if (isDefinedFlow(candidate)) {\n return candidate;\n }\n }\n\n return null;\n}\n\nfunction getNestedDefault(value: unknown): unknown {\n if (!value || typeof value !== \"object\" || !(\"default\" in value)) {\n return null;\n }\n return (value as { default?: unknown }).default ?? null;\n}\n\nfunction parseJsonInput(raw: string, label: string): unknown {\n try {\n return JSON.parse(raw);\n } catch (error) {\n throw new InvalidArgumentError(\n `${label} must contain valid JSON: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n}\n\nfunction printFlowRunResult(\n result: Awaited<ReturnType<FlowRunner[\"run\"]>>,\n globalFlags: GlobalFlags,\n): void {\n const payload = {\n action: \"flow_run_result\",\n runId: result.state.runId,\n flowName: result.state.flowName,\n runTitle: result.state.runTitle,\n flowPath: result.state.flowPath,\n status: result.state.status,\n currentNode: result.state.currentNode,\n currentNodeType: result.state.currentNodeType,\n currentNodeStartedAt: result.state.currentNodeStartedAt,\n lastHeartbeatAt: result.state.lastHeartbeatAt,\n statusDetail: result.state.statusDetail,\n waitingOn: result.state.waitingOn,\n runDir: result.runDir,\n outputs: result.state.outputs,\n sessionBindings: result.state.sessionBindings,\n };\n\n if (globalFlags.format === \"json\") {\n process.stdout.write(`${JSON.stringify(payload)}\\n`);\n return;\n }\n\n if (globalFlags.format === \"quiet\") {\n process.stdout.write(`${result.state.runId}\\n`);\n return;\n }\n\n process.stdout.write(`runId: ${payload.runId}\\n`);\n process.stdout.write(`flow: ${payload.flowName}\\n`);\n if (payload.runTitle) {\n process.stdout.write(`title: ${payload.runTitle}\\n`);\n }\n process.stdout.write(`status: ${payload.status}\\n`);\n process.stdout.write(`runDir: ${payload.runDir}\\n`);\n if (payload.currentNode) {\n process.stdout.write(`currentNode: ${payload.currentNode}\\n`);\n }\n if (payload.statusDetail) {\n process.stdout.write(`statusDetail: ${payload.statusDetail}\\n`);\n }\n if (payload.waitingOn) {\n process.stdout.write(`waitingOn: ${payload.waitingOn}\\n`);\n }\n process.stdout.write(`${JSON.stringify(payload.outputs, null, 2)}\\n`);\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"client-2fTFutRH.d.ts","names":[],"sources":["../src/acp/client.ts"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"flags-yXzUm7Aq.js","names":["resolveAgentCommandFromRegistry"],"sources":["../src/cli/flags.ts"],"sourcesContent":["import path from \"node:path\";\nimport { InvalidArgumentError } from \"commander\";\nimport type { Command } from \"commander\";\nimport {\n DEFAULT_AGENT_NAME,\n resolveAgentCommand as resolveAgentCommandFromRegistry,\n} from \"../agent-registry.js\";\nimport type { SystemPromptOption } from \"../runtime/engine/session-options.js\";\nimport { DEFAULT_QUEUE_OWNER_TTL_MS } from \"../session/session.js\";\nimport {\n AUTH_POLICIES,\n NON_INTERACTIVE_PERMISSION_POLICIES,\n OUTPUT_FORMATS,\n type AuthPolicy,\n type NonInteractivePermissionPolicy,\n type OutputFormat,\n type OutputPolicy,\n type PermissionMode,\n} from \"../types.js\";\nimport type { ResolvedAcpxConfig } from \"./config.js\";\n\nexport type PermissionFlags = {\n approveAll?: boolean;\n approveReads?: boolean;\n denyAll?: boolean;\n};\n\nexport function hasExplicitPermissionModeFlag(flags: PermissionFlags): boolean {\n return flags.approveAll === true || flags.approveReads === true || flags.denyAll === true;\n}\n\nexport type GlobalFlags = PermissionFlags & {\n agent?: string;\n cwd: string;\n authPolicy?: AuthPolicy;\n nonInteractivePermissions: NonInteractivePermissionPolicy;\n jsonStrict?: boolean;\n suppressReads?: boolean;\n terminal?: boolean;\n timeout?: number;\n ttl: number;\n verbose?: boolean;\n format: OutputFormat;\n model?: string;\n allowedTools?: string[];\n maxTurns?: number;\n systemPrompt?: SystemPromptOption;\n promptRetries?: number;\n};\n\nexport type PromptFlags = {\n session?: string;\n wait?: boolean;\n file?: string;\n};\n\nexport type ExecFlags = {\n file?: string;\n};\n\nexport type SessionsNewFlags = {\n name?: string;\n resumeSession?: string;\n};\n\nexport type SessionsHistoryFlags = {\n limit: number;\n};\n\nexport type StatusFlags = {\n session?: string;\n};\n\nexport type SessionsPruneFlags = {\n dryRun?: boolean;\n before?: Date;\n olderThan?: number;\n includeHistory?: boolean;\n};\n\nexport function parseOutputFormat(value: string): OutputFormat {\n if (!OUTPUT_FORMATS.includes(value as OutputFormat)) {\n throw new InvalidArgumentError(\n `Invalid format \"${value}\". Expected one of: ${OUTPUT_FORMATS.join(\", \")}`,\n );\n }\n return value as OutputFormat;\n}\n\nexport function parseAuthPolicy(value: string): AuthPolicy {\n if (!AUTH_POLICIES.includes(value as AuthPolicy)) {\n throw new InvalidArgumentError(\n `Invalid auth policy \"${value}\". Expected one of: ${AUTH_POLICIES.join(\", \")}`,\n );\n }\n return value as AuthPolicy;\n}\n\nexport function parseNonInteractivePermissionPolicy(value: string): NonInteractivePermissionPolicy {\n if (!NON_INTERACTIVE_PERMISSION_POLICIES.includes(value as NonInteractivePermissionPolicy)) {\n throw new InvalidArgumentError(\n `Invalid non-interactive permission policy \"${value}\". Expected one of: ${NON_INTERACTIVE_PERMISSION_POLICIES.join(\", \")}`,\n );\n }\n return value as NonInteractivePermissionPolicy;\n}\n\nexport function parseTimeoutSeconds(value: string): number {\n const parsed = Number(value);\n if (!Number.isFinite(parsed) || parsed <= 0) {\n throw new InvalidArgumentError(\"Timeout must be a positive number of seconds\");\n }\n return Math.round(parsed * 1000);\n}\n\nexport function parseTtlSeconds(value: string): number {\n const parsed = Number(value);\n if (!Number.isFinite(parsed) || parsed < 0) {\n throw new InvalidArgumentError(\"TTL must be a non-negative number of seconds\");\n }\n return Math.round(parsed * 1000);\n}\n\nexport function parseSessionName(value: string): string {\n const trimmed = value.trim();\n if (trimmed.length === 0) {\n throw new InvalidArgumentError(\"Session name must not be empty\");\n }\n return trimmed;\n}\n\nexport function parseNonEmptyValue(label: string, value: string): string {\n const trimmed = value.trim();\n if (trimmed.length === 0) {\n throw new InvalidArgumentError(`${label} must not be empty`);\n }\n return trimmed;\n}\n\nexport function parseHistoryLimit(value: string): number {\n const parsed = Number(value);\n if (!Number.isInteger(parsed) || parsed <= 0) {\n throw new InvalidArgumentError(\"Limit must be a positive integer\");\n }\n return parsed;\n}\n\nexport function parseDaysOlderThan(value: string): number {\n const parsed = Number(value);\n if (!Number.isInteger(parsed) || parsed <= 0) {\n throw new InvalidArgumentError(\"--older-than must be a positive integer number of days\");\n }\n return parsed;\n}\n\nexport function parsePruneBeforeDate(value: string): Date {\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) {\n throw new InvalidArgumentError(\n `--before must be a valid date (e.g. 2026-01-01 or 2026-01-01T00:00:00Z)`,\n );\n }\n return date;\n}\n\nexport function parseAllowedTools(value: string): string[] {\n const trimmed = value.trim();\n if (trimmed.length === 0) {\n return [];\n }\n\n const items = trimmed.split(\",\").map((item) => item.trim());\n if (items.some((item) => item.length === 0)) {\n throw new InvalidArgumentError(\n \"Allowed tools must be a comma-separated list without empty entries\",\n );\n }\n\n return items;\n}\n\nexport function parseMaxTurns(value: string): number {\n const parsed = Number(value);\n if (!Number.isInteger(parsed) || parsed <= 0) {\n throw new InvalidArgumentError(\"Max turns must be a positive integer\");\n }\n return parsed;\n}\n\nexport function resolveSystemPromptFlag(opts: {\n systemPrompt?: unknown;\n appendSystemPrompt?: unknown;\n}): SystemPromptOption | undefined {\n const replace =\n typeof opts.systemPrompt === \"string\" && opts.systemPrompt.length > 0\n ? opts.systemPrompt\n : undefined;\n const append =\n typeof opts.appendSystemPrompt === \"string\" && opts.appendSystemPrompt.length > 0\n ? opts.appendSystemPrompt\n : undefined;\n\n if (replace !== undefined && append !== undefined) {\n throw new InvalidArgumentError(\"Use only one of --system-prompt or --append-system-prompt\");\n }\n if (replace !== undefined) {\n return replace;\n }\n if (append !== undefined) {\n return { append };\n }\n return undefined;\n}\n\nexport function parsePromptRetries(value: string): number {\n const parsed = Number(value);\n if (!Number.isInteger(parsed) || parsed < 0) {\n throw new InvalidArgumentError(\"Prompt retries must be a non-negative integer\");\n }\n return parsed;\n}\n\nexport function resolvePermissionMode(\n flags: PermissionFlags,\n defaultMode: PermissionMode,\n): PermissionMode {\n const selected = [flags.approveAll, flags.approveReads, flags.denyAll].filter(Boolean).length;\n\n if (selected > 1) {\n throw new InvalidArgumentError(\n \"Use only one permission mode: --approve-all, --approve-reads, or --deny-all\",\n );\n }\n\n if (flags.approveAll) {\n return \"approve-all\";\n }\n if (flags.approveReads) {\n return \"approve-reads\";\n }\n if (flags.denyAll) {\n return \"deny-all\";\n }\n\n return defaultMode;\n}\n\nexport function addGlobalFlags(command: Command): Command {\n return command\n .option(\"--agent <command>\", \"Raw ACP agent command (escape hatch)\")\n .option(\"--cwd <dir>\", \"Working directory\", process.cwd())\n .option(\n \"--auth-policy <policy>\",\n \"Authentication policy: skip or fail when auth is required\",\n parseAuthPolicy,\n )\n .option(\"--approve-all\", \"Auto-approve all permission requests\")\n .option(\"--approve-reads\", \"Auto-approve read/search requests and prompt for writes\")\n .option(\"--deny-all\", \"Deny all permission requests\")\n .option(\n \"--non-interactive-permissions <policy>\",\n \"When prompting is unavailable: deny or fail\",\n parseNonInteractivePermissionPolicy,\n )\n .option(\"--format <fmt>\", \"Output format: text, json, quiet\", parseOutputFormat)\n .option(\"--suppress-reads\", \"Suppress raw read-file contents in output\")\n .option(\"--model <id>\", \"Agent model id\")\n .option(\n \"--allowed-tools <list>\",\n 'Allowed tool names as a comma-separated list (use \"\" for no tools)',\n parseAllowedTools,\n )\n .option(\"--max-turns <count>\", \"Maximum turns for the session\", parseMaxTurns)\n .option(\n \"--system-prompt <text>\",\n \"Replace the agent system prompt (claude-agent-acp via ACP _meta.systemPrompt)\",\n (value: string) => parseNonEmptyValue(\"System prompt\", value),\n )\n .option(\n \"--append-system-prompt <text>\",\n \"Append text to the agent system prompt (claude-agent-acp via ACP _meta.systemPrompt.append)\",\n (value: string) => parseNonEmptyValue(\"Append system prompt\", value),\n )\n .option(\n \"--prompt-retries <count>\",\n \"Retry failed prompt turns on transient errors (default: 0)\",\n parsePromptRetries,\n )\n .option(\n \"--json-strict\",\n \"Strict JSON mode: requires --format json and suppresses non-JSON stderr output\",\n )\n .option(\"--no-terminal\", \"Do not advertise ACP terminal capability\")\n .option(\"--timeout <seconds>\", \"Maximum time to wait for agent response\", parseTimeoutSeconds)\n .option(\n \"--ttl <seconds>\",\n \"Queue owner idle TTL before shutdown (0 = keep alive forever) (default: 300)\",\n parseTtlSeconds,\n )\n .option(\"--verbose\", \"Enable verbose debug logs\");\n}\n\nexport function addSessionOption(command: Command): Command {\n return command\n .option(\"-s, --session <name>\", \"Use named session instead of cwd default\", parseSessionName)\n .option(\n \"--no-wait\",\n \"Queue prompt and return immediately when another prompt is already running\",\n );\n}\n\nexport function addSessionNameOption(command: Command): Command {\n return command.option(\n \"-s, --session <name>\",\n \"Use named session instead of cwd default\",\n parseSessionName,\n );\n}\n\nexport function resolveSessionNameFromFlags(\n flags: StatusFlags,\n command: Command,\n): string | undefined {\n if (flags.session) {\n return flags.session;\n }\n\n // Commander parses options on the parent command when flags appear before the\n // subcommand (e.g. `acpx codex -s foo cancel`). Use optsWithGlobals() so\n // subcommands can still access those values.\n const allOpts = (command as unknown as { optsWithGlobals?: () => unknown }).optsWithGlobals?.();\n if (allOpts && typeof (allOpts as { session?: unknown }).session === \"string\") {\n return parseSessionName((allOpts as { session: string }).session);\n }\n\n const parentOpts = command.parent?.opts?.();\n if (parentOpts && typeof (parentOpts as { session?: unknown }).session === \"string\") {\n return parseSessionName((parentOpts as { session: string }).session);\n }\n\n return undefined;\n}\n\nexport function addPromptInputOption(command: Command): Command {\n return command.option(\"-f, --file <path>\", \"Read prompt text from file path (use - for stdin)\");\n}\n\nexport function resolveGlobalFlags(command: Command, config: ResolvedAcpxConfig): GlobalFlags {\n const opts = command.optsWithGlobals();\n const format = opts.format ?? config.format ?? \"text\";\n const jsonStrict = opts.jsonStrict === true;\n const verbose = opts.verbose === true;\n\n if (jsonStrict && format !== \"json\") {\n throw new InvalidArgumentError(\"--json-strict requires --format json\");\n }\n\n if (jsonStrict && verbose) {\n throw new InvalidArgumentError(\"--json-strict cannot be combined with --verbose\");\n }\n\n return {\n agent: opts.agent,\n cwd: opts.cwd ?? process.cwd(),\n authPolicy: opts.authPolicy ?? config.authPolicy,\n nonInteractivePermissions: opts.nonInteractivePermissions ?? config.nonInteractivePermissions,\n jsonStrict,\n suppressReads: opts.suppressReads === true,\n terminal: opts.terminal === false ? false : undefined,\n timeout: opts.timeout ?? config.timeoutMs,\n ttl: opts.ttl ?? config.ttlMs ?? DEFAULT_QUEUE_OWNER_TTL_MS,\n verbose,\n format,\n model: typeof opts.model === \"string\" ? parseNonEmptyValue(\"Model\", opts.model) : undefined,\n allowedTools: Array.isArray(opts.allowedTools) ? opts.allowedTools : undefined,\n maxTurns: typeof opts.maxTurns === \"number\" ? opts.maxTurns : undefined,\n systemPrompt: resolveSystemPromptFlag(opts),\n promptRetries: typeof opts.promptRetries === \"number\" ? opts.promptRetries : undefined,\n approveAll: opts.approveAll ? true : undefined,\n approveReads: opts.approveReads ? true : undefined,\n denyAll: opts.denyAll ? true : undefined,\n };\n}\n\nexport function resolveOutputPolicy(format: OutputFormat, jsonStrict: boolean): OutputPolicy {\n return {\n format,\n jsonStrict,\n suppressReads: false,\n suppressNonJsonStderr: jsonStrict,\n queueErrorAlreadyEmitted: format !== \"quiet\",\n suppressSdkConsoleErrors: jsonStrict,\n };\n}\n\nexport function resolveAgentInvocation(\n explicitAgentName: string | undefined,\n globalFlags: GlobalFlags,\n config: ResolvedAcpxConfig,\n): {\n agentName: string;\n agentCommand: string;\n cwd: string;\n} {\n const override = globalFlags.agent?.trim();\n if (override && explicitAgentName) {\n throw new InvalidArgumentError(\"Do not combine positional agent with --agent override\");\n }\n\n const agentName = explicitAgentName ?? config.defaultAgent ?? DEFAULT_AGENT_NAME;\n const agentCommand =\n override && override.length > 0\n ? override\n : resolveAgentCommandFromRegistry(agentName, config.agents);\n\n return {\n agentName,\n agentCommand,\n cwd: path.resolve(globalFlags.cwd),\n };\n}\n"],"mappings":"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"}