@madarco/agentbox 0.4.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/{chunk-J35IH7W5.js → chunk-BBZMA2K6.js} +61 -23
  2. package/dist/chunk-BBZMA2K6.js.map +1 -0
  3. package/dist/{chunk-SOMIKEN2.js → chunk-HHMWQNLF.js} +272 -214
  4. package/dist/chunk-HHMWQNLF.js.map +1 -0
  5. package/dist/{chunk-IDR4HVIC.js → chunk-HPZMD5DE.js} +2 -2
  6. package/dist/chunk-HPZMD5DE.js.map +1 -0
  7. package/dist/{chunk-NSIECUCS.js → chunk-HTTKML3C.js} +705 -289
  8. package/dist/chunk-HTTKML3C.js.map +1 -0
  9. package/dist/{chunk-WR5FFGE5.js → chunk-KJNZP6I3.js} +218 -128
  10. package/dist/chunk-KJNZP6I3.js.map +1 -0
  11. package/dist/{chunk-FQD6ZWYW.js → chunk-M7I247BK.js} +68 -65
  12. package/dist/chunk-M7I247BK.js.map +1 -0
  13. package/dist/create-6PWXI6HO-OWAMHBAK.js +15 -0
  14. package/dist/index.js +2394 -1283
  15. package/dist/index.js.map +1 -1
  16. package/dist/{lifecycle-LURNDNYO-UWQYPNPX.js → lifecycle-EMXR46DI-DUVBXNTV.js} +5 -5
  17. package/dist/{state-ZSP3ORXW-WI6KOIG3.js → state-KD7M46ZP-KHFTHFUS.js} +2 -2
  18. package/dist/stats-SZXOJE3D-N7OODCHW.js +19 -0
  19. package/package.json +3 -2
  20. package/runtime/docker/Dockerfile.box +65 -25
  21. package/runtime/docker/apps/cli/share/agentbox-setup/SKILL.md +52 -55
  22. package/runtime/docker/packages/ctl/dist/bin.cjs +272 -160
  23. package/runtime/docker/packages/sandbox-docker/scripts/agentbox-checkpoint-cleanup +52 -0
  24. package/runtime/docker/packages/sandbox-docker/scripts/agentbox-dockerd-start +87 -7
  25. package/runtime/docker/packages/sandbox-docker/scripts/agentbox-open +28 -0
  26. package/runtime/docker/packages/sandbox-docker/scripts/custom-system-CLAUDE.md +21 -15
  27. package/runtime/relay/bin.cjs +407 -12
  28. package/share/agentbox-setup/SKILL.md +52 -55
  29. package/dist/chunk-FQD6ZWYW.js.map +0 -1
  30. package/dist/chunk-IDR4HVIC.js.map +0 -1
  31. package/dist/chunk-J35IH7W5.js.map +0 -1
  32. package/dist/chunk-NSIECUCS.js.map +0 -1
  33. package/dist/chunk-SOMIKEN2.js.map +0 -1
  34. package/dist/chunk-WR5FFGE5.js.map +0 -1
  35. package/dist/create-4BQY2UYU-CGSW3RGE.js +0 -15
  36. package/dist/stats-GZFLPYTU-DBJ2DVBJ.js +0 -19
  37. /package/dist/{create-4BQY2UYU-CGSW3RGE.js.map → create-6PWXI6HO-OWAMHBAK.js.map} +0 -0
  38. /package/dist/{lifecycle-LURNDNYO-UWQYPNPX.js.map → lifecycle-EMXR46DI-DUVBXNTV.js.map} +0 -0
  39. /package/dist/{state-ZSP3ORXW-WI6KOIG3.js.map → state-KD7M46ZP-KHFTHFUS.js.map} +0 -0
  40. /package/dist/{stats-GZFLPYTU-DBJ2DVBJ.js.map → stats-SZXOJE3D-N7OODCHW.js.map} +0 -0
@@ -1,9 +1,10 @@
1
1
  #!/usr/bin/env bash
2
2
  # Start the in-box dockerd. Launched by the host via
3
- # `docker exec -d --user root` after the FUSE overlay is up. Idempotent — safe
4
- # to call again on `agentbox start`. Storage driver is fuse-overlayfs (set in
5
- # /etc/docker/daemon.json baked into the image) so the inner daemon doesn't
6
- # need the kernel `overlay` driver, which an unprivileged container can't load.
3
+ # `docker exec -d --user root`. Idempotent safe to call again on
4
+ # `agentbox start`. The storage driver is selected at runtime (see
5
+ # select_storage_driver below): the kernel-native `overlay2` when a probe
6
+ # proves it works on the data-root filesystem, otherwise `fuse-overlayfs`.
7
+ # The chosen driver is written to /etc/docker/daemon.json before launch.
7
8
 
8
9
  set -euo pipefail
9
10
 
@@ -33,14 +34,93 @@ rm -f /var/run/docker.pid /var/run/docker.sock
33
34
  mount -o remount,rw /sys/fs/cgroup 2>/dev/null || true
34
35
  mount -o remount,rw /proc/sys 2>/dev/null || true
