@madarco/agentbox 0.9.0 → 0.10.1
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 +102 -0
- package/README.md +161 -0
- package/dist/{_cloud-attach-ZXBCNWJX.js → _cloud-attach-2DGI6FUA.js} +4 -4
- package/dist/{chunk-NCJP5MTN.js → chunk-CDKVD6UO.js} +239 -61
- package/dist/chunk-CDKVD6UO.js.map +1 -0
- package/dist/{chunk-GU5LW4B5.js → chunk-I7NOGCL4.js} +374 -62
- package/dist/chunk-I7NOGCL4.js.map +1 -0
- package/dist/{chunk-BXQMIEHC.js → chunk-M2UWJKFA.js} +255 -163
- package/dist/chunk-M2UWJKFA.js.map +1 -0
- package/dist/{chunk-KL36BRN4.js → chunk-PWUVHPN6.js} +66 -17
- package/dist/{chunk-KL36BRN4.js.map → chunk-PWUVHPN6.js.map} +1 -1
- package/dist/{dist-CX5CGVEB.js → dist-BD5QJRDC.js} +4 -4
- package/dist/{dist-GDHP34ZK.js → dist-BNI5PQYK.js} +16 -4
- package/dist/dist-BNI5PQYK.js.map +1 -0
- package/dist/{dist-32EZBYG4.js → dist-SBCQVFCE.js} +23 -3
- package/dist/{dist-XML54CNB.js → dist-SJHY3HYN.js} +31 -6
- package/dist/dist-SJHY3HYN.js.map +1 -0
- package/dist/index.js +1787 -528
- package/dist/index.js.map +1 -1
- package/dist/{prepared-state-CL4CWXQA-H5THETIM.js → prepared-state-MQHD3M5F-O5M4NIN4.js} +2 -2
- package/package.json +10 -8
- package/runtime/docker/apps/cli/share/agentbox-setup/SKILL.md +10 -9
- package/runtime/docker/packages/ctl/dist/bin.cjs +38 -3
- package/runtime/hetzner/agentbox-setup-skill.md +10 -9
- package/runtime/hetzner/ctl.cjs +38 -3
- package/runtime/relay/bin.cjs +41 -3
- package/runtime/vercel/agentbox-setup-skill.md +10 -9
- package/runtime/vercel/ctl.cjs +38 -3
- package/runtime/vercel/custom-system-CLAUDE.md +1 -4
- package/runtime/vercel/scripts/provision.sh +40 -0
- package/share/agentbox-setup/SKILL.md +10 -9
- 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-2DGI6FUA.js.map} +0 -0
- /package/dist/{dist-CX5CGVEB.js.map → dist-BD5QJRDC.js.map} +0 -0
- /package/dist/{dist-32EZBYG4.js.map → dist-SBCQVFCE.js.map} +0 -0
- /package/dist/{prepared-state-CL4CWXQA-H5THETIM.js.map → prepared-state-MQHD3M5F-O5M4NIN4.js.map} +0 -0
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
readPreparedDockerState,
|
|
7
7
|
resolveContextFiles,
|
|
8
8
|
writePreparedDockerState
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-PWUVHPN6.js";
|
|
10
10
|
export {
|
|
11
11
|
DOCKERFILE_PATH,
|
|
12
12
|
computeDockerContextFingerprint,
|
|
@@ -15,4 +15,4 @@ export {
|
|
|
15
15
|
resolveContextFiles,
|
|
16
16
|
writePreparedDockerState
|
|
17
17
|
};
|
|
18
|
-
//# sourceMappingURL=prepared-state-
|
|
18
|
+
//# sourceMappingURL=prepared-state-MQHD3M5F-O5M4NIN4.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@madarco/agentbox",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.1",
|
|
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",
|
|
60
|
-
"@agentbox/
|
|
61
|
+
"@agentbox/config": "0.0.0",
|
|
61
62
|
"@agentbox/core": "0.0.0",
|
|
62
|
-
"@agentbox/relay": "0.0.0",
|
|
63
63
|
"@agentbox/ctl": "0.0.0",
|
|
64
|
-
"@agentbox/
|
|
65
|
-
"@agentbox/sandbox-daytona": "0.0.0",
|
|
66
|
-
"@agentbox/sandbox-vercel": "0.0.0",
|
|
64
|
+
"@agentbox/relay": "0.0.0",
|
|
67
65
|
"@agentbox/sandbox-cloud": "0.0.0",
|
|
66
|
+
"@agentbox/sandbox-core": "0.0.0",
|
|
67
|
+
"@agentbox/sandbox-hetzner": "0.0.0",
|
|
68
|
+
"@agentbox/sandbox-daytona": "0.0.0",
|
|
68
69
|
"@agentbox/sandbox-docker": "0.0.0",
|
|
69
|
-
"@agentbox/sandbox-
|
|
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
|
}
|
|
@@ -97,7 +97,7 @@ Full key list (run on the host): `agentbox config list --keys`.
|
|
|
97
97
|
## 6. Worked example
|
|
98
98
|
|
|
99
99
|
```yaml
|
|
100
|
-
# yaml-language-server: $schema=https://
|
|
100
|
+
# yaml-language-server: $schema=https://agent-box.sh/schema/agentbox.schema.json
|
|
101
101
|
# This agentbox.yaml setup this Next.js project, and includes:
|
|
102
102
|
# - a postgres database because it's used in the project
|
|
103
103
|
# - an inngest server for queues
|
|
@@ -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.
|
|
@@ -18548,6 +18548,12 @@ var KEY_REGISTRY = [
|
|
|
18548
18548
|
description: "Box image ref (advanced).",
|
|
18549
18549
|
advanced: true
|
|
18550
18550
|
},
|
|
18551
|
+
{
|
|
18552
|
+
key: "box.imageRegistry",
|
|
18553
|
+
type: "string",
|
|
18554
|
+
description: "Registry repo to pull the prebuilt docker base image from before building locally. Empty = always build. Docker only (advanced).",
|
|
18555
|
+
advanced: true
|
|
18556
|
+
},
|
|
18551
18557
|
{
|
|
18552
18558
|
key: "box.dockerCacheShared",
|
|
18553
18559
|
type: "bool",
|
|
@@ -18599,11 +18605,21 @@ var KEY_REGISTRY = [
|
|
|
18599
18605
|
type: "string",
|
|
18600
18606
|
description: "tmux session name for `agentbox claude`."
|
|
18601
18607
|
},
|
|
18608
|
+
{
|
|
18609
|
+
key: "claude.dangerouslySkipPermissions",
|
|
18610
|
+
type: "bool",
|
|
18611
|
+
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."
|
|
18612
|
+
},
|
|
18602
18613
|
{
|
|
18603
18614
|
key: "codex.sessionName",
|
|
18604
18615
|
type: "string",
|
|
18605
18616
|
description: "tmux session name for `agentbox codex`."
|
|
18606
18617
|
},
|
|
18618
|
+
{
|
|
18619
|
+
key: "codex.dangerouslySkipPermissions",
|
|
18620
|
+
type: "bool",
|
|
18621
|
+
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."
|
|
18622
|
+
},
|
|
18607
18623
|
{
|
|
18608
18624
|
key: "opencode.sessionName",
|
|
18609
18625
|
type: "string",
|
|
@@ -19657,6 +19673,18 @@ async function runCheckpointRpc(action, deps) {
|
|
|
19657
19673
|
stderr: "relay: AGENTBOX_CLI_ENTRY not set; cannot run checkpoint host-side\n"
|
|
19658
19674
|
};
|
|
19659
19675
|
}
|
|
19676
|
+
if (deps.backendName === "vercel" && deps.prompts && deps.subscribers && deps.subscribers.forBox(deps.boxId).length > 0) {
|
|
19677
|
+
const verdict = await askPrompt(deps.prompts, deps.subscribers, deps.boxId, {
|
|
19678
|
+
kind: "confirm",
|
|
19679
|
+
message: `Create checkpoint on ${deps.boxName ?? deps.boxId}? The vercel box will stop and reboot.`,
|
|
19680
|
+
detail: params.name ? `checkpoint: ${params.name}` : "(auto-named)",
|
|
19681
|
+
defaultAnswer: "n",
|
|
19682
|
+
context: { command: "checkpoint create", argv: params.name ? [params.name] : [] }
|
|
19683
|
+
});
|
|
19684
|
+
if (verdict.answer !== "y") {
|
|
19685
|
+
return { exitCode: 10, stdout: "", stderr: "checkpoint denied by user\n" };
|
|
19686
|
+
}
|
|
19687
|
+
}
|
|
19660
19688
|
const argv = [process.execPath, entry, "checkpoint", "create", deps.boxId];
|
|
19661
19689
|
if (params.name) argv.push("--name", params.name);
|
|
19662
19690
|
if (params.merged === true) argv.push("--merged");
|
|
@@ -20013,7 +20041,12 @@ function createRelayServer(opts) {
|
|
|
20013
20041
|
boxes: registry.size(),
|
|
20014
20042
|
events: events.size(),
|
|
20015
20043
|
pid: process.pid,
|
|
20016
|
-
cliEntry: Boolean(process.env.AGENTBOX_CLI_ENTRY)
|
|
20044
|
+
cliEntry: Boolean(process.env.AGENTBOX_CLI_ENTRY),
|
|
20045
|
+
// The spawning CLI's version/commit (inherited via env at spawn time).
|
|
20046
|
+
// `version` lets host-side ensureRelay reclaim a relay left over from a
|
|
20047
|
+
// different agentbox version; `commit` is observability-only.
|
|
20048
|
+
version: process.env.AGENTBOX_CLI_VERSION || void 0,
|
|
20049
|
+
commit: process.env.AGENTBOX_CLI_COMMIT || void 0
|
|
20017
20050
|
});
|
|
20018
20051
|
return;
|
|
20019
20052
|
}
|
|
@@ -21957,6 +21990,7 @@ var Supervisor = class extends import_node_events15.EventEmitter {
|
|
|
21957
21990
|
super();
|
|
21958
21991
|
this.opts = opts;
|
|
21959
21992
|
this.relay = new RelayClient();
|
|
21993
|
+
this.webProxy = new WebProxy(opts.webProxyPort);
|
|
21960
21994
|
}
|
|
21961
21995
|
opts;
|
|
21962
21996
|
units = /* @__PURE__ */ new Map();
|
|
@@ -21966,7 +22000,7 @@ var Supervisor = class extends import_node_events15.EventEmitter {
|
|
|
21966
22000
|
scheduling = false;
|
|
21967
22001
|
rescheduleDirty = false;
|
|
21968
22002
|
relay;
|
|
21969
|
-
webProxy
|
|
22003
|
+
webProxy;
|
|
21970
22004
|
/** The relay client the supervisor pushes state events on. Shared with the
|
|
21971
22005
|
* status reporter so both use the same fire-and-forget channel. */
|
|
21972
22006
|
get relayClient() {
|
|
@@ -22893,7 +22927,8 @@ function resolveBoxRelayPort() {
|
|
|
22893
22927
|
}
|
|
22894
22928
|
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
22929
|
const cfg = await loadConfig(opts.config);
|
|
22896
|
-
const
|
|
22930
|
+
const webProxyPort = Number(process.env.AGENTBOX_WEB_PROXY_PORT) || void 0;
|
|
22931
|
+
const sup = new Supervisor({ workspace: opts.workspace, logDir: opts.logDir, webProxyPort });
|
|
22897
22932
|
await sup.init(cfg);
|
|
22898
22933
|
const reporter = new StatusReporter({
|
|
22899
22934
|
supervisor: sup,
|
|
@@ -97,7 +97,7 @@ Full key list (run on the host): `agentbox config list --keys`.
|
|
|
97
97
|
## 6. Worked example
|
|
98
98
|
|
|
99
99
|
```yaml
|
|
100
|
-
# yaml-language-server: $schema=https://
|
|
100
|
+
# yaml-language-server: $schema=https://agent-box.sh/schema/agentbox.schema.json
|
|
101
101
|
# This agentbox.yaml setup this Next.js project, and includes:
|
|
102
102
|
# - a postgres database because it's used in the project
|
|
103
103
|
# - an inngest server for queues
|
|
@@ -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
|
@@ -18548,6 +18548,12 @@ var KEY_REGISTRY = [
|
|
|
18548
18548
|
description: "Box image ref (advanced).",
|
|
18549
18549
|
advanced: true
|
|
18550
18550
|
},
|
|
18551
|
+
{
|
|
18552
|
+
key: "box.imageRegistry",
|
|
18553
|
+
type: "string",
|
|
18554
|
+
description: "Registry repo to pull the prebuilt docker base image from before building locally. Empty = always build. Docker only (advanced).",
|
|
18555
|
+
advanced: true
|
|
18556
|
+
},
|
|
18551
18557
|
{
|
|
18552
18558
|
key: "box.dockerCacheShared",
|
|
18553
18559
|
type: "bool",
|
|
@@ -18599,11 +18605,21 @@ var KEY_REGISTRY = [
|
|
|
18599
18605
|
type: "string",
|
|
18600
18606
|
description: "tmux session name for `agentbox claude`."
|
|
18601
18607
|
},
|
|
18608
|
+
{
|
|
18609
|
+
key: "claude.dangerouslySkipPermissions",
|
|
18610
|
+
type: "bool",
|
|
18611
|
+
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."
|
|
18612
|
+
},
|
|
18602
18613
|
{
|
|
18603
18614
|
key: "codex.sessionName",
|
|
18604
18615
|
type: "string",
|
|
18605
18616
|
description: "tmux session name for `agentbox codex`."
|
|
18606
18617
|
},
|
|
18618
|
+
{
|
|
18619
|
+
key: "codex.dangerouslySkipPermissions",
|
|
18620
|
+
type: "bool",
|
|
18621
|
+
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."
|
|
18622
|
+
},
|
|
18607
18623
|
{
|
|
18608
18624
|
key: "opencode.sessionName",
|
|
18609
18625
|
type: "string",
|
|
@@ -19657,6 +19673,18 @@ async function runCheckpointRpc(action, deps) {
|
|
|
19657
19673
|
stderr: "relay: AGENTBOX_CLI_ENTRY not set; cannot run checkpoint host-side\n"
|
|
19658
19674
|
};
|
|
19659
19675
|
}
|
|
19676
|
+
if (deps.backendName === "vercel" && deps.prompts && deps.subscribers && deps.subscribers.forBox(deps.boxId).length > 0) {
|
|
19677
|
+
const verdict = await askPrompt(deps.prompts, deps.subscribers, deps.boxId, {
|
|
19678
|
+
kind: "confirm",
|
|
19679
|
+
message: `Create checkpoint on ${deps.boxName ?? deps.boxId}? The vercel box will stop and reboot.`,
|
|
19680
|
+
detail: params.name ? `checkpoint: ${params.name}` : "(auto-named)",
|
|
19681
|
+
defaultAnswer: "n",
|
|
19682
|
+
context: { command: "checkpoint create", argv: params.name ? [params.name] : [] }
|
|
19683
|
+
});
|
|
19684
|
+
if (verdict.answer !== "y") {
|
|
19685
|
+
return { exitCode: 10, stdout: "", stderr: "checkpoint denied by user\n" };
|
|
19686
|
+
}
|
|
19687
|
+
}
|
|
19660
19688
|
const argv = [process.execPath, entry, "checkpoint", "create", deps.boxId];
|
|
19661
19689
|
if (params.name) argv.push("--name", params.name);
|
|
19662
19690
|
if (params.merged === true) argv.push("--merged");
|
|
@@ -20013,7 +20041,12 @@ function createRelayServer(opts) {
|
|
|
20013
20041
|
boxes: registry.size(),
|
|
20014
20042
|
events: events.size(),
|
|
20015
20043
|
pid: process.pid,
|
|
20016
|
-
cliEntry: Boolean(process.env.AGENTBOX_CLI_ENTRY)
|
|
20044
|
+
cliEntry: Boolean(process.env.AGENTBOX_CLI_ENTRY),
|
|
20045
|
+
// The spawning CLI's version/commit (inherited via env at spawn time).
|
|
20046
|
+
// `version` lets host-side ensureRelay reclaim a relay left over from a
|
|
20047
|
+
// different agentbox version; `commit` is observability-only.
|
|
20048
|
+
version: process.env.AGENTBOX_CLI_VERSION || void 0,
|
|
20049
|
+
commit: process.env.AGENTBOX_CLI_COMMIT || void 0
|
|
20017
20050
|
});
|
|
20018
20051
|
return;
|
|
20019
20052
|
}
|
|
@@ -21957,6 +21990,7 @@ var Supervisor = class extends import_node_events15.EventEmitter {
|
|
|
21957
21990
|
super();
|
|
21958
21991
|
this.opts = opts;
|
|
21959
21992
|
this.relay = new RelayClient();
|
|
21993
|
+
this.webProxy = new WebProxy(opts.webProxyPort);
|
|
21960
21994
|
}
|
|
21961
21995
|
opts;
|
|
21962
21996
|
units = /* @__PURE__ */ new Map();
|
|
@@ -21966,7 +22000,7 @@ var Supervisor = class extends import_node_events15.EventEmitter {
|
|
|
21966
22000
|
scheduling = false;
|
|
21967
22001
|
rescheduleDirty = false;
|
|
21968
22002
|
relay;
|
|
21969
|
-
webProxy
|
|
22003
|
+
webProxy;
|
|
21970
22004
|
/** The relay client the supervisor pushes state events on. Shared with the
|
|
21971
22005
|
* status reporter so both use the same fire-and-forget channel. */
|
|
21972
22006
|
get relayClient() {
|
|
@@ -22893,7 +22927,8 @@ function resolveBoxRelayPort() {
|
|
|
22893
22927
|
}
|
|
22894
22928
|
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
22929
|
const cfg = await loadConfig(opts.config);
|
|
22896
|
-
const
|
|
22930
|
+
const webProxyPort = Number(process.env.AGENTBOX_WEB_PROXY_PORT) || void 0;
|
|
22931
|
+
const sup = new Supervisor({ workspace: opts.workspace, logDir: opts.logDir, webProxyPort });
|
|
22897
22932
|
await sup.init(cfg);
|
|
22898
22933
|
const reporter = new StatusReporter({
|
|
22899
22934
|
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
|
}
|
|
@@ -20097,6 +20114,9 @@ var BUILT_IN_DEFAULTS = {
|
|
|
20097
20114
|
isolateCodexConfig: false,
|
|
20098
20115
|
isolateOpencodeConfig: false,
|
|
20099
20116
|
image: "agentbox/box:dev",
|
|
20117
|
+
// Mirrors BOX_IMAGE_REGISTRY in @agentbox/sandbox-docker. Empty disables the
|
|
20118
|
+
// registry pull (always build the docker base image locally).
|
|
20119
|
+
imageRegistry: "ghcr.io/madarco/agentbox/box",
|
|
20100
20120
|
dockerCacheShared: false,
|
|
20101
20121
|
memory: 0,
|
|
20102
20122
|
cpus: 0,
|
|
@@ -20111,10 +20131,12 @@ var BUILT_IN_DEFAULTS = {
|
|
|
20111
20131
|
maxLayers: 3
|
|
20112
20132
|
},
|
|
20113
20133
|
claude: {
|
|
20114
|
-
sessionName: "claude"
|
|
20134
|
+
sessionName: "claude",
|
|
20135
|
+
dangerouslySkipPermissions: true
|
|
20115
20136
|
},
|
|
20116
20137
|
codex: {
|
|
20117
|
-
sessionName: "codex"
|
|
20138
|
+
sessionName: "codex",
|
|
20139
|
+
dangerouslySkipPermissions: true
|
|
20118
20140
|
},
|
|
20119
20141
|
opencode: {
|
|
20120
20142
|
sessionName: "opencode"
|
|
@@ -20251,6 +20273,12 @@ var KEY_REGISTRY = [
|
|
|
20251
20273
|
description: "Box image ref (advanced).",
|
|
20252
20274
|
advanced: true
|
|
20253
20275
|
},
|
|
20276
|
+
{
|
|
20277
|
+
key: "box.imageRegistry",
|
|
20278
|
+
type: "string",
|
|
20279
|
+
description: "Registry repo to pull the prebuilt docker base image from before building locally. Empty = always build. Docker only (advanced).",
|
|
20280
|
+
advanced: true
|
|
20281
|
+
},
|
|
20254
20282
|
{
|
|
20255
20283
|
key: "box.dockerCacheShared",
|
|
20256
20284
|
type: "bool",
|
|
@@ -20302,11 +20330,21 @@ var KEY_REGISTRY = [
|
|
|
20302
20330
|
type: "string",
|
|
20303
20331
|
description: "tmux session name for `agentbox claude`."
|
|
20304
20332
|
},
|
|
20333
|
+
{
|
|
20334
|
+
key: "claude.dangerouslySkipPermissions",
|
|
20335
|
+
type: "bool",
|
|
20336
|
+
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."
|
|
20337
|
+
},
|
|
20305
20338
|
{
|
|
20306
20339
|
key: "codex.sessionName",
|
|
20307
20340
|
type: "string",
|
|
20308
20341
|
description: "tmux session name for `agentbox codex`."
|
|
20309
20342
|
},
|
|
20343
|
+
{
|
|
20344
|
+
key: "codex.dangerouslySkipPermissions",
|
|
20345
|
+
type: "bool",
|
|
20346
|
+
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."
|
|
20347
|
+
},
|
|
20310
20348
|
{
|
|
20311
20349
|
key: "opencode.sessionName",
|
|
20312
20350
|
type: "string",
|
|
@@ -97,7 +97,7 @@ Full key list (run on the host): `agentbox config list --keys`.
|
|
|
97
97
|
## 6. Worked example
|
|
98
98
|
|
|
99
99
|
```yaml
|
|
100
|
-
# yaml-language-server: $schema=https://
|
|
100
|
+
# yaml-language-server: $schema=https://agent-box.sh/schema/agentbox.schema.json
|
|
101
101
|
# This agentbox.yaml setup this Next.js project, and includes:
|
|
102
102
|
# - a postgres database because it's used in the project
|
|
103
103
|
# - an inngest server for queues
|
|
@@ -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
|
@@ -18548,6 +18548,12 @@ var KEY_REGISTRY = [
|
|
|
18548
18548
|
description: "Box image ref (advanced).",
|
|
18549
18549
|
advanced: true
|
|
18550
18550
|
},
|
|
18551
|
+
{
|
|
18552
|
+
key: "box.imageRegistry",
|
|
18553
|
+
type: "string",
|
|
18554
|
+
description: "Registry repo to pull the prebuilt docker base image from before building locally. Empty = always build. Docker only (advanced).",
|
|
18555
|
+
advanced: true
|
|
18556
|
+
},
|
|
18551
18557
|
{
|
|
18552
18558
|
key: "box.dockerCacheShared",
|
|
18553
18559
|
type: "bool",
|
|
@@ -18599,11 +18605,21 @@ var KEY_REGISTRY = [
|
|
|
18599
18605
|
type: "string",
|
|
18600
18606
|
description: "tmux session name for `agentbox claude`."
|
|
18601
18607
|
},
|
|
18608
|
+
{
|
|
18609
|
+
key: "claude.dangerouslySkipPermissions",
|
|
18610
|
+
type: "bool",
|
|
18611
|
+
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."
|
|
18612
|
+
},
|
|
18602
18613
|
{
|
|
18603
18614
|
key: "codex.sessionName",
|
|
18604
18615
|
type: "string",
|
|
18605
18616
|
description: "tmux session name for `agentbox codex`."
|
|
18606
18617
|
},
|
|
18618
|
+
{
|
|
18619
|
+
key: "codex.dangerouslySkipPermissions",
|
|
18620
|
+
type: "bool",
|
|
18621
|
+
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."
|
|
18622
|
+
},
|
|
18607
18623
|
{
|
|
18608
18624
|
key: "opencode.sessionName",
|
|
18609
18625
|
type: "string",
|
|
@@ -19657,6 +19673,18 @@ async function runCheckpointRpc(action, deps) {
|
|
|
19657
19673
|
stderr: "relay: AGENTBOX_CLI_ENTRY not set; cannot run checkpoint host-side\n"
|
|
19658
19674
|
};
|
|
19659
19675
|
}
|
|
19676
|
+
if (deps.backendName === "vercel" && deps.prompts && deps.subscribers && deps.subscribers.forBox(deps.boxId).length > 0) {
|
|
19677
|
+
const verdict = await askPrompt(deps.prompts, deps.subscribers, deps.boxId, {
|
|
19678
|
+
kind: "confirm",
|
|
19679
|
+
message: `Create checkpoint on ${deps.boxName ?? deps.boxId}? The vercel box will stop and reboot.`,
|
|
19680
|
+
detail: params.name ? `checkpoint: ${params.name}` : "(auto-named)",
|
|
19681
|
+
defaultAnswer: "n",
|
|
19682
|
+
context: { command: "checkpoint create", argv: params.name ? [params.name] : [] }
|
|
19683
|
+
});
|
|
19684
|
+
if (verdict.answer !== "y") {
|
|
19685
|
+
return { exitCode: 10, stdout: "", stderr: "checkpoint denied by user\n" };
|
|
19686
|
+
}
|
|
19687
|
+
}
|
|
19660
19688
|
const argv = [process.execPath, entry, "checkpoint", "create", deps.boxId];
|
|
19661
19689
|
if (params.name) argv.push("--name", params.name);
|
|
19662
19690
|
if (params.merged === true) argv.push("--merged");
|
|
@@ -20013,7 +20041,12 @@ function createRelayServer(opts) {
|
|
|
20013
20041
|
boxes: registry.size(),
|
|
20014
20042
|
events: events.size(),
|
|
20015
20043
|
pid: process.pid,
|
|
20016
|
-
cliEntry: Boolean(process.env.AGENTBOX_CLI_ENTRY)
|
|
20044
|
+
cliEntry: Boolean(process.env.AGENTBOX_CLI_ENTRY),
|
|
20045
|
+
// The spawning CLI's version/commit (inherited via env at spawn time).
|
|
20046
|
+
// `version` lets host-side ensureRelay reclaim a relay left over from a
|
|
20047
|
+
// different agentbox version; `commit` is observability-only.
|
|
20048
|
+
version: process.env.AGENTBOX_CLI_VERSION || void 0,
|
|
20049
|
+
commit: process.env.AGENTBOX_CLI_COMMIT || void 0
|
|
20017
20050
|
});
|
|
20018
20051
|
return;
|
|
20019
20052
|
}
|
|
@@ -21957,6 +21990,7 @@ var Supervisor = class extends import_node_events15.EventEmitter {
|
|
|
21957
21990
|
super();
|
|
21958
21991
|
this.opts = opts;
|
|
21959
21992
|
this.relay = new RelayClient();
|
|
21993
|
+
this.webProxy = new WebProxy(opts.webProxyPort);
|
|
21960
21994
|
}
|
|
21961
21995
|
opts;
|
|
21962
21996
|
units = /* @__PURE__ */ new Map();
|
|
@@ -21966,7 +22000,7 @@ var Supervisor = class extends import_node_events15.EventEmitter {
|
|
|
21966
22000
|
scheduling = false;
|
|
21967
22001
|
rescheduleDirty = false;
|
|
21968
22002
|
relay;
|
|
21969
|
-
webProxy
|
|
22003
|
+
webProxy;
|
|
21970
22004
|
/** The relay client the supervisor pushes state events on. Shared with the
|
|
21971
22005
|
* status reporter so both use the same fire-and-forget channel. */
|
|
21972
22006
|
get relayClient() {
|
|
@@ -22893,7 +22927,8 @@ function resolveBoxRelayPort() {
|
|
|
22893
22927
|
}
|
|
22894
22928
|
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
22929
|
const cfg = await loadConfig(opts.config);
|
|
22896
|
-
const
|
|
22930
|
+
const webProxyPort = Number(process.env.AGENTBOX_WEB_PROXY_PORT) || void 0;
|
|
22931
|
+
const sup = new Supervisor({ workspace: opts.workspace, logDir: opts.logDir, webProxyPort });
|
|
22897
22932
|
await sup.init(cfg);
|
|
22898
22933
|
const reporter = new StatusReporter({
|
|
22899
22934
|
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"
|
|
@@ -97,7 +97,7 @@ Full key list (run on the host): `agentbox config list --keys`.
|
|
|
97
97
|
## 6. Worked example
|
|
98
98
|
|
|
99
99
|
```yaml
|
|
100
|
-
# yaml-language-server: $schema=https://
|
|
100
|
+
# yaml-language-server: $schema=https://agent-box.sh/schema/agentbox.schema.json
|
|
101
101
|
# This agentbox.yaml setup this Next.js project, and includes:
|
|
102
102
|
# - a postgres database because it's used in the project
|
|
103
103
|
# - an inngest server for queues
|
|
@@ -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.
|