Skip to main content

codex_wrapper/command/
login.rs

1use crate::Codex;
2use crate::command::CodexCommand;
3use crate::error::Result;
4use crate::exec::{self, CommandOutput};
5
6#[derive(Debug, Clone, Default)]
7pub struct LoginCommand {
8    config_overrides: Vec<String>,
9    enabled_features: Vec<String>,
10    disabled_features: Vec<String>,
11    with_api_key: bool,
12    with_access_token: bool,
13    device_auth: bool,
14}
15
16impl LoginCommand {
17    #[must_use]
18    pub fn new() -> Self {
19        Self::default()
20    }
21
22    #[must_use]
23    pub fn config(mut self, key_value: impl Into<String>) -> Self {
24        self.config_overrides.push(key_value.into());
25        self
26    }
27
28    #[must_use]
29    pub fn enable(mut self, feature: impl Into<String>) -> Self {
30        self.enabled_features.push(feature.into());
31        self
32    }
33
34    #[must_use]
35    pub fn disable(mut self, feature: impl Into<String>) -> Self {
36        self.disabled_features.push(feature.into());
37        self
38    }
39
40    #[must_use]
41    pub fn with_api_key(mut self) -> Self {
42        self.with_api_key = true;
43        self
44    }
45
46    /// Read an access token from stdin (`--with-access-token`).
47    #[must_use]
48    pub fn with_access_token(mut self) -> Self {
49        self.with_access_token = true;
50        self
51    }
52
53    #[must_use]
54    pub fn device_auth(mut self) -> Self {
55        self.device_auth = true;
56        self
57    }
58}
59
60impl CodexCommand for LoginCommand {
61    type Output = CommandOutput;
62
63    fn args(&self) -> Vec<String> {
64        let mut args = vec!["login".into()];
65        push_common(
66            &mut args,
67            &self.config_overrides,
68            &self.enabled_features,
69            &self.disabled_features,
70        );
71        if self.with_api_key {
72            args.push("--with-api-key".into());
73        }
74        if self.with_access_token {
75            args.push("--with-access-token".into());
76        }
77        if self.device_auth {
78            args.push("--device-auth".into());
79        }
80        args
81    }
82
83    async fn execute(&self, codex: &Codex) -> Result<CommandOutput> {
84        exec::run_codex(codex, self.args()).await
85    }
86}
87
88#[derive(Debug, Clone, Default)]
89pub struct LoginStatusCommand {
90    config_overrides: Vec<String>,
91    enabled_features: Vec<String>,
92    disabled_features: Vec<String>,
93}
94
95impl LoginStatusCommand {
96    #[must_use]
97    pub fn new() -> Self {
98        Self::default()
99    }
100
101    #[must_use]
102    pub fn config(mut self, key_value: impl Into<String>) -> Self {
103        self.config_overrides.push(key_value.into());
104        self
105    }
106
107    #[must_use]
108    pub fn enable(mut self, feature: impl Into<String>) -> Self {
109        self.enabled_features.push(feature.into());
110        self
111    }
112
113    #[must_use]
114    pub fn disable(mut self, feature: impl Into<String>) -> Self {
115        self.disabled_features.push(feature.into());
116        self
117    }
118}
119
120impl CodexCommand for LoginStatusCommand {
121    type Output = CommandOutput;
122
123    fn args(&self) -> Vec<String> {
124        let mut args = vec!["login".into(), "status".into()];
125        push_common(
126            &mut args,
127            &self.config_overrides,
128            &self.enabled_features,
129            &self.disabled_features,
130        );
131        args
132    }
133
134    async fn execute(&self, codex: &Codex) -> Result<CommandOutput> {
135        exec::run_codex(codex, self.args()).await
136    }
137}
138
139#[derive(Debug, Clone, Default)]
140pub struct LogoutCommand;
141
142impl LogoutCommand {
143    #[must_use]
144    pub fn new() -> Self {
145        Self
146    }
147}
148
149impl CodexCommand for LogoutCommand {
150    type Output = CommandOutput;
151
152    fn args(&self) -> Vec<String> {
153        vec!["logout".into()]
154    }
155
156    async fn execute(&self, codex: &Codex) -> Result<CommandOutput> {
157        exec::run_codex(codex, self.args()).await
158    }
159}
160
161fn push_common(
162    args: &mut Vec<String>,
163    configs: &[String],
164    enabled: &[String],
165    disabled: &[String],
166) {
167    for value in configs {
168        args.push("-c".into());
169        args.push(value.clone());
170    }
171    for value in enabled {
172        args.push("--enable".into());
173        args.push(value.clone());
174    }
175    for value in disabled {
176        args.push("--disable".into());
177        args.push(value.clone());
178    }
179}
180
181#[cfg(test)]
182mod tests {
183    use super::*;
184
185    #[test]
186    fn login_args() {
187        assert_eq!(
188            LoginCommand::new().with_api_key().args(),
189            vec!["login", "--with-api-key"]
190        );
191    }
192
193    #[test]
194    fn login_with_access_token_args() {
195        assert_eq!(
196            LoginCommand::new().with_access_token().args(),
197            vec!["login", "--with-access-token"]
198        );
199    }
200
201    #[test]
202    fn login_status_args() {
203        assert_eq!(LoginStatusCommand::new().args(), vec!["login", "status"]);
204    }
205
206    #[test]
207    fn logout_args() {
208        assert_eq!(LogoutCommand::new().args(), vec!["logout"]);
209    }
210}