1use crate::{CliOverridesPatch, ConfigOverride, FlagState};
2use serde::{Deserialize, Serialize};
3use serde_json::Value;
4use std::{collections::BTreeMap, process::ExitStatus};
5
6#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
8#[serde(from = "String", into = "String")]
9pub enum CodexFeatureStage {
10 Experimental,
11 Beta,
12 Stable,
13 Deprecated,
14 Removed,
15 Unknown(String),
16}
17
18impl CodexFeatureStage {
19 pub(crate) fn parse(raw: &str) -> Self {
20 let normalized = raw.trim();
21 match normalized.to_ascii_lowercase().as_str() {
22 "experimental" => CodexFeatureStage::Experimental,
23 "beta" => CodexFeatureStage::Beta,
24 "stable" => CodexFeatureStage::Stable,
25 "deprecated" => CodexFeatureStage::Deprecated,
26 "removed" => CodexFeatureStage::Removed,
27 _ => CodexFeatureStage::Unknown(normalized.to_string()),
28 }
29 }
30
31 pub fn as_str(&self) -> &str {
33 match self {
34 CodexFeatureStage::Experimental => "experimental",
35 CodexFeatureStage::Beta => "beta",
36 CodexFeatureStage::Stable => "stable",
37 CodexFeatureStage::Deprecated => "deprecated",
38 CodexFeatureStage::Removed => "removed",
39 CodexFeatureStage::Unknown(label) => label.as_str(),
40 }
41 }
42}
43
44impl From<String> for CodexFeatureStage {
45 fn from(value: String) -> Self {
46 CodexFeatureStage::parse(&value)
47 }
48}
49
50impl From<CodexFeatureStage> for String {
51 fn from(stage: CodexFeatureStage) -> Self {
52 String::from(&stage)
53 }
54}
55
56impl From<&CodexFeatureStage> for String {
57 fn from(stage: &CodexFeatureStage) -> Self {
58 stage.as_str().to_string()
59 }
60}
61
62#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
64pub struct CodexFeature {
65 pub name: String,
67 #[serde(default, skip_serializing_if = "Option::is_none")]
69 pub stage: Option<CodexFeatureStage>,
70 pub enabled: bool,
72 #[serde(flatten, default, skip_serializing_if = "BTreeMap::is_empty")]
74 pub extra: BTreeMap<String, Value>,
75}
76
77impl CodexFeature {
78 pub const fn is_enabled(&self) -> bool {
80 self.enabled
81 }
82}
83
84#[derive(Clone, Copy, Debug, Eq, PartialEq)]
86pub enum FeaturesListFormat {
87 Json,
88 Text,
89}
90
91#[derive(Clone, Debug, Eq, PartialEq)]
93pub struct FeaturesListOutput {
94 pub status: ExitStatus,
96 pub stdout: String,
98 pub stderr: String,
100 pub features: Vec<CodexFeature>,
102 pub format: FeaturesListFormat,
104}
105
106#[derive(Clone, Debug, Eq, PartialEq)]
108pub struct FeaturesListRequest {
109 pub json: bool,
111 pub overrides: CliOverridesPatch,
113}
114
115impl FeaturesListRequest {
116 pub fn new() -> Self {
118 Self {
119 json: false,
120 overrides: CliOverridesPatch::default(),
121 }
122 }
123
124 pub fn json(mut self, enable: bool) -> Self {
126 self.json = enable;
127 self
128 }
129
130 pub fn with_overrides(mut self, overrides: CliOverridesPatch) -> Self {
132 self.overrides = overrides;
133 self
134 }
135
136 pub fn config_override(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
138 self.overrides
139 .config_overrides
140 .push(ConfigOverride::new(key, value));
141 self
142 }
143
144 pub fn config_override_raw(mut self, raw: impl Into<String>) -> Self {
146 self.overrides
147 .config_overrides
148 .push(ConfigOverride::from_raw(raw));
149 self
150 }
151
152 pub fn profile(mut self, profile: impl Into<String>) -> Self {
154 let profile = profile.into();
155 self.overrides.profile = (!profile.trim().is_empty()).then_some(profile);
156 self
157 }
158
159 pub fn oss(mut self, enable: bool) -> Self {
161 self.overrides.oss = if enable {
162 FlagState::Enable
163 } else {
164 FlagState::Disable
165 };
166 self
167 }
168
169 pub fn enable_feature(mut self, name: impl Into<String>) -> Self {
171 self.overrides.feature_toggles.enable.push(name.into());
172 self
173 }
174
175 pub fn disable_feature(mut self, name: impl Into<String>) -> Self {
177 self.overrides.feature_toggles.disable.push(name.into());
178 self
179 }
180
181 pub fn search(mut self, enable: bool) -> Self {
183 self.overrides.search = if enable {
184 FlagState::Enable
185 } else {
186 FlagState::Disable
187 };
188 self
189 }
190}
191
192impl Default for FeaturesListRequest {
193 fn default() -> Self {
194 Self::new()
195 }
196}
197
198#[derive(Clone, Debug, Eq, PartialEq)]
200pub struct FeaturesCommandRequest {
201 pub overrides: CliOverridesPatch,
203}
204
205impl FeaturesCommandRequest {
206 pub fn new() -> Self {
207 Self {
208 overrides: CliOverridesPatch::default(),
209 }
210 }
211
212 pub fn with_overrides(mut self, overrides: CliOverridesPatch) -> Self {
214 self.overrides = overrides;
215 self
216 }
217}
218
219impl Default for FeaturesCommandRequest {
220 fn default() -> Self {
221 Self::new()
222 }
223}
224
225#[derive(Clone, Debug, Eq, PartialEq)]
227pub struct FeaturesEnableRequest {
228 pub feature: String,
230 pub overrides: CliOverridesPatch,
232}
233
234impl FeaturesEnableRequest {
235 pub fn new(feature: impl Into<String>) -> Self {
236 Self {
237 feature: feature.into(),
238 overrides: CliOverridesPatch::default(),
239 }
240 }
241
242 pub fn with_overrides(mut self, overrides: CliOverridesPatch) -> Self {
244 self.overrides = overrides;
245 self
246 }
247}
248
249#[derive(Clone, Debug, Eq, PartialEq)]
251pub struct FeaturesDisableRequest {
252 pub feature: String,
254 pub overrides: CliOverridesPatch,
256}
257
258impl FeaturesDisableRequest {
259 pub fn new(feature: impl Into<String>) -> Self {
260 Self {
261 feature: feature.into(),
262 overrides: CliOverridesPatch::default(),
263 }
264 }
265
266 pub fn with_overrides(mut self, overrides: CliOverridesPatch) -> Self {
268 self.overrides = overrides;
269 self
270 }
271}