feat(03-01): HookEvent struct, processHookEvent mapping, UpdateFromHook, WaitType

- HookEvent struct parses Claude Code hook JSON payload
- processHookEvent maps Notification/Stop/PostToolUse/PreToolUse to State+WaitType
- UpdateFromHook creates new entries and manages WaitingSince transitions
- SessionInfo.WaitType serialized in JSON with omitempty
- 12 tests cover all event mappings, edge cases, and JSON serialization

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Pierre Martin
2026-03-23 19:40:02 +01:00
parent 10a9d95116
commit e1b176cf55
4 changed files with 357 additions and 0 deletions

View File

@@ -101,3 +101,49 @@ func TestResponseWithSessions(t *testing.T) {
t.Error("waiting_since = nil, want non-nil")
}
}
func TestSessionInfoWaitTypeJSON(t *testing.T) {
// WaitType="permission" should appear in JSON
info := SessionInfo{
SessionID: "sess-1",
State: "Needs Input",
WaitType: "permission",
}
data, err := json.Marshal(info)
if err != nil {
t.Fatalf("marshal: %v", err)
}
var m map[string]interface{}
if err := json.Unmarshal(data, &m); err != nil {
t.Fatalf("unmarshal map: %v", err)
}
if wt, ok := m["wait_type"]; !ok {
t.Error("wait_type field missing from JSON")
} else if wt != "permission" {
t.Errorf("wait_type = %v, want %q", wt, "permission")
}
// WaitType="" should be omitted (omitempty)
info2 := SessionInfo{
SessionID: "sess-2",
State: "Working",
WaitType: "",
}
data2, err := json.Marshal(info2)
if err != nil {
t.Fatalf("marshal: %v", err)
}
var m2 map[string]interface{}
if err := json.Unmarshal(data2, &m2); err != nil {
t.Fatalf("unmarshal map: %v", err)
}
if _, ok := m2["wait_type"]; ok {
t.Error("wait_type should be omitted when empty")
}
}