@madarco/agentbox 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/_cloud-attach-T727ZPRV.js +13 -0
  2. package/dist/{chunk-NW5NYTQM.js → chunk-67N47KUS.js} +359 -85
  3. package/dist/chunk-67N47KUS.js.map +1 -0
  4. package/dist/{chunk-NAVL4R34.js → chunk-6OZDFNBF.js} +1084 -516
  5. package/dist/chunk-6OZDFNBF.js.map +1 -0
  6. package/dist/chunk-BGK32PZE.js +455 -0
  7. package/dist/chunk-BGK32PZE.js.map +1 -0
  8. package/dist/{chunk-7KOEFGN2.js → chunk-FODMEHD3.js} +52 -14
  9. package/dist/chunk-FODMEHD3.js.map +1 -0
  10. package/dist/{chunk-UK72UQ5U.js → chunk-G3H2L3O2.js} +55 -4
  11. package/dist/chunk-G3H2L3O2.js.map +1 -0
  12. package/dist/{chunk-V5KZGB5V.js → chunk-LEV3KICD.js} +18 -2
  13. package/dist/chunk-LEV3KICD.js.map +1 -0
  14. package/dist/{cloud-poller-ZIWSADJB-JXFRJUEM.js → cloud-poller-SUNA6ZQC-2RG5WPRN.js} +2 -2
  15. package/dist/{dist-R67WMLCF.js → dist-L4LCG5SJ.js} +120 -10
  16. package/dist/dist-L4LCG5SJ.js.map +1 -0
  17. package/dist/{dist-ETCFRVPA.js → dist-LOZBWMBF.js} +44 -20
  18. package/dist/{dist-QZGJIBT5.js → dist-ZODPD2I6.js} +142 -74
  19. package/dist/dist-ZODPD2I6.js.map +1 -0
  20. package/dist/index.js +3563 -845
  21. package/dist/index.js.map +1 -1
  22. package/dist/prepared-state-CL4CWXQA-ME4HSKDE.js +18 -0
  23. package/dist/prepared-state-CL4CWXQA-ME4HSKDE.js.map +1 -0
  24. package/package.json +4 -4
  25. package/runtime/daytona/custom-system-CLAUDE.md +39 -0
  26. package/runtime/docker/Dockerfile.box +22 -0
  27. package/runtime/docker/apps/cli/share/agentbox-setup/SKILL.md +1 -1
  28. package/runtime/docker/packages/ctl/dist/bin.cjs +1118 -71
  29. package/runtime/docker/packages/sandbox-docker/scripts/agentbox-codex-hooks.json +66 -35
  30. package/runtime/docker/packages/sandbox-docker/scripts/claude-managed-settings.json +62 -1
  31. package/runtime/docker/packages/sandbox-docker/scripts/custom-system-CLAUDE.md +15 -4
  32. package/runtime/docker/packages/sandbox-docker/scripts/gh-shim +263 -0
  33. package/runtime/docker/packages/sandbox-docker/scripts/git-shim +131 -0
  34. package/runtime/docker/packages/sandbox-docker/scripts/opencode-agentbox-plugin.js +76 -0
  35. package/runtime/hetzner/agentbox-codex-hooks.json +66 -35
  36. package/runtime/hetzner/agentbox-setup-skill.md +1 -1
  37. package/runtime/hetzner/claude-managed-settings.json +62 -1
  38. package/runtime/hetzner/ctl.cjs +1118 -71
  39. package/runtime/hetzner/custom-system-CLAUDE.md +26 -14
  40. package/runtime/hetzner/gh-shim +263 -0
  41. package/runtime/hetzner/git-shim +131 -0
  42. package/runtime/hetzner/opencode-agentbox-plugin.js +76 -0
  43. package/runtime/hetzner/scripts/install-box.sh +11 -2
  44. package/runtime/relay/bin.cjs +927 -36
  45. package/share/agentbox-setup/SKILL.md +1 -1
  46. package/share/host-skills/agentbox/SKILL.md +29 -0
  47. package/share/host-skills/agentbox-info/SKILL.md +211 -0
  48. package/share/host-skills/codex/agentbox.md +35 -0
  49. package/share/host-skills/opencode/agentbox.md +26 -0
  50. package/dist/_cloud-attach-DMVH6GWO.js +0 -12
  51. package/dist/chunk-7KOEFGN2.js.map +0 -1
  52. package/dist/chunk-NAVL4R34.js.map +0 -1
  53. package/dist/chunk-NW5NYTQM.js.map +0 -1
  54. package/dist/chunk-UK72UQ5U.js.map +0 -1
  55. package/dist/chunk-V5KZGB5V.js.map +0 -1
  56. package/dist/dist-QZGJIBT5.js.map +0 -1
  57. package/dist/dist-R67WMLCF.js.map +0 -1
  58. /package/dist/{_cloud-attach-DMVH6GWO.js.map → _cloud-attach-T727ZPRV.js.map} +0 -0
  59. /package/dist/{cloud-poller-ZIWSADJB-JXFRJUEM.js.map → cloud-poller-SUNA6ZQC-2RG5WPRN.js.map} +0 -0
  60. /package/dist/{dist-ETCFRVPA.js.map → dist-LOZBWMBF.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../packages/sandbox-daytona/src/dockerfile-context.ts","../../../packages/sandbox-daytona/src/env-loader.ts","../../../packages/sandbox-daytona/src/backend.ts","../../../packages/sandbox-daytona/src/retry.ts","../../../packages/sandbox-daytona/src/credentials.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\n/**\n * Locate `Dockerfile.box` + its build context so Daytona can `Image.fromDockerfile`\n * the same image the Docker provider builds locally. The Dockerfile COPYs from\n * the monorepo (packages/ctl/dist/bin.cjs, apps/cli/share/..., scripts/), so\n * the context dir must contain that tree.\n *\n * Mirrors `@agentbox/sandbox-docker`'s `resolveDockerBuild`, intentionally\n * inlined: sandbox-daytona must not depend on sandbox-docker (cross-provider\n * dep would defeat the point of `@agentbox/sandbox-cloud`).\n *\n * Resolution order:\n * 0. AGENTBOX_DOCKER_CONTEXT env override.\n * 1. Staged context shipped with the bundled `agent-box` package (sibling\n * of dist/, uniform in dev + installed).\n * 2. Legacy monorepo layout: Dockerfile.box at sandbox-docker's package\n * root, context = monorepo root.\n */\nexport interface DockerfileContext {\n dockerfile: string;\n context: string;\n}\n\nexport function resolveDockerfileContext(): DockerfileContext | null {\n const override = process.env.AGENTBOX_DOCKER_CONTEXT;\n if (override && existsSync(resolve(override, 'Dockerfile.box'))) {\n return { dockerfile: resolve(override, 'Dockerfile.box'), context: override };\n }\n const here = dirname(fileURLToPath(import.meta.url));\n const staged = resolve(here, '..', 'runtime', 'docker');\n if (existsSync(resolve(staged, 'Dockerfile.box'))) {\n return { dockerfile: resolve(staged, 'Dockerfile.box'), context: staged };\n }\n // Legacy monorepo: this module is at packages/sandbox-daytona/dist; the\n // Dockerfile lives at packages/sandbox-docker/Dockerfile.box; the build\n // context is the monorepo root.\n const monorepoRoot = resolve(here, '..', '..', '..');\n const dockerfile = resolve(monorepoRoot, 'packages', 'sandbox-docker', 'Dockerfile.box');\n if (existsSync(dockerfile)) {\n return { dockerfile, context: monorepoRoot };\n }\n return null;\n}\n\n/**\n * Locate the daytona-specific `custom-system-CLAUDE.md` that overlays the\n * docker-shaped one baked into `Dockerfile.box`. Daytona boxes have no host\n * `.git/` bind-mount, so the in-box hint needs daytona-specific git wording\n * (use `agentbox-ctl git` for any host-touching op). Same two-tier lookup\n * shape as `resolveDockerfileContext()`: staged CLI runtime first, monorepo\n * source as the dev fallback.\n */\nexport function resolveDaytonaCustomClaudeMd(): string | null {\n const here = dirname(fileURLToPath(import.meta.url));\n const staged = resolve(here, '..', 'runtime', 'daytona', 'custom-system-CLAUDE.md');\n if (existsSync(staged)) return staged;\n const monorepoRoot = resolve(here, '..', '..', '..');\n const dev = resolve(\n monorepoRoot,\n 'packages',\n 'sandbox-daytona',\n 'scripts',\n 'custom-system-CLAUDE.md',\n );\n if (existsSync(dev)) return dev;\n return null;\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { resolve } from 'node:path';\n\n/**\n * Daytona env auto-loader. The SDK reads `DAYTONA_API_KEY` /\n * `DAYTONA_JWT_TOKEN` + `DAYTONA_ORGANIZATION_ID` from `process.env`. We pull\n * those keys in from `~/.agentbox/secrets.env` so the SDK Just Works after\n * the user runs `agentbox daytona login` once.\n *\n * Lookup order (first wins; process.env is never overwritten):\n * 1. `process.env` (already set in the shell).\n * 2. `~/.agentbox/secrets.env` — written by `agentbox daytona login`.\n *\n * Project-level `.env` / `.env.local` are intentionally NOT consulted: those\n * files belong to the app code being developed, and a `DAYTONA_API_KEY`\n * there is typically meant for in-box code execution, not for the host CLI\n * to harvest and provision sandboxes with.\n *\n * Only Daytona-prefixed keys are imported; the rest of the file is left\n * alone. The loader is idempotent and side-effect-free after the first call.\n */\nconst DAYTONA_KEYS = [\n 'DAYTONA_API_KEY',\n 'DAYTONA_JWT_TOKEN',\n 'DAYTONA_ORGANIZATION_ID',\n 'DAYTONA_API_URL',\n 'DAYTONA_TARGET',\n] as const;\n\nlet loaded = false;\n\nexport function ensureDaytonaEnvLoaded(): void {\n if (loaded) return;\n loaded = true;\n importDaytonaFromFile(resolve(homedir(), '.agentbox', 'secrets.env'));\n}\n\nfunction importDaytonaFromFile(path: string): void {\n if (!existsSync(path)) return;\n let body: string;\n try {\n body = readFileSync(path, 'utf8');\n } catch {\n return;\n }\n const parsed = parseEnvFile(body);\n for (const key of DAYTONA_KEYS) {\n if (process.env[key] !== undefined) continue;\n const value = parsed[key];\n if (typeof value === 'string') {\n process.env[key] = value;\n }\n }\n}\n\n/**\n * Minimal `.env` parser: handles `KEY=value`, `KEY=\"value with spaces\"`,\n * `KEY='value with $special chars'`, `export KEY=value`, blank lines, and\n * `#` comments. Doesn't do variable interpolation — that's surprising to\n * users coming from full dotenv, but secrets typically don't reference each\n * other and we'd rather be predictable.\n */\nexport function parseEnvFile(body: string): Record<string, string> {\n const out: Record<string, string> = {};\n for (const rawLine of body.split(/\\r?\\n/)) {\n const line = rawLine.trim();\n if (line.length === 0 || line.startsWith('#')) continue;\n const stripped = line.startsWith('export ') ? line.slice('export '.length) : line;\n const eq = stripped.indexOf('=');\n if (eq <= 0) continue;\n const key = stripped.slice(0, eq).trim();\n let value = stripped.slice(eq + 1).trim();\n // Strip surrounding quotes (single or double).\n if (\n value.length >= 2 &&\n ((value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\")))\n ) {\n value = value.slice(1, -1);\n }\n out[key] = value;\n }\n return out;\n}\n","/**\n * Daytona `CloudBackend` — maps the provider-neutral cloud primitives onto\n * `@daytonaio/sdk`. Lazy SDK client + lazy sandbox handle resolution so\n * importing this module costs nothing until a daytona-tagged box does something.\n */\n\nimport { Daytona, DaytonaNotFoundError, Image, SandboxState, type Sandbox } from '@daytonaio/sdk';\nimport type { CloudSandboxSummary } from '@agentbox/core';\nimport type {\n CloudBackend,\n CloudExecOptions,\n CloudExecResult,\n CloudFileEntry,\n CloudHandle,\n CloudPreviewUrl,\n CloudProvisionRequest,\n CloudState,\n CloudVolumeMount,\n} from '@agentbox/core';\nimport { resolveDockerfileContext } from './dockerfile-context.js';\nimport { ensureDaytonaEnvLoaded } from './env-loader.js';\nimport { withDaytonaRetry } from './retry.js';\n\n/**\n * Thin shorthand for `withDaytonaRetry` with our defaults. Most methods are\n * idempotent and use `retryOnAmbiguous: true`; the few that aren't override.\n */\nfunction retry<T>(\n method: string,\n fn: () => Promise<T>,\n opts: {\n attemptTimeoutMs?: number;\n retryOnAmbiguous?: boolean;\n /** When true, single-shot — no backoff list, no retries. */\n noRetry?: boolean;\n } = {},\n): Promise<T> {\n return withDaytonaRetry(\n {\n method,\n retryOnAmbiguous: opts.retryOnAmbiguous ?? true,\n attemptTimeoutMs: opts.attemptTimeoutMs,\n backoffMs: opts.noRetry === true ? [] : undefined,\n },\n fn,\n );\n}\n\n/**\n * Sentinel image ref the cloud-provider hands to us when the user didn't pass\n * `--image`. We translate it to `Image.fromDockerfile(...)` so Daytona builds\n * the same box image the Docker provider builds locally.\n */\nexport const DEFAULT_BOX_IMAGE_REF = 'agentbox/box:dev';\n\nlet client: Daytona | null = null;\nexport function getClient(): Daytona {\n if (!client) {\n // Pull DAYTONA_* keys from `.env.local` / `.env` / `~/.agentbox/secrets.env`\n // into process.env first — the SDK reads from process.env and most users\n // keep secrets in a project file rather than their shell rc.\n ensureDaytonaEnvLoaded();\n try {\n // Daytona() reads DAYTONA_API_KEY / DAYTONA_JWT_TOKEN + DAYTONA_ORGANIZATION_ID\n // from env.\n client = new Daytona();\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n // The interactive prompt in `agentbox daytona login` handles first-run\n // setup; this error path is for non-TTY callers (CI, scripts) where the\n // prompt was skipped.\n throw new Error(\n `Daytona credentials not configured: ${msg}\\n` +\n `Run \\`agentbox daytona login\\` interactively, or set DAYTONA_API_KEY in the environment.`,\n );\n }\n }\n return client;\n}\n\nasync function getSandbox(id: string): Promise<Sandbox> {\n return getClient().get(id);\n}\n\nasync function maybeGetSandbox(id: string): Promise<Sandbox | null> {\n try {\n return await getClient().get(id);\n } catch {\n return null;\n }\n}\n\n/**\n * Map Daytona's `SandboxState` (16 fine-grained values incl. transitional ones)\n * onto our 4-value `CloudState`. Transitional states ('starting', 'creating')\n * are reported as 'running' so callers don't ping-pong; 'archived' maps to\n * 'paused' (our pause is Daytona's archive).\n */\nfunction mapState(s: SandboxState | string | undefined): CloudState {\n switch (s) {\n case SandboxState.STARTED:\n return 'running';\n case SandboxState.STARTING:\n case SandboxState.CREATING:\n case SandboxState.RESTORING:\n case SandboxState.BUILDING_SNAPSHOT:\n case SandboxState.PULLING_SNAPSHOT:\n case SandboxState.PENDING_BUILD:\n case SandboxState.STOPPING:\n return 'running';\n case SandboxState.STOPPED:\n return 'stopped';\n case SandboxState.ARCHIVED:\n case SandboxState.ARCHIVING:\n return 'paused';\n case SandboxState.DESTROYED:\n case SandboxState.DESTROYING:\n case SandboxState.ERROR:\n case SandboxState.BUILD_FAILED:\n case SandboxState.UNKNOWN:\n default:\n return 'missing';\n }\n}\n\n/**\n * Translate our provider-neutral `CloudVolumeMount` into the SDK shape Daytona\n * expects. The SDK's `VolumeMount` carries `volumeId` + `mountPath` (+ optional\n * `subpath` for S3-prefix mounts); a 1:1 mapping with our type.\n */\nfunction toDaytonaVolumeMount(v: CloudVolumeMount): {\n volumeId: string;\n mountPath: string;\n subpath?: string;\n} {\n return {\n volumeId: v.volumeId,\n mountPath: v.mountPath,\n ...(v.subpath ? { subpath: v.subpath } : {}),\n };\n}\n\n/** Translate the request's image ref into something Daytona's `create` accepts. */\nfunction resolveImage(ref: string): string | Image {\n if (ref !== DEFAULT_BOX_IMAGE_REF) return ref;\n const ctx = resolveDockerfileContext();\n if (!ctx) {\n throw new Error(\n \"could not locate the AgentBox Dockerfile.box build context for the Daytona snapshot. \" +\n \"Set AGENTBOX_DOCKER_CONTEXT to a directory containing Dockerfile.box, or pass --image <ref> with a Daytona-compatible image.\",\n );\n }\n // Image.fromDockerfile bundles the directory the Dockerfile lives in and\n // ships it to Daytona to build a snapshot. The Dockerfile.box COPYs from\n // the monorepo tree; the staged `runtime/docker` context already mirrors\n // that tree, so the build resolves COPY paths correctly.\n return Image.fromDockerfile(ctx.dockerfile);\n}\n\nexport const daytonaBackend: CloudBackend = {\n name: 'daytona',\n\n async provision(req: CloudProvisionRequest): Promise<CloudHandle> {\n // No-retry: provision is non-idempotent — a 504 after the request reaches\n // the origin could create a duplicate billable sandbox we can't reference\n // for cleanup. The wrapper still bounds wall-clock at 900s (matching the\n // existing inline SDK timeout) so a wedged connection fails cleanly.\n return retry(\n 'provision',\n async () => {\n // Two SDK overloads:\n // - `CreateSandboxFromSnapshotParams` takes `snapshot:` and no\n // `onSnapshotCreateLogs` (the snapshot already exists, nothing to build).\n // - `CreateSandboxFromImageParams` takes `image:` and accepts\n // `onSnapshotCreateLogs` for streaming the Dockerfile build.\n // TypeScript can't infer the right overload from a union literal, so\n // split the call.\n const baseParams = {\n ...(req.resources ? { resources: req.resources } : {}),\n envVars: req.env,\n ...(req.volumes && req.volumes.length > 0\n ? { volumes: req.volumes.map(toDaytonaVolumeMount) }\n : {}),\n labels: { 'agentbox.name': req.name },\n };\n const client = getClient();\n // The first-time Dockerfile.box snapshot build is ~41 layers and pulls\n // Chromium — comfortably 5+ minutes wall time. Daytona's default ready\n // timeout is too short for that; override with 15 min so a cold build\n // doesn't fail mid-snapshot. Cached snapshots and snapshot-based\n // creates come up in seconds.\n // Resolve `req.image` against Daytona's snapshot registry first when\n // it's set to a non-default value: `agentbox prepare --provider\n // daytona` registers a named snapshot and writes `box.image:\n // <name>` into project config; subsequent creates should boot from\n // that snapshot, not try to pull `<name>:latest` from Docker Hub.\n // Default ref (agentbox/box:dev) skips the lookup and goes through\n // resolveImage (Image.fromDockerfile). Explicit `req.snapshot` always\n // wins (cloud checkpoint path).\n let snapshotName = req.snapshot;\n if (!snapshotName && req.image && req.image !== DEFAULT_BOX_IMAGE_REF) {\n try {\n const snap = await client.snapshot.get(req.image);\n if (snap && snap.name) snapshotName = snap.name;\n } catch {\n // Not a known snapshot — fall through and treat as a Docker image ref.\n }\n }\n // Daytona rejects `resources` on the snapshot path — the snapshot's\n // own params encode them. Strip resources only for the snapshot\n // branch; the image branch keeps them.\n const snapshotParams: Record<string, unknown> = { ...baseParams };\n delete snapshotParams.resources;\n const sandbox = snapshotName\n ? await client.create({ snapshot: snapshotName, ...snapshotParams }, { timeout: 900 })\n : await client.create(\n { image: resolveImage(req.image), ...baseParams },\n {\n timeout: 900,\n ...(req.onLog ? { onSnapshotCreateLogs: req.onLog } : {}),\n },\n );\n return { sandboxId: sandbox.id };\n },\n { retryOnAmbiguous: false, attemptTimeoutMs: 900_000 },\n );\n },\n\n async ensureVolume(name: string): Promise<{ volumeId: string }> {\n // Daytona's `volume.get(name, create=true)` returns the existing volume or\n // initiates creation on first call. Critically, a freshly-created volume\n // comes back in `creating`/`pending_create` state — passing such a volume\n // into `Daytona.create({ volumes: […] })` is rejected with\n // \"Volume is not in a ready state. Current state: creating\". So poll\n // `volume.get` until the state lands on `ready` (or a terminal failure).\n //\n // Volumes are org-scoped on Daytona — every sandbox in the same Daytona\n // organization sees the same id, which is what we want for sharing agent\n // credentials across all of a user's boxes.\n //\n // Each individual `volume.get` call is retry-wrapped so a transient edge\n // hiccup mid-poll doesn't fail the whole ensure.\n const client = getClient();\n let vol = await retry('volume.get(create)', () => client.volume.get(name, true));\n // Volumes typically transition from creating → ready within a few seconds.\n // Allow up to 60s in case of slow control-plane operations.\n const deadline = Date.now() + 60_000;\n while (vol.state !== 'ready') {\n if (vol.state === 'error' || vol.state === 'deleted' || vol.state === 'deleting') {\n throw new Error(\n `Daytona volume '${name}' is in unrecoverable state '${vol.state}'. ` +\n `Delete it from the Daytona dashboard and retry.`,\n );\n }\n if (Date.now() >= deadline) {\n throw new Error(\n `Daytona volume '${name}' did not become ready within 60s (state: ${vol.state}). ` +\n `Try again — the Daytona control plane may be slow.`,\n );\n }\n await new Promise((r) => setTimeout(r, 1000));\n vol = await retry('volume.get(poll)', () => client.volume.get(name));\n }\n return { volumeId: vol.id };\n },\n\n async get(sandboxId: string): Promise<CloudHandle | null> {\n return retry('get', async () => {\n const sb = await maybeGetSandbox(sandboxId);\n return sb ? { sandboxId: sb.id } : null;\n });\n },\n\n async list(): Promise<CloudSandboxSummary[]> {\n return retry('list', async () => {\n const client = getClient();\n // `client.list()` returns `PaginatedSandboxes { items: Sandbox[] }`\n // (page 1 by default). For prune we don't need multi-page traversal\n // yet — sandboxes per org are bounded; if that changes, loop on page.\n const page = await client.list();\n const items = Array.isArray(page) ? page : (page.items ?? []);\n return items.map((sb): CloudSandboxSummary => {\n const summary: CloudSandboxSummary = { sandboxId: sb.id };\n const raw = sb as unknown as {\n name?: string;\n labels?: Record<string, string>;\n state?: string;\n createdAt?: string;\n };\n const friendly = raw.labels?.['agentbox.name'] ?? raw.name;\n if (friendly) summary.name = friendly;\n if (raw.createdAt) summary.createdAt = raw.createdAt;\n if (typeof raw.state === 'string') summary.state = mapState(raw.state);\n return summary;\n });\n });\n },\n\n async start(h: CloudHandle): Promise<void> {\n return retry(\n 'start',\n async () => {\n const sb = await getSandbox(h.sandboxId);\n await sb.start();\n },\n { attemptTimeoutMs: 60_000 },\n );\n },\n\n async stop(h: CloudHandle): Promise<void> {\n return retry(\n 'stop',\n async () => {\n const sb = await getSandbox(h.sandboxId);\n await sb.stop();\n },\n { attemptTimeoutMs: 60_000 },\n );\n },\n\n async pause(h: CloudHandle): Promise<void> {\n // Our pause == cold storage (Daytona archive). The tradeoff is documented\n // in CloudBackend's interface comment.\n return retry(\n 'pause',\n async () => {\n const sb = await getSandbox(h.sandboxId);\n await sb.archive();\n },\n { attemptTimeoutMs: 60_000 },\n );\n },\n\n async resume(h: CloudHandle): Promise<void> {\n return retry(\n 'resume',\n async () => {\n const sb = await getSandbox(h.sandboxId);\n await sb.start();\n },\n { attemptTimeoutMs: 60_000 },\n );\n },\n\n async destroy(h: CloudHandle): Promise<void> {\n return retry(\n 'destroy',\n async () => {\n const sb = await maybeGetSandbox(h.sandboxId);\n if (!sb) return; // already gone — destroy is idempotent\n // Daytona's `delete()` on a running sandbox is queued, not synchronous —\n // observed in practice: `delete()` returns ok, the sandbox stays in\n // 'started' for tens of seconds, then eventually disappears. Stopping\n // first makes the delete synchronous so callers (and the dashboard) see\n // it gone immediately. Swallow stop errors — if the sandbox is already\n // stopped/archived, delete still works.\n try {\n await sb.stop(60);\n } catch {\n /* best-effort */\n }\n try {\n await sb.delete(60);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n // Already deleted between stop and delete — fine.\n if (!/not found/i.test(msg)) throw err;\n }\n },\n { attemptTimeoutMs: 120_000 },\n );\n },\n\n async state(h: CloudHandle): Promise<CloudState> {\n return retry('state', async () => {\n const sb = await maybeGetSandbox(h.sandboxId);\n if (!sb) return 'missing';\n return mapState(sb.state);\n });\n },\n\n async exec(\n h: CloudHandle,\n cmd: string,\n opts?: CloudExecOptions,\n ): Promise<CloudExecResult> {\n return retry(\n 'exec',\n async () => {\n const sb = await getSandbox(h.sandboxId);\n // Daytona's ExecuteResponse returns combined output in `result` with no\n // separate stderr stream. Surface it as stdout and leave stderr empty —\n // callers that need split streams must redirect inside `cmd` itself.\n const r = await sb.process.executeCommand(cmd, opts?.cwd, opts?.env);\n return { exitCode: r.exitCode, stdout: r.result, stderr: '' };\n },\n { attemptTimeoutMs: opts?.attemptTimeoutMs ?? 120_000, noRetry: opts?.noRetry },\n );\n },\n\n async uploadFile(h: CloudHandle, localPath: string, remotePath: string): Promise<void> {\n return retry(\n 'uploadFile',\n async () => {\n const sb = await getSandbox(h.sandboxId);\n await sb.fs.uploadFile(localPath, remotePath);\n },\n { attemptTimeoutMs: 300_000 },\n );\n },\n\n async downloadFile(h: CloudHandle, remotePath: string, localPath: string): Promise<void> {\n return retry(\n 'downloadFile',\n async () => {\n const sb = await getSandbox(h.sandboxId);\n await sb.fs.downloadFile(remotePath, localPath);\n },\n { attemptTimeoutMs: 300_000 },\n );\n },\n\n async listFiles(h: CloudHandle, remoteDir: string): Promise<CloudFileEntry[]> {\n return retry('listFiles', async () => {\n const sb = await getSandbox(h.sandboxId);\n const files = await sb.fs.listFiles(remoteDir);\n return files.map((f) => ({\n name: f.name,\n isDir: Boolean((f as { isDir?: boolean }).isDir),\n }));\n });\n },\n\n async previewUrl(h: CloudHandle, port: number): Promise<CloudPreviewUrl> {\n return retry('previewUrl', async () => {\n const sb = await getSandbox(h.sandboxId);\n const p = await sb.getPreviewLink(port);\n // The host CloudBoxPoller attaches `token` as `x-daytona-preview-token`\n // for every /bridge call. Browser-bound URLs use `signedPreviewUrl` below\n // instead (the two token kinds are not interchangeable on Daytona).\n return { url: p.url, token: p.token };\n });\n },\n\n async signedPreviewUrl(\n h: CloudHandle,\n port: number,\n expiresInSeconds: number,\n ): Promise<CloudPreviewUrl> {\n return retry('signedPreviewUrl', async () => {\n const sb = await getSandbox(h.sandboxId);\n const s = await sb.getSignedPreviewUrl(port, expiresInSeconds);\n return { url: s.url, token: s.token };\n });\n },\n\n async attachArgv(h: CloudHandle): Promise<string[]> {\n return retry('attachArgv', async () => {\n const sb = await getSandbox(h.sandboxId);\n // 60 min default expiry matches the SDK default; an interactive session\n // longer than that is rare. `sandbox-cloud`'s buildAttach appends\n // `-t '<inner cmd>'` for the per-session tmux attach.\n const ssh = await sb.createSshAccess(60);\n return [\n 'ssh',\n // First-connect to a never-seen host fingerprint should be silent in a\n // PTY — the user already authenticated via Daytona's API.\n '-o', 'StrictHostKeyChecking=accept-new',\n // Daytona's SSH gateway terminates per-token; no key file, no port.\n `${ssh.token}@ssh.app.daytona.io`,\n ];\n });\n },\n\n async revokeAttachToken(h: CloudHandle, argv: string[]): Promise<void> {\n // argv[3] = `${token}@ssh.app.daytona.io`; pull the token off the front.\n const userhost = argv[argv.length - 1] ?? '';\n const atIdx = userhost.indexOf('@');\n if (atIdx <= 0) return;\n const token = userhost.slice(0, atIdx);\n if (token.length === 0) return;\n try {\n await retry('revokeAttachToken', async () => {\n const sb = await getSandbox(h.sandboxId);\n await sb.revokeSshAccess(token);\n });\n } catch {\n // Best-effort — tokens auto-expire after 60 min anyway.\n }\n },\n\n async createSnapshot(h: CloudHandle, snapshotName: string): Promise<void> {\n // Daytona's `_experimental_createSnapshot` puts the sandbox into the\n // `snapshotting` state, captures its filesystem, then returns. The\n // resulting snapshot is org-scoped and visible via the Daytona dashboard\n // and `client.snapshot.list()`. We give it a generous timeout (15min,\n // matching `provision`) because a large `/workspace` plus warmed agent\n // volumes can take a while to snapshot.\n //\n // No retry on ambiguous failures: a 504 mid-snapshot could leave a\n // half-built named snapshot in Daytona that a retry would collide on.\n // Matches `provision`'s policy.\n return retry(\n 'createSnapshot',\n async () => {\n const sb = await getSandbox(h.sandboxId);\n await sb._experimental_createSnapshot(snapshotName);\n },\n { attemptTimeoutMs: 900_000, retryOnAmbiguous: false },\n );\n },\n\n async deleteSnapshot(snapshotName: string): Promise<void> {\n return retry('deleteSnapshot', async () => {\n try {\n const client = getClient();\n const snapshot = await client.snapshot.get(snapshotName);\n await client.snapshot.delete(snapshot);\n } catch (err) {\n // Idempotent: a snapshot that's already gone is success from the\n // caller's perspective (mirrors `destroy()`'s \"not found\" handling).\n if (err instanceof DaytonaNotFoundError) return;\n const msg = err instanceof Error ? err.message : String(err);\n if (/not found/i.test(msg)) return;\n throw err;\n }\n });\n },\n};\n","/**\n * Bounded retry wrapper for `daytonaBackend` SDK calls. Daytona's CloudFront\n * edge intermittently 504s on `executeCommand` and other API calls (backlog\n * item 6.1) — without bounded retries an edge hiccup propagates as an\n * unbounded wedge in the calling code. This helper classifies transient\n * failures vs. permanent ones using the SDK's typed error classes, bounds\n * each attempt with a timeout, and caps the total wall-clock cost.\n *\n * Non-idempotent ops (`provision`) pass `retryOnAmbiguous: false` so a 504\n * after the request reached the origin doesn't create a duplicate sandbox.\n */\n\nimport {\n DaytonaAuthenticationError,\n DaytonaAuthorizationError,\n DaytonaConflictError,\n DaytonaConnectionError,\n DaytonaError,\n DaytonaNotFoundError,\n DaytonaRateLimitError,\n DaytonaTimeoutError,\n DaytonaValidationError,\n} from '@daytonaio/sdk';\n\nexport interface WithRetryOptions {\n /** Method name, used in retry log lines. */\n method: string;\n /** Per-attempt timeout (ms). Default 30_000. */\n attemptTimeoutMs?: number;\n /** Backoff before attempts 2, 3, … (ms). Default [1000, 2000, 4000]. */\n backoffMs?: readonly number[];\n /**\n * Whether to retry on errors where we can't be sure the server applied\n * the request — connection failures, per-attempt timeouts, and 5xx\n * responses (since 504 from CloudFront can mean \"origin still processing\").\n * Set false for non-idempotent operations (e.g. `provision`) where a\n * retry could create a duplicate.\n */\n retryOnAmbiguous: boolean;\n /** Override the default `process.stderr` retry sink (used by tests). */\n onRetry?: (line: string) => void;\n}\n\nconst DEFAULT_BACKOFF: readonly number[] = [1000, 2000, 4000];\nconst DEFAULT_ATTEMPT_TIMEOUT_MS = 30_000;\n\n/** Internal sentinel used by the per-attempt timeout race. */\nclass AttemptTimeoutError extends Error {\n constructor(method: string, ms: number) {\n super(`daytona ${method}: per-attempt timeout after ${String(ms)}ms`);\n this.name = 'AttemptTimeoutError';\n }\n}\n\nexport function isAttemptTimeout(err: unknown): err is AttemptTimeoutError {\n return err instanceof AttemptTimeoutError;\n}\n\n/**\n * Classify an error as retriable or not. `allowAmbiguous` gates the cases\n * where the server may or may not have applied the request — the caller\n * decides based on idempotency.\n */\nexport function isRetriable(err: unknown, allowAmbiguous: boolean): boolean {\n // Rate-limit responses always carry an intent from the server: back off.\n if (err instanceof DaytonaRateLimitError) return true;\n\n // Permanent client-side failures: never retry — the next call will get\n // the same answer and we'd just be wasting wall-clock.\n if (\n err instanceof DaytonaNotFoundError ||\n err instanceof DaytonaAuthenticationError ||\n err instanceof DaytonaAuthorizationError ||\n err instanceof DaytonaValidationError ||\n err instanceof DaytonaConflictError\n ) {\n return false;\n }\n\n // Connection / per-attempt timeout: the request may not have reached\n // the server. Gated by allowAmbiguous so non-idempotent callers can opt\n // out of double-execute risk.\n if (\n err instanceof DaytonaConnectionError ||\n err instanceof DaytonaTimeoutError ||\n err instanceof AttemptTimeoutError\n ) {\n return allowAmbiguous;\n }\n\n // Base DaytonaError: branch on statusCode. 5xx is ambiguous; 4xx we\n // didn't catch above is a permanent failure we hadn't seen before.\n if (err instanceof DaytonaError) {\n const status = err.statusCode;\n if (typeof status === 'number' && status >= 500 && status <= 599) {\n return allowAmbiguous;\n }\n return false;\n }\n\n // Axios-style fallback for raw errors that leak through without an SDK\n // wrapper. Match the same shape the SDK uses internally.\n if (err && typeof err === 'object') {\n const code = (err as { code?: unknown }).code;\n if (\n code === 'ECONNRESET' ||\n code === 'ETIMEDOUT' ||\n code === 'ECONNABORTED' ||\n code === 'EAI_AGAIN' ||\n code === 'ECONNREFUSED' ||\n code === 'ENOTFOUND'\n ) {\n return allowAmbiguous;\n }\n const status =\n (err as { response?: { status?: unknown } }).response?.status ??\n (err as { status?: unknown }).status ??\n (err as { statusCode?: unknown }).statusCode;\n if (typeof status === 'number' && status >= 500 && status <= 599) {\n return allowAmbiguous;\n }\n }\n\n return false;\n}\n\n/**\n * Run `fn`, retrying on transient failures with capped exponential backoff.\n * Each attempt is bounded by `attemptTimeoutMs` via Promise.race; total\n * wall-clock = sum(backoffMs) + maxAttempts * attemptTimeoutMs.\n */\nexport async function withDaytonaRetry<T>(\n opts: WithRetryOptions,\n fn: () => Promise<T>,\n): Promise<T> {\n const backoff = opts.backoffMs ?? DEFAULT_BACKOFF;\n const maxAttempts = backoff.length + 1;\n const timeoutMs = opts.attemptTimeoutMs ?? DEFAULT_ATTEMPT_TIMEOUT_MS;\n const log = opts.onRetry ?? defaultRetryLog;\n\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n return await raceTimeout(fn(), timeoutMs, opts.method);\n } catch (err) {\n const last = attempt === maxAttempts;\n if (last || !isRetriable(err, opts.retryOnAmbiguous)) throw err;\n const delay = backoff[attempt - 1] ?? backoff[backoff.length - 1] ?? 4000;\n log(\n `daytona ${opts.method}: attempt ${String(attempt)} failed (${errorSummary(err)}); retrying in ${String(delay)}ms`,\n );\n await sleep(delay);\n }\n }\n // Unreachable: the loop above either returns or throws.\n throw new Error(`withDaytonaRetry: exhausted attempts for ${opts.method}`);\n}\n\nfunction defaultRetryLog(line: string): void {\n // Prefix so log scrapers + users can distinguish retry chatter from real\n // CLI output. `\\n` before is intentional — many CLI surfaces use clack\n // spinners on stdout, and stderr lines without a leading newline can\n // collide with a redraw.\n process.stderr.write(`\\n[daytona-retry] ${line}\\n`);\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nasync function raceTimeout<T>(p: Promise<T>, ms: number, method: string): Promise<T> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n return await Promise.race([\n p,\n new Promise<never>((_resolve, reject) => {\n timer = setTimeout(() => reject(new AttemptTimeoutError(method, ms)), ms);\n }),\n ]);\n } finally {\n if (timer !== undefined) clearTimeout(timer);\n }\n}\n\nfunction errorSummary(err: unknown): string {\n if (err instanceof DaytonaError) {\n const status = err.statusCode;\n const cls = err.constructor.name;\n return `${cls}${typeof status === 'number' ? ` ${String(status)}` : ''}: ${truncate(err.message)}`;\n }\n if (err instanceof Error) {\n const code = (err as { code?: unknown }).code;\n return code !== undefined ? `${err.name}(${String(code)}): ${truncate(err.message)}` : `${err.name}: ${truncate(err.message)}`;\n }\n return truncate(String(err));\n}\n\nfunction truncate(s: string, max = 160): string {\n return s.length > max ? `${s.slice(0, max)}…` : s;\n}\n","import { spawnSync } from 'node:child_process';\nimport {\n chmodSync,\n existsSync,\n mkdirSync,\n readFileSync,\n renameSync,\n writeFileSync,\n} from 'node:fs';\nimport { homedir } from 'node:os';\nimport { dirname, resolve } from 'node:path';\nimport { confirm, isCancel, intro, log, note, outro, password, spinner, text } from '@clack/prompts';\nimport { ensureDaytonaEnvLoaded } from './env-loader.js';\n\nconst DASHBOARD_KEYS_URL = 'https://app.daytona.io/dashboard/keys';\n\n/**\n * Keys we manage in `~/.agentbox/secrets.env`. When the user reconfigures we\n * strip any prior values for these keys before appending the new ones so the\n * file never accumulates duplicates.\n */\nconst MANAGED_KEYS = ['DAYTONA_API_KEY', 'DAYTONA_JWT_TOKEN', 'DAYTONA_ORGANIZATION_ID'] as const;\ntype ManagedKey = (typeof MANAGED_KEYS)[number];\n\nexport interface EnsureDaytonaCredentialsOptions {\n /** Re-prompt even when valid credentials are already present (used by `agentbox daytona login`). */\n force?: boolean;\n}\n\n/**\n * First-run interactive setup for Daytona credentials. Walks the user through\n * opening the dashboard, pasting an API key (or JWT + organization ID), and\n * persists the result to `~/.agentbox/secrets.env` — which the env-loader\n * already picks up for every cloud command.\n *\n * No-op when credentials are already configured (env var or our secrets\n * file). Silent no-op when stdin isn't a TTY so scripted/CI callers get the\n * \"credentials not configured\" error from the SDK instead of a hung prompt.\n */\nexport async function ensureDaytonaCredentials(\n opts: EnsureDaytonaCredentialsOptions = {},\n): Promise<void> {\n ensureDaytonaEnvLoaded();\n\n if (!opts.force && hasUsableCredentials()) return;\n if (!process.stdin.isTTY) return;\n\n intro('Daytona setup');\n note(\n `AgentBox needs a Daytona API key to provision cloud boxes.\\n` +\n `Generate one at ${DASHBOARD_KEYS_URL}`,\n 'API key required',\n );\n\n const open = await confirm({\n message: `Open ${DASHBOARD_KEYS_URL} in your browser?`,\n initialValue: true,\n });\n if (isCancel(open)) {\n log.warn('Daytona setup cancelled — re-run `agentbox daytona login` when ready.');\n return;\n }\n if (open) openDashboard();\n\n // One retry on auth failure (typos are the common case). Beyond that we bail\n // and surface the validation error; the user can re-run `agentbox daytona login`.\n for (let attempt = 0; attempt < 2; attempt++) {\n const creds = await promptForCredentials();\n if (creds === null) return;\n\n const result = await validateCredentials(creds);\n if (result.ok) {\n persistCredentials(creds);\n log.success(`Daytona credentials saved to ${secretsPath()}`);\n outro('Setup complete.');\n return;\n }\n if (result.kind === 'auth' && attempt === 0) {\n log.error(`That key was rejected by Daytona: ${result.message}`);\n log.info('Try again, or press Ctrl-C to cancel.');\n continue;\n }\n if (result.kind === 'network') {\n log.warn(`Could not reach Daytona to validate (${result.message}) — saving anyway.`);\n persistCredentials(creds);\n log.success(`Daytona credentials saved to ${secretsPath()}`);\n outro('Setup complete (unvalidated).');\n return;\n }\n throw new Error(`Daytona credentials rejected: ${result.message}`);\n }\n}\n\nfunction hasUsableCredentials(): boolean {\n if (process.env.DAYTONA_API_KEY) return true;\n if (process.env.DAYTONA_JWT_TOKEN && process.env.DAYTONA_ORGANIZATION_ID) return true;\n return false;\n}\n\ninterface Credentials {\n apiKey?: string;\n jwtToken?: string;\n organizationId?: string;\n}\n\nasync function promptForCredentials(): Promise<Credentials | null> {\n const key = await password({\n message: 'Paste your Daytona API key (or JWT token)',\n validate(v) {\n if (!v || v.trim().length === 0) return 'Cannot be empty';\n return undefined;\n },\n });\n if (isCancel(key)) {\n log.warn('Daytona setup cancelled.');\n return null;\n }\n const trimmed = key.trim();\n\n // JWTs start with `eyJ` (base64-encoded `{\"`). API keys don't, and don't need\n // an org ID — the SDK derives it from the key. Only ask for org ID for JWTs.\n if (trimmed.startsWith('eyJ')) {\n const org = await text({\n message: 'Paste your Daytona organization ID',\n placeholder: 'org_...',\n validate(v) {\n if (!v || v.trim().length === 0) return 'Cannot be empty';\n return undefined;\n },\n });\n if (isCancel(org)) {\n log.warn('Daytona setup cancelled.');\n return null;\n }\n return { jwtToken: trimmed, organizationId: org.trim() };\n }\n\n return { apiKey: trimmed };\n}\n\ntype ValidationResult =\n | { ok: true }\n | { ok: false; kind: 'auth'; message: string }\n | { ok: false; kind: 'network'; message: string };\n\nasync function validateCredentials(creds: Credentials): Promise<ValidationResult> {\n const s = spinner();\n s.start('Validating credentials with Daytona');\n\n // Snapshot existing env so we can restore on failure — never poison\n // process.env with a bad key.\n const snapshot = snapshotManagedEnv();\n applyToEnv(creds);\n\n try {\n // Dynamic import so the SDK only loads when we actually need it (keeps the\n // Docker hot path lean, same reason as the provider registry).\n const { Daytona } = await import('@daytonaio/sdk');\n const client = new Daytona();\n await client.list();\n s.stop('Daytona credentials accepted');\n return { ok: true };\n } catch (err) {\n restoreManagedEnv(snapshot);\n const message = err instanceof Error ? err.message : String(err);\n s.stop('Daytona credentials check failed');\n if (/401|403|unauthor|forbidden|invalid/i.test(message)) {\n return { ok: false, kind: 'auth', message };\n }\n return { ok: false, kind: 'network', message };\n }\n}\n\nfunction snapshotManagedEnv(): Record<ManagedKey, string | undefined> {\n const out = {} as Record<ManagedKey, string | undefined>;\n for (const k of MANAGED_KEYS) out[k] = process.env[k];\n return out;\n}\n\nfunction restoreManagedEnv(snap: Record<ManagedKey, string | undefined>): void {\n for (const k of MANAGED_KEYS) {\n if (snap[k] === undefined) delete process.env[k];\n else process.env[k] = snap[k];\n }\n}\n\nfunction applyToEnv(creds: Credentials): void {\n // Wipe the other auth method so the SDK doesn't get confused by stale env\n // (e.g. an old JWT lingering from a previous shell export).\n for (const k of MANAGED_KEYS) delete process.env[k];\n if (creds.apiKey) process.env.DAYTONA_API_KEY = creds.apiKey;\n if (creds.jwtToken) process.env.DAYTONA_JWT_TOKEN = creds.jwtToken;\n if (creds.organizationId) process.env.DAYTONA_ORGANIZATION_ID = creds.organizationId;\n}\n\nfunction persistCredentials(creds: Credentials): void {\n applyToEnv(creds);\n const path = secretsPath();\n mkdirSync(dirname(path), { recursive: true });\n\n // Read existing file, strip any managed keys, append fresh values. Keeps\n // unrelated DAYTONA_API_URL / DAYTONA_TARGET (or anything else the user\n // dropped here) untouched.\n let existing = '';\n if (existsSync(path)) {\n try {\n existing = readFileSync(path, 'utf8');\n } catch {\n existing = '';\n }\n }\n\n const kept = existing\n .split(/\\r?\\n/)\n .filter((line) => {\n const stripped = line.startsWith('export ') ? line.slice('export '.length) : line;\n const eq = stripped.indexOf('=');\n if (eq <= 0) return true;\n const key = stripped.slice(0, eq).trim();\n return !(MANAGED_KEYS as readonly string[]).includes(key);\n })\n .join('\\n')\n .replace(/\\s+$/u, '');\n\n const lines: string[] = [];\n if (creds.apiKey) lines.push(`DAYTONA_API_KEY=${creds.apiKey}`);\n if (creds.jwtToken) lines.push(`DAYTONA_JWT_TOKEN=${creds.jwtToken}`);\n if (creds.organizationId) lines.push(`DAYTONA_ORGANIZATION_ID=${creds.organizationId}`);\n\n const body = (kept ? `${kept}\\n` : '') + lines.join('\\n') + '\\n';\n\n // Atomic write — rename(2) is atomic on the same filesystem, so partially\n // written secrets can't be left behind on a crash.\n const tmp = `${path}.tmp`;\n writeFileSync(tmp, body, { mode: 0o600 });\n try {\n chmodSync(tmp, 0o600);\n } catch {\n // chmod best-effort; writeFileSync mode already covers most filesystems.\n }\n renameSync(tmp, path);\n try {\n chmodSync(path, 0o600);\n } catch {\n // ignore — already attempted above\n }\n}\n\nfunction openDashboard(): void {\n try {\n const r = spawnSync('open', [DASHBOARD_KEYS_URL], { stdio: 'ignore' });\n if (r.status !== 0) {\n log.warn(`Could not auto-open the browser — visit ${DASHBOARD_KEYS_URL} manually.`);\n }\n } catch {\n log.warn(`Could not auto-open the browser — visit ${DASHBOARD_KEYS_URL} manually.`);\n }\n}\n\nexport function secretsPath(): string {\n return resolve(homedir(), '.agentbox', 'secrets.env');\n}\n\n/** What's currently configured. Used by `daytona login --status`. */\nexport interface DaytonaCredStatus {\n apiKey?: string;\n jwtToken?: string;\n organizationId?: string;\n source: 'env' | 'secrets.env' | 'none';\n}\n\nexport function readDaytonaCredStatus(): DaytonaCredStatus {\n // Snapshot what the shell already had before the loader runs so we can\n // distinguish env-from-shell from env-loaded-from-secrets.env.\n const shellHadKey = !!process.env.DAYTONA_API_KEY || !!process.env.DAYTONA_JWT_TOKEN;\n ensureDaytonaEnvLoaded();\n const apiKey = process.env.DAYTONA_API_KEY;\n const jwtToken = process.env.DAYTONA_JWT_TOKEN;\n const organizationId = process.env.DAYTONA_ORGANIZATION_ID;\n if (!apiKey && !jwtToken) return { source: 'none' };\n return {\n apiKey,\n jwtToken,\n organizationId,\n source: shellHadKey ? 'env' : 'secrets.env',\n };\n}\n\nexport function maskKey(value: string): string {\n if (value.length <= 8) return '*'.repeat(value.length);\n return `${value.slice(0, 4)}…${'*'.repeat(8)}${value.slice(-4)}`;\n}\n"],"mappings":";;;AAAA,SAAS,kBAAkB;AAC3B,SAAS,SAAS,eAAe;AACjC,SAAS,qBAAqB;ACF9B,SAAS,cAAAA,aAAY,oBAAoB;AACzC,SAAS,eAAe;AACxB,SAAS,WAAAC,gBAAe;ACIxB,SAAS,SAAS,wBAAAC,uBAAsB,OAAO,oBAAkC;ACMjF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;OACK;ACtBP,SAAS,iBAAiB;AAC1B;EACE;EACA,cAAAF;EACA;EACA,gBAAAG;EACA;EACA;OACK;AACP,SAAS,WAAAC,gBAAe;AACxB,SAAS,WAAAC,UAAS,WAAAJ,gBAAe;AACjC,SAAS,SAAS,UAAU,OAAO,KAAK,MAAM,OAAO,UAAU,SAAS,YAAY;AJe7E,SAAS,2BAAqD;AACnE,QAAM,WAAW,QAAQ,IAAI;AAC7B,MAAI,YAAY,WAAW,QAAQ,UAAU,gBAAgB,CAAC,GAAG;AAC/D,WAAO,EAAE,YAAY,QAAQ,UAAU,gBAAgB,GAAG,SAAS,SAAS;EAC9E;AACA,QAAM,OAAO,QAAQ,cAAc,YAAY,GAAG,CAAC;AACnD,QAAM,SAAS,QAAQ,MAAM,MAAM,WAAW,QAAQ;AACtD,MAAI,WAAW,QAAQ,QAAQ,gBAAgB,CAAC,GAAG;AACjD,WAAO,EAAE,YAAY,QAAQ,QAAQ,gBAAgB,GAAG,SAAS,OAAO;EAC1E;AAIA,QAAM,eAAe,QAAQ,MAAM,MAAM,MAAM,IAAI;AACnD,QAAM,aAAa,QAAQ,cAAc,YAAY,kBAAkB,gBAAgB;AACvF,MAAI,WAAW,UAAU,GAAG;AAC1B,WAAO,EAAE,YAAY,SAAS,aAAa;EAC7C;AACA,SAAO;AACT;AAUO,SAAS,+BAA8C;AAC5D,QAAM,OAAO,QAAQ,cAAc,YAAY,GAAG,CAAC;AACnD,QAAM,SAAS,QAAQ,MAAM,MAAM,WAAW,WAAW,yBAAyB;AAClF,MAAI,WAAW,MAAM,EAAG,QAAO;AAC/B,QAAM,eAAe,QAAQ,MAAM,MAAM,MAAM,IAAI;AACnD,QAAM,MAAM;IACV;IACA;IACA;IACA;IACA;EACF;AACA,MAAI,WAAW,GAAG,EAAG,QAAO;AAC5B,SAAO;AACT;AC/CA,IAAM,eAAe;EACnB;EACA;EACA;EACA;EACA;AACF;AAEA,IAAI,SAAS;AAEN,SAAS,yBAA+B;AAC7C,MAAI,OAAQ;AACZ,WAAS;AACT,wBAAsBA,SAAQ,QAAQ,GAAG,aAAa,aAAa,CAAC;AACtE;AAEA,SAAS,sBAAsB,MAAoB;AACjD,MAAI,CAACD,YAAW,IAAI,EAAG;AACvB,MAAI;AACJ,MAAI;AACF,WAAO,aAAa,MAAM,MAAM;EAClC,QAAQ;AACN;EACF;AACA,QAAM,SAAS,aAAa,IAAI;AAChC,aAAW,OAAO,cAAc;AAC9B,QAAI,QAAQ,IAAI,GAAG,MAAM,OAAW;AACpC,UAAM,QAAQ,OAAO,GAAG;AACxB,QAAI,OAAO,UAAU,UAAU;AAC7B,cAAQ,IAAI,GAAG,IAAI;IACrB;EACF;AACF;AASO,SAAS,aAAa,MAAsC;AACjE,QAAM,MAA8B,CAAC;AACrC,aAAW,WAAW,KAAK,MAAM,OAAO,GAAG;AACzC,UAAM,OAAO,QAAQ,KAAK;AAC1B,QAAI,KAAK,WAAW,KAAK,KAAK,WAAW,GAAG,EAAG;AAC/C,UAAM,WAAW,KAAK,WAAW,SAAS,IAAI,KAAK,MAAM,UAAU,MAAM,IAAI;AAC7E,UAAM,KAAK,SAAS,QAAQ,GAAG;AAC/B,QAAI,MAAM,EAAG;AACb,UAAM,MAAM,SAAS,MAAM,GAAG,EAAE,EAAE,KAAK;AACvC,QAAI,QAAQ,SAAS,MAAM,KAAK,CAAC,EAAE,KAAK;AAExC,QACE,MAAM,UAAU,MACd,MAAM,WAAW,GAAG,KAAK,MAAM,SAAS,GAAG,KAC1C,MAAM,WAAW,GAAG,KAAK,MAAM,SAAS,GAAG,IAC9C;AACA,cAAQ,MAAM,MAAM,GAAG,EAAE;IAC3B;AACA,QAAI,GAAG,IAAI;EACb;AACA,SAAO;AACT;AEzCA,IAAM,kBAAqC,CAAC,KAAM,KAAM,GAAI;AAC5D,IAAM,6BAA6B;AAGnC,IAAM,sBAAN,cAAkC,MAAM;EACtC,YAAY,QAAgB,IAAY;AACtC,UAAM,WAAW,MAAM,+BAA+B,OAAO,EAAE,CAAC,IAAI;AACpE,SAAK,OAAO;EACd;AACF;AAWO,SAAS,YAAY,KAAc,gBAAkC;AAE1E,MAAI,eAAe,sBAAuB,QAAO;AAIjD,MACE,eAAe,wBACf,eAAe,8BACf,eAAe,6BACf,eAAe,0BACf,eAAe,sBACf;AACA,WAAO;EACT;AAKA,MACE,eAAe,0BACf,eAAe,uBACf,eAAe,qBACf;AACA,WAAO;EACT;AAIA,MAAI,eAAe,cAAc;AAC/B,UAAM,SAAS,IAAI;AACnB,QAAI,OAAO,WAAW,YAAY,UAAU,OAAO,UAAU,KAAK;AAChE,aAAO;IACT;AACA,WAAO;EACT;AAIA,MAAI,OAAO,OAAO,QAAQ,UAAU;AAClC,UAAM,OAAQ,IAA2B;AACzC,QACE,SAAS,gBACT,SAAS,eACT,SAAS,kBACT,SAAS,eACT,SAAS,kBACT,SAAS,aACT;AACA,aAAO;IACT;AACA,UAAM,SACH,IAA4C,UAAU,UACtD,IAA6B,UAC7B,IAAiC;AACpC,QAAI,OAAO,WAAW,YAAY,UAAU,OAAO,UAAU,KAAK;AAChE,aAAO;IACT;EACF;AAEA,SAAO;AACT;AAOA,eAAsB,iBACpB,MACA,IACY;AACZ,QAAM,UAAU,KAAK,aAAa;AAClC,QAAM,cAAc,QAAQ,SAAS;AACrC,QAAM,YAAY,KAAK,oBAAoB;AAC3C,QAAMM,OAAM,KAAK,WAAW;AAE5B,WAAS,UAAU,GAAG,WAAW,aAAa,WAAW;AACvD,QAAI;AACF,aAAO,MAAM,YAAY,GAAG,GAAG,WAAW,KAAK,MAAM;IACvD,SAAS,KAAK;AACZ,YAAM,OAAO,YAAY;AACzB,UAAI,QAAQ,CAAC,YAAY,KAAK,KAAK,gBAAgB,EAAG,OAAM;AAC5D,YAAM,QAAQ,QAAQ,UAAU,CAAC,KAAK,QAAQ,QAAQ,SAAS,CAAC,KAAK;AACrEA;QACE,WAAW,KAAK,MAAM,aAAa,OAAO,OAAO,CAAC,YAAY,aAAa,GAAG,CAAC,kBAAkB,OAAO,KAAK,CAAC;MAChH;AACA,YAAM,MAAM,KAAK;IACnB;EACF;AAEA,QAAM,IAAI,MAAM,4CAA4C,KAAK,MAAM,EAAE;AAC3E;AAEA,SAAS,gBAAgB,MAAoB;AAK3C,UAAQ,OAAO,MAAM;kBAAqB,IAAI;CAAI;AACpD;AAEA,SAAS,MAAM,IAA2B;AACxC,SAAO,IAAI,QAAQ,CAACL,aAAY,WAAWA,UAAS,EAAE,CAAC;AACzD;AAEA,eAAe,YAAe,GAAe,IAAY,QAA4B;AACnF,MAAI;AACJ,MAAI;AACF,WAAO,MAAM,QAAQ,KAAK;MACxB;MACA,IAAI,QAAe,CAAC,UAAU,WAAW;AACvC,gBAAQ,WAAW,MAAM,OAAO,IAAI,oBAAoB,QAAQ,EAAE,CAAC,GAAG,EAAE;MAC1E,CAAC;IACH,CAAC;EACH,UAAA;AACE,QAAI,UAAU,OAAW,cAAa,KAAK;EAC7C;AACF;AAEA,SAAS,aAAa,KAAsB;AAC1C,MAAI,eAAe,cAAc;AAC/B,UAAM,SAAS,IAAI;AACnB,UAAM,MAAM,IAAI,YAAY;AAC5B,WAAO,GAAG,GAAG,GAAG,OAAO,WAAW,WAAW,IAAI,OAAO,MAAM,CAAC,KAAK,EAAE,KAAK,SAAS,IAAI,OAAO,CAAC;EAClG;AACA,MAAI,eAAe,OAAO;AACxB,UAAM,OAAQ,IAA2B;AACzC,WAAO,SAAS,SAAY,GAAG,IAAI,IAAI,IAAI,OAAO,IAAI,CAAC,MAAM,SAAS,IAAI,OAAO,CAAC,KAAK,GAAG,IAAI,IAAI,KAAK,SAAS,IAAI,OAAO,CAAC;EAC9H;AACA,SAAO,SAAS,OAAO,GAAG,CAAC;AAC7B;AAEA,SAAS,SAAS,GAAW,MAAM,KAAa;AAC9C,SAAO,EAAE,SAAS,MAAM,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC,WAAM;AAClD;AD3KA,SAAS,MACP,QACA,IACA,OAKI,CAAC,GACO;AACZ,SAAO;IACL;MACE;MACA,kBAAkB,KAAK,oBAAoB;MAC3C,kBAAkB,KAAK;MACvB,WAAW,KAAK,YAAY,OAAO,CAAC,IAAI;IAC1C;IACA;EACF;AACF;AAOO,IAAM,wBAAwB;AAErC,IAAI,SAAyB;AACtB,SAAS,YAAqB;AACnC,MAAI,CAAC,QAAQ;AAIX,2BAAuB;AACvB,QAAI;AAGF,eAAS,IAAI,QAAQ;IACvB,SAAS,KAAK;AACZ,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAI3D,YAAM,IAAI;QACR,uCAAuC,GAAG;;MAE5C;IACF;EACF;AACA,SAAO;AACT;AAEA,eAAe,WAAW,IAA8B;AACtD,SAAO,UAAU,EAAE,IAAI,EAAE;AAC3B;AAEA,eAAe,gBAAgB,IAAqC;AAClE,MAAI;AACF,WAAO,MAAM,UAAU,EAAE,IAAI,EAAE;EACjC,QAAQ;AACN,WAAO;EACT;AACF;AAQA,SAAS,SAAS,GAAkD;AAClE,UAAQ,GAAG;IACT,KAAK,aAAa;AAChB,aAAO;IACT,KAAK,aAAa;IAClB,KAAK,aAAa;IAClB,KAAK,aAAa;IAClB,KAAK,aAAa;IAClB,KAAK,aAAa;IAClB,KAAK,aAAa;IAClB,KAAK,aAAa;AAChB,aAAO;IACT,KAAK,aAAa;AAChB,aAAO;IACT,KAAK,aAAa;IAClB,KAAK,aAAa;AAChB,aAAO;IACT,KAAK,aAAa;IAClB,KAAK,aAAa;IAClB,KAAK,aAAa;IAClB,KAAK,aAAa;IAClB,KAAK,aAAa;IAClB;AACE,aAAO;EACX;AACF;AAOA,SAAS,qBAAqB,GAI5B;AACA,SAAO;IACL,UAAU,EAAE;IACZ,WAAW,EAAE;IACb,GAAI,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,IAAI,CAAC;EAC5C;AACF;AAGA,SAAS,aAAa,KAA6B;AACjD,MAAI,QAAQ,sBAAuB,QAAO;AAC1C,QAAM,MAAM,yBAAyB;AACrC,MAAI,CAAC,KAAK;AACR,UAAM,IAAI;MACR;IAEF;EACF;AAKA,SAAO,MAAM,eAAe,IAAI,UAAU;AAC5C;AAEO,IAAM,iBAA+B;EAC1C,MAAM;EAEN,MAAM,UAAU,KAAkD;AAKhE,WAAO;MACL;MACA,YAAY;AAQV,cAAM,aAAa;UACjB,GAAI,IAAI,YAAY,EAAE,WAAW,IAAI,UAAU,IAAI,CAAC;UACpD,SAAS,IAAI;UACb,GAAI,IAAI,WAAW,IAAI,QAAQ,SAAS,IACpC,EAAE,SAAS,IAAI,QAAQ,IAAI,oBAAoB,EAAE,IACjD,CAAC;UACL,QAAQ,EAAE,iBAAiB,IAAI,KAAK;QACtC;AACA,cAAMM,UAAS,UAAU;AAczB,YAAI,eAAe,IAAI;AACvB,YAAI,CAAC,gBAAgB,IAAI,SAAS,IAAI,UAAU,uBAAuB;AACrE,cAAI;AACF,kBAAM,OAAO,MAAMA,QAAO,SAAS,IAAI,IAAI,KAAK;AAChD,gBAAI,QAAQ,KAAK,KAAM,gBAAe,KAAK;UAC7C,QAAQ;UAER;QACF;AAIA,cAAM,iBAA0C,EAAE,GAAG,WAAW;AAChE,eAAO,eAAe;AACtB,cAAM,UAAU,eACZ,MAAMA,QAAO,OAAO,EAAE,UAAU,cAAc,GAAG,eAAe,GAAG,EAAE,SAAS,IAAI,CAAC,IACnF,MAAMA,QAAO;UACX,EAAE,OAAO,aAAa,IAAI,KAAK,GAAG,GAAG,WAAW;UAChD;YACE,SAAS;YACT,GAAI,IAAI,QAAQ,EAAE,sBAAsB,IAAI,MAAM,IAAI,CAAC;UACzD;QACF;AACJ,eAAO,EAAE,WAAW,QAAQ,GAAG;MACjC;MACA,EAAE,kBAAkB,OAAO,kBAAkB,IAAQ;IACvD;EACF;EAEA,MAAM,aAAa,MAA6C;AAc9D,UAAMA,UAAS,UAAU;AACzB,QAAI,MAAM,MAAM,MAAM,sBAAsB,MAAMA,QAAO,OAAO,IAAI,MAAM,IAAI,CAAC;AAG/E,UAAM,WAAW,KAAK,IAAI,IAAI;AAC9B,WAAO,IAAI,UAAU,SAAS;AAC5B,UAAI,IAAI,UAAU,WAAW,IAAI,UAAU,aAAa,IAAI,UAAU,YAAY;AAChF,cAAM,IAAI;UACR,mBAAmB,IAAI,gCAAgC,IAAI,KAAK;QAElE;MACF;AACA,UAAI,KAAK,IAAI,KAAK,UAAU;AAC1B,cAAM,IAAI;UACR,mBAAmB,IAAI,6CAA6C,IAAI,KAAK;QAE/E;MACF;AACA,YAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,GAAI,CAAC;AAC5C,YAAM,MAAM,MAAM,oBAAoB,MAAMA,QAAO,OAAO,IAAI,IAAI,CAAC;IACrE;AACA,WAAO,EAAE,UAAU,IAAI,GAAG;EAC5B;EAEA,MAAM,IAAI,WAAgD;AACxD,WAAO,MAAM,OAAO,YAAY;AAC9B,YAAM,KAAK,MAAM,gBAAgB,SAAS;AAC1C,aAAO,KAAK,EAAE,WAAW,GAAG,GAAG,IAAI;IACrC,CAAC;EACH;EAEA,MAAM,OAAuC;AAC3C,WAAO,MAAM,QAAQ,YAAY;AAC/B,YAAMA,UAAS,UAAU;AAIzB,YAAM,OAAO,MAAMA,QAAO,KAAK;AAC/B,YAAM,QAAQ,MAAM,QAAQ,IAAI,IAAI,OAAQ,KAAK,SAAS,CAAC;AAC3D,aAAO,MAAM,IAAI,CAAC,OAA4B;AAC5C,cAAM,UAA+B,EAAE,WAAW,GAAG,GAAG;AACxD,cAAM,MAAM;AAMZ,cAAM,WAAW,IAAI,SAAS,eAAe,KAAK,IAAI;AACtD,YAAI,SAAU,SAAQ,OAAO;AAC7B,YAAI,IAAI,UAAW,SAAQ,YAAY,IAAI;AAC3C,YAAI,OAAO,IAAI,UAAU,SAAU,SAAQ,QAAQ,SAAS,IAAI,KAAK;AACrE,eAAO;MACT,CAAC;IACH,CAAC;EACH;EAEA,MAAM,MAAM,GAA+B;AACzC,WAAO;MACL;MACA,YAAY;AACV,cAAM,KAAK,MAAM,WAAW,EAAE,SAAS;AACvC,cAAM,GAAG,MAAM;MACjB;MACA,EAAE,kBAAkB,IAAO;IAC7B;EACF;EAEA,MAAM,KAAK,GAA+B;AACxC,WAAO;MACL;MACA,YAAY;AACV,cAAM,KAAK,MAAM,WAAW,EAAE,SAAS;AACvC,cAAM,GAAG,KAAK;MAChB;MACA,EAAE,kBAAkB,IAAO;IAC7B;EACF;EAEA,MAAM,MAAM,GAA+B;AAGzC,WAAO;MACL;MACA,YAAY;AACV,cAAM,KAAK,MAAM,WAAW,EAAE,SAAS;AACvC,cAAM,GAAG,QAAQ;MACnB;MACA,EAAE,kBAAkB,IAAO;IAC7B;EACF;EAEA,MAAM,OAAO,GAA+B;AAC1C,WAAO;MACL;MACA,YAAY;AACV,cAAM,KAAK,MAAM,WAAW,EAAE,SAAS;AACvC,cAAM,GAAG,MAAM;MACjB;MACA,EAAE,kBAAkB,IAAO;IAC7B;EACF;EAEA,MAAM,QAAQ,GAA+B;AAC3C,WAAO;MACL;MACA,YAAY;AACV,cAAM,KAAK,MAAM,gBAAgB,EAAE,SAAS;AAC5C,YAAI,CAAC,GAAI;AAOT,YAAI;AACF,gBAAM,GAAG,KAAK,EAAE;QAClB,QAAQ;QAER;AACA,YAAI;AACF,gBAAM,GAAG,OAAO,EAAE;QACpB,SAAS,KAAK;AACZ,gBAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAE3D,cAAI,CAAC,aAAa,KAAK,GAAG,EAAG,OAAM;QACrC;MACF;MACA,EAAE,kBAAkB,KAAQ;IAC9B;EACF;EAEA,MAAM,MAAM,GAAqC;AAC/C,WAAO,MAAM,SAAS,YAAY;AAChC,YAAM,KAAK,MAAM,gBAAgB,EAAE,SAAS;AAC5C,UAAI,CAAC,GAAI,QAAO;AAChB,aAAO,SAAS,GAAG,KAAK;IAC1B,CAAC;EACH;EAEA,MAAM,KACJ,GACA,KACA,MAC0B;AAC1B,WAAO;MACL;MACA,YAAY;AACV,cAAM,KAAK,MAAM,WAAW,EAAE,SAAS;AAIvC,cAAM,IAAI,MAAM,GAAG,QAAQ,eAAe,KAAK,MAAM,KAAK,MAAM,GAAG;AACnE,eAAO,EAAE,UAAU,EAAE,UAAU,QAAQ,EAAE,QAAQ,QAAQ,GAAG;MAC9D;MACA,EAAE,kBAAkB,MAAM,oBAAoB,MAAS,SAAS,MAAM,QAAQ;IAChF;EACF;EAEA,MAAM,WAAW,GAAgB,WAAmB,YAAmC;AACrF,WAAO;MACL;MACA,YAAY;AACV,cAAM,KAAK,MAAM,WAAW,EAAE,SAAS;AACvC,cAAM,GAAG,GAAG,WAAW,WAAW,UAAU;MAC9C;MACA,EAAE,kBAAkB,IAAQ;IAC9B;EACF;EAEA,MAAM,aAAa,GAAgB,YAAoB,WAAkC;AACvF,WAAO;MACL;MACA,YAAY;AACV,cAAM,KAAK,MAAM,WAAW,EAAE,SAAS;AACvC,cAAM,GAAG,GAAG,aAAa,YAAY,SAAS;MAChD;MACA,EAAE,kBAAkB,IAAQ;IAC9B;EACF;EAEA,MAAM,UAAU,GAAgB,WAA8C;AAC5E,WAAO,MAAM,aAAa,YAAY;AACpC,YAAM,KAAK,MAAM,WAAW,EAAE,SAAS;AACvC,YAAM,QAAQ,MAAM,GAAG,GAAG,UAAU,SAAS;AAC7C,aAAO,MAAM,IAAI,CAAC,OAAO;QACvB,MAAM,EAAE;QACR,OAAO,QAAS,EAA0B,KAAK;MACjD,EAAE;IACJ,CAAC;EACH;EAEA,MAAM,WAAW,GAAgB,MAAwC;AACvE,WAAO,MAAM,cAAc,YAAY;AACrC,YAAM,KAAK,MAAM,WAAW,EAAE,SAAS;AACvC,YAAM,IAAI,MAAM,GAAG,eAAe,IAAI;AAItC,aAAO,EAAE,KAAK,EAAE,KAAK,OAAO,EAAE,MAAM;IACtC,CAAC;EACH;EAEA,MAAM,iBACJ,GACA,MACA,kBAC0B;AAC1B,WAAO,MAAM,oBAAoB,YAAY;AAC3C,YAAM,KAAK,MAAM,WAAW,EAAE,SAAS;AACvC,YAAM,IAAI,MAAM,GAAG,oBAAoB,MAAM,gBAAgB;AAC7D,aAAO,EAAE,KAAK,EAAE,KAAK,OAAO,EAAE,MAAM;IACtC,CAAC;EACH;EAEA,MAAM,WAAW,GAAmC;AAClD,WAAO,MAAM,cAAc,YAAY;AACrC,YAAM,KAAK,MAAM,WAAW,EAAE,SAAS;AAIvC,YAAM,MAAM,MAAM,GAAG,gBAAgB,EAAE;AACvC,aAAO;QACL;;;QAGA;QAAM;;QAEN,GAAG,IAAI,KAAK;MACd;IACF,CAAC;EACH;EAEA,MAAM,kBAAkB,GAAgB,MAA+B;AAErE,UAAM,WAAW,KAAK,KAAK,SAAS,CAAC,KAAK;AAC1C,UAAM,QAAQ,SAAS,QAAQ,GAAG;AAClC,QAAI,SAAS,EAAG;AAChB,UAAM,QAAQ,SAAS,MAAM,GAAG,KAAK;AACrC,QAAI,MAAM,WAAW,EAAG;AACxB,QAAI;AACF,YAAM,MAAM,qBAAqB,YAAY;AAC3C,cAAM,KAAK,MAAM,WAAW,EAAE,SAAS;AACvC,cAAM,GAAG,gBAAgB,KAAK;MAChC,CAAC;IACH,QAAQ;IAER;EACF;EAEA,MAAM,eAAe,GAAgB,cAAqC;AAWxE,WAAO;MACL;MACA,YAAY;AACV,cAAM,KAAK,MAAM,WAAW,EAAE,SAAS;AACvC,cAAM,GAAG,6BAA6B,YAAY;MACpD;MACA,EAAE,kBAAkB,KAAS,kBAAkB,MAAM;IACvD;EACF;EAEA,MAAM,eAAe,cAAqC;AACxD,WAAO,MAAM,kBAAkB,YAAY;AACzC,UAAI;AACF,cAAMA,UAAS,UAAU;AACzB,cAAM,WAAW,MAAMA,QAAO,SAAS,IAAI,YAAY;AACvD,cAAMA,QAAO,SAAS,OAAO,QAAQ;MACvC,SAAS,KAAK;AAGZ,YAAI,eAAeL,sBAAsB;AACzC,cAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,YAAI,aAAa,KAAK,GAAG,EAAG;AAC5B,cAAM;MACR;IACF,CAAC;EACH;AACF;AElgBA,IAAM,qBAAqB;AAO3B,IAAM,eAAe,CAAC,mBAAmB,qBAAqB,yBAAyB;AAkBvF,eAAsB,yBACpB,OAAwC,CAAC,GAC1B;AACf,yBAAuB;AAEvB,MAAI,CAAC,KAAK,SAAS,qBAAqB,EAAG;AAC3C,MAAI,CAAC,QAAQ,MAAM,MAAO;AAE1B,QAAM,eAAe;AACrB;IACE;kBACqB,kBAAkB;IACvC;EACF;AAEA,QAAM,OAAO,MAAM,QAAQ;IACzB,SAAS,QAAQ,kBAAkB;IACnC,cAAc;EAChB,CAAC;AACD,MAAI,SAAS,IAAI,GAAG;AAClB,QAAI,KAAK,4EAAuE;AAChF;EACF;AACA,MAAI,KAAM,eAAc;AAIxB,WAAS,UAAU,GAAG,UAAU,GAAG,WAAW;AAC5C,UAAM,QAAQ,MAAM,qBAAqB;AACzC,QAAI,UAAU,KAAM;AAEpB,UAAM,SAAS,MAAM,oBAAoB,KAAK;AAC9C,QAAI,OAAO,IAAI;AACb,yBAAmB,KAAK;AACxB,UAAI,QAAQ,gCAAgC,YAAY,CAAC,EAAE;AAC3D,YAAM,iBAAiB;AACvB;IACF;AACA,QAAI,OAAO,SAAS,UAAU,YAAY,GAAG;AAC3C,UAAI,MAAM,qCAAqC,OAAO,OAAO,EAAE;AAC/D,UAAI,KAAK,uCAAuC;AAChD;IACF;AACA,QAAI,OAAO,SAAS,WAAW;AAC7B,UAAI,KAAK,wCAAwC,OAAO,OAAO,yBAAoB;AACnF,yBAAmB,KAAK;AACxB,UAAI,QAAQ,gCAAgC,YAAY,CAAC,EAAE;AAC3D,YAAM,+BAA+B;AACrC;IACF;AACA,UAAM,IAAI,MAAM,iCAAiC,OAAO,OAAO,EAAE;EACnE;AACF;AAEA,SAAS,uBAAgC;AACvC,MAAI,QAAQ,IAAI,gBAAiB,QAAO;AACxC,MAAI,QAAQ,IAAI,qBAAqB,QAAQ,IAAI,wBAAyB,QAAO;AACjF,SAAO;AACT;AAQA,eAAe,uBAAoD;AACjE,QAAM,MAAM,MAAM,SAAS;IACzB,SAAS;IACT,SAAS,GAAG;AACV,UAAI,CAAC,KAAK,EAAE,KAAK,EAAE,WAAW,EAAG,QAAO;AACxC,aAAO;IACT;EACF,CAAC;AACD,MAAI,SAAS,GAAG,GAAG;AACjB,QAAI,KAAK,0BAA0B;AACnC,WAAO;EACT;AACA,QAAM,UAAU,IAAI,KAAK;AAIzB,MAAI,QAAQ,WAAW,KAAK,GAAG;AAC7B,UAAM,MAAM,MAAM,KAAK;MACrB,SAAS;MACT,aAAa;MACb,SAAS,GAAG;AACV,YAAI,CAAC,KAAK,EAAE,KAAK,EAAE,WAAW,EAAG,QAAO;AACxC,eAAO;MACT;IACF,CAAC;AACD,QAAI,SAAS,GAAG,GAAG;AACjB,UAAI,KAAK,0BAA0B;AACnC,aAAO;IACT;AACA,WAAO,EAAE,UAAU,SAAS,gBAAgB,IAAI,KAAK,EAAE;EACzD;AAEA,SAAO,EAAE,QAAQ,QAAQ;AAC3B;AAOA,eAAe,oBAAoB,OAA+C;AAChF,QAAM,IAAI,QAAQ;AAClB,IAAE,MAAM,qCAAqC;AAI7C,QAAM,WAAW,mBAAmB;AACpC,aAAW,KAAK;AAEhB,MAAI;AAGF,UAAM,EAAE,SAAAM,SAAQ,IAAI,MAAM,OAAO,gBAAgB;AACjD,UAAMD,UAAS,IAAIC,SAAQ;AAC3B,UAAMD,QAAO,KAAK;AAClB,MAAE,KAAK,8BAA8B;AACrC,WAAO,EAAE,IAAI,KAAK;EACpB,SAAS,KAAK;AACZ,sBAAkB,QAAQ;AAC1B,UAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,MAAE,KAAK,kCAAkC;AACzC,QAAI,sCAAsC,KAAK,OAAO,GAAG;AACvD,aAAO,EAAE,IAAI,OAAO,MAAM,QAAQ,QAAQ;IAC5C;AACA,WAAO,EAAE,IAAI,OAAO,MAAM,WAAW,QAAQ;EAC/C;AACF;AAEA,SAAS,qBAA6D;AACpE,QAAM,MAAM,CAAC;AACb,aAAW,KAAK,aAAc,KAAI,CAAC,IAAI,QAAQ,IAAI,CAAC;AACpD,SAAO;AACT;AAEA,SAAS,kBAAkB,MAAoD;AAC7E,aAAW,KAAK,cAAc;AAC5B,QAAI,KAAK,CAAC,MAAM,OAAW,QAAO,QAAQ,IAAI,CAAC;QAC1C,SAAQ,IAAI,CAAC,IAAI,KAAK,CAAC;EAC9B;AACF;AAEA,SAAS,WAAW,OAA0B;AAG5C,aAAW,KAAK,aAAc,QAAO,QAAQ,IAAI,CAAC;AAClD,MAAI,MAAM,OAAQ,SAAQ,IAAI,kBAAkB,MAAM;AACtD,MAAI,MAAM,SAAU,SAAQ,IAAI,oBAAoB,MAAM;AAC1D,MAAI,MAAM,eAAgB,SAAQ,IAAI,0BAA0B,MAAM;AACxE;AAEA,SAAS,mBAAmB,OAA0B;AACpD,aAAW,KAAK;AAChB,QAAM,OAAO,YAAY;AACzB,YAAUF,SAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAK5C,MAAI,WAAW;AACf,MAAIL,YAAW,IAAI,GAAG;AACpB,QAAI;AACF,iBAAWG,cAAa,MAAM,MAAM;IACtC,QAAQ;AACN,iBAAW;IACb;EACF;AAEA,QAAM,OAAO,SACV,MAAM,OAAO,EACb,OAAO,CAAC,SAAS;AAChB,UAAM,WAAW,KAAK,WAAW,SAAS,IAAI,KAAK,MAAM,UAAU,MAAM,IAAI;AAC7E,UAAM,KAAK,SAAS,QAAQ,GAAG;AAC/B,QAAI,MAAM,EAAG,QAAO;AACpB,UAAM,MAAM,SAAS,MAAM,GAAG,EAAE,EAAE,KAAK;AACvC,WAAO,CAAE,aAAmC,SAAS,GAAG;EAC1D,CAAC,EACA,KAAK,IAAI,EACT,QAAQ,SAAS,EAAE;AAEtB,QAAM,QAAkB,CAAC;AACzB,MAAI,MAAM,OAAQ,OAAM,KAAK,mBAAmB,MAAM,MAAM,EAAE;AAC9D,MAAI,MAAM,SAAU,OAAM,KAAK,qBAAqB,MAAM,QAAQ,EAAE;AACpE,MAAI,MAAM,eAAgB,OAAM,KAAK,2BAA2B,MAAM,cAAc,EAAE;AAEtF,QAAM,QAAQ,OAAO,GAAG,IAAI;IAAO,MAAM,MAAM,KAAK,IAAI,IAAI;AAI5D,QAAM,MAAM,GAAG,IAAI;AACnB,gBAAc,KAAK,MAAM,EAAE,MAAM,IAAM,CAAC;AACxC,MAAI;AACF,cAAU,KAAK,GAAK;EACtB,QAAQ;EAER;AACA,aAAW,KAAK,IAAI;AACpB,MAAI;AACF,cAAU,MAAM,GAAK;EACvB,QAAQ;EAER;AACF;AAEA,SAAS,gBAAsB;AAC7B,MAAI;AACF,UAAM,IAAI,UAAU,QAAQ,CAAC,kBAAkB,GAAG,EAAE,OAAO,SAAS,CAAC;AACrE,QAAI,EAAE,WAAW,GAAG;AAClB,UAAI,KAAK,gDAA2C,kBAAkB,YAAY;IACpF;EACF,QAAQ;AACN,QAAI,KAAK,gDAA2C,kBAAkB,YAAY;EACpF;AACF;AAEO,SAAS,cAAsB;AACpC,SAAOF,SAAQG,SAAQ,GAAG,aAAa,aAAa;AACtD;AAUO,SAAS,wBAA2C;AAGzD,QAAM,cAAc,CAAC,CAAC,QAAQ,IAAI,mBAAmB,CAAC,CAAC,QAAQ,IAAI;AACnE,yBAAuB;AACvB,QAAM,SAAS,QAAQ,IAAI;AAC3B,QAAM,WAAW,QAAQ,IAAI;AAC7B,QAAM,iBAAiB,QAAQ,IAAI;AACnC,MAAI,CAAC,UAAU,CAAC,SAAU,QAAO,EAAE,QAAQ,OAAO;AAClD,SAAO;IACL;IACA;IACA;IACA,QAAQ,cAAc,QAAQ;EAChC;AACF;AAEO,SAAS,QAAQ,OAAuB;AAC7C,MAAI,MAAM,UAAU,EAAG,QAAO,IAAI,OAAO,MAAM,MAAM;AACrD,SAAO,GAAG,MAAM,MAAM,GAAG,CAAC,CAAC,SAAI,IAAI,OAAO,CAAC,CAAC,GAAG,MAAM,MAAM,EAAE,CAAC;AAChE;","names":["existsSync","resolve","DaytonaNotFoundError","readFileSync","homedir","dirname","log","client","Daytona"]}
@@ -2,9 +2,9 @@
2
2
  import {
3
3
  CloudBoxPoller,
4
4
  CloudBoxPollers
5
- } from "./chunk-UK72UQ5U.js";
5
+ } from "./chunk-G3H2L3O2.js";
6
6
  export {
7
7
  CloudBoxPoller,
8
8
  CloudBoxPollers
9
9
  };
10
- //# sourceMappingURL=cloud-poller-ZIWSADJB-JXFRJUEM.js.map
10
+ //# sourceMappingURL=cloud-poller-SUNA6ZQC-2RG5WPRN.js.map
@@ -5,21 +5,86 @@ import {
5
5
  ensureDaytonaCredentials,
6
6
  ensureDaytonaEnvLoaded,
7
7
  getClient,
8
+ resolveDaytonaCustomClaudeMd,
8
9
  resolveDockerfileContext
9
- } from "./chunk-V5KZGB5V.js";
10
+ } from "./chunk-LEV3KICD.js";
10
11
  import {
11
12
  createCloudProvider
12
- } from "./chunk-NW5NYTQM.js";
13
+ } from "./chunk-67N47KUS.js";
13
14
  import {
14
15
  stageClaudeStaticForUpload,
15
16
  stageCodexStaticForUpload,
16
17
  stageOpencodeStaticForUpload
17
- } from "./chunk-NAVL4R34.js";
18
- import "./chunk-UK72UQ5U.js";
18
+ } from "./chunk-6OZDFNBF.js";
19
+ import {
20
+ DOCKER_CONTEXT_FILE_MAP,
21
+ computeContextSha256,
22
+ readCliStamp,
23
+ readPreparedStateRaw,
24
+ resolveContextFilesFrom,
25
+ writePreparedStateRaw
26
+ } from "./chunk-BGK32PZE.js";
27
+ import "./chunk-G3H2L3O2.js";
19
28
 
