claude_hooks 1.2.1 → 1.4.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 +47 -0
- data/README.md +21 -15
- data/docs/API/COMMON.md +4 -3
- data/docs/API/DIRECTORY_ADDED.md +34 -0
- data/docs/API/NOTIFICATION.md +5 -4
- data/docs/API/PERMISSION_DENIED.md +4 -0
- data/docs/API/PERMISSION_REQUEST.md +3 -3
- data/docs/API/POST_MODEL_SWITCH.md +53 -0
- data/docs/API/POST_TOOL_USE.md +7 -0
- data/docs/API/POST_TOOL_USE_FAILURE.md +1 -0
- data/docs/API/PRE_MODEL_SWITCH.md +67 -0
- data/docs/API/PRE_TOOL_USE.md +1 -0
- data/docs/API/SESSION_START.md +7 -1
- data/docs/API/SETUP.md +3 -3
- data/docs/API/STOP.md +6 -0
- data/docs/API/SUBAGENT_STOP.md +10 -0
- data/docs/API/TASK_CREATED.md +9 -7
- data/docs/API/USER_PROMPT_SUBMIT.md +14 -0
- data/docs/API/WORKTREE_REMOVE.md +9 -4
- data/docs/external/claude-hooks-reference.md +1188 -345
- data/docs/mitts/prd.md +8 -0
- data/docs/mitts/setup.md +5 -3
- data/lib/claude_hooks/base.rb +12 -0
- data/lib/claude_hooks/directory_added.rb +24 -0
- data/lib/claude_hooks/output/base.rb +6 -0
- data/lib/claude_hooks/output/directory_added.rb +21 -0
- data/lib/claude_hooks/output/notification.rb +10 -1
- data/lib/claude_hooks/output/post_model_switch.rb +50 -0
- data/lib/claude_hooks/output/post_tool_batch.rb +10 -0
- data/lib/claude_hooks/output/post_tool_use.rb +23 -5
- data/lib/claude_hooks/output/pre_model_switch.rb +121 -0
- data/lib/claude_hooks/output/pre_tool_use.rb +8 -0
- data/lib/claude_hooks/output/task_created.rb +34 -1
- data/lib/claude_hooks/output/user_prompt_expansion.rb +10 -0
- data/lib/claude_hooks/output/user_prompt_submit.rb +19 -6
- data/lib/claude_hooks/output/worktree_remove.rb +4 -2
- data/lib/claude_hooks/permission_denied.rb +7 -0
- data/lib/claude_hooks/permission_request.rb +10 -1
- data/lib/claude_hooks/post_model_switch.rb +70 -0
- data/lib/claude_hooks/post_tool_use.rb +14 -0
- data/lib/claude_hooks/post_tool_use_failure.rb +7 -0
- data/lib/claude_hooks/pre_model_switch.rb +90 -0
- data/lib/claude_hooks/pre_tool_use.rb +7 -0
- data/lib/claude_hooks/session_start.rb +18 -0
- data/lib/claude_hooks/setup.rb +3 -0
- data/lib/claude_hooks/task_created.rb +17 -0
- data/lib/claude_hooks/user_prompt_submit.rb +26 -5
- data/lib/claude_hooks/version.rb +1 -1
- data/lib/claude_hooks.rb +6 -0
- metadata +11 -2
|
@@ -30,6 +30,13 @@ module ClaudeHooks
|
|
|
30
30
|
@input_data['tool_use_id'] || @input_data['toolUseId']
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
+
# For MCP tools: { 'name' => ..., 'source' => ... } describing where the server's
|
|
34
|
+
# definition came from (e.g. 'plugin', 'sdk', 'user', 'project'). Base trust
|
|
35
|
+
# decisions on 'source', not on the name. nil for non-MCP tools. Requires Claude Code v2.1.274+.
|
|
36
|
+
def mcp_server
|
|
37
|
+
@input_data['mcp_server'] || @input_data['mcpServer']
|
|
38
|
+
end
|
|
39
|
+
|
|
33
40
|
# === OUTPUT DATA HELPERS ===
|
|
34
41
|
|
|
35
42
|
def block_tool!(reason = '')
|
|
@@ -59,5 +66,12 @@ module ClaudeHooks
|
|
|
59
66
|
@output_data['hookSpecificOutput'] ||= { 'hookEventName' => hook_event_name }
|
|
60
67
|
@output_data['hookSpecificOutput']['updatedMCPToolOutput'] = value
|
|
61
68
|
end
|
|
69
|
+
|
|
70
|
+
# Annotate this call's result for the auto-mode classifier (not for Claude).
|
|
71
|
+
# Requires Claude Code v2.1.236 or later.
|
|
72
|
+
def classifier_context!(note)
|
|
73
|
+
@output_data['hookSpecificOutput'] ||= { 'hookEventName' => hook_event_name }
|
|
74
|
+
@output_data['hookSpecificOutput']['classifierContext'] = note
|
|
75
|
+
end
|
|
62
76
|
end
|
|
63
77
|
end
|
|
@@ -24,6 +24,13 @@ module ClaudeHooks
|
|
|
24
24
|
@input_data['tool_use_id'] || @input_data['toolUseId']
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
+
# For MCP tools: { 'name' => ..., 'source' => ... } describing where the server's
|
|
28
|
+
# definition came from (e.g. 'plugin', 'sdk', 'user', 'project'). Base trust
|
|
29
|
+
# decisions on 'source', not on the name. nil for non-MCP tools. Requires Claude Code v2.1.274+.
|
|
30
|
+
def mcp_server
|
|
31
|
+
@input_data['mcp_server'] || @input_data['mcpServer']
|
|
32
|
+
end
|
|
33
|
+
|
|
27
34
|
def error
|
|
28
35
|
@input_data['error']
|
|
29
36
|
end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base'
|
|
4
|
+
|
|
5
|
+
module ClaudeHooks
|
|
6
|
+
class PreModelSwitch < Base
|
|
7
|
+
def self.hook_type
|
|
8
|
+
'PreModelSwitch'
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.input_fields
|
|
12
|
+
%w[from_model to_model requested_model source]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# === INPUT DATA ACCESS ===
|
|
16
|
+
|
|
17
|
+
def from_model
|
|
18
|
+
@input_data['from_model'] || @input_data['fromModel']
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def to_model
|
|
22
|
+
@input_data['to_model'] || @input_data['toModel']
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def requested_model
|
|
26
|
+
@input_data['requested_model'] || @input_data['requestedModel']
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def source
|
|
30
|
+
@input_data['source']
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def context_tokens
|
|
34
|
+
@input_data['context_tokens'] || @input_data['contextTokens']
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def prompt_cache_warm
|
|
38
|
+
@input_data.key?('prompt_cache_warm') ? @input_data['prompt_cache_warm'] : @input_data['promptCacheWarm']
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def cache_ttl
|
|
42
|
+
@input_data['cache_ttl'] || @input_data['cacheTtl']
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def estimated_cache_write_usd
|
|
46
|
+
@input_data['estimated_cache_write_usd'] || @input_data['estimatedCacheWriteUsd']
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def pricing
|
|
50
|
+
@input_data['pricing']
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# === OUTPUT DATA HELPERS ===
|
|
54
|
+
#
|
|
55
|
+
# PreModelSwitch mirrors PreToolUse's permissionDecision API (allow/deny/ask).
|
|
56
|
+
# It does not accept 'defer', 'updatedInput', or 'additionalContext'.
|
|
57
|
+
|
|
58
|
+
def approve!(reason = '')
|
|
59
|
+
@output_data['hookSpecificOutput'] = {
|
|
60
|
+
'hookEventName' => hook_event_name,
|
|
61
|
+
'permissionDecision' => 'allow',
|
|
62
|
+
'permissionDecisionReason' => reason
|
|
63
|
+
}
|
|
64
|
+
end
|
|
65
|
+
alias_method :allow!, :approve!
|
|
66
|
+
|
|
67
|
+
def deny!(reason = '')
|
|
68
|
+
@output_data['hookSpecificOutput'] = {
|
|
69
|
+
'hookEventName' => hook_event_name,
|
|
70
|
+
'permissionDecision' => 'deny',
|
|
71
|
+
'permissionDecisionReason' => reason
|
|
72
|
+
}
|
|
73
|
+
end
|
|
74
|
+
alias_method :block_switch!, :deny!
|
|
75
|
+
|
|
76
|
+
def ask!(reason = '')
|
|
77
|
+
@output_data['hookSpecificOutput'] = {
|
|
78
|
+
'hookEventName' => hook_event_name,
|
|
79
|
+
'permissionDecision' => 'ask',
|
|
80
|
+
'permissionDecisionReason' => reason
|
|
81
|
+
}
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Top-level decision:block also cancels the switch (equivalent to exit 2).
|
|
85
|
+
def block!(reason = '')
|
|
86
|
+
@output_data['decision'] = 'block'
|
|
87
|
+
@output_data['reason'] = reason
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
@@ -26,6 +26,13 @@ module ClaudeHooks
|
|
|
26
26
|
@input_data['tool_use_id'] || @input_data['toolUseId']
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
+
# For MCP tools: { 'name' => ..., 'source' => ... } describing where the server's
|
|
30
|
+
# definition came from (e.g. 'plugin', 'sdk', 'user', 'project'). Base trust
|
|
31
|
+
# decisions on 'source', not on the name. nil for non-MCP tools. Requires Claude Code v2.1.274+.
|
|
32
|
+
def mcp_server
|
|
33
|
+
@input_data['mcp_server'] || @input_data['mcpServer']
|
|
34
|
+
end
|
|
35
|
+
|
|
29
36
|
# === OUTPUT DATA HELPERS ===
|
|
30
37
|
|
|
31
38
|
def approve_tool!(reason = '')
|
|
@@ -26,6 +26,24 @@ module ClaudeHooks
|
|
|
26
26
|
@input_data['session_title'] || @input_data['sessionTitle']
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
+
# Optional cost/context fields present when source is "resume" or "fork".
|
|
30
|
+
|
|
31
|
+
def seconds_since_last_response
|
|
32
|
+
@input_data['seconds_since_last_response'] || @input_data['secondsSinceLastResponse']
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def context_tokens
|
|
36
|
+
@input_data['context_tokens'] || @input_data['contextTokens']
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def prompt_cache_likely_expired
|
|
40
|
+
@input_data.key?('prompt_cache_likely_expired') ? @input_data['prompt_cache_likely_expired'] : @input_data['promptCacheLikelyExpired']
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def estimated_cache_write_usd
|
|
44
|
+
@input_data['estimated_cache_write_usd'] || @input_data['estimatedCacheWriteUsd']
|
|
45
|
+
end
|
|
46
|
+
|
|
29
47
|
# === OUTPUT DATA HELPERS ===
|
|
30
48
|
|
|
31
49
|
def add_additional_context!(context)
|
data/lib/claude_hooks/setup.rb
CHANGED
|
@@ -16,6 +16,9 @@ module ClaudeHooks
|
|
|
16
16
|
@input_data['source']
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
+
# DEPRECATED: Claude Code now discards all Setup JSON output, including
|
|
20
|
+
# hookSpecificOutput.additionalContext. Kept for backward compatibility, but
|
|
21
|
+
# this no longer adds context — use a SessionStart hook to inject context instead.
|
|
19
22
|
def add_additional_context!(context)
|
|
20
23
|
@output_data['hookSpecificOutput'] ||= { 'hookEventName' => hook_event_name }
|
|
21
24
|
@output_data['hookSpecificOutput']['additionalContext'] = context
|
|
@@ -31,5 +31,22 @@ module ClaudeHooks
|
|
|
31
31
|
def team_name
|
|
32
32
|
@input_data['team_name'] || @input_data['teamName']
|
|
33
33
|
end
|
|
34
|
+
|
|
35
|
+
# === OUTPUT DATA HELPERS ===
|
|
36
|
+
#
|
|
37
|
+
# Claude Code ignores `continue: false` for TaskCreated. Block task creation
|
|
38
|
+
# either by exiting 2 or with a top-level decision:block; `reason` is returned
|
|
39
|
+
# to Claude as the task-creation error.
|
|
40
|
+
|
|
41
|
+
def block!(reason = '')
|
|
42
|
+
@output_data['decision'] = 'block'
|
|
43
|
+
@output_data['reason'] = reason
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def allow!
|
|
47
|
+
@output_data['decision'] = nil
|
|
48
|
+
@output_data['reason'] = nil
|
|
49
|
+
end
|
|
50
|
+
alias_method :unblock!, :allow!
|
|
34
51
|
end
|
|
35
52
|
end
|
|
@@ -20,18 +20,39 @@ module ClaudeHooks
|
|
|
20
20
|
alias_method :user_prompt, :prompt
|
|
21
21
|
alias_method :current_prompt, :prompt
|
|
22
22
|
|
|
23
|
+
# The session's custom title, when one is set. Requires Claude Code to send it
|
|
24
|
+
# (same meaning as SessionStart's session_title).
|
|
25
|
+
def session_title
|
|
26
|
+
@input_data['session_title'] || @input_data['sessionTitle']
|
|
27
|
+
end
|
|
28
|
+
|
|
23
29
|
# === OUTPUT DATA HELPERS ===
|
|
24
30
|
|
|
25
31
|
def add_additional_context!(context)
|
|
26
|
-
@output_data['hookSpecificOutput']
|
|
27
|
-
|
|
28
|
-
'additionalContext' => context
|
|
29
|
-
}
|
|
32
|
+
@output_data['hookSpecificOutput'] ||= { 'hookEventName' => hook_event_name }
|
|
33
|
+
@output_data['hookSpecificOutput']['additionalContext'] = context
|
|
30
34
|
end
|
|
31
35
|
alias_method :add_context!, :add_additional_context!
|
|
32
36
|
|
|
33
37
|
def empty_additional_context!
|
|
34
|
-
@output_data['hookSpecificOutput']
|
|
38
|
+
hso = @output_data['hookSpecificOutput']
|
|
39
|
+
return unless hso
|
|
40
|
+
|
|
41
|
+
hso.delete('additionalContext')
|
|
42
|
+
@output_data['hookSpecificOutput'] = nil if hso.keys == ['hookEventName']
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def session_title!(title)
|
|
46
|
+
@output_data['hookSpecificOutput'] ||= { 'hookEventName' => hook_event_name }
|
|
47
|
+
@output_data['hookSpecificOutput']['sessionTitle'] = title
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# When the prompt is blocked (block_prompt! or exit 2), leave the prompt text out
|
|
51
|
+
# of the block message shown to the user and written to the transcript. Doesn't
|
|
52
|
+
# remove it from other local files such as prompt history.
|
|
53
|
+
def suppress_original_prompt!(value = true)
|
|
54
|
+
@output_data['hookSpecificOutput'] ||= { 'hookEventName' => hook_event_name }
|
|
55
|
+
@output_data['hookSpecificOutput']['suppressOriginalPrompt'] = value
|
|
35
56
|
end
|
|
36
57
|
|
|
37
58
|
def block_prompt!(reason = '')
|
data/lib/claude_hooks/version.rb
CHANGED
data/lib/claude_hooks.rb
CHANGED
|
@@ -37,6 +37,9 @@ 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"
|
|
41
|
+
require_relative "claude_hooks/pre_model_switch"
|
|
42
|
+
require_relative "claude_hooks/post_model_switch"
|
|
40
43
|
|
|
41
44
|
# Output classes
|
|
42
45
|
require_relative "claude_hooks/output/base"
|
|
@@ -70,6 +73,9 @@ require_relative "claude_hooks/output/permission_denied"
|
|
|
70
73
|
require_relative "claude_hooks/output/elicitation"
|
|
71
74
|
require_relative "claude_hooks/output/elicitation_result"
|
|
72
75
|
require_relative "claude_hooks/output/worktree_create"
|
|
76
|
+
require_relative "claude_hooks/output/directory_added"
|
|
77
|
+
require_relative "claude_hooks/output/pre_model_switch"
|
|
78
|
+
require_relative "claude_hooks/output/post_model_switch"
|
|
73
79
|
|
|
74
80
|
module ClaudeHooks
|
|
75
81
|
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.4.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-10-14 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: json
|
|
@@ -73,6 +73,7 @@ files:
|
|
|
73
73
|
- docs/API/COMMON.md
|
|
74
74
|
- docs/API/CONFIG_CHANGE.md
|
|
75
75
|
- docs/API/CWD_CHANGED.md
|
|
76
|
+
- docs/API/DIRECTORY_ADDED.md
|
|
76
77
|
- docs/API/ELICITATION.md
|
|
77
78
|
- docs/API/ELICITATION_RESULT.md
|
|
78
79
|
- docs/API/FILE_CHANGED.md
|
|
@@ -82,10 +83,12 @@ files:
|
|
|
82
83
|
- docs/API/PERMISSION_DENIED.md
|
|
83
84
|
- docs/API/PERMISSION_REQUEST.md
|
|
84
85
|
- docs/API/POST_COMPACT.md
|
|
86
|
+
- docs/API/POST_MODEL_SWITCH.md
|
|
85
87
|
- docs/API/POST_TOOL_BATCH.md
|
|
86
88
|
- docs/API/POST_TOOL_USE.md
|
|
87
89
|
- docs/API/POST_TOOL_USE_FAILURE.md
|
|
88
90
|
- docs/API/PRE_COMPACT.md
|
|
91
|
+
- docs/API/PRE_MODEL_SWITCH.md
|
|
89
92
|
- docs/API/PRE_TOOL_USE.md
|
|
90
93
|
- docs/API/SESSION_END.md
|
|
91
94
|
- docs/API/SESSION_START.md
|
|
@@ -124,6 +127,7 @@ files:
|
|
|
124
127
|
- lib/claude_hooks/config_change.rb
|
|
125
128
|
- lib/claude_hooks/configuration.rb
|
|
126
129
|
- lib/claude_hooks/cwd_changed.rb
|
|
130
|
+
- lib/claude_hooks/directory_added.rb
|
|
127
131
|
- lib/claude_hooks/elicitation.rb
|
|
128
132
|
- lib/claude_hooks/elicitation_result.rb
|
|
129
133
|
- lib/claude_hooks/file_changed.rb
|
|
@@ -134,6 +138,7 @@ files:
|
|
|
134
138
|
- lib/claude_hooks/output/base.rb
|
|
135
139
|
- lib/claude_hooks/output/config_change.rb
|
|
136
140
|
- lib/claude_hooks/output/cwd_changed.rb
|
|
141
|
+
- lib/claude_hooks/output/directory_added.rb
|
|
137
142
|
- lib/claude_hooks/output/elicitation.rb
|
|
138
143
|
- lib/claude_hooks/output/elicitation_result.rb
|
|
139
144
|
- lib/claude_hooks/output/file_changed.rb
|
|
@@ -143,10 +148,12 @@ files:
|
|
|
143
148
|
- lib/claude_hooks/output/permission_denied.rb
|
|
144
149
|
- lib/claude_hooks/output/permission_request.rb
|
|
145
150
|
- lib/claude_hooks/output/post_compact.rb
|
|
151
|
+
- lib/claude_hooks/output/post_model_switch.rb
|
|
146
152
|
- lib/claude_hooks/output/post_tool_batch.rb
|
|
147
153
|
- lib/claude_hooks/output/post_tool_use.rb
|
|
148
154
|
- lib/claude_hooks/output/post_tool_use_failure.rb
|
|
149
155
|
- lib/claude_hooks/output/pre_compact.rb
|
|
156
|
+
- lib/claude_hooks/output/pre_model_switch.rb
|
|
150
157
|
- lib/claude_hooks/output/pre_tool_use.rb
|
|
151
158
|
- lib/claude_hooks/output/session_end.rb
|
|
152
159
|
- lib/claude_hooks/output/session_start.rb
|
|
@@ -165,10 +172,12 @@ files:
|
|
|
165
172
|
- lib/claude_hooks/permission_denied.rb
|
|
166
173
|
- lib/claude_hooks/permission_request.rb
|
|
167
174
|
- lib/claude_hooks/post_compact.rb
|
|
175
|
+
- lib/claude_hooks/post_model_switch.rb
|
|
168
176
|
- lib/claude_hooks/post_tool_batch.rb
|
|
169
177
|
- lib/claude_hooks/post_tool_use.rb
|
|
170
178
|
- lib/claude_hooks/post_tool_use_failure.rb
|
|
171
179
|
- lib/claude_hooks/pre_compact.rb
|
|
180
|
+
- lib/claude_hooks/pre_model_switch.rb
|
|
172
181
|
- lib/claude_hooks/pre_tool_use.rb
|
|
173
182
|
- lib/claude_hooks/session_end.rb
|
|
174
183
|
- lib/claude_hooks/session_start.rb
|