@dynamicagents/plugins 0.12.0 → 0.14.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 (132) hide show
  1. package/README.md +58 -77
  2. package/dist/browser/index.d.ts +0 -2
  3. package/dist/browser/index.js +21 -27
  4. package/dist/claude-code/cards.d.ts +55 -0
  5. package/dist/claude-code/cards.js +283 -0
  6. package/dist/claude-code/config.d.ts +28 -63
  7. package/dist/claude-code/config.js +0 -11
  8. package/dist/claude-code/egress.d.ts +8 -1
  9. package/dist/claude-code/egress.js +42 -4
  10. package/dist/claude-code/events.d.ts +106 -9
  11. package/dist/claude-code/events.js +201 -56
  12. package/dist/claude-code/github.d.ts +39 -0
  13. package/dist/claude-code/github.js +82 -0
  14. package/dist/claude-code/index.d.ts +16 -90
  15. package/dist/claude-code/index.js +14 -276
  16. package/dist/claude-code/model.d.ts +152 -0
  17. package/dist/claude-code/model.js +366 -0
  18. package/dist/claude-code/run.d.ts +230 -116
  19. package/dist/claude-code/run.js +380 -167
  20. package/dist/claude-code/session.d.ts +131 -0
  21. package/dist/claude-code/session.js +288 -0
  22. package/dist/claude-code/spec.d.ts +46 -0
  23. package/dist/claude-code/spec.js +83 -0
  24. package/dist/claude-code/verified.d.ts +15 -0
  25. package/dist/claude-code/verified.js +15 -0
  26. package/dist/computer/context.d.ts +1 -5
  27. package/dist/computer/context.js +7 -10
  28. package/dist/computer/file-lock.js +5 -4
  29. package/dist/computer/gate.d.ts +4 -4
  30. package/dist/computer/gate.js +5 -5
  31. package/dist/computer/index.d.ts +40 -258
  32. package/dist/computer/index.js +71 -324
  33. package/dist/computer/paths.d.ts +36 -16
  34. package/dist/computer/paths.js +42 -29
  35. package/dist/computer/proxy.d.ts +45 -0
  36. package/dist/computer/proxy.js +234 -0
  37. package/dist/computer/render.d.ts +1 -40
  38. package/dist/computer/render.js +2 -68
  39. package/dist/computer/tools-exec.js +12 -13
  40. package/dist/computer/tools-file.d.ts +9 -1
  41. package/dist/computer/tools-file.js +22 -82
  42. package/dist/computer/{tools-find.d.ts → tools-grep.d.ts} +1 -1
  43. package/dist/computer/tools-grep.js +129 -0
  44. package/dist/repo/checkout.d.ts +4 -5
  45. package/dist/repo/checkout.js +31 -8
  46. package/dist/repo/context.d.ts +35 -9
  47. package/dist/repo/context.js +101 -49
  48. package/dist/repo/index.d.ts +73 -28
  49. package/dist/repo/index.js +112 -96
  50. package/dist/repo/tools-checks.d.ts +3 -0
  51. package/dist/repo/tools-checks.js +112 -0
  52. package/dist/repo/tools-clone.js +1 -1
  53. package/dist/repo/tools-pr.d.ts +14 -0
  54. package/dist/repo/{tools-forge.js → tools-pr.js} +53 -36
  55. package/dist/repo/tools-review.d.ts +9 -0
  56. package/dist/repo/tools-review.js +67 -47
  57. package/dist/repo/tools-worktree.js +144 -60
  58. package/dist/repo/tools-worktrees.d.ts +12 -0
  59. package/dist/repo/tools-worktrees.js +48 -0
  60. package/dist/repo/url.d.ts +2 -2
  61. package/dist/repo/url.js +7 -7
  62. package/dist/scratch/index.d.ts +4 -4
  63. package/dist/scratch/index.js +12 -11
  64. package/dist/{computer → workspace}/advisory.d.ts +4 -4
  65. package/dist/{computer → workspace}/advisory.js +2 -2
  66. package/dist/{computer/host → workspace}/ca-trust.d.ts +8 -1
  67. package/dist/{computer/host → workspace}/ca-trust.js +12 -3
  68. package/dist/{computer/host → workspace}/container-deps.d.ts +4 -0
  69. package/dist/{computer/host → workspace}/container-deps.js +26 -1
  70. package/dist/{computer/host → workspace}/container-fault.d.ts +3 -3
  71. package/dist/{computer/host → workspace}/container-fault.js +23 -8
  72. package/dist/workspace/deps-snapshot.d.ts +110 -0
  73. package/dist/workspace/deps-snapshot.js +424 -0
  74. package/dist/workspace/exec.d.ts +94 -0
  75. package/dist/workspace/exec.js +153 -0
  76. package/dist/workspace/format.d.ts +36 -0
  77. package/dist/workspace/format.js +57 -0
  78. package/dist/{computer/host → workspace}/git-host.d.ts +21 -4
  79. package/dist/{computer/host → workspace}/git-host.js +72 -2
  80. package/dist/{computer/host → workspace}/git-identity.d.ts +1 -1
  81. package/dist/{computer/host → workspace}/git-identity.js +1 -1
  82. package/dist/workspace/index.d.ts +44 -47
  83. package/dist/workspace/index.js +52 -112
  84. package/dist/{computer/host → workspace}/install-job.d.ts +53 -4
  85. package/dist/{computer/host → workspace}/install-job.js +346 -178
  86. package/dist/{computer → workspace}/install.d.ts +17 -8
  87. package/dist/{computer → workspace}/install.js +24 -6
  88. package/dist/{computer/host/workspace.d.ts → workspace/object.d.ts} +125 -27
  89. package/dist/{computer/host/workspace.js → workspace/object.js} +341 -58
  90. package/dist/workspace/open.d.ts +95 -0
  91. package/dist/workspace/open.js +63 -0
  92. package/dist/workspace/read.d.ts +16 -0
  93. package/dist/workspace/read.js +22 -0
  94. package/dist/{computer → workspace}/shell.d.ts +5 -5
  95. package/dist/{computer → workspace}/shell.js +6 -6
  96. package/dist/{computer/host → workspace}/wake.d.ts +3 -1
  97. package/package.json +17 -37
  98. package/dist/arc-agi/analysis.d.ts +0 -322
  99. package/dist/arc-agi/analysis.js +0 -802
  100. package/dist/arc-agi/client.d.ts +0 -82
  101. package/dist/arc-agi/client.js +0 -113
  102. package/dist/arc-agi/game-tools.d.ts +0 -24
  103. package/dist/arc-agi/game-tools.js +0 -26
  104. package/dist/arc-agi/index.d.ts +0 -40
  105. package/dist/arc-agi/index.js +0 -175
  106. package/dist/arc-agi/main-agent.d.ts +0 -24
  107. package/dist/arc-agi/main-agent.js +0 -62
  108. package/dist/arc-agi/recipe.d.ts +0 -48
  109. package/dist/arc-agi/recipe.js +0 -97
  110. package/dist/arc-agi/scorecard.d.ts +0 -118
  111. package/dist/arc-agi/scorecard.js +0 -163
  112. package/dist/arc-agi/soul.d.ts +0 -29
  113. package/dist/arc-agi/soul.js +0 -79
  114. package/dist/arc-agi/store.d.ts +0 -153
  115. package/dist/arc-agi/store.js +0 -215
  116. package/dist/arc-agi/tools.d.ts +0 -36
  117. package/dist/arc-agi/tools.js +0 -574
  118. package/dist/arc-agi/types.d.ts +0 -211
  119. package/dist/arc-agi/types.js +0 -19
  120. package/dist/claude-code/recipe.d.ts +0 -53
  121. package/dist/claude-code/recipe.js +0 -100
  122. package/dist/computer/read.d.ts +0 -133
  123. package/dist/computer/read.js +0 -200
  124. package/dist/computer/tools-find.js +0 -216
  125. package/dist/recall/index.d.ts +0 -105
  126. package/dist/recall/index.js +0 -181
  127. package/dist/repo/tools-forge.d.ts +0 -4
  128. package/dist/triage/index.d.ts +0 -360
  129. package/dist/triage/index.js +0 -311
  130. /package/dist/{computer/host → workspace}/sync.d.ts +0 -0
  131. /package/dist/{computer/host → workspace}/sync.js +0 -0
  132. /package/dist/{computer/host → workspace}/wake.js +0 -0
