UNPKG

claude-switcher

Version:

Cross-platform CLI tool for switching between different Claude AI model configurations. Supports automatic backup, rollback, and multi-platform configuration management for Claude API integrations.

266 lines (265 loc) 10.9 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ErrorHandler = exports.ErrorSeverity = exports.PermissionError = exports.ValidationError = exports.FileSystemError = exports.ConfigurationError = void 0; const chalk_1 = __importDefault(require("chalk")); class ConfigurationError extends Error { constructor(message, code) { super(message); this.code = code; this.name = 'ConfigurationError'; } } exports.ConfigurationError = ConfigurationError; class FileSystemError extends Error { constructor(message, code, path) { super(message); this.code = code; this.path = path; this.name = 'FileSystemError'; } } exports.FileSystemError = FileSystemError; class ValidationError extends Error { constructor(message, field) { super(message); this.field = field; this.name = 'ValidationError'; } } exports.ValidationError = ValidationError; class PermissionError extends Error { constructor(message, path) { super(message); this.path = path; this.name = 'PermissionError'; } } exports.PermissionError = PermissionError; var ErrorSeverity; (function (ErrorSeverity) { ErrorSeverity["LOW"] = "low"; ErrorSeverity["MEDIUM"] = "medium"; ErrorSeverity["HIGH"] = "high"; ErrorSeverity["CRITICAL"] = "critical"; })(ErrorSeverity || (exports.ErrorSeverity = ErrorSeverity = {})); class ErrorHandler { static handleError(error, context) { let message = ''; let details = undefined; let suggestions = []; let severity = ErrorSeverity.MEDIUM; let recoverable = true; if (error instanceof ConfigurationError) { message = `配置错误: ${error.message}`; severity = ErrorSeverity.HIGH; suggestions = [ '检查配置文件格式是否正确', '确保所有必需字段都已填写', '参考示例配置文件' ]; } else if (error instanceof FileSystemError) { message = `文件系统错误: ${error.message}`; severity = ErrorSeverity.HIGH; if (error.code === 'ENOENT') { suggestions = [ '确认文件路径是否正确', '检查文件是否存在', '尝试重新创建缺失的文件' ]; } else if (error.code === 'EACCES' || error.code === 'EPERM') { suggestions = [ '检查文件权限设置', '尝试使用 sudo 运行命令', '确保当前用户有访问权限' ]; severity = ErrorSeverity.CRITICAL; } else if (error.code === 'ENOSPC') { suggestions = [ '清理磁盘空间', '删除不必要的文件', '检查磁盘使用情况' ]; severity = ErrorSeverity.CRITICAL; recoverable = false; } } else if (error instanceof ValidationError) { message = `验证错误: ${error.message}`; severity = ErrorSeverity.MEDIUM; suggestions = [ '检查输入数据格式', '确保所有必需字段都已提供', '参考文档中的格式要求' ]; } else if (error instanceof PermissionError) { message = `权限错误: ${error.message}`; severity = ErrorSeverity.CRITICAL; suggestions = [ '检查文件和目录权限', '确保当前用户有足够权限', '尝试使用管理员权限运行' ]; } else if (error instanceof Error) { const nodeError = error; if (nodeError.code && ErrorHandler.ERROR_MESSAGES[nodeError.code]) { message = ErrorHandler.ERROR_MESSAGES[nodeError.code]; details = error.message; } else { message = error.message; } switch (nodeError.code) { case 'ENOENT': suggestions = ['检查文件路径', '确认文件存在', '检查目录结构']; break; case 'EACCES': case 'EPERM': suggestions = ['检查文件权限', '使用管理员权限', '修改文件所有者']; severity = ErrorSeverity.CRITICAL; break; case 'ENOSPC': suggestions = ['清理磁盘空间', '删除临时文件', '扩展存储容量']; severity = ErrorSeverity.CRITICAL; recoverable = false; break; default: suggestions = ['重试操作', '检查系统状态', '查看详细日志']; } } else { message = '发生未知错误'; details = String(error); suggestions = ['重试操作', '重启应用程序', '联系技术支持']; severity = ErrorSeverity.HIGH; } if (context?.suggestions) { suggestions = [...suggestions, ...context.suggestions]; } if (context?.severity) { severity = context.severity; } if (context?.recoverable !== undefined) { recoverable = context.recoverable; } return { message, details, suggestions: [...new Set(suggestions)], severity, recoverable }; } static displayError(error, context) { const errorInfo = ErrorHandler.handleError(error, context); console.error(chalk_1.default.red('✗ 错误:'), errorInfo.message); if (errorInfo.details) { console.error(chalk_1.default.gray(' 详情:'), errorInfo.details); } if (context?.operation) { console.error(chalk_1.default.gray(' 操作:'), context.operation); } if (context?.file) { console.error(chalk_1.default.gray(' 文件:'), context.file); } if (context?.config) { console.error(chalk_1.default.gray(' 配置:'), context.config); } const severityColor = ErrorHandler.getSeverityColor(errorInfo.severity); console.error(chalk_1.default.gray(' 严重程度:'), severityColor(errorInfo.severity.toUpperCase())); if (errorInfo.suggestions.length > 0) { console.error(chalk_1.default.yellow('\n建议解决方案:')); errorInfo.suggestions.forEach((suggestion, index) => { console.error(chalk_1.default.yellow(` ${index + 1}. ${suggestion}`)); }); } if (!errorInfo.recoverable) { console.error(chalk_1.default.red('\n⚠️ 此错误无法自动恢复,需要手动干预')); } console.error(); } static getSeverityColor(severity) { switch (severity) { case ErrorSeverity.LOW: return chalk_1.default.green; case ErrorSeverity.MEDIUM: return chalk_1.default.yellow; case ErrorSeverity.HIGH: return chalk_1.default.red; case ErrorSeverity.CRITICAL: return chalk_1.default.red.bold; default: return chalk_1.default.gray; } } static createUserFriendlyError(scenario, details) { switch (scenario) { case 'claude_dir_not_found': return new FileSystemError(`找不到 Claude 配置目录。请确保 Claude 已正确安装并至少运行过一次。\n` + `预期位置: ${details?.expectedPath || '~/.claude'}`, 'ENOENT', details?.expectedPath); case 'no_configs_found': return new ConfigurationError(`未找到任何配置文件。请确保在 Claude 配置目录中有 settings_*.json 文件。\n` + `配置目录: ${details?.claudeDir || '~/.claude'}`); case 'invalid_config_format': return new ValidationError(`配置文件格式无效: ${details?.file || '未知文件'}。\n` + `请确保文件是有效的 JSON 格式,并包含必需的 'env' 字段。`, details?.file); case 'backup_failed': return new FileSystemError(`创建备份失败。无法继续配置切换操作以保护现有设置。\n` + `请检查磁盘空间和文件权限。`, 'BACKUP_FAILED'); case 'switch_verification_failed': return new ConfigurationError(`配置切换验证失败。写入的配置与源配置不匹配。\n` + `已自动回滚到之前的配置。`); default: return new Error(`未知错误场景: ${scenario}`); } } static async withErrorHandling(operation, context) { try { return await operation(); } catch (error) { const enhancedError = ErrorHandler.handleError(error, context); if (process.env.DEBUG) { console.error('Debug Error Info:', { error, context, enhancedError, stack: error instanceof Error ? error.stack : undefined }); } const newError = new Error(enhancedError.message); newError.originalError = error; newError.context = context; newError.suggestions = enhancedError.suggestions; newError.severity = enhancedError.severity; newError.recoverable = enhancedError.recoverable; throw newError; } } } exports.ErrorHandler = ErrorHandler; ErrorHandler.ERROR_MESSAGES = { ENOENT: '文件或目录不存在', EACCES: '权限不足,无法访问文件', EPERM: '操作被拒绝,权限不足', EEXIST: '文件已存在', ENOTDIR: '路径不是一个目录', EISDIR: '路径是一个目录,期望文件', EMFILE: '打开的文件过多', ENOSPC: '磁盘空间不足', INVALID_JSON: 'JSON 格式无效', MISSING_CONFIG: '配置文件缺失', INVALID_CONFIG: '配置格式无效', CONFIG_NOT_FOUND: '找不到指定的配置', NETWORK_ERROR: '网络连接错误', API_ERROR: 'API 调用失败', TIMEOUT: '操作超时', UNKNOWN: '未知错误' };