@dynamicagents/plugins 0.14.0 → 0.16.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 (141) hide show
  1. package/README.md +14 -14
  2. package/dist/claude-code/cards.d.ts +2 -0
  3. package/dist/claude-code/cards.js +11 -0
  4. package/dist/claude-code/config.d.ts +10 -83
  5. package/dist/claude-code/config.js +0 -2
  6. package/dist/claude-code/credentials.d.ts +32 -50
  7. package/dist/claude-code/credentials.js +115 -74
  8. package/dist/claude-code/daemon/index.d.ts +24 -0
  9. package/dist/claude-code/daemon/index.js +203 -0
  10. package/dist/claude-code/egress.d.ts +35 -117
  11. package/dist/claude-code/egress.js +80 -325
  12. package/dist/claude-code/events.d.ts +14 -17
  13. package/dist/claude-code/events.js +19 -15
  14. package/dist/claude-code/harness-wire.d.ts +45 -0
  15. package/dist/claude-code/harness-wire.js +47 -0
  16. package/dist/claude-code/index.d.ts +19 -29
  17. package/dist/claude-code/index.js +17 -25
  18. package/dist/claude-code/language-model.d.ts +19 -0
  19. package/dist/claude-code/language-model.js +71 -0
  20. package/dist/claude-code/model.d.ts +77 -70
  21. package/dist/claude-code/model.js +327 -327
  22. package/dist/claude-code/placeholder.d.ts +12 -0
  23. package/dist/claude-code/placeholder.js +12 -0
  24. package/dist/claude-code/spec.d.ts +4 -4
  25. package/dist/claude-code/spec.js +4 -4
  26. package/dist/computer/client.d.ts +88 -0
  27. package/dist/computer/client.js +6 -0
  28. package/dist/computer/context.d.ts +7 -7
  29. package/dist/computer/context.js +14 -18
  30. package/dist/computer/gate.d.ts +4 -23
  31. package/dist/computer/gate.js +1 -37
  32. package/dist/computer/index.d.ts +44 -43
  33. package/dist/computer/index.js +29 -50
  34. package/dist/computer/paths.d.ts +5 -27
  35. package/dist/computer/paths.js +7 -30
  36. package/dist/computer/proxy.d.ts +17 -31
  37. package/dist/computer/proxy.js +9 -44
  38. package/dist/computer/render.d.ts +3 -40
  39. package/dist/computer/render.js +3 -36
  40. package/dist/computer/sandbox.d.ts +55 -0
  41. package/dist/computer/sandbox.js +236 -0
  42. package/dist/computer/shell.d.ts +36 -0
  43. package/dist/computer/shell.js +41 -0
  44. package/dist/computer/tools-exec.js +3 -9
  45. package/dist/computer/tools-file.d.ts +1 -1
  46. package/dist/computer/tools-file.js +1 -1
  47. package/dist/{repo → repo-github}/checkout.d.ts +3 -4
  48. package/dist/{repo → repo-github}/checkout.js +3 -4
  49. package/dist/{repo → repo-github}/context.d.ts +14 -32
  50. package/dist/{repo → repo-github}/context.js +46 -81
  51. package/dist/{repo → repo-github}/index.d.ts +30 -13
  52. package/dist/{repo → repo-github}/index.js +25 -6
  53. package/dist/repo-github/mcp.d.ts +95 -0
  54. package/dist/repo-github/mcp.js +107 -0
  55. package/dist/repo-github/sandbox-egress.d.ts +68 -0
  56. package/dist/repo-github/sandbox-egress.js +272 -0
  57. package/dist/repo-github/sandbox-git.d.ts +30 -0
  58. package/dist/repo-github/sandbox-git.js +113 -0
  59. package/dist/{repo → repo-github}/tools-checks.js +43 -4
  60. package/dist/{repo → repo-github}/tools-clone.js +2 -21
  61. package/dist/{repo → repo-github}/tools-pr.d.ts +0 -1
  62. package/dist/{repo → repo-github}/tools-pr.js +85 -20
  63. package/dist/{repo → repo-github}/tools-review.d.ts +6 -0
  64. package/dist/{repo → repo-github}/tools-review.js +62 -176
  65. package/dist/{repo → repo-github}/url.d.ts +11 -0
  66. package/dist/{repo → repo-github}/url.js +12 -1
  67. package/dist/{workspace → sandbox}/advisory.d.ts +16 -35
  68. package/dist/{workspace → sandbox}/advisory.js +2 -29
  69. package/dist/sandbox/agent-exec.d.ts +31 -0
  70. package/dist/sandbox/agent-exec.js +62 -0
  71. package/dist/sandbox/ca-trust.d.ts +9 -0
  72. package/dist/sandbox/ca-trust.js +21 -0
  73. package/dist/sandbox/constants.d.ts +22 -0
  74. package/dist/sandbox/constants.js +22 -0
  75. package/dist/sandbox/daemon/composite.d.ts +9 -0
  76. package/dist/sandbox/daemon/composite.js +35 -0
  77. package/dist/sandbox/daemon/index.d.ts +47 -0
  78. package/dist/sandbox/daemon/index.js +116 -0
  79. package/dist/sandbox/egress.d.ts +81 -0
  80. package/dist/sandbox/egress.js +109 -0
  81. package/dist/sandbox/exec.d.ts +57 -0
  82. package/dist/sandbox/exec.js +52 -0
  83. package/dist/sandbox/format.d.ts +2 -0
  84. package/dist/sandbox/format.js +7 -0
  85. package/dist/sandbox/header.d.ts +50 -0
  86. package/dist/sandbox/header.js +94 -0
  87. package/dist/sandbox/index.d.ts +17 -0
  88. package/dist/sandbox/index.js +17 -0
  89. package/dist/{workspace/install.d.ts → sandbox/install-plan.d.ts} +2 -2
  90. package/dist/{workspace/install.js → sandbox/install-plan.js} +2 -2
  91. package/dist/sandbox/name.d.ts +27 -0
  92. package/dist/sandbox/name.js +32 -0
  93. package/dist/sandbox/object.d.ts +244 -0
  94. package/dist/sandbox/object.js +1139 -0
  95. package/dist/scratch/index.d.ts +1 -9
  96. package/dist/scratch/index.js +2 -18
  97. package/package.json +24 -20
  98. package/dist/claude-code/github.d.ts +0 -39
  99. package/dist/claude-code/github.js +0 -82
  100. package/dist/claude-code/run.d.ts +0 -491
  101. package/dist/claude-code/run.js +0 -913
  102. package/dist/claude-code/session.d.ts +0 -131
  103. package/dist/claude-code/session.js +0 -288
  104. package/dist/workspace/ca-trust.d.ts +0 -95
  105. package/dist/workspace/ca-trust.js +0 -312
  106. package/dist/workspace/container-deps.d.ts +0 -58
  107. package/dist/workspace/container-deps.js +0 -249
  108. package/dist/workspace/container-fault.d.ts +0 -38
  109. package/dist/workspace/container-fault.js +0 -73
  110. package/dist/workspace/deps-snapshot.d.ts +0 -110
  111. package/dist/workspace/deps-snapshot.js +0 -424
  112. package/dist/workspace/exec.d.ts +0 -94
  113. package/dist/workspace/exec.js +0 -153
  114. package/dist/workspace/format.d.ts +0 -36
  115. package/dist/workspace/format.js +0 -57
  116. package/dist/workspace/git-host.d.ts +0 -79
  117. package/dist/workspace/git-host.js +0 -226
  118. package/dist/workspace/git-identity.d.ts +0 -57
  119. package/dist/workspace/git-identity.js +0 -147
  120. package/dist/workspace/index.d.ts +0 -50
  121. package/dist/workspace/index.js +0 -58
  122. package/dist/workspace/install-job.d.ts +0 -170
  123. package/dist/workspace/install-job.js +0 -934
  124. package/dist/workspace/object.d.ts +0 -522
  125. package/dist/workspace/object.js +0 -1541
  126. package/dist/workspace/open.d.ts +0 -95
  127. package/dist/workspace/open.js +0 -63
  128. package/dist/workspace/read.d.ts +0 -16
  129. package/dist/workspace/read.js +0 -22
  130. package/dist/workspace/shell.d.ts +0 -45
  131. package/dist/workspace/shell.js +0 -80
  132. package/dist/workspace/sync.d.ts +0 -111
  133. package/dist/workspace/sync.js +0 -124
  134. package/dist/workspace/wake.d.ts +0 -21
  135. package/dist/workspace/wake.js +0 -10
  136. /package/dist/{repo → repo-github}/tools-checks.d.ts +0 -0
  137. /package/dist/{repo → repo-github}/tools-clone.d.ts +0 -0
  138. /package/dist/{repo → repo-github}/tools-worktree.d.ts +0 -0
  139. /package/dist/{repo → repo-github}/tools-worktree.js +0 -0
  140. /package/dist/{repo → repo-github}/tools-worktrees.d.ts +0 -0
  141. /package/dist/{repo → repo-github}/tools-worktrees.js +0 -0
