diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 2225be0a..fe0c74cf 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -6617,6 +6617,7 @@ dependencies = [ "core-foundation-sys", "core-text", "dirs", + "dunce", "futures-util", "globset", "hostname", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index c4a9dabf..8f38cc30 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -48,6 +48,7 @@ notify-rust = "4" keyring = { version = "3", features = ["apple-native", "windows-native", "linux-native"] } aes-gcm = "0.10" rand = "0.8" +dunce = "1" tokio-tungstenite = "0.24" futures-util = { version = "0.3", default-features = false, features = ["sink"] } clap = { version = "4", features = ["derive"] } diff --git a/src-tauri/src/commands/extensions.rs b/src-tauri/src/commands/extensions.rs index c1bfec39..ed6b4fe7 100644 --- a/src-tauri/src/commands/extensions.rs +++ b/src-tauri/src/commands/extensions.rs @@ -66,7 +66,7 @@ fn resolve_extensions_dir(app_handle: &tauri::AppHandle) -> Option { if let Some(dir) = std::env::current_dir() .ok() .map(|cwd| cwd.join("../extensions")) - .and_then(|p| p.canonicalize().ok()) + .and_then(|p| dunce::canonicalize(&p).ok()) .filter(|p| p.is_dir()) { return Some(dir); @@ -76,7 +76,7 @@ fn resolve_extensions_dir(app_handle: &tauri::AppHandle) -> Option { if let Some(dir) = std::env::current_dir() .ok() .map(|cwd| cwd.join("../.build/extensions")) - .and_then(|p| p.canonicalize().ok()) + .and_then(|p| dunce::canonicalize(&p).ok()) .filter(|p| p.is_dir()) { return Some(dir); diff --git a/src-tauri/src/commands/spawn_exthost.rs b/src-tauri/src/commands/spawn_exthost.rs index 55c84a98..3adf1f26 100644 --- a/src-tauri/src/commands/spawn_exthost.rs +++ b/src-tauri/src/commands/spawn_exthost.rs @@ -464,10 +464,12 @@ fn resolve_app_root_and_resource_dir( ) -> Result<(PathBuf, PathBuf), String> { use tauri::Manager; - let resource_dir = app_handle - .path() - .resource_dir() - .map_err(|e| format!("Failed to resolve resource dir: {e}"))?; + let resource_dir = strip_unc_prefix( + &app_handle + .path() + .resource_dir() + .map_err(|e| format!("Failed to resolve resource dir: {e}"))?, + ); // Walk up from resource dir to find the repo root let mut candidate = resource_dir.as_path(); @@ -484,6 +486,7 @@ fn resolve_app_root_and_resource_dir( // Fallback: try current working directory if let Ok(cwd) = std::env::current_dir() { + let cwd = strip_unc_prefix(&cwd); if cwd.join("out/bootstrap-fork.js").exists() { return Ok((cwd, resource_dir)); } @@ -502,3 +505,20 @@ fn resolve_app_root_and_resource_dir( resource_dir.display() )) } + +/// Strip the Windows UNC extended-length path prefix (`\\?\`) from a path. +/// +/// On Windows, `std::fs::canonicalize()` and Tauri's `resource_dir()` may +/// return paths with the `\\?\` prefix. Node.js handles this transparently, +/// but Bun does not — it treats the prefix as part of the file name, causing +/// module resolution failures in the Extension Host. +/// +/// On non-Windows platforms this is a no-op. +fn strip_unc_prefix(path: &std::path::Path) -> PathBuf { + let s = path.to_string_lossy(); + if let Some(stripped) = s.strip_prefix(r"\\?\") { + PathBuf::from(stripped) + } else { + path.to_path_buf() + } +}