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

@chatpanel/channels

v0.1.0

Published

Drive ChatPanel agents from external messaging surfaces (Telegram, WhatsApp). One normalize→invoke→stream core per platform, wired through @chatpanel/pii redaction and the @chatpanel/events audit log. The local Telegram shape is outbound-only (long-poll)

Readme

@chatpanel/channels

Drive your local ChatPanel agent from an external messaging surface — today Telegram, next WhatsApp. A phone message becomes an agent turn on your machine, streamed back to the chat, with PII redacted before anything leaves for the model and every run written to an audit log.

Design doc: chatpanel/docs/feature-f7-remote-channels.md.

Why this shape

The Telegram adapter uses getUpdates long-poll, which is outbound-only — the same property as Claude Code Remote Control: your machine never opens an inbound port, works behind NAT, needs no tunnel or public IP. The only hop that reaches the agent is the bridge on 127.0.0.1:4319, and it never leaves the box.

Telegram getUpdates ─long-poll→ @chatpanel/channels ─POST /chat (bridge token)→ chatpanel-bridge
     ↑ editMessageText (throttled) ←── SSE delta/done ──────────────────────────────────┘
                     │ normalize → pairing gate → pii.redact → capability(actor.kind:'channel')
                     ▼ append capability.invoked / privacy.redacted / privacy.egress

Layout

| file | role | pure? | |---|---|---| | src/normalize.js | platform message → one normalized shape | ✅ | | src/pairing.js | who may drive it, and their reach ceiling | ✅ | | src/invoke.js | normalized → capability invocation + pii redact + audit events | ✅ | | src/stream.js | bridge SSE → folded reply (+ Telegram split/throttle) | ✅ | | src/bridge.js | POST /chat (SSE) + /cancel on the local bridge | net | | src/eventlog.js | append-only JSONL sink over @chatpanel/events appender | net | | src/adapters/telegram.js | getUpdates long-poll transport (the LOCAL shape) | net | | bin/chatpanel-channels.js | CLI that wires it together | — |

The pure core is unit-testable without a bot or a bridge (npm test = 26 tests, incl. a real-socket SSE integration test).

Conversations are multi-turn: each chat keeps a bounded, redacted history so a follow-up ("…and the second one?") resolves against the prior answer. /new forgets it.

Run

npm install -g @chatpanel/channels   # or npx @chatpanel/channels telegram
  1. Start the bridge once (it writes ~/.chatpanel/bridge-token): chatpanel-bridge.
  2. Create a bot with @BotFather, copy its token.
  3. Run the adapter:
TELEGRAM_BOT_TOKEN=123:abc chatpanel-channels telegram
  1. Message your bot. It will say not paired. Pair the chat:
    • Bootstrap (dev): set CHANNELS_ALLOW=<yourChatId> before starting, or
    • Codes (real): mint a one-time code (pairing.requestCode() — surfaced in the extension) and send /pair <code> from the phone.

Chat commands: /pair <code>, /new (forget the conversation + fresh privacy vault), /stop, /help.

Env

| var | default | meaning | |---|---|---| | TELEGRAM_BOT_TOKEN | — | BotFather token (required) | | CHANNELS_ALLOW | — | comma list of chat ids to pre-pair (bootstrap) | | CHANNELS_AGENT | claude | bridge engine id (claude, codex, …) | | CHANNELS_PRIVACY | standard | standard restores real values for you · strict keeps [[PERSON_1]] in the reply | | CHANNELS_PII_TIER | basic | basic regex · full (needs a roster) also pseudonymizes people/orgs | | CHATPANEL_BRIDGE_URL | http://127.0.0.1:4319 | bridge address | | CHATPANEL_BRIDGE_TOKEN | — | overrides the token file |

Security posture (read before shipping)

This is the honest §7 of the design doc, made concrete:

  • PII redaction on egress is on by default and mandatory. Telegram bot traffic is not end-to-end encrypted, so inbound text is redacted (@chatpanel/pii) before it reaches the agent/model. CHANNELS_PRIVACY=strict additionally keeps placeholders in the reply so the provider never sees a real value either.
  • Pairing is authentication, not authorization. A chat-id allowlist + a paired code proves who sent a message. It does not bound what that message may do. Prompt-injection → tool execution is the real risk, because the bridge /chat runs shell/filesystem tools.
  • reach is carried but tool-scoping is the next layer (not yet built). Until it lands, run against a bridge whose agent is read-only / ask-mode for anything destructive. Do not point a write-capable, auto-approving agent at an untrusted chat.
  • Secrets: the BotFather token and the bridge token are the crown jewels. The bridge token is read 0600 from ~/.chatpanel; keep the bot token out of shell history (use a file / a keychain in a shipped build).

Every run leaves capability.invoked / privacy.redacted / privacy.egress in ~/.chatpanel/channels/events.jsonl — the audit trail neither Claude Code Remote nor Hermes has.

Status

Local (Telegram) shape: built. The WhatsApp/Cloudflare relay shape and the per-actor tool-authorization policy are designed but not built — see the feature doc, §5 build order.