diff --git a/codex-rs/app-server/Cargo.toml b/codex-rs/app-server/Cargo.toml index b2126f1947..7d6b340755 100644 --- a/codex-rs/app-server/Cargo.toml +++ b/codex-rs/app-server/Cargo.toml @@ -8,6 +8,10 @@ license.workspace = true name = "codex-app-server" path = "src/main.rs" +[[bin]] +name = "codex-app-server-test-notify-capture" +path = "src/bin/notify_capture.rs" + [lib] name = "codex_app_server" path = "src/lib.rs" @@ -18,14 +22,12 @@ workspace = true [dependencies] anyhow = { workspace = true } async-trait = { workspace = true } -base64 = { workspace = true } codex-arg0 = { workspace = true } codex-cloud-requirements = { workspace = true } codex-core = { workspace = true } codex-otel = { workspace = true } codex-shell-command = { workspace = true } codex-utils-cli = { workspace = true } -codex-utils-pty = { workspace = true } codex-backend-client = { workspace = true } codex-file-search = { workspace = true } codex-chatgpt = { workspace = true } @@ -66,6 +68,7 @@ axum = { workspace = true, default-features = false, features = [ "json", "tokio", ] } +base64 = { workspace = true } core_test_support = { workspace = true } codex-utils-cargo-bin = { workspace = true } pretty_assertions = { workspace = true } diff --git a/codex-rs/app-server/src/bin/notify_capture.rs b/codex-rs/app-server/src/bin/notify_capture.rs new file mode 100644 index 0000000000..7217e26310 --- /dev/null +++ b/codex-rs/app-server/src/bin/notify_capture.rs @@ -0,0 +1,44 @@ +use std::env; +use std::fs; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +use anyhow::Context; +use anyhow::Result; +use anyhow::anyhow; +use anyhow::bail; + +fn main() -> Result<()> { + let mut args = env::args_os(); + let _program = args.next(); + let output_path = PathBuf::from( + args.next() + .ok_or_else(|| anyhow!("expected output path as first argument"))?, + ); + let payload = args + .next() + .ok_or_else(|| anyhow!("expected payload as final argument"))?; + + if args.next().is_some() { + bail!("expected payload as final argument"); + } + + let payload = payload.to_string_lossy(); + let temp_path = PathBuf::from(format!("{}.tmp", output_path.display())); + let mut file = File::create(&temp_path) + .with_context(|| format!("failed to create {}", temp_path.display()))?; + file.write_all(payload.as_bytes()) + .with_context(|| format!("failed to write {}", temp_path.display()))?; + file.sync_all() + .with_context(|| format!("failed to sync {}", temp_path.display()))?; + fs::rename(&temp_path, &output_path).with_context(|| { + format!( + "failed to move {} into {}", + temp_path.display(), + output_path.display() + ) + })?; + + Ok(()) +} diff --git a/codex-rs/app-server/tests/suite/v2/initialize.rs b/codex-rs/app-server/tests/suite/v2/initialize.rs index de437c5bf5..8887e87f52 100644 --- a/codex-rs/app-server/tests/suite/v2/initialize.rs +++ b/codex-rs/app-server/tests/suite/v2/initialize.rs @@ -14,6 +14,7 @@ use codex_app_server_protocol::ThreadStartResponse; use codex_app_server_protocol::TurnStartParams; use codex_app_server_protocol::TurnStartResponse; use codex_app_server_protocol::UserInput as V2UserInput; +use codex_utils_cargo_bin::cargo_bin; use core_test_support::fs_wait; use pretty_assertions::assert_eq; use serde_json::Value; @@ -191,29 +192,22 @@ async fn turn_start_notify_payload_includes_initialize_client_name() -> Result<( let responses = vec![create_final_assistant_message_sse_response("Done")?]; let server = create_mock_responses_server_sequence_unchecked(responses).await; let codex_home = TempDir::new()?; - let notify_script = codex_home.path().join("notify.py"); - std::fs::write( - ¬ify_script, - r#"from pathlib import Path -import sys - -payload_path = Path(__file__).with_name("notify.json") -tmp_path = payload_path.with_suffix(".json.tmp") -tmp_path.write_text(sys.argv[-1], encoding="utf-8") -tmp_path.replace(payload_path) -"#, - )?; let notify_file = codex_home.path().join("notify.json"); - let notify_script = notify_script + let notify_capture = cargo_bin("codex-app-server-test-notify-capture")?; + let notify_capture = notify_capture .to_str() - .expect("notify script path should be valid UTF-8"); + .expect("notify capture path should be valid UTF-8"); + let notify_file_str = notify_file + .to_str() + .expect("notify file path should be valid UTF-8"); create_config_toml_with_extra( codex_home.path(), &server.uri(), "never", &format!( - "notify = [\"python3\", {}]", - toml_basic_string(notify_script) + "notify = [{}, {}]", + toml_basic_string(notify_capture), + toml_basic_string(notify_file_str) ), )?; @@ -297,6 +291,9 @@ model_provider = "mock_provider" {extra} +[features] +shell_snapshot = false + [model_providers.mock_provider] name = "Mock provider for test" base_url = "{server_uri}/v1"