yarli_cli/stream/
events.rs1use std::time::Duration;
8
9use chrono::{DateTime, Utc};
10use uuid::Uuid;
11
12use crate::yarli_core::domain::TaskId;
13use crate::yarli_core::entities::ContinuationPayload;
14use crate::yarli_core::fsm::run::RunState;
15use crate::yarli_core::fsm::task::TaskState;
16
17#[derive(Debug, Clone)]
19pub enum StreamEvent {
20 TaskDiscovered {
22 task_id: TaskId,
23 task_name: String,
24 depends_on: Vec<String>,
25 },
26
27 TaskTransition {
29 task_id: TaskId,
30 task_name: String,
31 from: TaskState,
32 to: TaskState,
33 elapsed: Option<Duration>,
34 exit_code: Option<i32>,
35 detail: Option<String>,
36 at: DateTime<Utc>,
37 },
38
39 RunTransition {
41 run_id: Uuid,
42 from: RunState,
43 to: RunState,
44 reason: Option<String>,
45 at: DateTime<Utc>,
46 },
47
48 CommandOutput {
50 task_id: TaskId,
51 task_name: String,
52 line: String,
53 },
54
55 TransientStatus { message: String },
58
59 ExplainUpdate { summary: String },
61
62 TaskWorker { task_id: TaskId, worker_id: String },
64
65 RunStarted {
67 run_id: Uuid,
68 objective: String,
69 at: DateTime<Utc>,
70 },
71
72 RunExited { payload: ContinuationPayload },
74
75 Tick,
77}
78
79#[derive(Debug, Clone)]
81pub struct TaskView {
82 pub task_id: TaskId,
83 pub name: String,
84 pub state: TaskState,
85 pub elapsed: Option<Duration>,
86 pub last_output_line: Option<String>,
87 pub blocked_by: Option<String>,
88 pub worker_id: Option<String>,
89}
90
91impl TaskView {
92 pub fn is_active(&self) -> bool {
94 matches!(
95 self.state,
96 TaskState::TaskExecuting | TaskState::TaskWaiting
97 )
98 }
99
100 pub fn is_terminal(&self) -> bool {
102 self.state.is_terminal()
103 }
104}
105
106#[cfg(test)]
107mod tests {
108 use super::*;
109
110 #[test]
111 fn task_view_active_states() {
112 let mut v = TaskView {
113 task_id: Uuid::new_v4(),
114 name: "test".into(),
115 state: TaskState::TaskExecuting,
116 elapsed: None,
117 last_output_line: None,
118 blocked_by: None,
119 worker_id: None,
120 };
121 assert!(v.is_active());
122
123 v.state = TaskState::TaskWaiting;
124 assert!(v.is_active());
125
126 v.state = TaskState::TaskReady;
127 assert!(!v.is_active());
128 }
129
130 #[test]
131 fn task_view_terminal_states() {
132 let mut v = TaskView {
133 task_id: Uuid::new_v4(),
134 name: "test".into(),
135 state: TaskState::TaskComplete,
136 elapsed: None,
137 last_output_line: None,
138 blocked_by: None,
139 worker_id: None,
140 };
141 assert!(v.is_terminal());
142
143 v.state = TaskState::TaskFailed;
144 assert!(v.is_terminal());
145
146 v.state = TaskState::TaskExecuting;
147 assert!(!v.is_terminal());
148 }
149}