@dynamicagents/plugins 0.11.1 → 0.12.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 +12 -13
- package/dist/arc-agi/analysis.d.ts +16 -30
- package/dist/arc-agi/analysis.js +20 -47
- package/dist/arc-agi/game-tools.d.ts +5 -6
- package/dist/arc-agi/index.d.ts +6 -8
- package/dist/arc-agi/index.js +3 -3
- package/dist/arc-agi/main-agent.d.ts +5 -8
- package/dist/arc-agi/main-agent.js +5 -8
- package/dist/arc-agi/recipe.d.ts +17 -20
- package/dist/arc-agi/recipe.js +17 -20
- package/dist/arc-agi/soul.d.ts +16 -27
- package/dist/arc-agi/soul.js +16 -27
- package/dist/arc-agi/store.d.ts +4 -5
- package/dist/arc-agi/store.js +4 -5
- package/dist/arc-agi/tools.d.ts +1 -1
- package/dist/arc-agi/tools.js +10 -12
- package/dist/arc-agi/types.d.ts +6 -7
- package/dist/claude-code/config.d.ts +88 -11
- package/dist/claude-code/config.js +11 -2
- package/dist/claude-code/credentials.d.ts +21 -9
- package/dist/claude-code/credentials.js +43 -9
- package/dist/claude-code/egress.d.ts +7 -13
- package/dist/claude-code/egress.js +9 -10
- package/dist/claude-code/events.d.ts +47 -0
- package/dist/claude-code/events.js +96 -10
- package/dist/claude-code/index.d.ts +31 -13
- package/dist/claude-code/index.js +62 -15
- package/dist/claude-code/run.d.ts +135 -41
- package/dist/claude-code/run.js +366 -61
- package/dist/computer/advisory.d.ts +31 -18
- package/dist/computer/advisory.js +30 -5
- package/dist/computer/context.d.ts +23 -0
- package/dist/computer/context.js +225 -0
- package/dist/computer/file-lock.d.ts +5 -0
- package/dist/computer/file-lock.js +39 -0
- package/dist/computer/gate.d.ts +8 -8
- package/dist/computer/gate.js +7 -7
- package/dist/computer/host/ca-trust.d.ts +88 -0
- package/dist/computer/host/ca-trust.js +303 -0
- package/dist/computer/host/container-deps.d.ts +54 -0
- package/dist/computer/host/container-deps.js +224 -0
- package/dist/computer/host/container-fault.d.ts +38 -0
- package/dist/computer/host/container-fault.js +58 -0
- package/dist/computer/host/git-host.d.ts +62 -0
- package/dist/computer/host/git-host.js +156 -0
- package/dist/computer/host/git-identity.d.ts +57 -0
- package/dist/computer/host/git-identity.js +147 -0
- package/dist/computer/host/install-job.d.ts +121 -0
- package/dist/computer/host/install-job.js +766 -0
- package/dist/computer/host/sync.d.ts +111 -0
- package/dist/computer/host/sync.js +124 -0
- package/dist/computer/host/wake.d.ts +19 -0
- package/dist/computer/host/wake.js +10 -0
- package/dist/computer/host/workspace.d.ts +424 -0
- package/dist/computer/host/workspace.js +1258 -0
- package/dist/computer/index.d.ts +70 -50
- package/dist/computer/index.js +79 -767
- package/dist/computer/install.d.ts +8 -12
- package/dist/computer/install.js +6 -9
- package/dist/computer/paths.d.ts +21 -16
- package/dist/computer/paths.js +40 -38
- package/dist/computer/read.d.ts +18 -22
- package/dist/computer/read.js +24 -27
- package/dist/computer/render.d.ts +28 -0
- package/dist/computer/render.js +34 -1
- package/dist/computer/shell.d.ts +45 -0
- package/dist/computer/shell.js +80 -0
- package/dist/computer/tools-exec.d.ts +3 -0
- package/dist/computer/tools-exec.js +269 -0
- package/dist/computer/tools-file.d.ts +4 -0
- package/dist/computer/tools-file.js +124 -0
- package/dist/computer/tools-find.d.ts +3 -0
- package/dist/computer/tools-find.js +216 -0
- package/dist/recall/index.d.ts +9 -3
- package/dist/recall/index.js +22 -12
- package/dist/repo/checkout.d.ts +34 -4
- package/dist/repo/checkout.js +36 -1
- package/dist/repo/context.d.ts +109 -0
- package/dist/repo/context.js +530 -0
- package/dist/repo/index.d.ts +6 -29
- package/dist/repo/index.js +17 -1027
- package/dist/repo/tools-clone.d.ts +4 -0
- package/dist/repo/tools-clone.js +192 -0
- package/dist/repo/tools-forge.d.ts +4 -0
- package/dist/repo/tools-forge.js +179 -0
- package/dist/repo/tools-review.d.ts +3 -0
- package/dist/repo/tools-review.js +373 -0
- package/dist/repo/tools-worktree.d.ts +4 -0
- package/dist/repo/tools-worktree.js +221 -0
- package/dist/triage/index.d.ts +6 -1
- package/dist/triage/index.js +32 -23
- package/dist/workspace/index.d.ts +3 -3
- package/dist/workspace/index.js +3 -3
- package/package.json +21 -15
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
import { DurableObject } from "cloudflare:workers";
|
|
2
|
+
import { type WorkspaceEgressPolicy, type WorkspaceStub } from "@cloudflare/computer";
|
|
3
|
+
import { CloudflareContainerBackend } from "@cloudflare/computer/backends/container";
|
|
4
|
+
import { type WorkspaceAdvisory } from "../advisory.js";
|
|
5
|
+
import type { InstallPlan, InstallState } from "../install.js";
|
|
6
|
+
import type { RepoGitResult } from "../../repo/index.js";
|
|
7
|
+
/**
|
|
8
|
+
* A workspace: one Durable Object, one container, one repository.
|
|
9
|
+
*
|
|
10
|
+
* **Shared by every agent in a Worker that has a container.** Each subclasses
|
|
11
|
+
* {@link WorkspaceObjectBase}, supplies a {@link WorkspaceObjectConfig}, and
|
|
12
|
+
* inherits everything else. Keep that seam narrow: it is the complete answer to
|
|
13
|
+
* "what is different about this agent's container", and anything that does not
|
|
14
|
+
* fit through it becomes a second copy of this file.
|
|
15
|
+
*
|
|
16
|
+
* A directory inside the plugin rather than a subpath beside it, so that one
|
|
17
|
+
* capability stays one import path and a consumer cannot take the tools without
|
|
18
|
+
* the object they address. The bundle cost of that is nothing: `sideEffects` is
|
|
19
|
+
* false, so an agent that only calls `sb_exec` carries no container backend and
|
|
20
|
+
* no isomorphic-git.
|
|
21
|
+
*
|
|
22
|
+
* What this file must not do is import the plugin barrel. The barrel re-exports
|
|
23
|
+
* this module, and the class below is built at import time — a cycle would
|
|
24
|
+
* evaluate its base as `undefined`. The imports above reach the leaf modules
|
|
25
|
+
* beside it instead.
|
|
26
|
+
*
|
|
27
|
+
* `@cloudflare/computer` pairs a SQLite-backed virtual filesystem in *this*
|
|
28
|
+
* object's storage with a container running `computerd`, which mounts it over
|
|
29
|
+
* FUSE at `/workspace`. Commands run against the same tree the Worker reads over
|
|
30
|
+
* RPC, and the tree outlives the container.
|
|
31
|
+
*
|
|
32
|
+
* **One repository per object**, because `computer` is strictly 1 DO ↔ 1
|
|
33
|
+
* container: the id derives from caller *and* repository (see `workspaceName`),
|
|
34
|
+
* so two repositories for one caller are two objects and two containers.
|
|
35
|
+
*
|
|
36
|
+
* **It constructs `Workspace` rather than using `withWorkspace`.** The mixin
|
|
37
|
+
* stores the `Workspace` under a module-private symbol the package does not
|
|
38
|
+
* export, so a method on the object cannot reach it — and what the host is
|
|
39
|
+
* required to do needs exactly that: driving an outstanding pull (the library
|
|
40
|
+
* owns no alarm and schedules nothing of its own), and the direct `runtime`
|
|
41
|
+
* access the detached install needs. So this object owns the `Workspace` and
|
|
42
|
+
* implements the one method the mixin otherwise provides,
|
|
43
|
+
* `__getWorkspaceStub`. Callers outside see no difference.
|
|
44
|
+
*
|
|
45
|
+
* ## What is here, and what is a module next door
|
|
46
|
+
*
|
|
47
|
+
* This file is the Durable Object: the wake map, the deadlines, the RPC surface
|
|
48
|
+
* and the wiring between them. The work each of those drives has its own home,
|
|
49
|
+
* and each carries the reasoning for its own decisions:
|
|
50
|
+
*
|
|
51
|
+
* - `./install-job.ts` — when a dependency install runs, and every guard on it.
|
|
52
|
+
* - `./sync.ts` — the host's half of syncing, which nothing else will do.
|
|
53
|
+
* - `./ca-trust.ts` — making a container able to speak TLS.
|
|
54
|
+
* - `./git-identity.ts` — who a container's commits belong to.
|
|
55
|
+
* - `./git-host.ts` — the operations that hold the forge credential.
|
|
56
|
+
*
|
|
57
|
+
* Each takes a small explicit seam, and that is the test: a module that needed
|
|
58
|
+
* the whole object back would be a module that did not want extracting.
|
|
59
|
+
*/
|
|
60
|
+
/** Where every checkout lives, inside the container and in the VFS. */
|
|
61
|
+
export declare const WORKSPACE_DIR = "/workspace";
|
|
62
|
+
/**
|
|
63
|
+
* The Durable Object name for one caller's checkout of one repository.
|
|
64
|
+
*
|
|
65
|
+
* Exported because several places must agree on it and none can see the others:
|
|
66
|
+
* the plugin that resolves the stub, the agent that hands it down to subagents,
|
|
67
|
+
* and the cancellation path. A pipe rather than a slash, so the caller half
|
|
68
|
+
* cannot forge a repository boundary by containing one.
|
|
69
|
+
*
|
|
70
|
+
* `repo` is undefined only before the first `repo_clone` or `scratch_open` of a
|
|
71
|
+
* session — what a task works in is model-chosen, so there is genuinely nothing
|
|
72
|
+
* to key on until it has chosen. That window resolves to a caller-level
|
|
73
|
+
* workspace, which is never worked in: `beforeCheckout` sets the repository
|
|
74
|
+
* before any git runs, and `scratch_open` sets its sentinel before anything
|
|
75
|
+
* resolves a name.
|
|
76
|
+
*
|
|
77
|
+
* `repo` is not always a repository. A host may pass a sentinel through here as
|
|
78
|
+
* one — a scratchpad is modelled that way, which is what keys it to its own
|
|
79
|
+
* object and its own container. Anything that is not a forge name works, as long
|
|
80
|
+
* as no caller could clone something that collides with it.
|
|
81
|
+
*/
|
|
82
|
+
export declare function workspaceName(callerKey: string, repo?: string): string;
|
|
83
|
+
/**
|
|
84
|
+
* `work`, refused once `ms` pass without it settling. The work itself goes on;
|
|
85
|
+
* only the wait for it ends — see {@link READY_DEADLINE_MS}.
|
|
86
|
+
*/
|
|
87
|
+
export declare function readyWithin(work: Promise<void>, ms: number): Promise<void>;
|
|
88
|
+
/**
|
|
89
|
+
* Named rather than the anonymous class expression an app would write here.
|
|
90
|
+
*
|
|
91
|
+
* This package emits declarations, and `DurableObject` brings `ctx` and `env` in
|
|
92
|
+
* protected — which makes the mixin's return type unnameable in a `.d.ts` and
|
|
93
|
+
* fails the build with TS4094. A named base gives the emitted type something to
|
|
94
|
+
* refer to. It costs one identifier and is invisible to a consumer.
|
|
95
|
+
*/
|
|
96
|
+
declare class WorkspaceContainerHost extends DurableObject<Cloudflare.Env> {
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* `withWorkspaceContainer` adds one method, `getWorkspaceContainer()`, over
|
|
100
|
+
* `this.ctx.container` — the runtime's own container handle. There is no
|
|
101
|
+
* `@cloudflare/containers` `Container` subclass here and so no `sleepAfter`:
|
|
102
|
+
* idle shutdown is this object's job, and it lands on the wake map with
|
|
103
|
+
* everything else.
|
|
104
|
+
*/
|
|
105
|
+
declare const WorkspaceContainerBase: typeof WorkspaceContainerHost & (new (...args: any[]) => WorkspaceContainerHost & {
|
|
106
|
+
getWorkspaceContainer(): import("@cloudflare/computer/backends/container").WorkspaceContainerAPI;
|
|
107
|
+
});
|
|
108
|
+
/**
|
|
109
|
+
* The forge credential, and who a commit made on this side is attributed to.
|
|
110
|
+
*
|
|
111
|
+
* Config rather than an env read, because this class cannot name a consumer's
|
|
112
|
+
* ambient `Env` — it is an interface `wrangler types` generates into *their*
|
|
113
|
+
* app, and a plugin that named it would compile only against the one Worker that
|
|
114
|
+
* happened to spell its bindings that way.
|
|
115
|
+
*
|
|
116
|
+
* It is also the honest direction. These are the repo plugin's secrets, declared
|
|
117
|
+
* by that plugin's `requires.secrets`, and a workspace holds them only because
|
|
118
|
+
* git runs on this side of the container boundary — see
|
|
119
|
+
* {@link file://./git-host.ts} for why it has to.
|
|
120
|
+
*/
|
|
121
|
+
export interface WorkspaceGitConfig {
|
|
122
|
+
/**
|
|
123
|
+
* The **name** of the binding holding the forge credential — never the
|
|
124
|
+
* credential itself.
|
|
125
|
+
*
|
|
126
|
+
* `workspaceConfig()` is an ordinary method on the prototype, and on a Durable
|
|
127
|
+
* Object `protected` is a typechecker's opinion rather than a runtime
|
|
128
|
+
* boundary: anything holding the namespace can call it. A config carrying the
|
|
129
|
+
* token would therefore hand it to any caller that asked — exactly what
|
|
130
|
+
* {@link file://./git-host.ts} exists to prevent, since the credential is
|
|
131
|
+
* supposed to be unreachable from anywhere but the moment git authenticates.
|
|
132
|
+
*
|
|
133
|
+
* So the config names the binding and the object reads it. Naming a secret by
|
|
134
|
+
* string is what the plugin contract's `requires.secrets` already does, and it
|
|
135
|
+
* is the only form available here: this package cannot name a consumer's
|
|
136
|
+
* ambient `Env`.
|
|
137
|
+
*
|
|
138
|
+
* An unset binding reads `undefined`, which means an unauthenticated request
|
|
139
|
+
* rather than a throw — that is what lets a workspace with no token still
|
|
140
|
+
* clone a public repository.
|
|
141
|
+
*/
|
|
142
|
+
tokenBinding: string;
|
|
143
|
+
/**
|
|
144
|
+
* Who a commit is attributed to — on this side, and in the container.
|
|
145
|
+
*
|
|
146
|
+
* Two things read it: this object's git client, and `./git-identity.ts`,
|
|
147
|
+
* which writes it into the container's system config so a repository the
|
|
148
|
+
* container made for itself is attributed rather than nameless.
|
|
149
|
+
*
|
|
150
|
+
* **The repo plugin is not one of them.** It resolves `RepoConfig.author`
|
|
151
|
+
* independently, with a generic fallback of its own, and nothing in either
|
|
152
|
+
* package checks the two agree — so a commit *can* be attributed differently
|
|
153
|
+
* depending on which side made it, and the only thing preventing that is a
|
|
154
|
+
* consumer answering both from one place. A deployment's fallback for an
|
|
155
|
+
* unset binding belongs where that binding is read; this takes the resolved
|
|
156
|
+
* answer.
|
|
157
|
+
*/
|
|
158
|
+
author: {
|
|
159
|
+
name: string;
|
|
160
|
+
email: string;
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* What one workspace object does not share with the next.
|
|
165
|
+
*
|
|
166
|
+
* Everything else about a workspace is identical between agents, which is why
|
|
167
|
+
* this interface is short and why it is worth having at all: a seam this narrow
|
|
168
|
+
* makes "what is different about this agent's container" a question with a
|
|
169
|
+
* complete answer in one place.
|
|
170
|
+
*/
|
|
171
|
+
export interface WorkspaceObjectConfig {
|
|
172
|
+
/**
|
|
173
|
+
* The wrangler Durable Object binding this class is bound as.
|
|
174
|
+
*
|
|
175
|
+
* Not cosmetic and not derivable: `computerd` dials **back** through it. The
|
|
176
|
+
* backend builds the container's loopback from this name plus the object id,
|
|
177
|
+
* so a wrong one produces a container that starts, mounts nothing and fails
|
|
178
|
+
* at the first command with no mention of a binding.
|
|
179
|
+
*/
|
|
180
|
+
binding: string;
|
|
181
|
+
/**
|
|
182
|
+
* Where this workspace's container may send traffic, and through what.
|
|
183
|
+
*
|
|
184
|
+
* `direct` is the plain behaviour: the container's own network position.
|
|
185
|
+
* `http-gateway` routes **everything** through a `Fetcher` this Worker
|
|
186
|
+
* supplies, which is what puts the Worker on the model path — see
|
|
187
|
+
* `@dynamicagents/plugins/claude-code`.
|
|
188
|
+
*
|
|
189
|
+
* **Required in practice, and its absence is silent.** It is a policy that
|
|
190
|
+
* defaults to `{ mode: "none" }`, and the backend derives the container's
|
|
191
|
+
* network flag from it. Omit it and the container
|
|
192
|
+
* comes up with no network at all: the workspace mounts, commands run, and
|
|
193
|
+
* the install dies on a registry it cannot reach with nothing naming egress
|
|
194
|
+
* as the cause.
|
|
195
|
+
*/
|
|
196
|
+
egress: WorkspaceEgressPolicy;
|
|
197
|
+
/** How this deployment installs dependencies for this agent's checkouts. */
|
|
198
|
+
installPlan: InstallPlan;
|
|
199
|
+
/** Log prefix — `coder-workspace`, `claude-coder-workspace`. */
|
|
200
|
+
label: string;
|
|
201
|
+
/**
|
|
202
|
+
* How long this agent's container stays up after the last command **started**.
|
|
203
|
+
*
|
|
204
|
+
* A per-agent value because the invariant on {@link CONTAINER_IDLE_MS} — it
|
|
205
|
+
* must exceed the longest command the shell allows — is an invariant about the
|
|
206
|
+
* *agent*, and the two differ by a factor of four. The coder's longest command
|
|
207
|
+
* is a tool call; `claude-coder`'s is a whole `claude -p` session that runs
|
|
208
|
+
* detached for its entire timeout.
|
|
209
|
+
*
|
|
210
|
+
* Omit it for the default. Raise it, never lower it, and raise it whenever the
|
|
211
|
+
* agent's longest command grows.
|
|
212
|
+
*/
|
|
213
|
+
containerIdleMs?: number;
|
|
214
|
+
/** The forge credential and commit identity — see {@link WorkspaceGitConfig}. */
|
|
215
|
+
git: WorkspaceGitConfig;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* One caller's checkout of one repository, and the container that mounts it.
|
|
219
|
+
*
|
|
220
|
+
* Abstract because a Durable Object class takes no constructor arguments, so
|
|
221
|
+
* per-agent configuration cannot arrive that way. {@link workspaceConfig} is the
|
|
222
|
+
* seam, and it is the shape core's own `RecipeSubagentBase.subagentRuntime`
|
|
223
|
+
* uses for exactly the same reason.
|
|
224
|
+
*
|
|
225
|
+
* ## Why `backend` and `#workspace` are lazy
|
|
226
|
+
*
|
|
227
|
+
* **Base class fields run before subclass fields**, so as plain fields they
|
|
228
|
+
* would read `undefined` from any `workspaceConfig()` that touches a subclass
|
|
229
|
+
* field — which `ClaudeCoderWorkspaceDO`'s does, for its credential store.
|
|
230
|
+
* Memoised getters remove the hazard rather than documenting it, which is what
|
|
231
|
+
* lets a subclass implement the seam however it likes.
|
|
232
|
+
*/
|
|
233
|
+
export declare abstract class WorkspaceObjectBase<TEnv extends Cloudflare.Env = Cloudflare.Env> extends WorkspaceContainerBase {
|
|
234
|
+
#private;
|
|
235
|
+
/**
|
|
236
|
+
* This Worker's bindings, as the host's own generated `Env` spells them.
|
|
237
|
+
*
|
|
238
|
+
* Re-declared rather than inherited so a subclass reading a binding of its own
|
|
239
|
+
* — `claude-coder`'s reaches for its credential pool — gets its real type
|
|
240
|
+
* instead of the base's. `declare` because the field is the runtime's; this
|
|
241
|
+
* only narrows what TypeScript believes about it.
|
|
242
|
+
*/
|
|
243
|
+
readonly env: TEnv;
|
|
244
|
+
/**
|
|
245
|
+
* Everything this agent's workspace does differently. Called once, lazily.
|
|
246
|
+
*
|
|
247
|
+
* Read through {@link #cfg}, never directly: an implementation may build
|
|
248
|
+
* something real — `claude-coder`'s constructs its egress gateway — and this
|
|
249
|
+
* is consulted on the busiest path in the object.
|
|
250
|
+
*/
|
|
251
|
+
protected abstract workspaceConfig(): WorkspaceObjectConfig;
|
|
252
|
+
get backend(): CloudflareContainerBackend;
|
|
253
|
+
/**
|
|
254
|
+
* What `getWorkspace(stub)` calls from outside this object.
|
|
255
|
+
*
|
|
256
|
+
* The one piece of `withWorkspace` reimplemented here — see the file comment
|
|
257
|
+
* for why the mixin is not used. `ready()` first, because the stub is only
|
|
258
|
+
* meaningful once the workspace has opened its store.
|
|
259
|
+
*/
|
|
260
|
+
__getWorkspaceStub(): Promise<WorkspaceStub>;
|
|
261
|
+
/**
|
|
262
|
+
* The same workspace, for a caller that will only touch the filesystem.
|
|
263
|
+
*
|
|
264
|
+
* **The container is not started, and that is the whole difference.** The
|
|
265
|
+
* filesystem is this object's own SQLite, so a read or write of it needs no
|
|
266
|
+
* container and an absent one cannot block it. {@link __getWorkspaceStub} adds
|
|
267
|
+
* `#ready()`, and the first command in a fresh container re-pushes the whole
|
|
268
|
+
* tree before it runs, with `timeoutMs` reaching the spawned process and
|
|
269
|
+
* nothing earlier.
|
|
270
|
+
*
|
|
271
|
+
* A stub cannot enforce what the caller does with it: `runtime.exec` on this
|
|
272
|
+
* one would run against a container with no CA. The exec paths take the other
|
|
273
|
+
* method — see `openWorkspaceFs` in `@dynamicagents/plugins/computer`.
|
|
274
|
+
*/
|
|
275
|
+
__getWorkspaceFsStub(): Promise<WorkspaceStub>;
|
|
276
|
+
/**
|
|
277
|
+
* Clone, fetch and push — the operations that need the forge token.
|
|
278
|
+
*
|
|
279
|
+
* The work is `./git-host.ts`, which owns why the credential stays on this
|
|
280
|
+
* side of the boundary. What stays here is what only this object can do: the
|
|
281
|
+
* entry-point bookkeeping, and making the workspace current before git reads
|
|
282
|
+
* it.
|
|
283
|
+
*/
|
|
284
|
+
gitClone(req: {
|
|
285
|
+
url: string;
|
|
286
|
+
dir: string;
|
|
287
|
+
allowedHosts: string[];
|
|
288
|
+
branch?: string;
|
|
289
|
+
depth?: number;
|
|
290
|
+
}): Promise<RepoGitResult>;
|
|
291
|
+
gitFetch(req: {
|
|
292
|
+
url: string;
|
|
293
|
+
dir: string;
|
|
294
|
+
allowedHosts: string[];
|
|
295
|
+
depth?: number;
|
|
296
|
+
}): Promise<RepoGitResult>;
|
|
297
|
+
gitPush(req: {
|
|
298
|
+
url: string;
|
|
299
|
+
dir: string;
|
|
300
|
+
branch: string;
|
|
301
|
+
allowedHosts: string[];
|
|
302
|
+
}): Promise<RepoGitResult>;
|
|
303
|
+
/**
|
|
304
|
+
* Start this checkout's dependency install, and return without waiting.
|
|
305
|
+
*
|
|
306
|
+
* Called from `repo_clone` through the repo plugin's `afterCheckout` hook, so
|
|
307
|
+
* it runs inside a model turn — see `./install-job.ts` for why the drain's owner
|
|
308
|
+
* is the thing that matters here.
|
|
309
|
+
*/
|
|
310
|
+
startInstall(req: {
|
|
311
|
+
dir: string;
|
|
312
|
+
repo?: string;
|
|
313
|
+
}): Promise<InstallState>;
|
|
314
|
+
/**
|
|
315
|
+
* Throw this workspace away if nothing has touched it for `maxIdleMs`.
|
|
316
|
+
*
|
|
317
|
+
* Re-checks the clock rather than trusting the caller: the alarm may have been
|
|
318
|
+
* armed a week ago, and a use since then must win. Safe to call from anywhere
|
|
319
|
+
* for the same reason, which is what lets the agent's cron poke it as a
|
|
320
|
+
* backstop without needing to know anything.
|
|
321
|
+
*/
|
|
322
|
+
reclaimIfIdle(maxIdleMs?: number): Promise<{
|
|
323
|
+
reclaimed: boolean;
|
|
324
|
+
idleMs: number;
|
|
325
|
+
bytes: number;
|
|
326
|
+
}>;
|
|
327
|
+
/**
|
|
328
|
+
* Record what was checked out here, and say whether it is actually visible.
|
|
329
|
+
*
|
|
330
|
+
* **The single writer of {@link CHECKOUT_KEY}**, called by the two paths that
|
|
331
|
+
* know a checkout landed: the repo plugin's `afterCheckout` hook, which fires
|
|
332
|
+
* only once a tree is established, and `scratch_open`, which fires once
|
|
333
|
+
* `git init` has exited 0.
|
|
334
|
+
*
|
|
335
|
+
* **Why the checkout is recorded apart from the install**, which call sites
|
|
336
|
+
* point here for rather than restating: an install is conditional and a
|
|
337
|
+
* checkout is not. `resolveInstallCommand` skips a checkout it finds nothing
|
|
338
|
+
* to install in — any without a `package.json` — so a path written only as
|
|
339
|
+
* part of an install is missing exactly there. What that costs is not an
|
|
340
|
+
* optimisation: {@link checkoutDir} is how a delegated session is told where
|
|
341
|
+
* to work, so a repository can clone perfectly, report itself correctly
|
|
342
|
+
* through the repo tools, and never be worked in. The install keeps its own
|
|
343
|
+
* context for the mirror-image reason — what to re-run on a cold container has
|
|
344
|
+
* a different lifetime from what is on disk.
|
|
345
|
+
*
|
|
346
|
+
* Returns the probe as well as the path, so a caller learns in one round trip
|
|
347
|
+
* whether the tree is visible rather than discovering it a delegation later.
|
|
348
|
+
*/
|
|
349
|
+
noteCheckout(req: {
|
|
350
|
+
dir: string;
|
|
351
|
+
repo?: string;
|
|
352
|
+
kind: "repo" | "scratch";
|
|
353
|
+
}): Promise<{
|
|
354
|
+
dir: string;
|
|
355
|
+
present: boolean;
|
|
356
|
+
}>;
|
|
357
|
+
/**
|
|
358
|
+
* Where the work is — a directory holding a git repository, or nothing.
|
|
359
|
+
*
|
|
360
|
+
* Two callers depend on that being the meaning rather than "a path somebody
|
|
361
|
+
* wrote down once": a Claude Code session takes it as its cwd, and
|
|
362
|
+
* `discardWorkingTree` runs `git reset --hard` in it. Both want the same
|
|
363
|
+
* question answered, and neither can recover from a confident wrong answer.
|
|
364
|
+
*
|
|
365
|
+
* So it is **probed, not remembered**. A record is where to look; `.git` being
|
|
366
|
+
* there is what makes the answer true. That costs one local read of this
|
|
367
|
+
* object's own SQLite — everything under the checkout is durable, `.git`
|
|
368
|
+
* included — and it is what turns a stale record into `undefined` instead of
|
|
369
|
+
* into a session started in a directory that is no longer a checkout.
|
|
370
|
+
*
|
|
371
|
+
* The record is the only source. A workspace that has never recorded one
|
|
372
|
+
* answers `undefined` until its next checkout does, which `repo_clone` does on
|
|
373
|
+
* any tree it can fetch and reset.
|
|
374
|
+
*/
|
|
375
|
+
checkoutDir(): Promise<string | undefined>;
|
|
376
|
+
/**
|
|
377
|
+
* Everything currently true about this workspace that a caller must not assume
|
|
378
|
+
* away — the array `sb_exec`, `sb_write` and `sb_edit` all consult.
|
|
379
|
+
*
|
|
380
|
+
* The policy is not here. `deriveAdvisories` decides which facts matter and
|
|
381
|
+
* how they are worded; this method gathers what only the object can see and
|
|
382
|
+
* hands it over. That split is why a host cannot get the severity of its own
|
|
383
|
+
* workspace wrong.
|
|
384
|
+
*
|
|
385
|
+
* **Nothing that starts a long job belongs on this path**, and the rule is
|
|
386
|
+
* sharper here than anywhere else in the object because every tool call reads
|
|
387
|
+
* it. `startInstall` in particular must never be reached from here: it hands
|
|
388
|
+
* its drain to `ctx.waitUntil`, whose lifetime is the invocation's, and an
|
|
389
|
+
* invocation on this path is a tool call that returns in milliseconds. The
|
|
390
|
+
* drain outlives its owner, dies mid-`npm ci` with "WritableStream RPC stub
|
|
391
|
+
* was disposed without calling close()", and leaves a half-written tree.
|
|
392
|
+
*
|
|
393
|
+
* A missing dependency tree arms an install here, which runs in the alarm,
|
|
394
|
+
* which owns no request and outlives every RPC. Here because a command reads
|
|
395
|
+
* this before its `#ready()` starts a container, so the gate holds it for the
|
|
396
|
+
* install rather than letting it outrun one.
|
|
397
|
+
*/
|
|
398
|
+
advisories(): Promise<readonly WorkspaceAdvisory[]>;
|
|
399
|
+
/**
|
|
400
|
+
* `computerd`'s outbound WebSocket upgrade, on its way back in.
|
|
401
|
+
*
|
|
402
|
+
* The container dials the loopback rather than the other way round, so this
|
|
403
|
+
* object is the server for its own container's capnweb session. Everything
|
|
404
|
+
* else on this object is RPC; this is the only HTTP it speaks.
|
|
405
|
+
*/
|
|
406
|
+
fetch(request: Request): Promise<Response>;
|
|
407
|
+
/**
|
|
408
|
+
* Every durable wake-up this object has, dispatched from the one alarm.
|
|
409
|
+
*
|
|
410
|
+
* **This must not throw.** The runtime retries a failing alarm handler a
|
|
411
|
+
* bounded number of times and then stops for good — so a throw here would
|
|
412
|
+
* eventually take every *future* wake-up down with it, permanently, and the
|
|
413
|
+
* only symptom is that nothing ever happens again.
|
|
414
|
+
*
|
|
415
|
+
* Nothing else belongs here. Each reason to wake is a registered callback the
|
|
416
|
+
* scheduler dispatches by name, so this method neither matches on keys nor
|
|
417
|
+
* catches per-callback failures — the scheduler retries a failing callback and
|
|
418
|
+
* reports one that fails for good through `onError`. Nor does it sweep for a
|
|
419
|
+
* schedule that neither rescheduled nor cleared itself: a one-shot row is
|
|
420
|
+
* dropped when it runs, so it cannot stay due forever.
|
|
421
|
+
*/
|
|
422
|
+
alarm(): Promise<void>;
|
|
423
|
+
}
|
|
424
|
+
export {};
|