fix: sync shell working directory for suggestions (#78)

## Summary
- synchronize the shell current working directory with Iris over the
existing IPC pipe
- use the synchronized directory for file, workspace, Git, and history
suggestions on macOS
- preserve the Linux `/proc/<pid>/cwd` and process-CWD fallbacks
- update zsh, bash, and fish integrations while preserving command exit
status

## Problem
On macOS, `/proc/<pid>/cwd` is unavailable, so `GetCWD` fell back to the
directory where Iris was launched, usually `$HOME`. After changing
directories in the shell, file suggestions could therefore continue to
come from `$HOME`.

## Tests
- `go test -race ./spec`
- `go test ./root -run ^'$'`
- `go test ./... -run ^'$'`
- generated zsh, bash, and fish hook syntax checks

Co-authored-by: Pavel Naumov <Pavel.Naumov@berekebank.kz>
This commit is contained in:
Pavel Naumov
2026-07-31 10:01:05 +07:00
committed by GitHub
co-authored by Pavel Naumov
parent cee756e2c1
commit 9f43fcb352
4 changed files with 103 additions and 10 deletions
+31 -6
View File
@@ -6,24 +6,49 @@ import (
"path/filepath"
"sort"
"strings"
"sync"
"github.com/versenilvis/iris/internal/config"
)
// for tracking current working dir
var ShellPID int
var (
// ShellPID tracks the underlying shell process.
ShellPID int
shellCWDMu sync.RWMutex
shellCWD string
)
// SetCWD updates the working directory reported by the underlying shell.
// Shell integrations call this whenever the prompt directory changes.
func SetCWD(cwd string) {
if cwd != "" && !filepath.IsAbs(cwd) {
return
}
shellCWDMu.Lock()
shellCWD = cwd
shellCWDMu.Unlock()
}
// GetCWD returns the current working directory of the underlying shell
// on Linux, it reads it from /proc/[pid]/cwd
// reported by shell integration. Linux can also read it from /proc/[pid]/cwd.
func GetCWD() string {
shellCWDMu.RLock()
cwd := shellCWD
shellCWDMu.RUnlock()
if cwd != "" {
return cwd
}
if ShellPID > 0 {
path := fmt.Sprintf("/proc/%d/cwd", ShellPID)
cwd, err := os.Readlink(path)
procCWD, err := os.Readlink(path)
if err == nil {
return cwd
return procCWD
}
}
cwd, _ := os.Getwd()
cwd, _ = os.Getwd()
return cwd
}