@dynamicagents/plugins 0.11.1 → 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 +59 -79
- 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 +73 -31
- package/dist/claude-code/config.js +0 -2
- package/dist/claude-code/credentials.d.ts +21 -9
- package/dist/claude-code/credentials.js +43 -9
- package/dist/claude-code/egress.d.ts +15 -14
- package/dist/claude-code/egress.js +51 -14
- package/dist/claude-code/events.d.ts +153 -9
- package/dist/claude-code/events.js +289 -58
- package/dist/claude-code/github.d.ts +39 -0
- package/dist/claude-code/github.js +82 -0
- package/dist/claude-code/index.d.ts +24 -80
- package/dist/claude-code/index.js +19 -234
- package/dist/claude-code/model.d.ts +152 -0
- package/dist/claude-code/model.js +342 -0
- package/dist/claude-code/run.d.ts +283 -92
- package/dist/claude-code/run.js +620 -114
- 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 +19 -0
- package/dist/computer/context.js +222 -0
- package/dist/computer/file-lock.d.ts +5 -0
- package/dist/computer/file-lock.js +40 -0
- package/dist/computer/gate.d.ts +12 -12
- package/dist/computer/gate.js +12 -12
- package/dist/computer/index.d.ts +57 -255
- package/dist/computer/index.js +98 -1039
- package/dist/computer/paths.d.ts +47 -22
- package/dist/computer/paths.js +64 -49
- package/dist/computer/proxy.d.ts +45 -0
- package/dist/computer/proxy.js +234 -0
- package/dist/computer/render.d.ts +27 -38
- package/dist/computer/render.js +32 -65
- package/dist/computer/tools-exec.d.ts +3 -0
- package/dist/computer/tools-exec.js +268 -0
- package/dist/computer/tools-file.d.ts +12 -0
- package/dist/computer/tools-file.js +64 -0
- package/dist/computer/tools-grep.d.ts +3 -0
- package/dist/computer/tools-grep.js +129 -0
- package/dist/repo/checkout.d.ts +35 -6
- package/dist/repo/checkout.js +64 -6
- package/dist/repo/context.d.ts +135 -0
- package/dist/repo/context.js +582 -0
- package/dist/repo/index.d.ts +79 -57
- package/dist/repo/index.js +118 -1112
- package/dist/repo/tools-checks.d.ts +3 -0
- package/dist/repo/tools-checks.js +112 -0
- package/dist/repo/tools-clone.d.ts +4 -0
- package/dist/repo/tools-clone.js +192 -0
- package/dist/repo/tools-pr.d.ts +14 -0
- package/dist/repo/tools-pr.js +196 -0
- package/dist/repo/tools-review.d.ts +12 -0
- package/dist/repo/tools-review.js +393 -0
- package/dist/repo/tools-worktree.d.ts +4 -0
- package/dist/repo/tools-worktree.js +305 -0
- 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 +33 -20
- package/dist/{computer → workspace}/advisory.js +32 -7
- package/dist/workspace/ca-trust.d.ts +95 -0
- package/dist/workspace/ca-trust.js +312 -0
- package/dist/workspace/container-deps.d.ts +54 -0
- package/dist/workspace/container-deps.js +224 -0
- package/dist/workspace/container-fault.d.ts +38 -0
- package/dist/workspace/container-fault.js +73 -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/workspace/git-host.d.ts +79 -0
- package/dist/workspace/git-host.js +226 -0
- package/dist/workspace/git-identity.d.ts +57 -0
- package/dist/workspace/git-identity.js +147 -0
- package/dist/workspace/index.d.ts +43 -47
- package/dist/workspace/index.js +52 -112
- package/dist/workspace/install-job.d.ts +121 -0
- package/dist/workspace/install-job.js +866 -0
- package/dist/{computer → workspace}/install.d.ts +15 -19
- package/dist/{computer → workspace}/install.js +8 -11
- package/dist/workspace/object.d.ts +502 -0
- package/dist/workspace/object.js +1427 -0
- 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/workspace/shell.d.ts +45 -0
- package/dist/workspace/shell.js +80 -0
- package/dist/workspace/sync.d.ts +111 -0
- package/dist/workspace/sync.js +124 -0
- package/dist/workspace/wake.d.ts +19 -0
- package/dist/workspace/wake.js +10 -0
- package/package.json +28 -42
- package/dist/arc-agi/analysis.d.ts +0 -336
- package/dist/arc-agi/analysis.js +0 -829
- 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 -25
- package/dist/arc-agi/game-tools.js +0 -26
- package/dist/arc-agi/index.d.ts +0 -42
- package/dist/arc-agi/index.js +0 -175
- package/dist/arc-agi/main-agent.d.ts +0 -27
- package/dist/arc-agi/main-agent.js +0 -65
- package/dist/arc-agi/recipe.d.ts +0 -51
- package/dist/arc-agi/recipe.js +0 -100
- 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 -40
- package/dist/arc-agi/soul.js +0 -90
- package/dist/arc-agi/store.d.ts +0 -154
- package/dist/arc-agi/store.js +0 -216
- package/dist/arc-agi/tools.d.ts +0 -36
- package/dist/arc-agi/tools.js +0 -576
- package/dist/arc-agi/types.d.ts +0 -212
- 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 -137
- package/dist/computer/read.js +0 -203
- package/dist/recall/index.d.ts +0 -99
- package/dist/recall/index.js +0 -171
- package/dist/triage/index.d.ts +0 -355
- package/dist/triage/index.js +0 -302
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
|
|
2
|
+
if (value !== null && value !== void 0) {
|
|
3
|
+
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
|
|
4
|
+
var dispose, inner;
|
|
5
|
+
if (async) {
|
|
6
|
+
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
|
|
7
|
+
dispose = value[Symbol.asyncDispose];
|
|
8
|
+
}
|
|
9
|
+
if (dispose === void 0) {
|
|
10
|
+
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
|
|
11
|
+
dispose = value[Symbol.dispose];
|
|
12
|
+
if (async) inner = dispose;
|
|
13
|
+
}
|
|
14
|
+
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
|
|
15
|
+
if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
|
|
16
|
+
env.stack.push({ value: value, dispose: dispose, async: async });
|
|
17
|
+
}
|
|
18
|
+
else if (async) {
|
|
19
|
+
env.stack.push({ async: true });
|
|
20
|
+
}
|
|
21
|
+
return value;
|
|
22
|
+
};
|
|
23
|
+
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
|
|
24
|
+
return function (env) {
|
|
25
|
+
function fail(e) {
|
|
26
|
+
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
|
|
27
|
+
env.hasError = true;
|
|
28
|
+
}
|
|
29
|
+
var r, s = 0;
|
|
30
|
+
function next() {
|
|
31
|
+
while (r = env.stack.pop()) {
|
|
32
|
+
try {
|
|
33
|
+
if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
|
|
34
|
+
if (r.dispose) {
|
|
35
|
+
var result = r.dispose.call(r.value);
|
|
36
|
+
if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
|
|
37
|
+
}
|
|
38
|
+
else s |= 1;
|
|
39
|
+
}
|
|
40
|
+
catch (e) {
|
|
41
|
+
fail(e);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
|
|
45
|
+
if (env.hasError) throw env.error;
|
|
46
|
+
}
|
|
47
|
+
return next();
|
|
48
|
+
};
|
|
49
|
+
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
50
|
+
var e = new Error(message);
|
|
51
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
52
|
+
});
|
|
53
|
+
import { DEFAULT_CWD, DEFAULT_TIMEOUT_MS } from "../workspace/exec.js";
|
|
54
|
+
import { withAbort } from "@dynamicagents/core";
|
|
55
|
+
import { execGate, writeGate } from "./gate.js";
|
|
56
|
+
/**
|
|
57
|
+
* The machinery every container tool closes over: the resolved config, the
|
|
58
|
+
* advisory gates, and the workspace opener the file tools share.
|
|
59
|
+
*/
|
|
60
|
+
/**
|
|
61
|
+
* How much command output the model is allowed to see, in characters.
|
|
62
|
+
*
|
|
63
|
+
* One `npm install` prints more than a small context window holds, and the
|
|
64
|
+
* interesting part of a failing build is the first error and the last summary —
|
|
65
|
+
* never the middle. So output is truncated from the middle rather than the end,
|
|
66
|
+
* which is what a naive `slice` would do and would drop the exit summary that
|
|
67
|
+
* says what actually failed.
|
|
68
|
+
*/
|
|
69
|
+
const DEFAULT_MAX_OUTPUT_CHARS = 16_000;
|
|
70
|
+
/**
|
|
71
|
+
* How often the install gate re-reads the install's status.
|
|
72
|
+
*
|
|
73
|
+
* An interval rather than a subscription because the status lives in another
|
|
74
|
+
* Durable Object with no event to wait on. Never slept past the gate itself —
|
|
75
|
+
* see `awaitAdvisories` in {@link computerContext}.
|
|
76
|
+
*/
|
|
77
|
+
const INSTALL_POLL_MS = 3_000;
|
|
78
|
+
/** Takes what {@link file://./index.ts buildComputerTools} takes. */
|
|
79
|
+
export function computerContext(workspace, config, advisories, fsWorkspace = workspace, lockScope) {
|
|
80
|
+
const cwd = config.cwd ?? DEFAULT_CWD;
|
|
81
|
+
const timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
82
|
+
const maxChars = config.maxOutputChars ?? DEFAULT_MAX_OUTPUT_CHARS;
|
|
83
|
+
const gateMs = config.installGateMs ?? 90_000;
|
|
84
|
+
const env = config.env;
|
|
85
|
+
const ownScope = crypto.randomUUID();
|
|
86
|
+
const scope = () => lockScope?.() ?? ownScope;
|
|
87
|
+
/**
|
|
88
|
+
* Wait out anything transient, up to the gate, and report whatever is left.
|
|
89
|
+
*
|
|
90
|
+
* Polled rather than subscribed: the state lives in another Durable Object,
|
|
91
|
+
* there is no event to wait on, and the whole window is under two minutes.
|
|
92
|
+
*
|
|
93
|
+
* **Read for every command, including the ones that need no dependencies.**
|
|
94
|
+
* The filter that spares `cat README.md` from queueing behind an `npm ci`
|
|
95
|
+
* lives in `execGate`, where it applies per advisory — because a dependency
|
|
96
|
+
* install and a full workspace are not relevant to the same commands, and one
|
|
97
|
+
* filter over both leaves a workspace at its ceiling silent for exactly the
|
|
98
|
+
* commands whose writes it is dropping. The cost is one same-colo RPC per
|
|
99
|
+
* command, against a class of silent data loss.
|
|
100
|
+
*/
|
|
101
|
+
const awaitAdvisories = async (command, signal) => {
|
|
102
|
+
if (!advisories)
|
|
103
|
+
return {};
|
|
104
|
+
// Fails **open**, and that belongs here rather than at the call site: this
|
|
105
|
+
// is a read of another Durable Object's state. An error must not take out a
|
|
106
|
+
// working shell — running the command is exactly what would have happened
|
|
107
|
+
// before the gate existed, and a spurious blockage would strand the
|
|
108
|
+
// agent.
|
|
109
|
+
const read = async () => {
|
|
110
|
+
try {
|
|
111
|
+
signal?.throwIfAborted();
|
|
112
|
+
return await withAbort(signal, advisories());
|
|
113
|
+
}
|
|
114
|
+
catch (err) {
|
|
115
|
+
// Open on a failed read, never on a cancel: failing open here would go on
|
|
116
|
+
// to run the command the caller just gave up on.
|
|
117
|
+
if (signal?.aborted)
|
|
118
|
+
throw err;
|
|
119
|
+
return [];
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
// Clamped to whatever is left of the gate, not the bare interval. A fixed
|
|
123
|
+
// sleep makes `installGateMs` a floor rather than the ceiling it is
|
|
124
|
+
// documented to be: at a 100 ms gate the loop still slept the full three
|
|
125
|
+
// seconds before looking again, so a public timeout overshot by 30×.
|
|
126
|
+
const deadline = Date.now() + gateMs;
|
|
127
|
+
let current = await read();
|
|
128
|
+
// Keyed on the gate's own verdict rather than on a state name, so "what is
|
|
129
|
+
// worth waiting for" has one definition and it is the one that will decide
|
|
130
|
+
// the outcome.
|
|
131
|
+
while (execGate(current, command).block && Date.now() < deadline) {
|
|
132
|
+
const wait = Math.min(INSTALL_POLL_MS, deadline - Date.now());
|
|
133
|
+
// Throws on a cancel rather than returning the verdict so far: a gate that
|
|
134
|
+
// outlived its caller would otherwise go on to run the command it was holding.
|
|
135
|
+
await withAbort(signal, new Promise((resolve) => setTimeout(resolve, wait)));
|
|
136
|
+
current = await read();
|
|
137
|
+
}
|
|
138
|
+
return execGate(current, command);
|
|
139
|
+
};
|
|
140
|
+
/**
|
|
141
|
+
* Whether a write can succeed at all, asked once and not polled.
|
|
142
|
+
*
|
|
143
|
+
* Separate from {@link awaitAdvisories} because the question is different:
|
|
144
|
+
* there is no command to classify and nothing worth waiting for. An install in
|
|
145
|
+
* flight does not stop a file being written, and the one thing that does —
|
|
146
|
+
* a workspace that no longer accepts writes — never resolves on its own.
|
|
147
|
+
*
|
|
148
|
+
* Fails **open** for the same reason the exec gate does: a read of another
|
|
149
|
+
* Durable Object's state must not take out a working tool.
|
|
150
|
+
*/
|
|
151
|
+
const refuseWrite = async () => {
|
|
152
|
+
if (!advisories)
|
|
153
|
+
return undefined;
|
|
154
|
+
try {
|
|
155
|
+
return writeGate(await advisories());
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
return undefined;
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
/**
|
|
162
|
+
* Host-supplied environment, with the undefined entries dropped.
|
|
163
|
+
*
|
|
164
|
+
* `RuntimeExecOptions.env` is `Record<string, string>`, and a config thunk
|
|
165
|
+
* that reads straight off `env` will hand back `undefined` for anything
|
|
166
|
+
* unset — which would otherwise arrive in the container as the string
|
|
167
|
+
* "undefined".
|
|
168
|
+
*/
|
|
169
|
+
const definedEnv = () => {
|
|
170
|
+
if (!env)
|
|
171
|
+
return undefined;
|
|
172
|
+
const entries = Object.entries(env()).filter((entry) => entry[1] !== undefined);
|
|
173
|
+
return entries.length > 0 ? Object.fromEntries(entries) : undefined;
|
|
174
|
+
};
|
|
175
|
+
/**
|
|
176
|
+
* Open the workspace, run one file operation in it, and own the failure.
|
|
177
|
+
*
|
|
178
|
+
* Lines every file tool would otherwise repeat with only the verb changed,
|
|
179
|
+
* and a chance for the next one to be written without them. The catch is the
|
|
180
|
+
* point: a failed file operation is the model's to recover from, and it can
|
|
181
|
+
* only recover from what it is told, so this returns the sentence rather than
|
|
182
|
+
* throwing it.
|
|
183
|
+
*
|
|
184
|
+
* `bash` deliberately does not use it. That one recognises `EEXEC_LOST`,
|
|
185
|
+
* logs, and carries an install warning through the failure path — a bespoke
|
|
186
|
+
* catch saying something this cannot.
|
|
187
|
+
*
|
|
188
|
+
* It opens through `fsWorkspace`, which is what makes the context block's
|
|
189
|
+
* sentence about these tools true: they answer while the container is down.
|
|
190
|
+
*/
|
|
191
|
+
const inWorkspace = async (gerund, subject, body) => {
|
|
192
|
+
try {
|
|
193
|
+
const env_1 = { stack: [], error: void 0, hasError: false };
|
|
194
|
+
try {
|
|
195
|
+
const ws = __addDisposableResource(env_1, await fsWorkspace(), false);
|
|
196
|
+
return await body(ws.fs);
|
|
197
|
+
}
|
|
198
|
+
catch (e_1) {
|
|
199
|
+
env_1.error = e_1;
|
|
200
|
+
env_1.hasError = true;
|
|
201
|
+
}
|
|
202
|
+
finally {
|
|
203
|
+
__disposeResources(env_1);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
catch (err) {
|
|
207
|
+
return `error ${gerund} ${subject}: ${String(err)}`;
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
return {
|
|
211
|
+
config,
|
|
212
|
+
cwd,
|
|
213
|
+
timeoutMs,
|
|
214
|
+
maxChars,
|
|
215
|
+
workspace,
|
|
216
|
+
awaitAdvisories,
|
|
217
|
+
definedEnv,
|
|
218
|
+
inWorkspace,
|
|
219
|
+
refuseWrite,
|
|
220
|
+
scope
|
|
221
|
+
};
|
|
222
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One mutation per file at a time, across every tool set in this isolate.
|
|
3
|
+
*
|
|
4
|
+
* `edit` reads, replaces and writes back over RPC, and the AI SDK runs one
|
|
5
|
+
* step's tool calls concurrently — so two edits to one file would both report
|
|
6
|
+
* success and the first would be lost. The workspace's `writeFile` takes the
|
|
7
|
+
* same lock, so Think's `write` never lands between an edit's read and its
|
|
8
|
+
* write. Module-level because a parent and a sub-agent can hold separate tool
|
|
9
|
+
* sets over one workspace; another isolate is out of reach.
|
|
10
|
+
*/
|
|
11
|
+
const tails = new Map();
|
|
12
|
+
/**
|
|
13
|
+
* `path` is canonicalised the way the filesystem resolves it, so spellings with
|
|
14
|
+
* `.`, `..` or doubled slashes share one lock.
|
|
15
|
+
*/
|
|
16
|
+
export async function withFileLock(scope, path, body) {
|
|
17
|
+
const key = `${scope}\0${canonical(path)}`;
|
|
18
|
+
const run = (tails.get(key) ?? Promise.resolve()).then(body);
|
|
19
|
+
const tail = run.catch(() => { });
|
|
20
|
+
tails.set(key, tail);
|
|
21
|
+
try {
|
|
22
|
+
return await run;
|
|
23
|
+
}
|
|
24
|
+
finally {
|
|
25
|
+
if (tails.get(key) === tail)
|
|
26
|
+
tails.delete(key);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function canonical(path) {
|
|
30
|
+
const out = [];
|
|
31
|
+
for (const segment of path.split("/")) {
|
|
32
|
+
if (segment === "" || segment === ".")
|
|
33
|
+
continue;
|
|
34
|
+
if (segment === "..")
|
|
35
|
+
out.pop();
|
|
36
|
+
else
|
|
37
|
+
out.push(segment);
|
|
38
|
+
}
|
|
39
|
+
return `/${out.join("/")}`;
|
|
40
|
+
}
|
package/dist/computer/gate.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { type WorkspaceAdvisory } from "
|
|
1
|
+
import { type WorkspaceAdvisory } from "../workspace/advisory.js";
|
|
2
2
|
/**
|
|
3
3
|
* What one shell command has to wait for, and what to say when it never ran.
|
|
4
4
|
*
|
|
5
|
-
* {@link file
|
|
5
|
+
* {@link file://../workspace/advisory.ts} decides what is true about the workspace and how
|
|
6
6
|
* to word it; this file decides what that means for a command about to run.
|
|
7
7
|
* {@link needsDependencies} is the part that cannot move there — it is a
|
|
8
8
|
* question about the *command*, and it is what stops `cat README.md` queueing
|
|
@@ -12,16 +12,16 @@ import { type WorkspaceAdvisory } from "./advisory.js";
|
|
|
12
12
|
* replaced underneath a command that was running.
|
|
13
13
|
*/
|
|
14
14
|
/**
|
|
15
|
-
* The one `
|
|
15
|
+
* The one `bash` failure that is not the command's fault.
|
|
16
16
|
*
|
|
17
17
|
* An execution running when the container is replaced throws `EEXEC_LOST`.
|
|
18
18
|
* Unexplained, the model receives `Execution "…" was lost when its container
|
|
19
19
|
* runtime was replaced`, reads it as a crash, and goes looking at its command.
|
|
20
20
|
*
|
|
21
|
-
* What it needs is
|
|
22
|
-
* because the filesystem is the Durable Object's rather than the
|
|
23
|
-
*
|
|
24
|
-
*
|
|
21
|
+
* What it needs is two facts: nothing ran to completion, and the workspace
|
|
22
|
+
* survived because the filesystem is the Durable Object's rather than the
|
|
23
|
+
* container's. So re-run it. `node_modules` is the container's, so the note
|
|
24
|
+
* says the replacement reinstalls it.
|
|
25
25
|
*
|
|
26
26
|
* Matched on `code` rather than the message — the property the package sets
|
|
27
27
|
* deliberately, and the one that survives a reworded string.
|
|
@@ -52,10 +52,10 @@ export declare function execLostNote(err: unknown): string | undefined;
|
|
|
52
52
|
* ## What a command is told depends on the command
|
|
53
53
|
*
|
|
54
54
|
* A dependency advisory reaches only commands that read `node_modules`; a
|
|
55
|
-
* universal one reaches everything.
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
55
|
+
* universal one reaches everything. Applying the dependency filter to capacity
|
|
56
|
+
* too is the mistake that asymmetry invites: a full workspace then says nothing
|
|
57
|
+
* at all to `echo hi > file.txt`, and the write being lost is usually not a
|
|
58
|
+
* dependency's.
|
|
59
59
|
*/
|
|
60
60
|
export interface ExecGate {
|
|
61
61
|
/** Set only for something transient: the command did not run. */
|
|
@@ -75,7 +75,7 @@ export declare function execGate(advisories: readonly WorkspaceAdvisory[], comma
|
|
|
75
75
|
/**
|
|
76
76
|
* Whether a write should happen at all, and what to say when it should not.
|
|
77
77
|
*
|
|
78
|
-
* `
|
|
78
|
+
* `write`, `edit` and `delete` do not go through {@link execGate}: they run no
|
|
79
79
|
* command, and a dependency install has nothing to do with writing source. One
|
|
80
80
|
* thing does reach them, and it is the worst of the set — a workspace that
|
|
81
81
|
* accepts no further writes takes an edit, reports the character count, and
|
package/dist/computer/gate.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { renderAdvisory, shapeOf } from "
|
|
1
|
+
import { renderAdvisory, shapeOf } from "../workspace/advisory.js";
|
|
2
2
|
/**
|
|
3
3
|
* What one shell command has to wait for, and what to say when it never ran.
|
|
4
4
|
*
|
|
5
|
-
* {@link file
|
|
5
|
+
* {@link file://../workspace/advisory.ts} decides what is true about the workspace and how
|
|
6
6
|
* to word it; this file decides what that means for a command about to run.
|
|
7
7
|
* {@link needsDependencies} is the part that cannot move there — it is a
|
|
8
8
|
* question about the *command*, and it is what stops `cat README.md` queueing
|
|
@@ -12,16 +12,16 @@ import { renderAdvisory, shapeOf } from "./advisory.js";
|
|
|
12
12
|
* replaced underneath a command that was running.
|
|
13
13
|
*/
|
|
14
14
|
/**
|
|
15
|
-
* The one `
|
|
15
|
+
* The one `bash` failure that is not the command's fault.
|
|
16
16
|
*
|
|
17
17
|
* An execution running when the container is replaced throws `EEXEC_LOST`.
|
|
18
18
|
* Unexplained, the model receives `Execution "…" was lost when its container
|
|
19
19
|
* runtime was replaced`, reads it as a crash, and goes looking at its command.
|
|
20
20
|
*
|
|
21
|
-
* What it needs is
|
|
22
|
-
* because the filesystem is the Durable Object's rather than the
|
|
23
|
-
*
|
|
24
|
-
*
|
|
21
|
+
* What it needs is two facts: nothing ran to completion, and the workspace
|
|
22
|
+
* survived because the filesystem is the Durable Object's rather than the
|
|
23
|
+
* container's. So re-run it. `node_modules` is the container's, so the note
|
|
24
|
+
* says the replacement reinstalls it.
|
|
25
25
|
*
|
|
26
26
|
* Matched on `code` rather than the message — the property the package sets
|
|
27
27
|
* deliberately, and the one that survives a reworded string.
|
|
@@ -31,9 +31,9 @@ export function execLostNote(err) {
|
|
|
31
31
|
return undefined;
|
|
32
32
|
return ("the container was replaced while this command was running, so it was lost — " +
|
|
33
33
|
"nothing ran to completion and no output survived. This is infrastructure, " +
|
|
34
|
-
"not your command: re-run it. The
|
|
35
|
-
"left it
|
|
36
|
-
"
|
|
34
|
+
"not your command: re-run it. The workspace is durable and is exactly as you " +
|
|
35
|
+
"left it. `node_modules` is not: the replacement reinstalls it, and a " +
|
|
36
|
+
"command that needs it waits for that.");
|
|
37
37
|
}
|
|
38
38
|
/** Which advisories this particular command needs to hear about. */
|
|
39
39
|
function relevantTo(advisories, command) {
|
|
@@ -76,7 +76,7 @@ export function execGate(advisories, command) {
|
|
|
76
76
|
/**
|
|
77
77
|
* Whether a write should happen at all, and what to say when it should not.
|
|
78
78
|
*
|
|
79
|
-
* `
|
|
79
|
+
* `write`, `edit` and `delete` do not go through {@link execGate}: they run no
|
|
80
80
|
* command, and a dependency install has nothing to do with writing source. One
|
|
81
81
|
* thing does reach them, and it is the worst of the set — a workspace that
|
|
82
82
|
* accepts no further writes takes an edit, reports the character count, and
|
|
@@ -108,7 +108,7 @@ export function writeGate(advisories) {
|
|
|
108
108
|
* Position is what makes this usable rather than merely cautious. Matching these
|
|
109
109
|
* anywhere in the string looks equivalent and is not: `\bvitest\b` also fires on
|
|
110
110
|
* `cat vitest.config.ts`, and `next.config.js`, `eslint.config.js` and
|
|
111
|
-
* `vite.config.ts` are exactly the files
|
|
111
|
+
* `vite.config.ts` are exactly the files an agent reads while orienting itself.
|
|
112
112
|
* Every one of those reads would then queue behind an `npm ci` it has no use for,
|
|
113
113
|
* which is the cost this whole check exists to remove.
|
|
114
114
|
*/
|