@@ -1,491 +0,0 @@
1
- import type { WorkspaceRuntimeExecHandle, WorkspaceRuntimeExecOptions, WorkspaceRuntimeGetOptions, WorkspaceRuntimeKillOptions } from "@cloudflare/computer";
2
- import type { NoteData } from "@dynamicagents/core/subagent";
3
- import { type ClaudeCodeResult, type RateLimitInfo } from "./events.js";
4
- import { type EffortLevel, type PermissionMode } from "./config.js";
5
- /**
6
- * Launching Claude Code in the workspace container, and draining it to its end.
7
- *
8
- * ## One sub-agent run is one `claude -p` session
9
- *
10
- * Not one turn, and not one tool call. The unit has to be substantial because of
11
- * what an invocation costs before it does anything: the harness carries an
12
- * 18.7-27k token cached prefix, and a ten-call burst billed **twenty** raw input
13
- * tokens against 187,130 cache reads. On anything short the prefix is the bill.
14
- *
15
- * ## Detached, then re-attached — never owned by a request
16
- *
17
- * The run is spawned under an exec id and left running, and a drain reads it to
18
- * its exit. A drain cut short — an eviction, a deploy — does not take the
19
- * session with it: the next one re-attaches under the same id. That shape is
20
- * not a preference: a session owned by the request that started it dies with
21
- * that request — the same way a dependency install dies halfway through
22
- * `npm ci`.
23
- *
24
- * ## The cursor
25
- *
26
- * `getExec(id, { resume })` accepts `"tail"`, `"full"` **or an event sequence
27
- * number**, and the number is what this uses. The caller stores the last `seq`
28
- * consumed, so a resumed drain starts exactly there instead of replaying an
29
- * arbitrary tail. Replay still happens when a drain dies before the cursor is
30
- * stored, which is why the note keys stay positional (see `toProgress`); the
31
- * cursor makes replay rare, the keys make it harmless.
32
- *
33
- * The cursor also carries the **exec id** and the **parsed result**, and both
34
- * are there for reasons that only show up under concurrency or retry — see
35
- * {@link DrainCursor}.
36
- */
37
- /**
38
- * Just enough of a workspace runtime to drive one detached session.
39
- *
40
- * Structural rather than `@cloudflare/computer`'s `WorkspaceRuntime`, for the
41
- * reason `InstallProbe` is structural one folder over: the class is not exported
42
- * as a type, it carries a dozen members none of this needs, and a spec that has
43
- * to construct one cannot test a drain without a container. Three methods is the
44
- * whole dependency.
45
- */
46
- export interface SessionRuntime {
47
- exec(source: string, options: WorkspaceRuntimeExecOptions<"utf8">): Promise<WorkspaceRuntimeExecHandle<"utf8">>;
48
- getExec(id: string, options: WorkspaceRuntimeGetOptions<"utf8">): Promise<WorkspaceRuntimeExecHandle<"utf8">>;
49
- killExec(id: string, options?: WorkspaceRuntimeKillOptions): Promise<void>;
50
- }
51
- /** Namespace for every session exec id in a workspace. */
52
- export declare const CLAUDE_EXEC_PREFIX = "claude-code-run";
53
- /**
54
- * The exec id one session occupies.
55
- *
56
- * **Per run, not fixed**, and the difference is load-bearing. A workspace is
57
- * one Durable Object and one container, but runs are concurrent — sessions in a
58
- * scratchpad share their parent's container — so under a single shared id they would spawn
59
- * over one another, each drain would attach to whichever exec won, and
60
- * `killRun` would stop somebody else's session. That is the displacement bug the
61
- * coder's install guard exists to prevent, in a new place; here the answer is
62
- * simply not to share the id.
63
- *
64
- * Fixed *per run*, though, because the point is still to find it again: an
65
- * isolate that dies mid-drain leaves the session running in the container, and
66
- * `getExec` is how the next drain re-attaches instead of starting a second one.
67
- */
68
- export declare function execIdFor(runId: string): string;
69
- /**
70
- * The id a run's follow-up turn runs under — its own, because the session's exec
71
- * has already finished under {@link execIdFor} and an id names one process.
72
- */
73
- export declare function followUpExecIdFor(runId: string): string;
74
- /**
75
- * What the container is given instead of a credential.
76
- *
77
- * Claude Code does not validate it locally: a run with this exact value
78
- * succeeds, and the container only ever sends the placeholder. The egress
79
- * gateway swaps in the real credential on the way out, so a `postinstall` script
80
- * that dumps the environment learns this and nothing else.
81
- *
82
- * Shaped like a real token deliberately: something that looks obviously fake
83
- * invites a future reader to "fix" it by putting the real one there.
84
- */
85
- export declare const CREDENTIAL_PLACEHOLDER: string;
86
- /**
87
- * Where every session keeps Claude Code's own state — its `CLAUDE_CONFIG_DIR`.
88
- *
89
- * The whole config directory moves, created if absent: the transcripts under
90
- * `projects/<cwd-with-/-as-->/<session-id>.jsonl`, the session index,
91
- * `.claude.json` and the auto-memory directory. None of it is a credential.
92
- *
93
- * This is what decides how long a session stays resumable. The CLI's own
94
- * `$HOME/.claude` is on the container's disk, so a conversation there dies with
95
- * the container — which a deploy, a rollout and the workspace's own idle timer
96
- * all end. Under the workspace mount it is the Durable Object's storage, and the
97
- * conversation outlives the container that held it; a later run can continue it
98
- * from that same workspace object, and from no other.
99
- *
100
- * **Fixed, and never a host's to choose.** A transcript is found only where it
101
- * was written, so every second place a session could write one is a resume that
102
- * cannot find it. `env` cannot move it either: {@link buildLaunch} refuses the
103
- * key.
104
- *
105
- * The directory is named {@link file://../computer/paths.ts SESSION_STATE_DIR},
106
- * which is the name the file tools' walk steps over: a transcript records every
107
- * line the session read, so a walk that descended into it would answer the
108
- * parent's `grep` for a line of source with the session that quoted it. The
109
- * name is written out here rather than imported, because `/claude-code` does
110
- * not reach `/computer` — a spec holds the two to the same spelling.
111
- */
112
- export declare const SESSION_CONFIG_DIR = "/workspace/.claude-sessions";
113
- export interface LaunchOptions {
114
- /** The run's prompt — the whole of what this session is asked to do. */
115
- prompt: string;
116
- /** Where the checkout is. The session runs with this as its cwd. */
117
- dir: string;
118
- model?: string;
119
- /**
120
- * How hard the model thinks, per turn. Unset, the model's own default.
121
- *
122
- * See {@link file://./config.ts ClaudeCodeConfig.effort} for what a level
123
- * costs, and why an unrecognised one is worse here than a rejected one.
124
- */
125
- effort?: EffortLevel;
126
- /**
127
- * Caps on Claude Code's own subagent tree — advisory, for the reason
128
- * {@link file://./config.ts ClaudeCodeConfig.maxSubagentDepth} gives.
129
- */
130
- maxSubagentDepth?: number;
131
- maxConcurrentSubagents?: number;
132
- /**
133
- * How the session answers its own permission prompts.
134
- *
135
- * Defaults to {@link DEFAULT_PERMISSION_MODE}. See
136
- * {@link file://./config.ts ClaudeCodeConfig.permissionMode} for why the
137
- * default is the permissive one, and {@link buildLaunch} for the root guard
138
- * that decides how it has to be passed.
139
- */
140
- permissionMode?: PermissionMode;
141
- /**
142
- * Merged last, so a host can add what a repository needs.
143
- *
144
- * **Never secrets**, and {@link RESERVED_ENV_KEY} is refused outright rather
145
- * than trusted to the reader of that sentence.
146
- */
147
- env?: Record<string, string>;
148
- /**
149
- * Who this session's commits are attributed to — see
150
- * {@link file://./config.ts ClaudeCodeConfig.author}.
151
- */
152
- author?: {
153
- name: string;
154
- email: string;
155
- };
156
- /**
157
- * A JSON Schema the session's answer must match, as `--json-schema`. The CLI
158
- * gives the model a `StructuredOutput` tool and holds the run until it is
159
- * called, and the result line carries the call's input as
160
- * `structured_output` — see {@link file://./events.ts ClaudeCodeResult}.
161
- */
162
- jsonSchema?: Record<string, unknown>;
163
- /**
164
- * A Claude Code session id to continue — the handle an earlier session left on
165
- * its {@link DrainCursor}, or reported on its `result` line.
166
- *
167
- * {@link LaunchOptions.prompt} is then the **next user turn** rather than a new
168
- * task: the conversation is already in the session's context, so a brief that
169
- * restates it pays for it twice.
170
- *
171
- * Not scoped to the working directory — a session recorded against one cwd
172
- * resumes under another and goes on appending to the original transcript — so
173
- * what decides whether this works is where the transcript is, which is
174
- * {@link SESSION_CONFIG_DIR} in the workspace the session ran in.
175
- *
176
- * **An id whose transcript is not there is not a failed session.** The CLI
177
- * prints `No conversation found with session ID`, emits a `result` line
178
- * carrying that as {@link file://./events.ts ClaudeCodeResult.errors}, and
179
- * exits in milliseconds; its client still makes its own startup requests, but
180
- * nothing is inferred and nothing is billed. The honest report is "not
181
- * resumable", and the retry is the same delegation without this.
182
- *
183
- * **An empty id is refused rather than dropped.** That retry is launching
184
- * without this option, not passing it empty.
185
- */
186
- resume?: string;
187
- /**
188
- * Fork the resumed conversation: continue it under a **new** session id,
189
- * leaving the original transcript whole and resumable.
190
- *
191
- * What a change of mode wants — a planning session, run under `plan`,
192
- * continued under the mode that writes — so that the plan's own conversation
193
- * can still be resumed for an edit afterwards. Continuing in the same mode
194
- * takes no fork: one conversation accumulating is what "continue" means.
195
- *
196
- * Refused without {@link LaunchOptions.resume}: on its own the flag has no
197
- * conversation to fork, and a caller that set it meant to resume one.
198
- */
199
- fork?: boolean;
200
- /**
201
- * Present GitHub's placeholder as `GH_TOKEN` and as git's credential, for a
202
- * gateway holding the real token — see {@link file://./github.ts}.
203
- */
204
- github?: boolean;
205
- }
206
- export interface Launch {
207
- command: string;
208
- env: Record<string, string>;
209
- }
210
- /**
211
- * Build the command and environment for one session.
212
- *
213
- * `--output-format stream-json` with `--verbose`, because the stream is the only
214
- * way to report progress before the run ends, and a run lasts for minutes.
215
- * `--verbose` is required: without it Claude Code emits
216
- * only the final result even in stream mode.
217
- *
218
- * Note what is **absent**. No `--bare` and no `--settings` override: a cloned
219
- * repository's `CLAUDE.md`, skills and hooks are exactly the material that makes
220
- * the agent good at that repository, and the container is already an
221
- * arbitrary-code-execution environment by design — the install runs the repo's
222
- * `postinstall`, the agent runs its test suite. Stripping one door while the
223
- * others stand open buys nothing and costs the agent its context.
224
- * `CLAUDE_CONFIG_DIR` is not that kind of flag, and every session gets it: it
225
- * moves where the *client* keeps its own state, touching nothing a repository
226
- * ships — see {@link SESSION_CONFIG_DIR}.
227
- *
228
- * No `ANTHROPIC_BASE_URL` either: `http-gateway` egress intercepts
229
- * transparently, so the client talks to the real hostname and the gateway sees
230
- * it. Nothing has to be told to use a proxy, which means nothing in the
231
- * container can be told *not* to.
232
- *
233
- * ## `--permission-mode`, and the root guard behind it
234
- *
235
- * The mode is always passed explicitly, never left to the CLI's `default` — see
236
- * {@link file://./config.ts ClaudeCodeConfig.permissionMode} for what an
237
- * unset mode does to a headless session, and why
238
- * {@link DEFAULT_PERMISSION_MODE} is the permissive value rather than a
239
- * concession.
240
- *
241
- * **`IS_SANDBOX=1` ships in the same branch as the flag, and separating the two
242
- * breaks a session harder than passing no flag at all.** The container runs as
243
- * root, and the CLI refuses to bypass its permission checks under uid 0 unless
244
- * that variable is set: it calls `process.exit(1)` **before the first JSON
245
- * line**, with the only explanation on stderr. The failure then surfaces as
246
- * "exited with code 1 without reporting a result" and names nothing. One branch
247
- * below writes both so they cannot drift, and the variable is applied *after* a
248
- * host's `env` so a host cannot unset the thing making its own mode work.
249
- *
250
- * `IS_SANDBOX` has one other documented effect in this client: a repeated API
251
- * `529` stops raising the custom overload error and keeps retrying instead.
252
- * Harmless here — the egress gateway is what decides when to give up.
253
- *
254
- * The alternative is an image that does not run as root, which is a real option
255
- * and a much larger one: the FUSE mount, the checkout and every install path
256
- * currently assume uid 0. If that ever changes, this variable is the line to
257
- * delete.
258
- */
259
- export declare function buildLaunch(options: LaunchOptions): Launch;
260
- /** Where a drain got to. Stored by the caller, so a cut-short drain resumes. */
261
- export interface DrainCursor {
262
- /**
263
- * The exec id this session occupies.
264
- *
265
- * Carried rather than derived so a re-attach cannot compute a different one
266
- * from the run id it happens to have in hand — and because a run's follow-up
267
- * is a second exec, and the cursor says which of the two it names.
268
- */
269
- execId: string;
270
- /** The last event sequence consumed; a resumed drain starts here. */
271
- seq: number;
272
- /**
273
- * The Claude Code session id, from the `init` line — the handle that continues
274
- * this conversation later.
275
- *
276
- * Carried here rather than read off the `result` line alone because the runs
277
- * that most need continuing are the ones that never reach a result: a session
278
- * stopped by its time limit, a cancel or a container rollout reports no result
279
- * at all, and without this the conversation it got half-way through would be
280
- * unreachable. The `init` line arrives in the first seconds, so a session has a
281
- * handle almost from the start — which is why {@link drainRun} offers the
282
- * cursor the moment the id appears instead of waiting out
283
- * {@link CHECKPOINT_MIN_MS}.
284
- */
285
- sessionId?: string;
286
- /** Bytes after the last newline — an incomplete line the next read finishes. */
287
- carry: string;
288
- /** Progress notes emitted so far. The base for the positional keys. */
289
- emitted: number;
290
- /**
291
- * The `result` line, once seen.
292
- *
293
- * Carried because it and the `exit` event are two separate events and a
294
- * drain can be cut short between them. Without this a run whose result
295
- * arrived just before an eviction reports a terminal outcome with **no
296
- * result** after it resumes — and a successful session would be reported as
297
- * one that died without a word.
298
- */
299
- result?: ClaudeCodeResult;
300
- /**
301
- * A bounded slice of the session's stderr, for the runs that explain
302
- * themselves nowhere else.
303
- *
304
- * stderr is not the protocol stream and is never parsed as one — see
305
- * `consume` below. It is kept for exactly one case: a process that exits
306
- * **before** emitting a `result` line, where the JSON stream holds nothing and
307
- * the only account of what happened is the text the CLI printed on its way
308
- * out. A bad flag, a refused permission mode under root, a Node crash. Without
309
- * this the caller can only report an exit code.
310
- *
311
- * Carried on the cursor rather than kept local because the death and the exit
312
- * event can land either side of an eviction.
313
- */
314
- stderr?: string;
315
- /**
316
- * When the pending thinking block began streaming, on this drain's clock —
317
- * see `ParsedStream.thinkingFrom` in `./events.ts`.
318
- */
319
- thinkingFrom?: number;
320
- }
321
- /** A cursor for a session that has not started yet. */
322
- export declare function freshCursor(execId: string): DrainCursor;
323
- export type DrainOutcome = {
324
- done: false;
325
- cursor: DrainCursor;
326
- progress: NoteData[];
327
- /**
328
- * The bucket as the client reported it **during this drain**, if it did.
329
- *
330
- * Deliberately not carried on the cursor the way `result` is. A caller
331
- * acts on this against whichever credential is leading *now*, so a reading
332
- * replayed on every resumed drain would let one old observation retire a
333
- * credential that was not even in use when it was taken. Absent means
334
- * "this drain learned nothing", which is the honest answer.
335
- */
336
- rateLimit?: RateLimitInfo;
337
- } | {
338
- done: true;
339
- cursor: DrainCursor;
340
- progress: NoteData[];
341
- /** The bucket as reported **in this drain**. See the `done: false` arm. */
342
- rateLimit?: RateLimitInfo;
343
- exitCode: number;
344
- /** Absent when the process died without ever emitting a `result` line. */
345
- result?: ClaudeCodeResult;
346
- /**
347
- * What the process printed on stderr, bounded — only when there is no
348
- * `result` to explain the exit. Present on the terminal outcome alone
349
- * because that is the only place a caller has nothing else to report.
350
- */
351
- stderr?: string;
352
- };
353
- export interface DrainOptions {
354
- /**
355
- * Called with each note as it is parsed, rather than with all of them when the
356
- * drain ends — a session runs for minutes, and a caller with nothing but the
357
- * outcome would learn everything at once, once the work is over.
358
- *
359
- * Notes are still returned on the outcome as well, so a caller that files them
360
- * from here must drop what it is handed back, or the same note is filed twice.
361
- * The keys are positional, so the transcript would dedupe it, but paying for
362
- * the second one to be discarded is not a plan.
363
- *
364
- * **Never awaited inside the read loop.** Calls are chained instead, so they
365
- * stay in order without stalling the read of the container's stream for as
366
- * long as the session is talkative, and the chain is settled before the drain
367
- * returns.
368
- */
369
- onProgress?: (note: NoteData) => void | Promise<void>;
370
- /**
371
- * Called with a cursor that is safe to store, no more often than
372
- * {@link CHECKPOINT_MIN_MS}.
373
- *
374
- * **Only meaningful alongside `onProgress`, and that coupling is the whole
375
- * point.** A cursor names a position whose notes have *already been handed to
376
- * the sink* — it rides the same chain, after them — so resuming from it loses
377
- * nothing the parent was sent. A note the sink **rejects** ends the
378
- * checkpoints for the rest of the drain, so no stored cursor passes it: a
379
- * drain cut after that resumes from before it, and files it again.
380
- *
381
- * Without it, a drain that dies mid-stream resumes from the start of the
382
- * session. One production run lost six and a half minutes of a session that
383
- * way and re-derived it by replaying the whole stream.
384
- */
385
- onCheckpoint?: (cursor: DrainCursor) => void | Promise<void>;
386
- /**
387
- * Stops the drain now: the cursor comes back as `done: false`, and the
388
- * session goes on running — stopping *it* is the caller's, with
389
- * {@link killRun}. Not honoured once the process has exited, because the read
390
- * to the end carries the filesystem sync; see the loop in {@link drainRun}.
391
- */
392
- signal?: AbortSignal;
393
- now?: () => number;
394
- }
395
- /** Whether a thrown value is the runtime refusing to reuse a live exec id. */
396
- export declare function isExecBusy(err: unknown): boolean;
397
- /**
398
- * Whether a thrown value means the session this cursor names is gone for good.
399
- *
400
- * `EEXEC_LOST` is the runtime saying the container that held the execution was
401
- * replaced. The session died with it, and no attachment will ever find it — so
402
- * unlike `EEXEC_BUSY`, which is a live session reached the wrong way, there is
403
- * nothing to recover and retrying only discovers that again.
404
- */
405
- export declare function isExecLost(err: unknown): boolean;
406
- /**
407
- * {@link attachRun} giving up on a subscriber that was never released. Unlike
408
- * a transient failure, nothing retries it: the run fails, and its host stops
409
- * the session.
410
- */
411
- export declare class AttachGivenUpError extends Error {
412
- name: string;
413
- }
414
- /**
415
- * Start a session, detached.
416
- *
417
- * **Falls back to attaching when the id is already live**, which is not a
418
- * nicety. `start` spawns and then drains for minutes, so a turn cut anywhere
419
- * after the spawn is recovered with no cursor stored yet — and
420
- * `@cloudflare/computer` refuses to reuse an id whose execution is still
421
- * running (`EEXEC_BUSY`). Without this the recovery throws, every later one
422
- * throws the same way, and a perfectly healthy session in the container becomes
423
- * unreachable.
424
- *
425
- * **The sync stays on the default, and `defer` is not an option here.** A
426
- * deferred exec skips the post-command pull entirely and settles the outcome
427
- * from the cursor instead — and its `cancel` reads the stream to the end first,
428
- * so stopping a drain would block until the session exits. Both halves are
429
- * exactly what this drain is built not to do.
430
- */
431
- export declare function startRun(runtime: SessionRuntime, options: LaunchOptions & {
432
- execId: string;
433
- timeoutMs: number;
434
- /** Stops the fallback's wait — see {@link AttachOptions.signal}. */
435
- signal?: AbortSignal;
436
- }): Promise<WorkspaceRuntimeExecHandle<"utf8">>;
437
- export interface AttachOptions {
438
- /**
439
- * How long to wait out a subscriber that has not been released: the
440
- * session's own `timeoutMs`.
441
- *
442
- * Giving up fails the run, and a failed run is stopped by its host — so a
443
- * shorter bound kills a healthy session, and past this one the session is
444
- * over anyway. How long a release actually took is logged when the attach
445
- * lands.
446
- */
447
- maxWaitMs: number;
448
- /** The clock and the wait, injectable so a spec can drive the bound. */
449
- now?: () => number;
450
- wait?: (ms: number) => Promise<void>;
451
- /** Stops the wait — see `DrainOptions.signal`. */
452
- signal?: AbortSignal;
453
- }
454
- /**
455
- * Re-attach to a session this isolate did not start.
456
- *
457
- * **Waits out a subscriber the previous drain has not released yet**, and that
458
- * wait is the point of this function rather than a refinement of it. The
459
- * alternative is not "fail fast" — it is spending a recovery to discover a
460
- * condition that clears on its own in a second, when recoveries are what a
461
- * deploy, a severed stub and a network drop have to be covered out of. A
462
- * deployment lost a twenty-one-minute session exactly that way — consecutive
463
- * attach races used the retries up, and the redeploy that followed had no
464
- * attempt left to be retried on. See {@link isExecSubscribed}.
465
- *
466
- * Everything else is rethrown on the first look, `EEXEC_LOST` above all: it is
467
- * the runtime saying the container was replaced, `resume` turns it into a report
468
- * for the model, and a retry loop would sit on it learning nothing.
469
- */
470
- export declare function attachRun(runtime: SessionRuntime, cursor: DrainCursor, options: AttachOptions): Promise<WorkspaceRuntimeExecHandle<"utf8">>;
471
- /**
472
- * Drain a session to its end.
473
- *
474
- * Returns `done: true` once the stream has finished, or `done: false` when the
475
- * caller's signal stopped the drain with the process still running.
476
- */
477
- export declare function drainRun(handle: WorkspaceRuntimeExecHandle<"utf8">, cursor: DrainCursor, options?: DrainOptions): Promise<DrainOutcome>;
478
- /**
479
- * What a session reports on `stderr` when its container went away under it:
480
- * the stream ended with no `exit` event, or a re-attach found the exec gone.
481
- */
482
- export declare function containerLost(printed?: string): string;
483
- /**
484
- * Stop a session.
485
- *
486
- * `SIGTERM` rather than `SIGKILL`: Claude Code aborts the turn, kills its own
487
- * Bash process tree, runs its `SessionEnd` hooks and exits 143. A `SIGKILL`
488
- * leaves whatever the session had spawned still running in a container the
489
- * workspace will keep using.
490
- */
491
- export declare function killRun(runtime: SessionRuntime, execId: string): Promise<void>;