proc

package
v0.1.1007 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 5, 2026 License: MIT Imports: 15 Imported by: 0

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

Constants

This section is empty.

Variables

View Source
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.

Functions

func Command

func Command(name string, args ...string) *exec.Cmd

Command is exec.Command, with no window of its own on Windows.

func CommandContext

func CommandContext(ctx context.Context, name string, args ...string) *exec.Cmd

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 a moment for that: magpie is exiting or putting a new version in its place, and nothing would end them after.

func Executable added in v0.1.977

func Executable(pid int) (string, error)

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 FindTool added in v0.1.929

func FindTool(name string) string

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). "" when none.

func IsMagpie added in v0.1.977

func IsMagpie(path string) bool

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.

func Kill added in v0.1.977

func Kill(pid int) error

Kill ends process pid at once. ErrDenied when this user may not.

func ListeningOn added in v0.1.977

func ListeningOn(ctx context.Context, port int) ([]int, error)

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 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 ProbeContext added in v0.1.599

func ProbeContext(ctx context.Context, name string, args ...string) *exec.Cmd

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

func ShellPath(sh string) []string

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 Terminate added in v0.1.977

func Terminate(pid int) error

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 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.

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.

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

func Version(bin string) string

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

type Process struct {
	PID  int
	Args string
}

A Process is one running on this computer, as the system lists it: its id and its command line, arguments joined by spaces.

func List added in v0.1.368

func List(ctx context.Context, prefix string) ([]Process, error)

List lists the running processes (Windows: only those named prefix*, since asking for all is slow there; elsewhere prefix is ignored). An error says the system couldn't be asked, not that nothing runs.

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

func StartTree(cmd *exec.Cmd) (*Tree, error)

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) Wait added in v0.1.183

func (t *Tree) Wait() error

Wait waits for the command, then ends what it left running.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL