npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

pi-sticky-prompt

v0.1.3

Published

Always-on-top, full-width macOS prompt bar for pi. A floating native window that survives terminal scrollback and lets you keep typing while you read scrollback history.

Readme

pi-sticky-prompt

Always-on-top, full-width macOS prompt bar for pi.

sticky bar expanded

Pi runs in normal terminal scrollback (not alternate-screen mode), so when you scroll the terminal up to read history, the input prompt scrolls out of view with everything else. pi-sticky-prompt solves that with a tiny native macOS window that sits permanently on top of every other window, on every space, and talks to your live pi sessions over a Unix domain socket.

You can scroll the terminal as much as you want — the prompt stays glued to the bottom of the screen.

Demo

https://github.com/user-attachments/assets/4b8a7e41-6df2-4bf2-98d3-4cd1513aefd9

| Collapsed | Session picker | | --- | --- | | collapsed | session picker |

┌──────────────────────────────────┐         ┌──────────────────────────┐
│ Terminal running pi              │  UDS    │ PiStickyPrompt.app       │
│ (interactive, scrollback intact) │ ◄────── │ floating NSPanel         │
│                                  │         │ always on top            │
└──────────────────────────────────┘         └──────────────────────────┘

Features

  • 🪟 Native floating windowNSPanel with .floating level + .canJoinAllSpaces. Visible above every app, every space, even fullscreen Ghostty / Terminal / iTerm.
  • 🖥️ Auto-docked to the bottom edge of whichever screen has a terminal app open. Plug in a monitor or move Terminal across screens — the bar follows.
  • 🔒 Lock / unlock — locked: full-width pinned to bottom; unlocked: free-move, resize, drag between monitors.
  • 📜 Multi-session aware — every pi process publishes its own socket; the bar lists all live sessions in a picker (⌘L) and remembers your selection across launches.
  • ⌨️ Global hotkey ⌘⌥P to toggle visibility from anywhere on the system.
  • 📉 Collapse to a one-line preview of long input (⌘M); expanding grows upward leaving the toolbar flush with the screen edge.
  • 🚦 Status echo — model, session name, and a live streaming indicator (green = idle, yellow = streaming, red = disconnected).
  • ↩️ Auto-focus the terminal after sending — keystrokes you make right after pressing Enter land in the terminal hosting that pi session, not in the bar.
  • 🛑 Abort current pi turn with Esc; press Esc twice quickly to hide the bar.

Requirements

  • macOS 13+ (Apple Silicon)
  • A pi installation (@mariozechner/pi-coding-agent)
  • Homebrew (for installing the HUD app)

Tested with Ghostty, Terminal.app, iTerm2, Alacritty, WezTerm, kitty, and Warp.

Building from source additionally requires Xcode command-line tools (xcode-select --install) and Swift 5.9+ — see Development.

Install

pi-sticky-prompt has two halves and each lives in the registry that fits it best:

| Half | What it does | Where it lives | | --- | --- | --- | | Extension | Lets pi sessions expose themselves over a Unix domain socket so the HUD can find them | npm — npm:pi-sticky-prompt | | HUD app | The native macOS floating window itself | Homebrew cask — pi-sticky-prompt |

1. Install the pi extension

pi install npm:pi-sticky-prompt

Reload pi (/reload) or start a fresh session. Each session will now publish a socket + descriptor under ~/.pi/agent/sockets/.

2. Install the macOS HUD

Recommended — Homebrew:

brew tap alonmartin2222/pi
brew install --cask pi-sticky-prompt

First launch may show a Gatekeeper prompt because the app is ad-hoc signed — right-click PiStickyPrompt.app in /Applications and pick Open once to whitelist it.

Alternative — download the prebuilt zip from a GitHub release:

  1. Grab PiStickyPrompt.app.zip from https://github.com/alonmartin2222/pi-sticky-prompt/releases/latest
  2. Unzip and drag PiStickyPrompt.app into /Applications

Alternative — build from source: see Development below.

3. Launch

Open PiStickyPrompt.app (Spotlight / Launchpad / open -a PiStickyPrompt). Add it to your Login Items in System Settings if you want it always running. Press ⌘⌥P to toggle the bar.

Usage

  1. Start any number of pi sessions in any terminal. Each session writes:
    • socket: ~/.pi/agent/sockets/pi-<pid>.sock
    • descriptor: ~/.pi/agent/sockets/pi-<pid>.json
  2. Launch PiStickyPrompt.app. It scans the descriptor directory and auto-attaches to the most-recent live session (or the one you previously chose).
  3. Type. Enter sends; Shift+Enter inserts a newline.

