@madarco/agentbox 0.6.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/dist/_cloud-attach-T727ZPRV.js +13 -0
  2. package/dist/chunk-67N47KUS.js +1640 -0
  3. package/dist/chunk-67N47KUS.js.map +1 -0
  4. package/dist/chunk-6OZDFNBF.js +8114 -0
  5. package/dist/chunk-6OZDFNBF.js.map +1 -0
  6. package/dist/chunk-BGK32PZE.js +455 -0
  7. package/dist/chunk-BGK32PZE.js.map +1 -0
  8. package/dist/chunk-FODMEHD3.js +1200 -0
  9. package/dist/chunk-FODMEHD3.js.map +1 -0
  10. package/dist/chunk-G3H2L3O2.js +288 -0
  11. package/dist/chunk-G3H2L3O2.js.map +1 -0
  12. package/dist/chunk-I24B6AXR.js +600 -0
  13. package/dist/chunk-I24B6AXR.js.map +1 -0
  14. package/dist/chunk-LEV3KICD.js +738 -0
  15. package/dist/chunk-LEV3KICD.js.map +1 -0
  16. package/dist/cloud-poller-SUNA6ZQC-2RG5WPRN.js +10 -0
  17. package/dist/dist-L4LCG5SJ.js +293 -0
  18. package/dist/dist-L4LCG5SJ.js.map +1 -0
  19. package/dist/dist-LOZBWMBF.js +447 -0
  20. package/dist/dist-ZODPD2I6.js +1407 -0
  21. package/dist/dist-ZODPD2I6.js.map +1 -0
  22. package/dist/index.js +7281 -2134
  23. package/dist/index.js.map +1 -1
  24. package/dist/prepared-state-CL4CWXQA-ME4HSKDE.js +18 -0
  25. package/package.json +8 -3
  26. package/runtime/daytona/custom-system-CLAUDE.md +39 -0
  27. package/runtime/docker/Dockerfile.box +120 -14
  28. package/runtime/docker/apps/cli/share/agentbox-setup/SKILL.md +15 -8
  29. package/runtime/docker/packages/ctl/dist/bin.cjs +11310 -816
  30. package/runtime/docker/packages/sandbox-docker/scripts/agentbox-codex-hooks.json +68 -0
  31. package/runtime/docker/packages/sandbox-docker/scripts/agentbox-open +9 -9
  32. package/runtime/docker/packages/sandbox-docker/scripts/claude-managed-settings.json +62 -1
  33. package/runtime/docker/packages/sandbox-docker/scripts/custom-system-CLAUDE.md +15 -4
  34. package/runtime/docker/packages/sandbox-docker/scripts/gh-shim +263 -0
  35. package/runtime/docker/packages/sandbox-docker/scripts/git-shim +131 -0
  36. package/runtime/docker/packages/sandbox-docker/scripts/opencode-agentbox-plugin.js +76 -0
  37. package/runtime/hetzner/agentbox-checkpoint-cleanup +52 -0
  38. package/runtime/hetzner/agentbox-codex-hooks.json +68 -0
  39. package/runtime/hetzner/agentbox-dockerd-start +132 -0
  40. package/runtime/hetzner/agentbox-open +28 -0
  41. package/runtime/hetzner/agentbox-setup-skill.md +196 -0
  42. package/runtime/hetzner/agentbox-vnc-start +77 -0
  43. package/runtime/hetzner/claude-managed-settings.json +115 -0
  44. package/runtime/hetzner/ctl.cjs +23397 -0
  45. package/runtime/hetzner/custom-system-CLAUDE.md +39 -0
  46. package/runtime/hetzner/gh-shim +263 -0
  47. package/runtime/hetzner/git-shim +131 -0
  48. package/runtime/hetzner/opencode-agentbox-plugin.js +76 -0
  49. package/runtime/hetzner/scripts/install-box.sh +374 -0
  50. package/runtime/relay/bin.cjs +10017 -817
  51. package/share/agentbox-setup/SKILL.md +15 -8
  52. package/share/host-skills/agentbox/SKILL.md +29 -0
  53. package/share/host-skills/agentbox-info/SKILL.md +211 -0
  54. package/share/host-skills/codex/agentbox.md +35 -0
  55. package/share/host-skills/opencode/agentbox.md +26 -0
  56. package/dist/chunk-BBZMA2K6.js +0 -238
  57. package/dist/chunk-BBZMA2K6.js.map +0 -1
  58. package/dist/chunk-HHMWQNLF.js +0 -1709
  59. package/dist/chunk-HHMWQNLF.js.map +0 -1
  60. package/dist/chunk-HPZMD5DE.js +0 -106
  61. package/dist/chunk-HPZMD5DE.js.map +0 -1
  62. package/dist/chunk-HTTKML3C.js +0 -2655
  63. package/dist/chunk-HTTKML3C.js.map +0 -1
  64. package/dist/chunk-KJNZP6I3.js +0 -586
  65. package/dist/chunk-KJNZP6I3.js.map +0 -1
  66. package/dist/chunk-M7I247BK.js +0 -525
  67. package/dist/chunk-M7I247BK.js.map +0 -1
  68. package/dist/create-6PWXI6HO-OWAMHBAK.js +0 -15
  69. package/dist/lifecycle-EMXR46DI-DUVBXNTV.js +0 -38
  70. package/dist/state-KD7M46ZP-KHFTHFUS.js +0 -26
  71. package/dist/stats-SZXOJE3D-N7OODCHW.js +0 -19
  72. /package/dist/{create-6PWXI6HO-OWAMHBAK.js.map → _cloud-attach-T727ZPRV.js.map} +0 -0
  73. /package/dist/{lifecycle-EMXR46DI-DUVBXNTV.js.map → cloud-poller-SUNA6ZQC-2RG5WPRN.js.map} +0 -0
  74. /package/dist/{state-KD7M46ZP-KHFTHFUS.js.map → dist-LOZBWMBF.js.map} +0 -0
  75. /package/dist/{stats-SZXOJE3D-N7OODCHW.js.map → prepared-state-CL4CWXQA-ME4HSKDE.js.map} +0 -0
