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

@blitzjb/claude-code-sdk

v0.3.0

Published

A conversational TypeScript SDK for Claude CLI with streaming support

Readme

Claude Code SDK

A conversational TypeScript SDK for Claude CLI with session management, robust error handling, and full subagent support.

🚨 Important Note for Newer Claude CLI Versions

Due to known issues with programmatic execution of Claude CLI (particularly versions with stream-json hanging), this SDK focuses on session management and history loading rather than direct CLI execution.

The SDK excels at:

  • ✅ Loading and parsing existing Claude CLI session history
  • ✅ Type-safe conversation management
  • ✅ Session resumption with full context
  • ✅ Unified message handling across all interaction types
  • Full subagent detection and tracking
  • Hierarchical message parsing with parent-child relationships
  • Complete project and session discovery
  • Directory enumeration for all Claude projects

For new conversations:

  • The SDK provides the exact command to run manually
  • Session history is automatically loaded once Claude CLI creates the session file
  • Full conversation context is maintained for subsequent operations

Features

  • 🗣️ Conversational API: Natural .say() and .ask() methods
  • 💾 History Integration: Uses Claude's built-in session storage
  • 🔒 Type Safety: Full TypeScript support with discriminated unions
  • 🛡️ Robust Error Handling: Graceful parsing with unknown message recovery
  • Session Management: Automatic loading and resumption
  • 🎯 Zero Dependencies: Lightweight (only node-pty for terminal compatibility)

Installation

npm install @blitzjb/claude-code-sdk

Quick Start

Basic Session Management

import { Claude } from '@blitzjb/claude-code-sdk';

// Start a conversation (provides manual command to run)
const conversation = await Claude.start();

// The SDK will provide the command to run:
// claude -p "your prompt" --output-format json --dangerously-skip-permissions

// After running the command manually, resume the session
const resumedChat = await Claude.resume(conversation.sessionId);
const history = resumedChat.getHistory();
console.log(`Loaded ${history.length} messages`);

Working with Existing Sessions

// Resume an existing session ID
const chat = await Claude.resume('existing-session-id');
await chat.load();

const history = chat.getHistory();
console.log(`Session has ${history.length} messages`);

// Get specific message types
const userMessages = history.filter(msg => msg.type === 'user');
const assistantMessages = history.filter(msg => msg.type === 'assistant');

// Access conversation content
history.forEach((msg, index) => {
  console.log(`${index + 1}. [${msg.timestamp.toLocaleTimeString()}] ${msg.type}: ${
    typeof msg.content === 'string' ? msg.content.substring(0, 50) + '...' : 'Tool use'
  }`);
});

Type-Safe Message Handling

const conversation = await Claude.resume('session-id');
await conversation.load();

const messages = conversation.getHistory();

messages.forEach(msg => {
  switch(msg.type) {
    case 'user':
      console.log(`User: ${msg.content}`);
      break;
    case 'assistant':
      if (typeof msg.content === 'string') {
        console.log(`Claude: ${msg.content}`);
      } else {
        console.log(`Tool: ${msg.content.name}`);
      }
      break;
    case 'tool_result':
      console.log(`Result: ${msg.content}`);
      break;
    case 'system':
      console.log(`System: ${msg.subtype}`);
      break;
  }
});

API Reference

Claude Class

// Start a new conversation (returns instructions for manual execution)
const chat = await Claude.start({ debug: true });

// Resume existing conversation
const chat = await Claude.resume('session-id');

// Check if session exists
const exists = await Claude.sessionExists('session-id');

// Get session summary
const summary = await Claude.getSessionSummary('session-id');

Conversation Class

// Load conversation history
await conversation.load();

// Get conversation history
const messages = conversation.getHistory();
const count = conversation.getMessageCount();
const lastMsg = conversation.getLastMessage();

// Get messages by type
const userMessages = conversation.getMessagesByType('user');

Subagent Support

The SDK automatically detects and parses subagent interactions from Claude CLI sessions. Subagent messages are included as part of the regular conversation history with additional metadata.

Simple History Loading

import { Claude } from '@blitzjb/claude-code-sdk';

// Load all history from a session (includes subagent interactions)
const history = await Claude.loadHistory('session-id');

// Filter subagent-related messages
const subagentMessages = history.filter(msg => (msg as any).parentToolUseId);
console.log(`Found ${subagentMessages.length} subagent messages`);

// Find Task tool calls (subagent initiations)
const taskCalls = history.filter(msg => 
  msg.type === 'assistant' && 
  typeof msg.content === 'object' && 
  msg.content?.name === 'Task'
);

console.log(`Found ${taskCalls.length} subagent tasks`);

Working with Subagent Data

// Load conversation with subagent data
const conversation = await Claude.resume('session-id');
const messages = conversation.getHistory();

// Process each message
messages.forEach((msg, index) => {
  console.log(`Message ${index}: ${msg.type}`);
  
  // Check if this message is part of a subagent
  if ((msg as any).parentToolUseId) {
    console.log(`  Part of subagent: ${(msg as any).parentToolUseId}`);
  }
  
  // Check if this is a subagent task initiation
  if ((msg as any).isSubagentTask) {
    console.log(`  Subagent type: ${(msg as any).subagentType}`);
  }
});

Subagent Types

Supports any custom subagent type as a string:

type SubagentType = string; // 'general-purpose', 'custom-agent', etc.

