use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum HookEvent {
SessionStart,
SessionEnd,
UserPrompt,
PreToolCall,
PostToolCall,
ToolError,
PreApproval,
PostApproval,
Notification,
PreCompact,
PostCompact,
PromptBuild,
MessageSend,
SessionReset,
ModelResolve,
MessageReceived,
MessageSent,
AgentLoopEnd,
ToolResultPersist,
SubagentStart,
SubagentStop,
KernelStart,
KernelStop,
}
impl fmt::Display for HookEvent {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::SessionStart => write!(f, "session_start"),
Self::SessionEnd => write!(f, "session_end"),
Self::UserPrompt => write!(f, "user_prompt"),
Self::PreToolCall => write!(f, "pre_tool_call"),
Self::PostToolCall => write!(f, "post_tool_call"),
Self::ToolError => write!(f, "tool_error"),
Self::PreApproval => write!(f, "pre_approval"),
Self::PostApproval => write!(f, "post_approval"),
Self::Notification => write!(f, "notification"),
Self::PreCompact => write!(f, "pre_compact"),
Self::PostCompact => write!(f, "post_compact"),
Self::PromptBuild => write!(f, "prompt_build"),
Self::MessageSend => write!(f, "message_send"),
Self::SessionReset => write!(f, "session_reset"),
Self::ModelResolve => write!(f, "model_resolve"),
Self::MessageReceived => write!(f, "message_received"),
Self::MessageSent => write!(f, "message_sent"),
Self::AgentLoopEnd => write!(f, "agent_loop_end"),
Self::ToolResultPersist => write!(f, "tool_result_persist"),
Self::SubagentStart => write!(f, "subagent_start"),
Self::SubagentStop => write!(f, "subagent_stop"),
Self::KernelStart => write!(f, "kernel_start"),
Self::KernelStop => write!(f, "kernel_stop"),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn all_hook_events_have_display_and_serde_roundtrip() {
let hooks: Vec<HookEvent> = vec![
HookEvent::SessionStart,
HookEvent::SessionEnd,
HookEvent::UserPrompt,
HookEvent::PreToolCall,
HookEvent::PostToolCall,
HookEvent::ToolError,
HookEvent::PreApproval,
HookEvent::PostApproval,
HookEvent::Notification,
HookEvent::PreCompact,
HookEvent::PostCompact,
HookEvent::PromptBuild,
HookEvent::MessageSend,
HookEvent::SessionReset,
HookEvent::ModelResolve,
HookEvent::MessageReceived,
HookEvent::MessageSent,
HookEvent::AgentLoopEnd,
HookEvent::ToolResultPersist,
HookEvent::SubagentStart,
HookEvent::SubagentStop,
HookEvent::KernelStart,
HookEvent::KernelStop,
];
for hook in &hooks {
let display = hook.to_string();
assert!(
!display.is_empty(),
"Display must not be empty for {hook:?}"
);
let json = serde_json::to_string(hook).unwrap();
let parsed: HookEvent = serde_json::from_str(&json).unwrap();
assert_eq!(*hook, parsed, "serde round-trip failed for {hook:?}");
}
}
}