@madarco/agentbox 0.13.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +125 -0
- package/README.md +11 -8
- package/dist/{_cloud-attach-HJC672UR.js → _cloud-attach-R6TRWG5L.js} +4 -4
- package/dist/{chunk-QYRK5H6Q.js → chunk-43Q5GWP6.js} +108 -56
- package/dist/chunk-43Q5GWP6.js.map +1 -0
- package/dist/{chunk-ECLLV5JH.js → chunk-72CJTXN6.js} +156 -5
- package/dist/chunk-72CJTXN6.js.map +1 -0
- package/dist/{chunk-R5XIDQFR.js → chunk-BKU34KYY.js} +170 -6
- package/dist/chunk-BKU34KYY.js.map +1 -0
- package/dist/{chunk-4NQXNQ53.js → chunk-E7CHS7ZR.js} +168 -58
- package/dist/chunk-E7CHS7ZR.js.map +1 -0
- package/dist/chunk-MCOU6CZS.js +346 -0
- package/dist/chunk-MCOU6CZS.js.map +1 -0
- package/dist/{chunk-B4QG2MCW.js → chunk-MLMFNN4T.js} +762 -483
- package/dist/chunk-MLMFNN4T.js.map +1 -0
- package/dist/{chunk-2LF5YILI.js → chunk-RSKG7AFU.js} +80 -6
- package/dist/chunk-RSKG7AFU.js.map +1 -0
- package/dist/{chunk-SNTHHWKY.js → chunk-XKH7NTT7.js} +80 -22
- package/dist/chunk-XKH7NTT7.js.map +1 -0
- package/dist/{dist-7KVUIKJX.js → dist-AGTIA7AD.js} +37 -226
- package/dist/dist-AGTIA7AD.js.map +1 -0
- package/dist/{dist-OPIBZ7XM.js → dist-FIFEFKJ7.js} +14 -69
- package/dist/dist-FIFEFKJ7.js.map +1 -0
- package/dist/dist-JZ3XO6EB.js +662 -0
- package/dist/dist-JZ3XO6EB.js.map +1 -0
- package/dist/{dist-OG6NW6SM.js → dist-OGJGZETZ.js} +5 -3
- package/dist/{dist-JAN5VABY.js → dist-S4XR4ACV.js} +25 -177
- package/dist/dist-S4XR4ACV.js.map +1 -0
- package/dist/index.js +2229 -1314
- package/dist/index.js.map +1 -1
- package/dist/{prepared-state-MQHD3M5F-KE4DT3GX.js → prepared-state-MQHD3M5F-Q27AZU53.js} +2 -2
- package/package.json +6 -4
- package/runtime/docker/Dockerfile.box +21 -26
- package/runtime/docker/apps/cli/share/agentbox-setup/SKILL.md +67 -1
- package/runtime/docker/packages/ctl/dist/bin.cjs +361 -43
- package/runtime/docker/packages/sandbox-docker/scripts/agentbox-vnc-start +17 -6
- package/runtime/docker/packages/sandbox-docker/scripts/chromium-resolver +57 -0
- package/runtime/docker/packages/sandbox-docker/scripts/claude-managed-settings.json +2 -1
- package/runtime/e2b/agentbox-checkpoint-cleanup +52 -0
- package/runtime/e2b/agentbox-codex-hooks.json +68 -0
- package/runtime/e2b/agentbox-open +28 -0
- package/runtime/e2b/agentbox-setup-skill.md +263 -0
- package/runtime/e2b/agentbox-vnc-start +102 -0
- package/runtime/e2b/attach-helper.cjs +167 -0
- package/runtime/e2b/claude-managed-settings.json +116 -0
- package/runtime/e2b/ctl.cjs +24158 -0
- package/runtime/e2b/custom-system-CLAUDE.md +46 -0
- package/runtime/e2b/gh-shim +344 -0
- package/runtime/e2b/git-shim +131 -0
- package/runtime/e2b/scripts/build-template.sh +295 -0
- package/runtime/hetzner/agentbox-setup-skill.md +67 -1
- package/runtime/hetzner/agentbox-vnc-start +17 -6
- package/runtime/hetzner/claude-managed-settings.json +2 -1
- package/runtime/hetzner/ctl.cjs +361 -43
- package/runtime/relay/bin.cjs +380 -233
- package/runtime/vercel/agentbox-setup-skill.md +67 -1
- package/runtime/vercel/agentbox-vnc-start +17 -6
- package/runtime/vercel/claude-managed-settings.json +2 -1
- package/runtime/vercel/ctl.cjs +361 -43
- package/share/agentbox-setup/SKILL.md +67 -1
- package/share/host-skills/agentbox-info/SKILL.md +47 -35
- package/dist/chunk-2LF5YILI.js.map +0 -1
- package/dist/chunk-4NQXNQ53.js.map +0 -1
- package/dist/chunk-B4QG2MCW.js.map +0 -1
- package/dist/chunk-ECLLV5JH.js.map +0 -1
- package/dist/chunk-QYRK5H6Q.js.map +0 -1
- package/dist/chunk-R5XIDQFR.js.map +0 -1
- package/dist/chunk-SNTHHWKY.js.map +0 -1
- package/dist/dist-7KVUIKJX.js.map +0 -1
- package/dist/dist-JAN5VABY.js.map +0 -1
- package/dist/dist-OPIBZ7XM.js.map +0 -1
- /package/dist/{_cloud-attach-HJC672UR.js.map → _cloud-attach-R6TRWG5L.js.map} +0 -0
- /package/dist/{dist-OG6NW6SM.js.map → dist-OGJGZETZ.js.map} +0 -0
- /package/dist/{prepared-state-MQHD3M5F-KE4DT3GX.js.map → prepared-state-MQHD3M5F-Q27AZU53.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../packages/sandbox-e2b/src/index.ts","../../../packages/sandbox-e2b/src/backend.ts","../../../packages/sandbox-e2b/src/retry.ts","../../../packages/sandbox-e2b/src/prepare.ts","../../../packages/sandbox-e2b/src/build-attach.ts"],"sourcesContent":["/**\n * The E2B sandbox provider. A thin `CloudBackend` over the `e2b` v2 SDK,\n * composed via `@agentbox/sandbox-cloud`'s `createCloudProvider` for\n * everything provider-agnostic (workspace seeding, ctl launch, state, relay\n * polling).\n *\n * Three capabilities are overridden on top of the cloud scaffold:\n * - `prepare` — bake the custom base template via Template.build\n * (`agentbox prepare --provider e2b`).\n * - `buildAttach` — SDK-streaming PTY bridge (E2B has no SSH).\n * - `checkpoint` — store the E2B snapshot id (template id) in the manifest\n * so restore boots from it (`Sandbox.createSnapshot` produces an\n * id-addressed reusable snapshot, same shape as Vercel).\n *\n * `launchDockerd: false` because E2B microVMs can't run nested containers.\n */\n\nimport type { BoxRecord, Provider, ProviderCheckpoint } from '@agentbox/core';\nimport {\n createCloudProvider,\n currentCloudBaseFingerprint,\n listCloudCheckpoints,\n removeCloudCheckpointDir,\n resolveCloudCheckpoint,\n writeCloudCheckpointManifest,\n} from '@agentbox/sandbox-cloud';\nimport { readCliStamp, recordBox } from '@agentbox/sandbox-core';\nimport { e2bBackend, DEFAULT_BOX_IMAGE_REF } from './backend.js';\nimport { Sandbox, resolveApiKey } from './sdk.js';\nimport { withE2bRetry } from './retry.js';\nimport { prepareE2bProvider } from './prepare.js';\nimport { buildE2bAttach } from './build-attach.js';\nimport { currentE2bBaseFingerprintLive } from './prepared-state.js';\n\nconst BACKEND_NAME = 'e2b';\n\nconst cloudProvider = createCloudProvider(e2bBackend, {\n // E2B applies resources at the template level (Template.build({ cpuCount,\n // memoryMB }) — `prepare` sets these). The numbers below are advisory\n // metadata for BoxRecord stats / the dashboard pane; per-create overrides\n // aren't honored by the SDK.\n defaultResources: { cpu: 2, memory: 4, disk: 8 },\n launchDockerd: false,\n});\n\n/**\n * Create a reusable, named E2B snapshot from a running sandbox.\n * `Sandbox.createSnapshot` pauses the source while capturing, then returns a\n * persistent `snapshotId` (template id form: `name:tag` or `template-id:tag`)\n * usable with `Sandbox.create({ template })` — see SDK docs.\n */\nasync function createE2bSnapshot(sandboxId: string, name: string): Promise<string> {\n const apiKey = resolveApiKey();\n return withE2bRetry(\n { method: 'createSnapshot', retryOnAmbiguous: false, attemptTimeoutMs: 900_000, backoffMs: [] },\n async () => {\n const info = await Sandbox.createSnapshot(sandboxId, { apiKey, name });\n return info.snapshotId;\n },\n );\n}\n\n/** Delete a snapshot by id. Idempotent — a missing snapshot is success. */\nasync function deleteE2bSnapshot(snapshotId: string): Promise<void> {\n const apiKey = resolveApiKey();\n await withE2bRetry({ method: 'deleteSnapshot', retryOnAmbiguous: true }, async () => {\n try {\n await Sandbox.deleteSnapshot(snapshotId, { apiKey });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n if (/not.?found|404/i.test(msg)) return; // idempotent\n throw err;\n }\n });\n}\n\n/**\n * Build a safe, unique E2B snapshot name. E2B names are global within a team\n * (`createSnapshot({ name })` reuses an existing name if it exists, growing\n * the build set). We stamp a per-create timestamp so each checkpoint gets its\n * own name → its own template id, never overwriting an earlier checkpoint.\n */\nfunction snapshotName(boxName: string, checkpointName: string): string {\n // E2B template names accept lower-case alnum + dashes/dots; coerce.\n const sanitize = (s: string): string =>\n s.toLowerCase().replace(/[^a-z0-9.-]+/g, '-').replace(/^-+|-+$/g, '');\n const ts = new Date().toISOString().replace(/[:.]/g, '-').replace('T', '_').replace('Z', '');\n return `agentbox-${sanitize(boxName)}-${sanitize(checkpointName)}-${sanitize(ts)}`;\n}\n\n/**\n * E2B-specific checkpoint capability. Unlike the scaffold's default (which\n * stores a caller-chosen snapshot *name*), we capture the SDK-returned\n * opaque snapshot id and store THAT in the manifest's `snapshotName` field —\n * the cloud create flow passes `manifest.snapshotName` straight to\n * `provision({ snapshot })`, and the E2B backend boots from it as a template\n * id. (Same id-addressed shape as Vercel's checkpoint capability.)\n */\nconst e2bCheckpoint: ProviderCheckpoint = {\n async create(box: BoxRecord, name: string) {\n if (!box.projectRoot) {\n throw new Error(\n 'cloud checkpoint requires the box to have a project root (run `agentbox checkpoint` from inside the project)',\n );\n }\n if (!box.cloud?.sandboxId) {\n throw new Error(`e2b box ${box.name} has no sandboxId — record is malformed`);\n }\n // NOTE: createSnapshot pauses the source sandbox; agentbox-ctl-checkpoint\n // resumes it lazily on the next op (Sandbox.connect auto-resumes).\n const e2bSnapName = snapshotName(box.name, name);\n const snapshotId = await createE2bSnapshot(box.cloud.sandboxId, e2bSnapName);\n // The box is now paused — persist it so the fast `agentbox list` path\n // doesn't show a stale `running` after a checkpoint. Best-effort.\n try {\n await recordBox({ ...box, cloud: { ...box.cloud, lastState: 'paused' } });\n } catch {\n // not worth failing the checkpoint over a state-record write\n }\n const info = await writeCloudCheckpointManifest(box.projectRoot, BACKEND_NAME, name, {\n snapshotName: snapshotId,\n sourceBoxId: box.id,\n sourceBoxName: box.name,\n baseProvider: BACKEND_NAME,\n baseFingerprint: currentCloudBaseFingerprint(BACKEND_NAME),\n cliVersion: readCliStamp().cliVersion,\n });\n return { ref: info.name };\n },\n async list(projectRoot: string) {\n const entries = await listCloudCheckpoints(projectRoot, BACKEND_NAME);\n return entries.map((e) => ({ ref: e.name, createdAt: e.manifest.createdAt }));\n },\n async remove(projectRoot: string, ref: string) {\n const entry = await resolveCloudCheckpoint(projectRoot, BACKEND_NAME, ref);\n if (!entry) return;\n try {\n await deleteE2bSnapshot(entry.manifest.snapshotName);\n } catch {\n // best-effort: drop the local manifest even if the remote delete failed\n // (network/perms/already-gone) so the user isn't left with a dead pointer.\n }\n await removeCloudCheckpointDir(projectRoot, BACKEND_NAME, ref);\n },\n};\n\nexport const e2bProvider: Provider = {\n ...cloudProvider,\n prepare: prepareE2bProvider,\n buildAttach: buildE2bAttach,\n checkpoint: e2bCheckpoint,\n baseFingerprint: () => currentE2bBaseFingerprintLive(),\n};\n\nexport { e2bBackend, DEFAULT_BOX_IMAGE_REF };\nexport { ensureE2bEnvLoaded, reloadE2bEnv } from './env-loader.js';\nexport {\n ensureE2bCredentials,\n readE2bCredStatus,\n secretsPath,\n maskKey,\n type EnsureE2bCredentialsOptions,\n type E2bCredStatus,\n} from './credentials.js';\nexport {\n RUNTIME_ASSETS,\n candidatesFor,\n resolveRuntimeAssets,\n findStagedCliRuntimeRoot,\n type RuntimeAsset,\n type ResolvedAsset,\n} from './runtime-assets.js';\nexport {\n prepareE2b,\n prepareE2bProvider,\n type PrepareE2bOptions,\n type PrepareE2bResult,\n} from './prepare.js';\nexport {\n currentE2bBaseFingerprintLive,\n ensureE2bBaseTemplate,\n preparedStatePath,\n readPreparedState,\n writePreparedState,\n updatePreparedState,\n type PreparedE2bState,\n type PreparedE2bBase,\n} from './prepared-state.js';\nexport { buildE2bAttach } from './build-attach.js';\n","/**\n * E2B `CloudBackend` — maps the provider-neutral cloud primitives onto the\n * `e2b` v2 SDK (Firecracker microVMs + pause/resume persistence). Composed\n * into a full `Provider` by `@agentbox/sandbox-cloud`'s `createCloudProvider`.\n *\n * Platform shape this backend is built around:\n * - Boxes boot from the prepared base template baked by `agentbox prepare\n * --provider e2b` (Template.build → custom Debian image with agentbox-ctl,\n * the vscode user, /workspace, claude/codex/opencode, tmux, Chromium).\n * `backend.provision` gates on `ensureE2bBaseTemplate()` (mirrors the\n * hetzner/vercel pattern: `prepare` itself sidesteps the gate so a cold\n * install can bootstrap). A snapshot ref (cloud checkpoint) wins over\n * the prepared base.\n * - No nested containers (Firecracker microVM); the provider sets\n * `launchDockerd: false`.\n * - Preview URLs (`{port}-{sandboxId}.{E2B_DOMAIN}`) are public HTTPS by\n * default (allowPublicTraffic=true); no header token needed. We construct\n * the URL string locally so `previewUrl` doesn't have to `Sandbox.connect`\n * (which would auto-resume a paused box).\n * - `Sandbox.getInfo` is a NON-resuming static API; `state()`/`get()` use it\n * to check existence cheaply without waking a paused sandbox. Auto-resume\n * happens only inside `Sandbox.connect` (used by ops that need a live\n * handle: exec, file ops, pause, destroy).\n * - `Sandbox.pause` is the canonical pause API (`betaPause` is deprecated).\n * - `Sandbox.createSnapshot` is the reusable-snapshot primitive; the\n * provider overrides the whole `checkpoint` capability in index.ts to\n * store the resulting snapshot id (matching vercel's id-addressed shape).\n * - No SSH — the provider overrides `buildAttach` with an SDK-streaming\n * PTY bridge (`buildE2bAttach`); the legacy `attachArgv` slot stays\n * unset.\n */\n\nimport { readFile } from 'node:fs/promises';\nimport type {\n CloudBackend,\n CloudExecOptions,\n CloudExecResult,\n CloudFileEntry,\n CloudHandle,\n CloudPreviewUrl,\n CloudProvisionRequest,\n CloudSandboxSummary,\n CloudState,\n} from '@agentbox/core';\nimport type { SandboxInfo, SandboxState } from './sdk.js';\nimport { Sandbox, Template, resolveApiKey } from './sdk.js';\nimport { withE2bRetry } from './retry.js';\nimport { ensureE2bBaseTemplate, readPreparedState } from './prepared-state.js';\n\n/**\n * Sentinel image ref the cloud-provider hands us when no --image was passed.\n * Mirrors docker's convention; the actual template id is read from the\n * prepared-state file by `provision`.\n */\nexport const DEFAULT_BOX_IMAGE_REF = 'agentbox/box:dev';\n\n/** Box user agentbox standardizes on (matches docker/vercel — created by build-template.sh). */\nconst BOX_USER = 'vscode';\nconst BOX_OWNER = 'vscode:vscode';\n\n/** Default E2B preview hostname. Override via the SDK's `E2B_DOMAIN` env. */\nconst DEFAULT_E2B_DOMAIN = 'e2b.app';\n\n/**\n * Per-box session timeout the SDK enforces. Past it, E2B auto-terminates the\n * sandbox; we explicitly extend via `sb.setTimeout` is not needed for Task 1's\n * smoke (boxes survive minutes, not hours). 45 min default mirrors vercel.\n */\nconst DEFAULT_TIMEOUT_MS = 45 * 60_000;\n\nconst E2B_WEB_PORT = 8080;\n\n/** Single-quote a string for safe embedding inside a `bash -lc '<…>'`. */\nfunction shq(s: string): string {\n return \"'\" + s.replace(/'/g, \"'\\\\''\") + \"'\";\n}\n\n/**\n * Convert a Node `Buffer` to a plain `ArrayBuffer` because E2B's `files.write`\n * `data:` field is `string | ArrayBuffer | Blob | ReadableStream` — Buffer is a\n * `Uint8Array` subclass and doesn't satisfy that union at the type level (even\n * though it works at runtime). Copy rather than slice the underlying buffer:\n * Buffers may share an underlying ArrayBuffer with a pooled allocator, so\n * `data.buffer` of a small Buffer can be a megabyte-long shared region.\n */\nfunction bufferToArrayBuffer(b: Buffer): ArrayBuffer {\n const ab = new ArrayBuffer(b.byteLength);\n new Uint8Array(ab).set(b);\n return ab;\n}\n\n/**\n * Map the SDK's nullable string state onto our 4-value `CloudState`.\n * E2B reports 'running' | 'paused' (per SDK types). Anything else (or absent)\n * → 'missing' so callers ping-pong the lifecycle into a clean state.\n */\nfunction mapState(s: SandboxState | undefined): CloudState {\n switch (s) {\n case 'running':\n return 'running';\n case 'paused':\n return 'paused';\n default:\n return 'missing';\n }\n}\n\n/** True when the error means \"sandbox doesn't exist\" (404). */\nfunction isNotFound(err: unknown): boolean {\n if (!err || typeof err !== 'object') return false;\n const name = err instanceof Error ? err.name : '';\n if (name === 'SandboxNotFoundError' || name === 'NotFoundError') return true;\n const status = (err as { statusCode?: unknown; status?: unknown }).statusCode ?? (err as { status?: unknown }).status;\n return status === 404;\n}\n\n/**\n * Sanitize a box name for use as the `metadata.name` value. E2B accepts\n * arbitrary strings (probed) but we strip control chars defensively so a name\n * with embedded newlines can't break log parsing or response shapes.\n */\nfunction safeMetadataName(name: string): string {\n return name.replace(/[\\u0000-\\u001f]/g, '').slice(0, 200);\n}\n\nexport const e2bBackend: CloudBackend = {\n name: 'e2b',\n\n // The cloud scaffold's WebProxy binds whatever port we expose here, and\n // `agentbox url --kind=web` resolves via `getHost(port)`. 8080 matches the\n // non-privileged convention vercel uses — `getHost` accepts any port, but\n // staying on 8080 keeps the in-box ctl flag (AGENTBOX_WEB_PROXY_PORT)\n // identical across cloud providers.\n webProxyPort: E2B_WEB_PORT,\n\n async provision(req: CloudProvisionRequest): Promise<CloudHandle> {\n const apiKey = resolveApiKey();\n const log = req.onLog ?? (() => {});\n // Resolve the template to boot from: an explicit cloud-checkpoint snapshot\n // (req.snapshot) wins, else the prepared base template id. We don't fall\n // back to E2B's stock `base` template — every box must have the agentbox\n // runtime baked in. The gate throws an actionable \"run `agentbox prepare`\"\n // error when no template is recorded yet (mirrors the hetzner/vercel\n // pattern: `prepare` itself sidesteps the gate by calling `prepareE2b`\n // directly, never `provision`).\n if (req.snapshot === undefined) {\n ensureE2bBaseTemplate();\n }\n const template = req.snapshot ?? readPreparedState().base?.templateId;\n if (!template) {\n throw new Error(\n 'e2b provision: no template available — `agentbox prepare --provider e2b` must run first',\n );\n }\n\n // No-retry: Sandbox.create is billable and non-idempotent — a timeout\n // after the request reached the origin could leave a duplicate sandbox we\n // can't reference for cleanup.\n const sb = await withE2bRetry(\n { method: 'provision', retryOnAmbiguous: false, attemptTimeoutMs: 300_000, backoffMs: [] },\n async () =>\n Sandbox.create({\n apiKey,\n template,\n // Friendly name (so prune can see it) + the 'agentbox' marker so\n // `list()` can filter out sandboxes provisioned by other tooling.\n metadata: { agentbox: 'true', 'agentbox.name': safeMetadataName(req.name), name: safeMetadataName(req.name) },\n envs: req.env,\n timeoutMs: req.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n }),\n );\n log(`e2b: created sandbox ${sb.sandboxId} (template ${template})`);\n return { sandboxId: sb.sandboxId };\n },\n\n async get(sandboxId: string): Promise<CloudHandle | null> {\n const apiKey = resolveApiKey();\n return withE2bRetry({ method: 'get', retryOnAmbiguous: true }, async () => {\n try {\n // Static, NON-resuming — won't wake a paused sandbox just to confirm\n // it exists (per orchestrator review #1: connect would auto-resume).\n await Sandbox.getInfo(sandboxId, { apiKey });\n return { sandboxId };\n } catch (err) {\n if (isNotFound(err)) return null;\n throw err;\n }\n });\n },\n\n async list(): Promise<CloudSandboxSummary[]> {\n const apiKey = resolveApiKey();\n return withE2bRetry({ method: 'list', retryOnAmbiguous: true }, async () => {\n const summaries: CloudSandboxSummary[] = [];\n // Default query returns both running and paused sandboxes. We filter\n // client-side to the ones we created (metadata.agentbox === 'true').\n for (const state of ['running', 'paused'] as const) {\n const paginator = Sandbox.list({ apiKey, query: { state: [state] } });\n while (paginator.hasNext) {\n const page = await paginator.nextItems();\n for (const info of page) {\n if (info.metadata?.['agentbox'] !== 'true') continue;\n const friendly =\n info.metadata?.['agentbox.name'] ?? info.metadata?.['name'];\n const summary: CloudSandboxSummary = { sandboxId: info.sandboxId, state };\n if (friendly) summary.name = friendly;\n const startedAt = info.startedAt;\n if (startedAt instanceof Date) summary.createdAt = startedAt.toISOString();\n summaries.push(summary);\n }\n }\n }\n return summaries;\n });\n },\n\n // E2B has no separate stop primitive — sandboxes are either running or\n // paused. start is therefore a connect-and-resume (auto-resume inside\n // Sandbox.connect handles a paused box transparently).\n async start(h: CloudHandle): Promise<void> {\n const apiKey = resolveApiKey();\n await withE2bRetry(\n { method: 'start', retryOnAmbiguous: true, attemptTimeoutMs: 120_000 },\n async () => {\n await Sandbox.connect(h.sandboxId, { apiKey });\n },\n );\n },\n\n // stop ≡ pause on E2B (the pause IS the cold-storage state).\n async stop(h: CloudHandle): Promise<void> {\n await this.pause(h);\n },\n\n async pause(h: CloudHandle): Promise<void> {\n const apiKey = resolveApiKey();\n await withE2bRetry(\n { method: 'pause', retryOnAmbiguous: true, attemptTimeoutMs: 120_000 },\n async () => {\n await Sandbox.pause(h.sandboxId, { apiKey });\n },\n );\n },\n\n async resume(h: CloudHandle): Promise<void> {\n await this.start(h);\n },\n\n async destroy(h: CloudHandle): Promise<void> {\n const apiKey = resolveApiKey();\n await withE2bRetry(\n { method: 'destroy', retryOnAmbiguous: true, attemptTimeoutMs: 120_000 },\n async () => {\n try {\n await Sandbox.kill(h.sandboxId, { apiKey });\n } catch (err) {\n if (isNotFound(err)) return; // idempotent\n throw err;\n }\n },\n );\n },\n\n async state(h: CloudHandle): Promise<CloudState> {\n const apiKey = resolveApiKey();\n return withE2bRetry({ method: 'state', retryOnAmbiguous: true }, async () => {\n try {\n const info: SandboxInfo = await Sandbox.getInfo(h.sandboxId, { apiKey });\n return mapState(info.state);\n } catch (err) {\n if (isNotFound(err)) return 'missing';\n throw err;\n }\n });\n },\n\n async exec(h: CloudHandle, cmd: string, opts?: CloudExecOptions): Promise<CloudExecResult> {\n const apiKey = resolveApiKey();\n // Default per-attempt cap is 5 min — covers the cloud scaffold's\n // workspace-seed/carry extracts (tar of thousands of files, chown -R).\n // Callers can shorten with opts.attemptTimeoutMs for snappier probes.\n const timeoutMs = opts?.attemptTimeoutMs ?? 300_000;\n return withE2bRetry(\n {\n method: 'exec',\n retryOnAmbiguous: opts?.noRetry ? false : true,\n attemptTimeoutMs: timeoutMs,\n backoffMs: opts?.noRetry ? [] : undefined,\n },\n async () => {\n // Connect for the live handle — auto-resumes a paused box, which is\n // the correct semantics for exec (caller wants the command to run).\n const sb = await Sandbox.connect(h.sandboxId, { apiKey });\n // E2B's `commands.run` accepts only 'root' | 'user' | 'vscode'…; any\n // unix username we create in the fixup is valid. Pass through.\n const user = (opts?.user ?? BOX_USER) as 'root' | 'user';\n try {\n const r = await sb.commands.run(cmd, {\n ...(opts?.cwd !== undefined ? { cwd: opts.cwd } : {}),\n ...(opts?.env !== undefined ? { envs: opts.env } : {}),\n user,\n timeoutMs,\n });\n return { exitCode: r.exitCode, stdout: r.stdout ?? '', stderr: r.stderr ?? '' };\n } catch (err) {\n // commands.run throws on non-zero exit; the CommandResult fields\n // (exitCode/stdout/stderr) hang off the error. Map back into our\n // CloudExecResult so callers see exit=1, not a thrown exception\n // (vercel/daytona/hetzner exec contract returns the result).\n if (err instanceof Error && err.name === 'CommandExitError') {\n const ce = err as unknown as {\n exitCode: number;\n stdout: string;\n stderr: string;\n };\n return { exitCode: ce.exitCode, stdout: ce.stdout ?? '', stderr: ce.stderr ?? '' };\n }\n throw err;\n }\n },\n );\n },\n\n async uploadFile(h: CloudHandle, localPath: string, remotePath: string): Promise<void> {\n const apiKey = resolveApiKey();\n await withE2bRetry(\n { method: 'uploadFile', retryOnAmbiguous: true, attemptTimeoutMs: 300_000 },\n async () => {\n const data = await readFile(localPath);\n const sb = await Sandbox.connect(h.sandboxId, { apiKey });\n await sb.files.write([{ path: remotePath, data: bufferToArrayBuffer(data) }]);\n // files.write writes as the default user; chown to vscode so reads\n // from the scaffold's `sudo -u vscode …` exec calls succeed. Best-\n // effort — a chown failure on a world-readable file is harmless.\n try {\n await sb.commands.run(`sudo -n chown ${BOX_OWNER} ${shq(remotePath)}`, {\n user: 'root',\n timeoutMs: 10_000,\n });\n } catch {\n // ignore — file is at least present and readable\n }\n },\n );\n },\n\n async downloadFile(h: CloudHandle, remotePath: string, localPath: string): Promise<void> {\n const apiKey = resolveApiKey();\n await withE2bRetry(\n { method: 'downloadFile', retryOnAmbiguous: true, attemptTimeoutMs: 300_000 },\n async () => {\n const sb = await Sandbox.connect(h.sandboxId, { apiKey });\n const bytes = await sb.files.read(remotePath, { format: 'bytes' });\n const { writeFile } = await import('node:fs/promises');\n await writeFile(localPath, Buffer.from(bytes));\n },\n );\n },\n\n async listFiles(h: CloudHandle, remoteDir: string): Promise<CloudFileEntry[]> {\n const apiKey = resolveApiKey();\n return withE2bRetry({ method: 'listFiles', retryOnAmbiguous: true }, async () => {\n const sb = await Sandbox.connect(h.sandboxId, { apiKey });\n const entries = await sb.files.list(remoteDir);\n return entries.map((e) => ({ name: e.name, isDir: e.type === 'dir' }));\n });\n },\n\n async previewUrl(h: CloudHandle, port: number): Promise<CloudPreviewUrl> {\n // E2B's `sandbox.getHost(port)` is just string interpolation of\n // `${port}-${sandboxId}.${sandboxDomain}` — calling it via Sandbox.connect\n // would auto-resume a paused box (the SDK's documented behavior). The\n // domain defaults to `e2b.app` with `E2B_DOMAIN` as the override (matches\n // the SDK's `ConnectionConfig` default), so we construct the URL locally\n // and never wake the box for a UI/dashboard URL fetch.\n const domain = process.env.E2B_DOMAIN ?? DEFAULT_E2B_DOMAIN;\n return { url: `https://${String(port)}-${h.sandboxId}.${domain}`, token: undefined };\n },\n\n // Fewer params than the interface's (h, port, expiresInSeconds) is fine —\n // E2B preview URLs are already public + browser-usable; no per-URL TTL.\n async signedPreviewUrl(h: CloudHandle, port: number): Promise<CloudPreviewUrl> {\n return this.previewUrl(h, port);\n },\n\n /**\n * Probe whether a snapshot (i.e. a template id) is still bootable. E2B's\n * snapshot ids look like `template-id:tag` or `team-slug/name:tag` — both\n * accepted by `Template.exists(name)`. Returns false on any lookup failure\n * (treated by the cloud-provider as \"gone\" so it falls back to a from-base\n * boot rather than 410ing the user).\n */\n async snapshotExists(snapshotName: string): Promise<boolean> {\n const apiKey = resolveApiKey();\n return withE2bRetry({ method: 'snapshotExists', retryOnAmbiguous: true }, async () => {\n try {\n return await Template.exists(snapshotName, { apiKey });\n } catch {\n return false;\n }\n });\n },\n};\n","/**\n * Bounded retry wrapper for E2B SDK calls — mirrors `withVercelRetry` /\n * `withHetznerRetry` in shape and intent. The E2B API rate-limits (429) and\n * can return transient 5xx during incidents; without bounded retries those\n * propagate as wedges in the calling lifecycle code.\n *\n * Non-idempotent ops (`provision`/`Sandbox.create`) pass `retryOnAmbiguous:\n * false` so a timeout after the request reached the origin doesn't create a\n * duplicate billable sandbox.\n */\n\nexport interface WithRetryOptions {\n method: string;\n /** Per-attempt timeout (ms). Default 30_000. */\n attemptTimeoutMs?: number;\n /** Backoff before attempts 2, 3, … (ms). Default [1000, 2000, 4000]. */\n backoffMs?: readonly number[];\n /**\n * Retry on errors where we can't be sure the server applied the request\n * (connection failures, per-attempt timeouts, 5xx). Set false for\n * non-idempotent operations where a retry could create a duplicate resource.\n */\n retryOnAmbiguous: boolean;\n /** Override the default stderr retry sink (used by tests). */\n onRetry?: (line: string) => void;\n}\n\nconst DEFAULT_BACKOFF: readonly number[] = [1000, 2000, 4000];\nconst DEFAULT_ATTEMPT_TIMEOUT_MS = 30_000;\n\nclass AttemptTimeoutError extends Error {\n constructor(method: string, ms: number) {\n super(`e2b ${method}: per-attempt timeout after ${String(ms)}ms`);\n this.name = 'AttemptTimeoutError';\n }\n}\n\nexport function isAttemptTimeout(err: unknown): err is AttemptTimeoutError {\n return err instanceof AttemptTimeoutError;\n}\n\n/** HTTP status code dug out of whatever error shape the SDK throws. */\nfunction statusCodeOf(err: unknown): number | undefined {\n if (!err || typeof err !== 'object') return undefined;\n for (const key of ['statusCode', 'status', 'code'] as const) {\n const v = (err as Record<string, unknown>)[key];\n if (typeof v === 'number') return v;\n }\n const resp = (err as { response?: { status?: unknown } }).response;\n if (resp && typeof resp.status === 'number') return resp.status;\n return undefined;\n}\n\nexport function isRetriable(err: unknown, allowAmbiguous: boolean): boolean {\n if (err instanceof AttemptTimeoutError) return allowAmbiguous;\n\n // The SDK exposes a dedicated `SandboxNotFoundError` and `RateLimitError`.\n // Match by error name to avoid an import cycle (sdk.ts → retry → sdk).\n const name = err instanceof Error ? err.name : undefined;\n if (name === 'RateLimitError') return true;\n if (name === 'SandboxNotFoundError') return false;\n\n const status = statusCodeOf(err);\n if (status !== undefined) {\n if (status === 429) return true;\n if (status >= 500 && status <= 599) return allowAmbiguous;\n return false;\n }\n\n // Raw fetch / undici errors. Node wraps low-level errors in `{ cause }`.\n if (err && typeof err === 'object') {\n const candidates: unknown[] = [err, (err as { cause?: unknown }).cause];\n for (const c of candidates) {\n if (!c || typeof c !== 'object') continue;\n const code = (c as { code?: unknown }).code;\n if (\n code === 'ECONNRESET' ||\n code === 'ETIMEDOUT' ||\n code === 'ECONNABORTED' ||\n code === 'EAI_AGAIN' ||\n code === 'ECONNREFUSED' ||\n code === 'ENOTFOUND' ||\n code === 'UND_ERR_SOCKET' ||\n code === 'UND_ERR_CONNECT_TIMEOUT'\n ) {\n return allowAmbiguous;\n }\n }\n }\n return false;\n}\n\nexport async function withE2bRetry<T>(opts: WithRetryOptions, fn: () => Promise<T>): Promise<T> {\n const backoff = opts.backoffMs ?? DEFAULT_BACKOFF;\n const maxAttempts = backoff.length + 1;\n const timeoutMs = opts.attemptTimeoutMs ?? DEFAULT_ATTEMPT_TIMEOUT_MS;\n const log = opts.onRetry ?? defaultRetryLog;\n\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n return await raceTimeout(fn(), timeoutMs, opts.method);\n } catch (err) {\n const last = attempt === maxAttempts;\n if (last || !isRetriable(err, opts.retryOnAmbiguous)) throw err;\n const delay = backoff[attempt - 1] ?? backoff[backoff.length - 1] ?? 4000;\n log(\n `e2b ${opts.method}: attempt ${String(attempt)} failed (${errorSummary(err)}); retrying in ${String(delay)}ms`,\n );\n await sleep(delay);\n }\n }\n throw new Error(`withE2bRetry: exhausted attempts for ${opts.method}`);\n}\n\nfunction defaultRetryLog(line: string): void {\n process.stderr.write(`\\n[e2b-retry] ${line}\\n`);\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n\nasync function raceTimeout<T>(p: Promise<T>, ms: number, method: string): Promise<T> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n return await Promise.race([\n p,\n new Promise<never>((_resolve, reject) => {\n timer = setTimeout(() => reject(new AttemptTimeoutError(method, ms)), ms);\n }),\n ]);\n } finally {\n if (timer !== undefined) clearTimeout(timer);\n }\n}\n\nfunction errorSummary(err: unknown): string {\n if (err instanceof Error) {\n const status = statusCodeOf(err);\n return status !== undefined\n ? `${err.name}(${String(status)}): ${truncate(err.message)}`\n : `${err.name}: ${truncate(err.message)}`;\n }\n return truncate(String(err));\n}\n\nfunction truncate(s: string, max = 160): string {\n return s.length > max ? `${s.slice(0, max)}…` : s;\n}\n","/**\n * `agentbox prepare --provider e2b` — bake the E2B base template.\n *\n * Unlike Vercel/Hetzner, E2B can build templates from a build DSL (the SDK's\n * `Template` + `Template.build`). We mirror Vercel's `prepare` shape but drive\n * the build through the SDK builder API instead of booting a sandbox + running\n * `provision.sh`:\n *\n * 1. Resolve runtime assets + fingerprint the build context. Skip-fast when\n * an up-to-date template id is already recorded.\n * 2. Stage every resolved asset under a temp `fileContextPath` directory\n * with predictable relative names (E2B's `template.copy(src, dest)`\n * requires sources to be RELATIVE paths inside the context dir).\n * 3. `Template({ fileContextPath })` → `.fromBaseImage()` (E2B's default\n * Debian 12 + node 20 + git + sudo). `.copy(rel, dest)` for each asset,\n * `.runCmd('bash /tmp/agentbox-build-template.sh', { user: 'root' })`,\n * `.setReadyCmd('test -x /usr/local/bin/agentbox-ctl')`.\n * 4. `Template.build(t, 'agentbox-base:<tag>', { cpuCount, memoryMB,\n * onBuildLogs })` streams logs into the spinner; returns the BuildInfo\n * with the template id.\n * 5. Persist `{ schema:1, base: { templateId, contextSha256, cliVersion,\n * cliCommit, createdAt } }` to ~/.agentbox/e2b-prepared.json.\n *\n * Templates on E2B are reusable named resources addressed by id+tag. Re-running\n * with the same name reuses the existing template id (E2B's documented\n * behavior). Unlike Vercel snapshots there's no per-box eviction concern; one\n * template is reused for every create.\n *\n * vCPU / RAM are template-level on E2B — set them here so per-box `create`\n * doesn't try to override them (which E2B rejects).\n */\n\nimport { copyFile, mkdir, mkdtemp, rm } from 'node:fs/promises';\nimport { tmpdir } from 'node:os';\nimport { dirname, join, resolve } from 'node:path';\nimport type { Provider } from '@agentbox/core';\nimport { computeContextSha256, readCliStamp } from '@agentbox/sandbox-core';\nimport { ensureE2bCredentials } from './credentials.js';\nimport { resolveApiKey, Template } from './sdk.js';\nimport {\n preparedStatePath,\n readPreparedState,\n writePreparedState,\n} from './prepared-state.js';\nimport {\n findStagedCliRuntimeRoot,\n resolveRuntimeAssets,\n type ResolvedAsset,\n} from './runtime-assets.js';\n\nexport interface PrepareE2bOptions {\n name?: string;\n hostWorkspace?: string;\n /** Force re-bake even when an up-to-date template id is recorded. */\n force?: boolean;\n /** vCPUs for the baked template (default 2). E2B applies this per-sandbox at boot. */\n cpuCount?: number;\n /** Memory in MiB for the baked template (default 4096). */\n memoryMB?: number;\n /** CLI runtime tree (set by the CLI to its dist neighbor). */\n cliRuntimeRoot?: string;\n /** Repo root for the dev fallback (defaults to a cwd-walk). */\n repoRoot?: string;\n onLog?: (line: string) => void;\n}\n\nexport interface PrepareE2bResult {\n snapshotName?: string;\n}\n\n/** Template name agentbox bakes under. E2B treats `name:tag` as a single addressable build. */\nconst TEMPLATE_NAME = 'agentbox-base:latest';\nconst DEFAULT_TAG = 'latest';\n\nconst DEFAULT_CPU = 2;\nconst DEFAULT_MEMORY_MB = 4096;\n\nexport async function prepareE2b(\n opts: PrepareE2bOptions = {},\n): Promise<PrepareE2bResult> {\n await ensureE2bCredentials();\n const apiKey = resolveApiKey();\n const log = opts.onLog ?? (() => {});\n const progress = (s: string) => log(`prepare-e2b: ${s}`);\n\n const assets = resolveRuntimeAssets({\n cliRuntimeRoot: opts.cliRuntimeRoot ?? findStagedCliRuntimeRoot(),\n repoRoot: opts.repoRoot,\n });\n const contextSha = await computeContextSha256(\n assets.map((a) => ({ rel: a.name, abs: a.localPath })),\n );\n\n // Skip-fast: existing template + matching fingerprint.\n //\n // Probe the persisted templateId itself, not TEMPLATE_NAME. If someone\n // (or another bake) rebuilt the alias under a different id, the name still\n // resolves but the stored id is stale and `Sandbox.create({ template: <stale id> })`\n // 404s. `Template.exists` accepts both `name:tag` and `template-id:tag`\n // forms, so we pass the exact id we'd later hand to `provision`.\n const existing = readPreparedState();\n if (!opts.force && existing.base) {\n if (existing.base.contextSha256 === contextSha) {\n const stillThere = await templateExists(existing.base.templateId, apiKey);\n if (stillThere) {\n progress(\n `template ${existing.base.templateId} already exists (fingerprint ${contextSha.slice(0, 12)} matches); skipping (pass --force to rebuild)`,\n );\n return { snapshotName: existing.base.templateId };\n }\n progress(`recorded template ${existing.base.templateId} is gone on E2B; rebuilding`);\n } else {\n progress(\n `build context changed (was ${existing.base.contextSha256?.slice(0, 12) ?? '<none>'}, now ${contextSha.slice(0, 12)}); rebuilding`,\n );\n }\n }\n\n // E2B's `template.copy(src, dest)` requires `src` to be a RELATIVE path\n // inside the Template's `fileContextPath`. Stage every resolved asset into\n // a temp dir under its logical name (asset.name) so the copy chain reads\n // from a single context root.\n const contextDir = await mkdtemp(join(tmpdir(), 'agentbox-e2b-build-'));\n try {\n progress(`staging build context at ${contextDir}`);\n await stageAssetsInto(contextDir, assets);\n\n // Build the Template via the SDK builder. fromBaseImage() starts from E2B's\n // own `e2bdev/base` (Debian 12 + node 20 + git + sudo), which halves the\n // install time vs starting from a vanilla Debian image.\n progress('assembling template build (fromBaseImage + asset copy + runCmd)');\n const template = Template({ fileContextPath: contextDir }).fromBaseImage();\n for (const a of assets) {\n progress(` copy ${a.name} -> ${a.remotePath}`);\n template.copy(a.name, a.remotePath, {\n forceUpload: true,\n mode: a.remoteMode,\n user: 'root',\n });\n }\n template.runCmd('bash /tmp/agentbox-build-template.sh 2>&1', { user: 'root' });\n // setReadyCmd flips the builder into TemplateFinal — required for build().\n // The check passes once the script's last `install` step lands the ctl bundle.\n const finalTemplate = template.setReadyCmd(\n 'test -x /usr/local/bin/agentbox-ctl',\n );\n\n const cpuCount = opts.cpuCount ?? DEFAULT_CPU;\n const memoryMB = opts.memoryMB ?? DEFAULT_MEMORY_MB;\n progress(\n `running Template.build('${TEMPLATE_NAME}', { cpuCount: ${String(cpuCount)}, memoryMB: ${String(memoryMB)} })`,\n );\n const info = await Template.build(finalTemplate, TEMPLATE_NAME, {\n apiKey,\n cpuCount,\n memoryMB,\n onBuildLogs: (entry: LogEntryLike) => {\n // LogEntry exposes timestamp / level / message; stream the human form.\n log(`[build] ${formatBuildLog(entry)}`);\n },\n });\n progress(`template built: id=${info.templateId} build=${info.buildId} name=${info.name}`);\n\n // Persist. `Sandbox.create({ template })` auto-appends `:default` when no\n // tag is given (and 404s if that tag wasn't built), so we MUST store the\n // tagged form. `info.templateId` is just the raw id with no tag; use the\n // first tag we built with (`latest`) or fall back to `info.tags[0]`.\n const tag = info.tags?.[0] ?? DEFAULT_TAG;\n const cliStamp = readCliStamp();\n const taggedId = `${info.templateId}:${tag}`;\n writePreparedState({\n schema: 1,\n base: {\n templateId: taggedId,\n // info.name is the full `name:tag` pair Template.build() was called\n // with (e.g. `agentbox-base:latest`). Earlier code re-appended `:${tag}`\n // and produced `agentbox-base:latest:latest` in the status display.\n templateName: info.name,\n contextSha256: contextSha,\n cliVersion: cliStamp.cliVersion,\n cliCommit: cliStamp.cliCommit,\n createdAt: new Date().toISOString(),\n },\n });\n progress(`wrote ${preparedStatePath()}`);\n\n progress(`prepare complete — base template ${taggedId}`);\n return { snapshotName: taggedId };\n } finally {\n await rm(contextDir, { recursive: true, force: true }).catch(() => {\n // best-effort: temp dir cleanup failures are noise, not errors.\n });\n }\n}\n\n/**\n * Copy every asset into `contextDir` under its logical `name`. Preserves the\n * source mode on the copy (E2B's `template.copy` also accepts a `mode`\n * override, but the on-disk mode keeps the local stage representative).\n */\nasync function stageAssetsInto(\n contextDir: string,\n assets: ResolvedAsset[],\n): Promise<void> {\n for (const a of assets) {\n const dest = resolve(contextDir, a.name);\n await mkdir(dirname(dest), { recursive: true });\n await copyFile(a.localPath, dest);\n }\n}\n\n/**\n * Check if a named template is bootable on E2B. Returns true on a 'ready'\n * build, false on anything else (deleted, errored, never built). Used by the\n * skip-fast path to detect a template that was deleted out-of-band.\n */\nasync function templateExists(name: string, apiKey: string): Promise<boolean> {\n try {\n return await Template.exists(name, { apiKey });\n } catch {\n return false;\n }\n}\n\n/**\n * E2B's `LogEntry` shape (timestamp, level, message). We treat the SDK's\n * type loosely here so the line-stream doesn't bind us to internal class\n * shapes — only the `.toString()` plus `.message` are documented.\n */\ninterface LogEntryLike {\n message?: string;\n level?: string;\n timestamp?: Date;\n toString(): string;\n}\n\nfunction formatBuildLog(entry: LogEntryLike): string {\n // The SDK's LogEntry.toString() emits a `[level] timestamp message` form.\n // For the spinner we only want the message — and clip overly long lines.\n const raw = typeof entry.message === 'string' ? entry.message : entry.toString();\n const cleaned = raw.replace(/\\r?\\n+$/, '');\n return cleaned.length > 200 ? cleaned.slice(0, 200) + '…' : cleaned;\n}\n\n/** Provider-level binding used by the CLI's `prepare` command. */\nexport const prepareE2bProvider: NonNullable<Provider['prepare']> = (req) =>\n prepareE2b({\n name: req.name,\n hostWorkspace: req.hostWorkspace ?? process.cwd(),\n force: req.force,\n onLog: req.onLog,\n });\n","/**\n * `buildE2bAttach` — the E2B provider's override of `Provider.buildAttach`.\n *\n * E2B has no SSH and no public PTY CLI like Vercel's `sbx exec -i`. We ship\n * our own attach helper (`attach-helper.cjs`) that connects to the sandbox via\n * the SDK and bridges the host PTY to an in-box `sandbox.pty.create()`.\n *\n * Argv shape:\n * node <attach-helper.cjs> --sandbox-id <id> --user vscode\n *\n * The inner bash command (`renderInnerCommand` output: tmux ensure + attach)\n * is passed through the environment as `AGENTBOX_E2B_INNER_CMD` so quoting\n * stays sane and it doesn't leak through `ps`. `E2B_API_KEY` is passed through\n * the env for the same reason. `node-pty` (the host PTY wrapper) is what\n * spawns this argv, so stdin/stdout/SIGWINCH all reach the helper unchanged.\n */\n\nimport { existsSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport {\n type AttachKind,\n type AttachSpec,\n type BoxRecord,\n type BuildAttachOptions,\n} from '@agentbox/core';\nimport { renderInnerCommand } from '@agentbox/sandbox-cloud';\nimport { resolveApiKey } from './sdk.js';\n\nconst SELF = dirname(fileURLToPath(import.meta.url));\n\n/**\n * Resolve the absolute path to `attach-helper.cjs`. In the published CLI it\n * lives at `runtime/e2b/attach-helper.cjs` (next to the staged provider\n * runtime tree); in dev it lives next to the package's `dist/`.\n */\nexport function resolveAttachHelperPath(): string {\n const candidates = [\n // dev: dist/index.js sibling\n resolve(SELF, 'attach-helper.cjs'),\n // dev: src compiled to dist/, while index.ts is in src/\n resolve(SELF, '..', 'dist', 'attach-helper.cjs'),\n // staged CLI: apps/cli/runtime/e2b/attach-helper.cjs\n resolve(SELF, '..', 'runtime', 'e2b', 'attach-helper.cjs'),\n resolve(SELF, '..', '..', 'runtime', 'e2b', 'attach-helper.cjs'),\n ];\n for (const p of candidates) {\n if (existsSync(p)) return p;\n }\n // Last-resort: still return the first candidate so the error message points\n // somewhere informative.\n return candidates[0]!;\n}\n\nexport async function buildE2bAttach(\n box: BoxRecord,\n kind: AttachKind,\n opts?: BuildAttachOptions,\n): Promise<AttachSpec> {\n const sandboxId = box.cloud?.sandboxId;\n if (!sandboxId) {\n throw new Error(`e2b box ${box.name} has no sandboxId — record is malformed`);\n }\n\n const helper = resolveAttachHelperPath();\n if (!existsSync(helper)) {\n throw new Error(\n `e2b attach helper not found at ${helper} — rebuild the CLI (\\`pnpm -w build\\`) ` +\n 'so packages/sandbox-e2b/dist/attach-helper.cjs is generated.',\n );\n }\n\n const apiKey = resolveApiKey();\n const inner = renderInnerCommand(kind, opts);\n\n const argv = [\n process.execPath,\n helper,\n '--sandbox-id',\n sandboxId,\n '--user',\n 'vscode',\n ];\n\n return {\n argv,\n env: {\n E2B_API_KEY: apiKey,\n AGENTBOX_E2B_INNER_CMD: inner,\n },\n };\n}\n"],"mappings":"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","names":["dirname","resolve","snapshotName","dirname","resolve","readCliStamp"]}
|
|
@@ -194,6 +194,7 @@ import {
|
|
|
194
194
|
snapshotPathFor,
|
|
195
195
|
snapshotPresent,
|
|
196
196
|
stageClaudeCredentialsForUpload,
|
|
197
|
+
stageClaudeJsonOnlyForUpload,
|
|
197
198
|
stageClaudeStaticForUpload,
|
|
198
199
|
stageCodexCredentialsForUpload,
|
|
199
200
|
stageCodexStaticForUpload,
|
|
@@ -219,7 +220,7 @@ import {
|
|
|
219
220
|
vscodeServerVolumeName,
|
|
220
221
|
waitForTmuxPaneContent,
|
|
221
222
|
warmUpClaudeCredentials
|
|
222
|
-
} from "./chunk-
|
|
223
|
+
} from "./chunk-MLMFNN4T.js";
|
|
223
224
|
import {
|
|
224
225
|
BOX_IMAGE_REGISTRY,
|
|
225
226
|
DEFAULT_BOX_IMAGE,
|
|
@@ -247,7 +248,7 @@ import {
|
|
|
247
248
|
resolveContextFiles,
|
|
248
249
|
tagImage,
|
|
249
250
|
writePreparedDockerState
|
|
250
|
-
} from "./chunk-
|
|
251
|
+
} from "./chunk-XKH7NTT7.js";
|
|
251
252
|
import "./chunk-G3H2L3O2.js";
|
|
252
253
|
export {
|
|
253
254
|
AmbiguousBoxError,
|
|
@@ -468,6 +469,7 @@ export {
|
|
|
468
469
|
snapshotPathFor,
|
|
469
470
|
snapshotPresent,
|
|
470
471
|
stageClaudeCredentialsForUpload,
|
|
472
|
+
stageClaudeJsonOnlyForUpload,
|
|
471
473
|
stageClaudeStaticForUpload,
|
|
472
474
|
stageCodexCredentialsForUpload,
|
|
473
475
|
stageCodexStaticForUpload,
|
|
@@ -496,4 +498,4 @@ export {
|
|
|
496
498
|
warmUpClaudeCredentials,
|
|
497
499
|
writePreparedDockerState
|
|
498
500
|
};
|
|
499
|
-
//# sourceMappingURL=dist-
|
|
501
|
+
//# sourceMappingURL=dist-OGJGZETZ.js.map
|
|
@@ -1,50 +1,52 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
RUNTIME_ASSETS,
|
|
3
4
|
Sandbox,
|
|
4
5
|
Snapshot,
|
|
6
|
+
candidatesFor,
|
|
7
|
+
currentVercelBaseFingerprintLive,
|
|
5
8
|
detectSbx,
|
|
6
9
|
ensureFreshCredentials,
|
|
10
|
+
ensureVercelBaseSnapshot,
|
|
7
11
|
ensureVercelCredentials,
|
|
8
12
|
ensureVercelEnvLoaded,
|
|
13
|
+
findStagedCliRuntimeRoot,
|
|
9
14
|
maskKey,
|
|
15
|
+
preparedStatePath,
|
|
16
|
+
readPreparedState,
|
|
10
17
|
readVercelCredStatus,
|
|
11
18
|
reloadVercelEnv,
|
|
12
19
|
resolveCredentials,
|
|
13
|
-
|
|
14
|
-
|
|
20
|
+
resolveRuntimeAssets,
|
|
21
|
+
secretsPath,
|
|
22
|
+
updatePreparedState,
|
|
23
|
+
writePreparedState
|
|
24
|
+
} from "./chunk-72CJTXN6.js";
|
|
15
25
|
import {
|
|
16
26
|
createCloudProvider,
|
|
27
|
+
currentCloudBaseFingerprint,
|
|
17
28
|
listCloudCheckpoints,
|
|
18
29
|
removeCloudCheckpointDir,
|
|
19
30
|
renderInnerCommand,
|
|
20
31
|
resolveCloudCheckpoint,
|
|
21
32
|
writeCloudCheckpointManifest
|
|
22
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-E7CHS7ZR.js";
|
|
23
34
|
import {
|
|
24
|
-
stageClaudeCredentialsForUpload,
|
|
25
35
|
stageClaudeStaticForUpload,
|
|
26
|
-
stageCodexCredentialsForUpload,
|
|
27
36
|
stageCodexStaticForUpload,
|
|
28
|
-
stageOpencodeCredentialsForUpload,
|
|
29
37
|
stageOpencodeStaticForUpload
|
|
30
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-MLMFNN4T.js";
|
|
31
39
|
import {
|
|
32
40
|
computeContextSha256,
|
|
33
|
-
preparedStatePathFor,
|
|
34
41
|
readCliStamp,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
writePreparedStateRaw
|
|
38
|
-
} from "./chunk-SNTHHWKY.js";
|
|
42
|
+
recordBox
|
|
43
|
+
} from "./chunk-XKH7NTT7.js";
|
|
39
44
|
import "./chunk-G3H2L3O2.js";
|
|
40
45
|
|
|
41
46
|
// ../../packages/sandbox-vercel/dist/index.js
|
|
42
47
|
import { readFile } from "fs/promises";
|
|
43
48
|
import { readFile as readFile2 } from "fs/promises";
|
|
44
49
|
import { Writable } from "stream";
|
|
45
|
-
import { existsSync } from "fs";
|
|
46
|
-
import { dirname, resolve } from "path";
|
|
47
|
-
import { fileURLToPath } from "url";
|
|
48
50
|
var DEFAULT_BACKOFF = [1e3, 2e3, 4e3];
|
|
49
51
|
var DEFAULT_ATTEMPT_TIMEOUT_MS = 3e4;
|
|
50
52
|
var AttemptTimeoutError = class extends Error {
|
|
@@ -134,34 +136,6 @@ function errorSummary(err) {
|
|
|
134
136
|
function truncate(s, max = 160) {
|
|
135
137
|
return s.length > max ? `${s.slice(0, max)}\u2026` : s;
|
|
136
138
|
}
|
|
137
|
-
var SCHEMA = 1;
|
|
138
|
-
function preparedStatePath() {
|
|
139
|
-
return preparedStatePathFor("vercel");
|
|
140
|
-
}
|
|
141
|
-
function readPreparedState() {
|
|
142
|
-
const raw = readPreparedStateRaw("vercel");
|
|
143
|
-
if (raw === null || typeof raw !== "object") return { schema: SCHEMA };
|
|
144
|
-
const parsed = raw;
|
|
145
|
-
if (parsed.schema !== SCHEMA) {
|
|
146
|
-
return { schema: SCHEMA };
|
|
147
|
-
}
|
|
148
|
-
return { schema: SCHEMA, base: parsed.base };
|
|
149
|
-
}
|
|
150
|
-
function writePreparedState(state) {
|
|
151
|
-
writePreparedStateRaw("vercel", state);
|
|
152
|
-
}
|
|
153
|
-
function updatePreparedState(mutate) {
|
|
154
|
-
const s = readPreparedState();
|
|
155
|
-
mutate(s);
|
|
156
|
-
writePreparedState(s);
|
|
157
|
-
}
|
|
158
|
-
function ensureVercelBaseSnapshot() {
|
|
159
|
-
const state = readPreparedState();
|
|
160
|
-
if (state.base !== void 0) return;
|
|
161
|
-
throw new Error(
|
|
162
|
-
"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."
|
|
163
|
-
);
|
|
164
|
-
}
|
|
165
139
|
var DEFAULT_BOX_IMAGE_REF = "agentbox/box:dev";
|
|
166
140
|
var BOX_USER = "vscode";
|
|
167
141
|
var BOX_OWNER = "vscode:vscode";
|
|
@@ -240,34 +214,6 @@ function buildRunCommand(cmd, opts) {
|
|
|
240
214
|
sudo: true
|
|
241
215
|
};
|
|
242
216
|
}
|
|
243
|
-
async function pushVercelAgentCredentials(sb, log) {
|
|
244
|
-
const specs = [
|
|
245
|
-
{ kind: "claude", stage: stageClaudeCredentialsForUpload, dest: "/home/vscode/.agentbox-creds/claude" },
|
|
246
|
-
{ kind: "codex", stage: stageCodexCredentialsForUpload, dest: "/home/vscode/.agentbox-creds/codex" },
|
|
247
|
-
{ kind: "opencode", stage: stageOpencodeCredentialsForUpload, dest: "/home/vscode/.agentbox-creds/opencode" }
|
|
248
|
-
];
|
|
249
|
-
for (const spec of specs) {
|
|
250
|
-
const staged = await spec.stage();
|
|
251
|
-
for (const w of staged.warnings) log(`vercel: [${spec.kind}-creds] ${w}`);
|
|
252
|
-
try {
|
|
253
|
-
if (!staged.tarballPath) {
|
|
254
|
-
log(`vercel: ${spec.kind}: no host credentials to push (skipping)`);
|
|
255
|
-
continue;
|
|
256
|
-
}
|
|
257
|
-
const remote = `/tmp/agentbox-${spec.kind}-creds.tar.gz`;
|
|
258
|
-
await sb.writeFiles([{ path: remote, content: await readFile(staged.tarballPath) }]);
|
|
259
|
-
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}`;
|
|
260
|
-
const r = await sb.runCommand({ cmd: "bash", args: ["-lc", extract], sudo: true });
|
|
261
|
-
if (r.exitCode !== 0) {
|
|
262
|
-
log(`vercel: WARN \u2014 ${spec.kind} credential extract failed (exit ${String(r.exitCode)})`);
|
|
263
|
-
} else {
|
|
264
|
-
log(`vercel: ${spec.kind}: credentials pushed`);
|
|
265
|
-
}
|
|
266
|
-
} finally {
|
|
267
|
-
await staged.cleanup();
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
217
|
var vercelBackend = {
|
|
272
218
|
name: "vercel",
|
|
273
219
|
// Vercel rejects privileged ports (<1024) and can't add a routable port to a
|
|
@@ -284,8 +230,6 @@ var vercelBackend = {
|
|
|
284
230
|
);
|
|
285
231
|
}
|
|
286
232
|
const networkPolicy = parseNetworkPolicy(req.networkPolicy);
|
|
287
|
-
const log = req.onLog ?? (() => {
|
|
288
|
-
});
|
|
289
233
|
const handle = await withVercelRetry(
|
|
290
234
|
{ method: "provision", retryOnAmbiguous: false, attemptTimeoutMs: 9e5, backoffMs: [] },
|
|
291
235
|
async () => {
|
|
@@ -309,14 +253,6 @@ var vercelBackend = {
|
|
|
309
253
|
return { sandboxId: sb.name };
|
|
310
254
|
}
|
|
311
255
|
);
|
|
312
|
-
try {
|
|
313
|
-
const sb = await getSandbox(handle.sandboxId);
|
|
314
|
-
await pushVercelAgentCredentials(sb, log);
|
|
315
|
-
} catch (err) {
|
|
316
|
-
log(
|
|
317
|
-
`vercel: WARN \u2014 agent credential push failed (${err instanceof Error ? err.message : String(err)}); in-box claude/codex/opencode will prompt for interactive login`
|
|
318
|
-
);
|
|
319
|
-
}
|
|
320
256
|
return handle;
|
|
321
257
|
},
|
|
322
258
|
async get(sandboxId) {
|
|
@@ -512,99 +448,6 @@ async function deleteVercelSnapshot(snapshotId) {
|
|
|
512
448
|
}
|
|
513
449
|
});
|
|
514
450
|
}
|
|
515
|
-
var SELF = dirname(fileURLToPath(import.meta.url));
|
|
516
|
-
function findStagedCliRuntimeRoot() {
|
|
517
|
-
const candidates = [
|
|
518
|
-
resolve(SELF, "..", "runtime"),
|
|
519
|
-
resolve(SELF, "..", "..", "runtime")
|
|
520
|
-
];
|
|
521
|
-
for (const c of candidates) {
|
|
522
|
-
if (existsSync(resolve(c, "vercel", "scripts", "provision.sh"))) return c;
|
|
523
|
-
}
|
|
524
|
-
return void 0;
|
|
525
|
-
}
|
|
526
|
-
var RUNTIME_ASSETS = [
|
|
527
|
-
{ name: "provision.sh", remotePath: "/tmp/agentbox-provision.sh", remoteMode: 493 },
|
|
528
|
-
{ name: "agentbox-ctl", remotePath: "/tmp/agentbox-ctl", remoteMode: 493 },
|
|
529
|
-
{ name: "agentbox-vnc-start", remotePath: "/tmp/agentbox-vnc-start", remoteMode: 493 },
|
|
530
|
-
{ name: "agentbox-checkpoint-cleanup", remotePath: "/tmp/agentbox-checkpoint-cleanup", remoteMode: 493 },
|
|
531
|
-
{ name: "agentbox-open", remotePath: "/tmp/agentbox-open", remoteMode: 493 },
|
|
532
|
-
{ name: "gh-shim", remotePath: "/tmp/agentbox-gh-shim", remoteMode: 493 },
|
|
533
|
-
{ name: "git-shim", remotePath: "/tmp/agentbox-git-shim", remoteMode: 493 },
|
|
534
|
-
{ name: "custom-system-CLAUDE.md", remotePath: "/tmp/agentbox-custom-CLAUDE.md", remoteMode: 420 },
|
|
535
|
-
{ name: "claude-managed-settings.json", remotePath: "/tmp/agentbox-managed-settings.json", remoteMode: 420 },
|
|
536
|
-
{ name: "agentbox-codex-hooks.json", remotePath: "/tmp/agentbox-codex-hooks.json", remoteMode: 420 },
|
|
537
|
-
{ name: "agentbox-setup-skill.md", remotePath: "/tmp/agentbox-setup-skill.md", remoteMode: 420 }
|
|
538
|
-
];
|
|
539
|
-
function candidatesFor(name, opts = {}) {
|
|
540
|
-
const cliRoot = opts.cliRuntimeRoot;
|
|
541
|
-
const monorepo = opts.repoRoot ?? guessRepoRoot();
|
|
542
|
-
const monorepoRelative = {
|
|
543
|
-
"provision.sh": ["packages/sandbox-vercel/scripts/provision.sh"],
|
|
544
|
-
"agentbox-ctl": ["packages/ctl/dist/bin.cjs"],
|
|
545
|
-
"agentbox-vnc-start": ["packages/sandbox-docker/scripts/agentbox-vnc-start"],
|
|
546
|
-
"agentbox-checkpoint-cleanup": ["packages/sandbox-docker/scripts/agentbox-checkpoint-cleanup"],
|
|
547
|
-
"agentbox-open": ["packages/sandbox-docker/scripts/agentbox-open"],
|
|
548
|
-
"gh-shim": ["packages/sandbox-docker/scripts/gh-shim"],
|
|
549
|
-
"git-shim": ["packages/sandbox-docker/scripts/git-shim"],
|
|
550
|
-
"custom-system-CLAUDE.md": ["packages/sandbox-vercel/scripts/custom-system-CLAUDE.md"],
|
|
551
|
-
"claude-managed-settings.json": ["packages/sandbox-docker/scripts/claude-managed-settings.json"],
|
|
552
|
-
"agentbox-codex-hooks.json": ["packages/sandbox-docker/scripts/agentbox-codex-hooks.json"],
|
|
553
|
-
"agentbox-setup-skill.md": ["apps/cli/share/agentbox-setup/SKILL.md"]
|
|
554
|
-
};
|
|
555
|
-
const cliRelative = {
|
|
556
|
-
"provision.sh": ["vercel/scripts/provision.sh"],
|
|
557
|
-
"agentbox-ctl": ["vercel/ctl.cjs"],
|
|
558
|
-
"agentbox-vnc-start": ["vercel/agentbox-vnc-start", "docker/packages/sandbox-docker/scripts/agentbox-vnc-start"],
|
|
559
|
-
"agentbox-checkpoint-cleanup": ["vercel/agentbox-checkpoint-cleanup", "docker/packages/sandbox-docker/scripts/agentbox-checkpoint-cleanup"],
|
|
560
|
-
"agentbox-open": ["vercel/agentbox-open", "docker/packages/sandbox-docker/scripts/agentbox-open"],
|
|
561
|
-
"gh-shim": ["vercel/gh-shim", "docker/packages/sandbox-docker/scripts/gh-shim"],
|
|
562
|
-
"git-shim": ["vercel/git-shim", "docker/packages/sandbox-docker/scripts/git-shim"],
|
|
563
|
-
"custom-system-CLAUDE.md": ["vercel/custom-system-CLAUDE.md"],
|
|
564
|
-
"claude-managed-settings.json": ["vercel/claude-managed-settings.json", "docker/packages/sandbox-docker/scripts/claude-managed-settings.json"],
|
|
565
|
-
"agentbox-codex-hooks.json": ["vercel/agentbox-codex-hooks.json", "docker/packages/sandbox-docker/scripts/agentbox-codex-hooks.json"],
|
|
566
|
-
"agentbox-setup-skill.md": ["vercel/agentbox-setup-skill.md", "docker/apps/cli/share/agentbox-setup/SKILL.md"]
|
|
567
|
-
};
|
|
568
|
-
const out = [];
|
|
569
|
-
if (cliRoot) {
|
|
570
|
-
for (const rel of cliRelative[name] ?? []) out.push(resolve(cliRoot, rel));
|
|
571
|
-
}
|
|
572
|
-
for (const rel of monorepoRelative[name] ?? []) out.push(resolve(monorepo, rel));
|
|
573
|
-
return out;
|
|
574
|
-
}
|
|
575
|
-
function resolveRuntimeAssets(opts = {}) {
|
|
576
|
-
const out = [];
|
|
577
|
-
const missing = [];
|
|
578
|
-
for (const asset of RUNTIME_ASSETS) {
|
|
579
|
-
const cands = candidatesFor(asset.name, opts);
|
|
580
|
-
const hit = cands.find((p) => existsSync(p));
|
|
581
|
-
if (!hit) {
|
|
582
|
-
missing.push({ name: asset.name, tried: cands });
|
|
583
|
-
continue;
|
|
584
|
-
}
|
|
585
|
-
out.push({ ...asset, localPath: hit });
|
|
586
|
-
}
|
|
587
|
-
if (missing.length > 0) {
|
|
588
|
-
const lines = missing.flatMap((m) => [` - ${m.name}: tried`, ...m.tried.map((p) => ` ${p}`)]);
|
|
589
|
-
throw new Error(
|
|
590
|
-
`vercel: could not resolve runtime assets needed to bake the base snapshot:
|
|
591
|
-
` + lines.join("\n") + `
|
|
592
|
-
|
|
593
|
-
If running from the monorepo, ensure \`pnpm -w build\` has run so packages/ctl/dist/bin.cjs exists.`
|
|
594
|
-
);
|
|
595
|
-
}
|
|
596
|
-
return out;
|
|
597
|
-
}
|
|
598
|
-
function guessRepoRoot() {
|
|
599
|
-
let cur = SELF;
|
|
600
|
-
for (let i = 0; i < 8; i++) {
|
|
601
|
-
if (existsSync(resolve(cur, "pnpm-workspace.yaml"))) return cur;
|
|
602
|
-
const parent = dirname(cur);
|
|
603
|
-
if (parent === cur) break;
|
|
604
|
-
cur = parent;
|
|
605
|
-
}
|
|
606
|
-
return SELF;
|
|
607
|
-
}
|
|
608
451
|
var BUILDER_TIMEOUT_MS = 25 * 6e4;
|
|
609
452
|
var SHELL = "/bin/bash";
|
|
610
453
|
async function prepareVercel(opts = {}) {
|
|
@@ -824,7 +667,10 @@ var vercelCheckpoint = {
|
|
|
824
667
|
const info = await writeCloudCheckpointManifest(box.projectRoot, BACKEND_NAME, name, {
|
|
825
668
|
snapshotName: snapshotId,
|
|
826
669
|
sourceBoxId: box.id,
|
|
827
|
-
sourceBoxName: box.name
|
|
670
|
+
sourceBoxName: box.name,
|
|
671
|
+
baseProvider: BACKEND_NAME,
|
|
672
|
+
baseFingerprint: currentCloudBaseFingerprint(BACKEND_NAME),
|
|
673
|
+
cliVersion: readCliStamp().cliVersion
|
|
828
674
|
});
|
|
829
675
|
return { ref: info.name };
|
|
830
676
|
},
|
|
@@ -846,13 +692,15 @@ var vercelProvider = {
|
|
|
846
692
|
...cloudProvider,
|
|
847
693
|
prepare: prepareVercelProvider,
|
|
848
694
|
buildAttach: buildVercelAttach,
|
|
849
|
-
checkpoint: vercelCheckpoint
|
|
695
|
+
checkpoint: vercelCheckpoint,
|
|
696
|
+
baseFingerprint: () => currentVercelBaseFingerprintLive()
|
|
850
697
|
};
|
|
851
698
|
export {
|
|
852
699
|
DEFAULT_BOX_IMAGE_REF,
|
|
853
700
|
RUNTIME_ASSETS,
|
|
854
701
|
buildVercelAttach,
|
|
855
702
|
candidatesFor,
|
|
703
|
+
currentVercelBaseFingerprintLive,
|
|
856
704
|
ensureVercelBaseSnapshot,
|
|
857
705
|
ensureVercelCredentials,
|
|
858
706
|
ensureVercelEnvLoaded,
|
|
@@ -871,4 +719,4 @@ export {
|
|
|
871
719
|
vercelProvider,
|
|
872
720
|
writePreparedState
|
|
873
721
|
};
|
|
874
|
-
//# sourceMappingURL=dist-
|
|
722
|
+
//# sourceMappingURL=dist-S4XR4ACV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../packages/sandbox-vercel/src/index.ts","../../../packages/sandbox-vercel/src/backend.ts","../../../packages/sandbox-vercel/src/retry.ts","../../../packages/sandbox-vercel/src/prepare.ts","../../../packages/sandbox-vercel/src/build-attach.ts"],"sourcesContent":["/**\n * The Vercel Sandbox provider. A thin `CloudBackend` over `@vercel/sandbox`,\n * composed via `@agentbox/sandbox-cloud`'s `createCloudProvider` for everything\n * provider-agnostic (workspace seeding, ctl/VNC launch, state, relay polling).\n *\n * Three capabilities are overridden on top of the cloud scaffold:\n * - `prepare` — bake the base snapshot (Vercel can't build from a Dockerfile).\n * - `buildAttach` — SDK-streaming tmux bridge (Vercel has no SSH).\n * - `checkpoint` — store the Vercel snapshot *id* in the manifest so restore\n * boots from it (Vercel snapshots are id-addressed, not name-addressed).\n *\n * `launchDockerd: false` because Vercel Sandbox can't run nested containers.\n */\n\nimport type { BoxRecord, Provider, ProviderCheckpoint } from '@agentbox/core';\nimport {\n createCloudProvider,\n currentCloudBaseFingerprint,\n listCloudCheckpoints,\n removeCloudCheckpointDir,\n resolveCloudCheckpoint,\n writeCloudCheckpointManifest,\n} from '@agentbox/sandbox-cloud';\nimport {\n vercelBackend,\n snapshotVercelSandbox,\n deleteVercelSnapshot,\n DEFAULT_BOX_IMAGE_REF,\n} from './backend.js';\nimport { readCliStamp, recordBox } from '@agentbox/sandbox-core';\nimport { prepareVercelProvider } from './prepare.js';\nimport { buildVercelAttach } from './build-attach.js';\nimport { currentVercelBaseFingerprintLive } from './prepared-state.js';\n\nconst BACKEND_NAME = 'vercel';\n\nconst cloudProvider = createCloudProvider(vercelBackend, {\n // Vercel couples RAM to vCPU at 2048 MB/vCPU; disk is a fixed 32 GB NVMe.\n defaultResources: { cpu: 2, memory: 4, disk: 32 },\n launchDockerd: false,\n});\n\n/**\n * Vercel-specific checkpoint capability. Unlike the scaffold's default (which\n * stores a caller-chosen snapshot *name*), we capture the opaque Vercel\n * snapshot id and store THAT in the manifest's `snapshotName` field — the cloud\n * create flow passes `manifest.snapshotName` straight to\n * `provision({ snapshot })`, and the Vercel backend boots from it as a snapshot\n * id. (The scaffold's `cloudSnapshotName` project-scoping isn't needed — Vercel\n * snapshot ids are already globally unique.)\n */\nconst vercelCheckpoint: ProviderCheckpoint = {\n async create(box: BoxRecord, name: string) {\n if (!box.projectRoot) {\n throw new Error(\n 'cloud checkpoint requires the box to have a project root (run `agentbox checkpoint` from inside the project)',\n );\n }\n if (!box.cloud?.sandboxId) {\n throw new Error(`vercel box ${box.name} has no sandboxId — record is malformed`);\n }\n // NOTE: snapshotting stops the source sandbox; persistent mode resumes it\n // on the next call. Surfaced to the user in `agentbox checkpoint` docs.\n const snapshotId = await snapshotVercelSandbox(box.cloud.sandboxId);\n // The box is now stopped — persist it so the fast `agentbox list` path\n // doesn't show a stale `running` after a checkpoint. Best-effort.\n try {\n await recordBox({ ...box, cloud: { ...box.cloud, lastState: 'paused' } });\n } catch {\n // not worth failing the checkpoint over a state-record write\n }\n const info = await writeCloudCheckpointManifest(box.projectRoot, BACKEND_NAME, name, {\n snapshotName: snapshotId,\n sourceBoxId: box.id,\n sourceBoxName: box.name,\n baseProvider: BACKEND_NAME,\n baseFingerprint: currentCloudBaseFingerprint(BACKEND_NAME),\n cliVersion: readCliStamp().cliVersion,\n });\n return { ref: info.name };\n },\n async list(projectRoot: string) {\n const entries = await listCloudCheckpoints(projectRoot, BACKEND_NAME);\n return entries.map((e) => ({ ref: e.name, createdAt: e.manifest.createdAt }));\n },\n async remove(projectRoot: string, ref: string) {\n const entry = await resolveCloudCheckpoint(projectRoot, BACKEND_NAME, ref);\n if (!entry) return;\n try {\n await deleteVercelSnapshot(entry.manifest.snapshotName);\n } catch {\n // best-effort: drop the local manifest even if the remote delete failed\n // (network/perms/already-gone) so the user isn't left with a dead pointer.\n }\n await removeCloudCheckpointDir(projectRoot, BACKEND_NAME, ref);\n },\n};\n\nexport const vercelProvider: Provider = {\n ...cloudProvider,\n prepare: prepareVercelProvider,\n buildAttach: buildVercelAttach,\n checkpoint: vercelCheckpoint,\n baseFingerprint: () => currentVercelBaseFingerprintLive(),\n};\n\nexport { vercelBackend, DEFAULT_BOX_IMAGE_REF };\nexport { ensureVercelEnvLoaded, reloadVercelEnv } from './env-loader.js';\nexport { ensureVercelCredentials } from './credentials.js';\nexport type { EnsureVercelCredentialsOptions } from './credentials.js';\nexport {\n readVercelCredStatus,\n secretsPath,\n maskKey,\n type VercelCredStatus,\n} from './credentials.js';\nexport {\n prepareVercel,\n prepareVercelProvider,\n type PrepareVercelOptions,\n type PrepareVercelResult,\n} from './prepare.js';\nexport {\n currentVercelBaseFingerprintLive,\n ensureVercelBaseSnapshot,\n preparedStatePath,\n readPreparedState,\n writePreparedState,\n updatePreparedState,\n type PreparedVercelState,\n type PreparedVercelBase,\n} from './prepared-state.js';\nexport {\n RUNTIME_ASSETS,\n candidatesFor,\n resolveRuntimeAssets,\n findStagedCliRuntimeRoot,\n type RuntimeAsset,\n type ResolvedAsset,\n} from './runtime-assets.js';\nexport { buildVercelAttach } from './build-attach.js';\n","/**\n * Vercel `CloudBackend` — maps the provider-neutral cloud primitives onto\n * `@vercel/sandbox` v2 (Firecracker microVMs + snapshots). Composed into a full\n * `Provider` by `@agentbox/sandbox-cloud`'s `createCloudProvider`.\n *\n * Platform shape this backend is built around (see docs/cloud-providers.md):\n * - No custom image — sandboxes boot from a Vercel snapshot baked once by\n * `agentbox prepare --provider vercel`. `provision` always needs a snapshot\n * id (the prepared base, or a cloud-checkpoint snapshot).\n * - No SSH — `attachArgv` is intentionally omitted; the provider overrides\n * `buildAttach` with a Vercel-SDK-streaming helper instead.\n * - No nested containers — dockerd is disabled at the provider level.\n * - Persistent sandboxes auto-snapshot on stop and auto-resume on the next\n * `Sandbox.get({ resume: true })`, which is how pause/resume map cleanly.\n * - The sandbox's native user is `vercel-sandbox`; agentbox standardizes on\n * `vscode` (uid 1000), created by provision.sh. So `exec` drops privileges\n * to `vscode` (root → `sudo -u vscode`) unless the caller asks for root,\n * and `uploadFile` chowns to uid 1000 after the SDK writes as\n * `vercel-sandbox`.\n * - Max 4 exposed ports: we use 80 (WebProxy), 6080 (noVNC), 8788 (relay/ctl\n * bridge). One slot is left free for a future per-service expose.\n */\n\nimport { readFile } from 'node:fs/promises';\nimport type {\n CloudBackend,\n CloudExecOptions,\n CloudExecResult,\n CloudFileEntry,\n CloudHandle,\n CloudPreviewUrl,\n CloudProvisionRequest,\n CloudSandboxSummary,\n CloudState,\n} from '@agentbox/core';\nimport type { NetworkPolicy } from '@vercel/sandbox';\nimport {\n ensureFreshCredentials,\n resolveCredentials,\n Sandbox,\n Snapshot,\n type SandboxType,\n} from './sdk.js';\nimport { withVercelRetry } from './retry.js';\nimport { readPreparedState } from './prepared-state.js';\n\n/** Sentinel image ref the cloud-provider hands us when no --image was passed. */\nexport const DEFAULT_BOX_IMAGE_REF = 'agentbox/box:dev';\n\n/** Box user agentbox standardizes on. provision.sh creates it (uid auto-assigned —\n * the Vercel default user may already hold 1000, and there are no bind mounts so\n * the exact uid is irrelevant). chown targets it by name, not number. */\nconst BOX_USER = 'vscode';\nconst BOX_OWNER = 'vscode:vscode';\n\n/**\n * Base ports exposed at create. Vercel REJECTS privileged ports (<1024) with a\n * 400, so we cannot expose the scaffold's WebProxy on :80. Instead the in-box\n * WebProxy binds 8080 (set via `webProxyPort` → AGENTBOX_WEB_PROXY_PORT) and we\n * expose 8080 here so `sandbox.domain(8080)` routes to it → the in-box `expose:`\n * service. Ports are fixed at create (update can't add a routable port to a\n * running sandbox — verified), so 8080 must be in this base set. The other two\n * base ports are 6080 (noVNC) and 8788 (the relay/ctl bridge the host poller\n * reaches via `sandbox.domain(8788)`). Remaining slots (up to VERCEL_MAX_PORTS)\n * are filled at create from `agentbox.yaml` `expose:` ports (see buildExposedPorts).\n */\nexport const VERCEL_EXPOSED_PORTS = [8080, 6080, 8788] as const;\n\n/** Vercel's hard per-sandbox exposed-port cap. */\nexport const VERCEL_MAX_PORTS = 4;\n\n/**\n * Merge requested `expose:` service ports into the base set: drop privileged\n * (<1024 — Vercel 400s) and out-of-range ports + dupes, preserve order, and cap\n * at Vercel's 4-port limit. A preview URL only routes to a port declared here at\n * create time, so this is what makes `services.*.expose` reachable on Vercel.\n */\nexport function buildExposedPorts(extra: readonly number[] | undefined): number[] {\n const ports = [...VERCEL_EXPOSED_PORTS] as number[];\n const seen = new Set<number>(ports);\n for (const p of extra ?? []) {\n if (ports.length >= VERCEL_MAX_PORTS) break;\n if (Number.isInteger(p) && p >= 1024 && p < 65_536 && !seen.has(p)) {\n ports.push(p);\n seen.add(p);\n }\n }\n return ports;\n}\n\n/**\n * Parse the `box.vercelNetworkPolicy` config string into a Vercel\n * `NetworkPolicy`. `''`/unset → undefined (SDK default = allow-all). The\n * literals `allow-all` / `deny-all` pass through; anything else is treated as a\n * comma-separated domain allowlist `{ allow: [...] }` (everything else denied).\n */\nexport function parseNetworkPolicy(raw: string | undefined): NetworkPolicy | undefined {\n const v = (raw ?? '').trim();\n if (v === '') return undefined;\n if (v === 'allow-all' || v === 'deny-all') return v;\n const allow = v\n .split(',')\n .map((s) => s.trim())\n .filter((s) => s.length > 0);\n return allow.length > 0 ? { allow } : undefined;\n}\n\n/**\n * Default per-session timeout. 45 min is the Hobby ceiling, so it's safe across\n * all plans; persistent mode makes a hit transparent (the VM auto-snapshots and\n * auto-resumes on the next SDK call). Pro/Enterprise users who want a longer\n * single session can rely on `extendTimeout` / future config.\n */\nconst DEFAULT_TIMEOUT_MS = 45 * 60_000;\n\n/**\n * Per-box snapshot retention. Keep one auto-snapshot, never expiring, so a\n * paused box can always resume; `destroy` purges a box's own snapshot explicitly.\n *\n * `deleteEvicted: false` is load-bearing, NOT a tweak. A box boots from a shared\n * snapshot (the prepared base, or a `setup` checkpoint), and Vercel reports that\n * source as the box's `currentSnapshotId` until it takes its first auto-snapshot\n * — i.e. the source is the first member of this box's retention window. With\n * `deleteEvicted: true`, the box's first stop/snapshot evicts the source and\n * DELETES it, nuking the shared base/checkpoint every other box depends on, so\n * every later `create` 410s with \"Snapshot expired or deleted.\" (Same hazard the\n * `destroy` guard already dodges, but eviction is automatic and bypasses it.)\n * `false` keeps evicted snapshots around (they fall back to `snapshotExpiration`,\n * which we pin to 0 = never at create) — trading a little snapshot accumulation\n * for never deleting a snapshot another box boots from.\n */\nconst KEEP_LAST_SNAPSHOTS = { count: 1, expiration: 0, deleteEvicted: false } as const;\n\nfunction creds(): Partial<{ token: string; teamId: string; projectId: string }> {\n return resolveCredentials();\n}\n\n/** Single-quote a string for safe embedding inside a `bash -lc '<…>'`. */\nfunction shq(s: string): string {\n return \"'\" + s.replace(/'/g, \"'\\\\''\") + \"'\";\n}\n\nasync function getSandbox(id: string): Promise<SandboxType> {\n // resume:false — plain handle resolution; lifecycle methods opt into resume.\n return Sandbox.get({ name: id, resume: false, ...creds() });\n}\n\nasync function maybeGetSandbox(id: string): Promise<SandboxType | null> {\n try {\n return await getSandbox(id);\n } catch {\n return null;\n }\n}\n\n/**\n * Map Vercel's session status onto our 4-value `CloudState`. Transitional\n * states report as 'running' so callers don't ping-pong; 'stopped' maps to\n * 'paused' because a persistent sandbox keeps an auto-snapshot and resumes on\n * the next call (our pause semantics). 'aborted'/'failed' → 'missing'.\n */\nfunction mapState(s: string | undefined): CloudState {\n switch (s) {\n case 'running':\n return 'running';\n case 'pending':\n case 'stopping':\n case 'snapshotting':\n return 'running';\n case 'stopped':\n return 'paused';\n case 'aborted':\n case 'failed':\n default:\n return 'missing';\n }\n}\n\n/**\n * Build a `runCommand` invocation that runs `cmd` (already a shell string) as\n * the box user (`vscode`) by default, or as root when requested. Always starts\n * the SDK command as root (`sudo: true`) so the inner `sudo -u vscode` is\n * reliably passwordless, then drops privileges. cwd + env are applied inside\n * the dropped shell so they land in the right user/home context.\n */\nfunction buildRunCommand(\n cmd: string,\n opts?: CloudExecOptions,\n): { cmd: string; args: string[]; sudo: boolean } {\n const prelude: string[] = [];\n if (opts?.cwd) prelude.push(`cd ${shq(opts.cwd)}`);\n for (const [k, v] of Object.entries(opts?.env ?? {})) {\n // The value is shell-quoted, but the key is interpolated bare into a\n // `bash -lc` string that runs as root — reject anything that isn't a POSIX\n // env-var name so a key like `x;rm -rf /` can't inject a command.\n if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(k)) {\n throw new Error(`vercel exec: invalid env var name ${JSON.stringify(k)}`);\n }\n prelude.push(`export ${k}=${shq(v)}`);\n }\n const inner = [...prelude, cmd].join('\\n');\n const user = opts?.user ?? BOX_USER;\n if (user === 'root') {\n return { cmd: 'bash', args: ['-lc', inner], sudo: true };\n }\n return {\n cmd: 'bash',\n args: ['-lc', `sudo -u ${user} -H bash -lc ${shq(inner)}`],\n sudo: true,\n };\n}\n\nexport const vercelBackend: CloudBackend = {\n name: 'vercel',\n\n // Vercel rejects privileged ports (<1024) and can't add a routable port to a\n // running sandbox (update registers a route that 502s — verified). So the\n // in-box WebProxy binds 8080 (exposed at create via VERCEL_EXPOSED_PORTS) and\n // `agentbox url` resolves sandbox.domain(8080) → WebProxy → the in-box service.\n webProxyPort: 8080,\n\n async provision(req: CloudProvisionRequest): Promise<CloudHandle> {\n await ensureFreshCredentials();\n // Resolve the snapshot to boot from: an explicit cloud-checkpoint snapshot\n // (req.snapshot) wins, else the prepared base. Vercel can't build from a\n // Dockerfile, so there is no image fallback — fail loud with the fix.\n const snapshotId = req.snapshot ?? readPreparedState().base?.snapshotId;\n if (!snapshotId) {\n throw new Error(\n 'no Vercel base snapshot found.\\n' +\n 'Run `agentbox prepare --provider vercel` first — Vercel cannot build images ' +\n 'from a Dockerfile, so the base snapshot is a one-time prerequisite.',\n );\n }\n const networkPolicy = parseNetworkPolicy(req.networkPolicy);\n // No-retry: Sandbox.create is billable and non-idempotent — a timeout after\n // the request reached the origin could leave a duplicate sandbox we can't\n // reference for cleanup.\n const handle = await withVercelRetry(\n { method: 'provision', retryOnAmbiguous: false, attemptTimeoutMs: 900_000, backoffMs: [] },\n async () => {\n const sb = await Sandbox.create({\n name: req.name,\n source: { type: 'snapshot', snapshotId },\n resources: { vcpus: req.resources?.cpu ?? 2 },\n ports: buildExposedPorts(req.exposePorts),\n timeout: req.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n env: req.env,\n tags: { agentbox: 'true', 'agentbox.name': req.name },\n persistent: true,\n // Pin the sandbox-default expiration to never. Evicted snapshots (see\n // KEEP_LAST_SNAPSHOTS) fall back to this, so the shared base/checkpoint\n // a box boots from is never re-stamped with a finite expiry on eviction.\n snapshotExpiration: 0,\n keepLastSnapshots: { ...KEEP_LAST_SNAPSHOTS },\n ...(networkPolicy ? { networkPolicy } : {}),\n ...creds(),\n });\n return { sandboxId: sb.name };\n },\n );\n // Agent credentials are seeded by `createCloudProvider`'s unified\n // post-provision step (`seedAgentVolumesIfFresh`) via `uploadFile` + `exec`\n // — the symlinks baked into provision.sh route ~/.claude/.credentials.json\n // etc. through to `~/.agentbox-creds/<agent>/`.\n return handle;\n },\n\n async get(sandboxId: string): Promise<CloudHandle | null> {\n await ensureFreshCredentials();\n return withVercelRetry({ method: 'get', retryOnAmbiguous: true }, async () => {\n const sb = await maybeGetSandbox(sandboxId);\n return sb ? { sandboxId: sb.name } : null;\n });\n },\n\n async list(): Promise<CloudSandboxSummary[]> {\n await ensureFreshCredentials();\n return withVercelRetry({ method: 'list', retryOnAmbiguous: true }, async () => {\n const page = await Sandbox.list({ ...creds() });\n const items = await page.toArray();\n return items\n .filter((sb) => sb.tags?.['agentbox'] === 'true')\n .map((sb): CloudSandboxSummary => {\n const summary: CloudSandboxSummary = { sandboxId: sb.name };\n const friendly = sb.tags?.['agentbox.name'] ?? sb.name;\n if (friendly) summary.name = friendly;\n if (typeof sb.createdAt === 'number') {\n summary.createdAt = new Date(sb.createdAt).toISOString();\n }\n summary.state = mapState(sb.status);\n return summary;\n });\n });\n },\n\n async start(h: CloudHandle): Promise<void> {\n await ensureFreshCredentials();\n await withVercelRetry(\n { method: 'start', retryOnAmbiguous: true, attemptTimeoutMs: 120_000 },\n async () => {\n // resume:true auto-resumes a persistent sandbox from its current snapshot.\n await Sandbox.get({ name: h.sandboxId, resume: true, ...creds() });\n },\n );\n },\n\n async stop(h: CloudHandle): Promise<void> {\n await ensureFreshCredentials();\n await withVercelRetry(\n { method: 'stop', retryOnAmbiguous: true, attemptTimeoutMs: 120_000 },\n async () => {\n const sb = await getSandbox(h.sandboxId);\n // For a persistent sandbox this captures an auto-snapshot and shuts the\n // VM down — resume happens lazily on the next Sandbox.get.\n await sb.stop();\n },\n );\n },\n\n // pause == stop on Vercel (the auto-snapshot IS the cold-storage state).\n async pause(h: CloudHandle): Promise<void> {\n await this.stop(h);\n },\n\n async resume(h: CloudHandle): Promise<void> {\n await this.start(h);\n },\n\n async destroy(h: CloudHandle): Promise<void> {\n await ensureFreshCredentials();\n await withVercelRetry(\n { method: 'destroy', retryOnAmbiguous: true, attemptTimeoutMs: 120_000 },\n async () => {\n const sb = await maybeGetSandbox(h.sandboxId);\n if (!sb) return; // already gone — destroy is idempotent\n // Purge only a snapshot THIS box created (its own stop-time auto-\n // snapshot), never the shared base/source it booted from. A fresh box\n // has currentSnapshotId === sourceSnapshotId === the prepared base, and\n // deleting that would nuke the base snapshot every other box depends on.\n const snapId = sb.currentSnapshotId;\n const source = sb.sourceSnapshotId;\n const base = readPreparedState().base?.snapshotId;\n const ownSnapshot =\n snapId !== undefined && snapId !== source && snapId !== base;\n await sb.delete();\n if (ownSnapshot) {\n try {\n const snap = await Snapshot.get({ snapshotId: snapId, ...creds() });\n await snap.delete();\n } catch {\n // best-effort: a snapshot already gone is fine; the user can clean\n // stragglers from the Vercel dashboard.\n }\n }\n },\n );\n },\n\n async state(h: CloudHandle): Promise<CloudState> {\n await ensureFreshCredentials();\n return withVercelRetry({ method: 'state', retryOnAmbiguous: true }, async () => {\n const sb = await maybeGetSandbox(h.sandboxId);\n if (!sb) return 'missing';\n return mapState(sb.status);\n });\n },\n\n async exec(h: CloudHandle, cmd: string, opts?: CloudExecOptions): Promise<CloudExecResult> {\n await ensureFreshCredentials();\n return withVercelRetry(\n {\n method: 'exec',\n retryOnAmbiguous: opts?.noRetry ? false : true,\n attemptTimeoutMs: opts?.attemptTimeoutMs ?? 120_000,\n backoffMs: opts?.noRetry ? [] : undefined,\n },\n async () => {\n const sb = await getSandbox(h.sandboxId);\n const r = await sb.runCommand(buildRunCommand(cmd, opts));\n const [stdout, stderr] = await Promise.all([r.stdout(), r.stderr()]);\n return { exitCode: r.exitCode, stdout, stderr };\n },\n );\n },\n\n async uploadFile(h: CloudHandle, localPath: string, remotePath: string): Promise<void> {\n await ensureFreshCredentials();\n await withVercelRetry(\n { method: 'uploadFile', retryOnAmbiguous: true, attemptTimeoutMs: 300_000 },\n async () => {\n const content = await readFile(localPath);\n const sb = await getSandbox(h.sandboxId);\n await sb.writeFiles([{ path: remotePath, content }]);\n // writeFiles writes as `vercel-sandbox`; chown to the box user so the\n // scaffold's vscode-context reads/extractions succeed. Best-effort —\n // a chown failure on a world-readable /tmp staging file is harmless.\n try {\n await sb.runCommand({ cmd: 'chown', args: [BOX_OWNER, remotePath], sudo: true });\n } catch {\n // ignore — file is at least present and readable\n }\n },\n );\n },\n\n async downloadFile(h: CloudHandle, remotePath: string, localPath: string): Promise<void> {\n await ensureFreshCredentials();\n await withVercelRetry(\n { method: 'downloadFile', retryOnAmbiguous: true, attemptTimeoutMs: 300_000 },\n async () => {\n const sb = await getSandbox(h.sandboxId);\n const written = await sb.downloadFile(\n { path: remotePath },\n { path: localPath },\n { mkdirRecursive: true },\n );\n if (written === null) {\n throw new Error(`vercel downloadFile: source not found: ${remotePath}`);\n }\n },\n );\n },\n\n async listFiles(h: CloudHandle, remoteDir: string): Promise<CloudFileEntry[]> {\n await ensureFreshCredentials();\n return withVercelRetry({ method: 'listFiles', retryOnAmbiguous: true }, async () => {\n const sb = await getSandbox(h.sandboxId);\n const entries = await sb.fs.readdir(remoteDir, { withFileTypes: true });\n return entries.map((e) => ({ name: e.name, isDir: e.isDirectory() }));\n });\n },\n\n async previewUrl(h: CloudHandle, port: number): Promise<CloudPreviewUrl> {\n await ensureFreshCredentials();\n return withVercelRetry({ method: 'previewUrl', retryOnAmbiguous: true }, async () => {\n const sb = await getSandbox(h.sandboxId);\n // sb.domain(port) is a public HTTPS URL (no header token needed).\n return { url: sb.domain(port), token: undefined };\n });\n },\n\n // Fewer params than the interface's (h, port, expiresInSeconds) is fine —\n // Vercel sandbox domains are already public + browser-usable, so the signed\n // URL is just the standard one (the TTL is governed by the sandbox session\n // lifetime, not a per-URL signature, so the expiry arg is irrelevant here).\n async signedPreviewUrl(h: CloudHandle, port: number): Promise<CloudPreviewUrl> {\n return this.previewUrl(h, port);\n },\n\n async snapshotExists(snapshotName: string): Promise<boolean> {\n await ensureFreshCredentials();\n return withVercelRetry({ method: 'snapshotExists', retryOnAmbiguous: true }, async () => {\n try {\n const snap = await Snapshot.get({ snapshotId: snapshotName, ...creds() });\n // `Snapshot.get` resolves deleted/failed tombstones (status field) rather\n // than throwing, so \"didn't throw\" wrongly passes a dead snapshot. Only a\n // 'created' snapshot can actually boot a sandbox.\n return snap.status === 'created';\n } catch {\n return false;\n }\n });\n },\n\n // NOTE: no `createSnapshot`/`deleteSnapshot` here. Vercel snapshots are\n // addressed by an opaque id (not a caller-chosen name), which doesn't fit the\n // CloudBackend `createSnapshot(handle, name): void` contract — the provider\n // needs the id back to store it in the checkpoint manifest. The Vercel\n // provider therefore overrides the whole `checkpoint` capability in index.ts\n // using `snapshotVercelSandbox` / `deleteVercelSnapshot` below.\n};\n\n/**\n * Snapshot a running sandbox and return the resulting Vercel snapshot id.\n * `sb.snapshot()` stops the source sandbox as part of capture; persistent mode\n * resumes it on the next SDK call, so the box comes back automatically.\n */\nexport async function snapshotVercelSandbox(sandboxId: string): Promise<string> {\n await ensureFreshCredentials();\n return withVercelRetry(\n { method: 'createSnapshot', retryOnAmbiguous: false, attemptTimeoutMs: 900_000, backoffMs: [] },\n async () => {\n const sb = await getSandbox(sandboxId);\n const snap = await sb.snapshot({ expiration: 0 });\n return snap.snapshotId;\n },\n );\n}\n\n/** Delete a Vercel snapshot by id. Idempotent — a missing snapshot is success. */\nexport async function deleteVercelSnapshot(snapshotId: string): Promise<void> {\n await ensureFreshCredentials();\n await withVercelRetry({ method: 'deleteSnapshot', retryOnAmbiguous: true }, async () => {\n try {\n const snap = await Snapshot.get({ snapshotId, ...creds() });\n await snap.delete();\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n if (/not.?found|404/i.test(msg)) return; // idempotent\n throw err;\n }\n });\n}\n","/**\n * Bounded retry wrapper for Vercel Sandbox SDK calls — mirrors\n * `withDaytonaRetry` / `withHetznerRetry` in shape and intent. The Vercel\n * control plane rate-limits (429) and can return transient 5xx during\n * incidents; without bounded retries those propagate as wedges in the calling\n * lifecycle code.\n *\n * Non-idempotent ops (`provision`/`Sandbox.create`, `createSnapshot`) pass\n * `retryOnAmbiguous: false` so a timeout after the request reached the origin\n * doesn't create a duplicate billable sandbox/snapshot.\n */\n\nexport interface WithRetryOptions {\n method: string;\n /** Per-attempt timeout (ms). Default 30_000. */\n attemptTimeoutMs?: number;\n /** Backoff before attempts 2, 3, … (ms). Default [1000, 2000, 4000]. */\n backoffMs?: readonly number[];\n /**\n * Retry on errors where we can't be sure the server applied the request\n * (connection failures, per-attempt timeouts, 5xx). Set false for\n * non-idempotent operations where a retry could create a duplicate resource.\n */\n retryOnAmbiguous: boolean;\n /** Override the default stderr retry sink (used by tests). */\n onRetry?: (line: string) => void;\n}\n\nconst DEFAULT_BACKOFF: readonly number[] = [1000, 2000, 4000];\nconst DEFAULT_ATTEMPT_TIMEOUT_MS = 30_000;\n\nclass AttemptTimeoutError extends Error {\n constructor(method: string, ms: number) {\n super(`vercel ${method}: per-attempt timeout after ${String(ms)}ms`);\n this.name = 'AttemptTimeoutError';\n }\n}\n\nexport function isAttemptTimeout(err: unknown): err is AttemptTimeoutError {\n return err instanceof AttemptTimeoutError;\n}\n\n/** HTTP status code dug out of whatever error shape the SDK throws. */\nfunction statusCodeOf(err: unknown): number | undefined {\n if (!err || typeof err !== 'object') return undefined;\n for (const key of ['statusCode', 'status', 'code'] as const) {\n const v = (err as Record<string, unknown>)[key];\n if (typeof v === 'number') return v;\n }\n const resp = (err as { response?: { status?: unknown } }).response;\n if (resp && typeof resp.status === 'number') return resp.status;\n return undefined;\n}\n\nexport function isRetriable(err: unknown, allowAmbiguous: boolean): boolean {\n if (err instanceof AttemptTimeoutError) return allowAmbiguous;\n\n const status = statusCodeOf(err);\n if (status !== undefined) {\n if (status === 429) return true; // rate limited — the server told us to wait\n if (status >= 500 && status <= 599) return allowAmbiguous;\n return false; // 4xx (auth, validation, not_found) — permanent\n }\n\n // Raw fetch / undici errors. Node wraps low-level errors in `{ cause }`.\n if (err && typeof err === 'object') {\n const candidates: unknown[] = [err, (err as { cause?: unknown }).cause];\n for (const c of candidates) {\n if (!c || typeof c !== 'object') continue;\n const code = (c as { code?: unknown }).code;\n if (\n code === 'ECONNRESET' ||\n code === 'ETIMEDOUT' ||\n code === 'ECONNABORTED' ||\n code === 'EAI_AGAIN' ||\n code === 'ECONNREFUSED' ||\n code === 'ENOTFOUND' ||\n code === 'UND_ERR_SOCKET' ||\n code === 'UND_ERR_CONNECT_TIMEOUT'\n ) {\n return allowAmbiguous;\n }\n }\n }\n return false;\n}\n\nexport async function withVercelRetry<T>(\n opts: WithRetryOptions,\n fn: () => Promise<T>,\n): Promise<T> {\n const backoff = opts.backoffMs ?? DEFAULT_BACKOFF;\n const maxAttempts = backoff.length + 1;\n const timeoutMs = opts.attemptTimeoutMs ?? DEFAULT_ATTEMPT_TIMEOUT_MS;\n const log = opts.onRetry ?? defaultRetryLog;\n\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n return await raceTimeout(fn(), timeoutMs, opts.method);\n } catch (err) {\n const last = attempt === maxAttempts;\n if (last || !isRetriable(err, opts.retryOnAmbiguous)) throw err;\n const delay = backoff[attempt - 1] ?? backoff[backoff.length - 1] ?? 4000;\n log(\n `vercel ${opts.method}: attempt ${String(attempt)} failed (${errorSummary(err)}); retrying in ${String(delay)}ms`,\n );\n await sleep(delay);\n }\n }\n throw new Error(`withVercelRetry: exhausted attempts for ${opts.method}`);\n}\n\nfunction defaultRetryLog(line: string): void {\n process.stderr.write(`\\n[vercel-retry] ${line}\\n`);\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms));\n}\n\nasync function raceTimeout<T>(p: Promise<T>, ms: number, method: string): Promise<T> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n return await Promise.race([\n p,\n new Promise<never>((_resolve, reject) => {\n timer = setTimeout(() => reject(new AttemptTimeoutError(method, ms)), ms);\n }),\n ]);\n } finally {\n if (timer !== undefined) clearTimeout(timer);\n }\n}\n\nfunction errorSummary(err: unknown): string {\n if (err instanceof Error) {\n const status = statusCodeOf(err);\n return status !== undefined\n ? `${err.name}(${String(status)}): ${truncate(err.message)}`\n : `${err.name}: ${truncate(err.message)}`;\n }\n return truncate(String(err));\n}\n\nfunction truncate(s: string, max = 160): string {\n return s.length > max ? `${s.slice(0, max)}…` : s;\n}\n","/**\n * `agentbox prepare --provider vercel` — bake the per-team Vercel base\n * snapshot. Vercel can't build an image from a Dockerfile, so (like hetzner)\n * we boot a fresh sandbox, run an installer, and snapshot the result. That\n * snapshot id is what every per-box `create` boots from.\n *\n * Flow:\n * 1. Resolve runtime assets + fingerprint the build context. Skip the bake\n * when an up-to-date base snapshot already exists (unless --force).\n * 2. `Sandbox.create({ runtime: 'node24', persistent: false })` — fresh AL2023.\n * 3. `writeFiles` the assets (ctl bundle, helpers, baked configs, provision.sh).\n * 4. Run provision.sh as root, streaming output to the prepare log.\n * 5. Stage host agent static config (claude/codex/opencode) into the snapshot.\n * 6. `sandbox.snapshot({ expiration: 0 })` → the never-expiring base snapshot.\n * 7. Persist the snapshot id into ~/.agentbox/vercel-prepared.json.\n * 8. Delete the builder sandbox.\n *\n * Step 8 is safe: a Vercel snapshot is an independent, id-addressed resource\n * that survives its source sandbox's deletion (verified live — snapshot stays\n * `status: 'created'` and boots a fresh sandbox after the builder is deleted).\n * We delete it best-effort *after* the snapshot id is persisted, so a delete\n * failure only leaves a lingering sandbox for Vercel's reaper, never a broken\n * bake.\n */\n\nimport { readFile } from 'node:fs/promises';\nimport { Writable } from 'node:stream';\nimport type { Provider } from '@agentbox/core';\nimport { computeContextSha256, readCliStamp } from '@agentbox/sandbox-core';\nimport {\n stageClaudeStaticForUpload,\n stageCodexStaticForUpload,\n stageOpencodeStaticForUpload,\n type StageResult,\n} from '@agentbox/sandbox-cloud';\nimport { ensureVercelCredentials } from './credentials.js';\nimport {\n ensureFreshCredentials,\n resolveCredentials,\n Sandbox,\n Snapshot,\n type SandboxType,\n} from './sdk.js';\nimport {\n preparedStatePath,\n readPreparedState,\n writePreparedState,\n} from './prepared-state.js';\nimport {\n findStagedCliRuntimeRoot,\n resolveRuntimeAssets,\n type ResolvedAsset,\n} from './runtime-assets.js';\n\nexport interface PrepareVercelOptions {\n name?: string;\n hostWorkspace?: string;\n /** Force re-bake even when an up-to-date base snapshot is recorded. */\n force?: boolean;\n /** vCPUs for the builder sandbox (default 4 for a fast bake). */\n vcpus?: number;\n /** CLI runtime tree (set by the CLI to its dist neighbor). */\n cliRuntimeRoot?: string;\n /** Repo root for the dev fallback (defaults to a cwd-walk). */\n repoRoot?: string;\n onLog?: (line: string) => void;\n}\n\nexport interface PrepareVercelResult {\n snapshotName?: string;\n}\n\nconst BUILDER_TIMEOUT_MS = 25 * 60_000;\nconst SHELL = '/bin/bash';\n\nexport async function prepareVercel(\n opts: PrepareVercelOptions = {},\n): Promise<PrepareVercelResult> {\n await ensureVercelCredentials();\n await ensureFreshCredentials();\n const creds = resolveCredentials();\n const log = opts.onLog ?? (() => {});\n const progress = (s: string) => log(`prepare-vercel: ${s}`);\n\n const assets = resolveRuntimeAssets({\n cliRuntimeRoot: opts.cliRuntimeRoot ?? findStagedCliRuntimeRoot(),\n repoRoot: opts.repoRoot,\n });\n const contextSha = await computeContextSha256(\n assets.map((a) => ({ rel: a.name, abs: a.localPath })),\n );\n\n // Skip-fast: existing base snapshot still on Vercel + matching fingerprint.\n const existing = readPreparedState();\n if (!opts.force && existing.base) {\n const stillThere = await snapshotExists(existing.base.snapshotId, creds);\n if (stillThere && existing.base.contextSha256 === contextSha) {\n progress(\n `base snapshot ${existing.base.snapshotId} already exists (fingerprint ${contextSha.slice(0, 12)} matches); skipping (pass --force to rebuild)`,\n );\n return { snapshotName: existing.base.snapshotId };\n }\n if (!stillThere) {\n progress(`recorded base snapshot ${existing.base.snapshotId} is gone on Vercel; rebuilding`);\n } else {\n progress(\n `build context changed (was ${existing.base.contextSha256?.slice(0, 12) ?? '<none>'}, now ${contextSha.slice(0, 12)}); rebuilding`,\n );\n }\n }\n\n progress(`creating builder sandbox (node24, ${String(opts.vcpus ?? 4)} vcpus)`);\n const sb = await Sandbox.create({\n runtime: 'node24',\n resources: { vcpus: opts.vcpus ?? 4 },\n timeout: BUILDER_TIMEOUT_MS,\n tags: { agentbox: 'true', 'agentbox.role': 'prepare' },\n persistent: false,\n ...creds,\n });\n progress(`builder sandbox ${sb.name} up`);\n\n // 3. Upload assets.\n progress(`uploading ${String(assets.length)} runtime asset(s)`);\n await sb.writeFiles(\n await Promise.all(\n assets.map(async (a: ResolvedAsset) => ({\n path: a.remotePath,\n content: await readFile(a.localPath),\n mode: a.remoteMode,\n })),\n ),\n );\n\n // 4. Run provision.sh as root, streaming output.\n progress('running provision.sh (this takes a few minutes)');\n const install = await sb.runCommand({\n cmd: SHELL,\n args: ['-lc', 'bash /tmp/agentbox-provision.sh 2>&1'],\n sudo: true,\n stdout: lineSink((l) => log(`[provision] ${l}`)),\n stderr: lineSink((l) => log(`[provision] ${l}`)),\n });\n if (install.exitCode !== 0) {\n throw new Error(`provision.sh failed on the builder sandbox (exit ${String(install.exitCode)})`);\n }\n progress('provision.sh complete');\n\n // 5. Stage host agent static config into the snapshot (best-effort).\n await stageAgentConfig(sb, opts.hostWorkspace, log);\n\n // 6. Snapshot (never expires). NOTE: this stops the builder sandbox.\n progress('creating base snapshot (expiration: never)');\n const snap = await sb.snapshot({ expiration: 0 });\n progress(`snapshot created: ${snap.snapshotId}`);\n\n // 7. Persist.\n const cliStamp = readCliStamp();\n writePreparedState({\n schema: 1,\n base: {\n snapshotId: snap.snapshotId,\n contextSha256: contextSha,\n cliVersion: cliStamp.cliVersion,\n cliCommit: cliStamp.cliCommit,\n createdAt: new Date().toISOString(),\n },\n });\n progress(`wrote ${preparedStatePath()}`);\n\n // 8. Delete the builder. The snapshot is an independent resource that\n // survives this (verified live), and its id is already persisted above, so\n // this is best-effort: a failure just leaves the sandbox for Vercel's reaper.\n progress('deleting builder sandbox');\n try {\n await sb.delete();\n progress('builder sandbox deleted');\n } catch (err) {\n progress(\n `builder delete failed (left for Vercel reaper): ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n\n progress(`prepare complete — base snapshot ${snap.snapshotId}`);\n return { snapshotName: snap.snapshotId };\n}\n\nasync function snapshotExists(\n snapshotId: string,\n creds: Partial<{ token: string; teamId: string; projectId: string }>,\n): Promise<boolean> {\n try {\n const snap = await Snapshot.get({ snapshotId, ...creds });\n // `Snapshot.get` resolves even for a deleted/failed snapshot (status field),\n // so a bare \"didn't throw\" wrongly skip-passes a tombstone. Only a 'created'\n // snapshot is bootable — anything else means rebuild.\n return snap.status === 'created';\n } catch {\n return false;\n }\n}\n\nasync function stageAgentConfig(\n sb: SandboxType,\n hostWorkspace: string | undefined,\n log: (line: string) => void,\n): Promise<void> {\n const progress = (s: string) => log(`prepare-vercel: ${s}`);\n progress('staging host agent static config');\n const stagings: Array<{ kind: 'claude' | 'codex' | 'opencode'; tar: StageResult; dest: string }> = [];\n try {\n const claudeTar = await stageClaudeStaticForUpload({ hostWorkspace });\n for (const w of claudeTar.warnings) progress(w);\n if (claudeTar.tarballPath) stagings.push({ kind: 'claude', tar: claudeTar, dest: '/home/vscode/.claude' });\n else await claudeTar.cleanup();\n\n const codexTar = await stageCodexStaticForUpload();\n for (const w of codexTar.warnings) progress(w);\n if (codexTar.tarballPath) stagings.push({ kind: 'codex', tar: codexTar, dest: '/home/vscode/.codex' });\n else await codexTar.cleanup();\n\n const opencodeTar = await stageOpencodeStaticForUpload();\n for (const w of opencodeTar.warnings) progress(w);\n if (opencodeTar.tarballPath) stagings.push({ kind: 'opencode', tar: opencodeTar, dest: '/home/vscode/.local/share/opencode' });\n else await opencodeTar.cleanup();\n\n for (const s of stagings) {\n const remote = `/tmp/agentbox-${s.kind}-static.tar.gz`;\n progress(`uploading ${s.kind} static config`);\n await sb.writeFiles([{ path: remote, content: await readFile(s.tar.tarballPath as string) }]);\n // Extract as vscode so files land owned by the box user. The dest dir\n // already exists (provision.sh's credential-pivot step) — extract into it.\n const extract =\n `sudo -u vscode mkdir -p ${s.dest} && ` +\n `sudo -u vscode tar -xzf ${remote} -C ${s.dest} --no-same-permissions --no-same-owner -m && ` +\n `rm -f ${remote}`;\n const r = await sb.runCommand({ cmd: SHELL, args: ['-lc', extract], sudo: true });\n if (r.exitCode !== 0) {\n progress(`WARN: ${s.kind} static extract failed (exit ${String(r.exitCode)}) — continuing`);\n } else {\n progress(`baked ${s.kind} static config into snapshot`);\n }\n }\n } finally {\n for (const s of stagings) await s.tar.cleanup();\n }\n}\n\n/**\n * Adapt a line-callback to the `Writable` the SDK's `runCommand` streams into.\n * Buffers partial lines so each `onLine` gets a complete line.\n */\nfunction lineSink(onLine: (line: string) => void): Writable {\n let buf = '';\n return new Writable({\n write(chunk: Buffer, _enc: BufferEncoding, cb: () => void) {\n buf += chunk.toString('utf8');\n let nl: number;\n while ((nl = buf.indexOf('\\n')) !== -1) {\n onLine(buf.slice(0, nl));\n buf = buf.slice(nl + 1);\n }\n cb();\n },\n final(cb: () => void) {\n if (buf.length > 0) onLine(buf);\n cb();\n },\n });\n}\n\n/** Provider-level binding used by the CLI's `prepare` command. */\nexport const prepareVercelProvider: NonNullable<Provider['prepare']> = (req) =>\n prepareVercel({\n name: req.name,\n hostWorkspace: req.hostWorkspace ?? process.cwd(),\n force: req.force,\n onLog: req.onLog,\n });\n","/**\n * `buildVercelAttach` — the Vercel provider's override of `Provider.buildAttach`.\n *\n * Vercel has no SSH, so the cloud scaffold's `ssh … -t '<cmd>'` argv is unusable.\n * Instead we drive the official Vercel Sandbox CLI (`sbx`/`sandbox`), which has a\n * real interactive PTY (`sbx exec -i`) and streams non-interactive output live —\n * giving a proper terminal with none of the old send-keys/capture-pane polling.\n *\n * Argv shape (validated against sbx 3.0.1):\n * sbx exec --sudo [-i] --project <p> --scope <team> <name>\n * -- sudo -u vscode -H bash -lc '<inner>'\n *\n * Notes:\n * - The sandbox's default exec user is `vercel-sandbox`; we pass `--sudo` (runs\n * as root) and then `sudo -u vscode -H` so tmux/agents run as the box user in\n * /workspace. Passing `sudo -u vscode …` directly as sbx's argv (not wrapped\n * in an outer `bash -lc`) avoids a double-`bash -lc` re-parse.\n * - `-i` only for interactive shell/agent attaches; detached pre-start and logs\n * run non-interactively (live stdout stream).\n * - The access token is passed via the child env (`VERCEL_AUTH_TOKEN`), never in\n * argv, so it can't leak through `ps`. project/scope are not secret → flags.\n * - `<inner>` is the shared cloud `renderInnerCommand` (same tmux ensure +\n * footer-aware config + `exec tmux attach` used by hetzner/daytona).\n */\n\nimport {\n type AttachKind,\n type AttachSpec,\n type BoxRecord,\n type BuildAttachOptions,\n} from '@agentbox/core';\nimport { renderInnerCommand } from '@agentbox/sandbox-cloud';\nimport { detectSbx } from './sbx-cli.js';\nimport { ensureFreshCredentials, resolveCredentials } from './sdk.js';\n\nexport async function buildVercelAttach(\n box: BoxRecord,\n kind: AttachKind,\n opts?: BuildAttachOptions,\n): Promise<AttachSpec> {\n const sandboxId = box.cloud?.sandboxId;\n if (!sandboxId) {\n throw new Error(`vercel box ${box.name} has no sandboxId — record is malformed`);\n }\n\n const det = await detectSbx();\n if (!det.installed || !det.bin) {\n throw new Error(\n 'Vercel interactive attach needs the Vercel `sandbox` CLI — run ' +\n '`agentbox vercel login` (it installs it) or `npm install -g sandbox`.',\n );\n }\n\n await ensureFreshCredentials();\n const { token, teamId, projectId } = resolveCredentials();\n\n // Interactive (real PTY) only for live shell/agent attaches. Detached\n // pre-start and logs stream non-interactively.\n const interactive = (kind === 'shell' || kind === 'agent') && !opts?.detached;\n\n // `sbx exec` (unlike `ssh -t`) forwards neither TERM nor the locale, so the\n // box session lands in TERM=unknown + an ASCII (POSIX) locale — tmux then\n // collapses Claude Code's Unicode glyphs (logo, spinner, box-drawing) to `_`.\n // Force a UTF-8 locale + a 256color TERM (matching the host PTY wrapper) so\n // the tmux server + the agent it spawns render correctly.\n const envPrelude = 'export LANG=C.UTF-8 LC_ALL=C.UTF-8 TERM=xterm-256color; ';\n const inner = envPrelude + renderInnerCommand(kind, opts);\n\n const argv = [\n det.bin,\n 'exec',\n '--sudo',\n ...(interactive ? ['-i'] : []),\n '--project',\n projectId,\n '--scope',\n teamId,\n sandboxId,\n '--',\n 'sudo',\n '-u',\n 'vscode',\n '-H',\n 'bash',\n '-lc',\n inner,\n ];\n\n return { argv, env: { VERCEL_AUTH_TOKEN: token } };\n}\n"],"mappings":"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","names":["readFile","creds","readFile","readCliStamp"]}
|