idePathConversion.ts 2.5 KB

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