Something went wrong. Try again.
source dump of claude code forked from oppi.li/claude-code
Something went wrong. Try again.
6.0 kB · 173 lines
TypeScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174import memoize from 'lodash-es/memoize.js'import * as path from 'path'import * as pathWin32 from 'path/win32'import { getCwd } from './cwd.js'import { logForDebugging } from './debug.js'import { execSync_DEPRECATED } from './execSyncWrapper.js'import { memoizeWithLRU } from './memoize.js'import { getPlatform } from './platform.js'
/** * Check if a file or directory exists on Windows using the dir command * @param path - The path to check * @returns true if the path exists, false otherwise */function checkPathExists(path: string): boolean { try { execSync_DEPRECATED(`dir "${path}"`, { stdio: 'pipe' }) return true } catch { return false }}
/** * Find an executable using where.exe on Windows * @param executable - The name of the executable to find * @returns The path to the executable or null if not found */function findExecutable(executable: string): string | null { // For git, check common installation locations first if (executable === 'git') { const defaultLocations = [ // check 64 bit before 32 bit 'C:\\Program Files\\Git\\cmd\\git.exe', 'C:\\Program Files (x86)\\Git\\cmd\\git.exe', // intentionally don't look for C:\Program Files\Git\mingw64\bin\git.exe // because that directory is the "raw" tools with no environment setup ]
for (const location of defaultLocations) { if (checkPathExists(location)) { return location } } }
// Fall back to where.exe try { const result = execSync_DEPRECATED(`where.exe ${executable}`, { stdio: 'pipe', encoding: 'utf8', }).trim()
// SECURITY: Filter out any results from the current directory // to prevent executing malicious git.bat/cmd/exe files const paths = result.split('\r\n').filter(Boolean) const cwd = getCwd().toLowerCase()
for (const candidatePath of paths) { // Normalize and compare paths to ensure we're not in current directory const normalizedPath = path.resolve(candidatePath).toLowerCase() const pathDir = path.dirname(normalizedPath).toLowerCase()
// Skip if the executable is in the current working directory if (pathDir === cwd || normalizedPath.startsWith(cwd + path.sep)) { logForDebugging( `Skipping potentially malicious executable in current directory: ${candidatePath}`, ) continue }
// Return the first valid path that's not in the current directory return candidatePath }
return null } catch { return null }}
/** * If Windows, set the SHELL environment variable to git-bash path. * This is used by BashTool and Shell.ts for user shell commands. * COMSPEC is left unchanged for system process execution. */export function setShellIfWindows(): void { if (getPlatform() === 'windows') { const gitBashPath = findGitBashPath() process.env.SHELL = gitBashPath logForDebugging(`Using bash path: "${gitBashPath}"`) }}
/** * Find the path where `bash.exe` included with git-bash exists, exiting the process if not found. */export const findGitBashPath = memoize((): string => { if (process.env.CLAUDE_CODE_GIT_BASH_PATH) { if (checkPathExists(process.env.CLAUDE_CODE_GIT_BASH_PATH)) { return process.env.CLAUDE_CODE_GIT_BASH_PATH } // biome-ignore lint/suspicious/noConsole:: intentional console output console.error( `Claude Code was unable to find CLAUDE_CODE_GIT_BASH_PATH path "${process.env.CLAUDE_CODE_GIT_BASH_PATH}"`, ) // eslint-disable-next-line custom-rules/no-process-exit process.exit(1) }
const gitPath = findExecutable('git') if (gitPath) { const bashPath = pathWin32.join(gitPath, '..', '..', 'bin', 'bash.exe') if (checkPathExists(bashPath)) { return bashPath } }
// biome-ignore lint/suspicious/noConsole:: intentional console output console.error( 'Claude Code on Windows requires git-bash (https://git-scm.com/downloads/win). If installed but not in PATH, set environment variable pointing to your bash.exe, similar to: CLAUDE_CODE_GIT_BASH_PATH=C:\\Program Files\\Git\\bin\\bash.exe', ) // eslint-disable-next-line custom-rules/no-process-exit process.exit(1)})
/** Convert a Windows path to a POSIX path using pure JS. */export const windowsPathToPosixPath = memoizeWithLRU( (windowsPath: string): string => { // Handle UNC paths: \\server\share -> //server/share if (windowsPath.startsWith('\\\\')) { return windowsPath.replace(/\\/g, '/') } // Handle drive letter paths: C:\Users\foo -> /c/Users/foo const match = windowsPath.match(/^([A-Za-z]):[/\\]/) if (match) { const driveLetter = match[1]!.toLowerCase() return '/' + driveLetter + windowsPath.slice(2).replace(/\\/g, '/') } // Already POSIX or relative — just flip slashes return windowsPath.replace(/\\/g, '/') }, (p: string) => p, 500,)
/** Convert a POSIX path to a Windows path using pure JS. */export const posixPathToWindowsPath = memoizeWithLRU( (posixPath: string): string => { // Handle UNC paths: //server/share -> \\server\share if (posixPath.startsWith('//')) { return posixPath.replace(/\//g, '\\') } // Handle /cygdrive/c/... format const cygdriveMatch = posixPath.match(/^\/cygdrive\/([A-Za-z])(\/|$)/) if (cygdriveMatch) { const driveLetter = cygdriveMatch[1]!.toUpperCase() const rest = posixPath.slice(('/cygdrive/' + cygdriveMatch[1]).length) return driveLetter + ':' + (rest || '\\').replace(/\//g, '\\') } // Handle /c/... format (MSYS2/Git Bash) const driveMatch = posixPath.match(/^\/([A-Za-z])(\/|$)/) if (driveMatch) { const driveLetter = driveMatch[1]!.toUpperCase() const rest = posixPath.slice(2) return driveLetter + ':' + (rest || '\\').replace(/\//g, '\\') } // Already Windows or relative — just flip slashes return posixPath.replace(/\//g, '\\') }, (p: string) => p, 500,)