mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-05 01:50:27 +08:00
- 重写 escapeWindowsArg 函数,正确处理反斜杠和引号转义 - 添加 escapeUnixArg 函数支持 Linux/macOS shell 转义 - 添加 normalizePathSeparators 函数自动转换路径分隔符 - 修复 vscode-lsp.ts 中的 TypeScript 类型错误
118 lines
3.6 KiB
TypeScript
118 lines
3.6 KiB
TypeScript
/**
|
|
* Cross-platform shell argument escaping utilities.
|
|
*
|
|
* Provides proper escaping for command-line arguments when using spawn({ shell: true })
|
|
* on different platforms:
|
|
* - Windows: cmd.exe metacharacter handling with proper quote escaping
|
|
* - Unix (Linux/macOS): POSIX shell escaping with single quotes
|
|
*/
|
|
|
|
/**
|
|
* Escape a command-line argument for Windows cmd.exe.
|
|
* Follows Microsoft C/C++ runtime argv parsing rules.
|
|
*
|
|
* Rules:
|
|
* 1. Arguments containing spaces, tabs, or quotes must be quoted
|
|
* 2. Backslashes are literal unless followed by a quote
|
|
* 3. To include a literal quote, use \"
|
|
* 4. Backslashes before a quote must be doubled: \\" produces \"
|
|
* 5. Trailing backslashes must be doubled when the arg is quoted
|
|
*
|
|
* @param arg - The argument to escape
|
|
* @returns Properly escaped argument safe for Windows command line
|
|
*/
|
|
export function escapeWindowsArg(arg: string): string {
|
|
if (arg === '') return '""';
|
|
|
|
// Normalize newlines to spaces to prevent cmd.exe issues
|
|
arg = arg.replace(/\r?\n/g, ' ');
|
|
|
|
// Check if the argument needs quoting
|
|
// Characters that require quoting: space, tab, double quote, or backslash
|
|
const needsQuoting = /[ \t"\\]/.test(arg);
|
|
|
|
if (!needsQuoting) {
|
|
// No special characters - return as is
|
|
return arg;
|
|
}
|
|
|
|
// Build the escaped string with proper quoting
|
|
let result = '"';
|
|
|
|
for (let i = 0; i < arg.length; i++) {
|
|
// Count consecutive backslashes
|
|
let backslashes = 0;
|
|
while (i < arg.length && arg[i] === '\\') {
|
|
backslashes++;
|
|
i++;
|
|
}
|
|
|
|
if (i === arg.length) {
|
|
// Trailing backslashes: double them all (they precede the closing quote)
|
|
result += '\\'.repeat(backslashes * 2);
|
|
break;
|
|
}
|
|
|
|
if (arg[i] === '"') {
|
|
// Backslashes followed by a quote: double the backslashes and escape the quote
|
|
result += '\\'.repeat(backslashes * 2 + 1) + '"';
|
|
} else {
|
|
// Backslashes not followed by a quote: they are literal
|
|
result += '\\'.repeat(backslashes) + arg[i];
|
|
}
|
|
}
|
|
|
|
result += '"';
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Escape a command-line argument for Unix shells (bash, sh, zsh).
|
|
* Uses single quotes which treat all characters literally except single quote itself.
|
|
*
|
|
* Strategy:
|
|
* - Wrap argument in single quotes
|
|
* - Replace any single quotes with: '\'' (end quote, escaped quote, start quote)
|
|
*
|
|
* @param arg - The argument to escape
|
|
* @returns Properly escaped argument safe for Unix shell
|
|
*/
|
|
export function escapeUnixArg(arg: string): string {
|
|
if (arg === '') return "''";
|
|
|
|
// If no special characters, return as-is
|
|
// Safe characters: alphanumeric, hyphen, underscore, dot, forward slash, colon
|
|
if (/^[a-zA-Z0-9_.\/:@=-]+$/.test(arg)) {
|
|
return arg;
|
|
}
|
|
|
|
// Use single quotes and escape any single quotes within
|
|
// 'arg' -> 'arg'\''s' for "arg's"
|
|
return "'" + arg.replace(/'/g, "'\\''") + "'";
|
|
}
|
|
|
|
/**
|
|
* Escape a command-line argument for the current platform.
|
|
* Automatically selects the appropriate escaping method based on OS.
|
|
*
|
|
* @param arg - The argument to escape
|
|
* @returns Properly escaped argument for the current platform's shell
|
|
*/
|
|
export function escapeShellArg(arg: string): string {
|
|
if (process.platform === 'win32') {
|
|
return escapeWindowsArg(arg);
|
|
}
|
|
return escapeUnixArg(arg);
|
|
}
|
|
|
|
/**
|
|
* Check if we need shell escaping on the current platform.
|
|
* Windows always needs escaping when shell: true due to cmd.exe.
|
|
* Unix typically doesn't need escaping when shell: false.
|
|
*
|
|
* @returns true if shell escaping should be applied
|
|
*/
|
|
export function needsShellEscaping(): boolean {
|
|
return process.platform === 'win32';
|
|
}
|