35
36
 
37
+ # --- Storage-driver selection -------------------------------------------------
38
+ # The inner dockerd's data root (/var/lib/docker, a Docker named volume) used
39
+ # to be pinned to fuse-overlayfs. fuse-overlayfs is broken on recent kernels
40
+ # (e.g. Docker Desktop's 6.x linuxkit kernel): inner `docker run` fails at
41
+ # execve() with "exec ...: invalid argument". The kernel-native overlay2
42
+ # driver works when the data-root filesystem can carry an overlay mount, which
43
+ # the ext4 named volume can. We pick overlay2 when a probe proves it works,
44
+ # else fall back to fuse-overlayfs.
45
+ #
46
+ # dockerd refuses to switch drivers once its data root is populated, so if the
47
+ # data root is already initialized under one driver we reuse that driver and
48
+ # skip the probe — a box created under one driver never switches.
49
+ DOCKER_DATA_ROOT=/var/lib/docker
50
+ DAEMON_JSON=/etc/docker/daemon.json
51
+
52
+ probe_overlay2() {
53
+ # The kernel overlay filesystem has to exist at all.
54
+ grep -qw overlay /proc/filesystems 2>/dev/null || return 1
55
+
56
+ local probe lower upper work merged ok=1
57
+ # The probe dir MUST live inside the data root so the test overlay is mounted
58
+ # on the SAME filesystem the real graph will use. A probe under /tmp would
59
+ # test the container's overlayfs writable layer — the wrong filesystem.
60
+ probe="$(mktemp -d "$DOCKER_DATA_ROOT/.overlay2-probe.XXXXXX" 2>/dev/null)" || return 1
61
+ lower="$probe/lower"; upper="$probe/upper"; work="$probe/work"; merged="$probe/merged"
62
+ mkdir -p "$lower" "$upper" "$work" "$merged" || { rm -rf "$probe"; return 1; }
63
+
64
+ # Stage a known-good executable so the merged view exposes it.
65
+ cp /bin/true "$lower/probe-bin" 2>/dev/null || { rm -rf "$probe"; return 1; }
66
+ chmod 0755 "$lower/probe-bin" 2>/dev/null || true
67
+
68
+ if mount -t overlay overlay \
69
+ -o "lowerdir=$lower,upperdir=$upper,workdir=$work" "$merged" 2>/dev/null; then
70
+ # The actual fuse-overlayfs failure mode: execve from the merged dir. A
71
+ # successful mount is not enough — fuse-overlayfs mounts fine and only
72
+ # fails here.
73
+ "$merged/probe-bin" >/dev/null 2>&1 || ok=0
74
+ umount "$merged" 2>/dev/null || umount -l "$merged" 2>/dev/null || true
75
+ else
76
+ ok=0
77
+ fi
78
+ rm -rf "$probe"
79
+ [ "$ok" = 1 ]
80
+ }
81
+
82
+ select_storage_driver() {
83
+ # 1. Reuse an already-initialized data root's driver — dockerd cannot switch
84
+ # a populated data root, and this script reruns on every `agentbox start`.
85
+ local has_overlay2=0 has_fuse=0
86
+ [ -d "$DOCKER_DATA_ROOT/overlay2" ] \
87
+ && [ -n "$(ls -A "$DOCKER_DATA_ROOT/overlay2" 2>/dev/null)" ] && has_overlay2=1
88
+ [ -d "$DOCKER_DATA_ROOT/fuse-overlayfs" ] \
89
+ && [ -n "$(ls -A "$DOCKER_DATA_ROOT/fuse-overlayfs" 2>/dev/null)" ] && has_fuse=1
90
+ if [ "$has_overlay2" = 1 ]; then echo "overlay2"; return 0; fi
91
+ if [ "$has_fuse" = 1 ]; then echo "fuse-overlayfs"; return 0; fi
92
+
93
+ # 2. Fresh data root: probe overlay2 against the data-root filesystem.
94
+ if probe_overlay2; then echo "overlay2"; return 0; fi
95
+ echo "fuse-overlayfs"
96
+ }
97
+
98
+ # Sweep any leaked probe dir from a hard-killed previous run (cosmetic; the
99
+ # driver subdir checks above ignore it, and dockerd ignores non-driver dirs).
100
+ rm -rf "$DOCKER_DATA_ROOT"/.overlay2-probe.* 2>/dev/null || true
101
+
102
+ STORAGE_DRIVER="$(select_storage_driver)"
103
+
104
+ # Write daemon.json with the resolved driver. `iptables: true` stays for inner
105
+ # bridge networking. Rewritten every start, but the driver is stable (step 1
106
+ # above), so this never causes a mid-life driver switch.
107
+ mkdir -p /etc/docker
108
+ printf '%s\n' \
109
+ "{ \"storage-driver\": \"$STORAGE_DRIVER\", \"iptables\": true }" \
110
+ > "$DAEMON_JSON"
111
+ # Truncate dockerd.log fresh for this start, marker line first; dockerd appends.
112
+ echo "agentbox-dockerd-start: storage-driver=$STORAGE_DRIVER" \
113
+ > /var/log/agentbox/dockerd.log
114
+ # --- end storage-driver selection --------------------------------------------
115
+
36
116
  # nohup + & + disown lets us survive the `docker exec -d` returning. dockerd
