navi_core/tool/
background.rs1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
5#[serde(rename_all = "snake_case")]
6pub enum BackgroundTaskStatus {
7 Running,
8 Completed,
9 Failed,
10 TimedOut,
11 Cancelled,
12}
13
14impl BackgroundTaskStatus {
15 pub fn is_final(self) -> bool {
16 self != Self::Running
17 }
18}
19
20impl std::fmt::Display for BackgroundTaskStatus {
21 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22 match self {
23 Self::Running => f.write_str("running"),
24 Self::Completed => f.write_str("completed"),
25 Self::Failed => f.write_str("failed"),
26 Self::TimedOut => f.write_str("timed_out"),
27 Self::Cancelled => f.write_str("cancelled"),
28 }
29 }
30}
31
32#[derive(Debug, Clone, Serialize, Deserialize)]
34pub struct BackgroundCommandSnapshot {
35 pub task_id: String,
36 pub command: String,
37 pub description: Option<String>,
38 pub status: BackgroundTaskStatus,
39 pub elapsed_ms: u64,
40 pub timeout_ms: u64,
41 pub exit_code: Option<i32>,
42 pub stdout: String,
43 pub stderr: String,
44 pub stdout_truncated: bool,
45 pub stderr_truncated: bool,
46 pub error: Option<String>,
47}
48
49impl BackgroundCommandSnapshot {
50 pub fn from_json(value: &serde_json::Value) -> Option<Self> {
53 let obj = value.as_object()?;
54 let task_id = obj.get("task_id")?.as_str()?.to_string();
55 let command = obj.get("command")?.as_str()?.to_string();
56 let description = obj
57 .get("description")
58 .and_then(|v| v.as_str())
59 .map(String::from);
60 let status_str = obj.get("status")?.as_str()?;
61 let status = match status_str {
62 "running" => BackgroundTaskStatus::Running,
63 "completed" => BackgroundTaskStatus::Completed,
64 "failed" => BackgroundTaskStatus::Failed,
65 "timed_out" => BackgroundTaskStatus::TimedOut,
66 "cancelled" => BackgroundTaskStatus::Cancelled,
67 _ => return None,
68 };
69 let elapsed_ms = obj.get("elapsed_ms")?.as_u64()?;
70 let timeout_ms = obj.get("timeout_ms")?.as_u64()?;
71 let exit_code = obj
72 .get("exit_code")
73 .and_then(|v| v.as_i64())
74 .map(|v| v as i32);
75 let stdout = obj
76 .get("stdout")
77 .and_then(|v| v.as_str())
78 .unwrap_or("")
79 .to_string();
80 let stderr = obj
81 .get("stderr")
82 .and_then(|v| v.as_str())
83 .unwrap_or("")
84 .to_string();
85 let stdout_truncated = obj
86 .get("stdout_truncated")
87 .and_then(|v| v.as_bool())
88 .unwrap_or(false);
89 let stderr_truncated = obj
90 .get("stderr_truncated")
91 .and_then(|v| v.as_bool())
92 .unwrap_or(false);
93 let error = obj.get("error").and_then(|v| v.as_str()).map(String::from);
94
95 Some(Self {
96 task_id,
97 command,
98 description,
99 status,
100 elapsed_ms,
101 timeout_ms,
102 exit_code,
103 stdout,
104 stderr,
105 stdout_truncated,
106 stderr_truncated,
107 error,
108 })
109 }
110
111 pub fn is_running(&self) -> bool {
113 self.status == BackgroundTaskStatus::Running
114 }
115}