@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.
- package/LICENSE +21 -0
- package/README.md +317 -0
- package/dist/cli.js +914 -0
- package/dist/constants.js +21 -0
- package/dist/env.js +188 -0
- package/dist/hooks.js +391 -0
- package/dist/index.js +77 -0
- package/dist/inputs.js +35 -0
- package/dist/logger.js +494 -0
- package/dist/outputs.js +282 -0
- package/dist/runtime.js +222 -0
- package/dist/scaffold.js +466 -0
- package/dist/tool-helpers.js +366 -0
- package/dist/tool-inputs.js +21 -0
- package/package.json +68 -0
- package/types/cli.d.ts +281 -0
- package/types/constants.d.ts +9 -0
- package/types/env.d.ts +150 -0
- package/types/hooks.d.ts +851 -0
- package/types/index.d.ts +137 -0
- package/types/inputs.d.ts +601 -0
- package/types/logger.d.ts +471 -0
- package/types/outputs.d.ts +643 -0
- package/types/runtime.d.ts +75 -0
- package/types/scaffold.d.ts +46 -0
- package/types/tool-helpers.d.ts +336 -0
- package/types/tool-inputs.d.ts +228 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared constants for the CLI and scaffold modules.
|
|
3
|
+
* @module
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Maps hook factory function names to their event names.
|
|
7
|
+
*/
|
|
8
|
+
export const HOOK_FACTORY_TO_EVENT = {
|
|
9
|
+
preToolUseHook: 'PreToolUse',
|
|
10
|
+
postToolUseHook: 'PostToolUse',
|
|
11
|
+
postToolUseFailureHook: 'PostToolUseFailure',
|
|
12
|
+
notificationHook: 'Notification',
|
|
13
|
+
userPromptSubmitHook: 'UserPromptSubmit',
|
|
14
|
+
sessionStartHook: 'SessionStart',
|
|
15
|
+
sessionEndHook: 'SessionEnd',
|
|
16
|
+
stopHook: 'Stop',
|
|
17
|
+
subagentStartHook: 'SubagentStart',
|
|
18
|
+
subagentStopHook: 'SubagentStop',
|
|
19
|
+
preCompactHook: 'PreCompact',
|
|
20
|
+
permissionRequestHook: 'PermissionRequest'
|
|
21
|
+
};
|
package/dist/env.js
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment variable utilities for Claude Code hooks.
|
|
3
|
+
*
|
|
4
|
+
* Provides typed access to Claude Code's environment variables and utilities
|
|
5
|
+
* for persisting environment variables in SessionStart hooks.
|
|
6
|
+
*
|
|
7
|
+
* ## Environment Variables
|
|
8
|
+
*
|
|
9
|
+
* Claude Code sets these environment variables when running hooks:
|
|
10
|
+
*
|
|
11
|
+
* | Variable | Description | Available In |
|
|
12
|
+
* |----------|-------------|--------------|
|
|
13
|
+
* | `CLAUDE_PROJECT_DIR` | Absolute path to project root | All hooks |
|
|
14
|
+
* | `CLAUDE_ENV_FILE` | Path to file for persisting env vars | SessionStart only |
|
|
15
|
+
* | `CLAUDE_CODE_REMOTE` | `"true"` if running remotely | All hooks |
|
|
16
|
+
* @module
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* import { getProjectDir, persistEnvVar, isRemoteEnvironment } from '@goodfoot/claude-code-hooks';
|
|
20
|
+
*
|
|
21
|
+
* // Get project directory
|
|
22
|
+
* const projectDir = getProjectDir();
|
|
23
|
+
*
|
|
24
|
+
* // Check if running remotely
|
|
25
|
+
* if (isRemoteEnvironment()) {
|
|
26
|
+
* // Handle remote-specific logic
|
|
27
|
+
* }
|
|
28
|
+
*
|
|
29
|
+
* // In SessionStart hook: persist environment variables
|
|
30
|
+
* persistEnvVar('NODE_ENV', 'production');
|
|
31
|
+
* persistEnvVar('API_KEY', 'secret-key');
|
|
32
|
+
* ```
|
|
33
|
+
* @see https://code.claude.com/docs/en/hooks#hook-execution-details
|
|
34
|
+
*/
|
|
35
|
+
import * as fs from 'node:fs';
|
|
36
|
+
/**
|
|
37
|
+
* Claude Code environment variable names.
|
|
38
|
+
*
|
|
39
|
+
* These are the environment variables that Claude Code sets when running hooks.
|
|
40
|
+
*/
|
|
41
|
+
export const CLAUDE_ENV_VARS = {
|
|
42
|
+
/**
|
|
43
|
+
* Absolute path to the project root directory where Claude Code was started.
|
|
44
|
+
* Available in all hooks.
|
|
45
|
+
*/
|
|
46
|
+
PROJECT_DIR: 'CLAUDE_PROJECT_DIR',
|
|
47
|
+
/**
|
|
48
|
+
* Path to a file where SessionStart hooks can persist environment variables.
|
|
49
|
+
* Variables written to this file will be available in all subsequent bash commands.
|
|
50
|
+
* Only available in SessionStart hooks.
|
|
51
|
+
*/
|
|
52
|
+
ENV_FILE: 'CLAUDE_ENV_FILE',
|
|
53
|
+
/**
|
|
54
|
+
* Set to "true" when running in a remote (web) environment.
|
|
55
|
+
* Not set or empty when running in local CLI environment.
|
|
56
|
+
*/
|
|
57
|
+
REMOTE: 'CLAUDE_CODE_REMOTE'
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Gets the Claude Code project directory.
|
|
61
|
+
*
|
|
62
|
+
* This is the absolute path to the project root where Claude Code was started.
|
|
63
|
+
* The value comes from the `CLAUDE_PROJECT_DIR` environment variable.
|
|
64
|
+
* @returns The project directory path, or undefined if not set
|
|
65
|
+
* @example
|
|
66
|
+
* ```typescript
|
|
67
|
+
* const projectDir = getProjectDir();
|
|
68
|
+
* if (projectDir) {
|
|
69
|
+
* const configPath = `${projectDir}/.claude/config.json`;
|
|
70
|
+
* }
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
export function getProjectDir() {
|
|
74
|
+
return process.env[CLAUDE_ENV_VARS.PROJECT_DIR];
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Gets the Claude Code env file path for persisting environment variables.
|
|
78
|
+
*
|
|
79
|
+
* This is only available in SessionStart hooks. The path points to a file
|
|
80
|
+
* where you can write shell export statements to persist environment variables
|
|
81
|
+
* for all subsequent bash commands in the session.
|
|
82
|
+
* @returns The env file path, or undefined if not set (not a SessionStart hook)
|
|
83
|
+
* @example
|
|
84
|
+
* ```typescript
|
|
85
|
+
* const envFile = getEnvFilePath();
|
|
86
|
+
* if (envFile) {
|
|
87
|
+
* // We're in a SessionStart hook and can persist env vars
|
|
88
|
+
* persistEnvVar('MY_VAR', 'my-value');
|
|
89
|
+
* }
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
export function getEnvFilePath() {
|
|
93
|
+
return process.env[CLAUDE_ENV_VARS.ENV_FILE];
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Checks if the hook is running in a remote (web) environment.
|
|
97
|
+
*
|
|
98
|
+
* Remote environments may have different capabilities or restrictions
|
|
99
|
+
* compared to local CLI environments.
|
|
100
|
+
* @returns true if running remotely, false if running locally
|
|
101
|
+
* @example
|
|
102
|
+
* ```typescript
|
|
103
|
+
* if (isRemoteEnvironment()) {
|
|
104
|
+
* // Use web-compatible approaches
|
|
105
|
+
* } else {
|
|
106
|
+
* // Can use local CLI features
|
|
107
|
+
* }
|
|
108
|
+
* ```
|
|
109
|
+
*/
|
|
110
|
+
export function isRemoteEnvironment() {
|
|
111
|
+
return process.env[CLAUDE_ENV_VARS.REMOTE] === 'true';
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Persists an environment variable for use in subsequent bash commands.
|
|
115
|
+
*
|
|
116
|
+
* This function writes a shell export statement to the `CLAUDE_ENV_FILE`,
|
|
117
|
+
* which Claude Code sources before running bash commands. This allows
|
|
118
|
+
* SessionStart hooks to configure the environment for the entire session.
|
|
119
|
+
*
|
|
120
|
+
* **Important**: This function only works in SessionStart hooks where
|
|
121
|
+
* `CLAUDE_ENV_FILE` is set. In other hooks, it will throw an error.
|
|
122
|
+
* @param name - The environment variable name
|
|
123
|
+
* @param value - The environment variable value (will be shell-escaped)
|
|
124
|
+
* @throws Error if CLAUDE_ENV_FILE is not set (not in a SessionStart hook)
|
|
125
|
+
* @example
|
|
126
|
+
* ```typescript
|
|
127
|
+
* import { sessionStartHook, sessionStartOutput, persistEnvVar } from '@goodfoot/claude-code-hooks';
|
|
128
|
+
*
|
|
129
|
+
* export default sessionStartHook({}, async (input) => {
|
|
130
|
+
* // Persist environment variables for the session
|
|
131
|
+
* persistEnvVar('NODE_ENV', 'production');
|
|
132
|
+
* persistEnvVar('API_KEY', process.env.MY_API_KEY ?? 'default');
|
|
133
|
+
* persistEnvVar('PATH', `${process.env.PATH}:./node_modules/.bin`);
|
|
134
|
+
*
|
|
135
|
+
* return sessionStartOutput({});
|
|
136
|
+
* });
|
|
137
|
+
* ```
|
|
138
|
+
* @see https://code.claude.com/docs/en/hooks#persisting-environment-variables
|
|
139
|
+
*/
|
|
140
|
+
export function persistEnvVar(name, value) {
|
|
141
|
+
const envFile = getEnvFilePath();
|
|
142
|
+
if (envFile === undefined) {
|
|
143
|
+
throw new Error(
|
|
144
|
+
'persistEnvVar can only be used in SessionStart hooks. ' + 'CLAUDE_ENV_FILE environment variable is not set.'
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
// Shell-escape the value to handle special characters
|
|
148
|
+
const escapedValue = escapeShellValue(value);
|
|
149
|
+
// Write the export statement
|
|
150
|
+
const exportStatement = `export ${name}=${escapedValue}\n`;
|
|
151
|
+
fs.appendFileSync(envFile, exportStatement, 'utf-8');
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Persists multiple environment variables at once.
|
|
155
|
+
*
|
|
156
|
+
* This is a convenience wrapper around `persistEnvVar` for setting
|
|
157
|
+
* multiple variables in a single call.
|
|
158
|
+
* @param vars - Object mapping variable names to values
|
|
159
|
+
* @throws Error if CLAUDE_ENV_FILE is not set (not in a SessionStart hook)
|
|
160
|
+
* @example
|
|
161
|
+
* ```typescript
|
|
162
|
+
* persistEnvVars({
|
|
163
|
+
* NODE_ENV: 'production',
|
|
164
|
+
* API_KEY: 'secret',
|
|
165
|
+
* DEBUG: 'false'
|
|
166
|
+
* });
|
|
167
|
+
* ```
|
|
168
|
+
*/
|
|
169
|
+
export function persistEnvVars(vars) {
|
|
170
|
+
for (const [name, value] of Object.entries(vars)) {
|
|
171
|
+
persistEnvVar(name, value);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Escapes a value for safe use in a shell export statement.
|
|
176
|
+
*
|
|
177
|
+
* Uses single quotes and escapes any embedded single quotes.
|
|
178
|
+
* This prevents shell injection and handles special characters.
|
|
179
|
+
* @param value - The value to escape
|
|
180
|
+
* @returns The shell-escaped value (with quotes)
|
|
181
|
+
* @internal
|
|
182
|
+
*/
|
|
183
|
+
function escapeShellValue(value) {
|
|
184
|
+
// Use single quotes and escape any embedded single quotes
|
|
185
|
+
// 'value' -> 'val'\''ue' for values containing single quotes
|
|
186
|
+
const escaped = value.replace(/'/g, "'\\''");
|
|
187
|
+
return `'${escaped}'`;
|
|
188
|
+
}
|
package/dist/hooks.js
ADDED
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook factory functions for Claude Code hooks.
|
|
3
|
+
*
|
|
4
|
+
* Provides typed factory functions for all 12 hook types that handle:
|
|
5
|
+
* - Input type narrowing based on hook event type
|
|
6
|
+
* - Output type enforcement via return types
|
|
7
|
+
* - Error wrapping with automatic logging
|
|
8
|
+
* - Logger context injection
|
|
9
|
+
*
|
|
10
|
+
* Each factory accepts a HookConfig with optional matcher and timeout settings,
|
|
11
|
+
* and returns a function that the runtime invokes when the hook file executes.
|
|
12
|
+
* @module
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* import { preToolUseHook, preToolUseOutput } from '@goodfoot/claude-code-hooks';
|
|
16
|
+
*
|
|
17
|
+
* export default preToolUseHook({ matcher: 'Bash' }, async (input, { logger }) => {
|
|
18
|
+
* logger.info('Processing Bash command');
|
|
19
|
+
* return preToolUseOutput({ allow: true });
|
|
20
|
+
* });
|
|
21
|
+
* ```
|
|
22
|
+
* @see https://code.claude.com/docs/en/hooks
|
|
23
|
+
*/
|
|
24
|
+
// ============================================================================
|
|
25
|
+
// Generic Factory
|
|
26
|
+
// ============================================================================
|
|
27
|
+
/**
|
|
28
|
+
* Creates a hook factory function for a specific hook type.
|
|
29
|
+
*
|
|
30
|
+
* This is the internal implementation used by all typed factories.
|
|
31
|
+
* It wraps the handler with error catching and logging.
|
|
32
|
+
* @param hookEventName - The hook event name
|
|
33
|
+
* @param config - Hook configuration
|
|
34
|
+
* @param handler - The handler function to wrap
|
|
35
|
+
* @returns A wrapped hook function
|
|
36
|
+
* @internal
|
|
37
|
+
*/
|
|
38
|
+
function createHookFunction(hookEventName, config, handler) {
|
|
39
|
+
const hookFn = async (input, context) => {
|
|
40
|
+
// Delegate error handling to the runtime - just execute the handler
|
|
41
|
+
// The runtime will catch errors, log them, and return appropriate output
|
|
42
|
+
return await handler(input, context);
|
|
43
|
+
};
|
|
44
|
+
// Attach metadata for runtime inspection
|
|
45
|
+
hookFn.hookEventName = hookEventName;
|
|
46
|
+
hookFn.matcher = config.matcher;
|
|
47
|
+
hookFn.timeout = config.timeout;
|
|
48
|
+
return hookFn;
|
|
49
|
+
}
|
|
50
|
+
/** @inheritdoc */
|
|
51
|
+
export function preToolUseHook(config, handler) {
|
|
52
|
+
return createHookFunction('PreToolUse', config, handler);
|
|
53
|
+
}
|
|
54
|
+
/** @inheritdoc */
|
|
55
|
+
export function postToolUseHook(config, handler) {
|
|
56
|
+
return createHookFunction('PostToolUse', config, handler);
|
|
57
|
+
}
|
|
58
|
+
/** @inheritdoc */
|
|
59
|
+
export function postToolUseFailureHook(config, handler) {
|
|
60
|
+
return createHookFunction('PostToolUseFailure', config, handler);
|
|
61
|
+
}
|
|
62
|
+
// ============================================================================
|
|
63
|
+
// Notification Hook Factory
|
|
64
|
+
// ============================================================================
|
|
65
|
+
/**
|
|
66
|
+
* Creates a Notification hook handler.
|
|
67
|
+
*
|
|
68
|
+
* Notification hooks fire when Claude Code sends a notification, allowing you to:
|
|
69
|
+
* - Forward notifications to external systems
|
|
70
|
+
* - Log important events
|
|
71
|
+
* - Trigger custom alerting
|
|
72
|
+
*
|
|
73
|
+
* **Matcher**: Matches against `notification_type`
|
|
74
|
+
* @param config - Hook configuration with optional matcher and timeout
|
|
75
|
+
* @param handler - The handler function to execute
|
|
76
|
+
* @returns A hook function that can be exported as the default export
|
|
77
|
+
* @example
|
|
78
|
+
* ```typescript
|
|
79
|
+
* import { notificationHook, notificationOutput } from '@goodfoot/claude-code-hooks';
|
|
80
|
+
*
|
|
81
|
+
* // Forward notifications to Slack
|
|
82
|
+
* export default notificationHook({}, async (input, { logger }) => {
|
|
83
|
+
* logger.info('Notification received', {
|
|
84
|
+
* type: input.notification_type,
|
|
85
|
+
* title: input.title
|
|
86
|
+
* });
|
|
87
|
+
*
|
|
88
|
+
* await sendSlackMessage(input.title ?? 'Notification', input.message);
|
|
89
|
+
*
|
|
90
|
+
* return notificationOutput({});
|
|
91
|
+
* });
|
|
92
|
+
* ```
|
|
93
|
+
* @see https://code.claude.com/docs/en/hooks#notification
|
|
94
|
+
*/
|
|
95
|
+
export function notificationHook(config, handler) {
|
|
96
|
+
return createHookFunction('Notification', config, handler);
|
|
97
|
+
}
|
|
98
|
+
// ============================================================================
|
|
99
|
+
// UserPromptSubmit Hook Factory
|
|
100
|
+
// ============================================================================
|
|
101
|
+
/**
|
|
102
|
+
* Creates a UserPromptSubmit hook handler.
|
|
103
|
+
*
|
|
104
|
+
* UserPromptSubmit hooks fire when a user submits a prompt, allowing you to:
|
|
105
|
+
* - Add additional context or instructions
|
|
106
|
+
* - Log user interactions
|
|
107
|
+
* - Validate or transform prompts
|
|
108
|
+
*
|
|
109
|
+
* **Matcher**: No matcher support - fires on all prompt submissions
|
|
110
|
+
* @param config - Hook configuration with optional timeout (matcher is ignored)
|
|
111
|
+
* @param handler - The handler function to execute
|
|
112
|
+
* @returns A hook function that can be exported as the default export
|
|
113
|
+
* @example
|
|
114
|
+
* ```typescript
|
|
115
|
+
* import { userPromptSubmitHook, userPromptSubmitOutput } from '@goodfoot/claude-code-hooks';
|
|
116
|
+
*
|
|
117
|
+
* // Add project context to every prompt
|
|
118
|
+
* export default userPromptSubmitHook({}, async (input, { logger }) => {
|
|
119
|
+
* logger.debug('User prompt submitted', { promptLength: input.prompt.length });
|
|
120
|
+
*
|
|
121
|
+
* const projectContext = await getProjectContext();
|
|
122
|
+
*
|
|
123
|
+
* return userPromptSubmitOutput({
|
|
124
|
+
* additionalContext: projectContext
|
|
125
|
+
* });
|
|
126
|
+
* });
|
|
127
|
+
* ```
|
|
128
|
+
* @see https://code.claude.com/docs/en/hooks#userpromptsubmit
|
|
129
|
+
*/
|
|
130
|
+
export function userPromptSubmitHook(config, handler) {
|
|
131
|
+
return createHookFunction('UserPromptSubmit', config, handler);
|
|
132
|
+
}
|
|
133
|
+
// ============================================================================
|
|
134
|
+
// SessionStart Hook Factory
|
|
135
|
+
// ============================================================================
|
|
136
|
+
/**
|
|
137
|
+
* Creates a SessionStart hook handler.
|
|
138
|
+
*
|
|
139
|
+
* SessionStart hooks fire when a Claude Code session starts or restarts,
|
|
140
|
+
* allowing you to:
|
|
141
|
+
* - Initialize session state
|
|
142
|
+
* - Inject context or instructions
|
|
143
|
+
* - Persist environment variables for subsequent bash commands
|
|
144
|
+
* - Set up logging or monitoring
|
|
145
|
+
*
|
|
146
|
+
* **Matcher**: Matches against `source` ('startup', 'resume', 'clear', 'compact')
|
|
147
|
+
*
|
|
148
|
+
* **Context**: SessionStart hooks receive an extended context with `persistEnvVar`
|
|
149
|
+
* and `persistEnvVars` functions for setting environment variables.
|
|
150
|
+
* @param config - Hook configuration with optional matcher and timeout
|
|
151
|
+
* @param handler - The handler function to execute
|
|
152
|
+
* @returns A hook function that can be exported as the default export
|
|
153
|
+
* @example
|
|
154
|
+
* ```typescript
|
|
155
|
+
* import { sessionStartHook, sessionStartOutput } from '@goodfoot/claude-code-hooks';
|
|
156
|
+
*
|
|
157
|
+
* // Persist environment variables for the session
|
|
158
|
+
* export default sessionStartHook({ matcher: 'startup' }, async (input, { logger, persistEnvVar }) => {
|
|
159
|
+
* logger.info('New session started', {
|
|
160
|
+
* sessionId: input.session_id,
|
|
161
|
+
* cwd: input.cwd
|
|
162
|
+
* });
|
|
163
|
+
*
|
|
164
|
+
* // Set environment variables for all subsequent bash commands
|
|
165
|
+
* persistEnvVar('NODE_ENV', 'development');
|
|
166
|
+
* persistEnvVar('DEBUG', 'true');
|
|
167
|
+
*
|
|
168
|
+
* return sessionStartOutput({});
|
|
169
|
+
* });
|
|
170
|
+
* ```
|
|
171
|
+
* @example
|
|
172
|
+
* ```typescript
|
|
173
|
+
* // Set multiple environment variables at once
|
|
174
|
+
* export default sessionStartHook({}, async (input, { persistEnvVars }) => {
|
|
175
|
+
* persistEnvVars({
|
|
176
|
+
* NODE_ENV: 'production',
|
|
177
|
+
* API_KEY: 'secret',
|
|
178
|
+
* DEBUG: 'false'
|
|
179
|
+
* });
|
|
180
|
+
*
|
|
181
|
+
* return sessionStartOutput({});
|
|
182
|
+
* });
|
|
183
|
+
* ```
|
|
184
|
+
* @see https://code.claude.com/docs/en/hooks#sessionstart
|
|
185
|
+
*/
|
|
186
|
+
export function sessionStartHook(config, handler) {
|
|
187
|
+
return createHookFunction('SessionStart', config, handler);
|
|
188
|
+
}
|
|
189
|
+
// ============================================================================
|
|
190
|
+
// SessionEnd Hook Factory
|
|
191
|
+
// ============================================================================
|
|
192
|
+
/**
|
|
193
|
+
* Creates a SessionEnd hook handler.
|
|
194
|
+
*
|
|
195
|
+
* SessionEnd hooks fire when a Claude Code session ends, allowing you to:
|
|
196
|
+
* - Clean up session resources
|
|
197
|
+
* - Log session metrics
|
|
198
|
+
* - Persist session state
|
|
199
|
+
*
|
|
200
|
+
* **Matcher**: Matches against `reason` (the exit reason string)
|
|
201
|
+
* @param config - Hook configuration with optional matcher and timeout
|
|
202
|
+
* @param handler - The handler function to execute
|
|
203
|
+
* @returns A hook function that can be exported as the default export
|
|
204
|
+
* @example
|
|
205
|
+
* ```typescript
|
|
206
|
+
* import { sessionEndHook, sessionEndOutput } from '@goodfoot/claude-code-hooks';
|
|
207
|
+
*
|
|
208
|
+
* // Log session end and clean up
|
|
209
|
+
* export default sessionEndHook({}, async (input, { logger }) => {
|
|
210
|
+
* logger.info('Session ended', {
|
|
211
|
+
* sessionId: input.session_id,
|
|
212
|
+
* reason: input.reason
|
|
213
|
+
* });
|
|
214
|
+
*
|
|
215
|
+
* await cleanupSessionResources(input.session_id);
|
|
216
|
+
*
|
|
217
|
+
* return sessionEndOutput({});
|
|
218
|
+
* });
|
|
219
|
+
* ```
|
|
220
|
+
* @see https://code.claude.com/docs/en/hooks#sessionend
|
|
221
|
+
*/
|
|
222
|
+
export function sessionEndHook(config, handler) {
|
|
223
|
+
return createHookFunction('SessionEnd', config, handler);
|
|
224
|
+
}
|
|
225
|
+
// ============================================================================
|
|
226
|
+
// Stop Hook Factory
|
|
227
|
+
// ============================================================================
|
|
228
|
+
/**
|
|
229
|
+
* Creates a Stop hook handler.
|
|
230
|
+
*
|
|
231
|
+
* Stop hooks fire when Claude Code is about to stop, allowing you to:
|
|
232
|
+
* - Block the stop and require additional action
|
|
233
|
+
* - Confirm the user wants to stop
|
|
234
|
+
* - Clean up resources before stopping
|
|
235
|
+
*
|
|
236
|
+
* **Matcher**: No matcher support - fires on all stop events
|
|
237
|
+
* @param config - Hook configuration with optional timeout (matcher is ignored)
|
|
238
|
+
* @param handler - The handler function to execute
|
|
239
|
+
* @returns A hook function that can be exported as the default export
|
|
240
|
+
* @example
|
|
241
|
+
* ```typescript
|
|
242
|
+
* import { stopHook, stopOutput } from '@goodfoot/claude-code-hooks';
|
|
243
|
+
*
|
|
244
|
+
* // Block stop if there are pending changes
|
|
245
|
+
* export default stopHook({}, async (input, { logger }) => {
|
|
246
|
+
* const pendingChanges = await checkPendingChanges();
|
|
247
|
+
*
|
|
248
|
+
* if (pendingChanges.length > 0) {
|
|
249
|
+
* logger.warn('Blocking stop due to pending changes', {
|
|
250
|
+
* count: pendingChanges.length
|
|
251
|
+
* });
|
|
252
|
+
*
|
|
253
|
+
* return stopOutput({
|
|
254
|
+
* decision: 'block',
|
|
255
|
+
* reason: `There are ${pendingChanges.length} uncommitted changes`,
|
|
256
|
+
* systemMessage: 'Please commit or discard changes before stopping'
|
|
257
|
+
* });
|
|
258
|
+
* }
|
|
259
|
+
*
|
|
260
|
+
* logger.info('Approving stop');
|
|
261
|
+
* return stopOutput({ decision: 'approve' });
|
|
262
|
+
* });
|
|
263
|
+
* ```
|
|
264
|
+
* @see https://code.claude.com/docs/en/hooks#stop
|
|
265
|
+
*/
|
|
266
|
+
export function stopHook(config, handler) {
|
|
267
|
+
return createHookFunction('Stop', config, handler);
|
|
268
|
+
}
|
|
269
|
+
// ============================================================================
|
|
270
|
+
// SubagentStart Hook Factory
|
|
271
|
+
// ============================================================================
|
|
272
|
+
/**
|
|
273
|
+
* Creates a SubagentStart hook handler.
|
|
274
|
+
*
|
|
275
|
+
* SubagentStart hooks fire when a subagent (Task tool) starts, allowing you to:
|
|
276
|
+
* - Inject context for the subagent
|
|
277
|
+
* - Log subagent invocations
|
|
278
|
+
* - Configure subagent behavior
|
|
279
|
+
*
|
|
280
|
+
* **Matcher**: Matches against `agent_type` (e.g., 'explore', 'codebase-analysis')
|
|
281
|
+
* @param config - Hook configuration with optional matcher and timeout
|
|
282
|
+
* @param handler - The handler function to execute
|
|
283
|
+
* @returns A hook function that can be exported as the default export
|
|
284
|
+
* @example
|
|
285
|
+
* ```typescript
|
|
286
|
+
* import { subagentStartHook, subagentStartOutput } from '@goodfoot/claude-code-hooks';
|
|
287
|
+
*
|
|
288
|
+
* // Add context for explore subagents
|
|
289
|
+
* export default subagentStartHook({ matcher: 'explore' }, async (input, { logger }) => {
|
|
290
|
+
* logger.info('Explore subagent starting', {
|
|
291
|
+
* agentId: input.agent_id,
|
|
292
|
+
* agentType: input.agent_type
|
|
293
|
+
* });
|
|
294
|
+
*
|
|
295
|
+
* return subagentStartOutput({
|
|
296
|
+
* additionalContext: 'Focus on finding patterns and conventions'
|
|
297
|
+
* });
|
|
298
|
+
* });
|
|
299
|
+
* ```
|
|
300
|
+
* @see https://code.claude.com/docs/en/hooks#subagentstart
|
|
301
|
+
*/
|
|
302
|
+
export function subagentStartHook(config, handler) {
|
|
303
|
+
return createHookFunction('SubagentStart', config, handler);
|
|
304
|
+
}
|
|
305
|
+
// ============================================================================
|
|
306
|
+
// SubagentStop Hook Factory
|
|
307
|
+
// ============================================================================
|
|
308
|
+
/**
|
|
309
|
+
* Creates a SubagentStop hook handler.
|
|
310
|
+
*
|
|
311
|
+
* SubagentStop hooks fire when a subagent completes or stops, allowing you to:
|
|
312
|
+
* - Block the subagent from stopping
|
|
313
|
+
* - Process subagent results
|
|
314
|
+
* - Clean up subagent resources
|
|
315
|
+
* - Log subagent completion
|
|
316
|
+
*
|
|
317
|
+
* **Matcher**: Matches against `agent_type` (e.g., 'explore', 'codebase-analysis')
|
|
318
|
+
* @param config - Hook configuration with optional matcher and timeout
|
|
319
|
+
* @param handler - The handler function to execute
|
|
320
|
+
* @returns A hook function that can be exported as the default export
|
|
321
|
+
* @example
|
|
322
|
+
* ```typescript
|
|
323
|
+
* import { subagentStopHook, subagentStopOutput } from '@goodfoot/claude-code-hooks';
|
|
324
|
+
*
|
|
325
|
+
* // Block explore subagents if task incomplete
|
|
326
|
+
* export default subagentStopHook({ matcher: 'explore' }, async (input, { logger }) => {
|
|
327
|
+
* logger.info('Subagent stopping', {
|
|
328
|
+
* agentId: input.agent_id,
|
|
329
|
+
* agentType: input.agent_type
|
|
330
|
+
* });
|
|
331
|
+
*
|
|
332
|
+
* // Block if transcript shows incomplete work
|
|
333
|
+
* return subagentStopOutput({
|
|
334
|
+
* decision: 'block',
|
|
335
|
+
* reason: 'Please verify exploration is complete'
|
|
336
|
+
* });
|
|
337
|
+
* });
|
|
338
|
+
* ```
|
|
339
|
+
* @see https://code.claude.com/docs/en/hooks#subagentstop
|
|
340
|
+
*/
|
|
341
|
+
export function subagentStopHook(config, handler) {
|
|
342
|
+
return createHookFunction('SubagentStop', config, handler);
|
|
343
|
+
}
|
|
344
|
+
// ============================================================================
|
|
345
|
+
// PreCompact Hook Factory
|
|
346
|
+
// ============================================================================
|
|
347
|
+
/**
|
|
348
|
+
* Creates a PreCompact hook handler.
|
|
349
|
+
*
|
|
350
|
+
* PreCompact hooks fire before context compaction occurs, allowing you to:
|
|
351
|
+
* - Preserve important information before compaction
|
|
352
|
+
* - Log compaction events
|
|
353
|
+
* - Modify custom instructions for the compacted context
|
|
354
|
+
*
|
|
355
|
+
* **Matcher**: Matches against `trigger` ('manual', 'auto')
|
|
356
|
+
* @param config - Hook configuration with optional matcher and timeout
|
|
357
|
+
* @param handler - The handler function to execute
|
|
358
|
+
* @returns A hook function that can be exported as the default export
|
|
359
|
+
* @example
|
|
360
|
+
* ```typescript
|
|
361
|
+
* import { preCompactHook, preCompactOutput } from '@goodfoot/claude-code-hooks';
|
|
362
|
+
*
|
|
363
|
+
* // Log compaction events and preserve context
|
|
364
|
+
* export default preCompactHook({}, async (input, { logger }) => {
|
|
365
|
+
* logger.info('Context compaction triggered', {
|
|
366
|
+
* trigger: input.trigger,
|
|
367
|
+
* hasCustomInstructions: input.custom_instructions !== null
|
|
368
|
+
* });
|
|
369
|
+
*
|
|
370
|
+
* return preCompactOutput({
|
|
371
|
+
* systemMessage: 'Remember: strict mode is enabled'
|
|
372
|
+
* });
|
|
373
|
+
* });
|
|
374
|
+
* ```
|
|
375
|
+
* @example
|
|
376
|
+
* ```typescript
|
|
377
|
+
* // Only handle manual compaction
|
|
378
|
+
* export default preCompactHook({ matcher: 'manual' }, async (input, { logger }) => {
|
|
379
|
+
* logger.info('Manual compaction requested');
|
|
380
|
+
* return preCompactOutput({});
|
|
381
|
+
* });
|
|
382
|
+
* ```
|
|
383
|
+
* @see https://code.claude.com/docs/en/hooks#precompact
|
|
384
|
+
*/
|
|
385
|
+
export function preCompactHook(config, handler) {
|
|
386
|
+
return createHookFunction('PreCompact', config, handler);
|
|
387
|
+
}
|
|
388
|
+
/** @inheritdoc */
|
|
389
|
+
export function permissionRequestHook(config, handler) {
|
|
390
|
+
return createHookFunction('PermissionRequest', config, handler);
|
|
391
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type-safe Claude Code hooks library.
|
|
3
|
+
*
|
|
4
|
+
* Provides typed input/output handling, output builders, and logging system
|
|
5
|
+
* for building Claude Code hooks with full type safety.
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
// Hook event names constant
|
|
9
|
+
export { HOOK_EVENT_NAMES } from './inputs.js';
|
|
10
|
+
// Output builder functions
|
|
11
|
+
export {
|
|
12
|
+
// Exit codes
|
|
13
|
+
EXIT_CODES,
|
|
14
|
+
// All 12 output builder functions
|
|
15
|
+
preToolUseOutput,
|
|
16
|
+
postToolUseOutput,
|
|
17
|
+
postToolUseFailureOutput,
|
|
18
|
+
userPromptSubmitOutput,
|
|
19
|
+
sessionStartOutput,
|
|
20
|
+
sessionEndOutput,
|
|
21
|
+
stopOutput,
|
|
22
|
+
subagentStartOutput,
|
|
23
|
+
subagentStopOutput,
|
|
24
|
+
notificationOutput,
|
|
25
|
+
preCompactOutput,
|
|
26
|
+
permissionRequestOutput
|
|
27
|
+
} from './outputs.js';
|
|
28
|
+
// Logger exports
|
|
29
|
+
export { LOG_LEVELS, Logger, logger } from './logger.js';
|
|
30
|
+
// Hook factory functions - all 12 hook types
|
|
31
|
+
export {
|
|
32
|
+
preToolUseHook,
|
|
33
|
+
postToolUseHook,
|
|
34
|
+
postToolUseFailureHook,
|
|
35
|
+
notificationHook,
|
|
36
|
+
userPromptSubmitHook,
|
|
37
|
+
sessionStartHook,
|
|
38
|
+
sessionEndHook,
|
|
39
|
+
stopHook,
|
|
40
|
+
subagentStartHook,
|
|
41
|
+
subagentStopHook,
|
|
42
|
+
preCompactHook,
|
|
43
|
+
permissionRequestHook
|
|
44
|
+
} from './hooks.js';
|
|
45
|
+
// Runtime exports - execute function
|
|
46
|
+
export {
|
|
47
|
+
// Main execute function for compiled hooks
|
|
48
|
+
execute
|
|
49
|
+
} from './runtime.js';
|
|
50
|
+
// Environment variable utilities
|
|
51
|
+
export {
|
|
52
|
+
// Environment variable name constants
|
|
53
|
+
CLAUDE_ENV_VARS,
|
|
54
|
+
// Getters
|
|
55
|
+
getProjectDir,
|
|
56
|
+
getEnvFilePath,
|
|
57
|
+
isRemoteEnvironment
|
|
58
|
+
} from './env.js';
|
|
59
|
+
// Tool helper functions - Type guards and utilities
|
|
60
|
+
export {
|
|
61
|
+
// Type guards
|
|
62
|
+
isWriteTool,
|
|
63
|
+
isEditTool,
|
|
64
|
+
isMultiEditTool,
|
|
65
|
+
isFileModifyingTool,
|
|
66
|
+
isReadTool,
|
|
67
|
+
isBashTool,
|
|
68
|
+
isGlobTool,
|
|
69
|
+
isGrepTool,
|
|
70
|
+
// File path utilities
|
|
71
|
+
getFilePath,
|
|
72
|
+
isJsTsFile,
|
|
73
|
+
isTsFile,
|
|
74
|
+
// Content inspection
|
|
75
|
+
checkContentForPattern,
|
|
76
|
+
forEachContent
|
|
77
|
+
} from './tool-helpers.js';
|