diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index e7263b14..38ee99fc 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -1762,6 +1762,7 @@ dependencies = [ "crossbeam-channel", "directories", "dirs 7.0.0", + "dunce", "env_logger", "flate2", "futures-util", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index db927c56..b997d0cf 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -119,6 +119,7 @@ serde_yaml = "0.9" thiserror = "2.0" regex-lite = "0.1" tempfile = "3" +dunce = "1" maxminddb = "0.32" quick-xml = { version = "0.42", features = ["serialize"] } diff --git a/src-tauri/src/extension_manager.rs b/src-tauri/src/extension_manager.rs index 4a760044..e8cfa424 100644 --- a/src-tauri/src/extension_manager.rs +++ b/src-tauri/src/extension_manager.rs @@ -683,7 +683,9 @@ impl ExtensionManager { dir: &Path, manifest: &serde_json::Value, ) -> Result> { - let absolute = dir.canonicalize()?; + // dunce, not std: on Windows std returns the `\\?\C:\...` form, which the + // Extensions page would show and `--load-extension` would be handed. + let absolute = dunce::canonicalize(dir)?; if !path_is_load_extension_safe(&absolute) { return Err(err_code("EXTENSION_PATH_HAS_COMMA")); } @@ -956,7 +958,7 @@ impl ExtensionManager { manifest: &serde_json::Value, explicit_name_provided: bool, ) -> Result<(), Box> { - let absolute = dir.canonicalize()?; + let absolute = dunce::canonicalize(dir)?; if !path_is_load_extension_safe(&absolute) { return Err(err_code("EXTENSION_PATH_HAS_COMMA")); } @@ -2201,7 +2203,11 @@ mod tests { let mgr = ExtensionManager::new(); let source = write_unpacked_fixture(&tmp.path().join("linked-extension"), "Linked Fixture"); - let canonical = source.canonicalize().unwrap().to_string_lossy().to_string(); + let canonical = dunce::canonicalize(&source) + .unwrap() + .to_string_lossy() + .to_string(); + assert!(!canonical.starts_with(r"\\?\"), "{canonical}"); let ext = mgr .add_unpacked_extension("Ignored".to_string(), &source, true) .unwrap(); diff --git a/src-tauri/src/mcp_integrations.rs b/src-tauri/src/mcp_integrations.rs index c55e17fb..bcd85660 100644 --- a/src-tauri/src/mcp_integrations.rs +++ b/src-tauri/src/mcp_integrations.rs @@ -180,7 +180,10 @@ impl AgentEnv { pub fn from_process() -> Option { Some(Self { platform: Platform::current(), - home: dirs::home_dir()?, + // std, not `dirs`: on Windows `dirs` asks for the Profile known folder + // and ignores USERPROFILE, while the clients themselves (Node's + // os.homedir(), Rust's home_dir) follow USERPROFILE. + home: std::env::home_dir()?, appdata: env_path("APPDATA"), xdg_config_home: env_path("XDG_CONFIG_HOME"), codex_home: env_path("CODEX_HOME"),