@madarco/agentbox 0.13.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/README.md +11 -8
  3. package/dist/{_cloud-attach-HJC672UR.js → _cloud-attach-GUBB5RH2.js} +4 -4
  4. package/dist/{chunk-R5XIDQFR.js → chunk-BKU34KYY.js} +170 -6
  5. package/dist/chunk-BKU34KYY.js.map +1 -0
  6. package/dist/{chunk-QYRK5H6Q.js → chunk-BYCLD6D6.js} +17 -9
  7. package/dist/chunk-BYCLD6D6.js.map +1 -0
  8. package/dist/chunk-LDMYHWUS.js +346 -0
  9. package/dist/chunk-LDMYHWUS.js.map +1 -0
  10. package/dist/{chunk-2LF5YILI.js → chunk-RSKG7AFU.js} +80 -6
  11. package/dist/chunk-RSKG7AFU.js.map +1 -0
  12. package/dist/{chunk-4NQXNQ53.js → chunk-TBSIJVSN.js} +149 -47
  13. package/dist/chunk-TBSIJVSN.js.map +1 -0
  14. package/dist/{chunk-B4QG2MCW.js → chunk-TCS5HXJX.js} +381 -174
  15. package/dist/chunk-TCS5HXJX.js.map +1 -0
  16. package/dist/{chunk-ECLLV5JH.js → chunk-VATTS2MR.js} +156 -5
  17. package/dist/chunk-VATTS2MR.js.map +1 -0
  18. package/dist/{chunk-SNTHHWKY.js → chunk-XKH7NTT7.js} +80 -22
  19. package/dist/chunk-XKH7NTT7.js.map +1 -0
  20. package/dist/dist-34RKQ74M.js +662 -0
  21. package/dist/dist-34RKQ74M.js.map +1 -0
  22. package/dist/{dist-OPIBZ7XM.js → dist-3IMQNTTV.js} +14 -69
  23. package/dist/dist-3IMQNTTV.js.map +1 -0
  24. package/dist/{dist-OG6NW6SM.js → dist-4DPOL5A7.js} +5 -3
  25. package/dist/{dist-JAN5VABY.js → dist-57M6ZA7H.js} +25 -177
  26. package/dist/dist-57M6ZA7H.js.map +1 -0
  27. package/dist/{dist-7KVUIKJX.js → dist-J2IHD5T7.js} +37 -226
  28. package/dist/dist-J2IHD5T7.js.map +1 -0
  29. package/dist/index.js +1376 -1029
  30. package/dist/index.js.map +1 -1
  31. package/dist/{prepared-state-MQHD3M5F-KE4DT3GX.js → prepared-state-MQHD3M5F-Q27AZU53.js} +2 -2
  32. package/package.json +8 -6
  33. package/runtime/docker/Dockerfile.box +21 -26
  34. package/runtime/docker/apps/cli/share/agentbox-setup/SKILL.md +37 -1
  35. package/runtime/docker/packages/ctl/dist/bin.cjs +40 -16
  36. package/runtime/docker/packages/sandbox-docker/scripts/agentbox-vnc-start +17 -6
  37. package/runtime/docker/packages/sandbox-docker/scripts/chromium-resolver +57 -0
  38. package/runtime/docker/packages/sandbox-docker/scripts/claude-managed-settings.json +2 -1
  39. package/runtime/e2b/agentbox-checkpoint-cleanup +52 -0
  40. package/runtime/e2b/agentbox-codex-hooks.json +68 -0
  41. package/runtime/e2b/agentbox-open +28 -0
  42. package/runtime/e2b/agentbox-setup-skill.md +233 -0
  43. package/runtime/e2b/agentbox-vnc-start +102 -0
  44. package/runtime/e2b/attach-helper.cjs +167 -0
  45. package/runtime/e2b/claude-managed-settings.json +116 -0
  46. package/runtime/e2b/ctl.cjs +23864 -0
  47. package/runtime/e2b/custom-system-CLAUDE.md +46 -0
  48. package/runtime/e2b/gh-shim +344 -0
  49. package/runtime/e2b/git-shim +131 -0
  50. package/runtime/e2b/scripts/build-template.sh +295 -0
  51. package/runtime/hetzner/agentbox-setup-skill.md +37 -1
  52. package/runtime/hetzner/agentbox-vnc-start +17 -6
  53. package/runtime/hetzner/claude-managed-settings.json +2 -1
  54. package/runtime/hetzner/ctl.cjs +40 -16
  55. package/runtime/relay/bin.cjs +297 -228
  56. package/runtime/vercel/agentbox-setup-skill.md +37 -1
  57. package/runtime/vercel/agentbox-vnc-start +17 -6
  58. package/runtime/vercel/claude-managed-settings.json +2 -1
  59. package/runtime/vercel/ctl.cjs +40 -16
  60. package/share/agentbox-setup/SKILL.md +37 -1
  61. package/share/host-skills/agentbox-info/SKILL.md +26 -34
  62. package/dist/chunk-2LF5YILI.js.map +0 -1
  63. package/dist/chunk-4NQXNQ53.js.map +0 -1
  64. package/dist/chunk-B4QG2MCW.js.map +0 -1
  65. package/dist/chunk-ECLLV5JH.js.map +0 -1
  66. package/dist/chunk-QYRK5H6Q.js.map +0 -1
  67. package/dist/chunk-R5XIDQFR.js.map +0 -1
  68. package/dist/chunk-SNTHHWKY.js.map +0 -1
  69. package/dist/dist-7KVUIKJX.js.map +0 -1
  70. package/dist/dist-JAN5VABY.js.map +0 -1
  71. package/dist/dist-OPIBZ7XM.js.map +0 -1
  72. /package/dist/{_cloud-attach-HJC672UR.js.map → _cloud-attach-GUBB5RH2.js.map} +0 -0
  73. /package/dist/{dist-OG6NW6SM.js.map → dist-4DPOL5A7.js.map} +0 -0
  74. /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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACgCA,SAAS,gBAAgB;AEAzB,SAAS,UAAU,OAAO,SAAS,UAAU;AAC7C,SAAS,cAAc;AACvB,SAAS,SAAS,MAAM,eAAe;ACjBvC,SAAS,kBAAkB;AAC3B,SAAS,WAAAA,UAAS,WAAAC,gBAAe;AACjC,SAAS,qBAAqB;AFQ9B,IAAM,kBAAqC,CAAC,KAAM,KAAM,GAAI;AAC5D,IAAM,6BAA6B;AAEnC,IAAM,sBAAN,cAAkC,MAAM;EACtC,YAAY,QAAgB,IAAY;AACtC,UAAM,OAAO,MAAM,+BAA+B,OAAO,EAAE,CAAC,IAAI;AAChE,SAAK,OAAO;EACd;AACF;AAOA,SAAS,aAAa,KAAkC;AACtD,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO;AAC5C,aAAW,OAAO,CAAC,cAAc,UAAU,MAAM,GAAY;AAC3D,UAAM,IAAK,IAAgC,GAAG;AAC9C,QAAI,OAAO,MAAM,SAAU,QAAO;EACpC;AACA,QAAM,OAAQ,IAA4C;AAC1D,MAAI,QAAQ,OAAO,KAAK,WAAW,SAAU,QAAO,KAAK;AACzD,SAAO;AACT;AAEO,SAAS,YAAY,KAAc,gBAAkC;AAC1E,MAAI,eAAe,oBAAqB,QAAO;AAI/C,QAAM,OAAO,eAAe,QAAQ,IAAI,OAAO;AAC/C,MAAI,SAAS,iBAAkB,QAAO;AACtC,MAAI,SAAS,uBAAwB,QAAO;AAE5C,QAAM,SAAS,aAAa,GAAG;AAC/B,MAAI,WAAW,QAAW;AACxB,QAAI,WAAW,IAAK,QAAO;AAC3B,QAAI,UAAU,OAAO,UAAU,IAAK,QAAO;AAC3C,WAAO;EACT;AAGA,MAAI,OAAO,OAAO,QAAQ,UAAU;AAClC,UAAM,aAAwB,CAAC,KAAM,IAA4B,KAAK;AACtE,eAAW,KAAK,YAAY;AAC1B,UAAI,CAAC,KAAK,OAAO,MAAM,SAAU;AACjC,YAAM,OAAQ,EAAyB;AACvC,UACE,SAAS,gBACT,SAAS,eACT,SAAS,kBACT,SAAS,eACT,SAAS,kBACT,SAAS,eACT,SAAS,oBACT,SAAS,2BACT;AACA,eAAO;MACT;IACF;EACF;AACA,SAAO;AACT;AAEA,eAAsB,aAAgB,MAAwB,IAAkC;AAC9F,QAAM,UAAU,KAAK,aAAa;AAClC,QAAM,cAAc,QAAQ,SAAS;AACrC,QAAM,YAAY,KAAK,oBAAoB;AAC3C,QAAM,MAAM,KAAK,WAAW;AAE5B,WAAS,UAAU,GAAG,WAAW,aAAa,WAAW;AACvD,QAAI;AACF,aAAO,MAAM,YAAY,GAAG,GAAG,WAAW,KAAK,MAAM;IACvD,SAAS,KAAK;AACZ,YAAM,OAAO,YAAY;AACzB,UAAI,QAAQ,CAAC,YAAY,KAAK,KAAK,gBAAgB,EAAG,OAAM;AAC5D,YAAM,QAAQ,QAAQ,UAAU,CAAC,KAAK,QAAQ,QAAQ,SAAS,CAAC,KAAK;AACrE;QACE,OAAO,KAAK,MAAM,aAAa,OAAO,OAAO,CAAC,YAAY,aAAa,GAAG,CAAC,kBAAkB,OAAO,KAAK,CAAC;MAC5G;AACA,YAAM,MAAM,KAAK;IACnB;EACF;AACA,QAAM,IAAI,MAAM,wCAAwC,KAAK,MAAM,EAAE;AACvE;AAEA,SAAS,gBAAgB,MAAoB;AAC3C,UAAQ,OAAO,MAAM;cAAiB,IAAI;CAAI;AAChD;AAEA,SAAS,MAAM,IAA2B;AACxC,SAAO,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,EAAE,CAAC;AAC7C;AAEA,eAAe,YAAe,GAAe,IAAY,QAA4B;AACnF,MAAI;AACJ,MAAI;AACF,WAAO,MAAM,QAAQ,KAAK;MACxB;MACA,IAAI,QAAe,CAAC,UAAU,WAAW;AACvC,gBAAQ,WAAW,MAAM,OAAO,IAAI,oBAAoB,QAAQ,EAAE,CAAC,GAAG,EAAE;MAC1E,CAAC;IACH,CAAC;EACH,UAAA;AACE,QAAI,UAAU,OAAW,cAAa,KAAK;EAC7C;AACF;AAEA,SAAS,aAAa,KAAsB;AAC1C,MAAI,eAAe,OAAO;AACxB,UAAM,SAAS,aAAa,GAAG;AAC/B,WAAO,WAAW,SACd,GAAG,IAAI,IAAI,IAAI,OAAO,MAAM,CAAC,MAAM,SAAS,IAAI,OAAO,CAAC,KACxD,GAAG,IAAI,IAAI,KAAK,SAAS,IAAI,OAAO,CAAC;EAC3C;AACA,SAAO,SAAS,OAAO,GAAG,CAAC;AAC7B;AAEA,SAAS,SAAS,GAAW,MAAM,KAAa;AAC9C,SAAO,EAAE,SAAS,MAAM,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC,WAAM;AAClD;AD9FO,IAAM,wBAAwB;AAGrC,IAAM,WAAW;AACjB,IAAM,YAAY;AAGlB,IAAM,qBAAqB;AAO3B,IAAM,qBAAqB,KAAK;AAEhC,IAAM,eAAe;AAGrB,SAAS,IAAI,GAAmB;AAC9B,SAAO,MAAM,EAAE,QAAQ,MAAM,OAAO,IAAI;AAC1C;AAUA,SAAS,oBAAoB,GAAwB;AACnD,QAAM,KAAK,IAAI,YAAY,EAAE,UAAU;AACvC,MAAI,WAAW,EAAE,EAAE,IAAI,CAAC;AACxB,SAAO;AACT;AAOA,SAAS,SAAS,GAAyC;AACzD,UAAQ,GAAG;IACT,KAAK;AACH,aAAO;IACT,KAAK;AACH,aAAO;IACT;AACE,aAAO;EACX;AACF;AAGA,SAAS,WAAW,KAAuB;AACzC,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO;AAC5C,QAAM,OAAO,eAAe,QAAQ,IAAI,OAAO;AAC/C,MAAI,SAAS,0BAA0B,SAAS,gBAAiB,QAAO;AACxE,QAAM,SAAU,IAAmD,cAAe,IAA6B;AAC/G,SAAO,WAAW;AACpB;AAOA,SAAS,iBAAiB,MAAsB;AAC9C,SAAO,KAAK,QAAQ,oBAAoB,EAAE,EAAE,MAAM,GAAG,GAAG;AAC1D;AAEO,IAAM,aAA2B;EACtC,MAAM;;;;;;EAON,cAAc;EAEd,MAAM,UAAU,KAAkD;AAChE,UAAM,SAAS,cAAc;AAC7B,UAAM,MAAM,IAAI,UAAU,MAAM;IAAC;AAQjC,QAAI,IAAI,aAAa,QAAW;AAC9B,4BAAsB;IACxB;AACA,UAAM,WAAW,IAAI,YAAY,kBAAkB,EAAE,MAAM;AAC3D,QAAI,CAAC,UAAU;AACb,YAAM,IAAI;QACR;MACF;IACF;AAKA,UAAM,KAAK,MAAM;MACf,EAAE,QAAQ,aAAa,kBAAkB,OAAO,kBAAkB,KAAS,WAAW,CAAC,EAAE;MACzF,YACE,QAAQ,OAAO;QACb;QACA;;;QAGA,UAAU,EAAE,UAAU,QAAQ,iBAAiB,iBAAiB,IAAI,IAAI,GAAG,MAAM,iBAAiB,IAAI,IAAI,EAAE;QAC5G,MAAM,IAAI;QACV,WAAW,IAAI,aAAa;MAC9B,CAAC;IACL;AACA,QAAI,wBAAwB,GAAG,SAAS,cAAc,QAAQ,GAAG;AACjE,WAAO,EAAE,WAAW,GAAG,UAAU;EACnC;EAEA,MAAM,IAAI,WAAgD;AACxD,UAAM,SAAS,cAAc;AAC7B,WAAO,aAAa,EAAE,QAAQ,OAAO,kBAAkB,KAAK,GAAG,YAAY;AACzE,UAAI;AAGF,cAAM,QAAQ,QAAQ,WAAW,EAAE,OAAO,CAAC;AAC3C,eAAO,EAAE,UAAU;MACrB,SAAS,KAAK;AACZ,YAAI,WAAW,GAAG,EAAG,QAAO;AAC5B,cAAM;MACR;IACF,CAAC;EACH;EAEA,MAAM,OAAuC;AAC3C,UAAM,SAAS,cAAc;AAC7B,WAAO,aAAa,EAAE,QAAQ,QAAQ,kBAAkB,KAAK,GAAG,YAAY;AAC1E,YAAM,YAAmC,CAAC;AAG1C,iBAAW,SAAS,CAAC,WAAW,QAAQ,GAAY;AAClD,cAAM,YAAY,QAAQ,KAAK,EAAE,QAAQ,OAAO,EAAE,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;AACpE,eAAO,UAAU,SAAS;AACxB,gBAAM,OAAO,MAAM,UAAU,UAAU;AACvC,qBAAW,QAAQ,MAAM;AACvB,gBAAI,KAAK,WAAW,UAAU,MAAM,OAAQ;AAC5C,kBAAM,WACJ,KAAK,WAAW,eAAe,KAAK,KAAK,WAAW,MAAM;AAC5D,kBAAM,UAA+B,EAAE,WAAW,KAAK,WAAW,MAAM;AACxE,gBAAI,SAAU,SAAQ,OAAO;AAC7B,kBAAM,YAAY,KAAK;AACvB,gBAAI,qBAAqB,KAAM,SAAQ,YAAY,UAAU,YAAY;AACzE,sBAAU,KAAK,OAAO;UACxB;QACF;MACF;AACA,aAAO;IACT,CAAC;EACH;;;;EAKA,MAAM,MAAM,GAA+B;AACzC,UAAM,SAAS,cAAc;AAC7B,UAAM;MACJ,EAAE,QAAQ,SAAS,kBAAkB,MAAM,kBAAkB,KAAQ;MACrE,YAAY;AACV,cAAM,QAAQ,QAAQ,EAAE,WAAW,EAAE,OAAO,CAAC;MAC/C;IACF;EACF;;EAGA,MAAM,KAAK,GAA+B;AACxC,UAAM,KAAK,MAAM,CAAC;EACpB;EAEA,MAAM,MAAM,GAA+B;AACzC,UAAM,SAAS,cAAc;AAC7B,UAAM;MACJ,EAAE,QAAQ,SAAS,kBAAkB,MAAM,kBAAkB,KAAQ;MACrE,YAAY;AACV,cAAM,QAAQ,MAAM,EAAE,WAAW,EAAE,OAAO,CAAC;MAC7C;IACF;EACF;EAEA,MAAM,OAAO,GAA+B;AAC1C,UAAM,KAAK,MAAM,CAAC;EACpB;EAEA,MAAM,QAAQ,GAA+B;AAC3C,UAAM,SAAS,cAAc;AAC7B,UAAM;MACJ,EAAE,QAAQ,WAAW,kBAAkB,MAAM,kBAAkB,KAAQ;MACvE,YAAY;AACV,YAAI;AACF,gBAAM,QAAQ,KAAK,EAAE,WAAW,EAAE,OAAO,CAAC;QAC5C,SAAS,KAAK;AACZ,cAAI,WAAW,GAAG,EAAG;AACrB,gBAAM;QACR;MACF;IACF;EACF;EAEA,MAAM,MAAM,GAAqC;AAC/C,UAAM,SAAS,cAAc;AAC7B,WAAO,aAAa,EAAE,QAAQ,SAAS,kBAAkB,KAAK,GAAG,YAAY;AAC3E,UAAI;AACF,cAAM,OAAoB,MAAM,QAAQ,QAAQ,EAAE,WAAW,EAAE,OAAO,CAAC;AACvE,eAAO,SAAS,KAAK,KAAK;MAC5B,SAAS,KAAK;AACZ,YAAI,WAAW,GAAG,EAAG,QAAO;AAC5B,cAAM;MACR;IACF,CAAC;EACH;EAEA,MAAM,KAAK,GAAgB,KAAa,MAAmD;AACzF,UAAM,SAAS,cAAc;AAI7B,UAAM,YAAY,MAAM,oBAAoB;AAC5C,WAAO;MACL;QACE,QAAQ;QACR,kBAAkB,MAAM,UAAU,QAAQ;QAC1C,kBAAkB;QAClB,WAAW,MAAM,UAAU,CAAC,IAAI;MAClC;MACA,YAAY;AAGV,cAAM,KAAK,MAAM,QAAQ,QAAQ,EAAE,WAAW,EAAE,OAAO,CAAC;AAGxD,cAAM,OAAQ,MAAM,QAAQ;AAC5B,YAAI;AACF,gBAAM,IAAI,MAAM,GAAG,SAAS,IAAI,KAAK;YACnC,GAAI,MAAM,QAAQ,SAAY,EAAE,KAAK,KAAK,IAAI,IAAI,CAAC;YACnD,GAAI,MAAM,QAAQ,SAAY,EAAE,MAAM,KAAK,IAAI,IAAI,CAAC;YACpD;YACA;UACF,CAAC;AACD,iBAAO,EAAE,UAAU,EAAE,UAAU,QAAQ,EAAE,UAAU,IAAI,QAAQ,EAAE,UAAU,GAAG;QAChF,SAAS,KAAK;AAKZ,cAAI,eAAe,SAAS,IAAI,SAAS,oBAAoB;AAC3D,kBAAM,KAAK;AAKX,mBAAO,EAAE,UAAU,GAAG,UAAU,QAAQ,GAAG,UAAU,IAAI,QAAQ,GAAG,UAAU,GAAG;UACnF;AACA,gBAAM;QACR;MACF;IACF;EACF;EAEA,MAAM,WAAW,GAAgB,WAAmB,YAAmC;AACrF,UAAM,SAAS,cAAc;AAC7B,UAAM;MACJ,EAAE,QAAQ,cAAc,kBAAkB,MAAM,kBAAkB,IAAQ;MAC1E,YAAY;AACV,cAAM,OAAO,MAAM,SAAS,SAAS;AACrC,cAAM,KAAK,MAAM,QAAQ,QAAQ,EAAE,WAAW,EAAE,OAAO,CAAC;AACxD,cAAM,GAAG,MAAM,MAAM,CAAC,EAAE,MAAM,YAAY,MAAM,oBAAoB,IAAI,EAAE,CAAC,CAAC;AAI5E,YAAI;AACF,gBAAM,GAAG,SAAS,IAAI,iBAAiB,SAAS,IAAI,IAAI,UAAU,CAAC,IAAI;YACrE,MAAM;YACN,WAAW;UACb,CAAC;QACH,QAAQ;QAER;MACF;IACF;EACF;EAEA,MAAM,aAAa,GAAgB,YAAoB,WAAkC;AACvF,UAAM,SAAS,cAAc;AAC7B,UAAM;MACJ,EAAE,QAAQ,gBAAgB,kBAAkB,MAAM,kBAAkB,IAAQ;MAC5E,YAAY;AACV,cAAM,KAAK,MAAM,QAAQ,QAAQ,EAAE,WAAW,EAAE,OAAO,CAAC;AACxD,cAAM,QAAQ,MAAM,GAAG,MAAM,KAAK,YAAY,EAAE,QAAQ,QAAQ,CAAC;AACjE,cAAM,EAAE,UAAU,IAAI,MAAM,OAAO,aAAkB;AACrD,cAAM,UAAU,WAAW,OAAO,KAAK,KAAK,CAAC;MAC/C;IACF;EACF;EAEA,MAAM,UAAU,GAAgB,WAA8C;AAC5E,UAAM,SAAS,cAAc;AAC7B,WAAO,aAAa,EAAE,QAAQ,aAAa,kBAAkB,KAAK,GAAG,YAAY;AAC/E,YAAM,KAAK,MAAM,QAAQ,QAAQ,EAAE,WAAW,EAAE,OAAO,CAAC;AACxD,YAAM,UAAU,MAAM,GAAG,MAAM,KAAK,SAAS;AAC7C,aAAO,QAAQ,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,EAAE,SAAS,MAAM,EAAE;IACvE,CAAC;EACH;EAEA,MAAM,WAAW,GAAgB,MAAwC;AAOvE,UAAM,SAAS,QAAQ,IAAI,cAAc;AACzC,WAAO,EAAE,KAAK,WAAW,OAAO,IAAI,CAAC,IAAI,EAAE,SAAS,IAAI,MAAM,IAAI,OAAO,OAAU;EACrF;;;EAIA,MAAM,iBAAiB,GAAgB,MAAwC;AAC7E,WAAO,KAAK,WAAW,GAAG,IAAI;EAChC;;;;;;;;EASA,MAAM,eAAeC,eAAwC;AAC3D,UAAM,SAAS,cAAc;AAC7B,WAAO,aAAa,EAAE,QAAQ,kBAAkB,kBAAkB,KAAK,GAAG,YAAY;AACpF,UAAI;AACF,eAAO,MAAM,SAAS,OAAOA,eAAc,EAAE,OAAO,CAAC;MACvD,QAAQ;AACN,eAAO;MACT;IACF,CAAC;EACH;AACF;AE3UA,IAAM,gBAAgB;AACtB,IAAM,cAAc;AAEpB,IAAM,cAAc;AACpB,IAAM,oBAAoB;AAE1B,eAAsB,WACpB,OAA0B,CAAC,GACA;AAC3B,QAAM,qBAAqB;AAC3B,QAAM,SAAS,cAAc;AAC7B,QAAM,MAAM,KAAK,UAAU,MAAM;EAAC;AAClC,QAAM,WAAW,CAAC,MAAc,IAAI,gBAAgB,CAAC,EAAE;AAEvD,QAAM,SAAS,qBAAqB;IAClC,gBAAgB,KAAK,kBAAkB,yBAAyB;IAChE,UAAU,KAAK;EACjB,CAAC;AACD,QAAM,aAAa,MAAM;IACvB,OAAO,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,KAAK,EAAE,UAAU,EAAE;EACvD;AASA,QAAM,WAAW,kBAAkB;AACnC,MAAI,CAAC,KAAK,SAAS,SAAS,MAAM;AAChC,QAAI,SAAS,KAAK,kBAAkB,YAAY;AAC9C,YAAM,aAAa,MAAM,eAAe,SAAS,KAAK,YAAY,MAAM;AACxE,UAAI,YAAY;AACd;UACE,YAAY,SAAS,KAAK,UAAU,gCAAgC,WAAW,MAAM,GAAG,EAAE,CAAC;QAC7F;AACA,eAAO,EAAE,cAAc,SAAS,KAAK,WAAW;MAClD;AACA,eAAS,qBAAqB,SAAS,KAAK,UAAU,6BAA6B;IACrF,OAAO;AACL;QACE,8BAA8B,SAAS,KAAK,eAAe,MAAM,GAAG,EAAE,KAAK,QAAQ,SAAS,WAAW,MAAM,GAAG,EAAE,CAAC;MACrH;IACF;EACF;AAMA,QAAM,aAAa,MAAM,QAAQ,KAAK,OAAO,GAAG,qBAAqB,CAAC;AACtE,MAAI;AACF,aAAS,4BAA4B,UAAU,EAAE;AACjD,UAAM,gBAAgB,YAAY,MAAM;AAKxC,aAAS,iEAAiE;AAC1E,UAAM,WAAW,SAAS,EAAE,iBAAiB,WAAW,CAAC,EAAE,cAAc;AACzE,eAAW,KAAK,QAAQ;AACtB,eAAS,UAAU,EAAE,IAAI,OAAO,EAAE,UAAU,EAAE;AAC9C,eAAS,KAAK,EAAE,MAAM,EAAE,YAAY;QAClC,aAAa;QACb,MAAM,EAAE;QACR,MAAM;MACR,CAAC;IACH;AACA,aAAS,OAAO,6CAA6C,EAAE,MAAM,OAAO,CAAC;AAG7E,UAAM,gBAAgB,SAAS;MAC7B;IACF;AAEA,UAAM,WAAW,KAAK,YAAY;AAClC,UAAM,WAAW,KAAK,YAAY;AAClC;MACE,2BAA2B,aAAa,kBAAkB,OAAO,QAAQ,CAAC,eAAe,OAAO,QAAQ,CAAC;IAC3G;AACA,UAAM,OAAO,MAAM,SAAS,MAAM,eAAe,eAAe;MAC9D;MACA;MACA;MACA,aAAa,CAAC,UAAwB;AAEpC,YAAI,WAAW,eAAe,KAAK,CAAC,EAAE;MACxC;IACF,CAAC;AACD,aAAS,sBAAsB,KAAK,UAAU,UAAU,KAAK,OAAO,SAAS,KAAK,IAAI,EAAE;AAMxF,UAAM,MAAM,KAAK,OAAO,CAAC,KAAK;AAC9B,UAAM,WAAW,aAAa;AAC9B,UAAM,WAAW,GAAG,KAAK,UAAU,IAAI,GAAG;AAC1C,uBAAmB;MACjB,QAAQ;MACR,MAAM;QACJ,YAAY;;;;QAIZ,cAAc,KAAK;QACnB,eAAe;QACf,YAAY,SAAS;QACrB,WAAW,SAAS;QACpB,YAAW,oBAAI,KAAK,GAAE,YAAY;MACpC;IACF,CAAC;AACD,aAAS,SAAS,kBAAkB,CAAC,EAAE;AAEvC,aAAS,yCAAoC,QAAQ,EAAE;AACvD,WAAO,EAAE,cAAc,SAAS;EAClC,UAAA;AACE,UAAM,GAAG,YAAY,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC,EAAE,MAAM,MAAM;IAEnE,CAAC;EACH;AACF;AAOA,eAAe,gBACb,YACA,QACe;AACf,aAAW,KAAK,QAAQ;AACtB,UAAM,OAAO,QAAQ,YAAY,EAAE,IAAI;AACvC,UAAM,MAAM,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAC9C,UAAM,SAAS,EAAE,WAAW,IAAI;EAClC;AACF;AAOA,eAAe,eAAe,MAAc,QAAkC;AAC5E,MAAI;AACF,WAAO,MAAM,SAAS,OAAO,MAAM,EAAE,OAAO,CAAC;EAC/C,QAAQ;AACN,WAAO;EACT;AACF;AAcA,SAAS,eAAe,OAA6B;AAGnD,QAAM,MAAM,OAAO,MAAM,YAAY,WAAW,MAAM,UAAU,MAAM,SAAS;AAC/E,QAAM,UAAU,IAAI,QAAQ,WAAW,EAAE;AACzC,SAAO,QAAQ,SAAS,MAAM,QAAQ,MAAM,GAAG,GAAG,IAAI,WAAM;AAC9D;AAGO,IAAM,qBAAuD,CAAC,QACnE,WAAW;EACT,MAAM,IAAI;EACV,eAAe,IAAI,iBAAiB,QAAQ,IAAI;EAChD,OAAO,IAAI;EACX,OAAO,IAAI;AACb,CAAC;AC9NH,IAAM,OAAOC,SAAQ,cAAc,YAAY,GAAG,CAAC;AAO5C,SAAS,0BAAkC;AAChD,QAAM,aAAa;;IAEjBC,SAAQ,MAAM,mBAAmB;;IAEjCA,SAAQ,MAAM,MAAM,QAAQ,mBAAmB;;IAE/CA,SAAQ,MAAM,MAAM,WAAW,OAAO,mBAAmB;IACzDA,SAAQ,MAAM,MAAM,MAAM,WAAW,OAAO,mBAAmB;EACjE;AACA,aAAW,KAAK,YAAY;AAC1B,QAAI,WAAW,CAAC,EAAG,QAAO;EAC5B;AAGA,SAAO,WAAW,CAAC;AACrB;AAEA,eAAsB,eACpB,KACA,MACA,MACqB;AACrB,QAAM,YAAY,IAAI,OAAO;AAC7B,MAAI,CAAC,WAAW;AACd,UAAM,IAAI,MAAM,WAAW,IAAI,IAAI,8CAAyC;EAC9E;AAEA,QAAM,SAAS,wBAAwB;AACvC,MAAI,CAAC,WAAW,MAAM,GAAG;AACvB,UAAM,IAAI;MACR,kCAAkC,MAAM;IAE1C;EACF;AAEA,QAAM,SAAS,cAAc;AAC7B,QAAM,QAAQ,mBAAmB,MAAM,IAAI;AAE3C,QAAM,OAAO;IACX,QAAQ;IACR;IACA;IACA;IACA;IACA;EACF;AAEA,SAAO;IACL;IACA,KAAK;MACH,aAAa;MACb,wBAAwB;IAC1B;EACF;AACF;AJzDA,IAAM,eAAe;AAErB,IAAM,gBAAgB,oBAAoB,YAAY;;;;;EAKpD,kBAAkB,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,EAAE;EAC/C,eAAe;AACjB,CAAC;AAQD,eAAe,kBAAkB,WAAmB,MAA+B;AACjF,QAAM,SAAS,cAAc;AAC7B,SAAO;IACL,EAAE,QAAQ,kBAAkB,kBAAkB,OAAO,kBAAkB,KAAS,WAAW,CAAC,EAAE;IAC9F,YAAY;AACV,YAAM,OAAO,MAAM,QAAQ,eAAe,WAAW,EAAE,QAAQ,KAAK,CAAC;AACrE,aAAO,KAAK;IACd;EACF;AACF;AAGA,eAAe,kBAAkB,YAAmC;AAClE,QAAM,SAAS,cAAc;AAC7B,QAAM,aAAa,EAAE,QAAQ,kBAAkB,kBAAkB,KAAK,GAAG,YAAY;AACnF,QAAI;AACF,YAAM,QAAQ,eAAe,YAAY,EAAE,OAAO,CAAC;IACrD,SAAS,KAAK;AACZ,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,UAAI,kBAAkB,KAAK,GAAG,EAAG;AACjC,YAAM;IACR;EACF,CAAC;AACH;AAQA,SAAS,aAAa,SAAiB,gBAAgC;AAErE,QAAM,WAAW,CAAC,MAChB,EAAE,YAAY,EAAE,QAAQ,iBAAiB,GAAG,EAAE,QAAQ,YAAY,EAAE;AACtE,QAAM,MAAK,oBAAI,KAAK,GAAE,YAAY,EAAE,QAAQ,SAAS,GAAG,EAAE,QAAQ,KAAK,GAAG,EAAE,QAAQ,KAAK,EAAE;AAC3F,SAAO,YAAY,SAAS,OAAO,CAAC,IAAI,SAAS,cAAc,CAAC,IAAI,SAAS,EAAE,CAAC;AAClF;AAUA,IAAM,gBAAoC;EACxC,MAAM,OAAO,KAAgB,MAAc;AACzC,QAAI,CAAC,IAAI,aAAa;AACpB,YAAM,IAAI;QACR;MACF;IACF;AACA,QAAI,CAAC,IAAI,OAAO,WAAW;AACzB,YAAM,IAAI,MAAM,WAAW,IAAI,IAAI,8CAAyC;IAC9E;AAGA,UAAM,cAAc,aAAa,IAAI,MAAM,IAAI;AAC/C,UAAM,aAAa,MAAM,kBAAkB,IAAI,MAAM,WAAW,WAAW;AAG3E,QAAI;AACF,YAAM,UAAU,EAAE,GAAG,KAAK,OAAO,EAAE,GAAG,IAAI,OAAO,WAAW,SAAS,EAAE,CAAC;IAC1E,QAAQ;IAER;AACA,UAAM,OAAO,MAAM,6BAA6B,IAAI,aAAa,cAAc,MAAM;MACnF,cAAc;MACd,aAAa,IAAI;MACjB,eAAe,IAAI;MACnB,cAAc;MACd,iBAAiB,4BAA4B,YAAY;MACzD,YAAYC,aAAa,EAAE;IAC7B,CAAC;AACD,WAAO,EAAE,KAAK,KAAK,KAAK;EAC1B;EACA,MAAM,KAAK,aAAqB;AAC9B,UAAM,UAAU,MAAM,qBAAqB,aAAa,YAAY;AACpE,WAAO,QAAQ,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,WAAW,EAAE,SAAS,UAAU,EAAE;EAC9E;EACA,MAAM,OAAO,aAAqB,KAAa;AAC7C,UAAM,QAAQ,MAAM,uBAAuB,aAAa,cAAc,GAAG;AACzE,QAAI,CAAC,MAAO;AACZ,QAAI;AACF,YAAM,kBAAkB,MAAM,SAAS,YAAY;IACrD,QAAQ;IAGR;AACA,UAAM,yBAAyB,aAAa,cAAc,GAAG;EAC/D;AACF;AAEO,IAAM,cAAwB;EACnC,GAAG;EACH,SAAS;EACT,aAAa;EACb,YAAY;EACZ,iBAAiB,MAAM,8BAA8B;AACvD;","names":["dirname","resolve","snapshotName","dirname","resolve","readCliStamp"]}
