{"id":31537701,"url":"https://github.com/sushichan044/cc-hooks-ts","last_synced_at":"2026-04-08T15:01:04.118Z","repository":{"id":311276574,"uuid":"1043306715","full_name":"sushichan044/cc-hooks-ts","owner":"sushichan044","description":"Define Claude Code hooks with full type safety.","archived":false,"fork":false,"pushed_at":"2026-03-10T09:36:41.000Z","size":974,"stargazers_count":33,"open_issues_count":5,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-03-10T16:59:12.191Z","etag":null,"topics":["claude-code","typescript"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/cc-hooks-ts","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sushichan044.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null},"funding":{"github":"sushichan044"}},"created_at":"2025-08-23T15:21:50.000Z","updated_at":"2026-03-05T03:35:16.000Z","dependencies_parsed_at":"2025-11-17T10:01:10.524Z","dependency_job_id":null,"html_url":"https://github.com/sushichan044/cc-hooks-ts","commit_stats":null,"previous_names":["sushichan044/cc-hooks-ts"],"tags_count":29,"template":false,"template_full_name":null,"purl":"pkg:github/sushichan044/cc-hooks-ts","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sushichan044%2Fcc-hooks-ts","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sushichan044%2Fcc-hooks-ts/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sushichan044%2Fcc-hooks-ts/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sushichan044%2Fcc-hooks-ts/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sushichan044","download_url":"https://codeload.github.com/sushichan044/cc-hooks-ts/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sushichan044%2Fcc-hooks-ts/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30417686,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-12T06:40:58.731Z","status":"ssl_error","status_checked_at":"2026-03-12T06:40:40.296Z","response_time":114,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["claude-code","typescript"],"created_at":"2025-10-04T08:10:13.790Z","updated_at":"2026-04-08T15:01:04.104Z","avatar_url":"https://github.com/sushichan044.png","language":"TypeScript","funding_links":["https://github.com/sponsors/sushichan044"],"categories":["TypeScript","Hook SDKs and Frameworks"],"sub_categories":[],"readme":"# cc-hooks-ts\n\nDefine Claude Code hooks with full type safety using TypeScript.\n\nSee [examples](./examples) for more usage examples.\n\n\u003c!-- TOC --\u003e\n\n- [cc-hooks-ts](#cc-hooks-ts)\n  - [Installation](#installation)\n  - [Basic Usage](#basic-usage)\n    - [Define a Hook](#define-a-hook)\n    - [Configure Claude Code](#configure-claude-code)\n  - [Tool Specific Hooks](#tool-specific-hooks)\n    - [Custom Tool Types Support](#custom-tool-types-support)\n  - [Advanced Usage](#advanced-usage)\n    - [Conditional Hook Execution](#conditional-hook-execution)\n    - [Advanced JSON Output](#advanced-json-output)\n    - [Async JSON Output (Experimental)](#async-json-output-experimental)\n  - [Documentation](#documentation)\n  - [Development](#development)\n    - [How to follow the upstream changes](#how-to-follow-the-upstream-changes)\n      - [If a Dependabot PR already exists](#if-a-dependabot-pr-already-exists)\n      - [If no Dependabot PR exists](#if-no-dependabot-pr-exists)\n  - [License](#license)\n  - [Contributing](#contributing)\n\n\u003c!-- /TOC --\u003e\n\n\u003e [!NOTE]\n\u003e Starting with versions 2.0.42, we will raise our version number to match Claude Code whenever Hook-related changes occur.\n\u003e\n\u003e This ensures we can adopt newer type definitions while maintaining compatibility.\n\n## Installation\n\n```bash\n# npm\nnpm i cc-hooks-ts\n\n# yarn\nyarn add cc-hooks-ts\n\n# pnpm\npnpm add cc-hooks-ts\n\n# Bun\nbun add cc-hooks-ts\n\n# Deno\ndeno add npm:cc-hooks-ts\n```\n\n## Basic Usage\n\n### Define a Hook\n\n```typescript\nimport { defineHook } from \"cc-hooks-ts\";\n\nconst hook = defineHook({\n  // Specify the event(s) that trigger this hook.\n  trigger: {\n    SessionStart: true,\n  },\n  // Implement what you want to do.\n  run: (context) =\u003e {\n    // Do something great here\n    return context.success({\n      messageForUser: \"Welcome to your coding session!\",\n    });\n  },\n});\n\n// import.meta.main is available in Node.js 24.2+ and Bun and Deno\nif (import.meta.main) {\n  const { runHook } = await import(\"cc-hooks-ts\");\n  await runHook(hook);\n}\n```\n\n### Configure Claude Code\n\nThen, load defined hooks in your Claude Code settings at `~/.claude/settings.json`.\n\n```json\n{\n  \"hooks\": {\n    \"SessionStart\": [\n      {\n        \"hooks\": [\n          {\n            \"type\": \"command\",\n            \"command\": \"bun run -i --silent path/to/your/sessionHook.ts\"\n          }\n        ]\n      }\n    ]\n  }\n}\n```\n\n## Tool Specific Hooks\n\nIn `PreToolUse`, `PostToolUse`, `PostToolUseFailure`, `PermissionRequest`, and `PermissionDenied` events, you can define hooks specific to tools by specifying tool names in the trigger configuration.\n\nFor example, you can create a hook that only runs before the `Read` tool is used:\n\n```typescript\nconst preReadHook = defineHook({\n  trigger: { PreToolUse: { Read: true } },\n  run: (context) =\u003e {\n    // context.input.tool_input is typed as { file_path: string; limit?: number; offset?: number; }\n    const { file_path } = context.input.tool_input;\n\n    if (file_path.includes(\".env\")) {\n      return context.blockingError(\"Cannot read environment files\");\n    }\n\n    return context.success();\n  },\n});\n\nif (import.meta.main) {\n  const { runHook } = await import(\"cc-hooks-ts\");\n  await runHook(preReadHook);\n}\n```\n\nThen configure it in Claude Code settings:\n\n```json\n{\n  \"hooks\": {\n    \"PreToolUse\": [\n      {\n        \"matcher\": \"Read\",\n        \"hooks\": [\n          {\n            \"type\": \"command\",\n            \"command\": \"bun run -i --silent path/to/your/preReadHook.ts\"\n          }\n        ]\n      }\n    ]\n  }\n}\n```\n\nThe same trigger shape also works for permission hooks:\n\n```typescript\nconst permissionRequestHook = defineHook({\n  trigger: { PermissionRequest: { Bash: true } },\n  run: (context) =\u003e {\n    // context.input.tool_input is typed as BashInput\n    const { command } = context.input.tool_input;\n\n    if (command.includes(\"rm -rf\")) {\n      return context.blockingError(\"Refusing destructive command\");\n    }\n\n    return context.success();\n  },\n});\n```\n\n### Custom Tool Types Support\n\nYou can add support for custom tools by extending the tool type definitions.\n\nThis is useful when you want to your MCP-defined tools to have type-safe hook inputs.\n\n```typescript\nimport { defineHook } from \"cc-hooks-ts\";\n\n// Example: type-safe hooks for DeepWiki MCP Server tools\ndeclare module \"cc-hooks-ts\" {\n  interface ToolSchema {\n    mcp__deepwiki__ask_question: {\n      input: {\n        question: string;\n        repoName: string;\n      };\n      response: unknown;\n    };\n  }\n}\n\nconst deepWikiHook = defineHook({\n  trigger: { PreToolUse: { mcp__deepwiki__ask_question: true } },\n  run: (context) =\u003e {\n    // context.input.tool_input is typed as { question: string; repoName: string; }\n    const { question, repoName } = context.input.tool_input;\n\n    if (question.length \u003e 500) {\n      return context.blockingError(\"Question is too long\");\n    }\n\n    return context.success();\n  },\n});\n```\n\n## Advanced Usage\n\n### Conditional Hook Execution\n\nYou can conditionally execute hooks based on runtime logic using the `shouldRun` function.\nIf `shouldRun` returns `false`, the hook will be skipped.\n\n```ts\nimport { defineHook } from \"cc-hooks-ts\";\n\nconst hook = defineHook({\n  trigger: {\n    Notification: true,\n  },\n  // Only run this hook on macOS\n  shouldRun: () =\u003e process.platform === \"darwin\",\n  run: (context) =\u003e {\n    // Some macOS-specific logic like sending a notification using AppleScript\n    return context.success();\n  },\n});\n```\n\n### Advanced JSON Output\n\nUse `context.json()` to return structured JSON output with advanced control over hook behavior.\n\nFor detailed information about available JSON fields and their behavior, see the [official documentation](https://docs.anthropic.com/en/docs/claude-code/hooks#advanced:-json-output).\n\n### Async JSON Output (Experimental)\n\n\u003e [!WARNING]\n\u003e This behavior is undocumented by Anthropic and may change.\n\n\u003e [!CAUTION]\n\u003e You must enable verbose output if you want to see async hook outputs like `systemMessage` or `hookSpecificOutput.additionalContext`.\n\u003e\n\u003e You can enable it in Claude Code by going to `/config` and setting \"verbose\" to true.\n\nAsync JSON output allows hooks to perform longer computations without blocking the Claude Code TUI.\n\nYou can use `context.defer()` to respond Claude Code immediately while performing longer computations in the background.\n\nYou should complete the async operation within a reasonable time (e.g. 15 seconds).\n\n```ts\nimport { defineHook } from \"cc-hooks-ts\";\n\nconst hook = defineHook({\n  trigger: { PostToolUse: { Read: true } },\n  run: (context) =\u003e\n    context.defer(\n      async () =\u003e {\n        // Simulate long-running computation\n        await new Promise((resolve) =\u003e setTimeout(resolve, 2000));\n\n        return {\n          event: \"PostToolUse\",\n          output: {\n            systemMessage: \"Read tool used successfully after async processing!\",\n          },\n        };\n      },\n      {\n        timeoutMs: 5000, // Optional timeout for the async operation.\n      },\n    ),\n});\n```\n\n## Documentation\n\nFor more detailed information about Claude Code hooks, visit the [official documentation](https://docs.anthropic.com/en/docs/claude-code/hooks).\n\n## Development\n\n```bash\n# Run tests\npnpm test\n\n# Build\npnpm build\n\n# Lint\npnpm lint\n\n# Format\npnpm format\n\n# Type check\npnpm typecheck\n```\n\n### How to follow the upstream changes\n\nDependabot automatically creates PRs to bump `@anthropic-ai/claude-agent-sdk`. The CI bot posts a type diff comment on each PR.\n\n#### If a Dependabot PR already exists\n\n1. Find the Dependabot PR that bumps `@anthropic-ai/claude-agent-sdk` and check out its branch.\n\n2. Read the type diff posted as a PR comment, then reflect the changes.\n   - Edit `src/hooks/` for changed hook input / output types.\n     - No need for adding tests in most cases since we are testing the whole type definitions in these files:\n       - `src/hooks/input/schemas.test-d.ts`\n       - `src/hooks/output/index.test-d.ts`\n       - `src/hooks/event.test-d.ts`\n       - `src/hooks/permission.test-d.ts`\n   - Edit `src/index.ts` for changed tool input / output types.\n   - YOU SHOULD NOT MODIFY `version` in `package.json` manually.\n\n3. Push to the Dependabot PR branch.\n\n4. Update the PR title to:\n\n   ```plaintext\n   fix: update to parity with Claude Code v$(npm info @anthropic-ai/claude-agent-sdk claudeCodeVersion)\n   ```\n\n#### If no Dependabot PR exists\n\n1. Create a new branch and bump `@anthropic-ai/claude-agent-sdk` to the latest version:\n\n   ```bash\n   git switch -c bump-claude-agent-sdk\n   pnpm add @anthropic-ai/claude-agent-sdk@latest\n   ```\n\n2. Get the type diff between the old and new versions:\n\n   ```bash\n   npm diff --diff=@anthropic-ai/claude-agent-sdk@\u003cold_version\u003e --diff=@anthropic-ai/claude-agent-sdk@\u003cnew_version\u003e '**/*.d.ts'\n   ```\n\n3. Reflect the changes (same as step 2 above).\n\n4. Commit, push, and create a PR with the title:\n\n   ```plaintext\n   fix: update to parity with Claude Code v$(npm info @anthropic-ai/claude-agent-sdk claudeCodeVersion)\n   ```\n\n## License\n\nMIT\n\n## Contributing\n\nWe welcome contributions! Feel free to open issues or submit pull requests.\n\n---\n\n**Made with ❤️ for hackers using Claude Code**\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsushichan044%2Fcc-hooks-ts","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsushichan044%2Fcc-hooks-ts","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsushichan044%2Fcc-hooks-ts/lists"}