From 4f7105a806308bc812b2831d622c5ecd38251639 Mon Sep 17 00:00:00 2001 From: bc19sam-afk Date: Sun, 12 Jul 2026 00:01:10 +1000 Subject: [PATCH] fix: use native marketplace paths outside Windows --- .../codex-plus-core/src/plugin_marketplace.rs | 123 +++++++++++++----- 1 file changed, 90 insertions(+), 33 deletions(-) diff --git a/crates/codex-plus-core/src/plugin_marketplace.rs b/crates/codex-plus-core/src/plugin_marketplace.rs index 0840a7388..46079c9ef 100644 --- a/crates/codex-plus-core/src/plugin_marketplace.rs +++ b/crates/codex-plus-core/src/plugin_marketplace.rs @@ -662,7 +662,7 @@ fn merge_marketplace_configs_and_plugins_into_text( } marketplaces[marketplace_name]["source_type"] = toml_edit::value("local"); marketplaces[marketplace_name]["source"] = - toml_edit::value(windows_extended_path(marketplace_root)); + toml_edit::value(local_marketplace_path(marketplace_root)); } if !plugin_ids.is_empty() { let plugins = table_mut_or_insert(&mut doc, "plugins")?; @@ -706,19 +706,33 @@ fn marketplace_config_points_to_root(home: &Path, marketplace_name: &str, root: .get("source") .and_then(Item::as_str) .unwrap_or_default(); - source_type == "local" && normalize_windows_extended_path(source) == root.to_string_lossy() + source_type == "local" && normalize_local_marketplace_path(source) == root.to_string_lossy() } -fn normalize_windows_extended_path(value: &str) -> String { - value.strip_prefix(r"\\?\").unwrap_or(value).to_string() +fn normalize_local_marketplace_path(value: &str) -> String { + #[cfg(windows)] + { + value.strip_prefix(r"\\?\").unwrap_or(value).to_string() + } + #[cfg(not(windows))] + { + value.to_string() + } } -fn windows_extended_path(path: &Path) -> String { - let value = path.to_string_lossy(); - if value.starts_with(r"\\?\") { - value.into_owned() - } else { - format!(r"\\?\{value}") +fn local_marketplace_path(path: &Path) -> String { + #[cfg(windows)] + { + let value = path.to_string_lossy(); + if value.starts_with(r"\\?\") { + value.into_owned() + } else { + format!(r"\\?\{value}") + } + } + #[cfg(not(windows))] + { + path.to_string_lossy().into_owned() } } @@ -756,6 +770,14 @@ fn ensure_trailing_newline(mut contents: String) -> String { mod tests { use super::*; + fn expected_local_marketplace_path(path: &Path) -> String { + if cfg!(windows) { + format!(r"\\?\{}", path.display()) + } else { + path.to_string_lossy().into_owned() + } + } + fn write_marketplace(home: &Path) { let root = home.join(".tmp").join("plugins"); std::fs::create_dir_all(root.join(".agents").join("plugins")).unwrap(); @@ -822,9 +844,11 @@ mod tests { parsed["marketplaces"]["openai-curated"]["source_type"].as_str(), Some("local") ); + let local_marketplace_source = + expected_local_marketplace_path(&home.join(".tmp").join("plugins")); assert_eq!( parsed["marketplaces"]["openai-curated"]["source"].as_str(), - Some(format!(r"\\?\{}", home.join(".tmp").join("plugins").display()).as_str()) + Some(local_marketplace_source.as_str()) ); assert_eq!( parsed["marketplaces"]["openai-api-curated"]["source_type"].as_str(), @@ -832,21 +856,63 @@ mod tests { ); assert_eq!( parsed["marketplaces"]["openai-api-curated"]["source"].as_str(), - Some(format!(r"\\?\{}", home.join(".tmp").join("plugins").display()).as_str()) + Some(local_marketplace_source.as_str()) ); assert_eq!( parsed["marketplaces"]["openai-curated-remote"]["source_type"].as_str(), Some("local") ); + let remote_marketplace_source = + expected_local_marketplace_path(&home.join(".tmp").join("plugins-remote")); assert_eq!( parsed["marketplaces"]["openai-curated-remote"]["source"].as_str(), - Some( - format!( - r"\\?\{}", - home.join(".tmp").join("plugins-remote").display() - ) - .as_str() - ) + Some(remote_marketplace_source.as_str()) + ); + } + + #[cfg(not(windows))] + #[test] + fn ensure_openai_curated_marketplace_config_repairs_windows_prefix_on_unix() { + let temp = tempfile::tempdir().unwrap(); + let home = temp.path(); + write_marketplace(home); + write_remote_marketplace(home); + let local_root = home.join(".tmp").join("plugins"); + let remote_root = home.join(".tmp").join("plugins-remote"); + std::fs::write( + home.join("config.toml"), + format!( + r#"[marketplaces.openai-curated] +source_type = "local" +source = '\\?\{}' + +[marketplaces.openai-api-curated] +source_type = "local" +source = '\\?\{}' + +[marketplaces.openai-curated-remote] +source_type = "local" +source = '\\?\{}' +"#, + local_root.display(), + local_root.display(), + remote_root.display() + ), + ) + .unwrap(); + + let changed = ensure_openai_curated_marketplace_config(home).unwrap(); + + assert!(changed); + let config = std::fs::read_to_string(home.join("config.toml")).unwrap(); + let parsed = config.parse::().unwrap(); + assert_eq!( + parsed["marketplaces"]["openai-curated"]["source"].as_str(), + Some(local_root.to_string_lossy().as_ref()) + ); + assert_eq!( + parsed["marketplaces"]["openai-curated-remote"]["source"].as_str(), + Some(remote_root.to_string_lossy().as_ref()) ); } @@ -883,12 +949,11 @@ mod tests { assert_eq!( parsed["marketplaces"]["role-specific-plugins"]["source"].as_str(), Some( - format!( - r"\\?\{}", - home.join(".tmp") + expected_local_marketplace_path( + &home + .join(".tmp") .join("marketplaces") .join("role-specific-plugins") - .display() ) .as_str() ) @@ -1003,11 +1068,7 @@ mod tests { assert_eq!( parsed["marketplaces"]["openai-curated-remote"]["source"].as_str(), Some( - format!( - r"\\?\{}", - home.join(".tmp").join("plugins-remote").display() - ) - .as_str() + expected_local_marketplace_path(&home.join(".tmp").join("plugins-remote")).as_str() ) ); } @@ -1044,11 +1105,7 @@ mod tests { assert_eq!( parsed["marketplaces"]["openai-curated-remote"]["source"].as_str(), Some( - format!( - r"\\?\{}", - home.join(".tmp").join("plugins-remote").display() - ) - .as_str() + expected_local_marketplace_path(&home.join(".tmp").join("plugins-remote")).as_str() ) ); }