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-9router

v0.1.2

Published

Pi Coding Agent extension for 9router with dynamic model discovery and local cache.

Readme

pi-9router

npm version npm downloads License: MIT GitHub release

Pi Coding Agent extension for 9router: register 9router as a Pi provider, discover models dynamically, enrich model metadata, and manage configuration from Pi with /9router.

Repository: https://github.com/ricatix/pi-9router npm package: https://www.npmjs.com/package/pi-9router

Why this exists

9router exposes an OpenAI-compatible API in front of many upstream models. This extension makes Pi see 9router as a native provider:

Pi Coding Agent ── OpenAI-compatible API ── 9router ── upstream models

You get one provider in Pi, backed by whatever models/routes your 9router instance exposes.

Features

  • Pi provider registration — registers 9router with Pi through registerProvider.
  • Dynamic model discovery — fetches available models from GET /v1/models.
  • OpenAI-compatible chat — uses Pi's openai-completions provider mode.
  • Model metadata enrichment — supplements discovered models with models.dev metadata when available.
  • Local model cache — starts from cache when possible, then refreshes in background.
  • Graceful startup — Pi remains usable even when 9router is not configured yet.
  • Dual env var support — accepts both NINE_ROUTER_* and 9ROUTER_* names.
  • Interactive setup — configure from Pi using /9router setup.
  • Slash command management — status, refresh, model listing, reasoning toggle, config clear.
  • Secret-safe output — API keys are not printed in status/error output.

Web search/fetch tools are intentionally not registered yet. The extension only exposes ninerouter_status until a stable 9router web-route contract is available.

Requirements

  • Pi Coding Agent
  • Bun for local development/build
  • A 9router API key and reachable 9router base URL

Default base URL:

https://9router.com/v1

Installation

From npm

pi install npm:pi-9router

If your Pi version uses ~/.pi/agent/settings.json package entries, add:

{
  "packages": ["npm:pi-9router"]
}

From GitHub

pi install git:github.com/ricatix/pi-9router

Or in ~/.pi/agent/settings.json:

{
  "packages": ["git:github.com/ricatix/pi-9router"]
}

Local checkout

git clone https://github.com/ricatix/pi-9router.git
cd pi-9router
bun install
bun run build

Then add local path to Pi settings:

{
  "packages": ["/absolute/path/to/pi-9router"]
}

Example:

{
  "packages": ["/Users/ricoaditya/Project/open-source-project/pi-9router"]
}

Restart Pi after changing packages.

Note: Pi's npm/git package loader discovers extensions through the pi.extensions manifest in package.json. This package declares pi.extensions: ["./dist/index.js"], so no extra wiring is required — Pi will import the built entry-point on startup. Local-path installs also work, but rely on a different fallback path in the host.

Configuration

You can configure 9router by environment variables or by /9router setup.

Environment variables

Recommended variable names:

export NINE_ROUTER_API_KEY="your-api-key"
export NINE_ROUTER_BASE_URL="https://9router.com/v1"

Also supported:

export 9ROUTER_API_KEY="your-api-key"
export 9ROUTER_BASE_URL="https://9router.com/v1"

NINE_ROUTER_* is safer in shells because variable names beginning with digits can be awkward or invalid in some environments.

Config files

Persistent config:

~/.pi/agent/9router-config.json

Model cache:

~/.pi/agent/9router-models-cache.json

Files containing secrets are written with restricted permissions when possible.

URL normalization

NINE_ROUTER_BASE_URL can be provided with or without /v1:

https://9router.com
https://9router.com/v1

Both normalize to:

https://9router.com/v1

Protocol is required. Use https://... or http://....

Usage

Start Pi after installing/configuring the extension:

pi

Run status:

/9router status

Refresh discovered models:

/9router refresh

List cached models:

/9router models

Open interactive setup:

/9router setup

After discovery succeeds, select a 9router model from Pi's model picker. Models are registered under provider 9router.

/9router commands

| Command | Description | | --- | --- | | /9router | Opens interactive setup when no sub-command is provided. | | /9router setup | Prompts for base URL and API key in Pi TUI. | | /9router status | Shows base URL, whether API key is set, cache count, and visible registry count when available. | | /9router refresh | Fetches latest models from 9router, enriches metadata, updates cache, and re-registers provider. | | /9router reload | Alias for refresh. | | /9router models | Prints cached model IDs. | | /9router reasoning on | Stores reasoning toggle as enabled. | | /9router reasoning off | Stores reasoning toggle as disabled. | | /9router clear | Clears local config and model cache. | | /9router debug | Alias for status. | | /9router config | Alias for setup. |

Note: reasoning config is persisted for future compatibility. Current provider model registration keeps reasoning disabled unless future 9router/Pi contracts expose a stable thinking mapping.

LLM tools

This extension registers one Pi tool:

| Tool | Description | | --- | --- | | ninerouter_status | Returns base URL, API-key presence, and cache count. |

Web search/fetch tools are not exposed in this release.

How startup works

  1. Read env vars and saved config.
  2. Normalize base URL.
  3. Register cached provider immediately if model cache exists.
  4. Refresh models in background when cache exists.
  5. On first run with no cache, wait for discovery so Pi can list models.
  6. If discovery fails but cache exists, keep cached models registered.
  7. If no API key exists, Pi still loads and /9router setup remains available.

Troubleshooting

/9router command is not registered

Pi's package loader only auto-loads an extension entry-point if the package declares it through the pi.extensions field in package.json. This package ships with:

{
  "pi": {
    "extensions": ["./dist/index.js"]
  }
}

