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
JavaScript
;
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: '未知错误'
};