diff --git a/codex-rs/app-server-protocol/schema/json/ClientRequest.json b/codex-rs/app-server-protocol/schema/json/ClientRequest.json index e57ffa12c..62495a79a 100644 --- a/codex-rs/app-server-protocol/schema/json/ClientRequest.json +++ b/codex-rs/app-server-protocol/schema/json/ClientRequest.json @@ -2864,6 +2864,12 @@ }, "WindowsSandboxSetupStartParams": { "properties": { + "cwd": { + "type": [ + "string", + "null" + ] + }, "mode": { "$ref": "#/definitions/WindowsSandboxSetupMode" } @@ -3908,4 +3914,4 @@ } ], "title": "ClientRequest" -} \ No newline at end of file +} diff --git a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json index 2ccd20466..f09f2fc55 100644 --- a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json +++ b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json @@ -15325,6 +15325,12 @@ "WindowsSandboxSetupStartParams": { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { + "cwd": { + "type": [ + "string", + "null" + ] + }, "mode": { "$ref": "#/definitions/v2/WindowsSandboxSetupMode" } @@ -15385,4 +15391,4 @@ }, "title": "CodexAppServerProtocol", "type": "object" -} \ No newline at end of file +} diff --git a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json index 1bbea24c8..7f37aaecb 100644 --- a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json +++ b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json @@ -14226,6 +14226,12 @@ "WindowsSandboxSetupStartParams": { "$schema": "http://json-schema.org/draft-07/schema#", "properties": { + "cwd": { + "type": [ + "string", + "null" + ] + }, "mode": { "$ref": "#/definitions/WindowsSandboxSetupMode" } @@ -14285,4 +14291,4 @@ }, "title": "CodexAppServerProtocolV2", "type": "object" -} \ No newline at end of file +} diff --git a/codex-rs/app-server-protocol/schema/json/v2/WindowsSandboxSetupStartParams.json b/codex-rs/app-server-protocol/schema/json/v2/WindowsSandboxSetupStartParams.json index 6f0663d20..663d36064 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/WindowsSandboxSetupStartParams.json +++ b/codex-rs/app-server-protocol/schema/json/v2/WindowsSandboxSetupStartParams.json @@ -10,6 +10,12 @@ } }, "properties": { + "cwd": { + "type": [ + "string", + "null" + ] + }, "mode": { "$ref": "#/definitions/WindowsSandboxSetupMode" } @@ -19,4 +25,4 @@ ], "title": "WindowsSandboxSetupStartParams", "type": "object" -} \ No newline at end of file +} diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/WindowsSandboxSetupStartParams.ts b/codex-rs/app-server-protocol/schema/typescript/v2/WindowsSandboxSetupStartParams.ts index 21daf6462..cb342c24c 100644 --- a/codex-rs/app-server-protocol/schema/typescript/v2/WindowsSandboxSetupStartParams.ts +++ b/codex-rs/app-server-protocol/schema/typescript/v2/WindowsSandboxSetupStartParams.ts @@ -3,4 +3,4 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. import type { WindowsSandboxSetupMode } from "./WindowsSandboxSetupMode"; -export type WindowsSandboxSetupStartParams = { mode: WindowsSandboxSetupMode, }; +export type WindowsSandboxSetupStartParams = { mode: WindowsSandboxSetupMode, cwd?: string | null, }; diff --git a/codex-rs/app-server-protocol/src/protocol/v2.rs b/codex-rs/app-server-protocol/src/protocol/v2.rs index 2147295c9..185d74fad 100644 --- a/codex-rs/app-server-protocol/src/protocol/v2.rs +++ b/codex-rs/app-server-protocol/src/protocol/v2.rs @@ -3927,6 +3927,8 @@ pub enum WindowsSandboxSetupMode { #[ts(export_to = "v2/")] pub struct WindowsSandboxSetupStartParams { pub mode: WindowsSandboxSetupMode, + #[ts(optional = nullable)] + pub cwd: Option, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)] diff --git a/codex-rs/app-server/README.md b/codex-rs/app-server/README.md index 068d4ee18..fa1627219 100644 --- a/codex-rs/app-server/README.md +++ b/codex-rs/app-server/README.md @@ -157,7 +157,7 @@ Example with notification opt-out: - `tool/requestUserInput` — prompt the user with 1–3 short questions for a tool call and return their answers (experimental). - `config/mcpServer/reload` — reload MCP server config from disk and queue a refresh for loaded threads (applied on each thread's next active turn); returns `{}`. Use this after editing `config.toml` without restarting the server. - `mcpServerStatus/list` — enumerate configured MCP servers with their tools, resources, resource templates, and auth status; supports cursor+limit pagination. -- `windowsSandbox/setupStart` — start Windows sandbox setup for the selected mode (`elevated` or `unelevated`); returns `{ started: true }` immediately and later emits `windowsSandbox/setupCompleted`. +- `windowsSandbox/setupStart` — start Windows sandbox setup for the selected mode (`elevated` or `unelevated`); accepts an optional `cwd` to target setup for a specific workspace, returns `{ started: true }` immediately, and later emits `windowsSandbox/setupCompleted`. - `feedback/upload` — submit a feedback report (classification + optional reason/logs, conversation_id, and optional `extraLogFiles` attachments array); returns the tracking thread id. - `command/exec` — run a single command under the server sandbox without starting a thread/turn (handy for utilities and validation). - `config/read` — fetch the effective config on disk after resolving config layering. diff --git a/codex-rs/app-server/src/codex_message_processor.rs b/codex-rs/app-server/src/codex_message_processor.rs index 80558642c..8d9f08ce6 100644 --- a/codex-rs/app-server/src/codex_message_processor.rs +++ b/codex-rs/app-server/src/codex_message_processor.rs @@ -6119,21 +6119,39 @@ impl CodexMessageProcessor { WindowsSandboxSetupMode::Unelevated => CoreWindowsSandboxSetupMode::Unelevated, }; let config = Arc::clone(&self.config); + let cli_overrides = self.cli_overrides.clone(); + let cloud_requirements = self.current_cloud_requirements(); + let command_cwd = params.cwd.unwrap_or_else(|| config.cwd.clone()); let outgoing = Arc::clone(&self.outgoing); let connection_id = request_id.connection_id; tokio::spawn(async move { - let setup_request = WindowsSandboxSetupRequest { - mode, - policy: config.permissions.sandbox_policy.get().clone(), - policy_cwd: config.cwd.clone(), - command_cwd: config.cwd.clone(), - env_map: std::env::vars().collect(), - codex_home: config.codex_home.clone(), - active_profile: config.active_profile.clone(), + let derived_config = derive_config_for_cwd( + &cli_overrides, + None, + ConfigOverrides { + cwd: Some(command_cwd.clone()), + ..Default::default() + }, + Some(command_cwd.clone()), + &cloud_requirements, + ) + .await; + let setup_result = match derived_config { + Ok(config) => { + let setup_request = WindowsSandboxSetupRequest { + mode, + policy: config.permissions.sandbox_policy.get().clone(), + policy_cwd: config.cwd.clone(), + command_cwd, + env_map: std::env::vars().collect(), + codex_home: config.codex_home.clone(), + active_profile: config.active_profile.clone(), + }; + codex_core::windows_sandbox::run_windows_sandbox_setup(setup_request).await + } + Err(err) => Err(err.into()), }; - let setup_result = - codex_core::windows_sandbox::run_windows_sandbox_setup(setup_request).await; let notification = WindowsSandboxSetupCompletedNotification { mode: match mode { CoreWindowsSandboxSetupMode::Elevated => WindowsSandboxSetupMode::Elevated, diff --git a/codex-rs/app-server/tests/suite/v2/windows_sandbox_setup.rs b/codex-rs/app-server/tests/suite/v2/windows_sandbox_setup.rs index 1f069b3ca..4512d9058 100644 --- a/codex-rs/app-server/tests/suite/v2/windows_sandbox_setup.rs +++ b/codex-rs/app-server/tests/suite/v2/windows_sandbox_setup.rs @@ -37,6 +37,7 @@ async fn windows_sandbox_setup_start_emits_completion_notification() -> Result<( let request_id = mcp .send_windows_sandbox_setup_start_request(WindowsSandboxSetupStartParams { mode: WindowsSandboxSetupMode::Unelevated, + cwd: None, }) .await?; let response: JSONRPCResponse = timeout(