Skip to main content

opencode_ralph_loop_cli/output/
mod.rs

1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
4#[serde(rename_all = "lowercase")]
5pub enum Action {
6    Created,
7    Updated,
8    Skipped,
9    Modified,
10    Missing,
11    Removed,
12}
13
14impl Action {
15    pub fn as_str(&self) -> &'static str {
16        match self {
17            Action::Created => "CREATED",
18            Action::Updated => "UPDATED",
19            Action::Skipped => "SKIPPED",
20            Action::Modified => "MODIFIED",
21            Action::Missing => "MISSING",
22            Action::Removed => "REMOVED",
23        }
24    }
25}
26
27#[derive(Debug, Clone, Serialize, Deserialize)]
28pub struct FileEntry {
29    pub path: String,
30    pub action: Action,
31    pub sha256: String,
32    pub expected_sha256: Option<String>,
33    pub size_bytes: u64,
34}
35
36#[derive(Debug, Clone, Serialize, Deserialize)]
37pub struct Summary {
38    pub created: usize,
39    pub updated: usize,
40    pub skipped: usize,
41    pub modified: usize,
42    pub missing: usize,
43    pub removed: usize,
44}
45
46impl Summary {
47    pub fn from_entries(entries: &[FileEntry]) -> Self {
48        let mut s = Self {
49            created: 0,
50            updated: 0,
51            skipped: 0,
52            modified: 0,
53            missing: 0,
54            removed: 0,
55        };
56        for e in entries {
57            match e.action {
58                Action::Created => s.created += 1,
59                Action::Updated => s.updated += 1,
60                Action::Skipped => s.skipped += 1,
61                Action::Modified => s.modified += 1,
62                Action::Missing => s.missing += 1,
63                Action::Removed => s.removed += 1,
64            }
65        }
66        s
67    }
68
69    pub fn has_drift(&self) -> bool {
70        self.modified > 0 || self.missing > 0
71    }
72}
73
74#[derive(Debug, Clone, Serialize, Deserialize)]
75pub struct Report {
76    pub status: String,
77    pub command: String,
78    pub files: Vec<FileEntry>,
79    pub summary: Summary,
80    pub cli_version: String,
81    pub schema_version: u32,
82    pub duration_ms: u64,
83    pub plugin_version: String,
84}
85
86impl Report {
87    pub fn new(command: impl Into<String>, plugin_version: impl Into<String>) -> Self {
88        Self {
89            status: "ok".to_string(),
90            command: command.into(),
91            files: Vec::new(),
92            summary: Summary {
93                created: 0,
94                updated: 0,
95                skipped: 0,
96                modified: 0,
97                missing: 0,
98                removed: 0,
99            },
100            cli_version: env!("CARGO_PKG_VERSION").to_string(),
101            schema_version: 1,
102            duration_ms: 0,
103            plugin_version: plugin_version.into(),
104        }
105    }
106
107    pub fn finalize(&mut self) {
108        self.summary = Summary::from_entries(&self.files);
109        if self.summary.has_drift() && self.status == "ok" {
110            self.status = "drift".to_string();
111        }
112    }
113
114    pub fn set_error(&mut self, msg: impl Into<String>) {
115        self.status = format!("error: {}", msg.into());
116    }
117}
118
119pub mod json;
120pub mod ndjson;
121pub mod text;