@yeepay/coderocket-mcp
Version:
CodeRocket MCP - Independent AI-powered code review server for Model Context Protocol
227 lines • 6.87 kB
JavaScript
import { appendFile } from 'fs/promises';
import { join } from 'path';
import { tmpdir } from 'os';
// 自定义错误类型
export class AIServiceError extends Error {
service;
constructor(message, service) {
super(message);
this.name = 'AIServiceError';
this.service = service;
}
}
export class GitError extends Error {
constructor(message) {
super(message);
this.name = 'GitError';
}
}
export class FileError extends Error {
constructor(message) {
super(message);
this.name = 'FileError';
}
}
/**
* 日志级别
*/
export var LogLevel;
(function (LogLevel) {
LogLevel[LogLevel["DEBUG"] = 0] = "DEBUG";
LogLevel[LogLevel["INFO"] = 1] = "INFO";
LogLevel[LogLevel["WARN"] = 2] = "WARN";
LogLevel[LogLevel["ERROR"] = 3] = "ERROR";
})(LogLevel || (LogLevel = {}));
/**
* 简单的日志记录器
*/
export class Logger {
logLevel;
logFile;
constructor(level = LogLevel.INFO, logFile) {
this.logLevel = level;
this.logFile = logFile;
// 如果没有指定日志文件,使用临时目录
if (!this.logFile) {
this.logFile = join(tmpdir(), 'coderocket-mcp.log');
}
}
/**
* 记录调试信息
*/
debug(message, context) {
this.log(LogLevel.DEBUG, message, context);
}
/**
* 记录信息
*/
info(message, context) {
this.log(LogLevel.INFO, message, context);
}
/**
* 记录警告
*/
warn(message, context) {
this.log(LogLevel.WARN, message, context);
}
/**
* 记录错误
*/
error(message, error, context) {
this.log(LogLevel.ERROR, message, context, error);
}
/**
* 核心日志记录方法
*/
async log(level, message, context, error) {
if (level < this.logLevel) {
return;
}
const entry = {
timestamp: new Date().toISOString(),
level,
message,
context,
error,
};
// 在 MCP 服务器模式下,只有在 DEBUG 模式或 WARN/ERROR 级别时才输出到控制台
// 这避免了 IDE 误认为 INFO 级别的日志是错误信息
const shouldOutputToConsole = process.env.DEBUG === 'true' || level >= LogLevel.WARN;
if (shouldOutputToConsole) {
const levelName = LogLevel[level];
const contextStr = context ? ` ${JSON.stringify(context)}` : '';
const errorStr = error ? ` Error: ${error.message}` : '';
// 所有控制台输出都使用 stderr 以避免污染 MCP 协议的 stdout
console.error(`[${entry.timestamp}] ${levelName}: ${message}${contextStr}${errorStr}`);
}
// 写入日志文件
if (this.logFile) {
try {
// 处理 Error 对象,避免循环结构
let logEntry = entry;
if (entry.error instanceof Error) {
logEntry = {
...entry,
error: {
name: entry.error.name,
message: entry.error.message,
stack: entry.error.stack,
},
};
}
const logLine = JSON.stringify(logEntry) + '\n';
await appendFile(this.logFile, logLine, 'utf-8');
}
catch (fileError) {
console.error('Failed to write to log file:', fileError);
}
}
}
/**
* 获取日志文件路径
*/
getLogFile() {
return this.logFile;
}
/**
* 设置日志级别
*/
setLevel(level) {
this.logLevel = level;
}
}
// 全局日志实例
export const logger = new Logger(process.env.NODE_ENV === 'development' ? LogLevel.DEBUG : LogLevel.INFO);
/**
* 错误处理工具类
*/
export class ErrorHandler {
logger;
constructor(logger) {
this.logger = logger;
}
/**
* 处理并格式化错误
*/
handleError(error, context) {
let formattedError;
if (error instanceof Error) {
formattedError = error;
}
else if (typeof error === 'string') {
formattedError = new Error(error);
}
else {
formattedError = new Error(`Unknown error: ${JSON.stringify(error)}`);
}
// 记录错误
this.logger.error(`${context ? `[${context}] ` : ''}${formattedError.message}`, formattedError, { context });
return formattedError;
}
/**
* 包装异步函数,自动处理错误
*/
wrapAsync(fn, context) {
return async (...args) => {
try {
return await fn(...args);
}
catch (error) {
throw this.handleError(error, context);
}
};
}
/**
* 创建用户友好的错误消息
*/
createUserFriendlyError(error, suggestions) {
// 根据错误类型提供不同的错误代码和建议
let errorCode = 'UNKNOWN_ERROR';
let userSuggestions = suggestions || [];
if (error instanceof GitError) {
errorCode = 'GIT_ERROR';
userSuggestions = [
'确保在Git仓库中执行',
'检查Git仓库状态',
'验证提交哈希是否存在',
...userSuggestions,
];
}
else if (error instanceof AIServiceError) {
errorCode = 'AI_SERVICE_ERROR';
userSuggestions = [
'检查AI服务配置',
'验证API密钥是否正确',
'确保网络连接正常',
'尝试切换到其他AI服务',
...userSuggestions,
];
}
else if (error instanceof FileError) {
errorCode = 'FILE_ERROR';
userSuggestions = [
'检查文件路径是否正确',
'确保文件存在且可读',
'验证文件权限',
...userSuggestions,
];
}
else if (error.message.includes('Shell command failed')) {
errorCode = 'SHELL_COMMAND_ERROR';
userSuggestions = [
'验证AI服务是否已配置',
'检查API密钥是否正确',
'确保有足够的权限执行命令',
...userSuggestions,
];
}
return {
error: error.message,
error_code: errorCode,
suggestions: userSuggestions,
};
}
}
// 全局错误处理器实例
export const errorHandler = new ErrorHandler(logger);
//# sourceMappingURL=logger.js.map