Skip to content

Commit 9b507c9

Browse files
Merge pull request #5 from timoconnellaus/feature/cli-setup
Execute TypeScript hooks directly with ts-node
2 parents 4cdfdc1 + 47d25cc commit 9b507c9

File tree

6 files changed

+154
-186
lines changed

6 files changed

+154
-186
lines changed

.claude/hooks/hooks.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
import {
2-
defineHooks,
3-
defineHook,
4-
logPreToolUseEvents,
5-
logPostToolUseEvents,
6-
logStopEvents,
7-
} from "../..";
1+
import { defineHooks } from '../..';
2+
import { logPreToolUseEvents, logPostToolUseEvents } from '../../src/hooks/logToolUseEvents';
3+
import { blockEnvFiles } from '../../src/hooks/blockEnvFiles';
4+
import { logStopEvents } from '../../src/hooks/logStopEvents';
85

9-
export default defineHooks({
10-
PreToolUse: [logPreToolUseEvents({ maxEventsStored: 100 })],
11-
PostToolUse: [logPostToolUseEvents({ maxEventsStored: 100 })],
12-
Stop: [logStopEvents({ maxEventsStored: 100 })],
13-
});
6+
defineHooks({
7+
PreToolUse: [
8+
logPreToolUseEvents(),
9+
blockEnvFiles
10+
],
11+
PostToolUse: [logPostToolUseEvents()],
12+
Stop: [logStopEvents()]
13+
});

.claude/settings.json

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,16 @@
66
"hooks": [
77
{
88
"type": "command",
9-
"command": "test -f \"./.hooks/hooks.js\" && node \"./.hooks/hooks.js\" __run_hook PreToolUse \".*\" \"0\" || (>&2 echo \"Error: Hook script not found at ./.hooks/hooks.js\" && >&2 echo \"Please run: npx define-claude-code-hooks\" && exit 1) # __managed_by_define_claude_code_hooks__"
9+
"command": "test -f \"./.claude/hooks/hooks.ts\" && npx ts-node \"./.claude/hooks/hooks.ts\" __run_hook PreToolUse \".*\" \"0\" || (>&2 echo \"Error: Hook script not found at ./.claude/hooks/hooks.ts\" && >&2 echo \"Please run: npx define-claude-code-hooks\" && exit 1) # __managed_by_define_claude_code_hooks__"
10+
}
11+
]
12+
},
13+
{
14+
"matcher": "Read|Write|Edit|MultiEdit",
15+
"hooks": [
16+
{
17+
"type": "command",
18+
"command": "test -f \"./.claude/hooks/hooks.ts\" && npx ts-node \"./.claude/hooks/hooks.ts\" __run_hook PreToolUse \"Read|Write|Edit|MultiEdit\" \"1\" || (>&2 echo \"Error: Hook script not found at ./.claude/hooks/hooks.ts\" && >&2 echo \"Please run: npx define-claude-code-hooks\" && exit 1) # __managed_by_define_claude_code_hooks__"
1019
}
1120
]
1221
}
@@ -17,7 +26,7 @@
1726
"hooks": [
1827
{
1928
"type": "command",
20-
"command": "test -f \"./.hooks/hooks.js\" && node \"./.hooks/hooks.js\" __run_hook PostToolUse \".*\" \"0\" || (>&2 echo \"Error: Hook script not found at ./.hooks/hooks.js\" && >&2 echo \"Please run: npx define-claude-code-hooks\" && exit 1) # __managed_by_define_claude_code_hooks__"
29+
"command": "test -f \"./.claude/hooks/hooks.ts\" && npx ts-node \"./.claude/hooks/hooks.ts\" __run_hook PostToolUse \".*\" \"0\" || (>&2 echo \"Error: Hook script not found at ./.claude/hooks/hooks.ts\" && >&2 echo \"Please run: npx define-claude-code-hooks\" && exit 1) # __managed_by_define_claude_code_hooks__"
2130
}
2231
]
2332
}
@@ -27,7 +36,7 @@
2736
"hooks": [
2837
{
2938
"type": "command",
30-
"command": "test -f \"./.hooks/hooks.js\" && node \"./.hooks/hooks.js\" __run_hook Stop || (>&2 echo \"Error: Hook script not found at ./.hooks/hooks.js\" && >&2 echo \"Please run: npx define-claude-code-hooks\" && exit 1) # __managed_by_define_claude_code_hooks__"
39+
"command": "test -f \"./.claude/hooks/hooks.ts\" && npx ts-node \"./.claude/hooks/hooks.ts\" __run_hook Stop || (>&2 echo \"Error: Hook script not found at ./.claude/hooks/hooks.ts\" && >&2 echo \"Please run: npx define-claude-code-hooks\" && exit 1) # __managed_by_define_claude_code_hooks__"
3140
}
3241
]
3342
}

