Skip to content

Feat/linux host support#33

Merged
madarco merged 11 commits into
mainfrom
feat/linux-host-support
May 31, 2026
Merged

Feat/linux host support#33
madarco merged 11 commits into
mainfrom
feat/linux-host-support

Conversation

@madarco
Copy link
Copy Markdown
Owner

@madarco madarco commented May 31, 2026

Note

Medium Risk
Prefixed box ids change the shape of new records (existing boxes unchanged); Linux xdg-open and Vercel provision builds are broad but mostly additive; the release-notes publish path is irreversible if misused.

Overview
This PR extends running the CLI on Linux hosts and polishes launch UX across docker and cloud.

Linux host: New hostOpenCommand() (xdg-open on Linux, open elsewhere) replaces hardcoded open across CLI commands, relay browser mirroring, credential dashboards, and docker export reveal. agentbox doctor now treats Linux as supported, with docker install/daemon hints tuned for permission-denied vs daemon-down. Docs and scripts/linux-dev-vm.sh document testing on a persistent Ubuntu VM.

After box create: printLaunchRecap shows one bordered card (box, project path, branch mapping, attach/detach hint) for claude/codex/opencode and cloud create, instead of scattered log lines and separate outro messages.

IDs: New boxes get ids via shared generateBoxId() with a b prefix so all-hex ids cannot collide with numeric project-index refs (agentbox open 4).

Attach UX: Wrapped-PTY input router re-emits the exact Ctrl+V bytes (including kitty/modifyOtherKeys sequences) after host→box image paste. Terminal spawn notes no longer repeat detach help (recap carries it).

Vercel / AL2023: provision.sh builds xclip and autocutsel from source for clipboard paste and VNC sync.

Other: /release-notes can optionally bump, commit, tag, push, and npm publish when given patch/minor/major. Marketing site adds favicons/manifest; apps/web/CLAUDE.md documents the static site layout.

Reviewed by Cursor Bugbot for commit 3ca0b19. Configure here.

madarco added 10 commits May 30, 2026 23:18
Make `agentbox doctor` Linux-accurate and add tooling to test the CLI on a
real Ubuntu host.

doctor (apps/cli/src/lib/doctor-checks.ts):
- checkPlatform() warns on unsupported OS (darwin/linux -> ok, else warn)
- docker-cli not-found hint is platform-specific (Linux docs link)
- docker daemon check distinguishes 'permission denied' (user not in the
  docker group) from a stopped daemon, with the matching fix as a hint

tooling:
- scripts/linux-dev-vm.sh: manage a persistent Hetzner Ubuntu VM
  (up/deploy/ssh/doctor/info/down) to test agentbox on Linux
- docs/linux-host-backlog.md: status + how-to + remaining macOS-only host
  assumptions (browser open->xdg-open, iTerm2/AppleScript, OrbStack paths)

Verified live on a clean Ubuntu 24.04 Hetzner VM: both the permission-denied
and healthy docker-daemon branches render correctly; no macOS regression.
Add hostOpenCommand() to @agentbox/sandbox-core (darwin -> open, linux ->
xdg-open) so opening a URL/path works on a Linux host, with a unit test.

Use it in the daytona/vercel/hetzner login dashboard openers, which were
hardcoded to the macOS `open` command (a no-op/error on Linux). First step of
the docs/linux-host-backlog.md 'browser open' item.
Swap the remaining hardcoded macOS `open` launchers to hostOpenCommand()
(open on macOS, xdg-open on Linux) so they work on a Linux host:

- apps/cli: url, screen, code (CLI-missing fallback), open (sshfs reveal),
  dashboard (VNC/web/code openers)
- relay: box-initiated 'open link on host' (host-actions.ts, server.ts)
- sandbox-docker: checkpoint/export reveal (host-export.ts)

