@madarco/agentbox 0.12.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -33,7 +33,7 @@ import {
33
33
  probeCloudCheckpoint,
34
34
  resolveCloudCheckpoint,
35
35
  seedAgentVolumesIfFresh
36
- } from "./chunk-DHJ7OMIP.js";
36
+ } from "./chunk-4NQXNQ53.js";
37
37
  import {
38
38
  ADVANCED_HINT_GROUPS,
39
39
  ALERT_BAND_ROWS,
@@ -64,7 +64,7 @@ import {
64
64
  statusLine,
65
65
  stripTitleGlyph,
66
66
  subscribePrompts
67
- } from "./chunk-HFV6THYG.js";
67
+ } from "./chunk-QYRK5H6Q.js";
68
68
  import {
69
69
  AmbiguousBoxError,
70
70
  BOX_STATUS_EVENT,
@@ -217,7 +217,7 @@ import {
217
217
  waitForTmuxPaneContent,
218
218
  warmUpClaudeCredentials,
219
219
  writeJob
220
- } from "./chunk-IZXPJPPV.js";
220
+ } from "./chunk-B4QG2MCW.js";
221
221
  import {
222
222
  DEFAULT_BOX_IMAGE,
223
223
  STATE_DIR,
@@ -234,11 +234,11 @@ import {
234
234
  import "./chunk-G3H2L3O2.js";
235
235
 
236
236
  // src/version.ts
237
- var AGENTBOX_VERSION = true ? "0.12.0" : "0.0.0-dev";
238
- var AGENTBOX_COMMIT = true ? "9df04087" : "dev";
237
+ var AGENTBOX_VERSION = true ? "0.13.0" : "0.0.0-dev";
238
+ var AGENTBOX_COMMIT = true ? "7a59c0de" : "dev";
239
239
 
240
240
  // src/index.ts
241
- import { Command as Command46 } from "commander";
241
+ import { Command as Command47 } from "commander";
242
242
 
243
243
  // src/engine-override.ts
244
244
  async function applyEngineOverrideAtStartup() {
@@ -912,7 +912,7 @@ async function dirSizeCapped(dir, cap) {
912
912
 
913
913
  // src/lib/carry-resync.ts
914
914
  async function resyncCarryFiles(args) {
915
- const log45 = args.onLog ?? (() => {
915
+ const log46 = args.onLog ?? (() => {
916
916
  });
917
917
  const prior = args.box.carry?.entries ?? [];
918
918
  if (prior.length === 0) return { recopied: 0, skippedNew: 0 };
@@ -920,7 +920,7 @@ async function resyncCarryFiles(args) {
920
920
  if (items.length === 0) return { recopied: 0, skippedNew: 0 };
921
921
  const resolved = await resolveCarry(items, { projectRoot: args.projectRoot });
922
922
  if (resolved.errors.length > 0) {
923
- log45(`carry: resync skipped (resolve errors: ${resolved.errors.length})`);
923
+ log46(`carry: resync skipped (resolve errors: ${resolved.errors.length})`);
924
924
  return { recopied: 0, skippedNew: 0 };
925
925
  }
926
926
  const priorByDest = new Map(prior.map((e) => [e.dest, e]));
@@ -937,7 +937,7 @@ async function resyncCarryFiles(args) {
937
937
  if (hash === void 0 || hash !== existing.hash) changed.push(entry);
938
938
  }
939
939
  if (skippedNew > 0) {
940
- log45(
940
+ log46(
941
941
  `carry: ${String(skippedNew)} new entry/entries not applied on resync \u2014 recreate the box to approve`
942
942
  );
943
943
  }
@@ -945,9 +945,9 @@ async function resyncCarryFiles(args) {
945
945
  const result = await copyCarryPathsToBox({
946
946
  container: args.box.container,
947
947
  entries: changed,
948
- onLog: log45
948
+ onLog: log46
949
949
  });
950
- for (const err of result.errors) log45(`carry: ${err}`);
950
+ for (const err of result.errors) log46(`carry: ${err}`);
951
951
  const updatedByDest = new Map(result.applied.map((e) => [e.dest, e]));
952
952
  const mergedEntries = prior.map((e) => updatedByDest.get(e.dest) ?? e);
953
953
  await recordBox({
@@ -955,7 +955,7 @@ async function resyncCarryFiles(args) {
955
955
  carry: { count: mergedEntries.length, entries: mergedEntries }
956
956
  });
957
957
  if (result.applied.length > 0) {
958
- log45(`carry: re-copied ${String(result.applied.length)} changed file(s)`);
958
+ log46(`carry: re-copied ${String(result.applied.length)} changed file(s)`);
959
959
  }
960
960
  return { recopied: result.applied.length, skippedNew };
961
961
  }
@@ -2056,11 +2056,11 @@ import { basename as basename2 } from "path";
2056
2056
  async function cloudBackendForProvider(provider) {
2057
2057
  switch (provider) {
2058
2058
  case "daytona":
2059
- return (await import("./dist-47LVLYUV.js")).daytonaBackend;
2059
+ return (await import("./dist-OPIBZ7XM.js")).daytonaBackend;
2060
2060
  case "hetzner":
2061
- return (await import("./dist-SWUOU34W.js")).hetznerBackend;
2061
+ return (await import("./dist-7KVUIKJX.js")).hetznerBackend;
2062
2062
  case "vercel":
2063
- return (await import("./dist-24PY2ZMO.js")).vercelBackend;
2063
+ return (await import("./dist-JAN5VABY.js")).vercelBackend;
2064
2064
  default:
2065
2065
  return null;
2066
2066
  }
@@ -3177,11 +3177,11 @@ var CLOUD_BACKENDS = ["daytona", "hetzner", "vercel"];
3177
3177
  async function cloudProviderFor(backend) {
3178
3178
  switch (backend) {
3179
3179
  case "daytona":
3180
- return (await import("./dist-47LVLYUV.js")).daytonaProvider;
3180
+ return (await import("./dist-OPIBZ7XM.js")).daytonaProvider;
3181
3181
  case "hetzner":
3182
- return (await import("./dist-SWUOU34W.js")).hetznerProvider;
3182
+ return (await import("./dist-7KVUIKJX.js")).hetznerProvider;
3183
3183
  case "vercel":
3184
- return (await import("./dist-24PY2ZMO.js")).vercelProvider;
3184
+ return (await import("./dist-JAN5VABY.js")).vercelProvider;
3185
3185
  }
3186
3186
  }
3187
3187
  var CHECKPOINT_NOTICE = "Checkpoint in progress \u2014 the box will be unresponsive for a moment";
@@ -5916,7 +5916,7 @@ var createCommand = new Command9("create").description(
5916
5916
  }
5917
5917
  outro4("done");
5918
5918
  if (attachClaudeAfter) {
5919
- const { cloudAgentAttach: cloudAgentAttach2 } = await import("./_cloud-attach-XKO4SHR3.js");
5919
+ const { cloudAgentAttach: cloudAgentAttach2 } = await import("./_cloud-attach-HJC672UR.js");
5920
5920
  await cloudAgentAttach2({
5921
5921
  box: result.record,
5922
5922
  binary: "claude",
@@ -6107,9 +6107,8 @@ var InputParser = class {
6107
6107
  else if (c === "c") this.onEvent({ type: "action", name: "code" });
6108
6108
  else if (c === "t") this.onEvent({ type: "action", name: "stop" });
6109
6109
  else if (c === "p") this.onEvent({ type: "action", name: "pause" });
6110
- else if (c === "d") this.onEvent({ type: "action", name: "destroy" });
6110
+ else if (c === "k") this.onEvent({ type: "action", name: "destroy" });
6111
6111
  else if (c === "q") this.onEvent({ type: "quit" });
6112
- else if (c === "k") this.onEvent({ type: "switch", dir: "prev" });
6113
6112
  else if (c === "j" || c === "n" || c === "N") this.onEvent({ type: "switch", dir: "next" });
6114
6113
  else {
6115
6114
  this.fwd.push(b);
@@ -9219,19 +9218,19 @@ var forkCommand = new Command23("fork").description(
9219
9218
  });
9220
9219
 
9221
9220
  // src/commands/install.ts
9222
- import { confirm as confirm14, intro as intro6, isCancel as isCancel15, log as log30, note as note2, outro as outro5, select as select2, spinner as spinner8 } from "@clack/prompts";
9223
- import { Command as Command25 } from "commander";
9221
+ import { confirm as confirm14, intro as intro7, isCancel as isCancel15, log as log31, note as note3, outro as outro6, select as select2, spinner as spinner8 } from "@clack/prompts";
9222
+ import { Command as Command26 } from "commander";
9224
9223
  import {
9225
- existsSync as existsSync7,
9224
+ existsSync as existsSync8,
9226
9225
  lstatSync,
9227
- mkdirSync as mkdirSync5,
9228
- readFileSync,
9226
+ mkdirSync as mkdirSync6,
9227
+ readFileSync as readFileSync2,
9229
9228
  rmSync,
9230
9229
  symlinkSync as symlinkSync2,
9231
- writeFileSync as writeFileSync4
9230
+ writeFileSync as writeFileSync5
9232
9231
  } from "fs";
9233
- import { homedir as homedir15 } from "os";
9234
- import { dirname as dirname2, join as join17, resolve as resolve3, sep } from "path";
9232
+ import { homedir as homedir16 } from "os";
9233
+ import { dirname as dirname3, join as join18, resolve as resolve3, sep } from "path";
9235
9234
  import { fileURLToPath } from "url";
9236
9235
 
9237
9236
  // src/lib/doctor-checks.ts
@@ -9357,7 +9356,7 @@ async function dockerChecks() {
9357
9356
  ];
9358
9357
  }
9359
9358
  const daemonRes = { label: "docker daemon", status: "ok", detail: "reachable" };
9360
- const mod = await import("./dist-RZZSSUNB.js");
9359
+ const mod = await import("./dist-OG6NW6SM.js");
9361
9360
  let imgRes;
9362
9361
  try {
9363
9362
  const img = await mod.imageInfo(mod.DEFAULT_BOX_IMAGE);
@@ -9388,7 +9387,7 @@ async function dockerChecks() {
9388
9387
  }
9389
9388
  async function daytonaChecks() {
9390
9389
  try {
9391
- const mod = await import("./dist-47LVLYUV.js");
9390
+ const mod = await import("./dist-OPIBZ7XM.js");
9392
9391
  const status = await mod.getDaytonaStatus();
9393
9392
  if (!status.configured) {
9394
9393
  return [
@@ -9424,7 +9423,7 @@ async function daytonaChecks() {
9424
9423
  }
9425
9424
  async function hetznerChecks() {
9426
9425
  try {
9427
- const mod = await import("./dist-SWUOU34W.js");
9426
+ const mod = await import("./dist-7KVUIKJX.js");
9428
9427
  const cred = mod.readHetznerCredStatus();
9429
9428
  const credRes = cred.source === "none" ? {
9430
9429
  label: "credentials",
@@ -9456,7 +9455,7 @@ async function hetznerChecks() {
9456
9455
  }
9457
9456
  async function vercelChecks() {
9458
9457
  try {
9459
- const mod = await import("./dist-24PY2ZMO.js");
9458
+ const mod = await import("./dist-JAN5VABY.js");
9460
9459
  const cred = mod.readVercelCredStatus();
9461
9460
  const credRes = cred.auth === "none" ? {
9462
9461
  label: "credentials",
@@ -9603,9 +9602,92 @@ function markSetupComplete(provider) {
9603
9602
  writeFileSync3(path, JSON.stringify(body, null, 2) + "\n");
9604
9603
  }
9605
9604
 
9606
- // src/commands/prepare.ts
9607
- import { intro as intro5, log as log29, spinner as spinner7 } from "@clack/prompts";
9605
+ // src/commands/install-cmux.ts
9606
+ import { intro as intro5, log as log29, note as note2, outro as outro5 } from "@clack/prompts";
9608
9607
  import { Command as Command24 } from "commander";
9608
+ import { existsSync as existsSync7, mkdirSync as mkdirSync5, readFileSync, renameSync as renameSync2, writeFileSync as writeFileSync4 } from "fs";
9609
+ import { homedir as homedir15 } from "os";
9610
+ import { dirname as dirname2, join as join17 } from "path";
9611
+ var CONTROL_ID = "agentbox";
9612
+ function cmuxDockPath(env = process.env) {
9613
+ const xdg = env["XDG_CONFIG_HOME"];
9614
+ const base = xdg && xdg.length > 0 ? xdg : join17(homedir15(), ".config");
9615
+ return join17(base, "cmux", "dock.json");
9616
+ }
9617
+ function upsertAgentboxControl(doc, opts) {
9618
+ const controls = Array.isArray(doc.controls) ? doc.controls : [];
9619
+ const next = {
9620
+ id: CONTROL_ID,
9621
+ title: opts.title,
9622
+ command: opts.command,
9623
+ height: opts.height
9624
+ };
9625
+ const idx = controls.findIndex((c) => c && c.id === CONTROL_ID);
9626
+ const merged = idx >= 0 ? controls.map((c, i) => i === idx ? { ...c, ...next } : c) : [...controls, next];
9627
+ return { ...doc, controls: merged };
9628
+ }
9629
+ function parseHeight(raw) {
9630
+ const n = Number(raw);
9631
+ if (!Number.isFinite(n) || n <= 0) return 320;
9632
+ return Math.round(n);
9633
+ }
9634
+ var installCmuxCommand = new Command24("cmux").description(
9635
+ "Add an AgentBox panel to the cmux sidebar dock (~/.config/cmux/dock.json) showing the live list of all your boxes."
9636
+ ).option("--height <points>", "panel height in points", "320").option("--title <text>", "panel title shown in the dock header", "AgentBox").option("--dry-run", "print the resulting dock.json without writing it").option("--force", "reset a dock.json that fails to parse (backed up to dock.json.bak)").action((opts) => {
9637
+ const dockPath = cmuxDockPath();
9638
+ const command = `agentbox list --cmux --watch`;
9639
+ const controlOpts = {
9640
+ command,
9641
+ title: opts.title ?? "AgentBox",
9642
+ height: parseHeight(opts.height)
9643
+ };
9644
+ let doc = { controls: [] };
9645
+ if (existsSync7(dockPath)) {
9646
+ const raw = readFileSync(dockPath, "utf8");
9647
+ try {
9648
+ const parsed = JSON.parse(raw);
9649
+ if (parsed && typeof parsed === "object") doc = parsed;
9650
+ } catch {
9651
+ if (!opts.force) {
9652
+ log29.error(
9653
+ `existing dock config is not valid JSON: ${dockPath}
9654
+ fix it by hand, or pass --force to back it up and write a fresh one`
9655
+ );
9656
+ process.exit(1);
9657
+ }
9658
+ if (!opts.dryRun) {
9659
+ renameSync2(dockPath, dockPath + ".bak");
9660
+ log29.warn(`backed up unparseable dock config to ${dockPath}.bak`);
9661
+ }
9662
+ doc = { controls: [] };
9663
+ }
9664
+ }
9665
+ const updated = upsertAgentboxControl(doc, controlOpts);
9666
+ const json = JSON.stringify(updated, null, 2) + "\n";
9667
+ if (opts.dryRun) {
9668
+ intro5("agentbox install cmux (dry run)");
9669
+ process.stdout.write(json);
9670
+ outro5(`would write ${dockPath}`);
9671
+ return;
9672
+ }
9673
+ mkdirSync5(dirname2(dockPath), { recursive: true });
9674
+ writeFileSync4(dockPath, json);
9675
+ intro5("AgentBox cmux dock panel");
9676
+ note2(
9677
+ `Wrote ${dockPath}
9678
+ Panel command: ${command}
9679
+
9680
+ To see it:
9681
+ 1. Enable Dock in cmux Settings -> Beta features -> Dock (it is off by default).
9682
+ 2. Open the right sidebar and switch it to the Dock tab.`,
9683
+ "Installed"
9684
+ );
9685
+ outro5("done");
9686
+ });
9687
+
9688
+ // src/commands/prepare.ts
9689
+ import { intro as intro6, log as log30, spinner as spinner7 } from "@clack/prompts";
9690
+ import { Command as Command25 } from "commander";
9609
9691
  async function dockerStatus() {
9610
9692
  let img;
9611
9693
  try {
@@ -9667,7 +9749,7 @@ async function renderDocker(status) {
9667
9749
  }
9668
9750
  async function daytonaStatus() {
9669
9751
  try {
9670
- const mod = await import("./dist-47LVLYUV.js");
9752
+ const mod = await import("./dist-OPIBZ7XM.js");
9671
9753
  return await mod.getDaytonaStatus();
9672
9754
  } catch (err) {
9673
9755
  return {
@@ -9741,7 +9823,7 @@ async function runPrepare(providerName, opts = {}) {
9741
9823
  }
9742
9824
  const provider = await getProvider(providerName);
9743
9825
  if (typeof provider.prepare !== "function") {
9744
- log29.error(`provider '${providerName}' does not implement prepare`);
9826
+ log30.error(`provider '${providerName}' does not implement prepare`);
9745
9827
  process.exit(1);
9746
9828
  }
9747
9829
  const cwd = opts.cwd ?? process.cwd();
@@ -9762,10 +9844,10 @@ async function runPrepare(providerName, opts = {}) {
9762
9844
  const configKey = boxImageConfigKey(providerName);
9763
9845
  try {
9764
9846
  const written = await setConfigValue("project", configKey, result.snapshotName, cwd);
9765
- log29.success(`${configKey} = ${result.snapshotName} (written to ${written.path})`);
9847
+ log30.success(`${configKey} = ${result.snapshotName} (written to ${written.path})`);
9766
9848
  } catch (err) {
9767
9849
  const msg = err instanceof Error ? err.message : String(err);
9768
- log29.warn(
9850
+ log30.warn(
9769
9851
  `prepared snapshot '${result.snapshotName}', but failed to pin it into the project config: ${msg}
9770
9852
  Run \`agentbox config set --project ${configKey} ${result.snapshotName}\` manually.`
9771
9853
  );
@@ -9779,21 +9861,21 @@ Run \`agentbox config set --project ${configKey} ${result.snapshotName}\` manual
9779
9861
  if (typeof projectImage === "string" && projectImage.length > 0 && projectImage !== DEFAULT_BOX_IMAGE) {
9780
9862
  const cleared = await unsetConfigValue("project", "box.image", cwd);
9781
9863
  if (cleared.existed) {
9782
- log29.warn(
9864
+ log30.warn(
9783
9865
  `migrated stale \`box.image\` from a previous prepare (was \`${projectImage}\`); re-set manually if you actually meant it: \`agentbox config set --project box.image <ref>\``
9784
9866
  );
9785
9867
  }
9786
9868
  }
9787
9869
  } catch (err) {
9788
9870
  const msg = err instanceof Error ? err.message : String(err);
9789
- log29.warn(`could not migrate stale box.image (continuing): ${msg}`);
9871
+ log30.warn(`could not migrate stale box.image (continuing): ${msg}`);
9790
9872
  }
9791
9873
  if (!opts.suppressStatus) {
9792
9874
  process.stdout.write("\n");
9793
9875
  await showStatus({ onlyProvider: providerName });
9794
9876
  }
9795
9877
  if (!opts.suppressTip) {
9796
- log29.info(
9878
+ log30.info(
9797
9879
  "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"
9798
9880
  );
9799
9881
  }
@@ -9802,7 +9884,7 @@ Run \`agentbox config set --project ${configKey} ${result.snapshotName}\` manual
9802
9884
  throw err;
9803
9885
  }
9804
9886
  }
9805
- var prepareCommand = new Command24("prepare").description(
9887
+ var prepareCommand = new Command25("prepare").description(
9806
9888
  "Build base sandbox images / snapshots, or show what is already prepared across providers."
9807
9889
  ).option(
9808
9890
  "-p, --provider <name>",
@@ -9816,7 +9898,7 @@ var prepareCommand = new Command24("prepare").description(
9816
9898
  return;
9817
9899
  }
9818
9900
  const providerName = opts.provider.trim();
9819
- intro5(`preparing ${providerName} base image`);
9901
+ intro6(`preparing ${providerName} base image`);
9820
9902
  await runPrepare(providerName, {
9821
9903
  name: opts.name,
9822
9904
  force: opts.force,
@@ -9925,34 +10007,34 @@ ${LOGO_L2}\x1B[0m` + SYNC_END2);
9925
10007
  }
9926
10008
  var LEGACY_INFO_MARKER = "Drive AgentBox from the host:";
9927
10009
  function installTargets() {
9928
- const home = homedir15();
9929
- const claudeSkills = join17(home, ".claude", "skills");
10010
+ const home = homedir16();
10011
+ const claudeSkills = join18(home, ".claude", "skills");
9930
10012
  return [
9931
- { src: join17("agentbox", "SKILL.md"), dest: join17(claudeSkills, "agentbox", "SKILL.md") },
10013
+ { src: join18("agentbox", "SKILL.md"), dest: join18(claudeSkills, "agentbox", "SKILL.md") },
9932
10014
  {
9933
- src: join17("agentbox-info", "SKILL.md"),
9934
- dest: join17(claudeSkills, "agentbox-info", "SKILL.md")
10015
+ src: join18("agentbox-info", "SKILL.md"),
10016
+ dest: join18(claudeSkills, "agentbox-info", "SKILL.md")
9935
10017
  },
9936
10018
  {
9937
- src: join17("codex", "agentbox.md"),
9938
- dest: join17(home, ".codex", "prompts", "agentbox.md"),
9939
- gateDir: join17(home, ".codex")
10019
+ src: join18("codex", "agentbox.md"),
10020
+ dest: join18(home, ".codex", "prompts", "agentbox.md"),
10021
+ gateDir: join18(home, ".codex")
9940
10022
  },
9941
10023
  {
9942
- src: join17("opencode", "agentbox.md"),
9943
- dest: join17(home, ".config", "opencode", "commands", "agentbox.md"),
9944
- gateDir: join17(home, ".config", "opencode")
10024
+ src: join18("opencode", "agentbox.md"),
10025
+ dest: join18(home, ".config", "opencode", "commands", "agentbox.md"),
10026
+ gateDir: join18(home, ".config", "opencode")
9945
10027
  }
9946
10028
  ];
9947
10029
  }
9948
10030
  function resolveHostSkillsDir() {
9949
- const here = dirname2(fileURLToPath(import.meta.url));
10031
+ const here = dirname3(fileURLToPath(import.meta.url));
9950
10032
  const candidates = [
9951
10033
  resolve3(here, "..", "share", "host-skills"),
9952
10034
  resolve3(here, "..", "..", "share", "host-skills")
9953
10035
  ];
9954
10036
  for (const c of candidates) {
9955
- if (existsSync7(c)) return c;
10037
+ if (existsSync8(c)) return c;
9956
10038
  }
9957
10039
  throw new Error(`could not locate bundled host skills; tried:
9958
10040
  ${candidates.join("\n ")}`);
@@ -9968,11 +10050,11 @@ function isSourceCheckout(srcDir) {
9968
10050
  return !srcDir.split(sep).includes("node_modules");
9969
10051
  }
9970
10052
  function writableReason(target, force) {
9971
- if (!existsSync7(target)) {
10053
+ if (!existsSync8(target)) {
9972
10054
  if (isSymlink(target)) return "managed";
9973
10055
  return "new";
9974
10056
  }
9975
- const existing = readFileSync(target, "utf8");
10057
+ const existing = readFileSync2(target, "utf8");
9976
10058
  if (existing.includes(MANAGED_SENTINEL) || existing.includes(LEGACY_INFO_MARKER)) {
9977
10059
  return "managed";
9978
10060
  }
@@ -9988,32 +10070,32 @@ function installHostSkills(opts = {}) {
9988
10070
  const blocked = [];
9989
10071
  let skipped = 0;
9990
10072
  for (const t of installTargets()) {
9991
- const src = join17(srcDir, t.src);
9992
- if (!existsSync7(src)) {
9993
- if (!quiet) log30.warn(`bundled file missing (skipped): ${src}`);
10073
+ const src = join18(srcDir, t.src);
10074
+ if (!existsSync8(src)) {
10075
+ if (!quiet) log31.warn(`bundled file missing (skipped): ${src}`);
9994
10076
  skipped++;
9995
10077
  continue;
9996
10078
  }
9997
- if (t.gateDir && !existsSync7(t.gateDir)) continue;
10079
+ if (t.gateDir && !existsSync8(t.gateDir)) continue;
9998
10080
  const reason = writableReason(t.dest, force);
9999
10081
  if (reason === "skip") {
10000
- if (!quiet) log30.warn(`user-modified file at ${t.dest}, skipping; pass --force to overwrite`);
10082
+ if (!quiet) log31.warn(`user-modified file at ${t.dest}, skipping; pass --force to overwrite`);
10001
10083
  blocked.push(t.dest);
10002
10084
  skipped++;
10003
10085
  continue;
10004
10086
  }
10005
10087
  if (dryRun) {
10006
- if (!quiet) log30.info(`would ${link ? "link" : "write"} ${t.dest} (${reason})`);
10088
+ if (!quiet) log31.info(`would ${link ? "link" : "write"} ${t.dest} (${reason})`);
10007
10089
  written.push(t.dest);
10008
10090
  continue;
10009
10091
  }
10010
- mkdirSync5(dirname2(t.dest), { recursive: true });
10092
+ mkdirSync6(dirname3(t.dest), { recursive: true });
10011
10093
  if (link) {
10012
10094
  rmSync(t.dest, { force: true });
10013
10095
  symlinkSync2(resolve3(srcDir, t.src), t.dest);
10014
10096
  } else {
10015
10097
  if (isSymlink(t.dest)) rmSync(t.dest, { force: true });
10016
- writeFileSync4(t.dest, readFileSync(src, "utf8"));
10098
+ writeFileSync5(t.dest, readFileSync2(src, "utf8"));
10017
10099
  }
10018
10100
  written.push(t.dest);
10019
10101
  }
@@ -10041,10 +10123,10 @@ function ensureTty() {
10041
10123
  async function runProviderLogin(name) {
10042
10124
  if (name === "docker") return true;
10043
10125
  if (name === "daytona") {
10044
- const mod2 = await import("./dist-47LVLYUV.js");
10126
+ const mod2 = await import("./dist-OPIBZ7XM.js");
10045
10127
  const status2 = await mod2.getDaytonaStatus();
10046
10128
  if (status2.configured) {
10047
- log30.info("daytona: already configured");
10129
+ log31.info("daytona: already configured");
10048
10130
  const rotate = await confirm14({ message: "Re-authenticate Daytona?", initialValue: false });
10049
10131
  if (isCancel15(rotate)) return false;
10050
10132
  if (rotate) await mod2.ensureDaytonaCredentials({ force: true });
@@ -10054,10 +10136,10 @@ async function runProviderLogin(name) {
10054
10136
  return true;
10055
10137
  }
10056
10138
  if (name === "hetzner") {
10057
- const mod2 = await import("./dist-SWUOU34W.js");
10139
+ const mod2 = await import("./dist-7KVUIKJX.js");
10058
10140
  const status2 = mod2.readHetznerCredStatus();
10059
10141
  if (status2.source !== "none") {
10060
- log30.info("hetzner: already configured");
10142
+ log31.info("hetzner: already configured");
10061
10143
  const rotate = await confirm14({ message: "Re-authenticate Hetzner?", initialValue: false });
10062
10144
  if (isCancel15(rotate)) return false;
10063
10145
  if (rotate) await mod2.ensureHetznerCredentials({ force: true });
@@ -10066,10 +10148,10 @@ async function runProviderLogin(name) {
10066
10148
  await mod2.ensureHetznerCredentials();
10067
10149
  return true;
10068
10150
  }
10069
- const mod = await import("./dist-24PY2ZMO.js");
10151
+ const mod = await import("./dist-JAN5VABY.js");
10070
10152
  const status = mod.readVercelCredStatus();
10071
10153
  if (status.auth !== "none") {
10072
- log30.info(`vercel: already configured (${status.auth})`);
10154
+ log31.info(`vercel: already configured (${status.auth})`);
10073
10155
  const rotate = await confirm14({ message: "Re-authenticate Vercel?", initialValue: false });
10074
10156
  if (isCancel15(rotate)) return false;
10075
10157
  if (rotate) await mod.ensureVercelCredentials({ force: true });
@@ -10094,17 +10176,17 @@ function isProviderName(s) {
10094
10176
  async function runInstallWizard(opts = {}) {
10095
10177
  if (!ensureTty()) return false;
10096
10178
  await animateBanner();
10097
- intro6("Check system compatibility");
10179
+ intro7("Check system compatibility");
10098
10180
  const sysResults = await runSystemChecks();
10099
10181
  const sysGroup = { title: "system", results: sysResults };
10100
10182
  process.stdout.write(" " + formatCompact([sysGroup]) + "\n");
10101
10183
  const hardFail = sysResults.find((r) => r.status === "fail");
10102
10184
  if (hardFail) {
10103
- log30.error(`system check failed: ${hardFail.label} \u2014 ${hardFail.detail}`);
10104
- log30.info("run `agentbox doctor` for full detail");
10185
+ log31.error(`system check failed: ${hardFail.label} \u2014 ${hardFail.detail}`);
10186
+ log31.info("run `agentbox doctor` for full detail");
10105
10187
  const cont = await confirm14({ message: "Continue anyway?", initialValue: false });
10106
10188
  if (isCancel15(cont) || !cont) {
10107
- outro5("aborted");
10189
+ outro6("aborted");
10108
10190
  return false;
10109
10191
  }
10110
10192
  }
@@ -10112,7 +10194,7 @@ async function runInstallWizard(opts = {}) {
10112
10194
  if (opts.provider) {
10113
10195
  const candidate = opts.provider.trim();
10114
10196
  if (!isProviderName(candidate)) {
10115
- log30.error(`unknown --provider: ${candidate}`);
10197
+ log31.error(`unknown --provider: ${candidate}`);
10116
10198
  return false;
10117
10199
  }
10118
10200
  providerName = candidate;
@@ -10127,7 +10209,7 @@ async function runInstallWizard(opts = {}) {
10127
10209
  }))
10128
10210
  });
10129
10211
  if (isCancel15(picked)) {
10130
- outro5("cancelled");
10212
+ outro6("cancelled");
10131
10213
  return false;
10132
10214
  }
10133
10215
  providerName = picked;
@@ -10135,14 +10217,14 @@ async function runInstallWizard(opts = {}) {
10135
10217
  if (providerName !== "docker") {
10136
10218
  const loggedIn = await runProviderLogin(providerName);
10137
10219
  if (!loggedIn) {
10138
- outro5("cancelled");
10220
+ outro6("cancelled");
10139
10221
  return false;
10140
10222
  }
10141
10223
  }
10142
10224
  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)`;
10143
10225
  const wantPrepare = opts.yes ? true : await confirm14({ message: prepareMsg, initialValue: true });
10144
10226
  if (isCancel15(wantPrepare)) {
10145
- outro5("cancelled");
10227
+ outro6("cancelled");
10146
10228
  return false;
10147
10229
  }
10148
10230
  if (wantPrepare) {
@@ -10154,12 +10236,12 @@ async function runInstallWizard(opts = {}) {
10154
10236
  suppressTip: true
10155
10237
  });
10156
10238
  } catch (err) {
10157
- log30.warn(
10239
+ log31.warn(
10158
10240
  `prepare failed: ${err instanceof Error ? err.message : String(err)} \u2014 you can rerun \`agentbox prepare --provider ${providerName}\` later`
10159
10241
  );
10160
10242
  }
10161
10243
  } else {
10162
- log30.info(
10244
+ log31.info(
10163
10245
  `skipped \u2014 the ${providerName} base will build lazily on first \`agentbox ${providerName === "docker" ? "" : providerName + " "}create\``
10164
10246
  );
10165
10247
  }
@@ -10174,25 +10256,25 @@ async function runInstallWizard(opts = {}) {
10174
10256
  sp.stop(`Agentbox Skills: nothing to write (${String(skillRes.skipped)} skipped)`);
10175
10257
  }
10176
10258
  if (skillRes.blocked.length > 0) {
10177
- log30.warn(
10259
+ log31.warn(
10178
10260
  `user-modified host skill file(s) left in place: ${skillRes.blocked.join(", ")}
10179
10261
  pass \`agentbox install --skills-only --force\` to overwrite`
10180
10262
  );
10181
10263
  }
10182
10264
  } catch (err) {
10183
10265
  sp.stop("Agentbox Skills: failed");
10184
- log30.warn(err instanceof Error ? err.message : String(err));
10266
+ log31.warn(err instanceof Error ? err.message : String(err));
10185
10267
  }
10186
10268
  markSetupComplete(providerName);
10187
10269
  const providerGroup = await runProviderChecks(providerName);
10188
10270
  process.stdout.write(" " + formatCompact([sysGroup, providerGroup]) + "\n");
10189
- note2(tutorialBody(providerName), "Next steps");
10190
- outro5(
10271
+ note3(tutorialBody(providerName), "Next steps");
10272
+ outro6(
10191
10273
  opts.fromAutoTrigger ? "\u2728 Setup complete \u2014 continuing with your command\u2026" : "\u2728 Setup complete"
10192
10274
  );
10193
10275
  return true;
10194
10276
  }
10195
- var installCommand = new Command25("install").description(
10277
+ var installCommand = new Command26("install").description(
10196
10278
  "Interactive setup wizard: system check, pick a provider, log in, prepare its base image/snapshot, and install the host /agentbox skill. `--skills-only` runs just the skill install."
10197
10279
  ).option(
10198
10280
  "--skills-only",
@@ -10202,25 +10284,25 @@ var installCommand = new Command25("install").description(
10202
10284
  "pre-select the provider to set up (docker | daytona | hetzner | vercel)"
10203
10285
  ).option("-y, --yes", "auto-confirm the prepare step").action(async (opts) => {
10204
10286
  if (opts.skillsOnly) {
10205
- intro6("Installing AgentBox host commands...");
10287
+ intro7("Installing AgentBox host commands...");
10206
10288
  let res;
10207
10289
  try {
10208
10290
  res = installHostSkills({ force: opts.force, dryRun: opts.dryRun });
10209
10291
  } catch (err) {
10210
- log30.error(err instanceof Error ? err.message : String(err));
10292
+ log31.error(err instanceof Error ? err.message : String(err));
10211
10293
  process.exit(1);
10212
10294
  }
10213
10295
  if (opts.dryRun) {
10214
- outro5(
10296
+ outro6(
10215
10297
  `dry-run: ${String(res.written.length)} file(s) would be written, ${String(res.skipped)} skipped`
10216
10298
  );
10217
10299
  return;
10218
10300
  }
10219
10301
  if (res.written.length === 0) {
10220
- outro5(`nothing installed (${String(res.skipped)} skipped)`);
10302
+ outro6(`nothing installed (${String(res.skipped)} skipped)`);
10221
10303
  return;
10222
10304
  }
10223
- outro5(`installed: ${res.written.join(", ")}`);
10305
+ outro6(`installed: ${res.written.join(", ")}`);
10224
10306
  return;
10225
10307
  }
10226
10308
  const ok = await runInstallWizard({
@@ -10231,10 +10313,12 @@ var installCommand = new Command25("install").description(
10231
10313
  });
10232
10314
  if (!ok) process.exit(1);
10233
10315
  });
10316
+ installCommand.enablePositionalOptions();
10317
+ installCommand.addCommand(installCmuxCommand);
10234
10318
 
10235
10319
  // src/commands/doctor.ts
10236
- import { Command as Command26 } from "commander";
10237
- var doctorCommand = new Command26("doctor").description(
10320
+ import { Command as Command27 } from "commander";
10321
+ var doctorCommand = new Command27("doctor").description(
10238
10322
  "Diagnose system compatibility and provider readiness (Node, git, ssh, Docker daemon, provider credentials, prepared snapshots)."
10239
10323
  ).option(
10240
10324
  "-p, --provider <name>",
@@ -10274,7 +10358,7 @@ var doctorCommand = new Command26("doctor").description(
10274
10358
  });
10275
10359
 
10276
10360
  // src/commands/git.ts
10277
- import { Command as Command27 } from "commander";
10361
+ import { Command as Command28 } from "commander";
10278
10362
  var WORKSPACE = "/workspace";
10279
10363
  var TOKEN_TTL_MS = 12e4;
10280
10364
  async function runInBox(box, argv2) {
@@ -10306,7 +10390,7 @@ function buildPredictedGhPrParams(ghArgs) {
10306
10390
  async function exitWith(code) {
10307
10391
  process.exit(code);
10308
10392
  }
10309
- var pushCommand = new Command27("push").description("Push the box's branch via the host relay (host creds, no prompt)").argument("<box>", "box ref: project index, id, id prefix, name, or container").argument("[args...]", "extra flags forwarded to `agentbox-ctl git push` (e.g. --force-with-lease, --tags)").option("--remote <name>", "remote name (default: origin)").allowExcessArguments(true).allowUnknownOption(true).action(async (boxRef, args, opts) => {
10393
+ var pushCommand = new Command28("push").description("Push the box's branch via the host relay (host creds, no prompt)").argument("<box>", "box ref: project index, id, id prefix, name, or container").argument("[args...]", "extra flags forwarded to `agentbox-ctl git push` (e.g. --force-with-lease, --tags)").option("--remote <name>", "remote name (default: origin)").allowExcessArguments(true).allowUnknownOption(true).action(async (boxRef, args, opts) => {
10310
10394
  try {
10311
10395
  const box = await resolveBoxOrExit(boxRef);
10312
10396
  const predicted = buildPredictedGitParams(opts.remote, args);
@@ -10319,7 +10403,7 @@ var pushCommand = new Command27("push").description("Push the box's branch via t
10319
10403
  handleLifecycleError(err);
10320
10404
  }
10321
10405
  });
10322
- var fetchCommand = new Command27("fetch").description("Fetch via the host relay (refs land in the shared .git)").argument("<box>", "box ref").argument("[args...]", "extra flags forwarded to `agentbox-ctl git fetch` (e.g. --prune)").option("--remote <name>", "remote name (default: origin)").allowExcessArguments(true).allowUnknownOption(true).action(async (boxRef, args, opts) => {
10406
+ var fetchCommand = new Command28("fetch").description("Fetch via the host relay (refs land in the shared .git)").argument("<box>", "box ref").argument("[args...]", "extra flags forwarded to `agentbox-ctl git fetch` (e.g. --prune)").option("--remote <name>", "remote name (default: origin)").allowExcessArguments(true).allowUnknownOption(true).action(async (boxRef, args, opts) => {
10323
10407
  try {
10324
10408
  const box = await resolveBoxOrExit(boxRef);
10325
10409
  const predicted = buildPredictedGitParams(opts.remote, args);
@@ -10332,7 +10416,7 @@ var fetchCommand = new Command27("fetch").description("Fetch via the host relay
10332
10416
  handleLifecycleError(err);
10333
10417
  }
10334
10418
  });
10335
- var pullCommand = new Command27("pull").description(
10419
+ var pullCommand = new Command28("pull").description(
10336
10420
  "Fetch via the relay then merge in /workspace. With <branch>: first `git checkout <branch>` so the box switches base branch and pulls latest \u2014 useful for reusing a box on a new task."
10337
10421
  ).argument("<box>", "box ref").argument("[branch]", "optional branch to switch to before pulling (e.g. main)").argument("[args...]", "extra flags forwarded to `agentbox-ctl git pull`").option("--remote <name>", "remote name (default: origin)").option("--ff-only", "pass --ff-only to the in-box merge").allowExcessArguments(true).allowUnknownOption(true).action(
10338
10422
  async (boxRef, branch, args, opts) => {
@@ -10354,7 +10438,7 @@ var pullCommand = new Command27("pull").description(
10354
10438
  }
10355
10439
  }
10356
10440
  );
10357
- var checkoutCommand = new Command27("checkout").description("Change the box's working branch (runs `git checkout <branch>` in /workspace)").argument("<box>", "box ref").argument("<branch>", "branch to check out inside the box").argument("[args...]", "extra flags forwarded to `git checkout`").allowExcessArguments(true).allowUnknownOption(true).action(async (boxRef, branch, args) => {
10441
+ var checkoutCommand = new Command28("checkout").description("Change the box's working branch (runs `git checkout <branch>` in /workspace)").argument("<box>", "box ref").argument("<branch>", "branch to check out inside the box").argument("[args...]", "extra flags forwarded to `git checkout`").allowExcessArguments(true).allowUnknownOption(true).action(async (boxRef, branch, args) => {
10358
10442
  try {
10359
10443
  const box = await resolveBoxOrExit(boxRef);
10360
10444
  await exitWith(await runAndStream(box, ["git", "checkout", branch, ...args]));
@@ -10362,7 +10446,7 @@ var checkoutCommand = new Command27("checkout").description("Change the box's wo
10362
10446
  handleLifecycleError(err);
10363
10447
  }
10364
10448
  });
10365
- var statusCommand = new Command27("status").description("Run `git status` in the box's /workspace (read-only, no relay)").argument("<box>", "box ref").argument("[args...]", "extra flags forwarded to `git status`").allowExcessArguments(true).allowUnknownOption(true).action(async (boxRef, args) => {
10449
+ var statusCommand = new Command28("status").description("Run `git status` in the box's /workspace (read-only, no relay)").argument("<box>", "box ref").argument("[args...]", "extra flags forwarded to `git status`").allowExcessArguments(true).allowUnknownOption(true).action(async (boxRef, args) => {
10366
10450
  try {
10367
10451
  const box = await resolveBoxOrExit(boxRef);
10368
10452
  await exitWith(await runAndStream(box, ["git", "status", ...args]));
@@ -10388,7 +10472,7 @@ function injectPrCreateHead2(op, box, args) {
10388
10472
  return injectPrCreateHead(op, rootWt?.branch, args);
10389
10473
  }
10390
10474
  function buildPrSubcommand(op) {
10391
- return new Command27(op).description(PR_OP_DESCRIPTIONS[op]).argument("<box>", "box ref").argument(
10475
+ return new Command28(op).description(PR_OP_DESCRIPTIONS[op]).argument("<box>", "box ref").argument(
10392
10476
  "[args...]",
10393
10477
  "extra flags forwarded to `gh pr <op>` (e.g. --title, --body, --label, --draft, --json)"
10394
10478
  ).allowExcessArguments(true).allowUnknownOption(true).action(async (boxRef, args) => {
@@ -10404,18 +10488,18 @@ function buildPrSubcommand(op) {
10404
10488
  }
10405
10489
  });
10406
10490
  }
10407
- var prCommand = new Command27("pr").description(
10491
+ var prCommand = new Command28("pr").description(
10408
10492
  "PR operations against a box's branch via the host `gh` CLI"
10409
10493
  );
10410
10494
  for (const op of GH_PR_OPS) {
10411
10495
  const sub = buildPrSubcommand(op);
10412
10496
  prCommand.addCommand(sub, op === "create" ? { isDefault: true } : void 0);
10413
10497
  }
10414
- 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);
10498
+ var gitCommand = new Command28("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);
10415
10499
 
10416
10500
  // src/commands/list.ts
10417
- import { log as log31 } from "@clack/prompts";
10418
- import { Command as Command28 } from "commander";
10501
+ import { log as log32 } from "@clack/prompts";
10502
+ import { Command as Command29 } from "commander";
10419
10503
  import { pathToFileURL } from "url";
10420
10504
 
10421
10505
  // src/hyperlink.ts
@@ -10469,13 +10553,56 @@ function parseIntervalMs(raw) {
10469
10553
  if (!Number.isFinite(n) || n <= 0) return 2e3;
10470
10554
  return Math.max(250, Math.round(n * 1e3));
10471
10555
  }
10472
- async function watchRender(produce, rawInterval) {
10556
+ async function watchRender(produce, rawInterval, opts = {}) {
10473
10557
  const ms = parseIntervalMs(rawInterval);
10474
10558
  const intervalLabel = `${String(ms / 1e3)}s`;
10475
10559
  process.stdout.write("\x1B[?25l");
10476
- process.once("exit", () => process.stdout.write("\x1B[?25h"));
10477
- process.once("SIGINT", () => process.exit(0));
10478
- const sleep5 = (d) => new Promise((r) => setTimeout(r, d));
10560
+ const stdin = process.stdin;
10561
+ const interactive = typeof opts.onKey === "function" && stdin.isTTY === true;
10562
+ const restore = () => {
10563
+ if (interactive && stdin.isTTY) stdin.setRawMode(false);
10564
+ process.stdout.write("\x1B[?25h");
10565
+ };
10566
+ process.once("exit", restore);
10567
+ let wake = null;
10568
+ let exiting = false;
10569
+ const exit = () => {
10570
+ exiting = true;
10571
+ wake?.();
10572
+ };
10573
+ if (interactive) {
10574
+ stdin.setRawMode(true);
10575
+ stdin.resume();
10576
+ stdin.setEncoding("utf8");
10577
+ stdin.on("data", (chunk) => {
10578
+ for (const key of chunk) {
10579
+ if (key === "" || key === "q") {
10580
+ exit();
10581
+ return;
10582
+ }
10583
+ const action = opts.onKey?.(key) ?? "ignore";
10584
+ if (action === "exit") {
10585
+ exit();
10586
+ return;
10587
+ }
10588
+ if (action === "redraw") wake?.();
10589
+ }
10590
+ });
10591
+ } else {
10592
+ process.once("SIGINT", () => process.exit(0));
10593
+ }
10594
+ const hint = interactive ? "q or Ctrl-C to exit" : "Ctrl-C to exit";
10595
+ const sleep5 = (d) => new Promise((r) => {
10596
+ const t = setTimeout(() => {
10597
+ wake = null;
10598
+ r();
10599
+ }, d);
10600
+ wake = () => {
10601
+ clearTimeout(t);
10602
+ wake = null;
10603
+ r();
10604
+ };
10605
+ });
10479
10606
  for (; ; ) {
10480
10607
  let body;
10481
10608
  try {
@@ -10484,14 +10611,23 @@ async function watchRender(produce, rawInterval) {
10484
10611
  body = `error: ${err instanceof Error ? err.message : String(err)}`;
10485
10612
  }
10486
10613
  const ts = (/* @__PURE__ */ new Date()).toLocaleTimeString();
10487
- process.stdout.write("\x1B[2J\x1B[3J\x1B[H");
10488
- process.stdout.write(
10489
- `watching every ${intervalLabel} \u2014 ${ts} \u2014 Ctrl-C to exit
10614
+ const trimmed = body.replace(/\n+$/, "");
10615
+ if (opts.hideStatusLine) {
10616
+ process.stdout.write(
10617
+ "\x1B[H" + trimmed.split("\n").map((l) => l + "\x1B[K").join("\n") + "\x1B[J"
10618
+ );
10619
+ } else {
10620
+ process.stdout.write("\x1B[2J\x1B[3J\x1B[H");
10621
+ process.stdout.write(`watching every ${intervalLabel} \u2014 ${ts} \u2014 ${hint}
10490
10622
 
10491
- ${body.replace(/\n+$/, "")}
10492
- `
10493
- );
10623
+ ${trimmed}
10624
+ `);
10625
+ }
10494
10626
  await sleep5(ms);
10627
+ if (exiting) {
10628
+ restore();
10629
+ process.exit(0);
10630
+ }
10495
10631
  }
10496
10632
  }
10497
10633
 
@@ -10556,6 +10692,102 @@ function agentSummary(b) {
10556
10692
  if (b.opencodeSession?.running) agents.push("opencode");
10557
10693
  return agents.length > 0 ? agents.join(", ") : "-";
10558
10694
  }
10695
+ var CMUX_COLOR = {
10696
+ blue: "38;5;39",
10697
+ amber: "38;5;214",
10698
+ red: "38;5;196",
10699
+ dim: "38;5;245"
10700
+ };
10701
+ function colorize(s, bucket) {
10702
+ return `\x1B[${CMUX_COLOR[bucket]}m${s}\x1B[0m`;
10703
+ }
10704
+ function tailKeep(s, max) {
10705
+ if (max <= 0) return "";
10706
+ if (s.length <= max) return s;
10707
+ if (max === 1) return "\u2026";
10708
+ return "\u2026" + s.slice(s.length - (max - 1));
10709
+ }
10710
+ function primaryAgent(b) {
10711
+ const real = (s) => !!s && s !== "unknown";
10712
+ if (real(b.claudeActivity) || b.claudeSessionTitle) {
10713
+ return { agent: "claude", activity: b.claudeActivity };
10714
+ }
10715
+ if (b.codexSession?.running || real(b.codexActivity)) {
10716
+ return { agent: "codex", activity: b.codexActivity };
10717
+ }
10718
+ if (b.opencodeSession?.running) return { agent: "opencode" };
10719
+ return { agent: "claude", activity: b.claudeActivity };
10720
+ }
10721
+ function activityView(a) {
10722
+ switch (a) {
10723
+ case "working":
10724
+ return { glyph: "\u25CF", label: "working", bucket: "blue" };
10725
+ case "compacting":
10726
+ return { glyph: "\u25CF", label: "compacting", bucket: "blue" };
10727
+ case "idle":
10728
+ return { glyph: "\u25CB", label: "idle", bucket: "dim" };
10729
+ case "waiting":
10730
+ case "question":
10731
+ return { glyph: "\u25D0", label: "needs input", bucket: "amber" };
10732
+ case "end-plan":
10733
+ return { glyph: "\u25D0", label: "plan ready", bucket: "amber" };
10734
+ case "error":
10735
+ return { glyph: "\u2716", label: "error", bucket: "red" };
10736
+ default:
10737
+ return { glyph: "\u25CB", label: "", bucket: "dim" };
10738
+ }
10739
+ }
10740
+ function cmuxStatusCell(b, color) {
10741
+ if (b.state !== "running") {
10742
+ const s = `[${b.state}]`;
10743
+ return color ? colorize(s, "dim") : s;
10744
+ }
10745
+ const { agent, activity } = primaryAgent(b);
10746
+ const v = activityView(activity);
10747
+ const text = `${v.glyph} ${agent ?? "agent"}${v.label ? " " + v.label : ""}`;
10748
+ return color ? colorize(text, v.bucket) : text;
10749
+ }
10750
+ function projectLabel(root) {
10751
+ if (!root) return "other";
10752
+ return root.split("/").filter(Boolean).pop() ?? root;
10753
+ }
10754
+ function projectHeader(label, color, width) {
10755
+ const max = Math.max(1, width - 6);
10756
+ const name = label.length > max ? label.slice(0, Math.max(1, max - 1)) + "\u2026" : label;
10757
+ const h = `\u2500\u2500 ${name} \u2500\u2500`;
10758
+ return color ? colorize(h, "dim") : h;
10759
+ }
10760
+ function renderCmuxRows(boxes, color, width) {
10761
+ const groups = /* @__PURE__ */ new Map();
10762
+ for (const b of boxes) {
10763
+ const key = b.projectRoot ?? "";
10764
+ const arr = groups.get(key);
10765
+ if (arr) arr.push(b);
10766
+ else groups.set(key, [b]);
10767
+ }
10768
+ const lines = [];
10769
+ let first = true;
10770
+ for (const [root, group] of groups) {
10771
+ if (!first) lines.push("");
10772
+ first = false;
10773
+ lines.push(projectHeader(projectLabel(root), color, width));
10774
+ for (const b of group) {
10775
+ const idx = b.projectIndex ? `${String(b.projectIndex)} ` : "";
10776
+ lines.push(`${idx}${tailKeep(b.name, Math.max(1, width - idx.length))}`);
10777
+ lines.push(" " + cmuxStatusCell(b, color));
10778
+ }
10779
+ }
10780
+ return lines.join("\n");
10781
+ }
10782
+ function cmuxEmptyMessage() {
10783
+ return "no boxes \xB7 agentbox create";
10784
+ }
10785
+ async function buildCmuxText(live, color) {
10786
+ const { boxes } = await scopedBoxes(true, live);
10787
+ if (boxes.length === 0) return cmuxEmptyMessage();
10788
+ const width = process.stdout.columns ?? 30;
10789
+ return renderCmuxRows(boxes, color, width);
10790
+ }
10559
10791
  function renderTable(boxes, stream) {
10560
10792
  const header = ["N", "NAME", "STATE", "AGENT", "SHELLS", "PROVIDER", "URL", "WORKSPACE"];
10561
10793
  const wsCol = header.length - 1;
@@ -10623,19 +10855,43 @@ async function buildListText(all, live) {
10623
10855
  ${table}`;
10624
10856
  }
10625
10857
  var listCommand2 = withWatchOptions(
10626
- new Command28("list").alias("ls").description("List agent boxes in the current project (-g for all)").option("-j, --json", "machine-readable JSON output").option("-g, --global", "include boxes from all projects").option(
10858
+ new Command29("list").alias("ls").description("List agent boxes in the current project (-g for all)").option("-j, --json", "machine-readable JSON output").option("-g, --global", "include boxes from all projects").option(
10627
10859
  "--live",
10628
10860
  "probe live cloud state via the provider SDK (slower; default: last host-known state)"
10629
- )
10861
+ ).option("--cmux", "compact output for the cmux dock sidebar (narrow, 2 lines per box)")
10630
10862
  ).action(async (opts) => {
10631
10863
  if (opts.json && opts.watch) {
10632
- log31.error("cannot combine --json with --watch");
10864
+ log32.error("cannot combine --json with --watch");
10633
10865
  process.exit(2);
10634
10866
  }
10635
10867
  const all = opts.global ?? false;
10636
10868
  const live = opts.live ?? false;
10869
+ if (opts.cmux) {
10870
+ const color = !!process.stdout.isTTY && !process.env.NO_COLOR;
10871
+ if (opts.watch) {
10872
+ await watchRender(() => buildCmuxText(live, color), opts.interval, { hideStatusLine: true });
10873
+ return;
10874
+ }
10875
+ process.stdout.write(await buildCmuxText(live, color) + "\n");
10876
+ return;
10877
+ }
10637
10878
  if (opts.watch) {
10638
- await watchRender(() => buildListText(all, live), opts.interval);
10879
+ let scoped2 = all;
10880
+ const checkbox = () => `[${scoped2 ? "x" : " "}] all projects \xB7 press g to toggle
10881
+ `;
10882
+ await watchRender(
10883
+ async () => checkbox() + await buildListText(scoped2, live),
10884
+ opts.interval,
10885
+ {
10886
+ onKey: (k) => {
10887
+ if (k === "g") {
10888
+ scoped2 = !scoped2;
10889
+ return "redraw";
10890
+ }
10891
+ return "ignore";
10892
+ }
10893
+ }
10894
+ );
10639
10895
  return;
10640
10896
  }
10641
10897
  if (opts.json) {
@@ -10647,11 +10903,11 @@ var listCommand2 = withWatchOptions(
10647
10903
  });
10648
10904
 
10649
10905
  // src/commands/logs.ts
10650
- import { log as log32 } from "@clack/prompts";
10651
- import { Command as Command29 } from "commander";
10906
+ import { log as log33 } from "@clack/prompts";
10907
+ import { Command as Command30 } from "commander";
10652
10908
  import { spawn as spawn3 } from "child_process";
10653
10909
  var DAEMON_LOG_PATH = "/var/log/agentbox/ctl-daemon.log";
10654
- var logsCommand = new Command29("logs").description("Print recent log lines from a box service; -f to stream").argument(
10910
+ var logsCommand = new Command30("logs").description("Print recent log lines from a box service; -f to stream").argument(
10655
10911
  "[box]",
10656
10912
  "box ref (optional when cwd has exactly 1 box): project index, id, id prefix, name, or container"
10657
10913
  ).argument("[service]", "service name from agentbox.yaml").option("-n, --tail <n>", "how many recent lines to print first", "200").option("-f, --follow", "keep the connection open and stream new lines").option(
@@ -10669,9 +10925,9 @@ var logsCommand = new Command29("logs").description("Print recent log lines from
10669
10925
  service = boxArg;
10670
10926
  }
10671
10927
  if (!service && !opts.daemon) {
10672
- log32.error("missing <service> argument");
10673
- log32.info("usage: agentbox logs [box] <service> [-n N] [-f]");
10674
- log32.info(" agentbox logs [box] --daemon [-n N] [-f]");
10928
+ log33.error("missing <service> argument");
10929
+ log33.info("usage: agentbox logs [box] <service> [-n N] [-f]");
10930
+ log33.info(" agentbox logs [box] --daemon [-n N] [-f]");
10675
10931
  process.exit(2);
10676
10932
  }
10677
10933
  const box = await resolveBoxOrExit(idOrName);
@@ -10682,7 +10938,7 @@ var logsCommand = new Command29("logs").description("Print recent log lines from
10682
10938
  if (!opts.follow) {
10683
10939
  const proc = await provider.exec(box, args, { user: "vscode" });
10684
10940
  if (proc.exitCode !== 0) {
10685
- log32.error(
10941
+ log33.error(
10686
10942
  `${opts.daemon ? "daemon log" : "agentbox-ctl logs"} failed: ${proc.stderr || proc.stdout}`
10687
10943
  );
10688
10944
  process.exit(1);
@@ -10738,12 +10994,12 @@ var logsCommand = new Command29("logs").description("Print recent log lines from
10738
10994
  });
10739
10995
 
10740
10996
  // src/commands/open.ts
10741
- import { log as log33 } from "@clack/prompts";
10997
+ import { log as log34 } from "@clack/prompts";
10742
10998
  import { execa as execa3 } from "execa";
10743
- import { existsSync as existsSync8, mkdirSync as mkdirSync6 } from "fs";
10744
- import { homedir as homedir16 } from "os";
10745
- import { join as join18 } from "path";
10746
- import { Command as Command30 } from "commander";
10999
+ import { existsSync as existsSync9, mkdirSync as mkdirSync7 } from "fs";
11000
+ import { homedir as homedir17 } from "os";
11001
+ import { join as join19 } from "path";
11002
+ import { Command as Command31 } from "commander";
10747
11003
 
10748
11004
  // src/commands/path.ts
10749
11005
  async function runPath(box, opts) {
@@ -10765,7 +11021,7 @@ async function runPath(box, opts) {
10765
11021
  }
10766
11022
 
10767
11023
  // src/commands/open.ts
10768
- var openCommand = new Command30("open").description("Open a box's /workspace in Finder (docker: rsync'd snapshot; cloud: sshfs mount)").argument(
11024
+ var openCommand = new Command31("open").description("Open a box's /workspace in Finder (docker: rsync'd snapshot; cloud: sshfs mount)").argument(
10769
11025
  "[box]",
10770
11026
  "box ref: project index, id, id prefix, name, or container (default: the only box in this project)"
10771
11027
  ).option("--no-refresh", "skip the rsync; open whatever's already on disk (docker only)").option(
@@ -10804,7 +11060,7 @@ var openCommand = new Command30("open").description("Open a box's /workspace in
10804
11060
  }
10805
11061
  });
10806
11062
  async function runCloudOpen(box, provider, opts) {
10807
- const mountRoot = join18(homedir16(), ".agentbox", "mounts", box.name);
11063
+ const mountRoot = join19(homedir17(), ".agentbox", "mounts", box.name);
10808
11064
  if (opts.unmount) {
10809
11065
  const ok = await tryUnmount(mountRoot);
10810
11066
  if (ok) process.stdout.write(`unmounted ${mountRoot}
@@ -10841,13 +11097,13 @@ async function runCloudOpen(box, provider, opts) {
10841
11097
  user: target.user,
10842
11098
  identityFile: target.identityFile
10843
11099
  });
10844
- if (!existsSync8(mountRoot)) {
10845
- mkdirSync6(mountRoot, { recursive: true, mode: 493 });
11100
+ if (!existsSync9(mountRoot)) {
11101
+ mkdirSync7(mountRoot, { recursive: true, mode: 493 });
10846
11102
  } else if (await isMounted(mountRoot)) {
10847
- log33.info(`re-mounting (stale mount detected at ${mountRoot})`);
11103
+ log34.info(`re-mounting (stale mount detected at ${mountRoot})`);
10848
11104
  await tryUnmount(mountRoot);
10849
11105
  }
10850
- log33.info(`mounting ${alias}:/workspace at ${mountRoot}`);
11106
+ log34.info(`mounting ${alias}:/workspace at ${mountRoot}`);
10851
11107
  const mount = await execa3(
10852
11108
  sshfsBin,
10853
11109
  [
@@ -10894,8 +11150,8 @@ async function tryUnmount(path) {
10894
11150
  }
10895
11151
 
10896
11152
  // src/commands/pause.ts
10897
- import { Command as Command31 } from "commander";
10898
- var pauseCommand = new Command31("pause").description(
11153
+ import { Command as Command32 } from "commander";
11154
+ var pauseCommand = new Command32("pause").description(
10899
11155
  "Pause a box. Docker: `docker pause` (cgroup freeze \u2014 sub-second resume). Cloud: backend.pause (Daytona archive \u2014 cold storage; resume is slower but uses no quota while archived)."
10900
11156
  ).argument(
10901
11157
  "[box]",
@@ -10918,8 +11174,8 @@ var pauseCommand = new Command31("pause").description(
10918
11174
  });
10919
11175
 
10920
11176
  // src/commands/prune.ts
10921
- import { confirm as confirm15, isCancel as isCancel16, log as log34 } from "@clack/prompts";
10922
- import { Command as Command32 } from "commander";
11177
+ import { confirm as confirm15, isCancel as isCancel16, log as log35 } from "@clack/prompts";
11178
+ import { Command as Command33 } from "commander";
10923
11179
  function totalRemovals(r, projectConfigs) {
10924
11180
  return r.removedRecords.length + r.removedContainers.length + r.removedVolumes.length + r.removedSnapshotDirs.length + r.removedBoxDirs.length + projectConfigs.length;
10925
11181
  }
@@ -10965,7 +11221,7 @@ async function liveProjectRoots() {
10965
11221
  return [];
10966
11222
  }
10967
11223
  }
10968
- var pruneCommand = new Command32("prune").description("Clean up orphan state.json records (and with --all, orphan docker resources)").option("--dry-run", "show what would be removed, don't change anything").option(
11224
+ var pruneCommand = new Command33("prune").description("Clean up orphan state.json records (and with --all, orphan docker resources)").option("--dry-run", "show what would be removed, don't change anything").option(
10969
11225
  "--all",
10970
11226
  "also remove orphan agentbox-* containers, volumes, snapshot dirs, and orphan per-project config dirs"
10971
11227
  ).option("-y, --yes", "skip the confirmation prompt").option(
@@ -10978,7 +11234,7 @@ var pruneCommand = new Command32("prune").description("Clean up orphan state.jso
10978
11234
  return;
10979
11235
  }
10980
11236
  if (opts.provider !== void 0 && opts.provider !== "docker") {
10981
- log34.error(`unknown provider '${opts.provider}'; expected docker, daytona, hetzner, or vercel`);
11237
+ log35.error(`unknown provider '${opts.provider}'; expected docker, daytona, hetzner, or vercel`);
10982
11238
  process.exit(2);
10983
11239
  }
10984
11240
  const dryRun = opts.dryRun ?? false;
@@ -10991,13 +11247,13 @@ var pruneCommand = new Command32("prune").description("Clean up orphan state.jso
10991
11247
  process.stdout.write("nothing to prune\n");
10992
11248
  return;
10993
11249
  }
10994
- log34.info(`would remove:
11250
+ log35.info(`would remove:
10995
11251
  ${summary(preview, previewProjects)}`);
10996
11252
  if (dryRun) return;
10997
11253
  if (!opts.yes) {
10998
11254
  const ok = await confirm15({ message: "Proceed with prune?", initialValue: true });
10999
11255
  if (isCancel16(ok) || !ok) {
11000
- log34.info("cancelled");
11256
+ log35.info("cancelled");
11001
11257
  return;
11002
11258
  }
11003
11259
  }
@@ -11018,7 +11274,7 @@ async function pruneCloud(provider, opts) {
11018
11274
  const dryRun = opts.dryRun ?? false;
11019
11275
  const backend = await cloudBackendForProvider(provider);
11020
11276
  if (!backend.list) {
11021
- log34.error(`${provider} backend doesn't expose \`list()\`; cannot enumerate sandboxes for prune`);
11277
+ log35.error(`${provider} backend doesn't expose \`list()\`; cannot enumerate sandboxes for prune`);
11022
11278
  process.exit(2);
11023
11279
  }
11024
11280
  const [remote, state] = await Promise.all([backend.list(), readState()]);
@@ -11038,7 +11294,7 @@ async function pruneCloud(provider, opts) {
11038
11294
  `);
11039
11295
  return;
11040
11296
  }
11041
- log34.info(`found ${String(orphans.length)} ${provider} sandbox(es) not in this CLI's state:`);
11297
+ log35.info(`found ${String(orphans.length)} ${provider} sandbox(es) not in this CLI's state:`);
11042
11298
  for (const sb of orphans) {
11043
11299
  const parts = [sb.sandboxId];
11044
11300
  if (sb.name) parts.push(sb.name);
@@ -11054,7 +11310,7 @@ async function pruneCloud(provider, opts) {
11054
11310
  initialValue: false
11055
11311
  });
11056
11312
  if (isCancel16(ok) || !ok) {
11057
- log34.info("cancelled");
11313
+ log35.info("cancelled");
11058
11314
  return;
11059
11315
  }
11060
11316
  }
@@ -11066,7 +11322,7 @@ async function pruneCloud(provider, opts) {
11066
11322
  deleted++;
11067
11323
  } catch (err) {
11068
11324
  failed++;
11069
- log34.warn(
11325
+ log35.warn(
11070
11326
  `delete ${sb.sandboxId} failed: ${err instanceof Error ? err.message : String(err)}`
11071
11327
  );
11072
11328
  }
@@ -11079,17 +11335,17 @@ async function pruneCloud(provider, opts) {
11079
11335
 
11080
11336
  // src/commands/queue.ts
11081
11337
  import { readFile as readFile5, stat as stat5 } from "fs/promises";
11082
- import { intro as intro7, log as log35, outro as outro6 } from "@clack/prompts";
11083
- import { Command as Command33 } from "commander";
11338
+ import { intro as intro8, log as log36, outro as outro7 } from "@clack/prompts";
11339
+ import { Command as Command34 } from "commander";
11084
11340
  var TERMINAL_STATUSES = /* @__PURE__ */ new Set(["done", "failed", "cancelled"]);
11085
- var queueCommand = new Command33("queue").description("Inspect and manage background `agentbox claude|codex|opencode -i` jobs");
11086
- var queueListCommand = new Command33("list").description("List queued, running, and (with --all) terminal background jobs").option("--all", "include done/failed/cancelled jobs (default: hide terminal)").action(async (opts) => {
11341
+ var queueCommand = new Command34("queue").description("Inspect and manage background `agentbox claude|codex|opencode -i` jobs");
11342
+ var queueListCommand = new Command34("list").description("List queued, running, and (with --all) terminal background jobs").option("--all", "include done/failed/cancelled jobs (default: hide terminal)").action(async (opts) => {
11087
11343
  const jobs = await loadQueue();
11088
11344
  const cfg = await loadQueueConfig();
11089
11345
  const visible = opts.all === true ? jobs : jobs.filter((j) => !TERMINAL_STATUSES.has(j.status));
11090
11346
  if (visible.length === 0) {
11091
- log35.info(opts.all ? "no queued jobs." : "no active queued jobs (--all to see terminal).");
11092
- log35.info(`queue.maxConcurrent = ${String(cfg.maxConcurrent)} (queue.enabled=${String(cfg.enabled)})`);
11347
+ log36.info(opts.all ? "no queued jobs." : "no active queued jobs (--all to see terminal).");
11348
+ log36.info(`queue.maxConcurrent = ${String(cfg.maxConcurrent)} (queue.enabled=${String(cfg.enabled)})`);
11093
11349
  return;
11094
11350
  }
11095
11351
  const rows = visible.map((j) => ({
@@ -11114,12 +11370,12 @@ var queueListCommand = new Command33("list").description("List queued, running,
11114
11370
  headers.map((h, i) => pad4(String(r[h]), widths[i])).join(" ") + "\n"
11115
11371
  );
11116
11372
  }
11117
- log35.info(`queue.maxConcurrent = ${String(cfg.maxConcurrent)} (queue.enabled=${String(cfg.enabled)})`);
11373
+ log36.info(`queue.maxConcurrent = ${String(cfg.maxConcurrent)} (queue.enabled=${String(cfg.enabled)})`);
11118
11374
  });
11119
- 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) => {
11375
+ var queueShowCommand = new Command34("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) => {
11120
11376
  const job = await readJob(id);
11121
11377
  if (!job) {
11122
- log35.error(`no job with id ${id}`);
11378
+ log36.error(`no job with id ${id}`);
11123
11379
  process.exit(1);
11124
11380
  }
11125
11381
  process.stdout.write(JSON.stringify(job, null, 2) + "\n");
@@ -11135,18 +11391,18 @@ var queueShowCommand = new Command33("show").description("Dump a job manifest an
11135
11391
  process.stdout.write(slice.join("\n"));
11136
11392
  if (!slice.join("\n").endsWith("\n")) process.stdout.write("\n");
11137
11393
  } catch {
11138
- log35.info(`(no log at ${job.logPath} yet)`);
11394
+ log36.info(`(no log at ${job.logPath} yet)`);
11139
11395
  }
11140
11396
  });
11141
- 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) => {
11142
- intro7(`Cancelling queue job ${id}...`);
11397
+ var queueCancelCommand = new Command34("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) => {
11398
+ intro8(`Cancelling queue job ${id}...`);
11143
11399
  const job = await readJob(id);
11144
11400
  if (!job) {
11145
- log35.error(`no job with id ${id}`);
11401
+ log36.error(`no job with id ${id}`);
11146
11402
  process.exit(1);
11147
11403
  }
11148
11404
  if (job.status !== "queued") {
11149
- log35.error(
11405
+ log36.error(
11150
11406
  `job ${id} is ${job.status}; cancel only flips 'queued' \u2192 'cancelled'.` + (job.status === "running" ? ` Use 'agentbox destroy ${job.boxName || id}' to stop the box.` : "")
11151
11407
  );
11152
11408
  process.exit(1);
@@ -11158,15 +11414,15 @@ var queueCancelCommand = new Command33("cancel").description("Cancel a queued jo
11158
11414
  reason: "cancelled by user"
11159
11415
  };
11160
11416
  await writeJob(cancelled);
11161
- outro6(`job ${id} cancelled`);
11417
+ outro7(`job ${id} cancelled`);
11162
11418
  });
11163
- 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) => {
11419
+ var queueClearCommand = new Command34("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) => {
11164
11420
  const targets = /* @__PURE__ */ new Set();
11165
11421
  if (opts.all === true || opts.done === true) targets.add("done");
11166
11422
  if (opts.all === true || opts.failed === true) targets.add("failed");
11167
11423
  if (opts.all === true || opts.cancelled === true) targets.add("cancelled");
11168
11424
  if (targets.size === 0) {
11169
- log35.error("pick at least one of: --done, --failed, --cancelled, --all");
11425
+ log36.error("pick at least one of: --done, --failed, --cancelled, --all");
11170
11426
  process.exit(2);
11171
11427
  }
11172
11428
  const jobs = await loadQueue();
@@ -11176,7 +11432,7 @@ var queueClearCommand = new Command33("clear").description("Sweep terminal-state
11176
11432
  await deleteJob(j.id);
11177
11433
  removed += 1;
11178
11434
  }
11179
- log35.success(`removed ${String(removed)} manifest${removed === 1 ? "" : "s"}`);
11435
+ log36.success(`removed ${String(removed)} manifest${removed === 1 ? "" : "s"}`);
11180
11436
  });
11181
11437
  var QUEUE_WAIT_EVENTS = [
11182
11438
  "new-box",
@@ -11189,11 +11445,11 @@ var QUEUE_WAIT_EVENTS = [
11189
11445
  var ACTIVE_JOB_STATUSES = /* @__PURE__ */ new Set(["queued", "running"]);
11190
11446
  var DEFAULT_QUEUE_WAIT_TIMEOUT_MS = 10 * 60 * 1e3;
11191
11447
  var QUEUE_POLL_INTERVAL_MS = 500;
11192
- var queueWaitForCommand = new Command33("wait-for").description(
11448
+ var queueWaitForCommand = new Command34("wait-for").description(
11193
11449
  `Block until a queue / box event fires. <event> one of: ${QUEUE_WAIT_EVENTS.join(" | ")}.`
11194
11450
  ).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) => {
11195
11451
  if (!QUEUE_WAIT_EVENTS.includes(eventRaw)) {
11196
- log35.error(`unknown event '${eventRaw}' (one of: ${QUEUE_WAIT_EVENTS.join(", ")})`);
11452
+ log36.error(`unknown event '${eventRaw}' (one of: ${QUEUE_WAIT_EVENTS.join(", ")})`);
11197
11453
  process.exit(2);
11198
11454
  }
11199
11455
  const event = eventRaw;
@@ -11213,11 +11469,11 @@ var queueWaitForCommand = new Command33("wait-for").description(
11213
11469
  if (opts.json === true) {
11214
11470
  process.stdout.write(JSON.stringify({ matched: false, event, elapsedMs }) + "\n");
11215
11471
  } else {
11216
- log35.error(`'${event}' did not occur within ${String(timeoutMs)}ms`);
11472
+ log36.error(`'${event}' did not occur within ${String(timeoutMs)}ms`);
11217
11473
  }
11218
11474
  process.exit(1);
11219
11475
  }
11220
- log35.error(err instanceof Error ? err.message : String(err));
11476
+ log36.error(err instanceof Error ? err.message : String(err));
11221
11477
  process.exit(1);
11222
11478
  }
11223
11479
  });
@@ -11314,8 +11570,8 @@ function truncate(s, max) {
11314
11570
  }
11315
11571
 
11316
11572
  // src/commands/relay.ts
11317
- import { log as log36, spinner as spinner9 } from "@clack/prompts";
11318
- import { Command as Command34 } from "commander";
11573
+ import { log as log37, spinner as spinner9 } from "@clack/prompts";
11574
+ import { Command as Command35 } from "commander";
11319
11575
  async function rehydrateFromState() {
11320
11576
  const state = await readState();
11321
11577
  await rehydrateRelayRegistry(
@@ -11357,7 +11613,7 @@ function renderStatus(s) {
11357
11613
  }
11358
11614
  return ["relay: not running", ` log: ${s.logFile}`].join("\n");
11359
11615
  }
11360
- var statusSub = new Command34("status").description("Show whether the host relay is running, with pid / port / box count").option("--json", "emit RelayStatus as JSON").action(async (opts) => {
11616
+ var statusSub = new Command35("status").description("Show whether the host relay is running, with pid / port / box count").option("--json", "emit RelayStatus as JSON").action(async (opts) => {
11361
11617
  try {
11362
11618
  const s = await getRelayStatus();
11363
11619
  if (opts.json) {
@@ -11369,7 +11625,7 @@ var statusSub = new Command34("status").description("Show whether the host relay
11369
11625
  handleLifecycleError(err);
11370
11626
  }
11371
11627
  });
11372
- var stopSub = new Command34("stop").description("Stop the host relay process (idempotent)").action(async () => {
11628
+ var stopSub = new Command35("stop").description("Stop the host relay process (idempotent)").action(async () => {
11373
11629
  try {
11374
11630
  const s = spinner9();
11375
11631
  s.start("stopping relay");
@@ -11381,7 +11637,7 @@ var stopSub = new Command34("stop").description("Stop the host relay process (id
11381
11637
  handleLifecycleError(err);
11382
11638
  }
11383
11639
  });
11384
- var startSub = new Command34("start").description("Start the host relay if not already running (idempotent)").action(async () => {
11640
+ var startSub = new Command35("start").description("Start the host relay if not already running (idempotent)").action(async () => {
11385
11641
  try {
11386
11642
  const s = spinner9();
11387
11643
  s.start("starting relay");
@@ -11392,7 +11648,7 @@ var startSub = new Command34("start").description("Start the host relay if not a
11392
11648
  handleLifecycleError(err);
11393
11649
  }
11394
11650
  });
11395
- var restartSub = new Command34("restart").description("Stop then start the host relay").action(async () => {
11651
+ var restartSub = new Command35("restart").description("Stop then start the host relay").action(async () => {
11396
11652
  try {
11397
11653
  const s = spinner9();
11398
11654
  s.start("stopping relay");
@@ -11408,35 +11664,35 @@ var restartSub = new Command34("restart").description("Stop then start the host
11408
11664
  s2.stop(`relay running on ${ep.hostUrl}`);
11409
11665
  } catch (err) {
11410
11666
  s2.stop("relay start failed");
11411
- log36.warn(err instanceof Error ? err.message : String(err));
11667
+ log37.warn(err instanceof Error ? err.message : String(err));
11412
11668
  throw err;
11413
11669
  }
11414
11670
  } catch (err) {
11415
11671
  handleLifecycleError(err);
11416
11672
  }
11417
11673
  });
11418
- var relayCommand = new Command34("relay").description("Manage the host relay process (status / stop / start / restart)").addCommand(statusSub, { isDefault: true }).addCommand(stopSub).addCommand(startSub).addCommand(restartSub);
11674
+ var relayCommand = new Command35("relay").description("Manage the host relay process (status / stop / start / restart)").addCommand(statusSub, { isDefault: true }).addCommand(stopSub).addCommand(startSub).addCommand(restartSub);
11419
11675
 
11420
11676
  // src/commands/_run-queued-job.ts
11421
- import { Command as Command35 } from "commander";
11422
- 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) => {
11423
- const log45 = openCommandLog(`queue-${id}`);
11424
- log45.write(`worker pid=${String(process.pid)} starting for job ${id}`);
11677
+ import { Command as Command36 } from "commander";
11678
+ var runQueuedJobCommand = new Command36("_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) => {
11679
+ const log46 = openCommandLog(`queue-${id}`);
11680
+ log46.write(`worker pid=${String(process.pid)} starting for job ${id}`);
11425
11681
  let job = null;
11426
11682
  try {
11427
11683
  job = await readJob(id);
11428
11684
  if (!job) {
11429
- log45.write(`FATAL: no manifest at id=${id}`);
11430
- log45.close();
11685
+ log46.write(`FATAL: no manifest at id=${id}`);
11686
+ log46.close();
11431
11687
  process.exit(64);
11432
11688
  }
11433
11689
  const onBoxCreated = (boxId) => {
11434
11690
  if (job) job = { ...job, boxId };
11435
11691
  };
11436
11692
  if ((job.providerName || "docker") === "docker") {
11437
- await runDockerJob(job, log45, onBoxCreated);
11693
+ await runDockerJob(job, log46, onBoxCreated);
11438
11694
  } else {
11439
- await runCloudJob(job, log45, onBoxCreated);
11695
+ await runCloudJob(job, log46, onBoxCreated);
11440
11696
  }
11441
11697
  const done = {
11442
11698
  ...job,
@@ -11445,12 +11701,12 @@ var runQueuedJobCommand = new Command35("_run-queued-job").description("internal
11445
11701
  exitCode: 0
11446
11702
  };
11447
11703
  await writeJob(done);
11448
- log45.write(`done`);
11449
- log45.close();
11704
+ log46.write(`done`);
11705
+ log46.close();
11450
11706
  process.exit(0);
11451
11707
  } catch (err) {
11452
11708
  const msg = err instanceof Error ? err.stack ?? err.message : String(err);
11453
- log45.write(`FAIL: ${msg}`);
11709
+ log46.write(`FAIL: ${msg}`);
11454
11710
  if (job) {
11455
11711
  try {
11456
11712
  const failed = {
@@ -11464,11 +11720,11 @@ var runQueuedJobCommand = new Command35("_run-queued-job").description("internal
11464
11720
  } catch {
11465
11721
  }
11466
11722
  }
11467
- log45.close();
11723
+ log46.close();
11468
11724
  process.exit(1);
11469
11725
  }
11470
11726
  });
11471
- async function runDockerJob(job, log45, onBoxCreated) {
11727
+ async function runDockerJob(job, log46, onBoxCreated) {
11472
11728
  const opts = job.createOpts;
11473
11729
  const cfg = await loadEffectiveConfig(opts.workspace, {
11474
11730
  cliOverrides: buildOverridesFromJob(job)
@@ -11480,7 +11736,7 @@ async function runDockerJob(job, log45, onBoxCreated) {
11480
11736
  const useSnapshot = opts.hostSnapshot === false ? false : opts.hostSnapshot === true ? true : cfg.effective.box.hostSnapshot ?? false;
11481
11737
  const resolved = job.agent === "claude-code" ? await resolveClaudeAuth(process.env) : null;
11482
11738
  const withPlaywright = cfg.effective.box.withPlaywright || cfg.effective.browser.default !== "agent-browser";
11483
- log45.write(`creating box for agent=${job.agent}`);
11739
+ log46.write(`creating box for agent=${job.agent}`);
11484
11740
  const result = await createBox({
11485
11741
  workspacePath: opts.workspace,
11486
11742
  name: opts.name && opts.name.length > 0 ? opts.name : void 0,
@@ -11506,22 +11762,22 @@ async function runDockerJob(job, log45, onBoxCreated) {
11506
11762
  // at box-create time (the worker runs on the host, so it can read the files).
11507
11763
  carry: opts.carry,
11508
11764
  projectRoot,
11509
- onLog: (line) => log45.write(line)
11765
+ onLog: (line) => log46.write(line)
11510
11766
  });
11511
- log45.write(`box created: ${result.record.container}`);
11767
+ log46.write(`box created: ${result.record.container}`);
11512
11768
  onBoxCreated(result.record.id);
11513
11769
  await writeJob({ ...job, boxId: result.record.id });
11514
11770
  const resyncWarning = result.resync ? buildResyncWarning(result.resync) : null;
11515
- if (resyncWarning) log45.write(resyncWarning);
11771
+ if (resyncWarning) log46.write(resyncWarning);
11516
11772
  const prompt = prependResyncWarning(resyncWarning, job.prompt);
11517
11773
  const promptedArgs = buildPromptArgs(job.agent, prompt, job.agentArgs);
11518
11774
  if (job.agent === "claude-code") {
11519
- log45.write(`checking plugin native deps`);
11775
+ log46.write(`checking plugin native deps`);
11520
11776
  await rebuildPluginNativeDeps(result.record.container, {
11521
11777
  volume: result.record.claudeConfigVolume ?? SHARED_CLAUDE_VOLUME,
11522
- onProgress: (line) => log45.write(line)
11778
+ onProgress: (line) => log46.write(line)
11523
11779
  });
11524
- log45.write(`starting claude session`);
11780
+ log46.write(`starting claude session`);
11525
11781
  await startClaudeSession({
11526
11782
  container: result.record.container,
11527
11783
  claudeArgs: applyClaudeSkipPermissions(promptedArgs, cfg.effective),
@@ -11529,22 +11785,22 @@ async function runDockerJob(job, log45, onBoxCreated) {
11529
11785
  boxName: result.record.name
11530
11786
  });
11531
11787
  } else if (job.agent === "codex") {
11532
- log45.write(`checking codex`);
11788
+ log46.write(`checking codex`);
11533
11789
  await ensureCodexInstalled(result.record.container, {
11534
- onProgress: (line) => log45.write(line)
11790
+ onProgress: (line) => log46.write(line)
11535
11791
  });
11536
- log45.write(`starting codex session`);
11792
+ log46.write(`starting codex session`);
11537
11793
  await startCodexSession({
11538
11794
  container: result.record.container,
11539
11795
  codexArgs: applyCodexSkipPermissions(promptedArgs, cfg.effective),
11540
11796
  sessionName: cfg.effective.codex.sessionName
11541
11797
  });
11542
11798
  } else if (job.agent === "opencode") {
11543
- log45.write(`checking opencode`);
11799
+ log46.write(`checking opencode`);
11544
11800
  await ensureOpencodeInstalled(result.record.container, {
11545
- onProgress: (line) => log45.write(line)
11801
+ onProgress: (line) => log46.write(line)
11546
11802
  });
11547
- log45.write(`starting opencode session`);
11803
+ log46.write(`starting opencode session`);
11548
11804
  await startOpencodeSession({
11549
11805
  container: result.record.container,
11550
11806
  opencodeArgs: promptedArgs,
@@ -11554,7 +11810,7 @@ async function runDockerJob(job, log45, onBoxCreated) {
11554
11810
  throw new Error(`unknown agent kind: ${String(job.agent)}`);
11555
11811
  }
11556
11812
  }
11557
- async function runCloudJob(job, log45, onBoxCreated) {
11813
+ async function runCloudJob(job, log46, onBoxCreated) {
11558
11814
  const opts = job.createOpts;
11559
11815
  const cfg = await loadEffectiveConfig(opts.workspace, {
11560
11816
  cliOverrides: buildOverridesFromJob(job)
@@ -11565,7 +11821,7 @@ async function runCloudJob(job, log45, onBoxCreated) {
11565
11821
  const providerDefault = resolveDefaultCheckpoint(cfg.effective, providerName);
11566
11822
  const checkpointRef = opts.snapshot && opts.snapshot.length > 0 ? opts.snapshot : providerDefault.length > 0 ? providerDefault : void 0;
11567
11823
  const withPlaywright = cfg.effective.box.withPlaywright || cfg.effective.browser.default !== "agent-browser";
11568
- log45.write(`creating cloud box (${providerName}) for agent=${job.agent}`);
11824
+ log46.write(`creating cloud box (${providerName}) for agent=${job.agent}`);
11569
11825
  const result = await provider.create({
11570
11826
  workspacePath: opts.workspace,
11571
11827
  name: opts.name && opts.name.length > 0 ? opts.name : void 0,
@@ -11579,9 +11835,9 @@ async function runCloudJob(job, log45, onBoxCreated) {
11579
11835
  // worker runs on the host too, so it reads the files and uploads them.
11580
11836
  carry: opts.carry,
11581
11837
  projectRoot,
11582
- onLog: (line) => log45.write(line)
11838
+ onLog: (line) => log46.write(line)
11583
11839
  });
11584
- log45.write(`box created: ${result.record.id}`);
11840
+ log46.write(`box created: ${result.record.id}`);
11585
11841
  onBoxCreated(result.record.id);
11586
11842
  await writeJob({ ...job, boxId: result.record.id });
11587
11843
  const promptedArgs = buildPromptArgs(job.agent, job.prompt, job.agentArgs);
@@ -11603,7 +11859,7 @@ async function runCloudJob(job, log45, onBoxCreated) {
11603
11859
  } else {
11604
11860
  throw new Error(`unknown agent kind: ${String(job.agent)}`);
11605
11861
  }
11606
- log45.write(`starting detached ${job.agent} session`);
11862
+ log46.write(`starting detached ${job.agent} session`);
11607
11863
  await cloudAgentStartDetached({
11608
11864
  box: result.record,
11609
11865
  binary,
@@ -11640,8 +11896,8 @@ function buildOverridesFromJob(job) {
11640
11896
 
11641
11897
  // src/commands/screen.ts
11642
11898
  import { spawnSync as spawnSync3 } from "child_process";
11643
- import { log as log37 } from "@clack/prompts";
11644
- import { Command as Command36 } from "commander";
11899
+ import { log as log38 } from "@clack/prompts";
11900
+ import { Command as Command37 } from "commander";
11645
11901
  var SIGNED_URL_TTL_MIN = 1;
11646
11902
  var SIGNED_URL_TTL_MAX = 86400;
11647
11903
  function parseTtlOrExit(raw) {
@@ -11654,7 +11910,7 @@ function parseTtlOrExit(raw) {
11654
11910
  }
11655
11911
  return n;
11656
11912
  }
11657
- var screenCommand = new Command36("screen").description("Open a box's VNC (noVNC) viewer in the browser (auto-unpause/start)").argument(
11913
+ var screenCommand = new Command37("screen").description("Open a box's VNC (noVNC) viewer in the browser (auto-unpause/start)").argument(
11658
11914
  "[box]",
11659
11915
  "box ref: project index, id, id prefix, name, or container (default: the only box in this project)"
11660
11916
  ).option("--print", "print the URL to stdout instead of launching the browser").option("--loopback", "docker only: use the 127.0.0.1 URL instead of the OrbStack .orb.local URL").option(
@@ -11671,10 +11927,10 @@ var screenCommand = new Command36("screen").description("Open a box's VNC (noVNC
11671
11927
  if (provider === "docker") {
11672
11928
  const insp = await inspectBox(box.id);
11673
11929
  if (insp.state === "paused") {
11674
- log37.info("box is paused; unpausing");
11930
+ log38.info("box is paused; unpausing");
11675
11931
  await unpauseBox(box.id);
11676
11932
  } else if (insp.state === "stopped") {
11677
- log37.info("box is stopped; starting");
11933
+ log38.info("box is stopped; starting");
11678
11934
  await startBox(box.id);
11679
11935
  } else if (insp.state === "missing") {
11680
11936
  throw new Error(`box ${box.name} has no container; was it destroyed?`);
@@ -11684,13 +11940,13 @@ var screenCommand = new Command36("screen").description("Open a box's VNC (noVNC
11684
11940
  const inBoxUrl = exposePort !== void 0 ? box.portlessUrl ?? `http://localhost:${String(exposePort)}` : "about:blank";
11685
11941
  const br = await ensureBoxBrowser(box.container, void 0, inBoxUrl);
11686
11942
  if (br.up && !br.alreadyRunning) {
11687
- log37.info(
11943
+ log38.info(
11688
11944
  exposePort !== void 0 ? `opened ${inBoxUrl} in the in-box browser (visible in the VNC view)` : "started in-box browser"
11689
11945
  );
11690
11946
  } else if (br.alreadyRunning) {
11691
- log37.info("in-box browser already running; left it untouched");
11947
+ log38.info("in-box browser already running; left it untouched");
11692
11948
  } else {
11693
- log37.warn(`could not start in-box browser: ${br.reason ?? "unknown"}`);
11949
+ log38.warn(`could not start in-box browser: ${br.reason ?? "unknown"}`);
11694
11950
  }
11695
11951
  const engine = await detectEngine();
11696
11952
  const urls = buildVncUrls(box, engine);
@@ -11711,10 +11967,10 @@ var screenCommand = new Command36("screen").description("Open a box's VNC (noVNC
11711
11967
  const p = await providerForBox(box);
11712
11968
  const state = await p.probeState(box);
11713
11969
  if (state === "paused") {
11714
- log37.info("box is paused; resuming");
11970
+ log38.info("box is paused; resuming");
11715
11971
  await p.resume(box);
11716
11972
  } else if (state === "stopped") {
11717
- log37.info("box is stopped; starting");
11973
+ log38.info("box is stopped; starting");
11718
11974
  await p.start(box);
11719
11975
  } else if (state === "missing") {
11720
11976
  throw new Error(`cloud sandbox for ${box.name} is missing; was it deleted?`);
@@ -11729,14 +11985,14 @@ var screenCommand = new Command36("screen").description("Open a box's VNC (noVNC
11729
11985
  user: "vscode"
11730
11986
  });
11731
11987
  if (br.exitCode === 0) {
11732
- log37.info(`opened ${webUrl} in the in-box browser (visible in the VNC view)`);
11988
+ log38.info(`opened ${webUrl} in the in-box browser (visible in the VNC view)`);
11733
11989
  } else {
11734
- log37.warn(
11990
+ log38.warn(
11735
11991
  `could not open in-box browser (continuing): ${br.stderr.trim() || br.stdout.trim() || `exit ${String(br.exitCode)}`}`
11736
11992
  );
11737
11993
  }
11738
11994
  } catch (err) {
11739
- log37.warn(
11995
+ log38.warn(
11740
11996
  `in-box browser skipped: ${err instanceof Error ? err.message : String(err)}`
11741
11997
  );
11742
11998
  }
@@ -11762,18 +12018,18 @@ var screenCommand = new Command36("screen").description("Open a box's VNC (noVNC
11762
12018
 
11763
12019
  // src/commands/shell.ts
11764
12020
  import { spawnSync as spawnSync4 } from "child_process";
11765
- import { log as log39 } from "@clack/prompts";
11766
- import { Command as Command37 } from "commander";
12021
+ import { log as log40 } from "@clack/prompts";
12022
+ import { Command as Command38 } from "commander";
11767
12023
 
11768
12024
  // src/commands/_provider-guard.ts
11769
- import { log as log38 } from "@clack/prompts";
12025
+ import { log as log39 } from "@clack/prompts";
11770
12026
  function requireDockerProvider(box, commandName) {
11771
12027
  const provider = box.provider ?? "docker";
11772
12028
  if (provider === "docker") return;
11773
- log38.error(
12029
+ log39.error(
11774
12030
  `\`agentbox ${commandName}\` doesn't yet support cloud boxes (this box's provider is '${provider}').`
11775
12031
  );
11776
- log38.info(
12032
+ log39.info(
11777
12033
  "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."
11778
12034
  );
11779
12035
  process.exit(2);
@@ -11813,10 +12069,10 @@ function fmtAgo2(iso) {
11813
12069
  async function ensureBoxRunning(box) {
11814
12070
  const insp = await inspectBox(box.id);
11815
12071
  if (insp.state === "paused") {
11816
- log39.info("box is paused; unpausing");
12072
+ log40.info("box is paused; unpausing");
11817
12073
  await unpauseBox(box.id);
11818
12074
  } else if (insp.state === "stopped") {
11819
- log39.info("box is stopped; starting");
12075
+ log40.info("box is stopped; starting");
11820
12076
  await startBox(box.id);
11821
12077
  } else if (insp.state === "missing") {
11822
12078
  throw new Error(`box ${box.name} has no container; was it destroyed?`);
@@ -11855,7 +12111,7 @@ async function startOrAttachShell(box, cfg) {
11855
12111
  const label = shellLabel(cfg.sessionName);
11856
12112
  const info = await shellSessionInfo(box.container, cfg.sessionName, cfg.user);
11857
12113
  if (info.running) {
11858
- log39.info(`reattaching to shell "${label}" \u2014 Control+a d to detach`);
12114
+ log40.info(`reattaching to shell "${label}" \u2014 Control+a d to detach`);
11859
12115
  } else {
11860
12116
  await startShellSession({
11861
12117
  container: box.container,
@@ -11863,7 +12119,7 @@ async function startOrAttachShell(box, cfg) {
11863
12119
  user: cfg.user,
11864
12120
  login: cfg.login
11865
12121
  });
11866
- log39.info(`shell "${label}" \u2014 Control+a d to detach, leaves it running`);
12122
+ log40.info(`shell "${label}" \u2014 Control+a d to detach, leaves it running`);
11867
12123
  }
11868
12124
  const code = await runWrappedAttach({
11869
12125
  container: box.container,
@@ -11878,7 +12134,7 @@ async function startOrAttachShell(box, cfg) {
11878
12134
  });
11879
12135
  process.exit(code);
11880
12136
  }
11881
- var shellCommand = new Command37("shell").description(
12137
+ var shellCommand = new Command38("shell").description(
11882
12138
  "Open an interactive shell in a box, in a detachable tmux session (auto-unpause/start)"
11883
12139
  ).argument(
11884
12140
  "[box]",
@@ -11969,7 +12225,7 @@ var shellCommand = new Command37("shell").description(
11969
12225
  handleLifecycleError(err);
11970
12226
  }
11971
12227
  });
11972
- var shellAttachCommand = new Command37("attach").description(
12228
+ var shellAttachCommand = new Command38("attach").description(
11973
12229
  "Attach to a shell tmux session in a box, starting one if none is running (auto-unpause/start)"
11974
12230
  ).argument(
11975
12231
  "[box]",
@@ -12007,7 +12263,7 @@ function renderShellTable(sessions) {
12007
12263
  for (const r of rows) process.stdout.write(`${fmt(r)}
12008
12264
  `);
12009
12265
  }
12010
- var shellLsCommand = new Command37("ls").description("List the shell tmux sessions running in a box").argument(
12266
+ var shellLsCommand = new Command38("ls").description("List the shell tmux sessions running in a box").argument(
12011
12267
  "[box]",
12012
12268
  "box ref: project index, id, id prefix, name, or container (default: the only box in this project)"
12013
12269
  ).action(async (idOrName) => {
@@ -12016,11 +12272,11 @@ var shellLsCommand = new Command37("ls").description("List the shell tmux sessio
12016
12272
  requireDockerProvider(box, "shell");
12017
12273
  const insp = await inspectBox(box.id);
12018
12274
  if (insp.state !== "running") {
12019
- log39.info(`box ${box.name} is ${insp.state} \u2014 no live shell sessions`);
12275
+ log40.info(`box ${box.name} is ${insp.state} \u2014 no live shell sessions`);
12020
12276
  return;
12021
12277
  }
12022
12278
  if (insp.shellSessions.length === 0) {
12023
- log39.info(
12279
+ log40.info(
12024
12280
  `no shell sessions in ${box.name} \u2014 start one with: agentbox shell ${reattachRef4(box)}`
12025
12281
  );
12026
12282
  return;
@@ -12030,7 +12286,7 @@ var shellLsCommand = new Command37("ls").description("List the shell tmux sessio
12030
12286
  handleLifecycleError(err);
12031
12287
  }
12032
12288
  });
12033
- var shellKillCommand = new Command37("kill").description("Kill a shell tmux session in a box (the shell and anything running in it)").argument(
12289
+ var shellKillCommand = new Command38("kill").description("Kill a shell tmux session in a box (the shell and anything running in it)").argument(
12034
12290
  "[box]",
12035
12291
  "box ref: project index, id, id prefix, name, or container (default: the only box in this project)"
12036
12292
  ).option("-n, --name <label>", "shell label to kill (default: the box default shell)").option("--all", "kill every shell session in the box").action(async function(idOrName) {
@@ -12040,25 +12296,25 @@ var shellKillCommand = new Command37("kill").description("Kill a shell tmux sess
12040
12296
  requireDockerProvider(box, "shell");
12041
12297
  const insp = await inspectBox(box.id);
12042
12298
  if (insp.state !== "running") {
12043
- log39.info(`box ${box.name} is ${insp.state} \u2014 no shell sessions to kill`);
12299
+ log40.info(`box ${box.name} is ${insp.state} \u2014 no shell sessions to kill`);
12044
12300
  return;
12045
12301
  }
12046
12302
  if (opts.all) {
12047
12303
  if (insp.shellSessions.length === 0) {
12048
- log39.info(`no shell sessions in ${box.name}`);
12304
+ log40.info(`no shell sessions in ${box.name}`);
12049
12305
  return;
12050
12306
  }
12051
12307
  let killed = 0;
12052
12308
  for (const s of insp.shellSessions) {
12053
12309
  if (await killShellSession(box.container, s.sessionName)) killed++;
12054
12310
  }
12055
- log39.success(`killed ${String(killed)} shell session${killed === 1 ? "" : "s"} in ${box.name}`);
12311
+ log40.success(`killed ${String(killed)} shell session${killed === 1 ? "" : "s"} in ${box.name}`);
12056
12312
  return;
12057
12313
  }
12058
12314
  const target = shellSessionName(opts.name);
12059
12315
  const ok = await killShellSession(box.container, target);
12060
- if (ok) log39.success(`killed shell "${shellLabel(target)}" in ${box.name}`);
12061
- else log39.warn(`no shell "${shellLabel(target)}" in ${box.name} (already gone?)`);
12316
+ if (ok) log40.success(`killed shell "${shellLabel(target)}" in ${box.name}`);
12317
+ else log40.warn(`no shell "${shellLabel(target)}" in ${box.name} (already gone?)`);
12062
12318
  } catch (err) {
12063
12319
  handleLifecycleError(err);
12064
12320
  }
@@ -12068,8 +12324,8 @@ shellCommand.addCommand(shellLsCommand);
12068
12324
  shellCommand.addCommand(shellKillCommand);
12069
12325
 
12070
12326
  // src/commands/start.ts
12071
- import { Command as Command38 } from "commander";
12072
- var startCommand = new Command38("start").description(
12327
+ import { Command as Command39 } from "commander";
12328
+ var startCommand = new Command39("start").description(
12073
12329
  "Start a stopped box. Docker: docker start + relaunch ctl/dockerd/vnc daemons. Cloud: backend.start, then re-resolve preview URLs/tokens, re-launch in-sandbox ctl/dockerd daemons, and re-register with the host relay (so the CloudBoxPoller resumes)."
12074
12330
  ).argument(
12075
12331
  "[box]",
@@ -12092,8 +12348,8 @@ var startCommand = new Command38("start").description(
12092
12348
  });
12093
12349
 
12094
12350
  // src/commands/status.ts
12095
- import { log as log41 } from "@clack/prompts";
12096
- import { Command as Command39 } from "commander";
12351
+ import { log as log42 } from "@clack/prompts";
12352
+ import { Command as Command40 } from "commander";
12097
12353
 
12098
12354
  // src/endpoints-render.ts
12099
12355
  function renderEndpointLines(endpoints, stream) {
@@ -12123,7 +12379,7 @@ function renderEndpointLines(endpoints, stream) {
12123
12379
  }
12124
12380
 
12125
12381
  // src/commands/inspect.ts
12126
- import { log as log40 } from "@clack/prompts";
12382
+ import { log as log41 } from "@clack/prompts";
12127
12383
  function fmtLimit(n, unit) {
12128
12384
  return n && n > 0 ? `${String(n)}${unit}` : "unlimited";
12129
12385
  }
@@ -12268,7 +12524,7 @@ function renderCodexActivityCloud(persisted) {
12268
12524
  async function runInspect(box, opts) {
12269
12525
  try {
12270
12526
  if (opts.json && opts.watch) {
12271
- log40.error("cannot combine --json with --watch");
12527
+ log41.error("cannot combine --json with --watch");
12272
12528
  process.exit(2);
12273
12529
  }
12274
12530
  const isCloud = (box.provider ?? "docker") !== "docker";
@@ -12305,14 +12561,14 @@ async function runInspect(box, opts) {
12305
12561
 
12306
12562
  // src/commands/status.ts
12307
12563
  var statusCommand2 = withWatchOptions(
12308
- new Command39("status").description("Show service + task status from a box's agentbox-ctl daemon").argument(
12564
+ new Command40("status").description("Show service + task status from a box's agentbox-ctl daemon").argument(
12309
12565
  "[box]",
12310
12566
  "box ref: project index, id, id prefix, name, or container (default: the only box in this project)"
12311
12567
  ).option("-j, --json", "machine-readable JSON output").option("--inspect", "show detailed box info (volumes, limits, paths) instead of service/task status")
12312
12568
  ).action(async (idOrName, opts) => {
12313
12569
  try {
12314
12570
  if (opts.json && opts.watch) {
12315
- log41.error("cannot combine --json with --watch");
12571
+ log42.error("cannot combine --json with --watch");
12316
12572
  process.exit(2);
12317
12573
  }
12318
12574
  const box = await resolveBoxOrExit(idOrName);
@@ -12479,8 +12735,8 @@ function renderPersisted2(s, state) {
12479
12735
  }
12480
12736
 
12481
12737
  // src/commands/stop.ts
12482
- import { Command as Command40 } from "commander";
12483
- var stopCommand = new Command40("stop").description(
12738
+ import { Command as Command41 } from "commander";
12739
+ var stopCommand = new Command41("stop").description(
12484
12740
  "Stop a box (Docker: docker stop; preserves upper + node_modules volumes. Cloud: backend.stop \u2014 sandbox stays in your account, disk preserved)."
12485
12741
  ).argument(
12486
12742
  "[box]",
@@ -12509,7 +12765,7 @@ restart with: agentbox start ${box.name}
12509
12765
  });
12510
12766
 
12511
12767
  // src/commands/top.ts
12512
- import { Command as Command41 } from "commander";
12768
+ import { Command as Command42 } from "commander";
12513
12769
  var COLS = ["BOX", "STATE", "CPU%", "MEM USAGE / LIMIT", "MEM%", "PIDS", "DISK", "NET I/O"];
12514
12770
  function row(name, state, s) {
12515
12771
  const mem = `${fmtBytes(s.memUsedBytes)} / ${fmtBytes(s.memLimitBytes)}`;
@@ -12583,7 +12839,7 @@ async function renderProjectFooters() {
12583
12839
 
12584
12840
  SYSTEM: ${parts.join(" - ")}` : "";
12585
12841
  }
12586
- var topCommand = new Command41("top").description("Live resource monitor (cpu/mem/pids/disk) for a box, the project, or every box").argument(
12842
+ var topCommand = new Command42("top").description("Live resource monitor (cpu/mem/pids/disk) for a box, the project, or every box").argument(
12587
12843
  "[box]",
12588
12844
  "box ref (default: every box on the host; --project narrows to the cwd's project)"
12589
12845
  ).option("-p, --project", "show only boxes in the cwd's project").option("--once", "print a single snapshot instead of watching").option("-j, --json", "machine-readable JSON (implies --once)").option("--interval <seconds>", "refresh interval", "2").option("--live", "probe live cloud state via the provider SDK (slower; default: last host-known)").action(async (idOrName, opts) => {
@@ -12616,8 +12872,8 @@ var topCommand = new Command41("top").description("Live resource monitor (cpu/me
12616
12872
  });
12617
12873
 
12618
12874
  // src/commands/unpause.ts
12619
- import { Command as Command42 } from "commander";
12620
- var unpauseCommand = new Command42("unpause").description(
12875
+ import { Command as Command43 } from "commander";
12876
+ var unpauseCommand = new Command43("unpause").description(
12621
12877
  "Resume a paused box. Docker: `docker unpause` (sub-second). Cloud: backend.resume (re-hydrates from archive \u2014 slower first time)."
12622
12878
  ).argument(
12623
12879
  "[box]",
@@ -12641,8 +12897,8 @@ var unpauseCommand = new Command42("unpause").description(
12641
12897
 
12642
12898
  // src/commands/update.ts
12643
12899
  import { spawn as spawn4 } from "child_process";
12644
- import { confirm as confirm16, intro as intro8, isCancel as isCancel17, log as log42, outro as outro7, spinner as spinner10 } from "@clack/prompts";
12645
- import { Command as Command43 } from "commander";
12900
+ import { confirm as confirm16, intro as intro9, isCancel as isCancel17, log as log43, outro as outro8, spinner as spinner10 } from "@clack/prompts";
12901
+ import { Command as Command44 } from "commander";
12646
12902
 
12647
12903
  // src/exec-method.ts
12648
12904
  function detectExecutionMethod(input) {
@@ -12686,7 +12942,7 @@ function runInherit(cmd, args) {
12686
12942
  child.on("close", (code) => resolveP(code ?? 0));
12687
12943
  });
12688
12944
  }
12689
- var updateCommand = new Command43("self-update").description(
12945
+ var updateCommand = new Command44("self-update").description(
12690
12946
  "Update agentbox: self-update via npm/pnpm (unless run via npx), refresh the host skills, wipe the box image so it rebuilds, and reload the relay"
12691
12947
  ).option("-y, --yes", "skip the confirmation prompt").option("--dry-run", "show what would happen, don't change anything").option("--skip-self", "skip the package self-update; only refresh the skills + image + relay").option("--skip-skills", "skip refreshing the host skill files in ~/.claude, ~/.codex, ~/.config/opencode").action(async (opts) => {
12692
12948
  try {
@@ -12694,10 +12950,10 @@ var updateCommand = new Command43("self-update").description(
12694
12950
  userAgent: process.env.npm_config_user_agent,
12695
12951
  argv1: process.argv[1]
12696
12952
  });
12697
- intro8("agentbox self-update");
12953
+ intro9("agentbox self-update");
12698
12954
  const selfStep = opts.skipSelf ? "self-update: skipped (--skip-self)" : describeSelfUpdate(method);
12699
12955
  const skillsStep = opts.skipSkills ? "skills: skipped (--skip-skills)" : "skills: refresh agentbox-managed host skill files in ~/.claude (and Codex/OpenCode)";
12700
- log42.info(
12956
+ log43.info(
12701
12957
  [
12702
12958
  "plan:",
12703
12959
  ` ${selfStep}`,
@@ -12707,41 +12963,41 @@ var updateCommand = new Command43("self-update").description(
12707
12963
  ].join("\n")
12708
12964
  );
12709
12965
  if (opts.dryRun) {
12710
- outro7("dry run \u2014 nothing changed");
12966
+ outro8("dry run \u2014 nothing changed");
12711
12967
  return;
12712
12968
  }
12713
12969
  if (!opts.yes) {
12714
12970
  const ok = await confirm16({ message: "Proceed with update?", initialValue: true });
12715
12971
  if (isCancel17(ok) || !ok) {
12716
- log42.info("cancelled");
12972
+ log43.info("cancelled");
12717
12973
  return;
12718
12974
  }
12719
12975
  }
12720
12976
  let selfUpdated = false;
12721
12977
  if (opts.skipSelf) {
12722
- log42.info("skipping self-update (--skip-self)");
12978
+ log43.info("skipping self-update (--skip-self)");
12723
12979
  } else {
12724
12980
  const cmd = selfUpdateCommand(method);
12725
12981
  if (cmd === null) {
12726
- log42.info(describeSelfUpdate(method));
12982
+ log43.info(describeSelfUpdate(method));
12727
12983
  } else {
12728
- log42.info(`running: ${cmd.cmd} ${cmd.args.join(" ")}`);
12984
+ log43.info(`running: ${cmd.cmd} ${cmd.args.join(" ")}`);
12729
12985
  const code = await runInherit(cmd.cmd, cmd.args);
12730
12986
  if (code !== 0) {
12731
12987
  throw new Error(`${cmd.cmd} exited with code ${String(code)}`);
12732
12988
  }
12733
12989
  selfUpdated = true;
12734
- log42.success(`updated ${PKG} via ${cmd.cmd}`);
12990
+ log43.success(`updated ${PKG} via ${cmd.cmd}`);
12735
12991
  }
12736
12992
  }
12737
12993
  if (opts.skipSkills) {
12738
- log42.info("skipping skills refresh (--skip-skills)");
12994
+ log43.info("skipping skills refresh (--skip-skills)");
12739
12995
  } else if (selfUpdated) {
12740
12996
  const code = await runInherit("agentbox", ["install", "--skills-only"]);
12741
12997
  if (code === 0) {
12742
- log42.success("refreshed host skills (via updated build)");
12998
+ log43.success("refreshed host skills (via updated build)");
12743
12999
  } else {
12744
- log42.warn(
13000
+ log43.warn(
12745
13001
  `host skills not refreshed (agentbox install --skills-only exited ${String(code)}) \u2014 run it manually to pick up the new versions`
12746
13002
  );
12747
13003
  }
@@ -12749,17 +13005,17 @@ var updateCommand = new Command43("self-update").description(
12749
13005
  try {
12750
13006
  const res = installHostSkills({ quiet: true });
12751
13007
  if (res.written.length > 0) {
12752
- log42.success(`refreshed host skills (${String(res.written.length)} file(s))`);
13008
+ log43.success(`refreshed host skills (${String(res.written.length)} file(s))`);
12753
13009
  } else {
12754
- log42.info(`host skills already current (${String(res.skipped)} skipped)`);
13010
+ log43.info(`host skills already current (${String(res.skipped)} skipped)`);
12755
13011
  }
12756
13012
  if (res.blocked.length > 0) {
12757
- log42.warn(
13013
+ log43.warn(
12758
13014
  `user-modified skill file(s) left in place: ${res.blocked.join(", ")} \u2014 run \`agentbox install --skills-only --force\` to overwrite`
12759
13015
  );
12760
13016
  }
12761
13017
  } catch (err) {
12762
- log42.warn(
13018
+ log43.warn(
12763
13019
  `host skills not refreshed (${err instanceof Error ? err.message : String(err)})`
12764
13020
  );
12765
13021
  }
@@ -12777,7 +13033,7 @@ var updateCommand = new Command43("self-update").description(
12777
13033
  stop.stopped ? `stopped relay (pid ${String(stop.pid)})` : "relay was not running"
12778
13034
  );
12779
13035
  if (selfUpdated) {
12780
- log42.info(
13036
+ log43.info(
12781
13037
  "relay will restart automatically (with the updated build) on your next `agentbox create` / `agentbox claude`"
12782
13038
  );
12783
13039
  } else {
@@ -12788,12 +13044,12 @@ var updateCommand = new Command43("self-update").description(
12788
13044
  sr2.stop(`relay back up on ${ep.hostUrl}`);
12789
13045
  } catch (err) {
12790
13046
  sr2.stop("relay restart failed");
12791
- log42.warn(
13047
+ log43.warn(
12792
13048
  `${err instanceof Error ? err.message : String(err)} \u2014 it will retry on the next box command`
12793
13049
  );
12794
13050
  }
12795
13051
  }
12796
- outro7("update complete");
13052
+ outro8("update complete");
12797
13053
  } catch (err) {
12798
13054
  handleLifecycleError(err);
12799
13055
  }
@@ -12801,8 +13057,8 @@ var updateCommand = new Command43("self-update").description(
12801
13057
 
12802
13058
  // src/commands/url.ts
12803
13059
  import { spawnSync as spawnSync5 } from "child_process";
12804
- import { log as log43 } from "@clack/prompts";
12805
- import { Command as Command44 } from "commander";
13060
+ import { log as log44 } from "@clack/prompts";
13061
+ import { Command as Command45 } from "commander";
12806
13062
  var SIGNED_URL_TTL_MIN2 = 1;
12807
13063
  var SIGNED_URL_TTL_MAX2 = 86400;
12808
13064
  function parseTtlOrExit2(raw) {
@@ -12815,7 +13071,7 @@ function parseTtlOrExit2(raw) {
12815
13071
  }
12816
13072
  return n;
12817
13073
  }
12818
- var urlCommand = new Command44("url").description(
13074
+ var urlCommand = new Command45("url").description(
12819
13075
  "Open a box's web app URL in the browser, even when no service declares `expose:` (auto-unpause/start)"
12820
13076
  ).argument(
12821
13077
  "[box]",
@@ -12834,10 +13090,10 @@ var urlCommand = new Command44("url").description(
12834
13090
  if (provider === "docker") {
12835
13091
  const insp = await inspectBox(box.id);
12836
13092
  if (insp.state === "paused") {
12837
- log43.info("box is paused; unpausing");
13093
+ log44.info("box is paused; unpausing");
12838
13094
  await unpauseBox(box.id);
12839
13095
  } else if (insp.state === "stopped") {
12840
- log43.info("box is stopped; starting");
13096
+ log44.info("box is stopped; starting");
12841
13097
  await startBox(box.id);
12842
13098
  } else if (insp.state === "missing") {
12843
13099
  throw new Error(`box ${box.name} has no container; was it destroyed?`);
@@ -12866,10 +13122,10 @@ var urlCommand = new Command44("url").description(
12866
13122
  const p = await providerForBox(box);
12867
13123
  const state = await p.probeState(box);
12868
13124
  if (state === "paused") {
12869
- log43.info("box is paused; resuming");
13125
+ log44.info("box is paused; resuming");
12870
13126
  await p.resume(box);
12871
13127
  } else if (state === "stopped") {
12872
- log43.info("box is stopped; starting");
13128
+ log44.info("box is stopped; starting");
12873
13129
  await p.start(box);
12874
13130
  } else if (state === "missing") {
12875
13131
  throw new Error(`cloud sandbox for ${box.name} is missing; was it deleted?`);
@@ -12893,9 +13149,9 @@ var urlCommand = new Command44("url").description(
12893
13149
  });
12894
13150
 
12895
13151
  // src/commands/wait.ts
12896
- import { log as log44 } from "@clack/prompts";
12897
- import { Command as Command45 } from "commander";
12898
- var waitCommand = new Command45("wait").description("Block until the box reports all autostart units ready").argument(
13152
+ import { log as log45 } from "@clack/prompts";
13153
+ import { Command as Command46 } from "commander";
13154
+ var waitCommand = new Command46("wait").description("Block until the box reports all autostart units ready").argument(
12899
13155
  "[box]",
12900
13156
  "box ref: project index, id, id prefix, name, or container (default: the only box in this project)"
12901
13157
  ).option("--timeout <ms>", "overall timeout in milliseconds", "120000").option("--units <names...>", "restrict to the named units").option("-j, --json", "machine-readable JSON output").action(async (idOrName, opts) => {
@@ -12911,7 +13167,7 @@ var waitCommand = new Command45("wait").description("Block until the box reports
12911
13167
  try {
12912
13168
  parsed = JSON.parse(proc.stdout);
12913
13169
  } catch {
12914
- log44.error(`agentbox-ctl wait-ready failed: ${proc.stderr || proc.stdout}`);
13170
+ log45.error(`agentbox-ctl wait-ready failed: ${proc.stderr || proc.stdout}`);
12915
13171
  process.exit(1);
12916
13172
  }
12917
13173
  if (opts.json) {
@@ -12950,7 +13206,7 @@ function rewriteProviderPrefix(argv2) {
12950
13206
  process.env.DOCKER_CLI_HINTS ??= "false";
12951
13207
  process.env.AGENTBOX_CLI_VERSION = AGENTBOX_VERSION;
12952
13208
  process.env.AGENTBOX_CLI_COMMIT = AGENTBOX_COMMIT;
12953
- var program = new Command46();
13209
+ var program = new Command47();
12954
13210
  program.name("agentbox").description("Launch coding agents in isolated sandboxes").version(AGENTBOX_VERSION);
12955
13211
  program.enablePositionalOptions();
12956
13212
  program.addCommand(createCommand);