@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.
- 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 +55 -0
- package/dist/claude-code/cards.js +283 -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 +366 -0
- package/dist/claude-code/run.d.ts +230 -116
- package/dist/claude-code/run.js +380 -167
- package/dist/claude-code/session.d.ts +131 -0
- package/dist/claude-code/session.js +288 -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-deps.d.ts +4 -0
- package/dist/{computer/host → workspace}/container-deps.js +26 -1
- package/dist/{computer/host → workspace}/container-fault.d.ts +3 -3
- package/dist/{computer/host → workspace}/container-fault.js +23 -8
- package/dist/workspace/deps-snapshot.d.ts +110 -0
- package/dist/workspace/deps-snapshot.js +424 -0
- 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 +44 -47
- package/dist/workspace/index.js +52 -112
- package/dist/{computer/host → workspace}/install-job.d.ts +53 -4
- package/dist/{computer/host → workspace}/install-job.js +346 -178
- package/dist/{computer → workspace}/install.d.ts +17 -8
- package/dist/{computer → workspace}/install.js +24 -6
- package/dist/{computer/host/workspace.d.ts → workspace/object.d.ts} +125 -27
- package/dist/{computer/host/workspace.js → workspace/object.js} +341 -58
- 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 +3 -1
- package/package.json +17 -37
- 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}/sync.d.ts +0 -0
- /package/dist/{computer/host → workspace}/sync.js +0 -0
- /package/dist/{computer/host → workspace}/wake.js +0 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { WorkspaceRuntimeStatus } from "@cloudflare/computer";
|
|
2
|
+
/**
|
|
3
|
+
* Text shared by the workspace and the tools over it: the output bound, the
|
|
4
|
+
* elapsed-time phrase, and what a killed command is told.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Middle-out truncation, so both the first error and the final summary survive.
|
|
8
|
+
*
|
|
9
|
+
* The guard is not defensive padding. Without it a `max` at or below the marker's
|
|
10
|
+
* own length makes `half` zero or negative, and `slice(-0)` is `slice(0)` — the
|
|
11
|
+
* *whole* string — so the function returns more than it was given: 500 characters
|
|
12
|
+
* in, 543 out at `max: 80`. A silent inversion of the one thing it does,
|
|
13
|
+
* reachable from a public config field.
|
|
14
|
+
*/
|
|
15
|
+
export declare function truncateOutput(text: string, max: number): string;
|
|
16
|
+
/** Elapsed time in the shape a sentence wants. */
|
|
17
|
+
export declare function humanMs(ms: number): string;
|
|
18
|
+
/**
|
|
19
|
+
* Why a command has nothing to show for itself.
|
|
20
|
+
*
|
|
21
|
+
* {@link renderResult} states a non-`completed` status on its verdict line;
|
|
22
|
+
* {@link file://./exec.ts workspaceExec} has no verdict line, only the four fields its caller
|
|
23
|
+
* branches on. A *killed* process writes nothing, so without this a `git clone`
|
|
24
|
+
* that hit the ten-minute ceiling reaches the model through
|
|
25
|
+
* `@dynamicagents/plugins/repo` as `clone failed:` with an empty reason — which reads
|
|
26
|
+
* like a bug in the plugin rather than a limit it can work within.
|
|
27
|
+
*
|
|
28
|
+
* Only `cancelled`. A `failed` status is an ordinary non-zero exit, where the
|
|
29
|
+
* command's own stderr is the better explanation and this would be noise on top
|
|
30
|
+
* of it.
|
|
31
|
+
*
|
|
32
|
+
* Both plausible causes are named because the exit code cannot separate them:
|
|
33
|
+
* 137 is SIGKILL, which is what the timeout sends *and* what the kernel sends a
|
|
34
|
+
* container that ran out of memory.
|
|
35
|
+
*/
|
|
36
|
+
export declare function cancelledNote(status: WorkspaceRuntimeStatus | undefined, exitCode: number, timeoutMs: number): string | undefined;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text shared by the workspace and the tools over it: the output bound, the
|
|
3
|
+
* elapsed-time phrase, and what a killed command is told.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Middle-out truncation, so both the first error and the final summary survive.
|
|
7
|
+
*
|
|
8
|
+
* The guard is not defensive padding. Without it a `max` at or below the marker's
|
|
9
|
+
* own length makes `half` zero or negative, and `slice(-0)` is `slice(0)` — the
|
|
10
|
+
* *whole* string — so the function returns more than it was given: 500 characters
|
|
11
|
+
* in, 543 out at `max: 80`. A silent inversion of the one thing it does,
|
|
12
|
+
* reachable from a public config field.
|
|
13
|
+
*/
|
|
14
|
+
export function truncateOutput(text, max) {
|
|
15
|
+
if (text.length <= max)
|
|
16
|
+
return text;
|
|
17
|
+
const marker = (dropped) => `\n\n… [${dropped} characters omitted from the middle] …\n\n`;
|
|
18
|
+
// No budget for two halves plus the marker: keep the head, which is where the
|
|
19
|
+
// first error is, and say nothing clever.
|
|
20
|
+
const half = Math.floor((max - marker(text.length).length) / 2);
|
|
21
|
+
if (half < 1)
|
|
22
|
+
return text.slice(0, Math.max(0, max));
|
|
23
|
+
return (text.slice(0, half) + marker(text.length - half * 2) + text.slice(-half));
|
|
24
|
+
}
|
|
25
|
+
/** Elapsed time in the shape a sentence wants. */
|
|
26
|
+
export function humanMs(ms) {
|
|
27
|
+
const s = Math.round(ms / 1000);
|
|
28
|
+
return s < 60
|
|
29
|
+
? `${s}s`
|
|
30
|
+
: `${Math.floor(s / 60)}m${String(s % 60).padStart(2, "0")}s`;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Why a command has nothing to show for itself.
|
|
34
|
+
*
|
|
35
|
+
* {@link renderResult} states a non-`completed` status on its verdict line;
|
|
36
|
+
* {@link file://./exec.ts workspaceExec} has no verdict line, only the four fields its caller
|
|
37
|
+
* branches on. A *killed* process writes nothing, so without this a `git clone`
|
|
38
|
+
* that hit the ten-minute ceiling reaches the model through
|
|
39
|
+
* `@dynamicagents/plugins/repo` as `clone failed:` with an empty reason — which reads
|
|
40
|
+
* like a bug in the plugin rather than a limit it can work within.
|
|
41
|
+
*
|
|
42
|
+
* Only `cancelled`. A `failed` status is an ordinary non-zero exit, where the
|
|
43
|
+
* command's own stderr is the better explanation and this would be noise on top
|
|
44
|
+
* of it.
|
|
45
|
+
*
|
|
46
|
+
* Both plausible causes are named because the exit code cannot separate them:
|
|
47
|
+
* 137 is SIGKILL, which is what the timeout sends *and* what the kernel sends a
|
|
48
|
+
* container that ran out of memory.
|
|
49
|
+
*/
|
|
50
|
+
export function cancelledNote(status, exitCode, timeoutMs) {
|
|
51
|
+
if (status !== "cancelled")
|
|
52
|
+
return undefined;
|
|
53
|
+
return (`the command was killed rather than exiting on its own (exit ${exitCode}), so ` +
|
|
54
|
+
`anything it had not yet written is gone. The two usual causes are the ` +
|
|
55
|
+
`per-command time limit — ${humanMs(timeoutMs)} here — and the container ` +
|
|
56
|
+
`running out of memory.`);
|
|
57
|
+
}
|
|
@@ -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,50 @@
|
|
|
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, type InstallTarget } from "./install-job.js";
|
|
46
|
+
export type { DepsSnapshotRecord } from "./deps-snapshot.js";
|
|
47
|
+
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";
|
|
48
|
+
export { ContainerTrust, TRUST_CA_COMMAND, type ContainerTrustDeps } from "./ca-trust.js";
|
|
49
|
+
export { WorkspaceGitHost, type GitHostDeps } from "./git-host.js";
|
|
50
|
+
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";
|