20
29
  // ../../packages/sandbox-daytona/dist/index.js
21
30
  import { Image } from "@daytonaio/sdk";
22
- function defaultSnapshotName() {
31
+ import { existsSync } from "fs";
32
+ import { dirname, resolve } from "path";
33
+ import { fileURLToPath } from "url";
34
+ var SCHEMA = 1;
35
+ function resolveDaytonaContextFiles() {
36
+ const ctx = resolveDockerfileContext();
37
+ if (!ctx) return null;
38
+ const here = dirname(fileURLToPath(import.meta.url));
39
+ const packageRoot = resolve(here, "..");
40
+ const monorepoRoot = resolve(here, "..", "..", "..");
41
+ const dockerPackageRoot = resolve(monorepoRoot, "packages", "sandbox-docker");
42
+ const docker = resolveContextFilesFrom(DOCKER_CONTEXT_FILE_MAP, {
43
+ contextDir: ctx.context,
44
+ devRoot: existsSync(dockerPackageRoot) ? dockerPackageRoot : packageRoot
45
+ });
46
+ if (!docker) return null;
47
+ const overlay = resolveDaytonaCustomClaudeMd();
48
+ if (!overlay) return null;
49
+ return [
50
+ ...docker,
51
+ // Daytona-specific overlay: separate logical name so a docker/daytona
52
+ // CLAUDE.md drift produces different fingerprints (the daytona snapshot
53
+ // contains both files in distinct locations).
54
+ { rel: "daytona/custom-system-CLAUDE.md", abs: overlay }
55
+ ];
56
+ }
57
+ async function computeDaytonaContextFingerprint() {
58
+ const files = resolveDaytonaContextFiles();
59
+ if (!files) return null;
60
+ return { contextSha256: await computeContextSha256(files), files };
61
+ }
62
+ function readPreparedDaytonaState() {
63
+ const raw = readPreparedStateRaw("daytona");
64
+ if (raw === null || typeof raw !== "object") return null;
65
+ const parsed = raw;
66
+ if (parsed.schema !== SCHEMA) return null;
67
+ return { schema: SCHEMA, base: parsed.base };
68
+ }
69
+ function writePreparedDaytonaState(opts) {
70
+ const stamp = readCliStamp();
71
+ const state = {
72
+ schema: SCHEMA,
73
+ base: {
74
+ imageRef: opts.snapshotName,
75
+ contextSha256: opts.contextSha256,
76
+ cliVersion: stamp.cliVersion,
77
+ cliCommit: stamp.cliCommit,
78
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
79
+ }
80
+ };
81
+ writePreparedStateRaw("daytona", state);
82
+ }
83
+ function preparedMatches(state, current) {
84
+ return state?.base?.contextSha256 === current;
85
+ }
86
+ function defaultSnapshotName(fingerprint) {
87
+ if (fingerprint) return `agentbox-base-${fingerprint.slice(0, 12)}`;
23
88
  return `agentbox-base-${Math.floor(Date.now() / 1e3).toString()}`;
24
89
  }
25
90
  async function stageAllAgentStatic(opts) {
@@ -53,33 +118,69 @@ async function prepareDaytona(opts) {
53
118
  ensureDaytonaEnvLoaded();
54
119
  const log = opts.onLog ?? (() => {
55
120
  });
56
- const snapshotName = opts.name ?? defaultSnapshotName();
121
+ const fingerprint = await computeDaytonaContextFingerprint();
122
+ const snapshotName = opts.name ?? defaultSnapshotName(fingerprint?.contextSha256 ?? null);
123
+ const prepared = readPreparedDaytonaState();
124
+ if (!opts.force && fingerprint && preparedMatches(prepared, fingerprint.contextSha256)) {
125
+ try {
126
+ const existing = await getClient().snapshot.get(
127
+ prepared?.base?.imageRef ?? snapshotName
128
+ );
129
+ if (existing?.name) {
130
+ log(
131
+ `daytona snapshot '${existing.name}' up to date (fingerprint ${fingerprint.contextSha256.slice(0, 12)}) \u2014 skipping rebuild (pass --force to override)`
132
+ );
133
+ return { snapshotName: existing.name };
134
+ }
135
+ log(
136
+ `recorded snapshot '${prepared?.base?.imageRef ?? snapshotName}' not found on Daytona; rebuilding`
137
+ );
138
+ } catch {
139
+ log(
140
+ `recorded snapshot lookup failed; rebuilding (pass --force to silence)`
141
+ );
142
+ }
143
+ } else if (!opts.force && fingerprint && prepared?.base?.contextSha256) {
144
+ log(
145
+ `daytona build context changed (was ${prepared.base.contextSha256.slice(0, 12)}, now ${fingerprint.contextSha256.slice(0, 12)}); rebuilding snapshot`
146
+ );
147
+ }
57
148
  const ctx = resolveDockerfileContext();
58
149
  if (!ctx) {
59
150
  throw new Error(
60
151
  "could not locate AgentBox Dockerfile.box build context for the Daytona snapshot. Set AGENTBOX_DOCKER_CONTEXT to the directory containing Dockerfile.box."
61
152
  );
62
153
  }
154
+ const daytonaClaudeMd = resolveDaytonaCustomClaudeMd();
155
+ if (!daytonaClaudeMd) {
156
+ throw new Error(
157
+ "could not locate packages/sandbox-daytona/scripts/custom-system-CLAUDE.md (or its staged runtime/daytona/ copy). Ensure `pnpm -w build` ran so the CLI staging populated runtime/daytona/."
158
+ );
159
+ }
63
160
  const stages = await stageAllAgentStatic({ hostWorkspace: opts.hostWorkspace });
64
161
  for (const s of stages) {
65
162
  for (const w of s.staged.warnings) log(w);
66
163
  }
67
164
  try {
68
165
  let image = Image.fromDockerfile(ctx.dockerfile);
69
- const extractCmds = [];
166
+ image = image.addLocalFile(daytonaClaudeMd, "/tmp/agentbox-custom-CLAUDE.md");
167
+ const extractCmds = [
168
+ "install -m 0644 /tmp/agentbox-custom-CLAUDE.md /etc/claude-code/CLAUDE.md",
169
+ "rm -f /tmp/agentbox-custom-CLAUDE.md"
170
+ ];
70
171
  const usable = stages.filter((s) => s.staged.tarballPath !== null);
71
172
  for (const s of usable) {
72
173
  image = image.addLocalFile(s.staged.tarballPath, s.remoteTar);
73
174
  extractCmds.push(`mkdir -p ${s.extractDir}`);
74
175
  extractCmds.push(`tar -xzf ${s.remoteTar} -C ${s.extractDir}`);
75
176
  }
76
- if (extractCmds.length > 0) {
177
+ if (usable.length > 0) {
77
178
  extractCmds.push(
78
179
  "chown -R vscode:vscode /home/vscode/.claude /home/vscode/.codex /home/vscode/.local"
79
180
  );
80
181
  extractCmds.push("rm -f /tmp/agentbox-seed-*.tar.gz");
81
- image = image.dockerfileCommands(["USER root"]).runCommands(...extractCmds).dockerfileCommands(["USER vscode"]);
82
182
  }
183
+ image = image.dockerfileCommands(["USER root"]).runCommands(...extractCmds).dockerfileCommands(["USER vscode"]);
83
184
  const client = getClient();
84
185
  log(`creating Daytona snapshot '${snapshotName}'\u2026`);
85
186
  const snapshot = await client.snapshot.create(
@@ -89,6 +190,15 @@ async function prepareDaytona(opts) {
89
190
  }
90
191
  );
91
192
  log(`snapshot '${snapshot.name}' is ${snapshot.state ?? "created"}`);
193
+ if (fingerprint) {
194
+ writePreparedDaytonaState({
195
+ snapshotName: snapshot.name ?? snapshotName,
196
+ contextSha256: fingerprint.contextSha256
197
+ });
198
+ log(
199
+ `recorded daytona-prepared.json (fingerprint ${fingerprint.contextSha256.slice(0, 12)})`
200
+ );
201
+ }
92
202
  return { snapshotName: snapshot.name ?? snapshotName };
93
203
  } finally {
94
204
  await Promise.all(stages.map((s) => s.staged.cleanup()));
@@ -180,4 +290,4 @@ export {
180
290
  getDaytonaStatus,
181
291
  resolveDockerfileContext
182
292
  };
183
- //# sourceMappingURL=dist-R67WMLCF.js.map
293
+ //# sourceMappingURL=dist-L4LCG5SJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../packages/sandbox-daytona/src/index.ts","../../../packages/sandbox-daytona/src/prepare.ts","../../../packages/sandbox-daytona/src/prepared-state.ts","../../../packages/sandbox-daytona/src/status.ts"],"sourcesContent":["/**\n * The Daytona Cloud sandbox provider. A thin `CloudBackend` over\n * `@daytonaio/sdk`, composed via `@agentbox/sandbox-cloud`'s `createCloudProvider`\n * for everything provider-agnostic (workspace seeding, ctl launch, state).\n */\n\nimport type { Provider } from '@agentbox/core';\nimport { createCloudProvider } from '@agentbox/sandbox-cloud';\nimport { daytonaBackend, DEFAULT_BOX_IMAGE_REF } from './backend.js';\nimport { prepareDaytona } from './prepare.js';\n\nconst cloudProvider = createCloudProvider(daytonaBackend, {\n defaultResources: { cpu: 2, memory: 4, disk: 8 },\n});\n\nexport const daytonaProvider: Provider = {\n ...cloudProvider,\n prepare: prepareDaytona,\n};\n\nexport { daytonaBackend, DEFAULT_BOX_IMAGE_REF };\nexport { resolveDockerfileContext, type DockerfileContext } from './dockerfile-context.js';\nexport { ensureDaytonaEnvLoaded } from './env-loader.js';\n// Called by the CLI provider registry to gate first-run interactive setup.\n// Plain async function — no commander surface — so adding it here doesn't\n// pull commander/clack into consumers' type graphs. The full CLI command\n// lives at the `./cli` subpath export.\nexport { ensureDaytonaCredentials } from './credentials.js';\nexport type { EnsureDaytonaCredentialsOptions } from './credentials.js';\nexport {\n getDaytonaStatus,\n type DaytonaStatus,\n type DaytonaSnapshotSummary,\n type DaytonaVolumeSummary,\n} from './status.js';\n","/**\n * Daytona-side implementation of the `Provider.prepare` hook (`agentbox\n * prepare --provider daytona`). One-time, user-triggered:\n *\n * 1. Stage filtered tarballs of the host's `~/.claude`, `~/.codex`, and\n * `~/.local/share/opencode` static config (no auth tokens — those go on\n * the per-org `agentbox-credentials` volume at create time).\n * 2. Build a layered Daytona `Image`: start from `Dockerfile.box`, then\n * `.addLocalFile()` each staged tarball + `.runCommands()` to extract\n * them into the right paths inside the image.\n * 3. Call `daytona.snapshot.create({ name, image }, { onLogs })` — Daytona\n * runs the build server-side, registers the result as an org-scoped\n * named snapshot, and returns when it's `active`.\n *\n * Replaces the old `agentbox daytona publish-snapshot` flow that\n * provisioned a sandbox + ran an in-sandbox bake + called the broken\n * `_experimental_createSnapshot`. The new path never provisions a sandbox.\n *\n * Source of truth for the public API:\n * https://www.daytona.io/docs/en/snapshots/\n */\n\nimport { Image } from '@daytonaio/sdk';\nimport type { PrepareOptions, PrepareResult } from '@agentbox/core';\nimport {\n stageClaudeStaticForUpload,\n stageCodexStaticForUpload,\n stageOpencodeStaticForUpload,\n type StageResult,\n} from '@agentbox/sandbox-cloud';\nimport { getClient } from './backend.js';\nimport { resolveDaytonaCustomClaudeMd, resolveDockerfileContext } from './dockerfile-context.js';\nimport { ensureDaytonaEnvLoaded } from './env-loader.js';\nimport {\n computeDaytonaContextFingerprint,\n preparedMatches,\n readPreparedDaytonaState,\n writePreparedDaytonaState,\n} from './prepared-state.js';\n\n/**\n * Default snapshot name. Keyed on the first 12 chars of the build-context\n * fingerprint so identical content produces the same snapshot name across\n * machines / CLI runs (idempotent): if the named snapshot already exists\n * on Daytona, prepare can short-circuit without uploading the build\n * context again. Falls back to a timestamp when fingerprinting fails\n * (partial dev rebuild).\n */\nfunction defaultSnapshotName(fingerprint: string | null): string {\n if (fingerprint) return `agentbox-base-${fingerprint.slice(0, 12)}`;\n return `agentbox-base-${Math.floor(Date.now() / 1000).toString()}`;\n}\n\ninterface AgentStage {\n kind: 'claude' | 'codex' | 'opencode';\n /** Path inside the image build that the tarball is uploaded to. */\n remoteTar: string;\n /** Path the image build extracts the tarball into. */\n extractDir: string;\n staged: StageResult;\n}\n\n/**\n * Stage the three agents' static tarballs in parallel. Each `StageResult`'s\n * `cleanup()` must be called by the caller, after the image build picks the\n * file up.\n */\nasync function stageAllAgentStatic(opts: { hostWorkspace?: string }): Promise<AgentStage[]> {\n const [claudeStaged, codexStaged, opencodeStaged] = await Promise.all([\n stageClaudeStaticForUpload({ hostWorkspace: opts.hostWorkspace }),\n stageCodexStaticForUpload(),\n stageOpencodeStaticForUpload(),\n ]);\n return [\n {\n kind: 'claude',\n remoteTar: '/tmp/agentbox-seed-claude.tar.gz',\n extractDir: '/home/vscode/.claude',\n staged: claudeStaged,\n },\n {\n kind: 'codex',\n remoteTar: '/tmp/agentbox-seed-codex.tar.gz',\n extractDir: '/home/vscode/.codex',\n staged: codexStaged,\n },\n {\n kind: 'opencode',\n remoteTar: '/tmp/agentbox-seed-opencode.tar.gz',\n extractDir: '/home/vscode/.local/share/opencode',\n staged: opencodeStaged,\n },\n ];\n}\n\n/**\n * Run `agentbox prepare --provider daytona`. Returns `{ snapshotName }` on\n * success so the CLI can pin it into the project config.\n */\nexport async function prepareDaytona(opts: PrepareOptions): Promise<PrepareResult> {\n ensureDaytonaEnvLoaded();\n const log = opts.onLog ?? (() => {});\n\n // Fingerprint the build context first so we can (a) name the snapshot\n // deterministically and (b) detect cache hits against the recorded\n // prepared state. Computed before staging so an early `null` (partial\n // dev rebuild) doesn't waste a tar staging cycle.\n const fingerprint = await computeDaytonaContextFingerprint();\n const snapshotName =\n opts.name ?? defaultSnapshotName(fingerprint?.contextSha256 ?? null);\n\n const prepared = readPreparedDaytonaState();\n if (\n !opts.force &&\n fingerprint &&\n preparedMatches(prepared, fingerprint.contextSha256)\n ) {\n // Confirm the snapshot still exists on Daytona before short-circuiting.\n // A \"yes locally, no on the server\" mismatch must rebuild.\n try {\n const existing = await getClient().snapshot.get(\n prepared?.base?.imageRef ?? snapshotName,\n );\n if (existing?.name) {\n log(\n `daytona snapshot '${existing.name}' up to date ` +\n `(fingerprint ${fingerprint.contextSha256.slice(0, 12)}) — skipping rebuild ` +\n `(pass --force to override)`,\n );\n return { snapshotName: existing.name };\n }\n log(\n `recorded snapshot '${prepared?.base?.imageRef ?? snapshotName}' not found on Daytona; rebuilding`,\n );\n } catch {\n log(\n `recorded snapshot lookup failed; rebuilding (pass --force to silence)`,\n );\n }\n } else if (!opts.force && fingerprint && prepared?.base?.contextSha256) {\n log(\n `daytona build context changed (was ${prepared.base.contextSha256.slice(0, 12)}, ` +\n `now ${fingerprint.contextSha256.slice(0, 12)}); rebuilding snapshot`,\n );\n }\n\n const ctx = resolveDockerfileContext();\n if (!ctx) {\n throw new Error(\n 'could not locate AgentBox Dockerfile.box build context for the Daytona snapshot. ' +\n 'Set AGENTBOX_DOCKER_CONTEXT to the directory containing Dockerfile.box.',\n );\n }\n\n const daytonaClaudeMd = resolveDaytonaCustomClaudeMd();\n if (!daytonaClaudeMd) {\n throw new Error(\n 'could not locate packages/sandbox-daytona/scripts/custom-system-CLAUDE.md ' +\n '(or its staged runtime/daytona/ copy). Ensure `pnpm -w build` ran so the ' +\n 'CLI staging populated runtime/daytona/.',\n );\n }\n\n const stages = await stageAllAgentStatic({ hostWorkspace: opts.hostWorkspace });\n // Surface staging warnings (codex Keychain landmine, etc.) before the\n // longer build kicks off.\n for (const s of stages) {\n for (const w of s.staged.warnings) log(w);\n }\n\n try {\n let image: Image = Image.fromDockerfile(ctx.dockerfile);\n\n // Overlay the daytona-specific /etc/claude-code/CLAUDE.md on top of the\n // docker-shaped one baked by Dockerfile.box. Daytona boxes have no host\n // .git/ bind-mount, so the in-box hint needs daytona-specific git wording.\n image = image.addLocalFile(daytonaClaudeMd, '/tmp/agentbox-custom-CLAUDE.md');\n const extractCmds: string[] = [\n 'install -m 0644 /tmp/agentbox-custom-CLAUDE.md /etc/claude-code/CLAUDE.md',\n 'rm -f /tmp/agentbox-custom-CLAUDE.md',\n ];\n\n // For each agent whose stage produced a tarball, add the file to the\n // image build context and append a single tar-extract + chown.\n const usable = stages.filter((s) => s.staged.tarballPath !== null);\n for (const s of usable) {\n image = image.addLocalFile(s.staged.tarballPath as string, s.remoteTar);\n extractCmds.push(`mkdir -p ${s.extractDir}`);\n extractCmds.push(`tar -xzf ${s.remoteTar} -C ${s.extractDir}`);\n }\n if (usable.length > 0) {\n // One final pass: own the extracted trees as the box user, then drop the\n // staging tarballs (no point shipping them twice in the image layer).\n extractCmds.push(\n 'chown -R vscode:vscode /home/vscode/.claude /home/vscode/.codex /home/vscode/.local',\n );\n extractCmds.push('rm -f /tmp/agentbox-seed-*.tar.gz');\n }\n // Dockerfile.box ends with `USER vscode`. Switch to root for the\n // install/tar/chown/rm pass — COPYed files are root-owned in /tmp (sticky\n // bit), chown -R on /home/vscode/.* only works as root, and\n // /etc/claude-code is root-owned. Switch back to vscode so the image\n // keeps its default-user invariant.\n image = image\n .dockerfileCommands(['USER root'])\n .runCommands(...extractCmds)\n .dockerfileCommands(['USER vscode']);\n\n const client = getClient();\n log(`creating Daytona snapshot '${snapshotName}'…`);\n const snapshot = await client.snapshot.create(\n { name: snapshotName, image },\n {\n onLogs: (chunk: string) => log(String(chunk).split('\\n').filter(Boolean).join(' ')),\n },\n );\n log(`snapshot '${snapshot.name}' is ${snapshot.state ?? 'created'}`);\n if (fingerprint) {\n writePreparedDaytonaState({\n snapshotName: snapshot.name ?? snapshotName,\n contextSha256: fingerprint.contextSha256,\n });\n log(\n `recorded daytona-prepared.json (fingerprint ${fingerprint.contextSha256.slice(0, 12)})`,\n );\n }\n return { snapshotName: snapshot.name ?? snapshotName };\n } finally {\n await Promise.all(stages.map((s) => s.staged.cleanup()));\n }\n}\n","/**\n * Daytona provider's `~/.agentbox/daytona-prepared.json` reader/writer +\n * build-context fingerprinting for the org-scoped base snapshot.\n *\n * The daytona prepare bakes the docker `Dockerfile.box` plus a daytona-\n * specific `custom-system-CLAUDE.md` overlay. The fingerprint covers both\n * — same canonical file map as the docker provider for the dockerfile\n * inputs, plus one extra entry for the daytona overlay.\n */\n\nimport { existsSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport {\n computeContextSha256,\n DOCKER_CONTEXT_FILE_MAP,\n readCliStamp,\n readPreparedStateRaw,\n resolveContextFilesFrom,\n writePreparedStateRaw,\n type ContextFile,\n type PreparedBaseSnapshot,\n} from '@agentbox/sandbox-core';\nimport { resolveDaytonaCustomClaudeMd, resolveDockerfileContext } from './dockerfile-context.js';\n\nconst SCHEMA = 1 as const;\n\nexport type PreparedDaytonaState = PreparedBaseSnapshot<string, never>;\n\n/**\n * Resolve every file that influences the daytona base snapshot: the docker\n * build context (shared map from sandbox-core) plus the daytona-specific\n * CLAUDE.md overlay added by `Image.addLocalFile` in `prepare.ts`.\n *\n * Returns `null` if any file is missing — callers degrade to \"always\n * rebuild\" rather than stamp a misleading fingerprint.\n */\nexport function resolveDaytonaContextFiles(): ContextFile[] | null {\n const ctx = resolveDockerfileContext();\n if (!ctx) return null;\n // sandbox-daytona's package root = parent of src/ or parent of dist/.\n // Mirrors the `resolve(here, '..', '..', '..')` walk in dockerfile-context.ts.\n const here = dirname(fileURLToPath(import.meta.url));\n const packageRoot = resolve(here, '..');\n const monorepoRoot = resolve(here, '..', '..', '..');\n // Docker's dev fallback is anchored at sandbox-docker's root, not\n // sandbox-daytona's, so we pass the monorepo root and prefix the dev\n // paths to walk into packages/sandbox-docker/.\n //\n // Simpler: just point devRoot at sandbox-docker's package root when it\n // exists (legacy monorepo layout).\n const dockerPackageRoot = resolve(monorepoRoot, 'packages', 'sandbox-docker');\n const docker = resolveContextFilesFrom(DOCKER_CONTEXT_FILE_MAP, {\n contextDir: ctx.context,\n devRoot: existsSync(dockerPackageRoot) ? dockerPackageRoot : packageRoot,\n });\n if (!docker) return null;\n const overlay = resolveDaytonaCustomClaudeMd();\n if (!overlay) return null;\n return [\n ...docker,\n // Daytona-specific overlay: separate logical name so a docker/daytona\n // CLAUDE.md drift produces different fingerprints (the daytona snapshot\n // contains both files in distinct locations).\n { rel: 'daytona/custom-system-CLAUDE.md', abs: overlay },\n ];\n}\n\nexport interface DaytonaFingerprint {\n contextSha256: string;\n files: ContextFile[];\n}\n\nexport async function computeDaytonaContextFingerprint(): Promise<DaytonaFingerprint | null> {\n const files = resolveDaytonaContextFiles();\n if (!files) return null;\n return { contextSha256: await computeContextSha256(files), files };\n}\n\nexport function readPreparedDaytonaState(): PreparedDaytonaState | null {\n const raw = readPreparedStateRaw('daytona');\n if (raw === null || typeof raw !== 'object') return null;\n const parsed = raw as Partial<PreparedDaytonaState>;\n if (parsed.schema !== SCHEMA) return null;\n return { schema: SCHEMA, base: parsed.base };\n}\n\nexport function writePreparedDaytonaState(opts: {\n snapshotName: string;\n contextSha256: string;\n}): void {\n const stamp = readCliStamp();\n const state: PreparedDaytonaState = {\n schema: SCHEMA,\n base: {\n imageRef: opts.snapshotName,\n contextSha256: opts.contextSha256,\n cliVersion: stamp.cliVersion,\n cliCommit: stamp.cliCommit,\n createdAt: new Date().toISOString(),\n },\n };\n writePreparedStateRaw('daytona', state);\n}\n\nexport function preparedMatches(\n state: PreparedDaytonaState | null,\n current: string,\n): boolean {\n return state?.base?.contextSha256 === current;\n}\n","/**\n * Read-only status helpers for `agentbox prepare` (no-args mode). Surfaces\n * the user-facing inventory of agentbox-owned base images / snapshots /\n * volumes on the configured Daytona org so the user can see at a glance\n * what's already prepared and what isn't.\n *\n * Daytona-side state lives in two places:\n * - **Snapshots** — built by `agentbox prepare --provider daytona`. Listed\n * filtered to `agentbox*` so we don't surface unrelated org snapshots.\n * - **Volumes** — the per-org `agentbox-credentials` volume created lazily\n * by `ensureAgentVolumesForCloud` on first `agentbox create --provider\n * daytona`.\n *\n * All calls swallow auth/network errors and return an empty section — the\n * status command must work for users who don't have Daytona configured.\n */\n\nimport { ensureDaytonaEnvLoaded } from './env-loader.js';\nimport { getClient } from './backend.js';\n\nexport interface DaytonaSnapshotSummary {\n name: string;\n state?: string;\n /** Snapshot size in GB, as reported by Daytona (may be undefined for non-`active` states). */\n sizeGb?: number;\n createdAt?: string;\n errorReason?: string;\n}\n\nexport interface DaytonaVolumeSummary {\n name: string;\n id: string;\n state?: string;\n createdAt?: string;\n lastUsedAt?: string;\n}\n\nexport interface DaytonaStatus {\n /** True when Daytona credentials are present + the SDK could connect. */\n configured: boolean;\n /** Snapshots whose name starts with `agentbox` (case-insensitive). */\n snapshots: DaytonaSnapshotSummary[];\n /** Volumes whose name starts with `agentbox` (case-insensitive). */\n volumes: DaytonaVolumeSummary[];\n /** Non-fatal explanation when `configured` is false. */\n reason?: string;\n}\n\nfunction isAgentboxName(name: unknown): boolean {\n return typeof name === 'string' && name.toLowerCase().startsWith('agentbox');\n}\n\n/**\n * Collect a read-only summary of agentbox-owned snapshots + volumes on the\n * Daytona org. Never throws — failure paths return `configured: false` with\n * a one-line reason.\n */\nexport async function getDaytonaStatus(): Promise<DaytonaStatus> {\n try {\n ensureDaytonaEnvLoaded();\n } catch (err) {\n return {\n configured: false,\n snapshots: [],\n volumes: [],\n reason: err instanceof Error ? err.message : String(err),\n };\n }\n\n let client;\n try {\n client = getClient();\n } catch (err) {\n return {\n configured: false,\n snapshots: [],\n volumes: [],\n reason: err instanceof Error ? err.message.split('\\n')[0] : String(err),\n };\n }\n\n const snapshots: DaytonaSnapshotSummary[] = [];\n const volumes: DaytonaVolumeSummary[] = [];\n let reason: string | undefined;\n\n try {\n const list = await client.snapshot.list();\n const items = (list as { items?: unknown[] }).items ?? (Array.isArray(list) ? list : []);\n for (const s of items) {\n const dto = s as { name?: unknown; state?: unknown; size?: unknown; createdAt?: unknown; errorReason?: unknown };\n if (!isAgentboxName(dto.name)) continue;\n snapshots.push({\n name: dto.name as string,\n state: typeof dto.state === 'string' ? dto.state : undefined,\n sizeGb: typeof dto.size === 'number' ? dto.size : undefined,\n createdAt: typeof dto.createdAt === 'string' ? dto.createdAt : undefined,\n errorReason: typeof dto.errorReason === 'string' ? dto.errorReason : undefined,\n });\n }\n } catch (err) {\n reason = `snapshot list failed: ${err instanceof Error ? err.message.split('\\n')[0] : String(err)}`;\n }\n\n try {\n const list = await client.volume.list();\n const items: unknown[] = Array.isArray(list)\n ? list\n : ((list as { items?: unknown[] }).items ?? []);\n for (const v of items) {\n const dto = v as { name?: unknown; id?: unknown; state?: unknown; createdAt?: unknown; lastUsedAt?: unknown };\n if (!isAgentboxName(dto.name)) continue;\n volumes.push({\n name: dto.name as string,\n id: typeof dto.id === 'string' ? dto.id : '',\n state: typeof dto.state === 'string' ? dto.state : undefined,\n createdAt: typeof dto.createdAt === 'string' ? dto.createdAt : undefined,\n lastUsedAt: typeof dto.lastUsedAt === 'string' ? dto.lastUsedAt : undefined,\n });\n }\n } catch (err) {\n const msg = `volume list failed: ${err instanceof Error ? err.message.split('\\n')[0] : String(err)}`;\n reason = reason ? `${reason}; ${msg}` : msg;\n }\n\n return {\n configured: true,\n snapshots: snapshots.sort((a, b) => (b.createdAt ?? '').localeCompare(a.createdAt ?? '')),\n volumes: volumes.sort((a, b) => a.name.localeCompare(b.name)),\n reason,\n };\n}\n"],"mappings":"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","names":[]}
@@ -13,7 +13,6 @@ import {
13
13
  CheckpointError,
14
14
  ClaudeSessionError,
15
15
  CodexSessionError,
16
- DEFAULT_BOX_IMAGE,
17
16
  DEFAULT_CLAUDE_SESSION,
18
17
  DEFAULT_CODEX_SESSION,
19
18
  DEFAULT_ENV_PATTERNS,
@@ -22,7 +21,6 @@ import {
22
21
  DEFAULT_SHELL_SESSION,
23
22
  EXCLUDE_DIRS,
24
23
  ExportError,
25
- GitWorktreeError,
26
24
  IDE_FLAVORS,
27
25
  OPENCODE_FORWARDED_ENV_KEYS,
28
26
  OpencodeSessionError,
@@ -38,17 +36,13 @@ import {
38
36
  SHARED_VSCODE_EXTENSIONS_VOLUME,
39
37
  SHELL_SESSION_PREFIX,
40
38
  SNAPSHOTS_ROOT,
41
- STATE_DIR,
42
- STATE_FILE,
43
39
  VNC_CONTAINER_PORT,
44
40
  WORKTREE_ROOT,
45
41
  agentboxHomeBytes,
46
42
  allCheckpointImagesBytes,
47
- allocateProjectIndex,
48
43
  allocateShellSessionName,
49
44
  attachClaudeSession,
50
45
  attachedContainerUri,
51
- autoPickProjectBox,
52
46
  bindWorktrees,
53
47
  boxResourceStats,
54
48
  boxRunDirFor,
@@ -69,6 +63,7 @@ import {
69
63
  buildOpencodeMounts,
70
64
  buildShellArgv,
71
65
  buildShellSessionAttachArgv,
66
+ buildTmuxConfigShellSnippet,
72
67
  buildTmuxSessionArgs,
73
68
  buildVncUrls,
74
69
  buildVscodeMounts,
@@ -85,23 +80,21 @@ import {
85
80
  cursorServerVolumeName,
86
81
  destroyBox,
87
82
  detectEngine,
88
- detectGitRepos,
89
83
  detectPortless,
90
84
  dockerProvider,
91
85
  dockerVolumeName,
86
+ downloadFromBox,
92
87
  ensureAgentboxTasksFile,
93
88
  ensureBoxBrowser,
94
89
  ensureClaudeVolume,
95
90
  ensureCodexInstalled,
96
91
  ensureCodexVolume,
97
92
  ensureIdeVolumes,
98
- ensureImage,
99
93
  ensureOpencodeInstalled,
100
94
  ensureOpencodeVolume,
101
95
  ensureRelay,
102
96
  ensureVscodeVolumes,
103
97
  execInBox,
104
- findBox,
105
98
  forgetBoxFromRelay,
106
99
  formatDetachNotice,
107
100
  generateRelayToken,
@@ -115,8 +108,6 @@ import {
115
108
  hostBackupHasCredentials,
116
109
  ideProfile,
117
110
  ideServerVolumeName,
118
- imageExists,
119
- imageInfo,
120
111
  inspectBox,
121
112
  installPortless,
122
113
  isShellSessionName,
@@ -127,6 +118,7 @@ import {
127
118
  listBoxes,
128
119
  listCheckpoints,
129
120
  listShellSessions,
121
+ mintHostInitiatedToken,
130
122
  openBoxInFinder,
131
123
  openInFinder,
132
124
  opencodeSessionInfo,
@@ -135,7 +127,6 @@ import {
135
127
  parseShellSessionList,
136
128
  parseSyncResult,
137
129
  pauseBox,
138
- pickFreshBranch,
139
130
  portlessAlias,
140
131
  portlessBrowserEnv,
141
132
  portlessGetUrl,
@@ -150,20 +141,16 @@ import {
150
141
  pullOpencodeConfig,
151
142
  pullToHost,
152
143
  readBoxStatus,
153
- readState,
154
144
  rebuildPluginNativeDeps,
155
- recordBox,
156
145
  refreshExport,
157
146
  registerBoxWithRelay,
158
147
  rehydrateRelayRegistry,
159
- removeBoxRecord,
160
148
  removeCheckpoint,
161
149
  removeImage,
162
150
  removeInBoxWorktree,
163
151
  repairIdeOwnership,
164
152
  repairVscodeServerOwnership,
165
153
  resetPortlessCache,
166
- resolveBoxRef,
167
154
  resolveCheckpoint,
168
155
  resolveClaudeVolume,
169
156
  resolveCodexVolume,
@@ -175,6 +162,7 @@ import {
175
162
  scanHostEnvFiles,
176
163
  scanPluginCacheForRebuild,
177
164
  seedCodexHooks,
165
+ seedOpencodePlugin,
178
166
  seedSetupSkillIntoVolume,
179
167
  seedWorkspace,
180
168
  seedWorkspaceFromDir,
@@ -190,6 +178,7 @@ import {
190
178
  stageCodexCredentialsForUpload,
191
179
  stageCodexStaticForUpload,
192
180
  stageOpencodeCredentialsForUpload,
181
+ stageOpencodeStateForUpload,
193
182
  stageOpencodeStaticForUpload,
194
183
  startBox,
195
184
  startClaudeSession,
@@ -201,6 +190,7 @@ import {
201
190
  stopRelay,
202
191
  syncClaudeCredentials,
203
192
  unpauseBox,
193
+ uploadToBox,
204
194
  volumeExists,
205
195
  volumeHasCodexAuth,
206
196
  volumeHasOpencodeAuth,
@@ -208,8 +198,31 @@ import {
208
198
  vscodeServerVolumeName,
209
199
  waitForTmuxPaneContent,
210
200
  warmUpClaudeCredentials
211
- } from "./chunk-NAVL4R34.js";
212
- import "./chunk-UK72UQ5U.js";
201
+ } from "./chunk-6OZDFNBF.js";
202
+ import {
203
+ DEFAULT_BOX_IMAGE,
204
+ GitWorktreeError,
205
+ STATE_DIR,
206
+ STATE_FILE,
207
+ allocateProjectIndex,
208
+ autoPickProjectBox,
209
+ computeDockerContextFingerprint,
210
+ detectGitRepos,
211
+ ensureImage,
212
+ findBox,
213
+ imageExists,
214
+ imageInfo,
215
+ pickFreshBranch,
216
+ preparedMatches,
217
+ readPreparedDockerState,
218
+ readState,
219
+ recordBox,
220
+ removeBoxRecord,
221
+ resolveBoxRef,
222
+ resolveContextFiles,
223
+ writePreparedDockerState
224
+ } from "./chunk-BGK32PZE.js";
225
+ import "./chunk-G3H2L3O2.js";
213
226
  export {
214
227
  AmbiguousBoxError,
215
228
  BOXES_ROOT,
@@ -280,6 +293,7 @@ export {
280
293
  buildOpencodeMounts,
281
294
  buildShellArgv,
282
295
  buildShellSessionAttachArgv,
296
+ buildTmuxConfigShellSnippet,
283
297
  buildTmuxSessionArgs,
284
298
  buildVncUrls,
285
299
  buildVscodeMounts,
@@ -288,6 +302,7 @@ export {
288
302
  clearRelayNotice,
289
303
  codexSessionInfo,
290
304
  collectRepoCarryOver,
305
+ computeDockerContextFingerprint,
291
306
  computeNextCheckpointName,
292
307
  copyHostEnvFilesToBox,
293
308
  copyHostFilesToBox,
@@ -300,6 +315,7 @@ export {
300
315
  detectPortless,
301
316
  dockerProvider,
302
317
  dockerVolumeName,
318
+ downloadFromBox,
303
319
  ensureAgentboxTasksFile,
304
320
  ensureBoxBrowser,
305
321
  ensureClaudeVolume,
@@ -338,6 +354,7 @@ export {
338
354
  listBoxes,
339
355
  listCheckpoints,
340
356
  listShellSessions,
357
+ mintHostInitiatedToken,
341
358
  openBoxInFinder,
342
359
  openInFinder,
343
360
  opencodeSessionInfo,
@@ -353,6 +370,7 @@ export {
353
370
  portlessInstallHint,
354
371
  portlessStartHint,
355
372
  portlessUnalias,
373
+ preparedMatches,
356
374
  projectCheckpointImageBytes,
357
375
  projectCheckpointsDir,
358
376
  pruneBoxes,
@@ -361,6 +379,7 @@ export {
361
379
  pullOpencodeConfig,
362
380
  pullToHost,
363
381
  readBoxStatus,
382
+ readPreparedDockerState,
364
383
  readState,
365
384
  rebuildPluginNativeDeps,
366
385
  recordBox,
@@ -378,6 +397,7 @@ export {
378
397
  resolveCheckpoint,
379
398
  resolveClaudeVolume,
380
399
  resolveCodexVolume,
400
+ resolveContextFiles,
381
401
  resolveOpencodeVolume,
382
402
  resolvePortlessHostStateDir,
383
403
  runInteractiveClaudeLogin,
@@ -386,6 +406,7 @@ export {
386
406
  scanHostEnvFiles,
387
407
  scanPluginCacheForRebuild,
388
408
  seedCodexHooks,
409
+ seedOpencodePlugin,
389
410
  seedSetupSkillIntoVolume,
390
411
  seedWorkspace,
391
412
  seedWorkspaceFromDir,
@@ -401,6 +422,7 @@ export {
401
422
  stageCodexCredentialsForUpload,
402
423
  stageCodexStaticForUpload,
403
424
  stageOpencodeCredentialsForUpload,
425
+ stageOpencodeStateForUpload,
404
426
  stageOpencodeStaticForUpload,
405
427
  startBox,
406
428
  startClaudeSession,
@@ -412,12 +434,14 @@ export {
412
434
  stopRelay,
413
435
  syncClaudeCredentials,
414
436
  unpauseBox,
437
+ uploadToBox,
415
438
  volumeExists,
416
439
  volumeHasCodexAuth,
417
440
  volumeHasOpencodeAuth,
418
441
  volumeSizeBytes,
419
442
  vscodeServerVolumeName,
420
443
  waitForTmuxPaneContent,
421
- warmUpClaudeCredentials
444
+ warmUpClaudeCredentials,
445
+ writePreparedDockerState
422
446
  };
423
- //# sourceMappingURL=dist-ETCFRVPA.js.map
447
+ //# sourceMappingURL=dist-LOZBWMBF.js.map