Keys

While the bar has keyboard focus:

| Key | Action | | ------------------ | --------------------------------------------------- | | ⌘⌥P (global) | Toggle bar visibility from anywhere on the system | | Enter | Send the prompt to the attached pi session | | Shift+Enter | Insert a newline inside the editor | | Esc | Abort current pi turn (twice quickly: hide bar) | | ⌘M | Collapse to one-line preview / expand back | | ⌘L | Open the session picker | | ⌘W | Hide the bar |

A status-bar icon (π▸) also exposes Toggle / Pick Session / Quit.

Toolbar

[●  session-name  │  model/name]                       [≡  🔒  ▲]
 │   │                │                                 │   │   │
 │   │                │                                 │   │   └ collapse / expand
 │   │                │                                 │   └ lock / unlock
 │   │                │                                 └ session picker
 │   │                └ provider/model
 │   └ session name (or cwd basename if unnamed)
 └ status dot: green = idle · yellow = streaming · red = disconnected

When idle, sending a prompt triggers a new turn. When pi is mid-turn (yellow dot), sending steers the running turn instead of queueing — same behaviour as typing in the pi TUI itself.

Lock vs unlock

  • 🔒 locked (default) — full screen-width, pinned to the bottom of whichever screen has a terminal app open. Re-snaps automatically on display changes (NSApplication.didChangeScreenParametersNotification).
  • 🔓 unlocked (orange tint) — drag from any background pixel to move, drag from the edges to resize, drag freely between monitors. The last unlocked frame is remembered. Click again to re-dock.

Architecture

Two pieces:

extensions/sticky-prompt.ts        ← TypeScript pi extension
PiStickyPrompt/                    ← Swift Package for the macOS HUD
├── Package.swift
├── Sources/PiStickyPrompt/
│   ├── main.swift                 ← entry point, sets accessory activation
│   ├── AppDelegate.swift          ← menu-bar item + global hotkey wiring
│   ├── HUDController.swift        ← owns the panel, picks a session, locking
│   ├── HUDPanel.swift             ← NSPanel subclass; canBecomeKey overrides
│   ├── PromptView.swift           ← top toolbar + editor + status row
│   ├── PromptTextView.swift       ← NSTextView with Enter/Esc/⌘M handling
│   ├── BridgeClient.swift         ← UDS client; line-delimited JSON protocol
│   ├── SessionDiscovery.swift     ← scans ~/.pi/agent/sockets for live pids
│   ├── TerminalScreen.swift       ← finds which NSScreen hosts a terminal
│   ├── TerminalLocator.swift      ← walks parent PIDs to find owning terminal
│   └── Hotkey.swift               ← Carbon RegisterEventHotKey wrapper
└── make-app.sh                    ← bundles the binary into a .app

Wire protocol

Line-delimited JSON over the Unix domain socket (LF only, both directions):

server -> client
  {"type":"hello",  pid, cwd, sessionFile, sessionName?, model?, streaming, started}
  {"type":"state",  streaming, model?, sessionName?}
  {"type":"ack",    ok, command:"prompt"|"abort", error?}
  {"type":"bye"}

client -> server
  {"type":"prompt", text}
  {"type":"abort"}
  {"type":"ping"}

You can drive the bridge from the shell to verify it without the HUD:

SOCK=$(ls -t ~/.pi/agent/sockets/pi-*.sock | head -1)
echo '{"type":"prompt","text":"hello from nc"}' | nc -U "$SOCK"

Permissions

  • No Accessibility permission required. We never use AX APIs.
  • No Screen Recording permission required. CGWindowListCopyWindowInfo returns window owner + bounds without it; we read only those, never pixels or window names.
  • The global hotkey uses Carbon's RegisterEventHotKey, which works for accessory (LSUIElement) apps without any permission prompts.

Auto-focus to terminal on send

After a successful prompt ack, the HUD walks the BSD process tree upward from the pi session's PID using sysctl(KERN_PROC_PID) until it finds an ancestor whose bundle ID matches a known terminal app (Ghostty, Terminal, iTerm2, Alacritty, WezTerm, kitty, Warp, Hyper). It then calls NSRunningApplication.activate(.activateIgnoringOtherApps) on that app. This brings the terminal to the front so your next keystroke goes to pi output instead of the now-empty input bar.

