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

v1.3.0

Published

A highly secure bash confirmation extension for pi, using the unbash AST parser to perfectly intercept subshells and logic gates.

Readme

pi-unbash 🛡️

A high-security, AST-powered bash confirmation extension for the pi coding agent.

Why pi-unbash?

Most bash confirmation extensions rely on simple string matching, regular expressions, or custom lexers to determine what commands an AI is trying to run. Those approaches can work for many cases, but they tend to get brittle once shell syntax becomes deeply nested or heavily composed. If an AI generates a command like:

FOO=bar echo "$(git status && `rm -rf /`)"

it is not enough to notice that the raw string contains suspicious text somewhere. The harder problem is to comprehensively extract the embedded commands that will actually execute, even when they are buried inside substitutions, pipelines, redirects, or control-flow syntax.

pi-unbash is different. It uses unbash, a fast, zero-dependency TypeScript parser that generates a full POSIX-compliant Abstract Syntax Tree (AST). pi-unbash recursively traverses that tree to extract embedded commands no matter how complicated the full shell command becomes—across pipes (|), logic gates (&&, ||), subshells ($(), `...`), heredocs, and more.

That same AST also makes the approval prompt easier to read: instead of showing only the raw LLM-generated shell string, pi-unbash can format the extracted commands into a clearer, more compact preview that is easier to approve or reject in the terminal UI.

If the AI tries to sneak an unapproved command past you, pi-unbash will catch it and block execution until you explicitly confirm it via the terminal UI.

Installation

You can install pi-unbash globally into your pi settings:

# Install globally
pi install npm:pi-unbash

# Or install locally for testing
pi -e ./path/to/pi-unbash

Usage

By default, pi-unbash allows a set of safe, read-only commands to execute silently. See src/defaults.ts for the full list.

If the AI attempts to run anything else (e.g., git commit, npm, rm, node), the execution is paused, and a confirmation dialog appears in your pi session:

⚠️ Unapproved Commands

 - npm test
 - git commit -A -m "update files"

 → Allow
   Always allow npm, git (this session)
   Reject

Allow runs the command once. Always allow X (this session) adds the base command(s) to an in-memory allowlist for the rest of the session — no prompts for that command again until you reload. Reject blocks execution.

Configuration

Settings are persisted globally in ~/.pi/agent/settings.json under the "unbash" key:

{
  "packages": [
    "npm:pi-unbash"
  ],
  "unbash": {
    "enabled": true,
    "alwaysAllowed": [
      "ls",
      "pwd",
      "cd",
      "cat",
      "echo",
      "grep",
      "find",
      "git"
    ]
  }
}

Allowlist

The alwaysAllowed setting controls which commands pass silently. You can allow a base command (all subcommands), or a specific subcommand (only matching invocations):

{
  "unbash": {
    "alwaysAllowed": [
      "ls", "pwd", "cd", "cat", "echo", "grep", "find",
      "git status",
      "git log",
      "git diff",
      "jira issue view",
      "git branch --show-current"
    ]
  }
}

Matching uses subsequence logic — the tokens in your allowlist entry must appear in order in the actual command, but extra flags and trailing arguments are permitted:

| Allowlist Entry | Matches | Doesn't Match | |----------------|---------|---------------| | git | all git commands | — | | git status | git status, git status --short | git commit -m "msg" | | git branch --show-current | git branch --show-current, git branch -v --show-current | git branch -D main | | jira issue view | jira issue view PROJ-123, jira issue view --verbose PROJ-123 | jira issue create |

Display Settings

The confirmation prompt elides long command arguments to keep the display readable:

  • The command name is always shown in full.
  • If the full command fits within commandDisplayMaxLength, it is shown unchanged.
  • Otherwise, the formatter shrinks later tokens only as much as needed to fit the total budget.
  • Path arguments (starting with /, ~/, ./, or ../) get path-aware middle elision that preserves the tail.
  • Other long arguments are prefix-truncated with only when needed.
  • commandDisplayArgMaxLength acts as the minimum per-token elision target, not a hard cap when there is still room in the overall display budget.
  • If the total display still exceeds commandDisplayMaxLength, the whole string is hard-truncated.
{
  "unbash": {
    "commandDisplayMaxLength": 120,
    "commandDisplayArgMaxLength": 40
  }
}
  • commandDisplayMaxLength — total character budget for the display string (default: 120).
  • commandDisplayArgMaxLength — minimum per-token elision target when shrinking long arguments/heredocs to fit the overall display budget (default: 40).

Commands

You can manage settings dynamically mid-session using the /unbash command:

  • /unbash allow <command> - Permanently allow a command (e.g., /unbash allow git or /unbash allow git status)
  • /unbash deny <command> - Remove a command from the allowed list (e.g., /unbash deny git status)
  • /unbash toggle - Turn the entire confirmation system on or off
  • /unbash list - Show current status, allowed commands, and session-allowed commands

License

MIT