@madarco/agentbox 0.1.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 (33) hide show
  1. package/LICENSE +21 -0
  2. package/dist/chunk-IDR4HVIC.js +106 -0
  3. package/dist/chunk-IDR4HVIC.js.map +1 -0
  4. package/dist/chunk-J35IH7W5.js +200 -0
  5. package/dist/chunk-J35IH7W5.js.map +1 -0
  6. package/dist/chunk-O5HS3QHW.js +2164 -0
  7. package/dist/chunk-O5HS3QHW.js.map +1 -0
  8. package/dist/chunk-OOOKFFR5.js +496 -0
  9. package/dist/chunk-OOOKFFR5.js.map +1 -0
  10. package/dist/chunk-RWJE6AER.js +515 -0
  11. package/dist/chunk-RWJE6AER.js.map +1 -0
  12. package/dist/chunk-SOMIKEN2.js +1651 -0
  13. package/dist/chunk-SOMIKEN2.js.map +1 -0
  14. package/dist/create-LSSO7H4I-GWNALUMF.js +15 -0
  15. package/dist/create-LSSO7H4I-GWNALUMF.js.map +1 -0
  16. package/dist/index.js +4067 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/lifecycle-P4FSKGR2-3466P54Y.js +38 -0
  19. package/dist/lifecycle-P4FSKGR2-3466P54Y.js.map +1 -0
  20. package/dist/state-ZSP3ORXW-WI6KOIG3.js +26 -0
  21. package/dist/state-ZSP3ORXW-WI6KOIG3.js.map +1 -0
  22. package/dist/stats-GZFLPYTU-DBJ2DVBJ.js +19 -0
  23. package/dist/stats-GZFLPYTU-DBJ2DVBJ.js.map +1 -0
  24. package/package.json +73 -0
  25. package/runtime/docker/Dockerfile.box +316 -0
  26. package/runtime/docker/apps/cli/share/agentbox-setup/SKILL.md +188 -0
  27. package/runtime/docker/packages/ctl/dist/bin.cjs +12770 -0
  28. package/runtime/docker/packages/sandbox-docker/scripts/agentbox-dockerd-start +52 -0
  29. package/runtime/docker/packages/sandbox-docker/scripts/agentbox-vnc-start +77 -0
  30. package/runtime/docker/packages/sandbox-docker/scripts/claude-managed-settings.json +54 -0
  31. package/runtime/docker/packages/sandbox-docker/scripts/custom-system-CLAUDE.md +21 -0
  32. package/runtime/relay/bin.cjs +11467 -0
  33. package/share/agentbox-setup/SKILL.md +188 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 AgentBox contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,106 @@
