@goodfoot/claude-code-hooks 1.0.1

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.
@@ -0,0 +1,601 @@
1
+ /**
2
+ * Input types for Claude Code hooks using wire format (snake_case).
3
+ *
4
+ * These types match the JSON format that Claude Code sends via stdin. Property names
5
+ * use snake_case to match the wire protocol directly without transformation overhead.
6
+ * Each hook input type includes comprehensive JSDoc documentation explaining when
7
+ * the hook fires and how to use it.
8
+ * @see https://code.claude.com/docs/en/hooks
9
+ * @module
10
+ */
11
+ import type { PermissionUpdate } from '@anthropic-ai/claude-agent-sdk/entrypoints/agentSdkTypes.js';
12
+ /**
13
+ * Permission mode for controlling how tool executions are handled.
14
+ * @see https://code.claude.com/docs/en/hooks#permission-modes
15
+ */
16
+ export type PermissionMode = 'default' | 'acceptEdits' | 'bypassPermissions' | 'plan' | 'delegate' | 'dontAsk';
17
+ /**
18
+ * Source that triggered a session start event.
19
+ *
20
+ * - `'startup'` - New session started from scratch
21
+ * - `'resume'` - Resuming a previous session
22
+ * - `'clear'` - Session cleared and restarted
23
+ * - `'compact'` - Session restarted after context compaction
24
+ */
25
+ export type SessionStartSource = 'startup' | 'resume' | 'clear' | 'compact';
26
+ /**
27
+ * Trigger type for pre-compact events.
28
+ *
29
+ * - `'manual'` - User explicitly requested compaction
30
+ * - `'auto'` - Automatic compaction due to context length
31
+ */
32
+ export type PreCompactTrigger = 'manual' | 'auto';
33
+ /**
34
+ * Reason for session end events.
35
+ *
36
+ * - `'clear'` - Session cleared by user
37
+ * - `'logout'` - User logged out
38
+ * - `'prompt_input_exit'` - User exited at prompt input
39
+ * - `'other'` - Other reasons
40
+ */
41
+ export type SessionEndReason = 'clear' | 'logout' | 'prompt_input_exit' | 'other';
42
+ /**
43
+ * Common fields present in all hook inputs.
44
+ *
45
+ * Every hook receives these base fields providing session context.
46
+ * Hook-specific inputs extend this base with additional fields.
47
+ * @example
48
+ * ```typescript
49
+ * // All hook inputs include these fields
50
+ * const handleAnyHook = (input: BaseHookInput) => {
51
+ * console.log(`Session: ${input.session_id}`);
52
+ * console.log(`Working directory: ${input.cwd}`);
53
+ * console.log(`Transcript: ${input.transcript_path}`);
54
+ * };
55
+ * ```
56
+ * @see https://code.claude.com/docs/en/hooks#hook-input-structure
57
+ */
58
+ export interface BaseHookInput {
59
+ /**
60
+ * Unique identifier for the current Claude Code session.
61
+ * Persists across conversation turns within the same session.
62
+ */
63
+ session_id: string;
64
+ /**
65
+ * Absolute path to the session transcript file.
66
+ * Contains the full conversation history in JSONL format.
67
+ */
68
+ transcript_path: string;
69
+ /**
70
+ * Current working directory for the Claude Code session.
71
+ * All file operations are relative to this directory.
72
+ */
73
+ cwd: string;
74
+ /**
75
+ * Current permission mode for tool execution.
76
+ * May be undefined if using default mode.
77
+ */
78
+ permission_mode?: PermissionMode;
79
+ }
80
+ /**
81
+ * Input for PreToolUse hooks.
82
+ *
83
+ * Fires before any tool is executed, allowing you to:
84
+ * - Inspect and validate tool inputs
85
+ * - Allow, deny, or modify the tool execution
86
+ * - Add custom permission logic
87
+ *
88
+ * This hook uses `tool_name` for matcher matching.
89
+ * @example
90
+ * ```typescript
91
+ * // Block dangerous Bash commands
92
+ * preToolUseHook({ matcher: 'Bash' }, async (input: PreToolUseInput) => {
93
+ * const command = input.tool_input.command as string;
94
+ * if (command.includes('rm -rf')) {
95
+ * return preToolUseOutput({
96
+ * deny: 'Destructive commands are not allowed'
97
+ * });
98
+ * }
99
+ * return preToolUseOutput({ allow: true });
100
+ * });
101
+ * ```
102
+ * @see https://code.claude.com/docs/en/hooks#pretooluse
103
+ */
104
+ export interface PreToolUseInput extends BaseHookInput {
105
+ /** Discriminator for hook event type. */
106
+ hook_event_name: 'PreToolUse';
107
+ /**
108
+ * Name of the tool being invoked.
109
+ * Examples: 'Bash', 'Read', 'Edit', 'Write', 'Glob', 'Grep'
110
+ */
111
+ tool_name: string;
112
+ /**
113
+ * Input parameters being passed to the tool.
114
+ * Structure varies by tool type.
115
+ */
116
+ tool_input: unknown;
117
+ /**
118
+ * Unique identifier for this specific tool invocation.
119
+ * Use this to correlate with PostToolUse events.
120
+ */
121
+ tool_use_id: string;
122
+ }
123
+ /**
124
+ * Input for PostToolUse hooks.
125
+ *
126
+ * Fires after a tool executes successfully, allowing you to:
127
+ * - Inspect tool results
128
+ * - Add additional context to the conversation
129
+ * - Modify MCP tool output
130
+ *
131
+ * This hook uses `tool_name` for matcher matching.
132
+ * @example
133
+ * ```typescript
134
+ * // Add context after file reads
135
+ * postToolUseHook({ matcher: 'Read' }, async (input: PostToolUseInput) => {
136
+ * const filePath = input.tool_input.file_path as string;
137
+ * return postToolUseOutput({
138
+ * additionalContext: `File ${filePath} was read successfully`
139
+ * });
140
+ * });
141
+ * ```
142
+ * @see https://code.claude.com/docs/en/hooks#posttooluse
143
+ */
144
+ export interface PostToolUseInput extends BaseHookInput {
145
+ /** Discriminator for hook event type. */
146
+ hook_event_name: 'PostToolUse';
147
+ /**
148
+ * Name of the tool that was invoked.
149
+ */
150
+ tool_name: string;
151
+ /**
152
+ * Input parameters that were passed to the tool.
153
+ */
154
+ tool_input: unknown;
155
+ /**
156
+ * Response returned by the tool.
157
+ * Structure varies by tool type.
158
+ */
159
+ tool_response: unknown;
160
+ /**
161
+ * Unique identifier for this tool invocation.
162
+ * Matches the tool_use_id from the corresponding PreToolUse event.
163
+ */
164
+ tool_use_id: string;
165
+ }
166
+ /**
167
+ * Input for PostToolUseFailure hooks.
168
+ *
169
+ * Fires after a tool execution fails, allowing you to:
170
+ * - Log or report tool failures
171
+ * - Add context about the failure
172
+ * - Take corrective action
173
+ *
174
+ * This hook uses `tool_name` for matcher matching.
175
+ * @example
176
+ * ```typescript
177
+ * // Log tool failures
178
+ * postToolUseFailureHook({ matcher: '.*' }, async (input: PostToolUseFailureInput) => {
179
+ * console.error(`Tool ${input.tool_name} failed: ${input.error}`);
180
+ * return postToolUseFailureOutput({
181
+ * additionalContext: 'Please try an alternative approach'
182
+ * });
183
+ * });
184
+ * ```
185
+ * @see https://code.claude.com/docs/en/hooks#posttoolusefailure
186
+ */
187
+ export interface PostToolUseFailureInput extends BaseHookInput {
188
+ /** Discriminator for hook event type. */
189
+ hook_event_name: 'PostToolUseFailure';
190
+ /**
191
+ * Name of the tool that failed.
192
+ */
193
+ tool_name: string;
194
+ /**
195
+ * Input parameters that were passed to the tool.
196
+ */
197
+ tool_input: unknown;
198
+ /**
199
+ * Unique identifier for this tool invocation.
200
+ */
201
+ tool_use_id: string;
202
+ /**
203
+ * Error message describing why the tool failed.
204
+ */
205
+ error: string;
206
+ /**
207
+ * Whether this failure was caused by a user interrupt.
208
+ */
209
+ is_interrupt?: boolean;
210
+ }
211
+ /**
212
+ * Input for Notification hooks.
213
+ *
214
+ * Fires when Claude Code sends a notification, allowing you to:
215
+ * - Forward notifications to external systems
216
+ * - Log important events
217
+ * - Trigger custom alerting
218
+ *
219
+ * This hook uses `notification_type` for matcher matching.
220
+ * @example
221
+ * ```typescript
222
+ * // Forward notifications to Slack
223
+ * notificationHook({}, async (input: NotificationInput) => {
224
+ * await sendSlackMessage(input.title, input.message);
225
+ * return notificationOutput({});
226
+ * });
227
+ * ```
228
+ * @see https://code.claude.com/docs/en/hooks#notification
229
+ */
230
+ export interface NotificationInput extends BaseHookInput {
231
+ /** Discriminator for hook event type. */
232
+ hook_event_name: 'Notification';
233
+ /**
234
+ * Main content of the notification.
235
+ */
236
+ message: string;
237
+ /**
238
+ * Optional title for the notification.
239
+ */
240
+ title?: string;
241
+ /**
242
+ * Type/category of the notification.
243
+ */
244
+ notification_type: string;
245
+ }
246
+ /**
247
+ * Input for UserPromptSubmit hooks.
248
+ *
249
+ * Fires when a user submits a prompt, allowing you to:
250
+ * - Add additional context or instructions
251
+ * - Log user interactions
252
+ * - Validate or transform prompts
253
+ *
254
+ * This hook does not support matchers; it fires on all prompt submissions.
255
+ * @example
256
+ * ```typescript
257
+ * // Add project context to every prompt
258
+ * userPromptSubmitHook({}, async (input: UserPromptSubmitInput) => {
259
+ * return userPromptSubmitOutput({
260
+ * additionalContext: await getProjectContext()
261
+ * });
262
+ * });
263
+ * ```
264
+ * @see https://code.claude.com/docs/en/hooks#userpromptsubmit
265
+ */
266
+ export interface UserPromptSubmitInput extends BaseHookInput {
267
+ /** Discriminator for hook event type. */
268
+ hook_event_name: 'UserPromptSubmit';
269
+ /**
270
+ * The prompt text submitted by the user.
271
+ */
272
+ prompt: string;
273
+ }
274
+ /**
275
+ * Input for SessionStart hooks.
276
+ *
277
+ * Fires when a Claude Code session starts or restarts, allowing you to:
278
+ * - Initialize session state
279
+ * - Inject context or instructions
280
+ * - Set up logging or monitoring
281
+ *
282
+ * This hook uses `source` for matcher matching.
283
+ * @example
284
+ * ```typescript
285
+ * // Initialize context for new sessions
286
+ * sessionStartHook({ matcher: 'startup' }, async (input: SessionStartInput) => {
287
+ * return sessionStartOutput({
288
+ * additionalContext: JSON.stringify({
289
+ * project: 'my-project',
290
+ * initialized: true
291
+ * })
292
+ * });
293
+ * });
294
+ * ```
295
+ * @see https://code.claude.com/docs/en/hooks#sessionstart
296
+ */
297
+ export interface SessionStartInput extends BaseHookInput {
298
+ /** Discriminator for hook event type. */
299
+ hook_event_name: 'SessionStart';
300
+ /**
301
+ * How the session was started.
302
+ *
303
+ * - `'startup'` - New session started from scratch
304
+ * - `'resume'` - Resuming a previous session
305
+ * - `'clear'` - Session cleared and restarted
306
+ * - `'compact'` - Session restarted after context compaction
307
+ */
308
+ source: SessionStartSource;
309
+ }
310
+ /**
311
+ * Input for SessionEnd hooks.
312
+ *
313
+ * Fires when a Claude Code session ends, allowing you to:
314
+ * - Clean up session resources
315
+ * - Log session metrics
316
+ * - Persist session state
317
+ *
318
+ * This hook uses `reason` for matcher matching.
319
+ * @example
320
+ * ```typescript
321
+ * // Log session end
322
+ * sessionEndHook({}, async (input: SessionEndInput) => {
323
+ * console.log(`Session ended: ${input.reason}`);
324
+ * return sessionEndOutput({});
325
+ * });
326
+ * ```
327
+ * @see https://code.claude.com/docs/en/hooks#sessionend
328
+ */
329
+ export interface SessionEndInput extends BaseHookInput {
330
+ /** Discriminator for hook event type. */
331
+ hook_event_name: 'SessionEnd';
332
+ /**
333
+ * The reason the session ended.
334
+ *
335
+ * - `'clear'` - Session cleared by user
336
+ * - `'logout'` - User logged out
337
+ * - `'prompt_input_exit'` - User exited at prompt input
338
+ * - `'other'` - Other reasons
339
+ */
340
+ reason: SessionEndReason;
341
+ }
342
+ /**
343
+ * Input for Stop hooks.
344
+ *
345
+ * Fires when Claude Code is about to stop, allowing you to:
346
+ * - Block the stop and require additional action
347
+ * - Confirm the user wants to stop
348
+ * - Clean up resources before stopping
349
+ *
350
+ * This hook does not support matchers; it fires on all stop events.
351
+ * @example
352
+ * ```typescript
353
+ * // Require confirmation before stopping with pending changes
354
+ * stopHook({}, async (input: StopInput) => {
355
+ * const pendingChanges = await checkPendingChanges();
356
+ * if (pendingChanges.length > 0) {
357
+ * return stopOutput({
358
+ * decision: 'block',
359
+ * reason: 'There are uncommitted changes'
360
+ * });
361
+ * }
362
+ * return stopOutput({ decision: 'approve' });
363
+ * });
364
+ * ```
365
+ * @see https://code.claude.com/docs/en/hooks#stop
366
+ */
367
+ export interface StopInput extends BaseHookInput {
368
+ /** Discriminator for hook event type. */
369
+ hook_event_name: 'Stop';
370
+ /**
371
+ * Whether a stop hook is currently active.
372
+ * Used to prevent recursive stop hook invocations.
373
+ */
374
+ stop_hook_active: boolean;
375
+ }
376
+ /**
377
+ * Input for SubagentStart hooks.
378
+ *
379
+ * Fires when a subagent (Task tool) starts, allowing you to:
380
+ * - Inject context for the subagent
381
+ * - Log subagent invocations
382
+ * - Configure subagent behavior
383
+ *
384
+ * This hook uses `agent_type` for matcher matching.
385
+ * @example
386
+ * ```typescript
387
+ * // Add context for explore subagents
388
+ * subagentStartHook({ matcher: 'explore' }, async (input: SubagentStartInput) => {
389
+ * return subagentStartOutput({
390
+ * additionalContext: 'Focus on finding patterns and conventions'
391
+ * });
392
+ * });
393
+ * ```
394
+ * @see https://code.claude.com/docs/en/hooks#subagentstart
395
+ */
396
+ export interface SubagentStartInput extends BaseHookInput {
397
+ /** Discriminator for hook event type. */
398
+ hook_event_name: 'SubagentStart';
399
+ /**
400
+ * Unique identifier for the subagent instance.
401
+ */
402
+ agent_id: string;
403
+ /**
404
+ * Type of subagent being started.
405
+ * Examples: 'explore', 'codebase-analysis', custom agent types
406
+ */
407
+ agent_type: string;
408
+ }
409
+ /**
410
+ * Input for SubagentStop hooks.
411
+ *
412
+ * Fires when a subagent completes or stops, allowing you to:
413
+ * - Process subagent results
414
+ * - Clean up subagent resources
415
+ * - Log subagent completion
416
+ * - Block subagent from stopping
417
+ *
418
+ * This hook uses `agent_type` for matcher matching.
419
+ * @example
420
+ * ```typescript
421
+ * // Block explore subagent if task incomplete
422
+ * subagentStopHook({ matcher: 'explore' }, async (input: SubagentStopInput) => {
423
+ * console.log(`Subagent ${input.agent_id} (${input.agent_type}) stopping`);
424
+ * return subagentStopOutput({
425
+ * decision: 'block',
426
+ * reason: 'Please verify all files were explored'
427
+ * });
428
+ * });
429
+ * ```
430
+ * @see https://code.claude.com/docs/en/hooks#subagentstop
431
+ */
432
+ export interface SubagentStopInput extends BaseHookInput {
433
+ /** Discriminator for hook event type. */
434
+ hook_event_name: 'SubagentStop';
435
+ /**
436
+ * Whether a stop hook is currently active.
437
+ */
438
+ stop_hook_active: boolean;
439
+ /**
440
+ * Unique identifier for the subagent instance.
441
+ */
442
+ agent_id: string;
443
+ /**
444
+ * Type of subagent that is stopping.
445
+ * Examples: 'explore', 'codebase-analysis', custom agent types
446
+ */
447
+ agent_type: string;
448
+ /**
449
+ * Path to the subagent's transcript file.
450
+ */
451
+ agent_transcript_path: string;
452
+ }
453
+ /**
454
+ * Input for PreCompact hooks.
455
+ *
456
+ * Fires before context compaction occurs, allowing you to:
457
+ * - Preserve important information before compaction
458
+ * - Log compaction events
459
+ * - Modify custom instructions for the compacted context
460
+ *
461
+ * This hook uses `trigger` for matcher matching.
462
+ * @example
463
+ * ```typescript
464
+ * // Log compaction events
465
+ * preCompactHook({}, async (input: PreCompactInput) => {
466
+ * console.log(`Compacting (${input.trigger})`);
467
+ * return preCompactOutput({});
468
+ * });
469
+ * ```
470
+ * @see https://code.claude.com/docs/en/hooks#precompact
471
+ */
472
+ export interface PreCompactInput extends BaseHookInput {
473
+ /** Discriminator for hook event type. */
474
+ hook_event_name: 'PreCompact';
475
+ /**
476
+ * What triggered the compaction.
477
+ *
478
+ * - `'manual'` - User explicitly requested compaction
479
+ * - `'auto'` - Automatic compaction due to context length
480
+ */
481
+ trigger: PreCompactTrigger;
482
+ /**
483
+ * Custom instructions to include in the compacted context.
484
+ * May be null if no custom instructions are set.
485
+ */
486
+ custom_instructions: string | null;
487
+ }
488
+ /**
489
+ * Input for PermissionRequest hooks.
490
+ *
491
+ * Fires when a permission prompt would be shown, allowing you to:
492
+ * - Auto-approve or deny tool executions
493
+ * - Implement custom permission logic
494
+ * - Modify tool inputs before approval
495
+ *
496
+ * This hook uses `tool_name` for matcher matching.
497
+ * @example
498
+ * ```typescript
499
+ * // Auto-approve read operations in allowed directories
500
+ * permissionRequestHook({ matcher: 'Read' }, async (input: PermissionRequestInput) => {
501
+ * const filePath = input.tool_input.file_path as string;
502
+ * if (filePath.startsWith('/allowed/')) {
503
+ * return permissionRequestOutput({
504
+ * allow: true
505
+ * });
506
+ * }
507
+ * return permissionRequestOutput({}); // Fall through to normal permission prompt
508
+ * });
509
+ * ```
510
+ * @see https://code.claude.com/docs/en/hooks#permissionrequest
511
+ */
512
+ export interface PermissionRequestInput extends BaseHookInput {
513
+ /** Discriminator for hook event type. */
514
+ hook_event_name: 'PermissionRequest';
515
+ /**
516
+ * Name of the tool requesting permission.
517
+ */
518
+ tool_name: string;
519
+ /**
520
+ * Input parameters for the tool.
521
+ */
522
+ tool_input: unknown;
523
+ /**
524
+ * Unique identifier for this specific tool invocation.
525
+ */
526
+ tool_use_id: string;
527
+ /**
528
+ * Suggested permission updates that would prevent future prompts.
529
+ * Typically used for "always allow" functionality.
530
+ */
531
+ permission_suggestions?: PermissionUpdate[];
532
+ }
533
+ /**
534
+ * Discriminated union of all hook input types.
535
+ *
536
+ * Use this type when handling multiple hook types in a single handler
537
+ * or when the hook type is not known statically.
538
+ * @example
539
+ * ```typescript
540
+ * // Handle any hook type with type narrowing
541
+ * function handleHook(input: HookInput) {
542
+ * switch (input.hook_event_name) {
543
+ * case 'PreToolUse':
544
+ * // TypeScript knows input is PreToolUseInput here
545
+ * console.log(`Tool: ${input.tool_name}`);
546
+ * break;
547
+ * case 'SessionStart':
548
+ * // TypeScript knows input is SessionStartInput here
549
+ * console.log(`Source: ${input.source}`);
550
+ * break;
551
+ * // ... handle other hook types
552
+ * }
553
+ * }
554
+ * ```
555
+ * @see https://code.claude.com/docs/en/hooks
556
+ */
557
+ export type HookInput =
558
+ | PreToolUseInput
559
+ | PostToolUseInput
560
+ | PostToolUseFailureInput
561
+ | NotificationInput
562
+ | UserPromptSubmitInput
563
+ | SessionStartInput
564
+ | SessionEndInput
565
+ | StopInput
566
+ | SubagentStartInput
567
+ | SubagentStopInput
568
+ | PreCompactInput
569
+ | PermissionRequestInput;
570
+ /**
571
+ * Hook event name literal union.
572
+ *
573
+ * All valid hook event names that can appear in the `hook_event_name` field.
574
+ */
575
+ export type HookEventName = HookInput['hook_event_name'];
576
+ /**
577
+ * All hook event names as a readonly array.
578
+ *
579
+ * Useful for iteration and validation.
580
+ * @example
581
+ * ```typescript
582
+ * for (const eventName of HOOK_EVENT_NAMES) {
583
+ * console.log(`Supported hook: ${eventName}`);
584
+ * }
585
+ * ```
586
+ */
587
+ export declare const HOOK_EVENT_NAMES: readonly [
588
+ 'PreToolUse',
589
+ 'PostToolUse',
590
+ 'PostToolUseFailure',
591
+ 'Notification',
592
+ 'UserPromptSubmit',
593
+ 'SessionStart',
594
+ 'SessionEnd',
595
+ 'Stop',
596
+ 'SubagentStart',
597
+ 'SubagentStop',
598
+ 'PreCompact',
599
+ 'PermissionRequest'
600
+ ];
601
+ export type { PermissionUpdate };