@madarco/agentbox 0.7.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.
Files changed (77) hide show
  1. package/dist/_cloud-attach-ZXBCNWJX.js +13 -0
  2. package/dist/{chunk-NW5NYTQM.js → chunk-BXQMIEHC.js} +459 -110
  3. package/dist/chunk-BXQMIEHC.js.map +1 -0
  4. package/dist/{chunk-UK72UQ5U.js → chunk-G3H2L3O2.js} +55 -4
  5. package/dist/chunk-G3H2L3O2.js.map +1 -0
  6. package/dist/{chunk-7KOEFGN2.js → chunk-GU5LW4B5.js} +385 -31
  7. package/dist/chunk-GU5LW4B5.js.map +1 -0
  8. package/dist/chunk-KL36BRN4.js +455 -0
  9. package/dist/chunk-KL36BRN4.js.map +1 -0
  10. package/dist/{chunk-V5KZGB5V.js → chunk-LEV3KICD.js} +18 -2
  11. package/dist/chunk-LEV3KICD.js.map +1 -0
  12. package/dist/chunk-MTVI44DW.js +662 -0
  13. package/dist/chunk-MTVI44DW.js.map +1 -0
  14. package/dist/{chunk-NAVL4R34.js → chunk-NCJP5MTN.js} +1281 -556
  15. package/dist/chunk-NCJP5MTN.js.map +1 -0
  16. package/dist/{cloud-poller-ZIWSADJB-JXFRJUEM.js → cloud-poller-SUNA6ZQC-2RG5WPRN.js} +2 -2
  17. package/dist/{dist-ETCFRVPA.js → dist-32EZBYG4.js} +50 -20
  18. package/dist/{dist-R67WMLCF.js → dist-CX5CGVEB.js} +120 -10
  19. package/dist/dist-CX5CGVEB.js.map +1 -0
  20. package/dist/{dist-QZGJIBT5.js → dist-GDHP34ZK.js} +141 -75
  21. package/dist/dist-GDHP34ZK.js.map +1 -0
  22. package/dist/dist-XML54CNB.js +849 -0
  23. package/dist/dist-XML54CNB.js.map +1 -0
  24. package/dist/index.js +3881 -867
  25. package/dist/index.js.map +1 -1
  26. package/dist/prepared-state-CL4CWXQA-H5THETIM.js +18 -0
  27. package/dist/prepared-state-CL4CWXQA-H5THETIM.js.map +1 -0
  28. package/package.json +7 -5
  29. package/runtime/daytona/custom-system-CLAUDE.md +39 -0
  30. package/runtime/docker/Dockerfile.box +22 -0
  31. package/runtime/docker/apps/cli/share/agentbox-setup/SKILL.md +1 -1
  32. package/runtime/docker/packages/ctl/dist/bin.cjs +1214 -98
  33. package/runtime/docker/packages/sandbox-docker/scripts/agentbox-codex-hooks.json +66 -35
  34. package/runtime/docker/packages/sandbox-docker/scripts/agentbox-vnc-start +15 -1
  35. package/runtime/docker/packages/sandbox-docker/scripts/claude-managed-settings.json +62 -1
  36. package/runtime/docker/packages/sandbox-docker/scripts/custom-system-CLAUDE.md +15 -4
  37. package/runtime/docker/packages/sandbox-docker/scripts/gh-shim +263 -0
  38. package/runtime/docker/packages/sandbox-docker/scripts/git-shim +131 -0
  39. package/runtime/docker/packages/sandbox-docker/scripts/opencode-agentbox-plugin.js +76 -0
  40. package/runtime/hetzner/agentbox-codex-hooks.json +66 -35
  41. package/runtime/hetzner/agentbox-setup-skill.md +1 -1
  42. package/runtime/hetzner/agentbox-vnc-start +15 -1
  43. package/runtime/hetzner/claude-managed-settings.json +62 -1
  44. package/runtime/hetzner/ctl.cjs +1214 -98
  45. package/runtime/hetzner/custom-system-CLAUDE.md +26 -14
  46. package/runtime/hetzner/gh-shim +263 -0
  47. package/runtime/hetzner/git-shim +131 -0
  48. package/runtime/hetzner/opencode-agentbox-plugin.js +76 -0
  49. package/runtime/hetzner/scripts/install-box.sh +11 -2
  50. package/runtime/relay/bin.cjs +1146 -63
  51. package/runtime/vercel/agentbox-checkpoint-cleanup +52 -0
  52. package/runtime/vercel/agentbox-codex-hooks.json +68 -0
  53. package/runtime/vercel/agentbox-open +28 -0
  54. package/runtime/vercel/agentbox-setup-skill.md +196 -0
  55. package/runtime/vercel/agentbox-vnc-start +91 -0
  56. package/runtime/vercel/claude-managed-settings.json +115 -0
  57. package/runtime/vercel/ctl.cjs +23466 -0
  58. package/runtime/vercel/custom-system-CLAUDE.md +50 -0
  59. package/runtime/vercel/gh-shim +263 -0
  60. package/runtime/vercel/git-shim +131 -0
  61. package/runtime/vercel/scripts/provision.sh +274 -0
  62. package/share/agentbox-setup/SKILL.md +1 -1
  63. package/share/host-skills/agentbox/SKILL.md +29 -0
  64. package/share/host-skills/agentbox-info/SKILL.md +211 -0
  65. package/share/host-skills/codex/agentbox.md +35 -0
  66. package/share/host-skills/opencode/agentbox.md +26 -0
  67. package/dist/_cloud-attach-DMVH6GWO.js +0 -12
  68. package/dist/chunk-7KOEFGN2.js.map +0 -1
  69. package/dist/chunk-NAVL4R34.js.map +0 -1
  70. package/dist/chunk-NW5NYTQM.js.map +0 -1
  71. package/dist/chunk-UK72UQ5U.js.map +0 -1
  72. package/dist/chunk-V5KZGB5V.js.map +0 -1
  73. package/dist/dist-QZGJIBT5.js.map +0 -1
  74. package/dist/dist-R67WMLCF.js.map +0 -1
  75. /package/dist/{_cloud-attach-DMVH6GWO.js.map → _cloud-attach-ZXBCNWJX.js.map} +0 -0
  76. /package/dist/{cloud-poller-ZIWSADJB-JXFRJUEM.js.map → cloud-poller-SUNA6ZQC-2RG5WPRN.js.map} +0 -0
  77. /package/dist/{dist-ETCFRVPA.js.map → dist-32EZBYG4.js.map} +0 -0
