@coreplane/switchboard 1.227.0 → 1.228.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/dist/assets/deploy/cloudflare-memory/worker.ts +157 -3
- package/dist/assets/deploy/cloudflare-resident/worker.ts +129 -14
- package/dist/assets/deploy/cloudflare-sandbox/Dockerfile +22 -18
- package/dist/assets/deploy/cloudflare-sandbox/package.json +1 -1
- package/dist/assets/deploy/cloudflare-sandbox/runtime-supervisor.sh +11 -10
- package/dist/assets/deploy/cloudflare-sandbox/worker.ts +332 -299
- package/dist/assets/deploy/cloudflare-sandbox/wrangler.template.jsonc +2 -2
- package/dist/assets/package-lock.json +7 -48
- package/dist/assets/package.json +1 -1
- package/dist/assets/project.json +2 -2
- package/dist/assets/source.json +3 -3
- package/dist/assets/src/agents/registry.ts +15 -0
- package/dist/assets/src/core/coordinator/contract.ts +6 -0
- package/dist/assets/src/core/coordinator/driver.ts +8 -6
- package/dist/assets/src/core/runEvents.ts +34 -1
- package/dist/assets/src/core/runFriction.ts +2 -1
- package/dist/assets/src/core/runRecord.ts +46 -3
- package/dist/assets/src/core/runUsage.ts +199 -0
- package/dist/assets/src/core/ship/coordinator.ts +4 -2
- package/dist/assets/src/execution/residentRebind.ts +84 -7
- package/dist/assets/src/execution/sandboxErrors.ts +14 -38
- package/dist/assets/src/execution/sandboxLifecycle.ts +78 -0
- package/dist/assets/web/dist/.vite/manifest.json +18 -18
- package/dist/assets/web/dist/assets/{ResidentDetailPage-Chvll3wy.js → ResidentDetailPage-B1Q9pabX.js} +1 -1
- package/dist/assets/web/dist/assets/{ResidentsIndexPage-B5f8IwGF.js → ResidentsIndexPage-CP7U_4aK.js} +1 -1
- package/dist/assets/web/dist/assets/{RunRoutePage-CRvmCuXh.js → RunRoutePage-dCC25f_b.js} +4 -4
- package/dist/assets/web/dist/assets/{RunsIndexPage-BTJuKFTv.js → RunsIndexPage-Cgp4t4C8.js} +1 -1
- package/dist/assets/web/dist/assets/{ScheduledPage-BVfgUBvP.js → ScheduledPage-DthDA2xG.js} +1 -1
- package/dist/assets/web/dist/assets/{StatusDot-CFXbAw7S.js → StatusDot-DDc88Kbs.js} +1 -1
- package/dist/assets/web/dist/assets/{Tooltip-DcHMtbHJ.js → Tooltip-CBapNhsh.js} +1 -1
- package/dist/assets/web/dist/assets/{dist-DKhqHu0V.js → dist-BnwSD1cL.js} +1 -1
- package/dist/assets/web/dist/assets/{main-CveRd2yk.js → main-ZhQGbZ2E.js} +2 -2
- package/dist/cli.js +808 -155
- package/package.json +1 -1
- package/dist/assets/src/execution/sandboxKeepalive.ts +0 -118
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coreplane/switchboard",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.228.0",
|
|
4
4
|
"description": "Mention it in Slack and an agent reviews the PR, ships the fix, or answers the question — on the model you choose, with its tools running where you decide.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://openswitchboard.dev",
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
// Sandbox activity keepalive (docs/reference/specs/execution.md item 2): one in-flight
|
|
2
|
-
// exec never outlives the container's activity timeout.
|
|
3
|
-
//
|
|
4
|
-
// On @cloudflare/containers 0.0.28 the base class kept an activity clock that
|
|
5
|
-
// every proxied fetch renewed ONCE, before the fetch, and an alarm loop
|
|
6
|
-
// stopped the container (SIGTERM) the moment the clock read expired — with no
|
|
7
|
-
// notion of a request still in flight. So a single command running longer
|
|
8
|
-
// than `sleepAfter` had its container killed under it, deterministically, at
|
|
9
|
-
// exactly `sleepAfter`: the command ends in `Command execution failed` and
|
|
10
|
-
// the next one lands in a fresh container with an empty /workspace. Renewing
|
|
11
|
-
// the clock on a timer WHILE a command runs turns `sleepAfter` into what its
|
|
12
|
-
// name says: idle time. The 0.3.x containers class that ships with sandbox
|
|
13
|
-
// 0.12.x counts in-flight requests itself and refuses to expire while one is
|
|
14
|
-
// open, so the keepalive is now belt-and-braces; it stays until a live
|
|
15
|
-
// long-command run proves the SDK's own tracking on our path.
|
|
16
|
-
//
|
|
17
|
-
// Deliberately free of node: imports so wrangler can bundle it into the
|
|
18
|
-
// sandbox Worker.
|
|
19
|
-
|
|
20
|
-
/** How long an IDLE container stays warm before the Durable Object stops it,
|
|
21
|
-
* in the Container class's own `<n>[smh]` grammar. With the keepalive below
|
|
22
|
-
* (and the SDK's own in-flight tracking) this is pure idle time — a running
|
|
23
|
-
* command can never reach it. 5 minutes frees a finished thread's slot
|
|
24
|
-
* (`max_instances`) sooner than the SDK default (20 min on 0.3.x, 10 min on
|
|
25
|
-
* 0.12.x), while a follow-up inside 5 minutes still lands on the same warm
|
|
26
|
-
* workspace; a later one re-clones, which is the documented per-thread
|
|
27
|
-
* degradation (item 1). */
|
|
28
|
-
export const SANDBOX_SLEEP_AFTER = "5m";
|
|
29
|
-
|
|
30
|
-
/** How often a running command renews the activity clock. Well inside
|
|
31
|
-
* SANDBOX_SLEEP_AFTER (the unit tests hold the ordering), so between two
|
|
32
|
-
* renewals the clock always has minutes to spare. */
|
|
33
|
-
export const EXEC_KEEPALIVE_INTERVAL_MS = 60_000;
|
|
34
|
-
|
|
35
|
-
/** The Container class's `sleepAfter` grammar (`"5m"`, `"90s"`, `"1h"`), in
|
|
36
|
-
* milliseconds — so a test can compare the interval against it. */
|
|
37
|
-
export function parseSleepAfterMs(expr: string): number {
|
|
38
|
-
const m = /^(\d+)([smh])$/.exec(expr);
|
|
39
|
-
if (!m) throw new Error(`invalid sleepAfter expression: "${expr}" (expected <n>s, <n>m or <n>h)`);
|
|
40
|
-
const n = Number(m[1]);
|
|
41
|
-
return n * (m[2] === "s" ? 1_000 : m[2] === "m" ? 60_000 : 3_600_000);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/** Run `run()` while calling `renew()` every `intervalMs` until it settles —
|
|
45
|
-
* resolve or reject alike. A renew that throws or rejects is swallowed: the
|
|
46
|
-
* keepalive exists to protect the command's result, never to replace it. A
|
|
47
|
-
* command that finishes inside one interval never triggers a renew. */
|
|
48
|
-
export async function withActivityKeepalive<T>(
|
|
49
|
-
renew: () => void | Promise<void>,
|
|
50
|
-
run: () => Promise<T>,
|
|
51
|
-
intervalMs: number,
|
|
52
|
-
): Promise<T> {
|
|
53
|
-
const timer = setInterval(() => {
|
|
54
|
-
try {
|
|
55
|
-
void Promise.resolve(renew()).catch(() => {});
|
|
56
|
-
} catch {
|
|
57
|
-
// a synchronous throw from renew — same policy as an async rejection
|
|
58
|
-
}
|
|
59
|
-
}, intervalMs);
|
|
60
|
-
try {
|
|
61
|
-
return await run();
|
|
62
|
-
} finally {
|
|
63
|
-
clearInterval(timer);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/** The texts the SDK produces when the container is torn down under a
|
|
68
|
-
* command, across generations. 0.3.x: the exec handler's generic wrapper (its
|
|
69
|
-
* real cause, "Session terminated", sat in a field the client discarded), the
|
|
70
|
-
* cause itself, and the stale-session answer the same attempt got once the
|
|
71
|
-
* sessions were cleared. 0.12.x: the typed `SessionTerminatedError` text
|
|
72
|
-
* (`Session '<id>' shell exited (exit code: <n>)`) and the
|
|
73
|
-
* `OperationInterruptedError` text for a container that stopped under a
|
|
74
|
-
* pending call, and the disconnect text for a sandbox `destroy()`ed under a
|
|
75
|
-
* pending call. Anything else — a transport error, a file-op failure — is
|
|
76
|
-
* never recycle-shaped, whenever it arrives. */
|
|
77
|
-
const RECYCLE_SHAPED: readonly RegExp[] = [
|
|
78
|
-
/^Command execution failed$/,
|
|
79
|
-
/^Session terminated$/i,
|
|
80
|
-
/^Session '[^']*' not found$/i,
|
|
81
|
-
/^Session '[^']*' shell exited \(exit code: /i,
|
|
82
|
-
/^The sandbox container stopped while the operation was pending\.?$/i,
|
|
83
|
-
/^The sandbox was destroyed while the operation was pending\.?$/i,
|
|
84
|
-
];
|
|
85
|
-
|
|
86
|
-
/** The 0.12.x typed errors that MEAN the container went away under the call.
|
|
87
|
-
* Matched by name, not `instanceof`: the Worker sees them after the Durable
|
|
88
|
-
* Object RPC boundary, which keeps `name`/`message` and drops the prototype. */
|
|
89
|
-
export const RECYCLE_ERROR_NAMES: readonly string[] = ["SessionTerminatedError", "OperationInterruptedError"];
|
|
90
|
-
|
|
91
|
-
/** Type first, text second: a typed recycle error, or a recycle-shaped text. */
|
|
92
|
-
export function isRecycleError(err: { name?: string; message?: string }): boolean {
|
|
93
|
-
if (err.name && RECYCLE_ERROR_NAMES.includes(err.name)) return true;
|
|
94
|
-
return !!err.message && RECYCLE_SHAPED.some((re) => re.test(err.message!.trim()));
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/** Grace inside which a recycle-shaped TEXT is taken at face value: a session
|
|
98
|
-
* that fails to start does so in seconds, not minutes. A typed recycle error
|
|
99
|
-
* needs no grace — the SDK is stating the container stopped. */
|
|
100
|
-
const RECYCLE_SUSPECT_AFTER_MS = 60_000;
|
|
101
|
-
|
|
102
|
-
/** The message `/exec` puts in-body when a command's failure looks like the
|
|
103
|
-
* container was recycled under it: a typed recycle error (`certain`), or a
|
|
104
|
-
* recycle-shaped text that arrived more than a minute into THIS attempt (a
|
|
105
|
-
* startup failure shows in seconds). Any other text, however late, is
|
|
106
|
-
* returned unchanged — timing alone never rewords an unrelated error. The exit
|
|
107
|
-
* code stays 127: it IS an infra failure — the workspace really is gone — and
|
|
108
|
-
* a faked exit 124 would tell the model to shorten a command that was never
|
|
109
|
-
* the problem. */
|
|
110
|
-
export function recycledMidCommandMessage(elapsedMs: number, msg: string, certain = false): string {
|
|
111
|
-
const shaped = RECYCLE_SHAPED.some((re) => re.test(msg.trim()));
|
|
112
|
-
if (!certain && (!shaped || elapsedMs <= RECYCLE_SUSPECT_AFTER_MS)) return msg;
|
|
113
|
-
const secs = Math.round(elapsedMs / 1_000);
|
|
114
|
-
return (
|
|
115
|
-
`sandbox recycled mid-command after ${secs}s — the container was replaced and /workspace is empty; ` +
|
|
116
|
-
`re-clone before continuing (${msg})`
|
|
117
|
-
);
|
|
118
|
-
}
|