fix: work on paths

This commit is contained in:
2026-02-04 12:40:50 -08:00
parent d712bccb91
commit ee201d71c8
9 changed files with 292 additions and 36 deletions
+29 -16
View File
@@ -8,6 +8,7 @@ use crate::bridge_manager::SharedBridgeManager;
use crate::config::{ClaudeStartOptions, HikariConfig};
use crate::stats::UsageStats;
use crate::temp_manager::SharedTempFileManager;
use crate::utils::normalize_path_separators;
const CONFIG_STORE_KEY: &str = "config";
@@ -126,7 +127,7 @@ pub async fn validate_directory(
// Expand ~ to home directory
let expanded_path = if path.starts_with("~") {
if let Some(home) = std::env::var_os("HOME") {
if let Some(home) = std::env::var_os("HOME").or_else(|| std::env::var_os("USERPROFILE")) {
let home_path = Path::new(&home);
if path == Path::new("~") {
home_path.to_path_buf()
@@ -165,14 +166,7 @@ pub async fn validate_directory(
// Return the canonicalized (absolute) path with forward slashes
expanded_path
.canonicalize()
.map(|p| {
// Convert to string and normalize path separators to forward slashes
let path_str = p.to_string_lossy().to_string();
// On Windows, replace backslashes with forward slashes
#[cfg(target_os = "windows")]
let path_str = path_str.replace('\\', "/");
path_str
})
.map(|p| normalize_path_separators(&p.to_string_lossy()))
.map_err(|e| format!("Failed to resolve path: {}", e))
}
@@ -212,9 +206,10 @@ pub async fn list_skills() -> Result<Vec<String>, String> {
use std::fs;
use std::path::Path;
// Get the home directory
let home =
std::env::var_os("HOME").ok_or_else(|| "Could not determine home directory".to_string())?;
// Get the home directory - use HOME on Unix, USERPROFILE on Windows
let home = std::env::var_os("HOME")
.or_else(|| std::env::var_os("USERPROFILE"))
.ok_or_else(|| "Could not determine home directory".to_string())?;
let skills_dir = Path::new(&home).join(".claude").join("skills");
@@ -444,10 +439,7 @@ pub async fn list_directory(path: String) -> Result<Vec<FileEntry>, String> {
continue;
}
let path_str = path.to_string_lossy().to_string();
// On Windows, replace backslashes with forward slashes
#[cfg(target_os = "windows")]
let path_str = path_str.replace('\\', "/");
let path_str = normalize_path_separators(&path.to_string_lossy());
file_entries.push(FileEntry {
name,
@@ -826,4 +818,25 @@ mod tests {
assert!(json.contains("/tmp/test.txt"));
assert!(json.contains("test.txt"));
}
#[test]
fn test_validate_directory_normalizes_backslashes() {
// This test ensures that paths with backslashes are normalized
// Create a temp directory for testing
let temp_dir = TempDir::new().unwrap();
// On Windows, the canonicalized path will have backslashes
// Our normalize_path_separators should convert them to forward slashes
let result = run_async(validate_directory(
temp_dir.path().to_string_lossy().to_string(),
None,
));
assert!(result.is_ok());
let normalized_path = result.unwrap();
// The result should never contain backslashes
assert!(!normalized_path.contains('\\'),
"Path should not contain backslashes: {}", normalized_path);
}
}
+1
View File
@@ -12,6 +12,7 @@ mod stats;
mod temp_manager;
mod tray;
mod types;
mod utils;
mod vbs_notification;
mod windows_toast;
mod wsl_bridge;
+71
View File
@@ -0,0 +1,71 @@
/// Utility functions for cross-platform compatibility
/// Normalize path separators to forward slashes for consistent handling across platforms
/// This always normalizes backslashes to forward slashes, regardless of platform,
/// because Windows paths may be passed to WSL which expects Unix-style paths
pub fn normalize_path_separators(path: &str) -> String {
path.replace('\\', "/")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[cfg(target_os = "windows")]
fn test_normalize_path_windows() {
assert_eq!(normalize_path_separators("C:\\Users\\test"), "C:/Users/test");
assert_eq!(normalize_path_separators("path\\to\\file"), "path/to/file");
assert_eq!(normalize_path_separators("already/forward"), "already/forward");
assert_eq!(normalize_path_separators("mixed\\path/file"), "mixed/path/file");
}
#[test]
#[cfg(not(target_os = "windows"))]
fn test_normalize_path_unix() {
assert_eq!(normalize_path_separators("/home/user"), "/home/user");
assert_eq!(normalize_path_separators("path/to/file"), "path/to/file");
// Even on Unix, we normalize backslashes since paths may come from Windows
assert_eq!(normalize_path_separators("weird\\path"), "weird/path");
assert_eq!(normalize_path_separators("/home/user\\file"), "/home/user/file");
}
#[test]
fn test_normalize_wsl_paths() {
// Test the exact issue that was happening
assert_eq!(
normalize_path_separators("/home/naomi/code/naomi/portfolio\\.."),
"/home/naomi/code/naomi/portfolio/.."
);
// Test mixed separators in WSL paths
assert_eq!(
normalize_path_separators("/mnt/c\\Users\\naomi\\Documents"),
"/mnt/c/Users/naomi/Documents"
);
// Test Windows paths that might be passed to WSL
assert_eq!(
normalize_path_separators("C:\\Users\\naomi\\.claude\\skills"),
"C:/Users/naomi/.claude/skills"
);
// Test that forward slashes remain unchanged
assert_eq!(
normalize_path_separators("/home/naomi/.claude/skills"),
"/home/naomi/.claude/skills"
);
// Test empty string
assert_eq!(normalize_path_separators(""), "");
// Test single backslash
assert_eq!(normalize_path_separators("\\"), "/");
// Test multiple consecutive backslashes
assert_eq!(
normalize_path_separators("path\\\\to\\\\file"),
"path//to//file"
);
}
}
+2 -5
View File
@@ -16,6 +16,7 @@ use crate::types::{
PermissionPromptEvent, QuestionOption, SessionEvent, StateChangeEvent, UserQuestionEvent,
WorkingDirectoryEvent,
};
use crate::utils::normalize_path_separators;
use parking_lot::RwLock;
const SEARCH_TOOLS: [&str; 5] = ["Read", "Glob", "Grep", "WebSearch", "WebFetch"];
@@ -137,11 +138,7 @@ impl WslBridge {
let working_dir = &options.working_dir;
// Normalize path separators to forward slashes
#[cfg(target_os = "windows")]
let normalized_dir = working_dir.replace('\\', "/");
#[cfg(not(target_os = "windows"))]
let normalized_dir = working_dir.clone();
self.working_directory = normalized_dir;
self.working_directory = normalize_path_separators(working_dir);
emit_connection_status(
&app,