diff --git a/bin/crc b/bin/crc index 457740a..64dc725 100755 --- a/bin/crc +++ b/bin/crc @@ -110,20 +110,29 @@ else esac fi -# tmux session name: stable, derived from the dir. tmux forbids '.' and ':'. -slug=$(printf %s "$slug_src" | tr '[:upper:]' '[:lower:]' | sed -e 's#[^a-z0-9]\{1,\}#-#g' -e 's#^-##' -e 's#-$##') -[ -n "$slug" ] || slug='home' -session="claude-rc-${slug}" +# tmux session name: a --session override (sanitized — tmux forbids '.' and +# ':'), else stable and derived from the dir. +if [ -n "$session_override" ]; then + session=$(printf %s "$session_override" | tr '.:' '--') +else + slug=$(printf %s "$slug_src" | tr '[:upper:]' '[:lower:]' | sed -e 's#[^a-z0-9]\{1,\}#-#g' -e 's#^-##' -e 's#-$##') + [ -n "$slug" ] || slug='home' + session="claude-rc-${slug}" +fi # --- build the remote bootstrap (base64'd to survive all quoting layers) ---- -# Decoded and run by `sh` on the far side. Computes DIR, validates it, then -# exec's tmux new-session -A (attach-or-create) running `claude rc` under a -# login shell so ~/.local/bin (where claude lives) is on PATH. +# Decoded and run by `sh` on the far side. Resolves DIR, validates it, then +# starts `claude rc` in a tmux session under a login shell (so ~/.local/bin, +# where claude lives, is on PATH). tmux -c sets the session start-dir, avoiding +# a fragile inner `cd "$DIR"`. ENSURE=1 → start detached if absent, no attach. +# RESPAWN=1 → wrap claude rc in a restart loop so crashes self-heal. boot=$(cat </dev/null; then echo "crc: directory not found on host: \$DIR" >&2 exit 1 fi -exec tmux new-session -A -s "\$SESS" "\${SHELL:-/bin/sh} -lc 'cd \"\$DIR\" && exec claude rc \$RC_ARGS'" +SH=\${SHELL:-/bin/sh} +if [ "\$RESPAWN" = 1 ]; then + CMD="\$SH -lc 'while true; do claude rc \$RC_ARGS; sleep 3; done'" +else + CMD="\$SH -lc 'exec claude rc \$RC_ARGS'" +fi +if [ "\$ENSURE" = 1 ]; then + if tmux has-session -t "\$SESS" 2>/dev/null; then + echo "crc: \$SESS already running" >&2 + else + tmux new-session -d -c "\$DIR" -s "\$SESS" "\$CMD" && echo "crc: started detached \$SESS" >&2 + fi +else + exec tmux new-session -A -c "\$DIR" -s "\$SESS" "\$CMD" +fi BOOT ) boot_b64=$(printf %s "$boot" | base64 | tr -d '\n') @@ -141,7 +164,7 @@ boot_b64=$(printf %s "$boot" | base64 | tr -d '\n') run_remote="printf %s '${boot_b64}' | base64 -d | sh" echo "crc: ${session} → claude rc in ${abs:-\$HOME/${rel}} on ${host}" >&2 -echo "crc: detach with Ctrl-b d (server keeps running); reattach by re-running this command." >&2 +[ "$ensure" -eq 0 ] && echo "crc: detach with Ctrl-b d (server keeps running); reattach by re-running this command." >&2 if [ "$dry_run" -eq 1 ]; then echo "--- remote script ($host) ---" >&2 @@ -156,6 +179,7 @@ case "$host" in eval "$run_remote" ;; *) - exec ssh -t "$host" "$run_remote" + if [ "$ensure" -eq 1 ]; then exec ssh "$host" "$run_remote" + else exec ssh -t "$host" "$run_remote"; fi ;; esac