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

cc-hooks-ts

v2.1.50

Published

Write claude code hooks with type safety

Readme

cc-hooks-ts

Define Claude Code hooks with full type safety using TypeScript.

See examples for more usage examples.

[!NOTE] Starting with versions 2.0.42, we will raise our version number to match Claude Code whenever Hook-related changes occur.

This ensures we can adopt newer type definitions while maintaining compatibility.

Installation

# npm
npm i cc-hooks-ts

# yarn
yarn add cc-hooks-ts

# pnpm
pnpm add cc-hooks-ts

# Bun
bun add cc-hooks-ts

# Deno
deno add npm:cc-hooks-ts

Basic Usage

Define a Hook

import { defineHook } from "cc-hooks-ts";

const hook = defineHook({
  // Specify the event(s) that trigger this hook.
  trigger: {
    SessionStart: true,
  },
  // Implement what you want to do.
  run: (context) => {
    // Do something great here
    return context.success({
      messageForUser: "Welcome to your coding session!",
    });
  },
});

// import.meta.main is available in Node.js 24.2+ and Bun and Deno
if (import.meta.main) {
  const { runHook } = await import("cc-hooks-ts");
  await runHook(hook);
}

Configure Claude Code

Then, load defined hooks in your Claude Code settings at ~/.claude/settings.json.

{
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "bun run -i --silent path/to/your/sessionHook.ts"
          }
        ]
      }
    ]
  }
}

Tool Specific Hooks

In PreToolUse, PostToolUse, and PostToolUseFailure events, you can define hooks specific to tools by specifying tool names in the trigger configuration.

For example, you can create a hook that only runs before the Read tool is used:

const preReadHook = defineHook({
  trigger: { PreToolUse: { Read: true } },
  run: (context) => {
    // context.input.tool_input is typed as { file_path: string; limit?: number; offset?: number; }
    const { file_path } = context.input.tool_input;

    if (file_path.includes(".env")) {
      return context.blockingError("Cannot read environment files");
    }

    return context.success();
  },
});

if (import.meta.main) {
  const { runHook } = await import("cc-hooks-ts");
  await runHook(preReadHook);
}

Then configure it in Claude Code settings:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Read",
        "hooks": [
          {
            "type": "command",
            "command": "bun run -i --silent path/to/your/preReadHook.ts"
          }
        ]
      }
    ]
  }
}

Custom Tool Types Support

You can add support for custom tools by extending the tool type definitions.

This is useful when you want to your MCP-defined tools to have type-safe hook inputs.

import { defineHook } from "cc-hooks-ts";

// Example: type-safe hooks for DeepWiki MCP Server tools
declare module "cc-hooks-ts" {
  interface ToolSchema {
    mcp__deepwiki__ask_question: {
      input: {
        question: string;
        repoName: string;
      };
      response: unknown;
    };
  }
}

const deepWikiHook = defineHook({
  trigger: { PreToolUse: { mcp__deepwiki__ask_question: true } },
  run: (context) => {
    // context.input.tool_input is typed as { question: string; repoName: string; }
    const { question, repoName } = context.input.tool_input;

    if (question.length > 500) {
      return context.blockingError("Question is too long");
    }

    return context.success();
  },
});

Advanced Usage

Conditional Hook Execution

You can conditionally execute hooks based on runtime logic using the shouldRun function. If shouldRun returns false, the hook will be skipped.

import { defineHook } from "cc-hooks-ts";

const hook = defineHook({
  trigger: {
    Notification: true,
  },
  // Only run this hook on macOS
  shouldRun: () => process.platform === "darwin",
  run: (context) => {
    // Some macOS-specific logic like sending a notification using AppleScript
    return context.success();
  },
});

Advanced JSON Output

Use context.json() to return structured JSON output with advanced control over hook behavior.

For detailed information about available JSON fields and their behavior, see the official documentation.

Async JSON Output (Experimental)

[!WARNING] This behavior is undocumented by Anthropic and may change.

[!CAUTION] You must enable verbose output if you want to see async hook outputs like systemMessage or hookSpecificOutput.additionalContext.

You can enable it in Claude Code by going to /config and setting "verbose" to true.

Async JSON output allows hooks to perform longer computations without blocking the Claude Code TUI.

You can use context.defer() to respond Claude Code immediately while performing longer computations in the background.

You should complete the async operation within a reasonable time (e.g. 15 seconds).

import { defineHook } from "cc-hooks-ts";

const hook = defineHook({
  trigger: { PostToolUse: { Read: true } },
  run: (context) =>
    context.defer(
      async () => {
        // Simulate long-running computation
        await new Promise((resolve) => setTimeout(resolve, 2000));

        return {
          event: "PostToolUse",
          output: {
            systemMessage: "Read tool used successfully after async processing!",
          },
        };
      },
      {
        timeoutMs: 5000, // Optional timeout for the async operation.
      },
    ),
});

Documentation

For more detailed information about Claude Code hooks, visit the official documentation.

Development

# Run tests
pnpm test

# Build
pnpm build

# Lint
pnpm lint

# Format
pnpm format

# Type check
pnpm typecheck

How to follow the upstream changes

  1. Install the latest version of @anthropic-ai/claude-agent-sdk and run pnpm run check.

    • If the command passes without errors, there are no type changes.
  2. Get diff of the types. This example gets the diff between Claude Code 2.0.69 and 2.0.70:

    npm diff --diff=@anthropic-ai/[email protected] --diff=@anthropic-ai/[email protected] '**/*.d.ts'
    
    # Only for humans, You can use dandavison/delta for better diff visualization
    npm diff --diff=@anthropic-ai/[email protected] --diff=@anthropic-ai/[email protected] '**/*.d.ts' | delta --side-by-side
  3. Reflect the changes.

    • Edit src/hooks/ for changed hook input / output types.
      • No need for adding tests in most cases since we are testing the whole type definitions in these files:
        • src/hooks/input/schemas.test-d.ts
        • src/hooks/output/index.test-d.ts
        • src/hooks/event.test-d.ts
        • src/hooks/permission.test-d.ts
    • Edit src/index.ts for changed tool input / output types.

License

MIT

Contributing

We welcome contributions! Feel free to open issues or submit pull requests.


Made with ❤️ for hackers using Claude Code