@dynamicagents/plugins 0.12.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +58 -77
- package/dist/browser/index.d.ts +0 -2
- package/dist/browser/index.js +21 -27
- package/dist/claude-code/cards.d.ts +53 -0
- package/dist/claude-code/cards.js +272 -0
- package/dist/claude-code/config.d.ts +28 -63
- package/dist/claude-code/config.js +0 -11
- package/dist/claude-code/egress.d.ts +8 -1
- package/dist/claude-code/egress.js +42 -4
- package/dist/claude-code/events.d.ts +106 -9
- package/dist/claude-code/events.js +201 -56
- package/dist/claude-code/github.d.ts +39 -0
- package/dist/claude-code/github.js +82 -0
- package/dist/claude-code/index.d.ts +16 -90
- package/dist/claude-code/index.js +14 -276
- package/dist/claude-code/model.d.ts +152 -0
- package/dist/claude-code/model.js +342 -0
- package/dist/claude-code/run.d.ts +209 -112
- package/dist/claude-code/run.js +339 -138
- package/dist/claude-code/session.d.ts +131 -0
- package/dist/claude-code/session.js +285 -0
- package/dist/claude-code/spec.d.ts +46 -0
- package/dist/claude-code/spec.js +83 -0
- package/dist/claude-code/verified.d.ts +15 -0
- package/dist/claude-code/verified.js +15 -0
- package/dist/computer/context.d.ts +1 -5
- package/dist/computer/context.js +7 -10
- package/dist/computer/file-lock.js +5 -4
- package/dist/computer/gate.d.ts +4 -4
- package/dist/computer/gate.js +5 -5
- package/dist/computer/index.d.ts +40 -258
- package/dist/computer/index.js +71 -324
- package/dist/computer/paths.d.ts +36 -16
- package/dist/computer/paths.js +42 -29
- package/dist/computer/proxy.d.ts +45 -0
- package/dist/computer/proxy.js +234 -0
- package/dist/computer/render.d.ts +1 -40
- package/dist/computer/render.js +2 -68
- package/dist/computer/tools-exec.js +12 -13
- package/dist/computer/tools-file.d.ts +9 -1
- package/dist/computer/tools-file.js +22 -82
- package/dist/computer/{tools-find.d.ts → tools-grep.d.ts} +1 -1
- package/dist/computer/tools-grep.js +129 -0
- package/dist/repo/checkout.d.ts +4 -5
- package/dist/repo/checkout.js +31 -8
- package/dist/repo/context.d.ts +35 -9
- package/dist/repo/context.js +101 -49
- package/dist/repo/index.d.ts +73 -28
- package/dist/repo/index.js +112 -96
- package/dist/repo/tools-checks.d.ts +3 -0
- package/dist/repo/tools-checks.js +112 -0
- package/dist/repo/tools-clone.js +1 -1
- package/dist/repo/tools-pr.d.ts +14 -0
- package/dist/repo/{tools-forge.js → tools-pr.js} +53 -36
- package/dist/repo/tools-review.d.ts +9 -0
- package/dist/repo/tools-review.js +67 -47
- package/dist/repo/tools-worktree.js +144 -60
- package/dist/repo/tools-worktrees.d.ts +12 -0
- package/dist/repo/tools-worktrees.js +48 -0
- package/dist/repo/url.d.ts +2 -2
- package/dist/repo/url.js +7 -7
- package/dist/scratch/index.d.ts +4 -4
- package/dist/scratch/index.js +12 -11
- package/dist/{computer → workspace}/advisory.d.ts +4 -4
- package/dist/{computer → workspace}/advisory.js +2 -2
- package/dist/{computer/host → workspace}/ca-trust.d.ts +8 -1
- package/dist/{computer/host → workspace}/ca-trust.js +12 -3
- package/dist/{computer/host → workspace}/container-fault.d.ts +3 -3
- package/dist/{computer/host → workspace}/container-fault.js +23 -8
- package/dist/workspace/exec.d.ts +94 -0
- package/dist/workspace/exec.js +153 -0
- package/dist/workspace/format.d.ts +36 -0
- package/dist/workspace/format.js +57 -0
- package/dist/{computer/host → workspace}/git-host.d.ts +21 -4
- package/dist/{computer/host → workspace}/git-host.js +72 -2
- package/dist/{computer/host → workspace}/git-identity.d.ts +1 -1
- package/dist/{computer/host → workspace}/git-identity.js +1 -1
- package/dist/workspace/index.d.ts +43 -47
- package/dist/workspace/index.js +52 -112
- package/dist/{computer/host → workspace}/install-job.d.ts +4 -4
- package/dist/{computer/host → workspace}/install-job.js +276 -176
- package/dist/{computer → workspace}/install.d.ts +8 -8
- package/dist/{computer → workspace}/install.js +3 -3
- package/dist/{computer/host/workspace.d.ts → workspace/object.d.ts} +105 -27
- package/dist/{computer/host/workspace.js → workspace/object.js} +217 -48
- package/dist/workspace/open.d.ts +95 -0
- package/dist/workspace/open.js +63 -0
- package/dist/workspace/read.d.ts +16 -0
- package/dist/workspace/read.js +22 -0
- package/dist/{computer → workspace}/shell.d.ts +5 -5
- package/dist/{computer → workspace}/shell.js +6 -6
- package/dist/{computer/host → workspace}/wake.d.ts +1 -1
- package/package.json +16 -36
- package/dist/arc-agi/analysis.d.ts +0 -322
- package/dist/arc-agi/analysis.js +0 -802
- package/dist/arc-agi/client.d.ts +0 -82
- package/dist/arc-agi/client.js +0 -113
- package/dist/arc-agi/game-tools.d.ts +0 -24
- package/dist/arc-agi/game-tools.js +0 -26
- package/dist/arc-agi/index.d.ts +0 -40
- package/dist/arc-agi/index.js +0 -175
- package/dist/arc-agi/main-agent.d.ts +0 -24
- package/dist/arc-agi/main-agent.js +0 -62
- package/dist/arc-agi/recipe.d.ts +0 -48
- package/dist/arc-agi/recipe.js +0 -97
- package/dist/arc-agi/scorecard.d.ts +0 -118
- package/dist/arc-agi/scorecard.js +0 -163
- package/dist/arc-agi/soul.d.ts +0 -29
- package/dist/arc-agi/soul.js +0 -79
- package/dist/arc-agi/store.d.ts +0 -153
- package/dist/arc-agi/store.js +0 -215
- package/dist/arc-agi/tools.d.ts +0 -36
- package/dist/arc-agi/tools.js +0 -574
- package/dist/arc-agi/types.d.ts +0 -211
- package/dist/arc-agi/types.js +0 -19
- package/dist/claude-code/recipe.d.ts +0 -53
- package/dist/claude-code/recipe.js +0 -100
- package/dist/computer/read.d.ts +0 -133
- package/dist/computer/read.js +0 -200
- package/dist/computer/tools-find.js +0 -216
- package/dist/recall/index.d.ts +0 -105
- package/dist/recall/index.js +0 -181
- package/dist/repo/tools-forge.d.ts +0 -4
- package/dist/triage/index.d.ts +0 -360
- package/dist/triage/index.js +0 -311
- /package/dist/{computer/host → workspace}/container-deps.d.ts +0 -0
- /package/dist/{computer/host → workspace}/container-deps.js +0 -0
- /package/dist/{computer/host → workspace}/sync.d.ts +0 -0
- /package/dist/{computer/host → workspace}/sync.js +0 -0
- /package/dist/{computer/host → workspace}/wake.js +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { RepoGitResult } from "
|
|
1
|
+
import type { RepoGitResult } from "../repo/index.js";
|
|
2
2
|
import type { GitClient } from "@cloudflare/computer/git";
|
|
3
3
|
/**
|
|
4
|
-
* The git operations that need the
|
|
4
|
+
* The git operations that need the GitHub token, run on this side.
|
|
5
5
|
*
|
|
6
6
|
* They are here rather than on the `WorkspaceStub` the plugin already holds
|
|
7
7
|
* because `WorkspaceGitStub` exposes only `cli(argv)` across a Durable Object
|
|
@@ -22,12 +22,12 @@ import type { GitClient } from "@cloudflare/computer/git";
|
|
|
22
22
|
* the workspace object's job and it must happen first: git here reads that
|
|
23
23
|
* object's SQLite, so a commit made in the container that has not been pulled
|
|
24
24
|
* yet is a commit this code cannot see. The workspace object's `gitClone`,
|
|
25
|
-
* `gitFetch` and `gitPush` in `./
|
|
25
|
+
* `gitFetch` and `gitPush` in `./object.ts` are where that is settled.
|
|
26
26
|
*/
|
|
27
27
|
export interface GitHostDeps {
|
|
28
28
|
/** The workspace's own client — isomorphic-git over the local store. */
|
|
29
29
|
git: () => GitClient;
|
|
30
|
-
/** The
|
|
30
|
+
/** The GitHub credential, read at the moment it would be handed over. */
|
|
31
31
|
token: () => string | undefined;
|
|
32
32
|
tag: () => string;
|
|
33
33
|
}
|
|
@@ -53,6 +53,11 @@ export declare class WorkspaceGitHost {
|
|
|
53
53
|
allowedHosts: string[];
|
|
54
54
|
depth?: number;
|
|
55
55
|
}): Promise<RepoGitResult>;
|
|
56
|
+
/**
|
|
57
|
+
* `remote.origin.url` from the local store, or `undefined` where there is no
|
|
58
|
+
* checkout or no origin. Reads only, and needs no credential.
|
|
59
|
+
*/
|
|
60
|
+
origin(dir: string): Promise<string | undefined>;
|
|
56
61
|
push(req: {
|
|
57
62
|
url: string;
|
|
58
63
|
dir: string;
|
|
@@ -60,3 +65,15 @@ export declare class WorkspaceGitHost {
|
|
|
60
65
|
allowedHosts: string[];
|
|
61
66
|
}): Promise<RepoGitResult>;
|
|
62
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* A git error's message with the chain of causes behind it.
|
|
70
|
+
*
|
|
71
|
+
* `@cloudflare/computer/git` wraps isomorphic-git's errors, and classifies some
|
|
72
|
+
* by a heuristic: any failure whose message mentions `.git` beside a missing
|
|
73
|
+
* path or a ref it could not find is reported as "not a git repository" — a
|
|
74
|
+
* sentence that is wrong about a checkout that plainly is one, and names
|
|
75
|
+
* neither the file nor the ref. What actually failed is only on `cause`, which
|
|
76
|
+
* a Durable Object boundary does not carry, so it is folded into the message
|
|
77
|
+
* here while the error is still itself.
|
|
78
|
+
*/
|
|
79
|
+
export declare function describeGitError(err: unknown): string;
|
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the container's own `git init` would write, over isomorphic-git's.
|
|
3
|
+
*
|
|
4
|
+
* isomorphic-git's `init` writes `core.*` for a filesystem without symlinks or
|
|
5
|
+
* an executable bit that ignores case, and the container's git obeys it. With
|
|
6
|
+
* `symlinks = false`, a command there that rewrites the tree — starter puts a
|
|
7
|
+
* worktree on its branch with `checkout -f` — writes each link as a file holding
|
|
8
|
+
* its target, and `status` calls that clean. With `filemode = false`, a script
|
|
9
|
+
* made executable is committed as 100644. The store models all three.
|
|
10
|
+
*/
|
|
11
|
+
const CONTAINER_CORE_CONFIG = {
|
|
12
|
+
"core.symlinks": true,
|
|
13
|
+
"core.filemode": true,
|
|
14
|
+
"core.ignorecase": false
|
|
15
|
+
};
|
|
1
16
|
export class WorkspaceGitHost {
|
|
2
17
|
deps;
|
|
3
18
|
constructor(deps) {
|
|
@@ -20,6 +35,10 @@ export class WorkspaceGitHost {
|
|
|
20
35
|
// checked at the moment the token would be handed over. The cost is four
|
|
21
36
|
// calls instead of one; `clone` is these four.
|
|
22
37
|
await git.init({ dir: req.dir });
|
|
38
|
+
// Straight after `init`, so a clone that fails part-way leaves nothing
|
|
39
|
+
// behind that the container's git would misread.
|
|
40
|
+
for (const [path, value] of Object.entries(CONTAINER_CORE_CONFIG))
|
|
41
|
+
await git.configSet({ dir: req.dir, path, value });
|
|
23
42
|
await git.remoteAdd({
|
|
24
43
|
dir: req.dir,
|
|
25
44
|
name: "origin",
|
|
@@ -46,7 +65,7 @@ export class WorkspaceGitHost {
|
|
|
46
65
|
throw new Error(`cloned ${req.url} but the remote named no default branch to check out`);
|
|
47
66
|
await git.checkout({ dir: req.dir, ref: landed });
|
|
48
67
|
// What a real `git clone` writes and the container's git will look for:
|
|
49
|
-
// without it the branch tracks nothing, and
|
|
68
|
+
// without it the branch tracks nothing, and an agent reaching for a bare
|
|
50
69
|
// `git status` in the shell sees a branch with no upstream.
|
|
51
70
|
await git.configSet({
|
|
52
71
|
dir: req.dir,
|
|
@@ -70,11 +89,33 @@ export class WorkspaceGitHost {
|
|
|
70
89
|
prune: true,
|
|
71
90
|
tags: false,
|
|
72
91
|
singleBranch: false,
|
|
92
|
+
// Every branch is fetched, but isomorphic-git still resolves one ref
|
|
93
|
+
// against the remote's list, and left to itself it picks the current
|
|
94
|
+
// branch's upstream. A checkout left on a branch whose pull request
|
|
95
|
+
// merged — and whose remote branch went with it — then fails every
|
|
96
|
+
// fetch with `Could not find refs/heads/<branch>`. The remote's HEAD
|
|
97
|
+
// is always listed.
|
|
98
|
+
remoteRef: "HEAD",
|
|
73
99
|
...(req.depth ? { depth: req.depth } : {})
|
|
74
100
|
});
|
|
75
101
|
return `fetched ${req.url} (default branch ${result.defaultBranch ?? "unknown"})`;
|
|
76
102
|
});
|
|
77
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* `remote.origin.url` from the local store, or `undefined` where there is no
|
|
106
|
+
* checkout or no origin. Reads only, and needs no credential.
|
|
107
|
+
*/
|
|
108
|
+
async origin(dir) {
|
|
109
|
+
try {
|
|
110
|
+
const url = await this.deps
|
|
111
|
+
.git()
|
|
112
|
+
.configGet({ dir, path: "remote.origin.url" });
|
|
113
|
+
return typeof url === "string" && url ? url : undefined;
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return undefined;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
78
119
|
async push(req) {
|
|
79
120
|
return this.#run(req.allowedHosts, async (git, onAuth) => {
|
|
80
121
|
const result = await git.push({
|
|
@@ -146,11 +187,40 @@ export class WorkspaceGitHost {
|
|
|
146
187
|
}
|
|
147
188
|
catch (err) {
|
|
148
189
|
const code = err?.code;
|
|
190
|
+
const message = describeGitError(err);
|
|
191
|
+
console.error(`[${this.deps.tag()}] git failed`, { code, message });
|
|
149
192
|
return {
|
|
150
193
|
ok: false,
|
|
151
194
|
...(typeof code === "string" ? { code } : {}),
|
|
152
|
-
message
|
|
195
|
+
message
|
|
153
196
|
};
|
|
154
197
|
}
|
|
155
198
|
}
|
|
156
199
|
}
|
|
200
|
+
/**
|
|
201
|
+
* A git error's message with the chain of causes behind it.
|
|
202
|
+
*
|
|
203
|
+
* `@cloudflare/computer/git` wraps isomorphic-git's errors, and classifies some
|
|
204
|
+
* by a heuristic: any failure whose message mentions `.git` beside a missing
|
|
205
|
+
* path or a ref it could not find is reported as "not a git repository" — a
|
|
206
|
+
* sentence that is wrong about a checkout that plainly is one, and names
|
|
207
|
+
* neither the file nor the ref. What actually failed is only on `cause`, which
|
|
208
|
+
* a Durable Object boundary does not carry, so it is folded into the message
|
|
209
|
+
* here while the error is still itself.
|
|
210
|
+
*/
|
|
211
|
+
export function describeGitError(err) {
|
|
212
|
+
const parts = [];
|
|
213
|
+
const seen = new Set();
|
|
214
|
+
let at = err;
|
|
215
|
+
for (let depth = 0; at !== undefined && at !== null && depth < 4; depth++) {
|
|
216
|
+
const e = at;
|
|
217
|
+
const text = typeof e.message === "string" ? e.message : String(at);
|
|
218
|
+
if (!seen.has(text)) {
|
|
219
|
+
seen.add(text);
|
|
220
|
+
const name = typeof e.name === "string" ? e.name : "";
|
|
221
|
+
parts.push(name && depth > 0 ? `${name}: ${text}` : text);
|
|
222
|
+
}
|
|
223
|
+
at = e.cause;
|
|
224
|
+
}
|
|
225
|
+
return parts.join(" ← ");
|
|
226
|
+
}
|
|
@@ -4,7 +4,7 @@ import type { Workspace } from "@cloudflare/computer";
|
|
|
4
4
|
* answers for it.
|
|
5
5
|
*
|
|
6
6
|
* `/repo` configures the checkouts it clones and names the identity on every
|
|
7
|
-
* commit it makes — see {@link file
|
|
7
|
+
* commit it makes — see {@link file://../repo/checkout.ts writeGitIdentity}.
|
|
8
8
|
* Neither reaches a repository the container made for itself: a submodule
|
|
9
9
|
* checked out by a bootstrap, a `git init`, a second clone from the shell. Those
|
|
10
10
|
* have no identity at all, and git refuses to commit without one — so whatever
|
|
@@ -55,7 +55,7 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
|
|
|
55
55
|
* answers for it.
|
|
56
56
|
*
|
|
57
57
|
* `/repo` configures the checkouts it clones and names the identity on every
|
|
58
|
-
* commit it makes — see {@link file
|
|
58
|
+
* commit it makes — see {@link file://../repo/checkout.ts writeGitIdentity}.
|
|
59
59
|
* Neither reaches a repository the container made for itself: a submodule
|
|
60
60
|
* checked out by a bootstrap, a `git init`, a second clone from the shell. Those
|
|
61
61
|
* have no identity at all, and git refuses to commit without one — so whatever
|
|
@@ -1,53 +1,49 @@
|
|
|
1
|
-
import type { ToolSet } from "ai";
|
|
2
|
-
import type { AgentPlugin, WorkspaceBacking, WorkspaceHandle } from "@dynamicagents/core";
|
|
3
1
|
/**
|
|
4
|
-
* `@dynamicagents/plugins/workspace` —
|
|
5
|
-
* and the
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* one
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* - the `workspace` tool family puts `ws_read`/`ws_write`/`ws_list` in front of
|
|
25
|
-
* the *model*, so it can keep notes across a context window it will outlive.
|
|
26
|
-
*
|
|
27
|
-
* A recipe opts into the second by naming `workspace` in its `toolFamilies`;
|
|
28
|
-
* the first applies to every execution regardless.
|
|
2
|
+
* `@dynamicagents/plugins/workspace` — the Durable Object a container workspace
|
|
3
|
+
* lives in, and the client side every other plugin reaches it through.
|
|
4
|
+
*
|
|
5
|
+
* The filesystem **is** a Durable Object's SQLite, mounted into the container
|
|
6
|
+
* over FUSE by `computerd`. Commands see a normal `/workspace`; the Worker reads
|
|
7
|
+
* the same tree over RPC; and when the container is replaced the tree is pushed
|
|
8
|
+
* back into the new one — so a checkout outlives the container that held it.
|
|
9
|
+
*
|
|
10
|
+
* `WorkspaceObjectBase` is the object: container backend, egress, CA trust,
|
|
11
|
+
* credentialed git, the dependency install, the sync drain and idle reclaim. A
|
|
12
|
+
* host subclasses it and answers a short config. Everything else here is what
|
|
13
|
+
* reaches it from outside: `openWorkspace`, `workspaceExec`, and the advisory
|
|
14
|
+
* vocabulary it reports its state in.
|
|
15
|
+
*
|
|
16
|
+
* `@dynamicagents/plugins/computer` is the agent's tools over it; `/repo` and
|
|
17
|
+
* `/scratch` take `workspaceExec` injected.
|
|
18
|
+
*
|
|
19
|
+
* Requires the Workers **Paid** plan (containers) and a Durable Object binding
|
|
20
|
+
* whose class extends `WorkspaceObjectBase` — see the README for the wrangler
|
|
21
|
+
* block.
|
|
29
22
|
*/
|
|
30
|
-
/**
|
|
31
|
-
export
|
|
23
|
+
/** How a repository installs its dependencies — the mechanical half. */
|
|
24
|
+
export { DEFAULT_INSTALL_PLAN, installFingerprint, resolveInstallCommand, type InstallPlan, type InstallProbe, type InstallResolution, type InstallRule, type InstallState } from "./install.js";
|
|
32
25
|
/**
|
|
33
|
-
* The
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* with its own tool assembly can reuse them.
|
|
26
|
+
* The workspace-advisory vocabulary, which a host needs all of: the type to
|
|
27
|
+
* return over RPC, `deriveAdvisories` to build it from what it already knows,
|
|
28
|
+
* and `sessionAdvisory` for a host driving a whole session rather than one
|
|
29
|
+
* command. `shapeOf` and `renderAdvisory` are exported for the specs that hold
|
|
30
|
+
* their exhaustiveness — a host has no reason to call either, since calling them
|
|
31
|
+
* would mean writing policy or wording that has one home already.
|
|
40
32
|
*/
|
|
41
|
-
export
|
|
33
|
+
export { deriveAdvisories, renderAdvisory, sessionAdvisory, shapeOf, type AdvisoryAudience, type AdvisoryInput, type AdvisoryShape, type WorkspaceAdvisory } from "./advisory.js";
|
|
34
|
+
export { pathExists } from "./read.js";
|
|
35
|
+
export { cancelledNote, truncateOutput } from "./format.js";
|
|
36
|
+
export { openWorkspace, openWorkspaceFs, workspaceNameFromRuntime, WORKSPACE_RUNTIME_KEY, type WorkspaceHost } from "./open.js";
|
|
37
|
+
export { withShell, withShellTranscript } from "./shell.js";
|
|
38
|
+
export { workspaceExec, DEFAULT_CWD, DEFAULT_TIMEOUT_MS, type WorkspaceClientConfig } from "./exec.js";
|
|
42
39
|
/**
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
* isolation is free and deleting the child wipes the workspace with the rest of
|
|
47
|
-
* its storage. `name` is lazy because a facet's name is set after construction.
|
|
48
|
-
*
|
|
49
|
-
* Exported because a host that assembles its own `SubagentRuntime` by hand may
|
|
50
|
-
* want it directly; the plugin's `workspaceBacking` is this same function.
|
|
40
|
+
* The object itself. The modules below import the client-side leaves beside
|
|
41
|
+
* them, never this barrel: a cycle through a module that builds a class at
|
|
42
|
+
* import time is a base that evaluates `undefined`.
|
|
51
43
|
*/
|
|
52
|
-
export
|
|
53
|
-
export
|
|
44
|
+
export { WorkspaceObjectBase, IDLE_RECLAIM_MS, WORKSPACE_DIR, workspaceName, type WorkspaceObjectConfig, type WorkspaceGitConfig } from "./object.js";
|
|
45
|
+
export { InstallJob, type InstallJobDeps } from "./install-job.js";
|
|
46
|
+
export { WorkspaceSync, SYNC_DRAIN_BUDGET_MS, SYNC_DRAIN_RESUME_MS, SYNC_DRAIN_MAX_BACKOFF_MS, syncRetryDelayMs, type DrainOutcome, type SyncDrainIntent, type WorkspaceSyncDeps } from "./sync.js";
|
|
47
|
+
export { ContainerTrust, TRUST_CA_COMMAND, type ContainerTrustDeps } from "./ca-trust.js";
|
|
48
|
+
export { WorkspaceGitHost, type GitHostDeps } from "./git-host.js";
|
|
49
|
+
export type { WorkspaceWakeHandlers } from "./wake.js";
|
package/dist/workspace/index.js
CHANGED
|
@@ -1,118 +1,58 @@
|
|
|
1
|
-
import { tool } from "ai";
|
|
2
|
-
import { z } from "zod";
|
|
3
|
-
import { definePlugin } from "@dynamicagents/core";
|
|
4
|
-
import { Workspace } from "@cloudflare/shell";
|
|
5
1
|
/**
|
|
6
|
-
* `@dynamicagents/plugins/workspace` —
|
|
7
|
-
* and the
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* one
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* - the `workspace` tool family puts `ws_read`/`ws_write`/`ws_list` in front of
|
|
27
|
-
* the *model*, so it can keep notes across a context window it will outlive.
|
|
28
|
-
*
|
|
29
|
-
* A recipe opts into the second by naming `workspace` in its `toolFamilies`;
|
|
30
|
-
* the first applies to every execution regardless.
|
|
2
|
+
* `@dynamicagents/plugins/workspace` — the Durable Object a container workspace
|
|
3
|
+
* lives in, and the client side every other plugin reaches it through.
|
|
4
|
+
*
|
|
5
|
+
* The filesystem **is** a Durable Object's SQLite, mounted into the container
|
|
6
|
+
* over FUSE by `computerd`. Commands see a normal `/workspace`; the Worker reads
|
|
7
|
+
* the same tree over RPC; and when the container is replaced the tree is pushed
|
|
8
|
+
* back into the new one — so a checkout outlives the container that held it.
|
|
9
|
+
*
|
|
10
|
+
* `WorkspaceObjectBase` is the object: container backend, egress, CA trust,
|
|
11
|
+
* credentialed git, the dependency install, the sync drain and idle reclaim. A
|
|
12
|
+
* host subclasses it and answers a short config. Everything else here is what
|
|
13
|
+
* reaches it from outside: `openWorkspace`, `workspaceExec`, and the advisory
|
|
14
|
+
* vocabulary it reports its state in.
|
|
15
|
+
*
|
|
16
|
+
* `@dynamicagents/plugins/computer` is the agent's tools over it; `/repo` and
|
|
17
|
+
* `/scratch` take `workspaceExec` injected.
|
|
18
|
+
*
|
|
19
|
+
* Requires the Workers **Paid** plan (containers) and a Durable Object binding
|
|
20
|
+
* whose class extends `WorkspaceObjectBase` — see the README for the wrangler
|
|
21
|
+
* block.
|
|
31
22
|
*/
|
|
32
|
-
/**
|
|
33
|
-
export
|
|
23
|
+
/** How a repository installs its dependencies — the mechanical half. */
|
|
24
|
+
export { DEFAULT_INSTALL_PLAN, installFingerprint, resolveInstallCommand } from "./install.js";
|
|
34
25
|
/**
|
|
35
|
-
* The
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
* with its own tool assembly can reuse them.
|
|
26
|
+
* The workspace-advisory vocabulary, which a host needs all of: the type to
|
|
27
|
+
* return over RPC, `deriveAdvisories` to build it from what it already knows,
|
|
28
|
+
* and `sessionAdvisory` for a host driving a whole session rather than one
|
|
29
|
+
* command. `shapeOf` and `renderAdvisory` are exported for the specs that hold
|
|
30
|
+
* their exhaustiveness — a host has no reason to call either, since calling them
|
|
31
|
+
* would mean writing policy or wording that has one home already.
|
|
42
32
|
*/
|
|
43
|
-
export
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
return content === null ? `(no file at ${path})` : content;
|
|
53
|
-
}
|
|
54
|
-
}),
|
|
55
|
-
ws_write: tool({
|
|
56
|
-
description: "Create or overwrite a workspace file. Use this to persist notes, hypotheses, and plans so you remember them after older turns scroll out of context.",
|
|
57
|
-
inputSchema: z.object({
|
|
58
|
-
path: z.string().describe("File path, e.g. 'notes.md'"),
|
|
59
|
-
content: z
|
|
60
|
-
.string()
|
|
61
|
-
.describe("Full file content (overwrites any existing file)")
|
|
62
|
-
}),
|
|
63
|
-
execute: async ({ path, content }) => {
|
|
64
|
-
// Returned rather than thrown: a write over the size cap is the model's
|
|
65
|
-
// mistake to correct, and it can only correct what it is told. The SDK
|
|
66
|
-
// would surface a throw as a tool error too, but this reads better and
|
|
67
|
-
// keeps the limit itself in the message.
|
|
68
|
-
try {
|
|
69
|
-
await workspace.write(path, content);
|
|
70
|
-
return `wrote ${path}`;
|
|
71
|
-
}
|
|
72
|
-
catch (err) {
|
|
73
|
-
return `error writing ${path}: ${String(err)}`;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}),
|
|
77
|
-
ws_list: tool({
|
|
78
|
-
description: "List the files currently in your workspace.",
|
|
79
|
-
inputSchema: z.object({
|
|
80
|
-
dir: z.string().optional().describe("Directory to list (default: root)")
|
|
81
|
-
}),
|
|
82
|
-
execute: async ({ dir }) => {
|
|
83
|
-
const entries = await workspace.list(dir);
|
|
84
|
-
if (entries.length === 0)
|
|
85
|
-
return "(workspace is empty)";
|
|
86
|
-
return entries
|
|
87
|
-
.map((e) => `${e.path}${e.type === "directory" ? "/" : ""} (${e.size} bytes)`)
|
|
88
|
-
.join("\n");
|
|
89
|
-
}
|
|
90
|
-
})
|
|
91
|
-
};
|
|
92
|
-
}
|
|
33
|
+
export { deriveAdvisories, renderAdvisory, sessionAdvisory, shapeOf } from "./advisory.js";
|
|
34
|
+
// A host implementing `InstallProbe` needs exactly this, and hand-rolling it
|
|
35
|
+
// loses the fast path: across a Durable Object boundary `fs` is a stub carrying
|
|
36
|
+
// `exists`, which a `stat`-only probe never asks for.
|
|
37
|
+
export { pathExists } from "./read.js";
|
|
38
|
+
export { cancelledNote, truncateOutput } from "./format.js";
|
|
39
|
+
export { openWorkspace, openWorkspaceFs, workspaceNameFromRuntime, WORKSPACE_RUNTIME_KEY } from "./open.js";
|
|
40
|
+
export { withShell, withShellTranscript } from "./shell.js";
|
|
41
|
+
export { workspaceExec, DEFAULT_CWD, DEFAULT_TIMEOUT_MS } from "./exec.js";
|
|
93
42
|
/**
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
* isolation is free and deleting the child wipes the workspace with the rest of
|
|
98
|
-
* its storage. `name` is lazy because a facet's name is set after construction.
|
|
99
|
-
*
|
|
100
|
-
* Exported because a host that assembles its own `SubagentRuntime` by hand may
|
|
101
|
-
* want it directly; the plugin's `workspaceBacking` is this same function.
|
|
43
|
+
* The object itself. The modules below import the client-side leaves beside
|
|
44
|
+
* them, never this barrel: a cycle through a module that builds a class at
|
|
45
|
+
* import time is a base that evaluates `undefined`.
|
|
102
46
|
*/
|
|
103
|
-
export
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
// No `requires`: shell backs the workspace with the Durable Object's own
|
|
116
|
-
// SQLite, which every DO already has. Nothing for the host to declare.
|
|
117
|
-
});
|
|
118
|
-
}
|
|
47
|
+
export { WorkspaceObjectBase, IDLE_RECLAIM_MS, WORKSPACE_DIR, workspaceName } from "./object.js";
|
|
48
|
+
// The dependency install, exported because a host that wants to report on one —
|
|
49
|
+
// or a spec that drives it — needs the type, not because anything but
|
|
50
|
+
// `./object.ts` constructs it.
|
|
51
|
+
export { InstallJob } from "./install-job.js";
|
|
52
|
+
// The pull the library owns no alarm for. Its constants are exported because a
|
|
53
|
+
// host deferring to a drain has to back off at the same rate this does.
|
|
54
|
+
export { WorkspaceSync, SYNC_DRAIN_BUDGET_MS, SYNC_DRAIN_RESUME_MS, SYNC_DRAIN_MAX_BACKOFF_MS, syncRetryDelayMs } from "./sync.js";
|
|
55
|
+
// `TRUST_CA_COMMAND` is exported so a host can assert what its image will be
|
|
56
|
+
// asked to run — see the file for why this cannot live in an entrypoint.
|
|
57
|
+
export { ContainerTrust, TRUST_CA_COMMAND } from "./ca-trust.js";
|
|
58
|
+
export { WorkspaceGitHost } from "./git-host.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type Workspace } from "@cloudflare/computer";
|
|
2
2
|
import type { Scheduler } from "@dynamicagents/core/alarm";
|
|
3
|
-
import { type InstallPlan, type InstallState } from "
|
|
3
|
+
import { type InstallPlan, type InstallState } from "./install.js";
|
|
4
4
|
import type { WorkspaceWakeHandlers } from "./wake.js";
|
|
5
5
|
export interface InstallJobDeps {
|
|
6
6
|
storage: DurableObjectStorage;
|
|
@@ -71,7 +71,7 @@ export declare class InstallJob {
|
|
|
71
71
|
*
|
|
72
72
|
* Called from `repo_clone` through the repo plugin's `afterCheckout` hook, so
|
|
73
73
|
* it runs inside a model turn and must not block on the install — 225 seconds
|
|
74
|
-
* for slack-gatekeeper, against a
|
|
74
|
+
* for slack-gatekeeper, against a turn that is cut at fifteen minutes.
|
|
75
75
|
*
|
|
76
76
|
* That caller is a model turn, which lives long enough to hold the drain handed
|
|
77
77
|
* to `ctx.waitUntil` below. **A short-lived caller cannot**, which is why an
|
|
@@ -102,7 +102,7 @@ export declare class InstallJob {
|
|
|
102
102
|
/**
|
|
103
103
|
* When a reinstall was queued, if one is waiting to run.
|
|
104
104
|
*
|
|
105
|
-
* Read by {@link file
|
|
105
|
+
* Read by {@link file://./advisory.ts deriveAdvisories}, which is the only
|
|
106
106
|
* caller that needs it: a `failed` record with a repair already queued is a
|
|
107
107
|
* transient condition wearing a permanent record's clothes.
|
|
108
108
|
*/
|
|
@@ -112,7 +112,7 @@ export declare class InstallJob {
|
|
|
112
112
|
*
|
|
113
113
|
* `clearArmed` first and unconditionally: this handler runs for minutes, and
|
|
114
114
|
* the stamp left in place is what a second arming would recognise as its own.
|
|
115
|
-
*
|
|
115
|
+
* The reservation in `#beginInstall` would catch a double, but the cheaper
|
|
116
116
|
* answer is not to schedule one.
|
|
117
117
|
*/
|
|
118
118
|
onRun(): Promise<void>;
|