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

nexting-cc-bridge

v0.13.1

Published

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

Downloads

5,056

Readme

nexting-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 Nexting app: Claude Code → Connect, which shows a one-line command (it embeds an account token, so no second login):

curl -fsSL https://nexting.ai/install-cc | NEXTING_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: NEXTING_CC_DISABLE=1 claude
  • Remove everything: nexting-cc-bridge uninstall

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

Windows

Codex is fully supported on native Windows (since 0.10.0):

irm https://nexting.ai/install-codex.ps1 | iex

That logs in (device-code browser auth), installs this package, and registers a per-user Scheduled Task (NextingCodexBridge, at-logon + restart-on-failure — the launchd equivalent). The bridge drives codex app-server --stdio per session; the official managed-daemon control socket is never dialed on Windows (it's broken there — openai/codex#24090). Terminal mode (phone-started PTY) is not available on Windows yet; app-server control covers send/steer/live sync. Remove with nexting-cc-bridge codex-uninstall.

Claude Code is fully supported on native Windows (since 0.11.0):

irm https://nexting.ai/install-cc.ps1 | iex

That logs in, installs this package, and sets up the Windows translation of the mac trio: a claude.cmd shim in ~/.nexting/bin (prepended to the USER Path — fully quit + reopen your terminal app for it to take effect; new tabs inherit the old environment), and a NextingCcBridge Scheduled Task running the hub (cli.js hub, named pipe \\.\pipe\nexting-cc-hub-<user> instead of the unix socket). Typing claude routes through claude-shim (same bypass rules as the bash shim: NEXTING_CC_DISABLE=1, piped stdio, -p/--print, non-interactive subcommands go straight to the real claude — resolved from known install locations first, %USERPROFILE%\.local\bin\claude.exe topmost; where.exe minus the shim dir is only a last resort). Interactive runs are wrapped in a ConPTY (node-pty) and mirror to the phone; phone-started sessions spawn the same way. Caveats: ConPTY is a translating layer (not byte-passthrough) and Claude Code has known ConPTY rendering issues upstream — expect occasional repaints; sessions not started through the shim show as idle (no ps/lsof on Windows). Remove with nexting-cc-bridge uninstall.

Region-locked egress (e.g. China)

A phone-created Claude Code session starts a real Mac-side PTY, and Codex starts its Mac app-server child. Those processes run under the launchd daemon, so they do NOT inherit the https_proxy your terminal claude wrapper uses. If your region needs a proxy to reach Anthropic/OpenAI, the agent can exit direct and fail 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 bridge-started agents exit from the same residential IP / timezone / locale as your terminal. If your shell rc defines CLAUDE_PROXY (or CLAUDE_PROXY_{USER,PASS,HOST,PORT}):

nexting-cc-bridge sync-proxy   # writes engineEnv to ~/.nexting/{cc,codex}-bridge.json
launchctl kickstart -k gui/$(id -u)/ai.nexting.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)
nexting-cc-bridge install     # install the `claude` shim + PATH + start the hub (idempotent)
nexting-cc-bridge uninstall   # remove shim + PATH entry + hub launchd (reversible)
nexting-cc-bridge hub         # the background daemon: holds the cloud link, multiplexes all shells
nexting-cc-bridge term -- ... # one wrapped `claude` that joins the hub (what the shim calls)

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

Architecture: hub (one daemon, one cloud WS, listens on ~/.nexting/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)
NEXTING_CC_URL=ws://localhost:7799/cc-bridge/connect NEXTING_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

End-to-End Encryption

The Pinclaw cloud acts as a relay and store, not the agent host. By default the cloud can see the session content it relays. E2E encryption is an opt-in feature (e2eEnabled: true in ~/.pinclaw/cc-bridge.json) that makes the cloud a pure ciphertext forwarder: it sees routing metadata and opaque blobs but no plaintext content.

Trust model

  • Trusted endpoints: the Mac bridge and the user's phone.
  • Untrusted: the Pinclaw cloud server (treated as a relay that may be compromised).
  • When E2E is on, only the endpoints can decrypt transcript text, titles, summaries, and stream deltas.

