Module: ClaudeHooks::CLI
- Defined in:
- lib/claude_hooks/cli.rb
Overview
CLI utility for testing hook handlers in isolation This module provides a standardized way to run hooks directly from the command line for testing and debugging purposes.
Class Method Summary collapse
-
.entrypoint(hook_class = nil, &block) ⇒ Object
Simplified entrypoint helper for hook scripts This handles all the STDIN reading, JSON parsing, error handling, and output execution.
-
.run_hook(hook_class, input_data = nil, &block) ⇒ Object
Run a hook class directly from command line Usage: ClaudeHooks::CLI.run_hook(YourHookClass) ClaudeHooks::CLI.run_hook(YourHookClass, custom_input_data) # With customization block: ClaudeHooks::CLI.run_hook(YourHookClass) do |input_data| input_data = true end.
-
.run_with_sample_data(hook_class, sample_data = {}, &block) ⇒ Object
Run hook with sample data (useful for development) Usage: ClaudeHooks::CLI.run_with_sample_data(YourHookClass) ClaudeHooks::CLI.run_with_sample_data(YourHookClass, { 'prompt' => 'test prompt' }) # With customization block: ClaudeHooks::CLI.run_with_sample_data(YourHookClass) do |input_data| input_data = 'Custom test prompt' input_data = true end.
-
.test_runner(hook_class, &block) ⇒ Object
Create a test runner block for a hook class This generates the common if FILE == $0 block content.
Class Method Details
.entrypoint(hook_class = nil, &block) ⇒ Object
Simplified entrypoint helper for hook scripts This handles all the STDIN reading, JSON parsing, error handling, and output execution
Usage patterns:
-
Block form - custom logic: ClaudeHooks::CLI.entrypoint do |input_data| hook = MyHook.new(input_data) hook.call hook.output_and_exit end
-
Simple form - single hook class: ClaudeHooks::CLI.entrypoint(MyHook)
-
Multiple hooks with merging: ClaudeHooks::CLI.entrypoint do |input_data| hook1 = Hook1.new(input_data) hook2 = Hook2.new(input_data) result1 = hook1.call result2 = hook2.call
# Use the appropriate output class for merging merged = ClaudeHooks::Output::PreToolUse.merge( hook1.output, hook2.output ) merged.output_and_exitend
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
# File 'lib/claude_hooks/cli.rb', line 121 def entrypoint(hook_class = nil, &block) # Read and parse input from STDIN input_data = JSON.parse(STDIN.read) if block_given? # Custom block form yield(input_data) elsif hook_class # Simple single hook form hook = hook_class.new(input_data) hook.call hook.output_and_exit else raise ArgumentError, "Either provide a hook_class or a block" end rescue JSON::ParserError => e STDERR.puts "JSON parsing error: #{e.}" error_response = { continue: false, stopReason: "JSON parsing error: #{e.}", suppressOutput: false } response = JSON.generate(error_response) puts response STDERR.puts response exit 1 rescue StandardError => e STDERR.puts "Hook execution error: #{e.}" STDERR.puts e.backtrace.join("\n") if e.backtrace error_response = { continue: false, stopReason: "Hook execution error: #{e.}", suppressOutput: false } response = JSON.generate(error_response) puts response STDERR.puts response exit 1 end |
.run_hook(hook_class, input_data = nil, &block) ⇒ Object
Run a hook class directly from command line Usage:
ClaudeHooks::CLI.run_hook(YourHookClass)
ClaudeHooks::CLI.run_hook(YourHookClass, custom_input_data)
# With customization block:
ClaudeHooks::CLI.run_hook(YourHookClass) do |input_data|
input_data['debug_mode'] = true
end
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
# File 'lib/claude_hooks/cli.rb', line 20 def run_hook(hook_class, input_data = nil, &block) # If no input data provided, read from STDIN input_data ||= read_stdin_input # Apply customization block if provided if block_given? yield(input_data) end # Create and execute the hook hook = hook_class.new(input_data) result = hook.call # Output the result as JSON (same format as production hooks) puts JSON.generate(result) if result result rescue StandardError => e handle_error(e, hook_class) end |
.run_with_sample_data(hook_class, sample_data = {}, &block) ⇒ Object
Run hook with sample data (useful for development) Usage:
ClaudeHooks::CLI.run_with_sample_data(YourHookClass)
ClaudeHooks::CLI.run_with_sample_data(YourHookClass, { 'prompt' => 'test prompt' })
# With customization block:
ClaudeHooks::CLI.run_with_sample_data(YourHookClass) do |input_data|
input_data['prompt'] = 'Custom test prompt'
input_data['debug'] = true
end
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/claude_hooks/cli.rb', line 73 def run_with_sample_data(hook_class, sample_data = {}, &block) default_sample = { 'session_id' => 'test-session', 'transcript_path' => '/tmp/test_transcript.md', 'cwd' => Dir.pwd, 'hook_event_name' => hook_class.hook_type } # Merge with hook-specific sample data merged_data = default_sample.merge(sample_data) # Apply customization block if provided if block_given? yield(merged_data) end run_hook(hook_class, merged_data) end |
.test_runner(hook_class, &block) ⇒ Object
Create a test runner block for a hook class This generates the common if FILE == $0 block content
Usage:
ClaudeHooks::CLI.test_runner(YourHookClass)
# With customization block:
ClaudeHooks::CLI.test_runner(YourHookClass) do |input_data|
input_data['custom_field'] = 'test_value'
input_data['user_name'] = 'TestUser'
end
52 53 54 55 56 57 58 59 60 61 |
# File 'lib/claude_hooks/cli.rb', line 52 def test_runner(hook_class, &block) input_data = read_stdin_input # Apply customization block if provided if block_given? yield(input_data) end run_hook(hook_class, input_data) end |