Class: ClaudeHooks::Base

Inherits:
Object
  • Object
show all
Defined in:
lib/claude_hooks/base.rb

Overview

Base class for Claude Code hook scripts

Constant Summary collapse

COMMON_INPUT_FIELDS =

Common input fields for all hook types

%w[session_id transcript_path cwd hook_event_name permission_mode].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(input_data = {}) ⇒ Base

Returns a new instance of Base.



29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/claude_hooks/base.rb', line 29

def initialize(input_data = {})
  @config = Configuration
  @input_data = input_data
  @output_data = {
    'continue' => true,
    'stopReason' => '',
    'suppressOutput' => false
  }
  @output = ClaudeHooks::Output::Base.for_hook_type(hook_type, @output_data)
  @logger = Logger.new(session_id, self.class.name)

  validate_input!
end

Instance Attribute Details

#configObject (readonly)

Returns the value of attribute config.



28
29
30
# File 'lib/claude_hooks/base.rb', line 28

def config
  @config
end

#input_dataObject (readonly)

Returns the value of attribute input_data.



28
29
30
# File 'lib/claude_hooks/base.rb', line 28

def input_data
  @input_data
end

#loggerObject (readonly)

Returns the value of attribute logger.



28
29
30
# File 'lib/claude_hooks/base.rb', line 28

def logger
  @logger
end

#outputObject (readonly)

Returns the value of attribute output.



28
29
30
# File 'lib/claude_hooks/base.rb', line 28

def output
  @output
end

#output_dataObject (readonly)

Returns the value of attribute output_data.



28
29
30
# File 'lib/claude_hooks/base.rb', line 28

def output_data
  @output_data
end

Class Method Details

.hook_typeObject

Override in subclasses to specify hook type

Raises:

  • (NotImplementedError)


15
16
17
# File 'lib/claude_hooks/base.rb', line 15

def self.hook_type
  raise NotImplementedError, "Subclasses must define hook_type"
end

.input_fieldsObject

Override in subclasses to specify hook-specific input fields

Raises:

  • (NotImplementedError)


20
21
22
# File 'lib/claude_hooks/base.rb', line 20

def self.input_fields
  raise NotImplementedError, "Subclasses must define input_fields"
end

Instance Method Details

#agent_idObject



83
84
85
# File 'lib/claude_hooks/base.rb', line 83

def agent_id
  @input_data['agent_id'] || @input_data['agentId']
end

#agent_typeObject



87
88
89
# File 'lib/claude_hooks/base.rb', line 87

def agent_type
  @input_data['agent_type'] || @input_data['agentType']
end

#allow_continue!Object

Allow Claude to continue (default: true)



113
114
115
# File 'lib/claude_hooks/base.rb', line 113

def allow_continue!
  @output_data['continue'] = true
end

#base_dirObject

CONFIG AND UTILITY METHODS ===



154
155
156
# File 'lib/claude_hooks/base.rb', line 154

def base_dir
  config.base_dir
end

#callObject

Main execution method - override in subclasses

Raises:

  • (NotImplementedError)


44
45
46
# File 'lib/claude_hooks/base.rb', line 44

def call
  raise NotImplementedError, "Subclasses must implement the call method"
end

#clear_specifics!Object



131
132
133
# File 'lib/claude_hooks/base.rb', line 131

def clear_specifics!
  @output_data['hookSpecificOutput'] = nil
end

#clear_system_message!Object



148
149
150
# File 'lib/claude_hooks/base.rb', line 148

def clear_system_message!
  @output_data.delete('systemMessage')
end

#cwdObject



66
67
68
# File 'lib/claude_hooks/base.rb', line 66

def cwd
  @input_data['cwd']
end

#effortObject



91
92
93
# File 'lib/claude_hooks/base.rb', line 91

def effort
  @input_data.dig('effort', 'level')
end

#home_claude_dirObject



158
159
160
# File 'lib/claude_hooks/base.rb', line 158

def home_claude_dir
  config.home_claude_dir
end

#home_path_for(relative_path) ⇒ Object



