fix: start iris in multiplexer panes instead of inheriting a dead one (#120)

closes #62
when you open a new Zellij pane, the shell inherits Iris’s environment
variables, so it thinks Iris is already running. But the pane doesn't
inherit the underlying connection (FD 13), so suggestions silently fail
into a dead pipe

the old code only checked for `tmux` by process name, ignoring Zellij
completely

- Fixed:

instead of checking for specific app names, Iris now tracks the active
terminal device (`IRIS_TTY`)

if a new shell detects that it's on a different `TTY` than Iris, it
clears the stale environment variables so Iris can start fresh. The
`IRIS_PID != PPID` check prevents Iris from trying to re-exec itself
when spawning sub-shells.

```sh
if [ -n "$IRIS_PID" ] && [ "$IRIS_PID" != "$PPID" ] && [ "${TTY:-$(tty 2>/dev/null)}" != "$IRIS_TTY" ]; then
    unset IRIS_PID IRIS_IS_CHILD IRIS_FD IRIS_TTY
fi

```
This commit is contained in:
VERSE
2026-08-06 15:42:56 +07:00
committed by GitHub
parent 2a87cd9783
commit fc1634b007
2 changed files with 30 additions and 13 deletions
+15 -10
View File
@@ -25,10 +25,10 @@ For example, add this to your ~/.zshrc:
case "zsh": case "zsh":
fmt.Printf(` fmt.Printf(`
# Iris Autostart Hook # Iris Autostart Hook
if [ -n "$TMUX" ] && [ -n "$IRIS_PID" ]; then # a multiplexer pane inherits IRIS_* but runs on its own tty, so those vars
if ps -o comm= -p $PPID 2>/dev/null | grep -q "tmux"; then # point at an iris that is not driving this terminal
unset IRIS_PID IRIS_IS_CHILD IRIS_FD if [ -n "$IRIS_PID" ] && [ "$IRIS_PID" != "$PPID" ] && [ "${TTY:-$(tty 2>/dev/null)}" != "$IRIS_TTY" ]; then
fi unset IRIS_PID IRIS_IS_CHILD IRIS_FD IRIS_TTY
fi fi
if [ -z "$IRIS_PID" ] && [ -z "$IRIS_RESCUE" ]; then if [ -z "$IRIS_PID" ] && [ -z "$IRIS_RESCUE" ]; then
@@ -68,10 +68,10 @@ fi
case "bash": case "bash":
fmt.Printf(` fmt.Printf(`
# Iris Autostart Hook # Iris Autostart Hook
if [ -n "$TMUX" ] && [ -n "$IRIS_PID" ]; then # a multiplexer pane inherits IRIS_* but runs on its own tty, so those vars
if ps -o comm= -p $PPID 2>/dev/null | grep -q "tmux"; then # point at an iris that is not driving this terminal
unset IRIS_PID IRIS_IS_CHILD IRIS_FD if [ -n "$IRIS_PID" ] && [ "$IRIS_PID" != "$PPID" ] && [ "$(tty 2>/dev/null)" != "$IRIS_TTY" ]; then
fi unset IRIS_PID IRIS_IS_CHILD IRIS_FD IRIS_TTY
fi fi
if [ -z "$IRIS_PID" ] && [ -z "$IRIS_RESCUE" ]; then if [ -z "$IRIS_PID" ] && [ -z "$IRIS_RESCUE" ]; then
@@ -96,11 +96,16 @@ fi
case "fish": case "fish":
fmt.Printf(` fmt.Printf(`
# Iris Autostart Hook # Iris Autostart Hook
if set -q TMUX; and set -q IRIS_PID # a multiplexer pane inherits IRIS_* but runs on its own tty, so those vars
if ps -o comm= -p $PPID 2>/dev/null | grep -q "tmux" # point at an iris that is not driving this terminal
if set -q IRIS_PID
set -l iris_ppid (ps -o ppid= -p $fish_pid 2>/dev/null | string trim)
set -l iris_cur_tty (tty 2>/dev/null)
if test "$IRIS_PID" != "$iris_ppid"; and test "$iris_cur_tty" != "$IRIS_TTY"
set -e IRIS_PID set -e IRIS_PID
set -e IRIS_IS_CHILD set -e IRIS_IS_CHILD
set -e IRIS_FD set -e IRIS_FD
set -e IRIS_TTY
end end
end end
+15 -3
View File
@@ -153,15 +153,27 @@ func runWrapper() {
c.ExtraFiles = make([]*os.File, 11) c.ExtraFiles = make([]*os.File, 11)
// pass write end of pipe to shell as fd 13 (since index 10 maps to 13) // pass write end of pipe to shell as fd 13 (since index 10 maps to 13)
c.ExtraFiles[10] = w c.ExtraFiles[10] = w
c.Env = adapter.GetEnv(13, os.Getpid())
ptmx, err := pty.Start(c) ptmx, tts, err := pty.Open()
if err != nil { if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "[IRIS] failed to start PTY: %v\n", err) _, _ = fmt.Fprintf(os.Stderr, "[IRIS] failed to open PTY: %v\n", err)
return return
} }
defer func() { _ = ptmx.Close() }() defer func() { _ = ptmx.Close() }()
c.Stdin, c.Stdout, c.Stderr = tts, tts, tts
c.SysProcAttr = &syscall.SysProcAttr{Setsid: true, Setctty: true}
// the shell compares its own tty against this to tell whether the inherited
// IRIS_* vars belong to it or leaked in from an outer terminal
c.Env = append(adapter.GetEnv(13, os.Getpid()), "IRIS_TTY="+tts.Name())
if err = c.Start(); err != nil {
_ = tts.Close()
_, _ = fmt.Fprintf(os.Stderr, "[IRIS] failed to start shell: %v\n", err)
return
}
_ = tts.Close()
stdinFile := os.Stdin stdinFile := os.Stdin
if !term.IsTerminal(int(stdinFile.Fd())) { if !term.IsTerminal(int(stdinFile.Fd())) {
if tty, ttyErr := os.OpenFile("/dev/tty", os.O_RDWR, 0); ttyErr == nil { if tty, ttyErr := os.OpenFile("/dev/tty", os.O_RDWR, 0); ttyErr == nil {