claude_hooks 1.2.0 → 1.3.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +27 -0
- data/README.md +152 -221
- data/docs/1.0.0_MIGRATION_GUIDE.md +6 -7
- data/docs/API/DIRECTORY_ADDED.md +34 -0
- data/docs/external/claude-hooks-reference.md +271 -107
- data/example_dotclaude/hooks/entrypoints/session_end.rb +5 -22
- data/example_dotclaude/hooks/entrypoints/user_prompt_submit.rb +4 -26
- data/example_dotclaude/hooks/{handlers/pre_tool_use/github_guard.rb → github_guard.rb} +7 -13
- data/example_dotclaude/settings.json +1 -1
- data/lib/claude_hooks/cli.rb +84 -149
- data/lib/claude_hooks/directory_added.rb +24 -0
- data/lib/claude_hooks/output/base.rb +2 -0
- data/lib/claude_hooks/output/directory_added.rb +21 -0
- data/lib/claude_hooks/version.rb +1 -1
- data/lib/claude_hooks.rb +2 -0
- metadata +6 -5
- data/.claude/settings.local.json +0 -21
- data/example_dotclaude/hooks/entrypoints/pre_tool_use.rb +0 -25
|
@@ -1,35 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
2
|
|
|
3
|
-
require '
|
|
3
|
+
require 'claude_hooks'
|
|
4
4
|
require_relative '../handlers/session_end/cleanup_handler'
|
|
5
5
|
require_relative '../handlers/session_end/log_session_stats'
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
# Read input from stdin
|
|
9
|
-
input_data = JSON.parse(STDIN.read)
|
|
10
|
-
|
|
11
|
-
# Initialize handlers
|
|
7
|
+
ClaudeHooks::CLI.run_hook do |input_data|
|
|
12
8
|
cleanup_handler = CleanupHandler.new(input_data)
|
|
13
9
|
log_handler = LogSessionStats.new(input_data)
|
|
14
10
|
|
|
15
|
-
# Execute handlers
|
|
16
11
|
cleanup_handler.call
|
|
17
12
|
log_handler.call
|
|
18
13
|
|
|
19
|
-
|
|
20
|
-
merged_output = ClaudeHooks::Output::SessionEnd.merge(
|
|
14
|
+
ClaudeHooks::Output::SessionEnd.merge(
|
|
21
15
|
cleanup_handler.output,
|
|
22
16
|
log_handler.output
|
|
23
|
-
)
|
|
24
|
-
|
|
25
|
-
# Output result and exit with appropriate code
|
|
26
|
-
merged_output.output_and_exit
|
|
27
|
-
|
|
28
|
-
rescue StandardError => e
|
|
29
|
-
STDERR.puts JSON.generate({
|
|
30
|
-
continue: false,
|
|
31
|
-
stopReason: "Hook execution error: #{e.message}",
|
|
32
|
-
suppressOutput: false
|
|
33
|
-
})
|
|
34
|
-
exit 2
|
|
35
|
-
end
|
|
17
|
+
).output_and_exit
|
|
18
|
+
end
|
|
@@ -1,40 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
2
|
|
|
3
|
-
# Example of the NEW simplified entrypoint pattern using output objects
|
|
4
|
-
# Compare this to the existing user_prompt_submit.rb to see the difference!
|
|
5
|
-
|
|
6
3
|
require 'claude_hooks'
|
|
7
|
-
require 'json'
|
|
8
|
-
# Require the output classes
|
|
9
|
-
require_relative '../../../lib/claude_hooks/output/base'
|
|
10
|
-
require_relative '../../../lib/claude_hooks/output/user_prompt_submit'
|
|
11
4
|
require_relative '../handlers/user_prompt_submit/append_rules'
|
|
12
5
|
require_relative '../handlers/user_prompt_submit/log_user_prompt'
|
|
13
6
|
|
|
14
|
-
|
|
15
|
-
# Read input from stdin
|
|
16
|
-
input_data = JSON.parse(STDIN.read)
|
|
17
|
-
|
|
18
|
-
# Execute all hook scripts
|
|
7
|
+
ClaudeHooks::CLI.run_hook do |input_data|
|
|
19
8
|
append_rules = AppendRules.new(input_data)
|
|
20
9
|
append_rules.call
|
|
21
10
|
|
|
22
11
|
log_user_prompt = LogUserPrompt.new(input_data)
|
|
23
12
|
log_user_prompt.call
|
|
24
13
|
|
|
25
|
-
|
|
14
|
+
ClaudeHooks::Output::UserPromptSubmit.merge(
|
|
26
15
|
append_rules.output,
|
|
27
16
|
log_user_prompt.output
|
|
28
|
-
)
|
|
29
|
-
|
|
30
|
-
merged_output.output_and_exit
|
|
31
|
-
|
|
32
|
-
rescue StandardError => e
|
|
33
|
-
# Same simple error pattern
|
|
34
|
-
STDERR.puts JSON.generate({
|
|
35
|
-
continue: false,
|
|
36
|
-
stopReason: "Hook execution error: #{e.message} #{e.backtrace.join("\n")}",
|
|
37
|
-
suppressOutput: false
|
|
38
|
-
})
|
|
39
|
-
exit 2
|
|
40
|
-
end
|
|
17
|
+
).output_and_exit
|
|
18
|
+
end
|
|
@@ -238,16 +238,10 @@ class GithubGuard < ClaudeHooks::PreToolUse
|
|
|
238
238
|
end
|
|
239
239
|
end
|
|
240
240
|
|
|
241
|
-
#
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
'hook_event_name' => 'PreToolUse',
|
|
249
|
-
'tool_name' => 'mcp__github__create_pull_request',
|
|
250
|
-
'tool_input' => { 'draft' => false },
|
|
251
|
-
)
|
|
252
|
-
end
|
|
253
|
-
end
|
|
241
|
+
# Registered directly in settings.json under PreToolUse. Claude Code runs this file
|
|
242
|
+
# with the hook payload on STDIN. on_error: :block makes the guard fail-closed — a
|
|
243
|
+
# crash blocks the tool instead of silently allowing it.
|
|
244
|
+
#
|
|
245
|
+
# Debug it by piping sample JSON:
|
|
246
|
+
# echo '{"hook_event_name":"PreToolUse","tool_name":"Bash","tool_input":{"command":"git push --force"}}' | ruby github_guard.rb
|
|
247
|
+
ClaudeHooks::CLI.run_hook(GithubGuard, on_error: :block)
|
data/lib/claude_hooks/cli.rb
CHANGED
|
@@ -3,191 +3,126 @@
|
|
|
3
3
|
require 'json'
|
|
4
4
|
|
|
5
5
|
module ClaudeHooks
|
|
6
|
-
# CLI utility for testing hook handlers in isolation
|
|
7
|
-
# This module provides a standardized way to run hooks directly from the command line
|
|
8
|
-
# for testing and debugging purposes.
|
|
9
6
|
module CLI
|
|
10
7
|
class << self
|
|
11
|
-
# Run a hook
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
8
|
+
# Run a hook script from the command line.
|
|
9
|
+
# Reads JSON from STDIN, calls hook.call, and exits with the correct code.
|
|
10
|
+
#
|
|
11
|
+
# on_error controls what happens when the hook raises an unexpected exception:
|
|
12
|
+
# :allow (default) — exit 1, non-blocking; Claude continues as if the hook didn't run.
|
|
13
|
+
# :block — exit 2, blocking; Claude stops and shows the error. Use this for
|
|
14
|
+
# security/policy hooks where a crash should never silently pass through.
|
|
15
|
+
#
|
|
16
|
+
# Usage patterns:
|
|
17
|
+
#
|
|
18
|
+
# 1. Single hook class:
|
|
19
|
+
# ClaudeHooks::CLI.run_hook(MyHook)
|
|
20
|
+
# ClaudeHooks::CLI.run_hook(MyHook, on_error: :block) # fail-closed
|
|
21
|
+
#
|
|
22
|
+
# 2. Multiple hooks with merging:
|
|
23
|
+
# ClaudeHooks::CLI.run_hook(on_error: :block) do |input_data|
|
|
24
|
+
# hook1 = Hook1.new(input_data)
|
|
25
|
+
# hook2 = Hook2.new(input_data)
|
|
26
|
+
# hook1.call
|
|
27
|
+
# hook2.call
|
|
28
|
+
# ClaudeHooks::Output::PreToolUse.merge(hook1.output, hook2.output).output_and_exit
|
|
29
|
+
# end
|
|
30
|
+
def run_hook(hook_class = nil, on_error: :allow, &block)
|
|
31
|
+
input_data = JSON.parse(STDIN.read)
|
|
32
|
+
|
|
25
33
|
if block_given?
|
|
26
34
|
yield(input_data)
|
|
35
|
+
elsif hook_class
|
|
36
|
+
hook = hook_class.new(input_data)
|
|
37
|
+
hook.call
|
|
38
|
+
hook.output_and_exit
|
|
39
|
+
else
|
|
40
|
+
raise ArgumentError, "Either provide a hook_class or a block"
|
|
27
41
|
end
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
# Output the result as JSON (same format as production hooks)
|
|
34
|
-
puts JSON.generate(result) if result
|
|
35
|
-
|
|
36
|
-
result
|
|
42
|
+
|
|
43
|
+
rescue JSON::ParserError => e
|
|
44
|
+
handle_run_error("JSON parsing error: #{e.message}", on_error)
|
|
45
|
+
|
|
37
46
|
rescue StandardError => e
|
|
38
|
-
|
|
47
|
+
handle_run_error("Hook execution error: #{e.message}", on_error, backtrace: e.backtrace)
|
|
39
48
|
end
|
|
40
49
|
|
|
41
|
-
#
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
#
|
|
48
|
-
|
|
49
|
-
#
|
|
50
|
-
# input_data['user_name'] = 'TestUser'
|
|
51
|
-
# end
|
|
50
|
+
# @deprecated Use {run_hook} instead.
|
|
51
|
+
def entrypoint(hook_class = nil, on_error: :allow, &block)
|
|
52
|
+
warn "[ClaudeHooks] CLI.entrypoint is deprecated — use CLI.run_hook instead."
|
|
53
|
+
run_hook(hook_class, on_error: on_error, &block)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Testing helpers — use these inside `if __FILE__ == $0` blocks, not in production.
|
|
57
|
+
|
|
58
|
+
# Run a hook with input read from STDIN, with optional block to mutate input_data before running.
|
|
52
59
|
def test_runner(hook_class, &block)
|
|
53
60
|
input_data = read_stdin_input
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
if block_given?
|
|
57
|
-
yield(input_data)
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
run_hook(hook_class, input_data)
|
|
61
|
+
yield(input_data) if block_given?
|
|
62
|
+
run_hook_with_data(hook_class, input_data)
|
|
61
63
|
end
|
|
62
64
|
|
|
63
|
-
# Run hook with sample data (
|
|
64
|
-
# Usage:
|
|
65
|
-
# ClaudeHooks::CLI.run_with_sample_data(YourHookClass)
|
|
66
|
-
# ClaudeHooks::CLI.run_with_sample_data(YourHookClass, { 'prompt' => 'test prompt' })
|
|
67
|
-
#
|
|
68
|
-
# # With customization block:
|
|
69
|
-
# ClaudeHooks::CLI.run_with_sample_data(YourHookClass) do |input_data|
|
|
70
|
-
# input_data['prompt'] = 'Custom test prompt'
|
|
71
|
-
# input_data['debug'] = true
|
|
72
|
-
# end
|
|
65
|
+
# Run a hook with synthetic sample data (no STDIN needed).
|
|
73
66
|
def run_with_sample_data(hook_class, sample_data = {}, &block)
|
|
74
|
-
|
|
67
|
+
input_data = {
|
|
75
68
|
'session_id' => 'test-session',
|
|
76
69
|
'transcript_path' => '/tmp/test_transcript.md',
|
|
77
70
|
'cwd' => Dir.pwd,
|
|
78
71
|
'hook_event_name' => hook_class.hook_type
|
|
79
|
-
}
|
|
72
|
+
}.merge(sample_data)
|
|
80
73
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
# Apply customization block if provided
|
|
85
|
-
if block_given?
|
|
86
|
-
yield(merged_data)
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
run_hook(hook_class, merged_data)
|
|
74
|
+
yield(input_data) if block_given?
|
|
75
|
+
run_hook_with_data(hook_class, input_data)
|
|
90
76
|
end
|
|
91
77
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
#
|
|
95
|
-
#
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
# hook.output_and_exit
|
|
102
|
-
# end
|
|
103
|
-
#
|
|
104
|
-
# 2. Simple form - single hook class:
|
|
105
|
-
# ClaudeHooks::CLI.entrypoint(MyHook)
|
|
106
|
-
#
|
|
107
|
-
# 3. Multiple hooks with merging:
|
|
108
|
-
# ClaudeHooks::CLI.entrypoint do |input_data|
|
|
109
|
-
# hook1 = Hook1.new(input_data)
|
|
110
|
-
# hook2 = Hook2.new(input_data)
|
|
111
|
-
# result1 = hook1.call
|
|
112
|
-
# result2 = hook2.call
|
|
113
|
-
#
|
|
114
|
-
# # Use the appropriate output class for merging
|
|
115
|
-
# merged = ClaudeHooks::Output::PreToolUse.merge(
|
|
116
|
-
# hook1.output,
|
|
117
|
-
# hook2.output
|
|
118
|
-
# )
|
|
119
|
-
# merged.output_and_exit
|
|
120
|
-
# end
|
|
121
|
-
def entrypoint(hook_class = nil, &block)
|
|
122
|
-
# Read and parse input from STDIN
|
|
123
|
-
input_data = JSON.parse(STDIN.read)
|
|
124
|
-
|
|
125
|
-
if block_given?
|
|
126
|
-
# Custom block form
|
|
127
|
-
yield(input_data)
|
|
128
|
-
elsif hook_class
|
|
129
|
-
# Simple single hook form
|
|
130
|
-
hook = hook_class.new(input_data)
|
|
131
|
-
hook.call
|
|
132
|
-
hook.output_and_exit
|
|
133
|
-
else
|
|
134
|
-
raise ArgumentError, "Either provide a hook_class or a block"
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
rescue JSON::ParserError => e
|
|
138
|
-
STDERR.puts "JSON parsing error: #{e.message}"
|
|
139
|
-
error_response = {
|
|
140
|
-
continue: false,
|
|
141
|
-
stopReason: "JSON parsing error: #{e.message}",
|
|
142
|
-
suppressOutput: false
|
|
143
|
-
}
|
|
144
|
-
response = JSON.generate(error_response)
|
|
145
|
-
puts response
|
|
146
|
-
STDERR.puts response
|
|
147
|
-
exit 1
|
|
148
|
-
|
|
78
|
+
private
|
|
79
|
+
|
|
80
|
+
# Runs a hook with already-parsed input_data. Returns the result without exiting.
|
|
81
|
+
# Used internally by test_runner and run_with_sample_data.
|
|
82
|
+
def run_hook_with_data(hook_class, input_data)
|
|
83
|
+
hook = hook_class.new(input_data)
|
|
84
|
+
result = hook.call
|
|
85
|
+
puts JSON.generate(result) if result
|
|
86
|
+
result
|
|
149
87
|
rescue StandardError => e
|
|
150
|
-
|
|
88
|
+
hook_name = hook_class.name || hook_class.to_s
|
|
89
|
+
STDERR.puts "Error in #{hook_name} hook: #{e.message}"
|
|
151
90
|
STDERR.puts e.backtrace.join("\n") if e.backtrace
|
|
152
|
-
|
|
153
|
-
error_response = {
|
|
91
|
+
response = JSON.generate({
|
|
154
92
|
continue: false,
|
|
155
|
-
stopReason: "
|
|
93
|
+
stopReason: "#{hook_name} execution error: #{e.message}",
|
|
156
94
|
suppressOutput: false
|
|
157
|
-
}
|
|
158
|
-
response = JSON.generate(error_response)
|
|
95
|
+
})
|
|
159
96
|
puts response
|
|
160
97
|
STDERR.puts response
|
|
161
98
|
exit 1
|
|
162
99
|
end
|
|
163
100
|
|
|
164
|
-
|
|
101
|
+
def handle_run_error(message, on_error, backtrace: nil)
|
|
102
|
+
if on_error == :block
|
|
103
|
+
# Exit 2: Claude Code shows stderr to the model as plain text (never
|
|
104
|
+
# parsed as JSON), so emit just the message and block.
|
|
105
|
+
STDERR.puts message
|
|
106
|
+
exit 2
|
|
107
|
+
else
|
|
108
|
+
# Exit 1: non-blocking. stderr's first line surfaces in the transcript.
|
|
109
|
+
STDERR.puts backtrace.join("\n") if backtrace
|
|
110
|
+
STDERR.puts JSON.generate({
|
|
111
|
+
continue: false,
|
|
112
|
+
stopReason: message,
|
|
113
|
+
suppressOutput: false
|
|
114
|
+
})
|
|
115
|
+
exit 1
|
|
116
|
+
end
|
|
117
|
+
end
|
|
165
118
|
|
|
166
119
|
def read_stdin_input
|
|
167
120
|
stdin_content = STDIN.read.strip
|
|
168
121
|
return {} if stdin_content.empty?
|
|
169
|
-
|
|
170
122
|
JSON.parse(stdin_content)
|
|
171
123
|
rescue JSON::ParserError => e
|
|
172
124
|
raise "Invalid JSON input: #{e.message}"
|
|
173
125
|
end
|
|
174
|
-
|
|
175
|
-
def handle_error(error, hook_class)
|
|
176
|
-
STDERR.puts "Error in #{hook_class.name} hook: #{error.message}"
|
|
177
|
-
STDERR.puts error.backtrace.join("\n") if error.backtrace
|
|
178
|
-
|
|
179
|
-
# Output error response in Claude Code format
|
|
180
|
-
error_response = {
|
|
181
|
-
continue: false,
|
|
182
|
-
stopReason: "#{hook_class.name} execution error: #{error.message}",
|
|
183
|
-
suppressOutput: false
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
response = JSON.generate(error_response)
|
|
187
|
-
puts response
|
|
188
|
-
STDERR.puts response
|
|
189
|
-
exit 1
|
|
190
|
-
end
|
|
191
126
|
end
|
|
192
127
|
end
|
|
193
|
-
end
|
|
128
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base'
|
|
4
|
+
|
|
5
|
+
module ClaudeHooks
|
|
6
|
+
class DirectoryAdded < Base
|
|
7
|
+
def self.hook_type
|
|
8
|
+
'DirectoryAdded'
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.input_fields
|
|
12
|
+
%w[directory source]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def directory
|
|
16
|
+
@input_data['directory']
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Values: slash_command | register_repo_root
|
|
20
|
+
def source
|
|
21
|
+
@input_data['source']
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base'
|
|
4
|
+
|
|
5
|
+
module ClaudeHooks
|
|
6
|
+
module Output
|
|
7
|
+
# DirectoryAdded is non-blocking — the directory is already added.
|
|
8
|
+
# Only `systemMessage` is consumed (as Claude context for `slash_command`,
|
|
9
|
+
# debug log for `register_repo_root`).
|
|
10
|
+
class DirectoryAdded < Base
|
|
11
|
+
def exit_code
|
|
12
|
+
0
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def self.merge(*outputs)
|
|
16
|
+
merged = super(*outputs)
|
|
17
|
+
new(merged.data)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
data/lib/claude_hooks/version.rb
CHANGED
data/lib/claude_hooks.rb
CHANGED
|
@@ -37,6 +37,7 @@ require_relative "claude_hooks/permission_denied"
|
|
|
37
37
|
require_relative "claude_hooks/elicitation"
|
|
38
38
|
require_relative "claude_hooks/elicitation_result"
|
|
39
39
|
require_relative "claude_hooks/worktree_create"
|
|
40
|
+
require_relative "claude_hooks/directory_added"
|
|
40
41
|
|
|
41
42
|
# Output classes
|
|
42
43
|
require_relative "claude_hooks/output/base"
|
|
@@ -70,6 +71,7 @@ require_relative "claude_hooks/output/permission_denied"
|
|
|
70
71
|
require_relative "claude_hooks/output/elicitation"
|
|
71
72
|
require_relative "claude_hooks/output/elicitation_result"
|
|
72
73
|
require_relative "claude_hooks/output/worktree_create"
|
|
74
|
+
require_relative "claude_hooks/output/directory_added"
|
|
73
75
|
|
|
74
76
|
module ClaudeHooks
|
|
75
77
|
class Error < StandardError; end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: claude_hooks
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Gabriel Dehan
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-08-15 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: json
|
|
@@ -64,7 +64,6 @@ files:
|
|
|
64
64
|
- ".agents/skills/ci-monitoring/SKILL.md"
|
|
65
65
|
- ".agents/skills/run-tests/SKILL.md"
|
|
66
66
|
- ".claude/auto-fix.md"
|
|
67
|
-
- ".claude/settings.local.json"
|
|
68
67
|
- AGENTS.md
|
|
69
68
|
- CHANGELOG.md
|
|
70
69
|
- README.md
|
|
@@ -74,6 +73,7 @@ files:
|
|
|
74
73
|
- docs/API/COMMON.md
|
|
75
74
|
- docs/API/CONFIG_CHANGE.md
|
|
76
75
|
- docs/API/CWD_CHANGED.md
|
|
76
|
+
- docs/API/DIRECTORY_ADDED.md
|
|
77
77
|
- docs/API/ELICITATION.md
|
|
78
78
|
- docs/API/ELICITATION_RESULT.md
|
|
79
79
|
- docs/API/FILE_CHANGED.md
|
|
@@ -110,10 +110,9 @@ files:
|
|
|
110
110
|
- docs/mitts/setup.md
|
|
111
111
|
- docs/mitts/task.md
|
|
112
112
|
- example_dotclaude/commands/.gitkeep
|
|
113
|
-
- example_dotclaude/hooks/entrypoints/pre_tool_use.rb
|
|
114
113
|
- example_dotclaude/hooks/entrypoints/session_end.rb
|
|
115
114
|
- example_dotclaude/hooks/entrypoints/user_prompt_submit.rb
|
|
116
|
-
- example_dotclaude/hooks/
|
|
115
|
+
- example_dotclaude/hooks/github_guard.rb
|
|
117
116
|
- example_dotclaude/hooks/handlers/session_end/cleanup_handler.rb
|
|
118
117
|
- example_dotclaude/hooks/handlers/session_end/log_session_stats.rb
|
|
119
118
|
- example_dotclaude/hooks/handlers/user_prompt_submit/append_rules.rb
|
|
@@ -126,6 +125,7 @@ files:
|
|
|
126
125
|
- lib/claude_hooks/config_change.rb
|
|
127
126
|
- lib/claude_hooks/configuration.rb
|
|
128
127
|
- lib/claude_hooks/cwd_changed.rb
|
|
128
|
+
- lib/claude_hooks/directory_added.rb
|
|
129
129
|
- lib/claude_hooks/elicitation.rb
|
|
130
130
|
- lib/claude_hooks/elicitation_result.rb
|
|
131
131
|
- lib/claude_hooks/file_changed.rb
|
|
@@ -136,6 +136,7 @@ files:
|
|
|
136
136
|
- lib/claude_hooks/output/base.rb
|
|
137
137
|
- lib/claude_hooks/output/config_change.rb
|
|
138
138
|
- lib/claude_hooks/output/cwd_changed.rb
|
|
139
|
+
- lib/claude_hooks/output/directory_added.rb
|
|
139
140
|
- lib/claude_hooks/output/elicitation.rb
|
|
140
141
|
- lib/claude_hooks/output/elicitation_result.rb
|
|
141
142
|
- lib/claude_hooks/output/file_changed.rb
|
data/.claude/settings.local.json
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"env": {
|
|
3
|
-
"CLAUDE_CODE_SUBAGENT_MODEL": "sonnet"
|
|
4
|
-
},
|
|
5
|
-
"permissions": {
|
|
6
|
-
"allow": [
|
|
7
|
-
"Read(//Users/gdehan/**)",
|
|
8
|
-
"Read(//Users/gdehan/.config/**)",
|
|
9
|
-
"Bash(herdr --help)",
|
|
10
|
-
"Bash(herdr config *)",
|
|
11
|
-
"Bash(herdr api *)",
|
|
12
|
-
"Bash(python3 -m json.tool)",
|
|
13
|
-
"Bash(python3 -c \"import sys,json; d=json.load\\(sys.stdin\\); print\\(list\\(d.keys\\(\\)\\)\\)\")",
|
|
14
|
-
"Bash(python3 -c \"import sys,json; d=json.load\\(sys.stdin\\); print\\(json.dumps\\(list\\(d.keys\\(\\)\\), indent=2\\)\\)\")",
|
|
15
|
-
"Bash(python3 -c ' *)",
|
|
16
|
-
"Bash(herdr server *)",
|
|
17
|
-
"WebFetch(domain:opencode.ai)",
|
|
18
|
-
"Bash(ruby *)"
|
|
19
|
-
]
|
|
20
|
-
}
|
|
21
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
require 'claude_hooks'
|
|
5
|
-
require_relative '../handlers/pre_tool_use/github_guard'
|
|
6
|
-
|
|
7
|
-
begin
|
|
8
|
-
# Read Claude Code input from stdin
|
|
9
|
-
input_data = JSON.parse($stdin.read)
|
|
10
|
-
|
|
11
|
-
github_guard = GithubGuard.new(input_data)
|
|
12
|
-
github_guard.call
|
|
13
|
-
|
|
14
|
-
github_guard.output_and_exit
|
|
15
|
-
rescue StandardError => e
|
|
16
|
-
puts JSON.generate(
|
|
17
|
-
{
|
|
18
|
-
continue: false,
|
|
19
|
-
stopReason: "Error in PreToolUse hook, #{e.message}, #{e.backtrace.join("\n")}",
|
|
20
|
-
suppressOutput: false,
|
|
21
|
-
},
|
|
22
|
-
)
|
|
23
|
-
# Allow anyway, to not block developers if there is an issue with the hook
|
|
24
|
-
exit 1
|
|
25
|
-
end
|