@@ -1,88 +1,31 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  DEFAULT_BOX_IMAGE_REF,
4
+ computeDaytonaContextFingerprint,
5
+ currentDaytonaBaseFingerprintLive,
4
6
  daytonaBackend,
5
7
  ensureDaytonaCredentials,
6
8
  ensureDaytonaEnvLoaded,
7
9
  getClient,
10
+ preparedMatches,
11
+ readPreparedDaytonaState,
8
12
  resolveDaytonaCustomClaudeMd,
9
- resolveDockerfileContext
10
- } from "./chunk-2LF5YILI.js";
13
+ resolveDockerfileContext,
14
+ writePreparedDaytonaState
15
+ } from "./chunk-RSKG7AFU.js";
11
16
  import {
12
17
  createCloudProvider
13
- } from "./chunk-4NQXNQ53.js";
18
+ } from "./chunk-TBSIJVSN.js";
14
19
  import {
15
20
  stageClaudeStaticForUpload,
16
21
  stageCodexStaticForUpload,
17
22
  stageOpencodeStaticForUpload
18
- } from "./chunk-B4QG2MCW.js";
19
- import {
20
- DOCKER_CONTEXT_FILE_MAP,
21
- computeContextSha256,
22
- readCliStamp,
23
- readPreparedStateRaw,
24
- resolveContextFilesFrom,
25
- writePreparedStateRaw
26
- } from "./chunk-SNTHHWKY.js";
23
+ } from "./chunk-TCS5HXJX.js";
24
+ import "./chunk-XKH7NTT7.js";
27
25
  import "./chunk-G3H2L3O2.js";
