@madarco/agentbox 0.10.1 → 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +44 -0
- package/dist/{_cloud-attach-2DGI6FUA.js → _cloud-attach-45ECDTRL.js} +4 -4
- package/dist/{chunk-MTVI44DW.js → chunk-ECLLV5JH.js} +6 -3
- package/dist/chunk-ECLLV5JH.js.map +1 -0
- package/dist/{chunk-M2UWJKFA.js → chunk-MXXXKJYS.js} +5 -5
- package/dist/chunk-MXXXKJYS.js.map +1 -0
- package/dist/{chunk-I7NOGCL4.js → chunk-PZ2TJF2U.js} +23 -11
- package/dist/chunk-PZ2TJF2U.js.map +1 -0
- package/dist/{chunk-I24B6AXR.js → chunk-R5XIDQFR.js} +6 -3
- package/dist/chunk-R5XIDQFR.js.map +1 -0
- package/dist/{chunk-PWUVHPN6.js → chunk-SNTHHWKY.js} +7 -3
- package/dist/chunk-SNTHHWKY.js.map +1 -0
- package/dist/{chunk-LEV3KICD.js → chunk-ZGVMN54V.js} +6 -3
- package/dist/{chunk-LEV3KICD.js.map → chunk-ZGVMN54V.js.map} +1 -1
- package/dist/{chunk-CDKVD6UO.js → chunk-ZJXTIH6C.js} +119 -87
- package/dist/chunk-ZJXTIH6C.js.map +1 -0
- package/dist/{dist-SBCQVFCE.js → dist-ASLPRUQR.js} +3 -3
- package/dist/{dist-BD5QJRDC.js → dist-PTJ6CEQY.js} +5 -5
- package/dist/{dist-SJHY3HYN.js → dist-RAZP76VX.js} +5 -5
- package/dist/{dist-BNI5PQYK.js → dist-WMQDMTWS.js} +5 -5
- package/dist/index.js +619 -546
- package/dist/index.js.map +1 -1
- package/dist/{prepared-state-MQHD3M5F-O5M4NIN4.js → prepared-state-MQHD3M5F-KE4DT3GX.js} +2 -2
- package/package.json +4 -4
- package/runtime/docker/packages/ctl/dist/bin.cjs +5 -2
- package/runtime/hetzner/ctl.cjs +5 -2
- package/runtime/relay/bin.cjs +37 -19
- package/runtime/vercel/ctl.cjs +5 -2
- package/runtime/vercel/scripts/provision.sh +20 -0
- package/dist/chunk-CDKVD6UO.js.map +0 -1
- package/dist/chunk-I24B6AXR.js.map +0 -1
- package/dist/chunk-I7NOGCL4.js.map +0 -1
- package/dist/chunk-M2UWJKFA.js.map +0 -1
- package/dist/chunk-MTVI44DW.js.map +0 -1
- package/dist/chunk-PWUVHPN6.js.map +0 -1
- /package/dist/{_cloud-attach-2DGI6FUA.js.map → _cloud-attach-45ECDTRL.js.map} +0 -0
- /package/dist/{dist-SBCQVFCE.js.map → dist-ASLPRUQR.js.map} +0 -0
- /package/dist/{dist-BD5QJRDC.js.map → dist-PTJ6CEQY.js.map} +0 -0
- /package/dist/{dist-SJHY3HYN.js.map → dist-RAZP76VX.js.map} +0 -0
- /package/dist/{dist-BNI5PQYK.js.map → dist-WMQDMTWS.js.map} +0 -0
- /package/dist/{prepared-state-MQHD3M5F-O5M4NIN4.js.map → prepared-state-MQHD3M5F-KE4DT3GX.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/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/shell.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 { randomBytes } from 'node:crypto';\nimport { basename } from 'node:path';\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 { allocateProjectIndex, readState, recordBox, removeBoxRecord } 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 seedAgentVolumesIfFresh,\n seedOpencodeModelState,\n} from './agent-credentials.js';\nimport {\n cloudSnapshotName,\n listCloudCheckpoints,\n removeCloudCheckpointDir,\n resolveCloudCheckpoint,\n writeCloudCheckpointManifest,\n} from './checkpoint.js';\nimport { isSnapshotGoneError } from './snapshot-error.js';\nimport { uploadEnvFiles } from './env-files.js';\nimport { uploadCarryPaths } from './carry.js';\nimport { readExposedServicePorts } from './expose-ports.js';\nimport {\n downloadFromCloudBox,\n pullCloudDirContents,\n uploadToCloudBox,\n} 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\n ? Number.parseInt(u.port, 10)\n : tls\n ? 443\n : 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 = randomBytes(4).toString('hex');\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 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 in-box dockerd — also dies with the sandbox. Best-effort,\n // mirrors the docker provider's lifecycle.ts:276 relaunch. 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 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 });\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 ? await opts.provisionImage(req) : (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\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(`relay ensure failed (continuing): ${err instanceof Error ? err.message : String(err)}`);\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(req.projectRoot, backend.name, req.checkpointRef);\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 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 // After the sandbox is up with the credential volumes mounted, seed\n // any volume that doesn't already carry a `.agentbox-seeded-at`\n // marker from the host's filtered ~/.claude / ~/.codex /\n // opencode tree. Idempotent per agent — subsequent boxes find the\n // marker and skip the upload entirely.\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 // 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: { count: number; entries: Array<{ src: string; dest: string; bytes: number }> } | 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 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 // Always-on in-box dockerd, matching the Docker provider\n // (packages/sandbox-docker/src/create.ts:788). 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) log(`dockerd did not become ready (continuing): ${dockerd.reason ?? 'unknown'}`);\n } catch (err) {\n log(`dockerd daemon launch failed (continuing): ${err instanceof Error ? err.message : String(err)}`);\n }\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 // 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 });\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 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 ): Promise<{ finalPath: string }> {\n return uploadToCloudBox(backend, handleFor(box), hostSrc, boxDst);\n },\n\n async downloadPath(\n box: BoxRecord,\n boxSrc: string,\n hostDst: string,\n ): Promise<{ finalPath: string }> {\n return downloadFromCloudBox(backend, handleFor(box), boxSrc, hostDst);\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 =>\n 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 });\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 isRealAgentCredential,\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 if (typeof backend.ensureVolume !== 'function') {\n log(\n `cloud backend '${backend.name}' has no volume primitive — agent credentials will not persist across boxes`,\n );\n return { mounts: [], env: buildForwardedEnv([]), agents: [] };\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 const agents = AGENT_SPECS.map((s) => s.kind);\n return { mounts, env: buildForwardedEnv(agents), agents };\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 wanted = new Set<CloudAgentKind>(opts.agents ?? AGENT_SPECS.map((s) => s.kind));\n const specs = AGENT_SPECS.filter((s) => wanted.has(s.kind));\n await Promise.all(specs.map((spec) => seedCredentialsOne(backend, handle, spec, opts)));\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\n if (!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 process.stderr.write(`[agent-creds] ${spec.kind}: uploading ${sizeKB} KB...\\n`);\n const t0 = Date.now();\n const remoteTar = `/tmp/agentbox-${spec.kind}-creds.tar.gz`;\n await backend.uploadFile(handle, staged.tarballPath, remoteTar);\n const upDt = ((Date.now() - t0) / 1000).toFixed(1);\n process.stderr.write(`[agent-creds] ${spec.kind}: upload done in ${upDt}s\\n`);\n\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.\n const stageDir = `/tmp/agentbox-creds-stage-${spec.kind}`;\n const extractCmd =\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 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 process.stderr.write(`[agent-creds] ${msg}\\n`);\n return;\n }\n log(`${spec.kind}: credentials seeded ✓`);\n process.stderr.write(`[agent-creds] ${spec.kind}: credentials seeded\\n`);\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 * 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';\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 schema: 1;\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 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) return null;\n return m;\n } catch {\n return null;\n }\n}\n\nexport async function listCloudCheckpoints(\n projectRoot: string,\n backend: string,\n): Promise<CloudCheckpointInfo[]> {\n const root = backendDir(backend, projectRoot);\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 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}\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: 1,\n name,\n backend,\n snapshotName: fields.snapshotName,\n sourceBoxId: fields.sourceBoxId,\n sourceBoxName: fields.sourceBoxName,\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\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 tarArgs = isDir\n ? ['-C', entry.absSrc, '-cf', localTar, '.']\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 const execOpts = args.backend.name === 'vercel' ? { 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): 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 await execa('tar', ['-C', srcParent, '-czf', localTar, 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): 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 packScript = [\n `set -euo pipefail`,\n `cd ${quoteShellArg(srcParent)}`,\n `tar -czf ${quoteShellArg(REMOTE_DOWN_TAR)} ${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","/**\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","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 // Match the host-side probe in packages/sandbox-docker/src/vnc.ts: poll for\n // ~5s, then give up. The script itself waits for Xvnc internally; this\n // outer probe confirms websockify's public port came up too.\n `for _ in $(seq 1 50); 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 5s\" >&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 {\n launchCloudCtlDaemon,\n type LaunchCloudCtlArgs,\n} from './ctl-launch.js';\nexport {\n launchCloudDockerdDaemon,\n type CloudDockerdLaunchResult,\n} 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 {\n uploadEnvFiles,\n type UploadEnvFilesArgs,\n type UploadEnvFilesResult,\n} from './env-files.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 listCloudCheckpoints,\n probeCloudCheckpoint,\n removeCloudCheckpointDir,\n resolveCloudCheckpoint,\n writeCloudCheckpointManifest,\n type CloudCheckpointInfo,\n type CloudCheckpointManifest,\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 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","mkdir","writeFile","rm","writeFile","join","mkdtemp","rm","tmpdir","join","execa","readFile","statSync","mkdir","writeFile","join","rm","mkdtemp","tmpdir","execa","readFile","WORKSPACE_DIR_DEFAULT","stat","basename","opts"]}
|