@madarco/agentbox 0.1.0 → 0.2.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.
@@ -27,7 +27,7 @@ import {
27
27
  snapshotPathFor,
28
28
  verifyOverlay,
29
29
  vscodeServerVolumeName
30
- } from "./chunk-O5HS3QHW.js";
30
+ } from "./chunk-3NIZKZPJ.js";
31
31
  import {
32
32
  allocateProjectIndex,
33
33
  readState,
@@ -51,7 +51,7 @@ import {
51
51
  runBox
52
52
  } from "./chunk-SOMIKEN2.js";
53
53
 
54
- // ../../packages/sandbox-docker/dist/chunk-IGNL6VQG.js
54
+ // ../../packages/sandbox-docker/dist/chunk-BC7AYNLK.js
55
55
  import { randomBytes } from "crypto";
56
56
  import { mkdir, stat } from "fs/promises";
57
57
  import { homedir } from "os";
@@ -493,4 +493,4 @@ export {
493
493
  defaultBoxName,
494
494
  createBox
495
495
  };
496
- //# sourceMappingURL=chunk-OOOKFFR5.js.map
496
+ //# sourceMappingURL=chunk-3OPLNXQ5.js.map
@@ -3,8 +3,8 @@ import {
3
3
  createBox,
4
4
  defaultBoxName,
5
5
  sanitizeBasename
6
- } from "./chunk-OOOKFFR5.js";
7
- import "./chunk-O5HS3QHW.js";
6
+ } from "./chunk-3OPLNXQ5.js";
7
+ import "./chunk-3NIZKZPJ.js";
8
8
  import "./chunk-IDR4HVIC.js";
9
9
  import "./chunk-SOMIKEN2.js";
