Files
magpie runs in a new terminal and adds it (PAMI on Discord) — the app downloaded from the site, and every Windows one, left terminals without the magpie command, and nothing in the GUI said whether it was there. A Command line row now asks each shell installed (zsh, bash, fish and the login shell; PowerShell and cmd on Windows) for its PATH and says, with a dot each, whether its magpie runs this app, another copy (with that copy's version, read from its .app's Info.plist or Homebrew Cellar folder, never by running it), or none. Add to PATH links this app's program (Homebrew's opt link, the AppImage) into the folder on the default shell's PATH whose magpie runs first, else ~/.local/bin or the like when on PATH, replacing another copy there as install.sh's ln -sf does; on Windows it puts the app's folder first in HKCU\Environment Path and broadcasts WM_SETTINGCHANGE. A shell whose PATH lacks that folder gets its own button naming its profile (~/.zshrc, ~/.bash_profile on the Mac or ~/.bashrc, fish's config.fish), which links into ~/.local/bin and adds that folder with one marked line, once; no profile is written otherwise. A translocated or disk-image app is told to move first and gets no button. It says new terminals take the change (on Windows: new PowerShell/cmd windows, restart Windows Terminal). GET/POST /api/cli; en/zh/ja/de. TestCLIOnPath (temp HOME, stubbed shells: link, fish profile once, a shadowing copy replaced, no folder → zsh's profile kept and appended, an unknown shell refused, plist version, translocated refused) and TestPathFirst are new; cli-path.test.cjs (WebKit, en and zh: per-shell dots, Add posts {} and turns green, fish's button posts fish alone, Windows lists PowerShell and cmd, translocated gets no button, no scroll, no select, no left border, translations) fails without the change; cli-behind and update-auto pass. Not tried on a real Windows machine. go vet, go build (darwin, GOOS=linux nogui, GOOS=windows) and go test -tags nogui ./... under a temp HOME pass (TestOTelWholeWaterfallFallback and TestDevinSignedInOnlyInMagpie failed once each under load and pass alone).
provider: Claude Code installed off magpie's PATH is found on Windows too, so its sign-in no longer says to install it (EZN7L2C3, #839) — claudeExecutable looked on PATH, then at ~/.local/bin/claude, /usr/local/bin/claude and /opt/homebrew/bin/claude; on Windows the installer's binary is ~/.local/bin/claude.exe, and a magpie started before Claude Code was installed hasn't its folder on PATH, so the Claude sign-in said "install Claude Code first" while the Agents page, which reads ~/.claude, listed it. proc.FindTool now finds a CLI as a terminal would: on PATH, in the folders users' tools go in (UserBinDirs: npm's, ~/.local/bin, bun's, volta's, pnpm's, …) as name.exe, name.cmd or name on Windows, then on the PATH the registry has now; the sign-in and the gateway's Claude runs both use it. TestClaudeFoundInLocalBin fails on the old code on Windows (built for windows/amd64 and run on the Windows 11 test box: claude ""), passes there and here; TestToolIn. go vet, builds (darwin, GOOS=linux nogui, GOOS=windows) and go test -tags nogui -count=1 ./... under a temp HOME pass.
provider: Claude Code installed off magpie's PATH is found on Windows too, so its sign-in no longer says to install it (EZN7L2C3, #839) — claudeExecutable looked on PATH, then at ~/.local/bin/claude, /usr/local/bin/claude and /opt/homebrew/bin/claude; on Windows the installer's binary is ~/.local/bin/claude.exe, and a magpie started before Claude Code was installed hasn't its folder on PATH, so the Claude sign-in said "install Claude Code first" while the Agents page, which reads ~/.claude, listed it. proc.FindTool now finds a CLI as a terminal would: on PATH, in the folders users' tools go in (UserBinDirs: npm's, ~/.local/bin, bun's, volta's, pnpm's, …) as name.exe, name.cmd or name on Windows, then on the PATH the registry has now; the sign-in and the gateway's Claude runs both use it. TestClaudeFoundInLocalBin fails on the old code on Windows (built for windows/amd64 and run on the Windows 11 test box: claude ""), passes there and here; TestToolIn. go vet, builds (darwin, GOOS=linux nogui, GOOS=windows) and go test -tags nogui -count=1 ./... under a temp HOME pass.
proc: the login-shell probe asks nushell through /bin/sh, and a value the shell printed instead of expanding counts as unset (#738: with nushell as the login shell, shellEnv's printf '…' "$PATH" "$CLAUDE_CONFIG_DIR" … came back as the text "$PATH", "$CLAUDE_CONFIG_DIR", … — a double-quoted string is literal in nushell — and setUnset exported every one of agentenv.Vars with its own name as the value; Claude sign-in then failed with "mkdir $CLAUDE_CONFIG_DIR: read-only file system" (putClaudeLogin's MkdirAll of that relative name under the GUI's cwd /), and the account lapsed minutes later as "Claude Code is no longer signed in", its sign-in looked for under that folder; Codex, Pi, omp and the rest were pointed at "$CODEX_HOME", "$PI_CODING_AGENT_DIR", "$OMP_PROFILE" the same way, in the GUI alone, which is the one caller of UserPath) — shellProbe builds the command: for a shell named nu it is ^/bin/sh -c '<the same printf>' (nushell has no POSIX quoting to ask with and its PATH is a list, while a child of it gets the environment as any child does, PATH joined back into one string, and sh expands the references; the outer string in nushell's single quotes where a backslash is a backslash, the format in sh's double quotes where \0 reaches printf), any other shell keeps the printf it had; and parseShellEnv takes a value that is the variable's own reference ("$CODEX_HOME", or "$PATH" for PATH) for unset, so a login shell with other quoting than POSIX leaves a variable alone rather than setting it to its name. TestShellEnvNushell runs the probe through a nushell on the machine (skipped where there is none) and checks the command's shape anyway; TestParseShellEnvUnexpanded feeds the unexpanded answer. Verified against nushell 0.116.0: PATH comes back, CODEX_HOME from the environment reaches sh, unset variables are "". (#739)
windows: the desktop app no longer opens a console window for every command it runs (#54) — it is linked as a GUI program and has no console, so each console CLI it started (devin auth status and models list, devin acp for every Devin turn, claude, codex, cursor-agent and grok probes and runs, grok login) was given a new console by Windows, and a Windows Terminal window with it, some every few seconds while the app sat idle. Every command magpie runs is now made through internal/proc, which starts it with CREATE_NO_WINDOW when magpie has no console of its own: the child gets a console without a window, and its output, which magpie always pipes back, arrives as before. A magpie run in a terminal (magpie serve, the TUI, the desktop app started from one with a command) has one, and its children share it as they did, so Ctrl+C there still reaches them. The relaunch after an update keeps its DETACHED_PROCESS, added to rather than replacing the flags it was made with, and a test fails on any command made with os/exec directly, so a new one can't bring the windows back
windows: the desktop app no longer opens a console window for every command it runs (#54) — it is linked as a GUI program and has no console, so each console CLI it started (devin auth status and models list, devin acp for every Devin turn, claude, codex, cursor-agent and grok probes and runs, grok login) was given a new console by Windows, and a Windows Terminal window with it, some every few seconds while the app sat idle. Every command magpie runs is now made through internal/proc, which starts it with CREATE_NO_WINDOW when magpie has no console of its own: the child gets a console without a window, and its output, which magpie always pipes back, arrives as before. A magpie run in a terminal (magpie serve, the TUI, the desktop app started from one with a command) has one, and its children share it as they did, so Ctrl+C there still reaches them. The relaunch after an update keeps its DETACHED_PROCESS, added to rather than replacing the flags it was made with, and a test fails on any command made with os/exec directly, so a new one can't bring the windows back
windows: the desktop app no longer opens a console window for every command it runs (#54) — it is linked as a GUI program and has no console, so each console CLI it started (devin auth status and models list, devin acp for every Devin turn, claude, codex, cursor-agent and grok probes and runs, grok login) was given a new console by Windows, and a Windows Terminal window with it, some every few seconds while the app sat idle. Every command magpie runs is now made through internal/proc, which starts it with CREATE_NO_WINDOW when magpie has no console of its own: the child gets a console without a window, and its output, which magpie always pipes back, arrives as before. A magpie run in a terminal (magpie serve, the TUI, the desktop app started from one with a command) has one, and its children share it as they did, so Ctrl+C there still reaches them. The relaunch after an update keeps its DETACHED_PROCESS, added to rather than replacing the flags it was made with, and a test fails on any command made with os/exec directly, so a new one can't bring the windows back
windows: the desktop app no longer opens a console window for every command it runs (#54) — it is linked as a GUI program and has no console, so each console CLI it started (devin auth status and models list, devin acp for every Devin turn, claude, codex, cursor-agent and grok probes and runs, grok login) was given a new console by Windows, and a Windows Terminal window with it, some every few seconds while the app sat idle. Every command magpie runs is now made through internal/proc, which starts it with CREATE_NO_WINDOW when magpie has no console of its own: the child gets a console without a window, and its output, which magpie always pipes back, arrives as before. A magpie run in a terminal (magpie serve, the TUI, the desktop app started from one with a command) has one, and its children share it as they did, so Ctrl+C there still reaches them. The relaunch after an update keeps its DETACHED_PROCESS, added to rather than replacing the flags it was made with, and a test fails on any command made with os/exec directly, so a new one can't bring the windows back
accounts: a slow or hanging agent CLI no longer holds the providers page (#123) — its timeout now ends the call (a CLI that is a script running node left node holding the output, and the call waited for it however long, the 10s timeouts notwithstanding: a CLI's pipes are closed 2s after); a CLI never answered before is waited for 3s, once, then served as nobody signed in until its answer comes behind; and a CLI saying nobody is signed in is kept like any answer, where before it wasn't and every start waited for it again. Tried with cursor-agent and devin hanging 20s and the network black-holed: the first providers call went from 40.6s to 6s on a first start, and to 13ms on the next
agent, provider: a CLI whose --version fails isn't run again until it changes, and an npm CLI's version is read from its package (#864) — macOS put up 「已阻止恶意软件:未打开 "codex"」 each time magpie's window opened: the codex magpie finds was asked its version every ten minutes (the model list's client version) and again with the Agents page (a failure retried after ten minutes), and macOS stops a program XProtect flags with that alert on every start. proc.Version is the one way both ask now: an npm CLI (…/node_modules/@openai/codex/bin/codex.js) has its package.json's version read and isn't run at all; any other is run with --version, and a run that ran and said nothing, or couldn't start, isn't made again until the binary's path, size or mtime changes (a reinstall); one cut off by the timeout is. A CLI that answered is asked as before. TestCodexVersionNotRerun (a codex that exits 137 run once over three ten-minute refreshes; an npm codex's version read, not run) fails on the old code (run 3 times); TestVersionRunsOnce. TestUpdateCLI and the agent and provider tests pass. go vet, builds (darwin, GOOS=linux nogui, GOOS=windows) and go test -tags nogui -count=1 ./... under a temp HOME pass but for TestClientGoneRecordedAsCanceled, which passes alone (-count=3).
agent, provider: a CLI whose --version fails isn't run again until it changes, and an npm CLI's version is read from its package (#864) — macOS put up 「已阻止恶意软件:未打开 "codex"」 each time magpie's window opened: the codex magpie finds was asked its version every ten minutes (the model list's client version) and again with the Agents page (a failure retried after ten minutes), and macOS stops a program XProtect flags with that alert on every start. proc.Version is the one way both ask now: an npm CLI (…/node_modules/@openai/codex/bin/codex.js) has its package.json's version read and isn't run at all; any other is run with --version, and a run that ran and said nothing, or couldn't start, isn't made again until the binary's path, size or mtime changes (a reinstall); one cut off by the timeout is. A CLI that answered is asked as before. TestCodexVersionNotRerun (a codex that exits 137 run once over three ten-minute refreshes; an npm codex's version read, not run) fails on the old code (run 3 times); TestVersionRunsOnce. TestUpdateCLI and the agent and provider tests pass. go vet, builds (darwin, GOOS=linux nogui, GOOS=windows) and go test -tags nogui -count=1 ./... under a temp HOME pass but for TestClientGoneRecordedAsCanceled, which passes alone (-count=3).
accounts: a slow or hanging agent CLI no longer holds the providers page (#123) — its timeout now ends the call (a CLI that is a script running node left node holding the output, and the call waited for it however long, the 10s timeouts notwithstanding: a CLI's pipes are closed 2s after); a CLI never answered before is waited for 3s, once, then served as nobody signed in until its answer comes behind; and a CLI saying nobody is signed in is kept like any answer, where before it wasn't and every start waited for it again. Tried with cursor-agent and devin hanging 20s and the network black-holed: the first providers call went from 40.6s to 6s on a first start, and to 13ms on the next