CLAUDE.md

Lines changed: 85 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,61 +4,72 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
44

55
## Project Overview
66

7-
This is a TypeScript library that provides type-safe hook definitions for Claude Code with automatic settings management. It allows users to define hooks that run at various points in Claude Code's lifecycle without manually editing settings.json files. Hook files are automatically compiled from TypeScript to JavaScript for execution.
7+
This is a TypeScript library that provides type-safe hook definitions for Claude Code with automatic settings management. It allows users to define hooks that run at various points in Claude Code's lifecycle without manually editing settings.json files. Hook files are executed directly using ts-node without compilation.
88

9-
## Build Commands
9+
## Development Commands
1010

1111
```bash
12+
# Install dependencies
13+
bun install
14+
1215
# Build the TypeScript project
1316
bun run build
1417

1518
# Watch mode for development
1619
bun run dev
1720

18-
# Install dependencies
19-
bun install
21+
# Run tests
22+
bun run test:run
23+
24+
# Run tests with coverage
25+
bun run test:coverage
26+
27+
# Type checking / linting
28+
bun run typecheck
2029
```
2130

2231
## Architecture
2332

2433
### Key Concepts
2534

2635
1. **Self-Executing Hooks**: Hook files act as both the hook definition and the runner. When `defineHooks` is called, it checks if it's being run as a CLI and handles two modes:
27-
2836
- `__generate_settings`: Outputs JSON information about defined hooks
2937
- `__run_hook`: Executes the appropriate hook handler
3038

31-
2. **No Separate Runner**: Unlike traditional approaches, there's no separate runner.js. The compiled hooks file itself is executed directly by the generated commands in settings.json.
39+
2. **No Separate Runner**: Unlike traditional approaches, there's no separate runner.js. The hooks file itself is executed directly by the generated commands in settings.json using ts-node.
3240

33-
3. **Automatic Compilation**: The CLI compiles TypeScript hook files to JavaScript in the `.hooks` directory:
34-
- TypeScript hooks are compiled on-the-fly when running the CLI
35-
- Compiled JavaScript files are placed in `.hooks/` (gitignored)
36-
- No need for ts-node at runtime - hooks run as pure JavaScript
41+
3. **Direct TypeScript Execution**: The CLI generates commands that use ts-node to execute TypeScript hooks directly:
42+
- No compilation step needed
43+
- TypeScript hooks are executed directly using ts-node
44+
- No intermediate JavaScript files are generated
3745

3846
4. **Smart Settings Generation**: The CLI only creates settings entries for hooks that are actually defined:
3947
- For PreToolUse/PostToolUse: One entry per matcher
4048
- For other hooks (Stop, Notification, SubagentStop): One entry only if handlers exist
49+
- Commands use `npx ts-node` to execute the TypeScript hooks directly
4150

4251
5. **Multiple Hook Files**: The system supports two different hook files, all located in `.claude/hooks/`:
43-
- `hooks.ts` - Project hooks (compiles to `.hooks/hooks.js`, updates `.claude/settings.json`)
44-
- `hooks.local.ts` - Local hooks (compiles to `.hooks/hooks.local.js`, updates `.claude/settings.local.json`)
45-
46-
The CLI automatically detects which files exist, compiles them, and updates the corresponding settings files.
52+
- `hooks.ts` - Project hooks (updates `.claude/settings.json`)
53+
- `hooks.local.ts` - Local hooks (updates `.claude/settings.local.json`)
4754

4855
### Core Components
4956

5057
- **src/index.ts**: Exports `defineHooks` and `defineHook` functions. Contains the self-execution logic that makes hooks files act as their own runners.
5158

52-
- **src/cli.ts**: The CLI that compiles TypeScript hooks to JavaScript and updates settings.json files. It automatically detects which hook files exist (hooks.ts, hooks.local.ts), compiles them to `.hooks/`, and updates the corresponding settings files.
59+
- **src/cli.ts**: The CLI that updates settings.json files to execute TypeScript hooks using ts-node. Includes an interactive `--init` command for project setup.
5360

5461
- **src/types.ts**: TypeScript type definitions for all hook types, inputs, and outputs. Key distinction between tool hooks (PreToolUse/PostToolUse) that have matchers and non-tool hooks.
5562

