@madarco/agentbox 0.9.0 → 0.10.1

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 (40) hide show
  1. package/CHANGELOG.md +102 -0
  2. package/README.md +161 -0
  3. package/dist/{_cloud-attach-ZXBCNWJX.js → _cloud-attach-2DGI6FUA.js} +4 -4
  4. package/dist/{chunk-NCJP5MTN.js → chunk-CDKVD6UO.js} +239 -61
  5. package/dist/chunk-CDKVD6UO.js.map +1 -0
  6. package/dist/{chunk-GU5LW4B5.js → chunk-I7NOGCL4.js} +374 -62
  7. package/dist/chunk-I7NOGCL4.js.map +1 -0
  8. package/dist/{chunk-BXQMIEHC.js → chunk-M2UWJKFA.js} +255 -163
  9. package/dist/chunk-M2UWJKFA.js.map +1 -0
  10. package/dist/{chunk-KL36BRN4.js → chunk-PWUVHPN6.js} +66 -17
  11. package/dist/{chunk-KL36BRN4.js.map → chunk-PWUVHPN6.js.map} +1 -1
  12. package/dist/{dist-CX5CGVEB.js → dist-BD5QJRDC.js} +4 -4
  13. package/dist/{dist-GDHP34ZK.js → dist-BNI5PQYK.js} +16 -4
  14. package/dist/dist-BNI5PQYK.js.map +1 -0
  15. package/dist/{dist-32EZBYG4.js → dist-SBCQVFCE.js} +23 -3
  16. package/dist/{dist-XML54CNB.js → dist-SJHY3HYN.js} +31 -6
  17. package/dist/dist-SJHY3HYN.js.map +1 -0
  18. package/dist/index.js +1787 -528
  19. package/dist/index.js.map +1 -1
  20. package/dist/{prepared-state-CL4CWXQA-H5THETIM.js → prepared-state-MQHD3M5F-O5M4NIN4.js} +2 -2
  21. package/package.json +10 -8
  22. package/runtime/docker/apps/cli/share/agentbox-setup/SKILL.md +10 -9
  23. package/runtime/docker/packages/ctl/dist/bin.cjs +38 -3
  24. package/runtime/hetzner/agentbox-setup-skill.md +10 -9
  25. package/runtime/hetzner/ctl.cjs +38 -3
  26. package/runtime/relay/bin.cjs +41 -3
  27. package/runtime/vercel/agentbox-setup-skill.md +10 -9
  28. package/runtime/vercel/ctl.cjs +38 -3
  29. package/runtime/vercel/custom-system-CLAUDE.md +1 -4
  30. package/runtime/vercel/scripts/provision.sh +40 -0
  31. package/share/agentbox-setup/SKILL.md +10 -9
  32. package/dist/chunk-BXQMIEHC.js.map +0 -1
  33. package/dist/chunk-GU5LW4B5.js.map +0 -1
  34. package/dist/chunk-NCJP5MTN.js.map +0 -1
  35. package/dist/dist-GDHP34ZK.js.map +0 -1
  36. package/dist/dist-XML54CNB.js.map +0 -1
  37. /package/dist/{_cloud-attach-ZXBCNWJX.js.map → _cloud-attach-2DGI6FUA.js.map} +0 -0
  38. /package/dist/{dist-CX5CGVEB.js.map → dist-BD5QJRDC.js.map} +0 -0
  39. /package/dist/{dist-32EZBYG4.js.map → dist-SBCQVFCE.js.map} +0 -0
  40. /package/dist/{prepared-state-CL4CWXQA-H5THETIM.js.map → prepared-state-MQHD3M5F-O5M4NIN4.js.map} +0 -0
@@ -5,7 +5,6 @@ import {
5
5
  STATE_DIR,
6
6
  STATE_FILE,
7
7
  allocateProjectIndex,
8
- buildImage,
9
8
  computeDockerContextFingerprint,
10
9
  detectGitRepos,
11
10
  ensureImage,
@@ -13,19 +12,19 @@ import {
13
12
  imageExists,
14
13
  pickFreshBranch,
15
14
  preparedMatches,
15
+ pullOrBuild,
16
16
  readCliStamp,
17
17
  readPreparedDockerState,
18
18
  readState,
19
19
  recordBox,
20
- removeBoxRecord,
21
- writePreparedDockerState
22
- } from "./chunk-KL36BRN4.js";
20
+ removeBoxRecord
21
+ } from "./chunk-PWUVHPN6.js";
23
22
 
24
23
  // ../../packages/sandbox-docker/dist/index.js
25
24
  import { randomBytes as randomBytes3 } from "crypto";
26
25
  import { mkdir as mkdir7, stat as stat6 } from "fs/promises";
27
26
  import { homedir as homedir9 } from "os";
28
- import { basename as basename2, join as join10, resolve as resolve3 } from "path";
27
+ import { basename as basename3, join as join10, resolve as resolve3 } from "path";
29
28
  import { execa as execa13 } from "execa";
30
29
 
31
30
  // ../../packages/ctl/dist/index.js
