@madarco/agentbox 0.15.0 → 0.16.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 (65) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/dist/{_cloud-attach-R6TRWG5L.js → _cloud-attach-5KJWOASL.js} +4 -4
  3. package/dist/{chunk-RSKG7AFU.js → chunk-3WCEB6RE.js} +2 -2
  4. package/dist/{chunk-XKH7NTT7.js → chunk-DBBUDKKB.js} +248 -5
  5. package/dist/chunk-DBBUDKKB.js.map +1 -0
  6. package/dist/{chunk-MLMFNN4T.js → chunk-GXJNJUEV.js} +688 -197
  7. package/dist/chunk-GXJNJUEV.js.map +1 -0
  8. package/dist/{chunk-MCOU6CZS.js → chunk-NW2UZQV6.js} +10 -6
  9. package/dist/chunk-NW2UZQV6.js.map +1 -0
  10. package/dist/{chunk-E7CHS7ZR.js → chunk-PIK47622.js} +18 -6
  11. package/dist/chunk-PIK47622.js.map +1 -0
  12. package/dist/{chunk-BKU34KYY.js → chunk-QXFNLKJJ.js} +9 -3
  13. package/dist/{chunk-BKU34KYY.js.map → chunk-QXFNLKJJ.js.map} +1 -1
  14. package/dist/{chunk-43Q5GWP6.js → chunk-SB4QTF2T.js} +7 -7
  15. package/dist/{chunk-72CJTXN6.js → chunk-SENASAU4.js} +10 -6
  16. package/dist/{chunk-72CJTXN6.js.map → chunk-SENASAU4.js.map} +1 -1
  17. package/dist/{dist-JZ3XO6EB.js → dist-4IQFJJQI.js} +5 -5
  18. package/dist/{dist-OGJGZETZ.js → dist-7YB7BMNG.js} +5 -5
  19. package/dist/{dist-FIFEFKJ7.js → dist-SL2QSMBE.js} +5 -5
  20. package/dist/{dist-AGTIA7AD.js → dist-VHI5QOSQ.js} +6 -6
  21. package/dist/{dist-S4XR4ACV.js → dist-XC47DSCR.js} +5 -5
  22. package/dist/index.js +210 -68
  23. package/dist/index.js.map +1 -1
  24. package/dist/{prepared-state-MQHD3M5F-Q27AZU53.js → prepared-state-MQHD3M5F-2LANTRL7.js} +2 -2
  25. package/package.json +5 -4
  26. package/runtime/docker/Dockerfile.box +21 -2
  27. package/runtime/docker/apps/cli/share/agentbox-setup/SKILL.md +82 -29
  28. package/runtime/docker/packages/ctl/dist/bin.cjs +10675 -9191
  29. package/runtime/docker/packages/sandbox-docker/scripts/agentbox-checkpoint-cleanup +5 -2
  30. package/runtime/docker/packages/sandbox-docker/scripts/linear-shim +181 -0
  31. package/runtime/docker/packages/sandbox-docker/scripts/ntn-shim +95 -0
  32. package/runtime/e2b/agentbox-checkpoint-cleanup +5 -2
  33. package/runtime/e2b/agentbox-setup-skill.md +82 -29
  34. package/runtime/e2b/ctl.cjs +10675 -9191
  35. package/runtime/e2b/linear-shim +181 -0
  36. package/runtime/e2b/ntn-shim +95 -0
  37. package/runtime/e2b/scripts/build-template.sh +13 -7
  38. package/runtime/hetzner/agentbox-checkpoint-cleanup +5 -2
  39. package/runtime/hetzner/agentbox-setup-skill.md +82 -29
  40. package/runtime/hetzner/ctl.cjs +10675 -9191
  41. package/runtime/hetzner/linear-shim +181 -0
  42. package/runtime/hetzner/ntn-shim +95 -0
  43. package/runtime/hetzner/scripts/install-box.sh +19 -9
  44. package/runtime/relay/bin.cjs +3696 -2895
  45. package/runtime/vercel/agentbox-checkpoint-cleanup +5 -2
  46. package/runtime/vercel/agentbox-setup-skill.md +82 -29
  47. package/runtime/vercel/ctl.cjs +10675 -9191
  48. package/runtime/vercel/linear-shim +181 -0
  49. package/runtime/vercel/ntn-shim +95 -0
  50. package/runtime/vercel/scripts/provision.sh +13 -7
  51. package/share/agentbox-setup/SKILL.md +82 -29
  52. package/share/host-skills/agentbox-info/SKILL.md +1 -1
  53. package/dist/chunk-E7CHS7ZR.js.map +0 -1
  54. package/dist/chunk-MCOU6CZS.js.map +0 -1
  55. package/dist/chunk-MLMFNN4T.js.map +0 -1
  56. package/dist/chunk-XKH7NTT7.js.map +0 -1
  57. /package/dist/{_cloud-attach-R6TRWG5L.js.map → _cloud-attach-5KJWOASL.js.map} +0 -0
  58. /package/dist/{chunk-RSKG7AFU.js.map → chunk-3WCEB6RE.js.map} +0 -0
  59. /package/dist/{chunk-43Q5GWP6.js.map → chunk-SB4QTF2T.js.map} +0 -0
  60. /package/dist/{dist-JZ3XO6EB.js.map → dist-4IQFJJQI.js.map} +0 -0
  61. /package/dist/{dist-OGJGZETZ.js.map → dist-7YB7BMNG.js.map} +0 -0
  62. /package/dist/{dist-FIFEFKJ7.js.map → dist-SL2QSMBE.js.map} +0 -0
  63. /package/dist/{dist-AGTIA7AD.js.map → dist-VHI5QOSQ.js.map} +0 -0
  64. /package/dist/{dist-S4XR4ACV.js.map → dist-XC47DSCR.js.map} +0 -0
  65. /package/dist/{prepared-state-MQHD3M5F-Q27AZU53.js.map → prepared-state-MQHD3M5F-2LANTRL7.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../packages/sandbox-cloud/src/cloud-provider.ts","../../../packages/sandbox-cloud/src/agent-credentials.ts","../../../packages/sandbox-cloud/src/dynamic-sync.ts","../../../packages/sandbox-cloud/src/claude-json-overlay.ts","../../../packages/sandbox-cloud/src/git-identity.ts","../../../packages/sandbox-cloud/src/shell.ts","../../../packages/sandbox-cloud/src/checkpoint.ts","../../../packages/sandbox-cloud/src/snapshot-error.ts","../../../packages/sandbox-cloud/src/env-files.ts","../../../packages/sandbox-cloud/src/carry.ts","../../../packages/sandbox-cloud/src/expose-ports.ts","../../../packages/sandbox-cloud/src/cloud-cp.ts","../../../packages/sandbox-cloud/src/ctl-launch.ts","../../../packages/sandbox-cloud/src/dockerd-launch.ts","../../../packages/sandbox-cloud/src/vnc-launch.ts","../../../packages/sandbox-cloud/src/workspace-seed.ts","../../../packages/sandbox-cloud/src/mock-backend.ts","../../../packages/sandbox-cloud/src/index.ts"],"sourcesContent":["/**\n * `createCloudProvider(backend)` — composes a full `Provider` from a thin\n * `CloudBackend`. Every cloud backend (Daytona, future Vercel, …) reuses this\n * scaffolding instead of re-implementing workspace seeding, ctl launch, state\n * persistence, URL resolution, etc.\n *\n * v0 covers create / lifecycle / probe / exec / resolveUrl on top of the\n * `CloudBackend` primitives. The host-poller comms layer (queued git.push,\n * status event mirroring, prompts) is Phase 4 — until then a cloud box's\n * `agentbox-ctl` runs without a relay, and host-only RPCs surface a clear\n * \"no relay configured\" error.\n */\n\nimport { basename } from 'node:path';\nimport { generateBoxId } from '@agentbox/core';\nimport type {\n AttachKind,\n AttachSpec,\n BoxRecord,\n BoxResourceStats,\n BoxRuntimeState,\n BuildAttachOptions,\n CloudBackend,\n CloudHandle,\n CreateBoxRequest,\n CreatedBox,\n ExecOptions,\n ExecResult,\n InspectedBox,\n Provider,\n ProviderCheckpoint,\n} from '@agentbox/core';\nimport {\n allocateProjectIndex,\n readCliStamp,\n readState,\n recordBox,\n removeBoxRecord,\n} from '@agentbox/sandbox-core';\nimport {\n buildTmuxConfigShellSnippet,\n ensureRelay,\n forgetBoxFromRelay,\n generateRelayToken,\n generateVncPassword,\n portlessAlias,\n portlessGetUrl,\n portlessUnalias,\n registerBoxWithRelay,\n} from '@agentbox/sandbox-docker';\nimport {\n ensureAgentVolumesForCloud,\n extractCloudAgentCredentials,\n refreshAgentCredentialsBackup,\n seedAgentVolumesIfFresh,\n seedOpencodeModelState,\n} from './agent-credentials.js';\nimport { seedDynamicConfig } from './dynamic-sync.js';\nimport { seedClaudeJsonAtCreate } from './claude-json-overlay.js';\nimport { seedGitIdentity } from './git-identity.js';\nimport {\n cloudSnapshotName,\n currentCloudBaseFingerprint,\n listCloudCheckpoints,\n removeCloudCheckpointDir,\n resolveCloudCheckpoint,\n writeCloudCheckpointManifest,\n} from './checkpoint.js';\nimport { loadEffectiveConfig } from '@agentbox/config';\nimport { isSnapshotGoneError } from './snapshot-error.js';\nimport { uploadEnvFiles } from './env-files.js';\nimport { uploadCarryPaths } from './carry.js';\nimport { readExposedServicePorts } from './expose-ports.js';\nimport { downloadFromCloudBox, pullCloudDirContents, uploadToCloudBox } from './cloud-cp.js';\nimport { launchCloudCtlDaemon } from './ctl-launch.js';\nimport { launchCloudDockerdDaemon } from './dockerd-launch.js';\nimport { quoteShellArgv } from './shell.js';\nimport { launchCloudVncDaemon } from './vnc-launch.js';\nimport { seedCloudWorkspace } from './workspace-seed.js';\n\n/** Workspace mount path inside every cloud sandbox. Matches the Docker model. */\nexport const CLOUD_WORKSPACE_DIR = '/workspace';\n/**\n * In-box port the supervisor's WebProxy binds to. Matches `RESERVED_WEB_PORT`\n * in `@agentbox/ctl` (the only container port AgentBox publishes) — node has\n * `cap_net_bind_service` set in both the Docker and Hetzner base images so the\n * bind to <1024 needs no root. Daytona's base image inherits the same setcap\n * via Dockerfile.box.\n */\nexport const CLOUD_WEB_PROXY_PORT = 80;\n/** In-box port the noVNC viewer (websockify) serves on — fixed by Dockerfile.box. */\nexport const CLOUD_VNC_PORT = 6080;\n/**\n * Default expiry for browser-bound signed preview URLs. 1h matches Daytona's\n * docs recommendation: long enough for one CLI invocation + browser session,\n * short enough that a stale link doesn't outlive the box. Override with the\n * CLI `--ttl` flag when sharing or running long-lived sessions.\n */\nexport const DEFAULT_SIGNED_URL_TTL_SECONDS = 3600;\n\n/**\n * Provider-neutral image selector. Cloud backends typically resolve it to a\n * snapshot ref (Daytona) or a registry image. Backends may translate it via\n * `provisionImage` (see `CreateCloudProviderOptions`).\n */\nexport interface CreateCloudProviderOptions {\n /**\n * Translate the request's image to a backend-specific image / snapshot ref.\n * When omitted the backend is handed `req.image` verbatim (or the v0 default\n * `agentbox/box:dev`, which most cloud backends won't be able to resolve —\n * Daytona uses its snapshot helper here).\n */\n provisionImage?(req: CreateBoxRequest): Promise<string>;\n /**\n * Per-create cloud resource ceiling. Default: 2 cpu / 4 GiB / 8 GiB disk.\n */\n defaultResources?: { cpu?: number; memory?: number; disk?: number };\n /**\n * Whether to launch the in-box `dockerd` daemon on create/start. Default\n * true (Daytona/Hetzner support nested containers). Vercel Sandbox blocks the\n * namespace syscalls a container runtime needs, so its provider sets this\n * false — otherwise every create/start logs a spurious dockerd failure.\n */\n launchDockerd?: boolean;\n}\n\nconst FALLBACK_IMAGE = 'agentbox/box:dev';\n\n/** Default Portless no-TLS proxy port — matches the host wizard's choice. */\nconst DEFAULT_PORTLESS_PROXY_PORT = 1355;\n\n/**\n * Parse a host portless preview URL like `http://my-box.localhost:1355` /\n * `https://my-box.localhost` into the proxy mode the in-VPS mirror should\n * match. Returns `undefined` when the URL isn't a `*.localhost` portless URL\n * (e.g. portless isn't installed and we fell back to a loopback URL).\n */\nfunction parsePortlessUrl(url: string): { proxyPort: number; tls: boolean } | undefined {\n try {\n const u = new URL(url);\n if (!u.hostname.endsWith('.localhost')) return undefined;\n const tls = u.protocol === 'https:';\n const proxyPort = u.port ? Number.parseInt(u.port, 10) : tls ? 443 : 80;\n if (!Number.isFinite(proxyPort)) return undefined;\n return { proxyPort, tls };\n } catch {\n return undefined;\n }\n}\n\n/**\n * Parse a loopback `http://127.0.0.1:<N>` URL into its port. Returns\n * `undefined` for any non-loopback URL (Daytona-style public URLs naturally\n * skip the Portless alias path).\n */\nfunction parseLoopbackPort(url: string): number | undefined {\n try {\n const u = new URL(url);\n if (u.hostname !== '127.0.0.1' && u.hostname !== 'localhost') return undefined;\n const port = Number.parseInt(u.port, 10);\n return Number.isFinite(port) ? port : undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Register a single host Portless alias `<alias>.localhost -> <previewUrl>`\n * when `previewUrl` resolves to a loopback `http://127.0.0.1:<port>` (Hetzner's\n * `ssh -L` forward). For backends that return a public URL (Daytona's signed\n * preview) the alias is naturally skipped. Best-effort: every Portless call\n * already swallows; we never throw from here. Returns the resolved URL on\n * success.\n */\nasync function registerHostPortlessAlias(args: {\n alias: string;\n previewUrl: string;\n label: string;\n onLog: (line: string) => void;\n}): Promise<string | undefined> {\n const localPort = parseLoopbackPort(args.previewUrl);\n if (localPort === undefined) return undefined;\n const ok = await portlessAlias(args.alias, localPort);\n if (!ok) {\n args.onLog(\n `portless: ${args.label} alias not registered (portless CLI missing or not running) — host URL stays http://127.0.0.1:${String(localPort)}`,\n );\n return undefined;\n }\n const url = await portlessGetUrl(args.alias);\n args.onLog(`portless alias ${url} -> 127.0.0.1:${String(localPort)}`);\n return url;\n}\n\n/**\n * Register the host Portless alias for `<boxName>.localhost -> <webPreviewUrl>`\n * and bring up the in-VPS mirror proxy so the same URL works from inside the\n * box. Best-effort: every step is gated on a previous step's success, and any\n * failure logs but doesn't throw. Returns `{ alias, url }` when the host alias\n * landed (so the caller can persist it on the BoxRecord), `undefined` otherwise.\n */\nasync function bootstrapPortlessForCloudBox(\n backend: CloudBackend,\n handle: CloudHandle,\n args: { boxName: string; webPreviewUrl: string; webPort: number; onLog: (line: string) => void },\n): Promise<{ alias: string; url: string } | undefined> {\n const url = await registerHostPortlessAlias({\n alias: args.boxName,\n previewUrl: args.webPreviewUrl,\n label: 'web',\n onLog: args.onLog,\n });\n if (!url) return undefined;\n if (backend.startInBoxPortless) {\n const mode = parsePortlessUrl(url) ?? { proxyPort: DEFAULT_PORTLESS_PROXY_PORT, tls: false };\n try {\n await backend.startInBoxPortless(handle, {\n boxName: args.boxName,\n proxyPort: mode.proxyPort,\n tls: mode.tls,\n webPort: args.webPort,\n });\n args.onLog(\n `portless: in-box mirror up on 127.0.0.1:${String(mode.proxyPort)} (${mode.tls ? 'https' : 'http'})`,\n );\n } catch (err) {\n args.onLog(\n `portless: in-box mirror failed (continuing): ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n return { alias: args.boxName, url };\n}\n\nexport function createCloudProvider(\n backend: CloudBackend,\n opts: CreateCloudProviderOptions = {},\n): Provider {\n const providerName = backend.name;\n\n function handleFor(box: BoxRecord): CloudHandle {\n const sandboxId = box.cloud?.sandboxId;\n if (!sandboxId) {\n throw new Error(`cloud box ${box.name} has no sandboxId — record is malformed`);\n }\n return { sandboxId };\n }\n\n /** Resolve a fresh per-cloud-box id + name + branch. */\n function mintBox(req: CreateBoxRequest): {\n id: string;\n name: string;\n branch: string;\n } {\n const id = generateBoxId();\n const name = req.name ?? `${basename(req.workspacePath)}-${id}`;\n return {\n id,\n name,\n // --use-branch reuses the named branch directly; otherwise fork a fresh\n // per-box branch. The CLI validated `useBranch` exists host-side.\n branch: req.useBranch ?? `agentbox/${name}`,\n };\n }\n\n async function probe(box: BoxRecord): Promise<BoxRuntimeState> {\n try {\n const h = handleFor(box);\n const state = await backend.state(h);\n // CloudState aligns with BoxRuntimeState by construction.\n return state;\n } catch {\n return 'missing';\n }\n }\n\n /**\n * Persist the last host-driven lifecycle state so `agentbox list`/`top`/the\n * dashboard can show it without a live SDK probe. `pause`/`stop` persist\n * `paused` (matches vercel/hetzner's stopped→paused; daytona's authoritative\n * `stopped` only shows under `--live`). Best-effort — a state-write failure\n * must not fail the lifecycle op itself.\n */\n async function persistLastState(box: BoxRecord, lastState: BoxRuntimeState): Promise<void> {\n if (!box.cloud) return;\n try {\n await recordBox({ ...box, cloud: { ...box.cloud, lastState } });\n } catch {\n // listBoxes falls back to the previous value; not worth failing stop/pause.\n }\n }\n\n // Re-ensure a freshly-woken cloud box. A resumed/restarted sandbox boots\n // fresh: its in-box processes are gone and (on some backends) preview URLs\n // rotate. Refresh the web/service/relay preview URLs, re-register host\n // portless aliases, persist the record, relaunch the in-box daemons\n // (ctl daemon -> in-box bridge + the agentbox.yaml tasks/services, dockerd,\n // VNC), and re-register with the host relay. Shared by `start()` (after\n // `backend.start`) and `resume()` (after `backend.resume`) so EVERY wake path\n // brings the box fully back, not just attach. Idempotent — the `launch*`\n // helpers no-op when the daemon is already alive.\n async function reEnsureCloudBox(box: BoxRecord, h: CloudHandle): Promise<BoxRecord> {\n // Preview URLs (and their tokens) can rotate across stop/start — refresh\n // the web + relay preview URLs and persist so `agentbox url` and the\n // host poller see the live values.\n const webPort = box.cloud?.webPort ?? backend.webProxyPort ?? CLOUD_WEB_PROXY_PORT;\n let webPreview: { url: string; token?: string } | undefined;\n try {\n webPreview = await backend.previewUrl(h, webPort);\n } catch {\n const cached = box.cloud?.previewUrls?.[webPort];\n webPreview = cached ? { url: cached } : undefined;\n }\n // Re-mint per-service preview URLs from `agentbox.yaml`. Daytona's\n // preview URLs rotate when a sandbox restarts, so any cached ports\n // need to be re-resolved against the live handle.\n const servicePreviews: Record<number, string> = {};\n try {\n const ports = await readExposedServicePorts(box.workspacePath);\n for (const port of ports) {\n if (port === webPort) continue;\n try {\n const p = await backend.previewUrl(h, port);\n servicePreviews[port] = p.url;\n } catch {\n // skip — falls back to cached value below if any\n }\n }\n } catch {\n // workspace path missing / yaml unreadable: keep cached previewUrls\n }\n let relayPreview: { url: string; token?: string } | undefined;\n try {\n relayPreview = await backend.previewUrl(h, 8788);\n } catch {\n relayPreview = box.cloud?.relayPreviewUrl\n ? { url: box.cloud.relayPreviewUrl, token: box.cloud.relayPreviewToken }\n : undefined;\n }\n // Build the refreshed preview map: keep cached values for ports we\n // couldn't re-resolve, overlay fresh URLs from this start.\n const mergedPreviews: Record<number, string> = {\n ...(box.cloud?.previewUrls ?? {}),\n ...servicePreviews,\n };\n if (webPreview !== undefined) mergedPreviews[webPort] = webPreview.url;\n\n // Portless: the `ssh -L` local port is fresh after `agentbox start`\n // (pickFreePort picks again), and the in-VPS portless proxy died with\n // the VPS. Re-register the host alias against the new local port and\n // bring the in-box mirror back up. Skipped when no host portless alias\n // was set originally (user opted out at create) or when the URL is\n // non-loopback (Daytona).\n let portlessAliasName: string | undefined = box.portlessAlias;\n let portlessUrlResolved: string | undefined = box.portlessUrl;\n if (box.portlessAlias && webPreview) {\n const r = await bootstrapPortlessForCloudBox(backend, h, {\n boxName: box.name,\n webPreviewUrl: webPreview.url,\n webPort,\n onLog: () => {},\n });\n if (r) {\n portlessAliasName = r.alias;\n portlessUrlResolved = r.url;\n }\n }\n // Same story for the VNC alias — the ssh -L port for 6080 is fresh.\n // Best-effort, silent (startBox has no onLog). Skipped when no VNC\n // alias was set at create.\n let portlessVncAliasName: string | undefined = box.portlessVncAlias;\n let portlessVncUrlResolved: string | undefined = box.portlessVncUrl;\n if (box.portlessVncAlias && box.vncEnabled) {\n try {\n const vncPreview = await backend.previewUrl(h, CLOUD_VNC_PORT);\n const url = await registerHostPortlessAlias({\n alias: box.portlessVncAlias,\n previewUrl: vncPreview.url,\n label: 'vnc',\n onLog: () => {},\n });\n if (url) {\n portlessVncAliasName = box.portlessVncAlias;\n portlessVncUrlResolved = url;\n }\n } catch {\n /* best-effort */\n }\n }\n\n const next: BoxRecord = {\n ...box,\n portlessAlias: portlessAliasName,\n portlessUrl: portlessUrlResolved,\n portlessVncAlias: portlessVncAliasName,\n portlessVncUrl: portlessVncUrlResolved,\n cloud: {\n ...(box.cloud ?? { backend: providerName, sandboxId: h.sandboxId }),\n webPort,\n previewUrls: Object.keys(mergedPreviews).length > 0 ? mergedPreviews : undefined,\n relayPreviewUrl: relayPreview?.url ?? box.cloud?.relayPreviewUrl,\n relayPreviewToken: relayPreview?.token ?? box.cloud?.relayPreviewToken,\n // reEnsureCloudBox only runs on a freshly-woken box (start/resume), so\n // the box is now running — persist it for the fast `agentbox list` path.\n lastState: 'running',\n },\n };\n await recordBox(next);\n // Re-launch in-box dockerd — it dies with the sandbox. Done BEFORE the ctl\n // supervisor (mirrors the docker provider's startBox) so a docker-based\n // agentbox.yaml service doesn't race a not-yet-ready socket on resume.\n // launchCloudDockerdDaemon blocks until ready. Best-effort. Skipped for\n // backends that can't run nested containers (vercel).\n if (opts.launchDockerd !== false) {\n try {\n const dockerd = await launchCloudDockerdDaemon({ backend, handle: h, timeoutMs: 60_000 });\n if (!dockerd.up) {\n // swallowed; surface only on follow-up `docker info`\n }\n } catch {\n // best-effort\n }\n }\n // Re-launch the ctl daemon — it dies with the sandbox.\n await launchCloudCtlDaemon({\n backend,\n handle: h,\n boxId: box.id,\n boxName: box.name,\n relayUrl: `http://127.0.0.1:${String(8788)}`,\n relayToken: box.relayToken ?? '',\n bridgeToken: box.cloud?.bridgeToken,\n webProxyPort: backend.webProxyPort,\n });\n // Re-launch the VNC stack — Xvnc + websockify die with the sandbox.\n // Best-effort: a failure here shouldn't block start; `agentbox screen`\n // surfaces the missing daemon with a clear error.\n if (box.vncEnabled && box.vncPassword) {\n try {\n await launchCloudVncDaemon({ backend, handle: h, vncPassword: box.vncPassword });\n } catch {\n // swallowed; user-visible error comes from `agentbox screen` if it\n // can't reach websockify after a few retries.\n }\n }\n // Re-register with the host relay so its CloudBoxPoller picks up the\n // fresh preview URL/token.\n if (relayPreview && box.relayToken && box.cloud?.bridgeToken) {\n try {\n await registerBoxWithRelay({\n boxId: box.id,\n token: box.relayToken,\n name: box.name,\n kind: 'cloud',\n backend: backend.name,\n previewUrl: relayPreview.url,\n previewToken: relayPreview.token,\n bridgeToken: box.cloud.bridgeToken,\n createdAt: box.createdAt,\n projectIndex: box.projectIndex,\n autoApproveHostActions: box.autoApproveHostActions,\n });\n } catch {\n // best-effort\n }\n }\n return next;\n }\n\n return {\n name: providerName,\n\n async create(req: CreateBoxRequest): Promise<CreatedBox> {\n const log = req.onLog ?? (() => {});\n const { id, name, branch } = mintBox(req);\n const image = opts.provisionImage\n ? await opts.provisionImage(req)\n : (req.image ?? FALLBACK_IMAGE);\n // Per-create overrides (currently vercel's box.vercelVcpus / vercelTimeoutMs,\n // threaded through providerOptions). Fall back to the provider's static\n // defaults so daytona/hetzner are unaffected.\n const baseResources = opts.defaultResources ?? { cpu: 2, memory: 4, disk: 8 };\n const vcpuOverride = req.providerOptions?.['vcpus'];\n const resources =\n typeof vcpuOverride === 'number' && vcpuOverride > 0\n ? { ...baseResources, cpu: vcpuOverride }\n : baseResources;\n const timeoutOverride = req.providerOptions?.['timeoutMs'];\n const timeoutMs =\n typeof timeoutOverride === 'number' && timeoutOverride > 0 ? timeoutOverride : undefined;\n const networkPolicyOpt = req.providerOptions?.['networkPolicy'];\n const networkPolicy =\n typeof networkPolicyOpt === 'string' && networkPolicyOpt.trim() !== ''\n ? networkPolicyOpt.trim()\n : undefined;\n // Generic VM-size string, resolved per-provider by the call site\n // (`resolveBoxSize` + `--size` flag). Each backend interprets it natively\n // (hetzner: server type; daytona: cpu-mem-disk GB); empty/undefined ⇒\n // backend uses its built-in default.\n const sizeOpt = req.providerOptions?.['size'];\n const size =\n typeof sizeOpt === 'string' && sizeOpt.trim() !== '' ? sizeOpt.trim() : undefined;\n\n // Per-box tokens: `relayToken` authenticates the in-box agent to its\n // in-sandbox relay (`/events`, `/rpc` bearer); `bridgeToken` separately\n // authenticates the HOST poller to the in-sandbox relay's `/bridge/*`\n // routes. Distinct so a compromised agent can't impersonate the host.\n const relayToken = generateRelayToken();\n const bridgeToken = generateRelayToken();\n\n // Bring the host relay up before we provision — registering the box\n // (and starting its CloudBoxPoller) happens at the bottom of this\n // function, and the loop wants the host relay reachable.\n try {\n await ensureRelay({ onLog: log });\n } catch (err) {\n log(\n `relay ensure failed (continuing): ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n\n // Resolve any cloud checkpoint the caller requested. When found, we\n // boot from the snapshot (which already carries /workspace + any\n // installed deps) instead of from the base image, and skip the\n // workspace-seeding step below. A `checkpointRef` set for a checkpoint\n // that doesn't exist for THIS backend is logged and silently dropped —\n // matches the wizard's provider-aware behavior (the user may have a\n // Docker checkpoint with the same name; that's not our store).\n let snapshotName: string | undefined;\n let resolvedCheckpointRef: string | undefined;\n if (req.checkpointRef && req.projectRoot) {\n const found = await resolveCloudCheckpoint(\n req.projectRoot,\n backend.name,\n req.checkpointRef,\n );\n if (found) {\n snapshotName = found.manifest.snapshotName;\n resolvedCheckpointRef = found.name;\n log(`provisioning from cloud checkpoint '${found.name}' (snapshot ${snapshotName})`);\n } else {\n log(\n `cloud checkpoint '${req.checkpointRef}' not found for ${backend.name}; provisioning from base image`,\n );\n }\n }\n\n // Reserve per-agent credential volumes (Claude / Codex / OpenCode)\n // before provision so we can pass them as mounts in the same SDK call —\n // Daytona only attaches volumes at create time, not after. Backends\n // without a volume primitive return an empty list and we degrade to\n // \"user logs in inside the box\" the way cloud worked before.\n const agentVolumes = await ensureAgentVolumesForCloud(backend, { onLog: log });\n\n // Read the `expose:` service ports up front so port-capped backends\n // (vercel) can declare them at create time — a preview URL only routes to\n // a port that was exposed when the sandbox was created. Reused below for\n // the per-service preview-URL map. Best-effort: [] when there's no yaml.\n const exposeServicePorts = await readExposedServicePorts(req.workspacePath);\n\n const provisionEnv = {\n AGENTBOX_BOX_ID: id,\n AGENTBOX_BOX_NAME: name,\n AGENTBOX_BOX_KIND: 'cloud',\n // In-sandbox relay is on the box's loopback at the in-box port.\n // 8788 is distinct from the host relay's 8787 so a nested agentbox\n // run inside the box can claim :8787 without colliding.\n AGENTBOX_RELAY_URL: `http://127.0.0.1:${String(8788)}`,\n AGENTBOX_RELAY_TOKEN: relayToken,\n AGENTBOX_BRIDGE_TOKEN: bridgeToken,\n ...agentVolumes.env,\n };\n const provisionFrom = async (snapshot: string | undefined): Promise<CloudHandle> => {\n log(\n snapshot\n ? `provisioning ${providerName} sandbox from snapshot`\n : `provisioning ${providerName} sandbox`,\n );\n return backend.provision({\n name,\n image,\n snapshot,\n resources,\n size,\n timeoutMs,\n exposePorts: exposeServicePorts,\n networkPolicy,\n env: provisionEnv,\n volumes: agentVolumes.mounts,\n onLog: log,\n });\n };\n\n let handle: CloudHandle;\n try {\n handle = await provisionFrom(snapshotName);\n } catch (err) {\n // The checkpoint snapshot we tried to boot from is gone (expired or\n // deleted out-of-band). Rather than crash, prune the dangling local\n // manifest and fall back to a from-scratch box on the base image —\n // the workspace seed below then runs as if no checkpoint existed.\n // (No fallback for a base-image boot: there's nothing left to retry.)\n if (snapshotName && isSnapshotGoneError(err)) {\n log(\n `checkpoint snapshot '${resolvedCheckpointRef ?? snapshotName}' has expired or been deleted; ` +\n 'starting a fresh box from the base image instead',\n );\n if (req.projectRoot && resolvedCheckpointRef) {\n try {\n await removeCloudCheckpointDir(req.projectRoot, backend.name, resolvedCheckpointRef);\n } catch {\n // best-effort: a stale manifest left behind only re-triggers this\n // same fallback next time, which is still safe.\n }\n }\n snapshotName = undefined;\n resolvedCheckpointRef = undefined;\n handle = await provisionFrom(undefined);\n } else {\n throw err;\n }\n }\n\n try {\n if (snapshotName) {\n // Snapshot already carries /workspace (captured by the source box's\n // `agentbox checkpoint create`). Re-seeding would clobber the\n // user's setup state. Match Docker's `applyCheckpointRef` behavior.\n log('skipping workspace seed — snapshot already contains /workspace');\n } else {\n await seedCloudWorkspace({\n backend,\n handle,\n workspacePath: req.workspacePath,\n branch,\n workspaceDir: CLOUD_WORKSPACE_DIR,\n bundleDepth: req.bundleDepth,\n fromBranch: req.fromBranch,\n useBranch: req.useBranch,\n onLog: log,\n });\n }\n\n // Refresh the host-side credential backups from the docker shared\n // volumes BEFORE seeding — only the docker create path keeps them\n // current, so cloud creates would otherwise push whatever access\n // token the docker volume last extracted (often expired by the time\n // the user attaches). Best-effort: when there's no docker on the host\n // or no shared volume, the helper is a noop and the seed proceeds\n // with whatever backup exists.\n await refreshAgentCredentialsBackup({ onLog: log });\n\n // Seed agent credentials into the box. Volume backends (daytona)\n // mount a per-org volume at `~/.agentbox-creds/<agent>/` and the seed\n // is idempotent via a `.agentbox-seeded-at` marker. Non-volume\n // backends (e2b, vercel, hetzner) push fresh into the box-baked\n // `~/.agentbox-creds/<agent>/` dirs every create — tokens are\n // renewable and the box FS is ephemeral. Either way the symlinks\n // baked into the snapshot (`~/.claude/.credentials.json` ->\n // `~/.agentbox-creds/claude/.credentials.json` etc.) route the\n // agent-expected paths through to the seeded files.\n if (agentVolumes.agents.length > 0) {\n await seedAgentVolumesIfFresh(backend, handle, {\n agents: agentVolumes.agents,\n hostWorkspace: req.workspacePath,\n onLog: log,\n });\n }\n\n // Seed the host's selected OpenCode model into the box's (ephemeral)\n // state dir on every create. Runs unconditionally — Hetzner has no\n // credentials volume, so it is absent from `agentVolumes.agents` above\n // yet still needs the model seeded.\n await seedOpencodeModelState(backend, handle, { onLog: log });\n\n // Overlay the in-box ~/.claude/_claude.json from the host's current\n // ~/.claude.json on every create. Without this, E2B (which doesn't\n // bake _claude.json at prepare-time) shows the first-run theme picker,\n // and vercel/hetzner/daytona inherit whatever onboarding state the\n // host had at prepare-time (stale if the user completed onboarding\n // after `agentbox prepare`). The payload is one tiny JSON file.\n await seedClaudeJsonAtCreate(backend, handle, {\n hostWorkspace: req.workspacePath,\n onLog: log,\n });\n\n // Seed the host's dynamic Claude config — global ~/.claude/workflows/\n // and this project's memory/ — incrementally on every create. Runs on\n // both fresh and checkpoint boots: the box carries a per-file manifest,\n // so a snapshot boot only re-uploads what changed on the host since.\n // Static config (plugins/skills/settings) is baked into the snapshot;\n // these two trees change between runs and ship per-box, like credentials.\n await seedDynamicConfig(backend, handle, { workspacePath: req.workspacePath, onLog: log });\n\n // Configure a git committer identity in the box. Docker inherits the\n // host's via a bind-mounted ~/.gitconfig; cloud boxes have none, so the\n // agent's `git commit` and `agentbox git pull`'s merge commit would\n // fail with \"Committer identity unknown\". Author as the host user when\n // resolvable, else a generic agentbox identity. Runs on both fresh and\n // snapshot boots (idempotent `git config --global`) so a snapshot that\n // didn't capture ~/.gitconfig can't leave the box identity-less.\n await seedGitIdentity(backend, handle, { hostRepo: req.workspacePath, onLog: log });\n\n // Copy the env/config files the setup wizard collected (`.env`,\n // `secrets.toml`, `agentbox.yaml`, …) into `/workspace`. The Docker\n // provider does the same via copyHostEnvFilesToBox; before this hook\n // these files were silently dropped on the cloud path.\n if (req.envFilesToImport && req.envFilesToImport.length > 0) {\n const { copied } = await uploadEnvFiles({\n backend,\n handle,\n workspacePath: req.workspacePath,\n files: req.envFilesToImport,\n workspaceDir: CLOUD_WORKSPACE_DIR,\n onLog: log,\n });\n if (copied > 0) log(`copied ${String(copied)} env/config file(s) into /workspace`);\n }\n\n // carry: from agentbox.yaml — runs after the env-file copies and\n // before the supervisor launches, mirroring the docker provider.\n // The host CLI already resolved + got user approval before threading\n // entries into req.carry.\n let carrySummary:\n | { count: number; entries: Array<{ src: string; dest: string; bytes: number }> }\n | undefined;\n if (req.carry && req.carry.length > 0) {\n log(`carry: copying ${String(req.carry.length)} host path(s) into the box`);\n const result = await uploadCarryPaths({\n backend,\n handle,\n entries: req.carry,\n onLog: log,\n });\n log(`carry: copied ${String(result.copied)}/${String(req.carry.length)} entry/entries`);\n for (const err of result.errors) log(`carry: ${err}`);\n if (result.applied.length > 0) {\n carrySummary = { count: result.applied.length, entries: result.applied };\n }\n }\n\n // Always-on in-box dockerd, matching the Docker provider\n // (packages/sandbox-docker/src/create.ts). Launched (and awaited ready)\n // BEFORE the ctl supervisor: the supervisor starts agentbox.yaml\n // services as soon as it's up, so a docker-based service must not race a\n // not-yet-ready socket. The image already bakes\n // /usr/local/bin/agentbox-dockerd-start; Daytona sandboxes ship with\n // CAP_SYS_ADMIN so it starts cleanly. Best-effort — a slow or failed\n // start shouldn't fail create; `agentbox start` re-launches it on\n // resume because dockerd dies with the sandbox. Skipped for backends\n // that can't run nested containers (vercel), which set launchDockerd:false.\n if (opts.launchDockerd !== false) {\n log('launching in-box dockerd');\n try {\n const dockerd = await launchCloudDockerdDaemon({ backend, handle, timeoutMs: 60_000 });\n if (!dockerd.up)\n log(`dockerd did not become ready (continuing): ${dockerd.reason ?? 'unknown'}`);\n } catch (err) {\n log(\n `dockerd daemon launch failed (continuing): ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n log('launching agentbox-ctl daemon');\n await launchCloudCtlDaemon({\n backend,\n handle,\n boxId: id,\n boxName: name,\n relayUrl: `http://127.0.0.1:${String(8788)}`,\n relayToken,\n bridgeToken,\n webProxyPort: backend.webProxyPort,\n });\n\n // Mint the per-box VNC password and start the in-sandbox VNC stack\n // when VNC is opted in (default-on, matching Docker). Best-effort —\n // a failure logs but doesn't fail create; `agentbox screen` will\n // surface \"daemon may not be up\" if the URL stays 502.\n const vncEnabled = req.vnc?.enabled !== false;\n const vncPassword = vncEnabled ? generateVncPassword() : undefined;\n if (vncEnabled && vncPassword) {\n log('launching VNC stack (Xvnc + websockify + noVNC)');\n try {\n await launchCloudVncDaemon({ backend, handle, vncPassword });\n } catch (err) {\n log(\n `VNC daemon launch failed (continuing): ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n // The box's \"web\" port: the in-box WebProxy port the provider exposes.\n // Defaults to 80; Vercel uses 8080 (it can't expose privileged ports).\n const wp = backend.webProxyPort ?? CLOUD_WEB_PROXY_PORT;\n\n // The web preview URL is best-effort at create — most boxes won't\n // have a service on the WebProxy port until the supervisor schedules\n // the `expose:` service. `agentbox url` re-resolves on demand.\n let webPreview: { url: string; token?: string } | undefined;\n try {\n webPreview = await backend.previewUrl(handle, wp);\n } catch {\n webPreview = undefined;\n }\n\n // Portless host alias + in-VPS mirror. Default-on for backends whose\n // `previewUrl()` returns a loopback URL (Hetzner); naturally skipped\n // for public-URL backends (Daytona) because the URL doesn't parse as\n // 127.0.0.1. Caller can opt out via `providerOptions.portless: false`.\n // Best-effort: every step logs + continues on failure.\n const portlessOpt = (req.providerOptions?.['portless'] as boolean | undefined) ?? true;\n let portlessAliasName: string | undefined;\n let portlessUrlResolved: string | undefined;\n if (portlessOpt && webPreview) {\n const r = await bootstrapPortlessForCloudBox(backend, handle, {\n boxName: name,\n webPreviewUrl: webPreview.url,\n webPort: wp,\n onLog: log,\n });\n if (r) {\n portlessAliasName = r.alias;\n portlessUrlResolved = r.url;\n }\n }\n // Parallel `vnc-<box-name>.localhost` alias against the in-box noVNC\n // port. Host-only — no in-box mirror; an agent inside the box opening\n // its own VNC view is a degenerate self-loop. Same loopback-URL gate\n // as the web path, so Daytona naturally skips and Hetzner registers.\n let vncPreview: { url: string; token?: string } | undefined;\n if (portlessOpt && vncEnabled) {\n try {\n vncPreview = await backend.previewUrl(handle, CLOUD_VNC_PORT);\n } catch {\n vncPreview = undefined;\n }\n }\n let portlessVncAliasName: string | undefined;\n let portlessVncUrlResolved: string | undefined;\n if (portlessOpt && vncPreview) {\n const vncAlias = `vnc-${name}`;\n const url = await registerHostPortlessAlias({\n alias: vncAlias,\n previewUrl: vncPreview.url,\n label: 'vnc',\n onLog: log,\n });\n if (url) {\n portlessVncAliasName = vncAlias;\n portlessVncUrlResolved = url;\n }\n }\n // Per-service preview URLs. Each `services.*.expose.port` from\n // `agentbox.yaml` gets a direct preview URL alongside the main\n // WebProxy URL — lets users hit services without going through the\n // WebProxy. Best-effort: a failed `previewUrl` for a given port\n // just omits it from the map.\n const servicePorts = exposeServicePorts;\n const servicePreviews: Record<number, string> = {};\n for (const port of servicePorts) {\n if (port === wp) continue;\n try {\n const p = await backend.previewUrl(handle, port);\n servicePreviews[port] = p.url;\n } catch {\n // skip this port; the user can still hit the service via the\n // WebProxy if the YAML wires `expose.as: 80`.\n }\n }\n\n // The bridge preview URL is critical: it's how the host CloudBoxPoller\n // reaches the in-sandbox relay. The ctl daemon binds 0.0.0.0:8788 in\n // box mode (cloud), so the Daytona preview proxy can route to it.\n let relayPreview: { url: string; token?: string } | undefined;\n try {\n relayPreview = await backend.previewUrl(handle, 8788);\n } catch {\n relayPreview = undefined;\n }\n\n // Allocate the per-project index BEFORE registering with the relay: the\n // relay keys the status.json path on the projectIndex it's registered\n // with (`<id>-<N>-<mnemonic>`), and the host reader (list / footer /\n // readBoxStatus) derives the same path from the box record. Registering\n // first (projectIndex undefined) made the relay write to the legacy\n // no-index path while the record had `projectIndex: N` — so the reader\n // looked at the `-N-` path, found nothing, and `agentbox list` showed\n // no AGENT status for cloud boxes.\n const state = await readState();\n const projectIndex = req.projectRoot\n ? allocateProjectIndex(state, req.projectRoot)\n : undefined;\n\n // Per-box host-action auto-approve policy (workspace > project > global).\n const autoApproveHostActions = (\n await loadEffectiveConfig(req.projectRoot ?? req.workspacePath)\n ).effective.box.autoApproveHostActions;\n\n // Tell the host relay about this cloud box so it spawns a poller.\n // Best-effort: a failed register doesn't break create (status / git\n // push just won't reach the host until a later register).\n if (relayPreview) {\n try {\n await registerBoxWithRelay({\n boxId: id,\n token: relayToken,\n name,\n projectIndex,\n kind: 'cloud',\n backend: backend.name,\n previewUrl: relayPreview.url,\n previewToken: relayPreview.token,\n bridgeToken,\n createdAt: new Date().toISOString(),\n autoApproveHostActions,\n });\n } catch (err) {\n log(\n `register with host relay failed (continuing): ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n const record: BoxRecord = {\n id,\n name,\n provider: providerName,\n // `container` carries the sandbox id with a `cloud:` prefix —\n // unique within state, never collides with a real docker\n // container, and grepping for `agentbox-cloud-*` (the old\n // synthetic value) finds nothing now. `image` mirrors the\n // resolved cloud image so `BoxRecord.image: string` stays\n // required without docker-internal readers seeing `undefined`.\n container: `cloud:${handle.sandboxId}`,\n image,\n workspacePath: req.workspacePath,\n projectRoot: req.projectRoot,\n projectIndex,\n relayToken,\n withPlaywright: req.withPlaywright,\n withEnv: req.withEnv,\n autoApproveHostActions: autoApproveHostActions ? true : undefined,\n carry: carrySummary,\n portlessAlias: portlessAliasName,\n portlessUrl: portlessUrlResolved,\n portlessVncAlias: portlessVncAliasName,\n portlessVncUrl: portlessVncUrlResolved,\n vncEnabled,\n vncPassword,\n vncContainerPort: vncEnabled ? CLOUD_VNC_PORT : undefined,\n resourceLimits: req.limits\n ? {\n memoryBytes: req.limits.memoryBytes ?? undefined,\n cpus: req.limits.cpus ?? undefined,\n pidsLimit: req.limits.pidsLimit ?? undefined,\n disk: req.limits.disk ?? undefined,\n }\n : undefined,\n cloud: {\n backend: backend.name,\n sandboxId: handle.sandboxId,\n image,\n webPort: wp,\n previewUrls: ((): Record<number, string> | undefined => {\n const m: Record<number, string> = { ...servicePreviews };\n if (webPreview) m[wp] = webPreview.url;\n return Object.keys(m).length > 0 ? m : undefined;\n })(),\n relayPreviewUrl: relayPreview?.url,\n relayPreviewToken: relayPreview?.token,\n bridgeToken,\n snapshotRef: resolvedCheckpointRef,\n lastState: 'running',\n },\n createdAt: new Date().toISOString(),\n };\n await recordBox(record);\n return { record, imageBuilt: false };\n } catch (err) {\n // Best-effort teardown of the half-provisioned sandbox so a failed\n // create doesn't leave the user paying for an inert box.\n try {\n await backend.destroy(handle);\n } catch {\n // The user is going to see the original error; suppressing this\n // secondary failure keeps the message clean.\n }\n throw err;\n }\n },\n\n async start(box: BoxRecord): Promise<BoxRecord> {\n const h = handleFor(box);\n await backend.start(h);\n return reEnsureCloudBox(box, h);\n },\n\n async pause(box: BoxRecord): Promise<void> {\n await backend.pause(handleFor(box));\n await persistLastState(box, 'paused');\n },\n\n async resume(box: BoxRecord): Promise<void> {\n const h = handleFor(box);\n await backend.resume(h);\n // A resumed sandbox boots fresh — ctl/bridge (-> the agentbox.yaml\n // tasks/services), VNC and dockerd are gone. Re-ensure everything\n // `start()` does so non-attach resume paths (`agentbox unpause`/`url`/\n // `checkpoint`/dashboard) don't strand a box with dead daemons. The\n // returned record is persisted inside `reEnsureCloudBox` (recordBox).\n await reEnsureCloudBox(box, h);\n },\n\n async stop(box: BoxRecord): Promise<void> {\n await backend.stop(handleFor(box));\n await persistLastState(box, 'paused');\n },\n\n async destroy(box: BoxRecord): Promise<void> {\n try {\n await backend.destroy(handleFor(box));\n } catch (err) {\n // Surface but don't block state cleanup — a \"missing\" sandbox should\n // still let `agentbox destroy` drop the local record.\n const msg = err instanceof Error ? err.message : String(err);\n if (!/not.?found|missing/i.test(msg)) throw err;\n }\n // Best-effort: drop the host Portless aliases (web + vnc) so neither\n // `<box>.localhost` nor `vnc-<box>.localhost` keeps pointing at a dead\n // ssh -L. The in-VPS portless dies with the VPS.\n if (box.portlessAlias) {\n try {\n await portlessUnalias(box.portlessAlias);\n } catch {\n // portlessUnalias swallows already; paranoid catch in case.\n }\n }\n if (box.portlessVncAlias) {\n try {\n await portlessUnalias(box.portlessVncAlias);\n } catch {\n // best-effort\n }\n }\n // Best-effort: stop the host poller and drop the registration.\n try {\n await forgetBoxFromRelay(box.id);\n } catch {\n // forgetBoxFromRelay already swallows; this catch is paranoid.\n }\n await removeBoxRecord(box.id);\n },\n\n async probeState(box: BoxRecord): Promise<BoxRuntimeState> {\n return probe(box);\n },\n\n async inspect(box: BoxRecord): Promise<InspectedBox> {\n const state = await probe(box);\n const webPort = box.cloud?.webPort ?? backend.webProxyPort ?? CLOUD_WEB_PROXY_PORT;\n // Prefer the stable Portless URL for the `web` endpoint when one was\n // registered — matches Docker's endpoint shape (sandbox-docker/src/\n // endpoints.ts:108-117) so `<name>.localhost` shows up uniformly in\n // `agentbox list` / `inspect`. Falls back to the ephemeral preview URL\n // when Portless wasn't enabled or didn't take.\n const portlessWebUrl =\n box.portlessAlias !== undefined\n ? (box.portlessUrl ?? `https://${box.portlessAlias}.localhost`)\n : undefined;\n const cachedWebUrl = box.cloud?.previewUrls?.[webPort];\n const webUrl = portlessWebUrl ?? cachedWebUrl;\n // Surface each per-service preview URL alongside the main WebProxy.\n // Naming is `service-<port>` because we don't track the YAML name\n // -> port map on the record (avoids extra wire shape just for\n // display).\n const endpoints: Array<{\n kind: 'web';\n name: string;\n containerPort: number;\n url: string;\n reachable: boolean;\n }> = [];\n if (webUrl) {\n endpoints.push({\n kind: 'web',\n name: 'web',\n containerPort: webPort,\n url: webUrl,\n reachable: true,\n });\n }\n for (const [portStr, url] of Object.entries(box.cloud?.previewUrls ?? {})) {\n const port = Number.parseInt(portStr, 10);\n if (!Number.isFinite(port) || port === webPort) continue;\n endpoints.push({\n kind: 'web',\n name: `service-${String(port)}`,\n containerPort: port,\n url,\n reachable: true,\n });\n }\n return {\n record: box,\n state,\n endpoints: {\n domain: webUrl ? new URL(webUrl).host : '',\n domainIsOrb: false,\n endpoints,\n },\n raw: undefined,\n };\n },\n\n async exec(box: BoxRecord, argv: string[], opts?: ExecOptions): Promise<ExecResult> {\n const r = await backend.exec(handleFor(box), quoteShellArgv(argv), {\n cwd: opts?.cwd,\n env: opts?.env,\n user: opts?.user,\n });\n return { exitCode: r.exitCode, stdout: r.stdout, stderr: r.stderr };\n },\n\n async buildAttach(\n box: BoxRecord,\n kind: AttachKind,\n opts?: BuildAttachOptions,\n ): Promise<AttachSpec> {\n if (!backend.attachArgv) {\n throw new Error(\n `cloud backend '${backend.name}' does not implement attachArgv — interactive attach not supported`,\n );\n }\n const handle = handleFor(box);\n const baseArgv = await backend.attachArgv(handle);\n const inner = renderInnerCommand(kind, opts);\n // -t forces TTY allocation on the remote side (the SSH default of\n // skipping TTY when a command is provided would break tmux + readline).\n // A `detached` build only creates the session (no `exec tmux attach`), so\n // it runs as a plain non-interactive exec — no TTY needed.\n const argv = opts?.detached\n ? [...baseArgv.slice(1), inner]\n : [...baseArgv.slice(1), '-t', inner];\n // Keep argv[0] = the program name (ssh) so callers can split.\n const fullArgv = [baseArgv[0]!, ...argv];\n const cleanup = backend.revokeAttachToken\n ? async (): Promise<void> => {\n await backend.revokeAttachToken!(handle, baseArgv);\n }\n : undefined;\n return { argv: fullArgv, cleanup };\n },\n\n async uploadPath(\n box: BoxRecord,\n hostSrc: string,\n boxDst: string,\n exclude?: string[],\n ): Promise<{ finalPath: string }> {\n return uploadToCloudBox(backend, handleFor(box), hostSrc, boxDst, exclude);\n },\n\n async downloadPath(\n box: BoxRecord,\n boxSrc: string,\n hostDst: string,\n exclude?: string[],\n ): Promise<{ finalPath: string }> {\n return downloadFromCloudBox(backend, handleFor(box), boxSrc, hostDst, exclude);\n },\n\n async downloadDirContents(\n box: BoxRecord,\n boxSrc: string,\n hostDst: string,\n ): Promise<{ finalPath: string }> {\n return pullCloudDirContents(backend, handleFor(box), boxSrc, hostDst);\n },\n\n async resolveUrl(\n box: BoxRecord,\n opts?: { loopback?: boolean; kind?: 'web' | 'vnc'; ttl?: number },\n ): Promise<string> {\n const h = handleFor(box);\n const kind = opts?.kind ?? 'web';\n // Prefer the stable Portless URL when one was registered (Hetzner gets\n // both; Daytona naturally skips since previewUrl is non-loopback). The\n // `--loopback` flag forces the raw signed/loopback path instead.\n if (!opts?.loopback) {\n if (kind === 'web' && box.portlessAlias) {\n return box.portlessUrl ?? `https://${box.portlessAlias}.localhost`;\n }\n if (kind === 'vnc' && box.portlessVncAlias) {\n return box.portlessVncUrl ?? `https://${box.portlessVncAlias}.localhost`;\n }\n }\n // VNC port is fixed by Dockerfile.box (websockify serves noVNC on :6080).\n const port =\n kind === 'vnc'\n ? CLOUD_VNC_PORT\n : (box.cloud?.webPort ?? backend.webProxyPort ?? CLOUD_WEB_PROXY_PORT);\n // Always re-resolve through the SDK — cached URLs on the record may be\n // from a previous start whose token has rotated. Prefer signed URLs\n // because the user is about to hand the URL to a browser (no way to\n // attach an `x-daytona-preview-token` header from a click).\n if (backend.signedPreviewUrl) {\n const ttl = opts?.ttl ?? DEFAULT_SIGNED_URL_TTL_SECONDS;\n try {\n const signed = await backend.signedPreviewUrl(h, port, ttl);\n return signed.url;\n } catch (err) {\n // Web fallback: some backends (Vercel) can't expose the privileged\n // WebProxy port (<1024), so resolving :80 throws \"no route\". Fall back\n // to the first exposed `expose:` service port so `agentbox url` still\n // reaches the app the user actually published. Daytona/Hetzner expose\n // :80 directly, so this branch never runs for them.\n if (kind === 'web') {\n const fallbackPort = await firstExposedServicePort(box);\n if (fallbackPort !== undefined && fallbackPort !== port) {\n const signed = await backend.signedPreviewUrl(h, fallbackPort, ttl);\n return signed.url;\n }\n }\n throw err;\n }\n }\n // No signed-URL primitive: fall back to the header-token URL, but fail\n // loudly so the caller sees this isn't usable in a browser as-is.\n const p = await backend.previewUrl(h, port);\n throw new Error(\n `cloud backend '${backend.name}' does not support signed preview URLs; ` +\n `the standard URL (${p.url}) requires a header token (e.g. x-daytona-preview-token: ${p.token ?? '<unset>'}) ` +\n `that browsers can't attach from a click. Use a programmatic client or wait for backend support.`,\n );\n },\n\n // Cloud checkpoint capability. Backends without `createSnapshot` get a\n // capability stub whose methods throw — the CLI's `agentbox checkpoint\n // create` then surfaces a clean \"not supported\" error rather than a\n // silent no-op.\n checkpoint: makeCloudCheckpoint(backend),\n\n // Extract the box's agent login(s) back to the host (~/.agentbox) so the\n // next box inherits the login. Lives on the base cloud provider (not inside\n // `checkpoint.create`) so it works even for providers that override the\n // whole `checkpoint` capability (vercel). The CLI calls this on\n // `checkpoint create --set-default`, while the box is guaranteed running.\n async extractAgentCredentials(box: BoxRecord): Promise<string[]> {\n if (!box.cloud?.sandboxId) return [];\n return extractCloudAgentCredentials(backend, { sandboxId: box.cloud.sandboxId });\n },\n\n // stats is provider-optional; cloud backends without a metrics API just\n // omit it. Backends that have one can decorate the returned provider.\n };\n}\n\n/** Reserved cloud ports that are never a user-facing web service. */\nconst RESERVED_CLOUD_PORTS = new Set<number>([CLOUD_WEB_PROXY_PORT, CLOUD_VNC_PORT, 8788]);\n\n/**\n * The lowest exposed `expose:` service port for a box, used as the web URL\n * fallback when the WebProxy port itself can't be exposed (Vercel). Prefers the\n * box record's `previewUrls` map (only ports that actually got a preview URL\n * land there), then falls back to re-reading `agentbox.yaml`. Returns undefined\n * when the box exposes no non-reserved service port.\n */\nasync function firstExposedServicePort(box: BoxRecord): Promise<number | undefined> {\n // The box's own WebProxy port (e.g. Vercel's 8080) is reserved too — it's the\n // web aggregator, not a user service port.\n const reserved = (p: number): boolean => RESERVED_CLOUD_PORTS.has(p) || p === box.cloud?.webPort;\n const fromRecord = Object.keys(box.cloud?.previewUrls ?? {})\n .map(Number)\n .filter((p) => Number.isInteger(p) && !reserved(p));\n if (fromRecord.length > 0) return Math.min(...fromRecord);\n try {\n const fromYaml = (await readExposedServicePorts(box.workspacePath)).filter((p) => !reserved(p));\n if (fromYaml.length > 0) return Math.min(...fromYaml);\n } catch {\n // workspace path missing / yaml unreadable — no fallback available\n }\n return undefined;\n}\n\n/**\n * Build the `Provider.checkpoint` capability for a cloud backend.\n *\n * - `create(box, name)` captures the live sandbox via `backend.createSnapshot`\n * and persists a thin manifest on the host (`~/.agentbox/cloud-checkpoints/…`).\n * - `list(projectRoot)` reads the on-disk manifest store.\n * - `remove(projectRoot, ref)` deletes the Daytona snapshot best-effort and\n * removes the local manifest unconditionally so a remote-only failure\n * doesn't leave the user with a dead pointer.\n */\nfunction makeCloudCheckpoint(backend: CloudBackend): ProviderCheckpoint {\n return {\n async create(box: BoxRecord, name: string) {\n if (!backend.createSnapshot) {\n throw new Error(\n `cloud backend '${backend.name}' doesn't support snapshots — \\`agentbox checkpoint\\` unavailable`,\n );\n }\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(`cloud box ${box.name} has no sandboxId — record is malformed`);\n }\n const snapshotName = cloudSnapshotName(box.projectRoot, name);\n await backend.createSnapshot({ sandboxId: box.cloud.sandboxId }, snapshotName);\n const info = await writeCloudCheckpointManifest(box.projectRoot, backend.name, name, {\n snapshotName,\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 if (backend.deleteSnapshot) {\n try {\n await backend.deleteSnapshot(entry.manifest.snapshotName);\n } catch {\n // Best-effort: even if the remote delete fails (network, perms,\n // or already-gone), drop the local manifest so the user isn't\n // stuck with a pointer to nothing. They can clean up the orphan\n // snapshot from the Daytona dashboard.\n }\n }\n await removeCloudCheckpointDir(projectRoot, backend.name, ref);\n },\n };\n}\n\n/**\n * Build the inner shell command tmux runs inside the cloud sandbox for an\n * attach. The string is later embedded in `ssh ... -t '<cmd>'`, so it must\n * be a single shell-safe phrase (the SSH client passes it to the remote\n * `sshd` which feeds it to the user's login shell).\n *\n * Three-stage: ensure the session exists (idempotent), apply the same\n * tmux configuration the docker provider uses (prefix remap, extended-keys,\n * `status off` to hide the inner status bar so it doesn't double up with\n * the wrapped-pty footer — see {@link buildTmuxConfigShellSnippet}), then\n * `exec tmux attach`. We can't use `tmux new-session -A` here because it\n * would attach before the `set` commands run; `has-session || new-session -d`\n * keeps the session detached long enough to configure it. `-c /workspace`\n * starts the session in the box's workspace dir so claude/codex/opencode\n * see /workspace as their cwd (otherwise tmux inherits the SSH login\n * shell's $HOME and the agents prompt for workspace-trust).\n */\nexport function renderInnerCommand(kind: AttachKind, opts?: BuildAttachOptions): string {\n const sessionName = opts?.sessionName ?? defaultSessionName(kind);\n const fallback = opts?.command ?? defaultCommand(kind, opts);\n if (kind === 'logs') {\n // logs always tails; tmux makes no sense here.\n return fallback;\n }\n if (opts?.noTmux) {\n return fallback;\n }\n const sessionQ = shellSingle(sessionName);\n const cwdQ = shellSingle(CLOUD_WORKSPACE_DIR);\n const fallbackQ = shellSingle(fallback);\n const configSnippet = buildTmuxConfigShellSnippet(sessionName);\n const lines = [\n `command -v tmux >/dev/null || { echo \"tmux not installed in sandbox\"; exit 127; }`,\n `tmux has-session -t ${sessionQ} 2>/dev/null || tmux new-session -d -c ${cwdQ} -s ${sessionQ} ${fallbackQ}`,\n configSnippet,\n ];\n // `detached`: create + configure the session but don't attach. Used to\n // pre-start a session with its full launch command before a new-tab attach\n // re-invokes `agentbox <agent> attach` (which carries no launch args).\n if (opts?.detached) return lines.join('; ');\n return [...lines, `exec tmux attach -t ${sessionQ}`].join('; ');\n}\n\nfunction defaultSessionName(kind: AttachKind): string {\n switch (kind) {\n case 'shell':\n return 'shell';\n case 'agent':\n return 'agent';\n case 'logs':\n return 'logs';\n }\n}\n\nfunction defaultCommand(kind: AttachKind, opts?: BuildAttachOptions): string {\n switch (kind) {\n case 'shell':\n return 'bash -l';\n case 'agent':\n // Caller didn't tell us which agent — fall back to a login shell;\n // claude/codex/opencode wrappers pass an explicit `command`.\n return 'bash -l';\n case 'logs': {\n if (!opts?.service) {\n return 'echo \"no service specified — set BuildAttachOptions.service\"';\n }\n // Prefer `agentbox-ctl logs` so the cloud follow stream matches the\n // docker format (timestamps + stream marker, ring-buffered tail). The\n // ctl daemon binds the unix socket regardless of how we exec in.\n const tail = opts.tail !== undefined ? String(opts.tail) : '200';\n const args = [`--tail ${shellSingle(tail)}`];\n if (opts.follow !== false) args.push('--follow');\n return `/usr/local/bin/agentbox-ctl logs ${shellSingle(opts.service)} ${args.join(' ')}`;\n }\n }\n}\n\n/** Wrap an arbitrary string in single quotes for embedding in a shell command. */\nfunction shellSingle(s: string): string {\n return \"'\" + s.replace(/'/g, \"'\\\\''\") + \"'\";\n}\n\n/** Helper: returns a BoxResourceStats stub so callers needn't unwrap optional. */\nexport function emptyCloudStats(provider: string): BoxResourceStats {\n return {\n source: provider,\n live: false,\n cpuPercent: null,\n memUsedBytes: null,\n memLimitBytes: null,\n memPercent: null,\n pids: null,\n diskUsedBytes: null,\n snapshotDiskBytes: null,\n checkpointVolumeBytes: null,\n netRxBytes: null,\n netTxBytes: null,\n blockReadBytes: null,\n blockWriteBytes: null,\n limits: { memoryBytes: null, cpus: null, pidsLimit: null, disk: null },\n warnings: [],\n };\n}\n","/**\n * Cloud-provider **credentials volume** management — the per-create half of\n * the agent state split. The other half (static config: plugins, skills,\n * settings, marketplaces, codex `config.toml`, opencode `config/`) is\n * layered into the published Daytona snapshot at\n * `agentbox prepare --provider daytona` time via the documented\n * `daytona.snapshot.create({ name, image })` API + `Image.fromDockerfile(...)\n * .addLocalFile(...).runCommands(...)` (see\n * `packages/sandbox-daytona/src/prepare.ts`).\n *\n * What lives here is the runtime side: credentials (`.credentials.json` for\n * claude, `auth.json` for codex/opencode) live on a single per-org\n * `agentbox-credentials` Daytona volume, mounted three times via `subpath`\n * at `/home/vscode/.agentbox-creds/{claude,codex,opencode}/`. Symlinks\n * baked into the box image route the agent-expected paths\n * (`~/.claude/.credentials.json` etc.) through to the volume.\n *\n * `seedAgentVolumesIfFresh` runs at every `agentbox create --provider\n * daytona`: it probes the per-agent marker file in the credentials volume\n * and uploads a tiny credentials-only tarball when missing. Re-seeding is\n * **explicit only** — vanilla create never overwrites credentials it\n * already finds. `agentbox daytona resync` passes `force: true` to refresh\n * after a host re-auth.\n */\n\nimport { chmod, mkdir, writeFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport {\n stageClaudeStaticForUpload,\n stageClaudeCredentialsForUpload,\n stageCodexStaticForUpload,\n stageCodexCredentialsForUpload,\n stageOpencodeStaticForUpload,\n stageOpencodeCredentialsForUpload,\n stageOpencodeStateForUpload,\n CREDENTIALS_BACKUP_FILE,\n CODEX_CREDENTIALS_BACKUP_FILE,\n OPENCODE_CREDENTIALS_BACKUP_FILE,\n DEFAULT_BOX_IMAGE,\n SHARED_CLAUDE_VOLUME,\n SHARED_CODEX_VOLUME,\n SHARED_OPENCODE_VOLUME,\n extractCodexCredentials,\n extractOpencodeCredentials,\n hostClaudeBackupExpired,\n isRealAgentCredential,\n syncClaudeCredentials,\n type StageResult,\n} from '@agentbox/sandbox-docker';\nimport type { CloudBackend, CloudHandle, CloudVolumeMount } from '@agentbox/core';\n\n/** Identifier for one of the three agents we sync into cloud sandboxes. */\nexport type CloudAgentKind = 'claude' | 'codex' | 'opencode';\n\n/**\n * Single per-org volume that holds all three agents' credentials. Mounted\n * three times via `subpath` so each agent's tokens get their own dir without\n * the volumes-API churn of registering three separate volumes.\n */\nconst CREDENTIALS_VOLUME = 'agentbox-credentials';\n\n/**\n * Per-agent metadata. `staticMountPath` is where the snapshot-baked static\n * config lives in the sandbox FS; `credentialsMountPath` is where the\n * credentials volume's per-agent subpath gets attached at runtime.\n * `credentialsSubpath` is the subdir inside the shared volume.\n */\ninterface AgentSpec {\n kind: CloudAgentKind;\n /** Where stage*Static tarballs extract (sandbox FS, snapshot-captured). */\n staticMountPath: string;\n /** Where the credentials-volume subpath gets mounted at runtime. */\n credentialsMountPath: string;\n /** Subdir of the shared credentials volume for this agent. */\n credentialsSubpath: string;\n stageStatic: (opts: { hostWorkspace?: string }) => Promise<StageResult>;\n stageCredentials: () => Promise<StageResult>;\n}\n\nconst AGENT_SPECS: AgentSpec[] = [\n {\n kind: 'claude',\n staticMountPath: '/home/vscode/.claude',\n credentialsMountPath: '/home/vscode/.agentbox-creds/claude',\n credentialsSubpath: 'claude/',\n stageStatic: (opts) => stageClaudeStaticForUpload({ hostWorkspace: opts.hostWorkspace }),\n stageCredentials: () => stageClaudeCredentialsForUpload(),\n },\n {\n kind: 'codex',\n staticMountPath: '/home/vscode/.codex',\n credentialsMountPath: '/home/vscode/.agentbox-creds/codex',\n credentialsSubpath: 'codex/',\n stageStatic: () => stageCodexStaticForUpload(),\n stageCredentials: () => stageCodexCredentialsForUpload(),\n },\n {\n kind: 'opencode',\n staticMountPath: '/home/vscode/.local/share/opencode',\n credentialsMountPath: '/home/vscode/.agentbox-creds/opencode',\n credentialsSubpath: 'opencode/',\n stageStatic: () => stageOpencodeStaticForUpload(),\n stageCredentials: () => stageOpencodeCredentialsForUpload(),\n },\n];\n\nimport {\n CLAUDE_FORWARDED_ENV_KEYS,\n CODEX_FORWARDED_ENV_KEYS,\n OPENCODE_FORWARDED_ENV_KEYS,\n} from '@agentbox/sandbox-docker';\n\n/**\n * Marker filename inside each agent's credentials subpath that records when\n * we last seeded the credentials. Single ISO-8601 timestamp on disk. Absent\n * marker = first time → upload.\n */\nconst SEED_MARKER = '.agentbox-seeded-at';\n\n/** Result of `ensureAgentVolumesForCloud` — pass `.mounts` straight into `provision({ volumes })`. */\nexport interface EnsureAgentVolumesResult {\n /** Volume mounts ready for `CloudProvisionRequest.volumes`. */\n mounts: CloudVolumeMount[];\n /**\n * Env vars to merge into the sandbox env at provision time. Includes\n * `OPENCODE_CONFIG_DIR` (so the in-box opencode reads its config from the\n * snapshot-baked `config/` subdir of its data dir) and any forwarded\n * provider API keys present in the host env.\n */\n env: Record<string, string>;\n /**\n * Agents we successfully reserved credentials mounts for. Pass back into\n * `seedAgentVolumesIfFresh` so it doesn't redo the kind list.\n */\n agents: CloudAgentKind[];\n}\n\n/**\n * Reserve the shared `agentbox-credentials` volume and return three subpath\n * mounts ready to thread into `CloudProvisionRequest.volumes`. Backends that\n * don't implement `ensureVolume` get an empty mount list (and a one-line log)\n * — the in-box agents fall back to interactive login.\n *\n * Idempotent: every call is a fast lookup for the already-created volume.\n * Safe to call on every `create`.\n */\nexport async function ensureAgentVolumesForCloud(\n backend: CloudBackend,\n opts: { onLog?: (line: string) => void } = {},\n): Promise<EnsureAgentVolumesResult> {\n const log = opts.onLog ?? (() => {});\n const allAgents = AGENT_SPECS.map((s) => s.kind);\n if (typeof backend.ensureVolume !== 'function') {\n // Non-volume backends (e2b, vercel, hetzner) still get credentials seeded\n // per-create — `seedAgentVolumesIfFresh` falls back to a direct upload+\n // extract into the box-baked `~/.agentbox-creds/<agent>/` dirs. The mounts\n // list stays empty (nothing to persist across boxes) but the agent list is\n // populated so the seed actually runs.\n log(\n `cloud backend '${backend.name}' has no volume primitive — agent credentials seeded per-create only`,\n );\n return { mounts: [], env: buildForwardedEnv(allAgents), agents: allAgents };\n }\n\n let volumeId: string;\n try {\n const ensured = await backend.ensureVolume(CREDENTIALS_VOLUME);\n volumeId = ensured.volumeId;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n log(`ensureVolume(${CREDENTIALS_VOLUME}) failed (skipping credentials seed): ${msg}`);\n return { mounts: [], env: buildForwardedEnv([]), agents: [] };\n }\n\n const mounts: CloudVolumeMount[] = AGENT_SPECS.map((spec) => ({\n volumeId,\n mountPath: spec.credentialsMountPath,\n subpath: spec.credentialsSubpath,\n }));\n return { mounts, env: buildForwardedEnv(allAgents), agents: allAgents };\n}\n\nfunction buildForwardedEnv(agents: CloudAgentKind[]): Record<string, string> {\n const env: Record<string, string> = {};\n // OpenCode reads its config dir from $OPENCODE_CONFIG_DIR; the snapshot\n // bake puts the config files at <data dir>/config/ to match what the\n // Docker provider does (see buildOpencodeMounts).\n if (agents.includes('opencode')) {\n env['OPENCODE_CONFIG_DIR'] = '/home/vscode/.local/share/opencode/config';\n }\n // Forward provider API keys from the host process env into the sandbox.\n // For agents authenticated via env-var (ANTHROPIC_API_KEY etc.) rather\n // than a stored auth file, this is the only way the in-box agent finds\n // its credentials. Mirrors the Docker provider's per-agent forwarding.\n const forwardedKeys = new Set<string>([\n ...CLAUDE_FORWARDED_ENV_KEYS,\n ...CODEX_FORWARDED_ENV_KEYS,\n ...OPENCODE_FORWARDED_ENV_KEYS,\n ]);\n for (const k of forwardedKeys) {\n const v = process.env[k];\n if (typeof v === 'string' && v.length > 0) env[k] = v;\n }\n return env;\n}\n\nexport interface SeedAgentVolumesOptions {\n /** Which agents to consider seeding. Defaults to all three. */\n agents?: CloudAgentKind[];\n /**\n * The host-absolute workspace path being mounted at `/workspace` inside\n * the box. Currently unused by the credentials-only seed (no `_claude.json`\n * involved), but kept on the interface for symmetry with the bake step\n * and forward compat with future credential-side rewrites.\n */\n hostWorkspace?: string;\n /**\n * When true, ignore the in-volume seed marker and re-upload. Used by\n * `agentbox daytona resync` and by the host-login flow. Default: false\n * (vanilla create never overwrites a seeded volume).\n */\n force?: boolean;\n onLog?: (line: string) => void;\n}\n\n/**\n * For each enabled agent: probe the credentials-subpath\n * `<credentialsMountPath>/.agentbox-seeded-at` marker via `backend.exec`. If\n * absent (or `force: true`), stage a credentials-only tarball, upload via\n * `backend.uploadFile`, extract inside the sandbox into the credentials\n * mount.\n *\n * Idempotent and safe to call on every `create`. Warnings from staging (e.g.\n * codex Keychain landmine) are forwarded via `onLog`. The payload is a\n * single small file per agent, so the FUSE-volume pathology that plagues\n * the static seed is irrelevant here.\n */\nexport async function seedAgentVolumesIfFresh(\n backend: CloudBackend,\n handle: CloudHandle,\n opts: SeedAgentVolumesOptions = {},\n): Promise<void> {\n const log = opts.onLog ?? (() => {});\n const wanted = new Set<CloudAgentKind>(opts.agents ?? AGENT_SPECS.map((s) => s.kind));\n const specs = AGENT_SPECS.filter((s) => wanted.has(s.kind));\n // Best-effort per agent: one agent's seed failure (transient SDK error,\n // missing host creds for that agent) must never sink `agentbox create`.\n // Matches the prior vercel/hetzner custom pushers, which caught + warned.\n // The in-box agent then falls back to interactive login.\n await Promise.allSettled(\n specs.map((spec) =>\n seedCredentialsOne(backend, handle, spec, opts).catch((err) => {\n log(\n `${spec.kind}: credentials seed failed (continuing): ${err instanceof Error ? err.message : String(err)}`,\n );\n }),\n ),\n );\n}\n\n/**\n * Refresh the host-side credential backups (`~/.agentbox/{claude,codex,opencode}-credentials.json`)\n * from the live docker shared volumes BEFORE cloud creates seed from them.\n *\n * Why this exists: `agentbox create --provider <cloud>` reads the host backups\n * to seed cloud boxes, but only the docker create path keeps them current\n * (`syncClaudeCredentials` runs at `packages/sandbox-docker/src/create.ts:593`).\n * Without this refresh, cloud creates push whatever access token the docker\n * volume last extracted — often expired by the time the user actually attaches\n * → in-box `claude` says \"401 Invalid authentication credentials\" even though\n * the box's `.credentials.json` is present.\n *\n * Best-effort: every helper already swallows its own failures (no docker on\n * the host, missing volume, etc.) and returns a noop result. We only nudge —\n * the seed still runs against whatever backup exists.\n *\n * Gated on `hostClaudeBackupExpired`: when the claude backup's `expiresAt` is\n * in the future we skip the docker round-trip entirely (`docker run` against\n * the shared volume is ~1-2s and almost always a noop on fresh tokens).\n */\nexport async function refreshAgentCredentialsBackup(opts: {\n onLog?: (line: string) => void;\n} = {}): Promise<void> {\n const log = opts.onLog ?? (() => {});\n if (!(await hostClaudeBackupExpired())) {\n return;\n }\n log('claude: host credentials backup expired — refreshing from docker shared volume');\n const image = DEFAULT_BOX_IMAGE;\n try {\n const r = await syncClaudeCredentials({ volume: SHARED_CLAUDE_VOLUME }, { image, isolate: false });\n if (r.direction === 'extracted') {\n log('claude: refreshed host credentials backup from docker shared volume');\n } else if (r.direction === 'noop') {\n log('claude: no docker shared volume to refresh from (continuing with existing backup)');\n }\n } catch {\n /* best-effort — syncClaudeCredentials already swallows internally */\n }\n // codex + opencode are extract-only (no docker bind mount of the host's real\n // ~/.codex into the box like claude has), so always try when the docker\n // volume exists. Both helpers return { copied: false } on any error.\n try { await extractCodexCredentials(SHARED_CODEX_VOLUME, image); } catch { /* best-effort */ }\n try { await extractOpencodeCredentials(SHARED_OPENCODE_VOLUME, image); } catch { /* best-effort */ }\n}\n\nasync function seedCredentialsOne(\n backend: CloudBackend,\n handle: CloudHandle,\n spec: AgentSpec,\n opts: SeedAgentVolumesOptions,\n): Promise<void> {\n const log = opts.onLog ?? (() => {});\n // Non-volume backends (e2b, vercel, hetzner) have an ephemeral per-box FS:\n // the `.agentbox-seeded-at` marker can't survive across boxes, and the host\n // tokens are renewable, so we just push fresh every create. Volume backends\n // (daytona) keep the marker-based idempotency so they don't re-upload into\n // a volume already carrying credentials from a previous box.\n const hasVolume = typeof backend.ensureVolume === 'function';\n\n if (hasVolume && !opts.force) {\n const probe = await backend.exec(\n handle,\n `test -f ${spec.credentialsMountPath}/${SEED_MARKER}`,\n );\n if (probe.exitCode === 0) {\n log(`${spec.kind}: credentials already seeded — mounting only`);\n return;\n }\n }\n\n log(`${spec.kind}: staging host credentials`);\n const staged = await spec.stageCredentials();\n for (const w of staged.warnings) log(w);\n try {\n if (staged.tarballPath === null) {\n log(`${spec.kind}: no credentials to seed`);\n return;\n }\n\n let tarSize = 0;\n try {\n const { statSync } = await import('node:fs');\n tarSize = statSync(staged.tarballPath).size;\n } catch {\n /* best-effort */\n }\n const sizeKB = (tarSize / 1024).toFixed(1);\n log(`${spec.kind}: uploading ${sizeKB} KB credentials tarball`);\n const t0 = Date.now();\n const remoteTar = `/tmp/agentbox-${spec.kind}-creds.tar.gz`;\n try {\n await backend.uploadFile(handle, staged.tarballPath, remoteTar);\n } catch (err) {\n // Match the per-agent best-effort the old vercel/hetzner pushers had:\n // a single agent's upload failure (transient SDK error, network blip)\n // must not sink `agentbox create`. Log and fall through; the in-box\n // agent then falls back to interactive login.\n const msg =\n `${spec.kind}: credentials upload failed (${err instanceof Error ? err.message : String(err)}); ` +\n `agent falls back to interactive login`;\n log(msg);\n return;\n }\n const upDt = ((Date.now() - t0) / 1000).toFixed(1);\n log(`${spec.kind}: upload done in ${upDt}s`);\n\n const extractCmd = hasVolume\n ? // Daytona volumes are S3-backed FUSE and reject chmod/utime. The\n // credentials payload is one small file, so we extract straight into\n // the mount with `cp` (not tar — tar would chmod the parent dir during\n // delayed-set-stat and abort with EPERM). Two-step: tar into a local-fs\n // staging dir, then cp the file across. Marker tracks idempotency.\n (() => {\n const stageDir = `/tmp/agentbox-creds-stage-${spec.kind}`;\n return (\n `set -e; ` +\n `rm -rf ${stageDir}; ` +\n `mkdir -p ${stageDir}; ` +\n `tar -xzf ${remoteTar} -C ${stageDir}; ` +\n `cp -r ${stageDir}/. ${spec.credentialsMountPath}/; ` +\n `rm -rf ${stageDir}; ` +\n `date -u +%FT%TZ > ${spec.credentialsMountPath}/${SEED_MARKER}; ` +\n `rm -f ${remoteTar}`\n );\n })()\n : // Ephemeral FS: extract straight into the box-baked `~/.agentbox-creds/\n // <agent>/` dir. `sudo -u vscode` ensures the on-disk file ends up\n // vscode-owned regardless of which user `backend.exec` runs as\n // (e2b: vscode, vercel: vscode, hetzner: vscode via ssh — sudo\n // works on all three because vscode has passwordless sudo). The\n // `--no-same-permissions --no-same-owner -m` flags mirror what\n // vercel/hetzner did in their old custom pushers.\n `set -e; ` +\n `sudo -u vscode mkdir -p ${spec.credentialsMountPath}; ` +\n `sudo -u vscode tar -xzf ${remoteTar} -C ${spec.credentialsMountPath} --no-same-permissions --no-same-owner -m; ` +\n `rm -f ${remoteTar}`;\n const extract = await backend.exec(handle, extractCmd);\n if (extract.exitCode !== 0) {\n const msg =\n `${spec.kind}: credentials extract failed (exit ${String(extract.exitCode)}); ` +\n `agent falls back to interactive login. ` +\n `stdout: ${extract.stdout.slice(-200)} stderr: ${extract.stderr.slice(-200)}`;\n log(msg);\n return;\n }\n log(`${spec.kind}: credentials seeded`);\n } finally {\n await staged.cleanup();\n }\n}\n\n/** Box-side OpenCode state dir (default XDG location; cloud sets no XDG_STATE_HOME). */\nconst OPENCODE_STATE_DIR = '/home/vscode/.local/state/opencode';\n\n/**\n * Seed the host's selected OpenCode model (`~/.local/state/opencode/model.json`)\n * into the box's default state dir, host-authoritative, on **every** create.\n *\n * Unlike credentials (a seed-once volume), the cloud box's state dir is ephemeral\n * — there is no persistent per-box store on either cloud (Daytona's only shared\n * volume holds credentials; Hetzner has none), so the host is authoritative each\n * create and there is no marker to gate on. Without this, OpenCode boots a cloud\n * box with its built-in default model instead of the one the user picked on the\n * host. Provider-agnostic: runs on any `CloudBackend` (`exec` + `uploadFile`).\n *\n * Best-effort: a failure logs and leaves the box on OpenCode's default — it must\n * never fail box creation.\n */\nexport async function seedOpencodeModelState(\n backend: CloudBackend,\n handle: CloudHandle,\n opts: { onLog?: (line: string) => void } = {},\n): Promise<void> {\n const log = opts.onLog ?? (() => {});\n const staged = await stageOpencodeStateForUpload();\n if (staged.tarballPath === null) {\n log('opencode: no host model selection to seed');\n return;\n }\n try {\n const remoteTar = '/tmp/agentbox-opencode-state.tar.gz';\n await backend.uploadFile(handle, staged.tarballPath, remoteTar);\n const res = await backend.exec(\n handle,\n `set -e; mkdir -p ${OPENCODE_STATE_DIR}; ` +\n `tar -xzf ${remoteTar} -C ${OPENCODE_STATE_DIR}; ` +\n `chown -R vscode:vscode ${OPENCODE_STATE_DIR} 2>/dev/null || true; ` +\n `rm -f ${remoteTar}`,\n );\n if (res.exitCode !== 0) {\n log(\n `opencode: model-state seed failed (exit ${String(res.exitCode)}); ` +\n `box falls back to OpenCode's default model. stderr: ${res.stderr.slice(-200)}`,\n );\n return;\n }\n log('opencode: model selection seeded ✓');\n } finally {\n await staged.cleanup();\n }\n}\n\n/**\n * Spec for a single agent — for callers that need the mount path or volume\n * name outside the create flow.\n */\nexport function agentSpecsForCloud(): Array<{\n kind: CloudAgentKind;\n staticMountPath: string;\n credentialsMountPath: string;\n credentialsSubpath: string;\n}> {\n return AGENT_SPECS.map((s) => ({\n kind: s.kind,\n staticMountPath: s.staticMountPath,\n credentialsMountPath: s.credentialsMountPath,\n credentialsSubpath: s.credentialsSubpath,\n }));\n}\n\n/**\n * Per-agent: the canonical in-box auth file (what the agent actually reads/\n * writes — NOT the `~/.agentbox-creds` symlink target, because an agent that\n * writes atomically replaces the symlink with a regular file there) and the\n * host backup file we mirror it into.\n */\nconst EXTRACT_SPECS: Array<{ kind: CloudAgentKind; boxPath: string; hostBackup: string }> = [\n { kind: 'claude', boxPath: '/home/vscode/.claude/.credentials.json', hostBackup: CREDENTIALS_BACKUP_FILE },\n { kind: 'codex', boxPath: '/home/vscode/.codex/auth.json', hostBackup: CODEX_CREDENTIALS_BACKUP_FILE },\n {\n kind: 'opencode',\n boxPath: '/home/vscode/.local/share/opencode/auth.json',\n hostBackup: OPENCODE_CREDENTIALS_BACKUP_FILE,\n },\n];\n\n/**\n * Extract the agent login credentials from a running cloud box back to the\n * host backups under `~/.agentbox/`, so the next box (seeded by the cloud\n * push) inherits the login. The cloud analogue of docker's\n * `syncClaudeCredentials` extract direction, generalized to codex/opencode —\n * cloud has no shared volume, so a login captured inside a box would otherwise\n * be lost on destroy.\n *\n * Reads the canonical agent path via `backend.exec(... cat ...)`; only writes\n * the host backup when the content passes `isRealAgentCredential`, so an empty\n * / not-logged-in box never clobbers a good backup. Best-effort per agent\n * (never throws). Returns the list of agents whose backup was updated.\n */\nexport async function extractCloudAgentCredentials(\n backend: CloudBackend,\n handle: CloudHandle,\n opts: {\n onLog?: (line: string) => void;\n /** Override host backup paths per agent (tests). Defaults to the ~/.agentbox constants. */\n backups?: Partial<Record<CloudAgentKind, string>>;\n } = {},\n): Promise<CloudAgentKind[]> {\n const log = opts.onLog ?? (() => {});\n const extracted: CloudAgentKind[] = [];\n for (const spec of EXTRACT_SPECS) {\n const hostBackup = opts.backups?.[spec.kind] ?? spec.hostBackup;\n try {\n // `cat` the canonical file; tolerate \"missing\" (exit 1) silently.\n const r = await backend.exec(handle, `cat ${spec.boxPath} 2>/dev/null`, { noRetry: true });\n const text = r.stdout;\n if (r.exitCode !== 0 || !text || !isRealAgentCredential(spec.kind, text)) continue;\n await mkdir(dirname(hostBackup), { recursive: true });\n await writeFile(hostBackup, text, { mode: 0o600 });\n await chmod(hostBackup, 0o600).catch(() => {});\n extracted.push(spec.kind);\n log(`extracted ${spec.kind} login from box to ${hostBackup}`);\n } catch (err) {\n log(\n `WARN: ${spec.kind} credential extract failed (${err instanceof Error ? err.message : String(err)}) — skipping`,\n );\n }\n }\n return extracted;\n}\n","/**\n * Per-box, incremental seed of Claude Code's dynamic config (global\n * `~/.claude/workflows/` + the project's `memory/`) into a cloud sandbox.\n *\n * The static config (plugins/skills/settings) is baked into the prepare-time\n * snapshot; workflows + memory change between runs, so we ship them on every\n * create — like credentials, but diffed per-file so re-creates carry only what\n * changed. The box records what it holds in a manifest at\n * {@link BOX_DYNAMIC_SYNC_MANIFEST}; because that file lives on the box\n * filesystem it rides along in every checkpoint, so a checkpoint boot only\n * syncs files changed on the host since the snapshot.\n *\n * Transport is the credential pattern — `backend.uploadFile` + `backend.exec`\n * (tar over the SDK / scp), no rsync — so it works on daytona, hetzner, and\n * vercel alike. `backend.exec` runs as `vscode` on all three, so extraction\n * into the vscode-owned home needs no chown.\n */\n\nimport { mkdtemp, rm, writeFile } from 'node:fs/promises';\nimport { tmpdir } from 'node:os';\nimport { dirname, join } from 'node:path';\nimport {\n BOX_DYNAMIC_SYNC_MANIFEST,\n BOX_MEMORY_DIR,\n BOX_WORKFLOWS_DIR,\n buildHostSyncManifest,\n computeSyncDelta,\n stageDynamicSyncTarball,\n type DynamicSyncManifest,\n} from '@agentbox/sandbox-docker';\nimport type { CloudBackend, CloudHandle } from '@agentbox/core';\n\nexport interface SeedDynamicConfigOptions {\n /** Host-absolute workspace path (locates the project's memory dir). */\n workspacePath: string;\n onLog?: (line: string) => void;\n}\n\n/** Single-quote a path for safe interpolation into the extract shell command. */\nfunction sq(p: string): string {\n return `'${p.replace(/'/g, `'\\\\''`)}'`;\n}\n\nconst REMOTE_TAR = '/tmp/agentbox-dynsync.tar.gz';\nconst BOX_STAGE = '/tmp/agentbox-dynsync-stage';\n\n/**\n * Diff the host's workflows + memory against the box's manifest and upload only\n * the delta. Best-effort: never throws into box creation. Runs on both fresh\n * and checkpoint boots — the manifest diff makes it a no-op when nothing\n * changed.\n */\nexport async function seedDynamicConfig(\n backend: CloudBackend,\n handle: CloudHandle,\n opts: SeedDynamicConfigOptions,\n): Promise<void> {\n const log = opts.onLog ?? (() => {});\n\n try {\n // 1. Read the manifest the box already carries (absent on a fresh box).\n let boxManifest: DynamicSyncManifest | null = null;\n try {\n const res = await backend.exec(handle, `cat ${BOX_DYNAMIC_SYNC_MANIFEST} 2>/dev/null || true`);\n const out = res.stdout.trim();\n if (res.exitCode === 0 && out.length > 0) {\n boxManifest = JSON.parse(out) as DynamicSyncManifest;\n }\n } catch {\n boxManifest = null; // treat unreadable/corrupt manifest as fresh\n }\n\n // 2. Hash the host sets, 3. diff.\n const host = await buildHostSyncManifest(opts.workspacePath);\n const delta = computeSyncDelta(host, boxManifest);\n if (delta.uploads.length === 0 && delta.deletions.length === 0) {\n log('claude workflows + memory already up to date in box');\n return;\n }\n delta.nextManifest.syncedAt = new Date().toISOString();\n\n // 4. Stage the changed files + the manifest.\n const staged = await stageDynamicSyncTarball(delta.uploads);\n const manifestDir = await mkdtemp(join(tmpdir(), 'agentbox-dynsync-manifest-'));\n const manifestTmp = join(manifestDir, 'dynamic-sync.json');\n await writeFile(manifestTmp, JSON.stringify(delta.nextManifest, null, 2));\n\n try {\n const steps: string[] = [\n 'set -e',\n `mkdir -p /home/vscode/.agentbox ${BOX_WORKFLOWS_DIR} ${BOX_MEMORY_DIR}`,\n ];\n if (staged.tarballPath) {\n await backend.uploadFile(handle, staged.tarballPath, REMOTE_TAR);\n steps.push(\n `rm -rf ${BOX_STAGE}`,\n `mkdir -p ${BOX_STAGE}`,\n `tar -xzf ${REMOTE_TAR} -C ${BOX_STAGE}`,\n `if [ -d ${BOX_STAGE}/workflows ]; then cp -a ${BOX_STAGE}/workflows/. ${BOX_WORKFLOWS_DIR}/; fi`,\n `if [ -d ${BOX_STAGE}/memory ]; then cp -a ${BOX_STAGE}/memory/. ${BOX_MEMORY_DIR}/; fi`,\n `rm -rf ${BOX_STAGE} ${REMOTE_TAR}`,\n );\n }\n for (const d of delta.deletions) {\n steps.push(`rm -f ${sq(d.dst)}`);\n }\n const res = await backend.exec(handle, steps.join('; '));\n if (res.exitCode !== 0) {\n log(\n `dynamic config seed failed (exit ${String(res.exitCode)}): ` +\n `${res.stderr.slice(-200)}`,\n );\n return;\n }\n\n // 5. Record the new manifest last — a failed extract must not record\n // state the box never reached.\n await backend.uploadFile(handle, manifestTmp, BOX_DYNAMIC_SYNC_MANIFEST);\n log(\n `seeded claude workflows + memory: ${String(delta.uploads.length)} file(s) updated, ` +\n `${String(delta.deletions.length)} removed`,\n );\n } finally {\n await staged.cleanup();\n await rm(dirname(manifestTmp), { recursive: true, force: true });\n }\n } catch (err) {\n log(\n `claude workflows + memory seed skipped (non-fatal): ` +\n `${err instanceof Error ? err.message : String(err)}`,\n );\n }\n}\n","/**\n * Per-create overlay of the in-box `~/.claude/_claude.json` from the host's\n * current `~/.claude.json` state.\n *\n * Runs on every cloud create across e2b/vercel/hetzner/daytona. The other\n * cloud providers also bake a `_claude.json` into their snapshot at prepare\n * time, but that baked file becomes stale if the host completes Claude's\n * onboarding (or changes theme) after `agentbox prepare`. E2B doesn't bake\n * `_claude.json` at all — only the symlink `~/.claude.json` ->\n * `~/.claude/_claude.json` — so without this overlay a fresh E2B box has no\n * `_claude.json` and Claude shows the theme picker on first run.\n *\n * The payload is one tiny JSON file; transport is `backend.uploadFile` +\n * `backend.exec`, the same primitive used for credentials/dynamic-sync. The\n * extract runs as `vscode`, so no chown is needed.\n *\n * Best-effort: a failure logs and never sinks `agentbox create`. The in-box\n * Claude will fall back to its baked / first-run behavior.\n */\n\nimport { stageClaudeJsonOnlyForUpload } from '@agentbox/sandbox-docker';\nimport type { CloudBackend, CloudHandle } from '@agentbox/core';\n\nexport interface SeedClaudeJsonOptions {\n /** Host-absolute workspace path being mounted at `/workspace` in the box. */\n hostWorkspace?: string;\n onLog?: (line: string) => void;\n}\n\nconst REMOTE_TAR = '/tmp/agentbox-claude-json.tar.gz';\nconst BOX_CLAUDE_DIR = '/home/vscode/.claude';\n\n/**\n * Stage `_claude.json` from the host, upload it to the box, and extract into\n * `~/.claude/`. Overwrites any baked `_claude.json` — this is intentional, the\n * baked one is a prepare-time snapshot and we want the latest host state.\n */\nexport async function seedClaudeJsonAtCreate(\n backend: CloudBackend,\n handle: CloudHandle,\n opts: SeedClaudeJsonOptions = {},\n): Promise<void> {\n const log = opts.onLog ?? (() => {});\n let staged: Awaited<ReturnType<typeof stageClaudeJsonOnlyForUpload>> | null = null;\n try {\n staged = await stageClaudeJsonOnlyForUpload({ hostWorkspace: opts.hostWorkspace });\n if (staged.tarballPath === null) {\n log('claude: no _claude.json overlay (host has no claude config)');\n return;\n }\n await backend.uploadFile(handle, staged.tarballPath, REMOTE_TAR);\n const extract = await backend.exec(\n handle,\n `set -e; mkdir -p ${BOX_CLAUDE_DIR}; ` +\n `tar -xzf ${REMOTE_TAR} -C ${BOX_CLAUDE_DIR}; ` +\n `rm -f ${REMOTE_TAR}`,\n );\n if (extract.exitCode !== 0) {\n log(\n `claude: _claude.json overlay extract failed (exit ${String(extract.exitCode)}); ` +\n `stderr: ${extract.stderr.slice(-200)}`,\n );\n return;\n }\n log('claude: _claude.json overlay seeded');\n } catch (err) {\n log(\n `claude: _claude.json overlay failed (continuing): ${err instanceof Error ? err.message : String(err)}`,\n );\n } finally {\n if (staged) await staged.cleanup();\n }\n}\n","import { execa } from 'execa';\nimport type { CloudBackend, CloudHandle } from '@agentbox/core';\nimport { bashScript, quoteShellArg } from './shell.js';\n\nexport interface SeedGitIdentityOptions {\n /** Host repo dir to read the effective `user.name`/`user.email` from. */\n hostRepo?: string;\n onLog?: (line: string) => void;\n}\n\n/** Generic fallback so a box always has a usable committer identity. */\nconst FALLBACK_NAME = 'agentbox';\nconst FALLBACK_EMAIL = 'agentbox@users.noreply.github.com';\n\n/**\n * Configure a git committer identity inside a cloud box.\n *\n * Docker boxes bind-mount the host `~/.gitconfig`, so they inherit the user's\n * identity for free. Cloud boxes (vercel/hetzner/daytona) can't bind-mount and\n * otherwise have *no* identity — which breaks any in-box commit: the agent's\n * own `git commit`, and the merge commit `agentbox git pull` writes. We mirror\n * the Docker behavior here: author as the host user when their identity is\n * resolvable, and fall back to a generic agentbox identity so commits never\n * fail with \"Committer identity unknown\".\n *\n * Reads the *effective* identity from the host repo (`git -C <repo> config\n * user.name`), so a repo-local override is honored just like a normal local\n * commit would. Sets `--global` for the box's agent user (cloud `exec` runs as\n * that user), which is where the in-box merge / agent commits look it up.\n */\nexport async function seedGitIdentity(\n backend: CloudBackend,\n handle: CloudHandle,\n opts: SeedGitIdentityOptions = {},\n): Promise<void> {\n const log = opts.onLog ?? (() => {});\n const name = (await readHostGitConfig('user.name', opts.hostRepo)) ?? FALLBACK_NAME;\n const email = (await readHostGitConfig('user.email', opts.hostRepo)) ?? FALLBACK_EMAIL;\n\n const script =\n `git config --global user.name ${quoteShellArg(name)} && ` +\n `git config --global user.email ${quoteShellArg(email)}`;\n const r = await backend.exec(handle, bashScript(script));\n if (r.exitCode !== 0) {\n // Non-fatal: the box still boots; the user just sees the identity error on\n // the next commit, same as before this step existed.\n log(`git: identity config failed (exit ${String(r.exitCode)}): ${(r.stderr || r.stdout).trim()}`);\n return;\n }\n log(`git: configured committer identity ${name} <${email}>`);\n}\n\n/** Read a host git config value (effective: system + global + repo-local). */\nasync function readHostGitConfig(key: string, hostRepo?: string): Promise<string | null> {\n const args = hostRepo ? ['-C', hostRepo, 'config', key] : ['config', key];\n const r = await execa('git', args, { reject: false });\n if (r.exitCode !== 0) return null;\n const value = (r.stdout ?? '').trim();\n return value.length > 0 ? value : null;\n}\n","/**\n * Build a single shell-safe command string from an argv array. Used everywhere\n * we hand a cloud backend's `exec(handle, cmd, ...)` an argv that originated\n * from CLI input — single-quoting every arg neutralises shell metacharacters.\n */\nexport function quoteShellArgv(argv: readonly string[]): string {\n return argv.map(quoteShellArg).join(' ');\n}\n\nexport function quoteShellArg(arg: string): string {\n if (arg.length === 0) return \"''\";\n // Fast-path for safe identifiers, paths, simple options: avoid quotes for\n // readability in logs. Anything else falls through to single-quoting.\n if (/^[A-Za-z0-9_@%+=:,./-]+$/.test(arg)) return arg;\n return \"'\" + arg.replace(/'/g, \"'\\\\''\") + \"'\";\n}\n\n/**\n * Wrap a multi-line shell script body so it runs under `bash -c` regardless\n * of what `/bin/sh` points at in the sandbox. Necessary on Daytona's images\n * where `executeCommand` shells out via `dash`, which rejects bash idioms\n * like `set -o pipefail`. Use this for any script that isn't trivially\n * POSIX-only.\n */\nexport function bashScript(body: string): string {\n return `bash -c ${quoteShellArg(body)}`;\n}\n","/**\n * Cloud checkpoint store — parallel to `packages/sandbox-docker/src/checkpoint.ts`\n * but backed by provider-native snapshots (Daytona's `_experimental_createSnapshot`)\n * instead of local Docker image tags.\n *\n * Each user-facing checkpoint (`setup`, `with-deps`, …) is scoped to a project\n * and stored as a thin manifest on the host:\n *\n * ~/.agentbox/cloud-checkpoints/<backend>/<projectHash-mnemonic>/<name>/manifest.json\n *\n * The manifest maps the project-scoped name to a provider-unique snapshot name\n * — Daytona snapshots are org-wide, so the snapshot name is prefixed with the\n * project hash to avoid collisions across projects (and across users in the\n * same org).\n */\n\nimport { mkdir, readFile, readdir, rm, writeFile } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { basename, join } from 'node:path';\nimport type { CloudBackend } from '@agentbox/core';\nimport { hashProjectPath, projectDirSegment, sanitizeMnemonic } from '@agentbox/config';\nimport { type PreparedProviderKind, readPreparedStateRaw } from '@agentbox/sandbox-core';\n\nexport const CLOUD_CHECKPOINTS_ROOT = join(homedir(), '.agentbox', 'cloud-checkpoints');\n\n/**\n * All cloud snapshot names share this prefix so a stray `agentbox-ckpt-*`\n * snapshot in the Daytona dashboard is clearly recognisable as AgentBox's.\n * Mirrors `CHECKPOINT_IMAGE_PREFIX` from the docker package.\n */\nexport const CLOUD_SNAPSHOT_NAME_PREFIX = 'agentbox-ckpt-';\n\nexport interface CloudCheckpointManifest {\n /**\n * Schema history:\n * 1 — original fields (no base fingerprint; staleness unverifiable)\n * 2 — adds `baseProvider`, `baseFingerprint`, `cliVersion` so the wizard\n * can tell a checkpoint captured against a now-rebuilt base snapshot\n * from a fresh one. A legacy schema-1 manifest has no fingerprint and\n * is treated as \"stale / unverifiable\" by `evaluateCheckpoint`.\n */\n schema: 1 | 2;\n /** User-facing, project-scoped name (e.g. \"setup\"). */\n name: string;\n /** Cloud backend the snapshot lives in (e.g. \"daytona\"). */\n backend: string;\n /**\n * Provider-unique snapshot name — what the backend's `createSnapshot()` was\n * called with, and what gets passed to `provision({ snapshot })` on restore.\n */\n snapshotName: string;\n sourceBoxId: string;\n sourceBoxName: string;\n /**\n * Cloud provider whose base-snapshot fingerprint this checkpoint was\n * captured against. Schema-2+ only.\n */\n baseProvider?: string;\n /**\n * Build-context fingerprint of the base snapshot at capture time (the\n * provider's `prepared-state` `contextSha256`). Schema-2+ only; missing →\n * legacy schema-1 → \"unverifiable / stale\".\n */\n baseFingerprint?: string;\n /** CLI version that captured the checkpoint. Schema-2+ only. */\n cliVersion?: string;\n createdAt: string;\n}\n\nexport interface CloudCheckpointInfo {\n name: string;\n /** Host dir holding `manifest.json`. */\n dir: string;\n manifest: CloudCheckpointManifest;\n}\n\n/**\n * Deterministic provider-unique snapshot name for a project checkpoint. The\n * project-hash prefix prevents collisions across projects (and across users\n * in the same Daytona org); the mnemonic suffix keeps the Daytona dashboard\n * readable. The leading `agentbox-ckpt-` lets cleanup scripts recognise our\n * snapshots.\n */\nexport function cloudSnapshotName(projectRoot: string, name: string): string {\n const mnemonic = sanitizeMnemonic(basename(projectRoot));\n return `${CLOUD_SNAPSHOT_NAME_PREFIX}${hashProjectPath(projectRoot)}_${mnemonic}-${name}`;\n}\n\nfunction backendDir(backend: string, projectRoot: string): string {\n return join(CLOUD_CHECKPOINTS_ROOT, backend, projectDirSegment(projectRoot));\n}\n\nfunction checkpointDir(backend: string, projectRoot: string, name: string): string {\n return join(backendDir(backend, projectRoot), name);\n}\n\nasync function readManifest(dir: string): Promise<CloudCheckpointManifest | null> {\n try {\n const raw = await readFile(join(dir, 'manifest.json'), 'utf8');\n const m = JSON.parse(raw) as CloudCheckpointManifest;\n if (m.schema !== 1 && m.schema !== 2) return null;\n return m;\n } catch {\n return null;\n }\n}\n\n/**\n * Read every valid cloud checkpoint manifest directly under `root` (a backend's\n * `<hash>-<mnemonic>` project dir), sorted by `createdAt`. Shared by the scoped\n * and global listers. Missing root / unreadable manifests are skipped.\n */\nasync function listCloudCheckpointsInDir(root: string): Promise<CloudCheckpointInfo[]> {\n let entries: string[];\n try {\n entries = (await readdir(root, { withFileTypes: true }))\n .filter((e) => e.isDirectory())\n .map((e) => e.name);\n } catch {\n return [];\n }\n const out: CloudCheckpointInfo[] = [];\n for (const name of entries) {\n const dir = join(root, name);\n const manifest = await readManifest(dir);\n if (manifest) out.push({ name, dir, manifest });\n }\n out.sort((a, b) => a.manifest.createdAt.localeCompare(b.manifest.createdAt));\n return out;\n}\n\nexport async function listCloudCheckpoints(\n projectRoot: string,\n backend: string,\n): Promise<CloudCheckpointInfo[]> {\n return listCloudCheckpointsInDir(backendDir(backend, projectRoot));\n}\n\nexport interface CloudCheckpointProjectGroup {\n /** `<hash>-<mnemonic>` dir name under CLOUD_CHECKPOINTS_ROOT/<backend>/. */\n segment: string;\n items: CloudCheckpointInfo[];\n}\n\n/**\n * Every project's cloud checkpoints for `backend`, one group per project dir.\n * Best-effort: a missing backend root returns `[]`, and segments with zero\n * valid manifests are dropped. Used by `checkpoints -g`.\n */\nexport async function listAllCloudCheckpoints(\n backend: string,\n): Promise<CloudCheckpointProjectGroup[]> {\n const backendRoot = join(CLOUD_CHECKPOINTS_ROOT, backend);\n let segments: string[];\n try {\n segments = (await readdir(backendRoot, { withFileTypes: true }))\n .filter((e) => e.isDirectory())\n .map((e) => e.name);\n } catch {\n return [];\n }\n const out: CloudCheckpointProjectGroup[] = [];\n for (const segment of segments) {\n const items = await listCloudCheckpointsInDir(join(backendRoot, segment));\n if (items.length > 0) out.push({ segment, items });\n }\n return out;\n}\n\nexport async function resolveCloudCheckpoint(\n projectRoot: string,\n backend: string,\n ref: string,\n): Promise<CloudCheckpointInfo | null> {\n const dir = checkpointDir(backend, projectRoot, ref);\n const manifest = await readManifest(dir);\n if (!manifest) return null;\n return { name: ref, dir, manifest };\n}\n\nexport interface WriteCloudManifestFields {\n snapshotName: string;\n sourceBoxId: string;\n sourceBoxName: string;\n baseProvider?: string;\n baseFingerprint?: string;\n cliVersion?: string;\n}\n\nexport async function writeCloudCheckpointManifest(\n projectRoot: string,\n backend: string,\n name: string,\n fields: WriteCloudManifestFields,\n): Promise<CloudCheckpointInfo> {\n const dir = checkpointDir(backend, projectRoot, name);\n await mkdir(dir, { recursive: true });\n const manifest: CloudCheckpointManifest = {\n schema: 2,\n name,\n backend,\n snapshotName: fields.snapshotName,\n sourceBoxId: fields.sourceBoxId,\n sourceBoxName: fields.sourceBoxName,\n baseProvider: fields.baseProvider,\n baseFingerprint: fields.baseFingerprint,\n cliVersion: fields.cliVersion,\n createdAt: new Date().toISOString(),\n };\n await writeFile(join(dir, 'manifest.json'), JSON.stringify(manifest, null, 2) + '\\n', 'utf8');\n return { name, dir, manifest };\n}\n\n/**\n * Current base-snapshot build-context fingerprint for a cloud provider, read\n * from its `~/.agentbox/<provider>-prepared.json`. Returns `undefined` when no\n * prepared state exists or it predates fingerprinting — callers then can't\n * verify staleness and must not falsely flag a checkpoint as stale.\n */\nexport function currentCloudBaseFingerprint(provider: string): string | undefined {\n try {\n const raw = readPreparedStateRaw(provider as PreparedProviderKind) as {\n base?: { contextSha256?: string };\n } | null;\n return raw?.base?.contextSha256;\n } catch {\n return undefined;\n }\n}\n\nexport async function removeCloudCheckpointDir(\n projectRoot: string,\n backend: string,\n name: string,\n): Promise<boolean> {\n const dir = checkpointDir(backend, projectRoot, name);\n const existed = (await readManifest(dir)) !== null;\n if (!existed) return false;\n await rm(dir, { recursive: true, force: true });\n return true;\n}\n\n/**\n * Probe whether a cloud checkpoint's underlying provider snapshot is still\n * bootable, pruning the dangling local manifest when it has expired or been\n * deleted out-of-band. Lets the create / wizard paths recover gracefully —\n * fall back to a from-scratch box and re-ask the setup wizard — instead of\n * letting `provision()` 410 on a snapshot that no longer exists.\n *\n * Returns `{ live: false }` when there is no manifest for `ref`. When the\n * backend can't probe (`snapshotExists` unimplemented) the snapshot is assumed\n * live: we never prune on uncertainty.\n */\nexport async function probeCloudCheckpoint(\n backend: Pick<CloudBackend, 'name' | 'snapshotExists'>,\n projectRoot: string,\n ref: string,\n): Promise<{ live: boolean; pruned: boolean }> {\n const found = await resolveCloudCheckpoint(projectRoot, backend.name, ref);\n if (!found) return { live: false, pruned: false };\n if (!backend.snapshotExists) return { live: true, pruned: false };\n const live = await backend.snapshotExists(found.manifest.snapshotName);\n if (live) return { live: true, pruned: false };\n await removeCloudCheckpointDir(projectRoot, backend.name, ref);\n return { live: false, pruned: true };\n}\n","/**\n * Detect the \"the snapshot I tried to boot from is gone\" failure across cloud\n * backends. Vercel surfaces it as an `APIError` with HTTP 410 (\"Gone\") and a\n * body of `{ error: { message: 'Snapshot expired or deleted.' } }`; other\n * backends phrase it differently. We match on the status code and a few\n * message shapes so the create path can fall back to a from-scratch box\n * instead of crashing when a base/checkpoint snapshot has been reaped.\n */\nexport function isSnapshotGoneError(err: unknown): boolean {\n if (err === null || typeof err !== 'object') return false;\n const e = err as {\n status?: unknown;\n response?: { status?: unknown };\n json?: { error?: { message?: unknown } };\n message?: unknown;\n };\n const status = e.response?.status ?? e.status;\n if (status === 410) return true;\n const parts = [\n typeof e.json?.error?.message === 'string' ? e.json.error.message : '',\n typeof e.message === 'string' ? e.message : '',\n ];\n const msg = parts.join(' ').toLowerCase();\n return (\n /snapshot[^.]*\\b(expired|deleted|gone|not[ -]?found)\\b/.test(msg) ||\n msg.includes('expired or deleted')\n );\n}\n","/**\n * Copy host env/config files (`.env`, `secrets.toml`, `agentbox.yaml`, …) into\n * a cloud sandbox's `/workspace` at create time. The cloud counterpart of\n * `copyHostEnvFilesToBox` in sandbox-docker — same `find` + `tar --null -T -`\n * packer on the host, swaps `docker exec tar -xf` for `backend.uploadFile` +\n * `backend.exec(tar -xf)`.\n *\n * The wizard collects `envFilesToImport` in apps/cli/src/wizard.ts (the same\n * field the Docker provider already honours). This module makes the cloud\n * provider honour it too.\n *\n * Best-effort: a scan/pack failure or empty match set logs and returns the\n * count rather than throwing — a missing optional secret mustn't abort an\n * otherwise healthy box.\n */\n\nimport { mkdtemp, rm, writeFile } from 'node:fs/promises';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\nimport { execa } from 'execa';\nimport { buildHostEnvFindArgs } from '@agentbox/sandbox-docker';\nimport type { CloudBackend, CloudHandle } from '@agentbox/core';\n\nexport interface UploadEnvFilesArgs {\n backend: CloudBackend;\n handle: CloudHandle;\n /** Absolute host workspace path the find runs against. */\n workspacePath: string;\n /** Glob patterns selected by the wizard (e.g. `.env`, `secrets.toml`). */\n files: string[];\n /** In-sandbox `/workspace` mount. Always `/workspace` today; configurable for tests. */\n workspaceDir?: string;\n onLog?: (line: string) => void;\n}\n\nexport interface UploadEnvFilesResult {\n /** Number of files written into the sandbox. 0 when nothing matched. */\n copied: number;\n}\n\nconst WORKSPACE_DIR_DEFAULT = '/workspace';\nconst REMOTE_TAR_PATH = '/tmp/agentbox-envfiles.tar';\n\nexport async function uploadEnvFiles(args: UploadEnvFilesArgs): Promise<UploadEnvFilesResult> {\n const log = args.onLog ?? (() => {});\n if (args.files.length === 0) return { copied: 0 };\n const workspaceDir = args.workspaceDir ?? WORKSPACE_DIR_DEFAULT;\n\n // 1. Enumerate matched files on the host with `find -print0` (NUL-delimited)\n // using exactly the same arg builder Docker uses, so the patterns + the\n // prune set behave identically across providers.\n const found = await execa('find', buildHostEnvFindArgs(args.files).slice(1), {\n cwd: args.workspacePath,\n reject: false,\n });\n if (found.exitCode !== 0) {\n log(`env-file scan failed: ${String(found.stderr).slice(0, 300)}`);\n return { copied: 0 };\n }\n const list = String(found.stdout)\n .split('\\0')\n .filter((p) => p.length > 0);\n if (list.length === 0) return { copied: 0 };\n\n // 2. Pack the matched files into a tar on the host. `--null -T -` reads the\n // file list NUL-delimited from stdin so paths with whitespace survive.\n // We write to a tempfile (rather than streaming) because backend.uploadFile\n // takes a local file path, not a stream.\n const stage = await mkdtemp(join(tmpdir(), 'agentbox-envfiles-'));\n const localTar = join(stage, 'envfiles.tar');\n try {\n const packed = await execa(\n 'tar',\n ['-C', args.workspacePath, '--null', '-T', '-', '-cf', localTar],\n { input: list.join('\\0'), reject: false },\n );\n if (packed.exitCode !== 0) {\n log(`env-file tar pack failed: ${String(packed.stderr).slice(0, 300)}`);\n return { copied: 0 };\n }\n // Ensure the file exists even when tar packed nothing useful (best-effort).\n await writeFile(join(stage, '.marker'), '').catch(() => {});\n\n // 3. Upload the tar into the sandbox + extract under /workspace. Same\n // `--no-same-*` + `-m` flags we use for the credential extracts: future-\n // proofs against ever putting /workspace on Daytona's FUSE volume tier\n // (chmod/utime would otherwise EPERM) and is harmless on regular disk.\n // `rm -f` cleans the staging tar so the sandbox /tmp doesn't accumulate\n // leftovers across multiple creates against the same handle (cheap).\n await args.backend.uploadFile(args.handle, localTar, REMOTE_TAR_PATH);\n const extract = await args.backend.exec(\n args.handle,\n `tar -xf ${REMOTE_TAR_PATH} -C ${workspaceDir} --no-same-permissions --no-same-owner -m && rm -f ${REMOTE_TAR_PATH}`,\n );\n if (extract.exitCode !== 0) {\n log(\n `env-file extract failed (exit ${String(extract.exitCode)}); ` +\n `stdout: ${extract.stdout.slice(-200)} stderr: ${extract.stderr.slice(-200)}`,\n );\n return { copied: 0 };\n }\n } finally {\n await rm(stage, { recursive: true, force: true });\n }\n return { copied: list.length };\n}\n","/**\n * Apply the `carry:` block from `agentbox.yaml` against a cloud sandbox.\n *\n * Mirror of `copyCarryPathsToBox` in `@agentbox/sandbox-docker`: per-entry tar\n * upload + extract, with destinations that may live anywhere in the box\n * (not constrained to /workspace). Runs after `uploadEnvFiles` and before the\n * supervisor launches, so the first declared task sees the carry files\n * already in place.\n *\n * Best-effort per-entry: a single failed entry is recorded in `errors` and\n * the function returns — the box stays usable; the caller logs the misses.\n */\n\nimport { mkdtemp, rm } from 'node:fs/promises';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\nimport { execa } from 'execa';\nimport type { CloudBackend, CloudHandle, ResolvedCarryEntry } from '@agentbox/core';\n\nexport interface UploadCarryArgs {\n backend: CloudBackend;\n handle: CloudHandle;\n entries: ResolvedCarryEntry[];\n onLog?: (line: string) => void;\n}\n\nexport interface UploadCarryResult {\n copied: number;\n errors: string[];\n /** Audit summary for BoxRecord.carry. */\n applied: Array<{ src: string; dest: string; bytes: number }>;\n}\n\n/** Hardcoded in-box home; cloud boxes always run as the `vscode` user. */\nconst BOX_HOME = '/home/vscode';\n\nexport async function uploadCarryPaths(args: UploadCarryArgs): Promise<UploadCarryResult> {\n const log = args.onLog ?? (() => {});\n if (args.entries.length === 0) {\n return { copied: 0, errors: [], applied: [] };\n }\n\n const stage = await mkdtemp(join(tmpdir(), 'agentbox-carry-'));\n const errors: string[] = [];\n const applied: UploadCarryResult['applied'] = [];\n let copied = 0;\n\n try {\n for (const [i, entry] of args.entries.entries()) {\n const where = `carry[${String(i)}] \"${entry.rawSrc}\"`;\n if (entry.kind === 'missing') {\n log(`${where}: skipped (missing on host, optional)`);\n continue;\n }\n try {\n await uploadOneEntry({\n backend: args.backend,\n handle: args.handle,\n entry,\n stageDir: stage,\n index: i,\n });\n copied += 1;\n applied.push({ src: entry.absSrc, dest: entry.absDest, bytes: entry.bytes ?? 0 });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n errors.push(`${where}: ${msg}`);\n log(`${where}: failed: ${msg}`);\n }\n }\n } finally {\n await rm(stage, { recursive: true, force: true });\n }\n\n return { copied, errors, applied };\n}\n\ninterface UploadOneArgs {\n backend: CloudBackend;\n handle: CloudHandle;\n entry: ResolvedCarryEntry;\n stageDir: string;\n index: number;\n}\n\nasync function uploadOneEntry(args: UploadOneArgs): Promise<void> {\n const { entry } = args;\n if (entry.kind === 'missing') return;\n\n // ~/ → /home/vscode at this layer (host-side). Never expanded inside the box\n // because the supervisor user's $HOME equals BOX_HOME, but the exec shell's\n // current user (the SDK's default) is not guaranteed to be vscode on every\n // backend — expanding here makes the destination path explicit.\n const boxDest = entry.absDest.startsWith('~/')\n ? `${BOX_HOME}/${entry.absDest.slice(2)}`\n : entry.absDest;\n\n const isDir = entry.kind === 'dir';\n const parentDir = isDir ? boxDest : dirnameUnix(boxDest);\n\n // 1. Tar the host source on disk so backend.uploadFile (which takes a path,\n // not a stream) has something to send.\n const localTar = join(args.stageDir, `carry-${String(args.index)}.tar`);\n const excludeArgs = isDir ? (entry.exclude ?? []).map((p) => `--exclude=${p}`) : [];\n const tarArgs = isDir\n ? ['-C', entry.absSrc, '-cf', localTar, ...excludeArgs, '.']\n : ['-C', dirnameUnix(entry.absSrc), '-cf', localTar, basenameUnix(entry.absSrc)];\n const packed = await execa('tar', tarArgs, { reject: false });\n if (packed.exitCode !== 0) {\n throw new Error(`tar pack failed: ${String(packed.stderr).slice(0, 300)}`);\n }\n\n // 2. Upload the tar into the sandbox under a temp path.\n const remoteTar = `/tmp/agentbox-carry-${String(args.index)}.tar`;\n await args.backend.uploadFile(args.handle, localTar, remoteTar);\n\n // 3. mkdir + extract + optional chmod + optional chown + cleanup, in one\n // bash command. Single-quoted args inside double-quoted command string —\n // paths are safe because carry: dest values are user-provided absolute\n // paths the resolver already vetted.\n const mode = entry.mode !== undefined ? entry.mode.toString(8).padStart(4, '0') : '';\n // Default: chown to the in-box vscode user (uid 1000). Explicit `user: 0`\n // (root) skips the chown so a root-owned extract stays root-owned.\n const uid = entry.user ?? 1000;\n // For files: tar's input contains a single entry at basename(absSrc), and\n // we extract at the dest's parent, then `mv` to the dest if the source\n // basename differs from the dest basename.\n const fileBase = !isDir ? basenameUnix(entry.absSrc) : '';\n const destBase = !isDir ? basenameUnix(boxDest) : '';\n const renameNeeded = !isDir && fileBase !== destBase;\n const parts: string[] = [\n `mkdir -p ${shellQuote(parentDir)}`,\n isDir\n ? `tar -xf ${remoteTar} -C ${shellQuote(boxDest)} --no-same-permissions --no-same-owner -m`\n : `tar -xf ${remoteTar} -C ${shellQuote(parentDir)} --no-same-permissions --no-same-owner -m`,\n ];\n if (renameNeeded) {\n parts.push(\n `mv ${shellQuote(`${parentDir}/${fileBase}`)} ${shellQuote(boxDest)}`,\n );\n }\n if (mode) parts.push(`chmod -R ${mode} ${shellQuote(boxDest)}`);\n parts.push(`chown -R ${String(uid)}:${String(uid)} ${shellQuote(boxDest)}`);\n // Parent-chain chown: `mkdir -p` ran as root, so any new dirs between\n // $HOME and dirname(boxDest) are root-owned. Walk back up to $HOME\n // (exclusive) and chown each. Only when dest is under $HOME — system\n // paths like /etc/* keep their existing ownership.\n if (boxDest.startsWith(BOX_HOME + '/') && parentDir !== BOX_HOME) {\n parts.push(\n `parent=$(dirname ${shellQuote(boxDest)}); ` +\n `while [ \"$parent\" != \"${BOX_HOME}\" ] && [ \"$parent\" != \"/\" ]; do ` +\n `chown ${String(uid)}:${String(uid)} \"$parent\"; ` +\n `parent=$(dirname \"$parent\"); ` +\n `done`,\n );\n }\n parts.push(`rm -f ${remoteTar}`);\n const cmd = parts.join(' && ');\n\n // Vercel-only: force the extract to run as root. Vercel's exec wraps a\n // non-root command in `sudo -u vscode -H bash -lc '<cmd>'`, and that extra\n // `bash -lc` nesting mangles this command's `$(...)`/`$var`/`while` (the\n // parent var expands empty → `dirname \".\"` loops forever → the exec hangs\n // until timeout, surfacing as \"Stream ended before command finished\"). Its\n // single-`bash -lc` root path doesn't re-parse, so the command runs cleanly.\n // The command still chowns the dest to the target uid (default vscode 1000),\n // so files end up vscode-owned and writable regardless of who runs it.\n //\n // Scoped explicitly to Vercel rather than relying on other backends ignoring\n // `user:` — Hetzner/Daytona keep their existing (working) carry path\n // unchanged even if they start honoring `user` later.\n // E2B joins the vercel carve-out: its default exec runs as `vscode` (uid\n // 1000), which cannot `chown` files to other uids. The carry chain ends with\n // a `chown -R 1000:1000`, so as vscode it errors with \"Operation not\n // permitted\" and the parent-chain loop never reaches its terminator. Forcing\n // root makes the chown a no-op (target uid matches existing owner) and lets\n // the parent-chain walk complete.\n const wantsRoot = args.backend.name === 'vercel' || args.backend.name === 'e2b';\n const execOpts = wantsRoot ? { user: 'root' as const } : undefined;\n const res = await args.backend.exec(args.handle, cmd, execOpts);\n if (res.exitCode !== 0) {\n throw new Error(\n `in-box extract failed (exit ${String(res.exitCode)}): ${(res.stderr || res.stdout).slice(-300)}`,\n );\n }\n}\n\nfunction dirnameUnix(p: string): string {\n const i = p.lastIndexOf('/');\n if (i <= 0) return '/';\n return p.slice(0, i);\n}\n\nfunction basenameUnix(p: string): string {\n const i = p.lastIndexOf('/');\n return i < 0 ? p : p.slice(i + 1);\n}\n\n/** Single-quote a shell argument; safe for any byte except NUL. */\nfunction shellQuote(s: string): string {\n return `'${s.replace(/'/g, `'\\\\''`)}'`;\n}\n","/**\n * Extract the internal `expose.port` values from a workspace's\n * `agentbox.yaml`. The cloud provider mints a preview URL per port so\n * users can hit services directly (the WebProxy on port 8080 also\n * stays — this is a side channel for raw access).\n *\n * Intentionally minimal: we don't validate the rest of the schema. The\n * supervisor enforces correctness at run-time; here we just need the\n * numeric `services.*.expose.port` values. Errors (missing file, bad\n * YAML, unexpected shape) silently degrade to \"no extra ports\", which\n * matches the existing \"URL is best-effort at create\" semantics.\n */\n\nimport { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { parse as parseYaml } from 'yaml';\n\nexport async function readExposedServicePorts(workspacePath: string): Promise<number[]> {\n let text: string;\n try {\n text = await readFile(join(workspacePath, 'agentbox.yaml'), 'utf8');\n } catch {\n return [];\n }\n let doc: unknown;\n try {\n doc = parseYaml(text);\n } catch {\n return [];\n }\n if (!isPlainObject(doc)) return [];\n const services = doc['services'];\n if (!isPlainObject(services)) return [];\n const out = new Set<number>();\n for (const value of Object.values(services)) {\n if (!isPlainObject(value)) continue;\n const expose = value['expose'];\n if (!isPlainObject(expose)) continue;\n const port = expose['port'];\n if (typeof port === 'number' && Number.isInteger(port) && port > 0 && port < 65_536) {\n out.add(port);\n }\n }\n return [...out].sort((a, b) => a - b);\n}\n\nfunction isPlainObject(v: unknown): v is Record<string, unknown> {\n return typeof v === 'object' && v !== null && !Array.isArray(v);\n}\n","/**\n * `cp`-style file transfer for cloud boxes — symmetric host↔box uploads and\n * downloads that mirror `docker cp` semantics. The Docker provider tar-pipes\n * over `docker exec`; clouds with no exec stream can't, so we stage to a\n * single tar file in `/tmp`, transfer it via `backend.uploadFile` /\n * `downloadFile`, and unpack on the other side. Handles files and\n * directories uniformly.\n *\n * Path semantics match `docker cp`'s pragmatic subset: trailing `/` on the\n * destination means \"treat as a directory, land the source under it\"; no\n * trailing `/` means \"destination is the full target path\" (rename during\n * extraction). The in-box `test -d` probe the Docker provider uses to detect\n * existing directories isn't replicated here — it'd cost an extra exec\n * round-trip per call and the trailing-`/` convention is the explicit form\n * anyway.\n */\n\nimport { execa } from 'execa';\nimport { existsSync, mkdirSync, renameSync, statSync } from 'node:fs';\nimport { mkdtemp, rm } from 'node:fs/promises';\nimport { tmpdir } from 'node:os';\nimport {\n basename as hostBasename,\n dirname as hostDirname,\n join as hostJoin,\n resolve as hostResolve,\n} from 'node:path';\nimport { posix } from 'node:path';\nimport type { CloudBackend, CloudHandle } from '@agentbox/core';\nimport { bashScript, quoteShellArg } from './shell.js';\n\nconst REMOTE_UP_TAR = '/tmp/agentbox-cp-up.tar.gz';\nconst REMOTE_DOWN_TAR = '/tmp/agentbox-cp-down.tar.gz';\n\nexport interface CloudCpResult {\n /** Final landed path on the receiving side. */\n finalPath: string;\n}\n\nexport async function uploadToCloudBox(\n backend: CloudBackend,\n handle: CloudHandle,\n hostSrc: string,\n boxDst: string,\n exclude?: string[],\n): Promise<CloudCpResult> {\n const srcAbs = hostResolve(hostSrc);\n if (!existsSync(srcAbs)) throw new Error(`source not found: ${hostSrc}`);\n const srcBasename = hostBasename(srcAbs);\n const srcParent = hostDirname(srcAbs);\n\n // Resolve `boxParent` + final filename per docker cp rules — see file\n // header. We can't probe `test -d` cheaply, so the user opts into the\n // dir-vs-file ambiguity with the trailing slash.\n let boxParent: string;\n let finalName: string;\n if (boxDst.endsWith('/')) {\n boxParent = boxDst.replace(/\\/+$/, '') || '/';\n finalName = srcBasename;\n } else {\n boxParent = posix.dirname(boxDst);\n finalName = posix.basename(boxDst);\n }\n const finalPath = boxParent === '/' ? `/${finalName}` : `${boxParent}/${finalName}`;\n\n const stage = await mkdtemp(hostJoin(tmpdir(), 'agentbox-cp-up-'));\n const localTar = hostJoin(stage, 'payload.tar.gz');\n try {\n // COPYFILE_DISABLE silences macOS BSD tar's `._*` resource-fork stubs\n // that would otherwise litter the box's filesystem on every upload.\n const excludeArgs = (exclude ?? []).map((p) => `--exclude=${p}`);\n await execa('tar', ['-C', srcParent, '-czf', localTar, ...excludeArgs, srcBasename], {\n env: { ...process.env, COPYFILE_DISABLE: '1' },\n });\n await backend.uploadFile(handle, localTar, REMOTE_UP_TAR);\n\n // Sudo for the dir ops because `boxParent` may be outside the user's\n // writable area (e.g. /etc/foo); devcontainers/base grants vscode\n // passwordless sudo and the SUDO=:'' fallback makes it a no-op when\n // sudo isn't available (test sandboxes).\n const initialPath = boxParent === '/' ? `/${srcBasename}` : `${boxParent}/${srcBasename}`;\n // Daytona's S3-backed FUSE volumes return ENOSYS for rename(2), so `mv`\n // fails when the destination crosses the mount boundary. `cp -f` + `rm`\n // works on every backend (and on the regular sandbox disk is no slower\n // than mv for a single file).\n const renameStep =\n finalName !== srcBasename\n ? `$SUDO cp -f ${quoteShellArg(initialPath)} ${quoteShellArg(finalPath)} && $SUDO rm -f ${quoteShellArg(initialPath)}`\n : ': # no rename';\n const script = [\n `set -euo pipefail`,\n `if command -v sudo >/dev/null 2>&1; then SUDO='sudo -n'; else SUDO=''; fi`,\n `$SUDO mkdir -p ${quoteShellArg(boxParent)}`,\n // --no-same-permissions / --no-same-owner / -m: Daytona's S3-backed\n // FUSE volumes reject chmod/utime/chown; skipping them lets the extract\n // complete on a mounted-volume destination. Harmless no-op on the\n // sandbox's regular disk. Same flags as the credential-seed extract.\n `$SUDO tar -xzf ${quoteShellArg(REMOTE_UP_TAR)} -C ${quoteShellArg(boxParent)} --no-same-permissions --no-same-owner -m`,\n renameStep,\n // chown only the landed path — anything we mkdir'd through stays at\n // its existing ownership. Tolerate failure (chown bad on read-only mounts).\n `$SUDO chown -R \"$(id -un):$(id -gn)\" ${quoteShellArg(finalPath)} || true`,\n `rm -f ${quoteShellArg(REMOTE_UP_TAR)}`,\n ].join('\\n');\n const r = await backend.exec(handle, bashScript(script));\n if (r.exitCode !== 0) {\n throw new Error(`cloud upload extract failed: ${r.stderr || r.stdout}`);\n }\n } finally {\n await rm(stage, { recursive: true, force: true });\n }\n return { finalPath };\n}\n\n/**\n * Pull the *contents* of an in-sandbox directory into a host directory —\n * `/workspace/*` → `<hostDst>/*`, not `<hostDst>/<srcBasename>/*`. Used by\n * `agentbox download` (the bulk workspace pull); `downloadFromCloudBox`\n * preserves the source basename for `docker cp` parity.\n */\nexport async function pullCloudDirContents(\n backend: CloudBackend,\n handle: CloudHandle,\n boxSrcDir: string,\n hostDstDir: string,\n): Promise<CloudCpResult> {\n const dstAbs = hostResolve(hostDstDir);\n mkdirSync(dstAbs, { recursive: true });\n\n const stage = await mkdtemp(hostJoin(tmpdir(), 'agentbox-pull-'));\n const localTar = hostJoin(stage, 'payload.tar.gz');\n try {\n // `tar -C <dir> -czf <tarball> .` packs the contents (no leading\n // basename component) so extraction lands them in dstAbs directly.\n const packScript = [\n `set -euo pipefail`,\n `cd ${quoteShellArg(boxSrcDir)}`,\n `tar -czf ${quoteShellArg(REMOTE_DOWN_TAR)} .`,\n ].join('\\n');\n const r = await backend.exec(handle, bashScript(packScript));\n if (r.exitCode !== 0) {\n throw new Error(`cloud workspace pack failed: ${r.stderr || r.stdout}`);\n }\n await backend.downloadFile(handle, REMOTE_DOWN_TAR, localTar);\n await execa('tar', ['-xzf', localTar, '-C', dstAbs]);\n await backend\n .exec(handle, `rm -f ${quoteShellArg(REMOTE_DOWN_TAR)}`)\n .catch(() => {\n /* best-effort */\n });\n } finally {\n await rm(stage, { recursive: true, force: true });\n }\n return { finalPath: dstAbs };\n}\n\nexport async function downloadFromCloudBox(\n backend: CloudBackend,\n handle: CloudHandle,\n boxSrc: string,\n hostDst: string,\n exclude?: string[],\n): Promise<CloudCpResult> {\n const srcBasename = posix.basename(boxSrc);\n const srcParent = posix.dirname(boxSrc);\n\n const dstAbs = hostResolve(hostDst);\n let hostParent: string;\n let finalName: string;\n const dstExists = existsSync(dstAbs);\n if (hostDst.endsWith('/') || (dstExists && statSync(dstAbs).isDirectory())) {\n hostParent = dstAbs;\n finalName = srcBasename;\n } else {\n hostParent = hostDirname(dstAbs);\n finalName = hostBasename(dstAbs);\n }\n mkdirSync(hostParent, { recursive: true });\n const finalPath = hostJoin(hostParent, finalName);\n\n const stage = await mkdtemp(hostJoin(tmpdir(), 'agentbox-cp-down-'));\n const localTar = hostJoin(stage, 'payload.tar.gz');\n try {\n const excludeArgs = (exclude ?? [])\n .map((p) => `--exclude=${quoteShellArg(p)}`)\n .join(' ');\n const packScript = [\n `set -euo pipefail`,\n `cd ${quoteShellArg(srcParent)}`,\n `tar -czf ${quoteShellArg(REMOTE_DOWN_TAR)} ${excludeArgs} ${quoteShellArg(srcBasename)}`,\n ].join('\\n');\n const r = await backend.exec(handle, bashScript(packScript));\n if (r.exitCode !== 0) {\n throw new Error(`cloud download pack failed: ${r.stderr || r.stdout}`);\n }\n await backend.downloadFile(handle, REMOTE_DOWN_TAR, localTar);\n await execa('tar', ['-xzf', localTar, '-C', hostParent]);\n if (finalName !== srcBasename) {\n renameSync(hostJoin(hostParent, srcBasename), finalPath);\n }\n // Best-effort cleanup; tolerate failure (sandbox may have ephemeral /tmp).\n await backend\n .exec(handle, `rm -f ${quoteShellArg(REMOTE_DOWN_TAR)}`)\n .catch(() => {\n /* best-effort */\n });\n } finally {\n await rm(stage, { recursive: true, force: true });\n }\n return { finalPath };\n}\n","import type { CloudBackend, CloudHandle } from '@agentbox/core';\nimport { bashScript, quoteShellArgv } from './shell.js';\n\n/**\n * Launch the in-box `agentbox-ctl daemon` inside a cloud sandbox. The image\n * (built from `Dockerfile.box`) already bakes `/usr/local/bin/agentbox-ctl`,\n * so this only `exec`s it detached with the per-box env wired in.\n *\n * The relay env is intentionally `undefined` in v0: the in-sandbox relay box-\n * mode + host poller (Phase 4) is not wired yet. With those env vars absent\n * the supervisor's `RelayClient` short-circuits to a no-op, the supervisor\n * still schedules `agentbox.yaml` tasks/services, and `agentbox-ctl git push`\n * surfaces a clear \"no relay configured\" error.\n */\nexport interface LaunchCloudCtlArgs {\n backend: CloudBackend;\n handle: CloudHandle;\n boxId: string;\n boxName: string;\n /** When set, exported as AGENTBOX_RELAY_URL inside the box. v0 leaves unset. */\n relayUrl?: string;\n /** When set, exported as AGENTBOX_RELAY_TOKEN inside the box. v0 leaves unset. */\n relayToken?: string;\n /** When set, exported as AGENTBOX_BRIDGE_TOKEN inside the box. v0 leaves unset. */\n bridgeToken?: string;\n /**\n * When set, exported as AGENTBOX_WEB_PROXY_PORT so the in-box ctl binds its\n * WebProxy on this port instead of the default 80. Vercel uses 8080 because it\n * can't expose privileged ports.\n */\n webProxyPort?: number;\n}\n\nexport async function launchCloudCtlDaemon(args: LaunchCloudCtlArgs): Promise<void> {\n const env: string[] = [\n `AGENTBOX_BOX_ID=${quoteShellArgv([args.boxId])}`,\n `AGENTBOX_BOX_NAME=${quoteShellArgv([args.boxName])}`,\n `AGENTBOX_BOX_KIND=cloud`,\n ];\n if (args.relayUrl) env.push(`AGENTBOX_RELAY_URL=${quoteShellArgv([args.relayUrl])}`);\n if (args.relayToken) env.push(`AGENTBOX_RELAY_TOKEN=${quoteShellArgv([args.relayToken])}`);\n if (args.bridgeToken) env.push(`AGENTBOX_BRIDGE_TOKEN=${quoteShellArgv([args.bridgeToken])}`);\n if (args.webProxyPort !== undefined)\n env.push(`AGENTBOX_WEB_PROXY_PORT=${quoteShellArgv([String(args.webProxyPort)])}`);\n\n // nohup + & detaches the daemon from the exec channel; logs go to the file\n // the daemon already uses for Docker boxes so debugging is uniform.\n // /run and /var/log are root-owned — the non-root sandbox user needs sudo\n // to create the per-box dirs (devcontainers/base grants vscode passwordless\n // sudo). The daemon itself can run as the current user.\n const script = [\n `set -e`,\n `if command -v sudo >/dev/null 2>&1; then SUDO='sudo -n'; else SUDO=''; fi`,\n `$SUDO mkdir -p /run/agentbox /var/log/agentbox`,\n `$SUDO chown \"$(id -un):$(id -gn)\" /run/agentbox /var/log/agentbox`,\n `export ${env.join(' ')}`,\n `nohup /usr/local/bin/agentbox-ctl daemon >> /var/log/agentbox/ctl-daemon.log 2>&1 &`,\n `disown`,\n `echo started`,\n ].join('\\n');\n\n const r = await args.backend.exec(args.handle, bashScript(script));\n if (r.exitCode !== 0) {\n throw new Error(`agentbox-ctl daemon launch failed: ${r.stderr || r.stdout}`);\n }\n}\n","/**\n * Launch the in-sandbox `dockerd` daemon for a cloud box. Mirrors what\n * `launchDockerdDaemon` does for Docker (calls\n * `/usr/local/bin/agentbox-dockerd-start` detached, then polls for the\n * `/var/run/docker.sock` to accept connections), adapted for cloud via\n * `backend.exec`.\n *\n * Daytona sandboxes ship with `CAP_SYS_ADMIN` available (validated by the\n * earlier DinD PoC), so the in-sandbox `dockerd` works once the bundled\n * helper script runs. This is opt-in for cloud — most users don't need\n * an in-sandbox docker.\n */\n\nimport type { CloudBackend, CloudHandle } from '@agentbox/core';\nimport { bashScript } from './shell.js';\n\nexport interface CloudDockerdLaunchResult {\n up: boolean;\n reason?: string;\n}\n\nexport async function launchCloudDockerdDaemon(args: {\n backend: CloudBackend;\n handle: CloudHandle;\n timeoutMs?: number;\n}): Promise<CloudDockerdLaunchResult> {\n const timeoutMs = args.timeoutMs ?? 60_000;\n // Spawn detached via `nohup ... &` so the exec's stdout/stderr aren't\n // tied to dockerd's lifetime. Redirect both to the standard agentbox\n // log path so `agentbox logs --daemon` style introspection can pick\n // it up.\n const startScript = [\n `set -euo pipefail`,\n `mkdir -p /var/log/agentbox`,\n `nohup sudo -n /usr/local/bin/agentbox-dockerd-start >> /var/log/agentbox/dockerd.log 2>&1 &`,\n `echo \"spawned dockerd\"`,\n ].join('\\n');\n const launch = await args.backend.exec(args.handle, bashScript(startScript));\n if (launch.exitCode !== 0) {\n return {\n up: false,\n reason: `dockerd launch failed: ${launch.stderr || launch.stdout}`,\n };\n }\n\n // Poll for the socket. The launch script returns immediately (nohup &);\n // dockerd needs ~5-15s on Daytona to initialize iptables + the storage\n // graphdriver.\n const probeCmd =\n '[ -S /var/run/docker.sock ] && docker -H unix:///var/run/docker.sock info >/dev/null 2>&1';\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline) {\n const probe = await args.backend.exec(args.handle, probeCmd);\n if (probe.exitCode === 0) return { up: true };\n await new Promise((r) => setTimeout(r, 500));\n }\n return {\n up: false,\n reason: `dockerd did not become ready within ${String(timeoutMs)}ms`,\n };\n}\n","import type { CloudBackend, CloudHandle } from '@agentbox/core';\nimport { bashScript, quoteShellArg } from './shell.js';\n\n/**\n * Launch the in-box VNC stack (Xvnc + websockify + noVNC) inside a cloud\n * sandbox. The image (built from `Dockerfile.box`) bakes\n * `/usr/local/bin/agentbox-vnc-start`, which is generic bash that reads\n * `AGENTBOX_VNC_PASSWORD` from env and is idempotent — re-running while the\n * daemons are alive is a no-op, so `start()` can blindly call us again.\n *\n * The password is injected inline at every exec call rather than baked into\n * the sandbox's provision-time `envVars`, so a Daytona stop/start doesn't\n * depend on Daytona preserving env across lifecycle transitions. Same shape\n * as `launchCloudCtlDaemon`.\n */\nexport interface LaunchCloudVncArgs {\n backend: CloudBackend;\n handle: CloudHandle;\n vncPassword: string;\n}\n\nexport async function launchCloudVncDaemon(args: LaunchCloudVncArgs): Promise<void> {\n // The script binds Xvnc on :5901 (loopback) and websockify on 0.0.0.0:6080.\n // We poll 6080 from inside the sandbox via bash's /dev/tcp pseudo-device —\n // the host can't reach the sandbox port directly (signed preview URLs are\n // public but high-latency and rate-limited, not the right path for a\n // readiness probe). Bound the probe so a wedged daemon surfaces an error.\n //\n // `cd /home/vscode` is load-bearing: Daytona's `executeCommand` runs us\n // from a transient CWD that doesn't necessarily exist by the time the\n // backgrounded websockify (Python) reads `os.getcwd()` for its default\n // cert path resolution. A stable CWD inside the sandbox user's home\n // avoids a `FileNotFoundError` at websockify startup.\n const script = [\n `set -e`,\n `cd /home/vscode`,\n `export AGENTBOX_VNC_PASSWORD=${quoteShellArg(args.vncPassword)}`,\n `mkdir -p /var/log/agentbox 2>/dev/null || true`,\n `nohup /usr/local/bin/agentbox-vnc-start >> /var/log/agentbox/vnc-start.log 2>&1 &`,\n `disown`,\n // Probe for websockify to bind 6080. ~15s ceiling: E2B's Python venv\n // startup (websockify is a pure-python proxy launched from a venv) takes\n // ~7-9s before the socket binds, so a 5s ceiling false-negatives every\n // create. Docker/hetzner/daytona/vercel come up well inside this window.\n `for _ in $(seq 1 150); do`,\n ` if (echo > /dev/tcp/127.0.0.1/6080) 2>/dev/null; then echo ready; exit 0; fi`,\n ` sleep 0.1`,\n `done`,\n `echo \"websockify did not bind 6080 within 15s\" >&2`,\n `exit 1`,\n ].join('\\n');\n\n const r = await args.backend.exec(args.handle, bashScript(script));\n if (r.exitCode !== 0) {\n throw new Error(`agentbox-vnc-start failed: ${r.stderr || r.stdout}`);\n }\n}\n","import { execa } from 'execa';\nimport { mkdtemp, rm, stat } from 'node:fs/promises';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\nimport type { CloudBackend, CloudHandle } from '@agentbox/core';\nimport { detectGitRepos } from '@agentbox/sandbox-core';\nimport { bashScript, quoteShellArgv } from './shell.js';\n\n/**\n * Seed `/workspace` inside a cloud sandbox from the host workspace. Mirrors\n * what `seedWorkspace` does for the Docker provider, adapted for the cloud\n * channel (`backend.uploadFile` + `backend.exec`):\n *\n * - Git workspace: `git clone --no-checkout [--depth=N] file://hostRepo`\n * into a host-side temp dir, tar the resulting `.git/`, upload, extract\n * into `/workspace`, repoint `origin`, `git checkout -B agentbox/<box>`\n * to materialize the working tree. Repeats per nested repo for monorepos.\n * - Non-git workspace: tar the host workspace, upload, extract.\n *\n * Why clone-and-tar instead of `git bundle`? `git bundle create` has no\n * `--depth` flag in any released git version (verified 2.39 and 2.52), and\n * the portable detours all produce bundles with unsatisfiable prerequisites.\n * Shipping a shallow clone is the only way to cap commit count portably.\n */\nexport interface SeedCloudWorkspaceArgs {\n backend: CloudBackend;\n handle: CloudHandle;\n /** Absolute host path the user passed via `-w`. */\n workspacePath: string;\n /** Branch name to check out inside the sandbox (`agentbox/<box-name>`). */\n branch: string;\n /** In-sandbox destination; defaults to `/workspace`. */\n workspaceDir?: string;\n /**\n * Commit cap for the host-side shallow `git clone`. `undefined` (the\n * common case) → adaptive default: clone the last `DEFAULT_BUNDLE_DEPTH`\n * commits and, if the resulting tar exceeds `LARGE_BUNDLE_THRESHOLD_BYTES`,\n * redo at `LARGE_BUNDLE_DEPTH`. `0` → full history (no `--depth`). `> 0` →\n * fixed shallow depth, no adaptive rebuild. Applied per repo.\n */\n bundleDepth?: number;\n /**\n * Base ref the box's `<branch>` is forked from (default: clone's HEAD).\n * When set, the host clone passes `--branch <fromBranch>` so the clone's\n * HEAD points at the requested ref, and the in-sandbox `git checkout -B\n * <branch>` picks it up. Nested repos keep their own default branch —\n * `<fromBranch>` is applied to the root only. Caller is responsible for\n * validating the ref host-side.\n */\n fromBranch?: string;\n /**\n * Reuse an existing branch directly (root repo only) instead of forking a\n * fresh per-box branch. The host clone pins `--branch <useBranch>` so the\n * clone HEAD lands on it, and the in-sandbox checkout is a plain `git\n * checkout <useBranch>` (no `-B` reset). Mutually exclusive with\n * `fromBranch` (enforced by the CLI). When set, `branch` equals\n * `useBranch`.\n */\n useBranch?: string;\n onLog?: (line: string) => void;\n}\n\nexport interface SeedCloudWorkspaceResult {\n /** True when a git repo was found at the workspace root and a clone was used. */\n fromGit: boolean;\n /** Resolved branch (matches `branch` arg). */\n branch: string;\n}\n\nconst WORKSPACE_DIR_DEFAULT = '/workspace';\n\nexport async function seedCloudWorkspace(\n args: SeedCloudWorkspaceArgs,\n): Promise<SeedCloudWorkspaceResult> {\n const workspaceDir = args.workspaceDir ?? WORKSPACE_DIR_DEFAULT;\n const log = args.onLog ?? (() => {});\n const repos = await detectGitRepos(args.workspacePath);\n const root = repos.find((r) => r.kind === 'root');\n const nested = repos.filter((r) => r.kind === 'nested');\n\n if (root) {\n log(\n nested.length > 0\n ? `seeding /workspace from shallow git clone (+${String(nested.length)} nested repo${nested.length === 1 ? '' : 's'})`\n : 'seeding /workspace from shallow git clone',\n );\n await seedFromGitClone({\n backend: args.backend,\n handle: args.handle,\n hostRepo: root.hostMainRepo,\n branch: args.branch,\n workspaceDir,\n bundleDepth: args.bundleDepth,\n fromBranch: args.fromBranch,\n useBranch: args.useBranch,\n onLog: log,\n });\n // Each nested repo gets its own clone at /workspace/<rel>. We do these\n // after the root clone because the root extract wipes /workspace; a\n // nested dir created during the root checkout (if tracked) would be\n // replaced when we extract over it.\n for (const r of nested) {\n const sub = `${workspaceDir}/${r.relPathFromWorkspace}`;\n log(`seeding nested repo ${r.relPathFromWorkspace} from shallow git clone`);\n await seedFromGitClone({\n backend: args.backend,\n handle: args.handle,\n hostRepo: r.hostMainRepo,\n branch: args.branch,\n workspaceDir: sub,\n bundleDepth: args.bundleDepth,\n onLog: log,\n });\n }\n return { fromGit: true, branch: args.branch };\n }\n\n log('seeding /workspace from workspace tarball (no git detected)');\n await seedFromTar({\n backend: args.backend,\n handle: args.handle,\n hostDir: args.workspacePath,\n workspaceDir,\n });\n return { fromGit: false, branch: args.branch };\n}\n\ninterface SeedFromGitCloneArgs {\n backend: CloudBackend;\n handle: CloudHandle;\n hostRepo: string;\n branch: string;\n workspaceDir: string;\n /** See `SeedCloudWorkspaceArgs.bundleDepth`. */\n bundleDepth?: number;\n /** See `SeedCloudWorkspaceArgs.fromBranch`. */\n fromBranch?: string;\n /** See `SeedCloudWorkspaceArgs.useBranch`. Root clone only. */\n useBranch?: string;\n onLog?: (line: string) => void;\n}\n\n/**\n * Temporary host ref used to carry the `git stash create` commit into the\n * shallow clone so the in-sandbox repo can apply it. Created before clone,\n * fetched into the clone under `refs/remotes/origin/<...>` with an explicit\n * refspec, then deleted from the host repo in `finally`.\n */\nconst STASH_CARRYOVER_REF = 'refs/agentbox-carryover/stash';\nconst REMOTE_UNTRACKED_TAR = '/tmp/agentbox-carryover-untracked.tar.gz';\n\n/**\n * Adaptive cap on the host-side shallow clone. Default keeps cold cloud\n * creates fast on big monorepos: clone the last 200 commits; if the tarred\n * `.git/` still exceeds 20 MB, redo at 100. Explicit `bundleDepth` skips\n * the adaptive rebuild (the user picked a number; trust it).\n */\nconst DEFAULT_BUNDLE_DEPTH = 200;\nconst LARGE_BUNDLE_DEPTH = 100;\nconst LARGE_BUNDLE_THRESHOLD_BYTES = 20 * 1024 * 1024;\n\nasync function seedFromGitClone(args: SeedFromGitCloneArgs): Promise<void> {\n const log = args.onLog ?? (() => {});\n const stage = await mkdtemp(join(tmpdir(), 'agentbox-clone-'));\n const cloneDir = join(stage, 'clone');\n const tarPath = join(stage, 'workspace.tar.gz');\n const untrackedTarPath = join(stage, 'untracked.tar.gz');\n // Per-repo carry-over (mirrors `collectRepoCarryOver` from sandbox-docker):\n // - `git stash create` captures every staged + tracked-modified change\n // (including deletes/renames) as a one-off commit.\n // - untracked files get tarred separately because `stash create` (no -u\n // option) doesn't capture them.\n // The stash commit rides into the shallow clone via an explicit-refspec\n // fetch after the initial clone (HEAD-only clone doesn't pull arbitrary\n // refs). The untracked tar uploads on the side and the in-sandbox script\n // untars it after `git checkout` materializes the working tree.\n //\n // --use-branch skips carry-over entirely: the box gets the reused branch's\n // committed tip, not the host's uncommitted state (which may belong to a\n // different branch). Mirrors the docker reuse path, which builds its\n // RepoCarryOver with `stashSha: null` / empty untracked.\n const stashSha = args.useBranch ? null : await safeStashCreate(args.hostRepo);\n const untrackedSize = args.useBranch\n ? 0\n : await maybeBuildUntrackedTar(args.hostRepo, untrackedTarPath);\n let stashRefCreated = false;\n try {\n if (stashSha) {\n const ref = await execa(\n 'git',\n ['-C', args.hostRepo, 'update-ref', STASH_CARRYOVER_REF, stashSha],\n { reject: false },\n );\n stashRefCreated = ref.exitCode === 0;\n }\n // Pick the initial depth.\n // - undefined → adaptive default (200, may rebuild at 100 if >20 MB)\n // - 0 → full history (no `--depth` flag)\n // - N > 0 → fixed shallow depth, no rebuild\n // Shallow history is fine here because `git push` from inside the box\n // travels through the host relay's bundle pull-back, which resolves the\n // merge base against the host repo's full history.\n const configured = args.bundleDepth;\n const adaptive = configured === undefined;\n const initialDepth: number | null = adaptive\n ? DEFAULT_BUNDLE_DEPTH\n : configured === 0\n ? null\n : configured;\n log(\n adaptive\n ? `clone: depth=${String(DEFAULT_BUNDLE_DEPTH)} (default, adaptive)`\n : initialDepth === null\n ? 'clone: depth=full (configured)'\n : `clone: depth=${String(initialDepth)} (configured)`,\n );\n // --use-branch reuses the named branch directly; otherwise --from-branch\n // (or nothing) picks the fork base. Either way it pins the clone's HEAD.\n const cloneBranch = args.useBranch ?? args.fromBranch;\n await runShallowClone(args.hostRepo, cloneDir, initialDepth, stashRefCreated, cloneBranch);\n await tarCloneDir(cloneDir, tarPath);\n if (adaptive && initialDepth !== null) {\n const size = await safeFileSize(tarPath);\n if (size > LARGE_BUNDLE_THRESHOLD_BYTES) {\n const mb = (size / (1024 * 1024)).toFixed(1);\n log(\n `clone tar exceeded ${String(LARGE_BUNDLE_THRESHOLD_BYTES / (1024 * 1024))} MB at depth ${String(DEFAULT_BUNDLE_DEPTH)} (${mb} MB), rebuilding at depth ${String(LARGE_BUNDLE_DEPTH)}`,\n );\n await rm(cloneDir, { recursive: true, force: true });\n await rm(tarPath, { force: true });\n await runShallowClone(args.hostRepo, cloneDir, LARGE_BUNDLE_DEPTH, stashRefCreated, cloneBranch);\n await tarCloneDir(cloneDir, tarPath);\n }\n }\n const remoteUrl = await readOriginUrl(args.hostRepo);\n const remoteTar = '/tmp/agentbox-workspace.tar.gz';\n await args.backend.uploadFile(args.handle, tarPath, remoteTar);\n if (untrackedSize > 0) {\n await args.backend.uploadFile(args.handle, untrackedTarPath, REMOTE_UNTRACKED_TAR);\n }\n const setOrigin = remoteUrl\n ? `git -C ${quoteShellArgv([args.workspaceDir])} remote set-url origin ${quoteShellArgv([remoteUrl])}`\n : ': # no host origin to copy';\n // Extract the shallow clone's .git over the destination, then repoint\n // `origin` from the file:// placeholder to the real upstream so future\n // fetch/push target the actual remote (`git push` itself travels back\n // through the host relay). `git checkout -B <branch>` then materializes\n // the working tree from HEAD (the clone was `--no-checkout`, so the\n // tarball only carried `.git/`).\n // /workspace lives at the root in the snapshot — root-owned by default\n // (Dockerfile.box never chowns it). The sandbox runs non-root, so the\n // dir ops need sudo. The devcontainers/base image grants passwordless\n // sudo to `vscode`; SUDO is a no-op when sudo isn't needed/available.\n const SUDO = `if command -v sudo >/dev/null 2>&1; then SUDO='sudo -n'; else SUDO=''; fi`;\n // Stash apply is best-effort — applying onto a possibly shallow clone\n // can hit \"needs merge\" conflicts in pathological cases (e.g. host had\n // local changes against a commit outside the depth window). Soft-fail\n // is better than blocking provision; any unapplied changes can be\n // re-derived from the host as a fallback.\n const carryOverSteps: string[] = stashSha\n ? [\n `if git -C ${quoteShellArgv([args.workspaceDir])} rev-parse --verify ${quoteShellArgv([`refs/remotes/origin/agentbox-carryover/stash`])} >/dev/null 2>&1; then ` +\n `git -C ${quoteShellArgv([args.workspaceDir])} stash apply ${quoteShellArgv([`refs/remotes/origin/agentbox-carryover/stash`])} || ` +\n `echo \"agentbox: stash apply soft-failed; carry-over may be incomplete\" >&2 ; ` +\n `git -C ${quoteShellArgv([args.workspaceDir])} update-ref -d ${quoteShellArgv([`refs/remotes/origin/agentbox-carryover/stash`])} || true ; ` +\n `fi`,\n ]\n : [];\n if (untrackedSize > 0) {\n carryOverSteps.push(\n `if [ -f ${quoteShellArgv([REMOTE_UNTRACKED_TAR])} ]; then ` +\n `tar -C ${quoteShellArgv([args.workspaceDir])} -xzf ${quoteShellArgv([REMOTE_UNTRACKED_TAR])} && ` +\n `rm -f ${quoteShellArgv([REMOTE_UNTRACKED_TAR])} ; ` +\n `fi`,\n );\n }\n const script = [\n `set -euo pipefail`,\n // Move out of any cwd we might inherit from Daytona's executeCommand\n // before we delete /workspace. The agentbox image bakes WORKDIR\n // /workspace; if the shell's cwd is /workspace when we `rm -rf` it,\n // the next process inherits a stale cwd FD and tar's children fail\n // with \"Unable to read current working directory\".\n `cd /tmp`,\n SUDO,\n // rm -rf only the directory we're about to extract into — for nested\n // repos this is just `/workspace/<rel>`, so the root clone (already\n // at `/workspace`) is preserved.\n `$SUDO rm -rf ${quoteShellArgv([args.workspaceDir])}`,\n `$SUDO mkdir -p ${quoteShellArgv([args.workspaceDir])}`,\n `$SUDO chown \"$(id -un):$(id -gn)\" ${quoteShellArgv([args.workspaceDir])}`,\n `tar -C ${quoteShellArgv([args.workspaceDir])} -xzf ${quoteShellArgv([remoteTar])}`,\n setOrigin,\n // reuse: the clone already landed on `<branch>` (pinned via `--branch`);\n // a plain checkout materializes the working tree without resetting the\n // ref. fork: `-B` (re)points `<branch>` at the clone HEAD.\n args.useBranch\n ? `git -C ${quoteShellArgv([args.workspaceDir])} checkout ${quoteShellArgv([args.branch])}`\n : `git -C ${quoteShellArgv([args.workspaceDir])} checkout -B ${quoteShellArgv([args.branch])}`,\n ...carryOverSteps,\n `rm -f ${quoteShellArgv([remoteTar])}`,\n ].join('\\n');\n // Daytona's executeCommand shells out via dash (`/bin/sh`), which rejects\n // bash idioms like `set -o pipefail`. Wrap in `bash -c` so the script\n // runs in bash regardless of what `/bin/sh` points at.\n const r = await args.backend.exec(args.handle, bashScript(script));\n if (r.exitCode !== 0) {\n throw new Error(`workspace seed (clone) failed: ${r.stderr || r.stdout}`);\n }\n } finally {\n // Defensive cleanup of the temp stash ref on host. If we threw between\n // updates, the ref may still be present; delete it so re-runs don't\n // accrue refs/agentbox-carryover/* entries.\n if (stashRefCreated) {\n await execa('git', ['-C', args.hostRepo, 'update-ref', '-d', STASH_CARRYOVER_REF], {\n reject: false,\n });\n }\n await rm(stage, { recursive: true, force: true });\n }\n}\n\n/**\n * Shallow `git clone --no-checkout` into `cloneDir`. `depth === null` → full\n * history (no `--depth` flag). When the host carries a stash ref, that ref\n * is explicitly fetched into the new clone under `refs/remotes/origin/...`\n * with a matching `--depth`, so the in-box `stash apply` can find it.\n *\n * `--no-checkout` skips materializing the working tree on host (we'd just\n * throw it away when we tar `.git/`). `file://` is required so git treats\n * the source as a remote — without it, `git clone <local-path>` uses object\n * hardlinks and silently ignores `--depth`, producing a full clone.\n */\nasync function runShallowClone(\n hostRepo: string,\n cloneDir: string,\n depth: number | null,\n includeStashRef: boolean,\n fromBranch?: string,\n): Promise<void> {\n const cloneArgs: string[] = ['clone', '--no-checkout', '--quiet'];\n if (depth !== null) cloneArgs.push(`--depth=${String(depth)}`);\n // `--branch` pins the clone's HEAD to the requested ref so the in-sandbox\n // `git checkout -B <branch>` picks up that ref as the fork point. Accepts\n // branch names + tags; SHAs aren't supported by `git clone --branch` and\n // would need a separate fetch (callers using SHAs should validate\n // host-side and pass a branch/tag name instead, or skip --from-branch).\n if (fromBranch) cloneArgs.push('--branch', fromBranch);\n cloneArgs.push(`file://${hostRepo}`, cloneDir);\n await execa('git', cloneArgs);\n if (includeStashRef) {\n // Soft-fail: the stash commit's parents could in principle fall outside\n // a very shallow window; the in-box `stash apply` already soft-fails,\n // so missing the ref here is equivalent.\n const fetchArgs: string[] = ['-C', cloneDir, 'fetch', '--quiet'];\n if (depth !== null) fetchArgs.push(`--depth=${String(depth)}`);\n fetchArgs.push(\n `file://${hostRepo}`,\n `+${STASH_CARRYOVER_REF}:refs/remotes/origin/agentbox-carryover/stash`,\n );\n await execa('git', fetchArgs, { reject: false });\n }\n}\n\nasync function tarCloneDir(cloneDir: string, outPath: string): Promise<void> {\n await execa('tar', ['-C', cloneDir, '-czf', outPath, '.'], {\n env: { ...process.env, COPYFILE_DISABLE: '1' },\n });\n}\n\nasync function safeFileSize(path: string): Promise<number> {\n try {\n return (await stat(path)).size;\n } catch {\n return 0;\n }\n}\n\n/**\n * Best-effort `git stash create` on the host repo. Returns the stash SHA\n * (or `null` when the worktree is clean / git is missing / the call fails).\n * Mirrors the docker provider's `collectRepoCarryOver` shape — pure host\n * git, no side effects on the working tree.\n */\nasync function safeStashCreate(hostRepo: string): Promise<string | null> {\n const r = await execa('git', ['-C', hostRepo, 'stash', 'create'], { reject: false });\n if (r.exitCode !== 0) return null;\n const sha = r.stdout.trim();\n return sha.length > 0 ? sha : null;\n}\n\n/**\n * Tar the repo's untracked-not-ignored files into `outPath`. Returns the\n * tar size in bytes (0 when there's nothing to tar, so callers can skip\n * the upload). `git stash create` doesn't capture untracked, so the carry-\n * over needs this side channel — matches docker's behavior.\n */\nasync function maybeBuildUntrackedTar(hostRepo: string, outPath: string): Promise<number> {\n const list = await execa(\n 'git',\n ['-C', hostRepo, 'ls-files', '--others', '--exclude-standard', '-z'],\n { reject: false },\n );\n if (list.exitCode !== 0 || list.stdout.length === 0) return 0;\n // Feed NUL-delimited paths to `tar --null -T -` so spaces / quotes /\n // newlines in filenames survive. Use COPYFILE_DISABLE=1 to suppress\n // macOS' AppleDouble `._<name>` sidecars (same hardening as the\n // agent-credential tarballs).\n const tar = await execa(\n 'tar',\n ['-C', hostRepo, '--null', '-T', '-', '-czf', outPath],\n {\n input: list.stdout,\n env: { ...process.env, COPYFILE_DISABLE: '1' },\n reject: false,\n },\n );\n if (tar.exitCode !== 0) return 0;\n try {\n const { stat } = await import('node:fs/promises');\n const s = await stat(outPath);\n return s.size;\n } catch {\n return 0;\n }\n}\n\nasync function readOriginUrl(hostRepo: string): Promise<string | null> {\n const r = await execa('git', ['-C', hostRepo, 'remote', 'get-url', 'origin'], { reject: false });\n if (r.exitCode !== 0) return null;\n const out = (r.stdout ?? '').trim();\n return out.length > 0 ? out : null;\n}\n\ninterface SeedFromTarArgs {\n backend: CloudBackend;\n handle: CloudHandle;\n hostDir: string;\n workspaceDir: string;\n}\n\nasync function seedFromTar(args: SeedFromTarArgs): Promise<void> {\n const stage = await mkdtemp(join(tmpdir(), 'agentbox-tar-'));\n const tarPath = join(stage, 'workspace.tar.gz');\n try {\n await execa('tar', ['-C', args.hostDir, '-czf', tarPath, '.']);\n const remoteTar = '/tmp/agentbox-workspace.tar.gz';\n await args.backend.uploadFile(args.handle, tarPath, remoteTar);\n const SUDO = `if command -v sudo >/dev/null 2>&1; then SUDO='sudo -n'; else SUDO=''; fi`;\n const script = [\n `set -euo pipefail`,\n // Move out of any cwd we might inherit from Daytona's executeCommand\n // before we delete /workspace. The agentbox image bakes WORKDIR\n // /workspace; if the shell's cwd is /workspace when we `rm -rf` it,\n // the next process inherits a stale cwd FD and git-clone's child\n // (index-pack) fails with \"Unable to read current working directory\".\n `cd /tmp`,\n SUDO,\n `$SUDO rm -rf ${quoteShellArgv([args.workspaceDir])}`,\n `$SUDO mkdir -p ${quoteShellArgv([args.workspaceDir])}`,\n `$SUDO chown \"$(id -un):$(id -gn)\" ${quoteShellArgv([args.workspaceDir])}`,\n `tar -C ${quoteShellArgv([args.workspaceDir])} -xzf ${quoteShellArgv([remoteTar])}`,\n `rm -f ${quoteShellArgv([remoteTar])}`,\n ].join('\\n');\n const r = await args.backend.exec(args.handle, bashScript(script));\n if (r.exitCode !== 0) {\n throw new Error(`workspace seed (tar) failed: ${r.stderr || r.stdout}`);\n }\n } finally {\n await rm(stage, { recursive: true, force: true });\n }\n}\n","/**\n * `MockCloudBackend` — a fully in-memory implementation of `CloudBackend` for\n * tests and as a reference. New cloud backends (Vercel, Fly.io, …) can use\n * the contract suite in `test/contract.ts` to validate that their backend\n * behaves the way `createCloudProvider` expects, and look at this file as a\n * minimal example.\n *\n * Behavior is intentionally simple — every method records the call (so\n * tests can assert ordering) and resolves with deterministic values. No\n * I/O. The implementation covers every required method on `CloudBackend`\n * plus every optional one, so contract tests can exercise both branches.\n */\n\nimport type {\n CloudBackend,\n CloudExecOptions,\n CloudExecResult,\n CloudFileEntry,\n CloudHandle,\n CloudPreviewUrl,\n CloudProvisionRequest,\n CloudSandboxSummary,\n CloudState,\n} from '@agentbox/core';\n\ninterface SandboxRecord {\n id: string;\n name: string;\n state: CloudState;\n createdAt: string;\n image: string;\n /** Pseudo-file content keyed by remote path. */\n files: Map<string, Uint8Array>;\n}\n\nexport interface MockCloudBackendOptions {\n /** Name reported by `backend.name`. Defaults to `'mock'`. */\n name?: string;\n /** Initial sandboxes pre-loaded into the backend (e.g. for list() tests). */\n preloaded?: Array<{ id: string; name?: string; state?: CloudState; createdAt?: string }>;\n /**\n * Optional hook fired before every method runs. Tests can use this to\n * inject failures (`throw new Error(...)` or a typed Daytona-shaped error\n * to exercise the retry wrapper).\n */\n beforeCall?: (method: string, args: unknown[]) => void | Promise<void>;\n}\n\nexport interface MockCloudBackend extends CloudBackend {\n /** Method names captured in invocation order — useful for assertions. */\n readonly calls: ReadonlyArray<{ method: string; args: unknown[] }>;\n /** Sandboxes currently present in the backend (post any provision/destroy). */\n readonly sandboxes: ReadonlyArray<Readonly<SandboxRecord>>;\n /**\n * Empty the recorded `calls` log. Useful between assertions in a single\n * test: do an action, assert, clear, do another action, assert again\n * without the first batch polluting the filter. Tests previously poked\n * `calls.length = 0`, which trips strict TS on the readonly array.\n */\n clearCalls(): void;\n}\n\n/** Make a fresh mock backend. Always returns a brand-new internal state. */\nexport function makeMockCloudBackend(opts: MockCloudBackendOptions = {}): MockCloudBackend {\n const name = opts.name ?? 'mock';\n const calls: Array<{ method: string; args: unknown[] }> = [];\n const sandboxes = new Map<string, SandboxRecord>();\n const snapshots = new Map<string, { id: string }>();\n\n for (const pre of opts.preloaded ?? []) {\n sandboxes.set(pre.id, {\n id: pre.id,\n name: pre.name ?? pre.id,\n state: pre.state ?? 'running',\n createdAt: pre.createdAt ?? new Date().toISOString(),\n image: 'mock/preloaded',\n files: new Map(),\n });\n }\n\n const record = async (method: string, args: unknown[]): Promise<void> => {\n calls.push({ method, args });\n if (opts.beforeCall) await opts.beforeCall(method, args);\n };\n const requireSandbox = (id: string): SandboxRecord => {\n const sb = sandboxes.get(id);\n if (!sb) throw new Error(`mock backend: sandbox ${id} not found`);\n return sb;\n };\n\n const backend: MockCloudBackend = {\n name,\n get calls() {\n return calls;\n },\n get sandboxes() {\n return Array.from(sandboxes.values());\n },\n clearCalls(): void {\n calls.length = 0;\n },\n\n async provision(req: CloudProvisionRequest): Promise<CloudHandle> {\n await record('provision', [req]);\n const id = `mock-${String(sandboxes.size + 1)}-${req.name}`;\n sandboxes.set(id, {\n id,\n name: req.name,\n state: 'running',\n createdAt: new Date().toISOString(),\n image: req.snapshot ?? req.image,\n files: new Map(),\n });\n return { sandboxId: id };\n },\n\n async get(sandboxId: string): Promise<CloudHandle | null> {\n await record('get', [sandboxId]);\n return sandboxes.has(sandboxId) ? { sandboxId } : null;\n },\n\n async list(): Promise<CloudSandboxSummary[]> {\n await record('list', []);\n return Array.from(sandboxes.values()).map((sb) => ({\n sandboxId: sb.id,\n name: sb.name,\n createdAt: sb.createdAt,\n state: sb.state,\n }));\n },\n\n async start(h: CloudHandle): Promise<void> {\n await record('start', [h]);\n const sb = requireSandbox(h.sandboxId);\n sb.state = 'running';\n },\n async stop(h: CloudHandle): Promise<void> {\n await record('stop', [h]);\n const sb = requireSandbox(h.sandboxId);\n sb.state = 'stopped';\n },\n async pause(h: CloudHandle): Promise<void> {\n await record('pause', [h]);\n const sb = requireSandbox(h.sandboxId);\n sb.state = 'paused';\n },\n async resume(h: CloudHandle): Promise<void> {\n await record('resume', [h]);\n const sb = requireSandbox(h.sandboxId);\n sb.state = 'running';\n },\n async destroy(h: CloudHandle): Promise<void> {\n await record('destroy', [h]);\n sandboxes.delete(h.sandboxId);\n },\n async state(h: CloudHandle): Promise<CloudState> {\n await record('state', [h]);\n const sb = sandboxes.get(h.sandboxId);\n return sb ? sb.state : 'missing';\n },\n\n async exec(\n h: CloudHandle,\n cmd: string,\n opts?: CloudExecOptions,\n ): Promise<CloudExecResult> {\n await record('exec', [h, cmd, opts]);\n requireSandbox(h.sandboxId);\n return { exitCode: 0, stdout: '', stderr: '' };\n },\n\n async uploadFile(h: CloudHandle, localPath: string, remotePath: string): Promise<void> {\n await record('uploadFile', [h, localPath, remotePath]);\n const sb = requireSandbox(h.sandboxId);\n sb.files.set(remotePath, new Uint8Array([0]));\n },\n async downloadFile(h: CloudHandle, remotePath: string, localPath: string): Promise<void> {\n await record('downloadFile', [h, remotePath, localPath]);\n const sb = requireSandbox(h.sandboxId);\n if (!sb.files.has(remotePath)) {\n throw new Error(`mock backend: ${remotePath} not in sandbox ${h.sandboxId}`);\n }\n },\n async listFiles(h: CloudHandle, remoteDir: string): Promise<CloudFileEntry[]> {\n await record('listFiles', [h, remoteDir]);\n const sb = requireSandbox(h.sandboxId);\n const prefix = remoteDir.endsWith('/') ? remoteDir : `${remoteDir}/`;\n const out: CloudFileEntry[] = [];\n for (const p of sb.files.keys()) {\n if (p.startsWith(prefix)) {\n out.push({ name: p.slice(prefix.length), isDir: false });\n }\n }\n return out;\n },\n\n async previewUrl(h: CloudHandle, port: number): Promise<CloudPreviewUrl> {\n await record('previewUrl', [h, port]);\n requireSandbox(h.sandboxId);\n return { url: `https://${String(port)}-${h.sandboxId}.mock.preview`, token: 'mock-token' };\n },\n\n async signedPreviewUrl(\n h: CloudHandle,\n port: number,\n expiresInSeconds: number,\n ): Promise<CloudPreviewUrl> {\n await record('signedPreviewUrl', [h, port, expiresInSeconds]);\n requireSandbox(h.sandboxId);\n return {\n url: `https://${String(port)}-${h.sandboxId}-signed${String(expiresInSeconds)}.mock.preview`,\n };\n },\n\n async attachArgv(h: CloudHandle): Promise<string[]> {\n await record('attachArgv', [h]);\n requireSandbox(h.sandboxId);\n return ['ssh', '-o', 'StrictHostKeyChecking=no', `mock-token@${h.sandboxId}.mock.ssh`];\n },\n\n async revokeAttachToken(h: CloudHandle, argv: string[]): Promise<void> {\n await record('revokeAttachToken', [h, argv]);\n },\n\n async ensureVolume(volumeName: string): Promise<{ volumeId: string }> {\n await record('ensureVolume', [volumeName]);\n return { volumeId: `vol-${volumeName}` };\n },\n\n async createSnapshot(h: CloudHandle, snapshotName: string): Promise<void> {\n await record('createSnapshot', [h, snapshotName]);\n requireSandbox(h.sandboxId);\n snapshots.set(snapshotName, { id: snapshotName });\n },\n\n async deleteSnapshot(snapshotName: string): Promise<void> {\n await record('deleteSnapshot', [snapshotName]);\n snapshots.delete(snapshotName);\n },\n };\n\n return backend;\n}\n","export {\n CLOUD_WEB_PROXY_PORT,\n CLOUD_WORKSPACE_DIR,\n createCloudProvider,\n emptyCloudStats,\n renderInnerCommand,\n type CreateCloudProviderOptions,\n} from './cloud-provider.js';\nexport { launchCloudCtlDaemon, type LaunchCloudCtlArgs } from './ctl-launch.js';\nexport { launchCloudDockerdDaemon, type CloudDockerdLaunchResult } from './dockerd-launch.js';\nexport {\n seedCloudWorkspace,\n type SeedCloudWorkspaceArgs,\n type SeedCloudWorkspaceResult,\n} from './workspace-seed.js';\nexport {\n agentSpecsForCloud,\n ensureAgentVolumesForCloud,\n extractCloudAgentCredentials,\n seedAgentVolumesIfFresh,\n seedOpencodeModelState,\n type CloudAgentKind,\n type EnsureAgentVolumesResult,\n type SeedAgentVolumesOptions,\n} from './agent-credentials.js';\nexport { uploadEnvFiles, type UploadEnvFilesArgs, type UploadEnvFilesResult } from './env-files.js';\nexport { seedDynamicConfig, type SeedDynamicConfigOptions } from './dynamic-sync.js';\nexport {\n seedClaudeJsonAtCreate,\n type SeedClaudeJsonOptions,\n} from './claude-json-overlay.js';\nexport { seedGitIdentity, type SeedGitIdentityOptions } from './git-identity.js';\nexport { bashScript, quoteShellArg, quoteShellArgv } from './shell.js';\nexport {\n makeMockCloudBackend,\n type MockCloudBackend,\n type MockCloudBackendOptions,\n} from './mock-backend.js';\nexport {\n downloadFromCloudBox,\n pullCloudDirContents,\n uploadToCloudBox,\n type CloudCpResult,\n} from './cloud-cp.js';\nexport {\n CLOUD_CHECKPOINTS_ROOT,\n CLOUD_SNAPSHOT_NAME_PREFIX,\n cloudSnapshotName,\n currentCloudBaseFingerprint,\n listAllCloudCheckpoints,\n listCloudCheckpoints,\n probeCloudCheckpoint,\n removeCloudCheckpointDir,\n resolveCloudCheckpoint,\n writeCloudCheckpointManifest,\n type CloudCheckpointInfo,\n type CloudCheckpointManifest,\n type CloudCheckpointProjectGroup,\n type WriteCloudManifestFields,\n} from './checkpoint.js';\n// Re-export host-side agent-config staging from sandbox-docker so cloud\n// providers (sandbox-daytona, future cloud backends) can use them without\n// taking a direct sandbox-docker dep (which would bend the provider-isolation\n// rule). The implementations live in sandbox-docker for historical reasons:\n// they were originally built for the docker rsync-into-volume flow and stayed\n// there when the cloud path adopted them.\nexport {\n stageClaudeStaticForUpload,\n stageClaudeJsonOnlyForUpload,\n stageClaudeCredentialsForUpload,\n stageCodexStaticForUpload,\n stageCodexCredentialsForUpload,\n stageOpencodeStaticForUpload,\n stageOpencodeCredentialsForUpload,\n CREDENTIALS_BACKUP_FILE,\n CODEX_CREDENTIALS_BACKUP_FILE,\n OPENCODE_CREDENTIALS_BACKUP_FILE,\n isRealAgentCredential,\n type CredentialAgentKind,\n type StageClaudeOptions,\n type StageCodexOptions,\n type StageOpencodeOptions,\n type StageResult,\n} from '@agentbox/sandbox-docker';\n// Portless helpers — same re-export pattern as the stage* helpers above.\n// Lives in sandbox-docker for historical reasons (the file predates the\n// hetzner provider), surfaced here so non-docker providers (sandbox-hetzner,\n// any future SSH-tunneled backend) don't need a direct sandbox-docker dep.\n// Phase 1 of the hetzner provider work: `portlessBrowserEnv` now takes a\n// `{ mapTarget }` option so the in-box Chromium remap targets the right host\n// gateway per provider (`host.docker.internal` for docker, `127.0.0.1` for\n// hetzner where the box is the VPS).\nexport {\n detectPortless,\n installPortless,\n portlessAlias,\n portlessBrowserEnv,\n portlessGetUrl,\n portlessInstallHint,\n portlessStartHint,\n portlessUnalias,\n resetPortlessCache,\n resolvePortlessHostStateDir,\n startPortlessProxy,\n PORTLESS_PROXY_PORT,\n type PortlessBrowserEnvOptions,\n type PortlessState,\n} from '@agentbox/sandbox-docker';\n"],"mappings":"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","names":["basename","writeFile","dirname","mkdir","rm","writeFile","join","mkdtemp","rm","writeFile","tmpdir","join","execa","mkdtemp","rm","tmpdir","join","execa","readFile","statSync","writeFile","dirname","REMOTE_TAR","join","mkdir","rm","execa","mkdtemp","tmpdir","readFile","WORKSPACE_DIR_DEFAULT","stat","basename","opts"]}