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

claude-wrap

v0.1.2

Published

Client library for wrapping the Claude Code CLI window: spawn it headless or in a visible terminal, read screen/parsed state, subscribe to status events, send input, and control out-of-process instances over a pipe or loopback HTTP.

Readme

claude-wrap

npm version npm downloads types node license

A client library for wrapping the Claude Code CLI window. Spawn claude headless (in an in-process PTY) or open a visible terminal window, mirror its output into a virtual screen, read parsed session state, subscribe to status changes, and send input — in-process or to out-of-process instances over a named pipe / loopback HTTP.

Windows-first. The headless PTY uses ConPTY; the windowed mode uses cmd.exe start. Other platforms work headlessly via node-pty (openWindow is ignored off Windows and falls back to headless).

Install

npm install claude-wrap

Requires Node ≥ 18 and the claude CLI on your PATH.

Native dependency: node-pty

This package depends on node-pty, a native (node-gyp) addon. Installation downloads a prebuilt binary when one matches your platform + Node ABI; otherwise it compiles from source and needs a C/C++ toolchain:

  • Windows — the "Desktop development with C++" workload (Visual Studio Build Tools) and Python 3.
  • macOS — Xcode Command Line Tools (xcode-select --install).
  • Linuxbuild-essential (gcc/g++/make) and Python 3.

If npm install fails building node-pty, install the toolchain above and retry.

Quickstart — headless ask()

import { ClaudeManager } from "claude-wrap";

const manager = new ClaudeManager();
const instance = manager.spawn({ cwd: process.cwd() });

// Send a prompt and wait until Claude goes idle. Returns the parsed state.
const state = await instance.ask("List the files in this repo.");

// `ask` may return with a pending permission prompt — handle it if present.
if (state.permissionPrompt) {
  instance.approve(); // or instance.deny()
}

// Read what's on screen (full scrollback, trailing blanks trimmed).
const snap = instance.snapshot({ clean: true });
console.log(snap.lines.join("\n"));

await instance.shutdown();

Subscribe to events

instance.on("status:busy", () => console.log("working…"));
instance.on("status:idle", () => console.log("done"));
instance.on("permission:prompt", ({ prompt }) => console.log("needs:", prompt.title));
instance.on("tool:start", ({ tool, args }) => console.log("tool:", tool, args));
instance.on("todo:changed", ({ todoList }) => console.log("todos:", todoList));

All event names are in ALL_SESSION_EVENTS; payload types are keyed in SessionEvents.

Stream the display as it updates

Two push APIs let you follow the terminal live instead of polling snapshot(). Both are headless-only (in windowed mode the PTY runs in the wrapper process, so neither fires).

Raw bytes — onData(cb). The truest live stream: every PTY output chunk, verbatim, including ANSI escape codes. Best for piping to your own terminal / xterm renderer.

const stop = instance.onData((chunk) => process.stdout.write(chunk));
// …later: stop();  // unsubscribe

Rendered lines — screen:changed + snapshot(). Fires (undebounced) on every screen redraw and hands you a signal; pull the current clean lines in the handler. Best when you want parsed/renderable text rather than escape codes. (Unlike the debounced state:changed, this reflects cosmetic redraws too.)

instance.on("screen:changed", () => {
  const { lines } = instance.snapshot({ clean: true });
  render(lines);
});

Pick onData for a faithful byte-for-byte mirror; pick screen:changed when you only need "the visible text changed, give me the new lines".

Open a visible window (Windows)

const win = manager.spawn({
  cwd: "C:\\my\\project",
  label: "my-project",
  openWindow: true,   // visible cmd.exe window the user can type into
  enablePipe: true,   // control channel for snapshots / input
  enableHttp: true,   // loopback HTTP bridge
});

The window registers itself in an on-disk instance registry, so a separate process can discover and drive it:

import { listInstances, snapshot, write } from "claude-wrap";

const [entry] = listInstances();
if (entry) {
  const snap = await snapshot(entry.pipe, { clean: true });
  await write(entry.pipe, "hello\r");
}

Forward events out-of-process — EventSink

When a wrapper runs in another process you can't call .on() on it. Attach an EventSink to forward its events over a transport. The built-in WebSocketEventSink ships a generic JSON wire format:

{ kind: "hello", instance, pid, cwd, label?, httpPort? }
{ kind: "event", instance, event: <SessionEvents key>, payload }
{ kind: "exit",  instance, exitCode }
import { ClaudeManager, WebSocketEventSink } from "claude-wrap";

const manager = new ClaudeManager();
manager.spawn({
  cwd: process.cwd(),
  reportTo: "ws://127.0.0.1:8080", // builds a WebSocketEventSink internally
});

// …or attach one explicitly:
const inst = manager.spawn({ cwd: process.cwd() });
inst.attachSink(new WebSocketEventSink("ws://127.0.0.1:8080", { idleDebounceMs: 2500 }));

The wrapper binary reads the same URL from the --report-to flag or the CLAUDE_WRAP_REPORT_URL environment variable.

Bins

| Bin | Purpose | |---|---| | claude-wrap | Launch a wrapped claude in a new terminal window | | claude-wrap-run | The wrapper process (PTY + pipe + HTTP bridge) | | claude-wrap-inject | CLI to snapshot/parse/drive a running instance over its pipe |

Logging

Diagnostic logs are written to claude-wrap.log in the OS temp directory. Override the path with the CLAUDE_WRAP_LOG environment variable.

License

MIT © Alex Kaffetzakis