Skip to content

Comments

feat: Notification hookのJSON出力対応(Task 9)+ SessionEnd統合#64

Merged
syou6162 merged 15 commits intomainfrom
notification_json
Feb 10, 2026
Merged

feat: Notification hookのJSON出力対応(Task 9)+ SessionEnd統合#64
syou6162 merged 15 commits intomainfrom
notification_json

Conversation

@syou6162
Copy link
Owner

@syou6162 syou6162 commented Feb 9, 2026

概要

Notification hookをJSON出力形式に移行し、Claude Code公式仕様に準拠させます。

これまでexit codeベースで制御していたNotification hookの出力を、他のhookタイプ(SessionStart, PostToolUse等)と同様にJSON出力形式に統一します。また、mainブランチのSessionEnd JSON出力対応( #63 )をコンフリクト回避のため統合しています。

背景

cchookは当初exit codeベースでhook出力を制御していたが、Claude Code公式仕様でJSON出力形式が導入されました。Phase 1(SessionStart)からPhase 8(SubagentStop)まで順次JSON出力対応を完了しており、本PRはTask 9としてNotification hookのJSON出力対応を行います。

公式ドキュメント https://code.claude.com/docs/en/hooks のNotificationセクションに準拠し、SessionStartに近いパターン(hookSpecificOutput + additionalContext)を採用しています。

変更内容

Notification JSON出力対応

型定義 (types.go)

  • NotificationOutput構造体追加(Common JSON Fields + hookSpecificOutput)
  • NotificationHookSpecificOutput構造体追加(hookEventName, additionalContext)

バリデーション (utils.go)

  • validateNotificationOutput関数追加
    • JSON Schema検証(hookEventName="Notification")
    • 未サポートフィールド検証(decision/reason禁止)

アクション実行 (executor.go)

  • ExecuteNotificationAction全面書き換え
    • 戻り値: error(*ActionOutput, error)
    • type="output": message → additionalContextに変換
    • type="command": JSON解析、スキーマ検証、ActionOutput構築
    • hookSpecificOutput任意対応(未指定時はデフォルト値で補完)
    • hookEventName欠落時の警告処理追加
    • stopReason/suppressOutputの伝搬対応
  • checkUnsupportedFieldsNotification追加

フック実行 (hooks.go)

  • executeNotificationHooksJSON実装(SessionStartパターン踏襲)
    • continue強制true(公式仕様 "Can block? = No")
    • フィールドマージルール: hookEventName(初回設定)、additionalContext/systemMessage(改行連結)、stopReason(最後の非空値)、suppressOutput(最後の値)
    • エラー時もcontinue: true維持 + errorを返してstderr警告を発火
  • RunNotificationHooksラッパー関数追加
  • executeNotificationHooks削除

エントリポイント (main.go)

  • Notification専用JSON出力ブロック追加
    • 常にexit 0(continue field controls behavior)
    • エラー時hookSpecificOutput補完
    • marshal失敗時のfallback JSON

ドキュメント (CLAUDE.md)

  • Notification JSON Outputセクション追加

mainブランチのSessionEnd JSON出力対応を統合

mainブランチにマージ済みの #63 (SessionEnd JSON出力対応)をコンフリクト回避のためnotification_jsonブランチに統合しています。

  • types.go: SessionEndOutput構造体追加
  • executor.go: ExecuteSessionEndActionをJSON対応に変更、checkUnsupportedFieldsSessionEnd追加
  • hooks.go: executeSessionEndHooksJSONRunSessionEndHooks追加
  • hooks_test.go: 関数呼び出しをJSON対応版に更新
  • actions_test.go: 古いSessionEndテスト削除
  • main.go: SessionEnd JSON出力ハンドリングブロック追加
  • utils.go: validateSessionEndOutput関数追加
  • CLAUDE.md: SessionEnd JSON Outputセクション追加

テスト

  • types_test.go: JSON marshal/unmarshalテスト(4ケース)
  • utils_test.go: バリデーションテスト(10ケース)
  • executor_test.go: TypeOutput(5ケース)+ TypeCommand(6ケース、hookSpecificOutput任意対応含む)
  • hooks_test.go: executeNotificationHooksJSON(5ケース)+ StopReason/SuppressOutput検証
  • integration_test.go: TestNotificationIntegration更新

全テスト通過: go test ./... および go test -tags=integration ./...

仕様準拠

  • Claude Code hooks公式ドキュメント https://code.claude.com/docs/en/hooks のNotificationセクションに準拠
  • Common JSON Fields: continue, stopReason, suppressOutput, systemMessage
  • hookSpecificOutput: hookEventName, additionalContext(任意フィールド、未指定時はデフォルト補完)
  • "Can block? = No" に従いcontinue常にtrue

関連情報

- NotificationOutput構造体を追加(Common JSON Fields + hookSpecificOutput)
- NotificationHookSpecificOutput構造体を追加(hookEventName, additionalContext)
- TestNotificationOutput_JSONSerialization追加
  - 全フィールドあり
  - 最小構成(continue + hookSpecificOutput)
  - 空additionalContext省略
  - omitempty動作確認
- Round-trip marshal/unmarshal検証

TDD: Red(未定義エラー)→ Green(全テスト成功)
- validateNotificationOutput関数を追加
  - JSON Schema検証(hookSpecificOutput必須、hookEventName="Notification")
  - 未サポートフィールド検証(decision/reason禁止)
- TestValidateNotificationOutput追加
  - 正常系: continue + hookSpecificOutput、全フィールド
  - 異常系: 無効な型、必須フィールド欠落、hookEventName不一致、未サポートフィールド
- コメント修正(全角→半角括弧、pre-commit自動修正)

TDD: Red(未定義エラー)→ Green(全テスト成功)
- ExecuteNotificationAction全面書き換え
  - 戻り値: error → (*ActionOutput, error)
  - type="output": continue/hookEventName/additionalContext設定
  - type="command": JSON解析、スキーマ検証、ActionOutput構築
  - 空メッセージ/空stdout/コマンド失敗時のエラーハンドリング
- checkUnsupportedFieldsNotification追加
  - decision/reasonなど未サポートフィールド警告
- TestExecuteNotificationAction_TypeOutput追加
  - 5ケース: continue未指定/false/true、テンプレート変数、空メッセージ
- actions_test.go旧テスト削除
  - WithExitError/CommandWithStubRunner(ExitError→ActionOutput移行)
- hooks.go一時修正
  - 戻り値受け取り対応(TODO: Step 4で書き換え予定)

TDD: Red(未定義エラー)→ Green(全テスト成功)
SessionStartパターン踏襲(hookSpecificOutput + additionalContext)
- TestExecuteNotificationAction_TypeCommand追加
  - 4ケース: 有効なJSON全フィールド、最小出力、コマンド失敗、空stdout
- 空stdout時の挙動検証(continue: true, hookEventName設定)
- コマンド失敗時のエラーハンドリング検証

TDD Green(全テストパス)
Step 3(ExecuteNotificationAction書き換えとテスト)完了
- executeNotificationHooksJSON関数実装
  - SessionStartパターン踏襲(hookSpecificOutput + additionalContext)
  - continue強制true(Notification cannot block)
  - エラー時もcontinue: true維持(graceful degradation)
- RunNotificationHooks関数追加(main.go呼び出し用)
- runHooks内のNotificationケース更新(JSON出力対応)
- 旧executeNotificationHooks削除
- TestExecuteNotificationHooksJSON追加
  - 5ケース: フックなし、単一アクション、複数連結、エラー時continue維持
- 旧テスト削除(executeNotificationHooks呼び出し2件)

TDD Green(全テストパス)
continue強制上書き実装(公式仕様「Can block? = No」準拠)
- Notification専用JSON出力ブロック追加
  - RunNotificationHooks呼び出し
  - エラー時hookSpecificOutput補完(continue: true維持)
  - marshal失敗時のfallback JSON(continue: true固定)
  - validateNotificationOutput呼び出し(警告のみ)
  - 常にexit 0(continue field controls behavior)
- SessionStartパターン準拠

手動テスト確認済み(JSON出力正常、exit 0)
- TestNotificationIntegration更新
  - executeNotificationHooksJSON呼び出しに変更
  - JSON出力検証追加(Continue, HookSpecificOutput, HookEventName)
- インデント修正(PostToolUseテスト)

全テスト成功(unit + integration)
Notification JSON出力対応完了
- Notification JSON Outputセクション追加
  - Output/Commandアクション説明
  - Field Mergingルール(continue強制true)
  - Exit Code Behavior(常にexit 0)
  - YAML例
- PostToolUse JSON Outputセクション後に配置

Task 9(Notification JSON出力対応)完了
Notification hookでcommand actionが返すstopReason/suppressOutputが
最終JSON出力に反映されていなかった問題を修正

- ExecuteNotificationAction: ActionOutputにStopReason/SuppressOutputをコピー
- executeNotificationHooksJSON: PostToolUseパターンに倣ってマージ処理追加
  - StopReason: 最後の非空値が勝ち
  - SuppressOutput: 最後の値が勝ち
- テスト追加: executor_test.go/hooks_test.goで検証
@syou6162 syou6162 self-assigned this Feb 9, 2026
Codexレビュー指摘(P2)に対応。公式仕様ではhookSpecificOutputは
任意フィールドだが、コードでは必須チェックしていた。

変更内容:
- executor.go: 必須チェック削除、未指定時にデフォルト値補完
- executor.go: 補完後のJSONでバリデーション実行(元のstdout使用を修正)
- executor_test.go: hookSpecificOutput未指定テストケース追加

これによりCommon Fieldsのみ返すコマンドも有効な出力として受け入れる。
Codexレビュー指摘(P2, 3回目)に対応。hookSpecificOutputが存在するが
hookEventNameが空の場合、自動補完せず警告+fail-safe扱いに変更。

変更内容:
- executor.go: hookEventName欠落時の警告処理追加(Continue: false)
- executor_test.go: hookEventName欠落ケースのテスト追加

これにより無効なコマンド出力が検知され、問題の切り分けが容易になる。
Codexレビュー指摘(P2, 3回目)に対応。条件エラーやアクション
エラーが発生した場合、SystemMessageに追記するだけでなく
errorも返すように修正。

変更内容:
- hooks.go: errors.Join(allErrors...)を返してmain.goの警告出力を発火
- hooks_test.go: 不適切なテストケースを削除

これにより開発日誌の「全エラーパスでstderr警告」方針に準拠し、
他フック(PostToolUse等)との一貫性が保たれる。
notification_jsonブランチとmainブランチ間のコンフリクトを解決し、
SessionEnd JSON出力対応(PR #63)を統合。

変更内容:
- CLAUDE.md: SessionEnd JSON Outputセクションを追加
- types.go: SessionEndOutput構造体を追加
- executor.go: ExecuteSessionEndActionをJSON対応に変更
  - 戻り値を(*ActionOutput, error)に変更
  - checkUnsupportedFieldsSessionEnd関数を追加
- hooks.go: executeSessionEndHooksJSONとRunSessionEndHooks関数を追加
  - runHooksでの呼び出しを更新
- hooks_test.go: 関数呼び出しをJSON対応版に更新
- actions_test.go: 古いSessionEndテストを削除(JSON対応版はexecutor_test.goにある)
- main.go: SessionEnd JSON出力ハンドリングブロックを追加
- utils.go: validateSessionEndOutput関数を追加

これにより、Notification JSON出力とSessionEnd JSON出力の両方が
コンフリクトなく共存できるようになった。
@syou6162 syou6162 changed the title feat: Notification hookのJSON出力対応(Task 9) feat: Notification hookのJSON出力対応(Task 9)+ SessionEnd統合 Feb 10, 2026
SessionEnd JSON出力対応の統合時に発生した実装の不一致を修正。

変更内容:
- README.md: SessionEndをJSON Output Eventsリストに移動(Legacy Exit Codeから削除)
- hooks.go: runHooks関数からSessionEndケースを削除(JSON出力はRunSessionEndHooksを使用)
- hooks_test.go: executeSessionEndHooks(旧版)を削除し、TestExecuteSessionEndHooksJSON(origin/main版)に置き換え

これにより、SessionEnd JSON出力対応がorigin/mainの実装と完全に一致し、
mainブランチへのマージ時にコンフリクトが発生しなくなる。
@syou6162 syou6162 marked this pull request as ready for review February 10, 2026 09:45
@syou6162 syou6162 merged commit d02d609 into main Feb 10, 2026
2 checks passed
@syou6162 syou6162 deleted the notification_json branch February 10, 2026 09:45
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.

1 participant