1
+ #!/usr/bin/env node
2
+
3
+ // ../../packages/sandbox-docker/dist/chunk-A72AUJNS.js
4
+ import { mkdir, readFile, writeFile } from "fs/promises";
5
+ import { homedir } from "os";
6
+ import { dirname, join } from "path";
7
+ var STATE_DIR = join(homedir(), ".agentbox");
8
+ var STATE_FILE = join(STATE_DIR, "state.json");
9
+ var EMPTY = { version: 1, boxes: [] };
10
+ async function readState(path = STATE_FILE) {
11
+ try {
12
+ const raw = await readFile(path, "utf8");
13
+ const parsed = JSON.parse(raw);
14
+ if (parsed.version !== 1 || !Array.isArray(parsed.boxes)) {
15
+ throw new Error(`unrecognized state file shape at ${path}`);
16
+ }
17
+ return parsed;
18
+ } catch (err) {
19
+ if (err.code === "ENOENT") {
20
+ return { ...EMPTY };
21
+ }
22
+ throw err;
23
+ }
24
+ }
25
+ async function writeState(state, path = STATE_FILE) {
26
+ await mkdir(dirname(path), { recursive: true });
27
+ await writeFile(path, JSON.stringify(state, null, 2) + "\n", "utf8");
28
+ }
29
+ async function recordBox(box, path = STATE_FILE) {
30
+ const state = await readState(path);
31
+ const next = {
32
+ version: 1,
33
+ boxes: [...state.boxes.filter((b) => b.id !== box.id), box]
34
+ };
35
+ await writeState(next, path);
36
+ }
37
+ async function removeBoxRecord(id, path = STATE_FILE) {
38
+ const state = await readState(path);
39
+ const before = state.boxes.length;
40
+ const next = {
41
+ version: 1,
42
+ boxes: state.boxes.filter((b) => b.id !== id)
43
+ };
44
+ if (next.boxes.length === before) return false;
45
+ await writeState(next, path);
46
+ return true;
47
+ }
48
+ function findBox(idOrName, state) {
49
+ const q = idOrName.trim();
50
+ if (q.length === 0) return { kind: "none" };
51
+ const exactId = state.boxes.find((b) => b.id === q);
52
+ if (exactId) return { kind: "ok", box: exactId };
53
+ const prefixMatches = state.boxes.filter((b) => b.id.startsWith(q));
54
+ if (prefixMatches.length === 1) return { kind: "ok", box: prefixMatches[0] };
55
+ if (prefixMatches.length > 1) return { kind: "ambiguous", matches: prefixMatches };
56
+ const byName = state.boxes.find((b) => b.name === q);
57
+ if (byName) return { kind: "ok", box: byName };
58
+ const byContainer = state.boxes.find((b) => b.container === q);
59
+ if (byContainer) return { kind: "ok", box: byContainer };
60
+ return { kind: "none" };
61
+ }
62
+ function allocateProjectIndex(state, projectRoot) {
63
+ let max = 0;
64
+ for (const b of state.boxes) {
65
+ if (b.projectRoot !== projectRoot) continue;
66
+ if (typeof b.projectIndex === "number" && b.projectIndex > max) {
67
+ max = b.projectIndex;
68
+ }
69
+ }
70
+ return max + 1;
71
+ }
72
+ function autoPickProjectBox(state, projectRoot) {
73
+ const matches = state.boxes.filter((b) => b.projectRoot === projectRoot);
74
+ if (matches.length === 0) return { kind: "none" };
75
+ if (matches.length === 1) return { kind: "ok", box: matches[0] };
76
+ return { kind: "ambiguous", matches };
77
+ }
78
+ function resolveBoxRef(ref, state, projectRoot) {
79
+ if (ref === void 0) {
80
+ if (projectRoot === void 0) return { kind: "none" };
81
+ return autoPickProjectBox(state, projectRoot);
82
+ }
83
+ const trimmed = ref.trim();
84
+ if (projectRoot !== void 0 && /^[1-9][0-9]*$/.test(trimmed)) {
85
+ const idx = Number.parseInt(trimmed, 10);
86
+ const hit = state.boxes.find(
87
+ (b) => b.projectRoot === projectRoot && b.projectIndex === idx
88
+ );
89
+ return hit ? { kind: "ok", box: hit } : { kind: "none" };
90
+ }
91
+ return findBox(trimmed, state);
92
+ }
93
+
94
+ export {
95
+ STATE_DIR,
96
+ STATE_FILE,
97
+ readState,
98
+ writeState,
99
+ recordBox,
100
+ removeBoxRecord,
101
+ findBox,
102
+ allocateProjectIndex,
103
+ autoPickProjectBox,
104
+ resolveBoxRef
105
+ };
106
+ //# sourceMappingURL=chunk-IDR4HVIC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../packages/sandbox-docker/src/state.ts"],"sourcesContent":["import { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { dirname, join } from 'node:path';\n\nexport const STATE_DIR = join(homedir(), '.agentbox');\nexport const STATE_FILE = join(STATE_DIR, 'state.json');\n\nexport interface BoxRecord {\n id: string;\n name: string;\n container: string;\n image: string;\n workspacePath: string;\n lowerPath: string;\n upperVolume: string;\n snapshotDir: string | null;\n /**\n * Host-side path to the agentbox-ctl unix socket bind-mounted into the\n * container at /run/agentbox/ctl.sock. Absent for boxes created before this\n * field existed (treated as \"ctl not available\").\n */\n socketPath?: string;\n /**\n * Docker volume mounted at /home/vscode/.claude inside the box. The default\n * shared volume (`agentbox-claude-config`) is reused across boxes; isolated\n * boxes get a per-box volume suffixed with the box id. Absent for boxes\n * created before this field existed.\n */\n claudeConfigVolume?: string;\n /**\n * Per-box volume holding `.vscode-server` (server binary + TS cache).\n * The shared `agentbox-vscode-extensions` volume layers over the `extensions`\n * subdir at run time and isn't recorded here (never auto-removed). Absent\n * for boxes created before this field existed.\n */\n vscodeServerVolume?: string;\n /**\n * Per-box volume holding `.cursor-server` (Cursor server binary + state).\n * Parallel to `vscodeServerVolume`. Absent for boxes created before this\n * field existed — lifecycle code falls back to deriving from `id`.\n */\n cursorServerVolume?: string;\n /**\n * Bearer token the in-box supervisor uses to authenticate with the host\n * relay. Generated at create time and forwarded as AGENTBOX_RELAY_TOKEN.\n * Absent for boxes created before the relay existed — those boxes simply\n * skip outbound push.\n */\n relayToken?: string;\n /**\n * Git worktrees mounted into the box. Empty/absent when the host workspace\n * is not a git checkout. The root entry (kind: 'root') replaces the box's\n * overlay lower; nested entries (kind: 'nested', from monorepo 1st-level\n * `.git` dirs) are bind-mounted at /workspace/<relPathFromWorkspace> after\n * the FUSE overlay is mounted.\n */\n gitWorktrees?: GitWorktreeRecord[];\n /**\n * True when the box was created with --with-playwright. The install happens\n * once at create time (npm install -g @playwright/cli@latest inside the\n * container); we record the choice for `agentbox inspect` visibility. Absent\n * on boxes created before this field existed (treated as false).\n */\n withPlaywright?: boolean;\n /**\n * True when the box was created with --with-env. The host's env/config files\n * (DEFAULT_ENV_PATTERNS) were copied into /workspace once at create time,\n * bypassing gitignore; recorded for `agentbox inspect` visibility. Absent on\n * boxes created before this field existed (treated as false).\n */\n withEnv?: boolean;\n /**\n * VNC stack (Xvnc + websockify + noVNC) is enabled for this box. Absent on\n * boxes created before VNC support landed → treated as disabled.\n */\n vncEnabled?: boolean;\n /** Container-side noVNC web port. Fixed to 6080 today; here for future-proofing. */\n vncContainerPort?: number;\n /** Random host port Docker assigned to the noVNC web server (resolved via `docker port`). */\n vncHostPort?: number;\n /** Per-box password baked into Xvnc's PasswordFile and embedded in the auto-connect URL. */\n vncPassword?: string;\n /**\n * Container port reserved for the web service `expose:` forward. Fixed to 80\n * today; the `-p` mapping is created unconditionally at `create`. Absent on\n * boxes created before web-port reservation landed → no web endpoint until\n * the box is recreated.\n */\n webContainerPort?: number;\n /** Random host port Docker assigned to container :80 (resolved via `docker port`). */\n webHostPort?: number;\n /**\n * Volume mounted at /var/lib/docker for the in-box dockerd. Per-box\n * (`agentbox-docker-<id>`) by default; the shared `agentbox-docker-cache`\n * volume when `dockerCacheShared` is true. Absent on boxes created before\n * DinD landed — those boxes have no in-box dockerd at all.\n */\n dockerVolume?: string;\n /**\n * True when this box's `dockerVolume` is the shared cache. Tells `destroyBox`\n * to skip removal (the shared volume holds image layers other boxes may\n * reuse) and `pruneBoxes --all` to allowlist it.\n */\n dockerCacheShared?: boolean;\n /**\n * Absolute host path of the project this box belongs to. Set by `createBox`\n * from the CLI-supplied `findProjectRoot(workspacePath)` (nearest ancestor\n * dir holding `agentbox.yaml`, else workspacePath itself). Used by\n * `resolveBoxRef` + `autoPickProjectBox` to scope numeric refs and auto-pick\n * to the cwd's project. Absent on boxes created before this field existed —\n * those boxes are never auto-picked or matched by numeric index.\n */\n projectRoot?: string;\n /**\n * Monotonic 1-based index within `projectRoot`. Allocated once at create via\n * `allocateProjectIndex` and never recycled — destroying box #2 leaves a gap\n * (next new box is #3, not #2). Lets `agentbox open 3` mean the same box for\n * that box's whole lifetime.\n */\n projectIndex?: number;\n /**\n * Ordered in-container lower directories (upper-most first) the FUSE overlay\n * was mounted with. Persisted so `startBox` re-mounts identically after a\n * stop/start. Absent on non-checkpoint boxes → `mountOverlay` defaults to\n * the single base bind `['/host-src']` (byte-identical to legacy boxes).\n */\n lowerDirs?: string[];\n /**\n * The per-project checkpoint Docker volume mounted read-only at\n * `/agentbox-checkpoints` when this box was created from a checkpoint (the\n * `lowerDirs` reference subdirs of that mount). Absent on non-checkpoint\n * boxes. `startBox` revalidates this volume still exists (Docker bakes the\n * mount at create time) before re-mounting.\n */\n checkpointVolume?: string;\n /**\n * Lineage of the checkpoint this box was created from. Drives chain-depth\n * (auto-merge threshold) and `agentbox inspect`. Absent when the box was not\n * created from a checkpoint.\n */\n checkpointSource?: {\n ref: string;\n type: 'layered' | 'merged';\n /** Checkpoint refs composing the chain, base-most last. */\n chain: string[];\n };\n /**\n * Resource ceilings actually applied at `docker run` (bytes/fractional/count;\n * the `disk` string only present when the engine's storage driver enforces\n * it — dropped + warned on overlay2/macOS). Absent on legacy boxes → treated\n * as unlimited. Surfaced by `agentbox inspect` and cross-checked by\n * `boxResourceStats`.\n */\n resourceLimits?: {\n memoryBytes?: number;\n cpus?: number;\n pidsLimit?: number;\n disk?: string;\n };\n createdAt: string; // ISO-8601\n}\n\nexport interface GitWorktreeRecord {\n kind: 'root' | 'nested';\n /** Host path to the main repo whose `.git/` is bind-mounted RW at the identical path inside the container. */\n hostMainRepo: string;\n /** Host path to the per-box worktree directory (under ~/.agentbox/boxes/<id>/worktrees/). */\n hostWorktreeDir: string;\n /** Container path that resolves to the worktree's working tree. /workspace for root, /workspace/<subpath> for nested. */\n containerPath: string;\n /** Branch the worktree was created on, e.g. `agentbox/<box-name>`. */\n branch: string;\n /** Workspace-relative path the repo was found at (empty string for root). */\n relPathFromWorkspace: string;\n}\n\nexport interface StateFile {\n version: 1;\n boxes: BoxRecord[];\n}\n\nconst EMPTY: StateFile = { version: 1, boxes: [] };\n\nexport async function readState(path: string = STATE_FILE): Promise<StateFile> {\n try {\n const raw = await readFile(path, 'utf8');\n const parsed = JSON.parse(raw) as StateFile;\n if (parsed.version !== 1 || !Array.isArray(parsed.boxes)) {\n throw new Error(`unrecognized state file shape at ${path}`);\n }\n return parsed;\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n return { ...EMPTY };\n }\n throw err;\n }\n}\n\nexport async function writeState(state: StateFile, path: string = STATE_FILE): Promise<void> {\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, JSON.stringify(state, null, 2) + '\\n', 'utf8');\n}\n\nexport async function recordBox(box: BoxRecord, path: string = STATE_FILE): Promise<void> {\n const state = await readState(path);\n const next: StateFile = {\n version: 1,\n boxes: [...state.boxes.filter((b) => b.id !== box.id), box],\n };\n await writeState(next, path);\n}\n\nexport async function removeBoxRecord(id: string, path: string = STATE_FILE): Promise<boolean> {\n const state = await readState(path);\n const before = state.boxes.length;\n const next: StateFile = {\n version: 1,\n boxes: state.boxes.filter((b) => b.id !== id),\n };\n if (next.boxes.length === before) return false;\n await writeState(next, path);\n return true;\n}\n\nexport type FindBoxResult =\n | { kind: 'ok'; box: BoxRecord }\n | { kind: 'none' }\n | { kind: 'ambiguous'; matches: BoxRecord[] };\n\n/**\n * Resolve a user-supplied identifier against the state file. Matching\n * precedence mirrors `docker`'s container reference resolution:\n *\n * 1. exact id\n * 2. unique id prefix\n * 3. exact name\n * 4. exact container name\n *\n * Returns `'ambiguous'` if step 2 finds more than one match (steps 1, 3, 4\n * are exact-match so they cannot be ambiguous on their own).\n */\nexport function findBox(idOrName: string, state: StateFile): FindBoxResult {\n const q = idOrName.trim();\n if (q.length === 0) return { kind: 'none' };\n\n const exactId = state.boxes.find((b) => b.id === q);\n if (exactId) return { kind: 'ok', box: exactId };\n\n const prefixMatches = state.boxes.filter((b) => b.id.startsWith(q));\n if (prefixMatches.length === 1) return { kind: 'ok', box: prefixMatches[0]! };\n if (prefixMatches.length > 1) return { kind: 'ambiguous', matches: prefixMatches };\n\n const byName = state.boxes.find((b) => b.name === q);\n if (byName) return { kind: 'ok', box: byName };\n\n const byContainer = state.boxes.find((b) => b.container === q);\n if (byContainer) return { kind: 'ok', box: byContainer };\n\n return { kind: 'none' };\n}\n\n/**\n * Next monotonic 1-based index for the given project. Reads only `state.boxes`\n * — caller is responsible for persisting the assignment. Boxes without\n * `projectRoot` are ignored (legacy records); boxes in *other* projects are\n * also ignored. Indices are never recycled, so a destroyed #2 leaves a gap.\n */\nexport function allocateProjectIndex(state: StateFile, projectRoot: string): number {\n let max = 0;\n for (const b of state.boxes) {\n if (b.projectRoot !== projectRoot) continue;\n if (typeof b.projectIndex === 'number' && b.projectIndex > max) {\n max = b.projectIndex;\n }\n }\n return max + 1;\n}\n\n/**\n * Auto-pick when a command's `[box]` argument is omitted. Returns the unique\n * box for `projectRoot`, an `ambiguous` carrying all candidates so the CLI can\n * print a chooser, or `none`.\n */\nexport function autoPickProjectBox(state: StateFile, projectRoot: string): FindBoxResult {\n const matches = state.boxes.filter((b) => b.projectRoot === projectRoot);\n if (matches.length === 0) return { kind: 'none' };\n if (matches.length === 1) return { kind: 'ok', box: matches[0]! };\n return { kind: 'ambiguous', matches };\n}\n\n/**\n * Top-level resolver every CLI command goes through. Combines numeric-index\n * lookup with the legacy `findBox` matcher:\n *\n * - `ref === undefined` and `projectRoot` known → autoPickProjectBox.\n * - `ref` is a pure positive integer and `projectRoot` known → resolve as\n * project index. **Never** falls through to `findBox` on miss, so\n * `agentbox open 3` is reserved for the index and won't accidentally\n * match a hex id like `3abc…`.\n * - Otherwise → `findBox` (id → prefix → name → container).\n */\nexport function resolveBoxRef(\n ref: string | undefined,\n state: StateFile,\n projectRoot: string | undefined,\n): FindBoxResult {\n if (ref === undefined) {\n if (projectRoot === undefined) return { kind: 'none' };\n return autoPickProjectBox(state, projectRoot);\n }\n const trimmed = ref.trim();\n if (projectRoot !== undefined && /^[1-9][0-9]*$/.test(trimmed)) {\n const idx = Number.parseInt(trimmed, 10);\n const hit = state.boxes.find(\n (b) => b.projectRoot === projectRoot && b.projectIndex === idx,\n );\n return hit ? { kind: 'ok', box: hit } : { kind: 'none' };\n }\n return findBox(trimmed, state);\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,200 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ CHECKPOINT_VOLUME_PREFIX,
4
+ checkpointVolumeName,
5
+ detectEngine,
6
+ inspectContainer,
7
+ inspectContainerStatus,
8
+ inspectVolumeMountpoint,
9
+ listAgentboxVolumes
10
+ } from "./chunk-SOMIKEN2.js";
11
+
12
+ // ../../packages/sandbox-docker/dist/chunk-ENPH736J.js
13
+ import { homedir } from "os";
14
+ import { join } from "path";
15
+ import { execa } from "execa";
16
+ function parseDockerSize(raw) {
17
+ const s = raw.trim();
18
+ if (!s || s === "--" || s === "N/A") return null;
19
+ const m = /^([\d.]+)\s*([A-Za-z]*)$/.exec(s);
20
+ if (!m) return null;
21
+ const n = Number(m[1]);
22
+ if (!Number.isFinite(n)) return null;
23
+ const unit = (m[2] ?? "").toLowerCase();
24
+ const mult = {
25
+ "": 1,
26
+ b: 1,
27
+ kb: 1e3,
28
+ mb: 1e6,
29
+ gb: 1e9,
30
+ tb: 1e12,
31
+ kib: 1024,
32
+ mib: 1024 ** 2,
33
+ gib: 1024 ** 3,
34
+ tib: 1024 ** 4
35
+ };
36
+ const factor = mult[unit];
37
+ return factor === void 0 ? null : n * factor;
38
+ }
39
+ function parsePercent(raw) {
40
+ if (!raw) return null;
41
+ const n = Number(raw.replace("%", "").trim());
42
+ return Number.isFinite(n) ? n : null;
43
+ }
44
+ function splitPair(raw) {
45
+ if (!raw) return null;
46
+ const parts = raw.split("/");
47
+ if (parts.length !== 2) return null;
48
+ return [parts[0].trim(), parts[1].trim()];
49
+ }
50
+ async function duBytes(path) {
51
+ const result = await execa("du", ["-sk", path], { reject: false });
52
+ if (result.exitCode !== 0) return null;
53
+ const kb = Number.parseInt((result.stdout ?? "").split(/\s+/)[0] ?? "", 10);
54
+ return Number.isNaN(kb) ? null : kb * 1024;
55
+ }
56
+ async function volumeSizeBytes(name) {
57
+ if (!name) return null;
58
+ const engine = await detectEngine();
59
+ if (engine === "orbstack") {
60
+ const live = join(homedir(), "OrbStack", "docker", "volumes", name);
61
+ const sz = await duBytes(live);
62
+ if (sz !== null) return sz;
63
+ }
64
+ const df = await execa(
65
+ "docker",
66
+ ["system", "df", "-v", "--format", "{{json .Volumes}}"],
67
+ { reject: false }
68
+ );
69
+ if (df.exitCode === 0) {
70
+ try {
71
+ const vols = JSON.parse(df.stdout || "[]");
72
+ const hit = vols.find((v) => v.Name === name);
73
+ const parsed = hit?.Size ? parseDockerSize(hit.Size) : null;
74
+ if (parsed !== null) return parsed;
75
+ } catch {
76
+ }
77
+ }
78
+ const mp = await inspectVolumeMountpoint(name);
79
+ if (mp && !mp.startsWith("/var/lib/docker")) {
80
+ return duBytes(mp);
81
+ }
82
+ return null;
83
+ }
84
+ async function projectCheckpointVolumeBytes(projectRoot) {
85
+ return volumeSizeBytes(checkpointVolumeName(projectRoot));
86
+ }
87
+ async function allCheckpointVolumesBytes() {
88
+ const vols = (await listAgentboxVolumes()).filter(
89
+ (v) => v.startsWith(CHECKPOINT_VOLUME_PREFIX)
90
+ );
91
+ if (vols.length === 0) return null;
92
+ const sizes = await Promise.all(vols.map((v) => volumeSizeBytes(v)));
93
+ const known = sizes.filter((s) => s !== null);
94
+ return known.length === 0 ? null : known.reduce((a, b) => a + b, 0);
95
+ }
96
+ async function agentboxHomeBytes() {
97
+ return duBytes(join(homedir(), ".agentbox"));
98
+ }
99
+ function limitsFromRecord(record) {
100
+ const r = record.resourceLimits;
101
+ return {
102
+ memoryBytes: r?.memoryBytes && r.memoryBytes > 0 ? r.memoryBytes : null,
103
+ cpus: r?.cpus && r.cpus > 0 ? r.cpus : null,
104
+ pidsLimit: r?.pidsLimit && r.pidsLimit > 0 ? r.pidsLimit : null,
105
+ disk: r?.disk || null
106
+ };
107
+ }
108
+ function reconcileLimits(persisted, dockerJson) {
109
+ const hc = dockerJson?.HostConfig;
110
+ if (!hc) return persisted;
111
+ const mem = typeof hc.Memory === "number" && hc.Memory > 0 ? hc.Memory : null;
112
+ const nano = typeof hc.NanoCpus === "number" && hc.NanoCpus > 0 ? hc.NanoCpus : null;
113
+ const pids = typeof hc.PidsLimit === "number" && hc.PidsLimit > 0 ? hc.PidsLimit : null;
114
+ return {
115
+ memoryBytes: mem ?? persisted.memoryBytes,
116
+ cpus: nano ? nano / 1e9 : persisted.cpus,
117
+ pidsLimit: pids ?? persisted.pidsLimit,
118
+ disk: persisted.disk
119
+ };
120
+ }
121
+ async function boxResourceStats(record) {
122
+ const warnings = [];
123
+ const dockerJson = await inspectContainer(record.container);
124
+ const limits = reconcileLimits(limitsFromRecord(record), dockerJson);
125
+ const [diskUpper, diskDocker, snapshotDiskBytes, checkpointVolumeBytes] = await Promise.all([
126
+ volumeSizeBytes(record.upperVolume),
127
+ record.dockerVolume ? volumeSizeBytes(record.dockerVolume) : Promise.resolve(null),
128
+ record.snapshotDir ? duBytes(record.snapshotDir) : Promise.resolve(null),
129
+ record.checkpointVolume ? volumeSizeBytes(record.checkpointVolume) : Promise.resolve(null)
130
+ ]);
131
+ const diskUsedBytes = diskUpper === null && diskDocker === null ? null : (diskUpper ?? 0) + (diskDocker ?? 0);
132
+ if (diskUsedBytes === null) {
133
+ warnings.push("disk usage unavailable on this engine");
134
+ }
135
+ const base = {
136
+ source: "docker",
137
+ live: false,
138
+ cpuPercent: null,
139
+ memUsedBytes: null,
140
+ memLimitBytes: limits.memoryBytes,
141
+ memPercent: null,
142
+ pids: null,
143
+ diskUsedBytes,
144
+ snapshotDiskBytes,
145
+ checkpointVolumeBytes,
146
+ netRxBytes: null,
147
+ netTxBytes: null,
148
+ blockReadBytes: null,
149
+ blockWriteBytes: null,
150
+ limits,
151
+ warnings
152
+ };
153
+ if (await inspectContainerStatus(record.container) !== "running") {
154
+ return base;
155
+ }
156
+ const proc = await execa(
157
+ "docker",
158
+ ["stats", "--no-stream", "--format", "{{json .}}", record.container],
159
+ { reject: false }
160
+ );
161
+ if (proc.exitCode !== 0 || !proc.stdout.trim()) {
162
+ return base;
163
+ }
164
+ let line;
165
+ try {
166
+ line = JSON.parse(proc.stdout.trim().split("\n")[0]);
167
+ } catch {
168
+ return base;
169
+ }
170
+ const memPair = splitPair(line.MemUsage);
171
+ const memUsedBytes = memPair ? parseDockerSize(memPair[0]) : null;
172
+ const memEngineTotal = memPair ? parseDockerSize(memPair[1]) : null;
173
+ const netPair = splitPair(line.NetIO);
174
+ const blkPair = splitPair(line.BlockIO);
175
+ return {
176
+ ...base,
177
+ live: true,
178
+ cpuPercent: parsePercent(line.CPUPerc),
179
+ memUsedBytes,
180
+ // The applied limit when set; otherwise docker stats' own denominator
181
+ // (the engine/host total).
182
+ memLimitBytes: limits.memoryBytes ?? memEngineTotal,
183
+ memPercent: parsePercent(line.MemPerc),
184
+ pids: line.PIDs ? Number.parseInt(line.PIDs, 10) || null : null,
185
+ netRxBytes: netPair ? parseDockerSize(netPair[0]) : null,
186
+ netTxBytes: netPair ? parseDockerSize(netPair[1]) : null,
187
+ blockReadBytes: blkPair ? parseDockerSize(blkPair[0]) : null,
188
+ blockWriteBytes: blkPair ? parseDockerSize(blkPair[1]) : null
189
+ };
190
+ }
191
+
192
+ export {
193
+ parseDockerSize,
194
+ volumeSizeBytes,
195
+ projectCheckpointVolumeBytes,
196
+ allCheckpointVolumesBytes,
197
+ agentboxHomeBytes,
198
+ boxResourceStats
199
+ };
200
+ //# sourceMappingURL=chunk-J35IH7W5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../packages/sandbox-docker/src/stats.ts"],"sourcesContent":["import { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { execa } from 'execa';\nimport type { BoxResourceLimits, BoxResourceStats } from '@agentbox/core';\nimport { CHECKPOINT_VOLUME_PREFIX, checkpointVolumeName } from './checkpoint.js';\nimport {\n inspectContainer,\n inspectContainerStatus,\n inspectVolumeMountpoint,\n listAgentboxVolumes,\n} from './docker.js';\nimport { detectEngine } from './host-export.js';\nimport type { BoxRecord } from './state.js';\n\n/**\n * Parse one of Docker's human-formatted size tokens (`512MiB`, `1.2kB`,\n * `3.4GB`, `0B`, `--`). Returns null when unparseable. Docker mixes binary\n * (`KiB/MiB/GiB`) and decimal (`kB/MB/GB`) suffixes depending on the column, so\n * we handle both.\n */\nexport function parseDockerSize(raw: string): number | null {\n const s = raw.trim();\n if (!s || s === '--' || s === 'N/A') return null;\n const m = /^([\\d.]+)\\s*([A-Za-z]*)$/.exec(s);\n if (!m) return null;\n const n = Number(m[1]);\n if (!Number.isFinite(n)) return null;\n const unit = (m[2] ?? '').toLowerCase();\n const mult: Record<string, number> = {\n '': 1,\n b: 1,\n kb: 1e3,\n mb: 1e6,\n gb: 1e9,\n tb: 1e12,\n kib: 1024,\n mib: 1024 ** 2,\n gib: 1024 ** 3,\n tib: 1024 ** 4,\n };\n const factor = mult[unit];\n return factor === undefined ? null : n * factor;\n}\n\nfunction parsePercent(raw: string | undefined): number | null {\n if (!raw) return null;\n const n = Number(raw.replace('%', '').trim());\n return Number.isFinite(n) ? n : null;\n}\n\n/** Split Docker's \"<a> / <b>\" pair columns (MemUsage, NetIO, BlockIO). */\nfunction splitPair(raw: string | undefined): [string, string] | null {\n if (!raw) return null;\n const parts = raw.split('/');\n if (parts.length !== 2) return null;\n return [parts[0]!.trim(), parts[1]!.trim()];\n}\n\nasync function duBytes(path: string): Promise<number | null> {\n const result = await execa('du', ['-sk', path], { reject: false });\n if (result.exitCode !== 0) return null;\n const kb = Number.parseInt((result.stdout ?? '').split(/\\s+/)[0] ?? '', 10);\n return Number.isNaN(kb) ? null : kb * 1024;\n}\n\n/**\n * Best-effort on-host byte size of a Docker named volume. Fastest path first:\n * 1. OrbStack exposes volumes live at ~/OrbStack/docker/volumes/<name>/.\n * 2. `docker system df -v` (cheap-walked once; may report \"N/A\").\n * 3. The reported mountpoint, only when host-readable (Linux native Docker).\n * Returns null when no path is reachable from the host (the macOS VM case\n * where `system df` also has no number).\n */\nexport async function volumeSizeBytes(name: string): Promise<number | null> {\n if (!name) return null;\n const engine = await detectEngine();\n if (engine === 'orbstack') {\n const live = join(homedir(), 'OrbStack', 'docker', 'volumes', name);\n const sz = await duBytes(live);\n if (sz !== null) return sz;\n }\n const df = await execa(\n 'docker',\n ['system', 'df', '-v', '--format', '{{json .Volumes}}'],\n { reject: false },\n );\n if (df.exitCode === 0) {\n try {\n const vols = JSON.parse(df.stdout || '[]') as Array<{ Name?: string; Size?: string }>;\n const hit = vols.find((v) => v.Name === name);\n const parsed = hit?.Size ? parseDockerSize(hit.Size) : null;\n if (parsed !== null) return parsed;\n } catch {\n // fall through to mountpoint\n }\n }\n const mp = await inspectVolumeMountpoint(name);\n if (mp && !mp.startsWith('/var/lib/docker')) {\n return duBytes(mp);\n }\n return null;\n}\n\n/** Size of the per-project shared checkpoint volume, or null when absent. */\nexport async function projectCheckpointVolumeBytes(\n projectRoot: string,\n): Promise<number | null> {\n return volumeSizeBytes(checkpointVolumeName(projectRoot));\n}\n\n/**\n * Total on-host bytes of every per-project checkpoint volume (the durable,\n * cross-box warm-state assets). Null when none exist or no size is reachable\n * from the host.\n */\nexport async function allCheckpointVolumesBytes(): Promise<number | null> {\n const vols = (await listAgentboxVolumes()).filter((v) =>\n v.startsWith(CHECKPOINT_VOLUME_PREFIX),\n );\n if (vols.length === 0) return null;\n const sizes = await Promise.all(vols.map((v) => volumeSizeBytes(v)));\n const known = sizes.filter((s): s is number => s !== null);\n return known.length === 0 ? null : known.reduce((a, b) => a + b, 0);\n}\n\n/** On-host byte size of the whole ~/.agentbox state/runtime directory. */\nexport async function agentboxHomeBytes(): Promise<number | null> {\n return duBytes(join(homedir(), '.agentbox'));\n}\n\nfunction limitsFromRecord(record: BoxRecord): BoxResourceLimits {\n const r = record.resourceLimits;\n return {\n memoryBytes: r?.memoryBytes && r.memoryBytes > 0 ? r.memoryBytes : null,\n cpus: r?.cpus && r.cpus > 0 ? r.cpus : null,\n pidsLimit: r?.pidsLimit && r.pidsLimit > 0 ? r.pidsLimit : null,\n disk: r?.disk || null,\n };\n}\n\n/**\n * Cross-check persisted limits against the live container's HostConfig so an\n * externally `docker update`d box still reports the truth. The persisted\n * record stays the fallback when the container is gone.\n */\nfunction reconcileLimits(persisted: BoxResourceLimits, dockerJson: unknown): BoxResourceLimits {\n const hc = (dockerJson as { HostConfig?: Record<string, unknown> } | null)?.HostConfig;\n if (!hc) return persisted;\n const mem = typeof hc.Memory === 'number' && hc.Memory > 0 ? hc.Memory : null;\n const nano = typeof hc.NanoCpus === 'number' && hc.NanoCpus > 0 ? hc.NanoCpus : null;\n const pids = typeof hc.PidsLimit === 'number' && hc.PidsLimit > 0 ? hc.PidsLimit : null;\n return {\n memoryBytes: mem ?? persisted.memoryBytes,\n cpus: nano ? nano / 1e9 : persisted.cpus,\n pidsLimit: pids ?? persisted.pidsLimit,\n disk: persisted.disk,\n };\n}\n\ninterface DockerStatsLine {\n CPUPerc?: string;\n MemUsage?: string;\n MemPerc?: string;\n PIDs?: string;\n NetIO?: string;\n BlockIO?: string;\n}\n\n/**\n * Provider-agnostic resource snapshot for a box. CPU/mem/pids/IO come from\n * `docker stats --no-stream` (point-in-time sample; only when the container is\n * running). Disk is the per-box writable surface (upper + docker data-root\n * volumes); the per-box host snapshot dir and the SHARED per-project\n * checkpoint volume are reported on their own fields and never summed into\n * `diskUsedBytes` (would double-count across a project's boxes).\n */\nexport async function boxResourceStats(record: BoxRecord): Promise<BoxResourceStats> {\n const warnings: string[] = [];\n const dockerJson = await inspectContainer(record.container);\n const limits = reconcileLimits(limitsFromRecord(record), dockerJson);\n\n const [diskUpper, diskDocker, snapshotDiskBytes, checkpointVolumeBytes] = await Promise.all([\n volumeSizeBytes(record.upperVolume),\n record.dockerVolume ? volumeSizeBytes(record.dockerVolume) : Promise.resolve(null),\n record.snapshotDir ? duBytes(record.snapshotDir) : Promise.resolve(null),\n record.checkpointVolume\n ? volumeSizeBytes(record.checkpointVolume)\n : Promise.resolve(null),\n ]);\n const diskUsedBytes =\n diskUpper === null && diskDocker === null ? null : (diskUpper ?? 0) + (diskDocker ?? 0);\n if (diskUsedBytes === null) {\n warnings.push('disk usage unavailable on this engine');\n }\n\n const base: BoxResourceStats = {\n source: 'docker',\n live: false,\n cpuPercent: null,\n memUsedBytes: null,\n memLimitBytes: limits.memoryBytes,\n memPercent: null,\n pids: null,\n diskUsedBytes,\n snapshotDiskBytes,\n checkpointVolumeBytes,\n netRxBytes: null,\n netTxBytes: null,\n blockReadBytes: null,\n blockWriteBytes: null,\n limits,\n warnings,\n };\n\n if ((await inspectContainerStatus(record.container)) !== 'running') {\n return base;\n }\n\n const proc = await execa(\n 'docker',\n ['stats', '--no-stream', '--format', '{{json .}}', record.container],\n { reject: false },\n );\n if (proc.exitCode !== 0 || !proc.stdout.trim()) {\n return base;\n }\n let line: DockerStatsLine;\n try {\n line = JSON.parse(proc.stdout.trim().split('\\n')[0]!) as DockerStatsLine;\n } catch {\n return base;\n }\n\n const memPair = splitPair(line.MemUsage);\n const memUsedBytes = memPair ? parseDockerSize(memPair[0]) : null;\n const memEngineTotal = memPair ? parseDockerSize(memPair[1]) : null;\n const netPair = splitPair(line.NetIO);\n const blkPair = splitPair(line.BlockIO);\n\n return {\n ...base,\n live: true,\n cpuPercent: parsePercent(line.CPUPerc),\n memUsedBytes,\n // The applied limit when set; otherwise docker stats' own denominator\n // (the engine/host total).\n memLimitBytes: limits.memoryBytes ?? memEngineTotal,\n memPercent: parsePercent(line.MemPerc),\n pids: line.PIDs ? Number.parseInt(line.PIDs, 10) || null : null,\n netRxBytes: netPair ? parseDockerSize(netPair[0]) : null,\n netTxBytes: netPair ? parseDockerSize(netPair[1]) : null,\n blockReadBytes: blkPair ? parseDockerSize(blkPair[0]) : null,\n blockWriteBytes: blkPair ? parseDockerSize(blkPair[1]) : null,\n };\n}\n"],"mappings":"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","names":[]}