Completes the docs/linux-host-backlog.md 'browser open' item (moved to Done).
Box ids were randomBytes(4).toString('hex') (8 hex chars), so ~2.3% came
out all decimal digits (e.g. 26524695). resolveBoxRef treats a bare
positive integer as a per-project index only and never falls through to
id match, so an all-digit id was unresolvable — breaking any id-targeting
command (surfaced via the relay's `checkpoint create <boxId>` in the
hetzner setup wizard).

Fix at the source: tag ids with a leading non-digit. New shared
@agentbox/core generateBoxId() returns `b`+8hex, used by both id mints
(docker create + cloud-provider, covering daytona/hetzner/vercel). Keeps
the clean "numeric ref = index" invariant and sets up a typed-id
namespace (b=box, room for c=checkpoint).
tmux is detected via $TMUX on every host, so attach-in-new-window works on
Linux inside tmux; iTerm2/AppleScript stays macOS-only and native Linux
emulators are out of scope for now (falls back to same-terminal attach).
Correct the now-stale 'CLI is macOS-only' comment in terminal/host.ts and move
the terminal item from open-blockers to a documented decision.
…tach hint)

Replaces the scattered id/provider/sandboxId rows and split detach hints with one bordered clack note showing box name (+source checkpoint), project folder (the agentbox.yaml dir, home-shortened), the from->to branch mapping, and the detach/reattach instruction. Shared by claude/codex/opencode across docker and cloud via printLaunchRecap.
clack's note() dims every body line; prefix each with reset + bright-white (honoring NO_COLOR) so the recap reads in plain white. strip-ansi padding is unaffected, so box alignment stays correct.
Two independent breaks in the host->box image-paste chain on the vercel
provider, both fixed:

1. Box side: the AL2023 bake never installed xclip/autocutsel (not in the
   AL2023 repos, unlike the Debian/Ubuntu apt path on docker/hetzner), so the
   in-box loadClipboardScript's xclip call failed silently. provision.sh now
   builds both from source (all build deps are in the AL2023 default repos),
   fail-loud. Requires a re-`prepare --provider vercel`.

2. Host side: the wrapped-PTY input router intercepted Ctrl+V only as the raw
   0x16 byte, while the Ctrl+a leader already handled the enhanced-keyboard
   (kitty / modifyOtherKeys) CSI-u encoding. When the inner app negotiates that
   protocol, the terminal sends Ctrl+V as ESC[118;5u, which slipped past the
   paste check -> forwarded verbatim, Claude read its own empty clipboard.
   Mirror the leader handling: intercept the CSI-u form too and re-emit the
   original sequence after the image loads. Provider-agnostic (hardens
   docker/daytona/hetzner against the same latent gap).

Verified: input-router unit tests cover both encodings; live vercel attach
pastes [Image #1] for both raw 0x16 and ESC[118;5u.
@vercel
Copy link
Copy Markdown

vercel Bot commented May 31, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agentbox-web Ready Ready Preview, Comment May 31, 2026 11:10am

Request Review

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 3ca0b19. Configure here.

Comment thread .claude/scheduled_tasks.lock Outdated
@@ -0,0 +1 @@
{"sessionId":"c356b96e-e5f8-4246-91cd-ca98dc6e88c3","pid":2752,"procStart":"Sat May 30 08:34:50 2026","acquiredAt":1780214836229} No newline at end of file
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accidentally committed session-specific lock file

Low Severity

The .claude/scheduled_tasks.lock file contains a session-specific sessionId, pid, procStart timestamp, and acquiredAt value from a specific development session (May 30, 2026). This is a runtime lock file that doesn't belong in version control — it will conflict across contributors and carries no useful repository state. It's also not covered by .gitignore.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 3ca0b19. Configure here.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 590e364git rm --cached the lock file and added .claude/scheduled_tasks.lock to .gitignore (keeping .claude/commands/ tracked). It was committed inadvertently in 3ca0b19.

Session-specific runtime lock (sessionId/pid/timestamps) accidentally
committed in 3ca0b19; it conflicts across contributors and carries no
repo state. Flagged by Cursor Bugbot on PR #33.
@madarco madarco merged commit 7359328 into main May 31, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant