1use crate::types::CallerKind;
2
3pub fn normalize_event(vendor: &str, caller: &CallerKind) -> String {
7 let canonical = match caller {
8 CallerKind::ClaudeCode => normalize_claude_code_event(vendor),
9 CallerKind::Cursor => normalize_cursor_event(vendor),
10 CallerKind::Windsurf => normalize_windsurf_event(vendor),
11 CallerKind::Cline => normalize_cline_event(vendor),
12 CallerKind::Amp => normalize_amp_event(vendor),
13 CallerKind::Unknown => None,
14 };
15
16 canonical
17 .map(|s| s.to_owned())
18 .unwrap_or_else(|| vendor.to_owned())
19}
20
21fn normalize_claude_code_event(vendor: &str) -> Option<&'static str> {
22 match vendor {
23 "PreToolUse" => Some("tool:before"),
24 "PostToolUse" => Some("tool:after"),
25 "Startup" => Some("session:start"),
26 "Stop" => Some("session:stop"),
27 "SubagentStop" => Some("agent:stop"),
28 "Notification" => Some("notification"),
29 _ => None,
30 }
31}
32
33fn normalize_cursor_event(vendor: &str) -> Option<&'static str> {
34 match vendor {
35 "BeforeToolCall" => Some("tool:before"),
36 "AfterToolCall" => Some("tool:after"),
37 "SessionStart" => Some("session:start"),
38 "SessionEnd" => Some("session:stop"),
39 "Notification" => Some("notification"),
40 _ => None,
41 }
42}
43
44fn normalize_windsurf_event(vendor: &str) -> Option<&'static str> {
45 match vendor {
46 "pre_tool" => Some("tool:before"),
47 "post_tool" => Some("tool:after"),
48 "session_start" => Some("session:start"),
49 "session_end" => Some("session:stop"),
50 "notification" => Some("notification"),
51 _ => None,
52 }
53}
54
55fn normalize_cline_event(vendor: &str) -> Option<&'static str> {
56 match vendor {
57 "beforeToolUse" => Some("tool:before"),
58 "afterToolUse" => Some("tool:after"),
59 "onStart" => Some("session:start"),
60 "onStop" => Some("session:stop"),
61 _ => None,
62 }
63}
64
65fn normalize_amp_event(vendor: &str) -> Option<&'static str> {
66 match vendor {
67 "tool.before" => Some("tool:before"),
68 "tool.after" => Some("tool:after"),
69 "session.start" => Some("session:start"),
70 "session.stop" => Some("session:stop"),
71 "agent.stop" => Some("agent:stop"),
72 _ => None,
73 }
74}
75
76#[cfg(test)]
81mod tests {
82 use super::normalize_event;
83 use crate::CallerKind;
84
85 #[test]
86 fn unknown_caller_returns_original_string() {
87 assert_eq!(normalize_event("SomeVendorEvent", &CallerKind::Unknown), "SomeVendorEvent");
88 assert_eq!(normalize_event("PreToolUse", &CallerKind::Unknown), "PreToolUse");
89 assert_eq!(normalize_event("", &CallerKind::Unknown), "");
90 }
91
92 #[test] fn cc_startup() { assert_eq!(normalize_event("Startup", &CallerKind::ClaudeCode), "session:start"); }
94 #[test] fn cc_stop() { assert_eq!(normalize_event("Stop", &CallerKind::ClaudeCode), "session:stop"); }
95 #[test] fn cc_subagent_stop(){ assert_eq!(normalize_event("SubagentStop", &CallerKind::ClaudeCode), "agent:stop"); }
96 #[test] fn cc_notification() { assert_eq!(normalize_event("Notification", &CallerKind::ClaudeCode), "notification"); }
97 #[test] fn cc_unknown_falls_through() { assert_eq!(normalize_event("Bogus", &CallerKind::ClaudeCode), "Bogus"); }
98
99 #[test] fn cur_session_start() { assert_eq!(normalize_event("SessionStart", &CallerKind::Cursor), "session:start"); }
101 #[test] fn cur_session_end() { assert_eq!(normalize_event("SessionEnd", &CallerKind::Cursor), "session:stop"); }
102 #[test] fn cur_notification() { assert_eq!(normalize_event("Notification", &CallerKind::Cursor), "notification"); }
103 #[test] fn cur_unknown_falls_through() { assert_eq!(normalize_event("Bogus", &CallerKind::Cursor), "Bogus"); }
104
105 #[test] fn ws_session_start() { assert_eq!(normalize_event("session_start", &CallerKind::Windsurf), "session:start"); }
107 #[test] fn ws_session_end() { assert_eq!(normalize_event("session_end", &CallerKind::Windsurf), "session:stop"); }
108 #[test] fn ws_notification() { assert_eq!(normalize_event("notification", &CallerKind::Windsurf), "notification"); }
109 #[test] fn ws_unknown_falls_through() { assert_eq!(normalize_event("bogus", &CallerKind::Windsurf), "bogus"); }
110
111 #[test] fn cl_on_start() { assert_eq!(normalize_event("onStart", &CallerKind::Cline), "session:start"); }
113 #[test] fn cl_on_stop() { assert_eq!(normalize_event("onStop", &CallerKind::Cline), "session:stop"); }
114 #[test] fn cl_unknown_falls_through() { assert_eq!(normalize_event("bogus", &CallerKind::Cline), "bogus"); }
115
116 #[test] fn amp_session_start() { assert_eq!(normalize_event("session.start", &CallerKind::Amp), "session:start"); }
118 #[test] fn amp_session_stop() { assert_eq!(normalize_event("session.stop", &CallerKind::Amp), "session:stop"); }
119 #[test] fn amp_agent_stop() { assert_eq!(normalize_event("agent.stop", &CallerKind::Amp), "agent:stop"); }
120 #[test] fn amp_unknown_falls_through() { assert_eq!(normalize_event("bogus.bogus", &CallerKind::Amp), "bogus.bogus"); }
121}