Multiple pi sessions

The pi extension publishes one socket + descriptor per pi process. The HUD scans the directory, hides any whose PID is no longer running, and shows the rest in the session picker (⌘L). The current selection is persisted in UserDefaults as pi.preferredPID so re-launches reattach to the same session if it's still alive.

Heads-up: macOS doesn't expose per-window activation through NSRunningApplication. If you have multiple windows of the same terminal app, only the most-recently-focused one of that app comes forward. Per- window raising would require Accessibility permission, which this project deliberately avoids.

Disabling

  • Hide the bar with ⌘⌥P or quit it from the menu bar.
  • To remove the extension half: pi remove npm:pi-sticky-prompt (or whichever spec you used to install it).
  • To keep the extension but stop the HUD: just don't launch the app. The socket sits unused; pi sessions don't notice.

Limitations

  • The bar is viewport-pinned because it is a separate macOS window, not because pi affects terminal scrollback. Terminal scrollback itself is unchanged.
  • One HUD process per machine is the intended deployment. Multiple HUDs can connect to the same socket but they will all see each other's state echoes.
  • macOS only. The HUD uses AppKit. The pi extension itself is cross-platform Node code, but the only client implementation today is the macOS app.
  • Tested only on macOS 13+ on Apple Silicon. Intel builds should work (the binary is built for arm64 only by default — drop in a universal slice in make-app.sh if needed).

Development

You only need this section if you're hacking on the source. End users should use Homebrew instead.

Prerequisites

  • Xcode command-line tools: xcode-select --install
  • Swift 5.9+ (ships with current macOS)
  • Node.js ≥ 20 (for the extension half)

Build & run

git clone https://github.com/alonmartin2222/pi-sticky-prompt.git
cd pi-sticky-prompt

make debug          # fast rebuild for iteration
make release        # optimised build + ad-hoc-signed .app bundle
make install        # release build copied to ~/Applications
make run            # release build + open the .app

Use swift build -c debug directly if you don't need the .app bundle.

Releasing a new version

The entire release is automated by scripts/release.sh — one command from your local machine, no CI needed:

scripts/release.sh           # patch bump (0.1.x → 0.1.x+1)
scripts/release.sh minor     # 0.x.y → 0.(x+1).0
scripts/release.sh major     # x.y.z → (x+1).0.0
scripts/release.sh 0.4.7     # explicit version

In order, the script:

  1. Preflights: clean tree, on main, in sync with origin, required CLIs (npm, gh, swift, ditto, …) available, gh + npm both authenticated as alonmartin2222, sibling Homebrew tap cloned.
  2. Runs npm version <bump> — bumps package.json, creates a commit and a vX.Y.Z git tag.
  3. Builds the macOS HUD via PiStickyPrompt/make-app.sh release.
  4. Stamps CFBundleShortVersionString / CFBundleVersion in Info.plist to the new version and re-signs ad-hoc.
  5. ditto-zips PiStickyPrompt.appPiStickyPrompt.app.zip and computes its SHA-256.
  6. Pushes main and the new tag to origin.
  7. gh release create — creates the GitHub release with auto-generated changelog from the commits since the previous tag, and attaches the zip.
  8. Bumps the cask in ~/git/pi-extensions/homebrew-pi (Casks/pi-sticky-prompt.rbversion and sha256), commits, pushes.
  9. Runs npm publish — the npm CLI prompts you for your 2FA OTP interactively.

One-time setup before the script will run:

  • npm login — authenticated as alonmartin2222.
  • gh auth login — authenticated as alonmartin2222. If your default gh account is something else, drop a personal access token (Contents: write on both pi-sticky-prompt and homebrew-pi) at ~/.config/pi-sticky-prompt/github-token; the script picks it up.
  • The tap repo cloned at ~/git/pi-extensions/homebrew-pi.

If any step fails, the script prints recovery instructions (how to undo the bump commit / delete the GitHub release / retry npm publish) so you never end up in a half-released state.

Contributing

Issues and PRs welcome at https://github.com/alonmartin2222/pi-sticky-prompt. The codebase is intentionally small:

  • extensions/sticky-prompt.ts — ~250 lines TypeScript
  • PiStickyPrompt/Sources/PiStickyPrompt/*.swift — ~900 lines Swift

The Carbon RegisterEventHotKey symbol signature is 'piPb' (0x70695062) — historical, but kept stable so config files stay portable.

License

MIT — see LICENSE.