10
10
  export {
@@ -12,4 +12,4 @@ export {
12
12
  defaultBoxName,
13
13
  sanitizeBasename
14
14
  };
15
- //# sourceMappingURL=create-LSSO7H4I-GWNALUMF.js.map
15
+ //# sourceMappingURL=create-SE6H4B5U-ESNDTXAI.js.map
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  createBox
4
- } from "./chunk-OOOKFFR5.js";
4
+ } from "./chunk-3OPLNXQ5.js";
5
5
  import {
6
6
  AmbiguousBoxError,
7
7
  BoxNotFoundError,
@@ -15,7 +15,7 @@ import {
15
15
  startBox,
16
16
  stopBox,
17
17
  unpauseBox
18
- } from "./chunk-RWJE6AER.js";
18
+ } from "./chunk-3NU4PS5W.js";
19
19
  import {
20
20
  ClaudeSessionError,
21
21
  SHARED_CLAUDE_VOLUME,
@@ -37,7 +37,7 @@ import {
37
37
  resolveClaudeVolume,
38
38
  startClaudeSession,
39
39
  stopRelay
40
- } from "./chunk-O5HS3QHW.js";
40
+ } from "./chunk-3NIZKZPJ.js";
41
41
  import {
42
42
  STATE_DIR,
43
43
  readState,
@@ -1916,6 +1916,28 @@ function menuLines(boxName, w, h) {
1916
1916
  for (let i = 0; i < h; i++) out.push(fit(body[i - top] ?? "", w));
1917
1917
  return out;
1918
1918
  }
1919
+ function lifecycleMenuLines(boxName, state, confirmDestroy, w, h) {
1920
+ const body = confirmDestroy ? [
1921
+ "",
1922
+ ` Destroy ${boxName}?`,
1923
+ " This removes the container and its volumes.",
1924
+ "",
1925
+ " [y] Yes, destroy",
1926
+ " [any other key] Cancel"
1927
+ ] : [
1928
+ "",
1929
+ ` Box ${boxName} is ${state}.`,
1930
+ "",
1931
+ state === "paused" ? " [u] Unpause" : " [s] Start",
1932
+ " [d] Destroy",
1933
+ "",
1934
+ " Ctrl+Option+\u2191/\u2193 switch \xB7 Ctrl-a then q quit"
1935
+ ];
1936
+ const top = Math.max(0, Math.floor((h - body.length) / 2));
1937
+ const out = [];
1938
+ for (let i = 0; i < h; i++) out.push(fit(body[i - top] ?? "", w));
1939
+ return out;
1940
+ }
1919
1941
  function createMenuLines(where, w, h) {
1920
1942
  const body = [
1921
1943
  "",
@@ -1990,6 +2012,7 @@ var Compositor = class {
1990
2012
  else if (e.type === "switch") this.switchBox(e.dir);
1991
2013
  else if (e.type === "action") void this.doAction(e.name);
1992
2014
  else if (this.createMenu) this.handleCreateMenuKey(e.bytes);
2015
+ else if (this.lifecycleMenu) this.handleLifecycleMenuKey(e.bytes);
1993
2016
  else if (this.menu) this.handleMenuKey(e.bytes);
1994
2017
  else this.session?.write(e.bytes);
1995
2018
  },
@@ -2013,6 +2036,7 @@ var Compositor = class {
2013
2036
  session = null;
2014
2037
  placeholder = null;
2015
2038
  menu = null;
2039
+ lifecycleMenu = null;
2016
2040
  createMenu = null;
2017
2041
  activeMode = "claude";
2018
2042
  flashMsg = null;
@@ -2082,7 +2106,7 @@ var Compositor = class {
2082
2106
  } else {
2083
2107
  const box = this.selectedBox();
2084
2108
  const running = box?.state === "running";
2085
- const reresolve = this.session && !running || this.placeholder && running || this.menu && !running;
2109
+ const reresolve = this.session && !running || this.placeholder && running || this.menu && !running || this.lifecycleMenu != null && box?.state !== this.lifecycleMenu.state;
2086
2110
  if (reresolve) await this.spawnActive();
2087
2111
  }
2088
2112
  if (JSON.stringify(this.boxes.map((b) => [b.id, b.state, b.claudeActivity])) !== before) {
@@ -2098,6 +2122,7 @@ var Compositor = class {
2098
2122
  this.disposeSession();
2099
2123
  this.placeholder = null;
2100
2124
  this.menu = null;
2125
+ this.lifecycleMenu = null;
2101
2126
  this.createMenu = null;
2102
2127
  this.clearRightPane();
2103
2128
  const id = this.selectedId;
@@ -2110,6 +2135,7 @@ var Compositor = class {
2110
2135
  this.disposeSession();
2111
2136
  this.placeholder = null;
2112
2137
  this.menu = null;
2138
+ this.lifecycleMenu = null;
2113
2139
  this.createMenu = null;
2114
2140
  if (target.kind === "attach") {
2115
2141
  this.activeMode = target.mode ?? "claude";
@@ -2124,6 +2150,12 @@ var Compositor = class {
2124
2150
  );
2125
2151
  } else if (target.kind === "menu") {
2126
2152
  this.menu = { boxName: this.selectedBox()?.name ?? this.selectedId };
2153
+ } else if (target.kind === "lifecycle-menu") {
2154
+ this.lifecycleMenu = {
2155
+ boxName: this.selectedBox()?.name ?? this.selectedId,
2156
+ state: target.state,
2157
+ confirmDestroy: false
2158
+ };
2127
2159
  } else if (target.kind === "create-menu") {
2128
2160
  this.createMenu = { where: target.where };
2129
2161
  } else {
@@ -2176,6 +2208,77 @@ var Compositor = class {
2176
2208
  this.busy = false;
2177
2209
  }
2178
2210
  }
2211
+ handleLifecycleMenuKey(bytes) {
2212
+ const m = this.lifecycleMenu;
2213
+ if (!m) return;
2214
+ for (const b of bytes) {
2215
+ if (m.confirmDestroy) {
2216
+ if (b === 121 || b === 13 || b === 10) {
2217
+ void this.choosePaused("destroy");
2218
+ } else {
2219
+ m.confirmDestroy = false;
2220
+ this.drawChrome();
2221
+ this.scheduleRender();
2222
+ }
2223
+ return;
2224
+ }
2225
+ const resumeKey = m.state === "paused" ? 117 : 115;
2226
+ if (b === resumeKey) {
2227
+ void this.choosePaused("resume");
2228
+ return;
2229
+ }
2230
+ if (b === 100) {
2231
+ m.confirmDestroy = true;
2232
+ this.drawChrome();
2233
+ this.scheduleRender();
2234
+ return;
2235
+ }
2236
+ }
2237
+ }
2238
+ async choosePaused(which) {
2239
+ if (this.busy) return;
2240
+ const id = this.selectedId;
2241
+ const name = this.selectedBox()?.name ?? id;
2242
+ const resumeVerb = this.lifecycleMenu?.state === "stopped" ? "start" : "unpause";
2243
+ this.busy = true;
2244
+ this.menu = null;
2245
+ this.lifecycleMenu = null;
2246
+ this.createMenu = null;
2247
+ this.placeholder = ["", which === "resume" ? " Resuming\u2026" : " Destroying\u2026"];
2248
+ this.prevRows = null;
2249
+ this.drawChrome();
2250
+ this.scheduleRender();
2251
+ try {
2252
+ if (which === "resume") {
2253
+ await this.deps.resumeBox(id);
2254
+ if (this.selectedId !== id || this.tornDown) return;
2255
+ await this.refreshBoxes();
2256
+ await this.spawnActive();
2257
+ } else {
2258
+ await this.deps.destroyBox(id);
2259
+ if (this.tornDown) return;
2260
+ await this.refreshBoxes();
2261
+ if (this.boxes[0]) this.selectedId = this.boxes[0].id;
2262
+ await this.spawnActive();
2263
+ this.flash(`destroyed ${name}`);
2264
+ }
2265
+ } catch (err) {
2266
+ if (this.selectedId !== id || this.tornDown) return;
2267
+ const msg = err instanceof Error ? err.message : String(err);
2268
+ const verb = which === "resume" ? resumeVerb : "destroy";
2269
+ this.placeholder = [
2270
+ "",
2271
+ ` Failed to ${verb} ${name}:`,
2272
+ ` ${msg}`,
2273
+ "",
2274
+ ` Try from a shell: agentbox ${verb} ${name}`
2275
+ ];
2276
+ this.prevRows = null;
2277
+ this.scheduleRender();
2278
+ } finally {
2279
+ this.busy = false;
2280
+ }
2281
+ }
2179
2282
  handleCreateMenuKey(bytes) {
2180
2283
  for (const b of bytes) {
2181
2284
  if (b === 99 || b === 13 || b === 10) {
@@ -2300,6 +2403,17 @@ var Compositor = class {
2300
2403
  let s = SYNC_BEGIN + "\x1B[?25l";
2301
2404
  for (let i = 0; i < r.h; i++) s += cursorTo2(r.x, r.y + i) + "\x1B[0m" + (lines[i] ?? "");
2302
2405
  this.out.write(s + SYNC_END);
2406
+ } else if (this.lifecycleMenu) {
2407
+ const lines = lifecycleMenuLines(
2408
+ this.lifecycleMenu.boxName,
2409
+ this.lifecycleMenu.state,
2410
+ this.lifecycleMenu.confirmDestroy,
2411
+ r.w,
2412
+ r.h
2413
+ );
2414
+ let s = SYNC_BEGIN + "\x1B[?25l";
2415
+ for (let i = 0; i < r.h; i++) s += cursorTo2(r.x, r.y + i) + "\x1B[0m" + (lines[i] ?? "");
2416
+ this.out.write(s + SYNC_END);
2303
2417
  } else if (this.createMenu) {
2304
2418
  const lines = createMenuLines(this.createMenu.where, r.w, r.h);
2305
2419
  let s = SYNC_BEGIN + "\x1B[?25l";
@@ -2437,6 +2551,9 @@ var dashboardCommand = new Command7("dashboard").description("Box list + the sel
2437
2551
  if (boxId === NEW_BOX_ID) return { kind: "create-menu", where: project.root };
2438
2552
  const box = (await listBoxes()).find((b) => b.id === boxId);
2439
2553
  if (!box) return { kind: "placeholder", lines: ["", " box not found"] };
2554
+ if (box.state === "paused" || box.state === "stopped") {
2555
+ return { kind: "lifecycle-menu", state: box.state };
2556
+ }
2440
2557
  if (box.state !== "running") {
2441
2558
  return {
2442
2559
  kind: "placeholder",
@@ -2552,6 +2669,15 @@ var dashboardCommand = new Command7("dashboard").description("Box list + the sel
2552
2669
  detach(process.execPath, [process.argv[1], "code", box.name, "--no-wait"]);
2553
2670
  return "Launching VS Code / Cursor\u2026";
2554
2671
  };
2672
+ const resumeBox = async (boxId) => {
2673
+ const box = (await listBoxes()).find((b) => b.id === boxId);
2674
+ if (!box) throw new Error("box not found");
2675
+ if (box.state === "paused") await unpauseBox(box.id);
2676
+ else await startBox(box.id);
2677
+ };
2678
+ const destroyBoxAction = async (boxId) => {
2679
+ await destroyBox(boxId);
2680
+ };
2555
2681
  const compositor = new Compositor(
2556
2682
  {
2557
2683
  ptySpawn,
@@ -2561,6 +2687,8 @@ var dashboardCommand = new Command7("dashboard").description("Box list + the sel
2561
2687
  startClaude,
2562
2688
  openShell,
2563
2689
  createNewBox,
2690
+ resumeBox,
2691
+ destroyBox: destroyBoxAction,
2564
2692
  openVnc,
2565
2693
  openCode,
2566
2694
  openWeb
@@ -2745,28 +2873,40 @@ function renderTable(boxes, stream) {
2745
2873
  (row2) => row2.map((cell, i) => padCell(cell ?? plain(""), i)).join(" ").trimEnd()
2746
2874
  ).join("\n");
2747
2875
  }
2748
- async function buildListText() {
2876
+ async function scopedBoxes(all) {
2749
2877
  const boxes = await listBoxes();
2750
- if (boxes.length === 0) return "no boxes \u2014 run `agentbox create` to make one";
2878
+ if (all) return { boxes, projectRoot: "", scoped: false };
2879
+ const { root } = await findProjectRoot(process.cwd());
2880
+ return { boxes: boxes.filter((b) => b.projectRoot === root), projectRoot: root, scoped: true };
2881
+ }
2882
+ async function buildListText(all) {
2883
+ const { boxes, projectRoot, scoped: scoped2 } = await scopedBoxes(all);
2884
+ if (boxes.length === 0) {
2885
+ if (scoped2) {
2886
+ return `no boxes in this project (${projectRoot}) \u2014 run \`agentbox create\`, or \`agentbox list --all\` to see all`;
2887
+ }
2888
+ return "no boxes \u2014 run `agentbox create` to make one";
2889
+ }
2751
2890
  return renderTable(boxes, process.stdout);
2752
2891
  }
2753
2892
  var listCommand2 = withWatchOptions(
2754
- new Command9("list").alias("ls").description("List all known agent boxes").option("-j, --json", "machine-readable JSON output")
2893
+ new Command9("list").alias("ls").description("List agent boxes in the current project (-a for all)").option("-j, --json", "machine-readable JSON output").option("-a, --all", "include boxes from all projects")
2755
2894
  ).action(async (opts) => {
2756
2895
  if (opts.json && opts.watch) {
2757
2896
  log11.error("cannot combine --json with --watch");
2758
2897
  process.exit(2);
2759
2898
  }
2899
+ const all = opts.all ?? false;
2760
2900
  if (opts.watch) {
2761
- await watchRender(buildListText, opts.interval);
2901
+ await watchRender(() => buildListText(all), opts.interval);
2762
2902
  return;
2763
2903
  }
2764
2904
  if (opts.json) {
2765
- const boxes = await listBoxes();
2905
+ const { boxes } = await scopedBoxes(all);
2766
2906
  process.stdout.write(JSON.stringify(boxes, null, 2) + "\n");
2767
2907
  return;
2768
2908
  }
2769
- process.stdout.write(await buildListText() + "\n");
2909
+ process.stdout.write(await buildListText(all) + "\n");
2770
2910
  });
2771
2911
 
2772
2912
  // src/commands/logs.ts