Use AbsolutePathBuf in skill loading and codex_home (#17407)

Helps with FS migration later
This commit is contained in:
pakrym-oai
2026-04-13 10:26:51 -07:00
committed by GitHub
parent d25a9822a7
commit ac82443d07
86 changed files with 850 additions and 625 deletions
+27 -30
View File
@@ -60,6 +60,8 @@ use crate::resume_picker::SessionSelection;
use crate::resume_picker::SessionTarget;
#[cfg(test)]
use crate::test_support::PathBufExt;
#[cfg(test)]
use crate::test_support::test_path_buf;
use crate::tui;
use crate::tui::TuiEvent;
use crate::update_action::UpdateAction;
@@ -1112,7 +1114,7 @@ impl App {
overrides.cwd = Some(cwd.clone());
let cwd_display = cwd.display().to_string();
ConfigBuilder::default()
.codex_home(self.config.codex_home.clone())
.codex_home(self.config.codex_home.to_path_buf())
.cli_overrides(self.cli_kv_overrides.clone())
.harness_overrides(overrides)
.build()
@@ -3867,13 +3869,7 @@ impl App {
let tx = app.app_event_tx.clone();
let logs_base_dir = app.config.codex_home.clone();
let sandbox_policy = app.config.permissions.sandbox_policy.get().clone();
Self::spawn_world_writable_scan(
cwd.to_path_buf(),
env_map,
logs_base_dir,
sandbox_policy,
tx,
);
Self::spawn_world_writable_scan(cwd, env_map, logs_base_dir, sandbox_policy, tx);
}
}
@@ -5231,7 +5227,7 @@ impl App {
let logs_base_dir = self.config.codex_home.clone();
let sandbox_policy = self.config.permissions.sandbox_policy.get().clone();
Self::spawn_world_writable_scan(
cwd.to_path_buf(),
cwd,
env_map,
logs_base_dir,
sandbox_policy,
@@ -5409,7 +5405,7 @@ impl App {
}
AppEvent::SetSkillEnabled { path, enabled } => {
let edits = [ConfigEdit::SetSkillConfig {
path: path.clone(),
path: path.to_path_buf(),
enabled,
}];
match ConfigEditsBuilder::new(&self.config.codex_home)
@@ -5418,7 +5414,7 @@ impl App {
.await
{
Ok(()) => {
self.chat_widget.update_skill_enabled(path.clone(), enabled);
self.chat_widget.update_skill_enabled(path, enabled);
if let Err(err) = self.refresh_in_memory_config_from_disk().await {
tracing::warn!(
error = %err,
@@ -6111,19 +6107,20 @@ impl App {
#[cfg(target_os = "windows")]
fn spawn_world_writable_scan(
cwd: PathBuf,
cwd: AbsolutePathBuf,
env_map: std::collections::HashMap<String, String>,
logs_base_dir: PathBuf,
logs_base_dir: AbsolutePathBuf,
sandbox_policy: codex_protocol::protocol::SandboxPolicy,
tx: AppEventSender,
) {
tokio::task::spawn_blocking(move || {
let logs_base_dir_path = logs_base_dir.as_path();
let result = codex_windows_sandbox::apply_world_writable_scan_and_denies(
&logs_base_dir,
&cwd,
logs_base_dir_path,
cwd.as_path(),
&env_map,
&sandbox_policy,
Some(logs_base_dir.as_path()),
Some(logs_base_dir_path),
);
if result.is_err() {
// Scan failed: warn without examples.
@@ -7905,7 +7902,7 @@ mod tests {
async fn update_feature_flags_enabling_guardian_selects_guardian_approvals() -> Result<()> {
let (mut app, mut app_event_rx, mut op_rx) = make_test_app_with_channels().await;
let codex_home = tempdir()?;
app.config.codex_home = codex_home.path().to_path_buf();
app.config.codex_home = codex_home.path().to_path_buf().abs();
let guardian_approvals = guardian_approvals_mode();
app.update_feature_flags(vec![(Feature::GuardianApproval, true)])
@@ -7989,7 +7986,7 @@ mod tests {
-> Result<()> {
let (mut app, mut app_event_rx, mut op_rx) = make_test_app_with_channels().await;
let codex_home = tempdir()?;
app.config.codex_home = codex_home.path().to_path_buf();
app.config.codex_home = codex_home.path().to_path_buf().abs();
let config_toml_path = codex_home.path().join("config.toml").abs();
let config_toml = "approvals_reviewer = \"guardian_subagent\"\napproval_policy = \"on-request\"\nsandbox_mode = \"workspace-write\"\n\n[features]\nguardian_approval = true\n";
std::fs::write(config_toml_path.as_path(), config_toml)?;
@@ -8080,7 +8077,7 @@ mod tests {
-> Result<()> {
let (mut app, _app_event_rx, mut op_rx) = make_test_app_with_channels().await;
let codex_home = tempdir()?;
app.config.codex_home = codex_home.path().to_path_buf();
app.config.codex_home = codex_home.path().to_path_buf().abs();
let guardian_approvals = guardian_approvals_mode();
let config_toml_path = codex_home.path().join("config.toml").abs();
let config_toml = "approvals_reviewer = \"user\"\n";
@@ -8148,7 +8145,7 @@ mod tests {
-> Result<()> {
let (mut app, mut app_event_rx, mut op_rx) = make_test_app_with_channels().await;
let codex_home = tempdir()?;
app.config.codex_home = codex_home.path().to_path_buf();
app.config.codex_home = codex_home.path().to_path_buf().abs();
let config_toml_path = codex_home.path().join("config.toml").abs();
let config_toml = "approvals_reviewer = \"user\"\napproval_policy = \"on-request\"\nsandbox_mode = \"workspace-write\"\n\n[features]\nguardian_approval = true\n";
std::fs::write(config_toml_path.as_path(), config_toml)?;
@@ -8207,7 +8204,7 @@ mod tests {
-> Result<()> {
let (mut app, _app_event_rx, mut op_rx) = make_test_app_with_channels().await;
let codex_home = tempdir()?;
app.config.codex_home = codex_home.path().to_path_buf();
app.config.codex_home = codex_home.path().to_path_buf().abs();
let guardian_approvals = guardian_approvals_mode();
app.active_profile = Some("guardian".to_string());
let config_toml_path = codex_home.path().join("config.toml").abs();
@@ -8278,7 +8275,7 @@ mod tests {
-> Result<()> {
let (mut app, mut app_event_rx, mut op_rx) = make_test_app_with_channels().await;
let codex_home = tempdir()?;
app.config.codex_home = codex_home.path().to_path_buf();
app.config.codex_home = codex_home.path().to_path_buf().abs();
app.active_profile = Some("guardian".to_string());
let config_toml_path = codex_home.path().join("config.toml").abs();
let config_toml = r#"
@@ -8366,7 +8363,7 @@ guardian_approval = true
-> Result<()> {
let (mut app, mut app_event_rx, mut op_rx) = make_test_app_with_channels().await;
let codex_home = tempdir()?;
app.config.codex_home = codex_home.path().to_path_buf();
app.config.codex_home = codex_home.path().to_path_buf().abs();
app.active_profile = Some("guardian".to_string());
let config_toml_path = codex_home.path().join("config.toml").abs();
let config_toml = "profile = \"guardian\"\napprovals_reviewer = \"guardian_subagent\"\n\n[features]\nguardian_approval = true\n";
@@ -9083,7 +9080,7 @@ guardian_approval = true
async fn render_clear_ui_header_after_long_transcript_for_snapshot() -> String {
let mut app = make_test_app().await;
app.config.cwd = PathBuf::from("/tmp/project").abs();
app.config.cwd = test_path_buf("/tmp/project").abs();
app.chat_widget.set_model("gpt-test");
app.chat_widget
.set_reasoning_effort(Some(ReasoningEffortConfig::High));
@@ -9136,7 +9133,7 @@ guardian_approval = true
approval_policy: AskForApproval::Never,
approvals_reviewer: ApprovalsReviewer::User,
sandbox_policy: SandboxPolicy::new_read_only_policy(),
cwd: PathBuf::from("/tmp/project").abs().to_path_buf(),
cwd: test_path_buf("/tmp/project"),
reasoning_effort: Some(ReasoningEffortConfig::High),
history_log_id: 0,
history_entry_count: 0,
@@ -9220,7 +9217,7 @@ guardian_approval = true
)]
async fn clear_ui_header_shows_fast_status_for_fast_capable_models() {
let mut app = make_test_app().await;
app.config.cwd = PathBuf::from("/tmp/project").abs();
app.config.cwd = test_path_buf("/tmp/project").abs();
app.chat_widget.set_model("gpt-5.4");
set_fast_mode_test_catalog(&mut app.chat_widget);
app.chat_widget
@@ -10229,7 +10226,7 @@ guardian_approval = true
async fn refresh_in_memory_config_from_disk_loads_latest_apps_state() -> Result<()> {
let mut app = make_test_app().await;
let codex_home = tempdir()?;
app.config.codex_home = codex_home.path().to_path_buf();
app.config.codex_home = codex_home.path().to_path_buf().abs();
let app_id = "unit_test_refresh_in_memory_config_connector".to_string();
assert_eq!(app_enabled_in_effective_config(&app.config, &app_id), None);
@@ -10269,7 +10266,7 @@ guardian_approval = true
-> Result<()> {
let mut app = make_test_app().await;
let codex_home = tempdir()?;
app.config.codex_home = codex_home.path().to_path_buf();
app.config.codex_home = codex_home.path().to_path_buf().abs();
std::fs::write(codex_home.path().join("config.toml"), "[broken")?;
let original_config = app.config.clone();
@@ -10323,7 +10320,7 @@ guardian_approval = true
-> Result<()> {
let mut app = make_test_app().await;
let codex_home = tempdir()?;
app.config.codex_home = codex_home.path().to_path_buf();
app.config.codex_home = codex_home.path().to_path_buf().abs();
std::fs::write(codex_home.path().join("config.toml"), "[broken")?;
let current_config = app.config.clone();
let current_cwd = current_config.cwd.clone();
@@ -10340,7 +10337,7 @@ guardian_approval = true
async fn rebuild_config_for_resume_or_fallback_errors_when_cwd_changes() -> Result<()> {
let mut app = make_test_app().await;
let codex_home = tempdir()?;
app.config.codex_home = codex_home.path().to_path_buf();
app.config.codex_home = codex_home.path().to_path_buf().abs();
std::fs::write(codex_home.path().join("config.toml"), "[broken")?;
let current_cwd = app.config.cwd.clone();
let next_cwd_tmp = tempdir()?;
+1 -1
View File
@@ -502,7 +502,7 @@ pub(crate) enum AppEvent {
/// Enable or disable a skill by path.
SetSkillEnabled {
path: PathBuf,
path: AbsolutePathBuf,
enabled: bool,
},
@@ -4008,6 +4008,8 @@ impl ChatComposer {
#[cfg(test)]
mod tests {
use super::*;
use crate::test_support::PathBufExt;
use crate::test_support::test_path_buf;
use image::ImageBuffer;
use image::Rgba;
use pretty_assertions::assert_eq;
@@ -5053,6 +5055,7 @@ mod tests {
#[test]
fn mention_items_show_plugin_owned_skill_and_app_duplicates() {
let skill_path = test_path_buf("/tmp/repo/google-calendar/SKILL.md").abs();
let (tx, _rx) = unbounded_channel::<AppEvent>();
let sender = AppEventSender::new(tx);
let mut composer = ChatComposer::new(
@@ -5078,7 +5081,7 @@ mod tests {
}),
dependencies: None,
policy: None,
path_to_skills_md: PathBuf::from("/tmp/repo/google-calendar/SKILL.md"),
path_to_skills_md: skill_path.clone(),
scope: codex_protocol::protocol::SkillScope::Repo,
}]));
composer.set_plugin_mentions(Some(vec![PluginCapabilitySummary {
@@ -5115,10 +5118,7 @@ mod tests {
let mentions = composer.mention_items();
assert_eq!(mentions.len(), 3);
assert_eq!(mentions[0].category_tag, Some("[Skill]".to_string()));
assert_eq!(
mentions[0].path,
Some("/tmp/repo/google-calendar/SKILL.md".to_string())
);
assert_eq!(mentions[0].path, Some(skill_path.display().to_string()));
assert_eq!(mentions[0].display_name, "Google Calendar".to_string());
assert_eq!(mentions[1].category_tag, Some("[Plugin]".to_string()));
assert_eq!(
@@ -5176,7 +5176,7 @@ mod tests {
}),
dependencies: None,
policy: None,
path_to_skills_md: PathBuf::from("/tmp/repo/google-calendar/SKILL.md"),
path_to_skills_md: test_path_buf("/tmp/repo/google-calendar/SKILL.md").abs(),
scope: codex_protocol::protocol::SkillScope::Repo,
}]));
composer.set_plugin_mentions(Some(vec![PluginCapabilitySummary {
+3 -2
View File
@@ -1242,6 +1242,8 @@ mod tests {
use crate::app_event::AppEvent;
use crate::status_indicator_widget::STATUS_DETAILS_DEFAULT_MAX_LINES;
use crate::status_indicator_widget::StatusDetailsCapitalization;
use crate::test_support::PathBufExt;
use crate::test_support::test_path_buf;
use codex_protocol::protocol::Op;
use codex_protocol::protocol::SkillScope;
use crossterm::event::KeyEventKind;
@@ -1250,7 +1252,6 @@ mod tests {
use ratatui::buffer::Buffer;
use ratatui::layout::Rect;
use std::cell::Cell;
use std::path::PathBuf;
use std::rc::Rc;
use tokio::sync::mpsc::unbounded_channel;
@@ -1719,7 +1720,7 @@ mod tests {
interface: None,
dependencies: None,
policy: None,
path_to_skills_md: PathBuf::from("test-skill"),
path_to_skills_md: test_path_buf("/tmp/test-skill/SKILL.md").abs(),
scope: SkillScope::User,
}]),
});
@@ -1,5 +1,4 @@
use std::path::PathBuf;
use codex_utils_absolute_path::AbsolutePathBuf;
use crossterm::event::KeyCode;
use crossterm::event::KeyEvent;
use crossterm::event::KeyModifiers;
@@ -38,7 +37,7 @@ pub(crate) struct SkillsToggleItem {
pub skill_name: String,
pub description: String,
pub enabled: bool,
pub path: PathBuf,
pub path: AbsolutePathBuf,
}
pub(crate) struct SkillsToggleView {
@@ -381,6 +380,8 @@ fn skills_toggle_hint_line() -> Line<'static> {
mod tests {
use super::*;
use crate::app_event::AppEvent;
use crate::test_support::PathBufExt;
use crate::test_support::test_path_buf;
use insta::assert_snapshot;
use ratatui::layout::Rect;
use tokio::sync::mpsc::unbounded_channel;
@@ -418,14 +419,14 @@ mod tests {
skill_name: "repo_scout".to_string(),
description: "Summarize the repo layout".to_string(),
enabled: true,
path: PathBuf::from("/tmp/skills/repo_scout.toml"),
path: test_path_buf("/tmp/skills/repo_scout.toml").abs(),
},
SkillsToggleItem {
name: "Changelog Writer".to_string(),
skill_name: "changelog_writer".to_string(),
description: "Draft release notes".to_string(),
enabled: false,
path: PathBuf::from("/tmp/skills/changelog_writer.toml"),
path: test_path_buf("/tmp/skills/changelog_writer.toml").abs(),
},
];
let view = SkillsToggleView::new(items, tx);
+5 -5
View File
@@ -801,7 +801,7 @@ pub(crate) struct ChatWidget {
pending_collab_spawn_requests: HashMap<String, multi_agents::SpawnRequestSummary>,
suppressed_exec_calls: HashSet<String>,
skills_all: Vec<ProtocolSkillMetadata>,
skills_initial_state: Option<HashMap<PathBuf, bool>>,
skills_initial_state: Option<HashMap<AbsolutePathBuf, bool>>,
last_unified_wait: Option<UnifiedExecWaitState>,
unified_exec_wait_streak: Option<UnifiedExecWaitStreak>,
turn_sleep_inhibitor: SleepInhibitor,
@@ -5353,7 +5353,7 @@ impl ChatWidget {
.map(|binding| binding.mention.clone())
.collect();
let mut skill_names_lower: HashSet<String> = HashSet::new();
let mut selected_skill_paths: HashSet<PathBuf> = HashSet::new();
let mut selected_skill_paths: HashSet<AbsolutePathBuf> = HashSet::new();
let mut selected_plugin_ids: HashSet<String> = HashSet::new();
if let Some(skills) = self.bottom_pane.skills() {
@@ -5375,7 +5375,7 @@ impl ChatWidget {
{
items.push(UserInput::Skill {
name: skill.name.clone(),
path: skill.path_to_skills_md.clone(),
path: skill.path_to_skills_md.to_path_buf(),
});
}
}
@@ -5389,7 +5389,7 @@ impl ChatWidget {
}
items.push(UserInput::Skill {
name: skill.name.clone(),
path: skill.path_to_skills_md.clone(),
path: skill.path_to_skills_md.to_path_buf(),
});
}
}
@@ -10341,7 +10341,7 @@ impl ChatWidget {
return;
}
let plugins = PluginsManager::new(self.config.codex_home.clone())
let plugins = PluginsManager::new(self.config.codex_home.to_path_buf())
.plugins_for_config(&self.config)
.capability_summaries()
.to_vec();
+15 -14
View File
@@ -1,7 +1,5 @@
use std::collections::HashMap;
use std::collections::HashSet;
use std::path::Path;
use std::path::PathBuf;
use super::ChatWidget;
use crate::app_event::AppEvent;
@@ -23,6 +21,7 @@ use codex_protocol::parse_command::ParsedCommand;
use codex_protocol::protocol::ListSkillsResponseEvent;
use codex_protocol::protocol::SkillMetadata as ProtocolSkillMetadata;
use codex_protocol::protocol::SkillsListEntry;
use codex_utils_absolute_path::AbsolutePathBuf;
impl ChatWidget {
pub(crate) fn open_skills_list(&mut self) {
@@ -68,7 +67,7 @@ impl ChatWidget {
let mut initial_state = HashMap::new();
for skill in &self.skills_all {
initial_state.insert(normalize_skill_config_path(&skill.path), skill.enabled);
initial_state.insert(skill.path.clone(), skill.enabled);
}
self.skills_initial_state = Some(initial_state);
@@ -95,10 +94,9 @@ impl ChatWidget {
self.bottom_pane.show_view(Box::new(view));
}
pub(crate) fn update_skill_enabled(&mut self, path: PathBuf, enabled: bool) {
let target = normalize_skill_config_path(&path);
pub(crate) fn update_skill_enabled(&mut self, path: AbsolutePathBuf, enabled: bool) {
for skill in &mut self.skills_all {
if normalize_skill_config_path(&skill.path) == target {
if skill.path == path {
skill.enabled = enabled;
}
}
@@ -111,7 +109,7 @@ impl ChatWidget {
};
let mut current_state = HashMap::new();
for skill in &self.skills_all {
current_state.insert(normalize_skill_config_path(&skill.path), skill.enabled);
current_state.insert(skill.path.clone(), skill.enabled);
}
let mut enabled_count = 0;
@@ -161,7 +159,11 @@ impl ChatWidget {
}
// Best effort only: annotate exact SKILL.md path matches from the loaded skills list.
if let Some(skill) = self.skills_all.iter().find(|skill| skill.path == *path) {
if let Some(skill) = self
.skills_all
.iter()
.find(|skill| skill.path.as_path() == path)
{
*name = format!("{name} ({} skill)", skill.name);
}
}
@@ -170,10 +172,13 @@ impl ChatWidget {
}
}
fn skills_for_cwd(cwd: &Path, skills_entries: &[SkillsListEntry]) -> Vec<ProtocolSkillMetadata> {
fn skills_for_cwd(
cwd: &AbsolutePathBuf,
skills_entries: &[SkillsListEntry],
) -> Vec<ProtocolSkillMetadata> {
skills_entries
.iter()
.find(|entry| entry.cwd.as_path() == cwd)
.find(|entry| entry.cwd.as_path() == cwd.as_path())
.map(|entry| entry.skills.clone())
.unwrap_or_default()
}
@@ -222,10 +227,6 @@ fn protocol_skill_to_core(skill: &ProtocolSkillMetadata) -> SkillMetadata {
}
}
fn normalize_skill_config_path(path: &Path) -> PathBuf {
dunce::canonicalize(path).unwrap_or_else(|_| path.to_path_buf())
}
pub(crate) fn collect_tool_mentions(
text: &str,
mention_paths: &HashMap<String, String>,
+1
View File
@@ -29,6 +29,7 @@ pub(super) use crate::legacy_core::skills::model::SkillMetadata;
pub(super) use crate::model_catalog::ModelCatalog;
pub(super) use crate::test_backend::VT100Backend;
pub(super) use crate::test_support::PathBufExt;
pub(super) use crate::test_support::test_path_buf;
pub(super) use crate::test_support::test_path_display;
pub(super) use crate::tui::FrameRequester;
pub(super) use assert_matches::assert_matches;
@@ -398,8 +398,8 @@ async fn submission_prefers_selected_duplicate_skill_path() {
});
drain_insert_history(&mut rx);
let repo_skill_path = PathBuf::from("/tmp/repo/figma/SKILL.md");
let user_skill_path = PathBuf::from("/tmp/user/figma/SKILL.md");
let repo_skill_path = test_path_buf("/tmp/repo/figma/SKILL.md").abs();
let user_skill_path = test_path_buf("/tmp/user/figma/SKILL.md").abs();
chat.set_skills(Some(vec![
SkillMetadata {
name: "figma".to_string(),
@@ -445,7 +445,7 @@ async fn submission_prefers_selected_duplicate_skill_path() {
_ => None,
})
.collect::<Vec<_>>();
assert_eq!(selected_skill_paths, vec![user_skill_path]);
assert_eq!(selected_skill_paths, vec![user_skill_path.to_path_buf()]);
}
#[tokio::test]
+2 -2
View File
@@ -11,7 +11,7 @@ pub(super) async fn test_config() -> Config {
let mut config =
Config::load_default_with_cli_overrides_for_codex_home(codex_home.clone(), Vec::new())
.expect("config");
config.codex_home = codex_home.clone();
config.codex_home = codex_home.abs();
config.sqlite_home = codex_home.clone();
config.log_dir = codex_home.join("log");
config.cwd = PathBuf::from(test_path_display("/tmp/project")).abs();
@@ -951,7 +951,7 @@ pub(super) fn plugins_test_detail(
description: format!("{name} description"),
short_description: None,
interface: None,
path: PathBuf::from(format!("/skills/{name}/SKILL.md")),
path: plugins_test_absolute_path(&format!("skills/{name}/SKILL.md")),
enabled: true,
})
.collect(),
@@ -245,10 +245,10 @@ async fn session_configured_syncs_widget_config_permissions_and_cwd() {
.sandbox_policy
.set(SandboxPolicy::new_workspace_write_policy())
.expect("set sandbox policy");
chat.config.cwd = PathBuf::from("/home/user/main").abs();
chat.config.cwd = test_path_buf("/home/user/main").abs();
let expected_sandbox = SandboxPolicy::new_read_only_policy();
let expected_cwd = PathBuf::from("/home/user/sub-agent").abs();
let expected_cwd = test_path_buf("/home/user/sub-agent").abs();
let configured = codex_protocol::protocol::SessionConfiguredEvent {
session_id: ThreadId::new(),
forked_from_id: None,
@@ -392,7 +392,9 @@ async fn forked_thread_history_line_includes_name_and_id_snapshot() {
let (chat, mut rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await;
let mut chat = chat;
let temp = tempdir().expect("tempdir");
chat.config.codex_home = temp.path().to_path_buf();
chat.config.codex_home =
codex_utils_absolute_path::AbsolutePathBuf::from_absolute_path(temp.path())
.expect("temp dir is absolute");
let forked_from_id =
ThreadId::from_string("e9f18a88-8081-4e51-9d4e-8af5cde2d8dd").expect("forked id");
@@ -429,7 +431,9 @@ async fn forked_thread_history_line_without_name_shows_id_once_snapshot() {
let (chat, mut rx, _op_rx) = make_chatwidget_manual(/*model_override*/ None).await;
let mut chat = chat;
let temp = tempdir().expect("tempdir");
chat.config.codex_home = temp.path().to_path_buf();
chat.config.codex_home =
codex_utils_absolute_path::AbsolutePathBuf::from_absolute_path(temp.path())
.expect("temp dir is absolute");
let forked_from_id =
ThreadId::from_string("019c2d47-4935-7423-a190-05691f566092").expect("forked id");
@@ -51,8 +51,9 @@ async fn preset_matching_accepts_workspace_write_with_extra_roots() {
.into_iter()
.find(|p| p.id == "auto")
.expect("auto preset exists");
let extra_root = test_path_buf("/tmp/extra").abs();
let current_sandbox = SandboxPolicy::WorkspaceWrite {
writable_roots: vec![PathBuf::from("C:\\extra").abs()],
writable_roots: vec![extra_root],
read_only_access: Default::default(),
network_access: false,
exclude_tmpdir_env_var: false,
@@ -496,7 +497,7 @@ async fn permissions_selection_marks_guardian_approvals_current_with_custom_work
.features
.set_enabled(Feature::GuardianApproval, /*enabled*/ true);
let extra_root = PathBuf::from("/tmp/guardian-approvals-extra").abs();
let extra_root = test_path_buf("/tmp/guardian-approvals-extra").abs();
chat.handle_codex_event(Event {
id: "session-configured-custom-workspace".to_string(),
+7 -3
View File
@@ -35,6 +35,8 @@ use crate::style::proposed_plan_style;
use crate::style::user_message_style;
#[cfg(test)]
use crate::test_support::PathBufExt;
#[cfg(test)]
use crate::test_support::test_path_buf;
use crate::text_formatting::format_and_truncate_tool_result;
use crate::text_formatting::truncate_text;
use crate::tooltips;
@@ -1843,7 +1845,9 @@ pub(crate) fn new_mcp_tools_output(
lines.push("".into());
}
let mcp_manager = McpManager::new(Arc::new(PluginsManager::new(config.codex_home.clone())));
let mcp_manager = McpManager::new(Arc::new(PluginsManager::new(
config.codex_home.to_path_buf(),
)));
let effective_servers = mcp_manager.effective_servers(config, /*auth*/ None);
let mut servers: Vec<_> = effective_servers.iter().collect();
servers.sort_by(|(a, _), (b, _)| a.cmp(b));
@@ -2988,7 +2992,7 @@ mod tests {
approval_policy: AskForApproval::Never,
approvals_reviewer: codex_protocol::config_types::ApprovalsReviewer::User,
sandbox_policy: SandboxPolicy::new_read_only_policy(),
cwd: PathBuf::from("/tmp/project").abs().to_path_buf(),
cwd: test_path_buf("/tmp/project"),
reasoning_effort: None,
history_log_id: 0,
history_entry_count: 0,
@@ -3108,7 +3112,7 @@ mod tests {
)]
async fn session_info_availability_nux_tooltip_snapshot() {
let mut config = test_config().await;
config.cwd = PathBuf::from("/tmp/project").abs();
config.cwd = test_path_buf("/tmp/project").abs();
let cell = new_session_info(
&config,
"gpt-5",
+5 -5
View File
@@ -870,7 +870,7 @@ pub async fn run_main(
if matches!(app_server_target, AppServerTarget::Embedded) {
#[allow(clippy::print_stderr)]
if let Err(err) = enforce_login_restrictions(&AuthConfig {
codex_home: config.codex_home.clone(),
codex_home: config.codex_home.to_path_buf(),
auth_credentials_store_mode: config.cli_auth_credentials_store_mode,
forced_login_method: config.forced_login_method,
forced_chatgpt_workspace_id: config.forced_chatgpt_workspace_id.clone(),
@@ -1137,7 +1137,7 @@ async fn run_ratatui_app(
// status detection edge cases.
if show_login_screen && !remote_mode {
cloud_requirements = cloud_requirements_loader_for_storage(
initial_config.codex_home.clone(),
initial_config.codex_home.to_path_buf(),
/*enable_codex_api_key_env*/ false,
initial_config.cli_auth_credentials_store_mode,
initial_config.chatgpt_base_url.clone(),
@@ -1378,7 +1378,7 @@ async fn run_ratatui_app(
// this must happen after the last possible reload.
if let Some(w) = crate::render::highlight::set_theme_override(
config.tui_theme.clone(),
find_codex_home().ok(),
find_codex_home().ok().map(AbsolutePathBuf::into_path_buf),
) {
config.startup_warnings.push(w);
}
@@ -2052,7 +2052,7 @@ mod tests {
std::fs::write(&rollout_path, "")?;
let state_runtime = codex_state::StateRuntime::init(
config.codex_home.clone(),
config.codex_home.to_path_buf(),
config.model_provider_id.clone(),
)
.await
@@ -2481,7 +2481,7 @@ trust_level = "untrusted"
)?;
let runtime = codex_state::StateRuntime::init(
config.codex_home.clone(),
config.codex_home.to_path_buf(),
config.model_provider_id.clone(),
)
.await
@@ -86,7 +86,7 @@ impl OnboardingScreen {
config,
} = args;
let cwd = config.cwd.to_path_buf();
let codex_home = config.codex_home.clone();
let codex_home = config.codex_home.to_path_buf();
let forced_login_method = config.forced_login_method;
let mut steps: Vec<Step> = Vec::new();
steps.push(Step::Welcome(WelcomeWidget::new(
+14 -14
View File
@@ -6,6 +6,7 @@ use crate::legacy_core::config::Config;
use crate::legacy_core::config::ConfigBuilder;
use crate::status::StatusAccountDisplay;
use crate::test_support::PathBufExt;
use crate::test_support::test_path_buf;
use chrono::Duration as ChronoDuration;
use chrono::TimeZone;
use chrono::Utc;
@@ -22,7 +23,6 @@ use codex_protocol::protocol::TokenUsageInfo;
use insta::assert_snapshot;
use pretty_assertions::assert_eq;
use ratatui::prelude::*;
use std::path::PathBuf;
use tempfile::TempDir;
async fn test_config(temp_home: &TempDir) -> Config {
@@ -108,7 +108,7 @@ async fn status_snapshot_includes_reasoning_details() {
})
.expect("set sandbox policy");
config.cwd = PathBuf::from("/workspace/tests").abs();
config.cwd = test_path_buf("/workspace/tests").abs();
let account_display = test_status_account_display();
let usage = TokenUsage {
@@ -192,7 +192,7 @@ async fn status_permissions_non_default_workspace_write_is_custom() {
exclude_slash_tmp: false,
})
.expect("set sandbox policy");
config.cwd = PathBuf::from("/workspace/tests").abs();
config.cwd = test_path_buf("/workspace/tests").abs();
let account_display = test_status_account_display();
let usage = TokenUsage::default();
@@ -241,7 +241,7 @@ async fn status_snapshot_includes_forked_from() {
let mut config = test_config(&temp_home).await;
config.model = Some("gpt-5.1-codex-max".to_string());
config.model_provider_id = "openai".to_string();
config.cwd = PathBuf::from("/workspace/tests").abs();
config.cwd = test_path_buf("/workspace/tests").abs();
let account_display = test_status_account_display();
let usage = TokenUsage {
@@ -295,7 +295,7 @@ async fn status_snapshot_includes_monthly_limit() {
let mut config = test_config(&temp_home).await;
config.model = Some("gpt-5.1-codex-max".to_string());
config.model_provider_id = "openai".to_string();
config.cwd = PathBuf::from("/workspace/tests").abs();
config.cwd = test_path_buf("/workspace/tests").abs();
let account_display = test_status_account_display();
let usage = TokenUsage {
@@ -548,7 +548,7 @@ async fn status_card_token_usage_excludes_cached_tokens() {
let temp_home = TempDir::new().expect("temp home");
let mut config = test_config(&temp_home).await;
config.model = Some("gpt-5.1-codex-max".to_string());
config.cwd = PathBuf::from("/workspace/tests").abs();
config.cwd = test_path_buf("/workspace/tests").abs();
let account_display = test_status_account_display();
let usage = TokenUsage {
@@ -596,7 +596,7 @@ async fn status_snapshot_truncates_in_narrow_terminal() {
config.model = Some("gpt-5.1-codex-max".to_string());
config.model_provider_id = "openai".to_string();
config.model_reasoning_summary = Some(ReasoningSummary::Detailed);
config.cwd = PathBuf::from("/workspace/tests").abs();
config.cwd = test_path_buf("/workspace/tests").abs();
let account_display = test_status_account_display();
let usage = TokenUsage {
@@ -659,7 +659,7 @@ async fn status_snapshot_shows_missing_limits_message() {
let temp_home = TempDir::new().expect("temp home");
let mut config = test_config(&temp_home).await;
config.model = Some("gpt-5.1-codex-max".to_string());
config.cwd = PathBuf::from("/workspace/tests").abs();
config.cwd = test_path_buf("/workspace/tests").abs();
let account_display = test_status_account_display();
let usage = TokenUsage {
@@ -707,7 +707,7 @@ async fn status_snapshot_shows_refreshing_limits_notice() {
let temp_home = TempDir::new().expect("temp home");
let mut config = test_config(&temp_home).await;
config.model = Some("gpt-5.1-codex-max".to_string());
config.cwd = PathBuf::from("/workspace/tests").abs();
config.cwd = test_path_buf("/workspace/tests").abs();
let usage = TokenUsage {
input_tokens: 500,
@@ -771,7 +771,7 @@ async fn status_snapshot_includes_credits_and_limits() {
let temp_home = TempDir::new().expect("temp home");
let mut config = test_config(&temp_home).await;
config.model = Some("gpt-5.1-codex".to_string());
config.cwd = PathBuf::from("/workspace/tests").abs();
config.cwd = test_path_buf("/workspace/tests").abs();
let account_display = test_status_account_display();
let usage = TokenUsage {
@@ -840,7 +840,7 @@ async fn status_snapshot_shows_unavailable_limits_message() {
let temp_home = TempDir::new().expect("temp home");
let mut config = test_config(&temp_home).await;
config.model = Some("gpt-5.1-codex-max".to_string());
config.cwd = PathBuf::from("/workspace/tests").abs();
config.cwd = test_path_buf("/workspace/tests").abs();
let account_display = test_status_account_display();
let usage = TokenUsage {
@@ -897,7 +897,7 @@ async fn status_snapshot_treats_refreshing_empty_limits_as_unavailable() {
let temp_home = TempDir::new().expect("temp home");
let mut config = test_config(&temp_home).await;
config.model = Some("gpt-5.1-codex-max".to_string());
config.cwd = PathBuf::from("/workspace/tests").abs();
config.cwd = test_path_buf("/workspace/tests").abs();
let usage = TokenUsage {
input_tokens: 500,
@@ -954,7 +954,7 @@ async fn status_snapshot_shows_stale_limits_message() {
let temp_home = TempDir::new().expect("temp home");
let mut config = test_config(&temp_home).await;
config.model = Some("gpt-5.1-codex-max".to_string());
config.cwd = PathBuf::from("/workspace/tests").abs();
config.cwd = test_path_buf("/workspace/tests").abs();
let account_display = test_status_account_display();
let usage = TokenUsage {
@@ -1020,7 +1020,7 @@ async fn status_snapshot_cached_limits_hide_credits_without_flag() {
let temp_home = TempDir::new().expect("temp home");
let mut config = test_config(&temp_home).await;
config.model = Some("gpt-5.1-codex".to_string());
config.cwd = PathBuf::from("/workspace/tests").abs();
config.cwd = test_path_buf("/workspace/tests").abs();
let account_display = test_status_account_display();
let usage = TokenUsage {
+2 -3
View File
@@ -1,7 +1,6 @@
pub(crate) use codex_utils_absolute_path::test_support::PathBufExt;
pub(crate) use codex_utils_absolute_path::test_support::PathExt;
use std::path::Path;
pub(crate) use codex_utils_absolute_path::test_support::test_path_buf;
pub(crate) fn test_path_display(path: &str) -> String {
Path::new(path).abs().display().to_string()
test_path_buf(path).display().to_string()
}