Skip to main content

codex_wrapper/
types.rs

1use std::collections::HashMap;
2use std::fmt;
3use std::str::FromStr;
4
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
8#[serde(rename_all = "kebab-case")]
9pub enum SandboxMode {
10    ReadOnly,
11    #[default]
12    WorkspaceWrite,
13    DangerFullAccess,
14}
15
16impl SandboxMode {
17    pub(crate) fn as_arg(self) -> &'static str {
18        match self {
19            Self::ReadOnly => "read-only",
20            Self::WorkspaceWrite => "workspace-write",
21            Self::DangerFullAccess => "danger-full-access",
22        }
23    }
24}
25
26#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
27#[serde(rename_all = "kebab-case")]
28pub enum ApprovalPolicy {
29    Untrusted,
30    OnFailure,
31    #[default]
32    OnRequest,
33    Never,
34}
35
36impl ApprovalPolicy {
37    pub(crate) fn as_arg(self) -> &'static str {
38        match self {
39            Self::Untrusted => "untrusted",
40            Self::OnFailure => "on-failure",
41            Self::OnRequest => "on-request",
42            Self::Never => "never",
43        }
44    }
45}
46
47#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
48#[serde(rename_all = "lowercase")]
49pub enum Color {
50    Always,
51    Never,
52    #[default]
53    Auto,
54}
55
56impl Color {
57    pub(crate) fn as_arg(self) -> &'static str {
58        match self {
59            Self::Always => "always",
60            Self::Never => "never",
61            Self::Auto => "auto",
62        }
63    }
64}
65
66#[cfg(feature = "json")]
67#[derive(Debug, Clone, Deserialize, Serialize)]
68pub struct JsonLineEvent {
69    #[serde(rename = "type", default)]
70    pub event_type: String,
71    #[serde(flatten)]
72    pub extra: HashMap<String, serde_json::Value>,
73}
74
75#[derive(Debug, Clone, Copy, PartialEq, Eq)]
76pub struct CliVersion {
77    pub major: u32,
78    pub minor: u32,
79    pub patch: u32,
80}
81
82impl CliVersion {
83    #[must_use]
84    pub fn new(major: u32, minor: u32, patch: u32) -> Self {
85        Self {
86            major,
87            minor,
88            patch,
89        }
90    }
91
92    pub fn parse_version_output(output: &str) -> Result<Self, VersionParseError> {
93        output
94            .split_whitespace()
95            .find_map(|token| token.parse().ok())
96            .ok_or_else(|| VersionParseError(output.trim().to_string()))
97    }
98
99    #[must_use]
100    pub fn satisfies_minimum(&self, minimum: &CliVersion) -> bool {
101        self >= minimum
102    }
103}
104
105impl PartialOrd for CliVersion {
106    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
107        Some(self.cmp(other))
108    }
109}
110
111impl Ord for CliVersion {
112    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
113        self.major
114            .cmp(&other.major)
115            .then(self.minor.cmp(&other.minor))
116            .then(self.patch.cmp(&other.patch))
117    }
118}
119
120impl fmt::Display for CliVersion {
121    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
122        write!(f, "{}.{}.{}", self.major, self.minor, self.patch)
123    }
124}
125
126impl FromStr for CliVersion {
127    type Err = VersionParseError;
128
129    fn from_str(s: &str) -> Result<Self, Self::Err> {
130        let parts: Vec<&str> = s.split('.').collect();
131        if parts.len() != 3 {
132            return Err(VersionParseError(s.to_string()));
133        }
134
135        Ok(Self {
136            major: parts[0]
137                .parse()
138                .map_err(|_| VersionParseError(s.to_string()))?,
139            minor: parts[1]
140                .parse()
141                .map_err(|_| VersionParseError(s.to_string()))?,
142            patch: parts[2]
143                .parse()
144                .map_err(|_| VersionParseError(s.to_string()))?,
145        })
146    }
147}
148
149#[derive(Debug, Clone, thiserror::Error)]
150#[error("invalid version string: {0:?}")]
151pub struct VersionParseError(pub String);
152
153#[cfg(test)]
154mod tests {
155    use super::*;
156
157    #[test]
158    fn parses_codex_version_output() {
159        let version = CliVersion::parse_version_output("codex-cli 0.116.0").unwrap();
160        assert_eq!(version, CliVersion::new(0, 116, 0));
161    }
162
163    #[test]
164    fn parses_plain_version_output() {
165        let version = CliVersion::parse_version_output("0.116.0").unwrap();
166        assert_eq!(version, CliVersion::new(0, 116, 0));
167    }
168}