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

pinclaw-cc-bridge

v0.8.3

Published

Pinclaw Claude Code bridge — runs Claude Code through a local hub so your phone mirrors and controls your terminal sessions (two-way synced).

Readme

pinclaw-cc-bridge

Runs on a user's Mac so their phone mirrors and controls their Claude Code terminal sessions, two-way synced — one model, no read-only/bubble split.

How it works (the "manager"): your claude is wrapped by a thin shell that runs the real, official claude in a pseudo-terminal. Your terminal stays native; the shell also mirrors the session to your phone and injects what the phone types. A single background hub daemon owns the cloud connection and multiplexes every wrapped session, so you can run many claudes at once and the phone switches between them.

The one hard limit (OS): a claude already running bare in a terminal can't be reached — macOS won't let an outside process inject into another process's tty. So only sessions started through the manager are phone-controllable. The installer makes that invisible by putting a claude shim first on your PATH, so you keep typing claude and every new session is automatically controllable.

Design: docs/superpowers/specs/2026-06-07-cc-manager-unified-design.md (current); earlier: …2026-06-06-cc-shared-session-json-shell-design.md, …2026-06-04-….

Install (end users)

In the Pinclaw app: Claude Code → Connect, which shows a one-line command (it embeds an account token, so no second login):

curl -fsSL https://pinclaw.ai/install-cc | PINCLAW_CC_TOKEN=<token> bash

This binds the Mac to your account, installs the manager, puts the claude shim on PATH, and starts the hub daemon (launchd). Then just run claude as usual.

  • Bypass once: PINCLAW_CC_DISABLE=1 claude
  • Remove everything: pinclaw-cc-bridge uninstall