170
171
172
# File 'lib/claude_hooks/base.rb', line 170

def home_path_for(relative_path)
  config.home_path_for(relative_path)
end

#hook_event_nameObject



70
71
72
# File 'lib/claude_hooks/base.rb', line 70

def hook_event_name
  @input_data['hook_event_name'] || @input_data['hookEventName'] || hook_type
end

#hook_typeObject



24
25
26
# File 'lib/claude_hooks/base.rb', line 24

def hook_type
  self.class.hook_type
end

#log(message = nil, level: :info, &block) ⇒ Object

Supports both single messages and blocks for multiline logging



179
180
181
# File 'lib/claude_hooks/base.rb', line 179

def log(message = nil, level: :info, &block)
  @logger.log(message, level: level, &block)
end

#output_and_exitObject



52
53
54
# File 'lib/claude_hooks/base.rb', line 52

def output_and_exit
  @output.output_and_exit
end

#path_for(relative_path, base_directory = nil) ⇒ Object



166
167
168
# File 'lib/claude_hooks/base.rb', line 166

def path_for(relative_path, base_directory = nil)
  config.path_for(relative_path, base_directory)
end

#permission_modeObject

Values: default|plan|acceptEdits|auto|dontAsk|bypassPermissions



75
76
77
# File 'lib/claude_hooks/base.rb', line 75

def permission_mode
  @input_data['permission_mode'] || @input_data['permissionMode'] || 'default'
end

#prevent_continue!(reason) ⇒ Object



117
118
119
120
# File 'lib/claude_hooks/base.rb', line 117

def prevent_continue!(reason)
  @output_data['continue'] = false
  @output_data['stopReason'] = reason
end

#project_claude_dirObject



162
163
164
# File 'lib/claude_hooks/base.rb', line 162

def project_claude_dir
  config.project_claude_dir
end

#project_path_for(relative_path) ⇒ Object



174
175
176
# File 'lib/claude_hooks/base.rb', line 174

def project_path_for(relative_path)
  config.project_path_for(relative_path)
end

#prompt_idObject



79
80
81
# File 'lib/claude_hooks/base.rb', line 79

def prompt_id
  @input_data['prompt_id'] || @input_data['promptId']
end

#read_transcriptObject Also known as: transcript



95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/claude_hooks/base.rb', line 95

def read_transcript
  unless transcript_path && File.exist?(transcript_path)
    log "Transcript file not found at #{transcript_path}", level: :warn
    return ''
  end

  begin
    File.read(transcript_path)
  rescue => e
    log "Error reading transcript file at #{transcript_path}: #{e.message}", level: :error
    ''
  end
end

#session_idObject

COMMON INPUT DATA ACCESS ===



58
59
60
# File 'lib/claude_hooks/base.rb', line 58

def session_id
  @input_data['session_id'] || 'claude-default-session'
end

#show_output!Object



127
128
129
# File 'lib/claude_hooks/base.rb', line 127

def show_output!
  @output_data['suppressOutput'] = false
end

#stringify_outputObject



48
49
50
# File 'lib/claude_hooks/base.rb', line 48

def stringify_output
  JSON.generate(@output_data)
end

#suppress_output!Object

Hide stdout from transcript mode (default: false)



123
124
125
# File 'lib/claude_hooks/base.rb', line 123

def suppress_output!
  @output_data['suppressOutput'] = true
end

#system_message!(message) ⇒ Object

System message shown to the user (not to Claude)



144
145
146
# File 'lib/claude_hooks/base.rb', line 144

def system_message!(message)
  @output_data['systemMessage'] = message
end

#terminal_sequenceObject



139
140
141
# File 'lib/claude_hooks/base.rb', line 139

def terminal_sequence
  @output_data['terminalSequence']
end

#terminal_sequence!(seq) ⇒ Object



135
136
137
# File 'lib/claude_hooks/base.rb', line 135

def terminal_sequence!(seq)
  @output_data['terminalSequence'] = seq
end

#transcript_pathObject



62
63
64
# File 'lib/claude_hooks/base.rb', line 62

def transcript_path
  @input_data['transcript_path']
end