Skip to content

fix(parser): display all hook types in GUI (Stop, PreToolUse, PostToolUse, etc.)#23

Merged
delexw merged 2 commits intomainfrom
claude/fix-repo-issues-oKGOX
Mar 29, 2026
Merged

fix(parser): display all hook types in GUI (Stop, PreToolUse, PostToolUse, etc.)#23
delexw merged 2 commits intomainfrom
claude/fix-repo-issues-oKGOX

Conversation

@delexw
Copy link
Copy Markdown
Owner

@delexw delexw commented Mar 29, 2026

Summary

Verified the actual JSONL formats written by Claude Code v2.1.86 (--debug + live session inspection + cli.js bundle analysis). Hooks were never displaying because the parser was looking for the wrong entry formats.

Root causes found

Stop hooks → system/stop_hook_summary

Claude Code writes a stop_hook_summary entry after every Stop hook invocation (success or failure):

{"type":"system","subtype":"stop_hook_summary","hookCount":1,
 "hookInfos":[{"command":"~/.claude/stop-hook-git-check.sh","durationMs":59}]}

This was silently dropped — "system" is in NOISE_ENTRY_TYPES.

When a Stop hook blocks (exit ≠ 0), Claude also injects:

{"type":"user","isMeta":true,"message":{"content":"Stop hook feedback:\n[cmd]: error output"}}

This fell through to a meta AI message rather than being shown as a hook.

All other hooks → type:"attachment" entries

PreToolUse, PostToolUse, PostToolUseFailure, UserPromptSubmit, Notification, SessionStart, etc. write their results as attachment entries:

{"type":"attachment","uuid":"...","timestamp":"...",
 "attachment":{"type":"hook_success"|"hook_non_blocking_error"|"hook_blocking_error"|"hook_cancelled",
               "hookEvent":"PreToolUse","hookName":"my-hook","toolUseID":"..."}}

Entry had no attachment field, so the hook data was silently discarded and the entry dropped by the empty-role fallback.

Changes

  • entry.rs: Add hook_count, hook_infos, prevented_continuation, attachment fields
  • classify.rs: Rescue before the noise filter:
    • system/stop_hook_summary (hookCount > 0) → HookMsg with hook_event:"Stop" and hook name from hookInfos[0].command
    • system/hook_progressHookMsg (verbose/stream-json mode)
    • user isMeta "Stop hook feedback:"HookMsg with parsed command + error text
    • attachment with hookEventHookMsg for all non-Stop hook events

Test plan

  • 274 Rust unit tests pass (cargo test)
  • New tests cover all rescue paths: stop_hook_summary, zero-hook drop, feedback entry, hook_success attachment, hook_blocking_error with message, non-hook attachment dropped

https://claude.ai/code/session_01MK63kGRSmtkGSXCDaqh8p3

claude added 2 commits March 29, 2026 01:02
…as HookMsg

Verified via --debug output and live JSONL inspection:

The actual hook entry format written to JSONL session files is:
  {type:"system", subtype:"stop_hook_summary", hookCount:N,
   hookInfos:[{command, durationMs}], preventedContinuation, ...}

This is written on EVERY Stop hook invocation (success or failure).
Previous code only rescued type:"progress" data.type:"hook_progress" entries,
which never appear in JSONL files — so hooks were never displayed.

When a Stop hook exits non-zero, Claude also injects a user meta entry:
  {type:"user", isMeta:true, message:{content:"Stop hook feedback:\n[cmd]: output"}}

Both are now rescued before the NOISE_ENTRY_TYPES filter:
- system/stop_hook_summary (hookCount > 0) → HookMsg with hook_event:"Stop"
  and hook_name extracted from hookInfos[0].command
- system/hook_progress → HookMsg (verbose/stream-json mode)
- user/isMeta "Stop hook feedback:" → HookMsg with parsed command and output

New Entry fields: hookCount, hookInfos, preventedContinuation.
Three new tests: stop_hook_summary rescue, zero-hook drop, feedback entry rescue.

https://claude.ai/code/session_01MK63kGRSmtkGSXCDaqh8p3
…e and all other hook events

Verified from cli.js bundle (v2.1.86):

All non-Stop hook events (PreToolUse, PostToolUse, PostToolUseFailure,
UserPromptSubmit, Notification, SessionStart, etc.) write their results
to the JSONL session file as type:"attachment" entries:

  {type:"attachment", uuid, timestamp,
   attachment:{type:"hook_success"|"hook_non_blocking_error"|
               "hook_blocking_error"|"hook_cancelled",
               hookEvent, hookName, toolUseID, ...}}

These were previously dropped because Entry had no attachment field
and the empty-role fallback silently discarded them.

Fix: add attachment: Option<Value> to Entry, rescue attachment entries
where attachment.hookEvent is non-empty as HookMsg. Blocking errors
also surface their error message in the command field.

This covers the full hook surface area:
- system/stop_hook_summary → Stop hooks (already fixed)
- type:attachment + hookEvent → ALL other hook events (this commit)
- system/hook_progress → verbose/stream-json mode hooks

Three new tests: hook_success attachment, hook_blocking_error with message,
non-hook attachment dropped.

https://claude.ai/code/session_01MK63kGRSmtkGSXCDaqh8p3
@delexw delexw merged commit fb9b0e5 into main Mar 29, 2026
1 check passed
@delexw delexw deleted the claude/fix-repo-issues-oKGOX branch March 29, 2026 01:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants