-
Notifications
You must be signed in to change notification settings - Fork 0
Create Notice #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| To test auto code review in PRs | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,173 @@ | ||||||||||||||||||||||||||||||||||||
| import memoize from 'lodash-es/memoize.js' | ||||||||||||||||||||||||||||||||||||
| import * as path from 'path' | ||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||||||||||||||||||||||||||||||||
| 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' | ||||||||||||||||||||||||||||||||||||
|
Comment on lines
+1
to
+8
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add
Suggested change
|
||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||
| * 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 | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
Comment on lines
+15
to
+22
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Comment on lines
+15
to
+22
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The function checkPathExists(filePath: string): boolean {
return existsSync(filePath)
} |
||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||
| * 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() | ||||||||||||||||||||||||||||||||||||
|
Comment on lines
+49
to
+52
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Potential command injection vulnerability. The |
||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // 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) | ||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Splitting by
Suggested change
|
||||||||||||||||||||||||||||||||||||
| 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) | ||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using
Suggested change
|
||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| 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, | ||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,13 @@ | ||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||
| * Polyfill for Promise.withResolvers() (ES2024, Node 22+). | ||||||||||||||||||||||||||||||||||
| * package.json declares "engines": { "node": ">=18.0.0" } so we can't use the native one. | ||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||
| export function withResolvers<T>(): PromiseWithResolvers<T> { | ||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since this polyfill is for environments where
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The type
Suggested change
|
||||||||||||||||||||||||||||||||||
| let resolve!: (value: T | PromiseLike<T>) => void | ||||||||||||||||||||||||||||||||||
| let reject!: (reason?: unknown) => void | ||||||||||||||||||||||||||||||||||
| const promise = new Promise<T>((res, rej) => { | ||||||||||||||||||||||||||||||||||
| resolve = res | ||||||||||||||||||||||||||||||||||
| reject = rej | ||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||
| return { promise, resolve, reject } | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Committing test placeholders like
Noticeto the repository root clutters the project structure. Such files should be removed before merging. If the intent is to add a legal notice, use the standardNOTICEfilename and include the appropriate attribution text.