@@ -1,1709 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // ../../packages/sandbox-docker/dist/chunk-FTYSR4JQ.js
4
- import { execa } from "execa";
5
- import { mkdir as mkdir2, readFile as readFile3 } from "fs/promises";
6
- import { homedir as homedir2 } from "os";
7
- import { join as join3 } from "path";
8
- import { execa as execa2 } from "execa";
9
-
10
- // ../../packages/config/dist/index.js
11
- import { parse as parseYaml } from "yaml";
12
- import { createHash } from "crypto";
13
- import { realpath, stat } from "fs/promises";
14
- import { homedir } from "os";
15
- import { basename, dirname, join, resolve } from "path";
16
- import { readFile } from "fs/promises";
17
- import { parse as parseYaml2 } from "yaml";
18
- import { mkdir, readFile as readFile2, rename, rm, stat as stat2, writeFile } from "fs/promises";
19
- import { dirname as dirname2, isAbsolute, join as join2 } from "path";
20
- import { stringify as stringifyYaml } from "yaml";
21
- import { readdir } from "fs/promises";
22
- var BUILT_IN_DEFAULTS = {
23
- box: {
24
- hostSnapshot: void 0,
25
- defaultCheckpoint: "",
26
- withPlaywright: false,
27
- withEnv: false,
28
- vnc: true,
29
- isolateClaudeConfig: false,
30
- image: "agentbox/box:dev",
31
- dockerCacheShared: false,
32
- memory: 0,
33
- cpus: 0,
34
- pidsLimit: 0,
35
- disk: ""
36
- },
37
- checkpoint: {
38
- maxLayers: 3
39
- },
40
- claude: {
41
- sessionName: "claude"
42
- },
43
- code: {
44
- ide: "auto",
45
- wait: true,
46
- timeoutMs: 12e4,
47
- autoTerminals: true
48
- },
49
- shell: {
50
- user: "vscode",
51
- login: true
52
- },
53
- engine: {
54
- kind: "auto"
55
- },
56
- browser: {
57
- default: "agent-browser"
58
- },
59
- relay: {
60
- port: 8787
61
- },
62
- vnc: {
63
- containerPort: 6080
64
- },
65
- autopause: {
66
- enabled: true,
67
- maxRunningBoxes: 5,
68
- idleMinutes: 5
69
- },
70
- maintenance: {
71
- pruneProjectConfigs: true,
72
- pruneProjectConfigsEvery: 50
73
- }
74
- };
75
- var KEY_REGISTRY = [
76
- {
77
- key: "box.hostSnapshot",
78
- type: "bool",
79
- description: "Use a frozen APFS clone of the host workspace as the overlay lower (default: prompt). Was box.snapshot."
80
- },
81
- {
82
- key: "box.defaultCheckpoint",
83
- type: "string",
84
- description: "Checkpoint ref new boxes in this project start from when --snapshot is not given (set via `agentbox checkpoint set-default`)."
85
- },
86
- {
87
- key: "checkpoint.maxLayers",
88
- type: "int",
89
- description: "Max stacked checkpoint layers before a new checkpoint is materialized merged (flattened) instead of layered.",
90
- advanced: true
91
- },
92
- {
93
- key: "box.withPlaywright",
94
- type: "bool",
95
- description: "Install @playwright/cli@latest in the box at create time."
96
- },
97
- {
98
- key: "box.withEnv",
99
- type: "bool",
100
- description: "Copy host env/config files (.env*, secrets.toml, agentbox.yaml, ...) into /workspace at box create time (gitignore-bypassing)."
101
- },
102
- {
103
- key: "box.vnc",
104
- type: "bool",
105
- description: "Run the per-box Xvnc + noVNC stack."
106
- },
107
- {
108
- key: "box.isolateClaudeConfig",
109
- type: "bool",
110
- description: "Use a per-box ~/.claude volume instead of the shared one."
111
- },
112
- {
113
- key: "box.image",
114
- type: "string",
115
- description: "Box image ref (advanced).",
116
- advanced: true
117
- },
118
- {
119
- key: "box.dockerCacheShared",
120
- type: "bool",
121
- description: "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)."
122
- },
123
- {
124
- key: "box.memory",
125
- type: "int",
126
- description: "Hard memory ceiling in MiB for new boxes (0 = unlimited). Use --memory on create/claude for byte/k/m/g strings."
127
- },
128
- {
129
- key: "box.cpus",
130
- type: "int",
131
- description: "CPU count cap for new boxes (0 = unlimited). Whole cores via config; use --cpus for fractional (e.g. 1.5)."
132
- },
133
- {
134
- key: "box.pidsLimit",
135
- type: "int",
136
- description: "Max process count (PIDs cgroup) for new boxes (0 = unlimited)."
137
- },
138
- {
139
- key: "box.disk",
140
- type: "string",
141
- description: "Best-effort writable-layer size for new boxes, e.g. '10G'. No-op on overlay2 / the macOS engines.",
142
- advanced: true
143
- },
144
- {
145
- key: "claude.sessionName",
146
- type: "string",
147
- description: "tmux session name for `agentbox claude`."
148
- },
149
- {
150
- key: "code.ide",
151
- type: "enum",
152
- enumValues: ["vscode", "cursor", "auto"],
153
- description: 'Which IDE `agentbox code` launches; "auto" prefers code, falls back to cursor.'
154
- },
155
- {
156
- key: "code.wait",
157
- type: "bool",
158
- description: "Block on agentbox-ctl wait-ready before opening the IDE."
159
- },
160
- {
161
- key: "code.timeoutMs",
162
- type: "int",
163
- description: "wait-ready timeout in milliseconds."
164
- },
165
- {
166
- key: "code.autoTerminals",
167
- type: "bool",
168
- description: "Generate /workspace/.vscode/tasks.json so the IDE auto-opens log panels."
169
- },
170
- {
171
- key: "shell.user",
172
- type: "string",
173
- description: "Default in-container user for `agentbox shell`."
174
- },
175
- {
176
- key: "shell.login",
177
- type: "bool",
178
- description: "Pass `-l` to bash so the login profile loads."
179
- },
180
- {
181
- key: "engine.kind",
182
- type: "enum",
183
- enumValues: ["orbstack", "docker-desktop", "other", "auto"],
184
- description: "Override the docker-engine auto-detection (used for OrbStack-only optimisations)."
185
- },
186
- {
187
- key: "browser.default",
188
- type: "enum",
189
- enumValues: ["agent-browser", "playwright", "both"],
190
- description: 'Default browser stack inside the box. "playwright" or "both" implies box.withPlaywright.'
191
- },
192
- {
193
- key: "relay.port",
194
- type: "int",
195
- description: "Host relay TCP port (advanced).",
196
- advanced: true
197
- },
198
- {
199
- key: "vnc.containerPort",
200
- type: "int",
201
- description: "Container-side noVNC port (advanced).",
202
- advanced: true
203
- },
204
- {
205
- key: "autopause.enabled",
206
- type: "bool",
207
- description: "Let the host relay periodically pause idle boxes when more than autopause.maxRunningBoxes are running."
208
- },
209
- {
210
- key: "autopause.maxRunningBoxes",
211
- type: "int",
212
- description: "Target maximum number of simultaneously-running boxes before idle ones get auto-paused."
213
- },
214
- {
215
- key: "autopause.idleMinutes",
216
- type: "int",
217
- description: "Minutes a box must be continuously idle (claude state) before it is eligible for auto-pause."
218
- },
219
- {
220
- key: "maintenance.pruneProjectConfigs",
221
- type: "bool",
222
- description: "Periodically delete ~/.agentbox/projects/<hash>/ dirs whose source workspace folder no longer exists."
223
- },
224
- {
225
- key: "maintenance.pruneProjectConfigsEvery",
226
- type: "int",
227
- description: "Run the orphan project-config sweep every N successful `agentbox create`."
228
- }
229
- ];
230
- var REGISTRY_BY_KEY = new Map(KEY_REGISTRY.map((d) => [d.key, d]));
231
- function lookupKey(key) {
232
- return REGISTRY_BY_KEY.get(key);
233
- }
234
- var UserConfigError = class extends Error {
235
- constructor(message) {
236
- super(message);
237
- this.name = "UserConfigError";
238
- }
239
- };
240
- function isPlainObject(v) {
241
- return typeof v === "object" && v !== null && !Array.isArray(v);
242
- }
243
- var RENAMED_KEYS = /* @__PURE__ */ new Map([["box.snapshot", "box.hostSnapshot"]]);
244
- var BRANCHES = (() => {
245
- const out = /* @__PURE__ */ new Map();
246
- for (const desc of KEY_REGISTRY) {
247
- const idx = desc.key.indexOf(".");
248
- if (idx < 0) {
249
- throw new Error(`KEY_REGISTRY entry ${desc.key} must use dot-path form (branch.leaf)`);
250
- }
251
- const branch = desc.key.slice(0, idx);
252
- const leaf = desc.key.slice(idx + 1);
253
- let entry = out.get(branch);
254
- if (!entry) {
255
- entry = { name: branch, leaves: /* @__PURE__ */ new Map() };
256
- out.set(branch, entry);
257
- }
258
- entry.leaves.set(leaf, desc);
259
- }
260
- return out;
261
- })();
262
- function coerceTypedValue(raw, desc, where) {
263
- if (raw === null) {
264
- throw new UserConfigError(`${where} must not be null (use \`agentbox config unset\` to clear)`);
265
- }
266
- switch (desc.type) {
267
- case "bool":
268
- if (typeof raw !== "boolean") {
269
- throw new UserConfigError(`${where} must be a boolean (got ${typeof raw})`);
270
- }
271
- return raw;
272
- case "string":
273
- if (typeof raw !== "string") {
274
- throw new UserConfigError(`${where} must be a string (got ${typeof raw})`);
275
- }
276
- if (raw.length === 0) {
277
- throw new UserConfigError(`${where} must not be empty`);
278
- }
279
- return raw;
280
- case "int":
281
- if (typeof raw !== "number" || !Number.isInteger(raw)) {
282
- throw new UserConfigError(`${where} must be an integer (got ${String(raw)})`);
283
- }
284
- return raw;
285
- case "enum":
286
- if (typeof raw !== "string" || !desc.enumValues.includes(raw)) {
287
- throw new UserConfigError(
288
- `${where} must be one of: ${desc.enumValues.join(", ")} (got ${String(raw)})`
289
- );
290
- }
291
- return raw;
292
- }
293
- }
294
- function parseUserConfig(text, where) {
295
- let doc;
296
- try {
297
- doc = parseYaml(text);
298
- } catch (err) {
299
- throw new UserConfigError(
300
- `${where}: yaml parse error: ${err instanceof Error ? err.message : String(err)}`
301
- );
302
- }
303
- if (doc === null || doc === void 0) return {};
304
- if (!isPlainObject(doc)) {
305
- throw new UserConfigError(`${where}: top-level must be a mapping`);
306
- }
307
- return parseUserConfigObject(doc, where);
308
- }
309
- function parseUserConfigObject(doc, where) {
310
- if (doc === null || doc === void 0) return {};
311
- if (!isPlainObject(doc)) {
312
- throw new UserConfigError(`${where}: must be a mapping`);
313
- }
314
- const out = {};
315
- for (const [branchName, branchRaw] of Object.entries(doc)) {
316
- const branchSpec = BRANCHES.get(branchName);
317
- if (!branchSpec) {
318
- throw new UserConfigError(
319
- `${where}: unknown config section "${branchName}" (known: ${[...BRANCHES.keys()].join(", ")})`
320
- );
321
- }
322
- if (branchRaw === null || branchRaw === void 0) continue;
323
- if (!isPlainObject(branchRaw)) {
324
- throw new UserConfigError(`${where}.${branchName}: must be a mapping`);
325
- }
326
- const branchOut = {};
327
- for (const [leafName, leafRaw] of Object.entries(branchRaw)) {
328
- const desc = branchSpec.leaves.get(leafName);
329
- if (!desc) {
330
- const renamedTo = RENAMED_KEYS.get(`${branchName}.${leafName}`);
331
- if (renamedTo) {
332
- throw new UserConfigError(
333
- `${where}.${branchName}.${leafName} was renamed to ${renamedTo} \u2014 update your config`
334
- );
335
- }
336
- throw new UserConfigError(
337
- `${where}.${branchName}: unknown key "${leafName}" (known: ${[...branchSpec.leaves.keys()].join(", ")})`
338
- );
339
- }
340
- if (leafRaw === void 0) continue;
341
- branchOut[leafName] = coerceTypedValue(leafRaw, desc, `${where}.${desc.key}`);
342
- }
343
- if (Object.keys(branchOut).length > 0) {
344
- out[branchName] = branchOut;
345
- }
346
- }
347
- return out;
348
- }
349
- function coerceFromString(key, raw) {
350
- const desc = lookupKeyOrThrow(key);
351
- switch (desc.type) {
352
- case "bool": {
353
- const v = raw.trim().toLowerCase();
354
- if (v === "true" || v === "yes" || v === "1" || v === "on") return true;
355
- if (v === "false" || v === "no" || v === "0" || v === "off") return false;
356
- throw new UserConfigError(`${key}: expected a boolean (true/false), got "${raw}"`);
357
- }
358
- case "string":
359
- if (raw.length === 0) throw new UserConfigError(`${key}: must not be empty`);
360
- return raw;
361
- case "int": {
362
- const n = Number(raw);
363
- if (!Number.isFinite(n) || !Number.isInteger(n)) {
364
- throw new UserConfigError(`${key}: expected an integer, got "${raw}"`);
365
- }
366
- return n;
367
- }
368
- case "enum":
369
- if (!desc.enumValues.includes(raw)) {
370
- throw new UserConfigError(
371
- `${key}: expected one of ${desc.enumValues.join(", ")}, got "${raw}"`
372
- );
373
- }
374
- return raw;
375
- }
376
- }
377
- function lookupKeyOrThrow(key) {
378
- const renamedTo = RENAMED_KEYS.get(key);
379
- if (renamedTo) {
380
- throw new UserConfigError(`${key} was renamed to ${renamedTo} \u2014 use ${renamedTo} instead`);
381
- }
382
- const idx = key.indexOf(".");
383
- if (idx < 0) {
384
- throw new UserConfigError(`unknown key "${key}" (must be in branch.leaf form)`);
385
- }
386
- const branch = BRANCHES.get(key.slice(0, idx));
387
- if (!branch) {
388
- throw new UserConfigError(
389
- `unknown config section "${key.slice(0, idx)}" (known: ${[...BRANCHES.keys()].join(", ")})`
390
- );
391
- }
392
- const desc = branch.leaves.get(key.slice(idx + 1));
393
- if (!desc) {
394
- throw new UserConfigError(
395
- `unknown key "${key}" (known in ${branch.name}: ${[...branch.leaves.keys()].join(", ")})`
396
- );
397
- }
398
- return desc;
399
- }
400
- var STATE_DIR = join(homedir(), ".agentbox");
401
- var GLOBAL_CONFIG_FILE = join(STATE_DIR, "config.yaml");
402
- var PROJECTS_DIR = join(STATE_DIR, "projects");
403
- var WORKSPACE_CONFIG_BASENAME = "agentbox.yaml";
404
- async function findProjectRoot(cwd) {
405
- const start = await canonicalize(cwd);
406
- let dir = start;
407
- for (let i = 0; i < 64; i++) {
408
- if (await fileExists(join(dir, WORKSPACE_CONFIG_BASENAME))) {
409
- return { root: dir, hasAgentboxYaml: true };
410
- }
411
- const parent = dirname(dir);
412
- if (parent === dir) break;
413
- dir = parent;
414
- }
415
- return { root: start, hasAgentboxYaml: false };
416
- }
417
- async function canonicalize(p) {
418
- const abs = resolve(p);
419
- try {
420
- return await realpath(abs);
421
- } catch {
422
- return abs;
423
- }
424
- }
425
- async function fileExists(p) {
426
- try {
427
- const st = await stat(p);
428
- return st.isFile();
429
- } catch {
430
- return false;
431
- }
432
- }
433
- function hashProjectPath(absPath) {
434
- const normalised = absPath.length > 1 && absPath.endsWith("/") ? absPath.slice(0, -1) : absPath;
435
- return createHash("sha1").update(normalised).digest("hex").slice(0, 16);
436
- }
437
- function sanitizeMnemonic(raw) {
438
- return raw.toLowerCase().replace(/-/g, "_").replace(/[^a-z0-9_]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "").slice(0, 32) || "unnamed";
439
- }
440
- function projectDirSegment(absPath) {
441
- return `${hashProjectPath(absPath)}-${sanitizeMnemonic(basename(absPath))}`;
442
- }
443
- function projectConfigDir(absPath) {
444
- return join(PROJECTS_DIR, projectDirSegment(absPath));
445
- }
446
- function projectConfigFile(absPath) {
447
- return join(projectConfigDir(absPath), "config.yaml");
448
- }
449
- function projectMetaFile(absPath) {
450
- return join(projectConfigDir(absPath), "meta.json");
451
- }
452
- function workspaceConfigFile(workspacePath) {
453
- return join(workspacePath, WORKSPACE_CONFIG_BASENAME);
454
- }
455
- async function configPathFor(scope, cwd) {
456
- if (scope === "global") return GLOBAL_CONFIG_FILE;
457
- const root = await findProjectRoot(cwd);
458
- if (scope === "project") return projectConfigFile(root.root);
459
- return workspaceConfigFile(root.root);
460
- }
461
- async function loadOptionalUserConfig(path) {
462
- let text;
463
- try {
464
- text = await readFile(path, "utf8");
465
- } catch (err) {
466
- if (err.code === "ENOENT") return {};
467
- throw err;
468
- }
469
- return parseUserConfig(text, path);
470
- }
471
- async function loadProjectAgentboxDefaults(workspacePath) {
472
- const path = workspaceConfigFile(workspacePath);
473
- let text;
474
- try {
475
- text = await readFile(path, "utf8");
476
- } catch (err) {
477
- if (err.code === "ENOENT") return {};
478
- throw err;
479
- }
480
- let doc;
481
- try {
482
- doc = parseYaml2(text);
483
- } catch {
484
- return {};
485
- }
486
- if (doc === null || doc === void 0 || typeof doc !== "object" || Array.isArray(doc)) {
487
- return {};
488
- }
489
- const defaults = doc["defaults"];
490
- if (defaults === void 0 || defaults === null) return {};
491
- return parseUserConfigObject(defaults, `${path} defaults`);
492
- }
493
- async function loadEffectiveConfig(cwd, opts = {}) {
494
- const projectRoot = await findProjectRoot(cwd);
495
- const projectPath = projectConfigFile(projectRoot.root);
496
- const workspacePath = projectRoot.hasAgentboxYaml ? workspaceConfigFile(projectRoot.root) : null;
497
- const [globalValues, projectValues, workspaceValues] = await Promise.all([
498
- loadOptionalUserConfig(GLOBAL_CONFIG_FILE),
499
- loadOptionalUserConfig(projectPath),
500
- workspacePath ? loadProjectAgentboxDefaults(projectRoot.root) : Promise.resolve({})
501
- ]);
502
- const cliValues = opts.cliOverrides ?? {};
503
- const { effective, sources } = mergeLayers({
504
- cli: cliValues,
505
- workspace: workspaceValues,
506
- project: projectValues,
507
- global: globalValues
508
- });
509
- return {
510
- effective,
511
- layers: {
512
- cli: { values: cliValues },
513
- workspace: { path: workspacePath, values: workspaceValues },
514
- project: { path: projectPath, values: projectValues },
515
- global: { path: GLOBAL_CONFIG_FILE, values: globalValues },
516
- defaults: BUILT_IN_DEFAULTS
517
- },
518
- sources,
519
- projectRoot: projectRoot.root,
520
- projectHash: hashProjectPath(projectRoot.root),
521
- hasAgentboxYaml: projectRoot.hasAgentboxYaml
522
- };
523
- }
524
- function mergeLayers(input) {
525
- const effective = JSON.parse(JSON.stringify(BUILT_IN_DEFAULTS));
526
- const sources = {};
527
- const layerOrder = [
528
- { source: "cli", values: input.cli },
529
- { source: "workspace", values: input.workspace },
530
- { source: "project", values: input.project },
531
- { source: "global", values: input.global }
532
- ];
533
- for (const desc of KEY_REGISTRY) {
534
- const idx = desc.key.indexOf(".");
535
- const branch = desc.key.slice(0, idx);
536
- const leaf = desc.key.slice(idx + 1);
537
- let chosen = null;
538
- for (const layer of layerOrder) {
539
- const v = readLeaf(layer.values, branch, leaf);
540
- if (v !== void 0) {
541
- chosen = { source: layer.source, value: v };
542
- break;
543
- }
544
- }
545
- if (chosen) {
546
- writeLeaf(effective, branch, leaf, chosen.value);
547
- sources[desc.key] = chosen.source;
548
- } else {
549
- sources[desc.key] = "default";
550
- }
551
- }
552
- return { effective, sources };
553
- }
554
- function readLeaf(obj, branch, leaf) {
555
- const b = obj[branch];
556
- if (b === void 0 || b === null || typeof b !== "object") return void 0;
557
- return b[leaf];
558
- }
559
- function writeLeaf(obj, branch, leaf, value) {
560
- const b = obj[branch];
561
- if (!b) return;
562
- b[leaf] = value;
563
- }
564
- async function setConfigValue(scope, key, value, cwd, opts = {}) {
565
- if (!lookupKey(key)) {
566
- throw new UserConfigError(`unknown key "${key}"`);
567
- }
568
- const coerced = opts.raw && typeof value === "string" ? coerceFromString(key, value) : value;
569
- const path = await configPathFor(scope, cwd);
570
- const current = await readExistingDoc(path);
571
- setLeaf(current, key, coerced);
572
- parseUserConfig(stringifyYaml(current), path);
573
- await atomicWriteYaml(path, current);
574
- if (scope === "project") {
575
- const root = (await findProjectRoot(cwd)).root;
576
- await touchProjectMeta(root);
577
- }
578
- return { path, coerced };
579
- }
580
- async function unsetConfigValue(scope, key, cwd) {
581
- if (!lookupKey(key)) {
582
- throw new UserConfigError(`unknown key "${key}"`);
583
- }
584
- const path = await configPathFor(scope, cwd);
585
- const current = await readExistingDoc(path);
586
- const existed = unsetLeaf(current, key);
587
- if (!existed) return { path, existed: false };
588
- await atomicWriteYaml(path, current);
589
- if (scope === "project") {
590
- const root = (await findProjectRoot(cwd)).root;
591
- await touchProjectMeta(root);
592
- }
593
- return { path, existed: true };
594
- }
595
- async function listProjectsConfigured() {
596
- let entries;
597
- try {
598
- entries = await readdir(PROJECTS_DIR);
599
- } catch (err) {
600
- if (err.code === "ENOENT") return [];
601
- throw err;
602
- }
603
- const out = [];
604
- for (const dirName of entries) {
605
- const m = /^([0-9a-f]{16})(?:-.+)?$/.exec(dirName);
606
- if (!m) continue;
607
- const hash = m[1];
608
- const meta = await readMeta(dirName);
609
- if (!meta) continue;
610
- const cfgPath = projectConfigFile(meta.originalPath);
611
- const hasConfig = await fileExists2(cfgPath);
612
- out.push({
613
- hash,
614
- dirName,
615
- originalPath: meta.originalPath,
616
- createdAt: meta.createdAt,
617
- lastSeenAt: meta.lastSeenAt,
618
- configPath: cfgPath,
619
- hasConfigFile: hasConfig
620
- });
621
- }
622
- out.sort((a, b) => a.originalPath.localeCompare(b.originalPath));
623
- return out;
624
- }
625
- async function pruneOrphanProjectConfigs(opts = {}) {
626
- const dryRun = opts.dryRun ?? false;
627
- const keep = new Set(opts.protectedPaths ?? []);
628
- const removed = [];
629
- for (const entry of await listProjectsConfigured()) {
630
- if (!isAbsolute(entry.originalPath) || keep.has(entry.originalPath)) continue;
631
- let missing = false;
632
- try {
633
- await stat2(entry.originalPath);
634
- } catch (err) {
635
- if (err.code === "ENOENT") missing = true;
636
- }
637
- if (!missing) continue;
638
- removed.push({ hash: entry.hash, originalPath: entry.originalPath });
639
- if (!dryRun) {
640
- try {
641
- await rm(join2(PROJECTS_DIR, entry.dirName), { recursive: true, force: true });
642
- } catch {
643
- }
644
- }
645
- }
646
- return { removed, dryRun };
647
- }
648
- var PROJECT_GC_COUNTER_FILE = join2(PROJECTS_DIR, ".gc.json");
649
- async function bumpProjectGcCounter() {
650
- let prior = 0;
651
- try {
652
- const parsed = JSON.parse(await readFile2(PROJECT_GC_COUNTER_FILE, "utf8"));
653
- if (typeof parsed.creates === "number" && Number.isFinite(parsed.creates)) {
654
- prior = parsed.creates;
655
- }
656
- } catch {
657
- }
658
- const next = prior + 1;
659
- await mkdir(PROJECTS_DIR, { recursive: true });
660
- const tmp = `${PROJECT_GC_COUNTER_FILE}.tmp-${process.pid.toString()}-${Date.now().toString(36)}`;
661
- await writeFile(tmp, JSON.stringify({ creates: next }) + "\n", { encoding: "utf8", mode: 420 });
662
- await rename(tmp, PROJECT_GC_COUNTER_FILE);
663
- return next;
664
- }
665
- async function readMeta(dirName) {
666
- const metaPath = `${PROJECTS_DIR}/${dirName}/meta.json`;
667
- try {
668
- const text = await readFile2(metaPath, "utf8");
669
- const parsed = JSON.parse(text);
670
- if (typeof parsed["originalPath"] !== "string") return null;
671
- return {
672
- originalPath: parsed["originalPath"],
673
- createdAt: typeof parsed["createdAt"] === "string" ? parsed["createdAt"] : null,
674
- lastSeenAt: typeof parsed["lastSeenAt"] === "string" ? parsed["lastSeenAt"] : null
675
- };
676
- } catch {
677
- return null;
678
- }
679
- }
680
- async function fileExists2(p) {
681
- try {
682
- const st = await stat2(p);
683
- return st.isFile();
684
- } catch {
685
- return false;
686
- }
687
- }
688
- async function readExistingDoc(path) {
689
- let text;
690
- try {
691
- text = await readFile2(path, "utf8");
692
- } catch (err) {
693
- if (err.code === "ENOENT") return {};
694
- throw err;
695
- }
696
- return parseUserConfig(text, path);
697
- }
698
- function setLeaf(doc, key, value) {
699
- const idx = key.indexOf(".");
700
- const branch = key.slice(0, idx);
701
- const leaf = key.slice(idx + 1);
702
- const root = doc;
703
- if (!root[branch] || typeof root[branch] !== "object") {
704
- root[branch] = {};
705
- }
706
- root[branch][leaf] = value;
707
- }
708
- function unsetLeaf(doc, key) {
709
- const idx = key.indexOf(".");
710
- const branch = key.slice(0, idx);
711
- const leaf = key.slice(idx + 1);
712
- const root = doc;
713
- const b = root[branch];
714
- if (!b || typeof b !== "object" || !(leaf in b)) return false;
715
- delete b[leaf];
716
- if (Object.keys(b).length === 0) {
717
- delete root[branch];
718
- }
719
- return true;
720
- }
721
- async function atomicWriteYaml(path, doc) {
722
- await mkdir(dirname2(path), { recursive: true });
723
- const text = Object.keys(doc).length === 0 ? "# managed by agentbox config \u2014 empty\n" : stringifyYaml(doc);
724
- const tmp = `${path}.tmp-${process.pid.toString()}-${Date.now().toString(36)}`;
725
- await writeFile(tmp, text, { encoding: "utf8", mode: 420 });
726
- await rename(tmp, path);
727
- }
728
- async function touchProjectMeta(absPath) {
729
- const dir = dirname2(projectMetaFile(absPath));
730
- await mkdir(dir, { recursive: true });
731
- const metaPath = projectMetaFile(absPath);
732
- let prior = {};
733
- try {
734
- prior = JSON.parse(await readFile2(metaPath, "utf8"));
735
- } catch {
736
- }
737
- const now = (/* @__PURE__ */ new Date()).toISOString();
738
- const next = {
739
- originalPath: absPath,
740
- hash: hashProjectPath(absPath),
741
- createdAt: prior.createdAt ?? now,
742
- lastSeenAt: now
743
- };
744
- const tmp = `${metaPath}.tmp-${process.pid.toString()}-${Date.now().toString(36)}`;
745
- await writeFile(tmp, JSON.stringify(next, null, 2) + "\n", { encoding: "utf8", mode: 420 });
746
- await rename(tmp, metaPath);
747
- }
748
-
749
- // ../../packages/sandbox-docker/dist/chunk-FTYSR4JQ.js
750
- import { execa as execa3 } from "execa";
751
- import { existsSync } from "fs";
752
- import { fileURLToPath } from "url";
753
- import { dirname as dirname3, resolve as resolve2 } from "path";
754
- import { mkdir as mkdir22, mkdtemp, readFile as readFile22, readdir as readdir2, rm as rm2, writeFile as writeFile2 } from "fs/promises";
755
- import { homedir as homedir22, tmpdir } from "os";
756
- import { basename as basename2, join as join22 } from "path";
757
- import { execa as execa4 } from "execa";
758
- async function dockerInfo() {
759
- const result = await execa("docker", ["info"], { reject: false });
760
- if (result.exitCode !== 0) {
761
- throw new Error(
762
- `docker info failed (exit ${String(result.exitCode)}). Is the Docker daemon running?
763
- ${String(result.stderr)}`
764
- );
765
- }
766
- }
767
- async function runBox(spec) {
768
- const args = [
769
- "run",
770
- "-d",
771
- "--name",
772
- spec.name,
773
- "--hostname",
774
- spec.name,
775
- "--cap-add=SYS_ADMIN",
776
- // dockerd inside the box (always-on, see launchDockerdDaemon) needs
777
- // NET_ADMIN to set up its bridge + iptables NAT for inner containers.
778
- // seccomp:unconfined is required because the default profile blocks
779
- // syscalls (notably keyctl, clone3 in some kernels) that nested containers
780
- // need. Both are scoped to the outer box's namespaces — inner containers
781
- // can't escape it. We still avoid --privileged for cloud portability.
782
- "--cap-add=NET_ADMIN",
783
- // /dev/fuse + SYS_ADMIN + apparmor:unconfined used to be required for the
784
- // outer /workspace FUSE overlay. That overlay is gone, but they're still
785
- // load-bearing for the *inner* dockerd's storage driver, which
786
- // agentbox-dockerd-start selects at runtime: SYS_ADMIN lets it `mount -t
787
- // overlay` for the preferred kernel-native overlay2 driver, and /dev/fuse
788
- // + SYS_ADMIN + apparmor:unconfined are needed for the fuse-overlayfs
789
- // fallback (used where overlay2's runtime probe fails).
790
- "--device=/dev/fuse",
791
- "--security-opt=apparmor:unconfined",
792
- "--security-opt=seccomp=unconfined",
793
- // cgroup v2 + DinD: with --cgroupns=host (the OrbStack default) the
794
- // outer container sees the host's read-only cgroup hierarchy at
795
- // /sys/fs/cgroup, so the inner dockerd can't `mkdir /sys/fs/cgroup/docker`
796
- // for its own slice and inner `docker run` fails with "read-only file
797
- // system". Private gives the box its own writable cgroup namespace; runc
798
- // creates the docker slice there and inner containers nest under it.
799
- "--cgroupns=private",
800
- // Make the host reachable from inside the container at the well-known DNS
801
- // name host.docker.internal. Docker Desktop / OrbStack ship this alias by
802
- // default; on Linux native Docker it requires this explicit flag (no-op
803
- // on the macOS engines). Boxes use it to reach the host relay process.
804
- "--add-host=host.docker.internal:host-gateway"
805
- ];
806
- const lim = spec.limits;
807
- if (lim) {
808
- if (lim.memoryBytes && lim.memoryBytes > 0) {
809
- args.push("--memory", String(Math.floor(lim.memoryBytes)));
810
- }
811
- if (lim.cpus && lim.cpus > 0) {
812
- args.push("--cpus", String(lim.cpus));
813
- }
814
- if (lim.pidsLimit && lim.pidsLimit > 0) {
815
- args.push("--pids-limit", String(Math.floor(lim.pidsLimit)));
816
- }
817
- if (lim.disk) {
818
- args.push("--storage-opt", `size=${lim.disk}`);
819
- }
820
- }
821
- for (const v of spec.extraVolumes ?? []) {
822
- args.push("-v", v);
823
- }
824
- for (const pm of spec.portMappings ?? []) {
825
- const host = pm.hostIp ? `${pm.hostIp}:${String(pm.hostPort)}` : String(pm.hostPort);
826
- args.push("-p", `${host}:${String(pm.containerPort)}`);
827
- }
828
- for (const [k, val] of Object.entries(spec.env ?? {})) {
829
- args.push("-e", `${k}=${val}`);
830
- }
831
- args.push(spec.image, "sleep", "infinity");
832
- const { stdout } = await execa("docker", args);
833
- return stdout.trim();
834
- }
835
- async function dockerStorageDriver() {
836
- const result = await execa("docker", ["info", "--format", "{{.Driver}}"], { reject: false });
837
- if (result.exitCode !== 0) return "";
838
- return (result.stdout ?? "").trim();
839
- }
840
- async function execInBox(container, cmd, opts = {}) {
841
- const args = ["exec"];
842
- if (opts.detach) args.push("-d");
843
- if (opts.user) args.push("--user", opts.user);
844
- args.push(container, ...cmd);
845
- const result = await execa("docker", args, {
846
- reject: false,
847
- ...opts.timeoutMs ? { timeout: opts.timeoutMs } : {}
848
- });
849
- return {
850
- exitCode: result.exitCode ?? -1,
851
- stdout: result.stdout ?? "",
852
- stderr: result.stderr ?? ""
853
- };
854
- }
855
- async function removeContainer(container) {
856
- await execa("docker", ["rm", "-f", container], { reject: false });
857
- }
858
- async function removeVolume(name) {
859
- await execa("docker", ["volume", "rm", name], { reject: false });
860
- }
861
- async function removeImage(ref, opts = {}) {
862
- const args = ["image", "rm"];
863
- if (opts.force !== false) args.push("-f");
864
- args.push(ref);
865
- const result = await execa("docker", args, { reject: false });
866
- return result.exitCode === 0;
867
- }
868
- async function containerExists(name) {
869
- const result = await execa("docker", ["container", "inspect", "--format", "{{.Id}}", name], {
870
- reject: false
871
- });
872
- return result.exitCode === 0;
873
- }
874
- async function volumeExists(name) {
875
- const result = await execa("docker", ["volume", "inspect", name], { reject: false });
876
- return result.exitCode === 0;
877
- }
878
- async function ensureVolume(name) {
879
- if (await volumeExists(name)) return;
880
- await execa("docker", ["volume", "create", name]);
881
- }
882
- async function removeNetwork(name) {
883
- await execa("docker", ["network", "rm", name], { reject: false });
884
- }
885
- async function pauseContainer(name) {
886
- await execa("docker", ["pause", name]);
887
- }
888
- async function unpauseContainer(name) {
889
- await execa("docker", ["unpause", name]);
890
- }
891
- async function stopContainer(name) {
892
- await execa("docker", ["stop", name]);
893
- }
894
- async function startContainer(name) {
895
- await execa("docker", ["start", name]);
896
- }
897
- async function inspectContainerStatus(name) {
898
- const result = await execa("docker", ["inspect", "--format", "{{.State.Status}}", name], {
899
- reject: false
900
- });
901
- if (result.exitCode !== 0) return "missing";
902
- const status = (result.stdout ?? "").trim();
903
- switch (status) {
904
- case "running":
905
- return "running";
906
- case "paused":
907
- return "paused";
908
- case "created":
909
- case "exited":
910
- case "dead":
911
- case "restarting":
912
- case "removing":
913
- return "stopped";
914
- default:
915
- return "missing";
916
- }
917
- }
918
- async function inspectContainer(name) {
919
- const result = await execa("docker", ["inspect", name], { reject: false });
920
- if (result.exitCode !== 0) return null;
921
- try {
922
- const parsed = JSON.parse(result.stdout ?? "null");
923
- return Array.isArray(parsed) ? parsed[0] ?? null : null;
924
- } catch {
925
- return null;
926
- }
927
- }
928
- async function inspectVolumeMountpoint(name) {
929
- const result = await execa("docker", ["volume", "inspect", "--format", "{{.Mountpoint}}", name], {
930
- reject: false
931
- });
932
- if (result.exitCode !== 0) return null;
933
- return (result.stdout ?? "").trim() || null;
934
- }
935
- var AGENTBOX_PREFIX = "agentbox-";
936
- async function listAgentboxContainers() {
937
- const result = await execa(
938
- "docker",
939
- ["ps", "-a", "--filter", `name=^${AGENTBOX_PREFIX}`, "--format", "{{.Names}}"],
940
- { reject: false }
941
- );
942
- if (result.exitCode !== 0) return [];
943
- return (result.stdout ?? "").split("\n").map((s) => s.trim()).filter((s) => s.startsWith(AGENTBOX_PREFIX));
944
- }
945
- async function publishedHostPort(container, containerPort) {
946
- const result = await execa("docker", ["port", container, `${String(containerPort)}/tcp`], {
947
- reject: false
948
- });
949
- if (result.exitCode !== 0) return null;
950
- const first = (result.stdout ?? "").split("\n")[0]?.trim();
951
- if (!first) return null;
952
- const m = /:(\d+)$/.exec(first);
953
- return m ? Number(m[1]) : null;
954
- }
955
- async function listAgentboxVolumes() {
956
- const result = await execa(
957
- "docker",
958
- ["volume", "ls", "--filter", `name=^${AGENTBOX_PREFIX}`, "--format", "{{.Name}}"],
959
- { reject: false }
960
- );
961
- if (result.exitCode !== 0) return [];
962
- return (result.stdout ?? "").split("\n").map((s) => s.trim()).filter((s) => s.startsWith(AGENTBOX_PREFIX));
963
- }
964
- var CONTAINER_EXPORT_MERGED = "/host-export";
965
- var cachedEngine = null;
966
- async function detectEngine() {
967
- if (cachedEngine !== null) return cachedEngine;
968
- const result = await execa2("docker", ["info", "--format", "{{.OperatingSystem}}"], {
969
- reject: false
970
- });
971
- const os = (result.stdout ?? "").trim().toLowerCase();
972
- if (os.includes("orbstack")) cachedEngine = "orbstack";
973
- else if (os.includes("docker desktop")) cachedEngine = "docker-desktop";
974
- else cachedEngine = "other";
975
- return cachedEngine;
976
- }
977
- function setEngineOverride(engine) {
978
- cachedEngine = engine;
979
- }
980
- var BOXES_ROOT = join3(homedir2(), ".agentbox", "boxes");
981
- function boxDirSegment(box) {
982
- const mnemonic = sanitizeMnemonic(box.name);
983
- const n = box.projectIndex;
984
- if (typeof n === "number" && Number.isFinite(n) && n > 0) {
985
- return `${box.id}-${String(n)}-${mnemonic}`;
986
- }
987
- return `${box.id}-${mnemonic}`;
988
- }
989
- function boxRunDirFor(box) {
990
- return join3(BOXES_ROOT, boxDirSegment(box));
991
- }
992
- function boxStatusPathFor(box) {
993
- return join3(boxRunDirFor(box), "status.json");
994
- }
995
- async function readBoxStatus(box) {
996
- try {
997
- const raw = await readFile3(boxStatusPathFor(box), "utf8");
998
- const parsed = JSON.parse(raw);
999
- if (parsed.schema !== 1) return null;
1000
- return parsed;
1001
- } catch {
1002
- return null;
1003
- }
1004
- }
1005
- function orbstackVolumePath(volume, ...sub) {
1006
- return join3(homedir2(), "OrbStack", "docker", "volumes", volume, ...sub);
1007
- }
1008
- async function getHostPaths(record) {
1009
- const boxDir = boxRunDirFor(record);
1010
- return {
1011
- boxDir,
1012
- mergedExport: join3(boxDir, "workspace")
1013
- };
1014
- }
1015
- async function hasContainerPath(container, path) {
1016
- const probe = await execInBox(container, ["test", "-d", path], { user: "root" });
1017
- return probe.exitCode === 0;
1018
- }
1019
- async function refreshExport(record, opts = {}) {
1020
- const paths = await getHostPaths(record);
1021
- const excludeNodeModules = !opts.includeNodeModules;
1022
- await mkdir2(paths.mergedExport, { recursive: true });
1023
- const bindAvailable = await hasContainerPath(record.container, CONTAINER_EXPORT_MERGED);
1024
- if (bindAvailable) {
1025
- const args = ["rsync", "-a", "--delete"];
1026
- if (excludeNodeModules) args.push("--exclude=node_modules");
1027
- args.push("/workspace/", `${CONTAINER_EXPORT_MERGED}/`);
1028
- const r = await execInBox(record.container, args, { user: "root" });
1029
- if (r.exitCode !== 0) {
1030
- throw new ExportError(`rsync into ${CONTAINER_EXPORT_MERGED} failed`, r.stdout, r.stderr);
1031
- }
1032
- return { hostPath: paths.mergedExport, copied: true, usedFallback: false };
1033
- }
1034
- const excludes = excludeNodeModules ? ["--exclude=node_modules"] : [];
1035
- const result = await execa2(
1036
- "docker",
1037
- ["exec", "--user", "root", record.container, "tar", "-cf", "-", ...excludes, "-C", "/workspace", "."],
1038
- { reject: false, encoding: "buffer" }
1039
- );
1040
- if (result.exitCode !== 0) {
1041
- throw new ExportError(
1042
- `tar from /workspace failed`,
1043
- "",
1044
- typeof result.stderr === "string" ? result.stderr : result.stderr.toString("utf8")
1045
- );
1046
- }
1047
- const extract = await execa2("tar", ["-xf", "-", "-C", paths.mergedExport], {
1048
- input: result.stdout,
1049
- reject: false
1050
- });
1051
- if (extract.exitCode !== 0) {
1052
- throw new ExportError("tar extract on host failed", extract.stdout, extract.stderr);
1053
- }
1054
- return { hostPath: paths.mergedExport, copied: true, usedFallback: true };
1055
- }
1056
- var DEFAULT_ENV_PATTERNS = [
1057
- ".env",
1058
- ".env.*",
1059
- ".envrc",
1060
- ".dev.vars",
1061
- "secrets.toml",
1062
- "local.settings.json",
1063
- "appsettings.*.json",
1064
- "agentbox.yaml"
1065
- ];
1066
- var ENV_PRUNE_DIRS = [
1067
- "node_modules",
1068
- ".git",
1069
- ".venv",
1070
- "venv",
1071
- "__pycache__",
1072
- "dist",
1073
- ".next",
1074
- "build"
1075
- ];
1076
- function buildEnvFindArgs(patterns) {
1077
- const nameGroup = (names) => {
1078
- const out = [];
1079
- names.forEach((n, i) => {
1080
- if (i > 0) out.push("-o");
1081
- out.push("-name", n);
1082
- });
1083
- return out;
1084
- };
1085
- return [
1086
- "find",
1087
- "/workspace",
1088
- "(",
1089
- "-type",
1090
- "d",
1091
- "(",
1092
- ...nameGroup(ENV_PRUNE_DIRS),
1093
- ")",
1094
- "-prune",
1095
- ")",
1096
- "-o",
1097
- "(",
1098
- "-type",
1099
- "f",
1100
- "(",
1101
- ...nameGroup(patterns),
1102
- ")",
1103
- "-printf",
1104
- "%P\\0",
1105
- ")"
1106
- ];
1107
- }
1108
- function buildHostEnvFindArgs(patterns) {
1109
- const nameGroup = (names) => {
1110
- const out = [];
1111
- names.forEach((n, i) => {
1112
- if (i > 0) out.push("-o");
1113
- out.push("-name", n);
1114
- });
1115
- return out;
1116
- };
1117
- return [
1118
- "find",
1119
- ".",
1120
- "(",
1121
- "-type",
1122
- "d",
1123
- "(",
1124
- ...nameGroup(ENV_PRUNE_DIRS),
1125
- ")",
1126
- "-prune",
1127
- ")",
1128
- "-o",
1129
- "(",
1130
- "-type",
1131
- "f",
1132
- "(",
1133
- ...nameGroup(patterns),
1134
- ")",
1135
- "-print0",
1136
- ")"
1137
- ];
1138
- }
1139
- async function copyHostEnvFilesToBox(opts) {
1140
- const log = opts.onLog ?? (() => {
1141
- });
1142
- const found = await execa2("find", buildHostEnvFindArgs(opts.patterns).slice(1), {
1143
- cwd: opts.workspaceDir,
1144
- reject: false
1145
- });
1146
- if (found.exitCode !== 0) {
1147
- log(`warning: env-file scan failed: ${String(found.stderr).slice(0, 300)}`);
1148
- return { copied: 0 };
1149
- }
1150
- const list = String(found.stdout).split("\0").filter((p) => p.length > 0);
1151
- if (list.length === 0) return { copied: 0 };
1152
- const packed = await execa2("tar", ["-C", opts.workspaceDir, "--null", "-T", "-", "-cf", "-"], {
1153
- input: list.join("\0"),
1154
- encoding: "buffer",
1155
- reject: false
1156
- });
1157
- if (packed.exitCode !== 0) {
1158
- log(`warning: env-file tar pack failed: ${String(packed.stderr).slice(0, 300)}`);
1159
- return { copied: 0 };
1160
- }
1161
- const extract = await execa2(
1162
- "docker",
1163
- ["exec", "-i", "--user", "1000:1000", opts.container, "tar", "-xf", "-", "-C", "/workspace"],
1164
- { input: packed.stdout, reject: false }
1165
- );
1166
- if (extract.exitCode !== 0) {
1167
- log(`warning: env-file copy into box failed: ${String(extract.stderr).slice(0, 300)}`);
1168
- return { copied: 0 };
1169
- }
1170
- return { copied: list.length };
1171
- }
1172
- async function scanHostEnvFiles(workspaceDir, patterns) {
1173
- if (patterns.length === 0) return [];
1174
- const found = await execa2("find", buildHostEnvFindArgs(patterns).slice(1), {
1175
- cwd: workspaceDir,
1176
- reject: false
1177
- });
1178
- if (found.exitCode !== 0) return [];
1179
- return String(found.stdout).split("\0").map((p) => p.replace(/^\.\//, "")).filter((p) => p.length > 0);
1180
- }
1181
- async function copyHostFilesToBox(opts) {
1182
- const log = opts.onLog ?? (() => {
1183
- });
1184
- const list = opts.files.map((p) => p.replace(/^\.\//, "")).filter((p) => p.length > 0);
1185
- if (list.length === 0) return { copied: 0 };
1186
- const packed = await execa2("tar", ["-C", opts.workspaceDir, "--null", "-T", "-", "-cf", "-"], {
1187
- input: list.join("\0"),
1188
- encoding: "buffer",
1189
- reject: false
1190
- });
1191
- if (packed.exitCode !== 0) {
1192
- log(`warning: env-file tar pack failed: ${String(packed.stderr).slice(0, 300)}`);
1193
- return { copied: 0 };
1194
- }
1195
- const extract = await execa2(
1196
- "docker",
1197
- ["exec", "-i", "--user", "1000:1000", opts.container, "tar", "-xf", "-", "-C", "/workspace"],
1198
- { input: packed.stdout, reject: false }
1199
- );
1200
- if (extract.exitCode !== 0) {
1201
- log(`warning: env-file copy into box failed: ${String(extract.stderr).slice(0, 300)}`);
1202
- return { copied: 0 };
1203
- }
1204
- return { copied: list.length };
1205
- }
1206
- function parseItemizedChanges(stdout) {
1207
- return stdout.split("\n").map((l) => l.trimEnd()).filter((l) => l.length > 0).filter((l) => {
1208
- const code = l[0];
1209
- const kind = l[1];
1210
- return (code === ">" || code === "<" || code === "c" || code === "*") && kind !== "d";
1211
- });
1212
- }
1213
- async function pullToHost(record, opts = {}) {
1214
- const paths = await getHostPaths(record);
1215
- let scratchDir;
1216
- if (opts.noRefresh) {
1217
- scratchDir = paths.mergedExport;
1218
- await mkdir2(scratchDir, { recursive: true });
1219
- } else {
1220
- const refreshed = await refreshExport(record, {
1221
- includeNodeModules: opts.includeNodeModules
1222
- });
1223
- scratchDir = refreshed.hostPath;
1224
- }
1225
- const segments = [];
1226
- let usedGitignore = false;
1227
- if (opts.respectGitignore !== false) {
1228
- const isGit = await execInBox(
1229
- record.container,
1230
- ["git", "-C", "/workspace", "rev-parse", "--is-inside-work-tree"],
1231
- { user: "root" }
1232
- );
1233
- if (isGit.exitCode === 0 && isGit.stdout.trim() === "true") {
1234
- const ls = await execInBox(
1235
- record.container,
1236
- ["git", "-C", "/workspace", "ls-files", "-z", "--cached", "--others", "--exclude-standard"],
1237
- { user: "root" }
1238
- );
1239
- if (ls.exitCode !== 0) {
1240
- throw new ExportError("git ls-files in box failed", ls.stdout, ls.stderr);
1241
- }
1242
- const tracked = ls.stdout.replace(/\0$/, "");
1243
- if (tracked.length > 0) segments.push(tracked);
1244
- usedGitignore = true;
1245
- }
1246
- }
1247
- if (opts.envPatterns && opts.envPatterns.length > 0) {
1248
- const found = await execInBox(
1249
- record.container,
1250
- buildEnvFindArgs(opts.envPatterns),
1251
- { user: "root" }
1252
- );
1253
- if (found.exitCode !== 0) {
1254
- throw new ExportError("find env files in box failed", found.stdout, found.stderr);
1255
- }
1256
- const envFiles = found.stdout.replace(/\0$/, "");
1257
- if (envFiles.length > 0) segments.push(envFiles);
1258
- }
1259
- const fileList = segments.length > 0 ? Array.from(new Set(segments.join("\0").split("\0"))).join("\0") : null;
1260
- const baseArgs = ["-a", "--checksum"];
1261
- if (fileList === null) {
1262
- baseArgs.push("--exclude=.git");
1263
- if (!opts.includeNodeModules) baseArgs.push("--exclude=node_modules");
1264
- } else {
1265
- baseArgs.push("--files-from=-", "--from0");
1266
- }
1267
- const src = `${scratchDir}/`;
1268
- const dst = `${record.workspacePath}/`;
1269
- const dry = await execa2("rsync", [...baseArgs, "--dry-run", "-i", src, dst], {
1270
- reject: false,
1271
- input: fileList !== null ? fileList : void 0
1272
- });
1273
- if (dry.exitCode !== 0) {
1274
- throw new ExportError("rsync dry-run failed", dry.stdout, dry.stderr);
1275
- }
1276
- const changes = parseItemizedChanges(dry.stdout);
1277
- if (opts.dryRun) {
1278
- return { hostPath: record.workspacePath, changes, applied: false, usedGitignore };
1279
- }
1280
- const real = await execa2("rsync", [...baseArgs, src, dst], {
1281
- reject: false,
1282
- input: fileList !== null ? fileList : void 0
1283
- });
1284
- if (real.exitCode !== 0) {
1285
- throw new ExportError(`rsync into ${record.workspacePath} failed`, real.stdout, real.stderr);
1286
- }
1287
- return { hostPath: record.workspacePath, changes, applied: true, usedGitignore };
1288
- }
1289
- async function openInFinder(record, opts) {
1290
- const engine = await detectEngine();
1291
- let hostPath;
1292
- let copied = false;
1293
- let usedFallback = false;
1294
- if (opts.noRefresh) {
1295
- const paths = await getHostPaths(record);
1296
- hostPath = paths.mergedExport;
1297
- await mkdir2(hostPath, { recursive: true });
1298
- } else {
1299
- const refreshed = await refreshExport(record, opts);
1300
- hostPath = refreshed.hostPath;
1301
- copied = refreshed.copied;
1302
- usedFallback = refreshed.usedFallback;
1303
- }
1304
- if (!opts.noOpen) {
1305
- const opened = await execa2("open", [hostPath], { reject: false });
1306
- if (opened.exitCode !== 0) {
1307
- throw new ExportError(`open ${hostPath} failed`, opened.stdout, opened.stderr);
1308
- }
1309
- }
1310
- return { hostPath, copied, usedFallback, engine };
1311
- }
1312
- var ExportError = class extends Error {
1313
- constructor(message, stdout, stderr) {
1314
- super(`${message}${stderr ? `: ${stderr.trim()}` : ""}`);
1315
- this.stdout = stdout;
1316
- this.stderr = stderr;
1317
- this.name = "ExportError";
1318
- }
1319
- stdout;
1320
- stderr;
1321
- };
1322
- var DEFAULT_BOX_IMAGE = "agentbox/box:dev";
1323
- var here = dirname3(fileURLToPath(import.meta.url));
1324
- function resolveDockerBuild() {
1325
- const override = process.env.AGENTBOX_DOCKER_CONTEXT;
1326
- if (override && existsSync(resolve2(override, "Dockerfile.box"))) {
1327
- return { dockerfile: resolve2(override, "Dockerfile.box"), context: override };
1328
- }
1329
- const staged = resolve2(here, "..", "runtime", "docker");
1330
- if (existsSync(resolve2(staged, "Dockerfile.box"))) {
1331
- return { dockerfile: resolve2(staged, "Dockerfile.box"), context: staged };
1332
- }
1333
- const packageRoot = resolve2(here, "..");
1334
- return {
1335
- dockerfile: resolve2(packageRoot, "Dockerfile.box"),
1336
- context: resolve2(packageRoot, "..", "..")
1337
- };
1338
- }
1339
- var { dockerfile: DOCKERFILE_PATH_RESOLVED, context: BUILD_CONTEXT_DIR_RESOLVED } = resolveDockerBuild();
1340
- var DOCKERFILE_PATH = DOCKERFILE_PATH_RESOLVED;
1341
- var BUILD_CONTEXT_DIR = BUILD_CONTEXT_DIR_RESOLVED;
1342
- async function imageExists(ref) {
1343
- const result = await execa3("docker", ["image", "inspect", ref], { reject: false });
1344
- return result.exitCode === 0;
1345
- }
1346
- async function buildImage(opts = {}) {
1347
- const ref = opts.ref ?? DEFAULT_BOX_IMAGE;
1348
- const dockerfile = opts.dockerfile ?? DOCKERFILE_PATH;
1349
- const contextDir = opts.contextDir ?? BUILD_CONTEXT_DIR;
1350
- const subprocess = execa3("docker", ["build", "-t", ref, "-f", dockerfile, contextDir], {
1351
- stderr: "pipe",
1352
- stdout: "pipe"
1353
- });
1354
- if (opts.onProgress) {
1355
- const forward = (chunk) => {
1356
- const text = typeof chunk === "string" ? chunk : chunk.toString("utf8");
1357
- for (const line of text.split(/\r?\n/)) {
1358
- if (line.length > 0) opts.onProgress?.(line);
1359
- }
1360
- };
1361
- subprocess.stdout?.on("data", forward);
1362
- subprocess.stderr?.on("data", forward);
1363
- }
1364
- await subprocess;
1365
- return ref;
1366
- }
1367
- async function ensureImage(ref = DEFAULT_BOX_IMAGE, opts = {}) {
1368
- if (await imageExists(ref)) {
1369
- return { ref, built: false };
1370
- }
1371
- await buildImage({
1372
- ref,
1373
- dockerfile: opts.dockerfile,
1374
- contextDir: opts.contextDir,
1375
- onProgress: opts.onProgress
1376
- });
1377
- return { ref, built: true };
1378
- }
1379
- var CHECKPOINTS_ROOT = join22(homedir22(), ".agentbox", "checkpoints");
1380
- var CHECKPOINT_IMAGE_PREFIX = "agentbox-ckpt-";
1381
- function checkpointImageTag(projectRoot, name) {
1382
- const mnemonic = sanitizeMnemonic(basename2(projectRoot));
1383
- return `${CHECKPOINT_IMAGE_PREFIX}${hashProjectPath(projectRoot)}_${mnemonic}:${name}`;
1384
- }
1385
- function projectCheckpointsDir(projectRoot) {
1386
- return join22(CHECKPOINTS_ROOT, projectDirSegment(projectRoot));
1387
- }
1388
- function checkpointDir(projectRoot, name) {
1389
- return join22(projectCheckpointsDir(projectRoot), name);
1390
- }
1391
- async function readManifest(dir) {
1392
- try {
1393
- const raw = await readFile22(join22(dir, "manifest.json"), "utf8");
1394
- const m = JSON.parse(raw);
1395
- if (m.schema !== 2) return null;
1396
- return m;
1397
- } catch {
1398
- return null;
1399
- }
1400
- }
1401
- async function listCheckpoints(projectRoot) {
1402
- const root = projectCheckpointsDir(projectRoot);
1403
- let entries;
1404
- try {
1405
- entries = (await readdir2(root, { withFileTypes: true })).filter((e) => e.isDirectory()).map((e) => e.name);
1406
- } catch {
1407
- return [];
1408
- }
1409
- const out = [];
1410
- for (const name of entries) {
1411
- const dir = join22(root, name);
1412
- const manifest = await readManifest(dir);
1413
- if (manifest) out.push({ name, dir, manifest });
1414
- }
1415
- out.sort((a, b) => a.manifest.createdAt.localeCompare(b.manifest.createdAt));
1416
- return out;
1417
- }
1418
- async function resolveCheckpoint(projectRoot, ref) {
1419
- const dir = checkpointDir(projectRoot, ref);
1420
- const manifest = await readManifest(dir);
1421
- if (!manifest) return null;
1422
- return { name: ref, dir, manifest };
1423
- }
1424
- async function listAllCheckpointImages() {
1425
- let projectDirs;
1426
- try {
1427
- projectDirs = (await readdir2(CHECKPOINTS_ROOT, { withFileTypes: true })).filter((e) => e.isDirectory()).map((e) => e.name);
1428
- } catch {
1429
- return [];
1430
- }
1431
- const out = /* @__PURE__ */ new Set();
1432
- for (const proj of projectDirs) {
1433
- const projPath = join22(CHECKPOINTS_ROOT, proj);
1434
- let names;
1435
- try {
1436
- names = (await readdir2(projPath, { withFileTypes: true })).filter((e) => e.isDirectory()).map((e) => e.name);
1437
- } catch {
1438
- continue;
1439
- }
1440
- for (const name of names) {
1441
- const manifest = await readManifest(join22(projPath, name));
1442
- if (manifest) out.add(manifest.image);
1443
- }
1444
- }
1445
- return Array.from(out);
1446
- }
1447
- async function removeCheckpoint(projectRoot, ref) {
1448
- const dir = checkpointDir(projectRoot, ref);
1449
- const manifest = await readManifest(dir);
1450
- if (!manifest) return false;
1451
- await rm2(dir, { recursive: true, force: true });
1452
- await removeImage(manifest.image, { force: true });
1453
- return true;
1454
- }
1455
- function computeNextCheckpointName(existingNames, boxName) {
1456
- const re = new RegExp(`^${boxName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}-(\\d+)$`);
1457
- let max = 0;
1458
- for (const n of existingNames) {
1459
- const m = re.exec(n);
1460
- if (m) max = Math.max(max, Number(m[1]));
1461
- }
1462
- return `${boxName}-${String(max + 1)}`;
1463
- }
1464
- async function nextCheckpointName(projectRoot, boxName) {
1465
- const existing = await listCheckpoints(projectRoot);
1466
- return computeNextCheckpointName(
1467
- existing.map((c) => c.name),
1468
- boxName
1469
- );
1470
- }
1471
- function chainDepth(box) {
1472
- return box.checkpointSource?.chain.length ?? 0;
1473
- }
1474
- async function runCleanup(container, log) {
1475
- const r = await execInBox(container, ["/usr/local/bin/agentbox-checkpoint-cleanup"], {
1476
- user: "root"
1477
- });
1478
- if (r.exitCode !== 0) {
1479
- log(`warning: checkpoint cleanup exited ${String(r.exitCode)}: ${r.stderr.slice(0, 200)}`);
1480
- }
1481
- }
1482
- async function inspectImageConfig(imageRef) {
1483
- const r = await execa4("docker", ["image", "inspect", imageRef], { reject: false });
1484
- if (r.exitCode !== 0) {
1485
- throw new CheckpointError(`docker image inspect ${imageRef} failed`, r.stdout, r.stderr);
1486
- }
1487
- const parsed = JSON.parse(r.stdout);
1488
- if (!Array.isArray(parsed) || parsed.length === 0 || !parsed[0]?.Config) {
1489
- throw new CheckpointError(`unexpected docker image inspect shape for ${imageRef}`, r.stdout, "");
1490
- }
1491
- return parsed[0].Config;
1492
- }
1493
- var RUNTIME_ENV_BLOCKLIST = /* @__PURE__ */ new Set([
1494
- "AGENTBOX",
1495
- "AGENTBOX_BOX_ID",
1496
- "AGENTBOX_BOX_NAME",
1497
- "AGENTBOX_HOST_WORKSPACE",
1498
- "AGENTBOX_PROJECT_ROOT",
1499
- "AGENTBOX_PROJECT_INDEX",
1500
- "AGENTBOX_RELAY_URL",
1501
- "AGENTBOX_RELAY_TOKEN",
1502
- "AGENTBOX_VNC_PASSWORD",
1503
- "CLAUDE_EFFORT",
1504
- "CLAUDE_CODE_OAUTH_TOKEN",
1505
- "ANTHROPIC_API_KEY",
1506
- "ANTHROPIC_MODEL"
1507
- ]);
1508
- function renderConfigDirectives(cfg) {
1509
- const lines = [];
1510
- for (const kv of cfg.Env ?? []) {
1511
- const eq = kv.indexOf("=");
1512
- if (eq <= 0) continue;
1513
- const k = kv.slice(0, eq);
1514
- if (RUNTIME_ENV_BLOCKLIST.has(k)) continue;
1515
- const v = kv.slice(eq + 1);
1516
- lines.push(`ENV ${k}=${dockerfileQuote(v)}`);
1517
- }
1518
- if (cfg.WorkingDir) lines.push(`WORKDIR ${cfg.WorkingDir}`);
1519
- if (cfg.User) lines.push(`USER ${cfg.User}`);
1520
- for (const p of Object.keys(cfg.ExposedPorts ?? {})) lines.push(`EXPOSE ${p.replace("/tcp", "")}`);
1521
- if (cfg.Entrypoint && cfg.Entrypoint.length > 0) {
1522
- lines.push(`ENTRYPOINT ${JSON.stringify(cfg.Entrypoint)}`);
1523
- }
1524
- if (cfg.Cmd && cfg.Cmd.length > 0) {
1525
- lines.push(`CMD ${JSON.stringify(cfg.Cmd)}`);
1526
- }
1527
- return lines;
1528
- }
1529
- function dockerfileQuote(v) {
1530
- if (/^[A-Za-z0-9._/:+@,=-]+$/.test(v)) return v;
1531
- return `"${v.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
1532
- }
1533
- async function createCheckpoint(opts) {
1534
- const log = opts.onLog ?? (() => {
1535
- });
1536
- const { box } = opts;
1537
- const type = opts.merged === true || chainDepth(box) >= opts.maxLayers ? "flattened" : "layered";
1538
- const name = opts.name ?? await nextCheckpointName(opts.projectRoot, box.name);
1539
- const dir = checkpointDir(opts.projectRoot, name);
1540
- const existing = await readManifest(dir);
1541
- if (existing) {
1542
- if (opts.replace) {
1543
- log(`replacing existing checkpoint ${name} (created ${existing.createdAt})`);
1544
- await removeCheckpoint(opts.projectRoot, name);
1545
- } else {
1546
- throw new CheckpointError(
1547
- `checkpoint ${name} already exists (created ${existing.createdAt}; rm it or pass --replace to recapture)`,
1548
- "",
1549
- ""
1550
- );
1551
- }
1552
- }
1553
- const tag = checkpointImageTag(opts.projectRoot, name);
1554
- await mkdir22(dir, { recursive: true });
1555
- log(`running pre-commit cleanup in ${box.container}`);
1556
- await runCleanup(box.container, log);
1557
- if (type === "layered") {
1558
- log(`docker commit ${box.container} -> ${tag} (layered)`);
1559
- const r = await execa4("docker", ["commit", box.container, tag], { reject: false });
1560
- if (r.exitCode !== 0) {
1561
- throw new CheckpointError(`docker commit failed for ${box.container}`, r.stdout, r.stderr);
1562
- }
1563
- } else {
1564
- log(`docker commit ${box.container} -> <intermediate> (flattened path)`);
1565
- const intermediate = `${tag}-intermediate`;
1566
- const commit = await execa4("docker", ["commit", box.container, intermediate], {
1567
- reject: false
1568
- });
1569
- if (commit.exitCode !== 0) {
1570
- throw new CheckpointError(`docker commit (intermediate) failed`, commit.stdout, commit.stderr);
1571
- }
1572
- try {
1573
- await flattenImage(intermediate, tag, log);
1574
- } finally {
1575
- await removeImage(intermediate, { force: true });
1576
- }
1577
- }
1578
- const base = (box.gitWorktrees ?? []).some((w) => w.kind === "root") ? "worktree" : "workspace";
1579
- const manifest = {
1580
- schema: 2,
1581
- name,
1582
- type,
1583
- image: tag,
1584
- // Layered carries lineage forward; flattened is self-contained.
1585
- parents: type === "layered" ? box.checkpointSource?.chain ?? [] : [],
1586
- base,
1587
- sourceBoxId: box.id,
1588
- sourceBoxName: box.name,
1589
- worktrees: box.gitWorktrees,
1590
- createdAt: (/* @__PURE__ */ new Date()).toISOString()
1591
- };
1592
- await writeFile2(join22(dir, "manifest.json"), JSON.stringify(manifest, null, 2) + "\n", "utf8");
1593
- if (opts.setDefault) {
1594
- await setConfigValue("project", "box.defaultCheckpoint", name, opts.projectRoot);
1595
- log(`set project default checkpoint -> ${name}`);
1596
- }
1597
- return { name, dir, manifest };
1598
- }
1599
- async function flattenImage(sourceTag, destTag, log) {
1600
- const tmpName = `agentbox-flatten-${Date.now().toString(36)}`;
1601
- const create = await execa4(
1602
- "docker",
1603
- ["create", "--name", tmpName, sourceTag, "sleep", "0"],
1604
- { reject: false }
1605
- );
1606
- if (create.exitCode !== 0) {
1607
- throw new CheckpointError(`docker create for flatten failed`, create.stdout, create.stderr);
1608
- }
1609
- const scratch = await mkdtemp(join22(tmpdir(), "agentbox-flatten-"));
1610
- try {
1611
- const rootfsPath = join22(scratch, "rootfs.tar");
1612
- log(`exporting rootfs of ${sourceTag} to ${rootfsPath}`);
1613
- const exp = await execa4("docker", ["export", "-o", rootfsPath, tmpName], { reject: false });
1614
- if (exp.exitCode !== 0) {
1615
- throw new CheckpointError(`docker export failed`, exp.stdout, exp.stderr);
1616
- }
1617
- const cfg = await inspectImageConfig(sourceTag);
1618
- const lines = [
1619
- "FROM scratch",
1620
- // ADD untars during build (Docker's documented behavior for local tars).
1621
- "ADD rootfs.tar /",
1622
- ...renderConfigDirectives(cfg)
1623
- ];
1624
- await writeFile2(join22(scratch, "Dockerfile"), lines.join("\n") + "\n", "utf8");
1625
- log(`building flattened ${destTag} from rootfs.tar (FROM scratch)`);
1626
- const build = await execa4(
1627
- "docker",
1628
- ["build", "-t", destTag, "-f", join22(scratch, "Dockerfile"), scratch],
1629
- { reject: false }
1630
- );
1631
- if (build.exitCode !== 0) {
1632
- throw new CheckpointError(`flatten docker build failed`, build.stdout, build.stderr);
1633
- }
1634
- } finally {
1635
- await execa4("docker", ["rm", "-f", tmpName], { reject: false });
1636
- await rm2(scratch, { recursive: true, force: true });
1637
- }
1638
- }
1639
- var CheckpointError = class extends Error {
1640
- constructor(message, stdout, stderr) {
1641
- super(`${message}${stderr ? `: ${stderr.trim()}` : ""}`);
1642
- this.stdout = stdout;
1643
- this.stderr = stderr;
1644
- this.name = "CheckpointError";
1645
- }
1646
- stdout;
1647
- stderr;
1648
- };
1649
-
1650
- export {
1651
- KEY_REGISTRY,
1652
- lookupKey,
1653
- UserConfigError,
1654
- findProjectRoot,
1655
- sanitizeMnemonic,
1656
- configPathFor,
1657
- loadEffectiveConfig,
1658
- setConfigValue,
1659
- unsetConfigValue,
1660
- listProjectsConfigured,
1661
- pruneOrphanProjectConfigs,
1662
- bumpProjectGcCounter,
1663
- dockerInfo,
1664
- runBox,
1665
- dockerStorageDriver,
1666
- execInBox,
1667
- removeContainer,
1668
- removeVolume,
1669
- removeImage,
1670
- containerExists,
1671
- volumeExists,
1672
- ensureVolume,
1673
- removeNetwork,
1674
- pauseContainer,
1675
- unpauseContainer,
1676
- stopContainer,
1677
- startContainer,
1678
- inspectContainerStatus,
1679
- inspectContainer,
1680
- inspectVolumeMountpoint,
1681
- listAgentboxContainers,
1682
- publishedHostPort,
1683
- listAgentboxVolumes,
1684
- CONTAINER_EXPORT_MERGED,
1685
- detectEngine,
1686
- setEngineOverride,
1687
- BOXES_ROOT,
1688
- boxRunDirFor,
1689
- readBoxStatus,
1690
- orbstackVolumePath,
1691
- getHostPaths,
1692
- refreshExport,
1693
- DEFAULT_ENV_PATTERNS,
1694
- copyHostEnvFilesToBox,
1695
- scanHostEnvFiles,
1696
- copyHostFilesToBox,
1697
- pullToHost,
1698
- openInFinder,
1699
- DEFAULT_BOX_IMAGE,
1700
- ensureImage,
1701
- CHECKPOINT_IMAGE_PREFIX,
1702
- checkpointImageTag,
1703
- listCheckpoints,
1704
- resolveCheckpoint,
1705
- listAllCheckpointImages,
1706
- removeCheckpoint,
1707
- createCheckpoint
1708
- };
1709
- //# sourceMappingURL=chunk-HHMWQNLF.js.map