What gets encrypted

| Content | Encrypted when E2E on | | --------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Session titles (cc_snapshot) | Yes | | Session summaries (cc_snapshot) | Yes | | Recent message text (cc_snapshot) | Yes | | Transcript entries (cc_event transcript_append) | Yes | | Streaming text and thinking deltas (cc_event stream_*_delta) | Yes | | Inbound user sends (cc_send content) | Yes | | Inbound question answers (cc_answer updatedInput) | Yes | | Media/image bytes | Yes — src/media-hydrator.ts encrypts blob bytes with sealBytes (session CEK) before upload and marks them encrypted: true; the phone decrypts with openBytes | | Terminal mirror frames (cc_term_output, cc_term_input) | No — these are already opaque binary blobs; the content stream above is where the readable text lives | | Control / handshake frames (reg, cc_hello, cc_term_hello, etc.) | No |

Cryptographic details (auditable)

All algorithms are in src/e2e/crypto.ts (Node built-in node:crypto only — no third-party crypto libraries).

Content encryption (per session, text fields):

  • Algorithm: AES-256-GCM
  • Per-session key: 32-byte Content Encryption Key (CEK), one per session, generated fresh by the bridge at session creation.
  • Wire envelope: e2e:v1:<base64(nonce[12] || ciphertext || tag[16])>
  • AAD (authenticated additional data): "<sessionId>|0|<field>" — binds every ciphertext to its session and field, preventing cross-session replay. The 0 is the sequence placeholder (current protocol has no per-frame sequence number). Field tags are: title, summary, msg, text, delta, send, answer.

Media encryption (binary):

  • Algorithm: AES-256-GCM (same sealBytes / openBytes helpers).
  • Wire layout: raw bytes — nonce[12] || ciphertext || tag[16] (no text prefix; an encrypted: true metadata flag marks the blob).
  • AAD: "<sessionId>|0|media"

Key wrapping (CEK delivery to the phone):

  • Algorithm: ephemeral X25519 ECDH → HKDF-SHA256 → AES-256-GCM
  • Derivation: HKDF-SHA256(ikm=X25519_shared, salt=UTF8(sessionId), info=UTF8("pinclaw-e2e-cek-wrap"), L=32)
  • Wire format: wrap:v1:<base64(ephPubSPKI[44] || nonce[12] || ct || tag[16])>
  • The bridge generates an ephemeral X25519 keypair per wrap, computes the shared secret with the recipient device's long-term public key, derives a per-wrap AES-256-GCM key, and seals the CEK. The recipient (phone) reverses the process.

Device identity key:

  • Each endpoint (Mac bridge, phone) has an X25519 long-term keypair.
  • The bridge private key is stored in the macOS Keychain (service pinclaw-bridge-e2e, written via security add-generic-password); it never leaves the machine. See src/e2e/keychain-identity.ts.
  • Public keys are published to the cloud key directory so endpoints can fetch each other's keys for wrapping.

Safety number (human-verifiable MITM protection):

  • SHA-256(sort(pubA, pubB)) — the first 10 bytes encoded in base32 (A-Z2-7), displayed as XXXXX-XXXXX.
  • Compare this five-plus-five string between your Mac terminal and the Pinclaw app. If they match, no cloud-side key swap has occurred.

What you can verify

  1. Algorithms: read src/e2e/crypto.ts — every cipher call is there. Node's built-in node:crypto module, no opaque libraries.
  2. Which fields are sealed/unsealed: read src/e2e/codec.ts (EnvelopeCodec.encryptOutbound / decryptInbound). The switch cases enumerate every frame type that the codec touches.
  3. Key storage: read src/e2e/keychain-identity.ts — the only I/O is security find-generic-password (read) and security add-generic-password (write) to the macOS login keychain.
  4. Tests and interop vectors: test/e2e-crypto.test.ts, test/e2e-codec.test.ts, test/e2e-wire.test.ts — the vectors in e2e-crypto.test.ts are the shared ground truth used to verify byte-level compatibility between the bridge, cloud, iOS, and Android.

To run just the E2E tests:

npm test -- --testPathPattern="e2e-"

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.