diff --git a/codex-rs/cli/src/main.rs b/codex-rs/cli/src/main.rs index f4b62f81ae..25050e39e7 100644 --- a/codex-rs/cli/src/main.rs +++ b/codex-rs/cli/src/main.rs @@ -79,7 +79,8 @@ enum Subcommand { GenerateTs(GenerateTsCommand), /// Browse and apply tasks from the cloud. - CloudTasks(CloudTasksCli), + #[clap(name = "cloud", alias = "cloud-tasks")] + Cloud(CloudTasksCli), } #[derive(Debug, Parser)] @@ -191,7 +192,7 @@ async fn cli_main(codex_linux_sandbox_exe: Option) -> anyhow::Result<() Some(Subcommand::Completion(completion_cli)) => { print_completion(completion_cli); } - Some(Subcommand::CloudTasks(mut cloud_cli)) => { + Some(Subcommand::Cloud(mut cloud_cli)) => { prepend_config_flags(&mut cloud_cli.config_overrides, cli.config_overrides); codex_cloud_tasks::run_main(cloud_cli, codex_linux_sandbox_exe).await?; } diff --git a/codex-rs/cloud-tasks/src/bin/envcheck.rs b/codex-rs/cloud-tasks/src/bin/envcheck.rs index 5cec6d7b6d..911267204d 100644 --- a/codex-rs/cloud-tasks/src/bin/envcheck.rs +++ b/codex-rs/cloud-tasks/src/bin/envcheck.rs @@ -36,7 +36,7 @@ async fn main() -> anyhow::Result<()> { || base_url.starts_with("https://chat.openai.com")) && !base_url.contains("/backend-api") { - base_url = format!("{base_url}/backend-api"); + base_url = format!("{base_url}/backend-api"); } println!("base_url: {base_url}"); println!( diff --git a/codex-rs/cloud-tasks/src/bin/newtask.rs b/codex-rs/cloud-tasks/src/bin/newtask.rs index d36bc46521..be6a0c5667 100644 --- a/codex-rs/cloud-tasks/src/bin/newtask.rs +++ b/codex-rs/cloud-tasks/src/bin/newtask.rs @@ -47,7 +47,7 @@ async fn main() -> anyhow::Result<()> { || base_url.starts_with("https://chat.openai.com")) && !base_url.contains("/backend-api") { - base_url = format!("{base_url}/backend-api"); + base_url = format!("{base_url}/backend-api"); } println!("base_url: {base_url}"); let is_wham = base_url.contains("/backend-api"); diff --git a/codex-rs/cloud-tasks/src/env_detect.rs b/codex-rs/cloud-tasks/src/env_detect.rs index b575a7da2b..33da9269dd 100644 --- a/codex-rs/cloud-tasks/src/env_detect.rs +++ b/codex-rs/cloud-tasks/src/env_detect.rs @@ -95,9 +95,7 @@ pub async fn autodetect_environment_id( anyhow::bail!("GET {list_url} failed: {status}; content-type={ct}; body={body}"); } let all_envs: Vec = serde_json::from_str(&body).map_err(|e| { - anyhow::anyhow!( - "Decode error for {list_url}: {e}; content-type={ct}; body={body}" - ) + anyhow::anyhow!("Decode error for {list_url}: {e}; content-type={ct}; body={body}") })?; if let Some(env) = pick_environment_row(&all_envs, desired_label.as_deref()) { return Ok(AutodetectSelection { @@ -230,9 +228,7 @@ fn parse_owner_repo(url: &str) -> Option<(String, String)> { let mut parts = rest.splitn(2, '/'); let owner = parts.next()?.to_string(); let repo = parts.next()?.to_string(); - crate::append_error_log(format!( - "env: parsed SSH GitHub origin => {owner}/{repo}" - )); + crate::append_error_log(format!("env: parsed SSH GitHub origin => {owner}/{repo}")); return Some((owner, repo)); } // HTTPS or git protocol @@ -247,9 +243,7 @@ fn parse_owner_repo(url: &str) -> Option<(String, String)> { let mut parts = rest.splitn(2, '/'); let owner = parts.next()?.to_string(); let repo = parts.next()?.to_string(); - crate::append_error_log(format!( - "env: parsed HTTP GitHub origin => {owner}/{repo}" - )); + crate::append_error_log(format!("env: parsed HTTP GitHub origin => {owner}/{repo}")); return Some((owner, repo)); } } diff --git a/codex-rs/cloud-tasks/src/lib.rs b/codex-rs/cloud-tasks/src/lib.rs index cf768cd652..e21f900128 100644 --- a/codex-rs/cloud-tasks/src/lib.rs +++ b/codex-rs/cloud-tasks/src/lib.rs @@ -31,7 +31,7 @@ pub(crate) fn append_error_log(message: impl AsRef) { // (no standalone patch summarizer needed – UI displays raw diffs) -/// Entry point for the `codex cloud-tasks` subcommand. +/// Entry point for the `codex cloud` subcommand. pub async fn run_main(_cli: Cli, _codex_linux_sandbox_exe: Option) -> anyhow::Result<()> { // Very minimal logging setup; mirrors other crates' pattern. let default_level = "error"; @@ -107,7 +107,7 @@ pub async fn run_main(_cli: Cli, _codex_linux_sandbox_exe: Option) -> a } _ => { eprintln!( - "Not signed in. Please run 'codex login' to sign in with ChatGPT, then re-run 'codex cloud-tasks'." + "Not signed in. Please run 'codex login' to sign in with ChatGPT, then re-run 'codex cloud'." ); std::process::exit(1); } @@ -115,7 +115,7 @@ pub async fn run_main(_cli: Cli, _codex_linux_sandbox_exe: Option) -> a } None => { eprintln!( - "Not signed in. Please run 'codex login' to sign in with ChatGPT, then re-run 'codex cloud-tasks'." + "Not signed in. Please run 'codex login' to sign in with ChatGPT, then re-run 'codex cloud'." ); std::process::exit(1); } @@ -351,8 +351,8 @@ pub async fn run_main(_cli: Cli, _codex_linux_sandbox_exe: Option) -> a // Render helper to centralize immediate redraws after handling events. let render_if_needed = |terminal: &mut Terminal>, - app: &mut app::App, - needs_redraw: &mut bool| + app: &mut app::App, + needs_redraw: &mut bool| -> anyhow::Result<()> { if *needs_redraw { terminal.draw(|f| ui::draw(f, app))?; @@ -1204,48 +1204,48 @@ fn pretty_lines_from_error(raw: &str) -> Vec { if let Some(body_idx) = raw.find(" body=") && let Some(json_start_rel) = raw[body_idx..].find('{') { - let json_start = body_idx + json_start_rel; - let json_str = raw[json_start..].trim(); - if let Ok(v) = serde_json::from_str::(json_str) { - // Prefer assistant turn context. - let turn = v - .get("current_assistant_turn") - .and_then(|x| x.as_object()) - .cloned() - .or_else(|| { - v.get("current_diff_task_turn") - .and_then(|x| x.as_object()) - .cloned() - }); - if let Some(t) = turn { - if let Some(err) = t.get("error").and_then(|e| e.as_object()) { - let code = err.get("code").and_then(|s| s.as_str()).unwrap_or(""); - let msg = err.get("message").and_then(|s| s.as_str()).unwrap_or(""); - if !code.is_empty() || !msg.is_empty() { - let summary = if code.is_empty() { - msg.to_string() - } else if msg.is_empty() { - code.to_string() - } else { - format!("{code}: {msg}") - }; - lines.push(format!("Assistant error: {summary}")); - } - } - if let Some(status) = t.get("turn_status").and_then(|s| s.as_str()) { - lines.push(format!("Status: {status}")); - } - if let Some(text) = t - .get("latest_event") - .and_then(|e| e.get("text")) - .and_then(|s| s.as_str()) - && !text.trim().is_empty() - { - lines.push(format!("Latest event: {}", text.trim())); + let json_start = body_idx + json_start_rel; + let json_str = raw[json_start..].trim(); + if let Ok(v) = serde_json::from_str::(json_str) { + // Prefer assistant turn context. + let turn = v + .get("current_assistant_turn") + .and_then(|x| x.as_object()) + .cloned() + .or_else(|| { + v.get("current_diff_task_turn") + .and_then(|x| x.as_object()) + .cloned() + }); + if let Some(t) = turn { + if let Some(err) = t.get("error").and_then(|e| e.as_object()) { + let code = err.get("code").and_then(|s| s.as_str()).unwrap_or(""); + let msg = err.get("message").and_then(|s| s.as_str()).unwrap_or(""); + if !code.is_empty() || !msg.is_empty() { + let summary = if code.is_empty() { + msg.to_string() + } else if msg.is_empty() { + code.to_string() + } else { + format!("{code}: {msg}") + }; + lines.push(format!("Assistant error: {summary}")); } } + if let Some(status) = t.get("turn_status").and_then(|s| s.as_str()) { + lines.push(format!("Status: {status}")); + } + if let Some(text) = t + .get("latest_event") + .and_then(|e| e.get("text")) + .and_then(|s| s.as_str()) + && !text.trim().is_empty() + { + lines.push(format!("Latest event: {}", text.trim())); + } } } + } if lines.len() == 1 { // Parsing yielded nothing; include a trimmed, short raw message tail for context. diff --git a/codex-rs/cloud-tasks/src/ui.rs b/codex-rs/cloud-tasks/src/ui.rs index 665e948980..d19074e13d 100644 --- a/codex-rs/cloud-tasks/src/ui.rs +++ b/codex-rs/cloud-tasks/src/ui.rs @@ -95,7 +95,6 @@ fn overlay_content(area: Rect) -> Rect { } pub fn draw_new_task_page(frame: &mut Frame, area: Rect, app: &mut App) { - let title_spans = { let mut spans: Vec = vec!["New Task".magenta().bold()]; if let Some(id) = app @@ -172,7 +171,7 @@ fn draw_list(frame: &mut Frame, area: Rect, app: &mut App) { .find(|r| &r.id == id) .and_then(|r| r.label.clone()) .unwrap_or_else(|| "Selected".to_string()); - format!(" • {label}").dim() + format!(" • {label}").dim() } else { " • All".dim() }; @@ -181,7 +180,7 @@ fn draw_list(frame: &mut Frame, area: Rect, app: &mut App) { " • 0%".dim() } else { let p = ((app.selected as f32) / ((app.tasks.len() - 1) as f32) * 100.0).round() as i32; - format!(" • {}%", p.clamp(0, 100)).dim() + format!(" • {}%", p.clamp(0, 100)).dim() }; let title_line = { let base = Line::from(vec!["Cloud Tasks".into(), suffix_span, percent_span]); @@ -452,7 +451,7 @@ pub fn draw_apply_modal(frame: &mut Frame, area: Rect, app: &mut App) { body_lines.push(Line::from("")); body_lines.push( Line::from(format!("Skipped ({}):", m.skipped_paths.len())) - .magenta() + .magenta() .bold(), ); for p in &m.skipped_paths {