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-code-wrapper

v1.0.1

Published

Node.js wrapper for the Claude Code CLI — process management, event parsing, session continuity, and permission relay

Downloads

28

Readme

claude-code-wrapper

GitHub

Node.js wrapper for the Claude Code CLI — build internal desktop apps powered by Claude Code.

This library is for developers building their own desktop applications that use Claude Code as the inference engine. It is not a third-party harness or proxy — it wraps your local Claude Code CLI installation, using your own API key and configuration, to give you programmatic control from Node.js.

Use it when you want to embed Claude Code into an Electron app, a local dev tool, an internal workflow, or anything else where you need structured access to Claude Code's streaming output, tool use, and multi-turn sessions.

Under the hood it manages: NDJSON stream parsing, incremental content assembly, multi-turn session continuity via --resume, permission request relay, and the many edge cases that surface in production (compaction mid-stream, partial JSON tool inputs, non-streaming fallback, flush-on-close). Born from the Synapse distributed agent swarm system, where dozens of concurrent Claude Code processes need rock-solid programmatic control.

Install

npm install claude-code-wrapper

Quick Start

One-shot prompt, await the result:

import { createSession } from 'claude-code-wrapper';

const session = createSession({ cwd: '/path/to/project' });
const turn = session.send('Explain what this project does in two sentences.');
const result = await turn.result;

console.log(result.text);
console.log(`Cost: $${result.cost}`);

Streaming

Subscribe to events for real-time output:

const session = createSession({ cwd: './my-project' });
const turn = session.send('Refactor the auth module to use JWT.');

turn.on('text', (chunk) => process.stdout.write(chunk));
turn.on('thinking', (chunk) => process.stderr.write(`[thinking] ${chunk}\n`));
turn.on('tool_use', (tool) => console.log(`Tool: ${tool.name}`, tool.input));
turn.on('tool_result', (res) => console.log(`Result for ${res.toolUseId}`));
turn.on('error', (err) => console.error(err.message));

const result = await turn.result;
console.log(`\nDone. Exit code: ${result.exitCode}`);

Multi-Turn

Each send() call automatically resumes the same session via --resume:

const session = createSession({ cwd: './my-project' });

const t1 = session.send('Read the README and summarize the architecture.');
await t1.result;

// Continues the same conversation — context is preserved
const t2 = session.send('Now add a /health endpoint based on that architecture.');
const result = await t2.result;

console.log(result.text);
console.log(`Session: ${session.sessionId}`);

Permission Handling

Three modes for controlling tool-use permissions:

Auto-approve everything

const session = createSession({
  cwd: './my-project',
  permissions: 'auto',
});

Deny all permission requests (skip)

const session = createSession({
  cwd: './my-project',
  permissions: 'skip',
});

Prompt — handle each request programmatically

const session = createSession({
  cwd: './my-project',
  permissions: 'prompt',
});

const turn = session.send('Delete all .tmp files in this directory.');

turn.on('permission', (request, respond) => {
  console.log(`Tool "${request.toolName}" wants to run:`, request.input);

  if (request.toolName === 'Bash' && /rm|delete/i.test(JSON.stringify(request.input))) {
    respond('deny');
  } else {
    respond('allow');
  }
});

await turn.result;

Parallel Workers

Spin up independent sessions for concurrent workloads:

const tasks = [
  { cwd: './api', prompt: 'Add input validation to all POST endpoints.' },
  { cwd: './web', prompt: 'Convert class components to functional components.' },
  { cwd: './docs', prompt: 'Generate API reference from JSDoc comments.' },
];

const results = await Promise.all(
  tasks.map(({ cwd, prompt }) => {
    const session = createSession({ cwd, permissions: 'auto' });
    return session.send(prompt).result;
  })
);

for (const r of results) {
  console.log(`Exit ${r.exitCode} | Cost: $${r.cost} | ${r.text.slice(0, 80)}...`);
}

API Overview

Functions

| Function | Description | |---|---| | createSession(opts) | Create a new CLI session. Returns a Session object. |

Session

| Property / Method | Description | |---|---| | session.send(prompt) | Send a prompt. Returns a Turn with events and .result. | | session.abort() | Kill the running CLI process. | | session.sessionId | The CLI session ID (populated after first send()). | | session.isActive | true while a turn is in progress. |

Session Options

| Option | Type | Default | Description | |---|---|---|---| | cwd | string | process.cwd() | Working directory for the CLI process. | | model | string | CLI default | Model to use (e.g. claude-sonnet-4-20250514). | | cli | string | 'claude' | Path to the Claude Code CLI binary. | | permissions | 'prompt' \| 'skip' \| 'auto' | 'prompt' | How to handle tool-use permission requests. | | dirs | string[] | — | Additional directories to allow. | | env | Record<string, string> | — | Extra environment variables for the CLI process. | | systemPrompt | string | — | System prompt passed to --system-prompt. | | debug | boolean \| 'verbose' | false | Enable debug logging. |

Turn

| Property / Method | Description | |---|---| | turn.on(event, fn) | Subscribe to a streaming event (see below). | | turn.result | Promise<TurnResult> that resolves when the turn completes. |

TurnResult

| Field | Type | Description | |---|---|---| | text | string | Full assembled text output. | | thinking | string | Full assembled thinking/reasoning output. | | toolCalls | ToolCall[] | All tool calls made during the turn. | | sessionId | string \| null | CLI session ID for resumption. | | cost | number \| null | Cost in USD, if reported. | | exitCode | number | CLI process exit code. | | duration | number | Wall-clock milliseconds. |

Events

| Event | Callback Signature | Description | |---|---|---| | text | (chunk: string) | Incremental text output. | | thinking | (chunk: string) | Incremental thinking/reasoning output. | | tool_use | (tool: ToolCall) | A tool call was made (id, name, input). | | tool_result | (result: ToolResult) | A tool returned a result (toolUseId, content). | | permission | (request, respond) | Permission requested. Call respond('allow') or respond('deny'). | | activity | (line: string) | Filtered stderr activity (progress stripped). | | compaction | (summary: string) | Context window was compacted. | | error | (err: { message, code? }) | An error occurred. | | done | (result: TurnResult) | Turn finished. Same data as turn.result. |

What It Handles For You

  • NDJSON buffering — Handles partial lines, split chunks, and malformed JSON gracefully.
  • Streaming assembly — Reconstructs text, thinking, and tool-use content from content_block_start/delta/stop sequences.
  • Compaction recovery — Detects mid-stream context compaction and resets streaming state without losing data.
  • Flush-on-close — Processes any remaining buffered content when the CLI process exits.
  • Non-streaming fallback — Handles responses delivered as complete assistant events instead of streaming deltas.
  • Session continuity — Tracks the session ID and automatically passes --resume on subsequent send() calls.
  • Stderr filtering — Strips ANSI codes, progress bars, and spinner characters; surfaces only meaningful activity lines.
  • Permission relay — Bridges CLI permission requests to your callback and writes the response back via stdin.

Requirements

  • Node.js 18+
  • Claude Code CLI installed and available on your PATH (or specify the path via the cli option)

Documentation

See the docs/ directory for in-depth guides:

License

MIT -- see LICENSE.

Credits

Born from the Synapse distributed agent swarm system.