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.
- package/README.md +128 -91
- package/dist/index.d.mts +2 -2
- 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
|
|
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
|
-
>
|
|
7
|
-
>
|
|
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
|
-
|
|
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
|
|
57
|
+
const hook = defineHook({
|
|
58
|
+
// Specify the event(s) that trigger this hook.
|
|
25
59
|
trigger: {
|
|
26
|
-
|
|
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
|
-
//
|
|
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(
|
|
74
|
+
await runHook(hook);
|
|
45
75
|
}
|
|
46
76
|
```
|
|
47
77
|
|
|
48
|
-
###
|
|
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
|
-
##
|
|
99
|
+
## Tool Specific Hooks
|
|
70
100
|
|
|
71
|
-
|
|
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
|
-
|
|
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
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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
|
-
|
|
126
|
+
Then configure it in Claude Code settings:
|
|
95
127
|
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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
|
-
|
|
146
|
+
### Custom Tool Types Support
|
|
108
147
|
|
|
109
|
-
|
|
148
|
+
You can add support for custom tools by extending the tool type definitions.
|
|
110
149
|
|
|
111
|
-
|
|
150
|
+
This is useful when you want to your MCP-defined tools to have type-safe hook inputs.
|
|
112
151
|
|
|
113
152
|
```typescript
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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 {
|
|
119
|
-
const {
|
|
171
|
+
// context.input.tool_input is typed as { question: string; repoName: string; }
|
|
172
|
+
const { question, repoName } = context.input.tool_input;
|
|
120
173
|
|
|
121
|
-
if (
|
|
122
|
-
return context.blockingError('
|
|
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
|
-
|
|
130
|
-
const multiEventHook = defineHook({
|
|
193
|
+
const hook = defineHook({
|
|
131
194
|
trigger: {
|
|
132
|
-
|
|
133
|
-
PostToolUse: { Read: true }
|
|
195
|
+
Notification: true
|
|
134
196
|
},
|
|
135
|
-
//
|
|
136
|
-
shouldRun: () => process.
|
|
197
|
+
// Only run this hook on macOS
|
|
198
|
+
shouldRun: () => process.platform === "darwin",
|
|
137
199
|
run: (context) => {
|
|
138
|
-
//
|
|
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
|
-
###
|
|
145
|
-
|
|
146
|
-
Executes hooks with complete lifecycle management:
|
|
206
|
+
### Advanced JSON Output
|
|
147
207
|
|
|
148
|
-
|
|
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
|
-
|
|
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
|
-
|
|
212
|
+
## Documentation
|
|
161
213
|
|
|
162
|
-
|
|
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,
|
|
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:
|
|
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.
|
|
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
|
-
"
|
|
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.
|
|
58
|
-
"type-fest": "5.
|
|
57
|
+
"tsdown": "0.17.0",
|
|
58
|
+
"type-fest": "5.3.1",
|
|
59
59
|
"typescript": "5.9.3",
|
|
60
|
-
"typescript-eslint": "8.48.
|
|
60
|
+
"typescript-eslint": "8.48.1",
|
|
61
61
|
"unplugin-unused": "0.5.6",
|
|
62
|
-
"vitest": "4.0.
|
|
62
|
+
"vitest": "4.0.15"
|
|
63
63
|
},
|
|
64
64
|
"dependencies": {
|
|
65
|
-
"@anthropic-ai/claude-agent-sdk": "0.1.
|
|
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": "
|
|
72
|
-
"format:check": "
|
|
71
|
+
"format": "oxfmt",
|
|
72
|
+
"format:check": "oxfmt --check",
|
|
73
73
|
"typecheck": "tsgo --noEmit",
|
|
74
74
|
"test": "vitest --run",
|
|
75
75
|
"build": "tsdown",
|