@@ -744,6 +743,9 @@ var BUILT_IN_DEFAULTS = {
744
743
  isolateCodexConfig: false,
745
744
  isolateOpencodeConfig: false,
746
745
  image: "agentbox/box:dev",
746
+ // Mirrors BOX_IMAGE_REGISTRY in @agentbox/sandbox-docker. Empty disables the
747
+ // registry pull (always build the docker base image locally).
748
+ imageRegistry: "ghcr.io/madarco/agentbox/box",
747
749
  dockerCacheShared: false,
748
750
  memory: 0,
749
751
  cpus: 0,
@@ -758,10 +760,12 @@ var BUILT_IN_DEFAULTS = {
758
760
  maxLayers: 3
759
761
  },
760
762
  claude: {
761
- sessionName: "claude"
763
+ sessionName: "claude",
764
+ dangerouslySkipPermissions: true
762
765
  },
763
766
  codex: {
764
- sessionName: "codex"
767
+ sessionName: "codex",
768
+ dangerouslySkipPermissions: true
765
769
  },
766
770
  opencode: {
767
771
  sessionName: "opencode"
@@ -898,6 +902,12 @@ var KEY_REGISTRY = [
898
902
  description: "Box image ref (advanced).",
899
903
  advanced: true
900
904
  },
905
+ {
906
+ key: "box.imageRegistry",
907
+ type: "string",
908
+ description: "Registry repo to pull the prebuilt docker base image from before building locally. Empty = always build. Docker only (advanced).",
909
+ advanced: true
910
+ },
901
911
  {
902
912
  key: "box.dockerCacheShared",
903
913
  type: "bool",
@@ -949,11 +959,21 @@ var KEY_REGISTRY = [
949
959
  type: "string",
950
960
  description: "tmux session name for `agentbox claude`."
951
961
  },
962
+ {
963
+ key: "claude.dangerouslySkipPermissions",
964
+ type: "bool",
965
+ description: "Launch claude in new boxes with --dangerously-skip-permissions (auto-accept tool use). Safe because boxes are isolated; on by default. Override per-box with --no-dangerously-skip-permissions."
966
+ },
952
967
  {
953
968
  key: "codex.sessionName",
954
969
  type: "string",
955
970
  description: "tmux session name for `agentbox codex`."
956
971
  },
972
+ {
973
+ key: "codex.dangerouslySkipPermissions",
974
+ type: "bool",
975
+ description: "Launch codex in new boxes with --dangerously-bypass-approvals-and-sandbox (never prompt for approval). Safe because boxes are isolated; on by default. Override per-box with --no-dangerously-skip-permissions."
976
+ },
957
977
  {
958
978
  key: "opencode.sessionName",
959
979
  type: "string",
@@ -1637,7 +1657,7 @@ async function touchProjectMeta(absPath) {
1637
1657
 
1638
1658
  // ../../packages/sandbox-docker/dist/index.js
1639
1659
  import { chmod, mkdir as mkdir32, readFile as readFile32 } from "fs/promises";
1640
- import { join as join32 } from "path";
1660
+ import { basename as basename2, join as join32 } from "path";
1641
1661
  import { execa as execa4 } from "execa";
1642
1662
  import { spawnSync as spawnSync2 } from "child_process";
1643
1663
  import { stat as stat22 } from "fs/promises";
@@ -1662,7 +1682,7 @@ import { homedir as homedir6, platform } from "os";
1662
1682
  import { join as join7, resolve as resolve2 } from "path";
1663
1683
  import { mkdir as mkdir5, mkdtemp as mkdtemp2, readFile as readFile5, readdir as readdir32, rm as rm3, writeFile as writeFile22 } from "fs/promises";
1664
1684
  import { homedir as homedir7, tmpdir as tmpdir2 } from "os";
1665
- import { basename as basename3, join as join8 } from "path";
1685
+ import { basename as basename22, join as join8 } from "path";
1666
1686
  import { execa as execa10 } from "execa";
1667
1687
  import { stat as stat5 } from "fs/promises";
1668
1688
  import { execa as execa11 } from "execa";
@@ -1670,10 +1690,11 @@ import { execa as execa12 } from "execa";
1670
1690
  import { spawn } from "child_process";
1671
1691
  import { randomBytes as randomBytes22 } from "crypto";
1672
1692
  import { existsSync as existsSync2, openSync } from "fs";
1673
- import { mkdir as mkdir6, readFile as readFile6, unlink as unlink2, writeFile as writeFile32 } from "fs/promises";
1693
+ import { cp, mkdir as mkdir6, readFile as readFile6, readdir as readdir4, rename as rename3, rm as rm4, unlink as unlink2, writeFile as writeFile32 } from "fs/promises";
1674
1694
  import { request as httpRequest } from "http";
1695
+ import { createRequire } from "module";
1675
1696
  import { homedir as homedir8 } from "os";
1676
- import { dirname as dirname3, join as join9, resolve as resolve22 } from "path";
1697
+ import { dirname as dirname3, join as join9, resolve as resolve22, sep } from "path";
1677
1698
  import { setTimeout as delay2 } from "timers/promises";
1678
1699
  import { fileURLToPath } from "url";
1679
1700
 
@@ -1864,7 +1885,7 @@ function queueLogPath(id) {
1864
1885
 
1865
1886
  // ../../packages/sandbox-docker/dist/index.js
1866
1887
  import { execa as execa15 } from "execa";
1867
- import { readdir as readdir4, rm as rm4, stat as stat7 } from "fs/promises";
1888
+ import { readdir as readdir5, rm as rm5, stat as stat7 } from "fs/promises";
1868
1889
  import { join as join12 } from "path";
1869
1890
 
1870
1891
  // ../../packages/core/dist/index.js
@@ -1925,11 +1946,11 @@ import { homedir as homedir10 } from "os";
1925
1946
  import { join as join13 } from "path";
1926
1947
  import { execa as execa16 } from "execa";
1927
1948
  import { existsSync as existsSync3, mkdirSync, renameSync, statSync } from "fs";
1928
- import { basename as basename32, dirname as dirname22, posix, resolve as resolve4 } from "path";
1949
+ import { basename as basename4, dirname as dirname22, posix, resolve as resolve4 } from "path";
1929
1950
  import { execa as execa17 } from "execa";
1930
- import { copyFile, mkdtemp as mkdtemp3, readdir as readdir5, readFile as readFile7, rm as rm5, stat as stat8, writeFile as writeFile4 } from "fs/promises";
1951
+ import { copyFile, mkdtemp as mkdtemp3, readdir as readdir6, readFile as readFile7, rm as rm6, stat as stat8, writeFile as writeFile4 } from "fs/promises";
1931
1952
  import { homedir as homedir11, tmpdir as tmpdir3 } from "os";
1932
- import { basename as basename4, join as join14, relative as relative2 } from "path";
1953
+ import { basename as basename5, join as join14, relative as relative2 } from "path";
1933
1954
  import { execa as execa18 } from "execa";
1934
1955
  function isHostPathHookCommand(command, hostHome) {
1935
1956
  if (typeof command !== "string" || command.length === 0) return false;
@@ -2728,13 +2749,13 @@ async function copyOneEntry(container, entry) {
2728
2749
  throw new Error(`mkdir -p ${parentDir} failed: ${String(mkdir8.stderr).slice(0, 300)}`);
2729
2750
  }
2730
2751
  if (entry.kind === "file") {
2731
- const cp = await execa22(
2752
+ const cp2 = await execa22(
2732
2753
  "docker",
2733
2754
  ["cp", entry.absSrc, `${container}:${boxDest}`],
2734
2755
  { reject: false }
2735
2756
  );
2736
- if (cp.exitCode !== 0) {
2737
- throw new Error(`docker cp failed: ${String(cp.stderr).slice(0, 300)}`);
2757
+ if (cp2.exitCode !== 0) {
2758
+ throw new Error(`docker cp failed: ${String(cp2.stderr).slice(0, 300)}`);
2738
2759
  }
2739
2760
  } else {
2740
2761
  const packed = await execa22(
@@ -3744,6 +3765,54 @@ function isRealAgentCredential(agent, text) {
3744
3765
  }
3745
3766
  return Object.keys(parsed).length > 0;
3746
3767
  }
3768
+ async function hostClaudeBackupExpired(path = CREDENTIALS_BACKUP_FILE, now = Date.now()) {
3769
+ try {
3770
+ const parsed = JSON.parse(await readFile32(path, "utf8"));
3771
+ const exp = parsed?.claudeAiOauth?.expiresAt;
3772
+ return typeof exp === "number" && Number.isFinite(exp) && exp < now;
3773
+ } catch {
3774
+ return false;
3775
+ }
3776
+ }
3777
+ function parseExtractResult(stdout) {
3778
+ return { copied: /\bCOPIED=yes\b/.test(stdout) };
3779
+ }
3780
+ async function extractVolumeAuthToBackup(opts) {
3781
+ try {
3782
+ await mkdir32(STATE_DIR, { recursive: true });
3783
+ const script = 'COPIED=no; if [ -s /dst/auth.json ]; then cp -a /dst/auth.json "/host-state/$DEST" && COPIED=yes; fi; echo "COPIED=$COPIED"';
3784
+ const { stdout } = await execa4("docker", [
3785
+ "run",
3786
+ "--rm",
3787
+ "--user",
3788
+ "0",
3789
+ "-v",
3790
+ `${opts.volume}:/dst`,
3791
+ "-v",
3792
+ `${STATE_DIR}:/host-state`,
3793
+ "-e",
3794
+ // Pass the destination filename via env so the path isn't interpolated
3795
+ // into the script string (keeps the docker arg list static + injection-safe).
3796
+ `DEST=${basename2(opts.backupFile)}`,
3797
+ opts.image,
3798
+ "sh",
3799
+ "-c",
3800
+ script
3801
+ ]);
3802
+ const result = parseExtractResult(stdout);
3803
+ if (result.copied) await chmod(opts.backupFile, 384).catch(() => {
3804
+ });
3805
+ return result;
3806
+ } catch {
3807
+ return { copied: false };
3808
+ }
3809
+ }
3810
+ function extractCodexCredentials(volume, image) {
3811
+ return extractVolumeAuthToBackup({ volume, image, backupFile: CODEX_CREDENTIALS_BACKUP_FILE });
3812
+ }
3813
+ function extractOpencodeCredentials(volume, image) {
3814
+ return extractVolumeAuthToBackup({ volume, image, backupFile: OPENCODE_CREDENTIALS_BACKUP_FILE });
3815
+ }
3747
3816
  async function hostBackupHasCredentials(path = CREDENTIALS_BACKUP_FILE) {
3748
3817
  try {
3749
3818
  const parsed = JSON.parse(await readFile32(path, "utf8"));
@@ -4998,7 +5067,7 @@ async function createSnapshot(opts) {
4998
5067
  var CHECKPOINTS_ROOT = join8(homedir7(), ".agentbox", "checkpoints");
4999
5068
  var CHECKPOINT_IMAGE_PREFIX = "agentbox-ckpt-";
5000
5069
  function checkpointImageTag(projectRoot, name) {
5001
- const mnemonic = sanitizeMnemonic(basename3(projectRoot));
5070
+ const mnemonic = sanitizeMnemonic(basename22(projectRoot));
5002
5071
  return `${CHECKPOINT_IMAGE_PREFIX}${hashProjectPath(projectRoot)}_${mnemonic}:${name}`;
5003
5072
  }
5004
5073
  function projectCheckpointsDir(projectRoot) {
@@ -5348,6 +5417,7 @@ async function ensureHomeOwnedByVscode(container) {
5348
5417
  var STATE_DIR22 = join9(homedir8(), ".agentbox");
5349
5418
  var PID_FILE = join9(STATE_DIR22, "relay.pid");
5350
5419
  var LOG_FILE = join9(STATE_DIR22, "relay.log");
5420
+ var RELAY_HOME_DIR = join9(STATE_DIR22, "relay");
5351
5421
  var PORT = DEFAULT_RELAY_PORT;
5352
5422
  var ENDPOINT = {
5353
5423
  // host.docker.internal is the Docker Desktop / OrbStack-supplied alias for
@@ -5358,6 +5428,13 @@ var ENDPOINT = {
5358
5428
  hostUrl: `http://127.0.0.1:${String(PORT)}`,
5359
5429
  port: PORT
5360
5430
  };
5431
+ function shouldReclaimForVersion(health, currentVersion) {
5432
+ if (health.cliEntry === false) return true;
5433
+ if (typeof health.version === "string" && health.version.length > 0 && typeof currentVersion === "string" && currentVersion.length > 0 && health.version !== currentVersion) {
5434
+ return true;
5435
+ }
5436
+ return false;
5437
+ }
5361
5438
  async function ensureRelay(opts = {}) {
5362
5439
  const log = opts.onLog ?? (() => {
5363
5440
  });
@@ -5366,12 +5443,19 @@ async function ensureRelay(opts = {}) {
5366
5443
  await removeContainer(RELAY_CONTAINER_NAME);
5367
5444
  log(`removed legacy relay container ${RELAY_CONTAINER_NAME}`);
5368
5445
  }
5446
+ const currentVersion = process.env.AGENTBOX_CLI_VERSION;
5369
5447
  const health = await fetchHealthz(500);
5370
5448
  if (health !== null) {
5371
- if (health.cliEntry !== false) {
5449
+ if (!shouldReclaimForVersion(health, currentVersion)) {
5372
5450
  return ENDPOINT;
5373
5451
  }
5374
- log("relay is alive but lacks AGENTBOX_CLI_ENTRY (cp/download/checkpoint would fail) \u2014 reclaiming");
5452
+ if (health.cliEntry === false) {
5453
+ log("relay is alive but lacks AGENTBOX_CLI_ENTRY (cp/download/checkpoint would fail) \u2014 reclaiming");
5454
+ } else {
5455
+ log(
5456
+ `relay was spawned by agentbox ${health.version ?? "?"} but this CLI is ${currentVersion ?? "?"} \u2014 reclaiming to keep the relay version-consistent`
5457
+ );
5458
+ }
5375
5459
  await reclaimRelay(health.pid, log);
5376
5460
  } else {
5377
5461
  const existingPid = await readPidFile();
@@ -5388,8 +5472,9 @@ async function ensureRelay(opts = {}) {
5388
5472
  });
5389
5473
  }
5390
5474
  }
5391
- const relayBin = resolveRelayBin();
5392
- const cliEntry = resolveCliEntry();
5475
+ const staged = await stageRelayHome(currentVersion ?? "", log).catch(() => null);
5476
+ const relayBin = staged?.relayBin ?? resolveRelayBin();
5477
+ const cliEntry = staged?.cliEntry ?? resolveCliEntry();
5393
5478
  if (cliEntry === null) {
5394
5479
  throw new Error(
5395
5480
  "cannot start the host relay: agentbox CLI entry not found (is the build complete / dist present?). Set AGENTBOX_CLI_ENTRY to override."
@@ -5411,7 +5496,7 @@ async function reclaimRelay(reportedPid, log) {
5411
5496
  });
5412
5497
  if (await pingHealthz(300)) {
5413
5498
  throw new Error(
5414
- `a relay without AGENTBOX_CLI_ENTRY is still listening on :${String(PORT)} and could not be stopped (reported pid ${String(reportedPid ?? "unknown")}); kill it manually and retry`
5499
+ `a relay is still listening on :${String(PORT)} and could not be stopped (reported pid ${String(reportedPid ?? "unknown")}); kill it manually and retry`
5415
5500
  );
5416
5501
  }
5417
5502
  }
@@ -5494,6 +5579,80 @@ function resolveCliEntry() {
5494
5579
  }
5495
5580
  return null;
5496
5581
  }
5582
+ async function stageRelayHome(version, log) {
5583
+ if (!version || version === "0.0.0-dev") return null;
5584
+ if (process.env.AGENTBOX_RELAY_BIN || process.env.AGENTBOX_CLI_ENTRY) return null;
5585
+ const cliRoot = findCliRoot(dirname3(fileURLToPath(import.meta.url)));
5586
+ if (cliRoot === null) return null;
5587
+ const homeDir = join9(RELAY_HOME_DIR, version);
5588
+ const stagedEntry = join9(homeDir, "dist", "index.js");
5589
+ const stagedBin = join9(homeDir, "runtime", "relay", "bin.cjs");
5590
+ if (existsSync2(stagedEntry) && existsSync2(stagedBin)) {
5591
+ return { relayBin: stagedBin, cliEntry: stagedEntry };
5592
+ }
5593
+ const nodeModules = resolveDepRoot(join9(cliRoot, "dist", "index.js"));
5594
+ if (nodeModules === null) return null;
5595
+ const tmpDir = `${homeDir}.tmp-${String(process.pid)}`;
5596
+ try {
5597
+ await mkdir6(RELAY_HOME_DIR, { recursive: true });
5598
+ await rm4(tmpDir, { recursive: true, force: true });
5599
+ await mkdir6(tmpDir, { recursive: true });
5600
+ for (const sub of ["dist", "runtime", "share"]) {
5601
+ const src = join9(cliRoot, sub);
5602
+ if (existsSync2(src)) await cp(src, join9(tmpDir, sub), { recursive: true });
5603
+ }
5604
+ await cp(nodeModules, join9(tmpDir, "node_modules"), { recursive: true, dereference: true });
5605
+ await rm4(homeDir, { recursive: true, force: true });
5606
+ await rename3(tmpDir, homeDir);
5607
+ } catch (err) {
5608
+ await rm4(tmpDir, { recursive: true, force: true }).catch(() => {
5609
+ });
5610
+ if (existsSync2(stagedEntry) && existsSync2(stagedBin)) {
5611
+ return { relayBin: stagedBin, cliEntry: stagedEntry };
5612
+ }
5613
+ log(`relay home staging failed (${err instanceof Error ? err.message : String(err)}); using bundle paths`);
5614
+ return null;
5615
+ }
5616
+ log(`staged relay home for ${version} at ${homeDir}`);
5617
+ await gcOldRelayHomes(version).catch(() => {
5618
+ });
5619
+ return { relayBin: stagedBin, cliEntry: stagedEntry };
5620
+ }
5621
+ function findCliRoot(moduleDir) {
5622
+ for (const root of [resolve22(moduleDir, ".."), resolve22(moduleDir, "..", "..")]) {
5623
+ if (existsSync2(join9(root, "dist", "index.js")) && existsSync2(join9(root, "runtime", "relay", "bin.cjs"))) {
5624
+ return root;
5625
+ }
5626
+ }
5627
+ return null;
5628
+ }
5629
+ function resolveDepRoot(fromFile) {
5630
+ try {
5631
+ const req = createRequire(fromFile);
5632
+ const main = req.resolve("commander");
5633
+ if (main.includes(`${sep}.pnpm${sep}`)) return null;
5634
+ const marker = `${sep}node_modules${sep}`;
5635
+ const idx = main.lastIndexOf(marker);
5636
+ if (idx === -1) return null;
5637
+ const nm = main.slice(0, idx + marker.length - 1);
5638
+ return existsSync2(join9(nm, "commander")) ? nm : null;
5639
+ } catch {
5640
+ return null;
5641
+ }
5642
+ }
5643
+ async function gcOldRelayHomes(keepVersion) {
5644
+ let entries;
5645
+ try {
5646
+ entries = await readdir4(RELAY_HOME_DIR);
5647
+ } catch {
5648
+ return;
5649
+ }
5650
+ for (const name of entries) {
5651
+ if (name === keepVersion) continue;
5652
+ await rm4(join9(RELAY_HOME_DIR, name), { recursive: true, force: true }).catch(() => {
5653
+ });
5654
+ }
5655
+ }
5497
5656
  async function stopRelay() {
5498
5657
  const pid = await readPidFile();
5499
5658
  if (pid === null) {
@@ -5532,7 +5691,7 @@ async function getRelayStatus() {
5532
5691
  pidAlive: pidAlive2,
5533
5692
  port: PORT,
5534
5693
  endpoint: ENDPOINT,
5535
- health: health === null ? null : { boxes: health.boxes, events: health.events },
5694
+ health: health === null ? null : { boxes: health.boxes, events: health.events, version: health.version, commit: health.commit },
5536
5695
  pidFile: PID_FILE,
5537
5696
  logFile: LOG_FILE
5538
5697
  };
@@ -5577,7 +5736,9 @@ function fetchHealthz(timeoutMs) {
5577
5736
  boxes: parsed.boxes,
5578
5737
  events: parsed.events,
5579
5738
  pid: typeof parsed.pid === "number" ? parsed.pid : void 0,
5580
- cliEntry: typeof parsed.cliEntry === "boolean" ? parsed.cliEntry : void 0
5739
+ cliEntry: typeof parsed.cliEntry === "boolean" ? parsed.cliEntry : void 0,
5740
+ version: typeof parsed.version === "string" && parsed.version.length > 0 ? parsed.version : void 0,
5741
+ commit: typeof parsed.commit === "string" && parsed.commit.length > 0 ? parsed.commit : void 0
5581
5742
  });
5582
5743
  } else {
5583
5744
  resolveP(null);
@@ -5930,7 +6091,7 @@ function generateBoxId() {
5930
6091
  return randomBytes3(4).toString("hex");
5931
6092
  }
5932
6093
  function sanitizeBasename(workspacePath) {
5933
- const raw = basename2(resolve3(workspacePath));
6094
+ const raw = basename3(resolve3(workspacePath));
5934
6095
  return raw.toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/-+/g, "-").replace(/^[-._]+|[-._]+$/g, "").slice(0, 30).replace(/[-._]+$/, "");
5935
6096
  }
5936
6097
  function defaultBoxName(workspacePath, id) {
@@ -6021,7 +6182,9 @@ async function createBox(opts) {
6021
6182
  const imageRef = checkpointImage ?? opts.image ?? DEFAULT_BOX_IMAGE;
6022
6183
  const ensureRef = checkpointImage ? opts.image ?? DEFAULT_BOX_IMAGE : imageRef;
6023
6184
  const { built } = await ensureImage(ensureRef, {
6024
- onProgress: (line) => log(`[image] ${line}`)
6185
+ onProgress: (line) => log(`[image] ${line}`),
6186
+ allowPull: opts.allowPull,
6187
+ registry: opts.imageRegistry
6025
6188
  });
6026
6189
  log(built ? `built image ${ensureRef}` : `using cached image ${imageRef}`);
6027
6190
  let relayUp = false;
@@ -6771,10 +6934,11 @@ async function listBoxes() {
6771
6934
  };
6772
6935
  return {
6773
6936
  ...b,
6774
- state: "running",
6937
+ state: b.cloud?.lastState ?? "running",
6775
6938
  endpoints: endpoints2,
6776
6939
  claudeActivity: persisted2?.claude.state,
6777
6940
  claudeSessionTitle: persisted2?.claude.sessionTitle,
6941
+ claudeQuestion: persisted2?.claude.state === "question" ? persisted2.claude.question : void 0,
6778
6942
  codexActivity: persisted2?.codex?.state,
6779
6943
  codexSessionTitle: persisted2?.codex?.sessionTitle,
6780
6944
  opencodeSessionTitle: persisted2?.opencode?.sessionTitle,
@@ -6795,6 +6959,7 @@ async function listBoxes() {
6795
6959
  endpoints,
6796
6960
  claudeActivity: persisted?.claude.state,
6797
6961
  claudeSessionTitle: persisted?.claude.sessionTitle,
6962
+ claudeQuestion: persisted?.claude.state === "question" ? persisted.claude.question : void 0,
6798
6963
  codexActivity: persisted?.codex?.state,
6799
6964
  codexSessionTitle: persisted?.codex?.sessionTitle,
6800
6965
  opencodeSessionTitle: persisted?.opencode?.sessionTitle,
@@ -7065,14 +7230,14 @@ async function destroyBox(idOrName, opts = {}) {
7065
7230
  let removedSnapshot = null;
7066
7231
  if (box.snapshotDir && !opts.keepSnapshot) {
7067
7232
  try {
7068
- await rm4(box.snapshotDir, { recursive: true, force: true });
7233
+ await rm5(box.snapshotDir, { recursive: true, force: true });
7069
7234
  removedSnapshot = box.snapshotDir;
7070
7235
  } catch {
7071
7236
  removedSnapshot = null;
7072
7237
  }
7073
7238
  }
7074
7239
  try {
7075
- await rm4(boxRunDirFor(box), { recursive: true, force: true });
7240
+ await rm5(boxRunDirFor(box), { recursive: true, force: true });
7076
7241
  } catch {
7077
7242
  }
7078
7243
  await removeBoxRecord(box.id);
@@ -7080,7 +7245,7 @@ async function destroyBox(idOrName, opts = {}) {
7080
7245
  }
7081
7246
  async function listSnapshotDirs() {
7082
7247
  try {
7083
- const entries = await readdir4(SNAPSHOTS_ROOT, { withFileTypes: true });
7248
+ const entries = await readdir5(SNAPSHOTS_ROOT, { withFileTypes: true });
7084
7249
  return entries.filter((e) => e.isDirectory()).map((e) => join12(SNAPSHOTS_ROOT, e.name));
7085
7250
  } catch {
7086
7251
  return [];
@@ -7088,7 +7253,7 @@ async function listSnapshotDirs() {
7088
7253
  }
7089
7254
  async function listBoxDirs() {
7090
7255
  try {
7091
- const entries = await readdir4(BOXES_ROOT, { withFileTypes: true });
7256
+ const entries = await readdir5(BOXES_ROOT, { withFileTypes: true });
7092
7257
  return entries.filter((e) => e.isDirectory()).map((e) => join12(BOXES_ROOT, e.name));
7093
7258
  } catch {
7094
7259
  return [];
@@ -7184,13 +7349,13 @@ async function pruneBoxes(opts = {}) {
7184
7349
  for (const v of orphanVolumes) await removeVolume(v);
7185
7350
  for (const d of orphanSnapshots) {
7186
7351
  try {
7187
- await rm4(d, { recursive: true, force: true });
7352
+ await rm5(d, { recursive: true, force: true });
7188
7353
  } catch {
7189
7354
  }
7190
7355
  }
7191
7356
  for (const d of orphanBoxDirs) {
7192
7357
  try {
7193
- await rm4(d, { recursive: true, force: true });
7358
+ await rm5(d, { recursive: true, force: true });
7194
7359
  } catch {
7195
7360
  }
7196
7361
  }
@@ -7455,7 +7620,7 @@ function asText(s) {
7455
7620
  async function uploadToBox(box, hostSrc, boxDst) {
7456
7621
  const srcAbs = resolve4(hostSrc);
7457
7622
  if (!existsSync3(srcAbs)) throw new Error(`source not found: ${hostSrc}`);
7458
- const srcBasename = basename32(srcAbs);
7623
+ const srcBasename = basename4(srcAbs);
7459
7624
  const srcParent = dirname22(srcAbs);
7460
7625
  let boxParent;
7461
7626
  let finalName;
@@ -7539,7 +7704,7 @@ async function downloadFromBox(box, boxSrc, hostDst) {
7539
7704
  finalName = srcBasename;
7540
7705
  } else {
7541
7706
  hostParent = dirname22(dstAbs);
7542
- finalName = basename32(dstAbs);
7707
+ finalName = basename4(dstAbs);
7543
7708
  }
7544
7709
  mkdirSync(hostParent, { recursive: true });
7545
7710
  const finalPath = posix.join(hostParent, finalName);
@@ -7575,6 +7740,8 @@ var dockerProvider = {
7575
7740
  fromBranch: req.fromBranch,
7576
7741
  useBranch: req.useBranch,
7577
7742
  image: req.image,
7743
+ allowPull: req.allowPull,
7744
+ imageRegistry: req.imageRegistry,
7578
7745
  onLog: req.onLog,
7579
7746
  claudeConfig: po.claudeConfig,
7580
7747
  claudeEnv: po.claudeEnv,
@@ -7681,15 +7848,19 @@ var dockerProvider = {
7681
7848
  return {};
7682
7849
  }
7683
7850
  }
7684
- opts.onLog?.(`building docker image ${ref}\u2026`);
7685
- await buildImage({ ref, onProgress: opts.onLog });
7851
+ const { source } = await pullOrBuild(ref, fingerprint, {
7852
+ onProgress: opts.onLog,
7853
+ allowPull: opts.force ? false : opts.allowPull,
7854
+ registry: opts.registry
7855
+ });
7686
7856
  if (fingerprint) {
7687
- writePreparedDockerState({ imageRef: ref, contextSha256: fingerprint.contextSha256 });
7688
7857
  opts.onLog?.(
7689
- `docker image ${ref} built; recorded fingerprint ${fingerprint.contextSha256.slice(0, 12)}`
7858
+ `docker image ${ref} ${source}; recorded fingerprint ${fingerprint.contextSha256.slice(0, 12)}`
7690
7859
  );
7691
7860
  } else {
7692
- opts.onLog?.(`docker image ${ref} built (fingerprint unavailable, prepared state not written)`);
7861
+ opts.onLog?.(
7862
+ `docker image ${ref} ${source} (fingerprint unavailable, prepared state not written)`
7863
+ );
7693
7864
  }
7694
7865
  return {};
7695
7866
  }
@@ -7708,7 +7879,7 @@ async function findBrokenSymlinks2(root) {
7708
7879
  async function walk(dir) {
7709
7880
  let entries;
7710
7881
  try {
7711
- entries = await readdir5(dir, { withFileTypes: true });
7882
+ entries = await readdir6(dir, { withFileTypes: true });
7712
7883
  } catch {
7713
7884
  return;
7714
7885
  }
@@ -7736,7 +7907,7 @@ function emptyResult(warnings = []) {
7736
7907
  }, warnings };
7737
7908
  }
7738
7909
  async function tarballFromDir(stageDir, agent) {
7739
- const tarballPath = join14(tmpdir3(), `agentbox-${agent}-${basename4(stageDir)}.tar.gz`);
7910
+ const tarballPath = join14(tmpdir3(), `agentbox-${agent}-${basename5(stageDir)}.tar.gz`);
7740
7911
  await execa18("tar", ["-czf", tarballPath, "-C", stageDir, "."], {
7741
7912
  env: { ...process.env, COPYFILE_DISABLE: "1" }
7742
7913
  });
@@ -7745,7 +7916,7 @@ async function tarballFromDir(stageDir, agent) {
7745
7916
  function makeCleanup(paths) {
7746
7917
  return async () => {
7747
7918
  for (const p of paths) {
7748
- await rm5(p, { recursive: true, force: true });
7919
+ await rm6(p, { recursive: true, force: true });
7749
7920
  }
7750
7921
  };
7751
7922
  }
@@ -7761,8 +7932,8 @@ async function stageSingleFileTarball(agent, sourcePath, tarballEntryName) {
7761
7932
  warnings: []
7762
7933
  };
7763
7934
  } catch (err) {
7764
- await rm5(stageDir, { recursive: true, force: true });
7765
- if (tarballPath) await rm5(tarballPath, { force: true });
7935
+ await rm6(stageDir, { recursive: true, force: true });
7936
+ if (tarballPath) await rm6(tarballPath, { force: true });
7766
7937
  throw err;
7767
7938
  }
7768
7939
  }
@@ -7845,7 +8016,7 @@ async function stageClaudeStaticForUpload(opts = {}) {
7845
8016
  const pluginsDir = join14(stageDir, "plugins");
7846
8017
  if (await pathExists7(pluginsDir)) {
7847
8018
  try {
7848
- const entries = await readdir5(pluginsDir, { withFileTypes: true });
8019
+ const entries = await readdir6(pluginsDir, { withFileTypes: true });
7849
8020
  for (const ent of entries) {
7850
8021
  if (!ent.isFile() || !ent.name.endsWith(".json")) continue;
7851
8022
  const file = join14(pluginsDir, ent.name);
@@ -7863,8 +8034,8 @@ async function stageClaudeStaticForUpload(opts = {}) {
7863
8034
  warnings: []
7864
8035
  };
7865
8036
  } catch (err) {
7866
- await rm5(stageDir, { recursive: true, force: true });
7867
- if (tarballPath) await rm5(tarballPath, { force: true });
8037
+ await rm6(stageDir, { recursive: true, force: true });
8038
+ if (tarballPath) await rm6(tarballPath, { force: true });
7868
8039
  throw err;
7869
8040
  }
7870
8041
  }
@@ -7924,16 +8095,17 @@ async function stageCodexStaticForUpload(opts = {}) {
7924
8095
  warnings: []
7925
8096
  };
7926
8097
  } catch (err) {
7927
- await rm5(stageDir, { recursive: true, force: true });
7928
- if (tarballPath) await rm5(tarballPath, { force: true });
8098
+ await rm6(stageDir, { recursive: true, force: true });
8099
+ if (tarballPath) await rm6(tarballPath, { force: true });
7929
8100
  throw err;
7930
8101
  }
7931
8102
  }
7932
8103
  async function stageCodexCredentialsForUpload(opts = {}) {
7933
- if (await pathExists7(CODEX_CREDENTIALS_BACKUP_FILE)) {
7934
- return stageSingleFileTarball("codex-creds", CODEX_CREDENTIALS_BACKUP_FILE, "auth.json");
7935
- }
7936
8104
  const hostHome = opts.hostHome ?? homedir11();
8105
+ const cloudBackup = join14(hostHome, ".agentbox", "codex-credentials.json");
8106
+ if (await pathExists7(cloudBackup)) {
8107
+ return stageSingleFileTarball("codex-creds", cloudBackup, "auth.json");
8108
+ }
7937
8109
  const hostAuth = join14(hostHome, ".codex", "auth.json");
7938
8110
  if (!await pathExists7(hostAuth)) return emptyResult([CODEX_KEYCHAIN_WARNING]);
7939
8111
  return stageSingleFileTarball("codex-creds", hostAuth, "auth.json");
@@ -7991,16 +8163,17 @@ async function stageOpencodeStaticForUpload(opts = {}) {
7991
8163
  warnings: []
7992
8164
  };
7993
8165
  } catch (err) {
7994
- await rm5(stageDir, { recursive: true, force: true });
7995
- if (tarballPath) await rm5(tarballPath, { force: true });
8166
+ await rm6(stageDir, { recursive: true, force: true });
8167
+ if (tarballPath) await rm6(tarballPath, { force: true });
7996
8168
  throw err;
7997
8169
  }
7998
8170
  }
7999
8171
  async function stageOpencodeCredentialsForUpload(opts = {}) {
8000
- if (await pathExists7(OPENCODE_CREDENTIALS_BACKUP_FILE)) {
8001
- return stageSingleFileTarball("opencode-creds", OPENCODE_CREDENTIALS_BACKUP_FILE, "auth.json");
8002
- }
8003
8172
  const hostHome = opts.hostHome ?? homedir11();
8173
+ const cloudBackup = join14(hostHome, ".agentbox", "opencode-credentials.json");
8174
+ if (await pathExists7(cloudBackup)) {
8175
+ return stageSingleFileTarball("opencode-creds", cloudBackup, "auth.json");
8176
+ }
8004
8177
  const hostAuth = join14(hostHome, ".local", "share", "opencode", "auth.json");
8005
8178
  if (!await pathExists7(hostAuth)) return emptyResult();
8006
8179
  return stageSingleFileTarball("opencode-creds", hostAuth, "auth.json");
@@ -8123,6 +8296,11 @@ export {
8123
8296
  CODEX_CREDENTIALS_BACKUP_FILE,
8124
8297
  OPENCODE_CREDENTIALS_BACKUP_FILE,
8125
8298
  isRealAgentCredential,
8299
+ hostClaudeBackupExpired,
8300
+ parseExtractResult,
8301
+ extractVolumeAuthToBackup,
8302
+ extractCodexCredentials,
8303
+ extractOpencodeCredentials,
8126
8304
  hostBackupHasCredentials,
8127
8305
  parseSyncResult,
8128
8306
  syncClaudeCredentials,
@@ -8268,4 +8446,4 @@ export {
8268
8446
  browserSessionActive,
8269
8447
  ensureBoxBrowser
8270
8448
  };
8271
- //# sourceMappingURL=chunk-NCJP5MTN.js.map
8449
+ //# sourceMappingURL=chunk-CDKVD6UO.js.map