@madarco/agentbox 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/dist/_cloud-attach-DMVH6GWO.js +12 -0
  2. package/dist/chunk-7KOEFGN2.js +1162 -0
  3. package/dist/chunk-7KOEFGN2.js.map +1 -0
  4. package/dist/chunk-I24B6AXR.js +600 -0
  5. package/dist/chunk-I24B6AXR.js.map +1 -0
  6. package/dist/chunk-NAVL4R34.js +7546 -0
  7. package/dist/chunk-NAVL4R34.js.map +1 -0
  8. package/dist/chunk-NW5NYTQM.js +1366 -0
  9. package/dist/chunk-NW5NYTQM.js.map +1 -0
  10. package/dist/chunk-UK72UQ5U.js +237 -0
  11. package/dist/chunk-UK72UQ5U.js.map +1 -0
  12. package/dist/chunk-V5KZGB5V.js +722 -0
  13. package/dist/chunk-V5KZGB5V.js.map +1 -0
  14. package/dist/cloud-poller-ZIWSADJB-JXFRJUEM.js +10 -0
  15. package/dist/dist-ETCFRVPA.js +423 -0
  16. package/dist/dist-QZGJIBT5.js +1339 -0
  17. package/dist/dist-QZGJIBT5.js.map +1 -0
  18. package/dist/dist-R67WMLCF.js +183 -0
  19. package/dist/dist-R67WMLCF.js.map +1 -0
  20. package/dist/index.js +4088 -1451
  21. package/dist/index.js.map +1 -1
  22. package/package.json +9 -4
  23. package/runtime/docker/Dockerfile.box +115 -19
  24. package/runtime/docker/apps/cli/share/agentbox-setup/SKILL.md +34 -19
  25. package/runtime/docker/packages/ctl/dist/bin.cjs +10246 -758
  26. package/runtime/docker/packages/sandbox-docker/scripts/agentbox-checkpoint-cleanup +13 -3
  27. package/runtime/docker/packages/sandbox-docker/scripts/agentbox-codex-hooks.json +37 -0
  28. package/runtime/docker/packages/sandbox-docker/scripts/agentbox-dockerd-start +87 -7
  29. package/runtime/docker/packages/sandbox-docker/scripts/agentbox-open +28 -0
  30. package/runtime/docker/packages/sandbox-docker/scripts/custom-system-CLAUDE.md +4 -9
  31. package/runtime/hetzner/agentbox-checkpoint-cleanup +52 -0
  32. package/runtime/hetzner/agentbox-codex-hooks.json +37 -0
  33. package/runtime/hetzner/agentbox-dockerd-start +132 -0
  34. package/runtime/hetzner/agentbox-open +28 -0
  35. package/runtime/hetzner/agentbox-setup-skill.md +196 -0
  36. package/runtime/hetzner/agentbox-vnc-start +77 -0
  37. package/runtime/hetzner/claude-managed-settings.json +54 -0
  38. package/runtime/hetzner/ctl.cjs +22350 -0
  39. package/runtime/hetzner/custom-system-CLAUDE.md +27 -0
  40. package/runtime/hetzner/scripts/install-box.sh +365 -0
  41. package/runtime/relay/bin.cjs +9182 -754
  42. package/share/agentbox-setup/SKILL.md +34 -19
  43. package/dist/chunk-6VTAPD4H.js +0 -507
  44. package/dist/chunk-6VTAPD4H.js.map +0 -1
  45. package/dist/chunk-7J5AJLWG.js +0 -238
  46. package/dist/chunk-7J5AJLWG.js.map +0 -1
  47. package/dist/chunk-FJNIFTWK.js +0 -523
  48. package/dist/chunk-FJNIFTWK.js.map +0 -1
  49. package/dist/chunk-HPZMD5DE.js +0 -106
  50. package/dist/chunk-HPZMD5DE.js.map +0 -1
  51. package/dist/chunk-PXUBE5KS.js +0 -2346
  52. package/dist/chunk-PXUBE5KS.js.map +0 -1
  53. package/dist/chunk-RFC5F5HR.js +0 -1709
  54. package/dist/chunk-RFC5F5HR.js.map +0 -1
  55. package/dist/create-AHZ3GVEZ-TGEDL7UX.js +0 -15
  56. package/dist/lifecycle-LFOL6YFM-TCHDX3J5.js +0 -38
  57. package/dist/state-KD7M46ZP-KHFTHFUS.js +0 -26
  58. package/dist/stats-Z4BVJODD-HEC4TMUZ.js +0 -19
  59. package/dist/stats-Z4BVJODD-HEC4TMUZ.js.map +0 -1
  60. /package/dist/{create-AHZ3GVEZ-TGEDL7UX.js.map → _cloud-attach-DMVH6GWO.js.map} +0 -0
  61. /package/dist/{lifecycle-LFOL6YFM-TCHDX3J5.js.map → cloud-poller-ZIWSADJB-JXFRJUEM.js.map} +0 -0
  62. /package/dist/{state-KD7M46ZP-KHFTHFUS.js.map → dist-ETCFRVPA.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 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 // /dev/fuse + SYS_ADMIN + apparmor:unconfined used to be required for the\n // outer /workspace FUSE overlay. That overlay is gone, but they're still\n // load-bearing for the *inner* dockerd: it runs with\n // storage-driver=fuse-overlayfs (set in /etc/docker/daemon.json in the\n // image) because the kernel `overlay` driver isn't usable from an\n // unprivileged outer container, and fuse-overlayfs needs the fuse device\n // + SYS_ADMIN to mount layers for inner containers.\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 ];\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 } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { execa } from 'execa';\nimport { sanitizeMnemonic } from '@agentbox/config';\nimport type { BoxStatus } from '@agentbox/ctl';\nimport { execInBox } from './docker.js';\nimport type { BoxRecord } from './state.js';\n\nexport type DockerEngine = 'orbstack' | 'docker-desktop' | 'other';\n\n/** In-container path bind-mounted to the per-box host export dir by createBox. */\nexport const CONTAINER_EXPORT_MERGED = '/host-export';\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 (rsync'd in by `refreshExport`). */\n mergedExport: string;\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\n/** Box-identity subset every dir helper accepts. Structurally compatible with\n * `BoxRecord`, but only the fields the segment needs. `projectIndex` is the\n * 1-based per-project number (`agentbox list`'s `N` column); when present, it\n * appears between the id and the mnemonic so dir listings sort cleanly within\n * a project and the segment matches `agentbox <cmd> <n>` intuitively. Legacy\n * (pre-feature) boxes lack it and keep the original `<id>-<mnemonic>` shape.\n */\nexport interface BoxDirRef {\n id: string;\n name: string;\n projectIndex?: number;\n}\n\n/** On-disk dir segment for a box: `<id>-<n>-<mnemonic>` (or `<id>-<mnemonic>` legacy). */\nexport function boxDirSegment(box: BoxDirRef): string {\n const mnemonic = sanitizeMnemonic(box.name);\n const n = box.projectIndex;\n if (typeof n === 'number' && Number.isFinite(n) && n > 0) {\n return `${box.id}-${String(n)}-${mnemonic}`;\n }\n return `${box.id}-${mnemonic}`;\n}\n\nexport function boxRunDirFor(box: BoxDirRef): string {\n return join(BOXES_ROOT, boxDirSegment(box));\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(box: BoxDirRef): string {\n return join(boxRunDirFor(box), '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(box: BoxDirRef): Promise<BoxStatus | null> {\n try {\n const raw = await readFile(boxStatusPathFor(box), '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\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 * NO `_data` wrapper. `docker volume inspect` reports the in-VM mountpoint\n * instead, which isn't reachable from macOS. Returns the path regardless of\n * whether it exists; callers stat it themselves. Used by claude's plugin-cache\n * pre-scan to find host-visible package.jsons on OrbStack.\n */\nexport function orbstackVolumePath(volume: string, ...sub: string[]): string {\n return join(homedir(), 'OrbStack', 'docker', 'volumes', volume, ...sub);\n}\n\nexport async function getHostPaths(\n record: Pick<BoxRecord, 'id' | 'name' | 'projectIndex'>,\n): Promise<HostPaths> {\n const boxDir = boxRunDirFor(record);\n return {\n boxDir,\n mergedExport: join(boxDir, 'workspace'),\n };\n}\n\nexport interface RefreshOptions {\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 copy actually ran (always true today; kept for callers). */\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\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 the per-box merged host export (~/.agentbox/boxes/<id>/workspace) so\n * Finder sees the box's current `/workspace`. /workspace lives in the\n * container's writable layer and is invisible to macOS directly, so we always\n * have to copy it out. Prefers rsync via the /host-export bind-mount; falls\n * back to a `tar | tar` pipe through `docker exec` for boxes that predate the\n * bind.\n */\nexport async function refreshExport(\n record: Pick<BoxRecord, 'id' | 'name' | 'projectIndex' | 'container'>,\n opts: RefreshOptions = {},\n): Promise<RefreshResult> {\n const paths = await getHostPaths(record);\n const excludeNodeModules = !opts.includeNodeModules;\n await mkdir(paths.mergedExport, { recursive: true });\n\n const bindAvailable = await hasContainerPath(record.container, CONTAINER_EXPORT_MERGED);\n if (bindAvailable) {\n const args = ['rsync', '-a', '--delete'];\n if (excludeNodeModules) args.push('--exclude=node_modules');\n args.push('/workspace/', `${CONTAINER_EXPORT_MERGED}/`);\n const r = await execInBox(record.container, args, { user: 'root' });\n if (r.exitCode !== 0) {\n throw new ExportError(`rsync into ${CONTAINER_EXPORT_MERGED} failed`, r.stdout, r.stderr);\n }\n return { hostPath: paths.mergedExport, 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 = excludeNodeModules ? ['--exclude=node_modules'] : [];\n const result = await execa(\n 'docker',\n ['exec', '--user', 'root', record.container, 'tar', '-cf', '-', ...excludes, '-C', '/workspace', '.'],\n { reject: false, encoding: 'buffer' },\n );\n if (result.exitCode !== 0) {\n throw new ExportError(\n `tar from /workspace 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', paths.mergedExport], {\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: paths.mergedExport, 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\n/**\n * Run `buildHostEnvFindArgs` against `workspaceDir` and return the matched\n * paths as a relative-path string array. Pure host-side helper: no docker, no\n * mutation. Empty array on a scan failure (best-effort, matching\n * `copyHostEnvFilesToBox`). Used by the setup wizard to preview a multiselect\n * of importable env files.\n */\nexport async function scanHostEnvFiles(\n workspaceDir: string,\n patterns: string[],\n): Promise<string[]> {\n if (patterns.length === 0) return [];\n const found = await execa('find', buildHostEnvFindArgs(patterns).slice(1), {\n cwd: workspaceDir,\n reject: false,\n });\n if (found.exitCode !== 0) return [];\n return String(found.stdout)\n .split('\\0')\n .map((p) => p.replace(/^\\.\\//, ''))\n .filter((p) => p.length > 0);\n}\n\nexport interface CopyHostFilesOptions {\n /** Target container name (must be running). */\n container: string;\n /** Absolute host workspace dir — the same dir that maps to /workspace. */\n workspaceDir: string;\n /** Relative paths (to workspaceDir) to copy. NUL-safe; no glob expansion. */\n files: string[];\n onLog?: (line: string) => void;\n}\n\n/**\n * Sibling to `copyHostEnvFilesToBox` that skips the `find` scan and trusts a\n * pre-vetted file list (e.g. the user's multiselect picks from the wizard).\n * Same tar-pipe body: tar reads the NUL-delimited list on stdin and pipes into\n * `docker exec tar -x`. Best-effort error handling — a tar/exec failure logs\n * and returns the count rather than throwing.\n */\nexport async function copyHostFilesToBox(\n opts: CopyHostFilesOptions,\n): Promise<{ copied: number }> {\n const log = opts.onLog ?? (() => {});\n // Normalise — drop any leading \"./\" so the in-container extract lands at the\n // right path, and drop empties so a stray trailing NUL doesn't become `tar: ''`.\n const list = opts.files.map((p) => p.replace(/^\\.\\//, '')).filter((p) => p.length > 0);\n if (list.length === 0) return { copied: 0 };\n\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`) — `/workspace` lives in\n * the container's writable layer, invisible to macOS directly; (2) a\n * host-side 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' | 'name' | 'projectIndex' | 'container' | 'workspacePath'>,\n opts: PullOptions = {},\n): Promise<PullResult> {\n const paths = await getHostPaths(record);\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 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 merged export (unless suppressed) and launch the macOS `open`\n * 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 --path` so scripted callers get a fresh\n * path in one call.\n */\nexport async function openInFinder(\n record: Pick<BoxRecord, 'id' | 'name' | 'projectIndex' | 'container'>,\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);\n hostPath = paths.mergedExport;\n await mkdir(hostPath, { recursive: true });\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, mkdtemp, readFile, readdir, rm, writeFile } from 'node:fs/promises';\nimport { homedir, tmpdir } from 'node:os';\nimport { basename, join } from 'node:path';\nimport { execa } from 'execa';\nimport {\n hashProjectPath,\n projectDirSegment,\n sanitizeMnemonic,\n setConfigValue,\n} from '@agentbox/config';\nimport { execInBox, removeImage } from './docker.js';\nimport { DEFAULT_BOX_IMAGE } from './image.js';\nimport type { BoxRecord, GitWorktreeRecord } from './state.js';\n\nexport const CHECKPOINTS_ROOT = join(homedir(), '.agentbox', 'checkpoints');\n\n/**\n * All per-project checkpoint *image* tags share this prefix. `prune --all`\n * allowlists by it (parallel to the old volume prefix) and `agentbox status`\n * /`inspect` recognizes a box's image as a checkpoint from this prefix.\n */\nexport const CHECKPOINT_IMAGE_PREFIX = 'agentbox-ckpt-';\n\nexport type CheckpointType = 'layered' | 'flattened';\n\n/**\n * Deterministic image tag for a project checkpoint. The repository segment is\n * keyed on the project root (same hash the per-project config dir uses) and\n * carries a mnemonic suffix so `docker images` reads self-describing. The\n * mnemonic is joined with `_` (not `-`) so the leading 16 hex chars remain\n * unambiguous and the existing `agentbox-ckpt-*` prune glob still matches.\n * Pure — unit-tested directly.\n */\nexport function checkpointImageTag(projectRoot: string, name: string): string {\n const mnemonic = sanitizeMnemonic(basename(projectRoot));\n return `${CHECKPOINT_IMAGE_PREFIX}${hashProjectPath(projectRoot)}_${mnemonic}:${name}`;\n}\n\nexport interface CheckpointManifest {\n schema: 2;\n name: string;\n type: CheckpointType;\n /** Local Docker image tag this checkpoint resolves to (`agentbox-ckpt-<hash>:<name>`). */\n image: string;\n /**\n * For a `layered` checkpoint, the older checkpoint refs this commit stacks\n * on — i.e. the chain the *source* box was built from (upper-most first,\n * base-most last). `[]` for a `flattened` checkpoint (self-contained,\n * exported+rebuilt as a single layer) or a layered checkpoint taken from a\n * box that itself started from bare host code.\n */\n parents: string[];\n base: 'worktree' | 'workspace';\n sourceBoxId: string;\n sourceBoxName: string;\n /**\n * Source box's per-worktree paths so a restored box can re-bind\n * `/workspace` (and `/workspace/<sub>`) without rerunning `seedWorkspace`.\n * `docker commit` does NOT capture bind-mounted content, so the captured\n * image's `/workspace` is empty — the actual worktree files live under\n * `gitWorktreePath` (preserved in the image's writable layer). On restore,\n * `bindWorktrees` reads these to wire the binds back. Absent only for\n * no-git boxes (their `seedWorkspaceFromDir` puts files directly in\n * `/workspace`, which the bind logic doesn't touch).\n */\n worktrees?: GitWorktreeRecord[];\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\nexport function projectCheckpointsDir(projectRoot: string): string {\n return join(CHECKPOINTS_ROOT, projectDirSegment(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 !== 2) 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\n/**\n * Walk every per-project checkpoint manifest under CHECKPOINTS_ROOT and\n * return the union of their `image` tags. Used by `pruneBoxes({ all: true })`\n * to keep an image alive as long as any manifest on disk points at it —\n * destroy leaves the checkpoint behind by design, and the user expects to\n * still be able to start a new box from it long after the source box is gone.\n *\n * Best-effort, matching listSnapshotDirs / listBoxDirs in lifecycle.ts:\n * missing root, unreadable / non-schema-2 manifests, and non-directory\n * entries at any level are all skipped silently.\n */\nexport async function listAllCheckpointImages(): Promise<string[]> {\n let projectDirs: string[];\n try {\n projectDirs = (await readdir(CHECKPOINTS_ROOT, { withFileTypes: true }))\n .filter((e) => e.isDirectory())\n .map((e) => e.name);\n } catch {\n return [];\n }\n const out = new Set<string>();\n for (const proj of projectDirs) {\n const projPath = join(CHECKPOINTS_ROOT, proj);\n let names: string[];\n try {\n names = (await readdir(projPath, { withFileTypes: true }))\n .filter((e) => e.isDirectory())\n .map((e) => e.name);\n } catch {\n continue;\n }\n for (const name of names) {\n const manifest = await readManifest(join(projPath, name));\n if (manifest) out.add(manifest.image);\n }\n }\n return Array.from(out);\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 // Image is the durable artifact; best-effort because nothing else references\n // it once the manifest is gone. `-f` so a stale tag without containers is\n // dropped even if Docker considers it \"in use\" via dangling layers.\n await removeImage(manifest.image, { force: true });\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\nexport interface CreateCheckpointOptions {\n box: BoxRecord;\n projectRoot: string;\n name?: string;\n /** Force a flattened (export+`FROM scratch` rebuild) capture. */\n merged?: boolean;\n setDefault?: boolean;\n /**\n * If an existing checkpoint has the same name, delete it (manifest + image)\n * before capturing. Without this, name collisions throw `CheckpointError`.\n * Useful for idempotent re-runs from the in-box agent (`agentbox-ctl\n * checkpoint --replace`), e.g. when the previous invocation's stdout was\n * lost mid-flight and the agent can't tell whether it succeeded.\n */\n replace?: boolean;\n /** checkpoint.maxLayers — auto-flatten when the source chain is at/over this. */\n maxLayers: number;\n onLog?: (line: string) => void;\n}\n\n/**\n * Run the pre-commit cleanup in the box. Script is image-baked at\n * /usr/local/bin/agentbox-checkpoint-cleanup. Best-effort: a non-zero exit\n * from the cleanup logs but does not abort the capture (the script itself\n * is also `set +e` for the same reason).\n */\nasync function runCleanup(container: string, log: (line: string) => void): Promise<void> {\n const r = await execInBox(container, ['/usr/local/bin/agentbox-checkpoint-cleanup'], {\n user: 'root',\n });\n if (r.exitCode !== 0) {\n log(`warning: checkpoint cleanup exited ${String(r.exitCode)}: ${r.stderr.slice(0, 200)}`);\n }\n}\n\n/**\n * Read the base image's Config block so the flatten step can replay\n * Env/Cmd/Entrypoint/WorkingDir/User/ExposedPorts on the `FROM scratch`\n * rebuild. (`docker export` discards every Config field.)\n */\nasync function inspectImageConfig(imageRef: string): Promise<DockerImageConfig> {\n const r = await execa('docker', ['image', 'inspect', imageRef], { reject: false });\n if (r.exitCode !== 0) {\n throw new CheckpointError(`docker image inspect ${imageRef} failed`, r.stdout, r.stderr);\n }\n const parsed = JSON.parse(r.stdout) as Array<{ Config: DockerImageConfig }>;\n if (!Array.isArray(parsed) || parsed.length === 0 || !parsed[0]?.Config) {\n throw new CheckpointError(`unexpected docker image inspect shape for ${imageRef}`, r.stdout, '');\n }\n return parsed[0].Config;\n}\n\ninterface DockerImageConfig {\n Env?: string[];\n Cmd?: string[];\n Entrypoint?: string[] | null;\n WorkingDir?: string;\n User?: string;\n ExposedPorts?: Record<string, unknown>;\n}\n\n/**\n * Per-instance env keys that `docker commit` picks up from the running\n * container's Config and that must NOT be baked into a project-shared\n * checkpoint image. `runBox -e` sets these per launch; persisting them\n * would leak another box's relay token / VNC password / box-id into every\n * future box restored from this checkpoint.\n */\nconst RUNTIME_ENV_BLOCKLIST = new Set([\n 'AGENTBOX',\n 'AGENTBOX_BOX_ID',\n 'AGENTBOX_BOX_NAME',\n 'AGENTBOX_HOST_WORKSPACE',\n 'AGENTBOX_PROJECT_ROOT',\n 'AGENTBOX_PROJECT_INDEX',\n 'AGENTBOX_RELAY_URL',\n 'AGENTBOX_RELAY_TOKEN',\n 'AGENTBOX_VNC_PASSWORD',\n 'CLAUDE_EFFORT',\n 'CLAUDE_CODE_OAUTH_TOKEN',\n 'ANTHROPIC_API_KEY',\n 'ANTHROPIC_MODEL',\n]);\n\n/**\n * Render the Dockerfile lines that replay an image's Config on top of a\n * `FROM scratch\\nADD rootfs.tar /` base. Each Env entry becomes its own ENV\n * line (the Dockerfile `ENV KEY=value` form is the only one that safely\n * handles `=` in values). Per-instance env keys (RUNTIME_ENV_BLOCKLIST) are\n * stripped — those come from `docker run -e` at the source box's launch and\n * must not leak into a project-shared checkpoint image.\n * Cmd/Entrypoint are emitted in their JSON exec form.\n */\nfunction renderConfigDirectives(cfg: DockerImageConfig): string[] {\n const lines: string[] = [];\n for (const kv of cfg.Env ?? []) {\n const eq = kv.indexOf('=');\n if (eq <= 0) continue;\n const k = kv.slice(0, eq);\n if (RUNTIME_ENV_BLOCKLIST.has(k)) continue;\n const v = kv.slice(eq + 1);\n lines.push(`ENV ${k}=${dockerfileQuote(v)}`);\n }\n if (cfg.WorkingDir) lines.push(`WORKDIR ${cfg.WorkingDir}`);\n if (cfg.User) lines.push(`USER ${cfg.User}`);\n for (const p of Object.keys(cfg.ExposedPorts ?? {})) lines.push(`EXPOSE ${p.replace('/tcp', '')}`);\n if (cfg.Entrypoint && cfg.Entrypoint.length > 0) {\n lines.push(`ENTRYPOINT ${JSON.stringify(cfg.Entrypoint)}`);\n }\n if (cfg.Cmd && cfg.Cmd.length > 0) {\n lines.push(`CMD ${JSON.stringify(cfg.Cmd)}`);\n }\n return lines;\n}\n\n/** Dockerfile-safe quoting for ENV values (handles spaces and quotes). */\nfunction dockerfileQuote(v: string): string {\n if (/^[A-Za-z0-9._/:+@,=-]+$/.test(v)) return v;\n return `\"${v.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"')}\"`;\n}\n\n/**\n * Capture a box's accumulated state as a project checkpoint.\n *\n * - `layered`: `docker exec /usr/local/bin/agentbox-checkpoint-cleanup` then\n * `docker commit <container> <tag>`. Captures everything the container has\n * written *and* the inherited image layers; the new image's parent is the\n * container's current image (i.e. the previous checkpoint or the base).\n * - `flattened`: same prelude, then `docker export | docker build` against\n * a tiny `FROM scratch` Dockerfile that ADDs the rootfs tar and replays\n * the base image's Env/Cmd/Entrypoint/WorkingDir/User/ExposedPorts. The\n * resulting image is a single layer.\n *\n * Flattened is chosen when `--merged` is passed or the source box's chain is\n * already `>= maxLayers` deep (caps image-layer growth and reset lineage).\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 ? 'flattened' : 'layered';\n const name = opts.name ?? (await nextCheckpointName(opts.projectRoot, box.name));\n const dir = checkpointDir(opts.projectRoot, name);\n const existing = await readManifest(dir);\n if (existing) {\n if (opts.replace) {\n log(`replacing existing checkpoint ${name} (created ${existing.createdAt})`);\n await removeCheckpoint(opts.projectRoot, name);\n } else {\n // Surface the existing checkpoint's createdAt so a caller whose previous\n // stdout was lost (e.g. the in-box agent's harness wiping output) can\n // immediately tell whether their prior attempt succeeded. Same `rm`\n // hint, plus a `--replace` shortcut for idempotent re-runs.\n throw new CheckpointError(\n `checkpoint ${name} already exists (created ${existing.createdAt}; rm it or pass --replace to recapture)`,\n '',\n '',\n );\n }\n }\n const tag = checkpointImageTag(opts.projectRoot, name);\n await mkdir(dir, { recursive: true });\n\n log(`running pre-commit cleanup in ${box.container}`);\n await runCleanup(box.container, log);\n\n if (type === 'layered') {\n log(`docker commit ${box.container} -> ${tag} (layered)`);\n const r = await execa('docker', ['commit', box.container, tag], { reject: false });\n if (r.exitCode !== 0) {\n throw new CheckpointError(`docker commit failed for ${box.container}`, r.stdout, r.stderr);\n }\n } else {\n log(`docker commit ${box.container} -> <intermediate> (flattened path)`);\n // Two-step: commit first (so we can `docker export` from the resulting\n // image without disturbing the live container), then export+build.\n const intermediate = `${tag}-intermediate`;\n const commit = await execa('docker', ['commit', box.container, intermediate], {\n reject: false,\n });\n if (commit.exitCode !== 0) {\n throw new CheckpointError(`docker commit (intermediate) failed`, commit.stdout, commit.stderr);\n }\n try {\n await flattenImage(intermediate, tag, log);\n } finally {\n // The intermediate is layered (commits don't squash); replaced by the\n // flattened tag. -f because dangling tags would otherwise pin the\n // layered intermediate forever.\n await removeImage(intermediate, { force: true });\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: 2,\n name,\n type,\n image: tag,\n // Layered carries lineage forward; flattened is self-contained.\n parents: type === 'layered' ? (box.checkpointSource?.chain ?? []) : [],\n base,\n sourceBoxId: box.id,\n sourceBoxName: box.name,\n worktrees: box.gitWorktrees,\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 * Flatten a layered image: export its rootfs as a tar, wrap it in a tiny\n * `FROM scratch` Dockerfile that replays the source image's Config block,\n * and build the result. Leaves the source image alone (caller removes it).\n */\nasync function flattenImage(\n sourceTag: string,\n destTag: string,\n log: (line: string) => void,\n): Promise<void> {\n // `docker export` needs a *container*, so create one without running it.\n const tmpName = `agentbox-flatten-${Date.now().toString(36)}`;\n const create = await execa(\n 'docker',\n ['create', '--name', tmpName, sourceTag, 'sleep', '0'],\n { reject: false },\n );\n if (create.exitCode !== 0) {\n throw new CheckpointError(`docker create for flatten failed`, create.stdout, create.stderr);\n }\n const scratch = await mkdtemp(join(tmpdir(), 'agentbox-flatten-'));\n try {\n const rootfsPath = join(scratch, 'rootfs.tar');\n log(`exporting rootfs of ${sourceTag} to ${rootfsPath}`);\n const exp = await execa('docker', ['export', '-o', rootfsPath, tmpName], { reject: false });\n if (exp.exitCode !== 0) {\n throw new CheckpointError(`docker export failed`, exp.stdout, exp.stderr);\n }\n\n // The Config block to replay is the *source* image's — that's what the\n // running container saw, and `docker commit` carries it through\n // unmodified. `docker export` drops it, which is the only reason we need\n // to inspect+replay here.\n const cfg = await inspectImageConfig(sourceTag);\n const lines = [\n 'FROM scratch',\n // ADD untars during build (Docker's documented behavior for local tars).\n 'ADD rootfs.tar /',\n ...renderConfigDirectives(cfg),\n ];\n await writeFile(join(scratch, 'Dockerfile'), lines.join('\\n') + '\\n', 'utf8');\n\n log(`building flattened ${destTag} from rootfs.tar (FROM scratch)`);\n const build = await execa(\n 'docker',\n ['build', '-t', destTag, '-f', join(scratch, 'Dockerfile'), scratch],\n { reject: false },\n );\n if (build.exitCode !== 0) {\n throw new CheckpointError(`flatten docker build failed`, build.stdout, build.stderr);\n }\n } finally {\n await execa('docker', ['rm', '-f', tmpName], { reject: false });\n await rm(scratch, { recursive: true, force: true });\n }\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/** Kept for the type-only import in `image.ts`'s self-update path. */\nexport const _DEFAULT_BASE_IMAGE_REF = DEFAULT_BOX_IMAGE;\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 { basename, 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\n/**\n * Make `raw` safe to embed as the mnemonic half of an on-disk dir segment or a\n * Docker tag repo. Lowercased so docker tag repos stay valid; `-` collapses to\n * `_` so the single `-` between hash and mnemonic remains the only one (which\n * is what `listProjectsConfigured` parses on). Bounded length, never empty.\n */\nexport function sanitizeMnemonic(raw: string): string {\n return (\n raw\n .toLowerCase()\n .replace(/-/g, '_')\n .replace(/[^a-z0-9_]+/g, '_')\n .replace(/_+/g, '_')\n .replace(/^_+|_+$/g, '')\n .slice(0, 32) || 'unnamed'\n );\n}\n\n/**\n * On-disk dir segment for a project under `~/.agentbox/projects/` and\n * `~/.agentbox/checkpoints/`: `<hash>-<mnemonic>`. The hash stays the\n * canonical key; the trailing mnemonic is decorative — readers parse the hash\n * as the leading 16 hex chars and ignore the suffix.\n */\nexport function projectDirSegment(absPath: string): string {\n return `${hashProjectPath(absPath)}-${sanitizeMnemonic(basename(absPath))}`;\n}\n\nexport function projectConfigDir(absPath: string): string {\n return join(PROJECTS_DIR, projectDirSegment(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 /** SHA-1 (first 16 hex chars) of `originalPath` — the canonical key. */\n hash: string;\n /**\n * On-disk dir name under `PROJECTS_DIR`. Equal to the hash for legacy\n * pre-rename dirs; `<hash>-<mnemonic>` for new dirs. Used directly when we\n * need to `rm` the dir so the call works regardless of which shape happens\n * to be on disk.\n */\n dirName: 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 dirName of entries) {\n // Dir shape is `<sha1-16>` (legacy) or `<sha1-16>-<mnemonic>` (current);\n // either way the leading 16 hex chars are the canonical key.\n const m = /^([0-9a-f]{16})(?:-.+)?$/.exec(dirName);\n if (!m) continue;\n const hash = m[1]!;\n const meta = await readMeta(dirName);\n if (!meta) continue;\n const cfgPath = projectConfigFile(meta.originalPath);\n const hasConfig = await fileExists(cfgPath);\n out.push({\n hash,\n dirName,\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 dir name (originalPath is gone, so recomputing\n // the segment from it would be pointless; entry.dirName preserves\n // whichever shape — legacy `<hash>` or new `<hash>-<mnemonic>` —\n // happens to be on disk).\n await rm(join(PROJECTS_DIR, entry.dirName), { 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 dirName: string,\n): Promise<{ originalPath: string; createdAt: string | null; lastSeenAt: string | null } | null> {\n const metaPath = `${PROJECTS_DIR}/${dirName}/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,iBAAgB;AAChC,SAAS,WAAAC,gBAAe;AACxB,SAAS,QAAAC,aAAY;AACrB,SAAS,SAAAC,cAAa;;;AIHtB,SAAS,SAAS,iBAAiB;ACAnC,SAAS,kBAAkB;AAC3B,SAAS,UAAU,YAAY;AAC/B,SAAS,eAAe;AACxB,SAAS,UAAU,SAAS,MAAM,eAAe;ACHjD,SAAS,gBAAgB;AACzB,SAAS,SAASC,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,KAAK;IACL,MAAM;IACN,aACE;EACJ;EACA;IACE,KAAK;IACL,MAAM;IACN,aAAa;EACf;AACF;AAEA,IAAM,kBAAkB,IAAI,IAA2B,aAAa,IAAI,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;AAEnF,SAAS,UAAU,KAAwC;AAChE,SAAO,gBAAgB,IAAI,GAAG;AAChC;AAEO,IAAM,kBAAN,cAA8B,MAAM;EACzC,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;EACd;AACF;AC/YA,SAAS,cAAc,GAA0C;AAC/D,SAAO,OAAO,MAAM,YAAY,MAAM,QAAQ,CAAC,MAAM,QAAQ,CAAC;AAChE;AAGA,IAAM,eAA4C,oBAAI,IAAI,CAAC,CAAC,gBAAgB,kBAAkB,CAAC,CAAC;AAQhG,IAAM,YAAqC,MAAM;AAC/C,QAAM,MAAM,oBAAI,IAAwB;AACxC,aAAW,QAAQ,cAAc;AAC/B,UAAM,MAAM,KAAK,IAAI,QAAQ,GAAG;AAChC,QAAI,MAAM,GAAG;AACX,YAAM,IAAI,MAAM,sBAAsB,KAAK,GAAG,uCAAuC;IACvF;AACA,UAAM,SAAS,KAAK,IAAI,MAAM,GAAG,GAAG;AACpC,UAAM,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AACnC,QAAI,QAAQ,IAAI,IAAI,MAAM;AAC1B,QAAI,CAAC,OAAO;AACV,cAAQ,EAAE,MAAM,QAAQ,QAAQ,oBAAI,IAAI,EAAE;AAC1C,UAAI,IAAI,QAAQ,KAAK;IACvB;AACA,UAAM,OAAO,IAAI,MAAM,IAAI;EAC7B;AACA,SAAO;AACT,GAAG;AAOH,SAAS,iBAAiB,KAAc,MAAqB,OAAwB;AACnF,MAAI,QAAQ,MAAM;AAChB,UAAM,IAAI,gBAAgB,GAAG,KAAK,4DAA4D;EAChG;AACA,UAAQ,KAAK,MAAM;IACjB,KAAK;AACH,UAAI,OAAO,QAAQ,WAAW;AAC5B,cAAM,IAAI,gBAAgB,GAAG,KAAK,2BAA2B,OAAO,GAAG,GAAG;MAC5E;AACA,aAAO;IACT,KAAK;AACH,UAAI,OAAO,QAAQ,UAAU;AAC3B,cAAM,IAAI,gBAAgB,GAAG,KAAK,0BAA0B,OAAO,GAAG,GAAG;MAC3E;AACA,UAAI,IAAI,WAAW,GAAG;AACpB,cAAM,IAAI,gBAAgB,GAAG,KAAK,oBAAoB;MACxD;AACA,aAAO;IACT,KAAK;AACH,UAAI,OAAO,QAAQ,YAAY,CAAC,OAAO,UAAU,GAAG,GAAG;AACrD,cAAM,IAAI,gBAAgB,GAAG,KAAK,4BAA4B,OAAO,GAAG,CAAC,GAAG;MAC9E;AACA,aAAO;IACT,KAAK;AACH,UAAI,OAAO,QAAQ,YAAY,CAAC,KAAK,WAAY,SAAS,GAAG,GAAG;AAC9D,cAAM,IAAI;UACR,GAAG,KAAK,oBAAoB,KAAK,WAAY,KAAK,IAAI,CAAC,SAAS,OAAO,GAAG,CAAC;QAC7E;MACF;AACA,aAAO;EACX;AACF;AASO,SAAS,gBAAgB,MAAc,OAAoC;AAChF,MAAI;AACJ,MAAI;AACF,UAAM,UAAU,IAAI;EACtB,SAAS,KAAK;AACZ,UAAM,IAAI;MACR,GAAG,KAAK,uBAAuB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;IACjF;EACF;AACA,MAAI,QAAQ,QAAQ,QAAQ,OAAW,QAAO,CAAC;AAC/C,MAAI,CAAC,cAAc,GAAG,GAAG;AACvB,UAAM,IAAI,gBAAgB,GAAG,KAAK,+BAA+B;EACnE;AACA,SAAO,sBAAsB,KAAK,KAAK;AACzC;AAOO,SAAS,sBAAsB,KAAc,OAAoC;AACtF,MAAI,QAAQ,QAAQ,QAAQ,OAAW,QAAO,CAAC;AAC/C,MAAI,CAAC,cAAc,GAAG,GAAG;AACvB,UAAM,IAAI,gBAAgB,GAAG,KAAK,qBAAqB;EACzD;AAEA,QAAM,MAA2B,CAAC;AAClC,aAAW,CAAC,YAAY,SAAS,KAAK,OAAO,QAAQ,GAAG,GAAG;AACzD,UAAM,aAAa,SAAS,IAAI,UAAU;AAC1C,QAAI,CAAC,YAAY;AACf,YAAM,IAAI;QACR,GAAG,KAAK,6BAA6B,UAAU,aAAa,CAAC,GAAG,SAAS,KAAK,CAAC,EAAE,KAAK,IAAI,CAAC;MAC7F;IACF;AACA,QAAI,cAAc,QAAQ,cAAc,OAAW;AACnD,QAAI,CAAC,cAAc,SAAS,GAAG;AAC7B,YAAM,IAAI,gBAAgB,GAAG,KAAK,IAAI,UAAU,qBAAqB;IACvE;AACA,UAAM,YAAqC,CAAC;AAC5C,eAAW,CAAC,UAAU,OAAO,KAAK,OAAO,QAAQ,SAAS,GAAG;AAC3D,YAAM,OAAO,WAAW,OAAO,IAAI,QAAQ;AAC3C,UAAI,CAAC,MAAM;AACT,cAAM,YAAY,aAAa,IAAI,GAAG,UAAU,IAAI,QAAQ,EAAE;AAC9D,YAAI,WAAW;AACb,gBAAM,IAAI;YACR,GAAG,KAAK,IAAI,UAAU,IAAI,QAAQ,mBAAmB,SAAS;UAChE;QACF;AACA,cAAM,IAAI;UACR,GAAG,KAAK,IAAI,UAAU,kBAAkB,QAAQ,aAAa,CAAC,GAAG,WAAW,OAAO,KAAK,CAAC,EAAE,KAAK,IAAI,CAAC;QACvG;MACF;AACA,UAAI,YAAY,OAAW;AAC3B,gBAAU,QAAQ,IAAI,iBAAiB,SAAS,MAAM,GAAG,KAAK,IAAI,KAAK,GAAG,EAAE;IAC9E;AACA,QAAI,OAAO,KAAK,SAAS,EAAE,SAAS,GAAG;AAGpC,UAAgC,UAAU,IAAI;IACjD;EACF;AACA,SAAO;AACT;AAOO,SAAS,iBAAiB,KAAa,KAAsB;AAClE,QAAM,OAAO,iBAAiB,GAAG;AACjC,UAAQ,KAAK,MAAM;IACjB,KAAK,QAAQ;AACX,YAAM,IAAI,IAAI,KAAK,EAAE,YAAY;AACjC,UAAI,MAAM,UAAU,MAAM,SAAS,MAAM,OAAO,MAAM,KAAM,QAAO;AACnE,UAAI,MAAM,WAAW,MAAM,QAAQ,MAAM,OAAO,MAAM,MAAO,QAAO;AACpE,YAAM,IAAI,gBAAgB,GAAG,GAAG,2CAA2C,GAAG,GAAG;IACnF;IACA,KAAK;AACH,UAAI,IAAI,WAAW,EAAG,OAAM,IAAI,gBAAgB,GAAG,GAAG,qBAAqB;AAC3E,aAAO;IACT,KAAK,OAAO;AACV,YAAM,IAAI,OAAO,GAAG;AACpB,UAAI,CAAC,OAAO,SAAS,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,GAAG;AAC/C,cAAM,IAAI,gBAAgB,GAAG,GAAG,+BAA+B,GAAG,GAAG;MACvE;AACA,aAAO;IACT;IACA,KAAK;AACH,UAAI,CAAC,KAAK,WAAY,SAAS,GAAG,GAAG;AACnC,cAAM,IAAI;UACR,GAAG,GAAG,qBAAqB,KAAK,WAAY,KAAK,IAAI,CAAC,UAAU,GAAG;QACrE;MACF;AACA,aAAO;EACX;AACF;AAEA,SAAS,iBAAiB,KAA4B;AACpD,QAAM,YAAY,aAAa,IAAI,GAAG;AACtC,MAAI,WAAW;AACb,UAAM,IAAI,gBAAgB,GAAG,GAAG,mBAAmB,SAAS,eAAU,SAAS,UAAU;EAC3F;AACA,QAAM,MAAM,IAAI,QAAQ,GAAG;AAC3B,MAAI,MAAM,GAAG;AACX,UAAM,IAAI,gBAAgB,gBAAgB,GAAG,iCAAiC;EAChF;AACA,QAAM,SAAS,SAAS,IAAI,IAAI,MAAM,GAAG,GAAG,CAAC;AAC7C,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI;MACR,2BAA2B,IAAI,MAAM,GAAG,GAAG,CAAC,aAAa,CAAC,GAAG,SAAS,KAAK,CAAC,EAAE,KAAK,IAAI,CAAC;IAC1F;EACF;AACA,QAAM,OAAO,OAAO,OAAO,IAAI,IAAI,MAAM,MAAM,CAAC,CAAC;AACjD,MAAI,CAAC,MAAM;AACT,UAAM,IAAI;MACR,gBAAgB,GAAG,eAAe,OAAO,IAAI,KAAK,CAAC,GAAG,OAAO,OAAO,KAAK,CAAC,EAAE,KAAK,IAAI,CAAC;IACxF;EACF;AACA,SAAO;AACT;ACxMO,IAAM,YAAY,KAAK,QAAQ,GAAG,WAAW;AAC7C,IAAM,qBAAqB,KAAK,WAAW,aAAa;AACxD,IAAM,eAAe,KAAK,WAAW,UAAU;AAC/C,IAAM,4BAA4B;AAkBzC,eAAsB,gBAAgB,KAAmC;AACvE,QAAM,QAAQ,MAAM,aAAa,GAAG;AACpC,MAAI,MAAM;AAEV,WAAS,IAAI,GAAG,IAAI,IAAI,KAAK;AAC3B,QAAI,MAAM,WAAW,KAAK,KAAK,yBAAyB,CAAC,GAAG;AAC1D,aAAO,EAAE,MAAM,KAAK,iBAAiB,KAAK;IAC5C;AACA,UAAM,SAAS,QAAQ,GAAG;AAC1B,QAAI,WAAW,IAAK;AACpB,UAAM;EACR;AACA,SAAO,EAAE,MAAM,OAAO,iBAAiB,MAAM;AAC/C;AAEA,eAAe,aAAa,GAA4B;AACtD,QAAM,MAAM,QAAQ,CAAC;AAIrB,MAAI;AACF,WAAO,MAAM,SAAS,GAAG;EAC3B,QAAQ;AACN,WAAO;EACT;AACF;AAEA,eAAe,WAAW,GAA6B;AACrD,MAAI;AACF,UAAM,KAAK,MAAM,KAAK,CAAC;AACvB,WAAO,GAAG,OAAO;EACnB,QAAQ;AACN,WAAO;EACT;AACF;AAOO,SAAS,gBAAgB,SAAyB;AACvD,QAAM,aAAa,QAAQ,SAAS,KAAK,QAAQ,SAAS,GAAG,IACzD,QAAQ,MAAM,GAAG,EAAE,IACnB;AACJ,SAAO,WAAW,MAAM,EAAE,OAAO,UAAU,EAAE,OAAO,KAAK,EAAE,MAAM,GAAG,EAAE;AACxE;AAQO,SAAS,iBAAiB,KAAqB;AACpD,SACE,IACG,YAAY,EACZ,QAAQ,MAAM,GAAG,EACjB,QAAQ,gBAAgB,GAAG,EAC3B,QAAQ,OAAO,GAAG,EAClB,QAAQ,YAAY,EAAE,EACtB,MAAM,GAAG,EAAE,KAAK;AAEvB;AAQO,SAAS,kBAAkB,SAAyB;AACzD,SAAO,GAAG,gBAAgB,OAAO,CAAC,IAAI,iBAAiB,SAAS,OAAO,CAAC,CAAC;AAC3E;AAEO,SAAS,iBAAiB,SAAyB;AACxD,SAAO,KAAK,cAAc,kBAAkB,OAAO,CAAC;AACtD;AAEO,SAAS,kBAAkB,SAAyB;AACzD,SAAO,KAAK,iBAAiB,OAAO,GAAG,aAAa;AACtD;AAEO,SAAS,gBAAgB,SAAyB;AACvD,SAAO,KAAK,iBAAiB,OAAO,GAAG,WAAW;AACpD;AAEO,SAAS,oBAAoB,eAA+B;AACjE,SAAO,KAAK,eAAe,yBAAyB;AACtD;AAOA,eAAsB,cACpB,OACA,KACiB;AACjB,MAAI,UAAU,SAAU,QAAO;AAC/B,QAAM,OAAO,MAAM,gBAAgB,GAAG;AACtC,MAAI,UAAU,UAAW,QAAO,kBAAkB,KAAK,IAAI;AAC3D,SAAO,oBAAoB,KAAK,IAAI;AACtC;AC9GA,eAAe,uBAAuB,MAA4C;AAChF,MAAI;AACJ,MAAI;AACF,WAAO,MAAM,SAAS,MAAM,MAAM;EACpC,SAAS,KAAK;AACZ,QAAK,IAA8B,SAAS,SAAU,QAAO,CAAC;AAC9D,UAAM;EACR;AACA,SAAO,gBAAgB,MAAM,IAAI;AACnC;AAWA,eAAsB,4BACpB,eAC8B;AAC9B,QAAM,OAAO,oBAAoB,aAAa;AAC9C,MAAI;AACJ,MAAI;AACF,WAAO,MAAM,SAAS,MAAM,MAAM;EACpC,SAAS,KAAK;AACZ,QAAK,IAA8B,SAAS,SAAU,QAAO,CAAC;AAC9D,UAAM;EACR;AACA,MAAI;AACJ,MAAI;AACF,UAAMJ,WAAU,IAAI;EACtB,QAAQ;AAGN,WAAO,CAAC;EACV;AACA,MAAI,QAAQ,QAAQ,QAAQ,UAAa,OAAO,QAAQ,YAAY,MAAM,QAAQ,GAAG,GAAG;AACtF,WAAO,CAAC;EACV;AACA,QAAM,WAAY,IAAgC,UAAU;AAC5D,MAAI,aAAa,UAAa,aAAa,KAAM,QAAO,CAAC;AACzD,SAAO,sBAAsB,UAAU,GAAG,IAAI,WAAW;AAC3D;AAcA,eAAsB,oBACpB,KACA,OAAmC,CAAC,GACb;AACvB,QAAM,cAAc,MAAM,gBAAgB,GAAG;AAC7C,QAAM,cAAc,kBAAkB,YAAY,IAAI;AACtD,QAAM,gBAAgB,YAAY,kBAAkB,oBAAoB,YAAY,IAAI,IAAI;AAE5F,QAAM,CAAC,cAAc,eAAe,eAAe,IAAI,MAAM,QAAQ,IAAI;IACvE,uBAAuB,kBAAkB;IACzC,uBAAuB,WAAW;IAClC,gBAAgB,4BAA4B,YAAY,IAAI,IAAI,QAAQ,QAAQ,CAAC,CAAC;EACpF,CAAC;AAED,QAAM,YAAY,KAAK,gBAAgB,CAAC;AAExC,QAAM,EAAE,WAAW,QAAQ,IAAI,YAAY;IACzC,KAAK;IACL,WAAW;IACX,SAAS;IACT,QAAQ;EACV,CAAC;AAED,SAAO;IACL;IACA,QAAQ;MACN,KAAK,EAAE,QAAQ,UAAU;MACzB,WAAW,EAAE,MAAM,eAAe,QAAQ,gBAAgB;MAC1D,SAAS,EAAE,MAAM,aAAa,QAAQ,cAAc;MACpD,QAAQ,EAAE,MAAM,oBAAoB,QAAQ,aAAa;MACzD,UAAU;IACZ;IACA;IACA,aAAa,YAAY;IACzB,aAAa,gBAAgB,YAAY,IAAI;IAC7C,iBAAiB,YAAY;EAC/B;AACF;AAcA,SAAS,YAAY,OAGnB;AAEA,QAAM,YAA6B,KAAK,MAAM,KAAK,UAAU,iBAAiB,CAAC;AAC/E,QAAM,UAAwC,CAAC;AAE/C,QAAM,aAA2E;IAC/E,EAAE,QAAQ,OAAO,QAAQ,MAAM,IAAI;IACnC,EAAE,QAAQ,aAAa,QAAQ,MAAM,UAAU;IAC/C,EAAE,QAAQ,WAAW,QAAQ,MAAM,QAAQ;IAC3C,EAAE,QAAQ,UAAU,QAAQ,MAAM,OAAO;EAC3C;AAEA,aAAW,QAAQ,cAAc;AAC/B,UAAM,MAAM,KAAK,IAAI,QAAQ,GAAG;AAChC,UAAM,SAAS,KAAK,IAAI,MAAM,GAAG,GAAG;AACpC,UAAM,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAEnC,QAAI,SAA0D;AAC9D,eAAW,SAAS,YAAY;AAC9B,YAAM,IAAI,SAAS,MAAM,QAAQ,QAAQ,IAAI;AAC7C,UAAI,MAAM,QAAW;AACnB,iBAAS,EAAE,QAAQ,MAAM,QAAQ,OAAO,EAAE;AAC1C;MACF;IACF;AAEA,QAAI,QAAQ;AACV,gBAAU,WAAW,QAAQ,MAAM,OAAO,KAAK;AAC/C,cAAQ,KAAK,GAAG,IAAI,OAAO;IAC7B,OAAO;AACL,cAAQ,KAAK,GAAG,IAAI;IACtB;EACF;AAEA,SAAO,EAAE,WAAW,QAAQ;AAC9B;AAEA,SAAS,SACP,KACA,QACA,MACS;AACT,QAAM,IAAK,IAAgC,MAAM;AACjD,MAAI,MAAM,UAAa,MAAM,QAAQ,OAAO,MAAM,SAAU,QAAO;AACnE,SAAQ,EAA8B,IAAI;AAC5C;AAEA,SAAS,UACP,KACA,QACA,MACA,OACM;AACN,QAAM,IAAK,IAA2D,MAAM;AAC5E,MAAI,CAAC,EAAG;AACR,IAAE,IAAI,IAAI;AACZ;AC7JA,eAAsB,eACpB,OACA,KACA,OACA,KACA,OAAmB,CAAC,GACE;AACtB,MAAI,CAAC,UAAU,GAAG,GAAG;AACnB,UAAM,IAAI,gBAAgB,gBAAgB,GAAG,GAAG;EAClD;AAEA,QAAM,UAAU,KAAK,OAAO,OAAO,UAAU,WACzC,iBAAiB,KAAK,KAAK,IAC3B;AAEJ,QAAM,OAAO,MAAM,cAAc,OAAO,GAAG;AAC3C,QAAM,UAAU,MAAM,gBAAgB,IAAI;AAC1C,UAAQ,SAAS,KAAK,OAAO;AAG7B,kBAAgB,cAAc,OAAO,GAAG,IAAI;AAC5C,QAAM,gBAAgB,MAAM,OAAO;AAEnC,MAAI,UAAU,WAAW;AACvB,UAAM,QAAQ,MAAM,gBAAgB,GAAG,GAAG;AAC1C,UAAM,iBAAiB,IAAI;EAC7B;AAEA,SAAO,EAAE,MAAM,QAAQ;AACzB;AAMA,eAAsB,iBACpB,OACA,KACA,KAC6C;AAC7C,MAAI,CAAC,UAAU,GAAG,GAAG;AACnB,UAAM,IAAI,gBAAgB,gBAAgB,GAAG,GAAG;EAClD;AACA,QAAM,OAAO,MAAM,cAAc,OAAO,GAAG;AAC3C,QAAM,UAAU,MAAM,gBAAgB,IAAI;AAC1C,QAAM,UAAU,UAAU,SAAS,GAAG;AACtC,MAAI,CAAC,QAAS,QAAO,EAAE,MAAM,SAAS,MAAM;AAC5C,QAAM,gBAAgB,MAAM,OAAO;AACnC,MAAI,UAAU,WAAW;AACvB,UAAM,QAAQ,MAAM,gBAAgB,GAAG,GAAG;AAC1C,UAAM,iBAAiB,IAAI;EAC7B;AACA,SAAO,EAAE,MAAM,SAAS,KAAK;AAC/B;AAuBA,eAAsB,yBAAkD;AACtE,MAAI;AACJ,MAAI;AACF,cAAU,MAAM,QAAQ,YAAY;EACtC,SAAS,KAAK;AACZ,QAAK,IAA8B,SAAS,SAAU,QAAO,CAAC;AAC9D,UAAM;EACR;AACA,QAAM,MAAsB,CAAC;AAC7B,aAAW,WAAW,SAAS;AAG7B,UAAM,IAAI,2BAA2B,KAAK,OAAO;AACjD,QAAI,CAAC,EAAG;AACR,UAAM,OAAO,EAAE,CAAC;AAChB,UAAM,OAAO,MAAM,SAAS,OAAO;AACnC,QAAI,CAAC,KAAM;AACX,UAAM,UAAU,kBAAkB,KAAK,YAAY;AACnD,UAAM,YAAY,MAAMK,YAAW,OAAO;AAC1C,QAAI,KAAK;MACP;MACA;MACA,cAAc,KAAK;MACnB,WAAW,KAAK;MAChB,YAAY,KAAK;MACjB,YAAY;MACZ,eAAe;IACjB,CAAC;EACH;AACA,MAAI,KAAK,CAAC,GAAG,MAAM,EAAE,aAAa,cAAc,EAAE,YAAY,CAAC;AAC/D,SAAO;AACT;AAqBA,eAAsB,0BACpB,OAAyC,CAAC,GACA;AAC1C,QAAM,SAAS,KAAK,UAAU;AAC9B,QAAM,OAAO,IAAI,IAAI,KAAK,kBAAkB,CAAC,CAAC;AAC9C,QAAM,UAAoD,CAAC;AAC3D,aAAW,SAAS,MAAM,uBAAuB,GAAG;AAClD,QAAI,CAAC,WAAW,MAAM,YAAY,KAAK,KAAK,IAAI,MAAM,YAAY,EAAG;AACrE,QAAI,UAAU;AACd,QAAI;AACF,YAAMH,MAAK,MAAM,YAAY;IAC/B,SAAS,KAAK;AACZ,UAAK,IAA8B,SAAS,SAAU,WAAU;IAClE;AACA,QAAI,CAAC,QAAS;AACd,YAAQ,KAAK,EAAE,MAAM,MAAM,MAAM,cAAc,MAAM,aAAa,CAAC;AACnE,QAAI,CAAC,QAAQ;AACX,UAAI;AAKF,cAAM,GAAGE,MAAK,cAAc,MAAM,OAAO,GAAG,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;MAC9E,QAAQ;MAER;IACF;EACF;AACA,SAAO,EAAE,SAAS,OAAO;AAC3B;AAOA,IAAM,0BAA0BA,MAAK,cAAc,UAAU;AAG7D,eAAsB,uBAAwC;AAC5D,MAAI,QAAQ;AACZ,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,MAAMH,UAAS,yBAAyB,MAAM,CAAC;AAGzE,QAAI,OAAO,OAAO,YAAY,YAAY,OAAO,SAAS,OAAO,OAAO,GAAG;AACzE,cAAQ,OAAO;IACjB;EACF,QAAQ;EAER;AACA,QAAM,OAAO,QAAQ;AACrB,QAAM,MAAM,cAAc,EAAE,WAAW,KAAK,CAAC;AAC7C,QAAM,MAAM,GAAG,uBAAuB,QAAQ,QAAQ,IAAI,SAAS,CAAC,IAAI,KAAK,IAAI,EAAE,SAAS,EAAE,CAAC;AAC/F,QAAM,UAAU,KAAK,KAAK,UAAU,EAAE,SAAS,KAAK,CAAC,IAAI,MAAM,EAAE,UAAU,QAAQ,MAAM,IAAM,CAAC;AAChG,QAAM,OAAO,KAAK,uBAAuB;AACzC,SAAO;AACT;AAEA,eAAe,SACb,SAC+F;AAC/F,QAAM,WAAW,GAAG,YAAY,IAAI,OAAO;AAC3C,MAAI;AACF,UAAM,OAAO,MAAMA,UAAS,UAAU,MAAM;AAC5C,UAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,QAAI,OAAO,OAAO,cAAc,MAAM,SAAU,QAAO;AACvD,WAAO;MACL,cAAc,OAAO,cAAc;MACnC,WAAW,OAAO,OAAO,WAAW,MAAM,WAAW,OAAO,WAAW,IAAI;MAC3E,YAAY,OAAO,OAAO,YAAY,MAAM,WAAW,OAAO,YAAY,IAAI;IAChF;EACF,QAAQ;AACN,WAAO;EACT;AACF;AAEA,eAAeI,YAAW,GAA6B;AACrD,MAAI;AACF,UAAM,KAAK,MAAMH,MAAK,CAAC;AACvB,WAAO,GAAG,OAAO;EACnB,QAAQ;AACN,WAAO;EACT;AACF;AAEA,eAAe,gBAAgB,MAA4C;AACzE,MAAI;AACJ,MAAI;AACF,WAAO,MAAMD,UAAS,MAAM,MAAM;EACpC,SAAS,KAAK;AACZ,QAAK,IAA8B,SAAS,SAAU,QAAO,CAAC;AAC9D,UAAM;EACR;AACA,SAAO,gBAAgB,MAAM,IAAI;AACnC;AAEA,SAAS,QAAQ,KAA0B,KAAa,OAAsB;AAC5E,QAAM,MAAM,IAAI,QAAQ,GAAG;AAC3B,QAAM,SAAS,IAAI,MAAM,GAAG,GAAG;AAC/B,QAAM,OAAO,IAAI,MAAM,MAAM,CAAC;AAC9B,QAAM,OAAO;AACb,MAAI,CAAC,KAAK,MAAM,KAAK,OAAO,KAAK,MAAM,MAAM,UAAU;AACrD,SAAK,MAAM,IAAI,CAAC;EAClB;AACA,OAAK,MAAM,EAAE,IAAI,IAAI;AACvB;AAEA,SAAS,UAAU,KAA0B,KAAsB;AACjE,QAAM,MAAM,IAAI,QAAQ,GAAG;AAC3B,QAAM,SAAS,IAAI,MAAM,GAAG,GAAG;AAC/B,QAAM,OAAO,IAAI,MAAM,MAAM,CAAC;AAC9B,QAAM,OAAO;AACb,QAAM,IAAI,KAAK,MAAM;AACrB,MAAI,CAAC,KAAK,OAAO,MAAM,YAAY,EAAE,QAAQ,GAAI,QAAO;AACxD,SAAO,EAAE,IAAI;AACb,MAAI,OAAO,KAAK,CAAC,EAAE,WAAW,GAAG;AAC/B,WAAO,KAAK,MAAM;EACpB;AACA,SAAO;AACT;AAEA,eAAe,gBAAgB,MAAc,KAAyC;AACpF,QAAM,MAAME,SAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAG9C,QAAM,OAAO,OAAO,KAAK,GAAG,EAAE,WAAW,IACrC,gDACA,cAAc,GAAG;AACrB,QAAM,MAAM,GAAG,IAAI,QAAQ,QAAQ,IAAI,SAAS,CAAC,IAAI,KAAK,IAAI,EAAE,SAAS,EAAE,CAAC;AAC5E,QAAM,UAAU,KAAK,MAAM,EAAE,UAAU,QAAQ,MAAM,IAAM,CAAC;AAC5D,QAAM,OAAO,KAAK,IAAI;AACxB;AAEA,eAAe,iBAAiB,SAAgC;AAC9D,QAAM,MAAMA,SAAQ,gBAAgB,OAAO,CAAC;AAC5C,QAAM,MAAM,KAAK,EAAE,WAAW,KAAK,CAAC;AACpC,QAAM,WAAW,gBAAgB,OAAO;AACxC,MAAI,QAAuD,CAAC;AAC5D,MAAI;AACF,YAAQ,KAAK,MAAM,MAAMF,UAAS,UAAU,MAAM,CAAC;EACrD,QAAQ;EAER;AACA,QAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,QAAM,OAAO;IACX,cAAc;IACd,MAAM,gBAAgB,OAAO;IAC7B,WAAW,MAAM,aAAa;IAC9B,YAAY;EACd;AACA,QAAM,MAAM,GAAG,QAAQ,QAAQ,QAAQ,IAAI,SAAS,CAAC,IAAI,KAAK,IAAI,EAAE,SAAS,EAAE,CAAC;AAChF,QAAM,UAAU,KAAK,KAAK,UAAU,MAAM,MAAM,CAAC,IAAI,MAAM,EAAE,UAAU,QAAQ,MAAM,IAAM,CAAC;AAC5F,QAAM,OAAO,KAAK,QAAQ;AAC5B;;;AN5TA,SAAS,SAAAK,cAAa;AACtB,SAAS,kBAAkB;AAC3B,SAAS,qBAAqB;AAC9B,SAAS,WAAAC,UAAS,WAAAC,gBAAe;ACHjC,SAAS,SAAAC,SAAO,SAAS,YAAAC,YAAU,WAAAC,UAAS,MAAAC,KAAI,aAAAC,kBAAiB;AACjE,SAAS,WAAAC,WAAS,cAAc;AAChC,SAAS,YAAAC,WAAU,QAAAC,cAAY;AAC/B,SAAS,SAAAV,cAAa;AHOtB,eAAsB,aAA4B;AAChD,QAAM,SAAiB,MAAM,MAAM,UAAU,CAAC,MAAM,GAAG,EAAE,QAAQ,MAAM,CAAC;AACxE,MAAI,OAAO,aAAa,GAAG;AACzB,UAAM,IAAI;MACR,4BAA4B,OAAO,OAAO,QAAQ,CAAC;EAAqC,OAAO,OAAO,MAAM,CAAC;IAC/G;EACF;AACF;AA4BA,eAAsB,OAAO,MAAmC;AAC9D,QAAM,OAAiB;IACrB;IACA;IACA;IACA,KAAK;IACL;IACA,KAAK;IACL;;;;;;;IAOA;;;;;;;;IAQA;IACA;IACA;;;;;;;IAOA;;;;;IAKA;EACF;AACA,QAAM,MAAM,KAAK;AACjB,MAAI,KAAK;AACP,QAAI,IAAI,eAAe,IAAI,cAAc,GAAG;AAC1C,WAAK,KAAK,YAAY,OAAO,KAAK,MAAM,IAAI,WAAW,CAAC,CAAC;IAC3D;AACA,QAAI,IAAI,QAAQ,IAAI,OAAO,GAAG;AAC5B,WAAK,KAAK,UAAU,OAAO,IAAI,IAAI,CAAC;IACtC;AACA,QAAI,IAAI,aAAa,IAAI,YAAY,GAAG;AACtC,WAAK,KAAK,gBAAgB,OAAO,KAAK,MAAM,IAAI,SAAS,CAAC,CAAC;IAC7D;AAGA,QAAI,IAAI,MAAM;AACZ,WAAK,KAAK,iBAAiB,QAAQ,IAAI,IAAI,EAAE;IAC/C;EACF;AACA,aAAW,KAAK,KAAK,gBAAgB,CAAC,GAAG;AACvC,SAAK,KAAK,MAAM,CAAC;EACnB;AACA,aAAW,MAAM,KAAK,gBAAgB,CAAC,GAAG;AACxC,UAAM,OAAO,GAAG,SAAS,GAAG,GAAG,MAAM,IAAI,OAAO,GAAG,QAAQ,CAAC,KAAK,OAAO,GAAG,QAAQ;AACnF,SAAK,KAAK,MAAM,GAAG,IAAI,IAAI,OAAO,GAAG,aAAa,CAAC,EAAE;EACvD;AACA,aAAW,CAAC,GAAG,GAAG,KAAK,OAAO,QAAQ,KAAK,OAAO,CAAC,CAAC,GAAG;AACrD,SAAK,KAAK,MAAM,GAAG,CAAC,IAAI,GAAG,EAAE;EAC/B;AACA,OAAK,KAAK,KAAK,OAAO,SAAS,UAAU;AAEzC,QAAM,EAAE,OAAO,IAAI,MAAM,MAAM,UAAU,IAAI;AAC7C,SAAO,OAAO,KAAK;AACrB;AAOA,eAAsB,sBAAuC;AAC3D,QAAM,SAAS,MAAM,MAAM,UAAU,CAAC,QAAQ,YAAY,aAAa,GAAG,EAAE,QAAQ,MAAM,CAAC;AAC3F,MAAI,OAAO,aAAa,EAAG,QAAO;AAClC,UAAQ,OAAO,UAAU,IAAI,KAAK;AACpC;AAEA,eAAsB,UACpB,WACA,KACA,OAAgE,CAAC,GACtC;AAC3B,QAAM,OAAiB,CAAC,MAAM;AAC9B,MAAI,KAAK,OAAQ,MAAK,KAAK,IAAI;AAC/B,MAAI,KAAK,KAAM,MAAK,KAAK,UAAU,KAAK,IAAI;AAC5C,OAAK,KAAK,WAAW,GAAG,GAAG;AAC3B,QAAM,SAAS,MAAM,MAAM,UAAU,MAAM;IACzC,QAAQ;IACR,GAAI,KAAK,YAAY,EAAE,SAAS,KAAK,UAAU,IAAI,CAAC;EACtD,CAAC;AACD,SAAO;IACL,UAAU,OAAO,YAAY;IAC7B,QAAQ,OAAO,UAAU;IACzB,QAAQ,OAAO,UAAU;EAC3B;AACF;AAEA,eAAsB,gBAAgB,WAAkC;AACtE,QAAM,MAAM,UAAU,CAAC,MAAM,MAAM,SAAS,GAAG,EAAE,QAAQ,MAAM,CAAC;AAClE;AAEA,eAAsB,aAAa,MAA6B;AAC9D,QAAM,MAAM,UAAU,CAAC,UAAU,MAAM,IAAI,GAAG,EAAE,QAAQ,MAAM,CAAC;AACjE;AAQA,eAAsB,YACpB,KACA,OAA4B,CAAC,GACX;AAClB,QAAM,OAAO,CAAC,SAAS,IAAI;AAC3B,MAAI,KAAK,UAAU,MAAO,MAAK,KAAK,IAAI;AACxC,OAAK,KAAK,GAAG;AACb,QAAM,SAAS,MAAM,MAAM,UAAU,MAAM,EAAE,QAAQ,MAAM,CAAC;AAC5D,SAAO,OAAO,aAAa;AAC7B;AAEA,eAAsB,gBAAgB,MAAgC;AACpE,QAAM,SAAS,MAAM,MAAM,UAAU,CAAC,aAAa,WAAW,YAAY,WAAW,IAAI,GAAG;IAC1F,QAAQ;EACV,CAAC;AACD,SAAO,OAAO,aAAa;AAC7B;AAEA,eAAsB,aAAa,MAAgC;AACjE,QAAM,SAAS,MAAM,MAAM,UAAU,CAAC,UAAU,WAAW,IAAI,GAAG,EAAE,QAAQ,MAAM,CAAC;AACnF,SAAO,OAAO,aAAa;AAC7B;AAEA,eAAsB,aAAa,MAA6B;AAC9D,MAAI,MAAM,aAAa,IAAI,EAAG;AAC9B,QAAM,MAAM,UAAU,CAAC,UAAU,UAAU,IAAI,CAAC;AAClD;AAYA,eAAsB,cAAc,MAA6B;AAC/D,QAAM,MAAM,UAAU,CAAC,WAAW,MAAM,IAAI,GAAG,EAAE,QAAQ,MAAM,CAAC;AAClE;AAMA,eAAsB,eAAe,MAA6B;AAChE,QAAM,MAAM,UAAU,CAAC,SAAS,IAAI,CAAC;AACvC;AAEA,eAAsB,iBAAiB,MAA6B;AAClE,QAAM,MAAM,UAAU,CAAC,WAAW,IAAI,CAAC;AACzC;AAEA,eAAsB,cAAc,MAA6B;AAC/D,QAAM,MAAM,UAAU,CAAC,QAAQ,IAAI,CAAC;AACtC;AAEA,eAAsB,eAAe,MAA6B;AAChE,QAAM,MAAM,UAAU,CAAC,SAAS,IAAI,CAAC;AACvC;AAEA,eAAsB,uBAAuB,MAA8C;AACzF,QAAM,SAAS,MAAM,MAAM,UAAU,CAAC,WAAW,YAAY,qBAAqB,IAAI,GAAG;IACvF,QAAQ;EACV,CAAC;AACD,MAAI,OAAO,aAAa,EAAG,QAAO;AAClC,QAAM,UAAU,OAAO,UAAU,IAAI,KAAK;AAC1C,UAAQ,QAAQ;IACd,KAAK;AACH,aAAO;IACT,KAAK;AACH,aAAO;IACT,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;IACL,KAAK;AACH,aAAO;IACT;AACE,aAAO;EACX;AACF;AAEA,eAAsB,iBAAiB,MAAuC;AAC5E,QAAM,SAAS,MAAM,MAAM,UAAU,CAAC,WAAW,IAAI,GAAG,EAAE,QAAQ,MAAM,CAAC;AACzE,MAAI,OAAO,aAAa,EAAG,QAAO;AAClC,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,OAAO,UAAU,MAAM;AACjD,WAAO,MAAM,QAAQ,MAAM,IAAK,OAAO,CAAC,KAAK,OAAQ;EACvD,QAAQ;AACN,WAAO;EACT;AACF;AAEA,eAAsB,wBAAwB,MAAsC;AAClF,QAAM,SAAS,MAAM,MAAM,UAAU,CAAC,UAAU,WAAW,YAAY,mBAAmB,IAAI,GAAG;IAC/F,QAAQ;EACV,CAAC;AACD,MAAI,OAAO,aAAa,EAAG,QAAO;AAClC,UAAQ,OAAO,UAAU,IAAI,KAAK,KAAK;AACzC;AAEA,IAAM,kBAAkB;AAExB,eAAsB,yBAA4C;AAChE,QAAM,SAAS,MAAM;IACnB;IACA,CAAC,MAAM,MAAM,YAAY,SAAS,eAAe,IAAI,YAAY,YAAY;IAC7E,EAAE,QAAQ,MAAM;EAClB;AACA,MAAI,OAAO,aAAa,EAAG,QAAO,CAAC;AACnC,UAAQ,OAAO,UAAU,IACtB,MAAM,IAAI,EACV,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EACnB,OAAO,CAAC,MAAM,EAAE,WAAW,eAAe,CAAC;AAChD;AAQA,eAAsB,kBACpB,WACA,eACwB;AACxB,QAAM,SAAS,MAAM,MAAM,UAAU,CAAC,QAAQ,WAAW,GAAG,OAAO,aAAa,CAAC,MAAM,GAAG;IACxF,QAAQ;EACV,CAAC;AACD,MAAI,OAAO,aAAa,EAAG,QAAO;AAClC,QAAM,SAAS,OAAO,UAAU,IAAI,MAAM,IAAI,EAAE,CAAC,GAAG,KAAK;AACzD,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,IAAI,UAAU,KAAK,KAAK;AAC9B,SAAO,IAAI,OAAO,EAAE,CAAC,CAAC,IAAI;AAC5B;AAEA,eAAsB,sBAAyC;AAC7D,QAAM,SAAS,MAAM;IACnB;IACA,CAAC,UAAU,MAAM,YAAY,SAAS,eAAe,IAAI,YAAY,WAAW;IAChF,EAAE,QAAQ,MAAM;EAClB;AACA,MAAI,OAAO,aAAa,EAAG,QAAO,CAAC;AACnC,UAAQ,OAAO,UAAU,IACtB,MAAM,IAAI,EACV,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EACnB,OAAO,CAAC,MAAM,EAAE,WAAW,eAAe,CAAC;AAChD;AC3SO,IAAM,0BAA0B;AASvC,IAAI,eAAoC;AAOxC,eAAsB,eAAsC;AAC1D,MAAI,iBAAiB,KAAM,QAAO;AAClC,QAAM,SAAS,MAAMW,OAAM,UAAU,CAAC,QAAQ,YAAY,sBAAsB,GAAG;IACjF,QAAQ;EACV,CAAC;AACD,QAAM,MAAM,OAAO,UAAU,IAAI,KAAK,EAAE,YAAY;AACpD,MAAI,GAAG,SAAS,UAAU,EAAG,gBAAe;WACnC,GAAG,SAAS,gBAAgB,EAAG,gBAAe;MAClD,gBAAe;AACpB,SAAO;AACT;AAUO,SAAS,kBAAkB,QAAmC;AACnE,iBAAe;AACjB;AAOO,IAAM,aAAaC,MAAKC,SAAQ,GAAG,aAAa,OAAO;AAgBvD,SAAS,cAAc,KAAwB;AACpD,QAAM,WAAW,iBAAiB,IAAI,IAAI;AAC1C,QAAM,IAAI,IAAI;AACd,MAAI,OAAO,MAAM,YAAY,OAAO,SAAS,CAAC,KAAK,IAAI,GAAG;AACxD,WAAO,GAAG,IAAI,EAAE,IAAI,OAAO,CAAC,CAAC,IAAI,QAAQ;EAC3C;AACA,SAAO,GAAG,IAAI,EAAE,IAAI,QAAQ;AAC9B;AAEO,SAAS,aAAa,KAAwB;AACnD,SAAOD,MAAK,YAAY,cAAc,GAAG,CAAC;AAC5C;AAQO,SAAS,iBAAiB,KAAwB;AACvD,SAAOA,MAAK,aAAa,GAAG,GAAG,aAAa;AAC9C;AAOA,eAAsB,cAAc,KAA2C;AAC7E,MAAI;AACF,UAAM,MAAM,MAAME,UAAS,iBAAiB,GAAG,GAAG,MAAM;AACxD,UAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,QAAI,OAAO,WAAW,EAAG,QAAO;AAChC,WAAO;EACT,QAAQ;AACN,WAAO;EACT;AACF;AAWO,SAAS,mBAAmB,WAAmB,KAAuB;AAC3E,SAAOF,MAAKC,SAAQ,GAAG,YAAY,UAAU,WAAW,QAAQ,GAAG,GAAG;AACxE;AAEA,eAAsB,aACpB,QACoB;AACpB,QAAM,SAAS,aAAa,MAAM;AAClC,SAAO;IACL;IACA,cAAcD,MAAK,QAAQ,WAAW;EACxC;AACF;AAgBA,eAAe,iBAAiB,WAAmB,MAAgC;AACjF,QAAM,QAAQ,MAAM,UAAU,WAAW,CAAC,QAAQ,MAAM,IAAI,GAAG,EAAE,MAAM,OAAO,CAAC;AAC/E,SAAO,MAAM,aAAa;AAC5B;AAUA,eAAsB,cACpB,QACA,OAAuB,CAAC,GACA;AACxB,QAAM,QAAQ,MAAM,aAAa,MAAM;AACvC,QAAM,qBAAqB,CAAC,KAAK;AACjC,QAAMG,OAAM,MAAM,cAAc,EAAE,WAAW,KAAK,CAAC;AAEnD,QAAM,gBAAgB,MAAM,iBAAiB,OAAO,WAAW,uBAAuB;AACtF,MAAI,eAAe;AACjB,UAAM,OAAO,CAAC,SAAS,MAAM,UAAU;AACvC,QAAI,mBAAoB,MAAK,KAAK,wBAAwB;AAC1D,SAAK,KAAK,eAAe,GAAG,uBAAuB,GAAG;AACtD,UAAM,IAAI,MAAM,UAAU,OAAO,WAAW,MAAM,EAAE,MAAM,OAAO,CAAC;AAClE,QAAI,EAAE,aAAa,GAAG;AACpB,YAAM,IAAI,YAAY,cAAc,uBAAuB,WAAW,EAAE,QAAQ,EAAE,MAAM;IAC1F;AACA,WAAO,EAAE,UAAU,MAAM,cAAc,QAAQ,MAAM,cAAc,MAAM;EAC3E;AAKA,QAAM,WAAW,qBAAqB,CAAC,wBAAwB,IAAI,CAAC;AACpE,QAAM,SAAS,MAAMJ;IACnB;IACA,CAAC,QAAQ,UAAU,QAAQ,OAAO,WAAW,OAAO,OAAO,KAAK,GAAG,UAAU,MAAM,cAAc,GAAG;IACpG,EAAE,QAAQ,OAAO,UAAU,SAAS;EACtC;AACA,MAAI,OAAO,aAAa,GAAG;AACzB,UAAM,IAAI;MACR;MACA;MACA,OAAO,OAAO,WAAW,WAAW,OAAO,SAAU,OAAO,OAAkB,SAAS,MAAM;IAC/F;EACF;AACA,QAAM,UAAU,MAAMA,OAAM,OAAO,CAAC,OAAO,KAAK,MAAM,MAAM,YAAY,GAAG;IACzE,OAAO,OAAO;IACd,QAAQ;EACV,CAAC;AACD,MAAI,QAAQ,aAAa,GAAG;AAC1B,UAAM,IAAI,YAAY,8BAA8B,QAAQ,QAAQ,QAAQ,MAAM;EACpF;AACA,SAAO,EAAE,UAAU,MAAM,cAAc,QAAQ,MAAM,cAAc,KAAK;AAC1E;AASO,IAAM,uBAAuB;EAClC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AACF;AAGA,IAAM,iBAAiB;EACrB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AACF;AAQA,SAAS,iBAAiB,UAA8B;AACtD,QAAM,YAAY,CAAC,UAA8B;AAC/C,UAAM,MAAgB,CAAC;AACvB,UAAM,QAAQ,CAAC,GAAG,MAAM;AACtB,UAAI,IAAI,EAAG,KAAI,KAAK,IAAI;AACxB,UAAI,KAAK,SAAS,CAAC;IACrB,CAAC;AACD,WAAO;EACT;AACA,SAAO;IACL;IACA;IACA;IACA;IACA;IACA;IACA,GAAG,UAAU,cAAc;IAC3B;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA,GAAG,UAAU,QAAQ;IACrB;IACA;IACA;IACA;EACF;AACF;AASO,SAAS,qBAAqB,UAA8B;AACjE,QAAM,YAAY,CAAC,UAA8B;AAC/C,UAAM,MAAgB,CAAC;AACvB,UAAM,QAAQ,CAAC,GAAG,MAAM;AACtB,UAAI,IAAI,EAAG,KAAI,KAAK,IAAI;AACxB,UAAI,KAAK,SAAS,CAAC;IACrB,CAAC;AACD,WAAO;EACT;AACA,SAAO;IACL;IACA;IACA;IACA;IACA;IACA;IACA,GAAG,UAAU,cAAc;IAC3B;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA,GAAG,UAAU,QAAQ;IACrB;IACA;IACA;EACF;AACF;AAuBA,eAAsB,sBACpB,MAC6B;AAC7B,QAAM,MAAM,KAAK,UAAU,MAAM;EAAC;AAKlC,QAAM,QAAQ,MAAMA,OAAM,QAAQ,qBAAqB,KAAK,QAAQ,EAAE,MAAM,CAAC,GAAG;IAC9E,KAAK,KAAK;IACV,QAAQ;EACV,CAAC;AACD,MAAI,MAAM,aAAa,GAAG;AACxB,QAAI,kCAAkC,OAAO,MAAM,MAAM,EAAE,MAAM,GAAG,GAAG,CAAC,EAAE;AAC1E,WAAO,EAAE,QAAQ,EAAE;EACrB;AACA,QAAM,OAAO,OAAO,MAAM,MAAM,EAC7B,MAAM,IAAI,EACV,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC;AAC7B,MAAI,KAAK,WAAW,EAAG,QAAO,EAAE,QAAQ,EAAE;AAG1C,QAAM,SAAS,MAAMA,OAAM,OAAO,CAAC,MAAM,KAAK,cAAc,UAAU,MAAM,KAAK,OAAO,GAAG,GAAG;IAC5F,OAAO,KAAK,KAAK,IAAI;IACrB,UAAU;IACV,QAAQ;EACV,CAAC;AACD,MAAI,OAAO,aAAa,GAAG;AACzB,QAAI,sCAAsC,OAAO,OAAO,MAAM,EAAE,MAAM,GAAG,GAAG,CAAC,EAAE;AAC/E,WAAO,EAAE,QAAQ,EAAE;EACrB;AACA,QAAM,UAAU,MAAMA;IACpB;IACA,CAAC,QAAQ,MAAM,UAAU,aAAa,KAAK,WAAW,OAAO,OAAO,KAAK,MAAM,YAAY;IAC3F,EAAE,OAAO,OAAO,QAAkB,QAAQ,MAAM;EAClD;AACA,MAAI,QAAQ,aAAa,GAAG;AAC1B,QAAI,2CAA2C,OAAO,QAAQ,MAAM,EAAE,MAAM,GAAG,GAAG,CAAC,EAAE;AACrF,WAAO,EAAE,QAAQ,EAAE;EACrB;AACA,SAAO,EAAE,QAAQ,KAAK,OAAO;AAC/B;AASA,eAAsB,iBACpB,cACA,UACmB;AACnB,MAAI,SAAS,WAAW,EAAG,QAAO,CAAC;AACnC,QAAM,QAAQ,MAAMA,OAAM,QAAQ,qBAAqB,QAAQ,EAAE,MAAM,CAAC,GAAG;IACzE,KAAK;IACL,QAAQ;EACV,CAAC;AACD,MAAI,MAAM,aAAa,EAAG,QAAO,CAAC;AAClC,SAAO,OAAO,MAAM,MAAM,EACvB,MAAM,IAAI,EACV,IAAI,CAAC,MAAM,EAAE,QAAQ,SAAS,EAAE,CAAC,EACjC,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC;AAC/B;AAmBA,eAAsB,mBACpB,MAC6B;AAC7B,QAAM,MAAM,KAAK,UAAU,MAAM;EAAC;AAGlC,QAAM,OAAO,KAAK,MAAM,IAAI,CAAC,MAAM,EAAE,QAAQ,SAAS,EAAE,CAAC,EAAE,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC;AACrF,MAAI,KAAK,WAAW,EAAG,QAAO,EAAE,QAAQ,EAAE;AAE1C,QAAM,SAAS,MAAMA,OAAM,OAAO,CAAC,MAAM,KAAK,cAAc,UAAU,MAAM,KAAK,OAAO,GAAG,GAAG;IAC5F,OAAO,KAAK,KAAK,IAAI;IACrB,UAAU;IACV,QAAQ;EACV,CAAC;AACD,MAAI,OAAO,aAAa,GAAG;AACzB,QAAI,sCAAsC,OAAO,OAAO,MAAM,EAAE,MAAM,GAAG,GAAG,CAAC,EAAE;AAC/E,WAAO,EAAE,QAAQ,EAAE;EACrB;AACA,QAAM,UAAU,MAAMA;IACpB;IACA,CAAC,QAAQ,MAAM,UAAU,aAAa,KAAK,WAAW,OAAO,OAAO,KAAK,MAAM,YAAY;IAC3F,EAAE,OAAO,OAAO,QAAkB,QAAQ,MAAM;EAClD;AACA,MAAI,QAAQ,aAAa,GAAG;AAC1B,QAAI,2CAA2C,OAAO,QAAQ,MAAM,EAAE,MAAM,GAAG,GAAG,CAAC,EAAE;AACrF,WAAO,EAAE,QAAQ,EAAE;EACrB;AACA,SAAO,EAAE,QAAQ,KAAK,OAAO;AAC/B;AAwCA,SAAS,qBAAqB,QAA0B;AACtD,SAAO,OACJ,MAAM,IAAI,EACV,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,EACtB,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC,EAC1B,OAAO,CAAC,MAAM;AACb,UAAM,OAAO,EAAE,CAAC;AAChB,UAAM,OAAO,EAAE,CAAC;AAChB,YAAQ,SAAS,OAAO,SAAS,OAAO,SAAS,OAAO,SAAS,QAAQ,SAAS;EACpF,CAAC;AACL;AAmBA,eAAsB,WACpB,QACA,OAAoB,CAAC,GACA;AACrB,QAAM,QAAQ,MAAM,aAAa,MAAM;AAEvC,MAAI;AACJ,MAAI,KAAK,WAAW;AAClB,iBAAa,MAAM;AACnB,UAAMI,OAAM,YAAY,EAAE,WAAW,KAAK,CAAC;EAC7C,OAAO;AACL,UAAM,YAAY,MAAM,cAAc,QAAQ;MAC5C,oBAAoB,KAAK;IAC3B,CAAC;AACD,iBAAa,UAAU;EACzB;AAMA,QAAM,WAAqB,CAAC;AAC5B,MAAI,gBAAgB;AACpB,MAAI,KAAK,qBAAqB,OAAO;AACnC,UAAM,QAAQ,MAAM;MAClB,OAAO;MACP,CAAC,OAAO,MAAM,cAAc,aAAa,uBAAuB;MAChE,EAAE,MAAM,OAAO;IACjB;AACA,QAAI,MAAM,aAAa,KAAK,MAAM,OAAO,KAAK,MAAM,QAAQ;AAC1D,YAAM,KAAK,MAAM;QACf,OAAO;QACP,CAAC,OAAO,MAAM,cAAc,YAAY,MAAM,YAAY,YAAY,oBAAoB;QAC1F,EAAE,MAAM,OAAO;MACjB;AACA,UAAI,GAAG,aAAa,GAAG;AACrB,cAAM,IAAI,YAAY,8BAA8B,GAAG,QAAQ,GAAG,MAAM;MAC1E;AAEA,YAAM,UAAU,GAAG,OAAO,QAAQ,OAAO,EAAE;AAC3C,UAAI,QAAQ,SAAS,EAAG,UAAS,KAAK,OAAO;AAC7C,sBAAgB;IAClB;EACF;AACA,MAAI,KAAK,eAAe,KAAK,YAAY,SAAS,GAAG;AACnD,UAAM,QAAQ,MAAM;MAClB,OAAO;MACP,iBAAiB,KAAK,WAAW;MACjC,EAAE,MAAM,OAAO;IACjB;AACA,QAAI,MAAM,aAAa,GAAG;AACxB,YAAM,IAAI,YAAY,gCAAgC,MAAM,QAAQ,MAAM,MAAM;IAClF;AACA,UAAM,WAAW,MAAM,OAAO,QAAQ,OAAO,EAAE;AAC/C,QAAI,SAAS,SAAS,EAAG,UAAS,KAAK,QAAQ;EACjD;AACA,QAAM,WACJ,SAAS,SAAS,IACd,MAAM,KAAK,IAAI,IAAI,SAAS,KAAK,IAAI,EAAE,MAAM,IAAI,CAAC,CAAC,EAAE,KAAK,IAAI,IAC9D;AAON,QAAM,WAAW,CAAC,MAAM,YAAY;AACpC,MAAI,aAAa,MAAM;AACrB,aAAS,KAAK,gBAAgB;AAC9B,QAAI,CAAC,KAAK,mBAAoB,UAAS,KAAK,wBAAwB;EACtE,OAAO;AACL,aAAS,KAAK,kBAAkB,SAAS;EAC3C;AACA,QAAM,MAAM,GAAG,UAAU;AACzB,QAAM,MAAM,GAAG,OAAO,aAAa;AAEnC,QAAM,MAAM,MAAMJ,OAAM,SAAS,CAAC,GAAG,UAAU,aAAa,MAAM,KAAK,GAAG,GAAG;IAC3E,QAAQ;IACR,OAAO,aAAa,OAAO,WAAW;EACxC,CAAC;AACD,MAAI,IAAI,aAAa,GAAG;AACtB,UAAM,IAAI,YAAY,wBAAwB,IAAI,QAAQ,IAAI,MAAM;EACtE;AACA,QAAM,UAAU,qBAAqB,IAAI,MAAM;AAE/C,MAAI,KAAK,QAAQ;AACf,WAAO,EAAE,UAAU,OAAO,eAAe,SAAS,SAAS,OAAO,cAAc;EAClF;AAEA,QAAM,OAAO,MAAMA,OAAM,SAAS,CAAC,GAAG,UAAU,KAAK,GAAG,GAAG;IACzD,QAAQ;IACR,OAAO,aAAa,OAAO,WAAW;EACxC,CAAC;AACD,MAAI,KAAK,aAAa,GAAG;AACvB,UAAM,IAAI,YAAY,cAAc,OAAO,aAAa,WAAW,KAAK,QAAQ,KAAK,MAAM;EAC7F;AACA,SAAO,EAAE,UAAU,OAAO,eAAe,SAAS,SAAS,MAAM,cAAc;AACjF;AAwBA,eAAsB,aACpB,QACA,MACqB;AACrB,QAAM,SAAS,MAAM,aAAa;AAClC,MAAI;AACJ,MAAI,SAAS;AACb,MAAI,eAAe;AAEnB,MAAI,KAAK,WAAW;AAClB,UAAM,QAAQ,MAAM,aAAa,MAAM;AACvC,eAAW,MAAM;AACjB,UAAMI,OAAM,UAAU,EAAE,WAAW,KAAK,CAAC;EAC3C,OAAO;AACL,UAAM,YAAY,MAAM,cAAc,QAAQ,IAAI;AAClD,eAAW,UAAU;AACrB,aAAS,UAAU;AACnB,mBAAe,UAAU;EAC3B;AAEA,MAAI,CAAC,KAAK,QAAQ;AAChB,UAAM,SAAS,MAAMJ,OAAM,QAAQ,CAAC,QAAQ,GAAG,EAAE,QAAQ,MAAM,CAAC;AAChE,QAAI,OAAO,aAAa,GAAG;AACzB,YAAM,IAAI,YAAY,QAAQ,QAAQ,WAAW,OAAO,QAAQ,OAAO,MAAM;IAC/E;EACF;AAEA,SAAO,EAAE,UAAU,QAAQ,cAAc,OAAO;AAClD;AAEO,IAAM,cAAN,cAA0B,MAAM;EACrC,YACE,SACgB,QACA,QAChB;AACA,UAAM,GAAG,OAAO,GAAG,SAAS,KAAK,OAAO,KAAK,CAAC,KAAK,EAAE,EAAE;AAHvC,SAAA,SAAA;AACA,SAAA,SAAA;AAGhB,SAAK,OAAO;EACd;EALkB;EACA;AAKpB;AChqBO,IAAM,oBAAoB;AAEjC,IAAM,OAAOK,SAAQ,cAAc,YAAY,GAAG,CAAC;AAcnD,SAAS,qBAA8D;AACrE,QAAM,WAAW,QAAQ,IAAI;AAC7B,MAAI,YAAY,WAAWC,SAAQ,UAAU,gBAAgB,CAAC,GAAG;AAC/D,WAAO,EAAE,YAAYA,SAAQ,UAAU,gBAAgB,GAAG,SAAS,SAAS;EAC9E;AACA,QAAM,SAASA,SAAQ,MAAM,MAAM,WAAW,QAAQ;AACtD,MAAI,WAAWA,SAAQ,QAAQ,gBAAgB,CAAC,GAAG;AACjD,WAAO,EAAE,YAAYA,SAAQ,QAAQ,gBAAgB,GAAG,SAAS,OAAO;EAC1E;AAGA,QAAM,cAAcA,SAAQ,MAAM,IAAI;AACtC,SAAO;IACL,YAAYA,SAAQ,aAAa,gBAAgB;IACjD,SAASA,SAAQ,aAAa,MAAM,IAAI;EAC1C;AACF;AAEA,IAAM,EAAE,YAAY,0BAA0B,SAAS,2BAA2B,IAChF,mBAAmB;AACd,IAAM,kBAAkB;AACxB,IAAM,oBAAoB;AAEjC,eAAsB,YAAY,KAA+B;AAC/D,QAAM,SAAS,MAAMN,OAAM,UAAU,CAAC,SAAS,WAAW,GAAG,GAAG,EAAE,QAAQ,MAAM,CAAC;AACjF,SAAO,OAAO,aAAa;AAC7B;AASA,eAAsB,WAAW,OAA0B,CAAC,GAAoB;AAC9E,QAAM,MAAM,KAAK,OAAO;AACxB,QAAM,aAAa,KAAK,cAAc;AACtC,QAAM,aAAa,KAAK,cAAc;AAEtC,QAAM,aAAaA,OAAM,UAAU,CAAC,SAAS,MAAM,KAAK,MAAM,YAAY,UAAU,GAAG;IACrF,QAAQ;IACR,QAAQ;EACV,CAAC;AAED,MAAI,KAAK,YAAY;AACnB,UAAM,UAAU,CAAC,UAAiC;AAChD,YAAM,OAAO,OAAO,UAAU,WAAW,QAAQ,MAAM,SAAS,MAAM;AACtE,iBAAW,QAAQ,KAAK,MAAM,OAAO,GAAG;AACtC,YAAI,KAAK,SAAS,EAAG,MAAK,aAAa,IAAI;MAC7C;IACF;AACA,eAAW,QAAQ,GAAG,QAAQ,OAAO;AACrC,eAAW,QAAQ,GAAG,QAAQ,OAAO;EACvC;AAEA,QAAM;AACN,SAAO;AACT;AAUA,eAAsB,YACpB,MAAc,mBACd,OAA2B,CAAC,GACc;AAC1C,MAAI,MAAM,YAAY,GAAG,GAAG;AAC1B,WAAO,EAAE,KAAK,OAAO,MAAM;EAC7B;AACA,QAAM,WAAW;IACf;IACA,YAAY,KAAK;IACjB,YAAY,KAAK;IACjB,YAAY,KAAK;EACnB,CAAC;AACD,SAAO,EAAE,KAAK,OAAO,KAAK;AAC5B;ACzFO,IAAM,mBAAmBC,OAAKC,UAAQ,GAAG,aAAa,aAAa;AAOnE,IAAM,0BAA0B;AAYhC,SAAS,mBAAmB,aAAqB,MAAsB;AAC5E,QAAM,WAAWK,iBAAiBC,UAAS,WAAW,CAAC;AACvD,SAAO,GAAG,uBAAuB,GAAG,gBAAgB,WAAW,CAAC,IAAI,QAAQ,IAAI,IAAI;AACtF;AAwCO,SAAS,sBAAsB,aAA6B;AACjE,SAAOP,OAAK,kBAAkB,kBAAkB,WAAW,CAAC;AAC9D;AAEA,SAAS,cAAc,aAAqB,MAAsB;AAChE,SAAOA,OAAK,sBAAsB,WAAW,GAAG,IAAI;AACtD;AAEA,eAAe,aAAa,KAAiD;AAC3E,MAAI;AACF,UAAM,MAAM,MAAME,WAASF,OAAK,KAAK,eAAe,GAAG,MAAM;AAC7D,UAAM,IAAI,KAAK,MAAM,GAAG;AACxB,QAAI,EAAE,WAAW,EAAG,QAAO;AAC3B,WAAO;EACT,QAAQ;AACN,WAAO;EACT;AACF;AAEA,eAAsB,gBAAgB,aAAgD;AACpF,QAAM,OAAO,sBAAsB,WAAW;AAC9C,MAAI;AACJ,MAAI;AACF,eAAW,MAAMQ,SAAQ,MAAM,EAAE,eAAe,KAAK,CAAC,GACnD,OAAO,CAAC,MAAM,EAAE,YAAY,CAAC,EAC7B,IAAI,CAAC,MAAM,EAAE,IAAI;EACtB,QAAQ;AACN,WAAO,CAAC;EACV;AACA,QAAM,MAAwB,CAAC;AAC/B,aAAW,QAAQ,SAAS;AAC1B,UAAM,MAAMR,OAAK,MAAM,IAAI;AAC3B,UAAM,WAAW,MAAM,aAAa,GAAG;AACvC,QAAI,SAAU,KAAI,KAAK,EAAE,MAAM,KAAK,SAAS,CAAC;EAChD;AACA,MAAI,KAAK,CAAC,GAAG,MAAM,EAAE,SAAS,UAAU,cAAc,EAAE,SAAS,SAAS,CAAC;AAC3E,SAAO;AACT;AAEA,eAAsB,kBACpB,aACA,KACgC;AAChC,QAAM,MAAM,cAAc,aAAa,GAAG;AAC1C,QAAM,WAAW,MAAM,aAAa,GAAG;AACvC,MAAI,CAAC,SAAU,QAAO;AACtB,SAAO,EAAE,MAAM,KAAK,KAAK,SAAS;AACpC;AAaA,eAAsB,0BAA6C;AACjE,MAAI;AACJ,MAAI;AACF,mBAAe,MAAMQ,SAAQ,kBAAkB,EAAE,eAAe,KAAK,CAAC,GACnE,OAAO,CAAC,MAAM,EAAE,YAAY,CAAC,EAC7B,IAAI,CAAC,MAAM,EAAE,IAAI;EACtB,QAAQ;AACN,WAAO,CAAC;EACV;AACA,QAAM,MAAM,oBAAI,IAAY;AAC5B,aAAW,QAAQ,aAAa;AAC9B,UAAM,WAAWR,OAAK,kBAAkB,IAAI;AAC5C,QAAI;AACJ,QAAI;AACF,eAAS,MAAMQ,SAAQ,UAAU,EAAE,eAAe,KAAK,CAAC,GACrD,OAAO,CAAC,MAAM,EAAE,YAAY,CAAC,EAC7B,IAAI,CAAC,MAAM,EAAE,IAAI;IACtB,QAAQ;AACN;IACF;AACA,eAAW,QAAQ,OAAO;AACxB,YAAM,WAAW,MAAM,aAAaR,OAAK,UAAU,IAAI,CAAC;AACxD,UAAI,SAAU,KAAI,IAAI,SAAS,KAAK;IACtC;EACF;AACA,SAAO,MAAM,KAAK,GAAG;AACvB;AAEA,eAAsB,iBAAiB,aAAqB,KAA+B;AACzF,QAAM,MAAM,cAAc,aAAa,GAAG;AAC1C,QAAM,WAAW,MAAM,aAAa,GAAG;AACvC,MAAI,CAAC,SAAU,QAAO;AACtB,QAAMS,IAAG,KAAK,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAI9C,QAAM,YAAY,SAAS,OAAO,EAAE,OAAO,KAAK,CAAC;AACjD,SAAO;AACT;AAOO,SAAS,0BAA0B,eAAyB,SAAyB;AAC1F,QAAM,KAAK,IAAI,OAAO,IAAI,QAAQ,QAAQ,uBAAuB,MAAM,CAAC,UAAU;AAClF,MAAI,MAAM;AACV,aAAW,KAAK,eAAe;AAC7B,UAAM,IAAI,GAAG,KAAK,CAAC;AACnB,QAAI,EAAG,OAAM,KAAK,IAAI,KAAK,OAAO,EAAE,CAAC,CAAC,CAAC;EACzC;AACA,SAAO,GAAG,OAAO,IAAI,OAAO,MAAM,CAAC,CAAC;AACtC;AAEA,eAAe,mBAAmB,aAAqB,SAAkC;AACvF,QAAM,WAAW,MAAM,gBAAgB,WAAW;AAClD,SAAO;IACL,SAAS,IAAI,CAAC,MAAM,EAAE,IAAI;IAC1B;EACF;AACF;AAEA,SAAS,WAAW,KAAwB;AAC1C,SAAO,IAAI,kBAAkB,MAAM,UAAU;AAC/C;AA4BA,eAAe,WAAW,WAAmB,KAA4C;AACvF,QAAM,IAAI,MAAM,UAAU,WAAW,CAAC,4CAA4C,GAAG;IACnF,MAAM;EACR,CAAC;AACD,MAAI,EAAE,aAAa,GAAG;AACpB,QAAI,sCAAsC,OAAO,EAAE,QAAQ,CAAC,KAAK,EAAE,OAAO,MAAM,GAAG,GAAG,CAAC,EAAE;EAC3F;AACF;AAOA,eAAe,mBAAmB,UAA8C;AAC9E,QAAM,IAAI,MAAMV,OAAM,UAAU,CAAC,SAAS,WAAW,QAAQ,GAAG,EAAE,QAAQ,MAAM,CAAC;AACjF,MAAI,EAAE,aAAa,GAAG;AACpB,UAAM,IAAI,gBAAgB,wBAAwB,QAAQ,WAAW,EAAE,QAAQ,EAAE,MAAM;EACzF;AACA,QAAM,SAAS,KAAK,MAAM,EAAE,MAAM;AAClC,MAAI,CAAC,MAAM,QAAQ,MAAM,KAAK,OAAO,WAAW,KAAK,CAAC,OAAO,CAAC,GAAG,QAAQ;AACvE,UAAM,IAAI,gBAAgB,6CAA6C,QAAQ,IAAI,EAAE,QAAQ,EAAE;EACjG;AACA,SAAO,OAAO,CAAC,EAAE;AACnB;AAkBA,IAAM,wBAAwB,oBAAI,IAAI;EACpC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AACF,CAAC;AAWD,SAAS,uBAAuB,KAAkC;AAChE,QAAM,QAAkB,CAAC;AACzB,aAAW,MAAM,IAAI,OAAO,CAAC,GAAG;AAC9B,UAAM,KAAK,GAAG,QAAQ,GAAG;AACzB,QAAI,MAAM,EAAG;AACb,UAAM,IAAI,GAAG,MAAM,GAAG,EAAE;AACxB,QAAI,sBAAsB,IAAI,CAAC,EAAG;AAClC,UAAM,IAAI,GAAG,MAAM,KAAK,CAAC;AACzB,UAAM,KAAK,OAAO,CAAC,IAAI,gBAAgB,CAAC,CAAC,EAAE;EAC7C;AACA,MAAI,IAAI,WAAY,OAAM,KAAK,WAAW,IAAI,UAAU,EAAE;AAC1D,MAAI,IAAI,KAAM,OAAM,KAAK,QAAQ,IAAI,IAAI,EAAE;AAC3C,aAAW,KAAK,OAAO,KAAK,IAAI,gBAAgB,CAAC,CAAC,EAAG,OAAM,KAAK,UAAU,EAAE,QAAQ,QAAQ,EAAE,CAAC,EAAE;AACjG,MAAI,IAAI,cAAc,IAAI,WAAW,SAAS,GAAG;AAC/C,UAAM,KAAK,cAAc,KAAK,UAAU,IAAI,UAAU,CAAC,EAAE;EAC3D;AACA,MAAI,IAAI,OAAO,IAAI,IAAI,SAAS,GAAG;AACjC,UAAM,KAAK,OAAO,KAAK,UAAU,IAAI,GAAG,CAAC,EAAE;EAC7C;AACA,SAAO;AACT;AAGA,SAAS,gBAAgB,GAAmB;AAC1C,MAAI,0BAA0B,KAAK,CAAC,EAAG,QAAO;AAC9C,SAAO,IAAI,EAAE,QAAQ,OAAO,MAAM,EAAE,QAAQ,MAAM,KAAK,CAAC;AAC1D;AAiBA,eAAsB,iBAAiB,MAAwD;AAC7F,QAAM,MAAM,KAAK,UAAU,MAAM;EAAC;AAClC,QAAM,EAAE,IAAI,IAAI;AAEhB,QAAM,OACJ,KAAK,WAAW,QAAQ,WAAW,GAAG,KAAK,KAAK,YAAY,cAAc;AAC5E,QAAM,OAAO,KAAK,QAAS,MAAM,mBAAmB,KAAK,aAAa,IAAI,IAAI;AAC9E,QAAM,MAAM,cAAc,KAAK,aAAa,IAAI;AAChD,QAAM,WAAW,MAAM,aAAa,GAAG;AACvC,MAAI,UAAU;AACZ,QAAI,KAAK,SAAS;AAChB,UAAI,iCAAiC,IAAI,aAAa,SAAS,SAAS,GAAG;AAC3E,YAAM,iBAAiB,KAAK,aAAa,IAAI;IAC/C,OAAO;AAKL,YAAM,IAAI;QACR,cAAc,IAAI,4BAA4B,SAAS,SAAS;QAChE;QACA;MACF;IACF;EACF;AACA,QAAM,MAAM,mBAAmB,KAAK,aAAa,IAAI;AACrD,QAAMI,QAAM,KAAK,EAAE,WAAW,KAAK,CAAC;AAEpC,MAAI,iCAAiC,IAAI,SAAS,EAAE;AACpD,QAAM,WAAW,IAAI,WAAW,GAAG;AAEnC,MAAI,SAAS,WAAW;AACtB,QAAI,iBAAiB,IAAI,SAAS,OAAO,GAAG,YAAY;AACxD,UAAM,IAAI,MAAMJ,OAAM,UAAU,CAAC,UAAU,IAAI,WAAW,GAAG,GAAG,EAAE,QAAQ,MAAM,CAAC;AACjF,QAAI,EAAE,aAAa,GAAG;AACpB,YAAM,IAAI,gBAAgB,4BAA4B,IAAI,SAAS,IAAI,EAAE,QAAQ,EAAE,MAAM;IAC3F;EACF,OAAO;AACL,QAAI,iBAAiB,IAAI,SAAS,qCAAqC;AAGvE,UAAM,eAAe,GAAG,GAAG;AAC3B,UAAM,SAAS,MAAMA,OAAM,UAAU,CAAC,UAAU,IAAI,WAAW,YAAY,GAAG;MAC5E,QAAQ;IACV,CAAC;AACD,QAAI,OAAO,aAAa,GAAG;AACzB,YAAM,IAAI,gBAAgB,uCAAuC,OAAO,QAAQ,OAAO,MAAM;IAC/F;AACA,QAAI;AACF,YAAM,aAAa,cAAc,KAAK,GAAG;IAC3C,UAAA;AAIE,YAAM,YAAY,cAAc,EAAE,OAAO,KAAK,CAAC;IACjD;EACF;AAEA,QAAM,QAAkC,IAAI,gBAAgB,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,SAAS,MAAM,IACzF,aACA;AACJ,QAAM,WAA+B;IACnC,QAAQ;IACR;IACA;IACA,OAAO;;IAEP,SAAS,SAAS,YAAa,IAAI,kBAAkB,SAAS,CAAC,IAAK,CAAC;IACrE;IACA,aAAa,IAAI;IACjB,eAAe,IAAI;IACnB,WAAW,IAAI;IACf,YAAW,oBAAI,KAAK,GAAE,YAAY;EACpC;AACA,QAAMW,WAAUV,OAAK,KAAK,eAAe,GAAG,KAAK,UAAU,UAAU,MAAM,CAAC,IAAI,MAAM,MAAM;AAE5F,MAAI,KAAK,YAAY;AACnB,UAAM,eAAe,WAAW,yBAAyB,MAAM,KAAK,WAAW;AAC/E,QAAI,qCAAqC,IAAI,EAAE;EACjD;AAEA,SAAO,EAAE,MAAM,KAAK,SAAS;AAC/B;AAOA,eAAe,aACb,WACA,SACA,KACe;AAEf,QAAM,UAAU,oBAAoB,KAAK,IAAI,EAAE,SAAS,EAAE,CAAC;AAC3D,QAAM,SAAS,MAAMD;IACnB;IACA,CAAC,UAAU,UAAU,SAAS,WAAW,SAAS,GAAG;IACrD,EAAE,QAAQ,MAAM;EAClB;AACA,MAAI,OAAO,aAAa,GAAG;AACzB,UAAM,IAAI,gBAAgB,oCAAoC,OAAO,QAAQ,OAAO,MAAM;EAC5F;AACA,QAAM,UAAU,MAAM,QAAQC,OAAK,OAAO,GAAG,mBAAmB,CAAC;AACjE,MAAI;AACF,UAAM,aAAaA,OAAK,SAAS,YAAY;AAC7C,QAAI,uBAAuB,SAAS,OAAO,UAAU,EAAE;AACvD,UAAM,MAAM,MAAMD,OAAM,UAAU,CAAC,UAAU,MAAM,YAAY,OAAO,GAAG,EAAE,QAAQ,MAAM,CAAC;AAC1F,QAAI,IAAI,aAAa,GAAG;AACtB,YAAM,IAAI,gBAAgB,wBAAwB,IAAI,QAAQ,IAAI,MAAM;IAC1E;AAMA,UAAM,MAAM,MAAM,mBAAmB,SAAS;AAC9C,UAAM,QAAQ;MACZ;;MAEA;MACA,GAAG,uBAAuB,GAAG;IAC/B;AACA,UAAMW,WAAUV,OAAK,SAAS,YAAY,GAAG,MAAM,KAAK,IAAI,IAAI,MAAM,MAAM;AAE5E,QAAI,sBAAsB,OAAO,iCAAiC;AAClE,UAAM,QAAQ,MAAMD;MAClB;MACA,CAAC,SAAS,MAAM,SAAS,MAAMC,OAAK,SAAS,YAAY,GAAG,OAAO;MACnE,EAAE,QAAQ,MAAM;IAClB;AACA,QAAI,MAAM,aAAa,GAAG;AACxB,YAAM,IAAI,gBAAgB,+BAA+B,MAAM,QAAQ,MAAM,MAAM;IACrF;EACF,UAAA;AACE,UAAMD,OAAM,UAAU,CAAC,MAAM,MAAM,OAAO,GAAG,EAAE,QAAQ,MAAM,CAAC;AAC9D,UAAMU,IAAG,SAAS,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;EACpD;AACF;AAEO,IAAM,kBAAN,cAA8B,MAAM;EACzC,YACE,SACgB,QACA,QAChB;AACA,UAAM,GAAG,OAAO,GAAG,SAAS,KAAK,OAAO,KAAK,CAAC,KAAK,EAAE,EAAE;AAHvC,SAAA,SAAA;AACA,SAAA,SAAA;AAGhB,SAAK,OAAO;EACd;EALkB;EACA;AAKpB;","names":["mkdir","readFile","homedir","join","execa","parseYaml","readFile","stat","dirname","join","fileExists","execa","dirname","resolve","mkdir","readFile","readdir","rm","writeFile","homedir","basename","join","execa","join","homedir","readFile","mkdir","dirname","resolve","sanitizeMnemonic","basename","readdir","rm","writeFile"]}
@@ -1,15 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- createBox,
4
- defaultBoxName,
5
- sanitizeBasename
6
- } from "./chunk-6VTAPD4H.js";
7
- import "./chunk-PXUBE5KS.js";
8
- import "./chunk-HPZMD5DE.js";
9
- import "./chunk-RFC5F5HR.js";
10
- export {
11
- createBox,
12
- defaultBoxName,
13
- sanitizeBasename
14
- };
15
- //# sourceMappingURL=create-AHZ3GVEZ-TGEDL7UX.js.map
@@ -1,38 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- AmbiguousBoxError,
4
- BoxNotFoundError,
5
- destroyBox,
6
- getBoxHostPaths,
7
- inspectBox,
8
- listBoxes,
9
- openBoxInFinder,
10
- pauseBox,
11
- pruneBoxes,
12
- snapshotPresent,
13
- startBox,
14
- stopBox,
15
- unpauseBox
16
- } from "./chunk-FJNIFTWK.js";
17
- import {
18
- SNAPSHOTS_ROOT
19
- } from "./chunk-PXUBE5KS.js";
20
- import "./chunk-HPZMD5DE.js";
21
- import "./chunk-RFC5F5HR.js";
22
- export {
23
- AmbiguousBoxError,
24
- BoxNotFoundError,
25
- SNAPSHOTS_ROOT,
26
- destroyBox,
27
- getBoxHostPaths,
28
- inspectBox,
29
- listBoxes,
30
- openBoxInFinder,
31
- pauseBox,
32
- pruneBoxes,
33
- snapshotPresent,
34
- startBox,
35
- stopBox,
36
- unpauseBox
37
- };
38
- //# sourceMappingURL=lifecycle-LFOL6YFM-TCHDX3J5.js.map
@@ -1,26 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- STATE_DIR,
4
- STATE_FILE,
5
- allocateProjectIndex,
6
- autoPickProjectBox,
7
- findBox,
8
- readState,
9
- recordBox,
10
- removeBoxRecord,
11
- resolveBoxRef,
12
- writeState
13
- } from "./chunk-HPZMD5DE.js";
14
- export {
15
- STATE_DIR,
16
- STATE_FILE,
17
- allocateProjectIndex,
18
- autoPickProjectBox,
19
- findBox,
20
- readState,
21
- recordBox,
22
- removeBoxRecord,
23
- resolveBoxRef,
24
- writeState
25
- };
26
- //# sourceMappingURL=state-KD7M46ZP-KHFTHFUS.js.map
@@ -1,19 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- agentboxHomeBytes,
4
- allCheckpointImagesBytes,
5
- boxResourceStats,
6
- parseDockerSize,
7
- projectCheckpointImageBytes,
8
- volumeSizeBytes
9
- } from "./chunk-7J5AJLWG.js";
10
- import "./chunk-RFC5F5HR.js";
11
- export {
12
- agentboxHomeBytes,
13
- allCheckpointImagesBytes,
14
- boxResourceStats,
15
- parseDockerSize,
16
- projectCheckpointImageBytes,
17
- volumeSizeBytes
18
- };
19
- //# sourceMappingURL=stats-Z4BVJODD-HEC4TMUZ.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}