fix(shell): let bash-preexec install last so atuin preexec fires

Eagerly calling __bp_install at source time made bash-preexec install
before starship/atuin/zoxide/ghostty modified PROMPT_COMMAND, so their
hooks landed after __bp_interactive_mode. bash-preexec then never marked
typed commands as interactive and skipped preexec_functions, so atuin's
__atuin_preexec never fired and history stopped recording
(ATUIN_PREEXEC_BACKEND stuck at "<shlvl>:none").

Remove the eager __bp_install and the manual PROMPT_COMMAND/array wiring
for starship, atuin and zoxide; each tool registers with bash-preexec
itself, and deferred install on the first prompt keeps
__bp_interactive_mode last (verified against bash-preexec 0.6.0).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
randogoth 2026-07-11 16:13:30 +03:00
parent 4c6a0d4b28
commit b7bb444f3d

View file

@ -19,20 +19,6 @@ is_interactive() {
[[ -t 1 || -n ${PS1:-} ]] [[ -t 1 || -n ${PS1:-} ]]
} }
append_unique() {
local var="$1" val="$2"
[[ ";${!var:-};" == *";$val;"* ]] && return
printf -v "$var" '%s' "${!var:+${!var%;};}$val"
}
prepend_unique_array() {
local name="$1" val="$2"
local -n arr="$name"
local out=("$val")
for f in "${arr[@]}"; do [[ $f != "$val" ]] && out+=("$f"); done
arr=("${out[@]}")
}
# ---- environment sanity ---------------------------------------------------- # ---- environment sanity ----------------------------------------------------
if [[ -z ${TERM:-} || $TERM == dumb ]]; then if [[ -z ${TERM:-} || $TERM == dumb ]]; then
@ -56,7 +42,10 @@ fi
if [[ -n ${BASH_VERSION:-} && -z ${bash_preexec_imported:-} && -r "@BASHPREEXEC@" ]]; then if [[ -n ${BASH_VERSION:-} && -z ${bash_preexec_imported:-} && -r "@BASHPREEXEC@" ]]; then
# shellcheck disable=SC1090 # shellcheck disable=SC1090
. "@BASHPREEXEC@" . "@BASHPREEXEC@"
have __bp_install && __bp_install # Do NOT call __bp_install here. bash-preexec must install on the FIRST prompt,
# after starship/atuin/zoxide/ghostty have modified PROMPT_COMMAND, so that
# __bp_interactive_mode stays the LAST PROMPT_COMMAND entry. Installing eagerly
# lets later hooks land after it and silently breaks preexec (atuin recording).
log_shell_init "bash-preexec loaded" log_shell_init "bash-preexec loaded"
fi fi
@ -68,7 +57,8 @@ if have @STARSHIP@; then
*/bash) eval "$(@STARSHIP@ init bash)" ;; */bash) eval "$(@STARSHIP@ init bash)" ;;
*/zsh) eval "$(@STARSHIP@ init zsh)" ;; */zsh) eval "$(@STARSHIP@ init zsh)" ;;
esac esac
append_unique PROMPT_COMMAND starship_precmd # starship's bash init registers starship_precmd/starship_preexec_all with
# bash-preexec directly; no manual PROMPT_COMMAND wiring needed.
else else
log_shell_init "starship skipped" log_shell_init "starship skipped"
fi fi
@ -87,10 +77,8 @@ if have @ATUIN@; then
*/bash) eval "$(@ATUIN@ init bash)" ;; */bash) eval "$(@ATUIN@ init bash)" ;;
*/zsh) eval "$(@ATUIN@ init zsh)" ;; */zsh) eval "$(@ATUIN@ init zsh)" ;;
esac esac
# atuin's init registers __atuin_preexec/__atuin_precmd with bash-preexec
declare -a preexec_functions precmd_functions # itself; manual array wiring only caused duplicate hook entries.
prepend_unique_array preexec_functions __atuin_preexec
prepend_unique_array precmd_functions __atuin_precmd
else else
log_shell_init "atuin skipped" log_shell_init "atuin skipped"
fi fi
@ -103,16 +91,13 @@ if have zoxide; then
*/bash) eval "$(zoxide init bash)" ;; */bash) eval "$(zoxide init bash)" ;;
*/zsh) eval "$(zoxide init zsh)" ;; */zsh) eval "$(zoxide init zsh)" ;;
esac esac
have __zoxide_hook && append_unique PROMPT_COMMAND __zoxide_hook # zoxide's bash init hooks into bash-preexec (precmd_functions) when it is
# present; manual PROMPT_COMMAND wiring only pushed hooks past
# __bp_interactive_mode and broke preexec ordering.
else else
log_shell_init "zoxide skipped" log_shell_init "zoxide skipped"
fi fi
# ---- bash-preexec PROMPT_COMMAND safety -----------------------------------
have __bp_precmd_invoke_cmd && append_unique PROMPT_COMMAND __bp_precmd_invoke_cmd
have __bp_interactive_mode && append_unique PROMPT_COMMAND __bp_interactive_mode
# ---- aliases -------------------------------------------------------------- # ---- aliases --------------------------------------------------------------
if have eza; then if have eza; then