From 812d73b42a27f920ed08a1bbc1c2fd83c13c3a74 Mon Sep 17 00:00:00 2001 From: VERSE Date: Wed, 29 Jul 2026 23:00:13 +0700 Subject: [PATCH] fix: iris stops working after exec a command in bash (#66) Fix #65 when the user presses Enter to run a command, Iris sets `isCommandActive = true` so it knows a command is running and skips rendering the overlay. After the command finishes, `isCommandActive` needs to reset to `false` for Iris to work again. In zsh/fish, preexec/precmd hooks send an `IRIS_CMD_STOP` signal over the IPC pipe, which Iris receives to reset `isCommandActive = false`. Bash has no equivalent hook, so `IRIS_CMD_STOP` is never sent and `isCommandActive` stays stuck at true forever so I added a bash-only fallback inside `isExecuting()`: if `isCommandActive` is true but `TIOCGPGRP` (a kernel API) confirms the shell's process group is back in the foreground (meaning the command finished), automatically reset `isCommandActive` to false. zsh/fish still rely on IPC signals as before also added a `PROMPT_COMMAND` hook to iris init bash to `send IRIS_CMD_STOP` after every command (belt-and-suspenders), though that's not the main fix --- root/init.go | 12 ++++++++++++ root/wrapper.go | 8 ++++++++ 2 files changed, 20 insertions(+) diff --git a/root/init.go b/root/init.go index 7d5fd76..506c3ef 100644 --- a/root/init.go +++ b/root/init.go @@ -71,6 +71,18 @@ if [ -z "$IRIS_PID" ] && [ -z "$IRIS_RESCUE" ]; then export IRIS_ACTIVE_SHELL="bash" exec iris fi + +# Iris Autocomplete Hook +if [ -n "$IRIS_PID" ] && [ -n "$IRIS_FD" ]; then + _iris_bash_precmd() { + printf "IRIS_CMD_STOP\x00" >&$IRIS_FD 2>/dev/null + } + + if [[ ";$PROMPT_COMMAND;" != *";_iris_bash_precmd;"* ]]; then + PROMPT_COMMAND="_iris_bash_precmd${PROMPT_COMMAND:+;$PROMPT_COMMAND}" + fi +fi + `) case "fish": fmt.Printf(` diff --git a/root/wrapper.go b/root/wrapper.go index 652d919..6df169c 100644 --- a/root/wrapper.go +++ b/root/wrapper.go @@ -287,6 +287,14 @@ func runWrapper() { renderOverlay := func() {} isExecuting := func() bool { if isCommandActive.Load() { + // for bash: no preexec/precmd hooks, so fall back to TIOCGPGRP to detect when shell returns + if shellName == "bash" { + pgrp, pgrpErr := unix.IoctlGetInt(int(ptmx.Fd()), unix.TIOCGPGRP) + if pgrpErr == nil && pgrp == shellPGID { + isCommandActive.Store(false) + return false + } + } return true } pgrp, err := unix.IoctlGetInt(int(ptmx.Fd()), unix.TIOCGPGRP)