Skip to main content

codex/commands/
cloud.rs

1use std::ffi::OsString;
2
3use crate::{
4    ApplyDiffArtifacts, CloudApplyRequest, CloudDiffRequest, CloudExecRequest, CloudListOutput,
5    CloudListRequest, CloudOverviewRequest, CloudStatusRequest, CodexClient, CodexError,
6};
7
8impl CodexClient {
9    /// Runs `codex cloud --help` and returns captured output.
10    pub async fn cloud_overview(
11        &self,
12        request: CloudOverviewRequest,
13    ) -> Result<ApplyDiffArtifacts, CodexError> {
14        self.run_simple_command_with_overrides(
15            vec![OsString::from("cloud"), OsString::from("--help")],
16            request.overrides,
17        )
18        .await
19    }
20
21    /// Lists Codex Cloud tasks via `codex cloud list`.
22    pub async fn cloud_list(
23        &self,
24        request: CloudListRequest,
25    ) -> Result<CloudListOutput, CodexError> {
26        let CloudListRequest {
27            json,
28            env_id,
29            limit,
30            cursor,
31            overrides,
32        } = request;
33
34        let mut args = vec![OsString::from("cloud"), OsString::from("list")];
35        if let Some(env_id) = env_id {
36            args.push(OsString::from("--env"));
37            args.push(OsString::from(env_id));
38        }
39        if let Some(limit) = limit {
40            args.push(OsString::from("--limit"));
41            args.push(OsString::from(limit.to_string()));
42        }
43        if let Some(cursor) = cursor {
44            args.push(OsString::from("--cursor"));
45            args.push(OsString::from(cursor));
46        }
47        if json {
48            args.push(OsString::from("--json"));
49        }
50
51        let artifacts = self
52            .run_simple_command_with_overrides(args, overrides)
53            .await?;
54        let parsed = if json {
55            Some(serde_json::from_str(&artifacts.stdout).map_err(|source| {
56                CodexError::JsonParse {
57                    context: "cloud list",
58                    stdout: artifacts.stdout.clone(),
59                    source,
60                }
61            })?)
62        } else {
63            None
64        };
65
66        Ok(CloudListOutput {
67            status: artifacts.status,
68            stdout: artifacts.stdout,
69            stderr: artifacts.stderr,
70            json: parsed,
71        })
72    }
73
74    /// Shows the status of a Codex Cloud task via `codex cloud status <TASK_ID>`.
75    pub async fn cloud_status(
76        &self,
77        request: CloudStatusRequest,
78    ) -> Result<ApplyDiffArtifacts, CodexError> {
79        let task_id = request.task_id.trim();
80        if task_id.is_empty() {
81            return Err(CodexError::EmptyTaskId);
82        }
83
84        self.run_simple_command_with_overrides(
85            vec![
86                OsString::from("cloud"),
87                OsString::from("status"),
88                OsString::from(task_id),
89            ],
90            request.overrides,
91        )
92        .await
93    }
94
95    /// Shows the unified diff for a Codex Cloud task via `codex cloud diff [--attempt N] <TASK_ID>`.
96    pub async fn cloud_diff(
97        &self,
98        request: CloudDiffRequest,
99    ) -> Result<ApplyDiffArtifacts, CodexError> {
100        let task_id = request.task_id.trim();
101        if task_id.is_empty() {
102            return Err(CodexError::EmptyTaskId);
103        }
104
105        let mut args = vec![OsString::from("cloud"), OsString::from("diff")];
106        if let Some(attempt) = request.attempt {
107            args.push(OsString::from("--attempt"));
108            args.push(OsString::from(attempt.to_string()));
109        }
110        args.push(OsString::from(task_id));
111        self.run_simple_command_with_overrides(args, request.overrides)
112            .await
113    }
114
115    /// Applies the diff for a Codex Cloud task locally via `codex cloud apply [--attempt N] <TASK_ID>`.
116    pub async fn cloud_apply(
117        &self,
118        request: CloudApplyRequest,
119    ) -> Result<ApplyDiffArtifacts, CodexError> {
120        let task_id = request.task_id.trim();
121        if task_id.is_empty() {
122            return Err(CodexError::EmptyTaskId);
123        }
124
125        let mut args = vec![OsString::from("cloud"), OsString::from("apply")];
126        if let Some(attempt) = request.attempt {
127            args.push(OsString::from("--attempt"));
128            args.push(OsString::from(attempt.to_string()));
129        }
130        args.push(OsString::from(task_id));
131        self.run_simple_command_with_overrides(args, request.overrides)
132            .await
133    }
134
135    /// Submits a new Codex Cloud task via `codex cloud exec`.
136    pub async fn cloud_exec(
137        &self,
138        request: CloudExecRequest,
139    ) -> Result<ApplyDiffArtifacts, CodexError> {
140        let env_id = request.env_id.trim();
141        if env_id.is_empty() {
142            return Err(CodexError::EmptyEnvId);
143        }
144
145        let mut args = vec![OsString::from("cloud"), OsString::from("exec")];
146        args.push(OsString::from("--env"));
147        args.push(OsString::from(env_id));
148        if let Some(attempts) = request.attempts {
149            args.push(OsString::from("--attempts"));
150            args.push(OsString::from(attempts.to_string()));
151        }
152        if let Some(branch) = request.branch {
153            args.push(OsString::from("--branch"));
154            args.push(OsString::from(branch));
155        }
156        if let Some(query) = request.query {
157            args.push(OsString::from(query));
158        }
159
160        self.run_simple_command_with_overrides(args, request.overrides)
161            .await
162    }
163}