claude_hooks 1.1.0 → 1.2.1
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/AGENTS.md +46 -0
- data/CHANGELOG.md +64 -0
- data/README.md +303 -239
- data/docs/1.0.0_MIGRATION_GUIDE.md +6 -7
- 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/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/base.rb +25 -0
- data/lib/claude_hooks/cli.rb +84 -149
- 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 -4
- data/example_dotclaude/hooks/entrypoints/pre_tool_use.rb +0 -25
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4ff845df334960263a1d36b01aeba57393609c59acbc63424572c9d7fdca7999
|
|
4
|
+
data.tar.gz: 70029c193102d9a63b6d6e5ff8361fcf42e506bff26435c907ec4a06010a571a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 28a4548cafd93c7f5d5c9d1f577399d8e90503c2e4ae1fa279a9723234045848c0b3bdbb1c41df9f0808d375eb5d345a5210d9db46fe74ba3332fb2394920530
|
|
7
|
+
data.tar.gz: e2555f3731aad5bacb7e572c9630fa9e39721b625684664bc2ea41d9b0579af146f697b10a6d99410368140ebb7cd37de53b2bd195e2a2c13a5100722502fcd2
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ci-monitoring
|
|
3
|
+
description: >
|
|
4
|
+
How to wait for GitHub Actions CI to finish on a PR after pushing commits,
|
|
5
|
+
without hanging forever or giving up too early. Use this skill whenever you
|
|
6
|
+
have pushed to a PR branch and need to confirm the checks pass before
|
|
7
|
+
reporting back or approving.
|
|
8
|
+
triggers:
|
|
9
|
+
- ci
|
|
10
|
+
- checks
|
|
11
|
+
- status check
|
|
12
|
+
- wait for ci
|
|
13
|
+
- green
|
|
14
|
+
- pipeline
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
# Waiting for CI on a PR
|
|
18
|
+
|
|
19
|
+
After you push commits to a PR branch, the PR's checks (`test.yml`, `ruby-gem.yml`)
|
|
20
|
+
re-run. You often need to confirm they pass before you comment "done" or before a
|
|
21
|
+
review approves. This is easy to get wrong in two opposite ways — hanging forever,
|
|
22
|
+
or declaring success while checks are still pending. Follow this pattern.
|
|
23
|
+
|
|
24
|
+
## Do NOT use the blocking watchers
|
|
25
|
+
|
|
26
|
+
These hang until completion with no timeout and will burn the whole run's time
|
|
27
|
+
budget (the agent's bash step is capped at ~10 minutes):
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
gh run watch # ❌ blocks indefinitely
|
|
31
|
+
gh pr checks --watch # ❌ blocks indefinitely
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Poll `statusCheckRollup` in a bounded foreground loop
|
|
35
|
+
|
|
36
|
+
Query the PR's aggregated check state and sleep between polls. Use
|
|
37
|
+
`statusCheckRollup`, **not** `gh pr checks --required`: the latter only returns
|
|
38
|
+
contexts that are *already registered*, so a check that registers late (a matrix
|
|
39
|
+
job, or a summary job with a long `needs:` list) can make it exit green early and
|
|
40
|
+
miss a failure.
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
PR=<pr-number>
|
|
44
|
+
for i in $(seq 1 9); do
|
|
45
|
+
# One JSON blob with every check's name, status, and conclusion.
|
|
46
|
+
rollup=$(gh pr view "$PR" --json statusCheckRollup \
|
|
47
|
+
--jq '.statusCheckRollup[] | {name: .name, status: .status, conclusion: .conclusion}')
|
|
48
|
+
|
|
49
|
+
# Are any checks still running / queued?
|
|
50
|
+
pending=$(echo "$rollup" | jq -sr '[.[] | select(.status != "COMPLETED")] | length')
|
|
51
|
+
|
|
52
|
+
if [ "$pending" -eq 0 ]; then
|
|
53
|
+
echo "All checks completed."
|
|
54
|
+
break
|
|
55
|
+
fi
|
|
56
|
+
echo "Attempt $i/9: $pending check(s) still running; sleeping 60s…"
|
|
57
|
+
sleep 60
|
|
58
|
+
done
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
That is 9 × 60s = ~9 minutes, which fits inside the bash step cap. If checks are
|
|
62
|
+
still pending after the loop, say so explicitly ("CI was still running when I
|
|
63
|
+
checked — see the PR checks tab") rather than claiming success.
|
|
64
|
+
|
|
65
|
+
## Decide pass/fail from the final rollup
|
|
66
|
+
|
|
67
|
+
A check passed only when `status == "COMPLETED"` **and**
|
|
68
|
+
`conclusion == "SUCCESS"` (or `NEUTRAL`/`SKIPPED`). Treat `FAILURE`,
|
|
69
|
+
`TIMED_OUT`, `CANCELLED`, `ACTION_REQUIRED`, or `STALE` as failing.
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
failed=$(gh pr view "$PR" --json statusCheckRollup \
|
|
73
|
+
--jq '[.statusCheckRollup[]
|
|
74
|
+
| select(.conclusion != null and .conclusion != "SUCCESS"
|
|
75
|
+
and .conclusion != "NEUTRAL" and .conclusion != "SKIPPED")]
|
|
76
|
+
| length')
|
|
77
|
+
if [ "$failed" -gt 0 ]; then
|
|
78
|
+
echo "CI failed — inspect the failing job before reporting done."
|
|
79
|
+
fi
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Do **not** treat `mergeStateStatus == BLOCKED` as a CI failure — it's a catch-all
|
|
83
|
+
(branch protection, pending review, etc.), not a check result.
|
|
84
|
+
|
|
85
|
+
## When a check fails
|
|
86
|
+
|
|
87
|
+
- Read the failing job's logs (`gh run view <run-id> --log-failed`) and fix the
|
|
88
|
+
cause. For this Ruby gem, most failures are the test suite — see the
|
|
89
|
+
`run-tests` skill.
|
|
90
|
+
- Re-run only the failed jobs if the failure looks transient (rare here):
|
|
91
|
+
`gh run rerun <run-id> --failed`.
|
|
92
|
+
- Never mark a PR done or approve over red CI. If you approve, the empty-body
|
|
93
|
+
approval reads as endorsing a broken build.
|
|
94
|
+
|
|
95
|
+
## Notes specific to this repo
|
|
96
|
+
|
|
97
|
+
- Relevant workflows on a PR: **`test.yml`** (Ruby 3.2 + 3.3 matrix — the one that
|
|
98
|
+
matters for correctness) and **`ruby-gem.yml`** (its publish job is gated on
|
|
99
|
+
`push` to `main`, so on a PR it only builds — a failure there is still worth
|
|
100
|
+
reading).
|
|
101
|
+
- A PR the bot opened may **not** auto-run these workflows: the built-in
|
|
102
|
+
`GITHUB_TOKEN` does not retrigger other workflows. If the checks tab is empty on
|
|
103
|
+
a bot-opened PR, that's expected, not a hang — note it and move on.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: run-tests
|
|
3
|
+
description: >
|
|
4
|
+
How to install dependencies and run the claude_hooks test suite.
|
|
5
|
+
Use this skill whenever you need to verify that code changes pass the tests
|
|
6
|
+
before committing.
|
|
7
|
+
triggers:
|
|
8
|
+
- test
|
|
9
|
+
- tests
|
|
10
|
+
- spec
|
|
11
|
+
- run_all_tests
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Running the claude_hooks Test Suite
|
|
15
|
+
|
|
16
|
+
This is a **Ruby gem**. Always run the full test suite after any code change and
|
|
17
|
+
before committing.
|
|
18
|
+
|
|
19
|
+
## Install dependencies
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
bundle install
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Run all tests
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
ruby test/run_all_tests.rb
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The suite must exit 0 before you commit. All files matching `test/test_*.rb` are
|
|
32
|
+
included automatically.
|
|
33
|
+
|
|
34
|
+
## Adding or updating tests
|
|
35
|
+
|
|
36
|
+
- Place new test files in `test/` named `test_<feature>.rb`.
|
|
37
|
+
- Use plain `Test::Unit` / `Minitest` — no RSpec.
|
|
38
|
+
- Run the full suite, not just the new file, to catch regressions.
|
|
39
|
+
|
|
40
|
+
## Common failure patterns
|
|
41
|
+
|
|
42
|
+
- **Missing gem**: run `bundle install` again; check `Gemfile.lock` was updated.
|
|
43
|
+
- **LoadError**: verify the `require` path matches the file under `lib/`.
|
|
44
|
+
- **Unexpected output**: the hooks write to `$stderr`; redirect if your test
|
|
45
|
+
captures stdout only.
|
data/AGENTS.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Agent guidance — claude_hooks
|
|
2
|
+
|
|
3
|
+
This file is loaded by the coding agents that run in this repo's GitHub Actions
|
|
4
|
+
bots. It is picked up via `load_available_skills` (which internally calls
|
|
5
|
+
`load_project_skills`, the loader that ingests `AGENTS.md`) in
|
|
6
|
+
`agent_task.py` (issue and PR bots) and by the `pr-review` composite action.
|
|
7
|
+
Keep it short and factual.
|
|
8
|
+
|
|
9
|
+
## What this project is
|
|
10
|
+
|
|
11
|
+
`claude_hooks` is a **Ruby gem** — a DSL for creating [Claude Code](https://docs.claude.com/en/docs/claude-code)
|
|
12
|
+
hooks (logging, security checks, workflow automation) with composable hook scripts.
|
|
13
|
+
Pure Ruby, no Rails. Public repo: https://github.com/gabriel-dehan/claude_hooks
|
|
14
|
+
|
|
15
|
+
## Layout
|
|
16
|
+
|
|
17
|
+
- `lib/claude_hooks/` — the gem. One file per hook type (`pre_tool_use.rb`,
|
|
18
|
+
`post_tool_use.rb`, `user_prompt_submit.rb`, `session_start.rb`, etc.), plus
|
|
19
|
+
`base.rb`, `configuration.rb`, `cli.rb`, `logger.rb`, `version.rb`.
|
|
20
|
+
- `test/` — plain Ruby tests (`test_*.rb`), no RSpec.
|
|
21
|
+
- `docs/` — human docs, including `docs/mitts/` for the bot setup itself.
|
|
22
|
+
|
|
23
|
+
## Running tests
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
bundle install
|
|
27
|
+
ruby test/run_all_tests.rb
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Run this before committing any code change; it must pass. Add or update tests in
|
|
31
|
+
`test/` when you change behavior.
|
|
32
|
+
|
|
33
|
+
## Conventions
|
|
34
|
+
|
|
35
|
+
- Match the surrounding code's style; this is a small, idiomatic Ruby gem.
|
|
36
|
+
- Keep changes minimal and focused on the request.
|
|
37
|
+
- Follow SemVer; note user-facing changes in `CHANGELOG.md`. `v1.0.0` introduced
|
|
38
|
+
breaking changes — check the changelog before assuming an API.
|
|
39
|
+
- Never commit secrets; never modify `.github/workflows/` permissions or CI secrets
|
|
40
|
+
unless the task is explicitly about the workflows.
|
|
41
|
+
|
|
42
|
+
## For PR review specifically
|
|
43
|
+
|
|
44
|
+
Verify that behavior changes come with tests and that `ruby test/run_all_tests.rb`
|
|
45
|
+
would still pass. Flag anything that breaks the documented DSL API without a
|
|
46
|
+
CHANGELOG note.
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,70 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.2.1] - 2026-07-15
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **`CLI.run_hook` — new primary entrypoint method** replacing `CLI.entrypoint`. Reads JSON from STDIN, runs the hook, and exits with the correct code and stream for the hook type.
|
|
13
|
+
- Accepts `on_error: :allow` (default, exit 1 — non-blocking) or `on_error: :block` (exit 2 — blocking). Use `:block` for security/policy hooks where a crash should never silently pass through.
|
|
14
|
+
- Supports a class form (`CLI.run_hook(MyHook)`) and a block form for multi-handler merging.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- **`CLI.entrypoint` deprecated** in favour of `CLI.run_hook`. It remains as a delegating alias with a deprecation warning and will be removed in a future minor version.
|
|
19
|
+
- **`CLI.run_hook` (old)** — the previous public `run_hook(hook_class, input_data)` helper used internally by `test_runner`/`run_with_sample_data` has been renamed to `run_hook_with_data` and made private. It was never intended as part of the public API.
|
|
20
|
+
- **Error output stream** — `CLI.run_hook` / `CLI.entrypoint` now write errors exclusively to stderr (previously the `:allow` path also wrote to stdout). On the `on_error: :block` (exit 2) path the message is written as **plain text**, not JSON, since Claude Code shows exit-2 stderr to the model verbatim and never parses it as JSON. The `:allow` (exit 1) path still writes the JSON error object to stderr.
|
|
21
|
+
- **README and examples** updated throughout to use `CLI.run_hook`.
|
|
22
|
+
|
|
23
|
+
### Notes
|
|
24
|
+
|
|
25
|
+
- No hook class or output class changes — existing hook scripts continue to work without modification
|
|
26
|
+
- `CLI.entrypoint` still works; only a deprecation warning is emitted
|
|
27
|
+
- 3 new tests covering `on_error: :block` (hook error → exit 2, invalid JSON → exit 2) and the deprecation warning
|
|
28
|
+
|
|
29
|
+
## [1.2.0] - 2026-07-14
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
|
|
33
|
+
- **20 new hook event classes** bringing full parity with the Claude Code Hooks spec v1.2.0 (30 events total):
|
|
34
|
+
- **Context-only**: `Setup`, `SubagentStart`
|
|
35
|
+
- **Blocking (top-level `decision`)**: `UserPromptExpansion`, `PostToolBatch`, `ConfigChange`
|
|
36
|
+
- **Blocking (exit-2 / `continue:false`)**: `TaskCreated`, `TaskCompleted`, `TeammateIdle`
|
|
37
|
+
- **Non-blocking**: `PostToolUseFailure`, `StopFailure`, `PostCompact`, `CwdChanged`, `FileChanged`, `InstructionsLoaded`, `WorktreeRemove`
|
|
38
|
+
- **JSON-API special**: `PermissionDenied`, `Elicitation`, `ElicitationResult`, `WorktreeCreate`
|
|
39
|
+
- **Display**: `MessageDisplay`
|
|
40
|
+
|
|
41
|
+
- **New common input readers** (available on all hook instances):
|
|
42
|
+
- `prompt_id`, `agent_id`, `agent_type`, `effort`
|
|
43
|
+
- `permission_mode` now documents `'auto'` as a valid value
|
|
44
|
+
|
|
45
|
+
- **`terminal_sequence!(seq)`** builder on all hooks; `terminal_sequence` accessor on output objects; `terminalSequence` (last non-nil wins) in `Output::Base.merge`
|
|
46
|
+
|
|
47
|
+
- **`PreToolUse` additions**: `defer_permission!`, `update_input!(hash)`, `add_additional_context!`; new output accessor `deferred?`
|
|
48
|
+
|
|
49
|
+
- **`PostToolUse` additions**: `update_tool_output!(value)`, `update_mcp_tool_output!(value)`; output accessors `updated_tool_output`, `updated_mcp_tool_output`, `output_updated?`
|
|
50
|
+
|
|
51
|
+
- **`SessionStart` additions**: builders `session_title!`, `initial_user_message!`, `watch_paths!(array)`, `reload_skills!(bool)`; matching output accessors `session_title`, `initial_user_message`, `watch_paths`, `reload_skills?`; input readers `model`, `session_title`
|
|
52
|
+
|
|
53
|
+
- **`Stop` / `SubagentStop` additions**: input readers `last_assistant_message`, `background_tasks`, `session_crons`; `add_additional_context!` builder + `output.additional_context` accessor; `SubagentStop` gains `agent_transcript_path`
|
|
54
|
+
|
|
55
|
+
- **`PreCompact` additions**: `block!(reason)` builder; `Output::PreCompact` gains `decision`, `reason`, `blocked?` accessors
|
|
56
|
+
|
|
57
|
+
- **`PostToolBatch` convenience**: `succeeded_calls` / `failed_calls` partitions over `tool_calls` (success derived from the entry's `tool_response`)
|
|
58
|
+
|
|
59
|
+
### Changed
|
|
60
|
+
|
|
61
|
+
- **`PermissionRequest` emitted JSON shape** — builders now emit `hookSpecificOutput.decision = { behavior, message?, updatedInput?, updatedPermissions?, interrupt? }` instead of flat `permissionDecision`/`permissionDecisionReason` keys. **Backward-compatible: no hook code changes required** — builder signatures (`allow_permission!`, `deny_permission!`, `update_input_and_allow!`) are unchanged; read-side accessors (`permission_decision`, `allowed?`, `denied?`, etc.) retain legacy fallback for any stored flat JSON.
|
|
62
|
+
|
|
63
|
+
- **`PreToolUse` merge precedence** corrected to `deny > defer > ask > allow` (was `deny > ask > allow`).
|
|
64
|
+
|
|
65
|
+
### Notes
|
|
66
|
+
|
|
67
|
+
- All changes are additive — existing hooks continue to work without modification
|
|
68
|
+
- Ships as minor `1.2.0` (no source-level breaks for users)
|
|
69
|
+
- Total hook event classes: 30 (added 20 new classes, including `MessageDisplay`)
|
|
70
|
+
- All 13 test files pass (0 failures, 0 errors)
|
|
71
|
+
|
|
8
72
|
## [1.1.0] - 2026-01-04
|
|
9
73
|
|
|
10
74
|
### Added
|