@madarco/agentbox 0.13.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +65 -0
- package/README.md +11 -8
- package/dist/{_cloud-attach-HJC672UR.js → _cloud-attach-GUBB5RH2.js} +4 -4
- package/dist/{chunk-R5XIDQFR.js → chunk-BKU34KYY.js} +170 -6
- package/dist/chunk-BKU34KYY.js.map +1 -0
- package/dist/{chunk-QYRK5H6Q.js → chunk-BYCLD6D6.js} +17 -9
- package/dist/chunk-BYCLD6D6.js.map +1 -0
- package/dist/chunk-LDMYHWUS.js +346 -0
- package/dist/chunk-LDMYHWUS.js.map +1 -0
- package/dist/{chunk-2LF5YILI.js → chunk-RSKG7AFU.js} +80 -6
- package/dist/chunk-RSKG7AFU.js.map +1 -0
- package/dist/{chunk-4NQXNQ53.js → chunk-TBSIJVSN.js} +149 -47
- package/dist/chunk-TBSIJVSN.js.map +1 -0
- package/dist/{chunk-B4QG2MCW.js → chunk-TCS5HXJX.js} +381 -174
- package/dist/chunk-TCS5HXJX.js.map +1 -0
- package/dist/{chunk-ECLLV5JH.js → chunk-VATTS2MR.js} +156 -5
- package/dist/chunk-VATTS2MR.js.map +1 -0
- package/dist/{chunk-SNTHHWKY.js → chunk-XKH7NTT7.js} +80 -22
- package/dist/chunk-XKH7NTT7.js.map +1 -0
- package/dist/dist-34RKQ74M.js +662 -0
- package/dist/dist-34RKQ74M.js.map +1 -0
- package/dist/{dist-OPIBZ7XM.js → dist-3IMQNTTV.js} +14 -69
- package/dist/dist-3IMQNTTV.js.map +1 -0
- package/dist/{dist-OG6NW6SM.js → dist-4DPOL5A7.js} +5 -3
- package/dist/{dist-JAN5VABY.js → dist-57M6ZA7H.js} +25 -177
- package/dist/dist-57M6ZA7H.js.map +1 -0
- package/dist/{dist-7KVUIKJX.js → dist-J2IHD5T7.js} +37 -226
- package/dist/dist-J2IHD5T7.js.map +1 -0
- package/dist/index.js +1376 -1029
- package/dist/index.js.map +1 -1
- package/dist/{prepared-state-MQHD3M5F-KE4DT3GX.js → prepared-state-MQHD3M5F-Q27AZU53.js} +2 -2
- package/package.json +8 -6
- package/runtime/docker/Dockerfile.box +21 -26
- package/runtime/docker/apps/cli/share/agentbox-setup/SKILL.md +37 -1
- package/runtime/docker/packages/ctl/dist/bin.cjs +40 -16
- package/runtime/docker/packages/sandbox-docker/scripts/agentbox-vnc-start +17 -6
- package/runtime/docker/packages/sandbox-docker/scripts/chromium-resolver +57 -0
- package/runtime/docker/packages/sandbox-docker/scripts/claude-managed-settings.json +2 -1
- package/runtime/e2b/agentbox-checkpoint-cleanup +52 -0
- package/runtime/e2b/agentbox-codex-hooks.json +68 -0
- package/runtime/e2b/agentbox-open +28 -0
- package/runtime/e2b/agentbox-setup-skill.md +233 -0
- package/runtime/e2b/agentbox-vnc-start +102 -0
- package/runtime/e2b/attach-helper.cjs +167 -0
- package/runtime/e2b/claude-managed-settings.json +116 -0
- package/runtime/e2b/ctl.cjs +23864 -0
- package/runtime/e2b/custom-system-CLAUDE.md +46 -0
- package/runtime/e2b/gh-shim +344 -0
- package/runtime/e2b/git-shim +131 -0
- package/runtime/e2b/scripts/build-template.sh +295 -0
- package/runtime/hetzner/agentbox-setup-skill.md +37 -1
- package/runtime/hetzner/agentbox-vnc-start +17 -6
- package/runtime/hetzner/claude-managed-settings.json +2 -1
- package/runtime/hetzner/ctl.cjs +40 -16
- package/runtime/relay/bin.cjs +297 -228
- package/runtime/vercel/agentbox-setup-skill.md +37 -1
- package/runtime/vercel/agentbox-vnc-start +17 -6
- package/runtime/vercel/claude-managed-settings.json +2 -1
- package/runtime/vercel/ctl.cjs +40 -16
- package/share/agentbox-setup/SKILL.md +37 -1
- package/share/host-skills/agentbox-info/SKILL.md +26 -34
- package/dist/chunk-2LF5YILI.js.map +0 -1
- package/dist/chunk-4NQXNQ53.js.map +0 -1
- package/dist/chunk-B4QG2MCW.js.map +0 -1
- package/dist/chunk-ECLLV5JH.js.map +0 -1
- package/dist/chunk-QYRK5H6Q.js.map +0 -1
- package/dist/chunk-R5XIDQFR.js.map +0 -1
- package/dist/chunk-SNTHHWKY.js.map +0 -1
- package/dist/dist-7KVUIKJX.js.map +0 -1
- package/dist/dist-JAN5VABY.js.map +0 -1
- package/dist/dist-OPIBZ7XM.js.map +0 -1
- /package/dist/{_cloud-attach-HJC672UR.js.map → _cloud-attach-GUBB5RH2.js.map} +0 -0
- /package/dist/{dist-OG6NW6SM.js.map → dist-4DPOL5A7.js.map} +0 -0
- /package/dist/{prepared-state-MQHD3M5F-KE4DT3GX.js.map → prepared-state-MQHD3M5F-Q27AZU53.js.map} +0 -0
|
@@ -4,7 +4,6 @@ import {
|
|
|
4
4
|
GitWorktreeError,
|
|
5
5
|
STATE_DIR,
|
|
6
6
|
STATE_FILE,
|
|
7
|
-
allocateProjectIndex,
|
|
8
7
|
computeDockerContextFingerprint,
|
|
9
8
|
detectGitRepos,
|
|
10
9
|
ensureImage,
|
|
@@ -18,13 +17,14 @@ import {
|
|
|
18
17
|
readPreparedDockerState,
|
|
19
18
|
readState,
|
|
20
19
|
recordBox,
|
|
21
|
-
removeBoxRecord
|
|
22
|
-
|
|
20
|
+
removeBoxRecord,
|
|
21
|
+
reserveProjectIndex
|
|
22
|
+
} from "./chunk-XKH7NTT7.js";
|
|
23
23
|
|
|
24
24
|
// ../../packages/sandbox-docker/dist/index.js
|
|
25
25
|
import { mkdir as mkdir7, stat as stat8 } from "fs/promises";
|
|
26
26
|
import { homedir as homedir10 } from "os";
|
|
27
|
-
import { basename as basename4, join as
|
|
27
|
+
import { basename as basename4, join as join12, resolve as resolve3 } from "path";
|
|
28
28
|
import { execa as execa14 } from "execa";
|
|
29
29
|
|
|
30
30
|
// ../../packages/ctl/dist/index.js
|
|
@@ -704,7 +704,7 @@ async function loadCarrySection(path) {
|
|
|
704
704
|
|
|
705
705
|
// ../../packages/sandbox-docker/dist/index.js
|
|
706
706
|
import { spawnSync } from "child_process";
|
|
707
|
-
import { mkdir as mkdir3, mkdtemp as mkdtemp2, readdir as readdir3, readFile as
|
|
707
|
+
import { mkdir as mkdir3, mkdtemp as mkdtemp2, readdir as readdir3, readFile as readFile42, realpath as realpath2, rm as rm2, stat as stat3, writeFile as writeFile22 } from "fs/promises";
|
|
708
708
|
import { homedir as homedir3, tmpdir as tmpdir2 } from "os";
|
|
709
709
|
import { isAbsolute as isAbsolute2, join as join4, relative as relative2 } from "path";
|
|
710
710
|
import { setTimeout as delay } from "timers/promises";
|
|
@@ -737,11 +737,13 @@ var BUILT_IN_DEFAULTS = {
|
|
|
737
737
|
defaultCheckpointDaytona: "",
|
|
738
738
|
defaultCheckpointHetzner: "",
|
|
739
739
|
defaultCheckpointVercel: "",
|
|
740
|
+
defaultCheckpointE2b: "",
|
|
740
741
|
size: "",
|
|
741
742
|
sizeDocker: "",
|
|
742
743
|
sizeDaytona: "",
|
|
743
744
|
sizeHetzner: "",
|
|
744
745
|
sizeVercel: "",
|
|
746
|
+
sizeE2b: "",
|
|
745
747
|
withPlaywright: false,
|
|
746
748
|
withEnv: false,
|
|
747
749
|
resyncOnStart: true,
|
|
@@ -754,6 +756,7 @@ var BUILT_IN_DEFAULTS = {
|
|
|
754
756
|
imageDaytona: "",
|
|
755
757
|
imageHetzner: "",
|
|
756
758
|
imageVercel: "",
|
|
759
|
+
imageE2b: "",
|
|
757
760
|
// Mirrors BOX_IMAGE_REGISTRY in @agentbox/sandbox-docker. Empty disables the
|
|
758
761
|
// registry pull (always build the docker base image locally).
|
|
759
762
|
imageRegistry: "ghcr.io/madarco/agentbox/box",
|
|
@@ -835,8 +838,8 @@ var KEY_REGISTRY = [
|
|
|
835
838
|
{
|
|
836
839
|
key: "box.provider",
|
|
837
840
|
type: "enum",
|
|
838
|
-
enumValues: ["docker", "daytona", "hetzner", "vercel"],
|
|
839
|
-
description: "Sandbox backend new boxes are created on: local Docker containers, Daytona Cloud sandboxes, Hetzner Cloud VPSes, or
|
|
841
|
+
enumValues: ["docker", "daytona", "hetzner", "vercel", "e2b"],
|
|
842
|
+
description: "Sandbox backend new boxes are created on: local Docker containers, Daytona Cloud sandboxes, Hetzner Cloud VPSes, Vercel Sandboxes, or E2B microVMs."
|
|
840
843
|
},
|
|
841
844
|
{
|
|
842
845
|
key: "box.hostSnapshot",
|
|
@@ -872,6 +875,12 @@ var KEY_REGISTRY = [
|
|
|
872
875
|
description: "Per-provider override of `box.defaultCheckpoint` for vercel. Wins over the global when set; set via `agentbox checkpoint set-default --provider vercel`.",
|
|
873
876
|
advanced: true
|
|
874
877
|
},
|
|
878
|
+
{
|
|
879
|
+
key: "box.defaultCheckpointE2b",
|
|
880
|
+
type: "string",
|
|
881
|
+
description: "Per-provider override of `box.defaultCheckpoint` for e2b. Wins over the global when set; set via `agentbox checkpoint set-default --provider e2b`.",
|
|
882
|
+
advanced: true
|
|
883
|
+
},
|
|
875
884
|
{
|
|
876
885
|
key: "box.size",
|
|
877
886
|
type: "string",
|
|
@@ -901,6 +910,12 @@ var KEY_REGISTRY = [
|
|
|
901
910
|
description: "Per-provider override of `box.size` for vercel. Reserved \u2014 vercel sizing is controlled via `box.vercelVcpus`.",
|
|
902
911
|
advanced: true
|
|
903
912
|
},
|
|
913
|
+
{
|
|
914
|
+
key: "box.sizeE2b",
|
|
915
|
+
type: "string",
|
|
916
|
+
description: "Per-provider override of `box.size` for e2b. Reserved \u2014 e2b sizing is template-level (set at `agentbox prepare --provider e2b` time via --vcpus / --memory).",
|
|
917
|
+
advanced: true
|
|
918
|
+
},
|
|
904
919
|
{
|
|
905
920
|
key: "checkpoint.maxLayers",
|
|
906
921
|
type: "int",
|
|
@@ -972,6 +987,12 @@ var KEY_REGISTRY = [
|
|
|
972
987
|
description: "Per-provider override of `box.image` for vercel (snapshot id, e.g. `snap_\u2026`). Written by `agentbox prepare --provider vercel`.",
|
|
973
988
|
advanced: true
|
|
974
989
|
},
|
|
990
|
+
{
|
|
991
|
+
key: "box.imageE2b",
|
|
992
|
+
type: "string",
|
|
993
|
+
description: "Per-provider override of `box.image` for e2b (template id or `name:tag`, e.g. `agentbox-base:latest`). Written by `agentbox prepare --provider e2b`.",
|
|
994
|
+
advanced: true
|
|
995
|
+
},
|
|
975
996
|
{
|
|
976
997
|
key: "box.imageRegistry",
|
|
977
998
|
type: "string",
|
|
@@ -1526,7 +1547,7 @@ function writeLeaf(obj, branch, leaf, value) {
|
|
|
1526
1547
|
b[leaf] = value;
|
|
1527
1548
|
}
|
|
1528
1549
|
function resolveDefaultCheckpoint(cfg, provider) {
|
|
1529
|
-
const perProvider = provider === "daytona" ? cfg.box.defaultCheckpointDaytona : provider === "hetzner" ? cfg.box.defaultCheckpointHetzner : provider === "vercel" ? cfg.box.defaultCheckpointVercel : cfg.box.defaultCheckpointDocker;
|
|
1550
|
+
const perProvider = provider === "daytona" ? cfg.box.defaultCheckpointDaytona : provider === "hetzner" ? cfg.box.defaultCheckpointHetzner : provider === "vercel" ? cfg.box.defaultCheckpointVercel : provider === "e2b" ? cfg.box.defaultCheckpointE2b : cfg.box.defaultCheckpointDocker;
|
|
1530
1551
|
if (perProvider && perProvider.length > 0) return perProvider;
|
|
1531
1552
|
return cfg.box.defaultCheckpoint;
|
|
1532
1553
|
}
|
|
@@ -1535,15 +1556,16 @@ function defaultCheckpointConfigKey(provider) {
|
|
|
1535
1556
|
if (provider === "daytona") return "box.defaultCheckpointDaytona";
|
|
1536
1557
|
if (provider === "hetzner") return "box.defaultCheckpointHetzner";
|
|
1537
1558
|
if (provider === "vercel") return "box.defaultCheckpointVercel";
|
|
1559
|
+
if (provider === "e2b") return "box.defaultCheckpointE2b";
|
|
1538
1560
|
return "box.defaultCheckpoint";
|
|
1539
1561
|
}
|
|
1540
1562
|
function resolveBoxSize(cfg, provider) {
|
|
1541
|
-
const perProvider = provider === "daytona" ? cfg.box.sizeDaytona : provider === "hetzner" ? cfg.box.sizeHetzner : provider === "vercel" ? cfg.box.sizeVercel : cfg.box.sizeDocker;
|
|
1563
|
+
const perProvider = provider === "daytona" ? cfg.box.sizeDaytona : provider === "hetzner" ? cfg.box.sizeHetzner : provider === "vercel" ? cfg.box.sizeVercel : provider === "e2b" ? cfg.box.sizeE2b : cfg.box.sizeDocker;
|
|
1542
1564
|
if (perProvider && perProvider.length > 0) return perProvider;
|
|
1543
1565
|
return cfg.box.size;
|
|
1544
1566
|
}
|
|
1545
1567
|
function resolveBoxImage(cfg, provider) {
|
|
1546
|
-
const perProvider = provider === "daytona" ? cfg.box.imageDaytona : provider === "hetzner" ? cfg.box.imageHetzner : provider === "vercel" ? cfg.box.imageVercel : cfg.box.imageDocker;
|
|
1568
|
+
const perProvider = provider === "daytona" ? cfg.box.imageDaytona : provider === "hetzner" ? cfg.box.imageHetzner : provider === "vercel" ? cfg.box.imageVercel : provider === "e2b" ? cfg.box.imageE2b : cfg.box.imageDocker;
|
|
1547
1569
|
if (perProvider && perProvider.length > 0) return perProvider;
|
|
1548
1570
|
return cfg.box.image;
|
|
1549
1571
|
}
|
|
@@ -1552,6 +1574,7 @@ function boxImageConfigKey(provider) {
|
|
|
1552
1574
|
if (provider === "daytona") return "box.imageDaytona";
|
|
1553
1575
|
if (provider === "hetzner") return "box.imageHetzner";
|
|
1554
1576
|
if (provider === "vercel") return "box.imageVercel";
|
|
1577
|
+
if (provider === "e2b") return "box.imageE2b";
|
|
1555
1578
|
return "box.image";
|
|
1556
1579
|
}
|
|
1557
1580
|
async function setConfigValue(scope, key, value, cwd, opts = {}) {
|
|
@@ -1752,7 +1775,7 @@ import { copyFile, mkdtemp, readdir as readdir22, readFile as readFile32, rm as
|
|
|
1752
1775
|
import { homedir as homedir22, tmpdir } from "os";
|
|
1753
1776
|
import { basename as basename2, join as join32, relative } from "path";
|
|
1754
1777
|
import { execa as execa4 } from "execa";
|
|
1755
|
-
import { chmod, mkdir as mkdir22, readFile as
|
|
1778
|
+
import { chmod, mkdir as mkdir22, readFile as readFile23 } from "fs/promises";
|
|
1756
1779
|
import { basename as basename3, join as join22 } from "path";
|
|
1757
1780
|
import { execa as execa3 } from "execa";
|
|
1758
1781
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
@@ -1766,11 +1789,14 @@ import { homedir as homedir5 } from "os";
|
|
|
1766
1789
|
import { join as join6 } from "path";
|
|
1767
1790
|
import { execa as execa7 } from "execa";
|
|
1768
1791
|
import { randomBytes as randomBytes3 } from "crypto";
|
|
1792
|
+
import { createHash as createHash22 } from "crypto";
|
|
1793
|
+
import { readFile as readFile52 } from "fs/promises";
|
|
1794
|
+
import { join as join7 } from "path";
|
|
1769
1795
|
import { execa as execa8 } from "execa";
|
|
1770
1796
|
import { existsSync } from "fs";
|
|
1771
|
-
import { readFile as
|
|
1797
|
+
import { readFile as readFile6 } from "fs/promises";
|
|
1772
1798
|
import { homedir as homedir6 } from "os";
|
|
1773
|
-
import { join as
|
|
1799
|
+
import { join as join8 } from "path";
|
|
1774
1800
|
import { execa as execa9 } from "execa";
|
|
1775
1801
|
|
|
1776
1802
|
// ../../packages/core/dist/index.js
|
|
@@ -1805,6 +1831,12 @@ function resolveAgentLauncher(kind) {
|
|
|
1805
1831
|
if (kind === "opencode") return opencodeLauncher;
|
|
1806
1832
|
throw new Error(`unknown agent kind: ${String(kind)}`);
|
|
1807
1833
|
}
|
|
1834
|
+
var UserFacingError = class extends Error {
|
|
1835
|
+
constructor(message) {
|
|
1836
|
+
super(message);
|
|
1837
|
+
this.name = "UserFacingError";
|
|
1838
|
+
}
|
|
1839
|
+
};
|
|
1808
1840
|
var BoxNotFoundError = class extends Error {
|
|
1809
1841
|
constructor(query) {
|
|
1810
1842
|
super(`no agentbox matches "${query}"`);
|
|
@@ -1833,10 +1865,10 @@ function generateBoxId() {
|
|
|
1833
1865
|
import { execa as execa10 } from "execa";
|
|
1834
1866
|
import { mkdir as mkdir42, readdir as readdir42, rm as rm32, stat as stat6 } from "fs/promises";
|
|
1835
1867
|
import { homedir as homedir7, platform } from "os";
|
|
1836
|
-
import { join as
|
|
1837
|
-
import { mkdir as mkdir5, mkdtemp as mkdtemp3, readFile as
|
|
1868
|
+
import { join as join9, resolve as resolve2 } from "path";
|
|
1869
|
+
import { mkdir as mkdir5, mkdtemp as mkdtemp3, readFile as readFile7, readdir as readdir5, rm as rm4, writeFile as writeFile32 } from "fs/promises";
|
|
1838
1870
|
import { homedir as homedir8, tmpdir as tmpdir3 } from "os";
|
|
1839
|
-
import { basename as basename32, join as
|
|
1871
|
+
import { basename as basename32, join as join10 } from "path";
|
|
1840
1872
|
import { execa as execa11 } from "execa";
|
|
1841
1873
|
import { stat as stat7 } from "fs/promises";
|
|
1842
1874
|
import { execa as execa12 } from "execa";
|
|
@@ -1844,22 +1876,22 @@ import { execa as execa13 } from "execa";
|
|
|
1844
1876
|
import { spawn } from "child_process";
|
|
1845
1877
|
import { randomBytes as randomBytes22 } from "crypto";
|
|
1846
1878
|
import { existsSync as existsSync2, openSync } from "fs";
|
|
1847
|
-
import { cp, mkdir as mkdir6, readFile as
|
|
1879
|
+
import { cp, mkdir as mkdir6, readFile as readFile8, readdir as readdir6, rename as rename3, rm as rm5, unlink as unlink2, writeFile as writeFile4 } from "fs/promises";
|
|
1848
1880
|
import { request as httpRequest } from "http";
|
|
1849
1881
|
import { createRequire } from "module";
|
|
1850
1882
|
import { homedir as homedir9 } from "os";
|
|
1851
|
-
import { dirname as dirname3, join as
|
|
1883
|
+
import { dirname as dirname3, join as join11, resolve as resolve22, sep } from "path";
|
|
1852
1884
|
import { setTimeout as delay2 } from "timers/promises";
|
|
1853
1885
|
import { fileURLToPath } from "url";
|
|
1854
1886
|
|
|
1855
1887
|
// ../../packages/relay/dist/index.js
|
|
1856
1888
|
import { createHash as createHash2, randomBytes as randomBytes2 } from "crypto";
|
|
1857
1889
|
import { execa } from "execa";
|
|
1858
|
-
import { spawn as
|
|
1890
|
+
import { spawn as spawn3 } from "child_process";
|
|
1859
1891
|
import {
|
|
1860
1892
|
mkdir as mkdir2,
|
|
1861
1893
|
readdir as readdir2,
|
|
1862
|
-
readFile as
|
|
1894
|
+
readFile as readFile4,
|
|
1863
1895
|
rename as rename2,
|
|
1864
1896
|
unlink,
|
|
1865
1897
|
writeFile as writeFile2
|
|
@@ -1921,7 +1953,7 @@ async function loadQueueConfig() {
|
|
|
1921
1953
|
const d = BUILT_IN_DEFAULTS.queue;
|
|
1922
1954
|
let global = {};
|
|
1923
1955
|
try {
|
|
1924
|
-
global = parseUserConfig(await
|
|
1956
|
+
global = parseUserConfig(await readFile4(GLOBAL_CONFIG_FILE, "utf8"), GLOBAL_CONFIG_FILE);
|
|
1925
1957
|
} catch {
|
|
1926
1958
|
}
|
|
1927
1959
|
const q = global.queue ?? {};
|
|
@@ -1941,7 +1973,7 @@ async function writeJob(job) {
|
|
|
1941
1973
|
}
|
|
1942
1974
|
async function readJob(id) {
|
|
1943
1975
|
try {
|
|
1944
|
-
const raw = await
|
|
1976
|
+
const raw = await readFile4(join3(QUEUE_DIR, `${id}.json`), "utf8");
|
|
1945
1977
|
return JSON.parse(raw);
|
|
1946
1978
|
} catch (err) {
|
|
1947
1979
|
if (err.code === "ENOENT") return null;
|
|
@@ -1967,7 +1999,7 @@ async function loadQueue() {
|
|
|
1967
1999
|
for (const name of entries) {
|
|
1968
2000
|
if (!name.endsWith(".json")) continue;
|
|
1969
2001
|
try {
|
|
1970
|
-
const raw = await
|
|
2002
|
+
const raw = await readFile4(join3(QUEUE_DIR, name), "utf8");
|
|
1971
2003
|
out.push(JSON.parse(raw));
|
|
1972
2004
|
} catch {
|
|
1973
2005
|
}
|
|
@@ -1975,6 +2007,8 @@ async function loadQueue() {
|
|
|
1975
2007
|
out.sort((a, b) => a.createdAt < b.createdAt ? -1 : a.createdAt > b.createdAt ? 1 : 0);
|
|
1976
2008
|
return out;
|
|
1977
2009
|
}
|
|
2010
|
+
var TERMINAL_RETENTION_MS = 60 * 60 * 1e3;
|
|
2011
|
+
var SWEEP_INTERVAL_MS = 60 * 1e3;
|
|
1978
2012
|
function processAlive(pid) {
|
|
1979
2013
|
try {
|
|
1980
2014
|
process.kill(pid, 0);
|
|
@@ -2043,7 +2077,7 @@ async function uncachedBoxStateCount() {
|
|
|
2043
2077
|
}
|
|
2044
2078
|
function inspectDockerState(containerName) {
|
|
2045
2079
|
return new Promise((resolveP) => {
|
|
2046
|
-
const child =
|
|
2080
|
+
const child = spawn3("docker", ["inspect", "--format", "{{.State.Status}}", containerName], {
|
|
2047
2081
|
stdio: ["ignore", "pipe", "pipe"]
|
|
2048
2082
|
});
|
|
2049
2083
|
let out = "";
|
|
@@ -2078,19 +2112,19 @@ function queueLogPath(id) {
|
|
|
2078
2112
|
// ../../packages/sandbox-docker/dist/index.js
|
|
2079
2113
|
import { execa as execa16 } from "execa";
|
|
2080
2114
|
import { readdir as readdir7, rm as rm6, stat as stat9 } from "fs/promises";
|
|
2081
|
-
import { join as
|
|
2115
|
+
import { join as join14 } from "path";
|
|
2082
2116
|
import { execa as execa15 } from "execa";
|
|
2083
|
-
import { join as
|
|
2117
|
+
import { join as join13 } from "path";
|
|
2084
2118
|
import { homedir as homedir11 } from "os";
|
|
2085
|
-
import { join as
|
|
2119
|
+
import { join as join15 } from "path";
|
|
2086
2120
|
import { execa as execa17 } from "execa";
|
|
2087
2121
|
import { existsSync as existsSync3, mkdirSync, renameSync, statSync } from "fs";
|
|
2088
2122
|
import { basename as basename5, dirname as dirname22, posix, resolve as resolve4 } from "path";
|
|
2089
2123
|
import { execa as execa18 } from "execa";
|
|
2090
|
-
import { createHash as
|
|
2091
|
-
import { copyFile as copyFile2, mkdir as mkdir8, mkdtemp as mkdtemp4, readdir as readdir8, readFile as
|
|
2124
|
+
import { createHash as createHash32 } from "crypto";
|
|
2125
|
+
import { copyFile as copyFile2, mkdir as mkdir8, mkdtemp as mkdtemp4, readdir as readdir8, readFile as readFile9, rm as rm7, stat as stat10 } from "fs/promises";
|
|
2092
2126
|
import { homedir as homedir12, tmpdir as tmpdir4 } from "os";
|
|
2093
|
-
import { basename as basename6, dirname as dirname32, join as
|
|
2127
|
+
import { basename as basename6, dirname as dirname32, join as join16 } from "path";
|
|
2094
2128
|
import { execa as execa19 } from "execa";
|
|
2095
2129
|
function isHostPathHookCommand(command, hostHome) {
|
|
2096
2130
|
if (typeof command !== "string" || command.length === 0) return false;
|
|
@@ -3021,7 +3055,7 @@ function isRealAgentCredential(agent, text) {
|
|
|
3021
3055
|
}
|
|
3022
3056
|
async function hostClaudeBackupExpired(path = CREDENTIALS_BACKUP_FILE, now = Date.now()) {
|
|
3023
3057
|
try {
|
|
3024
|
-
const parsed = JSON.parse(await
|
|
3058
|
+
const parsed = JSON.parse(await readFile23(path, "utf8"));
|
|
3025
3059
|
const exp = parsed?.claudeAiOauth?.expiresAt;
|
|
3026
3060
|
return typeof exp === "number" && Number.isFinite(exp) && exp < now;
|
|
3027
3061
|
} catch {
|
|
@@ -3069,7 +3103,7 @@ function extractOpencodeCredentials(volume, image) {
|
|
|
3069
3103
|
}
|
|
3070
3104
|
async function hostBackupHasCredentials(path = CREDENTIALS_BACKUP_FILE) {
|
|
3071
3105
|
try {
|
|
3072
|
-
const parsed = JSON.parse(await
|
|
3106
|
+
const parsed = JSON.parse(await readFile23(path, "utf8"));
|
|
3073
3107
|
const rt = parsed?.claudeAiOauth?.refreshToken;
|
|
3074
3108
|
return typeof rt === "string" && rt.length > 0;
|
|
3075
3109
|
} catch {
|
|
@@ -3241,6 +3275,64 @@ async function resolveClaudeMemoryDir(hostWorkspace, hostHome = homedir22()) {
|
|
|
3241
3275
|
}
|
|
3242
3276
|
return memDir;
|
|
3243
3277
|
}
|
|
3278
|
+
async function buildBoxClaudeJsonFromHost(opts) {
|
|
3279
|
+
const { hostHome, hostWorkspace } = opts;
|
|
3280
|
+
const hostClaudeJson = join32(hostHome, ".claude.json");
|
|
3281
|
+
let working;
|
|
3282
|
+
if (await pathExists(hostClaudeJson)) {
|
|
3283
|
+
try {
|
|
3284
|
+
working = JSON.parse(await readFile32(hostClaudeJson, "utf8"));
|
|
3285
|
+
} catch {
|
|
3286
|
+
working = null;
|
|
3287
|
+
}
|
|
3288
|
+
}
|
|
3289
|
+
if (working === void 0 || working === null) {
|
|
3290
|
+
working = {
|
|
3291
|
+
installMethod: "native",
|
|
3292
|
+
autoUpdates: false,
|
|
3293
|
+
autoUpdatesProtectedForNative: true,
|
|
3294
|
+
// Pre-accept onboarding so the in-box Claude doesn't show the theme
|
|
3295
|
+
// picker on first run. AgentBox installing implies the user has
|
|
3296
|
+
// already used Claude Code on the host.
|
|
3297
|
+
hasCompletedOnboarding: true,
|
|
3298
|
+
projects: { [CLOUD_WORKSPACE]: { hasTrustDialogAccepted: true } }
|
|
3299
|
+
};
|
|
3300
|
+
} else {
|
|
3301
|
+
working = filterHostHooks(working, hostHome).data;
|
|
3302
|
+
working = setInstallMethodNative(working).data;
|
|
3303
|
+
if (hostWorkspace) {
|
|
3304
|
+
working = addProjectAlias(working, hostWorkspace, CLOUD_WORKSPACE).data;
|
|
3305
|
+
}
|
|
3306
|
+
working = trustWorkspace(working, CLOUD_WORKSPACE).data;
|
|
3307
|
+
if (typeof working === "object" && working !== null) {
|
|
3308
|
+
const w = working;
|
|
3309
|
+
if (w["hasCompletedOnboarding"] !== true) w["hasCompletedOnboarding"] = true;
|
|
3310
|
+
}
|
|
3311
|
+
}
|
|
3312
|
+
return working;
|
|
3313
|
+
}
|
|
3314
|
+
async function stageClaudeJsonOnlyForUpload(opts = {}) {
|
|
3315
|
+
const hostHome = opts.hostHome ?? homedir22();
|
|
3316
|
+
const stageDir = await mkStageDir("claude-json-only");
|
|
3317
|
+
let tarballPath = null;
|
|
3318
|
+
try {
|
|
3319
|
+
const claudeJson = await buildBoxClaudeJsonFromHost({
|
|
3320
|
+
hostHome,
|
|
3321
|
+
hostWorkspace: opts.hostWorkspace
|
|
3322
|
+
});
|
|
3323
|
+
await writeFile3(join32(stageDir, "_claude.json"), JSON.stringify(claudeJson, null, 2));
|
|
3324
|
+
tarballPath = await tarballFromDir(stageDir, "claude-json-only");
|
|
3325
|
+
return {
|
|
3326
|
+
tarballPath,
|
|
3327
|
+
cleanup: makeCleanup([stageDir, tarballPath]),
|
|
3328
|
+
warnings: []
|
|
3329
|
+
};
|
|
3330
|
+
} catch (err) {
|
|
3331
|
+
await rm3(stageDir, { recursive: true, force: true });
|
|
3332
|
+
if (tarballPath) await rm3(tarballPath, { force: true });
|
|
3333
|
+
throw err;
|
|
3334
|
+
}
|
|
3335
|
+
}
|
|
3244
3336
|
async function stageClaudeStaticForUpload(opts = {}) {
|
|
3245
3337
|
const hostHome = opts.hostHome ?? homedir22();
|
|
3246
3338
|
const hostClaude = join32(hostHome, ".claude");
|
|
@@ -3273,31 +3365,11 @@ async function stageClaudeStaticForUpload(opts = {}) {
|
|
|
3273
3365
|
} catch {
|
|
3274
3366
|
}
|
|
3275
3367
|
}
|
|
3276
|
-
const
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
} catch {
|
|
3282
|
-
working = null;
|
|
3283
|
-
}
|
|
3284
|
-
}
|
|
3285
|
-
if (working === void 0 || working === null) {
|
|
3286
|
-
working = {
|
|
3287
|
-
installMethod: "native",
|
|
3288
|
-
autoUpdates: false,
|
|
3289
|
-
autoUpdatesProtectedForNative: true,
|
|
3290
|
-
projects: { [CLOUD_WORKSPACE]: { hasTrustDialogAccepted: true } }
|
|
3291
|
-
};
|
|
3292
|
-
} else {
|
|
3293
|
-
working = filterHostHooks(working, hostHome).data;
|
|
3294
|
-
working = setInstallMethodNative(working).data;
|
|
3295
|
-
if (opts.hostWorkspace) {
|
|
3296
|
-
working = addProjectAlias(working, opts.hostWorkspace, CLOUD_WORKSPACE).data;
|
|
3297
|
-
}
|
|
3298
|
-
working = trustWorkspace(working, CLOUD_WORKSPACE).data;
|
|
3299
|
-
}
|
|
3300
|
-
await writeFile3(join32(stageDir, "_claude.json"), JSON.stringify(working, null, 2));
|
|
3368
|
+
const claudeJson = await buildBoxClaudeJsonFromHost({
|
|
3369
|
+
hostHome,
|
|
3370
|
+
hostWorkspace: opts.hostWorkspace
|
|
3371
|
+
});
|
|
3372
|
+
await writeFile3(join32(stageDir, "_claude.json"), JSON.stringify(claudeJson, null, 2));
|
|
3301
3373
|
const pluginsDir = join32(stageDir, "plugins");
|
|
3302
3374
|
if (await pathExists(pluginsDir)) {
|
|
3303
3375
|
try {
|
|
@@ -3705,7 +3777,7 @@ async function maybeFilterTo(src, dest, hostHome, opts = {}) {
|
|
|
3705
3777
|
};
|
|
3706
3778
|
let parsed;
|
|
3707
3779
|
try {
|
|
3708
|
-
parsed = JSON.parse(await
|
|
3780
|
+
parsed = JSON.parse(await readFile42(src, "utf8"));
|
|
3709
3781
|
} catch {
|
|
3710
3782
|
return zero;
|
|
3711
3783
|
}
|
|
@@ -3788,7 +3860,7 @@ async function isDir(p) {
|
|
|
3788
3860
|
}
|
|
3789
3861
|
async function readReferencedPluginKeys(installedPluginsJsonPath) {
|
|
3790
3862
|
try {
|
|
3791
|
-
const raw = await
|
|
3863
|
+
const raw = await readFile42(installedPluginsJsonPath, "utf8");
|
|
3792
3864
|
return referencedPluginVersionKeys(JSON.parse(raw));
|
|
3793
3865
|
} catch {
|
|
3794
3866
|
return /* @__PURE__ */ new Set();
|
|
@@ -4263,7 +4335,7 @@ async function listChildDirs(dir) {
|
|
|
4263
4335
|
}
|
|
4264
4336
|
async function readJsonFile(path) {
|
|
4265
4337
|
try {
|
|
4266
|
-
return JSON.parse(await
|
|
4338
|
+
return JSON.parse(await readFile42(path, "utf8"));
|
|
4267
4339
|
} catch {
|
|
4268
4340
|
return void 0;
|
|
4269
4341
|
}
|
|
@@ -5380,6 +5452,75 @@ async function seedWorkspace(opts) {
|
|
|
5380
5452
|
}
|
|
5381
5453
|
}
|
|
5382
5454
|
}
|
|
5455
|
+
async function regenerateRestoredWorktrees(opts) {
|
|
5456
|
+
const log = opts.onLog ?? (() => {
|
|
5457
|
+
});
|
|
5458
|
+
const script = [
|
|
5459
|
+
"set -e",
|
|
5460
|
+
'OLD="$1"; NEW="$2"; MAIN="$3"; BR="$4"; BASE="$5"; META="$6"',
|
|
5461
|
+
// Rename baked content to the fresh unique path (rename, not copy).
|
|
5462
|
+
'[ "$OLD" = "$NEW" ] || mv "$OLD" "$NEW"',
|
|
5463
|
+
// Fresh branch at the base ref; -f is safe because pickFreshBranch already
|
|
5464
|
+
// guaranteed BR is unused on the host.
|
|
5465
|
+
'git -C "$MAIN" branch -f "$BR" "$BASE"',
|
|
5466
|
+
// Author worktree metadata under the bind-mounted host .git.
|
|
5467
|
+
'mkdir -p "$META"',
|
|
5468
|
+
'printf "../..\\n" > "$META/commondir"',
|
|
5469
|
+
'printf "%s\\n" "$NEW/.git" > "$META/gitdir"',
|
|
5470
|
+
'printf "ref: refs/heads/%s\\n" "$BR" > "$META/HEAD"',
|
|
5471
|
+
// Point the worktree's gitfile at the fresh metadata dir.
|
|
5472
|
+
'printf "gitdir: %s\\n" "$META" > "$NEW/.git"',
|
|
5473
|
+
// Reset tracked files to the fork base so the box starts CLEAN at the host
|
|
5474
|
+
// base ref — same git state as a fresh create. The baked tree was captured
|
|
5475
|
+
// on the source box's (possibly divergent/older) branch, so its tracked
|
|
5476
|
+
// deviations are staleness, not work; resetting drops that noise. The
|
|
5477
|
+
// gitignored warm artifacts (node_modules, .next, build caches) are
|
|
5478
|
+
// untouched by reset --hard — that warm state is the checkpoint's value.
|
|
5479
|
+
'git -C "$NEW" reset -q --hard HEAD',
|
|
5480
|
+
// Boxes carry no signing key; mirror seedWorkspace's per-worktree config so
|
|
5481
|
+
// host commit.gpgsign=true doesn't break in-box commits. extensions.
|
|
5482
|
+
// worktreeConfig writes the SHARED (bind-mounted) .git/config, so concurrent
|
|
5483
|
+
// boxes race on .git/config.lock — retry through the contention rather than
|
|
5484
|
+
// aborting (best-effort, like seedWorkspace). The per-worktree gpgsign write
|
|
5485
|
+
// needs the extension enabled first, so it follows the retry.
|
|
5486
|
+
"set +e",
|
|
5487
|
+
'for i in 1 2 3 4 5 6 7 8; do git -C "$MAIN" config extensions.worktreeConfig true && break; sleep 0.25; done',
|
|
5488
|
+
'git -C "$NEW" config --worktree commit.gpgsign false',
|
|
5489
|
+
"exit 0"
|
|
5490
|
+
].join("\n");
|
|
5491
|
+
for (const p of opts.plans) {
|
|
5492
|
+
const baseRef = p.kind === "root" ? opts.fromBranch ?? "HEAD" : "HEAD";
|
|
5493
|
+
const metaDir = `${p.hostMainRepo}/.git/worktrees/${fsSafeBranch(p.freshBranch)}`;
|
|
5494
|
+
const r = await execa8(
|
|
5495
|
+
"docker",
|
|
5496
|
+
[
|
|
5497
|
+
"exec",
|
|
5498
|
+
"--user",
|
|
5499
|
+
"vscode",
|
|
5500
|
+
opts.container,
|
|
5501
|
+
"bash",
|
|
5502
|
+
"-c",
|
|
5503
|
+
script,
|
|
5504
|
+
"bash",
|
|
5505
|
+
p.bakedGitWorktreePath,
|
|
5506
|
+
p.freshGitWorktreePath,
|
|
5507
|
+
p.hostMainRepo,
|
|
5508
|
+
p.freshBranch,
|
|
5509
|
+
baseRef,
|
|
5510
|
+
metaDir
|
|
5511
|
+
],
|
|
5512
|
+
{ reject: false }
|
|
5513
|
+
);
|
|
5514
|
+
if (r.exitCode !== 0) {
|
|
5515
|
+
throw new GitWorktreeError(
|
|
5516
|
+
`regenerate worktree for ${p.freshBranch} failed: ${r.stderr || r.stdout}`
|
|
5517
|
+
);
|
|
5518
|
+
}
|
|
5519
|
+
log(
|
|
5520
|
+
`restored worktree ${p.freshGitWorktreePath} on fresh branch ${p.freshBranch} (base ${baseRef})`
|
|
5521
|
+
);
|
|
5522
|
+
}
|
|
5523
|
+
}
|
|
5383
5524
|
async function seedWorkspaceFromDir(opts) {
|
|
5384
5525
|
const log = opts.onLog ?? (() => {
|
|
5385
5526
|
});
|
|
@@ -5419,6 +5560,12 @@ async function gitIn(container, ct, args) {
|
|
|
5419
5560
|
function splitNul(s) {
|
|
5420
5561
|
return s.split("\0").filter((p) => p.length > 0);
|
|
5421
5562
|
}
|
|
5563
|
+
var NON_REGULAR_TOKEN = "-";
|
|
5564
|
+
function classifyUntrackedOverlay(boxToken, hostHash) {
|
|
5565
|
+
if (boxToken === void 0) return "copy";
|
|
5566
|
+
if (boxToken === NON_REGULAR_TOKEN) return "conflict";
|
|
5567
|
+
return boxToken === hostHash ? "identical" : "conflict";
|
|
5568
|
+
}
|
|
5422
5569
|
async function unmergedPaths(container, ct) {
|
|
5423
5570
|
const r = await gitIn(container, ct, ["diff", "--name-only", "--diff-filter=U", "-z"]);
|
|
5424
5571
|
return r.exitCode === 0 ? splitNul(r.stdout) : [];
|
|
@@ -5515,7 +5662,7 @@ async function resyncWorkspaceFromHost(opts) {
|
|
|
5515
5662
|
}
|
|
5516
5663
|
}
|
|
5517
5664
|
if (hostUntracked.length > 0) {
|
|
5518
|
-
const
|
|
5665
|
+
const probe = await execa8(
|
|
5519
5666
|
"docker",
|
|
5520
5667
|
[
|
|
5521
5668
|
"exec",
|
|
@@ -5525,15 +5672,42 @@ async function resyncWorkspaceFromHost(opts) {
|
|
|
5525
5672
|
opts.container,
|
|
5526
5673
|
"bash",
|
|
5527
5674
|
"-c",
|
|
5528
|
-
'cd "$1" && while IFS= read -r -d "" f; do [ -
|
|
5675
|
+
'cd "$1" && while IFS= read -r -d "" f; do if [ -f "$f" ] && [ ! -L "$f" ]; then printf "%s\\0%s\\0" "$(sha256sum < "$f" | cut -d" " -f1)" "$f"; elif [ -e "$f" ]; then printf "%s\\0%s\\0" "-" "$f"; fi; done',
|
|
5529
5676
|
"bash",
|
|
5530
5677
|
ct
|
|
5531
5678
|
],
|
|
5532
5679
|
{ input: hostUntracked.join("\0"), reject: false }
|
|
5533
5680
|
);
|
|
5534
|
-
const
|
|
5535
|
-
|
|
5536
|
-
|
|
5681
|
+
const boxTokens = /* @__PURE__ */ new Map();
|
|
5682
|
+
if (probe.exitCode === 0) {
|
|
5683
|
+
const flat = splitNul(probe.stdout);
|
|
5684
|
+
for (let i = 0; i + 1 < flat.length; i += 2) {
|
|
5685
|
+
const token = flat[i];
|
|
5686
|
+
const path = flat[i + 1];
|
|
5687
|
+
if (token !== void 0 && path !== void 0) boxTokens.set(path, token);
|
|
5688
|
+
}
|
|
5689
|
+
}
|
|
5690
|
+
const toCopy = [];
|
|
5691
|
+
let identical = 0;
|
|
5692
|
+
for (const p of hostUntracked) {
|
|
5693
|
+
const boxToken = boxTokens.get(p);
|
|
5694
|
+
let hostHash = "";
|
|
5695
|
+
if (boxToken !== void 0 && boxToken !== NON_REGULAR_TOKEN) {
|
|
5696
|
+
try {
|
|
5697
|
+
hostHash = createHash22("sha256").update(await readFile52(join7(hostMain, p))).digest("hex");
|
|
5698
|
+
} catch {
|
|
5699
|
+
identical++;
|
|
5700
|
+
continue;
|
|
5701
|
+
}
|
|
5702
|
+
}
|
|
5703
|
+
const verdict = classifyUntrackedOverlay(boxToken, hostHash);
|
|
5704
|
+
if (verdict === "copy") toCopy.push(p);
|
|
5705
|
+
else if (verdict === "conflict") res.overlaySkipped.push(p);
|
|
5706
|
+
else identical++;
|
|
5707
|
+
}
|
|
5708
|
+
if (identical > 0) {
|
|
5709
|
+
log(`resync: ${ct}: ${String(identical)} untracked host file(s) already identical in box (no-op)`);
|
|
5710
|
+
}
|
|
5537
5711
|
if (toCopy.length > 0) {
|
|
5538
5712
|
const tarOut = await execa8("tar", ["-C", hostMain, "--null", "-T", "-", "-cf", "-"], {
|
|
5539
5713
|
input: toCopy.join("\0"),
|
|
@@ -5643,7 +5817,7 @@ async function startPortlessProxy() {
|
|
|
5643
5817
|
function portlessStateDirCandidates() {
|
|
5644
5818
|
const env = process.env["PORTLESS_STATE_DIR"];
|
|
5645
5819
|
if (env && env.trim().length > 0) return [env.trim()];
|
|
5646
|
-
return ["/tmp/portless",
|
|
5820
|
+
return ["/tmp/portless", join8(homedir6(), ".portless")];
|
|
5647
5821
|
}
|
|
5648
5822
|
function pidAlive(pid) {
|
|
5649
5823
|
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
@@ -5656,7 +5830,7 @@ function pidAlive(pid) {
|
|
|
5656
5830
|
}
|
|
5657
5831
|
async function readProxyPid(dir) {
|
|
5658
5832
|
try {
|
|
5659
|
-
const raw = await
|
|
5833
|
+
const raw = await readFile6(join8(dir, "proxy.pid"), "utf8");
|
|
5660
5834
|
const pid = Number.parseInt(raw.trim(), 10);
|
|
5661
5835
|
return Number.isFinite(pid) && pid > 0 ? pid : null;
|
|
5662
5836
|
} catch {
|
|
@@ -5676,7 +5850,7 @@ async function resolvePortlessHostStateDir(override) {
|
|
|
5676
5850
|
if (env && env.trim().length > 0) return env.trim();
|
|
5677
5851
|
const live = await findLivePortlessStateDir();
|
|
5678
5852
|
if (live) return live;
|
|
5679
|
-
const home =
|
|
5853
|
+
const home = join8(homedir6(), ".portless");
|
|
5680
5854
|
if (existsSync(home)) return home;
|
|
5681
5855
|
if (existsSync("/tmp/portless")) return "/tmp/portless";
|
|
5682
5856
|
return home;
|
|
@@ -5705,12 +5879,12 @@ var EXCLUDE_DIRS = /* @__PURE__ */ new Set([
|
|
|
5705
5879
|
".cache",
|
|
5706
5880
|
".parcel-cache"
|
|
5707
5881
|
]);
|
|
5708
|
-
var SNAPSHOTS_ROOT =
|
|
5882
|
+
var SNAPSHOTS_ROOT = join9(homedir7(), ".agentbox", "snapshots");
|
|
5709
5883
|
function snapshotPathFor(box) {
|
|
5710
5884
|
const mnemonic = sanitizeMnemonic(box.name);
|
|
5711
5885
|
const n = box.projectIndex;
|
|
5712
5886
|
const segment = typeof n === "number" && Number.isFinite(n) && n > 0 ? `${box.id}-${String(n)}-${mnemonic}` : `${box.id}-${mnemonic}`;
|
|
5713
|
-
return
|
|
5887
|
+
return join9(SNAPSHOTS_ROOT, segment);
|
|
5714
5888
|
}
|
|
5715
5889
|
async function findExcludedDirs(root, excluded = EXCLUDE_DIRS) {
|
|
5716
5890
|
const matches = [];
|
|
@@ -5723,7 +5897,7 @@ async function findExcludedDirs(root, excluded = EXCLUDE_DIRS) {
|
|
|
5723
5897
|
}
|
|
5724
5898
|
for (const entry of entries) {
|
|
5725
5899
|
if (!entry.isDirectory()) continue;
|
|
5726
|
-
const abs =
|
|
5900
|
+
const abs = join9(dir, entry.name);
|
|
5727
5901
|
if (excluded.has(entry.name)) {
|
|
5728
5902
|
matches.push(abs);
|
|
5729
5903
|
continue;
|
|
@@ -5745,21 +5919,21 @@ async function createSnapshot(opts) {
|
|
|
5745
5919
|
await Promise.all(toPrune.map((p) => rm32(p, { recursive: true, force: true })));
|
|
5746
5920
|
return { destination, prunedPaths: toPrune };
|
|
5747
5921
|
}
|
|
5748
|
-
var CHECKPOINTS_ROOT =
|
|
5922
|
+
var CHECKPOINTS_ROOT = join10(homedir8(), ".agentbox", "checkpoints");
|
|
5749
5923
|
var CHECKPOINT_IMAGE_PREFIX = "agentbox-ckpt-";
|
|
5750
5924
|
function checkpointImageTag(projectRoot, name) {
|
|
5751
5925
|
const mnemonic = sanitizeMnemonic(basename32(projectRoot));
|
|
5752
5926
|
return `${CHECKPOINT_IMAGE_PREFIX}${hashProjectPath(projectRoot)}_${mnemonic}:${name}`;
|
|
5753
5927
|
}
|
|
5754
5928
|
function projectCheckpointsDir(projectRoot) {
|
|
5755
|
-
return
|
|
5929
|
+
return join10(CHECKPOINTS_ROOT, projectDirSegment(projectRoot));
|
|
5756
5930
|
}
|
|
5757
5931
|
function checkpointDir(projectRoot, name) {
|
|
5758
|
-
return
|
|
5932
|
+
return join10(projectCheckpointsDir(projectRoot), name);
|
|
5759
5933
|
}
|
|
5760
5934
|
async function readManifest(dir) {
|
|
5761
5935
|
try {
|
|
5762
|
-
const raw = await
|
|
5936
|
+
const raw = await readFile7(join10(dir, "manifest.json"), "utf8");
|
|
5763
5937
|
const m = JSON.parse(raw);
|
|
5764
5938
|
if (m.schema !== 2 && m.schema !== 3) return null;
|
|
5765
5939
|
return m;
|
|
@@ -5776,7 +5950,7 @@ async function listCheckpointsInDir(root) {
|
|
|
5776
5950
|
}
|
|
5777
5951
|
const out = [];
|
|
5778
5952
|
for (const name of entries) {
|
|
5779
|
-
const dir =
|
|
5953
|
+
const dir = join10(root, name);
|
|
5780
5954
|
const manifest = await readManifest(dir);
|
|
5781
5955
|
if (manifest) out.push({ name, dir, manifest });
|
|
5782
5956
|
}
|
|
@@ -5795,7 +5969,7 @@ async function listAllCheckpoints() {
|
|
|
5795
5969
|
}
|
|
5796
5970
|
const out = [];
|
|
5797
5971
|
for (const segment of segments) {
|
|
5798
|
-
const items = await listCheckpointsInDir(
|
|
5972
|
+
const items = await listCheckpointsInDir(join10(CHECKPOINTS_ROOT, segment));
|
|
5799
5973
|
if (items.length > 0) out.push({ segment, items });
|
|
5800
5974
|
}
|
|
5801
5975
|
return out;
|
|
@@ -5815,7 +5989,7 @@ async function listAllCheckpointImages() {
|
|
|
5815
5989
|
}
|
|
5816
5990
|
const out = /* @__PURE__ */ new Set();
|
|
5817
5991
|
for (const proj of projectDirs) {
|
|
5818
|
-
const projPath =
|
|
5992
|
+
const projPath = join10(CHECKPOINTS_ROOT, proj);
|
|
5819
5993
|
let names;
|
|
5820
5994
|
try {
|
|
5821
5995
|
names = (await readdir5(projPath, { withFileTypes: true })).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
@@ -5823,7 +5997,7 @@ async function listAllCheckpointImages() {
|
|
|
5823
5997
|
continue;
|
|
5824
5998
|
}
|
|
5825
5999
|
for (const name of names) {
|
|
5826
|
-
const manifest = await readManifest(
|
|
6000
|
+
const manifest = await readManifest(join10(projPath, name));
|
|
5827
6001
|
if (manifest) out.add(manifest.image);
|
|
5828
6002
|
}
|
|
5829
6003
|
}
|
|
@@ -5984,7 +6158,7 @@ async function createCheckpoint(opts) {
|
|
|
5984
6158
|
cliVersion: stamp.cliVersion,
|
|
5985
6159
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
5986
6160
|
};
|
|
5987
|
-
await writeFile32(
|
|
6161
|
+
await writeFile32(join10(dir, "manifest.json"), JSON.stringify(manifest, null, 2) + "\n", "utf8");
|
|
5988
6162
|
if (opts.setDefault) {
|
|
5989
6163
|
await setConfigValue("project", "box.defaultCheckpointDocker", name, opts.projectRoot);
|
|
5990
6164
|
log(`set project default checkpoint (box.defaultCheckpointDocker) -> ${name}`);
|
|
@@ -6001,9 +6175,9 @@ async function flattenImage(sourceTag, destTag, log) {
|
|
|
6001
6175
|
if (create.exitCode !== 0) {
|
|
6002
6176
|
throw new CheckpointError(`docker create for flatten failed`, create.stdout, create.stderr);
|
|
6003
6177
|
}
|
|
6004
|
-
const scratch = await mkdtemp3(
|
|
6178
|
+
const scratch = await mkdtemp3(join10(tmpdir3(), "agentbox-flatten-"));
|
|
6005
6179
|
try {
|
|
6006
|
-
const rootfsPath =
|
|
6180
|
+
const rootfsPath = join10(scratch, "rootfs.tar");
|
|
6007
6181
|
log(`exporting rootfs of ${sourceTag} to ${rootfsPath}`);
|
|
6008
6182
|
const exp = await execa11("docker", ["export", "-o", rootfsPath, tmpName], { reject: false });
|
|
6009
6183
|
if (exp.exitCode !== 0) {
|
|
@@ -6016,11 +6190,11 @@ async function flattenImage(sourceTag, destTag, log) {
|
|
|
6016
6190
|
"ADD rootfs.tar /",
|
|
6017
6191
|
...renderConfigDirectives(cfg)
|
|
6018
6192
|
];
|
|
6019
|
-
await writeFile32(
|
|
6193
|
+
await writeFile32(join10(scratch, "Dockerfile"), lines.join("\n") + "\n", "utf8");
|
|
6020
6194
|
log(`building flattened ${destTag} from rootfs.tar (FROM scratch)`);
|
|
6021
6195
|
const build = await execa11(
|
|
6022
6196
|
"docker",
|
|
6023
|
-
["build", "-t", destTag, "-f",
|
|
6197
|
+
["build", "-t", destTag, "-f", join10(scratch, "Dockerfile"), scratch],
|
|
6024
6198
|
{ reject: false }
|
|
6025
6199
|
);
|
|
6026
6200
|
if (build.exitCode !== 0) {
|
|
@@ -6111,10 +6285,10 @@ async function ensureHomeOwnedByVscode(container) {
|
|
|
6111
6285
|
{ reject: false }
|
|
6112
6286
|
);
|
|
6113
6287
|
}
|
|
6114
|
-
var STATE_DIR22 =
|
|
6115
|
-
var PID_FILE =
|
|
6116
|
-
var LOG_FILE =
|
|
6117
|
-
var RELAY_HOME_DIR =
|
|
6288
|
+
var STATE_DIR22 = join11(homedir9(), ".agentbox");
|
|
6289
|
+
var PID_FILE = join11(STATE_DIR22, "relay.pid");
|
|
6290
|
+
var LOG_FILE = join11(STATE_DIR22, "relay.log");
|
|
6291
|
+
var RELAY_HOME_DIR = join11(STATE_DIR22, "relay");
|
|
6118
6292
|
var PORT = DEFAULT_RELAY_PORT;
|
|
6119
6293
|
var ENDPOINT = {
|
|
6120
6294
|
// host.docker.internal is the Docker Desktop / OrbStack-supplied alias for
|
|
@@ -6281,13 +6455,13 @@ async function stageRelayHome(version, log) {
|
|
|
6281
6455
|
if (process.env.AGENTBOX_RELAY_BIN || process.env.AGENTBOX_CLI_ENTRY) return null;
|
|
6282
6456
|
const cliRoot = findCliRoot(dirname3(fileURLToPath(import.meta.url)));
|
|
6283
6457
|
if (cliRoot === null) return null;
|
|
6284
|
-
const homeDir =
|
|
6285
|
-
const stagedEntry =
|
|
6286
|
-
const stagedBin =
|
|
6458
|
+
const homeDir = join11(RELAY_HOME_DIR, version);
|
|
6459
|
+
const stagedEntry = join11(homeDir, "dist", "index.js");
|
|
6460
|
+
const stagedBin = join11(homeDir, "runtime", "relay", "bin.cjs");
|
|
6287
6461
|
if (existsSync2(stagedEntry) && existsSync2(stagedBin)) {
|
|
6288
6462
|
return { relayBin: stagedBin, cliEntry: stagedEntry };
|
|
6289
6463
|
}
|
|
6290
|
-
const nodeModules = resolveDepRoot(
|
|
6464
|
+
const nodeModules = resolveDepRoot(join11(cliRoot, "dist", "index.js"));
|
|
6291
6465
|
if (nodeModules === null) return null;
|
|
6292
6466
|
const tmpDir = `${homeDir}.tmp-${String(process.pid)}`;
|
|
6293
6467
|
try {
|
|
@@ -6295,10 +6469,10 @@ async function stageRelayHome(version, log) {
|
|
|
6295
6469
|
await rm5(tmpDir, { recursive: true, force: true });
|
|
6296
6470
|
await mkdir6(tmpDir, { recursive: true });
|
|
6297
6471
|
for (const sub of ["dist", "runtime", "share"]) {
|
|
6298
|
-
const src =
|
|
6299
|
-
if (existsSync2(src)) await cp(src,
|
|
6472
|
+
const src = join11(cliRoot, sub);
|
|
6473
|
+
if (existsSync2(src)) await cp(src, join11(tmpDir, sub), { recursive: true });
|
|
6300
6474
|
}
|
|
6301
|
-
await cp(nodeModules,
|
|
6475
|
+
await cp(nodeModules, join11(tmpDir, "node_modules"), { recursive: true, dereference: true });
|
|
6302
6476
|
await rm5(homeDir, { recursive: true, force: true });
|
|
6303
6477
|
await rename3(tmpDir, homeDir);
|
|
6304
6478
|
} catch (err) {
|
|
@@ -6317,7 +6491,7 @@ async function stageRelayHome(version, log) {
|
|
|
6317
6491
|
}
|
|
6318
6492
|
function findCliRoot(moduleDir) {
|
|
6319
6493
|
for (const root of [resolve22(moduleDir, ".."), resolve22(moduleDir, "..", "..")]) {
|
|
6320
|
-
if (existsSync2(
|
|
6494
|
+
if (existsSync2(join11(root, "dist", "index.js")) && existsSync2(join11(root, "runtime", "relay", "bin.cjs"))) {
|
|
6321
6495
|
return root;
|
|
6322
6496
|
}
|
|
6323
6497
|
}
|
|
@@ -6332,7 +6506,7 @@ function resolveDepRoot(fromFile) {
|
|
|
6332
6506
|
const idx = main.lastIndexOf(marker);
|
|
6333
6507
|
if (idx === -1) return null;
|
|
6334
6508
|
const nm = main.slice(0, idx + marker.length - 1);
|
|
6335
|
-
return existsSync2(
|
|
6509
|
+
return existsSync2(join11(nm, "commander")) ? nm : null;
|
|
6336
6510
|
} catch {
|
|
6337
6511
|
return null;
|
|
6338
6512
|
}
|
|
@@ -6346,7 +6520,7 @@ async function gcOldRelayHomes(keepVersion) {
|
|
|
6346
6520
|
}
|
|
6347
6521
|
for (const name of entries) {
|
|
6348
6522
|
if (name === keepVersion) continue;
|
|
6349
|
-
await rm5(
|
|
6523
|
+
await rm5(join11(RELAY_HOME_DIR, name), { recursive: true, force: true }).catch(() => {
|
|
6350
6524
|
});
|
|
6351
6525
|
}
|
|
6352
6526
|
}
|
|
@@ -6457,7 +6631,7 @@ function fetchHealthz(timeoutMs) {
|
|
|
6457
6631
|
}
|
|
6458
6632
|
async function readPidFile() {
|
|
6459
6633
|
try {
|
|
6460
|
-
const text = await
|
|
6634
|
+
const text = await readFile8(PID_FILE, "utf8");
|
|
6461
6635
|
const pid = Number.parseInt(text.trim(), 10);
|
|
6462
6636
|
return Number.isFinite(pid) && pid > 0 ? pid : null;
|
|
6463
6637
|
} catch {
|
|
@@ -6803,7 +6977,7 @@ async function pathExists6(p) {
|
|
|
6803
6977
|
async function buildIdentityMounts() {
|
|
6804
6978
|
const home = homedir10();
|
|
6805
6979
|
const candidates = [
|
|
6806
|
-
{ src:
|
|
6980
|
+
{ src: join12(home, ".gitconfig"), dst: "/home/vscode/.gitconfig", readOnly: true }
|
|
6807
6981
|
];
|
|
6808
6982
|
const out = [];
|
|
6809
6983
|
for (const c of candidates) {
|
|
@@ -6820,7 +6994,7 @@ async function createBox(opts) {
|
|
|
6820
6994
|
if (!await pathExists6(workspace)) {
|
|
6821
6995
|
throw new Error(`workspace does not exist: ${workspace}`);
|
|
6822
6996
|
}
|
|
6823
|
-
const cfgPath =
|
|
6997
|
+
const cfgPath = join12(workspace, "agentbox.yaml");
|
|
6824
6998
|
if (await pathExists6(cfgPath)) {
|
|
6825
6999
|
try {
|
|
6826
7000
|
const cfg = await loadConfig(cfgPath);
|
|
@@ -6900,12 +7074,35 @@ async function createBox(opts) {
|
|
|
6900
7074
|
}
|
|
6901
7075
|
let projectIndex;
|
|
6902
7076
|
if (opts.projectRoot) {
|
|
6903
|
-
projectIndex =
|
|
7077
|
+
projectIndex = await reserveProjectIndex(
|
|
7078
|
+
{ id, name, container: containerName, image: imageRef, workspacePath: workspace, createdAt },
|
|
7079
|
+
opts.projectRoot
|
|
7080
|
+
);
|
|
6904
7081
|
}
|
|
6905
7082
|
const repoCarryOvers = [];
|
|
6906
7083
|
const gitWorktreeRecords = [];
|
|
7084
|
+
const restoreWorktreePlans = [];
|
|
6907
7085
|
if (checkpointImage && restoredWorktrees && restoredWorktrees.length > 0) {
|
|
6908
|
-
|
|
7086
|
+
for (const w of restoredWorktrees) {
|
|
7087
|
+
const branchBase = w.kind === "root" ? `agentbox/${name}` : `agentbox/${name}--${w.relPathFromWorkspace.replace(/[^A-Za-z0-9._-]+/g, "_")}`;
|
|
7088
|
+
const freshBranch = await pickFreshBranch(w.hostMainRepo, branchBase);
|
|
7089
|
+
const freshGitWorktreePath = gitWorktreePathFor(freshBranch);
|
|
7090
|
+
restoreWorktreePlans.push({
|
|
7091
|
+
hostMainRepo: w.hostMainRepo,
|
|
7092
|
+
kind: w.kind,
|
|
7093
|
+
bakedGitWorktreePath: w.gitWorktreePath,
|
|
7094
|
+
freshBranch,
|
|
7095
|
+
freshGitWorktreePath
|
|
7096
|
+
});
|
|
7097
|
+
gitWorktreeRecords.push({
|
|
7098
|
+
kind: w.kind,
|
|
7099
|
+
hostMainRepo: w.hostMainRepo,
|
|
7100
|
+
containerPath: w.containerPath,
|
|
7101
|
+
gitWorktreePath: freshGitWorktreePath,
|
|
7102
|
+
branch: freshBranch,
|
|
7103
|
+
relPathFromWorkspace: w.relPathFromWorkspace
|
|
7104
|
+
});
|
|
7105
|
+
}
|
|
6909
7106
|
}
|
|
6910
7107
|
if (!checkpointImage) {
|
|
6911
7108
|
const repos = await detectGitRepos(workspace);
|
|
@@ -7013,7 +7210,7 @@ async function createBox(opts) {
|
|
|
7013
7210
|
log(`seeded claude credentials into ${claudeSpec.volume} from host backup`);
|
|
7014
7211
|
}
|
|
7015
7212
|
const claudeMounts = buildClaudeMounts(claudeSpec, process.env);
|
|
7016
|
-
const wantCodex = opts.codexConfig !== void 0 || await pathExists6(
|
|
7213
|
+
const wantCodex = opts.codexConfig !== void 0 || await pathExists6(join12(homedir10(), ".codex"));
|
|
7017
7214
|
let codexMounts;
|
|
7018
7215
|
let codexConfigVolume;
|
|
7019
7216
|
if (wantCodex) {
|
|
@@ -7033,7 +7230,7 @@ async function createBox(opts) {
|
|
|
7033
7230
|
codexMounts = buildCodexMounts(codexSpec, process.env);
|
|
7034
7231
|
codexConfigVolume = codexSpec.volume;
|
|
7035
7232
|
}
|
|
7036
|
-
const wantOpencode = opts.opencodeConfig !== void 0 || await pathExists6(
|
|
7233
|
+
const wantOpencode = opts.opencodeConfig !== void 0 || await pathExists6(join12(homedir10(), ".config", "opencode")) || await pathExists6(join12(homedir10(), ".local", "share", "opencode"));
|
|
7037
7234
|
let opencodeMounts;
|
|
7038
7235
|
let opencodeConfigVolume;
|
|
7039
7236
|
if (wantOpencode) {
|
|
@@ -7054,9 +7251,9 @@ async function createBox(opts) {
|
|
|
7054
7251
|
opencodeConfigVolume = opencodeSpec.volume;
|
|
7055
7252
|
}
|
|
7056
7253
|
const boxDir = boxRunDirFor({ id, name, projectIndex });
|
|
7057
|
-
const socketDir =
|
|
7058
|
-
const socketPath =
|
|
7059
|
-
const mergedExportDir =
|
|
7254
|
+
const socketDir = join12(boxDir, "run");
|
|
7255
|
+
const socketPath = join12(socketDir, "ctl.sock");
|
|
7256
|
+
const mergedExportDir = join12(boxDir, "workspace");
|
|
7060
7257
|
await mkdir7(socketDir, { recursive: true });
|
|
7061
7258
|
await mkdir7(mergedExportDir, { recursive: true });
|
|
7062
7259
|
const extraVolumes = await buildIdentityMounts();
|
|
@@ -7145,6 +7342,36 @@ async function createBox(opts) {
|
|
|
7145
7342
|
effectiveLimits = { ...appliedLimits, disk: null };
|
|
7146
7343
|
}
|
|
7147
7344
|
}
|
|
7345
|
+
const baseRecord = {
|
|
7346
|
+
id,
|
|
7347
|
+
name,
|
|
7348
|
+
container: containerName,
|
|
7349
|
+
image: imageRef,
|
|
7350
|
+
workspacePath: workspace,
|
|
7351
|
+
snapshotDir,
|
|
7352
|
+
socketPath,
|
|
7353
|
+
claudeConfigVolume: claudeSpec.volume,
|
|
7354
|
+
codexConfigVolume,
|
|
7355
|
+
opencodeConfigVolume,
|
|
7356
|
+
vscodeServerVolume: vscodeServerVolumeName(id),
|
|
7357
|
+
cursorServerVolume: cursorServerVolumeName(id),
|
|
7358
|
+
relayToken: relayUp ? relayToken : void 0,
|
|
7359
|
+
gitWorktrees: gitWorktreeRecords.length > 0 ? gitWorktreeRecords : void 0,
|
|
7360
|
+
withPlaywright: opts.withPlaywright ? true : void 0,
|
|
7361
|
+
withEnv: opts.withEnv ? true : void 0,
|
|
7362
|
+
vncEnabled: vncEnabled ? true : void 0,
|
|
7363
|
+
vncContainerPort: vncEnabled ? VNC_CONTAINER_PORT : void 0,
|
|
7364
|
+
vncPassword,
|
|
7365
|
+
webContainerPort: WEB_CONTAINER_PORT,
|
|
7366
|
+
dockerVolume,
|
|
7367
|
+
dockerCacheShared: dockerCacheShared || void 0,
|
|
7368
|
+
projectRoot: opts.projectRoot,
|
|
7369
|
+
projectIndex,
|
|
7370
|
+
checkpointImage,
|
|
7371
|
+
checkpointSource,
|
|
7372
|
+
resourceLimits: persistableLimits(effectiveLimits),
|
|
7373
|
+
createdAt
|
|
7374
|
+
};
|
|
7148
7375
|
await runBox({
|
|
7149
7376
|
name: containerName,
|
|
7150
7377
|
image: imageRef,
|
|
@@ -7164,6 +7391,7 @@ async function createBox(opts) {
|
|
|
7164
7391
|
}
|
|
7165
7392
|
});
|
|
7166
7393
|
log(`container ${containerName} started`);
|
|
7394
|
+
await recordBox(baseRecord);
|
|
7167
7395
|
if (gitWorktreeRecords.length > 0) {
|
|
7168
7396
|
await chownGitBindParents({
|
|
7169
7397
|
container: containerName,
|
|
@@ -7189,6 +7417,7 @@ async function createBox(opts) {
|
|
|
7189
7417
|
if (opts.useBranch !== void 0) {
|
|
7190
7418
|
log(`seedWorkspace failed for --use-branch ${opts.useBranch}; cleaning up the box`);
|
|
7191
7419
|
await execa14("docker", ["rm", "-f", containerName], { reject: false });
|
|
7420
|
+
await removeBoxRecord(id);
|
|
7192
7421
|
for (const w of gitWorktreeRecords) {
|
|
7193
7422
|
await removeInBoxWorktree({
|
|
7194
7423
|
hostMainRepo: w.hostMainRepo,
|
|
@@ -7204,21 +7433,27 @@ async function createBox(opts) {
|
|
|
7204
7433
|
const source = snapshotDir ?? workspace;
|
|
7205
7434
|
await seedWorkspaceFromDir({ container: containerName, hostSource: source, onLog: log });
|
|
7206
7435
|
}
|
|
7207
|
-
} else if (
|
|
7436
|
+
} else if (restoreWorktreePlans.length > 0) {
|
|
7437
|
+
await regenerateRestoredWorktrees({
|
|
7438
|
+
container: containerName,
|
|
7439
|
+
plans: restoreWorktreePlans,
|
|
7440
|
+
fromBranch: opts.fromBranch,
|
|
7441
|
+
onLog: log
|
|
7442
|
+
});
|
|
7208
7443
|
await bindWorktrees(
|
|
7209
7444
|
containerName,
|
|
7210
|
-
|
|
7445
|
+
gitWorktreeRecords.map((w) => ({
|
|
7211
7446
|
kind: w.kind,
|
|
7212
7447
|
containerPath: w.containerPath,
|
|
7213
7448
|
gitWorktreePath: w.gitWorktreePath
|
|
7214
7449
|
})),
|
|
7215
7450
|
log
|
|
7216
7451
|
);
|
|
7217
|
-
log("re-bound /workspace from checkpoint image");
|
|
7452
|
+
log("re-bound /workspace from checkpoint image (fresh per-box worktree)");
|
|
7218
7453
|
if (opts.resyncOnStart !== false) {
|
|
7219
7454
|
const repos = await resyncWorkspaceFromHost({
|
|
7220
7455
|
container: containerName,
|
|
7221
|
-
worktrees:
|
|
7456
|
+
worktrees: gitWorktreeRecords,
|
|
7222
7457
|
onLog: log
|
|
7223
7458
|
});
|
|
7224
7459
|
resyncResult = {
|
|
@@ -7233,15 +7468,15 @@ async function createBox(opts) {
|
|
|
7233
7468
|
}
|
|
7234
7469
|
await repairIdeOwnership(containerName);
|
|
7235
7470
|
log(".vscode-server + .cursor-server ownership verified");
|
|
7236
|
-
const ctl = await launchCtlDaemon(containerName, socketPath);
|
|
7237
|
-
if (ctl.up) log("agentbox-ctl daemon up");
|
|
7238
|
-
else log(`agentbox-ctl daemon did not become reachable: ${ctl.reason}`);
|
|
7239
7471
|
const dockerd = await launchDockerdDaemon(containerName);
|
|
7240
7472
|
if (dockerd.up) {
|
|
7241
7473
|
log(`dockerd up (data root=${dockerVolume})`);
|
|
7242
7474
|
} else {
|
|
7243
7475
|
log(`dockerd did not become ready: ${dockerd.reason}`);
|
|
7244
7476
|
}
|
|
7477
|
+
const ctl = await launchCtlDaemon(containerName, socketPath);
|
|
7478
|
+
if (ctl.up) log("agentbox-ctl daemon up");
|
|
7479
|
+
else log(`agentbox-ctl daemon did not become reachable: ${ctl.reason}`);
|
|
7245
7480
|
if (opts.withPlaywright) {
|
|
7246
7481
|
log("installing @playwright/cli@latest (--with-playwright)");
|
|
7247
7482
|
const result = await execa14(
|
|
@@ -7360,41 +7595,14 @@ async function createBox(opts) {
|
|
|
7360
7595
|
}
|
|
7361
7596
|
}
|
|
7362
7597
|
const record = {
|
|
7363
|
-
|
|
7364
|
-
name,
|
|
7365
|
-
container: containerName,
|
|
7366
|
-
image: imageRef,
|
|
7367
|
-
workspacePath: workspace,
|
|
7368
|
-
snapshotDir,
|
|
7369
|
-
socketPath,
|
|
7370
|
-
claudeConfigVolume: claudeSpec.volume,
|
|
7371
|
-
codexConfigVolume,
|
|
7372
|
-
opencodeConfigVolume,
|
|
7373
|
-
vscodeServerVolume: vscodeServerVolumeName(id),
|
|
7374
|
-
cursorServerVolume: cursorServerVolumeName(id),
|
|
7375
|
-
relayToken: relayUp ? relayToken : void 0,
|
|
7376
|
-
gitWorktrees: gitWorktreeRecords.length > 0 ? gitWorktreeRecords : void 0,
|
|
7377
|
-
withPlaywright: opts.withPlaywright ? true : void 0,
|
|
7378
|
-
withEnv: opts.withEnv ? true : void 0,
|
|
7598
|
+
...baseRecord,
|
|
7379
7599
|
carry: carrySummary,
|
|
7380
|
-
vncEnabled: vncEnabled ? true : void 0,
|
|
7381
|
-
vncContainerPort: vncEnabled ? VNC_CONTAINER_PORT : void 0,
|
|
7382
7600
|
vncHostPort: vncHostPort ?? void 0,
|
|
7383
|
-
vncPassword,
|
|
7384
|
-
webContainerPort: WEB_CONTAINER_PORT,
|
|
7385
7601
|
webHostPort: webHostPort ?? void 0,
|
|
7386
7602
|
portlessAlias: portlessAliasName,
|
|
7387
7603
|
portlessUrl,
|
|
7388
7604
|
portlessVncAlias: portlessVncAliasName,
|
|
7389
|
-
portlessVncUrl
|
|
7390
|
-
dockerVolume,
|
|
7391
|
-
dockerCacheShared: dockerCacheShared || void 0,
|
|
7392
|
-
projectRoot: opts.projectRoot,
|
|
7393
|
-
projectIndex,
|
|
7394
|
-
checkpointImage,
|
|
7395
|
-
checkpointSource,
|
|
7396
|
-
resourceLimits: persistableLimits(effectiveLimits),
|
|
7397
|
-
createdAt
|
|
7605
|
+
portlessVncUrl
|
|
7398
7606
|
};
|
|
7399
7607
|
await recordBox(record);
|
|
7400
7608
|
return { record, imageBuilt: built, resync: resyncResult };
|
|
@@ -7580,7 +7788,7 @@ async function getBoxEndpoints(record, engine, persisted) {
|
|
|
7580
7788
|
for (const svc of persistedServices) pushService(svc.name, svc.port);
|
|
7581
7789
|
} else {
|
|
7582
7790
|
try {
|
|
7583
|
-
const cfg = await loadConfig(
|
|
7791
|
+
const cfg = await loadConfig(join13(record.workspacePath, "agentbox.yaml"));
|
|
7584
7792
|
if (!webServiceName) {
|
|
7585
7793
|
webServiceName = cfg.services.find((s) => s.expose)?.name ?? null;
|
|
7586
7794
|
}
|
|
@@ -7731,9 +7939,9 @@ async function resyncBox(idOrName, onLog) {
|
|
|
7731
7939
|
async function startBox(idOrName) {
|
|
7732
7940
|
const box = await resolveBox(idOrName);
|
|
7733
7941
|
for (const w of box.gitWorktrees ?? []) {
|
|
7734
|
-
if (!await pathExists7(
|
|
7942
|
+
if (!await pathExists7(join14(w.hostMainRepo, ".git"))) {
|
|
7735
7943
|
throw new Error(
|
|
7736
|
-
`main repo for box worktree missing: ${
|
|
7944
|
+
`main repo for box worktree missing: ${join14(w.hostMainRepo, ".git")} (recreate the box)`
|
|
7737
7945
|
);
|
|
7738
7946
|
}
|
|
7739
7947
|
}
|
|
@@ -7749,12 +7957,12 @@ async function startBox(idOrName) {
|
|
|
7749
7957
|
);
|
|
7750
7958
|
}
|
|
7751
7959
|
await ensureHomeOwnedByVscode(box.container);
|
|
7752
|
-
if (box.socketPath) {
|
|
7753
|
-
await launchCtlDaemon(box.container, box.socketPath);
|
|
7754
|
-
}
|
|
7755
7960
|
if (box.dockerVolume) {
|
|
7756
7961
|
await launchDockerdDaemon(box.container);
|
|
7757
7962
|
}
|
|
7963
|
+
if (box.socketPath) {
|
|
7964
|
+
await launchCtlDaemon(box.container, box.socketPath);
|
|
7965
|
+
}
|
|
7758
7966
|
if (box.vncEnabled) {
|
|
7759
7967
|
await launchVncDaemon(box.container);
|
|
7760
7968
|
const freshHostPort = await publishedHostPort(box.container, VNC_CONTAINER_PORT);
|
|
@@ -7902,16 +8110,13 @@ async function destroyBox(idOrName, opts = {}) {
|
|
|
7902
8110
|
} catch {
|
|
7903
8111
|
}
|
|
7904
8112
|
}
|
|
7905
|
-
const
|
|
7906
|
-
|
|
7907
|
-
|
|
7908
|
-
|
|
7909
|
-
|
|
7910
|
-
|
|
7911
|
-
|
|
7912
|
-
});
|
|
7913
|
-
} catch {
|
|
7914
|
-
}
|
|
8113
|
+
for (const w of box.gitWorktrees ?? []) {
|
|
8114
|
+
try {
|
|
8115
|
+
await removeInBoxWorktree({
|
|
8116
|
+
hostMainRepo: w.hostMainRepo,
|
|
8117
|
+
gitWorktreePath: w.gitWorktreePath
|
|
8118
|
+
});
|
|
8119
|
+
} catch {
|
|
7915
8120
|
}
|
|
7916
8121
|
}
|
|
7917
8122
|
const beforeContainer = await inspectContainerStatus(box.container);
|
|
@@ -7962,7 +8167,7 @@ async function destroyBox(idOrName, opts = {}) {
|
|
|
7962
8167
|
async function listSnapshotDirs() {
|
|
7963
8168
|
try {
|
|
7964
8169
|
const entries = await readdir7(SNAPSHOTS_ROOT, { withFileTypes: true });
|
|
7965
|
-
return entries.filter((e) => e.isDirectory()).map((e) =>
|
|
8170
|
+
return entries.filter((e) => e.isDirectory()).map((e) => join14(SNAPSHOTS_ROOT, e.name));
|
|
7966
8171
|
} catch {
|
|
7967
8172
|
return [];
|
|
7968
8173
|
}
|
|
@@ -7970,7 +8175,7 @@ async function listSnapshotDirs() {
|
|
|
7970
8175
|
async function listBoxDirs() {
|
|
7971
8176
|
try {
|
|
7972
8177
|
const entries = await readdir7(BOXES_ROOT, { withFileTypes: true });
|
|
7973
|
-
return entries.filter((e) => e.isDirectory()).map((e) =>
|
|
8178
|
+
return entries.filter((e) => e.isDirectory()).map((e) => join14(BOXES_ROOT, e.name));
|
|
7974
8179
|
} catch {
|
|
7975
8180
|
return [];
|
|
7976
8181
|
}
|
|
@@ -8155,7 +8360,7 @@ async function volumeSizeBytes(name) {
|
|
|
8155
8360
|
if (!name) return null;
|
|
8156
8361
|
const engine = await detectEngine();
|
|
8157
8362
|
if (engine === "orbstack") {
|
|
8158
|
-
const live =
|
|
8363
|
+
const live = join15(homedir11(), "OrbStack", "docker", "volumes", name);
|
|
8159
8364
|
const sz = await duBytes(live);
|
|
8160
8365
|
if (sz !== null) return sz;
|
|
8161
8366
|
}
|
|
@@ -8218,7 +8423,7 @@ async function allCheckpointImagesBytes() {
|
|
|
8218
8423
|
return any ? total : null;
|
|
8219
8424
|
}
|
|
8220
8425
|
async function agentboxHomeBytes() {
|
|
8221
|
-
return duBytes(
|
|
8426
|
+
return duBytes(join15(homedir11(), ".agentbox"));
|
|
8222
8427
|
}
|
|
8223
8428
|
function limitsFromRecord(record) {
|
|
8224
8429
|
const r = record.resourceLimits;
|
|
@@ -8604,7 +8809,7 @@ async function walkFiles(root, prefix = "") {
|
|
|
8604
8809
|
const out = [];
|
|
8605
8810
|
for (const ent of entries) {
|
|
8606
8811
|
const rel = prefix ? `${prefix}/${ent.name}` : ent.name;
|
|
8607
|
-
const full =
|
|
8812
|
+
const full = join16(root, ent.name);
|
|
8608
8813
|
if (ent.isDirectory()) {
|
|
8609
8814
|
out.push(...await walkFiles(full, rel));
|
|
8610
8815
|
} else if (ent.isFile()) {
|
|
@@ -8620,20 +8825,20 @@ async function walkFiles(root, prefix = "") {
|
|
|
8620
8825
|
return out;
|
|
8621
8826
|
}
|
|
8622
8827
|
async function hashFile(absPath) {
|
|
8623
|
-
const buf = await
|
|
8624
|
-
return
|
|
8828
|
+
const buf = await readFile9(absPath);
|
|
8829
|
+
return createHash32("sha256").update(buf).digest("hex");
|
|
8625
8830
|
}
|
|
8626
8831
|
async function buildHostSet(name, hostDir, boxDst) {
|
|
8627
8832
|
if (hostDir === null) return { dst: boxDst, files: {}, hostDir: null };
|
|
8628
8833
|
const rels = await walkFiles(hostDir);
|
|
8629
8834
|
const files = {};
|
|
8630
8835
|
for (const rel of rels) {
|
|
8631
|
-
files[rel] = await hashFile(
|
|
8836
|
+
files[rel] = await hashFile(join16(hostDir, rel));
|
|
8632
8837
|
}
|
|
8633
8838
|
return { dst: boxDst, files, hostDir };
|
|
8634
8839
|
}
|
|
8635
8840
|
async function buildHostSyncManifest(workspacePath, hostHome = homedir12()) {
|
|
8636
|
-
const workflowsDir =
|
|
8841
|
+
const workflowsDir = join16(hostHome, ".claude", "workflows");
|
|
8637
8842
|
const workflowsHost = await pathExists8(workflowsDir) ? workflowsDir : null;
|
|
8638
8843
|
const memoryHost = await resolveClaudeMemoryDir(workspacePath, hostHome);
|
|
8639
8844
|
const [workflows, memory] = await Promise.all([
|
|
@@ -8655,7 +8860,7 @@ function computeSyncDelta(host, box) {
|
|
|
8655
8860
|
uploads.push({
|
|
8656
8861
|
set: name,
|
|
8657
8862
|
rel,
|
|
8658
|
-
absSrc:
|
|
8863
|
+
absSrc: join16(hostSet.hostDir, rel),
|
|
8659
8864
|
dst: `${hostSet.dst}/${rel}`
|
|
8660
8865
|
});
|
|
8661
8866
|
}
|
|
@@ -8674,15 +8879,15 @@ async function stageDynamicSyncTarball(uploads) {
|
|
|
8674
8879
|
return { tarballPath: null, cleanup: async () => {
|
|
8675
8880
|
} };
|
|
8676
8881
|
}
|
|
8677
|
-
const stageDir = await mkdtemp4(
|
|
8882
|
+
const stageDir = await mkdtemp4(join16(tmpdir4(), "agentbox-dynsync-stage-"));
|
|
8678
8883
|
let tarballPath = null;
|
|
8679
8884
|
try {
|
|
8680
8885
|
for (const up of uploads) {
|
|
8681
|
-
const target =
|
|
8886
|
+
const target = join16(stageDir, up.set, up.rel);
|
|
8682
8887
|
await mkdir8(dirname32(target), { recursive: true });
|
|
8683
8888
|
await copyFile2(up.absSrc, target);
|
|
8684
8889
|
}
|
|
8685
|
-
tarballPath =
|
|
8890
|
+
tarballPath = join16(tmpdir4(), `agentbox-dynsync-${basename6(stageDir)}.tar.gz`);
|
|
8686
8891
|
await execa19("tar", ["-czf", tarballPath, "-C", stageDir, "."], {
|
|
8687
8892
|
env: { ...process.env, COPYFILE_DISABLE: "1" }
|
|
8688
8893
|
});
|
|
@@ -8748,6 +8953,7 @@ export {
|
|
|
8748
8953
|
renderPortsTable,
|
|
8749
8954
|
loadCarrySection,
|
|
8750
8955
|
resolveAgentLauncher,
|
|
8956
|
+
UserFacingError,
|
|
8751
8957
|
BoxNotFoundError,
|
|
8752
8958
|
AmbiguousBoxError,
|
|
8753
8959
|
generateBoxId,
|
|
@@ -8804,6 +9010,7 @@ export {
|
|
|
8804
9010
|
encodeClaudeProjectsKey,
|
|
8805
9011
|
BOX_CLAUDE_PROJECT_DIR,
|
|
8806
9012
|
resolveClaudeMemoryDir,
|
|
9013
|
+
stageClaudeJsonOnlyForUpload,
|
|
8807
9014
|
stageClaudeStaticForUpload,
|
|
8808
9015
|
stageClaudeCredentialsForUpload,
|
|
8809
9016
|
stageCodexStaticForUpload,
|
|
@@ -8979,4 +9186,4 @@ export {
|
|
|
8979
9186
|
browserSessionActive,
|
|
8980
9187
|
ensureBoxBrowser
|
|
8981
9188
|
};
|
|
8982
|
-
//# sourceMappingURL=chunk-
|
|
9189
|
+
//# sourceMappingURL=chunk-TCS5HXJX.js.map
|