@madarco/agentbox 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/dist/{_cloud-attach-O6NYTLES.js → _cloud-attach-6C5NMOHD.js} +4 -4
  3. package/dist/{chunk-2GPORKYF.js → chunk-D4Q2RUQI.js} +5 -5
  4. package/dist/chunk-D4Q2RUQI.js.map +1 -0
  5. package/dist/{chunk-MTVI44DW.js → chunk-ECLLV5JH.js} +6 -3
  6. package/dist/chunk-ECLLV5JH.js.map +1 -0
  7. package/dist/{chunk-7UIAO7PC.js → chunk-GUNUBIRB.js} +94 -75
  8. package/dist/chunk-GUNUBIRB.js.map +1 -0
  9. package/dist/{chunk-R4O5WPHW.js → chunk-NVSRGC5W.js} +23 -11
  10. package/dist/chunk-NVSRGC5W.js.map +1 -0
  11. package/dist/{chunk-I24B6AXR.js → chunk-R5XIDQFR.js} +6 -3
  12. package/dist/chunk-R5XIDQFR.js.map +1 -0
  13. package/dist/{chunk-KL36BRN4.js → chunk-SNTHHWKY.js} +70 -17
  14. package/dist/chunk-SNTHHWKY.js.map +1 -0
  15. package/dist/{chunk-LEV3KICD.js → chunk-ZGVMN54V.js} +6 -3
  16. package/dist/{chunk-LEV3KICD.js.map → chunk-ZGVMN54V.js.map} +1 -1
  17. package/dist/{dist-5FQGYRW5.js → dist-4SUIXKSD.js} +5 -5
  18. package/dist/{dist-PZW3GWWU.js → dist-HT2YV6PB.js} +5 -5
  19. package/dist/{dist-TMHSUVTP.js → dist-PJFJNXO2.js} +5 -5
  20. package/dist/{dist-BQNX7RQE.js → dist-ZEGIMYWZ.js} +13 -3
  21. package/dist/index.js +632 -547
  22. package/dist/index.js.map +1 -1
  23. package/dist/{prepared-state-CL4CWXQA-H5THETIM.js → prepared-state-MQHD3M5F-KE4DT3GX.js} +2 -2
  24. package/package.json +5 -5
  25. package/runtime/docker/apps/cli/share/agentbox-setup/SKILL.md +1 -1
  26. package/runtime/docker/packages/ctl/dist/bin.cjs +11 -2
  27. package/runtime/hetzner/agentbox-setup-skill.md +1 -1
  28. package/runtime/hetzner/ctl.cjs +11 -2
  29. package/runtime/relay/bin.cjs +14 -2
  30. package/runtime/vercel/agentbox-setup-skill.md +1 -1
  31. package/runtime/vercel/ctl.cjs +11 -2
  32. package/runtime/vercel/scripts/provision.sh +20 -0
  33. package/share/agentbox-setup/SKILL.md +1 -1
  34. package/dist/chunk-2GPORKYF.js.map +0 -1
  35. package/dist/chunk-7UIAO7PC.js.map +0 -1
  36. package/dist/chunk-I24B6AXR.js.map +0 -1
  37. package/dist/chunk-KL36BRN4.js.map +0 -1
  38. package/dist/chunk-MTVI44DW.js.map +0 -1
  39. package/dist/chunk-R4O5WPHW.js.map +0 -1
  40. /package/dist/{_cloud-attach-O6NYTLES.js.map → _cloud-attach-6C5NMOHD.js.map} +0 -0
  41. /package/dist/{dist-5FQGYRW5.js.map → dist-4SUIXKSD.js.map} +0 -0
  42. /package/dist/{dist-PZW3GWWU.js.map → dist-HT2YV6PB.js.map} +0 -0
  43. /package/dist/{dist-TMHSUVTP.js.map → dist-PJFJNXO2.js.map} +0 -0
  44. /package/dist/{dist-BQNX7RQE.js.map → dist-ZEGIMYWZ.js.map} +0 -0
  45. /package/dist/{prepared-state-CL4CWXQA-H5THETIM.js.map → prepared-state-MQHD3M5F-KE4DT3GX.js.map} +0 -0
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  maskKey,
6
6
  readDaytonaCredStatus,
7
7
  secretsPath
8
- } from "./chunk-LEV3KICD.js";
8
+ } from "./chunk-ZGVMN54V.js";
9
9
  import {
10
10
  detectEgressIp,
11
11
  ensureHetznerCredentials,
@@ -15,7 +15,7 @@ import {
15
15
  readHetznerCredStatus,
16
16
  secretsPath as secretsPath2,
17
17
  syncFirewallSource
18
- } from "./chunk-I24B6AXR.js";
18
+ } from "./chunk-R5XIDQFR.js";
19
19
  import {
20
20
  detectSbx,
21
21
  ensureVercelCredentials,
@@ -23,7 +23,7 @@ import {
23
23
  maskKey as maskKey3,
24
24
  readVercelCredStatus,
25
25
  secretsPath as secretsPath3
26
- } from "./chunk-MTVI44DW.js";
26
+ } from "./chunk-ECLLV5JH.js";
27
27
  import {
28
28
  agentSpecsForCloud,
29
29
  ensureAgentVolumesForCloud,
@@ -31,7 +31,7 @@ import {
31
31
  probeCloudCheckpoint,
32
32
  resolveCloudCheckpoint,
33
33
  seedAgentVolumesIfFresh
34
- } from "./chunk-2GPORKYF.js";
34
+ } from "./chunk-D4Q2RUQI.js";
35
35
  import {
36
36
  ADVANCED_HINT_GROUPS,
37
37
  ALERT_BAND_ROWS,
@@ -61,7 +61,7 @@ import {
61
61
  statusLine,
62
62
  stripTitleGlyph,
63
63
  subscribePrompts
64
- } from "./chunk-R4O5WPHW.js";
64
+ } from "./chunk-NVSRGC5W.js";
65
65
  import {
66
66
  AmbiguousBoxError,
67
67
  BOX_STATUS_EVENT,
@@ -207,20 +207,21 @@ import {
207
207
  waitForTmuxPaneContent,
208
208
  warmUpClaudeCredentials,
209
209
  writeJob
210
- } from "./chunk-7UIAO7PC.js";
210
+ } from "./chunk-GUNUBIRB.js";
211
211
  import {
212
212
  DEFAULT_BOX_IMAGE,
213
213
  STATE_DIR,
214
214
  ensureImage,
215
+ hostOpenCommand,
215
216
  imageInfo,
216
217
  readState,
217
218
  resolveBoxRef
218
- } from "./chunk-KL36BRN4.js";
219
+ } from "./chunk-SNTHHWKY.js";
219
220
  import "./chunk-G3H2L3O2.js";
220
221
 
221
222
  // src/version.ts
222
- var AGENTBOX_VERSION = true ? "0.10.0" : "0.0.0-dev";
223
- var AGENTBOX_COMMIT = true ? "e0ccad3c" : "dev";
223
+ var AGENTBOX_VERSION = true ? "0.11.0" : "0.0.0-dev";
224
+ var AGENTBOX_COMMIT = true ? "1f8ef1db" : "dev";
224
225
 
225
226
  // src/index.ts
226
227
  import { Command as Command46 } from "commander";
@@ -591,7 +592,7 @@ function parsePositiveInt(raw, label) {
591
592
  }
592
593
 
593
594
  // src/commands/claude.ts
594
- import { confirm as confirm3, intro, isCancel as isCancel4, log as log9, outro as outro2, spinner as spinner3 } from "@clack/prompts";
595
+ import { confirm as confirm3, intro, isCancel as isCancel4, log as log8, outro, spinner as spinner3 } from "@clack/prompts";
595
596
  import { Command as Command2 } from "commander";
596
597
 
597
598
  // src/auth.ts
@@ -822,9 +823,6 @@ function resolveAttachInOption(opts) {
822
823
  return void 0;
823
824
  }
824
825
 
825
- // src/commands/_cloud-agent-create.ts
826
- import { log as log4, outro } from "@clack/prompts";
827
-
828
826
  // src/lib/progress.ts
829
827
  import { spinner } from "@clack/prompts";
830
828
 
@@ -867,6 +865,138 @@ function makeProgressReporter(verbose) {
867
865
  };
868
866
  }
869
867
 
868
+ // src/lib/launch-recap.ts
869
+ import { homedir as homedir2 } from "os";
870
+ import { note } from "@clack/prompts";
871
+
872
+ // src/lib/from-branch.ts
873
+ import { execa } from "execa";
874
+ var SHA_RE = /^[0-9a-f]{7,40}$/i;
875
+ var FromBranchError = class extends Error {
876
+ constructor(message) {
877
+ super(message);
878
+ this.name = "FromBranchError";
879
+ }
880
+ };
881
+ async function resolveFromBranch(ref, opts) {
882
+ if (!ref || ref.length === 0) return void 0;
883
+ const remote = opts.remote ?? "origin";
884
+ const isSha = SHA_RE.test(ref);
885
+ if (!isSha) {
886
+ const fetched = await execa(
887
+ "git",
888
+ ["-C", opts.repo, "fetch", "--quiet", remote, ref],
889
+ { reject: false }
890
+ );
891
+ if (fetched.exitCode !== 0) {
892
+ }
893
+ }
894
+ const verify = await execa(
895
+ "git",
896
+ ["-C", opts.repo, "rev-parse", "--verify", `${ref}^{commit}`],
897
+ { reject: false }
898
+ );
899
+ if (verify.exitCode !== 0) {
900
+ throw new FromBranchError(
901
+ `--from-branch: unknown ref "${ref}" (not found in ${opts.repo} after fetch). Provide a branch, tag, or SHA reachable from the host repo.`
902
+ );
903
+ }
904
+ return ref;
905
+ }
906
+ var UseBranchError = class extends Error {
907
+ constructor(message) {
908
+ super(message);
909
+ this.name = "UseBranchError";
910
+ }
911
+ };
912
+ async function resolveUseBranch(name, opts) {
913
+ if (!name || name.length === 0) return void 0;
914
+ const remote = opts.remote ?? "origin";
915
+ await execa("git", ["-C", opts.repo, "fetch", "--quiet", remote, name], {
916
+ reject: false
917
+ });
918
+ const exists = await execa(
919
+ "git",
920
+ ["-C", opts.repo, "show-ref", "--verify", "--quiet", `refs/heads/${name}`],
921
+ { reject: false }
922
+ );
923
+ if (exists.exitCode !== 0) {
924
+ throw new UseBranchError(
925
+ `--use-branch: no local branch "${name}" in ${opts.repo}. Create or check it out on the host first (--use-branch reuses an existing branch; use --from-branch to fork a new box branch from a ref).`
926
+ );
927
+ }
928
+ return name;
929
+ }
930
+ async function currentHostBranch(repo) {
931
+ const r = await execa("git", ["-C", repo, "rev-parse", "--abbrev-ref", "HEAD"], {
932
+ reject: false
933
+ });
934
+ if (r.exitCode !== 0) return void 0;
935
+ const branch = r.stdout.trim();
936
+ if (!branch || branch === "HEAD") return void 0;
937
+ return branch;
938
+ }
939
+ async function resolveBranchSelection(opts) {
940
+ if (opts.useBranch && opts.fromBranch) {
941
+ throw new UseBranchError(
942
+ "--use-branch and --from-branch are mutually exclusive: --use-branch reuses an existing branch, --from-branch forks a new box branch from a base ref. Pass only one."
943
+ );
944
+ }
945
+ if (opts.useBranch) {
946
+ return { useBranch: await resolveUseBranch(opts.useBranch, { repo: opts.repo }) };
947
+ }
948
+ if (opts.fromBranch) {
949
+ return { fromBranch: await resolveFromBranch(opts.fromBranch, { repo: opts.repo }) };
950
+ }
951
+ if (opts.providerName !== "docker" && opts.cloudUseCurrentBranch) {
952
+ const current = await currentHostBranch(opts.repo);
953
+ if (current) {
954
+ opts.log?.(`cloud.useCurrentBranch: starting box on host branch "${current}"`);
955
+ return { useBranch: current };
956
+ }
957
+ opts.log?.(
958
+ "cloud.useCurrentBranch is set but host HEAD is detached; forking a fresh branch instead"
959
+ );
960
+ }
961
+ return {};
962
+ }
963
+
964
+ // src/lib/launch-recap.ts
965
+ function homeShorten(p) {
966
+ const home = homedir2();
967
+ return p === home || p.startsWith(home + "/") ? "~" + p.slice(home.length) : p;
968
+ }
969
+ function whiten(text) {
970
+ if (process.env.NO_COLOR) return text;
971
+ return text.split("\n").map((line) => `\x1B[0m\x1B[97m${line}\x1B[0m`).join("\n");
972
+ }
973
+ async function printLaunchRecap(args) {
974
+ const { record } = args;
975
+ const rows = [];
976
+ rows.push([
977
+ "box",
978
+ args.checkpointRef ? `${record.name} (${args.checkpointRef})` : record.name
979
+ ]);
980
+ if (record.projectRoot) {
981
+ rows.push(["project", homeShorten(record.projectRoot)]);
982
+ }
983
+ const toBranch = record.gitWorktrees?.find((w) => w.kind === "root")?.branch;
984
+ if (toBranch) {
985
+ if (args.useBranch) {
986
+ rows.push(["branch", `${toBranch} (reused)`]);
987
+ } else {
988
+ const base = args.fromBranch ?? await currentHostBranch(args.workspacePath) ?? "HEAD";
989
+ rows.push(["branch", `${base} \u2192 ${toBranch}`]);
990
+ }
991
+ }
992
+ const pad4 = Math.max(...rows.map(([label]) => label.length)) + 2;
993
+ const body = rows.map(([label, value]) => `${label.padEnd(pad4)}${value}`).join("\n");
994
+ const instruction = args.attaching ? `Ctrl+a d to detach. Reattach with: agentbox ${args.mode} attach ${args.reattach}` : `Attach with: agentbox ${args.mode} attach ${args.reattach}`;
995
+ note(whiten(`${body}
996
+
997
+ ${instruction}`));
998
+ }
999
+
870
1000
  // src/commands/_cloud-agent-create.ts
871
1001
  async function cloudAgentCreate(args) {
872
1002
  const s = makeProgressReporter(args.verbose === true);
@@ -877,12 +1007,7 @@ async function cloudAgentCreate(args) {
877
1007
  onLog: (line) => s.message(line)
878
1008
  });
879
1009
  const nSuffix = typeof result.record.projectIndex === "number" ? ` \xB7 n ${String(result.record.projectIndex)}` : "";
880
- s.stop(`box ${result.record.name} ready${nSuffix}`);
881
- log4.info(`id: ${result.record.id}`);
882
- log4.info(`provider: ${result.record.provider}`);
883
- if (result.record.cloud?.sandboxId) {
884
- log4.info(`sandboxId: ${result.record.cloud.sandboxId}`);
885
- }
1010
+ s.stop(`box ready${nSuffix}`);
886
1011
  let extraArgs = args.extraArgs;
887
1012
  if (args.beforeStart) {
888
1013
  const hook = await args.beforeStart(result.record);
@@ -890,13 +1015,19 @@ async function cloudAgentCreate(args) {
890
1015
  extraArgs = [...hook.agentArgsPrefix, ...extraArgs ?? []];
891
1016
  }
892
1017
  }
1018
+ await printLaunchRecap({
1019
+ record: result.record,
1020
+ mode: args.mode,
1021
+ reattach: typeof result.record.projectIndex === "number" ? String(result.record.projectIndex) : result.record.name,
1022
+ workspacePath: args.request.workspacePath,
1023
+ fromBranch: args.request.fromBranch,
1024
+ useBranch: args.request.useBranch,
1025
+ checkpointRef: args.request.checkpointRef,
1026
+ attaching: args.attach !== false
1027
+ });
893
1028
  if (args.attach === false) {
894
- outro(
895
- `session not started \u2014 attach with: agentbox ${args.mode} attach ${result.record.name}`
896
- );
897
1029
  return;
898
1030
  }
