@getpipher/term — a focused programmatic tmux driver for autonomous TUI QA
inside the pi coding agent. tmux-only v0.1; ships as lib/ (importable async
API) + extensions/term.ts (pi tool, 9 actions). Seeded by the ad-hoc
tmux-driving harness used across @getpipher/armory-todo + @getpipher/vision
QA. See docs/superpowers/specs/2026-07-22-term-design.md for the full design.
- v0.4.2 — shipped (2026-09-07). Two fixes: reaper installs no
SIGINT/SIGTERM handlers and never calls
process.exit(omp extension guard compliance, #2);spawn.envnow reaches the pane viatmux -e KEY=value(≥3.2) in both modes (#1). - v0.4.0 — shipped (2026-07-27).
spawnauto-detects via$TMUX: new detached window in the current session (pi inside tmux) or new detached session (pi outside tmux).killbranches tokill-window/kill-session. Default agent behavior: no-kill — leave the window/session for post-run inspection (lease: 30 min session-mode, 2 h window-mode). CI publishes on v0.4.0 tag. - v0.1.0 — shipped (2026-07-22). Original tmux-only flat design.
- npm org
getpipher, accountrz1989. Publish via CI onv*tag using the getpipher org secretNPM_TOKEN(granular, Bypass 2FA, scoped to @getpipher, visibility ALL — inherited by this repo). Verified 2026-07-22. - No build step — extensions ship raw
.ts(run via tsx at pi runtime).pnpm typecheck+pnpm test:run(node:test via tsx) before release. release.yml= cursor/vision shape (pnpm, node 20, typecheck + test:run gates, idempotent npm publish) + armory-todo's GitHub-Release step (gh release create --generate-notes, idempotent).
- tmux-only v0.1, flat — no premature
TerminalDriverabstraction. Extract the interface only when a 2nd real backend exists. - Exec seam —
lib/tmux.tsholds a module-levelexec: ExecFnwith asetExec()test seam (mirrorscursor/lib/focus/tmux.ts). Tests mock the exec to assert exact tmux arg arrays; an integration smoke runs against real tmux (skip-when-absent) to avoid the mock-proves-my-assumption anti-pattern. spawnauto-detects target (v0.4.0) — branches on$TMUX(via aninTmuxFnseam for tests): new window in the current session if pi is inside tmux, else a new detached session (the v0.1 fallback). Window-mode usesnew-window -d -P -F '#{window_id}|#{pane_id}'(NOT\t— tmux-Fprints literal\t, verified against real tmux) + an explicitresize-window -t <window_id>(NOTresize-pane— the session's attached client forces pane size to the client terminal;resize-windowsets the window size directly and sticks).killbranches:kill-window -t <window_id>for window-mode,kill-sessionfor session-mode.- Never-kill-attached —
kill()on a pane the tool didn't spawn is a no-op. Only panes registered viaspawnare eligible for lease/exit reaping. The user's live session/windows are never at risk. - Lease — session-mode 30 min, window-mode 2 h (generous — user may
inspect after the run); refresh-on-activity, single
setIntervalreap sweep (60s,unrefed).process.on('exit')reaps all spawned windows/sessions best-effort (mode-aware:kill-windowvskill-session). v0.4.2: NO SIGINT/SIGTERM listeners and neverprocess.exit— in-host signal ownership is forbidden (omp extension guard, #2); hard-killed hosts leak named, user-reapable sessions instead. waitForthrowsTermTimeoutErrorwith{pane, elapsed, timeout, pattern?, lastCapture}— no silent failures (CIPHER standard).sendKeysis pure literal (v0.2.0) —send-keys -lwith no escape interpretation. The v0.1.0parseKeystokenizer was removed (its textual- escape handling didn't match the raw-byte mapping). UsesendKeyfor special keys. Table-driven unit tests cover the literal path.
Single term tool, 9 actions: spawn | attach | send | sendKey | capture | waitFor | waitForQuiet | resize | kill. 1:1 with the lib. No /term slash,
no panel in v0.1 — the agent composes actions (getpipher UX convention: tool
action = agent-primary).