diff --git a/src/main/runtime/command-finished-launch-authority.test.ts b/src/main/runtime/command-finished-launch-authority.test.ts index bfda7ad05a5..fdd21b20c6a 100644 --- a/src/main/runtime/command-finished-launch-authority.test.ts +++ b/src/main/runtime/command-finished-launch-authority.test.ts @@ -27,4 +27,12 @@ describe('shouldRetireLaunchAuthorityOnCommandFinished', () => { expect(shouldRetireLaunchAuthorityOnCommandFinished('node')).toBe(false) expect(shouldRetireLaunchAuthorityOnCommandFinished('python3')).toBe(false) }) + // Why: the guard requires a *known* shell, so a user on ksh/dash/tcsh could + // never settle launched-agent authority until the pty itself exited. + it.each(['ksh', 'dash', 'tcsh', 'csh', 'ash', 'mksh', 'elvish', 'xonsh'])( + 'settles launch authority when the foreground shell is %s', + (shell) => { + expect(shouldRetireLaunchAuthorityOnCommandFinished(shell)).toBe(true) + } + ) }) diff --git a/src/main/runtime/orca-runtime.ts b/src/main/runtime/orca-runtime.ts index de28bc2eebb..21b7ab11687 100644 --- a/src/main/runtime/orca-runtime.ts +++ b/src/main/runtime/orca-runtime.ts @@ -15273,6 +15273,10 @@ export class OrcaRuntimeService { this.markPtyLivenessUnverifiable(ptyId, SSH_EXIT_UNCONFIRMED_REASON) } this.restoredOrchestrationAuthorityByPtyId.delete(ptyId) + // Why: launch authority is deliberately preserved here (unverifiable, not + // exited), but the settle-generation counter is bookkeeping for an + // in-flight command-finished check that can no longer land. + this.launchAuthorityCommandFinishedGenerationByPtyId.delete(ptyId) } else { this.retirePtyAgentLaunchAuthority(ptyId) } diff --git a/src/shared/shell-process-detection.ts b/src/shared/shell-process-detection.ts index 0ae76e42673..9a69fa98369 100644 --- a/src/shared/shell-process-detection.ts +++ b/src/shared/shell-process-detection.ts @@ -2,7 +2,9 @@ // renderer (agent-ready-wait, new-workspace). A bare shell is the negative // signal for "is an agent running" because it garbles injected preambles. const SHELL_NAMES = new Set( - '|bash|zsh|sh|fish|cmd|cmd.exe|powershell|powershell.exe|pwsh|pwsh.exe|nu'.split('|') + '|bash|zsh|sh|fish|cmd|cmd.exe|powershell|powershell.exe|pwsh|pwsh.exe|nu|ksh|mksh|dash|ash|tcsh|csh|elvish|xonsh'.split( + '|' + ) ) const WINDOWS_PROCESS_EXTENSION_RE = /\.(?:exe|cmd|bat|ps1)$/i