fix(shell): launch shell tabs as an interactive login shell

Shell-mode sessions resolve to an absolute shell path (issue #208's
fix) but launch it bare, with no -i/-l flags. Without those, the
spawned shell runs as a non-interactive child of the non-interactive
`bash -c` that launches the pane, so it never sources ~/.zshrc or
~/.bashrc — silently dropping aliases, PATH additions, and tool init
(zoxide, nvm, etc.).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
timkjr
2026-08-04 17:12:28 -05:00
co-authored by Claude Sonnet 5
parent 529d8fa8ea
commit d66007053b
2 changed files with 13 additions and 1 deletions
+5 -1
View File
@@ -780,7 +780,11 @@ export function buildSpawnCommand(options: {
// SERVER process's env — empty in containers and system systemd units, leaving
// the pane command ending in a dangling `&&` ("syntax error: unexpected end of
// file", pane dead on arrival). Resolve it in Node and quote the result.
return shellescape(resolveLocalShell());
// -i -l: interactive login shell, so the resolved shell sources the user's rc
// files (~/.zshrc, ~/.bashrc, etc.) instead of running as a bare non-interactive
// child of the non-interactive `bash -c` that launches the pane — without this,
// aliases, PATH additions, and tool init (zoxide, nvm, etc.) are silently dropped.
return `${shellescape(resolveLocalShell())} -i -l`;
}
/**
+8
View File
@@ -88,6 +88,14 @@ describe('shell-mode spawn command (issue #208)', () => {
expect(cmd.trim()).not.toBe('');
});
it('launches an interactive login shell, so rc files (~/.zshrc, ~/.bashrc, etc.) are sourced', () => {
// Without -i -l, the resolved shell runs as a bare non-interactive child of
// the non-interactive `bash -c` that launches the pane, silently dropping
// aliases, PATH additions, and tool init (zoxide, nvm, etc.).
const cmd = buildSpawnCommand({ mode: 'shell', sessionId: 'abc123de-0000-0000-0000-000000000000' });
expect(cmd.trim().endsWith('-i -l')).toBe(true);
});
it('produces a launch command that parses after the outer sh -c expansion layer', () => {
const cmd = buildSpawnCommand({ mode: 'shell', sessionId: 'abc123de-0000-0000-0000-000000000000' });
// Mirrors tmux-manager: `… bash -c ${JSON.stringify(launchCmd)}` handed to `sh -c`.