@agent-compose/sdk 0.8.4 → 0.8.6
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 +213 -189
- package/dist/agent/agent-context.d.ts +9 -1
- package/dist/agent/agent-loop.d.ts +14 -6
- package/dist/agent/perf-sampler.d.ts +27 -2
- package/dist/agent/run-agent.d.ts +1 -1
- package/dist/client.d.ts +250 -59
- package/dist/directives.d.ts +14 -0
- package/dist/display.d.ts +7 -0
- package/dist/errors.d.ts +1 -1
- package/dist/generated/agentc-commands.d.ts +34 -0
- package/dist/index.d.ts +13 -11
- package/dist/index.js +1692 -194
- package/dist/request-context/request-context.d.ts +1 -1
- package/dist/runtimes/_cli-agent.d.ts +278 -58
- package/dist/runtimes/claude-code.d.ts +90 -1
- package/dist/runtimes/claude.d.ts +1 -1
- package/dist/runtimes/codex.d.ts +94 -6
- package/dist/runtimes/codex.mid-turn-hook.test.d.ts +10 -0
- package/dist/runtimes/openai-desktop.d.ts +50 -0
- package/dist/runtimes/openai-desktop.js +1689 -211
- package/dist/runtimes/openai-desktop.test.d.ts +20 -0
- package/dist/runtimes/opencode.d.ts +48 -11
- package/dist/runtimes/opencode.test.d.ts +14 -0
- package/dist/runtimes/tool-pulse.test.d.ts +17 -0
- package/dist/sandbox/baked-clis.d.ts +75 -0
- package/dist/sandbox/devbox.d.ts +5 -5
- package/dist/sandbox/exec-stream.d.ts +1 -2
- package/dist/sandbox/network-policy.d.ts +23 -5
- package/dist/sandbox/registry.d.ts +12 -0
- package/dist/sandbox/sizes.d.ts +11 -5
- package/dist/sandbox.d.ts +5 -3
- package/dist/step-invocation/protocol.d.ts +3 -4
- package/dist/step-invocation/server.d.ts +2 -2
- package/dist/step-invocation/types.d.ts +2 -2
- package/dist/types/api-conversations.d.ts +513 -27
- package/dist/types/api-factory.d.ts +183 -3
- package/dist/types/api-projects.d.ts +480 -0
- package/dist/types/api-runs.d.ts +8 -0
- package/dist/types/api-scopes.d.ts +32 -3
- package/dist/types/conversation-stream.d.ts +27 -1
- package/dist/types/execution-context.d.ts +1 -1
- package/dist/types/protocol.d.ts +182 -2
- package/dist/types/runtime.d.ts +80 -2
- package/dist/types/workflow-metadata.d.ts +2 -4
- package/dist/types/workflow-plan.d.ts +1 -3
- package/dist/utils/bundler.d.ts +23 -0
- package/dist/workflow-steps/observability.d.ts +2 -3
- package/dist/workflow-steps/runner.d.ts +5 -8
- package/dist/workflow-steps/types.d.ts +8 -10
- package/dist/workflow-steps/workflow.d.ts +2 -1
- package/dist/workflows/engine.d.ts +3 -5
- package/dist/workflows/invoke-child.d.ts +2 -2
- package/package.json +2 -2
- package/src/agent/agent-context.ts +193 -116
- package/src/agent/agent-loop.ts +16 -9
- package/src/agent/desktop-open.ts +13 -1
- package/src/agent/perf-sampler.ts +54 -3
- package/src/agent/run-agent.ts +1 -1
- package/src/client.ts +418 -80
- package/src/directives.ts +21 -1
- package/src/display.ts +12 -0
- package/src/errors.ts +1 -0
- package/src/generated/agentc-commands.ts +571 -0
- package/src/index.ts +65 -18
- package/src/pause/pause-core.ts +2 -1
- package/src/request-context/request-context.ts +1 -1
- package/src/runtimes/_cli-agent.ts +607 -132
- package/src/runtimes/claude-code.ts +427 -20
- package/src/runtimes/claude.ts +1 -1
- package/src/runtimes/codex.ts +188 -19
- package/src/runtimes/openai-desktop.ts +82 -19
- package/src/runtimes/opencode.ts +195 -26
- package/src/sandbox/baked-clis.ts +86 -0
- package/src/sandbox/devbox.ts +5 -5
- package/src/sandbox/exec-stream.ts +1 -2
- package/src/sandbox/network-policy.ts +51 -7
- package/src/sandbox/providers/e2b.ts +63 -19
- package/src/sandbox/providers/vercel.ts +6 -6
- package/src/sandbox/registry.ts +19 -1
- package/src/sandbox/sizes.ts +11 -5
- package/src/sandbox.ts +9 -2
- package/src/step-invocation/invoker.ts +2 -6
- package/src/step-invocation/protocol.ts +3 -4
- package/src/step-invocation/server.ts +2 -2
- package/src/types/api-conversations.ts +424 -29
- package/src/types/api-factory.ts +189 -3
- package/src/types/api-projects.ts +443 -0
- package/src/types/api-runs.ts +5 -0
- package/src/types/api-scopes.ts +32 -3
- package/src/types/conversation-stream.ts +29 -1
- package/src/types/execution-context.ts +1 -1
- package/src/types/protocol.ts +180 -2
- package/src/types/runtime.ts +71 -2
- package/src/types/sandbox-environment.ts +1 -2
- package/src/types/workflow-metadata.ts +2 -4
- package/src/types/workflow-plan.ts +1 -3
- package/src/utils/bundler.ts +88 -19
- package/src/workflow-steps/observability.ts +2 -3
- package/src/workflow-steps/runner.ts +5 -8
- package/src/workflow-steps/types.ts +8 -10
- package/src/workflow-steps/workflow.ts +2 -1
- package/src/workflows/engine.ts +3 -5
- package/src/workflows/invoke-child.ts +2 -2
- package/dist/pause/__tests__/errors.test.d.ts +0 -1
- package/dist/pause/__tests__/wrappers.test.d.ts +0 -1
- package/dist/step-invocation/__tests__/protocol.test.d.ts +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* RequestContext — one typed bag carrying tenant identity + freeform
|
|
3
3
|
* per-run state across the boundary between server, dispatch, runner,
|
|
4
|
-
* workflow body, agent loop, and
|
|
4
|
+
* workflow body, agent loop, and processors.
|
|
5
5
|
*
|
|
6
6
|
* Two halves:
|
|
7
7
|
*
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* contract.
|
|
5
5
|
*
|
|
6
6
|
* This is a different *mechanism* from the other runtimes: `claudeRuntime`
|
|
7
|
-
* drives the Anthropic Agent SDK and `
|
|
7
|
+
* drives the Anthropic Agent SDK and `createVercelRuntime` drives the Vercel AI SDK,
|
|
8
8
|
* but a CLI-agent runtime spawns the provider's own CLI (`codex exec --json`,
|
|
9
9
|
* `amp -x --stream-json`) — the CLI brings its own agent loop + tools, and we
|
|
10
10
|
* only stream-parse the events it prints. Codex and Amp are the first two; this
|
|
@@ -60,6 +60,29 @@ export declare function runnerBusySentinelFragment(busyPath: string, tasksPath:
|
|
|
60
60
|
* `date +%s%3N` in the same exec, so host clock skew is irrelevant) is
|
|
61
61
|
* stale: three missed writes. */
|
|
62
62
|
export declare const RUNNER_HEARTBEAT_STALE_MS: number;
|
|
63
|
+
/** The sh fragment the heartbeat subshell runs each beat to rewrite the
|
|
64
|
+
* pulse file: `<guest epoch ms>,<cpu jiffies>,<written bytes>,<procs>`
|
|
65
|
+
* for every process in the runner's own session (the setsid tree — the
|
|
66
|
+
* CLI, its foreground tool, their children). Comma-separated so the
|
|
67
|
+
* probe can carry it as ONE whitespace-delimited field. Exported for
|
|
68
|
+
* tests. */
|
|
69
|
+
export declare function toolPulseFragment(pulsePath: string): string;
|
|
70
|
+
/** One tool-run pulse sample, parsed off the probe's trailing field. */
|
|
71
|
+
export interface TurnToolPulse {
|
|
72
|
+
/** Guest epoch ms when the sample was written. */
|
|
73
|
+
atMs: number;
|
|
74
|
+
/** Aggregate utime+stime jiffies across the runner's session. */
|
|
75
|
+
cpuJiffies: number;
|
|
76
|
+
/** Aggregate written bytes (wchar) across the runner's session. */
|
|
77
|
+
ioBytes: number;
|
|
78
|
+
/** Live processes in the session. */
|
|
79
|
+
procs: number;
|
|
80
|
+
}
|
|
81
|
+
/** Parse the pulse token (`at,cpu,io,procs`). Null on anything malformed —
|
|
82
|
+
* evidence-absent, never an error. Exported for tests. */
|
|
83
|
+
export declare function parseToolPulseToken(token: string): TurnToolPulse | null;
|
|
84
|
+
/** Bound on the pulse token read (4 numeric fields + commas). */
|
|
85
|
+
export declare const TOOL_PULSE_TOKEN_MAX_CHARS = 96;
|
|
63
86
|
/** Watchdog cadence while a tail stream is attached. Each tick is one fresh
|
|
64
87
|
* short exec; a healthy stream makes every tick a no-op. */
|
|
65
88
|
export declare const TAIL_WATCHDOG_INTERVAL_MS = 15000;
|
|
@@ -75,12 +98,42 @@ export declare const TAIL_ABANDON_AFTER_STREAM_DEATHS = 3;
|
|
|
75
98
|
* (envd HTTP, ~65ms RTT), consumed from the byte offset. Latency-tuned:
|
|
76
99
|
* this is the degraded path, correctness never depends on it being fast. */
|
|
77
100
|
export declare const DURABLE_POLL_INTERVAL_MS = 1000;
|
|
78
|
-
/**
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
*
|
|
82
|
-
|
|
83
|
-
|
|
101
|
+
/** Consecutive provider-attested "sandbox gone" probe failures ⇒ dead. */
|
|
102
|
+
export declare const PROBE_DEATH_GONE_STREAK = 3;
|
|
103
|
+
/** Not-found evidence must also persist this long (guards a momentary
|
|
104
|
+
* control-plane 404 blip from killing a live turn). */
|
|
105
|
+
export declare const PROBE_DEATH_GONE_WINDOW_MS = 15000;
|
|
106
|
+
/** Consecutive GENERIC probe-transport failures (timeouts, connection
|
|
107
|
+
* faults) ⇒ dead — only together with the window below. */
|
|
108
|
+
export declare const PROBE_DEATH_FAIL_STREAK = 20;
|
|
109
|
+
/** …and the failure run must span at least this long with zero durable
|
|
110
|
+
* evidence of any kind. */
|
|
111
|
+
export declare const PROBE_DEATH_FAIL_WINDOW_MS = 120000;
|
|
112
|
+
/** Provider evidence that the SANDBOX itself is gone — E2B's
|
|
113
|
+
* SandboxNotFoundError / NotFoundError classes (matched by name so no
|
|
114
|
+
* provider import rides in the runtime layer), or their messages after any
|
|
115
|
+
* wrapping ("Paused sandbox X not found" was run 3's exact shape). */
|
|
116
|
+
export declare function isSandboxGoneError(err: unknown): boolean;
|
|
117
|
+
/** One probe-failure run's bookkeeping (reset to zeros on ANY evidence). */
|
|
118
|
+
export interface ProbeDeathState {
|
|
119
|
+
/** Consecutive probe execs that THREW (no verdict at all). */
|
|
120
|
+
failStreak: number;
|
|
121
|
+
/** Consecutive throws that were provider "sandbox gone" evidence. */
|
|
122
|
+
goneStreak: number;
|
|
123
|
+
/** Wall-clock start of the current failure run (0 = no run). */
|
|
124
|
+
firstFailAtMs: number;
|
|
125
|
+
}
|
|
126
|
+
/** The death-door decision, pure for tests. Null = keep polling. */
|
|
127
|
+
export declare function probeDeathVerdict(s: ProbeDeathState, nowMs: number): "dead-gone" | "dead-silent" | null;
|
|
128
|
+
/** The CLI's stderr complaint when the thread it was told to resume does
|
|
129
|
+
* not exist on this machine: claude's `--resume <id>` "No conversation
|
|
130
|
+
* found with session ID" (the 2026-08-18 split-brain forensic) and
|
|
131
|
+
* opencode's `--session <id>` "Error: Session not found" (in the CLI's
|
|
132
|
+
* red-bold ANSI dressing; 1.18.34). When a nonzero exit's stderr carries
|
|
133
|
+
* it, the transport surfaces the stderr as the turn's LAST error event
|
|
134
|
+
* even though a bare result error already streamed — the consumer's
|
|
135
|
+
* classifier needs the specific complaint, not the generic
|
|
136
|
+
* `error_during_execution` token. */
|
|
84
137
|
export declare const RESUME_TARGET_MISSING_STDERR: RegExp;
|
|
85
138
|
/** One durable-trio reading, parsed from the probe exec's single line. */
|
|
86
139
|
export interface TurnProbeReading {
|
|
@@ -99,6 +152,10 @@ export interface TurnProbeReading {
|
|
|
99
152
|
* sample yet, or a garbled token — evidence-absent, never an error.
|
|
100
153
|
* Telemetry-only: no liveness verdict may ever read it. */
|
|
101
154
|
perf?: GuestPerfSample;
|
|
155
|
+
/** Latest tool-run pulse (the `.pulse` token field, 2026-08-29), when the
|
|
156
|
+
* guest wrote one AND it parsed clean. Telemetry-only, same rule as
|
|
157
|
+
* `perf`: no liveness verdict may ever read it. */
|
|
158
|
+
pulse?: TurnToolPulse;
|
|
102
159
|
}
|
|
103
160
|
/** The probe exec: one line, six fields, always exit 0 — faults surface as
|
|
104
161
|
* parse failures, not exec failures. Reads the guest's own clock in the
|
|
@@ -112,6 +169,7 @@ export declare function turnLivenessProbeCommand(paths: {
|
|
|
112
169
|
perfPath: string;
|
|
113
170
|
pid: number;
|
|
114
171
|
sentinel: string;
|
|
172
|
+
pulsePath?: string;
|
|
115
173
|
}): string;
|
|
116
174
|
/** Parse the probe's line. Null = unusable output (a wedged or faulted exec)
|
|
117
175
|
* — the caller treats that as "probe-failed", never as a verdict. The
|
|
@@ -138,10 +196,31 @@ export declare const INJECT_FEEDER_RESULT_TAIL_BYTES = 262144;
|
|
|
138
196
|
export declare const INJECT_ACK_POLL_ATTEMPTS = 30;
|
|
139
197
|
export declare const INJECT_ACK_POLL_SECONDS = "0.5";
|
|
140
198
|
export declare const INJECT_ACK_EXEC_TIMEOUT_MS = 25000;
|
|
199
|
+
/** How the guest recognises the CLI's terminal `result` event in the durable
|
|
200
|
+
* .out: a line that carries the `"type":"result"` pair and does not open
|
|
201
|
+
* with another event's type, as an awk condition over `$0` (POSIX awk, so
|
|
202
|
+
* dash, busybox and the macOS test hosts read it alike). The CLI does not
|
|
203
|
+
* keep its key order: 2.1.212 wrote `{"type":"result",…` but 2.1.278 and
|
|
204
|
+
* later write the pair near the END of the object
|
|
205
|
+
* (`{"duration_api_ms":…,"result":"…","type":"result","duration_ms":…}`), so
|
|
206
|
+
* the anchored prefix the resident contract used matched nothing on the
|
|
207
|
+
* pinned 2.1.283. Every other event the CLI writes opens with its own type
|
|
208
|
+
* (`{"type":"assistant",…`, `{"type":"stream_event",…`), which keeps a tool
|
|
209
|
+
* call whose input holds the same pair from counting; tool output and model
|
|
210
|
+
* text ride inside JSON strings, where the quotes are escaped. */
|
|
211
|
+
export declare const CLI_RESULT_LINE_AWK: string;
|
|
141
212
|
/** The in-guest feeder fragment, prepended to the detached wrapper script.
|
|
142
213
|
* Runs inside the setsid session (group-kill reaps it) and keys its loop to
|
|
143
214
|
* the wrapper's own pid (`$$`), like the heartbeat subshell. Exported for
|
|
144
|
-
* tests.
|
|
215
|
+
* tests.
|
|
216
|
+
*
|
|
217
|
+
* The forward is GUARDED: the fed and delivered counters advance only
|
|
218
|
+
* when `sed` wrote the lines. The loop keys on the wrapper, which outlives
|
|
219
|
+
* a CLI that died without a result line by the sentinel write and the
|
|
220
|
+
* exit push; in that window the FIFO has no reader, `sed` dies of SIGPIPE,
|
|
221
|
+
* and an unguarded counter still advanced, so the ack exited 0 for a line
|
|
222
|
+
* nobody could read and the settle sealed it (review C1). Guarded, the ack
|
|
223
|
+
* sees no advance and exits 4 or 5, and the message stays owed. */
|
|
145
224
|
export declare function streamInputFeederFragment(paths: {
|
|
146
225
|
promptPath: string;
|
|
147
226
|
fifoPath: string;
|
|
@@ -160,13 +239,25 @@ export declare function streamInputFeederFragment(paths: {
|
|
|
160
239
|
* activity) MUST wrap through here — the wrapper rides only the wire to
|
|
161
240
|
* the model; the stored conversation row keeps the user's raw text.
|
|
162
241
|
* The text is pinned by tests: change it deliberately or not at all. */
|
|
163
|
-
export declare function wrapMidTurnUserMessage(text: string): string;
|
|
242
|
+
export declare function wrapMidTurnUserMessage(text: string, opts?: MidTurnEnvelopeOptions): string;
|
|
243
|
+
/** Who a mid-turn message speaks for, when it is not the session user.
|
|
244
|
+
* `relayedFrom` = the display name of the person whose own words an agent
|
|
245
|
+
* relayed verbatim; `fromOwnerAgent` = the thread agent that owns this
|
|
246
|
+
* worker, in its own words; both absent = the session user's own message. */
|
|
247
|
+
export interface MidTurnEnvelopeOptions {
|
|
248
|
+
relayedFrom?: string | null;
|
|
249
|
+
fromOwnerAgent?: boolean;
|
|
250
|
+
}
|
|
164
251
|
/** The one delivery-ack exec `injectUserMessage` runs: append the message
|
|
165
252
|
* line to the durable inbox, then wait for the feeder's delivered counter
|
|
166
|
-
* to cover it. Exit 0 =
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
*
|
|
253
|
+
* to cover it. Exit 0 = written into the CLI's stdin pipe pre-result,
|
|
254
|
+
* which is NOT "the model saw it": the CLI surfaces the line at its next
|
|
255
|
+
* tool boundary, so a kill before then loses it, and the settle's kill
|
|
256
|
+
* terminals hold the anchor at the pre-inject dispatch head for that
|
|
257
|
+
* reason (review D8). 4 = the runner died first; 5 = not forwarded within
|
|
258
|
+
* the ack window (the feeder is not forwarding: it stopped on the result,
|
|
259
|
+
* the resident turn gate is closed, or the guest is crawling). Both
|
|
260
|
+
* non-zero exits mean "leave the message owed". Exported for tests. */
|
|
170
261
|
export declare function injectAppendAndAckCommand(args: {
|
|
171
262
|
line: string;
|
|
172
263
|
target: number;
|
|
@@ -174,6 +265,60 @@ export declare function injectAppendAndAckCommand(args: {
|
|
|
174
265
|
inboxPath: string;
|
|
175
266
|
deliveredPath: string;
|
|
176
267
|
}): string;
|
|
268
|
+
/** stdin is a live message stream: the FIFO feeder above delivers the prompt
|
|
269
|
+
* line first and inbox lines after (claude: `--input-format stream-json`). */
|
|
270
|
+
export interface StdinStreamInputSpec {
|
|
271
|
+
transport: "stdin-stream";
|
|
272
|
+
/** Serialise the opening prompt into ONE stream-input stdin line
|
|
273
|
+
* (claude: a stream-json user message). No trailing newline — the
|
|
274
|
+
* transport owns line framing. */
|
|
275
|
+
promptLine(prompt: string): string;
|
|
276
|
+
/** Serialise one mid-turn user message into ONE stdin line. No
|
|
277
|
+
* trailing newline. */
|
|
278
|
+
messageLine(text: string): string;
|
|
279
|
+
/** Serialise ONE in-band interrupt control line (claude: a stream-json
|
|
280
|
+
* `control_request` with subtype "interrupt") — the ESC equivalent.
|
|
281
|
+
* The CLI's control layer handles these immediately, MID-STEP
|
|
282
|
+
* included: the running tool call aborts (its tool_result records the
|
|
283
|
+
* harness's own rejection text), the run ends with an
|
|
284
|
+
* `error_during_execution` result within ~100ms, and the session file
|
|
285
|
+
* stays `--resume`-able with the whole turn context. Verified live
|
|
286
|
+
* against claude 2.1.236. Absent → the runtime has no in-band
|
|
287
|
+
* interrupt; callers fall back to kill semantics. */
|
|
288
|
+
interruptLine?(requestId: string): string;
|
|
289
|
+
}
|
|
290
|
+
/** The CLI hands the inbox to the model itself, through a hook it runs after
|
|
291
|
+
* each tool call it completes (codex: the platform's PostToolUse command
|
|
292
|
+
* hook, CODEX_MID_TURN_HOOK_COMMAND in codex.ts). The launch creates the
|
|
293
|
+
* inbox and exports its paths into the CLI's environment
|
|
294
|
+
* (toolHookInboxFragment); the hook reads them back, prints the unfed lines
|
|
295
|
+
* as its additional context for the model and advances the delivered
|
|
296
|
+
* counter. stdin stays the plain prompt file, so there is no in-band
|
|
297
|
+
* interrupt on this transport. */
|
|
298
|
+
export interface ToolHookInputSpec {
|
|
299
|
+
transport: "tool-hook";
|
|
300
|
+
/** Serialise one mid-turn user message into ONE inbox line the hook can
|
|
301
|
+
* splice into its JSON output without decoding: a JSON string literal. */
|
|
302
|
+
messageLine(text: string): string;
|
|
303
|
+
}
|
|
304
|
+
export type MidTurnInputSpec = StdinStreamInputSpec | ToolHookInputSpec;
|
|
305
|
+
/** The stdin-stream transport of a spec, or undefined. The FIFO feeder, the
|
|
306
|
+
* resident harness, the prewarm lane and the in-band interrupt exist only
|
|
307
|
+
* for this transport; the inject lane itself reads `midTurnInput`. */
|
|
308
|
+
export declare function stdinStreamInputOf(spec: Pick<CliAgentSpec, "midTurnInput">): StdinStreamInputSpec | undefined;
|
|
309
|
+
/** The environment the tool-hook lane hands the CLI, and so the hook: codex
|
|
310
|
+
* runs a command hook with the CLI process's own environment (codex-rs
|
|
311
|
+
* hooks/src/registry.rs Hooks::new, engine/command_runner.rs at
|
|
312
|
+
* rust-v0.160.0). The turn's inbox and delivered-counter paths. */
|
|
313
|
+
export declare const MID_TURN_INBOX_ENV = "AC_MID_TURN_INBOX";
|
|
314
|
+
export declare const MID_TURN_DELIVERED_ENV = "AC_MID_TURN_DELIVERED";
|
|
315
|
+
/** The tool-hook lane's launch fragment, prepended to the detached wrapper
|
|
316
|
+
* script (the shell the CLI starts in): a fresh inbox, the counter at 0,
|
|
317
|
+
* and both paths exported for the hook. Exported for tests. */
|
|
318
|
+
export declare function toolHookInboxFragment(paths: {
|
|
319
|
+
inboxPath: string;
|
|
320
|
+
deliveredPath: string;
|
|
321
|
+
}): string;
|
|
177
322
|
/** SIGTERM grace before escalation: attempts × sleep = 5s. */
|
|
178
323
|
export declare const REAP_TERM_WAIT_ATTEMPTS = 20;
|
|
179
324
|
/** Post-SIGKILL confirm window: attempts × sleep = 2s (a KILLed process only
|
|
@@ -196,33 +341,63 @@ export declare function reapKillAndConfirmCommand(pid: number): string;
|
|
|
196
341
|
export declare const RESIDENT_IDLE_TTL_S = 240;
|
|
197
342
|
/** Watchdog poll cadence (seconds). */
|
|
198
343
|
export declare const RESIDENT_WATCHDOG_POLL_S = 15;
|
|
199
|
-
/**
|
|
200
|
-
* the guest
|
|
201
|
-
* the
|
|
202
|
-
*
|
|
203
|
-
export declare
|
|
344
|
+
/** Shell command printing how many result lines the durable .out holds —
|
|
345
|
+
* the guest's turn accounting (feeder gate, idle check, adoption parity).
|
|
346
|
+
* Prints nothing when the file is missing: callers default an empty count
|
|
347
|
+
* to 0. */
|
|
348
|
+
export declare function cliResultCountCommand(outPath: string): string;
|
|
204
349
|
/** One bounded exec printing the count of result lines at or past
|
|
205
350
|
* `fromByte` (0-based) in the durable .out. Always exits 0; stdout is the
|
|
206
351
|
* count (a missing file reads as 0). Hint-grade by design. */
|
|
207
352
|
export declare function residentResultCountCommand(outPath: string, fromByte?: number): string;
|
|
353
|
+
/** One bounded exec reporting the LAST result line in the durable .out
|
|
354
|
+
* window [`fromByte`, `toByte`): prints `none` (no result line), `error`
|
|
355
|
+
* (its `is_error` is true) or `ok`. Always exits 0 and never prints the
|
|
356
|
+
* line itself. The harvest's confirm for a resident result the tailer never
|
|
357
|
+
* parsed (review C2): a count alone cannot say whether the turn failed. The
|
|
358
|
+
* whole line is searched for `"is_error":true`, wherever the CLI put it
|
|
359
|
+
* (key order is not fixed). `toByte` bounds the window to bytes a drain
|
|
360
|
+
* already walked past, so a result the drain never reached (or a line still
|
|
361
|
+
* being written past its line-aligned offset) is not confirmed; omitted,
|
|
362
|
+
* the window runs to the end of the file. A window with `toByte <= fromByte`
|
|
363
|
+
* is empty. */
|
|
364
|
+
export declare function residentLastResultCommand(outPath: string, fromByte?: number, toByte?: number): string;
|
|
208
365
|
/** The resident feeder: `streamInputFeederFragment` with the result-break
|
|
209
|
-
* REPLACED by the end-file break
|
|
210
|
-
*
|
|
211
|
-
*
|
|
366
|
+
* REPLACED by the end-file break (verified live by the spec's probe: two
|
|
367
|
+
* messages, one process, one session file, graceful exit on `.end`), plus
|
|
368
|
+
* the TURN GATE: inbox lines are forwarded only while a delivered turn is
|
|
369
|
+
* still unanswered (the result count in .out is below `.served`),
|
|
370
|
+
* the same two numbers the idle predicate reads. Without the gate, a line
|
|
371
|
+
* appended after the turn's result line but before the server settled the
|
|
372
|
+
* turn was fed into the idle CLI, started a turn nobody tails, and was
|
|
373
|
+
* acked as delivered: the message was never answered, and the extra result
|
|
374
|
+
* line broke the next adoption's parity. With the gate that line stays
|
|
375
|
+
* unfed, the inject ack exits 5, and the message stays owed for the
|
|
376
|
+
* follow-up turn. Adoption bumps `.served` BEFORE it appends, so the next
|
|
377
|
+
* turn's prompt still flows. The count is a full-file grep, re-run
|
|
378
|
+
* only on a poll that has unfed lines AND a changed (.out size, .served)
|
|
379
|
+
* pair, so an idle resident holding a gated line never rescans. The
|
|
380
|
+
* forward is guarded like the plain feeder's: the counters advance only
|
|
381
|
+
* when `sed` wrote the lines into the FIFO. */
|
|
212
382
|
export declare function residentFeederFragment(paths: {
|
|
213
383
|
promptPath: string;
|
|
214
384
|
fifoPath: string;
|
|
215
385
|
inboxPath: string;
|
|
216
386
|
deliveredPath: string;
|
|
217
387
|
endPath: string;
|
|
388
|
+
outPath: string;
|
|
389
|
+
servedPath: string;
|
|
218
390
|
}): string;
|
|
219
|
-
/** Sets `ac_idle` (1 = between turns: every delivered turn has its result
|
|
220
|
-
*
|
|
221
|
-
*
|
|
391
|
+
/** Sets `ac_idle` (1 = between turns: every delivered turn has its result).
|
|
392
|
+
* Embedded by the watchdog and the resident heartbeat gate: one idle
|
|
393
|
+
* predicate, stated once. Unfed inbox lines do not make a resident busy:
|
|
394
|
+
* the feeder's turn gate forwards a line only while results < served, so
|
|
395
|
+
* a line still unfed once results >= served is held until the next
|
|
396
|
+
* adoption bumps `.served` (a message that raced the result, owed on the
|
|
397
|
+
* server). Reading it as work would keep the heartbeat fresh and the
|
|
398
|
+
* watchdog quiet for as long as the line sat there. */
|
|
222
399
|
export declare function residentIdleCheckFragment(paths: {
|
|
223
400
|
outPath: string;
|
|
224
|
-
inboxPath: string;
|
|
225
|
-
deliveredPath: string;
|
|
226
401
|
servedPath: string;
|
|
227
402
|
}): string;
|
|
228
403
|
/** Guest idle watchdog: reap the whole process group after
|
|
@@ -247,8 +422,6 @@ export declare function residentIdleCheckFragment(paths: {
|
|
|
247
422
|
* process existence). */
|
|
248
423
|
export declare function residentIdleWatchdogFragment(paths: {
|
|
249
424
|
outPath: string;
|
|
250
|
-
inboxPath: string;
|
|
251
|
-
deliveredPath: string;
|
|
252
425
|
servedPath: string;
|
|
253
426
|
}): string;
|
|
254
427
|
/** Exit-event doorbell with the turnId read from a guest FILE at push time
|
|
@@ -286,6 +459,13 @@ export declare const INSTALL_PROBE_TIMEOUT_MS = 30000;
|
|
|
286
459
|
* detached launch — the session images bake only `claude`, so codex/
|
|
287
460
|
* opencode/cursor/droid MUST be installable at launch on a fresh machine. */
|
|
288
461
|
export declare const CLI_INSTALL_TIMEOUT_MS = 300000;
|
|
462
|
+
/** Recover the detached runner's pid from its durable pidfile after the
|
|
463
|
+
* launch exec's STREAM died (deadline_exceeded, canceled context, any wire
|
|
464
|
+
* fault). Reads over the file transport with a short retry so the race
|
|
465
|
+
* where the launch shell is still writing the pidfile is absorbed.
|
|
466
|
+
* Exported for the server's workflow-lane launch (turn-workflow/tailer.ts
|
|
467
|
+
* launchDetachedRunner), which recovers the same way. */
|
|
468
|
+
export declare function recoverLaunchPid(read: (path: string) => Promise<string>, pidPath: string): Promise<number>;
|
|
289
469
|
/** Single-quote a value for safe interpolation into a `sh -c` command line. */
|
|
290
470
|
export declare function shellQuote(value: string): string;
|
|
291
471
|
/** $HOME-relative path of the platform-managed session env file. The server
|
|
@@ -299,6 +479,16 @@ export declare const SESSION_ENV_FILE_RELPATH = ".agent-compose/session-env.sh";
|
|
|
299
479
|
* when no env file is configured. Errors are swallowed — a missing or
|
|
300
480
|
* unreadable file must never fail a turn. */
|
|
301
481
|
export declare function sessionEnvSourceFragment(relPath: string | undefined): string;
|
|
482
|
+
/** Shell command printing a fingerprint of the session env file's current
|
|
483
|
+
* bytes (POSIX `cksum`), or `absent` when there is no file. A resident
|
|
484
|
+
* records it next to its prompt immediately BEFORE sourcing the file, and
|
|
485
|
+
* an adoption compares the file's fingerprint at that moment with it: a
|
|
486
|
+
* fresh launch would source the file as it is now, the resident only ever
|
|
487
|
+
* saw the one it started with. Recording before the source keeps the
|
|
488
|
+
* comparison conservative — a write that lands between the two reads as a
|
|
489
|
+
* change. The guest file is the one truth every replica writes to, so the
|
|
490
|
+
* verdict never depends on which server process wrote it. */
|
|
491
|
+
export declare function sessionEnvFingerprintCommand(relPath: string): string;
|
|
302
492
|
/** The per-turn model-credential source fragment (`RuntimeOptions.
|
|
303
493
|
* credEnvFile` — an ABSOLUTE guest path), or "" when none is configured.
|
|
304
494
|
* Sourced AFTER the session env file so the turn actor's credential wins.
|
|
@@ -403,9 +593,9 @@ export interface CliAgentSpec {
|
|
|
403
593
|
* `effort` is present only when the caller configured a reasoning effort
|
|
404
594
|
* AND the spec has a real knob for it (see `CliReasoningEffort`).
|
|
405
595
|
* `streamInput` is true when the durable transport is feeding stdin as a
|
|
406
|
-
* live message stream (
|
|
407
|
-
* then the FIFO the feeder writes, and the CLI must be
|
|
408
|
-
* stream-input mode (claude: `--input-format stream-json`). */
|
|
596
|
+
* live message stream (the "stdin-stream" `midTurnInput` transport):
|
|
597
|
+
* `promptPath` is then the FIFO the feeder writes, and the CLI must be
|
|
598
|
+
* invoked in its stream-input mode (claude: `--input-format stream-json`). */
|
|
409
599
|
buildCommand(args: {
|
|
410
600
|
promptPath: string;
|
|
411
601
|
sessionId?: string;
|
|
@@ -447,27 +637,15 @@ export interface CliAgentSpec {
|
|
|
447
637
|
args: string[];
|
|
448
638
|
env?: Record<string, string>;
|
|
449
639
|
};
|
|
450
|
-
/** Mid-turn
|
|
451
|
-
*
|
|
452
|
-
*
|
|
453
|
-
*
|
|
454
|
-
*
|
|
455
|
-
*
|
|
456
|
-
*
|
|
457
|
-
*
|
|
458
|
-
|
|
459
|
-
* FIFO, which is what ends the CLI process (stream-input CLIs exit on
|
|
460
|
-
* stdin EOF, not after a result). Absent → the prompt file is the whole
|
|
461
|
-
* stdin, exactly as before. */
|
|
462
|
-
streamInput?: {
|
|
463
|
-
/** Serialise the opening prompt into ONE stream-input stdin line
|
|
464
|
-
* (claude: a stream-json user message). No trailing newline — the
|
|
465
|
-
* transport owns line framing. */
|
|
466
|
-
promptLine(prompt: string): string;
|
|
467
|
-
/** Serialise one mid-turn user message into ONE stdin line. No
|
|
468
|
-
* trailing newline. */
|
|
469
|
-
messageLine(text: string): string;
|
|
470
|
-
};
|
|
640
|
+
/** Mid-turn INPUT support (the delivery half of `injectUserMessage`): how
|
|
641
|
+
* a line appended to the turn's durable inbox reaches the CLI while its
|
|
642
|
+
* turn runs — see the transports above. Engages only on the durable
|
|
643
|
+
* detached transport (the inbox, the delivered counter and the feeder or
|
|
644
|
+
* hook live in the guest; single-exec transports keep the plain
|
|
645
|
+
* prompt-file stdin). Absent → the runtime cannot take a message
|
|
646
|
+
* mid-turn: every inject answers "unsupported" and the message waits for
|
|
647
|
+
* the turn boundary. */
|
|
648
|
+
midTurnInput?: MidTurnInputSpec;
|
|
471
649
|
}
|
|
472
650
|
export declare class CliAgentRunner implements ModelExecutionContract {
|
|
473
651
|
private readonly sandbox;
|
|
@@ -527,15 +705,57 @@ export declare class CliAgentRunner implements ModelExecutionContract {
|
|
|
527
705
|
* answers "unsupported" and the caller leaves the message owed. `chain`
|
|
528
706
|
* serializes appends so each delivery targets a deterministic line count. */
|
|
529
707
|
private turnInject;
|
|
708
|
+
/** The CURRENT turn's detached-runner wrapper pid (the setsid group
|
|
709
|
+
* leader echoed by the launch / recovered from the durable pidfile) —
|
|
710
|
+
* durable-transport turns only. Null between turns and on transports
|
|
711
|
+
* without a detached guest. See the contract doc (types/runtime.ts). */
|
|
712
|
+
private turnPid;
|
|
713
|
+
/** Advisory guest-pid identity for the live turn's runner tree — see the
|
|
714
|
+
* contract doc (types/runtime.ts). Never a liveness verdict. */
|
|
715
|
+
currentRunnerPid(): number | null;
|
|
716
|
+
/** Safe-to-persist durable byte offset — end of the last line whose
|
|
717
|
+
* messages have ALL been yielded (boot-time turn adoption; contract in
|
|
718
|
+
* types/runtime.ts). One line behind the parse cursor by design. */
|
|
719
|
+
private turnConsumedOffset;
|
|
720
|
+
/** End offset of the line currently being yielded from — promoted to
|
|
721
|
+
* `turnConsumedOffset` when the NEXT line is pulled (or at stream end). */
|
|
722
|
+
private turnPendingLineEnd;
|
|
723
|
+
currentTurnDurableOffset(): number | null;
|
|
530
724
|
/** Deliver one user message INTO the live turn — see the contract doc
|
|
531
725
|
* (types/runtime.ts). Appends a stream-input line to the turn's durable
|
|
532
726
|
* inbox and waits for the in-guest feeder's delivered-counter ack; only
|
|
533
|
-
* an acked forward (pre-result, into the CLI's stdin)
|
|
534
|
-
* "delivered"
|
|
535
|
-
*
|
|
536
|
-
* the
|
|
537
|
-
*
|
|
538
|
-
|
|
727
|
+
* an acked forward (pre-result, written into the CLI's stdin pipe)
|
|
728
|
+
* reports "delivered", and even then the model reads the line only at
|
|
729
|
+
* its next tool boundary (review D8). Guest exit 5 (ack window exhausted
|
|
730
|
+
* with the runner still alive: the feeder is not forwarding) reports
|
|
731
|
+
* "pending": the appended line may still be forwarded later, but it was
|
|
732
|
+
* NOT seen yet. Never throws. */
|
|
733
|
+
injectUserMessage(text: string, opts?: MidTurnEnvelopeOptions): Promise<"delivered" | "pending" | "closed" | "unsupported">;
|
|
734
|
+
/** Request an in-band step interrupt of the LIVE turn — the ESC
|
|
735
|
+
* equivalent; see the contract doc (types/runtime.ts). Appends the
|
|
736
|
+
* spec's interrupt control line to the turn's durable inbox; the guest
|
|
737
|
+
* feeder forwards it into the CLI's stdin, whose control layer handles
|
|
738
|
+
* it immediately — MID-STEP included, unlike queued user messages (the
|
|
739
|
+
* inject "pending" wall applies to turn-loop consumption, not the
|
|
740
|
+
* control layer). Only "delivered" means the control line reached the
|
|
741
|
+
* CLI's stdin; callers escalate anything else to kill semantics. Never
|
|
742
|
+
* throws. */
|
|
743
|
+
interruptTurn(): Promise<"delivered" | "pending" | "closed" | "unsupported">;
|
|
744
|
+
/** The one durable append+ack path both mid-turn producers share
|
|
745
|
+
* (`injectUserMessage`'s enveloped message line, `interruptTurn`'s raw
|
|
746
|
+
* control line). Serialized on the inject chain so every append targets
|
|
747
|
+
* a deterministic inbox line count. */
|
|
748
|
+
private appendTurnStreamLine;
|
|
749
|
+
/** The most recent probe reading's tool-run pulse (2026-08-29), plus the
|
|
750
|
+
* guest clock it was read against — telemetry only, refreshed by each
|
|
751
|
+
* `probeTurnLiveness` call. Null between turns / before any probe. */
|
|
752
|
+
private lastTurnPulse;
|
|
753
|
+
/** Peek the newest tool-run pulse the durable probe carried — the
|
|
754
|
+
* executor's evidence ticker reads it AFTER its liveness check to fan
|
|
755
|
+
* the tool-progress fact to clients. Never probes on its own. */
|
|
756
|
+
peekTurnPulse(): (TurnToolPulse & {
|
|
757
|
+
guestNowMs: number;
|
|
758
|
+
}) | null;
|
|
539
759
|
/** Durable three-valued liveness for the current turn — see the contract
|
|
540
760
|
* doc (types/runtime.ts). Never throws; never blocks past the probe's
|
|
541
761
|
* explicit exec timeout. */
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
* sessions this is the gateway-minted session virtual key pointed at the
|
|
34
34
|
* token-metering gateway's Anthropic passthrough (ADR-0039).
|
|
35
35
|
*/
|
|
36
|
-
import type { AgentMessageTaskNotification } from "../index.js";
|
|
36
|
+
import type { AgentMessage, AgentMessageCompaction, AgentMessageModelUsage, AgentMessagePlanLimits, AgentMessageTaskNotification, AgentMessageTaskProgress } from "../index.js";
|
|
37
37
|
import { type CliAgentSpec, type CliReasoningEffort } from "./_cli-agent.js";
|
|
38
38
|
/** Pinned Claude Code ACP adapter (Zed's npm shim — `claude` has no native
|
|
39
39
|
* ACP mode). Pinned EXACT, not a range: the adapter's README warns of
|
|
@@ -46,12 +46,54 @@ export declare const CLAUDE_CODE_ACP_ADAPTER = "@zed-industries/claude-code-acp@
|
|
|
46
46
|
* is skipped, absent fields stay absent, everything is clamped. Exported
|
|
47
47
|
* for tests. */
|
|
48
48
|
export declare function parseTaskNotifications(text: string, timestamp: string): AgentMessageTaskNotification[];
|
|
49
|
+
/** One user-role TEXT blob from the stream, mapped with sidechain awareness.
|
|
50
|
+
* Task-notification blocks parse into structure wherever they appear (their
|
|
51
|
+
* arrival side is resume-dependent — see the transport notes above). What
|
|
52
|
+
* remains is then split by attribution: TOP-LEVEL text (no parent id) stays
|
|
53
|
+
* unmapped exactly as before — prompt echoes and system reminders are not
|
|
54
|
+
* agent output. SIDECHAIN text (parent id present) is a message landing in
|
|
55
|
+
* a child subagent's thread — a delivered SendMessage steer — and forwards
|
|
56
|
+
* as `subagent_user_message`, except harness plumbing (`<system-reminder>`
|
|
57
|
+
* wrappers the CLI injects into child threads), which no renderer should
|
|
58
|
+
* see. Exported for tests. */
|
|
59
|
+
export declare function sidechainAwareUserText(text: string, parentToolUseId: string | undefined, timestamp: string): AgentMessage[];
|
|
49
60
|
/** One `system`/`task_notification` stream-json event mapped onto the same
|
|
50
61
|
* structured message the XML parse produces, or null when the event names
|
|
51
62
|
* no task id. Pure and tolerant over untrusted harness JSON: absent fields
|
|
52
63
|
* stay absent, everything is clamped; `output_file` (internal plumbing) is
|
|
53
64
|
* deliberately not forwarded. Exported for tests. */
|
|
54
65
|
export declare function parseSystemTaskNotification(p: Record<string, unknown>, timestamp: string): AgentMessageTaskNotification | null;
|
|
66
|
+
/** One `system`/`task_progress` event mapped onto the structured progress
|
|
67
|
+
* message, or null only when it names no task. Workflow tasks carry the
|
|
68
|
+
* cumulative `workflow_progress` entries; a plain background Agent-task
|
|
69
|
+
* heartbeat (no workflow entries — verified live on 2.1.241, ~10s cadence
|
|
70
|
+
* while the task runs) forwards with `workflow: []` so the platform can
|
|
71
|
+
* DECLARE the running task as session background work (the delegation-
|
|
72
|
+
* survives-the-human contract: parks, user interrupts, and supersedes all
|
|
73
|
+
* read the declared-children registry). Completion evidence still rides
|
|
74
|
+
* `task_notification`. Pure and tolerant over untrusted harness JSON:
|
|
75
|
+
* malformed entries are skipped, everything is clamped (phases keep the
|
|
76
|
+
* FIRST 32 — they are seeded up front; agents keep the LAST 128 — late
|
|
77
|
+
* spawns matter more than a long-settled prefix). Exported for tests. */
|
|
78
|
+
export declare function parseSystemTaskProgress(p: Record<string, unknown>, timestamp: string): AgentMessageTaskProgress | null;
|
|
79
|
+
/** One `system` event of the compaction family mapped onto the structured
|
|
80
|
+
* lifecycle message, or null when the event is not compaction-shaped (a
|
|
81
|
+
* plain `status` event with neither the compacting status nor a
|
|
82
|
+
* compact_result stays unmapped). Pure and tolerant over untrusted harness
|
|
83
|
+
* JSON. Exported for tests. */
|
|
84
|
+
export declare function parseSystemCompaction(p: Record<string, unknown>, timestamp: string): AgentMessageCompaction | null;
|
|
85
|
+
/** One `rate_limit_event` mapped onto the structured plan-limits message,
|
|
86
|
+
* or null when the event names no recognisable status. Pure and tolerant
|
|
87
|
+
* over untrusted harness JSON: every field is forwarded only when present
|
|
88
|
+
* and well-typed; nothing is defaulted or invented. Exported for tests. */
|
|
89
|
+
export declare function parsePlanLimits(p: Record<string, unknown>, timestamp: string): AgentMessagePlanLimits | null;
|
|
90
|
+
/** The terminal result's per-model report (`result.modelUsage`, keyed by
|
|
91
|
+
* the raw model string) mapped onto the protocol's per-model shape, or
|
|
92
|
+
* undefined when the result carries none. Counts the harness did not
|
|
93
|
+
* report stay absent (the four classes default to 0 only when the entry
|
|
94
|
+
* exists at all — an entry IS a report of that model). Pure; exported for
|
|
95
|
+
* tests. */
|
|
96
|
+
export declare function parseModelUsage(raw: unknown): Record<string, AgentMessageModelUsage> | undefined;
|
|
55
97
|
/** Claude Code's real reasoning knob is its own `--effort <level>` flag
|
|
56
98
|
* (low|medium|high|xhigh|max — verified against `claude -p --help`). The
|
|
57
99
|
* CliReasoningEffort union IS the CLI's vocabulary, so the level rides the
|
|
@@ -60,6 +102,53 @@ export declare function parseSystemTaskNotification(p: Record<string, unknown>,
|
|
|
60
102
|
* `MAX_THINKING_TOKENS` env mapping is gone: the CLI deprecated it (treated
|
|
61
103
|
* as on/off on current models) and it could never express xhigh/max. */
|
|
62
104
|
export declare const CLAUDE_CODE_EFFORT_LEVELS: readonly CliReasoningEffort[];
|
|
105
|
+
/** The Bash PreToolUse hook rtk installs for Claude Code (`rtk init -g
|
|
106
|
+
* --hook-only` writes exactly this entry — matcher `Bash`, command
|
|
107
|
+
* `rtk hook claude` — into ~/.claude/settings.json; the image bakes
|
|
108
|
+
* RTK_VERSION, sandbox/baked-clis.ts, which this payload was run against).
|
|
109
|
+
* `rtk hook claude` reads the PreToolUse JSON on stdin and, when it has a
|
|
110
|
+
* filter for the command, answers with `updatedInput` rewriting `git
|
|
111
|
+
* status` to `rtk git status` (ls, find, grep, test runners, bun, curl,
|
|
112
|
+
* docker, …), so the model reads rtk's compact output. A command it
|
|
113
|
+
* cannot compress — an unknown tool, a pipe into one, command or process
|
|
114
|
+
* substitution, a heredoc, a file redirect, anything already prefixed
|
|
115
|
+
* `rtk`, or a `RTK_DISABLED=1` prefix — gets no output and exit 0, which
|
|
116
|
+
* Claude Code treats as "no decision": the original command runs
|
|
117
|
+
* unchanged (all verified against the binary).
|
|
118
|
+
*
|
|
119
|
+
* The wrapper fails OPEN both ways. `command -v` covers images without
|
|
120
|
+
* rtk (the devbox, a bare Vercel VM): there a bare `rtk hook claude` would
|
|
121
|
+
* fail every Bash call's hook with exit 127 — non-blocking, but a stderr
|
|
122
|
+
* warning per call; rtk's own legacy shell hook degraded the same way
|
|
123
|
+
* ("binary not found: exit 0"). The trailing `exit 0` covers an rtk that
|
|
124
|
+
* cannot answer: Claude Code treats a PreToolUse hook's exit 2 as a BLOCK
|
|
125
|
+
* of the tool call with stderr fed to the model, and clap exits 2 with
|
|
126
|
+
* its usage for a subcommand it does not know — which is how the codex
|
|
127
|
+
* hook (RTK_CODEX_HOOK_COMMAND, codex.ts) blocked every codex shell
|
|
128
|
+
* command on 2026-10-03, when the image's rtk was a cache-served 0.45.0.
|
|
129
|
+
* rtk's hooks never exit non-zero on purpose, so a non-zero exit is a
|
|
130
|
+
* broken rtk, and the compressor must never cost the worker its shell:
|
|
131
|
+
* the exit code is dropped, and the smoke gate's rtk-hook-rewrite check
|
|
132
|
+
* is what proves the rewrite itself. */
|
|
133
|
+
export declare const RTK_BASH_HOOK_COMMAND = "command -v rtk >/dev/null 2>&1 && rtk hook claude; exit 0";
|
|
134
|
+
/** Settings every platform `claude` launch passes as `--settings` (inline
|
|
135
|
+
* JSON). Claude Code MERGES hook entries across its settings sources
|
|
136
|
+
* instead of replacing them (user → project → local → flag → managed), so
|
|
137
|
+
* this rides beside whatever the machine's own ~/.claude/settings.json
|
|
138
|
+
* carries, and nothing is written to that file — the right outcome, since
|
|
139
|
+
* the server never owns it: home carry tar-restores it whole across
|
|
140
|
+
* machines and the image capture strips it as personal state. */
|
|
141
|
+
export declare const CLAUDE_CODE_PLATFORM_SETTINGS: {
|
|
142
|
+
readonly hooks: {
|
|
143
|
+
readonly PreToolUse: readonly [{
|
|
144
|
+
readonly matcher: "Bash";
|
|
145
|
+
readonly hooks: readonly [{
|
|
146
|
+
readonly type: "command";
|
|
147
|
+
readonly command: "command -v rtk >/dev/null 2>&1 && rtk hook claude; exit 0";
|
|
148
|
+
}];
|
|
149
|
+
}];
|
|
150
|
+
};
|
|
151
|
+
};
|
|
63
152
|
export declare const claudeCodeSpec: CliAgentSpec;
|
|
64
153
|
export interface ClaudeCodeRuntimeConfig {
|
|
65
154
|
/** Claude model id (`--model`). Omit to use the CLI's configured default. */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** Claude Agent SDK runtime
|
|
1
|
+
/** Claude Agent SDK runtime. */
|
|
2
2
|
import { type ThinkingConfig } from "@anthropic-ai/claude-agent-sdk";
|
|
3
3
|
import type { AgentMessage, ModelExecutionContract, RuntimeOptions, SandboxProvider, ToolCallGateResult } from "../index.js";
|
|
4
4
|
import type { ProcessorContext, ToolCall } from "../processors/processor.js";
|