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

@hasna/bridge

v0.2.1

Published

Agent messaging bridge for Telegram and other channels

Readme

bridge

bridge connects local coding agents to external messaging channels. The local folder is open-bridge; the public package is @hasna/bridge; the CLI is bridge.

Install

bun install -g @hasna/bridge

Commands

The 0.2.x direction is session-first. A channel conversation attaches to a bridge session, and normal messages go to that session. Agent adapters that do not yet expose a stable create/send/resume API are marked compatibility in session state.

Session surface:

bridge sessions list
bridge sessions create --agent codewith --cwd /repo
bridge sessions attach SESSION_ID --channel telegram-main --conversation 123456789
bridge sessions use SESSION_ID --channel telegram-main --conversation 123456789
bridge sessions detach --channel telegram-main --conversation 123456789
bridge sessions pause SESSION_ID
bridge sessions resume SESSION_ID
bridge sessions close SESSION_ID
bridge sessions send SESSION_ID "status"

Route compatibility surface:

bridge init
bridge doctor
bridge channels add-telegram telegram-main --token-env TELEGRAM_BOT_TOKEN --allowed-chat-ids 123456789
bridge channels add-imessage imessage-main --allowed-handles +15555550100 --default-handle +15555550100
bridge profiles add codewith-main --agent-kind codewith --auth-profile account001 --cwd /Users/hasna
bridge agents add codewith --kind codewith --profile codewith-main
bridge routes add telegram-codewith --from telegram-main --to codewith --chat-ids 123456789
bridge serve
bridge daemon start

The session-backed multi-channel plan for the 0.2.x release is tracked in docs/session-bridge-plan.md.

Useful inspection commands:

bridge config path
bridge config show
bridge channels list
bridge profiles list
bridge agents list
bridge routes list

Direct operations:

bridge send telegram-main 123456789 "hello"
bridge send imessage-main +15555550100 "hello"
bridge ask codewith "summarize this repo"
bridge route-message --channel telegram-main --chat-id 123456789 --text "status" --json
bridge sessions route-message --channel telegram-main --chat-id 123456789 --text "status" --json

Daemon operations:

bridge daemon start
bridge daemon status
bridge daemon logs --lines 100
bridge daemon restart
bridge daemon stop

bridge daemon start uses the process supervisor by default. It starts bridge serve in the background, inherits the current environment, and writes private metadata and logs under ~/.hasna/bridge/daemon.

For login-started services:

bridge daemon install --supervisor auto
bridge daemon start --supervisor auto
bridge daemon stop --supervisor auto
bridge daemon uninstall --supervisor auto

install writes a user launchd file on macOS or a user systemd file on Linux. Telegram token values are not written to those files. Make token environment variables available to the user service manager before starting an installed daemon.

macOS:

launchctl setenv TELEGRAM_BOT_TOKEN "$TELEGRAM_BOT_TOKEN"
bridge daemon start --supervisor launchd

Linux:

systemctl --user import-environment TELEGRAM_BOT_TOKEN
bridge daemon start --supervisor systemd

Profiles

Profiles let one bridge process route messages to multiple accounts without changing global agent login state.

Codewith:

bridge profiles add cw-account001 --agent-kind codewith --auth-profile account001 --cwd /repo
bridge agents add codewith-main --kind codewith --profile cw-account001

Claude:

bridge profiles add claude-account001 --agent-kind claude --home ~/.hasna/accounts/profiles/claude/account001
bridge agents add claude-main --kind claude --profile claude-account001

AIcopilot:

bridge profiles add aicopilot-main --agent-kind aicopilot --cwd /repo
bridge agents add aicopilot-main --kind aicopilot --profile aicopilot-main

MCP

bridge-mcp exposes:

  • bridge_status
  • bridge_config
  • bridge_session_list
  • bridge_session_status
  • bridge_session_create
  • bridge_session_attach
  • bridge_session_send
  • bridge_session_route_message
  • bridge_route_message

Use bridge_session_route_message for normal inbound channel behavior through session bindings. bridge_route_message remains for compatibility with explicit stateless routes.

State

Default config path:

~/.hasna/bridge/config.json

Override with BRIDGE_HOME or BRIDGE_CONFIG.

bridge stores configuration and runtime state with private file permissions. Telegram bot tokens should stay in environment variables; config stores the env var name, not the token value. Telegram channels fail closed unless allowedChatIds are set or allowAllChats is explicitly enabled. Disabled channels do not match or deliver routes. Channel-level allowedChatIds are enforced before route matching, and long-poll offsets are persisted in ~/.hasna/bridge/state.json so restarts do not replay already-seen terminal updates. MCP config inspection redacts profile and agent environment values.

Session state also lives in ~/.hasna/bridge/state.json: sessions, bindings, messageLedger, and cursors. The daemon records inbound messages in the ledger and advances Telegram offsets only after a terminal state: delivered, skipped, or unauthorized. Failed messages remain retryable and do not advance the Telegram offset. If an agent succeeds but outbound delivery fails, the response is stored as agent_completed so retry delivery does not re-run the agent.

Daemon metadata and logs are private as well. Logs can contain prompts and agent responses, so treat them as sensitive.

Telegram Smoke Test

Create a bot with BotFather and set the token only in your shell:

export TELEGRAM_BOT_TOKEN='123456:...'

Send any message to the bot from the Telegram account or group you want to use, then find the chat id:

curl "https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/getUpdates"

Configure one allowed chat and a test shell agent:

bridge init
bridge channels add-telegram telegram-main --token-env TELEGRAM_BOT_TOKEN --allowed-chat-ids CHAT_ID --default-chat-id CHAT_ID
bridge profiles add shell-echo --agent-kind shell --command printf --arg 'bridge ok: {prompt}'
bridge agents add echo --kind shell --profile shell-echo
bridge sessions create --id test-session --agent echo
bridge sessions attach test-session --channel telegram-main --conversation CHAT_ID
bridge doctor
bridge daemon start
bridge daemon status

Send a plain Telegram message to the bot. It should reply with bridge ok: ... without any prefix. Inspect logs with bridge daemon logs, then stop it with bridge daemon stop.

For Telegram forum topics, use CHAT_ID:THREAD_ID as the conversation value.

For the first live test, use the default process supervisor above because it inherits TELEGRAM_BOT_TOKEN from your shell. Move to launchd/systemd after that works.

iMessage

iMessage is a local macOS channel. Sending uses the Messages app through osascript, so macOS may ask for Automation permission for the terminal or daemon host process.

Configure a send-only channel:

bridge channels add-imessage imessage-main --allowed-handles +15555550100 --default-handle +15555550100
bridge send imessage-main "hello"

If your Mac has more than one Messages account, add the account selector:

bridge channels add-imessage imessage-main --allowed-handles +15555550100 --account [email protected]

For receive mode, configured accounts are also used as a filter when Messages stores account metadata in chat.db. If an account is configured but an inbound row has no matching account metadata, the row is skipped rather than routed.

Enable local receive polling only when you are comfortable granting the daemon host access to Messages data:

bridge channels add-imessage imessage-main --allowed-handles +15555550100 --receive
bridge sessions attach SESSION_ID --channel imessage-main --conversation +15555550100
bridge daemon restart

Receive mode reads ~/Library/Messages/chat.db. If bridge doctor reports a chat database permission failure, grant Full Disk Access to the terminal or service host, or recreate the channel without --receive.

Inbound direct chats bind by handle. Group chats bind by local Messages chat id, shown internally as chat:<guid>, and replies go back to that chat after the sender handle passes the channel allowlist.