cc-hooks-ts 2.0.56 → 2.0.65

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +128 -91
  2. package/dist/index.d.mts +2 -2
  3. package/package.json +10 -10
package/README.md CHANGED
@@ -1,37 +1,67 @@
1
1
  # cc-hooks-ts
2
2
 
3
- Define Claude Code hooks with full type safety using TypeScript and Valibot validation.
3
+ Define Claude Code hooks with full type safety using TypeScript.
4
+
5
+ See [examples](./examples) for more usage examples.
6
+
7
+ <!-- TOC -->
8
+
9
+ - [cc-hooks-ts](#cc-hooks-ts)
10
+ - [Installation](#installation)
11
+ - [Basic Usage](#basic-usage)
12
+ - [Define a Hook](#define-a-hook)
13
+ - [Configure Claude Code](#configure-claude-code)
14
+ - [Tool Specific Hooks](#tool-specific-hooks)
15
+ - [Custom Tool Types Support](#custom-tool-types-support)
16
+ - [Advanced Usage](#advanced-usage)
17
+ - [Conditional Hook Execution](#conditional-hook-execution)
18
+ - [Advanced JSON Output](#advanced-json-output)
19
+ - [Documentation](#documentation)
20
+ - [Development](#development)
21
+ - [License](#license)
22
+ - [Contributing](#contributing)
23
+
24
+ <!-- /TOC -->
4
25
 
5
26
  > [!NOTE]
6
- > Beginning with versions equal to 2.0.0 or 2.0.42 and above, we started releasing using the same version numbers as Claude Code.
7
- > This enables us to support newer type definitions while preserving maximum compatibility.
27
+ > Starting with versions 2.0.42, we will raise our version number to match Claude Code whenever Hook-related changes occur.
28
+ >
29
+ > This ensures we can adopt newer type definitions while maintaining compatibility.
8
30
 
9
31
  ## Installation
10
32
 
11
33
  ```bash
12
- npx nypm add cc-hooks-ts
34
+ # npm
35
+ npm i cc-hooks-ts
36
+
37
+ # yarn
38
+ yarn add cc-hooks-ts
39
+
40
+ # pnpm
41
+ pnpm add cc-hooks-ts
42
+
43
+ # Bun
44
+ bun add cc-hooks-ts
45
+
46
+ # Deno
47
+ deno add npm:cc-hooks-ts
13
48
  ```
14
49
 
15
50
  ## Basic Usage
16
51
 
17
52
  ### Define a Hook
18
53
 
19
- Example of running a simple SessionStart hook on Bun:
20
-
21
54
  ```typescript
22
55
  import { defineHook } from "cc-hooks-ts";
23
56
 
24
- const sessionHook = defineHook({
57
+ const hook = defineHook({
58
+ // Specify the event(s) that trigger this hook.
25
59
  trigger: {
26
- // Specify the hook event to listen for
27
- SessionStart: true,
28
- PreToolUse: {
29
- // PreToolUser and PostToolUse can be tool-specific. (affects type of context)
30
- Read: true
31
- }
60
+ SessionStart: true
32
61
  },
62
+ // Implement what you want to do.
33
63
  run: (context) => {
34
- // do something great
64
+ // Do something great here
35
65
  return context.success({
36
66
  messageForUser: "Welcome to your coding session!"
37
67
  });
@@ -41,11 +71,11 @@ const sessionHook = defineHook({
41
71
  // import.meta.main is available in Node.js 24.2+ and Bun and Deno
42
72
  if (import.meta.main) {
43
73
  const { runHook } = await import("cc-hooks-ts");
44
- await runHook(sessionHook);
74
+ await runHook(hook);
45
75
  }
46
76
  ```
47
77
 
48
- ### Call from Claude Code
78
+ ### Configure Claude Code
49
79
 
50
80
  Then, load defined hooks in your Claude Code settings at `~/.claude/settings.json`.
51
81
 
@@ -57,7 +87,7 @@ Then, load defined hooks in your Claude Code settings at `~/.claude/settings.jso
57
87
  "hooks": [
58
88
  {
59
89
  "type": "command",
60
- "command": "bun run --silent path/to/your/sessionHook.ts"
90
+ "command": "bun run -i --silent path/to/your/sessionHook.ts"
61
91
  }
62
92
  ]
63
93
  }
@@ -66,111 +96,122 @@ Then, load defined hooks in your Claude Code settings at `~/.claude/settings.jso
66
96
  }
67
97
  ```
68
98
 
69
- ## Custom Tool Type Support
99
+ ## Tool Specific Hooks
70
100
 
71
- For better type inference in PreToolUse and PostToolUse hooks, you can extend the `ToolSchema` interface to define your own tool types:
101
+ In `PreToolUse`, `PostToolUse`, and `PostToolUseFailure` events, you can define hooks specific to tools by specifying tool names in the trigger configuration.
72
102
 
73
- ### Adding Custom Tool Definitions
74
-
75
- Extend the `ToolSchema` interface to add custom tool definitions:
103
+ For example, you can create a hook that only runs before the `Read` tool is used:
76
104
 
77
105
  ```typescript
78
- // Use "npm:cc-hooks-ts" for Deno
79
- declare module "cc-hooks-ts" {
80
- interface ToolSchema {
81
- MyCustomTool: {
82
- input: {
83
- customParam: string;
84
- optionalParam?: number;
85
- };
86
- response: {
87
- result: string;
88
- };
89
- };
106
+ const preReadHook = defineHook({
107
+ trigger: { PreToolUse: { Read: true } },
108
+ run: (context) => {
109
+ // context.input.tool_input is typed as { file_path: string; limit?: number; offset?: number; }
110
+ const { file_path } = context.input.tool_input;
111
+
112
+ if (file_path.includes('.env')) {
113
+ return context.blockingError('Cannot read environment files');
114
+ }
115
+
116
+ return context.success();
90
117
  }
118
+ });
119
+
120
+ if (import.meta.main) {
121
+ const { runHook } = await import("cc-hooks-ts");
122
+ await runHook(preReadHook);
91
123
  }
92
124
  ```
93
125
 
94
- Now you can use your custom tool with full type safety:
126
+ Then configure it in Claude Code settings:
95
127
 
96
- ```typescript
97
- const customToolHook = defineHook({
98
- trigger: { PreToolUse: { MyCustomTool: true } },
99
- run: (context) => {
100
- // context.input.tool_input is typed as { customParam: string; optionalParam?: number; }
101
- const { customParam, optionalParam } = context.input.tool_input;
102
- return context.success();
128
+ ```json
129
+ {
130
+ "hooks": {
131
+ "PreToolUse": [
132
+ {
133
+ "matcher": "Read",
134
+ "hooks": [
135
+ {
136
+ "type": "command",
137
+ "command": "bun run -i --silent path/to/your/preReadHook.ts"
138
+ }
139
+ ]
140
+ }
141
+ ]
103
142
  }
104
- });
143
+ }
105
144
  ```
106
145
 
107
- ## API Reference
146
+ ### Custom Tool Types Support
108
147
 
109
- ### defineHook Function
148
+ You can add support for custom tools by extending the tool type definitions.
110
149
 
111
- Creates type-safe hook definitions with full TypeScript inference:
150
+ This is useful when you want to your MCP-defined tools to have type-safe hook inputs.
112
151
 
113
152
  ```typescript
114
- // Tool-specific PreToolUse hook
115
- const readHook = defineHook({
116
- trigger: { PreToolUse: { Read: true } },
153
+ import { defineHook } from "cc-hooks-ts";
154
+
155
+ // Example: type-safe hooks for DeepWiki MCP Server tools
156
+ declare module "cc-hooks-ts" {
157
+ interface ToolSchema {
158
+ mcp__deepwiki__ask_question: {
159
+ input: {
160
+ question: string;
161
+ repoName: string;
162
+ };
163
+ response: unknown;
164
+ };
165
+ }
166
+ }
167
+
168
+ const deepWikiHook = defineHook({
169
+ trigger: { PreToolUse: { mcp__deepwiki__ask_question: true } },
117
170
  run: (context) => {
118
- // context.input.tool_input is typed as { file_path: string }
119
- const { file_path } = context.input.tool_input;
171
+ // context.input.tool_input is typed as { question: string; repoName: string; }
172
+ const { question, repoName } = context.input.tool_input;
120
173
 
121
- if (file_path.includes('.env')) {
122
- return context.blockingError('Cannot read environment files');
174
+ if (question.length > 500) {
175
+ return context.blockingError('Question is too long');
123
176
  }
124
177
 
125
178
  return context.success();
126
179
  }
127
180
  });
181
+ ```
182
+
183
+ ## Advanced Usage
184
+
185
+ ### Conditional Hook Execution
186
+
187
+ You can conditionally execute hooks based on runtime logic using the `shouldRun` function.
188
+ If `shouldRun` returns `false`, the hook will be skipped.
189
+
190
+ ```ts
191
+ import { defineHook } from "cc-hooks-ts";
128
192
 
129
- // Multiple event triggers
130
- const multiEventHook = defineHook({
193
+ const hook = defineHook({
131
194
  trigger: {
132
- PreToolUse: { Read: true, WebFetch: true },
133
- PostToolUse: { Read: true }
195
+ Notification: true
134
196
  },
135
- // Optional: Define when the hook should run.
136
- shouldRun: () => process.env.NODE_ENV === 'development',
197
+ // Only run this hook on macOS
198
+ shouldRun: () => process.platform === "darwin",
137
199
  run: (context) => {
138
- // Handle different events and tools based on context.input
139
- return context.success();
200
+ // Some macOS-specific logic like sending a notification using AppleScript
201
+ return context.success()
140
202
  }
141
203
  });
142
204
  ```
143
205
 
144
- ### runHook Function
145
-
146
- Executes hooks with complete lifecycle management:
206
+ ### Advanced JSON Output
147
207
 
148
- - Reads input from stdin
149
- - Validates input using Valibot schemas
150
- - Creates typed context
151
- - Executes hook handler
152
- - Formats and outputs results
153
-
154
- ```typescript
155
- await runHook(hook);
156
- ```
208
+ Use `context.json()` to return structured JSON output with advanced control over hook behavior.
157
209
 
158
- ### Hook Context
210
+ For 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).
159
211
 
160
- The context provides strongly typed input access and response helpers:
212
+ ## Documentation
161
213
 
162
- ```typescript
163
- run: (context) => {
164
- // Typed input based on trigger configuration
165
- const input = context.input;
166
-
167
- // Response helpers
168
- return context.success({ messageForUser: "Success!" });
169
- // or context.blockingError("Error occurred");
170
- // or context.nonBlockingError("Warning message");
171
- // or context.json({ event: "EventName", output: {...} });
172
- }
173
- ```
214
+ For more detailed information about Claude Code hooks, visit the [official documentation](https://docs.anthropic.com/en/docs/claude-code/hooks).
174
215
 
175
216
  ## Development
176
217
 
@@ -191,10 +232,6 @@ pnpm format
191
232
  pnpm typecheck
192
233
  ```
193
234
 
194
- ## Documentation
195
-
196
- For more detailed information about Claude Code hooks, visit the [official documentation](https://docs.anthropic.com/en/docs/claude-code/hooks).
197
-
198
235
  ## License
199
236
 
200
237
  MIT
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as v from "valibot";
2
- import { AgentInput, BashInput, BashOutputInput, ExitPlanModeInput, FileEditInput, FileReadInput, FileWriteInput, GlobInput, GrepInput, KillShellInput, ListMcpResourcesInput, NotebookEditInput, ReadMcpResourceInput, TodoWriteInput, WebFetchInput, WebSearchInput } from "@anthropic-ai/claude-agent-sdk/sdk-tools";
2
+ import { AgentInput, BashInput, ExitPlanModeInput, FileEditInput, FileReadInput, FileWriteInput, GlobInput, GrepInput, KillShellInput, ListMcpResourcesInput, NotebookEditInput, ReadMcpResourceInput, TaskOutputInput, TodoWriteInput, WebFetchInput, WebSearchInput } from "@anthropic-ai/claude-agent-sdk/sdk-tools";
3
3
 
4
4
  //#region src/utils/types.d.ts
5
5
  type Awaitable<T> = Promise<T> | T;
@@ -747,7 +747,7 @@ interface ToolSchema {
747
747
  };
748
748
  };
749
749
  BashOutput: {
750
- input: BashOutputInput;
750
+ input: TaskOutputInput;
751
751
  response: unknown;
752
752
  };
753
753
  Edit: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cc-hooks-ts",
3
- "version": "2.0.56",
3
+ "version": "2.0.65",
4
4
  "type": "module",
5
5
  "description": "Write claude code hooks with type safety",
6
6
  "sideEffects": false,
@@ -43,33 +43,33 @@
43
43
  },
44
44
  "devDependencies": {
45
45
  "@arethetypeswrong/core": "0.18.2",
46
- "@biomejs/biome": "2.3.8",
47
46
  "@types/node": "24.10.1",
48
47
  "@typescript/native-preview": "^7.0.0-dev.20251108.1",
49
48
  "@virtual-live-lab/eslint-config": "2.3.1",
50
49
  "@virtual-live-lab/tsconfig": "2.1.21",
51
50
  "eslint": "9.39.1",
52
51
  "eslint-plugin-import-access": "3.1.0",
53
- "pkg-pr-new": "0.0.60",
52
+ "oxfmt": "0.16.0",
53
+ "pkg-pr-new": "0.0.62",
54
54
  "publint": "0.3.15",
55
55
  "release-it": "19.0.6",
56
56
  "release-it-pnpm": "4.6.6",
57
- "tsdown": "0.16.8",
58
- "type-fest": "5.2.0",
57
+ "tsdown": "0.17.0",
58
+ "type-fest": "5.3.1",
59
59
  "typescript": "5.9.3",
60
- "typescript-eslint": "8.48.0",
60
+ "typescript-eslint": "8.48.1",
61
61
  "unplugin-unused": "0.5.6",
62
- "vitest": "4.0.14"
62
+ "vitest": "4.0.15"
63
63
  },
64
64
  "dependencies": {
65
- "@anthropic-ai/claude-agent-sdk": "0.1.56",
65
+ "@anthropic-ai/claude-agent-sdk": "0.1.65",
66
66
  "valibot": "^1.1.0"
67
67
  },
68
68
  "scripts": {
69
69
  "check": "pnpm run format:check && pnpm run lint && pnpm run typecheck && pnpm run test && pnpm run build",
70
70
  "lint": "eslint --max-warnings 0",
71
- "format": "biome format --write",
72
- "format:check": "biome format --reporter=github",
71
+ "format": "oxfmt",
72
+ "format:check": "oxfmt --check",
73
73
  "typecheck": "tsgo --noEmit",
74
74
  "test": "vitest --run",
75
75
  "build": "tsdown",