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