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

macroclaw-bridge

v0.1.0

Published

Serves live Claude Code session state to the MacroClaw iOS app over the local network.

Readme

macroclaw-bridge

Serves live Claude Code session state to the MacroClaw iOS app over your local network.

npx macroclaw-bridge

It prints a pairing token. The phone sends that token; without it the bridge serves nothing.

What it does

Claude Code already writes everything the deck needs. Each session is an append-only JSONL file under ~/.claude/projects/<slugified-cwd>/<session-uuid>.jsonl, carrying cwd, gitBranch, the model, per-turn token usage, an AI-generated title, and every tool call. The bridge tails those files and folds them into the shape MacroClaw renders.

The one thing that matters most falls out of the log for free: a session is blocked on you exactly when an AskUserQuestion tool call has no matching tool_result. That is what turns a card amber.

Files only ever grow, so the bridge keeps a byte offset per session and parses just the new tail.

Answering from the phone

npx macroclaw-bridge --install-hook

Then restart your Claude Code sessions. A tool call that needs permission now waits for MacroClaw instead of only the terminal.

It works through Claude Code's PreToolUse hook, which is built for exactly this: the hook runs before a tool call, and whatever it prints decides the call's fate.

session wants to run `rm -rf build`
  -> PreToolUse hook fires, makes one blocking request to the bridge
  -> bridge parks it and pushes it to the phone over SSE
  -> you tap allow / deny, optionally with a note
  -> hook prints {"permissionDecision":"allow"} and exits
  -> the session runs the command

Hooks get a 600-second timeout (configurable), so there is plenty of room for a human.

The note you type is a real channel to the model. Claude Code feeds permissionDecisionReason back verbatim on a deny, so "not on this network" arrives as the model's stated reason for being blocked, and it reacts to it.

It must never wedge your terminal

That is the governing rule, and every failure path ends the same way: the hook prints nothing, exits 0, and the session falls back to its ordinary permission prompt as though no hook were installed. Bridge not running, phone asleep, request timed out, malformed payload, bridge killed mid-wait — all identical, all safe. Shutting the bridge down releases anything parked first.

The handshake file the hook reads (~/.macroclaw/bridge.json, mode 0600) only exists while the bridge is running, so its absence is the ordinary "no bridge right now" case rather than an error.

What it cannot do

AskUserQuestion — the multiple-choice prompt — is a tool, so the hook does see it, but a hook can only allow or deny; it cannot hand back a chosen option. Denying with the choice as the reason does reach the model and works in practice, but it is a workaround rather than the real thing. Permission prompts, which are the common case, are handled properly.

Endpoints

| | | |---|---| | GET /health | No auth, no data. Confirms a discovered service is a bridge before pairing. | | GET /sessions | Board summaries, freshest first, no transcripts. | | GET /sessions/<id> | One session with its transcript, for the detail sheet. | | GET /events | Summaries and pending asks, then a push on every change (SSE). | | GET /pending | Tool calls waiting on an answer right now. | | POST /pending/<id> | Answer one: {"decision":"allow"\|"deny","reason":"..."} | | POST /hook/ask | Used by the hook. Blocks until answered. |

Transcripts are deliberately not in the list. Inlining them made the payload 1.7 MB for 160 sessions; summaries alone are about 17 KB, and the board draws no transcript anyway.

curl -s localhost:8787/health
curl -s -H "Authorization: Bearer $TOKEN" localhost:8787/sessions | jq
curl -sN -H "Authorization: Bearer $TOKEN" localhost:8787/events

Options

--port <n>      port to listen on (default 8787)
--token <s>     pairing token (default: a fresh random one each run)
--host <addr>   interface to bind (default 0.0.0.0; 127.0.0.1 keeps it on this machine)
--days <n>      only serve sessions touched in the last n days (default 7)
--limit <n>     most sessions to serve (default 60)
--name <s>      Bonjour service name (default MacroClaw)

Security

These logs contain your source, your file contents, and anything ever pasted into a session. Claude Code stores them 0600 for that reason. Putting them on a wire undoes that, so:

  • Every data endpoint requires the pairing token, compared with timingSafeEqual.
  • The default token is random per run — a restart invalidates the old one.
  • --host 127.0.0.1 keeps it off the network entirely, if you only want the Simulator.
  • Nothing is written. The bridge opens every file read-only.

It binds 0.0.0.0 by default because a phone cannot otherwise reach it. On a network you do not trust, don't.

Discovery

Advertised as _macroclaw._tcp, with a TXT record carrying host and port. The record is what makes discovery reliable: resolving a service endpoint client-side does not always yield a concrete address, and when it does not, the app can see the bridge and still fail to reach it.

Published through the platform's own mDNS responder — dns-sd on macOS, avahi-publish-service on Linux. A JavaScript responder would have to bind UDP 5353 itself and compete with the daemon that already owns it, which mostly works and fails silently when it doesn't. Shelling out also keeps the dependency count at zero, so npx has nothing to install.

If neither tool is present, discovery is skipped and the bridge prints its LAN addresses instead.

Known limits

  • Status is honest, not complete. Only three states are knowable from the log: blocked on a question, recently active, quiet. done and error would be guesses, so the bridge never claims them.
  • Answering covers permission prompts, not multiple-choice questions. See above.
  • Polling, not watching. fs.watch on a directory does not reliably report appends to files inside it on macOS, so a 1-second poll is the real change signal. Each pump stats a file and reads only when there are new bytes.
  • Same LAN only. Plenty of corporate and guest wifi blocks mDNS outright.

Tests

npm test

Drives the parser over a throwaway root, so it never touches your real sessions.