Files
magpie/internal/library/rtk_path_test.go
T
yetone 9848a9062a library: RTK says when rtk isn't on the PATH the agents get, and puts it there when asked (#601, Moody-Sin: magpie好像没有正确安装RTK — Pi said "RTK disabled: rtk binary not found in PATH" while the Library showed RTK working) — rtk's hooks run it by name (Pi's extension probes rtk --version and turns itself off when that fails; Claude Code's and Codex's are rtk hook …; the commands they rewrite to are rtk git status and so on), but magpie looked for rtk in more places than an agent's PATH: ~/.local/bin and ~/.cargo/bin, which the app adds to its own PATH whether the user's shell has them or not (rtk's own install.sh puts it in ~/.local/bin and only warns when that isn't on PATH), and WinGet\Links on Windows, which winget doesn't always link into. So rtk was "installed", the agents were switched on with it by its whole path, and none of them could run it. Now the PATH a terminal opened now has is read — the login shell's (proc.LoginPath, the one UserPath already asks for, kept a minute) or on Windows the registry's (moved from provider's registryPath) — and when rtk isn't in it the RTK card says so, with what Put RTK on PATH will do, and each agent that has rtk is tagged Not on PATH (不在 PATH 中). Put RTK on PATH (magpie library rtk path) links rtk into the first of ~/.local/bin, ~/bin, /opt/homebrew/bin, /usr/local/bin, linuxbrew's bin, ~/.cargo/bin that is on that PATH and writable, or on Windows adds rtk's own folder to the user's PATH in the registry (a link needs Developer Mode, and a copy is left behind when winget upgrades rtk; winget's package folder doesn't change across upgrades) and tells Explorer; with no such folder it says which folder to add to PATH in the shell profile — shell profiles are never edited. rtk is also found in winget's package folder (WinGet\Packages\rtk-ai.rtk_*), and rtk's script upgrades a linked rtk where the link points, not over the link. TestRTKOffPath and library-rtk-path.test.cjs (en, zh) fail without the change. go vet ./internal/..., go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build and vet, go test -tags nogui -count=1 ./... under a temp HOME pass but the known TestFXInState flake. The Windows registry path is built, not run on Windows.
2026-10-03 02:38:17 +08:00

66 lines
2.3 KiB
Go

//go:build !windows
package library
import (
"os"
"path/filepath"
"slices"
"strings"
"testing"
)
// TestRTKOffPath (#601): an rtk magpie finds where rtk's script puts it,
// ~/.local/bin, which the app adds to its own PATH but the user's shell
// may not have, isn't one the agents' hooks can run — Pi's turns itself
// off with "rtk binary not found in PATH". The page says so instead of
// showing RTK working, and Put RTK on PATH links it into a folder on it.
func TestRTKOffPath(t *testing.T) {
h := sandbox(t)
local := filepath.Join(h, ".local", "bin")
write(t, filepath.Join(local, "rtk"), fakeRTK)
os.Chmod(filepath.Join(local, "rtk"), 0o755)
tools := filepath.Join(h, "tools")
write(t, filepath.Join(tools, "curl"), "#!/bin/sh\n")
os.Chmod(filepath.Join(tools, "curl"), 0o755)
t.Setenv("PATH", tools)
v := ReadRTK()
if v.Path != filepath.Join(local, "rtk") || !v.OffPath {
t.Fatalf("rtk at %q, off PATH %v; want it found in ~/.local/bin and said to be off PATH", v.Path, v.OffPath)
}
if v.PathDir != "" {
t.Fatalf("no folder on PATH rtk can go in, yet PathDir is %q", v.PathDir)
}
if _, err := PathRTK(); err == nil || !strings.Contains(err.Error(), local) {
t.Fatalf("PathRTK with nowhere to put rtk: %v; want it to say to add %s to PATH", err, local)
}
if _, err := SetRTK("claude", true); err != nil {
t.Fatal(err)
}
// ~/bin is on the shell's PATH: rtk is linked in there
userBin := filepath.Join(h, "bin")
t.Setenv("PATH", tools+string(os.PathListSeparator)+userBin)
if v = ReadRTK(); !v.OffPath || v.PathDir != userBin || !v.PathLink {
t.Fatalf("off PATH %v, PathDir %q, link %v; want %s linked into", v.OffPath, v.PathDir, v.PathLink, userBin)
}
v, err := PathRTK()
if err != nil {
t.Fatal(err)
}
if v.OffPath || !slices.Contains(v.Restart, "claude") {
t.Fatalf("after PathRTK: off PATH %v, restart %v", v.OffPath, v.Restart)
}
if to, err := os.Readlink(filepath.Join(userBin, "rtk")); err != nil || to != filepath.Join(local, "rtk") {
t.Fatalf("~/bin/rtk links to %q (%v)", to, err)
}
// upgraded with its script into ~/.local/bin, where the link points,
// not over the link
c := rtkUpgrader(filepath.Join(userBin, "rtk"))
real, _ := filepath.EvalSymlinks(local)
if len(c) != 4 || c[3] != real {
t.Fatalf("upgrade through the link: %q; want rtk's script into %s", c, real)
}
}