source dump of claude code
at main 150 lines 3.8 kB view raw
1import { readdir, readFile } from 'fs/promises' 2import memoize from 'lodash-es/memoize.js' 3import { release as osRelease } from 'os' 4import { getFsImplementation } from './fsOperations.js' 5import { logError } from './log.js' 6 7export type Platform = 'macos' | 'windows' | 'wsl' | 'linux' | 'unknown' 8 9export const SUPPORTED_PLATFORMS: Platform[] = ['macos', 'wsl'] 10 11export const getPlatform = memoize((): Platform => { 12 try { 13 if (process.platform === 'darwin') { 14 return 'macos' 15 } 16 17 if (process.platform === 'win32') { 18 return 'windows' 19 } 20 21 if (process.platform === 'linux') { 22 // Check if running in WSL (Windows Subsystem for Linux) 23 try { 24 const procVersion = getFsImplementation().readFileSync( 25 '/proc/version', 26 { encoding: 'utf8' }, 27 ) 28 if ( 29 procVersion.toLowerCase().includes('microsoft') || 30 procVersion.toLowerCase().includes('wsl') 31 ) { 32 return 'wsl' 33 } 34 } catch (error) { 35 // Error reading /proc/version, assume regular Linux 36 logError(error) 37 } 38 39 // Regular Linux 40 return 'linux' 41 } 42 43 // Unknown platform 44 return 'unknown' 45 } catch (error) { 46 logError(error) 47 return 'unknown' 48 } 49}) 50 51export const getWslVersion = memoize((): string | undefined => { 52 // Only check for WSL on Linux systems 53 if (process.platform !== 'linux') { 54 return undefined 55 } 56 try { 57 const procVersion = getFsImplementation().readFileSync('/proc/version', { 58 encoding: 'utf8', 59 }) 60 61 // First check for explicit WSL version markers (e.g., "WSL2", "WSL3", etc.) 62 const wslVersionMatch = procVersion.match(/WSL(\d+)/i) 63 if (wslVersionMatch && wslVersionMatch[1]) { 64 return wslVersionMatch[1] 65 } 66 67 // If no explicit WSL version but contains Microsoft, assume WSL1 68 // This handles the original WSL1 format: "4.4.0-19041-Microsoft" 69 if (procVersion.toLowerCase().includes('microsoft')) { 70 return '1' 71 } 72 73 // Not WSL or unable to determine version 74 return undefined 75 } catch (error) { 76 logError(error) 77 return undefined 78 } 79}) 80 81export type LinuxDistroInfo = { 82 linuxDistroId?: string 83 linuxDistroVersion?: string 84 linuxKernel?: string 85} 86 87export const getLinuxDistroInfo = memoize( 88 async (): Promise<LinuxDistroInfo | undefined> => { 89 if (process.platform !== 'linux') { 90 return undefined 91 } 92 93 const result: LinuxDistroInfo = { 94 linuxKernel: osRelease(), 95 } 96 97 try { 98 const content = await readFile('/etc/os-release', 'utf8') 99 for (const line of content.split('\n')) { 100 const match = line.match(/^(ID|VERSION_ID)=(.*)$/) 101 if (match && match[1] && match[2]) { 102 const value = match[2].replace(/^"|"$/g, '') 103 if (match[1] === 'ID') { 104 result.linuxDistroId = value 105 } else { 106 result.linuxDistroVersion = value 107 } 108 } 109 } 110 } catch { 111 // /etc/os-release may not exist on all Linux systems 112 } 113 114 return result 115 }, 116) 117 118const VCS_MARKERS: Array<[string, string]> = [ 119 ['.git', 'git'], 120 ['.hg', 'mercurial'], 121 ['.svn', 'svn'], 122 ['.p4config', 'perforce'], 123 ['$tf', 'tfs'], 124 ['.tfvc', 'tfs'], 125 ['.jj', 'jujutsu'], 126 ['.sl', 'sapling'], 127] 128 129export async function detectVcs(dir?: string): Promise<string[]> { 130 const detected = new Set<string>() 131 132 // Check for Perforce via env var 133 if (process.env.P4PORT) { 134 detected.add('perforce') 135 } 136 137 try { 138 const targetDir = dir ?? getFsImplementation().cwd() 139 const entries = new Set(await readdir(targetDir)) 140 for (const [marker, vcs] of VCS_MARKERS) { 141 if (entries.has(marker)) { 142 detected.add(vcs) 143 } 144 } 145 } catch { 146 // Directory may not be readable 147 } 148 149 return [...detected] 150}