UNPKG

@xec-sh/core

Version:

Universal shell execution engine

325 lines 12.8 kB
import { ExecutionError } from './error.js'; export class EnhancedExecutionError extends ExecutionError { constructor(message, code, context = {}, suggestions = []) { super(message, code, { context, suggestions }); this.name = 'EnhancedExecutionError'; this.context = context; this.suggestions = suggestions; this.systemInfo = { platform: process.platform, arch: process.arch, nodeVersion: process.version }; } addSuggestion(suggestion) { this.suggestions.push(suggestion); return this; } format(verbose = false) { const lines = []; lines.push(`Error: ${this.message}`); lines.push(`Code: ${this.code}`); if (Object.keys(this.context).length > 0) { lines.push(''); lines.push('Context:'); if (this.context.command) lines.push(` Command: ${this.context.command}`); if (this.context.adapter) lines.push(` Adapter: ${this.context.adapter}`); if (this.context.host) lines.push(` Host: ${this.context.host}`); if (this.context.container) lines.push(` Container: ${this.context.container}`); if (this.context.pod) lines.push(` Pod: ${this.context.pod}`); if (this.context.cwd) lines.push(` Directory: ${this.context.cwd}`); if (this.context.duration) lines.push(` Duration: ${this.context.duration}ms`); } if (this.suggestions.length > 0) { lines.push(''); lines.push('Suggestions:'); this.suggestions.forEach((suggestion, i) => { lines.push(` ${i + 1}. ${suggestion.message}`); if (suggestion.command) { lines.push(` Try: ${suggestion.command}`); } if (suggestion.documentation) { lines.push(` See: ${suggestion.documentation}`); } }); } if (verbose && this.systemInfo) { lines.push(''); lines.push('System:'); lines.push(` Platform: ${this.systemInfo.platform}`); lines.push(` Architecture: ${this.systemInfo.arch}`); lines.push(` Node Version: ${this.systemInfo.nodeVersion}`); } if (verbose && this.stack) { lines.push(''); lines.push('Stack Trace:'); lines.push(this.stack); } return lines.join('\n'); } } export class EnhancedCommandError extends EnhancedExecutionError { constructor(command, exitCode, signal, stdout, stderr, duration, adapter = 'local') { const context = { command, adapter, duration, timestamp: new Date() }; const suggestions = generateCommandErrorSuggestions(command, exitCode, stderr, adapter); super(`Command failed with exit code ${exitCode}: ${command}`, 'COMMAND_FAILED', context, suggestions); this.exitCode = exitCode; this.signal = signal; this.stdout = stdout; this.stderr = stderr; this.duration = duration; this.name = 'EnhancedCommandError'; } } export class EnhancedConnectionError extends EnhancedExecutionError { constructor(host, originalError, port, adapter = 'ssh') { const context = { host, adapter, timestamp: new Date() }; const suggestions = generateConnectionErrorSuggestions(host, originalError, port, adapter); super(`Failed to connect to ${host}${port ? ':' + port : ''}: ${originalError.message}`, 'CONNECTION_FAILED', context, suggestions); this.host = host; this.originalError = originalError; this.port = port; this.name = 'EnhancedConnectionError'; } } export class EnhancedTimeoutError extends EnhancedExecutionError { constructor(command, timeout, adapter = 'local') { const context = { command, adapter, duration: timeout, timestamp: new Date() }; const suggestions = generateTimeoutErrorSuggestions(command, timeout, adapter); super(`Command timed out after ${timeout}ms: ${command}`, 'TIMEOUT', context, suggestions); this.timeout = timeout; this.name = 'EnhancedTimeoutError'; } } function generateCommandErrorSuggestions(command, exitCode, stderr, adapter) { const suggestions = []; switch (exitCode) { case 1: suggestions.push({ message: 'General error - check command syntax and arguments', documentation: 'https://www.gnu.org/software/bash/manual/html_node/Exit-Status.html' }); break; case 2: suggestions.push({ message: 'Misuse of shell command - check syntax', command: `man ${command.split(' ')[0]}` }); break; case 126: suggestions.push({ message: 'Command cannot execute - check permissions', command: `ls -la ${command.split(' ')[0]}` }); break; case 127: { suggestions.push({ message: 'Command not found - check if installed', command: `which ${command.split(' ')[0]}` }); const cmdName = command.split(' ')[0]; if (cmdName) { suggestions.push({ message: `Command '${cmdName}' not found - install it first`, command: getInstallCommand(cmdName) }); } break; } case 128: suggestions.push({ message: 'Invalid argument to exit', documentation: 'https://tldp.org/LDP/abs/html/exitcodes.html' }); break; } if (adapter === 'ssh') { suggestions.push({ message: 'Check SSH connection and remote environment', command: 'ssh -v <host> "which <command>"' }); } else if (adapter === 'docker') { suggestions.push({ message: 'Check if command exists in container', command: 'docker exec <container> which <command>' }); } else if (adapter === 'kubernetes') { suggestions.push({ message: 'Check if command exists in pod', command: 'kubectl exec <pod> -- which <command>' }); } if (stderr.includes('Permission denied')) { suggestions.push({ message: 'Permission denied - check file permissions or run with appropriate privileges', command: adapter === 'local' ? 'sudo <command>' : undefined }); } if (stderr.includes('No such file or directory')) { suggestions.push({ message: 'File or directory not found - check paths', command: 'ls -la <path>' }); } if (stderr.includes('command not found') || stderr.includes('not found')) { const cmdName = command.split(' ')[0]; suggestions.push({ message: `Command '${cmdName}' not found - install it first`, command: getInstallCommand(cmdName) }); } return suggestions; } function generateConnectionErrorSuggestions(host, error, port, adapter) { const suggestions = []; const errorMsg = error.message.toLowerCase(); suggestions.push({ message: 'Check network connectivity and host availability', command: `ping ${host}` }); if (errorMsg.includes('enotfound') || errorMsg.includes('getaddrinfo')) { suggestions.push({ message: 'Host not found - check hostname or DNS', command: `nslookup ${host}` }); suggestions.push({ message: 'Try using IP address instead of hostname', command: `ping ${host}` }); } if (errorMsg.includes('econnrefused')) { suggestions.push({ message: `Connection refused - check if service is running on port ${port || 'default'}`, command: port ? `nc -zv ${host} ${port}` : `ping ${host}` }); if (adapter === 'ssh') { suggestions.push({ message: 'Check if SSH service is running', command: `ssh -v ${host}` }); } } if (errorMsg.includes('etimedout') || errorMsg.includes('timeout')) { suggestions.push({ message: 'Connection timeout - check network connectivity', command: `ping -c 4 ${host}` }); suggestions.push({ message: 'Check firewall rules', documentation: 'https://xec.sh/docs/projects/cli/troubleshooting' }); } if (errorMsg.includes('authentication') || errorMsg.includes('permission')) { suggestions.push({ message: 'Authentication failed - check credentials', documentation: 'https://xec.sh/docs/projects/cli/troubleshooting' }); if (adapter === 'ssh') { suggestions.push({ message: 'Check SSH key permissions', command: 'chmod 600 ~/.ssh/id_rsa' }); } } return suggestions; } function generateTimeoutErrorSuggestions(command, timeout, adapter) { const suggestions = []; suggestions.push({ message: `Increase timeout (current: ${timeout}ms)`, command: `xec --timeout ${timeout * 2}ms "${command}"` }); if (command.includes('install') || command.includes('download')) { suggestions.push({ message: 'Long-running installation/download detected - consider running in background', command: `nohup ${command} &` }); } if (adapter === 'ssh') { suggestions.push({ message: 'Check SSH connection stability', command: 'xec config set ssh.keepaliveInterval 30' }); } if (adapter === 'docker' || adapter === 'kubernetes') { suggestions.push({ message: 'Check container/pod resources', command: adapter === 'docker' ? 'docker stats <container>' : 'kubectl top pod <pod>' }); } suggestions.push({ message: 'Run command directly to see why it\'s slow', documentation: 'https://xec.sh/docs/projects/cli/troubleshooting' }); return suggestions; } function getInstallCommand(command) { const commonCommands = { git: 'brew install git || apt-get install git || yum install git', node: 'brew install node || curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -', docker: 'brew install docker || curl -fsSL https://get.docker.com | sh', kubectl: 'brew install kubectl || snap install kubectl --classic', npm: 'Installed with Node.js', yarn: 'npm install -g yarn', python: 'brew install python || apt-get install python3', pip: 'python -m ensurepip', make: 'brew install make || apt-get install build-essential', curl: 'brew install curl || apt-get install curl', wget: 'brew install wget || apt-get install wget', jq: 'brew install jq || apt-get install jq', aws: 'brew install awscli || pip install awscli', gcloud: 'brew install google-cloud-sdk', az: 'brew install azure-cli' }; return commonCommands[command] || `Check package manager for '${command}'`; } export function enhanceError(error, context) { if (error instanceof EnhancedExecutionError) { if (context) { Object.assign(error.context, context); } return error; } if (error.name === 'CommandError') { const cmdError = error; return new EnhancedCommandError(cmdError.command, cmdError.exitCode, cmdError.signal, cmdError.stdout, cmdError.stderr, cmdError.duration, context?.adapter); } if (error.name === 'ConnectionError') { const connError = error; return new EnhancedConnectionError(connError.host, connError.originalError, connError.port, context?.adapter); } if (error.name === 'TimeoutError') { const timeoutError = error; return new EnhancedTimeoutError(timeoutError.command, timeoutError.timeout, context?.adapter); } return new EnhancedExecutionError(error.message, 'UNKNOWN_ERROR', context || {}, [{ message: 'An unexpected error occurred', documentation: 'https://xec.sh/docs/projects/cli/troubleshooting' }]); } //# sourceMappingURL=enhanced-error.js.map