@madarco/agentbox 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{_cloud-attach-T727ZPRV.js → _cloud-attach-ZXBCNWJX.js} +4 -4
- package/dist/{chunk-67N47KUS.js → chunk-BXQMIEHC.js} +106 -31
- package/dist/chunk-BXQMIEHC.js.map +1 -0
- package/dist/{chunk-FODMEHD3.js → chunk-GU5LW4B5.js} +341 -25
- package/dist/chunk-GU5LW4B5.js.map +1 -0
- package/dist/{chunk-BGK32PZE.js → chunk-KL36BRN4.js} +2 -2
- package/dist/chunk-KL36BRN4.js.map +1 -0
- package/dist/chunk-MTVI44DW.js +662 -0
- package/dist/chunk-MTVI44DW.js.map +1 -0
- package/dist/{chunk-6OZDFNBF.js → chunk-NCJP5MTN.js} +201 -44
- package/dist/chunk-NCJP5MTN.js.map +1 -0
- package/dist/{dist-LOZBWMBF.js → dist-32EZBYG4.js} +9 -3
- package/dist/{dist-L4LCG5SJ.js → dist-CX5CGVEB.js} +4 -4
- package/dist/{dist-ZODPD2I6.js → dist-GDHP34ZK.js} +8 -10
- package/dist/dist-GDHP34ZK.js.map +1 -0
- package/dist/dist-XML54CNB.js +849 -0
- package/dist/dist-XML54CNB.js.map +1 -0
- package/dist/index.js +636 -340
- package/dist/index.js.map +1 -1
- package/dist/{prepared-state-CL4CWXQA-ME4HSKDE.js → prepared-state-CL4CWXQA-H5THETIM.js} +2 -2
- package/package.json +7 -5
- package/runtime/docker/packages/ctl/dist/bin.cjs +98 -29
- package/runtime/docker/packages/sandbox-docker/scripts/agentbox-vnc-start +15 -1
- package/runtime/hetzner/agentbox-vnc-start +15 -1
- package/runtime/hetzner/ctl.cjs +98 -29
- package/runtime/relay/bin.cjs +229 -37
- package/runtime/vercel/agentbox-checkpoint-cleanup +52 -0
- package/runtime/vercel/agentbox-codex-hooks.json +68 -0
- package/runtime/vercel/agentbox-open +28 -0
- package/runtime/vercel/agentbox-setup-skill.md +196 -0
- package/runtime/vercel/agentbox-vnc-start +91 -0
- package/runtime/vercel/claude-managed-settings.json +115 -0
- package/runtime/vercel/ctl.cjs +23466 -0
- package/runtime/vercel/custom-system-CLAUDE.md +50 -0
- package/runtime/vercel/gh-shim +263 -0
- package/runtime/vercel/git-shim +131 -0
- package/runtime/vercel/scripts/provision.sh +274 -0
- package/dist/chunk-67N47KUS.js.map +0 -1
- package/dist/chunk-6OZDFNBF.js.map +0 -1
- package/dist/chunk-BGK32PZE.js.map +0 -1
- package/dist/chunk-FODMEHD3.js.map +0 -1
- package/dist/dist-ZODPD2I6.js.map +0 -1
- /package/dist/{_cloud-attach-T727ZPRV.js.map → _cloud-attach-ZXBCNWJX.js.map} +0 -0
- /package/dist/{dist-LOZBWMBF.js.map → dist-32EZBYG4.js.map} +0 -0
- /package/dist/{dist-L4LCG5SJ.js.map → dist-CX5CGVEB.js.map} +0 -0
- /package/dist/{prepared-state-CL4CWXQA-ME4HSKDE.js.map → prepared-state-CL4CWXQA-H5THETIM.js.map} +0 -0
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
readPreparedDockerState,
|
|
7
7
|
resolveContextFiles,
|
|
8
8
|
writePreparedDockerState
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-KL36BRN4.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-
|
|
18
|
+
//# sourceMappingURL=prepared-state-CL4CWXQA-H5THETIM.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@madarco/agentbox",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.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",
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"@clack/prompts": "^0.9.0",
|
|
44
44
|
"@daytonaio/sdk": "^0.179.0",
|
|
45
|
+
"@vercel/sandbox": "^2.0.1",
|
|
45
46
|
"@xterm/headless": "^5.5.0",
|
|
46
47
|
"commander": "^12.1.0",
|
|
47
48
|
"execa": "^9.5.2",
|
|
@@ -56,14 +57,15 @@
|
|
|
56
57
|
"tsup": "^8.3.5",
|
|
57
58
|
"typescript": "^5.7.2",
|
|
58
59
|
"vitest": "^2.1.8",
|
|
59
|
-
"@agentbox/
|
|
60
|
+
"@agentbox/sandbox-core": "0.0.0",
|
|
61
|
+
"@agentbox/core": "0.0.0",
|
|
60
62
|
"@agentbox/relay": "0.0.0",
|
|
61
63
|
"@agentbox/ctl": "0.0.0",
|
|
62
|
-
"@agentbox/
|
|
64
|
+
"@agentbox/config": "0.0.0",
|
|
65
|
+
"@agentbox/sandbox-daytona": "0.0.0",
|
|
66
|
+
"@agentbox/sandbox-vercel": "0.0.0",
|
|
63
67
|
"@agentbox/sandbox-cloud": "0.0.0",
|
|
64
|
-
"@agentbox/sandbox-core": "0.0.0",
|
|
65
68
|
"@agentbox/sandbox-docker": "0.0.0",
|
|
66
|
-
"@agentbox/sandbox-daytona": "0.0.0",
|
|
67
69
|
"@agentbox/sandbox-hetzner": "0.0.0"
|
|
68
70
|
},
|
|
69
71
|
"scripts": {
|
|
@@ -18469,8 +18469,8 @@ var KEY_REGISTRY = [
|
|
|
18469
18469
|
{
|
|
18470
18470
|
key: "box.provider",
|
|
18471
18471
|
type: "enum",
|
|
18472
|
-
enumValues: ["docker", "daytona", "hetzner"],
|
|
18473
|
-
description: "Sandbox backend new boxes are created on: local Docker containers, Daytona Cloud sandboxes,
|
|
18472
|
+
enumValues: ["docker", "daytona", "hetzner", "vercel"],
|
|
18473
|
+
description: "Sandbox backend new boxes are created on: local Docker containers, Daytona Cloud sandboxes, Hetzner Cloud VPSes, or Vercel Sandboxes."
|
|
18474
18474
|
},
|
|
18475
18475
|
{
|
|
18476
18476
|
key: "box.hostSnapshot",
|
|
@@ -18500,6 +18500,12 @@ var KEY_REGISTRY = [
|
|
|
18500
18500
|
description: "Per-provider override of `box.defaultCheckpoint` for hetzner. Wins over the global when set; set via `agentbox checkpoint set-default --provider hetzner`.",
|
|
18501
18501
|
advanced: true
|
|
18502
18502
|
},
|
|
18503
|
+
{
|
|
18504
|
+
key: "box.defaultCheckpointVercel",
|
|
18505
|
+
type: "string",
|
|
18506
|
+
description: "Per-provider override of `box.defaultCheckpoint` for vercel. Wins over the global when set; set via `agentbox checkpoint set-default --provider vercel`.",
|
|
18507
|
+
advanced: true
|
|
18508
|
+
},
|
|
18503
18509
|
{
|
|
18504
18510
|
key: "checkpoint.maxLayers",
|
|
18505
18511
|
type: "int",
|
|
@@ -18573,6 +18579,21 @@ var KEY_REGISTRY = [
|
|
|
18573
18579
|
type: "int",
|
|
18574
18580
|
description: "Cap git bundle history shipped to cloud sandboxes (daytona, hetzner). 0 = full history. Unset = adaptive default (last 200 commits; re-bundle at 100 if the bundle exceeds 20 MB). Ignored for docker (which bind-mounts .git/)."
|
|
18575
18581
|
},
|
|
18582
|
+
{
|
|
18583
|
+
key: "box.vercelVcpus",
|
|
18584
|
+
type: "int",
|
|
18585
|
+
description: "vCPUs for new --provider vercel boxes (Vercel couples RAM at 2048 MB/vCPU). Default 2. Vercel only accepts specific counts (e.g. 1, 2, 4, 8) \u2014 an unsupported value fails create with a 400. Vercel-only; ignored by other providers."
|
|
18586
|
+
},
|
|
18587
|
+
{
|
|
18588
|
+
key: "box.vercelTimeoutMs",
|
|
18589
|
+
type: "int",
|
|
18590
|
+
description: "Max session length (ms) for new --provider vercel boxes before the VM auto-snapshots; persistent mode auto-resumes on the next call. Default 2700000 (45 min, the Hobby ceiling). Vercel-only."
|
|
18591
|
+
},
|
|
18592
|
+
{
|
|
18593
|
+
key: "box.vercelNetworkPolicy",
|
|
18594
|
+
type: "string",
|
|
18595
|
+
description: "Egress lock for new --provider vercel boxes: 'allow-all' (default, unset), 'deny-all', or a comma-separated domain allowlist (e.g. 'github.com,*.npmjs.org') that denies everything else. Vercel-only; ignored by other providers."
|
|
18596
|
+
},
|
|
18576
18597
|
{
|
|
18577
18598
|
key: "claude.sessionName",
|
|
18578
18599
|
type: "string",
|
|
@@ -18690,6 +18711,21 @@ var KEY_REGISTRY = [
|
|
|
18690
18711
|
type: "int",
|
|
18691
18712
|
description: "Max number of simultaneously-running boxes (across providers) before background `-i` jobs queue up instead of starting immediately. Per-invocation override: `--max-running <n>`."
|
|
18692
18713
|
},
|
|
18714
|
+
{
|
|
18715
|
+
key: "queue.maxWorking",
|
|
18716
|
+
type: "int",
|
|
18717
|
+
description: "Max agents actively working/thinking (quota-consuming) at once before background `-i` jobs queue. 0 = disabled (use the queue.maxConcurrent running-box gate). Counts all boxes, foreground + queued. Per-invocation override: `--max-working <n>`."
|
|
18718
|
+
},
|
|
18719
|
+
{
|
|
18720
|
+
key: "queue.idleGraceSeconds",
|
|
18721
|
+
type: "int",
|
|
18722
|
+
description: "Seconds an agent must stay non-working before it frees its working slot (debounce against brief idle flaps between turns). Only used when queue.maxWorking > 0."
|
|
18723
|
+
},
|
|
18724
|
+
{
|
|
18725
|
+
key: "cloud.useCurrentBranch",
|
|
18726
|
+
type: "bool",
|
|
18727
|
+
description: "On cloud providers (daytona/hetzner), start new boxes on the host's current branch instead of forking a new agentbox/<box-name> branch. Overridden by an explicit --use-branch / --from-branch."
|
|
18728
|
+
},
|
|
18693
18729
|
{
|
|
18694
18730
|
key: "maintenance.pruneProjectConfigs",
|
|
18695
18731
|
type: "bool",
|
|
@@ -19119,6 +19155,23 @@ function isGhPrOp(value) {
|
|
|
19119
19155
|
return GH_PR_OPS.includes(value);
|
|
19120
19156
|
}
|
|
19121
19157
|
var GH_PR_READ_ONLY_OPS = /* @__PURE__ */ new Set(["view", "list"]);
|
|
19158
|
+
function injectPrCreateHead(op, branch, args) {
|
|
19159
|
+
if (op !== "create") return args;
|
|
19160
|
+
if (!branch || branch === "HEAD") return args;
|
|
19161
|
+
if (hasHeadArg(args)) return args;
|
|
19162
|
+
return ["--head", branch, ...args];
|
|
19163
|
+
}
|
|
19164
|
+
function hasHeadArg(args) {
|
|
19165
|
+
return args.some((a2) => a2 === "--head" || a2.startsWith("--head=") || a2.startsWith("-H"));
|
|
19166
|
+
}
|
|
19167
|
+
function prCreateNeedsHead(op, args) {
|
|
19168
|
+
return op === "create" && !hasHeadArg(args);
|
|
19169
|
+
}
|
|
19170
|
+
var PR_CREATE_NO_HEAD_REFUSAL = {
|
|
19171
|
+
exitCode: 65,
|
|
19172
|
+
stdout: "",
|
|
19173
|
+
stderr: "gh pr create: refusing to run without --head \u2014 could not resolve this box's branch, and falling back to the host repo's checked-out branch would open a PR for the wrong branch. Ensure the box branch is pushed, or pass --head <branch> explicitly.\n"
|
|
19174
|
+
};
|
|
19122
19175
|
var GH_RPC_TIMEOUT_MS = 12e4;
|
|
19123
19176
|
var GH_READY_CACHE_TTL_MS = 6e4;
|
|
19124
19177
|
var ghReadyCache;
|
|
@@ -19320,36 +19373,31 @@ var BoxStatusStore = class {
|
|
|
19320
19373
|
async function resolveCloudBackend(name) {
|
|
19321
19374
|
if (name === "daytona") {
|
|
19322
19375
|
const pkg = "@agentbox/sandbox-daytona";
|
|
19323
|
-
|
|
19324
|
-
const mod = await import(pkg);
|
|
19325
|
-
return mod.daytonaBackend;
|
|
19326
|
-
} catch (err) {
|
|
19327
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
19328
|
-
if (/cannot find module|MODULE_NOT_FOUND/i.test(msg)) {
|
|
19329
|
-
throw new Error(
|
|
19330
|
-
`relay: cannot load '${pkg}' at runtime \u2014 install it alongside @agentbox/relay (the @madarco/agentbox CLI normally provides this dependency). Original: ${msg}`
|
|
19331
|
-
);
|
|
19332
|
-
}
|
|
19333
|
-
throw err;
|
|
19334
|
-
}
|
|
19376
|
+
return loadCloudBackend(pkg, async () => (await import(pkg)).daytonaBackend);
|
|
19335
19377
|
}
|
|
19336
19378
|
if (name === "hetzner") {
|
|
19337
19379
|
const pkg = "@agentbox/sandbox-hetzner";
|
|
19338
|
-
|
|
19339
|
-
|
|
19340
|
-
|
|
19341
|
-
|
|
19342
|
-
|
|
19343
|
-
if (/cannot find module|MODULE_NOT_FOUND/i.test(msg)) {
|
|
19344
|
-
throw new Error(
|
|
19345
|
-
`relay: cannot load '${pkg}' at runtime \u2014 install it alongside @agentbox/relay (the @madarco/agentbox CLI normally provides this dependency). Original: ${msg}`
|
|
19346
|
-
);
|
|
19347
|
-
}
|
|
19348
|
-
throw err;
|
|
19349
|
-
}
|
|
19380
|
+
return loadCloudBackend(pkg, async () => (await import(pkg)).hetznerBackend);
|
|
19381
|
+
}
|
|
19382
|
+
if (name === "vercel") {
|
|
19383
|
+
const pkg = "@agentbox/sandbox-vercel";
|
|
19384
|
+
return loadCloudBackend(pkg, async () => (await import(pkg)).vercelBackend);
|
|
19350
19385
|
}
|
|
19351
19386
|
throw new Error(`no host executor for cloud backend '${name}'`);
|
|
19352
19387
|
}
|
|
19388
|
+
async function loadCloudBackend(pkg, load2) {
|
|
19389
|
+
try {
|
|
19390
|
+
return await load2();
|
|
19391
|
+
} catch (err) {
|
|
19392
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
19393
|
+
if (/cannot find module|MODULE_NOT_FOUND/i.test(msg)) {
|
|
19394
|
+
throw new Error(
|
|
19395
|
+
`relay: cannot load '${pkg}' at runtime \u2014 install it alongside @agentbox/relay (the @madarco/agentbox CLI normally provides this dependency). Original: ${msg}`
|
|
19396
|
+
);
|
|
19397
|
+
}
|
|
19398
|
+
throw err;
|
|
19399
|
+
}
|
|
19400
|
+
}
|
|
19353
19401
|
async function refreshCloudPreviewUrl(backendName, boxId, port) {
|
|
19354
19402
|
try {
|
|
19355
19403
|
const backend = await resolveCloudBackend(backendName);
|
|
@@ -19477,7 +19525,20 @@ async function runGhPrRpc(action, deps) {
|
|
|
19477
19525
|
}
|
|
19478
19526
|
}
|
|
19479
19527
|
}
|
|
19480
|
-
|
|
19528
|
+
let finalArgs = args;
|
|
19529
|
+
if (op === "create" && !args.some((a2) => a2 === "--head" || a2.startsWith("--head="))) {
|
|
19530
|
+
const backend = await resolveCloudBackend(deps.backendName);
|
|
19531
|
+
const handle = { sandboxId: lookup.cloudSandboxId };
|
|
19532
|
+
const containerPath = params.path ?? "/workspace";
|
|
19533
|
+
const branchProbe = await backend.exec(
|
|
19534
|
+
handle,
|
|
19535
|
+
`git -C ${shellQuote(containerPath)} rev-parse --abbrev-ref HEAD`
|
|
19536
|
+
);
|
|
19537
|
+
const branch = branchProbe.exitCode === 0 ? (branchProbe.stdout ?? "").trim() : "";
|
|
19538
|
+
finalArgs = injectPrCreateHead(op, branch, args);
|
|
19539
|
+
}
|
|
19540
|
+
if (prCreateNeedsHead(op, finalArgs)) return PR_CREATE_NO_HEAD_REFUSAL;
|
|
19541
|
+
return runHostGh(["pr", op, ...finalArgs], lookup.workspacePath);
|
|
19481
19542
|
}
|
|
19482
19543
|
async function runBrowserOpenMirror(action, deps) {
|
|
19483
19544
|
const params = action.params ?? {};
|
|
@@ -19947,7 +20008,13 @@ function createRelayServer(opts) {
|
|
|
19947
20008
|
const url = new URL(req.url ?? "/", `http://${req.headers.host ?? "relay"}`);
|
|
19948
20009
|
const route = `${req.method ?? "GET"} ${url.pathname}`;
|
|
19949
20010
|
if (route === "GET /healthz") {
|
|
19950
|
-
send(res, 200, {
|
|
20011
|
+
send(res, 200, {
|
|
20012
|
+
ok: true,
|
|
20013
|
+
boxes: registry.size(),
|
|
20014
|
+
events: events.size(),
|
|
20015
|
+
pid: process.pid,
|
|
20016
|
+
cliEntry: Boolean(process.env.AGENTBOX_CLI_ENTRY)
|
|
20017
|
+
});
|
|
19951
20018
|
return;
|
|
19952
20019
|
}
|
|
19953
20020
|
if (url.pathname.startsWith("/bridge/")) {
|
|
@@ -20605,7 +20672,9 @@ async function handleGhPrRpc(op, reg, params, prompts, subscribers, hostInitiate
|
|
|
20605
20672
|
return { exitCode: 10, stdout: "", stderr: "denied by user\n" };
|
|
20606
20673
|
}
|
|
20607
20674
|
}
|
|
20608
|
-
|
|
20675
|
+
const finalArgs = injectPrCreateHead(op, worktree.branch, args);
|
|
20676
|
+
if (prCreateNeedsHead(op, finalArgs)) return PR_CREATE_NO_HEAD_REFUSAL;
|
|
20677
|
+
return runHostGh(["pr", op, ...finalArgs], worktree.hostMainRepo);
|
|
20609
20678
|
}
|
|
20610
20679
|
async function handleCpRpc(reg, method, params) {
|
|
20611
20680
|
const entry = process.env.AGENTBOX_CLI_ENTRY;
|
|
@@ -65,11 +65,25 @@ if ! pgrep -u "$(id -u)" -x autocutsel >/dev/null; then
|
|
|
65
65
|
DISPLAY=:1 autocutsel -selection PRIMARY -fork >/dev/null 2>&1 || true
|
|
66
66
|
fi
|
|
67
67
|
|
|
68
|
+
# noVNC's static assets live at different paths per base image: Debian/Ubuntu
|
|
69
|
+
# (docker, hetzner) ship them at /usr/share/novnc via apt; the AL2023 bake
|
|
70
|
+
# (vercel) git-clones them to /usr/local/share/novnc. websockify runs
|
|
71
|
+
# os.chdir(--web) at startup, so a wrong path makes it FileNotFoundError and
|
|
72
|
+
# never bind 6080 — pick the first dir that exists.
|
|
73
|
+
NOVNC_WEB=""
|
|
74
|
+
for _d in /usr/share/novnc /usr/local/share/novnc; do
|
|
75
|
+
if [[ -d "$_d" ]]; then NOVNC_WEB="$_d"; break; fi
|
|
76
|
+
done
|
|
77
|
+
if [[ -z "$NOVNC_WEB" ]]; then
|
|
78
|
+
echo "agentbox-vnc-start: noVNC assets not found (looked in /usr/share/novnc, /usr/local/share/novnc)" >&2
|
|
79
|
+
exit 65
|
|
80
|
+
fi
|
|
81
|
+
|
|
68
82
|
# websockify serves noVNC at /vnc.html (--web) and tunnels WS frames to Xvnc's
|
|
69
83
|
# RFB. Bind 0.0.0.0:6080 so both Docker `-p` mappings and OrbStack's
|
|
70
84
|
# <name>.orb.local routing reach it.
|
|
71
85
|
websockify \
|
|
72
|
-
--web
|
|
86
|
+
--web="$NOVNC_WEB" \
|
|
73
87
|
0.0.0.0:6080 \
|
|
74
88
|
127.0.0.1:5901 \
|
|
75
89
|
>/var/log/agentbox/websockify.log 2>&1 &
|
|
@@ -65,11 +65,25 @@ if ! pgrep -u "$(id -u)" -x autocutsel >/dev/null; then
|
|
|
65
65
|
DISPLAY=:1 autocutsel -selection PRIMARY -fork >/dev/null 2>&1 || true
|
|
66
66
|
fi
|
|
67
67
|
|
|
68
|
+
# noVNC's static assets live at different paths per base image: Debian/Ubuntu
|
|
69
|
+
# (docker, hetzner) ship them at /usr/share/novnc via apt; the AL2023 bake
|
|
70
|
+
# (vercel) git-clones them to /usr/local/share/novnc. websockify runs
|
|
71
|
+
# os.chdir(--web) at startup, so a wrong path makes it FileNotFoundError and
|
|
72
|
+
# never bind 6080 — pick the first dir that exists.
|
|
73
|
+
NOVNC_WEB=""
|
|
74
|
+
for _d in /usr/share/novnc /usr/local/share/novnc; do
|
|
75
|
+
if [[ -d "$_d" ]]; then NOVNC_WEB="$_d"; break; fi
|
|
76
|
+
done
|
|
77
|
+
if [[ -z "$NOVNC_WEB" ]]; then
|
|
78
|
+
echo "agentbox-vnc-start: noVNC assets not found (looked in /usr/share/novnc, /usr/local/share/novnc)" >&2
|
|
79
|
+
exit 65
|
|
80
|
+
fi
|
|
81
|
+
|
|
68
82
|
# websockify serves noVNC at /vnc.html (--web) and tunnels WS frames to Xvnc's
|
|
69
83
|
# RFB. Bind 0.0.0.0:6080 so both Docker `-p` mappings and OrbStack's
|
|
70
84
|
# <name>.orb.local routing reach it.
|
|
71
85
|
websockify \
|
|
72
|
-
--web
|
|
86
|
+
--web="$NOVNC_WEB" \
|
|
73
87
|
0.0.0.0:6080 \
|
|
74
88
|
127.0.0.1:5901 \
|
|
75
89
|
>/var/log/agentbox/websockify.log 2>&1 &
|
package/runtime/hetzner/ctl.cjs
CHANGED
|
@@ -18469,8 +18469,8 @@ var KEY_REGISTRY = [
|
|
|
18469
18469
|
{
|
|
18470
18470
|
key: "box.provider",
|
|
18471
18471
|
type: "enum",
|
|
18472
|
-
enumValues: ["docker", "daytona", "hetzner"],
|
|
18473
|
-
description: "Sandbox backend new boxes are created on: local Docker containers, Daytona Cloud sandboxes,
|
|
18472
|
+
enumValues: ["docker", "daytona", "hetzner", "vercel"],
|
|
18473
|
+
description: "Sandbox backend new boxes are created on: local Docker containers, Daytona Cloud sandboxes, Hetzner Cloud VPSes, or Vercel Sandboxes."
|
|
18474
18474
|
},
|
|
18475
18475
|
{
|
|
18476
18476
|
key: "box.hostSnapshot",
|
|
@@ -18500,6 +18500,12 @@ var KEY_REGISTRY = [
|
|
|
18500
18500
|
description: "Per-provider override of `box.defaultCheckpoint` for hetzner. Wins over the global when set; set via `agentbox checkpoint set-default --provider hetzner`.",
|
|
18501
18501
|
advanced: true
|
|
18502
18502
|
},
|
|
18503
|
+
{
|
|
18504
|
+
key: "box.defaultCheckpointVercel",
|
|
18505
|
+
type: "string",
|
|
18506
|
+
description: "Per-provider override of `box.defaultCheckpoint` for vercel. Wins over the global when set; set via `agentbox checkpoint set-default --provider vercel`.",
|
|
18507
|
+
advanced: true
|
|
18508
|
+
},
|
|
18503
18509
|
{
|
|
18504
18510
|
key: "checkpoint.maxLayers",
|
|
18505
18511
|
type: "int",
|
|
@@ -18573,6 +18579,21 @@ var KEY_REGISTRY = [
|
|
|
18573
18579
|
type: "int",
|
|
18574
18580
|
description: "Cap git bundle history shipped to cloud sandboxes (daytona, hetzner). 0 = full history. Unset = adaptive default (last 200 commits; re-bundle at 100 if the bundle exceeds 20 MB). Ignored for docker (which bind-mounts .git/)."
|
|
18575
18581
|
},
|
|
18582
|
+
{
|
|
18583
|
+
key: "box.vercelVcpus",
|
|
18584
|
+
type: "int",
|
|
18585
|
+
description: "vCPUs for new --provider vercel boxes (Vercel couples RAM at 2048 MB/vCPU). Default 2. Vercel only accepts specific counts (e.g. 1, 2, 4, 8) \u2014 an unsupported value fails create with a 400. Vercel-only; ignored by other providers."
|
|
18586
|
+
},
|
|
18587
|
+
{
|
|
18588
|
+
key: "box.vercelTimeoutMs",
|
|
18589
|
+
type: "int",
|
|
18590
|
+
description: "Max session length (ms) for new --provider vercel boxes before the VM auto-snapshots; persistent mode auto-resumes on the next call. Default 2700000 (45 min, the Hobby ceiling). Vercel-only."
|
|
18591
|
+
},
|
|
18592
|
+
{
|
|
18593
|
+
key: "box.vercelNetworkPolicy",
|
|
18594
|
+
type: "string",
|
|
18595
|
+
description: "Egress lock for new --provider vercel boxes: 'allow-all' (default, unset), 'deny-all', or a comma-separated domain allowlist (e.g. 'github.com,*.npmjs.org') that denies everything else. Vercel-only; ignored by other providers."
|
|
18596
|
+
},
|
|
18576
18597
|
{
|
|
18577
18598
|
key: "claude.sessionName",
|
|
18578
18599
|
type: "string",
|
|
@@ -18690,6 +18711,21 @@ var KEY_REGISTRY = [
|
|
|
18690
18711
|
type: "int",
|
|
18691
18712
|
description: "Max number of simultaneously-running boxes (across providers) before background `-i` jobs queue up instead of starting immediately. Per-invocation override: `--max-running <n>`."
|
|
18692
18713
|
},
|
|
18714
|
+
{
|
|
18715
|
+
key: "queue.maxWorking",
|
|
18716
|
+
type: "int",
|
|
18717
|
+
description: "Max agents actively working/thinking (quota-consuming) at once before background `-i` jobs queue. 0 = disabled (use the queue.maxConcurrent running-box gate). Counts all boxes, foreground + queued. Per-invocation override: `--max-working <n>`."
|
|
18718
|
+
},
|
|
18719
|
+
{
|
|
18720
|
+
key: "queue.idleGraceSeconds",
|
|
18721
|
+
type: "int",
|
|
18722
|
+
description: "Seconds an agent must stay non-working before it frees its working slot (debounce against brief idle flaps between turns). Only used when queue.maxWorking > 0."
|
|
18723
|
+
},
|
|
18724
|
+
{
|
|
18725
|
+
key: "cloud.useCurrentBranch",
|
|
18726
|
+
type: "bool",
|
|
18727
|
+
description: "On cloud providers (daytona/hetzner), start new boxes on the host's current branch instead of forking a new agentbox/<box-name> branch. Overridden by an explicit --use-branch / --from-branch."
|
|
18728
|
+
},
|
|
18693
18729
|
{
|
|
18694
18730
|
key: "maintenance.pruneProjectConfigs",
|
|
18695
18731
|
type: "bool",
|
|
@@ -19119,6 +19155,23 @@ function isGhPrOp(value) {
|
|
|
19119
19155
|
return GH_PR_OPS.includes(value);
|
|
19120
19156
|
}
|
|
19121
19157
|
var GH_PR_READ_ONLY_OPS = /* @__PURE__ */ new Set(["view", "list"]);
|
|
19158
|
+
function injectPrCreateHead(op, branch, args) {
|
|
19159
|
+
if (op !== "create") return args;
|
|
19160
|
+
if (!branch || branch === "HEAD") return args;
|
|
19161
|
+
if (hasHeadArg(args)) return args;
|
|
19162
|
+
return ["--head", branch, ...args];
|
|
19163
|
+
}
|
|
19164
|
+
function hasHeadArg(args) {
|
|
19165
|
+
return args.some((a2) => a2 === "--head" || a2.startsWith("--head=") || a2.startsWith("-H"));
|
|
19166
|
+
}
|
|
19167
|
+
function prCreateNeedsHead(op, args) {
|
|
19168
|
+
return op === "create" && !hasHeadArg(args);
|
|
19169
|
+
}
|
|
19170
|
+
var PR_CREATE_NO_HEAD_REFUSAL = {
|
|
19171
|
+
exitCode: 65,
|
|
19172
|
+
stdout: "",
|
|
19173
|
+
stderr: "gh pr create: refusing to run without --head \u2014 could not resolve this box's branch, and falling back to the host repo's checked-out branch would open a PR for the wrong branch. Ensure the box branch is pushed, or pass --head <branch> explicitly.\n"
|
|
19174
|
+
};
|
|
19122
19175
|
var GH_RPC_TIMEOUT_MS = 12e4;
|
|
19123
19176
|
var GH_READY_CACHE_TTL_MS = 6e4;
|
|
19124
19177
|
var ghReadyCache;
|
|
@@ -19320,36 +19373,31 @@ var BoxStatusStore = class {
|
|
|
19320
19373
|
async function resolveCloudBackend(name) {
|
|
19321
19374
|
if (name === "daytona") {
|
|
19322
19375
|
const pkg = "@agentbox/sandbox-daytona";
|
|
19323
|
-
|
|
19324
|
-
const mod = await import(pkg);
|
|
19325
|
-
return mod.daytonaBackend;
|
|
19326
|
-
} catch (err) {
|
|
19327
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
19328
|
-
if (/cannot find module|MODULE_NOT_FOUND/i.test(msg)) {
|
|
19329
|
-
throw new Error(
|
|
19330
|
-
`relay: cannot load '${pkg}' at runtime \u2014 install it alongside @agentbox/relay (the @madarco/agentbox CLI normally provides this dependency). Original: ${msg}`
|
|
19331
|
-
);
|
|
19332
|
-
}
|
|
19333
|
-
throw err;
|
|
19334
|
-
}
|
|
19376
|
+
return loadCloudBackend(pkg, async () => (await import(pkg)).daytonaBackend);
|
|
19335
19377
|
}
|
|
19336
19378
|
if (name === "hetzner") {
|
|
19337
19379
|
const pkg = "@agentbox/sandbox-hetzner";
|
|
19338
|
-
|
|
19339
|
-
|
|
19340
|
-
|
|
19341
|
-
|
|
19342
|
-
|
|
19343
|
-
if (/cannot find module|MODULE_NOT_FOUND/i.test(msg)) {
|
|
19344
|
-
throw new Error(
|
|
19345
|
-
`relay: cannot load '${pkg}' at runtime \u2014 install it alongside @agentbox/relay (the @madarco/agentbox CLI normally provides this dependency). Original: ${msg}`
|
|
19346
|
-
);
|
|
19347
|
-
}
|
|
19348
|
-
throw err;
|
|
19349
|
-
}
|
|
19380
|
+
return loadCloudBackend(pkg, async () => (await import(pkg)).hetznerBackend);
|
|
19381
|
+
}
|
|
19382
|
+
if (name === "vercel") {
|
|
19383
|
+
const pkg = "@agentbox/sandbox-vercel";
|
|
19384
|
+
return loadCloudBackend(pkg, async () => (await import(pkg)).vercelBackend);
|
|
19350
19385
|
}
|
|
19351
19386
|
throw new Error(`no host executor for cloud backend '${name}'`);
|
|
19352
19387
|
}
|
|
19388
|
+
async function loadCloudBackend(pkg, load2) {
|
|
19389
|
+
try {
|
|
19390
|
+
return await load2();
|
|
19391
|
+
} catch (err) {
|
|
19392
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
19393
|
+
if (/cannot find module|MODULE_NOT_FOUND/i.test(msg)) {
|
|
19394
|
+
throw new Error(
|
|
19395
|
+
`relay: cannot load '${pkg}' at runtime \u2014 install it alongside @agentbox/relay (the @madarco/agentbox CLI normally provides this dependency). Original: ${msg}`
|
|
19396
|
+
);
|
|
19397
|
+
}
|
|
19398
|
+
throw err;
|
|
19399
|
+
}
|
|
19400
|
+
}
|
|
19353
19401
|
async function refreshCloudPreviewUrl(backendName, boxId, port) {
|
|
19354
19402
|
try {
|
|
19355
19403
|
const backend = await resolveCloudBackend(backendName);
|
|
@@ -19477,7 +19525,20 @@ async function runGhPrRpc(action, deps) {
|
|
|
19477
19525
|
}
|
|
19478
19526
|
}
|
|
19479
19527
|
}
|
|
19480
|
-
|
|
19528
|
+
let finalArgs = args;
|
|
19529
|
+
if (op === "create" && !args.some((a2) => a2 === "--head" || a2.startsWith("--head="))) {
|
|
19530
|
+
const backend = await resolveCloudBackend(deps.backendName);
|
|
19531
|
+
const handle = { sandboxId: lookup.cloudSandboxId };
|
|
19532
|
+
const containerPath = params.path ?? "/workspace";
|
|
19533
|
+
const branchProbe = await backend.exec(
|
|
19534
|
+
handle,
|
|
19535
|
+
`git -C ${shellQuote(containerPath)} rev-parse --abbrev-ref HEAD`
|
|
19536
|
+
);
|
|
19537
|
+
const branch = branchProbe.exitCode === 0 ? (branchProbe.stdout ?? "").trim() : "";
|
|
19538
|
+
finalArgs = injectPrCreateHead(op, branch, args);
|
|
19539
|
+
}
|
|
19540
|
+
if (prCreateNeedsHead(op, finalArgs)) return PR_CREATE_NO_HEAD_REFUSAL;
|
|
19541
|
+
return runHostGh(["pr", op, ...finalArgs], lookup.workspacePath);
|
|
19481
19542
|
}
|
|
19482
19543
|
async function runBrowserOpenMirror(action, deps) {
|
|
19483
19544
|
const params = action.params ?? {};
|
|
@@ -19947,7 +20008,13 @@ function createRelayServer(opts) {
|
|
|
19947
20008
|
const url = new URL(req.url ?? "/", `http://${req.headers.host ?? "relay"}`);
|
|
19948
20009
|
const route = `${req.method ?? "GET"} ${url.pathname}`;
|
|
19949
20010
|
if (route === "GET /healthz") {
|
|
19950
|
-
send(res, 200, {
|
|
20011
|
+
send(res, 200, {
|
|
20012
|
+
ok: true,
|
|
20013
|
+
boxes: registry.size(),
|
|
20014
|
+
events: events.size(),
|
|
20015
|
+
pid: process.pid,
|
|
20016
|
+
cliEntry: Boolean(process.env.AGENTBOX_CLI_ENTRY)
|
|
20017
|
+
});
|
|
19951
20018
|
return;
|
|
19952
20019
|
}
|
|
19953
20020
|
if (url.pathname.startsWith("/bridge/")) {
|
|
@@ -20605,7 +20672,9 @@ async function handleGhPrRpc(op, reg, params, prompts, subscribers, hostInitiate
|
|
|
20605
20672
|
return { exitCode: 10, stdout: "", stderr: "denied by user\n" };
|
|
20606
20673
|
}
|
|
20607
20674
|
}
|
|
20608
|
-
|
|
20675
|
+
const finalArgs = injectPrCreateHead(op, worktree.branch, args);
|
|
20676
|
+
if (prCreateNeedsHead(op, finalArgs)) return PR_CREATE_NO_HEAD_REFUSAL;
|
|
20677
|
+
return runHostGh(["pr", op, ...finalArgs], worktree.hostMainRepo);
|
|
20609
20678
|
}
|
|
20610
20679
|
async function handleCpRpc(reg, method, params) {
|
|
20611
20680
|
const entry = process.env.AGENTBOX_CLI_ENTRY;
|