@madarco/agentbox 0.9.0 → 0.10.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/CHANGELOG.md +89 -0
- package/README.md +161 -0
- package/dist/{_cloud-attach-ZXBCNWJX.js → _cloud-attach-O6NYTLES.js} +3 -3
- package/dist/{chunk-BXQMIEHC.js → chunk-2GPORKYF.js} +254 -162
- package/dist/chunk-2GPORKYF.js.map +1 -0
- package/dist/{chunk-NCJP5MTN.js → chunk-7UIAO7PC.js} +213 -51
- package/dist/chunk-7UIAO7PC.js.map +1 -0
- package/dist/{chunk-GU5LW4B5.js → chunk-R4O5WPHW.js} +374 -62
- package/dist/chunk-R4O5WPHW.js.map +1 -0
- package/dist/{dist-GDHP34ZK.js → dist-5FQGYRW5.js} +15 -3
- package/dist/dist-5FQGYRW5.js.map +1 -0
- package/dist/{dist-32EZBYG4.js → dist-BQNX7RQE.js} +12 -2
- package/dist/{dist-XML54CNB.js → dist-PZW3GWWU.js} +30 -5
- package/dist/dist-PZW3GWWU.js.map +1 -0
- package/dist/{dist-CX5CGVEB.js → dist-TMHSUVTP.js} +3 -3
- package/dist/index.js +1773 -526
- package/dist/index.js.map +1 -1
- package/package.json +9 -7
- package/runtime/docker/apps/cli/share/agentbox-setup/SKILL.md +9 -8
- package/runtime/docker/packages/ctl/dist/bin.cjs +32 -3
- package/runtime/hetzner/agentbox-setup-skill.md +9 -8
- package/runtime/hetzner/ctl.cjs +32 -3
- package/runtime/relay/bin.cjs +32 -3
- package/runtime/vercel/agentbox-setup-skill.md +9 -8
- package/runtime/vercel/ctl.cjs +32 -3
- package/runtime/vercel/custom-system-CLAUDE.md +1 -4
- package/runtime/vercel/scripts/provision.sh +40 -0
- package/share/agentbox-setup/SKILL.md +9 -8
- package/dist/chunk-BXQMIEHC.js.map +0 -1
- package/dist/chunk-GU5LW4B5.js.map +0 -1
- package/dist/chunk-NCJP5MTN.js.map +0 -1
- package/dist/dist-GDHP34ZK.js.map +0 -1
- package/dist/dist-XML54CNB.js.map +0 -1
- /package/dist/{_cloud-attach-ZXBCNWJX.js.map → _cloud-attach-O6NYTLES.js.map} +0 -0
- /package/dist/{dist-32EZBYG4.js.map → dist-BQNX7RQE.js.map} +0 -0
- /package/dist/{dist-CX5CGVEB.js.map → dist-TMHSUVTP.js.map} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@madarco/agentbox",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Launch Claude Code, Codex, and other coding agents in isolated sandboxes",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Marco D'Alia",
|
|
@@ -37,7 +37,8 @@
|
|
|
37
37
|
"files": [
|
|
38
38
|
"dist",
|
|
39
39
|
"share",
|
|
40
|
-
"runtime"
|
|
40
|
+
"runtime",
|
|
41
|
+
"CHANGELOG.md"
|
|
41
42
|
],
|
|
42
43
|
"dependencies": {
|
|
43
44
|
"@clack/prompts": "^0.9.0",
|
|
@@ -57,16 +58,16 @@
|
|
|
57
58
|
"tsup": "^8.3.5",
|
|
58
59
|
"typescript": "^5.7.2",
|
|
59
60
|
"vitest": "^2.1.8",
|
|
61
|
+
"@agentbox/config": "0.0.0",
|
|
62
|
+
"@agentbox/ctl": "0.0.0",
|
|
60
63
|
"@agentbox/sandbox-core": "0.0.0",
|
|
61
64
|
"@agentbox/core": "0.0.0",
|
|
62
65
|
"@agentbox/relay": "0.0.0",
|
|
63
|
-
"@agentbox/ctl": "0.0.0",
|
|
64
|
-
"@agentbox/config": "0.0.0",
|
|
65
66
|
"@agentbox/sandbox-daytona": "0.0.0",
|
|
66
|
-
"@agentbox/sandbox-vercel": "0.0.0",
|
|
67
|
-
"@agentbox/sandbox-cloud": "0.0.0",
|
|
68
67
|
"@agentbox/sandbox-docker": "0.0.0",
|
|
69
|
-
"@agentbox/sandbox-
|
|
68
|
+
"@agentbox/sandbox-cloud": "0.0.0",
|
|
69
|
+
"@agentbox/sandbox-hetzner": "0.0.0",
|
|
70
|
+
"@agentbox/sandbox-vercel": "0.0.0"
|
|
70
71
|
},
|
|
71
72
|
"scripts": {
|
|
72
73
|
"build": "tsup",
|
|
@@ -75,6 +76,7 @@
|
|
|
75
76
|
"test": "vitest run",
|
|
76
77
|
"typecheck": "tsc --noEmit",
|
|
77
78
|
"clean": "rm -rf dist runtime .turbo",
|
|
79
|
+
"version": "git add CHANGELOG.md",
|
|
78
80
|
"publish:patch": "npm version patch && git push --follow-tags",
|
|
79
81
|
"publish:minor": "npm version minor && git push --follow-tags"
|
|
80
82
|
}
|
|
@@ -164,14 +164,7 @@ services:
|
|
|
164
164
|
- A service with `restart: never` and an autostart dependency will block the dependent forever after one failed run — usually a mistake.
|
|
165
165
|
- `command:` is either a shell string (run via `bash -c`) or an argv array. Use the argv form if you need to avoid shell quoting.
|
|
166
166
|
|
|
167
|
-
## 8.
|
|
168
|
-
|
|
169
|
-
Checkpoint (snapshot) this box writable layer: once the box is warmed up (deps installed, services ready), checkpoint it with `agentbox-ctl checkpoint --name setup --replace --set-default` so future boxes start ready.
|
|
170
|
-
Run this command exactly once. The `--name setup --replace` makes it idempotent — if it ever needs to run again it overwrites the existing `setup` checkpoint instead of stacking duplicates.
|
|
171
|
-
This doesn't need to be confirmed by the user.
|
|
172
|
-
It will pause the container for several seconds so warn the user about it and write Done when it's done.
|
|
173
|
-
|
|
174
|
-
## 9. Hand-off
|
|
167
|
+
## 8. Hand-off
|
|
175
168
|
|
|
176
169
|
Tell the user (verbatim):
|
|
177
170
|
|
|
@@ -187,6 +180,14 @@ Tell the user (verbatim):
|
|
|
187
180
|
your box is ready, you can start more sessions with `agentbox claude`
|
|
188
181
|
you can access the web app at https://<boxname>.localhost
|
|
189
182
|
|
|
183
|
+
|
|
184
|
+
## 9. Checkpoint the warm state - DON't SKIP THIS STEP
|
|
185
|
+
|
|
186
|
+
Checkpoint (snapshot) this box writable layer: once the box is warmed up (deps installed, services ready), checkpoint it with `agentbox-ctl checkpoint --name setup --replace --set-default` so future boxes start ready.
|
|
187
|
+
Run this command exactly once. The `--name setup --replace` makes it idempotent — if it ever needs to run again it overwrites the existing `setup` checkpoint instead of stacking duplicates.
|
|
188
|
+
On all providers except Vercel, this doesn't need to be confirmed by the user. It will pause the container for several seconds so warn the user about it and write Done when it's done.
|
|
189
|
+
On Vercel: this actually STOPS the sandbox, so warn the user about it. Also the system will ask confirmation.
|
|
190
|
+
|
|
190
191
|
## 10. Known issues
|
|
191
192
|
|
|
192
193
|
- For Nextjs/Vite/Tasnstack projects, makes sure to forward also websocket for hot reload.
|
|
@@ -18599,11 +18599,21 @@ var KEY_REGISTRY = [
|
|
|
18599
18599
|
type: "string",
|
|
18600
18600
|
description: "tmux session name for `agentbox claude`."
|
|
18601
18601
|
},
|
|
18602
|
+
{
|
|
18603
|
+
key: "claude.dangerouslySkipPermissions",
|
|
18604
|
+
type: "bool",
|
|
18605
|
+
description: "Launch claude in new boxes with --dangerously-skip-permissions (auto-accept tool use). Safe because boxes are isolated; on by default. Override per-box with --no-dangerously-skip-permissions."
|
|
18606
|
+
},
|
|
18602
18607
|
{
|
|
18603
18608
|
key: "codex.sessionName",
|
|
18604
18609
|
type: "string",
|
|
18605
18610
|
description: "tmux session name for `agentbox codex`."
|
|
18606
18611
|
},
|
|
18612
|
+
{
|
|
18613
|
+
key: "codex.dangerouslySkipPermissions",
|
|
18614
|
+
type: "bool",
|
|
18615
|
+
description: "Launch codex in new boxes with --dangerously-bypass-approvals-and-sandbox (never prompt for approval). Safe because boxes are isolated; on by default. Override per-box with --no-dangerously-skip-permissions."
|
|
18616
|
+
},
|
|
18607
18617
|
{
|
|
18608
18618
|
key: "opencode.sessionName",
|
|
18609
18619
|
type: "string",
|
|
@@ -19657,6 +19667,18 @@ async function runCheckpointRpc(action, deps) {
|
|
|
19657
19667
|
stderr: "relay: AGENTBOX_CLI_ENTRY not set; cannot run checkpoint host-side\n"
|
|
19658
19668
|
};
|
|
19659
19669
|
}
|
|
19670
|
+
if (deps.backendName === "vercel" && deps.prompts && deps.subscribers && deps.subscribers.forBox(deps.boxId).length > 0) {
|
|
19671
|
+
const verdict = await askPrompt(deps.prompts, deps.subscribers, deps.boxId, {
|
|
19672
|
+
kind: "confirm",
|
|
19673
|
+
message: `Create checkpoint on ${deps.boxName ?? deps.boxId}? The vercel box will stop and reboot.`,
|
|
19674
|
+
detail: params.name ? `checkpoint: ${params.name}` : "(auto-named)",
|
|
19675
|
+
defaultAnswer: "n",
|
|
19676
|
+
context: { command: "checkpoint create", argv: params.name ? [params.name] : [] }
|
|
19677
|
+
});
|
|
19678
|
+
if (verdict.answer !== "y") {
|
|
19679
|
+
return { exitCode: 10, stdout: "", stderr: "checkpoint denied by user\n" };
|
|
19680
|
+
}
|
|
19681
|
+
}
|
|
19660
19682
|
const argv = [process.execPath, entry, "checkpoint", "create", deps.boxId];
|
|
19661
19683
|
if (params.name) argv.push("--name", params.name);
|
|
19662
19684
|
if (params.merged === true) argv.push("--merged");
|
|
@@ -20013,7 +20035,12 @@ function createRelayServer(opts) {
|
|
|
20013
20035
|
boxes: registry.size(),
|
|
20014
20036
|
events: events.size(),
|
|
20015
20037
|
pid: process.pid,
|
|
20016
|
-
cliEntry: Boolean(process.env.AGENTBOX_CLI_ENTRY)
|
|
20038
|
+
cliEntry: Boolean(process.env.AGENTBOX_CLI_ENTRY),
|
|
20039
|
+
// The spawning CLI's version/commit (inherited via env at spawn time).
|
|
20040
|
+
// `version` lets host-side ensureRelay reclaim a relay left over from a
|
|
20041
|
+
// different agentbox version; `commit` is observability-only.
|
|
20042
|
+
version: process.env.AGENTBOX_CLI_VERSION || void 0,
|
|
20043
|
+
commit: process.env.AGENTBOX_CLI_COMMIT || void 0
|
|
20017
20044
|
});
|
|
20018
20045
|
return;
|
|
20019
20046
|
}
|
|
@@ -21957,6 +21984,7 @@ var Supervisor = class extends import_node_events15.EventEmitter {
|
|
|
21957
21984
|
super();
|
|
21958
21985
|
this.opts = opts;
|
|
21959
21986
|
this.relay = new RelayClient();
|
|
21987
|
+
this.webProxy = new WebProxy(opts.webProxyPort);
|
|
21960
21988
|
}
|
|
21961
21989
|
opts;
|
|
21962
21990
|
units = /* @__PURE__ */ new Map();
|
|
@@ -21966,7 +21994,7 @@ var Supervisor = class extends import_node_events15.EventEmitter {
|
|
|
21966
21994
|
scheduling = false;
|
|
21967
21995
|
rescheduleDirty = false;
|
|
21968
21996
|
relay;
|
|
21969
|
-
webProxy
|
|
21997
|
+
webProxy;
|
|
21970
21998
|
/** The relay client the supervisor pushes state events on. Shared with the
|
|
21971
21999
|
* status reporter so both use the same fire-and-forget channel. */
|
|
21972
22000
|
get relayClient() {
|
|
@@ -22893,7 +22921,8 @@ function resolveBoxRelayPort() {
|
|
|
22893
22921
|
}
|
|
22894
22922
|
var daemonCommand = new Command("daemon").description("Run the agentbox-ctl supervisor in the foreground").option("--socket <path>", "unix socket path", DEFAULT_SOCKET_PATH).option("--config <path>", "path to agentbox.yaml", DEFAULT_CONFIG_PATH).option("--log-dir <path>", "where per-service log files are written", DEFAULT_LOG_DIR).option("--workspace <path>", "cwd for service processes", "/workspace").action(async (opts) => {
|
|
22895
22923
|
const cfg = await loadConfig(opts.config);
|
|
22896
|
-
const
|
|
22924
|
+
const webProxyPort = Number(process.env.AGENTBOX_WEB_PROXY_PORT) || void 0;
|
|
22925
|
+
const sup = new Supervisor({ workspace: opts.workspace, logDir: opts.logDir, webProxyPort });
|
|
22897
22926
|
await sup.init(cfg);
|
|
22898
22927
|
const reporter = new StatusReporter({
|
|
22899
22928
|
supervisor: sup,
|
|
@@ -164,14 +164,7 @@ services:
|
|
|
164
164
|
- A service with `restart: never` and an autostart dependency will block the dependent forever after one failed run — usually a mistake.
|
|
165
165
|
- `command:` is either a shell string (run via `bash -c`) or an argv array. Use the argv form if you need to avoid shell quoting.
|
|
166
166
|
|
|
167
|
-
## 8.
|
|
168
|
-
|
|
169
|
-
Checkpoint (snapshot) this box writable layer: once the box is warmed up (deps installed, services ready), checkpoint it with `agentbox-ctl checkpoint --name setup --replace --set-default` so future boxes start ready.
|
|
170
|
-
Run this command exactly once. The `--name setup --replace` makes it idempotent — if it ever needs to run again it overwrites the existing `setup` checkpoint instead of stacking duplicates.
|
|
171
|
-
This doesn't need to be confirmed by the user.
|
|
172
|
-
It will pause the container for several seconds so warn the user about it and write Done when it's done.
|
|
173
|
-
|
|
174
|
-
## 9. Hand-off
|
|
167
|
+
## 8. Hand-off
|
|
175
168
|
|
|
176
169
|
Tell the user (verbatim):
|
|
177
170
|
|
|
@@ -187,6 +180,14 @@ Tell the user (verbatim):
|
|
|
187
180
|
your box is ready, you can start more sessions with `agentbox claude`
|
|
188
181
|
you can access the web app at https://<boxname>.localhost
|
|
189
182
|
|
|
183
|
+
|
|
184
|
+
## 9. Checkpoint the warm state - DON't SKIP THIS STEP
|
|
185
|
+
|
|
186
|
+
Checkpoint (snapshot) this box writable layer: once the box is warmed up (deps installed, services ready), checkpoint it with `agentbox-ctl checkpoint --name setup --replace --set-default` so future boxes start ready.
|
|
187
|
+
Run this command exactly once. The `--name setup --replace` makes it idempotent — if it ever needs to run again it overwrites the existing `setup` checkpoint instead of stacking duplicates.
|
|
188
|
+
On all providers except Vercel, this doesn't need to be confirmed by the user. It will pause the container for several seconds so warn the user about it and write Done when it's done.
|
|
189
|
+
On Vercel: this actually STOPS the sandbox, so warn the user about it. Also the system will ask confirmation.
|
|
190
|
+
|
|
190
191
|
## 10. Known issues
|
|
191
192
|
|
|
192
193
|
- For Nextjs/Vite/Tasnstack projects, makes sure to forward also websocket for hot reload.
|
package/runtime/hetzner/ctl.cjs
CHANGED
|
@@ -18599,11 +18599,21 @@ var KEY_REGISTRY = [
|
|
|
18599
18599
|
type: "string",
|
|
18600
18600
|
description: "tmux session name for `agentbox claude`."
|
|
18601
18601
|
},
|
|
18602
|
+
{
|
|
18603
|
+
key: "claude.dangerouslySkipPermissions",
|
|
18604
|
+
type: "bool",
|
|
18605
|
+
description: "Launch claude in new boxes with --dangerously-skip-permissions (auto-accept tool use). Safe because boxes are isolated; on by default. Override per-box with --no-dangerously-skip-permissions."
|
|
18606
|
+
},
|
|
18602
18607
|
{
|
|
18603
18608
|
key: "codex.sessionName",
|
|
18604
18609
|
type: "string",
|
|
18605
18610
|
description: "tmux session name for `agentbox codex`."
|
|
18606
18611
|
},
|
|
18612
|
+
{
|
|
18613
|
+
key: "codex.dangerouslySkipPermissions",
|
|
18614
|
+
type: "bool",
|
|
18615
|
+
description: "Launch codex in new boxes with --dangerously-bypass-approvals-and-sandbox (never prompt for approval). Safe because boxes are isolated; on by default. Override per-box with --no-dangerously-skip-permissions."
|
|
18616
|
+
},
|
|
18607
18617
|
{
|
|
18608
18618
|
key: "opencode.sessionName",
|
|
18609
18619
|
type: "string",
|
|
@@ -19657,6 +19667,18 @@ async function runCheckpointRpc(action, deps) {
|
|
|
19657
19667
|
stderr: "relay: AGENTBOX_CLI_ENTRY not set; cannot run checkpoint host-side\n"
|
|
19658
19668
|
};
|
|
19659
19669
|
}
|
|
19670
|
+
if (deps.backendName === "vercel" && deps.prompts && deps.subscribers && deps.subscribers.forBox(deps.boxId).length > 0) {
|
|
19671
|
+
const verdict = await askPrompt(deps.prompts, deps.subscribers, deps.boxId, {
|
|
19672
|
+
kind: "confirm",
|
|
19673
|
+
message: `Create checkpoint on ${deps.boxName ?? deps.boxId}? The vercel box will stop and reboot.`,
|
|
19674
|
+
detail: params.name ? `checkpoint: ${params.name}` : "(auto-named)",
|
|
19675
|
+
defaultAnswer: "n",
|
|
19676
|
+
context: { command: "checkpoint create", argv: params.name ? [params.name] : [] }
|
|
19677
|
+
});
|
|
19678
|
+
if (verdict.answer !== "y") {
|
|
19679
|
+
return { exitCode: 10, stdout: "", stderr: "checkpoint denied by user\n" };
|
|
19680
|
+
}
|
|
19681
|
+
}
|
|
19660
19682
|
const argv = [process.execPath, entry, "checkpoint", "create", deps.boxId];
|
|
19661
19683
|
if (params.name) argv.push("--name", params.name);
|
|
19662
19684
|
if (params.merged === true) argv.push("--merged");
|
|
@@ -20013,7 +20035,12 @@ function createRelayServer(opts) {
|
|
|
20013
20035
|
boxes: registry.size(),
|
|
20014
20036
|
events: events.size(),
|
|
20015
20037
|
pid: process.pid,
|
|
20016
|
-
cliEntry: Boolean(process.env.AGENTBOX_CLI_ENTRY)
|
|
20038
|
+
cliEntry: Boolean(process.env.AGENTBOX_CLI_ENTRY),
|
|
20039
|
+
// The spawning CLI's version/commit (inherited via env at spawn time).
|
|
20040
|
+
// `version` lets host-side ensureRelay reclaim a relay left over from a
|
|
20041
|
+
// different agentbox version; `commit` is observability-only.
|
|
20042
|
+
version: process.env.AGENTBOX_CLI_VERSION || void 0,
|
|
20043
|
+
commit: process.env.AGENTBOX_CLI_COMMIT || void 0
|
|
20017
20044
|
});
|
|
20018
20045
|
return;
|
|
20019
20046
|
}
|
|
@@ -21957,6 +21984,7 @@ var Supervisor = class extends import_node_events15.EventEmitter {
|
|
|
21957
21984
|
super();
|
|
21958
21985
|
this.opts = opts;
|
|
21959
21986
|
this.relay = new RelayClient();
|
|
21987
|
+
this.webProxy = new WebProxy(opts.webProxyPort);
|
|
21960
21988
|
}
|
|
21961
21989
|
opts;
|
|
21962
21990
|
units = /* @__PURE__ */ new Map();
|
|
@@ -21966,7 +21994,7 @@ var Supervisor = class extends import_node_events15.EventEmitter {
|
|
|
21966
21994
|
scheduling = false;
|
|
21967
21995
|
rescheduleDirty = false;
|
|
21968
21996
|
relay;
|
|
21969
|
-
webProxy
|
|
21997
|
+
webProxy;
|
|
21970
21998
|
/** The relay client the supervisor pushes state events on. Shared with the
|
|
21971
21999
|
* status reporter so both use the same fire-and-forget channel. */
|
|
21972
22000
|
get relayClient() {
|
|
@@ -22893,7 +22921,8 @@ function resolveBoxRelayPort() {
|
|
|
22893
22921
|
}
|
|
22894
22922
|
var daemonCommand = new Command("daemon").description("Run the agentbox-ctl supervisor in the foreground").option("--socket <path>", "unix socket path", DEFAULT_SOCKET_PATH).option("--config <path>", "path to agentbox.yaml", DEFAULT_CONFIG_PATH).option("--log-dir <path>", "where per-service log files are written", DEFAULT_LOG_DIR).option("--workspace <path>", "cwd for service processes", "/workspace").action(async (opts) => {
|
|
22895
22923
|
const cfg = await loadConfig(opts.config);
|
|
22896
|
-
const
|
|
22924
|
+
const webProxyPort = Number(process.env.AGENTBOX_WEB_PROXY_PORT) || void 0;
|
|
22925
|
+
const sup = new Supervisor({ workspace: opts.workspace, logDir: opts.logDir, webProxyPort });
|
|
22897
22926
|
await sup.init(cfg);
|
|
22898
22927
|
const reporter = new StatusReporter({
|
|
22899
22928
|
supervisor: sup,
|
package/runtime/relay/bin.cjs
CHANGED
|
@@ -18684,6 +18684,18 @@ async function runCheckpointRpc(action, deps) {
|
|
|
18684
18684
|
stderr: "relay: AGENTBOX_CLI_ENTRY not set; cannot run checkpoint host-side\n"
|
|
18685
18685
|
};
|
|
18686
18686
|
}
|
|
18687
|
+
if (deps.backendName === "vercel" && deps.prompts && deps.subscribers && deps.subscribers.forBox(deps.boxId).length > 0) {
|
|
18688
|
+
const verdict = await askPrompt(deps.prompts, deps.subscribers, deps.boxId, {
|
|
18689
|
+
kind: "confirm",
|
|
18690
|
+
message: `Create checkpoint on ${deps.boxName ?? deps.boxId}? The vercel box will stop and reboot.`,
|
|
18691
|
+
detail: params.name ? `checkpoint: ${params.name}` : "(auto-named)",
|
|
18692
|
+
defaultAnswer: "n",
|
|
18693
|
+
context: { command: "checkpoint create", argv: params.name ? [params.name] : [] }
|
|
18694
|
+
});
|
|
18695
|
+
if (verdict.answer !== "y") {
|
|
18696
|
+
return { exitCode: 10, stdout: "", stderr: "checkpoint denied by user\n" };
|
|
18697
|
+
}
|
|
18698
|
+
}
|
|
18687
18699
|
const argv = [process.execPath, entry, "checkpoint", "create", deps.boxId];
|
|
18688
18700
|
if (params.name) argv.push("--name", params.name);
|
|
18689
18701
|
if (params.merged === true) argv.push("--merged");
|
|
@@ -19300,7 +19312,12 @@ function createRelayServer(opts) {
|
|
|
19300
19312
|
boxes: registry.size(),
|
|
19301
19313
|
events: events.size(),
|
|
19302
19314
|
pid: process.pid,
|
|
19303
|
-
cliEntry: Boolean(process.env.AGENTBOX_CLI_ENTRY)
|
|
19315
|
+
cliEntry: Boolean(process.env.AGENTBOX_CLI_ENTRY),
|
|
19316
|
+
// The spawning CLI's version/commit (inherited via env at spawn time).
|
|
19317
|
+
// `version` lets host-side ensureRelay reclaim a relay left over from a
|
|
19318
|
+
// different agentbox version; `commit` is observability-only.
|
|
19319
|
+
version: process.env.AGENTBOX_CLI_VERSION || void 0,
|
|
19320
|
+
commit: process.env.AGENTBOX_CLI_COMMIT || void 0
|
|
19304
19321
|
});
|
|
19305
19322
|
return;
|
|
19306
19323
|
}
|
|
@@ -20111,10 +20128,12 @@ var BUILT_IN_DEFAULTS = {
|
|
|
20111
20128
|
maxLayers: 3
|
|
20112
20129
|
},
|
|
20113
20130
|
claude: {
|
|
20114
|
-
sessionName: "claude"
|
|
20131
|
+
sessionName: "claude",
|
|
20132
|
+
dangerouslySkipPermissions: true
|
|
20115
20133
|
},
|
|
20116
20134
|
codex: {
|
|
20117
|
-
sessionName: "codex"
|
|
20135
|
+
sessionName: "codex",
|
|
20136
|
+
dangerouslySkipPermissions: true
|
|
20118
20137
|
},
|
|
20119
20138
|
opencode: {
|
|
20120
20139
|
sessionName: "opencode"
|
|
@@ -20302,11 +20321,21 @@ var KEY_REGISTRY = [
|
|
|
20302
20321
|
type: "string",
|
|
20303
20322
|
description: "tmux session name for `agentbox claude`."
|
|
20304
20323
|
},
|
|
20324
|
+
{
|
|
20325
|
+
key: "claude.dangerouslySkipPermissions",
|
|
20326
|
+
type: "bool",
|
|
20327
|
+
description: "Launch claude in new boxes with --dangerously-skip-permissions (auto-accept tool use). Safe because boxes are isolated; on by default. Override per-box with --no-dangerously-skip-permissions."
|
|
20328
|
+
},
|
|
20305
20329
|
{
|
|
20306
20330
|
key: "codex.sessionName",
|
|
20307
20331
|
type: "string",
|
|
20308
20332
|
description: "tmux session name for `agentbox codex`."
|
|
20309
20333
|
},
|
|
20334
|
+
{
|
|
20335
|
+
key: "codex.dangerouslySkipPermissions",
|
|
20336
|
+
type: "bool",
|
|
20337
|
+
description: "Launch codex in new boxes with --dangerously-bypass-approvals-and-sandbox (never prompt for approval). Safe because boxes are isolated; on by default. Override per-box with --no-dangerously-skip-permissions."
|
|
20338
|
+
},
|
|
20310
20339
|
{
|
|
20311
20340
|
key: "opencode.sessionName",
|
|
20312
20341
|
type: "string",
|
|
@@ -164,14 +164,7 @@ services:
|
|
|
164
164
|
- A service with `restart: never` and an autostart dependency will block the dependent forever after one failed run — usually a mistake.
|
|
165
165
|
- `command:` is either a shell string (run via `bash -c`) or an argv array. Use the argv form if you need to avoid shell quoting.
|
|
166
166
|
|
|
167
|
-
## 8.
|
|
168
|
-
|
|
169
|
-
Checkpoint (snapshot) this box writable layer: once the box is warmed up (deps installed, services ready), checkpoint it with `agentbox-ctl checkpoint --name setup --replace --set-default` so future boxes start ready.
|
|
170
|
-
Run this command exactly once. The `--name setup --replace` makes it idempotent — if it ever needs to run again it overwrites the existing `setup` checkpoint instead of stacking duplicates.
|
|
171
|
-
This doesn't need to be confirmed by the user.
|
|
172
|
-
It will pause the container for several seconds so warn the user about it and write Done when it's done.
|
|
173
|
-
|
|
174
|
-
## 9. Hand-off
|
|
167
|
+
## 8. Hand-off
|
|
175
168
|
|
|
176
169
|
Tell the user (verbatim):
|
|
177
170
|
|
|
@@ -187,6 +180,14 @@ Tell the user (verbatim):
|
|
|
187
180
|
your box is ready, you can start more sessions with `agentbox claude`
|
|
188
181
|
you can access the web app at https://<boxname>.localhost
|
|
189
182
|
|
|
183
|
+
|
|
184
|
+
## 9. Checkpoint the warm state - DON't SKIP THIS STEP
|
|
185
|
+
|
|
186
|
+
Checkpoint (snapshot) this box writable layer: once the box is warmed up (deps installed, services ready), checkpoint it with `agentbox-ctl checkpoint --name setup --replace --set-default` so future boxes start ready.
|
|
187
|
+
Run this command exactly once. The `--name setup --replace` makes it idempotent — if it ever needs to run again it overwrites the existing `setup` checkpoint instead of stacking duplicates.
|
|
188
|
+
On all providers except Vercel, this doesn't need to be confirmed by the user. It will pause the container for several seconds so warn the user about it and write Done when it's done.
|
|
189
|
+
On Vercel: this actually STOPS the sandbox, so warn the user about it. Also the system will ask confirmation.
|
|
190
|
+
|
|
190
191
|
## 10. Known issues
|
|
191
192
|
|
|
192
193
|
- For Nextjs/Vite/Tasnstack projects, makes sure to forward also websocket for hot reload.
|
package/runtime/vercel/ctl.cjs
CHANGED
|
@@ -18599,11 +18599,21 @@ var KEY_REGISTRY = [
|
|
|
18599
18599
|
type: "string",
|
|
18600
18600
|
description: "tmux session name for `agentbox claude`."
|
|
18601
18601
|
},
|
|
18602
|
+
{
|
|
18603
|
+
key: "claude.dangerouslySkipPermissions",
|
|
18604
|
+
type: "bool",
|
|
18605
|
+
description: "Launch claude in new boxes with --dangerously-skip-permissions (auto-accept tool use). Safe because boxes are isolated; on by default. Override per-box with --no-dangerously-skip-permissions."
|
|
18606
|
+
},
|
|
18602
18607
|
{
|
|
18603
18608
|
key: "codex.sessionName",
|
|
18604
18609
|
type: "string",
|
|
18605
18610
|
description: "tmux session name for `agentbox codex`."
|
|
18606
18611
|
},
|
|
18612
|
+
{
|
|
18613
|
+
key: "codex.dangerouslySkipPermissions",
|
|
18614
|
+
type: "bool",
|
|
18615
|
+
description: "Launch codex in new boxes with --dangerously-bypass-approvals-and-sandbox (never prompt for approval). Safe because boxes are isolated; on by default. Override per-box with --no-dangerously-skip-permissions."
|
|
18616
|
+
},
|
|
18607
18617
|
{
|
|
18608
18618
|
key: "opencode.sessionName",
|
|
18609
18619
|
type: "string",
|
|
@@ -19657,6 +19667,18 @@ async function runCheckpointRpc(action, deps) {
|
|
|
19657
19667
|
stderr: "relay: AGENTBOX_CLI_ENTRY not set; cannot run checkpoint host-side\n"
|
|
19658
19668
|
};
|
|
19659
19669
|
}
|
|
19670
|
+
if (deps.backendName === "vercel" && deps.prompts && deps.subscribers && deps.subscribers.forBox(deps.boxId).length > 0) {
|
|
19671
|
+
const verdict = await askPrompt(deps.prompts, deps.subscribers, deps.boxId, {
|
|
19672
|
+
kind: "confirm",
|
|
19673
|
+
message: `Create checkpoint on ${deps.boxName ?? deps.boxId}? The vercel box will stop and reboot.`,
|
|
19674
|
+
detail: params.name ? `checkpoint: ${params.name}` : "(auto-named)",
|
|
19675
|
+
defaultAnswer: "n",
|
|
19676
|
+
context: { command: "checkpoint create", argv: params.name ? [params.name] : [] }
|
|
19677
|
+
});
|
|
19678
|
+
if (verdict.answer !== "y") {
|
|
19679
|
+
return { exitCode: 10, stdout: "", stderr: "checkpoint denied by user\n" };
|
|
19680
|
+
}
|
|
19681
|
+
}
|
|
19660
19682
|
const argv = [process.execPath, entry, "checkpoint", "create", deps.boxId];
|
|
19661
19683
|
if (params.name) argv.push("--name", params.name);
|
|
19662
19684
|
if (params.merged === true) argv.push("--merged");
|
|
@@ -20013,7 +20035,12 @@ function createRelayServer(opts) {
|
|
|
20013
20035
|
boxes: registry.size(),
|
|
20014
20036
|
events: events.size(),
|
|
20015
20037
|
pid: process.pid,
|
|
20016
|
-
cliEntry: Boolean(process.env.AGENTBOX_CLI_ENTRY)
|
|
20038
|
+
cliEntry: Boolean(process.env.AGENTBOX_CLI_ENTRY),
|
|
20039
|
+
// The spawning CLI's version/commit (inherited via env at spawn time).
|
|
20040
|
+
// `version` lets host-side ensureRelay reclaim a relay left over from a
|
|
20041
|
+
// different agentbox version; `commit` is observability-only.
|
|
20042
|
+
version: process.env.AGENTBOX_CLI_VERSION || void 0,
|
|
20043
|
+
commit: process.env.AGENTBOX_CLI_COMMIT || void 0
|
|
20017
20044
|
});
|
|
20018
20045
|
return;
|
|
20019
20046
|
}
|
|
@@ -21957,6 +21984,7 @@ var Supervisor = class extends import_node_events15.EventEmitter {
|
|
|
21957
21984
|
super();
|
|
21958
21985
|
this.opts = opts;
|
|
21959
21986
|
this.relay = new RelayClient();
|
|
21987
|
+
this.webProxy = new WebProxy(opts.webProxyPort);
|
|
21960
21988
|
}
|
|
21961
21989
|
opts;
|
|
21962
21990
|
units = /* @__PURE__ */ new Map();
|
|
@@ -21966,7 +21994,7 @@ var Supervisor = class extends import_node_events15.EventEmitter {
|
|
|
21966
21994
|
scheduling = false;
|
|
21967
21995
|
rescheduleDirty = false;
|
|
21968
21996
|
relay;
|
|
21969
|
-
webProxy
|
|
21997
|
+
webProxy;
|
|
21970
21998
|
/** The relay client the supervisor pushes state events on. Shared with the
|
|
21971
21999
|
* status reporter so both use the same fire-and-forget channel. */
|
|
21972
22000
|
get relayClient() {
|
|
@@ -22893,7 +22921,8 @@ function resolveBoxRelayPort() {
|
|
|
22893
22921
|
}
|
|
22894
22922
|
var daemonCommand = new Command("daemon").description("Run the agentbox-ctl supervisor in the foreground").option("--socket <path>", "unix socket path", DEFAULT_SOCKET_PATH).option("--config <path>", "path to agentbox.yaml", DEFAULT_CONFIG_PATH).option("--log-dir <path>", "where per-service log files are written", DEFAULT_LOG_DIR).option("--workspace <path>", "cwd for service processes", "/workspace").action(async (opts) => {
|
|
22895
22923
|
const cfg = await loadConfig(opts.config);
|
|
22896
|
-
const
|
|
22924
|
+
const webProxyPort = Number(process.env.AGENTBOX_WEB_PROXY_PORT) || void 0;
|
|
22925
|
+
const sup = new Supervisor({ workspace: opts.workspace, logDir: opts.logDir, webProxyPort });
|
|
22897
22926
|
await sup.init(cfg);
|
|
22898
22927
|
const reporter = new StatusReporter({
|
|
22899
22928
|
supervisor: sup,
|
|
@@ -15,10 +15,7 @@ This box is **persistent**: stopping it captures a snapshot and resuming
|
|
|
15
15
|
restarts from that snapshot, so the filesystem survives a pause. You can also
|
|
16
16
|
save the current filesystem state for future boxes with
|
|
17
17
|
`agentbox-ctl checkpoint --set-default`, but a checkpoint/snapshot STOPS the
|
|
18
|
-
box, so use it only at the end of the setup wizard
|
|
19
|
-
idempotent tasks in `agentbox.yaml`. NB: this `agentbox-ctl` command normally
|
|
20
|
-
doesn't need user confirmation, but since it stops the box, ask for
|
|
21
|
-
confirmation before running it.
|
|
18
|
+
box, so use it only at the end of the setup wizard.
|
|
22
19
|
|
|
23
20
|
`/workspace` is a normal git checkout seeded from the host repo at create time.
|
|
24
21
|
Because there is no host bind-mount, plain `git` inside the box only affects
|
|
@@ -245,6 +245,46 @@ step "Claude Code (native installer, run as vscode)"
|
|
|
245
245
|
sudo -u vscode -H bash -lc 'curl -fsSL https://claude.ai/install.sh | bash -s stable'
|
|
246
246
|
done_ "Claude Code (native installer, run as vscode)"
|
|
247
247
|
|
|
248
|
+
step "Chrome runtime libs (dnf)"
|
|
249
|
+
# agent-browser launches Chromium at AGENT_BROWSER_EXECUTABLE_PATH
|
|
250
|
+
# (/usr/local/bin/chromium, set in the login-shell shim above). Docker + hetzner
|
|
251
|
+
# bake that binary in; do the same here. These are the AL2023 (dnf) equivalents
|
|
252
|
+
# of the Ubuntu `t64` Chrome deps the other two providers apt-install — the
|
|
253
|
+
# Ubuntu package names don't exist on Amazon Linux 2023. Fail loud: a missing lib
|
|
254
|
+
# means a silently broken browser, not a convenience we can skip.
|
|
255
|
+
dnf install -y -q --allowerasing \
|
|
256
|
+
nss nspr atk at-spi2-atk at-spi2-core cups-libs \
|
|
257
|
+
libdrm libxkbcommon libXcomposite libXdamage libXfixes libXrandr \
|
|
258
|
+
libXext libX11 libxcb mesa-libgbm pango cairo alsa-lib \
|
|
259
|
+
liberation-fonts
|
|
260
|
+
done_ "Chrome runtime libs (dnf)"
|
|
261
|
+
|
|
262
|
+
step "playwright + Chromium download (as vscode)"
|
|
263
|
+
# Run the download as vscode so the cache lands under
|
|
264
|
+
# /home/vscode/.cache/ms-playwright. Resolve a stable symlink at
|
|
265
|
+
# /usr/local/bin/chromium so AGENT_BROWSER_EXECUTABLE_PATH stays predictable
|
|
266
|
+
# across Chromium revision bumps (mirrors hetzner install-box.sh).
|
|
267
|
+
npm install -g playwright 2>&1 | tail -3
|
|
268
|
+
sudo -u vscode -H bash -lc 'playwright install chromium'
|
|
269
|
+
CHROME_BIN="$(sudo -u vscode -H bash -lc 'ls /home/vscode/.cache/ms-playwright/chromium-*/chrome-linux*/chrome 2>/dev/null | sort | tail -1')"
|
|
270
|
+
if [ -z "$CHROME_BIN" ] || [ ! -x "$CHROME_BIN" ]; then
|
|
271
|
+
echo "provision.sh: could not resolve Playwright Chromium binary" >&2
|
|
272
|
+
exit 70
|
|
273
|
+
fi
|
|
274
|
+
# Fail loud if a shared lib is missing — this is where an incomplete AL2023 dep
|
|
275
|
+
# set surfaces at bake time instead of at first agent-browser launch. Capture
|
|
276
|
+
# ldd's output first (|| true): under `set -euo pipefail` a non-zero ldd exit
|
|
277
|
+
# would otherwise dominate the `ldd | grep` pipeline and make the missing-libs
|
|
278
|
+
# check a silent no-op even when 'not found' lines are present.
|
|
279
|
+
LDD_OUT="$(ldd "$CHROME_BIN" 2>&1 || true)"
|
|
280
|
+
if printf '%s\n' "$LDD_OUT" | grep -q 'not found'; then
|
|
281
|
+
echo "provision.sh: Chromium has unresolved shared libs:" >&2
|
|
282
|
+
printf '%s\n' "$LDD_OUT" | grep 'not found' >&2
|
|
283
|
+
exit 71
|
|
284
|
+
fi
|
|
285
|
+
ln -sf "$CHROME_BIN" /usr/local/bin/chromium
|
|
286
|
+
done_ "playwright + Chromium download (as vscode)"
|
|
287
|
+
|
|
248
288
|
step "dnf cleanup"
|
|
249
289
|
dnf clean all 2>/dev/null || true
|
|
250
290
|
done_ "dnf cleanup"
|
|
@@ -164,14 +164,7 @@ services:
|
|
|
164
164
|
- A service with `restart: never` and an autostart dependency will block the dependent forever after one failed run — usually a mistake.
|
|
165
165
|
- `command:` is either a shell string (run via `bash -c`) or an argv array. Use the argv form if you need to avoid shell quoting.
|
|
166
166
|
|
|
167
|
-
## 8.
|
|
168
|
-
|
|
169
|
-
Checkpoint (snapshot) this box writable layer: once the box is warmed up (deps installed, services ready), checkpoint it with `agentbox-ctl checkpoint --name setup --replace --set-default` so future boxes start ready.
|
|
170
|
-
Run this command exactly once. The `--name setup --replace` makes it idempotent — if it ever needs to run again it overwrites the existing `setup` checkpoint instead of stacking duplicates.
|
|
171
|
-
This doesn't need to be confirmed by the user.
|
|
172
|
-
It will pause the container for several seconds so warn the user about it and write Done when it's done.
|
|
173
|
-
|
|
174
|
-
## 9. Hand-off
|
|
167
|
+
## 8. Hand-off
|
|
175
168
|
|
|
176
169
|
Tell the user (verbatim):
|
|
177
170
|
|
|
@@ -187,6 +180,14 @@ Tell the user (verbatim):
|
|
|
187
180
|
your box is ready, you can start more sessions with `agentbox claude`
|
|
188
181
|
you can access the web app at https://<boxname>.localhost
|
|
189
182
|
|
|
183
|
+
|
|
184
|
+
## 9. Checkpoint the warm state - DON't SKIP THIS STEP
|
|
185
|
+
|
|
186
|
+
Checkpoint (snapshot) this box writable layer: once the box is warmed up (deps installed, services ready), checkpoint it with `agentbox-ctl checkpoint --name setup --replace --set-default` so future boxes start ready.
|
|
187
|
+
Run this command exactly once. The `--name setup --replace` makes it idempotent — if it ever needs to run again it overwrites the existing `setup` checkpoint instead of stacking duplicates.
|
|
188
|
+
On all providers except Vercel, this doesn't need to be confirmed by the user. It will pause the container for several seconds so warn the user about it and write Done when it's done.
|
|
189
|
+
On Vercel: this actually STOPS the sandbox, so warn the user about it. Also the system will ask confirmation.
|
|
190
|
+
|
|
190
191
|
## 10. Known issues
|
|
191
192
|
|
|
192
193
|
- For Nextjs/Vite/Tasnstack projects, makes sure to forward also websocket for hot reload.
|