mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
Use AbsolutePathBuf for cwd state (#15710)
Migrate `cwd` and related session/config state to `AbsolutePathBuf` so downstream consumers consistently see absolute working directories. Add test-only `.abs()` helpers for `Path`, `PathBuf`, and `TempDir`, and update branch-local tests to use them instead of `AbsolutePathBuf::try_from(...)`. For the remaining TUI/app-server snapshot coverage that renders absolute cwd values, keep the snapshots unchanged and skip the Windows-only cases where the platform-specific absolute path layout differs.
This commit is contained in:
committed by
GitHub
Unverified
parent
178c3b15b4
commit
504aeb0e09
@@ -252,7 +252,7 @@ mod reload {
|
||||
|
||||
fn reload_overrides(config: &Config, preserve_current_provider: bool) -> ConfigOverrides {
|
||||
ConfigOverrides {
|
||||
cwd: Some(config.cwd.clone()),
|
||||
cwd: Some(config.cwd.to_path_buf()),
|
||||
model_provider: preserve_current_provider.then(|| config.model_provider_id.clone()),
|
||||
codex_linux_sandbox_exe: config.codex_linux_sandbox_exe.clone(),
|
||||
main_execve_wrapper_exe: config.main_execve_wrapper_exe.clone(),
|
||||
|
||||
+40
-37
@@ -33,6 +33,7 @@ use crate::models_manager::manager::ModelsManager;
|
||||
use crate::models_manager::manager::RefreshStrategy;
|
||||
use crate::parse_command::parse_command;
|
||||
use crate::parse_turn_item;
|
||||
use crate::path_utils::normalize_for_native_workdir;
|
||||
use crate::realtime_conversation::RealtimeConversationManager;
|
||||
use crate::realtime_conversation::handle_audio as handle_realtime_conversation_audio;
|
||||
use crate::realtime_conversation::handle_close as handle_realtime_conversation_close;
|
||||
@@ -835,10 +836,10 @@ pub(crate) struct TurnContext {
|
||||
pub(crate) reasoning_summary: ReasoningSummaryConfig,
|
||||
pub(crate) session_source: SessionSource,
|
||||
pub(crate) environment: Arc<Environment>,
|
||||
/// The session's current working directory. All relative paths provided by
|
||||
/// the model as well as sandbox policies are resolved against this path
|
||||
/// The session's absolute working directory. All relative paths provided
|
||||
/// by the model as well as sandbox policies are resolved against this path
|
||||
/// instead of `std::env::current_dir()`.
|
||||
pub(crate) cwd: PathBuf,
|
||||
pub(crate) cwd: AbsolutePathBuf,
|
||||
pub(crate) current_date: Option<String>,
|
||||
pub(crate) timezone: Option<String>,
|
||||
pub(crate) app_server_client_name: Option<String>,
|
||||
@@ -979,7 +980,7 @@ impl TurnContext {
|
||||
pub(crate) fn resolve_path(&self, path: Option<String>) -> PathBuf {
|
||||
path.as_ref()
|
||||
.map(PathBuf::from)
|
||||
.map_or_else(|| self.cwd.clone(), |p| self.cwd.join(p))
|
||||
.map_or_else(|| self.cwd.to_path_buf(), |p| self.cwd.as_path().join(p))
|
||||
}
|
||||
|
||||
pub(crate) fn compact_prompt(&self) -> &str {
|
||||
@@ -992,7 +993,7 @@ impl TurnContext {
|
||||
TurnContextItem {
|
||||
turn_id: Some(self.sub_id.clone()),
|
||||
trace_id: self.trace_id.clone(),
|
||||
cwd: self.cwd.clone(),
|
||||
cwd: self.cwd.to_path_buf(),
|
||||
current_date: self.current_date.clone(),
|
||||
timezone: self.timezone.clone(),
|
||||
approval_policy: self.approval_policy.value(),
|
||||
@@ -1068,14 +1069,11 @@ pub(crate) struct SessionConfiguration {
|
||||
network_sandbox_policy: NetworkSandboxPolicy,
|
||||
windows_sandbox_level: WindowsSandboxLevel,
|
||||
|
||||
/// Working directory that should be treated as the *root* of the
|
||||
/// Absolute working directory that should be treated as the *root* of the
|
||||
/// session. All relative paths supplied by the model as well as the
|
||||
/// execution sandbox are resolved against this directory **instead**
|
||||
/// of the process-wide current working directory. CLI front-ends are
|
||||
/// expected to expand this to an absolute path before sending the
|
||||
/// `ConfigureSession` operation so that the business-logic layer can
|
||||
/// operate deterministically.
|
||||
cwd: PathBuf,
|
||||
/// execution sandbox are resolved against this directory **instead** of
|
||||
/// the process-wide current working directory.
|
||||
cwd: AbsolutePathBuf,
|
||||
/// Directory containing all Codex state for this session.
|
||||
codex_home: PathBuf,
|
||||
/// Optional user-facing name for the thread, updated during the session.
|
||||
@@ -1107,7 +1105,7 @@ impl SessionConfiguration {
|
||||
approval_policy: self.approval_policy.value(),
|
||||
approvals_reviewer: self.approvals_reviewer,
|
||||
sandbox_policy: self.sandbox_policy.get().clone(),
|
||||
cwd: self.cwd.clone(),
|
||||
cwd: self.cwd.to_path_buf(),
|
||||
ephemeral: self.original_config_do_not_use.ephemeral,
|
||||
reasoning_effort: self.collaboration_mode.reasoning_effort(),
|
||||
personality: self.personality,
|
||||
@@ -1150,11 +1148,23 @@ impl SessionConfiguration {
|
||||
if let Some(windows_sandbox_level) = updates.windows_sandbox_level {
|
||||
next_configuration.windows_sandbox_level = windows_sandbox_level;
|
||||
}
|
||||
let mut cwd_changed = false;
|
||||
if let Some(cwd) = updates.cwd.clone() {
|
||||
next_configuration.cwd = cwd;
|
||||
cwd_changed = true;
|
||||
}
|
||||
|
||||
let absolute_cwd = updates
|
||||
.cwd
|
||||
.as_ref()
|
||||
.map(|cwd| {
|
||||
AbsolutePathBuf::relative_to_current_dir(normalize_for_native_workdir(
|
||||
cwd.as_path(),
|
||||
))
|
||||
.unwrap_or_else(|e| {
|
||||
warn!("failed to normalize update cwd: {cwd:?}: {e}");
|
||||
self.cwd.clone()
|
||||
})
|
||||
})
|
||||
.unwrap_or_else(|| self.cwd.clone());
|
||||
|
||||
let cwd_changed = absolute_cwd.as_path() != self.cwd.as_path();
|
||||
next_configuration.cwd = absolute_cwd;
|
||||
if sandbox_policy_changed || (cwd_changed && file_system_policy_matches_legacy) {
|
||||
// Preserve richer split policies across cwd-only updates; only
|
||||
// rederive when the session is already using the legacy bridge.
|
||||
@@ -1351,8 +1361,6 @@ impl Session {
|
||||
let auth_manager_for_context = auth_manager;
|
||||
let provider_for_context = provider;
|
||||
let session_telemetry_for_context = session_telemetry;
|
||||
let per_turn_config = Arc::new(per_turn_config);
|
||||
|
||||
let tools_config = ToolsConfig::new(&ToolsConfigParams {
|
||||
model_info: &model_info,
|
||||
available_models: &models_manager.try_list_models().unwrap_or_default(),
|
||||
@@ -1372,10 +1380,12 @@ impl Session {
|
||||
.with_agent_roles(per_turn_config.agent_roles.clone());
|
||||
|
||||
let cwd = session_configuration.cwd.clone();
|
||||
|
||||
let per_turn_config = Arc::new(per_turn_config);
|
||||
let turn_metadata_state = Arc::new(TurnMetadataState::new(
|
||||
conversation_id.to_string(),
|
||||
sub_id.clone(),
|
||||
cwd.clone(),
|
||||
cwd.to_path_buf(),
|
||||
session_configuration.sandbox_policy.get(),
|
||||
session_configuration.windows_sandbox_level,
|
||||
));
|
||||
@@ -1447,13 +1457,6 @@ impl Session {
|
||||
session_configuration.collaboration_mode.model(),
|
||||
session_configuration.provider
|
||||
);
|
||||
if !session_configuration.cwd.is_absolute() {
|
||||
return Err(anyhow::anyhow!(
|
||||
"cwd is not absolute: {:?}",
|
||||
session_configuration.cwd
|
||||
));
|
||||
}
|
||||
|
||||
let forked_from_id = initial_history.forked_from_id();
|
||||
|
||||
let (conversation_id, rollout_params) = match &initial_history {
|
||||
@@ -1723,7 +1726,7 @@ impl Session {
|
||||
ShellSnapshot::start_snapshotting(
|
||||
config.codex_home.clone(),
|
||||
conversation_id,
|
||||
session_configuration.cwd.clone(),
|
||||
session_configuration.cwd.to_path_buf(),
|
||||
&mut default_shell,
|
||||
session_telemetry.clone(),
|
||||
)
|
||||
@@ -1922,7 +1925,7 @@ impl Session {
|
||||
approval_policy: session_configuration.approval_policy.value(),
|
||||
approvals_reviewer: session_configuration.approvals_reviewer,
|
||||
sandbox_policy: session_configuration.sandbox_policy.get().clone(),
|
||||
cwd: session_configuration.cwd.clone(),
|
||||
cwd: session_configuration.cwd.to_path_buf(),
|
||||
reasoning_effort: session_configuration.collaboration_mode.reasoning_effort(),
|
||||
history_log_id,
|
||||
history_entry_count,
|
||||
@@ -1943,7 +1946,7 @@ impl Session {
|
||||
let sandbox_state = SandboxState {
|
||||
sandbox_policy: session_configuration.sandbox_policy.get().clone(),
|
||||
codex_linux_sandbox_exe: config.codex_linux_sandbox_exe.clone(),
|
||||
sandbox_cwd: session_configuration.cwd.clone(),
|
||||
sandbox_cwd: session_configuration.cwd.to_path_buf(),
|
||||
use_legacy_landlock: config.features.use_legacy_landlock(),
|
||||
};
|
||||
let mut required_mcp_servers: Vec<String> = mcp_servers
|
||||
@@ -2407,7 +2410,7 @@ impl Session {
|
||||
let sandbox_state = SandboxState {
|
||||
sandbox_policy: per_turn_config.permissions.sandbox_policy.get().clone(),
|
||||
codex_linux_sandbox_exe: per_turn_config.codex_linux_sandbox_exe.clone(),
|
||||
sandbox_cwd: per_turn_config.cwd.clone(),
|
||||
sandbox_cwd: per_turn_config.cwd.to_path_buf(),
|
||||
use_legacy_landlock: per_turn_config.features.use_legacy_landlock(),
|
||||
};
|
||||
if let Err(e) = self
|
||||
@@ -4138,7 +4141,7 @@ impl Session {
|
||||
let sandbox_state = SandboxState {
|
||||
sandbox_policy: turn_context.sandbox_policy.get().clone(),
|
||||
codex_linux_sandbox_exe: turn_context.codex_linux_sandbox_exe.clone(),
|
||||
sandbox_cwd: turn_context.cwd.clone(),
|
||||
sandbox_cwd: turn_context.cwd.to_path_buf(),
|
||||
use_legacy_landlock: turn_context.features.use_legacy_landlock(),
|
||||
};
|
||||
{
|
||||
@@ -4919,7 +4922,7 @@ mod handlers {
|
||||
) {
|
||||
let cwds = if cwds.is_empty() {
|
||||
let state = sess.state.lock().await;
|
||||
vec![state.session_configuration.cwd.clone()]
|
||||
vec![state.session_configuration.cwd.to_path_buf()]
|
||||
} else {
|
||||
cwds
|
||||
};
|
||||
@@ -5363,7 +5366,7 @@ async fn spawn_review_thread(
|
||||
let turn_metadata_state = Arc::new(TurnMetadataState::new(
|
||||
sess.conversation_id.to_string(),
|
||||
review_turn_id.clone(),
|
||||
parent_turn_context.cwd.clone(),
|
||||
parent_turn_context.cwd.to_path_buf(),
|
||||
parent_turn_context.sandbox_policy.get(),
|
||||
parent_turn_context.windows_sandbox_level,
|
||||
));
|
||||
@@ -5852,7 +5855,7 @@ pub(crate) async fn run_turn(
|
||||
let stop_request = codex_hooks::StopRequest {
|
||||
session_id: sess.conversation_id,
|
||||
turn_id: turn_context.sub_id.clone(),
|
||||
cwd: turn_context.cwd.clone(),
|
||||
cwd: turn_context.cwd.to_path_buf(),
|
||||
transcript_path: sess.hook_transcript_path().await,
|
||||
model: turn_context.model_info.slug.clone(),
|
||||
permission_mode: stop_hook_permission_mode,
|
||||
@@ -5902,7 +5905,7 @@ pub(crate) async fn run_turn(
|
||||
.hooks()
|
||||
.dispatch(HookPayload {
|
||||
session_id: sess.conversation_id,
|
||||
cwd: turn_context.cwd.clone(),
|
||||
cwd: turn_context.cwd.to_path_buf(),
|
||||
client: turn_context.app_server_client_name.clone(),
|
||||
triggered_at: chrono::Utc::now(),
|
||||
hook_event: HookEvent::AfterAgent {
|
||||
|
||||
@@ -62,7 +62,7 @@ async fn record_initial_history_resumed_bare_turn_context_does_not_hydrate_previ
|
||||
let previous_context_item = TurnContextItem {
|
||||
turn_id: Some(turn_context.sub_id.clone()),
|
||||
trace_id: turn_context.trace_id.clone(),
|
||||
cwd: turn_context.cwd.clone(),
|
||||
cwd: turn_context.cwd.to_path_buf(),
|
||||
current_date: turn_context.current_date.clone(),
|
||||
timezone: turn_context.timezone.clone(),
|
||||
approval_policy: turn_context.approval_policy.value(),
|
||||
@@ -101,7 +101,7 @@ async fn record_initial_history_resumed_hydrates_previous_turn_settings_from_lif
|
||||
let mut previous_context_item = TurnContextItem {
|
||||
turn_id: Some(turn_context.sub_id.clone()),
|
||||
trace_id: turn_context.trace_id.clone(),
|
||||
cwd: turn_context.cwd.clone(),
|
||||
cwd: turn_context.cwd.to_path_buf(),
|
||||
current_date: turn_context.current_date.clone(),
|
||||
timezone: turn_context.timezone.clone(),
|
||||
approval_policy: turn_context.approval_policy.value(),
|
||||
@@ -851,7 +851,7 @@ async fn record_initial_history_resumed_turn_context_after_compaction_reestablis
|
||||
let previous_context_item = TurnContextItem {
|
||||
turn_id: Some(turn_context.sub_id.clone()),
|
||||
trace_id: turn_context.trace_id.clone(),
|
||||
cwd: turn_context.cwd.clone(),
|
||||
cwd: turn_context.cwd.to_path_buf(),
|
||||
current_date: turn_context.current_date.clone(),
|
||||
timezone: turn_context.timezone.clone(),
|
||||
approval_policy: turn_context.approval_policy.value(),
|
||||
@@ -923,7 +923,7 @@ async fn record_initial_history_resumed_turn_context_after_compaction_reestablis
|
||||
serde_json::to_value(Some(TurnContextItem {
|
||||
turn_id: Some(turn_context.sub_id.clone()),
|
||||
trace_id: turn_context.trace_id.clone(),
|
||||
cwd: turn_context.cwd.clone(),
|
||||
cwd: turn_context.cwd.to_path_buf(),
|
||||
current_date: turn_context.current_date.clone(),
|
||||
timezone: turn_context.timezone.clone(),
|
||||
approval_policy: turn_context.approval_policy.value(),
|
||||
@@ -952,7 +952,7 @@ async fn record_initial_history_resumed_aborted_turn_without_id_clears_active_tu
|
||||
let previous_context_item = TurnContextItem {
|
||||
turn_id: Some(turn_context.sub_id.clone()),
|
||||
trace_id: turn_context.trace_id.clone(),
|
||||
cwd: turn_context.cwd.clone(),
|
||||
cwd: turn_context.cwd.to_path_buf(),
|
||||
current_date: turn_context.current_date.clone(),
|
||||
timezone: turn_context.timezone.clone(),
|
||||
approval_policy: turn_context.approval_policy.value(),
|
||||
@@ -1058,7 +1058,7 @@ async fn record_initial_history_resumed_unmatched_abort_preserves_active_turn_fo
|
||||
let current_context_item = TurnContextItem {
|
||||
turn_id: Some(current_turn_id.clone()),
|
||||
trace_id: turn_context.trace_id.clone(),
|
||||
cwd: turn_context.cwd.clone(),
|
||||
cwd: turn_context.cwd.to_path_buf(),
|
||||
current_date: turn_context.current_date.clone(),
|
||||
timezone: turn_context.timezone.clone(),
|
||||
approval_policy: turn_context.approval_policy.value(),
|
||||
@@ -1160,7 +1160,7 @@ async fn record_initial_history_resumed_trailing_incomplete_turn_compaction_clea
|
||||
let previous_context_item = TurnContextItem {
|
||||
turn_id: Some(turn_context.sub_id.clone()),
|
||||
trace_id: turn_context.trace_id.clone(),
|
||||
cwd: turn_context.cwd.clone(),
|
||||
cwd: turn_context.cwd.to_path_buf(),
|
||||
current_date: turn_context.current_date.clone(),
|
||||
timezone: turn_context.timezone.clone(),
|
||||
approval_policy: turn_context.approval_policy.value(),
|
||||
@@ -1304,7 +1304,7 @@ async fn record_initial_history_resumed_replaced_incomplete_compacted_turn_clear
|
||||
let previous_context_item = TurnContextItem {
|
||||
turn_id: Some(turn_context.sub_id.clone()),
|
||||
trace_id: turn_context.trace_id.clone(),
|
||||
cwd: turn_context.cwd.clone(),
|
||||
cwd: turn_context.cwd.to_path_buf(),
|
||||
current_date: turn_context.current_date.clone(),
|
||||
timezone: turn_context.timezone.clone(),
|
||||
approval_policy: turn_context.approval_policy.value(),
|
||||
|
||||
@@ -22,7 +22,6 @@ use codex_protocol::request_permissions::RequestPermissionsResponse;
|
||||
use codex_protocol::request_user_input::RequestUserInputArgs;
|
||||
use codex_protocol::request_user_input::RequestUserInputResponse;
|
||||
use codex_protocol::user_input::UserInput;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use serde_json::Value;
|
||||
use std::time::Duration;
|
||||
use tokio::sync::Mutex;
|
||||
@@ -518,7 +517,7 @@ async fn handle_patch_approval(
|
||||
let change_count = changes.len();
|
||||
let maybe_files = changes
|
||||
.keys()
|
||||
.map(|path| AbsolutePathBuf::from_absolute_path(parent_ctx.cwd.join(path)).ok())
|
||||
.map(|path| parent_ctx.cwd.join(path).ok())
|
||||
.collect::<Option<Vec<_>>>();
|
||||
if let Some(files) = maybe_files {
|
||||
let review_cancel = cancel_token.child_token();
|
||||
@@ -554,7 +553,7 @@ async fn handle_patch_approval(
|
||||
Arc::clone(parent_ctx),
|
||||
GuardianApprovalRequest::ApplyPatch {
|
||||
id: approval_id.clone(),
|
||||
cwd: parent_ctx.cwd.clone(),
|
||||
cwd: parent_ctx.cwd.to_path_buf(),
|
||||
files,
|
||||
change_count,
|
||||
patch,
|
||||
|
||||
@@ -80,6 +80,7 @@ use codex_protocol::protocol::ConversationAudioParams;
|
||||
use codex_protocol::protocol::RealtimeAudioFrame;
|
||||
use codex_protocol::protocol::Submission;
|
||||
use codex_protocol::protocol::W3cTraceContext;
|
||||
use core_test_support::PathBufExt;
|
||||
use core_test_support::context_snapshot;
|
||||
use core_test_support::context_snapshot::ContextSnapshotOptions;
|
||||
use core_test_support::context_snapshot::ContextSnapshotRenderMode;
|
||||
@@ -1266,7 +1267,7 @@ async fn record_initial_history_forked_hydrates_previous_turn_settings() {
|
||||
let previous_context_item = TurnContextItem {
|
||||
turn_id: Some(turn_context.sub_id.clone()),
|
||||
trace_id: turn_context.trace_id.clone(),
|
||||
cwd: turn_context.cwd.clone(),
|
||||
cwd: turn_context.cwd.to_path_buf(),
|
||||
current_date: turn_context.current_date.clone(),
|
||||
timezone: turn_context.timezone.clone(),
|
||||
approval_policy: turn_context.approval_policy.value(),
|
||||
@@ -2282,10 +2283,9 @@ async fn session_configuration_apply_preserves_split_file_system_policy_on_cwd_o
|
||||
let original_cwd = project_root.join("subdir");
|
||||
let docs_dir = original_cwd.join("docs");
|
||||
std::fs::create_dir_all(&docs_dir).expect("create docs dir");
|
||||
let docs_dir =
|
||||
codex_utils_absolute_path::AbsolutePathBuf::from_absolute_path(&docs_dir).expect("docs");
|
||||
let docs_dir = docs_dir.abs();
|
||||
|
||||
session_configuration.cwd = original_cwd;
|
||||
session_configuration.cwd = original_cwd.abs();
|
||||
session_configuration.sandbox_policy =
|
||||
codex_config::Constrained::allow_any(SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: Vec::new(),
|
||||
@@ -2407,10 +2407,9 @@ async fn session_configuration_apply_rederives_legacy_file_system_policy_on_cwd_
|
||||
let original_cwd = project_root.join("subdir");
|
||||
let docs_dir = original_cwd.join("docs");
|
||||
std::fs::create_dir_all(&docs_dir).expect("create docs dir");
|
||||
let docs_dir =
|
||||
codex_utils_absolute_path::AbsolutePathBuf::from_absolute_path(&docs_dir).expect("docs");
|
||||
let docs_dir = docs_dir.abs();
|
||||
|
||||
session_configuration.cwd = original_cwd;
|
||||
session_configuration.cwd = original_cwd.abs();
|
||||
session_configuration.sandbox_policy =
|
||||
codex_config::Constrained::allow_any(SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: Vec::new(),
|
||||
@@ -2444,6 +2443,36 @@ async fn session_configuration_apply_rederives_legacy_file_system_policy_on_cwd_
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn session_update_settings_keeps_runtime_cwds_absolute() {
|
||||
let (session, turn_context) = make_session_and_context().await;
|
||||
let updated_cwd = turn_context
|
||||
.cwd
|
||||
.join("project")
|
||||
.expect("resolve project dir");
|
||||
std::fs::create_dir_all(updated_cwd.as_path()).expect("create project dir");
|
||||
|
||||
session
|
||||
.update_settings(SessionSettingsUpdate {
|
||||
cwd: Some(PathBuf::from("project")),
|
||||
..Default::default()
|
||||
})
|
||||
.await
|
||||
.expect("cwd update should succeed");
|
||||
|
||||
let session_cwd = {
|
||||
let state = session.state.lock().await;
|
||||
state.session_configuration.cwd.clone()
|
||||
};
|
||||
let config = session.get_config().await;
|
||||
let next_turn = session.new_default_turn().await;
|
||||
|
||||
assert_eq!(session_cwd, updated_cwd);
|
||||
assert_eq!(config.cwd, turn_context.cwd);
|
||||
assert_eq!(next_turn.cwd, updated_cwd);
|
||||
assert_eq!(next_turn.config.cwd, updated_cwd);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn session_new_fails_when_zsh_fork_enabled_without_zsh_path() {
|
||||
let codex_home = tempfile::tempdir().expect("create temp dir");
|
||||
@@ -3058,7 +3087,7 @@ async fn user_turn_updates_approvals_reviewer() {
|
||||
text: "hello".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
cwd: config.cwd.clone(),
|
||||
cwd: config.cwd.to_path_buf(),
|
||||
approval_policy: config.permissions.approval_policy.value(),
|
||||
approvals_reviewer: Some(crate::config::types::ApprovalsReviewer::GuardianSubagent),
|
||||
sandbox_policy: config.permissions.sandbox_policy.get().clone(),
|
||||
@@ -5060,7 +5089,7 @@ async fn rejects_escalated_permissions_when_policy_not_on_request() {
|
||||
"echo hi".to_string(),
|
||||
]
|
||||
},
|
||||
cwd: turn_context.cwd.clone(),
|
||||
cwd: turn_context.cwd.to_path_buf(),
|
||||
expiration: timeout_ms.into(),
|
||||
capture_policy: ExecCapturePolicy::ShellTool,
|
||||
env: HashMap::new(),
|
||||
|
||||
@@ -23,7 +23,8 @@ use codex_protocol::models::ResponseItem;
|
||||
use codex_protocol::models::function_call_output_content_items_to_text;
|
||||
use codex_protocol::permissions::FileSystemSandboxPolicy;
|
||||
use codex_protocol::permissions::NetworkSandboxPolicy;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use core_test_support::PathExt;
|
||||
use core_test_support::TempDirExt;
|
||||
use core_test_support::codex_linux_sandbox_exe_or_skip;
|
||||
use core_test_support::responses::ev_assistant_message;
|
||||
use core_test_support::responses::ev_completed;
|
||||
@@ -123,7 +124,7 @@ async fn guardian_allows_shell_additional_permissions_requests_past_policy_valid
|
||||
"echo hi".to_string(),
|
||||
]
|
||||
},
|
||||
cwd: turn_context.cwd.clone(),
|
||||
cwd: turn_context.cwd.to_path_buf(),
|
||||
expiration: expiration_ms.into(),
|
||||
capture_policy: ExecCapturePolicy::ShellTool,
|
||||
env: HashMap::new(),
|
||||
@@ -388,12 +389,11 @@ async fn guardian_subagent_does_not_inherit_parent_exec_policy_rules() {
|
||||
.expect("write policy file");
|
||||
|
||||
let mut config = build_test_config(codex_home.path()).await;
|
||||
config.cwd = project_dir.path().to_path_buf();
|
||||
config.cwd = project_dir.abs();
|
||||
config.config_layer_stack = ConfigLayerStack::new(
|
||||
vec![ConfigLayerEntry::new(
|
||||
ConfigLayerSource::Project {
|
||||
dot_codex_folder: AbsolutePathBuf::from_absolute_path(project_dir.path())
|
||||
.expect("absolute project path"),
|
||||
dot_codex_folder: project_dir.path().abs(),
|
||||
},
|
||||
toml::Value::Table(Default::default()),
|
||||
)],
|
||||
|
||||
@@ -27,6 +27,9 @@ use serde::Deserialize;
|
||||
use tempfile::tempdir;
|
||||
|
||||
use super::*;
|
||||
use core_test_support::PathBufExt;
|
||||
use core_test_support::PathExt;
|
||||
use core_test_support::TempDirExt;
|
||||
use core_test_support::test_absolute_path;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
@@ -77,6 +80,23 @@ fn http_mcp(url: &str) -> McpServerConfig {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn load_config_normalizes_relative_cwd_override() -> std::io::Result<()> {
|
||||
let expected_cwd = AbsolutePathBuf::relative_to_current_dir("nested")?;
|
||||
let codex_home = tempdir()?;
|
||||
let config = Config::load_from_base_config_with_overrides(
|
||||
ConfigToml::default(),
|
||||
ConfigOverrides {
|
||||
cwd: Some(PathBuf::from("nested")),
|
||||
..Default::default()
|
||||
},
|
||||
codex_home.abs().into_path_buf(),
|
||||
)?;
|
||||
|
||||
assert_eq!(config.cwd, expected_cwd);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_toml_parsing() {
|
||||
let history_with_persistence = r#"
|
||||
@@ -460,7 +480,7 @@ fn default_permissions_profile_populates_runtime_sandbox_policy() -> std::io::Re
|
||||
codex_home.path().to_path_buf(),
|
||||
)?;
|
||||
|
||||
let memories_root = AbsolutePathBuf::try_from(codex_home.path().join("memories")).unwrap();
|
||||
let memories_root = codex_home.path().join("memories").abs();
|
||||
assert_eq!(
|
||||
config.permissions.file_system_sandbox_policy,
|
||||
FileSystemSandboxPolicy::restricted(vec![
|
||||
@@ -496,9 +516,7 @@ fn default_permissions_profile_populates_runtime_sandbox_policy() -> std::io::Re
|
||||
writable_roots: vec![memories_root],
|
||||
read_only_access: ReadOnlyAccess::Restricted {
|
||||
include_platform_defaults: true,
|
||||
readable_roots: vec![
|
||||
AbsolutePathBuf::try_from(cwd.path().join("docs")).expect("absolute docs path"),
|
||||
],
|
||||
readable_roots: vec![cwd.path().join("docs").abs(),],
|
||||
},
|
||||
network_access: false,
|
||||
exclude_tmpdir_env_var: true,
|
||||
@@ -1277,7 +1295,7 @@ fn add_dir_override_extends_workspace_writable_roots() -> std::io::Result<()> {
|
||||
temp_dir.path().to_path_buf(),
|
||||
)?;
|
||||
|
||||
let expected_backend = AbsolutePathBuf::try_from(backend).unwrap();
|
||||
let expected_backend = backend.abs();
|
||||
if cfg!(target_os = "windows") {
|
||||
match config.permissions.sandbox_policy.get() {
|
||||
SandboxPolicy::ReadOnly { .. } => {}
|
||||
@@ -1327,7 +1345,7 @@ fn workspace_write_always_includes_memories_root_once() -> std::io::Result<()> {
|
||||
let config = Config::load_from_base_config_with_overrides(
|
||||
ConfigToml {
|
||||
sandbox_workspace_write: Some(SandboxWorkspaceWrite {
|
||||
writable_roots: vec![AbsolutePathBuf::from_absolute_path(&memories_root)?],
|
||||
writable_roots: vec![memories_root.abs()],
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
@@ -1350,7 +1368,7 @@ fn workspace_write_always_includes_memories_root_once() -> std::io::Result<()> {
|
||||
"expected memories root directory to exist at {}",
|
||||
memories_root.display()
|
||||
);
|
||||
let expected_memories_root = AbsolutePathBuf::from_absolute_path(&memories_root)?;
|
||||
let expected_memories_root = memories_root.abs();
|
||||
match config.permissions.sandbox_policy.get() {
|
||||
SandboxPolicy::WorkspaceWrite { writable_roots, .. } => {
|
||||
assert_eq!(
|
||||
@@ -1768,7 +1786,7 @@ async fn managed_config_overrides_oauth_store_mode() -> anyhow::Result<()> {
|
||||
macos_managed_config_requirements_base64: None,
|
||||
};
|
||||
|
||||
let cwd = AbsolutePathBuf::try_from(codex_home.path())?;
|
||||
let cwd = codex_home.path().abs();
|
||||
let config_layer_stack = load_config_layers_state(
|
||||
codex_home.path(),
|
||||
Some(cwd),
|
||||
@@ -1897,7 +1915,7 @@ async fn managed_config_wins_over_cli_overrides() -> anyhow::Result<()> {
|
||||
macos_managed_config_requirements_base64: None,
|
||||
};
|
||||
|
||||
let cwd = AbsolutePathBuf::try_from(codex_home.path())?;
|
||||
let cwd = codex_home.path().abs();
|
||||
let config_layer_stack = load_config_layers_state(
|
||||
codex_home.path(),
|
||||
Some(cwd),
|
||||
@@ -2933,7 +2951,11 @@ struct PrecedenceTestFixture {
|
||||
}
|
||||
|
||||
impl PrecedenceTestFixture {
|
||||
fn cwd(&self) -> PathBuf {
|
||||
fn cwd(&self) -> AbsolutePathBuf {
|
||||
self.cwd.abs()
|
||||
}
|
||||
|
||||
fn cwd_path(&self) -> PathBuf {
|
||||
self.cwd.path().to_path_buf()
|
||||
}
|
||||
|
||||
@@ -2974,7 +2996,7 @@ fn loads_compact_prompt_from_file() -> std::io::Result<()> {
|
||||
std::fs::write(&prompt_path, " summarize differently ")?;
|
||||
|
||||
let cfg = ConfigToml {
|
||||
experimental_compact_prompt_file: Some(AbsolutePathBuf::from_absolute_path(prompt_path)?),
|
||||
experimental_compact_prompt_file: Some(prompt_path.abs()),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
@@ -3071,7 +3093,7 @@ fn load_config_rejects_missing_agent_role_config_file() -> std::io::Result<()> {
|
||||
"researcher".to_string(),
|
||||
AgentRoleToml {
|
||||
description: Some("Research role".to_string()),
|
||||
config_file: Some(AbsolutePathBuf::from_absolute_path(missing_path)?),
|
||||
config_file: Some(missing_path.abs()),
|
||||
nickname_candidates: None,
|
||||
},
|
||||
)]),
|
||||
@@ -4082,7 +4104,7 @@ fn model_catalog_json_loads_from_path() -> std::io::Result<()> {
|
||||
)?;
|
||||
|
||||
let cfg = ConfigToml {
|
||||
model_catalog_json: Some(AbsolutePathBuf::from_absolute_path(catalog_path)?),
|
||||
model_catalog_json: Some(catalog_path.abs()),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
@@ -4103,7 +4125,7 @@ fn model_catalog_json_rejects_empty_catalog() -> std::io::Result<()> {
|
||||
std::fs::write(&catalog_path, r#"{"models":[]}"#)?;
|
||||
|
||||
let cfg = ConfigToml {
|
||||
model_catalog_json: Some(AbsolutePathBuf::from_absolute_path(catalog_path)?),
|
||||
model_catalog_json: Some(catalog_path.abs()),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
@@ -4240,7 +4262,7 @@ fn test_precedence_fixture_with_o3_profile() -> std::io::Result<()> {
|
||||
|
||||
let o3_profile_overrides = ConfigOverrides {
|
||||
config_profile: Some("o3".to_string()),
|
||||
cwd: Some(fixture.cwd()),
|
||||
cwd: Some(fixture.cwd_path()),
|
||||
..Default::default()
|
||||
};
|
||||
let o3_profile_config: Config = Config::load_from_base_config_with_overrides(
|
||||
@@ -4368,7 +4390,7 @@ fn metrics_exporter_defaults_to_statsig_when_missing() -> std::io::Result<()> {
|
||||
let config = Config::load_from_base_config_with_overrides(
|
||||
fixture.cfg.clone(),
|
||||
ConfigOverrides {
|
||||
cwd: Some(fixture.cwd()),
|
||||
cwd: Some(fixture.cwd_path()),
|
||||
..Default::default()
|
||||
},
|
||||
fixture.codex_home(),
|
||||
@@ -4384,7 +4406,7 @@ fn test_precedence_fixture_with_gpt3_profile() -> std::io::Result<()> {
|
||||
|
||||
let gpt3_profile_overrides = ConfigOverrides {
|
||||
config_profile: Some("gpt3".to_string()),
|
||||
cwd: Some(fixture.cwd()),
|
||||
cwd: Some(fixture.cwd_path()),
|
||||
..Default::default()
|
||||
};
|
||||
let gpt3_profile_config = Config::load_from_base_config_with_overrides(
|
||||
@@ -4505,7 +4527,7 @@ fn test_precedence_fixture_with_gpt3_profile() -> std::io::Result<()> {
|
||||
// Verify that loading without specifying a profile in ConfigOverrides
|
||||
// uses the default profile from the config file (which is "gpt3").
|
||||
let default_profile_overrides = ConfigOverrides {
|
||||
cwd: Some(fixture.cwd()),
|
||||
cwd: Some(fixture.cwd_path()),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
@@ -4525,7 +4547,7 @@ fn test_precedence_fixture_with_zdr_profile() -> std::io::Result<()> {
|
||||
|
||||
let zdr_profile_overrides = ConfigOverrides {
|
||||
config_profile: Some("zdr".to_string()),
|
||||
cwd: Some(fixture.cwd()),
|
||||
cwd: Some(fixture.cwd_path()),
|
||||
..Default::default()
|
||||
};
|
||||
let zdr_profile_config = Config::load_from_base_config_with_overrides(
|
||||
@@ -4652,7 +4674,7 @@ fn test_precedence_fixture_with_gpt5_profile() -> std::io::Result<()> {
|
||||
|
||||
let gpt5_profile_overrides = ConfigOverrides {
|
||||
config_profile: Some("gpt5".to_string()),
|
||||
cwd: Some(fixture.cwd()),
|
||||
cwd: Some(fixture.cwd_path()),
|
||||
..Default::default()
|
||||
};
|
||||
let gpt5_profile_config = Config::load_from_base_config_with_overrides(
|
||||
@@ -4820,7 +4842,7 @@ fn test_requirements_web_search_mode_allowlist_does_not_warn_when_unset() -> any
|
||||
let config = Config::load_config_with_layer_stack(
|
||||
fixture.cfg.clone(),
|
||||
ConfigOverrides {
|
||||
cwd: Some(fixture.cwd()),
|
||||
cwd: Some(fixture.cwd_path()),
|
||||
..Default::default()
|
||||
},
|
||||
fixture.codex_home(),
|
||||
|
||||
@@ -395,10 +395,10 @@ pub struct Config {
|
||||
/// Syntax highlighting theme override (kebab-case name).
|
||||
pub tui_theme: Option<String>,
|
||||
|
||||
/// The directory that should be treated as the current working directory
|
||||
/// for the session. All relative paths inside the business-logic layer are
|
||||
/// resolved against this path.
|
||||
pub cwd: PathBuf,
|
||||
/// The absolute directory that should be treated as the current working
|
||||
/// directory for the session. All relative paths inside the business-logic
|
||||
/// layer are resolved against this path.
|
||||
pub cwd: AbsolutePathBuf,
|
||||
|
||||
/// Preferred store for CLI auth credentials.
|
||||
/// file (default): Use a file in the Codex home directory.
|
||||
@@ -683,7 +683,7 @@ impl ConfigBuilder {
|
||||
let loader_overrides = loader_overrides.unwrap_or_default();
|
||||
let cwd_override = harness_overrides.cwd.as_deref().or(fallback_cwd.as_deref());
|
||||
let cwd = match cwd_override {
|
||||
Some(path) => AbsolutePathBuf::try_from(path)?,
|
||||
Some(path) => AbsolutePathBuf::relative_to_current_dir(path)?,
|
||||
None => AbsolutePathBuf::current_dir()?,
|
||||
};
|
||||
harness_overrides.cwd = Some(cwd.to_path_buf());
|
||||
@@ -2104,7 +2104,7 @@ impl Config {
|
||||
let windows_sandbox_mode = resolve_windows_sandbox_mode(&cfg, &config_profile);
|
||||
let windows_sandbox_private_desktop =
|
||||
resolve_windows_sandbox_private_desktop(&cfg, &config_profile);
|
||||
let resolved_cwd = normalize_for_native_workdir({
|
||||
let resolved_cwd = AbsolutePathBuf::try_from(normalize_for_native_workdir({
|
||||
use std::env;
|
||||
|
||||
match cwd {
|
||||
@@ -2121,13 +2121,13 @@ impl Config {
|
||||
current
|
||||
}
|
||||
}
|
||||
});
|
||||
}))?;
|
||||
let mut additional_writable_roots: Vec<AbsolutePathBuf> = additional_writable_roots
|
||||
.into_iter()
|
||||
.map(|path| AbsolutePathBuf::resolve_path_against_base(path, &resolved_cwd))
|
||||
.map(|path| AbsolutePathBuf::resolve_path_against_base(path, resolved_cwd.as_path()))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
let active_project = cfg
|
||||
.get_active_project(&resolved_cwd)
|
||||
.get_active_project(resolved_cwd.as_path())
|
||||
.unwrap_or(ProjectConfig { trust_level: None });
|
||||
let permission_config_syntax = resolve_permission_config_syntax(
|
||||
&config_layer_stack,
|
||||
@@ -2200,12 +2200,15 @@ impl Config {
|
||||
&mut startup_warnings,
|
||||
)?;
|
||||
let mut sandbox_policy = file_system_sandbox_policy
|
||||
.to_legacy_sandbox_policy(network_sandbox_policy, &resolved_cwd)?;
|
||||
.to_legacy_sandbox_policy(network_sandbox_policy, resolved_cwd.as_path())?;
|
||||
if matches!(sandbox_policy, SandboxPolicy::WorkspaceWrite { .. }) {
|
||||
file_system_sandbox_policy = file_system_sandbox_policy
|
||||
.with_additional_writable_roots(&resolved_cwd, &additional_writable_roots);
|
||||
.with_additional_writable_roots(
|
||||
resolved_cwd.as_path(),
|
||||
&additional_writable_roots,
|
||||
);
|
||||
sandbox_policy = file_system_sandbox_policy
|
||||
.to_legacy_sandbox_policy(network_sandbox_policy, &resolved_cwd)?;
|
||||
.to_legacy_sandbox_policy(network_sandbox_policy, resolved_cwd.as_path())?;
|
||||
}
|
||||
(
|
||||
configured_network_proxy_config,
|
||||
@@ -2219,7 +2222,7 @@ impl Config {
|
||||
sandbox_mode,
|
||||
config_profile.sandbox_mode,
|
||||
windows_sandbox_level,
|
||||
&resolved_cwd,
|
||||
resolved_cwd.as_path(),
|
||||
Some(&constrained_sandbox_policy),
|
||||
);
|
||||
if let SandboxPolicy::WorkspaceWrite { writable_roots, .. } = &mut sandbox_policy {
|
||||
@@ -2229,8 +2232,10 @@ impl Config {
|
||||
}
|
||||
}
|
||||
}
|
||||
let file_system_sandbox_policy =
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy(&sandbox_policy, &resolved_cwd);
|
||||
let file_system_sandbox_policy = FileSystemSandboxPolicy::from_legacy_sandbox_policy(
|
||||
&sandbox_policy,
|
||||
resolved_cwd.as_path(),
|
||||
);
|
||||
let network_sandbox_policy = NetworkSandboxPolicy::from(&sandbox_policy);
|
||||
(
|
||||
configured_network_proxy_config,
|
||||
@@ -2566,11 +2571,11 @@ impl Config {
|
||||
} else {
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy(
|
||||
&effective_sandbox_policy,
|
||||
&resolved_cwd,
|
||||
resolved_cwd.as_path(),
|
||||
)
|
||||
};
|
||||
let effective_file_system_sandbox_policy = effective_file_system_sandbox_policy
|
||||
.with_additional_readable_roots(&resolved_cwd, &helper_readable_roots);
|
||||
.with_additional_readable_roots(resolved_cwd.as_path(), &helper_readable_roots);
|
||||
let effective_network_sandbox_policy =
|
||||
if effective_sandbox_policy == original_sandbox_policy {
|
||||
network_sandbox_policy
|
||||
|
||||
@@ -70,8 +70,8 @@ impl EnvironmentContext {
|
||||
) -> Self {
|
||||
let before_network = Self::network_from_turn_context_item(before);
|
||||
let after_network = Self::network_from_turn_context(after);
|
||||
let cwd = if before.cwd != after.cwd {
|
||||
Some(after.cwd.clone())
|
||||
let cwd = if before.cwd.as_path() != after.cwd.as_path() {
|
||||
Some(after.cwd.to_path_buf())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@@ -94,7 +94,7 @@ impl EnvironmentContext {
|
||||
|
||||
pub fn from_turn_context(turn_context: &TurnContext, shell: &Shell) -> Self {
|
||||
Self::new(
|
||||
Some(turn_context.cwd.clone()),
|
||||
Some(turn_context.cwd.to_path_buf()),
|
||||
shell.clone(),
|
||||
turn_context.current_date.clone(),
|
||||
turn_context.timezone.clone(),
|
||||
|
||||
@@ -140,7 +140,7 @@ impl GuardianReviewSessionReuseKey {
|
||||
base_instructions: spawn_config.base_instructions.clone(),
|
||||
user_instructions: spawn_config.user_instructions.clone(),
|
||||
compact_prompt: spawn_config.compact_prompt.clone(),
|
||||
cwd: spawn_config.cwd.clone(),
|
||||
cwd: spawn_config.cwd.to_path_buf(),
|
||||
mcp_servers: spawn_config.mcp_servers.clone(),
|
||||
codex_linux_sandbox_exe: spawn_config.codex_linux_sandbox_exe.clone(),
|
||||
main_execve_wrapper_exe: spawn_config.main_execve_wrapper_exe.clone(),
|
||||
@@ -512,7 +512,7 @@ async fn run_review_on_session(
|
||||
.codex
|
||||
.submit(Op::UserTurn {
|
||||
items: params.prompt_items.clone(),
|
||||
cwd: params.parent_turn.cwd.clone(),
|
||||
cwd: params.parent_turn.cwd.to_path_buf(),
|
||||
approval_policy: AskForApproval::Never,
|
||||
approvals_reviewer: None,
|
||||
sandbox_policy: SandboxPolicy::new_read_only_policy(),
|
||||
|
||||
@@ -25,7 +25,8 @@ use codex_protocol::protocol::EventMsg;
|
||||
use codex_protocol::protocol::GuardianAssessmentStatus;
|
||||
use codex_protocol::protocol::GuardianRiskLevel;
|
||||
use codex_protocol::protocol::ReviewDecision;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use core_test_support::PathBufExt;
|
||||
use core_test_support::TempDirExt;
|
||||
use core_test_support::context_snapshot;
|
||||
use core_test_support::context_snapshot::ContextSnapshotOptions;
|
||||
use core_test_support::responses::ev_assistant_message;
|
||||
@@ -322,7 +323,7 @@ fn guardian_assessment_action_value_redacts_apply_patch_patch_text() {
|
||||
("/tmp", "/tmp/guardian.txt")
|
||||
};
|
||||
let cwd = PathBuf::from(cwd);
|
||||
let file = AbsolutePathBuf::try_from(file).expect("absolute path");
|
||||
let file = PathBuf::from(file).abs();
|
||||
let action = GuardianApprovalRequest::ApplyPatch {
|
||||
id: "patch-1".to_string(),
|
||||
cwd: cwd.clone(),
|
||||
@@ -356,7 +357,7 @@ fn guardian_request_turn_id_prefers_network_access_owner_turn() {
|
||||
let apply_patch = GuardianApprovalRequest::ApplyPatch {
|
||||
id: "patch-1".to_string(),
|
||||
cwd: PathBuf::from("/tmp"),
|
||||
files: vec![AbsolutePathBuf::try_from("/tmp/guardian.txt").expect("absolute path")],
|
||||
files: vec![PathBuf::from("/tmp/guardian.txt").abs()],
|
||||
change_count: 1usize,
|
||||
patch: "*** Begin Patch\n*** Update File: guardian.txt\n@@\n+hello\n*** End Patch"
|
||||
.to_string(),
|
||||
@@ -384,7 +385,7 @@ async fn cancelled_guardian_review_emits_terminal_abort_without_warning() {
|
||||
GuardianApprovalRequest::ApplyPatch {
|
||||
id: "patch-1".to_string(),
|
||||
cwd: PathBuf::from("/tmp"),
|
||||
files: vec![AbsolutePathBuf::try_from("/tmp/guardian.txt").expect("absolute path")],
|
||||
files: vec![PathBuf::from("/tmp/guardian.txt").abs()],
|
||||
change_count: 1usize,
|
||||
patch: "*** Begin Patch\n*** Update File: guardian.txt\n@@\n+hello\n*** End Patch"
|
||||
.to_string(),
|
||||
@@ -512,7 +513,7 @@ async fn guardian_review_request_layout_matches_model_visible_request_snapshot()
|
||||
let (mut session, mut turn) = crate::codex::make_session_and_context().await;
|
||||
let temp_cwd = TempDir::new()?;
|
||||
let mut config = (*turn.config).clone();
|
||||
config.cwd = temp_cwd.path().to_path_buf();
|
||||
config.cwd = temp_cwd.abs();
|
||||
config.model_provider.base_url = Some(format!("{}/v1", server.uri()));
|
||||
let config = Arc::new(config);
|
||||
let models_manager = Arc::new(test_support::models_manager_with_provider(
|
||||
|
||||
@@ -92,7 +92,7 @@ pub(crate) async fn run_pending_session_start_hooks(
|
||||
|
||||
let request = codex_hooks::SessionStartRequest {
|
||||
session_id: sess.conversation_id,
|
||||
cwd: turn_context.cwd.clone(),
|
||||
cwd: turn_context.cwd.to_path_buf(),
|
||||
transcript_path: sess.hook_transcript_path().await,
|
||||
model: turn_context.model_info.slug.clone(),
|
||||
permission_mode: hook_permission_mode(turn_context),
|
||||
@@ -120,7 +120,7 @@ pub(crate) async fn run_pre_tool_use_hooks(
|
||||
let request = PreToolUseRequest {
|
||||
session_id: sess.conversation_id,
|
||||
turn_id: turn_context.sub_id.clone(),
|
||||
cwd: turn_context.cwd.clone(),
|
||||
cwd: turn_context.cwd.to_path_buf(),
|
||||
transcript_path: sess.hook_transcript_path().await,
|
||||
model: turn_context.model_info.slug.clone(),
|
||||
permission_mode: hook_permission_mode(turn_context),
|
||||
@@ -149,7 +149,7 @@ pub(crate) async fn run_user_prompt_submit_hooks(
|
||||
let request = UserPromptSubmitRequest {
|
||||
session_id: sess.conversation_id,
|
||||
turn_id: turn_context.sub_id.clone(),
|
||||
cwd: turn_context.cwd.clone(),
|
||||
cwd: turn_context.cwd.to_path_buf(),
|
||||
transcript_path: sess.hook_transcript_path().await,
|
||||
model: turn_context.model_info.slug.clone(),
|
||||
permission_mode: hook_permission_mode(turn_context),
|
||||
|
||||
@@ -266,7 +266,16 @@ mod agent {
|
||||
let root = memory_root(&config.codex_home);
|
||||
let mut agent_config = config.as_ref().clone();
|
||||
|
||||
agent_config.cwd = root;
|
||||
match AbsolutePathBuf::from_absolute_path(root) {
|
||||
Ok(root) => agent_config.cwd = root,
|
||||
Err(err) => {
|
||||
warn!(
|
||||
"memory phase-2 consolidation could not set cwd from codex_home {}: {err}",
|
||||
agent_config.codex_home.display()
|
||||
);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
// Consolidation threads must never feed back into phase-1 memory generation.
|
||||
agent_config.memories.generate_memories = false;
|
||||
// Approval policy
|
||||
|
||||
@@ -435,6 +435,7 @@ mod phase2 {
|
||||
use codex_state::Phase2JobClaimOutcome;
|
||||
use codex_state::Stage1Output;
|
||||
use codex_state::ThreadMetadataBuilder;
|
||||
use core_test_support::PathBufExt;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
@@ -469,7 +470,7 @@ mod phase2 {
|
||||
let codex_home = tempfile::tempdir().expect("create temp codex home");
|
||||
let mut config = test_config();
|
||||
config.codex_home = codex_home.path().to_path_buf();
|
||||
config.cwd = config.codex_home.clone();
|
||||
config.cwd = config.codex_home.abs();
|
||||
let config = Arc::new(config);
|
||||
|
||||
let state_db = codex_state::StateRuntime::init(
|
||||
@@ -507,7 +508,7 @@ mod phase2 {
|
||||
Utc::now(),
|
||||
SessionSource::Cli,
|
||||
);
|
||||
metadata_builder.cwd = self.config.cwd.clone();
|
||||
metadata_builder.cwd = self.config.cwd.to_path_buf();
|
||||
metadata_builder.model_provider = Some(self.config.model_provider_id.clone());
|
||||
let metadata = metadata_builder.build(&self.config.model_provider_id);
|
||||
|
||||
@@ -882,7 +883,7 @@ mod phase2 {
|
||||
let codex_home = tempfile::tempdir().expect("create temp codex home");
|
||||
let mut config = test_config();
|
||||
config.codex_home = codex_home.path().to_path_buf();
|
||||
config.cwd = config.codex_home.clone();
|
||||
config.cwd = config.codex_home.abs();
|
||||
let config = Arc::new(config);
|
||||
|
||||
let state_db = codex_state::StateRuntime::init(
|
||||
@@ -904,7 +905,7 @@ mod phase2 {
|
||||
Utc::now(),
|
||||
SessionSource::Cli,
|
||||
);
|
||||
metadata_builder.cwd = config.cwd.clone();
|
||||
metadata_builder.cwd = config.cwd.to_path_buf();
|
||||
metadata_builder.model_provider = Some(config.model_provider_id.clone());
|
||||
let metadata = metadata_builder.build(&config.model_provider_id);
|
||||
state_db
|
||||
|
||||
@@ -184,7 +184,7 @@ pub async fn read_project_docs(config: &Config) -> std::io::Result<Option<String
|
||||
/// directory (inclusive). Symlinks are allowed. When `project_doc_max_bytes`
|
||||
/// is zero, returns an empty list.
|
||||
pub fn discover_project_doc_paths(config: &Config) -> std::io::Result<Vec<PathBuf>> {
|
||||
let mut dir = config.cwd.clone();
|
||||
let mut dir = config.cwd.to_path_buf();
|
||||
if let Ok(canon) = normalize_path(&dir) {
|
||||
dir = canon;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use super::*;
|
||||
use crate::config::ConfigBuilder;
|
||||
use codex_features::Feature;
|
||||
use core_test_support::PathBufExt;
|
||||
use core_test_support::TempDirExt;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use tempfile::TempDir;
|
||||
@@ -18,7 +20,7 @@ async fn make_config(root: &TempDir, limit: usize, instructions: Option<&str>) -
|
||||
.await
|
||||
.expect("defaults for test should always succeed");
|
||||
|
||||
config.cwd = root.path().to_path_buf();
|
||||
config.cwd = root.abs();
|
||||
config.project_doc_max_bytes = limit;
|
||||
|
||||
config.user_instructions = instructions.map(ToOwned::to_owned);
|
||||
@@ -62,7 +64,7 @@ async fn make_config_with_project_root_markers(
|
||||
.await
|
||||
.expect("defaults for test should always succeed");
|
||||
|
||||
config.cwd = root.path().to_path_buf();
|
||||
config.cwd = root.abs();
|
||||
config.project_doc_max_bytes = limit;
|
||||
config.user_instructions = instructions.map(ToOwned::to_owned);
|
||||
config
|
||||
@@ -136,7 +138,7 @@ async fn finds_doc_in_repo_root() {
|
||||
|
||||
// Build config pointing at the nested dir.
|
||||
let mut cfg = make_config(&repo, 4096, None).await;
|
||||
cfg.cwd = nested;
|
||||
cfg.cwd = nested.abs();
|
||||
|
||||
let res = get_user_instructions(&cfg).await.expect("doc expected");
|
||||
assert_eq!(res, "root level doc");
|
||||
@@ -261,7 +263,7 @@ async fn concatenates_root_and_cwd_docs() {
|
||||
fs::write(nested.join("AGENTS.md"), "crate doc").unwrap();
|
||||
|
||||
let mut cfg = make_config(&repo, 4096, None).await;
|
||||
cfg.cwd = nested;
|
||||
cfg.cwd = nested.abs();
|
||||
|
||||
let res = get_user_instructions(&cfg).await.expect("doc expected");
|
||||
assert_eq!(res, "root doc\n\ncrate doc");
|
||||
@@ -278,13 +280,13 @@ async fn project_root_markers_are_honored_for_agents_discovery() {
|
||||
fs::write(nested.join("AGENTS.md"), "child doc").unwrap();
|
||||
|
||||
let mut cfg = make_config_with_project_root_markers(&root, 4096, None, &[".codex-root"]).await;
|
||||
cfg.cwd = nested;
|
||||
cfg.cwd = nested.abs();
|
||||
|
||||
let discovery = discover_project_doc_paths(&cfg).expect("discover paths");
|
||||
let expected_parent =
|
||||
dunce::canonicalize(root.path().join("AGENTS.md")).expect("canonical parent doc path");
|
||||
let expected_child =
|
||||
dunce::canonicalize(cfg.cwd.join("AGENTS.md")).expect("canonical child doc path");
|
||||
dunce::canonicalize(cfg.cwd.as_path().join("AGENTS.md")).expect("canonical child doc path");
|
||||
assert_eq!(discovery.len(), 2);
|
||||
assert_eq!(discovery[0], expected_parent);
|
||||
assert_eq!(discovery[1], expected_child);
|
||||
|
||||
@@ -145,7 +145,7 @@ pub(crate) async fn execute_user_shell_command(
|
||||
process_id: None,
|
||||
turn_id: turn_context.sub_id.clone(),
|
||||
command: display_command.clone(),
|
||||
cwd: cwd.clone(),
|
||||
cwd: cwd.to_path_buf(),
|
||||
parsed_cmd: parsed_cmd.clone(),
|
||||
source: ExecCommandSource::UserShell,
|
||||
interaction_input: None,
|
||||
@@ -156,7 +156,7 @@ pub(crate) async fn execute_user_shell_command(
|
||||
let sandbox_policy = SandboxPolicy::DangerFullAccess;
|
||||
let exec_env = ExecRequest {
|
||||
command: exec_command.clone(),
|
||||
cwd: cwd.clone(),
|
||||
cwd: cwd.to_path_buf(),
|
||||
env: create_env(
|
||||
&turn_context.shell_environment_policy,
|
||||
Some(session.conversation_id),
|
||||
@@ -221,7 +221,7 @@ pub(crate) async fn execute_user_shell_command(
|
||||
process_id: None,
|
||||
turn_id: turn_context.sub_id.clone(),
|
||||
command: display_command.clone(),
|
||||
cwd: cwd.clone(),
|
||||
cwd: cwd.to_path_buf(),
|
||||
parsed_cmd: parsed_cmd.clone(),
|
||||
source: ExecCommandSource::UserShell,
|
||||
interaction_input: None,
|
||||
@@ -245,7 +245,7 @@ pub(crate) async fn execute_user_shell_command(
|
||||
process_id: None,
|
||||
turn_id: turn_context.sub_id.clone(),
|
||||
command: display_command.clone(),
|
||||
cwd: cwd.clone(),
|
||||
cwd: cwd.to_path_buf(),
|
||||
parsed_cmd: parsed_cmd.clone(),
|
||||
source: ExecCommandSource::UserShell,
|
||||
interaction_input: None,
|
||||
@@ -289,7 +289,7 @@ pub(crate) async fn execute_user_shell_command(
|
||||
process_id: None,
|
||||
turn_id: turn_context.sub_id.clone(),
|
||||
command: display_command,
|
||||
cwd,
|
||||
cwd: cwd.to_path_buf(),
|
||||
parsed_cmd,
|
||||
source: ExecCommandSource::UserShell,
|
||||
interaction_input: None,
|
||||
|
||||
@@ -12,6 +12,7 @@ use codex_protocol::openai_models::ModelsResponse;
|
||||
use codex_protocol::protocol::AgentMessageEvent;
|
||||
use codex_protocol::protocol::TurnStartedEvent;
|
||||
use codex_protocol::protocol::UserMessageEvent;
|
||||
use core_test_support::PathExt;
|
||||
use core_test_support::responses::mount_models_once;
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::time::Duration;
|
||||
@@ -236,7 +237,7 @@ async fn shutdown_all_threads_bounded_submits_shutdown_to_every_thread() {
|
||||
let temp_dir = tempdir().expect("tempdir");
|
||||
let mut config = test_config();
|
||||
config.codex_home = temp_dir.path().join("codex-home");
|
||||
config.cwd = config.codex_home.clone();
|
||||
config.cwd = config.codex_home.abs();
|
||||
std::fs::create_dir_all(&config.codex_home).expect("create codex home");
|
||||
|
||||
let manager = ThreadManager::with_models_provider_and_home_for_tests(
|
||||
@@ -275,7 +276,7 @@ async fn new_uses_configured_openai_provider_for_model_refresh() {
|
||||
let temp_dir = tempdir().expect("tempdir");
|
||||
let mut config = test_config();
|
||||
config.codex_home = temp_dir.path().join("codex-home");
|
||||
config.cwd = config.codex_home.clone();
|
||||
config.cwd = config.codex_home.abs();
|
||||
std::fs::create_dir_all(&config.codex_home).expect("create codex home");
|
||||
config.model_catalog = None;
|
||||
config
|
||||
@@ -408,7 +409,7 @@ async fn interrupted_fork_snapshot_does_not_synthesize_turn_id_for_legacy_histor
|
||||
let temp_dir = tempdir().expect("tempdir");
|
||||
let mut config = test_config();
|
||||
config.codex_home = temp_dir.path().join("codex-home");
|
||||
config.cwd = config.codex_home.clone();
|
||||
config.cwd = config.codex_home.abs();
|
||||
std::fs::create_dir_all(&config.codex_home).expect("create codex home");
|
||||
|
||||
let auth_manager =
|
||||
@@ -505,7 +506,7 @@ async fn interrupted_fork_snapshot_preserves_explicit_turn_id() {
|
||||
let temp_dir = tempdir().expect("tempdir");
|
||||
let mut config = test_config();
|
||||
config.codex_home = temp_dir.path().join("codex-home");
|
||||
config.cwd = config.codex_home.clone();
|
||||
config.cwd = config.codex_home.abs();
|
||||
std::fs::create_dir_all(&config.codex_home).expect("create codex home");
|
||||
|
||||
let auth_manager =
|
||||
@@ -591,7 +592,7 @@ async fn interrupted_fork_snapshot_uses_persisted_mid_turn_history_without_live_
|
||||
let temp_dir = tempdir().expect("tempdir");
|
||||
let mut config = test_config();
|
||||
config.codex_home = temp_dir.path().join("codex-home");
|
||||
config.cwd = config.codex_home.clone();
|
||||
config.cwd = config.codex_home.abs();
|
||||
std::fs::create_dir_all(&config.codex_home).expect("create codex home");
|
||||
|
||||
let auth_manager =
|
||||
|
||||
@@ -89,7 +89,7 @@ impl ToolHandler for ArtifactsHandler {
|
||||
let result = client
|
||||
.execute_build(ArtifactBuildRequest {
|
||||
source: args.source,
|
||||
cwd: turn.cwd.clone(),
|
||||
cwd: turn.cwd.to_path_buf(),
|
||||
timeout: Some(Duration::from_millis(
|
||||
args.timeout_ms
|
||||
.unwrap_or(DEFAULT_EXECUTION_TIMEOUT.as_millis() as u64),
|
||||
@@ -221,7 +221,7 @@ fn default_runtime_manager(codex_home: std::path::PathBuf) -> ArtifactRuntimeMan
|
||||
async fn emit_exec_begin(session: &Session, turn: &TurnContext, call_id: &str) {
|
||||
let emitter = ToolEmitter::shell(
|
||||
vec![ARTIFACTS_TOOL_NAME.to_string()],
|
||||
turn.cwd.clone(),
|
||||
turn.cwd.to_path_buf(),
|
||||
ExecCommandSource::Agent,
|
||||
/*freeform*/ true,
|
||||
);
|
||||
@@ -247,7 +247,7 @@ async fn emit_exec_end(
|
||||
};
|
||||
let emitter = ToolEmitter::shell(
|
||||
vec![ARTIFACTS_TOOL_NAME.to_string()],
|
||||
turn.cwd.clone(),
|
||||
turn.cwd.to_path_buf(),
|
||||
ExecCommandSource::Agent,
|
||||
/*freeform*/ true,
|
||||
);
|
||||
|
||||
@@ -61,7 +61,7 @@ async fn emit_js_repl_exec_begin(
|
||||
) {
|
||||
let emitter = ToolEmitter::shell(
|
||||
vec!["js_repl".to_string()],
|
||||
turn.cwd.clone(),
|
||||
turn.cwd.to_path_buf(),
|
||||
ExecCommandSource::Agent,
|
||||
/*freeform*/ false,
|
||||
);
|
||||
@@ -80,7 +80,7 @@ async fn emit_js_repl_exec_end(
|
||||
let exec_output = build_js_repl_exec_output(output, error, duration);
|
||||
let emitter = ToolEmitter::shell(
|
||||
vec!["js_repl".to_string()],
|
||||
turn.cwd.clone(),
|
||||
turn.cwd.to_path_buf(),
|
||||
ExecCommandSource::Agent,
|
||||
/*freeform*/ false,
|
||||
);
|
||||
|
||||
@@ -77,7 +77,7 @@ async fn emit_js_repl_exec_end_sends_event() {
|
||||
assert_eq!(event.call_id, "call-1");
|
||||
assert_eq!(event.turn_id, turn.sub_id);
|
||||
assert_eq!(event.command, vec!["js_repl".to_string()]);
|
||||
assert_eq!(event.cwd, turn.cwd);
|
||||
assert_eq!(event.cwd, turn.cwd.to_path_buf());
|
||||
assert_eq!(event.source, ExecCommandSource::Agent);
|
||||
assert_eq!(event.interaction_input, None);
|
||||
assert_eq!(event.stdout, "hello");
|
||||
|
||||
@@ -39,6 +39,7 @@ use codex_protocol::protocol::InitialHistory;
|
||||
use codex_protocol::protocol::InterAgentCommunication;
|
||||
use codex_protocol::protocol::RolloutItem;
|
||||
use codex_protocol::user_input::UserInput;
|
||||
use core_test_support::TempDirExt;
|
||||
use pretty_assertions::assert_eq;
|
||||
use serde::Deserialize;
|
||||
use serde_json::json;
|
||||
@@ -2236,7 +2237,7 @@ async fn build_agent_spawn_config_uses_turn_context_values() {
|
||||
..ShellEnvironmentPolicy::default()
|
||||
};
|
||||
let temp_dir = tempfile::tempdir().expect("temp dir");
|
||||
turn.cwd = temp_dir.path().to_path_buf();
|
||||
turn.cwd = temp_dir.abs();
|
||||
turn.codex_linux_sandbox_exe = Some(PathBuf::from("/bin/echo"));
|
||||
let sandbox_policy = pick_allowed_sandbox_policy(
|
||||
&turn.config.permissions.sandbox_policy,
|
||||
|
||||
@@ -1050,7 +1050,7 @@ impl JsReplManager {
|
||||
"--experimental-vm-modules".to_string(),
|
||||
kernel_path.to_string_lossy().to_string(),
|
||||
],
|
||||
cwd: turn.cwd.clone(),
|
||||
cwd: turn.cwd.to_path_buf(),
|
||||
env,
|
||||
additional_permissions: None,
|
||||
};
|
||||
|
||||
@@ -14,6 +14,8 @@ use codex_protocol::models::FunctionCallOutputPayload;
|
||||
use codex_protocol::models::ImageDetail;
|
||||
use codex_protocol::models::ResponseInputItem;
|
||||
use codex_protocol::openai_models::InputModality;
|
||||
use core_test_support::PathBufExt;
|
||||
use core_test_support::TempDirExt;
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
@@ -739,7 +741,7 @@ async fn interrupt_active_exec_stops_aborted_kernel_before_later_exec() -> anyho
|
||||
|
||||
let dir = tempdir()?;
|
||||
let (session, mut turn) = make_session_and_context().await;
|
||||
turn.cwd = dir.path().to_path_buf();
|
||||
turn.cwd = dir.abs();
|
||||
set_danger_full_access(&mut turn);
|
||||
let session = Arc::new(session);
|
||||
let turn = Arc::new(turn);
|
||||
@@ -1017,7 +1019,7 @@ async fn js_repl_waits_for_unawaited_tool_calls_before_completion() -> anyhow::R
|
||||
|
||||
let marker = turn
|
||||
.cwd
|
||||
.join(format!("js-repl-unawaited-marker-{}.txt", Uuid::new_v4()));
|
||||
.join(format!("js-repl-unawaited-marker-{}.txt", Uuid::new_v4()))?;
|
||||
let marker_json = serde_json::to_string(&marker.to_string_lossy().to_string())?;
|
||||
let result = manager
|
||||
.execute(
|
||||
@@ -1062,10 +1064,10 @@ async fn js_repl_persisted_tool_helpers_work_across_cells() -> anyhow::Result<()
|
||||
|
||||
let global_marker = turn
|
||||
.cwd
|
||||
.join(format!("js-repl-global-helper-{}.txt", Uuid::new_v4()));
|
||||
.join(format!("js-repl-global-helper-{}.txt", Uuid::new_v4()))?;
|
||||
let lexical_marker = turn
|
||||
.cwd
|
||||
.join(format!("js-repl-lexical-helper-{}.txt", Uuid::new_v4()));
|
||||
.join(format!("js-repl-lexical-helper-{}.txt", Uuid::new_v4()))?;
|
||||
let global_marker_json = serde_json::to_string(&global_marker.to_string_lossy().to_string())?;
|
||||
let lexical_marker_json = serde_json::to_string(&lexical_marker.to_string_lossy().to_string())?;
|
||||
|
||||
@@ -2101,7 +2103,7 @@ async fn js_repl_prefers_env_node_module_dirs_over_config() -> anyhow::Result<()
|
||||
"CODEX_JS_REPL_NODE_MODULE_DIRS".to_string(),
|
||||
env_base.path().to_string_lossy().to_string(),
|
||||
);
|
||||
turn.cwd = cwd_dir.path().to_path_buf();
|
||||
turn.cwd = cwd_dir.abs();
|
||||
turn.js_repl = Arc::new(JsReplHandle::with_node_path(
|
||||
turn.config.js_repl_node_path.clone(),
|
||||
vec![config_base.path().to_path_buf()],
|
||||
@@ -2145,7 +2147,7 @@ async fn js_repl_resolves_from_first_config_dir() -> anyhow::Result<()> {
|
||||
turn.shell_environment_policy
|
||||
.r#set
|
||||
.remove("CODEX_JS_REPL_NODE_MODULE_DIRS");
|
||||
turn.cwd = cwd_dir.path().to_path_buf();
|
||||
turn.cwd = cwd_dir.abs();
|
||||
turn.js_repl = Arc::new(JsReplHandle::with_node_path(
|
||||
turn.config.js_repl_node_path.clone(),
|
||||
vec![
|
||||
@@ -2189,7 +2191,7 @@ async fn js_repl_falls_back_to_cwd_node_modules() -> anyhow::Result<()> {
|
||||
turn.shell_environment_policy
|
||||
.r#set
|
||||
.remove("CODEX_JS_REPL_NODE_MODULE_DIRS");
|
||||
turn.cwd = cwd_dir.path().to_path_buf();
|
||||
turn.cwd = cwd_dir.abs();
|
||||
turn.js_repl = Arc::new(JsReplHandle::with_node_path(
|
||||
turn.config.js_repl_node_path.clone(),
|
||||
vec![config_base.path().to_path_buf()],
|
||||
@@ -2230,7 +2232,7 @@ async fn js_repl_accepts_node_modules_dir_entries() -> anyhow::Result<()> {
|
||||
turn.shell_environment_policy
|
||||
.r#set
|
||||
.remove("CODEX_JS_REPL_NODE_MODULE_DIRS");
|
||||
turn.cwd = cwd_dir.path().to_path_buf();
|
||||
turn.cwd = cwd_dir.abs();
|
||||
turn.js_repl = Arc::new(JsReplHandle::with_node_path(
|
||||
turn.config.js_repl_node_path.clone(),
|
||||
vec![base_dir.path().join("node_modules")],
|
||||
@@ -2284,7 +2286,7 @@ async fn js_repl_supports_relative_file_imports() -> anyhow::Result<()> {
|
||||
turn.shell_environment_policy
|
||||
.r#set
|
||||
.remove("CODEX_JS_REPL_NODE_MODULE_DIRS");
|
||||
turn.cwd = cwd_dir.path().to_path_buf();
|
||||
turn.cwd = cwd_dir.abs();
|
||||
turn.js_repl = Arc::new(JsReplHandle::with_node_path(
|
||||
turn.config.js_repl_node_path.clone(),
|
||||
Vec::new(),
|
||||
@@ -2331,7 +2333,7 @@ async fn js_repl_supports_absolute_file_imports() -> anyhow::Result<()> {
|
||||
turn.shell_environment_policy
|
||||
.r#set
|
||||
.remove("CODEX_JS_REPL_NODE_MODULE_DIRS");
|
||||
turn.cwd = cwd_dir.path().to_path_buf();
|
||||
turn.cwd = cwd_dir.abs();
|
||||
turn.js_repl = Arc::new(JsReplHandle::with_node_path(
|
||||
turn.config.js_repl_node_path.clone(),
|
||||
Vec::new(),
|
||||
@@ -2385,7 +2387,7 @@ async fn js_repl_imported_local_files_can_access_repl_globals() -> anyhow::Resul
|
||||
turn.shell_environment_policy
|
||||
.r#set
|
||||
.remove("CODEX_JS_REPL_NODE_MODULE_DIRS");
|
||||
turn.cwd = cwd_dir.path().to_path_buf();
|
||||
turn.cwd = cwd_dir.abs();
|
||||
turn.js_repl = Arc::new(JsReplHandle::with_node_path(
|
||||
turn.config.js_repl_node_path.clone(),
|
||||
Vec::new(),
|
||||
@@ -2429,7 +2431,7 @@ async fn js_repl_reimports_local_files_after_edit() -> anyhow::Result<()> {
|
||||
turn.shell_environment_policy
|
||||
.r#set
|
||||
.remove("CODEX_JS_REPL_NODE_MODULE_DIRS");
|
||||
turn.cwd = cwd_dir.path().to_path_buf();
|
||||
turn.cwd = cwd_dir.abs();
|
||||
turn.js_repl = Arc::new(JsReplHandle::with_node_path(
|
||||
turn.config.js_repl_node_path.clone(),
|
||||
Vec::new(),
|
||||
@@ -2485,7 +2487,7 @@ async fn js_repl_reimports_local_files_after_fixing_failure() -> anyhow::Result<
|
||||
turn.shell_environment_policy
|
||||
.r#set
|
||||
.remove("CODEX_JS_REPL_NODE_MODULE_DIRS");
|
||||
turn.cwd = cwd_dir.path().to_path_buf();
|
||||
turn.cwd = cwd_dir.abs();
|
||||
turn.js_repl = Arc::new(JsReplHandle::with_node_path(
|
||||
turn.config.js_repl_node_path.clone(),
|
||||
Vec::new(),
|
||||
@@ -2563,7 +2565,7 @@ async fn js_repl_local_files_expose_node_like_import_meta() -> anyhow::Result<()
|
||||
turn.shell_environment_policy
|
||||
.r#set
|
||||
.remove("CODEX_JS_REPL_NODE_MODULE_DIRS");
|
||||
turn.cwd = cwd_dir.path().to_path_buf();
|
||||
turn.cwd = cwd_dir.abs();
|
||||
turn.js_repl = Arc::new(JsReplHandle::with_node_path(
|
||||
turn.config.js_repl_node_path.clone(),
|
||||
Vec::new(),
|
||||
@@ -2648,7 +2650,7 @@ async fn js_repl_local_files_reject_static_bare_imports() -> anyhow::Result<()>
|
||||
turn.shell_environment_policy
|
||||
.r#set
|
||||
.remove("CODEX_JS_REPL_NODE_MODULE_DIRS");
|
||||
turn.cwd = cwd_dir.path().to_path_buf();
|
||||
turn.cwd = cwd_dir.abs();
|
||||
turn.js_repl = Arc::new(JsReplHandle::with_node_path(
|
||||
turn.config.js_repl_node_path.clone(),
|
||||
Vec::new(),
|
||||
@@ -2693,7 +2695,7 @@ async fn js_repl_rejects_unsupported_file_specifiers() -> anyhow::Result<()> {
|
||||
turn.shell_environment_policy
|
||||
.r#set
|
||||
.remove("CODEX_JS_REPL_NODE_MODULE_DIRS");
|
||||
turn.cwd = cwd_dir.path().to_path_buf();
|
||||
turn.cwd = cwd_dir.abs();
|
||||
turn.js_repl = Arc::new(JsReplHandle::with_node_path(
|
||||
turn.config.js_repl_node_path.clone(),
|
||||
Vec::new(),
|
||||
@@ -2795,7 +2797,7 @@ async fn js_repl_blocks_sensitive_builtin_imports_from_local_files() -> anyhow::
|
||||
turn.shell_environment_policy
|
||||
.r#set
|
||||
.remove("CODEX_JS_REPL_NODE_MODULE_DIRS");
|
||||
turn.cwd = cwd_dir.path().to_path_buf();
|
||||
turn.cwd = cwd_dir.abs();
|
||||
turn.js_repl = Arc::new(JsReplHandle::with_node_path(
|
||||
turn.config.js_repl_node_path.clone(),
|
||||
Vec::new(),
|
||||
@@ -2845,7 +2847,7 @@ async fn js_repl_local_files_do_not_escape_node_module_search_roots() -> anyhow:
|
||||
turn.shell_environment_policy
|
||||
.r#set
|
||||
.remove("CODEX_JS_REPL_NODE_MODULE_DIRS");
|
||||
turn.cwd = cwd_dir.clone();
|
||||
turn.cwd = cwd_dir.abs();
|
||||
turn.js_repl = Arc::new(JsReplHandle::with_node_path(
|
||||
turn.config.js_repl_node_path.clone(),
|
||||
Vec::new(),
|
||||
|
||||
@@ -379,7 +379,7 @@ impl NetworkApprovalService {
|
||||
approval_id,
|
||||
/*approval_id*/ None,
|
||||
prompt_command,
|
||||
turn_context.cwd.clone(),
|
||||
turn_context.cwd.to_path_buf(),
|
||||
Some(prompt_reason),
|
||||
Some(network_approval_context.clone()),
|
||||
/*proposed_execpolicy_amendment*/ None,
|
||||
|
||||
@@ -530,7 +530,7 @@ async fn dispatch_after_tool_use_hook(
|
||||
.hooks()
|
||||
.dispatch(HookPayload {
|
||||
session_id: session.conversation_id,
|
||||
cwd: turn.cwd.clone(),
|
||||
cwd: turn.cwd.to_path_buf(),
|
||||
client: turn.app_server_client_name.clone(),
|
||||
triggered_at: chrono::Utc::now(),
|
||||
hook_event: HookEvent::AfterToolUse {
|
||||
|
||||
@@ -159,7 +159,7 @@ pub(super) async fn try_run_zsh_fork(
|
||||
network: sandbox_network,
|
||||
windows_sandbox_level,
|
||||
arg0,
|
||||
sandbox_policy_cwd: ctx.turn.cwd.clone(),
|
||||
sandbox_policy_cwd: ctx.turn.cwd.to_path_buf(),
|
||||
macos_seatbelt_profile_extensions: ctx
|
||||
.turn
|
||||
.config
|
||||
@@ -263,7 +263,7 @@ pub(crate) async fn prepare_unified_exec_zsh_fork(
|
||||
network: exec_request.network.clone(),
|
||||
windows_sandbox_level: exec_request.windows_sandbox_level,
|
||||
arg0: exec_request.arg0.clone(),
|
||||
sandbox_policy_cwd: ctx.turn.cwd.clone(),
|
||||
sandbox_policy_cwd: ctx.turn.cwd.to_path_buf(),
|
||||
macos_seatbelt_profile_extensions: ctx
|
||||
.turn
|
||||
.config
|
||||
|
||||
@@ -160,7 +160,7 @@ impl UnifiedExecProcessManager {
|
||||
let cwd = request
|
||||
.workdir
|
||||
.clone()
|
||||
.unwrap_or_else(|| context.turn.cwd.clone());
|
||||
.unwrap_or_else(|| context.turn.cwd.to_path_buf());
|
||||
let process = self
|
||||
.open_session_with_sandbox(&request, cwd.clone(), context)
|
||||
.await;
|
||||
|
||||
Reference in New Issue
Block a user