@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.
Files changed (40) hide show
  1. package/CHANGELOG.md +102 -0
  2. package/README.md +161 -0
  3. package/dist/{_cloud-attach-ZXBCNWJX.js → _cloud-attach-2DGI6FUA.js} +4 -4
  4. package/dist/{chunk-NCJP5MTN.js → chunk-CDKVD6UO.js} +239 -61
  5. package/dist/chunk-CDKVD6UO.js.map +1 -0
  6. package/dist/{chunk-GU5LW4B5.js → chunk-I7NOGCL4.js} +374 -62
  7. package/dist/chunk-I7NOGCL4.js.map +1 -0
  8. package/dist/{chunk-BXQMIEHC.js → chunk-M2UWJKFA.js} +255 -163
  9. package/dist/chunk-M2UWJKFA.js.map +1 -0
  10. package/dist/{chunk-KL36BRN4.js → chunk-PWUVHPN6.js} +66 -17
  11. package/dist/{chunk-KL36BRN4.js.map → chunk-PWUVHPN6.js.map} +1 -1
  12. package/dist/{dist-CX5CGVEB.js → dist-BD5QJRDC.js} +4 -4
  13. package/dist/{dist-GDHP34ZK.js → dist-BNI5PQYK.js} +16 -4
  14. package/dist/dist-BNI5PQYK.js.map +1 -0
  15. package/dist/{dist-32EZBYG4.js → dist-SBCQVFCE.js} +23 -3
  16. package/dist/{dist-XML54CNB.js → dist-SJHY3HYN.js} +31 -6
  17. package/dist/dist-SJHY3HYN.js.map +1 -0
  18. package/dist/index.js +1787 -528
  19. package/dist/index.js.map +1 -1
  20. package/dist/{prepared-state-CL4CWXQA-H5THETIM.js → prepared-state-MQHD3M5F-O5M4NIN4.js} +2 -2
  21. package/package.json +10 -8
  22. package/runtime/docker/apps/cli/share/agentbox-setup/SKILL.md +10 -9
  23. package/runtime/docker/packages/ctl/dist/bin.cjs +38 -3
  24. package/runtime/hetzner/agentbox-setup-skill.md +10 -9
  25. package/runtime/hetzner/ctl.cjs +38 -3
  26. package/runtime/relay/bin.cjs +41 -3
  27. package/runtime/vercel/agentbox-setup-skill.md +10 -9
  28. package/runtime/vercel/ctl.cjs +38 -3
  29. package/runtime/vercel/custom-system-CLAUDE.md +1 -4
  30. package/runtime/vercel/scripts/provision.sh +40 -0
  31. package/share/agentbox-setup/SKILL.md +10 -9
  32. package/dist/chunk-BXQMIEHC.js.map +0 -1
  33. package/dist/chunk-GU5LW4B5.js.map +0 -1
  34. package/dist/chunk-NCJP5MTN.js.map +0 -1
  35. package/dist/dist-GDHP34ZK.js.map +0 -1
  36. package/dist/dist-XML54CNB.js.map +0 -1
  37. /package/dist/{_cloud-attach-ZXBCNWJX.js.map → _cloud-attach-2DGI6FUA.js.map} +0 -0
  38. /package/dist/{dist-CX5CGVEB.js.map → dist-BD5QJRDC.js.map} +0 -0
  39. /package/dist/{dist-32EZBYG4.js.map → dist-SBCQVFCE.js.map} +0 -0
  40. /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-KL36BRN4.js";
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-CL4CWXQA-H5THETIM.js.map
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.9.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/sandbox-core": "0.0.0",
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/config": "0.0.0",
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-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
  }
@@ -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://agentbox.dev/schema/agentbox.schema.json
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. Checkpoint the warm state (do this at the very end)
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 = new 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 sup = new Supervisor({ workspace: opts.workspace, logDir: opts.logDir });
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://agentbox.dev/schema/agentbox.schema.json
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. Checkpoint the warm state (do this at the very end)
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 = new 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 sup = new Supervisor({ workspace: opts.workspace, logDir: opts.logDir });
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,
@@ -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://agentbox.dev/schema/agentbox.schema.json
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. Checkpoint the warm state (do this at the very end)
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 = new 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 sup = new Supervisor({ workspace: opts.workspace, logDir: opts.logDir });
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 — otherwise rely on
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://agentbox.dev/schema/agentbox.schema.json
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. Checkpoint the warm state (do this at the very end)
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.