@@ -0,0 +1,849 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ Sandbox,
4
+ Snapshot,
5
+ detectSbx,
6
+ ensureFreshCredentials,
7
+ ensureVercelCredentials,
8
+ ensureVercelEnvLoaded,
9
+ maskKey,
10
+ readVercelCredStatus,
11
+ reloadVercelEnv,
12
+ resolveCredentials,
13
+ secretsPath
14
+ } from "./chunk-MTVI44DW.js";
15
+ import {
16
+ createCloudProvider,
17
+ listCloudCheckpoints,
18
+ removeCloudCheckpointDir,
19
+ renderInnerCommand,
20
+ resolveCloudCheckpoint,
21
+ writeCloudCheckpointManifest
22
+ } from "./chunk-BXQMIEHC.js";
23
+ import {
24
+ stageClaudeCredentialsForUpload,
25
+ stageClaudeStaticForUpload,
26
+ stageCodexCredentialsForUpload,
27
+ stageCodexStaticForUpload,
28
+ stageOpencodeCredentialsForUpload,
29
+ stageOpencodeStaticForUpload
30
+ } from "./chunk-NCJP5MTN.js";
31
+ import {
32
+ computeContextSha256,
33
+ preparedStatePathFor,
34
+ readCliStamp,
35
+ readPreparedStateRaw,
36
+ writePreparedStateRaw
37
+ } from "./chunk-KL36BRN4.js";
38
+ import "./chunk-G3H2L3O2.js";
39
+
40
+ // ../../packages/sandbox-vercel/dist/index.js
41
+ import { readFile } from "fs/promises";
42
+ import { readFile as readFile2 } from "fs/promises";
43
+ import { Writable } from "stream";
44
+ import { existsSync } from "fs";
45
+ import { dirname, resolve } from "path";
46
+ import { fileURLToPath } from "url";
47
+ var DEFAULT_BACKOFF = [1e3, 2e3, 4e3];
48
+ var DEFAULT_ATTEMPT_TIMEOUT_MS = 3e4;
49
+ var AttemptTimeoutError = class extends Error {
50
+ constructor(method, ms) {
51
+ super(`vercel ${method}: per-attempt timeout after ${String(ms)}ms`);
52
+ this.name = "AttemptTimeoutError";
53
+ }
54
+ };
55
+ function statusCodeOf(err) {
56
+ if (!err || typeof err !== "object") return void 0;
57
+ for (const key of ["statusCode", "status", "code"]) {
58
+ const v = err[key];
59
+ if (typeof v === "number") return v;
60
+ }
61
+ const resp = err.response;
62
+ if (resp && typeof resp.status === "number") return resp.status;
63
+ return void 0;
64
+ }
65
+ function isRetriable(err, allowAmbiguous) {
66
+ if (err instanceof AttemptTimeoutError) return allowAmbiguous;
67
+ const status = statusCodeOf(err);
68
+ if (status !== void 0) {
69
+ if (status === 429) return true;
70
+ if (status >= 500 && status <= 599) return allowAmbiguous;
71
+ return false;
72
+ }
73
+ if (err && typeof err === "object") {
74
+ const candidates = [err, err.cause];
75
+ for (const c of candidates) {
76
+ if (!c || typeof c !== "object") continue;
77
+ const code = c.code;
78
+ if (code === "ECONNRESET" || code === "ETIMEDOUT" || code === "ECONNABORTED" || code === "EAI_AGAIN" || code === "ECONNREFUSED" || code === "ENOTFOUND" || code === "UND_ERR_SOCKET" || code === "UND_ERR_CONNECT_TIMEOUT") {
79
+ return allowAmbiguous;
80
+ }
81
+ }
82
+ }
83
+ return false;
84
+ }
85
+ async function withVercelRetry(opts, fn) {
86
+ const backoff = opts.backoffMs ?? DEFAULT_BACKOFF;
87
+ const maxAttempts = backoff.length + 1;
88
+ const timeoutMs = opts.attemptTimeoutMs ?? DEFAULT_ATTEMPT_TIMEOUT_MS;
89
+ const log = opts.onRetry ?? defaultRetryLog;
90
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
91
+ try {
92
+ return await raceTimeout(fn(), timeoutMs, opts.method);
93
+ } catch (err) {
94
+ const last = attempt === maxAttempts;
95
+ if (last || !isRetriable(err, opts.retryOnAmbiguous)) throw err;
96
+ const delay = backoff[attempt - 1] ?? backoff[backoff.length - 1] ?? 4e3;
97
+ log(
98
+ `vercel ${opts.method}: attempt ${String(attempt)} failed (${errorSummary(err)}); retrying in ${String(delay)}ms`
99
+ );
100
+ await sleep(delay);
101
+ }
102
+ }
103
+ throw new Error(`withVercelRetry: exhausted attempts for ${opts.method}`);
104
+ }
105
+ function defaultRetryLog(line) {
106
+ process.stderr.write(`
107
+ [vercel-retry] ${line}
108
+ `);
109
+ }
110
+ function sleep(ms) {
111
+ return new Promise((r) => setTimeout(r, ms));
112
+ }
113
+ async function raceTimeout(p, ms, method) {
114
+ let timer;
115
+ try {
116
+ return await Promise.race([
117
+ p,
118
+ new Promise((_resolve, reject) => {
119
+ timer = setTimeout(() => reject(new AttemptTimeoutError(method, ms)), ms);
120
+ })
121
+ ]);
122
+ } finally {
123
+ if (timer !== void 0) clearTimeout(timer);
124
+ }
125
+ }
126
+ function errorSummary(err) {
127
+ if (err instanceof Error) {
128
+ const status = statusCodeOf(err);
129
+ return status !== void 0 ? `${err.name}(${String(status)}): ${truncate(err.message)}` : `${err.name}: ${truncate(err.message)}`;
130
+ }
131
+ return truncate(String(err));
132
+ }
133
+ function truncate(s, max = 160) {
134
+ return s.length > max ? `${s.slice(0, max)}\u2026` : s;
135
+ }
136
+ var SCHEMA = 1;
137
+ function preparedStatePath() {
138
+ return preparedStatePathFor("vercel");
139
+ }
140
+ function readPreparedState() {
141
+ const raw = readPreparedStateRaw("vercel");
142
+ if (raw === null || typeof raw !== "object") return { schema: SCHEMA };
143
+ const parsed = raw;
144
+ if (parsed.schema !== SCHEMA) {
145
+ return { schema: SCHEMA };
146
+ }
147
+ return { schema: SCHEMA, base: parsed.base };
148
+ }
149
+ function writePreparedState(state) {
150
+ writePreparedStateRaw("vercel", state);
151
+ }
152
+ function updatePreparedState(mutate) {
153
+ const s = readPreparedState();
154
+ mutate(s);
155
+ writePreparedState(s);
156
+ }
157
+ function ensureVercelBaseSnapshot() {
158
+ const state = readPreparedState();
159
+ if (state.base !== void 0) return;
160
+ throw new Error(
161
+ "no Vercel base snapshot found.\nRun `agentbox prepare --provider vercel` first \u2014 Vercel cannot build images from a Dockerfile, so the base snapshot is a one-time prerequisite for cloud boxes."
162
+ );
163
+ }
164
+ var DEFAULT_BOX_IMAGE_REF = "agentbox/box:dev";
165
+ var BOX_USER = "vscode";
166
+ var BOX_OWNER = "vscode:vscode";
167
+ var VERCEL_EXPOSED_PORTS = [6080, 8788];
168
+ var VERCEL_MAX_PORTS = 4;
169
+ function buildExposedPorts(extra) {
170
+ const ports = [...VERCEL_EXPOSED_PORTS];
171
+ const seen = new Set(ports);
172
+ for (const p of extra ?? []) {
173
+ if (ports.length >= VERCEL_MAX_PORTS) break;
174
+ if (Number.isInteger(p) && p >= 1024 && p < 65536 && !seen.has(p)) {
175
+ ports.push(p);
176
+ seen.add(p);
177
+ }
178
+ }
179
+ return ports;
180
+ }
181
+ function parseNetworkPolicy(raw) {
182
+ const v = (raw ?? "").trim();
183
+ if (v === "") return void 0;
184
+ if (v === "allow-all" || v === "deny-all") return v;
185
+ const allow = v.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
186
+ return allow.length > 0 ? { allow } : void 0;
187
+ }
188
+ var DEFAULT_TIMEOUT_MS = 45 * 6e4;
189
+ var KEEP_LAST_SNAPSHOTS = { count: 1, expiration: 0, deleteEvicted: true };
190
+ function creds() {
191
+ return resolveCredentials();
192
+ }
193
+ function shq(s) {
194
+ return "'" + s.replace(/'/g, "'\\''") + "'";
195
+ }
196
+ async function getSandbox(id) {
197
+ return Sandbox.get({ name: id, resume: false, ...creds() });
198
+ }
199
+ async function maybeGetSandbox(id) {
200
+ try {
201
+ return await getSandbox(id);
202
+ } catch {
203
+ return null;
204
+ }
205
+ }
206
+ function mapState(s) {
207
+ switch (s) {
208
+ case "running":
209
+ return "running";
210
+ case "pending":
211
+ case "stopping":
212
+ case "snapshotting":
213
+ return "running";
214
+ case "stopped":
215
+ return "paused";
216
+ case "aborted":
217
+ case "failed":
218
+ default:
219
+ return "missing";
220
+ }
221
+ }
222
+ function buildRunCommand(cmd, opts) {
223
+ const prelude = [];
224
+ if (opts?.cwd) prelude.push(`cd ${shq(opts.cwd)}`);
225
+ for (const [k, v] of Object.entries(opts?.env ?? {})) {
226
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(k)) {
227
+ throw new Error(`vercel exec: invalid env var name ${JSON.stringify(k)}`);
228
+ }
229
+ prelude.push(`export ${k}=${shq(v)}`);
230
+ }
231
+ const inner = [...prelude, cmd].join("\n");
232
+ const user = opts?.user ?? BOX_USER;
233
+ if (user === "root") {
234
+ return { cmd: "bash", args: ["-lc", inner], sudo: true };
235
+ }
236
+ return {
237
+ cmd: "bash",
238
+ args: ["-lc", `sudo -u ${user} -H bash -lc ${shq(inner)}`],
239
+ sudo: true
240
+ };
241
+ }
242
+ async function pushVercelAgentCredentials(sb, log) {
243
+ const specs = [
244
+ { kind: "claude", stage: stageClaudeCredentialsForUpload, dest: "/home/vscode/.agentbox-creds/claude" },
245
+ { kind: "codex", stage: stageCodexCredentialsForUpload, dest: "/home/vscode/.agentbox-creds/codex" },
246
+ { kind: "opencode", stage: stageOpencodeCredentialsForUpload, dest: "/home/vscode/.agentbox-creds/opencode" }
247
+ ];
248
+ for (const spec of specs) {
249
+ const staged = await spec.stage();
250
+ for (const w of staged.warnings) log(`vercel: [${spec.kind}-creds] ${w}`);
251
+ try {
252
+ if (!staged.tarballPath) {
253
+ log(`vercel: ${spec.kind}: no host credentials to push (skipping)`);
254
+ continue;
255
+ }
256
+ const remote = `/tmp/agentbox-${spec.kind}-creds.tar.gz`;
257
+ await sb.writeFiles([{ path: remote, content: await readFile(staged.tarballPath) }]);
258
+ const extract = `sudo -u vscode mkdir -p ${spec.dest} && sudo -u vscode tar -xzf ${remote} -C ${spec.dest} --no-same-permissions --no-same-owner -m && rm -f ${remote}`;
259
+ const r = await sb.runCommand({ cmd: "bash", args: ["-lc", extract], sudo: true });
260
+ if (r.exitCode !== 0) {
261
+ log(`vercel: WARN \u2014 ${spec.kind} credential extract failed (exit ${String(r.exitCode)})`);
262
+ } else {
263
+ log(`vercel: ${spec.kind}: credentials pushed`);
264
+ }
265
+ } finally {
266
+ await staged.cleanup();
267
+ }
268
+ }
269
+ }
270
+ var vercelBackend = {
271
+ name: "vercel",
272
+ async provision(req) {
273
+ await ensureFreshCredentials();
274
+ const snapshotId = req.snapshot ?? readPreparedState().base?.snapshotId;
275
+ if (!snapshotId) {
276
+ throw new Error(
277
+ "no Vercel base snapshot found.\nRun `agentbox prepare --provider vercel` first \u2014 Vercel cannot build images from a Dockerfile, so the base snapshot is a one-time prerequisite."
278
+ );
279
+ }
280
+ const networkPolicy = parseNetworkPolicy(req.networkPolicy);
281
+ const log = req.onLog ?? (() => {
282
+ });
283
+ const handle = await withVercelRetry(
284
+ { method: "provision", retryOnAmbiguous: false, attemptTimeoutMs: 9e5, backoffMs: [] },
285
+ async () => {
286
+ const sb = await Sandbox.create({
287
+ name: req.name,
288
+ source: { type: "snapshot", snapshotId },
289
+ resources: { vcpus: req.resources?.cpu ?? 2 },
290
+ ports: buildExposedPorts(req.exposePorts),
291
+ timeout: req.timeoutMs ?? DEFAULT_TIMEOUT_MS,
292
+ env: req.env,
293
+ tags: { agentbox: "true", "agentbox.name": req.name },
294
+ persistent: true,
295
+ keepLastSnapshots: { ...KEEP_LAST_SNAPSHOTS },
296
+ ...networkPolicy ? { networkPolicy } : {},
297
+ ...creds()
298
+ });
299
+ return { sandboxId: sb.name };
300
+ }
301
+ );
302
+ try {
303
+ const sb = await getSandbox(handle.sandboxId);
304
+ await pushVercelAgentCredentials(sb, log);
305
+ } catch (err) {
306
+ log(
307
+ `vercel: WARN \u2014 agent credential push failed (${err instanceof Error ? err.message : String(err)}); in-box claude/codex/opencode will prompt for interactive login`
308
+ );
309
+ }
310
+ return handle;
311
+ },
312
+ async get(sandboxId) {
313
+ await ensureFreshCredentials();
314
+ return withVercelRetry({ method: "get", retryOnAmbiguous: true }, async () => {
315
+ const sb = await maybeGetSandbox(sandboxId);
316
+ return sb ? { sandboxId: sb.name } : null;
317
+ });
318
+ },
319
+ async list() {
320
+ await ensureFreshCredentials();
321
+ return withVercelRetry({ method: "list", retryOnAmbiguous: true }, async () => {
322
+ const page = await Sandbox.list({ ...creds() });
323
+ const items = await page.toArray();
324
+ return items.filter((sb) => sb.tags?.["agentbox"] === "true").map((sb) => {
325
+ const summary = { sandboxId: sb.name };
326
+ const friendly = sb.tags?.["agentbox.name"] ?? sb.name;
327
+ if (friendly) summary.name = friendly;
328
+ if (typeof sb.createdAt === "number") {
329
+ summary.createdAt = new Date(sb.createdAt).toISOString();
330
+ }
331
+ summary.state = mapState(sb.status);
332
+ return summary;
333
+ });
334
+ });
335
+ },
336
+ async start(h) {
337
+ await ensureFreshCredentials();
338
+ await withVercelRetry(
339
+ { method: "start", retryOnAmbiguous: true, attemptTimeoutMs: 12e4 },
340
+ async () => {
341
+ await Sandbox.get({ name: h.sandboxId, resume: true, ...creds() });
342
+ }
343
+ );
344
+ },
345
+ async stop(h) {
346
+ await ensureFreshCredentials();
347
+ await withVercelRetry(
348
+ { method: "stop", retryOnAmbiguous: true, attemptTimeoutMs: 12e4 },
349
+ async () => {
350
+ const sb = await getSandbox(h.sandboxId);
351
+ await sb.stop();
352
+ }
353
+ );
354
+ },
355
+ // pause == stop on Vercel (the auto-snapshot IS the cold-storage state).
356
+ async pause(h) {
357
+ await this.stop(h);
358
+ },
359
+ async resume(h) {
360
+ await this.start(h);
361
+ },
362
+ async destroy(h) {
363
+ await ensureFreshCredentials();
364
+ await withVercelRetry(
365
+ { method: "destroy", retryOnAmbiguous: true, attemptTimeoutMs: 12e4 },
366
+ async () => {
367
+ const sb = await maybeGetSandbox(h.sandboxId);
368
+ if (!sb) return;
369
+ const snapId = sb.currentSnapshotId;
370
+ const source = sb.sourceSnapshotId;
371
+ const base = readPreparedState().base?.snapshotId;
372
+ const ownSnapshot = snapId !== void 0 && snapId !== source && snapId !== base;
373
+ await sb.delete();
374
+ if (ownSnapshot) {
375
+ try {
376
+ const snap = await Snapshot.get({ snapshotId: snapId, ...creds() });
377
+ await snap.delete();
378
+ } catch {
379
+ }
380
+ }
381
+ }
382
+ );
383
+ },
384
+ async state(h) {
385
+ await ensureFreshCredentials();
386
+ return withVercelRetry({ method: "state", retryOnAmbiguous: true }, async () => {
387
+ const sb = await maybeGetSandbox(h.sandboxId);
388
+ if (!sb) return "missing";
389
+ return mapState(sb.status);
390
+ });
391
+ },
392
+ async exec(h, cmd, opts) {
393
+ await ensureFreshCredentials();
394
+ return withVercelRetry(
395
+ {
396
+ method: "exec",
397
+ retryOnAmbiguous: opts?.noRetry ? false : true,
398
+ attemptTimeoutMs: opts?.attemptTimeoutMs ?? 12e4,
399
+ backoffMs: opts?.noRetry ? [] : void 0
400
+ },
401
+ async () => {
402
+ const sb = await getSandbox(h.sandboxId);
403
+ const r = await sb.runCommand(buildRunCommand(cmd, opts));
404
+ const [stdout, stderr] = await Promise.all([r.stdout(), r.stderr()]);
405
+ return { exitCode: r.exitCode, stdout, stderr };
406
+ }
407
+ );
408
+ },
409
+ async uploadFile(h, localPath, remotePath) {
410
+ await ensureFreshCredentials();
411
+ await withVercelRetry(
412
+ { method: "uploadFile", retryOnAmbiguous: true, attemptTimeoutMs: 3e5 },
413
+ async () => {
414
+ const content = await readFile(localPath);
415
+ const sb = await getSandbox(h.sandboxId);
416
+ await sb.writeFiles([{ path: remotePath, content }]);
417
+ try {
418
+ await sb.runCommand({ cmd: "chown", args: [BOX_OWNER, remotePath], sudo: true });
419
+ } catch {
420
+ }
421
+ }
422
+ );
423
+ },
424
+ async downloadFile(h, remotePath, localPath) {
425
+ await ensureFreshCredentials();
426
+ await withVercelRetry(
427
+ { method: "downloadFile", retryOnAmbiguous: true, attemptTimeoutMs: 3e5 },
428
+ async () => {
429
+ const sb = await getSandbox(h.sandboxId);
430
+ const written = await sb.downloadFile(
431
+ { path: remotePath },
432
+ { path: localPath },
433
+ { mkdirRecursive: true }
434
+ );
435
+ if (written === null) {
436
+ throw new Error(`vercel downloadFile: source not found: ${remotePath}`);
437
+ }
438
+ }
439
+ );
440
+ },
441
+ async listFiles(h, remoteDir) {
442
+ await ensureFreshCredentials();
443
+ return withVercelRetry({ method: "listFiles", retryOnAmbiguous: true }, async () => {
444
+ const sb = await getSandbox(h.sandboxId);
445
+ const entries = await sb.fs.readdir(remoteDir, { withFileTypes: true });
446
+ return entries.map((e) => ({ name: e.name, isDir: e.isDirectory() }));
447
+ });
448
+ },
449
+ async previewUrl(h, port) {
450
+ await ensureFreshCredentials();
451
+ return withVercelRetry({ method: "previewUrl", retryOnAmbiguous: true }, async () => {
452
+ const sb = await getSandbox(h.sandboxId);
453
+ return { url: sb.domain(port), token: void 0 };
454
+ });
455
+ },
456
+ // Fewer params than the interface's (h, port, expiresInSeconds) is fine —
457
+ // Vercel sandbox domains are already public + browser-usable, so the signed
458
+ // URL is just the standard one (the TTL is governed by the sandbox session
459
+ // lifetime, not a per-URL signature, so the expiry arg is irrelevant here).
460
+ async signedPreviewUrl(h, port) {
461
+ return this.previewUrl(h, port);
462
+ }
463
+ // NOTE: no `createSnapshot`/`deleteSnapshot` here. Vercel snapshots are
464
+ // addressed by an opaque id (not a caller-chosen name), which doesn't fit the
465
+ // CloudBackend `createSnapshot(handle, name): void` contract — the provider
466
+ // needs the id back to store it in the checkpoint manifest. The Vercel
467
+ // provider therefore overrides the whole `checkpoint` capability in index.ts
468
+ // using `snapshotVercelSandbox` / `deleteVercelSnapshot` below.
469
+ };
470
+ async function snapshotVercelSandbox(sandboxId) {
471
+ await ensureFreshCredentials();
472
+ return withVercelRetry(
473
+ { method: "createSnapshot", retryOnAmbiguous: false, attemptTimeoutMs: 9e5, backoffMs: [] },
474
+ async () => {
475
+ const sb = await getSandbox(sandboxId);
476
+ const snap = await sb.snapshot({ expiration: 0 });
477
+ return snap.snapshotId;
478
+ }
479
+ );
480
+ }
481
+ async function deleteVercelSnapshot(snapshotId) {
482
+ await ensureFreshCredentials();
483
+ await withVercelRetry({ method: "deleteSnapshot", retryOnAmbiguous: true }, async () => {
484
+ try {
485
+ const snap = await Snapshot.get({ snapshotId, ...creds() });
486
+ await snap.delete();
487
+ } catch (err) {
488
+ const msg = err instanceof Error ? err.message : String(err);
489
+ if (/not.?found|404/i.test(msg)) return;
490
+ throw err;
491
+ }
492
+ });
493
+ }
494
+ var SELF = dirname(fileURLToPath(import.meta.url));
495
+ function findStagedCliRuntimeRoot() {
496
+ const candidates = [
497
+ resolve(SELF, "..", "runtime"),
498
+ resolve(SELF, "..", "..", "runtime")
499
+ ];
500
+ for (const c of candidates) {
501
+ if (existsSync(resolve(c, "vercel", "scripts", "provision.sh"))) return c;
502
+ }
503
+ return void 0;
504
+ }
505
+ var RUNTIME_ASSETS = [
506
+ { name: "provision.sh", remotePath: "/tmp/agentbox-provision.sh", remoteMode: 493 },
507
+ { name: "agentbox-ctl", remotePath: "/tmp/agentbox-ctl", remoteMode: 493 },
508
+ { name: "agentbox-vnc-start", remotePath: "/tmp/agentbox-vnc-start", remoteMode: 493 },
509
+ { name: "agentbox-checkpoint-cleanup", remotePath: "/tmp/agentbox-checkpoint-cleanup", remoteMode: 493 },
510
+ { name: "agentbox-open", remotePath: "/tmp/agentbox-open", remoteMode: 493 },
511
+ { name: "gh-shim", remotePath: "/tmp/agentbox-gh-shim", remoteMode: 493 },
512
+ { name: "git-shim", remotePath: "/tmp/agentbox-git-shim", remoteMode: 493 },
513
+ { name: "custom-system-CLAUDE.md", remotePath: "/tmp/agentbox-custom-CLAUDE.md", remoteMode: 420 },
514
+ { name: "claude-managed-settings.json", remotePath: "/tmp/agentbox-managed-settings.json", remoteMode: 420 },
515
+ { name: "agentbox-codex-hooks.json", remotePath: "/tmp/agentbox-codex-hooks.json", remoteMode: 420 },
516
+ { name: "agentbox-setup-skill.md", remotePath: "/tmp/agentbox-setup-skill.md", remoteMode: 420 }
517
+ ];
518
+ function candidatesFor(name, opts = {}) {
519
+ const cliRoot = opts.cliRuntimeRoot;
520
+ const monorepo = opts.repoRoot ?? guessRepoRoot();
521
+ const monorepoRelative = {
522
+ "provision.sh": ["packages/sandbox-vercel/scripts/provision.sh"],
523
+ "agentbox-ctl": ["packages/ctl/dist/bin.cjs"],
524
+ "agentbox-vnc-start": ["packages/sandbox-docker/scripts/agentbox-vnc-start"],
525
+ "agentbox-checkpoint-cleanup": ["packages/sandbox-docker/scripts/agentbox-checkpoint-cleanup"],
526
+ "agentbox-open": ["packages/sandbox-docker/scripts/agentbox-open"],
527
+ "gh-shim": ["packages/sandbox-docker/scripts/gh-shim"],
528
+ "git-shim": ["packages/sandbox-docker/scripts/git-shim"],
529
+ "custom-system-CLAUDE.md": ["packages/sandbox-vercel/scripts/custom-system-CLAUDE.md"],
530
+ "claude-managed-settings.json": ["packages/sandbox-docker/scripts/claude-managed-settings.json"],
531
+ "agentbox-codex-hooks.json": ["packages/sandbox-docker/scripts/agentbox-codex-hooks.json"],
532
+ "agentbox-setup-skill.md": ["apps/cli/share/agentbox-setup/SKILL.md"]
533
+ };
534
+ const cliRelative = {
535
+ "provision.sh": ["vercel/scripts/provision.sh"],
536
+ "agentbox-ctl": ["vercel/ctl.cjs"],
537
+ "agentbox-vnc-start": ["vercel/agentbox-vnc-start", "docker/packages/sandbox-docker/scripts/agentbox-vnc-start"],
538
+ "agentbox-checkpoint-cleanup": ["vercel/agentbox-checkpoint-cleanup", "docker/packages/sandbox-docker/scripts/agentbox-checkpoint-cleanup"],
539
+ "agentbox-open": ["vercel/agentbox-open", "docker/packages/sandbox-docker/scripts/agentbox-open"],
540
+ "gh-shim": ["vercel/gh-shim", "docker/packages/sandbox-docker/scripts/gh-shim"],
541
+ "git-shim": ["vercel/git-shim", "docker/packages/sandbox-docker/scripts/git-shim"],
542
+ "custom-system-CLAUDE.md": ["vercel/custom-system-CLAUDE.md"],
543
+ "claude-managed-settings.json": ["vercel/claude-managed-settings.json", "docker/packages/sandbox-docker/scripts/claude-managed-settings.json"],
544
+ "agentbox-codex-hooks.json": ["vercel/agentbox-codex-hooks.json", "docker/packages/sandbox-docker/scripts/agentbox-codex-hooks.json"],
545
+ "agentbox-setup-skill.md": ["vercel/agentbox-setup-skill.md", "docker/apps/cli/share/agentbox-setup/SKILL.md"]
546
+ };
547
+ const out = [];
548
+ if (cliRoot) {
549
+ for (const rel of cliRelative[name] ?? []) out.push(resolve(cliRoot, rel));
550
+ }
551
+ for (const rel of monorepoRelative[name] ?? []) out.push(resolve(monorepo, rel));
552
+ return out;
553
+ }
554
+ function resolveRuntimeAssets(opts = {}) {
555
+ const out = [];
556
+ const missing = [];
557
+ for (const asset of RUNTIME_ASSETS) {
558
+ const cands = candidatesFor(asset.name, opts);
559
+ const hit = cands.find((p) => existsSync(p));
560
+ if (!hit) {
561
+ missing.push({ name: asset.name, tried: cands });
562
+ continue;
563
+ }
564
+ out.push({ ...asset, localPath: hit });
565
+ }
566
+ if (missing.length > 0) {
567
+ const lines = missing.flatMap((m) => [` - ${m.name}: tried`, ...m.tried.map((p) => ` ${p}`)]);
568
+ throw new Error(
569
+ `vercel: could not resolve runtime assets needed to bake the base snapshot:
570
+ ` + lines.join("\n") + `
571
+
572
+ If running from the monorepo, ensure \`pnpm -w build\` has run so packages/ctl/dist/bin.cjs exists.`
573
+ );
574
+ }
575
+ return out;
576
+ }
577
+ function guessRepoRoot() {
578
+ let cur = SELF;
579
+ for (let i = 0; i < 8; i++) {
580
+ if (existsSync(resolve(cur, "pnpm-workspace.yaml"))) return cur;
581
+ const parent = dirname(cur);
582
+ if (parent === cur) break;
583
+ cur = parent;
584
+ }
585
+ return SELF;
586
+ }
587
+ var BUILDER_TIMEOUT_MS = 25 * 6e4;
588
+ var SHELL = "/bin/bash";
589
+ async function prepareVercel(opts = {}) {
590
+ await ensureVercelCredentials();
591
+ await ensureFreshCredentials();
592
+ const creds2 = resolveCredentials();
593
+ const log = opts.onLog ?? (() => {
594
+ });
595
+ const progress = (s) => log(`prepare-vercel: ${s}`);
596
+ const assets = resolveRuntimeAssets({
597
+ cliRuntimeRoot: opts.cliRuntimeRoot ?? findStagedCliRuntimeRoot(),
598
+ repoRoot: opts.repoRoot
599
+ });
600
+ const contextSha = await computeContextSha256(
601
+ assets.map((a) => ({ rel: a.name, abs: a.localPath }))
602
+ );
603
+ const existing = readPreparedState();
604
+ if (!opts.force && existing.base) {
605
+ const stillThere = await snapshotExists(existing.base.snapshotId, creds2);
606
+ if (stillThere && existing.base.contextSha256 === contextSha) {
607
+ progress(
608
+ `base snapshot ${existing.base.snapshotId} already exists (fingerprint ${contextSha.slice(0, 12)} matches); skipping (pass --force to rebuild)`
609
+ );
610
+ return { snapshotName: existing.base.snapshotId };
611
+ }
612
+ if (!stillThere) {
613
+ progress(`recorded base snapshot ${existing.base.snapshotId} is gone on Vercel; rebuilding`);
614
+ } else {
615
+ progress(
616
+ `build context changed (was ${existing.base.contextSha256?.slice(0, 12) ?? "<none>"}, now ${contextSha.slice(0, 12)}); rebuilding`
617
+ );
618
+ }
619
+ }
620
+ progress(`creating builder sandbox (node24, ${String(opts.vcpus ?? 4)} vcpus)`);
621
+ const sb = await Sandbox.create({
622
+ runtime: "node24",
623
+ resources: { vcpus: opts.vcpus ?? 4 },
624
+ timeout: BUILDER_TIMEOUT_MS,
625
+ tags: { agentbox: "true", "agentbox.role": "prepare" },
626
+ persistent: false,
627
+ ...creds2
628
+ });
629
+ progress(`builder sandbox ${sb.name} up`);
630
+ progress(`uploading ${String(assets.length)} runtime asset(s)`);
631
+ await sb.writeFiles(
632
+ await Promise.all(
633
+ assets.map(async (a) => ({
634
+ path: a.remotePath,
635
+ content: await readFile2(a.localPath),
636
+ mode: a.remoteMode
637
+ }))
638
+ )
639
+ );
640
+ progress("running provision.sh (this takes a few minutes)");
641
+ const install = await sb.runCommand({
642
+ cmd: SHELL,
643
+ args: ["-lc", "bash /tmp/agentbox-provision.sh 2>&1"],
644
+ sudo: true,
645
+ stdout: lineSink((l) => log(`[provision] ${l}`)),
646
+ stderr: lineSink((l) => log(`[provision] ${l}`))
647
+ });
648
+ if (install.exitCode !== 0) {
649
+ throw new Error(`provision.sh failed on the builder sandbox (exit ${String(install.exitCode)})`);
650
+ }
651
+ progress("provision.sh complete");
652
+ await stageAgentConfig(sb, opts.hostWorkspace, log);
653
+ progress("creating base snapshot (expiration: never)");
654
+ const snap = await sb.snapshot({ expiration: 0 });
655
+ progress(`snapshot created: ${snap.snapshotId}`);
656
+ const cliStamp = readCliStamp();
657
+ writePreparedState({
658
+ schema: 1,
659
+ base: {
660
+ snapshotId: snap.snapshotId,
661
+ contextSha256: contextSha,
662
+ cliVersion: cliStamp.cliVersion,
663
+ cliCommit: cliStamp.cliCommit,
664
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
665
+ }
666
+ });
667
+ progress(`wrote ${preparedStatePath()}`);
668
+ progress("deleting builder sandbox");
669
+ try {
670
+ await sb.delete();
671
+ progress("builder sandbox deleted");
672
+ } catch (err) {
673
+ progress(
674
+ `builder delete failed (left for Vercel reaper): ${err instanceof Error ? err.message : String(err)}`
675
+ );
676
+ }
677
+ progress(`prepare complete \u2014 base snapshot ${snap.snapshotId}`);
678
+ return { snapshotName: snap.snapshotId };
679
+ }
680
+ async function snapshotExists(snapshotId, creds2) {
681
+ try {
682
+ const snap = await Snapshot.get({ snapshotId, ...creds2 });
683
+ return snap.status === "created";
684
+ } catch {
685
+ return false;
686
+ }
687
+ }
688
+ async function stageAgentConfig(sb, hostWorkspace, log) {
689
+ const progress = (s) => log(`prepare-vercel: ${s}`);
690
+ progress("staging host agent static config");
691
+ const stagings = [];
692
+ try {
693
+ const claudeTar = await stageClaudeStaticForUpload({ hostWorkspace });
694
+ for (const w of claudeTar.warnings) progress(w);
695
+ if (claudeTar.tarballPath) stagings.push({ kind: "claude", tar: claudeTar, dest: "/home/vscode/.claude" });
696
+ else await claudeTar.cleanup();
697
+ const codexTar = await stageCodexStaticForUpload();
698
+ for (const w of codexTar.warnings) progress(w);
699
+ if (codexTar.tarballPath) stagings.push({ kind: "codex", tar: codexTar, dest: "/home/vscode/.codex" });
700
+ else await codexTar.cleanup();
701
+ const opencodeTar = await stageOpencodeStaticForUpload();
702
+ for (const w of opencodeTar.warnings) progress(w);
703
+ if (opencodeTar.tarballPath) stagings.push({ kind: "opencode", tar: opencodeTar, dest: "/home/vscode/.local/share/opencode" });
704
+ else await opencodeTar.cleanup();
705
+ for (const s of stagings) {
706
+ const remote = `/tmp/agentbox-${s.kind}-static.tar.gz`;
707
+ progress(`uploading ${s.kind} static config`);
708
+ await sb.writeFiles([{ path: remote, content: await readFile2(s.tar.tarballPath) }]);
709
+ const extract = `sudo -u vscode mkdir -p ${s.dest} && sudo -u vscode tar -xzf ${remote} -C ${s.dest} --no-same-permissions --no-same-owner -m && rm -f ${remote}`;
710
+ const r = await sb.runCommand({ cmd: SHELL, args: ["-lc", extract], sudo: true });
711
+ if (r.exitCode !== 0) {
712
+ progress(`WARN: ${s.kind} static extract failed (exit ${String(r.exitCode)}) \u2014 continuing`);
713
+ } else {
714
+ progress(`baked ${s.kind} static config into snapshot`);
715
+ }
716
+ }
717
+ } finally {
718
+ for (const s of stagings) await s.tar.cleanup();
719
+ }
720
+ }
721
+ function lineSink(onLine) {
722
+ let buf = "";
723
+ return new Writable({
724
+ write(chunk, _enc, cb) {
725
+ buf += chunk.toString("utf8");
726
+ let nl;
727
+ while ((nl = buf.indexOf("\n")) !== -1) {
728
+ onLine(buf.slice(0, nl));
729
+ buf = buf.slice(nl + 1);
730
+ }
731
+ cb();
732
+ },
733
+ final(cb) {
734
+ if (buf.length > 0) onLine(buf);
735
+ cb();
736
+ }
737
+ });
738
+ }
739
+ var prepareVercelProvider = (req) => prepareVercel({
740
+ name: req.name,
741
+ hostWorkspace: req.hostWorkspace ?? process.cwd(),
742
+ force: req.force,
743
+ onLog: req.onLog
744
+ });
745
+ async function buildVercelAttach(box, kind, opts) {
746
+ const sandboxId = box.cloud?.sandboxId;
747
+ if (!sandboxId) {
748
+ throw new Error(`vercel box ${box.name} has no sandboxId \u2014 record is malformed`);
749
+ }
750
+ const det = await detectSbx();
751
+ if (!det.installed || !det.bin) {
752
+ throw new Error(
753
+ "Vercel interactive attach needs the Vercel `sandbox` CLI \u2014 run `agentbox vercel login` (it installs it) or `npm install -g sandbox`."
754
+ );
755
+ }
756
+ await ensureFreshCredentials();
757
+ const { token, teamId, projectId } = resolveCredentials();
758
+ const interactive = (kind === "shell" || kind === "agent") && !opts?.detached;
759
+ const envPrelude = "export LANG=C.UTF-8 LC_ALL=C.UTF-8 TERM=xterm-256color; ";
760
+ const inner = envPrelude + renderInnerCommand(kind, opts);
761
+ const argv = [
762
+ det.bin,
763
+ "exec",
764
+ "--sudo",
765
+ ...interactive ? ["-i"] : [],
766
+ "--project",
767
+ projectId,
768
+ "--scope",
769
+ teamId,
770
+ sandboxId,
771
+ "--",
772
+ "sudo",
773
+ "-u",
774
+ "vscode",
775
+ "-H",
776
+ "bash",
777
+ "-lc",
778
+ inner
779
+ ];
780
+ return { argv, env: { VERCEL_AUTH_TOKEN: token } };
781
+ }
782
+ var BACKEND_NAME = "vercel";
783
+ var cloudProvider = createCloudProvider(vercelBackend, {
784
+ // Vercel couples RAM to vCPU at 2048 MB/vCPU; disk is a fixed 32 GB NVMe.
785
+ defaultResources: { cpu: 2, memory: 4, disk: 32 },
786
+ launchDockerd: false
787
+ });
788
+ var vercelCheckpoint = {
789
+ async create(box, name) {
790
+ if (!box.projectRoot) {
791
+ throw new Error(
792
+ "cloud checkpoint requires the box to have a project root (run `agentbox checkpoint` from inside the project)"
793
+ );
794
+ }
795
+ if (!box.cloud?.sandboxId) {
796
+ throw new Error(`vercel box ${box.name} has no sandboxId \u2014 record is malformed`);
797
+ }
798
+ const snapshotId = await snapshotVercelSandbox(box.cloud.sandboxId);
799
+ const info = await writeCloudCheckpointManifest(box.projectRoot, BACKEND_NAME, name, {
800
+ snapshotName: snapshotId,
801
+ sourceBoxId: box.id,
802
+ sourceBoxName: box.name
803
+ });
804
+ return { ref: info.name };
805
+ },
806
+ async list(projectRoot) {
807
+ const entries = await listCloudCheckpoints(projectRoot, BACKEND_NAME);
808
+ return entries.map((e) => ({ ref: e.name, createdAt: e.manifest.createdAt }));
809
+ },
810
+ async remove(projectRoot, ref) {
811
+ const entry = await resolveCloudCheckpoint(projectRoot, BACKEND_NAME, ref);
812
+ if (!entry) return;
813
+ try {
814
+ await deleteVercelSnapshot(entry.manifest.snapshotName);
815
+ } catch {
816
+ }
817
+ await removeCloudCheckpointDir(projectRoot, BACKEND_NAME, ref);
818
+ }
819
+ };
820
+ var vercelProvider = {
821
+ ...cloudProvider,
822
+ prepare: prepareVercelProvider,
823
+ buildAttach: buildVercelAttach,
824
+ checkpoint: vercelCheckpoint
825
+ };
826
+ export {
827
+ DEFAULT_BOX_IMAGE_REF,
828
+ RUNTIME_ASSETS,
829
+ buildVercelAttach,
830
+ candidatesFor,
831
+ ensureVercelBaseSnapshot,
832
+ ensureVercelCredentials,
833
+ ensureVercelEnvLoaded,
834
+ findStagedCliRuntimeRoot,
835
+ maskKey,
836
+ prepareVercel,
837
+ prepareVercelProvider,
838
+ preparedStatePath,
839
+ readPreparedState,
840
+ readVercelCredStatus,
841
+ reloadVercelEnv,
842
+ resolveRuntimeAssets,
843
+ secretsPath,
844
+ updatePreparedState,
845
+ vercelBackend,
846
+ vercelProvider,
847
+ writePreparedState
848
+ };
849
+ //# sourceMappingURL=dist-XML54CNB.js.map