37
117
  # reads /etc/docker/daemon.json on its own; no flags here keeps the start path
38
118
  # debuggable from inside the container (just edit the file and restart).
39
- nohup dockerd >/var/log/agentbox/dockerd.log 2>&1 &
119
+ nohup dockerd >>/var/log/agentbox/dockerd.log 2>&1 &
40
120
 
41
121
  # Wait for the socket to become accept()-able. Bound by ~30s — first start has
42
- # to initialize iptables chains and the fuse-overlayfs graphdriver, which is
43
- # noticeably slower than overlay2.
122
+ # to initialize iptables chains and the storage graphdriver (fuse-overlayfs is
123
+ # noticeably slower to initialize than overlay2).
44
124
  for _ in $(seq 1 300); do
45
125
  if [ -S /var/run/docker.sock ] \
46
126
  && docker -H unix:///var/run/docker.sock info >/dev/null 2>&1; then
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env bash
2
+ # Routes in-box URL opens to the *host's* default browser via the agentbox
3
+ # relay. The box has no real browser of its own. This script is installed at
4
+ # /usr/local/bin (earlier in PATH than xdg-utils' /usr/bin/xdg-open, which it
5
+ # is also symlinked over) and is the box's $BROWSER, so `xdg-open`, Claude
6
+ # Code's OAuth flow, `gh`, `git web--browse`, python's webbrowser, etc. all
7
+ # land here.
8
+ #
9
+ # Only http(s) URLs are forwarded to the host. Anything else (a file path,
10
+ # another scheme) falls through to the real xdg-open, which resolves it
11
+ # locally inside the box.
12
+
13
+ set -uo pipefail
14
+
15
+ target="${1:-}"
16
+
17
+ case "$target" in
18
+ http://* | https://*)
19
+ exec agentbox-ctl open "$target"
20
+ ;;
21
+ *)
22
+ if [[ -x /usr/bin/xdg-open ]]; then
23
+ exec /usr/bin/xdg-open "$@"
24
+ fi
25
+ echo "agentbox-open: not an http(s) URL: $target" >&2
26
+ exit 1
27
+ ;;
28
+ esac
@@ -1,21 +1,27 @@
1
1
  # AgentBox sandbox
2
2
 
3
3
  You are running inside an AgentBox sandbox: a Linux Docker container with
4
- docker-in-docker (run `docker` directly, no sudo). The host filesystem is
5
- mounted read-only at /host-src; /workspace is a FUSE overlay where your
6
- writes go to a per-box volume.
4
+ docker-in-docker (run `docker` directly, no sudo).
5
+ Your user is `vscode` and you can use passwordless **sudo** to run commands as root.
6
+ `/workspace` is your own per-box git worktree on branch `agentbox/<box-name>`:
7
+ writes there stay in the container's writable layer and don't touch the host's working
8
+ tree.
7
9
 
8
- This container has no SSH credentials and no host gitconfig identity.
9
- For git operations that need the user (push, pull from private remotes),
10
- use `agentbox-ctl git pull|push -- <args>` — it RPCs to the host, which
11
- runs git with the real SSH agent and gitconfig. Local commits work as
12
- normal because the main `.git/` is bind-mounted at the same absolute
13
- path as on the host.
10
+ You can save the current filesystem state to be reused by future boxes by
11
+ running `agentbox-ctl checkpoint --set-default`. This doesn't need to be confirmed by the user.
14
12
 
15
- Your `~/.claude` and `/workspace` env files live only in this box. If
16
- you install a skill/plugin (or otherwise change `~/.claude`), tell the
17
- user to run `agentbox pull claude` on the host to copy it back. If you
18
- create or change `.env`/`.envrc`/secrets files, tell them to run
19
- `agentbox pull env`. Both are additive and never overwrite host files.
13
+ The main `.git/` is bind-mounted at the same absolute path as on
14
+ the host, so local commits show up in the host's `git log` immediately.
15
+ No SSH creds, no host gitconfig identity. For ops that need the user
16
+ (push, fetch from private remotes), use `agentbox-ctl git push|fetch|pull
17
+ -- <args>` it RPCs to the host, which runs git with the real SSH agent.
20
18
 
21
- Box identity is in /etc/agentbox/box.env and the AGENTBOX_* env vars.
19
+ For ad-hoc file transfers between this box and the host, use
20
+ `agentbox-ctl cp toHost <boxPath> <hostPath>` and
21
+ `agentbox-ctl cp fromHost <hostPath> <boxPath>` or `agentbox-ctl download claude` / `download env` /
22
+ `download config`. They RPC to the host and
23
+ ask the user for confirmation on the wrapper that runs `agentbox claude`;
24
+ deny returns exit 10 (`denied by user`).
25
+ Don't put any timeout on the command, it will run forever and the user will be notified through multiple channels.
26
+
27
+ Box identity: /etc/agentbox/box.env and the AGENTBOX_* env vars.