fix(remote-ssh): use remote user's real shell, keep dead panes alive

Remote shell-mode sessions hardcoded 'exec bash -l', ignoring the
remote user's actual login shell. sshd sets $SHELL from the remote
user's /etc/passwd entry, so 'exec $SHELL -i -l' launches their real
shell (zsh, fish, etc.) with rc files sourced, same fix as the local
shell-mode launch.

Also set remain-on-exit on the remote tmux session. It was only ever
set on the local socket, so if the remote command exited for any
reason -- even something transient -- tmux destroyed the pane, window,
and (being the only session) the whole remote server, tearing down the
local ssh attach along with it and leaving no trace to diagnose. The
local pane saw this as an instant clean exit, and reconnect's -A then
created a fresh session, which could repeat as a flap loop with no
evidence surviving between attempts.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
timkjr
2026-08-04 16:39:29 -05:00
co-authored by Claude Sonnet 5
parent 529d8fa8ea
commit 474efd9023
5 changed files with 18 additions and 4 deletions
+1 -1
View File
@@ -55,7 +55,7 @@ describe('remote-hosts domain', () => {
});
it('returns safe mode defaults and remote display values', () => {
expect(defaultRemoteCommandForMode('shell')).toBe('exec bash -l');
expect(defaultRemoteCommandForMode('shell')).toBe('exec $SHELL -i -l');
expect(defaultRemoteCommandForMode('codex')).toBe('exec codex');
// Mirrors the local claude default so the remote agent runs non-interactively.
expect(defaultRemoteCommandForMode('claude')).toBe('exec claude --dangerously-skip-permissions');
+2 -1
View File
@@ -150,9 +150,10 @@ describe('COD-107 buildRemoteLaunchCommand — threads connection args', () => {
const sh = (s: string) => "'" + s.replace(/'/g, "'\\''") + "'";
const remoteName = `codeman-ssh-${SESSION_ID.slice(0, 8)}`;
const path = sh('/home/ubuntu/work');
const paneCommand = `cd ${path} && exec bash -l`;
const paneCommand = `cd ${path} && exec $SHELL -i -l`;
const tmuxInvocation = [
`tmux -L codeman-remote new-session -A -s ${remoteName} -c ${path} ${sh(paneCommand)}`,
`set -t ${remoteName} remain-on-exit on`,
`set -t ${remoteName} status off`,
`set -t ${remoteName} mouse off`,
`set -t ${remoteName} prefix C-q`,
+2 -1
View File
@@ -137,7 +137,8 @@ describe('TmuxManager (unit)', () => {
sessionId: 'abc123def456',
});
expect(command).toContain('exec bash -l');
expect(command).toContain('exec $SHELL -i -l');
expect(command).toContain('remain-on-exit on');
});
it('defaults claude to a non-interactive launch (--dangerously-skip-permissions)', () => {