Carry shell invocation metadata and report executor PATH directories (#49360)

## What changed

- Carry the selected shell and login mode through unified exec using `ShellInvocation`. Use this metadata for shell snapshots and credential brokerage instead of inferring it from command arguments.
- Add `prependPathDirs` to exec-server environment metadata, populated from the executor's package PATH directory. Default to an empty list for older servers and omit empty lists from serialized output.

## Testing

Extend environment metadata round-trip coverage for `prependPathDirs` and the remote exec-server integration test to verify the packaged `codex-path` directory is reported.

GitOrigin-RevId: c571c068effcb305d196a701ad9a335ec7a3f5a2
This commit is contained in:
Adam Perry @ OpenAI
2026-09-29 20:40:21 +00:00
committed by copyberry
parent 1983c48fd1
commit 995138d71a
13 changed files with 107 additions and 56 deletions
@@ -6,6 +6,7 @@ use codex_file_system::FileSystemSandboxContext;
pub use codex_file_system::WalkOptions;
pub use codex_file_system::WalkOutcome;
use codex_file_system::WireFileSystemSandboxContext;
use codex_install_context::InstallContext;
use codex_network_proxy::ManagedNetworkSandboxContext;
use codex_network_proxy::RemoteNetworkProxyLaunchConfig;
use codex_protocol::ThreadId;
@@ -116,6 +117,9 @@ pub struct EnvironmentInfo {
/// Operating system reported by the executor; absent for legacy exec-servers.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub platform_os: Option<String>,
/// Executor directories to prepend to `PATH` when missing, in priority order.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub prepend_path_dirs: Vec<PathUri>,
/// Executor-local default directories for resolving `:tmpdir`, when reported.
/// On Windows, a command's `TEMP` or `TMP` overrides take precedence.
#[serde(default, skip_serializing_if = "Option::is_none")]
@@ -252,6 +256,13 @@ impl EnvironmentInfo {
cwd: cwd.and_then(|cwd| PathUri::from_host_native_path(cwd).ok()),
user_home_dir: PathUri::from_host_native_path("~").ok(),
platform_os: Some(std::env::consts::OS.to_string()),
prepend_path_dirs: InstallContext::current()
.package_layout
.as_ref()
.and_then(|layout| layout.path_dir.as_ref())
.into_iter()
.map(PathUri::from_abs_path)
.collect(),
temporary_directories: Some(temporary_directories),
temp_dir,
capabilities: EnvironmentCapabilities {
@@ -1372,6 +1383,7 @@ mod tests {
cwd: None,
user_home_dir: None,
platform_os: None,
prepend_path_dirs: Vec::new(),
temporary_directories: None,
temp_dir: None,
capabilities: EnvironmentCapabilities::default(),
@@ -1447,6 +1459,7 @@ mod tests {
"cwd": null,
"userHomeDir": "file:///C:/Users/remote",
"platformOs": "windows",
"prependPathDirs": ["file:///C:/tools/bin", "file:///D:/tools/bin"],
"temporaryDirectories": ["file:///C:/Temp", "file:///D:/Temp"],
"capabilities": {
"networkProxyLaunch": false,