Skip to content

Commit 5971df4

Browse files
committed
fix: WSL UNC path conversion and code cleanup
- Handle \\wsl.localhost\Distro\path -> /path conversion correctly - Handle \\wsl$\Distro\path -> /path conversion correctly - Fix indentation in AgentExecution.tsx model selector buttons - Add shared ClaudeModel type and CLAUDE_MODELS config in types/hooks.ts
1 parent e6337ef commit 5971df4

3 files changed

Lines changed: 78 additions & 9 deletions

File tree

src-tauri/src/shell_environment.rs

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,13 +273,33 @@ pub fn check_claude_in_wsl(_distro: Option<&str>) -> Option<String> {
273273

274274
/// Convert a Windows path to WSL path format
275275
/// e.g., C:\Users\user\project -> /mnt/c/Users/user/project
276+
/// Also handles WSL UNC paths: \\wsl.localhost\Ubuntu\home\user -> /home/user
276277
#[cfg(windows)]
277278
pub fn windows_to_wsl_path(windows_path: &str) -> String {
278279
// Handle UNC paths and standard paths
279280
let path = windows_path.replace('\\', "/");
280281

282+
// Check for WSL UNC paths first: //wsl.localhost/Distro/path or //wsl$/Distro/path
283+
if let Some(rest) = path.strip_prefix("//wsl.localhost/") {
284+
// Format: //wsl.localhost/Ubuntu/home/user/... -> /home/user/...
285+
// Skip the distro name (first path component)
286+
if let Some(slash_pos) = rest.find('/') {
287+
return rest[slash_pos..].to_string();
288+
}
289+
return format!("/{}", rest);
290+
}
291+
292+
if let Some(rest) = path.strip_prefix("//wsl$/") {
293+
// Format: //wsl$/Ubuntu/home/user/... -> /home/user/...
294+
// Skip the distro name (first path component)
295+
if let Some(slash_pos) = rest.find('/') {
296+
return rest[slash_pos..].to_string();
297+
}
298+
return format!("/{}", rest);
299+
}
300+
281301
if let Some(rest) = path.strip_prefix("//") {
282-
// UNC path: \\server\share -> /mnt/server/share (approximate)
302+
// Other UNC paths: \\server\share -> /mnt/server/share (approximate)
283303
format!("/mnt/{}", rest)
284304
} else if path.len() >= 2 && path.chars().nth(1) == Some(':') {
285305
// Drive letter path: C:/... -> /mnt/c/...
@@ -395,10 +415,27 @@ mod tests {
395415
#[test]
396416
#[cfg(windows)]
397417
fn test_windows_to_wsl_path() {
418+
// Standard Windows drive paths
398419
assert_eq!(
399420
windows_to_wsl_path(r"C:\Users\test\project"),
400421
"/mnt/c/Users/test/project"
401422
);
402423
assert_eq!(windows_to_wsl_path(r"D:\dev\myapp"), "/mnt/d/dev/myapp");
424+
425+
// WSL UNC paths - these should extract the Linux path
426+
assert_eq!(
427+
windows_to_wsl_path(r"\\wsl.localhost\Ubuntu\home\jordan\project"),
428+
"/home/jordan/project"
429+
);
430+
assert_eq!(
431+
windows_to_wsl_path(r"\\wsl$\Ubuntu\home\user\code"),
432+
"/home/user/code"
433+
);
434+
435+
// Already a Linux path (passthrough)
436+
assert_eq!(
437+
windows_to_wsl_path("/home/jordan/project"),
438+
"/home/jordan/project"
439+
);
403440
}
404441
}

src/components/AgentExecution.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -616,10 +616,10 @@ export const AgentExecution: React.FC<AgentExecutionProps> = ({
616616
<div className="w-2 h-2 rounded-full bg-primary" />
617617
)}
618618
</div>
619-
<div className="text-left">
620-
<div className="text-body-small font-medium">Claude Sonnet</div>
621-
<div className="text-caption text-muted-foreground">Balanced performance</div>
622-
</div>
619+
<div className="text-left">
620+
<div className="text-body-small font-medium">Claude Sonnet</div>
621+
<div className="text-caption text-muted-foreground">Balanced performance</div>
622+
</div>
623623
</div>
624624
</motion.button>
625625

@@ -646,10 +646,10 @@ export const AgentExecution: React.FC<AgentExecutionProps> = ({
646646
<div className="w-2 h-2 rounded-full bg-primary" />
647647
)}
648648
</div>
649-
<div className="text-left">
650-
<div className="text-body-small font-medium">Claude Opus</div>
651-
<div className="text-caption text-muted-foreground">Most capable</div>
652-
</div>
649+
<div className="text-left">
650+
<div className="text-body-small font-medium">Claude Opus</div>
651+
<div className="text-caption text-muted-foreground">Most capable</div>
652+
</div>
653653
</div>
654654
</motion.button>
655655

src/types/hooks.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,38 @@
22
* Types for Claude Code hooks configuration
33
*/
44

5+
/**
6+
* Model type for Claude model selection
7+
* Used across prompt input, agents, and session components
8+
*/
9+
export type ClaudeModel = "sonnet" | "opus" | "haiku";
10+
11+
/**
12+
* Model display configuration
13+
*/
14+
export interface ModelConfig {
15+
id: ClaudeModel;
16+
name: string;
17+
description: string;
18+
shortName: string;
19+
}
20+
21+
/**
22+
* Available Claude models with display metadata
23+
*/
24+
export const CLAUDE_MODELS: ModelConfig[] = [
25+
{ id: "sonnet", name: "Claude Sonnet", description: "Balanced performance", shortName: "S" },
26+
{ id: "opus", name: "Claude Opus", description: "Most capable", shortName: "O" },
27+
{ id: "haiku", name: "Claude Haiku", description: "Fast & efficient", shortName: "H" },
28+
];
29+
30+
/**
31+
* Get display name for a model
32+
*/
33+
export function getModelDisplayName(model: ClaudeModel): string {
34+
return CLAUDE_MODELS.find(m => m.id === model)?.name ?? model;
35+
}
36+
537
export interface HookCommand {
638
type: 'command';
739
command: string;

0 commit comments

Comments
 (0)