forked from heavy-duty/box
feat: 'claudebox tmux <box> [session]' — a shell that survives you
'shell' is a child of the exec connection: drop the terminal and a long Claude run inside it is SIGHUP'd — which has already cost one run. tmux is installed in every box but relying on remembering to start it is how that run was lost. New verb, not a changed default: 'tmux new-session -A -s <session>' attaches when the session exists and creates it when it doesn't, so starting work and reattaching after a disconnect are the same command. The session name (default: main) gives parallel streams in one box. 'shell' stays bare on purpose — two verbs, two contracts — so tmux's costs (nesting, scrollback semantics, exit-vs-detach) are only paid when asked for. Closes #6
This commit is contained in:
parent
f241b1f27a
commit
eacb1a9e28
2 changed files with 32 additions and 0 deletions
|
|
@ -82,6 +82,7 @@ claudebox list # list your boxes
|
|||
claudebox info <box> # one box: state, IP, snapshot labels
|
||||
claudebox shell <box> # enter as the claude user
|
||||
claudebox exec <box> -- <cmd...> # run a command in the box
|
||||
claudebox tmux <box> [session] # attach/create a tmux session — survives disconnects
|
||||
claudebox snapshot <box> [label] # checkpoint (label defaults to manual-<epoch>)
|
||||
claudebox restore <box> <snap> # roll back to a snapshot
|
||||
claudebox rename <box> <new> # rename a box (stop it first)
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ CMDS=(
|
|||
"info^<box> [--json]^box^One box: state, type, IP, and its snapshot labels^fn:cmd_info^"
|
||||
"shell^<box>^box^Open a shell in a box, as the claude user^fn:cmd_shell^"
|
||||
"exec^<box> -- <cmd...>^box^Run a command inside a box^fn:cmd_exec^"
|
||||
"tmux^<box> [<session>]^box^Attach or create a tmux session in a box — survives disconnects^fn:cmd_tmux^"
|
||||
"snapshot^<box> [<label>]^box^Checkpoint a box (label defaults to manual-<epoch>)^fn:cmd_snapshot^"
|
||||
"restore^<box> <snapshot>^box,arg2^Roll a box back to one of its snapshots^incus:restore^restored {} to {1}"
|
||||
"rename^<box> <new-name>^box,arg2,stopped^Rename a box (it must be stopped first)^incus:rename^renamed {} to {1}"
|
||||
|
|
@ -227,6 +228,23 @@ flags as its own.
|
|||
claudebox exec work -- git -C project pull
|
||||
claudebox exec work -- claude --version
|
||||
EOF
|
||||
;;
|
||||
tmux) cat <<'EOF'
|
||||
A shell that survives you. 'shell' is a child of the exec connection — if your
|
||||
terminal or SSH session drops, everything running in it is SIGHUP'd, and a
|
||||
long Claude run dies with it. This attaches a tmux session instead
|
||||
(new-session -A): created if new, reattached if it exists — so starting work
|
||||
and resuming after a disconnect are the same command, with no state to
|
||||
remember.
|
||||
|
||||
The session name (default: main) buys parallel streams in one box:
|
||||
|
||||
claudebox tmux work # attach or create 'main'
|
||||
claudebox tmux work run-1 # a second, independent stream, same box
|
||||
|
||||
Detach with Ctrl-b d; 'exit' ends the session. For a plain shell with none of
|
||||
tmux's semantics, 'claudebox shell' is unchanged.
|
||||
EOF
|
||||
;;
|
||||
snapshot) cat <<'EOF'
|
||||
Checkpoint a box. Snapshots are how an authenticated box is reused: log in
|
||||
|
|
@ -572,6 +590,19 @@ cmd_info() {
|
|||
cmd_shell() { incus exec "$inst" -- sudo -u claude -i; }
|
||||
cmd_exec() { incus exec "$inst" -- sudo -u claude -i "${args[@]:1}"; }
|
||||
|
||||
# A shell is a child of the exec connection: drop the terminal and everything
|
||||
# in it is SIGHUP'd — a long Claude run dies with it. tmux 'new-session -A'
|
||||
# attaches when the session exists and creates it when it doesn't, so starting
|
||||
# work and reattaching after a disconnect are the same command. 'shell' stays
|
||||
# bare on purpose — two verbs, two contracts.
|
||||
cmd_tmux() {
|
||||
local session="${args[1]:-main}"
|
||||
case "$session" in
|
||||
*[!A-Za-z0-9_-]*) usage_error "session names are letters, digits, '-' and '_' — got '$session'" ;;
|
||||
esac
|
||||
incus exec "$inst" -- sudo -u claude -i tmux new-session -A -s "$session"
|
||||
}
|
||||
|
||||
cmd_snapshot() {
|
||||
local label="${args[1]:-manual-$(date +%s)}"
|
||||
incus snapshot create "$inst" "$label"
|
||||
|
|
|
|||
Loading…
Reference in a new issue