omp packages

@monotykamary/pi-localterm0.5.1

localterm <-> pi integration: Kitty graphics for the browser renderer, scrubbing localterm-managed secret env vars from the agent's bash-tool children, and OSC 9 desktop notifications when the agent finishes a long turn.

GitHub Actions Published 3 days ago MIT ~584 downloads/mo

Untested on omp

This is a pi package. No one has reported whether it works on omp yet. If you try it, add your result below.

Did it work for you?

Result

One report per person. A new report replaces your old one.

Reports 0

No reports yet.

Readme

@monotykamary/pi-localterm

A pi extension that integrates localterm with pi. Three features, all inert outside localterm:

  1. Kitty graphics + OSC 8 links — localterm renders xterm.js with Kitty graphics and web-link support, but sets TERM=xterm-256color and strips terminal-identity env vars so applications do not infer unrelated emulator features. pi-tui therefore reports images/hyperlinks as unsupported. This extension detects LOCALTERM=1 (injected into every localterm PTY) and defaults Pi v1's PI_IMAGE_PROTOCOL and PI_HYPERLINKS overrides to Kitty and enabled. Explicit environment overrides and Pi's terminal.images / terminal.hyperlinks settings remain authoritative; it does not spoof another terminal's identity. Localterm handles ordinary Kitty placements, direct/chunked payloads, temp-root file media, and U=1 Unicode virtual placements used by pi-math and Neovim image integrations.
  2. Secret scrubbing for the agent's bash tool — localterm injects a secret only into the shimmed process's env (pi's), not its parent shell. But pi's bash tool spawns commands with { ...process.env }, so without this the agent's commands would inherit every secret pi received. This extension overrides the bash tool with a spawn hook that deletes the pi process's localterm-managed secret env vars from each command's child env only — pi's own process.env (and its provider calls) keep them.
  3. Desktop notifications on agent completion — pi's only notification primitive is ctx.ui.notify, an in-TUI banner invisible once you switch away from the pi tab. localterm already has an OSC 9 (ESC ] 9 ; MESSAGE BEL) → browser desktop-notification pipeline (opt-in via "Desktop alerts" in Settings). The extension writes an OSC 9 on agent_settled, reusing that pipeline so a user who stepped away gets an OS notification only after the agent has no automatic retry, compaction, or queued continuation left. It also coordinates with @monotykamary/pi-retry through Pi's shared extension event bus so that extension's delayed hidden retries do not produce intermediate notifications. Threshold-gated (turns ≥ 30 s) so quick back-and-forth doesn't spam a focused user; TUI-mode-guarded so json/rpc/-p stdout isn't polluted with OSC bytes. Note: emitting OSC 9 also fires localterm's notification automation trigger, so a notification-event automation will fire on agent completion.

Install

From npm (published package):

pi install npm:@monotykamary/pi-localterm

From source (this monorepo, for a one-off run):

git clone https://github.com/monotykamary/localterm
pi -e ./localterm/packages/pi-extension
Manual install (load on every session)

Clone and add the package to pi's global settings so it loads automatically:

git clone https://github.com/monotykamary/localterm ~/src/localterm

Then edit ~/.pi/agent/settings.json:

{
  "packages": ["/Users/you/src/localterm/packages/pi-extension"]
}

Or, for a project-only install, add the same path to <cwd>/.pi/settings.json instead. Then /reload in pi.

The extension auto-activates only inside localterm (LOCALTERM=1); outside localterm it registers nothing and pi behaves exactly as default.

Pi v1 fullscreen images

Pi v1 defaults to fullscreen mode and reuses uploaded Kitty images when scrolling. LocalTerm's patched image addon preserves uploads across placement-only deletion, keeps image tiles through line clears, and separates normal/alternate-buffer state. The fix ships in LocalTerm's terminal UI, not only this extension. Update LocalTerm as well as the extension, reload the browser UI, and start a fresh Pi process so both bundled and extension-visible capability caches use the new overrides. Existing Pi settings such as terminal.showImages: false are unchanged.

For an older LocalTerm UI, pi --tui-mode regular avoids the fullscreen redraw path while you arrange the update. The browser regression probe is documented in harness/pi-images.

How the scrub works

localterm stores secret policy (names + the env var each exports) in ~/.localterm/secrets.json and per-process wiring (pi → which secret names it receives) in ~/.localterm/processes.json. Only names and env vars — never values (values live in the macOS Keychain). The extension reads those two files to find the env-var names the pi process is wired to, and strips exactly those from each bash-tool child's environment.

Resolution mirrors the shim 1:1: the shim injects the pi process's requestedSecrets (resolved to env vars); the scrub strips exactly that set. The strip set is recomputed on session_start (new / resume / fork / reload), so a policy change is picked up on the next session transition.

This extends localterm's existing least-privilege property — "the shimmed binary sees the key, its parent shell doesn't" — to "pi sees the key, the agent's bash commands don't." It converts silent env inheritance into an explicit, greppable localterm secret get <name> call when an agent's command genuinely needs a key.

What this is not

This is defense-in-depth, not a security boundary. The keys still live in pi's own process.env, so a command the agent generates can recover them via parent-process introspection (ps eww $PPID on macOS, /proc/$PPID/environ on Linux) or by shelling out to security find-generic-password directly (the shim's own resolution path). The scrub stops passive/accidental leakage (env, printenv, a script reading $VAR), not active exfiltration by a prompt-injected or adversarial agent.

For untrusted or unmonitored agents, don't wire secrets to the pi process at all — give pi its provider keys through pi's own config, and run pi in a container/VM/micro-VM with short-lived credentials.

Overriding the bash tool

The scrub overrides pi's built-in bash tool by name (extensions apply after the built-in in pi's tool registry). It reconstructs the tool via createBashToolDefinition and preserves a user's configured shellPath and shellCommandPrefix (read from ~/.pi/agent/settings.json + <cwd>/.pi/settings.json) so the override is behavior-identical to the built-in apart from the env scrub. If another extension also overrides bash, only the first-registered one wins — that's a pi-level constraint.

Fabric background-shell integration

With pi-fabric 0.92.33 or newer, nested pi.bash calls use Fabric's local process runner while retaining this extension's environment scrub and streaming output redaction. Fabric owns automatic backgrounding, background: true, cwd, PIDs, hard timeouts, cancellation, and session cleanup. Output is redacted before Fabric records previews or background logs; Pi's own credentials remain intact.

The registered bash definition carries the host-local Symbol.for("pi-fabric:bash-middleware:v1") capability. No Fabric dependency, second tool registration, or load-order handshake is needed. Without compatible Fabric, the same standalone scrubbed/redacted bash implementation runs as before. Policy refresh on session_start applies to future commands through either path.

Both packages must be updated, then /reload Pi to load the rebuilt extensions. This remains defense-in-depth, not protection against deliberate secret recovery.

Requirements

  • pi ≥ 1.0.0 (uses the documented Pi capability overrides, agent_settled, the shared extension event bus, the spawnHook tool option, and createBashToolDefinition). Older Pi installations should keep pi-localterm 0.4.x.
  • localterm with LOCALTERM=1 in the PTY environment (v0.7+). The scrub additionally needs localterm's secrets/processes policy files on the same machine.

License

MIT