28
26
 
29
27
  // ../../packages/sandbox-daytona/dist/index.js
30
28
  import { Image } from "@daytonaio/sdk";
31
- import { existsSync } from "fs";
32
- import { dirname, resolve } from "path";
33
- import { fileURLToPath } from "url";
34
- var SCHEMA = 1;
35
- function resolveDaytonaContextFiles() {
36
- const ctx = resolveDockerfileContext();
37
- if (!ctx) return null;
38
- const here = dirname(fileURLToPath(import.meta.url));
39
- const packageRoot = resolve(here, "..");
40
- const monorepoRoot = resolve(here, "..", "..", "..");
41
- const dockerPackageRoot = resolve(monorepoRoot, "packages", "sandbox-docker");
42
- const docker = resolveContextFilesFrom(DOCKER_CONTEXT_FILE_MAP, {
43
- contextDir: ctx.context,
44
- devRoot: existsSync(dockerPackageRoot) ? dockerPackageRoot : packageRoot
45
- });
46
- if (!docker) return null;
47
- const overlay = resolveDaytonaCustomClaudeMd();
48
- if (!overlay) return null;
49
- return [
50
- ...docker,
51
- // Daytona-specific overlay: separate logical name so a docker/daytona
52
- // CLAUDE.md drift produces different fingerprints (the daytona snapshot
53
- // contains both files in distinct locations).
54
- { rel: "daytona/custom-system-CLAUDE.md", abs: overlay }
55
- ];
56
- }
57
- async function computeDaytonaContextFingerprint() {
58
- const files = resolveDaytonaContextFiles();
59
- if (!files) return null;
60
- return { contextSha256: await computeContextSha256(files), files };
61
- }
62
- function readPreparedDaytonaState() {
63
- const raw = readPreparedStateRaw("daytona");
64
- if (raw === null || typeof raw !== "object") return null;
65
- const parsed = raw;
66
- if (parsed.schema !== SCHEMA) return null;
67
- return { schema: SCHEMA, base: parsed.base };
68
- }
69
- function writePreparedDaytonaState(opts) {
70
- const stamp = readCliStamp();
71
- const state = {
72
- schema: SCHEMA,
73
- base: {
74
- imageRef: opts.snapshotName,
75
- contextSha256: opts.contextSha256,
76
- cliVersion: stamp.cliVersion,
77
- cliCommit: stamp.cliCommit,
78
- createdAt: (/* @__PURE__ */ new Date()).toISOString()
79
- }
80
- };
81
- writePreparedStateRaw("daytona", state);
82
- }
83
- function preparedMatches(state, current) {
84
- return state?.base?.contextSha256 === current;
85
- }
86
29
  function defaultSnapshotName(fingerprint) {
87
30
  if (fingerprint) return `agentbox-base-${fingerprint.slice(0, 12)}`;
88
31
  return `agentbox-base-${Math.floor(Date.now() / 1e3).toString()}`;
@@ -279,10 +222,12 @@ var cloudProvider = createCloudProvider(daytonaBackend, {
279
222
  });
280
223
  var daytonaProvider = {
281
224
  ...cloudProvider,
282
- prepare: prepareDaytona
225
+ prepare: prepareDaytona,
226
+ baseFingerprint: () => currentDaytonaBaseFingerprintLive()
283
227
  };
284
228
  export {
285
229
  DEFAULT_BOX_IMAGE_REF,
230
+ currentDaytonaBaseFingerprintLive,
286
231
  daytonaBackend,
287
232
  daytonaProvider,
288
233
  ensureDaytonaCredentials,
@@ -290,4 +235,4 @@ export {
290
235
  getDaytonaStatus,
291
236
  resolveDockerfileContext
292
237
  };
293
- //# sourceMappingURL=dist-OPIBZ7XM.js.map
238
+ //# sourceMappingURL=dist-3IMQNTTV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../packages/sandbox-daytona/src/index.ts","../../../packages/sandbox-daytona/src/prepare.ts","../../../packages/sandbox-daytona/src/status.ts"],"sourcesContent":["/**\n * The Daytona Cloud sandbox provider. A thin `CloudBackend` over\n * `@daytonaio/sdk`, composed via `@agentbox/sandbox-cloud`'s `createCloudProvider`\n * for everything provider-agnostic (workspace seeding, ctl launch, state).\n */\n\nimport type { Provider } from '@agentbox/core';\nimport { createCloudProvider } from '@agentbox/sandbox-cloud';\nimport { daytonaBackend, DEFAULT_BOX_IMAGE_REF } from './backend.js';\nimport { prepareDaytona } from './prepare.js';\nimport { currentDaytonaBaseFingerprintLive } from './prepared-state.js';\n\nconst cloudProvider = createCloudProvider(daytonaBackend, {\n defaultResources: { cpu: 2, memory: 4, disk: 8 },\n});\n\nexport const daytonaProvider: Provider = {\n ...cloudProvider,\n prepare: prepareDaytona,\n baseFingerprint: () => currentDaytonaBaseFingerprintLive(),\n};\n\nexport { daytonaBackend, DEFAULT_BOX_IMAGE_REF };\nexport { resolveDockerfileContext, type DockerfileContext } from './dockerfile-context.js';\nexport { ensureDaytonaEnvLoaded } from './env-loader.js';\nexport { currentDaytonaBaseFingerprintLive } from './prepared-state.js';\n// Called by the CLI provider registry to gate first-run interactive setup.\n// Plain async function — no commander surface — so adding it here doesn't\n// pull commander/clack into consumers' type graphs. The full CLI command\n// lives at the `./cli` subpath export.\nexport { ensureDaytonaCredentials } from './credentials.js';\nexport type { EnsureDaytonaCredentialsOptions } from './credentials.js';\nexport {\n getDaytonaStatus,\n type DaytonaStatus,\n type DaytonaSnapshotSummary,\n type DaytonaVolumeSummary,\n} from './status.js';\n","/**\n * Daytona-side implementation of the `Provider.prepare` hook (`agentbox\n * prepare --provider daytona`). One-time, user-triggered:\n *\n * 1. Stage filtered tarballs of the host's `~/.claude`, `~/.codex`, and\n * `~/.local/share/opencode` static config (no auth tokens — those go on\n * the per-org `agentbox-credentials` volume at create time).\n * 2. Build a layered Daytona `Image`: start from `Dockerfile.box`, then\n * `.addLocalFile()` each staged tarball + `.runCommands()` to extract\n * them into the right paths inside the image.\n * 3. Call `daytona.snapshot.create({ name, image }, { onLogs })` — Daytona\n * runs the build server-side, registers the result as an org-scoped\n * named snapshot, and returns when it's `active`.\n *\n * Replaces the old `agentbox daytona publish-snapshot` flow that\n * provisioned a sandbox + ran an in-sandbox bake + called the broken\n * `_experimental_createSnapshot`. The new path never provisions a sandbox.\n *\n * Source of truth for the public API:\n * https://www.daytona.io/docs/en/snapshots/\n */\n\nimport { Image } from '@daytonaio/sdk';\nimport type { PrepareOptions, PrepareResult } from '@agentbox/core';\nimport {\n stageClaudeStaticForUpload,\n stageCodexStaticForUpload,\n stageOpencodeStaticForUpload,\n type StageResult,\n} from '@agentbox/sandbox-cloud';\nimport { getClient } from './backend.js';\nimport { resolveDaytonaCustomClaudeMd, resolveDockerfileContext } from './dockerfile-context.js';\nimport { ensureDaytonaEnvLoaded } from './env-loader.js';\nimport {\n computeDaytonaContextFingerprint,\n preparedMatches,\n readPreparedDaytonaState,\n writePreparedDaytonaState,\n} from './prepared-state.js';\n\n/**\n * Default snapshot name. Keyed on the first 12 chars of the build-context\n * fingerprint so identical content produces the same snapshot name across\n * machines / CLI runs (idempotent): if the named snapshot already exists\n * on Daytona, prepare can short-circuit without uploading the build\n * context again. Falls back to a timestamp when fingerprinting fails\n * (partial dev rebuild).\n */\nfunction defaultSnapshotName(fingerprint: string | null): string {\n if (fingerprint) return `agentbox-base-${fingerprint.slice(0, 12)}`;\n return `agentbox-base-${Math.floor(Date.now() / 1000).toString()}`;\n}\n\ninterface AgentStage {\n kind: 'claude' | 'codex' | 'opencode';\n /** Path inside the image build that the tarball is uploaded to. */\n remoteTar: string;\n /** Path the image build extracts the tarball into. */\n extractDir: string;\n staged: StageResult;\n}\n\n/**\n * Stage the three agents' static tarballs in parallel. Each `StageResult`'s\n * `cleanup()` must be called by the caller, after the image build picks the\n * file up.\n */\nasync function stageAllAgentStatic(opts: { hostWorkspace?: string }): Promise<AgentStage[]> {\n const [claudeStaged, codexStaged, opencodeStaged] = await Promise.all([\n stageClaudeStaticForUpload({ hostWorkspace: opts.hostWorkspace }),\n stageCodexStaticForUpload(),\n stageOpencodeStaticForUpload(),\n ]);\n return [\n {\n kind: 'claude',\n remoteTar: '/tmp/agentbox-seed-claude.tar.gz',\n extractDir: '/home/vscode/.claude',\n staged: claudeStaged,\n },\n {\n kind: 'codex',\n remoteTar: '/tmp/agentbox-seed-codex.tar.gz',\n extractDir: '/home/vscode/.codex',\n staged: codexStaged,\n },\n {\n kind: 'opencode',\n remoteTar: '/tmp/agentbox-seed-opencode.tar.gz',\n extractDir: '/home/vscode/.local/share/opencode',\n staged: opencodeStaged,\n },\n ];\n}\n\n/**\n * Run `agentbox prepare --provider daytona`. Returns `{ snapshotName }` on\n * success so the CLI can pin it into the project config.\n */\nexport async function prepareDaytona(opts: PrepareOptions): Promise<PrepareResult> {\n ensureDaytonaEnvLoaded();\n const log = opts.onLog ?? (() => {});\n\n // Fingerprint the build context first so we can (a) name the snapshot\n // deterministically and (b) detect cache hits against the recorded\n // prepared state. Computed before staging so an early `null` (partial\n // dev rebuild) doesn't waste a tar staging cycle.\n const fingerprint = await computeDaytonaContextFingerprint();\n const snapshotName =\n opts.name ?? defaultSnapshotName(fingerprint?.contextSha256 ?? null);\n\n const prepared = readPreparedDaytonaState();\n if (\n !opts.force &&\n fingerprint &&\n preparedMatches(prepared, fingerprint.contextSha256)\n ) {\n // Confirm the snapshot still exists on Daytona before short-circuiting.\n // A \"yes locally, no on the server\" mismatch must rebuild.\n try {\n const existing = await getClient().snapshot.get(\n prepared?.base?.imageRef ?? snapshotName,\n );\n if (existing?.name) {\n log(\n `daytona snapshot '${existing.name}' up to date ` +\n `(fingerprint ${fingerprint.contextSha256.slice(0, 12)}) — skipping rebuild ` +\n `(pass --force to override)`,\n );\n return { snapshotName: existing.name };\n }\n log(\n `recorded snapshot '${prepared?.base?.imageRef ?? snapshotName}' not found on Daytona; rebuilding`,\n );\n } catch {\n log(\n `recorded snapshot lookup failed; rebuilding (pass --force to silence)`,\n );\n }\n } else if (!opts.force && fingerprint && prepared?.base?.contextSha256) {\n log(\n `daytona build context changed (was ${prepared.base.contextSha256.slice(0, 12)}, ` +\n `now ${fingerprint.contextSha256.slice(0, 12)}); rebuilding snapshot`,\n );\n }\n\n const ctx = resolveDockerfileContext();\n if (!ctx) {\n throw new Error(\n 'could not locate AgentBox Dockerfile.box build context for the Daytona snapshot. ' +\n 'Set AGENTBOX_DOCKER_CONTEXT to the directory containing Dockerfile.box.',\n );\n }\n\n const daytonaClaudeMd = resolveDaytonaCustomClaudeMd();\n if (!daytonaClaudeMd) {\n throw new Error(\n 'could not locate packages/sandbox-daytona/scripts/custom-system-CLAUDE.md ' +\n '(or its staged runtime/daytona/ copy). Ensure `pnpm -w build` ran so the ' +\n 'CLI staging populated runtime/daytona/.',\n );\n }\n\n const stages = await stageAllAgentStatic({ hostWorkspace: opts.hostWorkspace });\n // Surface staging warnings (codex Keychain landmine, etc.) before the\n // longer build kicks off.\n for (const s of stages) {\n for (const w of s.staged.warnings) log(w);\n }\n\n try {\n let image: Image = Image.fromDockerfile(ctx.dockerfile);\n\n // Overlay the daytona-specific /etc/claude-code/CLAUDE.md on top of the\n // docker-shaped one baked by Dockerfile.box. Daytona boxes have no host\n // .git/ bind-mount, so the in-box hint needs daytona-specific git wording.\n image = image.addLocalFile(daytonaClaudeMd, '/tmp/agentbox-custom-CLAUDE.md');\n const extractCmds: string[] = [\n 'install -m 0644 /tmp/agentbox-custom-CLAUDE.md /etc/claude-code/CLAUDE.md',\n 'rm -f /tmp/agentbox-custom-CLAUDE.md',\n ];\n\n // For each agent whose stage produced a tarball, add the file to the\n // image build context and append a single tar-extract + chown.\n const usable = stages.filter((s) => s.staged.tarballPath !== null);\n for (const s of usable) {\n image = image.addLocalFile(s.staged.tarballPath as string, s.remoteTar);\n extractCmds.push(`mkdir -p ${s.extractDir}`);\n extractCmds.push(`tar -xzf ${s.remoteTar} -C ${s.extractDir}`);\n }\n if (usable.length > 0) {\n // One final pass: own the extracted trees as the box user, then drop the\n // staging tarballs (no point shipping them twice in the image layer).\n extractCmds.push(\n 'chown -R vscode:vscode /home/vscode/.claude /home/vscode/.codex /home/vscode/.local',\n );\n extractCmds.push('rm -f /tmp/agentbox-seed-*.tar.gz');\n }\n // Dockerfile.box ends with `USER vscode`. Switch to root for the\n // install/tar/chown/rm pass — COPYed files are root-owned in /tmp (sticky\n // bit), chown -R on /home/vscode/.* only works as root, and\n // /etc/claude-code is root-owned. Switch back to vscode so the image\n // keeps its default-user invariant.\n image = image\n .dockerfileCommands(['USER root'])\n .runCommands(...extractCmds)\n .dockerfileCommands(['USER vscode']);\n\n const client = getClient();\n log(`creating Daytona snapshot '${snapshotName}'…`);\n const snapshot = await client.snapshot.create(\n { name: snapshotName, image },\n {\n onLogs: (chunk: string) => log(String(chunk).split('\\n').filter(Boolean).join(' ')),\n },\n );\n log(`snapshot '${snapshot.name}' is ${snapshot.state ?? 'created'}`);\n if (fingerprint) {\n writePreparedDaytonaState({\n snapshotName: snapshot.name ?? snapshotName,\n contextSha256: fingerprint.contextSha256,\n });\n log(\n `recorded daytona-prepared.json (fingerprint ${fingerprint.contextSha256.slice(0, 12)})`,\n );\n }\n return { snapshotName: snapshot.name ?? snapshotName };\n } finally {\n await Promise.all(stages.map((s) => s.staged.cleanup()));\n }\n}\n","/**\n * Read-only status helpers for `agentbox prepare` (no-args mode). Surfaces\n * the user-facing inventory of agentbox-owned base images / snapshots /\n * volumes on the configured Daytona org so the user can see at a glance\n * what's already prepared and what isn't.\n *\n * Daytona-side state lives in two places:\n * - **Snapshots** — built by `agentbox prepare --provider daytona`. Listed\n * filtered to `agentbox*` so we don't surface unrelated org snapshots.\n * - **Volumes** — the per-org `agentbox-credentials` volume created lazily\n * by `ensureAgentVolumesForCloud` on first `agentbox create --provider\n * daytona`.\n *\n * All calls swallow auth/network errors and return an empty section — the\n * status command must work for users who don't have Daytona configured.\n */\n\nimport { ensureDaytonaEnvLoaded } from './env-loader.js';\nimport { getClient } from './backend.js';\n\nexport interface DaytonaSnapshotSummary {\n name: string;\n state?: string;\n /** Snapshot size in GB, as reported by Daytona (may be undefined for non-`active` states). */\n sizeGb?: number;\n createdAt?: string;\n errorReason?: string;\n}\n\nexport interface DaytonaVolumeSummary {\n name: string;\n id: string;\n state?: string;\n createdAt?: string;\n lastUsedAt?: string;\n}\n\nexport interface DaytonaStatus {\n /** True when Daytona credentials are present + the SDK could connect. */\n configured: boolean;\n /** Snapshots whose name starts with `agentbox` (case-insensitive). */\n snapshots: DaytonaSnapshotSummary[];\n /** Volumes whose name starts with `agentbox` (case-insensitive). */\n volumes: DaytonaVolumeSummary[];\n /** Non-fatal explanation when `configured` is false. */\n reason?: string;\n}\n\nfunction isAgentboxName(name: unknown): boolean {\n return typeof name === 'string' && name.toLowerCase().startsWith('agentbox');\n}\n\n/**\n * Collect a read-only summary of agentbox-owned snapshots + volumes on the\n * Daytona org. Never throws — failure paths return `configured: false` with\n * a one-line reason.\n */\nexport async function getDaytonaStatus(): Promise<DaytonaStatus> {\n try {\n ensureDaytonaEnvLoaded();\n } catch (err) {\n return {\n configured: false,\n snapshots: [],\n volumes: [],\n reason: err instanceof Error ? err.message : String(err),\n };\n }\n\n let client;\n try {\n client = getClient();\n } catch (err) {\n return {\n configured: false,\n snapshots: [],\n volumes: [],\n reason: err instanceof Error ? err.message.split('\\n')[0] : String(err),\n };\n }\n\n const snapshots: DaytonaSnapshotSummary[] = [];\n const volumes: DaytonaVolumeSummary[] = [];\n let reason: string | undefined;\n\n try {\n const list = await client.snapshot.list();\n const items = (list as { items?: unknown[] }).items ?? (Array.isArray(list) ? list : []);\n for (const s of items) {\n const dto = s as { name?: unknown; state?: unknown; size?: unknown; createdAt?: unknown; errorReason?: unknown };\n if (!isAgentboxName(dto.name)) continue;\n snapshots.push({\n name: dto.name as string,\n state: typeof dto.state === 'string' ? dto.state : undefined,\n sizeGb: typeof dto.size === 'number' ? dto.size : undefined,\n createdAt: typeof dto.createdAt === 'string' ? dto.createdAt : undefined,\n errorReason: typeof dto.errorReason === 'string' ? dto.errorReason : undefined,\n });\n }\n } catch (err) {\n reason = `snapshot list failed: ${err instanceof Error ? err.message.split('\\n')[0] : String(err)}`;\n }\n\n try {\n const list = await client.volume.list();\n const items: unknown[] = Array.isArray(list)\n ? list\n : ((list as { items?: unknown[] }).items ?? []);\n for (const v of items) {\n const dto = v as { name?: unknown; id?: unknown; state?: unknown; createdAt?: unknown; lastUsedAt?: unknown };\n if (!isAgentboxName(dto.name)) continue;\n volumes.push({\n name: dto.name as string,\n id: typeof dto.id === 'string' ? dto.id : '',\n state: typeof dto.state === 'string' ? dto.state : undefined,\n createdAt: typeof dto.createdAt === 'string' ? dto.createdAt : undefined,\n lastUsedAt: typeof dto.lastUsedAt === 'string' ? dto.lastUsedAt : undefined,\n });\n }\n } catch (err) {\n const msg = `volume list failed: ${err instanceof Error ? err.message.split('\\n')[0] : String(err)}`;\n reason = reason ? `${reason}; ${msg}` : msg;\n }\n\n return {\n configured: true,\n snapshots: snapshots.sort((a, b) => (b.createdAt ?? '').localeCompare(a.createdAt ?? '')),\n volumes: volumes.sort((a, b) => a.name.localeCompare(b.name)),\n reason,\n };\n}\n"],"mappings":"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","names":[]}
@@ -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-B4QG2MCW.js";
223
+ } from "./chunk-TCS5HXJX.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-SNTHHWKY.js";
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-OG6NW6SM.js.map
501
+ //# sourceMappingURL=dist-4DPOL5A7.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
- secretsPath
14
- } from "./chunk-ECLLV5JH.js";
20
+ resolveRuntimeAssets,
21
+ secretsPath,
22
+ updatePreparedState,
23
+ writePreparedState
24
+ } from "./chunk-VATTS2MR.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-4NQXNQ53.js";
33
+ } from "./chunk-TBSIJVSN.js";
23
34
  import {
24
- stageClaudeCredentialsForUpload,
25
35
  stageClaudeStaticForUpload,
26
- stageCodexCredentialsForUpload,
27
36
  stageCodexStaticForUpload,
28
- stageOpencodeCredentialsForUpload,
29
37
  stageOpencodeStaticForUpload
30
- } from "./chunk-B4QG2MCW.js";
38
+ } from "./chunk-TCS5HXJX.js";
31
39
  import {
32
40
  computeContextSha256,
33
- preparedStatePathFor,
34
41
  readCliStamp,
35
- readPreparedStateRaw,
36
- recordBox,
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-JAN5VABY.js.map
722
+ //# sourceMappingURL=dist-57M6ZA7H.js.map