claude_hooks 1.1.0 → 1.2.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/.agents/skills/ci-monitoring/SKILL.md +103 -0
- data/.agents/skills/run-tests/SKILL.md +45 -0
- data/.claude/settings.local.json +21 -0
- data/AGENTS.md +46 -0
- data/CHANGELOG.md +43 -0
- data/README.md +156 -21
- data/docs/API/COMMON.md +7 -1
- data/docs/API/CONFIG_CHANGE.md +39 -0
- data/docs/API/CWD_CHANGED.md +34 -0
- data/docs/API/ELICITATION.md +44 -0
- data/docs/API/ELICITATION_RESULT.md +43 -0
- data/docs/API/FILE_CHANGED.md +37 -0
- data/docs/API/INSTRUCTIONS_LOADED.md +30 -0
- data/docs/API/MESSAGE_DISPLAY.md +38 -0
- data/docs/API/PERMISSION_DENIED.md +37 -0
- data/docs/API/PERMISSION_REQUEST.md +11 -8
- data/docs/API/POST_COMPACT.md +30 -0
- data/docs/API/POST_TOOL_BATCH.md +39 -0
- data/docs/API/POST_TOOL_USE_FAILURE.md +31 -0
- data/docs/API/PRE_COMPACT.md +10 -2
- data/docs/API/PRE_TOOL_USE.md +5 -1
- data/docs/API/SETUP.md +37 -0
- data/docs/API/STOP_FAILURE.md +19 -0
- data/docs/API/SUBAGENT_START.md +40 -0
- data/docs/API/TASK_COMPLETED.md +43 -0
- data/docs/API/TASK_CREATED.md +43 -0
- data/docs/API/TEAMMATE_IDLE.md +40 -0
- data/docs/API/USER_PROMPT_EXPANSION.md +43 -0
- data/docs/API/WORKTREE_CREATE.md +39 -0
- data/docs/API/WORKTREE_REMOVE.md +33 -0
- data/docs/PROMPT_BASED_HOOKS.md +386 -0
- data/docs/external/claude-hooks-reference.md +2406 -854
- data/docs/mitts/ideabox.md +12 -0
- data/docs/mitts/prd.md +417 -0
- data/docs/mitts/setup.md +303 -0
- data/docs/mitts/task.md +44 -0
- data/lib/claude_hooks/base.rb +25 -0
- data/lib/claude_hooks/config_change.rb +28 -0
- data/lib/claude_hooks/cwd_changed.rb +28 -0
- data/lib/claude_hooks/elicitation.rb +61 -0
- data/lib/claude_hooks/elicitation_result.rb +57 -0
- data/lib/claude_hooks/file_changed.rb +41 -0
- data/lib/claude_hooks/instructions_loaded.rb +23 -0
- data/lib/claude_hooks/message_display.rb +58 -0
- data/lib/claude_hooks/output/base.rb +46 -1
- data/lib/claude_hooks/output/config_change.rb +47 -0
- data/lib/claude_hooks/output/cwd_changed.rb +42 -0
- data/lib/claude_hooks/output/elicitation.rb +67 -0
- data/lib/claude_hooks/output/elicitation_result.rb +63 -0
- data/lib/claude_hooks/output/file_changed.rb +42 -0
- data/lib/claude_hooks/output/instructions_loaded.rb +19 -0
- data/lib/claude_hooks/output/message_display.rb +49 -0
- data/lib/claude_hooks/output/permission_denied.rb +42 -0
- data/lib/claude_hooks/output/permission_request.rb +50 -25
- data/lib/claude_hooks/output/post_compact.rb +18 -0
- data/lib/claude_hooks/output/post_tool_batch.rb +51 -0
- data/lib/claude_hooks/output/post_tool_use.rb +12 -0
- data/lib/claude_hooks/output/post_tool_use_failure.rb +42 -0
- data/lib/claude_hooks/output/pre_compact.rb +34 -3
- data/lib/claude_hooks/output/pre_tool_use.rb +8 -2
- data/lib/claude_hooks/output/session_start.rb +30 -8
- data/lib/claude_hooks/output/setup.rb +42 -0
- data/lib/claude_hooks/output/stop.rb +15 -0
- data/lib/claude_hooks/output/stop_failure.rb +19 -0
- data/lib/claude_hooks/output/subagent_start.rb +42 -0
- data/lib/claude_hooks/output/task_completed.rb +18 -0
- data/lib/claude_hooks/output/task_created.rb +18 -0
- data/lib/claude_hooks/output/teammate_idle.rb +18 -0
- data/lib/claude_hooks/output/user_prompt_expansion.rb +51 -0
- data/lib/claude_hooks/output/worktree_create.rb +60 -0
- data/lib/claude_hooks/output/worktree_remove.rb +19 -0
- data/lib/claude_hooks/permission_denied.rb +41 -0
- data/lib/claude_hooks/permission_request.rb +16 -9
- data/lib/claude_hooks/post_compact.rb +23 -0
- data/lib/claude_hooks/post_tool_batch.rb +59 -0
- data/lib/claude_hooks/post_tool_use.rb +10 -0
- data/lib/claude_hooks/post_tool_use_failure.rb +45 -0
- data/lib/claude_hooks/pre_compact.rb +7 -0
- data/lib/claude_hooks/pre_tool_use.rb +20 -2
- data/lib/claude_hooks/session_start.rb +28 -0
- data/lib/claude_hooks/setup.rb +25 -0
- data/lib/claude_hooks/stop.rb +17 -0
- data/lib/claude_hooks/stop_failure.rb +27 -0
- data/lib/claude_hooks/subagent_start.rb +23 -0
- data/lib/claude_hooks/subagent_stop.rb +5 -1
- data/lib/claude_hooks/task_completed.rb +35 -0
- data/lib/claude_hooks/task_created.rb +35 -0
- data/lib/claude_hooks/teammate_idle.rb +23 -0
- data/lib/claude_hooks/user_prompt_expansion.rb +45 -0
- data/lib/claude_hooks/version.rb +1 -1
- data/lib/claude_hooks/worktree_create.rb +27 -0
- data/lib/claude_hooks/worktree_remove.rb +19 -0
- data/lib/claude_hooks.rb +40 -0
- metadata +71 -2
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base'
|
|
4
|
+
|
|
5
|
+
module ClaudeHooks
|
|
6
|
+
class PostToolBatch < Base
|
|
7
|
+
def self.hook_type
|
|
8
|
+
'PostToolBatch'
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.input_fields
|
|
12
|
+
%w[tool_calls]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def tool_calls
|
|
16
|
+
@input_data['tool_calls'] || @input_data['toolCalls'] || []
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Convenience partitions over tool_calls. Entries carry a `tool_response`
|
|
20
|
+
# rather than an explicit success flag, so success is derived from the
|
|
21
|
+
# presence of a response that isn't flagged as an error. When your payload
|
|
22
|
+
# shape differs, use the raw `tool_calls` array instead.
|
|
23
|
+
def succeeded_calls
|
|
24
|
+
tool_calls.reject { |call| failed_call?(call) }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def failed_calls
|
|
28
|
+
tool_calls.select { |call| failed_call?(call) }
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def block!(reason = '')
|
|
32
|
+
@output_data['decision'] = 'block'
|
|
33
|
+
@output_data['reason'] = reason
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def add_additional_context!(context)
|
|
37
|
+
@output_data['hookSpecificOutput'] ||= { 'hookEventName' => hook_event_name }
|
|
38
|
+
@output_data['hookSpecificOutput']['additionalContext'] = context
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
# A call is considered failed when its response is missing or carries an
|
|
44
|
+
# error marker (`is_error`/`isError` true, or an `error` key).
|
|
45
|
+
def failed_call?(call)
|
|
46
|
+
return true unless call.is_a?(Hash)
|
|
47
|
+
|
|
48
|
+
response = call['tool_response'] || call['toolResponse']
|
|
49
|
+
return true if response.nil?
|
|
50
|
+
|
|
51
|
+
if response.is_a?(Hash)
|
|
52
|
+
return true if response['is_error'] == true || response['isError'] == true
|
|
53
|
+
return true if response.key?('error') && !response['error'].nil?
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
false
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -49,5 +49,15 @@ module ClaudeHooks
|
|
|
49
49
|
}
|
|
50
50
|
end
|
|
51
51
|
alias_method :add_context!, :add_additional_context!
|
|
52
|
+
|
|
53
|
+
def update_tool_output!(value)
|
|
54
|
+
@output_data['hookSpecificOutput'] ||= { 'hookEventName' => hook_event_name }
|
|
55
|
+
@output_data['hookSpecificOutput']['updatedToolOutput'] = value
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def update_mcp_tool_output!(value)
|
|
59
|
+
@output_data['hookSpecificOutput'] ||= { 'hookEventName' => hook_event_name }
|
|
60
|
+
@output_data['hookSpecificOutput']['updatedMCPToolOutput'] = value
|
|
61
|
+
end
|
|
52
62
|
end
|
|
53
63
|
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base'
|
|
4
|
+
|
|
5
|
+
module ClaudeHooks
|
|
6
|
+
class PostToolUseFailure < Base
|
|
7
|
+
def self.hook_type
|
|
8
|
+
'PostToolUseFailure'
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.input_fields
|
|
12
|
+
%w[tool_name tool_input tool_use_id error]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def tool_name
|
|
16
|
+
@input_data['tool_name']
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def tool_input
|
|
20
|
+
@input_data['tool_input']
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def tool_use_id
|
|
24
|
+
@input_data['tool_use_id'] || @input_data['toolUseId']
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def error
|
|
28
|
+
@input_data['error']
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def is_interrupt
|
|
32
|
+
@input_data.key?('is_interrupt') ? @input_data['is_interrupt'] : @input_data['isInterrupt']
|
|
33
|
+
end
|
|
34
|
+
alias_method :interrupt?, :is_interrupt
|
|
35
|
+
|
|
36
|
+
def duration_ms
|
|
37
|
+
@input_data['duration_ms'] || @input_data['durationMs']
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def add_additional_context!(context)
|
|
41
|
+
@output_data['hookSpecificOutput'] ||= { 'hookEventName' => hook_event_name }
|
|
42
|
+
@output_data['hookSpecificOutput']['additionalContext'] = context
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -27,6 +27,13 @@ module ClaudeHooks
|
|
|
27
27
|
end
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
+
# === OUTPUT DATA HELPERS ===
|
|
31
|
+
|
|
32
|
+
def block!(reason = '')
|
|
33
|
+
@output_data['decision'] = 'block'
|
|
34
|
+
@output_data['reason'] = reason
|
|
35
|
+
end
|
|
36
|
+
|
|
30
37
|
# === UTILITY HELPERS ===
|
|
31
38
|
|
|
32
39
|
def backup_transcript!(backup_file_path)
|
|
@@ -58,9 +58,27 @@ module ClaudeHooks
|
|
|
58
58
|
'permissionDecision' => 'allow'
|
|
59
59
|
}
|
|
60
60
|
@output_data['hookSpecificOutput']['updatedInput'] = updated_input
|
|
61
|
-
|
|
62
|
-
# Ensure permission decision is 'allow' when updating input
|
|
63
61
|
@output_data['hookSpecificOutput']['permissionDecision'] = 'allow'
|
|
64
62
|
end
|
|
63
|
+
|
|
64
|
+
def defer_permission!
|
|
65
|
+
@output_data['hookSpecificOutput'] = {
|
|
66
|
+
'hookEventName' => hook_event_name,
|
|
67
|
+
'permissionDecision' => 'defer'
|
|
68
|
+
}
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def update_input!(updated_input)
|
|
72
|
+
@output_data['hookSpecificOutput'] ||= {
|
|
73
|
+
'hookEventName' => hook_event_name,
|
|
74
|
+
'permissionDecision' => 'allow'
|
|
75
|
+
}
|
|
76
|
+
@output_data['hookSpecificOutput']['updatedInput'] = updated_input
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def add_additional_context!(context)
|
|
80
|
+
@output_data['hookSpecificOutput'] ||= { 'hookEventName' => hook_event_name }
|
|
81
|
+
@output_data['hookSpecificOutput']['additionalContext'] = context
|
|
82
|
+
end
|
|
65
83
|
end
|
|
66
84
|
end
|
|
@@ -18,6 +18,14 @@ module ClaudeHooks
|
|
|
18
18
|
@input_data['source']
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
+
def model
|
|
22
|
+
@input_data['model']
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def session_title
|
|
26
|
+
@input_data['session_title'] || @input_data['sessionTitle']
|
|
27
|
+
end
|
|
28
|
+
|
|
21
29
|
# === OUTPUT DATA HELPERS ===
|
|
22
30
|
|
|
23
31
|
def add_additional_context!(context)
|
|
@@ -31,5 +39,25 @@ module ClaudeHooks
|
|
|
31
39
|
def empty_additional_context!
|
|
32
40
|
@output_data['hookSpecificOutput'] = nil
|
|
33
41
|
end
|
|
42
|
+
|
|
43
|
+
def session_title!(title)
|
|
44
|
+
@output_data['hookSpecificOutput'] ||= { 'hookEventName' => hook_event_name }
|
|
45
|
+
@output_data['hookSpecificOutput']['sessionTitle'] = title
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def initial_user_message!(message)
|
|
49
|
+
@output_data['hookSpecificOutput'] ||= { 'hookEventName' => hook_event_name }
|
|
50
|
+
@output_data['hookSpecificOutput']['initialUserMessage'] = message
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def watch_paths!(paths)
|
|
54
|
+
@output_data['hookSpecificOutput'] ||= { 'hookEventName' => hook_event_name }
|
|
55
|
+
@output_data['hookSpecificOutput']['watchPaths'] = Array(paths)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def reload_skills!(value = true)
|
|
59
|
+
@output_data['hookSpecificOutput'] ||= { 'hookEventName' => hook_event_name }
|
|
60
|
+
@output_data['hookSpecificOutput']['reloadSkills'] = value
|
|
61
|
+
end
|
|
34
62
|
end
|
|
35
63
|
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base'
|
|
4
|
+
|
|
5
|
+
module ClaudeHooks
|
|
6
|
+
class Setup < Base
|
|
7
|
+
def self.hook_type
|
|
8
|
+
'Setup'
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.input_fields
|
|
12
|
+
%w[source]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def source
|
|
16
|
+
@input_data['source']
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def add_additional_context!(context)
|
|
20
|
+
@output_data['hookSpecificOutput'] ||= { 'hookEventName' => hook_event_name }
|
|
21
|
+
@output_data['hookSpecificOutput']['additionalContext'] = context
|
|
22
|
+
end
|
|
23
|
+
alias_method :add_context!, :add_additional_context!
|
|
24
|
+
end
|
|
25
|
+
end
|
data/lib/claude_hooks/stop.rb
CHANGED
|
@@ -26,6 +26,18 @@ module ClaudeHooks
|
|
|
26
26
|
@input_data['stop_hook_active']
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
+
def last_assistant_message
|
|
30
|
+
@input_data['last_assistant_message'] || @input_data['lastAssistantMessage']
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def background_tasks
|
|
34
|
+
@input_data['background_tasks'] || @input_data['backgroundTasks'] || []
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def session_crons
|
|
38
|
+
@input_data['session_crons'] || @input_data['sessionCrons'] || []
|
|
39
|
+
end
|
|
40
|
+
|
|
29
41
|
# === OUTPUT DATA HELPERS ===
|
|
30
42
|
|
|
31
43
|
# Block Claude from stopping (force it to continue)
|
|
@@ -40,5 +52,10 @@ module ClaudeHooks
|
|
|
40
52
|
@output_data.delete('decision')
|
|
41
53
|
@output_data.delete('reason')
|
|
42
54
|
end
|
|
55
|
+
|
|
56
|
+
def add_additional_context!(context)
|
|
57
|
+
@output_data['hookSpecificOutput'] ||= { 'hookEventName' => hook_event_name }
|
|
58
|
+
@output_data['hookSpecificOutput']['additionalContext'] = context
|
|
59
|
+
end
|
|
43
60
|
end
|
|
44
61
|
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base'
|
|
4
|
+
|
|
5
|
+
module ClaudeHooks
|
|
6
|
+
class StopFailure < Base
|
|
7
|
+
def self.hook_type
|
|
8
|
+
'StopFailure'
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.input_fields
|
|
12
|
+
%w[error]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def error
|
|
16
|
+
@input_data['error']
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def error_details
|
|
20
|
+
@input_data['error_details'] || @input_data['errorDetails']
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def last_assistant_message
|
|
24
|
+
@input_data['last_assistant_message'] || @input_data['lastAssistantMessage']
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base'
|
|
4
|
+
|
|
5
|
+
module ClaudeHooks
|
|
6
|
+
class SubagentStart < Base
|
|
7
|
+
def self.hook_type
|
|
8
|
+
'SubagentStart'
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.input_fields
|
|
12
|
+
%w[agent_id agent_type]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# agent_id and agent_type readers come from Base (Part A)
|
|
16
|
+
|
|
17
|
+
def add_additional_context!(context)
|
|
18
|
+
@output_data['hookSpecificOutput'] ||= { 'hookEventName' => hook_event_name }
|
|
19
|
+
@output_data['hookSpecificOutput']['additionalContext'] = context
|
|
20
|
+
end
|
|
21
|
+
alias_method :add_context!, :add_additional_context!
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base'
|
|
4
|
+
|
|
5
|
+
module ClaudeHooks
|
|
6
|
+
class TaskCompleted < Base
|
|
7
|
+
def self.hook_type
|
|
8
|
+
'TaskCompleted'
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.input_fields
|
|
12
|
+
%w[task_id task_subject]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def task_id
|
|
16
|
+
@input_data['task_id'] || @input_data['taskId']
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def task_subject
|
|
20
|
+
@input_data['task_subject'] || @input_data['taskSubject']
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def task_description
|
|
24
|
+
@input_data['task_description'] || @input_data['taskDescription']
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def teammate_name
|
|
28
|
+
@input_data['teammate_name'] || @input_data['teammateName']
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def team_name
|
|
32
|
+
@input_data['team_name'] || @input_data['teamName']
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base'
|
|
4
|
+
|
|
5
|
+
module ClaudeHooks
|
|
6
|
+
class TaskCreated < Base
|
|
7
|
+
def self.hook_type
|
|
8
|
+
'TaskCreated'
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.input_fields
|
|
12
|
+
%w[task_id task_subject]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def task_id
|
|
16
|
+
@input_data['task_id'] || @input_data['taskId']
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def task_subject
|
|
20
|
+
@input_data['task_subject'] || @input_data['taskSubject']
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def task_description
|
|
24
|
+
@input_data['task_description'] || @input_data['taskDescription']
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def teammate_name
|
|
28
|
+
@input_data['teammate_name'] || @input_data['teammateName']
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def team_name
|
|
32
|
+
@input_data['team_name'] || @input_data['teamName']
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base'
|
|
4
|
+
|
|
5
|
+
module ClaudeHooks
|
|
6
|
+
class TeammateIdle < Base
|
|
7
|
+
def self.hook_type
|
|
8
|
+
'TeammateIdle'
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.input_fields
|
|
12
|
+
%w[teammate_name team_name]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def teammate_name
|
|
16
|
+
@input_data['teammate_name'] || @input_data['teammateName']
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def team_name
|
|
20
|
+
@input_data['team_name'] || @input_data['teamName']
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base'
|
|
4
|
+
|
|
5
|
+
module ClaudeHooks
|
|
6
|
+
class UserPromptExpansion < Base
|
|
7
|
+
def self.hook_type
|
|
8
|
+
'UserPromptExpansion'
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.input_fields
|
|
12
|
+
%w[expansion_type command_name command_args command_source prompt]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def expansion_type
|
|
16
|
+
@input_data['expansion_type'] || @input_data['expansionType']
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def command_name
|
|
20
|
+
@input_data['command_name'] || @input_data['commandName']
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def command_args
|
|
24
|
+
@input_data['command_args'] || @input_data['commandArgs']
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def command_source
|
|
28
|
+
@input_data['command_source'] || @input_data['commandSource']
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def prompt
|
|
32
|
+
@input_data['prompt']
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def block!(reason = '')
|
|
36
|
+
@output_data['decision'] = 'block'
|
|
37
|
+
@output_data['reason'] = reason
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def add_additional_context!(context)
|
|
41
|
+
@output_data['hookSpecificOutput'] ||= { 'hookEventName' => hook_event_name }
|
|
42
|
+
@output_data['hookSpecificOutput']['additionalContext'] = context
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
data/lib/claude_hooks/version.rb
CHANGED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base'
|
|
4
|
+
|
|
5
|
+
module ClaudeHooks
|
|
6
|
+
class WorktreeCreate < Base
|
|
7
|
+
def self.hook_type
|
|
8
|
+
'WorktreeCreate'
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.input_fields
|
|
12
|
+
%w[name]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def name
|
|
16
|
+
@input_data['name']
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Emit the worktree path as bare stdout (last non-empty line).
|
|
20
|
+
# Also sets hookSpecificOutput.worktreePath for programmatic access.
|
|
21
|
+
def worktree_path!(path)
|
|
22
|
+
@output_data['_worktree_path'] = path
|
|
23
|
+
@output_data['hookSpecificOutput'] ||= { 'hookEventName' => hook_event_name }
|
|
24
|
+
@output_data['hookSpecificOutput']['worktreePath'] = path
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base'
|
|
4
|
+
|
|
5
|
+
module ClaudeHooks
|
|
6
|
+
class WorktreeRemove < Base
|
|
7
|
+
def self.hook_type
|
|
8
|
+
'WorktreeRemove'
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.input_fields
|
|
12
|
+
%w[worktree_path]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def worktree_path
|
|
16
|
+
@input_data['worktree_path'] || @input_data['worktreePath']
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
data/lib/claude_hooks.rb
CHANGED
|
@@ -12,11 +12,31 @@ require_relative "claude_hooks/pre_tool_use"
|
|
|
12
12
|
require_relative "claude_hooks/permission_request"
|
|
13
13
|
require_relative "claude_hooks/post_tool_use"
|
|
14
14
|
require_relative "claude_hooks/notification"
|
|
15
|
+
require_relative "claude_hooks/message_display"
|
|
15
16
|
require_relative "claude_hooks/stop"
|
|
16
17
|
require_relative "claude_hooks/subagent_stop"
|
|
17
18
|
require_relative "claude_hooks/pre_compact"
|
|
18
19
|
require_relative "claude_hooks/session_start"
|
|
19
20
|
require_relative "claude_hooks/session_end"
|
|
21
|
+
require_relative "claude_hooks/setup"
|
|
22
|
+
require_relative "claude_hooks/subagent_start"
|
|
23
|
+
require_relative "claude_hooks/user_prompt_expansion"
|
|
24
|
+
require_relative "claude_hooks/post_tool_batch"
|
|
25
|
+
require_relative "claude_hooks/config_change"
|
|
26
|
+
require_relative "claude_hooks/task_created"
|
|
27
|
+
require_relative "claude_hooks/task_completed"
|
|
28
|
+
require_relative "claude_hooks/teammate_idle"
|
|
29
|
+
require_relative "claude_hooks/post_tool_use_failure"
|
|
30
|
+
require_relative "claude_hooks/stop_failure"
|
|
31
|
+
require_relative "claude_hooks/post_compact"
|
|
32
|
+
require_relative "claude_hooks/cwd_changed"
|
|
33
|
+
require_relative "claude_hooks/file_changed"
|
|
34
|
+
require_relative "claude_hooks/instructions_loaded"
|
|
35
|
+
require_relative "claude_hooks/worktree_remove"
|
|
36
|
+
require_relative "claude_hooks/permission_denied"
|
|
37
|
+
require_relative "claude_hooks/elicitation"
|
|
38
|
+
require_relative "claude_hooks/elicitation_result"
|
|
39
|
+
require_relative "claude_hooks/worktree_create"
|
|
20
40
|
|
|
21
41
|
# Output classes
|
|
22
42
|
require_relative "claude_hooks/output/base"
|
|
@@ -25,11 +45,31 @@ require_relative "claude_hooks/output/pre_tool_use"
|
|
|
25
45
|
require_relative "claude_hooks/output/permission_request"
|
|
26
46
|
require_relative "claude_hooks/output/post_tool_use"
|
|
27
47
|
require_relative "claude_hooks/output/notification"
|
|
48
|
+
require_relative "claude_hooks/output/message_display"
|
|
28
49
|
require_relative "claude_hooks/output/stop"
|
|
29
50
|
require_relative "claude_hooks/output/subagent_stop"
|
|
30
51
|
require_relative "claude_hooks/output/pre_compact"
|
|
31
52
|
require_relative "claude_hooks/output/session_start"
|
|
32
53
|
require_relative "claude_hooks/output/session_end"
|
|
54
|
+
require_relative "claude_hooks/output/setup"
|
|
55
|
+
require_relative "claude_hooks/output/subagent_start"
|
|
56
|
+
require_relative "claude_hooks/output/user_prompt_expansion"
|
|
57
|
+
require_relative "claude_hooks/output/post_tool_batch"
|
|
58
|
+
require_relative "claude_hooks/output/config_change"
|
|
59
|
+
require_relative "claude_hooks/output/task_created"
|
|
60
|
+
require_relative "claude_hooks/output/task_completed"
|
|
61
|
+
require_relative "claude_hooks/output/teammate_idle"
|
|
62
|
+
require_relative "claude_hooks/output/post_tool_use_failure"
|
|
63
|
+
require_relative "claude_hooks/output/stop_failure"
|
|
64
|
+
require_relative "claude_hooks/output/post_compact"
|
|
65
|
+
require_relative "claude_hooks/output/cwd_changed"
|
|
66
|
+
require_relative "claude_hooks/output/file_changed"
|
|
67
|
+
require_relative "claude_hooks/output/instructions_loaded"
|
|
68
|
+
require_relative "claude_hooks/output/worktree_remove"
|
|
69
|
+
require_relative "claude_hooks/output/permission_denied"
|
|
70
|
+
require_relative "claude_hooks/output/elicitation"
|
|
71
|
+
require_relative "claude_hooks/output/elicitation_result"
|
|
72
|
+
require_relative "claude_hooks/output/worktree_create"
|
|
33
73
|
|
|
34
74
|
module ClaudeHooks
|
|
35
75
|
class Error < StandardError; end
|