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

@statechange/ssh-tunnel-manager

v0.1.2

Published

Declarative SSH tunnel manager with a CLI and macOS menu bar app. Define your tunnels in a JSON config — the tool keeps them running.

Readme

SSH Tunnel Manager

Declarative SSH tunnel manager with a CLI and macOS menu bar app. Define your tunnels in a JSON config — the tool keeps them running.

localhost:5432 ──► bastion.example.com ──► db.internal:5432
localhost:8080 ──► jump.example.com   ──► admin.internal:8080

Install

With an AI agent (recommended)

The best way to use SSH Tunnel Manager is through an AI agent skill. Install the skill, then just tell your agent what tunnels you need — it handles the rest.

npx skills add statechangelabs/ssh-tunnel-manager

This adds the ssh-tunnel and ssh-tunnel-debug skills to your agent. Then you can say things like:

"Set up an SSH tunnel to my Postgres database on bastion.example.com"

"My tunnel to the staging server isn't connecting"

The agent will install the CLI if needed, create the tunnel, verify it's working, and troubleshoot any issues.

Direct install

npm install -g @statechange/ssh-tunnel-manager

This single command:

  • Installs the ssh-tunnels CLI globally
  • Creates ~/.ssh-tunnels/ directories
  • Sets up a macOS LaunchAgent for the menu bar app
  • Starts the menu bar app automatically

CLI Usage

# See all tunnels and their status
ssh-tunnels status

# Add a tunnel
ssh-tunnels add \
  --name "Prod Postgres" \
  --host bastion.example.com \
  --user root \
  --localPort 5433 \
  --remoteHost db.internal \
  --remotePort 5432 \
  --enabled

# Enable / disable / remove
ssh-tunnels enable prod-postgres
ssh-tunnels disable prod-postgres
ssh-tunnels remove prod-postgres

# View logs (first place to look when a tunnel fails)
ssh-tunnels logs prod-postgres

# Sync all tunnels to match config
ssh-tunnels sync

# Watch config and auto-sync on changes
ssh-tunnels watch

# JSON output for scripting / AI agents
ssh-tunnels status --json
ssh-tunnels enable prod-postgres --json

Menu Bar App

The Electron menu bar app runs as a macOS LaunchAgent and provides:

  • Tray icon — green (all OK), yellow (partially running), red (failures)
  • Click to toggle tunnels on/off
  • Add Tunnel form
  • Sync Now button
  • Auto-recovery — syncs every 30 seconds, restarts crashed tunnels

The app and CLI share the same config file (~/.ssh-tunnels/config.json). Changes from either side are reflected in both.

How It Works

Tunnels are defined in ~/.ssh-tunnels/config.json:

{
  "tunnels": [
    {
      "id": "prod-postgres",
      "name": "Prod Postgres",
      "host": "bastion.example.com",
      "user": "root",
      "localPort": 5433,
      "remoteHost": "db.internal",
      "remotePort": 5432,
      "enabled": true
    }
  ]
}

When a tunnel is enabled, the manager spawns a detached ssh -N -L ... process and writes its PID to ~/.ssh-tunnels/pids/. The sync command reconciles running processes against the config — starting missing tunnels and stopping ones that should be off.

Common Ports

| Port | Service | |-------|-------------| | 5432 | PostgreSQL | | 3306 | MySQL | | 6379 | Redis | | 27017 | MongoDB | | 8080 | Dev server | | 9200 | Elasticsearch |

Troubleshooting

| Symptom | Likely cause | Fix | |---------|-------------|-----| | "Permission denied (publickey)" | Wrong SSH user | Recreate with --user root | | Tunnel stops immediately | Auth failure or port conflict | ssh-tunnels logs <id> | | "Address already in use" | Port conflict | lsof -i :<port> | | Tunnel starts but port not open | Remote service down | SSH in and check the service |

For detailed diagnostics, install the ssh-tunnel-debug skill or check the debug guide.

Uninstall

# Stop the menu bar app and remove the LaunchAgent
launchctl unload ~/Library/LaunchAgents/com.statechange.ssh-tunnel-manager.plist
rm ~/Library/LaunchAgents/com.statechange.ssh-tunnel-manager.plist

# Remove the CLI
npm uninstall -g @statechange/ssh-tunnel-manager

# Optionally remove config and data
rm -rf ~/.ssh-tunnels

License

MIT