@madarco/agentbox 0.4.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-WR5FFGE5.js → chunk-6VTAPD4H.js} +123 -112
- package/dist/chunk-6VTAPD4H.js.map +1 -0
- package/dist/{chunk-J35IH7W5.js → chunk-7J5AJLWG.js} +61 -23
- package/dist/chunk-7J5AJLWG.js.map +1 -0
- package/dist/{chunk-FQD6ZWYW.js → chunk-FJNIFTWK.js} +66 -65
- package/dist/chunk-FJNIFTWK.js.map +1 -0
- package/dist/{chunk-IDR4HVIC.js → chunk-HPZMD5DE.js} +2 -2
- package/dist/chunk-HPZMD5DE.js.map +1 -0
- package/dist/{chunk-NSIECUCS.js → chunk-PXUBE5KS.js} +365 -258
- package/dist/chunk-PXUBE5KS.js.map +1 -0
- package/dist/{chunk-SOMIKEN2.js → chunk-RFC5F5HR.js} +272 -214
- package/dist/chunk-RFC5F5HR.js.map +1 -0
- package/dist/create-AHZ3GVEZ-TGEDL7UX.js +15 -0
- package/dist/index.js +2757 -1854
- package/dist/index.js.map +1 -1
- package/dist/{lifecycle-LURNDNYO-UWQYPNPX.js → lifecycle-LFOL6YFM-TCHDX3J5.js} +5 -5
- package/dist/{state-ZSP3ORXW-WI6KOIG3.js → state-KD7M46ZP-KHFTHFUS.js} +2 -2
- package/dist/stats-Z4BVJODD-HEC4TMUZ.js +19 -0
- package/package.json +5 -4
- package/runtime/docker/Dockerfile.box +47 -19
- package/runtime/docker/apps/cli/share/agentbox-setup/SKILL.md +39 -50
- package/runtime/docker/packages/ctl/dist/bin.cjs +219 -148
- package/runtime/docker/packages/sandbox-docker/scripts/agentbox-checkpoint-cleanup +42 -0
- package/runtime/docker/packages/sandbox-docker/scripts/custom-system-CLAUDE.md +26 -15
- package/runtime/relay/bin.cjs +288 -12
- package/share/agentbox-setup/SKILL.md +39 -50
- package/dist/chunk-FQD6ZWYW.js.map +0 -1
- package/dist/chunk-IDR4HVIC.js.map +0 -1
- package/dist/chunk-J35IH7W5.js.map +0 -1
- package/dist/chunk-NSIECUCS.js.map +0 -1
- package/dist/chunk-SOMIKEN2.js.map +0 -1
- package/dist/chunk-WR5FFGE5.js.map +0 -1
- package/dist/create-4BQY2UYU-CGSW3RGE.js +0 -15
- package/dist/stats-GZFLPYTU-DBJ2DVBJ.js +0 -19
- /package/dist/{create-4BQY2UYU-CGSW3RGE.js.map → create-AHZ3GVEZ-TGEDL7UX.js.map} +0 -0
- /package/dist/{lifecycle-LURNDNYO-UWQYPNPX.js.map → lifecycle-LFOL6YFM-TCHDX3J5.js.map} +0 -0
- /package/dist/{state-ZSP3ORXW-WI6KOIG3.js.map → state-KD7M46ZP-KHFTHFUS.js.map} +0 -0
- /package/dist/{stats-GZFLPYTU-DBJ2DVBJ.js.map → stats-Z4BVJODD-HEC4TMUZ.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../packages/sandbox-docker/src/docker.ts","../../../packages/sandbox-docker/src/host-export.ts","../../../packages/sandbox-docker/src/image.ts","../../../packages/sandbox-docker/src/checkpoint.ts","../../../packages/config/src/types.ts","../../../packages/config/src/parse.ts","../../../packages/config/src/paths.ts","../../../packages/config/src/load.ts","../../../packages/config/src/write.ts"],"sourcesContent":["import { execa, type Result } from 'execa';\n\nexport interface DockerExecResult {\n exitCode: number;\n stdout: string;\n stderr: string;\n}\n\nexport type ContainerRuntimeState = 'running' | 'paused' | 'stopped' | 'missing';\n\nexport async function dockerInfo(): Promise<void> {\n const result: Result = await execa('docker', ['info'], { reject: false });\n if (result.exitCode !== 0) {\n throw new Error(\n `docker info failed (exit ${String(result.exitCode)}). Is the Docker daemon running?\\n${String(result.stderr)}`,\n );\n }\n}\n\n/**\n * Engine-agnostic resource ceilings. Memory in bytes, cpus fractional, disk a\n * raw engine-native size string. `null`/absent = unlimited.\n */\nexport interface BoxLimitSpec {\n memoryBytes?: number | null;\n cpus?: number | null;\n pidsLimit?: number | null;\n disk?: string | null;\n}\n\nexport interface RunBoxSpec {\n name: string;\n image: string;\n lowerPath: string;\n upperVolume: string;\n extraVolumes?: string[];\n env?: Record<string, string>;\n limits?: BoxLimitSpec;\n /**\n * docker `-p` mappings to forward host ports into the container. `hostPort: 0`\n * lets Docker pick a free ephemeral port; resolve it back with\n * {@link publishedHostPort}. `hostIp` defaults to all interfaces — pin it to\n * `127.0.0.1` for loopback-only exposure.\n */\n portMappings?: Array<{ hostPort: number; containerPort: number; hostIp?: string }>;\n}\n\nexport async function runBox(spec: RunBoxSpec): Promise<string> {\n const args: string[] = [\n 'run',\n '-d',\n '--name',\n spec.name,\n '--hostname',\n spec.name,\n '--cap-add=SYS_ADMIN',\n // dockerd inside the box (always-on, see launchDockerdDaemon) needs\n // NET_ADMIN to set up its bridge + iptables NAT for inner containers.\n // seccomp:unconfined is required because the default profile blocks\n // syscalls (notably keyctl, clone3 in some kernels) that nested containers\n // need. Both are scoped to the outer box's namespaces — inner containers\n // can't escape it. We still avoid --privileged for cloud portability.\n '--cap-add=NET_ADMIN',\n '--device=/dev/fuse',\n '--security-opt=apparmor:unconfined',\n '--security-opt=seccomp=unconfined',\n // cgroup v2 + DinD: with --cgroupns=host (the OrbStack default) the\n // outer container sees the host's read-only cgroup hierarchy at\n // /sys/fs/cgroup, so the inner dockerd can't `mkdir /sys/fs/cgroup/docker`\n // for its own slice and inner `docker run` fails with \"read-only file\n // system\". Private gives the box its own writable cgroup namespace; runc\n // creates the docker slice there and inner containers nest under it.\n '--cgroupns=private',\n // Make the host reachable from inside the container at the well-known DNS\n // name host.docker.internal. Docker Desktop / OrbStack ship this alias by\n // default; on Linux native Docker it requires this explicit flag (no-op\n // on the macOS engines). Boxes use it to reach the host relay process.\n '--add-host=host.docker.internal:host-gateway',\n '-v',\n `${spec.lowerPath}:/host-src:ro`,\n '-v',\n `${spec.upperVolume}:/upper`,\n ];\n const lim = spec.limits;\n if (lim) {\n if (lim.memoryBytes && lim.memoryBytes > 0) {\n args.push('--memory', String(Math.floor(lim.memoryBytes)));\n }\n if (lim.cpus && lim.cpus > 0) {\n args.push('--cpus', String(lim.cpus));\n }\n if (lim.pidsLimit && lim.pidsLimit > 0) {\n args.push('--pids-limit', String(Math.floor(lim.pidsLimit)));\n }\n // Best-effort: a no-op on overlay2 / the macOS engines. createBox() drops\n // this on those drivers (and warns) so `docker run` doesn't hard-error.\n if (lim.disk) {\n args.push('--storage-opt', `size=${lim.disk}`);\n }\n }\n for (const v of spec.extraVolumes ?? []) {\n args.push('-v', v);\n }\n for (const pm of spec.portMappings ?? []) {\n const host = pm.hostIp ? `${pm.hostIp}:${String(pm.hostPort)}` : String(pm.hostPort);\n args.push('-p', `${host}:${String(pm.containerPort)}`);\n }\n for (const [k, val] of Object.entries(spec.env ?? {})) {\n args.push('-e', `${k}=${val}`);\n }\n args.push(spec.image, 'sleep', 'infinity');\n\n const { stdout } = await execa('docker', args);\n return stdout.trim();\n}\n\n/**\n * The engine's storage driver (`overlay2`, `fuse-overlayfs`, `btrfs`, …).\n * `--storage-opt size=` is only enforced by devicemapper/btrfs/zfs/windowsfilter\n * — a no-op everywhere the macOS engines run. Empty string on probe failure.\n */\nexport async function dockerStorageDriver(): Promise<string> {\n const result = await execa('docker', ['info', '--format', '{{.Driver}}'], { reject: false });\n if (result.exitCode !== 0) return '';\n return (result.stdout ?? '').trim();\n}\n\nexport async function execInBox(\n container: string,\n cmd: string[],\n opts: { user?: string; detach?: boolean; timeoutMs?: number } = {},\n): Promise<DockerExecResult> {\n const args: string[] = ['exec'];\n if (opts.detach) args.push('-d');\n if (opts.user) args.push('--user', opts.user);\n args.push(container, ...cmd);\n const result = await execa('docker', args, {\n reject: false,\n ...(opts.timeoutMs ? { timeout: opts.timeoutMs } : {}),\n });\n return {\n exitCode: result.exitCode ?? -1,\n stdout: result.stdout ?? '',\n stderr: result.stderr ?? '',\n };\n}\n\nexport async function removeContainer(container: string): Promise<void> {\n await execa('docker', ['rm', '-f', container], { reject: false });\n}\n\nexport async function removeVolume(name: string): Promise<void> {\n await execa('docker', ['volume', 'rm', name], { reject: false });\n}\n\n/**\n * Best-effort `docker image rm`. Returns true when the image was actually\n * removed, false when it was already absent (or removal failed). `-f` is\n * passed by default so a stale tagged image with no live containers goes away\n * even if other tags point at the same layers.\n */\nexport async function removeImage(\n ref: string,\n opts: { force?: boolean } = {},\n): Promise<boolean> {\n const args = ['image', 'rm'];\n if (opts.force !== false) args.push('-f');\n args.push(ref);\n const result = await execa('docker', args, { reject: false });\n return result.exitCode === 0;\n}\n\nexport async function containerExists(name: string): Promise<boolean> {\n const result = await execa('docker', ['container', 'inspect', '--format', '{{.Id}}', name], {\n reject: false,\n });\n return result.exitCode === 0;\n}\n\nexport async function volumeExists(name: string): Promise<boolean> {\n const result = await execa('docker', ['volume', 'inspect', name], { reject: false });\n return result.exitCode === 0;\n}\n\nexport async function ensureVolume(name: string): Promise<void> {\n if (await volumeExists(name)) return;\n await execa('docker', ['volume', 'create', name]);\n}\n\nexport async function networkExists(name: string): Promise<boolean> {\n const result = await execa('docker', ['network', 'inspect', name], { reject: false });\n return result.exitCode === 0;\n}\n\nexport async function ensureNetwork(name: string): Promise<void> {\n if (await networkExists(name)) return;\n await execa('docker', ['network', 'create', name]);\n}\n\nexport async function removeNetwork(name: string): Promise<void> {\n await execa('docker', ['network', 'rm', name], { reject: false });\n}\n\nexport async function containerIsRunning(name: string): Promise<boolean> {\n return (await inspectContainerStatus(name)) === 'running';\n}\n\nexport async function pauseContainer(name: string): Promise<void> {\n await execa('docker', ['pause', name]);\n}\n\nexport async function unpauseContainer(name: string): Promise<void> {\n await execa('docker', ['unpause', name]);\n}\n\nexport async function stopContainer(name: string): Promise<void> {\n await execa('docker', ['stop', name]);\n}\n\nexport async function startContainer(name: string): Promise<void> {\n await execa('docker', ['start', name]);\n}\n\nexport async function inspectContainerStatus(name: string): Promise<ContainerRuntimeState> {\n const result = await execa('docker', ['inspect', '--format', '{{.State.Status}}', name], {\n reject: false,\n });\n if (result.exitCode !== 0) return 'missing';\n const status = (result.stdout ?? '').trim();\n switch (status) {\n case 'running':\n return 'running';\n case 'paused':\n return 'paused';\n case 'created':\n case 'exited':\n case 'dead':\n case 'restarting':\n case 'removing':\n return 'stopped';\n default:\n return 'missing';\n }\n}\n\nexport async function inspectContainer(name: string): Promise<unknown | null> {\n const result = await execa('docker', ['inspect', name], { reject: false });\n if (result.exitCode !== 0) return null;\n try {\n const parsed = JSON.parse(result.stdout ?? 'null') as unknown[];\n return Array.isArray(parsed) ? (parsed[0] ?? null) : null;\n } catch {\n return null;\n }\n}\n\nexport async function inspectVolumeMountpoint(name: string): Promise<string | null> {\n const result = await execa('docker', ['volume', 'inspect', '--format', '{{.Mountpoint}}', name], {\n reject: false,\n });\n if (result.exitCode !== 0) return null;\n return (result.stdout ?? '').trim() || null;\n}\n\nconst AGENTBOX_PREFIX = 'agentbox-';\n\nexport async function listAgentboxContainers(): Promise<string[]> {\n const result = await execa(\n 'docker',\n ['ps', '-a', '--filter', `name=^${AGENTBOX_PREFIX}`, '--format', '{{.Names}}'],\n { reject: false },\n );\n if (result.exitCode !== 0) return [];\n return (result.stdout ?? '')\n .split('\\n')\n .map((s) => s.trim())\n .filter((s) => s.startsWith(AGENTBOX_PREFIX));\n}\n\n/**\n * Resolve the host port Docker assigned to a `-p hostPort:containerPort` mapping\n * that used `hostPort=0`. Returns null when the port isn't published or the\n * container is gone. `docker port <name> 6080/tcp` prints e.g.\n * `127.0.0.1:54321` (one line per binding); we take the first.\n */\nexport async function publishedHostPort(\n container: string,\n containerPort: number,\n): Promise<number | null> {\n const result = await execa('docker', ['port', container, `${String(containerPort)}/tcp`], {\n reject: false,\n });\n if (result.exitCode !== 0) return null;\n const first = (result.stdout ?? '').split('\\n')[0]?.trim();\n if (!first) return null;\n const m = /:(\\d+)$/.exec(first);\n return m ? Number(m[1]) : null;\n}\n\nexport async function listAgentboxVolumes(): Promise<string[]> {\n const result = await execa(\n 'docker',\n ['volume', 'ls', '--filter', `name=^${AGENTBOX_PREFIX}`, '--format', '{{.Name}}'],\n { reject: false },\n );\n if (result.exitCode !== 0) return [];\n return (result.stdout ?? '')\n .split('\\n')\n .map((s) => s.trim())\n .filter((s) => s.startsWith(AGENTBOX_PREFIX));\n}\n","import { mkdir, readFile, stat } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { execa } from 'execa';\nimport type { BoxStatus } from '@agentbox/ctl';\nimport { execInBox, inspectVolumeMountpoint } from './docker.js';\nimport type { BoxRecord } from './state.js';\n\nexport type DockerEngine = 'orbstack' | 'docker-desktop' | 'other';\n\n/** In-container paths bind-mounted to per-box host dirs by createBox. */\nexport const CONTAINER_EXPORT_MERGED = '/host-export';\nexport const CONTAINER_EXPORT_UPPER = '/host-export-upper';\n\n/** Layer the user wants to look at. */\nexport type ExportLayer = 'merged' | 'upper';\n\nexport interface HostPaths {\n /** Per-box runtime dir on host, e.g. ~/.agentbox/boxes/<id>. */\n boxDir: string;\n /** Snapshot target for the merged /workspace view. */\n mergedExport: string;\n /** Snapshot target for /upper/upper (used on engines without a live host path). */\n upperExport: string;\n /**\n * Native host path to the upper named volume's `upper/` subdir on OrbStack —\n * a live, zero-copy view of the writes layer. Null on Docker Desktop and any\n * engine where the volume isn't browsable from the Mac filesystem.\n */\n upperLiveOnHost: string | null;\n}\n\nlet cachedEngine: DockerEngine | null = null;\n\n/**\n * Inspect the docker daemon to decide which host-side conventions apply.\n * `docker info --format '{{.OperatingSystem}}'` returns strings like\n * \"OrbStack\" or \"Docker Desktop\" — we only care about those two on macOS.\n */\nexport async function detectEngine(): Promise<DockerEngine> {\n if (cachedEngine !== null) return cachedEngine;\n const result = await execa('docker', ['info', '--format', '{{.OperatingSystem}}'], {\n reject: false,\n });\n const os = (result.stdout ?? '').trim().toLowerCase();\n if (os.includes('orbstack')) cachedEngine = 'orbstack';\n else if (os.includes('docker desktop')) cachedEngine = 'docker-desktop';\n else cachedEngine = 'other';\n return cachedEngine;\n}\n\n/**\n * Pin the engine to a specific value, bypassing the `docker info` probe. Two\n * callers today:\n * 1. The CLI bootstrap (apps/cli) when the user has set `engine.kind` in\n * ~/.agentbox/config.yaml — the override applies for the rest of the\n * process so every `detectEngine()` returns the user's choice.\n * 2. Tests, via `__setEngineForTesting` (kept as an alias for back-compat).\n */\nexport function setEngineOverride(engine: DockerEngine | null): void {\n cachedEngine = engine;\n}\n\n/** @deprecated alias for `setEngineOverride`; kept so existing tests don't churn. */\nexport function __setEngineForTesting(engine: DockerEngine | null): void {\n cachedEngine = engine;\n}\n\nexport const BOXES_ROOT = join(homedir(), '.agentbox', 'boxes');\n\nexport function boxRunDirFor(id: string): string {\n return join(BOXES_ROOT, id);\n}\n\n/**\n * Per-box durable status file. The host relay writes it (atomic tmp+rename)\n * when the in-box daemon pushes a `box-status` snapshot; it persists here on\n * the host fs even while the box is paused/stopped. Path must stay in sync\n * with `boxStatusPathFor` in @agentbox/relay's status-store.\n */\nexport function boxStatusPathFor(id: string): string {\n return join(boxRunDirFor(id), 'status.json');\n}\n\n/**\n * Read the persisted box status, or null when there is none (box predates the\n * feature, relay never received a push, corrupt JSON, or a future-incompatible\n * schema). Never throws — callers fall back to live/“unknown”.\n */\nexport async function readBoxStatus(id: string): Promise<BoxStatus | null> {\n try {\n const raw = await readFile(boxStatusPathFor(id), 'utf8');\n const parsed = JSON.parse(raw) as BoxStatus;\n if (parsed.schema !== 1) return null;\n return parsed;\n } catch {\n return null;\n }\n}\n\nasync function pathExists(p: string): Promise<boolean> {\n try {\n await stat(p);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Host path to a subpath inside an OrbStack-managed named volume.\n *\n * OrbStack exposes named volumes at `~/OrbStack/docker/volumes/<name>/` —\n * note: NO `_data` subdir; volume contents appear directly under `<name>/`.\n * `docker volume inspect` reports the in-VM `/var/lib/docker/...` mountpoint\n * instead, which isn't reachable from macOS. Returns the path regardless of\n * whether it exists; callers stat it themselves.\n */\nexport function orbstackVolumePath(volume: string, ...sub: string[]): string {\n return join(homedir(), 'OrbStack', 'docker', 'volumes', volume, ...sub);\n}\n\n/**\n * Resolve the host-visible path to the upper volume's writes layer for live\n * browsing.\n *\n * Docker Desktop has no equivalent host path — returns null.\n */\nexport async function resolveUpperLiveOnHost(\n upperVolume: string,\n engine: DockerEngine,\n): Promise<string | null> {\n if (engine !== 'orbstack') return null;\n // Primary: OrbStack's documented shared folder. Contents of the volume sit\n // directly under <vol>/ — no _data wrapper.\n const orbPath = orbstackVolumePath(upperVolume, 'upper');\n if (await pathExists(orbPath)) return orbPath;\n // Fallback: if docker reports a real-looking host mountpoint (e.g. on Linux\n // hosts or unusual setups), trust it.\n const mp = await inspectVolumeMountpoint(upperVolume);\n if (mp && !mp.startsWith('/var/lib/docker')) {\n const candidate = join(mp, 'upper');\n if (await pathExists(candidate)) return candidate;\n }\n return null;\n}\n\nexport async function getHostPaths(\n record: Pick<BoxRecord, 'id' | 'upperVolume'>,\n engine?: DockerEngine,\n): Promise<HostPaths> {\n const eng = engine ?? (await detectEngine());\n const boxDir = boxRunDirFor(record.id);\n return {\n boxDir,\n mergedExport: join(boxDir, 'workspace'),\n upperExport: join(boxDir, 'upper'),\n upperLiveOnHost: await resolveUpperLiveOnHost(record.upperVolume, eng),\n };\n}\n\nexport interface RefreshOptions {\n layer: ExportLayer;\n /** When true, include /workspace/node_modules in the merged export. Off by default. */\n includeNodeModules?: boolean;\n}\n\nexport interface RefreshResult {\n /** Host path that now reflects the box's current state. */\n hostPath: string;\n /** True when an rsync/tar copy actually ran. False when the OrbStack live path was used directly. */\n copied: boolean;\n /** True when the box predates the /host-export bind and we used the tar-pipe fallback. */\n usedFallback: boolean;\n}\n\ninterface RefreshContext {\n hostBoxDir: string;\n hostTarget: string;\n containerSource: string;\n containerBind: string;\n excludeNodeModules: boolean;\n}\n\nasync function hasContainerPath(container: string, path: string): Promise<boolean> {\n const probe = await execInBox(container, ['test', '-d', path], { user: 'root' });\n return probe.exitCode === 0;\n}\n\n/**\n * Refresh a per-box host export so Finder sees the box's current state.\n *\n * Strategy:\n * - For OrbStack + layer=upper, no copy is needed — the named volume is live\n * on disk. Caller should prefer `hostPaths.upperLiveOnHost`.\n * - Otherwise rsync from the in-container source (`/workspace` or\n * `/upper/upper`) to the bind-mounted host dir (`/host-export` or\n * `/host-export-upper`).\n * - Boxes created before the bind-mounts existed fall back to streaming a\n * `tar | tar` through `docker exec` into the host dir directly.\n */\nexport async function refreshExport(\n record: Pick<BoxRecord, 'id' | 'container' | 'upperVolume'>,\n opts: RefreshOptions,\n): Promise<RefreshResult> {\n const engine = await detectEngine();\n const paths = await getHostPaths(record, engine);\n\n if (opts.layer === 'upper' && engine === 'orbstack' && paths.upperLiveOnHost) {\n await mkdir(paths.boxDir, { recursive: true });\n return { hostPath: paths.upperLiveOnHost, copied: false, usedFallback: false };\n }\n\n const ctx: RefreshContext =\n opts.layer === 'merged'\n ? {\n hostBoxDir: paths.boxDir,\n hostTarget: paths.mergedExport,\n containerSource: '/workspace',\n containerBind: CONTAINER_EXPORT_MERGED,\n excludeNodeModules: !opts.includeNodeModules,\n }\n : {\n hostBoxDir: paths.boxDir,\n hostTarget: paths.upperExport,\n containerSource: '/upper/upper',\n containerBind: CONTAINER_EXPORT_UPPER,\n excludeNodeModules: false,\n };\n\n await mkdir(ctx.hostTarget, { recursive: true });\n\n const bindAvailable = await hasContainerPath(record.container, ctx.containerBind);\n if (bindAvailable) {\n const args = ['rsync', '-a', '--delete'];\n if (ctx.excludeNodeModules) args.push('--exclude=node_modules');\n args.push(`${ctx.containerSource}/`, `${ctx.containerBind}/`);\n const r = await execInBox(record.container, args, { user: 'root' });\n if (r.exitCode !== 0) {\n throw new ExportError(`rsync into ${ctx.containerBind} failed`, r.stdout, r.stderr);\n }\n return { hostPath: ctx.hostTarget, copied: true, usedFallback: false };\n }\n\n // Fallback for pre-existing boxes: stream a tar through docker exec into the\n // host target. Slower and skips the in-place delete that rsync gives us, but\n // it works without recreating the container.\n const excludes = ctx.excludeNodeModules ? ['--exclude=node_modules'] : [];\n const result = await execa(\n 'docker',\n ['exec', '--user', 'root', record.container, 'tar', '-cf', '-', ...excludes, '-C', ctx.containerSource, '.'],\n { reject: false, encoding: 'buffer' },\n );\n if (result.exitCode !== 0) {\n throw new ExportError(\n `tar from ${ctx.containerSource} failed`,\n '',\n typeof result.stderr === 'string' ? result.stderr : (result.stderr as Buffer).toString('utf8'),\n );\n }\n const extract = await execa('tar', ['-xf', '-', '-C', ctx.hostTarget], {\n input: result.stdout as Buffer,\n reject: false,\n });\n if (extract.exitCode !== 0) {\n throw new ExportError('tar extract on host failed', extract.stdout, extract.stderr);\n }\n return { hostPath: ctx.hostTarget, copied: true, usedFallback: true };\n}\n\n/**\n * Default env/config file basename globs for `pull env` / `pull --with-env`.\n * These are almost always gitignored, so a normal gitignore-aware `pull`\n * skips them; this list opts them back in explicitly. `agentbox.yaml` is\n * included so a file generated in-box by `/agentbox-setup` lands on the host\n * even before it's committed.\n */\nexport const DEFAULT_ENV_PATTERNS = [\n '.env',\n '.env.*',\n '.envrc',\n '.dev.vars',\n 'secrets.toml',\n 'local.settings.json',\n 'appsettings.*.json',\n 'agentbox.yaml',\n];\n\n/** Directories the env-file `find` prunes — heavy or never-relevant. */\nconst ENV_PRUNE_DIRS = [\n 'node_modules',\n '.git',\n '.venv',\n 'venv',\n '__pycache__',\n 'dist',\n '.next',\n 'build',\n];\n\n/**\n * Build the in-box `find` argv that enumerates env/config files by basename\n * glob, pruning `ENV_PRUNE_DIRS`. `-printf '%P\\0'` emits NUL-delimited paths\n * already relative to /workspace (so they feed rsync --files-from --from0\n * directly, exactly like `git ls-files -z`).\n */\nfunction buildEnvFindArgs(patterns: string[]): string[] {\n const nameGroup = (names: string[]): string[] => {\n const out: string[] = [];\n names.forEach((n, i) => {\n if (i > 0) out.push('-o');\n out.push('-name', n);\n });\n return out;\n };\n return [\n 'find',\n '/workspace',\n '(',\n '-type',\n 'd',\n '(',\n ...nameGroup(ENV_PRUNE_DIRS),\n ')',\n '-prune',\n ')',\n '-o',\n '(',\n '-type',\n 'f',\n '(',\n ...nameGroup(patterns),\n ')',\n '-printf',\n '%P\\\\0',\n ')',\n ];\n}\n\n/**\n * Host-side mirror of `buildEnvFindArgs` for the reverse direction (host →\n * box). Rooted at `.` (run with cwd = the host workspace) and uses `-print0`\n * instead of `-printf '%P\\0'` because macOS's BSD `find` has no `-printf`;\n * `./relpath` entries feed `tar -C <workspace> --null -T -` directly, exactly\n * like the untracked-file pipe in git-worktree.ts.\n */\nexport function buildHostEnvFindArgs(patterns: string[]): string[] {\n const nameGroup = (names: string[]): string[] => {\n const out: string[] = [];\n names.forEach((n, i) => {\n if (i > 0) out.push('-o');\n out.push('-name', n);\n });\n return out;\n };\n return [\n 'find',\n '.',\n '(',\n '-type',\n 'd',\n '(',\n ...nameGroup(ENV_PRUNE_DIRS),\n ')',\n '-prune',\n ')',\n '-o',\n '(',\n '-type',\n 'f',\n '(',\n ...nameGroup(patterns),\n ')',\n '-print0',\n ')',\n ];\n}\n\nexport interface CopyHostEnvOptions {\n /** Target container name (must be running with the overlay mounted). */\n container: string;\n /** Absolute host workspace dir — the same dir that maps to /workspace. */\n workspaceDir: string;\n /** Basename globs to copy (normally DEFAULT_ENV_PATTERNS). */\n patterns: string[];\n onLog?: (line: string) => void;\n}\n\n/**\n * Copy the host's env/config files (selected by `patterns`, gitignore ignored)\n * into the running box's `/workspace`. The reverse of `pullToHost`'s env\n * segment. Writes land in the overlay's writable upper layer (the container is\n * up + mounted at call time), so they survive pause/stop/start.\n *\n * Best-effort: a tar/exec failure or an empty match set logs and returns the\n * count rather than throwing — a missing secret shouldn't abort an otherwise\n * healthy box. Files extract as uid 1000 so they're owned by `vscode` like the\n * rest of /workspace.\n */\nexport async function copyHostEnvFilesToBox(\n opts: CopyHostEnvOptions,\n): Promise<{ copied: number }> {\n const log = opts.onLog ?? (() => {});\n\n // Default (utf8) encoding: `find` output is NUL-delimited path text, and\n // `encoding:'buffer'` would hand back a Uint8Array whose .toString() is\n // comma-joined byte codes, not the paths.\n const found = await execa('find', buildHostEnvFindArgs(opts.patterns).slice(1), {\n cwd: opts.workspaceDir,\n reject: false,\n });\n if (found.exitCode !== 0) {\n log(`warning: env-file scan failed: ${String(found.stderr).slice(0, 300)}`);\n return { copied: 0 };\n }\n const list = String(found.stdout)\n .split('\\0')\n .filter((p) => p.length > 0);\n if (list.length === 0) return { copied: 0 };\n\n // Same fork-and-stream as the untracked-file carry-over in git-worktree.ts.\n const packed = await execa('tar', ['-C', opts.workspaceDir, '--null', '-T', '-', '-cf', '-'], {\n input: list.join('\\0'),\n encoding: 'buffer',\n reject: false,\n });\n if (packed.exitCode !== 0) {\n log(`warning: env-file tar pack failed: ${String(packed.stderr).slice(0, 300)}`);\n return { copied: 0 };\n }\n const extract = await execa(\n 'docker',\n ['exec', '-i', '--user', '1000:1000', opts.container, 'tar', '-xf', '-', '-C', '/workspace'],\n { input: packed.stdout as Buffer, reject: false },\n );\n if (extract.exitCode !== 0) {\n log(`warning: env-file copy into box failed: ${String(extract.stderr).slice(0, 300)}`);\n return { copied: 0 };\n }\n return { copied: list.length };\n}\n\nexport interface PullOptions {\n /** Default true. When false, skip git ls-files and use the static exclude-list. */\n respectGitignore?: boolean;\n /** Default false. When true, don't filter node_modules even in fallback mode. */\n includeNodeModules?: boolean;\n /** Default false. Skip the initial refreshExport — pull whatever's already in the scratch dir. */\n noRefresh?: boolean;\n /** Default false. Run rsync with --dry-run; return the change list without writing. */\n dryRun?: boolean;\n /**\n * Extra env/config files to pull, selected by these basename globs via an\n * in-box `find` (heavy dirs pruned). Composes WITH gitignore selection: the\n * rsync file list is the union of the git-tracked set (unless\n * respectGitignore is false) and these matches. Empty/undefined = no env\n * segment.\n */\n envPatterns?: string[];\n}\n\nexport interface PullResult {\n /** Absolute host workspace path the pull targeted (record.workspacePath). */\n hostPath: string;\n /** Per-file rsync change list (itemized `-i` lines, transfers/deletes only). */\n changes: string[];\n /** True when an actual write happened. False on dry-run. */\n applied: boolean;\n /** True when gitignore-mode was used (vs. the fallback exclude-list). */\n usedGitignore: boolean;\n}\n\n/**\n * Keep only itemized lines that represent an actual file transfer or delete.\n * rsync `-i` emits a leading 11-char code: char 0 is the update type\n * (`>`/`<`/`c`/`*` = transfer/change/delete; `.` = attr-only, skipped) and\n * char 1 is the entry type (`f` file, `d` dir, ...). Directory lines (`d`)\n * are pruned: rsync creates parent dirs as a side effect of transferring\n * files, so counting them would overstate \"files changed\".\n */\nfunction parseItemizedChanges(stdout: string): string[] {\n return stdout\n .split('\\n')\n .map((l) => l.trimEnd())\n .filter((l) => l.length > 0)\n .filter((l) => {\n const code = l[0];\n const kind = l[1];\n return (code === '>' || code === '<' || code === 'c' || code === '*') && kind !== 'd';\n });\n}\n\n/**\n * Reverse of `refreshExport`: bring the box's merged `/workspace` view back\n * into the user's actual host working directory (`record.workspacePath`).\n *\n * Two-stage: (1) `refreshExport` materializes `/workspace` in the per-box\n * scratch dir (`~/.agentbox/boxes/<id>/workspace`) — that path is the only\n * way to read the in-container FUSE overlay from the Mac; (2) a host-side\n * rsync copies scratch → `workspacePath`.\n *\n * Filtering: by default we ask git *inside the box* which files it would\n * track (`git ls-files --cached --others --exclude-standard`) so node_modules\n * / build dirs / gitignored secrets never leak back. Non-git workspaces (or\n * `respectGitignore: false`) fall back to a static `--exclude` list.\n *\n * Never passes `--delete`: files that exist on the host but not in the box\n * are preserved. Removals are the user's call.\n */\nexport async function pullToHost(\n record: Pick<BoxRecord, 'id' | 'container' | 'upperVolume' | 'workspacePath'>,\n opts: PullOptions = {},\n): Promise<PullResult> {\n const engine = await detectEngine();\n const paths = await getHostPaths(record, engine);\n\n let scratchDir: string;\n if (opts.noRefresh) {\n scratchDir = paths.mergedExport;\n await mkdir(scratchDir, { recursive: true });\n } else {\n const refreshed = await refreshExport(record, {\n layer: 'merged',\n includeNodeModules: opts.includeNodeModules,\n });\n scratchDir = refreshed.hostPath;\n }\n\n // The rsync file list is the union of up to two independent NUL-delimited\n // segments: git-tracked (gitignore-aware) and env-pattern (gitignore\n // bypassed). If neither is produced we fall through to the static\n // exclude-list (non-git workspace, no env patterns).\n const segments: string[] = [];\n let usedGitignore = false;\n if (opts.respectGitignore !== false) {\n const isGit = await execInBox(\n record.container,\n ['git', '-C', '/workspace', 'rev-parse', '--is-inside-work-tree'],\n { user: 'root' },\n );\n if (isGit.exitCode === 0 && isGit.stdout.trim() === 'true') {\n const ls = await execInBox(\n record.container,\n ['git', '-C', '/workspace', 'ls-files', '-z', '--cached', '--others', '--exclude-standard'],\n { user: 'root' },\n );\n if (ls.exitCode !== 0) {\n throw new ExportError('git ls-files in box failed', ls.stdout, ls.stderr);\n }\n // git -z is NUL-delimited; rsync --from0 wants the same.\n const tracked = ls.stdout.replace(/\\0$/, '');\n if (tracked.length > 0) segments.push(tracked);\n usedGitignore = true;\n }\n }\n if (opts.envPatterns && opts.envPatterns.length > 0) {\n const found = await execInBox(\n record.container,\n buildEnvFindArgs(opts.envPatterns),\n { user: 'root' },\n );\n if (found.exitCode !== 0) {\n throw new ExportError('find env files in box failed', found.stdout, found.stderr);\n }\n const envFiles = found.stdout.replace(/\\0$/, '');\n if (envFiles.length > 0) segments.push(envFiles);\n }\n const fileList =\n segments.length > 0\n ? Array.from(new Set(segments.join('\\0').split('\\0'))).join('\\0')\n : null;\n\n // --checksum, not the default size+mtime quick-check: the box runs on a\n // fresh git worktree so every file's mtime differs from the user's working\n // tree even when the content is byte-identical. Without -c, rsync would\n // \"update\" the entire tree. -c compares content hashes so only genuinely\n // changed files are written.\n const baseArgs = ['-a', '--checksum'];\n if (fileList === null) {\n baseArgs.push('--exclude=.git');\n if (!opts.includeNodeModules) baseArgs.push('--exclude=node_modules');\n } else {\n baseArgs.push('--files-from=-', '--from0');\n }\n const src = `${scratchDir}/`;\n const dst = `${record.workspacePath}/`;\n\n const dry = await execa('rsync', [...baseArgs, '--dry-run', '-i', src, dst], {\n reject: false,\n input: fileList !== null ? fileList : undefined,\n });\n if (dry.exitCode !== 0) {\n throw new ExportError('rsync dry-run failed', dry.stdout, dry.stderr);\n }\n const changes = parseItemizedChanges(dry.stdout);\n\n if (opts.dryRun) {\n return { hostPath: record.workspacePath, changes, applied: false, usedGitignore };\n }\n\n const real = await execa('rsync', [...baseArgs, src, dst], {\n reject: false,\n input: fileList !== null ? fileList : undefined,\n });\n if (real.exitCode !== 0) {\n throw new ExportError(`rsync into ${record.workspacePath} failed`, real.stdout, real.stderr);\n }\n return { hostPath: record.workspacePath, changes, applied: true, usedGitignore };\n}\n\nexport interface OpenOptions extends RefreshOptions {\n /** When true, skip rsync and just open whatever's already on disk. */\n noRefresh?: boolean;\n /** When true, refresh as usual but don't launch macOS `open` on the resulting path. */\n noOpen?: boolean;\n}\n\nexport interface OpenResult {\n hostPath: string;\n copied: boolean;\n usedFallback: boolean;\n engine: DockerEngine;\n}\n\n/**\n * Refresh the requested export (unless suppressed) and launch the macOS\n * `open` command on it. Returns the host path that was opened.\n *\n * Set `noOpen: true` to refresh and return the path without launching\n * Finder — used by `agentbox open --print` so scripted callers get a\n * fresh path in one call.\n */\nexport async function openInFinder(\n record: Pick<BoxRecord, 'id' | 'container' | 'upperVolume'>,\n opts: OpenOptions,\n): Promise<OpenResult> {\n const engine = await detectEngine();\n let hostPath: string;\n let copied = false;\n let usedFallback = false;\n\n if (opts.noRefresh) {\n const paths = await getHostPaths(record, engine);\n if (opts.layer === 'upper' && engine === 'orbstack' && paths.upperLiveOnHost) {\n hostPath = paths.upperLiveOnHost;\n } else {\n hostPath = opts.layer === 'merged' ? paths.mergedExport : paths.upperExport;\n await mkdir(hostPath, { recursive: true });\n }\n } else {\n const refreshed = await refreshExport(record, opts);\n hostPath = refreshed.hostPath;\n copied = refreshed.copied;\n usedFallback = refreshed.usedFallback;\n }\n\n if (!opts.noOpen) {\n const opened = await execa('open', [hostPath], { reject: false });\n if (opened.exitCode !== 0) {\n throw new ExportError(`open ${hostPath} failed`, opened.stdout, opened.stderr);\n }\n }\n\n return { hostPath, copied, usedFallback, engine };\n}\n\nexport class ExportError extends Error {\n constructor(\n message: string,\n public readonly stdout: string,\n public readonly stderr: string,\n ) {\n super(`${message}${stderr ? `: ${stderr.trim()}` : ''}`);\n this.name = 'ExportError';\n }\n}\n","import { execa } from 'execa';\nimport { existsSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport { dirname, resolve } from 'node:path';\n\nexport const DEFAULT_BOX_IMAGE = 'agentbox/box:dev';\n\nconst here = dirname(fileURLToPath(import.meta.url));\n\n// The Dockerfile's COPY lines reference monorepo-relative paths\n// (packages/ctl/dist/bin.cjs, apps/cli/share/..., packages/sandbox-docker/scripts/*),\n// so the build context must be a dir containing that tree.\n//\n// Resolution order:\n// 0. AGENTBOX_DOCKER_CONTEXT env override (dir holding Dockerfile.box).\n// 1. Staged context shipped with the bundled `agent-box` package: this\n// module is bundled into the CLI at <root>/dist, the stage step mirrors\n// the COPY tree at <root>/runtime/docker (sibling of dist/, uniform in\n// dev and when installed).\n// 2. Legacy monorepo: Dockerfile.box at the sandbox-docker package root,\n// build context = monorepo root.\nfunction resolveDockerBuild(): { dockerfile: string; context: string } {\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 staged = resolve(here, '..', 'runtime', 'docker');\n if (existsSync(resolve(staged, 'Dockerfile.box'))) {\n return { dockerfile: resolve(staged, 'Dockerfile.box'), context: staged };\n }\n // Legacy: src/ (or the unbundled package dist/) is one level under the\n // package root; the monorepo root is two more up.\n const packageRoot = resolve(here, '..');\n return {\n dockerfile: resolve(packageRoot, 'Dockerfile.box'),\n context: resolve(packageRoot, '..', '..'),\n };\n}\n\nconst { dockerfile: DOCKERFILE_PATH_RESOLVED, context: BUILD_CONTEXT_DIR_RESOLVED } =\n resolveDockerBuild();\nexport const DOCKERFILE_PATH = DOCKERFILE_PATH_RESOLVED;\nexport const BUILD_CONTEXT_DIR = BUILD_CONTEXT_DIR_RESOLVED;\n\nexport async function imageExists(ref: string): Promise<boolean> {\n const result = await execa('docker', ['image', 'inspect', ref], { reject: false });\n return result.exitCode === 0;\n}\n\nexport interface BuildImageOptions {\n ref?: string;\n dockerfile?: string;\n contextDir?: string;\n onProgress?: (line: string) => void;\n}\n\nexport async function buildImage(opts: BuildImageOptions = {}): Promise<string> {\n const ref = opts.ref ?? DEFAULT_BOX_IMAGE;\n const dockerfile = opts.dockerfile ?? DOCKERFILE_PATH;\n const contextDir = opts.contextDir ?? BUILD_CONTEXT_DIR;\n\n const subprocess = execa('docker', ['build', '-t', ref, '-f', dockerfile, contextDir], {\n stderr: 'pipe',\n stdout: 'pipe',\n });\n\n if (opts.onProgress) {\n const forward = (chunk: Buffer | string): void => {\n const text = typeof chunk === 'string' ? chunk : chunk.toString('utf8');\n for (const line of text.split(/\\r?\\n/)) {\n if (line.length > 0) opts.onProgress?.(line);\n }\n };\n subprocess.stdout?.on('data', forward);\n subprocess.stderr?.on('data', forward);\n }\n\n await subprocess;\n return ref;\n}\n\nexport interface EnsureImageOptions {\n onProgress?: (line: string) => void;\n /** Dockerfile path. Defaults to `Dockerfile.box` next to this package. */\n dockerfile?: string;\n /** Build context directory. Defaults to the monorepo root. */\n contextDir?: string;\n}\n\nexport async function ensureImage(\n ref: string = DEFAULT_BOX_IMAGE,\n opts: EnsureImageOptions = {},\n): Promise<{ ref: string; built: boolean }> {\n if (await imageExists(ref)) {\n return { ref, built: false };\n }\n await buildImage({\n ref,\n dockerfile: opts.dockerfile,\n contextDir: opts.contextDir,\n onProgress: opts.onProgress,\n });\n return { ref, built: true };\n}\n\n","import { mkdir, readFile, readdir, rm, writeFile } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { execa } from 'execa';\nimport { hashProjectPath, setConfigValue } from '@agentbox/config';\nimport { ensureVolume } from './docker.js';\nimport { DEFAULT_BOX_IMAGE } from './image.js';\nimport type { BoxRecord } from './state.js';\n\nexport const CHECKPOINTS_ROOT = join(homedir(), '.agentbox', 'checkpoints');\n\n/** All per-project checkpoint volumes share this prefix (prune allowlist). */\nexport const CHECKPOINT_VOLUME_PREFIX = 'agentbox-ckpt-';\n\n/** Read-only mount point of the per-project checkpoint volume inside a box. */\nexport const CHECKPOINT_MOUNT = '/agentbox-checkpoints';\n\n/**\n * One Docker volume per project; each checkpoint is a `<name>` subdir inside\n * it. Deterministic from the project root (same hash the per-project config\n * dir uses), so it survives box destroy and is shared read-only across boxes.\n * Pure — unit-tested directly.\n */\nexport function checkpointVolumeName(projectRoot: string): string {\n return `${CHECKPOINT_VOLUME_PREFIX}${hashProjectPath(projectRoot)}`;\n}\n\nexport type CheckpointType = 'layered' | 'merged';\n\nexport interface CheckpointManifest {\n schema: 1;\n name: string;\n type: CheckpointType;\n /**\n * For a layered checkpoint, the older checkpoint refs this delta stacks on\n * (upper-most first, base-most last) — i.e. the chain the *source* box was\n * built from. `[]` for a merged checkpoint (self-contained) or a layered\n * checkpoint taken from a box that itself started from bare host code.\n */\n parents: string[];\n base: 'worktree' | 'workspace';\n sourceBoxId: string;\n sourceBoxName: string;\n /** Per-project Docker volume the captured tree lives in (subdir = `name`). */\n volume: string;\n createdAt: string;\n}\n\nexport interface CheckpointInfo {\n name: string;\n /** Host dir holding `manifest.json` (`~/.agentbox/checkpoints/<hash>/<name>`). */\n dir: string;\n manifest: CheckpointManifest;\n}\n\n/** Resolved lower spec a new box should mount when starting from a checkpoint. */\nexport interface CheckpointLowerSpec {\n type: CheckpointType;\n /** The single per-project checkpoint volume (mounted ro once at CHECKPOINT_MOUNT). */\n volume: string;\n /**\n * Checkpoint subdir names within `volume`, upper-most first. For `layered`\n * the caller appends the base lower (`/host-src`) after these; for `merged`\n * this is the sole lower (single entry).\n */\n subpaths: string[];\n /** Checkpoint refs composing the chain, base-most last (for BoxRecord.checkpointSource). */\n chain: string[];\n}\n\nexport function projectCheckpointsDir(projectRoot: string): string {\n return join(CHECKPOINTS_ROOT, hashProjectPath(projectRoot));\n}\n\nfunction checkpointDir(projectRoot: string, name: string): string {\n return join(projectCheckpointsDir(projectRoot), name);\n}\n\nasync function readManifest(dir: string): Promise<CheckpointManifest | null> {\n try {\n const raw = await readFile(join(dir, 'manifest.json'), 'utf8');\n const m = JSON.parse(raw) as CheckpointManifest;\n if (m.schema !== 1) return null;\n return m;\n } catch {\n return null;\n }\n}\n\nexport async function listCheckpoints(projectRoot: string): Promise<CheckpointInfo[]> {\n const root = projectCheckpointsDir(projectRoot);\n let entries: string[];\n try {\n entries = (await readdir(root, { withFileTypes: true }))\n .filter((e) => e.isDirectory())\n .map((e) => e.name);\n } catch {\n return [];\n }\n const out: CheckpointInfo[] = [];\n for (const name of entries) {\n const dir = join(root, name);\n const manifest = await readManifest(dir);\n if (manifest) out.push({ name, dir, manifest });\n }\n out.sort((a, b) => a.manifest.createdAt.localeCompare(b.manifest.createdAt));\n return out;\n}\n\nexport async function resolveCheckpoint(\n projectRoot: string,\n ref: string,\n): Promise<CheckpointInfo | null> {\n const dir = checkpointDir(projectRoot, ref);\n const manifest = await readManifest(dir);\n if (!manifest) return null;\n return { name: ref, dir, manifest };\n}\n\nexport async function removeCheckpoint(projectRoot: string, ref: string): Promise<boolean> {\n const dir = checkpointDir(projectRoot, ref);\n const manifest = await readManifest(dir);\n if (!manifest) return false;\n await rm(dir, { recursive: true, force: true });\n // Delete only this checkpoint's subdir; the per-project volume stays for the\n // project's other checkpoints. Best-effort (volume may already be gone).\n const volume = manifest.volume || checkpointVolumeName(projectRoot);\n await execa(\n 'docker',\n ['run', '--rm', '--user', '0:0', '-v', `${volume}:/dst`, DEFAULT_BOX_IMAGE, 'rm', '-rf', `/dst/${ref}`],\n { reject: false },\n );\n return true;\n}\n\n/**\n * Next `<boxName>-<n>` given the names already present. Monotonic per\n * box-name; gaps from deleted checkpoints are skipped (max+1, never\n * recycled). Pure — unit-tested directly.\n */\nexport function computeNextCheckpointName(existingNames: string[], boxName: string): string {\n const re = new RegExp(`^${boxName.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}-(\\\\d+)$`);\n let max = 0;\n for (const n of existingNames) {\n const m = re.exec(n);\n if (m) max = Math.max(max, Number(m[1]));\n }\n return `${boxName}-${String(max + 1)}`;\n}\n\nasync function nextCheckpointName(projectRoot: string, boxName: string): Promise<string> {\n const existing = await listCheckpoints(projectRoot);\n return computeNextCheckpointName(\n existing.map((c) => c.name),\n boxName,\n );\n}\n\nfunction chainDepth(box: BoxRecord): number {\n return box.checkpointSource?.chain.length ?? 0;\n}\n\n/** Quote a string for safe single-quoted embedding in a bash -lc script. */\nfunction shq(s: string): string {\n return `'${s.replace(/'/g, `'\\\\''`)}'`;\n}\n\nexport interface CreateCheckpointOptions {\n box: BoxRecord;\n projectRoot: string;\n name?: string;\n merged?: boolean;\n setDefault?: boolean;\n /** checkpoint.maxLayers — auto-merge when the source chain is at/over this. */\n maxLayers: number;\n onLog?: (line: string) => void;\n}\n\n/**\n * Capture a box's accumulated state as a project checkpoint, into a `<name>`\n * subdir of the per-project Docker volume.\n *\n * - `layered`: copy the box's overlay write delta (`/upper/upper`, which now\n * holds node_modules/build caches/env files) volume→volume in a throwaway\n * root container. The destination is ext4, so overlay char-device whiteouts\n * survive `cp -a` natively (no `.wh.` translation needed) and the copy\n * never crosses the VM↔host bridge.\n * - `merged`: tar the box's merged `/workspace` (everything) into the subdir,\n * used later as a single sole lower.\n *\n * Merged is chosen when `--merged` is passed or the source box's checkpoint\n * chain is already `>= maxLayers` deep (caps the lowerdir stack).\n */\nexport async function createCheckpoint(opts: CreateCheckpointOptions): Promise<CheckpointInfo> {\n const log = opts.onLog ?? (() => {});\n const { box } = opts;\n\n const type: CheckpointType =\n opts.merged === true || chainDepth(box) >= opts.maxLayers ? 'merged' : 'layered';\n const name = opts.name ?? (await nextCheckpointName(opts.projectRoot, box.name));\n const dir = checkpointDir(opts.projectRoot, name);\n if (await readManifest(dir)) {\n throw new CheckpointError(`checkpoint ${name} already exists (rm it first)`, '', '');\n }\n const volume = checkpointVolumeName(opts.projectRoot);\n await ensureVolume(volume);\n await mkdir(dir, { recursive: true });\n const qn = shq(name);\n\n if (type === 'layered') {\n log(`capturing upper delta of ${box.container} -> ${volume}/${name} (layered)`);\n // Volume→volume copy in a throwaway root container: all VM-local ext4, no\n // virtiofs bridge crossing, and overlay char-device whiteouts are\n // preserved as-is (fuse-overlayfs honors them in a lowerdir).\n const script = [\n 'set -u',\n `rm -rf /dst/${qn}`,\n `mkdir -p /dst/${qn}`,\n `cp -a /src/upper/. /dst/${qn}/ 2>/dev/null || true`,\n `ls -A /dst/${qn} >/dev/null`,\n ].join('\\n');\n const r = await execa(\n 'docker',\n [\n 'run',\n '--rm',\n '--user',\n '0:0',\n '-v',\n `${box.upperVolume}:/src:ro`,\n '-v',\n `${volume}:/dst`,\n box.image,\n 'bash',\n '-lc',\n script,\n ],\n { reject: false },\n );\n if (r.exitCode !== 0) {\n throw new CheckpointError(`failed to copy upper layer for ${box.name}`, r.stdout, r.stderr);\n }\n } else {\n log(`capturing merged /workspace of ${box.container} -> ${volume}/${name} (merged)`);\n const packed = await execa(\n 'docker',\n ['exec', '--user', 'root', box.container, 'tar', '-C', '/workspace', '-cf', '-', '.'],\n { reject: false, encoding: 'buffer' },\n );\n if (packed.exitCode !== 0) {\n throw new CheckpointError(\n `failed to tar merged /workspace for ${box.name} (is the box running?)`,\n '',\n typeof packed.stderr === 'string'\n ? packed.stderr\n : (packed.stderr as Buffer).toString('utf8'),\n );\n }\n const extract = await execa(\n 'docker',\n [\n 'run',\n '-i',\n '--rm',\n '--user',\n '0:0',\n '-v',\n `${volume}:/dst`,\n box.image,\n 'bash',\n '-lc',\n `set -u; rm -rf /dst/${qn}; mkdir -p /dst/${qn}; tar -xf - -C /dst/${qn}`,\n ],\n { input: packed.stdout as Buffer, reject: false },\n );\n if (extract.exitCode !== 0) {\n throw new CheckpointError(\n 'tar extract into checkpoint volume failed',\n extract.stdout,\n extract.stderr,\n );\n }\n }\n\n const base: 'worktree' | 'workspace' = (box.gitWorktrees ?? []).some((w) => w.kind === 'root')\n ? 'worktree'\n : 'workspace';\n const manifest: CheckpointManifest = {\n schema: 1,\n name,\n type,\n parents: type === 'layered' ? (box.checkpointSource?.chain ?? []) : [],\n base,\n sourceBoxId: box.id,\n sourceBoxName: box.name,\n volume,\n createdAt: new Date().toISOString(),\n };\n await writeFile(join(dir, 'manifest.json'), JSON.stringify(manifest, null, 2) + '\\n', 'utf8');\n\n if (opts.setDefault) {\n await setConfigValue('project', 'box.defaultCheckpoint', name, opts.projectRoot);\n log(`set project default checkpoint -> ${name}`);\n }\n\n return { name, dir, manifest };\n}\n\n/**\n * Resolve the lower spec a new box should stack when starting from checkpoint\n * `ref`. All layers in a chain live in the one per-project volume, so the box\n * mounts it once; `subpaths` are the per-layer subdir names (upper-most\n * first). For `layered` the caller appends the base lower after these; for\n * `merged` `subpaths` is the sole lower.\n */\nexport async function resolveCheckpointLower(\n projectRoot: string,\n ref: string,\n): Promise<CheckpointLowerSpec> {\n const head = await resolveCheckpoint(projectRoot, ref);\n if (!head) throw new CheckpointError(`checkpoint not found: ${ref}`, '', '');\n if (!head.manifest.volume) {\n throw new CheckpointError(\n `checkpoint ${ref} is a legacy host-dir checkpoint; recreate it`,\n '',\n '',\n );\n }\n const volume = head.manifest.volume;\n\n if (head.manifest.type === 'merged') {\n return { type: 'merged', volume, subpaths: [head.name], chain: [head.name] };\n }\n\n const subpaths = [head.name];\n const chain = [head.name];\n for (const parentRef of head.manifest.parents) {\n const p = await resolveCheckpoint(projectRoot, parentRef);\n if (!p) {\n throw new CheckpointError(\n `checkpoint ${ref} references missing parent ${parentRef}`,\n '',\n '',\n );\n }\n subpaths.push(p.name);\n chain.push(p.name);\n }\n return { type: 'layered', volume, subpaths, chain };\n}\n\nexport class CheckpointError extends Error {\n constructor(\n message: string,\n public readonly stdout: string,\n public readonly stderr: string,\n ) {\n super(`${message}${stderr ? `: ${stderr.trim()}` : ''}`);\n this.name = 'CheckpointError';\n }\n}\n","/**\n * Layered user config. The same shape is accepted at three layers:\n * - global ~/.agentbox/config.yaml\n * - project ~/.agentbox/projects/<hash>/config.yaml\n * - workspace defaults: block in ./agentbox.yaml\n *\n * Plus a CLI-flag layer at runtime. Precedence (highest wins):\n * cli > workspace > project > global > built-in defaults.\n */\n\nexport type IdeFlavor = 'vscode' | 'cursor' | 'auto';\nexport type EngineKind = 'orbstack' | 'docker-desktop' | 'other' | 'auto';\nexport type BrowserKind = 'agent-browser' | 'playwright' | 'both';\n\nexport interface UserConfig {\n box?: {\n hostSnapshot?: boolean;\n defaultCheckpoint?: string;\n withPlaywright?: boolean;\n withEnv?: boolean;\n vnc?: boolean;\n isolateClaudeConfig?: boolean;\n image?: string;\n dockerCacheShared?: boolean;\n memory?: number;\n cpus?: number;\n pidsLimit?: number;\n disk?: string;\n };\n checkpoint?: {\n maxLayers?: number;\n };\n claude?: {\n sessionName?: string;\n };\n code?: {\n ide?: IdeFlavor;\n wait?: boolean;\n timeoutMs?: number;\n autoTerminals?: boolean;\n };\n shell?: {\n user?: string;\n login?: boolean;\n };\n engine?: {\n kind?: EngineKind;\n };\n browser?: {\n default?: BrowserKind;\n };\n relay?: {\n port?: number;\n };\n vnc?: {\n containerPort?: number;\n };\n autopause?: {\n enabled?: boolean;\n maxRunningBoxes?: number;\n idleMinutes?: number;\n };\n maintenance?: {\n pruneProjectConfigs?: boolean;\n pruneProjectConfigsEvery?: number;\n };\n}\n\n/**\n * Required-everywhere variant returned as the merged effective config. Each\n * leaf is filled from BUILT_IN_DEFAULTS when no layer set it.\n *\n * `box.hostSnapshot` is intentionally `boolean | undefined` (unprompted): the\n * default is \"ask the user\", expressed as undefined.\n */\nexport interface EffectiveConfig {\n box: {\n hostSnapshot: boolean | undefined;\n defaultCheckpoint: string;\n withPlaywright: boolean;\n withEnv: boolean;\n vnc: boolean;\n isolateClaudeConfig: boolean;\n image: string;\n dockerCacheShared: boolean;\n memory: number;\n cpus: number;\n pidsLimit: number;\n disk: string;\n };\n checkpoint: {\n maxLayers: number;\n };\n claude: {\n sessionName: string;\n };\n code: {\n ide: IdeFlavor;\n wait: boolean;\n timeoutMs: number;\n autoTerminals: boolean;\n };\n shell: {\n user: string;\n login: boolean;\n };\n engine: {\n kind: EngineKind;\n };\n browser: {\n default: BrowserKind;\n };\n relay: {\n port: number;\n };\n vnc: {\n containerPort: number;\n };\n autopause: {\n enabled: boolean;\n maxRunningBoxes: number;\n idleMinutes: number;\n };\n maintenance: {\n pruneProjectConfigs: boolean;\n pruneProjectConfigsEvery: number;\n };\n}\n\nexport type ConfigSource = 'cli' | 'workspace' | 'project' | 'global' | 'default';\n\nexport interface ConfigLayer {\n source: ConfigSource;\n /** File path the layer was loaded from. Absent for `cli` and `default`. */\n path?: string;\n values: Partial<UserConfig>;\n}\n\nexport interface LoadedConfig {\n effective: EffectiveConfig;\n layers: {\n cli: { values: Partial<UserConfig> };\n workspace: { path: string | null; values: Partial<UserConfig> };\n project: { path: string; values: Partial<UserConfig> };\n global: { path: string; values: Partial<UserConfig> };\n defaults: EffectiveConfig;\n };\n /** Per-leaf source map: 'box.hostSnapshot' -> 'workspace'. Powers `config get --all`. */\n sources: Record<string, ConfigSource>;\n /** Resolved project root used for the project layer (cwd if no agentbox.yaml found). */\n projectRoot: string;\n projectHash: string;\n /** True if we walked up to an agentbox.yaml; false if we fell back to cwd. */\n hasAgentboxYaml: boolean;\n}\n\nexport const BUILT_IN_DEFAULTS: EffectiveConfig = {\n box: {\n hostSnapshot: undefined,\n defaultCheckpoint: '',\n withPlaywright: false,\n withEnv: false,\n vnc: true,\n isolateClaudeConfig: false,\n image: 'agentbox/box:dev',\n dockerCacheShared: false,\n memory: 0,\n cpus: 0,\n pidsLimit: 0,\n disk: '',\n },\n checkpoint: {\n maxLayers: 3,\n },\n claude: {\n sessionName: 'claude',\n },\n code: {\n ide: 'auto',\n wait: true,\n timeoutMs: 120_000,\n autoTerminals: true,\n },\n shell: {\n user: 'vscode',\n login: true,\n },\n engine: {\n kind: 'auto',\n },\n browser: {\n default: 'agent-browser',\n },\n relay: {\n port: 8787,\n },\n vnc: {\n containerPort: 6080,\n },\n autopause: {\n enabled: true,\n maxRunningBoxes: 5,\n idleMinutes: 5,\n },\n maintenance: {\n pruneProjectConfigs: true,\n pruneProjectConfigsEvery: 50,\n },\n};\n\nexport type KeyType = 'bool' | 'string' | 'int' | 'enum';\n\nexport interface KeyDescriptor {\n /** Dot-path, e.g. \"box.snapshot\". */\n key: string;\n type: KeyType;\n enumValues?: readonly string[];\n description: string;\n /** True for keys most users shouldn't touch (image, ports). Hidden from `list` by default. */\n advanced?: boolean;\n}\n\n/**\n * Single source of truth for which keys are addressable from the CLI. The\n * parser, `set`/`unset`, and `list` all walk this. Adding a key here is the\n * one place a new field has to be registered (plus the type interface above\n * and the JSON schema).\n */\nexport const KEY_REGISTRY: readonly KeyDescriptor[] = [\n {\n key: 'box.hostSnapshot',\n type: 'bool',\n description:\n 'Use a frozen APFS clone of the host workspace as the overlay lower (default: prompt). Was box.snapshot.',\n },\n {\n key: 'box.defaultCheckpoint',\n type: 'string',\n description:\n 'Checkpoint ref new boxes in this project start from when --snapshot is not given (set via `agentbox checkpoint set-default`).',\n },\n {\n key: 'checkpoint.maxLayers',\n type: 'int',\n description:\n 'Max stacked checkpoint layers before a new checkpoint is materialized merged (flattened) instead of layered.',\n advanced: true,\n },\n {\n key: 'box.withPlaywright',\n type: 'bool',\n description: 'Install @playwright/cli@latest in the box at create time.',\n },\n {\n key: 'box.withEnv',\n type: 'bool',\n description:\n 'Copy host env/config files (.env*, secrets.toml, agentbox.yaml, ...) into /workspace at box create time (gitignore-bypassing).',\n },\n {\n key: 'box.vnc',\n type: 'bool',\n description: 'Run the per-box Xvnc + noVNC stack.',\n },\n {\n key: 'box.isolateClaudeConfig',\n type: 'bool',\n description: 'Use a per-box ~/.claude volume instead of the shared one.',\n },\n {\n key: 'box.image',\n type: 'string',\n description: 'Box image ref (advanced).',\n advanced: true,\n },\n {\n key: 'box.dockerCacheShared',\n type: 'bool',\n description:\n \"Share the in-box docker image cache across boxes via the 'agentbox-docker-cache' volume (preserved on destroy/prune; only one box can run at a time when set).\",\n },\n {\n key: 'box.memory',\n type: 'int',\n description:\n 'Hard memory ceiling in MiB for new boxes (0 = unlimited). Use --memory on create/claude for byte/k/m/g strings.',\n },\n {\n key: 'box.cpus',\n type: 'int',\n description:\n 'CPU count cap for new boxes (0 = unlimited). Whole cores via config; use --cpus for fractional (e.g. 1.5).',\n },\n {\n key: 'box.pidsLimit',\n type: 'int',\n description: 'Max process count (PIDs cgroup) for new boxes (0 = unlimited).',\n },\n {\n key: 'box.disk',\n type: 'string',\n description:\n \"Best-effort writable-layer size for new boxes, e.g. '10G'. No-op on overlay2 / the macOS engines.\",\n advanced: true,\n },\n {\n key: 'claude.sessionName',\n type: 'string',\n description: 'tmux session name for `agentbox claude`.',\n },\n {\n key: 'code.ide',\n type: 'enum',\n enumValues: ['vscode', 'cursor', 'auto'] as const,\n description: 'Which IDE `agentbox code` launches; \"auto\" prefers code, falls back to cursor.',\n },\n {\n key: 'code.wait',\n type: 'bool',\n description: 'Block on agentbox-ctl wait-ready before opening the IDE.',\n },\n {\n key: 'code.timeoutMs',\n type: 'int',\n description: 'wait-ready timeout in milliseconds.',\n },\n {\n key: 'code.autoTerminals',\n type: 'bool',\n description: 'Generate /workspace/.vscode/tasks.json so the IDE auto-opens log panels.',\n },\n {\n key: 'shell.user',\n type: 'string',\n description: 'Default in-container user for `agentbox shell`.',\n },\n {\n key: 'shell.login',\n type: 'bool',\n description: 'Pass `-l` to bash so the login profile loads.',\n },\n {\n key: 'engine.kind',\n type: 'enum',\n enumValues: ['orbstack', 'docker-desktop', 'other', 'auto'] as const,\n description: 'Override the docker-engine auto-detection (used for OrbStack-only optimisations).',\n },\n {\n key: 'browser.default',\n type: 'enum',\n enumValues: ['agent-browser', 'playwright', 'both'] as const,\n description: 'Default browser stack inside the box. \"playwright\" or \"both\" implies box.withPlaywright.',\n },\n {\n key: 'relay.port',\n type: 'int',\n description: 'Host relay TCP port (advanced).',\n advanced: true,\n },\n {\n key: 'vnc.containerPort',\n type: 'int',\n description: 'Container-side noVNC port (advanced).',\n advanced: true,\n },\n {\n key: 'autopause.enabled',\n type: 'bool',\n description:\n 'Let the host relay periodically pause idle boxes when more than autopause.maxRunningBoxes are running.',\n },\n {\n key: 'autopause.maxRunningBoxes',\n type: 'int',\n description:\n 'Target maximum number of simultaneously-running boxes before idle ones get auto-paused.',\n },\n {\n key: 'autopause.idleMinutes',\n type: 'int',\n description:\n 'Minutes a box must be continuously idle (claude state) before it is eligible for auto-pause.',\n },\n {\n key: 'maintenance.pruneProjectConfigs',\n type: 'bool',\n description:\n 'Periodically delete ~/.agentbox/projects/<hash>/ dirs whose source workspace folder no longer exists.',\n },\n {\n key: 'maintenance.pruneProjectConfigsEvery',\n type: 'int',\n description: 'Run the orphan project-config sweep every N successful `agentbox create`.',\n },\n];\n\nconst REGISTRY_BY_KEY = new Map<string, KeyDescriptor>(KEY_REGISTRY.map((d) => [d.key, d]));\n\nexport function lookupKey(key: string): KeyDescriptor | undefined {\n return REGISTRY_BY_KEY.get(key);\n}\n\nexport class UserConfigError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'UserConfigError';\n }\n}\n\nexport type ConfigScope = 'global' | 'project';\n","import { parse as parseYaml } from 'yaml';\nimport {\n KEY_REGISTRY,\n type KeyDescriptor,\n type UserConfig,\n UserConfigError,\n} from './types.js';\n\nfunction isPlainObject(v: unknown): v is Record<string, unknown> {\n return typeof v === 'object' && v !== null && !Array.isArray(v);\n}\n\n/** Keys removed in a rename. Surfaced with a migration hint instead of a bare \"unknown key\". */\nconst RENAMED_KEYS: ReadonlyMap<string, string> = new Map([['box.snapshot', 'box.hostSnapshot']]);\n\ninterface BranchSpec {\n name: string;\n /** Map of leaf-key (dot-suffix) → descriptor whose `key` starts with this branch. */\n leaves: Map<string, KeyDescriptor>;\n}\n\nconst BRANCHES: Map<string, BranchSpec> = (() => {\n const out = new Map<string, BranchSpec>();\n for (const desc of KEY_REGISTRY) {\n const idx = desc.key.indexOf('.');\n if (idx < 0) {\n throw new Error(`KEY_REGISTRY entry ${desc.key} must use dot-path form (branch.leaf)`);\n }\n const branch = desc.key.slice(0, idx);\n const leaf = desc.key.slice(idx + 1);\n let entry = out.get(branch);\n if (!entry) {\n entry = { name: branch, leaves: new Map() };\n out.set(branch, entry);\n }\n entry.leaves.set(leaf, desc);\n }\n return out;\n})();\n\n/**\n * Coerce a typed YAML scalar (already typed by the YAML parser) into the\n * descriptor's expected type. Strings from the CLI go through `coerceFromString`\n * instead — that path accepts e.g. \"true\" or \"120000\".\n */\nfunction coerceTypedValue(raw: unknown, desc: KeyDescriptor, where: string): unknown {\n if (raw === null) {\n throw new UserConfigError(`${where} must not be null (use \\`agentbox config unset\\` to clear)`);\n }\n switch (desc.type) {\n case 'bool':\n if (typeof raw !== 'boolean') {\n throw new UserConfigError(`${where} must be a boolean (got ${typeof raw})`);\n }\n return raw;\n case 'string':\n if (typeof raw !== 'string') {\n throw new UserConfigError(`${where} must be a string (got ${typeof raw})`);\n }\n if (raw.length === 0) {\n throw new UserConfigError(`${where} must not be empty`);\n }\n return raw;\n case 'int':\n if (typeof raw !== 'number' || !Number.isInteger(raw)) {\n throw new UserConfigError(`${where} must be an integer (got ${String(raw)})`);\n }\n return raw;\n case 'enum':\n if (typeof raw !== 'string' || !desc.enumValues!.includes(raw)) {\n throw new UserConfigError(\n `${where} must be one of: ${desc.enumValues!.join(', ')} (got ${String(raw)})`,\n );\n }\n return raw;\n }\n}\n\n/**\n * Parse a UserConfig document text (YAML). Strict: unknown branches and\n * unknown leaves throw UserConfigError so typos surface early.\n *\n * `where` is the human-readable origin for error messages, e.g. the file path.\n * Empty / whitespace-only input parses to `{}`.\n */\nexport function parseUserConfig(text: string, where: string): Partial<UserConfig> {\n let doc: unknown;\n try {\n doc = parseYaml(text);\n } catch (err) {\n throw new UserConfigError(\n `${where}: yaml parse error: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n if (doc === null || doc === undefined) return {};\n if (!isPlainObject(doc)) {\n throw new UserConfigError(`${where}: top-level must be a mapping`);\n }\n return parseUserConfigObject(doc, where);\n}\n\n/**\n * Same validation as `parseUserConfig` but starting from an already-decoded\n * object. Used when the caller has the YAML parsed (e.g. agentbox.yaml's\n * `defaults:` block).\n */\nexport function parseUserConfigObject(doc: unknown, where: string): Partial<UserConfig> {\n if (doc === null || doc === undefined) return {};\n if (!isPlainObject(doc)) {\n throw new UserConfigError(`${where}: must be a mapping`);\n }\n\n const out: Partial<UserConfig> = {};\n for (const [branchName, branchRaw] of Object.entries(doc)) {\n const branchSpec = BRANCHES.get(branchName);\n if (!branchSpec) {\n throw new UserConfigError(\n `${where}: unknown config section \"${branchName}\" (known: ${[...BRANCHES.keys()].join(', ')})`,\n );\n }\n if (branchRaw === null || branchRaw === undefined) continue;\n if (!isPlainObject(branchRaw)) {\n throw new UserConfigError(`${where}.${branchName}: must be a mapping`);\n }\n const branchOut: Record<string, unknown> = {};\n for (const [leafName, leafRaw] of Object.entries(branchRaw)) {\n const desc = branchSpec.leaves.get(leafName);\n if (!desc) {\n const renamedTo = RENAMED_KEYS.get(`${branchName}.${leafName}`);\n if (renamedTo) {\n throw new UserConfigError(\n `${where}.${branchName}.${leafName} was renamed to ${renamedTo} — update your config`,\n );\n }\n throw new UserConfigError(\n `${where}.${branchName}: unknown key \"${leafName}\" (known: ${[...branchSpec.leaves.keys()].join(', ')})`,\n );\n }\n if (leafRaw === undefined) continue;\n branchOut[leafName] = coerceTypedValue(leafRaw, desc, `${where}.${desc.key}`);\n }\n if (Object.keys(branchOut).length > 0) {\n // We've validated that each branch matches one of UserConfig's known\n // sub-objects; the indexed write keeps the union type happy.\n (out as Record<string, unknown>)[branchName] = branchOut;\n }\n }\n return out;\n}\n\n/**\n * Coerce a string (e.g. typed at the CLI by `agentbox config set`) into the\n * declared type for `key`. Booleans accept true/false/yes/no/1/0 (case\n * insensitive). Returns the typed value or throws UserConfigError.\n */\nexport function coerceFromString(key: string, raw: string): unknown {\n const desc = lookupKeyOrThrow(key);\n switch (desc.type) {\n case 'bool': {\n const v = raw.trim().toLowerCase();\n if (v === 'true' || v === 'yes' || v === '1' || v === 'on') return true;\n if (v === 'false' || v === 'no' || v === '0' || v === 'off') return false;\n throw new UserConfigError(`${key}: expected a boolean (true/false), got \"${raw}\"`);\n }\n case 'string':\n if (raw.length === 0) throw new UserConfigError(`${key}: must not be empty`);\n return raw;\n case 'int': {\n const n = Number(raw);\n if (!Number.isFinite(n) || !Number.isInteger(n)) {\n throw new UserConfigError(`${key}: expected an integer, got \"${raw}\"`);\n }\n return n;\n }\n case 'enum':\n if (!desc.enumValues!.includes(raw)) {\n throw new UserConfigError(\n `${key}: expected one of ${desc.enumValues!.join(', ')}, got \"${raw}\"`,\n );\n }\n return raw;\n }\n}\n\nfunction lookupKeyOrThrow(key: string): KeyDescriptor {\n const renamedTo = RENAMED_KEYS.get(key);\n if (renamedTo) {\n throw new UserConfigError(`${key} was renamed to ${renamedTo} — use ${renamedTo} instead`);\n }\n const idx = key.indexOf('.');\n if (idx < 0) {\n throw new UserConfigError(`unknown key \"${key}\" (must be in branch.leaf form)`);\n }\n const branch = BRANCHES.get(key.slice(0, idx));\n if (!branch) {\n throw new UserConfigError(\n `unknown config section \"${key.slice(0, idx)}\" (known: ${[...BRANCHES.keys()].join(', ')})`,\n );\n }\n const desc = branch.leaves.get(key.slice(idx + 1));\n if (!desc) {\n throw new UserConfigError(\n `unknown key \"${key}\" (known in ${branch.name}: ${[...branch.leaves.keys()].join(', ')})`,\n );\n }\n return desc;\n}\n","import { createHash } from 'node:crypto';\nimport { realpath, stat } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { dirname, join, resolve } from 'node:path';\nimport type { ConfigScope } from './types.js';\n\nexport const STATE_DIR = join(homedir(), '.agentbox');\nexport const GLOBAL_CONFIG_FILE = join(STATE_DIR, 'config.yaml');\nexport const PROJECTS_DIR = join(STATE_DIR, 'projects');\nexport const WORKSPACE_CONFIG_BASENAME = 'agentbox.yaml';\n\nexport interface ProjectRoot {\n /** Absolute path to the resolved project root (host filesystem). */\n root: string;\n hasAgentboxYaml: boolean;\n}\n\n/**\n * Walk up from `cwd` until we find an `agentbox.yaml`. That dir is the\n * \"project\". If no ancestor has one, we fall back to `cwd` (per spec) so\n * `agentbox config` still does something sane in dirs without a workspace\n * file. The returned path is always absolute and **symlink-canonicalised**\n * via `realpath` — without this, macOS's `/tmp` symlink to `/private/tmp`\n * makes `findProjectRoot('/tmp/x')` (at create time, --workspace) and\n * `findProjectRoot(process.cwd())` (at resolve time, the same dir) return\n * different roots, breaking the per-project box index match.\n */\nexport async function findProjectRoot(cwd: string): Promise<ProjectRoot> {\n const start = await canonicalize(cwd);\n let dir = start;\n // Defensive cap on iterations: filesystem roots end with `dirname(x) === x`.\n for (let i = 0; i < 64; i++) {\n if (await fileExists(join(dir, WORKSPACE_CONFIG_BASENAME))) {\n return { root: dir, hasAgentboxYaml: true };\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return { root: start, hasAgentboxYaml: false };\n}\n\nasync function canonicalize(p: string): Promise<string> {\n const abs = resolve(p);\n // realpath only works for paths that exist. cwd and create-time\n // workspaces always do; fall back to the resolved (non-canonicalised)\n // path for anything else (e.g. config get from a deleted dir).\n try {\n return await realpath(abs);\n } catch {\n return abs;\n }\n}\n\nasync function fileExists(p: string): Promise<boolean> {\n try {\n const st = await stat(p);\n return st.isFile();\n } catch {\n return false;\n }\n}\n\n/**\n * SHA-1 (first 16 hex chars) of the *normalised* absolute path. We strip a\n * single trailing slash so `/foo/` and `/foo` hash identically. Case is\n * preserved — macOS APFS is case-preserving and so is the user's intent.\n */\nexport function hashProjectPath(absPath: string): string {\n const normalised = absPath.length > 1 && absPath.endsWith('/')\n ? absPath.slice(0, -1)\n : absPath;\n return createHash('sha1').update(normalised).digest('hex').slice(0, 16);\n}\n\nexport function projectConfigDir(absPath: string): string {\n return join(PROJECTS_DIR, hashProjectPath(absPath));\n}\n\nexport function projectConfigFile(absPath: string): string {\n return join(projectConfigDir(absPath), 'config.yaml');\n}\n\nexport function projectMetaFile(absPath: string): string {\n return join(projectConfigDir(absPath), 'meta.json');\n}\n\nexport function workspaceConfigFile(workspacePath: string): string {\n return join(workspacePath, WORKSPACE_CONFIG_BASENAME);\n}\n\n/**\n * Resolve a file path for a given scope. For `global`, no cwd is needed;\n * for `project`, `cwd` selects which project hash. Workspace path uses the\n * resolved project root (the dir holding `agentbox.yaml`, or cwd as fallback).\n */\nexport async function configPathFor(\n scope: ConfigScope | 'workspace',\n cwd: string,\n): Promise<string> {\n if (scope === 'global') return GLOBAL_CONFIG_FILE;\n const root = await findProjectRoot(cwd);\n if (scope === 'project') return projectConfigFile(root.root);\n return workspaceConfigFile(root.root);\n}\n","import { readFile } from 'node:fs/promises';\nimport { parse as parseYaml } from 'yaml';\nimport {\n findProjectRoot,\n GLOBAL_CONFIG_FILE,\n hashProjectPath,\n projectConfigFile,\n workspaceConfigFile,\n} from './paths.js';\nimport { parseUserConfig, parseUserConfigObject } from './parse.js';\nimport {\n BUILT_IN_DEFAULTS,\n type ConfigSource,\n type EffectiveConfig,\n KEY_REGISTRY,\n type LoadedConfig,\n type UserConfig,\n} from './types.js';\n\n/**\n * ENOENT-tolerant read of a UserConfig file. Anything else propagates.\n */\nasync function loadOptionalUserConfig(path: string): Promise<Partial<UserConfig>> {\n let text: string;\n try {\n text = await readFile(path, 'utf8');\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return {};\n throw err;\n }\n return parseUserConfig(text, path);\n}\n\n/**\n * Read the `defaults:` block from `<workspacePath>/agentbox.yaml`. Returns\n * `{}` if the file is missing or has no `defaults:` key. Throws on YAML\n * parse errors or invalid `defaults:` content (so typos surface as soon as\n * the user runs anything in the workspace).\n *\n * The rest of `agentbox.yaml` is owned by `@agentbox/ctl` — we don't validate\n * it here and we don't depend on that package.\n */\nexport async function loadProjectAgentboxDefaults(\n workspacePath: string,\n): Promise<Partial<UserConfig>> {\n const path = workspaceConfigFile(workspacePath);\n let text: string;\n try {\n text = await readFile(path, 'utf8');\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return {};\n throw err;\n }\n let doc: unknown;\n try {\n doc = parseYaml(text);\n } catch {\n // The ctl parser will surface its own error on the next box action; we\n // only throw if defaults: is present and broken (validated below).\n return {};\n }\n if (doc === null || doc === undefined || typeof doc !== 'object' || Array.isArray(doc)) {\n return {};\n }\n const defaults = (doc as Record<string, unknown>)['defaults'];\n if (defaults === undefined || defaults === null) return {};\n return parseUserConfigObject(defaults, `${path} defaults`);\n}\n\nexport interface LoadEffectiveConfigOptions {\n /** Highest-precedence layer; values supplied by command-line flags. */\n cliOverrides?: Partial<UserConfig>;\n}\n\n/**\n * Load and merge all four config sources for the cwd. Per-leaf precedence\n * (highest wins): cli > workspace > project > global > built-in defaults.\n *\n * The returned `sources` map has one entry per leaf in the registry — useful\n * for `agentbox config get --all` to show provenance.\n */\nexport async function loadEffectiveConfig(\n cwd: string,\n opts: LoadEffectiveConfigOptions = {},\n): Promise<LoadedConfig> {\n const projectRoot = await findProjectRoot(cwd);\n const projectPath = projectConfigFile(projectRoot.root);\n const workspacePath = projectRoot.hasAgentboxYaml ? workspaceConfigFile(projectRoot.root) : null;\n\n const [globalValues, projectValues, workspaceValues] = await Promise.all([\n loadOptionalUserConfig(GLOBAL_CONFIG_FILE),\n loadOptionalUserConfig(projectPath),\n workspacePath ? loadProjectAgentboxDefaults(projectRoot.root) : Promise.resolve({}),\n ]);\n\n const cliValues = opts.cliOverrides ?? {};\n\n const { effective, sources } = mergeLayers({\n cli: cliValues,\n workspace: workspaceValues,\n project: projectValues,\n global: globalValues,\n });\n\n return {\n effective,\n layers: {\n cli: { values: cliValues },\n workspace: { path: workspacePath, values: workspaceValues },\n project: { path: projectPath, values: projectValues },\n global: { path: GLOBAL_CONFIG_FILE, values: globalValues },\n defaults: BUILT_IN_DEFAULTS,\n },\n sources,\n projectRoot: projectRoot.root,\n projectHash: hashProjectPath(projectRoot.root),\n hasAgentboxYaml: projectRoot.hasAgentboxYaml,\n };\n}\n\ninterface MergeInput {\n cli: Partial<UserConfig>;\n workspace: Partial<UserConfig>;\n project: Partial<UserConfig>;\n global: Partial<UserConfig>;\n}\n\n/**\n * Walk every key in KEY_REGISTRY, pick the highest-precedence layer that has\n * a leaf value, and record the source. Lower-precedence layers never\n * overwrite a higher-precedence definition; absent leaves don't shadow.\n */\nfunction mergeLayers(input: MergeInput): {\n effective: EffectiveConfig;\n sources: Record<string, ConfigSource>;\n} {\n // Deep-clone the defaults; we'll overwrite leaves in place.\n const effective: EffectiveConfig = JSON.parse(JSON.stringify(BUILT_IN_DEFAULTS)) as EffectiveConfig;\n const sources: Record<string, ConfigSource> = {};\n\n const layerOrder: Array<{ source: ConfigSource; values: Partial<UserConfig> }> = [\n { source: 'cli', values: input.cli },\n { source: 'workspace', values: input.workspace },\n { source: 'project', values: input.project },\n { source: 'global', values: input.global },\n ];\n\n for (const desc of KEY_REGISTRY) {\n const idx = desc.key.indexOf('.');\n const branch = desc.key.slice(0, idx);\n const leaf = desc.key.slice(idx + 1);\n\n let chosen: { source: ConfigSource; value: unknown } | null = null;\n for (const layer of layerOrder) {\n const v = readLeaf(layer.values, branch, leaf);\n if (v !== undefined) {\n chosen = { source: layer.source, value: v };\n break;\n }\n }\n\n if (chosen) {\n writeLeaf(effective, branch, leaf, chosen.value);\n sources[desc.key] = chosen.source;\n } else {\n sources[desc.key] = 'default';\n }\n }\n\n return { effective, sources };\n}\n\nfunction readLeaf(\n obj: Partial<UserConfig>,\n branch: string,\n leaf: string,\n): unknown {\n const b = (obj as Record<string, unknown>)[branch];\n if (b === undefined || b === null || typeof b !== 'object') return undefined;\n return (b as Record<string, unknown>)[leaf];\n}\n\nfunction writeLeaf(\n obj: EffectiveConfig,\n branch: string,\n leaf: string,\n value: unknown,\n): void {\n const b = (obj as unknown as Record<string, Record<string, unknown>>)[branch];\n if (!b) return; // BUILT_IN_DEFAULTS guarantees the branch exists\n b[leaf] = value;\n}\n","import { mkdir, readFile, rename, rm, stat, writeFile } from 'node:fs/promises';\nimport { dirname, isAbsolute, join } from 'node:path';\nimport { stringify as stringifyYaml } from 'yaml';\nimport {\n configPathFor,\n findProjectRoot,\n hashProjectPath,\n PROJECTS_DIR,\n projectConfigFile,\n projectMetaFile,\n} from './paths.js';\nimport { coerceFromString, parseUserConfig } from './parse.js';\nimport { type ConfigScope, lookupKey, type UserConfig, UserConfigError } from './types.js';\nimport { readdir } from 'node:fs/promises';\n\ninterface WriteResult {\n path: string;\n /** The value we coerced and stored, after string→typed conversion. */\n coerced: unknown;\n}\n\ninterface SetOptions {\n /**\n * When true (the CLI `set` path), accept a string and coerce. When false\n * (programmatic), accept any typed value and write it through after a\n * round-trip parse for validation.\n */\n raw?: boolean;\n}\n\n/**\n * Write a single key into the chosen scope's config file. Creates parent\n * dirs and (for project scope) the meta.json sidecar. Atomic via tmp-rename.\n */\nexport async function setConfigValue(\n scope: ConfigScope,\n key: string,\n value: unknown,\n cwd: string,\n opts: SetOptions = {},\n): Promise<WriteResult> {\n if (!lookupKey(key)) {\n throw new UserConfigError(`unknown key \"${key}\"`);\n }\n\n const coerced = opts.raw && typeof value === 'string'\n ? coerceFromString(key, value)\n : value;\n\n const path = await configPathFor(scope, cwd);\n const current = await readExistingDoc(path);\n setLeaf(current, key, coerced);\n // Re-parse to validate the merged document; any change that produces an\n // invalid file (shouldn't be possible here, but defence-in-depth) throws.\n parseUserConfig(stringifyYaml(current), path);\n await atomicWriteYaml(path, current);\n\n if (scope === 'project') {\n const root = (await findProjectRoot(cwd)).root;\n await touchProjectMeta(root);\n }\n\n return { path, coerced };\n}\n\n/**\n * Remove a key from the chosen scope's config file. Empty parent objects are\n * pruned so the file stays tidy. ENOENT is treated as success.\n */\nexport async function unsetConfigValue(\n scope: ConfigScope,\n key: string,\n cwd: string,\n): Promise<{ path: string; existed: boolean }> {\n if (!lookupKey(key)) {\n throw new UserConfigError(`unknown key \"${key}\"`);\n }\n const path = await configPathFor(scope, cwd);\n const current = await readExistingDoc(path);\n const existed = unsetLeaf(current, key);\n if (!existed) return { path, existed: false };\n await atomicWriteYaml(path, current);\n if (scope === 'project') {\n const root = (await findProjectRoot(cwd)).root;\n await touchProjectMeta(root);\n }\n return { path, existed: true };\n}\n\ninterface ProjectEntry {\n hash: string;\n originalPath: string;\n createdAt: string | null;\n lastSeenAt: string | null;\n configPath: string;\n hasConfigFile: boolean;\n}\n\n/**\n * Enumerate per-project config dirs. The meta.json's recorded\n * `originalPath` is what we report — the hash on disk is opaque.\n */\nexport async function listProjectsConfigured(): Promise<ProjectEntry[]> {\n let entries: string[];\n try {\n entries = await readdir(PROJECTS_DIR);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return [];\n throw err;\n }\n const out: ProjectEntry[] = [];\n for (const hash of entries) {\n if (!/^[0-9a-f]{16}$/.test(hash)) continue;\n const meta = await readMeta(hash);\n if (!meta) continue;\n const cfgPath = projectConfigFile(meta.originalPath);\n const hasConfig = await fileExists(cfgPath);\n out.push({\n hash,\n originalPath: meta.originalPath,\n createdAt: meta.createdAt,\n lastSeenAt: meta.lastSeenAt,\n configPath: cfgPath,\n hasConfigFile: hasConfig,\n });\n }\n out.sort((a, b) => a.originalPath.localeCompare(b.originalPath));\n return out;\n}\n\nexport interface PruneOrphanProjectConfigsOptions {\n dryRun?: boolean;\n /** Absolute project roots of live boxes — kept even if the folder is gone. */\n protectedPaths?: string[];\n}\n\nexport interface PruneOrphanProjectConfigsResult {\n removed: { hash: string; originalPath: string }[];\n dryRun: boolean;\n}\n\n/**\n * Delete `~/.agentbox/projects/<hash>/` dirs whose recorded `originalPath`\n * workspace folder no longer exists on disk. Conservative by construction:\n * only an ENOENT on `originalPath` counts as orphaned (a transient/permission\n * error is never treated as \"deleted\"), and any path in `protectedPaths` (the\n * project roots of still-live boxes) is left alone. Best-effort and\n * idempotent — a failed `rm` is swallowed.\n */\nexport async function pruneOrphanProjectConfigs(\n opts: PruneOrphanProjectConfigsOptions = {},\n): Promise<PruneOrphanProjectConfigsResult> {\n const dryRun = opts.dryRun ?? false;\n const keep = new Set(opts.protectedPaths ?? []);\n const removed: { hash: string; originalPath: string }[] = [];\n for (const entry of await listProjectsConfigured()) {\n if (!isAbsolute(entry.originalPath) || keep.has(entry.originalPath)) continue;\n let missing = false;\n try {\n await stat(entry.originalPath);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') missing = true;\n }\n if (!missing) continue;\n removed.push({ hash: entry.hash, originalPath: entry.originalPath });\n if (!dryRun) {\n try {\n // Remove by the on-disk hash dir name (originalPath is gone, so\n // recomputing the hash from it would be pointless).\n await rm(join(PROJECTS_DIR, entry.hash), { recursive: true, force: true });\n } catch {\n /* best-effort */\n }\n }\n }\n return { removed, dryRun };\n}\n\n/**\n * Sidecar counter for the periodic create-time sweep. Lives inside\n * `PROJECTS_DIR` but `listProjectsConfigured` only reads 16-hex-named dirs, so\n * a dotfile here is invisible to it.\n */\nconst PROJECT_GC_COUNTER_FILE = join(PROJECTS_DIR, '.gc.json');\n\n/** Read `{creates}` (0 if missing/corrupt), increment, atomic-write, return new value. */\nexport async function bumpProjectGcCounter(): Promise<number> {\n let prior = 0;\n try {\n const parsed = JSON.parse(await readFile(PROJECT_GC_COUNTER_FILE, 'utf8')) as {\n creates?: unknown;\n };\n if (typeof parsed.creates === 'number' && Number.isFinite(parsed.creates)) {\n prior = parsed.creates;\n }\n } catch {\n /* missing or corrupt -> start from 0 */\n }\n const next = prior + 1;\n await mkdir(PROJECTS_DIR, { recursive: true });\n const tmp = `${PROJECT_GC_COUNTER_FILE}.tmp-${process.pid.toString()}-${Date.now().toString(36)}`;\n await writeFile(tmp, JSON.stringify({ creates: next }) + '\\n', { encoding: 'utf8', mode: 0o644 });\n await rename(tmp, PROJECT_GC_COUNTER_FILE);\n return next;\n}\n\nasync function readMeta(\n hash: string,\n): Promise<{ originalPath: string; createdAt: string | null; lastSeenAt: string | null } | null> {\n const metaPath = `${PROJECTS_DIR}/${hash}/meta.json`;\n try {\n const text = await readFile(metaPath, 'utf8');\n const parsed = JSON.parse(text) as Record<string, unknown>;\n if (typeof parsed['originalPath'] !== 'string') return null;\n return {\n originalPath: parsed['originalPath'],\n createdAt: typeof parsed['createdAt'] === 'string' ? parsed['createdAt'] : null,\n lastSeenAt: typeof parsed['lastSeenAt'] === 'string' ? parsed['lastSeenAt'] : null,\n };\n } catch {\n return null;\n }\n}\n\nasync function fileExists(p: string): Promise<boolean> {\n try {\n const st = await stat(p);\n return st.isFile();\n } catch {\n return false;\n }\n}\n\nasync function readExistingDoc(path: string): Promise<Partial<UserConfig>> {\n let text: string;\n try {\n text = await readFile(path, 'utf8');\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return {};\n throw err;\n }\n return parseUserConfig(text, path);\n}\n\nfunction setLeaf(doc: Partial<UserConfig>, key: string, value: unknown): void {\n const idx = key.indexOf('.');\n const branch = key.slice(0, idx);\n const leaf = key.slice(idx + 1);\n const root = doc as unknown as Record<string, Record<string, unknown>>;\n if (!root[branch] || typeof root[branch] !== 'object') {\n root[branch] = {};\n }\n root[branch][leaf] = value;\n}\n\nfunction unsetLeaf(doc: Partial<UserConfig>, key: string): boolean {\n const idx = key.indexOf('.');\n const branch = key.slice(0, idx);\n const leaf = key.slice(idx + 1);\n const root = doc as unknown as Record<string, Record<string, unknown>>;\n const b = root[branch];\n if (!b || typeof b !== 'object' || !(leaf in b)) return false;\n delete b[leaf];\n if (Object.keys(b).length === 0) {\n delete root[branch];\n }\n return true;\n}\n\nasync function atomicWriteYaml(path: string, doc: Partial<UserConfig>): Promise<void> {\n await mkdir(dirname(path), { recursive: true });\n // YAML serialises empty objects as `{}` which is correct but ugly; if the\n // doc is empty we still want a usable placeholder file.\n const text = Object.keys(doc).length === 0\n ? '# managed by agentbox config — empty\\n'\n : stringifyYaml(doc);\n const tmp = `${path}.tmp-${process.pid.toString()}-${Date.now().toString(36)}`;\n await writeFile(tmp, text, { encoding: 'utf8', mode: 0o644 });\n await rename(tmp, path);\n}\n\nasync function touchProjectMeta(absPath: string): Promise<void> {\n const dir = dirname(projectMetaFile(absPath));\n await mkdir(dir, { recursive: true });\n const metaPath = projectMetaFile(absPath);\n let prior: { originalPath?: string; createdAt?: string } = {};\n try {\n prior = JSON.parse(await readFile(metaPath, 'utf8')) as typeof prior;\n } catch {\n /* fresh file */\n }\n const now = new Date().toISOString();\n const next = {\n originalPath: absPath,\n hash: hashProjectPath(absPath),\n createdAt: prior.createdAt ?? now,\n lastSeenAt: now,\n };\n const tmp = `${metaPath}.tmp-${process.pid.toString()}-${Date.now().toString(36)}`;\n await writeFile(tmp, JSON.stringify(next, null, 2) + '\\n', { encoding: 'utf8', mode: 0o644 });\n await rename(tmp, metaPath);\n}\n\n// Re-export for ergonomics; same path resolution as the loader uses.\nexport { configPathFor };\n"],"mappings":";;;AAAA,SAAS,aAA0B;ACAnC,SAAS,SAAAA,QAAO,YAAAC,WAAU,QAAAC,aAAY;AACtC,SAAS,WAAAC,gBAAe;AACxB,SAAS,QAAAC,aAAY;AACrB,SAAS,SAAAC,cAAa;ACHtB,SAAS,SAAAA,cAAa;AACtB,SAAS,kBAAkB;AAC3B,SAAS,qBAAqB;AAC9B,SAAS,WAAAC,UAAS,WAAAC,gBAAe;ACHjC,SAAS,SAAAP,SAAO,YAAAC,YAAU,WAAAO,UAAS,MAAAC,KAAI,aAAAC,kBAAiB;AACxD,SAAS,WAAAP,iBAAe;AACxB,SAAS,QAAAC,cAAY;AACrB,SAAS,SAAAC,cAAa;;;AEHtB,SAAS,SAAS,iBAAiB;ACAnC,SAAS,kBAAkB;AAC3B,SAAS,UAAU,YAAY;AAC/B,SAAS,eAAe;AACxB,SAAS,SAAS,MAAM,eAAe;ACHvC,SAAS,gBAAgB;AACzB,SAAS,SAASM,kBAAiB;ACDnC,SAAS,OAAO,YAAAC,WAAU,QAAQ,IAAI,QAAAC,OAAM,iBAAiB;AAC7D,SAAS,WAAAC,UAAS,YAAY,QAAAC,aAAY;AAC1C,SAAS,aAAa,qBAAqB;AAW3C,SAAS,eAAe;AJ+IjB,IAAM,oBAAqC;EAChD,KAAK;IACH,cAAc;IACd,mBAAmB;IACnB,gBAAgB;IAChB,SAAS;IACT,KAAK;IACL,qBAAqB;IACrB,OAAO;IACP,mBAAmB;IACnB,QAAQ;IACR,MAAM;IACN,WAAW;IACX,MAAM;EACR;EACA,YAAY;IACV,WAAW;EACb;EACA,QAAQ;IACN,aAAa;EACf;EACA,MAAM;IACJ,KAAK;IACL,MAAM;IACN,WAAW;IACX,eAAe;EACjB;EACA,OAAO;IACL,MAAM;IACN,OAAO;EACT;EACA,QAAQ;IACN,MAAM;EACR;EACA,SAAS;IACP,SAAS;EACX;EACA,OAAO;IACL,MAAM;EACR;EACA,KAAK;IACH,eAAe;EACjB;EACA,WAAW;IACT,SAAS;IACT,iBAAiB;IACjB,aAAa;EACf;EACA,aAAa;IACX,qBAAqB;IACrB,0BAA0B;EAC5B;AACF;AAoBO,IAAM,eAAyC;EACpD;IACE,KAAK;IACL,MAAM;IACN,aACE;EACJ;EACA;IACE,KAAK;IACL,MAAM;IACN,aACE;EACJ;EACA;IACE,KAAK;IACL,MAAM;IACN,aACE;IACF,UAAU;EACZ;EACA;IACE,KAAK;IACL,MAAM;IACN,aAAa;EACf;EACA;IACE,KAAK;IACL,MAAM;IACN,aACE;EACJ;EACA;IACE,KAAK;IACL,MAAM;IACN,aAAa;EACf;EACA;IACE,KAAK;IACL,MAAM;IACN,aAAa;EACf;EACA;IACE,KAAK;IACL,MAAM;IACN,aAAa;IACb,UAAU;EACZ;EACA;IACE,KAAK;IACL,MAAM;IACN,aACE;EACJ;EACA;IACE,KAAK;IACL,MAAM;IACN,aACE;EACJ;EACA;IACE,KAAK;IACL,MAAM;IACN,aACE;EACJ;EACA;IACE,KAAK;IACL,MAAM;IACN,aAAa;EACf;EACA;IACE,KAAK;IACL,MAAM;IACN,aACE;IACF,UAAU;EACZ;EACA;IACE,KAAK;IACL,MAAM;IACN,aAAa;EACf;EACA;IACE,KAAK;IACL,MAAM;IACN,YAAY,CAAC,UAAU,UAAU,MAAM;IACvC,aAAa;EACf;EACA;IACE,KAAK;IACL,MAAM;IACN,aAAa;EACf;EACA;IACE,KAAK;IACL,MAAM;IACN,aAAa;EACf;EACA;IACE,KAAK;IACL,MAAM;IACN,aAAa;EACf;EACA;IACE,KAAK;IACL,MAAM;IACN,aAAa;EACf;EACA;IACE,KAAK;IACL,MAAM;IACN,aAAa;EACf;EACA;IACE,KAAK;IACL,MAAM;IACN,YAAY,CAAC,YAAY,kBAAkB,SAAS,MAAM;IAC1D,aAAa;EACf;EACA;IACE,KAAK;IACL,MAAM;IACN,YAAY,CAAC,iBAAiB,cAAc,MAAM;IAClD,aAAa;EACf;EACA;IACE,KAAK;IACL,MAAM;IACN,aAAa;IACb,UAAU;EACZ;EACA;IACE,KAAK;IACL,MAAM;IACN,aAAa;IACb,UAAU;EACZ;EACA;IACE,KAAK;IACL,MAAM;IACN,aACE;EACJ;EACA;IACE,KAAK;IACL,MAAM;IACN,aACE;EACJ;EACA;IACE,KAAK;IACL,MAAM;IACN,aACE;EACJ;EACA;IACE,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","names":["mkdir","readFile","stat","homedir","join","execa","dirname","resolve","readdir","rm","writeFile","parseYaml","readFile","stat","dirname","join","fileExists","execa","join","homedir","readFile","stat","mkdir","dirname","resolve","readdir","rm","writeFile"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../packages/sandbox-docker/src/create.ts","../../../packages/sandbox-docker/src/box-env.ts"],"sourcesContent":["import { randomBytes } from 'node:crypto';\nimport { mkdir, stat } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { basename, join, resolve } from 'node:path';\nimport { execa } from 'execa';\nimport { ConfigError, loadConfig } from '@agentbox/ctl';\nimport { buildClaudeMounts, ensureClaudeVolume, resolveClaudeVolume } from './claude.js';\nimport {\n type BoxLimitSpec,\n containerExists,\n dockerInfo,\n dockerStorageDriver,\n ensureVolume,\n publishedHostPort,\n runBox,\n} from './docker.js';\nimport { dockerVolumeName, launchDockerdDaemon } from './dockerd.js';\nimport { generateVncPassword, launchVncDaemon, VNC_CONTAINER_PORT } from './vnc.js';\nimport { WEB_CONTAINER_PORT } from './web.js';\nimport { createBoxWorktree, detectGitRepos } from './git-worktree.js';\nimport {\n CONTAINER_EXPORT_MERGED,\n CONTAINER_EXPORT_UPPER,\n DEFAULT_ENV_PATTERNS,\n boxRunDirFor,\n copyHostEnvFilesToBox,\n} from './host-export.js';\nimport { DEFAULT_BOX_IMAGE, ensureImage } from './image.js';\nimport {\n mountOverlay,\n verifyOverlay,\n type NestedWorktreeBind,\n type OverlayCheck,\n} from './overlay.js';\nimport {\n allocateProjectIndex,\n readState,\n recordBox,\n type BoxRecord,\n type GitWorktreeRecord,\n} from './state.js';\nimport { createSnapshot, snapshotPathFor } from './snapshot.js';\nimport { CHECKPOINT_MOUNT, resolveCheckpointLower } from './checkpoint.js';\nimport { launchCtlDaemon } from './ctl.js';\nimport { writeBoxEnvFile } from './box-env.js';\nimport {\n ensureRelay,\n generateRelayToken,\n registerBoxWithRelay,\n rehydrateRelayRegistry,\n} from './relay.js';\nimport {\n buildIdeMounts,\n cursorServerVolumeName,\n ensureIdeVolumes,\n repairIdeOwnership,\n vscodeServerVolumeName,\n} from './vscode.js';\n\nexport interface CreateBoxOptions {\n workspacePath: string;\n name?: string;\n /** Frozen APFS clone of the host workspace as the overlay lower (the `--host-snapshot` path). */\n useSnapshot: boolean;\n /**\n * Start the box from a project checkpoint (the `--snapshot <ref>` path).\n * Resolved against `projectRoot` (or `workspacePath` when unset). A\n * `layered` checkpoint stacks its captured delta(s) over the normal base\n * lower; a `merged` checkpoint is the sole, frozen lower.\n */\n checkpointRef?: string;\n image?: string;\n onLog?: (line: string) => void;\n /**\n * Claude Code config volume. When omitted, defaults to `{ isolate: false }` —\n * every box mounts the shared `agentbox-claude-config` volume at\n * /home/vscode/.claude so auth / skills / plugins persist across boxes.\n */\n claudeConfig?: { isolate: boolean };\n /** Extra env vars forwarded to the container (merged on top of claude env forwarding). */\n claudeEnv?: Record<string, string>;\n /**\n * When true, run `npm install -g @playwright/cli@latest` inside the box after\n * the overlay is mounted. agent-browser is always installed in the image; this\n * flag adds the Playwright CLI on top for boxes that need it.\n */\n withPlaywright?: boolean;\n /**\n * When true, copy the host's env/config files (DEFAULT_ENV_PATTERNS basename\n * globs — `.env*`, `secrets.toml`, `agentbox.yaml`, ...) into the box's\n * /workspace after the overlay is mounted, bypassing gitignore. The reverse\n * of `pull env`. One-shot at create time; the files persist in the writable\n * upper layer across pause/stop/start.\n */\n withEnv?: boolean;\n /**\n * VNC stack (Xvnc on :1 + websockify serving noVNC on container :6080).\n * Defaults to enabled. The CLI exposes `--no-vnc` for opt-out. Disabling\n * skips port mapping + password generation + the in-container supervisor\n * launch; the apt-installed binaries stay in the image but are unused.\n */\n vnc?: { enabled: boolean };\n /**\n * Docker-in-Docker. Always-on (the in-box dockerd is part of the box\n * surface). When `sharedCache` is true the per-box `agentbox-docker-<id>`\n * volume is replaced with the shared `agentbox-docker-cache` volume — image\n * layers persist across boxes (and `destroy`/`prune` won't remove it).\n */\n docker?: { sharedCache: boolean };\n /**\n * Absolute host path of the cwd's project at create time. When provided,\n * `createBox` stamps `projectRoot` + an allocated `projectIndex` on the\n * BoxRecord so the CLI can auto-pick / resolve by index. The CLI computes\n * this via `findProjectRoot(workspacePath)` from `@agentbox/config`; this\n * package stays free of the config dep. Omit for unowned boxes created\n * directly via the programmatic API.\n */\n projectRoot?: string;\n /**\n * Container resource ceilings (engine-agnostic: bytes / fractional cpus /\n * pid count / raw disk size string). Absent fields = unlimited. `disk` is\n * best-effort: dropped (with a warning via `onLog`) when the engine's\n * storage driver can't enforce `--storage-opt size=` (overlay2 / macOS).\n */\n limits?: BoxLimitSpec;\n}\n\nexport interface CreatedBox {\n record: BoxRecord;\n overlayChecks: OverlayCheck[];\n imageBuilt: boolean;\n}\n\n/**\n * Compact the engine-applied limits into the BoxRecord shape: only fields that\n * actually constrain the box (>0 / non-empty). Returns undefined when nothing\n * was applied so legacy/unlimited boxes stay free of the field.\n */\nfunction persistableLimits(\n lim: BoxLimitSpec | undefined,\n): BoxRecord['resourceLimits'] | undefined {\n if (!lim) return undefined;\n const out: NonNullable<BoxRecord['resourceLimits']> = {};\n if (lim.memoryBytes && lim.memoryBytes > 0) out.memoryBytes = Math.floor(lim.memoryBytes);\n if (lim.cpus && lim.cpus > 0) out.cpus = lim.cpus;\n if (lim.pidsLimit && lim.pidsLimit > 0) out.pidsLimit = Math.floor(lim.pidsLimit);\n if (lim.disk) out.disk = lim.disk;\n return Object.keys(out).length > 0 ? out : undefined;\n}\n\nfunction generateBoxId(): string {\n return randomBytes(4).toString('hex');\n}\n\nexport function sanitizeBasename(workspacePath: string): string {\n const raw = basename(resolve(workspacePath));\n return raw\n .toLowerCase()\n .replace(/[^a-z0-9._-]+/g, '-')\n .replace(/-+/g, '-')\n .replace(/^[-._]+|[-._]+$/g, '')\n .slice(0, 30)\n .replace(/[-._]+$/, '');\n}\n\nexport function defaultBoxName(workspacePath: string, id: string): string {\n const base = sanitizeBasename(workspacePath);\n return base.length > 0 ? `${base}-${id}` : id;\n}\n\nasync function pathExists(p: string): Promise<boolean> {\n try {\n await stat(p);\n return true;\n } catch {\n return false;\n }\n}\n\n// ~/.claude is intentionally NOT in this list: it lives in the named volume\n// `agentbox-claude-config` (see resolveClaudeVolume / ensureClaudeVolume) so\n// auth persists inside the container without leaking host state. Only\n// non-claude identity files are bind-mounted from the host.\nasync function buildIdentityMounts(): Promise<string[]> {\n const home = homedir();\n const candidates: Array<{ src: string; dst: string; readOnly: boolean }> = [\n { src: join(home, '.codex'), dst: '/home/vscode/.codex', readOnly: false },\n { src: join(home, '.gitconfig'), dst: '/home/vscode/.gitconfig', readOnly: true },\n ];\n const out: string[] = [];\n for (const c of candidates) {\n if (await pathExists(c.src)) {\n out.push(`${c.src}:${c.dst}${c.readOnly ? ':ro' : ''}`);\n }\n }\n return out;\n}\n\nexport async function createBox(opts: CreateBoxOptions): Promise<CreatedBox> {\n const log = opts.onLog ?? (() => {});\n const workspace = resolve(opts.workspacePath);\n if (!(await pathExists(workspace))) {\n throw new Error(`workspace does not exist: ${workspace}`);\n }\n\n // Pre-flight agentbox.yaml validation on the host so the user sees the real\n // ConfigError instead of an opaque \"socket did not appear\" timeout from the\n // detached daemon exec later. The daemon re-validates inside the box anyway\n // — defence in depth, and necessary because the file lives in the overlay\n // and can be edited after create.\n const cfgPath = join(workspace, 'agentbox.yaml');\n if (await pathExists(cfgPath)) {\n try {\n const cfg = await loadConfig(cfgPath);\n log(`agentbox.yaml validated (${String(cfg.services.length)} service(s))`);\n } catch (err) {\n if (err instanceof ConfigError) {\n throw new Error(`agentbox.yaml validation failed:\\n ${err.message}`);\n }\n throw err;\n }\n }\n\n await dockerInfo();\n log('docker daemon reachable');\n\n const imageRef = opts.image ?? DEFAULT_BOX_IMAGE;\n const { built } = await ensureImage(imageRef, {\n onProgress: (line) => log(`[image] ${line}`),\n });\n log(built ? `built image ${imageRef}` : `using cached image ${imageRef}`);\n\n // Bring up the host relay before the box so the box can post events\n // immediately on boot. Best-effort — a relay outage shouldn't block create.\n // Always re-push known box tokens after ensure: the relay's registry is\n // in-memory, so a daemon restart or `docker restart agentbox-relay` between\n // CLI invocations leaves it empty. Repushing is idempotent and cheap.\n let relayUp = false;\n try {\n await ensureRelay({ onLog: log });\n const existing = await readState();\n await rehydrateRelayRegistry(existing.boxes);\n relayUp = true;\n } catch (err) {\n log(`relay unavailable: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n const id = generateBoxId();\n const name = opts.name ?? defaultBoxName(workspace, id);\n const containerName = `agentbox-${name}`;\n const createdAt = new Date().toISOString();\n if (await containerExists(containerName)) {\n throw new Error(`container ${containerName} already exists; remove it first`);\n }\n\n // Detect host git repos at workspace root + 1st-level subdirs and create a\n // dedicated worktree per repo on a fresh `agentbox/<box-name>` branch. The\n // host's working tree stays untouched; uncommitted (tracked + untracked)\n // state is carried into the worktree so the agent picks up where the user\n // left off. The root worktree (if any) replaces the box's overlay lower so\n // /workspace is the agent's editable working tree; nested worktrees are\n // staged on a side path and bind-mounted on top of /workspace/<subpath>\n // after the FUSE overlay is up (see mountOverlay).\n const worktreesRoot = join(boxRunDirFor(id), 'worktrees');\n await mkdir(worktreesRoot, { recursive: true });\n const gitWorktreeRecords: GitWorktreeRecord[] = [];\n const nestedWorktreeBinds: NestedWorktreeBind[] = [];\n const repos = await detectGitRepos(workspace);\n if (repos.length > 0) {\n log(\n `detected ${String(repos.length)} git repo(s): ` +\n repos.map((r) => `${r.kind}${r.relPathFromWorkspace ? '@' + r.relPathFromWorkspace : ''}`).join(', '),\n );\n }\n for (const r of repos) {\n const worktreeDir = join(worktreesRoot, r.relPathFromWorkspace || 'root');\n const branchBase =\n r.kind === 'root'\n ? `agentbox/${name}`\n : `agentbox/${name}--${r.relPathFromWorkspace.replace(/[^A-Za-z0-9._-]+/g, '_')}`;\n const result = await createBoxWorktree({\n hostMainRepo: r.hostMainRepo,\n branchName: branchBase,\n worktreeDir,\n onLog: log,\n });\n const containerPath = r.kind === 'root' ? '/workspace' : `/workspace/${r.relPathFromWorkspace}`;\n gitWorktreeRecords.push({\n kind: r.kind,\n hostMainRepo: r.hostMainRepo,\n hostWorktreeDir: worktreeDir,\n containerPath,\n branch: result.branchName,\n relPathFromWorkspace: r.relPathFromWorkspace,\n });\n if (r.kind === 'nested') {\n nestedWorktreeBinds.push({\n containerPath,\n mountFromPath: `/agentbox-worktrees/${r.relPathFromWorkspace}`,\n });\n }\n }\n\n let lowerPath = workspace;\n const rootWorktree = gitWorktreeRecords.find((w) => w.kind === 'root');\n if (rootWorktree) {\n lowerPath = rootWorktree.hostWorktreeDir;\n log(`using worktree as overlay lower: ${lowerPath}`);\n }\n\n let snapshotDir: string | null = null;\n if (opts.useSnapshot) {\n snapshotDir = snapshotPathFor(id);\n log(`cloning workspace to ${snapshotDir} (APFS clone where available)`);\n const snap = await createSnapshot({ source: lowerPath, destination: snapshotDir });\n log(`pruned ${snap.prunedPaths.length} platform-dependent dirs from snapshot`);\n lowerPath = snapshotDir;\n }\n\n // Checkpoint restore: mount the per-project checkpoint volume read-only\n // ONCE at /agentbox-checkpoints; the overlay uses its `<name>` subdirs as\n // lowerdirs (layered, over the /host-src base) or the sole lower (merged,\n // code frozen). The base bind is always `${lowerPath}:/host-src`.\n let lowerDirs: string[] | undefined;\n let checkpointVolume: string | undefined;\n let checkpointSource: BoxRecord['checkpointSource'];\n if (opts.checkpointRef) {\n const projectRootForCkpt = opts.projectRoot ?? workspace;\n const spec = await resolveCheckpointLower(projectRootForCkpt, opts.checkpointRef);\n checkpointVolume = spec.volume;\n const layerDirs = spec.subpaths.map((s) => `${CHECKPOINT_MOUNT}/${s}`);\n lowerDirs = spec.type === 'merged' ? layerDirs : [...layerDirs, '/host-src'];\n checkpointSource = { ref: opts.checkpointRef, type: spec.type, chain: spec.chain };\n log(\n `starting from checkpoint ${opts.checkpointRef} (${spec.type}, ${String(spec.subpaths.length)} layer(s), volume ${spec.volume})`,\n );\n }\n\n const upperVolume = `agentbox-upper-${id}`;\n await ensureVolume(upperVolume);\n await ensureIdeVolumes(id);\n const dockerCacheShared = opts.docker?.sharedCache === true;\n const dockerVolume = dockerVolumeName(id, dockerCacheShared);\n await ensureVolume(dockerVolume);\n log(\n `prepared volumes ${upperVolume}, ${vscodeServerVolumeName(id)}, ${cursorServerVolumeName(id)}, ${dockerVolume}`,\n );\n const ide = buildIdeMounts(id);\n\n // Claude Code config volume. Shared by default so users sign in once across\n // every box; --isolate-claude-config opts into a per-box volume. Either way,\n // the host's ~/.claude is the authoritative source: we rsync host -> volume\n // on every create so updates on the host (new login, new skills, new MCP)\n // flow into the next box. Sync is additive — box-only state (session logs,\n // etc.) is preserved.\n const claudeSpec = resolveClaudeVolume({\n isolate: opts.claudeConfig?.isolate ?? false,\n boxId: id,\n });\n const claudeEnsured = await ensureClaudeVolume(claudeSpec, {\n syncFromHost: true,\n image: imageRef,\n hostWorkspace: workspace,\n });\n if (claudeEnsured.synced) {\n log(`synced ${claudeSpec.volume} from ~/.claude`);\n if ((claudeEnsured.filteredHookCount ?? 0) > 0) {\n log(\n `filtered ${String(claudeEnsured.filteredHookCount)} host-path hook(s) (paths under ~/)`,\n );\n }\n if (claudeEnsured.clearedInstallMethod) {\n log(\"cleared host's installMethod from synced .claude.json (box uses the native installer)\");\n }\n if (claudeEnsured.aliasedProjectKey) {\n log(`aliased project state for ${workspace} -> /workspace in synced .claude.json`);\n }\n } else if (claudeEnsured.created) {\n log(`created empty volume ${claudeSpec.volume} (no host ~/.claude to sync)`);\n } else {\n log(`reusing volume ${claudeSpec.volume} (no host ~/.claude to sync)`);\n }\n const claudeMounts = buildClaudeMounts(claudeSpec, process.env);\n\n const boxDir = boxRunDirFor(id);\n const socketDir = join(boxDir, 'run');\n const socketPath = join(socketDir, 'ctl.sock');\n // Per-box host dirs that `agentbox open` / `agentbox path` refresh into.\n // We bind these in at create time so a later `docker exec rsync` can write\n // straight to the host filesystem — no container restart needed.\n const mergedExportDir = join(boxDir, 'workspace');\n const upperExportDir = join(boxDir, 'upper');\n await mkdir(socketDir, { recursive: true });\n await mkdir(mergedExportDir, { recursive: true });\n await mkdir(upperExportDir, { recursive: true });\n\n const extraVolumes = await buildIdentityMounts();\n extraVolumes.push(...claudeMounts.extraVolumes);\n extraVolumes.push(...ide.extraVolumes);\n extraVolumes.push(`${socketDir}:/run/agentbox`);\n extraVolumes.push(`${mergedExportDir}:${CONTAINER_EXPORT_MERGED}`);\n extraVolumes.push(`${upperExportDir}:${CONTAINER_EXPORT_UPPER}`);\n // In-box dockerd's data root. Per-box (`agentbox-docker-<id>`, wiped on\n // destroy) by default; shared (`agentbox-docker-cache`, preserved) when\n // `box.dockerCacheShared` is set.\n extraVolumes.push(`${dockerVolume}:/var/lib/docker`);\n // Bind-mount each main repo's `.git/` at its identical absolute host path,\n // RW. Worktree pointer files (`<worktree>/.git`) and the back-reference at\n // `<main>/.git/worktrees/<name>/gitdir` contain absolute paths; both must\n // resolve to the same path on host and inside the container or git breaks\n // on one side.\n for (const w of gitWorktreeRecords) {\n extraVolumes.push(`${w.hostMainRepo}/.git:${w.hostMainRepo}/.git`);\n }\n // Stage nested worktrees on a side path so mountOverlay() can bind-mount\n // them on top of /workspace/<subpath> after the FUSE overlay is up.\n for (const w of gitWorktreeRecords) {\n if (w.kind === 'nested') {\n extraVolumes.push(`${w.hostWorktreeDir}:/agentbox-worktrees/${w.relPathFromWorkspace}`);\n }\n }\n // Per-project checkpoint volume, mounted read-only once; the overlay's\n // lowerdirs are its `<name>` subdirs (see mountOverlay).\n if (checkpointVolume) {\n extraVolumes.push(`${checkpointVolume}:${CHECKPOINT_MOUNT}:ro`);\n }\n for (const v of extraVolumes) log(`mounting agent dir: ${v}`);\n\n // Per-box bearer token for the host relay. Register *before* runBox so the\n // box's supervisor can post on boot. Skip if the relay isn't reachable —\n // the box still works, it just won't deliver events to the host.\n const relayToken = generateRelayToken();\n if (relayUp) {\n try {\n await registerBoxWithRelay({\n boxId: id,\n token: relayToken,\n name,\n containerName,\n createdAt,\n worktrees: gitWorktreeRecords,\n });\n log(`registered box token with relay`);\n } catch (err) {\n log(`relay register failed: ${err instanceof Error ? err.message : String(err)}`);\n relayUp = false;\n }\n }\n const relayEnv: Record<string, string> = relayUp\n ? {\n // host.docker.internal resolves to the host (where the relay node\n // process is running). The matching `--add-host` is set in runBox.\n AGENTBOX_RELAY_URL: `http://host.docker.internal:8787`,\n AGENTBOX_RELAY_TOKEN: relayToken,\n }\n : {};\n\n // VNC stack defaults on; the CLI surfaces `--no-vnc` for opt-out. Generate\n // the password and the port mapping up front so they're baked into the\n // container's env + `-p` flags before `docker run` — both must be set at\n // create time (env survives stop/start; port mappings are immutable).\n const vncEnabled = opts.vnc?.enabled !== false;\n const vncPassword = vncEnabled ? generateVncPassword() : undefined;\n const vncEnv: Record<string, string> = vncEnabled && vncPassword\n ? { AGENTBOX_VNC_PASSWORD: vncPassword }\n : {};\n const vncPortMappings = vncEnabled\n ? [{ hostPort: 0, containerPort: VNC_CONTAINER_PORT, hostIp: '127.0.0.1' }]\n : [];\n\n // Reserve the web port unconditionally: `docker run -p` is immutable, but the\n // `expose:`-flagged service is usually only known after the in-box wizard\n // writes agentbox.yaml. The supervisor forwards :80 to it later; here we just\n // guarantee a published host port exists for whenever that happens.\n const webPortMappings = [\n { hostPort: 0, containerPort: WEB_CONTAINER_PORT, hostIp: '127.0.0.1' },\n ];\n\n // Per-project monotonic index. Allocated *before* runBox so it can be\n // injected as AGENTBOX_PROJECT_INDEX in the container env. Re-reads state\n // each time so concurrent creates from the same project see each other's\n // assignments (last-write-wins is fine — `recordBox` upserts by id, and\n // index collisions are harmless since each box's id is unique).\n let projectIndex: number | undefined;\n if (opts.projectRoot) {\n projectIndex = allocateProjectIndex(await readState(), opts.projectRoot);\n }\n\n // Identity vars that make the box self-aware. `AGENTBOX=1` is the sentinel\n // `[ -n \"$AGENTBOX\" ]` checks key off. The rest are metadata for in-box\n // agents — `AGENTBOX_HOST_WORKSPACE` is intentionally the absolute host\n // path (not a mount), so an agent can explain to the user what host dir\n // they are looking at.\n const agentboxEnv: Record<string, string> = {\n AGENTBOX: '1',\n AGENTBOX_BOX_NAME: name,\n AGENTBOX_HOST_WORKSPACE: workspace,\n ...(opts.projectRoot ? { AGENTBOX_PROJECT_ROOT: opts.projectRoot } : {}),\n ...(projectIndex !== undefined\n ? { AGENTBOX_PROJECT_INDEX: String(projectIndex) }\n : {}),\n };\n const boxEnvForFile: Record<string, string> = {\n AGENTBOX_BOX_ID: id,\n ...agentboxEnv,\n };\n\n // `--storage-opt size=` is only enforced by devicemapper/btrfs/zfs — a hard\n // error on overlay2 / fuse-overlayfs (every macOS engine). Drop it + warn so\n // create doesn't blow up; the other limits are universal.\n const appliedLimits: BoxLimitSpec | undefined = opts.limits;\n let effectiveLimits = appliedLimits;\n if (appliedLimits?.disk) {\n const driver = await dockerStorageDriver();\n if (!/^(devicemapper|btrfs|zfs|windowsfilter)$/.test(driver)) {\n log(\n `warning: --disk/box.disk is a no-op on this engine (storage-driver=${driver || 'unknown'}); ignoring`,\n );\n effectiveLimits = { ...appliedLimits, disk: null };\n }\n }\n\n await runBox({\n name: containerName,\n image: imageRef,\n lowerPath,\n upperVolume,\n extraVolumes,\n limits: effectiveLimits,\n portMappings: [...vncPortMappings, ...webPortMappings],\n env: {\n AGENTBOX_BOX_ID: id,\n ...agentboxEnv,\n ...claudeMounts.env,\n ...relayEnv,\n ...vncEnv,\n ...(opts.claudeEnv ?? {}),\n },\n });\n log(`container ${containerName} started`);\n\n // /etc/agentbox/box.env: sourced by /etc/profile.d/agentbox.sh in login\n // shells (the docker-run env doesn't reach `agentbox shell <box>` cleanly\n // without it). Best-effort — env vars on the container are the primary\n // path; this file is for shells launched via tools that strip env.\n const boxEnv = await writeBoxEnvFile(containerName, boxEnvForFile);\n if (boxEnv.ok) log('wrote /etc/agentbox/box.env');\n else log(`writing /etc/agentbox/box.env failed: ${boxEnv.reason}`);\n\n try {\n await mountOverlay(containerName, { lowerDirs, nestedWorktrees: nestedWorktreeBinds });\n log('fuse-overlayfs mounted at /workspace');\n if (nestedWorktreeBinds.length > 0) {\n log(`bind-mounted ${String(nestedWorktreeBinds.length)} nested worktree(s) over /workspace`);\n }\n } catch (err) {\n log(`overlay mount failed; leaving container ${containerName} running so you can inspect it`);\n throw err;\n }\n\n const overlayChecks = await verifyOverlay(containerName, lowerDirs ?? ['/host-src']);\n const failed = overlayChecks.filter((c) => !c.ok);\n if (failed.length > 0) {\n const detail = failed.map((c) => ` - ${c.name}: ${c.detail}`).join('\\n');\n throw new Error(`overlay verification failed:\\n${detail}`);\n }\n log('overlay verified');\n\n await repairIdeOwnership(containerName);\n log('.vscode-server + .cursor-server ownership verified');\n\n const ctl = await launchCtlDaemon(containerName, socketPath);\n if (ctl.up) log('agentbox-ctl daemon up');\n else log(`agentbox-ctl daemon did not become reachable: ${ctl.reason}`);\n\n // dockerd: always-on, mirrors launchVncDaemon. Best-effort — a slow start\n // shouldn't fail box creation; `agentbox start` will relaunch on restart\n // (the daemon dies with the container). Storage driver is fuse-overlayfs,\n // pinned in /etc/docker/daemon.json baked into the image.\n const dockerd = await launchDockerdDaemon(containerName);\n if (dockerd.up) {\n log(`dockerd up (storage-driver=fuse-overlayfs, data root=${dockerVolume})`);\n } else {\n log(`dockerd did not become ready: ${dockerd.reason}`);\n }\n\n if (opts.withPlaywright) {\n log('installing @playwright/cli@latest (--with-playwright)');\n // npm-global writes to /usr/lib/node_modules/, so we need root. The\n // resulting binary lives in /usr/bin and persists in the container's\n // writable layer across pause/stop/start — no need to reinstall on start.\n const result = await execa(\n 'docker',\n [\n 'exec',\n '--user',\n 'root',\n containerName,\n 'bash',\n '-lc',\n 'npm install -g @playwright/cli@latest 2>&1',\n ],\n { reject: false },\n );\n for (const line of (result.stdout ?? '').split('\\n')) {\n if (line.trim().length > 0) log(`[playwright] ${line}`);\n }\n if (result.exitCode !== 0) {\n throw new Error(\n `failed to install @playwright/cli (exit ${String(result.exitCode)}): ${(result.stderr ?? '').toString().slice(0, 400)}`,\n );\n }\n log('@playwright/cli installed');\n }\n\n if (opts.withEnv) {\n log('copying host env/config files into /workspace (--with-env)');\n const { copied } = await copyHostEnvFilesToBox({\n container: containerName,\n workspaceDir: workspace,\n patterns: DEFAULT_ENV_PATTERNS,\n onLog: log,\n });\n log(copied > 0 ? `copied ${String(copied)} env/config file(s)` : 'no env/config files found');\n }\n\n // VNC daemon (Xvnc + websockify). Best-effort, like launchCtlDaemon. The\n // host port mapping was wired into runBox above (hostPort=0 → random); we\n // resolve the assigned port here for storage. If the daemon fails to come\n // up we still record vncEnabled so `agentbox start` will retry the launch\n // — the failure is usually transient (apt-running, fs slow).\n let vncHostPort: number | null = null;\n if (vncEnabled) {\n const vnc = await launchVncDaemon(containerName);\n if (vnc.up) log('vnc stack up (Xvnc + websockify + noVNC)');\n else log(`vnc stack did not become reachable: ${vnc.reason}`);\n vncHostPort = await publishedHostPort(containerName, VNC_CONTAINER_PORT);\n if (vncHostPort) log(`vnc web on host 127.0.0.1:${String(vncHostPort)}`);\n }\n\n const webHostPort = await publishedHostPort(containerName, WEB_CONTAINER_PORT);\n if (webHostPort) {\n log(\n `web port reserved on host 127.0.0.1:${String(webHostPort)} ` +\n `(forwards to the web service once agentbox.yaml sets a service expose:)`,\n );\n }\n\n const record: BoxRecord = {\n id,\n name,\n container: containerName,\n image: imageRef,\n workspacePath: workspace,\n lowerPath,\n upperVolume,\n snapshotDir,\n socketPath,\n claudeConfigVolume: claudeSpec.volume,\n vscodeServerVolume: vscodeServerVolumeName(id),\n cursorServerVolume: cursorServerVolumeName(id),\n relayToken: relayUp ? relayToken : undefined,\n gitWorktrees: gitWorktreeRecords.length > 0 ? gitWorktreeRecords : undefined,\n withPlaywright: opts.withPlaywright ? true : undefined,\n withEnv: opts.withEnv ? true : undefined,\n vncEnabled: vncEnabled ? true : undefined,\n vncContainerPort: vncEnabled ? VNC_CONTAINER_PORT : undefined,\n vncHostPort: vncHostPort ?? undefined,\n vncPassword: vncPassword,\n webContainerPort: WEB_CONTAINER_PORT,\n webHostPort: webHostPort ?? undefined,\n dockerVolume,\n dockerCacheShared: dockerCacheShared || undefined,\n projectRoot: opts.projectRoot,\n projectIndex,\n lowerDirs,\n checkpointVolume,\n checkpointSource,\n resourceLimits: persistableLimits(effectiveLimits),\n createdAt,\n };\n await recordBox(record);\n\n return { record, overlayChecks, imageBuilt: built };\n}\n","import { execa } from 'execa';\n\n/**\n * Writes /etc/agentbox/box.env inside the container as a POSIX-sourceable\n * key='value' file. Paired with /etc/profile.d/agentbox.sh (baked in the\n * image), which `set -a; . /etc/agentbox/box.env; set +a`s it on login.\n *\n * Best-effort: failure is logged by the caller; an unwritable file just\n * means interactive shells lose the AGENTBOX_* vars (the env vars baked\n * into docker run still survive).\n */\nexport async function writeBoxEnvFile(\n container: string,\n env: Record<string, string>,\n): Promise<{ ok: true } | { ok: false; reason: string }> {\n const body = formatBoxEnvBody(env);\n const result = await execa(\n 'docker',\n ['exec', '--user', 'root', '-i', container, 'sh', '-c', 'umask 022 && cat > /etc/agentbox/box.env'],\n { input: body, reject: false },\n );\n if (result.exitCode !== 0) {\n return {\n ok: false,\n reason: `docker exec failed (exit ${String(result.exitCode)}): ${(result.stderr ?? '').toString().slice(0, 400)}`,\n };\n }\n return { ok: true };\n}\n\n// Single-quote each value and escape embedded single quotes as '\\''. Avoids\n// double-quoted form because `. ` would expand $foo / `cmd` at source time.\nexport function formatBoxEnvBody(env: Record<string, string>): string {\n const lines: string[] = [];\n for (const [k, v] of Object.entries(env)) {\n lines.push(`${k}=${shellSingleQuote(v)}`);\n }\n return lines.join('\\n') + '\\n';\n}\n\nfunction shellSingleQuote(s: string): string {\n return `'${s.replace(/'/g, `'\\\\''`)}'`;\n}\n"],"mappings":"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","names":["execa","execa"]}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
createBox,
|
|
4
|
-
defaultBoxName,
|
|
5
|
-
sanitizeBasename
|
|
6
|
-
} from "./chunk-WR5FFGE5.js";
|
|
7
|
-
import "./chunk-NSIECUCS.js";
|
|
8
|
-
import "./chunk-IDR4HVIC.js";
|
|
9
|
-
import "./chunk-SOMIKEN2.js";
|
|
10
|
-
export {
|
|
11
|
-
createBox,
|
|
12
|
-
defaultBoxName,
|
|
13
|
-
sanitizeBasename
|
|
14
|
-
};
|
|
15
|
-
//# sourceMappingURL=create-4BQY2UYU-CGSW3RGE.js.map
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
agentboxHomeBytes,
|
|
4
|
-
allCheckpointVolumesBytes,
|
|
5
|
-
boxResourceStats,
|
|
6
|
-
parseDockerSize,
|
|
7
|
-
projectCheckpointVolumeBytes,
|
|
8
|
-
volumeSizeBytes
|
|
9
|
-
} from "./chunk-J35IH7W5.js";
|
|
10
|
-
import "./chunk-SOMIKEN2.js";
|
|
11
|
-
export {
|
|
12
|
-
agentboxHomeBytes,
|
|
13
|
-
allCheckpointVolumesBytes,
|
|
14
|
-
boxResourceStats,
|
|
15
|
-
parseDockerSize,
|
|
16
|
-
projectCheckpointVolumeBytes,
|
|
17
|
-
volumeSizeBytes
|
|
18
|
-
};
|
|
19
|
-
//# sourceMappingURL=stats-GZFLPYTU-DBJ2DVBJ.js.map
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|