Example: Manual Command

// Run this to generate subagent interactions:
// claude -p "Please use the general-purpose agent to analyze this code" --output-format stream-json --verbose

// Then load the session:
const sessionId = 'your-session-id-from-cli';
const history = await Claude.loadHistory(sessionId);

// Subagent interactions are automatically parsed and included
console.log(`Total messages: ${history.length}`);

Project and Session Discovery

The SDK provides comprehensive methods to discover and enumerate all Claude projects and sessions.

List All Projects

// Get all project directories in ~/.claude/projects/
const projects = await Claude.listProjects();
console.log(`Found ${projects.length} projects:`);

projects.forEach(project => {
  const realPath = Claude.getProjectNameFromPath(project);
  console.log(`${project} → ${realPath}`);
});

List Sessions in a Project

// Get all sessions within a specific project
const sessions = await Claude.listSessionsInProject('project-name');
console.log(`Found ${sessions.length} sessions in project`);

sessions.forEach(sessionId => {
  console.log(`Session: ${sessionId}`);
});

Get All Sessions Globally

// Get all sessions across all projects
const allSessions = await Claude.getAllSessions();
console.log(`Total sessions: ${allSessions.length}`);

allSessions.forEach(({project, sessionId}) => {
  const realPath = Claude.getProjectNameFromPath(project);
  console.log(`${realPath}: ${sessionId}`);
});

Utility Methods

// Check if a project exists
const exists = await Claude.projectExists('project-name');

// Convert encoded project path to real path
const realPath = Claude.getProjectNameFromPath('-Users-user-Projects-myapp');
console.log(realPath); // Users/user/Projects/myapp

// Load history from a specific project and session
const sessionFile = ClaudePaths.getSessionFileFromProject(sessionId, projectName);

Complete Discovery Example

import { Claude } from '@blitzjb/claude-code-sdk';

async function discoverAllSessions() {
  // Get all projects
  const projects = await Claude.listProjects();
  console.log(`📁 Found ${projects.length} projects`);
  
  // Get all sessions globally
  const allSessions = await Claude.getAllSessions();
  console.log(`💬 Found ${allSessions.length} total sessions`);
  
  // Group sessions by project
  const sessionsByProject = allSessions.reduce((acc, {project, sessionId}) => {
    if (!acc[project]) acc[project] = [];
    acc[project].push(sessionId);
    return acc;
  }, {} as Record<string, string[]>);
  
  // Display summary
  for (const [project, sessions] of Object.entries(sessionsByProject)) {
    const realPath = Claude.getProjectNameFromPath(project);
    console.log(`\n${realPath}:`);
    console.log(`  ${sessions.length} sessions`);
    
    // Load a sample session
    if (sessions.length > 0) {
      const history = await Claude.loadHistory(sessions[0]);
      console.log(`  Sample session has ${history.length} messages`);
    }
  }
}

Message Types

All messages use a unified type system:

type Message = 
  | UserMessage      // { type: 'user', content: string }
  | AssistantMessage // { type: 'assistant', content: string | ToolUse }
  | ToolMessage      // { type: 'tool_result', toolUseId, content }
  | SystemMessage    // { type: 'system', subtype, data }
  | UnknownMessage;  // { type: 'unknown', raw, parseError }

Workflow

1. Starting a New Conversation

const conversation = await Claude.start();
console.log(`Session ID: ${conversation.sessionId}`);

// SDK provides the command to run manually:
// claude -p "your prompt" --output-format json --dangerously-skip-permissions

2. Working with Session History

// After running Claude CLI manually, resume the session
const chat = await Claude.resume('session-id-from-step-1');
await chat.load();

const history = chat.getHistory();
console.log(`Loaded ${history.length} messages from Claude CLI session`);

3. Continuing Conversations

// For continued conversations, the SDK provides the resume command:
// claude -p "follow up question" --resume session-id --output-format json --dangerously-skip-permissions

// Then load the updated session:
await chat.load(); // Reloads with new messages
const updatedHistory = chat.getHistory();

Why This Approach?

  1. Claude CLI Reliability Issues: Programmatic execution of Claude CLI has known hanging issues with stream-json format
  2. Session Persistence: Manual execution ensures sessions are properly saved to Claude's storage
  3. Full Feature Access: Manual execution provides access to all Claude CLI features (tools, etc.)
  4. Type Safety: SDK provides full TypeScript safety for session management
  5. Best of Both Worlds: Combines Claude CLI's full capabilities with SDK convenience

Session Storage

The SDK reads from Claude CLI's built-in storage:

  • Location: ~/.claude/projects/
  • Format: JSONL files with UUID names
  • Content: Complete conversation history with tools, timestamps, and metadata

Configuration

// Debug mode for detailed logging
const conversation = await Claude.start({ debug: true });

// Work with specific session ID
const conversation = await Claude.start({ sessionId: 'your-uuid' });

// Validate session ID format
if (Claude.validateSessionId(sessionId)) {
  // Valid UUID format
}

Requirements

  • Node.js 16+
  • Claude CLI installed and configured
  • TypeScript 5+ (for development)

Contributing

  1. Clone the repository
  2. Run npm install
  3. Run npm run build to compile TypeScript
  4. Test with existing Claude CLI sessions

License

MIT

Support

For issues related to:

The SDK provides a robust, type-safe interface for working with Claude CLI sessions while respecting the CLI's execution limitations.