Documentation
¶
Overview ¶
Package proc makes the commands magpie runs: agents' CLIs, the probes that ask them what they have, the system's own tools. Every one is made here rather than with os/exec, so that on Windows none of them opens a window.
The desktop app on Windows is linked as a GUI program and has no console. A console program it starts (devin, claude, codex, cursor-agent, grok, the probes behind them) is given a new console by Windows, and with it a window, one for every run; so a child of a magpie with no console is started with CREATE_NO_WINDOW, which gives it a console without one. A magpie run in a terminal, or the desktop app started from one with a command, lets its children share that console as before, so Ctrl+C there reaches them too. Nothing magpie starts reads or writes the terminal itself: its output is piped back, which a hidden console doesn't change.
Index ¶
- Variables
- func Command(name string, args ...string) *exec.Cmd
- func CommandContext(ctx context.Context, name string, args ...string) *exec.Cmd
- func EndProbes()
- func Executable(pid int) (string, error)
- func FindShell(name string) string
- func FindTool(name string) string
- func Forget()
- func IsForwarder(path string) bool
- func IsMagpie(path string) bool
- func Isolated() bool
- func Kill(pid int) error
- func ListeningOn(ctx context.Context, port int) ([]int, error)
- func LoginEnv(k string) string
- func LoginPath() []string
- func Look(name string) (string, error)
- func LookPath(name string) (string, error)
- func OpenBrowser(url string) error
- func ProbeContext(ctx context.Context, name string, args ...string) *exec.Cmd
- func RealPath(p string) (string, error)
- func ShellPath(sh string) []string
- func SystemDirs(paths ...string) []string
- func Terminate(pid int) error
- func Unwrap(name, path string) string
- func UserBinDirs() []string
- func UserPath()
- func Version(bin string) string
- type Process
- type Tree
Constants ¶
This section is empty.
Variables ¶
var ErrDenied = errors.New("not allowed to end it")
ErrDenied is a process this user may not end: another user's, or one run as administrator.
var ProxyVars = []string{"HTTP_PROXY", "http_proxy", "HTTPS_PROXY", "https_proxy", "ALL_PROXY", "all_proxy", "NO_PROXY", "no_proxy"}
ProxyVars are the proxy variables the login shell is asked for beside agentenv.Vars. An agent run in a terminal has the ones its profile sets, and so does one the ChatGPT app starts (it takes the login shell's environment as it opens), while magpie opened from the Dock doesn't: a NO_PROXY=127.0.0.1 in .zshrc keeps Codex's requests for magpie off a proxy that magpie, reading its own environment, thought they went through (liu_dyj on X). They are only read (LoginEnv), never set in magpie's environment: magpie's own requests take their proxy from netproxy.
Functions ¶
func CommandContext ¶
CommandContext is exec.CommandContext, with no window of its own on Windows.
func EndProbes ¶ added in v0.1.599
func EndProbes()
EndProbes kills every probe still running, with what it started, and waits until none of that is left: magpie is exiting or putting a new version in its place, and nothing would end them after. A kill that missed a process being forked signals the group again until it is empty, and an exit before that left the missed one running, adopted by init (#1278); the wait is bounded by how long a kill goes on (killFor on Unix).
func Executable ¶ added in v0.1.977
Executable is the path of the program process pid runs, as the system says it: the one it was started from, also when that file has been replaced since (an update).
func FindShell ¶ added in v0.1.1166
FindShell is the program of the shell name (zsh, bash, fish, nu) installed here, "" when there is none. A desktop app's PATH is launchd's, so the folders shells are installed in are looked in first, then the shells /etc/shells lists, then PATH.
func FindTool ¶ added in v0.1.929
FindTool is the command-line tool name as a terminal would run it: on PATH, else in one of the folders a user's tools are installed in (UserBinDirs), else, on Windows, on the PATH the registry has now, which a magpie started before the tool was installed doesn't have (#839: the Claude sign-in said Claude Code wasn't installed, its installer having put claude.exe in ~/.local/bin after magpie started). A version manager's wrapper script found there is given as the program it runs (Unwrap). "" when none. Where it is on PATH is kept while those folders are unchanged (LookPath); Unwrap keeps its own answer by the script's size and time.
func Forget ¶ added in v0.1.1214
func Forget()
Forget drops every answer kept by LookPath and FindTool, so the next asks again: the reader asked to look for agents again.
func IsForwarder ¶ added in v0.1.1035
IsForwarder says whether the program at path holds a port for a container or a VM, which serves on it from inside: OrbStack's helper, Docker Desktop's backend and vpnkit, docker-proxy, Podman's gvproxy, Lima's (Colima's, Rancher Desktop's) host agent, WSL's relay. A magpie answering there runs in that container (leslie_luo on Discord: magpie v0.1.552 in OrbStack held 3425, and its helper was named as the program to quit), which only the container's own tools stop.
func IsMagpie ¶ added in v0.1.977
IsMagpie says whether the program at path is a magpie: magpie, its magpie-* builds or dial, its name before; with .exe, and Windows' .old for one replaced by an update while it ran, or .old-2 when that one was still held.
func Isolated ¶ added in v0.1.1258
func Isolated() bool
Isolated reports whether this is a test binary testenv isolated, where nothing of the machine's own (its folders, its registry) is read.
func ListeningOn ¶ added in v0.1.977
ListeningOn is the ids of the processes listening on TCP port, that this user can see: lsof on a Mac, /proc on Linux, Get-NetTCPConnection on Windows. Another user's process may be missing.
func LoginEnv ¶ added in v0.1.1214
LoginEnv is the value a terminal opened now has for k, one of agentenv.Vars, ProxyVars or agentenv.ClaudeProviders: the login shell's, asked as LoginPath asks and with it; "" when the shell has none for it or doesn't say.
func LoginPath ¶ added in v0.1.681
func LoginPath() []string
LoginPath is the PATH a terminal opened now has — the login shell's — for telling whether a command an agent runs by name is found there, which the app's own PATH can't: UserPath adds folders the shell may not have. nil when the shell doesn't say; asked again after a minute.
func Look ¶ added in v0.1.1214
Look is exec.LookPath as it is, a wrapper script given as itself, the answer kept while the PATH folders are unchanged.
func LookPath ¶ added in v0.1.1210
LookPath is exec.LookPath, with a version manager's wrapper script found there given as the program it runs (Unwrap). Where it is on PATH is kept while the PATH folders are unchanged (Look); Unwrap keeps its own answer by the script's size and time.
func OpenBrowser ¶ added in v0.1.1231
OpenBrowser opens url in the user's default browser. The error is the launcher's failing to start, for the caller to show with the link to open by hand: a sign-in that waits on a page that never opened only times out (#2043).
func ProbeContext ¶ added in v0.1.599
ProbeContext is CommandContext for a command magpie only asks something of and waits on for the answer: who a CLI says is signed in, its version. The CLI is often a script (a version manager's wrapper, a shim), and killing it on the timeout left what it had started running; a probe still asking when magpie quit or updated itself was left whole, adopted by init with nothing to end it, and one stuck in a loop held a core for hours. A probe leads a group of its own on Unix, the context ending kills the whole group, and EndProbes does the same for those still asking when magpie exits. ctx must end (a timeout): the probe is forgotten when it does.
func ShellPath ¶ added in v0.1.1003
ShellPath is the PATH the shell sh (zsh, bash, fish) has in a terminal opened now, whether or not it is the login shell; nil when it doesn't say within a few seconds.
func SystemDirs ¶ added in v0.1.1169
SystemDirs are paths of the machine's own, outside any home (Homebrew's /opt/homebrew/bin, /usr/local/bin, an app in /Applications, the registry's PATH), as discovery looks in them: as they are, except in a test binary testenv isolated, where each lies under the test's home instead. A test that empties PATH means a machine without the tool; the host's /opt/homebrew/bin/claude was found anyway, so the tests of the downloaded Claude Code failed on a Mac with Homebrew's (#1525). A test that wants one there writes it under its home at that path.
func Terminate ¶ added in v0.1.977
Terminate asks process pid to end: SIGTERM on Unix, which a magpie quits on; on Windows it is ended at once (nothing else reaches a tray app). ErrDenied when this user may not.
func Unwrap ¶ added in v0.1.1210
Unwrap is the program path stands for when it is a small script that runs name through mise (`mise x … -- name`, `mise exec`, rtx's old name): what `mise which name` says. path itself otherwise, and when mise isn't here or doesn't say within a few seconds.
func UserBinDirs ¶ added in v0.1.441
func UserBinDirs() []string
UserBinDirs are the folders a user's command-line tools are installed in that exist here — npm's prefixes, each Node version of nvm, fnm and mise, bun, volta, pnpm, asdf, the standalone installers' ~/.local/bin, Homebrew — for finding one PATH doesn't reach. A manager's Node versions come in the order a terminal would reach them: its default first, then the highest version (v22 before v9).
func UserPath ¶ added in v0.1.67
func UserPath()
UserPath gives the desktop app the PATH a terminal of the user's has. One opened from the Finder, the Dock or a login item gets launchd's /usr/bin:/bin:/usr/sbin:/sbin and nothing a shell profile adds, so a claude or codex installed with a custom npm prefix (~/.npm-global/bin), nvm, bun, volta or asdf wasn't found: the agent wasn't seen and its subscription couldn't be used. The folders those tools use are added at once, when they exist; the login shell's own PATH is asked for after. Of nvm's Nodes only the one a terminal gets is added: its default alias's, not the folder whose name sorts last (nvmBins).
The same call brings the agents' own variables (agentenv.Vars: PI_CODING_AGENT_DIR, CODEX_HOME, CLAUDE_CONFIG_DIR, ...) the profile sets and the app wasn't started with, so that magpie writes an agent's config into the folder the agent reads, not its default one in the home (atie on Discord: Pi's models.json went to ~/.pi/agent with PI_CODING_AGENT_DIR set in the shell). One already in magpie's environment is kept. One holding a relative path is lent to the programs magpie starts all the same, but magpie itself reads them through appdir.LookupEnv, which passes such a value over, as it does the ones magpie started with. Those are read as magpie starts (the library is synced into the agents at once), so the answer is waited for, but no more than shellWait: a slow profile mustn't hold the window up, and what it says later is still taken.
func Version ¶ added in v0.1.961
Version is what the CLI at bin says its version is: the version in the package.json of the npm package it is a file of, read rather than run, else what bin --version prints (stdout and stderr, ANSI and all), "" when it says nothing. A run that fails other than by taking too long isn't made again until the binary changes (#864): macOS stops a program XProtect flags with a "contains malware" alert on each start, and a CLI asked its version every few minutes put one up every time magpie's window opened. An npm CLI isn't run at all: its package says the version its --version would.
Types ¶
type Process ¶ added in v0.1.368
A Process is one running on this computer, as the system lists it: its id and its command line, arguments joined by spaces.
type Tree ¶ added in v0.1.183
type Tree struct {
// contains filtered or unexported fields
}
A Tree is a started command and the processes it starts in turn: an agent's CLI with the MCP servers, shells and helpers it runs. Killing the CLI alone leaves those running, so they are ended with it.
func StartTree ¶ added in v0.1.183
StartTree starts cmd in a group of its own: a session on Unix, a job on Windows. It has no terminal then, and a Ctrl+C there doesn't reach it.
func (*Tree) Kill ¶ added in v0.1.183
func (t *Tree) Kill()
Kill ends the command and every process of its tree.
func (*Tree) Stop ¶ added in v0.1.1241
Stop asks the command to end, so it can clean up first, and ends its tree once it has (Wait sweeps what it left) or grace has passed (Kill). Claude Code holding its OAuth refresh lock removes it as it exits on SIGTERM, and a SIGKILL left ~/.claude/.oauth_refresh.lock behind for every later request to wait on (#2195). Windows has no such signal: the tree is killed at once there. It returns at once; the channel closes once the tree is ended. A tree no one Waits for is killed after grace.