@@ -10,7 +10,7 @@
10
10
  *
11
11
  * ## Why this exists at all
12
12
  *
13
- * The alternative is a sentence in the subagent's soul — "install dependencies
13
+ * The alternative is a sentence in the sub-agent's soul — "install dependencies
14
14
  * before you do anything else" — and a standard with no command attached is one a
15
15
  * model satisfies with whichever check is cheapest: edit a README, run
16
16
  * `prettier --check` on that one file, report the change verified, and never run
@@ -36,16 +36,16 @@ export interface InstallProbe {
36
36
  * Where the install has got to, as the host reports it and the tools read it.
37
37
  *
38
38
  * Declared here rather than in the host because both sides depend on it and
39
- * neither owns the other: the Durable Object runs the job, and `sb_exec` refuses
39
+ * neither owns the other: the Durable Object runs the job, and `bash` refuses
40
40
  * to run against a tree that is still being built. A shape they agreed on
41
41
  * informally would drift, and the drift would show up as a shell command running
42
42
  * halfway through an `npm ci`.
43
43
  *
44
- * ## Why it is core's `JobState` with one field intersected in
44
+ * ## Why it is the host's `JobState` with one field intersected in
45
45
  *
46
- * Core owns the *choreography* around a job a Durable Object drives through its
47
- * alarm — arming, the single-flight guard, the staleness bound, the generation
48
- * marker a drain checks before it writes. This package owns what an install
46
+ * Core's `/job` owns the *choreography* around a job a Durable Object drives
47
+ * through its alarm — arming, the single-flight guard, the staleness bound, the
48
+ * generation a drain writes under. This package owns what an install
49
49
  * specifically **is**: which package manager, which lockfile, what counts as
50
50
  * skippable. Splitting them along that line is what lets a second job on the
51
51
  * same object — a coding-agent run, say — reuse every rule without inheriting
@@ -146,7 +146,7 @@ export declare function resolveInstallCommand(fs: InstallProbe, dir: string, pla
146
146
  * from `pnpm@9` to `pnpm@10`, or add a dependency without regenerating the lock,
147
147
  * and every one of those changes what an install produces while leaving the
148
148
  * lockfile byte-identical. Hashing the lockfile alone calls that a match, skips
149
- * the install, and hands the subagent a `node_modules` that is quietly wrong —
149
+ * the install, and hands the agent a `node_modules` that is quietly wrong —
150
150
  * which surfaces as a missing module in a build, three tool calls later, with
151
151
  * nothing pointing back at the install that never ran.
152
152
  *
@@ -184,6 +184,15 @@ export declare function resolveInstallCommand(fs: InstallProbe, dir: string, pla
184
184
  * A matching fingerprint means "the same install would produce the same tree".
185
185
  * It does **not** mean the tree is there: it is on the container's disk, and
186
186
  * goes with the container. The caller also needs a record that this container
187
- * finished it — see `./host/install-job.ts`.
187
+ * finished it — see `./install-job.ts`.
188
188
  */
189
189
  export declare function installFingerprint(fs: InstallProbe, dir: string, resolution: InstallResolution): Promise<string | null>;
190
+ /**
191
+ * The same digest for a package root an install reached without being pointed
192
+ * at it — a submodule a bootstrap installs, say — where there is no command to
193
+ * fold in, and every lockfile the plan knows stands in for the one it would pick.
194
+ *
195
+ * For `./deps-snapshot.ts`, which restores every root's tree at once and so has
196
+ * to know none of them moved.
197
+ */
198
+ export declare function rootFingerprint(fs: InstallProbe, dir: string, plan: InstallPlan): Promise<string | null>;
@@ -10,7 +10,7 @@
10
10
  *
11
11
  * ## Why this exists at all
12
12
  *
13
- * The alternative is a sentence in the subagent's soul — "install dependencies
13
+ * The alternative is a sentence in the sub-agent's soul — "install dependencies
14
14
  * before you do anything else" — and a standard with no command attached is one a
15
15
  * model satisfies with whichever check is cheapest: edit a README, run
16
16
  * `prettier --check` on that one file, report the change verified, and never run
@@ -96,6 +96,10 @@ function pinnedManager(packageJson) {
96
96
  return undefined;
97
97
  }
98
98
  }
99
+ /** Every lockfile the plan names, each once. */
100
+ function planLockfiles(plan) {
101
+ return [...new Set(plan.rules.flatMap((r) => [...r.lockfiles]))];
102
+ }
99
103
  /**
100
104
  * Every lockfile the plan knows of that is present in `dir`.
101
105
  *
@@ -103,9 +107,8 @@ function pinnedManager(packageJson) {
103
107
  * about which manager it drives.
104
108
  */
105
109
  async function knownLockfiles(fs, dir, plan) {
106
- const names = [...new Set(plan.rules.flatMap((r) => [...r.lockfiles]))];
107
110
  const present = [];
108
- for (const name of names) {
111
+ for (const name of planLockfiles(plan)) {
109
112
  if (await fs.exists(`${dir}/${name}`))
110
113
  present.push(name);
111
114
  }
@@ -221,7 +224,7 @@ async function firstPresent(fs, dir, names) {
221
224
  * from `pnpm@9` to `pnpm@10`, or add a dependency without regenerating the lock,
222
225
  * and every one of those changes what an install produces while leaving the
223
226
  * lockfile byte-identical. Hashing the lockfile alone calls that a match, skips
224
- * the install, and hands the subagent a `node_modules` that is quietly wrong —
227
+ * the install, and hands the agent a `node_modules` that is quietly wrong —
225
228
  * which surfaces as a missing module in a build, three tool calls later, with
226
229
  * nothing pointing back at the install that never ran.
227
230
  *
@@ -259,7 +262,7 @@ async function firstPresent(fs, dir, names) {
259
262
  * A matching fingerprint means "the same install would produce the same tree".
260
263
  * It does **not** mean the tree is there: it is on the container's disk, and
261
264
  * goes with the container. The caller also needs a record that this container
262
- * finished it — see `./host/install-job.ts`.
265
+ * finished it — see `./install-job.ts`.
263
266
  */
264
267
  export async function installFingerprint(fs, dir, resolution) {
265
268
  if (resolution.kind !== "run")
@@ -273,10 +276,25 @@ export async function installFingerprint(fs, dir, resolution) {
273
276
  ...resolution.lockfiles,
274
277
  ...INSTALL_CONFIG_FILES
275
278
  ];
279
+ return await digestFiles(fs, dir, names, resolution.command);
280
+ }
281
+ /**
282
+ * The same digest for a package root an install reached without being pointed
283
+ * at it — a submodule a bootstrap installs, say — where there is no command to
284
+ * fold in, and every lockfile the plan knows stands in for the one it would pick.
285
+ *
286
+ * For `./deps-snapshot.ts`, which restores every root's tree at once and so has
287
+ * to know none of them moved.
288
+ */
289
+ export async function rootFingerprint(fs, dir, plan) {
290
+ return await digestFiles(fs, dir, ["package.json", ...planLockfiles(plan), ...INSTALL_CONFIG_FILES], "");
291
+ }
292
+ /** `prefix`, then every file of `names` present in `dir`; null when none is. */
293
+ async function digestFiles(fs, dir, names, prefix) {
276
294
  // Names as well as contents. Two lockfiles will not collide on content in
277
295
  // practice, but a digest that cannot say *which* file it read is one that
278
296
  // silently depends on the caller resolving them in the same order forever.
279
- let input = resolution.command;
297
+ let input = prefix;
280
298
  let found = false;
281
299
  for (const name of names) {
282
300
  if (!(await fs.exists(`${dir}/${name}`)))
@@ -1,9 +1,10 @@
1
1
  import { DurableObject } from "cloudflare:workers";
2
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";
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";
7
8
  /**
8
9
  * A workspace: one Durable Object, one container, one repository.
9
10
  *
@@ -16,7 +17,7 @@ import type { RepoGitResult } from "../../repo/index.js";
16
17
  * A directory inside the plugin rather than a subpath beside it, so that one
17
18
  * capability stays one import path and a consumer cannot take the tools without
18
19
  * 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
+ * false, so an agent that only calls `bash` carries no container backend and
20
21
  * no isomorphic-git.
21
22
  *
22
23
  * What this file must not do is import the plugin barrel. The barrel re-exports
@@ -29,7 +30,7 @@ import type { RepoGitResult } from "../../repo/index.js";
29
30
  * FUSE at `/workspace`. Commands run against the same tree the Worker reads over
30
31
  * RPC, and the tree outlives the container.
31
32
  *
32
- * **One repository per object**, because `computer` is strictly 1 DO ↔ 1
33
+ * **One repository per object**, because `@cloudflare/computer` is strictly 1 DO ↔ 1
33
34
  * container: the id derives from caller *and* repository (see `workspaceName`),
34
35
  * so two repositories for one caller are two objects and two containers.
35
36
  *
@@ -49,10 +50,11 @@ import type { RepoGitResult } from "../../repo/index.js";
49
50
  * and each carries the reasoning for its own decisions:
50
51
  *
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.
52
54
  * - `./sync.ts` — the host's half of syncing, which nothing else will do.
53
55
  * - `./ca-trust.ts` — making a container able to speak TLS.
54
56
  * - `./git-identity.ts` — who a container's commits belong to.
55
- * - `./git-host.ts` — the operations that hold the forge credential.
57
+ * - `./git-host.ts` — the operations that hold the GitHub credential.
56
58
  *
57
59
  * Each takes a small explicit seam, and that is the test: a module that needed
58
60
  * the whole object back would be a module that did not want extracting.
@@ -63,7 +65,7 @@ export declare const WORKSPACE_DIR = "/workspace";
63
65
  * The Durable Object name for one caller's checkout of one repository.
64
66
  *
65
67
  * 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,
68
+ * the plugin that resolves the stub, the agent that hands it down to sub-agents,
67
69
  * and the cancellation path. A pipe rather than a slash, so the caller half
68
70
  * cannot forge a repository boundary by containing one.
69
71
  *
@@ -76,10 +78,23 @@ export declare const WORKSPACE_DIR = "/workspace";
76
78
  *
77
79
  * `repo` is not always a repository. A host may pass a sentinel through here as
78
80
  * 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
81
+ * object and its own container. Anything that is not a GitHub name works, as long
80
82
  * as no caller could clone something that collides with it.
81
83
  */
82
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;
83
98
  /**
84
99
  * `work`, refused once `ms` pass without it settling. The work itself goes on;
85
100
  * only the wait for it ends — see {@link READY_DEADLINE_MS}.
@@ -97,16 +112,15 @@ declare class WorkspaceContainerHost extends DurableObject<Cloudflare.Env> {
97
112
  }
98
113
  /**
99
114
  * `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.
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}.
104
118
  */
105
119
  declare const WorkspaceContainerBase: typeof WorkspaceContainerHost & (new (...args: any[]) => WorkspaceContainerHost & {
106
120
  getWorkspaceContainer(): import("@cloudflare/computer/backends/container").WorkspaceContainerAPI;
107
121
  });
108
122
  /**
109
- * The forge credential, and who a commit made on this side is attributed to.
123
+ * The GitHub credential, and who a commit made on this side is attributed to.
110
124
  *
111
125
  * Config rather than an env read, because this class cannot name a consumer's
112
126
  * ambient `Env` — it is an interface `wrangler types` generates into *their*
@@ -120,7 +134,7 @@ declare const WorkspaceContainerBase: typeof WorkspaceContainerHost & (new (...a
120
134
  */
121
135
  export interface WorkspaceGitConfig {
122
136
  /**
123
- * The **name** of the binding holding the forge credential — never the
137
+ * The **name** of the binding holding the GitHub credential — never the
124
138
  * credential itself.
125
139
  *
126
140
  * `workspaceConfig()` is an ordinary method on the prototype, and on a Durable
@@ -196,7 +210,7 @@ export interface WorkspaceObjectConfig {
196
210
  egress: WorkspaceEgressPolicy;
197
211
  /** How this deployment installs dependencies for this agent's checkouts. */
198
212
  installPlan: InstallPlan;
199
- /** Log prefix — `coder-workspace`, `claude-coder-workspace`. */
213
+ /** Log prefix — `coding-workspace`, `claude-coordinator-workspace`. */
200
214
  label: string;
201
215
  /**
202
216
  * How long this agent's container stays up after the last command **started**.
@@ -204,14 +218,23 @@ export interface WorkspaceObjectConfig {
204
218
  * A per-agent value because the invariant on {@link CONTAINER_IDLE_MS} — it
205
219
  * must exceed the longest command the shell allows — is an invariant about the
206
220
  * *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
221
+ * is a tool call; `claude-coordinator`'s is a whole `claude -p` session that runs
208
222
  * detached for its entire timeout.
209
223
  *
210
224
  * Omit it for the default. Raise it, never lower it, and raise it whenever the
211
225
  * agent's longest command grows.
212
226
  */
213
227
  containerIdleMs?: number;
214
- /** The forge credential and commit identity — see {@link WorkspaceGitConfig}. */
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}. */
215
238
  git: WorkspaceGitConfig;
216
239
  }
217
240
  /**
@@ -219,14 +242,13 @@ export interface WorkspaceObjectConfig {
219
242
  *
220
243
  * Abstract because a Durable Object class takes no constructor arguments, so
221
244
  * 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.
245
+ * seam, for the same reason Think's own hooks are methods rather than options.
224
246
  *
225
247
  * ## Why `backend` and `#workspace` are lazy
226
248
  *
227
249
  * **Base class fields run before subclass fields**, so as plain fields they
228
250
  * would read `undefined` from any `workspaceConfig()` that touches a subclass
229
- * field — which `ClaudeCoderWorkspaceDO`'s does, for its credential store.
251
+ * field — which `ClaudeCoordinatorWorkspace`'s does, for its credential store.
230
252
  * Memoised getters remove the hazard rather than documenting it, which is what
231
253
  * lets a subclass implement the seam however it likes.
232
254
  */
@@ -236,7 +258,7 @@ export declare abstract class WorkspaceObjectBase<TEnv extends Cloudflare.Env =
236
258
  * This Worker's bindings, as the host's own generated `Env` spells them.
237
259
  *
238
260
  * 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
261
+ * — `claude-coordinator`'s reaches for its credential pool — gets its real type
240
262
  * instead of the base's. `declare` because the field is the runtime's; this
241
263
  * only narrows what TypeScript believes about it.
242
264
  */
@@ -245,11 +267,11 @@ export declare abstract class WorkspaceObjectBase<TEnv extends Cloudflare.Env =
245
267
  * Everything this agent's workspace does differently. Called once, lazily.
246
268
  *
247
269
  * Read through {@link #cfg}, never directly: an implementation may build
248
- * something real — `claude-coder`'s constructs its egress gateway — and this
270
+ * something real — `claude-coordinator`'s constructs its egress gateway — and this
249
271
  * is consulted on the busiest path in the object.
250
272
  */
251
273
  protected abstract workspaceConfig(): WorkspaceObjectConfig;
252
- get backend(): CloudflareContainerBackend;
274
+ get backend(): ContainerBackend;
253
275
  /**
254
276
  * What `getWorkspace(stub)` calls from outside this object.
255
277
  *
@@ -270,11 +292,11 @@ export declare abstract class WorkspaceObjectBase<TEnv extends Cloudflare.Env =
270
292
  *
271
293
  * A stub cannot enforce what the caller does with it: `runtime.exec` on this
272
294
  * one would run against a container with no CA. The exec paths take the other
273
- * method — see `openWorkspaceFs` in `@dynamicagents/plugins/computer`.
295
+ * method — see `openWorkspaceFs` in `./open.ts`.
274
296
  */
275
297
  __getWorkspaceFsStub(): Promise<WorkspaceStub>;
276
298
  /**
277
- * Clone, fetch and push — the operations that need the forge token.
299
+ * Clone, fetch and push — the operations that need the GitHub token.
278
300
  *
279
301
  * The work is `./git-host.ts`, which owns why the credential stays on this
280
302
  * side of the boundary. What stays here is what only this object can do: the
@@ -300,6 +322,12 @@ export declare abstract class WorkspaceObjectBase<TEnv extends Cloudflare.Env =
300
322
  branch: string;
301
323
  allowedHosts: string[];
302
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>;
303
331
  /**
304
332
  * Start this checkout's dependency install, and return without waiting.
305
333
  *
@@ -311,6 +339,76 @@ export declare abstract class WorkspaceObjectBase<TEnv extends Cloudflare.Env =
311
339
  dir: string;
312
340
  repo?: string;
313
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
+ }>;
314
412
  /**
315
413
  * Throw this workspace away if nothing has touched it for `maxIdleMs`.
316
414
  *
@@ -375,7 +473,7 @@ export declare abstract class WorkspaceObjectBase<TEnv extends Cloudflare.Env =
375
473
  checkoutDir(): Promise<string | undefined>;
376
474
  /**
377
475
  * 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.
476
+ * away — the array `bash`, `edit` and the workspace's writes all consult.
379
477
  *
380
478
  * The policy is not here. `deriveAdvisories` decides which facts matter and
381
479
  * how they are worded; this method gathers what only the object can see and