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 🙏

© 2025 – Pkg Stats / Ryan Hefner

claude-hook-sdk

v1.1.0

Published

TypeScript SDK for building Claude Code hooks

Readme

Claude Hook SDK (TypeScript)

A TypeScript SDK for building Claude Code hooks, providing a clean and fluent API for handling hook events and responses.

Installation

npm install claude-hook-sdk

Quick Start

Basic Usage

import { createHook } from 'claude-hook-sdk'

// Create a hook from stdin
const hook = await createHook()

// Build a response
hook.response()
  .approve('Tool usage approved')
  .continue()

Hook Types

The SDK supports all Claude Code hook events:

  • PreToolUse: Executed before tool calls
  • PostToolUse: Executed after tool calls
  • Notification: Handles notification events
  • Stop: Handles stop events
  • SubagentStop: Handles subagent stop events

Example Hook Script

#!/usr/bin/env node
import { createHook, PreToolUseHook } from 'claude-hook-sdk'

async function main() {
  const hook = await createHook()
  
  if (hook instanceof PreToolUseHook) {
    const toolName = hook.toolName()
    const toolInput = hook.toolInput()
    
    // Block dangerous operations
    if (toolName === 'Bash' && toolInput.command?.includes('rm -rf')) {
      hook.response()
        .block('Dangerous command blocked')
        .continue()
      return
    }
  }
  
  // Default: approve
  hook.response()
    .approve('Tool usage approved')
    .continue()
}

main()

API Reference

Factory Functions

  • createHook(): Promise<AnyHook> - Create hook from stdin
  • createHookFromString(json: string): AnyHook - Create hook from JSON string
  • createHookFromPayload(payload: HookPayload): AnyHook - Create hook from parsed payload

Hook Classes

Base Hook Class

All hooks inherit from the base Hook class:

abstract class Hook {
  getSessionId(): string
  getTranscriptPath(): string
  getRawData(): HookPayload
  transcript(): any[]
  response(): ResponseBuilder
  error(message: string): never
  success(message: string): never
  abstract eventName(): string
}

PreToolUseHook

class PreToolUseHook extends Hook {
  toolName(): string
  toolInput(): Record<string, any>
  toolInput<T>(key: string): T | undefined
  toolInput<T>(key: string, defaultValue: T): T
  estimatedTokens(): number
}

PostToolUseHook

class PostToolUseHook extends Hook {
  toolName(): string
  toolInput(): Record<string, any>
  toolInput<T>(key: string): T | undefined  
  toolInput<T>(key: string, defaultValue: T): T
  toolResponse(): Record<string, any>
  toolResponse<T>(key: string): T | undefined
  toolResponse<T>(key: string, defaultValue: T): T
}

NotificationHook

class NotificationHook extends Hook {
  message(): string
  title(): string
}

StopHook & SubagentStopHook

class StopHook extends Hook {
  stopHookActive(): boolean
}

class SubagentStopHook extends Hook {
  stopHookActive(): boolean
}

ResponseBuilder

Fluent API for building hook responses:

class ResponseBuilder {
  approve(reason?: string): this
  block(reason: string): this
  suppressOutput(): this
  merge(fields: Record<string, any>): this
  continue(): never  // Exits with code 0
  stop(reason: string): never  // Exits with code 1
}

CLI Tools

Basic Hook Runner

echo '{"session_id":"test","transcript_path":"/tmp/test.jsonl","hook_event_name":"Notification","message":"Hello"}' | claude-hook

Routers

The SDK includes multiple routing options:

Deterministic Router (Legacy)

# Basic usage (defaults to Gemini CLI routing)
deterministic-router

# Configurable via environment variables
ROUTER_TARGET=my-cli ROUTER_NAME="My CLI" deterministic-router

Configurable Router (Recommended)

# Gemini router (default)
ROUTER_TYPE=gemini configurable-router

# Claude router
ROUTER_TYPE=claude configurable-router

# Multi-model router
ROUTER_TYPE=multi configurable-router

# Custom router
ROUTER_TYPE=custom ROUTER_TARGET=my-tool ROUTER_NAME="My Tool" configurable-router

Router Configuration

Environment variables for customization:

  • ROUTER_TYPE: Router type (gemini, claude, multi, custom)
  • ROUTER_TARGET: Target delegate name (e.g., gemini-cli, claude-opus)
  • ROUTER_NAME: Human-readable name for routing decisions
  • ROUTER_MAX_FILE_SIZE: Maximum file size in bytes (default: 10MB)
  • ROUTER_MAX_FILES: Maximum number of files (default: 3)
  • ROUTER_MAX_TOKENS: Maximum estimated tokens (default: 50000)

Programmatic Router Usage

import { ConfigurableRouter, PreToolUseHook } from 'claude-hook-sdk'

// Create a custom router
const router = new ConfigurableRouter({ maxFiles: 5, maxTokens: 100000 })
  .addSizeBasedRule('Large Model', 'claude-opus')
  .addToolBasedRule('Code Assistant', 'claude-sonnet', ['Edit', 'Write'])
  .addCustomRule('Special Case', 'custom-tool', (hook) => {
    return hook.toolInput('special') === true
  })

// Use with a hook
if (hook instanceof PreToolUseHook) {
  router.route(hook)
}

// Or evaluate without routing
const result = router.evaluate(hook)
if (result.shouldRoute) {
  console.log(`Would route to: ${result.rule?.target}`)
}

Configuration

Example Claude Code settings:

{
  "hooks": [
    {
      "event": "PreToolUse",
      "matcher": "mcp__gemini-cli__.*",
      "command": "deterministic-router"
    },
    {
      "event": "PreToolUse", 
      "matcher": ".*",
      "command": "configurable-router",
      "env": {
        "ROUTER_TYPE": "multi",
        "ROUTER_MAX_FILES": "5"
      }
    },
    {
      "event": "PostToolUse",
      "matcher": ".*",
      "command": "claude-hook"
    }
  ]
}

Testing

npm test          # Run tests
npm run test:watch  # Watch mode
npm run test:coverage  # Coverage report

Development

npm run build    # Build TypeScript
npm run dev      # Watch mode

License

MIT