diff --git a/codex-rs/app-server/src/request_processors/turn_processor.rs b/codex-rs/app-server/src/request_processors/turn_processor.rs index da51172754..c27a3f38b3 100644 --- a/codex-rs/app-server/src/request_processors/turn_processor.rs +++ b/codex-rs/app-server/src/request_processors/turn_processor.rs @@ -441,11 +441,12 @@ impl TurnRequestProcessor { return Ok(None); } - let cwd = request.cwd; - let effective_cwd = cwd + let requested_cwd = request.cwd; + let effective_cwd = requested_cwd .as_ref() .map(|cwd| AbsolutePathBuf::resolve_path_against_base(cwd, base_snapshot.cwd.as_path())) .unwrap_or_else(|| base_snapshot.cwd.clone()); + let cwd = requested_cwd.map(|_| effective_cwd.to_path_buf()); let runtime_workspace_roots = request.runtime_workspace_roots.map(|workspace_roots| { resolve_runtime_workspace_roots(workspace_roots, &effective_cwd) }); diff --git a/codex-rs/app-server/tests/suite/v2/thread_settings.rs b/codex-rs/app-server/tests/suite/v2/thread_settings.rs index 0a9bb6f913..961524933a 100644 --- a/codex-rs/app-server/tests/suite/v2/thread_settings.rs +++ b/codex-rs/app-server/tests/suite/v2/thread_settings.rs @@ -191,22 +191,23 @@ async fn thread_settings_update_applies_partial_patch_and_emits_full_state() -> } #[tokio::test] -async fn thread_settings_update_retargets_permissions_when_cwd_changes() -> Result<()> { +async fn thread_settings_update_absolutizes_relative_cwd_before_permissions() -> Result<()> { let server = create_mock_responses_server_repeating_assistant("Done").await; let codex_home = TempDir::new()?; write_config(&codex_home, &server.uri())?; - let next_cwd = TempDir::new()?; - let next_cwd_abs = AbsolutePathBuf::try_from(next_cwd.path())?; let mut mcp = McpProcess::new(codex_home.path()).await?; timeout(DEFAULT_READ_TIMEOUT, mcp.initialize()).await??; let ThreadStartResponse { thread, .. } = start_thread(&mut mcp).await?; + let next_cwd = std::path::PathBuf::from("next-cwd"); + let next_cwd_abs = thread.cwd.join(&next_cwd); + std::fs::create_dir_all(next_cwd_abs.as_path())?; let response = send_thread_settings_update( &mut mcp, ThreadSettingsUpdateParams { thread_id: thread.id, - cwd: Some(next_cwd.path().to_path_buf()), + cwd: Some(next_cwd), permissions: Some(PermissionProfileSelectionParams::new(":workspace")), ..Default::default() },