mirror of
https://github.com/stablyai/orca.git
synced 2026-10-17 00:03:08 +00:00
Mirror upstream bash-preexec so preexec dispatch test reflects real command
The naive $BASH_COMMAND imitation captured Orca's chained __orca_osc133_epilogue instead of the user command, failing on CI. Read the command from history like real bash-preexec does. Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
@@ -590,24 +590,39 @@ describePosix('daemon shell-ready launch config', () => {
|
||||
)
|
||||
|
||||
itWithBash(
|
||||
'dispatches bash-preexec callbacks against the real command, not Orca hooks',
|
||||
'dispatches a non-empty preexec_functions 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.
|
||||
// chains it. A real preexec callback must fire against the user's command —
|
||||
// not __orca_osc133_epilogue. Mirror upstream bash-preexec faithfully: it
|
||||
// enables `functrace` (so Orca's `trap -p DEBUG` capture sees its trap),
|
||||
// defers that install to the first prompt via PROMPT_COMMAND, and reads the
|
||||
// command from `history` (so DEBUG fires on prompt hooks never dispatch a
|
||||
// phantom). The naive `$BASH_COMMAND` imitation does none of these.
|
||||
writeFileSync(
|
||||
join(userDataPath, '.bash_profile'),
|
||||
[
|
||||
'preexec_functions=(__user_preexec)',
|
||||
'__user_preexec() { printf \'USER_PREEXEC:%s\\n\' "$1"; }',
|
||||
'__bp_inside=0',
|
||||
'__bp_last_hist=""',
|
||||
'__bp_preexec_invoke_exec() {',
|
||||
' (( __bp_inside > 0 )) && return',
|
||||
' [[ -n "${__bp_interactive_mode:-}" ]] || return',
|
||||
' local __bp_inside=1',
|
||||
' local this_command',
|
||||
' this_command="$(builtin history 1)"',
|
||||
' this_command="${this_command#"${this_command%%[![:space:]]*}"}"',
|
||||
' this_command="${this_command#* }"',
|
||||
' this_command="${this_command#"${this_command%%[![:space:]]*}"}"',
|
||||
' [[ -n "$this_command" && "$this_command" != "$__bp_last_hist" ]] || return',
|
||||
' __bp_last_hist="$this_command"',
|
||||
' __bp_interactive_mode=""',
|
||||
' local f',
|
||||
' for f in "${preexec_functions[@]}"; do "$f" "$BASH_COMMAND"; done',
|
||||
' for f in "${preexec_functions[@]}"; do "$f" "$this_command"; done',
|
||||
'}',
|
||||
"__bp_arm() { __bp_interactive_mode=1; trap '__bp_preexec_invoke_exec' DEBUG; }",
|
||||
"__bp_arm() { set -o functrace; __bp_interactive_mode=1; trap '__bp_preexec_invoke_exec' DEBUG; }",
|
||||
'PROMPT_COMMAND="${PROMPT_COMMAND:+$PROMPT_COMMAND;}__bp_arm"'
|
||||
].join('\n')
|
||||
)
|
||||
|
||||
@@ -1757,15 +1757,14 @@ export function connectPanePty(
|
||||
}
|
||||
return pendingWrite.then(() => interruptInference.flushPending())
|
||||
}
|
||||
// Why: a launched/hook-known agent pane must confirm — not trust — a 133;D so a
|
||||
// full-screen agent's leaked nested-shell 133;D can't clear its tab identity,
|
||||
// even on a restore where no command-start read has recorded evidence yet.
|
||||
const paneHasKnownAgentIdentity = (): boolean => {
|
||||
const state = useAppStore.getState()
|
||||
// Why: the 133;D confirmation guard and the visible-pane resampler both key off
|
||||
// "does this pane expect an agent"; derive each signal once so the two callers
|
||||
// can't drift and silently reintroduce the icon bug this fix closes.
|
||||
const paneHasLiveHookAgentIcon = (state: ReturnType<typeof useAppStore.getState>): boolean => {
|
||||
const entry = state.agentStatusByPaneKey[cacheKey]
|
||||
if (entry?.state !== 'done' && agentTypeToIconAgent(entry?.agentType)) {
|
||||
return true
|
||||
}
|
||||
return entry?.state !== 'done' && Boolean(agentTypeToIconAgent(entry?.agentType))
|
||||
}
|
||||
const paneExpectsLaunchAgent = (state: ReturnType<typeof useAppStore.getState>): boolean => {
|
||||
const tab = (state.tabsByWorktree[deps.worktreeId] ?? []).find(
|
||||
(candidate) => candidate.id === deps.tabId
|
||||
)
|
||||
@@ -1773,6 +1772,13 @@ export function connectPanePty(
|
||||
tab?.launchAgent ?? paneStartup?.launchAgent ?? paneStartup?.initialAgentStatus?.agent
|
||||
)
|
||||
}
|
||||
// Why: a launched/hook-known agent pane must confirm — not trust — a 133;D so a
|
||||
// full-screen agent's leaked nested-shell 133;D can't clear its tab identity,
|
||||
// even on a restore where no command-start read has recorded evidence yet.
|
||||
const paneHasKnownAgentIdentity = (): boolean => {
|
||||
const state = useAppStore.getState()
|
||||
return paneHasLiveHookAgentIcon(state) || paneExpectsLaunchAgent(state)
|
||||
}
|
||||
// Why: a plain `codex`/`grok` sets its OSC title and the shell never repaints
|
||||
// it on exit, so a confirmed return-to-shell must clear a title that still
|
||||
// names an agent — otherwise the tab reads "grok" over a bare prompt. Only
|
||||
@@ -1811,16 +1817,10 @@ export function connectPanePty(
|
||||
if (foreground?.agent) {
|
||||
return
|
||||
}
|
||||
const entry = state.agentStatusByPaneKey[cacheKey]
|
||||
if (entry?.state !== 'done' && agentTypeToIconAgent(entry?.agentType)) {
|
||||
if (paneHasLiveHookAgentIcon(state)) {
|
||||
return
|
||||
}
|
||||
const tab = (state.tabsByWorktree[deps.worktreeId] ?? []).find(
|
||||
(candidate) => candidate.id === deps.tabId
|
||||
)
|
||||
const expectsAgent = Boolean(
|
||||
tab?.launchAgent ?? paneStartup?.launchAgent ?? paneStartup?.initialAgentStatus?.agent
|
||||
)
|
||||
const expectsAgent = paneExpectsLaunchAgent(state)
|
||||
// Why: with no shell mark yet, launchAgent bootstrap already paints the icon,
|
||||
// so a read is pointless. Otherwise probe the foreground: a shell mark (from a
|
||||
// reattach or a full-screen agent's leaked nested-shell 133;D) can hide a
|
||||
|
||||
Reference in New Issue
Block a user