Skip to main content

codex_chatgpt/
apply_command.rs

1use std::path::PathBuf;
2
3use clap::Parser;
4use codex_core::config::Config;
5use codex_git_utils::ApplyGitRequest;
6use codex_git_utils::apply_git_patch;
7use codex_utils_cli::CliConfigOverrides;
8
9use crate::get_task::GetTaskResponse;
10use crate::get_task::OutputItem;
11use crate::get_task::PrOutputItem;
12use crate::get_task::get_task;
13
14/// Applies the latest diff from a Codex agent task.
15#[derive(Debug, Parser)]
16pub struct ApplyCommand {
17    pub task_id: String,
18
19    #[clap(flatten)]
20    pub config_overrides: CliConfigOverrides,
21}
22pub async fn run_apply_command(
23    apply_cli: ApplyCommand,
24    cwd: Option<PathBuf>,
25) -> anyhow::Result<()> {
26    let config = Config::load_with_cli_overrides(
27        apply_cli
28            .config_overrides
29            .parse_overrides()
30            .map_err(anyhow::Error::msg)?,
31    )
32    .await?;
33
34    let task_response = get_task(&config, apply_cli.task_id).await?;
35    apply_diff_from_task(task_response, cwd).await
36}
37
38pub async fn apply_diff_from_task(
39    task_response: GetTaskResponse,
40    cwd: Option<PathBuf>,
41) -> anyhow::Result<()> {
42    let diff_turn = match task_response.current_diff_task_turn {
43        Some(turn) => turn,
44        None => anyhow::bail!("No diff turn found"),
45    };
46    let output_diff = diff_turn.output_items.iter().find_map(|item| match item {
47        OutputItem::Pr(PrOutputItem { output_diff }) => Some(output_diff),
48        _ => None,
49    });
50    match output_diff {
51        Some(output_diff) => apply_diff(&output_diff.diff, cwd).await,
52        None => anyhow::bail!("No PR output item found"),
53    }
54}
55
56async fn apply_diff(diff: &str, cwd: Option<PathBuf>) -> anyhow::Result<()> {
57    let cwd = cwd.unwrap_or(std::env::current_dir().unwrap_or_else(|_| std::env::temp_dir()));
58    let req = ApplyGitRequest {
59        cwd,
60        diff: diff.to_string(),
61        revert: false,
62        preflight: false,
63    };
64    let res = apply_git_patch(&req)?;
65    if res.exit_code != 0 {
66        anyhow::bail!(
67            "Git apply failed (applied={}, skipped={}, conflicts={})\nstdout:\n{}\nstderr:\n{}",
68            res.applied_paths.len(),
69            res.skipped_paths.len(),
70            res.conflicted_paths.len(),
71            res.stdout,
72            res.stderr
73        );
74    }
75    println!("Successfully applied diff");
76    Ok(())
77}