If /9router is missing after pi install npm:pi-9router:

  1. Verify the installed package.json has the pi.extensions field:
    cat ~/.pi/agent/npm/node_modules/pi-9router/package.json | grep -A2 '"pi"'
  2. If absent, your installed version is older than 0.1.2. Reinstall:
    pi install npm:pi-9router
  3. Restart Pi (or run /reload) so the new manifest is picked up.
  4. Confirm the package is loaded:
    pi list
    npm:pi-9router should appear under User packages.

Local-path installs (local:/path/to/pi-9router) hide this issue because the host falls back to importing dist/index.js even without the manifest — but the manifest is still required for npm: and git: sources.

API key belum ada

Set API key using env vars or run:

/9router setup

No 9router models in Pi

Run:

/9router status
/9router refresh

Check:

  • NINE_ROUTER_API_KEY is set.
  • NINE_ROUTER_BASE_URL points to a reachable 9router endpoint.
  • GET <baseUrl>/models returns model data.

For default hosted 9router:

curl -H "Authorization: Bearer $NINE_ROUTER_API_KEY" https://9router.com/v1/models

Gagal refresh

Common causes:

  • Invalid API key.
  • Base URL missing protocol.
  • Network/TLS issue.
  • 9router instance returned no models.

The extension redacts long token-like strings and your literal API key from errors.

Interactive setup not available

/9router setup needs Pi TUI context. In non-interactive/headless mode, use env vars or edit:

~/.pi/agent/9router-config.json

Env var beginning with digit fails

Use NINE_ROUTER_API_KEY instead of 9ROUTER_API_KEY.

Development

git clone https://github.com/ricatix/pi-9router.git
cd pi-9router
bun install
bun run typecheck
bun test
bun run build

Project structure

pi-9router/
├── src/
│   ├── index.ts        # Pi extension entrypoint
│   ├── auth.ts         # env auth and base URL normalization
│   ├── discovery.ts    # 9router /models discovery
│   ├── enrichment.ts   # models.dev metadata enrichment
│   ├── validation.ts   # credential validation helper
│   ├── models.ts       # Pi/OpenCode model mapping helpers
│   ├── state.ts        # config/cache persistence
│   ├── commands.ts     # /9router command router
│   ├── web.ts          # reserved web helper module
│   ├── errors.ts       # custom errors
│   ├── util.ts         # hashing/redaction utilities
│   └── types.ts        # local shared types
├── tests/
│   └── core.test.ts
├── package.json
├── tsconfig.json
└── README.md

Validation

Run before pushing or publishing:

bun run typecheck
bun test
bun run build

Publishing checklist

Before publishing:

  1. Verify package metadata in package.json.
  2. Run validation commands.
  3. Confirm dist/ is fresh.
  4. Confirm README install commands point to the intended npm package.
  5. Confirm no secrets in config, cache, shell history, or test fixtures.
  6. Pick the next version (semver): MAJOR.MINOR.PATCH for stable, MAJOR.MINOR.PATCH-rc.N for pre-release.
  7. Push the tag — the workflow handles the rest.

Stable release:

git tag v0.2.0
git push origin v0.2.0
# workflow runs typecheck + test + build + npm publish --provenance

Pre-release (lands under the next dist-tag, leaves latest untouched):

git tag v0.2.0-rc.1
git push origin v0.2.0-rc.1

Manual one-off publish (requires npm login + 2FA OTP, no provenance):

bun install
bun run typecheck
bun test
bun run build
npm publish --otp=<code>

Install published package:

pi install npm:pi-9router
# or pin a pre-release
pi install npm:pi-9router@next

Release & CI/CD

The .github/workflows/publish.yml workflow runs on every v*.*.* tag push and:

  1. Installs Bun + Node 24 + latest npm (npm 11.5.1+ is required for OIDC).
  2. Runs bun install --frozen-lockfile, bun run typecheck, bun test, bun run build.
  3. Syncs package.json#version to the pushed tag.
  4. Publishes to npm with --provenance. Pre-release tags are published under the next dist-tag.

Why Node 24 / npm 11.5.1+

Trusted publishing via OIDC requires npm 11.5.1+ to perform the token exchange with npmjs.com. Node 22 ships with npm 10.x, which silently fails the OIDC handshake and surfaces a misleading E404 'package@version' is not in this registry error. Node 24 LTS ships with npm 11.x and works out of the box.

Why no registry-url on setup-node

When you set registry-url on actions/setup-node@v4, the action writes a //registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN} line to .npmrc. With no NODE_AUTH_TOKEN secret configured (the intended state for OIDC), the placeholder expands to an empty string. npm then treats that as "auth is configured" and short-circuits the OIDC token exchange. The workflow sets the registry via npm config set instead.

One-time setup

After the first manual publish, configure the trusted publisher at:

https://www.npmjs.com/package/pi-9router/access

with:

| Field | Value | | --- | --- | | Repository owner / org | ricatix | | Repository name | pi-9router | | Workflow filename | publish.yml | | Environment name | (leave empty) |

After that, every push of a v*.*.* tag is published automatically with no NPM_TOKEN secret.

Security

  • API keys are sent only to the configured 9router base URL through Authorization: Bearer ....
  • Status output shows only set or unset, never key values.
  • Config/cache files are written under ~/.pi/agent/.
  • Config files are restricted to owner read/write where the platform allows it.
  • Model cache contains model metadata, not credentials.
  • Do not commit local ~/.pi/agent/9router-config.json or API keys.

Report security issues privately through GitHub once repository security advisories are enabled:

https://github.com/ricatix/pi-9router/security

Roadmap

  • Stable web search/fetch tools after 9router web-route contract is finalized.
  • Full reasoning/thinking mapping when Pi and 9router expose a stable compatible shape.
  • More integration tests against a live Pi extension runtime.

License

MIT © 2026 ricatix. See LICENSE for the full text.