@dynamicagents/plugins 0.12.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +58 -77
- package/dist/browser/index.d.ts +0 -2
- package/dist/browser/index.js +21 -27
- package/dist/claude-code/cards.d.ts +53 -0
- package/dist/claude-code/cards.js +272 -0
- package/dist/claude-code/config.d.ts +28 -63
- package/dist/claude-code/config.js +0 -11
- package/dist/claude-code/egress.d.ts +8 -1
- package/dist/claude-code/egress.js +42 -4
- package/dist/claude-code/events.d.ts +106 -9
- package/dist/claude-code/events.js +201 -56
- package/dist/claude-code/github.d.ts +39 -0
- package/dist/claude-code/github.js +82 -0
- package/dist/claude-code/index.d.ts +16 -90
- package/dist/claude-code/index.js +14 -276
- package/dist/claude-code/model.d.ts +152 -0
- package/dist/claude-code/model.js +342 -0
- package/dist/claude-code/run.d.ts +209 -112
- package/dist/claude-code/run.js +339 -138
- package/dist/claude-code/session.d.ts +131 -0
- package/dist/claude-code/session.js +285 -0
- package/dist/claude-code/spec.d.ts +46 -0
- package/dist/claude-code/spec.js +83 -0
- package/dist/claude-code/verified.d.ts +15 -0
- package/dist/claude-code/verified.js +15 -0
- package/dist/computer/context.d.ts +1 -5
- package/dist/computer/context.js +7 -10
- package/dist/computer/file-lock.js +5 -4
- package/dist/computer/gate.d.ts +4 -4
- package/dist/computer/gate.js +5 -5
- package/dist/computer/index.d.ts +40 -258
- package/dist/computer/index.js +71 -324
- package/dist/computer/paths.d.ts +36 -16
- package/dist/computer/paths.js +42 -29
- package/dist/computer/proxy.d.ts +45 -0
- package/dist/computer/proxy.js +234 -0
- package/dist/computer/render.d.ts +1 -40
- package/dist/computer/render.js +2 -68
- package/dist/computer/tools-exec.js +12 -13
- package/dist/computer/tools-file.d.ts +9 -1
- package/dist/computer/tools-file.js +22 -82
- package/dist/computer/{tools-find.d.ts → tools-grep.d.ts} +1 -1
- package/dist/computer/tools-grep.js +129 -0
- package/dist/repo/checkout.d.ts +4 -5
- package/dist/repo/checkout.js +31 -8
- package/dist/repo/context.d.ts +35 -9
- package/dist/repo/context.js +101 -49
- package/dist/repo/index.d.ts +73 -28
- package/dist/repo/index.js +112 -96
- package/dist/repo/tools-checks.d.ts +3 -0
- package/dist/repo/tools-checks.js +112 -0
- package/dist/repo/tools-clone.js +1 -1
- package/dist/repo/tools-pr.d.ts +14 -0
- package/dist/repo/{tools-forge.js → tools-pr.js} +53 -36
- package/dist/repo/tools-review.d.ts +9 -0
- package/dist/repo/tools-review.js +67 -47
- package/dist/repo/tools-worktree.js +144 -60
- package/dist/repo/tools-worktrees.d.ts +12 -0
- package/dist/repo/tools-worktrees.js +48 -0
- package/dist/repo/url.d.ts +2 -2
- package/dist/repo/url.js +7 -7
- package/dist/scratch/index.d.ts +4 -4
- package/dist/scratch/index.js +12 -11
- package/dist/{computer → workspace}/advisory.d.ts +4 -4
- package/dist/{computer → workspace}/advisory.js +2 -2
- package/dist/{computer/host → workspace}/ca-trust.d.ts +8 -1
- package/dist/{computer/host → workspace}/ca-trust.js +12 -3
- package/dist/{computer/host → workspace}/container-fault.d.ts +3 -3
- package/dist/{computer/host → workspace}/container-fault.js +23 -8
- package/dist/workspace/exec.d.ts +94 -0
- package/dist/workspace/exec.js +153 -0
- package/dist/workspace/format.d.ts +36 -0
- package/dist/workspace/format.js +57 -0
- package/dist/{computer/host → workspace}/git-host.d.ts +21 -4
- package/dist/{computer/host → workspace}/git-host.js +72 -2
- package/dist/{computer/host → workspace}/git-identity.d.ts +1 -1
- package/dist/{computer/host → workspace}/git-identity.js +1 -1
- package/dist/workspace/index.d.ts +43 -47
- package/dist/workspace/index.js +52 -112
- package/dist/{computer/host → workspace}/install-job.d.ts +4 -4
- package/dist/{computer/host → workspace}/install-job.js +276 -176
- package/dist/{computer → workspace}/install.d.ts +8 -8
- package/dist/{computer → workspace}/install.js +3 -3
- package/dist/{computer/host/workspace.d.ts → workspace/object.d.ts} +105 -27
- package/dist/{computer/host/workspace.js → workspace/object.js} +217 -48
- package/dist/workspace/open.d.ts +95 -0
- package/dist/workspace/open.js +63 -0
- package/dist/workspace/read.d.ts +16 -0
- package/dist/workspace/read.js +22 -0
- package/dist/{computer → workspace}/shell.d.ts +5 -5
- package/dist/{computer → workspace}/shell.js +6 -6
- package/dist/{computer/host → workspace}/wake.d.ts +1 -1
- package/package.json +16 -36
- package/dist/arc-agi/analysis.d.ts +0 -322
- package/dist/arc-agi/analysis.js +0 -802
- package/dist/arc-agi/client.d.ts +0 -82
- package/dist/arc-agi/client.js +0 -113
- package/dist/arc-agi/game-tools.d.ts +0 -24
- package/dist/arc-agi/game-tools.js +0 -26
- package/dist/arc-agi/index.d.ts +0 -40
- package/dist/arc-agi/index.js +0 -175
- package/dist/arc-agi/main-agent.d.ts +0 -24
- package/dist/arc-agi/main-agent.js +0 -62
- package/dist/arc-agi/recipe.d.ts +0 -48
- package/dist/arc-agi/recipe.js +0 -97
- package/dist/arc-agi/scorecard.d.ts +0 -118
- package/dist/arc-agi/scorecard.js +0 -163
- package/dist/arc-agi/soul.d.ts +0 -29
- package/dist/arc-agi/soul.js +0 -79
- package/dist/arc-agi/store.d.ts +0 -153
- package/dist/arc-agi/store.js +0 -215
- package/dist/arc-agi/tools.d.ts +0 -36
- package/dist/arc-agi/tools.js +0 -574
- package/dist/arc-agi/types.d.ts +0 -211
- package/dist/arc-agi/types.js +0 -19
- package/dist/claude-code/recipe.d.ts +0 -53
- package/dist/claude-code/recipe.js +0 -100
- package/dist/computer/read.d.ts +0 -133
- package/dist/computer/read.js +0 -200
- package/dist/computer/tools-find.js +0 -216
- package/dist/recall/index.d.ts +0 -105
- package/dist/recall/index.js +0 -181
- package/dist/repo/tools-forge.d.ts +0 -4
- package/dist/triage/index.d.ts +0 -360
- package/dist/triage/index.js +0 -311
- /package/dist/{computer/host → workspace}/container-deps.d.ts +0 -0
- /package/dist/{computer/host → workspace}/container-deps.js +0 -0
- /package/dist/{computer/host → workspace}/sync.d.ts +0 -0
- /package/dist/{computer/host → workspace}/sync.js +0 -0
- /package/dist/{computer/host → workspace}/wake.js +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { WorkspaceRuntimeExecHandle, WorkspaceRuntimeExecOptions, WorkspaceRuntimeGetOptions, WorkspaceRuntimeKillOptions } from "@cloudflare/computer";
|
|
2
|
-
import type {
|
|
2
|
+
import type { NoteData } from "@dynamicagents/core/subagent";
|
|
3
3
|
import { type ClaudeCodeResult, type RateLimitInfo } from "./events.js";
|
|
4
4
|
import { type EffortLevel, type PermissionMode } from "./config.js";
|
|
5
5
|
/**
|
|
6
|
-
* Launching Claude Code in the workspace container, and draining it
|
|
6
|
+
* Launching Claude Code in the workspace container, and draining it to its end.
|
|
7
7
|
*
|
|
8
|
-
* ## One
|
|
8
|
+
* ## One sub-agent run is one `claude -p` session
|
|
9
9
|
*
|
|
10
10
|
* Not one turn, and not one tool call. The unit has to be substantial because of
|
|
11
11
|
* what an invocation costs before it does anything: the harness carries an
|
|
@@ -14,19 +14,21 @@ import { type EffortLevel, type PermissionMode } from "./config.js";
|
|
|
14
14
|
*
|
|
15
15
|
* ## Detached, then re-attached — never owned by a request
|
|
16
16
|
*
|
|
17
|
-
* The run is spawned under an exec id and left running
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
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`.
|
|
21
23
|
*
|
|
22
24
|
* ## The cursor
|
|
23
25
|
*
|
|
24
26
|
* `getExec(id, { resume })` accepts `"tail"`, `"full"` **or an event sequence
|
|
25
|
-
* number**, and the number is what this uses.
|
|
26
|
-
*
|
|
27
|
-
* arbitrary tail. Replay still happens when a
|
|
28
|
-
*
|
|
29
|
-
*
|
|
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.
|
|
30
32
|
*
|
|
31
33
|
* The cursor also carries the **exec id** and the **parsed result**, and both
|
|
32
34
|
* are there for reasons that only show up under concurrency or retry — see
|
|
@@ -51,20 +53,24 @@ export declare const CLAUDE_EXEC_PREFIX = "claude-code-run";
|
|
|
51
53
|
/**
|
|
52
54
|
* The exec id one session occupies.
|
|
53
55
|
*
|
|
54
|
-
* **Per
|
|
55
|
-
* one Durable Object and one container, but
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
* would
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
* is simply not to share the id.
|
|
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.
|
|
62
63
|
*
|
|
63
|
-
* Fixed *per
|
|
64
|
+
* Fixed *per run*, though, because the point is still to find it again: an
|
|
64
65
|
* isolate that dies mid-drain leaves the session running in the container, and
|
|
65
|
-
* `getExec` is how the next
|
|
66
|
+
* `getExec` is how the next drain re-attaches instead of starting a second one.
|
|
66
67
|
*/
|
|
67
|
-
export declare function execIdFor(
|
|
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;
|
|
68
74
|
/**
|
|
69
75
|
* What the container is given instead of a credential.
|
|
70
76
|
*
|
|
@@ -77,8 +83,35 @@ export declare function execIdFor(subtaskId: string | number): string;
|
|
|
77
83
|
* invites a future reader to "fix" it by putting the real one there.
|
|
78
84
|
*/
|
|
79
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";
|
|
80
113
|
export interface LaunchOptions {
|
|
81
|
-
/** The
|
|
114
|
+
/** The run's prompt — the whole of what this session is asked to do. */
|
|
82
115
|
prompt: string;
|
|
83
116
|
/** Where the checkout is. The session runs with this as its cwd. */
|
|
84
117
|
dir: string;
|
|
@@ -120,6 +153,55 @@ export interface LaunchOptions {
|
|
|
120
153
|
name: string;
|
|
121
154
|
email: string;
|
|
122
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;
|
|
123
205
|
}
|
|
124
206
|
export interface Launch {
|
|
125
207
|
command: string;
|
|
@@ -129,17 +211,19 @@ export interface Launch {
|
|
|
129
211
|
* Build the command and environment for one session.
|
|
130
212
|
*
|
|
131
213
|
* `--output-format stream-json` with `--verbose`, because the stream is the only
|
|
132
|
-
* way to report progress before the run ends and a run
|
|
133
|
-
*
|
|
214
|
+
* way to report progress before the run ends, and a run lasts for minutes.
|
|
215
|
+
* `--verbose` is required: without it Claude Code emits
|
|
134
216
|
* only the final result even in stream mode.
|
|
135
217
|
*
|
|
136
|
-
* Note what is **absent**. No `--bare
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
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}.
|
|
143
227
|
*
|
|
144
228
|
* No `ANTHROPIC_BASE_URL` either: `http-gateway` egress intercepts
|
|
145
229
|
* transparently, so the client talks to the real hostname and the gateway sees
|
|
@@ -173,17 +257,32 @@ export interface Launch {
|
|
|
173
257
|
* delete.
|
|
174
258
|
*/
|
|
175
259
|
export declare function buildLaunch(options: LaunchOptions): Launch;
|
|
176
|
-
/** Where a drain got to.
|
|
260
|
+
/** Where a drain got to. Stored by the caller, so a cut-short drain resumes. */
|
|
177
261
|
export interface DrainCursor {
|
|
178
262
|
/**
|
|
179
263
|
* The exec id this session occupies.
|
|
180
264
|
*
|
|
181
265
|
* Carried rather than derived so a re-attach cannot compute a different one
|
|
182
|
-
* from the
|
|
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.
|
|
183
268
|
*/
|
|
184
269
|
execId: string;
|
|
185
|
-
/** The last event sequence consumed;
|
|
270
|
+
/** The last event sequence consumed; a resumed drain starts here. */
|
|
186
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;
|
|
187
286
|
/** Bytes after the last newline — an incomplete line the next read finishes. */
|
|
188
287
|
carry: string;
|
|
189
288
|
/** Progress notes emitted so far. The base for the positional keys. */
|
|
@@ -191,11 +290,11 @@ export interface DrainCursor {
|
|
|
191
290
|
/**
|
|
192
291
|
* The `result` line, once seen.
|
|
193
292
|
*
|
|
194
|
-
* Carried because it and the `exit` event are two separate events and a
|
|
195
|
-
* can
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
*
|
|
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.
|
|
199
298
|
*/
|
|
200
299
|
result?: ClaudeCodeResult;
|
|
201
300
|
/**
|
|
@@ -210,31 +309,36 @@ export interface DrainCursor {
|
|
|
210
309
|
* this the caller can only report an exit code.
|
|
211
310
|
*
|
|
212
311
|
* Carried on the cursor rather than kept local because the death and the exit
|
|
213
|
-
* event can land
|
|
312
|
+
* event can land either side of an eviction.
|
|
214
313
|
*/
|
|
215
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;
|
|
216
320
|
}
|
|
217
321
|
/** A cursor for a session that has not started yet. */
|
|
218
322
|
export declare function freshCursor(execId: string): DrainCursor;
|
|
219
323
|
export type DrainOutcome = {
|
|
220
324
|
done: false;
|
|
221
325
|
cursor: DrainCursor;
|
|
222
|
-
progress:
|
|
326
|
+
progress: NoteData[];
|
|
223
327
|
/**
|
|
224
|
-
* The bucket as the client reported it **during this
|
|
328
|
+
* The bucket as the client reported it **during this drain**, if it did.
|
|
225
329
|
*
|
|
226
330
|
* Deliberately not carried on the cursor the way `result` is. A caller
|
|
227
331
|
* acts on this against whichever credential is leading *now*, so a reading
|
|
228
|
-
* replayed on every
|
|
229
|
-
*
|
|
230
|
-
* "this
|
|
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.
|
|
231
335
|
*/
|
|
232
336
|
rateLimit?: RateLimitInfo;
|
|
233
337
|
} | {
|
|
234
338
|
done: true;
|
|
235
339
|
cursor: DrainCursor;
|
|
236
|
-
progress:
|
|
237
|
-
/** The bucket as reported **in this
|
|
340
|
+
progress: NoteData[];
|
|
341
|
+
/** The bucket as reported **in this drain**. See the `done: false` arm. */
|
|
238
342
|
rateLimit?: RateLimitInfo;
|
|
239
343
|
exitCode: number;
|
|
240
344
|
/** Absent when the process died without ever emitting a `result` line. */
|
|
@@ -247,110 +351,99 @@ export type DrainOutcome = {
|
|
|
247
351
|
stderr?: string;
|
|
248
352
|
};
|
|
249
353
|
export interface DrainOptions {
|
|
250
|
-
/**
|
|
251
|
-
* How long this chunk may block before checkpointing and yielding.
|
|
252
|
-
*
|
|
253
|
-
* **This is the coder path's soft limit**, justified the same way core's
|
|
254
|
-
* `CHUNK_SOFT_MS` is — by the step timeout — but checked as a deadline on
|
|
255
|
-
* reading the session's stdout stream rather than between turns, because a
|
|
256
|
-
* `claude -p` session runs its own loop inside the container and there are no
|
|
257
|
-
* core-visible turns to stop between. The stream is the only synchronisation
|
|
258
|
-
* point there is. {@link file://./config.ts ClaudeCodeConfig.windowMs} holds
|
|
259
|
-
* how the default is sized against that timeout, what the headroom it leaves
|
|
260
|
-
* is for, and why that headroom is an expectation rather than a guarantee.
|
|
261
|
-
*
|
|
262
|
-
* It is also what stops a run burning its whole chunk allowance in seconds: a
|
|
263
|
-
* drain that returned the moment it had nothing to read would exhaust
|
|
264
|
-
* `MAX_CHUNKS_PER_BRANCH` before the session finished thinking.
|
|
265
|
-
*
|
|
266
|
-
* **It is not the reporting interval**, and reading it as one is the mistake
|
|
267
|
-
* {@link DrainOptions.onProgress} exists to remove: a session that finishes
|
|
268
|
-
* inside a single window reaches no boundary at all, so a caller with nothing
|
|
269
|
-
* but the outcome learns everything at once, once the work is over.
|
|
270
|
-
*/
|
|
271
|
-
windowMs: number;
|
|
272
354
|
/**
|
|
273
355
|
* Called with each note as it is parsed, rather than with all of them when the
|
|
274
|
-
*
|
|
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.
|
|
275
358
|
*
|
|
276
|
-
* Notes are still returned on the outcome as well, so a caller that
|
|
277
|
-
* here must drop what it is handed back, or the same note is
|
|
278
|
-
* keys are positional, so the
|
|
279
|
-
* second
|
|
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.
|
|
280
363
|
*
|
|
281
|
-
* **Never awaited inside the read loop.**
|
|
282
|
-
*
|
|
283
|
-
*
|
|
284
|
-
*
|
|
285
|
-
* before the drain returns.
|
|
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.
|
|
286
368
|
*/
|
|
287
|
-
onProgress?: (
|
|
369
|
+
onProgress?: (note: NoteData) => void | Promise<void>;
|
|
288
370
|
/**
|
|
289
|
-
* Called with a cursor that is safe to
|
|
371
|
+
* Called with a cursor that is safe to store, no more often than
|
|
290
372
|
* {@link CHECKPOINT_MIN_MS}.
|
|
291
373
|
*
|
|
292
374
|
* **Only meaningful alongside `onProgress`, and that coupling is the whole
|
|
293
|
-
* point.** A
|
|
294
|
-
*
|
|
295
|
-
*
|
|
296
|
-
*
|
|
297
|
-
*
|
|
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.
|
|
298
380
|
*
|
|
299
|
-
* Without it, a
|
|
300
|
-
*
|
|
301
|
-
*
|
|
302
|
-
* replaying the whole stream.
|
|
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.
|
|
303
384
|
*/
|
|
304
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;
|
|
305
393
|
now?: () => number;
|
|
306
394
|
}
|
|
395
|
+
/** Whether a thrown value is the runtime refusing to reuse a live exec id. */
|
|
396
|
+
export declare function isExecBusy(err: unknown): boolean;
|
|
307
397
|
/**
|
|
308
398
|
* Whether a thrown value means the session this cursor names is gone for good.
|
|
309
399
|
*
|
|
310
400
|
* `EEXEC_LOST` is the runtime saying the container that held the execution was
|
|
311
401
|
* replaced. The session died with it, and no attachment will ever find it — so
|
|
312
402
|
* unlike `EEXEC_BUSY`, which is a live session reached the wrong way, there is
|
|
313
|
-
* nothing to recover and retrying only
|
|
403
|
+
* nothing to recover and retrying only discovers that again.
|
|
314
404
|
*/
|
|
315
405
|
export declare function isExecLost(err: unknown): boolean;
|
|
316
406
|
/**
|
|
317
407
|
* Start a session, detached.
|
|
318
408
|
*
|
|
319
409
|
* **Falls back to attaching when the id is already live**, which is not a
|
|
320
|
-
* nicety. `start` spawns and then drains for minutes, so a
|
|
321
|
-
*
|
|
322
|
-
*
|
|
323
|
-
*
|
|
410
|
+
* nicety. `start` spawns and then drains for minutes, so a turn cut anywhere
|
|
411
|
+
* after the spawn is recovered with no cursor stored yet — and
|
|
412
|
+
* `@cloudflare/computer` refuses to reuse an id whose execution is still
|
|
413
|
+
* running (`EEXEC_BUSY`). Without this the recovery throws, every later one
|
|
324
414
|
* throws the same way, and a perfectly healthy session in the container becomes
|
|
325
415
|
* unreachable.
|
|
326
416
|
*
|
|
327
417
|
* **The sync stays on the default, and `defer` is not an option here.** A
|
|
328
418
|
* deferred exec skips the post-command pull entirely and settles the outcome
|
|
329
419
|
* from the cursor instead — and its `cancel` reads the stream to the end first,
|
|
330
|
-
* so
|
|
331
|
-
*
|
|
420
|
+
* so stopping a drain would block until the session exits. Both halves are
|
|
421
|
+
* exactly what this drain is built not to do.
|
|
332
422
|
*/
|
|
333
423
|
export declare function startRun(runtime: SessionRuntime, options: LaunchOptions & {
|
|
334
424
|
execId: string;
|
|
335
425
|
timeoutMs: number;
|
|
426
|
+
/** Stops the fallback's wait — see {@link AttachOptions.signal}. */
|
|
427
|
+
signal?: AbortSignal;
|
|
336
428
|
}): Promise<WorkspaceRuntimeExecHandle<"utf8">>;
|
|
337
429
|
/** The clock and the wait, injectable so a spec can drive the bound. */
|
|
338
430
|
export interface AttachOptions {
|
|
339
431
|
now?: () => number;
|
|
340
432
|
wait?: (ms: number) => Promise<void>;
|
|
433
|
+
/** Stops the wait — see `DrainOptions.signal`. */
|
|
434
|
+
signal?: AbortSignal;
|
|
341
435
|
}
|
|
342
436
|
/**
|
|
343
437
|
* Re-attach to a session this isolate did not start.
|
|
344
438
|
*
|
|
345
|
-
* **Waits out a subscriber the previous
|
|
439
|
+
* **Waits out a subscriber the previous drain has not released yet**, and that
|
|
346
440
|
* wait is the point of this function rather than a refinement of it. The
|
|
347
|
-
* alternative is not "fail fast" — it is spending a
|
|
348
|
-
* condition that clears on its own in a second, when
|
|
349
|
-
*
|
|
350
|
-
*
|
|
351
|
-
*
|
|
352
|
-
*
|
|
353
|
-
* followed had no attempt left to be retried on. See {@link isExecSubscribed}.
|
|
441
|
+
* alternative is not "fail fast" — it is spending a recovery to discover a
|
|
442
|
+
* condition that clears on its own in a second, when recoveries are what a
|
|
443
|
+
* deploy, a severed stub and a network drop have to be covered out of. A
|
|
444
|
+
* deployment lost a twenty-one-minute session exactly that way — consecutive
|
|
445
|
+
* attach races used the retries up, and the redeploy that followed had no
|
|
446
|
+
* attempt left to be retried on. See {@link isExecSubscribed}.
|
|
354
447
|
*
|
|
355
448
|
* Everything else is rethrown on the first look, `EEXEC_LOST` above all: it is
|
|
356
449
|
* the runtime saying the container was replaced, `resume` turns it into a report
|
|
@@ -359,13 +452,17 @@ export interface AttachOptions {
|
|
|
359
452
|
*/
|
|
360
453
|
export declare function attachRun(runtime: SessionRuntime, cursor: DrainCursor, options?: AttachOptions): Promise<WorkspaceRuntimeExecHandle<"utf8">>;
|
|
361
454
|
/**
|
|
362
|
-
* Drain a session
|
|
455
|
+
* Drain a session to its end.
|
|
363
456
|
*
|
|
364
|
-
* Returns `done:
|
|
365
|
-
*
|
|
366
|
-
|
|
457
|
+
* Returns `done: true` once the stream has finished, or `done: false` when the
|
|
458
|
+
* caller's signal stopped the drain with the process still running.
|
|
459
|
+
*/
|
|
460
|
+
export declare function drainRun(handle: WorkspaceRuntimeExecHandle<"utf8">, cursor: DrainCursor, options?: DrainOptions): Promise<DrainOutcome>;
|
|
461
|
+
/**
|
|
462
|
+
* What a session reports on `stderr` when its container went away under it:
|
|
463
|
+
* the stream ended with no `exit` event, or a re-attach found the exec gone.
|
|
367
464
|
*/
|
|
368
|
-
export declare function
|
|
465
|
+
export declare function containerLost(printed?: string): string;
|
|
369
466
|
/**
|
|
370
467
|
* Stop a session.
|
|
371
468
|
*
|