899
- outro(`attaching ${args.mode} \u2014 Control+a d to detach, leaves the agent running`);
900
1031
  await cloudAgentAttach({
901
1032
  box: result.record,
902
1033
  binary: args.binary,
@@ -915,7 +1046,7 @@ async function cloudAgentCreate(args) {
915
1046
  import { join as join4 } from "path";
916
1047
 
917
1048
  // src/carry-prompt.ts
918
- import { isCancel, log as log5, select } from "@clack/prompts";
1049
+ import { isCancel, log as log4, select } from "@clack/prompts";
919
1050
 
920
1051
  // src/fmt.ts
921
1052
  function fmtBytes(n) {
@@ -999,7 +1130,7 @@ function printSummary(entries) {
999
1130
  ` ${pad(e.rawSrc, srcW)} \u2192 ${pad(e.rawDest, destW)} ${pad(size, 9)} ${flags.join(", ")}`
1000
1131
  );
1001
1132
  }
1002
- log5.message(rows.join("\n"));
1133
+ log4.message(rows.join("\n"));
1003
1134
  }
1004
1135
  function pad(s, w) {
1005
1136
  if (s.length >= w) return s;
@@ -1008,13 +1139,13 @@ function pad(s, w) {
1008
1139
 
1009
1140
  // src/lib/carry-resolve.ts
1010
1141
  import { realpath, stat as stat2 } from "fs/promises";
1011
- import { homedir as homedir2 } from "os";
1142
+ import { homedir as homedir3 } from "os";
1012
1143
  import { isAbsolute, join as join3, normalize, resolve } from "path";
1013
1144
  var DEFAULT_MAX_BYTES = 50 * 1024 * 1024;
1014
1145
  var DENYLIST_DEST_PREFIXES = ["/proc", "/sys", "/dev"];
1015
1146
  var DENYLIST_DEST_EXACT = /* @__PURE__ */ new Set(["/etc/passwd", "/etc/shadow"]);
1016
1147
  async function resolveCarry(items, opts) {
1017
- const home = opts.homeDir ?? homedir2();
1148
+ const home = opts.homeDir ?? homedir3();
1018
1149
  const cap = opts.maxBytes ?? readMaxBytesFromEnv() ?? DEFAULT_MAX_BYTES;
1019
1150
  const projectRoot = opts.projectRoot;
1020
1151
  const entries = [];
@@ -1208,7 +1339,7 @@ async function dirSizeCapped(dir, cap) {
1208
1339
 
1209
1340
  // src/lib/carry-gate.ts
1210
1341
  async function runCarryGate(args) {
1211
- const log45 = args.onLog ?? (() => {
1342
+ const log44 = args.onLog ?? (() => {
1212
1343
  });
1213
1344
  const yamlPath = join4(args.projectRoot, "agentbox.yaml");
1214
1345
  const items = await loadCarrySection(yamlPath);
@@ -1230,108 +1361,16 @@ async function runCarryGate(args) {
1230
1361
  });
1231
1362
  if (decision === "cancel") return { decision: "cancel" };
1232
1363
  if (decision === "skip-this-run") {
1233
- log45(`carry: skipped for this box (${String(resolved.entries.length)} entry/entries not copied)`);
1364
+ log44(`carry: skipped for this box (${String(resolved.entries.length)} entry/entries not copied)`);
1234
1365
  return { decision: "skip", entries: [] };
1235
1366
  }
1236
1367
  return { decision: "approve", entries: resolved.entries };
1237
1368
  }
1238
1369
 
1239
- // src/lib/from-branch.ts
1240
- import { execa } from "execa";
1241
- var SHA_RE = /^[0-9a-f]{7,40}$/i;
1242
- var FromBranchError = class extends Error {
1243
- constructor(message) {
1244
- super(message);
1245
- this.name = "FromBranchError";
1246
- }
1247
- };
1248
- async function resolveFromBranch(ref, opts) {
1249
- if (!ref || ref.length === 0) return void 0;
1250
- const remote = opts.remote ?? "origin";
1251
- const isSha = SHA_RE.test(ref);
1252
- if (!isSha) {
1253
- const fetched = await execa(
1254
- "git",
1255
- ["-C", opts.repo, "fetch", "--quiet", remote, ref],
1256
- { reject: false }
1257
- );
1258
- if (fetched.exitCode !== 0) {
1259
- }
1260
- }
1261
- const verify = await execa(
1262
- "git",
1263
- ["-C", opts.repo, "rev-parse", "--verify", `${ref}^{commit}`],
1264
- { reject: false }
1265
- );
1266
- if (verify.exitCode !== 0) {
1267
- throw new FromBranchError(
1268
- `--from-branch: unknown ref "${ref}" (not found in ${opts.repo} after fetch). Provide a branch, tag, or SHA reachable from the host repo.`
1269
- );
1270
- }
1271
- return ref;
1272
- }
1273
- var UseBranchError = class extends Error {
1274
- constructor(message) {
1275
- super(message);
1276
- this.name = "UseBranchError";
1277
- }
1278
- };
1279
- async function resolveUseBranch(name, opts) {
1280
- if (!name || name.length === 0) return void 0;
1281
- const remote = opts.remote ?? "origin";
1282
- await execa("git", ["-C", opts.repo, "fetch", "--quiet", remote, name], {
1283
- reject: false
1284
- });
1285
- const exists = await execa(
1286
- "git",
1287
- ["-C", opts.repo, "show-ref", "--verify", "--quiet", `refs/heads/${name}`],
1288
- { reject: false }
1289
- );
1290
- if (exists.exitCode !== 0) {
1291
- throw new UseBranchError(
1292
- `--use-branch: no local branch "${name}" in ${opts.repo}. Create or check it out on the host first (--use-branch reuses an existing branch; use --from-branch to fork a new box branch from a ref).`
1293
- );
1294
- }
1295
- return name;
1296
- }
1297
- async function currentHostBranch(repo) {
1298
- const r = await execa("git", ["-C", repo, "rev-parse", "--abbrev-ref", "HEAD"], {
1299
- reject: false
1300
- });
1301
- if (r.exitCode !== 0) return void 0;
1302
- const branch = r.stdout.trim();
1303
- if (!branch || branch === "HEAD") return void 0;
1304
- return branch;
1305
- }
1306
- async function resolveBranchSelection(opts) {
1307
- if (opts.useBranch && opts.fromBranch) {
1308
- throw new UseBranchError(
1309
- "--use-branch and --from-branch are mutually exclusive: --use-branch reuses an existing branch, --from-branch forks a new box branch from a base ref. Pass only one."
1310
- );
1311
- }
1312
- if (opts.useBranch) {
1313
- return { useBranch: await resolveUseBranch(opts.useBranch, { repo: opts.repo }) };
1314
- }
1315
- if (opts.fromBranch) {
1316
- return { fromBranch: await resolveFromBranch(opts.fromBranch, { repo: opts.repo }) };
1317
- }
1318
- if (opts.providerName !== "docker" && opts.cloudUseCurrentBranch) {
1319
- const current = await currentHostBranch(opts.repo);
1320
- if (current) {
1321
- opts.log?.(`cloud.useCurrentBranch: starting box on host branch "${current}"`);
1322
- return { useBranch: current };
1323
- }
1324
- opts.log?.(
1325
- "cloud.useCurrentBranch is set but host HEAD is detached; forking a fresh branch instead"
1326
- );
1327
- }
1328
- return {};
1329
- }
1330
-
1331
1370
  // src/session-teleport/claude.ts
1332
1371
  import { mkdir, mkdtemp, readdir, readFile as readFile2, stat as stat3, writeFile } from "fs/promises";
1333
1372
  import { existsSync } from "fs";
1334
- import { homedir as homedir3, tmpdir } from "os";
1373
+ import { homedir as homedir4, tmpdir } from "os";
1335
1374
  import { join as join5 } from "path";
1336
1375
 
1337
1376
  // src/session-teleport/cwd-encoding.ts
@@ -1352,7 +1391,7 @@ var TeleportError = class extends Error {
1352
1391
  // src/session-teleport/claude.ts
1353
1392
  var BOX_CLAUDE_PROJECTS_DIR = `/home/vscode/.claude/projects/${BOX_WORKSPACE_ENCODED}`;
1354
1393
  async function resolveClaudeTeleport(opts) {
1355
- const hostHome = opts.hostHome ?? homedir3();
1394
+ const hostHome = opts.hostHome ?? homedir4();
1356
1395
  const projectDir = join5(
1357
1396
  hostHome,
1358
1397
  ".claude",
@@ -1439,10 +1478,10 @@ async function rewriteSessionFile(src, dst, hostCwd) {
1439
1478
  // src/session-teleport/codex.ts
1440
1479
  import { mkdtemp as mkdtemp2, readdir as readdir2, readFile as readFile3, stat as stat4, writeFile as writeFile2 } from "fs/promises";
1441
1480
  import { existsSync as existsSync2 } from "fs";
1442
- import { homedir as homedir4, tmpdir as tmpdir2 } from "os";
1481
+ import { homedir as homedir5, tmpdir as tmpdir2 } from "os";
1443
1482
  import { join as join6 } from "path";
1444
1483
  async function resolveCodexTeleport(opts) {
1445
- const hostHome = opts.hostHome ?? homedir4();
1484
+ const hostHome = opts.hostHome ?? homedir5();
1446
1485
  const sessionsRoot = join6(hostHome, ".codex", "sessions");
1447
1486
  if (!existsSync2(sessionsRoot)) {
1448
1487
  throw new TeleportError(
@@ -1649,29 +1688,29 @@ async function uploadTeleport(input) {
1649
1688
  }
1650
1689
 
1651
1690
  // src/lib/install-hint.ts
1652
- import { log as log6 } from "@clack/prompts";
1691
+ import { log as log5 } from "@clack/prompts";
1653
1692
  import { existsSync as existsSync3, mkdirSync, writeFileSync } from "fs";
1654
- import { homedir as homedir5 } from "os";
1693
+ import { homedir as homedir6 } from "os";
1655
1694
  import { join as join7 } from "path";
1656
1695
  function maybeShowInstallHint() {
1657
1696
  try {
1658
- const skill = join7(homedir5(), ".claude", "skills", "agentbox", "SKILL.md");
1697
+ const skill = join7(homedir6(), ".claude", "skills", "agentbox", "SKILL.md");
1659
1698
  if (existsSync3(skill)) return;
1660
- const marker = join7(homedir5(), ".agentbox", "install-hint-shown");
1699
+ const marker = join7(homedir6(), ".agentbox", "install-hint-shown");
1661
1700
  if (existsSync3(marker)) return;
1662
- mkdirSync(join7(homedir5(), ".agentbox"), { recursive: true });
1701
+ mkdirSync(join7(homedir6(), ".agentbox"), { recursive: true });
1663
1702
  writeFileSync(marker, "");
1664
- log6.info("tip: run 'agentbox install' to enable the /agentbox fork command in host Claude");
1703
+ log5.info("tip: run 'agentbox install' to enable the /agentbox fork command in host Claude");
1665
1704
  } catch {
1666
1705
  }
1667
1706
  }
1668
1707
 
1669
1708
  // src/lib/log-file.ts
1670
1709
  import { closeSync, mkdirSync as mkdirSync2, openSync, renameSync, symlinkSync, unlinkSync, writeFileSync as writeFileSync2, writeSync } from "fs";
1671
- import { homedir as homedir6 } from "os";
1710
+ import { homedir as homedir7 } from "os";
1672
1711
  import { join as join8 } from "path";
1673
1712
  function stateDir() {
1674
- return process.env.AGENTBOX_HOME ?? join8(homedir6(), ".agentbox");
1713
+ return process.env.AGENTBOX_HOME ?? join8(homedir7(), ".agentbox");
1675
1714
  }
1676
1715
  function logsDir() {
1677
1716
  return join8(stateDir(), "logs");
@@ -1795,7 +1834,7 @@ function resolveLimits(box, flags) {
1795
1834
  }
1796
1835
 
1797
1836
  // src/portless-prompt.ts
1798
- import { confirm, isCancel as isCancel2, log as log7, spinner as spinner2 } from "@clack/prompts";
1837
+ import { confirm, isCancel as isCancel2, log as log6, spinner as spinner2 } from "@clack/prompts";
1799
1838
  async function setupPortlessHost() {
1800
1839
  let state = await detectPortless();
1801
1840
  if (!state.installed) {
@@ -1805,13 +1844,13 @@ async function setupPortlessHost() {
1805
1844
  resetPortlessCache();
1806
1845
  s2.stop(ok ? "portless installed" : "portless install failed");
1807
1846
  if (!ok) {
1808
- log7.warn(`Could not install Portless \u2014 run \`${portlessInstallHint()}\` yourself.`);
1847
+ log6.warn(`Could not install Portless \u2014 run \`${portlessInstallHint()}\` yourself.`);
1809
1848
  return;
1810
1849
  }
1811
1850
  state = await detectPortless();
1812
1851
  }
1813
1852
  if (state.proxyRunning) {
1814
- log7.info("Portless proxy already running \u2014 boxes will use it.");
1853
+ log6.info("Portless proxy already running \u2014 boxes will use it.");
1815
1854
  return;
1816
1855
  }
1817
1856
  const s = spinner2();
@@ -1823,7 +1862,7 @@ async function setupPortlessHost() {
1823
1862
  s.stop("portless proxy started");
1824
1863
  } else {
1825
1864
  s.stop("portless proxy did not start");
1826
- log7.warn(`Could not start the Portless proxy \u2014 run \`${portlessStartHint()}\` yourself.`);
1865
+ log6.warn(`Could not start the Portless proxy \u2014 run \`${portlessStartHint()}\` yourself.`);
1827
1866
  }
1828
1867
  }
1829
1868
  async function maybePromptPortless(args) {
@@ -1838,7 +1877,7 @@ async function maybePromptPortless(args) {
1838
1877
  try {
1839
1878
  await setConfigValue("global", "portless.enabled", answer, args.cwd, { raw: false });
1840
1879
  } catch (err) {
1841
- log7.warn(
1880
+ log6.warn(
1842
1881
  `Could not save the Portless preference: ${err instanceof Error ? err.message : String(err)}`
1843
1882
  );
1844
1883
  }
@@ -1847,18 +1886,18 @@ async function maybePromptPortless(args) {
1847
1886
  }
1848
1887
 
1849
1888
  // src/wizard.ts
1850
- import { confirm as confirm2, isCancel as isCancel3, log as log8, multiselect } from "@clack/prompts";
1889
+ import { confirm as confirm2, isCancel as isCancel3, log as log7, multiselect } from "@clack/prompts";
1851
1890
  import { basename } from "path";
1852
1891
 
1853
1892
  // src/provider/cloud-backend.ts
1854
1893
  async function cloudBackendForProvider(provider) {
1855
1894
  switch (provider) {
1856
1895
  case "daytona":
1857
- return (await import("./dist-TMHSUVTP.js")).daytonaBackend;
1896
+ return (await import("./dist-PJFJNXO2.js")).daytonaBackend;
1858
1897
  case "hetzner":
1859
- return (await import("./dist-5FQGYRW5.js")).hetznerBackend;
1898
+ return (await import("./dist-4SUIXKSD.js")).hetznerBackend;
1860
1899
  case "vercel":
1861
- return (await import("./dist-PZW3GWWU.js")).vercelBackend;
1900
+ return (await import("./dist-HT2YV6PB.js")).vercelBackend;
1862
1901
  default:
1863
1902
  return null;
1864
1903
  }
@@ -1909,7 +1948,7 @@ async function maybeRunSetupWizard(args) {
1909
1948
  const proj = await findProjectRoot(args.workspace);
1910
1949
  if (proj.hasAgentboxYaml) return { action: "proceed" };
1911
1950
  if (args.checkpointRef && await checkpointAppliesHere(args)) {
1912
- log8.info(`starting from checkpoint "${args.checkpointRef}"; skipping agentbox.yaml setup`);
1951
+ log7.info(`starting from checkpoint "${args.checkpointRef}"; skipping agentbox.yaml setup`);
1913
1952
  return { action: "proceed" };
1914
1953
  }
1915
1954
  let envFilesToImport;
@@ -1998,7 +2037,7 @@ function logPrune(rebuild) {
1998
2037
  if (rebuild.prunedBytes <= 0) return;
1999
2038
  const mb = Math.round(rebuild.prunedBytes / 1024 / 1024);
2000
2039
  const n = rebuild.pruned.length;
2001
- log9.info(`pruned ${String(n)} stale plugin cache${n === 1 ? "" : "s"} (${String(mb)} MB freed)`);
2040
+ log8.info(`pruned ${String(n)} stale plugin cache${n === 1 ? "" : "s"} (${String(mb)} MB freed)`);
2002
2041
  }
2003
2042
  var RELAY_HOST_URL = `http://127.0.0.1:${String(DEFAULT_RELAY_PORT)}`;
2004
2043
  async function attachClaudeWrapped(box, sessionName, reattach, onError, openIn) {
@@ -2062,7 +2101,7 @@ async function maybeRunClaudeLogin(args) {
2062
2101
  const message = args.authSource === "auth-file" ? "You're on a legacy API token (shows as 'Claude API'). Sign in with your Claude subscription instead?" : "Sign in with your Claude subscription? (saved and reused by every box)";
2063
2102
  const answer = await confirm3({ message, initialValue: true });
2064
2103
  if (isCancel4(answer) || !answer) {
2065
- log9.info("Skipped sign-in \u2014 claude will prompt you to /login inside the box.");
2104
+ log8.info("Skipped sign-in \u2014 claude will prompt you to /login inside the box.");
2066
2105
  return;
2067
2106
  }
2068
2107
  const s = spinner3();
@@ -2076,10 +2115,10 @@ async function maybeRunClaudeLogin(args) {
2076
2115
  s.stop("image ready");
2077
2116
  const exitCode = await runClaudeLoginContainer(args.image, ["--claudeai"]);
2078
2117
  if (exitCode !== 0) {
2079
- log9.warn("Claude login did not complete; continuing \u2014 run `agentbox claude login` to retry.");
2118
+ log8.warn("Claude login did not complete; continuing \u2014 run `agentbox claude login` to retry.");
2080
2119
  return;
2081
2120
  }
2082
- log9.success("Signed in with your Claude subscription \u2014 saved for future boxes.");
2121
+ log8.success("Signed in with your Claude subscription \u2014 saved for future boxes.");
2083
2122
  }
2084
2123
  async function maybeRunCloudClaudeLogin(args) {
2085
2124
  if (!process.stdin.isTTY || args.yes) return;
@@ -2090,7 +2129,7 @@ async function maybeRunCloudClaudeLogin(args) {
2090
2129
  const message = expired ? "Your saved Claude login looks expired. Sign in again? (saved and reused by every box)" : "Sign in with your Claude subscription? (saved and reused by every box)";
2091
2130
  const answer = await confirm3({ message, initialValue: true });
2092
2131
  if (isCancel4(answer) || !answer) {
2093
- log9.info("Skipped sign-in \u2014 claude will prompt you to /login inside the box.");
2132
+ log8.info("Skipped sign-in \u2014 claude will prompt you to /login inside the box.");
2094
2133
  return;
2095
2134
  }
2096
2135
  const s = spinner3();
@@ -2104,10 +2143,10 @@ async function maybeRunCloudClaudeLogin(args) {
2104
2143
  s.stop("image ready");
2105
2144
  const exitCode = await runClaudeLoginContainer(args.image, ["--claudeai"]);
2106
2145
  if (exitCode !== 0) {
2107
- log9.warn("Claude login did not complete; continuing \u2014 run `agentbox claude login` to retry.");
2146
+ log8.warn("Claude login did not complete; continuing \u2014 run `agentbox claude login` to retry.");
2108
2147
  return;
2109
2148
  }
2110
- log9.success("Signed in with your Claude subscription \u2014 saved for future boxes.");
2149
+ log8.success("Signed in with your Claude subscription \u2014 saved for future boxes.");
2111
2150
  }
2112
2151
  var claudeCommand = new Command2("claude").description("Create a sandboxed box and launch Claude Code in a detachable tmux session").option("-w, --workspace <path>", "host workspace to mount", process.cwd()).option("-n, --name <name>", "friendly box name (default: <workspace-basename>-<id>)").option("--host-snapshot", "APFS-clone the host workspace into a per-box scratch dir before seeding /workspace (stabilizes the tar-pipe source)").option("--no-host-snapshot", "tar-pipe directly from the live host workspace at create time").option(
2113
2152
  "--snapshot <ref>",
@@ -2174,14 +2213,14 @@ var claudeCommand = new Command2("claude").description("Create a sandboxed box a
2174
2213
  intro("Starting Claude in a box...");
2175
2214
  let resumeMode = null;
2176
2215
  if (opts.continue === true && opts.resume) {
2177
- log9.error("only one of -c / --continue / --resume can be passed");
2216
+ log8.error("only one of -c / --continue / --resume can be passed");
2178
2217
  cmdLog.close();
2179
2218
  process.exit(2);
2180
2219
  }
2181
2220
  if (opts.continue === true) resumeMode = { kind: "continue" };
2182
2221
  else if (opts.resume) resumeMode = { kind: "resume", id: opts.resume };
2183
2222
  if (resumeMode && opts.initialPrompt && opts.initialPrompt.length > 0) {
2184
- log9.error("-i / --initial-prompt cannot be combined with -c / --resume (seeding a new turn into a resumed session is not supported).");
2223
+ log8.error("-i / --initial-prompt cannot be combined with -c / --resume (seeding a new turn into a resumed session is not supported).");
2185
2224
  cmdLog.close();
2186
2225
  process.exit(2);
2187
2226
  }
@@ -2196,7 +2235,7 @@ var claudeCommand = new Command2("claude").description("Create a sandboxed box a
2196
2235
  });
2197
2236
  } catch (err) {
2198
2237
  if (err instanceof TeleportError) {
2199
- log9.error(err.message);
2238
+ log8.error(err.message);
2200
2239
  cmdLog.close();
2201
2240
  process.exit(2);
2202
2241
  }
@@ -2211,7 +2250,7 @@ var claudeCommand = new Command2("claude").description("Create a sandboxed box a
2211
2250
  const isCloud = providerName !== "docker";
2212
2251
  if (opts.initialPrompt && opts.initialPrompt.length > 0) {
2213
2252
  if (isCloud) {
2214
- log9.error("-i / --initial-prompt is currently docker-only (cloud sessions only start on attach).");
2253
+ log8.error("-i / --initial-prompt is currently docker-only (cloud sessions only start on attach).");
2215
2254
  cmdLog.close();
2216
2255
  process.exit(2);
2217
2256
  }
@@ -2222,7 +2261,7 @@ var claudeCommand = new Command2("claude").description("Create a sandboxed box a
2222
2261
  });
2223
2262
  } catch (err) {
2224
2263
  if (err instanceof MissingAgentCredsError) {
2225
- log9.error(err.message);
2264
+ log8.error(err.message);
2226
2265
  cmdLog.close();
2227
2266
  process.exit(2);
2228
2267
  }
@@ -2240,7 +2279,7 @@ var claudeCommand = new Command2("claude").description("Create a sandboxed box a
2240
2279
  maxRunningOverride,
2241
2280
  maxWorkingOverride
2242
2281
  });
2243
- outro2(
2282
+ outro(
2244
2283
  `job ${result.job.id} queued (${String(result.runningCount)}/${String(result.maxConcurrent)} running); log: ${result.job.logPath}`
2245
2284
  );
2246
2285
  cmdLog.close();
@@ -2280,13 +2319,13 @@ var claudeCommand = new Command2("claude").description("Create a sandboxed box a
2280
2319
  onLog: (line) => cmdLog.write(line)
2281
2320
  });
2282
2321
  if (gate.decision === "cancel") {
2283
- log9.warn("carry: cancelled \u2014 not creating the box");
2322
+ log8.warn("carry: cancelled \u2014 not creating the box");
2284
2323
  cmdLog.close();
2285
2324
  process.exit(0);
2286
2325
  }
2287
2326
  if (gate.decision === "approve") carryEntries = gate.entries;
2288
2327
  } catch (err) {
2289
- log9.error(err instanceof Error ? err.message : String(err));
2328
+ log8.error(err instanceof Error ? err.message : String(err));
2290
2329
  cmdLog.close();
2291
2330
  process.exit(1);
2292
2331
  }
@@ -2316,7 +2355,7 @@ var claudeCommand = new Command2("claude").description("Create a sandboxed box a
2316
2355
  }));
2317
2356
  } catch (err) {
2318
2357
  if (err instanceof FromBranchError || err instanceof UseBranchError) {
2319
- log9.error(err.message);
2358
+ log8.error(err.message);
2320
2359
  cmdLog.close();
2321
2360
  process.exit(2);
2322
2361
  }
@@ -2360,7 +2399,7 @@ var claudeCommand = new Command2("claude").description("Create a sandboxed box a
2360
2399
  return { agentArgsPrefix: resumePrepared.forwardArgs };
2361
2400
  } catch (err) {
2362
2401
  if (err instanceof TeleportError) {
2363
- log9.error(err.message);
2402
+ log8.error(err.message);
2364
2403
  cmdLog.close();
2365
2404
  process.exit(2);
2366
2405
  }
@@ -2430,8 +2469,8 @@ var claudeCommand = new Command2("claude").description("Create a sandboxed box a
2430
2469
  } catch (err) {
2431
2470
  if (err instanceof TeleportError) {
2432
2471
  s.stop("teleport failed");
2433
- log9.error(err.message);
2434
- log9.info(
2472
+ log8.error(err.message);
2473
+ log8.info(
2435
2474
  `The box ${result.record.container} is up but unused. Destroy it with: agentbox destroy ${result.record.container} -y`
2436
2475
  );
2437
2476
  cmdLog.close();
@@ -2448,20 +2487,26 @@ var claudeCommand = new Command2("claude").description("Create a sandboxed box a
2448
2487
  boxName: result.record.name
2449
2488
  });
2450
2489
  const nSuffix = typeof result.record.projectIndex === "number" ? ` \xB7 n ${String(result.record.projectIndex)}` : "";
2451
- s.stop(`box ${result.record.container} ready${nSuffix}`);
2490
+ s.stop(`box ready${nSuffix}`);
2452
2491
  logPrune(rebuild);
2453
2492
  for (const f of rebuild.failed) {
2454
- log9.warn(`plugin install failed for ${f.dir}; claude may still load it. stderr:
2493
+ log8.warn(`plugin install failed for ${f.dir}; claude may still load it. stderr:
2455
2494
  ${f.stderr.trim()}`);
2456
2495
  }
2457
2496
  maybeShowInstallHint();
2497
+ await printLaunchRecap({
2498
+ record: result.record,
2499
+ mode: "claude",
2500
+ reattach: reattachRef(result.record),
2501
+ workspacePath: opts.workspace,
2502
+ fromBranch,
2503
+ useBranch,
2504
+ checkpointRef,
2505
+ attaching: opts.attach !== false
2506
+ });
2458
2507
  if (opts.attach === false) {
2459
- outro2(
2460
- `session started \u2014 attach with: agentbox claude attach ${reattachRef(result.record)}`
2461
- );
2462
2508
  return;
2463
2509
  }
2464
- outro2("attaching \u2014 Control+a d to detach, leaves claude running");
2465
2510
  await attachClaudeWrapped(
2466
2511
  result.record,
2467
2512
  sessionName,
@@ -2473,10 +2518,10 @@ ${f.stderr.trim()}`);
2473
2518
  s.stop("failed");
2474
2519
  cmdLog.write(`FAIL: ${err instanceof Error ? err.stack ?? err.message : String(err)}`);
2475
2520
  if (err instanceof ClaudeSessionError) {
2476
- log9.error(err.message);
2521
+ log8.error(err.message);
2477
2522
  if (containerName) {
2478
- log9.info(`The box ${containerName} is still running. Destroy it with:`);
2479
- log9.info(` agentbox destroy ${containerName} -y`);
2523
+ log8.info(`The box ${containerName} is still running. Destroy it with:`);
2524
+ log8.info(` agentbox destroy ${containerName} -y`);
2480
2525
  }
2481
2526
  cmdLog.close();
2482
2527
  process.exit(1);
@@ -2514,12 +2559,12 @@ async function startOrAttachClaude(box, claudeArgs, opts, resumePrepared) {
2514
2559
  );
2515
2560
  }
2516
2561
  if (!wantAttach) {
2517
- outro2(
2562
+ outro(
2518
2563
  `session "${sessionName}" already running \u2014 attach with: agentbox claude attach ${reattachRef(box)}`
2519
2564
  );
2520
2565
  return;
2521
2566
  }
2522
- outro2(`session "${sessionName}" already running \u2014 attaching (Control+a d to detach)`);
2567
+ outro(`session "${sessionName}" already running \u2014 attaching (Control+a d to detach)`);
2523
2568
  await attachClaudeWrapped(box, sessionName, reattachRef(box), void 0, openIn);
2524
2569
  return;
2525
2570
  }
@@ -2577,7 +2622,7 @@ async function startOrAttachClaude(box, claudeArgs, opts, resumePrepared) {
2577
2622
  } catch (err) {
2578
2623
  if (err instanceof TeleportError) {
2579
2624
  s.stop("teleport failed");
2580
- log9.error(err.message);
2625
+ log8.error(err.message);
2581
2626
  process.exit(2);
2582
2627
  }
2583
2628
  throw err;
@@ -2593,16 +2638,16 @@ async function startOrAttachClaude(box, claudeArgs, opts, resumePrepared) {
2593
2638
  s.stop(`box ${box.container} ready`);
2594
2639
  logPrune(rebuild);
2595
2640
  for (const f of rebuild.failed) {
2596
- log9.warn(`plugin install failed for ${f.dir}; claude may still load it. stderr:
2641
+ log8.warn(`plugin install failed for ${f.dir}; claude may still load it. stderr:
2597
2642
  ${f.stderr.trim()}`);
2598
2643
  }
2599
2644
  if (!wantAttach) {
2600
- outro2(
2645
+ outro(
2601
2646
  `session "${sessionName}" started \u2014 attach with: agentbox claude attach ${reattachRef(box)}`
2602
2647
  );
2603
2648
  return;
2604
2649
  }
2605
- outro2("attaching \u2014 Control+a d to detach, leaves claude running");
2650
+ outro("attaching \u2014 Control+a d to detach, leaves claude running");
2606
2651
  await attachClaudeWrapped(box, sessionName, reattachRef(box), void 0, openIn);
2607
2652
  }
2608
2653
  var claudeAttachCommand = new Command2("attach").description(
@@ -2632,7 +2677,7 @@ var claudeAttachCommand = new Command2("attach").description(
2632
2677
  await startOrAttachClaude(box, [], { ...opts, syncConfig: false });
2633
2678
  } catch (err) {
2634
2679
  if (err instanceof ClaudeSessionError) {
2635
- log9.error(err.message);
2680
+ log8.error(err.message);
2636
2681
  process.exit(1);
2637
2682
  }
2638
2683
  handleLifecycleError(err);
@@ -2664,7 +2709,7 @@ var claudeStartCommand = new Command2("start").description(
2664
2709
  let effectiveClaudeArgs = shifted && idOrName ? [idOrName, ...claudeArgs] : claudeArgs;
2665
2710
  let resumeMode = null;
2666
2711
  if (opts.continue === true && opts.resume) {
2667
- log9.error("only one of -c / --continue / --resume can be passed");
2712
+ log8.error("only one of -c / --continue / --resume can be passed");
2668
2713
  process.exit(2);
2669
2714
  }
2670
2715
  if (opts.continue === true) resumeMode = { kind: "continue" };
@@ -2679,7 +2724,7 @@ var claudeStartCommand = new Command2("start").description(
2679
2724
  });
2680
2725
  } catch (err) {
2681
2726
  if (err instanceof TeleportError) {
2682
- log9.error(err.message);
2727
+ log8.error(err.message);
2683
2728
  process.exit(2);
2684
2729
  }
2685
2730
  throw err;
@@ -2687,7 +2732,7 @@ var claudeStartCommand = new Command2("start").description(
2687
2732
  }
2688
2733
  if ((box.provider ?? "docker") !== "docker") {
2689
2734
  if (opts.attach === false) {
2690
- outro2(
2735
+ outro(
2691
2736
  `--no-attach: cloud agent sessions are started lazily on attach. Run: agentbox claude attach ${reattachRef(box)}`
2692
2737
  );
2693
2738
  return;
@@ -2706,7 +2751,7 @@ var claudeStartCommand = new Command2("start").description(
2706
2751
  effectiveClaudeArgs = [...resumePrepared.forwardArgs, ...effectiveClaudeArgs];
2707
2752
  } catch (err) {
2708
2753
  if (err instanceof TeleportError) {
2709
- log9.error(err.message);
2754
+ log8.error(err.message);
2710
2755
  process.exit(2);
2711
2756
  }
2712
2757
  throw err;
@@ -2725,7 +2770,7 @@ var claudeStartCommand = new Command2("start").description(
2725
2770
  await startOrAttachClaude(box, effectiveClaudeArgs, opts, resumePrepared);
2726
2771
  } catch (err) {
2727
2772
  if (err instanceof ClaudeSessionError) {
2728
- log9.error(err.message);
2773
+ log8.error(err.message);
2729
2774
  process.exit(1);
2730
2775
  }
2731
2776
  handleLifecycleError(err);
@@ -2739,7 +2784,7 @@ var claudeLoginCommand = new Command2("login").description(
2739
2784
  ).action(async (args) => {
2740
2785
  intro("Signing in to Claude...");
2741
2786
  if (!process.stdin.isTTY) {
2742
- log9.error("`agentbox claude login` needs an interactive terminal.");
2787
+ log8.error("`agentbox claude login` needs an interactive terminal.");
2743
2788
  process.exit(1);
2744
2789
  }
2745
2790
  try {
@@ -2751,10 +2796,10 @@ var claudeLoginCommand = new Command2("login").description(
2751
2796
  s.stop("image ready");
2752
2797
  const exitCode = await runClaudeLoginContainer(image, args);
2753
2798
  if (exitCode !== 0) {
2754
- log9.warn(`\`claude auth login\` exited with code ${String(exitCode)}`);
2799
+ log8.warn(`\`claude auth login\` exited with code ${String(exitCode)}`);
2755
2800
  process.exit(exitCode);
2756
2801
  }
2757
- outro2("signed in \u2014 credentials saved for future boxes");
2802
+ outro("signed in \u2014 credentials saved for future boxes");
2758
2803
  } catch (err) {
2759
2804
  handleLifecycleError(err);
2760
2805
  }
@@ -2764,17 +2809,17 @@ claudeCommand.addCommand(claudeStartCommand);
2764
2809
  claudeCommand.addCommand(claudeLoginCommand);
2765
2810
 
2766
2811
  // src/commands/checkpoint.ts
2767
- import { confirm as confirm4, isCancel as isCancel5, log as log10 } from "@clack/prompts";
2812
+ import { confirm as confirm4, isCancel as isCancel5, log as log9 } from "@clack/prompts";
2768
2813
  import { Command as Command3 } from "commander";
2769
2814
  var CLOUD_BACKENDS = ["daytona", "hetzner", "vercel"];
2770
2815
  async function cloudProviderFor(backend) {
2771
2816
  switch (backend) {
2772
2817
  case "daytona":
2773
- return (await import("./dist-TMHSUVTP.js")).daytonaProvider;
2818
+ return (await import("./dist-PJFJNXO2.js")).daytonaProvider;
2774
2819
  case "hetzner":
2775
- return (await import("./dist-5FQGYRW5.js")).hetznerProvider;
2820
+ return (await import("./dist-4SUIXKSD.js")).hetznerProvider;
2776
2821
  case "vercel":
2777
- return (await import("./dist-PZW3GWWU.js")).vercelProvider;
2822
+ return (await import("./dist-HT2YV6PB.js")).vercelProvider;
2778
2823
  }
2779
2824
  }
2780
2825
  var CHECKPOINT_NOTICE = "Checkpoint in progress \u2014 the box will be unresponsive for a moment";
@@ -2798,10 +2843,10 @@ var createSub = new Command3("create").description("Capture a box state as a pro
2798
2843
  }
2799
2844
  const insp = await inspectBox(box.id);
2800
2845
  if (insp.state === "paused") {
2801
- log10.info("box is paused; unpausing");
2846
+ log9.info("box is paused; unpausing");
2802
2847
  await unpauseBox(box.id);
2803
2848
  } else if (insp.state === "stopped") {
2804
- log10.info("box is stopped; starting");
2849
+ log9.info("box is stopped; starting");
2805
2850
  await startBox(box.id);
2806
2851
  } else if (insp.state === "missing") {
2807
2852
  throw new Error(`box ${box.name} has no container; was it destroyed?`);
@@ -2836,13 +2881,13 @@ var createSub = new Command3("create").description("Capture a box state as a pro
2836
2881
  setDefault: opts.setDefault === true,
2837
2882
  replace: opts.replace === true,
2838
2883
  maxLayers: cfg.effective.checkpoint.maxLayers,
2839
- onLog: (line) => log10.info(line)
2884
+ onLog: (line) => log9.info(line)
2840
2885
  });
2841
- log10.success(
2886
+ log9.success(
2842
2887
  `checkpoint ${info.name} (${info.manifest.type}) -> ${info.dir}` + (opts.setDefault ? " [project default]" : "")
2843
2888
  );
2844
2889
  if (!opts.setDefault) {
2845
- log10.info(
2890
+ log9.info(
2846
2891
  `make it the default for new boxes: agentbox checkpoint set-default ${info.name}`
2847
2892
  );
2848
2893
  }
@@ -2957,7 +3002,7 @@ var rmSub = new Command3("rm").description("Delete a checkpoint (any provider th
2957
3002
  if (!opts.yes) {
2958
3003
  const ok = await confirm4({ message: `Delete checkpoint ${ref}?`, initialValue: false });
2959
3004
  if (isCancel5(ok) || !ok) {
2960
- log10.info("cancelled");
3005
+ log9.info("cancelled");
2961
3006
  return;
2962
3007
  }
2963
3008
  }
@@ -2978,7 +3023,7 @@ var rmSub = new Command3("rm").description("Delete a checkpoint (any provider th
2978
3023
  process.stdout.write(`removed ${backend} checkpoint ${ref}
2979
3024
  `);
2980
3025
  } catch (err) {
2981
- log10.warn(
3026
+ log9.warn(
2982
3027
  `${backend} checkpoint remove failed: ${err instanceof Error ? err.message : String(err)}`
2983
3028
  );
2984
3029
  }
@@ -2996,9 +3041,9 @@ var rmSub = new Command3("rm").description("Delete a checkpoint (any provider th
2996
3041
  for (const [key, projectValue, effectiveValue] of defKeys) {
2997
3042
  if (projectValue === ref) {
2998
3043
  await unsetConfigValue("project", key, projectRoot);
2999
- log10.info(`cleared project ${key} (was ${ref})`);
3044
+ log9.info(`cleared project ${key} (was ${ref})`);
3000
3045
  } else if (effectiveValue === ref) {
3001
- log10.warn(
3046
+ log9.warn(
3002
3047
  `${key} = ${ref} is set outside the per-project config (global or agentbox.yaml defaults) \u2014 clear it manually`
3003
3048
  );
3004
3049
  }
@@ -3009,17 +3054,17 @@ var rmSub = new Command3("rm").description("Delete a checkpoint (any provider th
3009
3054
  });
3010
3055
  async function runCloudCheckpointCreate(box, opts) {
3011
3056
  if (opts.merged) {
3012
- log10.warn("--merged is Docker-only (cloud snapshots are always flattened); ignoring");
3057
+ log9.warn("--merged is Docker-only (cloud snapshots are always flattened); ignoring");
3013
3058
  }
3014
3059
  const projectRoot = await projectRootFor(box.workspacePath, box.projectRoot);
3015
3060
  const name = opts.name ?? `${box.name}-${String(Date.now()).slice(-6)}`;
3016
3061
  const provider = await providerForBox(box);
3017
3062
  const state = await provider.probeState(box);
3018
3063
  if (state === "paused") {
3019
- log10.info("box is paused; resuming");
3064
+ log9.info("box is paused; resuming");
3020
3065
  await provider.resume(box);
3021
3066
  } else if (state === "stopped") {
3022
- log10.info("box is stopped; starting");
3067
+ log9.info("box is stopped; starting");
3023
3068
  await provider.start(box);
3024
3069
  } else if (state === "missing") {
3025
3070
  throw new Error(`cloud sandbox for ${box.name} is missing; was it deleted?`);
@@ -3033,7 +3078,7 @@ async function runCloudCheckpointCreate(box, opts) {
3033
3078
  initialValue: false
3034
3079
  });
3035
3080
  if (isCancel5(ok) || !ok) {
3036
- log10.info("cancelled");
3081
+ log9.info("cancelled");
3037
3082
  return;
3038
3083
  }
3039
3084
  }
@@ -3048,21 +3093,21 @@ async function runCloudCheckpointCreate(box, opts) {
3048
3093
  try {
3049
3094
  const saved = await provider.extractAgentCredentials(box);
3050
3095
  if (saved.length > 0) {
3051
- log10.info(`saved ${saved.join(", ")} login to ~/.agentbox for future boxes`);
3096
+ log9.info(`saved ${saved.join(", ")} login to ~/.agentbox for future boxes`);
3052
3097
  }
3053
3098
  } catch (err) {
3054
- log10.warn(`agent credential extract skipped: ${err instanceof Error ? err.message : String(err)}`);
3099
+ log9.warn(`agent credential extract skipped: ${err instanceof Error ? err.message : String(err)}`);
3055
3100
  }
3056
3101
  }
3057
- log10.info(`capturing cloud snapshot '${name}' (this may take a few minutes)`);
3102
+ log9.info(`capturing cloud snapshot '${name}' (this may take a few minutes)`);
3058
3103
  const result = await provider.checkpoint.create(box, name);
3059
- log10.success(`checkpoint ${result.ref} (daytona snapshot) captured`);
3104
+ log9.success(`checkpoint ${result.ref} (daytona snapshot) captured`);
3060
3105
  if (opts.setDefault) {
3061
3106
  const key = defaultCheckpointConfigKey(box.provider ?? "daytona");
3062
3107
  await setConfigValue("project", key, result.ref, projectRoot);
3063
- log10.info(`set project default checkpoint (${key}) -> ${result.ref}`);
3108
+ log9.info(`set project default checkpoint (${key}) -> ${result.ref}`);
3064
3109
  } else {
3065
- log10.info(
3110
+ log9.info(
3066
3111
  `make it the default for new boxes: agentbox checkpoint set-default --provider ${box.provider ?? "daytona"} ${result.ref}`
3067
3112
  );
3068
3113
  }
@@ -3074,15 +3119,15 @@ var checkpointCommand = new Command3("checkpoint").alias("checkpoints").descript
3074
3119
 
3075
3120
  // src/commands/code.ts
3076
3121
  import { spawn } from "child_process";
3077
- import { log as log11 } from "@clack/prompts";
3122
+ import { log as log10 } from "@clack/prompts";
3078
3123
  import { Command as Command4, InvalidArgumentError } from "commander";
3079
3124
 
3080
3125
  // src/ssh-config.ts
3081
3126
  import { promises as fs } from "fs";
3082
- import { homedir as homedir7 } from "os";
3127
+ import { homedir as homedir8 } from "os";
3083
3128
  import { join as join9 } from "path";
3084
3129
  function sshConfigPath() {
3085
- return join9(homedir7(), ".ssh", "config");
3130
+ return join9(homedir8(), ".ssh", "config");
3086
3131
  }
3087
3132
  function beginMarker(alias) {
3088
3133
  return `# BEGIN agentbox cloud box ${alias}`;
@@ -3133,7 +3178,7 @@ function buildBlock(opts) {
3133
3178
  }
3134
3179
  async function writeAgentboxSshAlias(opts) {
3135
3180
  const path = sshConfigPath();
3136
- await fs.mkdir(join9(homedir7(), ".ssh"), { recursive: true, mode: 448 });
3181
+ await fs.mkdir(join9(homedir8(), ".ssh"), { recursive: true, mode: 448 });
3137
3182
  const existing = await readConfig();
3138
3183
  const stripped = stripBlock(existing, opts.alias);
3139
3184
  const separator = stripped.length === 0 || stripped.endsWith("\n") ? "" : "\n";
@@ -3215,11 +3260,11 @@ var codeCommand = new Command4("code").description("Open a box in VS Code or Cur
3215
3260
  }
3216
3261
  const exit = await launchIde(folderUri, forcedIde);
3217
3262
  if (exit.code !== 0) {
3218
- log11.error(`failed to launch ${exit.flavor ? ideProfile(exit.flavor).displayName : "IDE"} via ${exit.via} (exit ${String(exit.code)})`);
3263
+ log10.error(`failed to launch ${exit.flavor ? ideProfile(exit.flavor).displayName : "IDE"} via ${exit.via} (exit ${String(exit.code)})`);
3219
3264
  process.stdout.write(folderUri + "\n");
3220
3265
  process.exit(1);
3221
3266
  }
3222
- log11.success(
3267
+ log10.success(
3223
3268
  `opening ${box.name} in ${ideProfile(exit.flavor).displayName} (${exit.via})`
3224
3269
  );
3225
3270
  } catch (err) {
@@ -3229,10 +3274,10 @@ var codeCommand = new Command4("code").description("Open a box in VS Code or Cur
3229
3274
  async function prepareDockerAttach(box, opts) {
3230
3275
  const insp = await inspectBox(box.id);
3231
3276
  if (insp.state === "paused") {
3232
- log11.info(`box is paused; unpausing`);
3277
+ log10.info(`box is paused; unpausing`);
3233
3278
  await unpauseBox(box.id);
3234
3279
  } else if (insp.state === "stopped") {
3235
- log11.info(`box is stopped; starting`);
3280
+ log10.info(`box is stopped; starting`);
3236
3281
  await startBox(box.id);
3237
3282
  } else if (insp.state === "missing") {
3238
3283
  throw new Error(`box ${box.name} has no container; was it destroyed?`);
@@ -3243,9 +3288,9 @@ async function prepareDockerAttach(box, opts) {
3243
3288
  const lines = [];
3244
3289
  if (reply.timedOut.length > 0) lines.push(`timed out: ${reply.timedOut.join(", ")}`);
3245
3290
  if (reply.failed.length > 0) lines.push(`failed: ${reply.failed.join(", ")}`);
3246
- log11.warn(`box not fully ready (${lines.join("; ")}). Opening anyway.`);
3291
+ log10.warn(`box not fully ready (${lines.join("; ")}). Opening anyway.`);
3247
3292
  } else {
3248
- log11.success("all units ready");
3293
+ log10.success("all units ready");
3249
3294
  }
3250
3295
  }
3251
3296
  if (opts.autoTerminals) {
@@ -3255,14 +3300,14 @@ async function prepareDockerAttach(box, opts) {
3255
3300
  regen: opts.regenTasks
3256
3301
  });
3257
3302
  if (r.status === "wrote") {
3258
- log11.info(`wrote /workspace/.vscode/tasks.json (${String(services.length)} service(s))`);
3303
+ log10.info(`wrote /workspace/.vscode/tasks.json (${String(services.length)} service(s))`);
3259
3304
  } else if (r.status === "skipped-user-owned") {
3260
- log11.warn(
3305
+ log10.warn(
3261
3306
  "user-owned .vscode/tasks.json detected; skipping auto-terminals (pass --regen-tasks to overwrite)"
3262
3307
  );
3263
3308
  }
3264
3309
  } catch (err) {
3265
- log11.warn(
3310
+ log10.warn(
3266
3311
  `auto-terminals failed: ${err instanceof Error ? err.message : String(err)}`
3267
3312
  );
3268
3313
  }
@@ -3274,10 +3319,10 @@ async function prepareCloudAttach(box, opts) {
3274
3319
  const p = await providerForBox(box);
3275
3320
  const state = await p.probeState(box);
3276
3321
  if (state === "paused") {
3277
- log11.info("box is paused; resuming");
3322
+ log10.info("box is paused; resuming");
3278
3323
  await p.resume(box);
3279
3324
  } else if (state === "stopped") {
3280
- log11.info("box is stopped; starting");
3325
+ log10.info("box is stopped; starting");
3281
3326
  await p.start(box);
3282
3327
  } else if (state === "missing") {
3283
3328
  throw new Error(`cloud sandbox for ${box.name} is missing; was it deleted?`);
@@ -3290,12 +3335,12 @@ async function prepareCloudAttach(box, opts) {
3290
3335
  const lines = [];
3291
3336
  if (reply.timedOut.length > 0) lines.push(`timed out: ${reply.timedOut.join(", ")}`);
3292
3337
  if (reply.failed.length > 0) lines.push(`failed: ${reply.failed.join(", ")}`);
3293
- log11.warn(`box not fully ready (${lines.join("; ")}). Opening anyway.`);
3338
+ log10.warn(`box not fully ready (${lines.join("; ")}). Opening anyway.`);
3294
3339
  } else {
3295
- log11.success("all units ready");
3340
+ log10.success("all units ready");
3296
3341
  }
3297
3342
  } catch (err) {
3298
- log11.warn(`wait-ready failed (continuing): ${err instanceof Error ? err.message : String(err)}`);
3343
+ log10.warn(`wait-ready failed (continuing): ${err instanceof Error ? err.message : String(err)}`);
3299
3344
  }
3300
3345
  }
3301
3346
  if (!p.buildAttach) {
@@ -3317,7 +3362,7 @@ async function prepareCloudAttach(box, opts) {
3317
3362
  user: target.user,
3318
3363
  identityFile: target.identityFile
3319
3364
  });
3320
- log11.info(`updated ~/.ssh/config alias ${alias}`);
3365
+ log10.info(`updated ~/.ssh/config alias ${alias}`);
3321
3366
  return `vscode-remote://ssh-remote+${alias}/workspace`;
3322
3367
  }
3323
3368
  async function runWaitReadyDocker(container, timeoutMs) {
@@ -3342,7 +3387,7 @@ async function launchIde(folderUri, forced) {
3342
3387
  if (code !== null) return code;
3343
3388
  const cursor = await tryCli("cursor", folderUri);
3344
3389
  if (cursor !== null) return cursor;
3345
- log11.warn("neither `code` nor `cursor` found in PATH; falling back to `open vscode://...`");
3390
+ log10.warn("neither `code` nor `cursor` found in PATH; falling back to `open vscode://...`");
3346
3391
  return launchOne("vscode", folderUri);
3347
3392
  }
3348
3393
  async function tryCli(flavor, folderUri) {
@@ -3355,11 +3400,11 @@ async function launchOne(flavor, folderUri) {
3355
3400
  const profile = ideProfile(flavor);
3356
3401
  const cliCode = await spawnCommand(profile.cli, ["--folder-uri", folderUri]);
3357
3402
  if (cliCode !== 127) return { code: cliCode, flavor, via: "cli" };
3358
- log11.warn(
3359
- `\`${profile.cli}\` not found in PATH; falling back to \`open ${profile.protocolScheme}://...\` (the %2B URL-encoding bug may break attach)`
3403
+ log10.warn(
3404
+ `\`${profile.cli}\` not found in PATH; falling back to \`${hostOpenCommand()} ${profile.protocolScheme}://...\` (the %2B URL-encoding bug may break attach)`
3360
3405
  );
3361
3406
  const url = `${profile.protocolScheme}://${folderUri.replace(/^vscode-remote:\/\//, "vscode-remote/")}`;
3362
- const fallback = await spawnCommand("open", [url]);
3407
+ const fallback = await spawnCommand(hostOpenCommand(), [url]);
3363
3408
  return { code: fallback, flavor, via: "open" };
3364
3409
  }
3365
3410
  function spawnCommand(cmd, args) {
@@ -3384,9 +3429,9 @@ async function fetchServiceNamesDocker(container) {
3384
3429
 
3385
3430
  // src/commands/codex.ts
3386
3431
  import { access } from "fs/promises";
3387
- import { homedir as homedir8 } from "os";
3432
+ import { homedir as homedir9 } from "os";
3388
3433
  import { join as join10 } from "path";
3389
- import { confirm as confirm5, intro as intro2, isCancel as isCancel6, log as log12, outro as outro3, spinner as spinner4 } from "@clack/prompts";
3434
+ import { confirm as confirm5, intro as intro2, isCancel as isCancel6, log as log11, outro as outro2, spinner as spinner4 } from "@clack/prompts";
3390
3435
  import { Command as Command5 } from "commander";
3391
3436
  function reattachRef2(r) {
3392
3437
  return typeof r.projectIndex === "number" ? String(r.projectIndex) : r.name;
@@ -3463,7 +3508,7 @@ async function maybeRunCodexLogin(args) {
3463
3508
  initialValue: true
3464
3509
  });
3465
3510
  if (isCancel6(answer) || !answer) {
3466
- log12.info("Skipped sign-in \u2014 codex will prompt you to sign in inside the box.");
3511
+ log11.info("Skipped sign-in \u2014 codex will prompt you to sign in inside the box.");
3467
3512
  return;
3468
3513
  }
3469
3514
  const s = spinner4();
@@ -3474,14 +3519,14 @@ async function maybeRunCodexLogin(args) {
3474
3519
  s.stop("image ready");
3475
3520
  const exitCode = await runCodexLoginContainer(args.image, []);
3476
3521
  if (exitCode !== 0) {
3477
- log12.warn("Codex login did not complete; continuing \u2014 run `agentbox codex login` to retry.");
3522
+ log11.warn("Codex login did not complete; continuing \u2014 run `agentbox codex login` to retry.");
3478
3523
  return;
3479
3524
  }
3480
- log12.success("Signed in to Codex \u2014 saved for future boxes.");
3525
+ log11.success("Signed in to Codex \u2014 saved for future boxes.");
3481
3526
  }
3482
3527
  async function cloudCodexCredAvailable(env = process.env) {
3483
3528
  if ((env["OPENAI_API_KEY"] ?? "").length > 0) return true;
3484
- for (const p of [CODEX_CREDENTIALS_BACKUP_FILE, join10(homedir8(), ".codex", "auth.json")]) {
3529
+ for (const p of [CODEX_CREDENTIALS_BACKUP_FILE, join10(homedir9(), ".codex", "auth.json")]) {
3485
3530
  try {
3486
3531
  await access(p);
3487
3532
  return true;
@@ -3498,7 +3543,7 @@ async function maybeRunCloudCodexLogin(args) {
3498
3543
  initialValue: true
3499
3544
  });
3500
3545
  if (isCancel6(answer) || !answer) {
3501
- log12.info("Skipped sign-in \u2014 codex will prompt you to sign in inside the box.");
3546
+ log11.info("Skipped sign-in \u2014 codex will prompt you to sign in inside the box.");
3502
3547
  return;
3503
3548
  }
3504
3549
  const s = spinner4();
@@ -3509,12 +3554,12 @@ async function maybeRunCloudCodexLogin(args) {
3509
3554
  s.stop("image ready");
3510
3555
  const exitCode = await runCodexLoginContainer(args.image, []);
3511
3556
  if (exitCode !== 0) {
3512
- log12.warn("Codex login did not complete; continuing \u2014 run `agentbox codex login` to retry.");
3557
+ log11.warn("Codex login did not complete; continuing \u2014 run `agentbox codex login` to retry.");
3513
3558
  return;
3514
3559
  }
3515
3560
  const { copied } = await extractCodexCredentials(SHARED_CODEX_VOLUME, args.image);
3516
- if (copied) log12.success("Signed in to Codex \u2014 saved for future boxes.");
3517
- else log12.warn("Codex login finished but no auth.json was captured \u2014 sign in inside the box if needed.");
3561
+ if (copied) log11.success("Signed in to Codex \u2014 saved for future boxes.");
3562
+ else log11.warn("Codex login finished but no auth.json was captured \u2014 sign in inside the box if needed.");
3518
3563
  }
3519
3564
  var codexCommand = new Command5("codex").description("Create a sandboxed box and launch OpenAI Codex in a detachable tmux session").option("-w, --workspace <path>", "host workspace to mount", process.cwd()).option("-n, --name <name>", "friendly box name (default: <workspace-basename>-<id>)").option("--host-snapshot", "APFS-clone the host workspace into a per-box scratch dir before seeding /workspace (stabilizes the tar-pipe source)").option("--no-host-snapshot", "tar-pipe directly from the live host workspace at create time").option(
3520
3565
  "--snapshot <ref>",
@@ -3581,14 +3626,14 @@ var codexCommand = new Command5("codex").description("Create a sandboxed box and
3581
3626
  intro2("Starting Codex in a box...");
3582
3627
  let resumeMode = null;
3583
3628
  if (opts.continue === true && opts.resume) {
3584
- log12.error("only one of -c / --continue / --resume can be passed");
3629
+ log11.error("only one of -c / --continue / --resume can be passed");
3585
3630
  cmdLog.close();
3586
3631
  process.exit(2);
3587
3632
  }
3588
3633
  if (opts.continue === true) resumeMode = { kind: "continue" };
3589
3634
  else if (opts.resume) resumeMode = { kind: "resume", id: opts.resume };
3590
3635
  if (resumeMode && opts.initialPrompt && opts.initialPrompt.length > 0) {
3591
- log12.error("-i / --initial-prompt cannot be combined with -c / --resume.");
3636
+ log11.error("-i / --initial-prompt cannot be combined with -c / --resume.");
3592
3637
  cmdLog.close();
3593
3638
  process.exit(2);
3594
3639
  }
@@ -3603,7 +3648,7 @@ var codexCommand = new Command5("codex").description("Create a sandboxed box and
3603
3648
  });
3604
3649
  } catch (err) {
3605
3650
  if (err instanceof TeleportError) {
3606
- log12.error(err.message);
3651
+ log11.error(err.message);
3607
3652
  cmdLog.close();
3608
3653
  process.exit(2);
3609
3654
  }
@@ -3620,7 +3665,7 @@ var codexCommand = new Command5("codex").description("Create a sandboxed box and
3620
3665
  const checkpointRef = opts.snapshot && opts.snapshot.length > 0 ? opts.snapshot : providerDefault.length > 0 ? providerDefault : void 0;
3621
3666
  if (opts.initialPrompt && opts.initialPrompt.length > 0) {
3622
3667
  if (isCloud) {
3623
- log12.error("-i / --initial-prompt is currently docker-only (cloud sessions only start on attach).");
3668
+ log11.error("-i / --initial-prompt is currently docker-only (cloud sessions only start on attach).");
3624
3669
  cmdLog.close();
3625
3670
  process.exit(2);
3626
3671
  }
@@ -3631,7 +3676,7 @@ var codexCommand = new Command5("codex").description("Create a sandboxed box and
3631
3676
  });
3632
3677
  } catch (err) {
3633
3678
  if (err instanceof MissingAgentCredsError) {
3634
- log12.error(err.message);
3679
+ log11.error(err.message);
3635
3680
  cmdLog.close();
3636
3681
  process.exit(2);
3637
3682
  }
@@ -3649,7 +3694,7 @@ var codexCommand = new Command5("codex").description("Create a sandboxed box and
3649
3694
  maxRunningOverride,
3650
3695
  maxWorkingOverride
3651
3696
  });
3652
- outro3(
3697
+ outro2(
3653
3698
  `job ${result.job.id} queued (${String(result.runningCount)}/${String(result.maxConcurrent)} running); log: ${result.job.logPath}`
3654
3699
  );
3655
3700
  cmdLog.close();
@@ -3665,13 +3710,13 @@ var codexCommand = new Command5("codex").description("Create a sandboxed box and
3665
3710
  onLog: (line) => cmdLog.write(line)
3666
3711
  });
3667
3712
  if (gate.decision === "cancel") {
3668
- log12.warn("carry: cancelled \u2014 not creating the box");
3713
+ log11.warn("carry: cancelled \u2014 not creating the box");
3669
3714
  cmdLog.close();
3670
3715
  process.exit(0);
3671
3716
  }
3672
3717
  if (gate.decision === "approve") carryEntries = gate.entries;
3673
3718
  } catch (err) {
3674
- log12.error(err instanceof Error ? err.message : String(err));
3719
+ log11.error(err instanceof Error ? err.message : String(err));
3675
3720
  cmdLog.close();
3676
3721
  process.exit(1);
3677
3722
  }
@@ -3688,7 +3733,7 @@ var codexCommand = new Command5("codex").description("Create a sandboxed box and
3688
3733
  }));
3689
3734
  } catch (err) {
3690
3735
  if (err instanceof FromBranchError || err instanceof UseBranchError) {
3691
- log12.error(err.message);
3736
+ log11.error(err.message);
3692
3737
  cmdLog.close();
3693
3738
  process.exit(2);
3694
3739
  }
@@ -3732,7 +3777,7 @@ var codexCommand = new Command5("codex").description("Create a sandboxed box and
3732
3777
  return { agentArgsPrefix: resumePrepared.forwardArgs };
3733
3778
  } catch (err) {
3734
3779
  if (err instanceof TeleportError) {
3735
- log12.error(err.message);
3780
+ log11.error(err.message);
3736
3781
  cmdLog.close();
3737
3782
  process.exit(2);
3738
3783
  }
@@ -3807,8 +3852,8 @@ var codexCommand = new Command5("codex").description("Create a sandboxed box and
3807
3852
  } catch (err) {
3808
3853
  if (err instanceof TeleportError) {
3809
3854
  s.stop("teleport failed");
3810
- log12.error(err.message);
3811
- log12.info(
3855
+ log11.error(err.message);
3856
+ log11.info(
3812
3857
  `The box ${result.record.container} is up but unused. Destroy it with: agentbox destroy ${result.record.container} -y`
3813
3858
  );
3814
3859
  cmdLog.close();
@@ -3824,14 +3869,20 @@ var codexCommand = new Command5("codex").description("Create a sandboxed box and
3824
3869
  sessionName
3825
3870
  });
3826
3871
  const nSuffix = typeof result.record.projectIndex === "number" ? ` \xB7 n ${String(result.record.projectIndex)}` : "";
3827
- s.stop(`box ${result.record.container} ready${nSuffix}`);
3872
+ s.stop(`box ready${nSuffix}`);
3873
+ await printLaunchRecap({
3874
+ record: result.record,
3875
+ mode: "codex",
3876
+ reattach: reattachRef2(result.record),
3877
+ workspacePath: opts.workspace,
3878
+ fromBranch,
3879
+ useBranch,
3880
+ checkpointRef,
3881
+ attaching: opts.attach !== false
3882
+ });
3828
3883
  if (opts.attach === false) {
3829
- outro3(
3830
- `session started \u2014 attach with: agentbox codex attach ${reattachRef2(result.record)}`
3831
- );
3832
3884
  return;
3833
3885
  }
3834
- outro3("attaching \u2014 Control+a d to detach, leaves codex running");
3835
3886
  await attachCodexWrapped(
3836
3887
  result.record,
3837
3888
  sessionName,
@@ -3843,10 +3894,10 @@ var codexCommand = new Command5("codex").description("Create a sandboxed box and
3843
3894
  s.stop("failed");
3844
3895
  cmdLog.write(`FAIL: ${err instanceof Error ? err.stack ?? err.message : String(err)}`);
3845
3896
  if (err instanceof CodexSessionError) {
3846
- log12.error(err.message);
3897
+ log11.error(err.message);
3847
3898
  if (containerName) {
3848
- log12.info(`The box ${containerName} is still running. Destroy it with:`);
3849
- log12.info(` agentbox destroy ${containerName} -y`);
3899
+ log11.info(`The box ${containerName} is still running. Destroy it with:`);
3900
+ log11.info(` agentbox destroy ${containerName} -y`);
3850
3901
  }
3851
3902
  cmdLog.close();
3852
3903
  process.exit(1);
@@ -3883,12 +3934,12 @@ async function startOrAttachCodex(box, codexArgs, opts, resumePrepared) {
3883
3934
  );
3884
3935
  }
3885
3936
  if (!wantAttach) {
3886
- outro3(
3937
+ outro2(
3887
3938
  `session "${sessionName}" already running \u2014 attach with: agentbox codex attach ${reattachRef2(box)}`
3888
3939
  );
3889
3940
  return;
3890
3941
  }
3891
- outro3(`session "${sessionName}" already running \u2014 attaching (Control+a d to detach)`);
3942
+ outro2(`session "${sessionName}" already running \u2014 attaching (Control+a d to detach)`);
3892
3943
  await attachCodexWrapped(box, sessionName, reattachRef2(box), void 0, openIn);
3893
3944
  return;
3894
3945
  }
@@ -3932,7 +3983,7 @@ async function startOrAttachCodex(box, codexArgs, opts, resumePrepared) {
3932
3983
  } catch (err) {
3933
3984
  if (err instanceof TeleportError) {
3934
3985
  s.stop("teleport failed");
3935
- log12.error(err.message);
3986
+ log11.error(err.message);
3936
3987
  process.exit(2);
3937
3988
  }
3938
3989
  throw err;
@@ -3942,12 +3993,12 @@ async function startOrAttachCodex(box, codexArgs, opts, resumePrepared) {
3942
3993
  await startCodexSession({ container: box.container, codexArgs: effectiveArgs, sessionName });
3943
3994
  s.stop(`box ${box.container} ready`);
3944
3995
  if (!wantAttach) {
3945
- outro3(
3996
+ outro2(
3946
3997
  `session "${sessionName}" started \u2014 attach with: agentbox codex attach ${reattachRef2(box)}`
3947
3998
  );
3948
3999
  return;
3949
4000
  }
3950
- outro3("attaching \u2014 Control+a d to detach, leaves codex running");
4001
+ outro2("attaching \u2014 Control+a d to detach, leaves codex running");
3951
4002
  await attachCodexWrapped(box, sessionName, reattachRef2(box), void 0, openIn);
3952
4003
  }
3953
4004
  var codexAttachCommand = new Command5("attach").description(
@@ -3977,7 +4028,7 @@ var codexAttachCommand = new Command5("attach").description(
3977
4028
  await startOrAttachCodex(box, [], { ...opts, syncConfig: false });
3978
4029
  } catch (err) {
3979
4030
  if (err instanceof CodexSessionError) {
3980
- log12.error(err.message);
4031
+ log11.error(err.message);
3981
4032
  process.exit(1);
3982
4033
  }
3983
4034
  handleLifecycleError(err);
@@ -4009,7 +4060,7 @@ var codexStartCommand = new Command5("start").description(
4009
4060
  let effectiveCodexArgs = shifted && idOrName ? [idOrName, ...codexArgs] : codexArgs;
4010
4061
  let resumeMode = null;
4011
4062
  if (opts.continue === true && opts.resume) {
4012
- log12.error("only one of -c / --continue / --resume can be passed");
4063
+ log11.error("only one of -c / --continue / --resume can be passed");
4013
4064
  process.exit(2);
4014
4065
  }
4015
4066
  if (opts.continue === true) resumeMode = { kind: "continue" };
@@ -4024,7 +4075,7 @@ var codexStartCommand = new Command5("start").description(
4024
4075
  });
4025
4076
  } catch (err) {
4026
4077
  if (err instanceof TeleportError) {
4027
- log12.error(err.message);
4078
+ log11.error(err.message);
4028
4079
  process.exit(2);
4029
4080
  }
4030
4081
  throw err;
@@ -4032,7 +4083,7 @@ var codexStartCommand = new Command5("start").description(
4032
4083
  }
4033
4084
  if ((box.provider ?? "docker") !== "docker") {
4034
4085
  if (opts.attach === false) {
4035
- outro3(
4086
+ outro2(
4036
4087
  `--no-attach: cloud agent sessions are started lazily on attach. Run: agentbox codex attach ${reattachRef2(box)}`
4037
4088
  );
4038
4089
  return;
@@ -4051,7 +4102,7 @@ var codexStartCommand = new Command5("start").description(
4051
4102
  effectiveCodexArgs = [...resumePrepared.forwardArgs, ...effectiveCodexArgs];
4052
4103
  } catch (err) {
4053
4104
  if (err instanceof TeleportError) {
4054
- log12.error(err.message);
4105
+ log11.error(err.message);
4055
4106
  process.exit(2);
4056
4107
  }
4057
4108
  throw err;
@@ -4070,7 +4121,7 @@ var codexStartCommand = new Command5("start").description(
4070
4121
  await startOrAttachCodex(box, effectiveCodexArgs, opts, resumePrepared);
4071
4122
  } catch (err) {
4072
4123
  if (err instanceof CodexSessionError) {
4073
- log12.error(err.message);
4124
+ log11.error(err.message);
4074
4125
  process.exit(1);
4075
4126
  }
4076
4127
  handleLifecycleError(err);
@@ -4084,7 +4135,7 @@ var codexLoginCommand = new Command5("login").description(
4084
4135
  ).action(async (args) => {
4085
4136
  intro2("Signing in to Codex...");
4086
4137
  if (!process.stdin.isTTY) {
4087
- log12.error("`agentbox codex login` needs an interactive terminal.");
4138
+ log11.error("`agentbox codex login` needs an interactive terminal.");
4088
4139
  process.exit(1);
4089
4140
  }
4090
4141
  try {
@@ -4098,10 +4149,10 @@ var codexLoginCommand = new Command5("login").description(
4098
4149
  s.stop("image ready");
4099
4150
  const exitCode = await runCodexLoginContainer(image, args);
4100
4151
  if (exitCode !== 0) {
4101
- log12.warn(`\`codex login\` exited with code ${String(exitCode)}`);
4152
+ log11.warn(`\`codex login\` exited with code ${String(exitCode)}`);
4102
4153
  process.exit(exitCode);
4103
4154
  }
4104
- outro3("signed in \u2014 credentials saved for future boxes");
4155
+ outro2("signed in \u2014 credentials saved for future boxes");
4105
4156
  } catch (err) {
4106
4157
  handleLifecycleError(err);
4107
4158
  }
@@ -4112,9 +4163,9 @@ codexCommand.addCommand(codexLoginCommand);
4112
4163
 
4113
4164
  // src/commands/opencode.ts
4114
4165
  import { access as access2 } from "fs/promises";
4115
- import { homedir as homedir9 } from "os";
4166
+ import { homedir as homedir10 } from "os";
4116
4167
  import { join as join11 } from "path";
4117
- import { confirm as confirm6, intro as intro3, isCancel as isCancel7, log as log13, outro as outro4, spinner as spinner5 } from "@clack/prompts";
4168
+ import { confirm as confirm6, intro as intro3, isCancel as isCancel7, log as log12, outro as outro3, spinner as spinner5 } from "@clack/prompts";
4118
4169
  import { Command as Command6 } from "commander";
4119
4170
  function reattachRef3(r) {
4120
4171
  return typeof r.projectIndex === "number" ? String(r.projectIndex) : r.name;
@@ -4188,7 +4239,7 @@ async function maybeRunOpencodeLogin(args) {
4188
4239
  initialValue: true
4189
4240
  });
4190
4241
  if (isCancel7(answer) || !answer) {
4191
- log13.info("Skipped sign-in \u2014 opencode will prompt you to sign in inside the box.");
4242
+ log12.info("Skipped sign-in \u2014 opencode will prompt you to sign in inside the box.");
4192
4243
  return;
4193
4244
  }
4194
4245
  const s = spinner5();
@@ -4202,16 +4253,16 @@ async function maybeRunOpencodeLogin(args) {
4202
4253
  s.stop("image ready");
4203
4254
  const exitCode = await runOpencodeLoginContainer(args.image, []);
4204
4255
  if (exitCode !== 0) {
4205
- log13.warn("OpenCode login did not complete; continuing \u2014 run `agentbox opencode login` to retry.");
4256
+ log12.warn("OpenCode login did not complete; continuing \u2014 run `agentbox opencode login` to retry.");
4206
4257
  return;
4207
4258
  }
4208
- log13.success("Signed in to OpenCode \u2014 saved for future boxes.");
4259
+ log12.success("Signed in to OpenCode \u2014 saved for future boxes.");
4209
4260
  }
4210
4261
  async function cloudOpencodeCredAvailable(env = process.env) {
4211
4262
  for (const k of OPENCODE_FORWARDED_ENV_KEYS) {
4212
4263
  if ((env[k] ?? "").length > 0) return true;
4213
4264
  }
4214
- for (const p of [OPENCODE_CREDENTIALS_BACKUP_FILE, join11(homedir9(), ".local", "share", "opencode", "auth.json")]) {
4265
+ for (const p of [OPENCODE_CREDENTIALS_BACKUP_FILE, join11(homedir10(), ".local", "share", "opencode", "auth.json")]) {
4215
4266
  try {
4216
4267
  await access2(p);
4217
4268
  return true;
@@ -4228,7 +4279,7 @@ async function maybeRunCloudOpencodeLogin(args) {
4228
4279
  initialValue: true
4229
4280
  });
4230
4281
  if (isCancel7(answer) || !answer) {
4231
- log13.info("Skipped sign-in \u2014 opencode will prompt you to sign in inside the box.");
4282
+ log12.info("Skipped sign-in \u2014 opencode will prompt you to sign in inside the box.");
4232
4283
  return;
4233
4284
  }
4234
4285
  const s = spinner5();
@@ -4242,12 +4293,12 @@ async function maybeRunCloudOpencodeLogin(args) {
4242
4293
  s.stop("image ready");
4243
4294
  const exitCode = await runOpencodeLoginContainer(args.image, []);
4244
4295
  if (exitCode !== 0) {
4245
- log13.warn("OpenCode login did not complete; continuing \u2014 run `agentbox opencode login` to retry.");
4296
+ log12.warn("OpenCode login did not complete; continuing \u2014 run `agentbox opencode login` to retry.");
4246
4297
  return;
4247
4298
  }
4248
4299
  const { copied } = await extractOpencodeCredentials(SHARED_OPENCODE_VOLUME, args.image);
4249
- if (copied) log13.success("Signed in to OpenCode \u2014 saved for future boxes.");
4250
- else log13.warn("OpenCode login finished but no auth.json was captured \u2014 sign in inside the box if needed.");
4300
+ if (copied) log12.success("Signed in to OpenCode \u2014 saved for future boxes.");
4301
+ else log12.warn("OpenCode login finished but no auth.json was captured \u2014 sign in inside the box if needed.");
4251
4302
  }
4252
4303
  var opencodeCommand = new Command6("opencode").description("Create a sandboxed box and launch OpenCode in a detachable tmux session").option("-w, --workspace <path>", "host workspace to mount", process.cwd()).option("-n, --name <name>", "friendly box name (default: <workspace-basename>-<id>)").option("--host-snapshot", "APFS-clone the host workspace into a per-box scratch dir before seeding /workspace (stabilizes the tar-pipe source)").option("--no-host-snapshot", "tar-pipe directly from the live host workspace at create time").option(
4253
4304
  "--snapshot <ref>",
@@ -4315,7 +4366,7 @@ var opencodeCommand = new Command6("opencode").description("Create a sandboxed b
4315
4366
  });
4316
4367
  } catch (err) {
4317
4368
  if (err instanceof TeleportError) {
4318
- log13.error(err.message);
4369
+ log12.error(err.message);
4319
4370
  cmdLog.close();
4320
4371
  process.exit(2);
4321
4372
  }
@@ -4332,7 +4383,7 @@ var opencodeCommand = new Command6("opencode").description("Create a sandboxed b
4332
4383
  const checkpointRef = opts.snapshot && opts.snapshot.length > 0 ? opts.snapshot : providerDefault.length > 0 ? providerDefault : void 0;
4333
4384
  if (opts.initialPrompt && opts.initialPrompt.length > 0) {
4334
4385
  if (isCloud) {
4335
- log13.error("-i / --initial-prompt is currently docker-only (cloud sessions only start on attach).");
4386
+ log12.error("-i / --initial-prompt is currently docker-only (cloud sessions only start on attach).");
4336
4387
  cmdLog.close();
4337
4388
  process.exit(2);
4338
4389
  }
@@ -4343,7 +4394,7 @@ var opencodeCommand = new Command6("opencode").description("Create a sandboxed b
4343
4394
  });
4344
4395
  } catch (err) {
4345
4396
  if (err instanceof MissingAgentCredsError) {
4346
- log13.error(err.message);
4397
+ log12.error(err.message);
4347
4398
  cmdLog.close();
4348
4399
  process.exit(2);
4349
4400
  }
@@ -4361,7 +4412,7 @@ var opencodeCommand = new Command6("opencode").description("Create a sandboxed b
4361
4412
  maxRunningOverride,
4362
4413
  maxWorkingOverride
4363
4414
  });
4364
- outro4(
4415
+ outro3(
4365
4416
  `job ${result.job.id} queued (${String(result.runningCount)}/${String(result.maxConcurrent)} running); log: ${result.job.logPath}`
4366
4417
  );
4367
4418
  cmdLog.close();
@@ -4377,13 +4428,13 @@ var opencodeCommand = new Command6("opencode").description("Create a sandboxed b
4377
4428
  onLog: (line) => cmdLog.write(line)
4378
4429
  });
4379
4430
  if (gate.decision === "cancel") {
4380
- log13.warn("carry: cancelled \u2014 not creating the box");
4431
+ log12.warn("carry: cancelled \u2014 not creating the box");
4381
4432
  cmdLog.close();
4382
4433
  process.exit(0);
4383
4434
  }
4384
4435
  if (gate.decision === "approve") carryEntries = gate.entries;
4385
4436
  } catch (err) {
4386
- log13.error(err instanceof Error ? err.message : String(err));
4437
+ log12.error(err instanceof Error ? err.message : String(err));
4387
4438
  cmdLog.close();
4388
4439
  process.exit(1);
4389
4440
  }
@@ -4400,7 +4451,7 @@ var opencodeCommand = new Command6("opencode").description("Create a sandboxed b
4400
4451
  }));
4401
4452
  } catch (err) {
4402
4453
  if (err instanceof FromBranchError || err instanceof UseBranchError) {
4403
- log13.error(err.message);
4454
+ log12.error(err.message);
4404
4455
  cmdLog.close();
4405
4456
  process.exit(2);
4406
4457
  }
@@ -4489,14 +4540,20 @@ var opencodeCommand = new Command6("opencode").description("Create a sandboxed b
4489
4540
  sessionName
4490
4541
  });
4491
4542
  const nSuffix = typeof result.record.projectIndex === "number" ? ` \xB7 n ${String(result.record.projectIndex)}` : "";
4492
- s.stop(`box ${result.record.container} ready${nSuffix}`);
4543
+ s.stop(`box ready${nSuffix}`);
4544
+ await printLaunchRecap({
4545
+ record: result.record,
4546
+ mode: "opencode",
4547
+ reattach: reattachRef3(result.record),
4548
+ workspacePath: opts.workspace,
4549
+ fromBranch,
4550
+ useBranch,
4551
+ checkpointRef,
4552
+ attaching: opts.attach !== false
4553
+ });
4493
4554
  if (opts.attach === false) {
4494
- outro4(
4495
- `session started \u2014 attach with: agentbox opencode attach ${reattachRef3(result.record)}`
4496
- );
4497
4555
  return;
4498
4556
  }
4499
- outro4("attaching \u2014 Control+a d to detach, leaves opencode running");
4500
4557
  await attachOpencodeWrapped(
4501
4558
  result.record,
4502
4559
  sessionName,
@@ -4508,10 +4565,10 @@ var opencodeCommand = new Command6("opencode").description("Create a sandboxed b
4508
4565
  s.stop("failed");
4509
4566
  cmdLog.write(`FAIL: ${err instanceof Error ? err.stack ?? err.message : String(err)}`);
4510
4567
  if (err instanceof OpencodeSessionError) {
4511
- log13.error(err.message);
4568
+ log12.error(err.message);
4512
4569
  if (containerName) {
4513
- log13.info(`The box ${containerName} is still running. Destroy it with:`);
4514
- log13.info(` agentbox destroy ${containerName} -y`);
4570
+ log12.info(`The box ${containerName} is still running. Destroy it with:`);
4571
+ log12.info(` agentbox destroy ${containerName} -y`);
4515
4572
  }
4516
4573
  cmdLog.close();
4517
4574
  process.exit(1);
@@ -4537,12 +4594,12 @@ async function startOrAttachOpencode(box, opencodeArgs, opts) {
4537
4594
  const existing = await opencodeSessionInfo(box.container, sessionName);
4538
4595
  if (existing.running) {
4539
4596
  if (!wantAttach) {
4540
- outro4(
4597
+ outro3(
4541
4598
  `session "${sessionName}" already running \u2014 attach with: agentbox opencode attach ${reattachRef3(box)}`
4542
4599
  );
4543
4600
  return;
4544
4601
  }
4545
- outro4(`session "${sessionName}" already running \u2014 attaching (Control+a d to detach)`);
4602
+ outro3(`session "${sessionName}" already running \u2014 attaching (Control+a d to detach)`);
4546
4603
  await attachOpencodeWrapped(box, sessionName, reattachRef3(box), void 0, openIn);
4547
4604
  return;
4548
4605
  }
@@ -4572,12 +4629,12 @@ async function startOrAttachOpencode(box, opencodeArgs, opts) {
4572
4629
  await startOpencodeSession({ container: box.container, opencodeArgs, sessionName });
4573
4630
  s.stop(`box ${box.container} ready`);
4574
4631
  if (!wantAttach) {
4575
- outro4(
4632
+ outro3(
4576
4633
  `session "${sessionName}" started \u2014 attach with: agentbox opencode attach ${reattachRef3(box)}`
4577
4634
  );
4578
4635
  return;
4579
4636
  }
4580
- outro4("attaching \u2014 Control+a d to detach, leaves opencode running");
4637
+ outro3("attaching \u2014 Control+a d to detach, leaves opencode running");
4581
4638
  await attachOpencodeWrapped(box, sessionName, reattachRef3(box), void 0, openIn);
4582
4639
  }
4583
4640
  var opencodeAttachCommand = new Command6("attach").description(
@@ -4607,7 +4664,7 @@ var opencodeAttachCommand = new Command6("attach").description(
4607
4664
  await startOrAttachOpencode(box, [], { ...opts, syncConfig: false });
4608
4665
  } catch (err) {
4609
4666
  if (err instanceof OpencodeSessionError) {
4610
- log13.error(err.message);
4667
+ log12.error(err.message);
4611
4668
  process.exit(1);
4612
4669
  }
4613
4670
  handleLifecycleError(err);
@@ -4646,7 +4703,7 @@ var opencodeStartCommand = new Command6("start").description(
4646
4703
  });
4647
4704
  } catch (err) {
4648
4705
  if (err instanceof TeleportError) {
4649
- log13.error(err.message);
4706
+ log12.error(err.message);
4650
4707
  process.exit(2);
4651
4708
  }
4652
4709
  throw err;
@@ -4654,7 +4711,7 @@ var opencodeStartCommand = new Command6("start").description(
4654
4711
  }
4655
4712
  if ((box.provider ?? "docker") !== "docker") {
4656
4713
  if (opts.attach === false) {
4657
- outro4(
4714
+ outro3(
4658
4715
  `--no-attach: cloud agent sessions are started lazily on attach. Run: agentbox opencode attach ${reattachRef3(box)}`
4659
4716
  );
4660
4717
  return;
@@ -4675,7 +4732,7 @@ var opencodeStartCommand = new Command6("start").description(
4675
4732
  await startOrAttachOpencode(box, effectiveOpencodeArgs, opts);
4676
4733
  } catch (err) {
4677
4734
  if (err instanceof OpencodeSessionError) {
4678
- log13.error(err.message);
4735
+ log12.error(err.message);
4679
4736
  process.exit(1);
4680
4737
  }
4681
4738
  handleLifecycleError(err);
@@ -4689,7 +4746,7 @@ var opencodeLoginCommand = new Command6("login").description(
4689
4746
  ).action(async (args) => {
4690
4747
  intro3("Signing in to OpenCode...");
4691
4748
  if (!process.stdin.isTTY) {
4692
- log13.error("`agentbox opencode login` needs an interactive terminal.");
4749
+ log12.error("`agentbox opencode login` needs an interactive terminal.");
4693
4750
  process.exit(1);
4694
4751
  }
4695
4752
  try {
@@ -4703,10 +4760,10 @@ var opencodeLoginCommand = new Command6("login").description(
4703
4760
  s.stop("image ready");
4704
4761
  const exitCode = await runOpencodeLoginContainer(image, args);
4705
4762
  if (exitCode !== 0) {
4706
- log13.warn(`\`opencode auth login\` exited with code ${String(exitCode)}`);
4763
+ log12.warn(`\`opencode auth login\` exited with code ${String(exitCode)}`);
4707
4764
  process.exit(exitCode);
4708
4765
  }
4709
- outro4("signed in \u2014 credentials saved for future boxes");
4766
+ outro3("signed in \u2014 credentials saved for future boxes");
4710
4767
  } catch (err) {
4711
4768
  handleLifecycleError(err);
4712
4769
  }
@@ -4982,7 +5039,7 @@ function handleError(err) {
4982
5039
  var configCommand = new Command7("config").description("Read / write layered config (global, per-project, workspace `defaults:` block)").addCommand(getCommand).addCommand(setCommand).addCommand(unsetCommand).addCommand(listCommand).addCommand(pathCommand).addCommand(editCommand).addCommand(listProjectsCommand);
4983
5040
 
4984
5041
  // src/commands/cp.ts
4985
- import { log as log14 } from "@clack/prompts";
5042
+ import { log as log13 } from "@clack/prompts";
4986
5043
  import { Command as Command8 } from "commander";
4987
5044
  function parseBoxArg(arg) {
4988
5045
  const idx = arg.indexOf(":");
@@ -5065,10 +5122,10 @@ var cpCommand = new Command8("cp").description("Copy files between host and box
5065
5122
  }
5066
5123
  const insp = await inspectBox(box.id);
5067
5124
  if (insp.state === "paused") {
5068
- log14.info("box is paused; unpausing");
5125
+ log13.info("box is paused; unpausing");
5069
5126
  await unpauseBox(box.id);
5070
5127
  } else if (insp.state === "stopped") {
5071
- log14.info("box is stopped; starting");
5128
+ log13.info("box is stopped; starting");
5072
5129
  await startBox(box.id);
5073
5130
  } else if (insp.state === "missing") {
5074
5131
  throw new Error(`box ${box.name} has no container; was it destroyed?`);
@@ -5076,7 +5133,7 @@ var cpCommand = new Command8("cp").description("Copy files between host and box
5076
5133
  if (parsed.direction === "upload") {
5077
5134
  const result = await uploadToBox(box, parsed.hostPath, parsed.boxPath);
5078
5135
  if (result.warn) {
5079
- log14.warn(`copied to ${box.name}:${result.finalPath}, but ${result.warn}`);
5136
+ log13.warn(`copied to ${box.name}:${result.finalPath}, but ${result.warn}`);
5080
5137
  } else {
5081
5138
  process.stdout.write(`copied to ${box.name}:${result.finalPath}
5082
5139
  `);
@@ -5092,7 +5149,7 @@ var cpCommand = new Command8("cp").description("Copy files between host and box
5092
5149
  });
5093
5150
 
5094
5151
  // src/commands/create.ts
5095
- import { intro as intro4, log as log15, outro as outro5 } from "@clack/prompts";
5152
+ import { intro as intro4, log as log14, outro as outro4 } from "@clack/prompts";
5096
5153
  import { Command as Command9 } from "commander";
5097
5154
  import { execSync, spawnSync as spawnSync2 } from "child_process";
5098
5155
  function buildCliOverrides(opts) {
@@ -5139,7 +5196,10 @@ async function attachShell(record) {
5139
5196
  var createCommand = new Command9("create").description("Create and start a new agent box (Docker container with /workspace seeded via in-container git worktree)").option("-w, --workspace <path>", "host workspace to mount", process.cwd()).option("-n, --name <name>", "friendly box name (default: <workspace-basename>-<id>)").option("--provider <name>", "sandbox backend: 'docker' (default) or 'daytona' (cloud)").option("--host-snapshot", "APFS-clone the host workspace into a per-box scratch dir before seeding /workspace (stabilizes the tar-pipe source)").option("--no-host-snapshot", "bind the live workspace directly (host edits leak into reads)").option(
5140
5197
  "--snapshot <ref>",
5141
5198
  "start from a project checkpoint (see `agentbox checkpoint`); overrides box.defaultCheckpoint"
5142
- ).option("--image <ref>", "override the box image", void 0).option("--attach", "drop into a shell inside the box after it is ready").option("--with-playwright", "also install @playwright/cli@latest globally inside the box").option(
5199
+ ).option("--image <ref>", "override the box image", void 0).option(
5200
+ "--build",
5201
+ "build the docker base image locally instead of pulling the prebuilt one from the registry"
5202
+ ).option("--attach", "drop into a shell inside the box after it is ready").option("--with-playwright", "also install @playwright/cli@latest globally inside the box").option(
5143
5203
  "--with-env",
5144
5204
  "copy host env/config files (.env*, secrets.toml, agentbox.yaml, ...) into /workspace at create time (gitignore-bypassing)"
5145
5205
  ).option("--no-vnc", "disable the per-box Xvnc + noVNC web client (on by default)").option(
@@ -5212,13 +5272,13 @@ var createCommand = new Command9("create").description("Create and start a new a
5212
5272
  onLog: (line) => cmdLog.write(line)
5213
5273
  });
5214
5274
  if (gate.decision === "cancel") {
5215
- log15.warn("carry: cancelled \u2014 not creating the box");
5275
+ log14.warn("carry: cancelled \u2014 not creating the box");
5216
5276
  cmdLog.close();
5217
5277
  process.exit(0);
5218
5278
  }
5219
5279
  if (gate.decision === "approve") carryEntries = gate.entries;
5220
5280
  } catch (err) {
5221
- log15.error(err instanceof Error ? err.message : String(err));
5281
+ log14.error(err instanceof Error ? err.message : String(err));
5222
5282
  cmdLog.close();
5223
5283
  process.exit(1);
5224
5284
  }
@@ -5266,7 +5326,7 @@ var createCommand = new Command9("create").description("Create and start a new a
5266
5326
  } catch (err) {
5267
5327
  if (err instanceof FromBranchError || err instanceof UseBranchError) {
5268
5328
  s.stop("aborting: invalid branch selection");
5269
- log15.error(err.message);
5329
+ log14.error(err.message);
5270
5330
  cmdLog.close();
5271
5331
  process.exit(2);
5272
5332
  }
@@ -5277,6 +5337,8 @@ var createCommand = new Command9("create").description("Create and start a new a
5277
5337
  name: opts.name,
5278
5338
  checkpointRef,
5279
5339
  image: cfg.effective.box.image,
5340
+ allowPull: opts.build ? false : void 0,
5341
+ imageRegistry: cfg.effective.box.imageRegistry,
5280
5342
  withPlaywright,
5281
5343
  withEnv: cfg.effective.box.withEnv,
5282
5344
  envFilesToImport: wiz.envFilesToImport,
@@ -5306,17 +5368,17 @@ var createCommand = new Command9("create").description("Create and start a new a
5306
5368
  }
5307
5369
  });
5308
5370
  s.stop(`box ${result.record.container} ready`);
5309
- log15.info(`id: ${result.record.id}`);
5371
+ log14.info(`id: ${result.record.id}`);
5310
5372
  if (typeof result.record.projectIndex === "number") {
5311
- log15.info(`n: ${String(result.record.projectIndex)} (in ${projectRoot})`);
5373
+ log14.info(`n: ${String(result.record.projectIndex)} (in ${projectRoot})`);
5312
5374
  }
5313
- log15.info(`container: ${result.record.container}`);
5314
- log15.info(`image: ${result.record.image}${result.imageBuilt ? " (built just now)" : ""}`);
5375
+ log14.info(`container: ${result.record.container}`);
5376
+ log14.info(`image: ${result.record.image}${result.imageBuilt ? " (built just now)" : ""}`);
5315
5377
  if (result.record.snapshotDir) {
5316
- log15.info(`snapshot: ${result.record.snapshotDir}`);
5378
+ log14.info(`snapshot: ${result.record.snapshotDir}`);
5317
5379
  }
5318
5380
  if (result.record.checkpointSource) {
5319
- log15.info(
5381
+ log14.info(
5320
5382
  `checkpoint: ${result.record.checkpointSource.ref} (${result.record.checkpointSource.type}) \u2192 ${result.record.checkpointImage ?? "(missing)"}`
5321
5383
  );
5322
5384
  }
@@ -5328,7 +5390,7 @@ var createCommand = new Command9("create").description("Create and start a new a
5328
5390
  ` agentbox claude attach ${result.record.name}`,
5329
5391
  ` agentbox url ${result.record.name}`
5330
5392
  ];
5331
- log15.message(
5393
+ log14.message(
5332
5394
  [
5333
5395
  "",
5334
5396
  "Try it:",
@@ -5347,7 +5409,7 @@ var createCommand = new Command9("create").description("Create and start a new a
5347
5409
  const protectedPaths = boxes.map((b) => b.projectRoot).filter((p) => typeof p === "string");
5348
5410
  const res = await pruneOrphanProjectConfigs({ protectedPaths });
5349
5411
  if (res.removed.length > 0) {
5350
- log15.info(
5412
+ log14.info(
5351
5413
  `cleaned ${String(res.removed.length)} orphan project config dir(s): ` + res.removed.map((r) => r.originalPath).join(", ")
5352
5414
  );
5353
5415
  }
@@ -5355,9 +5417,9 @@ var createCommand = new Command9("create").description("Create and start a new a
5355
5417
  } catch {
5356
5418
  }
5357
5419
  }
5358
- outro5("done");
5420
+ outro4("done");
5359
5421
  if (attachClaudeAfter) {
5360
- const { cloudAgentAttach: cloudAgentAttach2 } = await import("./_cloud-attach-O6NYTLES.js");
5422
+ const { cloudAgentAttach: cloudAgentAttach2 } = await import("./_cloud-attach-6C5NMOHD.js");
5361
5423
  await cloudAgentAttach2({
5362
5424
  box: result.record,
5363
5425
  binary: "claude",
@@ -5373,14 +5435,14 @@ var createCommand = new Command9("create").description("Create and start a new a
5373
5435
  s.stop("failed");
5374
5436
  const msg = err instanceof Error ? err.message : String(err);
5375
5437
  cmdLog.write(`FAIL: ${err instanceof Error ? err.stack ?? err.message : String(err)}`);
5376
- log15.error(msg);
5438
+ log14.error(msg);
5377
5439
  try {
5378
5440
  const running = execSync('docker ps --format "{{.Names}}"', {
5379
5441
  stdio: ["ignore", "pipe", "ignore"]
5380
5442
  }).toString().split("\n").filter((n) => n.startsWith("agentbox-"));
5381
5443
  if (running.length > 0) {
5382
- log15.warn(`leftover containers: ${running.join(", ")}`);
5383
- log15.warn(`remove with: docker rm -f ${running.join(" ")}`);
5444
+ log14.warn(`leftover containers: ${running.join(", ")}`);
5445
+ log14.warn(`remove with: docker rm -f ${running.join(" ")}`);
5384
5446
  }
5385
5447
  } catch {
5386
5448
  }
@@ -5393,7 +5455,7 @@ var createCommand = new Command9("create").description("Create and start a new a
5393
5455
 
5394
5456
  // src/commands/dashboard.ts
5395
5457
  import { spawn as spawn2 } from "child_process";
5396
- import { log as log16 } from "@clack/prompts";
5458
+ import { log as log15 } from "@clack/prompts";
5397
5459
  import { Command as Command10 } from "commander";
5398
5460
 
5399
5461
  // src/dashboard/layout.ts
@@ -6917,7 +6979,7 @@ function toSidebar(b) {
6917
6979
  var dashboardCommand = new Command10("dashboard").description("Box list + the selected box live Agent session").argument("[box]", "initial box (default: first running box; -p restricts to the cwd project)").option("-p, --project", "only this project's boxes (default: all boxes globally)").action(async (idOrName, opts) => {
6918
6980
  try {
6919
6981
  if (!process.stdout.isTTY || !process.stdin.isTTY) {
6920
- log16.error("agentbox dashboard needs an interactive terminal");
6982
+ log15.error("agentbox dashboard needs an interactive terminal");
6921
6983
  process.exit(2);
6922
6984
  }
6923
6985
  const backend = await loadPtyBackend();
@@ -6927,10 +6989,10 @@ var dashboardCommand = new Command10("dashboard").description("Box list + the se
6927
6989
  ptySpawn = backend.ptySpawn;
6928
6990
  termCtor = backend.termCtor;
6929
6991
  } else {
6930
- log16.error(
6992
+ log15.error(
6931
6993
  "agentbox dashboard is unavailable here (native terminal backend failed to load)"
6932
6994
  );
6933
- log16.info("use `agentbox claude` / `agentbox claude attach` instead");
6995
+ log15.info("use `agentbox claude` / `agentbox claude attach` instead");
6934
6996
  process.exit(2);
6935
6997
  }
6936
6998
  const project = await findProjectRoot(process.cwd());
@@ -7242,9 +7304,9 @@ var dashboardCommand = new Command10("dashboard").description("Box list + the se
7242
7304
  if (!br.up) return `VNC: in-box browser unavailable (${br.reason ?? "box not running?"})`;
7243
7305
  } catch {
7244
7306
  }
7245
- detach("open", [url]);
7307
+ detach(hostOpenCommand(), [url]);
7246
7308
  if (exposedWebUrl) {
7247
- detach("open", [exposedWebUrl]);
7309
+ detach(hostOpenCommand(), [exposedWebUrl]);
7248
7310
  return "Opening VNC + web in browser\u2026";
7249
7311
  }
7250
7312
  return "Opening VNC in browser\u2026";
@@ -7253,7 +7315,7 @@ var dashboardCommand = new Command10("dashboard").description("Box list + the se
7253
7315
  const box = (await listBoxes()).find((b) => b.id === boxId);
7254
7316
  if (!box) return "box not found";
7255
7317
  const { url } = webTarget(box);
7256
- detach("open", [url]);
7318
+ detach(hostOpenCommand(), [url]);
7257
7319
  return `Opening ${url.replace(/^https?:\/\//, "")}\u2026`;
7258
7320
  };
7259
7321
  const openCode = async (boxId) => {
@@ -7335,11 +7397,11 @@ var dashboardCommand = new Command10("dashboard").description("Box list + the se
7335
7397
  });
7336
7398
 
7337
7399
  // ../../packages/sandbox-daytona/dist/cli.js
7338
- import { log as log17, spinner as spinner6 } from "@clack/prompts";
7400
+ import { log as log16, spinner as spinner6 } from "@clack/prompts";
7339
7401
  import { Command as Command11 } from "commander";
7340
7402
  function reportError(err) {
7341
7403
  const message = err instanceof Error ? err.message : String(err);
7342
- log17.error(message);
7404
+ log16.error(message);
7343
7405
  process.exitCode = 1;
7344
7406
  }
7345
7407
  var loginSub = new Command11("login").description("Set up (or rotate) Daytona credentials for cloud boxes").option("--status", "show what is currently configured (masked) and exit").action(async (opts) => {
@@ -7398,7 +7460,7 @@ var resyncSub = new Command11("resync").description(
7398
7460
  const sb = spinner6();
7399
7461
  sb.start(`provisioning throwaway sandbox to refresh: ${agents.join(", ")}`);
7400
7462
  const ensured = await ensureAgentVolumesForCloud(daytonaBackend, {
7401
- onLog: (line) => log17.info(line)
7463
+ onLog: (line) => log16.info(line)
7402
7464
  });
7403
7465
  if (ensured.agents.length === 0) {
7404
7466
  sb.stop("no agent volumes available \u2014 the daytona backend has no volume primitive");
@@ -7438,7 +7500,7 @@ var resyncSub = new Command11("resync").description(
7438
7500
  }
7439
7501
  sb3.stop("throwaway sandbox destroyed");
7440
7502
  }
7441
- log17.success(
7503
+ log16.success(
7442
7504
  `Daytona agent volumes refreshed: ${agents.join(", ")}. Next \`agentbox create --provider daytona\` will use the updated credentials.`
7443
7505
  );
7444
7506
  } catch (err) {
@@ -7458,11 +7520,11 @@ var dockerCommand = new Command12("docker").description(
7458
7520
  });
7459
7521
 
7460
7522
  // ../../packages/sandbox-hetzner/dist/cli.js
7461
- import { log as log18 } from "@clack/prompts";
7523
+ import { log as log17 } from "@clack/prompts";
7462
7524
  import { Command as Command13 } from "commander";
7463
7525
  function reportError2(err) {
7464
7526
  const message = err instanceof Error ? err.message : String(err);
7465
- log18.error(message);
7527
+ log17.error(message);
7466
7528
  process.exitCode = 1;
7467
7529
  }
7468
7530
  var loginSub2 = new Command13("login").description("Set up (or rotate) Hetzner Cloud credentials for VPS boxes").option("--status", "show what is currently configured (masked) and exit").action(async (opts) => {
@@ -7606,11 +7668,11 @@ var hetznerCommand = new Command13("hetzner").description(
7606
7668
  ).addCommand(loginSub2, { isDefault: true }).addCommand(firewallSub);
7607
7669
 
7608
7670
  // ../../packages/sandbox-vercel/dist/cli.js
7609
- import { log as log19 } from "@clack/prompts";
7671
+ import { log as log18 } from "@clack/prompts";
7610
7672
  import { Command as Command14 } from "commander";
7611
7673
  function reportError3(err) {
7612
7674
  const message = err instanceof Error ? err.message : String(err);
7613
- log19.error(message);
7675
+ log18.error(message);
7614
7676
  process.exitCode = 1;
7615
7677
  }
7616
7678
  function relativeExpiry(expiresAt) {
@@ -7681,7 +7743,7 @@ var vercelCommand = new Command14("vercel").description(
7681
7743
  ).addCommand(loginSub3, { isDefault: true });
7682
7744
 
7683
7745
  // src/commands/destroy.ts
7684
- import { confirm as confirm7, isCancel as isCancel8, log as log20 } from "@clack/prompts";
7746
+ import { confirm as confirm7, isCancel as isCancel8, log as log19 } from "@clack/prompts";
7685
7747
  import { Command as Command15 } from "commander";
7686
7748
  var destroyCommand = new Command15("destroy").alias("rm").description("Destroy a box and discard its container writable layer (where /workspace lived)").argument(
7687
7749
  "[box]",
@@ -7690,7 +7752,7 @@ var destroyCommand = new Command15("destroy").alias("rm").description("Destroy a
7690
7752
  try {
7691
7753
  const box = await resolveBoxOrExit(idOrName);
7692
7754
  if (!opts.yes) {
7693
- log20.warn("Will also wipe the box volume and agent work-in-progress");
7755
+ log19.warn("Will also wipe the box volume and agent work-in-progress");
7694
7756
  const rootBranch = box.gitWorktrees?.find((w) => w.kind === "root")?.branch;
7695
7757
  const lines = [box.name];
7696
7758
  if (rootBranch) lines.push(`branch: ${rootBranch}`);
@@ -7698,13 +7760,13 @@ var destroyCommand = new Command15("destroy").alias("rm").description("Destroy a
7698
7760
  if (box.snapshotDir) {
7699
7761
  lines.push(`snapshot: ${box.snapshotDir}${opts.keepSnapshot ? " (will be kept)" : ""}`);
7700
7762
  }
7701
- log20.info(lines.join("\n"));
7763
+ log19.info(lines.join("\n"));
7702
7764
  const ok = await confirm7({
7703
7765
  message: "Destroy this box?",
7704
7766
  initialValue: false
7705
7767
  });
7706
7768
  if (isCancel8(ok) || !ok) {
7707
- log20.info("cancelled");
7769
+ log19.info("cancelled");
7708
7770
  return;
7709
7771
  }
7710
7772
  }
@@ -7737,11 +7799,11 @@ var destroyCommand = new Command15("destroy").alias("rm").description("Destroy a
7737
7799
  });
7738
7800
 
7739
7801
  // src/commands/download.ts
7740
- import { confirm as confirm13, isCancel as isCancel14, log as log26 } from "@clack/prompts";
7802
+ import { confirm as confirm13, isCancel as isCancel14, log as log25 } from "@clack/prompts";
7741
7803
  import { Command as Command21 } from "commander";
7742
7804
 
7743
7805
  // src/commands/download-claude.ts
7744
- import { confirm as confirm8, isCancel as isCancel9, log as log21 } from "@clack/prompts";
7806
+ import { confirm as confirm8, isCancel as isCancel9, log as log20 } from "@clack/prompts";
7745
7807
  import { Command as Command16 } from "commander";
7746
7808
  function tag(item) {
7747
7809
  const noun = item.category === "plugins" ? "plugin" : item.category.replace(/s$/, "");
@@ -7757,7 +7819,7 @@ var downloadClaudeCommand = new Command16("claude").description(
7757
7819
  const box = await resolveBoxOrExit(idOrName);
7758
7820
  const volume = box.claudeConfigVolume ?? resolveClaudeVolume({ isolate: false, boxId: box.id }).volume;
7759
7821
  if (volume === SHARED_CLAUDE_VOLUME) {
7760
- log21.warn(
7822
+ log20.warn(
7761
7823
  `Reading the shared ${SHARED_CLAUDE_VOLUME} volume \u2014 it aggregates Claude extensions installed in ANY box, not just ${box.name}.`
7762
7824
  );
7763
7825
  }
@@ -7787,7 +7849,7 @@ var downloadClaudeCommand = new Command16("claude").description(
7787
7849
  initialValue: false
7788
7850
  });
7789
7851
  if (isCancel9(ok) || !ok) {
7790
- log21.info("cancelled");
7852
+ log20.info("cancelled");
7791
7853
  return;
7792
7854
  }
7793
7855
  }
@@ -7802,7 +7864,7 @@ var downloadClaudeCommand = new Command16("claude").description(
7802
7864
  });
7803
7865
 
7804
7866
  // src/commands/download-codex.ts
7805
- import { confirm as confirm9, isCancel as isCancel10, log as log22 } from "@clack/prompts";
7867
+ import { confirm as confirm9, isCancel as isCancel10, log as log21 } from "@clack/prompts";
7806
7868
  import { Command as Command17 } from "commander";
7807
7869
  var downloadCodexCommand = new Command17("codex").description(
7808
7870
  "Download box-side Codex config/auth (config.toml, auth.json, prompts) back to host ~/.codex (additive)"
@@ -7814,7 +7876,7 @@ var downloadCodexCommand = new Command17("codex").description(
7814
7876
  const box = await resolveBoxOrExit(idOrName);
7815
7877
  const volume = box.codexConfigVolume ?? resolveCodexVolume({ isolate: false, boxId: box.id }).volume;
7816
7878
  if (volume === SHARED_CODEX_VOLUME) {
7817
- log22.warn(
7879
+ log21.warn(
7818
7880
  `Reading the shared ${SHARED_CODEX_VOLUME} volume \u2014 it aggregates Codex config from ANY box, not just ${box.name}.`
7819
7881
  );
7820
7882
  }
@@ -7840,7 +7902,7 @@ var downloadCodexCommand = new Command17("codex").description(
7840
7902
  initialValue: false
7841
7903
  });
7842
7904
  if (isCancel10(ok) || !ok) {
7843
- log22.info("cancelled");
7905
+ log21.info("cancelled");
7844
7906
  return;
7845
7907
  }
7846
7908
  }
@@ -7853,7 +7915,7 @@ var downloadCodexCommand = new Command17("codex").description(
7853
7915
  });
7854
7916
 
7855
7917
  // src/commands/download-opencode.ts
7856
- import { confirm as confirm10, isCancel as isCancel11, log as log23 } from "@clack/prompts";
7918
+ import { confirm as confirm10, isCancel as isCancel11, log as log22 } from "@clack/prompts";
7857
7919
  import { Command as Command18 } from "commander";
7858
7920
  var downloadOpencodeCommand = new Command18("opencode").description(
7859
7921
  "Download box-side OpenCode config/auth (auth.json, opencode.json, agents, commands, themes) back to host ~/.config + ~/.local/share opencode (additive)"
@@ -7865,7 +7927,7 @@ var downloadOpencodeCommand = new Command18("opencode").description(
7865
7927
  const box = await resolveBoxOrExit(idOrName);
7866
7928
  const volume = box.opencodeConfigVolume ?? resolveOpencodeVolume({ isolate: false, boxId: box.id }).volume;
7867
7929
  if (volume === SHARED_OPENCODE_VOLUME) {
7868
- log23.warn(
7930
+ log22.warn(
7869
7931
  `Reading the shared ${SHARED_OPENCODE_VOLUME} volume \u2014 it aggregates OpenCode config from ANY box, not just ${box.name}.`
7870
7932
  );
7871
7933
  }
@@ -7891,7 +7953,7 @@ var downloadOpencodeCommand = new Command18("opencode").description(
7891
7953
  initialValue: false
7892
7954
  });
7893
7955
  if (isCancel11(ok) || !ok) {
7894
- log23.info("cancelled");
7956
+ log22.info("cancelled");
7895
7957
  return;
7896
7958
  }
7897
7959
  }
@@ -7904,7 +7966,7 @@ var downloadOpencodeCommand = new Command18("opencode").description(
7904
7966
  });
7905
7967
 
7906
7968
  // src/commands/download-config.ts
7907
- import { confirm as confirm11, isCancel as isCancel12, log as log24 } from "@clack/prompts";
7969
+ import { confirm as confirm11, isCancel as isCancel12, log as log23 } from "@clack/prompts";
7908
7970
  import { Command as Command19 } from "commander";
7909
7971
  function tagChange(line) {
7910
7972
  const sp = line.indexOf(" ");
@@ -7922,15 +7984,15 @@ var downloadConfigCommand = new Command19("config").description("Download agentb
7922
7984
  const box = await resolveBoxOrExit(idOrName);
7923
7985
  const insp = await inspectBox(box.id);
7924
7986
  if (insp.state === "paused") {
7925
- log24.info("box is paused; unpausing");
7987
+ log23.info("box is paused; unpausing");
7926
7988
  await unpauseBox(box.id);
7927
7989
  } else if (insp.state === "stopped") {
7928
- log24.info("box is stopped; starting");
7990
+ log23.info("box is stopped; starting");
7929
7991
  await startBox(box.id);
7930
7992
  } else if (insp.state === "missing") {
7931
7993
  throw new Error(`box ${box.name} has no container; was it destroyed?`);
7932
7994
  }
7933
- log24.info(`agentbox.yaml bypasses gitignore and copies directly into ${box.workspacePath}`);
7995
+ log23.info(`agentbox.yaml bypasses gitignore and copies directly into ${box.workspacePath}`);
7934
7996
  const preview = await pullToHost(box, {
7935
7997
  dryRun: true,
7936
7998
  respectGitignore: false,
@@ -7958,7 +8020,7 @@ var downloadConfigCommand = new Command19("config").description("Download agentb
7958
8020
  initialValue: false
7959
8021
  });
7960
8022
  if (isCancel12(ok) || !ok) {
7961
- log24.info("cancelled");
8023
+ log23.info("cancelled");
7962
8024
  return;
7963
8025
  }
7964
8026
  }
@@ -7980,7 +8042,7 @@ var downloadConfigCommand = new Command19("config").description("Download agentb
7980
8042
  });
7981
8043
 
7982
8044
  // src/commands/download-env.ts
7983
- import { confirm as confirm12, isCancel as isCancel13, log as log25 } from "@clack/prompts";
8045
+ import { confirm as confirm12, isCancel as isCancel13, log as log24 } from "@clack/prompts";
7984
8046
  import { Command as Command20 } from "commander";
7985
8047
  function tagChange2(line) {
7986
8048
  const sp = line.indexOf(" ");
@@ -8004,15 +8066,15 @@ var downloadEnvCommand = new Command20("env").description(
8004
8066
  const box = await resolveBoxOrExit(idOrName);
8005
8067
  const insp = await inspectBox(box.id);
8006
8068
  if (insp.state === "paused") {
8007
- log25.info("box is paused; unpausing");
8069
+ log24.info("box is paused; unpausing");
8008
8070
  await unpauseBox(box.id);
8009
8071
  } else if (insp.state === "stopped") {
8010
- log25.info("box is stopped; starting");
8072
+ log24.info("box is stopped; starting");
8011
8073
  await startBox(box.id);
8012
8074
  } else if (insp.state === "missing") {
8013
8075
  throw new Error(`box ${box.name} has no container; was it destroyed?`);
8014
8076
  }
8015
- log25.info(
8077
+ log24.info(
8016
8078
  `env/config files bypass gitignore and copy directly into ${box.workspacePath}`
8017
8079
  );
8018
8080
  const patterns = [...DEFAULT_ENV_PATTERNS, ...opts.pattern];
@@ -8043,7 +8105,7 @@ var downloadEnvCommand = new Command20("env").description(
8043
8105
  initialValue: false
8044
8106
  });
8045
8107
  if (isCancel13(ok) || !ok) {
8046
- log25.info("cancelled");
8108
+ log24.info("cancelled");
8047
8109
  return;
8048
8110
  }
8049
8111
  }
@@ -8091,7 +8153,7 @@ var downloadCommand = new Command21("download").enablePositionalOptions().descri
8091
8153
  throw new Error("cloud download does not yet support --dry-run; omit to bulk-pull /workspace.");
8092
8154
  }
8093
8155
  if (!opts.respectGitignore || opts.includeNodeModules || opts.withEnv || opts.pattern.length > 0) {
8094
- log26.warn(
8156
+ log25.warn(
8095
8157
  "cloud download ignores gitignore/--with-env/--pattern filters in v1 \u2014 pulling the whole /workspace tree (Phase 6 polish)."
8096
8158
  );
8097
8159
  }
@@ -8101,7 +8163,7 @@ var downloadCommand = new Command21("download").enablePositionalOptions().descri
8101
8163
  initialValue: false
8102
8164
  });
8103
8165
  if (isCancel14(ok) || !ok) {
8104
- log26.info("cancelled");
8166
+ log25.info("cancelled");
8105
8167
  return;
8106
8168
  }
8107
8169
  }
@@ -8120,17 +8182,17 @@ var downloadCommand = new Command21("download").enablePositionalOptions().descri
8120
8182
  }
8121
8183
  const insp = await inspectBox(box.id);
8122
8184
  if (insp.state === "paused") {
8123
- log26.info("box is paused; unpausing");
8185
+ log25.info("box is paused; unpausing");
8124
8186
  await unpauseBox(box.id);
8125
8187
  } else if (insp.state === "stopped") {
8126
- log26.info("box is stopped; starting");
8188
+ log25.info("box is stopped; starting");
8127
8189
  await startBox(box.id);
8128
8190
  } else if (insp.state === "missing") {
8129
8191
  throw new Error(`box ${box.name} has no container; was it destroyed?`);
8130
8192
  }
8131
8193
  const rootWorktree = box.gitWorktrees?.find((w) => w.kind === "root");
8132
8194
  if (rootWorktree) {
8133
- log26.warn(
8195
+ log25.warn(
8134
8196
  `This box has been committing to branch \`${rootWorktree.branch}\` in a separate worktree.
8135
8197
  For a git-aware merge instead of a file copy, run from your checkout:
8136
8198
  git merge ${rootWorktree.branch}
@@ -8166,7 +8228,7 @@ Continuing with rsync into ${box.workspacePath}`
8166
8228
  initialValue: false
8167
8229
  });
8168
8230
  if (isCancel14(ok) || !ok) {
8169
- log26.info("cancelled");
8231
+ log25.info("cancelled");
8170
8232
  return;
8171
8233
  }
8172
8234
  }
@@ -8194,7 +8256,7 @@ downloadCommand.addCommand(downloadOpencodeCommand);
8194
8256
  downloadCommand.addCommand(downloadConfigCommand);
8195
8257
 
8196
8258
  // src/commands/drive.ts
8197
- import { log as log27 } from "@clack/prompts";
8259
+ import { log as log26 } from "@clack/prompts";
8198
8260
  import { Command as Command22 } from "commander";
8199
8261
 
8200
8262
  // src/lib/drive/keys.ts
@@ -8480,7 +8542,7 @@ var driveWaitCommand = new Command22("wait").description("Block until --text app
8480
8542
  }) + "\n"
8481
8543
  );
8482
8544
  } else {
8483
- log27.error(`text not found within ${String(timeoutMs)}ms: ${opts.text}`);
8545
+ log26.error(`text not found within ${String(timeoutMs)}ms: ${opts.text}`);
8484
8546
  }
8485
8547
  process.exit(1);
8486
8548
  } catch (err) {
@@ -8507,8 +8569,8 @@ driveCommand.addCommand(driveWaitCommand);
8507
8569
  driveCommand.addCommand(driveResizeCommand);
8508
8570
  function handleDriveError(err) {
8509
8571
  if (err instanceof SessionNotFoundError) {
8510
- log27.error(err.message);
8511
- log27.info("start an agent first (e.g. `agentbox claude <box>`) or pass --session.");
8572
+ log26.error(err.message);
8573
+ log26.info("start an agent first (e.g. `agentbox claude <box>`) or pass --session.");
8512
8574
  process.exit(2);
8513
8575
  }
8514
8576
  handleLifecycleError(err);
@@ -8532,10 +8594,10 @@ function sleep2(ms) {
8532
8594
  }
8533
8595
 
8534
8596
  // src/commands/fork.ts
8535
- import { log as log28 } from "@clack/prompts";
8597
+ import { log as log27 } from "@clack/prompts";
8536
8598
  import { Command as Command23 } from "commander";
8537
8599
  import { existsSync as existsSync4, readdirSync, statSync } from "fs";
8538
- import { homedir as homedir10 } from "os";
8600
+ import { homedir as homedir11 } from "os";
8539
8601
  import { join as join12 } from "path";
8540
8602
  var FORK_AGENTS = ["claude", "codex", "opencode"];
8541
8603
  var AGENT_COMMAND = {
@@ -8556,7 +8618,7 @@ function resolveSessionArgs(agent, opts) {
8556
8618
  }
8557
8619
  if (opts.session) return ["--resume", opts.session];
8558
8620
  if (agent === "codex") return ["--continue"];
8559
- const dir = join12(homedir10(), ".claude", "projects", encodeClaudeProjectsDir(opts.workspace));
8621
+ const dir = join12(homedir11(), ".claude", "projects", encodeClaudeProjectsDir(opts.workspace));
8560
8622
  if (!existsSync4(dir)) return ["--continue"];
8561
8623
  const now = Date.now();
8562
8624
  const recent = readdirSync(dir).filter((f) => f.endsWith(".jsonl")).map((f) => {
@@ -8601,19 +8663,19 @@ var forkCommand = new Command23("fork").description(
8601
8663
  "auto-approve agentbox.yaml's carry: block (fork skips carry by default \u2014 it does not silently re-copy host files into the new box)"
8602
8664
  ).action(async (opts) => {
8603
8665
  if ((process.env.AGENTBOX_RELAY_URL ?? "").trim().length > 0) {
8604
- log28.error(
8666
+ log27.error(
8605
8667
  "agentbox fork runs on the host only: it teleports a host agent session into a new box. You appear to be inside a box (AGENTBOX_RELAY_URL is set) \u2014 box\u2192box fork is not supported yet."
8606
8668
  );
8607
8669
  process.exit(2);
8608
8670
  }
8609
8671
  const agent = opts.agent?.trim() || "claude";
8610
8672
  if (!FORK_AGENTS.includes(agent)) {
8611
- log28.error(`--agent: expected one of ${FORK_AGENTS.join(", ")}, got "${opts.agent ?? ""}"`);
8673
+ log27.error(`--agent: expected one of ${FORK_AGENTS.join(", ")}, got "${opts.agent ?? ""}"`);
8612
8674
  process.exit(2);
8613
8675
  }
8614
8676
  const attachIn = opts.attachIn ?? "tab";
8615
8677
  if (!FORK_ATTACH_VALUES.includes(attachIn)) {
8616
- log28.error(`--attach-in: expected one of ${FORK_ATTACH_VALUES.join(", ")}, got "${attachIn}"`);
8678
+ log27.error(`--attach-in: expected one of ${FORK_ATTACH_VALUES.join(", ")}, got "${attachIn}"`);
8617
8679
  process.exit(2);
8618
8680
  }
8619
8681
  const provider = opts.provider?.trim();
@@ -8621,7 +8683,7 @@ var forkCommand = new Command23("fork").description(
8621
8683
  try {
8622
8684
  sessionArgs = resolveSessionArgs(agent, opts);
8623
8685
  } catch (err) {
8624
- log28.error(err instanceof Error ? err.message : String(err));
8686
+ log27.error(err instanceof Error ? err.message : String(err));
8625
8687
  process.exit(2);
8626
8688
  }
8627
8689
  const subArgv = [
@@ -8639,16 +8701,16 @@ var forkCommand = new Command23("fork").description(
8639
8701
  });
8640
8702
 
8641
8703
  // src/commands/install.ts
8642
- import { confirm as confirm14, intro as intro6, isCancel as isCancel15, log as log30, note, outro as outro6, select as select2, spinner as spinner8 } from "@clack/prompts";
8704
+ import { confirm as confirm14, intro as intro6, isCancel as isCancel15, log as log29, note as note2, outro as outro5, select as select2, spinner as spinner8 } from "@clack/prompts";
8643
8705
  import { Command as Command25 } from "commander";
8644
8706
  import { existsSync as existsSync6, mkdirSync as mkdirSync5, readFileSync, writeFileSync as writeFileSync4 } from "fs";
8645
- import { homedir as homedir13 } from "os";
8707
+ import { homedir as homedir14 } from "os";
8646
8708
  import { dirname as dirname2, join as join15, resolve as resolve2 } from "path";
8647
8709
  import { fileURLToPath } from "url";
8648
8710
 
8649
8711
  // src/lib/doctor-checks.ts
8650
8712
  import { accessSync, constants as fsConstants, mkdirSync as mkdirSync3 } from "fs";
8651
- import { homedir as homedir11 } from "os";
8713
+ import { homedir as homedir12 } from "os";
8652
8714
  import { join as join13 } from "path";
8653
8715
  import { execa as execa2 } from "execa";
8654
8716
  var ALL_PROVIDERS = ["docker", "daytona", "hetzner", "vercel"];
@@ -8688,10 +8750,16 @@ function checkNode() {
8688
8750
  };
8689
8751
  }
8690
8752
  function checkPlatform() {
8691
- return { label: "platform", status: "ok", detail: `${process.platform}/${process.arch}` };
8753
+ const supported = process.platform === "darwin" || process.platform === "linux";
8754
+ return {
8755
+ label: "platform",
8756
+ status: supported ? "ok" : "warn",
8757
+ detail: `${process.platform}/${process.arch}`,
8758
+ hint: supported ? void 0 : "agentbox supports macOS and Linux hosts; this OS is untested"
8759
+ };
8692
8760
  }
8693
8761
  function checkAgentboxHome() {
8694
- const dir = join13(homedir11(), ".agentbox");
8762
+ const dir = join13(homedir12(), ".agentbox");
8695
8763
  try {
8696
8764
  mkdirSync3(dir, { recursive: true });
8697
8765
  accessSync(dir, fsConstants.W_OK);
@@ -8728,6 +8796,7 @@ async function runSystemChecks() {
8728
8796
  return [checkNode(), checkPlatform(), checkAgentboxHome(), git, ssh];
8729
8797
  }
8730
8798
  async function dockerChecks() {
8799
+ const linux = process.platform === "linux";
8731
8800
  const cli = await probeVersion("docker");
8732
8801
  if (!cli) {
8733
8802
  return [
@@ -8735,25 +8804,34 @@ async function dockerChecks() {
8735
8804
  label: "docker cli",
8736
8805
  status: "warn",
8737
8806
  detail: "not found",
8738
- hint: "install Docker Desktop, OrbStack, or docker engine"
8807
+ hint: linux ? "install docker engine: https://docs.docker.com/engine/install/" : "install Docker Desktop, OrbStack, or docker engine"
8739
8808
  }
8740
8809
  ];
8741
8810
  }
8742
8811
  const cliRes = { label: "docker cli", status: "ok", detail: cli };
8743
8812
  const info = await execa2("docker", ["info"], { reject: false });
8744
8813
  if (info.exitCode !== 0) {
8814
+ const permDenied = `${info.stderr ?? ""}`.toLowerCase().includes("permission denied");
8815
+ let hint;
8816
+ if (permDenied && linux) {
8817
+ hint = "add your user to the docker group: `sudo usermod -aG docker $USER`, then log out/in (or run `newgrp docker`)";
8818
+ } else if (linux) {
8819
+ hint = "start Docker: `sudo systemctl start docker` (install docker engine if missing)";
8820
+ } else {
8821
+ hint = "start Docker (Desktop / OrbStack)";
8822
+ }
8745
8823
  return [
8746
8824
  cliRes,
8747
8825
  {
8748
8826
  label: "docker daemon",
8749
8827
  status: "warn",
8750
- detail: "unreachable",
8751
- hint: "start Docker (Desktop / OrbStack / `systemctl start docker`)"
8828
+ detail: permDenied ? "permission denied" : "unreachable",
8829
+ hint
8752
8830
  }
8753
8831
  ];
8754
8832
  }
8755
8833
  const daemonRes = { label: "docker daemon", status: "ok", detail: "reachable" };
8756
- const mod = await import("./dist-BQNX7RQE.js");
8834
+ const mod = await import("./dist-ZEGIMYWZ.js");
8757
8835
  let imgRes;
8758
8836
  try {
8759
8837
  const img = await mod.imageInfo(mod.DEFAULT_BOX_IMAGE);
@@ -8784,7 +8862,7 @@ async function dockerChecks() {
8784
8862
  }
8785
8863
  async function daytonaChecks() {
8786
8864
  try {
8787
- const mod = await import("./dist-TMHSUVTP.js");
8865
+ const mod = await import("./dist-PJFJNXO2.js");
8788
8866
  const status = await mod.getDaytonaStatus();
8789
8867
  if (!status.configured) {
8790
8868
  return [
@@ -8820,7 +8898,7 @@ async function daytonaChecks() {
8820
8898
  }
8821
8899
  async function hetznerChecks() {
8822
8900
  try {
8823
- const mod = await import("./dist-5FQGYRW5.js");
8901
+ const mod = await import("./dist-4SUIXKSD.js");
8824
8902
  const cred = mod.readHetznerCredStatus();
8825
8903
  const credRes = cred.source === "none" ? {
8826
8904
  label: "credentials",
@@ -8852,7 +8930,7 @@ async function hetznerChecks() {
8852
8930
  }
8853
8931
  async function vercelChecks() {
8854
8932
  try {
8855
- const mod = await import("./dist-PZW3GWWU.js");
8933
+ const mod = await import("./dist-HT2YV6PB.js");
8856
8934
  const cred = mod.readVercelCredStatus();
8857
8935
  const credRes = cred.auth === "none" ? {
8858
8936
  label: "credentials",
@@ -8979,11 +9057,11 @@ function formatDetailed(groups) {
8979
9057
 
8980
9058
  // src/lib/first-run.ts
8981
9059
  import { existsSync as existsSync5, mkdirSync as mkdirSync4, writeFileSync as writeFileSync3 } from "fs";
8982
- import { homedir as homedir12 } from "os";
9060
+ import { homedir as homedir13 } from "os";
8983
9061
  import { dirname, join as join14 } from "path";
8984
9062
  var MARKER_VERSION = 1;
8985
9063
  function setupMarkerPath() {
8986
- return join14(homedir12(), ".agentbox", "setup-complete.json");
9064
+ return join14(homedir13(), ".agentbox", "setup-complete.json");
8987
9065
  }
8988
9066
  function isFirstRun() {
8989
9067
  return !existsSync5(setupMarkerPath());
@@ -9000,7 +9078,7 @@ function markSetupComplete(provider) {
9000
9078
  }
9001
9079
 
9002
9080
  // src/commands/prepare.ts
9003
- import { intro as intro5, log as log29, spinner as spinner7 } from "@clack/prompts";
9081
+ import { intro as intro5, log as log28, spinner as spinner7 } from "@clack/prompts";
9004
9082
  import { Command as Command24 } from "commander";
9005
9083
  async function dockerStatus() {
9006
9084
  let img;
@@ -9063,7 +9141,7 @@ async function renderDocker(status) {
9063
9141
  }
9064
9142
  async function daytonaStatus() {
9065
9143
  try {
9066
- const mod = await import("./dist-TMHSUVTP.js");
9144
+ const mod = await import("./dist-PJFJNXO2.js");
9067
9145
  return await mod.getDaytonaStatus();
9068
9146
  } catch (err) {
9069
9147
  return {
@@ -9137,10 +9215,11 @@ async function runPrepare(providerName, opts = {}) {
9137
9215
  }
9138
9216
  const provider = await getProvider(providerName);
9139
9217
  if (typeof provider.prepare !== "function") {
9140
- log29.error(`provider '${providerName}' does not implement prepare`);
9218
+ log28.error(`provider '${providerName}' does not implement prepare`);
9141
9219
  process.exit(1);
9142
9220
  }
9143
9221
  const cwd = opts.cwd ?? process.cwd();
9222
+ const registry = providerName === "docker" ? await loadEffectiveConfig(cwd).then((c) => c.effective.box.imageRegistry).catch(() => void 0) : void 0;
9144
9223
  const sp = spinner7();
9145
9224
  sp.start(`preparing ${providerName}\u2026`);
9146
9225
  try {
@@ -9148,16 +9227,18 @@ async function runPrepare(providerName, opts = {}) {
9148
9227
  name: opts.name,
9149
9228
  hostWorkspace: cwd,
9150
9229
  force: opts.force,
9230
+ allowPull: opts.build ? false : void 0,
9231
+ registry,
9151
9232
  onLog: (line) => sp.message(line.slice(0, 80))
9152
9233
  });
9153
9234
  if (result.snapshotName !== void 0) {
9154
9235
  sp.stop(`prepared ${providerName}: snapshot '${result.snapshotName}'`);
9155
9236
  try {
9156
9237
  const written = await setConfigValue("project", "box.image", result.snapshotName, cwd);
9157
- log29.success(`box.image = ${result.snapshotName} (written to ${written.path})`);
9238
+ log28.success(`box.image = ${result.snapshotName} (written to ${written.path})`);
9158
9239
  } catch (err) {
9159
9240
  const msg = err instanceof Error ? err.message : String(err);
9160
- log29.warn(
9241
+ log28.warn(
9161
9242
  `prepared snapshot '${result.snapshotName}', but failed to pin it into the project config: ${msg}
9162
9243
  Run \`agentbox config set --project box.image ${result.snapshotName}\` manually.`
9163
9244
  );
@@ -9170,7 +9251,7 @@ Run \`agentbox config set --project box.image ${result.snapshotName}\` manually.
9170
9251
  await showStatus({ onlyProvider: providerName });
9171
9252
  }
9172
9253
  if (!opts.suppressTip) {
9173
- log29.info(
9254
+ log28.info(
9174
9255
  "tip: install the agentbox host skill so Claude Code on this machine can drive AgentBox for you:\n npx skills add https://github.com/madarco/agentbox --skill agentbox"
9175
9256
  );
9176
9257
  }
@@ -9184,7 +9265,10 @@ var prepareCommand = new Command24("prepare").description(
9184
9265
  ).option(
9185
9266
  "-p, --provider <name>",
9186
9267
  "provider to prepare (docker | daytona | hetzner | vercel). Omit for status-only."
9187
- ).option("-n, --name <name>", "snapshot name (Daytona only; default: agentbox-base-<timestamp>)").option("-f, --force", "rebuild even if the image / snapshot already exists").option("-y, --yes", "skip confirmation prompts (cost / time warnings)").option("--status", "show status without preparing anything").action(async (opts) => {
9268
+ ).option("-n, --name <name>", "snapshot name (Daytona only; default: agentbox-base-<timestamp>)").option("-f, --force", "rebuild even if the image / snapshot already exists").option(
9269
+ "--build",
9270
+ "docker: build the base image locally instead of pulling the prebuilt one from the registry"
9271
+ ).option("-y, --yes", "skip confirmation prompts (cost / time warnings)").option("--status", "show status without preparing anything").action(async (opts) => {
9188
9272
  if (!opts.provider || opts.status) {
9189
9273
  await showStatus({});
9190
9274
  return;
@@ -9194,6 +9278,7 @@ var prepareCommand = new Command24("prepare").description(
9194
9278
  await runPrepare(providerName, {
9195
9279
  name: opts.name,
9196
9280
  force: opts.force,
9281
+ build: opts.build,
9197
9282
  yes: opts.yes
9198
9283
  });
9199
9284
  });
@@ -9298,7 +9383,7 @@ ${LOGO_L2}\x1B[0m` + SYNC_END2);
9298
9383
  }
9299
9384
  var LEGACY_INFO_MARKER = "Drive AgentBox from the host:";
9300
9385
  function installTargets() {
9301
- const home = homedir13();
9386
+ const home = homedir14();
9302
9387
  const claudeSkills = join15(home, ".claude", "skills");
9303
9388
  return [
9304
9389
  { src: join15("agentbox", "SKILL.md"), dest: join15(claudeSkills, "agentbox", "SKILL.md") },
@@ -9349,20 +9434,20 @@ function installHostSkills(opts = {}) {
9349
9434
  for (const t of installTargets()) {
9350
9435
  const src = join15(srcDir, t.src);
9351
9436
  if (!existsSync6(src)) {
9352
- if (!quiet) log30.warn(`bundled file missing (skipped): ${src}`);
9437
+ if (!quiet) log29.warn(`bundled file missing (skipped): ${src}`);
9353
9438
  skipped++;
9354
9439
  continue;
9355
9440
  }
9356
9441
  if (t.gateDir && !existsSync6(t.gateDir)) continue;
9357
9442
  const reason = writableReason(t.dest, force);
9358
9443
  if (reason === "skip") {
9359
- if (!quiet) log30.warn(`user-modified file at ${t.dest}, skipping; pass --force to overwrite`);
9444
+ if (!quiet) log29.warn(`user-modified file at ${t.dest}, skipping; pass --force to overwrite`);
9360
9445
  blocked.push(t.dest);
9361
9446
  skipped++;
9362
9447
  continue;
9363
9448
  }
9364
9449
  if (dryRun) {
9365
- if (!quiet) log30.info(`would write ${t.dest} (${reason})`);
9450
+ if (!quiet) log29.info(`would write ${t.dest} (${reason})`);
9366
9451
  written.push(t.dest);
9367
9452
  continue;
9368
9453
  }
@@ -9394,10 +9479,10 @@ function ensureTty() {
9394
9479
  async function runProviderLogin(name) {
9395
9480
  if (name === "docker") return true;
9396
9481
  if (name === "daytona") {
9397
- const mod2 = await import("./dist-TMHSUVTP.js");
9482
+ const mod2 = await import("./dist-PJFJNXO2.js");
9398
9483
  const status2 = await mod2.getDaytonaStatus();
9399
9484
  if (status2.configured) {
9400
- log30.info("daytona: already configured");
9485
+ log29.info("daytona: already configured");
9401
9486
  const rotate = await confirm14({ message: "Re-authenticate Daytona?", initialValue: false });
9402
9487
  if (isCancel15(rotate)) return false;
9403
9488
  if (rotate) await mod2.ensureDaytonaCredentials({ force: true });
@@ -9407,10 +9492,10 @@ async function runProviderLogin(name) {
9407
9492
  return true;
9408
9493
  }
9409
9494
  if (name === "hetzner") {
9410
- const mod2 = await import("./dist-5FQGYRW5.js");
9495
+ const mod2 = await import("./dist-4SUIXKSD.js");
9411
9496
  const status2 = mod2.readHetznerCredStatus();
9412
9497
  if (status2.source !== "none") {
9413
- log30.info("hetzner: already configured");
9498
+ log29.info("hetzner: already configured");
9414
9499
  const rotate = await confirm14({ message: "Re-authenticate Hetzner?", initialValue: false });
9415
9500
  if (isCancel15(rotate)) return false;
9416
9501
  if (rotate) await mod2.ensureHetznerCredentials({ force: true });
@@ -9419,10 +9504,10 @@ async function runProviderLogin(name) {
9419
9504
  await mod2.ensureHetznerCredentials();
9420
9505
  return true;
9421
9506
  }
9422
- const mod = await import("./dist-PZW3GWWU.js");
9507
+ const mod = await import("./dist-HT2YV6PB.js");
9423
9508
  const status = mod.readVercelCredStatus();
9424
9509
  if (status.auth !== "none") {
9425
- log30.info(`vercel: already configured (${status.auth})`);
9510
+ log29.info(`vercel: already configured (${status.auth})`);
9426
9511
  const rotate = await confirm14({ message: "Re-authenticate Vercel?", initialValue: false });
9427
9512
  if (isCancel15(rotate)) return false;
9428
9513
  if (rotate) await mod.ensureVercelCredentials({ force: true });
@@ -9453,11 +9538,11 @@ async function runInstallWizard(opts = {}) {
9453
9538
  process.stdout.write(" " + formatCompact([sysGroup]) + "\n");
9454
9539
  const hardFail = sysResults.find((r) => r.status === "fail");
9455
9540
  if (hardFail) {
9456
- log30.error(`system check failed: ${hardFail.label} \u2014 ${hardFail.detail}`);
9457
- log30.info("run `agentbox doctor` for full detail");
9541
+ log29.error(`system check failed: ${hardFail.label} \u2014 ${hardFail.detail}`);
9542
+ log29.info("run `agentbox doctor` for full detail");
9458
9543
  const cont = await confirm14({ message: "Continue anyway?", initialValue: false });
9459
9544
  if (isCancel15(cont) || !cont) {
9460
- outro6("aborted");
9545
+ outro5("aborted");
9461
9546
  return false;
9462
9547
  }
9463
9548
  }
@@ -9465,7 +9550,7 @@ async function runInstallWizard(opts = {}) {
9465
9550
  if (opts.provider) {
9466
9551
  const candidate = opts.provider.trim();
9467
9552
  if (!isProviderName(candidate)) {
9468
- log30.error(`unknown --provider: ${candidate}`);
9553
+ log29.error(`unknown --provider: ${candidate}`);
9469
9554
  return false;
9470
9555
  }
9471
9556
  providerName = candidate;
@@ -9480,7 +9565,7 @@ async function runInstallWizard(opts = {}) {
9480
9565
  }))
9481
9566
  });
9482
9567
  if (isCancel15(picked)) {
9483
- outro6("cancelled");
9568
+ outro5("cancelled");
9484
9569
  return false;
9485
9570
  }
9486
9571
  providerName = picked;
@@ -9488,14 +9573,14 @@ async function runInstallWizard(opts = {}) {
9488
9573
  if (providerName !== "docker") {
9489
9574
  const loggedIn = await runProviderLogin(providerName);
9490
9575
  if (!loggedIn) {
9491
- outro6("cancelled");
9576
+ outro5("cancelled");
9492
9577
  return false;
9493
9578
  }
9494
9579
  }
9495
9580
  const prepareMsg = providerName === "docker" ? "Build the box image now? (~1GB, a few minutes)" : `Bake the ${providerName} base snapshot now? (a few minutes, uses cloud time)`;
9496
9581
  const wantPrepare = opts.yes ? true : await confirm14({ message: prepareMsg, initialValue: true });
9497
9582
  if (isCancel15(wantPrepare)) {
9498
- outro6("cancelled");
9583
+ outro5("cancelled");
9499
9584
  return false;
9500
9585
  }
9501
9586
  if (wantPrepare) {
@@ -9507,12 +9592,12 @@ async function runInstallWizard(opts = {}) {
9507
9592
  suppressTip: true
9508
9593
  });
9509
9594
  } catch (err) {
9510
- log30.warn(
9595
+ log29.warn(
9511
9596
  `prepare failed: ${err instanceof Error ? err.message : String(err)} \u2014 you can rerun \`agentbox prepare --provider ${providerName}\` later`
9512
9597
  );
9513
9598
  }
9514
9599
  } else {
9515
- log30.info(
9600
+ log29.info(
9516
9601
  `skipped \u2014 the ${providerName} base will build lazily on first \`agentbox ${providerName === "docker" ? "" : providerName + " "}create\``
9517
9602
  );
9518
9603
  }
@@ -9527,20 +9612,20 @@ async function runInstallWizard(opts = {}) {
9527
9612
  sp.stop(`Agentbox Skills: nothing to write (${String(skillRes.skipped)} skipped)`);
9528
9613
  }
9529
9614
  if (skillRes.blocked.length > 0) {
9530
- log30.warn(
9615
+ log29.warn(
9531
9616
  `user-modified host skill file(s) left in place: ${skillRes.blocked.join(", ")}
9532
9617
  pass \`agentbox install --skills-only --force\` to overwrite`
9533
9618
  );
9534
9619
  }
9535
9620
  } catch (err) {
9536
9621
  sp.stop("Agentbox Skills: failed");
9537
- log30.warn(err instanceof Error ? err.message : String(err));
9622
+ log29.warn(err instanceof Error ? err.message : String(err));
9538
9623
  }
9539
9624
  markSetupComplete(providerName);
9540
9625
  const providerGroup = await runProviderChecks(providerName);
9541
9626
  process.stdout.write(" " + formatCompact([sysGroup, providerGroup]) + "\n");
9542
- note(tutorialBody(providerName), "Next steps");
9543
- outro6(
9627
+ note2(tutorialBody(providerName), "Next steps");
9628
+ outro5(
9544
9629
  opts.fromAutoTrigger ? "\u2728 Setup complete \u2014 continuing with your command\u2026" : "\u2728 Setup complete"
9545
9630
  );
9546
9631
  return true;
@@ -9560,20 +9645,20 @@ var installCommand = new Command25("install").description(
9560
9645
  try {
9561
9646
  res = installHostSkills({ force: opts.force, dryRun: opts.dryRun });
9562
9647
  } catch (err) {
9563
- log30.error(err instanceof Error ? err.message : String(err));
9648
+ log29.error(err instanceof Error ? err.message : String(err));
9564
9649
  process.exit(1);
9565
9650
  }
9566
9651
  if (opts.dryRun) {
9567
- outro6(
9652
+ outro5(
9568
9653
  `dry-run: ${String(res.written.length)} file(s) would be written, ${String(res.skipped)} skipped`
9569
9654
  );
9570
9655
  return;
9571
9656
  }
9572
9657
  if (res.written.length === 0) {
9573
- outro6(`nothing installed (${String(res.skipped)} skipped)`);
9658
+ outro5(`nothing installed (${String(res.skipped)} skipped)`);
9574
9659
  return;
9575
9660
  }
9576
- outro6(`installed: ${res.written.join(", ")}`);
9661
+ outro5(`installed: ${res.written.join(", ")}`);
9577
9662
  return;
9578
9663
  }
9579
9664
  const ok = await runInstallWizard({
@@ -9765,7 +9850,7 @@ for (const op of GH_PR_OPS) {
9765
9850
  var gitCommand = new Command27("git").description("Run git / gh pr operations against a box from the host").addCommand(pushCommand).addCommand(fetchCommand).addCommand(pullCommand).addCommand(checkoutCommand).addCommand(statusCommand).addCommand(prCommand);
9766
9851
 
9767
9852
  // src/commands/list.ts
9768
- import { log as log31 } from "@clack/prompts";
9853
+ import { log as log30 } from "@clack/prompts";
9769
9854
  import { Command as Command28 } from "commander";
9770
9855
  import { pathToFileURL } from "url";
9771
9856
 
@@ -9980,7 +10065,7 @@ var listCommand2 = withWatchOptions(
9980
10065
  )
9981
10066
  ).action(async (opts) => {
9982
10067
  if (opts.json && opts.watch) {
9983
- log31.error("cannot combine --json with --watch");
10068
+ log30.error("cannot combine --json with --watch");
9984
10069
  process.exit(2);
9985
10070
  }
9986
10071
  const all = opts.global ?? false;
@@ -9998,7 +10083,7 @@ var listCommand2 = withWatchOptions(
9998
10083
  });
9999
10084
 
10000
10085
  // src/commands/logs.ts
10001
- import { log as log32 } from "@clack/prompts";
10086
+ import { log as log31 } from "@clack/prompts";
10002
10087
  import { Command as Command29 } from "commander";
10003
10088
  import { spawn as spawn3 } from "child_process";
10004
10089
  var DAEMON_LOG_PATH = "/var/log/agentbox/ctl-daemon.log";
@@ -10020,9 +10105,9 @@ var logsCommand = new Command29("logs").description("Print recent log lines from
10020
10105
  service = boxArg;
10021
10106
  }
10022
10107
  if (!service && !opts.daemon) {
10023
- log32.error("missing <service> argument");
10024
- log32.info("usage: agentbox logs [box] <service> [-n N] [-f]");
10025
- log32.info(" agentbox logs [box] --daemon [-n N] [-f]");
10108
+ log31.error("missing <service> argument");
10109
+ log31.info("usage: agentbox logs [box] <service> [-n N] [-f]");
10110
+ log31.info(" agentbox logs [box] --daemon [-n N] [-f]");
10026
10111
  process.exit(2);
10027
10112
  }
10028
10113
  const box = await resolveBoxOrExit(idOrName);
@@ -10033,7 +10118,7 @@ var logsCommand = new Command29("logs").description("Print recent log lines from
10033
10118
  if (!opts.follow) {
10034
10119
  const proc = await provider.exec(box, args, { user: "vscode" });
10035
10120
  if (proc.exitCode !== 0) {
10036
- log32.error(
10121
+ log31.error(
10037
10122
  `${opts.daemon ? "daemon log" : "agentbox-ctl logs"} failed: ${proc.stderr || proc.stdout}`
10038
10123
  );
10039
10124
  process.exit(1);
@@ -10089,10 +10174,10 @@ var logsCommand = new Command29("logs").description("Print recent log lines from
10089
10174
  });
10090
10175
 
10091
10176
  // src/commands/open.ts
10092
- import { log as log33 } from "@clack/prompts";
10177
+ import { log as log32 } from "@clack/prompts";
10093
10178
  import { execa as execa3 } from "execa";
10094
10179
  import { existsSync as existsSync7, mkdirSync as mkdirSync6 } from "fs";
10095
- import { homedir as homedir14 } from "os";
10180
+ import { homedir as homedir15 } from "os";
10096
10181
  import { join as join16 } from "path";
10097
10182
  import { Command as Command30 } from "commander";
10098
10183
 
@@ -10155,7 +10240,7 @@ var openCommand = new Command30("open").description("Open a box's /workspace in
10155
10240
  }
10156
10241
  });
10157
10242
  async function runCloudOpen(box, provider, opts) {
10158
- const mountRoot = join16(homedir14(), ".agentbox", "mounts", box.name);
10243
+ const mountRoot = join16(homedir15(), ".agentbox", "mounts", box.name);
10159
10244
  if (opts.unmount) {
10160
10245
  const ok = await tryUnmount(mountRoot);
10161
10246
  if (ok) process.stdout.write(`unmounted ${mountRoot}
@@ -10195,10 +10280,10 @@ async function runCloudOpen(box, provider, opts) {
10195
10280
  if (!existsSync7(mountRoot)) {
10196
10281
  mkdirSync6(mountRoot, { recursive: true, mode: 493 });
10197
10282
  } else if (await isMounted(mountRoot)) {
10198
- log33.info(`re-mounting (stale mount detected at ${mountRoot})`);
10283
+ log32.info(`re-mounting (stale mount detected at ${mountRoot})`);
10199
10284
  await tryUnmount(mountRoot);
10200
10285
  }
10201
- log33.info(`mounting ${alias}:/workspace at ${mountRoot}`);
10286
+ log32.info(`mounting ${alias}:/workspace at ${mountRoot}`);
10202
10287
  const mount = await execa3(
10203
10288
  sshfsBin,
10204
10289
  [
@@ -10218,7 +10303,7 @@ async function runCloudOpen(box, provider, opts) {
10218
10303
  if (mount.exitCode !== 0) {
10219
10304
  throw new Error(`sshfs mount failed (exit ${String(mount.exitCode)}): ${mount.stderr || mount.stdout}`);
10220
10305
  }
10221
- await execa3("open", [mountRoot], { reject: false });
10306
+ await execa3(hostOpenCommand(), [mountRoot], { reject: false });
10222
10307
  process.stdout.write(`opened ${mountRoot}
10223
10308
  `);
10224
10309
  process.stdout.write(`unmount later with: agentbox open ${box.name} --unmount
@@ -10269,7 +10354,7 @@ var pauseCommand = new Command31("pause").description(
10269
10354
  });
10270
10355
 
10271
10356
  // src/commands/prune.ts
10272
- import { confirm as confirm15, isCancel as isCancel16, log as log34 } from "@clack/prompts";
10357
+ import { confirm as confirm15, isCancel as isCancel16, log as log33 } from "@clack/prompts";
10273
10358
  import { Command as Command32 } from "commander";
10274
10359
  function totalRemovals(r, projectConfigs) {
10275
10360
  return r.removedRecords.length + r.removedContainers.length + r.removedVolumes.length + r.removedSnapshotDirs.length + r.removedBoxDirs.length + projectConfigs.length;
@@ -10329,7 +10414,7 @@ var pruneCommand = new Command32("prune").description("Clean up orphan state.jso
10329
10414
  return;
10330
10415
  }
10331
10416
  if (opts.provider !== void 0 && opts.provider !== "docker") {
10332
- log34.error(`unknown provider '${opts.provider}'; expected docker, daytona, hetzner, or vercel`);
10417
+ log33.error(`unknown provider '${opts.provider}'; expected docker, daytona, hetzner, or vercel`);
10333
10418
  process.exit(2);
10334
10419
  }
10335
10420
  const dryRun = opts.dryRun ?? false;
@@ -10342,13 +10427,13 @@ var pruneCommand = new Command32("prune").description("Clean up orphan state.jso
10342
10427
  process.stdout.write("nothing to prune\n");
10343
10428
  return;
10344
10429
  }
10345
- log34.info(`would remove:
10430
+ log33.info(`would remove:
10346
10431
  ${summary(preview, previewProjects)}`);
10347
10432
  if (dryRun) return;
10348
10433
  if (!opts.yes) {
10349
10434
  const ok = await confirm15({ message: "Proceed with prune?", initialValue: true });
10350
10435
  if (isCancel16(ok) || !ok) {
10351
- log34.info("cancelled");
10436
+ log33.info("cancelled");
10352
10437
  return;
10353
10438
  }
10354
10439
  }
@@ -10369,7 +10454,7 @@ async function pruneCloud(provider, opts) {
10369
10454
  const dryRun = opts.dryRun ?? false;
10370
10455
  const backend = await cloudBackendForProvider(provider);
10371
10456
  if (!backend.list) {
10372
- log34.error(`${provider} backend doesn't expose \`list()\`; cannot enumerate sandboxes for prune`);
10457
+ log33.error(`${provider} backend doesn't expose \`list()\`; cannot enumerate sandboxes for prune`);
10373
10458
  process.exit(2);
10374
10459
  }
10375
10460
  const [remote, state] = await Promise.all([backend.list(), readState()]);
@@ -10389,7 +10474,7 @@ async function pruneCloud(provider, opts) {
10389
10474
  `);
10390
10475
  return;
10391
10476
  }
10392
- log34.info(`found ${String(orphans.length)} ${provider} sandbox(es) not in this CLI's state:`);
10477
+ log33.info(`found ${String(orphans.length)} ${provider} sandbox(es) not in this CLI's state:`);
10393
10478
  for (const sb of orphans) {
10394
10479
  const parts = [sb.sandboxId];
10395
10480
  if (sb.name) parts.push(sb.name);
@@ -10405,7 +10490,7 @@ async function pruneCloud(provider, opts) {
10405
10490
  initialValue: false
10406
10491
  });
10407
10492
  if (isCancel16(ok) || !ok) {
10408
- log34.info("cancelled");
10493
+ log33.info("cancelled");
10409
10494
  return;
10410
10495
  }
10411
10496
  }
@@ -10417,7 +10502,7 @@ async function pruneCloud(provider, opts) {
10417
10502
  deleted++;
10418
10503
  } catch (err) {
10419
10504
  failed++;
10420
- log34.warn(
10505
+ log33.warn(
10421
10506
  `delete ${sb.sandboxId} failed: ${err instanceof Error ? err.message : String(err)}`
10422
10507
  );
10423
10508
  }
@@ -10430,7 +10515,7 @@ async function pruneCloud(provider, opts) {
10430
10515
 
10431
10516
  // src/commands/queue.ts
10432
10517
  import { readFile as readFile4, stat as stat5 } from "fs/promises";
10433
- import { intro as intro7, log as log35, outro as outro7 } from "@clack/prompts";
10518
+ import { intro as intro7, log as log34, outro as outro6 } from "@clack/prompts";
10434
10519
  import { Command as Command33 } from "commander";
10435
10520
  var TERMINAL_STATUSES = /* @__PURE__ */ new Set(["done", "failed", "cancelled"]);
10436
10521
  var queueCommand = new Command33("queue").description("Inspect and manage background `agentbox claude|codex|opencode -i` jobs");
@@ -10439,8 +10524,8 @@ var queueListCommand = new Command33("list").description("List queued, running,
10439
10524
  const cfg = await loadQueueConfig();
10440
10525
  const visible = opts.all === true ? jobs : jobs.filter((j) => !TERMINAL_STATUSES.has(j.status));
10441
10526
  if (visible.length === 0) {
10442
- log35.info(opts.all ? "no queued jobs." : "no active queued jobs (--all to see terminal).");
10443
- log35.info(`queue.maxConcurrent = ${String(cfg.maxConcurrent)} (queue.enabled=${String(cfg.enabled)})`);
10527
+ log34.info(opts.all ? "no queued jobs." : "no active queued jobs (--all to see terminal).");
10528
+ log34.info(`queue.maxConcurrent = ${String(cfg.maxConcurrent)} (queue.enabled=${String(cfg.enabled)})`);
10444
10529
  return;
10445
10530
  }
10446
10531
  const rows = visible.map((j) => ({
@@ -10465,12 +10550,12 @@ var queueListCommand = new Command33("list").description("List queued, running,
10465
10550
  headers.map((h, i) => pad4(String(r[h]), widths[i])).join(" ") + "\n"
10466
10551
  );
10467
10552
  }
10468
- log35.info(`queue.maxConcurrent = ${String(cfg.maxConcurrent)} (queue.enabled=${String(cfg.enabled)})`);
10553
+ log34.info(`queue.maxConcurrent = ${String(cfg.maxConcurrent)} (queue.enabled=${String(cfg.enabled)})`);
10469
10554
  });
10470
10555
  var queueShowCommand = new Command33("show").description("Dump a job manifest and tail its log").argument("<id>", "queue job id (from `agentbox queue list`)").option("--tail <n>", "lines of log to print (default: 50)", "50").action(async (id, opts) => {
10471
10556
  const job = await readJob(id);
10472
10557
  if (!job) {
10473
- log35.error(`no job with id ${id}`);
10558
+ log34.error(`no job with id ${id}`);
10474
10559
  process.exit(1);
10475
10560
  }
10476
10561
  process.stdout.write(JSON.stringify(job, null, 2) + "\n");
@@ -10486,18 +10571,18 @@ var queueShowCommand = new Command33("show").description("Dump a job manifest an
10486
10571
  process.stdout.write(slice.join("\n"));
10487
10572
  if (!slice.join("\n").endsWith("\n")) process.stdout.write("\n");
10488
10573
  } catch {
10489
- log35.info(`(no log at ${job.logPath} yet)`);
10574
+ log34.info(`(no log at ${job.logPath} yet)`);
10490
10575
  }
10491
10576
  });
10492
10577
  var queueCancelCommand = new Command33("cancel").description("Cancel a queued job; running jobs are NOT killed \u2014 use `agentbox destroy` instead").argument("<id>", "queue job id (from `agentbox queue list`)").action(async (id) => {
10493
10578
  intro7(`Cancelling queue job ${id}...`);
10494
10579
  const job = await readJob(id);
10495
10580
  if (!job) {
10496
- log35.error(`no job with id ${id}`);
10581
+ log34.error(`no job with id ${id}`);
10497
10582
  process.exit(1);
10498
10583
  }
10499
10584
  if (job.status !== "queued") {
10500
- log35.error(
10585
+ log34.error(
10501
10586
  `job ${id} is ${job.status}; cancel only flips 'queued' \u2192 'cancelled'.` + (job.status === "running" ? ` Use 'agentbox destroy ${job.boxName || id}' to stop the box.` : "")
10502
10587
  );
10503
10588
  process.exit(1);
@@ -10509,7 +10594,7 @@ var queueCancelCommand = new Command33("cancel").description("Cancel a queued jo
10509
10594
  reason: "cancelled by user"
10510
10595
  };
10511
10596
  await writeJob(cancelled);
10512
- outro7(`job ${id} cancelled`);
10597
+ outro6(`job ${id} cancelled`);
10513
10598
  });
10514
10599
  var queueClearCommand = new Command33("clear").description("Sweep terminal-state manifests from ~/.agentbox/queue/").option("--done", "remove done jobs").option("--failed", "remove failed jobs").option("--cancelled", "remove cancelled jobs").option("--all", "remove every terminal-state job (done + failed + cancelled)").action(async (opts) => {
10515
10600
  const targets = /* @__PURE__ */ new Set();
@@ -10517,7 +10602,7 @@ var queueClearCommand = new Command33("clear").description("Sweep terminal-state
10517
10602
  if (opts.all === true || opts.failed === true) targets.add("failed");
10518
10603
  if (opts.all === true || opts.cancelled === true) targets.add("cancelled");
10519
10604
  if (targets.size === 0) {
10520
- log35.error("pick at least one of: --done, --failed, --cancelled, --all");
10605
+ log34.error("pick at least one of: --done, --failed, --cancelled, --all");
10521
10606
  process.exit(2);
10522
10607
  }
10523
10608
  const jobs = await loadQueue();
@@ -10527,7 +10612,7 @@ var queueClearCommand = new Command33("clear").description("Sweep terminal-state
10527
10612
  await deleteJob(j.id);
10528
10613
  removed += 1;
10529
10614
  }
10530
- log35.success(`removed ${String(removed)} manifest${removed === 1 ? "" : "s"}`);
10615
+ log34.success(`removed ${String(removed)} manifest${removed === 1 ? "" : "s"}`);
10531
10616
  });
10532
10617
  var QUEUE_WAIT_EVENTS = [
10533
10618
  "new-box",
@@ -10544,7 +10629,7 @@ var queueWaitForCommand = new Command33("wait-for").description(
10544
10629
  `Block until a queue / box event fires. <event> one of: ${QUEUE_WAIT_EVENTS.join(" | ")}.`
10545
10630
  ).argument("<event>", `target event: ${QUEUE_WAIT_EVENTS.join(" | ")}`).option("--box <ref>", "box ref (required for box-paused / box-running / box-stopped)").option("--job <id>", "queue job id (required for job-done)").option("--timeout <ms>", `wall-clock cap (default: ${String(DEFAULT_QUEUE_WAIT_TIMEOUT_MS)})`).option("--json", "emit a JSON envelope { matched, elapsedMs, ... }").action(async (eventRaw, opts) => {
10546
10631
  if (!QUEUE_WAIT_EVENTS.includes(eventRaw)) {
10547
- log35.error(`unknown event '${eventRaw}' (one of: ${QUEUE_WAIT_EVENTS.join(", ")})`);
10632
+ log34.error(`unknown event '${eventRaw}' (one of: ${QUEUE_WAIT_EVENTS.join(", ")})`);
10548
10633
  process.exit(2);
10549
10634
  }
10550
10635
  const event = eventRaw;
@@ -10564,11 +10649,11 @@ var queueWaitForCommand = new Command33("wait-for").description(
10564
10649
  if (opts.json === true) {
10565
10650
  process.stdout.write(JSON.stringify({ matched: false, event, elapsedMs }) + "\n");
10566
10651
  } else {
10567
- log35.error(`'${event}' did not occur within ${String(timeoutMs)}ms`);
10652
+ log34.error(`'${event}' did not occur within ${String(timeoutMs)}ms`);
10568
10653
  }
10569
10654
  process.exit(1);
10570
10655
  }
10571
- log35.error(err instanceof Error ? err.message : String(err));
10656
+ log34.error(err instanceof Error ? err.message : String(err));
10572
10657
  process.exit(1);
10573
10658
  }
10574
10659
  });
@@ -10665,7 +10750,7 @@ function truncate(s, max) {
10665
10750
  }
10666
10751
 
10667
10752
  // src/commands/relay.ts
10668
- import { log as log36, spinner as spinner9 } from "@clack/prompts";
10753
+ import { log as log35, spinner as spinner9 } from "@clack/prompts";
10669
10754
  import { Command as Command34 } from "commander";
10670
10755
  async function rehydrateFromState() {
10671
10756
  const state = await readState();
@@ -10759,7 +10844,7 @@ var restartSub = new Command34("restart").description("Stop then start the host
10759
10844
  s2.stop(`relay running on ${ep.hostUrl}`);
10760
10845
  } catch (err) {
10761
10846
  s2.stop("relay start failed");
10762
- log36.warn(err instanceof Error ? err.message : String(err));
10847
+ log35.warn(err instanceof Error ? err.message : String(err));
10763
10848
  throw err;
10764
10849
  }
10765
10850
  } catch (err) {
@@ -10771,17 +10856,17 @@ var relayCommand = new Command34("relay").description("Manage the host relay pro
10771
10856
  // src/commands/_run-queued-job.ts
10772
10857
  import { Command as Command35 } from "commander";
10773
10858
  var runQueuedJobCommand = new Command35("_run-queued-job").description("internal: run a queued background agent job (do not invoke directly)").argument("<id>", "queue job id (from ~/.agentbox/queue/<id>.json)").action(async (id) => {
10774
- const log45 = openCommandLog(`queue-${id}`);
10775
- log45.write(`worker pid=${String(process.pid)} starting for job ${id}`);
10859
+ const log44 = openCommandLog(`queue-${id}`);
10860
+ log44.write(`worker pid=${String(process.pid)} starting for job ${id}`);
10776
10861
  let job = null;
10777
10862
  try {
10778
10863
  job = await readJob(id);
10779
10864
  if (!job) {
10780
- log45.write(`FATAL: no manifest at id=${id}`);
10781
- log45.close();
10865
+ log44.write(`FATAL: no manifest at id=${id}`);
10866
+ log44.close();
10782
10867
  process.exit(64);
10783
10868
  }
10784
- await runDockerJob(job, log45, (boxId) => {
10869
+ await runDockerJob(job, log44, (boxId) => {
10785
10870
  if (job) job = { ...job, boxId };
10786
10871
  });
10787
10872
  const done = {
@@ -10791,12 +10876,12 @@ var runQueuedJobCommand = new Command35("_run-queued-job").description("internal
10791
10876
  exitCode: 0
10792
10877
  };
10793
10878
  await writeJob(done);
10794
- log45.write(`done`);
10795
- log45.close();
10879
+ log44.write(`done`);
10880
+ log44.close();
10796
10881
  process.exit(0);
10797
10882
  } catch (err) {
10798
10883
  const msg = err instanceof Error ? err.stack ?? err.message : String(err);
10799
- log45.write(`FAIL: ${msg}`);
10884
+ log44.write(`FAIL: ${msg}`);
10800
10885
  if (job) {
10801
10886
  try {
10802
10887
  const failed = {
@@ -10810,11 +10895,11 @@ var runQueuedJobCommand = new Command35("_run-queued-job").description("internal
10810
10895
  } catch {
10811
10896
  }
10812
10897
  }
10813
- log45.close();
10898
+ log44.close();
10814
10899
  process.exit(1);
10815
10900
  }
10816
10901
  });
10817
- async function runDockerJob(job, log45, onBoxCreated) {
10902
+ async function runDockerJob(job, log44, onBoxCreated) {
10818
10903
  const opts = job.createOpts;
10819
10904
  const cfg = await loadEffectiveConfig(opts.workspace, {
10820
10905
  cliOverrides: buildOverridesFromJob(job)
@@ -10829,7 +10914,7 @@ async function runDockerJob(job, log45, onBoxCreated) {
10829
10914
  const useSnapshot = opts.hostSnapshot === false ? false : opts.hostSnapshot === true ? true : cfg.effective.box.hostSnapshot ?? false;
10830
10915
  const resolved = job.agent === "claude-code" ? await resolveClaudeAuth(process.env) : null;
10831
10916
  const withPlaywright = cfg.effective.box.withPlaywright || cfg.effective.browser.default !== "agent-browser";
10832
- log45.write(`creating box for agent=${job.agent}`);
10917
+ log44.write(`creating box for agent=${job.agent}`);
10833
10918
  const result = await createBox({
10834
10919
  workspacePath: opts.workspace,
10835
10920
  name: opts.name && opts.name.length > 0 ? opts.name : void 0,
@@ -10851,19 +10936,19 @@ async function runDockerJob(job, log45, onBoxCreated) {
10851
10936
  portlessStateDir: cfg.effective.portless.stateDir || void 0,
10852
10937
  limits: resolveLimits(cfg.effective.box, opts),
10853
10938
  projectRoot,
10854
- onLog: (line) => log45.write(line)
10939
+ onLog: (line) => log44.write(line)
10855
10940
  });
10856
- log45.write(`box created: ${result.record.container}`);
10941
+ log44.write(`box created: ${result.record.container}`);
10857
10942
  onBoxCreated(result.record.id);
10858
10943
  await writeJob({ ...job, boxId: result.record.id });
10859
10944
  const promptedArgs = buildPromptArgs(job.agent, job.prompt, job.agentArgs);
10860
10945
  if (job.agent === "claude-code") {
10861
- log45.write(`checking plugin native deps`);
10946
+ log44.write(`checking plugin native deps`);
10862
10947
  await rebuildPluginNativeDeps(result.record.container, {
10863
10948
  volume: result.record.claudeConfigVolume ?? SHARED_CLAUDE_VOLUME,
10864
- onProgress: (line) => log45.write(line)
10949
+ onProgress: (line) => log44.write(line)
10865
10950
  });
10866
- log45.write(`starting claude session`);
10951
+ log44.write(`starting claude session`);
10867
10952
  await startClaudeSession({
10868
10953
  container: result.record.container,
10869
10954
  claudeArgs: applyClaudeSkipPermissions(promptedArgs, cfg.effective),
@@ -10871,22 +10956,22 @@ async function runDockerJob(job, log45, onBoxCreated) {
10871
10956
  boxName: result.record.name
10872
10957
  });
10873
10958
  } else if (job.agent === "codex") {
10874
- log45.write(`checking codex`);
10959
+ log44.write(`checking codex`);
10875
10960
  await ensureCodexInstalled(result.record.container, {
10876
- onProgress: (line) => log45.write(line)
10961
+ onProgress: (line) => log44.write(line)
10877
10962
  });
10878
- log45.write(`starting codex session`);
10963
+ log44.write(`starting codex session`);
10879
10964
  await startCodexSession({
10880
10965
  container: result.record.container,
10881
10966
  codexArgs: applyCodexSkipPermissions(promptedArgs, cfg.effective),
10882
10967
  sessionName: cfg.effective.codex.sessionName
10883
10968
  });
10884
10969
  } else if (job.agent === "opencode") {
10885
- log45.write(`checking opencode`);
10970
+ log44.write(`checking opencode`);
10886
10971
  await ensureOpencodeInstalled(result.record.container, {
10887
- onProgress: (line) => log45.write(line)
10972
+ onProgress: (line) => log44.write(line)
10888
10973
  });
10889
- log45.write(`starting opencode session`);
10974
+ log44.write(`starting opencode session`);
10890
10975
  await startOpencodeSession({
10891
10976
  container: result.record.container,
10892
10977
  opencodeArgs: promptedArgs,
@@ -10925,7 +11010,7 @@ function buildOverridesFromJob(job) {
10925
11010
 
10926
11011
  // src/commands/screen.ts
10927
11012
  import { spawnSync as spawnSync3 } from "child_process";
10928
- import { log as log37 } from "@clack/prompts";
11013
+ import { log as log36 } from "@clack/prompts";
10929
11014
  import { Command as Command36 } from "commander";
10930
11015
  var SIGNED_URL_TTL_MIN = 1;
10931
11016
  var SIGNED_URL_TTL_MAX = 86400;
@@ -10956,10 +11041,10 @@ var screenCommand = new Command36("screen").description("Open a box's VNC (noVNC
10956
11041
  if (provider === "docker") {
10957
11042
  const insp = await inspectBox(box.id);
10958
11043
  if (insp.state === "paused") {
10959
- log37.info("box is paused; unpausing");
11044
+ log36.info("box is paused; unpausing");
10960
11045
  await unpauseBox(box.id);
10961
11046
  } else if (insp.state === "stopped") {
10962
- log37.info("box is stopped; starting");
11047
+ log36.info("box is stopped; starting");
10963
11048
  await startBox(box.id);
10964
11049
  } else if (insp.state === "missing") {
10965
11050
  throw new Error(`box ${box.name} has no container; was it destroyed?`);
@@ -10969,13 +11054,13 @@ var screenCommand = new Command36("screen").description("Open a box's VNC (noVNC
10969
11054
  const inBoxUrl = exposePort !== void 0 ? box.portlessUrl ?? `http://localhost:${String(exposePort)}` : "about:blank";
10970
11055
  const br = await ensureBoxBrowser(box.container, void 0, inBoxUrl);
10971
11056
  if (br.up && !br.alreadyRunning) {
10972
- log37.info(
11057
+ log36.info(
10973
11058
  exposePort !== void 0 ? `opened ${inBoxUrl} in the in-box browser (visible in the VNC view)` : "started in-box browser"
10974
11059
  );
10975
11060
  } else if (br.alreadyRunning) {
10976
- log37.info("in-box browser already running; left it untouched");
11061
+ log36.info("in-box browser already running; left it untouched");
10977
11062
  } else {
10978
- log37.warn(`could not start in-box browser: ${br.reason ?? "unknown"}`);
11063
+ log36.warn(`could not start in-box browser: ${br.reason ?? "unknown"}`);
10979
11064
  }
10980
11065
  const engine = await detectEngine();
10981
11066
  const urls = buildVncUrls(box, engine);
@@ -10996,10 +11081,10 @@ var screenCommand = new Command36("screen").description("Open a box's VNC (noVNC
10996
11081
  const p = await providerForBox(box);
10997
11082
  const state = await p.probeState(box);
10998
11083
  if (state === "paused") {
10999
- log37.info("box is paused; resuming");
11084
+ log36.info("box is paused; resuming");
11000
11085
  await p.resume(box);
11001
11086
  } else if (state === "stopped") {
11002
- log37.info("box is stopped; starting");
11087
+ log36.info("box is stopped; starting");
11003
11088
  await p.start(box);
11004
11089
  } else if (state === "missing") {
11005
11090
  throw new Error(`cloud sandbox for ${box.name} is missing; was it deleted?`);
@@ -11014,14 +11099,14 @@ var screenCommand = new Command36("screen").description("Open a box's VNC (noVNC
11014
11099
  user: "vscode"
11015
11100
  });
11016
11101
  if (br.exitCode === 0) {
11017
- log37.info(`opened ${webUrl} in the in-box browser (visible in the VNC view)`);
11102
+ log36.info(`opened ${webUrl} in the in-box browser (visible in the VNC view)`);
11018
11103
  } else {
11019
- log37.warn(
11104
+ log36.warn(
11020
11105
  `could not open in-box browser (continuing): ${br.stderr.trim() || br.stdout.trim() || `exit ${String(br.exitCode)}`}`
11021
11106
  );
11022
11107
  }
11023
11108
  } catch (err) {
11024
- log37.warn(
11109
+ log36.warn(
11025
11110
  `in-box browser skipped: ${err instanceof Error ? err.message : String(err)}`
11026
11111
  );
11027
11112
  }
@@ -11034,7 +11119,7 @@ var screenCommand = new Command36("screen").description("Open a box's VNC (noVNC
11034
11119
  `);
11035
11120
  return;
11036
11121
  }
11037
- const opened = spawnSync3("open", [url], { stdio: "inherit" });
11122
+ const opened = spawnSync3(hostOpenCommand(), [url], { stdio: "inherit" });
11038
11123
  if (opened.status !== 0) {
11039
11124
  throw new Error(`open ${url} failed (exit ${String(opened.status ?? "n/a")})`);
11040
11125
  }
@@ -11047,18 +11132,18 @@ var screenCommand = new Command36("screen").description("Open a box's VNC (noVNC
11047
11132
 
11048
11133
  // src/commands/shell.ts
11049
11134
  import { spawnSync as spawnSync4 } from "child_process";
11050
- import { log as log39 } from "@clack/prompts";
11135
+ import { log as log38 } from "@clack/prompts";
11051
11136
  import { Command as Command37 } from "commander";
11052
11137
 
11053
11138
  // src/commands/_provider-guard.ts
11054
- import { log as log38 } from "@clack/prompts";
11139
+ import { log as log37 } from "@clack/prompts";
11055
11140
  function requireDockerProvider(box, commandName) {
11056
11141
  const provider = box.provider ?? "docker";
11057
11142
  if (provider === "docker") return;
11058
- log38.error(
11143
+ log37.error(
11059
11144
  `\`agentbox ${commandName}\` doesn't yet support cloud boxes (this box's provider is '${provider}').`
11060
11145
  );
11061
- log38.info(
11146
+ log37.info(
11062
11147
  "Cloud-provider routing for this command is on the Phase 3 backlog. For now: use `agentbox url` for web access, `agentbox-ctl git push` from inside the sandbox via SSH/web terminal, or fall back to the cloud provider's own console."
11063
11148
  );
11064
11149
  process.exit(2);
@@ -11098,10 +11183,10 @@ function fmtAgo2(iso) {
11098
11183
  async function ensureBoxRunning(box) {
11099
11184
  const insp = await inspectBox(box.id);
11100
11185
  if (insp.state === "paused") {
11101
- log39.info("box is paused; unpausing");
11186
+ log38.info("box is paused; unpausing");
11102
11187
  await unpauseBox(box.id);
11103
11188
  } else if (insp.state === "stopped") {
11104
- log39.info("box is stopped; starting");
11189
+ log38.info("box is stopped; starting");
11105
11190
  await startBox(box.id);
11106
11191
  } else if (insp.state === "missing") {
11107
11192
  throw new Error(`box ${box.name} has no container; was it destroyed?`);
@@ -11140,7 +11225,7 @@ async function startOrAttachShell(box, cfg) {
11140
11225
  const label = shellLabel(cfg.sessionName);
11141
11226
  const info = await shellSessionInfo(box.container, cfg.sessionName, cfg.user);
11142
11227
  if (info.running) {
11143
- log39.info(`reattaching to shell "${label}" \u2014 Control+a d to detach`);
11228
+ log38.info(`reattaching to shell "${label}" \u2014 Control+a d to detach`);
11144
11229
  } else {
11145
11230
  await startShellSession({
11146
11231
  container: box.container,
@@ -11148,7 +11233,7 @@ async function startOrAttachShell(box, cfg) {
11148
11233
  user: cfg.user,
11149
11234
  login: cfg.login
11150
11235
  });
11151
- log39.info(`shell "${label}" \u2014 Control+a d to detach, leaves it running`);
11236
+ log38.info(`shell "${label}" \u2014 Control+a d to detach, leaves it running`);
11152
11237
  }
11153
11238
  const code = await runWrappedAttach({
11154
11239
  container: box.container,
@@ -11301,11 +11386,11 @@ var shellLsCommand = new Command37("ls").description("List the shell tmux sessio
11301
11386
  requireDockerProvider(box, "shell");
11302
11387
  const insp = await inspectBox(box.id);
11303
11388
  if (insp.state !== "running") {
11304
- log39.info(`box ${box.name} is ${insp.state} \u2014 no live shell sessions`);
11389
+ log38.info(`box ${box.name} is ${insp.state} \u2014 no live shell sessions`);
11305
11390
  return;
11306
11391
  }
11307
11392
  if (insp.shellSessions.length === 0) {
11308
- log39.info(
11393
+ log38.info(
11309
11394
  `no shell sessions in ${box.name} \u2014 start one with: agentbox shell ${reattachRef4(box)}`
11310
11395
  );
11311
11396
  return;
@@ -11325,25 +11410,25 @@ var shellKillCommand = new Command37("kill").description("Kill a shell tmux sess
11325
11410
  requireDockerProvider(box, "shell");
11326
11411
  const insp = await inspectBox(box.id);
11327
11412
  if (insp.state !== "running") {
11328
- log39.info(`box ${box.name} is ${insp.state} \u2014 no shell sessions to kill`);
11413
+ log38.info(`box ${box.name} is ${insp.state} \u2014 no shell sessions to kill`);
11329
11414
  return;
11330
11415
  }
11331
11416
  if (opts.all) {
11332
11417
  if (insp.shellSessions.length === 0) {
11333
- log39.info(`no shell sessions in ${box.name}`);
11418
+ log38.info(`no shell sessions in ${box.name}`);
11334
11419
  return;
11335
11420
  }
11336
11421
  let killed = 0;
11337
11422
  for (const s of insp.shellSessions) {
11338
11423
  if (await killShellSession(box.container, s.sessionName)) killed++;
11339
11424
  }
11340
- log39.success(`killed ${String(killed)} shell session${killed === 1 ? "" : "s"} in ${box.name}`);
11425
+ log38.success(`killed ${String(killed)} shell session${killed === 1 ? "" : "s"} in ${box.name}`);
11341
11426
  return;
11342
11427
  }
11343
11428
  const target = shellSessionName(opts.name);
11344
11429
  const ok = await killShellSession(box.container, target);
11345
- if (ok) log39.success(`killed shell "${shellLabel(target)}" in ${box.name}`);
11346
- else log39.warn(`no shell "${shellLabel(target)}" in ${box.name} (already gone?)`);
11430
+ if (ok) log38.success(`killed shell "${shellLabel(target)}" in ${box.name}`);
11431
+ else log38.warn(`no shell "${shellLabel(target)}" in ${box.name} (already gone?)`);
11347
11432
  } catch (err) {
11348
11433
  handleLifecycleError(err);
11349
11434
  }
@@ -11377,7 +11462,7 @@ var startCommand = new Command38("start").description(
11377
11462
  });
11378
11463
 
11379
11464
  // src/commands/status.ts
11380
- import { log as log41 } from "@clack/prompts";
11465
+ import { log as log40 } from "@clack/prompts";
11381
11466
  import { Command as Command39 } from "commander";
11382
11467
 
11383
11468
  // src/endpoints-render.ts
@@ -11408,7 +11493,7 @@ function renderEndpointLines(endpoints, stream) {
11408
11493
  }
11409
11494
 
11410
11495
  // src/commands/inspect.ts
11411
- import { log as log40 } from "@clack/prompts";
11496
+ import { log as log39 } from "@clack/prompts";
11412
11497
  function fmtLimit(n, unit) {
11413
11498
  return n && n > 0 ? `${String(n)}${unit}` : "unlimited";
11414
11499
  }
@@ -11553,7 +11638,7 @@ function renderCodexActivityCloud(persisted) {
11553
11638
  async function runInspect(box, opts) {
11554
11639
  try {
11555
11640
  if (opts.json && opts.watch) {
11556
- log40.error("cannot combine --json with --watch");
11641
+ log39.error("cannot combine --json with --watch");
11557
11642
  process.exit(2);
11558
11643
  }
11559
11644
  const isCloud = (box.provider ?? "docker") !== "docker";
@@ -11597,7 +11682,7 @@ var statusCommand2 = withWatchOptions(
11597
11682
  ).action(async (idOrName, opts) => {
11598
11683
  try {
11599
11684
  if (opts.json && opts.watch) {
11600
- log41.error("cannot combine --json with --watch");
11685
+ log40.error("cannot combine --json with --watch");
11601
11686
  process.exit(2);
11602
11687
  }
11603
11688
  const box = await resolveBoxOrExit(idOrName);
@@ -11926,7 +12011,7 @@ var unpauseCommand = new Command42("unpause").description(
11926
12011
 
11927
12012
  // src/commands/update.ts
11928
12013
  import { spawn as spawn4 } from "child_process";
11929
- import { confirm as confirm16, intro as intro8, isCancel as isCancel17, log as log42, outro as outro8, spinner as spinner10 } from "@clack/prompts";
12014
+ import { confirm as confirm16, intro as intro8, isCancel as isCancel17, log as log41, outro as outro7, spinner as spinner10 } from "@clack/prompts";
11930
12015
  import { Command as Command43 } from "commander";
11931
12016
 
11932
12017
  // src/exec-method.ts
@@ -11981,7 +12066,7 @@ var updateCommand = new Command43("self-update").description(
11981
12066
  });
11982
12067
  intro8("agentbox self-update");
11983
12068
  const selfStep = opts.skipSelf ? "self-update: skipped (--skip-self)" : describeSelfUpdate(method);
11984
- log42.info(
12069
+ log41.info(
11985
12070
  [
11986
12071
  "plan:",
11987
12072
  ` ${selfStep}`,
@@ -11990,31 +12075,31 @@ var updateCommand = new Command43("self-update").description(
11990
12075
  ].join("\n")
11991
12076
  );
11992
12077
  if (opts.dryRun) {
11993
- outro8("dry run \u2014 nothing changed");
12078
+ outro7("dry run \u2014 nothing changed");
11994
12079
  return;
11995
12080
  }
11996
12081
  if (!opts.yes) {
11997
12082
  const ok = await confirm16({ message: "Proceed with update?", initialValue: true });
11998
12083
  if (isCancel17(ok) || !ok) {
11999
- log42.info("cancelled");
12084
+ log41.info("cancelled");
12000
12085
  return;
12001
12086
  }
12002
12087
  }
12003
12088
  let selfUpdated = false;
12004
12089
  if (opts.skipSelf) {
12005
- log42.info("skipping self-update (--skip-self)");
12090
+ log41.info("skipping self-update (--skip-self)");
12006
12091
  } else {
12007
12092
  const cmd = selfUpdateCommand(method);
12008
12093
  if (cmd === null) {
12009
- log42.info(describeSelfUpdate(method));
12094
+ log41.info(describeSelfUpdate(method));
12010
12095
  } else {
12011
- log42.info(`running: ${cmd.cmd} ${cmd.args.join(" ")}`);
12096
+ log41.info(`running: ${cmd.cmd} ${cmd.args.join(" ")}`);
12012
12097
  const code = await runInherit(cmd.cmd, cmd.args);
12013
12098
  if (code !== 0) {
12014
12099
  throw new Error(`${cmd.cmd} exited with code ${String(code)}`);
12015
12100
  }
12016
12101
  selfUpdated = true;
12017
- log42.success(`updated ${PKG} via ${cmd.cmd}`);
12102
+ log41.success(`updated ${PKG} via ${cmd.cmd}`);
12018
12103
  }
12019
12104
  }
12020
12105
  const s = spinner10();
@@ -12030,7 +12115,7 @@ var updateCommand = new Command43("self-update").description(
12030
12115
  stop.stopped ? `stopped relay (pid ${String(stop.pid)})` : "relay was not running"
12031
12116
  );
12032
12117
  if (selfUpdated) {
12033
- log42.info(
12118
+ log41.info(
12034
12119
  "relay will restart automatically (with the updated build) on your next `agentbox create` / `agentbox claude`"
12035
12120
  );
12036
12121
  } else {
@@ -12041,12 +12126,12 @@ var updateCommand = new Command43("self-update").description(
12041
12126
  sr2.stop(`relay back up on ${ep.hostUrl}`);
12042
12127
  } catch (err) {
12043
12128
  sr2.stop("relay restart failed");
12044
- log42.warn(
12129
+ log41.warn(
12045
12130
  `${err instanceof Error ? err.message : String(err)} \u2014 it will retry on the next box command`
12046
12131
  );
12047
12132
  }
12048
12133
  }
12049
- outro8("update complete");
12134
+ outro7("update complete");
12050
12135
  } catch (err) {
12051
12136
  handleLifecycleError(err);
12052
12137
  }
@@ -12054,7 +12139,7 @@ var updateCommand = new Command43("self-update").description(
12054
12139
 
12055
12140
  // src/commands/url.ts
12056
12141
  import { spawnSync as spawnSync5 } from "child_process";
12057
- import { log as log43 } from "@clack/prompts";
12142
+ import { log as log42 } from "@clack/prompts";
12058
12143
  import { Command as Command44 } from "commander";
12059
12144
  var SIGNED_URL_TTL_MIN2 = 1;
12060
12145
  var SIGNED_URL_TTL_MAX2 = 86400;
@@ -12087,10 +12172,10 @@ var urlCommand = new Command44("url").description(
12087
12172
  if (provider === "docker") {
12088
12173
  const insp = await inspectBox(box.id);
12089
12174
  if (insp.state === "paused") {
12090
- log43.info("box is paused; unpausing");
12175
+ log42.info("box is paused; unpausing");
12091
12176
  await unpauseBox(box.id);
12092
12177
  } else if (insp.state === "stopped") {
12093
- log43.info("box is stopped; starting");
12178
+ log42.info("box is stopped; starting");
12094
12179
  await startBox(box.id);
12095
12180
  } else if (insp.state === "missing") {
12096
12181
  throw new Error(`box ${box.name} has no container; was it destroyed?`);
@@ -12119,10 +12204,10 @@ var urlCommand = new Command44("url").description(
12119
12204
  const p = await providerForBox(box);
12120
12205
  const state = await p.probeState(box);
12121
12206
  if (state === "paused") {
12122
- log43.info("box is paused; resuming");
12207
+ log42.info("box is paused; resuming");
12123
12208
  await p.resume(box);
12124
12209
  } else if (state === "stopped") {
12125
- log43.info("box is stopped; starting");
12210
+ log42.info("box is stopped; starting");
12126
12211
  await p.start(box);
12127
12212
  } else if (state === "missing") {
12128
12213
  throw new Error(`cloud sandbox for ${box.name} is missing; was it deleted?`);
@@ -12134,7 +12219,7 @@ var urlCommand = new Command44("url").description(
12134
12219
  `);
12135
12220
  return;
12136
12221
  }
12137
- const opened = spawnSync5("open", [url], { stdio: "inherit" });
12222
+ const opened = spawnSync5(hostOpenCommand(), [url], { stdio: "inherit" });
12138
12223
  if (opened.status !== 0) {
12139
12224
  throw new Error(`open ${url} failed (exit ${String(opened.status ?? "n/a")})`);
12140
12225
  }
@@ -12146,7 +12231,7 @@ var urlCommand = new Command44("url").description(
12146
12231
  });
12147
12232
 
12148
12233
  // src/commands/wait.ts
12149
- import { log as log44 } from "@clack/prompts";
12234
+ import { log as log43 } from "@clack/prompts";
12150
12235
  import { Command as Command45 } from "commander";
12151
12236
  var waitCommand = new Command45("wait").description("Block until the box reports all autostart units ready").argument(
12152
12237
  "[box]",
@@ -12164,7 +12249,7 @@ var waitCommand = new Command45("wait").description("Block until the box reports
12164
12249
  try {
12165
12250
  parsed = JSON.parse(proc.stdout);
12166
12251
  } catch {
12167
- log44.error(`agentbox-ctl wait-ready failed: ${proc.stderr || proc.stdout}`);
12252
+ log43.error(`agentbox-ctl wait-ready failed: ${proc.stderr || proc.stdout}`);
12168
12253
  process.exit(1);
12169
12254
  }
12170
12255
  if (opts.json) {