ricecoder_hooks/events/
system.rs

1//! System events for ricecoder
2//!
3//! This module defines system events that can trigger hooks, such as file saves,
4//! test completions, and code generation completions.
5
6use serde::{Deserialize, Serialize};
7
8/// System event types
9///
10/// These events are emitted by ricecoder components and can trigger registered hooks.
11#[derive(Debug, Clone, Serialize, Deserialize)]
12#[serde(tag = "type")]
13pub enum SystemEvent {
14    /// File was saved
15    #[serde(rename = "file_saved")]
16    FileSaved(FileSavedEvent),
17
18    /// Test execution completed
19    #[serde(rename = "test_passed")]
20    TestPassed(TestPassedEvent),
21
22    /// Test execution failed
23    #[serde(rename = "test_failed")]
24    TestFailed(TestFailedEvent),
25
26    /// Code generation completed
27    #[serde(rename = "generation_complete")]
28    GenerationComplete(GenerationCompleteEvent),
29
30    /// Code refactoring completed
31    #[serde(rename = "refactoring_complete")]
32    RefactoringComplete(RefactoringCompleteEvent),
33
34    /// Code review completed
35    #[serde(rename = "review_complete")]
36    ReviewComplete(ReviewCompleteEvent),
37
38    /// Build completed successfully
39    #[serde(rename = "build_success")]
40    BuildSuccess(BuildSuccessEvent),
41
42    /// Build failed
43    #[serde(rename = "build_failed")]
44    BuildFailedEvent(BuildFailedEvent),
45
46    /// Deployment completed
47    #[serde(rename = "deployment_complete")]
48    DeploymentComplete(DeploymentCompleteEvent),
49
50    /// Custom event
51    #[serde(rename = "custom")]
52    Custom(CustomEvent),
53}
54
55/// File saved event
56///
57/// Emitted when a file is saved in the editor or through the CLI.
58#[derive(Debug, Clone, Serialize, Deserialize)]
59pub struct FileSavedEvent {
60    /// Path to the saved file
61    pub file_path: String,
62
63    /// File size in bytes
64    pub size: u64,
65
66    /// File hash (SHA256)
67    pub hash: String,
68
69    /// Timestamp of the save
70    pub timestamp: String,
71
72    /// Language of the file (if detected)
73    pub language: Option<String>,
74}
75
76/// Test passed event
77///
78/// Emitted when a test execution completes successfully.
79#[derive(Debug, Clone, Serialize, Deserialize)]
80pub struct TestPassedEvent {
81    /// Test name or path
82    pub test_name: String,
83
84    /// Duration in milliseconds
85    pub duration_ms: u64,
86
87    /// Number of assertions passed
88    pub assertions_passed: u32,
89
90    /// Timestamp of the test completion
91    pub timestamp: String,
92}
93
94/// Test failed event
95///
96/// Emitted when a test execution fails.
97#[derive(Debug, Clone, Serialize, Deserialize)]
98pub struct TestFailedEvent {
99    /// Test name or path
100    pub test_name: String,
101
102    /// Duration in milliseconds
103    pub duration_ms: u64,
104
105    /// Number of assertions failed
106    pub assertions_failed: u32,
107
108    /// Error message
109    pub error_message: String,
110
111    /// Timestamp of the test completion
112    pub timestamp: String,
113}
114
115/// Code generation completed event
116///
117/// Emitted when code generation from a specification completes.
118#[derive(Debug, Clone, Serialize, Deserialize)]
119pub struct GenerationCompleteEvent {
120    /// Specification file path
121    pub spec_path: String,
122
123    /// Output directory
124    pub output_dir: String,
125
126    /// Number of files generated
127    pub files_generated: u32,
128
129    /// Duration in milliseconds
130    pub duration_ms: u64,
131
132    /// Timestamp of the completion
133    pub timestamp: String,
134}
135
136/// Code refactoring completed event
137///
138/// Emitted when code refactoring completes.
139#[derive(Debug, Clone, Serialize, Deserialize)]
140pub struct RefactoringCompleteEvent {
141    /// File path that was refactored
142    pub file_path: String,
143
144    /// Number of changes made
145    pub changes_made: u32,
146
147    /// Duration in milliseconds
148    pub duration_ms: u64,
149
150    /// Timestamp of the completion
151    pub timestamp: String,
152}
153
154/// Code review completed event
155///
156/// Emitted when a code review completes.
157#[derive(Debug, Clone, Serialize, Deserialize)]
158pub struct ReviewCompleteEvent {
159    /// File path that was reviewed
160    pub file_path: String,
161
162    /// Number of issues found
163    pub issues_found: u32,
164
165    /// Severity level (info, warning, error)
166    pub severity: String,
167
168    /// Duration in milliseconds
169    pub duration_ms: u64,
170
171    /// Timestamp of the completion
172    pub timestamp: String,
173}
174
175/// Build success event
176///
177/// Emitted when a build completes successfully.
178#[derive(Debug, Clone, Serialize, Deserialize)]
179pub struct BuildSuccessEvent {
180    /// Build target
181    pub target: String,
182
183    /// Duration in milliseconds
184    pub duration_ms: u64,
185
186    /// Output artifacts
187    pub artifacts: Vec<String>,
188
189    /// Timestamp of the completion
190    pub timestamp: String,
191}
192
193/// Build failed event
194///
195/// Emitted when a build fails.
196#[derive(Debug, Clone, Serialize, Deserialize)]
197pub struct BuildFailedEvent {
198    /// Build target
199    pub target: String,
200
201    /// Duration in milliseconds
202    pub duration_ms: u64,
203
204    /// Error message
205    pub error_message: String,
206
207    /// Timestamp of the completion
208    pub timestamp: String,
209}
210
211/// Deployment completed event
212///
213/// Emitted when a deployment completes.
214#[derive(Debug, Clone, Serialize, Deserialize)]
215pub struct DeploymentCompleteEvent {
216    /// Deployment target
217    pub target: String,
218
219    /// Deployment environment
220    pub environment: String,
221
222    /// Duration in milliseconds
223    pub duration_ms: u64,
224
225    /// Timestamp of the completion
226    pub timestamp: String,
227}
228
229/// Custom event
230///
231/// Allows for custom events to be emitted and handled by hooks.
232#[derive(Debug, Clone, Serialize, Deserialize)]
233pub struct CustomEvent {
234    /// Event name
235    pub name: String,
236
237    /// Event data
238    pub data: serde_json::Value,
239
240    /// Timestamp of the event
241    pub timestamp: String,
242}
243
244impl SystemEvent {
245    /// Get the event type as a string
246    pub fn event_type(&self) -> &'static str {
247        match self {
248            SystemEvent::FileSaved(_) => "file_saved",
249            SystemEvent::TestPassed(_) => "test_passed",
250            SystemEvent::TestFailed(_) => "test_failed",
251            SystemEvent::GenerationComplete(_) => "generation_complete",
252            SystemEvent::RefactoringComplete(_) => "refactoring_complete",
253            SystemEvent::ReviewComplete(_) => "review_complete",
254            SystemEvent::BuildSuccess(_) => "build_success",
255            SystemEvent::BuildFailedEvent(_) => "build_failed",
256            SystemEvent::DeploymentComplete(_) => "deployment_complete",
257            SystemEvent::Custom(_) => "custom",
258        }
259    }
260
261    /// Convert to event context
262    pub fn to_event_context(&self) -> crate::types::EventContext {
263        crate::types::EventContext {
264            data: serde_json::to_value(self).unwrap_or(serde_json::json!({})),
265            metadata: serde_json::json!({
266                "event_type": self.event_type(),
267                "timestamp": chrono::Utc::now().to_rfc3339(),
268            }),
269        }
270    }
271}
272
273#[cfg(test)]
274mod tests {
275    use super::*;
276
277    #[test]
278    fn test_file_saved_event() {
279        let event = FileSavedEvent {
280            file_path: "/path/to/file.rs".to_string(),
281            size: 1024,
282            hash: "abc123".to_string(),
283            timestamp: "2024-01-01T12:00:00Z".to_string(),
284            language: Some("rust".to_string()),
285        };
286
287        assert_eq!(event.file_path, "/path/to/file.rs");
288        assert_eq!(event.size, 1024);
289    }
290
291    #[test]
292    fn test_test_passed_event() {
293        let event = TestPassedEvent {
294            test_name: "test_example".to_string(),
295            duration_ms: 100,
296            assertions_passed: 5,
297            timestamp: "2024-01-01T12:00:00Z".to_string(),
298        };
299
300        assert_eq!(event.test_name, "test_example");
301        assert_eq!(event.duration_ms, 100);
302    }
303
304    #[test]
305    fn test_system_event_type() {
306        let event = SystemEvent::FileSaved(FileSavedEvent {
307            file_path: "/path/to/file.rs".to_string(),
308            size: 1024,
309            hash: "abc123".to_string(),
310            timestamp: "2024-01-01T12:00:00Z".to_string(),
311            language: Some("rust".to_string()),
312        });
313
314        assert_eq!(event.event_type(), "file_saved");
315    }
316
317    #[test]
318    fn test_custom_event() {
319        let event = SystemEvent::Custom(CustomEvent {
320            name: "my_event".to_string(),
321            data: serde_json::json!({"key": "value"}),
322            timestamp: "2024-01-01T12:00:00Z".to_string(),
323        });
324
325        assert_eq!(event.event_type(), "custom");
326    }
327
328    #[test]
329    fn test_event_serialization() {
330        let event = SystemEvent::FileSaved(FileSavedEvent {
331            file_path: "/path/to/file.rs".to_string(),
332            size: 1024,
333            hash: "abc123".to_string(),
334            timestamp: "2024-01-01T12:00:00Z".to_string(),
335            language: Some("rust".to_string()),
336        });
337
338        let json = serde_json::to_string(&event).unwrap();
339        assert!(json.contains("file_saved"));
340        assert!(json.contains("/path/to/file.rs"));
341    }
342}