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

@petersr/claude-pty-web-harness-core

v0.5.0

Published

Transport-agnostic core: drive Claude Code in a pupptyeer pty, stream its JSONL as chat events.

Readme

@petersr/claude-pty-web-harness-core

The transport-agnostic core of the claude-pty-web-harness. ClaudeHarness drives the interactive Claude Code TUI inside a pupptyeer pty, tails the JSONL transcript Claude persists, and turns it into a stream of typed ChatEvents. No HTTP, no UI: wire it to any transport (see the reference server).

Install

npm i @petersr/claude-pty-web-harness-core

Requires Node >= 20, claude on PATH (logged in), and a running pupptyeer daemon (npm i -g @petersr/pupptyeer && pupptyeer daemon install). The pupptyeer-client dependency is pulled in automatically; the harness connects to the daemon and fails loud if it is unreachable (it never spawns one).

Usage

import { ClaudeHarness } from "@petersr/claude-pty-web-harness-core";
import type { ChatEvent, SessionStatus } from "@petersr/claude-pty-web-harness-protocol";

const harness = await ClaudeHarness.create({
  // all optional: socketPath, readiness: "screen" | "delay", allowedRoots
});

harness.on("chat", (sessionId: string, event: ChatEvent) => { /* render */ });
harness.on("status", (sessionId: string, status: SessionStatus, error?: string) => {
  // status "failed" carries a StartupFailure reason in `error`
  // (auth_blocked, rate_limit, workspace_trust_blocked, tool_approval_blocked,
  //  custom_api_key_detected, startup_timeout)
});

const session = await harness.createSession({ cwd: "/repo", model: "sonnet" });
await harness.sendPrompt(session.id, "first line\nsecond line"); // multi-line, one paste

createSession also takes command, permissionMode, extraArgs, env (merged over the daemon's own environment for the spawned process), cols, and rows; see USAGE.md for the full option list and why env is there.

Also: harness.list(), harness.get(id), harness.transcript(id), harness.interrupt(id), harness.kill(id), and harness.blob(sessionId, blobId) (bytes + mediaType for an image ContentPart, or undefined - back the GET /:id/blobs/:blobId route with it; never inline the bytes into a ChatEvent).

sendPrompt captures the screen once before writing anything (in readiness: "screen" mode only) and throws PickerOpenError (code: "picker_open", exported from this package) if a numbered picker - an AskUserQuestion prompt, a tool-permission prompt, and the trust modal all render identically, so it cannot say which one - is open: the trailing Enter that submits a prompt would otherwise confirm whichever option is highlighted. It fails open on a capture timeout, and it still leaves a narrow race between the capture and the Enter, so treat it as reducing collisions, not eliminating them. A caller that already knows what is on screen can pass { force: true } to skip the check; it is not available over the reference HTTP/WS server.

See the project README and USAGE.md for the full API and the permission-mode notes.

License

MIT