diff --git a/src/cliproxy/cliproxy-executor.ts b/src/cliproxy/cliproxy-executor.ts index 626e4519..808a1814 100644 --- a/src/cliproxy/cliproxy-executor.ts +++ b/src/cliproxy/cliproxy-executor.ts @@ -286,6 +286,29 @@ export async function execClaudeWithCLIProxy( spinner.succeed('CLIProxy binary ready'); } catch (error) { spinner.fail('Failed to prepare CLIProxy'); + const err = error as Error; + + // Check if network offline (DNS, connection, or timeout failure) + const networkErrors = [ + 'getaddrinfo', + 'ENOTFOUND', + 'ETIMEDOUT', + 'ECONNREFUSED', + 'ENETUNREACH', + 'EAI_AGAIN', + ]; + const isNetworkError = networkErrors.some((errCode) => err.message.includes(errCode)); + + if (isNetworkError) { + console.error(''); + console.error(fail('No network connection detected')); + console.error(''); + console.error('CLIProxy binary download requires internet access.'); + console.error('Please check your network connection and try again.'); + console.error(''); + process.exit(1); + } + throw error; } } diff --git a/src/utils/shell-executor.ts b/src/utils/shell-executor.ts index ffea9d3c..d60e3574 100644 --- a/src/utils/shell-executor.ts +++ b/src/utils/shell-executor.ts @@ -11,9 +11,33 @@ import { getImageReadBlockHookEnv } from './hooks/image-read-block-hook-env'; /** * Escape arguments for shell execution (Windows compatibility) + * Handles PowerShell special characters: backticks, $variables, double quotes */ export function escapeShellArg(arg: string): string { - return '"' + String(arg).replace(/"/g, '""') + '"'; + const isWindows = process.platform === 'win32'; + + if (isWindows) { + // PowerShell: Use single quotes for literal strings to prevent variable expansion + // Escape single quotes by doubling them (PowerShell syntax) + // Fallback to double quotes with escapes if single quotes present + if (arg.includes("'")) { + // Contains single quote - use double quotes with escape sequences + return ( + '"' + + String(arg) + .replace(/\$/g, '`$') // Escape $ to prevent variable expansion + .replace(/`/g, '``') // Escape backticks + .replace(/"/g, '`"') + // Escape double quotes + '"' + ); + } else { + // No single quotes - use single quotes for literal string (safest) + return "'" + String(arg) + "'"; + } + } else { + // Unix/macOS: Double quotes with escaped inner quotes + return '"' + String(arg).replace(/"/g, '""') + '"'; + } } /**