Skip to main content

starpod_hooks/
event.rs

1use serde::{Deserialize, Serialize};
2use std::fmt;
3
4/// Available hook event types.
5///
6/// Each variant represents a lifecycle point where hooks can observe or
7/// control agent behavior.
8///
9/// # Example
10///
11/// ```
12/// use starpod_hooks::HookEvent;
13///
14/// let event = HookEvent::PostToolUse;
15/// assert_eq!(event.to_string(), "PostToolUse");
16/// ```
17#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
18pub enum HookEvent {
19    /// Before a tool is executed. Can modify input or block execution.
20    PreToolUse,
21    /// After successful tool execution. Can observe results.
22    PostToolUse,
23    /// When tool execution fails.
24    PostToolUseFailure,
25    /// System notification (info, warning, error).
26    Notification,
27    /// When the user submits a prompt.
28    UserPromptSubmit,
29    /// When a session begins.
30    SessionStart,
31    /// When a session ends.
32    SessionEnd,
33    /// Agent stop event.
34    Stop,
35    /// Before a subagent starts.
36    SubagentStart,
37    /// After a subagent stops.
38    SubagentStop,
39    /// Before conversation compaction.
40    PreCompact,
41    /// When a permission decision is requested.
42    PermissionRequest,
43    /// Initial setup event.
44    Setup,
45    /// Teammate idle notification.
46    TeammateIdle,
47    /// Task completion event.
48    TaskCompleted,
49    /// Configuration change event.
50    ConfigChange,
51    /// Git worktree created.
52    WorktreeCreate,
53    /// Git worktree removed.
54    WorktreeRemove,
55}
56
57impl fmt::Display for HookEvent {
58    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59        match self {
60            HookEvent::PreToolUse => write!(f, "PreToolUse"),
61            HookEvent::PostToolUse => write!(f, "PostToolUse"),
62            HookEvent::PostToolUseFailure => write!(f, "PostToolUseFailure"),
63            HookEvent::Notification => write!(f, "Notification"),
64            HookEvent::UserPromptSubmit => write!(f, "UserPromptSubmit"),
65            HookEvent::SessionStart => write!(f, "SessionStart"),
66            HookEvent::SessionEnd => write!(f, "SessionEnd"),
67            HookEvent::Stop => write!(f, "Stop"),
68            HookEvent::SubagentStart => write!(f, "SubagentStart"),
69            HookEvent::SubagentStop => write!(f, "SubagentStop"),
70            HookEvent::PreCompact => write!(f, "PreCompact"),
71            HookEvent::PermissionRequest => write!(f, "PermissionRequest"),
72            HookEvent::Setup => write!(f, "Setup"),
73            HookEvent::TeammateIdle => write!(f, "TeammateIdle"),
74            HookEvent::TaskCompleted => write!(f, "TaskCompleted"),
75            HookEvent::ConfigChange => write!(f, "ConfigChange"),
76            HookEvent::WorktreeCreate => write!(f, "WorktreeCreate"),
77            HookEvent::WorktreeRemove => write!(f, "WorktreeRemove"),
78        }
79    }
80}
81
82#[cfg(test)]
83mod tests {
84    use super::*;
85
86    #[test]
87    fn display_matches_variant_name() {
88        assert_eq!(HookEvent::PreToolUse.to_string(), "PreToolUse");
89        assert_eq!(HookEvent::PostToolUse.to_string(), "PostToolUse");
90        assert_eq!(HookEvent::SessionStart.to_string(), "SessionStart");
91        assert_eq!(HookEvent::WorktreeRemove.to_string(), "WorktreeRemove");
92    }
93
94    #[test]
95    fn hook_event_equality() {
96        assert_eq!(HookEvent::Stop, HookEvent::Stop);
97        assert_ne!(HookEvent::Stop, HookEvent::Setup);
98    }
99
100    #[test]
101    fn hook_event_hash_works_in_hashmap() {
102        use std::collections::HashMap;
103        let mut map = HashMap::new();
104        map.insert(HookEvent::PreToolUse, "pre");
105        map.insert(HookEvent::PostToolUse, "post");
106        assert_eq!(map.get(&HookEvent::PreToolUse), Some(&"pre"));
107        assert_eq!(map.get(&HookEvent::PostToolUse), Some(&"post"));
108        assert_eq!(map.get(&HookEvent::Stop), None);
109    }
110
111    #[test]
112    fn serde_roundtrip() {
113        let event = HookEvent::ConfigChange;
114        let json = serde_json::to_string(&event).unwrap();
115        let back: HookEvent = serde_json::from_str(&json).unwrap();
116        assert_eq!(event, back);
117    }
118}