diff --git a/bin/rclaude b/bin/rclaude index c238b96..8ab6d31 100755 --- a/bin/rclaude +++ b/bin/rclaude @@ -319,6 +319,13 @@ EOF _PICK_PY_SNIPPET='for _p in python3.13 python3.12 python3.11 python3; do _b=$(command -v "$_p" 2>/dev/null) || continue; "$_b" -c "import claude_code_batch_sdk" 2>/dev/null && PY="$_b" && break; done; [ -z "${PY:-}" ] && { echo "rclaude: no python with claude_code_batch_sdk found" >&2; exit 2; }' _REMOTE_TRIAGE_BOOT='export PATH=$HOME/.local/bin:/opt/homebrew/bin:$PATH; '"$_PICK_PY_SNIPPET"';' +# Keepalive options for interactive ssh -t sessions. Sends a keepalive every +# 30s; tolerates 6 consecutive failures (~3 min of network blip) before the +# transport drops. Pair with `tmux new-session -A` below so a manual reconnect +# (re-running cc/rclaude resume) lands back in the same tmux session — the +# work itself is already protected by tmux on the remote. +_SSH_LIVE_OPTS='-o ServerAliveInterval=30 -o ServerAliveCountMax=6 -o TCPKeepAlive=yes' + # Run the triage helper on with the supplied extra args. Stdout is the # raw TSV emitted by _claude-triage (one row per session). list_triage_on() { @@ -693,7 +700,7 @@ cmd_resume() { if is_local "$_host"; then exec tmux attach -t "$_target" else - exec ssh -t "$_host" tmux attach -t "$_target" + exec ssh -t $_SSH_LIVE_OPTS "$_host" tmux attach -t "$_target" fi ;; disk) @@ -907,4 +914,8 @@ fi sync_tmux_conf "$host" inner=$(build_inner "$dir") -exec ssh -t "$host" "tmux new-session -s '${session}' \"${inner}\"" +# `new-session -A` attaches if a session of that name already exists, so +# re-running rclaude after a broken pipe lands you back in the same tmux +# session instead of erroring with "duplicate session". Combined with +# _SSH_LIVE_OPTS this tolerates short network drops without losing work. +exec ssh -t $_SSH_LIVE_OPTS "$host" "tmux new-session -A -s '${session}' \"${inner}\""