56-
- **src/hooks/**: Predefined hook utilities for common logging scenarios (logToolUseEvents, logStopEvents, logNotificationEvents)
63+
- **src/hooks/**: Predefined hook utilities:
64+
- `logToolUseEvents.ts`: Logs PreToolUse and PostToolUse events to JSON files
65+
- `logStopEvents.ts`: Logs Stop and SubagentStop events
66+
- `logNotificationEvents.ts`: Logs notification events
67+
- `blockEnvFiles.ts`: Security hook that blocks access to .env files
68+
- `announceHooks.ts`: Text-to-speech announcements for various events
5769

5870
### Hook Definition Structure
5971

6072
Tool hooks (PreToolUse/PostToolUse):
61-
6273
```typescript
6374
{
6475
matcher: string, // Regex pattern for tool names
@@ -67,7 +78,6 @@ Tool hooks (PreToolUse/PostToolUse):
6778
```
6879

6980
Non-tool hooks (Stop, Notification, SubagentStop):
70-
7181
```typescript
7282
async (input) => {
7383
/* ... */
@@ -80,11 +90,32 @@ The CLI removes all hooks marked with `__managed_by_define_claude_code_hooks__`
8090

8191
```json
8292
{
83-
"command": "node \"./.hooks/hooks.js\" __run_hook PreToolUse \"Bash\" \"0\" # __managed_by_define_claude_code_hooks__"
93+
"command": "npx ts-node \"./.claude/hooks/hooks.ts\" __run_hook PreToolUse \"Bash\" \"0\" # __managed_by_define_claude_code_hooks__"
8494
}
8595
```
8696

87-
Note that commands reference the compiled JavaScript files in `.hooks/`, not the original TypeScript files.
97+
Commands use `npx ts-node` to execute the TypeScript files directly.
98+
99+
## Testing
100+
101+
The project uses Vitest for testing with comprehensive coverage:
102+
103+
```bash
104+
# Run a single test file
105+
bun run test src/hooks/__tests__/logToolUseEvents.test.ts
106+
107+
# Run tests in watch mode
108+
bun run test
109+
110+
# Run tests with coverage report
111+
bun run test:coverage
112+
```
113+
114+
Test structure:
115+
- Each hook has corresponding tests in `src/hooks/__tests__/`
116+
- Test utilities in `src/__tests__/` (fixtures, mockFs, testUtils)
117+
- Global test setup in `src/__tests__/setup.ts`
118+
- Coverage configuration in `vitest.config.mjs`
88119

89120
## Development Notes
90121

@@ -93,17 +124,10 @@ Note that commands reference the compiled JavaScript files in `.hooks/`, not the
93124
- Hook source files are all located in `.claude/hooks/`:
94125
- `hooks.ts` (project-wide hooks)
95126
- `hooks.local.ts` (local-only hooks, not committed to git)
96-
- Compiled JavaScript files are generated in `.hooks/`:
97-
- `.hooks/hooks.js`
98-
- `.hooks/hooks.local.js`
99-
- The `.hooks/` directory is gitignored
100127
- Compatible with npm, yarn, pnpm, and bun package managers
101-
- The CLI no longer requires flags - it automatically detects which hook files exist, compiles them, and updates the appropriate settings files
102-
- No runtime dependency on ts-node - hooks execute as pure JavaScript
103-
104-
### Testing
105-
106-
When testing the package, create test repositories in the `tmp/` folder in the project root. This folder is already in `.gitignore` so test projects won't be committed.
128+
- The CLI automatically detects which hook files exist and updates the appropriate settings files
129+
- Requires ts-node as a dependency for executing TypeScript hooks
130+
- When testing the package, create test repositories in the `tmp/` folder (already in `.gitignore`)
107131

108132
## Release Process
109133

@@ -153,3 +177,34 @@ For testing new features before a stable release:
153177
The package is published under the `@timoaus` scope as `@timoaus/define-claude-code-hooks`.
154178

155179
Note: The repository must have the `NPM_TOKEN` secret configured for publishing.
180+
181+
## CLI Features
182+
183+
### Interactive Initialization
184+
185+
The CLI provides an `--init` command for easy project setup:
186+
187+
```bash
188+
define-claude-code-hooks --init
189+
```
190+
191+
This command:
192+
- Uses interactive prompts to select predefined hooks
193+
- Automatically installs the package if needed (including ts-node)
194+
- Detects the package manager (npm/yarn/pnpm/bun)
195+
- Adds a `claude:hooks` script to package.json
196+
- Creates initial hook files with selected hooks
197+
198+
### Automatic Hook Detection
199+
200+
The CLI automatically:
201+
- Scans for hook files in `.claude/hooks/`
202+
- Generates commands that use ts-node to execute the TypeScript files
203+
- Updates corresponding settings files
204+
- Preserves user-defined hooks while managing its own
205+
206+
# important-instruction-reminders
207+
Do what has been asked; nothing more, nothing less.
208+
NEVER create files unless they're absolutely necessary for achieving your goal.
209+
ALWAYS prefer editing an existing file to creating a new one.
210+
NEVER proactively create documentation files (*.md) or README files. Only create documentation files if explicitly requested by the User.

0 commit comments

Comments
 (0)