From fe5cd52fc7c016b51df67f90375b043cdfc41315 Mon Sep 17 00:00:00 2001 From: Jinjing <6427696+AmethystLiang@users.noreply.github.com> Date: Sun, 5 Jul 2026 22:05:06 -0700 Subject: [PATCH] Fix terminal shell integration and DEBUG trap chaining in bash Chain external DEBUG traps (e.g., starship, bash-preexec) dynamically in a prompt epilogue rather than using static hooks. This ensures our own DEBUG trap survives re-arming by third-party frameworks and reliably emits OSC 133 sequences. Additionally: - Print the shell-ready marker inside the precmd hook to avoid modifying and displacing hooks at the end of PROMPT_COMMAND. - Skip redundant foreground state checks in the PTY connection when a shell prompt is already active and no background agent is expected. --- src/main/daemon/shell-ready.test.ts | 33 +++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/main/daemon/shell-ready.test.ts b/src/main/daemon/shell-ready.test.ts index f9f0d0291e4..599027b96dc 100644 --- a/src/main/daemon/shell-ready.test.ts +++ b/src/main/daemon/shell-ready.test.ts @@ -589,6 +589,39 @@ describePosix('daemon shell-ready launch config', () => { } ) + itWithBash( + 'dispatches bash-preexec callbacks against the real command, not Orca hooks', + async () => { + const { getDaemonBashShellReadyRcfileContent } = await importFreshShellReady() + // Why: Orca's epilogue captures bash-preexec's re-armed DEBUG trap and + // chains it. A non-empty preexec_functions must still see the user's real + // command as $BASH_COMMAND — not __orca_osc133_epilogue or a __bp_* helper. + writeFileSync( + join(userDataPath, '.bash_profile'), + [ + 'preexec_functions=(__user_preexec)', + '__user_preexec() { printf \'USER_PREEXEC:%s\\n\' "$1"; }', + '__bp_preexec_invoke_exec() {', + ' [[ -n "${__bp_interactive_mode:-}" ]] || return', + ' __bp_interactive_mode=""', + ' local f', + ' for f in "${preexec_functions[@]}"; do "$f" "$BASH_COMMAND"; done', + '}', + "__bp_arm() { __bp_interactive_mode=1; trap '__bp_preexec_invoke_exec' DEBUG; }", + 'PROMPT_COMMAND="${PROMPT_COMMAND:+$PROMPT_COMMAND;}__bp_arm"' + ].join('\n') + ) + + const output = runInteractiveBashRcfile(getDaemonBashShellReadyRcfileContent(), userDataPath) + + expectBashOsc133Lifecycle(output) + expect(output).toContain('USER_PREEXEC:true') + expect(output).toContain('USER_PREEXEC:false') + expect(output).not.toContain('USER_PREEXEC:__orca_osc133') + expect(output).not.toContain('USER_PREEXEC:__bp_') + } + ) + itWithBash('normalizes array PROMPT_COMMAND hooks so bash 3.2 still runs cleanup', async () => { const { getDaemonBashShellReadyRcfileContent } = await importFreshShellReady() writeFileSync(