(No app token? curl -fsSL https://pinclaw.ai/install-cc | bash falls back to device-code browser auth.)

Region-locked egress (e.g. China)

A phone send spawns a fresh headless claude/codex under the launchd daemon — it does NOT go through your terminal, so it doesn't inherit the https_proxy your terminal claude wrapper uses. If your region needs a proxy to reach Anthropic/OpenAI, that child exits direct and fails 403 Request not allowed (while the terminal works). Worse, a different exit IP on the same account is an account-ban risk.

Fix: set engineEnv so the bridge child exits from the same residential IP / timezone / locale as your terminal. If your shell rc defines CLAUDE_PROXY (or CLAUDE_PROXY_{USER,PASS,HOST,PORT}):

pinclaw-cc-bridge sync-proxy   # writes engineEnv to ~/.pinclaw/{cc,codex}-bridge.json
launchctl kickstart -k gui/$(id -u)/ai.pinclaw.cc-bridge

Otherwise add an engineEnv object by hand to those config files. It fails closed (a dead proxy errors the request, never falls back to direct) and the daemon log prints engine egress: PROXIED via … / DIRECT so you can verify it. Re-run sync-proxy after rotating the proxy. US users need none of this.

How discovery works

  • Scans ~/.claude/projects/<encoded-cwd>/*.jsonl — each JSONL is one session, mtime = last active. (encoded-cwd = every non-alphanumeric char → -.)
  • Finds live sessions via ps, matching the CLI by argv0 basename claude (since 0.5.1 — covers npm, pnpm, and the native installer's ~/.local/bin/claude; the desktop app is excluded), deduped to root processes by PPID. Procs started with --session-id <uuid> (every wrapper-run session) bind pid↔session exactly; only bare procs without it fall back to the heuristic: lsof the proc's cwd, then with N live procs in a project the N newest JSONLs touched within the last 30 minutes are running, the rest idle (the freshness bound keeps hours-old sessions from showing as running just because unrelated procs exist in the same project); extra procs with no JSONL yet are virtual pending-<pid>.
  • List rows read only head 16KB (title/cwd) + tail 128KB (recent messages). Full transcript is read on demand when the phone opens a session.
  • Row title (since 0.4.1) = the session's live recap: the freshest {type:"system", subtype:"away_summary"} entry Claude Code keeps appending to the JSONL (tail window beats head). Falls back to ai-title, then the first user message — slash-command wrappers render as /name, local-command caveats are skipped. Codex sessions have no recap and keep their meta title.
  • Codex transcripts (since 0.5.1) parse ~/.codex/sessions/ rollout JSONL and hide the bookkeeping the Codex TUI never renders — developer/system-role instruction messages and user-role <environment_context> / <user_instructions> / <turn_aborted> prefix messages — so the phone shows exactly what Codex shows.
  • Live streaming (since 0.5.0): while a phone has a session open, the cloud arms a watch (cc_watch / alias cc_watch_start) and the bridge tails that session's JSONL (transcript-watcher.ts + watch-manager.ts), pushing new entries as cc_event{kind:"transcript_append", startIndex, …} (idempotent by absolute index) plus watch_ok{entryCount} reconciliation heartbeats, so terminal-driven turns appear on the phone block-by-block instead of on the next poll. Watches stop on cc_unwatch / cc_watch_stop or expire on their own TTL; watch_failed tells the phone to fall back to polling.

Commands

# normal usage (set up by the installer; you don't run these by hand)
pinclaw-cc-bridge install     # install the `claude` shim + PATH + start the hub (idempotent)
pinclaw-cc-bridge uninstall   # remove shim + PATH entry + hub launchd (reversible)
pinclaw-cc-bridge hub         # the background daemon: holds the cloud link, multiplexes all shells
pinclaw-cc-bridge term -- ... # one wrapped `claude` that joins the hub (what the shim calls)

# debug / legacy
pinclaw-cc-bridge once        # print one discovery snapshot as JSON and exit
pinclaw-cc-bridge start       # legacy read-only discovery daemon
pinclaw-cc-bridge mirror      # legacy single-session mirror (one bridge per user)

Architecture: hub (one daemon, one cloud WS, listens on ~/.pinclaw/cc-hub.sock) ← many term shells (each = one pty-wrapped claude, registers over the local socket). The hub multiplexes all shells to the cloud and routes phone input back to the right one by termId. A shell exiting (Ctrl-C / crash) sends bye, so the phone never sees a ghost terminal.

Local dev / end-to-end proof (no cloud needed)

npm install
npm test                              # unit tests (122)
node --import tsx src/dev-server.ts &  # cloud stand-in (ws://localhost:7799)
PINCLAW_CC_URL=ws://localhost:7799/cc-bridge/connect PINCLAW_CC_TOKEN=dummy \
  node --import tsx src/cli.ts start & # bridge against real ~/.claude/projects
node --import tsx src/phone-probe.ts   # simulates the phone: lists + opens a transcript

Wire protocols

Terminal mirror — hub ⇄ cloud (the current model): Hub → cloud: cc_term_hello {termId,cwd,title,cols,rows}, cc_term_output {termId,data(b64)}, cc_term_bye {termId}. Cloud → hub: cc_term_input {termId,data}, cc_term_resize {termId,cols,rows}.

Shell ⇄ hub (local socket, newline-JSON, hub-protocol.ts): shell → hub reg / out / bye; hub → shell in / resize.

Phone ⇄ cloud (routes/cc.ts): GET /cc/term/list, GET /cc/term/stream (SSE bytes, replays the rolling buffer then live), POST /cc/term/input, POST /cc/term/resize, and POST /cc/pair (logged-in phone mints an account-bound install token). Cloud relay: services/cc-term-service.ts (per-term rolling 256KB buffer, replay-then-live, drops on bye).

Legacy (bubble/discovery, still present): cc_hello/cc_snapshot/cc_event + /cc/sessions|attach|send|stream; migrations 049_claude_code_mode.sql + 050_cc_sessions_controllable.sql. The unified iOS UI uses the terminal path only.