/ utils / idePathConversion.ts
idePathConversion.ts
 1  /**
 2   * Path conversion utilities for IDE communication
 3   * Handles conversions between Claude's environment and the IDE's environment
 4   */
 5  
 6  import { execFileSync } from 'child_process'
 7  
 8  export interface IDEPathConverter {
 9    /**
10     * Convert path from IDE format to Claude's local format
11     * Used when reading workspace folders from IDE lockfile
12     */
13    toLocalPath(idePath: string): string
14  
15    /**
16     * Convert path from Claude's local format to IDE format
17     * Used when sending paths to IDE (showDiffInIDE, etc.)
18     */
19    toIDEPath(localPath: string): string
20  }
21  
22  /**
23   * Converter for Windows IDE + WSL Claude scenario
24   */
25  export class WindowsToWSLConverter implements IDEPathConverter {
26    constructor(private wslDistroName: string | undefined) {}
27  
28    toLocalPath(windowsPath: string): string {
29      if (!windowsPath) return windowsPath
30  
31      // Check if this is a path from a different WSL distro
32      if (this.wslDistroName) {
33        const wslUncMatch = windowsPath.match(
34          /^\\\\wsl(?:\.localhost|\$)\\([^\\]+)(.*)$/,
35        )
36        if (wslUncMatch && wslUncMatch[1] !== this.wslDistroName) {
37          // Different distro - wslpath will fail, so return original path
38          return windowsPath
39        }
40      }
41  
42      try {
43        // Use wslpath to convert Windows paths to WSL paths
44        const result = execFileSync('wslpath', ['-u', windowsPath], {
45          encoding: 'utf8',
46          stdio: ['pipe', 'pipe', 'ignore'], // wslpath writes "wslpath: <errortext>" to stderr
47        }).trim()
48  
49        return result
50      } catch {
51        // If wslpath fails, fall back to manual conversion
52        return windowsPath
53          .replace(/\\/g, '/') // Convert backslashes to forward slashes
54          .replace(/^([A-Z]):/i, (_, letter) => `/mnt/${letter.toLowerCase()}`)
55      }
56    }
57  
58    toIDEPath(wslPath: string): string {
59      if (!wslPath) return wslPath
60  
61      try {
62        // Use wslpath to convert WSL paths to Windows paths
63        const result = execFileSync('wslpath', ['-w', wslPath], {
64          encoding: 'utf8',
65          stdio: ['pipe', 'pipe', 'ignore'], // wslpath writes "wslpath: <errortext>" to stderr
66        }).trim()
67  
68        return result
69      } catch {
70        // If wslpath fails, return the original path
71        return wslPath
72      }
73    }
74  }
75  
76  /**
77   * Check if distro names match for WSL UNC paths
78   */
79  export function checkWSLDistroMatch(
80    windowsPath: string,
81    wslDistroName: string,
82  ): boolean {
83    const wslUncMatch = windowsPath.match(
84      /^\\\\wsl(?:\.localhost|\$)\\([^\\]+)(.*)$/,
85    )
86    if (wslUncMatch) {
87      return wslUncMatch[1] === wslDistroName
88    }
89    return true // Not a WSL UNC path, so no distro mismatch
90  }