xiaozhi-client 1.6.8 → 1.6.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/Logger.ts","../src/ProxyMCPServer.ts","../src/services/TransportFactory.ts","../src/services/MCPService.ts","../src/adapters/ConfigAdapter.ts","../src/utils/mcpServerUtils.ts","../src/configManager.ts","../src/services/MCPServiceManager.ts","../src/services/MCPServiceManagerSingleton.ts","../src/services/XiaozhiConnectionManager.ts","../src/services/XiaozhiConnectionManagerSingleton.ts","../src/services/EventBus.ts","../src/services/ConfigService.ts","../src/handlers/ConfigApiHandler.ts","../src/handlers/HeartbeatHandler.ts","../src/handlers/RealtimeNotificationHandler.ts","../src/cli/Constants.ts","../src/cli/errors/ErrorMessages.ts","../src/cli/errors/index.ts","../src/cli/errors/ErrorHandlers.ts","../src/cli/utils/FileUtils.ts","../src/cli/utils/FormatUtils.ts","../src/cli/utils/PathUtils.ts","../src/cli/utils/PlatformUtils.ts","../src/cli/utils/Validation.ts","../src/cli/utils/VersionUtils.ts","../src/cli/services/ProcessManager.ts","../src/cli/services/DaemonManager.ts","../src/transports/TransportAdapter.ts","../src/transports/HTTPAdapter.ts","../src/transports/StdioAdapter.ts","../src/transports/WebSocketAdapter.ts","../src/core/MCPMessageHandler.ts","../src/core/UnifiedMCPServer.ts","../src/core/ServerFactory.ts","../src/services/MCPServer.ts","../src/cli/services/ServiceManager.ts","../src/cli/services/TemplateManager.ts","../src/cli/Container.ts","../src/handlers/ServiceApiHandler.ts","../src/handlers/StaticFileHandler.ts","../src/handlers/StatusApiHandler.ts","../src/services/NotificationService.ts","../src/services/StatusService.ts","../src/WebServer.ts","../src/WebServerStandalone.ts"],"sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport chalk from \"chalk\";\nimport pino from \"pino\";\nimport type { Logger as PinoLogger } from \"pino\";\n\n/**\n * 格式化日期时间为 YYYY-MM-DD HH:mm:ss 格式\n * @param date 要格式化的日期对象\n * @returns 格式化后的日期时间字符串\n */\nfunction formatDateTime(date: Date): string {\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, \"0\");\n const day = String(date.getDate()).padStart(2, \"0\");\n const hours = String(date.getHours()).padStart(2, \"0\");\n const minutes = String(date.getMinutes()).padStart(2, \"0\");\n const seconds = String(date.getSeconds()).padStart(2, \"0\");\n\n return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;\n}\n\n/**\n * 高性能日志记录器,基于 pino 实现\n *\n * 特性:\n * - 支持控制台和文件双重输出\n * - 支持守护进程模式(仅文件输出)\n * - 支持结构化日志记录\n * - 自动日志文件轮转和管理\n * - 高性能异步写入\n * - 完整的错误堆栈跟踪\n */\nexport class Logger {\n private logFilePath: string | null = null;\n private pinoInstance: PinoLogger;\n private isDaemonMode: boolean;\n private maxLogFileSize = 10 * 1024 * 1024; // 10MB 默认最大文件大小\n private maxLogFiles = 5; // 最多保留5个日志文件\n\n constructor() {\n // 检查是否为守护进程模式\n this.isDaemonMode = process.env.XIAOZHI_DAEMON === \"true\";\n\n // 创建 pino 实例\n this.pinoInstance = this.createPinoInstance();\n }\n\n private createPinoInstance(): PinoLogger {\n const streams: pino.StreamEntry[] = [];\n\n // 控制台流 - 只在非守护进程模式下添加\n if (!this.isDaemonMode) {\n // 使用高性能的控制台输出流\n const consoleStream = this.createOptimizedConsoleStream();\n streams.push({\n level: \"debug\",\n stream: consoleStream,\n });\n }\n\n // 文件流 - 如果有日志文件路径,使用高性能异步写入\n if (this.logFilePath) {\n streams.push({\n level: \"debug\",\n stream: pino.destination({\n dest: this.logFilePath,\n sync: false, // 异步写入提升性能\n append: true,\n mkdir: true,\n }),\n });\n }\n\n // 如果没有流,创建一个空的流避免错误\n if (streams.length === 0) {\n streams.push({\n level: \"debug\",\n stream: pino.destination({ dest: \"/dev/null\" }),\n });\n }\n\n return pino(\n {\n level: \"debug\",\n // 高性能配置\n timestamp:\n pino.stdTimeFunctions?.isoTime || (() => `,\"time\":${Date.now()}`),\n formatters: {\n // 优化级别格式化\n level: (_label: string, number: number) => ({ level: number }),\n },\n // 禁用不必要的功能以提升性能\n base: null, // 不包含 pid 和 hostname\n serializers: {\n // 优化错误序列化,在测试环境中安全处理\n err: pino.stdSerializers?.err || ((err: any) => err),\n },\n },\n pino.multistream(streams, { dedupe: true })\n );\n }\n\n private createOptimizedConsoleStream() {\n // 预编译级别映射以提升性能\n const levelMap = new Map([\n [20, { name: \"DEBUG\", color: chalk.gray }],\n [30, { name: \"INFO\", color: chalk.blue }],\n [40, { name: \"WARN\", color: chalk.yellow }],\n [50, { name: \"ERROR\", color: chalk.red }],\n [60, { name: \"FATAL\", color: chalk.red }],\n ]);\n\n return {\n write: (chunk: string) => {\n try {\n const logObj = JSON.parse(chunk);\n const message = this.formatConsoleMessageOptimized(logObj, levelMap);\n // 在测试环境中安全地写入\n this.safeWrite(`${message}\\n`);\n } catch (error) {\n // 如果解析失败,直接输出原始内容\n this.safeWrite(chunk);\n }\n },\n };\n }\n\n /**\n * 安全地写入到 stderr,在测试环境中避免错误\n */\n private safeWrite(content: string): void {\n try {\n if (process.stderr && typeof process.stderr.write === \"function\") {\n process.stderr.write(content);\n } else if (console && typeof console.error === \"function\") {\n // 在测试环境中回退到 console.error\n console.error(content.trim());\n }\n } catch (error) {\n // 在极端情况下静默失败,避免测试中断\n }\n }\n\n private formatConsoleMessageOptimized(\n logObj: any,\n levelMap: Map<number, { name: string; color: (text: string) => string }>\n ): string {\n const timestamp = formatDateTime(new Date());\n\n const levelInfo = levelMap.get(logObj.level) || {\n name: \"UNKNOWN\",\n color: (text: string) => text,\n };\n const coloredLevel = levelInfo.color(`[${levelInfo.name}]`);\n\n // 处理结构化日志中的 args,保持兼容性\n let message = logObj.msg;\n if (logObj.args && Array.isArray(logObj.args)) {\n const argsStr = logObj.args\n .map((arg: any) =>\n typeof arg === \"object\" ? JSON.stringify(arg) : String(arg)\n )\n .join(\" \");\n message = `${message} ${argsStr}`;\n }\n\n return `[${timestamp}] ${coloredLevel} ${message}`;\n }\n\n /**\n * 初始化日志文件\n * @param projectDir 项目目录\n */\n initLogFile(projectDir: string): void {\n this.logFilePath = path.join(projectDir, \"xiaozhi.log\");\n\n // 检查并轮转日志文件\n this.rotateLogFileIfNeeded();\n\n // 确保日志文件存在\n if (!fs.existsSync(this.logFilePath)) {\n fs.writeFileSync(this.logFilePath, \"\");\n }\n\n // 重新创建 pino 实例以包含文件流\n this.pinoInstance = this.createPinoInstance();\n }\n\n /**\n * 设置是否启用文件日志\n * @param enable 是否启用\n */\n enableFileLogging(enable: boolean): void {\n // 在 pino 实现中,文件日志的启用/禁用通过重新创建实例来实现\n // 这里保持方法兼容性,但实际上文件日志在 initLogFile 时就已经启用\n if (enable && this.logFilePath) {\n // 重新创建 pino 实例以确保文件流正确配置\n this.pinoInstance = this.createPinoInstance();\n }\n }\n\n /**\n * 记录信息级别日志\n * @param message 日志消息\n * @param args 额外参数\n * @example\n * logger.info('用户登录', 'userId', 12345);\n * logger.info({ userId: 12345, action: 'login' }, '用户登录');\n */\n info(message: string, ...args: any[]): void;\n /**\n * 记录结构化信息级别日志\n * @param obj 结构化日志对象\n * @param message 可选的日志消息\n */\n info(obj: object, message?: string): void;\n info(messageOrObj: string | object, ...args: any[]): void {\n if (typeof messageOrObj === \"string\") {\n if (args.length === 0) {\n this.pinoInstance.info(messageOrObj);\n } else {\n this.pinoInstance.info({ args }, messageOrObj);\n }\n } else {\n // 结构化日志支持\n this.pinoInstance.info(messageOrObj, args[0] || \"\");\n }\n }\n\n success(message: string, ...args: any[]): void;\n success(obj: object, message?: string): void;\n success(messageOrObj: string | object, ...args: any[]): void {\n // success 映射为 info 级别,保持 API 兼容性\n if (typeof messageOrObj === \"string\") {\n if (args.length === 0) {\n this.pinoInstance.info(messageOrObj);\n } else {\n this.pinoInstance.info({ args }, messageOrObj);\n }\n } else {\n this.pinoInstance.info(messageOrObj, args[0] || \"\");\n }\n }\n\n warn(message: string, ...args: any[]): void;\n warn(obj: object, message?: string): void;\n warn(messageOrObj: string | object, ...args: any[]): void {\n if (typeof messageOrObj === \"string\") {\n if (args.length === 0) {\n this.pinoInstance.warn(messageOrObj);\n } else {\n this.pinoInstance.warn({ args }, messageOrObj);\n }\n } else {\n this.pinoInstance.warn(messageOrObj, args[0] || \"\");\n }\n }\n\n error(message: string, ...args: any[]): void;\n error(obj: object, message?: string): void;\n error(messageOrObj: string | object, ...args: any[]): void {\n if (typeof messageOrObj === \"string\") {\n if (args.length === 0) {\n this.pinoInstance.error(messageOrObj);\n } else {\n // 改进错误处理 - 特殊处理 Error 对象\n const errorArgs = args.map((arg) => {\n if (arg instanceof Error) {\n return {\n message: arg.message,\n stack: arg.stack,\n name: arg.name,\n cause: arg.cause,\n };\n }\n return arg;\n });\n this.pinoInstance.error({ args: errorArgs }, messageOrObj);\n }\n } else {\n // 结构化错误日志,自动提取错误信息\n const enhancedObj = this.enhanceErrorObject(messageOrObj);\n this.pinoInstance.error(enhancedObj, args[0] || \"\");\n }\n }\n\n debug(message: string, ...args: any[]): void;\n debug(obj: object, message?: string): void;\n debug(messageOrObj: string | object, ...args: any[]): void {\n if (typeof messageOrObj === \"string\") {\n if (args.length === 0) {\n this.pinoInstance.debug(messageOrObj);\n } else {\n this.pinoInstance.debug({ args }, messageOrObj);\n }\n } else {\n this.pinoInstance.debug(messageOrObj, args[0] || \"\");\n }\n }\n\n log(message: string, ...args: any[]): void;\n log(obj: object, message?: string): void;\n log(messageOrObj: string | object, ...args: any[]): void {\n // log 方法使用 info 级别\n if (typeof messageOrObj === \"string\") {\n if (args.length === 0) {\n this.pinoInstance.info(messageOrObj);\n } else {\n this.pinoInstance.info({ args }, messageOrObj);\n }\n } else {\n this.pinoInstance.info(messageOrObj, args[0] || \"\");\n }\n }\n\n /**\n * 增强错误对象,提取更多错误信息\n */\n private enhanceErrorObject(obj: any): any {\n const enhanced = { ...obj };\n\n // 遍历对象属性,查找 Error 实例\n for (const [key, value] of Object.entries(enhanced)) {\n if (value instanceof Error) {\n enhanced[key] = {\n message: value.message,\n stack: value.stack,\n name: value.name,\n cause: value.cause,\n };\n }\n }\n\n return enhanced;\n }\n\n /**\n * 检查并轮转日志文件(如果需要)\n */\n private rotateLogFileIfNeeded(): void {\n if (!this.logFilePath || !fs.existsSync(this.logFilePath)) {\n return;\n }\n\n try {\n const stats = fs.statSync(this.logFilePath);\n if (stats.size > this.maxLogFileSize) {\n this.rotateLogFile();\n }\n } catch (error) {\n // 忽略文件状态检查错误\n }\n }\n\n /**\n * 轮转日志文件\n */\n private rotateLogFile(): void {\n if (!this.logFilePath) return;\n\n try {\n const logDir = path.dirname(this.logFilePath);\n const logName = path.basename(this.logFilePath, \".log\");\n\n // 移动现有的编号日志文件\n for (let i = this.maxLogFiles - 1; i >= 1; i--) {\n const oldFile = path.join(logDir, `${logName}.${i}.log`);\n const newFile = path.join(logDir, `${logName}.${i + 1}.log`);\n\n if (fs.existsSync(oldFile)) {\n if (i === this.maxLogFiles - 1) {\n // 删除最老的文件\n fs.unlinkSync(oldFile);\n } else {\n fs.renameSync(oldFile, newFile);\n }\n }\n }\n\n // 将当前日志文件重命名为 .1.log\n const firstRotatedFile = path.join(logDir, `${logName}.1.log`);\n fs.renameSync(this.logFilePath, firstRotatedFile);\n } catch (error) {\n // 轮转失败时忽略错误,继续使用当前文件\n }\n }\n\n /**\n * 清理旧的日志文件\n */\n cleanupOldLogs(): void {\n if (!this.logFilePath) return;\n\n try {\n const logDir = path.dirname(this.logFilePath);\n const logName = path.basename(this.logFilePath, \".log\");\n\n // 删除超过最大数量的日志文件\n for (let i = this.maxLogFiles + 1; i <= this.maxLogFiles + 10; i++) {\n const oldFile = path.join(logDir, `${logName}.${i}.log`);\n if (fs.existsSync(oldFile)) {\n fs.unlinkSync(oldFile);\n }\n }\n } catch (error) {\n // 忽略清理错误\n }\n }\n\n /**\n * 设置日志文件管理参数\n */\n setLogFileOptions(maxSize: number, maxFiles: number): void {\n this.maxLogFileSize = maxSize;\n this.maxLogFiles = maxFiles;\n }\n\n /**\n * 创建一个带标签的日志实例(已废弃,直接返回原实例)\n * @param tag 标签(不再使用)\n * @deprecated 标签功能已移除\n */\n withTag(_tag: string): Logger {\n // 不再添加标签,直接返回共享实例\n return this;\n }\n\n /**\n * 关闭日志文件流\n */\n close(): void {\n // pino 实例会自动处理流的关闭\n // 这里保持方法兼容性\n }\n}\n\n// 导出单例实例\nexport const logger = new Logger();\n","import type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport WebSocket from \"ws\";\nimport { type Logger, logger } from \"./Logger.js\";\n\nexport type { Tool };\n\n// MCP 消息接口\ninterface MCPMessage {\n jsonrpc: string;\n id?: number | string;\n method?: string;\n params?: any;\n result?: any;\n}\n\n// 连接状态枚举\nenum ConnectionState {\n DISCONNECTED = \"disconnected\",\n CONNECTING = \"connecting\",\n CONNECTED = \"connected\",\n RECONNECTING = \"reconnecting\",\n FAILED = \"failed\",\n}\n\n// 工具调用错误码枚举\nexport enum ToolCallErrorCode {\n INVALID_PARAMS = -32602, // 无效参数\n TOOL_NOT_FOUND = -32601, // 工具不存在\n TOOL_EXECUTION_ERROR = -32000, // 工具执行错误\n SERVICE_UNAVAILABLE = -32001, // 服务不可用\n TIMEOUT = -32002, // 调用超时\n}\n\n// 工具调用错误类\nexport class ToolCallError extends Error {\n constructor(\n public code: ToolCallErrorCode,\n message: string,\n public data?: any\n ) {\n super(message);\n this.name = \"ToolCallError\";\n }\n}\n\n// 工具调用配置接口\ninterface ToolCallOptions {\n timeout?: number;\n retryAttempts?: number;\n retryDelay?: number;\n}\n\n// 性能指标接口\ninterface PerformanceMetrics {\n totalCalls: number;\n successfulCalls: number;\n failedCalls: number;\n averageResponseTime: number;\n minResponseTime: number;\n maxResponseTime: number;\n successRate: number;\n lastUpdated: Date;\n}\n\n// 调用记录接口\ninterface CallRecord {\n id: string;\n toolName: string;\n startTime: Date;\n endTime?: Date;\n duration?: number;\n success: boolean;\n errorCode?: number;\n errorMessage?: string;\n}\n\n// 重试配置接口\ninterface RetryConfig {\n maxAttempts: number;\n initialDelay: number;\n maxDelay: number;\n backoffMultiplier: number;\n retryableErrors: ToolCallErrorCode[];\n}\n\n// 重连配置接口\ninterface ReconnectOptions {\n enabled: boolean; // 是否启用自动重连\n maxAttempts: number; // 最大重连次数\n initialInterval: number; // 初始重连间隔(ms)\n maxInterval: number; // 最大重连间隔(ms)\n backoffStrategy: \"linear\" | \"exponential\" | \"fixed\"; // 退避策略\n backoffMultiplier: number; // 退避倍数\n timeout: number; // 单次连接超时时间(ms)\n jitter: boolean; // 是否添加随机抖动\n}\n\n// 重连状态接口\ninterface ReconnectState {\n attempts: number; // 当前重连次数\n nextInterval: number; // 下次重连间隔\n timer: NodeJS.Timeout | null; // 重连定时器\n lastError: Error | null; // 最后一次错误\n isManualDisconnect: boolean; // 是否为主动断开\n}\n\n// 服务器选项接口\ninterface ProxyMCPServerOptions {\n reconnect?: Partial<ReconnectOptions>;\n}\n\n// 服务器状态接口\ninterface ProxyMCPServerStatus {\n connected: boolean;\n initialized: boolean;\n url: string;\n availableTools: number;\n connectionState: ConnectionState;\n reconnectAttempts: number;\n lastError: string | null;\n}\n\nexport class ProxyMCPServer {\n private endpointUrl: string;\n private ws: WebSocket | null = null;\n private logger: Logger;\n private isConnected = false;\n private serverInitialized = false;\n\n // 工具管理\n private tools: Map<string, Tool> = new Map();\n\n // 连接状态管理\n private connectionState: ConnectionState = ConnectionState.DISCONNECTED;\n\n // 重连配置\n private reconnectOptions: ReconnectOptions;\n\n // 重连状态\n private reconnectState: ReconnectState = {\n attempts: 0,\n nextInterval: 0,\n timer: null,\n lastError: null,\n isManualDisconnect: false,\n };\n\n // 连接超时定时器\n private connectionTimeout: NodeJS.Timeout | null = null;\n\n // 性能监控\n private performanceMetrics: PerformanceMetrics = {\n totalCalls: 0,\n successfulCalls: 0,\n failedCalls: 0,\n averageResponseTime: 0,\n minResponseTime: Number.MAX_VALUE,\n maxResponseTime: 0,\n successRate: 0,\n lastUpdated: new Date(),\n };\n\n // 调用记录(保留最近100条)\n private callRecords: CallRecord[] = [];\n private readonly maxCallRecords = 100;\n\n // 重试配置\n private retryConfig: RetryConfig = {\n maxAttempts: 3,\n initialDelay: 1000,\n maxDelay: 10000,\n backoffMultiplier: 2,\n retryableErrors: [\n ToolCallErrorCode.SERVICE_UNAVAILABLE,\n ToolCallErrorCode.TIMEOUT,\n ],\n };\n\n // 工具调用配置\n private toolCallConfig: ToolCallOptions = {\n timeout: 30000,\n retryAttempts: 3,\n retryDelay: 1000,\n };\n\n constructor(endpointUrl: string, options?: ProxyMCPServerOptions) {\n this.endpointUrl = endpointUrl;\n this.logger = logger;\n\n // 初始化重连配置\n this.reconnectOptions = {\n enabled: true,\n maxAttempts: 10,\n initialInterval: 3000,\n maxInterval: 30000,\n backoffStrategy: \"exponential\",\n backoffMultiplier: 1.5,\n timeout: 10000,\n jitter: true,\n ...options?.reconnect,\n };\n\n this.reconnectState.nextInterval = this.reconnectOptions.initialInterval;\n }\n\n /**\n * 设置 MCPServiceManager 实例\n * @param serviceManager MCPServiceManager 实例\n */\n setServiceManager(serviceManager: any): void {\n // 临时存储在一个变量中,避免类型检查问题\n (this as any).serviceManager = serviceManager;\n this.logger.info(\"已设置 MCPServiceManager\");\n\n // 立即同步工具\n this.syncToolsFromServiceManager();\n }\n\n /**\n * 从 MCPServiceManager 同步工具\n * 优化版本:支持增量同步和错误恢复\n */\n syncToolsFromServiceManager(): void {\n const serviceManager = (this as any).serviceManager;\n if (!serviceManager) {\n this.logger.debug(\"MCPServiceManager 未设置,跳过工具同步\");\n return;\n }\n\n try {\n // 从 MCPServiceManager 获取所有工具\n const allTools = serviceManager.getAllTools();\n\n // 原子性更新:先构建新的工具映射,再替换\n const newTools = new Map<string, Tool>();\n\n for (const toolInfo of allTools) {\n newTools.set(toolInfo.name, {\n name: toolInfo.name,\n description: toolInfo.description,\n inputSchema: toolInfo.inputSchema,\n });\n }\n\n // 原子性替换\n this.tools = newTools;\n\n this.logger.info(`已从 MCPServiceManager 同步 ${this.tools.size} 个工具`);\n } catch (error) {\n this.logger.error(\n `同步工具失败: ${error instanceof Error ? error.message : String(error)}`\n );\n // 同步失败时保持现有工具不变,确保服务可用性\n }\n }\n\n /**\n * 添加单个工具\n * @param name 工具名称\n * @param tool 工具定义\n * @param options 工具选项(可选)\n * @returns 返回 this 支持链式调用\n */\n addTool(name: string, tool: Tool): this {\n this.validateTool(name, tool);\n this.tools.set(name, tool);\n this.logger.debug(`工具 '${name}' 已添加`);\n // TODO: 未来可以使用 options 参数来设置工具的启用状态、元数据等\n return this;\n }\n\n /**\n * 批量添加工具\n * @param tools 工具对象,键为工具名称,值为工具定义\n * @returns 返回 this 支持链式调用\n */\n addTools(tools: Record<string, Tool>): this {\n for (const [name, tool] of Object.entries(tools)) {\n this.addTool(name, tool);\n }\n return this;\n }\n\n /**\n * 移除单个工具\n * @param name 工具名称\n * @returns 返回 this 支持链式调用\n */\n removeTool(name: string): this {\n if (this.tools.delete(name)) {\n this.logger.debug(`工具 '${name}' 已移除`);\n } else {\n this.logger.warn(`尝试移除不存在的工具: '${name}'`);\n }\n return this;\n }\n\n /**\n * 获取当前所有工具列表\n * @returns 工具数组\n */\n getTools(): Tool[] {\n // 每次获取工具时都尝试从 MCPServiceManager 同步\n try {\n this.syncToolsFromServiceManager();\n } catch (error) {\n // 静默处理同步错误,不影响现有工具的返回\n }\n\n return Array.from(this.tools.values());\n }\n\n /**\n * 检查工具是否存在\n * @param name 工具名称\n * @returns 是否存在\n */\n hasTool(name: string): boolean {\n return this.tools.has(name);\n }\n\n /**\n * 验证工具的有效性\n * @param name 工具名称\n * @param tool 工具定义\n */\n private validateTool(name: string, tool: Tool): void {\n if (!name || typeof name !== \"string\" || name.trim() === \"\") {\n throw new Error(\"工具名称必须是非空字符串\");\n }\n\n if (this.tools.has(name)) {\n throw new Error(`工具 '${name}' 已存在`);\n }\n\n if (!tool || typeof tool !== \"object\") {\n throw new Error(\"工具必须是有效的对象\");\n }\n\n // 验证工具的必需字段\n if (!tool.name || typeof tool.name !== \"string\") {\n throw new Error(\"工具必须包含有效的 'name' 字段\");\n }\n\n if (!tool.description || typeof tool.description !== \"string\") {\n throw new Error(\"工具必须包含有效的 'description' 字段\");\n }\n\n if (!tool.inputSchema || typeof tool.inputSchema !== \"object\") {\n throw new Error(\"工具必须包含有效的 'inputSchema' 字段\");\n }\n\n // 验证 inputSchema 的基本结构\n if (!tool.inputSchema.type || !tool.inputSchema.properties) {\n throw new Error(\n \"工具的 inputSchema 必须包含 'type' 和 'properties' 字段\"\n );\n }\n }\n\n /**\n * 连接 MCP 接入点\n * @returns 连接成功后的 Promise\n */\n public async connect(): Promise<void> {\n // 连接前验证\n if (this.tools.size === 0) {\n throw new Error(\"未配置任何工具。请在连接前至少添加一个工具。\");\n }\n\n // 如果正在连接中,等待当前连接完成\n if (this.connectionState === ConnectionState.CONNECTING) {\n throw new Error(\"连接正在进行中,请等待连接完成\");\n }\n\n // 清理之前的连接\n this.cleanupConnection();\n\n // 重置手动断开标志\n this.reconnectState.isManualDisconnect = false;\n\n return this.attemptConnection();\n }\n\n /**\n * 尝试建立连接\n * @returns 连接成功后的 Promise\n */\n private async attemptConnection(): Promise<void> {\n this.connectionState = ConnectionState.CONNECTING;\n this.logger.info(\n `正在连接 MCP 接入点: ${this.endpointUrl} (尝试 ${\n this.reconnectState.attempts + 1\n }/${this.reconnectOptions.maxAttempts})`\n );\n\n return new Promise((resolve, reject) => {\n // 设置连接超时\n this.connectionTimeout = setTimeout(() => {\n const error = new Error(\n `连接超时 (${this.reconnectOptions.timeout}ms)`\n );\n this.handleConnectionError(error);\n reject(error);\n }, this.reconnectOptions.timeout);\n\n this.ws = new WebSocket(this.endpointUrl);\n\n this.ws.on(\"open\", () => {\n this.handleConnectionSuccess();\n resolve();\n });\n\n this.ws.on(\"message\", (data) => {\n try {\n const message: MCPMessage = JSON.parse(data.toString());\n this.handleMessage(message);\n } catch (error) {\n this.logger.error(\"MCP 消息解析错误:\", error);\n }\n });\n\n this.ws.on(\"close\", (code, reason) => {\n this.handleConnectionClose(code, reason.toString());\n });\n\n this.ws.on(\"error\", (error) => {\n this.handleConnectionError(error);\n reject(error);\n });\n });\n }\n\n /**\n * 处理连接成功\n */\n private handleConnectionSuccess(): void {\n // 清理连接超时定时器\n if (this.connectionTimeout) {\n clearTimeout(this.connectionTimeout);\n this.connectionTimeout = null;\n }\n\n this.isConnected = true;\n this.connectionState = ConnectionState.CONNECTED;\n\n // 重置重连状态\n this.reconnectState.attempts = 0;\n this.reconnectState.nextInterval = this.reconnectOptions.initialInterval;\n this.reconnectState.lastError = null;\n\n this.logger.info(\"MCP WebSocket 连接已建立\");\n }\n\n /**\n * 处理连接错误\n */\n private handleConnectionError(error: Error): void {\n // 清理连接超时定时器\n if (this.connectionTimeout) {\n clearTimeout(this.connectionTimeout);\n this.connectionTimeout = null;\n }\n\n this.reconnectState.lastError = error;\n this.logger.error(\"MCP WebSocket 错误:\", error.message);\n\n // 清理当前连接\n this.cleanupConnection();\n }\n\n /**\n * 处理连接关闭\n */\n private handleConnectionClose(code: number, reason: string): void {\n this.isConnected = false;\n this.serverInitialized = false;\n this.logger.info(`MCP 连接已关闭 (代码: ${code}, 原因: ${reason})`);\n\n // 如果是手动断开,不进行重连\n if (this.reconnectState.isManualDisconnect) {\n this.connectionState = ConnectionState.DISCONNECTED;\n return;\n }\n\n // 检查是否需要重连\n if (this.shouldReconnect()) {\n this.scheduleReconnect();\n } else {\n this.connectionState = ConnectionState.FAILED;\n this.logger.warn(\n `已达到最大重连次数 (${this.reconnectOptions.maxAttempts}),停止重连`\n );\n }\n }\n\n /**\n * 检查是否应该重连\n */\n private shouldReconnect(): boolean {\n return (\n this.reconnectOptions.enabled &&\n this.reconnectState.attempts < this.reconnectOptions.maxAttempts &&\n !this.reconnectState.isManualDisconnect\n );\n }\n\n /**\n * 安排重连\n */\n private scheduleReconnect(): void {\n this.connectionState = ConnectionState.RECONNECTING;\n this.reconnectState.attempts++;\n\n // 计算下次重连间隔\n this.calculateNextInterval();\n\n this.logger.info(\n `将在 ${this.reconnectState.nextInterval}ms 后进行第 ${this.reconnectState.attempts} 次重连`\n );\n\n // 清理之前的重连定时器\n if (this.reconnectState.timer) {\n clearTimeout(this.reconnectState.timer);\n }\n\n // 设置重连定时器\n this.reconnectState.timer = setTimeout(async () => {\n try {\n await this.attemptConnection();\n } catch (error) {\n // 连接失败会触发 handleConnectionError,无需额外处理\n }\n }, this.reconnectState.nextInterval);\n }\n\n /**\n * 计算下次重连间隔\n */\n private calculateNextInterval(): void {\n let interval: number;\n\n switch (this.reconnectOptions.backoffStrategy) {\n case \"fixed\":\n interval = this.reconnectOptions.initialInterval;\n break;\n\n case \"linear\":\n interval =\n this.reconnectOptions.initialInterval +\n this.reconnectState.attempts *\n this.reconnectOptions.backoffMultiplier *\n 1000;\n break;\n\n case \"exponential\":\n interval =\n this.reconnectOptions.initialInterval *\n this.reconnectOptions.backoffMultiplier **\n (this.reconnectState.attempts - 1);\n break;\n\n default:\n interval = this.reconnectOptions.initialInterval;\n }\n\n // 限制最大间隔\n interval = Math.min(interval, this.reconnectOptions.maxInterval);\n\n // 添加随机抖动\n if (this.reconnectOptions.jitter) {\n const jitterRange = interval * 0.1; // 10% 抖动\n const jitter = (Math.random() - 0.5) * 2 * jitterRange;\n interval += jitter;\n }\n\n this.reconnectState.nextInterval = Math.max(interval, 1000); // 最小1秒\n }\n\n /**\n * 清理连接资源\n */\n private cleanupConnection(): void {\n // 清理 WebSocket\n if (this.ws) {\n // 移除所有事件监听器,防止在关闭时触发错误事件\n this.ws.removeAllListeners();\n\n // 安全关闭 WebSocket\n try {\n if (this.ws.readyState === WebSocket.OPEN) {\n this.ws.close(1000, \"Cleaning up connection\");\n } else if (this.ws.readyState === WebSocket.CONNECTING) {\n this.ws.terminate(); // 强制终止正在连接的 WebSocket\n }\n } catch (error) {\n // 忽略关闭时的错误\n this.logger.debug(\"WebSocket 关闭时出现错误(已忽略):\", error);\n }\n\n this.ws = null;\n }\n\n // 清理连接超时定时器\n if (this.connectionTimeout) {\n clearTimeout(this.connectionTimeout);\n this.connectionTimeout = null;\n }\n\n // 重置连接状态\n this.isConnected = false;\n this.serverInitialized = false;\n }\n\n /**\n * 停止重连\n */\n private stopReconnect(): void {\n if (this.reconnectState.timer) {\n clearTimeout(this.reconnectState.timer);\n this.reconnectState.timer = null;\n }\n }\n\n private handleMessage(message: MCPMessage): void {\n this.logger.debug(\"收到 MCP 消息:\", JSON.stringify(message, null, 2));\n\n if (message.method) {\n this.handleServerRequest(message);\n }\n }\n\n private handleServerRequest(request: MCPMessage): void {\n switch (request.method) {\n case \"initialize\":\n case \"notifications/initialized\":\n this.sendResponse(request.id, {\n protocolVersion: \"2024-11-05\",\n capabilities: {\n tools: { listChanged: true },\n logging: {},\n },\n serverInfo: {\n name: \"xiaozhi-mcp-server\",\n version: \"1.0.0\",\n },\n });\n this.serverInitialized = true;\n this.logger.info(\"MCP 服务器初始化完成\");\n break;\n\n case \"tools/list\": {\n const toolsList = this.getTools();\n this.sendResponse(request.id, { tools: toolsList });\n this.logger.info(`MCP 工具列表已发送 (${toolsList.length}个工具)`);\n break;\n }\n\n case \"tools/call\": {\n // 异步处理工具调用,避免阻塞其他消息\n this.handleToolCall(request).catch((error) => {\n this.logger.error(\"处理工具调用时发生未捕获错误:\", error);\n });\n break;\n }\n\n case \"ping\":\n this.sendResponse(request.id, {});\n this.logger.debug(\"回应 MCP ping 消息\");\n break;\n\n default:\n this.logger.warn(`未知的 MCP 请求: ${request.method}`);\n }\n }\n\n private sendResponse(id: number | string | undefined, result: any): void {\n this.logger.debug(\n `尝试发送响应: id=${id}, isConnected=${this.isConnected}, wsReadyState=${this.ws?.readyState}`\n );\n\n if (this.isConnected && this.ws?.readyState === WebSocket.OPEN) {\n const response: MCPMessage = {\n jsonrpc: \"2.0\",\n id,\n result,\n };\n\n try {\n this.ws.send(JSON.stringify(response));\n this.logger.info(`响应已发送: id=${id}`, {\n responseSize: JSON.stringify(response).length,\n });\n } catch (error) {\n this.logger.error(`发送响应失败: id=${id}`, error);\n }\n } else {\n this.logger.error(`无法发送响应: id=${id}, 连接状态检查失败`, {\n isConnected: this.isConnected,\n wsReadyState: this.ws?.readyState,\n wsReadyStateText:\n this.ws?.readyState === WebSocket.OPEN\n ? \"OPEN\"\n : this.ws?.readyState === WebSocket.CONNECTING\n ? \"CONNECTING\"\n : this.ws?.readyState === WebSocket.CLOSING\n ? \"CLOSING\"\n : this.ws?.readyState === WebSocket.CLOSED\n ? \"CLOSED\"\n : \"UNKNOWN\",\n });\n\n // 尝试重新连接并发送响应\n if (!this.isConnected || this.ws?.readyState !== WebSocket.OPEN) {\n this.logger.warn(`尝试重新连接以发送响应: id=${id}`);\n this.scheduleReconnect();\n }\n }\n }\n\n /**\n * 获取 MCP 服务器状态\n * @returns 服务器状态\n */\n public getStatus(): ProxyMCPServerStatus {\n return {\n connected: this.isConnected,\n initialized: this.serverInitialized,\n url: this.endpointUrl,\n availableTools: this.tools.size,\n connectionState: this.connectionState,\n reconnectAttempts: this.reconnectState.attempts,\n lastError: this.reconnectState.lastError?.message || null,\n };\n }\n\n /**\n * 主动断开 MCP 连接\n */\n public disconnect(): void {\n this.logger.info(\"主动断开 MCP 连接\");\n\n // 标记为手动断开,阻止自动重连\n this.reconnectState.isManualDisconnect = true;\n\n // 停止重连定时器\n this.stopReconnect();\n\n // 清理连接资源\n this.cleanupConnection();\n\n // 设置状态为已断开\n this.connectionState = ConnectionState.DISCONNECTED;\n }\n\n /**\n * 手动重连 MCP 接入点\n */\n public async reconnect(): Promise<void> {\n this.logger.info(\"手动重连 MCP 接入点\");\n\n // 停止自动重连\n this.stopReconnect();\n\n // 重置重连状态\n this.reconnectState.attempts = 0;\n this.reconnectState.nextInterval = this.reconnectOptions.initialInterval;\n this.reconnectState.isManualDisconnect = false;\n\n // 清理现有连接\n this.cleanupConnection();\n\n // 尝试连接\n await this.connect();\n }\n\n /**\n * 启用自动重连\n */\n public enableReconnect(): void {\n this.reconnectOptions.enabled = true;\n this.logger.info(\"自动重连已启用\");\n }\n\n /**\n * 禁用自动重连\n */\n public disableReconnect(): void {\n this.reconnectOptions.enabled = false;\n this.stopReconnect();\n this.logger.info(\"自动重连已禁用\");\n }\n\n /**\n * 更新重连配置\n */\n public updateReconnectOptions(options: Partial<ReconnectOptions>): void {\n this.reconnectOptions = { ...this.reconnectOptions, ...options };\n this.logger.info(\"重连配置已更新\", options);\n }\n\n /**\n * 获取重连配置\n */\n public getReconnectOptions(): ReconnectOptions {\n return { ...this.reconnectOptions };\n }\n\n /**\n * 重置重连状态\n */\n public resetReconnectState(): void {\n this.stopReconnect();\n this.reconnectState.attempts = 0;\n this.reconnectState.nextInterval = this.reconnectOptions.initialInterval;\n this.reconnectState.lastError = null;\n this.logger.info(\"重连状态已重置\");\n }\n\n /**\n * 处理工具调用请求\n */\n private async handleToolCall(request: MCPMessage): Promise<void> {\n // 确保 request.id 存在且类型正确\n if (request.id === undefined || request.id === null) {\n throw new ToolCallError(\n ToolCallErrorCode.INVALID_PARAMS,\n \"请求 ID 不能为空\"\n );\n }\n\n // 保持原始 ID 类型(number | string),不进行类型转换\n const requestId = request.id;\n let callRecord: CallRecord | null = null;\n\n try {\n // 1. 验证请求格式\n const params = this.validateToolCallParams(request.params);\n\n // 2. 记录调用开始\n callRecord = this.recordCallStart(params.name, requestId);\n\n this.logger.info(`开始处理工具调用: ${params.name}`, {\n requestId,\n toolName: params.name,\n hasArguments: !!params.arguments,\n });\n\n // 3. 检查服务管理器是否可用\n const serviceManager = (this as any).serviceManager;\n if (!serviceManager) {\n throw new ToolCallError(\n ToolCallErrorCode.SERVICE_UNAVAILABLE,\n \"MCPServiceManager 未设置\"\n );\n }\n\n // 4. 执行工具调用(带重试机制)\n const result = await this.executeToolWithRetry(\n serviceManager,\n params.name,\n params.arguments || {}\n );\n\n // 5. 发送成功响应\n this.sendResponse(requestId, {\n content: result.content || [\n { type: \"text\", text: JSON.stringify(result) },\n ],\n isError: result.isError || false,\n });\n\n // 6. 记录调用成功\n if (callRecord) {\n this.recordCallEnd(callRecord, true);\n }\n\n this.logger.info(`工具调用成功: ${params.name}`, {\n requestId,\n duration: callRecord?.duration ? `${callRecord.duration}ms` : \"unknown\",\n });\n } catch (error) {\n // 7. 处理错误并发送错误响应\n if (callRecord) {\n const errorCode =\n error instanceof ToolCallError\n ? error.code\n : ToolCallErrorCode.TOOL_EXECUTION_ERROR;\n const errorMessage =\n error instanceof Error ? error.message : \"未知错误\";\n this.recordCallEnd(callRecord, false, errorCode, errorMessage);\n }\n\n this.handleToolCallError(error, requestId, callRecord?.duration || 0);\n }\n }\n\n /**\n * 验证工具调用参数\n */\n private validateToolCallParams(params: any): {\n name: string;\n arguments?: any;\n } {\n if (!params || typeof params !== \"object\") {\n throw new ToolCallError(\n ToolCallErrorCode.INVALID_PARAMS,\n \"请求参数必须是对象\"\n );\n }\n\n if (!params.name || typeof params.name !== \"string\") {\n throw new ToolCallError(\n ToolCallErrorCode.INVALID_PARAMS,\n \"工具名称必须是非空字符串\"\n );\n }\n\n if (\n params.arguments !== undefined &&\n (typeof params.arguments !== \"object\" || Array.isArray(params.arguments))\n ) {\n throw new ToolCallError(\n ToolCallErrorCode.INVALID_PARAMS,\n \"工具参数必须是对象\"\n );\n }\n\n return {\n name: params.name,\n arguments: params.arguments,\n };\n }\n\n /**\n * 带重试机制的工具执行\n */\n private async executeToolWithRetry(\n serviceManager: any,\n toolName: string,\n arguments_: any\n ): Promise<any> {\n let lastError: ToolCallError | null = null;\n\n for (let attempt = 1; attempt <= this.retryConfig.maxAttempts; attempt++) {\n try {\n return await this.executeToolWithTimeout(\n serviceManager,\n toolName,\n arguments_,\n this.toolCallConfig.timeout\n );\n } catch (error) {\n // 确保错误是 ToolCallError 类型\n if (error instanceof ToolCallError) {\n lastError = error;\n } else {\n // 如果不是 ToolCallError,转换为 ToolCallError\n lastError = new ToolCallError(\n ToolCallErrorCode.TOOL_EXECUTION_ERROR,\n error instanceof Error ? error.message : \"未知错误\"\n );\n }\n\n // 检查是否是可重试的错误\n if (\n this.retryConfig.retryableErrors.includes(lastError.code) &&\n attempt < this.retryConfig.maxAttempts\n ) {\n // 计算重试延迟\n const delay = Math.min(\n this.retryConfig.initialDelay *\n this.retryConfig.backoffMultiplier ** (attempt - 1),\n this.retryConfig.maxDelay\n );\n\n this.logger.warn(\n `工具调用失败,将在 ${delay}ms 后重试 (${attempt}/${this.retryConfig.maxAttempts})`,\n {\n toolName,\n error: lastError.message,\n attempt,\n delay,\n }\n );\n\n // 等待重试延迟\n await new Promise((resolve) => setTimeout(resolve, delay));\n continue;\n }\n\n // 不可重试的错误或已达到最大重试次数\n break;\n }\n }\n\n // 所有重试都失败了,抛出最后一个错误\n throw lastError;\n }\n\n /**\n * 带超时控制的工具执行\n */\n private async executeToolWithTimeout(\n serviceManager: any,\n toolName: string,\n arguments_: any,\n timeoutMs = 30000\n ): Promise<any> {\n return new Promise((resolve, reject) => {\n // 设置超时定时器\n const timeoutId = setTimeout(() => {\n reject(\n new ToolCallError(\n ToolCallErrorCode.TIMEOUT,\n `工具调用超时 (${timeoutMs}ms): ${toolName}`\n )\n );\n }, timeoutMs);\n\n // 执行工具调用\n serviceManager\n .callTool(toolName, arguments_)\n .then((result: any) => {\n clearTimeout(timeoutId);\n resolve(result);\n })\n .catch((error: any) => {\n clearTimeout(timeoutId);\n\n // 将内部错误转换为工具调用错误\n if (error.message?.includes(\"未找到工具\")) {\n reject(\n new ToolCallError(\n ToolCallErrorCode.TOOL_NOT_FOUND,\n `工具不存在: ${toolName}`\n )\n );\n } else if (\n error.message?.includes(\"服务\") &&\n error.message?.includes(\"不可用\")\n ) {\n reject(\n new ToolCallError(\n ToolCallErrorCode.SERVICE_UNAVAILABLE,\n error.message\n )\n );\n } else if (error.message?.includes(\"暂时不可用\")) {\n // 处理临时性错误,标记为服务不可用(可重试)\n reject(\n new ToolCallError(\n ToolCallErrorCode.SERVICE_UNAVAILABLE,\n error.message\n )\n );\n } else if (error.message?.includes(\"持续不可用\")) {\n // 处理持续性错误,也标记为服务不可用(可重试)\n reject(\n new ToolCallError(\n ToolCallErrorCode.SERVICE_UNAVAILABLE,\n error.message\n )\n );\n } else {\n reject(\n new ToolCallError(\n ToolCallErrorCode.TOOL_EXECUTION_ERROR,\n `工具执行失败: ${error.message}`\n )\n );\n }\n });\n });\n }\n\n /**\n * 处理工具调用错误\n */\n private handleToolCallError(\n error: any,\n requestId: string | number | undefined,\n duration: number\n ): void {\n let errorResponse: any;\n\n if (error instanceof ToolCallError) {\n // 标准工具调用错误\n errorResponse = {\n code: error.code,\n message: error.message,\n data: error.data,\n };\n } else {\n // 未知错误\n errorResponse = {\n code: ToolCallErrorCode.TOOL_EXECUTION_ERROR,\n message: error?.message || \"未知错误\",\n data: { originalError: error?.toString() || \"null\" },\n };\n }\n\n // 发送错误响应\n this.sendErrorResponse(requestId, errorResponse);\n\n // 记录错误日志\n this.logger.error(\"工具调用失败\", {\n requestId,\n duration: `${duration}ms`,\n error: errorResponse,\n });\n }\n\n /**\n * 发送错误响应\n */\n private sendErrorResponse(\n id: string | number | undefined,\n error: { code: number; message: string; data?: any }\n ): void {\n if (this.isConnected && this.ws?.readyState === WebSocket.OPEN) {\n const response = {\n jsonrpc: \"2.0\",\n id,\n error,\n };\n this.ws.send(JSON.stringify(response));\n this.logger.debug(\"已发送错误响应:\", response);\n }\n }\n\n /**\n * 记录工具调用开始\n */\n private recordCallStart(\n toolName: string,\n requestId: string | number\n ): CallRecord {\n const record: CallRecord = {\n id: String(requestId), // 内部记录时转换为字符串,但不影响响应 ID 类型\n toolName,\n startTime: new Date(),\n success: false,\n };\n\n // 添加到记录列表\n this.callRecords.push(record);\n\n // 保持记录数量在限制内\n if (this.callRecords.length > this.maxCallRecords) {\n this.callRecords.shift();\n }\n\n return record;\n }\n\n /**\n * 记录工具调用结束\n */\n private recordCallEnd(\n record: CallRecord,\n success: boolean,\n errorCode?: number,\n errorMessage?: string\n ): void {\n record.endTime = new Date();\n record.duration = record.endTime.getTime() - record.startTime.getTime();\n record.success = success;\n record.errorCode = errorCode;\n record.errorMessage = errorMessage;\n\n // 更新性能指标\n this.updatePerformanceMetrics(record);\n }\n\n /**\n * 更新性能指标\n */\n private updatePerformanceMetrics(record: CallRecord): void {\n this.performanceMetrics.totalCalls++;\n\n if (record.success) {\n this.performanceMetrics.successfulCalls++;\n } else {\n this.performanceMetrics.failedCalls++;\n }\n\n if (record.duration !== undefined) {\n // 更新响应时间统计\n if (record.duration < this.performanceMetrics.minResponseTime) {\n this.performanceMetrics.minResponseTime = record.duration;\n }\n if (record.duration > this.performanceMetrics.maxResponseTime) {\n this.performanceMetrics.maxResponseTime = record.duration;\n }\n\n // 计算平均响应时间\n const totalTime = this.callRecords\n .filter((r) => r.duration !== undefined)\n .reduce((sum, r) => sum + (r.duration || 0), 0);\n const completedCalls = this.callRecords.filter(\n (r) => r.duration !== undefined\n ).length;\n this.performanceMetrics.averageResponseTime =\n completedCalls > 0 ? totalTime / completedCalls : 0;\n }\n\n // 计算成功率\n this.performanceMetrics.successRate =\n this.performanceMetrics.totalCalls > 0\n ? (this.performanceMetrics.successfulCalls /\n this.performanceMetrics.totalCalls) *\n 100\n : 0;\n\n this.performanceMetrics.lastUpdated = new Date();\n }\n\n /**\n * 获取性能指标\n */\n public getPerformanceMetrics(): PerformanceMetrics {\n return { ...this.performanceMetrics };\n }\n\n /**\n * 获取调用记录\n */\n public getCallRecords(limit?: number): CallRecord[] {\n const records = [...this.callRecords].reverse(); // 最新的在前\n return limit ? records.slice(0, limit) : records;\n }\n\n /**\n * 重置性能指标\n */\n public resetPerformanceMetrics(): void {\n this.performanceMetrics = {\n totalCalls: 0,\n successfulCalls: 0,\n failedCalls: 0,\n averageResponseTime: 0,\n minResponseTime: Number.MAX_VALUE,\n maxResponseTime: 0,\n successRate: 0,\n lastUpdated: new Date(),\n };\n this.callRecords = [];\n }\n\n /**\n * 更新工具调用配置\n */\n public updateToolCallConfig(config: Partial<ToolCallOptions>): void {\n this.toolCallConfig = { ...this.toolCallConfig, ...config };\n this.logger.info(\"工具调用配置已更新\", this.toolCallConfig);\n }\n\n /**\n * 更新重试配置\n */\n public updateRetryConfig(config: Partial<RetryConfig>): void {\n this.retryConfig = { ...this.retryConfig, ...config };\n this.logger.info(\"重试配置已更新\", this.retryConfig);\n }\n\n /**\n * 获取当前配置\n */\n public getConfiguration(): {\n toolCall: ToolCallOptions;\n retry: RetryConfig;\n } {\n return {\n toolCall: { ...this.toolCallConfig },\n retry: { ...this.retryConfig },\n };\n }\n\n /**\n * 获取服务器状态(增强版)\n */\n public getEnhancedStatus(): ProxyMCPServerStatus & {\n performance: PerformanceMetrics;\n configuration: {\n toolCall: ToolCallOptions;\n retry: RetryConfig;\n };\n } {\n return {\n connected: this.isConnected,\n initialized: this.serverInitialized,\n url: this.endpointUrl,\n availableTools: this.tools.size,\n connectionState: this.connectionState,\n reconnectAttempts: this.reconnectState.attempts,\n lastError: this.reconnectState.lastError?.message || null,\n performance: this.getPerformanceMetrics(),\n configuration: this.getConfiguration(),\n };\n }\n}\n","import {\n SSEClientTransport,\n type SSEClientTransportOptions,\n} from \"@modelcontextprotocol/sdk/client/sse.js\";\nimport { StdioClientTransport } from \"@modelcontextprotocol/sdk/client/stdio.js\";\nimport {\n StreamableHTTPClientTransport,\n type StreamableHTTPClientTransportOptions,\n} from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\nimport { EventSource } from \"eventsource\";\nimport { type Logger, logger } from \"../Logger.js\";\nimport { type MCPServiceConfig, MCPTransportType } from \"./MCPService.js\";\n\n// 全局 polyfill EventSource(用于 SSE)\nif (typeof global !== \"undefined\" && !global.EventSource) {\n (global as any).EventSource = EventSource;\n}\n\n// Transport 基础接口\nexport interface Transport {\n connect?(): Promise<void>;\n close?(): Promise<void>;\n}\n\n// 创建 logger 实例\nfunction getLogger(): Logger {\n return logger;\n}\n\n/**\n * 创建 transport 实例\n * @param config MCP 服务配置\n * @returns transport 实例\n */\nexport function createTransport(config: MCPServiceConfig): any {\n const logger = getLogger();\n logger.info(\n `[TransportFactory] 创建 ${config.type} transport for ${config.name}`\n );\n\n switch (config.type) {\n case MCPTransportType.STDIO:\n return createStdioTransport(config);\n\n case MCPTransportType.SSE:\n return createSSETransport(config);\n\n case MCPTransportType.MODELSCOPE_SSE:\n return createModelScopeSSETransport(config);\n\n case MCPTransportType.STREAMABLE_HTTP:\n return createStreamableHTTPTransport(config);\n\n default:\n throw new Error(`不支持的传输类型: ${config.type}`);\n }\n}\n\n/**\n * 创建 Stdio transport\n */\nfunction createStdioTransport(config: MCPServiceConfig): StdioClientTransport {\n if (!config.command) {\n throw new Error(\"stdio transport 需要 command 配置\");\n }\n\n return new StdioClientTransport({\n command: config.command,\n args: config.args || [],\n });\n}\n\n/**\n * 创建 SSE transport\n */\nfunction createSSETransport(config: MCPServiceConfig): SSEClientTransport {\n if (!config.url) {\n throw new Error(\"SSE transport 需要 URL 配置\");\n }\n\n const url = new URL(config.url);\n const options = createSSEOptions(config);\n\n return new SSEClientTransport(url, options);\n}\n\n/**\n * 创建 ModelScope SSE transport\n */\nfunction createModelScopeSSETransport(\n config: MCPServiceConfig\n): SSEClientTransport {\n if (!config.url) {\n throw new Error(\"ModelScope SSE transport 需要 URL 配置\");\n }\n\n if (!config.apiKey) {\n throw new Error(\"ModelScope SSE transport 需要 apiKey 配置\");\n }\n\n const url = new URL(config.url);\n const options = createModelScopeSSEOptions(config);\n\n return new SSEClientTransport(url, options);\n}\n\nfunction createStreamableHTTPTransport(\n config: MCPServiceConfig\n): StreamableHTTPClientTransport {\n if (!config.url) {\n throw new Error(\"StreamableHTTP transport 需要 URL 配置\");\n }\n\n const url = new URL(config.url);\n const options = createStreamableHTTPOptions(config);\n return new StreamableHTTPClientTransport(url, options);\n}\n\n/**\n * 创建 SSE 选项\n */\nfunction createSSEOptions(config: MCPServiceConfig): SSEClientTransportOptions {\n const options: any = {};\n\n // 添加认证头\n if (config.apiKey) {\n options.headers = {\n Authorization: `Bearer ${config.apiKey}`,\n ...config.headers,\n };\n } else if (config.headers) {\n options.headers = config.headers;\n }\n\n return options;\n}\n\n/**\n * 创建 ModelScope SSE 选项\n */\nfunction createModelScopeSSEOptions(config: MCPServiceConfig): any {\n const token = config.apiKey!; // 已在调用方验证过\n\n // 如果有自定义SSE选项,使用它们\n if (config.customSSEOptions) {\n return config.customSSEOptions;\n }\n\n // 默认的ModelScope SSE选项配置\n return {\n eventSourceInit: {\n fetch: async (url: string | URL | Request, init?: RequestInit) => {\n // 添加认证头\n const headers = {\n ...init?.headers,\n Authorization: `Bearer ${token}`,\n };\n\n return fetch(url, { ...init, headers });\n },\n },\n requestInit: {\n headers: {\n Authorization: `Bearer ${token}`,\n ...config.headers,\n },\n },\n };\n}\n\nfunction createStreamableHTTPOptions(\n config: MCPServiceConfig\n): StreamableHTTPClientTransportOptions {\n const options: any = {};\n\n // 添加认证头\n if (config.apiKey) {\n options.headers = {\n Authorization: `Bearer ${config.apiKey}`,\n ...config.headers,\n };\n } else if (config.headers) {\n options.headers = config.headers;\n }\n\n return options;\n}\n\n/**\n * 验证配置\n */\nexport function validateConfig(config: MCPServiceConfig): void {\n if (!config.name || typeof config.name !== \"string\") {\n throw new Error(\"配置必须包含有效的 name 字段\");\n }\n\n if (!config.type) {\n throw new Error(\"配置必须包含 type 字段\");\n }\n\n switch (config.type) {\n case MCPTransportType.STDIO:\n if (!config.command) {\n throw new Error(\"stdio 类型需要 command 字段\");\n }\n break;\n\n case MCPTransportType.SSE:\n case MCPTransportType.STREAMABLE_HTTP:\n if (!config.url) {\n throw new Error(`${config.type} 类型需要 url 字段`);\n }\n break;\n\n case MCPTransportType.MODELSCOPE_SSE:\n if (!config.url) {\n throw new Error(\"modelscope-sse 类型需要 url 字段\");\n }\n if (!config.apiKey) {\n throw new Error(\n \"modelscope-sse 类型需要 apiKey 字段。请在配置文件中设置 modelscope.apiKey 或确保服务配置包含 apiKey\"\n );\n }\n break;\n\n default:\n throw new Error(`不支持的传输类型: ${config.type}`);\n }\n}\n\n/**\n * 获取支持的传输类型列表\n */\nexport function getSupportedTypes(): MCPTransportType[] {\n return [\n MCPTransportType.STDIO,\n MCPTransportType.SSE,\n MCPTransportType.MODELSCOPE_SSE,\n MCPTransportType.STREAMABLE_HTTP,\n ];\n}\n\n/**\n * Transport 工厂对象(保持 API 兼容性)\n */\nexport const TransportFactory = {\n create: createTransport,\n validateConfig,\n getSupportedTypes,\n};\n","import { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport { type Logger, logger } from \"../Logger.js\";\nimport { TransportFactory } from \"./TransportFactory.js\";\n\n// 通信方式枚举\nexport enum MCPTransportType {\n STDIO = \"stdio\",\n SSE = \"sse\",\n STREAMABLE_HTTP = \"streamable-http\",\n MODELSCOPE_SSE = \"modelscope-sse\",\n}\n\n// 连接状态枚举\nexport enum ConnectionState {\n DISCONNECTED = \"disconnected\",\n CONNECTING = \"connecting\",\n CONNECTED = \"connected\",\n RECONNECTING = \"reconnecting\",\n FAILED = \"failed\",\n}\n\n// 重连配置接口\nexport interface ReconnectOptions {\n enabled: boolean;\n maxAttempts: number;\n initialInterval: number;\n maxInterval: number;\n backoffStrategy: \"linear\" | \"exponential\" | \"fixed\";\n backoffMultiplier: number;\n timeout: number;\n jitter: boolean;\n}\n\n// Ping配置接口\nexport interface PingOptions {\n enabled: boolean;\n interval: number; // ping间隔(毫秒)\n timeout: number; // ping超时(毫秒)\n maxFailures: number; // 最大连续失败次数\n startDelay: number; // 连接成功后开始ping的延迟(毫秒)\n}\n\n// ModelScope SSE 自定义选项接口\nexport interface ModelScopeSSEOptions {\n eventSourceInit?: {\n fetch?: (\n url: string | URL | Request,\n init?: RequestInit\n ) => Promise<Response>;\n };\n requestInit?: RequestInit;\n}\n\n// MCPService 配置接口\nexport interface MCPServiceConfig {\n name: string;\n type: MCPTransportType;\n // stdio 配置\n command?: string;\n args?: string[];\n // 网络配置\n url?: string;\n // 认证配置\n apiKey?: string;\n headers?: Record<string, string>;\n // ModelScope 特有配置\n modelScopeAuth?: boolean;\n customSSEOptions?: ModelScopeSSEOptions;\n // 重连配置\n reconnect?: Partial<ReconnectOptions>;\n // ping配置\n ping?: Partial<PingOptions>;\n // 超时配置\n timeout?: number;\n // 重试配置\n retryAttempts?: number;\n}\n\n// MCPService 状态接口\nexport interface MCPServiceStatus {\n name: string;\n connected: boolean;\n initialized: boolean;\n transportType: MCPTransportType;\n toolCount: number;\n lastError?: string;\n reconnectAttempts: number;\n connectionState: ConnectionState;\n // ping状态\n pingEnabled: boolean;\n lastPingTime?: Date;\n pingFailureCount: number;\n isPinging: boolean;\n}\n\n// MCPService 选项接口\nexport interface MCPServiceOptions {\n reconnect?: Partial<ReconnectOptions>;\n}\n\n// 重连状态接口\ninterface ReconnectState {\n attempts: number;\n nextInterval: number;\n timer: NodeJS.Timeout | null;\n lastError: Error | null;\n isManualDisconnect: boolean;\n}\n\n// 工具调用结果接口\nexport interface ToolCallResult {\n content: Array<{\n type: string;\n text: string;\n }>;\n isError?: boolean;\n}\n\n/**\n * MCP 服务类\n * 负责管理单个 MCP 服务的连接、工具管理和调用\n */\nexport class MCPService {\n private config: MCPServiceConfig;\n private client: Client | null = null;\n private transport: any = null;\n private tools: Map<string, Tool> = new Map();\n private connectionState: ConnectionState = ConnectionState.DISCONNECTED;\n private reconnectOptions: ReconnectOptions;\n private reconnectState: ReconnectState;\n private logger: Logger;\n private connectionTimeout: NodeJS.Timeout | null = null;\n private initialized = false;\n\n // Ping相关属性\n private pingOptions: PingOptions;\n private pingTimer: NodeJS.Timeout | null = null;\n private pingFailureCount = 0;\n private lastPingTime: Date | null = null;\n private isPinging = false;\n\n constructor(config: MCPServiceConfig, options?: MCPServiceOptions) {\n this.config = config;\n this.logger = logger;\n\n // 验证配置\n this.validateConfig();\n\n // 初始化重连配置\n this.reconnectOptions = {\n enabled: true,\n maxAttempts: 10,\n initialInterval: 3000,\n maxInterval: 30000,\n backoffStrategy: \"exponential\",\n backoffMultiplier: 1.5,\n timeout: 10000,\n jitter: true,\n ...options?.reconnect,\n ...config.reconnect,\n };\n\n // 初始化ping配置\n this.pingOptions = {\n enabled: true, // 默认启用\n interval: 30000, // 30秒\n timeout: 5000, // 5秒超时\n maxFailures: 3, // 最大连续失败3次\n startDelay: 5000, // 连接成功后5秒开始ping\n ...config.ping,\n };\n\n // 初始化重连状态\n this.reconnectState = {\n attempts: 0,\n nextInterval: this.reconnectOptions.initialInterval,\n timer: null,\n lastError: null,\n isManualDisconnect: false,\n };\n }\n\n /**\n * 带标签的日志方法\n */\n private logWithTag(\n level: \"info\" | \"error\" | \"warn\" | \"debug\",\n message: string,\n ...args: any[]\n ): void {\n const taggedMessage = `[MCP-${this.config.name}] ${message}`;\n this.logger[level](taggedMessage, ...args);\n }\n\n /**\n * 验证配置\n */\n private validateConfig(): void {\n // 使用 TransportFactory 进行配置验证\n TransportFactory.validateConfig(this.config);\n }\n\n /**\n * 连接到 MCP 服务\n */\n async connect(): Promise<void> {\n // 如果正在连接中,等待当前连接完成\n if (this.connectionState === ConnectionState.CONNECTING) {\n throw new Error(\"连接正在进行中,请等待连接完成\");\n }\n\n // 清理之前的连接\n this.cleanupConnection();\n\n // 重置手动断开标志\n this.reconnectState.isManualDisconnect = false;\n\n return this.attemptConnection();\n }\n\n /**\n * 尝试建立连接\n */\n private async attemptConnection(): Promise<void> {\n this.connectionState = ConnectionState.CONNECTING;\n this.logWithTag(\n \"info\",\n `正在连接 MCP 服务: ${this.config.name} (尝试 ${\n this.reconnectState.attempts + 1\n }/${this.reconnectOptions.maxAttempts})`\n );\n\n return new Promise((resolve, reject) => {\n // 设置连接超时\n this.connectionTimeout = setTimeout(() => {\n const error = new Error(\n `连接超时 (${this.reconnectOptions.timeout}ms)`\n );\n this.handleConnectionError(error);\n reject(error);\n }, this.reconnectOptions.timeout);\n\n try {\n this.client = new Client(\n {\n name: `xiaozhi-${this.config.name}-client`,\n version: \"1.0.0\",\n },\n {\n capabilities: {\n tools: {},\n },\n }\n );\n\n // 使用 TransportFactory 创建传输层\n this.transport = TransportFactory.create(this.config);\n\n // 连接到 MCP 服务\n this.client\n .connect(this.transport)\n .then(async () => {\n this.handleConnectionSuccess();\n\n // 获取工具列表\n await this.refreshTools();\n\n resolve();\n })\n .catch((error) => {\n this.handleConnectionError(error);\n reject(error);\n });\n } catch (error) {\n this.handleConnectionError(error as Error);\n reject(error);\n }\n });\n }\n\n /**\n * 处理连接成功\n */\n private handleConnectionSuccess(): void {\n // 清理连接超时定时器\n if (this.connectionTimeout) {\n clearTimeout(this.connectionTimeout);\n this.connectionTimeout = null;\n }\n\n this.connectionState = ConnectionState.CONNECTED;\n this.initialized = true;\n\n // 重置重连状态\n this.reconnectState.attempts = 0;\n this.reconnectState.nextInterval = this.reconnectOptions.initialInterval;\n this.reconnectState.lastError = null;\n\n // 重置ping状态\n this.resetPingState();\n\n this.logWithTag(\"info\", `MCP 服务 ${this.config.name} 连接已建立`);\n\n // 启动ping监控\n this.startPingMonitoring();\n }\n\n /**\n * 处理连接错误\n */\n private handleConnectionError(error: Error): void {\n // 清理连接超时定时器\n if (this.connectionTimeout) {\n clearTimeout(this.connectionTimeout);\n this.connectionTimeout = null;\n }\n\n this.reconnectState.lastError = error;\n this.logger.error(`MCP 服务 ${this.config.name} 连接错误:`, error.message);\n\n // 清理当前连接\n this.cleanupConnection();\n\n // 检查是否需要重连\n if (this.shouldReconnect()) {\n this.scheduleReconnect();\n } else {\n this.connectionState = ConnectionState.FAILED;\n this.logger.warn(\n `${this.config.name} 已达到最大重连次数 (${this.reconnectOptions.maxAttempts}),停止重连`\n );\n }\n }\n\n /**\n * 检查是否应该重连\n */\n private shouldReconnect(): boolean {\n return (\n this.reconnectOptions.enabled &&\n this.reconnectState.attempts < this.reconnectOptions.maxAttempts &&\n !this.reconnectState.isManualDisconnect\n );\n }\n\n /**\n * 安排重连\n */\n private scheduleReconnect(): void {\n this.connectionState = ConnectionState.RECONNECTING;\n this.reconnectState.attempts++;\n\n // 计算下次重连间隔\n this.calculateNextInterval();\n\n this.logger.info(\n `${this.config.name} 将在 ${this.reconnectState.nextInterval}ms 后进行第 ${this.reconnectState.attempts} 次重连`\n );\n\n // 清理之前的重连定时器\n if (this.reconnectState.timer) {\n clearTimeout(this.reconnectState.timer);\n }\n\n // 设置重连定时器\n this.reconnectState.timer = setTimeout(async () => {\n try {\n await this.attemptConnection();\n } catch (error) {\n // 连接失败会触发 handleConnectionError,无需额外处理\n }\n }, this.reconnectState.nextInterval);\n }\n\n /**\n * 计算下次重连间隔\n */\n private calculateNextInterval(): void {\n let interval: number;\n\n switch (this.reconnectOptions.backoffStrategy) {\n case \"fixed\":\n interval = this.reconnectOptions.initialInterval;\n break;\n\n case \"linear\":\n interval =\n this.reconnectOptions.initialInterval +\n this.reconnectState.attempts *\n this.reconnectOptions.backoffMultiplier *\n 1000;\n break;\n\n case \"exponential\":\n interval =\n this.reconnectOptions.initialInterval *\n this.reconnectOptions.backoffMultiplier **\n (this.reconnectState.attempts - 1);\n break;\n\n default:\n interval = this.reconnectOptions.initialInterval;\n }\n\n // 限制最大间隔\n interval = Math.min(interval, this.reconnectOptions.maxInterval);\n\n // 添加随机抖动\n if (this.reconnectOptions.jitter) {\n const jitterRange = interval * 0.1; // 10% 抖动\n const jitter = (Math.random() - 0.5) * 2 * jitterRange;\n interval += jitter;\n }\n\n this.reconnectState.nextInterval = Math.max(interval, 1000); // 最小1秒\n }\n\n /**\n * 清理连接资源\n */\n private cleanupConnection(): void {\n // 停止ping监控\n this.stopPingMonitoring();\n\n // 清理客户端\n if (this.client) {\n try {\n this.client.close().catch(() => {\n // 忽略关闭时的错误\n });\n } catch (error) {\n // 忽略关闭时的错误\n }\n this.client = null;\n }\n\n // 清理传输层\n this.transport = null;\n\n // 清理连接超时定时器\n if (this.connectionTimeout) {\n clearTimeout(this.connectionTimeout);\n this.connectionTimeout = null;\n }\n\n // 重置状态\n this.initialized = false;\n }\n\n /**\n * 停止重连\n */\n private stopReconnect(): void {\n if (this.reconnectState.timer) {\n clearTimeout(this.reconnectState.timer);\n this.reconnectState.timer = null;\n }\n }\n\n /**\n * 刷新工具列表\n */\n private async refreshTools(): Promise<void> {\n if (!this.client) {\n throw new Error(\"客户端未初始化\");\n }\n\n try {\n const toolsResult = await this.client.listTools();\n const tools: Tool[] = toolsResult.tools || [];\n\n // 清空现有工具\n this.tools.clear();\n\n // 注册工具到映射表\n for (const tool of tools) {\n this.tools.set(tool.name, tool);\n }\n\n this.logger.info(\n `${this.config.name} 服务加载了 ${tools.length} 个工具: ${tools\n .map((t) => t.name)\n .join(\", \")}`\n );\n } catch (error) {\n this.logger.error(\n `${this.config.name} 获取工具列表失败:`,\n error instanceof Error ? error.message : String(error)\n );\n throw error;\n }\n }\n\n /**\n * 断开连接\n */\n async disconnect(): Promise<void> {\n this.logger.info(`主动断开 MCP 服务 ${this.config.name} 连接`);\n\n // 标记为手动断开,阻止自动重连\n this.reconnectState.isManualDisconnect = true;\n\n // 停止ping监控\n this.stopPingMonitoring();\n\n // 停止重连定时器\n this.stopReconnect();\n\n // 清理连接资源\n this.cleanupConnection();\n\n // 设置状态为已断开\n this.connectionState = ConnectionState.DISCONNECTED;\n }\n\n /**\n * 手动重连\n */\n async reconnect(): Promise<void> {\n this.logger.info(`手动重连 MCP 服务 ${this.config.name}`);\n\n // 停止自动重连\n this.stopReconnect();\n\n // 重置重连状态\n this.reconnectState.attempts = 0;\n this.reconnectState.nextInterval = this.reconnectOptions.initialInterval;\n this.reconnectState.isManualDisconnect = false;\n\n // 清理现有连接\n this.cleanupConnection();\n\n // 尝试连接\n await this.connect();\n }\n\n /**\n * 获取工具列表\n */\n getTools(): Tool[] {\n return Array.from(this.tools.values());\n }\n\n /**\n * 调用工具\n */\n async callTool(name: string, arguments_: any): Promise<ToolCallResult> {\n if (!this.client) {\n throw new Error(`服务 ${this.config.name} 未连接`);\n }\n\n if (!this.tools.has(name)) {\n throw new Error(`工具 ${name} 在服务 ${this.config.name} 中不存在`);\n }\n\n this.logger.info(\n `调用 ${this.config.name} 服务的工具 ${name},参数:`,\n JSON.stringify(arguments_)\n );\n\n try {\n const result = await this.client.callTool({\n name,\n arguments: arguments_ || {},\n });\n\n this.logger.info(\n `工具 ${name} 调用成功,结果:`,\n `${JSON.stringify(result).substring(0, 500)}...`\n );\n\n return result as ToolCallResult;\n } catch (error) {\n this.logger.error(\n `工具 ${name} 调用失败:`,\n error instanceof Error ? error.message : String(error)\n );\n throw error;\n }\n }\n\n /**\n * 获取服务配置\n */\n getConfig(): MCPServiceConfig {\n return this.config;\n }\n\n /**\n * 获取服务状态\n */\n getStatus(): MCPServiceStatus {\n return {\n name: this.config.name,\n connected: this.connectionState === ConnectionState.CONNECTED,\n initialized: this.initialized,\n transportType: this.config.type,\n toolCount: this.tools.size,\n lastError: this.reconnectState.lastError?.message,\n reconnectAttempts: this.reconnectState.attempts,\n connectionState: this.connectionState,\n // ping状态\n pingEnabled: this.pingOptions.enabled,\n lastPingTime: this.lastPingTime || undefined,\n pingFailureCount: this.pingFailureCount,\n isPinging: this.isPinging,\n };\n }\n\n /**\n * 检查是否已连接\n */\n isConnected(): boolean {\n return (\n this.connectionState === ConnectionState.CONNECTED && this.initialized\n );\n }\n\n /**\n * 启用自动重连\n */\n enableReconnect(): void {\n this.reconnectOptions.enabled = true;\n this.logger.info(`${this.config.name} 自动重连已启用`);\n }\n\n /**\n * 禁用自动重连\n */\n disableReconnect(): void {\n this.reconnectOptions.enabled = false;\n this.stopReconnect();\n this.logger.info(`${this.config.name} 自动重连已禁用`);\n }\n\n /**\n * 更新重连配置\n */\n updateReconnectOptions(options: Partial<ReconnectOptions>): void {\n this.reconnectOptions = { ...this.reconnectOptions, ...options };\n this.logger.info(`${this.config.name} 重连配置已更新`, options);\n }\n\n /**\n * 获取重连配置\n */\n getReconnectOptions(): ReconnectOptions {\n return { ...this.reconnectOptions };\n }\n\n /**\n * 重置重连状态\n */\n resetReconnectState(): void {\n this.stopReconnect();\n this.reconnectState.attempts = 0;\n this.reconnectState.nextInterval = this.reconnectOptions.initialInterval;\n this.reconnectState.lastError = null;\n this.logger.info(`${this.config.name} 重连状态已重置`);\n }\n\n /**\n * 启动ping监控\n */\n private startPingMonitoring(): void {\n if (!this.pingOptions.enabled || this.pingTimer || !this.isConnected()) {\n return;\n }\n\n this.logger.info(\n `${this.config.name} 启动ping监控,间隔: ${this.pingOptions.interval}ms`\n );\n\n // 延迟启动ping,让连接稳定\n setTimeout(() => {\n if (this.isConnected() && !this.pingTimer) {\n this.pingTimer = setInterval(() => {\n this.performPing();\n }, this.pingOptions.interval);\n }\n }, this.pingOptions.startDelay);\n }\n\n /**\n * 停止ping监控\n */\n private stopPingMonitoring(): void {\n if (this.pingTimer) {\n clearInterval(this.pingTimer);\n this.pingTimer = null;\n this.logger.debug(`${this.config.name} 停止ping监控`);\n }\n }\n\n /**\n * 执行ping检查\n */\n private async performPing(): Promise<void> {\n if (!this.client || this.isPinging || !this.isConnected()) {\n return;\n }\n\n this.isPinging = true;\n const startTime = performance.now();\n\n try {\n this.logger.debug(\n `${this.config.name} 发送ping请求(通过listTools检测连接)`\n );\n\n // 使用Promise.race实现超时控制\n // 由于MCP SDK可能没有直接的ping方法,我们使用listTools作为连接检测\n // 这是一个轻量级的操作,可以有效检测连接状态\n const pingPromise = this.client.listTools();\n\n const timeoutPromise = new Promise((_, reject) => {\n setTimeout(() => {\n reject(new Error(`Ping超时 (${this.pingOptions.timeout}ms)`));\n }, this.pingOptions.timeout);\n });\n\n await Promise.race([pingPromise, timeoutPromise]);\n\n const duration = performance.now() - startTime;\n this.handlePingSuccess(duration);\n } catch (error) {\n const duration = performance.now() - startTime;\n this.handlePingFailure(error as Error, duration);\n } finally {\n this.isPinging = false;\n }\n }\n\n /**\n * 处理ping成功\n */\n private handlePingSuccess(duration: number): void {\n this.pingFailureCount = 0;\n this.lastPingTime = new Date();\n this.logger.debug(\n `${this.config.name} ping成功,延迟: ${duration.toFixed(2)}ms`\n );\n }\n\n /**\n * 处理ping失败\n */\n private handlePingFailure(error: Error, duration: number): void {\n this.pingFailureCount++;\n this.logger.warn(\n `${this.config.name} ping失败 (${this.pingFailureCount}/${this.pingOptions.maxFailures}),` +\n `延迟: ${duration.toFixed(2)}ms,错误: ${error.message}`\n );\n\n // 如果连续失败次数达到阈值,触发重连\n if (this.pingFailureCount >= this.pingOptions.maxFailures) {\n this.logger.error(\n `${this.config.name} 连续ping失败达到阈值,触发重连机制`\n );\n\n // 停止ping监控,避免干扰重连过程\n this.stopPingMonitoring();\n\n // 创建连接错误并触发现有的重连机制\n const connectionError = new Error(\n `Ping检测失败,连续失败${this.pingFailureCount}次,连接可能已断开`\n );\n this.handleConnectionError(connectionError);\n }\n }\n\n /**\n * 重置ping状态\n */\n private resetPingState(): void {\n this.pingFailureCount = 0;\n this.lastPingTime = null;\n this.isPinging = false;\n }\n\n /**\n * 启用ping监控\n */\n enablePing(): void {\n this.pingOptions.enabled = true;\n this.logger.info(`${this.config.name} ping监控已启用`);\n\n // 如果当前已连接,立即启动ping监控\n if (this.isConnected()) {\n this.startPingMonitoring();\n }\n }\n\n /**\n * 禁用ping监控\n */\n disablePing(): void {\n this.pingOptions.enabled = false;\n this.stopPingMonitoring();\n this.logger.info(`${this.config.name} ping监控已禁用`);\n }\n\n /**\n * 更新ping配置\n */\n updatePingOptions(options: Partial<PingOptions>): void {\n const wasEnabled = this.pingOptions.enabled;\n this.pingOptions = { ...this.pingOptions, ...options };\n\n this.logger.info(`${this.config.name} ping配置已更新`, options);\n\n // 如果启用状态发生变化,相应地启动或停止监控\n if (wasEnabled !== this.pingOptions.enabled) {\n if (this.pingOptions.enabled && this.isConnected()) {\n this.startPingMonitoring();\n } else if (!this.pingOptions.enabled) {\n this.stopPingMonitoring();\n }\n }\n }\n\n /**\n * 获取ping配置\n */\n getPingOptions(): PingOptions {\n return { ...this.pingOptions };\n }\n}\n","/**\n * 配置适配器\n * 将旧的配置格式转换为新的 MCPServiceConfig 格式,确保向后兼容性\n */\n\nimport { isAbsolute, resolve } from \"node:path\";\nimport { logger as globalLogger } from \"../Logger.js\";\nimport type {\n LocalMCPServerConfig,\n MCPServerConfig,\n SSEMCPServerConfig,\n StreamableHTTPMCPServerConfig,\n} from \"../configManager.js\";\nimport type { MCPServiceConfig } from \"../services/MCPService.js\";\nimport { MCPTransportType } from \"../services/MCPService.js\";\n\n// 为配置适配器创建带标签的 logger\nconst logger = globalLogger.withTag(\"ConfigAdapter\");\n\n/**\n * 配置验证错误类\n */\nexport class ConfigValidationError extends Error {\n constructor(\n message: string,\n public readonly configName?: string\n ) {\n super(message);\n this.name = \"ConfigValidationError\";\n }\n}\n\n/**\n * 将旧的 MCPServerConfig 转换为新的 MCPServiceConfig\n */\nexport function convertLegacyToNew(\n serviceName: string,\n legacyConfig: MCPServerConfig\n): MCPServiceConfig {\n logger.debug(`转换配置: ${serviceName}`, legacyConfig);\n\n try {\n // 验证输入参数\n if (!serviceName || typeof serviceName !== \"string\") {\n throw new ConfigValidationError(\"服务名称必须是非空字符串\");\n }\n\n if (!legacyConfig || typeof legacyConfig !== \"object\") {\n throw new ConfigValidationError(\"配置对象不能为空\", serviceName);\n }\n\n // 根据配置类型进行转换\n const newConfig = convertByConfigType(serviceName, legacyConfig);\n\n // 验证转换后的配置\n validateNewConfig(newConfig);\n\n logger.info(`配置转换成功: ${serviceName} -> ${newConfig.type}`);\n return newConfig;\n } catch (error) {\n logger.error(`配置转换失败: ${serviceName}`, error);\n throw error instanceof ConfigValidationError\n ? error\n : new ConfigValidationError(\n `配置转换失败: ${error instanceof Error ? error.message : String(error)}`,\n serviceName\n );\n }\n}\n\n/**\n * 根据配置类型进行转换\n */\nfunction convertByConfigType(\n serviceName: string,\n legacyConfig: MCPServerConfig\n): MCPServiceConfig {\n // 检查是否为本地 stdio 配置\n if (isLocalConfig(legacyConfig)) {\n return convertLocalConfig(serviceName, legacyConfig);\n }\n\n // 检查是否为 SSE 配置\n if (isSSEConfig(legacyConfig)) {\n return convertSSEConfig(serviceName, legacyConfig);\n }\n\n // 检查是否为 Streamable HTTP 配置\n if (isStreamableHTTPConfig(legacyConfig)) {\n return convertStreamableHTTPConfig(serviceName, legacyConfig);\n }\n\n throw new ConfigValidationError(\"无法识别的配置类型\", serviceName);\n}\n\n/**\n * 转换本地 stdio 配置\n */\nfunction convertLocalConfig(\n serviceName: string,\n config: LocalMCPServerConfig\n): MCPServiceConfig {\n if (!config.command) {\n throw new ConfigValidationError(\n \"本地配置必须包含 command 字段\",\n serviceName\n );\n }\n\n // 获取用户的工作目录(优先使用环境变量,否则使用当前工作目录)\n const workingDir = process.env.XIAOZHI_CONFIG_DIR || process.cwd();\n\n // 解析 args 中的相对路径\n const resolvedArgs = (config.args || []).map((arg) => {\n // 检查是否为相对路径(以 ./ 开头或不以 / 开头且包含文件扩展名)\n if (isRelativePath(arg)) {\n const resolvedPath = resolve(workingDir, arg);\n logger.debug(`解析相对路径: ${arg} -> ${resolvedPath}`);\n return resolvedPath;\n }\n return arg;\n });\n\n return {\n name: serviceName,\n type: MCPTransportType.STDIO,\n command: config.command,\n args: resolvedArgs,\n // 默认重连配置\n reconnect: {\n enabled: true,\n maxAttempts: 5,\n initialInterval: 3000,\n maxInterval: 30000,\n backoffStrategy: \"exponential\" as const,\n backoffMultiplier: 1.5,\n timeout: 10000,\n jitter: true,\n },\n // 默认 ping 配置\n ping: {\n enabled: true,\n interval: 30000,\n timeout: 5000,\n maxFailures: 3,\n startDelay: 5000,\n },\n timeout: 30000,\n };\n}\n\n/**\n * 转换 SSE 配置\n */\nfunction convertSSEConfig(\n serviceName: string,\n config: SSEMCPServerConfig\n): MCPServiceConfig {\n if (!config.url) {\n throw new ConfigValidationError(\"SSE 配置必须包含 url 字段\", serviceName);\n }\n\n // 检查是否为 ModelScope 服务\n const isModelScope = isModelScopeURL(config.url);\n\n const baseConfig: MCPServiceConfig = {\n name: serviceName,\n type: isModelScope ? MCPTransportType.MODELSCOPE_SSE : MCPTransportType.SSE,\n url: config.url,\n // 默认重连配置\n reconnect: {\n enabled: true,\n maxAttempts: 10,\n initialInterval: 3000,\n maxInterval: 30000,\n backoffStrategy: \"exponential\" as const,\n backoffMultiplier: 1.5,\n timeout: 15000,\n jitter: true,\n },\n // 默认 ping 配置\n ping: {\n enabled: true,\n interval: 30000,\n timeout: 5000,\n maxFailures: 3,\n startDelay: 5000,\n },\n timeout: 30000,\n };\n\n // 如果是 ModelScope 服务,添加特殊配置\n if (isModelScope) {\n baseConfig.modelScopeAuth = true;\n }\n\n return baseConfig;\n}\n\n/**\n * 转换 Streamable HTTP 配置\n */\nfunction convertStreamableHTTPConfig(\n serviceName: string,\n config: StreamableHTTPMCPServerConfig\n): MCPServiceConfig {\n if (!config.url) {\n throw new ConfigValidationError(\n \"Streamable HTTP 配置必须包含 url 字段\",\n serviceName\n );\n }\n\n return {\n name: serviceName,\n type: MCPTransportType.STREAMABLE_HTTP,\n url: config.url,\n // 默认重连配置\n reconnect: {\n enabled: true,\n maxAttempts: 5,\n initialInterval: 3000,\n maxInterval: 30000,\n backoffStrategy: \"exponential\" as const,\n backoffMultiplier: 1.5,\n timeout: 15000,\n jitter: true,\n },\n // 默认 ping 配置\n ping: {\n enabled: false, // HTTP 连接通常不需要 ping\n interval: 60000,\n timeout: 10000,\n maxFailures: 3,\n startDelay: 10000,\n },\n timeout: 30000,\n };\n}\n\n/**\n * 批量转换配置\n */\nexport function convertLegacyConfigBatch(\n legacyConfigs: Record<string, MCPServerConfig>\n): Record<string, MCPServiceConfig> {\n const newConfigs: Record<string, MCPServiceConfig> = {};\n const errors: Array<{ serviceName: string; error: Error }> = [];\n\n for (const [serviceName, legacyConfig] of Object.entries(legacyConfigs)) {\n try {\n newConfigs[serviceName] = convertLegacyToNew(serviceName, legacyConfig);\n } catch (error) {\n errors.push({\n serviceName,\n error: error instanceof Error ? error : new Error(String(error)),\n });\n }\n }\n\n if (errors.length > 0) {\n const errorMessages = errors\n .map(({ serviceName, error }) => `${serviceName}: ${error.message}`)\n .join(\"; \");\n throw new ConfigValidationError(`批量配置转换失败: ${errorMessages}`);\n }\n\n logger.info(\n `批量配置转换成功,共转换 ${Object.keys(newConfigs).length} 个服务`\n );\n return newConfigs;\n}\n\n/**\n * 检查是否为相对路径\n */\nfunction isRelativePath(path: string): boolean {\n // 使用 Node.js 的 path.isAbsolute() 来正确检测绝对路径\n // 这个方法能够正确处理 Windows、macOS、Linux 三个平台的路径格式\n if (isAbsolute(path)) {\n return false; // 绝对路径不是相对路径\n }\n\n // 检查是否为相对路径的条件:\n // 1. 以 ./ 或 ../ 开头\n // 2. 包含常见的脚本文件扩展名(且不是绝对路径)\n if (path.startsWith(\"./\") || path.startsWith(\"../\")) {\n return true;\n }\n\n // 如果包含文件扩展名且不是绝对路径,也认为是相对路径\n if (/\\.(js|py|ts|mjs|cjs)$/i.test(path)) {\n return true;\n }\n\n return false;\n}\n\n/**\n * 检查是否为本地配置\n */\nfunction isLocalConfig(\n config: MCPServerConfig\n): config is LocalMCPServerConfig {\n return \"command\" in config && typeof config.command === \"string\";\n}\n\n/**\n * 检查是否为 SSE 配置\n */\nfunction isSSEConfig(config: MCPServerConfig): config is SSEMCPServerConfig {\n return \"type\" in config && config.type === \"sse\" && \"url\" in config;\n}\n\n/**\n * 检查是否为 Streamable HTTP 配置\n */\nfunction isStreamableHTTPConfig(\n config: MCPServerConfig\n): config is StreamableHTTPMCPServerConfig {\n return (\n \"url\" in config &&\n (!(\"type\" in config) || config.type === \"streamable-http\")\n );\n}\n\n/**\n * 检查是否为 ModelScope URL\n */\nfunction isModelScopeURL(url: string): boolean {\n return url.includes(\"modelscope.net\") || url.includes(\"modelscope.cn\");\n}\n\n/**\n * 验证新配置格式\n */\nfunction validateNewConfig(config: MCPServiceConfig): void {\n if (!config.name || typeof config.name !== \"string\") {\n throw new ConfigValidationError(\"配置必须包含有效的 name 字段\");\n }\n\n if (!Object.values(MCPTransportType).includes(config.type)) {\n throw new ConfigValidationError(`无效的传输类型: ${config.type}`);\n }\n\n // 根据传输类型验证必需字段\n switch (config.type) {\n case MCPTransportType.STDIO:\n if (!config.command) {\n throw new ConfigValidationError(\"STDIO 配置必须包含 command 字段\");\n }\n break;\n\n case MCPTransportType.SSE:\n case MCPTransportType.MODELSCOPE_SSE:\n case MCPTransportType.STREAMABLE_HTTP:\n if (!config.url) {\n throw new ConfigValidationError(`${config.type} 配置必须包含 url 字段`);\n }\n break;\n\n default:\n throw new ConfigValidationError(`不支持的传输类型: ${config.type}`);\n }\n}\n\n/**\n * 获取配置类型描述\n */\nexport function getConfigTypeDescription(config: MCPServerConfig): string {\n if (isLocalConfig(config)) {\n return `本地进程 (${config.command})`;\n }\n if (isSSEConfig(config)) {\n const isModelScope = isModelScopeURL(config.url);\n return `SSE${isModelScope ? \" (ModelScope)\" : \"\"} (${config.url})`;\n }\n if (isStreamableHTTPConfig(config)) {\n return `Streamable HTTP (${config.url})`;\n }\n return \"未知类型\";\n}\n","/**\n * MCP 服务工具函数 - 服务端版本\n * 用于判断 MCP 服务的通信类型和其他相关操作\n */\n\n// 定义通信类型\nexport type MCPCommunicationType = \"stdio\" | \"sse\" | \"streamable-http\";\n\n// 定义 MCP 服务配置类型(与客户端保持一致)\nexport interface LocalMCPServerConfig {\n command: string;\n args: string[];\n env?: Record<string, string>;\n}\n\nexport interface SSEMCPServerConfig {\n type: \"sse\";\n url: string;\n}\n\nexport interface StreamableHTTPMCPServerConfig {\n type?: \"streamable-http\"; // 可选,因为默认就是 streamable-http\n url: string;\n}\n\nexport type MCPServerConfig =\n | LocalMCPServerConfig\n | SSEMCPServerConfig\n | StreamableHTTPMCPServerConfig;\n\n/**\n * 判断 MCP 服务的通信类型\n *\n * @param serverConfig MCP 服务配置对象\n * @returns 通信类型:'stdio' | 'sse' | 'streamable-http'\n *\n * 判断逻辑:\n * 1. 如果配置对象有 command 字段 → stdio\n * 2. 如果配置对象有 type 字段且值为 \"sse\" → sse\n * 3. 如果配置对象有 url 字段但没有 type 字段,或者 type 字段不是 \"sse\" → streamable-http\n *\n * @example\n * ```typescript\n * // stdio 类型\n * const stdioConfig = {\n * command: \"node\",\n * args: [\"./mcpServers/calculator.js\"]\n * };\n * getMcpServerCommunicationType(stdioConfig); // \"stdio\"\n *\n * // sse 类型\n * const sseConfig = {\n * type: \"sse\" as const,\n * url: \"https://mcp.api-inference.modelscope.net/d3cfd34529ae4e/sse\"\n * };\n * getMcpServerCommunicationType(sseConfig); // \"sse\"\n *\n * // streamable-http 类型\n * const httpConfig = {\n * url: \"https://mcp.amap.com/mcp?key=1ec31da021b2702787841ea4ee822de3\"\n * };\n * getMcpServerCommunicationType(httpConfig); // \"streamable-http\"\n * ```\n */\nexport function getMcpServerCommunicationType(\n serverConfig: MCPServerConfig | Record<string, any>\n): MCPCommunicationType {\n // 参数验证\n if (!serverConfig || typeof serverConfig !== \"object\") {\n throw new Error(\"服务配置必须是一个有效的对象\");\n }\n\n // 1. 检查是否为 stdio 类型(有 command 字段)\n if (\"command\" in serverConfig && typeof serverConfig.command === \"string\") {\n return \"stdio\";\n }\n\n // 2. 检查是否为 sse 类型(有 type: \"sse\" 字段)\n if (\"type\" in serverConfig && serverConfig.type === \"sse\") {\n return \"sse\";\n }\n\n // 3. 检查是否为 streamable-http 类型(有 type: \"streamable-http\" 字段或有 url 字段)\n if (\n (\"type\" in serverConfig && serverConfig.type === \"streamable-http\") ||\n (\"url\" in serverConfig && typeof serverConfig.url === \"string\")\n ) {\n return \"streamable-http\";\n }\n\n // 如果都不匹配,抛出错误\n throw new Error(\n \"无法识别的 MCP 服务配置类型。配置必须包含 command 字段(stdio)、type: 'sse' 字段(sse)或 url 字段(streamable-http)\"\n );\n}\n\n/**\n * 检查 MCP 服务配置是否为 stdio 类型\n */\nexport function isStdioMcpServer(\n serverConfig: MCPServerConfig | Record<string, any>\n): serverConfig is LocalMCPServerConfig {\n return getMcpServerCommunicationType(serverConfig) === \"stdio\";\n}\n\n/**\n * 检查 MCP 服务配置是否为 sse 类型\n */\nexport function isSSEMcpServer(\n serverConfig: MCPServerConfig | Record<string, any>\n): serverConfig is SSEMCPServerConfig {\n return getMcpServerCommunicationType(serverConfig) === \"sse\";\n}\n\n/**\n * 检查 MCP 服务配置是否为 streamable-http 类型\n */\nexport function isStreamableHTTPMcpServer(\n serverConfig: MCPServerConfig | Record<string, any>\n): serverConfig is StreamableHTTPMCPServerConfig {\n return getMcpServerCommunicationType(serverConfig) === \"streamable-http\";\n}\n\n/**\n * 获取 MCP 服务配置的显示名称\n * 用于在日志中显示更友好的通信类型名称\n */\nexport function getMcpServerTypeDisplayName(\n serverConfig: MCPServerConfig | Record<string, any>\n): string {\n const type = getMcpServerCommunicationType(serverConfig);\n\n switch (type) {\n case \"stdio\":\n return \"本地进程 (stdio)\";\n case \"sse\":\n return \"服务器推送 (SSE)\";\n case \"streamable-http\":\n return \"流式 HTTP\";\n default:\n return \"未知类型\";\n }\n}\n\n/**\n * 验证 MCP 服务配置的完整性\n * 根据不同的通信类型验证必需的字段\n */\nexport function validateMcpServerConfig(\n serverName: string,\n serverConfig: any\n): { valid: boolean; error?: string } {\n if (!serverConfig || typeof serverConfig !== \"object\") {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 的配置必须是一个对象`,\n };\n }\n\n try {\n const communicationType = getMcpServerCommunicationType(serverConfig);\n\n switch (communicationType) {\n case \"stdio\":\n if (!serverConfig.command || typeof serverConfig.command !== \"string\") {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 缺少必需的 command 字段或字段类型不正确`,\n };\n }\n if (!Array.isArray(serverConfig.args)) {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 的 args 字段必须是数组`,\n };\n }\n if (serverConfig.env && typeof serverConfig.env !== \"object\") {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 的 env 字段必须是对象`,\n };\n }\n break;\n\n case \"sse\":\n if (serverConfig.type !== \"sse\") {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 的 type 字段必须是 \"sse\"`,\n };\n }\n if (!serverConfig.url || typeof serverConfig.url !== \"string\") {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 缺少必需的 url 字段或字段类型不正确`,\n };\n }\n break;\n\n case \"streamable-http\":\n if (!serverConfig.url || typeof serverConfig.url !== \"string\") {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 缺少必需的 url 字段或字段类型不正确`,\n };\n }\n if (serverConfig.type && serverConfig.type !== \"streamable-http\") {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 的 type 字段如果存在,必须是 \"streamable-http\"`,\n };\n }\n break;\n\n default:\n return {\n valid: false,\n error: `服务 \"${serverName}\" 的配置类型无法识别`,\n };\n }\n\n return { valid: true };\n } catch (error) {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 的配置无效: ${\n error instanceof Error ? error.message : \"未知错误\"\n }`,\n };\n }\n}\n","import { copyFileSync, existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport * as commentJson from \"comment-json\";\nimport dayjs from \"dayjs\";\nimport JSON5 from \"json5\";\nimport * as json5Writer from \"json5-writer\";\nimport { logger } from \"./Logger\";\nimport { validateMcpServerConfig } from \"./utils/mcpServerUtils\";\n\n// 在 ESM 中,需要从 import.meta.url 获取当前文件目录\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n// 默认连接配置\nconst DEFAULT_CONNECTION_CONFIG: Required<ConnectionConfig> = {\n heartbeatInterval: 30000, // 30秒心跳间隔\n heartbeatTimeout: 10000, // 10秒心跳超时\n reconnectInterval: 5000, // 5秒重连间隔\n};\n\n// 配置文件接口定义\n// 本地 MCP 服务配置\nexport interface LocalMCPServerConfig {\n command: string;\n args: string[];\n env?: Record<string, string>;\n}\n\n// SSE MCP 服务配置\nexport interface SSEMCPServerConfig {\n type: \"sse\";\n url: string;\n}\n\n// Streamable HTTP MCP 服务配置\nexport interface StreamableHTTPMCPServerConfig {\n type?: \"streamable-http\"; // 可选,因为默认就是 streamable-http\n url: string;\n}\n\n// 统一的 MCP 服务配置\nexport type MCPServerConfig =\n | LocalMCPServerConfig\n | SSEMCPServerConfig\n | StreamableHTTPMCPServerConfig;\n\nexport interface MCPToolConfig {\n description?: string;\n enable: boolean;\n usageCount?: number; // 工具使用次数\n lastUsedTime?: string; // 最后使用时间(ISO 8601 格式)\n}\n\nexport interface MCPServerToolsConfig {\n tools: Record<string, MCPToolConfig>;\n}\n\nexport interface ConnectionConfig {\n heartbeatInterval?: number; // 心跳检测间隔(毫秒),默认30000\n heartbeatTimeout?: number; // 心跳超时时间(毫秒),默认10000\n reconnectInterval?: number; // 重连间隔(毫秒),默认5000\n}\n\nexport interface ModelScopeConfig {\n apiKey?: string; // ModelScope API 密钥\n}\n\nexport interface WebUIConfig {\n port?: number; // Web UI 端口号,默认 9999\n autoRestart?: boolean; // 是否在配置更新后自动重启服务,默认 true\n}\n\nexport interface AppConfig {\n mcpEndpoint: string | string[];\n mcpServers: Record<string, MCPServerConfig>;\n mcpServerConfig?: Record<string, MCPServerToolsConfig>;\n connection?: ConnectionConfig; // 连接配置(可选,用于向后兼容)\n modelscope?: ModelScopeConfig; // ModelScope 配置(可选)\n webUI?: WebUIConfig; // Web UI 配置(可选)\n}\n\n/**\n * 配置管理类\n * 负责管理应用配置,提供只读访问和安全的配置更新功能\n */\nexport class ConfigManager {\n private static instance: ConfigManager;\n private defaultConfigPath: string;\n private config: AppConfig | null = null;\n private currentConfigPath: string | null = null; // 跟踪当前使用的配置文件路径\n private json5Writer: any = null; // json5-writer 实例,用于保留 JSON5 注释\n\n private constructor() {\n // 使用模板目录中的默认配置文件\n // 在不同环境中尝试不同的路径\n const possiblePaths = [\n // 构建后的环境:dist/configManager.js -> dist/templates/default/xiaozhi.config.json\n resolve(__dirname, \"templates\", \"default\", \"xiaozhi.config.json\"),\n // 开发环境:src/configManager.ts -> templates/default/xiaozhi.config.json\n resolve(__dirname, \"..\", \"templates\", \"default\", \"xiaozhi.config.json\"),\n // 测试环境或其他情况\n resolve(process.cwd(), \"templates\", \"default\", \"xiaozhi.config.json\"),\n ];\n\n // 找到第一个存在的路径\n this.defaultConfigPath =\n possiblePaths.find((path) => existsSync(path)) || possiblePaths[0];\n }\n\n /**\n * 获取配置文件路径(动态计算)\n * 支持多种配置文件格式:json5 > jsonc > json\n */\n private getConfigFilePath(): string {\n // 配置文件路径 - 优先使用环境变量指定的目录,否则使用当前工作目录\n const configDir = process.env.XIAOZHI_CONFIG_DIR || process.cwd();\n\n // 按优先级检查配置文件是否存在\n const configFileNames = [\n \"xiaozhi.config.json5\",\n \"xiaozhi.config.jsonc\",\n \"xiaozhi.config.json\",\n ];\n\n for (const fileName of configFileNames) {\n const filePath = resolve(configDir, fileName);\n if (existsSync(filePath)) {\n return filePath;\n }\n }\n\n // 如果都不存在,返回默认的 JSON 文件路径\n return resolve(configDir, \"xiaozhi.config.json\");\n }\n\n /**\n * 获取配置文件格式\n */\n private getConfigFileFormat(filePath: string): \"json5\" | \"jsonc\" | \"json\" {\n if (filePath.endsWith(\".json5\")) {\n return \"json5\";\n }\n\n if (filePath.endsWith(\".jsonc\")) {\n return \"jsonc\";\n }\n\n return \"json\";\n }\n\n /**\n * 获取配置管理器单例实例\n */\n public static getInstance(): ConfigManager {\n if (!ConfigManager.instance) {\n ConfigManager.instance = new ConfigManager();\n }\n return ConfigManager.instance;\n }\n\n /**\n * 检查配置文件是否存在\n */\n public configExists(): boolean {\n // 配置文件路径 - 优先使用环境变量指定的目录,否则使用当前工作目录\n const configDir = process.env.XIAOZHI_CONFIG_DIR || process.cwd();\n\n // 按优先级检查配置文件是否存在\n const configFileNames = [\n \"xiaozhi.config.json5\",\n \"xiaozhi.config.jsonc\",\n \"xiaozhi.config.json\",\n ];\n\n for (const fileName of configFileNames) {\n const filePath = resolve(configDir, fileName);\n if (existsSync(filePath)) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * 初始化配置文件\n * 从 config.default.json 复制到 config.json\n * @param format 配置文件格式,默认为 json\n */\n public initConfig(format: \"json\" | \"json5\" | \"jsonc\" = \"json\"): void {\n if (!existsSync(this.defaultConfigPath)) {\n throw new Error(`默认配置模板文件不存在: ${this.defaultConfigPath}`);\n }\n\n // 检查是否已有任何格式的配置文件\n if (this.configExists()) {\n throw new Error(\"配置文件已存在,无需重复初始化\");\n }\n\n // 确定目标配置文件路径\n const configDir = process.env.XIAOZHI_CONFIG_DIR || process.cwd();\n const targetFileName = `xiaozhi.config.${format}`;\n const configPath = resolve(configDir, targetFileName);\n\n // 复制默认配置文件\n copyFileSync(this.defaultConfigPath, configPath);\n this.config = null; // 重置缓存\n this.json5Writer = null; // 重置 json5Writer 实例\n }\n\n /**\n * 加载配置文件\n */\n private loadConfig(): AppConfig {\n if (!this.configExists()) {\n throw new Error(\"配置文件不存在,请先运行 xiaozhi init 初始化配置\");\n }\n\n try {\n const configPath = this.getConfigFilePath();\n this.currentConfigPath = configPath; // 记录当前使用的配置文件路径\n const configFileFormat = this.getConfigFileFormat(configPath);\n const rawConfigData = readFileSync(configPath, \"utf8\");\n\n // 移除可能存在的UTF-8 BOM字符(\\uFEFF)\n // BOM字符在某些编辑器中不可见,但会导致JSON解析失败\n // 这个过滤确保即使文件包含BOM字符也能正常解析\n const configData = rawConfigData.replace(/^\\uFEFF/, \"\");\n\n let config: AppConfig;\n\n // 根据文件格式使用相应的解析器\n switch (configFileFormat) {\n case \"json5\":\n // 使用 JSON5 解析配置对象,同时使用 json5-writer 保留注释信息\n config = JSON5.parse(configData) as AppConfig;\n // 创建 json5-writer 实例用于后续保存时保留注释\n this.json5Writer = json5Writer.load(configData);\n break;\n case \"jsonc\":\n // 使用 comment-json 解析 JSONC 格式,保留注释信息\n config = commentJson.parse(configData) as unknown as AppConfig;\n break;\n default:\n config = JSON.parse(configData) as AppConfig;\n break;\n }\n\n // 验证配置结构\n this.validateConfig(config);\n\n return config;\n } catch (error) {\n if (error instanceof SyntaxError) {\n throw new Error(`配置文件格式错误: ${error.message}`);\n }\n throw error;\n }\n }\n\n /**\n * 验证配置文件结构\n */\n private validateConfig(config: unknown): void {\n if (!config || typeof config !== \"object\") {\n throw new Error(\"配置文件格式错误:根对象无效\");\n }\n\n const configObj = config as Record<string, unknown>;\n\n if (configObj.mcpEndpoint === undefined || configObj.mcpEndpoint === null) {\n throw new Error(\"配置文件格式错误:mcpEndpoint 字段无效\");\n }\n\n // 验证 mcpEndpoint 类型(字符串或字符串数组)\n if (typeof configObj.mcpEndpoint === \"string\") {\n // 空字符串是允许的,getMcpEndpoints 会返回空数组\n } else if (Array.isArray(configObj.mcpEndpoint)) {\n if (configObj.mcpEndpoint.length === 0) {\n throw new Error(\"配置文件格式错误:mcpEndpoint 数组不能为空\");\n }\n for (const endpoint of configObj.mcpEndpoint) {\n if (typeof endpoint !== \"string\" || endpoint.trim() === \"\") {\n throw new Error(\n \"配置文件格式错误:mcpEndpoint 数组中的每个元素必须是非空字符串\"\n );\n }\n }\n } else {\n throw new Error(\"配置文件格式错误:mcpEndpoint 必须是字符串或字符串数组\");\n }\n\n if (!configObj.mcpServers || typeof configObj.mcpServers !== \"object\") {\n throw new Error(\"配置文件格式错误:mcpServers 字段无效\");\n }\n\n // 验证每个 MCP 服务配置\n for (const [serverName, serverConfig] of Object.entries(\n configObj.mcpServers as Record<string, unknown>\n )) {\n if (!serverConfig || typeof serverConfig !== \"object\") {\n throw new Error(`配置文件格式错误:mcpServers.${serverName} 无效`);\n }\n\n // 使用统一的验证逻辑\n const validation = validateMcpServerConfig(serverName, serverConfig);\n if (!validation.valid) {\n throw new Error(`配置文件格式错误:${validation.error}`);\n }\n }\n }\n\n /**\n * 获取配置(只读)\n */\n public getConfig(): Readonly<AppConfig> {\n this.config = this.loadConfig();\n\n // 返回深度只读副本\n return JSON.parse(JSON.stringify(this.config));\n }\n\n /**\n * 获取可修改的配置对象(内部使用,保留注释信息)\n */\n private getMutableConfig(): AppConfig {\n if (!this.config) {\n this.config = this.loadConfig();\n }\n return this.config;\n }\n\n /**\n * 获取 MCP 端点(向后兼容)\n * @deprecated 使用 getMcpEndpoints() 获取所有端点\n */\n public getMcpEndpoint(): string {\n const config = this.getConfig();\n if (Array.isArray(config.mcpEndpoint)) {\n return config.mcpEndpoint[0] || \"\";\n }\n return config.mcpEndpoint;\n }\n\n /**\n * 获取所有 MCP 端点\n */\n public getMcpEndpoints(): string[] {\n const config = this.getConfig();\n if (Array.isArray(config.mcpEndpoint)) {\n return [...config.mcpEndpoint];\n }\n return config.mcpEndpoint ? [config.mcpEndpoint] : [];\n }\n\n /**\n * 获取 MCP 服务配置\n */\n public getMcpServers(): Readonly<Record<string, MCPServerConfig>> {\n const config = this.getConfig();\n return config.mcpServers;\n }\n\n /**\n * 获取 MCP 服务工具配置\n */\n public getMcpServerConfig(): Readonly<Record<string, MCPServerToolsConfig>> {\n const config = this.getConfig();\n return config.mcpServerConfig || {};\n }\n\n /**\n * 获取指定服务的工具配置\n */\n public getServerToolsConfig(\n serverName: string\n ): Readonly<Record<string, MCPToolConfig>> {\n const serverConfig = this.getMcpServerConfig();\n return serverConfig[serverName]?.tools || {};\n }\n\n /**\n * 检查工具是否启用\n */\n public isToolEnabled(serverName: string, toolName: string): boolean {\n const toolsConfig = this.getServerToolsConfig(serverName);\n const toolConfig = toolsConfig[toolName];\n return toolConfig?.enable !== false; // 默认启用\n }\n\n /**\n * 更新 MCP 端点(支持字符串或数组)\n */\n public updateMcpEndpoint(endpoint: string | string[]): void {\n if (Array.isArray(endpoint)) {\n if (endpoint.length === 0) {\n throw new Error(\"MCP 端点数组不能为空\");\n }\n for (const ep of endpoint) {\n if (!ep || typeof ep !== \"string\") {\n throw new Error(\"MCP 端点数组中的每个元素必须是非空字符串\");\n }\n }\n } else {\n if (!endpoint || typeof endpoint !== \"string\") {\n throw new Error(\"MCP 端点必须是非空字符串\");\n }\n }\n\n const config = this.getMutableConfig();\n config.mcpEndpoint = endpoint;\n this.saveConfig(config);\n }\n\n /**\n * 添加 MCP 端点\n */\n public addMcpEndpoint(endpoint: string): void {\n if (!endpoint || typeof endpoint !== \"string\") {\n throw new Error(\"MCP 端点必须是非空字符串\");\n }\n\n const config = this.getMutableConfig();\n const currentEndpoints = this.getMcpEndpoints();\n\n // 检查是否已存在\n if (currentEndpoints.includes(endpoint)) {\n throw new Error(`MCP 端点 ${endpoint} 已存在`);\n }\n\n const newEndpoints = [...currentEndpoints, endpoint];\n config.mcpEndpoint = newEndpoints;\n this.saveConfig(config);\n }\n\n /**\n * 移除 MCP 端点\n */\n public removeMcpEndpoint(endpoint: string): void {\n if (!endpoint || typeof endpoint !== \"string\") {\n throw new Error(\"MCP 端点必须是非空字符串\");\n }\n\n const config = this.getMutableConfig();\n const currentEndpoints = this.getMcpEndpoints();\n\n // 检查是否存在\n const index = currentEndpoints.indexOf(endpoint);\n if (index === -1) {\n throw new Error(`MCP 端点 ${endpoint} 不存在`);\n }\n\n // 不允许删除最后一个端点\n if (currentEndpoints.length === 1) {\n throw new Error(\"不能删除最后一个 MCP 端点\");\n }\n\n const newEndpoints = currentEndpoints.filter((ep) => ep !== endpoint);\n config.mcpEndpoint = newEndpoints;\n this.saveConfig(config);\n }\n\n /**\n * 更新 MCP 服务配置\n */\n public updateMcpServer(\n serverName: string,\n serverConfig: MCPServerConfig\n ): void {\n if (!serverName || typeof serverName !== \"string\") {\n throw new Error(\"服务名称必须是非空字符串\");\n }\n\n // 使用统一的验证逻辑\n const validation = validateMcpServerConfig(serverName, serverConfig);\n if (!validation.valid) {\n throw new Error(validation.error || \"服务配置验证失败\");\n }\n const config = this.getMutableConfig();\n // 直接修改配置对象以保留注释信息\n config.mcpServers[serverName] = serverConfig;\n this.saveConfig(config);\n }\n\n /**\n * 删除 MCP 服务配置\n */\n public removeMcpServer(serverName: string): void {\n if (!serverName || typeof serverName !== \"string\") {\n throw new Error(\"服务名称必须是非空字符串\");\n }\n\n const config = this.getConfig();\n if (!config.mcpServers[serverName]) {\n throw new Error(`服务 ${serverName} 不存在`);\n }\n\n const newMcpServers = { ...config.mcpServers };\n delete newMcpServers[serverName];\n\n const newConfig = {\n ...config,\n mcpServers: newMcpServers,\n };\n this.saveConfig(newConfig);\n }\n\n /**\n * 更新服务工具配置\n */\n public updateServerToolsConfig(\n serverName: string,\n toolsConfig: Record<string, MCPToolConfig>\n ): void {\n const config = this.getMutableConfig();\n\n // 确保 mcpServerConfig 存在\n if (!config.mcpServerConfig) {\n config.mcpServerConfig = {};\n }\n\n // 如果 toolsConfig 为空对象,则删除该服务的配置\n if (Object.keys(toolsConfig).length === 0) {\n delete config.mcpServerConfig[serverName];\n } else {\n // 更新指定服务的工具配置\n config.mcpServerConfig[serverName] = {\n tools: toolsConfig,\n };\n }\n\n this.saveConfig(config);\n }\n\n /**\n * 删除指定服务器的工具配置\n */\n public removeServerToolsConfig(serverName: string): void {\n const config = this.getConfig();\n const newConfig = { ...config };\n\n // 确保 mcpServerConfig 存在\n if (newConfig.mcpServerConfig) {\n // 删除指定服务的工具配置\n delete newConfig.mcpServerConfig[serverName];\n this.saveConfig(newConfig);\n }\n }\n\n /**\n * 清理无效的服务器工具配置\n * 删除在 mcpServerConfig 中存在但在 mcpServers 中不存在的服务配置\n */\n public cleanupInvalidServerToolsConfig(): void {\n const config = this.getMutableConfig();\n\n // 如果没有 mcpServerConfig,无需清理\n if (!config.mcpServerConfig) {\n return;\n }\n\n const validServerNames = Object.keys(config.mcpServers);\n const configuredServerNames = Object.keys(config.mcpServerConfig);\n\n // 找出需要清理的服务名称\n const invalidServerNames = configuredServerNames.filter(\n (serverName) => !validServerNames.includes(serverName)\n );\n\n if (invalidServerNames.length > 0) {\n // 删除无效的服务配置\n for (const serverName of invalidServerNames) {\n delete config.mcpServerConfig[serverName];\n }\n\n this.saveConfig(config);\n\n logger.info(\n `已清理 ${invalidServerNames.length} 个无效的服务工具配置: ${invalidServerNames.join(\", \")}`\n );\n }\n }\n\n /**\n * 设置工具启用状态\n */\n public setToolEnabled(\n serverName: string,\n toolName: string,\n enabled: boolean,\n description?: string\n ): void {\n const config = this.getMutableConfig();\n\n // 确保 mcpServerConfig 存在\n if (!config.mcpServerConfig) {\n config.mcpServerConfig = {};\n }\n\n // 确保服务配置存在\n if (!config.mcpServerConfig[serverName]) {\n config.mcpServerConfig[serverName] = { tools: {} };\n }\n\n // 更新工具配置\n config.mcpServerConfig[serverName].tools[toolName] = {\n ...config.mcpServerConfig[serverName].tools[toolName],\n enable: enabled,\n ...(description && { description }),\n };\n\n this.saveConfig(config);\n }\n\n /**\n * 保存配置到文件\n * 保存到原始配置文件路径,保持文件格式一致性\n */\n private saveConfig(config: AppConfig): void {\n try {\n // 验证配置\n this.validateConfig(config);\n\n // 确定保存路径 - 优先使用当前配置文件路径,否则使用默认路径\n let configPath: string;\n if (this.currentConfigPath) {\n configPath = this.currentConfigPath;\n } else {\n // 如果没有当前路径,使用 getConfigFilePath 获取\n configPath = this.getConfigFilePath();\n this.currentConfigPath = configPath;\n }\n\n // 根据文件格式选择序列化方法\n const configFileFormat = this.getConfigFileFormat(configPath);\n let configContent: string;\n\n switch (configFileFormat) {\n case \"json5\":\n // 对于 JSON5 格式,使用 json5-writer 库保留注释\n try {\n if (this.json5Writer) {\n // 使用 json5-writer 更新配置并保留注释\n this.json5Writer.write(config);\n configContent = this.json5Writer.toSource();\n } else {\n // 如果没有 json5Writer 实例,回退到标准 JSON5\n console.warn(\"没有 json5Writer 实例,回退到标准 JSON5 格式\");\n configContent = JSON5.stringify(config, null, 2);\n }\n } catch (json5WriterError) {\n // 如果 json5-writer 序列化失败,回退到标准 JSON5\n console.warn(\n \"使用 json5-writer 保存失败,回退到标准 JSON5 格式:\",\n json5WriterError\n );\n configContent = JSON5.stringify(config, null, 2);\n }\n break;\n case \"jsonc\":\n // 对于 JSONC 格式,使用 comment-json 库保留注释\n try {\n // 直接使用 comment-json 的 stringify 方法\n // 如果 config 是通过 comment-json.parse 解析的,注释信息会被保留\n configContent = commentJson.stringify(config, null, 2);\n } catch (commentJsonError) {\n // 如果 comment-json 序列化失败,回退到标准 JSON\n console.warn(\n \"使用 comment-json 保存失败,回退到标准 JSON 格式:\",\n commentJsonError\n );\n configContent = JSON.stringify(config, null, 2);\n }\n break;\n default:\n configContent = JSON.stringify(config, null, 2);\n break;\n }\n\n // 保存到文件\n writeFileSync(configPath, configContent, \"utf8\");\n\n // 更新缓存\n this.config = config;\n\n // 通知 Web 界面配置已更新(如果 Web 服务器正在运行)\n this.notifyConfigUpdate(config);\n } catch (error) {\n throw new Error(\n `保存配置失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n\n /**\n * 重新加载配置(清除缓存)\n */\n public reloadConfig(): void {\n this.config = null;\n this.currentConfigPath = null; // 清除配置文件路径缓存\n this.json5Writer = null; // 清除 json5Writer 实例\n }\n\n /**\n * 获取配置文件路径\n */\n public getConfigPath(): string {\n return this.getConfigFilePath();\n }\n\n /**\n * 获取默认配置文件路径\n */\n public getDefaultConfigPath(): string {\n return this.defaultConfigPath;\n }\n\n /**\n * 获取连接配置(包含默认值)\n */\n public getConnectionConfig(): Required<ConnectionConfig> {\n const config = this.getConfig();\n const connectionConfig = config.connection || {};\n\n return {\n heartbeatInterval:\n connectionConfig.heartbeatInterval ??\n DEFAULT_CONNECTION_CONFIG.heartbeatInterval,\n heartbeatTimeout:\n connectionConfig.heartbeatTimeout ??\n DEFAULT_CONNECTION_CONFIG.heartbeatTimeout,\n reconnectInterval:\n connectionConfig.reconnectInterval ??\n DEFAULT_CONNECTION_CONFIG.reconnectInterval,\n };\n }\n\n /**\n * 获取心跳检测间隔(毫秒)\n */\n public getHeartbeatInterval(): number {\n return this.getConnectionConfig().heartbeatInterval;\n }\n\n /**\n * 获取心跳超时时间(毫秒)\n */\n public getHeartbeatTimeout(): number {\n return this.getConnectionConfig().heartbeatTimeout;\n }\n\n /**\n * 获取重连间隔(毫秒)\n */\n public getReconnectInterval(): number {\n return this.getConnectionConfig().reconnectInterval;\n }\n\n /**\n * 更新连接配置\n */\n public updateConnectionConfig(\n connectionConfig: Partial<ConnectionConfig>\n ): void {\n const config = this.getMutableConfig();\n\n // 确保 connection 对象存在\n if (!config.connection) {\n config.connection = {};\n }\n\n // 直接修改现有的 connection 对象以保留注释\n Object.assign(config.connection, connectionConfig);\n this.saveConfig(config);\n }\n\n /**\n * 更新工具使用统计信息\n * @param serverName 服务名称\n * @param toolName 工具名称\n * @param callTime 调用时间(ISO 8601 格式)\n */\n public async updateToolUsageStats(\n serverName: string,\n toolName: string,\n callTime: string\n ): Promise<void> {\n try {\n const config = this.getMutableConfig();\n\n // 确保 mcpServerConfig 存在\n if (!config.mcpServerConfig) {\n config.mcpServerConfig = {};\n }\n\n // 确保服务配置存在\n if (!config.mcpServerConfig[serverName]) {\n config.mcpServerConfig[serverName] = { tools: {} };\n }\n\n // 确保工具配置存在\n if (!config.mcpServerConfig[serverName].tools[toolName]) {\n config.mcpServerConfig[serverName].tools[toolName] = {\n enable: true, // 默认启用\n };\n }\n\n const toolConfig = config.mcpServerConfig[serverName].tools[toolName];\n const currentUsageCount = toolConfig.usageCount || 0;\n const currentLastUsedTime = toolConfig.lastUsedTime;\n\n // 更新使用次数\n toolConfig.usageCount = currentUsageCount + 1;\n\n // 时间校验:只有新时间晚于现有时间才更新 lastUsedTime\n if (\n !currentLastUsedTime ||\n new Date(callTime) > new Date(currentLastUsedTime)\n ) {\n // 使用 dayjs 格式化时间为更易读的格式\n toolConfig.lastUsedTime = dayjs(callTime).format(\"YYYY-MM-DD HH:mm:ss\");\n }\n\n // 保存配置\n this.saveConfig(config);\n\n logger.debug(\n `工具使用统计已更新: ${serverName}/${toolName}, 使用次数: ${toolConfig.usageCount}`\n );\n } catch (error) {\n // 错误不应该影响主要的工具调用流程\n logger.error(\n `更新工具使用统计失败 (${serverName}/${toolName}): ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n\n /**\n * 设置心跳检测间隔\n */\n public setHeartbeatInterval(interval: number): void {\n if (interval <= 0) {\n throw new Error(\"心跳检测间隔必须大于0\");\n }\n this.updateConnectionConfig({ heartbeatInterval: interval });\n }\n\n /**\n * 设置心跳超时时间\n */\n public setHeartbeatTimeout(timeout: number): void {\n if (timeout <= 0) {\n throw new Error(\"心跳超时时间必须大于0\");\n }\n this.updateConnectionConfig({ heartbeatTimeout: timeout });\n }\n\n /**\n * 设置重连间隔\n */\n public setReconnectInterval(interval: number): void {\n if (interval <= 0) {\n throw new Error(\"重连间隔必须大于0\");\n }\n this.updateConnectionConfig({ reconnectInterval: interval });\n }\n\n /**\n * 获取 ModelScope 配置\n */\n public getModelScopeConfig(): Readonly<ModelScopeConfig> {\n const config = this.getConfig();\n return config.modelscope || {};\n }\n\n /**\n * 获取 ModelScope API Key\n * 优先从配置文件读取,其次从环境变量读取\n */\n public getModelScopeApiKey(): string | undefined {\n const modelScopeConfig = this.getModelScopeConfig();\n return modelScopeConfig.apiKey || process.env.MODELSCOPE_API_TOKEN;\n }\n\n /**\n * 更新 ModelScope 配置\n */\n public updateModelScopeConfig(\n modelScopeConfig: Partial<ModelScopeConfig>\n ): void {\n const config = this.getMutableConfig();\n\n // 确保 modelscope 对象存在\n if (!config.modelscope) {\n config.modelscope = {};\n }\n\n // 直接修改现有的 modelscope 对象以保留注释\n Object.assign(config.modelscope, modelScopeConfig);\n this.saveConfig(config);\n }\n\n /**\n * 设置 ModelScope API Key\n */\n public setModelScopeApiKey(apiKey: string): void {\n if (!apiKey || typeof apiKey !== \"string\") {\n throw new Error(\"API Key 必须是非空字符串\");\n }\n this.updateModelScopeConfig({ apiKey });\n }\n\n /**\n * 获取 Web UI 配置\n */\n public getWebUIConfig(): Readonly<WebUIConfig> {\n const config = this.getConfig();\n return config.webUI || {};\n }\n\n /**\n * 获取 Web UI 端口号\n */\n public getWebUIPort(): number {\n const webUIConfig = this.getWebUIConfig();\n return webUIConfig.port ?? 9999; // 默认端口 9999\n }\n\n /**\n * 通知 Web 界面配置已更新\n * 如果 Web 服务器正在运行,通过 WebSocket 广播配置更新\n */\n private notifyConfigUpdate(config: AppConfig): void {\n try {\n // 检查是否有全局的 webServer 实例(当使用 --ui 参数启动时会设置)\n const webServer = (global as any).__webServer;\n if (webServer && typeof webServer.broadcastConfigUpdate === \"function\") {\n // 调用 webServer 的 broadcastConfigUpdate 方法来通知所有连接的客户端\n webServer.broadcastConfigUpdate(config);\n console.log(\"已通过 WebSocket 广播配置更新\");\n }\n } catch (error) {\n // 静默处理错误,不影响配置保存的主要功能\n console.warn(\n \"通知 Web 界面配置更新失败:\",\n error instanceof Error ? error.message : String(error)\n );\n }\n }\n\n /**\n * 更新 Web UI 配置\n */\n public updateWebUIConfig(webUIConfig: Partial<WebUIConfig>): void {\n const config = this.getMutableConfig();\n\n // 确保 webUI 对象存在\n if (!config.webUI) {\n config.webUI = {};\n }\n\n // 直接修改现有的 webUI 对象以保留注释\n Object.assign(config.webUI, webUIConfig);\n this.saveConfig(config);\n }\n\n /**\n * 设置 Web UI 端口号\n */\n public setWebUIPort(port: number): void {\n if (!Number.isInteger(port) || port <= 0 || port > 65535) {\n throw new Error(\"端口号必须是 1-65535 之间的整数\");\n }\n this.updateWebUIConfig({ port });\n }\n}\n\n// 导出单例实例\nexport const configManager = ConfigManager.getInstance();\n","#!/usr/bin/env node\n\n/**\n * MCP 服务管理器\n * 使用 MCPService 实例管理多个 MCP 服务\n * 专注于实例管理、工具聚合和路由调用\n */\n\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport { type Logger, logger } from \"../Logger.js\";\nimport { type MCPToolConfig, configManager } from \"../configManager.js\";\nimport {\n MCPService,\n type MCPServiceConfig,\n MCPTransportType,\n} from \"./MCPService.js\";\n\n// 工具信息接口(保持向后兼容)\ninterface ToolInfo {\n serviceName: string;\n originalName: string;\n tool: Tool;\n}\n\n// 服务状态接口(保持向后兼容)\ninterface ServiceStatus {\n connected: boolean;\n clientName: string;\n}\n\n// 管理器状态接口(保持向后兼容)\ninterface ManagerStatus {\n services: Record<string, ServiceStatus>;\n totalTools: number;\n availableTools: string[];\n}\n\n// 工具调用结果接口(保持向后兼容)\ninterface ToolCallResult {\n content: Array<{\n type: string;\n text: string;\n }>;\n isError?: boolean;\n}\n\nexport class MCPServiceManager {\n private services: Map<string, MCPService> = new Map();\n private configs: Record<string, MCPServiceConfig> = {};\n private logger: Logger;\n private tools: Map<string, ToolInfo> = new Map(); // 缓存工具信息,保持向后兼容\n\n /**\n * 创建 MCPServiceManager 实例\n * @param configs 可选的初始服务配置\n */\n constructor(configs?: Record<string, MCPServiceConfig>) {\n this.logger = logger;\n this.configs = configs || {};\n }\n\n /**\n * 启动所有 MCP 服务\n */\n async startAllServices(): Promise<void> {\n this.logger.info(\"[MCPManager] 正在启动所有 MCP 服务...\");\n\n const configEntries = Object.entries(this.configs);\n if (configEntries.length === 0) {\n this.logger.warn(\n \"[MCPManager] 没有配置任何 MCP 服务,请使用 addServiceConfig() 添加服务配置\"\n );\n return;\n }\n\n for (const [serviceName] of configEntries) {\n await this.startService(serviceName);\n }\n\n this.logger.info(\"[MCPManager] 所有 MCP 服务启动完成\");\n }\n\n /**\n * 启动单个 MCP 服务\n */\n async startService(serviceName: string): Promise<void> {\n this.logger.info(`[MCPManager] 启动 MCP 服务: ${serviceName}`);\n\n const config = this.configs[serviceName];\n if (!config) {\n throw new Error(`未找到服务配置: ${serviceName}`);\n }\n\n try {\n // 如果服务已存在,先停止它\n if (this.services.has(serviceName)) {\n await this.stopService(serviceName);\n }\n\n // 创建 MCPService 实例\n const service = new MCPService(config);\n\n // 连接到服务\n await service.connect();\n\n // 存储服务实例\n this.services.set(serviceName, service);\n\n // 更新工具缓存\n await this.refreshToolsCache();\n\n const tools = service.getTools();\n this.logger.info(\n `[MCPManager] ${serviceName} 服务启动成功,加载了 ${tools.length} 个工具:`,\n tools.map((t) => t.name).join(\", \")\n );\n } catch (error) {\n this.logger.error(\n `[MCPManager] 启动 ${serviceName} 服务失败:`,\n (error as Error).message\n );\n throw error;\n }\n }\n\n /**\n * 停止单个服务\n */\n async stopService(serviceName: string): Promise<void> {\n this.logger.info(`[MCPManager] 停止 MCP 服务: ${serviceName}`);\n\n const service = this.services.get(serviceName);\n if (!service) {\n this.logger.warn(`[MCPManager] 服务 ${serviceName} 不存在或未启动`);\n return;\n }\n\n try {\n await service.disconnect();\n this.services.delete(serviceName);\n\n // 更新工具缓存\n await this.refreshToolsCache();\n\n this.logger.info(`[MCPManager] ${serviceName} 服务已停止`);\n } catch (error) {\n this.logger.error(\n `[MCPManager] 停止 ${serviceName} 服务失败:`,\n (error as Error).message\n );\n throw error;\n }\n }\n\n /**\n * 刷新工具缓存\n */\n private async refreshToolsCache(): Promise<void> {\n this.tools.clear();\n\n for (const [serviceName, service] of this.services) {\n if (service.isConnected()) {\n const tools = service.getTools();\n for (const tool of tools) {\n const toolKey = `${serviceName}__${tool.name}`;\n this.tools.set(toolKey, {\n serviceName,\n originalName: tool.name,\n tool,\n });\n }\n }\n }\n\n // 同步工具配置到配置文件\n await this.syncToolsConfigToFile();\n }\n\n /**\n * 获取所有可用工具(已启用的工具)\n */\n getAllTools(): Array<{\n name: string;\n description: string;\n inputSchema: any;\n serviceName: string;\n originalName: string;\n }> {\n const allTools: Array<{\n name: string;\n description: string;\n inputSchema: any;\n serviceName: string;\n originalName: string;\n }> = [];\n\n for (const [toolKey, toolInfo] of this.tools) {\n // 检查工具是否启用\n const isEnabled = configManager.isToolEnabled(\n toolInfo.serviceName,\n toolInfo.originalName\n );\n\n // 只返回启用的工具\n if (isEnabled) {\n allTools.push({\n name: toolKey,\n description: toolInfo.tool.description || \"\",\n inputSchema: toolInfo.tool.inputSchema,\n serviceName: toolInfo.serviceName,\n originalName: toolInfo.originalName,\n });\n }\n }\n return allTools;\n }\n\n /**\n * 调用 MCP 工具\n */\n async callTool(toolName: string, arguments_: any): Promise<ToolCallResult> {\n this.logger.info(`[MCPManager] 调用工具: ${toolName},参数:`, arguments_);\n\n const toolInfo = this.tools.get(toolName);\n if (!toolInfo) {\n throw new Error(`未找到工具: ${toolName}`);\n }\n\n const service = this.services.get(toolInfo.serviceName);\n if (!service) {\n throw new Error(`服务 ${toolInfo.serviceName} 不可用`);\n }\n\n if (!service.isConnected()) {\n throw new Error(`服务 ${toolInfo.serviceName} 未连接`);\n }\n\n try {\n const result = await service.callTool(\n toolInfo.originalName,\n arguments_ || {}\n );\n\n this.logger.info(`[MCPManager] 工具 ${toolName} 调用成功,结果:`, result);\n return result as ToolCallResult;\n } catch (error) {\n this.logger.error(\n `[MCPManager] 工具 ${toolName} 调用失败:`,\n (error as Error).message\n );\n throw error;\n }\n }\n\n /**\n * 停止所有服务\n */\n async stopAllServices(): Promise<void> {\n this.logger.info(\"[MCPManager] 正在停止所有 MCP 服务...\");\n\n // 停止所有服务实例\n for (const [serviceName, service] of this.services) {\n try {\n await service.disconnect();\n this.logger.info(`[MCPManager] ${serviceName} 服务已停止`);\n } catch (error) {\n this.logger.error(\n `[MCPManager] 停止 ${serviceName} 服务失败:`,\n (error as Error).message\n );\n }\n }\n\n this.services.clear();\n this.tools.clear();\n\n this.logger.info(\"[MCPManager] 所有 MCP 服务已停止\");\n }\n\n /**\n * 获取服务状态\n */\n getStatus(): ManagerStatus {\n const status: ManagerStatus = {\n services: {},\n totalTools: this.tools.size,\n availableTools: Array.from(this.tools.keys()),\n };\n\n for (const [serviceName, service] of this.services) {\n const serviceStatus = service.getStatus();\n status.services[serviceName] = {\n connected: serviceStatus.connected,\n clientName: `xiaozhi-${serviceName}-client`,\n };\n }\n\n return status;\n }\n\n /**\n * 获取指定服务实例\n */\n getService(name: string): MCPService | undefined {\n return this.services.get(name);\n }\n\n /**\n * 获取所有服务实例\n */\n getAllServices(): Map<string, MCPService> {\n return new Map(this.services);\n }\n\n /**\n * 增强服务配置\n * 根据服务类型添加必要的全局配置\n */\n private enhanceServiceConfig(config: MCPServiceConfig): MCPServiceConfig {\n const enhancedConfig = { ...config };\n\n try {\n // 处理 ModelScope SSE 服务\n if (config.type === MCPTransportType.MODELSCOPE_SSE) {\n const modelScopeApiKey = configManager.getModelScopeApiKey();\n if (modelScopeApiKey) {\n enhancedConfig.apiKey = modelScopeApiKey;\n this.logger.info(\n `[MCPManager] 为 ${config.name} 服务添加 ModelScope API Key`\n );\n } else {\n this.logger.warn(\n `[MCPManager] ${config.name} 服务需要 ModelScope API Key,但未在配置中找到`\n );\n throw new Error(\n `ModelScope SSE 服务 ${config.name} 需要 API Key,请在配置文件中设置 modelscope.apiKey`\n );\n }\n }\n\n return enhancedConfig;\n } catch (error) {\n this.logger.error(`[MCPManager] 配置增强失败: ${config.name}`, error);\n throw error;\n }\n }\n\n /**\n * 添加服务配置(重载方法以支持两种调用方式)\n */\n addServiceConfig(name: string, config: MCPServiceConfig): void;\n addServiceConfig(config: MCPServiceConfig): void;\n addServiceConfig(\n nameOrConfig: string | MCPServiceConfig,\n config?: MCPServiceConfig\n ): void {\n let finalConfig: MCPServiceConfig;\n let serviceName: string;\n\n if (typeof nameOrConfig === \"string\" && config) {\n // 两参数版本\n serviceName = nameOrConfig;\n finalConfig = config;\n } else if (typeof nameOrConfig === \"object\") {\n // 单参数版本\n serviceName = nameOrConfig.name;\n finalConfig = nameOrConfig;\n } else {\n throw new Error(\"Invalid arguments for addServiceConfig\");\n }\n\n // 增强配置\n const enhancedConfig = this.enhanceServiceConfig(finalConfig);\n\n // 存储增强后的配置\n this.configs[serviceName] = enhancedConfig;\n this.logger.info(`[MCPManager] 已添加服务配置: ${serviceName}`);\n }\n\n /**\n * 更新服务配置\n */\n updateServiceConfig(name: string, config: MCPServiceConfig): void {\n // 增强配置\n const enhancedConfig = this.enhanceServiceConfig(config);\n\n // 存储增强后的配置\n this.configs[name] = enhancedConfig;\n this.logger.info(`[MCPManager] 已更新并增强服务配置: ${name}`);\n }\n\n /**\n * 移除服务配置\n */\n removeServiceConfig(name: string): void {\n delete this.configs[name];\n this.logger.info(`[MCPManager] 已移除服务配置: ${name}`);\n }\n\n /**\n * 同步工具配置到配置文件\n * 实现自动同步 MCP 服务工具配置到 xiaozhi.config.json\n */\n private async syncToolsConfigToFile(): Promise<void> {\n try {\n this.logger.debug(\"[MCPManager] 开始同步工具配置到配置文件\");\n\n // 获取当前配置文件中的 mcpServerConfig\n const currentServerConfigs = configManager.getMcpServerConfig();\n\n // 遍历所有已连接的服务\n for (const [serviceName, service] of this.services) {\n if (!service.isConnected()) {\n continue;\n }\n\n const tools = service.getTools();\n if (tools.length === 0) {\n continue;\n }\n\n // 获取当前服务在配置文件中的工具配置\n const currentToolsConfig =\n currentServerConfigs[serviceName]?.tools || {};\n\n // 构建新的工具配置\n const newToolsConfig: Record<string, MCPToolConfig> = {};\n\n for (const tool of tools) {\n const currentToolConfig = currentToolsConfig[tool.name];\n\n // 如果工具已存在,保留用户设置的 enable 状态,但更新描述\n if (currentToolConfig) {\n newToolsConfig[tool.name] = {\n ...currentToolConfig,\n description:\n tool.description || currentToolConfig.description || \"\",\n };\n } else {\n // 新工具,默认启用\n newToolsConfig[tool.name] = {\n description: tool.description || \"\",\n enable: true,\n };\n }\n }\n\n // 检查是否有工具被移除(在配置文件中存在但在当前工具列表中不存在)\n const currentToolNames = tools.map((t) => t.name);\n const configToolNames = Object.keys(currentToolsConfig);\n const removedTools = configToolNames.filter(\n (name) => !currentToolNames.includes(name)\n );\n\n if (removedTools.length > 0) {\n this.logger.info(\n `[MCPManager] 检测到服务 ${serviceName} 移除了 ${removedTools.length} 个工具: ${removedTools.join(\", \")}`\n );\n }\n\n // 检查配置是否有变化\n const hasChanges = this.hasToolsConfigChanged(\n currentToolsConfig,\n newToolsConfig\n );\n\n if (hasChanges) {\n // 更新配置文件\n configManager.updateServerToolsConfig(serviceName, newToolsConfig);\n\n const addedTools = Object.keys(newToolsConfig).filter(\n (name) => !currentToolsConfig[name]\n );\n const updatedTools = Object.keys(newToolsConfig).filter((name) => {\n const current = currentToolsConfig[name];\n const updated = newToolsConfig[name];\n return current && current.description !== updated.description;\n });\n\n this.logger.info(\n `[MCPManager] 已同步服务 ${serviceName} 的工具配置:`\n );\n if (addedTools.length > 0) {\n this.logger.info(` - 新增工具: ${addedTools.join(\", \")}`);\n }\n if (updatedTools.length > 0) {\n this.logger.info(` - 更新工具: ${updatedTools.join(\", \")}`);\n }\n if (removedTools.length > 0) {\n this.logger.info(` - 移除工具: ${removedTools.join(\", \")}`);\n }\n }\n }\n\n this.logger.debug(\"[MCPManager] 工具配置同步完成\");\n } catch (error) {\n this.logger.error(\"[MCPManager] 同步工具配置到配置文件失败:\", error);\n // 不抛出错误,避免影响服务正常运行\n }\n }\n\n /**\n * 检查工具配置是否有变化\n */\n private hasToolsConfigChanged(\n currentConfig: Record<string, MCPToolConfig>,\n newConfig: Record<string, MCPToolConfig>\n ): boolean {\n const currentKeys = Object.keys(currentConfig);\n const newKeys = Object.keys(newConfig);\n\n // 检查工具数量是否变化\n if (currentKeys.length !== newKeys.length) {\n return true;\n }\n\n // 检查是否有新增或删除的工具\n const addedTools = newKeys.filter((key) => !currentKeys.includes(key));\n const removedTools = currentKeys.filter((key) => !newKeys.includes(key));\n\n if (addedTools.length > 0 || removedTools.length > 0) {\n return true;\n }\n\n // 检查现有工具的描述是否有变化\n for (const toolName of currentKeys) {\n const currentTool = currentConfig[toolName];\n const newTool = newConfig[toolName];\n\n if (currentTool.description !== newTool.description) {\n return true;\n }\n }\n\n return false;\n }\n}\n\nexport default MCPServiceManager;\n","/**\n * MCP 服务管理器单例\n * 提供全局唯一的 MCPServiceManager 实例,解决多实例资源冲突问题\n */\n\nimport MCPServiceManager from \"./MCPServiceManager.js\";\n\n// 重新导出相关类型,便于外部使用\nexport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nexport type { LocalMCPServerConfig } from \"../configManager.js\";\n\n// 单例状态枚举\nenum SingletonState {\n NOT_INITIALIZED = \"not_initialized\",\n INITIALIZING = \"initializing\",\n INITIALIZED = \"initialized\",\n FAILED = \"failed\",\n CLEANUP = \"cleanup\",\n}\n\n// 单例状态接口\ninterface SingletonStatus {\n state: SingletonState;\n initializationTime?: Date;\n lastError?: Error;\n instanceId?: string;\n}\n\n// 单例状态管理变量\nlet instance: MCPServiceManager | null = null;\nlet initPromise: Promise<MCPServiceManager> | null = null;\nlet state: SingletonState = SingletonState.NOT_INITIALIZED;\nlet lastError: Error | null = null;\nlet instanceId: string | null = null;\n\n/**\n * 创建 MCPServiceManager 实例(私有函数)\n */\nasync function createInstance(): Promise<MCPServiceManager> {\n console.log(\"🚀 正在初始化 MCPServiceManager 单例...\");\n\n const manager = new MCPServiceManager();\n\n return manager;\n}\n\n/**\n * 获取 MCPServiceManager 单例实例\n *\n * @returns Promise<MCPServiceManager> 管理器实例\n * @throws Error 如果初始化失败\n */\nasync function getInstance(): Promise<MCPServiceManager> {\n // 如果已经初始化完成,直接返回实例\n if (instance && state === SingletonState.INITIALIZED) {\n return instance;\n }\n\n // 如果正在初始化中,等待同一个初始化Promise\n if (initPromise && state === SingletonState.INITIALIZING) {\n return initPromise;\n }\n\n // 如果之前初始化失败,重置状态准备重试\n if (state === SingletonState.FAILED) {\n reset();\n }\n\n // 开始新的初始化过程\n state = SingletonState.INITIALIZING;\n initPromise = createInstance();\n\n try {\n instance = await initPromise;\n state = SingletonState.INITIALIZED;\n instanceId = `mcp-manager-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;\n lastError = null;\n\n console.log(`✅ MCPServiceManager 单例初始化成功,实例ID: ${instanceId}`);\n return instance;\n } catch (error) {\n state = SingletonState.FAILED;\n lastError = error as Error;\n initPromise = null;\n\n console.error(\n \"❌ MCPServiceManager 单例初始化失败:\",\n (error as Error).message\n );\n throw error;\n }\n}\n\n/**\n * 清理单例资源\n *\n * @returns Promise<void>\n */\nasync function cleanup(): Promise<void> {\n if (state === SingletonState.CLEANUP) {\n console.log(\"⚠️ MCPServiceManager 单例已在清理中,跳过重复清理\");\n return;\n }\n\n console.log(\"🧹 正在清理 MCPServiceManager 单例资源...\");\n state = SingletonState.CLEANUP;\n\n try {\n // 清理初始化Promise\n if (initPromise) {\n try {\n const instanceFromPromise = await initPromise;\n await instanceFromPromise.stopAllServices();\n } catch (error) {\n console.error(\"清理初始化中的实例失败:\", (error as Error).message);\n }\n initPromise = null;\n }\n\n // 清理已初始化的实例\n if (instance) {\n await instance.stopAllServices();\n instance = null;\n }\n\n state = SingletonState.NOT_INITIALIZED;\n lastError = null;\n instanceId = null;\n\n console.log(\"✅ MCPServiceManager 单例资源清理完成\");\n } catch (error) {\n console.error(\n \"❌ MCPServiceManager 单例清理失败:\",\n (error as Error).message\n );\n // 即使清理失败,也要重置状态,避免永久锁定\n reset();\n throw error;\n }\n}\n\n/**\n * 重置单例状态(用于错误恢复)\n *\n * 注意:这个方法不会清理资源,只是重置状态\n * 如果需要清理资源,请使用 cleanup() 方法\n */\nfunction reset(): void {\n console.log(\"🔄 重置 MCPServiceManager 单例状态\");\n\n instance = null;\n initPromise = null;\n state = SingletonState.NOT_INITIALIZED;\n lastError = null;\n instanceId = null;\n}\n\n/**\n * 检查单例是否已初始化\n *\n * @returns boolean 是否已初始化\n */\nfunction isInitialized(): boolean {\n return state === SingletonState.INITIALIZED && instance !== null;\n}\n\n/**\n * 获取单例状态信息\n *\n * @returns SingletonStatus 状态信息\n */\nfunction getStatus(): SingletonStatus {\n return {\n state: state,\n initializationTime: instanceId ? new Date() : undefined,\n lastError: lastError || undefined,\n instanceId: instanceId || undefined,\n };\n}\n\n/**\n * 强制重新初始化单例\n *\n * 这个方法会先清理现有资源,然后重新初始化\n *\n * @returns Promise<MCPServiceManager> 新的管理器实例\n */\nasync function forceReinitialize(): Promise<MCPServiceManager> {\n console.log(\"🔄 强制重新初始化 MCPServiceManager 单例...\");\n\n await cleanup();\n return getInstance();\n}\n\n/**\n * 获取当前实例(同步方法,仅在确定已初始化时使用)\n *\n * @returns MCPServiceManager | null 当前实例或null\n */\nfunction getCurrentInstance(): MCPServiceManager | null {\n return instance;\n}\n\n/**\n * 等待初始化完成(如果正在初始化中)\n *\n * @returns Promise<boolean> 是否成功初始化\n */\nasync function waitForInitialization(): Promise<boolean> {\n if (state === SingletonState.INITIALIZED) {\n return true;\n }\n\n if (state === SingletonState.INITIALIZING && initPromise) {\n try {\n await initPromise;\n return true;\n } catch (error) {\n return false;\n }\n }\n\n return false;\n}\n\n/**\n * MCPServiceManager 全局单例管理器\n *\n * 使用对象包装模块级函数,保持原有API接口不变\n */\nexport const MCPServiceManagerSingleton = {\n getInstance,\n cleanup,\n reset,\n isInitialized,\n getStatus,\n forceReinitialize,\n getCurrentInstance,\n waitForInitialization,\n} as const;\n\n// 导出默认实例(便于使用)\nexport default MCPServiceManagerSingleton;\n\n// 进程退出时自动清理资源\nprocess.on(\"exit\", () => {\n if (MCPServiceManagerSingleton.isInitialized()) {\n console.log(\"🔄 进程退出,正在清理 MCPServiceManager 单例...\");\n // 注意:这里不能使用 await,因为 exit 事件是同步的\n MCPServiceManagerSingleton.reset();\n }\n});\n\n// 处理未捕获的异常\nprocess.on(\"uncaughtException\", async (error) => {\n console.error(\"💥 未捕获的异常,清理 MCPServiceManager 单例:\", error);\n try {\n await MCPServiceManagerSingleton.cleanup();\n } catch (cleanupError) {\n console.error(\"清理过程中发生错误:\", cleanupError);\n }\n});\n\n// 处理未处理的Promise拒绝\nprocess.on(\"unhandledRejection\", async (reason) => {\n console.error(\"💥 未处理的Promise拒绝,清理 MCPServiceManager 单例:\", reason);\n try {\n await MCPServiceManagerSingleton.cleanup();\n } catch (cleanupError) {\n console.error(\"清理过程中发生错误:\", cleanupError);\n }\n});\n","import { EventEmitter } from \"node:events\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport { type Logger, logger } from \"../Logger.js\";\nimport { ProxyMCPServer } from \"../ProxyMCPServer.js\";\n\n// 使用接口定义避免循环依赖\ninterface IMCPServiceManager {\n getAllTools(): Tool[];\n}\n\n// 配置变更事件类型\nexport interface ConfigChangeEvent {\n type:\n | \"endpoints_added\"\n | \"endpoints_removed\"\n | \"endpoints_updated\"\n | \"options_updated\";\n data: {\n added?: string[];\n removed?: string[];\n updated?: string[];\n oldOptions?: Partial<XiaozhiConnectionOptions>;\n newOptions?: Partial<XiaozhiConnectionOptions>;\n };\n timestamp: Date;\n}\n\n// 重连策略枚举\nexport enum ReconnectStrategy {\n EXPONENTIAL_BACKOFF = \"exponential_backoff\",\n LINEAR_BACKOFF = \"linear_backoff\",\n FIXED_INTERVAL = \"fixed_interval\",\n ADAPTIVE = \"adaptive\",\n}\n\n// 错误类型枚举\nexport enum ConnectionErrorType {\n NETWORK_ERROR = \"network_error\",\n AUTHENTICATION_ERROR = \"authentication_error\",\n SERVER_ERROR = \"server_error\",\n TIMEOUT_ERROR = \"timeout_error\",\n UNKNOWN_ERROR = \"unknown_error\",\n}\n\n// 连接选项接口\nexport interface XiaozhiConnectionOptions {\n healthCheckInterval?: number; // 健康检查间隔(毫秒),默认 30000\n reconnectInterval?: number; // 重连间隔(毫秒),默认 5000\n maxReconnectAttempts?: number; // 最大重连次数,默认 10\n loadBalanceStrategy?: \"round-robin\" | \"random\" | \"health-based\"; // 负载均衡策略,默认 'round-robin'\n connectionTimeout?: number; // 连接超时时间(毫秒),默认 10000\n reconnectStrategy?: ReconnectStrategy; // 重连策略,默认 exponential_backoff\n maxReconnectDelay?: number; // 最大重连延迟(毫秒),默认 30000\n reconnectBackoffMultiplier?: number; // 退避乘数,默认 2\n jitterEnabled?: boolean; // 是否启用抖动,默认 true\n}\n\n// 连接状态接口\nexport interface ConnectionStatus {\n endpoint: string;\n connected: boolean;\n initialized: boolean;\n lastConnected?: Date;\n lastError?: string;\n reconnectAttempts: number;\n healthScore: number; // 健康度评分 (0-100)\n lastHealthCheck?: Date;\n responseTime?: number; // 响应时间(毫秒)\n consecutiveFailures: number; // 连续失败次数\n totalRequests: number; // 总请求次数\n successfulRequests: number; // 成功请求次数\n lastSuccessTime?: Date; // 最后成功时间\n healthCheckEnabled: boolean; // 是否启用健康检查\n // 重连相关状态\n isReconnecting: boolean; // 是否正在重连\n nextReconnectTime?: Date; // 下次重连时间\n lastReconnectAttempt?: Date; // 最后重连尝试时间\n reconnectDelay: number; // 当前重连延迟(毫秒)\n errorType?: ConnectionErrorType; // 错误类型\n reconnectHistory: Array<{\n // 重连历史\n timestamp: Date;\n success: boolean;\n error?: string;\n delay: number;\n }>;\n}\n\n// 连接状态枚举\nexport enum XiaozhiConnectionState {\n DISCONNECTED = \"disconnected\",\n CONNECTING = \"connecting\",\n CONNECTED = \"connected\",\n RECONNECTING = \"reconnecting\",\n FAILED = \"failed\",\n}\n\n// 默认配置\nconst DEFAULT_OPTIONS: Required<XiaozhiConnectionOptions> = {\n healthCheckInterval: 30000,\n reconnectInterval: 5000,\n maxReconnectAttempts: 10,\n loadBalanceStrategy: \"round-robin\",\n connectionTimeout: 10000,\n reconnectStrategy: ReconnectStrategy.EXPONENTIAL_BACKOFF,\n maxReconnectDelay: 30000,\n reconnectBackoffMultiplier: 2,\n jitterEnabled: true,\n};\n\n/**\n * 小智连接管理器\n * 负责管理多个小智接入点的连接,提供统一的连接管理、健康检查、负载均衡等功能\n */\nexport class XiaozhiConnectionManager extends EventEmitter {\n // 连接实例管理\n private connections: Map<string, ProxyMCPServer> = new Map();\n private connectionStates: Map<string, ConnectionStatus> = new Map();\n\n // 核心依赖\n private mcpServiceManager: IMCPServiceManager | null = null;\n private logger: Logger;\n\n // 状态管理\n private isInitialized = false;\n private isConnecting = false;\n\n // 配置选项\n private options: Required<XiaozhiConnectionOptions>;\n\n // 健康检查和重连管理\n private healthCheckInterval: NodeJS.Timeout | null = null;\n private reconnectTimers: Map<string, NodeJS.Timeout> = new Map();\n\n // 负载均衡状态\n private roundRobinIndex = 0;\n private lastSelectedEndpoint: string | null = null;\n\n // 性能监控\n private performanceMetrics = {\n connectionStartTime: 0,\n totalConnectionTime: 0,\n averageConnectionTime: 0,\n connectionCount: 0,\n memoryUsage: {\n initial: 0,\n current: 0,\n peak: 0,\n },\n prewarmedConnections: new Set<string>(),\n };\n\n constructor(options?: XiaozhiConnectionOptions) {\n super();\n this.logger = logger;\n this.options = { ...DEFAULT_OPTIONS, ...options };\n\n this.logger.info(\"[XiaozhiConnectionManager] 实例已创建\");\n this.logger.debug(\"[XiaozhiConnectionManager] 配置选项:\", this.options);\n }\n\n /**\n * 初始化连接管理器\n * @param endpoints 小智接入点列表\n * @param tools 工具列表\n */\n async initialize(endpoints: string[], tools: Tool[]): Promise<void> {\n if (this.isInitialized) {\n this.logger.warn(\"XiaozhiConnectionManager 已经初始化,跳过重复初始化\");\n return;\n }\n\n this.logger.info(\n `开始初始化 XiaozhiConnectionManager,端点数量: ${endpoints.length}`\n );\n\n try {\n // 验证输入参数\n this.validateInitializeParams(endpoints, tools);\n\n // 清理现有连接(如果有)\n await this.cleanup();\n\n // 为每个端点创建连接实例\n for (const endpoint of endpoints) {\n await this.createConnection(endpoint, tools);\n }\n\n this.isInitialized = true;\n\n // 记录初始内存使用\n this.performanceMetrics.memoryUsage.initial =\n process.memoryUsage().heapUsed;\n this.performanceMetrics.memoryUsage.current =\n this.performanceMetrics.memoryUsage.initial;\n this.performanceMetrics.memoryUsage.peak =\n this.performanceMetrics.memoryUsage.initial;\n\n this.logger.info(\n `XiaozhiConnectionManager 初始化完成,管理 ${this.connections.size} 个连接`\n );\n } catch (error) {\n this.logger.error(\"XiaozhiConnectionManager 初始化失败:\", error);\n await this.cleanup(); // 清理部分创建的连接\n throw error;\n }\n }\n\n /**\n * 连接所有端点\n */\n async connect(): Promise<void> {\n if (!this.isInitialized) {\n throw new Error(\n \"XiaozhiConnectionManager 未初始化,请先调用 initialize()\"\n );\n }\n\n if (this.isConnecting) {\n this.logger.warn(\"连接操作正在进行中,请等待完成\");\n return;\n }\n\n this.isConnecting = true;\n this.performanceMetrics.connectionStartTime = Date.now();\n this.logger.info(`开始连接所有端点,总数: ${this.connections.size}`);\n\n try {\n const connectionPromises: Promise<void>[] = [];\n\n // 并发连接所有端点\n for (const [endpoint, proxyServer] of this.connections) {\n connectionPromises.push(\n this.connectSingleEndpoint(endpoint, proxyServer)\n );\n }\n\n // 等待所有连接完成(允许部分失败)\n const results = await Promise.allSettled(connectionPromises);\n\n // 统计连接结果\n const successCount = results.filter(\n (result) => result.status === \"fulfilled\"\n ).length;\n const failureCount = results.length - successCount;\n\n // 更新性能指标\n const connectionTime =\n Date.now() - this.performanceMetrics.connectionStartTime;\n this.performanceMetrics.totalConnectionTime += connectionTime;\n this.performanceMetrics.connectionCount++;\n this.performanceMetrics.averageConnectionTime =\n this.performanceMetrics.totalConnectionTime /\n this.performanceMetrics.connectionCount;\n\n this.logger.info(\n `连接完成 - 成功: ${successCount}, 失败: ${failureCount}, 耗时: ${connectionTime}ms`\n );\n\n // 如果所有连接都失败,抛出错误\n if (successCount === 0) {\n throw new Error(\"所有小智接入点连接失败\");\n }\n\n // 启动健康检查\n this.startHealthCheck();\n } finally {\n this.isConnecting = false;\n }\n }\n\n /**\n * 断开所有连接\n */\n async disconnect(): Promise<void> {\n this.logger.info(\"开始断开所有连接\");\n\n // 停止健康检查\n this.stopHealthCheck();\n\n // 清理重连定时器\n this.clearAllReconnectTimers();\n\n // 断开所有连接\n const disconnectPromises: Promise<void>[] = [];\n for (const [endpoint, proxyServer] of this.connections) {\n disconnectPromises.push(\n this.disconnectSingleEndpoint(endpoint, proxyServer)\n );\n }\n\n await Promise.allSettled(disconnectPromises);\n this.logger.info(\"所有连接已断开\");\n }\n\n /**\n * 动态添加端点\n * @param endpoint 端点地址\n */\n async addEndpoint(endpoint: string): Promise<void> {\n if (!this.isInitialized) {\n throw new Error(\"XiaozhiConnectionManager 未初始化\");\n }\n\n if (this.connections.has(endpoint)) {\n this.logger.warn(`端点 ${endpoint} 已存在,跳过添加`);\n return;\n }\n\n this.logger.info(`动态添加端点: ${endpoint}`);\n\n try {\n // 获取当前工具列表\n const tools = this.getCurrentTools();\n\n // 创建新连接\n await this.createConnection(endpoint, tools);\n\n // 如果管理器已连接,则连接新端点\n if (this.isAnyConnected()) {\n const proxyServer = this.connections.get(endpoint)!;\n await this.connectSingleEndpoint(endpoint, proxyServer);\n }\n\n this.logger.info(`端点 ${endpoint} 添加成功`);\n } catch (error) {\n this.logger.error(`添加端点 ${endpoint} 失败:`, error);\n // 清理失败的连接\n this.connections.delete(endpoint);\n this.connectionStates.delete(endpoint);\n throw error;\n }\n }\n\n /**\n * 动态移除端点\n * @param endpoint 端点地址\n */\n async removeEndpoint(endpoint: string): Promise<void> {\n if (!this.connections.has(endpoint)) {\n this.logger.warn(`端点 ${endpoint} 不存在,跳过移除`);\n return;\n }\n\n this.logger.info(`动态移除端点: ${endpoint}`);\n\n try {\n const proxyServer = this.connections.get(endpoint)!;\n\n // 断开连接\n await this.disconnectSingleEndpoint(endpoint, proxyServer);\n\n // 清理资源\n this.connections.delete(endpoint);\n this.connectionStates.delete(endpoint);\n\n // 清理重连定时器\n const timer = this.reconnectTimers.get(endpoint);\n if (timer) {\n clearTimeout(timer);\n this.reconnectTimers.delete(endpoint);\n }\n\n this.logger.info(`端点 ${endpoint} 移除成功`);\n } catch (error) {\n this.logger.error(`移除端点 ${endpoint} 失败:`, error);\n throw error;\n }\n }\n\n /**\n * 获取健康的连接列表\n */\n getHealthyConnections(): ProxyMCPServer[] {\n const healthyConnections: ProxyMCPServer[] = [];\n\n for (const [endpoint, proxyServer] of this.connections) {\n const status = this.connectionStates.get(endpoint);\n if (status?.connected && status.healthScore > 50) {\n healthyConnections.push(proxyServer);\n }\n }\n\n return healthyConnections;\n }\n\n /**\n * 获取所有连接状态\n */\n getConnectionStatus(): ConnectionStatus[] {\n return Array.from(this.connectionStates.values());\n }\n\n /**\n * 检查是否有任何连接处于连接状态\n */\n isAnyConnected(): boolean {\n for (const status of this.connectionStates.values()) {\n if (status.connected) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * 设置 MCP 服务管理器\n * @param manager MCP 服务管理器实例\n */\n setServiceManager(manager: IMCPServiceManager): void {\n this.mcpServiceManager = manager;\n this.logger.info(\"已设置 MCPServiceManager\");\n\n // 如果已有连接,同步工具到所有连接\n if (this.connections.size > 0) {\n this.syncToolsToAllConnections();\n }\n }\n\n /**\n * 启用/禁用指定端点的健康检查\n * @param endpoint 端点地址\n * @param enabled 是否启用\n */\n setHealthCheckEnabled(endpoint: string, enabled: boolean): void {\n const status = this.connectionStates.get(endpoint);\n if (status) {\n status.healthCheckEnabled = enabled;\n this.logger.info(\n `端点 ${endpoint} 健康检查已${enabled ? \"启用\" : \"禁用\"}`\n );\n } else {\n this.logger.warn(`端点 ${endpoint} 不存在,无法设置健康检查状态`);\n }\n }\n\n /**\n * 获取健康检查统计信息\n */\n getHealthCheckStats(): Record<\n string,\n {\n endpoint: string;\n healthScore: number;\n successRate: number;\n averageResponseTime: number;\n consecutiveFailures: number;\n lastHealthCheck?: Date;\n lastSuccessTime?: Date;\n }\n > {\n const stats: Record<string, any> = {};\n\n for (const [endpoint, status] of this.connectionStates) {\n const successRate =\n status.totalRequests > 0\n ? (status.successfulRequests / status.totalRequests) * 100\n : 0;\n\n stats[endpoint] = {\n endpoint,\n healthScore: status.healthScore,\n successRate: Math.round(successRate * 100) / 100,\n averageResponseTime: status.responseTime || 0,\n consecutiveFailures: status.consecutiveFailures,\n lastHealthCheck: status.lastHealthCheck,\n lastSuccessTime: status.lastSuccessTime,\n };\n }\n\n return stats;\n }\n\n /**\n * 手动触发健康检查\n */\n async triggerHealthCheck(): Promise<void> {\n this.logger.info(\"手动触发健康检查\");\n await this.performHealthCheck();\n }\n\n /**\n * 手动触发指定端点的重连\n * @param endpoint 端点地址\n */\n async triggerReconnect(endpoint: string): Promise<void> {\n const status = this.connectionStates.get(endpoint);\n if (!status) {\n throw new Error(`端点 ${endpoint} 不存在`);\n }\n\n if (status.connected) {\n this.logger.warn(`端点 ${endpoint} 已连接,无需重连`);\n return;\n }\n\n this.logger.info(`手动触发重连: ${endpoint}`);\n\n // 清理现有的重连定时器\n const existingTimer = this.reconnectTimers.get(endpoint);\n if (existingTimer) {\n clearTimeout(existingTimer);\n this.reconnectTimers.delete(endpoint);\n }\n\n // 立即执行重连\n await this.performReconnect(endpoint);\n }\n\n /**\n * 停止指定端点的重连\n * @param endpoint 端点地址\n */\n stopReconnect(endpoint: string): void {\n const status = this.connectionStates.get(endpoint);\n if (!status) {\n this.logger.warn(`端点 ${endpoint} 不存在`);\n return;\n }\n\n const timer = this.reconnectTimers.get(endpoint);\n if (timer) {\n clearTimeout(timer);\n this.reconnectTimers.delete(endpoint);\n status.isReconnecting = false;\n status.nextReconnectTime = undefined;\n this.logger.info(`已停止端点 ${endpoint} 的重连`);\n }\n }\n\n /**\n * 停止所有端点的重连\n */\n stopAllReconnects(): void {\n this.logger.info(\"停止所有端点的重连\");\n\n for (const [endpoint] of this.reconnectTimers) {\n this.stopReconnect(endpoint);\n }\n }\n\n /**\n * 获取重连统计信息\n */\n getReconnectStats(): Record<\n string,\n {\n endpoint: string;\n reconnectAttempts: number;\n isReconnecting: boolean;\n nextReconnectTime?: Date;\n lastReconnectAttempt?: Date;\n reconnectDelay: number;\n errorType?: ConnectionErrorType;\n recentReconnectHistory: Array<{\n timestamp: Date;\n success: boolean;\n error?: string;\n delay: number;\n }>;\n }\n > {\n const stats: Record<string, any> = {};\n\n for (const [endpoint, status] of this.connectionStates) {\n stats[endpoint] = {\n endpoint,\n reconnectAttempts: status.reconnectAttempts,\n isReconnecting: status.isReconnecting,\n nextReconnectTime: status.nextReconnectTime,\n lastReconnectAttempt: status.lastReconnectAttempt,\n reconnectDelay: status.reconnectDelay,\n errorType: status.errorType,\n recentReconnectHistory: status.reconnectHistory.slice(-5), // 最近5次\n };\n }\n\n return stats;\n }\n\n /**\n * 验证端点配置\n */\n private validateEndpoints(endpoints: string[]): {\n valid: string[];\n invalid: string[];\n } {\n const valid: string[] = [];\n const invalid: string[] = [];\n\n for (const endpoint of endpoints) {\n if (!endpoint || typeof endpoint !== \"string\") {\n invalid.push(endpoint);\n continue;\n }\n\n if (!endpoint.startsWith(\"ws://\") && !endpoint.startsWith(\"wss://\")) {\n invalid.push(endpoint);\n continue;\n }\n\n // 检查是否是有效的 URL\n try {\n new URL(endpoint);\n valid.push(endpoint);\n } catch {\n invalid.push(endpoint);\n }\n }\n\n return { valid, invalid };\n }\n\n /**\n * 验证连接选项\n */\n private validateOptions(options: Partial<XiaozhiConnectionOptions>): {\n valid: boolean;\n errors: string[];\n } {\n const errors: string[] = [];\n\n if (options.healthCheckInterval !== undefined) {\n if (\n typeof options.healthCheckInterval !== \"number\" ||\n options.healthCheckInterval < 1000\n ) {\n errors.push(\"healthCheckInterval 必须是大于等于 1000 的数字\");\n }\n }\n\n if (options.reconnectInterval !== undefined) {\n if (\n typeof options.reconnectInterval !== \"number\" ||\n options.reconnectInterval < 100\n ) {\n errors.push(\"reconnectInterval 必须是大于等于 100 的数字\");\n }\n }\n\n if (options.maxReconnectAttempts !== undefined) {\n if (\n typeof options.maxReconnectAttempts !== \"number\" ||\n options.maxReconnectAttempts < 0\n ) {\n errors.push(\"maxReconnectAttempts 必须是大于等于 0 的数字\");\n }\n }\n\n if (options.connectionTimeout !== undefined) {\n if (\n typeof options.connectionTimeout !== \"number\" ||\n options.connectionTimeout < 1000\n ) {\n errors.push(\"connectionTimeout 必须是大于等于 1000 的数字\");\n }\n }\n\n if (options.maxReconnectDelay !== undefined) {\n if (\n typeof options.maxReconnectDelay !== \"number\" ||\n options.maxReconnectDelay < 1000\n ) {\n errors.push(\"maxReconnectDelay 必须是大于等于 1000 的数字\");\n }\n }\n\n if (options.reconnectBackoffMultiplier !== undefined) {\n if (\n typeof options.reconnectBackoffMultiplier !== \"number\" ||\n options.reconnectBackoffMultiplier < 1\n ) {\n errors.push(\"reconnectBackoffMultiplier 必须是大于等于 1 的数字\");\n }\n }\n\n if (options.loadBalanceStrategy !== undefined) {\n const validStrategies = [\"round-robin\", \"random\", \"health-based\"];\n if (!validStrategies.includes(options.loadBalanceStrategy)) {\n errors.push(\n `loadBalanceStrategy 必须是以下值之一: ${validStrategies.join(\", \")}`\n );\n }\n }\n\n if (options.reconnectStrategy !== undefined) {\n const validStrategies = Object.values(ReconnectStrategy);\n if (!validStrategies.includes(options.reconnectStrategy)) {\n errors.push(\n `reconnectStrategy 必须是以下值之一: ${validStrategies.join(\", \")}`\n );\n }\n }\n\n return { valid: errors.length === 0, errors };\n }\n\n /**\n * 更新端点配置\n * @param newEndpoints 新的端点列表\n * @param tools 工具列表\n */\n async updateEndpoints(\n newEndpoints: string[],\n tools: Tool[] = []\n ): Promise<void> {\n if (!this.isInitialized) {\n throw new Error(\"XiaozhiConnectionManager 未初始化\");\n }\n\n this.logger.info(`更新端点配置,新端点数量: ${newEndpoints.length}`);\n\n // 验证新端点\n const { valid: validEndpoints, invalid: invalidEndpoints } =\n this.validateEndpoints(newEndpoints);\n\n if (invalidEndpoints.length > 0) {\n this.logger.warn(`发现无效端点: ${invalidEndpoints.join(\", \")}`);\n }\n\n if (validEndpoints.length === 0) {\n throw new Error(\"没有有效的端点\");\n }\n\n // 计算变更\n const currentEndpoints = Array.from(this.connections.keys());\n const toAdd = validEndpoints.filter((ep) => !currentEndpoints.includes(ep));\n const toRemove = currentEndpoints.filter(\n (ep) => !validEndpoints.includes(ep)\n );\n const toKeep = currentEndpoints.filter((ep) => validEndpoints.includes(ep));\n\n this.logger.info(\n `端点变更 - 添加: ${toAdd.length}, 移除: ${toRemove.length}, 保持: ${toKeep.length}`\n );\n\n try {\n // 移除不需要的端点\n for (const endpoint of toRemove) {\n await this.removeEndpoint(endpoint);\n }\n\n // 添加新端点\n for (const endpoint of toAdd) {\n await this.addEndpoint(endpoint);\n }\n\n // 发送配置变更事件\n const changeEvent: ConfigChangeEvent = {\n type:\n toAdd.length > 0 && toRemove.length > 0\n ? \"endpoints_updated\"\n : toAdd.length > 0\n ? \"endpoints_added\"\n : \"endpoints_removed\",\n data: {\n added: toAdd.length > 0 ? toAdd : undefined,\n removed: toRemove.length > 0 ? toRemove : undefined,\n updated:\n toAdd.length > 0 && toRemove.length > 0\n ? validEndpoints\n : undefined,\n },\n timestamp: new Date(),\n };\n\n this.emit(\"configChange\", changeEvent);\n this.logger.info(\"端点配置更新完成\");\n } catch (error) {\n this.logger.error(\"端点配置更新失败:\", error);\n throw error;\n }\n }\n\n /**\n * 更新连接选项\n * @param newOptions 新的连接选项\n */\n updateOptions(newOptions: Partial<XiaozhiConnectionOptions>): void {\n this.logger.info(\"更新连接选项\");\n\n // 验证新选项\n const { valid, errors } = this.validateOptions(newOptions);\n\n if (!valid) {\n throw new Error(`无效的连接选项: ${errors.join(\", \")}`);\n }\n\n const oldOptions = { ...this.options };\n\n // 更新选项\n this.options = { ...this.options, ...newOptions };\n\n // 发送配置变更事件\n const changeEvent: ConfigChangeEvent = {\n type: \"options_updated\",\n data: {\n oldOptions,\n newOptions,\n },\n timestamp: new Date(),\n };\n\n this.emit(\"configChange\", changeEvent);\n this.logger.info(\"连接选项更新完成\");\n this.logger.debug(\"新的配置选项:\", this.options);\n }\n\n /**\n * 获取当前配置\n */\n getCurrentConfig(): {\n endpoints: string[];\n options: Required<XiaozhiConnectionOptions>;\n } {\n return {\n endpoints: Array.from(this.connections.keys()),\n options: { ...this.options },\n };\n }\n\n /**\n * 热重载配置\n * @param config 新配置\n */\n async reloadConfig(config: {\n endpoints?: string[];\n options?: Partial<XiaozhiConnectionOptions>;\n tools?: Tool[];\n }): Promise<void> {\n this.logger.info(\"开始热重载配置\");\n\n try {\n // 更新选项(如果提供)\n if (config.options) {\n this.updateOptions(config.options);\n }\n\n // 更新端点(如果提供)\n if (config.endpoints) {\n await this.updateEndpoints(config.endpoints, config.tools || []);\n }\n\n this.logger.info(\"配置热重载完成\");\n } catch (error) {\n this.logger.error(\"配置热重载失败:\", error);\n throw error;\n }\n }\n\n /**\n * 根据负载均衡策略选择最佳连接\n * @param excludeEndpoints 要排除的端点列表\n */\n selectBestConnection(excludeEndpoints: string[] = []): ProxyMCPServer | null {\n const healthyConnections = this.getHealthyConnections();\n\n if (healthyConnections.length === 0) {\n this.logger.warn(\"没有健康的连接可用\");\n return null;\n }\n\n // 过滤掉要排除的端点\n const availableConnections = healthyConnections.filter((connection) => {\n const endpoint = this.getEndpointByConnection(connection);\n return endpoint && !excludeEndpoints.includes(endpoint);\n });\n\n if (availableConnections.length === 0) {\n this.logger.warn(\"没有可用的连接(排除指定端点后)\");\n return null;\n }\n\n let selectedConnection: ProxyMCPServer;\n\n switch (this.options.loadBalanceStrategy) {\n case \"round-robin\":\n selectedConnection = this.selectRoundRobin(availableConnections);\n break;\n\n case \"random\":\n selectedConnection = this.selectRandom(availableConnections);\n break;\n\n case \"health-based\":\n selectedConnection = this.selectHealthBased(availableConnections);\n break;\n\n default:\n selectedConnection = this.selectRoundRobin(availableConnections);\n }\n\n // 更新最后选择的端点\n this.lastSelectedEndpoint =\n this.getEndpointByConnection(selectedConnection);\n\n return selectedConnection;\n }\n\n /**\n * 轮询算法选择连接\n */\n private selectRoundRobin(connections: ProxyMCPServer[]): ProxyMCPServer {\n if (connections.length === 0) {\n throw new Error(\"没有可用的连接\");\n }\n\n const connection = connections[this.roundRobinIndex % connections.length];\n this.roundRobinIndex = (this.roundRobinIndex + 1) % connections.length;\n\n return connection;\n }\n\n /**\n * 随机算法选择连接\n */\n private selectRandom(connections: ProxyMCPServer[]): ProxyMCPServer {\n if (connections.length === 0) {\n throw new Error(\"没有可用的连接\");\n }\n\n const randomIndex = Math.floor(Math.random() * connections.length);\n return connections[randomIndex];\n }\n\n /**\n * 基于健康度的选择算法\n */\n private selectHealthBased(connections: ProxyMCPServer[]): ProxyMCPServer {\n if (connections.length === 0) {\n throw new Error(\"没有可用的连接\");\n }\n\n // 获取所有连接的健康度信息\n const connectionHealths = connections.map((connection) => {\n const endpoint = this.getEndpointByConnection(connection);\n const status = endpoint ? this.connectionStates.get(endpoint) : null;\n return {\n connection,\n endpoint,\n healthScore: status?.healthScore || 0,\n responseTime: status?.responseTime || Number.POSITIVE_INFINITY,\n successRate:\n status && status.totalRequests > 0\n ? (status.successfulRequests / status.totalRequests) * 100\n : 0,\n };\n });\n\n // 按健康度排序(健康度高、响应时间短、成功率高的优先)\n connectionHealths.sort((a, b) => {\n // 首先按健康度排序\n if (a.healthScore !== b.healthScore) {\n return b.healthScore - a.healthScore;\n }\n\n // 健康度相同时,按成功率排序\n if (a.successRate !== b.successRate) {\n return b.successRate - a.successRate;\n }\n\n // 成功率相同时,按响应时间排序\n return a.responseTime - b.responseTime;\n });\n\n // 使用加权随机选择,健康度高的连接被选中的概率更大\n const totalWeight = connectionHealths.reduce(\n (sum, item) => sum + (item.healthScore + 1),\n 0\n );\n let randomWeight = Math.random() * totalWeight;\n\n for (const item of connectionHealths) {\n randomWeight -= item.healthScore + 1;\n if (randomWeight <= 0) {\n return item.connection;\n }\n }\n\n // 如果没有选中任何连接,返回健康度最高的\n return connectionHealths[0].connection;\n }\n\n /**\n * 根据连接实例获取端点地址\n */\n private getEndpointByConnection(connection: ProxyMCPServer): string | null {\n for (const [endpoint, conn] of this.connections) {\n if (conn === connection) {\n return endpoint;\n }\n }\n return null;\n }\n\n /**\n * 获取负载均衡统计信息\n */\n getLoadBalanceStats(): {\n strategy: string;\n totalConnections: number;\n healthyConnections: number;\n lastSelectedEndpoint: string | null;\n roundRobinIndex: number;\n connectionWeights: Record<\n string,\n {\n healthScore: number;\n responseTime: number;\n successRate: number;\n weight: number;\n }\n >;\n } {\n const healthyConnections = this.getHealthyConnections();\n const connectionWeights: Record<string, any> = {};\n\n for (const [endpoint, status] of this.connectionStates) {\n const successRate =\n status.totalRequests > 0\n ? (status.successfulRequests / status.totalRequests) * 100\n : 0;\n\n // 计算权重(用于健康度选择算法)\n const weight = status.healthScore + 1;\n\n connectionWeights[endpoint] = {\n healthScore: status.healthScore,\n responseTime: status.responseTime || 0,\n successRate: Math.round(successRate * 100) / 100,\n weight,\n };\n }\n\n return {\n strategy: this.options.loadBalanceStrategy,\n totalConnections: this.connections.size,\n healthyConnections: healthyConnections.length,\n lastSelectedEndpoint: this.lastSelectedEndpoint,\n roundRobinIndex: this.roundRobinIndex,\n connectionWeights,\n };\n }\n\n /**\n * 切换负载均衡策略\n * @param strategy 新的负载均衡策略\n */\n setLoadBalanceStrategy(\n strategy: \"round-robin\" | \"random\" | \"health-based\"\n ): void {\n const oldStrategy = this.options.loadBalanceStrategy;\n this.options.loadBalanceStrategy = strategy;\n\n // 重置轮询索引\n if (strategy === \"round-robin\") {\n this.roundRobinIndex = 0;\n }\n\n this.logger.info(`负载均衡策略已从 ${oldStrategy} 切换到 ${strategy}`);\n\n // 发送配置变更事件\n const changeEvent: ConfigChangeEvent = {\n type: \"options_updated\",\n data: {\n oldOptions: { loadBalanceStrategy: oldStrategy },\n newOptions: { loadBalanceStrategy: strategy },\n },\n timestamp: new Date(),\n };\n\n this.emit(\"configChange\", changeEvent);\n }\n\n /**\n * 执行故障转移\n * @param failedEndpoint 失败的端点\n */\n async performFailover(\n failedEndpoint: string\n ): Promise<ProxyMCPServer | null> {\n this.logger.warn(`执行故障转移,失败端点: ${failedEndpoint}`);\n\n // 选择备用连接(排除失败的端点)\n const backupConnection = this.selectBestConnection([failedEndpoint]);\n\n if (!backupConnection) {\n this.logger.error(\"故障转移失败:没有可用的备用连接\");\n return null;\n }\n\n const backupEndpoint = this.getEndpointByConnection(backupConnection);\n this.logger.info(`故障转移成功,切换到端点: ${backupEndpoint}`);\n\n return backupConnection;\n }\n\n /**\n * 连接预热机制\n * @param endpoints 要预热的端点列表\n */\n async prewarmConnections(endpoints: string[] = []): Promise<void> {\n const targetEndpoints =\n endpoints.length > 0 ? endpoints : Array.from(this.connections.keys());\n\n this.logger.info(`开始预热连接,端点数量: ${targetEndpoints.length}`);\n\n const prewarmPromises = targetEndpoints.map(async (endpoint) => {\n if (this.performanceMetrics.prewarmedConnections.has(endpoint)) {\n this.logger.debug(`端点 ${endpoint} 已预热,跳过`);\n return;\n }\n\n try {\n const connection = this.connections.get(endpoint);\n if (connection) {\n // 执行预热操作(例如建立连接、验证状态等)\n await this.performHealthCheck();\n this.performanceMetrics.prewarmedConnections.add(endpoint);\n this.logger.debug(`端点 ${endpoint} 预热完成`);\n }\n } catch (error) {\n this.logger.warn(`端点 ${endpoint} 预热失败:`, error);\n }\n });\n\n await Promise.all(prewarmPromises);\n this.logger.info(\n `连接预热完成,成功预热 ${this.performanceMetrics.prewarmedConnections.size} 个端点`\n );\n }\n\n /**\n * 更新性能指标\n */\n private updatePerformanceMetrics(): void {\n const currentMemory = process.memoryUsage().heapUsed;\n this.performanceMetrics.memoryUsage.current = currentMemory;\n\n if (currentMemory > this.performanceMetrics.memoryUsage.peak) {\n this.performanceMetrics.memoryUsage.peak = currentMemory;\n }\n }\n\n /**\n * 获取性能指标\n */\n getPerformanceMetrics(): {\n connectionTime: {\n total: number;\n average: number;\n count: number;\n };\n memoryUsage: {\n initial: number;\n current: number;\n peak: number;\n growth: number;\n growthPercentage: number;\n };\n prewarmedConnections: number;\n totalConnections: number;\n healthyConnections: number;\n } {\n this.updatePerformanceMetrics();\n\n const memoryGrowth =\n this.performanceMetrics.memoryUsage.current -\n this.performanceMetrics.memoryUsage.initial;\n const growthPercentage =\n this.performanceMetrics.memoryUsage.initial > 0\n ? (memoryGrowth / this.performanceMetrics.memoryUsage.initial) * 100\n : 0;\n\n return {\n connectionTime: {\n total: this.performanceMetrics.totalConnectionTime,\n average: this.performanceMetrics.averageConnectionTime,\n count: this.performanceMetrics.connectionCount,\n },\n memoryUsage: {\n initial: this.performanceMetrics.memoryUsage.initial,\n current: this.performanceMetrics.memoryUsage.current,\n peak: this.performanceMetrics.memoryUsage.peak,\n growth: memoryGrowth,\n growthPercentage: Math.round(growthPercentage * 100) / 100,\n },\n prewarmedConnections: this.performanceMetrics.prewarmedConnections.size,\n totalConnections: this.connections.size,\n healthyConnections: this.getHealthyConnections().length,\n };\n }\n\n /**\n * 优化内存使用\n */\n optimizeMemoryUsage(): void {\n this.logger.info(\"开始内存优化\");\n\n // 清理过期的重连历史记录和健康检查历史\n for (const [, status] of this.connectionStates) {\n if (status.reconnectHistory && status.reconnectHistory.length > 10) {\n // 只保留最近10次记录\n status.reconnectHistory = status.reconnectHistory.slice(-10);\n }\n\n // 清理过期的健康检查历史\n // 重置一些累积的统计数据以防止无限增长\n if (status.totalRequests > 10000) {\n // 重置计数器,但保持比率\n const successRate = status.successfulRequests / status.totalRequests;\n status.totalRequests = 1000;\n status.successfulRequests = Math.round(successRate * 1000);\n }\n }\n\n // 强制垃圾回收(如果可用)\n if (global.gc) {\n global.gc();\n }\n\n this.updatePerformanceMetrics();\n this.logger.info(\"内存优化完成\");\n }\n\n /**\n * 资源清理\n */\n async cleanup(): Promise<void> {\n this.logger.info(\"开始清理 XiaozhiConnectionManager 资源\");\n\n try {\n // 断开所有连接\n await this.disconnect();\n\n // 清理连接实例\n this.connections.clear();\n this.connectionStates.clear();\n\n // 重置状态\n this.isInitialized = false;\n this.isConnecting = false;\n this.roundRobinIndex = 0;\n this.lastSelectedEndpoint = null;\n\n this.logger.info(\"XiaozhiConnectionManager 资源清理完成\");\n } catch (error) {\n this.logger.error(\"XiaozhiConnectionManager 资源清理失败:\", error);\n throw error;\n }\n }\n\n // ==================== 私有方法 ====================\n\n /**\n * 验证初始化参数\n */\n private validateInitializeParams(endpoints: string[], tools: Tool[]): void {\n if (!Array.isArray(endpoints) || endpoints.length === 0) {\n throw new Error(\"端点列表不能为空\");\n }\n\n if (!Array.isArray(tools)) {\n throw new Error(\"工具列表必须是数组\");\n }\n\n // 验证端点格式\n for (const endpoint of endpoints) {\n if (!endpoint || typeof endpoint !== \"string\") {\n throw new Error(`无效的端点地址: ${endpoint}`);\n }\n\n if (!endpoint.startsWith(\"ws://\") && !endpoint.startsWith(\"wss://\")) {\n throw new Error(`端点地址必须是 WebSocket URL: ${endpoint}`);\n }\n }\n }\n\n /**\n * 创建单个连接\n */\n private async createConnection(\n endpoint: string,\n tools: Tool[]\n ): Promise<void> {\n this.logger.debug(`创建连接实例: ${endpoint}`);\n\n try {\n // 创建 ProxyMCPServer 实例\n const proxyServer = new ProxyMCPServer(endpoint);\n\n // 设置 MCP 服务管理器\n if (this.mcpServiceManager) {\n proxyServer.setServiceManager(this.mcpServiceManager);\n }\n\n // 存储连接实例\n this.connections.set(endpoint, proxyServer);\n\n // 初始化连接状态\n this.connectionStates.set(endpoint, {\n endpoint,\n connected: false,\n initialized: false,\n reconnectAttempts: 0,\n healthScore: 100, // 初始健康度为满分\n consecutiveFailures: 0,\n totalRequests: 0,\n successfulRequests: 0,\n healthCheckEnabled: true,\n isReconnecting: false,\n reconnectDelay: this.options.reconnectInterval,\n reconnectHistory: [],\n });\n\n this.logger.debug(`连接实例创建成功: ${endpoint}`);\n } catch (error) {\n this.logger.error(`创建连接实例失败 ${endpoint}:`, error);\n throw error;\n }\n }\n\n /**\n * 连接单个端点\n */\n private async connectSingleEndpoint(\n endpoint: string,\n proxyServer: ProxyMCPServer\n ): Promise<void> {\n const status = this.connectionStates.get(endpoint);\n if (!status) {\n throw new Error(`端点状态不存在: ${endpoint}`);\n }\n\n this.logger.debug(`连接端点: ${endpoint}`);\n\n try {\n // 更新状态为连接中\n status.connected = false;\n status.initialized = false;\n\n // 执行连接\n await proxyServer.connect();\n\n // 更新连接成功状态\n status.connected = true;\n status.initialized = true;\n status.lastConnected = new Date();\n status.lastError = undefined;\n status.reconnectAttempts = 0;\n status.healthScore = 100;\n\n this.logger.info(`端点连接成功: ${endpoint}`);\n } catch (error) {\n // 更新连接失败状态\n status.connected = false;\n status.initialized = false;\n status.lastError = error instanceof Error ? error.message : String(error);\n status.reconnectAttempts++;\n status.healthScore = Math.max(0, status.healthScore - 20);\n\n this.logger.error(`端点连接失败 ${endpoint}:`, error);\n\n // 启动重连(如果未超过最大重连次数)\n this.scheduleReconnect(endpoint);\n\n throw error;\n }\n }\n\n /**\n * 断开单个端点\n */\n private async disconnectSingleEndpoint(\n endpoint: string,\n proxyServer: ProxyMCPServer\n ): Promise<void> {\n const status = this.connectionStates.get(endpoint);\n if (!status) {\n return;\n }\n\n this.logger.debug(`断开端点: ${endpoint}`);\n\n try {\n // 执行断开连接(ProxyMCPServer.disconnect 是同步方法)\n proxyServer.disconnect();\n\n // 更新状态\n status.connected = false;\n status.initialized = false;\n\n this.logger.debug(`端点断开成功: ${endpoint}`);\n } catch (error) {\n this.logger.error(`端点断开失败 ${endpoint}:`, error);\n // 即使断开失败,也要更新状态\n status.connected = false;\n status.initialized = false;\n }\n }\n\n /**\n * 获取当前工具列表\n */\n private getCurrentTools(): Tool[] {\n if (!this.mcpServiceManager) {\n return [];\n }\n\n try {\n return this.mcpServiceManager.getAllTools();\n } catch (error) {\n this.logger.error(\"获取工具列表失败:\", error);\n return [];\n }\n }\n\n /**\n * 同步工具到所有连接\n */\n private syncToolsToAllConnections(): void {\n if (!this.mcpServiceManager) {\n return;\n }\n\n this.logger.debug(\"同步工具到所有连接\");\n\n for (const [endpoint, proxyServer] of this.connections) {\n try {\n proxyServer.setServiceManager(this.mcpServiceManager);\n this.logger.debug(`工具同步成功: ${endpoint}`);\n } catch (error) {\n this.logger.error(`工具同步失败 ${endpoint}:`, error);\n }\n }\n }\n\n /**\n * 启动健康检查\n */\n private startHealthCheck(): void {\n if (this.healthCheckInterval) {\n return; // 已经启动\n }\n\n this.logger.debug(\n `启动健康检查,间隔: ${this.options.healthCheckInterval}ms`\n );\n\n this.healthCheckInterval = setInterval(() => {\n this.performHealthCheck();\n }, this.options.healthCheckInterval);\n }\n\n /**\n * 停止健康检查\n */\n private stopHealthCheck(): void {\n if (this.healthCheckInterval) {\n clearInterval(this.healthCheckInterval);\n this.healthCheckInterval = null;\n this.logger.debug(\"健康检查已停止\");\n }\n }\n\n /**\n * 执行健康检查\n */\n private async performHealthCheck(): Promise<void> {\n this.logger.debug(\"执行健康检查\");\n\n const healthCheckPromises: Promise<void>[] = [];\n\n for (const [endpoint, status] of this.connectionStates) {\n if (!status.healthCheckEnabled) {\n continue;\n }\n\n healthCheckPromises.push(this.performSingleHealthCheck(endpoint, status));\n }\n\n // 并发执行所有健康检查\n await Promise.allSettled(healthCheckPromises);\n }\n\n /**\n * 执行单个端点的健康检查\n */\n private async performSingleHealthCheck(\n endpoint: string,\n status: ConnectionStatus\n ): Promise<void> {\n const startTime = Date.now();\n status.lastHealthCheck = new Date();\n status.totalRequests++;\n\n try {\n const proxyServer = this.connections.get(endpoint);\n if (!proxyServer) {\n throw new Error(`连接实例不存在: ${endpoint}`);\n }\n\n // 执行健康检查(这里使用简单的连接状态检查)\n // 在实际实现中,可以调用 ProxyMCPServer 的 ping 方法或其他健康检查方法\n await this.checkConnectionHealth(proxyServer, endpoint);\n\n // 健康检查成功\n const responseTime = Date.now() - startTime;\n this.handleHealthCheckSuccess(status, responseTime);\n } catch (error) {\n // 健康检查失败\n const responseTime = Date.now() - startTime;\n this.handleHealthCheckFailure(status, error as Error, responseTime);\n }\n }\n\n /**\n * 检查连接健康状态\n */\n private async checkConnectionHealth(\n proxyServer: any,\n endpoint: string\n ): Promise<void> {\n // 检查基本连接状态\n if (!proxyServer) {\n throw new Error(\"连接实例不存在\");\n }\n\n // 这里可以扩展更复杂的健康检查逻辑\n // 例如:发送 ping 请求、检查工具列表等\n\n // 模拟健康检查延迟\n await new Promise((resolve) => setTimeout(resolve, 10));\n\n // 如果连接状态为断开,抛出错误\n const status = this.connectionStates.get(endpoint);\n if (!status?.connected) {\n throw new Error(\"连接已断开\");\n }\n }\n\n /**\n * 处理健康检查成功\n */\n private handleHealthCheckSuccess(\n status: ConnectionStatus,\n responseTime: number\n ): void {\n status.successfulRequests++;\n status.consecutiveFailures = 0;\n status.responseTime = responseTime;\n status.lastSuccessTime = new Date();\n\n // 更新健康度评分\n this.updateHealthScore(status, true, responseTime);\n\n this.logger.debug(\n `健康检查成功: ${status.endpoint}, 响应时间: ${responseTime}ms, 健康度: ${status.healthScore}`\n );\n }\n\n /**\n * 处理健康检查失败\n */\n private handleHealthCheckFailure(\n status: ConnectionStatus,\n error: Error,\n responseTime: number\n ): void {\n status.consecutiveFailures++;\n status.responseTime = responseTime;\n status.lastError = error.message;\n\n // 更新健康度评分\n this.updateHealthScore(status, false, responseTime);\n\n this.logger.warn(\n `健康检查失败: ${status.endpoint}, 错误: ${error.message}, 连续失败: ${status.consecutiveFailures}, 健康度: ${status.healthScore}`\n );\n\n // 如果连续失败次数过多,考虑触发重连\n if (status.consecutiveFailures >= 3 && status.connected) {\n this.logger.warn(\n `端点 ${status.endpoint} 连续失败 ${status.consecutiveFailures} 次,可能需要重连`\n );\n // 这里可以触发重连逻辑\n }\n }\n\n /**\n * 更新健康度评分\n */\n private updateHealthScore(\n status: ConnectionStatus,\n success: boolean,\n responseTime: number\n ): void {\n const baseScore = status.healthScore;\n\n if (success) {\n // 成功时增加健康度\n let increment = 5;\n\n // 根据响应时间调整增量\n if (responseTime < 100) {\n increment = 10; // 响应快,增量大\n } else if (responseTime < 500) {\n increment = 7; // 响应中等\n } else if (responseTime < 1000) {\n increment = 5; // 响应慢\n } else {\n increment = 2; // 响应很慢\n }\n\n status.healthScore = Math.min(100, baseScore + increment);\n } else {\n // 失败时减少健康度\n let decrement = 15;\n\n // 根据连续失败次数调整减量\n if (status.consecutiveFailures >= 5) {\n decrement = 30; // 连续失败多次,减量大\n } else if (status.consecutiveFailures >= 3) {\n decrement = 20;\n }\n\n status.healthScore = Math.max(0, baseScore - decrement);\n }\n\n // 计算成功率并调整健康度\n if (status.totalRequests > 0) {\n const successRate = status.successfulRequests / status.totalRequests;\n\n // 如果成功率低于 50%,进一步降低健康度\n if (successRate < 0.5) {\n status.healthScore = Math.max(0, status.healthScore - 10);\n }\n // 如果成功率高于 90%,适当提升健康度\n else if (successRate > 0.9) {\n status.healthScore = Math.min(100, status.healthScore + 5);\n }\n }\n }\n\n /**\n * 分类连接错误类型\n */\n private classifyConnectionError(error: Error): ConnectionErrorType {\n const errorMessage = error.message.toLowerCase();\n\n if (\n errorMessage.includes(\"timeout\") ||\n errorMessage.includes(\"timed out\")\n ) {\n return ConnectionErrorType.TIMEOUT_ERROR;\n }\n\n if (\n errorMessage.includes(\"network\") ||\n errorMessage.includes(\"connection refused\") ||\n errorMessage.includes(\"econnrefused\") ||\n errorMessage.includes(\"enotfound\")\n ) {\n return ConnectionErrorType.NETWORK_ERROR;\n }\n\n if (\n errorMessage.includes(\"auth\") ||\n errorMessage.includes(\"unauthorized\") ||\n errorMessage.includes(\"forbidden\") ||\n errorMessage.includes(\"401\") ||\n errorMessage.includes(\"403\")\n ) {\n return ConnectionErrorType.AUTHENTICATION_ERROR;\n }\n\n if (\n errorMessage.includes(\"server\") ||\n errorMessage.includes(\"500\") ||\n errorMessage.includes(\"502\") ||\n errorMessage.includes(\"503\") ||\n errorMessage.includes(\"504\")\n ) {\n return ConnectionErrorType.SERVER_ERROR;\n }\n\n return ConnectionErrorType.UNKNOWN_ERROR;\n }\n\n /**\n * 计算重连延迟\n */\n private calculateReconnectDelay(status: ConnectionStatus): number {\n const baseDelay = this.options.reconnectInterval;\n const maxDelay = this.options.maxReconnectDelay;\n const multiplier = this.options.reconnectBackoffMultiplier;\n const attempts = status.reconnectAttempts;\n\n let delay: number;\n\n switch (this.options.reconnectStrategy) {\n case ReconnectStrategy.FIXED_INTERVAL:\n delay = baseDelay;\n break;\n\n case ReconnectStrategy.LINEAR_BACKOFF:\n delay = baseDelay * (attempts + 1);\n break;\n\n case ReconnectStrategy.EXPONENTIAL_BACKOFF:\n delay = baseDelay * multiplier ** attempts;\n break;\n\n case ReconnectStrategy.ADAPTIVE:\n // 自适应策略:根据错误类型和历史成功率调整\n delay = this.calculateAdaptiveDelay(\n status,\n baseDelay,\n multiplier,\n attempts\n );\n break;\n\n default:\n delay = baseDelay * multiplier ** attempts;\n }\n\n // 限制最大延迟\n delay = Math.min(delay, maxDelay);\n\n // 添加抖动以避免雷群效应\n if (this.options.jitterEnabled) {\n const jitter = delay * 0.1 * Math.random(); // 10% 的随机抖动\n delay += jitter;\n }\n\n return Math.round(delay);\n }\n\n /**\n * 计算自适应重连延迟\n */\n private calculateAdaptiveDelay(\n status: ConnectionStatus,\n baseDelay: number,\n multiplier: number,\n attempts: number\n ): number {\n let delay = baseDelay;\n\n // 根据错误类型调整\n switch (status.errorType) {\n case ConnectionErrorType.NETWORK_ERROR:\n // 网络错误,使用指数退避\n delay = baseDelay * multiplier ** attempts;\n break;\n\n case ConnectionErrorType.AUTHENTICATION_ERROR:\n // 认证错误,延迟更长\n delay = baseDelay * multiplier ** attempts * 2;\n break;\n\n case ConnectionErrorType.SERVER_ERROR:\n // 服务器错误,适中延迟\n delay = baseDelay * (1 + attempts);\n break;\n\n case ConnectionErrorType.TIMEOUT_ERROR:\n // 超时错误,线性增长\n delay = baseDelay * (1 + attempts * 0.5);\n break;\n\n default:\n delay = baseDelay * multiplier ** attempts;\n }\n\n // 根据历史成功率调整\n if (status.reconnectHistory.length > 0) {\n const recentHistory = status.reconnectHistory.slice(-5); // 最近5次\n const successRate =\n recentHistory.filter((h) => h.success).length / recentHistory.length;\n\n if (successRate < 0.2) {\n // 成功率很低,增加延迟\n delay *= 1.5;\n } else if (successRate > 0.8) {\n // 成功率很高,减少延迟\n delay *= 0.8;\n }\n }\n\n return delay;\n }\n\n /**\n * 检查是否应该重连\n */\n private shouldReconnect(status: ConnectionStatus): boolean {\n // 检查重连次数限制\n if (status.reconnectAttempts >= this.options.maxReconnectAttempts) {\n this.logger.warn(\n `端点 ${status.endpoint} 已达到最大重连次数 ${this.options.maxReconnectAttempts}`\n );\n return false;\n }\n\n // 检查错误类型\n if (status.errorType === ConnectionErrorType.AUTHENTICATION_ERROR) {\n // 认证错误通常不应该重连太多次\n if (status.reconnectAttempts >= 3) {\n this.logger.warn(`端点 ${status.endpoint} 认证错误,停止重连`);\n return false;\n }\n }\n\n // 检查连续失败次数\n if (status.consecutiveFailures >= 10) {\n this.logger.warn(`端点 ${status.endpoint} 连续失败次数过多,停止重连`);\n return false;\n }\n\n return true;\n }\n\n /**\n * 安排重连\n */\n private scheduleReconnect(endpoint: string): void {\n const status = this.connectionStates.get(endpoint);\n if (!status) {\n return;\n }\n\n // 分类错误类型\n if (status.lastError) {\n status.errorType = this.classifyConnectionError(\n new Error(status.lastError)\n );\n }\n\n // 检查是否应该重连\n if (!this.shouldReconnect(status)) {\n status.isReconnecting = false;\n return;\n }\n\n // 清理现有的重连定时器\n const existingTimer = this.reconnectTimers.get(endpoint);\n if (existingTimer) {\n clearTimeout(existingTimer);\n }\n\n // 计算重连延迟\n const delay = this.calculateReconnectDelay(status);\n status.reconnectDelay = delay;\n status.isReconnecting = true;\n status.nextReconnectTime = new Date(Date.now() + delay);\n\n this.logger.info(\n `安排重连 ${endpoint},延迟: ${delay}ms,尝试次数: ${status.reconnectAttempts + 1},错误类型: ${status.errorType}`\n );\n\n const timer = setTimeout(async () => {\n this.reconnectTimers.delete(endpoint);\n await this.performReconnect(endpoint);\n }, delay);\n\n this.reconnectTimers.set(endpoint, timer);\n }\n\n /**\n * 执行重连\n */\n private async performReconnect(endpoint: string): Promise<void> {\n const status = this.connectionStates.get(endpoint);\n const proxyServer = this.connections.get(endpoint);\n\n if (!status || !proxyServer) {\n return;\n }\n\n status.lastReconnectAttempt = new Date();\n status.isReconnecting = true;\n\n this.logger.info(\n `开始重连 ${endpoint},第 ${status.reconnectAttempts + 1} 次尝试`\n );\n\n try {\n await this.connectSingleEndpoint(endpoint, proxyServer);\n\n // 重连成功\n status.isReconnecting = false;\n status.reconnectHistory.push({\n timestamp: new Date(),\n success: true,\n delay: status.reconnectDelay,\n });\n\n this.logger.info(`重连成功 ${endpoint}`);\n } catch (error) {\n // 重连失败\n status.isReconnecting = false;\n status.reconnectHistory.push({\n timestamp: new Date(),\n success: false,\n error: error instanceof Error ? error.message : String(error),\n delay: status.reconnectDelay,\n });\n\n this.logger.error(`重连失败 ${endpoint}:`, error);\n\n // 继续安排下次重连\n this.scheduleReconnect(endpoint);\n }\n\n // 限制重连历史记录数量\n if (status.reconnectHistory.length > 20) {\n status.reconnectHistory = status.reconnectHistory.slice(-20);\n }\n }\n\n /**\n * 清理所有重连定时器\n */\n private clearAllReconnectTimers(): void {\n for (const [, timer] of this.reconnectTimers) {\n clearTimeout(timer);\n }\n this.reconnectTimers.clear();\n }\n}\n","/**\n * 小智连接管理器单例\n * 提供全局唯一的 XiaozhiConnectionManager 实例,解决多实例资源冲突问题\n */\n\nimport {\n XiaozhiConnectionManager,\n type XiaozhiConnectionOptions,\n} from \"./XiaozhiConnectionManager.js\";\n\n// 重新导出相关类型,便于外部使用\nexport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nexport type {\n XiaozhiConnectionOptions,\n ConnectionStatus,\n} from \"./XiaozhiConnectionManager.js\";\n\n// 单例状态枚举\nenum SingletonState {\n NOT_INITIALIZED = \"not_initialized\",\n INITIALIZING = \"initializing\",\n INITIALIZED = \"initialized\",\n FAILED = \"failed\",\n CLEANUP = \"cleanup\",\n}\n\n// 单例状态接口\ninterface SingletonStatus {\n state: SingletonState;\n initializationTime?: Date;\n lastError?: Error;\n instanceId?: string;\n}\n\n// 单例状态管理变量\nlet instance: XiaozhiConnectionManager | null = null;\nlet initPromise: Promise<XiaozhiConnectionManager> | null = null;\nlet state: SingletonState = SingletonState.NOT_INITIALIZED;\nlet lastError: Error | null = null;\nlet instanceId: string | null = null;\n\n/**\n * 创建 XiaozhiConnectionManager 实例(私有函数)\n */\nasync function createInstance(\n options?: XiaozhiConnectionOptions\n): Promise<XiaozhiConnectionManager> {\n console.log(\"🚀 正在初始化 XiaozhiConnectionManager 单例...\");\n\n const manager = new XiaozhiConnectionManager(options);\n\n return manager;\n}\n\n/**\n * 获取 XiaozhiConnectionManager 单例实例\n *\n * @param options 连接选项(仅在首次创建时生效)\n * @returns Promise<XiaozhiConnectionManager> 管理器实例\n * @throws Error 如果初始化失败\n */\nasync function getInstance(\n options?: XiaozhiConnectionOptions\n): Promise<XiaozhiConnectionManager> {\n // 如果已经初始化完成,直接返回实例\n if (instance && state === SingletonState.INITIALIZED) {\n return instance;\n }\n\n // 如果正在初始化中,等待同一个初始化Promise\n if (initPromise && state === SingletonState.INITIALIZING) {\n return initPromise;\n }\n\n // 如果之前初始化失败,重置状态准备重试\n if (state === SingletonState.FAILED) {\n reset();\n }\n\n // 开始新的初始化过程\n state = SingletonState.INITIALIZING;\n initPromise = createInstance(options);\n\n try {\n instance = await initPromise;\n state = SingletonState.INITIALIZED;\n instanceId = `xiaozhi-connection-manager-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;\n lastError = null;\n\n console.log(\n `✅ XiaozhiConnectionManager 单例初始化成功,实例ID: ${instanceId}`\n );\n return instance;\n } catch (error) {\n state = SingletonState.FAILED;\n lastError = error as Error;\n initPromise = null;\n\n console.error(\n \"❌ XiaozhiConnectionManager 单例初始化失败:\",\n (error as Error).message\n );\n throw error;\n }\n}\n\n/**\n * 清理单例资源\n *\n * @returns Promise<void>\n */\nasync function cleanup(): Promise<void> {\n if (state === SingletonState.CLEANUP) {\n console.log(\"⚠️ XiaozhiConnectionManager 单例已在清理中,跳过重复清理\");\n return;\n }\n\n console.log(\"🧹 正在清理 XiaozhiConnectionManager 单例资源...\");\n state = SingletonState.CLEANUP;\n\n try {\n // 清理初始化Promise\n if (initPromise) {\n try {\n const instanceFromPromise = await initPromise;\n await instanceFromPromise.cleanup();\n } catch (error) {\n console.error(\"清理初始化中的实例失败:\", (error as Error).message);\n }\n initPromise = null;\n }\n\n // 清理已初始化的实例\n if (instance) {\n await instance.cleanup();\n instance = null;\n }\n\n state = SingletonState.NOT_INITIALIZED;\n lastError = null;\n instanceId = null;\n\n console.log(\"✅ XiaozhiConnectionManager 单例资源清理完成\");\n } catch (error) {\n console.error(\n \"❌ XiaozhiConnectionManager 单例清理失败:\",\n (error as Error).message\n );\n // 即使清理失败,也要重置状态,避免永久锁定\n reset();\n throw error;\n }\n}\n\n/**\n * 重置单例状态(不进行清理)\n *\n * 这个方法只重置内部状态变量,不调用实例的清理方法\n * 主要用于错误恢复和测试场景\n */\nfunction reset(): void {\n console.log(\"🔄 重置 XiaozhiConnectionManager 单例状态...\");\n\n // 清理定时器(如果有)\n if (initPromise) {\n initPromise = null;\n }\n\n // 重置状态变量\n instance = null;\n state = SingletonState.NOT_INITIALIZED;\n lastError = null;\n instanceId = null;\n\n console.log(\"✅ XiaozhiConnectionManager 单例状态已重置\");\n}\n\n/**\n * 检查单例是否已初始化\n *\n * @returns boolean 是否已初始化\n */\nfunction isInitialized(): boolean {\n return state === SingletonState.INITIALIZED && instance !== null;\n}\n\n/**\n * 获取单例状态信息\n *\n * @returns SingletonStatus 状态信息\n */\nfunction getStatus(): SingletonStatus {\n return {\n state,\n initializationTime: instanceId ? new Date() : undefined,\n lastError: lastError || undefined,\n instanceId: instanceId || undefined,\n };\n}\n\n/**\n * 强制重新初始化单例\n *\n * 这个方法会先清理现有资源,然后重新初始化\n *\n * @param options 连接选项\n * @returns Promise<XiaozhiConnectionManager> 新的管理器实例\n */\nasync function forceReinitialize(\n options?: XiaozhiConnectionOptions\n): Promise<XiaozhiConnectionManager> {\n console.log(\"🔄 强制重新初始化 XiaozhiConnectionManager 单例...\");\n\n await cleanup();\n return getInstance(options);\n}\n\n/**\n * 获取当前实例(同步方法,仅在确定已初始化时使用)\n *\n * @returns XiaozhiConnectionManager | null 当前实例或null\n */\nfunction getCurrentInstance(): XiaozhiConnectionManager | null {\n return instance;\n}\n\n/**\n * 等待初始化完成(如果正在初始化中)\n *\n * @returns Promise<boolean> 是否成功初始化\n */\nasync function waitForInitialization(): Promise<boolean> {\n if (state === SingletonState.INITIALIZED) {\n return true;\n }\n\n if (state === SingletonState.INITIALIZING && initPromise) {\n try {\n await initPromise;\n return true;\n } catch (error) {\n return false;\n }\n }\n\n return false;\n}\n\n/**\n * XiaozhiConnectionManager 全局单例管理器\n *\n * 使用对象包装模块级函数,保持原有API接口不变\n */\nexport const XiaozhiConnectionManagerSingleton = {\n getInstance,\n cleanup,\n reset,\n isInitialized,\n getStatus,\n forceReinitialize,\n getCurrentInstance,\n waitForInitialization,\n} as const;\n\n// 导出默认实例(便于使用)\nexport default XiaozhiConnectionManagerSingleton;\n\n// 进程退出时自动清理资源\nprocess.on(\"exit\", () => {\n if (XiaozhiConnectionManagerSingleton.isInitialized()) {\n console.log(\"🔄 进程退出,正在清理 XiaozhiConnectionManager 单例...\");\n // 注意:这里不能使用 await,因为 exit 事件是同步的\n XiaozhiConnectionManagerSingleton.reset();\n }\n});\n\n// 处理未捕获的异常\nprocess.on(\"uncaughtException\", async (error) => {\n console.error(\"💥 未捕获的异常,清理 XiaozhiConnectionManager 单例:\", error);\n try {\n await XiaozhiConnectionManagerSingleton.cleanup();\n } catch (cleanupError) {\n console.error(\"清理过程中发生错误:\", cleanupError);\n }\n});\n\n// 处理未处理的Promise拒绝\nprocess.on(\"unhandledRejection\", async (reason) => {\n console.error(\n \"💥 未处理的Promise拒绝,清理 XiaozhiConnectionManager 单例:\",\n reason\n );\n try {\n await XiaozhiConnectionManagerSingleton.cleanup();\n } catch (cleanupError) {\n console.error(\"清理过程中发生错误:\", cleanupError);\n }\n});\n","import { EventEmitter } from \"node:events\";\nimport { type Logger, logger } from \"../Logger.js\";\n\n/**\n * 事件类型定义\n */\nexport interface EventBusEvents {\n // 配置相关事件\n \"config:updated\": { config: any; source: string };\n \"config:error\": { error: Error; operation: string };\n\n // 状态相关事件\n \"status:updated\": { status: any; source: string };\n \"status:error\": { error: Error; operation: string };\n\n // 服务相关事件\n \"service:restart:requested\": { source: string };\n \"service:restart:started\": { timestamp: number };\n \"service:restart:completed\": { timestamp: number };\n \"service:restart:failed\": { error: Error; timestamp: number };\n\n // WebSocket 相关事件\n \"websocket:client:connected\": { clientId: string; timestamp: number };\n \"websocket:client:disconnected\": { clientId: string; timestamp: number };\n \"websocket:message:received\": { type: string; data: any; clientId: string };\n\n // 通知相关事件\n \"notification:broadcast\": { type: string; data: any; target?: string };\n \"notification:error\": { error: Error; type: string };\n}\n\n/**\n * 事件总线 - 用于模块间的解耦通信\n */\nexport class EventBus extends EventEmitter {\n private logger: Logger;\n private eventStats: Map<string, { count: number; lastEmitted: Date }> =\n new Map();\n private maxListeners = 50; // 增加最大监听器数量\n\n constructor() {\n super();\n this.logger = logger.withTag(\"EventBus\");\n this.setMaxListeners(this.maxListeners);\n this.setupErrorHandling();\n }\n\n /**\n * 设置错误处理\n */\n private setupErrorHandling(): void {\n this.on(\"error\", (error) => {\n this.logger.error(\"EventBus 内部错误:\", error);\n });\n\n // 监听器数量警告\n this.on(\"newListener\", (eventName) => {\n const listenerCount = this.listenerCount(eventName);\n if (listenerCount > this.maxListeners * 0.8) {\n this.logger.warn(\n `事件 ${eventName} 的监听器数量过多: ${listenerCount}`\n );\n }\n });\n }\n\n /**\n * 发射事件(类型安全)\n */\n emitEvent<K extends keyof EventBusEvents>(\n eventName: K,\n data: EventBusEvents[K]\n ): boolean {\n try {\n this.updateEventStats(eventName as string);\n this.logger.debug(`发射事件: ${eventName}`, data);\n return this.emit(eventName, data);\n } catch (error) {\n this.logger.error(`发射事件失败: ${eventName}`, error);\n return false;\n }\n }\n\n /**\n * 监听事件(类型安全)\n */\n onEvent<K extends keyof EventBusEvents>(\n eventName: K,\n listener: (data: EventBusEvents[K]) => void\n ): this {\n this.logger.debug(`添加事件监听器: ${eventName}`);\n return this.on(eventName, listener);\n }\n\n /**\n * 一次性监听事件(类型安全)\n */\n onceEvent<K extends keyof EventBusEvents>(\n eventName: K,\n listener: (data: EventBusEvents[K]) => void\n ): this {\n this.logger.debug(`添加一次性事件监听器: ${eventName}`);\n return this.once(eventName, listener);\n }\n\n /**\n * 移除事件监听器(类型安全)\n */\n offEvent<K extends keyof EventBusEvents>(\n eventName: K,\n listener: (data: EventBusEvents[K]) => void\n ): this {\n this.logger.debug(`移除事件监听器: ${eventName}`);\n return this.off(eventName, listener);\n }\n\n /**\n * 更新事件统计\n */\n private updateEventStats(eventName: string): void {\n const stats = this.eventStats.get(eventName) || {\n count: 0,\n lastEmitted: new Date(),\n };\n stats.count++;\n stats.lastEmitted = new Date();\n this.eventStats.set(eventName, stats);\n }\n\n /**\n * 获取事件统计信息\n */\n getEventStats(): Record<string, { count: number; lastEmitted: Date }> {\n const stats: Record<string, { count: number; lastEmitted: Date }> = {};\n for (const [eventName, stat] of this.eventStats) {\n stats[eventName] = { ...stat };\n }\n return stats;\n }\n\n /**\n * 获取监听器统计信息\n */\n getListenerStats(): Record<string, number> {\n const stats: Record<string, number> = {};\n for (const eventName of this.eventNames()) {\n stats[eventName as string] = this.listenerCount(eventName);\n }\n return stats;\n }\n\n /**\n * 清理事件统计\n */\n clearEventStats(): void {\n this.eventStats.clear();\n this.logger.info(\"事件统计已清理\");\n }\n\n /**\n * 获取事件总线状态\n */\n getStatus(): {\n totalEvents: number;\n totalListeners: number;\n eventStats: Record<string, { count: number; lastEmitted: Date }>;\n listenerStats: Record<string, number>;\n } {\n return {\n totalEvents: this.eventStats.size,\n totalListeners: Object.values(this.getListenerStats()).reduce(\n (sum, count) => sum + count,\n 0\n ),\n eventStats: this.getEventStats(),\n listenerStats: this.getListenerStats(),\n };\n }\n\n /**\n * 销毁事件总线\n */\n destroy(): void {\n this.removeAllListeners();\n this.eventStats.clear();\n this.logger.info(\"EventBus 已销毁\");\n }\n}\n\n// 单例实例\nlet eventBusInstance: EventBus | null = null;\n\n/**\n * 获取事件总线单例\n */\nexport function getEventBus(): EventBus {\n if (!eventBusInstance) {\n eventBusInstance = new EventBus();\n }\n return eventBusInstance;\n}\n\n/**\n * 销毁事件总线单例\n */\nexport function destroyEventBus(): void {\n if (eventBusInstance) {\n eventBusInstance.destroy();\n eventBusInstance = null;\n }\n}\n","import { type Logger, logger } from \"../Logger.js\";\nimport { type AppConfig, configManager } from \"../configManager.js\";\nimport { type EventBus, getEventBus } from \"./EventBus.js\";\n\n/**\n * 配置服务 - 统一的配置管理服务\n */\nexport class ConfigService {\n private logger: Logger;\n private eventBus: EventBus;\n\n constructor() {\n this.logger = logger.withTag(\"ConfigService\");\n this.eventBus = getEventBus();\n }\n\n /**\n * 获取完整配置\n */\n async getConfig(): Promise<AppConfig> {\n try {\n const config = configManager.getConfig();\n this.logger.debug(\"获取配置成功\");\n return config;\n } catch (error) {\n this.logger.error(\"获取配置失败:\", error);\n this.eventBus.emitEvent(\"config:error\", {\n error: error instanceof Error ? error : new Error(String(error)),\n operation: \"getConfig\",\n });\n throw error;\n }\n }\n\n /**\n * 更新配置\n */\n async updateConfig(newConfig: AppConfig, source = \"unknown\"): Promise<void> {\n try {\n this.logger.info(`开始更新配置,来源: ${source}`);\n\n // 验证配置\n this.validateConfig(newConfig);\n\n // 更新 MCP 端点\n if (newConfig.mcpEndpoint !== configManager.getMcpEndpoint()) {\n configManager.updateMcpEndpoint(newConfig.mcpEndpoint);\n }\n\n // 更新 MCP 服务\n const currentServers = configManager.getMcpServers();\n for (const [name, config] of Object.entries(newConfig.mcpServers)) {\n if (JSON.stringify(currentServers[name]) !== JSON.stringify(config)) {\n configManager.updateMcpServer(name, config);\n }\n }\n\n // 删除不存在的服务\n for (const name of Object.keys(currentServers)) {\n if (!(name in newConfig.mcpServers)) {\n configManager.removeMcpServer(name);\n // 同时清理该服务在 mcpServerConfig 中的工具配置\n configManager.removeServerToolsConfig(name);\n }\n }\n\n // 更新连接配置\n if (newConfig.connection) {\n configManager.updateConnectionConfig(newConfig.connection);\n }\n\n // 更新 ModelScope 配置\n if (newConfig.modelscope) {\n configManager.updateModelScopeConfig(newConfig.modelscope);\n }\n\n // 更新 Web UI 配置\n if (newConfig.webUI) {\n configManager.updateWebUIConfig(newConfig.webUI);\n }\n\n // 更新服务工具配置\n if (newConfig.mcpServerConfig) {\n for (const [serverName, toolsConfig] of Object.entries(\n newConfig.mcpServerConfig\n )) {\n for (const [toolName, toolConfig] of Object.entries(\n toolsConfig.tools\n )) {\n configManager.setToolEnabled(\n serverName,\n toolName,\n toolConfig.enable\n );\n }\n }\n }\n\n this.logger.info(\"配置更新成功\");\n\n // 发射配置更新事件\n this.eventBus.emitEvent(\"config:updated\", {\n config: newConfig,\n source,\n });\n } catch (error) {\n this.logger.error(\"配置更新失败:\", error);\n this.eventBus.emitEvent(\"config:error\", {\n error: error instanceof Error ? error : new Error(String(error)),\n operation: \"updateConfig\",\n });\n throw error;\n }\n }\n\n /**\n * 获取 MCP 端点\n */\n getMcpEndpoint(): string {\n try {\n return configManager.getMcpEndpoint();\n } catch (error) {\n this.logger.error(\"获取 MCP 端点失败:\", error);\n throw error;\n }\n }\n\n /**\n * 获取 MCP 端点列表\n */\n getMcpEndpoints(): string[] {\n try {\n return configManager.getMcpEndpoints();\n } catch (error) {\n this.logger.error(\"获取 MCP 端点列表失败:\", error);\n throw error;\n }\n }\n\n /**\n * 获取 MCP 服务配置\n */\n getMcpServers(): Record<string, any> {\n try {\n return configManager.getMcpServers();\n } catch (error) {\n this.logger.error(\"获取 MCP 服务配置失败:\", error);\n throw error;\n }\n }\n\n /**\n * 获取连接配置\n */\n getConnectionConfig(): any {\n try {\n return configManager.getConnectionConfig();\n } catch (error) {\n this.logger.error(\"获取连接配置失败:\", error);\n throw error;\n }\n }\n\n /**\n * 获取 Web UI 端口\n */\n getWebUIPort(): number {\n try {\n return configManager.getWebUIPort() || 9999;\n } catch (error) {\n this.logger.error(\"获取 Web UI 端口失败:\", error);\n return 9999;\n }\n }\n\n /**\n * 验证配置\n */\n private validateConfig(config: AppConfig): void {\n if (!config || typeof config !== \"object\") {\n throw new Error(\"配置必须是有效的对象\");\n }\n\n if (!config.mcpEndpoint) {\n throw new Error(\"配置必须包含 mcpEndpoint\");\n }\n\n if (!config.mcpServers || typeof config.mcpServers !== \"object\") {\n throw new Error(\"配置必须包含有效的 mcpServers\");\n }\n }\n\n /**\n * 检查配置是否存在\n */\n configExists(): boolean {\n return configManager.configExists();\n }\n\n /**\n * 重新加载配置\n */\n async reloadConfig(): Promise<AppConfig> {\n try {\n this.logger.info(\"重新加载配置\");\n configManager.reloadConfig();\n const config = await this.getConfig();\n\n this.eventBus.emitEvent(\"config:updated\", {\n config,\n source: \"reload\",\n });\n\n return config;\n } catch (error) {\n this.logger.error(\"重新加载配置失败:\", error);\n this.eventBus.emitEvent(\"config:error\", {\n error: error instanceof Error ? error : new Error(String(error)),\n operation: \"reloadConfig\",\n });\n throw error;\n }\n }\n\n /**\n * 获取配置文件路径\n */\n getConfigPath(): string {\n return configManager.getConfigPath();\n }\n}\n","import type { Context } from \"hono\";\nimport { type Logger, logger } from \"../Logger.js\";\nimport type { AppConfig } from \"../configManager.js\";\nimport { ConfigService } from \"../services/ConfigService.js\";\n\n/**\n * 统一响应格式接口\n */\ninterface ApiErrorResponse {\n error: {\n code: string;\n message: string;\n details?: any;\n };\n}\n\ninterface ApiSuccessResponse<T = any> {\n success: boolean;\n data?: T;\n message?: string;\n}\n\n/**\n * 配置 API 处理器\n */\nexport class ConfigApiHandler {\n private logger: Logger;\n private configService: ConfigService;\n\n constructor() {\n this.logger = logger.withTag(\"ConfigApiHandler\");\n this.configService = new ConfigService();\n }\n\n /**\n * 创建统一的错误响应\n */\n private createErrorResponse(\n code: string,\n message: string,\n details?: any\n ): ApiErrorResponse {\n return {\n error: {\n code,\n message,\n details,\n },\n };\n }\n\n /**\n * 创建统一的成功响应\n */\n private createSuccessResponse<T>(\n data?: T,\n message?: string\n ): ApiSuccessResponse<T> {\n return {\n success: true,\n data,\n message,\n };\n }\n\n /**\n * 获取配置\n * GET /api/config\n */\n async getConfig(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理获取配置请求\");\n const config = await this.configService.getConfig();\n this.logger.info(\"获取配置成功\");\n return c.json(this.createSuccessResponse(config));\n } catch (error) {\n this.logger.error(\"获取配置失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"CONFIG_READ_ERROR\",\n error instanceof Error ? error.message : \"获取配置失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 更新配置\n * PUT /api/config\n */\n async updateConfig(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理更新配置请求\");\n const newConfig: AppConfig = await c.req.json();\n\n // 验证请求体\n if (!newConfig || typeof newConfig !== \"object\") {\n const errorResponse = this.createErrorResponse(\n \"INVALID_REQUEST_BODY\",\n \"请求体必须是有效的配置对象\"\n );\n return c.json(errorResponse, 400);\n }\n\n await this.configService.updateConfig(newConfig, \"http-api\");\n this.logger.info(\"配置更新成功\");\n\n return c.json(this.createSuccessResponse(null, \"配置更新成功\"));\n } catch (error) {\n this.logger.error(\"配置更新失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"CONFIG_UPDATE_ERROR\",\n error instanceof Error ? error.message : \"配置更新失败\"\n );\n return c.json(errorResponse, 400);\n }\n }\n\n /**\n * 获取 MCP 端点\n * GET /api/config/mcp-endpoint\n */\n async getMcpEndpoint(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理获取 MCP 端点请求\");\n const endpoint = this.configService.getMcpEndpoint();\n this.logger.debug(\"获取 MCP 端点成功\");\n return c.json(this.createSuccessResponse({ endpoint }));\n } catch (error) {\n this.logger.error(\"获取 MCP 端点失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"MCP_ENDPOINT_READ_ERROR\",\n error instanceof Error ? error.message : \"获取 MCP 端点失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 获取 MCP 端点列表\n * GET /api/config/mcp-endpoints\n */\n async getMcpEndpoints(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理获取 MCP 端点列表请求\");\n const endpoints = this.configService.getMcpEndpoints();\n this.logger.debug(\"获取 MCP 端点列表成功\");\n return c.json(this.createSuccessResponse({ endpoints }));\n } catch (error) {\n this.logger.error(\"获取 MCP 端点列表失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"MCP_ENDPOINTS_READ_ERROR\",\n error instanceof Error ? error.message : \"获取 MCP 端点列表失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 获取 MCP 服务配置\n * GET /api/config/mcp-servers\n */\n async getMcpServers(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理获取 MCP 服务配置请求\");\n const servers = this.configService.getMcpServers();\n this.logger.debug(\"获取 MCP 服务配置成功\");\n return c.json(this.createSuccessResponse({ servers }));\n } catch (error) {\n this.logger.error(\"获取 MCP 服务配置失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"MCP_SERVERS_READ_ERROR\",\n error instanceof Error ? error.message : \"获取 MCP 服务配置失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 获取连接配置\n * GET /api/config/connection\n */\n async getConnectionConfig(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理获取连接配置请求\");\n const connection = this.configService.getConnectionConfig();\n this.logger.debug(\"获取连接配置成功\");\n return c.json(this.createSuccessResponse({ connection }));\n } catch (error) {\n this.logger.error(\"获取连接配置失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"CONNECTION_CONFIG_READ_ERROR\",\n error instanceof Error ? error.message : \"获取连接配置失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 重新加载配置\n * POST /api/config/reload\n */\n async reloadConfig(c: Context): Promise<Response> {\n try {\n this.logger.info(\"处理重新加载配置请求\");\n const config = await this.configService.reloadConfig();\n this.logger.info(\"重新加载配置成功\");\n return c.json(this.createSuccessResponse(config, \"配置重新加载成功\"));\n } catch (error) {\n this.logger.error(\"重新加载配置失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"CONFIG_RELOAD_ERROR\",\n error instanceof Error ? error.message : \"重新加载配置失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 获取配置文件路径\n * GET /api/config/path\n */\n async getConfigPath(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理获取配置文件路径请求\");\n const path = this.configService.getConfigPath();\n this.logger.debug(\"获取配置文件路径成功\");\n return c.json(this.createSuccessResponse({ path }));\n } catch (error) {\n this.logger.error(\"获取配置文件路径失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"CONFIG_PATH_READ_ERROR\",\n error instanceof Error ? error.message : \"获取配置文件路径失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 检查配置是否存在\n * GET /api/config/exists\n */\n async checkConfigExists(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理检查配置是否存在请求\");\n const exists = this.configService.configExists();\n this.logger.debug(`配置存在检查结果: ${exists}`);\n return c.json(this.createSuccessResponse({ exists }));\n } catch (error) {\n this.logger.error(\"检查配置是否存在失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"CONFIG_EXISTS_CHECK_ERROR\",\n error instanceof Error ? error.message : \"检查配置是否存在失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n}\n","import { type Logger, logger } from \"../Logger.js\";\nimport { ConfigService } from \"../services/ConfigService.js\";\nimport type { NotificationService } from \"../services/NotificationService.js\";\nimport type { StatusService } from \"../services/StatusService.js\";\n\n/**\n * 心跳消息接口\n */\ninterface HeartbeatMessage {\n type: \"clientStatus\";\n data: {\n status?: \"connected\" | \"disconnected\";\n mcpEndpoint?: string;\n activeMCPServers?: string[];\n timestamp?: number;\n };\n}\n\n/**\n * 心跳处理器\n */\nexport class HeartbeatHandler {\n private logger: Logger;\n private statusService: StatusService;\n private notificationService: NotificationService;\n private configService: ConfigService;\n\n constructor(\n statusService: StatusService,\n notificationService: NotificationService\n ) {\n this.logger = logger.withTag(\"HeartbeatHandler\");\n this.statusService = statusService;\n this.notificationService = notificationService;\n this.configService = new ConfigService();\n }\n\n /**\n * 处理客户端状态更新(心跳)\n */\n async handleClientStatus(\n ws: any,\n message: HeartbeatMessage,\n clientId: string\n ): Promise<void> {\n try {\n this.logger.debug(`处理客户端状态更新: ${clientId}`, message.data);\n\n // 更新客户端信息\n const statusUpdate = {\n ...message.data,\n lastHeartbeat: Date.now(),\n };\n\n this.statusService.updateClientInfo(\n statusUpdate,\n `websocket-${clientId}`\n );\n\n // 发送最新配置给客户端(心跳响应)\n await this.sendLatestConfig(ws, clientId);\n\n this.logger.debug(`客户端状态更新成功: ${clientId}`);\n } catch (error) {\n this.logger.error(`处理客户端状态更新失败: ${clientId}`, error);\n this.sendError(\n ws,\n \"CLIENT_STATUS_ERROR\",\n error instanceof Error ? error.message : \"客户端状态更新失败\"\n );\n }\n }\n\n /**\n * 发送最新配置给客户端\n */\n private async sendLatestConfig(ws: any, clientId: string): Promise<void> {\n try {\n const latestConfig = await this.configService.getConfig();\n const message = {\n type: \"configUpdate\",\n data: latestConfig,\n timestamp: Date.now(),\n };\n\n ws.send(JSON.stringify(message));\n this.logger.debug(`最新配置已发送给客户端: ${clientId}`);\n } catch (error) {\n this.logger.error(`发送最新配置失败: ${clientId}`, error);\n // 不抛出错误,避免影响心跳处理\n }\n }\n\n /**\n * 发送错误消息\n */\n private sendError(ws: any, code: string, message: string): void {\n try {\n const errorResponse = {\n type: \"error\",\n error: {\n code,\n message,\n timestamp: Date.now(),\n },\n };\n ws.send(JSON.stringify(errorResponse));\n } catch (error) {\n this.logger.error(\"发送错误消息失败:\", error);\n }\n }\n\n /**\n * 检查客户端心跳超时\n */\n checkHeartbeatTimeout(): void {\n const lastHeartbeat = this.statusService.getLastHeartbeat();\n const now = Date.now();\n const HEARTBEAT_TIMEOUT = 35000; // 35 seconds\n\n if (lastHeartbeat && now - lastHeartbeat > HEARTBEAT_TIMEOUT) {\n this.logger.warn(\"客户端心跳超时,标记为断开连接\");\n this.statusService.updateClientInfo(\n { status: \"disconnected\" },\n \"heartbeat-timeout\"\n );\n }\n }\n\n /**\n * 启动心跳监控\n */\n startHeartbeatMonitoring(): NodeJS.Timeout {\n const MONITOR_INTERVAL = 10000; // 10 seconds\n\n this.logger.info(\"启动心跳监控\");\n\n return setInterval(() => {\n this.checkHeartbeatTimeout();\n this.cleanupDisconnectedClients();\n }, MONITOR_INTERVAL);\n }\n\n /**\n * 清理断开连接的客户端\n */\n private cleanupDisconnectedClients(): void {\n try {\n this.notificationService.cleanupDisconnectedClients();\n } catch (error) {\n this.logger.error(\"清理断开连接的客户端失败:\", error);\n }\n }\n\n /**\n * 停止心跳监控\n */\n stopHeartbeatMonitoring(intervalId: NodeJS.Timeout): void {\n this.logger.info(\"停止心跳监控\");\n clearInterval(intervalId);\n }\n\n /**\n * 获取心跳统计信息\n */\n getHeartbeatStats(): {\n lastHeartbeat?: number;\n isConnected: boolean;\n clientStats: {\n totalClients: number;\n connectedClients: number;\n queuedMessages: number;\n };\n } {\n return {\n lastHeartbeat: this.statusService.getLastHeartbeat(),\n isConnected: this.statusService.isClientConnected(),\n clientStats: this.notificationService.getClientStats(),\n };\n }\n\n /**\n * 处理客户端连接建立\n */\n handleClientConnect(clientId: string): void {\n this.logger.info(`客户端连接建立: ${clientId}`);\n\n // 更新状态为连接\n this.statusService.updateClientInfo(\n {\n status: \"connected\",\n lastHeartbeat: Date.now(),\n },\n `websocket-connect-${clientId}`\n );\n }\n\n /**\n * 处理客户端连接断开\n */\n handleClientDisconnect(clientId: string): void {\n this.logger.info(`客户端连接断开: ${clientId}`);\n\n // 更新状态为断开连接\n this.statusService.updateClientInfo(\n { status: \"disconnected\" },\n `websocket-disconnect-${clientId}`\n );\n }\n\n /**\n * 发送心跳响应\n */\n sendHeartbeatResponse(ws: any, clientId: string): void {\n try {\n const response = {\n type: \"heartbeatResponse\",\n data: {\n timestamp: Date.now(),\n status: \"ok\",\n },\n };\n\n ws.send(JSON.stringify(response));\n this.logger.debug(`心跳响应已发送: ${clientId}`);\n } catch (error) {\n this.logger.error(`发送心跳响应失败: ${clientId}`, error);\n }\n }\n\n /**\n * 验证心跳消息格式\n */\n validateHeartbeatMessage(message: any): message is HeartbeatMessage {\n return (\n message &&\n typeof message === \"object\" &&\n message.type === \"clientStatus\" &&\n message.data &&\n typeof message.data === \"object\"\n );\n }\n}\n","import { type Logger, logger } from \"../Logger.js\";\nimport { ConfigService } from \"../services/ConfigService.js\";\nimport { type EventBus, getEventBus } from \"../services/EventBus.js\";\nimport type { NotificationService } from \"../services/NotificationService.js\";\nimport type { StatusService } from \"../services/StatusService.js\";\n\n/**\n * WebSocket 消息接口\n */\ninterface WebSocketMessage {\n type: string;\n data?: any;\n clientId?: string;\n}\n\n/**\n * 实时通知处理器\n */\nexport class RealtimeNotificationHandler {\n private logger: Logger;\n private notificationService: NotificationService;\n private configService: ConfigService;\n private statusService: StatusService;\n private eventBus: EventBus;\n\n constructor(\n notificationService: NotificationService,\n statusService: StatusService\n ) {\n this.logger = logger.withTag(\"RealtimeNotificationHandler\");\n this.notificationService = notificationService;\n this.configService = new ConfigService();\n this.statusService = statusService;\n this.eventBus = getEventBus();\n }\n\n /**\n * 处理 WebSocket 消息\n * @deprecated 部分消息类型已废弃,建议使用 HTTP API\n */\n async handleMessage(\n ws: any,\n message: WebSocketMessage,\n clientId: string\n ): Promise<void> {\n try {\n this.logger.debug(`处理 WebSocket 消息: ${message.type}`, { clientId });\n\n // 发射消息接收事件\n this.eventBus.emitEvent(\"websocket:message:received\", {\n type: message.type,\n data: message.data,\n clientId,\n });\n\n switch (message.type) {\n case \"getConfig\":\n await this.handleGetConfig(ws, clientId);\n break;\n\n case \"updateConfig\":\n await this.handleUpdateConfig(ws, message.data, clientId);\n break;\n\n case \"getStatus\":\n await this.handleGetStatus(ws, clientId);\n break;\n\n case \"restartService\":\n await this.handleRestartService(ws, clientId);\n break;\n\n default:\n this.logger.warn(`未知的 WebSocket 消息类型: ${message.type}`, {\n clientId,\n });\n this.sendError(\n ws,\n \"UNKNOWN_MESSAGE_TYPE\",\n `未知的消息类型: ${message.type}`\n );\n }\n } catch (error) {\n this.logger.error(`处理 WebSocket 消息失败: ${message.type}`, error);\n this.sendError(\n ws,\n \"MESSAGE_PROCESSING_ERROR\",\n error instanceof Error ? error.message : \"消息处理失败\"\n );\n }\n }\n\n /**\n * 处理获取配置请求\n * @deprecated 使用 GET /api/config 替代\n */\n private async handleGetConfig(ws: any, clientId: string): Promise<void> {\n this.logDeprecationWarning(\"WebSocket getConfig\", \"GET /api/config\");\n\n try {\n const config = await this.configService.getConfig();\n this.logger.debug(\"WebSocket: getConfig 请求处理成功\", { clientId });\n ws.send(JSON.stringify({ type: \"config\", data: config }));\n } catch (error) {\n this.logger.error(\"WebSocket: getConfig 请求处理失败\", error);\n this.sendError(\n ws,\n \"CONFIG_READ_ERROR\",\n error instanceof Error ? error.message : \"获取配置失败\"\n );\n }\n }\n\n /**\n * 处理更新配置请求\n * @deprecated 使用 PUT /api/config 替代\n */\n private async handleUpdateConfig(\n ws: any,\n configData: any,\n clientId: string\n ): Promise<void> {\n this.logDeprecationWarning(\"WebSocket updateConfig\", \"PUT /api/config\");\n\n try {\n await this.configService.updateConfig(\n configData,\n `websocket-${clientId}`\n );\n this.logger.debug(\"WebSocket: updateConfig 请求处理成功\", { clientId });\n } catch (error) {\n this.logger.error(\"WebSocket: updateConfig 请求处理失败\", error);\n this.sendError(\n ws,\n \"CONFIG_UPDATE_ERROR\",\n error instanceof Error ? error.message : \"配置更新失败\"\n );\n }\n }\n\n /**\n * 处理获取状态请求\n * @deprecated 使用 GET /api/status 替代\n */\n private async handleGetStatus(ws: any, clientId: string): Promise<void> {\n this.logDeprecationWarning(\"WebSocket getStatus\", \"GET /api/status\");\n\n try {\n const status = this.statusService.getFullStatus();\n ws.send(JSON.stringify({ type: \"status\", data: status.client }));\n this.logger.debug(\"WebSocket: getStatus 请求处理成功\", { clientId });\n } catch (error) {\n this.logger.error(\"WebSocket: getStatus 请求处理失败\", error);\n this.sendError(\n ws,\n \"STATUS_READ_ERROR\",\n error instanceof Error ? error.message : \"获取状态失败\"\n );\n }\n }\n\n /**\n * 处理重启服务请求\n * @deprecated 使用 POST /api/services/restart 替代\n */\n private async handleRestartService(ws: any, clientId: string): Promise<void> {\n this.logDeprecationWarning(\n \"WebSocket restartService\",\n \"POST /api/services/restart\"\n );\n\n try {\n this.logger.info(\"WebSocket: 收到服务重启请求\", { clientId });\n\n // 发射重启请求事件\n this.eventBus.emitEvent(\"service:restart:requested\", {\n source: `websocket-${clientId}`,\n });\n\n // 更新重启状态\n this.statusService.updateRestartStatus(\"restarting\");\n } catch (error) {\n this.logger.error(\"WebSocket: 处理重启请求失败\", error);\n this.sendError(\n ws,\n \"RESTART_REQUEST_ERROR\",\n error instanceof Error ? error.message : \"处理重启请求失败\"\n );\n }\n }\n\n /**\n * 发送错误消息\n */\n private sendError(ws: any, code: string, message: string): void {\n try {\n const errorResponse = {\n type: \"error\",\n error: {\n code,\n message,\n timestamp: Date.now(),\n },\n };\n ws.send(JSON.stringify(errorResponse));\n } catch (error) {\n this.logger.error(\"发送错误消息失败:\", error);\n }\n }\n\n /**\n * 记录废弃功能使用警告\n */\n private logDeprecationWarning(feature: string, alternative: string): void {\n this.logger.warn(\n `[DEPRECATED] ${feature} 功能已废弃,请使用 ${alternative} 替代`\n );\n }\n\n /**\n * 发送初始数据给新连接的客户端\n */\n async sendInitialData(ws: any, clientId: string): Promise<void> {\n try {\n this.logger.debug(\"发送初始数据给客户端\", { clientId });\n\n // 发送当前配置\n const config = await this.configService.getConfig();\n ws.send(JSON.stringify({ type: \"configUpdate\", data: config }));\n\n // 发送当前状态\n const status = this.statusService.getFullStatus();\n ws.send(JSON.stringify({ type: \"statusUpdate\", data: status.client }));\n\n // 如果有重启状态,也发送\n if (status.restart) {\n ws.send(\n JSON.stringify({ type: \"restartStatus\", data: status.restart })\n );\n }\n\n this.logger.debug(\"初始数据发送完成\", { clientId });\n } catch (error) {\n this.logger.error(\"发送初始数据失败:\", error);\n this.sendError(\n ws,\n \"INITIAL_DATA_ERROR\",\n error instanceof Error ? error.message : \"发送初始数据失败\"\n );\n }\n }\n\n /**\n * 处理客户端断开连接\n */\n handleClientDisconnect(clientId: string): void {\n this.logger.info(`客户端断开连接: ${clientId}`);\n this.notificationService.unregisterClient(clientId);\n }\n\n /**\n * 处理客户端连接\n */\n handleClientConnect(ws: any, clientId: string): void {\n this.logger.info(`客户端连接: ${clientId}`);\n this.notificationService.registerClient(clientId, ws);\n }\n}\n","/**\n * CLI 常量定义\n */\n\n/**\n * 服务相关常量\n */\nexport const SERVICE_CONSTANTS = {\n /** 服务名称 */\n NAME: \"xiaozhi-mcp-service\",\n /** 默认端口 */\n DEFAULT_PORT: 3000,\n /** Web UI 默认端口 */\n DEFAULT_WEB_UI_PORT: 9999,\n /** PID 文件名 */\n PID_FILE: \"xiaozhi.pid\",\n /** 日志文件名 */\n LOG_FILE: \"xiaozhi.log\",\n} as const;\n\n/**\n * 配置相关常量\n */\nexport const CONFIG_CONSTANTS = {\n /** 配置文件名(按优先级排序) */\n FILE_NAMES: [\n \"xiaozhi.config.json5\",\n \"xiaozhi.config.jsonc\",\n \"xiaozhi.config.json\",\n ],\n /** 默认配置文件名 */\n DEFAULT_FILE: \"xiaozhi.config.default.json\",\n /** 配置目录环境变量 */\n DIR_ENV_VAR: \"XIAOZHI_CONFIG_DIR\",\n} as const;\n\n/**\n * 路径相关常量\n */\nexport const PATH_CONSTANTS = {\n /** 工作目录名 */\n WORK_DIR: \".xiaozhi\",\n /** 模板目录名 */\n TEMPLATES_DIR: \"templates\",\n /** 日志目录名 */\n LOGS_DIR: \"logs\",\n} as const;\n\n/**\n * 错误码常量\n */\nexport const ERROR_CODES = {\n /** 通用错误 */\n GENERAL_ERROR: \"GENERAL_ERROR\",\n /** 配置错误 */\n CONFIG_ERROR: \"CONFIG_ERROR\",\n /** 服务错误 */\n SERVICE_ERROR: \"SERVICE_ERROR\",\n /** 验证错误 */\n VALIDATION_ERROR: \"VALIDATION_ERROR\",\n /** 文件操作错误 */\n FILE_ERROR: \"FILE_ERROR\",\n /** 进程错误 */\n PROCESS_ERROR: \"PROCESS_ERROR\",\n /** 网络错误 */\n NETWORK_ERROR: \"NETWORK_ERROR\",\n /** 权限错误 */\n PERMISSION_ERROR: \"PERMISSION_ERROR\",\n} as const;\n\n/**\n * 超时常量(毫秒)\n */\nexport const TIMEOUT_CONSTANTS = {\n /** 进程停止超时 */\n PROCESS_STOP: 3000,\n /** 服务启动超时 */\n SERVICE_START: 10000,\n /** 网络请求超时 */\n NETWORK_REQUEST: 5000,\n /** 文件操作超时 */\n FILE_OPERATION: 2000,\n} as const;\n\n/**\n * 重试常量\n */\nexport const RETRY_CONSTANTS = {\n /** 默认重试次数 */\n DEFAULT_ATTEMPTS: 3,\n /** 重试间隔(毫秒) */\n DEFAULT_INTERVAL: 1000,\n /** 最大重试间隔(毫秒) */\n MAX_INTERVAL: 5000,\n} as const;\n","/**\n * 错误消息管理\n */\n\nimport { ERROR_CODES } from \"../Constants.js\";\n\n/**\n * 错误消息映射\n */\nconst ERROR_HELP_MESSAGES: Record<string, string> = {\n [ERROR_CODES.CONFIG_ERROR]: '运行 \"xiaozhi --help\" 查看配置相关命令',\n [ERROR_CODES.SERVICE_ERROR]: '运行 \"xiaozhi status\" 检查服务状态',\n [ERROR_CODES.VALIDATION_ERROR]: \"检查输入参数是否正确\",\n [ERROR_CODES.FILE_ERROR]: \"检查文件路径和权限\",\n [ERROR_CODES.PROCESS_ERROR]: \"检查进程状态和权限\",\n [ERROR_CODES.NETWORK_ERROR]: \"检查网络连接和防火墙设置\",\n [ERROR_CODES.PERMISSION_ERROR]: \"尝试使用管理员权限运行\",\n};\n\n/**\n * 常见问题解决方案\n */\nconst COMMON_SOLUTIONS: Record<string, string[]> = {\n config_not_found: [\n '运行 \"xiaozhi init\" 初始化配置文件',\n \"检查当前目录是否为项目根目录\",\n \"设置 XIAOZHI_CONFIG_DIR 环境变量指定配置目录\",\n ],\n service_port_occupied: [\n \"检查端口是否被其他程序占用\",\n '使用 \"lsof -i :端口号\" 查看端口使用情况',\n \"更改配置文件中的端口设置\",\n ],\n permission_denied: [\n \"检查文件和目录权限\",\n \"使用 sudo 或管理员权限运行\",\n \"确保当前用户有足够的权限\",\n ],\n service_start_failed: [\n \"检查配置文件格式是否正确\",\n \"查看日志文件获取详细错误信息\",\n \"确保所有依赖服务正常运行\",\n ],\n};\n\n/**\n * 错误消息管理类\n */\nexport class ERROR_MESSAGES {\n /**\n * 获取错误码对应的帮助信息\n */\n static getHelpMessage(errorCode: string): string | undefined {\n return ERROR_HELP_MESSAGES[errorCode];\n }\n\n /**\n * 获取常见问题的解决方案\n */\n static getSolutions(problemKey: string): string[] {\n return COMMON_SOLUTIONS[problemKey] || [];\n }\n\n /**\n * 格式化错误消息\n */\n static formatError(error: Error, context?: string): string {\n const contextPrefix = context ? `[${context}] ` : \"\";\n return `${contextPrefix}${error.message}`;\n }\n\n /**\n * 获取友好的错误描述\n */\n static getFriendlyMessage(errorCode: string): string {\n const friendlyMessages: Record<string, string> = {\n [ERROR_CODES.CONFIG_ERROR]: \"配置文件相关错误\",\n [ERROR_CODES.SERVICE_ERROR]: \"服务运行相关错误\",\n [ERROR_CODES.VALIDATION_ERROR]: \"输入验证错误\",\n [ERROR_CODES.FILE_ERROR]: \"文件操作错误\",\n [ERROR_CODES.PROCESS_ERROR]: \"进程管理错误\",\n [ERROR_CODES.NETWORK_ERROR]: \"网络连接错误\",\n [ERROR_CODES.PERMISSION_ERROR]: \"权限不足错误\",\n };\n\n return friendlyMessages[errorCode] || \"未知错误\";\n }\n\n /**\n * 检查是否为可恢复错误\n */\n static isRecoverable(errorCode: string): boolean {\n const recoverableErrors: string[] = [\n ERROR_CODES.NETWORK_ERROR,\n ERROR_CODES.FILE_ERROR,\n ERROR_CODES.SERVICE_ERROR,\n ];\n\n return recoverableErrors.includes(errorCode);\n }\n\n /**\n * 获取错误的严重程度\n */\n static getSeverity(\n errorCode: string\n ): \"low\" | \"medium\" | \"high\" | \"critical\" {\n const severityMap: Record<string, \"low\" | \"medium\" | \"high\" | \"critical\"> =\n {\n [ERROR_CODES.VALIDATION_ERROR]: \"low\",\n [ERROR_CODES.FILE_ERROR]: \"medium\",\n [ERROR_CODES.CONFIG_ERROR]: \"medium\",\n [ERROR_CODES.NETWORK_ERROR]: \"medium\",\n [ERROR_CODES.SERVICE_ERROR]: \"high\",\n [ERROR_CODES.PROCESS_ERROR]: \"high\",\n [ERROR_CODES.PERMISSION_ERROR]: \"critical\",\n };\n\n return severityMap[errorCode] || \"medium\";\n }\n}\n","/**\n * 统一错误处理系统\n */\n\nimport { ERROR_CODES } from \"../Constants.js\";\n\n/**\n * CLI 基础错误类\n */\nexport class CLIError extends Error {\n constructor(\n message: string,\n public code: string,\n public exitCode = 1,\n public suggestions?: string[]\n ) {\n super(message);\n this.name = \"CLIError\";\n\n // 确保错误堆栈正确显示\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, CLIError);\n }\n }\n\n /**\n * 创建带建议的错误\n */\n static withSuggestions(\n message: string,\n code: string,\n suggestions: string[]\n ): CLIError {\n return new CLIError(message, code, 1, suggestions);\n }\n}\n\n/**\n * 配置错误\n */\nexport class ConfigError extends CLIError {\n constructor(message: string, suggestions?: string[]) {\n super(message, ERROR_CODES.CONFIG_ERROR, 1, suggestions);\n this.name = \"ConfigError\";\n }\n\n static configNotFound(): ConfigError {\n return new ConfigError(\"配置文件不存在\", [\n '请运行 \"xiaozhi init\" 初始化配置文件',\n ]);\n }\n\n static invalidFormat(format: string): ConfigError {\n return new ConfigError(`无效的配置文件格式: ${format}`, [\n \"支持的格式: json, json5, jsonc\",\n ]);\n }\n}\n\n/**\n * 服务错误\n */\nexport class ServiceError extends CLIError {\n constructor(message: string, suggestions?: string[]) {\n super(message, ERROR_CODES.SERVICE_ERROR, 1, suggestions);\n this.name = \"ServiceError\";\n }\n\n static alreadyRunning(pid: number): ServiceError {\n return new ServiceError(`服务已经在运行 (PID: ${pid})`, [\n '请先运行 \"xiaozhi stop\" 停止现有服务',\n '或者使用 \"xiaozhi restart\" 重启服务',\n ]);\n }\n\n static autoRestarting(pid: number): ServiceError {\n return new ServiceError(\n `检测到服务已在运行 (PID: ${pid}),正在自动重启...`,\n [\"如果不希望自动重启,请使用 xiaozhi stop 手动停止服务\"]\n );\n }\n\n static notRunning(): ServiceError {\n return new ServiceError(\"服务未运行\", ['请运行 \"xiaozhi start\" 启动服务']);\n }\n\n static startFailed(reason: string): ServiceError {\n return new ServiceError(`服务启动失败: ${reason}`, [\n \"检查配置文件是否正确\",\n \"确保端口未被占用\",\n \"查看日志文件获取详细信息\",\n ]);\n }\n}\n\n/**\n * 验证错误\n */\nexport class ValidationError extends CLIError {\n constructor(message: string, field: string) {\n super(`验证失败: ${field} - ${message}`, ERROR_CODES.VALIDATION_ERROR, 1);\n this.name = \"ValidationError\";\n }\n\n static invalidPort(port: number): ValidationError {\n return new ValidationError(\n `端口号必须在 1-65535 范围内,当前值: ${port}`,\n \"port\"\n );\n }\n\n static requiredField(field: string): ValidationError {\n return new ValidationError(\"必填字段不能为空\", field);\n }\n}\n\n/**\n * 文件操作错误\n */\nexport class FileError extends CLIError {\n constructor(message: string, filePath?: string, suggestions?: string[]) {\n const fullMessage = filePath ? `${message}: ${filePath}` : message;\n super(fullMessage, ERROR_CODES.FILE_ERROR, 1, suggestions);\n this.name = \"FileError\";\n }\n\n static notFound(filePath: string): FileError {\n return new FileError(\"文件不存在\", filePath, [\"检查文件路径是否正确\"]);\n }\n\n static permissionDenied(filePath: string): FileError {\n return new FileError(\"权限不足\", filePath, [\n \"检查文件权限或使用管理员权限运行\",\n ]);\n }\n\n static alreadyExists(filePath: string): FileError {\n return new FileError(\"文件已存在\", filePath, [\n \"使用不同的文件名或删除现有文件\",\n ]);\n }\n}\n\n/**\n * 进程错误\n */\nexport class ProcessError extends CLIError {\n constructor(message: string, pid?: number, suggestions?: string[]) {\n const fullMessage = pid ? `${message} (PID: ${pid})` : message;\n super(fullMessage, ERROR_CODES.PROCESS_ERROR, 1, suggestions);\n this.name = \"ProcessError\";\n }\n\n static killFailed(pid: number): ProcessError {\n return new ProcessError(\"无法终止进程\", pid, [\n \"进程可能已经停止或权限不足\",\n ]);\n }\n\n static notFound(pid: number): ProcessError {\n return new ProcessError(\"进程不存在\", pid);\n }\n}\n","/**\n * 错误处理器\n */\n\nimport chalk from \"chalk\";\nimport { ERROR_MESSAGES } from \"./ErrorMessages.js\";\nimport { CLIError } from \"./index.js\";\n\n/**\n * 错误处理器类\n */\nexport class ErrorHandler {\n /**\n * 处理错误并退出程序\n */\n static handle(error: Error): never {\n if (error instanceof CLIError) {\n ErrorHandler.handleCLIError(error);\n } else {\n ErrorHandler.handleUnknownError(error);\n }\n\n process.exit(1);\n }\n\n /**\n * 处理 CLI 错误\n */\n private static handleCLIError(error: CLIError): void {\n console.error(chalk.red(`❌ 错误: ${error.message}`));\n\n // 显示错误码(调试模式)\n if (process.env.DEBUG) {\n console.error(chalk.gray(`错误码: ${error.code}`));\n }\n\n // 显示建议\n if (error.suggestions && error.suggestions.length > 0) {\n console.log(chalk.yellow(\"💡 建议:\"));\n for (const suggestion of error.suggestions) {\n console.log(chalk.gray(` ${suggestion}`));\n }\n }\n\n // 显示相关帮助信息\n const helpMessage = ERROR_MESSAGES.getHelpMessage(error.code);\n if (helpMessage) {\n console.log(chalk.blue(`ℹ️ ${helpMessage}`));\n }\n }\n\n /**\n * 处理未知错误\n */\n private static handleUnknownError(error: Error): void {\n console.error(chalk.red(`❌ 未知错误: ${error.message}`));\n\n // 在调试模式下显示完整堆栈\n if (process.env.DEBUG || process.env.NODE_ENV === \"development\") {\n console.error(chalk.gray(\"堆栈信息:\"));\n console.error(chalk.gray(error.stack));\n } else {\n console.log(\n chalk.yellow(\"💡 提示: 设置 DEBUG=1 环境变量查看详细错误信息\")\n );\n }\n }\n\n /**\n * 异步操作错误处理包装器\n */\n static async handleAsync<T>(\n operation: () => Promise<T>,\n context: string\n ): Promise<T> {\n try {\n return await operation();\n } catch (error) {\n if (error instanceof CLIError) {\n throw error;\n }\n if (error instanceof Error) {\n throw new CLIError(\n `${context}失败: ${error.message}`,\n \"OPERATION_FAILED\",\n 1\n );\n }\n throw new CLIError(`${context}失败: 未知错误`, \"OPERATION_FAILED\", 1);\n }\n }\n\n /**\n * 同步操作错误处理包装器\n */\n static handleSync<T>(operation: () => T, context: string): T {\n try {\n return operation();\n } catch (error) {\n if (error instanceof CLIError) {\n throw error;\n }\n if (error instanceof Error) {\n throw new CLIError(\n `${context}失败: ${error.message}`,\n \"OPERATION_FAILED\",\n 1\n );\n }\n throw new CLIError(`${context}失败: 未知错误`, \"OPERATION_FAILED\", 1);\n }\n }\n\n /**\n * 警告处理\n */\n static warn(message: string, suggestions?: string[]): void {\n console.warn(chalk.yellow(`⚠️ 警告: ${message}`));\n\n if (suggestions && suggestions.length > 0) {\n console.log(chalk.yellow(\"💡 建议:\"));\n for (const suggestion of suggestions) {\n console.log(chalk.gray(` ${suggestion}`));\n }\n }\n }\n\n /**\n * 信息提示\n */\n static info(message: string): void {\n console.log(chalk.blue(`ℹ️ ${message}`));\n }\n\n /**\n * 成功提示\n */\n static success(message: string): void {\n console.log(chalk.green(`✅ ${message}`));\n }\n}\n","/**\n * 文件操作工具\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport type { FileOperationOptions } from \"../Types.js\";\nimport { FileError } from \"../errors/index.js\";\n\n/**\n * 文件工具类\n */\nexport class FileUtils {\n /**\n * 检查文件是否存在\n */\n static exists(filePath: string): boolean {\n try {\n return fs.existsSync(filePath);\n } catch {\n return false;\n }\n }\n\n /**\n * 确保目录存在\n */\n static ensureDir(dirPath: string): void {\n try {\n if (!fs.existsSync(dirPath)) {\n fs.mkdirSync(dirPath, { recursive: true });\n }\n } catch (error) {\n throw new FileError(\"无法创建目录\", dirPath);\n }\n }\n\n /**\n * 读取文件内容\n */\n static readFile(filePath: string, encoding: BufferEncoding = \"utf8\"): string {\n try {\n if (!FileUtils.exists(filePath)) {\n throw FileError.notFound(filePath);\n }\n return fs.readFileSync(filePath, encoding);\n } catch (error) {\n if (error instanceof FileError) {\n throw error;\n }\n throw new FileError(\"无法读取文件\", filePath);\n }\n }\n\n /**\n * 写入文件内容\n */\n static writeFile(\n filePath: string,\n content: string,\n options?: { overwrite?: boolean }\n ): void {\n try {\n if (!options?.overwrite && FileUtils.exists(filePath)) {\n throw FileError.alreadyExists(filePath);\n }\n\n // 确保目录存在\n const dir = path.dirname(filePath);\n FileUtils.ensureDir(dir);\n\n fs.writeFileSync(filePath, content, \"utf8\");\n } catch (error) {\n if (error instanceof FileError) {\n throw error;\n }\n throw new FileError(\"无法写入文件\", filePath);\n }\n }\n\n /**\n * 复制文件\n */\n static copyFile(\n srcPath: string,\n destPath: string,\n options?: { overwrite?: boolean }\n ): void {\n try {\n if (!FileUtils.exists(srcPath)) {\n throw FileError.notFound(srcPath);\n }\n\n if (!options?.overwrite && FileUtils.exists(destPath)) {\n throw FileError.alreadyExists(destPath);\n }\n\n // 确保目标目录存在\n const destDir = path.dirname(destPath);\n FileUtils.ensureDir(destDir);\n\n fs.copyFileSync(srcPath, destPath);\n } catch (error) {\n if (error instanceof FileError) {\n throw error;\n }\n throw new FileError(\"无法复制文件\", srcPath);\n }\n }\n\n /**\n * 删除文件\n */\n static deleteFile(filePath: string): void {\n try {\n if (FileUtils.exists(filePath)) {\n fs.unlinkSync(filePath);\n }\n } catch (error) {\n throw new FileError(\"无法删除文件\", filePath);\n }\n }\n\n /**\n * 复制目录\n */\n static copyDirectory(\n srcDir: string,\n destDir: string,\n options: FileOperationOptions = {}\n ): void {\n try {\n if (!FileUtils.exists(srcDir)) {\n throw FileError.notFound(srcDir);\n }\n\n // 确保目标目录存在\n FileUtils.ensureDir(destDir);\n\n const items = fs.readdirSync(srcDir);\n\n for (const item of items) {\n // 检查是否在排除列表中\n if (options.exclude?.includes(item)) {\n continue;\n }\n\n const srcPath = path.join(srcDir, item);\n const destPath = path.join(destDir, item);\n const stat = fs.statSync(srcPath);\n\n if (stat.isDirectory()) {\n if (options.recursive !== false) {\n FileUtils.copyDirectory(srcPath, destPath, options);\n }\n } else {\n FileUtils.copyFile(srcPath, destPath, {\n overwrite: options.overwrite,\n });\n }\n }\n } catch (error) {\n if (error instanceof FileError) {\n throw error;\n }\n throw new FileError(\"无法复制目录\", srcDir);\n }\n }\n\n /**\n * 删除目录\n */\n static deleteDirectory(\n dirPath: string,\n options: { recursive?: boolean } = {}\n ): void {\n try {\n if (FileUtils.exists(dirPath)) {\n fs.rmSync(dirPath, {\n recursive: options.recursive ?? true,\n force: true,\n });\n }\n } catch (error) {\n throw new FileError(\"无法删除目录\", dirPath);\n }\n }\n\n /**\n * 获取文件信息\n */\n static getFileInfo(filePath: string): {\n size: number;\n isFile: boolean;\n isDirectory: boolean;\n mtime: Date;\n ctime: Date;\n } {\n try {\n if (!FileUtils.exists(filePath)) {\n throw FileError.notFound(filePath);\n }\n\n const stats = fs.statSync(filePath);\n return {\n size: stats.size,\n isFile: stats.isFile(),\n isDirectory: stats.isDirectory(),\n mtime: stats.mtime,\n ctime: stats.ctime,\n };\n } catch (error) {\n if (error instanceof FileError) {\n throw error;\n }\n throw new FileError(\"无法获取文件信息\", filePath);\n }\n }\n\n /**\n * 列出目录内容\n */\n static listDirectory(\n dirPath: string,\n options: {\n recursive?: boolean;\n includeHidden?: boolean;\n } = {}\n ): string[] {\n try {\n if (!FileUtils.exists(dirPath)) {\n throw FileError.notFound(dirPath);\n }\n\n const items = fs.readdirSync(dirPath);\n let result: string[] = [];\n\n for (const item of items) {\n // 跳过隐藏文件(除非明确要求包含)\n if (!options.includeHidden && item.startsWith(\".\")) {\n continue;\n }\n\n const itemPath = path.join(dirPath, item);\n result.push(itemPath);\n\n // 递归处理子目录\n if (options.recursive && fs.statSync(itemPath).isDirectory()) {\n const subItems = FileUtils.listDirectory(itemPath, options);\n result = result.concat(subItems);\n }\n }\n\n return result;\n } catch (error) {\n if (error instanceof FileError) {\n throw error;\n }\n throw new FileError(\"无法列出目录内容\", dirPath);\n }\n }\n\n /**\n * 创建临时文件\n */\n static createTempFile(prefix = \"xiaozhi-\", suffix = \".tmp\"): string {\n const tempDir = process.env.TMPDIR || process.env.TEMP || \"/tmp\";\n const timestamp = Date.now();\n const random = Math.random().toString(36).substring(2);\n const fileName = `${prefix}${timestamp}-${random}${suffix}`;\n return path.join(tempDir, fileName);\n }\n\n /**\n * 检查文件权限\n */\n static checkPermissions(\n filePath: string,\n mode: number = fs.constants.R_OK | fs.constants.W_OK\n ): boolean {\n try {\n fs.accessSync(filePath, mode);\n return true;\n } catch {\n return false;\n }\n }\n\n /**\n * 获取文件扩展名\n */\n static getExtension(filePath: string): string {\n return path.extname(filePath).toLowerCase();\n }\n\n /**\n * 获取文件名(不含扩展名)\n */\n static getBaseName(filePath: string): string {\n return path.basename(filePath, path.extname(filePath));\n }\n\n /**\n * 规范化路径\n */\n static normalizePath(filePath: string): string {\n return path.normalize(filePath);\n }\n\n /**\n * 解析相对路径为绝对路径\n */\n static resolvePath(filePath: string, basePath?: string): string {\n if (basePath) {\n return path.resolve(basePath, filePath);\n }\n return path.resolve(filePath);\n }\n}\n","/**\n * 格式化工具\n */\n\n/**\n * 格式化工具类\n */\nexport class FormatUtils {\n /**\n * 格式化运行时间\n */\n static formatUptime(ms: number): string {\n const seconds = Math.floor(ms / 1000);\n const minutes = Math.floor(seconds / 60);\n const hours = Math.floor(minutes / 60);\n const days = Math.floor(hours / 24);\n\n if (days > 0) {\n return `${days}天 ${hours % 24}小时 ${minutes % 60}分钟`;\n }\n if (hours > 0) {\n return `${hours}小时 ${minutes % 60}分钟`;\n }\n if (minutes > 0) {\n return `${minutes}分钟 ${seconds % 60}秒`;\n }\n return `${seconds}秒`;\n }\n\n /**\n * 格式化文件大小\n */\n static formatFileSize(bytes: number): string {\n const units = [\"B\", \"KB\", \"MB\", \"GB\", \"TB\"];\n let size = bytes;\n let unitIndex = 0;\n\n while (size >= 1024 && unitIndex < units.length - 1) {\n size /= 1024;\n unitIndex++;\n }\n\n return `${size.toFixed(unitIndex === 0 ? 0 : 1)} ${units[unitIndex]}`;\n }\n\n /**\n * 格式化时间戳\n */\n static formatTimestamp(\n timestamp: number,\n format: \"full\" | \"date\" | \"time\" = \"full\"\n ): string {\n const date = new Date(timestamp);\n\n switch (format) {\n case \"date\":\n return date.toLocaleDateString(\"zh-CN\");\n case \"time\":\n return date.toLocaleTimeString(\"zh-CN\");\n default:\n return date.toLocaleString(\"zh-CN\");\n }\n }\n\n /**\n * 格式化进程 ID\n */\n static formatPid(pid: number): string {\n return `PID: ${pid}`;\n }\n\n /**\n * 格式化端口号\n */\n static formatPort(port: number): string {\n return `端口: ${port}`;\n }\n\n /**\n * 格式化 URL\n */\n static formatUrl(\n protocol: string,\n host: string,\n port: number,\n path?: string\n ): string {\n const url = `${protocol}://${host}:${port}`;\n return path ? `${url}${path}` : url;\n }\n\n /**\n * 格式化配置键值对\n */\n static formatConfigPair(key: string, value: any): string {\n if (typeof value === \"object\") {\n return `${key}: ${JSON.stringify(value, null, 2)}`;\n }\n return `${key}: ${value}`;\n }\n\n /**\n * 格式化错误消息\n */\n static formatError(error: Error, includeStack = false): string {\n let message = `错误: ${error.message}`;\n\n if (includeStack && error.stack) {\n message += `\\n堆栈信息:\\n${error.stack}`;\n }\n\n return message;\n }\n\n /**\n * 格式化列表\n */\n static formatList(items: string[], bullet = \"•\"): string {\n return items.map((item) => `${bullet} ${item}`).join(\"\\n\");\n }\n\n /**\n * 格式化表格数据\n */\n static formatTable(data: Record<string, any>[]): string {\n if (data.length === 0) return \"\";\n\n const keys = Object.keys(data[0]);\n const maxWidths = keys.map((key) =>\n Math.max(key.length, ...data.map((row) => String(row[key]).length))\n );\n\n // 表头\n const header = keys.map((key, i) => key.padEnd(maxWidths[i])).join(\" | \");\n const separator = maxWidths.map((width) => \"-\".repeat(width)).join(\"-|-\");\n\n // 数据行\n const rows = data.map((row) =>\n keys.map((key, i) => String(row[key]).padEnd(maxWidths[i])).join(\" | \")\n );\n\n return [header, separator, ...rows].join(\"\\n\");\n }\n\n /**\n * 格式化进度条\n */\n static formatProgressBar(current: number, total: number, width = 20): string {\n const percentage = Math.min(current / total, 1);\n const filled = Math.floor(percentage * width);\n const empty = width - filled;\n\n const bar = \"█\".repeat(filled) + \"░\".repeat(empty);\n const percent = Math.floor(percentage * 100);\n\n return `[${bar}] ${percent}% (${current}/${total})`;\n }\n\n /**\n * 格式化命令行参数\n */\n static formatCommandArgs(command: string, args: string[]): string {\n const quotedArgs = args.map((arg) =>\n arg.includes(\" \") ? `\"${arg}\"` : arg\n );\n return `${command} ${quotedArgs.join(\" \")}`;\n }\n\n /**\n * 截断长文本\n */\n static truncateText(text: string, maxLength: number, suffix = \"...\"): string {\n if (text.length <= maxLength) return text;\n return text.substring(0, maxLength - suffix.length) + suffix;\n }\n\n /**\n * 格式化 JSON\n */\n static formatJson(obj: any, indent = 2): string {\n try {\n return JSON.stringify(obj, null, indent);\n } catch (error) {\n return String(obj);\n }\n }\n\n /**\n * 格式化布尔值\n */\n static formatBoolean(\n value: boolean,\n trueText = \"是\",\n falseText = \"否\"\n ): string {\n return value ? trueText : falseText;\n }\n}\n","/**\n * 路径处理工具\n */\n\nimport { tmpdir } from \"node:os\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport {\n CONFIG_CONSTANTS,\n PATH_CONSTANTS,\n SERVICE_CONSTANTS,\n} from \"../Constants.js\";\nimport { FileUtils } from \"./FileUtils.js\";\n\n/**\n * 路径工具类\n */\nexport class PathUtils {\n /**\n * 获取 PID 文件路径\n */\n static getPidFile(): string {\n // 优先使用环境变量中的配置目录,否则使用当前工作目录\n const configDir =\n process.env[CONFIG_CONSTANTS.DIR_ENV_VAR] || process.cwd();\n return path.join(configDir, `.${SERVICE_CONSTANTS.NAME}.pid`);\n }\n\n /**\n * 获取日志文件路径\n */\n static getLogFile(projectDir?: string): string {\n const baseDir = projectDir || process.cwd();\n return path.join(baseDir, SERVICE_CONSTANTS.LOG_FILE);\n }\n\n /**\n * 获取配置目录路径\n */\n static getConfigDir(): string {\n return process.env[CONFIG_CONSTANTS.DIR_ENV_VAR] || process.cwd();\n }\n\n /**\n * 获取工作目录路径\n */\n static getWorkDir(): string {\n const configDir = PathUtils.getConfigDir();\n return path.join(configDir, PATH_CONSTANTS.WORK_DIR);\n }\n\n /**\n * 获取模板目录路径\n */\n static getTemplatesDir(): string[] {\n // 在 ES 模块环境中获取当前目录\n const __filename = fileURLToPath(import.meta.url);\n const scriptDir = path.dirname(__filename);\n\n return [\n // 构建后的环境:dist/cli.js -> dist/templates\n path.join(scriptDir, PATH_CONSTANTS.TEMPLATES_DIR),\n // 开发环境:src/cli/utils/PathUtils.ts -> templates\n path.join(scriptDir, \"..\", \"..\", \"..\", PATH_CONSTANTS.TEMPLATES_DIR),\n // npm 全局安装\n path.join(\n scriptDir,\n \"..\",\n \"..\",\n \"..\",\n \"..\",\n PATH_CONSTANTS.TEMPLATES_DIR\n ),\n ];\n }\n\n /**\n * 查找模板目录\n */\n static findTemplatesDir(): string | null {\n const possiblePaths = PathUtils.getTemplatesDir();\n\n for (const templatesDir of possiblePaths) {\n if (FileUtils.exists(templatesDir)) {\n return templatesDir;\n }\n }\n\n return null;\n }\n\n /**\n * 获取模板路径\n */\n static getTemplatePath(templateName: string): string | null {\n const templatesDir = PathUtils.findTemplatesDir();\n if (!templatesDir) {\n return null;\n }\n\n const templatePath = path.join(templatesDir, templateName);\n return FileUtils.exists(templatePath) ? templatePath : null;\n }\n\n /**\n * 获取脚本目录路径\n */\n static getScriptDir(): string {\n const __filename = fileURLToPath(import.meta.url);\n return path.dirname(__filename);\n }\n\n /**\n * 获取项目根目录路径\n */\n static getProjectRoot(): string {\n const scriptDir = PathUtils.getScriptDir();\n // 从 src/cli/utils 回到项目根目录\n return path.join(scriptDir, \"..\", \"..\", \"..\");\n }\n\n /**\n * 获取构建输出目录路径\n */\n static getDistDir(): string {\n const projectRoot = PathUtils.getProjectRoot();\n return path.join(projectRoot, \"dist\");\n }\n\n /**\n * 获取相对于项目根目录的路径\n */\n static getRelativePath(filePath: string): string {\n const projectRoot = PathUtils.getProjectRoot();\n return path.relative(projectRoot, filePath);\n }\n\n /**\n * 解析配置文件路径\n */\n static resolveConfigPath(format?: \"json\" | \"json5\" | \"jsonc\"): string {\n const configDir = PathUtils.getConfigDir();\n\n if (format) {\n return path.join(configDir, `xiaozhi.config.${format}`);\n }\n\n // 按优先级查找配置文件\n for (const fileName of CONFIG_CONSTANTS.FILE_NAMES) {\n const filePath = path.join(configDir, fileName);\n if (FileUtils.exists(filePath)) {\n return filePath;\n }\n }\n\n // 返回默认配置文件路径\n return path.join(configDir, CONFIG_CONSTANTS.FILE_NAMES[2]); // xiaozhi.config.json\n }\n\n /**\n * 获取默认配置文件路径\n */\n static getDefaultConfigPath(): string {\n const projectRoot = PathUtils.getProjectRoot();\n return path.join(projectRoot, CONFIG_CONSTANTS.DEFAULT_FILE);\n }\n\n /**\n * 验证路径安全性(防止路径遍历攻击)\n */\n static validatePath(inputPath: string): boolean {\n const normalizedPath = path.normalize(inputPath);\n return !normalizedPath.includes(\"..\");\n }\n\n /**\n * 确保路径在指定目录内\n */\n static ensurePathWithin(inputPath: string, baseDir: string): string {\n const resolvedPath = path.resolve(baseDir, inputPath);\n const resolvedBase = path.resolve(baseDir);\n\n if (!resolvedPath.startsWith(resolvedBase)) {\n throw new Error(`路径 ${inputPath} 超出了允许的范围`);\n }\n\n return resolvedPath;\n }\n\n /**\n * 获取可执行文件路径\n */\n static getExecutablePath(name: string): string {\n // 直接基于当前执行的 CLI 脚本位置计算\n const cliPath = process.argv[1]; // 当前执行的脚本路径\n const distDir = path.dirname(cliPath); // 获取 dist 目录\n return path.join(distDir, `${name}.js`);\n }\n\n /**\n * 获取 MCP 服务器代理路径\n */\n static getMcpServerProxyPath(): string {\n return PathUtils.getExecutablePath(\"mcpServerProxy\");\n }\n\n /**\n * 获取 Web 服务器独立启动脚本路径\n */\n static getWebServerStandalonePath(): string {\n return PathUtils.getExecutablePath(\"WebServerStandalone\");\n }\n\n /**\n * 创建安全的文件路径\n */\n static createSafePath(...segments: string[]): string {\n const joinedPath = path.join(...segments);\n const normalizedPath = path.normalize(joinedPath);\n\n // 检查路径是否包含危险字符\n if (normalizedPath.includes(\"..\") || normalizedPath.includes(\"~\")) {\n throw new Error(`不安全的路径: ${normalizedPath}`);\n }\n\n return normalizedPath;\n }\n\n /**\n * 获取临时目录路径\n */\n static getTempDir(): string {\n // 使用 Node.js 的 os.tmpdir() 来获取跨平台的临时目录\n return process.env.TMPDIR || process.env.TEMP || tmpdir();\n }\n\n /**\n * 获取用户主目录路径\n */\n static getHomeDir(): string {\n return process.env.HOME || process.env.USERPROFILE || \"\";\n }\n}\n","/**\n * 平台相关工具\n */\n\nimport { execSync } from \"node:child_process\";\nimport { TIMEOUT_CONSTANTS } from \"../Constants.js\";\nimport type { Platform } from \"../Types.js\";\nimport { ProcessError } from \"../errors/index.js\";\n\n/**\n * 平台工具类\n */\nexport class PlatformUtils {\n /**\n * 获取当前平台\n */\n static getCurrentPlatform(): Platform {\n return process.platform as Platform;\n }\n\n /**\n * 检查是否为 Windows 平台\n */\n static isWindows(): boolean {\n return process.platform === \"win32\";\n }\n\n /**\n * 检查是否为 macOS 平台\n */\n static isMacOS(): boolean {\n return process.platform === \"darwin\";\n }\n\n /**\n * 检查是否为 Linux 平台\n */\n static isLinux(): boolean {\n return process.platform === \"linux\";\n }\n\n /**\n * 检查是否为类 Unix 系统\n */\n static isUnixLike(): boolean {\n return !PlatformUtils.isWindows();\n }\n\n /**\n * 检查进程是否为 xiaozhi-client 进程\n */\n static isXiaozhiProcess(pid: number): boolean {\n try {\n // 在容器环境或测试环境中,使用更宽松的检查策略\n if (\n process.env.XIAOZHI_CONTAINER === \"true\" ||\n process.env.NODE_ENV === \"test\"\n ) {\n // 容器环境或测试环境中,如果 PID 存在就认为是有效的\n // 因为容器通常只运行一个主要应用,测试环境中mock了进程检查\n process.kill(pid, 0);\n return true;\n }\n\n // 非容器环境中,尝试更严格的进程检查\n try {\n let cmdline = \"\";\n if (PlatformUtils.isWindows()) {\n // Windows 系统\n const result = execSync(`tasklist /FI \"PID eq ${pid}\" /FO CSV /NH`, {\n encoding: \"utf8\",\n timeout: TIMEOUT_CONSTANTS.PROCESS_STOP,\n });\n cmdline = result.toLowerCase();\n } else {\n // Unix-like 系统\n const result = execSync(`ps -p ${pid} -o comm=`, {\n encoding: \"utf8\",\n timeout: TIMEOUT_CONSTANTS.PROCESS_STOP,\n });\n cmdline = result.toLowerCase();\n }\n\n // 检查是否包含 node 或 xiaozhi 相关关键词\n return cmdline.includes(\"node\") || cmdline.includes(\"xiaozhi\");\n } catch (error) {\n // 如果无法获取进程信息,回退到简单的 PID 检查\n process.kill(pid, 0);\n return true;\n }\n } catch (error) {\n return false;\n }\n }\n\n /**\n * 杀死进程\n */\n static async killProcess(\n pid: number,\n signal: NodeJS.Signals = \"SIGTERM\"\n ): Promise<void> {\n try {\n process.kill(pid, signal);\n\n // 等待进程停止\n let attempts = 0;\n const maxAttempts = 30; // 3秒超时\n\n while (attempts < maxAttempts) {\n await new Promise((resolve) => setTimeout(resolve, 100));\n\n try {\n process.kill(pid, 0);\n attempts++;\n } catch {\n // 进程已停止\n return;\n }\n }\n\n // 如果还在运行,强制停止\n try {\n process.kill(pid, 0);\n process.kill(pid, \"SIGKILL\");\n await new Promise((resolve) => setTimeout(resolve, 500));\n } catch {\n // 进程已停止\n }\n } catch (error) {\n throw new ProcessError(\n `无法终止进程: ${error instanceof Error ? error.message : String(error)}`,\n pid\n );\n }\n }\n\n /**\n * 检查进程是否存在\n */\n static processExists(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n }\n\n /**\n * 获取系统信息\n */\n static getSystemInfo(): {\n platform: Platform;\n arch: string;\n nodeVersion: string;\n isContainer: boolean;\n } {\n return {\n platform: PlatformUtils.getCurrentPlatform(),\n arch: process.arch,\n nodeVersion: process.version,\n isContainer: process.env.XIAOZHI_CONTAINER === \"true\",\n };\n }\n\n /**\n * 获取环境变量\n */\n static getEnvVar(name: string, defaultValue?: string): string | undefined {\n return process.env[name] || defaultValue;\n }\n\n /**\n * 设置环境变量\n */\n static setEnvVar(name: string, value: string): void {\n process.env[name] = value;\n }\n\n /**\n * 检查是否在容器环境中运行\n */\n static isContainerEnvironment(): boolean {\n return process.env.XIAOZHI_CONTAINER === \"true\";\n }\n\n /**\n * 检查是否在测试环境中运行\n */\n static isTestEnvironment(): boolean {\n return process.env.NODE_ENV === \"test\";\n }\n\n /**\n * 检查是否在开发环境中运行\n */\n static isDevelopmentEnvironment(): boolean {\n return process.env.NODE_ENV === \"development\";\n }\n\n /**\n * 获取合适的 tail 命令\n */\n static getTailCommand(filePath: string): { command: string; args: string[] } {\n if (PlatformUtils.isWindows()) {\n return {\n command: \"powershell\",\n args: [\"-Command\", `Get-Content -Path \"${filePath}\" -Wait`],\n };\n }\n return {\n command: \"tail\",\n args: [\"-f\", filePath],\n };\n }\n}\n","/**\n * 输入验证工具\n */\n\nimport type { ConfigFormat } from \"../Types.js\";\nimport { ValidationError } from \"../errors/index.js\";\n\n/**\n * 验证工具类\n */\nexport class Validation {\n /**\n * 验证端口号\n */\n static validatePort(port: number): void {\n if (!Number.isInteger(port) || port < 1 || port > 65535) {\n throw ValidationError.invalidPort(port);\n }\n }\n\n /**\n * 验证配置文件格式\n */\n static validateConfigFormat(format: string): ConfigFormat {\n const validFormats: ConfigFormat[] = [\"json\", \"json5\", \"jsonc\"];\n\n if (!validFormats.includes(format as ConfigFormat)) {\n throw new ValidationError(\n `无效的配置文件格式: ${format},支持的格式: ${validFormats.join(\", \")}`,\n \"format\"\n );\n }\n\n return format as ConfigFormat;\n }\n\n /**\n * 验证必填字段\n */\n static validateRequired(value: any, fieldName: string): void {\n if (value === undefined || value === null || value === \"\") {\n throw ValidationError.requiredField(fieldName);\n }\n }\n\n /**\n * 验证字符串长度\n */\n static validateStringLength(\n value: string,\n fieldName: string,\n options: { min?: number; max?: number } = {}\n ): void {\n if (options.min !== undefined && value.length < options.min) {\n throw new ValidationError(\n `长度不能少于 ${options.min} 个字符,当前长度: ${value.length}`,\n fieldName\n );\n }\n\n if (options.max !== undefined && value.length > options.max) {\n throw new ValidationError(\n `长度不能超过 ${options.max} 个字符,当前长度: ${value.length}`,\n fieldName\n );\n }\n }\n\n /**\n * 验证 URL 格式\n */\n static validateUrl(url: string, fieldName = \"url\"): void {\n try {\n new URL(url);\n } catch {\n throw new ValidationError(`无效的 URL 格式: ${url}`, fieldName);\n }\n }\n\n /**\n * 验证 WebSocket URL 格式\n */\n static validateWebSocketUrl(url: string, fieldName = \"websocket_url\"): void {\n Validation.validateUrl(url, fieldName);\n\n const parsedUrl = new URL(url);\n if (![\"ws:\", \"wss:\"].includes(parsedUrl.protocol)) {\n throw new ValidationError(\n `WebSocket URL 必须使用 ws:// 或 wss:// 协议,当前协议: ${parsedUrl.protocol}`,\n fieldName\n );\n }\n }\n\n /**\n * 验证 HTTP URL 格式\n */\n static validateHttpUrl(url: string, fieldName = \"http_url\"): void {\n Validation.validateUrl(url, fieldName);\n\n const parsedUrl = new URL(url);\n if (![\"http:\", \"https:\"].includes(parsedUrl.protocol)) {\n throw new ValidationError(\n `HTTP URL 必须使用 http:// 或 https:// 协议,当前协议: ${parsedUrl.protocol}`,\n fieldName\n );\n }\n }\n\n /**\n * 验证项目名称\n */\n static validateProjectName(name: string): void {\n Validation.validateRequired(name, \"projectName\");\n Validation.validateStringLength(name, \"projectName\", { min: 1, max: 100 });\n\n // 检查是否包含非法字符\n const invalidChars = /[<>:\"/\\\\|?*]/;\n const hasControlChars = name\n .split(\"\")\n .some((char) => char.charCodeAt(0) < 32);\n\n if (invalidChars.test(name) || hasControlChars) {\n throw new ValidationError(\n '项目名称不能包含以下字符: < > : \" / \\\\ | ? * 以及控制字符',\n \"projectName\"\n );\n }\n\n // 检查是否以点开头\n if (name.startsWith(\".\")) {\n throw new ValidationError(\"项目名称不能以点开头\", \"projectName\");\n }\n }\n\n /**\n * 验证模板名称\n */\n static validateTemplateName(name: string): void {\n Validation.validateRequired(name, \"templateName\");\n Validation.validateStringLength(name, \"templateName\", { min: 1, max: 50 });\n\n // 模板名称只能包含字母、数字、连字符和下划线\n const validPattern = /^[a-zA-Z0-9_-]+$/;\n if (!validPattern.test(name)) {\n throw new ValidationError(\n \"模板名称只能包含字母、数字、连字符和下划线\",\n \"templateName\"\n );\n }\n }\n\n /**\n * 验证环境变量名称\n */\n static validateEnvVarName(name: string): void {\n Validation.validateRequired(name, \"envVarName\");\n\n // 环境变量名称只能包含大写字母、数字和下划线,且不能以数字开头\n const validPattern = /^[A-Z_][A-Z0-9_]*$/;\n if (!validPattern.test(name)) {\n throw new ValidationError(\n \"环境变量名称只能包含大写字母、数字和下划线,且不能以数字开头\",\n \"envVarName\"\n );\n }\n }\n\n /**\n * 验证 JSON 格式\n */\n static validateJson(jsonString: string, fieldName = \"json\"): any {\n try {\n return JSON.parse(jsonString);\n } catch (error) {\n throw new ValidationError(\n `无效的 JSON 格式: ${error instanceof Error ? error.message : String(error)}`,\n fieldName\n );\n }\n }\n\n /**\n * 验证数字范围\n */\n static validateNumberRange(\n value: number,\n fieldName: string,\n options: { min?: number; max?: number } = {}\n ): void {\n if (options.min !== undefined && value < options.min) {\n throw new ValidationError(\n `值不能小于 ${options.min},当前值: ${value}`,\n fieldName\n );\n }\n\n if (options.max !== undefined && value > options.max) {\n throw new ValidationError(\n `值不能大于 ${options.max},当前值: ${value}`,\n fieldName\n );\n }\n }\n\n /**\n * 验证数组长度\n */\n static validateArrayLength(\n array: any[],\n fieldName: string,\n options: { min?: number; max?: number } = {}\n ): void {\n if (options.min !== undefined && array.length < options.min) {\n throw new ValidationError(\n `数组长度不能少于 ${options.min},当前长度: ${array.length}`,\n fieldName\n );\n }\n\n if (options.max !== undefined && array.length > options.max) {\n throw new ValidationError(\n `数组长度不能超过 ${options.max},当前长度: ${array.length}`,\n fieldName\n );\n }\n }\n\n /**\n * 验证对象属性\n */\n static validateObjectProperties(\n obj: Record<string, any>,\n requiredProps: string[],\n fieldName = \"object\"\n ): void {\n for (const prop of requiredProps) {\n if (!(prop in obj)) {\n throw new ValidationError(`缺少必需的属性: ${prop}`, fieldName);\n }\n }\n }\n\n /**\n * 验证枚举值\n */\n static validateEnum<T extends string>(\n value: string,\n validValues: T[],\n fieldName: string\n ): T {\n if (!validValues.includes(value as T)) {\n throw new ValidationError(\n `无效的值: ${value},有效值: ${validValues.join(\", \")}`,\n fieldName\n );\n }\n return value as T;\n }\n\n /**\n * 验证正则表达式\n */\n static validateRegex(pattern: string, fieldName = \"regex\"): RegExp {\n try {\n return new RegExp(pattern);\n } catch (error) {\n throw new ValidationError(\n `无效的正则表达式: ${error instanceof Error ? error.message : String(error)}`,\n fieldName\n );\n }\n }\n}\n","/**\n * 版本管理工具\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { FileError } from \"../errors/index.js\";\n\n/**\n * 版本信息接口\n */\nexport interface VersionInfo {\n version: string;\n name?: string;\n description?: string;\n author?: string;\n}\n\n/**\n * 版本工具类\n */\nexport class VersionUtils {\n private static cachedVersion: string | null = null;\n\n /**\n * 获取版本号\n */\n static getVersion(): string {\n if (VersionUtils.cachedVersion) {\n return VersionUtils.cachedVersion;\n }\n\n try {\n // 在 ES 模块环境中获取当前目录\n const __filename = fileURLToPath(import.meta.url);\n const currentDir = path.dirname(__filename);\n\n // 尝试多个可能的 package.json 路径\n const possiblePaths = [\n // 构建后环境:dist/cli.js -> dist/package.json (优先)\n path.join(currentDir, \"package.json\"),\n // 构建后环境:dist/cli.js -> package.json\n path.join(currentDir, \"..\", \"package.json\"),\n // 开发环境:src/cli/utils/VersionUtils.ts -> package.json\n path.join(currentDir, \"..\", \"..\", \"..\", \"package.json\"),\n // 全局安装环境\n path.join(currentDir, \"..\", \"..\", \"..\", \"..\", \"package.json\"),\n ];\n\n for (const packagePath of possiblePaths) {\n if (fs.existsSync(packagePath)) {\n const packageJson = JSON.parse(fs.readFileSync(packagePath, \"utf8\"));\n if (packageJson.version) {\n VersionUtils.cachedVersion = packageJson.version;\n return packageJson.version;\n }\n }\n }\n\n // 如果都找不到,返回默认版本\n VersionUtils.cachedVersion = \"unknown\";\n return \"unknown\";\n } catch (error) {\n console.warn(\"无法从 package.json 读取版本信息:\", error);\n VersionUtils.cachedVersion = \"unknown\";\n return \"unknown\";\n }\n }\n\n /**\n * 获取完整版本信息\n */\n static getVersionInfo(): VersionInfo {\n try {\n const __filename = fileURLToPath(import.meta.url);\n const currentDir = path.dirname(__filename);\n\n const possiblePaths = [\n // 构建后环境:dist/cli.js -> dist/package.json (优先)\n path.join(currentDir, \"package.json\"),\n // 构建后环境:dist/cli.js -> package.json\n path.join(currentDir, \"..\", \"package.json\"),\n // 开发环境:src/cli/utils/VersionUtils.ts -> package.json\n path.join(currentDir, \"..\", \"..\", \"..\", \"package.json\"),\n // 全局安装环境\n path.join(currentDir, \"..\", \"..\", \"..\", \"..\", \"package.json\"),\n ];\n\n for (const packagePath of possiblePaths) {\n if (fs.existsSync(packagePath)) {\n const packageJson = JSON.parse(fs.readFileSync(packagePath, \"utf8\"));\n return {\n version: packageJson.version || \"unknown\",\n name: packageJson.name,\n description: packageJson.description,\n author: packageJson.author,\n };\n }\n }\n\n return { version: \"unknown\" };\n } catch (error) {\n throw new FileError(\"无法读取版本信息\", \"package.json\");\n }\n }\n\n /**\n * 比较版本号\n */\n static compareVersions(version1: string, version2: string): number {\n const v1Parts = version1.split(\".\").map(Number);\n const v2Parts = version2.split(\".\").map(Number);\n const maxLength = Math.max(v1Parts.length, v2Parts.length);\n\n for (let i = 0; i < maxLength; i++) {\n const v1Part = v1Parts[i] || 0;\n const v2Part = v2Parts[i] || 0;\n\n if (v1Part > v2Part) return 1;\n if (v1Part < v2Part) return -1;\n }\n\n return 0;\n }\n\n /**\n * 检查版本是否有效\n */\n static isValidVersion(version: string): boolean {\n const versionRegex = /^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9.-]+)?$/;\n return versionRegex.test(version);\n }\n\n /**\n * 清除版本缓存\n */\n static clearCache(): void {\n VersionUtils.cachedVersion = null;\n }\n}\n","/**\n * 进程管理服务\n */\n\nimport fs from \"node:fs\";\nimport { SERVICE_CONSTANTS } from \"../Constants.js\";\nimport { FileError, ProcessError } from \"../errors/index.js\";\nimport type {\n ProcessManager as IProcessManager,\n ServiceStatus,\n} from \"../interfaces/Service.js\";\nimport { FileUtils } from \"../utils/FileUtils.js\";\nimport { FormatUtils } from \"../utils/FormatUtils.js\";\nimport { PathUtils } from \"../utils/PathUtils.js\";\nimport { PlatformUtils } from \"../utils/PlatformUtils.js\";\n\n/**\n * PID 文件信息接口\n */\ninterface PidFileInfo {\n pid: number;\n startTime: number;\n mode: \"foreground\" | \"daemon\";\n}\n\n/**\n * 进程管理器实现\n */\nexport class ProcessManagerImpl implements IProcessManager {\n /**\n * 获取 PID 文件路径\n */\n private getPidFilePath(): string {\n return PathUtils.getPidFile();\n }\n\n /**\n * 读取 PID 文件信息\n */\n private readPidFile(): PidFileInfo | null {\n try {\n const pidFilePath = this.getPidFilePath();\n\n if (!FileUtils.exists(pidFilePath)) {\n return null;\n }\n\n const pidContent = FileUtils.readFile(pidFilePath).trim();\n const [pidStr, startTimeStr, mode] = pidContent.split(\"|\");\n\n const pid = Number.parseInt(pidStr);\n const startTime = Number.parseInt(startTimeStr);\n\n if (Number.isNaN(pid) || Number.isNaN(startTime)) {\n // PID 文件损坏,删除它\n this.cleanupPidFile();\n return null;\n }\n\n return {\n pid,\n startTime,\n mode: (mode as \"foreground\" | \"daemon\") || \"foreground\",\n };\n } catch (error) {\n // 读取失败,可能文件损坏\n this.cleanupPidFile();\n return null;\n }\n }\n\n /**\n * 写入 PID 文件信息\n */\n private writePidFile(pid: number, mode: \"foreground\" | \"daemon\"): void {\n try {\n const pidInfo = `${pid}|${Date.now()}|${mode}`;\n const pidFilePath = this.getPidFilePath();\n FileUtils.writeFile(pidFilePath, pidInfo, { overwrite: true });\n } catch (error) {\n throw new FileError(\"无法写入 PID 文件\", this.getPidFilePath());\n }\n }\n\n /**\n * 检查是否为 xiaozhi 进程\n */\n isXiaozhiProcess(pid: number): boolean {\n return PlatformUtils.isXiaozhiProcess(pid);\n }\n\n /**\n * 获取服务状态\n */\n getServiceStatus(): ServiceStatus {\n try {\n const pidInfo = this.readPidFile();\n\n if (!pidInfo) {\n return { running: false };\n }\n\n // 检查进程是否还在运行且是 xiaozhi 进程\n if (!this.isXiaozhiProcess(pidInfo.pid)) {\n // 进程不存在或不是 xiaozhi 进程,删除 PID 文件\n this.cleanupPidFile();\n return { running: false };\n }\n\n // 计算运行时间\n const uptime = FormatUtils.formatUptime(Date.now() - pidInfo.startTime);\n\n return {\n running: true,\n pid: pidInfo.pid,\n uptime,\n mode: pidInfo.mode,\n };\n } catch (error) {\n return { running: false };\n }\n }\n\n /**\n * 保存进程信息\n */\n savePidInfo(pid: number, mode: \"foreground\" | \"daemon\"): void {\n this.writePidFile(pid, mode);\n }\n\n /**\n * 杀死进程\n */\n async killProcess(pid: number): Promise<void> {\n try {\n await PlatformUtils.killProcess(pid);\n } catch (error) {\n throw new ProcessError(\n `无法终止进程: ${error instanceof Error ? error.message : String(error)}`,\n pid\n );\n }\n }\n\n /**\n * 优雅停止进程\n */\n async gracefulKillProcess(pid: number): Promise<void> {\n try {\n // 尝试优雅停止\n process.kill(pid, \"SIGTERM\");\n\n // 等待进程停止\n let attempts = 0;\n const maxAttempts = 30; // 3秒超时\n\n while (attempts < maxAttempts) {\n await new Promise((resolve) => setTimeout(resolve, 100));\n\n try {\n process.kill(pid, 0);\n attempts++;\n } catch {\n // 进程已停止\n return;\n }\n }\n\n // 如果还在运行,强制停止\n try {\n process.kill(pid, 0);\n process.kill(pid, \"SIGKILL\");\n await new Promise((resolve) => setTimeout(resolve, 500));\n } catch {\n // 进程已停止\n }\n } catch (error) {\n throw new ProcessError(\n `无法停止进程: ${error instanceof Error ? error.message : String(error)}`,\n pid\n );\n }\n }\n\n /**\n * 清理 PID 文件\n */\n cleanupPidFile(): void {\n try {\n const pidFilePath = this.getPidFilePath();\n if (FileUtils.exists(pidFilePath)) {\n FileUtils.deleteFile(pidFilePath);\n }\n } catch (error) {\n // 忽略清理错误,但可以记录日志\n console.warn(\"清理 PID 文件失败:\", error);\n }\n }\n\n /**\n * 检查进程是否存在\n */\n processExists(pid: number): boolean {\n return PlatformUtils.processExists(pid);\n }\n\n /**\n * 清理容器环境的旧状态\n */\n cleanupContainerState(): void {\n if (PlatformUtils.isContainerEnvironment()) {\n try {\n this.cleanupPidFile();\n } catch (error) {\n // 忽略清理错误\n }\n }\n }\n\n /**\n * 获取进程信息\n */\n getProcessInfo(pid: number): { exists: boolean; isXiaozhi: boolean } {\n const exists = this.processExists(pid);\n const isXiaozhi = exists ? this.isXiaozhiProcess(pid) : false;\n\n return { exists, isXiaozhi };\n }\n\n /**\n * 验证 PID 文件完整性\n */\n validatePidFile(): boolean {\n try {\n const pidInfo = this.readPidFile();\n return pidInfo !== null;\n } catch {\n return false;\n }\n }\n}\n","/**\n * 守护进程管理服务\n */\n\nimport { type ChildProcess, spawn } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport { ProcessError, ServiceError } from \"../errors/index.js\";\nimport type {\n DaemonManager as IDaemonManager,\n ProcessManager,\n} from \"../interfaces/Service.js\";\nimport { PathUtils } from \"../utils/PathUtils.js\";\nimport { PlatformUtils } from \"../utils/PlatformUtils.js\";\n\n/**\n * 守护进程选项\n */\nexport interface DaemonOptions {\n /** 日志文件名 */\n logFileName?: string;\n /** 环境变量 */\n env?: Record<string, string>;\n /** 是否打开浏览器 */\n openBrowser?: boolean;\n /** 工作目录 */\n cwd?: string;\n}\n\n/**\n * 守护进程管理器实现\n */\nexport class DaemonManagerImpl implements IDaemonManager {\n private currentDaemon: ChildProcess | null = null;\n\n constructor(\n private processManager: ProcessManager,\n private logger: any\n ) {}\n\n /**\n * 启动守护进程\n */\n async startDaemon(\n serverFactory: () => Promise<any>,\n options: DaemonOptions = {}\n ): Promise<void> {\n try {\n // 检查是否已有守护进程在运行\n const status = this.processManager.getServiceStatus();\n if (status.running) {\n throw ServiceError.alreadyRunning(status.pid!);\n }\n\n // 启动守护进程\n const child = await this.spawnDaemonProcess(serverFactory, options);\n this.currentDaemon = child;\n\n // 保存 PID 信息\n this.processManager.savePidInfo(child.pid!, \"daemon\");\n\n // 设置日志重定向\n await this.setupLogging(child, options.logFileName || \"xiaozhi.log\");\n\n // 设置进程事件监听\n this.setupEventHandlers(child);\n\n // 分离进程\n child.unref();\n\n this.logger.info(`守护进程已启动 (PID: ${child.pid})`);\n } catch (error) {\n throw new ServiceError(\n `启动守护进程失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * 停止守护进程\n */\n async stopDaemon(): Promise<void> {\n try {\n const status = this.processManager.getServiceStatus();\n\n if (!status.running) {\n throw ServiceError.notRunning();\n }\n\n // 优雅停止守护进程\n await this.processManager.gracefulKillProcess(status.pid!);\n\n // 清理 PID 文件\n this.processManager.cleanupPidFile();\n\n // 清理当前守护进程引用\n this.currentDaemon = null;\n\n this.logger.info(\"守护进程已停止\");\n } catch (error) {\n throw new ServiceError(\n `停止守护进程失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * 重启守护进程\n */\n async restartDaemon(\n serverFactory: () => Promise<any>,\n options: DaemonOptions = {}\n ): Promise<void> {\n try {\n // 先停止现有守护进程\n const status = this.processManager.getServiceStatus();\n if (status.running) {\n await this.stopDaemon();\n // 等待一下确保完全停止\n await new Promise((resolve) => setTimeout(resolve, 1000));\n }\n\n // 重新启动守护进程\n await this.startDaemon(serverFactory, options);\n } catch (error) {\n throw new ServiceError(\n `重启守护进程失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * 获取守护进程状态\n */\n getDaemonStatus(): { running: boolean; pid?: number; uptime?: string } {\n return this.processManager.getServiceStatus();\n }\n\n /**\n * 连接到守护进程日志\n */\n async attachToLogs(logFileName = \"xiaozhi.log\"): Promise<void> {\n try {\n const logFilePath = PathUtils.getLogFile();\n\n if (!fs.existsSync(logFilePath)) {\n throw new ServiceError(\"日志文件不存在\");\n }\n\n // 使用平台相关的 tail 命令\n const { command, args } = PlatformUtils.getTailCommand(logFilePath);\n const tail = spawn(command, args, { stdio: \"inherit\" });\n\n // 处理中断信号\n process.on(\"SIGINT\", () => {\n console.log(\"\\n断开连接,服务继续在后台运行\");\n tail.kill();\n process.exit(0);\n });\n\n tail.on(\"exit\", () => {\n process.exit(0);\n });\n\n tail.on(\"error\", (error) => {\n throw new ServiceError(`连接日志失败: ${error.message}`);\n });\n } catch (error) {\n throw new ServiceError(\n `连接日志失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * 生成守护进程\n */\n private async spawnDaemonProcess(\n serverFactory: () => Promise<any>,\n options: DaemonOptions\n ): Promise<ChildProcess> {\n // 获取启动脚本路径\n const scriptPath = PathUtils.getWebServerStandalonePath();\n\n // 构建启动参数\n const args = [scriptPath];\n if (options.openBrowser) {\n args.push(\"--open-browser\");\n }\n\n // 构建环境变量\n const env = {\n ...process.env,\n XIAOZHI_CONFIG_DIR: PathUtils.getConfigDir(),\n XIAOZHI_DAEMON: \"true\",\n ...options.env,\n };\n\n // 启动子进程\n const child = spawn(\"node\", args, {\n detached: true,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n env,\n cwd: options.cwd || process.cwd(),\n });\n\n if (!child.pid) {\n throw new ProcessError(\"无法启动守护进程\", 0);\n }\n\n return child;\n }\n\n /**\n * 设置日志重定向\n */\n private async setupLogging(\n child: ChildProcess,\n logFileName: string\n ): Promise<void> {\n try {\n const logFilePath = PathUtils.getLogFile();\n\n // 确保日志目录存在\n const path = await import(\"node:path\");\n const logDir = path.dirname(logFilePath);\n if (!fs.existsSync(logDir)) {\n fs.mkdirSync(logDir, { recursive: true });\n }\n\n // 创建日志流\n const logStream = fs.createWriteStream(logFilePath, { flags: \"a\" });\n\n // 重定向标准输出和错误输出\n child.stdout?.pipe(logStream);\n child.stderr?.pipe(logStream);\n\n // 写入启动日志\n const timestamp = new Date().toISOString();\n logStream.write(`\\n[${timestamp}] 守护进程启动 (PID: ${child.pid})\\n`);\n } catch (error) {\n this.logger.warn(\n `设置日志重定向失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * 设置事件处理器\n */\n private setupEventHandlers(child: ChildProcess): void {\n // 监听进程退出\n child.on(\"exit\", (code, signal) => {\n if (code !== 0 && code !== null) {\n this.logger.error(`守护进程异常退出 (代码: ${code}, 信号: ${signal})`);\n } else {\n this.logger.info(\"守护进程正常退出\");\n }\n\n // 清理 PID 文件\n this.processManager.cleanupPidFile();\n this.currentDaemon = null;\n });\n\n // 监听进程错误\n child.on(\"error\", (error) => {\n this.logger.error(`守护进程错误: ${error.message}`);\n this.processManager.cleanupPidFile();\n this.currentDaemon = null;\n });\n\n // 监听进程断开连接\n child.on(\"disconnect\", () => {\n this.logger.info(\"守护进程断开连接\");\n });\n }\n\n /**\n * 检查守护进程健康状态\n */\n async checkHealth(): Promise<boolean> {\n try {\n const status = this.getDaemonStatus();\n\n if (!status.running || !status.pid) {\n return false;\n }\n\n // 检查进程是否真的在运行\n const processInfo = this.processManager.getProcessInfo(status.pid);\n return processInfo.exists && processInfo.isXiaozhi;\n } catch {\n return false;\n }\n }\n\n /**\n * 获取当前守护进程引用\n */\n getCurrentDaemon(): ChildProcess | null {\n return this.currentDaemon;\n }\n\n /**\n * 清理守护进程资源\n */\n cleanup(): void {\n if (this.currentDaemon) {\n try {\n this.currentDaemon.kill(\"SIGTERM\");\n } catch (error) {\n this.logger.warn(\n `清理守护进程失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n this.currentDaemon = null;\n }\n }\n}\n","/**\n * 传输适配器抽象基类\n * 定义了所有传输协议的统一接口,支持 stdio、SSE、HTTP、WebSocket 等多种传输方式\n * 这是阶段二重构的核心组件,用于抽象不同的传输层实现\n */\n\nimport { type Logger, logger } from \"../Logger.js\";\nimport type { MCPMessageHandler } from \"../core/MCPMessageHandler.js\";\n\n// MCP 消息接口\nexport interface MCPMessage {\n jsonrpc: \"2.0\";\n method: string;\n params?: any;\n id?: string | number;\n}\n\n// MCP 响应接口\nexport interface MCPResponse {\n jsonrpc: \"2.0\";\n result?: any;\n error?: MCPError;\n id: string | number | null;\n}\n\n// MCP 错误接口\nexport interface MCPError {\n code: number;\n message: string;\n data?: any;\n}\n\n// 连接状态枚举\nexport enum ConnectionState {\n DISCONNECTED = \"disconnected\",\n CONNECTING = \"connecting\",\n CONNECTED = \"connected\",\n ERROR = \"error\",\n}\n\n// 传输适配器配置接口\nexport interface TransportConfig {\n name: string;\n timeout?: number;\n retryAttempts?: number;\n retryDelay?: number;\n}\n\n/**\n * 传输适配器抽象基类\n * 所有具体的传输适配器都必须继承此类并实现抽象方法\n */\nexport abstract class TransportAdapter {\n protected logger: Logger;\n protected messageHandler: MCPMessageHandler;\n protected connectionId: string;\n protected config: TransportConfig;\n protected state: ConnectionState = ConnectionState.DISCONNECTED;\n\n constructor(messageHandler: MCPMessageHandler, config: TransportConfig) {\n this.messageHandler = messageHandler;\n this.config = config;\n this.connectionId = this.generateConnectionId();\n this.logger = logger;\n }\n\n /**\n * 初始化传输适配器\n * 子类应该在此方法中进行必要的初始化工作\n */\n abstract initialize(): Promise<void>;\n\n /**\n * 启动传输适配器\n * 子类应该在此方法中启动监听或连接\n */\n abstract start(): Promise<void>;\n\n /**\n * 停止传输适配器\n * 子类应该在此方法中清理资源和关闭连接\n */\n abstract stop(): Promise<void>;\n\n /**\n * 发送消息\n * 子类应该实现具体的消息发送逻辑\n */\n abstract sendMessage(message: MCPMessage | MCPResponse): Promise<void>;\n\n /**\n * 处理接收到的消息\n * 这是一个通用的消息处理方法,子类可以直接使用\n */\n protected async handleIncomingMessage(message: MCPMessage): Promise<void> {\n try {\n this.logger.debug(`处理接收到的消息: ${message.method}`, message);\n\n const response = await this.messageHandler.handleMessage(message);\n\n this.logger.debug(\"发送响应消息:\", response);\n await this.sendMessage(response);\n } catch (error) {\n this.logger.error(`处理消息时出错: ${message.method}`, error);\n\n const errorResponse = this.createErrorResponse(\n error as Error,\n message.id\n );\n await this.sendMessage(errorResponse);\n }\n }\n\n /**\n * 创建错误响应\n * 统一的错误响应创建方法\n */\n protected createErrorResponse(\n error: Error,\n id?: string | number\n ): MCPResponse {\n // 根据错误类型确定错误代码\n let errorCode = -32603; // Internal error\n\n if (\n error.message.includes(\"未找到工具\") ||\n error.message.includes(\"未知的方法\")\n ) {\n errorCode = -32601; // Method not found\n } else if (\n error.message.includes(\"参数\") ||\n error.message.includes(\"不能为空\")\n ) {\n errorCode = -32602; // Invalid params\n }\n\n return {\n jsonrpc: \"2.0\",\n error: {\n code: errorCode,\n message: error.message,\n data: {\n stack: error.stack,\n },\n },\n id: id || null,\n };\n }\n\n /**\n * 生成唯一的连接ID\n */\n private generateConnectionId(): string {\n const timestamp = Date.now();\n const random = Math.random().toString(36).substr(2, 9);\n return `${this.config.name}_${timestamp}_${random}`;\n }\n\n /**\n * 获取连接ID\n */\n getConnectionId(): string {\n return this.connectionId;\n }\n\n /**\n * 获取连接状态\n */\n getState(): ConnectionState {\n return this.state;\n }\n\n /**\n * 设置连接状态\n */\n protected setState(state: ConnectionState): void {\n const oldState = this.state;\n this.state = state;\n\n if (oldState !== state) {\n this.logger.info(`连接状态变更: ${oldState} -> ${state}`);\n this.onStateChange(oldState, state);\n }\n }\n\n /**\n * 状态变更回调\n * 子类可以重写此方法来处理状态变更事件\n */\n protected onStateChange(\n oldState: ConnectionState,\n newState: ConnectionState\n ): void {\n // 默认实现为空,子类可以重写\n }\n\n /**\n * 获取配置\n */\n getConfig(): TransportConfig {\n return { ...this.config };\n }\n\n /**\n * 获取消息处理器\n */\n getMessageHandler(): MCPMessageHandler {\n return this.messageHandler;\n }\n\n /**\n * 解析 JSON 消息\n * 统一的 JSON 解析方法,包含错误处理\n */\n protected parseMessage(data: string): MCPMessage | null {\n try {\n const message = JSON.parse(data.trim());\n\n // 验证基本的 JSON-RPC 格式\n if (!message.jsonrpc || message.jsonrpc !== \"2.0\") {\n this.logger.warn(\"收到非 JSON-RPC 2.0 格式的消息\", message);\n return null;\n }\n\n if (!message.method) {\n this.logger.warn(\"收到没有 method 字段的消息\", message);\n return null;\n }\n\n return message;\n } catch (error) {\n this.logger.error(\"解析 JSON 消息失败\", { data, error });\n return null;\n }\n }\n\n /**\n * 序列化消息\n * 统一的消息序列化方法\n */\n protected serializeMessage(message: MCPMessage | MCPResponse): string {\n try {\n return JSON.stringify(message);\n } catch (error) {\n this.logger.error(\"序列化消息失败\", { message, error });\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n throw new Error(`消息序列化失败: ${errorMessage}`);\n }\n }\n\n /**\n * 验证消息格式\n * 验证消息是否符合 MCP 协议规范\n */\n protected validateMessage(message: any): boolean {\n if (!message || typeof message !== \"object\") {\n return false;\n }\n\n if (message.jsonrpc !== \"2.0\") {\n return false;\n }\n\n // 请求消息必须有 method 字段\n if (message.method && typeof message.method !== \"string\") {\n return false;\n }\n\n // 响应消息必须有 result 或 error 字段\n if (!message.method && !message.result && !message.error) {\n return false;\n }\n\n return true;\n }\n\n /**\n * 处理超时\n * 统一的超时处理方法\n */\n protected createTimeoutPromise<T>(\n promise: Promise<T>,\n timeoutMs: number\n ): Promise<T> {\n return Promise.race([\n promise,\n new Promise<T>((_, reject) => {\n setTimeout(() => {\n reject(new Error(`操作超时: ${timeoutMs}ms`));\n }, timeoutMs);\n }),\n ]);\n }\n}\n","/**\n * HTTP 传输适配器\n * 处理 HTTP 和 SSE (Server-Sent Events) 的 MCP 通信\n * 从 mcpServer.ts 中抽取的 HTTP/SSE 处理逻辑\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport type { Server } from \"node:http\";\nimport express from \"express\";\nimport type { Request, Response } from \"express\";\nimport type { MCPMessageHandler } from \"../core/MCPMessageHandler.js\";\nimport { ConnectionState, TransportAdapter } from \"./TransportAdapter.js\";\nimport type {\n MCPMessage,\n MCPResponse,\n TransportConfig,\n} from \"./TransportAdapter.js\";\n\n/**\n * SSE 客户端接口\n */\ninterface SSEClient {\n id: string;\n sessionId: string;\n response: Response;\n connectedAt: Date;\n}\n\n/**\n * HTTP 适配器配置\n */\nexport interface HTTPConfig extends TransportConfig {\n port?: number;\n host?: string;\n enableSSE?: boolean;\n enableRPC?: boolean;\n corsOrigin?: string;\n maxClients?: number;\n}\n\n/**\n * HTTP 传输适配器实现\n * 支持直接 HTTP RPC 调用和 SSE 流式通信\n */\nexport class HTTPAdapter extends TransportAdapter {\n private app: express.Application;\n private server: Server | null = null;\n private clients: Map<string, SSEClient> = new Map();\n private port: number;\n private host: string;\n private enableSSE: boolean;\n private enableRPC: boolean;\n private corsOrigin: string;\n private maxClients: number;\n\n constructor(\n messageHandler: MCPMessageHandler,\n config: HTTPConfig = { name: \"http\" }\n ) {\n super(messageHandler, config);\n\n this.port = config.port || 3000;\n this.host = config.host || \"0.0.0.0\";\n this.enableSSE = config.enableSSE !== false; // 默认启用\n this.enableRPC = config.enableRPC !== false; // 默认启用\n this.corsOrigin = config.corsOrigin || \"*\";\n this.maxClients = config.maxClients !== undefined ? config.maxClients : 100;\n\n this.app = express();\n this.setupMiddleware();\n }\n\n /**\n * 初始化 HTTP 适配器\n */\n async initialize(): Promise<void> {\n this.logger.info(\"初始化 HTTP 适配器\");\n\n try {\n this.setupRoutes();\n this.setState(ConnectionState.CONNECTING);\n this.logger.info(\"HTTP 适配器初始化完成\");\n } catch (error) {\n this.logger.error(\"HTTP 适配器初始化失败\", error);\n this.setState(ConnectionState.ERROR);\n throw error;\n }\n }\n\n /**\n * 启动 HTTP 服务器\n */\n async start(): Promise<void> {\n if (this.server) {\n this.logger.warn(\"HTTP 服务器已在运行\");\n return;\n }\n\n this.logger.info(`启动 HTTP 服务器在 ${this.host}:${this.port}`);\n\n return new Promise((resolve, reject) => {\n this.server = this.app.listen(this.port, this.host, () => {\n this.setState(ConnectionState.CONNECTED);\n this.logger.info(\"HTTP 适配器启动成功\");\n this.logger.info(`- RPC 端点: http://${this.host}:${this.port}/rpc`);\n if (this.enableSSE) {\n this.logger.info(`- SSE 端点: http://${this.host}:${this.port}/sse`);\n this.logger.info(\n `- 消息端点: http://${this.host}:${this.port}/messages`\n );\n }\n resolve();\n });\n\n this.server?.on(\"error\", (error) => {\n this.logger.error(\"HTTP 服务器错误\", error);\n this.setState(ConnectionState.ERROR);\n reject(error);\n });\n });\n }\n\n /**\n * 停止 HTTP 服务器\n */\n async stop(): Promise<void> {\n if (!this.server) {\n return;\n }\n\n this.logger.info(\"停止 HTTP 服务器\");\n\n return new Promise((resolve) => {\n // 关闭所有 SSE 连接\n for (const client of this.clients.values()) {\n client.response.end();\n }\n this.clients.clear();\n\n this.server!.close(() => {\n this.server = null;\n this.setState(ConnectionState.DISCONNECTED);\n this.logger.info(\"HTTP 服务器已停止\");\n resolve();\n });\n });\n }\n\n /**\n * 发送消息(对于 HTTP 适配器,这个方法主要用于 SSE)\n */\n async sendMessage(message: MCPMessage | MCPResponse): Promise<void> {\n // HTTP 适配器的消息发送主要通过 HTTP 响应或 SSE 推送\n // 这里实现 SSE 广播功能\n if (this.clients.size > 0) {\n this.broadcastToClients(message);\n }\n }\n\n /**\n * 设置中间件\n */\n private setupMiddleware(): void {\n // 解析 JSON 请求体\n this.app.use(express.json({ limit: \"10mb\" }));\n this.app.use(express.urlencoded({ extended: true }));\n\n // 设置 CORS\n this.app.use((req, res, next) => {\n res.header(\"Access-Control-Allow-Origin\", this.corsOrigin);\n res.header(\"Access-Control-Allow-Methods\", \"GET, POST, OPTIONS\");\n res.header(\"Access-Control-Allow-Headers\", \"Content-Type, Accept\");\n res.header(\"Cache-Control\", \"no-cache\");\n next();\n });\n\n // 请求日志\n this.app.use((req, res, next) => {\n this.logger.debug(`${req.method} ${req.path}`, {\n query: req.query,\n headers: req.headers,\n });\n next();\n });\n }\n\n /**\n * 设置路由\n */\n private setupRoutes(): void {\n // SSE 端点\n if (this.enableSSE) {\n this.app.get(\"/sse\", this.handleSSE.bind(this));\n this.app.post(\"/messages\", this.handleMessages.bind(this));\n }\n\n // RPC 端点\n if (this.enableRPC) {\n this.app.post(\"/rpc\", this.handleRPC.bind(this));\n }\n\n // 状态端点\n this.app.get(\"/status\", this.handleStatus.bind(this));\n\n // 健康检查端点\n this.app.get(\"/health\", this.handleHealth.bind(this));\n }\n\n /**\n * 处理 SSE 连接\n */\n private handleSSE(req: Request, res: Response): void {\n // 检查客户端数量限制\n if (this.clients.size >= this.maxClients) {\n res.status(503).json({\n error: \"服务器繁忙,客户端连接数已达上限\",\n maxClients: this.maxClients,\n });\n return;\n }\n\n const clientId = Date.now().toString();\n const sessionId = randomUUID();\n\n // 设置 SSE 头部\n res.setHeader(\"Content-Type\", \"text/event-stream\");\n res.setHeader(\"Cache-Control\", \"no-cache, no-transform\");\n res.setHeader(\"Connection\", \"keep-alive\");\n res.setHeader(\"X-Accel-Buffering\", \"no\");\n\n // 注册客户端\n const client: SSEClient = {\n id: clientId,\n sessionId,\n response: res,\n connectedAt: new Date(),\n };\n\n this.clients.set(sessionId, client);\n this.logger.info(`SSE 客户端已连接: ${clientId} (会话: ${sessionId})`);\n\n // 发送端点事件(MCP SDK 标准)\n res.write(`event: endpoint\\ndata: /messages?sessionId=${sessionId}\\n\\n`);\n\n // 处理客户端断开连接\n req.on(\"close\", () => {\n this.clients.delete(sessionId);\n this.logger.info(\n `SSE 客户端已断开连接: ${clientId} (会话: ${sessionId})`\n );\n });\n\n // 处理连接错误\n req.on(\"error\", (error) => {\n this.logger.error(`SSE 客户端连接错误: ${clientId}`, error);\n this.clients.delete(sessionId);\n });\n }\n\n /**\n * 处理 SSE 消息\n */\n private async handleMessages(req: Request, res: Response): Promise<void> {\n try {\n const sessionId = req.query.sessionId as string;\n const message = req.body;\n\n this.logger.debug(`收到 SSE 消息 (会话: ${sessionId}):`, message);\n\n if (!sessionId || !this.clients.has(sessionId)) {\n res.status(400).json({\n jsonrpc: \"2.0\",\n error: {\n code: -32600,\n message: \"无效或缺少 sessionId\",\n },\n id: message.id,\n });\n return;\n }\n\n // 处理消息\n const response = await this.messageHandler.handleMessage(message);\n this.logger.debug(\"SSE 消息处理响应:\", response);\n\n // 通过 SSE 发送响应\n const client = this.clients.get(sessionId);\n if (client) {\n this.sendToClient(client, response);\n }\n\n // 发送 202 Accepted 确认\n res.status(202).send();\n } catch (error) {\n this.logger.error(\"处理 SSE 消息时出错\", error);\n res.status(500).json({\n jsonrpc: \"2.0\",\n error: {\n code: -32603,\n message: (error as Error).message,\n },\n });\n }\n }\n\n /**\n * 处理 RPC 请求\n */\n private async handleRPC(req: Request, res: Response): Promise<void> {\n try {\n const message = req.body;\n this.logger.debug(\"收到 RPC 消息:\", message);\n\n // 处理消息\n const response = await this.messageHandler.handleMessage(message);\n res.json(response);\n } catch (error) {\n this.logger.error(\"处理 RPC 消息时出错\", error);\n res.status(500).json({\n jsonrpc: \"2.0\",\n error: {\n code: -32603,\n message: (error as Error).message,\n },\n id: req.body?.id || null,\n });\n }\n }\n\n /**\n * 处理状态请求\n */\n private handleStatus(req: Request, res: Response): void {\n res.json({\n status: \"ok\",\n mode: \"mcp-server\", // 从用户角度看,这是 MCP 服务器的状态\n serviceManager: \"running\", // 添加服务管理器状态\n clients: this.clients.size,\n tools: 0, // 工具数量,这里先设为0,后续可以从消息处理器获取\n maxClients: this.maxClients,\n enableSSE: this.enableSSE,\n enableRPC: this.enableRPC,\n uptime: process.uptime(),\n });\n }\n\n /**\n * 处理健康检查\n */\n private handleHealth(req: Request, res: Response): void {\n res.json({\n status: \"ok\",\n mode: \"mcp-server\", // 从用户角度看,这是 MCP 服务器的健康状态\n timestamp: new Date().toISOString(),\n });\n }\n\n /**\n * 向特定客户端发送消息\n */\n private sendToClient(\n client: SSEClient,\n message: MCPMessage | MCPResponse\n ): void {\n try {\n const data = this.serializeMessage(message);\n client.response.write(`data: ${data}\\n\\n`);\n\n this.logger.debug(`消息已发送到客户端 ${client.id}`, {\n sessionId: client.sessionId,\n messageId: message.id,\n });\n } catch (error) {\n this.logger.error(`向客户端 ${client.id} 发送消息失败`, error);\n // 移除有问题的客户端\n this.clients.delete(client.sessionId);\n }\n }\n\n /**\n * 广播消息到所有客户端\n */\n private broadcastToClients(message: MCPMessage | MCPResponse): void {\n for (const client of this.clients.values()) {\n this.sendToClient(client, message);\n }\n }\n\n /**\n * 获取适配器状态\n */\n getStatus(): {\n isRunning: boolean;\n port: number;\n host: string;\n clientCount: number;\n maxClients: number;\n enableSSE: boolean;\n enableRPC: boolean;\n connectionId: string;\n state: ConnectionState;\n } {\n return {\n isRunning: this.server !== null,\n port: this.port,\n host: this.host,\n clientCount: this.clients.size,\n maxClients: this.maxClients,\n enableSSE: this.enableSSE,\n enableRPC: this.enableRPC,\n connectionId: this.connectionId,\n state: this.state,\n };\n }\n\n /**\n * 获取连接的客户端列表\n */\n getClients(): Array<{\n id: string;\n sessionId: string;\n connectedAt: Date;\n }> {\n return Array.from(this.clients.values()).map((client) => ({\n id: client.id,\n sessionId: client.sessionId,\n connectedAt: client.connectedAt,\n }));\n }\n}\n","/**\n * Stdio 传输适配器\n * 处理通过标准输入输出进行的 MCP 通信,主要用于 Cursor 等客户端\n * 从 mcpServerProxy.ts 中抽取的 stdio 处理逻辑\n */\n\nimport type { MCPMessageHandler } from \"../core/MCPMessageHandler.js\";\nimport { ConnectionState, TransportAdapter } from \"./TransportAdapter.js\";\nimport type {\n MCPMessage,\n MCPResponse,\n TransportConfig,\n} from \"./TransportAdapter.js\";\n\n/**\n * Stdio 适配器配置\n */\nexport interface StdioConfig extends TransportConfig {\n encoding?: BufferEncoding;\n bufferSize?: number;\n}\n\n/**\n * Stdio 传输适配器实现\n * 处理标准输入输出的 JSON-RPC 消息通信\n */\nexport class StdioAdapter extends TransportAdapter {\n private messageBuffer = \"\";\n private isRunning = false;\n private encoding: BufferEncoding;\n private bufferSize: number;\n\n constructor(\n messageHandler: MCPMessageHandler,\n config: StdioConfig = { name: \"stdio\" }\n ) {\n super(messageHandler, config);\n this.encoding = config.encoding || \"utf8\";\n this.bufferSize = config.bufferSize || 1024 * 1024; // 1MB default buffer\n }\n\n /**\n * 初始化 Stdio 适配器\n */\n async initialize(): Promise<void> {\n this.logger.info(\"初始化 Stdio 适配器\");\n\n try {\n // 设置标准输入编码\n process.stdin.setEncoding(this.encoding);\n\n // 设置进程退出处理\n this.setupProcessHandlers();\n\n this.setState(ConnectionState.CONNECTING);\n this.logger.info(\"Stdio 适配器初始化完成\");\n } catch (error) {\n this.logger.error(\"Stdio 适配器初始化失败\", error);\n this.setState(ConnectionState.ERROR);\n throw error;\n }\n }\n\n /**\n * 启动 Stdio 适配器\n */\n async start(): Promise<void> {\n if (this.isRunning) {\n this.logger.warn(\"Stdio 适配器已在运行\");\n return;\n }\n\n this.logger.info(\"启动 Stdio 适配器\");\n\n try {\n this.isRunning = true;\n this.setupStdioHandlers();\n this.setState(ConnectionState.CONNECTED);\n\n this.logger.info(\"Stdio 适配器启动成功,等待消息...\");\n } catch (error) {\n this.logger.error(\"启动 Stdio 适配器失败\", error);\n this.setState(ConnectionState.ERROR);\n this.isRunning = false;\n throw error;\n }\n }\n\n /**\n * 停止 Stdio 适配器\n */\n async stop(): Promise<void> {\n if (!this.isRunning) {\n return;\n }\n\n this.logger.info(\"停止 Stdio 适配器\");\n\n try {\n this.isRunning = false;\n this.removeStdioHandlers();\n this.setState(ConnectionState.DISCONNECTED);\n\n this.logger.info(\"Stdio 适配器已停止\");\n } catch (error) {\n this.logger.error(\"停止 Stdio 适配器时出错\", error);\n throw error;\n }\n }\n\n /**\n * 发送消息到标准输出\n */\n async sendMessage(message: MCPMessage | MCPResponse): Promise<void> {\n try {\n const serializedMessage = this.serializeMessage(message);\n\n // 写入到标准输出,添加换行符\n process.stdout.write(`${serializedMessage}\\n`);\n\n this.logger.debug(\"消息已发送到 stdout\", {\n messageId: message.id,\n method: \"method\" in message ? message.method : \"response\",\n });\n } catch (error) {\n this.logger.error(\"发送消息失败\", error);\n throw error;\n }\n }\n\n /**\n * 设置标准输入输出处理器\n */\n private setupStdioHandlers(): void {\n // 处理标准输入数据\n process.stdin.on(\"data\", this.handleStdinData.bind(this));\n\n // 处理标准输入结束\n process.stdin.on(\"end\", this.handleStdinEnd.bind(this));\n\n // 处理标准输入错误\n process.stdin.on(\"error\", this.handleStdinError.bind(this));\n }\n\n /**\n * 移除标准输入输出处理器\n */\n private removeStdioHandlers(): void {\n process.stdin.removeListener(\"data\", this.handleStdinData.bind(this));\n process.stdin.removeListener(\"end\", this.handleStdinEnd.bind(this));\n process.stdin.removeListener(\"error\", this.handleStdinError.bind(this));\n }\n\n /**\n * 处理标准输入数据\n */\n private async handleStdinData(data: Buffer | string): Promise<void> {\n try {\n // 将数据添加到缓冲区\n this.messageBuffer += data.toString();\n\n // 检查缓冲区大小\n if (this.messageBuffer.length > this.bufferSize) {\n this.logger.warn(\n `消息缓冲区超过限制 (${this.bufferSize} bytes),清空缓冲区`\n );\n this.messageBuffer = \"\";\n return;\n }\n\n // 按换行符分割消息\n const lines = this.messageBuffer.split(\"\\n\");\n\n // 保留最后一个不完整的行在缓冲区中\n this.messageBuffer = lines.pop() || \"\";\n\n // 处理完整的消息行\n for (const line of lines) {\n const trimmedLine = line.trim();\n if (trimmedLine) {\n await this.processMessageLine(trimmedLine);\n }\n }\n } catch (error) {\n this.logger.error(\"处理 stdin 数据时出错\", error);\n }\n }\n\n /**\n * 处理单行消息\n */\n private async processMessageLine(line: string): Promise<void> {\n try {\n this.logger.debug(`处理消息行: ${line.substring(0, 200)}...`);\n\n const message = this.parseMessage(line);\n if (message) {\n await this.handleIncomingMessage(message);\n }\n } catch (error) {\n this.logger.error(`处理消息行失败: ${line.substring(0, 100)}...`, error);\n\n // 发送错误响应\n const errorResponse: MCPResponse = {\n jsonrpc: \"2.0\",\n error: {\n code: -32700,\n message: \"解析错误\",\n data: { originalLine: line.substring(0, 100) },\n },\n id: null,\n };\n\n await this.sendMessage(errorResponse);\n }\n }\n\n /**\n * 处理标准输入结束\n */\n private handleStdinEnd(): void {\n this.logger.info(\"标准输入已关闭,停止适配器\");\n this.stop().catch((error) => {\n this.logger.error(\"停止适配器时出错\", error);\n });\n }\n\n /**\n * 处理标准输入错误\n */\n private handleStdinError(error: Error): void {\n this.logger.error(\"标准输入错误\", error);\n this.setState(ConnectionState.ERROR);\n }\n\n /**\n * 设置进程处理器\n */\n private setupProcessHandlers(): void {\n // 处理进程退出信号\n const handleExit = () => {\n this.logger.info(\"收到退出信号,清理资源\");\n this.stop().finally(() => {\n process.exit(0);\n });\n };\n\n process.on(\"SIGINT\", handleExit);\n process.on(\"SIGTERM\", handleExit);\n\n // 处理未捕获的异常\n process.on(\"uncaughtException\", (error) => {\n this.logger.error(\"未捕获的异常\", error);\n this.setState(ConnectionState.ERROR);\n });\n\n // 处理未处理的 Promise 拒绝\n process.on(\"unhandledRejection\", (reason, promise) => {\n this.logger.error(\"未处理的 Promise 拒绝\", { reason, promise });\n });\n }\n\n /**\n * 获取适配器状态信息\n */\n getStatus(): {\n isRunning: boolean;\n bufferSize: number;\n encoding: string;\n connectionId: string;\n state: ConnectionState;\n } {\n return {\n isRunning: this.isRunning,\n bufferSize: this.messageBuffer.length,\n encoding: this.encoding,\n connectionId: this.connectionId,\n state: this.state,\n };\n }\n\n /**\n * 清空消息缓冲区\n */\n clearBuffer(): void {\n this.messageBuffer = \"\";\n this.logger.debug(\"消息缓冲区已清空\");\n }\n}\n","/**\n * WebSocket 传输适配器\n * 阶段四重构:支持 WebSocket 双向通信和自动重连\n *\n * 主要功能:\n * 1. WebSocket 连接管理和自动重连\n * 2. 双向实时通信支持\n * 3. 连接池管理和性能优化\n * 4. 消息压缩和批量处理\n */\n\nimport WebSocket, { WebSocketServer } from \"ws\";\nimport type { MCPMessageHandler } from \"../core/MCPMessageHandler.js\";\nimport { ConnectionState, TransportAdapter } from \"./TransportAdapter.js\";\nimport type {\n MCPMessage,\n MCPResponse,\n TransportConfig,\n} from \"./TransportAdapter.js\";\n\n/**\n * WebSocket 连接状态枚举\n */\nexport enum WebSocketState {\n DISCONNECTED = \"disconnected\",\n CONNECTING = \"connecting\",\n CONNECTED = \"connected\",\n RECONNECTING = \"reconnecting\",\n FAILED = \"failed\",\n}\n\n/**\n * 重连配置接口\n */\nexport interface ReconnectOptions {\n enabled: boolean;\n maxAttempts: number;\n initialInterval: number;\n maxInterval: number;\n backoffStrategy: \"linear\" | \"exponential\" | \"fixed\";\n backoffMultiplier: number;\n timeout: number;\n jitter: boolean;\n}\n\n/**\n * WebSocket 适配器配置\n */\nexport interface WebSocketConfig extends TransportConfig {\n endpointUrl: string;\n mode?: \"client\" | \"server\";\n reconnect?: Partial<ReconnectOptions>;\n compression?: boolean;\n batchSize?: number;\n batchTimeout?: number;\n maxConnections?: number;\n}\n\n/**\n * 重连状态接口\n */\ninterface ReconnectState {\n attempts: number;\n nextInterval: number;\n timer: NodeJS.Timeout | null;\n lastError: Error | null;\n isManualDisconnect: boolean;\n}\n\n/**\n * 消息批处理队列项\n */\ninterface BatchQueueItem {\n message: MCPMessage | MCPResponse;\n timestamp: number;\n resolve: () => void;\n reject: (error: Error) => void;\n}\n\n/**\n * WebSocket 传输适配器实现\n * 支持客户端和服务器模式的 WebSocket 通信\n */\nexport class WebSocketAdapter extends TransportAdapter {\n private ws: WebSocket | null = null;\n private wsServer: WebSocketServer | null = null;\n private endpointUrl: string;\n private mode: \"client\" | \"server\";\n private wsState: WebSocketState = WebSocketState.DISCONNECTED;\n\n // 重连相关\n private reconnectOptions: ReconnectOptions;\n private reconnectState: ReconnectState;\n private connectionTimeout: NodeJS.Timeout | null = null;\n\n // 性能优化相关\n private compression: boolean;\n private batchQueue: BatchQueueItem[] = [];\n private batchTimer: NodeJS.Timeout | null = null;\n private batchSize: number;\n private batchTimeout: number;\n\n // 连接池管理\n private connections: Map<string, WebSocket> = new Map();\n private maxConnections: number;\n\n constructor(messageHandler: MCPMessageHandler, config: WebSocketConfig) {\n super(messageHandler, config);\n\n this.endpointUrl = config.endpointUrl;\n this.mode = config.mode || \"client\";\n this.compression = config.compression || false;\n this.batchSize = config.batchSize || 10;\n this.batchTimeout = config.batchTimeout || 100;\n this.maxConnections = config.maxConnections || 100;\n\n // 初始化重连配置\n this.reconnectOptions = {\n enabled: true,\n maxAttempts: 5,\n initialInterval: 1000,\n maxInterval: 30000,\n backoffStrategy: \"exponential\",\n backoffMultiplier: 1.5,\n timeout: 10000,\n jitter: true,\n ...config.reconnect,\n };\n\n // 初始化重连状态\n this.reconnectState = {\n attempts: 0,\n nextInterval: this.reconnectOptions.initialInterval,\n timer: null,\n lastError: null,\n isManualDisconnect: false,\n };\n }\n\n /**\n * 初始化 WebSocket 适配器\n */\n async initialize(): Promise<void> {\n this.logger.info(`初始化 WebSocket 适配器 (${this.mode} 模式)`);\n\n try {\n this.setState(ConnectionState.CONNECTING);\n this.wsState = WebSocketState.CONNECTING;\n\n if (this.mode === \"client\") {\n await this.initializeClient();\n } else {\n await this.initializeServer();\n }\n\n this.logger.info(\"WebSocket 适配器初始化完成\");\n } catch (error) {\n this.logger.error(\"WebSocket 适配器初始化失败\", error);\n this.setState(ConnectionState.ERROR);\n this.wsState = WebSocketState.FAILED;\n throw error;\n }\n }\n\n /**\n * 初始化客户端模式\n */\n private async initializeClient(): Promise<void> {\n return new Promise((resolve, reject) => {\n // 设置连接超时\n this.connectionTimeout = setTimeout(() => {\n const error = new Error(\n `连接超时 (${this.reconnectOptions.timeout}ms)`\n );\n this.handleConnectionError(error);\n reject(error);\n }, this.reconnectOptions.timeout);\n\n this.ws = new WebSocket(this.endpointUrl);\n\n // 启用压缩\n if (this.compression) {\n // WebSocket 压缩扩展会自动处理\n }\n\n this.ws.on(\"open\", () => {\n this.handleConnectionSuccess();\n resolve();\n });\n\n this.ws.on(\"message\", (data) => {\n this.handleIncomingData(data);\n });\n\n this.ws.on(\"close\", (code, reason) => {\n this.handleConnectionClose(code, reason.toString());\n });\n\n this.ws.on(\"error\", (error) => {\n this.handleConnectionError(error);\n reject(error);\n });\n });\n }\n\n /**\n * 初始化服务器模式\n */\n private async initializeServer(): Promise<void> {\n return new Promise((resolve, reject) => {\n try {\n const url = new URL(this.endpointUrl);\n const port = Number.parseInt(url.port) || 8080;\n\n this.wsServer = new WebSocketServer({\n port,\n perMessageDeflate: this.compression,\n });\n\n this.wsServer.on(\"connection\", (ws, request) => {\n this.handleNewConnection(ws, request);\n });\n\n this.wsServer.on(\"error\", (error) => {\n this.logger.error(\"WebSocket 服务器错误\", error);\n reject(error);\n });\n\n this.logger.info(`WebSocket 服务器监听端口 ${port}`);\n resolve();\n } catch (error) {\n reject(error);\n }\n });\n }\n\n /**\n * 启动 WebSocket 适配器\n */\n async start(): Promise<void> {\n if (this.wsState === WebSocketState.CONNECTED) {\n this.logger.warn(\"WebSocket 适配器已启动\");\n return;\n }\n\n this.logger.info(\"启动 WebSocket 适配器\");\n\n try {\n this.setState(ConnectionState.CONNECTED);\n this.wsState = WebSocketState.CONNECTED;\n\n this.logger.info(\"WebSocket 适配器启动成功\");\n } catch (error) {\n this.logger.error(\"启动 WebSocket 适配器失败\", error);\n this.setState(ConnectionState.ERROR);\n this.wsState = WebSocketState.FAILED;\n throw error;\n }\n }\n\n /**\n * 停止 WebSocket 适配器\n */\n async stop(): Promise<void> {\n this.logger.info(\"停止 WebSocket 适配器\");\n\n try {\n // 标记为手动断开\n this.reconnectState.isManualDisconnect = true;\n\n // 清理重连定时器\n if (this.reconnectState.timer) {\n clearTimeout(this.reconnectState.timer);\n this.reconnectState.timer = null;\n }\n\n // 清理批处理定时器\n if (this.batchTimer) {\n clearTimeout(this.batchTimer);\n this.batchTimer = null;\n }\n\n // 处理剩余的批处理消息\n await this.flushBatchQueue();\n\n // 关闭客户端连接\n if (this.ws) {\n this.ws.close();\n this.ws = null;\n }\n\n // 关闭服务器\n if (this.wsServer) {\n this.wsServer.close();\n this.wsServer = null;\n }\n\n // 关闭所有连接\n for (const [id, connection] of this.connections) {\n connection.close();\n }\n this.connections.clear();\n\n this.setState(ConnectionState.DISCONNECTED);\n this.wsState = WebSocketState.DISCONNECTED;\n\n this.logger.info(\"WebSocket 适配器已停止\");\n } catch (error) {\n this.logger.error(\"停止 WebSocket 适配器时出错\", error);\n throw error;\n }\n }\n\n /**\n * 发送消息\n */\n async sendMessage(message: MCPMessage | MCPResponse): Promise<void> {\n if (this.wsState !== WebSocketState.CONNECTED) {\n throw new Error(`WebSocket 未连接 (状态: ${this.wsState})`);\n }\n\n // 如果启用了批处理,添加到队列\n if (this.batchSize > 1) {\n return this.addToBatchQueue(message);\n }\n\n // 直接发送\n return this.sendMessageDirect(message);\n }\n\n /**\n * 直接发送消息\n */\n private async sendMessageDirect(\n message: MCPMessage | MCPResponse\n ): Promise<void> {\n try {\n const serializedMessage = this.serializeMessage(message);\n\n if (this.mode === \"client\" && this.ws) {\n this.ws.send(serializedMessage);\n } else if (this.mode === \"server\") {\n // 广播到所有连接\n for (const connection of this.connections.values()) {\n if (connection.readyState === WebSocket.OPEN) {\n connection.send(serializedMessage);\n }\n }\n }\n\n this.logger.debug(\"消息已发送\", {\n messageId: message.id,\n method: \"method\" in message ? message.method : \"response\",\n });\n } catch (error) {\n this.logger.error(\"发送消息失败\", error);\n throw error;\n }\n }\n\n /**\n * 添加消息到批处理队列\n */\n private async addToBatchQueue(\n message: MCPMessage | MCPResponse\n ): Promise<void> {\n return new Promise((resolve, reject) => {\n this.batchQueue.push({\n message,\n timestamp: Date.now(),\n resolve,\n reject,\n });\n\n // 如果队列达到批处理大小,立即处理\n if (this.batchQueue.length >= this.batchSize) {\n this.flushBatchQueue();\n } else if (!this.batchTimer) {\n // 设置批处理超时\n this.batchTimer = setTimeout(() => {\n this.flushBatchQueue();\n }, this.batchTimeout);\n }\n });\n }\n\n /**\n * 刷新批处理队列\n */\n private async flushBatchQueue(): Promise<void> {\n if (this.batchQueue.length === 0) {\n return;\n }\n\n // 清理定时器\n if (this.batchTimer) {\n clearTimeout(this.batchTimer);\n this.batchTimer = null;\n }\n\n const batch = this.batchQueue.splice(0);\n\n try {\n // 批量发送消息\n const messages = batch.map((item) => item.message);\n const batchMessage = {\n jsonrpc: \"2.0\" as const,\n method: \"batch\",\n params: { messages },\n id: `batch_${Date.now()}`,\n };\n\n await this.sendMessageDirect(batchMessage);\n\n // 解析所有 Promise\n for (const item of batch) {\n item.resolve();\n }\n\n this.logger.debug(`批处理发送 ${batch.length} 条消息`);\n } catch (error) {\n // 拒绝所有 Promise\n for (const item of batch) {\n item.reject(error as Error);\n }\n this.logger.error(\"批处理发送失败\", error);\n }\n }\n\n /**\n * 处理接收到的数据\n */\n private async handleIncomingData(data: WebSocket.Data): Promise<void> {\n try {\n const messageStr = data.toString();\n const message = this.parseMessage(messageStr);\n\n if (message) {\n // 检查是否是批处理消息\n if (message.method === \"batch\" && message.params?.messages) {\n // 处理批处理消息\n for (const batchedMessage of message.params.messages) {\n await this.handleIncomingMessage(batchedMessage);\n }\n } else {\n await this.handleIncomingMessage(message);\n }\n }\n } catch (error) {\n this.logger.error(\"处理接收数据失败\", error);\n }\n }\n\n /**\n * 处理连接成功\n */\n private handleConnectionSuccess(): void {\n // 清理连接超时定时器\n if (this.connectionTimeout) {\n clearTimeout(this.connectionTimeout);\n this.connectionTimeout = null;\n }\n\n this.setState(ConnectionState.CONNECTED);\n this.wsState = WebSocketState.CONNECTED;\n\n // 重置重连状态\n this.reconnectState.attempts = 0;\n this.reconnectState.nextInterval = this.reconnectOptions.initialInterval;\n this.reconnectState.lastError = null;\n\n this.logger.info(\"WebSocket 连接已建立\");\n }\n\n /**\n * 处理连接错误\n */\n private handleConnectionError(error: Error): void {\n // 清理连接超时定时器\n if (this.connectionTimeout) {\n clearTimeout(this.connectionTimeout);\n this.connectionTimeout = null;\n }\n\n this.reconnectState.lastError = error;\n this.logger.error(\"WebSocket 连接错误\", error);\n\n this.setState(ConnectionState.ERROR);\n this.wsState = WebSocketState.FAILED;\n\n // 清理当前连接\n this.cleanupConnection();\n }\n\n /**\n * 处理连接关闭\n */\n private handleConnectionClose(code: number, reason: string): void {\n this.setState(ConnectionState.DISCONNECTED);\n this.wsState = WebSocketState.DISCONNECTED;\n\n this.logger.info(`WebSocket 连接已关闭 (代码: ${code}, 原因: ${reason})`);\n\n // 如果是手动断开,不进行重连\n if (this.reconnectState.isManualDisconnect) {\n return;\n }\n\n // 检查是否需要重连\n if (this.shouldReconnect()) {\n this.scheduleReconnect();\n } else {\n this.wsState = WebSocketState.FAILED;\n this.logger.warn(\n `已达到最大重连次数 (${this.reconnectOptions.maxAttempts}),停止重连`\n );\n }\n }\n\n /**\n * 处理新连接(服务器模式)\n */\n private handleNewConnection(ws: WebSocket, request: any): void {\n // 检查连接数限制\n if (this.connections.size >= this.maxConnections) {\n this.logger.warn(\"达到最大连接数限制,拒绝新连接\");\n ws.close(1013, \"服务器繁忙\");\n return;\n }\n\n const connectionId = `${this.getConnectionId()}_${this.connections.size}`;\n this.connections.set(connectionId, ws);\n\n this.logger.info(`新 WebSocket 连接: ${connectionId}`);\n\n ws.on(\"message\", (data) => {\n this.handleIncomingData(data);\n });\n\n ws.on(\"close\", () => {\n this.connections.delete(connectionId);\n this.logger.info(`WebSocket 连接已断开: ${connectionId}`);\n });\n\n ws.on(\"error\", (error) => {\n this.logger.error(`WebSocket 连接错误 ${connectionId}:`, error);\n this.connections.delete(connectionId);\n });\n }\n\n /**\n * 清理连接\n */\n private cleanupConnection(): void {\n if (this.ws) {\n this.ws.removeAllListeners();\n this.ws = null;\n }\n }\n\n /**\n * 检查是否应该重连\n */\n private shouldReconnect(): boolean {\n return (\n this.reconnectOptions.enabled &&\n this.reconnectState.attempts < this.reconnectOptions.maxAttempts &&\n !this.reconnectState.isManualDisconnect\n );\n }\n\n /**\n * 安排重连\n */\n private scheduleReconnect(): void {\n this.wsState = WebSocketState.RECONNECTING;\n this.reconnectState.attempts++;\n\n // 计算重连间隔\n let interval = this.calculateReconnectInterval();\n\n // 添加随机抖动\n if (this.reconnectOptions.jitter) {\n interval += Math.random() * 1000;\n }\n\n this.logger.info(\n `安排重连 (第 ${this.reconnectState.attempts} 次,${interval}ms 后)`\n );\n\n this.reconnectState.timer = setTimeout(async () => {\n try {\n await this.initializeClient();\n } catch (error) {\n this.logger.error(\"重连失败\", error);\n\n if (this.shouldReconnect()) {\n this.scheduleReconnect();\n } else {\n this.wsState = WebSocketState.FAILED;\n }\n }\n }, interval);\n }\n\n /**\n * 计算重连间隔\n */\n private calculateReconnectInterval(): number {\n const { backoffStrategy, initialInterval, maxInterval, backoffMultiplier } =\n this.reconnectOptions;\n const attempts = this.reconnectState.attempts;\n\n let interval: number;\n\n switch (backoffStrategy) {\n case \"linear\":\n interval = initialInterval + attempts * 1000;\n break;\n case \"exponential\":\n interval = initialInterval * backoffMultiplier ** attempts;\n break;\n default:\n interval = initialInterval;\n break;\n }\n\n return Math.min(interval, maxInterval);\n }\n\n /**\n * 获取适配器状态\n */\n getStatus(): {\n wsState: WebSocketState;\n connectionState: ConnectionState;\n mode: string;\n endpointUrl: string;\n connectionCount: number;\n reconnectAttempts: number;\n batchQueueSize: number;\n compression: boolean;\n } {\n return {\n wsState: this.wsState,\n connectionState: this.state,\n mode: this.mode,\n endpointUrl: this.endpointUrl,\n connectionCount: this.connections.size,\n reconnectAttempts: this.reconnectState.attempts,\n batchQueueSize: this.batchQueue.length,\n compression: this.compression,\n };\n }\n\n /**\n * 强制重连\n */\n async forceReconnect(): Promise<void> {\n if (this.mode !== \"client\") {\n throw new Error(\"只有客户端模式支持重连\");\n }\n\n this.logger.info(\"强制重连\");\n\n // 重置重连状态\n this.reconnectState.attempts = 0;\n this.reconnectState.isManualDisconnect = false;\n\n // 关闭当前连接\n if (this.ws) {\n this.ws.close();\n }\n\n // 立即重连\n await this.initializeClient();\n }\n}\n","/**\n * 统一的 MCP 消息处理器\n * 负责处理所有 MCP 协议消息,包括 initialize、tools/list、tools/call 等\n * 这是阶段一重构的核心组件,用于消除双层代理架构\n */\n\nimport { type Logger, logger } from \"../Logger.js\";\nimport type { MCPServiceManager } from \"../services/MCPServiceManager.js\";\n\n// MCP 消息接口\ninterface MCPMessage {\n jsonrpc: \"2.0\";\n method: string;\n params?: any;\n id?: string | number;\n}\n\n// MCP 响应接口\ninterface MCPResponse {\n jsonrpc: \"2.0\";\n result?: any;\n error?: MCPError;\n id: string | number | null;\n}\n\n// MCP 错误接口\ninterface MCPError {\n code: number;\n message: string;\n data?: any;\n}\n\n// 初始化参数接口\ninterface InitializeParams {\n protocolVersion: string;\n capabilities: any;\n clientInfo: {\n name: string;\n version: string;\n };\n}\n\n// 工具调用参数接口\ninterface ToolCallParams {\n name: string;\n arguments?: any;\n}\n\nexport class MCPMessageHandler {\n private logger: Logger;\n private serviceManager: MCPServiceManager;\n\n constructor(serviceManager: MCPServiceManager) {\n this.serviceManager = serviceManager;\n this.logger = logger;\n }\n\n /**\n * 处理 MCP 消息的统一入口\n * @param message MCP 消息\n * @returns MCP 响应\n */\n async handleMessage(message: MCPMessage): Promise<MCPResponse> {\n this.logger.debug(`处理 MCP 消息: ${message.method}`, message);\n\n try {\n switch (message.method) {\n case \"initialize\":\n return await this.handleInitialize(message.params, message.id);\n case \"tools/list\":\n return await this.handleToolsList(message.id);\n case \"tools/call\":\n return await this.handleToolCall(message.params, message.id);\n case \"ping\":\n return await this.handlePing(message.id);\n default:\n throw new Error(`未知的方法: ${message.method}`);\n }\n } catch (error) {\n this.logger.error(`处理消息时出错: ${message.method}`, error);\n return this.createErrorResponse(error as Error, message.id);\n }\n }\n\n /**\n * 处理 initialize 请求\n * @param params 初始化参数\n * @param id 消息ID\n * @returns 初始化响应\n */\n private async handleInitialize(\n params: InitializeParams,\n id?: string | number\n ): Promise<MCPResponse> {\n this.logger.info(\"处理 initialize 请求\", params);\n\n return {\n jsonrpc: \"2.0\",\n result: {\n serverInfo: {\n name: \"xiaozhi-mcp-server\",\n version: \"1.0.0\",\n },\n capabilities: {\n tools: {},\n logging: {},\n },\n protocolVersion: \"2024-11-05\",\n },\n id: id || null,\n };\n }\n\n /**\n * 处理 tools/list 请求\n * @param id 消息ID\n * @returns 工具列表响应\n */\n private async handleToolsList(id?: string | number): Promise<MCPResponse> {\n this.logger.info(\"处理 tools/list 请求\");\n\n try {\n const tools = this.serviceManager.getAllTools();\n\n // 转换为 MCP 标准格式\n const mcpTools = tools.map((tool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema,\n }));\n\n this.logger.info(`返回 ${mcpTools.length} 个工具`);\n\n return {\n jsonrpc: \"2.0\",\n result: {\n tools: mcpTools,\n },\n id: id || null,\n };\n } catch (error) {\n this.logger.error(\"获取工具列表失败\", error);\n throw error;\n }\n }\n\n /**\n * 处理 tools/call 请求\n * @param params 工具调用参数\n * @param id 消息ID\n * @returns 工具调用响应\n */\n private async handleToolCall(\n params: ToolCallParams,\n id?: string | number\n ): Promise<MCPResponse> {\n this.logger.info(`处理 tools/call 请求: ${params.name}`, params);\n\n try {\n if (!params.name) {\n throw new Error(\"工具名称不能为空\");\n }\n\n const result = await this.serviceManager.callTool(\n params.name,\n params.arguments || {}\n );\n\n this.logger.info(`工具 ${params.name} 调用成功`);\n\n return {\n jsonrpc: \"2.0\",\n result: {\n content: result.content,\n isError: result.isError || false,\n },\n id: id || null,\n };\n } catch (error) {\n this.logger.error(`工具调用失败: ${params.name}`, error);\n throw error;\n }\n }\n\n /**\n * 处理 ping 请求\n * @param id 消息ID\n * @returns ping 响应\n */\n private async handlePing(id?: string | number): Promise<MCPResponse> {\n this.logger.debug(\"处理 ping 请求\");\n\n return {\n jsonrpc: \"2.0\",\n result: {\n status: \"ok\",\n timestamp: new Date().toISOString(),\n },\n id: id || null,\n };\n }\n\n /**\n * 创建错误响应\n * @param error 错误对象\n * @param id 消息ID\n * @returns 错误响应\n */\n private createErrorResponse(error: Error, id?: string | number): MCPResponse {\n // 根据错误类型确定错误代码\n let errorCode = -32603; // Internal error\n\n if (\n error.message.includes(\"未找到工具\") ||\n error.message.includes(\"未知的方法\")\n ) {\n errorCode = -32601; // Method not found\n } else if (\n error.message.includes(\"参数\") ||\n error.message.includes(\"不能为空\")\n ) {\n errorCode = -32602; // Invalid params\n }\n\n return {\n jsonrpc: \"2.0\",\n error: {\n code: errorCode,\n message: error.message,\n data: {\n stack: error.stack,\n },\n },\n id: id || null,\n };\n }\n\n /**\n * 获取服务管理器实例\n * @returns MCPServiceManager 实例\n */\n getServiceManager(): MCPServiceManager {\n return this.serviceManager;\n }\n}\n","/**\n * 统一 MCP 服务器\n * 阶段三重构:整合所有传输协议和服务管理的统一服务器实现\n *\n * 这是整个 MCP 系统的核心类,负责:\n * 1. 管理多种传输适配器(HTTP、Stdio、WebSocket等)\n * 2. 统一的工具注册和管理\n * 3. 连接生命周期管理\n * 4. 消息路由和处理\n */\n\nimport { EventEmitter } from \"node:events\";\nimport { type Logger, logger } from \"../Logger.js\";\nimport { MCPServiceManager } from \"../services/MCPServiceManager.js\";\nimport {\n ConnectionState,\n type TransportAdapter,\n} from \"../transports/TransportAdapter.js\";\nimport type {\n MCPMessage,\n MCPResponse,\n} from \"../transports/TransportAdapter.js\";\nimport { MCPMessageHandler } from \"./MCPMessageHandler.js\";\n\n/**\n * 工具信息接口\n */\nexport interface ToolInfo {\n name: string;\n description?: string;\n inputSchema?: any;\n serviceName: string;\n originalName: string;\n}\n\n/**\n * 连接信息接口\n */\nexport interface ConnectionInfo {\n id: string;\n transportName: string;\n state: ConnectionState;\n connectedAt: Date;\n lastActivity: Date;\n}\n\n/**\n * 服务器配置接口\n */\nexport interface UnifiedServerConfig {\n name?: string;\n enableLogging?: boolean;\n logLevel?: string;\n maxConnections?: number;\n connectionTimeout?: number;\n}\n\n/**\n * 简化的工具注册表\n * 基于现有的 MCPServiceManager 提供统一的工具管理接口\n */\nexport class ToolRegistry {\n private serviceManager: MCPServiceManager;\n private logger: Logger;\n\n constructor(serviceManager: MCPServiceManager) {\n this.serviceManager = serviceManager;\n this.logger = logger;\n }\n\n async initialize(): Promise<void> {\n this.logger.info(\"初始化工具注册表\");\n // 工具注册表的初始化由 MCPServiceManager 处理\n }\n\n /**\n * 获取所有工具\n */\n getAllTools(): ToolInfo[] {\n return this.serviceManager.getAllTools().map((tool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema,\n serviceName: tool.serviceName,\n originalName: tool.originalName,\n }));\n }\n\n /**\n * 查找工具\n */\n findTool(toolName: string): ToolInfo | null {\n const tools = this.getAllTools();\n return tools.find((tool) => tool.name === toolName) || null;\n }\n\n /**\n * 检查工具是否存在\n */\n hasTool(toolName: string): boolean {\n return this.findTool(toolName) !== null;\n }\n}\n\n/**\n * 简化的连接管理器\n * 管理传输适配器的连接状态和生命周期\n */\nexport class ConnectionManager extends EventEmitter {\n private connections: Map<string, ConnectionInfo> = new Map();\n private logger: Logger;\n\n constructor() {\n super();\n this.logger = logger;\n }\n\n async initialize(): Promise<void> {\n this.logger.info(\"初始化连接管理器\");\n }\n\n /**\n * 注册连接\n */\n registerConnection(\n id: string,\n transportName: string,\n state: ConnectionState\n ): void {\n const connectionInfo: ConnectionInfo = {\n id,\n transportName,\n state,\n connectedAt: new Date(),\n lastActivity: new Date(),\n };\n\n this.connections.set(id, connectionInfo);\n this.emit(\"connectionRegistered\", connectionInfo);\n this.logger.debug(`连接已注册: ${id} (${transportName})`);\n }\n\n /**\n * 更新连接状态\n */\n updateConnectionState(id: string, state: ConnectionState): void {\n const connection = this.connections.get(id);\n if (connection) {\n connection.state = state;\n connection.lastActivity = new Date();\n this.emit(\"connectionStateChanged\", connection);\n this.logger.debug(`连接状态更新: ${id} -> ${state}`);\n }\n }\n\n /**\n * 移除连接\n */\n removeConnection(id: string): void {\n const connection = this.connections.get(id);\n if (connection) {\n this.connections.delete(id);\n this.emit(\"connectionRemoved\", connection);\n this.logger.debug(`连接已移除: ${id}`);\n }\n }\n\n /**\n * 获取所有连接\n */\n getAllConnections(): ConnectionInfo[] {\n return Array.from(this.connections.values());\n }\n\n /**\n * 获取活跃连接数\n */\n getActiveConnectionCount(): number {\n return Array.from(this.connections.values()).filter(\n (conn) => conn.state === ConnectionState.CONNECTED\n ).length;\n }\n\n /**\n * 关闭所有连接\n */\n async closeAllConnections(): Promise<void> {\n this.logger.info(\"关闭所有连接\");\n this.connections.clear();\n this.emit(\"allConnectionsClosed\");\n }\n}\n\n/**\n * 统一 MCP 服务器\n * 整合所有传输协议和服务管理的核心服务器类\n */\nexport class UnifiedMCPServer extends EventEmitter {\n private serviceManager: MCPServiceManager;\n private messageHandler: MCPMessageHandler;\n private transportAdapters: Map<string, TransportAdapter> = new Map();\n private toolRegistry: ToolRegistry;\n private connectionManager: ConnectionManager;\n private isRunning = false;\n private logger: Logger;\n private config: UnifiedServerConfig;\n\n constructor(config: UnifiedServerConfig = {}) {\n super();\n\n this.config = {\n name: \"UnifiedMCPServer\",\n enableLogging: true,\n logLevel: \"info\",\n maxConnections: 100,\n connectionTimeout: 30000,\n ...config,\n };\n\n this.logger = logger;\n\n // 初始化核心组件\n this.serviceManager = new MCPServiceManager();\n this.messageHandler = new MCPMessageHandler(this.serviceManager);\n this.toolRegistry = new ToolRegistry(this.serviceManager);\n this.connectionManager = new ConnectionManager();\n\n // 设置事件监听\n this.setupEventListeners();\n }\n\n /**\n * 设置事件监听器\n */\n private setupEventListeners(): void {\n // 监听连接管理器事件\n this.connectionManager.on(\n \"connectionRegistered\",\n (connection: ConnectionInfo) => {\n this.emit(\"connectionRegistered\", connection);\n }\n );\n\n this.connectionManager.on(\n \"connectionStateChanged\",\n (connection: ConnectionInfo) => {\n this.emit(\"connectionStateChanged\", connection);\n }\n );\n\n this.connectionManager.on(\n \"connectionRemoved\",\n (connection: ConnectionInfo) => {\n this.emit(\"connectionRemoved\", connection);\n }\n );\n }\n\n /**\n * 初始化服务器\n */\n async initialize(): Promise<void> {\n this.logger.info(\"初始化统一 MCP 服务器\");\n\n try {\n // 初始化核心组件\n await this.serviceManager.startAllServices();\n await this.toolRegistry.initialize();\n await this.connectionManager.initialize();\n\n this.logger.info(\"统一 MCP 服务器初始化完成\");\n this.emit(\"initialized\");\n } catch (error) {\n this.logger.error(\"统一 MCP 服务器初始化失败\", error);\n throw error;\n }\n }\n\n /**\n * 注册传输适配器\n */\n async registerTransport(\n name: string,\n adapter: TransportAdapter\n ): Promise<void> {\n if (this.transportAdapters.has(name)) {\n throw new Error(`传输适配器 ${name} 已存在`);\n }\n\n this.logger.info(`注册传输适配器: ${name}`);\n\n try {\n // 初始化适配器\n await adapter.initialize();\n\n // 注册适配器\n this.transportAdapters.set(name, adapter);\n\n // 注册连接到连接管理器\n this.connectionManager.registerConnection(\n adapter.getConnectionId(),\n name,\n adapter.getState()\n );\n\n this.logger.info(`传输适配器 ${name} 注册成功`);\n this.emit(\"transportRegistered\", { name, adapter });\n } catch (error) {\n this.logger.error(`注册传输适配器 ${name} 失败`, error);\n throw error;\n }\n }\n\n /**\n * 启动服务器\n */\n async start(): Promise<void> {\n if (this.isRunning) {\n throw new Error(\"服务器已在运行\");\n }\n\n this.logger.info(\"启动统一 MCP 服务器\");\n\n try {\n // 启动所有传输适配器\n for (const [name, adapter] of this.transportAdapters) {\n try {\n await adapter.start();\n\n // 更新连接状态\n this.connectionManager.updateConnectionState(\n adapter.getConnectionId(),\n adapter.getState()\n );\n\n this.logger.info(`传输适配器 ${name} 启动成功`);\n } catch (error) {\n this.logger.error(`传输适配器 ${name} 启动失败`, error);\n throw error;\n }\n }\n\n this.isRunning = true;\n this.logger.info(\"统一 MCP 服务器启动成功\");\n this.emit(\"started\");\n } catch (error) {\n this.logger.error(\"统一 MCP 服务器启动失败\", error);\n throw error;\n }\n }\n\n /**\n * 停止服务器\n */\n async stop(): Promise<void> {\n if (!this.isRunning) {\n return;\n }\n\n this.logger.info(\"停止统一 MCP 服务器\");\n\n try {\n // 停止所有传输适配器\n for (const [name, adapter] of this.transportAdapters) {\n try {\n await adapter.stop();\n\n // 更新连接状态\n this.connectionManager.updateConnectionState(\n adapter.getConnectionId(),\n adapter.getState()\n );\n\n this.logger.info(`传输适配器 ${name} 停止成功`);\n } catch (error) {\n this.logger.error(`传输适配器 ${name} 停止失败`, error);\n }\n }\n\n // 关闭所有连接\n await this.connectionManager.closeAllConnections();\n\n // 停止服务管理器\n await this.serviceManager.stopAllServices();\n\n this.isRunning = false;\n this.logger.info(\"统一 MCP 服务器停止成功\");\n this.emit(\"stopped\");\n } catch (error) {\n this.logger.error(\"统一 MCP 服务器停止失败\", error);\n throw error;\n }\n }\n\n /**\n * 获取服务管理器\n */\n getServiceManager(): MCPServiceManager {\n return this.serviceManager;\n }\n\n /**\n * 获取工具注册表\n */\n getToolRegistry(): ToolRegistry {\n return this.toolRegistry;\n }\n\n /**\n * 获取连接管理器\n */\n getConnectionManager(): ConnectionManager {\n return this.connectionManager;\n }\n\n /**\n * 获取消息处理器\n */\n getMessageHandler(): MCPMessageHandler {\n return this.messageHandler;\n }\n\n /**\n * 获取服务器状态\n */\n getStatus(): {\n isRunning: boolean;\n transportCount: number;\n activeConnections: number;\n toolCount: number;\n config: UnifiedServerConfig;\n } {\n return {\n isRunning: this.isRunning,\n transportCount: this.transportAdapters.size,\n activeConnections: this.connectionManager.getActiveConnectionCount(),\n toolCount: this.toolRegistry.getAllTools().length,\n config: this.config,\n };\n }\n\n /**\n * 获取所有传输适配器\n */\n getTransportAdapters(): Map<string, TransportAdapter> {\n return new Map(this.transportAdapters);\n }\n\n /**\n * 检查服务器是否正在运行\n */\n isServerRunning(): boolean {\n return this.isRunning;\n }\n}\n","/**\n * MCP 服务器工厂\n * 阶段三重构:支持多种传输协议的自动选择和服务器创建\n *\n * 主要功能:\n * 1. 根据环境自动选择合适的传输协议\n * 2. 创建和配置 UnifiedMCPServer 实例\n * 3. 注册和管理传输适配器\n * 4. 提供便捷的服务器创建方法\n */\n\nimport { logger } from \"../Logger.js\";\nimport { HTTPAdapter, type HTTPConfig } from \"../transports/HTTPAdapter.js\";\nimport { StdioAdapter, type StdioConfig } from \"../transports/StdioAdapter.js\";\nimport { TransportAdapter } from \"../transports/TransportAdapter.js\";\nimport {\n WebSocketAdapter,\n type WebSocketConfig,\n} from \"../transports/WebSocketAdapter.js\";\nimport type { MCPMessageHandler } from \"./MCPMessageHandler.js\";\nimport {\n UnifiedMCPServer,\n type UnifiedServerConfig,\n} from \"./UnifiedMCPServer.js\";\n\n/**\n * 服务器模式枚举\n */\nexport enum ServerMode {\n STDIO = \"stdio\", // 标准输入输出模式(Cursor 等客户端)\n HTTP = \"http\", // HTTP 服务器模式(Web 客户端)\n WEBSOCKET = \"websocket\", // WebSocket 模式(实时双向通信)\n HYBRID = \"hybrid\", // 混合模式(同时支持多种传输)\n AUTO = \"auto\", // 自动检测模式\n}\n\n/**\n * 服务器工厂配置\n */\nexport interface ServerFactoryConfig {\n mode?: ServerMode;\n serverConfig?: UnifiedServerConfig;\n stdioConfig?: StdioConfig;\n httpConfig?: HTTPConfig;\n websocketConfig?: WebSocketConfig;\n autoDetect?: {\n checkStdin?: boolean;\n checkEnvironment?: boolean;\n defaultMode?: ServerMode;\n };\n}\n\n/**\n * 环境检测结果\n */\ninterface EnvironmentDetection {\n hasStdin: boolean;\n isInteractive: boolean;\n hasPort: boolean;\n suggestedMode: ServerMode;\n reasons: string[];\n}\n\n// 使用全局 logger 实例\n\n/**\n * 创建 MCP 服务器\n * 根据配置或环境自动选择合适的传输协议\n */\nexport async function createServer(\n config: ServerFactoryConfig = {}\n): Promise<UnifiedMCPServer> {\n logger.info(\"[ServerFactory] 开始创建 MCP 服务器\", config);\n\n try {\n // 确定服务器模式\n const mode = await determineServerMode(config);\n logger.info(`[ServerFactory] 确定服务器模式: ${mode}`);\n\n // 创建统一服务器实例\n const server = new UnifiedMCPServer(config.serverConfig);\n await server.initialize();\n\n // 根据模式注册传输适配器\n await registerTransportsForMode(server, mode, config);\n\n logger.info(\"[ServerFactory] MCP 服务器创建成功\");\n return server;\n } catch (error) {\n logger.error(\"[ServerFactory] 创建 MCP 服务器失败\", error);\n throw error;\n }\n}\n\n/**\n * 创建 Stdio 模式服务器\n * 专门用于 Cursor 等客户端的标准输入输出通信\n */\nexport async function createStdioServer(\n config: StdioConfig = { name: \"stdio\" }\n): Promise<UnifiedMCPServer> {\n logger.info(\"[ServerFactory] 创建 Stdio 模式服务器\");\n\n const server = new UnifiedMCPServer();\n await server.initialize();\n\n const messageHandler = server.getMessageHandler();\n const stdioAdapter = new StdioAdapter(messageHandler, config);\n\n await server.registerTransport(\"stdio\", stdioAdapter);\n\n logger.info(\"[ServerFactory] Stdio 模式服务器创建成功\");\n return server;\n}\n\n/**\n * 创建 HTTP 模式服务器\n * 专门用于 Web 客户端的 HTTP/SSE 通信\n */\nexport async function createHTTPServer(\n config: HTTPConfig = { name: \"http\" }\n): Promise<UnifiedMCPServer> {\n logger.info(\"创建 HTTP 模式服务器\");\n\n const server = new UnifiedMCPServer();\n await server.initialize();\n\n const messageHandler = server.getMessageHandler();\n const httpAdapter = new HTTPAdapter(messageHandler, config);\n\n await server.registerTransport(\"http\", httpAdapter);\n\n logger.info(\"HTTP 模式服务器创建成功\");\n return server;\n}\n\n/**\n * 创建 WebSocket 模式服务器\n * 专门用于实时双向通信\n */\nexport async function createWebSocketServer(\n config: WebSocketConfig = {\n name: \"websocket\",\n endpointUrl: \"ws://localhost:8080\",\n }\n): Promise<UnifiedMCPServer> {\n logger.info(\"创建 WebSocket 模式服务器\");\n\n const server = new UnifiedMCPServer();\n await server.initialize();\n\n const messageHandler = server.getMessageHandler();\n const wsAdapter = new WebSocketAdapter(messageHandler, config);\n\n await server.registerTransport(\"websocket\", wsAdapter);\n\n logger.info(\"WebSocket 模式服务器创建成功\");\n return server;\n}\n\n/**\n * 创建混合模式服务器\n * 同时支持多种传输协议\n */\nexport async function createHybridServer(\n stdioConfig: StdioConfig = { name: \"stdio\" },\n httpConfig: HTTPConfig = { name: \"http\" },\n websocketConfig?: WebSocketConfig\n): Promise<UnifiedMCPServer> {\n logger.info(\"创建混合模式服务器\");\n\n const server = new UnifiedMCPServer();\n await server.initialize();\n\n const messageHandler = server.getMessageHandler();\n\n // 注册 Stdio 适配器\n const stdioAdapter = new StdioAdapter(messageHandler, stdioConfig);\n await server.registerTransport(\"stdio\", stdioAdapter);\n\n // 注册 HTTP 适配器\n const httpAdapter = new HTTPAdapter(messageHandler, httpConfig);\n await server.registerTransport(\"http\", httpAdapter);\n\n // 可选注册 WebSocket 适配器\n if (websocketConfig) {\n const wsAdapter = new WebSocketAdapter(messageHandler, websocketConfig);\n await server.registerTransport(\"websocket\", wsAdapter);\n }\n\n logger.info(\"混合模式服务器创建成功\");\n return server;\n}\n\n/**\n * 确定服务器模式\n */\nasync function determineServerMode(\n config: ServerFactoryConfig\n): Promise<ServerMode> {\n if (config.mode && config.mode !== ServerMode.AUTO) {\n return config.mode;\n }\n\n // 自动检测环境\n const detection = await detectEnvironment(config.autoDetect);\n logger.info(\"环境检测结果\", detection);\n\n return detection.suggestedMode;\n}\n\n/**\n * 检测运行环境\n */\nasync function detectEnvironment(\n options: ServerFactoryConfig[\"autoDetect\"] = {}\n): Promise<EnvironmentDetection> {\n const {\n checkStdin = true,\n checkEnvironment = true,\n defaultMode = ServerMode.HTTP,\n } = options;\n\n const detection: EnvironmentDetection = {\n hasStdin: false,\n isInteractive: false,\n hasPort: false,\n suggestedMode: defaultMode,\n reasons: [],\n };\n\n // 检查标准输入\n if (checkStdin) {\n detection.hasStdin = !process.stdin.isTTY;\n detection.isInteractive = process.stdin.isTTY || false;\n\n if (detection.hasStdin) {\n detection.reasons.push(\"检测到标准输入流\");\n }\n\n if (detection.isInteractive) {\n detection.reasons.push(\"检测到交互式终端\");\n }\n }\n\n // 检查环境变量\n let explicitModeSet = false;\n if (checkEnvironment) {\n const mcpServerMode = process.env.MCP_SERVER_MODE;\n const port = process.env.PORT || process.env.MCP_PORT;\n\n if (mcpServerMode === \"stdio\") {\n detection.suggestedMode = ServerMode.STDIO;\n detection.reasons.push(\"环境变量 MCP_SERVER_MODE=stdio\");\n explicitModeSet = true;\n } else if (mcpServerMode === \"http\") {\n detection.suggestedMode = ServerMode.HTTP;\n detection.reasons.push(\"环境变量 MCP_SERVER_MODE=http\");\n explicitModeSet = true;\n } else if (mcpServerMode === \"websocket\") {\n detection.suggestedMode = ServerMode.WEBSOCKET;\n detection.reasons.push(\"环境变量 MCP_SERVER_MODE=websocket\");\n explicitModeSet = true;\n } else if (mcpServerMode === \"hybrid\") {\n detection.suggestedMode = ServerMode.HYBRID;\n detection.reasons.push(\"环境变量 MCP_SERVER_MODE=hybrid\");\n explicitModeSet = true;\n }\n\n if (port) {\n detection.hasPort = true;\n detection.reasons.push(`检测到端口配置: ${port}`);\n }\n }\n\n // 智能推断模式(仅在没有明确设置环境变量时)\n if (!explicitModeSet && detection.suggestedMode === defaultMode) {\n if (detection.hasStdin && !detection.isInteractive) {\n detection.suggestedMode = ServerMode.STDIO;\n detection.reasons.push(\"推断:非交互式环境,适合 Stdio 模式\");\n } else if (detection.isInteractive || detection.hasPort) {\n detection.suggestedMode = ServerMode.HTTP;\n detection.reasons.push(\"推断:交互式环境或有端口配置,适合 HTTP 模式\");\n }\n }\n\n return detection;\n}\n\n/**\n * 为指定模式注册传输适配器\n */\nasync function registerTransportsForMode(\n server: UnifiedMCPServer,\n mode: ServerMode,\n config: ServerFactoryConfig\n): Promise<void> {\n const messageHandler = server.getMessageHandler();\n\n switch (mode) {\n case ServerMode.STDIO:\n await registerStdioTransport(server, messageHandler, config.stdioConfig);\n break;\n\n case ServerMode.HTTP:\n await registerHTTPTransport(server, messageHandler, config.httpConfig);\n break;\n\n case ServerMode.WEBSOCKET:\n await registerWebSocketTransport(\n server,\n messageHandler,\n config.websocketConfig\n );\n break;\n\n case ServerMode.HYBRID:\n await registerStdioTransport(server, messageHandler, config.stdioConfig);\n await registerHTTPTransport(server, messageHandler, config.httpConfig);\n if (config.websocketConfig) {\n await registerWebSocketTransport(\n server,\n messageHandler,\n config.websocketConfig\n );\n }\n break;\n\n default:\n throw new Error(`不支持的服务器模式: ${mode}`);\n }\n}\n\n/**\n * 注册 Stdio 传输适配器\n */\nasync function registerStdioTransport(\n server: UnifiedMCPServer,\n messageHandler: MCPMessageHandler,\n config: StdioConfig = { name: \"stdio\" }\n): Promise<void> {\n const stdioAdapter = new StdioAdapter(messageHandler, config);\n await server.registerTransport(\"stdio\", stdioAdapter);\n logger.info(\"Stdio 传输适配器注册成功\");\n}\n\n/**\n * 注册 HTTP 传输适配器\n */\nasync function registerHTTPTransport(\n server: UnifiedMCPServer,\n messageHandler: MCPMessageHandler,\n config: HTTPConfig = { name: \"http\" }\n): Promise<void> {\n // 设置默认端口\n const httpConfig: HTTPConfig = {\n port: 3000,\n host: \"0.0.0.0\",\n ...config,\n };\n\n // 从环境变量获取端口\n if (process.env.PORT) {\n httpConfig.port = Number.parseInt(process.env.PORT, 10);\n } else if (process.env.MCP_PORT) {\n httpConfig.port = Number.parseInt(process.env.MCP_PORT, 10);\n }\n\n const httpAdapter = new HTTPAdapter(messageHandler, httpConfig);\n await server.registerTransport(\"http\", httpAdapter);\n logger.info(`HTTP 传输适配器注册成功 (端口: ${httpConfig.port})`);\n}\n\n/**\n * 注册 WebSocket 传输适配器\n */\nasync function registerWebSocketTransport(\n server: UnifiedMCPServer,\n messageHandler: MCPMessageHandler,\n config: WebSocketConfig = {\n name: \"websocket\",\n endpointUrl: \"ws://localhost:8080\",\n }\n): Promise<void> {\n // 设置默认配置\n const wsConfig: WebSocketConfig = {\n mode: \"client\",\n compression: true,\n batchSize: 10,\n batchTimeout: 100,\n maxConnections: 100,\n ...config,\n };\n\n // 从环境变量获取端点URL\n if (process.env.WEBSOCKET_URL) {\n wsConfig.endpointUrl = process.env.WEBSOCKET_URL;\n } else if (process.env.MCP_WEBSOCKET_URL) {\n wsConfig.endpointUrl = process.env.MCP_WEBSOCKET_URL;\n }\n\n const wsAdapter = new WebSocketAdapter(messageHandler, wsConfig);\n await server.registerTransport(\"websocket\", wsAdapter);\n logger.info(`WebSocket 传输适配器注册成功 (端点: ${wsConfig.endpointUrl})`);\n}\n\n/**\n * 获取推荐的服务器配置\n * 根据环境提供最佳的配置建议\n */\nexport async function getRecommendedConfig(): Promise<ServerFactoryConfig> {\n const detection = await detectEnvironment();\n\n const config: ServerFactoryConfig = {\n mode: detection.suggestedMode,\n autoDetect: {\n checkStdin: true,\n checkEnvironment: true,\n defaultMode: ServerMode.HTTP,\n },\n };\n\n // 根据检测结果调整配置\n if (detection.hasPort) {\n config.httpConfig = {\n name: \"http\",\n port: Number.parseInt(\n process.env.PORT || process.env.MCP_PORT || \"3000\",\n 10\n ),\n };\n }\n\n if (detection.hasStdin) {\n config.stdioConfig = {\n name: \"stdio\",\n encoding: \"utf8\",\n };\n }\n\n // WebSocket 配置(如果有相关环境变量)\n if (process.env.WEBSOCKET_URL || process.env.MCP_WEBSOCKET_URL) {\n config.websocketConfig = {\n name: \"websocket\",\n endpointUrl:\n process.env.WEBSOCKET_URL ||\n process.env.MCP_WEBSOCKET_URL ||\n \"ws://localhost:8080\",\n mode: \"client\",\n compression: true,\n };\n }\n\n return config;\n}\n\n/**\n * 验证服务器配置\n */\nexport function validateConfig(config: ServerFactoryConfig): void {\n if (config.mode === ServerMode.HTTP && config.httpConfig?.port) {\n const port = config.httpConfig.port;\n if (port < 1 || port > 65535) {\n throw new Error(`无效的端口号: ${port}`);\n }\n }\n\n if (config.stdioConfig?.encoding) {\n const validEncodings = [\n \"utf8\",\n \"ascii\",\n \"utf16le\",\n \"ucs2\",\n \"base64\",\n \"latin1\",\n \"binary\",\n \"hex\",\n ];\n if (!validEncodings.includes(config.stdioConfig.encoding)) {\n throw new Error(`不支持的编码: ${config.stdioConfig.encoding}`);\n }\n }\n\n if (config.websocketConfig) {\n const wsConfig = config.websocketConfig;\n\n // 验证端点URL\n if (!wsConfig.endpointUrl) {\n throw new Error(\"WebSocket 端点URL不能为空\");\n }\n\n try {\n new URL(wsConfig.endpointUrl);\n } catch {\n throw new Error(`无效的 WebSocket 端点URL: ${wsConfig.endpointUrl}`);\n }\n\n // 验证模式\n if (wsConfig.mode && ![\"client\", \"server\"].includes(wsConfig.mode)) {\n throw new Error(`无效的 WebSocket 模式: ${wsConfig.mode}`);\n }\n\n // 验证批处理配置\n if (\n wsConfig.batchSize !== undefined &&\n (wsConfig.batchSize < 1 || wsConfig.batchSize > 1000)\n ) {\n throw new Error(`无效的批处理大小: ${wsConfig.batchSize}`);\n }\n\n // 验证最大连接数\n if (\n wsConfig.maxConnections &&\n (wsConfig.maxConnections < 1 || wsConfig.maxConnections > 10000)\n ) {\n throw new Error(`无效的最大连接数: ${wsConfig.maxConnections}`);\n }\n }\n}\n","import { EventEmitter } from \"node:events\";\nimport { Logger } from \"../Logger.js\";\nimport { ProxyMCPServer } from \"../ProxyMCPServer.js\";\nimport { configManager } from \"../configManager.js\";\nimport { createHTTPServer } from \"../core/ServerFactory.js\";\nimport type { UnifiedMCPServer } from \"../core/UnifiedMCPServer.js\";\nimport type { HTTPConfig } from \"../transports/HTTPAdapter.js\";\n\nconst logger = new Logger();\n\n/**\n * MCP 服务器类(重构版)\n * 现在基于 UnifiedMCPServer 和传输层抽象实现\n * 保持向后兼容的 API,但内部使用新的统一架构\n */\nexport class MCPServer extends EventEmitter {\n private unifiedServer: UnifiedMCPServer | null = null;\n private proxyMCPServer: ProxyMCPServer | null = null;\n private port: number;\n private isStarted = false;\n\n constructor(port = 3000) {\n super();\n this.port = port;\n }\n\n /**\n * 初始化统一服务器\n */\n private async initializeUnifiedServer(): Promise<void> {\n if (this.unifiedServer) {\n return;\n }\n\n logger.info(\"初始化统一 MCP 服务器\");\n\n try {\n // 创建 HTTP 模式的统一服务器\n const httpConfig: HTTPConfig = {\n name: \"http\",\n port: this.port,\n host: \"0.0.0.0\",\n enableSSE: true,\n enableRPC: true,\n };\n\n this.unifiedServer = await createHTTPServer(httpConfig);\n\n // 转发统一服务器的事件\n this.unifiedServer.on(\"started\", () => this.emit(\"started\"));\n this.unifiedServer.on(\"stopped\", () => this.emit(\"stopped\"));\n this.unifiedServer.on(\"connectionRegistered\", (connection) => {\n this.emit(\"connectionRegistered\", connection);\n });\n\n logger.info(\"统一 MCP 服务器初始化完成\");\n } catch (error) {\n logger.error(\"初始化统一 MCP 服务器失败\", error);\n throw error;\n }\n }\n\n /**\n * 初始化小智接入点连接\n */\n private async initializeMCPClient(): Promise<void> {\n try {\n // 获取小智接入点配置\n let mcpEndpoint: string | null = null;\n try {\n if (configManager.configExists()) {\n const endpoints = configManager.getMcpEndpoints();\n mcpEndpoint =\n endpoints.find((ep) => ep && !ep.includes(\"<请填写\")) || null;\n }\n } catch (error) {\n logger.warn(\"从配置中读取小智接入点失败:\", error);\n }\n\n // 只有在配置了有效端点时才启动连接\n if (mcpEndpoint) {\n this.proxyMCPServer = new ProxyMCPServer(mcpEndpoint);\n\n // 设置服务管理器\n if (this.unifiedServer) {\n this.proxyMCPServer.setServiceManager(\n this.unifiedServer.getServiceManager()\n );\n }\n\n await this.proxyMCPServer.connect();\n logger.info(\"小智接入点连接成功\");\n } else {\n logger.info(\"未配置有效的小智接入点,跳过连接\");\n }\n } catch (error) {\n logger.error(\"初始化小智接入点连接失败:\", error);\n }\n }\n\n /**\n * 启动服务器\n */\n public async start(): Promise<void> {\n if (this.isStarted) {\n logger.warn(\"服务器已启动\");\n return;\n }\n\n try {\n logger.info(\"启动 MCP 服务器\");\n\n // 初始化统一服务器\n await this.initializeUnifiedServer();\n\n // 启动统一服务器\n if (this.unifiedServer) {\n await this.unifiedServer.start();\n }\n\n // 初始化小智接入点连接(不阻塞服务器启动)\n this.initializeMCPClient().catch((error) => {\n logger.error(\"初始化小智接入点连接失败:\", error);\n });\n\n this.isStarted = true;\n this.emit(\"started\");\n logger.info(\"MCP 服务器启动成功\");\n } catch (error) {\n logger.error(\"启动 MCP 服务器失败:\", error);\n throw error;\n }\n }\n\n /**\n * 停止服务器\n */\n public async stop(): Promise<void> {\n if (!this.isStarted) {\n logger.warn(\"服务器未启动\");\n return;\n }\n\n try {\n logger.info(\"停止 MCP 服务器\");\n\n // 停止统一服务器\n if (this.unifiedServer) {\n await this.unifiedServer.stop();\n }\n\n // 停止小智接入点连接\n if (this.proxyMCPServer) {\n this.proxyMCPServer.disconnect();\n this.proxyMCPServer = null;\n }\n\n this.isStarted = false;\n this.emit(\"stopped\");\n logger.info(\"MCP 服务器已停止\");\n } catch (error) {\n logger.error(\"停止 MCP 服务器失败:\", error);\n throw error;\n }\n }\n\n /**\n * 获取服务管理器(向后兼容)\n */\n getServiceManager() {\n return this.unifiedServer?.getServiceManager() || null;\n }\n\n /**\n * 获取消息处理器(向后兼容)\n */\n getMessageHandler() {\n return this.unifiedServer?.getMessageHandler() || null;\n }\n\n /**\n * 获取服务器状态\n */\n getStatus() {\n if (!this.unifiedServer) {\n return {\n isRunning: false,\n port: this.port,\n mode: \"mcp-server\",\n };\n }\n\n const status = this.unifiedServer.getStatus();\n return {\n ...status,\n port: this.port,\n mode: \"mcp-server\",\n proxyConnected: this.proxyMCPServer !== null,\n };\n }\n\n /**\n * 检查服务器是否正在运行\n */\n isRunning(): boolean {\n return this.isStarted && (this.unifiedServer?.isServerRunning() || false);\n }\n}\n","/**\n * 服务管理服务\n */\n\nimport { ConfigError, ServiceError } from \"../errors/index.js\";\nimport type {\n ServiceManager as IServiceManager,\n ProcessManager,\n ServiceStartOptions,\n ServiceStatus,\n} from \"../interfaces/Service.js\";\nimport { PathUtils } from \"../utils/PathUtils.js\";\nimport { PlatformUtils } from \"../utils/PlatformUtils.js\";\nimport { Validation } from \"../utils/Validation.js\";\n\n/**\n * 服务管理器实现\n */\nexport class ServiceManagerImpl implements IServiceManager {\n constructor(\n private processManager: ProcessManager,\n private configManager: any,\n private logger: any\n ) {}\n\n /**\n * 启动服务\n */\n async start(options: ServiceStartOptions): Promise<void> {\n try {\n // 验证启动选项\n this.validateStartOptions(options);\n\n // 清理容器环境状态\n this.processManager.cleanupContainerState();\n\n // 检查服务是否已经在运行\n const status = this.getStatus();\n if (status.running) {\n // 自动停止现有服务并重新启动\n console.log(`检测到服务已在运行 (PID: ${status.pid}),正在自动重启...`);\n\n try {\n // 优雅停止现有进程\n await this.processManager.gracefulKillProcess(status.pid!);\n\n // 清理 PID 文件\n this.processManager.cleanupPidFile();\n\n // 等待一下确保完全停止\n await new Promise((resolve) => setTimeout(resolve, 1000));\n\n console.log(\"现有服务已停止,正在启动新服务...\");\n } catch (stopError) {\n console.warn(\n `停止现有服务时出现警告: ${stopError instanceof Error ? stopError.message : String(stopError)}`\n );\n // 继续尝试启动新服务,因为旧进程可能已经不存在了\n }\n }\n\n // 检查环境配置\n this.checkEnvironment();\n\n // 根据模式启动服务\n switch (options.mode) {\n case \"mcp-server\":\n await this.startMcpServerMode(options);\n break;\n case \"stdio\":\n await this.startStdioMode(options);\n break;\n case \"normal\":\n await this.startNormalMode(options);\n break;\n default:\n await this.startNormalMode(options);\n break;\n }\n } catch (error) {\n if (error instanceof ServiceError) {\n throw error;\n }\n throw ServiceError.startFailed(\n error instanceof Error ? error.message : String(error)\n );\n }\n }\n\n /**\n * 停止服务\n */\n async stop(): Promise<void> {\n try {\n const status = this.getStatus();\n\n if (!status.running) {\n throw ServiceError.notRunning();\n }\n\n // 优雅停止进程\n await this.processManager.gracefulKillProcess(status.pid!);\n\n // 清理 PID 文件\n this.processManager.cleanupPidFile();\n } catch (error) {\n if (error instanceof ServiceError) {\n throw error;\n }\n throw new ServiceError(\n `停止服务失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * 重启服务\n */\n async restart(options: ServiceStartOptions): Promise<void> {\n try {\n // 先停止服务\n const status = this.getStatus();\n if (status.running) {\n await this.stop();\n // 等待一下确保完全停止\n await new Promise((resolve) => setTimeout(resolve, 1000));\n }\n\n // 重新启动服务\n await this.start(options);\n } catch (error) {\n throw new ServiceError(\n `重启服务失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * 获取服务状态\n */\n getStatus(): ServiceStatus {\n return this.processManager.getServiceStatus();\n }\n\n /**\n * 验证启动选项\n */\n private validateStartOptions(options: ServiceStartOptions): void {\n if (options.port !== undefined) {\n Validation.validatePort(options.port);\n }\n\n if (\n options.mode &&\n ![\"normal\", \"mcp-server\", \"stdio\"].includes(options.mode)\n ) {\n throw new ServiceError(`无效的运行模式: ${options.mode}`);\n }\n }\n\n /**\n * 检查环境配置\n */\n private checkEnvironment(): void {\n // 检查配置文件是否存在\n if (!this.configManager.configExists()) {\n throw ConfigError.configNotFound();\n }\n\n // 可以添加更多环境检查\n try {\n const config = this.configManager.getConfig();\n if (!config) {\n throw new ConfigError(\"配置文件无效\");\n }\n } catch (error) {\n if (error instanceof ConfigError) {\n throw error;\n }\n throw new ConfigError(\n `配置文件错误: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * 启动普通模式\n */\n private async startNormalMode(options: ServiceStartOptions): Promise<void> {\n const { spawn } = await import(\"node:child_process\");\n\n if (options.daemon) {\n // 后台模式\n await this.startWebServerInDaemon(options.ui || false);\n } else {\n // 前台模式\n await this.startWebServerInForeground(options.ui || false);\n }\n }\n\n /**\n * 启动 MCP Server 模式\n */\n private async startMcpServerMode(\n options: ServiceStartOptions\n ): Promise<void> {\n const port = options.port || 3000;\n const { spawn } = await import(\"node:child_process\");\n\n if (options.daemon) {\n // 后台模式\n const scriptPath = PathUtils.getExecutablePath(\"cli\");\n const child = spawn(\n \"node\",\n [scriptPath, \"start\", \"--server\", port.toString()],\n {\n detached: true,\n stdio: [\"ignore\", \"ignore\", \"ignore\"], // 完全忽略所有 stdio,避免阻塞\n env: {\n ...process.env,\n XIAOZHI_CONFIG_DIR: PathUtils.getConfigDir(),\n XIAOZHI_DAEMON: \"true\",\n MCP_SERVER_MODE: \"true\",\n },\n }\n );\n\n // 保存 PID 信息\n this.processManager.savePidInfo(child.pid!, \"daemon\");\n\n // 完全分离子进程\n child.unref();\n\n // 输出启动信息后立即退出父进程\n console.log(\n `✅ MCP Server 已在后台启动 (PID: ${child.pid}, Port: ${port})`\n );\n console.log(`💡 使用 'xiaozhi status' 查看状态`);\n\n // 立即退出父进程,释放终端控制权\n process.exit(0);\n } else {\n // 前台模式 - 直接启动 MCP Server\n const { MCPServer } = await import(\"../../services/MCPServer.js\");\n const server = new MCPServer(port);\n\n // 处理退出信号\n const cleanup = async () => {\n await server.stop();\n process.exit(0);\n };\n\n process.on(\"SIGINT\", cleanup);\n process.on(\"SIGTERM\", cleanup);\n\n await server.start();\n }\n }\n\n /**\n * 启动 stdio 模式\n */\n private async startStdioMode(options: ServiceStartOptions): Promise<void> {\n const { spawn } = await import(\"node:child_process\");\n const mcpProxyPath = PathUtils.getMcpServerProxyPath();\n\n // 直接执行 mcpServerProxy,它已经支持 stdio\n const child = spawn(\"node\", [mcpProxyPath], {\n stdio: \"inherit\",\n env: {\n ...process.env,\n XIAOZHI_CONFIG_DIR: PathUtils.getConfigDir(),\n },\n });\n\n // 保存 PID 信息\n this.processManager.savePidInfo(child.pid!, \"foreground\");\n }\n\n /**\n * 后台模式启动 WebServer\n */\n private async startWebServerInDaemon(openBrowser: boolean): Promise<void> {\n const { spawn } = await import(\"node:child_process\");\n const webServerPath = PathUtils.getWebServerStandalonePath();\n\n const fs = await import(\"node:fs\");\n if (!fs.default.existsSync(webServerPath)) {\n throw new ServiceError(`WebServer 文件不存在: ${webServerPath}`);\n }\n\n const args = [webServerPath];\n if (openBrowser) {\n args.push(\"--open-browser\");\n }\n\n const child = spawn(\"node\", args, {\n detached: true,\n stdio: [\"ignore\", \"ignore\", \"ignore\"], // 完全忽略所有 stdio,避免阻塞\n env: {\n ...process.env,\n XIAOZHI_CONFIG_DIR: PathUtils.getConfigDir(),\n XIAOZHI_DAEMON: \"true\",\n },\n });\n\n // 保存 PID 信息\n this.processManager.savePidInfo(child.pid!, \"daemon\");\n\n // 完全分离子进程\n child.unref();\n\n // 输出启动信息后立即退出父进程\n console.log(`✅ 后台服务已启动 (PID: ${child.pid})`);\n console.log(`💡 使用 'xiaozhi status' 查看状态`);\n console.log(`💡 使用 'xiaozhi attach' 查看日志`);\n\n // 立即退出父进程,释放终端控制权\n process.exit(0);\n }\n\n /**\n * 前台模式启动 WebServer\n */\n private async startWebServerInForeground(\n openBrowser: boolean\n ): Promise<void> {\n const { WebServer } = await import(\"../../WebServer.js\");\n const server = new WebServer();\n\n // 处理退出信号\n const cleanup = async () => {\n await server.stop();\n this.processManager.cleanupPidFile();\n process.exit(0);\n };\n\n process.on(\"SIGINT\", cleanup);\n process.on(\"SIGTERM\", cleanup);\n\n // 保存 PID 信息\n this.processManager.savePidInfo(process.pid, \"foreground\");\n\n await server.start();\n\n if (openBrowser) {\n const config = this.configManager.getConfig();\n const port = config?.webServer?.port || 9999;\n await this.openBrowserUrl(`http://localhost:${port}`);\n }\n }\n\n /**\n * 打开浏览器URL\n */\n private async openBrowserUrl(url: string): Promise<void> {\n try {\n const { spawn } = await import(\"node:child_process\");\n const platform = PlatformUtils.getCurrentPlatform();\n\n let command: string;\n let args: string[];\n\n if (platform === \"darwin\") {\n command = \"open\";\n args = [url];\n } else if (platform === \"win32\") {\n command = \"start\";\n args = [\"\", url];\n } else {\n command = \"xdg-open\";\n args = [url];\n }\n\n spawn(command, args, { detached: true, stdio: \"ignore\" });\n console.log(`🌐 已尝试打开浏览器: ${url}`);\n } catch (error) {\n console.log(`⚠️ 自动打开浏览器失败,请手动访问: ${url}`);\n }\n }\n}\n","/**\n * 模板管理服务\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { FileError, ValidationError } from \"../errors/index.js\";\nimport type { TemplateManager as ITemplateManager } from \"../interfaces/Service.js\";\nimport { FileUtils } from \"../utils/FileUtils.js\";\nimport { PathUtils } from \"../utils/PathUtils.js\";\nimport { Validation } from \"../utils/Validation.js\";\n\n/**\n * 模板信息接口\n */\nexport interface TemplateInfo {\n name: string;\n path: string;\n description?: string;\n version?: string;\n author?: string;\n files: string[];\n}\n\n/**\n * 模板创建选项\n */\nexport interface TemplateCreateOptions {\n templateName?: string;\n targetPath: string;\n projectName: string;\n variables?: Record<string, string>;\n}\n\n/**\n * 模板管理器实现\n */\nexport class TemplateManagerImpl implements ITemplateManager {\n private templateCache = new Map<string, TemplateInfo>();\n\n /**\n * 获取可用模板列表\n */\n async getAvailableTemplates(): Promise<TemplateInfo[]> {\n try {\n const templatesDir = PathUtils.findTemplatesDir();\n\n if (!templatesDir) {\n return [];\n }\n\n const templates: TemplateInfo[] = [];\n const templateDirs = fs\n .readdirSync(templatesDir, { withFileTypes: true })\n .filter((dirent) => dirent.isDirectory())\n .map((dirent) => dirent.name);\n\n for (const templateName of templateDirs) {\n try {\n const templateInfo = await this.getTemplateInfo(templateName);\n if (templateInfo) {\n templates.push(templateInfo);\n }\n } catch (error) {\n // 跳过无效的模板目录\n console.warn(`跳过无效模板: ${templateName}`);\n }\n }\n\n return templates;\n } catch (error) {\n throw new FileError(\n \"无法读取模板目录\",\n PathUtils.findTemplatesDir() || \"\"\n );\n }\n }\n\n /**\n * 获取模板信息\n */\n async getTemplateInfo(templateName: string): Promise<TemplateInfo | null> {\n try {\n // 验证模板名称\n Validation.validateTemplateName(templateName);\n\n // 检查缓存\n if (this.templateCache.has(templateName)) {\n return this.templateCache.get(templateName)!;\n }\n\n const templatePath = PathUtils.getTemplatePath(templateName);\n if (!templatePath) {\n return null;\n }\n\n // 读取模板配置文件\n const configPath = path.join(templatePath, \"template.json\");\n let config: any = {};\n\n if (FileUtils.exists(configPath)) {\n try {\n const configContent = FileUtils.readFile(configPath);\n config = JSON.parse(configContent);\n } catch (error) {\n console.warn(`模板配置文件解析失败: ${templateName}`);\n }\n }\n\n // 获取模板文件列表\n const files = this.getTemplateFiles(templatePath);\n\n const templateInfo: TemplateInfo = {\n name: templateName,\n path: templatePath,\n description: config.description || `${templateName} 模板`,\n version: config.version || \"1.0.0\",\n author: config.author,\n files,\n };\n\n // 缓存模板信息\n this.templateCache.set(templateName, templateInfo);\n\n return templateInfo;\n } catch (error) {\n if (error instanceof ValidationError) {\n throw error;\n }\n throw new FileError(`无法获取模板信息: ${templateName}`, \"\");\n }\n }\n\n /**\n * 复制模板到目标目录\n */\n async copyTemplate(templateName: string, targetPath: string): Promise<void> {\n await this.createProject({\n templateName,\n targetPath,\n projectName: path.basename(targetPath),\n });\n }\n\n /**\n * 创建项目\n */\n async createProject(options: TemplateCreateOptions): Promise<void> {\n try {\n // 验证输入参数\n this.validateCreateOptions(options);\n\n // 获取模板信息\n const templateName = options.templateName || \"default\";\n const templateInfo = await this.getTemplateInfo(templateName);\n\n if (!templateInfo) {\n throw new FileError(`模板不存在: ${templateName}`, \"\");\n }\n\n // 检查目标路径\n const targetPath = path.resolve(options.targetPath);\n if (FileUtils.exists(targetPath)) {\n throw FileError.alreadyExists(targetPath);\n }\n\n // 创建项目目录\n FileUtils.ensureDir(targetPath);\n\n // 复制模板文件\n await this.copyTemplateFiles(templateInfo, targetPath, options);\n\n // 处理模板变量替换\n await this.processTemplateVariables(targetPath, options);\n\n console.log(`✅ 项目创建成功: ${targetPath}`);\n } catch (error) {\n if (error instanceof FileError || error instanceof ValidationError) {\n throw error;\n }\n throw new FileError(\n `创建项目失败: ${error instanceof Error ? error.message : String(error)}`,\n options.targetPath\n );\n }\n }\n\n /**\n * 验证模板\n */\n async validateTemplate(templateName: string): Promise<boolean> {\n try {\n const templateInfo = await this.getTemplateInfo(templateName);\n\n if (!templateInfo) {\n return false;\n }\n\n // 检查必要文件是否存在\n const requiredFiles = [\"package.json\"]; // 可以根据需要调整\n\n for (const requiredFile of requiredFiles) {\n const filePath = path.join(templateInfo.path, requiredFile);\n if (!FileUtils.exists(filePath)) {\n console.warn(`模板缺少必要文件: ${requiredFile}`);\n return false;\n }\n }\n\n return true;\n } catch {\n return false;\n }\n }\n\n /**\n * 清除模板缓存\n */\n clearCache(): void {\n this.templateCache.clear();\n }\n\n /**\n * 获取模板文件列表\n */\n private getTemplateFiles(templatePath: string): string[] {\n try {\n const files = FileUtils.listDirectory(templatePath, {\n recursive: true,\n includeHidden: false,\n });\n\n // 过滤掉模板配置文件和其他不需要的文件\n return files.filter((file) => {\n const relativePath = path.relative(templatePath, file);\n return (\n !relativePath.startsWith(\".\") &&\n relativePath !== \"template.json\" &&\n !relativePath.includes(\"node_modules\")\n );\n });\n } catch {\n return [];\n }\n }\n\n /**\n * 验证创建选项\n */\n private validateCreateOptions(options: TemplateCreateOptions): void {\n Validation.validateRequired(options.targetPath, \"targetPath\");\n Validation.validateRequired(options.projectName, \"projectName\");\n Validation.validateProjectName(options.projectName);\n\n if (options.templateName) {\n Validation.validateTemplateName(options.templateName);\n }\n }\n\n /**\n * 复制模板文件\n */\n private async copyTemplateFiles(\n templateInfo: TemplateInfo,\n targetPath: string,\n options: TemplateCreateOptions\n ): Promise<void> {\n try {\n // 复制所有模板文件\n FileUtils.copyDirectory(templateInfo.path, targetPath, {\n exclude: [\"template.json\", \".git\", \"node_modules\"],\n overwrite: false,\n recursive: true,\n });\n } catch (error) {\n throw new FileError(\n `复制模板文件失败: ${error instanceof Error ? error.message : String(error)}`,\n templateInfo.path\n );\n }\n }\n\n /**\n * 处理模板变量替换\n */\n private async processTemplateVariables(\n targetPath: string,\n options: TemplateCreateOptions\n ): Promise<void> {\n try {\n // 默认变量\n const variables = {\n PROJECT_NAME: options.projectName,\n PROJECT_NAME_LOWER: options.projectName.toLowerCase(),\n PROJECT_NAME_UPPER: options.projectName.toUpperCase(),\n ...options.variables,\n };\n\n // 获取需要处理的文件\n const filesToProcess = [\n \"package.json\",\n \"README.md\",\n \"src/**/*.ts\",\n \"src/**/*.js\",\n \"src/**/*.json\",\n ];\n\n for (const pattern of filesToProcess) {\n const files = this.findFilesByPattern(targetPath, pattern);\n\n for (const filePath of files) {\n await this.replaceVariablesInFile(filePath, variables);\n }\n }\n } catch (error) {\n console.warn(\n `处理模板变量失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * 根据模式查找文件\n */\n private findFilesByPattern(basePath: string, pattern: string): string[] {\n try {\n if (!pattern.includes(\"*\")) {\n // 简单文件路径\n const filePath = path.join(basePath, pattern);\n return FileUtils.exists(filePath) ? [filePath] : [];\n }\n\n // 简单的通配符支持\n const files = FileUtils.listDirectory(basePath, { recursive: true });\n const regex = new RegExp(\n pattern.replace(/\\*\\*/g, \".*\").replace(/\\*/g, \"[^/]*\")\n );\n\n return files.filter((file) => {\n const relativePath = path.relative(basePath, file);\n return regex.test(relativePath);\n });\n } catch {\n return [];\n }\n }\n\n /**\n * 替换文件中的变量\n */\n private async replaceVariablesInFile(\n filePath: string,\n variables: Record<string, string>\n ): Promise<void> {\n try {\n let content = FileUtils.readFile(filePath);\n let hasChanges = false;\n\n // 替换变量 {{VARIABLE_NAME}}\n for (const [key, value] of Object.entries(variables)) {\n const regex = new RegExp(`{{\\\\s*${key}\\\\s*}}`, \"g\");\n if (regex.test(content)) {\n content = content.replace(regex, value);\n hasChanges = true;\n }\n }\n\n // 如果有变更,写回文件\n if (hasChanges) {\n FileUtils.writeFile(filePath, content, { overwrite: true });\n }\n } catch (error) {\n console.warn(\n `替换文件变量失败 ${filePath}: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n}\n","/**\n * 依赖注入容器\n */\n\nimport { logger } from \"../Logger.js\";\nimport { configManager } from \"../configManager.js\";\nimport { ErrorHandler } from \"./errors/ErrorHandlers.js\";\nimport type { IDIContainer } from \"./interfaces/Config.js\";\nimport { FileUtils } from \"./utils/FileUtils.js\";\nimport { FormatUtils } from \"./utils/FormatUtils.js\";\nimport { PathUtils } from \"./utils/PathUtils.js\";\nimport { PlatformUtils } from \"./utils/PlatformUtils.js\";\nimport { Validation } from \"./utils/Validation.js\";\nimport { VersionUtils } from \"./utils/VersionUtils.js\";\n\n/**\n * 依赖注入容器实现\n */\nexport class DIContainer implements IDIContainer {\n private instances = new Map<string, any>();\n private factories = new Map<string, () => any>();\n private asyncFactories = new Map<string, () => Promise<any>>();\n private singletons = new Set<string>();\n\n /**\n * 注册服务工厂\n */\n register<T>(key: string, factory: () => T, singleton = false): void {\n this.factories.set(key, factory);\n if (singleton) {\n this.singletons.add(key);\n }\n }\n\n /**\n * 注册单例服务\n */\n registerSingleton<T>(key: string, factory: () => T): void {\n this.register(key, factory, true);\n }\n\n /**\n * 注册实例\n */\n registerInstance<T>(key: string, instance: T): void {\n this.instances.set(key, instance);\n this.singletons.add(key);\n }\n\n /**\n * 获取服务实例\n */\n get<T>(key: string): T {\n // 如果是单例且已经创建过实例,直接返回\n if (this.singletons.has(key) && this.instances.has(key)) {\n return this.instances.get(key);\n }\n\n // 获取工厂函数\n const factory = this.factories.get(key);\n if (!factory) {\n throw new Error(`Service ${key} not registered`);\n }\n\n // 创建实例\n const instance = factory();\n\n // 如果是单例,缓存实例\n if (this.singletons.has(key)) {\n this.instances.set(key, instance);\n }\n\n return instance;\n }\n\n /**\n * 检查服务是否已注册\n */\n has(key: string): boolean {\n return this.factories.has(key) || this.instances.has(key);\n }\n\n /**\n * 清除所有注册的服务\n */\n clear(): void {\n this.instances.clear();\n this.factories.clear();\n this.singletons.clear();\n }\n\n /**\n * 获取所有已注册的服务键\n */\n getRegisteredKeys(): string[] {\n const factoryKeys = Array.from(this.factories.keys());\n const instanceKeys = Array.from(this.instances.keys());\n return [...new Set([...factoryKeys, ...instanceKeys])];\n }\n\n /**\n * 创建默认容器实例\n */\n static create(): DIContainer {\n const container = new DIContainer();\n\n // 注册工具类(单例)\n container.registerSingleton(\"versionUtils\", () => {\n return VersionUtils;\n });\n\n container.registerSingleton(\"platformUtils\", () => {\n return PlatformUtils;\n });\n\n container.registerSingleton(\"formatUtils\", () => {\n return FormatUtils;\n });\n\n container.registerSingleton(\"fileUtils\", () => {\n return FileUtils;\n });\n\n container.registerSingleton(\"pathUtils\", () => {\n return PathUtils;\n });\n\n container.registerSingleton(\"validation\", () => {\n return Validation;\n });\n\n // 注册配置管理器(单例)\n container.registerSingleton(\"configManager\", () => {\n return configManager;\n });\n\n // 注册日志管理器(单例)\n container.registerSingleton(\"logger\", () => {\n return logger;\n });\n\n // 注册错误处理器(单例)\n container.registerSingleton(\"errorHandler\", () => {\n return ErrorHandler;\n });\n\n // 注册服务层\n container.registerSingleton(\"processManager\", () => {\n const ProcessManagerModule = require(\"./services/ProcessManager.js\");\n return new ProcessManagerModule.ProcessManagerImpl();\n });\n\n container.registerSingleton(\"daemonManager\", () => {\n const DaemonManagerModule = require(\"./services/DaemonManager.js\");\n const processManager = container.get(\"processManager\") as any;\n const logger = container.get(\"logger\") as any;\n return new DaemonManagerModule.DaemonManagerImpl(processManager, logger);\n });\n\n container.registerSingleton(\"serviceManager\", () => {\n const ServiceManagerModule = require(\"./services/ServiceManager.js\");\n const processManager = container.get(\"processManager\") as any;\n const configManager = container.get(\"configManager\") as any;\n const logger = container.get(\"logger\") as any;\n return new ServiceManagerModule.ServiceManagerImpl(\n processManager,\n configManager,\n logger\n );\n });\n\n container.registerSingleton(\"templateManager\", () => {\n // 使用动态导入的同步版本\n const TemplateManagerModule = require(\"./services/TemplateManager.js\");\n return new TemplateManagerModule.TemplateManagerImpl();\n });\n\n // 注册命令层(稍后在命令层实现时添加)\n // container.register('serviceCommand', () => {\n // const { ServiceCommand } = require('./commands/ServiceCommand.js');\n // const serviceManager = container.get('serviceManager');\n // const processManager = container.get('processManager');\n // return new ServiceCommand(serviceManager, processManager);\n // });\n\n // container.register('configCommand', () => {\n // const { ConfigCommand } = require('./commands/ConfigCommand.js');\n // const configManager = container.get('configManager');\n // const validation = container.get('validation');\n // return new ConfigCommand(configManager, validation);\n // });\n\n // container.register('projectCommand', () => {\n // const { ProjectCommand } = require('./commands/ProjectCommand.js');\n // const templateManager = container.get('templateManager');\n // const fileUtils = container.get('fileUtils');\n // return new ProjectCommand(templateManager, fileUtils);\n // });\n\n // container.register('mcpCommand', () => {\n // const { McpCommand } = require('./commands/McpCommand.js');\n // return new McpCommand();\n // });\n\n // container.register('infoCommand', () => {\n // const { InfoCommand } = require('./commands/InfoCommand.js');\n // const versionUtils = container.get('versionUtils');\n // const platformUtils = container.get('platformUtils');\n // return new InfoCommand(versionUtils, platformUtils);\n // });\n\n return container;\n }\n}\n\n/**\n * 创建并配置 DI 容器\n */\nexport async function createContainer(): Promise<IDIContainer> {\n return DIContainer.create();\n}\n","import { spawn } from \"node:child_process\";\nimport type { Context } from \"hono\";\nimport { type Logger, logger } from \"../Logger.js\";\nimport { createContainer } from \"../cli/Container.js\";\nimport { type EventBus, getEventBus } from \"../services/EventBus.js\";\nimport type { StatusService } from \"../services/StatusService.js\";\n\n/**\n * 统一响应格式接口\n */\ninterface ApiErrorResponse {\n error: {\n code: string;\n message: string;\n details?: any;\n };\n}\n\ninterface ApiSuccessResponse<T = any> {\n success: boolean;\n data?: T;\n message?: string;\n}\n\n/**\n * 服务 API 处理器\n */\nexport class ServiceApiHandler {\n private logger: Logger;\n private statusService: StatusService;\n private eventBus: EventBus;\n\n constructor(statusService: StatusService) {\n this.logger = logger.withTag(\"ServiceApiHandler\");\n this.statusService = statusService;\n this.eventBus = getEventBus();\n }\n\n /**\n * 创建统一的错误响应\n */\n private createErrorResponse(\n code: string,\n message: string,\n details?: any\n ): ApiErrorResponse {\n return {\n error: {\n code,\n message,\n details,\n },\n };\n }\n\n /**\n * 创建统一的成功响应\n */\n private createSuccessResponse<T>(\n data?: T,\n message?: string\n ): ApiSuccessResponse<T> {\n return {\n success: true,\n data,\n message,\n };\n }\n\n /**\n * 重启服务\n * POST /api/services/restart\n */\n async restartService(c: Context): Promise<Response> {\n try {\n this.logger.info(\"处理服务重启请求\");\n\n // 发射重启请求事件\n this.eventBus.emitEvent(\"service:restart:requested\", {\n source: \"http-api\",\n });\n\n // 更新重启状态\n this.statusService.updateRestartStatus(\"restarting\");\n\n // 异步执行重启,不阻塞响应\n setTimeout(async () => {\n try {\n await this.executeRestart();\n // 服务重启需要一些时间,延迟发送成功状态\n setTimeout(() => {\n this.statusService.updateRestartStatus(\"completed\");\n }, 5000);\n } catch (error) {\n this.logger.error(\"服务重启失败:\", error);\n this.statusService.updateRestartStatus(\n \"failed\",\n error instanceof Error ? error.message : \"未知错误\"\n );\n }\n }, 500);\n\n return c.json(this.createSuccessResponse(null, \"重启请求已接收\"));\n } catch (error) {\n this.logger.error(\"处理重启请求失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"RESTART_REQUEST_ERROR\",\n error instanceof Error ? error.message : \"处理重启请求失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 执行服务重启\n */\n private async executeRestart(): Promise<void> {\n this.logger.info(\"正在重启 MCP 服务...\");\n\n try {\n // 获取当前服务状态\n const container = await createContainer();\n const serviceManager = container.get(\"serviceManager\") as any;\n const status = await serviceManager.getStatus();\n\n if (!status.running) {\n this.logger.warn(\"MCP 服务未运行,尝试启动服务\");\n\n // 如果服务未运行,尝试启动服务\n const startArgs = [\"start\", \"--daemon\"];\n const child = spawn(\"xiaozhi\", startArgs, {\n detached: true,\n stdio: \"ignore\",\n env: {\n ...process.env,\n XIAOZHI_CONFIG_DIR: process.env.XIAOZHI_CONFIG_DIR || process.cwd(),\n },\n });\n child.unref();\n this.logger.info(\"MCP 服务启动命令已发送\");\n return;\n }\n\n // 获取服务运行模式\n const isDaemon = status.mode === \"daemon\";\n\n // 执行重启命令\n const restartArgs = [\"restart\"];\n if (isDaemon) {\n restartArgs.push(\"--daemon\");\n }\n\n // 在子进程中执行重启命令\n const child = spawn(\"xiaozhi\", restartArgs, {\n detached: true,\n stdio: \"ignore\",\n env: {\n ...process.env,\n XIAOZHI_CONFIG_DIR: process.env.XIAOZHI_CONFIG_DIR || process.cwd(),\n },\n });\n\n child.unref();\n this.logger.info(\"MCP 服务重启命令已发送\");\n } catch (error) {\n this.logger.error(\"重启服务失败:\", error);\n throw error;\n }\n }\n\n /**\n * 停止服务\n * POST /api/services/stop\n */\n async stopService(c: Context): Promise<Response> {\n try {\n this.logger.info(\"处理服务停止请求\");\n\n // 执行停止命令\n const stopArgs = [\"stop\"];\n const child = spawn(\"xiaozhi\", stopArgs, {\n detached: true,\n stdio: \"ignore\",\n env: {\n ...process.env,\n XIAOZHI_CONFIG_DIR: process.env.XIAOZHI_CONFIG_DIR || process.cwd(),\n },\n });\n\n child.unref();\n this.logger.info(\"MCP 服务停止命令已发送\");\n\n return c.json(this.createSuccessResponse(null, \"停止请求已接收\"));\n } catch (error) {\n this.logger.error(\"处理停止请求失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"STOP_REQUEST_ERROR\",\n error instanceof Error ? error.message : \"处理停止请求失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 启动服务\n * POST /api/services/start\n */\n async startService(c: Context): Promise<Response> {\n try {\n this.logger.info(\"处理服务启动请求\");\n\n // 执行启动命令\n const startArgs = [\"start\", \"--daemon\"];\n const child = spawn(\"xiaozhi\", startArgs, {\n detached: true,\n stdio: \"ignore\",\n env: {\n ...process.env,\n XIAOZHI_CONFIG_DIR: process.env.XIAOZHI_CONFIG_DIR || process.cwd(),\n },\n });\n\n child.unref();\n this.logger.info(\"MCP 服务启动命令已发送\");\n\n return c.json(this.createSuccessResponse(null, \"启动请求已接收\"));\n } catch (error) {\n this.logger.error(\"处理启动请求失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"START_REQUEST_ERROR\",\n error instanceof Error ? error.message : \"处理启动请求失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 获取服务状态\n * GET /api/services/status\n */\n async getServiceStatus(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理获取服务状态请求\");\n\n const container = await createContainer();\n const serviceManager = container.get(\"serviceManager\") as any;\n const status = await serviceManager.getStatus();\n\n this.logger.debug(\"获取服务状态成功\");\n return c.json(this.createSuccessResponse(status));\n } catch (error) {\n this.logger.error(\"获取服务状态失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"SERVICE_STATUS_READ_ERROR\",\n error instanceof Error ? error.message : \"获取服务状态失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 获取服务健康状态\n * GET /api/services/health\n */\n async getServiceHealth(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理获取服务健康状态请求\");\n\n // 简单的健康检查\n const health = {\n status: \"healthy\",\n timestamp: Date.now(),\n uptime: process.uptime(),\n memory: process.memoryUsage(),\n version: process.version,\n };\n\n this.logger.debug(\"获取服务健康状态成功\");\n return c.json(this.createSuccessResponse(health));\n } catch (error) {\n this.logger.error(\"获取服务健康状态失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"SERVICE_HEALTH_READ_ERROR\",\n error instanceof Error ? error.message : \"获取服务健康状态失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n}\n","import { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { Context } from \"hono\";\nimport { type Logger, logger } from \"../Logger.js\";\n\n/**\n * 静态文件处理器\n */\nexport class StaticFileHandler {\n private logger: Logger;\n private webPath: string | null = null;\n\n constructor() {\n this.logger = logger.withTag(\"StaticFileHandler\");\n this.initializeWebPath();\n }\n\n /**\n * 初始化 Web 路径\n */\n private initializeWebPath(): void {\n try {\n // 获取当前文件所在目录\n const __dirname = dirname(fileURLToPath(import.meta.url));\n\n this.logger.debug(`当前文件目录: ${__dirname}`);\n\n // 确定web目录路径\n // 无论是全局安装还是直接执行,实际运行的都是 dist/cli.js 或 dist/handlers/StaticFileHandler.js\n // 因此静态文件应该位于相对于 dist 目录的 ../web/dist 路径\n const possibleWebPaths = [\n // 主要路径:从 dist 目录向上查找 web/dist\n // 对于 dist/handlers/StaticFileHandler.js -> ../../web/dist\n // 对于 dist/cli.js -> ../web/dist\n join(__dirname, \"..\", \"..\", \"web\", \"dist\"),\n join(__dirname, \"..\", \"web\", \"dist\"),\n\n // 备用路径:查找未构建的 web 目录(开发模式)\n join(__dirname, \"..\", \"..\", \"web\"),\n join(__dirname, \"..\", \"web\"),\n\n // 兜底路径:从源码目录查找(开发模式下的源码执行)\n join(__dirname, \"..\", \"..\", \"..\", \"web\", \"dist\"),\n join(__dirname, \"..\", \"..\", \"..\", \"web\"),\n ];\n\n // 查找第一个存在的路径\n this.webPath =\n possibleWebPaths.find((p) => {\n const exists = existsSync(p);\n this.logger.debug(`检查路径 ${p}: ${exists ? \"存在\" : \"不存在\"}`);\n return exists;\n }) || null;\n\n if (this.webPath) {\n this.logger.info(`静态文件服务路径: ${this.webPath}`);\n } else {\n this.logger.warn(\"未找到静态文件目录\");\n this.logger.debug(\"尝试的路径:\", possibleWebPaths);\n }\n } catch (error) {\n this.logger.error(\"初始化静态文件路径失败:\", error);\n }\n }\n\n /**\n * 处理静态文件请求\n * GET /*\n */\n async handleStaticFile(c: Context): Promise<Response> {\n const pathname = new URL(c.req.url).pathname;\n\n try {\n this.logger.debug(`处理静态文件请求: ${pathname}`);\n\n if (!this.webPath) {\n return this.createErrorPage(c, \"找不到前端资源文件\");\n }\n\n // 处理路径\n let filePath = pathname;\n if (filePath === \"/\") {\n filePath = \"/index.html\";\n }\n\n // 安全性检查:防止路径遍历\n if (filePath.includes(\"..\")) {\n this.logger.warn(`路径遍历攻击尝试: ${filePath}`);\n return c.text(\"Forbidden\", 403);\n }\n\n const fullPath = join(this.webPath, filePath);\n\n // 检查文件是否存在\n if (!existsSync(fullPath)) {\n // 对于 SPA,返回 index.html\n const indexPath = join(this.webPath, \"index.html\");\n if (existsSync(indexPath)) {\n this.logger.debug(`SPA 回退到 index.html: ${pathname}`);\n return this.serveFile(c, indexPath, \"text/html\");\n }\n\n this.logger.debug(`文件不存在: ${fullPath}`);\n return c.text(\"Not Found\", 404);\n }\n\n // 确定 Content-Type\n const contentType = this.getContentType(fullPath);\n\n this.logger.debug(\n `服务静态文件: ${fullPath}, Content-Type: ${contentType}`\n );\n return this.serveFile(c, fullPath, contentType);\n } catch (error) {\n this.logger.error(`服务静态文件错误 (${pathname}):`, error);\n return c.text(\"Internal Server Error\", 500);\n }\n }\n\n /**\n * 服务文件\n */\n private async serveFile(\n c: Context,\n filePath: string,\n contentType: string\n ): Promise<Response> {\n try {\n const content = await readFile(filePath);\n\n // 对于文本文件,返回字符串;对于二进制文件,返回 ArrayBuffer\n if (\n contentType.startsWith(\"text/\") ||\n contentType.includes(\"javascript\") ||\n contentType.includes(\"json\")\n ) {\n return c.text(content.toString(), 200, { \"Content-Type\": contentType });\n }\n\n return c.body(content, 200, { \"Content-Type\": contentType });\n } catch (error) {\n this.logger.error(`读取文件失败: ${filePath}`, error);\n throw error;\n }\n }\n\n /**\n * 获取文件的 Content-Type\n */\n private getContentType(filePath: string): string {\n const ext = filePath.split(\".\").pop()?.toLowerCase();\n\n const contentTypes: Record<string, string> = {\n html: \"text/html\",\n htm: \"text/html\",\n js: \"application/javascript\",\n mjs: \"application/javascript\",\n css: \"text/css\",\n json: \"application/json\",\n png: \"image/png\",\n jpg: \"image/jpeg\",\n jpeg: \"image/jpeg\",\n gif: \"image/gif\",\n svg: \"image/svg+xml\",\n ico: \"image/x-icon\",\n woff: \"font/woff\",\n woff2: \"font/woff2\",\n ttf: \"font/ttf\",\n eot: \"application/vnd.ms-fontobject\",\n pdf: \"application/pdf\",\n txt: \"text/plain\",\n xml: \"application/xml\",\n zip: \"application/zip\",\n tar: \"application/x-tar\",\n gz: \"application/gzip\",\n };\n\n return contentTypes[ext || \"\"] || \"application/octet-stream\";\n }\n\n /**\n * 创建错误页面\n */\n private createErrorPage(c: Context, message: string): Response {\n const errorHtml = `\n <!DOCTYPE html>\n <html>\n <head>\n <title>小智配置管理</title>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <style>\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n max-width: 800px;\n margin: 50px auto;\n padding: 20px;\n line-height: 1.6;\n color: #333;\n }\n .error {\n color: #e53e3e;\n background: #fed7d7;\n padding: 20px;\n border-radius: 8px;\n border-left: 4px solid #e53e3e;\n }\n .info {\n background: #e6f3ff;\n padding: 20px;\n border-radius: 8px;\n border-left: 4px solid #0066cc;\n margin-top: 20px;\n }\n pre {\n background: #f5f5f5;\n padding: 10px;\n border-radius: 4px;\n overflow-x: auto;\n }\n h1 {\n color: #2d3748;\n margin-bottom: 20px;\n }\n </style>\n </head>\n <body>\n <h1>小智配置管理</h1>\n <div class=\"error\">\n <p><strong>错误:</strong>${message}</p>\n </div>\n <div class=\"info\">\n <p><strong>解决方案:</strong></p>\n <p>请先构建前端项目:</p>\n <pre>cd web && pnpm install && pnpm build</pre>\n <p>然后重新启动服务器。</p>\n </div>\n </body>\n </html>\n `;\n\n return c.html(errorHtml);\n }\n\n /**\n * 检查静态文件目录是否存在\n */\n isWebPathAvailable(): boolean {\n return this.webPath !== null && existsSync(this.webPath);\n }\n\n /**\n * 获取静态文件目录路径\n */\n getWebPath(): string | null {\n return this.webPath;\n }\n\n /**\n * 重新初始化 Web 路径\n */\n reinitializeWebPath(): void {\n this.initializeWebPath();\n }\n}\n","import type { Context } from \"hono\";\nimport { type Logger, logger } from \"../Logger.js\";\nimport type { StatusService } from \"../services/StatusService.js\";\n\n/**\n * 统一响应格式接口\n */\ninterface ApiErrorResponse {\n error: {\n code: string;\n message: string;\n details?: any;\n };\n}\n\ninterface ApiSuccessResponse<T = any> {\n success: boolean;\n data?: T;\n message?: string;\n}\n\n/**\n * 状态 API 处理器\n */\nexport class StatusApiHandler {\n private logger: Logger;\n private statusService: StatusService;\n\n constructor(statusService: StatusService) {\n this.logger = logger.withTag(\"StatusApiHandler\");\n this.statusService = statusService;\n }\n\n /**\n * 创建统一的错误响应\n */\n private createErrorResponse(\n code: string,\n message: string,\n details?: any\n ): ApiErrorResponse {\n return {\n error: {\n code,\n message,\n details,\n },\n };\n }\n\n /**\n * 创建统一的成功响应\n */\n private createSuccessResponse<T>(\n data?: T,\n message?: string\n ): ApiSuccessResponse<T> {\n return {\n success: true,\n data,\n message,\n };\n }\n\n /**\n * 获取完整状态\n * GET /api/status\n */\n async getStatus(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理获取状态请求\");\n const status = this.statusService.getFullStatus();\n this.logger.debug(\"获取状态成功\");\n return c.json(this.createSuccessResponse(status));\n } catch (error) {\n this.logger.error(\"获取状态失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"STATUS_READ_ERROR\",\n error instanceof Error ? error.message : \"获取状态失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 获取客户端状态\n * GET /api/status/client\n */\n async getClientStatus(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理获取客户端状态请求\");\n const clientStatus = this.statusService.getClientStatus();\n this.logger.debug(\"获取客户端状态成功\");\n return c.json(this.createSuccessResponse(clientStatus));\n } catch (error) {\n this.logger.error(\"获取客户端状态失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"CLIENT_STATUS_READ_ERROR\",\n error instanceof Error ? error.message : \"获取客户端状态失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 获取重启状态\n * GET /api/status/restart\n */\n async getRestartStatus(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理获取重启状态请求\");\n const restartStatus = this.statusService.getRestartStatus();\n this.logger.debug(\"获取重启状态成功\");\n return c.json(this.createSuccessResponse(restartStatus));\n } catch (error) {\n this.logger.error(\"获取重启状态失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"RESTART_STATUS_READ_ERROR\",\n error instanceof Error ? error.message : \"获取重启状态失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 检查客户端是否连接\n * GET /api/status/connected\n */\n async checkClientConnected(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理检查客户端连接请求\");\n const connected = this.statusService.isClientConnected();\n this.logger.debug(`客户端连接状态: ${connected}`);\n return c.json(this.createSuccessResponse({ connected }));\n } catch (error) {\n this.logger.error(\"检查客户端连接失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"CLIENT_CONNECTION_CHECK_ERROR\",\n error instanceof Error ? error.message : \"检查客户端连接失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 获取最后心跳时间\n * GET /api/status/heartbeat\n */\n async getLastHeartbeat(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理获取最后心跳时间请求\");\n const lastHeartbeat = this.statusService.getLastHeartbeat();\n this.logger.debug(\"获取最后心跳时间成功\");\n return c.json(this.createSuccessResponse({ lastHeartbeat }));\n } catch (error) {\n this.logger.error(\"获取最后心跳时间失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"HEARTBEAT_READ_ERROR\",\n error instanceof Error ? error.message : \"获取最后心跳时间失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 获取活跃的 MCP 服务器列表\n * GET /api/status/mcp-servers\n */\n async getActiveMCPServers(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理获取活跃 MCP 服务器请求\");\n const servers = this.statusService.getActiveMCPServers();\n this.logger.debug(\"获取活跃 MCP 服务器成功\");\n return c.json(this.createSuccessResponse({ servers }));\n } catch (error) {\n this.logger.error(\"获取活跃 MCP 服务器失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"ACTIVE_MCP_SERVERS_READ_ERROR\",\n error instanceof Error ? error.message : \"获取活跃 MCP 服务器失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 更新客户端状态\n * PUT /api/status/client\n */\n async updateClientStatus(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理更新客户端状态请求\");\n const statusUpdate = await c.req.json();\n\n // 验证请求体\n if (!statusUpdate || typeof statusUpdate !== \"object\") {\n const errorResponse = this.createErrorResponse(\n \"INVALID_REQUEST_BODY\",\n \"请求体必须是有效的状态对象\"\n );\n return c.json(errorResponse, 400);\n }\n\n this.statusService.updateClientInfo(statusUpdate, \"http-api\");\n this.logger.info(\"客户端状态更新成功\");\n\n return c.json(this.createSuccessResponse(null, \"客户端状态更新成功\"));\n } catch (error) {\n this.logger.error(\"更新客户端状态失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"CLIENT_STATUS_UPDATE_ERROR\",\n error instanceof Error ? error.message : \"更新客户端状态失败\"\n );\n return c.json(errorResponse, 400);\n }\n }\n\n /**\n * 设置活跃的 MCP 服务器列表\n * PUT /api/status/mcp-servers\n */\n async setActiveMCPServers(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理设置活跃 MCP 服务器请求\");\n const { servers } = await c.req.json();\n\n // 验证请求体\n if (!Array.isArray(servers)) {\n const errorResponse = this.createErrorResponse(\n \"INVALID_REQUEST_BODY\",\n \"servers 必须是字符串数组\"\n );\n return c.json(errorResponse, 400);\n }\n\n this.statusService.setActiveMCPServers(servers);\n this.logger.info(\"活跃 MCP 服务器设置成功\");\n\n return c.json(\n this.createSuccessResponse(null, \"活跃 MCP 服务器设置成功\")\n );\n } catch (error) {\n this.logger.error(\"设置活跃 MCP 服务器失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"ACTIVE_MCP_SERVERS_UPDATE_ERROR\",\n error instanceof Error ? error.message : \"设置活跃 MCP 服务器失败\"\n );\n return c.json(errorResponse, 400);\n }\n }\n\n /**\n * 重置状态\n * POST /api/status/reset\n */\n async resetStatus(c: Context): Promise<Response> {\n try {\n this.logger.info(\"处理重置状态请求\");\n this.statusService.reset();\n this.logger.info(\"状态重置成功\");\n return c.json(this.createSuccessResponse(null, \"状态重置成功\"));\n } catch (error) {\n this.logger.error(\"重置状态失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"STATUS_RESET_ERROR\",\n error instanceof Error ? error.message : \"重置状态失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n}\n","import { type Logger, logger } from \"../Logger.js\";\nimport type { AppConfig } from \"../configManager.js\";\nimport { type EventBus, getEventBus } from \"./EventBus.js\";\nimport type { ClientInfo, RestartStatus } from \"./StatusService.js\";\n\n/**\n * WebSocket 客户端接口\n */\nexport interface WebSocketClient {\n id: string;\n ws: any; // WebSocket 实例\n readyState: number;\n send: (data: string) => void;\n}\n\n/**\n * 通知消息接口\n */\nexport interface NotificationMessage {\n type: string;\n data?: any;\n timestamp?: number;\n}\n\n/**\n * 通知服务 - 统一的通知管理服务\n */\nexport class NotificationService {\n private logger: Logger;\n private eventBus: EventBus;\n private clients: Map<string, WebSocketClient> = new Map();\n private messageQueue: Map<string, NotificationMessage[]> = new Map();\n private maxQueueSize = 100;\n\n constructor() {\n this.logger = logger.withTag(\"NotificationService\");\n this.eventBus = getEventBus();\n this.setupEventListeners();\n }\n\n /**\n * 设置事件监听器\n */\n private setupEventListeners(): void {\n // 监听配置更新事件\n this.eventBus.onEvent(\"config:updated\", (data) => {\n this.broadcastConfigUpdate(data.config);\n });\n\n // 监听状态更新事件\n this.eventBus.onEvent(\"status:updated\", (data) => {\n this.broadcastStatusUpdate(data.status);\n });\n\n // 监听重启状态事件\n this.eventBus.onEvent(\"service:restart:started\", (data) => {\n this.broadcastRestartStatus(\"restarting\", undefined, data.timestamp);\n });\n\n this.eventBus.onEvent(\"service:restart:completed\", (data) => {\n this.broadcastRestartStatus(\"completed\", undefined, data.timestamp);\n });\n\n this.eventBus.onEvent(\"service:restart:failed\", (data) => {\n this.broadcastRestartStatus(\"failed\", data.error.message, data.timestamp);\n });\n\n // 监听通知广播事件\n this.eventBus.onEvent(\"notification:broadcast\", (data) => {\n if (data.target) {\n this.sendToClient(data.target, data.type, data.data);\n } else {\n this.broadcast(data.type, data.data);\n }\n });\n }\n\n /**\n * 注册 WebSocket 客户端\n */\n registerClient(clientId: string, ws: any): void {\n try {\n const client: WebSocketClient = {\n id: clientId,\n ws,\n readyState: ws.readyState,\n send: (data: string) => {\n if (ws.readyState === 1) {\n // WebSocket.OPEN\n ws.send(data);\n }\n },\n };\n\n this.clients.set(clientId, client);\n this.logger.info(`WebSocket 客户端已注册: ${clientId}`);\n this.logger.debug(`当前客户端数量: ${this.clients.size}`);\n\n // 发送排队的消息\n this.sendQueuedMessages(clientId);\n\n // 发射客户端连接事件\n this.eventBus.emitEvent(\"websocket:client:connected\", {\n clientId,\n timestamp: Date.now(),\n });\n } catch (error) {\n this.logger.error(`注册客户端失败: ${clientId}`, error);\n this.eventBus.emitEvent(\"notification:error\", {\n error: error instanceof Error ? error : new Error(String(error)),\n type: \"client:register\",\n });\n }\n }\n\n /**\n * 注销 WebSocket 客户端\n */\n unregisterClient(clientId: string): void {\n try {\n if (this.clients.has(clientId)) {\n this.clients.delete(clientId);\n this.messageQueue.delete(clientId);\n this.logger.info(`WebSocket 客户端已注销: ${clientId}`);\n this.logger.debug(`剩余客户端数量: ${this.clients.size}`);\n\n // 发射客户端断开事件\n this.eventBus.emitEvent(\"websocket:client:disconnected\", {\n clientId,\n timestamp: Date.now(),\n });\n }\n } catch (error) {\n this.logger.error(`注销客户端失败: ${clientId}`, error);\n }\n }\n\n /**\n * 广播消息给所有客户端\n */\n broadcast(type: string, data?: any): void {\n const message: NotificationMessage = {\n type,\n data,\n timestamp: Date.now(),\n };\n\n this.logger.debug(`广播消息: ${type}`, { clientCount: this.clients.size });\n\n for (const [clientId, client] of this.clients) {\n this.sendMessageToClient(client, message, clientId);\n }\n }\n\n /**\n * 发送消息给特定客户端\n */\n sendToClient(clientId: string, type: string, data?: any): void {\n const message: NotificationMessage = {\n type,\n data,\n timestamp: Date.now(),\n };\n\n const client = this.clients.get(clientId);\n if (client) {\n this.sendMessageToClient(client, message, clientId);\n } else {\n // 客户端不在线,将消息加入队列\n this.queueMessage(clientId, message);\n }\n }\n\n /**\n * 发送消息给客户端\n */\n private sendMessageToClient(\n client: WebSocketClient,\n message: NotificationMessage,\n clientId: string\n ): void {\n try {\n if (client.ws.readyState === 1) {\n // WebSocket.OPEN\n const messageStr = JSON.stringify(message);\n client.send(messageStr);\n this.logger.debug(`消息已发送给客户端 ${clientId}: ${message.type}`);\n } else {\n // 连接不可用,将消息加入队列\n this.queueMessage(clientId, message);\n this.logger.warn(`客户端 ${clientId} 连接不可用,消息已加入队列`);\n }\n } catch (error) {\n this.logger.error(`发送消息给客户端 ${clientId} 失败:`, error);\n this.queueMessage(clientId, message);\n this.eventBus.emitEvent(\"notification:error\", {\n error: error instanceof Error ? error : new Error(String(error)),\n type: \"message:send\",\n });\n }\n }\n\n /**\n * 将消息加入队列\n */\n private queueMessage(clientId: string, message: NotificationMessage): void {\n if (!this.messageQueue.has(clientId)) {\n this.messageQueue.set(clientId, []);\n }\n\n const queue = this.messageQueue.get(clientId)!;\n queue.push(message);\n\n // 限制队列大小\n if (queue.length > this.maxQueueSize) {\n queue.shift(); // 移除最旧的消息\n this.logger.warn(`客户端 ${clientId} 消息队列已满,移除最旧消息`);\n }\n }\n\n /**\n * 发送排队的消息\n */\n private sendQueuedMessages(clientId: string): void {\n const queue = this.messageQueue.get(clientId);\n if (!queue || queue.length === 0) {\n return;\n }\n\n const client = this.clients.get(clientId);\n if (!client) {\n return;\n }\n\n this.logger.info(`发送 ${queue.length} 条排队消息给客户端 ${clientId}`);\n\n for (const message of queue) {\n this.sendMessageToClient(client, message, clientId);\n }\n\n // 清空队列\n this.messageQueue.delete(clientId);\n }\n\n /**\n * 广播配置更新\n */\n broadcastConfigUpdate(config: AppConfig): void {\n this.broadcast(\"configUpdate\", config);\n }\n\n /**\n * 广播状态更新\n */\n broadcastStatusUpdate(status: ClientInfo): void {\n this.broadcast(\"statusUpdate\", status);\n }\n\n /**\n * 广播重启状态\n */\n broadcastRestartStatus(\n status: \"restarting\" | \"completed\" | \"failed\",\n error?: string,\n timestamp?: number\n ): void {\n const restartStatus: RestartStatus = {\n status,\n error,\n timestamp: timestamp || Date.now(),\n };\n\n this.broadcast(\"restartStatus\", restartStatus);\n }\n\n /**\n * 获取客户端统计信息\n */\n getClientStats(): {\n totalClients: number;\n connectedClients: number;\n queuedMessages: number;\n } {\n const connectedClients = Array.from(this.clients.values()).filter(\n (client) => client.ws.readyState === 1\n ).length;\n\n const queuedMessages = Array.from(this.messageQueue.values()).reduce(\n (total, queue) => total + queue.length,\n 0\n );\n\n return {\n totalClients: this.clients.size,\n connectedClients,\n queuedMessages,\n };\n }\n\n /**\n * 清理断开的客户端\n */\n cleanupDisconnectedClients(): void {\n const disconnectedClients: string[] = [];\n\n for (const [clientId, client] of this.clients) {\n if (client.ws.readyState !== 1) {\n // Not WebSocket.OPEN\n disconnectedClients.push(clientId);\n }\n }\n\n for (const clientId of disconnectedClients) {\n this.unregisterClient(clientId);\n }\n\n if (disconnectedClients.length > 0) {\n this.logger.info(`清理了 ${disconnectedClients.length} 个断开的客户端`);\n }\n }\n\n /**\n * 销毁通知服务\n */\n destroy(): void {\n this.logger.info(\"销毁通知服务\");\n this.clients.clear();\n this.messageQueue.clear();\n }\n}\n","import { type Logger, logger } from \"../Logger.js\";\nimport { type EventBus, getEventBus } from \"./EventBus.js\";\n\n/**\n * 客户端信息接口\n */\nexport interface ClientInfo {\n status: \"connected\" | \"disconnected\";\n mcpEndpoint: string;\n activeMCPServers: string[];\n lastHeartbeat?: number;\n}\n\n/**\n * 重启状态接口\n */\nexport interface RestartStatus {\n status: \"restarting\" | \"completed\" | \"failed\";\n error?: string;\n timestamp: number;\n}\n\n/**\n * 状态服务 - 统一的状态管理服务\n */\nexport class StatusService {\n private logger: Logger;\n private eventBus: EventBus;\n private clientInfo: ClientInfo = {\n status: \"disconnected\",\n mcpEndpoint: \"\",\n activeMCPServers: [],\n };\n private restartStatus?: RestartStatus;\n private heartbeatTimeout?: NodeJS.Timeout;\n private readonly HEARTBEAT_TIMEOUT = 35000; // 35 seconds\n\n constructor() {\n this.logger = logger.withTag(\"StatusService\");\n this.eventBus = getEventBus();\n }\n\n /**\n * 获取客户端状态\n */\n getClientStatus(): ClientInfo {\n return { ...this.clientInfo };\n }\n\n /**\n * 更新客户端信息\n */\n updateClientInfo(info: Partial<ClientInfo>, source = \"unknown\"): void {\n try {\n const oldStatus = { ...this.clientInfo };\n this.clientInfo = { ...this.clientInfo, ...info };\n\n if (info.lastHeartbeat) {\n this.clientInfo.lastHeartbeat = Date.now();\n }\n\n // Reset heartbeat timeout when receiving client status\n if (info.status === \"connected\") {\n this.resetHeartbeatTimeout();\n }\n\n this.logger.debug(`客户端状态更新,来源: ${source}`, {\n old: oldStatus,\n new: this.clientInfo,\n });\n\n // 发射状态更新事件\n this.eventBus.emitEvent(\"status:updated\", {\n status: this.clientInfo,\n source,\n });\n } catch (error) {\n this.logger.error(\"更新客户端状态失败:\", error);\n this.eventBus.emitEvent(\"status:error\", {\n error: error instanceof Error ? error : new Error(String(error)),\n operation: \"updateClientInfo\",\n });\n }\n }\n\n /**\n * 获取重启状态\n */\n getRestartStatus(): RestartStatus | undefined {\n return this.restartStatus ? { ...this.restartStatus } : undefined;\n }\n\n /**\n * 更新重启状态\n */\n updateRestartStatus(\n status: \"restarting\" | \"completed\" | \"failed\",\n error?: string\n ): void {\n try {\n this.restartStatus = {\n status,\n error,\n timestamp: Date.now(),\n };\n\n this.logger.info(`重启状态更新: ${status}`, { error });\n\n // 根据状态发射不同的事件\n switch (status) {\n case \"restarting\":\n this.eventBus.emitEvent(\"service:restart:started\", {\n timestamp: this.restartStatus.timestamp,\n });\n break;\n case \"completed\":\n this.eventBus.emitEvent(\"service:restart:completed\", {\n timestamp: this.restartStatus.timestamp,\n });\n break;\n case \"failed\":\n this.eventBus.emitEvent(\"service:restart:failed\", {\n error: new Error(error || \"重启失败\"),\n timestamp: this.restartStatus.timestamp,\n });\n break;\n }\n } catch (error) {\n this.logger.error(\"更新重启状态失败:\", error);\n this.eventBus.emitEvent(\"status:error\", {\n error: error instanceof Error ? error : new Error(String(error)),\n operation: \"updateRestartStatus\",\n });\n }\n }\n\n /**\n * 获取完整状态信息\n */\n getFullStatus(): {\n client: ClientInfo;\n restart?: RestartStatus;\n timestamp: number;\n } {\n return {\n client: this.getClientStatus(),\n restart: this.getRestartStatus(),\n timestamp: Date.now(),\n };\n }\n\n /**\n * 重置心跳超时\n */\n private resetHeartbeatTimeout(): void {\n // Clear existing timeout\n if (this.heartbeatTimeout) {\n clearTimeout(this.heartbeatTimeout);\n }\n\n // Set new timeout\n this.heartbeatTimeout = setTimeout(() => {\n this.logger.warn(\"客户端心跳超时,标记为断开连接\");\n this.updateClientInfo({ status: \"disconnected\" }, \"heartbeat-timeout\");\n }, this.HEARTBEAT_TIMEOUT);\n }\n\n /**\n * 清除心跳超时\n */\n clearHeartbeatTimeout(): void {\n if (this.heartbeatTimeout) {\n clearTimeout(this.heartbeatTimeout);\n this.heartbeatTimeout = undefined;\n }\n }\n\n /**\n * 检查客户端是否连接\n */\n isClientConnected(): boolean {\n return this.clientInfo.status === \"connected\";\n }\n\n /**\n * 获取最后心跳时间\n */\n getLastHeartbeat(): number | undefined {\n return this.clientInfo.lastHeartbeat;\n }\n\n /**\n * 获取活跃的 MCP 服务器列表\n */\n getActiveMCPServers(): string[] {\n return [...this.clientInfo.activeMCPServers];\n }\n\n /**\n * 设置活跃的 MCP 服务器列表\n */\n setActiveMCPServers(servers: string[]): void {\n this.updateClientInfo(\n { activeMCPServers: [...servers] },\n \"mcp-servers-update\"\n );\n }\n\n /**\n * 设置 MCP 端点\n */\n setMcpEndpoint(endpoint: string): void {\n this.updateClientInfo({ mcpEndpoint: endpoint }, \"mcp-endpoint-update\");\n }\n\n /**\n * 重置状态\n */\n reset(): void {\n this.logger.info(\"重置状态服务\");\n this.clearHeartbeatTimeout();\n this.clientInfo = {\n status: \"disconnected\",\n mcpEndpoint: \"\",\n activeMCPServers: [],\n };\n this.restartStatus = undefined;\n }\n\n /**\n * 销毁状态服务\n */\n destroy(): void {\n this.logger.info(\"销毁状态服务\");\n this.clearHeartbeatTimeout();\n this.reset();\n }\n}\n","import { createServer } from \"node:http\";\nimport { serve } from \"@hono/node-server\";\nimport { Hono } from \"hono\";\nimport { cors } from \"hono/cors\";\nimport { WebSocketServer } from \"ws\";\nimport { type Logger, logger } from \"./Logger.js\";\nimport { ProxyMCPServer, type Tool } from \"./ProxyMCPServer.js\";\nimport { convertLegacyToNew } from \"./adapters/ConfigAdapter.js\";\nimport { createContainer } from \"./cli/Container.js\";\nimport { configManager } from \"./configManager.js\";\nimport type { AppConfig, MCPServerConfig } from \"./configManager.js\";\n// MCPTransportType 已移除,不再需要导入\nimport type { MCPServiceManager } from \"./services/MCPServiceManager.js\";\nimport { MCPServiceManagerSingleton } from \"./services/MCPServiceManagerSingleton.js\";\nimport type { XiaozhiConnectionManager } from \"./services/XiaozhiConnectionManager.js\";\nimport { XiaozhiConnectionManagerSingleton } from \"./services/XiaozhiConnectionManagerSingleton.js\";\n\nimport { ConfigApiHandler } from \"./handlers/ConfigApiHandler.js\";\nimport { HeartbeatHandler } from \"./handlers/HeartbeatHandler.js\";\nimport { RealtimeNotificationHandler } from \"./handlers/RealtimeNotificationHandler.js\";\nimport { ServiceApiHandler } from \"./handlers/ServiceApiHandler.js\";\nimport { StaticFileHandler } from \"./handlers/StaticFileHandler.js\";\nimport { StatusApiHandler } from \"./handlers/StatusApiHandler.js\";\nimport { ConfigService } from \"./services/ConfigService.js\";\n// 导入新的服务和处理器\nimport {\n type EventBus,\n destroyEventBus,\n getEventBus,\n} from \"./services/EventBus.js\";\nimport { NotificationService } from \"./services/NotificationService.js\";\nimport { StatusService } from \"./services/StatusService.js\";\n\n// 统一错误响应格式\ninterface ApiErrorResponse {\n error: {\n code: string;\n message: string;\n details?: any;\n };\n}\n\n// 统一成功响应格式\ninterface ApiSuccessResponse<T = any> {\n success: boolean;\n data?: T;\n message?: string;\n}\n\n// 硬编码常量已移除,改为配置驱动\ninterface ClientInfo {\n status: \"connected\" | \"disconnected\";\n mcpEndpoint: string;\n activeMCPServers: string[];\n lastHeartbeat?: number;\n}\n\n/**\n * WebServer - 主控制器,协调各个服务和处理器\n */\nexport class WebServer {\n private app: Hono;\n private httpServer: any = null;\n private wss: WebSocketServer | null = null;\n private logger: Logger;\n private port: number;\n\n // 事件总线\n private eventBus: EventBus;\n\n // 服务层\n private configService: ConfigService;\n private statusService: StatusService;\n private notificationService: NotificationService;\n\n // HTTP API 处理器\n private configApiHandler: ConfigApiHandler;\n private statusApiHandler: StatusApiHandler;\n private serviceApiHandler: ServiceApiHandler;\n private staticFileHandler: StaticFileHandler;\n\n // WebSocket 处理器\n private realtimeNotificationHandler: RealtimeNotificationHandler;\n private heartbeatHandler: HeartbeatHandler;\n\n // 心跳监控\n private heartbeatMonitorInterval?: NodeJS.Timeout;\n\n // 向后兼容的属性\n private proxyMCPServer: ProxyMCPServer | undefined;\n private xiaozhiConnectionManager: XiaozhiConnectionManager | undefined;\n private mcpServiceManager: MCPServiceManager | undefined;\n\n /**\n * 创建统一的错误响应\n * @deprecated 使用处理器中的方法替代\n */\n private createErrorResponse(\n code: string,\n message: string,\n details?: any\n ): ApiErrorResponse {\n return {\n error: {\n code,\n message,\n details,\n },\n };\n }\n\n /**\n * 创建统一的成功响应\n * @deprecated 使用处理器中的方法替代\n */\n private createSuccessResponse<T>(\n data?: T,\n message?: string\n ): ApiSuccessResponse<T> {\n return {\n success: true,\n data,\n message,\n };\n }\n\n /**\n * 记录废弃功能使用警告\n * @deprecated 使用处理器中的方法替代\n */\n private logDeprecationWarning(feature: string, alternative: string): void {\n this.logger.warn(\n `[DEPRECATED] ${feature} 功能已废弃,请使用 ${alternative} 替代`\n );\n }\n\n constructor(port?: number) {\n // 端口配置\n try {\n this.port = port ?? configManager.getWebUIPort() ?? 9999;\n } catch (error) {\n // 配置读取失败时使用默认端口\n this.port = port ?? 9999;\n }\n this.logger = logger.withTag(\"WebServer\");\n\n // 初始化事件总线\n this.eventBus = getEventBus();\n\n // 初始化服务层\n this.configService = new ConfigService();\n this.statusService = new StatusService();\n this.notificationService = new NotificationService();\n\n // 初始化 HTTP API 处理器\n this.configApiHandler = new ConfigApiHandler();\n this.statusApiHandler = new StatusApiHandler(this.statusService);\n this.serviceApiHandler = new ServiceApiHandler(this.statusService);\n this.staticFileHandler = new StaticFileHandler();\n\n // 初始化 WebSocket 处理器\n this.realtimeNotificationHandler = new RealtimeNotificationHandler(\n this.notificationService,\n this.statusService\n );\n this.heartbeatHandler = new HeartbeatHandler(\n this.statusService,\n this.notificationService\n );\n\n // 初始化 Hono 应用\n this.app = new Hono();\n this.setupMiddleware();\n this.setupRoutes();\n\n this.logger.info(\"WebServer 架构重构完成 - 第二阶段:模块化拆分\");\n\n // HTTP 服务器和 WebSocket 服务器将在 start() 方法中初始化\n }\n\n /**\n * 初始化所有连接(配置驱动)\n */\n private async initializeConnections(): Promise<void> {\n try {\n this.logger.info(\"开始初始化连接...\");\n\n // 1. 读取配置\n const config = await this.loadConfiguration();\n\n // 2. 初始化 MCP 服务管理器\n this.mcpServiceManager = await MCPServiceManagerSingleton.getInstance();\n\n // 3. 从配置加载 MCP 服务\n await this.loadMCPServicesFromConfig(config.mcpServers);\n\n // 4. 获取工具列表\n const tools = this.mcpServiceManager.getAllTools();\n this.logger.info(`已加载 ${tools.length} 个工具`);\n\n // 5. 初始化小智接入点连接\n await this.initializeXiaozhiConnection(config.mcpEndpoint, tools);\n\n this.logger.info(\"所有连接初始化完成\");\n } catch (error) {\n this.logger.error(\"连接初始化失败:\", error);\n throw error;\n }\n }\n\n /**\n * 加载配置文件\n */\n private async loadConfiguration(): Promise<{\n mcpEndpoint: string | string[];\n mcpServers: Record<string, MCPServerConfig>;\n webUIPort: number;\n }> {\n if (!configManager.configExists()) {\n throw new Error(\"配置文件不存在,请先运行 'xiaozhi init' 初始化配置\");\n }\n\n // 在加载配置前,先清理无效的服务器工具配置\n // 确保 mcpServerConfig 与 mcpServers 保持同步\n configManager.cleanupInvalidServerToolsConfig();\n\n const config = configManager.getConfig();\n\n return {\n mcpEndpoint: config.mcpEndpoint,\n mcpServers: config.mcpServers,\n webUIPort: config.webUI?.port ?? 9999,\n };\n }\n\n /**\n * 从配置加载 MCP 服务\n */\n private async loadMCPServicesFromConfig(\n mcpServers: Record<string, MCPServerConfig>\n ): Promise<void> {\n if (!this.mcpServiceManager) {\n throw new Error(\"MCPServiceManager 未初始化\");\n }\n\n for (const [name, config] of Object.entries(mcpServers)) {\n this.logger.info(`添加 MCP 服务配置: ${name}`);\n // 使用配置适配器转换配置格式\n const serviceConfig = convertLegacyToNew(name, config);\n this.mcpServiceManager.addServiceConfig(name, serviceConfig);\n }\n\n await this.mcpServiceManager.startAllServices();\n this.logger.info(\"所有 MCP 服务已启动\");\n }\n\n /**\n * 初始化小智接入点连接\n */\n private async initializeXiaozhiConnection(\n mcpEndpoint: string | string[],\n tools: Tool[]\n ): Promise<void> {\n // 处理多端点配置\n const endpoints = Array.isArray(mcpEndpoint) ? mcpEndpoint : [mcpEndpoint];\n const validEndpoints = endpoints.filter(\n (ep) => ep && !ep.includes(\"<请填写\")\n );\n\n if (validEndpoints.length === 0) {\n this.logger.warn(\"未配置有效的小智接入点,跳过连接\");\n return;\n }\n\n this.logger.info(\n `初始化小智接入点连接管理器,端点数量: ${validEndpoints.length}`\n );\n this.logger.debug(\"有效端点列表:\", validEndpoints);\n\n try {\n // 获取小智连接管理器单例\n this.xiaozhiConnectionManager =\n await XiaozhiConnectionManagerSingleton.getInstance({\n healthCheckInterval: 30000,\n reconnectInterval: 5000,\n maxReconnectAttempts: 10,\n loadBalanceStrategy: \"round-robin\",\n connectionTimeout: 10000,\n });\n\n // 设置 MCP 服务管理器\n if (this.mcpServiceManager) {\n this.xiaozhiConnectionManager.setServiceManager(this.mcpServiceManager);\n }\n\n // 初始化连接管理器\n await this.xiaozhiConnectionManager.initialize(validEndpoints, tools);\n\n // 连接所有端点\n await this.xiaozhiConnectionManager.connect();\n\n // 设置配置变更监听器\n this.xiaozhiConnectionManager.on(\"configChange\", (event: any) => {\n this.logger.info(`小智连接配置变更: ${event.type}`, event.data);\n });\n\n this.logger.info(\n `小智接入点连接管理器初始化完成,管理 ${validEndpoints.length} 个端点`\n );\n } catch (error) {\n this.logger.error(\"小智接入点连接管理器初始化失败:\", error);\n\n // 如果新的连接管理器失败,回退到原有的单连接模式(向后兼容)\n this.logger.warn(\"回退到单连接模式\");\n const validEndpoint = validEndpoints[0];\n\n this.logger.info(`初始化单个小智接入点连接: ${validEndpoint}`);\n this.proxyMCPServer = new ProxyMCPServer(validEndpoint);\n\n if (this.mcpServiceManager) {\n this.proxyMCPServer.setServiceManager(this.mcpServiceManager);\n }\n\n // 使用重连机制连接到小智接入点\n await this.connectWithRetry(\n () => this.proxyMCPServer!.connect(),\n \"小智接入点连接\"\n );\n this.logger.info(\"小智接入点连接成功(单连接模式)\");\n }\n }\n\n /**\n * 获取最佳的小智连接(用于向后兼容)\n */\n private getBestXiaozhiConnection(): ProxyMCPServer | null {\n if (this.xiaozhiConnectionManager) {\n return this.xiaozhiConnectionManager.selectBestConnection();\n }\n return this.proxyMCPServer || null;\n }\n\n /**\n * 获取小智连接状态信息\n */\n getXiaozhiConnectionStatus(): any {\n if (this.xiaozhiConnectionManager) {\n return {\n type: \"multi-endpoint\",\n manager: {\n healthyConnections:\n this.xiaozhiConnectionManager.getHealthyConnections().length,\n totalConnections:\n this.xiaozhiConnectionManager.getConnectionStatus().length,\n loadBalanceStats: this.xiaozhiConnectionManager.getLoadBalanceStats(),\n healthCheckStats: this.xiaozhiConnectionManager.getHealthCheckStats(),\n reconnectStats: this.xiaozhiConnectionManager.getReconnectStats(),\n },\n connections: this.xiaozhiConnectionManager.getConnectionStatus(),\n };\n }\n\n if (this.proxyMCPServer) {\n return {\n type: \"single-endpoint\",\n connected: true,\n endpoint: \"unknown\",\n };\n }\n\n return {\n type: \"none\",\n connected: false,\n };\n }\n\n /**\n * 带重试的连接方法\n */\n private async connectWithRetry<T>(\n connectionFn: () => Promise<T>,\n context: string,\n maxAttempts = 5,\n initialDelay = 1000,\n maxDelay = 30000,\n backoffMultiplier = 2\n ): Promise<T> {\n let lastError: Error | null = null;\n\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n this.logger.info(`${context} - 尝试连接 (${attempt}/${maxAttempts})`);\n return await connectionFn();\n } catch (error) {\n lastError = error as Error;\n this.logger.warn(`${context} - 连接失败:`, error);\n\n if (attempt < maxAttempts) {\n const delay = Math.min(\n initialDelay * backoffMultiplier ** (attempt - 1),\n maxDelay\n );\n this.logger.info(`${context} - ${delay}ms 后重试...`);\n await this.sleep(delay);\n }\n }\n }\n\n throw new Error(\n `${context} - 连接失败,已达到最大重试次数: ${lastError?.message}`\n );\n }\n\n /**\n * 延迟工具方法\n */\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n private setupMiddleware() {\n // CORS 中间件\n this.app?.use(\n \"*\",\n cors({\n origin: \"*\",\n allowMethods: [\"GET\", \"POST\", \"PUT\", \"OPTIONS\"],\n allowHeaders: [\"Content-Type\"],\n })\n );\n\n // 错误处理中间件\n this.app?.onError((err, c) => {\n this.logger.error(\"HTTP request error:\", err);\n const errorResponse = this.createErrorResponse(\n \"INTERNAL_SERVER_ERROR\",\n \"服务器内部错误\",\n process.env.NODE_ENV === \"development\" ? err.stack : undefined\n );\n return c.json(errorResponse, 500);\n });\n }\n\n private setupRoutes() {\n // 配置相关 API 路由\n this.app?.get(\"/api/config\", (c) => this.configApiHandler.getConfig(c));\n this.app?.put(\"/api/config\", (c) => this.configApiHandler.updateConfig(c));\n this.app?.get(\"/api/config/mcp-endpoint\", (c) =>\n this.configApiHandler.getMcpEndpoint(c)\n );\n this.app?.get(\"/api/config/mcp-endpoints\", (c) =>\n this.configApiHandler.getMcpEndpoints(c)\n );\n this.app?.get(\"/api/config/mcp-servers\", (c) =>\n this.configApiHandler.getMcpServers(c)\n );\n this.app?.get(\"/api/config/connection\", (c) =>\n this.configApiHandler.getConnectionConfig(c)\n );\n this.app?.post(\"/api/config/reload\", (c) =>\n this.configApiHandler.reloadConfig(c)\n );\n this.app?.get(\"/api/config/path\", (c) =>\n this.configApiHandler.getConfigPath(c)\n );\n this.app?.get(\"/api/config/exists\", (c) =>\n this.configApiHandler.checkConfigExists(c)\n );\n\n // 状态相关 API 路由\n this.app?.get(\"/api/status\", (c) => this.statusApiHandler.getStatus(c));\n this.app?.get(\"/api/status/client\", (c) =>\n this.statusApiHandler.getClientStatus(c)\n );\n this.app?.get(\"/api/status/restart\", (c) =>\n this.statusApiHandler.getRestartStatus(c)\n );\n this.app?.get(\"/api/status/connected\", (c) =>\n this.statusApiHandler.checkClientConnected(c)\n );\n this.app?.get(\"/api/status/heartbeat\", (c) =>\n this.statusApiHandler.getLastHeartbeat(c)\n );\n this.app?.get(\"/api/status/mcp-servers\", (c) =>\n this.statusApiHandler.getActiveMCPServers(c)\n );\n this.app?.put(\"/api/status/client\", (c) =>\n this.statusApiHandler.updateClientStatus(c)\n );\n this.app?.put(\"/api/status/mcp-servers\", (c) =>\n this.statusApiHandler.setActiveMCPServers(c)\n );\n this.app?.post(\"/api/status/reset\", (c) =>\n this.statusApiHandler.resetStatus(c)\n );\n\n // 服务相关 API 路由\n this.app?.post(\"/api/services/restart\", (c) =>\n this.serviceApiHandler.restartService(c)\n );\n this.app?.post(\"/api/services/stop\", (c) =>\n this.serviceApiHandler.stopService(c)\n );\n this.app?.post(\"/api/services/start\", (c) =>\n this.serviceApiHandler.startService(c)\n );\n this.app?.get(\"/api/services/status\", (c) =>\n this.serviceApiHandler.getServiceStatus(c)\n );\n this.app?.get(\"/api/services/health\", (c) =>\n this.serviceApiHandler.getServiceHealth(c)\n );\n\n // 处理未知的 API 路由\n this.app?.all(\"/api/*\", async (c) => {\n const errorResponse = this.createErrorResponse(\n \"API_NOT_FOUND\",\n `API 端点不存在: ${c.req.path}`\n );\n return c.json(errorResponse, 404);\n });\n\n // 静态文件服务 - 放在最后作为回退\n this.app.get(\"*\", (c) => this.staticFileHandler.handleStaticFile(c));\n }\n\n private setupWebSocket() {\n if (!this.wss) return;\n\n this.wss.on(\"connection\", (ws) => {\n // 生成客户端 ID\n const clientId = `client-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n\n this.logger.info(`WebSocket 客户端已连接: ${clientId}`);\n this.logger.debug(\n `当前 WebSocket 连接数: ${this.wss?.clients.size || 0}`\n );\n\n // 注册客户端到通知服务\n this.realtimeNotificationHandler.handleClientConnect(ws, clientId);\n this.heartbeatHandler.handleClientConnect(clientId);\n\n ws.on(\"message\", async (message) => {\n try {\n const data = JSON.parse(message.toString());\n\n // 根据消息类型分发到不同的处理器\n if (data.type === \"clientStatus\") {\n await this.heartbeatHandler.handleClientStatus(ws, data, clientId);\n } else {\n await this.realtimeNotificationHandler.handleMessage(\n ws,\n data,\n clientId\n );\n }\n } catch (error) {\n this.logger.error(\"WebSocket message error:\", error);\n const errorResponse = {\n type: \"error\",\n error: {\n code: \"MESSAGE_PARSE_ERROR\",\n message: error instanceof Error ? error.message : \"消息解析失败\",\n timestamp: Date.now(),\n },\n };\n ws.send(JSON.stringify(errorResponse));\n }\n });\n\n ws.on(\"close\", () => {\n this.logger.info(`WebSocket 客户端已断开连接: ${clientId}`);\n this.logger.debug(\n `剩余 WebSocket 连接数: ${this.wss?.clients.size || 0}`\n );\n\n // 处理客户端断开连接\n this.realtimeNotificationHandler.handleClientDisconnect(clientId);\n this.heartbeatHandler.handleClientDisconnect(clientId);\n });\n\n ws.on(\"error\", (error) => {\n this.logger.error(`WebSocket 连接错误 (${clientId}):`, error);\n });\n\n // 发送初始数据\n this.realtimeNotificationHandler.sendInitialData(ws, clientId);\n });\n }\n\n public async start(): Promise<void> {\n // 检查服务器是否已经启动\n if (this.httpServer) {\n this.logger.warn(\"Web server is already running\");\n return;\n }\n\n // 1. 启动 HTTP 服务器\n const server = serve({\n fetch: this.app.fetch,\n port: this.port,\n hostname: \"0.0.0.0\", // 绑定到所有网络接口,支持 Docker 部署\n createServer,\n });\n\n // 保存服务器实例\n this.httpServer = server;\n\n // 设置 WebSocket 服务器\n this.wss = new WebSocketServer({ server: this.httpServer });\n this.setupWebSocket();\n\n // 启动心跳监控\n this.heartbeatMonitorInterval =\n this.heartbeatHandler.startHeartbeatMonitoring();\n\n this.logger.info(`Web server listening on http://0.0.0.0:${this.port}`);\n this.logger.info(`Local access: http://localhost:${this.port}`);\n\n // 输出架构重构信息\n this.logger.info(\"=== 通信架构重构信息 - 第二阶段完成 ===\");\n this.logger.info(\"✅ 模块化拆分: HTTP/WebSocket 处理器独立\");\n this.logger.info(\n \"✅ 服务层抽象: ConfigService, StatusService, NotificationService\"\n );\n this.logger.info(\"✅ 事件驱动机制: EventBus 实现模块间解耦通信\");\n this.logger.info(\"✅ HTTP API 职责: 配置管理、状态查询、服务控制\");\n this.logger.info(\"✅ WebSocket 职责: 实时通知、心跳检测、事件广播\");\n this.logger.info(\n \"⚠️ 已废弃的 WebSocket 消息: getConfig, updateConfig, getStatus, restartService\"\n );\n this.logger.info(\"📖 推荐使用对应的 HTTP API 替代废弃的 WebSocket 消息\");\n this.logger.info(\"================================================\");\n\n // 2. 初始化所有连接(配置驱动)\n try {\n await this.initializeConnections();\n this.logger.info(\"所有连接初始化完成\");\n } catch (error) {\n this.logger.error(\"连接初始化失败,但 Web 服务器继续运行:\", error);\n // 连接失败不影响 Web 服务器启动,用户可以通过界面查看错误信息\n }\n }\n\n public stop(): Promise<void> {\n return new Promise((resolve) => {\n let resolved = false;\n\n const doResolve = () => {\n if (!resolved) {\n resolved = true;\n resolve();\n }\n };\n\n // 停止 MCP 客户端\n this.proxyMCPServer?.disconnect();\n\n // 停止心跳监控\n if (this.heartbeatMonitorInterval) {\n this.heartbeatHandler.stopHeartbeatMonitoring(\n this.heartbeatMonitorInterval\n );\n this.heartbeatMonitorInterval = undefined;\n }\n\n // 强制断开所有 WebSocket 客户端连接\n if (this.wss) {\n for (const client of this.wss.clients) {\n client.terminate();\n }\n\n // 关闭 WebSocket 服务器\n this.wss.close(() => {\n // 强制关闭 HTTP 服务器,不等待现有连接\n if (this.httpServer) {\n this.httpServer.close(() => {\n this.logger.info(\"Web server stopped\");\n doResolve();\n });\n } else {\n this.logger.info(\"Web server stopped\");\n doResolve();\n }\n\n // 设置超时,如果 2 秒内没有关闭则强制退出\n setTimeout(() => {\n this.logger.info(\"Web server force stopped\");\n doResolve();\n }, 2000);\n });\n } else {\n this.logger.info(\"Web server stopped\");\n doResolve();\n }\n });\n }\n\n /**\n * 销毁 WebServer 实例,清理所有资源\n */\n public destroy(): void {\n this.logger.info(\"销毁 WebServer 实例\");\n\n // 停止心跳监控\n if (this.heartbeatMonitorInterval) {\n this.heartbeatHandler.stopHeartbeatMonitoring(\n this.heartbeatMonitorInterval\n );\n this.heartbeatMonitorInterval = undefined;\n }\n\n // 销毁服务层\n this.statusService.destroy();\n this.notificationService.destroy();\n\n // 销毁事件总线\n destroyEventBus();\n\n // 断开 MCP 连接\n this.proxyMCPServer?.disconnect();\n\n this.logger.info(\"WebServer 实例已销毁\");\n }\n}\n","#!/usr/bin/env node\n\n/**\n * WebServer 独立启动脚本\n * 用于后台模式启动,替代原有的 adaptiveMCPPipe 启动方式\n */\n\n// 动态导入避免 CLI 代码执行\nasync function importModules() {\n const webServerModule = await import(\"./WebServer.js\");\n const configModule = await import(\"./configManager.js\");\n const loggerModule = await import(\"./Logger.js\");\n return {\n WebServer: webServerModule.WebServer,\n configManager: configModule.configManager,\n logger: loggerModule.logger,\n };\n}\n\nimport { spawn } from \"node:child_process\";\n\nasync function main() {\n const args = process.argv.slice(2);\n const openBrowser = args.includes(\"--open-browser\");\n\n try {\n // 动态导入模块\n const { WebServer, configManager, logger } = await importModules();\n\n // 初始化日志\n if (process.env.XIAOZHI_CONFIG_DIR) {\n logger.initLogFile(process.env.XIAOZHI_CONFIG_DIR);\n logger.enableFileLogging(true);\n }\n\n // 启动 WebServer\n const webServer = new WebServer();\n await webServer.start();\n\n logger.info(\"[WEBSERVER_STANDALONE] WebServer 启动成功\");\n\n // 自动打开浏览器\n if (openBrowser) {\n const port = configManager.getWebUIPort();\n const url = `http://localhost:${port}`;\n await openBrowserUrl(url);\n }\n\n // 处理退出信号\n const cleanup = async () => {\n logger.info(\"[WEBSERVER_STANDALONE] 正在停止 WebServer...\");\n await webServer.stop();\n process.exit(0);\n };\n\n process.on(\"SIGINT\", cleanup);\n process.on(\"SIGTERM\", cleanup);\n } catch (error) {\n console.error(\"WebServer 启动失败:\", error);\n process.exit(1);\n }\n}\n\n/**\n * 打开浏览器URL\n */\nasync function openBrowserUrl(url: string): Promise<void> {\n try {\n const platform = process.platform;\n\n let command: string;\n let args: string[];\n\n if (platform === \"darwin\") {\n command = \"open\";\n args = [url];\n } else if (platform === \"win32\") {\n command = \"start\";\n args = [\"\", url];\n } else {\n command = \"xdg-open\";\n args = [url];\n }\n\n spawn(command, args, { detached: true, stdio: \"ignore\" });\n console.log(`已尝试打开浏览器: ${url}`);\n } catch (error) {\n console.warn(\"自动打开浏览器失败:\", error);\n }\n}\n\n// 检查是否为直接执行\nif (import.meta.url === `file://${process.argv[1]}`) {\n main();\n}\n"],"mappings":"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","names":["Logger_exports","__export","Logger","logger","fs","path","chalk","pino","formatDateTime","date","year","month","day","hours","minutes","seconds","init_Logger","__esmMin","__name","streams","consoleStream","_label","number","err","levelMap","chunk","logObj","message","content","timestamp","levelInfo","text","coloredLevel","argsStr","arg","projectDir","enable","messageOrObj","args","errorArgs","enhancedObj","obj","enhanced","key","value","logDir","logName","i","oldFile","newFile","firstRotatedFile","maxSize","maxFiles","_tag","WebSocket","ToolCallError","ProxyMCPServer","init_ProxyMCPServer","__esmMin","init_Logger","code","message","data","__name","endpointUrl","options","logger","serviceManager","allTools","newTools","toolInfo","error","name","tool","tools","resolve","reject","reason","interval","jitterRange","jitter","request","toolsList","id","result","response","requestId","callRecord","params","errorCode","errorMessage","toolName","arguments_","lastError","attempt","delay","timeoutMs","timeoutId","duration","errorResponse","record","success","totalTime","r","sum","completedCalls","limit","records","config","SSEClientTransport","StdioClientTransport","StreamableHTTPClientTransport","EventSource","getLogger","logger","createTransport","config","createStdioTransport","createSSETransport","createModelScopeSSETransport","createStreamableHTTPTransport","url","options","createSSEOptions","createModelScopeSSEOptions","createStreamableHTTPOptions","token","__name","init","headers","validateConfig","getSupportedTypes","TransportFactory","init_TransportFactory","__esmMin","init_Logger","init_MCPService","Client","MCPTransportType","MCPService","init_MCPService","__esmMin","init_Logger","init_TransportFactory","__name","config","options","logger","level","message","args","taggedMessage","TransportFactory","resolve","reject","error","interval","jitterRange","jitter","tools","tool","t","name","arguments_","result","startTime","pingPromise","timeoutPromise","_","duration","connectionError","wasEnabled","isAbsolute","resolve","convertLegacyToNew","serviceName","legacyConfig","logger","ConfigValidationError","newConfig","convertByConfigType","validateNewConfig","error","isLocalConfig","convertLocalConfig","isSSEConfig","convertSSEConfig","isStreamableHTTPConfig","convertStreamableHTTPConfig","config","workingDir","resolvedArgs","arg","isRelativePath","resolvedPath","isModelScope","isModelScopeURL","baseConfig","path","url","MCPTransportType","init_ConfigAdapter","__esmMin","init_Logger","init_MCPService","message","configName","__name","getMcpServerCommunicationType","serverConfig","validateMcpServerConfig","serverName","error","init_mcpServerUtils","__esmMin","__name","configManager_exports","__export","ConfigManager","configManager","copyFileSync","existsSync","readFileSync","writeFileSync","dirname","resolve","fileURLToPath","commentJson","dayjs","JSON5","json5Writer","__dirname","DEFAULT_CONNECTION_CONFIG","init_configManager","__esmMin","init_Logger","init_mcpServerUtils","_ConfigManager","__name","possiblePaths","path","configDir","configFileNames","fileName","filePath","format","targetFileName","configPath","configFileFormat","configData","config","error","configObj","endpoint","serverName","serverConfig","validation","validateMcpServerConfig","toolName","ep","currentEndpoints","newEndpoints","newMcpServers","newConfig","toolsConfig","validServerNames","invalidServerNames","logger","enabled","description","configContent","json5WriterError","commentJsonError","connectionConfig","callTime","toolConfig","currentUsageCount","currentLastUsedTime","interval","timeout","modelScopeConfig","apiKey","webServer","webUIConfig","port","MCPServiceManager","MCPServiceManager_default","init_MCPServiceManager","__esmMin","init_Logger","init_configManager","init_MCPService","__name","configs","logger","configEntries","serviceName","config","service","MCPService","tools","t","error","tool","toolKey","allTools","toolInfo","configManager","toolName","arguments_","result","status","serviceStatus","name","enhancedConfig","modelScopeApiKey","nameOrConfig","finalConfig","currentServerConfigs","currentToolsConfig","newToolsConfig","currentToolConfig","currentToolNames","removedTools","addedTools","updatedTools","current","updated","currentConfig","newConfig","currentKeys","newKeys","key","currentTool","newTool","createInstance","MCPServiceManager_default","getInstance","instance","state","initPromise","reset","instanceId","lastError","error","cleanup","isInitialized","getStatus","forceReinitialize","getCurrentInstance","waitForInitialization","MCPServiceManagerSingleton","init_MCPServiceManagerSingleton","__esmMin","init_MCPServiceManager","__name","cleanupError","reason","EventEmitter","ReconnectStrategy","DEFAULT_OPTIONS","XiaozhiConnectionManager","init_XiaozhiConnectionManager","__esmMin","init_Logger","init_ProxyMCPServer","__name","options","logger","endpoints","tools","endpoint","error","connectionPromises","proxyServer","results","successCount","result","failureCount","connectionTime","disconnectPromises","timer","healthyConnections","status","manager","enabled","stats","successRate","existingTimer","valid","invalid","errors","validStrategies","newEndpoints","validEndpoints","invalidEndpoints","currentEndpoints","toAdd","ep","toRemove","toKeep","changeEvent","newOptions","oldOptions","config","excludeEndpoints","availableConnections","connection","selectedConnection","connections","randomIndex","connectionHealths","a","b","totalWeight","sum","item","randomWeight","conn","connectionWeights","weight","strategy","oldStrategy","failedEndpoint","backupConnection","backupEndpoint","targetEndpoints","prewarmPromises","currentMemory","memoryGrowth","growthPercentage","ProxyMCPServer","healthCheckPromises","startTime","responseTime","resolve","success","baseScore","increment","decrement","errorMessage","baseDelay","maxDelay","multiplier","attempts","delay","jitter","recentHistory","h","createInstance","options","XiaozhiConnectionManager","getInstance","instance","state","initPromise","reset","instanceId","lastError","error","cleanup","isInitialized","getStatus","forceReinitialize","getCurrentInstance","waitForInitialization","XiaozhiConnectionManagerSingleton","init_XiaozhiConnectionManagerSingleton","__esmMin","init_XiaozhiConnectionManager","__name","cleanupError","reason","EventEmitter","getEventBus","eventBusInstance","EventBus","destroyEventBus","init_EventBus","__esmMin","init_Logger","__name","logger","error","eventName","listenerCount","data","listener","stats","stat","sum","count","ConfigService","init_ConfigService","__esmMin","init_Logger","init_configManager","init_EventBus","__name","logger","getEventBus","config","configManager","error","newConfig","source","currentServers","name","serverName","toolsConfig","toolName","toolConfig","ConfigApiHandler","init_ConfigApiHandler","__esmMin","init_Logger","init_ConfigService","__name","logger","ConfigService","code","message","details","data","c","config","error","errorResponse","newConfig","endpoint","endpoints","servers","connection","path","exists","HeartbeatHandler","init_HeartbeatHandler","__esmMin","init_Logger","init_ConfigService","__name","statusService","notificationService","logger","ConfigService","ws","message","clientId","statusUpdate","error","code","errorResponse","lastHeartbeat","now","intervalId","response","RealtimeNotificationHandler","init_RealtimeNotificationHandler","__esmMin","init_Logger","init_ConfigService","init_EventBus","__name","notificationService","statusService","logger","ConfigService","getEventBus","ws","message","clientId","error","config","configData","status","code","errorResponse","feature","alternative","SERVICE_CONSTANTS","CONFIG_CONSTANTS","PATH_CONSTANTS","ERROR_CODES","TIMEOUT_CONSTANTS","init_Constants","__esmMin","ERROR_HELP_MESSAGES","COMMON_SOLUTIONS","ERROR_MESSAGES","init_ErrorMessages","__esmMin","init_Constants","ERROR_CODES","__name","errorCode","problemKey","error","context","CLIError","ConfigError","ServiceError","ValidationError","FileError","ProcessError","init_errors","__esmMin","init_Constants","_CLIError","message","code","exitCode","suggestions","__name","_ConfigError","ERROR_CODES","format","_ServiceError","pid","reason","_ValidationError","field","port","_FileError","filePath","fullMessage","_ProcessError","chalk","ErrorHandler","init_ErrorHandlers","__esmMin","init_ErrorMessages","init_errors","_ErrorHandler","__name","error","CLIError","suggestion","helpMessage","ERROR_MESSAGES","operation","context","message","suggestions","fs","path","FileUtils","init_FileUtils","__esmMin","init_errors","_FileUtils","__name","filePath","dirPath","FileError","encoding","error","content","options","dir","srcPath","destPath","destDir","srcDir","items","item","stats","result","itemPath","subItems","prefix","suffix","tempDir","timestamp","random","fileName","mode","basePath","FormatUtils","init_FormatUtils","__esmMin","__name","ms","seconds","minutes","hours","days","bytes","units","size","unitIndex","timestamp","format","date","pid","port","protocol","host","path","url","key","value","error","includeStack","message","items","bullet","item","data","keys","maxWidths","row","header","i","separator","width","rows","current","total","percentage","filled","empty","bar","percent","command","args","quotedArgs","arg","text","maxLength","suffix","obj","indent","trueText","falseText","tmpdir","path","fileURLToPath","PathUtils","init_PathUtils","__esmMin","init_Constants","init_FileUtils","_PathUtils","__name","configDir","CONFIG_CONSTANTS","SERVICE_CONSTANTS","projectDir","baseDir","PATH_CONSTANTS","__filename","scriptDir","possiblePaths","templatesDir","FileUtils","templateName","templatePath","projectRoot","filePath","format","fileName","inputPath","resolvedPath","resolvedBase","name","cliPath","distDir","segments","joinedPath","normalizedPath","execSync","PlatformUtils","init_PlatformUtils","__esmMin","init_Constants","init_errors","_PlatformUtils","__name","pid","cmdline","TIMEOUT_CONSTANTS","signal","attempts","maxAttempts","resolve","error","ProcessError","name","defaultValue","value","filePath","Validation","init_Validation","__esmMin","init_errors","_Validation","__name","port","ValidationError","format","validFormats","value","fieldName","options","url","parsedUrl","name","invalidChars","hasControlChars","char","jsonString","error","array","obj","requiredProps","prop","validValues","pattern","fs","path","fileURLToPath","VersionUtils","init_VersionUtils","__esmMin","init_errors","_VersionUtils","__name","__filename","currentDir","possiblePaths","packagePath","packageJson","error","FileError","version1","version2","v1Parts","v2Parts","maxLength","i","v1Part","v2Part","version","ProcessManager_exports","__export","ProcessManagerImpl","init_ProcessManager","__esmMin","init_errors","init_FileUtils","init_FormatUtils","init_PathUtils","init_PlatformUtils","__name","PathUtils","pidFilePath","FileUtils","pidContent","pidStr","startTimeStr","mode","pid","startTime","pidInfo","FileError","PlatformUtils","uptime","FormatUtils","error","ProcessError","attempts","maxAttempts","resolve","exists","isXiaozhi","DaemonManager_exports","__export","DaemonManagerImpl","spawn","fs","init_DaemonManager","__esmMin","init_errors","init_PathUtils","init_PlatformUtils","processManager","logger","__name","serverFactory","options","status","ServiceError","child","error","resolve","logFileName","logFilePath","PathUtils","command","args","PlatformUtils","tail","env","ProcessError","logDir","logStream","timestamp","code","signal","processInfo","TransportAdapter","init_TransportAdapter","__esmMin","init_Logger","__name","messageHandler","config","logger","message","response","error","errorResponse","id","errorCode","timestamp","random","state","oldState","newState","data","errorMessage","promise","timeoutMs","_","reject","randomUUID","express","HTTPAdapter","init_HTTPAdapter","__esmMin","init_TransportAdapter","TransportAdapter","__name","messageHandler","config","error","resolve","reject","client","message","req","res","next","clientId","sessionId","response","data","init_StdioAdapter","__esmMin","init_TransportAdapter","WebSocket","WebSocketServer","init_WebSocketAdapter","__esmMin","init_TransportAdapter","MCPMessageHandler","init_MCPMessageHandler","__esmMin","init_Logger","__name","serviceManager","logger","message","error","params","id","mcpTools","tool","result","errorCode","EventEmitter","ToolRegistry","ConnectionManager","UnifiedMCPServer","init_UnifiedMCPServer","__esmMin","init_Logger","init_MCPServiceManager","init_TransportAdapter","init_MCPMessageHandler","__name","serviceManager","logger","tool","toolName","id","transportName","state","connectionInfo","connection","conn","config","MCPServiceManager","MCPMessageHandler","error","name","adapter","createHTTPServer","config","logger","server","UnifiedMCPServer","messageHandler","httpAdapter","HTTPAdapter","init_ServerFactory","__esmMin","init_Logger","init_HTTPAdapter","init_StdioAdapter","init_WebSocketAdapter","init_UnifiedMCPServer","__name","MCPServer_exports","__export","MCPServer","EventEmitter","logger","init_MCPServer","__esmMin","init_Logger","init_ProxyMCPServer","init_configManager","init_ServerFactory","Logger","__name","port","httpConfig","createHTTPServer","connection","error","mcpEndpoint","configManager","ep","ProxyMCPServer","ServiceManager_exports","__export","ServiceManagerImpl","init_ServiceManager","__esmMin","init_errors","init_PathUtils","init_PlatformUtils","init_Validation","processManager","configManager","logger","__name","options","status","resolve","stopError","error","ServiceError","Validation","ConfigError","spawn","port","scriptPath","PathUtils","child","MCPServer","server","cleanup","mcpProxyPath","openBrowser","webServerPath","args","WebServer","url","platform","PlatformUtils","command","TemplateManager_exports","__export","TemplateManagerImpl","fs","path","init_TemplateManager","__esmMin","init_errors","init_FileUtils","init_PathUtils","init_Validation","__name","templatesDir","PathUtils","templates","templateDirs","dirent","templateName","templateInfo","FileError","Validation","templatePath","configPath","config","FileUtils","configContent","files","error","ValidationError","targetPath","options","requiredFiles","requiredFile","filePath","file","relativePath","variables","filesToProcess","pattern","basePath","regex","content","hasChanges","key","value","createContainer","DIContainer","init_Container","__esmMin","init_Logger","init_configManager","init_ErrorHandlers","init_FileUtils","init_FormatUtils","init_PathUtils","init_PlatformUtils","init_Validation","init_VersionUtils","_DIContainer","__name","key","factory","singleton","instance","factoryKeys","instanceKeys","container","VersionUtils","PlatformUtils","FormatUtils","FileUtils","PathUtils","Validation","configManager","logger","ErrorHandler","ProcessManagerModule","DaemonManagerModule","processManager","ServiceManagerModule","TemplateManagerModule","spawn","ServiceApiHandler","init_ServiceApiHandler","__esmMin","init_Logger","init_Container","init_EventBus","__name","statusService","logger","getEventBus","code","message","details","data","c","error","errorResponse","status","createContainer","isDaemon","restartArgs","health","existsSync","readFile","dirname","join","fileURLToPath","StaticFileHandler","init_StaticFileHandler","__esmMin","init_Logger","__name","logger","__dirname","possibleWebPaths","p","exists","error","c","pathname","filePath","fullPath","indexPath","contentType","content","ext","message","errorHtml","StatusApiHandler","init_StatusApiHandler","__esmMin","init_Logger","__name","statusService","logger","code","message","details","data","c","status","error","errorResponse","clientStatus","restartStatus","connected","lastHeartbeat","servers","statusUpdate","NotificationService","init_NotificationService","__esmMin","init_Logger","init_EventBus","__name","logger","getEventBus","data","clientId","ws","client","error","type","message","messageStr","queue","config","status","timestamp","restartStatus","connectedClients","queuedMessages","total","disconnectedClients","StatusService","init_StatusService","__esmMin","init_Logger","init_EventBus","__name","logger","getEventBus","info","source","oldStatus","error","status","servers","endpoint","WebServer_exports","__export","WebServer","createServer","serve","Hono","cors","WebSocketServer","init_WebServer","__esmMin","init_Logger","init_ProxyMCPServer","init_ConfigAdapter","init_configManager","init_MCPServiceManagerSingleton","init_XiaozhiConnectionManagerSingleton","init_ConfigApiHandler","init_HeartbeatHandler","init_RealtimeNotificationHandler","init_ServiceApiHandler","init_StaticFileHandler","init_StatusApiHandler","init_ConfigService","init_EventBus","init_NotificationService","init_StatusService","__name","code","message","details","data","feature","alternative","port","configManager","logger","getEventBus","ConfigService","StatusService","NotificationService","ConfigApiHandler","StatusApiHandler","ServiceApiHandler","StaticFileHandler","RealtimeNotificationHandler","HeartbeatHandler","config","MCPServiceManagerSingleton","tools","error","mcpServers","name","serviceConfig","convertLegacyToNew","mcpEndpoint","validEndpoints","ep","XiaozhiConnectionManagerSingleton","event","validEndpoint","ProxyMCPServer","connectionFn","context","maxAttempts","initialDelay","maxDelay","backoffMultiplier","lastError","attempt","delay","ms","resolve","err","c","errorResponse","ws","clientId","server","resolved","doResolve","client","destroyEventBus","spawn","importModules","webServerModule","configModule","loggerModule","__name","main","openBrowser","WebServer","configManager","logger","webServer","url","openBrowserUrl","cleanup","error","platform","command","args","spawn"]}
1
+ {"version":3,"sources":["../src/Logger.ts","../src/ProxyMCPServer.ts","../src/services/TransportFactory.ts","../src/services/MCPService.ts","../src/adapters/ConfigAdapter.ts","../src/utils/mcpServerUtils.ts","../src/configManager.ts","../src/services/MCPServiceManager.ts","../src/services/MCPServiceManagerSingleton.ts","../src/services/XiaozhiConnectionManager.ts","../src/services/XiaozhiConnectionManagerSingleton.ts","../src/services/EventBus.ts","../src/services/ConfigService.ts","../src/handlers/ConfigApiHandler.ts","../src/handlers/HeartbeatHandler.ts","../src/handlers/RealtimeNotificationHandler.ts","../src/cli/Constants.ts","../src/cli/errors/ErrorMessages.ts","../src/cli/errors/index.ts","../src/cli/errors/ErrorHandlers.ts","../src/cli/utils/FileUtils.ts","../src/cli/utils/FormatUtils.ts","../src/cli/utils/PathUtils.ts","../src/cli/utils/PlatformUtils.ts","../src/cli/utils/Validation.ts","../src/cli/utils/VersionUtils.ts","../src/cli/services/ProcessManager.ts","../src/cli/services/DaemonManager.ts","../src/transports/TransportAdapter.ts","../src/transports/HTTPAdapter.ts","../src/transports/StdioAdapter.ts","../src/transports/WebSocketAdapter.ts","../src/core/MCPMessageHandler.ts","../src/core/UnifiedMCPServer.ts","../src/core/ServerFactory.ts","../src/services/MCPServer.ts","../src/cli/services/ServiceManager.ts","../src/cli/services/TemplateManager.ts","../src/cli/Container.ts","../src/handlers/ServiceApiHandler.ts","../src/handlers/StaticFileHandler.ts","../src/handlers/StatusApiHandler.ts","../src/services/NotificationService.ts","../src/services/StatusService.ts","../src/WebServer.ts","../src/WebServerStandalone.ts"],"sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport chalk from \"chalk\";\nimport pino from \"pino\";\nimport type { Logger as PinoLogger } from \"pino\";\n\n/**\n * 格式化日期时间为 YYYY-MM-DD HH:mm:ss 格式\n * @param date 要格式化的日期对象\n * @returns 格式化后的日期时间字符串\n */\nfunction formatDateTime(date: Date): string {\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, \"0\");\n const day = String(date.getDate()).padStart(2, \"0\");\n const hours = String(date.getHours()).padStart(2, \"0\");\n const minutes = String(date.getMinutes()).padStart(2, \"0\");\n const seconds = String(date.getSeconds()).padStart(2, \"0\");\n\n return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;\n}\n\n/**\n * 高性能日志记录器,基于 pino 实现\n *\n * 特性:\n * - 支持控制台和文件双重输出\n * - 支持守护进程模式(仅文件输出)\n * - 支持结构化日志记录\n * - 自动日志文件轮转和管理\n * - 高性能异步写入\n * - 完整的错误堆栈跟踪\n */\nexport class Logger {\n private logFilePath: string | null = null;\n private pinoInstance: PinoLogger;\n private isDaemonMode: boolean;\n private maxLogFileSize = 10 * 1024 * 1024; // 10MB 默认最大文件大小\n private maxLogFiles = 5; // 最多保留5个日志文件\n\n constructor() {\n // 检查是否为守护进程模式\n this.isDaemonMode = process.env.XIAOZHI_DAEMON === \"true\";\n\n // 创建 pino 实例\n this.pinoInstance = this.createPinoInstance();\n }\n\n private createPinoInstance(): PinoLogger {\n const streams: pino.StreamEntry[] = [];\n\n // 控制台流 - 只在非守护进程模式下添加\n if (!this.isDaemonMode) {\n // 使用高性能的控制台输出流\n const consoleStream = this.createOptimizedConsoleStream();\n streams.push({\n level: \"debug\",\n stream: consoleStream,\n });\n }\n\n // 文件流 - 如果有日志文件路径,使用高性能异步写入\n if (this.logFilePath) {\n streams.push({\n level: \"debug\",\n stream: pino.destination({\n dest: this.logFilePath,\n sync: false, // 异步写入提升性能\n append: true,\n mkdir: true,\n }),\n });\n }\n\n // 如果没有流,创建一个空的流避免错误\n if (streams.length === 0) {\n streams.push({\n level: \"debug\",\n stream: pino.destination({ dest: \"/dev/null\" }),\n });\n }\n\n return pino(\n {\n level: \"debug\",\n // 高性能配置\n timestamp:\n pino.stdTimeFunctions?.isoTime || (() => `,\"time\":${Date.now()}`),\n formatters: {\n // 优化级别格式化\n level: (_label: string, number: number) => ({ level: number }),\n },\n // 禁用不必要的功能以提升性能\n base: null, // 不包含 pid 和 hostname\n serializers: {\n // 优化错误序列化,在测试环境中安全处理\n err: pino.stdSerializers?.err || ((err: any) => err),\n },\n },\n pino.multistream(streams, { dedupe: true })\n );\n }\n\n private createOptimizedConsoleStream() {\n // 预编译级别映射以提升性能\n const levelMap = new Map([\n [20, { name: \"DEBUG\", color: chalk.gray }],\n [30, { name: \"INFO\", color: chalk.blue }],\n [40, { name: \"WARN\", color: chalk.yellow }],\n [50, { name: \"ERROR\", color: chalk.red }],\n [60, { name: \"FATAL\", color: chalk.red }],\n ]);\n\n return {\n write: (chunk: string) => {\n try {\n const logObj = JSON.parse(chunk);\n const message = this.formatConsoleMessageOptimized(logObj, levelMap);\n // 在测试环境中安全地写入\n this.safeWrite(`${message}\\n`);\n } catch (error) {\n // 如果解析失败,直接输出原始内容\n this.safeWrite(chunk);\n }\n },\n };\n }\n\n /**\n * 安全地写入到 stderr,在测试环境中避免错误\n */\n private safeWrite(content: string): void {\n try {\n if (process.stderr && typeof process.stderr.write === \"function\") {\n process.stderr.write(content);\n } else if (console && typeof console.error === \"function\") {\n // 在测试环境中回退到 console.error\n console.error(content.trim());\n }\n } catch (error) {\n // 在极端情况下静默失败,避免测试中断\n }\n }\n\n private formatConsoleMessageOptimized(\n logObj: any,\n levelMap: Map<number, { name: string; color: (text: string) => string }>\n ): string {\n const timestamp = formatDateTime(new Date());\n\n const levelInfo = levelMap.get(logObj.level) || {\n name: \"UNKNOWN\",\n color: (text: string) => text,\n };\n const coloredLevel = levelInfo.color(`[${levelInfo.name}]`);\n\n // 处理结构化日志中的 args,保持兼容性\n let message = logObj.msg;\n if (logObj.args && Array.isArray(logObj.args)) {\n const argsStr = logObj.args\n .map((arg: any) =>\n typeof arg === \"object\" ? JSON.stringify(arg) : String(arg)\n )\n .join(\" \");\n message = `${message} ${argsStr}`;\n }\n\n return `[${timestamp}] ${coloredLevel} ${message}`;\n }\n\n /**\n * 初始化日志文件\n * @param projectDir 项目目录\n */\n initLogFile(projectDir: string): void {\n this.logFilePath = path.join(projectDir, \"xiaozhi.log\");\n\n // 检查并轮转日志文件\n this.rotateLogFileIfNeeded();\n\n // 确保日志文件存在\n if (!fs.existsSync(this.logFilePath)) {\n fs.writeFileSync(this.logFilePath, \"\");\n }\n\n // 重新创建 pino 实例以包含文件流\n this.pinoInstance = this.createPinoInstance();\n }\n\n /**\n * 设置是否启用文件日志\n * @param enable 是否启用\n */\n enableFileLogging(enable: boolean): void {\n // 在 pino 实现中,文件日志的启用/禁用通过重新创建实例来实现\n // 这里保持方法兼容性,但实际上文件日志在 initLogFile 时就已经启用\n if (enable && this.logFilePath) {\n // 重新创建 pino 实例以确保文件流正确配置\n this.pinoInstance = this.createPinoInstance();\n }\n }\n\n /**\n * 记录信息级别日志\n * @param message 日志消息\n * @param args 额外参数\n * @example\n * logger.info('用户登录', 'userId', 12345);\n * logger.info({ userId: 12345, action: 'login' }, '用户登录');\n */\n info(message: string, ...args: any[]): void;\n /**\n * 记录结构化信息级别日志\n * @param obj 结构化日志对象\n * @param message 可选的日志消息\n */\n info(obj: object, message?: string): void;\n info(messageOrObj: string | object, ...args: any[]): void {\n if (typeof messageOrObj === \"string\") {\n if (args.length === 0) {\n this.pinoInstance.info(messageOrObj);\n } else {\n this.pinoInstance.info({ args }, messageOrObj);\n }\n } else {\n // 结构化日志支持\n this.pinoInstance.info(messageOrObj, args[0] || \"\");\n }\n }\n\n success(message: string, ...args: any[]): void;\n success(obj: object, message?: string): void;\n success(messageOrObj: string | object, ...args: any[]): void {\n // success 映射为 info 级别,保持 API 兼容性\n if (typeof messageOrObj === \"string\") {\n if (args.length === 0) {\n this.pinoInstance.info(messageOrObj);\n } else {\n this.pinoInstance.info({ args }, messageOrObj);\n }\n } else {\n this.pinoInstance.info(messageOrObj, args[0] || \"\");\n }\n }\n\n warn(message: string, ...args: any[]): void;\n warn(obj: object, message?: string): void;\n warn(messageOrObj: string | object, ...args: any[]): void {\n if (typeof messageOrObj === \"string\") {\n if (args.length === 0) {\n this.pinoInstance.warn(messageOrObj);\n } else {\n this.pinoInstance.warn({ args }, messageOrObj);\n }\n } else {\n this.pinoInstance.warn(messageOrObj, args[0] || \"\");\n }\n }\n\n error(message: string, ...args: any[]): void;\n error(obj: object, message?: string): void;\n error(messageOrObj: string | object, ...args: any[]): void {\n if (typeof messageOrObj === \"string\") {\n if (args.length === 0) {\n this.pinoInstance.error(messageOrObj);\n } else {\n // 改进错误处理 - 特殊处理 Error 对象\n const errorArgs = args.map((arg) => {\n if (arg instanceof Error) {\n return {\n message: arg.message,\n stack: arg.stack,\n name: arg.name,\n cause: arg.cause,\n };\n }\n return arg;\n });\n this.pinoInstance.error({ args: errorArgs }, messageOrObj);\n }\n } else {\n // 结构化错误日志,自动提取错误信息\n const enhancedObj = this.enhanceErrorObject(messageOrObj);\n this.pinoInstance.error(enhancedObj, args[0] || \"\");\n }\n }\n\n debug(message: string, ...args: any[]): void;\n debug(obj: object, message?: string): void;\n debug(messageOrObj: string | object, ...args: any[]): void {\n if (typeof messageOrObj === \"string\") {\n if (args.length === 0) {\n this.pinoInstance.debug(messageOrObj);\n } else {\n this.pinoInstance.debug({ args }, messageOrObj);\n }\n } else {\n this.pinoInstance.debug(messageOrObj, args[0] || \"\");\n }\n }\n\n log(message: string, ...args: any[]): void;\n log(obj: object, message?: string): void;\n log(messageOrObj: string | object, ...args: any[]): void {\n // log 方法使用 info 级别\n if (typeof messageOrObj === \"string\") {\n if (args.length === 0) {\n this.pinoInstance.info(messageOrObj);\n } else {\n this.pinoInstance.info({ args }, messageOrObj);\n }\n } else {\n this.pinoInstance.info(messageOrObj, args[0] || \"\");\n }\n }\n\n /**\n * 增强错误对象,提取更多错误信息\n */\n private enhanceErrorObject(obj: any): any {\n const enhanced = { ...obj };\n\n // 遍历对象属性,查找 Error 实例\n for (const [key, value] of Object.entries(enhanced)) {\n if (value instanceof Error) {\n enhanced[key] = {\n message: value.message,\n stack: value.stack,\n name: value.name,\n cause: value.cause,\n };\n }\n }\n\n return enhanced;\n }\n\n /**\n * 检查并轮转日志文件(如果需要)\n */\n private rotateLogFileIfNeeded(): void {\n if (!this.logFilePath || !fs.existsSync(this.logFilePath)) {\n return;\n }\n\n try {\n const stats = fs.statSync(this.logFilePath);\n if (stats.size > this.maxLogFileSize) {\n this.rotateLogFile();\n }\n } catch (error) {\n // 忽略文件状态检查错误\n }\n }\n\n /**\n * 轮转日志文件\n */\n private rotateLogFile(): void {\n if (!this.logFilePath) return;\n\n try {\n const logDir = path.dirname(this.logFilePath);\n const logName = path.basename(this.logFilePath, \".log\");\n\n // 移动现有的编号日志文件\n for (let i = this.maxLogFiles - 1; i >= 1; i--) {\n const oldFile = path.join(logDir, `${logName}.${i}.log`);\n const newFile = path.join(logDir, `${logName}.${i + 1}.log`);\n\n if (fs.existsSync(oldFile)) {\n if (i === this.maxLogFiles - 1) {\n // 删除最老的文件\n fs.unlinkSync(oldFile);\n } else {\n fs.renameSync(oldFile, newFile);\n }\n }\n }\n\n // 将当前日志文件重命名为 .1.log\n const firstRotatedFile = path.join(logDir, `${logName}.1.log`);\n fs.renameSync(this.logFilePath, firstRotatedFile);\n } catch (error) {\n // 轮转失败时忽略错误,继续使用当前文件\n }\n }\n\n /**\n * 清理旧的日志文件\n */\n cleanupOldLogs(): void {\n if (!this.logFilePath) return;\n\n try {\n const logDir = path.dirname(this.logFilePath);\n const logName = path.basename(this.logFilePath, \".log\");\n\n // 删除超过最大数量的日志文件\n for (let i = this.maxLogFiles + 1; i <= this.maxLogFiles + 10; i++) {\n const oldFile = path.join(logDir, `${logName}.${i}.log`);\n if (fs.existsSync(oldFile)) {\n fs.unlinkSync(oldFile);\n }\n }\n } catch (error) {\n // 忽略清理错误\n }\n }\n\n /**\n * 设置日志文件管理参数\n */\n setLogFileOptions(maxSize: number, maxFiles: number): void {\n this.maxLogFileSize = maxSize;\n this.maxLogFiles = maxFiles;\n }\n\n /**\n * 创建一个带标签的日志实例(已废弃,直接返回原实例)\n * @param tag 标签(不再使用)\n * @deprecated 标签功能已移除\n */\n withTag(_tag: string): Logger {\n // 不再添加标签,直接返回共享实例\n return this;\n }\n\n /**\n * 关闭日志文件流\n */\n close(): void {\n // pino 实例会自动处理流的关闭\n // 这里保持方法兼容性\n }\n}\n\n// 导出单例实例\nexport const logger = new Logger();\n","import type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport WebSocket from \"ws\";\nimport { type Logger, logger } from \"./Logger.js\";\n\nexport type { Tool };\n\n// MCP 消息接口\ninterface MCPMessage {\n jsonrpc: string;\n id?: number | string;\n method?: string;\n params?: any;\n result?: any;\n}\n\n// 连接状态枚举\nenum ConnectionState {\n DISCONNECTED = \"disconnected\",\n CONNECTING = \"connecting\",\n CONNECTED = \"connected\",\n RECONNECTING = \"reconnecting\",\n FAILED = \"failed\",\n}\n\n// 工具调用错误码枚举\nexport enum ToolCallErrorCode {\n INVALID_PARAMS = -32602, // 无效参数\n TOOL_NOT_FOUND = -32601, // 工具不存在\n TOOL_EXECUTION_ERROR = -32000, // 工具执行错误\n SERVICE_UNAVAILABLE = -32001, // 服务不可用\n TIMEOUT = -32002, // 调用超时\n}\n\n// 工具调用错误类\nexport class ToolCallError extends Error {\n constructor(\n public code: ToolCallErrorCode,\n message: string,\n public data?: any\n ) {\n super(message);\n this.name = \"ToolCallError\";\n }\n}\n\n// 工具调用配置接口\ninterface ToolCallOptions {\n timeout?: number;\n retryAttempts?: number;\n retryDelay?: number;\n}\n\n// 性能指标接口\ninterface PerformanceMetrics {\n totalCalls: number;\n successfulCalls: number;\n failedCalls: number;\n averageResponseTime: number;\n minResponseTime: number;\n maxResponseTime: number;\n successRate: number;\n lastUpdated: Date;\n}\n\n// 调用记录接口\ninterface CallRecord {\n id: string;\n toolName: string;\n startTime: Date;\n endTime?: Date;\n duration?: number;\n success: boolean;\n errorCode?: number;\n errorMessage?: string;\n}\n\n// 重试配置接口\ninterface RetryConfig {\n maxAttempts: number;\n initialDelay: number;\n maxDelay: number;\n backoffMultiplier: number;\n retryableErrors: ToolCallErrorCode[];\n}\n\n// 重连配置接口\ninterface ReconnectOptions {\n enabled: boolean; // 是否启用自动重连\n maxAttempts: number; // 最大重连次数\n initialInterval: number; // 初始重连间隔(ms)\n maxInterval: number; // 最大重连间隔(ms)\n backoffStrategy: \"linear\" | \"exponential\" | \"fixed\"; // 退避策略\n backoffMultiplier: number; // 退避倍数\n timeout: number; // 单次连接超时时间(ms)\n jitter: boolean; // 是否添加随机抖动\n}\n\n// 重连状态接口\ninterface ReconnectState {\n attempts: number; // 当前重连次数\n nextInterval: number; // 下次重连间隔\n timer: NodeJS.Timeout | null; // 重连定时器\n lastError: Error | null; // 最后一次错误\n isManualDisconnect: boolean; // 是否为主动断开\n}\n\n// 服务器选项接口\ninterface ProxyMCPServerOptions {\n reconnect?: Partial<ReconnectOptions>;\n}\n\n// 服务器状态接口\ninterface ProxyMCPServerStatus {\n connected: boolean;\n initialized: boolean;\n url: string;\n availableTools: number;\n connectionState: ConnectionState;\n reconnectAttempts: number;\n lastError: string | null;\n}\n\nexport class ProxyMCPServer {\n private endpointUrl: string;\n private ws: WebSocket | null = null;\n private logger: Logger;\n private isConnected = false;\n private serverInitialized = false;\n\n // 工具管理\n private tools: Map<string, Tool> = new Map();\n\n // 连接状态管理\n private connectionState: ConnectionState = ConnectionState.DISCONNECTED;\n\n // 重连配置\n private reconnectOptions: ReconnectOptions;\n\n // 重连状态\n private reconnectState: ReconnectState = {\n attempts: 0,\n nextInterval: 0,\n timer: null,\n lastError: null,\n isManualDisconnect: false,\n };\n\n // 连接超时定时器\n private connectionTimeout: NodeJS.Timeout | null = null;\n\n // 性能监控\n private performanceMetrics: PerformanceMetrics = {\n totalCalls: 0,\n successfulCalls: 0,\n failedCalls: 0,\n averageResponseTime: 0,\n minResponseTime: Number.MAX_VALUE,\n maxResponseTime: 0,\n successRate: 0,\n lastUpdated: new Date(),\n };\n\n // 调用记录(保留最近100条)\n private callRecords: CallRecord[] = [];\n private readonly maxCallRecords = 100;\n\n // 重试配置\n private retryConfig: RetryConfig = {\n maxAttempts: 3,\n initialDelay: 1000,\n maxDelay: 10000,\n backoffMultiplier: 2,\n retryableErrors: [\n ToolCallErrorCode.SERVICE_UNAVAILABLE,\n ToolCallErrorCode.TIMEOUT,\n ],\n };\n\n // 工具调用配置\n private toolCallConfig: ToolCallOptions = {\n timeout: 30000,\n retryAttempts: 3,\n retryDelay: 1000,\n };\n\n constructor(endpointUrl: string, options?: ProxyMCPServerOptions) {\n this.endpointUrl = endpointUrl;\n this.logger = logger;\n\n // 初始化重连配置\n this.reconnectOptions = {\n enabled: true,\n maxAttempts: 10,\n initialInterval: 3000,\n maxInterval: 30000,\n backoffStrategy: \"exponential\",\n backoffMultiplier: 1.5,\n timeout: 10000,\n jitter: true,\n ...options?.reconnect,\n };\n\n this.reconnectState.nextInterval = this.reconnectOptions.initialInterval;\n }\n\n /**\n * 设置 MCPServiceManager 实例\n * @param serviceManager MCPServiceManager 实例\n */\n setServiceManager(serviceManager: any): void {\n // 临时存储在一个变量中,避免类型检查问题\n (this as any).serviceManager = serviceManager;\n this.logger.info(\"已设置 MCPServiceManager\");\n\n // 立即同步工具\n this.syncToolsFromServiceManager();\n }\n\n /**\n * 从 MCPServiceManager 同步工具\n * 优化版本:支持增量同步和错误恢复\n */\n syncToolsFromServiceManager(): void {\n const serviceManager = (this as any).serviceManager;\n if (!serviceManager) {\n this.logger.debug(\"MCPServiceManager 未设置,跳过工具同步\");\n return;\n }\n\n try {\n // 从 MCPServiceManager 获取所有工具\n const allTools = serviceManager.getAllTools();\n\n // 原子性更新:先构建新的工具映射,再替换\n const newTools = new Map<string, Tool>();\n\n for (const toolInfo of allTools) {\n newTools.set(toolInfo.name, {\n name: toolInfo.name,\n description: toolInfo.description,\n inputSchema: toolInfo.inputSchema,\n });\n }\n\n // 原子性替换\n this.tools = newTools;\n\n this.logger.info(`已从 MCPServiceManager 同步 ${this.tools.size} 个工具`);\n } catch (error) {\n this.logger.error(\n `同步工具失败: ${error instanceof Error ? error.message : String(error)}`\n );\n // 同步失败时保持现有工具不变,确保服务可用性\n }\n }\n\n /**\n * 添加单个工具\n * @param name 工具名称\n * @param tool 工具定义\n * @param options 工具选项(可选)\n * @returns 返回 this 支持链式调用\n */\n addTool(name: string, tool: Tool): this {\n this.validateTool(name, tool);\n this.tools.set(name, tool);\n this.logger.debug(`工具 '${name}' 已添加`);\n // TODO: 未来可以使用 options 参数来设置工具的启用状态、元数据等\n return this;\n }\n\n /**\n * 批量添加工具\n * @param tools 工具对象,键为工具名称,值为工具定义\n * @returns 返回 this 支持链式调用\n */\n addTools(tools: Record<string, Tool>): this {\n for (const [name, tool] of Object.entries(tools)) {\n this.addTool(name, tool);\n }\n return this;\n }\n\n /**\n * 移除单个工具\n * @param name 工具名称\n * @returns 返回 this 支持链式调用\n */\n removeTool(name: string): this {\n if (this.tools.delete(name)) {\n this.logger.debug(`工具 '${name}' 已移除`);\n } else {\n this.logger.warn(`尝试移除不存在的工具: '${name}'`);\n }\n return this;\n }\n\n /**\n * 获取当前所有工具列表\n * @returns 工具数组\n */\n getTools(): Tool[] {\n // 每次获取工具时都尝试从 MCPServiceManager 同步\n try {\n this.syncToolsFromServiceManager();\n } catch (error) {\n // 静默处理同步错误,不影响现有工具的返回\n }\n\n return Array.from(this.tools.values());\n }\n\n /**\n * 检查工具是否存在\n * @param name 工具名称\n * @returns 是否存在\n */\n hasTool(name: string): boolean {\n return this.tools.has(name);\n }\n\n /**\n * 验证工具的有效性\n * @param name 工具名称\n * @param tool 工具定义\n */\n private validateTool(name: string, tool: Tool): void {\n if (!name || typeof name !== \"string\" || name.trim() === \"\") {\n throw new Error(\"工具名称必须是非空字符串\");\n }\n\n if (this.tools.has(name)) {\n throw new Error(`工具 '${name}' 已存在`);\n }\n\n if (!tool || typeof tool !== \"object\") {\n throw new Error(\"工具必须是有效的对象\");\n }\n\n // 验证工具的必需字段\n if (!tool.name || typeof tool.name !== \"string\") {\n throw new Error(\"工具必须包含有效的 'name' 字段\");\n }\n\n if (!tool.description || typeof tool.description !== \"string\") {\n throw new Error(\"工具必须包含有效的 'description' 字段\");\n }\n\n if (!tool.inputSchema || typeof tool.inputSchema !== \"object\") {\n throw new Error(\"工具必须包含有效的 'inputSchema' 字段\");\n }\n\n // 验证 inputSchema 的基本结构\n if (!tool.inputSchema.type || !tool.inputSchema.properties) {\n throw new Error(\n \"工具的 inputSchema 必须包含 'type' 和 'properties' 字段\"\n );\n }\n }\n\n /**\n * 连接 MCP 接入点\n * @returns 连接成功后的 Promise\n */\n public async connect(): Promise<void> {\n // 连接前验证\n if (this.tools.size === 0) {\n throw new Error(\"未配置任何工具。请在连接前至少添加一个工具。\");\n }\n\n // 如果正在连接中,等待当前连接完成\n if (this.connectionState === ConnectionState.CONNECTING) {\n throw new Error(\"连接正在进行中,请等待连接完成\");\n }\n\n // 清理之前的连接\n this.cleanupConnection();\n\n // 重置手动断开标志\n this.reconnectState.isManualDisconnect = false;\n\n return this.attemptConnection();\n }\n\n /**\n * 尝试建立连接\n * @returns 连接成功后的 Promise\n */\n private async attemptConnection(): Promise<void> {\n this.connectionState = ConnectionState.CONNECTING;\n this.logger.info(\n `正在连接 MCP 接入点: ${this.endpointUrl} (尝试 ${\n this.reconnectState.attempts + 1\n }/${this.reconnectOptions.maxAttempts})`\n );\n\n return new Promise((resolve, reject) => {\n // 设置连接超时\n this.connectionTimeout = setTimeout(() => {\n const error = new Error(\n `连接超时 (${this.reconnectOptions.timeout}ms)`\n );\n this.handleConnectionError(error);\n reject(error);\n }, this.reconnectOptions.timeout);\n\n this.ws = new WebSocket(this.endpointUrl);\n\n this.ws.on(\"open\", () => {\n this.handleConnectionSuccess();\n resolve();\n });\n\n this.ws.on(\"message\", (data) => {\n try {\n const message: MCPMessage = JSON.parse(data.toString());\n this.handleMessage(message);\n } catch (error) {\n this.logger.error(\"MCP 消息解析错误:\", error);\n }\n });\n\n this.ws.on(\"close\", (code, reason) => {\n this.handleConnectionClose(code, reason.toString());\n });\n\n this.ws.on(\"error\", (error) => {\n this.handleConnectionError(error);\n reject(error);\n });\n });\n }\n\n /**\n * 处理连接成功\n */\n private handleConnectionSuccess(): void {\n // 清理连接超时定时器\n if (this.connectionTimeout) {\n clearTimeout(this.connectionTimeout);\n this.connectionTimeout = null;\n }\n\n this.isConnected = true;\n this.connectionState = ConnectionState.CONNECTED;\n\n // 重置重连状态\n this.reconnectState.attempts = 0;\n this.reconnectState.nextInterval = this.reconnectOptions.initialInterval;\n this.reconnectState.lastError = null;\n\n this.logger.info(\"MCP WebSocket 连接已建立\");\n }\n\n /**\n * 处理连接错误\n */\n private handleConnectionError(error: Error): void {\n // 清理连接超时定时器\n if (this.connectionTimeout) {\n clearTimeout(this.connectionTimeout);\n this.connectionTimeout = null;\n }\n\n this.reconnectState.lastError = error;\n this.logger.error(\"MCP WebSocket 错误:\", error.message);\n\n // 清理当前连接\n this.cleanupConnection();\n }\n\n /**\n * 处理连接关闭\n */\n private handleConnectionClose(code: number, reason: string): void {\n this.isConnected = false;\n this.serverInitialized = false;\n this.logger.info(`MCP 连接已关闭 (代码: ${code}, 原因: ${reason})`);\n\n // 如果是手动断开,不进行重连\n if (this.reconnectState.isManualDisconnect) {\n this.connectionState = ConnectionState.DISCONNECTED;\n return;\n }\n\n // 检查是否需要重连\n if (this.shouldReconnect()) {\n this.scheduleReconnect();\n } else {\n this.connectionState = ConnectionState.FAILED;\n this.logger.warn(\n `已达到最大重连次数 (${this.reconnectOptions.maxAttempts}),停止重连`\n );\n }\n }\n\n /**\n * 检查是否应该重连\n */\n private shouldReconnect(): boolean {\n return (\n this.reconnectOptions.enabled &&\n this.reconnectState.attempts < this.reconnectOptions.maxAttempts &&\n !this.reconnectState.isManualDisconnect\n );\n }\n\n /**\n * 安排重连\n */\n private scheduleReconnect(): void {\n this.connectionState = ConnectionState.RECONNECTING;\n this.reconnectState.attempts++;\n\n // 计算下次重连间隔\n this.calculateNextInterval();\n\n this.logger.info(\n `将在 ${this.reconnectState.nextInterval}ms 后进行第 ${this.reconnectState.attempts} 次重连`\n );\n\n // 清理之前的重连定时器\n if (this.reconnectState.timer) {\n clearTimeout(this.reconnectState.timer);\n }\n\n // 设置重连定时器\n this.reconnectState.timer = setTimeout(async () => {\n try {\n await this.attemptConnection();\n } catch (error) {\n // 连接失败会触发 handleConnectionError,无需额外处理\n }\n }, this.reconnectState.nextInterval);\n }\n\n /**\n * 计算下次重连间隔\n */\n private calculateNextInterval(): void {\n let interval: number;\n\n switch (this.reconnectOptions.backoffStrategy) {\n case \"fixed\":\n interval = this.reconnectOptions.initialInterval;\n break;\n\n case \"linear\":\n interval =\n this.reconnectOptions.initialInterval +\n this.reconnectState.attempts *\n this.reconnectOptions.backoffMultiplier *\n 1000;\n break;\n\n case \"exponential\":\n interval =\n this.reconnectOptions.initialInterval *\n this.reconnectOptions.backoffMultiplier **\n (this.reconnectState.attempts - 1);\n break;\n\n default:\n interval = this.reconnectOptions.initialInterval;\n }\n\n // 限制最大间隔\n interval = Math.min(interval, this.reconnectOptions.maxInterval);\n\n // 添加随机抖动\n if (this.reconnectOptions.jitter) {\n const jitterRange = interval * 0.1; // 10% 抖动\n const jitter = (Math.random() - 0.5) * 2 * jitterRange;\n interval += jitter;\n }\n\n this.reconnectState.nextInterval = Math.max(interval, 1000); // 最小1秒\n }\n\n /**\n * 清理连接资源\n */\n private cleanupConnection(): void {\n // 清理 WebSocket\n if (this.ws) {\n // 移除所有事件监听器,防止在关闭时触发错误事件\n this.ws.removeAllListeners();\n\n // 安全关闭 WebSocket\n try {\n if (this.ws.readyState === WebSocket.OPEN) {\n this.ws.close(1000, \"Cleaning up connection\");\n } else if (this.ws.readyState === WebSocket.CONNECTING) {\n this.ws.terminate(); // 强制终止正在连接的 WebSocket\n }\n } catch (error) {\n // 忽略关闭时的错误\n this.logger.debug(\"WebSocket 关闭时出现错误(已忽略):\", error);\n }\n\n this.ws = null;\n }\n\n // 清理连接超时定时器\n if (this.connectionTimeout) {\n clearTimeout(this.connectionTimeout);\n this.connectionTimeout = null;\n }\n\n // 重置连接状态\n this.isConnected = false;\n this.serverInitialized = false;\n }\n\n /**\n * 停止重连\n */\n private stopReconnect(): void {\n if (this.reconnectState.timer) {\n clearTimeout(this.reconnectState.timer);\n this.reconnectState.timer = null;\n }\n }\n\n private handleMessage(message: MCPMessage): void {\n this.logger.debug(\"收到 MCP 消息:\", JSON.stringify(message, null, 2));\n\n if (message.method) {\n this.handleServerRequest(message);\n }\n }\n\n private handleServerRequest(request: MCPMessage): void {\n switch (request.method) {\n case \"initialize\":\n case \"notifications/initialized\":\n this.sendResponse(request.id, {\n protocolVersion: \"2024-11-05\",\n capabilities: {\n tools: { listChanged: true },\n logging: {},\n },\n serverInfo: {\n name: \"xiaozhi-mcp-server\",\n version: \"1.0.0\",\n },\n });\n this.serverInitialized = true;\n this.logger.info(\"MCP 服务器初始化完成\");\n break;\n\n case \"tools/list\": {\n const toolsList = this.getTools();\n this.sendResponse(request.id, { tools: toolsList });\n this.logger.info(`MCP 工具列表已发送 (${toolsList.length}个工具)`);\n break;\n }\n\n case \"tools/call\": {\n // 异步处理工具调用,避免阻塞其他消息\n this.handleToolCall(request).catch((error) => {\n this.logger.error(\"处理工具调用时发生未捕获错误:\", error);\n });\n break;\n }\n\n case \"ping\":\n this.sendResponse(request.id, {});\n this.logger.debug(\"回应 MCP ping 消息\");\n break;\n\n default:\n this.logger.warn(`未知的 MCP 请求: ${request.method}`);\n }\n }\n\n private sendResponse(id: number | string | undefined, result: any): void {\n this.logger.debug(\n `尝试发送响应: id=${id}, isConnected=${this.isConnected}, wsReadyState=${this.ws?.readyState}`\n );\n\n if (this.isConnected && this.ws?.readyState === WebSocket.OPEN) {\n const response: MCPMessage = {\n jsonrpc: \"2.0\",\n id,\n result,\n };\n\n try {\n this.ws.send(JSON.stringify(response));\n this.logger.info(`响应已发送: id=${id}`, {\n responseSize: JSON.stringify(response).length,\n });\n } catch (error) {\n this.logger.error(`发送响应失败: id=${id}`, error);\n }\n } else {\n this.logger.error(`无法发送响应: id=${id}, 连接状态检查失败`, {\n isConnected: this.isConnected,\n wsReadyState: this.ws?.readyState,\n wsReadyStateText:\n this.ws?.readyState === WebSocket.OPEN\n ? \"OPEN\"\n : this.ws?.readyState === WebSocket.CONNECTING\n ? \"CONNECTING\"\n : this.ws?.readyState === WebSocket.CLOSING\n ? \"CLOSING\"\n : this.ws?.readyState === WebSocket.CLOSED\n ? \"CLOSED\"\n : \"UNKNOWN\",\n });\n\n // 尝试重新连接并发送响应\n if (!this.isConnected || this.ws?.readyState !== WebSocket.OPEN) {\n this.logger.warn(`尝试重新连接以发送响应: id=${id}`);\n this.scheduleReconnect();\n }\n }\n }\n\n /**\n * 获取 MCP 服务器状态\n * @returns 服务器状态\n */\n public getStatus(): ProxyMCPServerStatus {\n return {\n connected: this.isConnected,\n initialized: this.serverInitialized,\n url: this.endpointUrl,\n availableTools: this.tools.size,\n connectionState: this.connectionState,\n reconnectAttempts: this.reconnectState.attempts,\n lastError: this.reconnectState.lastError?.message || null,\n };\n }\n\n /**\n * 主动断开 MCP 连接\n */\n public disconnect(): void {\n this.logger.info(\"主动断开 MCP 连接\");\n\n // 标记为手动断开,阻止自动重连\n this.reconnectState.isManualDisconnect = true;\n\n // 停止重连定时器\n this.stopReconnect();\n\n // 清理连接资源\n this.cleanupConnection();\n\n // 设置状态为已断开\n this.connectionState = ConnectionState.DISCONNECTED;\n }\n\n /**\n * 手动重连 MCP 接入点\n */\n public async reconnect(): Promise<void> {\n this.logger.info(\"手动重连 MCP 接入点\");\n\n // 停止自动重连\n this.stopReconnect();\n\n // 重置重连状态\n this.reconnectState.attempts = 0;\n this.reconnectState.nextInterval = this.reconnectOptions.initialInterval;\n this.reconnectState.isManualDisconnect = false;\n\n // 清理现有连接\n this.cleanupConnection();\n\n // 尝试连接\n await this.connect();\n }\n\n /**\n * 启用自动重连\n */\n public enableReconnect(): void {\n this.reconnectOptions.enabled = true;\n this.logger.info(\"自动重连已启用\");\n }\n\n /**\n * 禁用自动重连\n */\n public disableReconnect(): void {\n this.reconnectOptions.enabled = false;\n this.stopReconnect();\n this.logger.info(\"自动重连已禁用\");\n }\n\n /**\n * 更新重连配置\n */\n public updateReconnectOptions(options: Partial<ReconnectOptions>): void {\n this.reconnectOptions = { ...this.reconnectOptions, ...options };\n this.logger.info(\"重连配置已更新\", options);\n }\n\n /**\n * 获取重连配置\n */\n public getReconnectOptions(): ReconnectOptions {\n return { ...this.reconnectOptions };\n }\n\n /**\n * 重置重连状态\n */\n public resetReconnectState(): void {\n this.stopReconnect();\n this.reconnectState.attempts = 0;\n this.reconnectState.nextInterval = this.reconnectOptions.initialInterval;\n this.reconnectState.lastError = null;\n this.logger.info(\"重连状态已重置\");\n }\n\n /**\n * 处理工具调用请求\n */\n private async handleToolCall(request: MCPMessage): Promise<void> {\n // 确保 request.id 存在且类型正确\n if (request.id === undefined || request.id === null) {\n throw new ToolCallError(\n ToolCallErrorCode.INVALID_PARAMS,\n \"请求 ID 不能为空\"\n );\n }\n\n // 保持原始 ID 类型(number | string),不进行类型转换\n const requestId = request.id;\n let callRecord: CallRecord | null = null;\n\n try {\n // 1. 验证请求格式\n const params = this.validateToolCallParams(request.params);\n\n // 2. 记录调用开始\n callRecord = this.recordCallStart(params.name, requestId);\n\n this.logger.info(`开始处理工具调用: ${params.name}`, {\n requestId,\n toolName: params.name,\n hasArguments: !!params.arguments,\n });\n\n // 3. 检查服务管理器是否可用\n const serviceManager = (this as any).serviceManager;\n if (!serviceManager) {\n throw new ToolCallError(\n ToolCallErrorCode.SERVICE_UNAVAILABLE,\n \"MCPServiceManager 未设置\"\n );\n }\n\n // 4. 执行工具调用(带重试机制)\n const result = await this.executeToolWithRetry(\n serviceManager,\n params.name,\n params.arguments || {}\n );\n\n // 5. 发送成功响应\n this.sendResponse(requestId, {\n content: result.content || [\n { type: \"text\", text: JSON.stringify(result) },\n ],\n isError: result.isError || false,\n });\n\n // 6. 记录调用成功\n if (callRecord) {\n this.recordCallEnd(callRecord, true);\n }\n\n this.logger.info(`工具调用成功: ${params.name}`, {\n requestId,\n duration: callRecord?.duration ? `${callRecord.duration}ms` : \"unknown\",\n });\n } catch (error) {\n // 7. 处理错误并发送错误响应\n if (callRecord) {\n const errorCode =\n error instanceof ToolCallError\n ? error.code\n : ToolCallErrorCode.TOOL_EXECUTION_ERROR;\n const errorMessage =\n error instanceof Error ? error.message : \"未知错误\";\n this.recordCallEnd(callRecord, false, errorCode, errorMessage);\n }\n\n this.handleToolCallError(error, requestId, callRecord?.duration || 0);\n }\n }\n\n /**\n * 验证工具调用参数\n */\n private validateToolCallParams(params: any): {\n name: string;\n arguments?: any;\n } {\n if (!params || typeof params !== \"object\") {\n throw new ToolCallError(\n ToolCallErrorCode.INVALID_PARAMS,\n \"请求参数必须是对象\"\n );\n }\n\n if (!params.name || typeof params.name !== \"string\") {\n throw new ToolCallError(\n ToolCallErrorCode.INVALID_PARAMS,\n \"工具名称必须是非空字符串\"\n );\n }\n\n if (\n params.arguments !== undefined &&\n (typeof params.arguments !== \"object\" || Array.isArray(params.arguments))\n ) {\n throw new ToolCallError(\n ToolCallErrorCode.INVALID_PARAMS,\n \"工具参数必须是对象\"\n );\n }\n\n return {\n name: params.name,\n arguments: params.arguments,\n };\n }\n\n /**\n * 带重试机制的工具执行\n */\n private async executeToolWithRetry(\n serviceManager: any,\n toolName: string,\n arguments_: any\n ): Promise<any> {\n let lastError: ToolCallError | null = null;\n\n for (let attempt = 1; attempt <= this.retryConfig.maxAttempts; attempt++) {\n try {\n return await this.executeToolWithTimeout(\n serviceManager,\n toolName,\n arguments_,\n this.toolCallConfig.timeout\n );\n } catch (error) {\n // 确保错误是 ToolCallError 类型\n if (error instanceof ToolCallError) {\n lastError = error;\n } else {\n // 如果不是 ToolCallError,转换为 ToolCallError\n lastError = new ToolCallError(\n ToolCallErrorCode.TOOL_EXECUTION_ERROR,\n error instanceof Error ? error.message : \"未知错误\"\n );\n }\n\n // 检查是否是可重试的错误\n if (\n this.retryConfig.retryableErrors.includes(lastError.code) &&\n attempt < this.retryConfig.maxAttempts\n ) {\n // 计算重试延迟\n const delay = Math.min(\n this.retryConfig.initialDelay *\n this.retryConfig.backoffMultiplier ** (attempt - 1),\n this.retryConfig.maxDelay\n );\n\n this.logger.warn(\n `工具调用失败,将在 ${delay}ms 后重试 (${attempt}/${this.retryConfig.maxAttempts})`,\n {\n toolName,\n error: lastError.message,\n attempt,\n delay,\n }\n );\n\n // 等待重试延迟\n await new Promise((resolve) => setTimeout(resolve, delay));\n continue;\n }\n\n // 不可重试的错误或已达到最大重试次数\n break;\n }\n }\n\n // 所有重试都失败了,抛出最后一个错误\n throw lastError;\n }\n\n /**\n * 带超时控制的工具执行\n */\n private async executeToolWithTimeout(\n serviceManager: any,\n toolName: string,\n arguments_: any,\n timeoutMs = 30000\n ): Promise<any> {\n return new Promise((resolve, reject) => {\n // 设置超时定时器\n const timeoutId = setTimeout(() => {\n reject(\n new ToolCallError(\n ToolCallErrorCode.TIMEOUT,\n `工具调用超时 (${timeoutMs}ms): ${toolName}`\n )\n );\n }, timeoutMs);\n\n // 执行工具调用\n serviceManager\n .callTool(toolName, arguments_)\n .then((result: any) => {\n clearTimeout(timeoutId);\n resolve(result);\n })\n .catch((error: any) => {\n clearTimeout(timeoutId);\n\n // 将内部错误转换为工具调用错误\n if (error.message?.includes(\"未找到工具\")) {\n reject(\n new ToolCallError(\n ToolCallErrorCode.TOOL_NOT_FOUND,\n `工具不存在: ${toolName}`\n )\n );\n } else if (\n error.message?.includes(\"服务\") &&\n error.message?.includes(\"不可用\")\n ) {\n reject(\n new ToolCallError(\n ToolCallErrorCode.SERVICE_UNAVAILABLE,\n error.message\n )\n );\n } else if (error.message?.includes(\"暂时不可用\")) {\n // 处理临时性错误,标记为服务不可用(可重试)\n reject(\n new ToolCallError(\n ToolCallErrorCode.SERVICE_UNAVAILABLE,\n error.message\n )\n );\n } else if (error.message?.includes(\"持续不可用\")) {\n // 处理持续性错误,也标记为服务不可用(可重试)\n reject(\n new ToolCallError(\n ToolCallErrorCode.SERVICE_UNAVAILABLE,\n error.message\n )\n );\n } else {\n reject(\n new ToolCallError(\n ToolCallErrorCode.TOOL_EXECUTION_ERROR,\n `工具执行失败: ${error.message}`\n )\n );\n }\n });\n });\n }\n\n /**\n * 处理工具调用错误\n */\n private handleToolCallError(\n error: any,\n requestId: string | number | undefined,\n duration: number\n ): void {\n let errorResponse: any;\n\n if (error instanceof ToolCallError) {\n // 标准工具调用错误\n errorResponse = {\n code: error.code,\n message: error.message,\n data: error.data,\n };\n } else {\n // 未知错误\n errorResponse = {\n code: ToolCallErrorCode.TOOL_EXECUTION_ERROR,\n message: error?.message || \"未知错误\",\n data: { originalError: error?.toString() || \"null\" },\n };\n }\n\n // 发送错误响应\n this.sendErrorResponse(requestId, errorResponse);\n\n // 记录错误日志\n this.logger.error(\"工具调用失败\", {\n requestId,\n duration: `${duration}ms`,\n error: errorResponse,\n });\n }\n\n /**\n * 发送错误响应\n */\n private sendErrorResponse(\n id: string | number | undefined,\n error: { code: number; message: string; data?: any }\n ): void {\n if (this.isConnected && this.ws?.readyState === WebSocket.OPEN) {\n const response = {\n jsonrpc: \"2.0\",\n id,\n error,\n };\n this.ws.send(JSON.stringify(response));\n this.logger.debug(\"已发送错误响应:\", response);\n }\n }\n\n /**\n * 记录工具调用开始\n */\n private recordCallStart(\n toolName: string,\n requestId: string | number\n ): CallRecord {\n const record: CallRecord = {\n id: String(requestId), // 内部记录时转换为字符串,但不影响响应 ID 类型\n toolName,\n startTime: new Date(),\n success: false,\n };\n\n // 添加到记录列表\n this.callRecords.push(record);\n\n // 保持记录数量在限制内\n if (this.callRecords.length > this.maxCallRecords) {\n this.callRecords.shift();\n }\n\n return record;\n }\n\n /**\n * 记录工具调用结束\n */\n private recordCallEnd(\n record: CallRecord,\n success: boolean,\n errorCode?: number,\n errorMessage?: string\n ): void {\n record.endTime = new Date();\n record.duration = record.endTime.getTime() - record.startTime.getTime();\n record.success = success;\n record.errorCode = errorCode;\n record.errorMessage = errorMessage;\n\n // 更新性能指标\n this.updatePerformanceMetrics(record);\n }\n\n /**\n * 更新性能指标\n */\n private updatePerformanceMetrics(record: CallRecord): void {\n this.performanceMetrics.totalCalls++;\n\n if (record.success) {\n this.performanceMetrics.successfulCalls++;\n } else {\n this.performanceMetrics.failedCalls++;\n }\n\n if (record.duration !== undefined) {\n // 更新响应时间统计\n if (record.duration < this.performanceMetrics.minResponseTime) {\n this.performanceMetrics.minResponseTime = record.duration;\n }\n if (record.duration > this.performanceMetrics.maxResponseTime) {\n this.performanceMetrics.maxResponseTime = record.duration;\n }\n\n // 计算平均响应时间\n const totalTime = this.callRecords\n .filter((r) => r.duration !== undefined)\n .reduce((sum, r) => sum + (r.duration || 0), 0);\n const completedCalls = this.callRecords.filter(\n (r) => r.duration !== undefined\n ).length;\n this.performanceMetrics.averageResponseTime =\n completedCalls > 0 ? totalTime / completedCalls : 0;\n }\n\n // 计算成功率\n this.performanceMetrics.successRate =\n this.performanceMetrics.totalCalls > 0\n ? (this.performanceMetrics.successfulCalls /\n this.performanceMetrics.totalCalls) *\n 100\n : 0;\n\n this.performanceMetrics.lastUpdated = new Date();\n }\n\n /**\n * 获取性能指标\n */\n public getPerformanceMetrics(): PerformanceMetrics {\n return { ...this.performanceMetrics };\n }\n\n /**\n * 获取调用记录\n */\n public getCallRecords(limit?: number): CallRecord[] {\n const records = [...this.callRecords].reverse(); // 最新的在前\n return limit ? records.slice(0, limit) : records;\n }\n\n /**\n * 重置性能指标\n */\n public resetPerformanceMetrics(): void {\n this.performanceMetrics = {\n totalCalls: 0,\n successfulCalls: 0,\n failedCalls: 0,\n averageResponseTime: 0,\n minResponseTime: Number.MAX_VALUE,\n maxResponseTime: 0,\n successRate: 0,\n lastUpdated: new Date(),\n };\n this.callRecords = [];\n }\n\n /**\n * 更新工具调用配置\n */\n public updateToolCallConfig(config: Partial<ToolCallOptions>): void {\n this.toolCallConfig = { ...this.toolCallConfig, ...config };\n this.logger.info(\"工具调用配置已更新\", this.toolCallConfig);\n }\n\n /**\n * 更新重试配置\n */\n public updateRetryConfig(config: Partial<RetryConfig>): void {\n this.retryConfig = { ...this.retryConfig, ...config };\n this.logger.info(\"重试配置已更新\", this.retryConfig);\n }\n\n /**\n * 获取当前配置\n */\n public getConfiguration(): {\n toolCall: ToolCallOptions;\n retry: RetryConfig;\n } {\n return {\n toolCall: { ...this.toolCallConfig },\n retry: { ...this.retryConfig },\n };\n }\n\n /**\n * 获取服务器状态(增强版)\n */\n public getEnhancedStatus(): ProxyMCPServerStatus & {\n performance: PerformanceMetrics;\n configuration: {\n toolCall: ToolCallOptions;\n retry: RetryConfig;\n };\n } {\n return {\n connected: this.isConnected,\n initialized: this.serverInitialized,\n url: this.endpointUrl,\n availableTools: this.tools.size,\n connectionState: this.connectionState,\n reconnectAttempts: this.reconnectState.attempts,\n lastError: this.reconnectState.lastError?.message || null,\n performance: this.getPerformanceMetrics(),\n configuration: this.getConfiguration(),\n };\n }\n}\n","import {\n SSEClientTransport,\n type SSEClientTransportOptions,\n} from \"@modelcontextprotocol/sdk/client/sse.js\";\nimport { StdioClientTransport } from \"@modelcontextprotocol/sdk/client/stdio.js\";\nimport {\n StreamableHTTPClientTransport,\n type StreamableHTTPClientTransportOptions,\n} from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\nimport { EventSource } from \"eventsource\";\nimport { type Logger, logger } from \"../Logger.js\";\nimport { type MCPServiceConfig, MCPTransportType } from \"./MCPService.js\";\n\n// 全局 polyfill EventSource(用于 SSE)\nif (typeof global !== \"undefined\" && !global.EventSource) {\n (global as any).EventSource = EventSource;\n}\n\n// Transport 基础接口\nexport interface Transport {\n connect?(): Promise<void>;\n close?(): Promise<void>;\n}\n\n// 创建 logger 实例\nfunction getLogger(): Logger {\n return logger;\n}\n\n/**\n * 创建 transport 实例\n * @param config MCP 服务配置\n * @returns transport 实例\n */\nexport function createTransport(config: MCPServiceConfig): any {\n const logger = getLogger();\n logger.info(\n `[TransportFactory] 创建 ${config.type} transport for ${config.name}`\n );\n\n switch (config.type) {\n case MCPTransportType.STDIO:\n return createStdioTransport(config);\n\n case MCPTransportType.SSE:\n return createSSETransport(config);\n\n case MCPTransportType.MODELSCOPE_SSE:\n return createModelScopeSSETransport(config);\n\n case MCPTransportType.STREAMABLE_HTTP:\n return createStreamableHTTPTransport(config);\n\n default:\n throw new Error(`不支持的传输类型: ${config.type}`);\n }\n}\n\n/**\n * 创建 Stdio transport\n */\nfunction createStdioTransport(config: MCPServiceConfig): StdioClientTransport {\n if (!config.command) {\n throw new Error(\"stdio transport 需要 command 配置\");\n }\n\n return new StdioClientTransport({\n command: config.command,\n args: config.args || [],\n env: config.env, // 传递环境变量\n });\n}\n\n/**\n * 创建 SSE transport\n */\nfunction createSSETransport(config: MCPServiceConfig): SSEClientTransport {\n if (!config.url) {\n throw new Error(\"SSE transport 需要 URL 配置\");\n }\n\n const url = new URL(config.url);\n const options = createSSEOptions(config);\n\n return new SSEClientTransport(url, options);\n}\n\n/**\n * 创建 ModelScope SSE transport\n */\nfunction createModelScopeSSETransport(\n config: MCPServiceConfig\n): SSEClientTransport {\n if (!config.url) {\n throw new Error(\"ModelScope SSE transport 需要 URL 配置\");\n }\n\n if (!config.apiKey) {\n throw new Error(\"ModelScope SSE transport 需要 apiKey 配置\");\n }\n\n const url = new URL(config.url);\n const options = createModelScopeSSEOptions(config);\n\n return new SSEClientTransport(url, options);\n}\n\nfunction createStreamableHTTPTransport(\n config: MCPServiceConfig\n): StreamableHTTPClientTransport {\n if (!config.url) {\n throw new Error(\"StreamableHTTP transport 需要 URL 配置\");\n }\n\n const url = new URL(config.url);\n const options = createStreamableHTTPOptions(config);\n return new StreamableHTTPClientTransport(url, options);\n}\n\n/**\n * 创建 SSE 选项\n */\nfunction createSSEOptions(config: MCPServiceConfig): SSEClientTransportOptions {\n const options: any = {};\n\n // 添加认证头\n if (config.apiKey) {\n options.headers = {\n Authorization: `Bearer ${config.apiKey}`,\n ...config.headers,\n };\n } else if (config.headers) {\n options.headers = config.headers;\n }\n\n return options;\n}\n\n/**\n * 创建 ModelScope SSE 选项\n */\nfunction createModelScopeSSEOptions(config: MCPServiceConfig): any {\n const token = config.apiKey!; // 已在调用方验证过\n\n // 如果有自定义SSE选项,使用它们\n if (config.customSSEOptions) {\n return config.customSSEOptions;\n }\n\n // 默认的ModelScope SSE选项配置\n return {\n eventSourceInit: {\n fetch: async (url: string | URL | Request, init?: RequestInit) => {\n // 添加认证头\n const headers = {\n ...init?.headers,\n Authorization: `Bearer ${token}`,\n };\n\n return fetch(url, { ...init, headers });\n },\n },\n requestInit: {\n headers: {\n Authorization: `Bearer ${token}`,\n ...config.headers,\n },\n },\n };\n}\n\nfunction createStreamableHTTPOptions(\n config: MCPServiceConfig\n): StreamableHTTPClientTransportOptions {\n const options: any = {};\n\n // 添加认证头\n if (config.apiKey) {\n options.headers = {\n Authorization: `Bearer ${config.apiKey}`,\n ...config.headers,\n };\n } else if (config.headers) {\n options.headers = config.headers;\n }\n\n return options;\n}\n\n/**\n * 验证配置\n */\nexport function validateConfig(config: MCPServiceConfig): void {\n if (!config.name || typeof config.name !== \"string\") {\n throw new Error(\"配置必须包含有效的 name 字段\");\n }\n\n if (!config.type) {\n throw new Error(\"配置必须包含 type 字段\");\n }\n\n switch (config.type) {\n case MCPTransportType.STDIO:\n if (!config.command) {\n throw new Error(\"stdio 类型需要 command 字段\");\n }\n break;\n\n case MCPTransportType.SSE:\n case MCPTransportType.STREAMABLE_HTTP:\n if (!config.url) {\n throw new Error(`${config.type} 类型需要 url 字段`);\n }\n break;\n\n case MCPTransportType.MODELSCOPE_SSE:\n if (!config.url) {\n throw new Error(\"modelscope-sse 类型需要 url 字段\");\n }\n if (!config.apiKey) {\n throw new Error(\n \"modelscope-sse 类型需要 apiKey 字段。请在配置文件中设置 modelscope.apiKey 或确保服务配置包含 apiKey\"\n );\n }\n break;\n\n default:\n throw new Error(`不支持的传输类型: ${config.type}`);\n }\n}\n\n/**\n * 获取支持的传输类型列表\n */\nexport function getSupportedTypes(): MCPTransportType[] {\n return [\n MCPTransportType.STDIO,\n MCPTransportType.SSE,\n MCPTransportType.MODELSCOPE_SSE,\n MCPTransportType.STREAMABLE_HTTP,\n ];\n}\n\n/**\n * Transport 工厂对象(保持 API 兼容性)\n */\nexport const TransportFactory = {\n create: createTransport,\n validateConfig,\n getSupportedTypes,\n};\n","import { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport { type Logger, logger } from \"../Logger.js\";\nimport { TransportFactory } from \"./TransportFactory.js\";\n\n// 通信方式枚举\nexport enum MCPTransportType {\n STDIO = \"stdio\",\n SSE = \"sse\",\n STREAMABLE_HTTP = \"streamable-http\",\n MODELSCOPE_SSE = \"modelscope-sse\",\n}\n\n// 连接状态枚举\nexport enum ConnectionState {\n DISCONNECTED = \"disconnected\",\n CONNECTING = \"connecting\",\n CONNECTED = \"connected\",\n RECONNECTING = \"reconnecting\",\n FAILED = \"failed\",\n}\n\n// 重连配置接口\nexport interface ReconnectOptions {\n enabled: boolean;\n maxAttempts: number;\n initialInterval: number;\n maxInterval: number;\n backoffStrategy: \"linear\" | \"exponential\" | \"fixed\";\n backoffMultiplier: number;\n timeout: number;\n jitter: boolean;\n}\n\n// Ping配置接口\nexport interface PingOptions {\n enabled: boolean;\n interval: number; // ping间隔(毫秒)\n timeout: number; // ping超时(毫秒)\n maxFailures: number; // 最大连续失败次数\n startDelay: number; // 连接成功后开始ping的延迟(毫秒)\n}\n\n// ModelScope SSE 自定义选项接口\nexport interface ModelScopeSSEOptions {\n eventSourceInit?: {\n fetch?: (\n url: string | URL | Request,\n init?: RequestInit\n ) => Promise<Response>;\n };\n requestInit?: RequestInit;\n}\n\n// MCPService 配置接口\nexport interface MCPServiceConfig {\n name: string;\n type: MCPTransportType;\n // stdio 配置\n command?: string;\n args?: string[];\n env?: Record<string, string>; // 环境变量配置\n // 网络配置\n url?: string;\n // 认证配置\n apiKey?: string;\n headers?: Record<string, string>;\n // ModelScope 特有配置\n modelScopeAuth?: boolean;\n customSSEOptions?: ModelScopeSSEOptions;\n // 重连配置\n reconnect?: Partial<ReconnectOptions>;\n // ping配置\n ping?: Partial<PingOptions>;\n // 超时配置\n timeout?: number;\n // 重试配置\n retryAttempts?: number;\n}\n\n// MCPService 状态接口\nexport interface MCPServiceStatus {\n name: string;\n connected: boolean;\n initialized: boolean;\n transportType: MCPTransportType;\n toolCount: number;\n lastError?: string;\n reconnectAttempts: number;\n connectionState: ConnectionState;\n // ping状态\n pingEnabled: boolean;\n lastPingTime?: Date;\n pingFailureCount: number;\n isPinging: boolean;\n}\n\n// MCPService 选项接口\nexport interface MCPServiceOptions {\n reconnect?: Partial<ReconnectOptions>;\n}\n\n// 重连状态接口\ninterface ReconnectState {\n attempts: number;\n nextInterval: number;\n timer: NodeJS.Timeout | null;\n lastError: Error | null;\n isManualDisconnect: boolean;\n}\n\n// 工具调用结果接口\nexport interface ToolCallResult {\n content: Array<{\n type: string;\n text: string;\n }>;\n isError?: boolean;\n}\n\n/**\n * MCP 服务类\n * 负责管理单个 MCP 服务的连接、工具管理和调用\n */\nexport class MCPService {\n private config: MCPServiceConfig;\n private client: Client | null = null;\n private transport: any = null;\n private tools: Map<string, Tool> = new Map();\n private connectionState: ConnectionState = ConnectionState.DISCONNECTED;\n private reconnectOptions: ReconnectOptions;\n private reconnectState: ReconnectState;\n private logger: Logger;\n private connectionTimeout: NodeJS.Timeout | null = null;\n private initialized = false;\n\n // Ping相关属性\n private pingOptions: PingOptions;\n private pingTimer: NodeJS.Timeout | null = null;\n private pingFailureCount = 0;\n private lastPingTime: Date | null = null;\n private isPinging = false;\n\n constructor(config: MCPServiceConfig, options?: MCPServiceOptions) {\n this.config = config;\n this.logger = logger;\n\n // 验证配置\n this.validateConfig();\n\n // 初始化重连配置\n this.reconnectOptions = {\n enabled: true,\n maxAttempts: 10,\n initialInterval: 3000,\n maxInterval: 30000,\n backoffStrategy: \"exponential\",\n backoffMultiplier: 1.5,\n timeout: 10000,\n jitter: true,\n ...options?.reconnect,\n ...config.reconnect,\n };\n\n // 初始化ping配置\n this.pingOptions = {\n enabled: true, // 默认启用\n interval: 30000, // 30秒\n timeout: 5000, // 5秒超时\n maxFailures: 3, // 最大连续失败3次\n startDelay: 5000, // 连接成功后5秒开始ping\n ...config.ping,\n };\n\n // 初始化重连状态\n this.reconnectState = {\n attempts: 0,\n nextInterval: this.reconnectOptions.initialInterval,\n timer: null,\n lastError: null,\n isManualDisconnect: false,\n };\n }\n\n /**\n * 带标签的日志方法\n */\n private logWithTag(\n level: \"info\" | \"error\" | \"warn\" | \"debug\",\n message: string,\n ...args: any[]\n ): void {\n const taggedMessage = `[MCP-${this.config.name}] ${message}`;\n this.logger[level](taggedMessage, ...args);\n }\n\n /**\n * 验证配置\n */\n private validateConfig(): void {\n // 使用 TransportFactory 进行配置验证\n TransportFactory.validateConfig(this.config);\n }\n\n /**\n * 连接到 MCP 服务\n */\n async connect(): Promise<void> {\n // 如果正在连接中,等待当前连接完成\n if (this.connectionState === ConnectionState.CONNECTING) {\n throw new Error(\"连接正在进行中,请等待连接完成\");\n }\n\n // 清理之前的连接\n this.cleanupConnection();\n\n // 重置手动断开标志\n this.reconnectState.isManualDisconnect = false;\n\n return this.attemptConnection();\n }\n\n /**\n * 尝试建立连接\n */\n private async attemptConnection(): Promise<void> {\n this.connectionState = ConnectionState.CONNECTING;\n this.logWithTag(\n \"info\",\n `正在连接 MCP 服务: ${this.config.name} (尝试 ${\n this.reconnectState.attempts + 1\n }/${this.reconnectOptions.maxAttempts})`\n );\n\n return new Promise((resolve, reject) => {\n // 设置连接超时\n this.connectionTimeout = setTimeout(() => {\n const error = new Error(\n `连接超时 (${this.reconnectOptions.timeout}ms)`\n );\n this.handleConnectionError(error);\n reject(error);\n }, this.reconnectOptions.timeout);\n\n try {\n this.client = new Client(\n {\n name: `xiaozhi-${this.config.name}-client`,\n version: \"1.0.0\",\n },\n {\n capabilities: {\n tools: {},\n },\n }\n );\n\n // 使用 TransportFactory 创建传输层\n this.transport = TransportFactory.create(this.config);\n\n // 连接到 MCP 服务\n this.client\n .connect(this.transport)\n .then(async () => {\n this.handleConnectionSuccess();\n\n // 获取工具列表\n await this.refreshTools();\n\n resolve();\n })\n .catch((error) => {\n this.handleConnectionError(error);\n reject(error);\n });\n } catch (error) {\n this.handleConnectionError(error as Error);\n reject(error);\n }\n });\n }\n\n /**\n * 处理连接成功\n */\n private handleConnectionSuccess(): void {\n // 清理连接超时定时器\n if (this.connectionTimeout) {\n clearTimeout(this.connectionTimeout);\n this.connectionTimeout = null;\n }\n\n this.connectionState = ConnectionState.CONNECTED;\n this.initialized = true;\n\n // 重置重连状态\n this.reconnectState.attempts = 0;\n this.reconnectState.nextInterval = this.reconnectOptions.initialInterval;\n this.reconnectState.lastError = null;\n\n // 重置ping状态\n this.resetPingState();\n\n this.logWithTag(\"info\", `MCP 服务 ${this.config.name} 连接已建立`);\n\n // 启动ping监控\n this.startPingMonitoring();\n }\n\n /**\n * 处理连接错误\n */\n private handleConnectionError(error: Error): void {\n // 清理连接超时定时器\n if (this.connectionTimeout) {\n clearTimeout(this.connectionTimeout);\n this.connectionTimeout = null;\n }\n\n this.reconnectState.lastError = error;\n this.logger.error(`MCP 服务 ${this.config.name} 连接错误:`, error.message);\n\n // 清理当前连接\n this.cleanupConnection();\n\n // 检查是否需要重连\n if (this.shouldReconnect()) {\n this.scheduleReconnect();\n } else {\n this.connectionState = ConnectionState.FAILED;\n this.logger.warn(\n `${this.config.name} 已达到最大重连次数 (${this.reconnectOptions.maxAttempts}),停止重连`\n );\n }\n }\n\n /**\n * 检查是否应该重连\n */\n private shouldReconnect(): boolean {\n return (\n this.reconnectOptions.enabled &&\n this.reconnectState.attempts < this.reconnectOptions.maxAttempts &&\n !this.reconnectState.isManualDisconnect\n );\n }\n\n /**\n * 安排重连\n */\n private scheduleReconnect(): void {\n this.connectionState = ConnectionState.RECONNECTING;\n this.reconnectState.attempts++;\n\n // 计算下次重连间隔\n this.calculateNextInterval();\n\n this.logger.info(\n `${this.config.name} 将在 ${this.reconnectState.nextInterval}ms 后进行第 ${this.reconnectState.attempts} 次重连`\n );\n\n // 清理之前的重连定时器\n if (this.reconnectState.timer) {\n clearTimeout(this.reconnectState.timer);\n }\n\n // 设置重连定时器\n this.reconnectState.timer = setTimeout(async () => {\n try {\n await this.attemptConnection();\n } catch (error) {\n // 连接失败会触发 handleConnectionError,无需额外处理\n }\n }, this.reconnectState.nextInterval);\n }\n\n /**\n * 计算下次重连间隔\n */\n private calculateNextInterval(): void {\n let interval: number;\n\n switch (this.reconnectOptions.backoffStrategy) {\n case \"fixed\":\n interval = this.reconnectOptions.initialInterval;\n break;\n\n case \"linear\":\n interval =\n this.reconnectOptions.initialInterval +\n this.reconnectState.attempts *\n this.reconnectOptions.backoffMultiplier *\n 1000;\n break;\n\n case \"exponential\":\n interval =\n this.reconnectOptions.initialInterval *\n this.reconnectOptions.backoffMultiplier **\n (this.reconnectState.attempts - 1);\n break;\n\n default:\n interval = this.reconnectOptions.initialInterval;\n }\n\n // 限制最大间隔\n interval = Math.min(interval, this.reconnectOptions.maxInterval);\n\n // 添加随机抖动\n if (this.reconnectOptions.jitter) {\n const jitterRange = interval * 0.1; // 10% 抖动\n const jitter = (Math.random() - 0.5) * 2 * jitterRange;\n interval += jitter;\n }\n\n this.reconnectState.nextInterval = Math.max(interval, 1000); // 最小1秒\n }\n\n /**\n * 清理连接资源\n */\n private cleanupConnection(): void {\n // 停止ping监控\n this.stopPingMonitoring();\n\n // 清理客户端\n if (this.client) {\n try {\n this.client.close().catch(() => {\n // 忽略关闭时的错误\n });\n } catch (error) {\n // 忽略关闭时的错误\n }\n this.client = null;\n }\n\n // 清理传输层\n this.transport = null;\n\n // 清理连接超时定时器\n if (this.connectionTimeout) {\n clearTimeout(this.connectionTimeout);\n this.connectionTimeout = null;\n }\n\n // 重置状态\n this.initialized = false;\n }\n\n /**\n * 停止重连\n */\n private stopReconnect(): void {\n if (this.reconnectState.timer) {\n clearTimeout(this.reconnectState.timer);\n this.reconnectState.timer = null;\n }\n }\n\n /**\n * 刷新工具列表\n */\n private async refreshTools(): Promise<void> {\n if (!this.client) {\n throw new Error(\"客户端未初始化\");\n }\n\n try {\n const toolsResult = await this.client.listTools();\n const tools: Tool[] = toolsResult.tools || [];\n\n // 清空现有工具\n this.tools.clear();\n\n // 注册工具到映射表\n for (const tool of tools) {\n this.tools.set(tool.name, tool);\n }\n\n this.logger.info(\n `${this.config.name} 服务加载了 ${tools.length} 个工具: ${tools\n .map((t) => t.name)\n .join(\", \")}`\n );\n } catch (error) {\n this.logger.error(\n `${this.config.name} 获取工具列表失败:`,\n error instanceof Error ? error.message : String(error)\n );\n throw error;\n }\n }\n\n /**\n * 断开连接\n */\n async disconnect(): Promise<void> {\n this.logger.info(`主动断开 MCP 服务 ${this.config.name} 连接`);\n\n // 标记为手动断开,阻止自动重连\n this.reconnectState.isManualDisconnect = true;\n\n // 停止ping监控\n this.stopPingMonitoring();\n\n // 停止重连定时器\n this.stopReconnect();\n\n // 清理连接资源\n this.cleanupConnection();\n\n // 设置状态为已断开\n this.connectionState = ConnectionState.DISCONNECTED;\n }\n\n /**\n * 手动重连\n */\n async reconnect(): Promise<void> {\n this.logger.info(`手动重连 MCP 服务 ${this.config.name}`);\n\n // 停止自动重连\n this.stopReconnect();\n\n // 重置重连状态\n this.reconnectState.attempts = 0;\n this.reconnectState.nextInterval = this.reconnectOptions.initialInterval;\n this.reconnectState.isManualDisconnect = false;\n\n // 清理现有连接\n this.cleanupConnection();\n\n // 尝试连接\n await this.connect();\n }\n\n /**\n * 获取工具列表\n */\n getTools(): Tool[] {\n return Array.from(this.tools.values());\n }\n\n /**\n * 调用工具\n */\n async callTool(name: string, arguments_: any): Promise<ToolCallResult> {\n if (!this.client) {\n throw new Error(`服务 ${this.config.name} 未连接`);\n }\n\n if (!this.tools.has(name)) {\n throw new Error(`工具 ${name} 在服务 ${this.config.name} 中不存在`);\n }\n\n this.logger.info(\n `调用 ${this.config.name} 服务的工具 ${name},参数:`,\n JSON.stringify(arguments_)\n );\n\n try {\n const result = await this.client.callTool({\n name,\n arguments: arguments_ || {},\n });\n\n this.logger.info(\n `工具 ${name} 调用成功,结果:`,\n `${JSON.stringify(result).substring(0, 500)}...`\n );\n\n return result as ToolCallResult;\n } catch (error) {\n this.logger.error(\n `工具 ${name} 调用失败:`,\n error instanceof Error ? error.message : String(error)\n );\n throw error;\n }\n }\n\n /**\n * 获取服务配置\n */\n getConfig(): MCPServiceConfig {\n return this.config;\n }\n\n /**\n * 获取服务状态\n */\n getStatus(): MCPServiceStatus {\n return {\n name: this.config.name,\n connected: this.connectionState === ConnectionState.CONNECTED,\n initialized: this.initialized,\n transportType: this.config.type,\n toolCount: this.tools.size,\n lastError: this.reconnectState.lastError?.message,\n reconnectAttempts: this.reconnectState.attempts,\n connectionState: this.connectionState,\n // ping状态\n pingEnabled: this.pingOptions.enabled,\n lastPingTime: this.lastPingTime || undefined,\n pingFailureCount: this.pingFailureCount,\n isPinging: this.isPinging,\n };\n }\n\n /**\n * 检查是否已连接\n */\n isConnected(): boolean {\n return (\n this.connectionState === ConnectionState.CONNECTED && this.initialized\n );\n }\n\n /**\n * 启用自动重连\n */\n enableReconnect(): void {\n this.reconnectOptions.enabled = true;\n this.logger.info(`${this.config.name} 自动重连已启用`);\n }\n\n /**\n * 禁用自动重连\n */\n disableReconnect(): void {\n this.reconnectOptions.enabled = false;\n this.stopReconnect();\n this.logger.info(`${this.config.name} 自动重连已禁用`);\n }\n\n /**\n * 更新重连配置\n */\n updateReconnectOptions(options: Partial<ReconnectOptions>): void {\n this.reconnectOptions = { ...this.reconnectOptions, ...options };\n this.logger.info(`${this.config.name} 重连配置已更新`, options);\n }\n\n /**\n * 获取重连配置\n */\n getReconnectOptions(): ReconnectOptions {\n return { ...this.reconnectOptions };\n }\n\n /**\n * 重置重连状态\n */\n resetReconnectState(): void {\n this.stopReconnect();\n this.reconnectState.attempts = 0;\n this.reconnectState.nextInterval = this.reconnectOptions.initialInterval;\n this.reconnectState.lastError = null;\n this.logger.info(`${this.config.name} 重连状态已重置`);\n }\n\n /**\n * 启动ping监控\n */\n private startPingMonitoring(): void {\n if (!this.pingOptions.enabled || this.pingTimer || !this.isConnected()) {\n return;\n }\n\n this.logger.info(\n `${this.config.name} 启动ping监控,间隔: ${this.pingOptions.interval}ms`\n );\n\n // 延迟启动ping,让连接稳定\n setTimeout(() => {\n if (this.isConnected() && !this.pingTimer) {\n this.pingTimer = setInterval(() => {\n this.performPing();\n }, this.pingOptions.interval);\n }\n }, this.pingOptions.startDelay);\n }\n\n /**\n * 停止ping监控\n */\n private stopPingMonitoring(): void {\n if (this.pingTimer) {\n clearInterval(this.pingTimer);\n this.pingTimer = null;\n this.logger.debug(`${this.config.name} 停止ping监控`);\n }\n }\n\n /**\n * 执行ping检查\n */\n private async performPing(): Promise<void> {\n if (!this.client || this.isPinging || !this.isConnected()) {\n return;\n }\n\n this.isPinging = true;\n const startTime = performance.now();\n\n try {\n this.logger.debug(\n `${this.config.name} 发送ping请求(通过listTools检测连接)`\n );\n\n // 使用Promise.race实现超时控制\n // 由于MCP SDK可能没有直接的ping方法,我们使用listTools作为连接检测\n // 这是一个轻量级的操作,可以有效检测连接状态\n const pingPromise = this.client.listTools();\n\n const timeoutPromise = new Promise((_, reject) => {\n setTimeout(() => {\n reject(new Error(`Ping超时 (${this.pingOptions.timeout}ms)`));\n }, this.pingOptions.timeout);\n });\n\n await Promise.race([pingPromise, timeoutPromise]);\n\n const duration = performance.now() - startTime;\n this.handlePingSuccess(duration);\n } catch (error) {\n const duration = performance.now() - startTime;\n this.handlePingFailure(error as Error, duration);\n } finally {\n this.isPinging = false;\n }\n }\n\n /**\n * 处理ping成功\n */\n private handlePingSuccess(duration: number): void {\n this.pingFailureCount = 0;\n this.lastPingTime = new Date();\n this.logger.debug(\n `${this.config.name} ping成功,延迟: ${duration.toFixed(2)}ms`\n );\n }\n\n /**\n * 处理ping失败\n */\n private handlePingFailure(error: Error, duration: number): void {\n this.pingFailureCount++;\n this.logger.warn(\n `${this.config.name} ping失败 (${this.pingFailureCount}/${this.pingOptions.maxFailures}),` +\n `延迟: ${duration.toFixed(2)}ms,错误: ${error.message}`\n );\n\n // 如果连续失败次数达到阈值,触发重连\n if (this.pingFailureCount >= this.pingOptions.maxFailures) {\n this.logger.error(\n `${this.config.name} 连续ping失败达到阈值,触发重连机制`\n );\n\n // 停止ping监控,避免干扰重连过程\n this.stopPingMonitoring();\n\n // 创建连接错误并触发现有的重连机制\n const connectionError = new Error(\n `Ping检测失败,连续失败${this.pingFailureCount}次,连接可能已断开`\n );\n this.handleConnectionError(connectionError);\n }\n }\n\n /**\n * 重置ping状态\n */\n private resetPingState(): void {\n this.pingFailureCount = 0;\n this.lastPingTime = null;\n this.isPinging = false;\n }\n\n /**\n * 启用ping监控\n */\n enablePing(): void {\n this.pingOptions.enabled = true;\n this.logger.info(`${this.config.name} ping监控已启用`);\n\n // 如果当前已连接,立即启动ping监控\n if (this.isConnected()) {\n this.startPingMonitoring();\n }\n }\n\n /**\n * 禁用ping监控\n */\n disablePing(): void {\n this.pingOptions.enabled = false;\n this.stopPingMonitoring();\n this.logger.info(`${this.config.name} ping监控已禁用`);\n }\n\n /**\n * 更新ping配置\n */\n updatePingOptions(options: Partial<PingOptions>): void {\n const wasEnabled = this.pingOptions.enabled;\n this.pingOptions = { ...this.pingOptions, ...options };\n\n this.logger.info(`${this.config.name} ping配置已更新`, options);\n\n // 如果启用状态发生变化,相应地启动或停止监控\n if (wasEnabled !== this.pingOptions.enabled) {\n if (this.pingOptions.enabled && this.isConnected()) {\n this.startPingMonitoring();\n } else if (!this.pingOptions.enabled) {\n this.stopPingMonitoring();\n }\n }\n }\n\n /**\n * 获取ping配置\n */\n getPingOptions(): PingOptions {\n return { ...this.pingOptions };\n }\n}\n","/**\n * 配置适配器\n * 将旧的配置格式转换为新的 MCPServiceConfig 格式,确保向后兼容性\n */\n\nimport { isAbsolute, resolve } from \"node:path\";\nimport { logger as globalLogger } from \"../Logger.js\";\nimport type {\n LocalMCPServerConfig,\n MCPServerConfig,\n SSEMCPServerConfig,\n StreamableHTTPMCPServerConfig,\n} from \"../configManager.js\";\nimport type { MCPServiceConfig } from \"../services/MCPService.js\";\nimport { MCPTransportType } from \"../services/MCPService.js\";\n\n// 为配置适配器创建带标签的 logger\nconst logger = globalLogger.withTag(\"ConfigAdapter\");\n\n/**\n * 配置验证错误类\n */\nexport class ConfigValidationError extends Error {\n constructor(\n message: string,\n public readonly configName?: string\n ) {\n super(message);\n this.name = \"ConfigValidationError\";\n }\n}\n\n/**\n * 将旧的 MCPServerConfig 转换为新的 MCPServiceConfig\n */\nexport function convertLegacyToNew(\n serviceName: string,\n legacyConfig: MCPServerConfig\n): MCPServiceConfig {\n logger.debug(`转换配置: ${serviceName}`, legacyConfig);\n\n try {\n // 验证输入参数\n if (!serviceName || typeof serviceName !== \"string\") {\n throw new ConfigValidationError(\"服务名称必须是非空字符串\");\n }\n\n if (!legacyConfig || typeof legacyConfig !== \"object\") {\n throw new ConfigValidationError(\"配置对象不能为空\", serviceName);\n }\n\n // 根据配置类型进行转换\n const newConfig = convertByConfigType(serviceName, legacyConfig);\n\n // 验证转换后的配置\n validateNewConfig(newConfig);\n\n logger.info(`配置转换成功: ${serviceName} -> ${newConfig.type}`);\n return newConfig;\n } catch (error) {\n logger.error(`配置转换失败: ${serviceName}`, error);\n throw error instanceof ConfigValidationError\n ? error\n : new ConfigValidationError(\n `配置转换失败: ${error instanceof Error ? error.message : String(error)}`,\n serviceName\n );\n }\n}\n\n/**\n * 根据配置类型进行转换\n */\nfunction convertByConfigType(\n serviceName: string,\n legacyConfig: MCPServerConfig\n): MCPServiceConfig {\n // 检查是否为本地 stdio 配置\n if (isLocalConfig(legacyConfig)) {\n return convertLocalConfig(serviceName, legacyConfig);\n }\n\n // 检查是否为 SSE 配置\n if (isSSEConfig(legacyConfig)) {\n return convertSSEConfig(serviceName, legacyConfig);\n }\n\n // 检查是否为 Streamable HTTP 配置\n if (isStreamableHTTPConfig(legacyConfig)) {\n return convertStreamableHTTPConfig(serviceName, legacyConfig);\n }\n\n throw new ConfigValidationError(\"无法识别的配置类型\", serviceName);\n}\n\n/**\n * 转换本地 stdio 配置\n */\nfunction convertLocalConfig(\n serviceName: string,\n config: LocalMCPServerConfig\n): MCPServiceConfig {\n if (!config.command) {\n throw new ConfigValidationError(\n \"本地配置必须包含 command 字段\",\n serviceName\n );\n }\n\n // 获取用户的工作目录(优先使用环境变量,否则使用当前工作目录)\n const workingDir = process.env.XIAOZHI_CONFIG_DIR || process.cwd();\n\n // 解析 args 中的相对路径\n const resolvedArgs = (config.args || []).map((arg) => {\n // 检查是否为相对路径(以 ./ 开头或不以 / 开头且包含文件扩展名)\n if (isRelativePath(arg)) {\n const resolvedPath = resolve(workingDir, arg);\n logger.debug(`解析相对路径: ${arg} -> ${resolvedPath}`);\n return resolvedPath;\n }\n return arg;\n });\n\n return {\n name: serviceName,\n type: MCPTransportType.STDIO,\n command: config.command,\n args: resolvedArgs,\n env: config.env, // 传递环境变量\n // 默认重连配置\n reconnect: {\n enabled: true,\n maxAttempts: 5,\n initialInterval: 3000,\n maxInterval: 30000,\n backoffStrategy: \"exponential\" as const,\n backoffMultiplier: 1.5,\n timeout: 10000,\n jitter: true,\n },\n // 默认 ping 配置\n ping: {\n enabled: true,\n interval: 30000,\n timeout: 5000,\n maxFailures: 3,\n startDelay: 5000,\n },\n timeout: 30000,\n };\n}\n\n/**\n * 转换 SSE 配置\n */\nfunction convertSSEConfig(\n serviceName: string,\n config: SSEMCPServerConfig\n): MCPServiceConfig {\n if (!config.url) {\n throw new ConfigValidationError(\"SSE 配置必须包含 url 字段\", serviceName);\n }\n\n // 检查是否为 ModelScope 服务\n const isModelScope = isModelScopeURL(config.url);\n\n const baseConfig: MCPServiceConfig = {\n name: serviceName,\n type: isModelScope ? MCPTransportType.MODELSCOPE_SSE : MCPTransportType.SSE,\n url: config.url,\n // 默认重连配置\n reconnect: {\n enabled: true,\n maxAttempts: 10,\n initialInterval: 3000,\n maxInterval: 30000,\n backoffStrategy: \"exponential\" as const,\n backoffMultiplier: 1.5,\n timeout: 15000,\n jitter: true,\n },\n // 默认 ping 配置\n ping: {\n enabled: true,\n interval: 30000,\n timeout: 5000,\n maxFailures: 3,\n startDelay: 5000,\n },\n timeout: 30000,\n };\n\n // 如果是 ModelScope 服务,添加特殊配置\n if (isModelScope) {\n baseConfig.modelScopeAuth = true;\n }\n\n return baseConfig;\n}\n\n/**\n * 转换 Streamable HTTP 配置\n */\nfunction convertStreamableHTTPConfig(\n serviceName: string,\n config: StreamableHTTPMCPServerConfig\n): MCPServiceConfig {\n if (!config.url) {\n throw new ConfigValidationError(\n \"Streamable HTTP 配置必须包含 url 字段\",\n serviceName\n );\n }\n\n return {\n name: serviceName,\n type: MCPTransportType.STREAMABLE_HTTP,\n url: config.url,\n // 默认重连配置\n reconnect: {\n enabled: true,\n maxAttempts: 5,\n initialInterval: 3000,\n maxInterval: 30000,\n backoffStrategy: \"exponential\" as const,\n backoffMultiplier: 1.5,\n timeout: 15000,\n jitter: true,\n },\n // 默认 ping 配置\n ping: {\n enabled: false, // HTTP 连接通常不需要 ping\n interval: 60000,\n timeout: 10000,\n maxFailures: 3,\n startDelay: 10000,\n },\n timeout: 30000,\n };\n}\n\n/**\n * 批量转换配置\n */\nexport function convertLegacyConfigBatch(\n legacyConfigs: Record<string, MCPServerConfig>\n): Record<string, MCPServiceConfig> {\n const newConfigs: Record<string, MCPServiceConfig> = {};\n const errors: Array<{ serviceName: string; error: Error }> = [];\n\n for (const [serviceName, legacyConfig] of Object.entries(legacyConfigs)) {\n try {\n newConfigs[serviceName] = convertLegacyToNew(serviceName, legacyConfig);\n } catch (error) {\n errors.push({\n serviceName,\n error: error instanceof Error ? error : new Error(String(error)),\n });\n }\n }\n\n if (errors.length > 0) {\n const errorMessages = errors\n .map(({ serviceName, error }) => `${serviceName}: ${error.message}`)\n .join(\"; \");\n throw new ConfigValidationError(`批量配置转换失败: ${errorMessages}`);\n }\n\n logger.info(\n `批量配置转换成功,共转换 ${Object.keys(newConfigs).length} 个服务`\n );\n return newConfigs;\n}\n\n/**\n * 检查是否为相对路径\n */\nfunction isRelativePath(path: string): boolean {\n // 使用 Node.js 的 path.isAbsolute() 来正确检测绝对路径\n // 这个方法能够正确处理 Windows、macOS、Linux 三个平台的路径格式\n if (isAbsolute(path)) {\n return false; // 绝对路径不是相对路径\n }\n\n // 检查是否为相对路径的条件:\n // 1. 以 ./ 或 ../ 开头\n // 2. 包含常见的脚本文件扩展名(且不是绝对路径)\n if (path.startsWith(\"./\") || path.startsWith(\"../\")) {\n return true;\n }\n\n // 如果包含文件扩展名且不是绝对路径,也认为是相对路径\n if (/\\.(js|py|ts|mjs|cjs)$/i.test(path)) {\n return true;\n }\n\n return false;\n}\n\n/**\n * 检查是否为本地配置\n */\nfunction isLocalConfig(\n config: MCPServerConfig\n): config is LocalMCPServerConfig {\n return \"command\" in config && typeof config.command === \"string\";\n}\n\n/**\n * 检查是否为 SSE 配置\n */\nfunction isSSEConfig(config: MCPServerConfig): config is SSEMCPServerConfig {\n return \"type\" in config && config.type === \"sse\" && \"url\" in config;\n}\n\n/**\n * 检查是否为 Streamable HTTP 配置\n */\nfunction isStreamableHTTPConfig(\n config: MCPServerConfig\n): config is StreamableHTTPMCPServerConfig {\n return (\n \"url\" in config &&\n (!(\"type\" in config) || config.type === \"streamable-http\")\n );\n}\n\n/**\n * 检查是否为 ModelScope URL\n */\nfunction isModelScopeURL(url: string): boolean {\n return url.includes(\"modelscope.net\") || url.includes(\"modelscope.cn\");\n}\n\n/**\n * 验证新配置格式\n */\nfunction validateNewConfig(config: MCPServiceConfig): void {\n if (!config.name || typeof config.name !== \"string\") {\n throw new ConfigValidationError(\"配置必须包含有效的 name 字段\");\n }\n\n if (!Object.values(MCPTransportType).includes(config.type)) {\n throw new ConfigValidationError(`无效的传输类型: ${config.type}`);\n }\n\n // 根据传输类型验证必需字段\n switch (config.type) {\n case MCPTransportType.STDIO:\n if (!config.command) {\n throw new ConfigValidationError(\"STDIO 配置必须包含 command 字段\");\n }\n break;\n\n case MCPTransportType.SSE:\n case MCPTransportType.MODELSCOPE_SSE:\n case MCPTransportType.STREAMABLE_HTTP:\n if (!config.url) {\n throw new ConfigValidationError(`${config.type} 配置必须包含 url 字段`);\n }\n break;\n\n default:\n throw new ConfigValidationError(`不支持的传输类型: ${config.type}`);\n }\n}\n\n/**\n * 获取配置类型描述\n */\nexport function getConfigTypeDescription(config: MCPServerConfig): string {\n if (isLocalConfig(config)) {\n return `本地进程 (${config.command})`;\n }\n if (isSSEConfig(config)) {\n const isModelScope = isModelScopeURL(config.url);\n return `SSE${isModelScope ? \" (ModelScope)\" : \"\"} (${config.url})`;\n }\n if (isStreamableHTTPConfig(config)) {\n return `Streamable HTTP (${config.url})`;\n }\n return \"未知类型\";\n}\n","/**\n * MCP 服务工具函数 - 服务端版本\n * 用于判断 MCP 服务的通信类型和其他相关操作\n */\n\n// 定义通信类型\nexport type MCPCommunicationType = \"stdio\" | \"sse\" | \"streamable-http\";\n\n// 定义 MCP 服务配置类型(与客户端保持一致)\nexport interface LocalMCPServerConfig {\n command: string;\n args: string[];\n env?: Record<string, string>;\n}\n\nexport interface SSEMCPServerConfig {\n type: \"sse\";\n url: string;\n}\n\nexport interface StreamableHTTPMCPServerConfig {\n type?: \"streamable-http\"; // 可选,因为默认就是 streamable-http\n url: string;\n}\n\nexport type MCPServerConfig =\n | LocalMCPServerConfig\n | SSEMCPServerConfig\n | StreamableHTTPMCPServerConfig;\n\n/**\n * 判断 MCP 服务的通信类型\n *\n * @param serverConfig MCP 服务配置对象\n * @returns 通信类型:'stdio' | 'sse' | 'streamable-http'\n *\n * 判断逻辑:\n * 1. 如果配置对象有 command 字段 → stdio\n * 2. 如果配置对象有 type 字段且值为 \"sse\" → sse\n * 3. 如果配置对象有 url 字段但没有 type 字段,或者 type 字段不是 \"sse\" → streamable-http\n *\n * @example\n * ```typescript\n * // stdio 类型\n * const stdioConfig = {\n * command: \"node\",\n * args: [\"./mcpServers/calculator.js\"]\n * };\n * getMcpServerCommunicationType(stdioConfig); // \"stdio\"\n *\n * // sse 类型\n * const sseConfig = {\n * type: \"sse\" as const,\n * url: \"https://mcp.api-inference.modelscope.net/d3cfd34529ae4e/sse\"\n * };\n * getMcpServerCommunicationType(sseConfig); // \"sse\"\n *\n * // streamable-http 类型\n * const httpConfig = {\n * url: \"https://mcp.amap.com/mcp?key=1ec31da021b2702787841ea4ee822de3\"\n * };\n * getMcpServerCommunicationType(httpConfig); // \"streamable-http\"\n * ```\n */\nexport function getMcpServerCommunicationType(\n serverConfig: MCPServerConfig | Record<string, any>\n): MCPCommunicationType {\n // 参数验证\n if (!serverConfig || typeof serverConfig !== \"object\") {\n throw new Error(\"服务配置必须是一个有效的对象\");\n }\n\n // 1. 检查是否为 stdio 类型(有 command 字段)\n if (\"command\" in serverConfig && typeof serverConfig.command === \"string\") {\n return \"stdio\";\n }\n\n // 2. 检查是否为 sse 类型(有 type: \"sse\" 字段)\n if (\"type\" in serverConfig && serverConfig.type === \"sse\") {\n return \"sse\";\n }\n\n // 3. 检查是否为 streamable-http 类型(有 type: \"streamable-http\" 字段或有 url 字段)\n if (\n (\"type\" in serverConfig && serverConfig.type === \"streamable-http\") ||\n (\"url\" in serverConfig && typeof serverConfig.url === \"string\")\n ) {\n return \"streamable-http\";\n }\n\n // 如果都不匹配,抛出错误\n throw new Error(\n \"无法识别的 MCP 服务配置类型。配置必须包含 command 字段(stdio)、type: 'sse' 字段(sse)或 url 字段(streamable-http)\"\n );\n}\n\n/**\n * 检查 MCP 服务配置是否为 stdio 类型\n */\nexport function isStdioMcpServer(\n serverConfig: MCPServerConfig | Record<string, any>\n): serverConfig is LocalMCPServerConfig {\n return getMcpServerCommunicationType(serverConfig) === \"stdio\";\n}\n\n/**\n * 检查 MCP 服务配置是否为 sse 类型\n */\nexport function isSSEMcpServer(\n serverConfig: MCPServerConfig | Record<string, any>\n): serverConfig is SSEMCPServerConfig {\n return getMcpServerCommunicationType(serverConfig) === \"sse\";\n}\n\n/**\n * 检查 MCP 服务配置是否为 streamable-http 类型\n */\nexport function isStreamableHTTPMcpServer(\n serverConfig: MCPServerConfig | Record<string, any>\n): serverConfig is StreamableHTTPMCPServerConfig {\n return getMcpServerCommunicationType(serverConfig) === \"streamable-http\";\n}\n\n/**\n * 获取 MCP 服务配置的显示名称\n * 用于在日志中显示更友好的通信类型名称\n */\nexport function getMcpServerTypeDisplayName(\n serverConfig: MCPServerConfig | Record<string, any>\n): string {\n const type = getMcpServerCommunicationType(serverConfig);\n\n switch (type) {\n case \"stdio\":\n return \"本地进程 (stdio)\";\n case \"sse\":\n return \"服务器推送 (SSE)\";\n case \"streamable-http\":\n return \"流式 HTTP\";\n default:\n return \"未知类型\";\n }\n}\n\n/**\n * 验证 MCP 服务配置的完整性\n * 根据不同的通信类型验证必需的字段\n */\nexport function validateMcpServerConfig(\n serverName: string,\n serverConfig: any\n): { valid: boolean; error?: string } {\n if (!serverConfig || typeof serverConfig !== \"object\") {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 的配置必须是一个对象`,\n };\n }\n\n try {\n const communicationType = getMcpServerCommunicationType(serverConfig);\n\n switch (communicationType) {\n case \"stdio\":\n if (!serverConfig.command || typeof serverConfig.command !== \"string\") {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 缺少必需的 command 字段或字段类型不正确`,\n };\n }\n if (!Array.isArray(serverConfig.args)) {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 的 args 字段必须是数组`,\n };\n }\n if (serverConfig.env && typeof serverConfig.env !== \"object\") {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 的 env 字段必须是对象`,\n };\n }\n break;\n\n case \"sse\":\n if (serverConfig.type !== \"sse\") {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 的 type 字段必须是 \"sse\"`,\n };\n }\n if (!serverConfig.url || typeof serverConfig.url !== \"string\") {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 缺少必需的 url 字段或字段类型不正确`,\n };\n }\n break;\n\n case \"streamable-http\":\n if (!serverConfig.url || typeof serverConfig.url !== \"string\") {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 缺少必需的 url 字段或字段类型不正确`,\n };\n }\n if (serverConfig.type && serverConfig.type !== \"streamable-http\") {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 的 type 字段如果存在,必须是 \"streamable-http\"`,\n };\n }\n break;\n\n default:\n return {\n valid: false,\n error: `服务 \"${serverName}\" 的配置类型无法识别`,\n };\n }\n\n return { valid: true };\n } catch (error) {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 的配置无效: ${\n error instanceof Error ? error.message : \"未知错误\"\n }`,\n };\n }\n}\n","import { copyFileSync, existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport * as commentJson from \"comment-json\";\nimport dayjs from \"dayjs\";\nimport JSON5 from \"json5\";\nimport * as json5Writer from \"json5-writer\";\nimport { logger } from \"./Logger\";\nimport { validateMcpServerConfig } from \"./utils/mcpServerUtils\";\n\n// 在 ESM 中,需要从 import.meta.url 获取当前文件目录\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n// 默认连接配置\nconst DEFAULT_CONNECTION_CONFIG: Required<ConnectionConfig> = {\n heartbeatInterval: 30000, // 30秒心跳间隔\n heartbeatTimeout: 10000, // 10秒心跳超时\n reconnectInterval: 5000, // 5秒重连间隔\n};\n\n// 配置文件接口定义\n// 本地 MCP 服务配置\nexport interface LocalMCPServerConfig {\n command: string;\n args: string[];\n env?: Record<string, string>;\n}\n\n// SSE MCP 服务配置\nexport interface SSEMCPServerConfig {\n type: \"sse\";\n url: string;\n}\n\n// Streamable HTTP MCP 服务配置\nexport interface StreamableHTTPMCPServerConfig {\n type?: \"streamable-http\"; // 可选,因为默认就是 streamable-http\n url: string;\n}\n\n// 统一的 MCP 服务配置\nexport type MCPServerConfig =\n | LocalMCPServerConfig\n | SSEMCPServerConfig\n | StreamableHTTPMCPServerConfig;\n\nexport interface MCPToolConfig {\n description?: string;\n enable: boolean;\n usageCount?: number; // 工具使用次数\n lastUsedTime?: string; // 最后使用时间(ISO 8601 格式)\n}\n\nexport interface MCPServerToolsConfig {\n tools: Record<string, MCPToolConfig>;\n}\n\nexport interface ConnectionConfig {\n heartbeatInterval?: number; // 心跳检测间隔(毫秒),默认30000\n heartbeatTimeout?: number; // 心跳超时时间(毫秒),默认10000\n reconnectInterval?: number; // 重连间隔(毫秒),默认5000\n}\n\nexport interface ModelScopeConfig {\n apiKey?: string; // ModelScope API 密钥\n}\n\nexport interface WebUIConfig {\n port?: number; // Web UI 端口号,默认 9999\n autoRestart?: boolean; // 是否在配置更新后自动重启服务,默认 true\n}\n\nexport interface AppConfig {\n mcpEndpoint: string | string[];\n mcpServers: Record<string, MCPServerConfig>;\n mcpServerConfig?: Record<string, MCPServerToolsConfig>;\n connection?: ConnectionConfig; // 连接配置(可选,用于向后兼容)\n modelscope?: ModelScopeConfig; // ModelScope 配置(可选)\n webUI?: WebUIConfig; // Web UI 配置(可选)\n}\n\n/**\n * 配置管理类\n * 负责管理应用配置,提供只读访问和安全的配置更新功能\n */\nexport class ConfigManager {\n private static instance: ConfigManager;\n private defaultConfigPath: string;\n private config: AppConfig | null = null;\n private currentConfigPath: string | null = null; // 跟踪当前使用的配置文件路径\n private json5Writer: any = null; // json5-writer 实例,用于保留 JSON5 注释\n\n private constructor() {\n // 使用模板目录中的默认配置文件\n // 在不同环境中尝试不同的路径\n const possiblePaths = [\n // 构建后的环境:dist/configManager.js -> dist/templates/default/xiaozhi.config.json\n resolve(__dirname, \"templates\", \"default\", \"xiaozhi.config.json\"),\n // 开发环境:src/configManager.ts -> templates/default/xiaozhi.config.json\n resolve(__dirname, \"..\", \"templates\", \"default\", \"xiaozhi.config.json\"),\n // 测试环境或其他情况\n resolve(process.cwd(), \"templates\", \"default\", \"xiaozhi.config.json\"),\n ];\n\n // 找到第一个存在的路径\n this.defaultConfigPath =\n possiblePaths.find((path) => existsSync(path)) || possiblePaths[0];\n }\n\n /**\n * 获取配置文件路径(动态计算)\n * 支持多种配置文件格式:json5 > jsonc > json\n */\n private getConfigFilePath(): string {\n // 配置文件路径 - 优先使用环境变量指定的目录,否则使用当前工作目录\n const configDir = process.env.XIAOZHI_CONFIG_DIR || process.cwd();\n\n // 按优先级检查配置文件是否存在\n const configFileNames = [\n \"xiaozhi.config.json5\",\n \"xiaozhi.config.jsonc\",\n \"xiaozhi.config.json\",\n ];\n\n for (const fileName of configFileNames) {\n const filePath = resolve(configDir, fileName);\n if (existsSync(filePath)) {\n return filePath;\n }\n }\n\n // 如果都不存在,返回默认的 JSON 文件路径\n return resolve(configDir, \"xiaozhi.config.json\");\n }\n\n /**\n * 获取配置文件格式\n */\n private getConfigFileFormat(filePath: string): \"json5\" | \"jsonc\" | \"json\" {\n if (filePath.endsWith(\".json5\")) {\n return \"json5\";\n }\n\n if (filePath.endsWith(\".jsonc\")) {\n return \"jsonc\";\n }\n\n return \"json\";\n }\n\n /**\n * 获取配置管理器单例实例\n */\n public static getInstance(): ConfigManager {\n if (!ConfigManager.instance) {\n ConfigManager.instance = new ConfigManager();\n }\n return ConfigManager.instance;\n }\n\n /**\n * 检查配置文件是否存在\n */\n public configExists(): boolean {\n // 配置文件路径 - 优先使用环境变量指定的目录,否则使用当前工作目录\n const configDir = process.env.XIAOZHI_CONFIG_DIR || process.cwd();\n\n // 按优先级检查配置文件是否存在\n const configFileNames = [\n \"xiaozhi.config.json5\",\n \"xiaozhi.config.jsonc\",\n \"xiaozhi.config.json\",\n ];\n\n for (const fileName of configFileNames) {\n const filePath = resolve(configDir, fileName);\n if (existsSync(filePath)) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * 初始化配置文件\n * 从 config.default.json 复制到 config.json\n * @param format 配置文件格式,默认为 json\n */\n public initConfig(format: \"json\" | \"json5\" | \"jsonc\" = \"json\"): void {\n if (!existsSync(this.defaultConfigPath)) {\n throw new Error(`默认配置模板文件不存在: ${this.defaultConfigPath}`);\n }\n\n // 检查是否已有任何格式的配置文件\n if (this.configExists()) {\n throw new Error(\"配置文件已存在,无需重复初始化\");\n }\n\n // 确定目标配置文件路径\n const configDir = process.env.XIAOZHI_CONFIG_DIR || process.cwd();\n const targetFileName = `xiaozhi.config.${format}`;\n const configPath = resolve(configDir, targetFileName);\n\n // 复制默认配置文件\n copyFileSync(this.defaultConfigPath, configPath);\n this.config = null; // 重置缓存\n this.json5Writer = null; // 重置 json5Writer 实例\n }\n\n /**\n * 加载配置文件\n */\n private loadConfig(): AppConfig {\n if (!this.configExists()) {\n throw new Error(\"配置文件不存在,请先运行 xiaozhi init 初始化配置\");\n }\n\n try {\n const configPath = this.getConfigFilePath();\n this.currentConfigPath = configPath; // 记录当前使用的配置文件路径\n const configFileFormat = this.getConfigFileFormat(configPath);\n const rawConfigData = readFileSync(configPath, \"utf8\");\n\n // 移除可能存在的UTF-8 BOM字符(\\uFEFF)\n // BOM字符在某些编辑器中不可见,但会导致JSON解析失败\n // 这个过滤确保即使文件包含BOM字符也能正常解析\n const configData = rawConfigData.replace(/^\\uFEFF/, \"\");\n\n let config: AppConfig;\n\n // 根据文件格式使用相应的解析器\n switch (configFileFormat) {\n case \"json5\":\n // 使用 JSON5 解析配置对象,同时使用 json5-writer 保留注释信息\n config = JSON5.parse(configData) as AppConfig;\n // 创建 json5-writer 实例用于后续保存时保留注释\n this.json5Writer = json5Writer.load(configData);\n break;\n case \"jsonc\":\n // 使用 comment-json 解析 JSONC 格式,保留注释信息\n config = commentJson.parse(configData) as unknown as AppConfig;\n break;\n default:\n config = JSON.parse(configData) as AppConfig;\n break;\n }\n\n // 验证配置结构\n this.validateConfig(config);\n\n return config;\n } catch (error) {\n if (error instanceof SyntaxError) {\n throw new Error(`配置文件格式错误: ${error.message}`);\n }\n throw error;\n }\n }\n\n /**\n * 验证配置文件结构\n */\n private validateConfig(config: unknown): void {\n if (!config || typeof config !== \"object\") {\n throw new Error(\"配置文件格式错误:根对象无效\");\n }\n\n const configObj = config as Record<string, unknown>;\n\n if (configObj.mcpEndpoint === undefined || configObj.mcpEndpoint === null) {\n throw new Error(\"配置文件格式错误:mcpEndpoint 字段无效\");\n }\n\n // 验证 mcpEndpoint 类型(字符串或字符串数组)\n if (typeof configObj.mcpEndpoint === \"string\") {\n // 空字符串是允许的,getMcpEndpoints 会返回空数组\n } else if (Array.isArray(configObj.mcpEndpoint)) {\n if (configObj.mcpEndpoint.length === 0) {\n throw new Error(\"配置文件格式错误:mcpEndpoint 数组不能为空\");\n }\n for (const endpoint of configObj.mcpEndpoint) {\n if (typeof endpoint !== \"string\" || endpoint.trim() === \"\") {\n throw new Error(\n \"配置文件格式错误:mcpEndpoint 数组中的每个元素必须是非空字符串\"\n );\n }\n }\n } else {\n throw new Error(\"配置文件格式错误:mcpEndpoint 必须是字符串或字符串数组\");\n }\n\n if (!configObj.mcpServers || typeof configObj.mcpServers !== \"object\") {\n throw new Error(\"配置文件格式错误:mcpServers 字段无效\");\n }\n\n // 验证每个 MCP 服务配置\n for (const [serverName, serverConfig] of Object.entries(\n configObj.mcpServers as Record<string, unknown>\n )) {\n if (!serverConfig || typeof serverConfig !== \"object\") {\n throw new Error(`配置文件格式错误:mcpServers.${serverName} 无效`);\n }\n\n // 使用统一的验证逻辑\n const validation = validateMcpServerConfig(serverName, serverConfig);\n if (!validation.valid) {\n throw new Error(`配置文件格式错误:${validation.error}`);\n }\n }\n }\n\n /**\n * 获取配置(只读)\n */\n public getConfig(): Readonly<AppConfig> {\n this.config = this.loadConfig();\n\n // 返回深度只读副本\n return JSON.parse(JSON.stringify(this.config));\n }\n\n /**\n * 获取可修改的配置对象(内部使用,保留注释信息)\n */\n private getMutableConfig(): AppConfig {\n if (!this.config) {\n this.config = this.loadConfig();\n }\n return this.config;\n }\n\n /**\n * 获取 MCP 端点(向后兼容)\n * @deprecated 使用 getMcpEndpoints() 获取所有端点\n */\n public getMcpEndpoint(): string {\n const config = this.getConfig();\n if (Array.isArray(config.mcpEndpoint)) {\n return config.mcpEndpoint[0] || \"\";\n }\n return config.mcpEndpoint;\n }\n\n /**\n * 获取所有 MCP 端点\n */\n public getMcpEndpoints(): string[] {\n const config = this.getConfig();\n if (Array.isArray(config.mcpEndpoint)) {\n return [...config.mcpEndpoint];\n }\n return config.mcpEndpoint ? [config.mcpEndpoint] : [];\n }\n\n /**\n * 获取 MCP 服务配置\n */\n public getMcpServers(): Readonly<Record<string, MCPServerConfig>> {\n const config = this.getConfig();\n return config.mcpServers;\n }\n\n /**\n * 获取 MCP 服务工具配置\n */\n public getMcpServerConfig(): Readonly<Record<string, MCPServerToolsConfig>> {\n const config = this.getConfig();\n return config.mcpServerConfig || {};\n }\n\n /**\n * 获取指定服务的工具配置\n */\n public getServerToolsConfig(\n serverName: string\n ): Readonly<Record<string, MCPToolConfig>> {\n const serverConfig = this.getMcpServerConfig();\n return serverConfig[serverName]?.tools || {};\n }\n\n /**\n * 检查工具是否启用\n */\n public isToolEnabled(serverName: string, toolName: string): boolean {\n const toolsConfig = this.getServerToolsConfig(serverName);\n const toolConfig = toolsConfig[toolName];\n return toolConfig?.enable !== false; // 默认启用\n }\n\n /**\n * 更新 MCP 端点(支持字符串或数组)\n */\n public updateMcpEndpoint(endpoint: string | string[]): void {\n if (Array.isArray(endpoint)) {\n if (endpoint.length === 0) {\n throw new Error(\"MCP 端点数组不能为空\");\n }\n for (const ep of endpoint) {\n if (!ep || typeof ep !== \"string\") {\n throw new Error(\"MCP 端点数组中的每个元素必须是非空字符串\");\n }\n }\n } else {\n if (!endpoint || typeof endpoint !== \"string\") {\n throw new Error(\"MCP 端点必须是非空字符串\");\n }\n }\n\n const config = this.getMutableConfig();\n config.mcpEndpoint = endpoint;\n this.saveConfig(config);\n }\n\n /**\n * 添加 MCP 端点\n */\n public addMcpEndpoint(endpoint: string): void {\n if (!endpoint || typeof endpoint !== \"string\") {\n throw new Error(\"MCP 端点必须是非空字符串\");\n }\n\n const config = this.getMutableConfig();\n const currentEndpoints = this.getMcpEndpoints();\n\n // 检查是否已存在\n if (currentEndpoints.includes(endpoint)) {\n throw new Error(`MCP 端点 ${endpoint} 已存在`);\n }\n\n const newEndpoints = [...currentEndpoints, endpoint];\n config.mcpEndpoint = newEndpoints;\n this.saveConfig(config);\n }\n\n /**\n * 移除 MCP 端点\n */\n public removeMcpEndpoint(endpoint: string): void {\n if (!endpoint || typeof endpoint !== \"string\") {\n throw new Error(\"MCP 端点必须是非空字符串\");\n }\n\n const config = this.getMutableConfig();\n const currentEndpoints = this.getMcpEndpoints();\n\n // 检查是否存在\n const index = currentEndpoints.indexOf(endpoint);\n if (index === -1) {\n throw new Error(`MCP 端点 ${endpoint} 不存在`);\n }\n\n // 不允许删除最后一个端点\n if (currentEndpoints.length === 1) {\n throw new Error(\"不能删除最后一个 MCP 端点\");\n }\n\n const newEndpoints = currentEndpoints.filter((ep) => ep !== endpoint);\n config.mcpEndpoint = newEndpoints;\n this.saveConfig(config);\n }\n\n /**\n * 更新 MCP 服务配置\n */\n public updateMcpServer(\n serverName: string,\n serverConfig: MCPServerConfig\n ): void {\n if (!serverName || typeof serverName !== \"string\") {\n throw new Error(\"服务名称必须是非空字符串\");\n }\n\n // 使用统一的验证逻辑\n const validation = validateMcpServerConfig(serverName, serverConfig);\n if (!validation.valid) {\n throw new Error(validation.error || \"服务配置验证失败\");\n }\n const config = this.getMutableConfig();\n // 直接修改配置对象以保留注释信息\n config.mcpServers[serverName] = serverConfig;\n this.saveConfig(config);\n }\n\n /**\n * 删除 MCP 服务配置\n */\n public removeMcpServer(serverName: string): void {\n if (!serverName || typeof serverName !== \"string\") {\n throw new Error(\"服务名称必须是非空字符串\");\n }\n\n const config = this.getConfig();\n if (!config.mcpServers[serverName]) {\n throw new Error(`服务 ${serverName} 不存在`);\n }\n\n const newMcpServers = { ...config.mcpServers };\n delete newMcpServers[serverName];\n\n const newConfig = {\n ...config,\n mcpServers: newMcpServers,\n };\n this.saveConfig(newConfig);\n }\n\n /**\n * 更新服务工具配置\n */\n public updateServerToolsConfig(\n serverName: string,\n toolsConfig: Record<string, MCPToolConfig>\n ): void {\n const config = this.getMutableConfig();\n\n // 确保 mcpServerConfig 存在\n if (!config.mcpServerConfig) {\n config.mcpServerConfig = {};\n }\n\n // 如果 toolsConfig 为空对象,则删除该服务的配置\n if (Object.keys(toolsConfig).length === 0) {\n delete config.mcpServerConfig[serverName];\n } else {\n // 更新指定服务的工具配置\n config.mcpServerConfig[serverName] = {\n tools: toolsConfig,\n };\n }\n\n this.saveConfig(config);\n }\n\n /**\n * 删除指定服务器的工具配置\n */\n public removeServerToolsConfig(serverName: string): void {\n const config = this.getConfig();\n const newConfig = { ...config };\n\n // 确保 mcpServerConfig 存在\n if (newConfig.mcpServerConfig) {\n // 删除指定服务的工具配置\n delete newConfig.mcpServerConfig[serverName];\n this.saveConfig(newConfig);\n }\n }\n\n /**\n * 清理无效的服务器工具配置\n * 删除在 mcpServerConfig 中存在但在 mcpServers 中不存在的服务配置\n */\n public cleanupInvalidServerToolsConfig(): void {\n const config = this.getMutableConfig();\n\n // 如果没有 mcpServerConfig,无需清理\n if (!config.mcpServerConfig) {\n return;\n }\n\n const validServerNames = Object.keys(config.mcpServers);\n const configuredServerNames = Object.keys(config.mcpServerConfig);\n\n // 找出需要清理的服务名称\n const invalidServerNames = configuredServerNames.filter(\n (serverName) => !validServerNames.includes(serverName)\n );\n\n if (invalidServerNames.length > 0) {\n // 删除无效的服务配置\n for (const serverName of invalidServerNames) {\n delete config.mcpServerConfig[serverName];\n }\n\n this.saveConfig(config);\n\n logger.info(\n `已清理 ${invalidServerNames.length} 个无效的服务工具配置: ${invalidServerNames.join(\", \")}`\n );\n }\n }\n\n /**\n * 设置工具启用状态\n */\n public setToolEnabled(\n serverName: string,\n toolName: string,\n enabled: boolean,\n description?: string\n ): void {\n const config = this.getMutableConfig();\n\n // 确保 mcpServerConfig 存在\n if (!config.mcpServerConfig) {\n config.mcpServerConfig = {};\n }\n\n // 确保服务配置存在\n if (!config.mcpServerConfig[serverName]) {\n config.mcpServerConfig[serverName] = { tools: {} };\n }\n\n // 更新工具配置\n config.mcpServerConfig[serverName].tools[toolName] = {\n ...config.mcpServerConfig[serverName].tools[toolName],\n enable: enabled,\n ...(description && { description }),\n };\n\n this.saveConfig(config);\n }\n\n /**\n * 保存配置到文件\n * 保存到原始配置文件路径,保持文件格式一致性\n */\n private saveConfig(config: AppConfig): void {\n try {\n // 验证配置\n this.validateConfig(config);\n\n // 确定保存路径 - 优先使用当前配置文件路径,否则使用默认路径\n let configPath: string;\n if (this.currentConfigPath) {\n configPath = this.currentConfigPath;\n } else {\n // 如果没有当前路径,使用 getConfigFilePath 获取\n configPath = this.getConfigFilePath();\n this.currentConfigPath = configPath;\n }\n\n // 根据文件格式选择序列化方法\n const configFileFormat = this.getConfigFileFormat(configPath);\n let configContent: string;\n\n switch (configFileFormat) {\n case \"json5\":\n // 对于 JSON5 格式,使用 json5-writer 库保留注释\n try {\n if (this.json5Writer) {\n // 使用 json5-writer 更新配置并保留注释\n this.json5Writer.write(config);\n configContent = this.json5Writer.toSource();\n } else {\n // 如果没有 json5Writer 实例,回退到标准 JSON5\n console.warn(\"没有 json5Writer 实例,回退到标准 JSON5 格式\");\n configContent = JSON5.stringify(config, null, 2);\n }\n } catch (json5WriterError) {\n // 如果 json5-writer 序列化失败,回退到标准 JSON5\n console.warn(\n \"使用 json5-writer 保存失败,回退到标准 JSON5 格式:\",\n json5WriterError\n );\n configContent = JSON5.stringify(config, null, 2);\n }\n break;\n case \"jsonc\":\n // 对于 JSONC 格式,使用 comment-json 库保留注释\n try {\n // 直接使用 comment-json 的 stringify 方法\n // 如果 config 是通过 comment-json.parse 解析的,注释信息会被保留\n configContent = commentJson.stringify(config, null, 2);\n } catch (commentJsonError) {\n // 如果 comment-json 序列化失败,回退到标准 JSON\n console.warn(\n \"使用 comment-json 保存失败,回退到标准 JSON 格式:\",\n commentJsonError\n );\n configContent = JSON.stringify(config, null, 2);\n }\n break;\n default:\n configContent = JSON.stringify(config, null, 2);\n break;\n }\n\n // 保存到文件\n writeFileSync(configPath, configContent, \"utf8\");\n\n // 更新缓存\n this.config = config;\n\n // 通知 Web 界面配置已更新(如果 Web 服务器正在运行)\n this.notifyConfigUpdate(config);\n } catch (error) {\n throw new Error(\n `保存配置失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n\n /**\n * 重新加载配置(清除缓存)\n */\n public reloadConfig(): void {\n this.config = null;\n this.currentConfigPath = null; // 清除配置文件路径缓存\n this.json5Writer = null; // 清除 json5Writer 实例\n }\n\n /**\n * 获取配置文件路径\n */\n public getConfigPath(): string {\n return this.getConfigFilePath();\n }\n\n /**\n * 获取默认配置文件路径\n */\n public getDefaultConfigPath(): string {\n return this.defaultConfigPath;\n }\n\n /**\n * 获取连接配置(包含默认值)\n */\n public getConnectionConfig(): Required<ConnectionConfig> {\n const config = this.getConfig();\n const connectionConfig = config.connection || {};\n\n return {\n heartbeatInterval:\n connectionConfig.heartbeatInterval ??\n DEFAULT_CONNECTION_CONFIG.heartbeatInterval,\n heartbeatTimeout:\n connectionConfig.heartbeatTimeout ??\n DEFAULT_CONNECTION_CONFIG.heartbeatTimeout,\n reconnectInterval:\n connectionConfig.reconnectInterval ??\n DEFAULT_CONNECTION_CONFIG.reconnectInterval,\n };\n }\n\n /**\n * 获取心跳检测间隔(毫秒)\n */\n public getHeartbeatInterval(): number {\n return this.getConnectionConfig().heartbeatInterval;\n }\n\n /**\n * 获取心跳超时时间(毫秒)\n */\n public getHeartbeatTimeout(): number {\n return this.getConnectionConfig().heartbeatTimeout;\n }\n\n /**\n * 获取重连间隔(毫秒)\n */\n public getReconnectInterval(): number {\n return this.getConnectionConfig().reconnectInterval;\n }\n\n /**\n * 更新连接配置\n */\n public updateConnectionConfig(\n connectionConfig: Partial<ConnectionConfig>\n ): void {\n const config = this.getMutableConfig();\n\n // 确保 connection 对象存在\n if (!config.connection) {\n config.connection = {};\n }\n\n // 直接修改现有的 connection 对象以保留注释\n Object.assign(config.connection, connectionConfig);\n this.saveConfig(config);\n }\n\n /**\n * 更新工具使用统计信息\n * @param serverName 服务名称\n * @param toolName 工具名称\n * @param callTime 调用时间(ISO 8601 格式)\n */\n public async updateToolUsageStats(\n serverName: string,\n toolName: string,\n callTime: string\n ): Promise<void> {\n try {\n const config = this.getMutableConfig();\n\n // 确保 mcpServerConfig 存在\n if (!config.mcpServerConfig) {\n config.mcpServerConfig = {};\n }\n\n // 确保服务配置存在\n if (!config.mcpServerConfig[serverName]) {\n config.mcpServerConfig[serverName] = { tools: {} };\n }\n\n // 确保工具配置存在\n if (!config.mcpServerConfig[serverName].tools[toolName]) {\n config.mcpServerConfig[serverName].tools[toolName] = {\n enable: true, // 默认启用\n };\n }\n\n const toolConfig = config.mcpServerConfig[serverName].tools[toolName];\n const currentUsageCount = toolConfig.usageCount || 0;\n const currentLastUsedTime = toolConfig.lastUsedTime;\n\n // 更新使用次数\n toolConfig.usageCount = currentUsageCount + 1;\n\n // 时间校验:只有新时间晚于现有时间才更新 lastUsedTime\n if (\n !currentLastUsedTime ||\n new Date(callTime) > new Date(currentLastUsedTime)\n ) {\n // 使用 dayjs 格式化时间为更易读的格式\n toolConfig.lastUsedTime = dayjs(callTime).format(\"YYYY-MM-DD HH:mm:ss\");\n }\n\n // 保存配置\n this.saveConfig(config);\n\n logger.debug(\n `工具使用统计已更新: ${serverName}/${toolName}, 使用次数: ${toolConfig.usageCount}`\n );\n } catch (error) {\n // 错误不应该影响主要的工具调用流程\n logger.error(\n `更新工具使用统计失败 (${serverName}/${toolName}): ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n\n /**\n * 设置心跳检测间隔\n */\n public setHeartbeatInterval(interval: number): void {\n if (interval <= 0) {\n throw new Error(\"心跳检测间隔必须大于0\");\n }\n this.updateConnectionConfig({ heartbeatInterval: interval });\n }\n\n /**\n * 设置心跳超时时间\n */\n public setHeartbeatTimeout(timeout: number): void {\n if (timeout <= 0) {\n throw new Error(\"心跳超时时间必须大于0\");\n }\n this.updateConnectionConfig({ heartbeatTimeout: timeout });\n }\n\n /**\n * 设置重连间隔\n */\n public setReconnectInterval(interval: number): void {\n if (interval <= 0) {\n throw new Error(\"重连间隔必须大于0\");\n }\n this.updateConnectionConfig({ reconnectInterval: interval });\n }\n\n /**\n * 获取 ModelScope 配置\n */\n public getModelScopeConfig(): Readonly<ModelScopeConfig> {\n const config = this.getConfig();\n return config.modelscope || {};\n }\n\n /**\n * 获取 ModelScope API Key\n * 优先从配置文件读取,其次从环境变量读取\n */\n public getModelScopeApiKey(): string | undefined {\n const modelScopeConfig = this.getModelScopeConfig();\n return modelScopeConfig.apiKey || process.env.MODELSCOPE_API_TOKEN;\n }\n\n /**\n * 更新 ModelScope 配置\n */\n public updateModelScopeConfig(\n modelScopeConfig: Partial<ModelScopeConfig>\n ): void {\n const config = this.getMutableConfig();\n\n // 确保 modelscope 对象存在\n if (!config.modelscope) {\n config.modelscope = {};\n }\n\n // 直接修改现有的 modelscope 对象以保留注释\n Object.assign(config.modelscope, modelScopeConfig);\n this.saveConfig(config);\n }\n\n /**\n * 设置 ModelScope API Key\n */\n public setModelScopeApiKey(apiKey: string): void {\n if (!apiKey || typeof apiKey !== \"string\") {\n throw new Error(\"API Key 必须是非空字符串\");\n }\n this.updateModelScopeConfig({ apiKey });\n }\n\n /**\n * 获取 Web UI 配置\n */\n public getWebUIConfig(): Readonly<WebUIConfig> {\n const config = this.getConfig();\n return config.webUI || {};\n }\n\n /**\n * 获取 Web UI 端口号\n */\n public getWebUIPort(): number {\n const webUIConfig = this.getWebUIConfig();\n return webUIConfig.port ?? 9999; // 默认端口 9999\n }\n\n /**\n * 通知 Web 界面配置已更新\n * 如果 Web 服务器正在运行,通过 WebSocket 广播配置更新\n */\n private notifyConfigUpdate(config: AppConfig): void {\n try {\n // 检查是否有全局的 webServer 实例(当使用 --ui 参数启动时会设置)\n const webServer = (global as any).__webServer;\n if (webServer && typeof webServer.broadcastConfigUpdate === \"function\") {\n // 调用 webServer 的 broadcastConfigUpdate 方法来通知所有连接的客户端\n webServer.broadcastConfigUpdate(config);\n console.log(\"已通过 WebSocket 广播配置更新\");\n }\n } catch (error) {\n // 静默处理错误,不影响配置保存的主要功能\n console.warn(\n \"通知 Web 界面配置更新失败:\",\n error instanceof Error ? error.message : String(error)\n );\n }\n }\n\n /**\n * 更新 Web UI 配置\n */\n public updateWebUIConfig(webUIConfig: Partial<WebUIConfig>): void {\n const config = this.getMutableConfig();\n\n // 确保 webUI 对象存在\n if (!config.webUI) {\n config.webUI = {};\n }\n\n // 直接修改现有的 webUI 对象以保留注释\n Object.assign(config.webUI, webUIConfig);\n this.saveConfig(config);\n }\n\n /**\n * 设置 Web UI 端口号\n */\n public setWebUIPort(port: number): void {\n if (!Number.isInteger(port) || port <= 0 || port > 65535) {\n throw new Error(\"端口号必须是 1-65535 之间的整数\");\n }\n this.updateWebUIConfig({ port });\n }\n}\n\n// 导出单例实例\nexport const configManager = ConfigManager.getInstance();\n","#!/usr/bin/env node\n\n/**\n * MCP 服务管理器\n * 使用 MCPService 实例管理多个 MCP 服务\n * 专注于实例管理、工具聚合和路由调用\n */\n\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport { type Logger, logger } from \"../Logger.js\";\nimport { type MCPToolConfig, configManager } from \"../configManager.js\";\nimport {\n MCPService,\n type MCPServiceConfig,\n MCPTransportType,\n} from \"./MCPService.js\";\n\n// 工具信息接口(保持向后兼容)\ninterface ToolInfo {\n serviceName: string;\n originalName: string;\n tool: Tool;\n}\n\n// 服务状态接口(保持向后兼容)\ninterface ServiceStatus {\n connected: boolean;\n clientName: string;\n}\n\n// 管理器状态接口(保持向后兼容)\ninterface ManagerStatus {\n services: Record<string, ServiceStatus>;\n totalTools: number;\n availableTools: string[];\n}\n\n// 工具调用结果接口(保持向后兼容)\ninterface ToolCallResult {\n content: Array<{\n type: string;\n text: string;\n }>;\n isError?: boolean;\n}\n\nexport class MCPServiceManager {\n private services: Map<string, MCPService> = new Map();\n private configs: Record<string, MCPServiceConfig> = {};\n private logger: Logger;\n private tools: Map<string, ToolInfo> = new Map(); // 缓存工具信息,保持向后兼容\n\n /**\n * 创建 MCPServiceManager 实例\n * @param configs 可选的初始服务配置\n */\n constructor(configs?: Record<string, MCPServiceConfig>) {\n this.logger = logger;\n this.configs = configs || {};\n }\n\n /**\n * 启动所有 MCP 服务\n */\n async startAllServices(): Promise<void> {\n this.logger.info(\"[MCPManager] 正在启动所有 MCP 服务...\");\n\n const configEntries = Object.entries(this.configs);\n if (configEntries.length === 0) {\n this.logger.warn(\n \"[MCPManager] 没有配置任何 MCP 服务,请使用 addServiceConfig() 添加服务配置\"\n );\n return;\n }\n\n for (const [serviceName] of configEntries) {\n await this.startService(serviceName);\n }\n\n this.logger.info(\"[MCPManager] 所有 MCP 服务启动完成\");\n }\n\n /**\n * 启动单个 MCP 服务\n */\n async startService(serviceName: string): Promise<void> {\n this.logger.info(`[MCPManager] 启动 MCP 服务: ${serviceName}`);\n\n const config = this.configs[serviceName];\n if (!config) {\n throw new Error(`未找到服务配置: ${serviceName}`);\n }\n\n try {\n // 如果服务已存在,先停止它\n if (this.services.has(serviceName)) {\n await this.stopService(serviceName);\n }\n\n // 创建 MCPService 实例\n const service = new MCPService(config);\n\n // 连接到服务\n await service.connect();\n\n // 存储服务实例\n this.services.set(serviceName, service);\n\n // 更新工具缓存\n await this.refreshToolsCache();\n\n const tools = service.getTools();\n this.logger.info(\n `[MCPManager] ${serviceName} 服务启动成功,加载了 ${tools.length} 个工具:`,\n tools.map((t) => t.name).join(\", \")\n );\n } catch (error) {\n this.logger.error(\n `[MCPManager] 启动 ${serviceName} 服务失败:`,\n (error as Error).message\n );\n throw error;\n }\n }\n\n /**\n * 停止单个服务\n */\n async stopService(serviceName: string): Promise<void> {\n this.logger.info(`[MCPManager] 停止 MCP 服务: ${serviceName}`);\n\n const service = this.services.get(serviceName);\n if (!service) {\n this.logger.warn(`[MCPManager] 服务 ${serviceName} 不存在或未启动`);\n return;\n }\n\n try {\n await service.disconnect();\n this.services.delete(serviceName);\n\n // 更新工具缓存\n await this.refreshToolsCache();\n\n this.logger.info(`[MCPManager] ${serviceName} 服务已停止`);\n } catch (error) {\n this.logger.error(\n `[MCPManager] 停止 ${serviceName} 服务失败:`,\n (error as Error).message\n );\n throw error;\n }\n }\n\n /**\n * 刷新工具缓存\n */\n private async refreshToolsCache(): Promise<void> {\n this.tools.clear();\n\n for (const [serviceName, service] of this.services) {\n if (service.isConnected()) {\n const tools = service.getTools();\n for (const tool of tools) {\n const toolKey = `${serviceName}__${tool.name}`;\n this.tools.set(toolKey, {\n serviceName,\n originalName: tool.name,\n tool,\n });\n }\n }\n }\n\n // 同步工具配置到配置文件\n await this.syncToolsConfigToFile();\n }\n\n /**\n * 获取所有可用工具(已启用的工具)\n */\n getAllTools(): Array<{\n name: string;\n description: string;\n inputSchema: any;\n serviceName: string;\n originalName: string;\n }> {\n const allTools: Array<{\n name: string;\n description: string;\n inputSchema: any;\n serviceName: string;\n originalName: string;\n }> = [];\n\n for (const [toolKey, toolInfo] of this.tools) {\n // 检查工具是否启用\n const isEnabled = configManager.isToolEnabled(\n toolInfo.serviceName,\n toolInfo.originalName\n );\n\n // 只返回启用的工具\n if (isEnabled) {\n allTools.push({\n name: toolKey,\n description: toolInfo.tool.description || \"\",\n inputSchema: toolInfo.tool.inputSchema,\n serviceName: toolInfo.serviceName,\n originalName: toolInfo.originalName,\n });\n }\n }\n return allTools;\n }\n\n /**\n * 调用 MCP 工具\n */\n async callTool(toolName: string, arguments_: any): Promise<ToolCallResult> {\n this.logger.info(`[MCPManager] 调用工具: ${toolName},参数:`, arguments_);\n\n const toolInfo = this.tools.get(toolName);\n if (!toolInfo) {\n throw new Error(`未找到工具: ${toolName}`);\n }\n\n const service = this.services.get(toolInfo.serviceName);\n if (!service) {\n throw new Error(`服务 ${toolInfo.serviceName} 不可用`);\n }\n\n if (!service.isConnected()) {\n throw new Error(`服务 ${toolInfo.serviceName} 未连接`);\n }\n\n try {\n const result = await service.callTool(\n toolInfo.originalName,\n arguments_ || {}\n );\n\n this.logger.info(`[MCPManager] 工具 ${toolName} 调用成功,结果:`, result);\n return result as ToolCallResult;\n } catch (error) {\n this.logger.error(\n `[MCPManager] 工具 ${toolName} 调用失败:`,\n (error as Error).message\n );\n throw error;\n }\n }\n\n /**\n * 停止所有服务\n */\n async stopAllServices(): Promise<void> {\n this.logger.info(\"[MCPManager] 正在停止所有 MCP 服务...\");\n\n // 停止所有服务实例\n for (const [serviceName, service] of this.services) {\n try {\n await service.disconnect();\n this.logger.info(`[MCPManager] ${serviceName} 服务已停止`);\n } catch (error) {\n this.logger.error(\n `[MCPManager] 停止 ${serviceName} 服务失败:`,\n (error as Error).message\n );\n }\n }\n\n this.services.clear();\n this.tools.clear();\n\n this.logger.info(\"[MCPManager] 所有 MCP 服务已停止\");\n }\n\n /**\n * 获取服务状态\n */\n getStatus(): ManagerStatus {\n const status: ManagerStatus = {\n services: {},\n totalTools: this.tools.size,\n availableTools: Array.from(this.tools.keys()),\n };\n\n for (const [serviceName, service] of this.services) {\n const serviceStatus = service.getStatus();\n status.services[serviceName] = {\n connected: serviceStatus.connected,\n clientName: `xiaozhi-${serviceName}-client`,\n };\n }\n\n return status;\n }\n\n /**\n * 获取指定服务实例\n */\n getService(name: string): MCPService | undefined {\n return this.services.get(name);\n }\n\n /**\n * 获取所有服务实例\n */\n getAllServices(): Map<string, MCPService> {\n return new Map(this.services);\n }\n\n /**\n * 增强服务配置\n * 根据服务类型添加必要的全局配置\n */\n private enhanceServiceConfig(config: MCPServiceConfig): MCPServiceConfig {\n const enhancedConfig = { ...config };\n\n try {\n // 处理 ModelScope SSE 服务\n if (config.type === MCPTransportType.MODELSCOPE_SSE) {\n const modelScopeApiKey = configManager.getModelScopeApiKey();\n if (modelScopeApiKey) {\n enhancedConfig.apiKey = modelScopeApiKey;\n this.logger.info(\n `[MCPManager] 为 ${config.name} 服务添加 ModelScope API Key`\n );\n } else {\n this.logger.warn(\n `[MCPManager] ${config.name} 服务需要 ModelScope API Key,但未在配置中找到`\n );\n throw new Error(\n `ModelScope SSE 服务 ${config.name} 需要 API Key,请在配置文件中设置 modelscope.apiKey`\n );\n }\n }\n\n return enhancedConfig;\n } catch (error) {\n this.logger.error(`[MCPManager] 配置增强失败: ${config.name}`, error);\n throw error;\n }\n }\n\n /**\n * 添加服务配置(重载方法以支持两种调用方式)\n */\n addServiceConfig(name: string, config: MCPServiceConfig): void;\n addServiceConfig(config: MCPServiceConfig): void;\n addServiceConfig(\n nameOrConfig: string | MCPServiceConfig,\n config?: MCPServiceConfig\n ): void {\n let finalConfig: MCPServiceConfig;\n let serviceName: string;\n\n if (typeof nameOrConfig === \"string\" && config) {\n // 两参数版本\n serviceName = nameOrConfig;\n finalConfig = config;\n } else if (typeof nameOrConfig === \"object\") {\n // 单参数版本\n serviceName = nameOrConfig.name;\n finalConfig = nameOrConfig;\n } else {\n throw new Error(\"Invalid arguments for addServiceConfig\");\n }\n\n // 增强配置\n const enhancedConfig = this.enhanceServiceConfig(finalConfig);\n\n // 存储增强后的配置\n this.configs[serviceName] = enhancedConfig;\n this.logger.info(`[MCPManager] 已添加服务配置: ${serviceName}`);\n }\n\n /**\n * 更新服务配置\n */\n updateServiceConfig(name: string, config: MCPServiceConfig): void {\n // 增强配置\n const enhancedConfig = this.enhanceServiceConfig(config);\n\n // 存储增强后的配置\n this.configs[name] = enhancedConfig;\n this.logger.info(`[MCPManager] 已更新并增强服务配置: ${name}`);\n }\n\n /**\n * 移除服务配置\n */\n removeServiceConfig(name: string): void {\n delete this.configs[name];\n this.logger.info(`[MCPManager] 已移除服务配置: ${name}`);\n }\n\n /**\n * 同步工具配置到配置文件\n * 实现自动同步 MCP 服务工具配置到 xiaozhi.config.json\n */\n private async syncToolsConfigToFile(): Promise<void> {\n try {\n this.logger.debug(\"[MCPManager] 开始同步工具配置到配置文件\");\n\n // 获取当前配置文件中的 mcpServerConfig\n const currentServerConfigs = configManager.getMcpServerConfig();\n\n // 遍历所有已连接的服务\n for (const [serviceName, service] of this.services) {\n if (!service.isConnected()) {\n continue;\n }\n\n const tools = service.getTools();\n if (tools.length === 0) {\n continue;\n }\n\n // 获取当前服务在配置文件中的工具配置\n const currentToolsConfig =\n currentServerConfigs[serviceName]?.tools || {};\n\n // 构建新的工具配置\n const newToolsConfig: Record<string, MCPToolConfig> = {};\n\n for (const tool of tools) {\n const currentToolConfig = currentToolsConfig[tool.name];\n\n // 如果工具已存在,保留用户设置的 enable 状态,但更新描述\n if (currentToolConfig) {\n newToolsConfig[tool.name] = {\n ...currentToolConfig,\n description:\n tool.description || currentToolConfig.description || \"\",\n };\n } else {\n // 新工具,默认启用\n newToolsConfig[tool.name] = {\n description: tool.description || \"\",\n enable: true,\n };\n }\n }\n\n // 检查是否有工具被移除(在配置文件中存在但在当前工具列表中不存在)\n const currentToolNames = tools.map((t) => t.name);\n const configToolNames = Object.keys(currentToolsConfig);\n const removedTools = configToolNames.filter(\n (name) => !currentToolNames.includes(name)\n );\n\n if (removedTools.length > 0) {\n this.logger.info(\n `[MCPManager] 检测到服务 ${serviceName} 移除了 ${removedTools.length} 个工具: ${removedTools.join(\", \")}`\n );\n }\n\n // 检查配置是否有变化\n const hasChanges = this.hasToolsConfigChanged(\n currentToolsConfig,\n newToolsConfig\n );\n\n if (hasChanges) {\n // 更新配置文件\n configManager.updateServerToolsConfig(serviceName, newToolsConfig);\n\n const addedTools = Object.keys(newToolsConfig).filter(\n (name) => !currentToolsConfig[name]\n );\n const updatedTools = Object.keys(newToolsConfig).filter((name) => {\n const current = currentToolsConfig[name];\n const updated = newToolsConfig[name];\n return current && current.description !== updated.description;\n });\n\n this.logger.info(\n `[MCPManager] 已同步服务 ${serviceName} 的工具配置:`\n );\n if (addedTools.length > 0) {\n this.logger.info(` - 新增工具: ${addedTools.join(\", \")}`);\n }\n if (updatedTools.length > 0) {\n this.logger.info(` - 更新工具: ${updatedTools.join(\", \")}`);\n }\n if (removedTools.length > 0) {\n this.logger.info(` - 移除工具: ${removedTools.join(\", \")}`);\n }\n }\n }\n\n this.logger.debug(\"[MCPManager] 工具配置同步完成\");\n } catch (error) {\n this.logger.error(\"[MCPManager] 同步工具配置到配置文件失败:\", error);\n // 不抛出错误,避免影响服务正常运行\n }\n }\n\n /**\n * 检查工具配置是否有变化\n */\n private hasToolsConfigChanged(\n currentConfig: Record<string, MCPToolConfig>,\n newConfig: Record<string, MCPToolConfig>\n ): boolean {\n const currentKeys = Object.keys(currentConfig);\n const newKeys = Object.keys(newConfig);\n\n // 检查工具数量是否变化\n if (currentKeys.length !== newKeys.length) {\n return true;\n }\n\n // 检查是否有新增或删除的工具\n const addedTools = newKeys.filter((key) => !currentKeys.includes(key));\n const removedTools = currentKeys.filter((key) => !newKeys.includes(key));\n\n if (addedTools.length > 0 || removedTools.length > 0) {\n return true;\n }\n\n // 检查现有工具的描述是否有变化\n for (const toolName of currentKeys) {\n const currentTool = currentConfig[toolName];\n const newTool = newConfig[toolName];\n\n if (currentTool.description !== newTool.description) {\n return true;\n }\n }\n\n return false;\n }\n}\n\nexport default MCPServiceManager;\n","/**\n * MCP 服务管理器单例\n * 提供全局唯一的 MCPServiceManager 实例,解决多实例资源冲突问题\n */\n\nimport MCPServiceManager from \"./MCPServiceManager.js\";\n\n// 重新导出相关类型,便于外部使用\nexport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nexport type { LocalMCPServerConfig } from \"../configManager.js\";\n\n// 单例状态枚举\nenum SingletonState {\n NOT_INITIALIZED = \"not_initialized\",\n INITIALIZING = \"initializing\",\n INITIALIZED = \"initialized\",\n FAILED = \"failed\",\n CLEANUP = \"cleanup\",\n}\n\n// 单例状态接口\ninterface SingletonStatus {\n state: SingletonState;\n initializationTime?: Date;\n lastError?: Error;\n instanceId?: string;\n}\n\n// 单例状态管理变量\nlet instance: MCPServiceManager | null = null;\nlet initPromise: Promise<MCPServiceManager> | null = null;\nlet state: SingletonState = SingletonState.NOT_INITIALIZED;\nlet lastError: Error | null = null;\nlet instanceId: string | null = null;\n\n/**\n * 创建 MCPServiceManager 实例(私有函数)\n */\nasync function createInstance(): Promise<MCPServiceManager> {\n console.log(\"🚀 正在初始化 MCPServiceManager 单例...\");\n\n const manager = new MCPServiceManager();\n\n return manager;\n}\n\n/**\n * 获取 MCPServiceManager 单例实例\n *\n * @returns Promise<MCPServiceManager> 管理器实例\n * @throws Error 如果初始化失败\n */\nasync function getInstance(): Promise<MCPServiceManager> {\n // 如果已经初始化完成,直接返回实例\n if (instance && state === SingletonState.INITIALIZED) {\n return instance;\n }\n\n // 如果正在初始化中,等待同一个初始化Promise\n if (initPromise && state === SingletonState.INITIALIZING) {\n return initPromise;\n }\n\n // 如果之前初始化失败,重置状态准备重试\n if (state === SingletonState.FAILED) {\n reset();\n }\n\n // 开始新的初始化过程\n state = SingletonState.INITIALIZING;\n initPromise = createInstance();\n\n try {\n instance = await initPromise;\n state = SingletonState.INITIALIZED;\n instanceId = `mcp-manager-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;\n lastError = null;\n\n console.log(`✅ MCPServiceManager 单例初始化成功,实例ID: ${instanceId}`);\n return instance;\n } catch (error) {\n state = SingletonState.FAILED;\n lastError = error as Error;\n initPromise = null;\n\n console.error(\n \"❌ MCPServiceManager 单例初始化失败:\",\n (error as Error).message\n );\n throw error;\n }\n}\n\n/**\n * 清理单例资源\n *\n * @returns Promise<void>\n */\nasync function cleanup(): Promise<void> {\n if (state === SingletonState.CLEANUP) {\n console.log(\"⚠️ MCPServiceManager 单例已在清理中,跳过重复清理\");\n return;\n }\n\n console.log(\"🧹 正在清理 MCPServiceManager 单例资源...\");\n state = SingletonState.CLEANUP;\n\n try {\n // 清理初始化Promise\n if (initPromise) {\n try {\n const instanceFromPromise = await initPromise;\n await instanceFromPromise.stopAllServices();\n } catch (error) {\n console.error(\"清理初始化中的实例失败:\", (error as Error).message);\n }\n initPromise = null;\n }\n\n // 清理已初始化的实例\n if (instance) {\n await instance.stopAllServices();\n instance = null;\n }\n\n state = SingletonState.NOT_INITIALIZED;\n lastError = null;\n instanceId = null;\n\n console.log(\"✅ MCPServiceManager 单例资源清理完成\");\n } catch (error) {\n console.error(\n \"❌ MCPServiceManager 单例清理失败:\",\n (error as Error).message\n );\n // 即使清理失败,也要重置状态,避免永久锁定\n reset();\n throw error;\n }\n}\n\n/**\n * 重置单例状态(用于错误恢复)\n *\n * 注意:这个方法不会清理资源,只是重置状态\n * 如果需要清理资源,请使用 cleanup() 方法\n */\nfunction reset(): void {\n console.log(\"🔄 重置 MCPServiceManager 单例状态\");\n\n instance = null;\n initPromise = null;\n state = SingletonState.NOT_INITIALIZED;\n lastError = null;\n instanceId = null;\n}\n\n/**\n * 检查单例是否已初始化\n *\n * @returns boolean 是否已初始化\n */\nfunction isInitialized(): boolean {\n return state === SingletonState.INITIALIZED && instance !== null;\n}\n\n/**\n * 获取单例状态信息\n *\n * @returns SingletonStatus 状态信息\n */\nfunction getStatus(): SingletonStatus {\n return {\n state: state,\n initializationTime: instanceId ? new Date() : undefined,\n lastError: lastError || undefined,\n instanceId: instanceId || undefined,\n };\n}\n\n/**\n * 强制重新初始化单例\n *\n * 这个方法会先清理现有资源,然后重新初始化\n *\n * @returns Promise<MCPServiceManager> 新的管理器实例\n */\nasync function forceReinitialize(): Promise<MCPServiceManager> {\n console.log(\"🔄 强制重新初始化 MCPServiceManager 单例...\");\n\n await cleanup();\n return getInstance();\n}\n\n/**\n * 获取当前实例(同步方法,仅在确定已初始化时使用)\n *\n * @returns MCPServiceManager | null 当前实例或null\n */\nfunction getCurrentInstance(): MCPServiceManager | null {\n return instance;\n}\n\n/**\n * 等待初始化完成(如果正在初始化中)\n *\n * @returns Promise<boolean> 是否成功初始化\n */\nasync function waitForInitialization(): Promise<boolean> {\n if (state === SingletonState.INITIALIZED) {\n return true;\n }\n\n if (state === SingletonState.INITIALIZING && initPromise) {\n try {\n await initPromise;\n return true;\n } catch (error) {\n return false;\n }\n }\n\n return false;\n}\n\n/**\n * MCPServiceManager 全局单例管理器\n *\n * 使用对象包装模块级函数,保持原有API接口不变\n */\nexport const MCPServiceManagerSingleton = {\n getInstance,\n cleanup,\n reset,\n isInitialized,\n getStatus,\n forceReinitialize,\n getCurrentInstance,\n waitForInitialization,\n} as const;\n\n// 导出默认实例(便于使用)\nexport default MCPServiceManagerSingleton;\n\n// 进程退出时自动清理资源\nprocess.on(\"exit\", () => {\n if (MCPServiceManagerSingleton.isInitialized()) {\n console.log(\"🔄 进程退出,正在清理 MCPServiceManager 单例...\");\n // 注意:这里不能使用 await,因为 exit 事件是同步的\n MCPServiceManagerSingleton.reset();\n }\n});\n\n// 处理未捕获的异常\nprocess.on(\"uncaughtException\", async (error) => {\n console.error(\"💥 未捕获的异常,清理 MCPServiceManager 单例:\", error);\n try {\n await MCPServiceManagerSingleton.cleanup();\n } catch (cleanupError) {\n console.error(\"清理过程中发生错误:\", cleanupError);\n }\n});\n\n// 处理未处理的Promise拒绝\nprocess.on(\"unhandledRejection\", async (reason) => {\n console.error(\"💥 未处理的Promise拒绝,清理 MCPServiceManager 单例:\", reason);\n try {\n await MCPServiceManagerSingleton.cleanup();\n } catch (cleanupError) {\n console.error(\"清理过程中发生错误:\", cleanupError);\n }\n});\n","import { EventEmitter } from \"node:events\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport { type Logger, logger } from \"../Logger.js\";\nimport { ProxyMCPServer } from \"../ProxyMCPServer.js\";\n\n// 使用接口定义避免循环依赖\ninterface IMCPServiceManager {\n getAllTools(): Tool[];\n}\n\n// 配置变更事件类型\nexport interface ConfigChangeEvent {\n type:\n | \"endpoints_added\"\n | \"endpoints_removed\"\n | \"endpoints_updated\"\n | \"options_updated\";\n data: {\n added?: string[];\n removed?: string[];\n updated?: string[];\n oldOptions?: Partial<XiaozhiConnectionOptions>;\n newOptions?: Partial<XiaozhiConnectionOptions>;\n };\n timestamp: Date;\n}\n\n// 重连策略枚举\nexport enum ReconnectStrategy {\n EXPONENTIAL_BACKOFF = \"exponential_backoff\",\n LINEAR_BACKOFF = \"linear_backoff\",\n FIXED_INTERVAL = \"fixed_interval\",\n ADAPTIVE = \"adaptive\",\n}\n\n// 错误类型枚举\nexport enum ConnectionErrorType {\n NETWORK_ERROR = \"network_error\",\n AUTHENTICATION_ERROR = \"authentication_error\",\n SERVER_ERROR = \"server_error\",\n TIMEOUT_ERROR = \"timeout_error\",\n UNKNOWN_ERROR = \"unknown_error\",\n}\n\n// 连接选项接口\nexport interface XiaozhiConnectionOptions {\n healthCheckInterval?: number; // 健康检查间隔(毫秒),默认 30000\n reconnectInterval?: number; // 重连间隔(毫秒),默认 5000\n maxReconnectAttempts?: number; // 最大重连次数,默认 10\n loadBalanceStrategy?: \"round-robin\" | \"random\" | \"health-based\"; // 负载均衡策略,默认 'round-robin'\n connectionTimeout?: number; // 连接超时时间(毫秒),默认 10000\n reconnectStrategy?: ReconnectStrategy; // 重连策略,默认 exponential_backoff\n maxReconnectDelay?: number; // 最大重连延迟(毫秒),默认 30000\n reconnectBackoffMultiplier?: number; // 退避乘数,默认 2\n jitterEnabled?: boolean; // 是否启用抖动,默认 true\n}\n\n// 连接状态接口\nexport interface ConnectionStatus {\n endpoint: string;\n connected: boolean;\n initialized: boolean;\n lastConnected?: Date;\n lastError?: string;\n reconnectAttempts: number;\n healthScore: number; // 健康度评分 (0-100)\n lastHealthCheck?: Date;\n responseTime?: number; // 响应时间(毫秒)\n consecutiveFailures: number; // 连续失败次数\n totalRequests: number; // 总请求次数\n successfulRequests: number; // 成功请求次数\n lastSuccessTime?: Date; // 最后成功时间\n healthCheckEnabled: boolean; // 是否启用健康检查\n // 重连相关状态\n isReconnecting: boolean; // 是否正在重连\n nextReconnectTime?: Date; // 下次重连时间\n lastReconnectAttempt?: Date; // 最后重连尝试时间\n reconnectDelay: number; // 当前重连延迟(毫秒)\n errorType?: ConnectionErrorType; // 错误类型\n reconnectHistory: Array<{\n // 重连历史\n timestamp: Date;\n success: boolean;\n error?: string;\n delay: number;\n }>;\n}\n\n// 连接状态枚举\nexport enum XiaozhiConnectionState {\n DISCONNECTED = \"disconnected\",\n CONNECTING = \"connecting\",\n CONNECTED = \"connected\",\n RECONNECTING = \"reconnecting\",\n FAILED = \"failed\",\n}\n\n// 默认配置\nconst DEFAULT_OPTIONS: Required<XiaozhiConnectionOptions> = {\n healthCheckInterval: 30000,\n reconnectInterval: 5000,\n maxReconnectAttempts: 10,\n loadBalanceStrategy: \"round-robin\",\n connectionTimeout: 10000,\n reconnectStrategy: ReconnectStrategy.EXPONENTIAL_BACKOFF,\n maxReconnectDelay: 30000,\n reconnectBackoffMultiplier: 2,\n jitterEnabled: true,\n};\n\n/**\n * 小智连接管理器\n * 负责管理多个小智接入点的连接,提供统一的连接管理、健康检查、负载均衡等功能\n */\nexport class XiaozhiConnectionManager extends EventEmitter {\n // 连接实例管理\n private connections: Map<string, ProxyMCPServer> = new Map();\n private connectionStates: Map<string, ConnectionStatus> = new Map();\n\n // 核心依赖\n private mcpServiceManager: IMCPServiceManager | null = null;\n private logger: Logger;\n\n // 状态管理\n private isInitialized = false;\n private isConnecting = false;\n\n // 配置选项\n private options: Required<XiaozhiConnectionOptions>;\n\n // 健康检查和重连管理\n private healthCheckInterval: NodeJS.Timeout | null = null;\n private reconnectTimers: Map<string, NodeJS.Timeout> = new Map();\n\n // 负载均衡状态\n private roundRobinIndex = 0;\n private lastSelectedEndpoint: string | null = null;\n\n // 性能监控\n private performanceMetrics = {\n connectionStartTime: 0,\n totalConnectionTime: 0,\n averageConnectionTime: 0,\n connectionCount: 0,\n memoryUsage: {\n initial: 0,\n current: 0,\n peak: 0,\n },\n prewarmedConnections: new Set<string>(),\n };\n\n constructor(options?: XiaozhiConnectionOptions) {\n super();\n this.logger = logger;\n this.options = { ...DEFAULT_OPTIONS, ...options };\n\n this.logger.info(\"[XiaozhiConnectionManager] 实例已创建\");\n this.logger.debug(\"[XiaozhiConnectionManager] 配置选项:\", this.options);\n }\n\n /**\n * 初始化连接管理器\n * @param endpoints 小智接入点列表\n * @param tools 工具列表\n */\n async initialize(endpoints: string[], tools: Tool[]): Promise<void> {\n if (this.isInitialized) {\n this.logger.warn(\"XiaozhiConnectionManager 已经初始化,跳过重复初始化\");\n return;\n }\n\n this.logger.info(\n `开始初始化 XiaozhiConnectionManager,端点数量: ${endpoints.length}`\n );\n\n try {\n // 验证输入参数\n this.validateInitializeParams(endpoints, tools);\n\n // 清理现有连接(如果有)\n await this.cleanup();\n\n // 为每个端点创建连接实例\n for (const endpoint of endpoints) {\n await this.createConnection(endpoint, tools);\n }\n\n this.isInitialized = true;\n\n // 记录初始内存使用\n this.performanceMetrics.memoryUsage.initial =\n process.memoryUsage().heapUsed;\n this.performanceMetrics.memoryUsage.current =\n this.performanceMetrics.memoryUsage.initial;\n this.performanceMetrics.memoryUsage.peak =\n this.performanceMetrics.memoryUsage.initial;\n\n this.logger.info(\n `XiaozhiConnectionManager 初始化完成,管理 ${this.connections.size} 个连接`\n );\n } catch (error) {\n this.logger.error(\"XiaozhiConnectionManager 初始化失败:\", error);\n await this.cleanup(); // 清理部分创建的连接\n throw error;\n }\n }\n\n /**\n * 连接所有端点\n */\n async connect(): Promise<void> {\n if (!this.isInitialized) {\n throw new Error(\n \"XiaozhiConnectionManager 未初始化,请先调用 initialize()\"\n );\n }\n\n if (this.isConnecting) {\n this.logger.warn(\"连接操作正在进行中,请等待完成\");\n return;\n }\n\n this.isConnecting = true;\n this.performanceMetrics.connectionStartTime = Date.now();\n this.logger.info(`开始连接所有端点,总数: ${this.connections.size}`);\n\n try {\n const connectionPromises: Promise<void>[] = [];\n\n // 并发连接所有端点\n for (const [endpoint, proxyServer] of this.connections) {\n connectionPromises.push(\n this.connectSingleEndpoint(endpoint, proxyServer)\n );\n }\n\n // 等待所有连接完成(允许部分失败)\n const results = await Promise.allSettled(connectionPromises);\n\n // 统计连接结果\n const successCount = results.filter(\n (result) => result.status === \"fulfilled\"\n ).length;\n const failureCount = results.length - successCount;\n\n // 更新性能指标\n const connectionTime =\n Date.now() - this.performanceMetrics.connectionStartTime;\n this.performanceMetrics.totalConnectionTime += connectionTime;\n this.performanceMetrics.connectionCount++;\n this.performanceMetrics.averageConnectionTime =\n this.performanceMetrics.totalConnectionTime /\n this.performanceMetrics.connectionCount;\n\n this.logger.info(\n `连接完成 - 成功: ${successCount}, 失败: ${failureCount}, 耗时: ${connectionTime}ms`\n );\n\n // 如果所有连接都失败,抛出错误\n if (successCount === 0) {\n throw new Error(\"所有小智接入点连接失败\");\n }\n\n // 启动健康检查\n this.startHealthCheck();\n } finally {\n this.isConnecting = false;\n }\n }\n\n /**\n * 断开所有连接\n */\n async disconnect(): Promise<void> {\n this.logger.info(\"开始断开所有连接\");\n\n // 停止健康检查\n this.stopHealthCheck();\n\n // 清理重连定时器\n this.clearAllReconnectTimers();\n\n // 断开所有连接\n const disconnectPromises: Promise<void>[] = [];\n for (const [endpoint, proxyServer] of this.connections) {\n disconnectPromises.push(\n this.disconnectSingleEndpoint(endpoint, proxyServer)\n );\n }\n\n await Promise.allSettled(disconnectPromises);\n this.logger.info(\"所有连接已断开\");\n }\n\n /**\n * 动态添加端点\n * @param endpoint 端点地址\n */\n async addEndpoint(endpoint: string): Promise<void> {\n if (!this.isInitialized) {\n throw new Error(\"XiaozhiConnectionManager 未初始化\");\n }\n\n if (this.connections.has(endpoint)) {\n this.logger.warn(`端点 ${endpoint} 已存在,跳过添加`);\n return;\n }\n\n this.logger.info(`动态添加端点: ${endpoint}`);\n\n try {\n // 获取当前工具列表\n const tools = this.getCurrentTools();\n\n // 创建新连接\n await this.createConnection(endpoint, tools);\n\n // 如果管理器已连接,则连接新端点\n if (this.isAnyConnected()) {\n const proxyServer = this.connections.get(endpoint)!;\n await this.connectSingleEndpoint(endpoint, proxyServer);\n }\n\n this.logger.info(`端点 ${endpoint} 添加成功`);\n } catch (error) {\n this.logger.error(`添加端点 ${endpoint} 失败:`, error);\n // 清理失败的连接\n this.connections.delete(endpoint);\n this.connectionStates.delete(endpoint);\n throw error;\n }\n }\n\n /**\n * 动态移除端点\n * @param endpoint 端点地址\n */\n async removeEndpoint(endpoint: string): Promise<void> {\n if (!this.connections.has(endpoint)) {\n this.logger.warn(`端点 ${endpoint} 不存在,跳过移除`);\n return;\n }\n\n this.logger.info(`动态移除端点: ${endpoint}`);\n\n try {\n const proxyServer = this.connections.get(endpoint)!;\n\n // 断开连接\n await this.disconnectSingleEndpoint(endpoint, proxyServer);\n\n // 清理资源\n this.connections.delete(endpoint);\n this.connectionStates.delete(endpoint);\n\n // 清理重连定时器\n const timer = this.reconnectTimers.get(endpoint);\n if (timer) {\n clearTimeout(timer);\n this.reconnectTimers.delete(endpoint);\n }\n\n this.logger.info(`端点 ${endpoint} 移除成功`);\n } catch (error) {\n this.logger.error(`移除端点 ${endpoint} 失败:`, error);\n throw error;\n }\n }\n\n /**\n * 获取健康的连接列表\n */\n getHealthyConnections(): ProxyMCPServer[] {\n const healthyConnections: ProxyMCPServer[] = [];\n\n for (const [endpoint, proxyServer] of this.connections) {\n const status = this.connectionStates.get(endpoint);\n if (status?.connected && status.healthScore > 50) {\n healthyConnections.push(proxyServer);\n }\n }\n\n return healthyConnections;\n }\n\n /**\n * 获取所有连接状态\n */\n getConnectionStatus(): ConnectionStatus[] {\n return Array.from(this.connectionStates.values());\n }\n\n /**\n * 检查是否有任何连接处于连接状态\n */\n isAnyConnected(): boolean {\n for (const status of this.connectionStates.values()) {\n if (status.connected) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * 设置 MCP 服务管理器\n * @param manager MCP 服务管理器实例\n */\n setServiceManager(manager: IMCPServiceManager): void {\n this.mcpServiceManager = manager;\n this.logger.info(\"已设置 MCPServiceManager\");\n\n // 如果已有连接,同步工具到所有连接\n if (this.connections.size > 0) {\n this.syncToolsToAllConnections();\n }\n }\n\n /**\n * 启用/禁用指定端点的健康检查\n * @param endpoint 端点地址\n * @param enabled 是否启用\n */\n setHealthCheckEnabled(endpoint: string, enabled: boolean): void {\n const status = this.connectionStates.get(endpoint);\n if (status) {\n status.healthCheckEnabled = enabled;\n this.logger.info(\n `端点 ${endpoint} 健康检查已${enabled ? \"启用\" : \"禁用\"}`\n );\n } else {\n this.logger.warn(`端点 ${endpoint} 不存在,无法设置健康检查状态`);\n }\n }\n\n /**\n * 获取健康检查统计信息\n */\n getHealthCheckStats(): Record<\n string,\n {\n endpoint: string;\n healthScore: number;\n successRate: number;\n averageResponseTime: number;\n consecutiveFailures: number;\n lastHealthCheck?: Date;\n lastSuccessTime?: Date;\n }\n > {\n const stats: Record<string, any> = {};\n\n for (const [endpoint, status] of this.connectionStates) {\n const successRate =\n status.totalRequests > 0\n ? (status.successfulRequests / status.totalRequests) * 100\n : 0;\n\n stats[endpoint] = {\n endpoint,\n healthScore: status.healthScore,\n successRate: Math.round(successRate * 100) / 100,\n averageResponseTime: status.responseTime || 0,\n consecutiveFailures: status.consecutiveFailures,\n lastHealthCheck: status.lastHealthCheck,\n lastSuccessTime: status.lastSuccessTime,\n };\n }\n\n return stats;\n }\n\n /**\n * 手动触发健康检查\n */\n async triggerHealthCheck(): Promise<void> {\n this.logger.info(\"手动触发健康检查\");\n await this.performHealthCheck();\n }\n\n /**\n * 手动触发指定端点的重连\n * @param endpoint 端点地址\n */\n async triggerReconnect(endpoint: string): Promise<void> {\n const status = this.connectionStates.get(endpoint);\n if (!status) {\n throw new Error(`端点 ${endpoint} 不存在`);\n }\n\n if (status.connected) {\n this.logger.warn(`端点 ${endpoint} 已连接,无需重连`);\n return;\n }\n\n this.logger.info(`手动触发重连: ${endpoint}`);\n\n // 清理现有的重连定时器\n const existingTimer = this.reconnectTimers.get(endpoint);\n if (existingTimer) {\n clearTimeout(existingTimer);\n this.reconnectTimers.delete(endpoint);\n }\n\n // 立即执行重连\n await this.performReconnect(endpoint);\n }\n\n /**\n * 停止指定端点的重连\n * @param endpoint 端点地址\n */\n stopReconnect(endpoint: string): void {\n const status = this.connectionStates.get(endpoint);\n if (!status) {\n this.logger.warn(`端点 ${endpoint} 不存在`);\n return;\n }\n\n const timer = this.reconnectTimers.get(endpoint);\n if (timer) {\n clearTimeout(timer);\n this.reconnectTimers.delete(endpoint);\n status.isReconnecting = false;\n status.nextReconnectTime = undefined;\n this.logger.info(`已停止端点 ${endpoint} 的重连`);\n }\n }\n\n /**\n * 停止所有端点的重连\n */\n stopAllReconnects(): void {\n this.logger.info(\"停止所有端点的重连\");\n\n for (const [endpoint] of this.reconnectTimers) {\n this.stopReconnect(endpoint);\n }\n }\n\n /**\n * 获取重连统计信息\n */\n getReconnectStats(): Record<\n string,\n {\n endpoint: string;\n reconnectAttempts: number;\n isReconnecting: boolean;\n nextReconnectTime?: Date;\n lastReconnectAttempt?: Date;\n reconnectDelay: number;\n errorType?: ConnectionErrorType;\n recentReconnectHistory: Array<{\n timestamp: Date;\n success: boolean;\n error?: string;\n delay: number;\n }>;\n }\n > {\n const stats: Record<string, any> = {};\n\n for (const [endpoint, status] of this.connectionStates) {\n stats[endpoint] = {\n endpoint,\n reconnectAttempts: status.reconnectAttempts,\n isReconnecting: status.isReconnecting,\n nextReconnectTime: status.nextReconnectTime,\n lastReconnectAttempt: status.lastReconnectAttempt,\n reconnectDelay: status.reconnectDelay,\n errorType: status.errorType,\n recentReconnectHistory: status.reconnectHistory.slice(-5), // 最近5次\n };\n }\n\n return stats;\n }\n\n /**\n * 验证端点配置\n */\n private validateEndpoints(endpoints: string[]): {\n valid: string[];\n invalid: string[];\n } {\n const valid: string[] = [];\n const invalid: string[] = [];\n\n for (const endpoint of endpoints) {\n if (!endpoint || typeof endpoint !== \"string\") {\n invalid.push(endpoint);\n continue;\n }\n\n if (!endpoint.startsWith(\"ws://\") && !endpoint.startsWith(\"wss://\")) {\n invalid.push(endpoint);\n continue;\n }\n\n // 检查是否是有效的 URL\n try {\n new URL(endpoint);\n valid.push(endpoint);\n } catch {\n invalid.push(endpoint);\n }\n }\n\n return { valid, invalid };\n }\n\n /**\n * 验证连接选项\n */\n private validateOptions(options: Partial<XiaozhiConnectionOptions>): {\n valid: boolean;\n errors: string[];\n } {\n const errors: string[] = [];\n\n if (options.healthCheckInterval !== undefined) {\n if (\n typeof options.healthCheckInterval !== \"number\" ||\n options.healthCheckInterval < 1000\n ) {\n errors.push(\"healthCheckInterval 必须是大于等于 1000 的数字\");\n }\n }\n\n if (options.reconnectInterval !== undefined) {\n if (\n typeof options.reconnectInterval !== \"number\" ||\n options.reconnectInterval < 100\n ) {\n errors.push(\"reconnectInterval 必须是大于等于 100 的数字\");\n }\n }\n\n if (options.maxReconnectAttempts !== undefined) {\n if (\n typeof options.maxReconnectAttempts !== \"number\" ||\n options.maxReconnectAttempts < 0\n ) {\n errors.push(\"maxReconnectAttempts 必须是大于等于 0 的数字\");\n }\n }\n\n if (options.connectionTimeout !== undefined) {\n if (\n typeof options.connectionTimeout !== \"number\" ||\n options.connectionTimeout < 1000\n ) {\n errors.push(\"connectionTimeout 必须是大于等于 1000 的数字\");\n }\n }\n\n if (options.maxReconnectDelay !== undefined) {\n if (\n typeof options.maxReconnectDelay !== \"number\" ||\n options.maxReconnectDelay < 1000\n ) {\n errors.push(\"maxReconnectDelay 必须是大于等于 1000 的数字\");\n }\n }\n\n if (options.reconnectBackoffMultiplier !== undefined) {\n if (\n typeof options.reconnectBackoffMultiplier !== \"number\" ||\n options.reconnectBackoffMultiplier < 1\n ) {\n errors.push(\"reconnectBackoffMultiplier 必须是大于等于 1 的数字\");\n }\n }\n\n if (options.loadBalanceStrategy !== undefined) {\n const validStrategies = [\"round-robin\", \"random\", \"health-based\"];\n if (!validStrategies.includes(options.loadBalanceStrategy)) {\n errors.push(\n `loadBalanceStrategy 必须是以下值之一: ${validStrategies.join(\", \")}`\n );\n }\n }\n\n if (options.reconnectStrategy !== undefined) {\n const validStrategies = Object.values(ReconnectStrategy);\n if (!validStrategies.includes(options.reconnectStrategy)) {\n errors.push(\n `reconnectStrategy 必须是以下值之一: ${validStrategies.join(\", \")}`\n );\n }\n }\n\n return { valid: errors.length === 0, errors };\n }\n\n /**\n * 更新端点配置\n * @param newEndpoints 新的端点列表\n * @param tools 工具列表\n */\n async updateEndpoints(\n newEndpoints: string[],\n tools: Tool[] = []\n ): Promise<void> {\n if (!this.isInitialized) {\n throw new Error(\"XiaozhiConnectionManager 未初始化\");\n }\n\n this.logger.info(`更新端点配置,新端点数量: ${newEndpoints.length}`);\n\n // 验证新端点\n const { valid: validEndpoints, invalid: invalidEndpoints } =\n this.validateEndpoints(newEndpoints);\n\n if (invalidEndpoints.length > 0) {\n this.logger.warn(`发现无效端点: ${invalidEndpoints.join(\", \")}`);\n }\n\n if (validEndpoints.length === 0) {\n throw new Error(\"没有有效的端点\");\n }\n\n // 计算变更\n const currentEndpoints = Array.from(this.connections.keys());\n const toAdd = validEndpoints.filter((ep) => !currentEndpoints.includes(ep));\n const toRemove = currentEndpoints.filter(\n (ep) => !validEndpoints.includes(ep)\n );\n const toKeep = currentEndpoints.filter((ep) => validEndpoints.includes(ep));\n\n this.logger.info(\n `端点变更 - 添加: ${toAdd.length}, 移除: ${toRemove.length}, 保持: ${toKeep.length}`\n );\n\n try {\n // 移除不需要的端点\n for (const endpoint of toRemove) {\n await this.removeEndpoint(endpoint);\n }\n\n // 添加新端点\n for (const endpoint of toAdd) {\n await this.addEndpoint(endpoint);\n }\n\n // 发送配置变更事件\n const changeEvent: ConfigChangeEvent = {\n type:\n toAdd.length > 0 && toRemove.length > 0\n ? \"endpoints_updated\"\n : toAdd.length > 0\n ? \"endpoints_added\"\n : \"endpoints_removed\",\n data: {\n added: toAdd.length > 0 ? toAdd : undefined,\n removed: toRemove.length > 0 ? toRemove : undefined,\n updated:\n toAdd.length > 0 && toRemove.length > 0\n ? validEndpoints\n : undefined,\n },\n timestamp: new Date(),\n };\n\n this.emit(\"configChange\", changeEvent);\n this.logger.info(\"端点配置更新完成\");\n } catch (error) {\n this.logger.error(\"端点配置更新失败:\", error);\n throw error;\n }\n }\n\n /**\n * 更新连接选项\n * @param newOptions 新的连接选项\n */\n updateOptions(newOptions: Partial<XiaozhiConnectionOptions>): void {\n this.logger.info(\"更新连接选项\");\n\n // 验证新选项\n const { valid, errors } = this.validateOptions(newOptions);\n\n if (!valid) {\n throw new Error(`无效的连接选项: ${errors.join(\", \")}`);\n }\n\n const oldOptions = { ...this.options };\n\n // 更新选项\n this.options = { ...this.options, ...newOptions };\n\n // 发送配置变更事件\n const changeEvent: ConfigChangeEvent = {\n type: \"options_updated\",\n data: {\n oldOptions,\n newOptions,\n },\n timestamp: new Date(),\n };\n\n this.emit(\"configChange\", changeEvent);\n this.logger.info(\"连接选项更新完成\");\n this.logger.debug(\"新的配置选项:\", this.options);\n }\n\n /**\n * 获取当前配置\n */\n getCurrentConfig(): {\n endpoints: string[];\n options: Required<XiaozhiConnectionOptions>;\n } {\n return {\n endpoints: Array.from(this.connections.keys()),\n options: { ...this.options },\n };\n }\n\n /**\n * 热重载配置\n * @param config 新配置\n */\n async reloadConfig(config: {\n endpoints?: string[];\n options?: Partial<XiaozhiConnectionOptions>;\n tools?: Tool[];\n }): Promise<void> {\n this.logger.info(\"开始热重载配置\");\n\n try {\n // 更新选项(如果提供)\n if (config.options) {\n this.updateOptions(config.options);\n }\n\n // 更新端点(如果提供)\n if (config.endpoints) {\n await this.updateEndpoints(config.endpoints, config.tools || []);\n }\n\n this.logger.info(\"配置热重载完成\");\n } catch (error) {\n this.logger.error(\"配置热重载失败:\", error);\n throw error;\n }\n }\n\n /**\n * 根据负载均衡策略选择最佳连接\n * @param excludeEndpoints 要排除的端点列表\n */\n selectBestConnection(excludeEndpoints: string[] = []): ProxyMCPServer | null {\n const healthyConnections = this.getHealthyConnections();\n\n if (healthyConnections.length === 0) {\n this.logger.warn(\"没有健康的连接可用\");\n return null;\n }\n\n // 过滤掉要排除的端点\n const availableConnections = healthyConnections.filter((connection) => {\n const endpoint = this.getEndpointByConnection(connection);\n return endpoint && !excludeEndpoints.includes(endpoint);\n });\n\n if (availableConnections.length === 0) {\n this.logger.warn(\"没有可用的连接(排除指定端点后)\");\n return null;\n }\n\n let selectedConnection: ProxyMCPServer;\n\n switch (this.options.loadBalanceStrategy) {\n case \"round-robin\":\n selectedConnection = this.selectRoundRobin(availableConnections);\n break;\n\n case \"random\":\n selectedConnection = this.selectRandom(availableConnections);\n break;\n\n case \"health-based\":\n selectedConnection = this.selectHealthBased(availableConnections);\n break;\n\n default:\n selectedConnection = this.selectRoundRobin(availableConnections);\n }\n\n // 更新最后选择的端点\n this.lastSelectedEndpoint =\n this.getEndpointByConnection(selectedConnection);\n\n return selectedConnection;\n }\n\n /**\n * 轮询算法选择连接\n */\n private selectRoundRobin(connections: ProxyMCPServer[]): ProxyMCPServer {\n if (connections.length === 0) {\n throw new Error(\"没有可用的连接\");\n }\n\n const connection = connections[this.roundRobinIndex % connections.length];\n this.roundRobinIndex = (this.roundRobinIndex + 1) % connections.length;\n\n return connection;\n }\n\n /**\n * 随机算法选择连接\n */\n private selectRandom(connections: ProxyMCPServer[]): ProxyMCPServer {\n if (connections.length === 0) {\n throw new Error(\"没有可用的连接\");\n }\n\n const randomIndex = Math.floor(Math.random() * connections.length);\n return connections[randomIndex];\n }\n\n /**\n * 基于健康度的选择算法\n */\n private selectHealthBased(connections: ProxyMCPServer[]): ProxyMCPServer {\n if (connections.length === 0) {\n throw new Error(\"没有可用的连接\");\n }\n\n // 获取所有连接的健康度信息\n const connectionHealths = connections.map((connection) => {\n const endpoint = this.getEndpointByConnection(connection);\n const status = endpoint ? this.connectionStates.get(endpoint) : null;\n return {\n connection,\n endpoint,\n healthScore: status?.healthScore || 0,\n responseTime: status?.responseTime || Number.POSITIVE_INFINITY,\n successRate:\n status && status.totalRequests > 0\n ? (status.successfulRequests / status.totalRequests) * 100\n : 0,\n };\n });\n\n // 按健康度排序(健康度高、响应时间短、成功率高的优先)\n connectionHealths.sort((a, b) => {\n // 首先按健康度排序\n if (a.healthScore !== b.healthScore) {\n return b.healthScore - a.healthScore;\n }\n\n // 健康度相同时,按成功率排序\n if (a.successRate !== b.successRate) {\n return b.successRate - a.successRate;\n }\n\n // 成功率相同时,按响应时间排序\n return a.responseTime - b.responseTime;\n });\n\n // 使用加权随机选择,健康度高的连接被选中的概率更大\n const totalWeight = connectionHealths.reduce(\n (sum, item) => sum + (item.healthScore + 1),\n 0\n );\n let randomWeight = Math.random() * totalWeight;\n\n for (const item of connectionHealths) {\n randomWeight -= item.healthScore + 1;\n if (randomWeight <= 0) {\n return item.connection;\n }\n }\n\n // 如果没有选中任何连接,返回健康度最高的\n return connectionHealths[0].connection;\n }\n\n /**\n * 根据连接实例获取端点地址\n */\n private getEndpointByConnection(connection: ProxyMCPServer): string | null {\n for (const [endpoint, conn] of this.connections) {\n if (conn === connection) {\n return endpoint;\n }\n }\n return null;\n }\n\n /**\n * 获取负载均衡统计信息\n */\n getLoadBalanceStats(): {\n strategy: string;\n totalConnections: number;\n healthyConnections: number;\n lastSelectedEndpoint: string | null;\n roundRobinIndex: number;\n connectionWeights: Record<\n string,\n {\n healthScore: number;\n responseTime: number;\n successRate: number;\n weight: number;\n }\n >;\n } {\n const healthyConnections = this.getHealthyConnections();\n const connectionWeights: Record<string, any> = {};\n\n for (const [endpoint, status] of this.connectionStates) {\n const successRate =\n status.totalRequests > 0\n ? (status.successfulRequests / status.totalRequests) * 100\n : 0;\n\n // 计算权重(用于健康度选择算法)\n const weight = status.healthScore + 1;\n\n connectionWeights[endpoint] = {\n healthScore: status.healthScore,\n responseTime: status.responseTime || 0,\n successRate: Math.round(successRate * 100) / 100,\n weight,\n };\n }\n\n return {\n strategy: this.options.loadBalanceStrategy,\n totalConnections: this.connections.size,\n healthyConnections: healthyConnections.length,\n lastSelectedEndpoint: this.lastSelectedEndpoint,\n roundRobinIndex: this.roundRobinIndex,\n connectionWeights,\n };\n }\n\n /**\n * 切换负载均衡策略\n * @param strategy 新的负载均衡策略\n */\n setLoadBalanceStrategy(\n strategy: \"round-robin\" | \"random\" | \"health-based\"\n ): void {\n const oldStrategy = this.options.loadBalanceStrategy;\n this.options.loadBalanceStrategy = strategy;\n\n // 重置轮询索引\n if (strategy === \"round-robin\") {\n this.roundRobinIndex = 0;\n }\n\n this.logger.info(`负载均衡策略已从 ${oldStrategy} 切换到 ${strategy}`);\n\n // 发送配置变更事件\n const changeEvent: ConfigChangeEvent = {\n type: \"options_updated\",\n data: {\n oldOptions: { loadBalanceStrategy: oldStrategy },\n newOptions: { loadBalanceStrategy: strategy },\n },\n timestamp: new Date(),\n };\n\n this.emit(\"configChange\", changeEvent);\n }\n\n /**\n * 执行故障转移\n * @param failedEndpoint 失败的端点\n */\n async performFailover(\n failedEndpoint: string\n ): Promise<ProxyMCPServer | null> {\n this.logger.warn(`执行故障转移,失败端点: ${failedEndpoint}`);\n\n // 选择备用连接(排除失败的端点)\n const backupConnection = this.selectBestConnection([failedEndpoint]);\n\n if (!backupConnection) {\n this.logger.error(\"故障转移失败:没有可用的备用连接\");\n return null;\n }\n\n const backupEndpoint = this.getEndpointByConnection(backupConnection);\n this.logger.info(`故障转移成功,切换到端点: ${backupEndpoint}`);\n\n return backupConnection;\n }\n\n /**\n * 连接预热机制\n * @param endpoints 要预热的端点列表\n */\n async prewarmConnections(endpoints: string[] = []): Promise<void> {\n const targetEndpoints =\n endpoints.length > 0 ? endpoints : Array.from(this.connections.keys());\n\n this.logger.info(`开始预热连接,端点数量: ${targetEndpoints.length}`);\n\n const prewarmPromises = targetEndpoints.map(async (endpoint) => {\n if (this.performanceMetrics.prewarmedConnections.has(endpoint)) {\n this.logger.debug(`端点 ${endpoint} 已预热,跳过`);\n return;\n }\n\n try {\n const connection = this.connections.get(endpoint);\n if (connection) {\n // 执行预热操作(例如建立连接、验证状态等)\n await this.performHealthCheck();\n this.performanceMetrics.prewarmedConnections.add(endpoint);\n this.logger.debug(`端点 ${endpoint} 预热完成`);\n }\n } catch (error) {\n this.logger.warn(`端点 ${endpoint} 预热失败:`, error);\n }\n });\n\n await Promise.all(prewarmPromises);\n this.logger.info(\n `连接预热完成,成功预热 ${this.performanceMetrics.prewarmedConnections.size} 个端点`\n );\n }\n\n /**\n * 更新性能指标\n */\n private updatePerformanceMetrics(): void {\n const currentMemory = process.memoryUsage().heapUsed;\n this.performanceMetrics.memoryUsage.current = currentMemory;\n\n if (currentMemory > this.performanceMetrics.memoryUsage.peak) {\n this.performanceMetrics.memoryUsage.peak = currentMemory;\n }\n }\n\n /**\n * 获取性能指标\n */\n getPerformanceMetrics(): {\n connectionTime: {\n total: number;\n average: number;\n count: number;\n };\n memoryUsage: {\n initial: number;\n current: number;\n peak: number;\n growth: number;\n growthPercentage: number;\n };\n prewarmedConnections: number;\n totalConnections: number;\n healthyConnections: number;\n } {\n this.updatePerformanceMetrics();\n\n const memoryGrowth =\n this.performanceMetrics.memoryUsage.current -\n this.performanceMetrics.memoryUsage.initial;\n const growthPercentage =\n this.performanceMetrics.memoryUsage.initial > 0\n ? (memoryGrowth / this.performanceMetrics.memoryUsage.initial) * 100\n : 0;\n\n return {\n connectionTime: {\n total: this.performanceMetrics.totalConnectionTime,\n average: this.performanceMetrics.averageConnectionTime,\n count: this.performanceMetrics.connectionCount,\n },\n memoryUsage: {\n initial: this.performanceMetrics.memoryUsage.initial,\n current: this.performanceMetrics.memoryUsage.current,\n peak: this.performanceMetrics.memoryUsage.peak,\n growth: memoryGrowth,\n growthPercentage: Math.round(growthPercentage * 100) / 100,\n },\n prewarmedConnections: this.performanceMetrics.prewarmedConnections.size,\n totalConnections: this.connections.size,\n healthyConnections: this.getHealthyConnections().length,\n };\n }\n\n /**\n * 优化内存使用\n */\n optimizeMemoryUsage(): void {\n this.logger.info(\"开始内存优化\");\n\n // 清理过期的重连历史记录和健康检查历史\n for (const [, status] of this.connectionStates) {\n if (status.reconnectHistory && status.reconnectHistory.length > 10) {\n // 只保留最近10次记录\n status.reconnectHistory = status.reconnectHistory.slice(-10);\n }\n\n // 清理过期的健康检查历史\n // 重置一些累积的统计数据以防止无限增长\n if (status.totalRequests > 10000) {\n // 重置计数器,但保持比率\n const successRate = status.successfulRequests / status.totalRequests;\n status.totalRequests = 1000;\n status.successfulRequests = Math.round(successRate * 1000);\n }\n }\n\n // 强制垃圾回收(如果可用)\n if (global.gc) {\n global.gc();\n }\n\n this.updatePerformanceMetrics();\n this.logger.info(\"内存优化完成\");\n }\n\n /**\n * 资源清理\n */\n async cleanup(): Promise<void> {\n this.logger.info(\"开始清理 XiaozhiConnectionManager 资源\");\n\n try {\n // 断开所有连接\n await this.disconnect();\n\n // 清理连接实例\n this.connections.clear();\n this.connectionStates.clear();\n\n // 重置状态\n this.isInitialized = false;\n this.isConnecting = false;\n this.roundRobinIndex = 0;\n this.lastSelectedEndpoint = null;\n\n this.logger.info(\"XiaozhiConnectionManager 资源清理完成\");\n } catch (error) {\n this.logger.error(\"XiaozhiConnectionManager 资源清理失败:\", error);\n throw error;\n }\n }\n\n // ==================== 私有方法 ====================\n\n /**\n * 验证初始化参数\n */\n private validateInitializeParams(endpoints: string[], tools: Tool[]): void {\n if (!Array.isArray(endpoints) || endpoints.length === 0) {\n throw new Error(\"端点列表不能为空\");\n }\n\n if (!Array.isArray(tools)) {\n throw new Error(\"工具列表必须是数组\");\n }\n\n // 验证端点格式\n for (const endpoint of endpoints) {\n if (!endpoint || typeof endpoint !== \"string\") {\n throw new Error(`无效的端点地址: ${endpoint}`);\n }\n\n if (!endpoint.startsWith(\"ws://\") && !endpoint.startsWith(\"wss://\")) {\n throw new Error(`端点地址必须是 WebSocket URL: ${endpoint}`);\n }\n }\n }\n\n /**\n * 创建单个连接\n */\n private async createConnection(\n endpoint: string,\n tools: Tool[]\n ): Promise<void> {\n this.logger.debug(`创建连接实例: ${endpoint}`);\n\n try {\n // 创建 ProxyMCPServer 实例\n const proxyServer = new ProxyMCPServer(endpoint);\n\n // 设置 MCP 服务管理器\n if (this.mcpServiceManager) {\n proxyServer.setServiceManager(this.mcpServiceManager);\n }\n\n // 存储连接实例\n this.connections.set(endpoint, proxyServer);\n\n // 初始化连接状态\n this.connectionStates.set(endpoint, {\n endpoint,\n connected: false,\n initialized: false,\n reconnectAttempts: 0,\n healthScore: 100, // 初始健康度为满分\n consecutiveFailures: 0,\n totalRequests: 0,\n successfulRequests: 0,\n healthCheckEnabled: true,\n isReconnecting: false,\n reconnectDelay: this.options.reconnectInterval,\n reconnectHistory: [],\n });\n\n this.logger.debug(`连接实例创建成功: ${endpoint}`);\n } catch (error) {\n this.logger.error(`创建连接实例失败 ${endpoint}:`, error);\n throw error;\n }\n }\n\n /**\n * 连接单个端点\n */\n private async connectSingleEndpoint(\n endpoint: string,\n proxyServer: ProxyMCPServer\n ): Promise<void> {\n const status = this.connectionStates.get(endpoint);\n if (!status) {\n throw new Error(`端点状态不存在: ${endpoint}`);\n }\n\n this.logger.debug(`连接端点: ${endpoint}`);\n\n try {\n // 更新状态为连接中\n status.connected = false;\n status.initialized = false;\n\n // 执行连接\n await proxyServer.connect();\n\n // 更新连接成功状态\n status.connected = true;\n status.initialized = true;\n status.lastConnected = new Date();\n status.lastError = undefined;\n status.reconnectAttempts = 0;\n status.healthScore = 100;\n\n this.logger.info(`端点连接成功: ${endpoint}`);\n } catch (error) {\n // 更新连接失败状态\n status.connected = false;\n status.initialized = false;\n status.lastError = error instanceof Error ? error.message : String(error);\n status.reconnectAttempts++;\n status.healthScore = Math.max(0, status.healthScore - 20);\n\n this.logger.error(`端点连接失败 ${endpoint}:`, error);\n\n // 启动重连(如果未超过最大重连次数)\n this.scheduleReconnect(endpoint);\n\n throw error;\n }\n }\n\n /**\n * 断开单个端点\n */\n private async disconnectSingleEndpoint(\n endpoint: string,\n proxyServer: ProxyMCPServer\n ): Promise<void> {\n const status = this.connectionStates.get(endpoint);\n if (!status) {\n return;\n }\n\n this.logger.debug(`断开端点: ${endpoint}`);\n\n try {\n // 执行断开连接(ProxyMCPServer.disconnect 是同步方法)\n proxyServer.disconnect();\n\n // 更新状态\n status.connected = false;\n status.initialized = false;\n\n this.logger.debug(`端点断开成功: ${endpoint}`);\n } catch (error) {\n this.logger.error(`端点断开失败 ${endpoint}:`, error);\n // 即使断开失败,也要更新状态\n status.connected = false;\n status.initialized = false;\n }\n }\n\n /**\n * 获取当前工具列表\n */\n private getCurrentTools(): Tool[] {\n if (!this.mcpServiceManager) {\n return [];\n }\n\n try {\n return this.mcpServiceManager.getAllTools();\n } catch (error) {\n this.logger.error(\"获取工具列表失败:\", error);\n return [];\n }\n }\n\n /**\n * 同步工具到所有连接\n */\n private syncToolsToAllConnections(): void {\n if (!this.mcpServiceManager) {\n return;\n }\n\n this.logger.debug(\"同步工具到所有连接\");\n\n for (const [endpoint, proxyServer] of this.connections) {\n try {\n proxyServer.setServiceManager(this.mcpServiceManager);\n this.logger.debug(`工具同步成功: ${endpoint}`);\n } catch (error) {\n this.logger.error(`工具同步失败 ${endpoint}:`, error);\n }\n }\n }\n\n /**\n * 启动健康检查\n */\n private startHealthCheck(): void {\n if (this.healthCheckInterval) {\n return; // 已经启动\n }\n\n this.logger.debug(\n `启动健康检查,间隔: ${this.options.healthCheckInterval}ms`\n );\n\n this.healthCheckInterval = setInterval(() => {\n this.performHealthCheck();\n }, this.options.healthCheckInterval);\n }\n\n /**\n * 停止健康检查\n */\n private stopHealthCheck(): void {\n if (this.healthCheckInterval) {\n clearInterval(this.healthCheckInterval);\n this.healthCheckInterval = null;\n this.logger.debug(\"健康检查已停止\");\n }\n }\n\n /**\n * 执行健康检查\n */\n private async performHealthCheck(): Promise<void> {\n this.logger.debug(\"执行健康检查\");\n\n const healthCheckPromises: Promise<void>[] = [];\n\n for (const [endpoint, status] of this.connectionStates) {\n if (!status.healthCheckEnabled) {\n continue;\n }\n\n healthCheckPromises.push(this.performSingleHealthCheck(endpoint, status));\n }\n\n // 并发执行所有健康检查\n await Promise.allSettled(healthCheckPromises);\n }\n\n /**\n * 执行单个端点的健康检查\n */\n private async performSingleHealthCheck(\n endpoint: string,\n status: ConnectionStatus\n ): Promise<void> {\n const startTime = Date.now();\n status.lastHealthCheck = new Date();\n status.totalRequests++;\n\n try {\n const proxyServer = this.connections.get(endpoint);\n if (!proxyServer) {\n throw new Error(`连接实例不存在: ${endpoint}`);\n }\n\n // 执行健康检查(这里使用简单的连接状态检查)\n // 在实际实现中,可以调用 ProxyMCPServer 的 ping 方法或其他健康检查方法\n await this.checkConnectionHealth(proxyServer, endpoint);\n\n // 健康检查成功\n const responseTime = Date.now() - startTime;\n this.handleHealthCheckSuccess(status, responseTime);\n } catch (error) {\n // 健康检查失败\n const responseTime = Date.now() - startTime;\n this.handleHealthCheckFailure(status, error as Error, responseTime);\n }\n }\n\n /**\n * 检查连接健康状态\n */\n private async checkConnectionHealth(\n proxyServer: any,\n endpoint: string\n ): Promise<void> {\n // 检查基本连接状态\n if (!proxyServer) {\n throw new Error(\"连接实例不存在\");\n }\n\n // 这里可以扩展更复杂的健康检查逻辑\n // 例如:发送 ping 请求、检查工具列表等\n\n // 模拟健康检查延迟\n await new Promise((resolve) => setTimeout(resolve, 10));\n\n // 如果连接状态为断开,抛出错误\n const status = this.connectionStates.get(endpoint);\n if (!status?.connected) {\n throw new Error(\"连接已断开\");\n }\n }\n\n /**\n * 处理健康检查成功\n */\n private handleHealthCheckSuccess(\n status: ConnectionStatus,\n responseTime: number\n ): void {\n status.successfulRequests++;\n status.consecutiveFailures = 0;\n status.responseTime = responseTime;\n status.lastSuccessTime = new Date();\n\n // 更新健康度评分\n this.updateHealthScore(status, true, responseTime);\n\n this.logger.debug(\n `健康检查成功: ${status.endpoint}, 响应时间: ${responseTime}ms, 健康度: ${status.healthScore}`\n );\n }\n\n /**\n * 处理健康检查失败\n */\n private handleHealthCheckFailure(\n status: ConnectionStatus,\n error: Error,\n responseTime: number\n ): void {\n status.consecutiveFailures++;\n status.responseTime = responseTime;\n status.lastError = error.message;\n\n // 更新健康度评分\n this.updateHealthScore(status, false, responseTime);\n\n this.logger.warn(\n `健康检查失败: ${status.endpoint}, 错误: ${error.message}, 连续失败: ${status.consecutiveFailures}, 健康度: ${status.healthScore}`\n );\n\n // 如果连续失败次数过多,考虑触发重连\n if (status.consecutiveFailures >= 3 && status.connected) {\n this.logger.warn(\n `端点 ${status.endpoint} 连续失败 ${status.consecutiveFailures} 次,可能需要重连`\n );\n // 这里可以触发重连逻辑\n }\n }\n\n /**\n * 更新健康度评分\n */\n private updateHealthScore(\n status: ConnectionStatus,\n success: boolean,\n responseTime: number\n ): void {\n const baseScore = status.healthScore;\n\n if (success) {\n // 成功时增加健康度\n let increment = 5;\n\n // 根据响应时间调整增量\n if (responseTime < 100) {\n increment = 10; // 响应快,增量大\n } else if (responseTime < 500) {\n increment = 7; // 响应中等\n } else if (responseTime < 1000) {\n increment = 5; // 响应慢\n } else {\n increment = 2; // 响应很慢\n }\n\n status.healthScore = Math.min(100, baseScore + increment);\n } else {\n // 失败时减少健康度\n let decrement = 15;\n\n // 根据连续失败次数调整减量\n if (status.consecutiveFailures >= 5) {\n decrement = 30; // 连续失败多次,减量大\n } else if (status.consecutiveFailures >= 3) {\n decrement = 20;\n }\n\n status.healthScore = Math.max(0, baseScore - decrement);\n }\n\n // 计算成功率并调整健康度\n if (status.totalRequests > 0) {\n const successRate = status.successfulRequests / status.totalRequests;\n\n // 如果成功率低于 50%,进一步降低健康度\n if (successRate < 0.5) {\n status.healthScore = Math.max(0, status.healthScore - 10);\n }\n // 如果成功率高于 90%,适当提升健康度\n else if (successRate > 0.9) {\n status.healthScore = Math.min(100, status.healthScore + 5);\n }\n }\n }\n\n /**\n * 分类连接错误类型\n */\n private classifyConnectionError(error: Error): ConnectionErrorType {\n const errorMessage = error.message.toLowerCase();\n\n if (\n errorMessage.includes(\"timeout\") ||\n errorMessage.includes(\"timed out\")\n ) {\n return ConnectionErrorType.TIMEOUT_ERROR;\n }\n\n if (\n errorMessage.includes(\"network\") ||\n errorMessage.includes(\"connection refused\") ||\n errorMessage.includes(\"econnrefused\") ||\n errorMessage.includes(\"enotfound\")\n ) {\n return ConnectionErrorType.NETWORK_ERROR;\n }\n\n if (\n errorMessage.includes(\"auth\") ||\n errorMessage.includes(\"unauthorized\") ||\n errorMessage.includes(\"forbidden\") ||\n errorMessage.includes(\"401\") ||\n errorMessage.includes(\"403\")\n ) {\n return ConnectionErrorType.AUTHENTICATION_ERROR;\n }\n\n if (\n errorMessage.includes(\"server\") ||\n errorMessage.includes(\"500\") ||\n errorMessage.includes(\"502\") ||\n errorMessage.includes(\"503\") ||\n errorMessage.includes(\"504\")\n ) {\n return ConnectionErrorType.SERVER_ERROR;\n }\n\n return ConnectionErrorType.UNKNOWN_ERROR;\n }\n\n /**\n * 计算重连延迟\n */\n private calculateReconnectDelay(status: ConnectionStatus): number {\n const baseDelay = this.options.reconnectInterval;\n const maxDelay = this.options.maxReconnectDelay;\n const multiplier = this.options.reconnectBackoffMultiplier;\n const attempts = status.reconnectAttempts;\n\n let delay: number;\n\n switch (this.options.reconnectStrategy) {\n case ReconnectStrategy.FIXED_INTERVAL:\n delay = baseDelay;\n break;\n\n case ReconnectStrategy.LINEAR_BACKOFF:\n delay = baseDelay * (attempts + 1);\n break;\n\n case ReconnectStrategy.EXPONENTIAL_BACKOFF:\n delay = baseDelay * multiplier ** attempts;\n break;\n\n case ReconnectStrategy.ADAPTIVE:\n // 自适应策略:根据错误类型和历史成功率调整\n delay = this.calculateAdaptiveDelay(\n status,\n baseDelay,\n multiplier,\n attempts\n );\n break;\n\n default:\n delay = baseDelay * multiplier ** attempts;\n }\n\n // 限制最大延迟\n delay = Math.min(delay, maxDelay);\n\n // 添加抖动以避免雷群效应\n if (this.options.jitterEnabled) {\n const jitter = delay * 0.1 * Math.random(); // 10% 的随机抖动\n delay += jitter;\n }\n\n return Math.round(delay);\n }\n\n /**\n * 计算自适应重连延迟\n */\n private calculateAdaptiveDelay(\n status: ConnectionStatus,\n baseDelay: number,\n multiplier: number,\n attempts: number\n ): number {\n let delay = baseDelay;\n\n // 根据错误类型调整\n switch (status.errorType) {\n case ConnectionErrorType.NETWORK_ERROR:\n // 网络错误,使用指数退避\n delay = baseDelay * multiplier ** attempts;\n break;\n\n case ConnectionErrorType.AUTHENTICATION_ERROR:\n // 认证错误,延迟更长\n delay = baseDelay * multiplier ** attempts * 2;\n break;\n\n case ConnectionErrorType.SERVER_ERROR:\n // 服务器错误,适中延迟\n delay = baseDelay * (1 + attempts);\n break;\n\n case ConnectionErrorType.TIMEOUT_ERROR:\n // 超时错误,线性增长\n delay = baseDelay * (1 + attempts * 0.5);\n break;\n\n default:\n delay = baseDelay * multiplier ** attempts;\n }\n\n // 根据历史成功率调整\n if (status.reconnectHistory.length > 0) {\n const recentHistory = status.reconnectHistory.slice(-5); // 最近5次\n const successRate =\n recentHistory.filter((h) => h.success).length / recentHistory.length;\n\n if (successRate < 0.2) {\n // 成功率很低,增加延迟\n delay *= 1.5;\n } else if (successRate > 0.8) {\n // 成功率很高,减少延迟\n delay *= 0.8;\n }\n }\n\n return delay;\n }\n\n /**\n * 检查是否应该重连\n */\n private shouldReconnect(status: ConnectionStatus): boolean {\n // 检查重连次数限制\n if (status.reconnectAttempts >= this.options.maxReconnectAttempts) {\n this.logger.warn(\n `端点 ${status.endpoint} 已达到最大重连次数 ${this.options.maxReconnectAttempts}`\n );\n return false;\n }\n\n // 检查错误类型\n if (status.errorType === ConnectionErrorType.AUTHENTICATION_ERROR) {\n // 认证错误通常不应该重连太多次\n if (status.reconnectAttempts >= 3) {\n this.logger.warn(`端点 ${status.endpoint} 认证错误,停止重连`);\n return false;\n }\n }\n\n // 检查连续失败次数\n if (status.consecutiveFailures >= 10) {\n this.logger.warn(`端点 ${status.endpoint} 连续失败次数过多,停止重连`);\n return false;\n }\n\n return true;\n }\n\n /**\n * 安排重连\n */\n private scheduleReconnect(endpoint: string): void {\n const status = this.connectionStates.get(endpoint);\n if (!status) {\n return;\n }\n\n // 分类错误类型\n if (status.lastError) {\n status.errorType = this.classifyConnectionError(\n new Error(status.lastError)\n );\n }\n\n // 检查是否应该重连\n if (!this.shouldReconnect(status)) {\n status.isReconnecting = false;\n return;\n }\n\n // 清理现有的重连定时器\n const existingTimer = this.reconnectTimers.get(endpoint);\n if (existingTimer) {\n clearTimeout(existingTimer);\n }\n\n // 计算重连延迟\n const delay = this.calculateReconnectDelay(status);\n status.reconnectDelay = delay;\n status.isReconnecting = true;\n status.nextReconnectTime = new Date(Date.now() + delay);\n\n this.logger.info(\n `安排重连 ${endpoint},延迟: ${delay}ms,尝试次数: ${status.reconnectAttempts + 1},错误类型: ${status.errorType}`\n );\n\n const timer = setTimeout(async () => {\n this.reconnectTimers.delete(endpoint);\n await this.performReconnect(endpoint);\n }, delay);\n\n this.reconnectTimers.set(endpoint, timer);\n }\n\n /**\n * 执行重连\n */\n private async performReconnect(endpoint: string): Promise<void> {\n const status = this.connectionStates.get(endpoint);\n const proxyServer = this.connections.get(endpoint);\n\n if (!status || !proxyServer) {\n return;\n }\n\n status.lastReconnectAttempt = new Date();\n status.isReconnecting = true;\n\n this.logger.info(\n `开始重连 ${endpoint},第 ${status.reconnectAttempts + 1} 次尝试`\n );\n\n try {\n await this.connectSingleEndpoint(endpoint, proxyServer);\n\n // 重连成功\n status.isReconnecting = false;\n status.reconnectHistory.push({\n timestamp: new Date(),\n success: true,\n delay: status.reconnectDelay,\n });\n\n this.logger.info(`重连成功 ${endpoint}`);\n } catch (error) {\n // 重连失败\n status.isReconnecting = false;\n status.reconnectHistory.push({\n timestamp: new Date(),\n success: false,\n error: error instanceof Error ? error.message : String(error),\n delay: status.reconnectDelay,\n });\n\n this.logger.error(`重连失败 ${endpoint}:`, error);\n\n // 继续安排下次重连\n this.scheduleReconnect(endpoint);\n }\n\n // 限制重连历史记录数量\n if (status.reconnectHistory.length > 20) {\n status.reconnectHistory = status.reconnectHistory.slice(-20);\n }\n }\n\n /**\n * 清理所有重连定时器\n */\n private clearAllReconnectTimers(): void {\n for (const [, timer] of this.reconnectTimers) {\n clearTimeout(timer);\n }\n this.reconnectTimers.clear();\n }\n}\n","/**\n * 小智连接管理器单例\n * 提供全局唯一的 XiaozhiConnectionManager 实例,解决多实例资源冲突问题\n */\n\nimport {\n XiaozhiConnectionManager,\n type XiaozhiConnectionOptions,\n} from \"./XiaozhiConnectionManager.js\";\n\n// 重新导出相关类型,便于外部使用\nexport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nexport type {\n XiaozhiConnectionOptions,\n ConnectionStatus,\n} from \"./XiaozhiConnectionManager.js\";\n\n// 单例状态枚举\nenum SingletonState {\n NOT_INITIALIZED = \"not_initialized\",\n INITIALIZING = \"initializing\",\n INITIALIZED = \"initialized\",\n FAILED = \"failed\",\n CLEANUP = \"cleanup\",\n}\n\n// 单例状态接口\ninterface SingletonStatus {\n state: SingletonState;\n initializationTime?: Date;\n lastError?: Error;\n instanceId?: string;\n}\n\n// 单例状态管理变量\nlet instance: XiaozhiConnectionManager | null = null;\nlet initPromise: Promise<XiaozhiConnectionManager> | null = null;\nlet state: SingletonState = SingletonState.NOT_INITIALIZED;\nlet lastError: Error | null = null;\nlet instanceId: string | null = null;\n\n/**\n * 创建 XiaozhiConnectionManager 实例(私有函数)\n */\nasync function createInstance(\n options?: XiaozhiConnectionOptions\n): Promise<XiaozhiConnectionManager> {\n console.log(\"🚀 正在初始化 XiaozhiConnectionManager 单例...\");\n\n const manager = new XiaozhiConnectionManager(options);\n\n return manager;\n}\n\n/**\n * 获取 XiaozhiConnectionManager 单例实例\n *\n * @param options 连接选项(仅在首次创建时生效)\n * @returns Promise<XiaozhiConnectionManager> 管理器实例\n * @throws Error 如果初始化失败\n */\nasync function getInstance(\n options?: XiaozhiConnectionOptions\n): Promise<XiaozhiConnectionManager> {\n // 如果已经初始化完成,直接返回实例\n if (instance && state === SingletonState.INITIALIZED) {\n return instance;\n }\n\n // 如果正在初始化中,等待同一个初始化Promise\n if (initPromise && state === SingletonState.INITIALIZING) {\n return initPromise;\n }\n\n // 如果之前初始化失败,重置状态准备重试\n if (state === SingletonState.FAILED) {\n reset();\n }\n\n // 开始新的初始化过程\n state = SingletonState.INITIALIZING;\n initPromise = createInstance(options);\n\n try {\n instance = await initPromise;\n state = SingletonState.INITIALIZED;\n instanceId = `xiaozhi-connection-manager-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;\n lastError = null;\n\n console.log(\n `✅ XiaozhiConnectionManager 单例初始化成功,实例ID: ${instanceId}`\n );\n return instance;\n } catch (error) {\n state = SingletonState.FAILED;\n lastError = error as Error;\n initPromise = null;\n\n console.error(\n \"❌ XiaozhiConnectionManager 单例初始化失败:\",\n (error as Error).message\n );\n throw error;\n }\n}\n\n/**\n * 清理单例资源\n *\n * @returns Promise<void>\n */\nasync function cleanup(): Promise<void> {\n if (state === SingletonState.CLEANUP) {\n console.log(\"⚠️ XiaozhiConnectionManager 单例已在清理中,跳过重复清理\");\n return;\n }\n\n console.log(\"🧹 正在清理 XiaozhiConnectionManager 单例资源...\");\n state = SingletonState.CLEANUP;\n\n try {\n // 清理初始化Promise\n if (initPromise) {\n try {\n const instanceFromPromise = await initPromise;\n await instanceFromPromise.cleanup();\n } catch (error) {\n console.error(\"清理初始化中的实例失败:\", (error as Error).message);\n }\n initPromise = null;\n }\n\n // 清理已初始化的实例\n if (instance) {\n await instance.cleanup();\n instance = null;\n }\n\n state = SingletonState.NOT_INITIALIZED;\n lastError = null;\n instanceId = null;\n\n console.log(\"✅ XiaozhiConnectionManager 单例资源清理完成\");\n } catch (error) {\n console.error(\n \"❌ XiaozhiConnectionManager 单例清理失败:\",\n (error as Error).message\n );\n // 即使清理失败,也要重置状态,避免永久锁定\n reset();\n throw error;\n }\n}\n\n/**\n * 重置单例状态(不进行清理)\n *\n * 这个方法只重置内部状态变量,不调用实例的清理方法\n * 主要用于错误恢复和测试场景\n */\nfunction reset(): void {\n console.log(\"🔄 重置 XiaozhiConnectionManager 单例状态...\");\n\n // 清理定时器(如果有)\n if (initPromise) {\n initPromise = null;\n }\n\n // 重置状态变量\n instance = null;\n state = SingletonState.NOT_INITIALIZED;\n lastError = null;\n instanceId = null;\n\n console.log(\"✅ XiaozhiConnectionManager 单例状态已重置\");\n}\n\n/**\n * 检查单例是否已初始化\n *\n * @returns boolean 是否已初始化\n */\nfunction isInitialized(): boolean {\n return state === SingletonState.INITIALIZED && instance !== null;\n}\n\n/**\n * 获取单例状态信息\n *\n * @returns SingletonStatus 状态信息\n */\nfunction getStatus(): SingletonStatus {\n return {\n state,\n initializationTime: instanceId ? new Date() : undefined,\n lastError: lastError || undefined,\n instanceId: instanceId || undefined,\n };\n}\n\n/**\n * 强制重新初始化单例\n *\n * 这个方法会先清理现有资源,然后重新初始化\n *\n * @param options 连接选项\n * @returns Promise<XiaozhiConnectionManager> 新的管理器实例\n */\nasync function forceReinitialize(\n options?: XiaozhiConnectionOptions\n): Promise<XiaozhiConnectionManager> {\n console.log(\"🔄 强制重新初始化 XiaozhiConnectionManager 单例...\");\n\n await cleanup();\n return getInstance(options);\n}\n\n/**\n * 获取当前实例(同步方法,仅在确定已初始化时使用)\n *\n * @returns XiaozhiConnectionManager | null 当前实例或null\n */\nfunction getCurrentInstance(): XiaozhiConnectionManager | null {\n return instance;\n}\n\n/**\n * 等待初始化完成(如果正在初始化中)\n *\n * @returns Promise<boolean> 是否成功初始化\n */\nasync function waitForInitialization(): Promise<boolean> {\n if (state === SingletonState.INITIALIZED) {\n return true;\n }\n\n if (state === SingletonState.INITIALIZING && initPromise) {\n try {\n await initPromise;\n return true;\n } catch (error) {\n return false;\n }\n }\n\n return false;\n}\n\n/**\n * XiaozhiConnectionManager 全局单例管理器\n *\n * 使用对象包装模块级函数,保持原有API接口不变\n */\nexport const XiaozhiConnectionManagerSingleton = {\n getInstance,\n cleanup,\n reset,\n isInitialized,\n getStatus,\n forceReinitialize,\n getCurrentInstance,\n waitForInitialization,\n} as const;\n\n// 导出默认实例(便于使用)\nexport default XiaozhiConnectionManagerSingleton;\n\n// 进程退出时自动清理资源\nprocess.on(\"exit\", () => {\n if (XiaozhiConnectionManagerSingleton.isInitialized()) {\n console.log(\"🔄 进程退出,正在清理 XiaozhiConnectionManager 单例...\");\n // 注意:这里不能使用 await,因为 exit 事件是同步的\n XiaozhiConnectionManagerSingleton.reset();\n }\n});\n\n// 处理未捕获的异常\nprocess.on(\"uncaughtException\", async (error) => {\n console.error(\"💥 未捕获的异常,清理 XiaozhiConnectionManager 单例:\", error);\n try {\n await XiaozhiConnectionManagerSingleton.cleanup();\n } catch (cleanupError) {\n console.error(\"清理过程中发生错误:\", cleanupError);\n }\n});\n\n// 处理未处理的Promise拒绝\nprocess.on(\"unhandledRejection\", async (reason) => {\n console.error(\n \"💥 未处理的Promise拒绝,清理 XiaozhiConnectionManager 单例:\",\n reason\n );\n try {\n await XiaozhiConnectionManagerSingleton.cleanup();\n } catch (cleanupError) {\n console.error(\"清理过程中发生错误:\", cleanupError);\n }\n});\n","import { EventEmitter } from \"node:events\";\nimport { type Logger, logger } from \"../Logger.js\";\n\n/**\n * 事件类型定义\n */\nexport interface EventBusEvents {\n // 配置相关事件\n \"config:updated\": { config: any; source: string };\n \"config:error\": { error: Error; operation: string };\n\n // 状态相关事件\n \"status:updated\": { status: any; source: string };\n \"status:error\": { error: Error; operation: string };\n\n // 服务相关事件\n \"service:restart:requested\": { source: string };\n \"service:restart:started\": { timestamp: number };\n \"service:restart:completed\": { timestamp: number };\n \"service:restart:failed\": { error: Error; timestamp: number };\n\n // WebSocket 相关事件\n \"websocket:client:connected\": { clientId: string; timestamp: number };\n \"websocket:client:disconnected\": { clientId: string; timestamp: number };\n \"websocket:message:received\": { type: string; data: any; clientId: string };\n\n // 通知相关事件\n \"notification:broadcast\": { type: string; data: any; target?: string };\n \"notification:error\": { error: Error; type: string };\n}\n\n/**\n * 事件总线 - 用于模块间的解耦通信\n */\nexport class EventBus extends EventEmitter {\n private logger: Logger;\n private eventStats: Map<string, { count: number; lastEmitted: Date }> =\n new Map();\n private maxListeners = 50; // 增加最大监听器数量\n\n constructor() {\n super();\n this.logger = logger.withTag(\"EventBus\");\n this.setMaxListeners(this.maxListeners);\n this.setupErrorHandling();\n }\n\n /**\n * 设置错误处理\n */\n private setupErrorHandling(): void {\n this.on(\"error\", (error) => {\n this.logger.error(\"EventBus 内部错误:\", error);\n });\n\n // 监听器数量警告\n this.on(\"newListener\", (eventName) => {\n const listenerCount = this.listenerCount(eventName);\n if (listenerCount > this.maxListeners * 0.8) {\n this.logger.warn(\n `事件 ${eventName} 的监听器数量过多: ${listenerCount}`\n );\n }\n });\n }\n\n /**\n * 发射事件(类型安全)\n */\n emitEvent<K extends keyof EventBusEvents>(\n eventName: K,\n data: EventBusEvents[K]\n ): boolean {\n try {\n this.updateEventStats(eventName as string);\n this.logger.debug(`发射事件: ${eventName}`, data);\n return this.emit(eventName, data);\n } catch (error) {\n this.logger.error(`发射事件失败: ${eventName}`, error);\n return false;\n }\n }\n\n /**\n * 监听事件(类型安全)\n */\n onEvent<K extends keyof EventBusEvents>(\n eventName: K,\n listener: (data: EventBusEvents[K]) => void\n ): this {\n this.logger.debug(`添加事件监听器: ${eventName}`);\n return this.on(eventName, listener);\n }\n\n /**\n * 一次性监听事件(类型安全)\n */\n onceEvent<K extends keyof EventBusEvents>(\n eventName: K,\n listener: (data: EventBusEvents[K]) => void\n ): this {\n this.logger.debug(`添加一次性事件监听器: ${eventName}`);\n return this.once(eventName, listener);\n }\n\n /**\n * 移除事件监听器(类型安全)\n */\n offEvent<K extends keyof EventBusEvents>(\n eventName: K,\n listener: (data: EventBusEvents[K]) => void\n ): this {\n this.logger.debug(`移除事件监听器: ${eventName}`);\n return this.off(eventName, listener);\n }\n\n /**\n * 更新事件统计\n */\n private updateEventStats(eventName: string): void {\n const stats = this.eventStats.get(eventName) || {\n count: 0,\n lastEmitted: new Date(),\n };\n stats.count++;\n stats.lastEmitted = new Date();\n this.eventStats.set(eventName, stats);\n }\n\n /**\n * 获取事件统计信息\n */\n getEventStats(): Record<string, { count: number; lastEmitted: Date }> {\n const stats: Record<string, { count: number; lastEmitted: Date }> = {};\n for (const [eventName, stat] of this.eventStats) {\n stats[eventName] = { ...stat };\n }\n return stats;\n }\n\n /**\n * 获取监听器统计信息\n */\n getListenerStats(): Record<string, number> {\n const stats: Record<string, number> = {};\n for (const eventName of this.eventNames()) {\n stats[eventName as string] = this.listenerCount(eventName);\n }\n return stats;\n }\n\n /**\n * 清理事件统计\n */\n clearEventStats(): void {\n this.eventStats.clear();\n this.logger.info(\"事件统计已清理\");\n }\n\n /**\n * 获取事件总线状态\n */\n getStatus(): {\n totalEvents: number;\n totalListeners: number;\n eventStats: Record<string, { count: number; lastEmitted: Date }>;\n listenerStats: Record<string, number>;\n } {\n return {\n totalEvents: this.eventStats.size,\n totalListeners: Object.values(this.getListenerStats()).reduce(\n (sum, count) => sum + count,\n 0\n ),\n eventStats: this.getEventStats(),\n listenerStats: this.getListenerStats(),\n };\n }\n\n /**\n * 销毁事件总线\n */\n destroy(): void {\n this.removeAllListeners();\n this.eventStats.clear();\n this.logger.info(\"EventBus 已销毁\");\n }\n}\n\n// 单例实例\nlet eventBusInstance: EventBus | null = null;\n\n/**\n * 获取事件总线单例\n */\nexport function getEventBus(): EventBus {\n if (!eventBusInstance) {\n eventBusInstance = new EventBus();\n }\n return eventBusInstance;\n}\n\n/**\n * 销毁事件总线单例\n */\nexport function destroyEventBus(): void {\n if (eventBusInstance) {\n eventBusInstance.destroy();\n eventBusInstance = null;\n }\n}\n","import { type Logger, logger } from \"../Logger.js\";\nimport { type AppConfig, configManager } from \"../configManager.js\";\nimport { type EventBus, getEventBus } from \"./EventBus.js\";\n\n/**\n * 配置服务 - 统一的配置管理服务\n */\nexport class ConfigService {\n private logger: Logger;\n private eventBus: EventBus;\n\n constructor() {\n this.logger = logger.withTag(\"ConfigService\");\n this.eventBus = getEventBus();\n }\n\n /**\n * 获取完整配置\n */\n async getConfig(): Promise<AppConfig> {\n try {\n const config = configManager.getConfig();\n this.logger.debug(\"获取配置成功\");\n return config;\n } catch (error) {\n this.logger.error(\"获取配置失败:\", error);\n this.eventBus.emitEvent(\"config:error\", {\n error: error instanceof Error ? error : new Error(String(error)),\n operation: \"getConfig\",\n });\n throw error;\n }\n }\n\n /**\n * 更新配置\n */\n async updateConfig(newConfig: AppConfig, source = \"unknown\"): Promise<void> {\n try {\n this.logger.info(`开始更新配置,来源: ${source}`);\n\n // 验证配置\n this.validateConfig(newConfig);\n\n // 更新 MCP 端点\n if (newConfig.mcpEndpoint !== configManager.getMcpEndpoint()) {\n configManager.updateMcpEndpoint(newConfig.mcpEndpoint);\n }\n\n // 更新 MCP 服务\n const currentServers = configManager.getMcpServers();\n for (const [name, config] of Object.entries(newConfig.mcpServers)) {\n if (JSON.stringify(currentServers[name]) !== JSON.stringify(config)) {\n configManager.updateMcpServer(name, config);\n }\n }\n\n // 删除不存在的服务\n for (const name of Object.keys(currentServers)) {\n if (!(name in newConfig.mcpServers)) {\n configManager.removeMcpServer(name);\n // 同时清理该服务在 mcpServerConfig 中的工具配置\n configManager.removeServerToolsConfig(name);\n }\n }\n\n // 更新连接配置\n if (newConfig.connection) {\n configManager.updateConnectionConfig(newConfig.connection);\n }\n\n // 更新 ModelScope 配置\n if (newConfig.modelscope) {\n configManager.updateModelScopeConfig(newConfig.modelscope);\n }\n\n // 更新 Web UI 配置\n if (newConfig.webUI) {\n configManager.updateWebUIConfig(newConfig.webUI);\n }\n\n // 更新服务工具配置\n if (newConfig.mcpServerConfig) {\n for (const [serverName, toolsConfig] of Object.entries(\n newConfig.mcpServerConfig\n )) {\n for (const [toolName, toolConfig] of Object.entries(\n toolsConfig.tools\n )) {\n configManager.setToolEnabled(\n serverName,\n toolName,\n toolConfig.enable\n );\n }\n }\n }\n\n this.logger.info(\"配置更新成功\");\n\n // 发射配置更新事件\n this.eventBus.emitEvent(\"config:updated\", {\n config: newConfig,\n source,\n });\n } catch (error) {\n this.logger.error(\"配置更新失败:\", error);\n this.eventBus.emitEvent(\"config:error\", {\n error: error instanceof Error ? error : new Error(String(error)),\n operation: \"updateConfig\",\n });\n throw error;\n }\n }\n\n /**\n * 获取 MCP 端点\n */\n getMcpEndpoint(): string {\n try {\n return configManager.getMcpEndpoint();\n } catch (error) {\n this.logger.error(\"获取 MCP 端点失败:\", error);\n throw error;\n }\n }\n\n /**\n * 获取 MCP 端点列表\n */\n getMcpEndpoints(): string[] {\n try {\n return configManager.getMcpEndpoints();\n } catch (error) {\n this.logger.error(\"获取 MCP 端点列表失败:\", error);\n throw error;\n }\n }\n\n /**\n * 获取 MCP 服务配置\n */\n getMcpServers(): Record<string, any> {\n try {\n return configManager.getMcpServers();\n } catch (error) {\n this.logger.error(\"获取 MCP 服务配置失败:\", error);\n throw error;\n }\n }\n\n /**\n * 获取连接配置\n */\n getConnectionConfig(): any {\n try {\n return configManager.getConnectionConfig();\n } catch (error) {\n this.logger.error(\"获取连接配置失败:\", error);\n throw error;\n }\n }\n\n /**\n * 获取 Web UI 端口\n */\n getWebUIPort(): number {\n try {\n return configManager.getWebUIPort() || 9999;\n } catch (error) {\n this.logger.error(\"获取 Web UI 端口失败:\", error);\n return 9999;\n }\n }\n\n /**\n * 验证配置\n */\n private validateConfig(config: AppConfig): void {\n if (!config || typeof config !== \"object\") {\n throw new Error(\"配置必须是有效的对象\");\n }\n\n if (!config.mcpEndpoint) {\n throw new Error(\"配置必须包含 mcpEndpoint\");\n }\n\n if (!config.mcpServers || typeof config.mcpServers !== \"object\") {\n throw new Error(\"配置必须包含有效的 mcpServers\");\n }\n }\n\n /**\n * 检查配置是否存在\n */\n configExists(): boolean {\n return configManager.configExists();\n }\n\n /**\n * 重新加载配置\n */\n async reloadConfig(): Promise<AppConfig> {\n try {\n this.logger.info(\"重新加载配置\");\n configManager.reloadConfig();\n const config = await this.getConfig();\n\n this.eventBus.emitEvent(\"config:updated\", {\n config,\n source: \"reload\",\n });\n\n return config;\n } catch (error) {\n this.logger.error(\"重新加载配置失败:\", error);\n this.eventBus.emitEvent(\"config:error\", {\n error: error instanceof Error ? error : new Error(String(error)),\n operation: \"reloadConfig\",\n });\n throw error;\n }\n }\n\n /**\n * 获取配置文件路径\n */\n getConfigPath(): string {\n return configManager.getConfigPath();\n }\n}\n","import type { Context } from \"hono\";\nimport { type Logger, logger } from \"../Logger.js\";\nimport type { AppConfig } from \"../configManager.js\";\nimport { ConfigService } from \"../services/ConfigService.js\";\n\n/**\n * 统一响应格式接口\n */\ninterface ApiErrorResponse {\n error: {\n code: string;\n message: string;\n details?: any;\n };\n}\n\ninterface ApiSuccessResponse<T = any> {\n success: boolean;\n data?: T;\n message?: string;\n}\n\n/**\n * 配置 API 处理器\n */\nexport class ConfigApiHandler {\n private logger: Logger;\n private configService: ConfigService;\n\n constructor() {\n this.logger = logger.withTag(\"ConfigApiHandler\");\n this.configService = new ConfigService();\n }\n\n /**\n * 创建统一的错误响应\n */\n private createErrorResponse(\n code: string,\n message: string,\n details?: any\n ): ApiErrorResponse {\n return {\n error: {\n code,\n message,\n details,\n },\n };\n }\n\n /**\n * 创建统一的成功响应\n */\n private createSuccessResponse<T>(\n data?: T,\n message?: string\n ): ApiSuccessResponse<T> {\n return {\n success: true,\n data,\n message,\n };\n }\n\n /**\n * 获取配置\n * GET /api/config\n */\n async getConfig(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理获取配置请求\");\n const config = await this.configService.getConfig();\n this.logger.info(\"获取配置成功\");\n return c.json(this.createSuccessResponse(config));\n } catch (error) {\n this.logger.error(\"获取配置失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"CONFIG_READ_ERROR\",\n error instanceof Error ? error.message : \"获取配置失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 更新配置\n * PUT /api/config\n */\n async updateConfig(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理更新配置请求\");\n const newConfig: AppConfig = await c.req.json();\n\n // 验证请求体\n if (!newConfig || typeof newConfig !== \"object\") {\n const errorResponse = this.createErrorResponse(\n \"INVALID_REQUEST_BODY\",\n \"请求体必须是有效的配置对象\"\n );\n return c.json(errorResponse, 400);\n }\n\n await this.configService.updateConfig(newConfig, \"http-api\");\n this.logger.info(\"配置更新成功\");\n\n return c.json(this.createSuccessResponse(null, \"配置更新成功\"));\n } catch (error) {\n this.logger.error(\"配置更新失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"CONFIG_UPDATE_ERROR\",\n error instanceof Error ? error.message : \"配置更新失败\"\n );\n return c.json(errorResponse, 400);\n }\n }\n\n /**\n * 获取 MCP 端点\n * GET /api/config/mcp-endpoint\n */\n async getMcpEndpoint(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理获取 MCP 端点请求\");\n const endpoint = this.configService.getMcpEndpoint();\n this.logger.debug(\"获取 MCP 端点成功\");\n return c.json(this.createSuccessResponse({ endpoint }));\n } catch (error) {\n this.logger.error(\"获取 MCP 端点失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"MCP_ENDPOINT_READ_ERROR\",\n error instanceof Error ? error.message : \"获取 MCP 端点失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 获取 MCP 端点列表\n * GET /api/config/mcp-endpoints\n */\n async getMcpEndpoints(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理获取 MCP 端点列表请求\");\n const endpoints = this.configService.getMcpEndpoints();\n this.logger.debug(\"获取 MCP 端点列表成功\");\n return c.json(this.createSuccessResponse({ endpoints }));\n } catch (error) {\n this.logger.error(\"获取 MCP 端点列表失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"MCP_ENDPOINTS_READ_ERROR\",\n error instanceof Error ? error.message : \"获取 MCP 端点列表失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 获取 MCP 服务配置\n * GET /api/config/mcp-servers\n */\n async getMcpServers(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理获取 MCP 服务配置请求\");\n const servers = this.configService.getMcpServers();\n this.logger.debug(\"获取 MCP 服务配置成功\");\n return c.json(this.createSuccessResponse({ servers }));\n } catch (error) {\n this.logger.error(\"获取 MCP 服务配置失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"MCP_SERVERS_READ_ERROR\",\n error instanceof Error ? error.message : \"获取 MCP 服务配置失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 获取连接配置\n * GET /api/config/connection\n */\n async getConnectionConfig(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理获取连接配置请求\");\n const connection = this.configService.getConnectionConfig();\n this.logger.debug(\"获取连接配置成功\");\n return c.json(this.createSuccessResponse({ connection }));\n } catch (error) {\n this.logger.error(\"获取连接配置失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"CONNECTION_CONFIG_READ_ERROR\",\n error instanceof Error ? error.message : \"获取连接配置失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 重新加载配置\n * POST /api/config/reload\n */\n async reloadConfig(c: Context): Promise<Response> {\n try {\n this.logger.info(\"处理重新加载配置请求\");\n const config = await this.configService.reloadConfig();\n this.logger.info(\"重新加载配置成功\");\n return c.json(this.createSuccessResponse(config, \"配置重新加载成功\"));\n } catch (error) {\n this.logger.error(\"重新加载配置失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"CONFIG_RELOAD_ERROR\",\n error instanceof Error ? error.message : \"重新加载配置失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 获取配置文件路径\n * GET /api/config/path\n */\n async getConfigPath(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理获取配置文件路径请求\");\n const path = this.configService.getConfigPath();\n this.logger.debug(\"获取配置文件路径成功\");\n return c.json(this.createSuccessResponse({ path }));\n } catch (error) {\n this.logger.error(\"获取配置文件路径失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"CONFIG_PATH_READ_ERROR\",\n error instanceof Error ? error.message : \"获取配置文件路径失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 检查配置是否存在\n * GET /api/config/exists\n */\n async checkConfigExists(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理检查配置是否存在请求\");\n const exists = this.configService.configExists();\n this.logger.debug(`配置存在检查结果: ${exists}`);\n return c.json(this.createSuccessResponse({ exists }));\n } catch (error) {\n this.logger.error(\"检查配置是否存在失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"CONFIG_EXISTS_CHECK_ERROR\",\n error instanceof Error ? error.message : \"检查配置是否存在失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n}\n","import { type Logger, logger } from \"../Logger.js\";\nimport { ConfigService } from \"../services/ConfigService.js\";\nimport type { NotificationService } from \"../services/NotificationService.js\";\nimport type { StatusService } from \"../services/StatusService.js\";\n\n/**\n * 心跳消息接口\n */\ninterface HeartbeatMessage {\n type: \"clientStatus\";\n data: {\n status?: \"connected\" | \"disconnected\";\n mcpEndpoint?: string;\n activeMCPServers?: string[];\n timestamp?: number;\n };\n}\n\n/**\n * 心跳处理器\n */\nexport class HeartbeatHandler {\n private logger: Logger;\n private statusService: StatusService;\n private notificationService: NotificationService;\n private configService: ConfigService;\n\n constructor(\n statusService: StatusService,\n notificationService: NotificationService\n ) {\n this.logger = logger.withTag(\"HeartbeatHandler\");\n this.statusService = statusService;\n this.notificationService = notificationService;\n this.configService = new ConfigService();\n }\n\n /**\n * 处理客户端状态更新(心跳)\n */\n async handleClientStatus(\n ws: any,\n message: HeartbeatMessage,\n clientId: string\n ): Promise<void> {\n try {\n this.logger.debug(`处理客户端状态更新: ${clientId}`, message.data);\n\n // 更新客户端信息\n const statusUpdate = {\n ...message.data,\n lastHeartbeat: Date.now(),\n };\n\n this.statusService.updateClientInfo(\n statusUpdate,\n `websocket-${clientId}`\n );\n\n // 发送最新配置给客户端(心跳响应)\n await this.sendLatestConfig(ws, clientId);\n\n this.logger.debug(`客户端状态更新成功: ${clientId}`);\n } catch (error) {\n this.logger.error(`处理客户端状态更新失败: ${clientId}`, error);\n this.sendError(\n ws,\n \"CLIENT_STATUS_ERROR\",\n error instanceof Error ? error.message : \"客户端状态更新失败\"\n );\n }\n }\n\n /**\n * 发送最新配置给客户端\n */\n private async sendLatestConfig(ws: any, clientId: string): Promise<void> {\n try {\n const latestConfig = await this.configService.getConfig();\n const message = {\n type: \"configUpdate\",\n data: latestConfig,\n timestamp: Date.now(),\n };\n\n ws.send(JSON.stringify(message));\n this.logger.debug(`最新配置已发送给客户端: ${clientId}`);\n } catch (error) {\n this.logger.error(`发送最新配置失败: ${clientId}`, error);\n // 不抛出错误,避免影响心跳处理\n }\n }\n\n /**\n * 发送错误消息\n */\n private sendError(ws: any, code: string, message: string): void {\n try {\n const errorResponse = {\n type: \"error\",\n error: {\n code,\n message,\n timestamp: Date.now(),\n },\n };\n ws.send(JSON.stringify(errorResponse));\n } catch (error) {\n this.logger.error(\"发送错误消息失败:\", error);\n }\n }\n\n /**\n * 检查客户端心跳超时\n */\n checkHeartbeatTimeout(): void {\n const lastHeartbeat = this.statusService.getLastHeartbeat();\n const now = Date.now();\n const HEARTBEAT_TIMEOUT = 35000; // 35 seconds\n\n if (lastHeartbeat && now - lastHeartbeat > HEARTBEAT_TIMEOUT) {\n this.logger.warn(\"客户端心跳超时,标记为断开连接\");\n this.statusService.updateClientInfo(\n { status: \"disconnected\" },\n \"heartbeat-timeout\"\n );\n }\n }\n\n /**\n * 启动心跳监控\n */\n startHeartbeatMonitoring(): NodeJS.Timeout {\n const MONITOR_INTERVAL = 10000; // 10 seconds\n\n this.logger.info(\"启动心跳监控\");\n\n return setInterval(() => {\n this.checkHeartbeatTimeout();\n this.cleanupDisconnectedClients();\n }, MONITOR_INTERVAL);\n }\n\n /**\n * 清理断开连接的客户端\n */\n private cleanupDisconnectedClients(): void {\n try {\n this.notificationService.cleanupDisconnectedClients();\n } catch (error) {\n this.logger.error(\"清理断开连接的客户端失败:\", error);\n }\n }\n\n /**\n * 停止心跳监控\n */\n stopHeartbeatMonitoring(intervalId: NodeJS.Timeout): void {\n this.logger.info(\"停止心跳监控\");\n clearInterval(intervalId);\n }\n\n /**\n * 获取心跳统计信息\n */\n getHeartbeatStats(): {\n lastHeartbeat?: number;\n isConnected: boolean;\n clientStats: {\n totalClients: number;\n connectedClients: number;\n queuedMessages: number;\n };\n } {\n return {\n lastHeartbeat: this.statusService.getLastHeartbeat(),\n isConnected: this.statusService.isClientConnected(),\n clientStats: this.notificationService.getClientStats(),\n };\n }\n\n /**\n * 处理客户端连接建立\n */\n handleClientConnect(clientId: string): void {\n this.logger.info(`客户端连接建立: ${clientId}`);\n\n // 更新状态为连接\n this.statusService.updateClientInfo(\n {\n status: \"connected\",\n lastHeartbeat: Date.now(),\n },\n `websocket-connect-${clientId}`\n );\n }\n\n /**\n * 处理客户端连接断开\n */\n handleClientDisconnect(clientId: string): void {\n this.logger.info(`客户端连接断开: ${clientId}`);\n\n // 更新状态为断开连接\n this.statusService.updateClientInfo(\n { status: \"disconnected\" },\n `websocket-disconnect-${clientId}`\n );\n }\n\n /**\n * 发送心跳响应\n */\n sendHeartbeatResponse(ws: any, clientId: string): void {\n try {\n const response = {\n type: \"heartbeatResponse\",\n data: {\n timestamp: Date.now(),\n status: \"ok\",\n },\n };\n\n ws.send(JSON.stringify(response));\n this.logger.debug(`心跳响应已发送: ${clientId}`);\n } catch (error) {\n this.logger.error(`发送心跳响应失败: ${clientId}`, error);\n }\n }\n\n /**\n * 验证心跳消息格式\n */\n validateHeartbeatMessage(message: any): message is HeartbeatMessage {\n return (\n message &&\n typeof message === \"object\" &&\n message.type === \"clientStatus\" &&\n message.data &&\n typeof message.data === \"object\"\n );\n }\n}\n","import { type Logger, logger } from \"../Logger.js\";\nimport { ConfigService } from \"../services/ConfigService.js\";\nimport { type EventBus, getEventBus } from \"../services/EventBus.js\";\nimport type { NotificationService } from \"../services/NotificationService.js\";\nimport type { StatusService } from \"../services/StatusService.js\";\n\n/**\n * WebSocket 消息接口\n */\ninterface WebSocketMessage {\n type: string;\n data?: any;\n clientId?: string;\n}\n\n/**\n * 实时通知处理器\n */\nexport class RealtimeNotificationHandler {\n private logger: Logger;\n private notificationService: NotificationService;\n private configService: ConfigService;\n private statusService: StatusService;\n private eventBus: EventBus;\n\n constructor(\n notificationService: NotificationService,\n statusService: StatusService\n ) {\n this.logger = logger.withTag(\"RealtimeNotificationHandler\");\n this.notificationService = notificationService;\n this.configService = new ConfigService();\n this.statusService = statusService;\n this.eventBus = getEventBus();\n }\n\n /**\n * 处理 WebSocket 消息\n * @deprecated 部分消息类型已废弃,建议使用 HTTP API\n */\n async handleMessage(\n ws: any,\n message: WebSocketMessage,\n clientId: string\n ): Promise<void> {\n try {\n this.logger.debug(`处理 WebSocket 消息: ${message.type}`, { clientId });\n\n // 发射消息接收事件\n this.eventBus.emitEvent(\"websocket:message:received\", {\n type: message.type,\n data: message.data,\n clientId,\n });\n\n switch (message.type) {\n case \"getConfig\":\n await this.handleGetConfig(ws, clientId);\n break;\n\n case \"updateConfig\":\n await this.handleUpdateConfig(ws, message.data, clientId);\n break;\n\n case \"getStatus\":\n await this.handleGetStatus(ws, clientId);\n break;\n\n case \"restartService\":\n await this.handleRestartService(ws, clientId);\n break;\n\n default:\n this.logger.warn(`未知的 WebSocket 消息类型: ${message.type}`, {\n clientId,\n });\n this.sendError(\n ws,\n \"UNKNOWN_MESSAGE_TYPE\",\n `未知的消息类型: ${message.type}`\n );\n }\n } catch (error) {\n this.logger.error(`处理 WebSocket 消息失败: ${message.type}`, error);\n this.sendError(\n ws,\n \"MESSAGE_PROCESSING_ERROR\",\n error instanceof Error ? error.message : \"消息处理失败\"\n );\n }\n }\n\n /**\n * 处理获取配置请求\n * @deprecated 使用 GET /api/config 替代\n */\n private async handleGetConfig(ws: any, clientId: string): Promise<void> {\n this.logDeprecationWarning(\"WebSocket getConfig\", \"GET /api/config\");\n\n try {\n const config = await this.configService.getConfig();\n this.logger.debug(\"WebSocket: getConfig 请求处理成功\", { clientId });\n ws.send(JSON.stringify({ type: \"config\", data: config }));\n } catch (error) {\n this.logger.error(\"WebSocket: getConfig 请求处理失败\", error);\n this.sendError(\n ws,\n \"CONFIG_READ_ERROR\",\n error instanceof Error ? error.message : \"获取配置失败\"\n );\n }\n }\n\n /**\n * 处理更新配置请求\n * @deprecated 使用 PUT /api/config 替代\n */\n private async handleUpdateConfig(\n ws: any,\n configData: any,\n clientId: string\n ): Promise<void> {\n this.logDeprecationWarning(\"WebSocket updateConfig\", \"PUT /api/config\");\n\n try {\n await this.configService.updateConfig(\n configData,\n `websocket-${clientId}`\n );\n this.logger.debug(\"WebSocket: updateConfig 请求处理成功\", { clientId });\n } catch (error) {\n this.logger.error(\"WebSocket: updateConfig 请求处理失败\", error);\n this.sendError(\n ws,\n \"CONFIG_UPDATE_ERROR\",\n error instanceof Error ? error.message : \"配置更新失败\"\n );\n }\n }\n\n /**\n * 处理获取状态请求\n * @deprecated 使用 GET /api/status 替代\n */\n private async handleGetStatus(ws: any, clientId: string): Promise<void> {\n this.logDeprecationWarning(\"WebSocket getStatus\", \"GET /api/status\");\n\n try {\n const status = this.statusService.getFullStatus();\n ws.send(JSON.stringify({ type: \"status\", data: status.client }));\n this.logger.debug(\"WebSocket: getStatus 请求处理成功\", { clientId });\n } catch (error) {\n this.logger.error(\"WebSocket: getStatus 请求处理失败\", error);\n this.sendError(\n ws,\n \"STATUS_READ_ERROR\",\n error instanceof Error ? error.message : \"获取状态失败\"\n );\n }\n }\n\n /**\n * 处理重启服务请求\n * @deprecated 使用 POST /api/services/restart 替代\n */\n private async handleRestartService(ws: any, clientId: string): Promise<void> {\n this.logDeprecationWarning(\n \"WebSocket restartService\",\n \"POST /api/services/restart\"\n );\n\n try {\n this.logger.info(\"WebSocket: 收到服务重启请求\", { clientId });\n\n // 发射重启请求事件\n this.eventBus.emitEvent(\"service:restart:requested\", {\n source: `websocket-${clientId}`,\n });\n\n // 更新重启状态\n this.statusService.updateRestartStatus(\"restarting\");\n } catch (error) {\n this.logger.error(\"WebSocket: 处理重启请求失败\", error);\n this.sendError(\n ws,\n \"RESTART_REQUEST_ERROR\",\n error instanceof Error ? error.message : \"处理重启请求失败\"\n );\n }\n }\n\n /**\n * 发送错误消息\n */\n private sendError(ws: any, code: string, message: string): void {\n try {\n const errorResponse = {\n type: \"error\",\n error: {\n code,\n message,\n timestamp: Date.now(),\n },\n };\n ws.send(JSON.stringify(errorResponse));\n } catch (error) {\n this.logger.error(\"发送错误消息失败:\", error);\n }\n }\n\n /**\n * 记录废弃功能使用警告\n */\n private logDeprecationWarning(feature: string, alternative: string): void {\n this.logger.warn(\n `[DEPRECATED] ${feature} 功能已废弃,请使用 ${alternative} 替代`\n );\n }\n\n /**\n * 发送初始数据给新连接的客户端\n */\n async sendInitialData(ws: any, clientId: string): Promise<void> {\n try {\n this.logger.debug(\"发送初始数据给客户端\", { clientId });\n\n // 发送当前配置\n const config = await this.configService.getConfig();\n ws.send(JSON.stringify({ type: \"configUpdate\", data: config }));\n\n // 发送当前状态\n const status = this.statusService.getFullStatus();\n ws.send(JSON.stringify({ type: \"statusUpdate\", data: status.client }));\n\n // 如果有重启状态,也发送\n if (status.restart) {\n ws.send(\n JSON.stringify({ type: \"restartStatus\", data: status.restart })\n );\n }\n\n this.logger.debug(\"初始数据发送完成\", { clientId });\n } catch (error) {\n this.logger.error(\"发送初始数据失败:\", error);\n this.sendError(\n ws,\n \"INITIAL_DATA_ERROR\",\n error instanceof Error ? error.message : \"发送初始数据失败\"\n );\n }\n }\n\n /**\n * 处理客户端断开连接\n */\n handleClientDisconnect(clientId: string): void {\n this.logger.info(`客户端断开连接: ${clientId}`);\n this.notificationService.unregisterClient(clientId);\n }\n\n /**\n * 处理客户端连接\n */\n handleClientConnect(ws: any, clientId: string): void {\n this.logger.info(`客户端连接: ${clientId}`);\n this.notificationService.registerClient(clientId, ws);\n }\n}\n","/**\n * CLI 常量定义\n */\n\n/**\n * 服务相关常量\n */\nexport const SERVICE_CONSTANTS = {\n /** 服务名称 */\n NAME: \"xiaozhi-mcp-service\",\n /** 默认端口 */\n DEFAULT_PORT: 3000,\n /** Web UI 默认端口 */\n DEFAULT_WEB_UI_PORT: 9999,\n /** PID 文件名 */\n PID_FILE: \"xiaozhi.pid\",\n /** 日志文件名 */\n LOG_FILE: \"xiaozhi.log\",\n} as const;\n\n/**\n * 配置相关常量\n */\nexport const CONFIG_CONSTANTS = {\n /** 配置文件名(按优先级排序) */\n FILE_NAMES: [\n \"xiaozhi.config.json5\",\n \"xiaozhi.config.jsonc\",\n \"xiaozhi.config.json\",\n ],\n /** 默认配置文件名 */\n DEFAULT_FILE: \"xiaozhi.config.default.json\",\n /** 配置目录环境变量 */\n DIR_ENV_VAR: \"XIAOZHI_CONFIG_DIR\",\n} as const;\n\n/**\n * 路径相关常量\n */\nexport const PATH_CONSTANTS = {\n /** 工作目录名 */\n WORK_DIR: \".xiaozhi\",\n /** 模板目录名 */\n TEMPLATES_DIR: \"templates\",\n /** 日志目录名 */\n LOGS_DIR: \"logs\",\n} as const;\n\n/**\n * 错误码常量\n */\nexport const ERROR_CODES = {\n /** 通用错误 */\n GENERAL_ERROR: \"GENERAL_ERROR\",\n /** 配置错误 */\n CONFIG_ERROR: \"CONFIG_ERROR\",\n /** 服务错误 */\n SERVICE_ERROR: \"SERVICE_ERROR\",\n /** 验证错误 */\n VALIDATION_ERROR: \"VALIDATION_ERROR\",\n /** 文件操作错误 */\n FILE_ERROR: \"FILE_ERROR\",\n /** 进程错误 */\n PROCESS_ERROR: \"PROCESS_ERROR\",\n /** 网络错误 */\n NETWORK_ERROR: \"NETWORK_ERROR\",\n /** 权限错误 */\n PERMISSION_ERROR: \"PERMISSION_ERROR\",\n} as const;\n\n/**\n * 超时常量(毫秒)\n */\nexport const TIMEOUT_CONSTANTS = {\n /** 进程停止超时 */\n PROCESS_STOP: 3000,\n /** 服务启动超时 */\n SERVICE_START: 10000,\n /** 网络请求超时 */\n NETWORK_REQUEST: 5000,\n /** 文件操作超时 */\n FILE_OPERATION: 2000,\n} as const;\n\n/**\n * 重试常量\n */\nexport const RETRY_CONSTANTS = {\n /** 默认重试次数 */\n DEFAULT_ATTEMPTS: 3,\n /** 重试间隔(毫秒) */\n DEFAULT_INTERVAL: 1000,\n /** 最大重试间隔(毫秒) */\n MAX_INTERVAL: 5000,\n} as const;\n","/**\n * 错误消息管理\n */\n\nimport { ERROR_CODES } from \"../Constants.js\";\n\n/**\n * 错误消息映射\n */\nconst ERROR_HELP_MESSAGES: Record<string, string> = {\n [ERROR_CODES.CONFIG_ERROR]: '运行 \"xiaozhi --help\" 查看配置相关命令',\n [ERROR_CODES.SERVICE_ERROR]: '运行 \"xiaozhi status\" 检查服务状态',\n [ERROR_CODES.VALIDATION_ERROR]: \"检查输入参数是否正确\",\n [ERROR_CODES.FILE_ERROR]: \"检查文件路径和权限\",\n [ERROR_CODES.PROCESS_ERROR]: \"检查进程状态和权限\",\n [ERROR_CODES.NETWORK_ERROR]: \"检查网络连接和防火墙设置\",\n [ERROR_CODES.PERMISSION_ERROR]: \"尝试使用管理员权限运行\",\n};\n\n/**\n * 常见问题解决方案\n */\nconst COMMON_SOLUTIONS: Record<string, string[]> = {\n config_not_found: [\n '运行 \"xiaozhi init\" 初始化配置文件',\n \"检查当前目录是否为项目根目录\",\n \"设置 XIAOZHI_CONFIG_DIR 环境变量指定配置目录\",\n ],\n service_port_occupied: [\n \"检查端口是否被其他程序占用\",\n '使用 \"lsof -i :端口号\" 查看端口使用情况',\n \"更改配置文件中的端口设置\",\n ],\n permission_denied: [\n \"检查文件和目录权限\",\n \"使用 sudo 或管理员权限运行\",\n \"确保当前用户有足够的权限\",\n ],\n service_start_failed: [\n \"检查配置文件格式是否正确\",\n \"查看日志文件获取详细错误信息\",\n \"确保所有依赖服务正常运行\",\n ],\n};\n\n/**\n * 错误消息管理类\n */\nexport class ERROR_MESSAGES {\n /**\n * 获取错误码对应的帮助信息\n */\n static getHelpMessage(errorCode: string): string | undefined {\n return ERROR_HELP_MESSAGES[errorCode];\n }\n\n /**\n * 获取常见问题的解决方案\n */\n static getSolutions(problemKey: string): string[] {\n return COMMON_SOLUTIONS[problemKey] || [];\n }\n\n /**\n * 格式化错误消息\n */\n static formatError(error: Error, context?: string): string {\n const contextPrefix = context ? `[${context}] ` : \"\";\n return `${contextPrefix}${error.message}`;\n }\n\n /**\n * 获取友好的错误描述\n */\n static getFriendlyMessage(errorCode: string): string {\n const friendlyMessages: Record<string, string> = {\n [ERROR_CODES.CONFIG_ERROR]: \"配置文件相关错误\",\n [ERROR_CODES.SERVICE_ERROR]: \"服务运行相关错误\",\n [ERROR_CODES.VALIDATION_ERROR]: \"输入验证错误\",\n [ERROR_CODES.FILE_ERROR]: \"文件操作错误\",\n [ERROR_CODES.PROCESS_ERROR]: \"进程管理错误\",\n [ERROR_CODES.NETWORK_ERROR]: \"网络连接错误\",\n [ERROR_CODES.PERMISSION_ERROR]: \"权限不足错误\",\n };\n\n return friendlyMessages[errorCode] || \"未知错误\";\n }\n\n /**\n * 检查是否为可恢复错误\n */\n static isRecoverable(errorCode: string): boolean {\n const recoverableErrors: string[] = [\n ERROR_CODES.NETWORK_ERROR,\n ERROR_CODES.FILE_ERROR,\n ERROR_CODES.SERVICE_ERROR,\n ];\n\n return recoverableErrors.includes(errorCode);\n }\n\n /**\n * 获取错误的严重程度\n */\n static getSeverity(\n errorCode: string\n ): \"low\" | \"medium\" | \"high\" | \"critical\" {\n const severityMap: Record<string, \"low\" | \"medium\" | \"high\" | \"critical\"> =\n {\n [ERROR_CODES.VALIDATION_ERROR]: \"low\",\n [ERROR_CODES.FILE_ERROR]: \"medium\",\n [ERROR_CODES.CONFIG_ERROR]: \"medium\",\n [ERROR_CODES.NETWORK_ERROR]: \"medium\",\n [ERROR_CODES.SERVICE_ERROR]: \"high\",\n [ERROR_CODES.PROCESS_ERROR]: \"high\",\n [ERROR_CODES.PERMISSION_ERROR]: \"critical\",\n };\n\n return severityMap[errorCode] || \"medium\";\n }\n}\n","/**\n * 统一错误处理系统\n */\n\nimport { ERROR_CODES } from \"../Constants.js\";\n\n/**\n * CLI 基础错误类\n */\nexport class CLIError extends Error {\n constructor(\n message: string,\n public code: string,\n public exitCode = 1,\n public suggestions?: string[]\n ) {\n super(message);\n this.name = \"CLIError\";\n\n // 确保错误堆栈正确显示\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, CLIError);\n }\n }\n\n /**\n * 创建带建议的错误\n */\n static withSuggestions(\n message: string,\n code: string,\n suggestions: string[]\n ): CLIError {\n return new CLIError(message, code, 1, suggestions);\n }\n}\n\n/**\n * 配置错误\n */\nexport class ConfigError extends CLIError {\n constructor(message: string, suggestions?: string[]) {\n super(message, ERROR_CODES.CONFIG_ERROR, 1, suggestions);\n this.name = \"ConfigError\";\n }\n\n static configNotFound(): ConfigError {\n return new ConfigError(\"配置文件不存在\", [\n '请运行 \"xiaozhi init\" 初始化配置文件',\n ]);\n }\n\n static invalidFormat(format: string): ConfigError {\n return new ConfigError(`无效的配置文件格式: ${format}`, [\n \"支持的格式: json, json5, jsonc\",\n ]);\n }\n}\n\n/**\n * 服务错误\n */\nexport class ServiceError extends CLIError {\n constructor(message: string, suggestions?: string[]) {\n super(message, ERROR_CODES.SERVICE_ERROR, 1, suggestions);\n this.name = \"ServiceError\";\n }\n\n static alreadyRunning(pid: number): ServiceError {\n return new ServiceError(`服务已经在运行 (PID: ${pid})`, [\n '请先运行 \"xiaozhi stop\" 停止现有服务',\n '或者使用 \"xiaozhi restart\" 重启服务',\n ]);\n }\n\n static autoRestarting(pid: number): ServiceError {\n return new ServiceError(\n `检测到服务已在运行 (PID: ${pid}),正在自动重启...`,\n [\"如果不希望自动重启,请使用 xiaozhi stop 手动停止服务\"]\n );\n }\n\n static notRunning(): ServiceError {\n return new ServiceError(\"服务未运行\", ['请运行 \"xiaozhi start\" 启动服务']);\n }\n\n static startFailed(reason: string): ServiceError {\n return new ServiceError(`服务启动失败: ${reason}`, [\n \"检查配置文件是否正确\",\n \"确保端口未被占用\",\n \"查看日志文件获取详细信息\",\n ]);\n }\n}\n\n/**\n * 验证错误\n */\nexport class ValidationError extends CLIError {\n constructor(message: string, field: string) {\n super(`验证失败: ${field} - ${message}`, ERROR_CODES.VALIDATION_ERROR, 1);\n this.name = \"ValidationError\";\n }\n\n static invalidPort(port: number): ValidationError {\n return new ValidationError(\n `端口号必须在 1-65535 范围内,当前值: ${port}`,\n \"port\"\n );\n }\n\n static requiredField(field: string): ValidationError {\n return new ValidationError(\"必填字段不能为空\", field);\n }\n}\n\n/**\n * 文件操作错误\n */\nexport class FileError extends CLIError {\n constructor(message: string, filePath?: string, suggestions?: string[]) {\n const fullMessage = filePath ? `${message}: ${filePath}` : message;\n super(fullMessage, ERROR_CODES.FILE_ERROR, 1, suggestions);\n this.name = \"FileError\";\n }\n\n static notFound(filePath: string): FileError {\n return new FileError(\"文件不存在\", filePath, [\"检查文件路径是否正确\"]);\n }\n\n static permissionDenied(filePath: string): FileError {\n return new FileError(\"权限不足\", filePath, [\n \"检查文件权限或使用管理员权限运行\",\n ]);\n }\n\n static alreadyExists(filePath: string): FileError {\n return new FileError(\"文件已存在\", filePath, [\n \"使用不同的文件名或删除现有文件\",\n ]);\n }\n}\n\n/**\n * 进程错误\n */\nexport class ProcessError extends CLIError {\n constructor(message: string, pid?: number, suggestions?: string[]) {\n const fullMessage = pid ? `${message} (PID: ${pid})` : message;\n super(fullMessage, ERROR_CODES.PROCESS_ERROR, 1, suggestions);\n this.name = \"ProcessError\";\n }\n\n static killFailed(pid: number): ProcessError {\n return new ProcessError(\"无法终止进程\", pid, [\n \"进程可能已经停止或权限不足\",\n ]);\n }\n\n static notFound(pid: number): ProcessError {\n return new ProcessError(\"进程不存在\", pid);\n }\n}\n","/**\n * 错误处理器\n */\n\nimport chalk from \"chalk\";\nimport { ERROR_MESSAGES } from \"./ErrorMessages.js\";\nimport { CLIError } from \"./index.js\";\n\n/**\n * 错误处理器类\n */\nexport class ErrorHandler {\n /**\n * 处理错误并退出程序\n */\n static handle(error: Error): never {\n if (error instanceof CLIError) {\n ErrorHandler.handleCLIError(error);\n } else {\n ErrorHandler.handleUnknownError(error);\n }\n\n process.exit(1);\n }\n\n /**\n * 处理 CLI 错误\n */\n private static handleCLIError(error: CLIError): void {\n console.error(chalk.red(`❌ 错误: ${error.message}`));\n\n // 显示错误码(调试模式)\n if (process.env.DEBUG) {\n console.error(chalk.gray(`错误码: ${error.code}`));\n }\n\n // 显示建议\n if (error.suggestions && error.suggestions.length > 0) {\n console.log(chalk.yellow(\"💡 建议:\"));\n for (const suggestion of error.suggestions) {\n console.log(chalk.gray(` ${suggestion}`));\n }\n }\n\n // 显示相关帮助信息\n const helpMessage = ERROR_MESSAGES.getHelpMessage(error.code);\n if (helpMessage) {\n console.log(chalk.blue(`ℹ️ ${helpMessage}`));\n }\n }\n\n /**\n * 处理未知错误\n */\n private static handleUnknownError(error: Error): void {\n console.error(chalk.red(`❌ 未知错误: ${error.message}`));\n\n // 在调试模式下显示完整堆栈\n if (process.env.DEBUG || process.env.NODE_ENV === \"development\") {\n console.error(chalk.gray(\"堆栈信息:\"));\n console.error(chalk.gray(error.stack));\n } else {\n console.log(\n chalk.yellow(\"💡 提示: 设置 DEBUG=1 环境变量查看详细错误信息\")\n );\n }\n }\n\n /**\n * 异步操作错误处理包装器\n */\n static async handleAsync<T>(\n operation: () => Promise<T>,\n context: string\n ): Promise<T> {\n try {\n return await operation();\n } catch (error) {\n if (error instanceof CLIError) {\n throw error;\n }\n if (error instanceof Error) {\n throw new CLIError(\n `${context}失败: ${error.message}`,\n \"OPERATION_FAILED\",\n 1\n );\n }\n throw new CLIError(`${context}失败: 未知错误`, \"OPERATION_FAILED\", 1);\n }\n }\n\n /**\n * 同步操作错误处理包装器\n */\n static handleSync<T>(operation: () => T, context: string): T {\n try {\n return operation();\n } catch (error) {\n if (error instanceof CLIError) {\n throw error;\n }\n if (error instanceof Error) {\n throw new CLIError(\n `${context}失败: ${error.message}`,\n \"OPERATION_FAILED\",\n 1\n );\n }\n throw new CLIError(`${context}失败: 未知错误`, \"OPERATION_FAILED\", 1);\n }\n }\n\n /**\n * 警告处理\n */\n static warn(message: string, suggestions?: string[]): void {\n console.warn(chalk.yellow(`⚠️ 警告: ${message}`));\n\n if (suggestions && suggestions.length > 0) {\n console.log(chalk.yellow(\"💡 建议:\"));\n for (const suggestion of suggestions) {\n console.log(chalk.gray(` ${suggestion}`));\n }\n }\n }\n\n /**\n * 信息提示\n */\n static info(message: string): void {\n console.log(chalk.blue(`ℹ️ ${message}`));\n }\n\n /**\n * 成功提示\n */\n static success(message: string): void {\n console.log(chalk.green(`✅ ${message}`));\n }\n}\n","/**\n * 文件操作工具\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport type { FileOperationOptions } from \"../Types.js\";\nimport { FileError } from \"../errors/index.js\";\n\n/**\n * 文件工具类\n */\nexport class FileUtils {\n /**\n * 检查文件是否存在\n */\n static exists(filePath: string): boolean {\n try {\n return fs.existsSync(filePath);\n } catch {\n return false;\n }\n }\n\n /**\n * 确保目录存在\n */\n static ensureDir(dirPath: string): void {\n try {\n if (!fs.existsSync(dirPath)) {\n fs.mkdirSync(dirPath, { recursive: true });\n }\n } catch (error) {\n throw new FileError(\"无法创建目录\", dirPath);\n }\n }\n\n /**\n * 读取文件内容\n */\n static readFile(filePath: string, encoding: BufferEncoding = \"utf8\"): string {\n try {\n if (!FileUtils.exists(filePath)) {\n throw FileError.notFound(filePath);\n }\n return fs.readFileSync(filePath, encoding);\n } catch (error) {\n if (error instanceof FileError) {\n throw error;\n }\n throw new FileError(\"无法读取文件\", filePath);\n }\n }\n\n /**\n * 写入文件内容\n */\n static writeFile(\n filePath: string,\n content: string,\n options?: { overwrite?: boolean }\n ): void {\n try {\n if (!options?.overwrite && FileUtils.exists(filePath)) {\n throw FileError.alreadyExists(filePath);\n }\n\n // 确保目录存在\n const dir = path.dirname(filePath);\n FileUtils.ensureDir(dir);\n\n fs.writeFileSync(filePath, content, \"utf8\");\n } catch (error) {\n if (error instanceof FileError) {\n throw error;\n }\n throw new FileError(\"无法写入文件\", filePath);\n }\n }\n\n /**\n * 复制文件\n */\n static copyFile(\n srcPath: string,\n destPath: string,\n options?: { overwrite?: boolean }\n ): void {\n try {\n if (!FileUtils.exists(srcPath)) {\n throw FileError.notFound(srcPath);\n }\n\n if (!options?.overwrite && FileUtils.exists(destPath)) {\n throw FileError.alreadyExists(destPath);\n }\n\n // 确保目标目录存在\n const destDir = path.dirname(destPath);\n FileUtils.ensureDir(destDir);\n\n fs.copyFileSync(srcPath, destPath);\n } catch (error) {\n if (error instanceof FileError) {\n throw error;\n }\n throw new FileError(\"无法复制文件\", srcPath);\n }\n }\n\n /**\n * 删除文件\n */\n static deleteFile(filePath: string): void {\n try {\n if (FileUtils.exists(filePath)) {\n fs.unlinkSync(filePath);\n }\n } catch (error) {\n throw new FileError(\"无法删除文件\", filePath);\n }\n }\n\n /**\n * 复制目录\n */\n static copyDirectory(\n srcDir: string,\n destDir: string,\n options: FileOperationOptions = {}\n ): void {\n try {\n if (!FileUtils.exists(srcDir)) {\n throw FileError.notFound(srcDir);\n }\n\n // 确保目标目录存在\n FileUtils.ensureDir(destDir);\n\n const items = fs.readdirSync(srcDir);\n\n for (const item of items) {\n // 检查是否在排除列表中\n if (options.exclude?.includes(item)) {\n continue;\n }\n\n const srcPath = path.join(srcDir, item);\n const destPath = path.join(destDir, item);\n const stat = fs.statSync(srcPath);\n\n if (stat.isDirectory()) {\n if (options.recursive !== false) {\n FileUtils.copyDirectory(srcPath, destPath, options);\n }\n } else {\n FileUtils.copyFile(srcPath, destPath, {\n overwrite: options.overwrite,\n });\n }\n }\n } catch (error) {\n if (error instanceof FileError) {\n throw error;\n }\n throw new FileError(\"无法复制目录\", srcDir);\n }\n }\n\n /**\n * 删除目录\n */\n static deleteDirectory(\n dirPath: string,\n options: { recursive?: boolean } = {}\n ): void {\n try {\n if (FileUtils.exists(dirPath)) {\n fs.rmSync(dirPath, {\n recursive: options.recursive ?? true,\n force: true,\n });\n }\n } catch (error) {\n throw new FileError(\"无法删除目录\", dirPath);\n }\n }\n\n /**\n * 获取文件信息\n */\n static getFileInfo(filePath: string): {\n size: number;\n isFile: boolean;\n isDirectory: boolean;\n mtime: Date;\n ctime: Date;\n } {\n try {\n if (!FileUtils.exists(filePath)) {\n throw FileError.notFound(filePath);\n }\n\n const stats = fs.statSync(filePath);\n return {\n size: stats.size,\n isFile: stats.isFile(),\n isDirectory: stats.isDirectory(),\n mtime: stats.mtime,\n ctime: stats.ctime,\n };\n } catch (error) {\n if (error instanceof FileError) {\n throw error;\n }\n throw new FileError(\"无法获取文件信息\", filePath);\n }\n }\n\n /**\n * 列出目录内容\n */\n static listDirectory(\n dirPath: string,\n options: {\n recursive?: boolean;\n includeHidden?: boolean;\n } = {}\n ): string[] {\n try {\n if (!FileUtils.exists(dirPath)) {\n throw FileError.notFound(dirPath);\n }\n\n const items = fs.readdirSync(dirPath);\n let result: string[] = [];\n\n for (const item of items) {\n // 跳过隐藏文件(除非明确要求包含)\n if (!options.includeHidden && item.startsWith(\".\")) {\n continue;\n }\n\n const itemPath = path.join(dirPath, item);\n result.push(itemPath);\n\n // 递归处理子目录\n if (options.recursive && fs.statSync(itemPath).isDirectory()) {\n const subItems = FileUtils.listDirectory(itemPath, options);\n result = result.concat(subItems);\n }\n }\n\n return result;\n } catch (error) {\n if (error instanceof FileError) {\n throw error;\n }\n throw new FileError(\"无法列出目录内容\", dirPath);\n }\n }\n\n /**\n * 创建临时文件\n */\n static createTempFile(prefix = \"xiaozhi-\", suffix = \".tmp\"): string {\n const tempDir = process.env.TMPDIR || process.env.TEMP || \"/tmp\";\n const timestamp = Date.now();\n const random = Math.random().toString(36).substring(2);\n const fileName = `${prefix}${timestamp}-${random}${suffix}`;\n return path.join(tempDir, fileName);\n }\n\n /**\n * 检查文件权限\n */\n static checkPermissions(\n filePath: string,\n mode: number = fs.constants.R_OK | fs.constants.W_OK\n ): boolean {\n try {\n fs.accessSync(filePath, mode);\n return true;\n } catch {\n return false;\n }\n }\n\n /**\n * 获取文件扩展名\n */\n static getExtension(filePath: string): string {\n return path.extname(filePath).toLowerCase();\n }\n\n /**\n * 获取文件名(不含扩展名)\n */\n static getBaseName(filePath: string): string {\n return path.basename(filePath, path.extname(filePath));\n }\n\n /**\n * 规范化路径\n */\n static normalizePath(filePath: string): string {\n return path.normalize(filePath);\n }\n\n /**\n * 解析相对路径为绝对路径\n */\n static resolvePath(filePath: string, basePath?: string): string {\n if (basePath) {\n return path.resolve(basePath, filePath);\n }\n return path.resolve(filePath);\n }\n}\n","/**\n * 格式化工具\n */\n\n/**\n * 格式化工具类\n */\nexport class FormatUtils {\n /**\n * 格式化运行时间\n */\n static formatUptime(ms: number): string {\n const seconds = Math.floor(ms / 1000);\n const minutes = Math.floor(seconds / 60);\n const hours = Math.floor(minutes / 60);\n const days = Math.floor(hours / 24);\n\n if (days > 0) {\n return `${days}天 ${hours % 24}小时 ${minutes % 60}分钟`;\n }\n if (hours > 0) {\n return `${hours}小时 ${minutes % 60}分钟`;\n }\n if (minutes > 0) {\n return `${minutes}分钟 ${seconds % 60}秒`;\n }\n return `${seconds}秒`;\n }\n\n /**\n * 格式化文件大小\n */\n static formatFileSize(bytes: number): string {\n const units = [\"B\", \"KB\", \"MB\", \"GB\", \"TB\"];\n let size = bytes;\n let unitIndex = 0;\n\n while (size >= 1024 && unitIndex < units.length - 1) {\n size /= 1024;\n unitIndex++;\n }\n\n return `${size.toFixed(unitIndex === 0 ? 0 : 1)} ${units[unitIndex]}`;\n }\n\n /**\n * 格式化时间戳\n */\n static formatTimestamp(\n timestamp: number,\n format: \"full\" | \"date\" | \"time\" = \"full\"\n ): string {\n const date = new Date(timestamp);\n\n switch (format) {\n case \"date\":\n return date.toLocaleDateString(\"zh-CN\");\n case \"time\":\n return date.toLocaleTimeString(\"zh-CN\");\n default:\n return date.toLocaleString(\"zh-CN\");\n }\n }\n\n /**\n * 格式化进程 ID\n */\n static formatPid(pid: number): string {\n return `PID: ${pid}`;\n }\n\n /**\n * 格式化端口号\n */\n static formatPort(port: number): string {\n return `端口: ${port}`;\n }\n\n /**\n * 格式化 URL\n */\n static formatUrl(\n protocol: string,\n host: string,\n port: number,\n path?: string\n ): string {\n const url = `${protocol}://${host}:${port}`;\n return path ? `${url}${path}` : url;\n }\n\n /**\n * 格式化配置键值对\n */\n static formatConfigPair(key: string, value: any): string {\n if (typeof value === \"object\") {\n return `${key}: ${JSON.stringify(value, null, 2)}`;\n }\n return `${key}: ${value}`;\n }\n\n /**\n * 格式化错误消息\n */\n static formatError(error: Error, includeStack = false): string {\n let message = `错误: ${error.message}`;\n\n if (includeStack && error.stack) {\n message += `\\n堆栈信息:\\n${error.stack}`;\n }\n\n return message;\n }\n\n /**\n * 格式化列表\n */\n static formatList(items: string[], bullet = \"•\"): string {\n return items.map((item) => `${bullet} ${item}`).join(\"\\n\");\n }\n\n /**\n * 格式化表格数据\n */\n static formatTable(data: Record<string, any>[]): string {\n if (data.length === 0) return \"\";\n\n const keys = Object.keys(data[0]);\n const maxWidths = keys.map((key) =>\n Math.max(key.length, ...data.map((row) => String(row[key]).length))\n );\n\n // 表头\n const header = keys.map((key, i) => key.padEnd(maxWidths[i])).join(\" | \");\n const separator = maxWidths.map((width) => \"-\".repeat(width)).join(\"-|-\");\n\n // 数据行\n const rows = data.map((row) =>\n keys.map((key, i) => String(row[key]).padEnd(maxWidths[i])).join(\" | \")\n );\n\n return [header, separator, ...rows].join(\"\\n\");\n }\n\n /**\n * 格式化进度条\n */\n static formatProgressBar(current: number, total: number, width = 20): string {\n const percentage = Math.min(current / total, 1);\n const filled = Math.floor(percentage * width);\n const empty = width - filled;\n\n const bar = \"█\".repeat(filled) + \"░\".repeat(empty);\n const percent = Math.floor(percentage * 100);\n\n return `[${bar}] ${percent}% (${current}/${total})`;\n }\n\n /**\n * 格式化命令行参数\n */\n static formatCommandArgs(command: string, args: string[]): string {\n const quotedArgs = args.map((arg) =>\n arg.includes(\" \") ? `\"${arg}\"` : arg\n );\n return `${command} ${quotedArgs.join(\" \")}`;\n }\n\n /**\n * 截断长文本\n */\n static truncateText(text: string, maxLength: number, suffix = \"...\"): string {\n if (text.length <= maxLength) return text;\n return text.substring(0, maxLength - suffix.length) + suffix;\n }\n\n /**\n * 格式化 JSON\n */\n static formatJson(obj: any, indent = 2): string {\n try {\n return JSON.stringify(obj, null, indent);\n } catch (error) {\n return String(obj);\n }\n }\n\n /**\n * 格式化布尔值\n */\n static formatBoolean(\n value: boolean,\n trueText = \"是\",\n falseText = \"否\"\n ): string {\n return value ? trueText : falseText;\n }\n}\n","/**\n * 路径处理工具\n */\n\nimport { realpathSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport {\n CONFIG_CONSTANTS,\n PATH_CONSTANTS,\n SERVICE_CONSTANTS,\n} from \"../Constants.js\";\nimport { FileUtils } from \"./FileUtils.js\";\n\n/**\n * 路径工具类\n */\nexport class PathUtils {\n /**\n * 获取 PID 文件路径\n */\n static getPidFile(): string {\n // 优先使用环境变量中的配置目录,否则使用当前工作目录\n const configDir =\n process.env[CONFIG_CONSTANTS.DIR_ENV_VAR] || process.cwd();\n return path.join(configDir, `.${SERVICE_CONSTANTS.NAME}.pid`);\n }\n\n /**\n * 获取日志文件路径\n */\n static getLogFile(projectDir?: string): string {\n const baseDir = projectDir || process.cwd();\n return path.join(baseDir, SERVICE_CONSTANTS.LOG_FILE);\n }\n\n /**\n * 获取配置目录路径\n */\n static getConfigDir(): string {\n return process.env[CONFIG_CONSTANTS.DIR_ENV_VAR] || process.cwd();\n }\n\n /**\n * 获取工作目录路径\n */\n static getWorkDir(): string {\n const configDir = PathUtils.getConfigDir();\n return path.join(configDir, PATH_CONSTANTS.WORK_DIR);\n }\n\n /**\n * 获取模板目录路径\n */\n static getTemplatesDir(): string[] {\n // 在 ES 模块环境中获取当前目录\n const __filename = fileURLToPath(import.meta.url);\n const scriptDir = path.dirname(__filename);\n\n return [\n // 构建后的环境:dist/cli.js -> dist/templates\n path.join(scriptDir, PATH_CONSTANTS.TEMPLATES_DIR),\n // 开发环境:src/cli/utils/PathUtils.ts -> templates\n path.join(scriptDir, \"..\", \"..\", \"..\", PATH_CONSTANTS.TEMPLATES_DIR),\n // npm 全局安装\n path.join(\n scriptDir,\n \"..\",\n \"..\",\n \"..\",\n \"..\",\n PATH_CONSTANTS.TEMPLATES_DIR\n ),\n ];\n }\n\n /**\n * 查找模板目录\n */\n static findTemplatesDir(): string | null {\n const possiblePaths = PathUtils.getTemplatesDir();\n\n for (const templatesDir of possiblePaths) {\n if (FileUtils.exists(templatesDir)) {\n return templatesDir;\n }\n }\n\n return null;\n }\n\n /**\n * 获取模板路径\n */\n static getTemplatePath(templateName: string): string | null {\n const templatesDir = PathUtils.findTemplatesDir();\n if (!templatesDir) {\n return null;\n }\n\n const templatePath = path.join(templatesDir, templateName);\n return FileUtils.exists(templatePath) ? templatePath : null;\n }\n\n /**\n * 获取脚本目录路径\n */\n static getScriptDir(): string {\n const __filename = fileURLToPath(import.meta.url);\n return path.dirname(__filename);\n }\n\n /**\n * 获取项目根目录路径\n */\n static getProjectRoot(): string {\n const scriptDir = PathUtils.getScriptDir();\n // 从 src/cli/utils 回到项目根目录\n return path.join(scriptDir, \"..\", \"..\", \"..\");\n }\n\n /**\n * 获取构建输出目录路径\n */\n static getDistDir(): string {\n const projectRoot = PathUtils.getProjectRoot();\n return path.join(projectRoot, \"dist\");\n }\n\n /**\n * 获取相对于项目根目录的路径\n */\n static getRelativePath(filePath: string): string {\n const projectRoot = PathUtils.getProjectRoot();\n return path.relative(projectRoot, filePath);\n }\n\n /**\n * 解析配置文件路径\n */\n static resolveConfigPath(format?: \"json\" | \"json5\" | \"jsonc\"): string {\n const configDir = PathUtils.getConfigDir();\n\n if (format) {\n return path.join(configDir, `xiaozhi.config.${format}`);\n }\n\n // 按优先级查找配置文件\n for (const fileName of CONFIG_CONSTANTS.FILE_NAMES) {\n const filePath = path.join(configDir, fileName);\n if (FileUtils.exists(filePath)) {\n return filePath;\n }\n }\n\n // 返回默认配置文件路径\n return path.join(configDir, CONFIG_CONSTANTS.FILE_NAMES[2]); // xiaozhi.config.json\n }\n\n /**\n * 获取默认配置文件路径\n */\n static getDefaultConfigPath(): string {\n const projectRoot = PathUtils.getProjectRoot();\n return path.join(projectRoot, CONFIG_CONSTANTS.DEFAULT_FILE);\n }\n\n /**\n * 验证路径安全性(防止路径遍历攻击)\n */\n static validatePath(inputPath: string): boolean {\n const normalizedPath = path.normalize(inputPath);\n return !normalizedPath.includes(\"..\");\n }\n\n /**\n * 确保路径在指定目录内\n */\n static ensurePathWithin(inputPath: string, baseDir: string): string {\n const resolvedPath = path.resolve(baseDir, inputPath);\n const resolvedBase = path.resolve(baseDir);\n\n if (!resolvedPath.startsWith(resolvedBase)) {\n throw new Error(`路径 ${inputPath} 超出了允许的范围`);\n }\n\n return resolvedPath;\n }\n\n /**\n * 获取可执行文件路径\n */\n static getExecutablePath(name: string): string {\n // 获取当前执行的 CLI 脚本路径\n const cliPath = process.argv[1];\n\n // 处理 cliPath 为 undefined 的情况\n if (!cliPath) {\n // 如果没有脚本路径,使用当前工作目录\n return path.join(process.cwd(), `${name}.js`);\n }\n\n // 解析符号链接,获取真实路径\n let realCliPath: string;\n try {\n realCliPath = realpathSync(cliPath);\n } catch (error) {\n // 如果无法解析符号链接,使用原路径\n realCliPath = cliPath;\n }\n\n // 获取 dist 目录\n const distDir = path.dirname(realCliPath);\n return path.join(distDir, `${name}.js`);\n }\n\n /**\n * 获取 MCP 服务器代理路径\n */\n static getMcpServerProxyPath(): string {\n return PathUtils.getExecutablePath(\"mcpServerProxy\");\n }\n\n /**\n * 获取 Web 服务器独立启动脚本路径\n */\n static getWebServerStandalonePath(): string {\n return PathUtils.getExecutablePath(\"WebServerStandalone\");\n }\n\n /**\n * 创建安全的文件路径\n */\n static createSafePath(...segments: string[]): string {\n const joinedPath = path.join(...segments);\n const normalizedPath = path.normalize(joinedPath);\n\n // 检查路径是否包含危险字符\n if (normalizedPath.includes(\"..\") || normalizedPath.includes(\"~\")) {\n throw new Error(`不安全的路径: ${normalizedPath}`);\n }\n\n return normalizedPath;\n }\n\n /**\n * 获取临时目录路径\n */\n static getTempDir(): string {\n // 使用 Node.js 的 os.tmpdir() 来获取跨平台的临时目录\n return process.env.TMPDIR || process.env.TEMP || tmpdir();\n }\n\n /**\n * 获取用户主目录路径\n */\n static getHomeDir(): string {\n return process.env.HOME || process.env.USERPROFILE || \"\";\n }\n}\n","/**\n * 平台相关工具\n */\n\nimport { execSync } from \"node:child_process\";\nimport { TIMEOUT_CONSTANTS } from \"../Constants.js\";\nimport type { Platform } from \"../Types.js\";\nimport { ProcessError } from \"../errors/index.js\";\n\n/**\n * 平台工具类\n */\nexport class PlatformUtils {\n /**\n * 获取当前平台\n */\n static getCurrentPlatform(): Platform {\n return process.platform as Platform;\n }\n\n /**\n * 检查是否为 Windows 平台\n */\n static isWindows(): boolean {\n return process.platform === \"win32\";\n }\n\n /**\n * 检查是否为 macOS 平台\n */\n static isMacOS(): boolean {\n return process.platform === \"darwin\";\n }\n\n /**\n * 检查是否为 Linux 平台\n */\n static isLinux(): boolean {\n return process.platform === \"linux\";\n }\n\n /**\n * 检查是否为类 Unix 系统\n */\n static isUnixLike(): boolean {\n return !PlatformUtils.isWindows();\n }\n\n /**\n * 检查进程是否为 xiaozhi-client 进程\n */\n static isXiaozhiProcess(pid: number): boolean {\n try {\n // 在容器环境或测试环境中,使用更宽松的检查策略\n if (\n process.env.XIAOZHI_CONTAINER === \"true\" ||\n process.env.NODE_ENV === \"test\"\n ) {\n // 容器环境或测试环境中,如果 PID 存在就认为是有效的\n // 因为容器通常只运行一个主要应用,测试环境中mock了进程检查\n process.kill(pid, 0);\n return true;\n }\n\n // 非容器环境中,尝试更严格的进程检查\n try {\n let cmdline = \"\";\n if (PlatformUtils.isWindows()) {\n // Windows 系统\n const result = execSync(`tasklist /FI \"PID eq ${pid}\" /FO CSV /NH`, {\n encoding: \"utf8\",\n timeout: TIMEOUT_CONSTANTS.PROCESS_STOP,\n });\n cmdline = result.toLowerCase();\n } else {\n // Unix-like 系统\n const result = execSync(`ps -p ${pid} -o comm=`, {\n encoding: \"utf8\",\n timeout: TIMEOUT_CONSTANTS.PROCESS_STOP,\n });\n cmdline = result.toLowerCase();\n }\n\n // 检查是否包含 node 或 xiaozhi 相关关键词\n return cmdline.includes(\"node\") || cmdline.includes(\"xiaozhi\");\n } catch (error) {\n // 如果无法获取进程信息,回退到简单的 PID 检查\n process.kill(pid, 0);\n return true;\n }\n } catch (error) {\n return false;\n }\n }\n\n /**\n * 杀死进程\n */\n static async killProcess(\n pid: number,\n signal: NodeJS.Signals = \"SIGTERM\"\n ): Promise<void> {\n try {\n process.kill(pid, signal);\n\n // 等待进程停止\n let attempts = 0;\n const maxAttempts = 30; // 3秒超时\n\n while (attempts < maxAttempts) {\n await new Promise((resolve) => setTimeout(resolve, 100));\n\n try {\n process.kill(pid, 0);\n attempts++;\n } catch {\n // 进程已停止\n return;\n }\n }\n\n // 如果还在运行,强制停止\n try {\n process.kill(pid, 0);\n process.kill(pid, \"SIGKILL\");\n await new Promise((resolve) => setTimeout(resolve, 500));\n } catch {\n // 进程已停止\n }\n } catch (error) {\n throw new ProcessError(\n `无法终止进程: ${error instanceof Error ? error.message : String(error)}`,\n pid\n );\n }\n }\n\n /**\n * 检查进程是否存在\n */\n static processExists(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n }\n\n /**\n * 获取系统信息\n */\n static getSystemInfo(): {\n platform: Platform;\n arch: string;\n nodeVersion: string;\n isContainer: boolean;\n } {\n return {\n platform: PlatformUtils.getCurrentPlatform(),\n arch: process.arch,\n nodeVersion: process.version,\n isContainer: process.env.XIAOZHI_CONTAINER === \"true\",\n };\n }\n\n /**\n * 获取环境变量\n */\n static getEnvVar(name: string, defaultValue?: string): string | undefined {\n return process.env[name] || defaultValue;\n }\n\n /**\n * 设置环境变量\n */\n static setEnvVar(name: string, value: string): void {\n process.env[name] = value;\n }\n\n /**\n * 检查是否在容器环境中运行\n */\n static isContainerEnvironment(): boolean {\n return process.env.XIAOZHI_CONTAINER === \"true\";\n }\n\n /**\n * 检查是否在测试环境中运行\n */\n static isTestEnvironment(): boolean {\n return process.env.NODE_ENV === \"test\";\n }\n\n /**\n * 检查是否在开发环境中运行\n */\n static isDevelopmentEnvironment(): boolean {\n return process.env.NODE_ENV === \"development\";\n }\n\n /**\n * 获取合适的 tail 命令\n */\n static getTailCommand(filePath: string): { command: string; args: string[] } {\n if (PlatformUtils.isWindows()) {\n return {\n command: \"powershell\",\n args: [\"-Command\", `Get-Content -Path \"${filePath}\" -Wait`],\n };\n }\n return {\n command: \"tail\",\n args: [\"-f\", filePath],\n };\n }\n}\n","/**\n * 输入验证工具\n */\n\nimport type { ConfigFormat } from \"../Types.js\";\nimport { ValidationError } from \"../errors/index.js\";\n\n/**\n * 验证工具类\n */\nexport class Validation {\n /**\n * 验证端口号\n */\n static validatePort(port: number): void {\n if (!Number.isInteger(port) || port < 1 || port > 65535) {\n throw ValidationError.invalidPort(port);\n }\n }\n\n /**\n * 验证配置文件格式\n */\n static validateConfigFormat(format: string): ConfigFormat {\n const validFormats: ConfigFormat[] = [\"json\", \"json5\", \"jsonc\"];\n\n if (!validFormats.includes(format as ConfigFormat)) {\n throw new ValidationError(\n `无效的配置文件格式: ${format},支持的格式: ${validFormats.join(\", \")}`,\n \"format\"\n );\n }\n\n return format as ConfigFormat;\n }\n\n /**\n * 验证必填字段\n */\n static validateRequired(value: any, fieldName: string): void {\n if (value === undefined || value === null || value === \"\") {\n throw ValidationError.requiredField(fieldName);\n }\n }\n\n /**\n * 验证字符串长度\n */\n static validateStringLength(\n value: string,\n fieldName: string,\n options: { min?: number; max?: number } = {}\n ): void {\n if (options.min !== undefined && value.length < options.min) {\n throw new ValidationError(\n `长度不能少于 ${options.min} 个字符,当前长度: ${value.length}`,\n fieldName\n );\n }\n\n if (options.max !== undefined && value.length > options.max) {\n throw new ValidationError(\n `长度不能超过 ${options.max} 个字符,当前长度: ${value.length}`,\n fieldName\n );\n }\n }\n\n /**\n * 验证 URL 格式\n */\n static validateUrl(url: string, fieldName = \"url\"): void {\n try {\n new URL(url);\n } catch {\n throw new ValidationError(`无效的 URL 格式: ${url}`, fieldName);\n }\n }\n\n /**\n * 验证 WebSocket URL 格式\n */\n static validateWebSocketUrl(url: string, fieldName = \"websocket_url\"): void {\n Validation.validateUrl(url, fieldName);\n\n const parsedUrl = new URL(url);\n if (![\"ws:\", \"wss:\"].includes(parsedUrl.protocol)) {\n throw new ValidationError(\n `WebSocket URL 必须使用 ws:// 或 wss:// 协议,当前协议: ${parsedUrl.protocol}`,\n fieldName\n );\n }\n }\n\n /**\n * 验证 HTTP URL 格式\n */\n static validateHttpUrl(url: string, fieldName = \"http_url\"): void {\n Validation.validateUrl(url, fieldName);\n\n const parsedUrl = new URL(url);\n if (![\"http:\", \"https:\"].includes(parsedUrl.protocol)) {\n throw new ValidationError(\n `HTTP URL 必须使用 http:// 或 https:// 协议,当前协议: ${parsedUrl.protocol}`,\n fieldName\n );\n }\n }\n\n /**\n * 验证项目名称\n */\n static validateProjectName(name: string): void {\n Validation.validateRequired(name, \"projectName\");\n Validation.validateStringLength(name, \"projectName\", { min: 1, max: 100 });\n\n // 检查是否包含非法字符\n const invalidChars = /[<>:\"/\\\\|?*]/;\n const hasControlChars = name\n .split(\"\")\n .some((char) => char.charCodeAt(0) < 32);\n\n if (invalidChars.test(name) || hasControlChars) {\n throw new ValidationError(\n '项目名称不能包含以下字符: < > : \" / \\\\ | ? * 以及控制字符',\n \"projectName\"\n );\n }\n\n // 检查是否以点开头\n if (name.startsWith(\".\")) {\n throw new ValidationError(\"项目名称不能以点开头\", \"projectName\");\n }\n }\n\n /**\n * 验证模板名称\n */\n static validateTemplateName(name: string): void {\n Validation.validateRequired(name, \"templateName\");\n Validation.validateStringLength(name, \"templateName\", { min: 1, max: 50 });\n\n // 模板名称只能包含字母、数字、连字符和下划线\n const validPattern = /^[a-zA-Z0-9_-]+$/;\n if (!validPattern.test(name)) {\n throw new ValidationError(\n \"模板名称只能包含字母、数字、连字符和下划线\",\n \"templateName\"\n );\n }\n }\n\n /**\n * 验证环境变量名称\n */\n static validateEnvVarName(name: string): void {\n Validation.validateRequired(name, \"envVarName\");\n\n // 环境变量名称只能包含大写字母、数字和下划线,且不能以数字开头\n const validPattern = /^[A-Z_][A-Z0-9_]*$/;\n if (!validPattern.test(name)) {\n throw new ValidationError(\n \"环境变量名称只能包含大写字母、数字和下划线,且不能以数字开头\",\n \"envVarName\"\n );\n }\n }\n\n /**\n * 验证 JSON 格式\n */\n static validateJson(jsonString: string, fieldName = \"json\"): any {\n try {\n return JSON.parse(jsonString);\n } catch (error) {\n throw new ValidationError(\n `无效的 JSON 格式: ${error instanceof Error ? error.message : String(error)}`,\n fieldName\n );\n }\n }\n\n /**\n * 验证数字范围\n */\n static validateNumberRange(\n value: number,\n fieldName: string,\n options: { min?: number; max?: number } = {}\n ): void {\n if (options.min !== undefined && value < options.min) {\n throw new ValidationError(\n `值不能小于 ${options.min},当前值: ${value}`,\n fieldName\n );\n }\n\n if (options.max !== undefined && value > options.max) {\n throw new ValidationError(\n `值不能大于 ${options.max},当前值: ${value}`,\n fieldName\n );\n }\n }\n\n /**\n * 验证数组长度\n */\n static validateArrayLength(\n array: any[],\n fieldName: string,\n options: { min?: number; max?: number } = {}\n ): void {\n if (options.min !== undefined && array.length < options.min) {\n throw new ValidationError(\n `数组长度不能少于 ${options.min},当前长度: ${array.length}`,\n fieldName\n );\n }\n\n if (options.max !== undefined && array.length > options.max) {\n throw new ValidationError(\n `数组长度不能超过 ${options.max},当前长度: ${array.length}`,\n fieldName\n );\n }\n }\n\n /**\n * 验证对象属性\n */\n static validateObjectProperties(\n obj: Record<string, any>,\n requiredProps: string[],\n fieldName = \"object\"\n ): void {\n for (const prop of requiredProps) {\n if (!(prop in obj)) {\n throw new ValidationError(`缺少必需的属性: ${prop}`, fieldName);\n }\n }\n }\n\n /**\n * 验证枚举值\n */\n static validateEnum<T extends string>(\n value: string,\n validValues: T[],\n fieldName: string\n ): T {\n if (!validValues.includes(value as T)) {\n throw new ValidationError(\n `无效的值: ${value},有效值: ${validValues.join(\", \")}`,\n fieldName\n );\n }\n return value as T;\n }\n\n /**\n * 验证正则表达式\n */\n static validateRegex(pattern: string, fieldName = \"regex\"): RegExp {\n try {\n return new RegExp(pattern);\n } catch (error) {\n throw new ValidationError(\n `无效的正则表达式: ${error instanceof Error ? error.message : String(error)}`,\n fieldName\n );\n }\n }\n}\n","/**\n * 版本管理工具\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { FileError } from \"../errors/index.js\";\n\n/**\n * 版本信息接口\n */\nexport interface VersionInfo {\n version: string;\n name?: string;\n description?: string;\n author?: string;\n}\n\n/**\n * 版本工具类\n */\nexport class VersionUtils {\n private static cachedVersion: string | null = null;\n\n /**\n * 获取版本号\n */\n static getVersion(): string {\n if (VersionUtils.cachedVersion) {\n return VersionUtils.cachedVersion;\n }\n\n try {\n // 在 ES 模块环境中获取当前目录\n const __filename = fileURLToPath(import.meta.url);\n const currentDir = path.dirname(__filename);\n\n // 尝试多个可能的 package.json 路径\n const possiblePaths = [\n // 构建后环境:dist/cli.js -> dist/package.json (优先)\n path.join(currentDir, \"package.json\"),\n // 构建后环境:dist/cli.js -> package.json\n path.join(currentDir, \"..\", \"package.json\"),\n // 开发环境:src/cli/utils/VersionUtils.ts -> package.json\n path.join(currentDir, \"..\", \"..\", \"..\", \"package.json\"),\n // 全局安装环境\n path.join(currentDir, \"..\", \"..\", \"..\", \"..\", \"package.json\"),\n ];\n\n for (const packagePath of possiblePaths) {\n if (fs.existsSync(packagePath)) {\n const packageJson = JSON.parse(fs.readFileSync(packagePath, \"utf8\"));\n if (packageJson.version) {\n VersionUtils.cachedVersion = packageJson.version;\n return packageJson.version;\n }\n }\n }\n\n // 如果都找不到,返回默认版本\n VersionUtils.cachedVersion = \"unknown\";\n return \"unknown\";\n } catch (error) {\n console.warn(\"无法从 package.json 读取版本信息:\", error);\n VersionUtils.cachedVersion = \"unknown\";\n return \"unknown\";\n }\n }\n\n /**\n * 获取完整版本信息\n */\n static getVersionInfo(): VersionInfo {\n try {\n const __filename = fileURLToPath(import.meta.url);\n const currentDir = path.dirname(__filename);\n\n const possiblePaths = [\n // 构建后环境:dist/cli.js -> dist/package.json (优先)\n path.join(currentDir, \"package.json\"),\n // 构建后环境:dist/cli.js -> package.json\n path.join(currentDir, \"..\", \"package.json\"),\n // 开发环境:src/cli/utils/VersionUtils.ts -> package.json\n path.join(currentDir, \"..\", \"..\", \"..\", \"package.json\"),\n // 全局安装环境\n path.join(currentDir, \"..\", \"..\", \"..\", \"..\", \"package.json\"),\n ];\n\n for (const packagePath of possiblePaths) {\n if (fs.existsSync(packagePath)) {\n const packageJson = JSON.parse(fs.readFileSync(packagePath, \"utf8\"));\n return {\n version: packageJson.version || \"unknown\",\n name: packageJson.name,\n description: packageJson.description,\n author: packageJson.author,\n };\n }\n }\n\n return { version: \"unknown\" };\n } catch (error) {\n throw new FileError(\"无法读取版本信息\", \"package.json\");\n }\n }\n\n /**\n * 比较版本号\n */\n static compareVersions(version1: string, version2: string): number {\n const v1Parts = version1.split(\".\").map(Number);\n const v2Parts = version2.split(\".\").map(Number);\n const maxLength = Math.max(v1Parts.length, v2Parts.length);\n\n for (let i = 0; i < maxLength; i++) {\n const v1Part = v1Parts[i] || 0;\n const v2Part = v2Parts[i] || 0;\n\n if (v1Part > v2Part) return 1;\n if (v1Part < v2Part) return -1;\n }\n\n return 0;\n }\n\n /**\n * 检查版本是否有效\n */\n static isValidVersion(version: string): boolean {\n const versionRegex = /^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9.-]+)?$/;\n return versionRegex.test(version);\n }\n\n /**\n * 清除版本缓存\n */\n static clearCache(): void {\n VersionUtils.cachedVersion = null;\n }\n}\n","/**\n * 进程管理服务\n */\n\nimport fs from \"node:fs\";\nimport { SERVICE_CONSTANTS } from \"../Constants.js\";\nimport { FileError, ProcessError } from \"../errors/index.js\";\nimport type {\n ProcessManager as IProcessManager,\n ServiceStatus,\n} from \"../interfaces/Service.js\";\nimport { FileUtils } from \"../utils/FileUtils.js\";\nimport { FormatUtils } from \"../utils/FormatUtils.js\";\nimport { PathUtils } from \"../utils/PathUtils.js\";\nimport { PlatformUtils } from \"../utils/PlatformUtils.js\";\n\n/**\n * PID 文件信息接口\n */\ninterface PidFileInfo {\n pid: number;\n startTime: number;\n mode: \"foreground\" | \"daemon\";\n}\n\n/**\n * 进程管理器实现\n */\nexport class ProcessManagerImpl implements IProcessManager {\n /**\n * 获取 PID 文件路径\n */\n private getPidFilePath(): string {\n return PathUtils.getPidFile();\n }\n\n /**\n * 读取 PID 文件信息\n */\n private readPidFile(): PidFileInfo | null {\n try {\n const pidFilePath = this.getPidFilePath();\n\n if (!FileUtils.exists(pidFilePath)) {\n return null;\n }\n\n const pidContent = FileUtils.readFile(pidFilePath).trim();\n const [pidStr, startTimeStr, mode] = pidContent.split(\"|\");\n\n const pid = Number.parseInt(pidStr);\n const startTime = Number.parseInt(startTimeStr);\n\n if (Number.isNaN(pid) || Number.isNaN(startTime)) {\n // PID 文件损坏,删除它\n this.cleanupPidFile();\n return null;\n }\n\n return {\n pid,\n startTime,\n mode: (mode as \"foreground\" | \"daemon\") || \"foreground\",\n };\n } catch (error) {\n // 读取失败,可能文件损坏\n this.cleanupPidFile();\n return null;\n }\n }\n\n /**\n * 写入 PID 文件信息\n */\n private writePidFile(pid: number, mode: \"foreground\" | \"daemon\"): void {\n try {\n const pidInfo = `${pid}|${Date.now()}|${mode}`;\n const pidFilePath = this.getPidFilePath();\n FileUtils.writeFile(pidFilePath, pidInfo, { overwrite: true });\n } catch (error) {\n throw new FileError(\"无法写入 PID 文件\", this.getPidFilePath());\n }\n }\n\n /**\n * 检查是否为 xiaozhi 进程\n */\n isXiaozhiProcess(pid: number): boolean {\n return PlatformUtils.isXiaozhiProcess(pid);\n }\n\n /**\n * 获取服务状态\n */\n getServiceStatus(): ServiceStatus {\n try {\n const pidInfo = this.readPidFile();\n\n if (!pidInfo) {\n return { running: false };\n }\n\n // 检查进程是否还在运行且是 xiaozhi 进程\n if (!this.isXiaozhiProcess(pidInfo.pid)) {\n // 进程不存在或不是 xiaozhi 进程,删除 PID 文件\n this.cleanupPidFile();\n return { running: false };\n }\n\n // 计算运行时间\n const uptime = FormatUtils.formatUptime(Date.now() - pidInfo.startTime);\n\n return {\n running: true,\n pid: pidInfo.pid,\n uptime,\n mode: pidInfo.mode,\n };\n } catch (error) {\n return { running: false };\n }\n }\n\n /**\n * 保存进程信息\n */\n savePidInfo(pid: number, mode: \"foreground\" | \"daemon\"): void {\n this.writePidFile(pid, mode);\n }\n\n /**\n * 杀死进程\n */\n async killProcess(pid: number): Promise<void> {\n try {\n await PlatformUtils.killProcess(pid);\n } catch (error) {\n throw new ProcessError(\n `无法终止进程: ${error instanceof Error ? error.message : String(error)}`,\n pid\n );\n }\n }\n\n /**\n * 优雅停止进程\n */\n async gracefulKillProcess(pid: number): Promise<void> {\n try {\n // 尝试优雅停止\n process.kill(pid, \"SIGTERM\");\n\n // 等待进程停止\n let attempts = 0;\n const maxAttempts = 30; // 3秒超时\n\n while (attempts < maxAttempts) {\n await new Promise((resolve) => setTimeout(resolve, 100));\n\n try {\n process.kill(pid, 0);\n attempts++;\n } catch {\n // 进程已停止\n return;\n }\n }\n\n // 如果还在运行,强制停止\n try {\n process.kill(pid, 0);\n process.kill(pid, \"SIGKILL\");\n await new Promise((resolve) => setTimeout(resolve, 500));\n } catch {\n // 进程已停止\n }\n } catch (error) {\n throw new ProcessError(\n `无法停止进程: ${error instanceof Error ? error.message : String(error)}`,\n pid\n );\n }\n }\n\n /**\n * 清理 PID 文件\n */\n cleanupPidFile(): void {\n try {\n const pidFilePath = this.getPidFilePath();\n if (FileUtils.exists(pidFilePath)) {\n FileUtils.deleteFile(pidFilePath);\n }\n } catch (error) {\n // 忽略清理错误,但可以记录日志\n console.warn(\"清理 PID 文件失败:\", error);\n }\n }\n\n /**\n * 检查进程是否存在\n */\n processExists(pid: number): boolean {\n return PlatformUtils.processExists(pid);\n }\n\n /**\n * 清理容器环境的旧状态\n */\n cleanupContainerState(): void {\n if (PlatformUtils.isContainerEnvironment()) {\n try {\n this.cleanupPidFile();\n } catch (error) {\n // 忽略清理错误\n }\n }\n }\n\n /**\n * 获取进程信息\n */\n getProcessInfo(pid: number): { exists: boolean; isXiaozhi: boolean } {\n const exists = this.processExists(pid);\n const isXiaozhi = exists ? this.isXiaozhiProcess(pid) : false;\n\n return { exists, isXiaozhi };\n }\n\n /**\n * 验证 PID 文件完整性\n */\n validatePidFile(): boolean {\n try {\n const pidInfo = this.readPidFile();\n return pidInfo !== null;\n } catch {\n return false;\n }\n }\n}\n","/**\n * 守护进程管理服务\n */\n\nimport { type ChildProcess, spawn } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport { ProcessError, ServiceError } from \"../errors/index.js\";\nimport type {\n DaemonManager as IDaemonManager,\n ProcessManager,\n} from \"../interfaces/Service.js\";\nimport { PathUtils } from \"../utils/PathUtils.js\";\nimport { PlatformUtils } from \"../utils/PlatformUtils.js\";\n\n/**\n * 守护进程选项\n */\nexport interface DaemonOptions {\n /** 日志文件名 */\n logFileName?: string;\n /** 环境变量 */\n env?: Record<string, string>;\n /** 是否打开浏览器 */\n openBrowser?: boolean;\n /** 工作目录 */\n cwd?: string;\n}\n\n/**\n * 守护进程管理器实现\n */\nexport class DaemonManagerImpl implements IDaemonManager {\n private currentDaemon: ChildProcess | null = null;\n\n constructor(\n private processManager: ProcessManager,\n private logger: any\n ) {}\n\n /**\n * 启动守护进程\n */\n async startDaemon(\n serverFactory: () => Promise<any>,\n options: DaemonOptions = {}\n ): Promise<void> {\n try {\n // 检查是否已有守护进程在运行\n const status = this.processManager.getServiceStatus();\n if (status.running) {\n throw ServiceError.alreadyRunning(status.pid!);\n }\n\n // 启动守护进程\n const child = await this.spawnDaemonProcess(serverFactory, options);\n this.currentDaemon = child;\n\n // 保存 PID 信息\n this.processManager.savePidInfo(child.pid!, \"daemon\");\n\n // 设置日志重定向\n await this.setupLogging(child, options.logFileName || \"xiaozhi.log\");\n\n // 设置进程事件监听\n this.setupEventHandlers(child);\n\n // 分离进程\n child.unref();\n\n this.logger.info(`守护进程已启动 (PID: ${child.pid})`);\n } catch (error) {\n throw new ServiceError(\n `启动守护进程失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * 停止守护进程\n */\n async stopDaemon(): Promise<void> {\n try {\n const status = this.processManager.getServiceStatus();\n\n if (!status.running) {\n throw ServiceError.notRunning();\n }\n\n // 优雅停止守护进程\n await this.processManager.gracefulKillProcess(status.pid!);\n\n // 清理 PID 文件\n this.processManager.cleanupPidFile();\n\n // 清理当前守护进程引用\n this.currentDaemon = null;\n\n this.logger.info(\"守护进程已停止\");\n } catch (error) {\n throw new ServiceError(\n `停止守护进程失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * 重启守护进程\n */\n async restartDaemon(\n serverFactory: () => Promise<any>,\n options: DaemonOptions = {}\n ): Promise<void> {\n try {\n // 先停止现有守护进程\n const status = this.processManager.getServiceStatus();\n if (status.running) {\n await this.stopDaemon();\n // 等待一下确保完全停止\n await new Promise((resolve) => setTimeout(resolve, 1000));\n }\n\n // 重新启动守护进程\n await this.startDaemon(serverFactory, options);\n } catch (error) {\n throw new ServiceError(\n `重启守护进程失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * 获取守护进程状态\n */\n getDaemonStatus(): { running: boolean; pid?: number; uptime?: string } {\n return this.processManager.getServiceStatus();\n }\n\n /**\n * 连接到守护进程日志\n */\n async attachToLogs(logFileName = \"xiaozhi.log\"): Promise<void> {\n try {\n const logFilePath = PathUtils.getLogFile();\n\n if (!fs.existsSync(logFilePath)) {\n throw new ServiceError(\"日志文件不存在\");\n }\n\n // 使用平台相关的 tail 命令\n const { command, args } = PlatformUtils.getTailCommand(logFilePath);\n const tail = spawn(command, args, { stdio: \"inherit\" });\n\n // 处理中断信号\n process.on(\"SIGINT\", () => {\n console.log(\"\\n断开连接,服务继续在后台运行\");\n tail.kill();\n process.exit(0);\n });\n\n tail.on(\"exit\", () => {\n process.exit(0);\n });\n\n tail.on(\"error\", (error) => {\n throw new ServiceError(`连接日志失败: ${error.message}`);\n });\n } catch (error) {\n throw new ServiceError(\n `连接日志失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * 生成守护进程\n */\n private async spawnDaemonProcess(\n serverFactory: () => Promise<any>,\n options: DaemonOptions\n ): Promise<ChildProcess> {\n // 获取启动脚本路径\n const scriptPath = PathUtils.getWebServerStandalonePath();\n\n // 构建启动参数\n const args = [scriptPath];\n if (options.openBrowser) {\n args.push(\"--open-browser\");\n }\n\n // 构建环境变量\n const env = {\n ...process.env,\n XIAOZHI_CONFIG_DIR: PathUtils.getConfigDir(),\n XIAOZHI_DAEMON: \"true\",\n ...options.env,\n };\n\n // 启动子进程\n const child = spawn(\"node\", args, {\n detached: true,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n env,\n cwd: options.cwd || process.cwd(),\n });\n\n if (!child.pid) {\n throw new ProcessError(\"无法启动守护进程\", 0);\n }\n\n return child;\n }\n\n /**\n * 设置日志重定向\n */\n private async setupLogging(\n child: ChildProcess,\n logFileName: string\n ): Promise<void> {\n try {\n const logFilePath = PathUtils.getLogFile();\n\n // 确保日志目录存在\n const path = await import(\"node:path\");\n const logDir = path.dirname(logFilePath);\n if (!fs.existsSync(logDir)) {\n fs.mkdirSync(logDir, { recursive: true });\n }\n\n // 创建日志流\n const logStream = fs.createWriteStream(logFilePath, { flags: \"a\" });\n\n // 重定向标准输出和错误输出\n child.stdout?.pipe(logStream);\n child.stderr?.pipe(logStream);\n\n // 写入启动日志\n const timestamp = new Date().toISOString();\n logStream.write(`\\n[${timestamp}] 守护进程启动 (PID: ${child.pid})\\n`);\n } catch (error) {\n this.logger.warn(\n `设置日志重定向失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * 设置事件处理器\n */\n private setupEventHandlers(child: ChildProcess): void {\n // 监听进程退出\n child.on(\"exit\", (code, signal) => {\n if (code !== 0 && code !== null) {\n this.logger.error(`守护进程异常退出 (代码: ${code}, 信号: ${signal})`);\n } else {\n this.logger.info(\"守护进程正常退出\");\n }\n\n // 清理 PID 文件\n this.processManager.cleanupPidFile();\n this.currentDaemon = null;\n });\n\n // 监听进程错误\n child.on(\"error\", (error) => {\n this.logger.error(`守护进程错误: ${error.message}`);\n this.processManager.cleanupPidFile();\n this.currentDaemon = null;\n });\n\n // 监听进程断开连接\n child.on(\"disconnect\", () => {\n this.logger.info(\"守护进程断开连接\");\n });\n }\n\n /**\n * 检查守护进程健康状态\n */\n async checkHealth(): Promise<boolean> {\n try {\n const status = this.getDaemonStatus();\n\n if (!status.running || !status.pid) {\n return false;\n }\n\n // 检查进程是否真的在运行\n const processInfo = this.processManager.getProcessInfo(status.pid);\n return processInfo.exists && processInfo.isXiaozhi;\n } catch {\n return false;\n }\n }\n\n /**\n * 获取当前守护进程引用\n */\n getCurrentDaemon(): ChildProcess | null {\n return this.currentDaemon;\n }\n\n /**\n * 清理守护进程资源\n */\n cleanup(): void {\n if (this.currentDaemon) {\n try {\n this.currentDaemon.kill(\"SIGTERM\");\n } catch (error) {\n this.logger.warn(\n `清理守护进程失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n this.currentDaemon = null;\n }\n }\n}\n","/**\n * 传输适配器抽象基类\n * 定义了所有传输协议的统一接口,支持 stdio、SSE、HTTP、WebSocket 等多种传输方式\n * 这是阶段二重构的核心组件,用于抽象不同的传输层实现\n */\n\nimport { type Logger, logger } from \"../Logger.js\";\nimport type { MCPMessageHandler } from \"../core/MCPMessageHandler.js\";\n\n// MCP 消息接口\nexport interface MCPMessage {\n jsonrpc: \"2.0\";\n method: string;\n params?: any;\n id?: string | number;\n}\n\n// MCP 响应接口\nexport interface MCPResponse {\n jsonrpc: \"2.0\";\n result?: any;\n error?: MCPError;\n id: string | number | null;\n}\n\n// MCP 错误接口\nexport interface MCPError {\n code: number;\n message: string;\n data?: any;\n}\n\n// 连接状态枚举\nexport enum ConnectionState {\n DISCONNECTED = \"disconnected\",\n CONNECTING = \"connecting\",\n CONNECTED = \"connected\",\n ERROR = \"error\",\n}\n\n// 传输适配器配置接口\nexport interface TransportConfig {\n name: string;\n timeout?: number;\n retryAttempts?: number;\n retryDelay?: number;\n}\n\n/**\n * 传输适配器抽象基类\n * 所有具体的传输适配器都必须继承此类并实现抽象方法\n */\nexport abstract class TransportAdapter {\n protected logger: Logger;\n protected messageHandler: MCPMessageHandler;\n protected connectionId: string;\n protected config: TransportConfig;\n protected state: ConnectionState = ConnectionState.DISCONNECTED;\n\n constructor(messageHandler: MCPMessageHandler, config: TransportConfig) {\n this.messageHandler = messageHandler;\n this.config = config;\n this.connectionId = this.generateConnectionId();\n this.logger = logger;\n }\n\n /**\n * 初始化传输适配器\n * 子类应该在此方法中进行必要的初始化工作\n */\n abstract initialize(): Promise<void>;\n\n /**\n * 启动传输适配器\n * 子类应该在此方法中启动监听或连接\n */\n abstract start(): Promise<void>;\n\n /**\n * 停止传输适配器\n * 子类应该在此方法中清理资源和关闭连接\n */\n abstract stop(): Promise<void>;\n\n /**\n * 发送消息\n * 子类应该实现具体的消息发送逻辑\n */\n abstract sendMessage(message: MCPMessage | MCPResponse): Promise<void>;\n\n /**\n * 处理接收到的消息\n * 这是一个通用的消息处理方法,子类可以直接使用\n */\n protected async handleIncomingMessage(message: MCPMessage): Promise<void> {\n try {\n this.logger.debug(`处理接收到的消息: ${message.method}`, message);\n\n const response = await this.messageHandler.handleMessage(message);\n\n this.logger.debug(\"发送响应消息:\", response);\n await this.sendMessage(response);\n } catch (error) {\n this.logger.error(`处理消息时出错: ${message.method}`, error);\n\n const errorResponse = this.createErrorResponse(\n error as Error,\n message.id\n );\n await this.sendMessage(errorResponse);\n }\n }\n\n /**\n * 创建错误响应\n * 统一的错误响应创建方法\n */\n protected createErrorResponse(\n error: Error,\n id?: string | number\n ): MCPResponse {\n // 根据错误类型确定错误代码\n let errorCode = -32603; // Internal error\n\n if (\n error.message.includes(\"未找到工具\") ||\n error.message.includes(\"未知的方法\")\n ) {\n errorCode = -32601; // Method not found\n } else if (\n error.message.includes(\"参数\") ||\n error.message.includes(\"不能为空\")\n ) {\n errorCode = -32602; // Invalid params\n }\n\n return {\n jsonrpc: \"2.0\",\n error: {\n code: errorCode,\n message: error.message,\n data: {\n stack: error.stack,\n },\n },\n id: id || null,\n };\n }\n\n /**\n * 生成唯一的连接ID\n */\n private generateConnectionId(): string {\n const timestamp = Date.now();\n const random = Math.random().toString(36).substr(2, 9);\n return `${this.config.name}_${timestamp}_${random}`;\n }\n\n /**\n * 获取连接ID\n */\n getConnectionId(): string {\n return this.connectionId;\n }\n\n /**\n * 获取连接状态\n */\n getState(): ConnectionState {\n return this.state;\n }\n\n /**\n * 设置连接状态\n */\n protected setState(state: ConnectionState): void {\n const oldState = this.state;\n this.state = state;\n\n if (oldState !== state) {\n this.logger.info(`连接状态变更: ${oldState} -> ${state}`);\n this.onStateChange(oldState, state);\n }\n }\n\n /**\n * 状态变更回调\n * 子类可以重写此方法来处理状态变更事件\n */\n protected onStateChange(\n oldState: ConnectionState,\n newState: ConnectionState\n ): void {\n // 默认实现为空,子类可以重写\n }\n\n /**\n * 获取配置\n */\n getConfig(): TransportConfig {\n return { ...this.config };\n }\n\n /**\n * 获取消息处理器\n */\n getMessageHandler(): MCPMessageHandler {\n return this.messageHandler;\n }\n\n /**\n * 解析 JSON 消息\n * 统一的 JSON 解析方法,包含错误处理\n */\n protected parseMessage(data: string): MCPMessage | null {\n try {\n const message = JSON.parse(data.trim());\n\n // 验证基本的 JSON-RPC 格式\n if (!message.jsonrpc || message.jsonrpc !== \"2.0\") {\n this.logger.warn(\"收到非 JSON-RPC 2.0 格式的消息\", message);\n return null;\n }\n\n if (!message.method) {\n this.logger.warn(\"收到没有 method 字段的消息\", message);\n return null;\n }\n\n return message;\n } catch (error) {\n this.logger.error(\"解析 JSON 消息失败\", { data, error });\n return null;\n }\n }\n\n /**\n * 序列化消息\n * 统一的消息序列化方法\n */\n protected serializeMessage(message: MCPMessage | MCPResponse): string {\n try {\n return JSON.stringify(message);\n } catch (error) {\n this.logger.error(\"序列化消息失败\", { message, error });\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n throw new Error(`消息序列化失败: ${errorMessage}`);\n }\n }\n\n /**\n * 验证消息格式\n * 验证消息是否符合 MCP 协议规范\n */\n protected validateMessage(message: any): boolean {\n if (!message || typeof message !== \"object\") {\n return false;\n }\n\n if (message.jsonrpc !== \"2.0\") {\n return false;\n }\n\n // 请求消息必须有 method 字段\n if (message.method && typeof message.method !== \"string\") {\n return false;\n }\n\n // 响应消息必须有 result 或 error 字段\n if (!message.method && !message.result && !message.error) {\n return false;\n }\n\n return true;\n }\n\n /**\n * 处理超时\n * 统一的超时处理方法\n */\n protected createTimeoutPromise<T>(\n promise: Promise<T>,\n timeoutMs: number\n ): Promise<T> {\n return Promise.race([\n promise,\n new Promise<T>((_, reject) => {\n setTimeout(() => {\n reject(new Error(`操作超时: ${timeoutMs}ms`));\n }, timeoutMs);\n }),\n ]);\n }\n}\n","/**\n * HTTP 传输适配器\n * 处理 HTTP 和 SSE (Server-Sent Events) 的 MCP 通信\n * 从 mcpServer.ts 中抽取的 HTTP/SSE 处理逻辑\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport type { Server } from \"node:http\";\nimport express from \"express\";\nimport type { Request, Response } from \"express\";\nimport type { MCPMessageHandler } from \"../core/MCPMessageHandler.js\";\nimport { ConnectionState, TransportAdapter } from \"./TransportAdapter.js\";\nimport type {\n MCPMessage,\n MCPResponse,\n TransportConfig,\n} from \"./TransportAdapter.js\";\n\n/**\n * SSE 客户端接口\n */\ninterface SSEClient {\n id: string;\n sessionId: string;\n response: Response;\n connectedAt: Date;\n}\n\n/**\n * HTTP 适配器配置\n */\nexport interface HTTPConfig extends TransportConfig {\n port?: number;\n host?: string;\n enableSSE?: boolean;\n enableRPC?: boolean;\n corsOrigin?: string;\n maxClients?: number;\n}\n\n/**\n * HTTP 传输适配器实现\n * 支持直接 HTTP RPC 调用和 SSE 流式通信\n */\nexport class HTTPAdapter extends TransportAdapter {\n private app: express.Application;\n private server: Server | null = null;\n private clients: Map<string, SSEClient> = new Map();\n private port: number;\n private host: string;\n private enableSSE: boolean;\n private enableRPC: boolean;\n private corsOrigin: string;\n private maxClients: number;\n\n constructor(\n messageHandler: MCPMessageHandler,\n config: HTTPConfig = { name: \"http\" }\n ) {\n super(messageHandler, config);\n\n this.port = config.port || 3000;\n this.host = config.host || \"0.0.0.0\";\n this.enableSSE = config.enableSSE !== false; // 默认启用\n this.enableRPC = config.enableRPC !== false; // 默认启用\n this.corsOrigin = config.corsOrigin || \"*\";\n this.maxClients = config.maxClients !== undefined ? config.maxClients : 100;\n\n this.app = express();\n this.setupMiddleware();\n }\n\n /**\n * 初始化 HTTP 适配器\n */\n async initialize(): Promise<void> {\n this.logger.info(\"初始化 HTTP 适配器\");\n\n try {\n this.setupRoutes();\n this.setState(ConnectionState.CONNECTING);\n this.logger.info(\"HTTP 适配器初始化完成\");\n } catch (error) {\n this.logger.error(\"HTTP 适配器初始化失败\", error);\n this.setState(ConnectionState.ERROR);\n throw error;\n }\n }\n\n /**\n * 启动 HTTP 服务器\n */\n async start(): Promise<void> {\n if (this.server) {\n this.logger.warn(\"HTTP 服务器已在运行\");\n return;\n }\n\n this.logger.info(`启动 HTTP 服务器在 ${this.host}:${this.port}`);\n\n return new Promise((resolve, reject) => {\n this.server = this.app.listen(this.port, this.host, () => {\n this.setState(ConnectionState.CONNECTED);\n this.logger.info(\"HTTP 适配器启动成功\");\n this.logger.info(`- RPC 端点: http://${this.host}:${this.port}/rpc`);\n if (this.enableSSE) {\n this.logger.info(`- SSE 端点: http://${this.host}:${this.port}/sse`);\n this.logger.info(\n `- 消息端点: http://${this.host}:${this.port}/messages`\n );\n }\n resolve();\n });\n\n this.server?.on(\"error\", (error) => {\n this.logger.error(\"HTTP 服务器错误\", error);\n this.setState(ConnectionState.ERROR);\n reject(error);\n });\n });\n }\n\n /**\n * 停止 HTTP 服务器\n */\n async stop(): Promise<void> {\n if (!this.server) {\n return;\n }\n\n this.logger.info(\"停止 HTTP 服务器\");\n\n return new Promise((resolve) => {\n // 关闭所有 SSE 连接\n for (const client of this.clients.values()) {\n client.response.end();\n }\n this.clients.clear();\n\n this.server!.close(() => {\n this.server = null;\n this.setState(ConnectionState.DISCONNECTED);\n this.logger.info(\"HTTP 服务器已停止\");\n resolve();\n });\n });\n }\n\n /**\n * 发送消息(对于 HTTP 适配器,这个方法主要用于 SSE)\n */\n async sendMessage(message: MCPMessage | MCPResponse): Promise<void> {\n // HTTP 适配器的消息发送主要通过 HTTP 响应或 SSE 推送\n // 这里实现 SSE 广播功能\n if (this.clients.size > 0) {\n this.broadcastToClients(message);\n }\n }\n\n /**\n * 设置中间件\n */\n private setupMiddleware(): void {\n // 解析 JSON 请求体\n this.app.use(express.json({ limit: \"10mb\" }));\n this.app.use(express.urlencoded({ extended: true }));\n\n // 设置 CORS\n this.app.use((req, res, next) => {\n res.header(\"Access-Control-Allow-Origin\", this.corsOrigin);\n res.header(\"Access-Control-Allow-Methods\", \"GET, POST, OPTIONS\");\n res.header(\"Access-Control-Allow-Headers\", \"Content-Type, Accept\");\n res.header(\"Cache-Control\", \"no-cache\");\n next();\n });\n\n // 请求日志\n this.app.use((req, res, next) => {\n this.logger.debug(`${req.method} ${req.path}`, {\n query: req.query,\n headers: req.headers,\n });\n next();\n });\n }\n\n /**\n * 设置路由\n */\n private setupRoutes(): void {\n // SSE 端点\n if (this.enableSSE) {\n this.app.get(\"/sse\", this.handleSSE.bind(this));\n this.app.post(\"/messages\", this.handleMessages.bind(this));\n }\n\n // RPC 端点\n if (this.enableRPC) {\n this.app.post(\"/rpc\", this.handleRPC.bind(this));\n }\n\n // 状态端点\n this.app.get(\"/status\", this.handleStatus.bind(this));\n\n // 健康检查端点\n this.app.get(\"/health\", this.handleHealth.bind(this));\n }\n\n /**\n * 处理 SSE 连接\n */\n private handleSSE(req: Request, res: Response): void {\n // 检查客户端数量限制\n if (this.clients.size >= this.maxClients) {\n res.status(503).json({\n error: \"服务器繁忙,客户端连接数已达上限\",\n maxClients: this.maxClients,\n });\n return;\n }\n\n const clientId = Date.now().toString();\n const sessionId = randomUUID();\n\n // 设置 SSE 头部\n res.setHeader(\"Content-Type\", \"text/event-stream\");\n res.setHeader(\"Cache-Control\", \"no-cache, no-transform\");\n res.setHeader(\"Connection\", \"keep-alive\");\n res.setHeader(\"X-Accel-Buffering\", \"no\");\n\n // 注册客户端\n const client: SSEClient = {\n id: clientId,\n sessionId,\n response: res,\n connectedAt: new Date(),\n };\n\n this.clients.set(sessionId, client);\n this.logger.info(`SSE 客户端已连接: ${clientId} (会话: ${sessionId})`);\n\n // 发送端点事件(MCP SDK 标准)\n res.write(`event: endpoint\\ndata: /messages?sessionId=${sessionId}\\n\\n`);\n\n // 处理客户端断开连接\n req.on(\"close\", () => {\n this.clients.delete(sessionId);\n this.logger.info(\n `SSE 客户端已断开连接: ${clientId} (会话: ${sessionId})`\n );\n });\n\n // 处理连接错误\n req.on(\"error\", (error) => {\n this.logger.error(`SSE 客户端连接错误: ${clientId}`, error);\n this.clients.delete(sessionId);\n });\n }\n\n /**\n * 处理 SSE 消息\n */\n private async handleMessages(req: Request, res: Response): Promise<void> {\n try {\n const sessionId = req.query.sessionId as string;\n const message = req.body;\n\n this.logger.debug(`收到 SSE 消息 (会话: ${sessionId}):`, message);\n\n if (!sessionId || !this.clients.has(sessionId)) {\n res.status(400).json({\n jsonrpc: \"2.0\",\n error: {\n code: -32600,\n message: \"无效或缺少 sessionId\",\n },\n id: message.id,\n });\n return;\n }\n\n // 处理消息\n const response = await this.messageHandler.handleMessage(message);\n this.logger.debug(\"SSE 消息处理响应:\", response);\n\n // 通过 SSE 发送响应\n const client = this.clients.get(sessionId);\n if (client) {\n this.sendToClient(client, response);\n }\n\n // 发送 202 Accepted 确认\n res.status(202).send();\n } catch (error) {\n this.logger.error(\"处理 SSE 消息时出错\", error);\n res.status(500).json({\n jsonrpc: \"2.0\",\n error: {\n code: -32603,\n message: (error as Error).message,\n },\n });\n }\n }\n\n /**\n * 处理 RPC 请求\n */\n private async handleRPC(req: Request, res: Response): Promise<void> {\n try {\n const message = req.body;\n this.logger.debug(\"收到 RPC 消息:\", message);\n\n // 处理消息\n const response = await this.messageHandler.handleMessage(message);\n res.json(response);\n } catch (error) {\n this.logger.error(\"处理 RPC 消息时出错\", error);\n res.status(500).json({\n jsonrpc: \"2.0\",\n error: {\n code: -32603,\n message: (error as Error).message,\n },\n id: req.body?.id || null,\n });\n }\n }\n\n /**\n * 处理状态请求\n */\n private handleStatus(req: Request, res: Response): void {\n res.json({\n status: \"ok\",\n mode: \"mcp-server\", // 从用户角度看,这是 MCP 服务器的状态\n serviceManager: \"running\", // 添加服务管理器状态\n clients: this.clients.size,\n tools: 0, // 工具数量,这里先设为0,后续可以从消息处理器获取\n maxClients: this.maxClients,\n enableSSE: this.enableSSE,\n enableRPC: this.enableRPC,\n uptime: process.uptime(),\n });\n }\n\n /**\n * 处理健康检查\n */\n private handleHealth(req: Request, res: Response): void {\n res.json({\n status: \"ok\",\n mode: \"mcp-server\", // 从用户角度看,这是 MCP 服务器的健康状态\n timestamp: new Date().toISOString(),\n });\n }\n\n /**\n * 向特定客户端发送消息\n */\n private sendToClient(\n client: SSEClient,\n message: MCPMessage | MCPResponse\n ): void {\n try {\n const data = this.serializeMessage(message);\n client.response.write(`data: ${data}\\n\\n`);\n\n this.logger.debug(`消息已发送到客户端 ${client.id}`, {\n sessionId: client.sessionId,\n messageId: message.id,\n });\n } catch (error) {\n this.logger.error(`向客户端 ${client.id} 发送消息失败`, error);\n // 移除有问题的客户端\n this.clients.delete(client.sessionId);\n }\n }\n\n /**\n * 广播消息到所有客户端\n */\n private broadcastToClients(message: MCPMessage | MCPResponse): void {\n for (const client of this.clients.values()) {\n this.sendToClient(client, message);\n }\n }\n\n /**\n * 获取适配器状态\n */\n getStatus(): {\n isRunning: boolean;\n port: number;\n host: string;\n clientCount: number;\n maxClients: number;\n enableSSE: boolean;\n enableRPC: boolean;\n connectionId: string;\n state: ConnectionState;\n } {\n return {\n isRunning: this.server !== null,\n port: this.port,\n host: this.host,\n clientCount: this.clients.size,\n maxClients: this.maxClients,\n enableSSE: this.enableSSE,\n enableRPC: this.enableRPC,\n connectionId: this.connectionId,\n state: this.state,\n };\n }\n\n /**\n * 获取连接的客户端列表\n */\n getClients(): Array<{\n id: string;\n sessionId: string;\n connectedAt: Date;\n }> {\n return Array.from(this.clients.values()).map((client) => ({\n id: client.id,\n sessionId: client.sessionId,\n connectedAt: client.connectedAt,\n }));\n }\n}\n","/**\n * Stdio 传输适配器\n * 处理通过标准输入输出进行的 MCP 通信,主要用于 Cursor 等客户端\n * 从 mcpServerProxy.ts 中抽取的 stdio 处理逻辑\n */\n\nimport type { MCPMessageHandler } from \"../core/MCPMessageHandler.js\";\nimport { ConnectionState, TransportAdapter } from \"./TransportAdapter.js\";\nimport type {\n MCPMessage,\n MCPResponse,\n TransportConfig,\n} from \"./TransportAdapter.js\";\n\n/**\n * Stdio 适配器配置\n */\nexport interface StdioConfig extends TransportConfig {\n encoding?: BufferEncoding;\n bufferSize?: number;\n}\n\n/**\n * Stdio 传输适配器实现\n * 处理标准输入输出的 JSON-RPC 消息通信\n */\nexport class StdioAdapter extends TransportAdapter {\n private messageBuffer = \"\";\n private isRunning = false;\n private encoding: BufferEncoding;\n private bufferSize: number;\n\n constructor(\n messageHandler: MCPMessageHandler,\n config: StdioConfig = { name: \"stdio\" }\n ) {\n super(messageHandler, config);\n this.encoding = config.encoding || \"utf8\";\n this.bufferSize = config.bufferSize || 1024 * 1024; // 1MB default buffer\n }\n\n /**\n * 初始化 Stdio 适配器\n */\n async initialize(): Promise<void> {\n this.logger.info(\"初始化 Stdio 适配器\");\n\n try {\n // 设置标准输入编码\n process.stdin.setEncoding(this.encoding);\n\n // 设置进程退出处理\n this.setupProcessHandlers();\n\n this.setState(ConnectionState.CONNECTING);\n this.logger.info(\"Stdio 适配器初始化完成\");\n } catch (error) {\n this.logger.error(\"Stdio 适配器初始化失败\", error);\n this.setState(ConnectionState.ERROR);\n throw error;\n }\n }\n\n /**\n * 启动 Stdio 适配器\n */\n async start(): Promise<void> {\n if (this.isRunning) {\n this.logger.warn(\"Stdio 适配器已在运行\");\n return;\n }\n\n this.logger.info(\"启动 Stdio 适配器\");\n\n try {\n this.isRunning = true;\n this.setupStdioHandlers();\n this.setState(ConnectionState.CONNECTED);\n\n this.logger.info(\"Stdio 适配器启动成功,等待消息...\");\n } catch (error) {\n this.logger.error(\"启动 Stdio 适配器失败\", error);\n this.setState(ConnectionState.ERROR);\n this.isRunning = false;\n throw error;\n }\n }\n\n /**\n * 停止 Stdio 适配器\n */\n async stop(): Promise<void> {\n if (!this.isRunning) {\n return;\n }\n\n this.logger.info(\"停止 Stdio 适配器\");\n\n try {\n this.isRunning = false;\n this.removeStdioHandlers();\n this.setState(ConnectionState.DISCONNECTED);\n\n this.logger.info(\"Stdio 适配器已停止\");\n } catch (error) {\n this.logger.error(\"停止 Stdio 适配器时出错\", error);\n throw error;\n }\n }\n\n /**\n * 发送消息到标准输出\n */\n async sendMessage(message: MCPMessage | MCPResponse): Promise<void> {\n try {\n const serializedMessage = this.serializeMessage(message);\n\n // 写入到标准输出,添加换行符\n process.stdout.write(`${serializedMessage}\\n`);\n\n this.logger.debug(\"消息已发送到 stdout\", {\n messageId: message.id,\n method: \"method\" in message ? message.method : \"response\",\n });\n } catch (error) {\n this.logger.error(\"发送消息失败\", error);\n throw error;\n }\n }\n\n /**\n * 设置标准输入输出处理器\n */\n private setupStdioHandlers(): void {\n // 处理标准输入数据\n process.stdin.on(\"data\", this.handleStdinData.bind(this));\n\n // 处理标准输入结束\n process.stdin.on(\"end\", this.handleStdinEnd.bind(this));\n\n // 处理标准输入错误\n process.stdin.on(\"error\", this.handleStdinError.bind(this));\n }\n\n /**\n * 移除标准输入输出处理器\n */\n private removeStdioHandlers(): void {\n process.stdin.removeListener(\"data\", this.handleStdinData.bind(this));\n process.stdin.removeListener(\"end\", this.handleStdinEnd.bind(this));\n process.stdin.removeListener(\"error\", this.handleStdinError.bind(this));\n }\n\n /**\n * 处理标准输入数据\n */\n private async handleStdinData(data: Buffer | string): Promise<void> {\n try {\n // 将数据添加到缓冲区\n this.messageBuffer += data.toString();\n\n // 检查缓冲区大小\n if (this.messageBuffer.length > this.bufferSize) {\n this.logger.warn(\n `消息缓冲区超过限制 (${this.bufferSize} bytes),清空缓冲区`\n );\n this.messageBuffer = \"\";\n return;\n }\n\n // 按换行符分割消息\n const lines = this.messageBuffer.split(\"\\n\");\n\n // 保留最后一个不完整的行在缓冲区中\n this.messageBuffer = lines.pop() || \"\";\n\n // 处理完整的消息行\n for (const line of lines) {\n const trimmedLine = line.trim();\n if (trimmedLine) {\n await this.processMessageLine(trimmedLine);\n }\n }\n } catch (error) {\n this.logger.error(\"处理 stdin 数据时出错\", error);\n }\n }\n\n /**\n * 处理单行消息\n */\n private async processMessageLine(line: string): Promise<void> {\n try {\n this.logger.debug(`处理消息行: ${line.substring(0, 200)}...`);\n\n const message = this.parseMessage(line);\n if (message) {\n await this.handleIncomingMessage(message);\n }\n } catch (error) {\n this.logger.error(`处理消息行失败: ${line.substring(0, 100)}...`, error);\n\n // 发送错误响应\n const errorResponse: MCPResponse = {\n jsonrpc: \"2.0\",\n error: {\n code: -32700,\n message: \"解析错误\",\n data: { originalLine: line.substring(0, 100) },\n },\n id: null,\n };\n\n await this.sendMessage(errorResponse);\n }\n }\n\n /**\n * 处理标准输入结束\n */\n private handleStdinEnd(): void {\n this.logger.info(\"标准输入已关闭,停止适配器\");\n this.stop().catch((error) => {\n this.logger.error(\"停止适配器时出错\", error);\n });\n }\n\n /**\n * 处理标准输入错误\n */\n private handleStdinError(error: Error): void {\n this.logger.error(\"标准输入错误\", error);\n this.setState(ConnectionState.ERROR);\n }\n\n /**\n * 设置进程处理器\n */\n private setupProcessHandlers(): void {\n // 处理进程退出信号\n const handleExit = () => {\n this.logger.info(\"收到退出信号,清理资源\");\n this.stop().finally(() => {\n process.exit(0);\n });\n };\n\n process.on(\"SIGINT\", handleExit);\n process.on(\"SIGTERM\", handleExit);\n\n // 处理未捕获的异常\n process.on(\"uncaughtException\", (error) => {\n this.logger.error(\"未捕获的异常\", error);\n this.setState(ConnectionState.ERROR);\n });\n\n // 处理未处理的 Promise 拒绝\n process.on(\"unhandledRejection\", (reason, promise) => {\n this.logger.error(\"未处理的 Promise 拒绝\", { reason, promise });\n });\n }\n\n /**\n * 获取适配器状态信息\n */\n getStatus(): {\n isRunning: boolean;\n bufferSize: number;\n encoding: string;\n connectionId: string;\n state: ConnectionState;\n } {\n return {\n isRunning: this.isRunning,\n bufferSize: this.messageBuffer.length,\n encoding: this.encoding,\n connectionId: this.connectionId,\n state: this.state,\n };\n }\n\n /**\n * 清空消息缓冲区\n */\n clearBuffer(): void {\n this.messageBuffer = \"\";\n this.logger.debug(\"消息缓冲区已清空\");\n }\n}\n","/**\n * WebSocket 传输适配器\n * 阶段四重构:支持 WebSocket 双向通信和自动重连\n *\n * 主要功能:\n * 1. WebSocket 连接管理和自动重连\n * 2. 双向实时通信支持\n * 3. 连接池管理和性能优化\n * 4. 消息压缩和批量处理\n */\n\nimport WebSocket, { WebSocketServer } from \"ws\";\nimport type { MCPMessageHandler } from \"../core/MCPMessageHandler.js\";\nimport { ConnectionState, TransportAdapter } from \"./TransportAdapter.js\";\nimport type {\n MCPMessage,\n MCPResponse,\n TransportConfig,\n} from \"./TransportAdapter.js\";\n\n/**\n * WebSocket 连接状态枚举\n */\nexport enum WebSocketState {\n DISCONNECTED = \"disconnected\",\n CONNECTING = \"connecting\",\n CONNECTED = \"connected\",\n RECONNECTING = \"reconnecting\",\n FAILED = \"failed\",\n}\n\n/**\n * 重连配置接口\n */\nexport interface ReconnectOptions {\n enabled: boolean;\n maxAttempts: number;\n initialInterval: number;\n maxInterval: number;\n backoffStrategy: \"linear\" | \"exponential\" | \"fixed\";\n backoffMultiplier: number;\n timeout: number;\n jitter: boolean;\n}\n\n/**\n * WebSocket 适配器配置\n */\nexport interface WebSocketConfig extends TransportConfig {\n endpointUrl: string;\n mode?: \"client\" | \"server\";\n reconnect?: Partial<ReconnectOptions>;\n compression?: boolean;\n batchSize?: number;\n batchTimeout?: number;\n maxConnections?: number;\n}\n\n/**\n * 重连状态接口\n */\ninterface ReconnectState {\n attempts: number;\n nextInterval: number;\n timer: NodeJS.Timeout | null;\n lastError: Error | null;\n isManualDisconnect: boolean;\n}\n\n/**\n * 消息批处理队列项\n */\ninterface BatchQueueItem {\n message: MCPMessage | MCPResponse;\n timestamp: number;\n resolve: () => void;\n reject: (error: Error) => void;\n}\n\n/**\n * WebSocket 传输适配器实现\n * 支持客户端和服务器模式的 WebSocket 通信\n */\nexport class WebSocketAdapter extends TransportAdapter {\n private ws: WebSocket | null = null;\n private wsServer: WebSocketServer | null = null;\n private endpointUrl: string;\n private mode: \"client\" | \"server\";\n private wsState: WebSocketState = WebSocketState.DISCONNECTED;\n\n // 重连相关\n private reconnectOptions: ReconnectOptions;\n private reconnectState: ReconnectState;\n private connectionTimeout: NodeJS.Timeout | null = null;\n\n // 性能优化相关\n private compression: boolean;\n private batchQueue: BatchQueueItem[] = [];\n private batchTimer: NodeJS.Timeout | null = null;\n private batchSize: number;\n private batchTimeout: number;\n\n // 连接池管理\n private connections: Map<string, WebSocket> = new Map();\n private maxConnections: number;\n\n constructor(messageHandler: MCPMessageHandler, config: WebSocketConfig) {\n super(messageHandler, config);\n\n this.endpointUrl = config.endpointUrl;\n this.mode = config.mode || \"client\";\n this.compression = config.compression || false;\n this.batchSize = config.batchSize || 10;\n this.batchTimeout = config.batchTimeout || 100;\n this.maxConnections = config.maxConnections || 100;\n\n // 初始化重连配置\n this.reconnectOptions = {\n enabled: true,\n maxAttempts: 5,\n initialInterval: 1000,\n maxInterval: 30000,\n backoffStrategy: \"exponential\",\n backoffMultiplier: 1.5,\n timeout: 10000,\n jitter: true,\n ...config.reconnect,\n };\n\n // 初始化重连状态\n this.reconnectState = {\n attempts: 0,\n nextInterval: this.reconnectOptions.initialInterval,\n timer: null,\n lastError: null,\n isManualDisconnect: false,\n };\n }\n\n /**\n * 初始化 WebSocket 适配器\n */\n async initialize(): Promise<void> {\n this.logger.info(`初始化 WebSocket 适配器 (${this.mode} 模式)`);\n\n try {\n this.setState(ConnectionState.CONNECTING);\n this.wsState = WebSocketState.CONNECTING;\n\n if (this.mode === \"client\") {\n await this.initializeClient();\n } else {\n await this.initializeServer();\n }\n\n this.logger.info(\"WebSocket 适配器初始化完成\");\n } catch (error) {\n this.logger.error(\"WebSocket 适配器初始化失败\", error);\n this.setState(ConnectionState.ERROR);\n this.wsState = WebSocketState.FAILED;\n throw error;\n }\n }\n\n /**\n * 初始化客户端模式\n */\n private async initializeClient(): Promise<void> {\n return new Promise((resolve, reject) => {\n // 设置连接超时\n this.connectionTimeout = setTimeout(() => {\n const error = new Error(\n `连接超时 (${this.reconnectOptions.timeout}ms)`\n );\n this.handleConnectionError(error);\n reject(error);\n }, this.reconnectOptions.timeout);\n\n this.ws = new WebSocket(this.endpointUrl);\n\n // 启用压缩\n if (this.compression) {\n // WebSocket 压缩扩展会自动处理\n }\n\n this.ws.on(\"open\", () => {\n this.handleConnectionSuccess();\n resolve();\n });\n\n this.ws.on(\"message\", (data) => {\n this.handleIncomingData(data);\n });\n\n this.ws.on(\"close\", (code, reason) => {\n this.handleConnectionClose(code, reason.toString());\n });\n\n this.ws.on(\"error\", (error) => {\n this.handleConnectionError(error);\n reject(error);\n });\n });\n }\n\n /**\n * 初始化服务器模式\n */\n private async initializeServer(): Promise<void> {\n return new Promise((resolve, reject) => {\n try {\n const url = new URL(this.endpointUrl);\n const port = Number.parseInt(url.port) || 8080;\n\n this.wsServer = new WebSocketServer({\n port,\n perMessageDeflate: this.compression,\n });\n\n this.wsServer.on(\"connection\", (ws, request) => {\n this.handleNewConnection(ws, request);\n });\n\n this.wsServer.on(\"error\", (error) => {\n this.logger.error(\"WebSocket 服务器错误\", error);\n reject(error);\n });\n\n this.logger.info(`WebSocket 服务器监听端口 ${port}`);\n resolve();\n } catch (error) {\n reject(error);\n }\n });\n }\n\n /**\n * 启动 WebSocket 适配器\n */\n async start(): Promise<void> {\n if (this.wsState === WebSocketState.CONNECTED) {\n this.logger.warn(\"WebSocket 适配器已启动\");\n return;\n }\n\n this.logger.info(\"启动 WebSocket 适配器\");\n\n try {\n this.setState(ConnectionState.CONNECTED);\n this.wsState = WebSocketState.CONNECTED;\n\n this.logger.info(\"WebSocket 适配器启动成功\");\n } catch (error) {\n this.logger.error(\"启动 WebSocket 适配器失败\", error);\n this.setState(ConnectionState.ERROR);\n this.wsState = WebSocketState.FAILED;\n throw error;\n }\n }\n\n /**\n * 停止 WebSocket 适配器\n */\n async stop(): Promise<void> {\n this.logger.info(\"停止 WebSocket 适配器\");\n\n try {\n // 标记为手动断开\n this.reconnectState.isManualDisconnect = true;\n\n // 清理重连定时器\n if (this.reconnectState.timer) {\n clearTimeout(this.reconnectState.timer);\n this.reconnectState.timer = null;\n }\n\n // 清理批处理定时器\n if (this.batchTimer) {\n clearTimeout(this.batchTimer);\n this.batchTimer = null;\n }\n\n // 处理剩余的批处理消息\n await this.flushBatchQueue();\n\n // 关闭客户端连接\n if (this.ws) {\n this.ws.close();\n this.ws = null;\n }\n\n // 关闭服务器\n if (this.wsServer) {\n this.wsServer.close();\n this.wsServer = null;\n }\n\n // 关闭所有连接\n for (const [id, connection] of this.connections) {\n connection.close();\n }\n this.connections.clear();\n\n this.setState(ConnectionState.DISCONNECTED);\n this.wsState = WebSocketState.DISCONNECTED;\n\n this.logger.info(\"WebSocket 适配器已停止\");\n } catch (error) {\n this.logger.error(\"停止 WebSocket 适配器时出错\", error);\n throw error;\n }\n }\n\n /**\n * 发送消息\n */\n async sendMessage(message: MCPMessage | MCPResponse): Promise<void> {\n if (this.wsState !== WebSocketState.CONNECTED) {\n throw new Error(`WebSocket 未连接 (状态: ${this.wsState})`);\n }\n\n // 如果启用了批处理,添加到队列\n if (this.batchSize > 1) {\n return this.addToBatchQueue(message);\n }\n\n // 直接发送\n return this.sendMessageDirect(message);\n }\n\n /**\n * 直接发送消息\n */\n private async sendMessageDirect(\n message: MCPMessage | MCPResponse\n ): Promise<void> {\n try {\n const serializedMessage = this.serializeMessage(message);\n\n if (this.mode === \"client\" && this.ws) {\n this.ws.send(serializedMessage);\n } else if (this.mode === \"server\") {\n // 广播到所有连接\n for (const connection of this.connections.values()) {\n if (connection.readyState === WebSocket.OPEN) {\n connection.send(serializedMessage);\n }\n }\n }\n\n this.logger.debug(\"消息已发送\", {\n messageId: message.id,\n method: \"method\" in message ? message.method : \"response\",\n });\n } catch (error) {\n this.logger.error(\"发送消息失败\", error);\n throw error;\n }\n }\n\n /**\n * 添加消息到批处理队列\n */\n private async addToBatchQueue(\n message: MCPMessage | MCPResponse\n ): Promise<void> {\n return new Promise((resolve, reject) => {\n this.batchQueue.push({\n message,\n timestamp: Date.now(),\n resolve,\n reject,\n });\n\n // 如果队列达到批处理大小,立即处理\n if (this.batchQueue.length >= this.batchSize) {\n this.flushBatchQueue();\n } else if (!this.batchTimer) {\n // 设置批处理超时\n this.batchTimer = setTimeout(() => {\n this.flushBatchQueue();\n }, this.batchTimeout);\n }\n });\n }\n\n /**\n * 刷新批处理队列\n */\n private async flushBatchQueue(): Promise<void> {\n if (this.batchQueue.length === 0) {\n return;\n }\n\n // 清理定时器\n if (this.batchTimer) {\n clearTimeout(this.batchTimer);\n this.batchTimer = null;\n }\n\n const batch = this.batchQueue.splice(0);\n\n try {\n // 批量发送消息\n const messages = batch.map((item) => item.message);\n const batchMessage = {\n jsonrpc: \"2.0\" as const,\n method: \"batch\",\n params: { messages },\n id: `batch_${Date.now()}`,\n };\n\n await this.sendMessageDirect(batchMessage);\n\n // 解析所有 Promise\n for (const item of batch) {\n item.resolve();\n }\n\n this.logger.debug(`批处理发送 ${batch.length} 条消息`);\n } catch (error) {\n // 拒绝所有 Promise\n for (const item of batch) {\n item.reject(error as Error);\n }\n this.logger.error(\"批处理发送失败\", error);\n }\n }\n\n /**\n * 处理接收到的数据\n */\n private async handleIncomingData(data: WebSocket.Data): Promise<void> {\n try {\n const messageStr = data.toString();\n const message = this.parseMessage(messageStr);\n\n if (message) {\n // 检查是否是批处理消息\n if (message.method === \"batch\" && message.params?.messages) {\n // 处理批处理消息\n for (const batchedMessage of message.params.messages) {\n await this.handleIncomingMessage(batchedMessage);\n }\n } else {\n await this.handleIncomingMessage(message);\n }\n }\n } catch (error) {\n this.logger.error(\"处理接收数据失败\", error);\n }\n }\n\n /**\n * 处理连接成功\n */\n private handleConnectionSuccess(): void {\n // 清理连接超时定时器\n if (this.connectionTimeout) {\n clearTimeout(this.connectionTimeout);\n this.connectionTimeout = null;\n }\n\n this.setState(ConnectionState.CONNECTED);\n this.wsState = WebSocketState.CONNECTED;\n\n // 重置重连状态\n this.reconnectState.attempts = 0;\n this.reconnectState.nextInterval = this.reconnectOptions.initialInterval;\n this.reconnectState.lastError = null;\n\n this.logger.info(\"WebSocket 连接已建立\");\n }\n\n /**\n * 处理连接错误\n */\n private handleConnectionError(error: Error): void {\n // 清理连接超时定时器\n if (this.connectionTimeout) {\n clearTimeout(this.connectionTimeout);\n this.connectionTimeout = null;\n }\n\n this.reconnectState.lastError = error;\n this.logger.error(\"WebSocket 连接错误\", error);\n\n this.setState(ConnectionState.ERROR);\n this.wsState = WebSocketState.FAILED;\n\n // 清理当前连接\n this.cleanupConnection();\n }\n\n /**\n * 处理连接关闭\n */\n private handleConnectionClose(code: number, reason: string): void {\n this.setState(ConnectionState.DISCONNECTED);\n this.wsState = WebSocketState.DISCONNECTED;\n\n this.logger.info(`WebSocket 连接已关闭 (代码: ${code}, 原因: ${reason})`);\n\n // 如果是手动断开,不进行重连\n if (this.reconnectState.isManualDisconnect) {\n return;\n }\n\n // 检查是否需要重连\n if (this.shouldReconnect()) {\n this.scheduleReconnect();\n } else {\n this.wsState = WebSocketState.FAILED;\n this.logger.warn(\n `已达到最大重连次数 (${this.reconnectOptions.maxAttempts}),停止重连`\n );\n }\n }\n\n /**\n * 处理新连接(服务器模式)\n */\n private handleNewConnection(ws: WebSocket, request: any): void {\n // 检查连接数限制\n if (this.connections.size >= this.maxConnections) {\n this.logger.warn(\"达到最大连接数限制,拒绝新连接\");\n ws.close(1013, \"服务器繁忙\");\n return;\n }\n\n const connectionId = `${this.getConnectionId()}_${this.connections.size}`;\n this.connections.set(connectionId, ws);\n\n this.logger.info(`新 WebSocket 连接: ${connectionId}`);\n\n ws.on(\"message\", (data) => {\n this.handleIncomingData(data);\n });\n\n ws.on(\"close\", () => {\n this.connections.delete(connectionId);\n this.logger.info(`WebSocket 连接已断开: ${connectionId}`);\n });\n\n ws.on(\"error\", (error) => {\n this.logger.error(`WebSocket 连接错误 ${connectionId}:`, error);\n this.connections.delete(connectionId);\n });\n }\n\n /**\n * 清理连接\n */\n private cleanupConnection(): void {\n if (this.ws) {\n this.ws.removeAllListeners();\n this.ws = null;\n }\n }\n\n /**\n * 检查是否应该重连\n */\n private shouldReconnect(): boolean {\n return (\n this.reconnectOptions.enabled &&\n this.reconnectState.attempts < this.reconnectOptions.maxAttempts &&\n !this.reconnectState.isManualDisconnect\n );\n }\n\n /**\n * 安排重连\n */\n private scheduleReconnect(): void {\n this.wsState = WebSocketState.RECONNECTING;\n this.reconnectState.attempts++;\n\n // 计算重连间隔\n let interval = this.calculateReconnectInterval();\n\n // 添加随机抖动\n if (this.reconnectOptions.jitter) {\n interval += Math.random() * 1000;\n }\n\n this.logger.info(\n `安排重连 (第 ${this.reconnectState.attempts} 次,${interval}ms 后)`\n );\n\n this.reconnectState.timer = setTimeout(async () => {\n try {\n await this.initializeClient();\n } catch (error) {\n this.logger.error(\"重连失败\", error);\n\n if (this.shouldReconnect()) {\n this.scheduleReconnect();\n } else {\n this.wsState = WebSocketState.FAILED;\n }\n }\n }, interval);\n }\n\n /**\n * 计算重连间隔\n */\n private calculateReconnectInterval(): number {\n const { backoffStrategy, initialInterval, maxInterval, backoffMultiplier } =\n this.reconnectOptions;\n const attempts = this.reconnectState.attempts;\n\n let interval: number;\n\n switch (backoffStrategy) {\n case \"linear\":\n interval = initialInterval + attempts * 1000;\n break;\n case \"exponential\":\n interval = initialInterval * backoffMultiplier ** attempts;\n break;\n default:\n interval = initialInterval;\n break;\n }\n\n return Math.min(interval, maxInterval);\n }\n\n /**\n * 获取适配器状态\n */\n getStatus(): {\n wsState: WebSocketState;\n connectionState: ConnectionState;\n mode: string;\n endpointUrl: string;\n connectionCount: number;\n reconnectAttempts: number;\n batchQueueSize: number;\n compression: boolean;\n } {\n return {\n wsState: this.wsState,\n connectionState: this.state,\n mode: this.mode,\n endpointUrl: this.endpointUrl,\n connectionCount: this.connections.size,\n reconnectAttempts: this.reconnectState.attempts,\n batchQueueSize: this.batchQueue.length,\n compression: this.compression,\n };\n }\n\n /**\n * 强制重连\n */\n async forceReconnect(): Promise<void> {\n if (this.mode !== \"client\") {\n throw new Error(\"只有客户端模式支持重连\");\n }\n\n this.logger.info(\"强制重连\");\n\n // 重置重连状态\n this.reconnectState.attempts = 0;\n this.reconnectState.isManualDisconnect = false;\n\n // 关闭当前连接\n if (this.ws) {\n this.ws.close();\n }\n\n // 立即重连\n await this.initializeClient();\n }\n}\n","/**\n * 统一的 MCP 消息处理器\n * 负责处理所有 MCP 协议消息,包括 initialize、tools/list、tools/call 等\n * 这是阶段一重构的核心组件,用于消除双层代理架构\n */\n\nimport { type Logger, logger } from \"../Logger.js\";\nimport type { MCPServiceManager } from \"../services/MCPServiceManager.js\";\n\n// MCP 消息接口\ninterface MCPMessage {\n jsonrpc: \"2.0\";\n method: string;\n params?: any;\n id?: string | number;\n}\n\n// MCP 响应接口\ninterface MCPResponse {\n jsonrpc: \"2.0\";\n result?: any;\n error?: MCPError;\n id: string | number | null;\n}\n\n// MCP 错误接口\ninterface MCPError {\n code: number;\n message: string;\n data?: any;\n}\n\n// 初始化参数接口\ninterface InitializeParams {\n protocolVersion: string;\n capabilities: any;\n clientInfo: {\n name: string;\n version: string;\n };\n}\n\n// 工具调用参数接口\ninterface ToolCallParams {\n name: string;\n arguments?: any;\n}\n\nexport class MCPMessageHandler {\n private logger: Logger;\n private serviceManager: MCPServiceManager;\n\n constructor(serviceManager: MCPServiceManager) {\n this.serviceManager = serviceManager;\n this.logger = logger;\n }\n\n /**\n * 处理 MCP 消息的统一入口\n * @param message MCP 消息\n * @returns MCP 响应\n */\n async handleMessage(message: MCPMessage): Promise<MCPResponse> {\n this.logger.debug(`处理 MCP 消息: ${message.method}`, message);\n\n try {\n switch (message.method) {\n case \"initialize\":\n return await this.handleInitialize(message.params, message.id);\n case \"tools/list\":\n return await this.handleToolsList(message.id);\n case \"tools/call\":\n return await this.handleToolCall(message.params, message.id);\n case \"ping\":\n return await this.handlePing(message.id);\n default:\n throw new Error(`未知的方法: ${message.method}`);\n }\n } catch (error) {\n this.logger.error(`处理消息时出错: ${message.method}`, error);\n return this.createErrorResponse(error as Error, message.id);\n }\n }\n\n /**\n * 处理 initialize 请求\n * @param params 初始化参数\n * @param id 消息ID\n * @returns 初始化响应\n */\n private async handleInitialize(\n params: InitializeParams,\n id?: string | number\n ): Promise<MCPResponse> {\n this.logger.info(\"处理 initialize 请求\", params);\n\n return {\n jsonrpc: \"2.0\",\n result: {\n serverInfo: {\n name: \"xiaozhi-mcp-server\",\n version: \"1.0.0\",\n },\n capabilities: {\n tools: {},\n logging: {},\n },\n protocolVersion: \"2024-11-05\",\n },\n id: id || null,\n };\n }\n\n /**\n * 处理 tools/list 请求\n * @param id 消息ID\n * @returns 工具列表响应\n */\n private async handleToolsList(id?: string | number): Promise<MCPResponse> {\n this.logger.info(\"处理 tools/list 请求\");\n\n try {\n const tools = this.serviceManager.getAllTools();\n\n // 转换为 MCP 标准格式\n const mcpTools = tools.map((tool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema,\n }));\n\n this.logger.info(`返回 ${mcpTools.length} 个工具`);\n\n return {\n jsonrpc: \"2.0\",\n result: {\n tools: mcpTools,\n },\n id: id || null,\n };\n } catch (error) {\n this.logger.error(\"获取工具列表失败\", error);\n throw error;\n }\n }\n\n /**\n * 处理 tools/call 请求\n * @param params 工具调用参数\n * @param id 消息ID\n * @returns 工具调用响应\n */\n private async handleToolCall(\n params: ToolCallParams,\n id?: string | number\n ): Promise<MCPResponse> {\n this.logger.info(`处理 tools/call 请求: ${params.name}`, params);\n\n try {\n if (!params.name) {\n throw new Error(\"工具名称不能为空\");\n }\n\n const result = await this.serviceManager.callTool(\n params.name,\n params.arguments || {}\n );\n\n this.logger.info(`工具 ${params.name} 调用成功`);\n\n return {\n jsonrpc: \"2.0\",\n result: {\n content: result.content,\n isError: result.isError || false,\n },\n id: id || null,\n };\n } catch (error) {\n this.logger.error(`工具调用失败: ${params.name}`, error);\n throw error;\n }\n }\n\n /**\n * 处理 ping 请求\n * @param id 消息ID\n * @returns ping 响应\n */\n private async handlePing(id?: string | number): Promise<MCPResponse> {\n this.logger.debug(\"处理 ping 请求\");\n\n return {\n jsonrpc: \"2.0\",\n result: {\n status: \"ok\",\n timestamp: new Date().toISOString(),\n },\n id: id || null,\n };\n }\n\n /**\n * 创建错误响应\n * @param error 错误对象\n * @param id 消息ID\n * @returns 错误响应\n */\n private createErrorResponse(error: Error, id?: string | number): MCPResponse {\n // 根据错误类型确定错误代码\n let errorCode = -32603; // Internal error\n\n if (\n error.message.includes(\"未找到工具\") ||\n error.message.includes(\"未知的方法\")\n ) {\n errorCode = -32601; // Method not found\n } else if (\n error.message.includes(\"参数\") ||\n error.message.includes(\"不能为空\")\n ) {\n errorCode = -32602; // Invalid params\n }\n\n return {\n jsonrpc: \"2.0\",\n error: {\n code: errorCode,\n message: error.message,\n data: {\n stack: error.stack,\n },\n },\n id: id || null,\n };\n }\n\n /**\n * 获取服务管理器实例\n * @returns MCPServiceManager 实例\n */\n getServiceManager(): MCPServiceManager {\n return this.serviceManager;\n }\n}\n","/**\n * 统一 MCP 服务器\n * 阶段三重构:整合所有传输协议和服务管理的统一服务器实现\n *\n * 这是整个 MCP 系统的核心类,负责:\n * 1. 管理多种传输适配器(HTTP、Stdio、WebSocket等)\n * 2. 统一的工具注册和管理\n * 3. 连接生命周期管理\n * 4. 消息路由和处理\n */\n\nimport { EventEmitter } from \"node:events\";\nimport { type Logger, logger } from \"../Logger.js\";\nimport { MCPServiceManager } from \"../services/MCPServiceManager.js\";\nimport {\n ConnectionState,\n type TransportAdapter,\n} from \"../transports/TransportAdapter.js\";\nimport type {\n MCPMessage,\n MCPResponse,\n} from \"../transports/TransportAdapter.js\";\nimport { MCPMessageHandler } from \"./MCPMessageHandler.js\";\n\n/**\n * 工具信息接口\n */\nexport interface ToolInfo {\n name: string;\n description?: string;\n inputSchema?: any;\n serviceName: string;\n originalName: string;\n}\n\n/**\n * 连接信息接口\n */\nexport interface ConnectionInfo {\n id: string;\n transportName: string;\n state: ConnectionState;\n connectedAt: Date;\n lastActivity: Date;\n}\n\n/**\n * 服务器配置接口\n */\nexport interface UnifiedServerConfig {\n name?: string;\n enableLogging?: boolean;\n logLevel?: string;\n maxConnections?: number;\n connectionTimeout?: number;\n}\n\n/**\n * 简化的工具注册表\n * 基于现有的 MCPServiceManager 提供统一的工具管理接口\n */\nexport class ToolRegistry {\n private serviceManager: MCPServiceManager;\n private logger: Logger;\n\n constructor(serviceManager: MCPServiceManager) {\n this.serviceManager = serviceManager;\n this.logger = logger;\n }\n\n async initialize(): Promise<void> {\n this.logger.info(\"初始化工具注册表\");\n // 工具注册表的初始化由 MCPServiceManager 处理\n }\n\n /**\n * 获取所有工具\n */\n getAllTools(): ToolInfo[] {\n return this.serviceManager.getAllTools().map((tool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema,\n serviceName: tool.serviceName,\n originalName: tool.originalName,\n }));\n }\n\n /**\n * 查找工具\n */\n findTool(toolName: string): ToolInfo | null {\n const tools = this.getAllTools();\n return tools.find((tool) => tool.name === toolName) || null;\n }\n\n /**\n * 检查工具是否存在\n */\n hasTool(toolName: string): boolean {\n return this.findTool(toolName) !== null;\n }\n}\n\n/**\n * 简化的连接管理器\n * 管理传输适配器的连接状态和生命周期\n */\nexport class ConnectionManager extends EventEmitter {\n private connections: Map<string, ConnectionInfo> = new Map();\n private logger: Logger;\n\n constructor() {\n super();\n this.logger = logger;\n }\n\n async initialize(): Promise<void> {\n this.logger.info(\"初始化连接管理器\");\n }\n\n /**\n * 注册连接\n */\n registerConnection(\n id: string,\n transportName: string,\n state: ConnectionState\n ): void {\n const connectionInfo: ConnectionInfo = {\n id,\n transportName,\n state,\n connectedAt: new Date(),\n lastActivity: new Date(),\n };\n\n this.connections.set(id, connectionInfo);\n this.emit(\"connectionRegistered\", connectionInfo);\n this.logger.debug(`连接已注册: ${id} (${transportName})`);\n }\n\n /**\n * 更新连接状态\n */\n updateConnectionState(id: string, state: ConnectionState): void {\n const connection = this.connections.get(id);\n if (connection) {\n connection.state = state;\n connection.lastActivity = new Date();\n this.emit(\"connectionStateChanged\", connection);\n this.logger.debug(`连接状态更新: ${id} -> ${state}`);\n }\n }\n\n /**\n * 移除连接\n */\n removeConnection(id: string): void {\n const connection = this.connections.get(id);\n if (connection) {\n this.connections.delete(id);\n this.emit(\"connectionRemoved\", connection);\n this.logger.debug(`连接已移除: ${id}`);\n }\n }\n\n /**\n * 获取所有连接\n */\n getAllConnections(): ConnectionInfo[] {\n return Array.from(this.connections.values());\n }\n\n /**\n * 获取活跃连接数\n */\n getActiveConnectionCount(): number {\n return Array.from(this.connections.values()).filter(\n (conn) => conn.state === ConnectionState.CONNECTED\n ).length;\n }\n\n /**\n * 关闭所有连接\n */\n async closeAllConnections(): Promise<void> {\n this.logger.info(\"关闭所有连接\");\n this.connections.clear();\n this.emit(\"allConnectionsClosed\");\n }\n}\n\n/**\n * 统一 MCP 服务器\n * 整合所有传输协议和服务管理的核心服务器类\n */\nexport class UnifiedMCPServer extends EventEmitter {\n private serviceManager: MCPServiceManager;\n private messageHandler: MCPMessageHandler;\n private transportAdapters: Map<string, TransportAdapter> = new Map();\n private toolRegistry: ToolRegistry;\n private connectionManager: ConnectionManager;\n private isRunning = false;\n private logger: Logger;\n private config: UnifiedServerConfig;\n\n constructor(config: UnifiedServerConfig = {}) {\n super();\n\n this.config = {\n name: \"UnifiedMCPServer\",\n enableLogging: true,\n logLevel: \"info\",\n maxConnections: 100,\n connectionTimeout: 30000,\n ...config,\n };\n\n this.logger = logger;\n\n // 初始化核心组件\n this.serviceManager = new MCPServiceManager();\n this.messageHandler = new MCPMessageHandler(this.serviceManager);\n this.toolRegistry = new ToolRegistry(this.serviceManager);\n this.connectionManager = new ConnectionManager();\n\n // 设置事件监听\n this.setupEventListeners();\n }\n\n /**\n * 设置事件监听器\n */\n private setupEventListeners(): void {\n // 监听连接管理器事件\n this.connectionManager.on(\n \"connectionRegistered\",\n (connection: ConnectionInfo) => {\n this.emit(\"connectionRegistered\", connection);\n }\n );\n\n this.connectionManager.on(\n \"connectionStateChanged\",\n (connection: ConnectionInfo) => {\n this.emit(\"connectionStateChanged\", connection);\n }\n );\n\n this.connectionManager.on(\n \"connectionRemoved\",\n (connection: ConnectionInfo) => {\n this.emit(\"connectionRemoved\", connection);\n }\n );\n }\n\n /**\n * 初始化服务器\n */\n async initialize(): Promise<void> {\n this.logger.info(\"初始化统一 MCP 服务器\");\n\n try {\n // 初始化核心组件\n await this.serviceManager.startAllServices();\n await this.toolRegistry.initialize();\n await this.connectionManager.initialize();\n\n this.logger.info(\"统一 MCP 服务器初始化完成\");\n this.emit(\"initialized\");\n } catch (error) {\n this.logger.error(\"统一 MCP 服务器初始化失败\", error);\n throw error;\n }\n }\n\n /**\n * 注册传输适配器\n */\n async registerTransport(\n name: string,\n adapter: TransportAdapter\n ): Promise<void> {\n if (this.transportAdapters.has(name)) {\n throw new Error(`传输适配器 ${name} 已存在`);\n }\n\n this.logger.info(`注册传输适配器: ${name}`);\n\n try {\n // 初始化适配器\n await adapter.initialize();\n\n // 注册适配器\n this.transportAdapters.set(name, adapter);\n\n // 注册连接到连接管理器\n this.connectionManager.registerConnection(\n adapter.getConnectionId(),\n name,\n adapter.getState()\n );\n\n this.logger.info(`传输适配器 ${name} 注册成功`);\n this.emit(\"transportRegistered\", { name, adapter });\n } catch (error) {\n this.logger.error(`注册传输适配器 ${name} 失败`, error);\n throw error;\n }\n }\n\n /**\n * 启动服务器\n */\n async start(): Promise<void> {\n if (this.isRunning) {\n throw new Error(\"服务器已在运行\");\n }\n\n this.logger.info(\"启动统一 MCP 服务器\");\n\n try {\n // 启动所有传输适配器\n for (const [name, adapter] of this.transportAdapters) {\n try {\n await adapter.start();\n\n // 更新连接状态\n this.connectionManager.updateConnectionState(\n adapter.getConnectionId(),\n adapter.getState()\n );\n\n this.logger.info(`传输适配器 ${name} 启动成功`);\n } catch (error) {\n this.logger.error(`传输适配器 ${name} 启动失败`, error);\n throw error;\n }\n }\n\n this.isRunning = true;\n this.logger.info(\"统一 MCP 服务器启动成功\");\n this.emit(\"started\");\n } catch (error) {\n this.logger.error(\"统一 MCP 服务器启动失败\", error);\n throw error;\n }\n }\n\n /**\n * 停止服务器\n */\n async stop(): Promise<void> {\n if (!this.isRunning) {\n return;\n }\n\n this.logger.info(\"停止统一 MCP 服务器\");\n\n try {\n // 停止所有传输适配器\n for (const [name, adapter] of this.transportAdapters) {\n try {\n await adapter.stop();\n\n // 更新连接状态\n this.connectionManager.updateConnectionState(\n adapter.getConnectionId(),\n adapter.getState()\n );\n\n this.logger.info(`传输适配器 ${name} 停止成功`);\n } catch (error) {\n this.logger.error(`传输适配器 ${name} 停止失败`, error);\n }\n }\n\n // 关闭所有连接\n await this.connectionManager.closeAllConnections();\n\n // 停止服务管理器\n await this.serviceManager.stopAllServices();\n\n this.isRunning = false;\n this.logger.info(\"统一 MCP 服务器停止成功\");\n this.emit(\"stopped\");\n } catch (error) {\n this.logger.error(\"统一 MCP 服务器停止失败\", error);\n throw error;\n }\n }\n\n /**\n * 获取服务管理器\n */\n getServiceManager(): MCPServiceManager {\n return this.serviceManager;\n }\n\n /**\n * 获取工具注册表\n */\n getToolRegistry(): ToolRegistry {\n return this.toolRegistry;\n }\n\n /**\n * 获取连接管理器\n */\n getConnectionManager(): ConnectionManager {\n return this.connectionManager;\n }\n\n /**\n * 获取消息处理器\n */\n getMessageHandler(): MCPMessageHandler {\n return this.messageHandler;\n }\n\n /**\n * 获取服务器状态\n */\n getStatus(): {\n isRunning: boolean;\n transportCount: number;\n activeConnections: number;\n toolCount: number;\n config: UnifiedServerConfig;\n } {\n return {\n isRunning: this.isRunning,\n transportCount: this.transportAdapters.size,\n activeConnections: this.connectionManager.getActiveConnectionCount(),\n toolCount: this.toolRegistry.getAllTools().length,\n config: this.config,\n };\n }\n\n /**\n * 获取所有传输适配器\n */\n getTransportAdapters(): Map<string, TransportAdapter> {\n return new Map(this.transportAdapters);\n }\n\n /**\n * 检查服务器是否正在运行\n */\n isServerRunning(): boolean {\n return this.isRunning;\n }\n}\n","/**\n * MCP 服务器工厂\n * 阶段三重构:支持多种传输协议的自动选择和服务器创建\n *\n * 主要功能:\n * 1. 根据环境自动选择合适的传输协议\n * 2. 创建和配置 UnifiedMCPServer 实例\n * 3. 注册和管理传输适配器\n * 4. 提供便捷的服务器创建方法\n */\n\nimport { logger } from \"../Logger.js\";\nimport { HTTPAdapter, type HTTPConfig } from \"../transports/HTTPAdapter.js\";\nimport { StdioAdapter, type StdioConfig } from \"../transports/StdioAdapter.js\";\nimport { TransportAdapter } from \"../transports/TransportAdapter.js\";\nimport {\n WebSocketAdapter,\n type WebSocketConfig,\n} from \"../transports/WebSocketAdapter.js\";\nimport type { MCPMessageHandler } from \"./MCPMessageHandler.js\";\nimport {\n UnifiedMCPServer,\n type UnifiedServerConfig,\n} from \"./UnifiedMCPServer.js\";\n\n/**\n * 服务器模式枚举\n */\nexport enum ServerMode {\n STDIO = \"stdio\", // 标准输入输出模式(Cursor 等客户端)\n HTTP = \"http\", // HTTP 服务器模式(Web 客户端)\n WEBSOCKET = \"websocket\", // WebSocket 模式(实时双向通信)\n HYBRID = \"hybrid\", // 混合模式(同时支持多种传输)\n AUTO = \"auto\", // 自动检测模式\n}\n\n/**\n * 服务器工厂配置\n */\nexport interface ServerFactoryConfig {\n mode?: ServerMode;\n serverConfig?: UnifiedServerConfig;\n stdioConfig?: StdioConfig;\n httpConfig?: HTTPConfig;\n websocketConfig?: WebSocketConfig;\n autoDetect?: {\n checkStdin?: boolean;\n checkEnvironment?: boolean;\n defaultMode?: ServerMode;\n };\n}\n\n/**\n * 环境检测结果\n */\ninterface EnvironmentDetection {\n hasStdin: boolean;\n isInteractive: boolean;\n hasPort: boolean;\n suggestedMode: ServerMode;\n reasons: string[];\n}\n\n// 使用全局 logger 实例\n\n/**\n * 创建 MCP 服务器\n * 根据配置或环境自动选择合适的传输协议\n */\nexport async function createServer(\n config: ServerFactoryConfig = {}\n): Promise<UnifiedMCPServer> {\n logger.info(\"[ServerFactory] 开始创建 MCP 服务器\", config);\n\n try {\n // 确定服务器模式\n const mode = await determineServerMode(config);\n logger.info(`[ServerFactory] 确定服务器模式: ${mode}`);\n\n // 创建统一服务器实例\n const server = new UnifiedMCPServer(config.serverConfig);\n await server.initialize();\n\n // 根据模式注册传输适配器\n await registerTransportsForMode(server, mode, config);\n\n logger.info(\"[ServerFactory] MCP 服务器创建成功\");\n return server;\n } catch (error) {\n logger.error(\"[ServerFactory] 创建 MCP 服务器失败\", error);\n throw error;\n }\n}\n\n/**\n * 创建 Stdio 模式服务器\n * 专门用于 Cursor 等客户端的标准输入输出通信\n */\nexport async function createStdioServer(\n config: StdioConfig = { name: \"stdio\" }\n): Promise<UnifiedMCPServer> {\n logger.info(\"[ServerFactory] 创建 Stdio 模式服务器\");\n\n const server = new UnifiedMCPServer();\n await server.initialize();\n\n const messageHandler = server.getMessageHandler();\n const stdioAdapter = new StdioAdapter(messageHandler, config);\n\n await server.registerTransport(\"stdio\", stdioAdapter);\n\n logger.info(\"[ServerFactory] Stdio 模式服务器创建成功\");\n return server;\n}\n\n/**\n * 创建 HTTP 模式服务器\n * 专门用于 Web 客户端的 HTTP/SSE 通信\n */\nexport async function createHTTPServer(\n config: HTTPConfig = { name: \"http\" }\n): Promise<UnifiedMCPServer> {\n logger.info(\"创建 HTTP 模式服务器\");\n\n const server = new UnifiedMCPServer();\n await server.initialize();\n\n const messageHandler = server.getMessageHandler();\n const httpAdapter = new HTTPAdapter(messageHandler, config);\n\n await server.registerTransport(\"http\", httpAdapter);\n\n logger.info(\"HTTP 模式服务器创建成功\");\n return server;\n}\n\n/**\n * 创建 WebSocket 模式服务器\n * 专门用于实时双向通信\n */\nexport async function createWebSocketServer(\n config: WebSocketConfig = {\n name: \"websocket\",\n endpointUrl: \"ws://localhost:8080\",\n }\n): Promise<UnifiedMCPServer> {\n logger.info(\"创建 WebSocket 模式服务器\");\n\n const server = new UnifiedMCPServer();\n await server.initialize();\n\n const messageHandler = server.getMessageHandler();\n const wsAdapter = new WebSocketAdapter(messageHandler, config);\n\n await server.registerTransport(\"websocket\", wsAdapter);\n\n logger.info(\"WebSocket 模式服务器创建成功\");\n return server;\n}\n\n/**\n * 创建混合模式服务器\n * 同时支持多种传输协议\n */\nexport async function createHybridServer(\n stdioConfig: StdioConfig = { name: \"stdio\" },\n httpConfig: HTTPConfig = { name: \"http\" },\n websocketConfig?: WebSocketConfig\n): Promise<UnifiedMCPServer> {\n logger.info(\"创建混合模式服务器\");\n\n const server = new UnifiedMCPServer();\n await server.initialize();\n\n const messageHandler = server.getMessageHandler();\n\n // 注册 Stdio 适配器\n const stdioAdapter = new StdioAdapter(messageHandler, stdioConfig);\n await server.registerTransport(\"stdio\", stdioAdapter);\n\n // 注册 HTTP 适配器\n const httpAdapter = new HTTPAdapter(messageHandler, httpConfig);\n await server.registerTransport(\"http\", httpAdapter);\n\n // 可选注册 WebSocket 适配器\n if (websocketConfig) {\n const wsAdapter = new WebSocketAdapter(messageHandler, websocketConfig);\n await server.registerTransport(\"websocket\", wsAdapter);\n }\n\n logger.info(\"混合模式服务器创建成功\");\n return server;\n}\n\n/**\n * 确定服务器模式\n */\nasync function determineServerMode(\n config: ServerFactoryConfig\n): Promise<ServerMode> {\n if (config.mode && config.mode !== ServerMode.AUTO) {\n return config.mode;\n }\n\n // 自动检测环境\n const detection = await detectEnvironment(config.autoDetect);\n logger.info(\"环境检测结果\", detection);\n\n return detection.suggestedMode;\n}\n\n/**\n * 检测运行环境\n */\nasync function detectEnvironment(\n options: ServerFactoryConfig[\"autoDetect\"] = {}\n): Promise<EnvironmentDetection> {\n const {\n checkStdin = true,\n checkEnvironment = true,\n defaultMode = ServerMode.HTTP,\n } = options;\n\n const detection: EnvironmentDetection = {\n hasStdin: false,\n isInteractive: false,\n hasPort: false,\n suggestedMode: defaultMode,\n reasons: [],\n };\n\n // 检查标准输入\n if (checkStdin) {\n detection.hasStdin = !process.stdin.isTTY;\n detection.isInteractive = process.stdin.isTTY || false;\n\n if (detection.hasStdin) {\n detection.reasons.push(\"检测到标准输入流\");\n }\n\n if (detection.isInteractive) {\n detection.reasons.push(\"检测到交互式终端\");\n }\n }\n\n // 检查环境变量\n let explicitModeSet = false;\n if (checkEnvironment) {\n const mcpServerMode = process.env.MCP_SERVER_MODE;\n const port = process.env.PORT || process.env.MCP_PORT;\n\n if (mcpServerMode === \"stdio\") {\n detection.suggestedMode = ServerMode.STDIO;\n detection.reasons.push(\"环境变量 MCP_SERVER_MODE=stdio\");\n explicitModeSet = true;\n } else if (mcpServerMode === \"http\") {\n detection.suggestedMode = ServerMode.HTTP;\n detection.reasons.push(\"环境变量 MCP_SERVER_MODE=http\");\n explicitModeSet = true;\n } else if (mcpServerMode === \"websocket\") {\n detection.suggestedMode = ServerMode.WEBSOCKET;\n detection.reasons.push(\"环境变量 MCP_SERVER_MODE=websocket\");\n explicitModeSet = true;\n } else if (mcpServerMode === \"hybrid\") {\n detection.suggestedMode = ServerMode.HYBRID;\n detection.reasons.push(\"环境变量 MCP_SERVER_MODE=hybrid\");\n explicitModeSet = true;\n }\n\n if (port) {\n detection.hasPort = true;\n detection.reasons.push(`检测到端口配置: ${port}`);\n }\n }\n\n // 智能推断模式(仅在没有明确设置环境变量时)\n if (!explicitModeSet && detection.suggestedMode === defaultMode) {\n if (detection.hasStdin && !detection.isInteractive) {\n detection.suggestedMode = ServerMode.STDIO;\n detection.reasons.push(\"推断:非交互式环境,适合 Stdio 模式\");\n } else if (detection.isInteractive || detection.hasPort) {\n detection.suggestedMode = ServerMode.HTTP;\n detection.reasons.push(\"推断:交互式环境或有端口配置,适合 HTTP 模式\");\n }\n }\n\n return detection;\n}\n\n/**\n * 为指定模式注册传输适配器\n */\nasync function registerTransportsForMode(\n server: UnifiedMCPServer,\n mode: ServerMode,\n config: ServerFactoryConfig\n): Promise<void> {\n const messageHandler = server.getMessageHandler();\n\n switch (mode) {\n case ServerMode.STDIO:\n await registerStdioTransport(server, messageHandler, config.stdioConfig);\n break;\n\n case ServerMode.HTTP:\n await registerHTTPTransport(server, messageHandler, config.httpConfig);\n break;\n\n case ServerMode.WEBSOCKET:\n await registerWebSocketTransport(\n server,\n messageHandler,\n config.websocketConfig\n );\n break;\n\n case ServerMode.HYBRID:\n await registerStdioTransport(server, messageHandler, config.stdioConfig);\n await registerHTTPTransport(server, messageHandler, config.httpConfig);\n if (config.websocketConfig) {\n await registerWebSocketTransport(\n server,\n messageHandler,\n config.websocketConfig\n );\n }\n break;\n\n default:\n throw new Error(`不支持的服务器模式: ${mode}`);\n }\n}\n\n/**\n * 注册 Stdio 传输适配器\n */\nasync function registerStdioTransport(\n server: UnifiedMCPServer,\n messageHandler: MCPMessageHandler,\n config: StdioConfig = { name: \"stdio\" }\n): Promise<void> {\n const stdioAdapter = new StdioAdapter(messageHandler, config);\n await server.registerTransport(\"stdio\", stdioAdapter);\n logger.info(\"Stdio 传输适配器注册成功\");\n}\n\n/**\n * 注册 HTTP 传输适配器\n */\nasync function registerHTTPTransport(\n server: UnifiedMCPServer,\n messageHandler: MCPMessageHandler,\n config: HTTPConfig = { name: \"http\" }\n): Promise<void> {\n // 设置默认端口\n const httpConfig: HTTPConfig = {\n port: 3000,\n host: \"0.0.0.0\",\n ...config,\n };\n\n // 从环境变量获取端口\n if (process.env.PORT) {\n httpConfig.port = Number.parseInt(process.env.PORT, 10);\n } else if (process.env.MCP_PORT) {\n httpConfig.port = Number.parseInt(process.env.MCP_PORT, 10);\n }\n\n const httpAdapter = new HTTPAdapter(messageHandler, httpConfig);\n await server.registerTransport(\"http\", httpAdapter);\n logger.info(`HTTP 传输适配器注册成功 (端口: ${httpConfig.port})`);\n}\n\n/**\n * 注册 WebSocket 传输适配器\n */\nasync function registerWebSocketTransport(\n server: UnifiedMCPServer,\n messageHandler: MCPMessageHandler,\n config: WebSocketConfig = {\n name: \"websocket\",\n endpointUrl: \"ws://localhost:8080\",\n }\n): Promise<void> {\n // 设置默认配置\n const wsConfig: WebSocketConfig = {\n mode: \"client\",\n compression: true,\n batchSize: 10,\n batchTimeout: 100,\n maxConnections: 100,\n ...config,\n };\n\n // 从环境变量获取端点URL\n if (process.env.WEBSOCKET_URL) {\n wsConfig.endpointUrl = process.env.WEBSOCKET_URL;\n } else if (process.env.MCP_WEBSOCKET_URL) {\n wsConfig.endpointUrl = process.env.MCP_WEBSOCKET_URL;\n }\n\n const wsAdapter = new WebSocketAdapter(messageHandler, wsConfig);\n await server.registerTransport(\"websocket\", wsAdapter);\n logger.info(`WebSocket 传输适配器注册成功 (端点: ${wsConfig.endpointUrl})`);\n}\n\n/**\n * 获取推荐的服务器配置\n * 根据环境提供最佳的配置建议\n */\nexport async function getRecommendedConfig(): Promise<ServerFactoryConfig> {\n const detection = await detectEnvironment();\n\n const config: ServerFactoryConfig = {\n mode: detection.suggestedMode,\n autoDetect: {\n checkStdin: true,\n checkEnvironment: true,\n defaultMode: ServerMode.HTTP,\n },\n };\n\n // 根据检测结果调整配置\n if (detection.hasPort) {\n config.httpConfig = {\n name: \"http\",\n port: Number.parseInt(\n process.env.PORT || process.env.MCP_PORT || \"3000\",\n 10\n ),\n };\n }\n\n if (detection.hasStdin) {\n config.stdioConfig = {\n name: \"stdio\",\n encoding: \"utf8\",\n };\n }\n\n // WebSocket 配置(如果有相关环境变量)\n if (process.env.WEBSOCKET_URL || process.env.MCP_WEBSOCKET_URL) {\n config.websocketConfig = {\n name: \"websocket\",\n endpointUrl:\n process.env.WEBSOCKET_URL ||\n process.env.MCP_WEBSOCKET_URL ||\n \"ws://localhost:8080\",\n mode: \"client\",\n compression: true,\n };\n }\n\n return config;\n}\n\n/**\n * 验证服务器配置\n */\nexport function validateConfig(config: ServerFactoryConfig): void {\n if (config.mode === ServerMode.HTTP && config.httpConfig?.port) {\n const port = config.httpConfig.port;\n if (port < 1 || port > 65535) {\n throw new Error(`无效的端口号: ${port}`);\n }\n }\n\n if (config.stdioConfig?.encoding) {\n const validEncodings = [\n \"utf8\",\n \"ascii\",\n \"utf16le\",\n \"ucs2\",\n \"base64\",\n \"latin1\",\n \"binary\",\n \"hex\",\n ];\n if (!validEncodings.includes(config.stdioConfig.encoding)) {\n throw new Error(`不支持的编码: ${config.stdioConfig.encoding}`);\n }\n }\n\n if (config.websocketConfig) {\n const wsConfig = config.websocketConfig;\n\n // 验证端点URL\n if (!wsConfig.endpointUrl) {\n throw new Error(\"WebSocket 端点URL不能为空\");\n }\n\n try {\n new URL(wsConfig.endpointUrl);\n } catch {\n throw new Error(`无效的 WebSocket 端点URL: ${wsConfig.endpointUrl}`);\n }\n\n // 验证模式\n if (wsConfig.mode && ![\"client\", \"server\"].includes(wsConfig.mode)) {\n throw new Error(`无效的 WebSocket 模式: ${wsConfig.mode}`);\n }\n\n // 验证批处理配置\n if (\n wsConfig.batchSize !== undefined &&\n (wsConfig.batchSize < 1 || wsConfig.batchSize > 1000)\n ) {\n throw new Error(`无效的批处理大小: ${wsConfig.batchSize}`);\n }\n\n // 验证最大连接数\n if (\n wsConfig.maxConnections &&\n (wsConfig.maxConnections < 1 || wsConfig.maxConnections > 10000)\n ) {\n throw new Error(`无效的最大连接数: ${wsConfig.maxConnections}`);\n }\n }\n}\n","import { EventEmitter } from \"node:events\";\nimport { Logger } from \"../Logger.js\";\nimport { ProxyMCPServer } from \"../ProxyMCPServer.js\";\nimport { configManager } from \"../configManager.js\";\nimport { createHTTPServer } from \"../core/ServerFactory.js\";\nimport type { UnifiedMCPServer } from \"../core/UnifiedMCPServer.js\";\nimport type { HTTPConfig } from \"../transports/HTTPAdapter.js\";\n\nconst logger = new Logger();\n\n/**\n * MCP 服务器类(重构版)\n * 现在基于 UnifiedMCPServer 和传输层抽象实现\n * 保持向后兼容的 API,但内部使用新的统一架构\n */\nexport class MCPServer extends EventEmitter {\n private unifiedServer: UnifiedMCPServer | null = null;\n private proxyMCPServer: ProxyMCPServer | null = null;\n private port: number;\n private isStarted = false;\n\n constructor(port = 3000) {\n super();\n this.port = port;\n }\n\n /**\n * 初始化统一服务器\n */\n private async initializeUnifiedServer(): Promise<void> {\n if (this.unifiedServer) {\n return;\n }\n\n logger.info(\"初始化统一 MCP 服务器\");\n\n try {\n // 创建 HTTP 模式的统一服务器\n const httpConfig: HTTPConfig = {\n name: \"http\",\n port: this.port,\n host: \"0.0.0.0\",\n enableSSE: true,\n enableRPC: true,\n };\n\n this.unifiedServer = await createHTTPServer(httpConfig);\n\n // 转发统一服务器的事件\n this.unifiedServer.on(\"started\", () => this.emit(\"started\"));\n this.unifiedServer.on(\"stopped\", () => this.emit(\"stopped\"));\n this.unifiedServer.on(\"connectionRegistered\", (connection) => {\n this.emit(\"connectionRegistered\", connection);\n });\n\n logger.info(\"统一 MCP 服务器初始化完成\");\n } catch (error) {\n logger.error(\"初始化统一 MCP 服务器失败\", error);\n throw error;\n }\n }\n\n /**\n * 初始化小智接入点连接\n */\n private async initializeMCPClient(): Promise<void> {\n try {\n // 获取小智接入点配置\n let mcpEndpoint: string | null = null;\n try {\n if (configManager.configExists()) {\n const endpoints = configManager.getMcpEndpoints();\n mcpEndpoint =\n endpoints.find((ep) => ep && !ep.includes(\"<请填写\")) || null;\n }\n } catch (error) {\n logger.warn(\"从配置中读取小智接入点失败:\", error);\n }\n\n // 只有在配置了有效端点时才启动连接\n if (mcpEndpoint) {\n this.proxyMCPServer = new ProxyMCPServer(mcpEndpoint);\n\n // 设置服务管理器\n if (this.unifiedServer) {\n this.proxyMCPServer.setServiceManager(\n this.unifiedServer.getServiceManager()\n );\n }\n\n await this.proxyMCPServer.connect();\n logger.info(\"小智接入点连接成功\");\n } else {\n logger.info(\"未配置有效的小智接入点,跳过连接\");\n }\n } catch (error) {\n logger.error(\"初始化小智接入点连接失败:\", error);\n }\n }\n\n /**\n * 启动服务器\n */\n public async start(): Promise<void> {\n if (this.isStarted) {\n logger.warn(\"服务器已启动\");\n return;\n }\n\n try {\n logger.info(\"启动 MCP 服务器\");\n\n // 初始化统一服务器\n await this.initializeUnifiedServer();\n\n // 启动统一服务器\n if (this.unifiedServer) {\n await this.unifiedServer.start();\n }\n\n // 初始化小智接入点连接(不阻塞服务器启动)\n this.initializeMCPClient().catch((error) => {\n logger.error(\"初始化小智接入点连接失败:\", error);\n });\n\n this.isStarted = true;\n this.emit(\"started\");\n logger.info(\"MCP 服务器启动成功\");\n } catch (error) {\n logger.error(\"启动 MCP 服务器失败:\", error);\n throw error;\n }\n }\n\n /**\n * 停止服务器\n */\n public async stop(): Promise<void> {\n if (!this.isStarted) {\n logger.warn(\"服务器未启动\");\n return;\n }\n\n try {\n logger.info(\"停止 MCP 服务器\");\n\n // 停止统一服务器\n if (this.unifiedServer) {\n await this.unifiedServer.stop();\n }\n\n // 停止小智接入点连接\n if (this.proxyMCPServer) {\n this.proxyMCPServer.disconnect();\n this.proxyMCPServer = null;\n }\n\n this.isStarted = false;\n this.emit(\"stopped\");\n logger.info(\"MCP 服务器已停止\");\n } catch (error) {\n logger.error(\"停止 MCP 服务器失败:\", error);\n throw error;\n }\n }\n\n /**\n * 获取服务管理器(向后兼容)\n */\n getServiceManager() {\n return this.unifiedServer?.getServiceManager() || null;\n }\n\n /**\n * 获取消息处理器(向后兼容)\n */\n getMessageHandler() {\n return this.unifiedServer?.getMessageHandler() || null;\n }\n\n /**\n * 获取服务器状态\n */\n getStatus() {\n if (!this.unifiedServer) {\n return {\n isRunning: false,\n port: this.port,\n mode: \"mcp-server\",\n };\n }\n\n const status = this.unifiedServer.getStatus();\n return {\n ...status,\n port: this.port,\n mode: \"mcp-server\",\n proxyConnected: this.proxyMCPServer !== null,\n };\n }\n\n /**\n * 检查服务器是否正在运行\n */\n isRunning(): boolean {\n return this.isStarted && (this.unifiedServer?.isServerRunning() || false);\n }\n}\n","/**\n * 服务管理服务\n */\n\nimport { ConfigError, ServiceError } from \"../errors/index.js\";\nimport type {\n ServiceManager as IServiceManager,\n ProcessManager,\n ServiceStartOptions,\n ServiceStatus,\n} from \"../interfaces/Service.js\";\nimport { PathUtils } from \"../utils/PathUtils.js\";\nimport { PlatformUtils } from \"../utils/PlatformUtils.js\";\nimport { Validation } from \"../utils/Validation.js\";\n\n/**\n * 服务管理器实现\n */\nexport class ServiceManagerImpl implements IServiceManager {\n constructor(\n private processManager: ProcessManager,\n private configManager: any,\n private logger: any\n ) {}\n\n /**\n * 启动服务\n */\n async start(options: ServiceStartOptions): Promise<void> {\n try {\n // 验证启动选项\n this.validateStartOptions(options);\n\n // 清理容器环境状态\n this.processManager.cleanupContainerState();\n\n // 检查服务是否已经在运行\n const status = this.getStatus();\n if (status.running) {\n // 自动停止现有服务并重新启动\n console.log(`检测到服务已在运行 (PID: ${status.pid}),正在自动重启...`);\n\n try {\n // 优雅停止现有进程\n await this.processManager.gracefulKillProcess(status.pid!);\n\n // 清理 PID 文件\n this.processManager.cleanupPidFile();\n\n // 等待一下确保完全停止\n await new Promise((resolve) => setTimeout(resolve, 1000));\n\n console.log(\"现有服务已停止,正在启动新服务...\");\n } catch (stopError) {\n console.warn(\n `停止现有服务时出现警告: ${stopError instanceof Error ? stopError.message : String(stopError)}`\n );\n // 继续尝试启动新服务,因为旧进程可能已经不存在了\n }\n }\n\n // 检查环境配置\n this.checkEnvironment();\n\n // 根据模式启动服务\n switch (options.mode) {\n case \"mcp-server\":\n await this.startMcpServerMode(options);\n break;\n case \"stdio\":\n await this.startStdioMode(options);\n break;\n case \"normal\":\n await this.startNormalMode(options);\n break;\n default:\n await this.startNormalMode(options);\n break;\n }\n } catch (error) {\n if (error instanceof ServiceError) {\n throw error;\n }\n throw ServiceError.startFailed(\n error instanceof Error ? error.message : String(error)\n );\n }\n }\n\n /**\n * 停止服务\n */\n async stop(): Promise<void> {\n try {\n const status = this.getStatus();\n\n if (!status.running) {\n throw ServiceError.notRunning();\n }\n\n // 优雅停止进程\n await this.processManager.gracefulKillProcess(status.pid!);\n\n // 清理 PID 文件\n this.processManager.cleanupPidFile();\n } catch (error) {\n if (error instanceof ServiceError) {\n throw error;\n }\n throw new ServiceError(\n `停止服务失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * 重启服务\n */\n async restart(options: ServiceStartOptions): Promise<void> {\n try {\n // 先停止服务\n const status = this.getStatus();\n if (status.running) {\n await this.stop();\n // 等待一下确保完全停止\n await new Promise((resolve) => setTimeout(resolve, 1000));\n }\n\n // 重新启动服务\n await this.start(options);\n } catch (error) {\n throw new ServiceError(\n `重启服务失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * 获取服务状态\n */\n getStatus(): ServiceStatus {\n return this.processManager.getServiceStatus();\n }\n\n /**\n * 验证启动选项\n */\n private validateStartOptions(options: ServiceStartOptions): void {\n if (options.port !== undefined) {\n Validation.validatePort(options.port);\n }\n\n if (\n options.mode &&\n ![\"normal\", \"mcp-server\", \"stdio\"].includes(options.mode)\n ) {\n throw new ServiceError(`无效的运行模式: ${options.mode}`);\n }\n }\n\n /**\n * 检查环境配置\n */\n private checkEnvironment(): void {\n // 检查配置文件是否存在\n if (!this.configManager.configExists()) {\n throw ConfigError.configNotFound();\n }\n\n // 可以添加更多环境检查\n try {\n const config = this.configManager.getConfig();\n if (!config) {\n throw new ConfigError(\"配置文件无效\");\n }\n } catch (error) {\n if (error instanceof ConfigError) {\n throw error;\n }\n throw new ConfigError(\n `配置文件错误: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * 启动普通模式\n */\n private async startNormalMode(options: ServiceStartOptions): Promise<void> {\n const { spawn } = await import(\"node:child_process\");\n\n if (options.daemon) {\n // 后台模式\n await this.startWebServerInDaemon(options.ui || false);\n } else {\n // 前台模式\n await this.startWebServerInForeground(options.ui || false);\n }\n }\n\n /**\n * 启动 MCP Server 模式\n */\n private async startMcpServerMode(\n options: ServiceStartOptions\n ): Promise<void> {\n const port = options.port || 3000;\n const { spawn } = await import(\"node:child_process\");\n\n if (options.daemon) {\n // 后台模式\n const scriptPath = PathUtils.getExecutablePath(\"cli\");\n const child = spawn(\n \"node\",\n [scriptPath, \"start\", \"--server\", port.toString()],\n {\n detached: true,\n stdio: [\"ignore\", \"ignore\", \"ignore\"], // 完全忽略所有 stdio,避免阻塞\n env: {\n ...process.env,\n XIAOZHI_CONFIG_DIR: PathUtils.getConfigDir(),\n XIAOZHI_DAEMON: \"true\",\n MCP_SERVER_MODE: \"true\",\n },\n }\n );\n\n // 保存 PID 信息\n this.processManager.savePidInfo(child.pid!, \"daemon\");\n\n // 完全分离子进程\n child.unref();\n\n // 输出启动信息后立即退出父进程\n console.log(\n `✅ MCP Server 已在后台启动 (PID: ${child.pid}, Port: ${port})`\n );\n console.log(`💡 使用 'xiaozhi status' 查看状态`);\n\n // 立即退出父进程,释放终端控制权\n process.exit(0);\n } else {\n // 前台模式 - 直接启动 MCP Server\n const { MCPServer } = await import(\"../../services/MCPServer.js\");\n const server = new MCPServer(port);\n\n // 处理退出信号\n const cleanup = async () => {\n await server.stop();\n process.exit(0);\n };\n\n process.on(\"SIGINT\", cleanup);\n process.on(\"SIGTERM\", cleanup);\n\n await server.start();\n }\n }\n\n /**\n * 启动 stdio 模式\n */\n private async startStdioMode(options: ServiceStartOptions): Promise<void> {\n const { spawn } = await import(\"node:child_process\");\n const mcpProxyPath = PathUtils.getMcpServerProxyPath();\n\n // 直接执行 mcpServerProxy,它已经支持 stdio\n const child = spawn(\"node\", [mcpProxyPath], {\n stdio: \"inherit\",\n env: {\n ...process.env,\n XIAOZHI_CONFIG_DIR: PathUtils.getConfigDir(),\n },\n });\n\n // 保存 PID 信息\n this.processManager.savePidInfo(child.pid!, \"foreground\");\n }\n\n /**\n * 后台模式启动 WebServer\n */\n private async startWebServerInDaemon(openBrowser: boolean): Promise<void> {\n const { spawn } = await import(\"node:child_process\");\n const webServerPath = PathUtils.getWebServerStandalonePath();\n\n const fs = await import(\"node:fs\");\n if (!fs.default.existsSync(webServerPath)) {\n throw new ServiceError(`WebServer 文件不存在: ${webServerPath}`);\n }\n\n const args = [webServerPath];\n if (openBrowser) {\n args.push(\"--open-browser\");\n }\n\n const child = spawn(\"node\", args, {\n detached: true,\n stdio: [\"ignore\", \"ignore\", \"ignore\"], // 完全忽略所有 stdio,避免阻塞\n env: {\n ...process.env,\n XIAOZHI_CONFIG_DIR: PathUtils.getConfigDir(),\n XIAOZHI_DAEMON: \"true\",\n },\n });\n\n // 保存 PID 信息\n this.processManager.savePidInfo(child.pid!, \"daemon\");\n\n // 完全分离子进程\n child.unref();\n\n // 输出启动信息后立即退出父进程\n console.log(`✅ 后台服务已启动 (PID: ${child.pid})`);\n console.log(`💡 使用 'xiaozhi status' 查看状态`);\n console.log(`💡 使用 'xiaozhi attach' 查看日志`);\n\n // 立即退出父进程,释放终端控制权\n process.exit(0);\n }\n\n /**\n * 前台模式启动 WebServer\n */\n private async startWebServerInForeground(\n openBrowser: boolean\n ): Promise<void> {\n const { WebServer } = await import(\"../../WebServer.js\");\n const server = new WebServer();\n\n // 处理退出信号\n const cleanup = async () => {\n await server.stop();\n this.processManager.cleanupPidFile();\n process.exit(0);\n };\n\n process.on(\"SIGINT\", cleanup);\n process.on(\"SIGTERM\", cleanup);\n\n // 保存 PID 信息\n this.processManager.savePidInfo(process.pid, \"foreground\");\n\n await server.start();\n\n if (openBrowser) {\n const config = this.configManager.getConfig();\n const port = config?.webServer?.port || 9999;\n await this.openBrowserUrl(`http://localhost:${port}`);\n }\n }\n\n /**\n * 打开浏览器URL\n */\n private async openBrowserUrl(url: string): Promise<void> {\n try {\n const { spawn } = await import(\"node:child_process\");\n const platform = PlatformUtils.getCurrentPlatform();\n\n let command: string;\n let args: string[];\n\n if (platform === \"darwin\") {\n command = \"open\";\n args = [url];\n } else if (platform === \"win32\") {\n command = \"start\";\n args = [\"\", url];\n } else {\n command = \"xdg-open\";\n args = [url];\n }\n\n spawn(command, args, { detached: true, stdio: \"ignore\" });\n console.log(`🌐 已尝试打开浏览器: ${url}`);\n } catch (error) {\n console.log(`⚠️ 自动打开浏览器失败,请手动访问: ${url}`);\n }\n }\n}\n","/**\n * 模板管理服务\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { FileError, ValidationError } from \"../errors/index.js\";\nimport type { TemplateManager as ITemplateManager } from \"../interfaces/Service.js\";\nimport { FileUtils } from \"../utils/FileUtils.js\";\nimport { PathUtils } from \"../utils/PathUtils.js\";\nimport { Validation } from \"../utils/Validation.js\";\n\n/**\n * 模板信息接口\n */\nexport interface TemplateInfo {\n name: string;\n path: string;\n description?: string;\n version?: string;\n author?: string;\n files: string[];\n}\n\n/**\n * 模板创建选项\n */\nexport interface TemplateCreateOptions {\n templateName?: string;\n targetPath: string;\n projectName: string;\n variables?: Record<string, string>;\n}\n\n/**\n * 模板管理器实现\n */\nexport class TemplateManagerImpl implements ITemplateManager {\n private templateCache = new Map<string, TemplateInfo>();\n\n /**\n * 获取可用模板列表\n */\n async getAvailableTemplates(): Promise<TemplateInfo[]> {\n try {\n const templatesDir = PathUtils.findTemplatesDir();\n\n if (!templatesDir) {\n return [];\n }\n\n const templates: TemplateInfo[] = [];\n const templateDirs = fs\n .readdirSync(templatesDir, { withFileTypes: true })\n .filter((dirent) => dirent.isDirectory())\n .map((dirent) => dirent.name);\n\n for (const templateName of templateDirs) {\n try {\n const templateInfo = await this.getTemplateInfo(templateName);\n if (templateInfo) {\n templates.push(templateInfo);\n }\n } catch (error) {\n // 跳过无效的模板目录\n console.warn(`跳过无效模板: ${templateName}`);\n }\n }\n\n return templates;\n } catch (error) {\n throw new FileError(\n \"无法读取模板目录\",\n PathUtils.findTemplatesDir() || \"\"\n );\n }\n }\n\n /**\n * 获取模板信息\n */\n async getTemplateInfo(templateName: string): Promise<TemplateInfo | null> {\n try {\n // 验证模板名称\n Validation.validateTemplateName(templateName);\n\n // 检查缓存\n if (this.templateCache.has(templateName)) {\n return this.templateCache.get(templateName)!;\n }\n\n const templatePath = PathUtils.getTemplatePath(templateName);\n if (!templatePath) {\n return null;\n }\n\n // 读取模板配置文件\n const configPath = path.join(templatePath, \"template.json\");\n let config: any = {};\n\n if (FileUtils.exists(configPath)) {\n try {\n const configContent = FileUtils.readFile(configPath);\n config = JSON.parse(configContent);\n } catch (error) {\n console.warn(`模板配置文件解析失败: ${templateName}`);\n }\n }\n\n // 获取模板文件列表\n const files = this.getTemplateFiles(templatePath);\n\n const templateInfo: TemplateInfo = {\n name: templateName,\n path: templatePath,\n description: config.description || `${templateName} 模板`,\n version: config.version || \"1.0.0\",\n author: config.author,\n files,\n };\n\n // 缓存模板信息\n this.templateCache.set(templateName, templateInfo);\n\n return templateInfo;\n } catch (error) {\n if (error instanceof ValidationError) {\n throw error;\n }\n throw new FileError(`无法获取模板信息: ${templateName}`, \"\");\n }\n }\n\n /**\n * 复制模板到目标目录\n */\n async copyTemplate(templateName: string, targetPath: string): Promise<void> {\n await this.createProject({\n templateName,\n targetPath,\n projectName: path.basename(targetPath),\n });\n }\n\n /**\n * 创建项目\n */\n async createProject(options: TemplateCreateOptions): Promise<void> {\n try {\n // 验证输入参数\n this.validateCreateOptions(options);\n\n // 获取模板信息\n const templateName = options.templateName || \"default\";\n const templateInfo = await this.getTemplateInfo(templateName);\n\n if (!templateInfo) {\n throw new FileError(`模板不存在: ${templateName}`, \"\");\n }\n\n // 检查目标路径\n const targetPath = path.resolve(options.targetPath);\n if (FileUtils.exists(targetPath)) {\n throw FileError.alreadyExists(targetPath);\n }\n\n // 创建项目目录\n FileUtils.ensureDir(targetPath);\n\n // 复制模板文件\n await this.copyTemplateFiles(templateInfo, targetPath, options);\n\n // 处理模板变量替换\n await this.processTemplateVariables(targetPath, options);\n\n console.log(`✅ 项目创建成功: ${targetPath}`);\n } catch (error) {\n if (error instanceof FileError || error instanceof ValidationError) {\n throw error;\n }\n throw new FileError(\n `创建项目失败: ${error instanceof Error ? error.message : String(error)}`,\n options.targetPath\n );\n }\n }\n\n /**\n * 验证模板\n */\n async validateTemplate(templateName: string): Promise<boolean> {\n try {\n const templateInfo = await this.getTemplateInfo(templateName);\n\n if (!templateInfo) {\n return false;\n }\n\n // 检查必要文件是否存在\n const requiredFiles = [\"package.json\"]; // 可以根据需要调整\n\n for (const requiredFile of requiredFiles) {\n const filePath = path.join(templateInfo.path, requiredFile);\n if (!FileUtils.exists(filePath)) {\n console.warn(`模板缺少必要文件: ${requiredFile}`);\n return false;\n }\n }\n\n return true;\n } catch {\n return false;\n }\n }\n\n /**\n * 清除模板缓存\n */\n clearCache(): void {\n this.templateCache.clear();\n }\n\n /**\n * 获取模板文件列表\n */\n private getTemplateFiles(templatePath: string): string[] {\n try {\n const files = FileUtils.listDirectory(templatePath, {\n recursive: true,\n includeHidden: false,\n });\n\n // 过滤掉模板配置文件和其他不需要的文件\n return files.filter((file) => {\n const relativePath = path.relative(templatePath, file);\n return (\n !relativePath.startsWith(\".\") &&\n relativePath !== \"template.json\" &&\n !relativePath.includes(\"node_modules\")\n );\n });\n } catch {\n return [];\n }\n }\n\n /**\n * 验证创建选项\n */\n private validateCreateOptions(options: TemplateCreateOptions): void {\n Validation.validateRequired(options.targetPath, \"targetPath\");\n Validation.validateRequired(options.projectName, \"projectName\");\n Validation.validateProjectName(options.projectName);\n\n if (options.templateName) {\n Validation.validateTemplateName(options.templateName);\n }\n }\n\n /**\n * 复制模板文件\n */\n private async copyTemplateFiles(\n templateInfo: TemplateInfo,\n targetPath: string,\n options: TemplateCreateOptions\n ): Promise<void> {\n try {\n // 复制所有模板文件\n FileUtils.copyDirectory(templateInfo.path, targetPath, {\n exclude: [\"template.json\", \".git\", \"node_modules\"],\n overwrite: false,\n recursive: true,\n });\n } catch (error) {\n throw new FileError(\n `复制模板文件失败: ${error instanceof Error ? error.message : String(error)}`,\n templateInfo.path\n );\n }\n }\n\n /**\n * 处理模板变量替换\n */\n private async processTemplateVariables(\n targetPath: string,\n options: TemplateCreateOptions\n ): Promise<void> {\n try {\n // 默认变量\n const variables = {\n PROJECT_NAME: options.projectName,\n PROJECT_NAME_LOWER: options.projectName.toLowerCase(),\n PROJECT_NAME_UPPER: options.projectName.toUpperCase(),\n ...options.variables,\n };\n\n // 获取需要处理的文件\n const filesToProcess = [\n \"package.json\",\n \"README.md\",\n \"src/**/*.ts\",\n \"src/**/*.js\",\n \"src/**/*.json\",\n ];\n\n for (const pattern of filesToProcess) {\n const files = this.findFilesByPattern(targetPath, pattern);\n\n for (const filePath of files) {\n await this.replaceVariablesInFile(filePath, variables);\n }\n }\n } catch (error) {\n console.warn(\n `处理模板变量失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * 根据模式查找文件\n */\n private findFilesByPattern(basePath: string, pattern: string): string[] {\n try {\n if (!pattern.includes(\"*\")) {\n // 简单文件路径\n const filePath = path.join(basePath, pattern);\n return FileUtils.exists(filePath) ? [filePath] : [];\n }\n\n // 简单的通配符支持\n const files = FileUtils.listDirectory(basePath, { recursive: true });\n const regex = new RegExp(\n pattern.replace(/\\*\\*/g, \".*\").replace(/\\*/g, \"[^/]*\")\n );\n\n return files.filter((file) => {\n const relativePath = path.relative(basePath, file);\n return regex.test(relativePath);\n });\n } catch {\n return [];\n }\n }\n\n /**\n * 替换文件中的变量\n */\n private async replaceVariablesInFile(\n filePath: string,\n variables: Record<string, string>\n ): Promise<void> {\n try {\n let content = FileUtils.readFile(filePath);\n let hasChanges = false;\n\n // 替换变量 {{VARIABLE_NAME}}\n for (const [key, value] of Object.entries(variables)) {\n const regex = new RegExp(`{{\\\\s*${key}\\\\s*}}`, \"g\");\n if (regex.test(content)) {\n content = content.replace(regex, value);\n hasChanges = true;\n }\n }\n\n // 如果有变更,写回文件\n if (hasChanges) {\n FileUtils.writeFile(filePath, content, { overwrite: true });\n }\n } catch (error) {\n console.warn(\n `替换文件变量失败 ${filePath}: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n}\n","/**\n * 依赖注入容器\n */\n\nimport { logger } from \"../Logger.js\";\nimport { configManager } from \"../configManager.js\";\nimport { ErrorHandler } from \"./errors/ErrorHandlers.js\";\nimport type { IDIContainer } from \"./interfaces/Config.js\";\nimport { FileUtils } from \"./utils/FileUtils.js\";\nimport { FormatUtils } from \"./utils/FormatUtils.js\";\nimport { PathUtils } from \"./utils/PathUtils.js\";\nimport { PlatformUtils } from \"./utils/PlatformUtils.js\";\nimport { Validation } from \"./utils/Validation.js\";\nimport { VersionUtils } from \"./utils/VersionUtils.js\";\n\n/**\n * 依赖注入容器实现\n */\nexport class DIContainer implements IDIContainer {\n private instances = new Map<string, any>();\n private factories = new Map<string, () => any>();\n private asyncFactories = new Map<string, () => Promise<any>>();\n private singletons = new Set<string>();\n\n /**\n * 注册服务工厂\n */\n register<T>(key: string, factory: () => T, singleton = false): void {\n this.factories.set(key, factory);\n if (singleton) {\n this.singletons.add(key);\n }\n }\n\n /**\n * 注册单例服务\n */\n registerSingleton<T>(key: string, factory: () => T): void {\n this.register(key, factory, true);\n }\n\n /**\n * 注册实例\n */\n registerInstance<T>(key: string, instance: T): void {\n this.instances.set(key, instance);\n this.singletons.add(key);\n }\n\n /**\n * 获取服务实例\n */\n get<T>(key: string): T {\n // 如果是单例且已经创建过实例,直接返回\n if (this.singletons.has(key) && this.instances.has(key)) {\n return this.instances.get(key);\n }\n\n // 获取工厂函数\n const factory = this.factories.get(key);\n if (!factory) {\n throw new Error(`Service ${key} not registered`);\n }\n\n // 创建实例\n const instance = factory();\n\n // 如果是单例,缓存实例\n if (this.singletons.has(key)) {\n this.instances.set(key, instance);\n }\n\n return instance;\n }\n\n /**\n * 检查服务是否已注册\n */\n has(key: string): boolean {\n return this.factories.has(key) || this.instances.has(key);\n }\n\n /**\n * 清除所有注册的服务\n */\n clear(): void {\n this.instances.clear();\n this.factories.clear();\n this.singletons.clear();\n }\n\n /**\n * 获取所有已注册的服务键\n */\n getRegisteredKeys(): string[] {\n const factoryKeys = Array.from(this.factories.keys());\n const instanceKeys = Array.from(this.instances.keys());\n return [...new Set([...factoryKeys, ...instanceKeys])];\n }\n\n /**\n * 创建默认容器实例\n */\n static create(): DIContainer {\n const container = new DIContainer();\n\n // 注册工具类(单例)\n container.registerSingleton(\"versionUtils\", () => {\n return VersionUtils;\n });\n\n container.registerSingleton(\"platformUtils\", () => {\n return PlatformUtils;\n });\n\n container.registerSingleton(\"formatUtils\", () => {\n return FormatUtils;\n });\n\n container.registerSingleton(\"fileUtils\", () => {\n return FileUtils;\n });\n\n container.registerSingleton(\"pathUtils\", () => {\n return PathUtils;\n });\n\n container.registerSingleton(\"validation\", () => {\n return Validation;\n });\n\n // 注册配置管理器(单例)\n container.registerSingleton(\"configManager\", () => {\n return configManager;\n });\n\n // 注册日志管理器(单例)\n container.registerSingleton(\"logger\", () => {\n return logger;\n });\n\n // 注册错误处理器(单例)\n container.registerSingleton(\"errorHandler\", () => {\n return ErrorHandler;\n });\n\n // 注册服务层\n container.registerSingleton(\"processManager\", () => {\n const ProcessManagerModule = require(\"./services/ProcessManager.js\");\n return new ProcessManagerModule.ProcessManagerImpl();\n });\n\n container.registerSingleton(\"daemonManager\", () => {\n const DaemonManagerModule = require(\"./services/DaemonManager.js\");\n const processManager = container.get(\"processManager\") as any;\n const logger = container.get(\"logger\") as any;\n return new DaemonManagerModule.DaemonManagerImpl(processManager, logger);\n });\n\n container.registerSingleton(\"serviceManager\", () => {\n const ServiceManagerModule = require(\"./services/ServiceManager.js\");\n const processManager = container.get(\"processManager\") as any;\n const configManager = container.get(\"configManager\") as any;\n const logger = container.get(\"logger\") as any;\n return new ServiceManagerModule.ServiceManagerImpl(\n processManager,\n configManager,\n logger\n );\n });\n\n container.registerSingleton(\"templateManager\", () => {\n // 使用动态导入的同步版本\n const TemplateManagerModule = require(\"./services/TemplateManager.js\");\n return new TemplateManagerModule.TemplateManagerImpl();\n });\n\n // 注册命令层(稍后在命令层实现时添加)\n // container.register('serviceCommand', () => {\n // const { ServiceCommand } = require('./commands/ServiceCommand.js');\n // const serviceManager = container.get('serviceManager');\n // const processManager = container.get('processManager');\n // return new ServiceCommand(serviceManager, processManager);\n // });\n\n // container.register('configCommand', () => {\n // const { ConfigCommand } = require('./commands/ConfigCommand.js');\n // const configManager = container.get('configManager');\n // const validation = container.get('validation');\n // return new ConfigCommand(configManager, validation);\n // });\n\n // container.register('projectCommand', () => {\n // const { ProjectCommand } = require('./commands/ProjectCommand.js');\n // const templateManager = container.get('templateManager');\n // const fileUtils = container.get('fileUtils');\n // return new ProjectCommand(templateManager, fileUtils);\n // });\n\n // container.register('mcpCommand', () => {\n // const { McpCommand } = require('./commands/McpCommand.js');\n // return new McpCommand();\n // });\n\n // container.register('infoCommand', () => {\n // const { InfoCommand } = require('./commands/InfoCommand.js');\n // const versionUtils = container.get('versionUtils');\n // const platformUtils = container.get('platformUtils');\n // return new InfoCommand(versionUtils, platformUtils);\n // });\n\n return container;\n }\n}\n\n/**\n * 创建并配置 DI 容器\n */\nexport async function createContainer(): Promise<IDIContainer> {\n return DIContainer.create();\n}\n","import { spawn } from \"node:child_process\";\nimport type { Context } from \"hono\";\nimport { type Logger, logger } from \"../Logger.js\";\nimport { createContainer } from \"../cli/Container.js\";\nimport { type EventBus, getEventBus } from \"../services/EventBus.js\";\nimport type { StatusService } from \"../services/StatusService.js\";\n\n/**\n * 统一响应格式接口\n */\ninterface ApiErrorResponse {\n error: {\n code: string;\n message: string;\n details?: any;\n };\n}\n\ninterface ApiSuccessResponse<T = any> {\n success: boolean;\n data?: T;\n message?: string;\n}\n\n/**\n * 服务 API 处理器\n */\nexport class ServiceApiHandler {\n private logger: Logger;\n private statusService: StatusService;\n private eventBus: EventBus;\n\n constructor(statusService: StatusService) {\n this.logger = logger.withTag(\"ServiceApiHandler\");\n this.statusService = statusService;\n this.eventBus = getEventBus();\n }\n\n /**\n * 创建统一的错误响应\n */\n private createErrorResponse(\n code: string,\n message: string,\n details?: any\n ): ApiErrorResponse {\n return {\n error: {\n code,\n message,\n details,\n },\n };\n }\n\n /**\n * 创建统一的成功响应\n */\n private createSuccessResponse<T>(\n data?: T,\n message?: string\n ): ApiSuccessResponse<T> {\n return {\n success: true,\n data,\n message,\n };\n }\n\n /**\n * 重启服务\n * POST /api/services/restart\n */\n async restartService(c: Context): Promise<Response> {\n try {\n this.logger.info(\"处理服务重启请求\");\n\n // 发射重启请求事件\n this.eventBus.emitEvent(\"service:restart:requested\", {\n source: \"http-api\",\n });\n\n // 更新重启状态\n this.statusService.updateRestartStatus(\"restarting\");\n\n // 异步执行重启,不阻塞响应\n setTimeout(async () => {\n try {\n await this.executeRestart();\n // 服务重启需要一些时间,延迟发送成功状态\n setTimeout(() => {\n this.statusService.updateRestartStatus(\"completed\");\n }, 5000);\n } catch (error) {\n this.logger.error(\"服务重启失败:\", error);\n this.statusService.updateRestartStatus(\n \"failed\",\n error instanceof Error ? error.message : \"未知错误\"\n );\n }\n }, 500);\n\n return c.json(this.createSuccessResponse(null, \"重启请求已接收\"));\n } catch (error) {\n this.logger.error(\"处理重启请求失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"RESTART_REQUEST_ERROR\",\n error instanceof Error ? error.message : \"处理重启请求失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 执行服务重启\n */\n private async executeRestart(): Promise<void> {\n this.logger.info(\"正在重启 MCP 服务...\");\n\n try {\n // 获取当前服务状态\n const container = await createContainer();\n const serviceManager = container.get(\"serviceManager\") as any;\n const status = await serviceManager.getStatus();\n\n if (!status.running) {\n this.logger.warn(\"MCP 服务未运行,尝试启动服务\");\n\n // 如果服务未运行,尝试启动服务\n const startArgs = [\"start\", \"--daemon\"];\n const child = spawn(\"xiaozhi\", startArgs, {\n detached: true,\n stdio: \"ignore\",\n env: {\n ...process.env,\n XIAOZHI_CONFIG_DIR: process.env.XIAOZHI_CONFIG_DIR || process.cwd(),\n },\n });\n child.unref();\n this.logger.info(\"MCP 服务启动命令已发送\");\n return;\n }\n\n // 获取服务运行模式\n const isDaemon = status.mode === \"daemon\";\n\n // 执行重启命令\n const restartArgs = [\"restart\"];\n if (isDaemon) {\n restartArgs.push(\"--daemon\");\n }\n\n // 在子进程中执行重启命令\n const child = spawn(\"xiaozhi\", restartArgs, {\n detached: true,\n stdio: \"ignore\",\n env: {\n ...process.env,\n XIAOZHI_CONFIG_DIR: process.env.XIAOZHI_CONFIG_DIR || process.cwd(),\n },\n });\n\n child.unref();\n this.logger.info(\"MCP 服务重启命令已发送\");\n } catch (error) {\n this.logger.error(\"重启服务失败:\", error);\n throw error;\n }\n }\n\n /**\n * 停止服务\n * POST /api/services/stop\n */\n async stopService(c: Context): Promise<Response> {\n try {\n this.logger.info(\"处理服务停止请求\");\n\n // 执行停止命令\n const stopArgs = [\"stop\"];\n const child = spawn(\"xiaozhi\", stopArgs, {\n detached: true,\n stdio: \"ignore\",\n env: {\n ...process.env,\n XIAOZHI_CONFIG_DIR: process.env.XIAOZHI_CONFIG_DIR || process.cwd(),\n },\n });\n\n child.unref();\n this.logger.info(\"MCP 服务停止命令已发送\");\n\n return c.json(this.createSuccessResponse(null, \"停止请求已接收\"));\n } catch (error) {\n this.logger.error(\"处理停止请求失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"STOP_REQUEST_ERROR\",\n error instanceof Error ? error.message : \"处理停止请求失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 启动服务\n * POST /api/services/start\n */\n async startService(c: Context): Promise<Response> {\n try {\n this.logger.info(\"处理服务启动请求\");\n\n // 执行启动命令\n const startArgs = [\"start\", \"--daemon\"];\n const child = spawn(\"xiaozhi\", startArgs, {\n detached: true,\n stdio: \"ignore\",\n env: {\n ...process.env,\n XIAOZHI_CONFIG_DIR: process.env.XIAOZHI_CONFIG_DIR || process.cwd(),\n },\n });\n\n child.unref();\n this.logger.info(\"MCP 服务启动命令已发送\");\n\n return c.json(this.createSuccessResponse(null, \"启动请求已接收\"));\n } catch (error) {\n this.logger.error(\"处理启动请求失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"START_REQUEST_ERROR\",\n error instanceof Error ? error.message : \"处理启动请求失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 获取服务状态\n * GET /api/services/status\n */\n async getServiceStatus(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理获取服务状态请求\");\n\n const container = await createContainer();\n const serviceManager = container.get(\"serviceManager\") as any;\n const status = await serviceManager.getStatus();\n\n this.logger.debug(\"获取服务状态成功\");\n return c.json(this.createSuccessResponse(status));\n } catch (error) {\n this.logger.error(\"获取服务状态失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"SERVICE_STATUS_READ_ERROR\",\n error instanceof Error ? error.message : \"获取服务状态失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 获取服务健康状态\n * GET /api/services/health\n */\n async getServiceHealth(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理获取服务健康状态请求\");\n\n // 简单的健康检查\n const health = {\n status: \"healthy\",\n timestamp: Date.now(),\n uptime: process.uptime(),\n memory: process.memoryUsage(),\n version: process.version,\n };\n\n this.logger.debug(\"获取服务健康状态成功\");\n return c.json(this.createSuccessResponse(health));\n } catch (error) {\n this.logger.error(\"获取服务健康状态失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"SERVICE_HEALTH_READ_ERROR\",\n error instanceof Error ? error.message : \"获取服务健康状态失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n}\n","import { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { Context } from \"hono\";\nimport { type Logger, logger } from \"../Logger.js\";\n\n/**\n * 静态文件处理器\n */\nexport class StaticFileHandler {\n private logger: Logger;\n private webPath: string | null = null;\n\n constructor() {\n this.logger = logger.withTag(\"StaticFileHandler\");\n this.initializeWebPath();\n }\n\n /**\n * 初始化 Web 路径\n */\n private initializeWebPath(): void {\n try {\n // 获取当前文件所在目录\n const __dirname = dirname(fileURLToPath(import.meta.url));\n\n this.logger.debug(`当前文件目录: ${__dirname}`);\n\n // 确定web目录路径\n // 无论是全局安装还是直接执行,实际运行的都是 dist/cli.js 或 dist/handlers/StaticFileHandler.js\n // 因此静态文件应该位于相对于 dist 目录的 ../web/dist 路径\n const possibleWebPaths = [\n // 主要路径:从 dist 目录向上查找 web/dist\n // 对于 dist/handlers/StaticFileHandler.js -> ../../web/dist\n // 对于 dist/cli.js -> ../web/dist\n join(__dirname, \"..\", \"..\", \"web\", \"dist\"),\n join(__dirname, \"..\", \"web\", \"dist\"),\n\n // 备用路径:查找未构建的 web 目录(开发模式)\n join(__dirname, \"..\", \"..\", \"web\"),\n join(__dirname, \"..\", \"web\"),\n\n // 兜底路径:从源码目录查找(开发模式下的源码执行)\n join(__dirname, \"..\", \"..\", \"..\", \"web\", \"dist\"),\n join(__dirname, \"..\", \"..\", \"..\", \"web\"),\n ];\n\n // 查找第一个存在的路径\n this.webPath =\n possibleWebPaths.find((p) => {\n const exists = existsSync(p);\n this.logger.debug(`检查路径 ${p}: ${exists ? \"存在\" : \"不存在\"}`);\n return exists;\n }) || null;\n\n if (this.webPath) {\n this.logger.info(`静态文件服务路径: ${this.webPath}`);\n } else {\n this.logger.warn(\"未找到静态文件目录\");\n this.logger.debug(\"尝试的路径:\", possibleWebPaths);\n }\n } catch (error) {\n this.logger.error(\"初始化静态文件路径失败:\", error);\n }\n }\n\n /**\n * 处理静态文件请求\n * GET /*\n */\n async handleStaticFile(c: Context): Promise<Response> {\n const pathname = new URL(c.req.url).pathname;\n\n try {\n this.logger.debug(`处理静态文件请求: ${pathname}`);\n\n if (!this.webPath) {\n return this.createErrorPage(c, \"找不到前端资源文件\");\n }\n\n // 处理路径\n let filePath = pathname;\n if (filePath === \"/\") {\n filePath = \"/index.html\";\n }\n\n // 安全性检查:防止路径遍历\n if (filePath.includes(\"..\")) {\n this.logger.warn(`路径遍历攻击尝试: ${filePath}`);\n return c.text(\"Forbidden\", 403);\n }\n\n const fullPath = join(this.webPath, filePath);\n\n // 检查文件是否存在\n if (!existsSync(fullPath)) {\n // 对于 SPA,返回 index.html\n const indexPath = join(this.webPath, \"index.html\");\n if (existsSync(indexPath)) {\n this.logger.debug(`SPA 回退到 index.html: ${pathname}`);\n return this.serveFile(c, indexPath, \"text/html\");\n }\n\n this.logger.debug(`文件不存在: ${fullPath}`);\n return c.text(\"Not Found\", 404);\n }\n\n // 确定 Content-Type\n const contentType = this.getContentType(fullPath);\n\n this.logger.debug(\n `服务静态文件: ${fullPath}, Content-Type: ${contentType}`\n );\n return this.serveFile(c, fullPath, contentType);\n } catch (error) {\n this.logger.error(`服务静态文件错误 (${pathname}):`, error);\n return c.text(\"Internal Server Error\", 500);\n }\n }\n\n /**\n * 服务文件\n */\n private async serveFile(\n c: Context,\n filePath: string,\n contentType: string\n ): Promise<Response> {\n try {\n const content = await readFile(filePath);\n\n // 对于文本文件,返回字符串;对于二进制文件,返回 ArrayBuffer\n if (\n contentType.startsWith(\"text/\") ||\n contentType.includes(\"javascript\") ||\n contentType.includes(\"json\")\n ) {\n return c.text(content.toString(), 200, { \"Content-Type\": contentType });\n }\n\n return c.body(content, 200, { \"Content-Type\": contentType });\n } catch (error) {\n this.logger.error(`读取文件失败: ${filePath}`, error);\n throw error;\n }\n }\n\n /**\n * 获取文件的 Content-Type\n */\n private getContentType(filePath: string): string {\n const ext = filePath.split(\".\").pop()?.toLowerCase();\n\n const contentTypes: Record<string, string> = {\n html: \"text/html\",\n htm: \"text/html\",\n js: \"application/javascript\",\n mjs: \"application/javascript\",\n css: \"text/css\",\n json: \"application/json\",\n png: \"image/png\",\n jpg: \"image/jpeg\",\n jpeg: \"image/jpeg\",\n gif: \"image/gif\",\n svg: \"image/svg+xml\",\n ico: \"image/x-icon\",\n woff: \"font/woff\",\n woff2: \"font/woff2\",\n ttf: \"font/ttf\",\n eot: \"application/vnd.ms-fontobject\",\n pdf: \"application/pdf\",\n txt: \"text/plain\",\n xml: \"application/xml\",\n zip: \"application/zip\",\n tar: \"application/x-tar\",\n gz: \"application/gzip\",\n };\n\n return contentTypes[ext || \"\"] || \"application/octet-stream\";\n }\n\n /**\n * 创建错误页面\n */\n private createErrorPage(c: Context, message: string): Response {\n const errorHtml = `\n <!DOCTYPE html>\n <html>\n <head>\n <title>小智配置管理</title>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <style>\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n max-width: 800px;\n margin: 50px auto;\n padding: 20px;\n line-height: 1.6;\n color: #333;\n }\n .error {\n color: #e53e3e;\n background: #fed7d7;\n padding: 20px;\n border-radius: 8px;\n border-left: 4px solid #e53e3e;\n }\n .info {\n background: #e6f3ff;\n padding: 20px;\n border-radius: 8px;\n border-left: 4px solid #0066cc;\n margin-top: 20px;\n }\n pre {\n background: #f5f5f5;\n padding: 10px;\n border-radius: 4px;\n overflow-x: auto;\n }\n h1 {\n color: #2d3748;\n margin-bottom: 20px;\n }\n </style>\n </head>\n <body>\n <h1>小智配置管理</h1>\n <div class=\"error\">\n <p><strong>错误:</strong>${message}</p>\n </div>\n <div class=\"info\">\n <p><strong>解决方案:</strong></p>\n <p>请先构建前端项目:</p>\n <pre>cd web && pnpm install && pnpm build</pre>\n <p>然后重新启动服务器。</p>\n </div>\n </body>\n </html>\n `;\n\n return c.html(errorHtml);\n }\n\n /**\n * 检查静态文件目录是否存在\n */\n isWebPathAvailable(): boolean {\n return this.webPath !== null && existsSync(this.webPath);\n }\n\n /**\n * 获取静态文件目录路径\n */\n getWebPath(): string | null {\n return this.webPath;\n }\n\n /**\n * 重新初始化 Web 路径\n */\n reinitializeWebPath(): void {\n this.initializeWebPath();\n }\n}\n","import type { Context } from \"hono\";\nimport { type Logger, logger } from \"../Logger.js\";\nimport type { StatusService } from \"../services/StatusService.js\";\n\n/**\n * 统一响应格式接口\n */\ninterface ApiErrorResponse {\n error: {\n code: string;\n message: string;\n details?: any;\n };\n}\n\ninterface ApiSuccessResponse<T = any> {\n success: boolean;\n data?: T;\n message?: string;\n}\n\n/**\n * 状态 API 处理器\n */\nexport class StatusApiHandler {\n private logger: Logger;\n private statusService: StatusService;\n\n constructor(statusService: StatusService) {\n this.logger = logger.withTag(\"StatusApiHandler\");\n this.statusService = statusService;\n }\n\n /**\n * 创建统一的错误响应\n */\n private createErrorResponse(\n code: string,\n message: string,\n details?: any\n ): ApiErrorResponse {\n return {\n error: {\n code,\n message,\n details,\n },\n };\n }\n\n /**\n * 创建统一的成功响应\n */\n private createSuccessResponse<T>(\n data?: T,\n message?: string\n ): ApiSuccessResponse<T> {\n return {\n success: true,\n data,\n message,\n };\n }\n\n /**\n * 获取完整状态\n * GET /api/status\n */\n async getStatus(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理获取状态请求\");\n const status = this.statusService.getFullStatus();\n this.logger.debug(\"获取状态成功\");\n return c.json(this.createSuccessResponse(status));\n } catch (error) {\n this.logger.error(\"获取状态失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"STATUS_READ_ERROR\",\n error instanceof Error ? error.message : \"获取状态失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 获取客户端状态\n * GET /api/status/client\n */\n async getClientStatus(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理获取客户端状态请求\");\n const clientStatus = this.statusService.getClientStatus();\n this.logger.debug(\"获取客户端状态成功\");\n return c.json(this.createSuccessResponse(clientStatus));\n } catch (error) {\n this.logger.error(\"获取客户端状态失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"CLIENT_STATUS_READ_ERROR\",\n error instanceof Error ? error.message : \"获取客户端状态失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 获取重启状态\n * GET /api/status/restart\n */\n async getRestartStatus(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理获取重启状态请求\");\n const restartStatus = this.statusService.getRestartStatus();\n this.logger.debug(\"获取重启状态成功\");\n return c.json(this.createSuccessResponse(restartStatus));\n } catch (error) {\n this.logger.error(\"获取重启状态失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"RESTART_STATUS_READ_ERROR\",\n error instanceof Error ? error.message : \"获取重启状态失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 检查客户端是否连接\n * GET /api/status/connected\n */\n async checkClientConnected(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理检查客户端连接请求\");\n const connected = this.statusService.isClientConnected();\n this.logger.debug(`客户端连接状态: ${connected}`);\n return c.json(this.createSuccessResponse({ connected }));\n } catch (error) {\n this.logger.error(\"检查客户端连接失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"CLIENT_CONNECTION_CHECK_ERROR\",\n error instanceof Error ? error.message : \"检查客户端连接失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 获取最后心跳时间\n * GET /api/status/heartbeat\n */\n async getLastHeartbeat(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理获取最后心跳时间请求\");\n const lastHeartbeat = this.statusService.getLastHeartbeat();\n this.logger.debug(\"获取最后心跳时间成功\");\n return c.json(this.createSuccessResponse({ lastHeartbeat }));\n } catch (error) {\n this.logger.error(\"获取最后心跳时间失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"HEARTBEAT_READ_ERROR\",\n error instanceof Error ? error.message : \"获取最后心跳时间失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 获取活跃的 MCP 服务器列表\n * GET /api/status/mcp-servers\n */\n async getActiveMCPServers(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理获取活跃 MCP 服务器请求\");\n const servers = this.statusService.getActiveMCPServers();\n this.logger.debug(\"获取活跃 MCP 服务器成功\");\n return c.json(this.createSuccessResponse({ servers }));\n } catch (error) {\n this.logger.error(\"获取活跃 MCP 服务器失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"ACTIVE_MCP_SERVERS_READ_ERROR\",\n error instanceof Error ? error.message : \"获取活跃 MCP 服务器失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 更新客户端状态\n * PUT /api/status/client\n */\n async updateClientStatus(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理更新客户端状态请求\");\n const statusUpdate = await c.req.json();\n\n // 验证请求体\n if (!statusUpdate || typeof statusUpdate !== \"object\") {\n const errorResponse = this.createErrorResponse(\n \"INVALID_REQUEST_BODY\",\n \"请求体必须是有效的状态对象\"\n );\n return c.json(errorResponse, 400);\n }\n\n this.statusService.updateClientInfo(statusUpdate, \"http-api\");\n this.logger.info(\"客户端状态更新成功\");\n\n return c.json(this.createSuccessResponse(null, \"客户端状态更新成功\"));\n } catch (error) {\n this.logger.error(\"更新客户端状态失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"CLIENT_STATUS_UPDATE_ERROR\",\n error instanceof Error ? error.message : \"更新客户端状态失败\"\n );\n return c.json(errorResponse, 400);\n }\n }\n\n /**\n * 设置活跃的 MCP 服务器列表\n * PUT /api/status/mcp-servers\n */\n async setActiveMCPServers(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理设置活跃 MCP 服务器请求\");\n const { servers } = await c.req.json();\n\n // 验证请求体\n if (!Array.isArray(servers)) {\n const errorResponse = this.createErrorResponse(\n \"INVALID_REQUEST_BODY\",\n \"servers 必须是字符串数组\"\n );\n return c.json(errorResponse, 400);\n }\n\n this.statusService.setActiveMCPServers(servers);\n this.logger.info(\"活跃 MCP 服务器设置成功\");\n\n return c.json(\n this.createSuccessResponse(null, \"活跃 MCP 服务器设置成功\")\n );\n } catch (error) {\n this.logger.error(\"设置活跃 MCP 服务器失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"ACTIVE_MCP_SERVERS_UPDATE_ERROR\",\n error instanceof Error ? error.message : \"设置活跃 MCP 服务器失败\"\n );\n return c.json(errorResponse, 400);\n }\n }\n\n /**\n * 重置状态\n * POST /api/status/reset\n */\n async resetStatus(c: Context): Promise<Response> {\n try {\n this.logger.info(\"处理重置状态请求\");\n this.statusService.reset();\n this.logger.info(\"状态重置成功\");\n return c.json(this.createSuccessResponse(null, \"状态重置成功\"));\n } catch (error) {\n this.logger.error(\"重置状态失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"STATUS_RESET_ERROR\",\n error instanceof Error ? error.message : \"重置状态失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n}\n","import { type Logger, logger } from \"../Logger.js\";\nimport type { AppConfig } from \"../configManager.js\";\nimport { type EventBus, getEventBus } from \"./EventBus.js\";\nimport type { ClientInfo, RestartStatus } from \"./StatusService.js\";\n\n/**\n * WebSocket 客户端接口\n */\nexport interface WebSocketClient {\n id: string;\n ws: any; // WebSocket 实例\n readyState: number;\n send: (data: string) => void;\n}\n\n/**\n * 通知消息接口\n */\nexport interface NotificationMessage {\n type: string;\n data?: any;\n timestamp?: number;\n}\n\n/**\n * 通知服务 - 统一的通知管理服务\n */\nexport class NotificationService {\n private logger: Logger;\n private eventBus: EventBus;\n private clients: Map<string, WebSocketClient> = new Map();\n private messageQueue: Map<string, NotificationMessage[]> = new Map();\n private maxQueueSize = 100;\n\n constructor() {\n this.logger = logger.withTag(\"NotificationService\");\n this.eventBus = getEventBus();\n this.setupEventListeners();\n }\n\n /**\n * 设置事件监听器\n */\n private setupEventListeners(): void {\n // 监听配置更新事件\n this.eventBus.onEvent(\"config:updated\", (data) => {\n this.broadcastConfigUpdate(data.config);\n });\n\n // 监听状态更新事件\n this.eventBus.onEvent(\"status:updated\", (data) => {\n this.broadcastStatusUpdate(data.status);\n });\n\n // 监听重启状态事件\n this.eventBus.onEvent(\"service:restart:started\", (data) => {\n this.broadcastRestartStatus(\"restarting\", undefined, data.timestamp);\n });\n\n this.eventBus.onEvent(\"service:restart:completed\", (data) => {\n this.broadcastRestartStatus(\"completed\", undefined, data.timestamp);\n });\n\n this.eventBus.onEvent(\"service:restart:failed\", (data) => {\n this.broadcastRestartStatus(\"failed\", data.error.message, data.timestamp);\n });\n\n // 监听通知广播事件\n this.eventBus.onEvent(\"notification:broadcast\", (data) => {\n if (data.target) {\n this.sendToClient(data.target, data.type, data.data);\n } else {\n this.broadcast(data.type, data.data);\n }\n });\n }\n\n /**\n * 注册 WebSocket 客户端\n */\n registerClient(clientId: string, ws: any): void {\n try {\n const client: WebSocketClient = {\n id: clientId,\n ws,\n readyState: ws.readyState,\n send: (data: string) => {\n if (ws.readyState === 1) {\n // WebSocket.OPEN\n ws.send(data);\n }\n },\n };\n\n this.clients.set(clientId, client);\n this.logger.info(`WebSocket 客户端已注册: ${clientId}`);\n this.logger.debug(`当前客户端数量: ${this.clients.size}`);\n\n // 发送排队的消息\n this.sendQueuedMessages(clientId);\n\n // 发射客户端连接事件\n this.eventBus.emitEvent(\"websocket:client:connected\", {\n clientId,\n timestamp: Date.now(),\n });\n } catch (error) {\n this.logger.error(`注册客户端失败: ${clientId}`, error);\n this.eventBus.emitEvent(\"notification:error\", {\n error: error instanceof Error ? error : new Error(String(error)),\n type: \"client:register\",\n });\n }\n }\n\n /**\n * 注销 WebSocket 客户端\n */\n unregisterClient(clientId: string): void {\n try {\n if (this.clients.has(clientId)) {\n this.clients.delete(clientId);\n this.messageQueue.delete(clientId);\n this.logger.info(`WebSocket 客户端已注销: ${clientId}`);\n this.logger.debug(`剩余客户端数量: ${this.clients.size}`);\n\n // 发射客户端断开事件\n this.eventBus.emitEvent(\"websocket:client:disconnected\", {\n clientId,\n timestamp: Date.now(),\n });\n }\n } catch (error) {\n this.logger.error(`注销客户端失败: ${clientId}`, error);\n }\n }\n\n /**\n * 广播消息给所有客户端\n */\n broadcast(type: string, data?: any): void {\n const message: NotificationMessage = {\n type,\n data,\n timestamp: Date.now(),\n };\n\n this.logger.debug(`广播消息: ${type}`, { clientCount: this.clients.size });\n\n for (const [clientId, client] of this.clients) {\n this.sendMessageToClient(client, message, clientId);\n }\n }\n\n /**\n * 发送消息给特定客户端\n */\n sendToClient(clientId: string, type: string, data?: any): void {\n const message: NotificationMessage = {\n type,\n data,\n timestamp: Date.now(),\n };\n\n const client = this.clients.get(clientId);\n if (client) {\n this.sendMessageToClient(client, message, clientId);\n } else {\n // 客户端不在线,将消息加入队列\n this.queueMessage(clientId, message);\n }\n }\n\n /**\n * 发送消息给客户端\n */\n private sendMessageToClient(\n client: WebSocketClient,\n message: NotificationMessage,\n clientId: string\n ): void {\n try {\n if (client.ws.readyState === 1) {\n // WebSocket.OPEN\n const messageStr = JSON.stringify(message);\n client.send(messageStr);\n this.logger.debug(`消息已发送给客户端 ${clientId}: ${message.type}`);\n } else {\n // 连接不可用,将消息加入队列\n this.queueMessage(clientId, message);\n this.logger.warn(`客户端 ${clientId} 连接不可用,消息已加入队列`);\n }\n } catch (error) {\n this.logger.error(`发送消息给客户端 ${clientId} 失败:`, error);\n this.queueMessage(clientId, message);\n this.eventBus.emitEvent(\"notification:error\", {\n error: error instanceof Error ? error : new Error(String(error)),\n type: \"message:send\",\n });\n }\n }\n\n /**\n * 将消息加入队列\n */\n private queueMessage(clientId: string, message: NotificationMessage): void {\n if (!this.messageQueue.has(clientId)) {\n this.messageQueue.set(clientId, []);\n }\n\n const queue = this.messageQueue.get(clientId)!;\n queue.push(message);\n\n // 限制队列大小\n if (queue.length > this.maxQueueSize) {\n queue.shift(); // 移除最旧的消息\n this.logger.warn(`客户端 ${clientId} 消息队列已满,移除最旧消息`);\n }\n }\n\n /**\n * 发送排队的消息\n */\n private sendQueuedMessages(clientId: string): void {\n const queue = this.messageQueue.get(clientId);\n if (!queue || queue.length === 0) {\n return;\n }\n\n const client = this.clients.get(clientId);\n if (!client) {\n return;\n }\n\n this.logger.info(`发送 ${queue.length} 条排队消息给客户端 ${clientId}`);\n\n for (const message of queue) {\n this.sendMessageToClient(client, message, clientId);\n }\n\n // 清空队列\n this.messageQueue.delete(clientId);\n }\n\n /**\n * 广播配置更新\n */\n broadcastConfigUpdate(config: AppConfig): void {\n this.broadcast(\"configUpdate\", config);\n }\n\n /**\n * 广播状态更新\n */\n broadcastStatusUpdate(status: ClientInfo): void {\n this.broadcast(\"statusUpdate\", status);\n }\n\n /**\n * 广播重启状态\n */\n broadcastRestartStatus(\n status: \"restarting\" | \"completed\" | \"failed\",\n error?: string,\n timestamp?: number\n ): void {\n const restartStatus: RestartStatus = {\n status,\n error,\n timestamp: timestamp || Date.now(),\n };\n\n this.broadcast(\"restartStatus\", restartStatus);\n }\n\n /**\n * 获取客户端统计信息\n */\n getClientStats(): {\n totalClients: number;\n connectedClients: number;\n queuedMessages: number;\n } {\n const connectedClients = Array.from(this.clients.values()).filter(\n (client) => client.ws.readyState === 1\n ).length;\n\n const queuedMessages = Array.from(this.messageQueue.values()).reduce(\n (total, queue) => total + queue.length,\n 0\n );\n\n return {\n totalClients: this.clients.size,\n connectedClients,\n queuedMessages,\n };\n }\n\n /**\n * 清理断开的客户端\n */\n cleanupDisconnectedClients(): void {\n const disconnectedClients: string[] = [];\n\n for (const [clientId, client] of this.clients) {\n if (client.ws.readyState !== 1) {\n // Not WebSocket.OPEN\n disconnectedClients.push(clientId);\n }\n }\n\n for (const clientId of disconnectedClients) {\n this.unregisterClient(clientId);\n }\n\n if (disconnectedClients.length > 0) {\n this.logger.info(`清理了 ${disconnectedClients.length} 个断开的客户端`);\n }\n }\n\n /**\n * 销毁通知服务\n */\n destroy(): void {\n this.logger.info(\"销毁通知服务\");\n this.clients.clear();\n this.messageQueue.clear();\n }\n}\n","import { type Logger, logger } from \"../Logger.js\";\nimport { type EventBus, getEventBus } from \"./EventBus.js\";\n\n/**\n * 客户端信息接口\n */\nexport interface ClientInfo {\n status: \"connected\" | \"disconnected\";\n mcpEndpoint: string;\n activeMCPServers: string[];\n lastHeartbeat?: number;\n}\n\n/**\n * 重启状态接口\n */\nexport interface RestartStatus {\n status: \"restarting\" | \"completed\" | \"failed\";\n error?: string;\n timestamp: number;\n}\n\n/**\n * 状态服务 - 统一的状态管理服务\n */\nexport class StatusService {\n private logger: Logger;\n private eventBus: EventBus;\n private clientInfo: ClientInfo = {\n status: \"disconnected\",\n mcpEndpoint: \"\",\n activeMCPServers: [],\n };\n private restartStatus?: RestartStatus;\n private heartbeatTimeout?: NodeJS.Timeout;\n private readonly HEARTBEAT_TIMEOUT = 35000; // 35 seconds\n\n constructor() {\n this.logger = logger.withTag(\"StatusService\");\n this.eventBus = getEventBus();\n }\n\n /**\n * 获取客户端状态\n */\n getClientStatus(): ClientInfo {\n return { ...this.clientInfo };\n }\n\n /**\n * 更新客户端信息\n */\n updateClientInfo(info: Partial<ClientInfo>, source = \"unknown\"): void {\n try {\n const oldStatus = { ...this.clientInfo };\n this.clientInfo = { ...this.clientInfo, ...info };\n\n if (info.lastHeartbeat) {\n this.clientInfo.lastHeartbeat = Date.now();\n }\n\n // Reset heartbeat timeout when receiving client status\n if (info.status === \"connected\") {\n this.resetHeartbeatTimeout();\n }\n\n this.logger.debug(`客户端状态更新,来源: ${source}`, {\n old: oldStatus,\n new: this.clientInfo,\n });\n\n // 发射状态更新事件\n this.eventBus.emitEvent(\"status:updated\", {\n status: this.clientInfo,\n source,\n });\n } catch (error) {\n this.logger.error(\"更新客户端状态失败:\", error);\n this.eventBus.emitEvent(\"status:error\", {\n error: error instanceof Error ? error : new Error(String(error)),\n operation: \"updateClientInfo\",\n });\n }\n }\n\n /**\n * 获取重启状态\n */\n getRestartStatus(): RestartStatus | undefined {\n return this.restartStatus ? { ...this.restartStatus } : undefined;\n }\n\n /**\n * 更新重启状态\n */\n updateRestartStatus(\n status: \"restarting\" | \"completed\" | \"failed\",\n error?: string\n ): void {\n try {\n this.restartStatus = {\n status,\n error,\n timestamp: Date.now(),\n };\n\n this.logger.info(`重启状态更新: ${status}`, { error });\n\n // 根据状态发射不同的事件\n switch (status) {\n case \"restarting\":\n this.eventBus.emitEvent(\"service:restart:started\", {\n timestamp: this.restartStatus.timestamp,\n });\n break;\n case \"completed\":\n this.eventBus.emitEvent(\"service:restart:completed\", {\n timestamp: this.restartStatus.timestamp,\n });\n break;\n case \"failed\":\n this.eventBus.emitEvent(\"service:restart:failed\", {\n error: new Error(error || \"重启失败\"),\n timestamp: this.restartStatus.timestamp,\n });\n break;\n }\n } catch (error) {\n this.logger.error(\"更新重启状态失败:\", error);\n this.eventBus.emitEvent(\"status:error\", {\n error: error instanceof Error ? error : new Error(String(error)),\n operation: \"updateRestartStatus\",\n });\n }\n }\n\n /**\n * 获取完整状态信息\n */\n getFullStatus(): {\n client: ClientInfo;\n restart?: RestartStatus;\n timestamp: number;\n } {\n return {\n client: this.getClientStatus(),\n restart: this.getRestartStatus(),\n timestamp: Date.now(),\n };\n }\n\n /**\n * 重置心跳超时\n */\n private resetHeartbeatTimeout(): void {\n // Clear existing timeout\n if (this.heartbeatTimeout) {\n clearTimeout(this.heartbeatTimeout);\n }\n\n // Set new timeout\n this.heartbeatTimeout = setTimeout(() => {\n this.logger.warn(\"客户端心跳超时,标记为断开连接\");\n this.updateClientInfo({ status: \"disconnected\" }, \"heartbeat-timeout\");\n }, this.HEARTBEAT_TIMEOUT);\n }\n\n /**\n * 清除心跳超时\n */\n clearHeartbeatTimeout(): void {\n if (this.heartbeatTimeout) {\n clearTimeout(this.heartbeatTimeout);\n this.heartbeatTimeout = undefined;\n }\n }\n\n /**\n * 检查客户端是否连接\n */\n isClientConnected(): boolean {\n return this.clientInfo.status === \"connected\";\n }\n\n /**\n * 获取最后心跳时间\n */\n getLastHeartbeat(): number | undefined {\n return this.clientInfo.lastHeartbeat;\n }\n\n /**\n * 获取活跃的 MCP 服务器列表\n */\n getActiveMCPServers(): string[] {\n return [...this.clientInfo.activeMCPServers];\n }\n\n /**\n * 设置活跃的 MCP 服务器列表\n */\n setActiveMCPServers(servers: string[]): void {\n this.updateClientInfo(\n { activeMCPServers: [...servers] },\n \"mcp-servers-update\"\n );\n }\n\n /**\n * 设置 MCP 端点\n */\n setMcpEndpoint(endpoint: string): void {\n this.updateClientInfo({ mcpEndpoint: endpoint }, \"mcp-endpoint-update\");\n }\n\n /**\n * 重置状态\n */\n reset(): void {\n this.logger.info(\"重置状态服务\");\n this.clearHeartbeatTimeout();\n this.clientInfo = {\n status: \"disconnected\",\n mcpEndpoint: \"\",\n activeMCPServers: [],\n };\n this.restartStatus = undefined;\n }\n\n /**\n * 销毁状态服务\n */\n destroy(): void {\n this.logger.info(\"销毁状态服务\");\n this.clearHeartbeatTimeout();\n this.reset();\n }\n}\n","import { createServer } from \"node:http\";\nimport { serve } from \"@hono/node-server\";\nimport { Hono } from \"hono\";\nimport { cors } from \"hono/cors\";\nimport { WebSocketServer } from \"ws\";\nimport { type Logger, logger } from \"./Logger.js\";\nimport { ProxyMCPServer, type Tool } from \"./ProxyMCPServer.js\";\nimport { convertLegacyToNew } from \"./adapters/ConfigAdapter.js\";\nimport { createContainer } from \"./cli/Container.js\";\nimport { configManager } from \"./configManager.js\";\nimport type { AppConfig, MCPServerConfig } from \"./configManager.js\";\n// MCPTransportType 已移除,不再需要导入\nimport type { MCPServiceManager } from \"./services/MCPServiceManager.js\";\nimport { MCPServiceManagerSingleton } from \"./services/MCPServiceManagerSingleton.js\";\nimport type { XiaozhiConnectionManager } from \"./services/XiaozhiConnectionManager.js\";\nimport { XiaozhiConnectionManagerSingleton } from \"./services/XiaozhiConnectionManagerSingleton.js\";\n\nimport { ConfigApiHandler } from \"./handlers/ConfigApiHandler.js\";\nimport { HeartbeatHandler } from \"./handlers/HeartbeatHandler.js\";\nimport { RealtimeNotificationHandler } from \"./handlers/RealtimeNotificationHandler.js\";\nimport { ServiceApiHandler } from \"./handlers/ServiceApiHandler.js\";\nimport { StaticFileHandler } from \"./handlers/StaticFileHandler.js\";\nimport { StatusApiHandler } from \"./handlers/StatusApiHandler.js\";\nimport { ConfigService } from \"./services/ConfigService.js\";\n// 导入新的服务和处理器\nimport {\n type EventBus,\n destroyEventBus,\n getEventBus,\n} from \"./services/EventBus.js\";\nimport { NotificationService } from \"./services/NotificationService.js\";\nimport { StatusService } from \"./services/StatusService.js\";\n\n// 统一错误响应格式\ninterface ApiErrorResponse {\n error: {\n code: string;\n message: string;\n details?: any;\n };\n}\n\n// 统一成功响应格式\ninterface ApiSuccessResponse<T = any> {\n success: boolean;\n data?: T;\n message?: string;\n}\n\n// 硬编码常量已移除,改为配置驱动\ninterface ClientInfo {\n status: \"connected\" | \"disconnected\";\n mcpEndpoint: string;\n activeMCPServers: string[];\n lastHeartbeat?: number;\n}\n\n/**\n * WebServer - 主控制器,协调各个服务和处理器\n */\nexport class WebServer {\n private app: Hono;\n private httpServer: any = null;\n private wss: WebSocketServer | null = null;\n private logger: Logger;\n private port: number;\n\n // 事件总线\n private eventBus: EventBus;\n\n // 服务层\n private configService: ConfigService;\n private statusService: StatusService;\n private notificationService: NotificationService;\n\n // HTTP API 处理器\n private configApiHandler: ConfigApiHandler;\n private statusApiHandler: StatusApiHandler;\n private serviceApiHandler: ServiceApiHandler;\n private staticFileHandler: StaticFileHandler;\n\n // WebSocket 处理器\n private realtimeNotificationHandler: RealtimeNotificationHandler;\n private heartbeatHandler: HeartbeatHandler;\n\n // 心跳监控\n private heartbeatMonitorInterval?: NodeJS.Timeout;\n\n // 向后兼容的属性\n private proxyMCPServer: ProxyMCPServer | undefined;\n private xiaozhiConnectionManager: XiaozhiConnectionManager | undefined;\n private mcpServiceManager: MCPServiceManager | undefined;\n\n /**\n * 创建统一的错误响应\n * @deprecated 使用处理器中的方法替代\n */\n private createErrorResponse(\n code: string,\n message: string,\n details?: any\n ): ApiErrorResponse {\n return {\n error: {\n code,\n message,\n details,\n },\n };\n }\n\n /**\n * 创建统一的成功响应\n * @deprecated 使用处理器中的方法替代\n */\n private createSuccessResponse<T>(\n data?: T,\n message?: string\n ): ApiSuccessResponse<T> {\n return {\n success: true,\n data,\n message,\n };\n }\n\n /**\n * 记录废弃功能使用警告\n * @deprecated 使用处理器中的方法替代\n */\n private logDeprecationWarning(feature: string, alternative: string): void {\n this.logger.warn(\n `[DEPRECATED] ${feature} 功能已废弃,请使用 ${alternative} 替代`\n );\n }\n\n constructor(port?: number) {\n // 端口配置\n try {\n this.port = port ?? configManager.getWebUIPort() ?? 9999;\n } catch (error) {\n // 配置读取失败时使用默认端口\n this.port = port ?? 9999;\n }\n this.logger = logger.withTag(\"WebServer\");\n\n // 初始化事件总线\n this.eventBus = getEventBus();\n\n // 初始化服务层\n this.configService = new ConfigService();\n this.statusService = new StatusService();\n this.notificationService = new NotificationService();\n\n // 初始化 HTTP API 处理器\n this.configApiHandler = new ConfigApiHandler();\n this.statusApiHandler = new StatusApiHandler(this.statusService);\n this.serviceApiHandler = new ServiceApiHandler(this.statusService);\n this.staticFileHandler = new StaticFileHandler();\n\n // 初始化 WebSocket 处理器\n this.realtimeNotificationHandler = new RealtimeNotificationHandler(\n this.notificationService,\n this.statusService\n );\n this.heartbeatHandler = new HeartbeatHandler(\n this.statusService,\n this.notificationService\n );\n\n // 初始化 Hono 应用\n this.app = new Hono();\n this.setupMiddleware();\n this.setupRoutes();\n\n this.logger.info(\"WebServer 架构重构完成 - 第二阶段:模块化拆分\");\n\n // HTTP 服务器和 WebSocket 服务器将在 start() 方法中初始化\n }\n\n /**\n * 初始化所有连接(配置驱动)\n */\n private async initializeConnections(): Promise<void> {\n try {\n this.logger.info(\"开始初始化连接...\");\n\n // 1. 读取配置\n const config = await this.loadConfiguration();\n\n // 2. 初始化 MCP 服务管理器\n this.mcpServiceManager = await MCPServiceManagerSingleton.getInstance();\n\n // 3. 从配置加载 MCP 服务\n await this.loadMCPServicesFromConfig(config.mcpServers);\n\n // 4. 获取工具列表\n const tools = this.mcpServiceManager.getAllTools();\n this.logger.info(`已加载 ${tools.length} 个工具`);\n\n // 5. 初始化小智接入点连接\n await this.initializeXiaozhiConnection(config.mcpEndpoint, tools);\n\n this.logger.info(\"所有连接初始化完成\");\n } catch (error) {\n this.logger.error(\"连接初始化失败:\", error);\n throw error;\n }\n }\n\n /**\n * 加载配置文件\n */\n private async loadConfiguration(): Promise<{\n mcpEndpoint: string | string[];\n mcpServers: Record<string, MCPServerConfig>;\n webUIPort: number;\n }> {\n if (!configManager.configExists()) {\n throw new Error(\"配置文件不存在,请先运行 'xiaozhi init' 初始化配置\");\n }\n\n // 在加载配置前,先清理无效的服务器工具配置\n // 确保 mcpServerConfig 与 mcpServers 保持同步\n configManager.cleanupInvalidServerToolsConfig();\n\n const config = configManager.getConfig();\n\n return {\n mcpEndpoint: config.mcpEndpoint,\n mcpServers: config.mcpServers,\n webUIPort: config.webUI?.port ?? 9999,\n };\n }\n\n /**\n * 从配置加载 MCP 服务\n */\n private async loadMCPServicesFromConfig(\n mcpServers: Record<string, MCPServerConfig>\n ): Promise<void> {\n if (!this.mcpServiceManager) {\n throw new Error(\"MCPServiceManager 未初始化\");\n }\n\n for (const [name, config] of Object.entries(mcpServers)) {\n this.logger.info(`添加 MCP 服务配置: ${name}`);\n // 使用配置适配器转换配置格式\n const serviceConfig = convertLegacyToNew(name, config);\n this.mcpServiceManager.addServiceConfig(name, serviceConfig);\n }\n\n await this.mcpServiceManager.startAllServices();\n this.logger.info(\"所有 MCP 服务已启动\");\n }\n\n /**\n * 初始化小智接入点连接\n */\n private async initializeXiaozhiConnection(\n mcpEndpoint: string | string[],\n tools: Tool[]\n ): Promise<void> {\n // 处理多端点配置\n const endpoints = Array.isArray(mcpEndpoint) ? mcpEndpoint : [mcpEndpoint];\n const validEndpoints = endpoints.filter(\n (ep) => ep && !ep.includes(\"<请填写\")\n );\n\n if (validEndpoints.length === 0) {\n this.logger.warn(\"未配置有效的小智接入点,跳过连接\");\n return;\n }\n\n this.logger.info(\n `初始化小智接入点连接管理器,端点数量: ${validEndpoints.length}`\n );\n this.logger.debug(\"有效端点列表:\", validEndpoints);\n\n try {\n // 获取小智连接管理器单例\n this.xiaozhiConnectionManager =\n await XiaozhiConnectionManagerSingleton.getInstance({\n healthCheckInterval: 30000,\n reconnectInterval: 5000,\n maxReconnectAttempts: 10,\n loadBalanceStrategy: \"round-robin\",\n connectionTimeout: 10000,\n });\n\n // 设置 MCP 服务管理器\n if (this.mcpServiceManager) {\n this.xiaozhiConnectionManager.setServiceManager(this.mcpServiceManager);\n }\n\n // 初始化连接管理器\n await this.xiaozhiConnectionManager.initialize(validEndpoints, tools);\n\n // 连接所有端点\n await this.xiaozhiConnectionManager.connect();\n\n // 设置配置变更监听器\n this.xiaozhiConnectionManager.on(\"configChange\", (event: any) => {\n this.logger.info(`小智连接配置变更: ${event.type}`, event.data);\n });\n\n this.logger.info(\n `小智接入点连接管理器初始化完成,管理 ${validEndpoints.length} 个端点`\n );\n } catch (error) {\n this.logger.error(\"小智接入点连接管理器初始化失败:\", error);\n\n // 如果新的连接管理器失败,回退到原有的单连接模式(向后兼容)\n this.logger.warn(\"回退到单连接模式\");\n const validEndpoint = validEndpoints[0];\n\n this.logger.info(`初始化单个小智接入点连接: ${validEndpoint}`);\n this.proxyMCPServer = new ProxyMCPServer(validEndpoint);\n\n if (this.mcpServiceManager) {\n this.proxyMCPServer.setServiceManager(this.mcpServiceManager);\n }\n\n // 使用重连机制连接到小智接入点\n await this.connectWithRetry(\n () => this.proxyMCPServer!.connect(),\n \"小智接入点连接\"\n );\n this.logger.info(\"小智接入点连接成功(单连接模式)\");\n }\n }\n\n /**\n * 获取最佳的小智连接(用于向后兼容)\n */\n private getBestXiaozhiConnection(): ProxyMCPServer | null {\n if (this.xiaozhiConnectionManager) {\n return this.xiaozhiConnectionManager.selectBestConnection();\n }\n return this.proxyMCPServer || null;\n }\n\n /**\n * 获取小智连接状态信息\n */\n getXiaozhiConnectionStatus(): any {\n if (this.xiaozhiConnectionManager) {\n return {\n type: \"multi-endpoint\",\n manager: {\n healthyConnections:\n this.xiaozhiConnectionManager.getHealthyConnections().length,\n totalConnections:\n this.xiaozhiConnectionManager.getConnectionStatus().length,\n loadBalanceStats: this.xiaozhiConnectionManager.getLoadBalanceStats(),\n healthCheckStats: this.xiaozhiConnectionManager.getHealthCheckStats(),\n reconnectStats: this.xiaozhiConnectionManager.getReconnectStats(),\n },\n connections: this.xiaozhiConnectionManager.getConnectionStatus(),\n };\n }\n\n if (this.proxyMCPServer) {\n return {\n type: \"single-endpoint\",\n connected: true,\n endpoint: \"unknown\",\n };\n }\n\n return {\n type: \"none\",\n connected: false,\n };\n }\n\n /**\n * 带重试的连接方法\n */\n private async connectWithRetry<T>(\n connectionFn: () => Promise<T>,\n context: string,\n maxAttempts = 5,\n initialDelay = 1000,\n maxDelay = 30000,\n backoffMultiplier = 2\n ): Promise<T> {\n let lastError: Error | null = null;\n\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n this.logger.info(`${context} - 尝试连接 (${attempt}/${maxAttempts})`);\n return await connectionFn();\n } catch (error) {\n lastError = error as Error;\n this.logger.warn(`${context} - 连接失败:`, error);\n\n if (attempt < maxAttempts) {\n const delay = Math.min(\n initialDelay * backoffMultiplier ** (attempt - 1),\n maxDelay\n );\n this.logger.info(`${context} - ${delay}ms 后重试...`);\n await this.sleep(delay);\n }\n }\n }\n\n throw new Error(\n `${context} - 连接失败,已达到最大重试次数: ${lastError?.message}`\n );\n }\n\n /**\n * 延迟工具方法\n */\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n private setupMiddleware() {\n // CORS 中间件\n this.app?.use(\n \"*\",\n cors({\n origin: \"*\",\n allowMethods: [\"GET\", \"POST\", \"PUT\", \"OPTIONS\"],\n allowHeaders: [\"Content-Type\"],\n })\n );\n\n // 错误处理中间件\n this.app?.onError((err, c) => {\n this.logger.error(\"HTTP request error:\", err);\n const errorResponse = this.createErrorResponse(\n \"INTERNAL_SERVER_ERROR\",\n \"服务器内部错误\",\n process.env.NODE_ENV === \"development\" ? err.stack : undefined\n );\n return c.json(errorResponse, 500);\n });\n }\n\n private setupRoutes() {\n // 配置相关 API 路由\n this.app?.get(\"/api/config\", (c) => this.configApiHandler.getConfig(c));\n this.app?.put(\"/api/config\", (c) => this.configApiHandler.updateConfig(c));\n this.app?.get(\"/api/config/mcp-endpoint\", (c) =>\n this.configApiHandler.getMcpEndpoint(c)\n );\n this.app?.get(\"/api/config/mcp-endpoints\", (c) =>\n this.configApiHandler.getMcpEndpoints(c)\n );\n this.app?.get(\"/api/config/mcp-servers\", (c) =>\n this.configApiHandler.getMcpServers(c)\n );\n this.app?.get(\"/api/config/connection\", (c) =>\n this.configApiHandler.getConnectionConfig(c)\n );\n this.app?.post(\"/api/config/reload\", (c) =>\n this.configApiHandler.reloadConfig(c)\n );\n this.app?.get(\"/api/config/path\", (c) =>\n this.configApiHandler.getConfigPath(c)\n );\n this.app?.get(\"/api/config/exists\", (c) =>\n this.configApiHandler.checkConfigExists(c)\n );\n\n // 状态相关 API 路由\n this.app?.get(\"/api/status\", (c) => this.statusApiHandler.getStatus(c));\n this.app?.get(\"/api/status/client\", (c) =>\n this.statusApiHandler.getClientStatus(c)\n );\n this.app?.get(\"/api/status/restart\", (c) =>\n this.statusApiHandler.getRestartStatus(c)\n );\n this.app?.get(\"/api/status/connected\", (c) =>\n this.statusApiHandler.checkClientConnected(c)\n );\n this.app?.get(\"/api/status/heartbeat\", (c) =>\n this.statusApiHandler.getLastHeartbeat(c)\n );\n this.app?.get(\"/api/status/mcp-servers\", (c) =>\n this.statusApiHandler.getActiveMCPServers(c)\n );\n this.app?.put(\"/api/status/client\", (c) =>\n this.statusApiHandler.updateClientStatus(c)\n );\n this.app?.put(\"/api/status/mcp-servers\", (c) =>\n this.statusApiHandler.setActiveMCPServers(c)\n );\n this.app?.post(\"/api/status/reset\", (c) =>\n this.statusApiHandler.resetStatus(c)\n );\n\n // 服务相关 API 路由\n this.app?.post(\"/api/services/restart\", (c) =>\n this.serviceApiHandler.restartService(c)\n );\n this.app?.post(\"/api/services/stop\", (c) =>\n this.serviceApiHandler.stopService(c)\n );\n this.app?.post(\"/api/services/start\", (c) =>\n this.serviceApiHandler.startService(c)\n );\n this.app?.get(\"/api/services/status\", (c) =>\n this.serviceApiHandler.getServiceStatus(c)\n );\n this.app?.get(\"/api/services/health\", (c) =>\n this.serviceApiHandler.getServiceHealth(c)\n );\n\n // 处理未知的 API 路由\n this.app?.all(\"/api/*\", async (c) => {\n const errorResponse = this.createErrorResponse(\n \"API_NOT_FOUND\",\n `API 端点不存在: ${c.req.path}`\n );\n return c.json(errorResponse, 404);\n });\n\n // 静态文件服务 - 放在最后作为回退\n this.app.get(\"*\", (c) => this.staticFileHandler.handleStaticFile(c));\n }\n\n private setupWebSocket() {\n if (!this.wss) return;\n\n this.wss.on(\"connection\", (ws) => {\n // 生成客户端 ID\n const clientId = `client-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n\n this.logger.info(`WebSocket 客户端已连接: ${clientId}`);\n this.logger.debug(\n `当前 WebSocket 连接数: ${this.wss?.clients.size || 0}`\n );\n\n // 注册客户端到通知服务\n this.realtimeNotificationHandler.handleClientConnect(ws, clientId);\n this.heartbeatHandler.handleClientConnect(clientId);\n\n ws.on(\"message\", async (message) => {\n try {\n const data = JSON.parse(message.toString());\n\n // 根据消息类型分发到不同的处理器\n if (data.type === \"clientStatus\") {\n await this.heartbeatHandler.handleClientStatus(ws, data, clientId);\n } else {\n await this.realtimeNotificationHandler.handleMessage(\n ws,\n data,\n clientId\n );\n }\n } catch (error) {\n this.logger.error(\"WebSocket message error:\", error);\n const errorResponse = {\n type: \"error\",\n error: {\n code: \"MESSAGE_PARSE_ERROR\",\n message: error instanceof Error ? error.message : \"消息解析失败\",\n timestamp: Date.now(),\n },\n };\n ws.send(JSON.stringify(errorResponse));\n }\n });\n\n ws.on(\"close\", () => {\n this.logger.info(`WebSocket 客户端已断开连接: ${clientId}`);\n this.logger.debug(\n `剩余 WebSocket 连接数: ${this.wss?.clients.size || 0}`\n );\n\n // 处理客户端断开连接\n this.realtimeNotificationHandler.handleClientDisconnect(clientId);\n this.heartbeatHandler.handleClientDisconnect(clientId);\n });\n\n ws.on(\"error\", (error) => {\n this.logger.error(`WebSocket 连接错误 (${clientId}):`, error);\n });\n\n // 发送初始数据\n this.realtimeNotificationHandler.sendInitialData(ws, clientId);\n });\n }\n\n public async start(): Promise<void> {\n // 检查服务器是否已经启动\n if (this.httpServer) {\n this.logger.warn(\"Web server is already running\");\n return;\n }\n\n // 1. 启动 HTTP 服务器\n const server = serve({\n fetch: this.app.fetch,\n port: this.port,\n hostname: \"0.0.0.0\", // 绑定到所有网络接口,支持 Docker 部署\n createServer,\n });\n\n // 保存服务器实例\n this.httpServer = server;\n\n // 设置 WebSocket 服务器\n this.wss = new WebSocketServer({ server: this.httpServer });\n this.setupWebSocket();\n\n // 启动心跳监控\n this.heartbeatMonitorInterval =\n this.heartbeatHandler.startHeartbeatMonitoring();\n\n this.logger.info(`Web server listening on http://0.0.0.0:${this.port}`);\n this.logger.info(`Local access: http://localhost:${this.port}`);\n\n // 输出架构重构信息\n this.logger.info(\"=== 通信架构重构信息 - 第二阶段完成 ===\");\n this.logger.info(\"✅ 模块化拆分: HTTP/WebSocket 处理器独立\");\n this.logger.info(\n \"✅ 服务层抽象: ConfigService, StatusService, NotificationService\"\n );\n this.logger.info(\"✅ 事件驱动机制: EventBus 实现模块间解耦通信\");\n this.logger.info(\"✅ HTTP API 职责: 配置管理、状态查询、服务控制\");\n this.logger.info(\"✅ WebSocket 职责: 实时通知、心跳检测、事件广播\");\n this.logger.info(\n \"⚠️ 已废弃的 WebSocket 消息: getConfig, updateConfig, getStatus, restartService\"\n );\n this.logger.info(\"📖 推荐使用对应的 HTTP API 替代废弃的 WebSocket 消息\");\n this.logger.info(\"================================================\");\n\n // 2. 初始化所有连接(配置驱动)\n try {\n await this.initializeConnections();\n this.logger.info(\"所有连接初始化完成\");\n } catch (error) {\n this.logger.error(\"连接初始化失败,但 Web 服务器继续运行:\", error);\n // 连接失败不影响 Web 服务器启动,用户可以通过界面查看错误信息\n }\n }\n\n public stop(): Promise<void> {\n return new Promise((resolve) => {\n let resolved = false;\n\n const doResolve = () => {\n if (!resolved) {\n resolved = true;\n resolve();\n }\n };\n\n // 停止 MCP 客户端\n this.proxyMCPServer?.disconnect();\n\n // 停止心跳监控\n if (this.heartbeatMonitorInterval) {\n this.heartbeatHandler.stopHeartbeatMonitoring(\n this.heartbeatMonitorInterval\n );\n this.heartbeatMonitorInterval = undefined;\n }\n\n // 强制断开所有 WebSocket 客户端连接\n if (this.wss) {\n for (const client of this.wss.clients) {\n client.terminate();\n }\n\n // 关闭 WebSocket 服务器\n this.wss.close(() => {\n // 强制关闭 HTTP 服务器,不等待现有连接\n if (this.httpServer) {\n this.httpServer.close(() => {\n this.logger.info(\"Web server stopped\");\n doResolve();\n });\n } else {\n this.logger.info(\"Web server stopped\");\n doResolve();\n }\n\n // 设置超时,如果 2 秒内没有关闭则强制退出\n setTimeout(() => {\n this.logger.info(\"Web server force stopped\");\n doResolve();\n }, 2000);\n });\n } else {\n this.logger.info(\"Web server stopped\");\n doResolve();\n }\n });\n }\n\n /**\n * 销毁 WebServer 实例,清理所有资源\n */\n public destroy(): void {\n this.logger.info(\"销毁 WebServer 实例\");\n\n // 停止心跳监控\n if (this.heartbeatMonitorInterval) {\n this.heartbeatHandler.stopHeartbeatMonitoring(\n this.heartbeatMonitorInterval\n );\n this.heartbeatMonitorInterval = undefined;\n }\n\n // 销毁服务层\n this.statusService.destroy();\n this.notificationService.destroy();\n\n // 销毁事件总线\n destroyEventBus();\n\n // 断开 MCP 连接\n this.proxyMCPServer?.disconnect();\n\n this.logger.info(\"WebServer 实例已销毁\");\n }\n}\n","#!/usr/bin/env node\n\n/**\n * WebServer 独立启动脚本\n * 用于后台模式启动,替代原有的 adaptiveMCPPipe 启动方式\n */\n\n// 动态导入避免 CLI 代码执行\nasync function importModules() {\n const webServerModule = await import(\"./WebServer.js\");\n const configModule = await import(\"./configManager.js\");\n const loggerModule = await import(\"./Logger.js\");\n return {\n WebServer: webServerModule.WebServer,\n configManager: configModule.configManager,\n logger: loggerModule.logger,\n };\n}\n\nimport { spawn } from \"node:child_process\";\n\nasync function main() {\n const args = process.argv.slice(2);\n const openBrowser = args.includes(\"--open-browser\");\n\n try {\n // 动态导入模块\n const { WebServer, configManager, logger } = await importModules();\n\n // 初始化日志\n if (process.env.XIAOZHI_CONFIG_DIR) {\n logger.initLogFile(process.env.XIAOZHI_CONFIG_DIR);\n logger.enableFileLogging(true);\n }\n\n // 启动 WebServer\n const webServer = new WebServer();\n await webServer.start();\n\n logger.info(\"[WEBSERVER_STANDALONE] WebServer 启动成功\");\n\n // 自动打开浏览器\n if (openBrowser) {\n const port = configManager.getWebUIPort();\n const url = `http://localhost:${port}`;\n await openBrowserUrl(url);\n }\n\n // 处理退出信号\n const cleanup = async () => {\n logger.info(\"[WEBSERVER_STANDALONE] 正在停止 WebServer...\");\n await webServer.stop();\n process.exit(0);\n };\n\n process.on(\"SIGINT\", cleanup);\n process.on(\"SIGTERM\", cleanup);\n } catch (error) {\n console.error(\"WebServer 启动失败:\", error);\n process.exit(1);\n }\n}\n\n/**\n * 打开浏览器URL\n */\nasync function openBrowserUrl(url: string): Promise<void> {\n try {\n const platform = process.platform;\n\n let command: string;\n let args: string[];\n\n if (platform === \"darwin\") {\n command = \"open\";\n args = [url];\n } else if (platform === \"win32\") {\n command = \"start\";\n args = [\"\", url];\n } else {\n command = \"xdg-open\";\n args = [url];\n }\n\n spawn(command, args, { detached: true, stdio: \"ignore\" });\n console.log(`已尝试打开浏览器: ${url}`);\n } catch (error) {\n console.warn(\"自动打开浏览器失败:\", error);\n }\n}\n\n// 检查是否为直接执行\nif (import.meta.url === `file://${process.argv[1]}`) {\n main();\n}\n"],"mappings":";ggBAAA,IAAAA,GAAA,GAAAC,EAAAD,GAAA,YAAAE,GAAA,WAAAC,IAAA,UAAYC,MAAQ,KACpB,UAAYC,MAAU,OACtB,OAAOC,OAAW,QAClB,OAAOC,OAAU,OAQjB,SAASC,GAAeC,EAAoB,CAC1C,IAAMC,EAAOD,EAAK,YAAY,EACxBE,EAAQ,OAAOF,EAAK,SAAS,EAAI,CAAC,EAAE,SAAS,EAAG,GAAG,EACnDG,EAAM,OAAOH,EAAK,QAAQ,CAAC,EAAE,SAAS,EAAG,GAAG,EAC5CI,EAAQ,OAAOJ,EAAK,SAAS,CAAC,EAAE,SAAS,EAAG,GAAG,EAC/CK,EAAU,OAAOL,EAAK,WAAW,CAAC,EAAE,SAAS,EAAG,GAAG,EACnDM,EAAU,OAAON,EAAK,WAAW,CAAC,EAAE,SAAS,EAAG,GAAG,EAEzD,MAAO,GAAGC,CAAI,IAAIC,CAAK,IAAIC,CAAG,IAAIC,CAAK,IAAIC,CAAO,IAAIC,CAAO,EAC/D,CApBA,IAiCab,GAqZAC,EAtbba,EAAAC,EAAA,kBAWSC,EAAAV,GAAA,kBAsBIN,GAAN,KAAa,CAjCpB,MAiCoB,CAAAgB,EAAA,eACV,YAA6B,KAC7B,aACA,aACA,eAAiB,GAAK,KAAO,KAC7B,YAAc,EAEtB,aAAc,CAEZ,KAAK,aAAe,QAAQ,IAAI,iBAAmB,OAGnD,KAAK,aAAe,KAAK,mBAAmB,CAC9C,CAEQ,oBAAiC,CACvC,IAAMC,EAA8B,CAAC,EAGrC,GAAI,CAAC,KAAK,aAAc,CAEtB,IAAMC,EAAgB,KAAK,6BAA6B,EACxDD,EAAQ,KAAK,CACX,MAAO,QACP,OAAQC,CACV,CAAC,CACH,CAGA,OAAI,KAAK,aACPD,EAAQ,KAAK,CACX,MAAO,QACP,OAAQZ,GAAK,YAAY,CACvB,KAAM,KAAK,YACX,KAAM,GACN,OAAQ,GACR,MAAO,EACT,CAAC,CACH,CAAC,EAICY,EAAQ,SAAW,GACrBA,EAAQ,KAAK,CACX,MAAO,QACP,OAAQZ,GAAK,YAAY,CAAE,KAAM,WAAY,CAAC,CAChD,CAAC,EAGIA,GACL,CACE,MAAO,QAEP,UACEA,GAAK,kBAAkB,UAAY,IAAM,WAAW,KAAK,IAAI,CAAC,IAChE,WAAY,CAEV,MAAOW,EAAA,CAACG,EAAgBC,KAAoB,CAAE,MAAOA,CAAO,GAArD,QACT,EAEA,KAAM,KACN,YAAa,CAEX,IAAKf,GAAK,gBAAgB,MAASgB,GAAaA,EAClD,CACF,EACAhB,GAAK,YAAYY,EAAS,CAAE,OAAQ,EAAK,CAAC,CAC5C,CACF,CAEQ,8BAA+B,CAErC,IAAMK,EAAW,IAAI,IAAI,CACvB,CAAC,GAAI,CAAE,KAAM,QAAS,MAAOlB,GAAM,IAAK,CAAC,EACzC,CAAC,GAAI,CAAE,KAAM,OAAQ,MAAOA,GAAM,IAAK,CAAC,EACxC,CAAC,GAAI,CAAE,KAAM,OAAQ,MAAOA,GAAM,MAAO,CAAC,EAC1C,CAAC,GAAI,CAAE,KAAM,QAAS,MAAOA,GAAM,GAAI,CAAC,EACxC,CAAC,GAAI,CAAE,KAAM,QAAS,MAAOA,GAAM,GAAI,CAAC,CAC1C,CAAC,EAED,MAAO,CACL,MAAOY,EAACO,GAAkB,CACxB,GAAI,CACF,IAAMC,EAAS,KAAK,MAAMD,CAAK,EACzBE,EAAU,KAAK,8BAA8BD,EAAQF,CAAQ,EAEnE,KAAK,UAAU,GAAGG,CAAO;AAAA,CAAI,CAC/B,MAAgB,CAEd,KAAK,UAAUF,CAAK,CACtB,CACF,EAVO,QAWT,CACF,CAKQ,UAAUG,EAAuB,CACvC,GAAI,CACE,QAAQ,QAAU,OAAO,QAAQ,OAAO,OAAU,WACpD,QAAQ,OAAO,MAAMA,CAAO,EACnB,SAAW,OAAO,QAAQ,OAAU,YAE7C,QAAQ,MAAMA,EAAQ,KAAK,CAAC,CAEhC,MAAgB,CAEhB,CACF,CAEQ,8BACNF,EACAF,EACQ,CACR,IAAMK,EAAYrB,GAAe,IAAI,IAAM,EAErCsB,EAAYN,EAAS,IAAIE,EAAO,KAAK,GAAK,CAC9C,KAAM,UACN,MAAOR,EAACa,GAAiBA,EAAlB,QACT,EACMC,EAAeF,EAAU,MAAM,IAAIA,EAAU,IAAI,GAAG,EAGtDH,EAAUD,EAAO,IACrB,GAAIA,EAAO,MAAQ,MAAM,QAAQA,EAAO,IAAI,EAAG,CAC7C,IAAMO,EAAUP,EAAO,KACpB,IAAKQ,GACJ,OAAOA,GAAQ,SAAW,KAAK,UAAUA,CAAG,EAAI,OAAOA,CAAG,CAC5D,EACC,KAAK,GAAG,EACXP,EAAU,GAAGA,CAAO,IAAIM,CAAO,EACjC,CAEA,MAAO,IAAIJ,CAAS,KAAKG,CAAY,IAAIL,CAAO,EAClD,CAMA,YAAYQ,EAA0B,CACpC,KAAK,YAAmB,OAAKA,EAAY,aAAa,EAGtD,KAAK,sBAAsB,EAGnB,aAAW,KAAK,WAAW,GAC9B,gBAAc,KAAK,YAAa,EAAE,EAIvC,KAAK,aAAe,KAAK,mBAAmB,CAC9C,CAMA,kBAAkBC,EAAuB,CAGnCA,GAAU,KAAK,cAEjB,KAAK,aAAe,KAAK,mBAAmB,EAEhD,CAiBA,KAAKC,KAAkCC,EAAmB,CACpD,OAAOD,GAAiB,SACtBC,EAAK,SAAW,EAClB,KAAK,aAAa,KAAKD,CAAY,EAEnC,KAAK,aAAa,KAAK,CAAE,KAAAC,CAAK,EAAGD,CAAY,EAI/C,KAAK,aAAa,KAAKA,EAAcC,EAAK,CAAC,GAAK,EAAE,CAEtD,CAIA,QAAQD,KAAkCC,EAAmB,CAEvD,OAAOD,GAAiB,SACtBC,EAAK,SAAW,EAClB,KAAK,aAAa,KAAKD,CAAY,EAEnC,KAAK,aAAa,KAAK,CAAE,KAAAC,CAAK,EAAGD,CAAY,EAG/C,KAAK,aAAa,KAAKA,EAAcC,EAAK,CAAC,GAAK,EAAE,CAEtD,CAIA,KAAKD,KAAkCC,EAAmB,CACpD,OAAOD,GAAiB,SACtBC,EAAK,SAAW,EAClB,KAAK,aAAa,KAAKD,CAAY,EAEnC,KAAK,aAAa,KAAK,CAAE,KAAAC,CAAK,EAAGD,CAAY,EAG/C,KAAK,aAAa,KAAKA,EAAcC,EAAK,CAAC,GAAK,EAAE,CAEtD,CAIA,MAAMD,KAAkCC,EAAmB,CACzD,GAAI,OAAOD,GAAiB,SAC1B,GAAIC,EAAK,SAAW,EAClB,KAAK,aAAa,MAAMD,CAAY,MAC/B,CAEL,IAAME,EAAYD,EAAK,IAAKJ,GACtBA,aAAe,MACV,CACL,QAASA,EAAI,QACb,MAAOA,EAAI,MACX,KAAMA,EAAI,KACV,MAAOA,EAAI,KACb,EAEKA,CACR,EACD,KAAK,aAAa,MAAM,CAAE,KAAMK,CAAU,EAAGF,CAAY,CAC3D,KACK,CAEL,IAAMG,EAAc,KAAK,mBAAmBH,CAAY,EACxD,KAAK,aAAa,MAAMG,EAAaF,EAAK,CAAC,GAAK,EAAE,CACpD,CACF,CAIA,MAAMD,KAAkCC,EAAmB,CACrD,OAAOD,GAAiB,SACtBC,EAAK,SAAW,EAClB,KAAK,aAAa,MAAMD,CAAY,EAEpC,KAAK,aAAa,MAAM,CAAE,KAAAC,CAAK,EAAGD,CAAY,EAGhD,KAAK,aAAa,MAAMA,EAAcC,EAAK,CAAC,GAAK,EAAE,CAEvD,CAIA,IAAID,KAAkCC,EAAmB,CAEnD,OAAOD,GAAiB,SACtBC,EAAK,SAAW,EAClB,KAAK,aAAa,KAAKD,CAAY,EAEnC,KAAK,aAAa,KAAK,CAAE,KAAAC,CAAK,EAAGD,CAAY,EAG/C,KAAK,aAAa,KAAKA,EAAcC,EAAK,CAAC,GAAK,EAAE,CAEtD,CAKQ,mBAAmBG,EAAe,CACxC,IAAMC,EAAW,CAAE,GAAGD,CAAI,EAG1B,OAAW,CAACE,EAAKC,CAAK,IAAK,OAAO,QAAQF,CAAQ,EAC5CE,aAAiB,QACnBF,EAASC,CAAG,EAAI,CACd,QAASC,EAAM,QACf,MAAOA,EAAM,MACb,KAAMA,EAAM,KACZ,MAAOA,EAAM,KACf,GAIJ,OAAOF,CACT,CAKQ,uBAA8B,CACpC,GAAI,GAAC,KAAK,aAAe,CAAI,aAAW,KAAK,WAAW,GAIxD,GAAI,CACe,WAAS,KAAK,WAAW,EAChC,KAAO,KAAK,gBACpB,KAAK,cAAc,CAEvB,MAAgB,CAEhB,CACF,CAKQ,eAAsB,CAC5B,GAAK,KAAK,YAEV,GAAI,CACF,IAAMG,EAAc,UAAQ,KAAK,WAAW,EACtCC,EAAe,WAAS,KAAK,YAAa,MAAM,EAGtD,QAASC,EAAI,KAAK,YAAc,EAAGA,GAAK,EAAGA,IAAK,CAC9C,IAAMC,EAAe,OAAKH,EAAQ,GAAGC,CAAO,IAAIC,CAAC,MAAM,EACjDE,EAAe,OAAKJ,EAAQ,GAAGC,CAAO,IAAIC,EAAI,CAAC,MAAM,EAEpD,aAAWC,CAAO,IACnBD,IAAM,KAAK,YAAc,EAExB,aAAWC,CAAO,EAElB,aAAWA,EAASC,CAAO,EAGpC,CAGA,IAAMC,EAAwB,OAAKL,EAAQ,GAAGC,CAAO,QAAQ,EAC1D,aAAW,KAAK,YAAaI,CAAgB,CAClD,MAAgB,CAEhB,CACF,CAKA,gBAAuB,CACrB,GAAK,KAAK,YAEV,GAAI,CACF,IAAML,EAAc,UAAQ,KAAK,WAAW,EACtCC,EAAe,WAAS,KAAK,YAAa,MAAM,EAGtD,QAASC,EAAI,KAAK,YAAc,EAAGA,GAAK,KAAK,YAAc,GAAIA,IAAK,CAClE,IAAMC,EAAe,OAAKH,EAAQ,GAAGC,CAAO,IAAIC,CAAC,MAAM,EAChD,aAAWC,CAAO,GACpB,aAAWA,CAAO,CAEzB,CACF,MAAgB,CAEhB,CACF,CAKA,kBAAkBG,EAAiBC,EAAwB,CACzD,KAAK,eAAiBD,EACtB,KAAK,YAAcC,CACrB,CAOA,QAAQC,EAAsB,CAE5B,OAAO,IACT,CAKA,OAAc,CAGd,CACF,EAGalD,EAAS,IAAID,KCrb1B,OAAOoD,MAAe,KADtB,IAkCaC,EAwFAC,EA1HbC,GAAAC,EAAA,kBAEAC,IAgCaJ,EAAN,cAA4B,KAAM,CACvC,YACSK,EACPC,EACOC,EACP,CACA,MAAMD,CAAO,EAJN,UAAAD,EAEA,UAAAE,EAGP,KAAK,KAAO,eACd,CA1CF,MAkCyC,CAAAC,EAAA,sBASzC,EA+EaP,EAAN,KAAqB,CA1H5B,MA0H4B,CAAAO,EAAA,uBAClB,YACA,GAAuB,KACvB,OACA,YAAc,GACd,kBAAoB,GAGpB,MAA2B,IAAI,IAG/B,gBAAmC,eAGnC,iBAGA,eAAiC,CACvC,SAAU,EACV,aAAc,EACd,MAAO,KACP,UAAW,KACX,mBAAoB,EACtB,EAGQ,kBAA2C,KAG3C,mBAAyC,CAC/C,WAAY,EACZ,gBAAiB,EACjB,YAAa,EACb,oBAAqB,EACrB,gBAAiB,OAAO,UACxB,gBAAiB,EACjB,YAAa,EACb,YAAa,IAAI,IACnB,EAGQ,YAA4B,CAAC,EACpB,eAAiB,IAG1B,YAA2B,CACjC,YAAa,EACb,aAAc,IACd,SAAU,IACV,kBAAmB,EACnB,gBAAiB,CACf,OACA,MACF,CACF,EAGQ,eAAkC,CACxC,QAAS,IACT,cAAe,EACf,WAAY,GACd,EAEA,YAAYC,EAAqBC,EAAiC,CAChE,KAAK,YAAcD,EACnB,KAAK,OAASE,EAGd,KAAK,iBAAmB,CACtB,QAAS,GACT,YAAa,GACb,gBAAiB,IACjB,YAAa,IACb,gBAAiB,cACjB,kBAAmB,IACnB,QAAS,IACT,OAAQ,GACR,GAAGD,GAAS,SACd,EAEA,KAAK,eAAe,aAAe,KAAK,iBAAiB,eAC3D,CAMA,kBAAkBE,EAA2B,CAE1C,KAAa,eAAiBA,EAC/B,KAAK,OAAO,KAAK,sCAAuB,EAGxC,KAAK,4BAA4B,CACnC,CAMA,6BAAoC,CAClC,IAAMA,EAAkB,KAAa,eACrC,GAAI,CAACA,EAAgB,CACnB,KAAK,OAAO,MAAM,gFAA8B,EAChD,MACF,CAEA,GAAI,CAEF,IAAMC,EAAWD,EAAe,YAAY,EAGtCE,EAAW,IAAI,IAErB,QAAWC,KAAYF,EACrBC,EAAS,IAAIC,EAAS,KAAM,CAC1B,KAAMA,EAAS,KACf,YAAaA,EAAS,YACtB,YAAaA,EAAS,WACxB,CAAC,EAIH,KAAK,MAAQD,EAEb,KAAK,OAAO,KAAK,+CAA2B,KAAK,MAAM,IAAI,qBAAM,CACnE,OAASE,EAAO,CACd,KAAK,OAAO,MACV,yCAAWA,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACnE,CAEF,CACF,CASA,QAAQC,EAAcC,EAAkB,CACtC,YAAK,aAAaD,EAAMC,CAAI,EAC5B,KAAK,MAAM,IAAID,EAAMC,CAAI,EACzB,KAAK,OAAO,MAAM,iBAAOD,CAAI,sBAAO,EAE7B,IACT,CAOA,SAASE,EAAmC,CAC1C,OAAW,CAACF,EAAMC,CAAI,IAAK,OAAO,QAAQC,CAAK,EAC7C,KAAK,QAAQF,EAAMC,CAAI,EAEzB,OAAO,IACT,CAOA,WAAWD,EAAoB,CAC7B,OAAI,KAAK,MAAM,OAAOA,CAAI,EACxB,KAAK,OAAO,MAAM,iBAAOA,CAAI,sBAAO,EAEpC,KAAK,OAAO,KAAK,kEAAgBA,CAAI,GAAG,EAEnC,IACT,CAMA,UAAmB,CAEjB,GAAI,CACF,KAAK,4BAA4B,CACnC,MAAgB,CAEhB,CAEA,OAAO,MAAM,KAAK,KAAK,MAAM,OAAO,CAAC,CACvC,CAOA,QAAQA,EAAuB,CAC7B,OAAO,KAAK,MAAM,IAAIA,CAAI,CAC5B,CAOQ,aAAaA,EAAcC,EAAkB,CACnD,GAAI,CAACD,GAAQ,OAAOA,GAAS,UAAYA,EAAK,KAAK,IAAM,GACvD,MAAM,IAAI,MAAM,0EAAc,EAGhC,GAAI,KAAK,MAAM,IAAIA,CAAI,EACrB,MAAM,IAAI,MAAM,iBAAOA,CAAI,sBAAO,EAGpC,GAAI,CAACC,GAAQ,OAAOA,GAAS,SAC3B,MAAM,IAAI,MAAM,8DAAY,EAI9B,GAAI,CAACA,EAAK,MAAQ,OAAOA,EAAK,MAAS,SACrC,MAAM,IAAI,MAAM,4EAAqB,EAGvC,GAAI,CAACA,EAAK,aAAe,OAAOA,EAAK,aAAgB,SACnD,MAAM,IAAI,MAAM,mFAA4B,EAG9C,GAAI,CAACA,EAAK,aAAe,OAAOA,EAAK,aAAgB,SACnD,MAAM,IAAI,MAAM,mFAA4B,EAI9C,GAAI,CAACA,EAAK,YAAY,MAAQ,CAACA,EAAK,YAAY,WAC9C,MAAM,IAAI,MACR,iGACF,CAEJ,CAMA,MAAa,SAAyB,CAEpC,GAAI,KAAK,MAAM,OAAS,EACtB,MAAM,IAAI,MAAM,sIAAwB,EAI1C,GAAI,KAAK,kBAAoB,aAC3B,MAAM,IAAI,MAAM,4FAAiB,EAInC,YAAK,kBAAkB,EAGvB,KAAK,eAAe,mBAAqB,GAElC,KAAK,kBAAkB,CAChC,CAMA,MAAc,mBAAmC,CAC/C,YAAK,gBAAkB,aACvB,KAAK,OAAO,KACV,oDAAiB,KAAK,WAAW,kBAC/B,KAAK,eAAe,SAAW,CACjC,IAAI,KAAK,iBAAiB,WAAW,GACvC,EAEO,IAAI,QAAQ,CAACE,EAASC,IAAW,CAEtC,KAAK,kBAAoB,WAAW,IAAM,CACxC,IAAML,EAAQ,IAAI,MAChB,6BAAS,KAAK,iBAAiB,OAAO,KACxC,EACA,KAAK,sBAAsBA,CAAK,EAChCK,EAAOL,CAAK,CACd,EAAG,KAAK,iBAAiB,OAAO,EAEhC,KAAK,GAAK,IAAIjB,EAAU,KAAK,WAAW,EAExC,KAAK,GAAG,GAAG,OAAQ,IAAM,CACvB,KAAK,wBAAwB,EAC7BqB,EAAQ,CACV,CAAC,EAED,KAAK,GAAG,GAAG,UAAYb,GAAS,CAC9B,GAAI,CACF,IAAMD,EAAsB,KAAK,MAAMC,EAAK,SAAS,CAAC,EACtD,KAAK,cAAcD,CAAO,CAC5B,OAASU,EAAO,CACd,KAAK,OAAO,MAAM,4CAAeA,CAAK,CACxC,CACF,CAAC,EAED,KAAK,GAAG,GAAG,QAAS,CAACX,EAAMiB,IAAW,CACpC,KAAK,sBAAsBjB,EAAMiB,EAAO,SAAS,CAAC,CACpD,CAAC,EAED,KAAK,GAAG,GAAG,QAAUN,GAAU,CAC7B,KAAK,sBAAsBA,CAAK,EAChCK,EAAOL,CAAK,CACd,CAAC,CACH,CAAC,CACH,CAKQ,yBAAgC,CAElC,KAAK,oBACP,aAAa,KAAK,iBAAiB,EACnC,KAAK,kBAAoB,MAG3B,KAAK,YAAc,GACnB,KAAK,gBAAkB,YAGvB,KAAK,eAAe,SAAW,EAC/B,KAAK,eAAe,aAAe,KAAK,iBAAiB,gBACzD,KAAK,eAAe,UAAY,KAEhC,KAAK,OAAO,KAAK,8CAAqB,CACxC,CAKQ,sBAAsBA,EAAoB,CAE5C,KAAK,oBACP,aAAa,KAAK,iBAAiB,EACnC,KAAK,kBAAoB,MAG3B,KAAK,eAAe,UAAYA,EAChC,KAAK,OAAO,MAAM,8BAAqBA,EAAM,OAAO,EAGpD,KAAK,kBAAkB,CACzB,CAKQ,sBAAsBX,EAAciB,EAAsB,CAMhE,GALA,KAAK,YAAc,GACnB,KAAK,kBAAoB,GACzB,KAAK,OAAO,KAAK,qDAAkBjB,CAAI,mBAASiB,CAAM,GAAG,EAGrD,KAAK,eAAe,mBAAoB,CAC1C,KAAK,gBAAkB,eACvB,MACF,CAGI,KAAK,gBAAgB,EACvB,KAAK,kBAAkB,GAEvB,KAAK,gBAAkB,SACvB,KAAK,OAAO,KACV,2DAAc,KAAK,iBAAiB,WAAW,iCACjD,EAEJ,CAKQ,iBAA2B,CACjC,OACE,KAAK,iBAAiB,SACtB,KAAK,eAAe,SAAW,KAAK,iBAAiB,aACrD,CAAC,KAAK,eAAe,kBAEzB,CAKQ,mBAA0B,CAChC,KAAK,gBAAkB,eACvB,KAAK,eAAe,WAGpB,KAAK,sBAAsB,EAE3B,KAAK,OAAO,KACV,gBAAM,KAAK,eAAe,YAAY,+BAAW,KAAK,eAAe,QAAQ,qBAC/E,EAGI,KAAK,eAAe,OACtB,aAAa,KAAK,eAAe,KAAK,EAIxC,KAAK,eAAe,MAAQ,WAAW,SAAY,CACjD,GAAI,CACF,MAAM,KAAK,kBAAkB,CAC/B,MAAgB,CAEhB,CACF,EAAG,KAAK,eAAe,YAAY,CACrC,CAKQ,uBAA8B,CACpC,IAAIC,EAEJ,OAAQ,KAAK,iBAAiB,gBAAiB,CAC7C,IAAK,QACHA,EAAW,KAAK,iBAAiB,gBACjC,MAEF,IAAK,SACHA,EACE,KAAK,iBAAiB,gBACtB,KAAK,eAAe,SAClB,KAAK,iBAAiB,kBACtB,IACJ,MAEF,IAAK,cACHA,EACE,KAAK,iBAAiB,gBACtB,KAAK,iBAAiB,oBACnB,KAAK,eAAe,SAAW,GACpC,MAEF,QACEA,EAAW,KAAK,iBAAiB,eACrC,CAMA,GAHAA,EAAW,KAAK,IAAIA,EAAU,KAAK,iBAAiB,WAAW,EAG3D,KAAK,iBAAiB,OAAQ,CAChC,IAAMC,EAAcD,EAAW,GACzBE,GAAU,KAAK,OAAO,EAAI,IAAO,EAAID,EAC3CD,GAAYE,CACd,CAEA,KAAK,eAAe,aAAe,KAAK,IAAIF,EAAU,GAAI,CAC5D,CAKQ,mBAA0B,CAEhC,GAAI,KAAK,GAAI,CAEX,KAAK,GAAG,mBAAmB,EAG3B,GAAI,CACE,KAAK,GAAG,aAAexB,EAAU,KACnC,KAAK,GAAG,MAAM,IAAM,wBAAwB,EACnC,KAAK,GAAG,aAAeA,EAAU,YAC1C,KAAK,GAAG,UAAU,CAEtB,OAASiB,EAAO,CAEd,KAAK,OAAO,MAAM,sFAA2BA,CAAK,CACpD,CAEA,KAAK,GAAK,IACZ,CAGI,KAAK,oBACP,aAAa,KAAK,iBAAiB,EACnC,KAAK,kBAAoB,MAI3B,KAAK,YAAc,GACnB,KAAK,kBAAoB,EAC3B,CAKQ,eAAsB,CACxB,KAAK,eAAe,QACtB,aAAa,KAAK,eAAe,KAAK,EACtC,KAAK,eAAe,MAAQ,KAEhC,CAEQ,cAAcV,EAA2B,CAC/C,KAAK,OAAO,MAAM,iCAAc,KAAK,UAAUA,EAAS,KAAM,CAAC,CAAC,EAE5DA,EAAQ,QACV,KAAK,oBAAoBA,CAAO,CAEpC,CAEQ,oBAAoBoB,EAA2B,CACrD,OAAQA,EAAQ,OAAQ,CACtB,IAAK,aACL,IAAK,4BACH,KAAK,aAAaA,EAAQ,GAAI,CAC5B,gBAAiB,aACjB,aAAc,CACZ,MAAO,CAAE,YAAa,EAAK,EAC3B,QAAS,CAAC,CACZ,EACA,WAAY,CACV,KAAM,qBACN,QAAS,OACX,CACF,CAAC,EACD,KAAK,kBAAoB,GACzB,KAAK,OAAO,KAAK,sDAAc,EAC/B,MAEF,IAAK,aAAc,CACjB,IAAMC,EAAY,KAAK,SAAS,EAChC,KAAK,aAAaD,EAAQ,GAAI,CAAE,MAAOC,CAAU,CAAC,EAClD,KAAK,OAAO,KAAK,mDAAgBA,EAAU,MAAM,qBAAM,EACvD,KACF,CAEA,IAAK,aAAc,CAEjB,KAAK,eAAeD,CAAO,EAAE,MAAOV,GAAU,CAC5C,KAAK,OAAO,MAAM,wFAAmBA,CAAK,CAC5C,CAAC,EACD,KACF,CAEA,IAAK,OACH,KAAK,aAAaU,EAAQ,GAAI,CAAC,CAAC,EAChC,KAAK,OAAO,MAAM,oCAAgB,EAClC,MAEF,QACE,KAAK,OAAO,KAAK,wCAAeA,EAAQ,MAAM,EAAE,CACpD,CACF,CAEQ,aAAaE,EAAiCC,EAAmB,CAKvE,GAJA,KAAK,OAAO,MACV,4CAAcD,CAAE,iBAAiB,KAAK,WAAW,kBAAkB,KAAK,IAAI,UAAU,EACxF,EAEI,KAAK,aAAe,KAAK,IAAI,aAAe7B,EAAU,KAAM,CAC9D,IAAM+B,EAAuB,CAC3B,QAAS,MACT,GAAAF,EACA,OAAAC,CACF,EAEA,GAAI,CACF,KAAK,GAAG,KAAK,KAAK,UAAUC,CAAQ,CAAC,EACrC,KAAK,OAAO,KAAK,sCAAaF,CAAE,GAAI,CAClC,aAAc,KAAK,UAAUE,CAAQ,EAAE,MACzC,CAAC,CACH,OAASd,EAAO,CACd,KAAK,OAAO,MAAM,4CAAcY,CAAE,GAAIZ,CAAK,CAC7C,CACF,MACE,KAAK,OAAO,MAAM,4CAAcY,CAAE,qDAAc,CAC9C,YAAa,KAAK,YAClB,aAAc,KAAK,IAAI,WACvB,iBACE,KAAK,IAAI,aAAe7B,EAAU,KAC9B,OACA,KAAK,IAAI,aAAeA,EAAU,WAChC,aACA,KAAK,IAAI,aAAeA,EAAU,QAChC,UACA,KAAK,IAAI,aAAeA,EAAU,OAChC,SACA,SACd,CAAC,GAGG,CAAC,KAAK,aAAe,KAAK,IAAI,aAAeA,EAAU,QACzD,KAAK,OAAO,KAAK,0EAAmB6B,CAAE,EAAE,EACxC,KAAK,kBAAkB,EAG7B,CAMO,WAAkC,CACvC,MAAO,CACL,UAAW,KAAK,YAChB,YAAa,KAAK,kBAClB,IAAK,KAAK,YACV,eAAgB,KAAK,MAAM,KAC3B,gBAAiB,KAAK,gBACtB,kBAAmB,KAAK,eAAe,SACvC,UAAW,KAAK,eAAe,WAAW,SAAW,IACvD,CACF,CAKO,YAAmB,CACxB,KAAK,OAAO,KAAK,2CAAa,EAG9B,KAAK,eAAe,mBAAqB,GAGzC,KAAK,cAAc,EAGnB,KAAK,kBAAkB,EAGvB,KAAK,gBAAkB,cACzB,CAKA,MAAa,WAA2B,CACtC,KAAK,OAAO,KAAK,iDAAc,EAG/B,KAAK,cAAc,EAGnB,KAAK,eAAe,SAAW,EAC/B,KAAK,eAAe,aAAe,KAAK,iBAAiB,gBACzD,KAAK,eAAe,mBAAqB,GAGzC,KAAK,kBAAkB,EAGvB,MAAM,KAAK,QAAQ,CACrB,CAKO,iBAAwB,CAC7B,KAAK,iBAAiB,QAAU,GAChC,KAAK,OAAO,KAAK,4CAAS,CAC5B,CAKO,kBAAyB,CAC9B,KAAK,iBAAiB,QAAU,GAChC,KAAK,cAAc,EACnB,KAAK,OAAO,KAAK,4CAAS,CAC5B,CAKO,uBAAuBlB,EAA0C,CACtE,KAAK,iBAAmB,CAAE,GAAG,KAAK,iBAAkB,GAAGA,CAAQ,EAC/D,KAAK,OAAO,KAAK,6CAAWA,CAAO,CACrC,CAKO,qBAAwC,CAC7C,MAAO,CAAE,GAAG,KAAK,gBAAiB,CACpC,CAKO,qBAA4B,CACjC,KAAK,cAAc,EACnB,KAAK,eAAe,SAAW,EAC/B,KAAK,eAAe,aAAe,KAAK,iBAAiB,gBACzD,KAAK,eAAe,UAAY,KAChC,KAAK,OAAO,KAAK,4CAAS,CAC5B,CAKA,MAAc,eAAegB,EAAoC,CAE/D,GAAIA,EAAQ,KAAO,QAAaA,EAAQ,KAAO,KAC7C,MAAM,IAAI1B,EACR,OACA,0CACF,EAIF,IAAM+B,EAAYL,EAAQ,GACtBM,EAAgC,KAEpC,GAAI,CAEF,IAAMC,EAAS,KAAK,uBAAuBP,EAAQ,MAAM,EAGzDM,EAAa,KAAK,gBAAgBC,EAAO,KAAMF,CAAS,EAExD,KAAK,OAAO,KAAK,qDAAaE,EAAO,IAAI,GAAI,CAC3C,UAAAF,EACA,SAAUE,EAAO,KACjB,aAAc,CAAC,CAACA,EAAO,SACzB,CAAC,EAGD,IAAMrB,EAAkB,KAAa,eACrC,GAAI,CAACA,EACH,MAAM,IAAIZ,EACR,OACA,sCACF,EAIF,IAAM6B,EAAS,MAAM,KAAK,qBACxBjB,EACAqB,EAAO,KACPA,EAAO,WAAa,CAAC,CACvB,EAGA,KAAK,aAAaF,EAAW,CAC3B,QAASF,EAAO,SAAW,CACzB,CAAE,KAAM,OAAQ,KAAM,KAAK,UAAUA,CAAM,CAAE,CAC/C,EACA,QAASA,EAAO,SAAW,EAC7B,CAAC,EAGGG,GACF,KAAK,cAAcA,EAAY,EAAI,EAGrC,KAAK,OAAO,KAAK,yCAAWC,EAAO,IAAI,GAAI,CACzC,UAAAF,EACA,SAAUC,GAAY,SAAW,GAAGA,EAAW,QAAQ,KAAO,SAChE,CAAC,CACH,OAAShB,EAAO,CAEd,GAAIgB,EAAY,CACd,IAAME,EACJlB,aAAiBhB,EACbgB,EAAM,KACN,MACAmB,EACJnB,aAAiB,MAAQA,EAAM,QAAU,2BAC3C,KAAK,cAAcgB,EAAY,GAAOE,EAAWC,CAAY,CAC/D,CAEA,KAAK,oBAAoBnB,EAAOe,EAAWC,GAAY,UAAY,CAAC,CACtE,CACF,CAKQ,uBAAuBC,EAG7B,CACA,GAAI,CAACA,GAAU,OAAOA,GAAW,SAC/B,MAAM,IAAIjC,EACR,OACA,wDACF,EAGF,GAAI,CAACiC,EAAO,MAAQ,OAAOA,EAAO,MAAS,SACzC,MAAM,IAAIjC,EACR,OACA,0EACF,EAGF,GACEiC,EAAO,YAAc,SACpB,OAAOA,EAAO,WAAc,UAAY,MAAM,QAAQA,EAAO,SAAS,GAEvE,MAAM,IAAIjC,EACR,OACA,wDACF,EAGF,MAAO,CACL,KAAMiC,EAAO,KACb,UAAWA,EAAO,SACpB,CACF,CAKA,MAAc,qBACZrB,EACAwB,EACAC,EACc,CACd,IAAIC,EAAkC,KAEtC,QAASC,EAAU,EAAGA,GAAW,KAAK,YAAY,YAAaA,IAC7D,GAAI,CACF,OAAO,MAAM,KAAK,uBAChB3B,EACAwB,EACAC,EACA,KAAK,eAAe,OACtB,CACF,OAASrB,EAAO,CAad,GAXIA,aAAiBhB,EACnBsC,EAAYtB,EAGZsB,EAAY,IAAItC,EACd,MACAgB,aAAiB,MAAQA,EAAM,QAAU,0BAC3C,EAKA,KAAK,YAAY,gBAAgB,SAASsB,EAAU,IAAI,GACxDC,EAAU,KAAK,YAAY,YAC3B,CAEA,IAAMC,EAAQ,KAAK,IACjB,KAAK,YAAY,aACf,KAAK,YAAY,oBAAsBD,EAAU,GACnD,KAAK,YAAY,QACnB,EAEA,KAAK,OAAO,KACV,0DAAaC,CAAK,0BAAWD,CAAO,IAAI,KAAK,YAAY,WAAW,IACpE,CACE,SAAAH,EACA,MAAOE,EAAU,QACjB,QAAAC,EACA,MAAAC,CACF,CACF,EAGA,MAAM,IAAI,QAASpB,GAAY,WAAWA,EAASoB,CAAK,CAAC,EACzD,QACF,CAGA,KACF,CAIF,MAAMF,CACR,CAKA,MAAc,uBACZ1B,EACAwB,EACAC,EACAI,EAAY,IACE,CACd,OAAO,IAAI,QAAQ,CAACrB,EAASC,IAAW,CAEtC,IAAMqB,EAAY,WAAW,IAAM,CACjCrB,EACE,IAAIrB,EACF,OACA,yCAAWyC,CAAS,QAAQL,CAAQ,EACtC,CACF,CACF,EAAGK,CAAS,EAGZ7B,EACG,SAASwB,EAAUC,CAAU,EAC7B,KAAMR,GAAgB,CACrB,aAAaa,CAAS,EACtBtB,EAAQS,CAAM,CAChB,CAAC,EACA,MAAOb,GAAe,CACrB,aAAa0B,CAAS,EAGlB1B,EAAM,SAAS,SAAS,gCAAO,EACjCK,EACE,IAAIrB,EACF,OACA,mCAAUoC,CAAQ,EACpB,CACF,EAEApB,EAAM,SAAS,SAAS,cAAI,GAC5BA,EAAM,SAAS,SAAS,oBAAK,EAE7BK,EACE,IAAIrB,EACF,OACAgB,EAAM,OACR,CACF,EACSA,EAAM,SAAS,SAAS,gCAAO,EAExCK,EACE,IAAIrB,EACF,OACAgB,EAAM,OACR,CACF,EACSA,EAAM,SAAS,SAAS,gCAAO,EAExCK,EACE,IAAIrB,EACF,OACAgB,EAAM,OACR,CACF,EAEAK,EACE,IAAIrB,EACF,MACA,yCAAWgB,EAAM,OAAO,EAC1B,CACF,CAEJ,CAAC,CACL,CAAC,CACH,CAKQ,oBACNA,EACAe,EACAY,EACM,CACN,IAAIC,EAEA5B,aAAiBhB,EAEnB4C,EAAgB,CACd,KAAM5B,EAAM,KACZ,QAASA,EAAM,QACf,KAAMA,EAAM,IACd,EAGA4B,EAAgB,CACd,KAAM,MACN,QAAS5B,GAAO,SAAW,2BAC3B,KAAM,CAAE,cAAeA,GAAO,SAAS,GAAK,MAAO,CACrD,EAIF,KAAK,kBAAkBe,EAAWa,CAAa,EAG/C,KAAK,OAAO,MAAM,uCAAU,CAC1B,UAAAb,EACA,SAAU,GAAGY,CAAQ,KACrB,MAAOC,CACT,CAAC,CACH,CAKQ,kBACNhB,EACAZ,EACM,CACN,GAAI,KAAK,aAAe,KAAK,IAAI,aAAejB,EAAU,KAAM,CAC9D,IAAM+B,EAAW,CACf,QAAS,MACT,GAAAF,EACA,MAAAZ,CACF,EACA,KAAK,GAAG,KAAK,KAAK,UAAUc,CAAQ,CAAC,EACrC,KAAK,OAAO,MAAM,8CAAYA,CAAQ,CACxC,CACF,CAKQ,gBACNM,EACAL,EACY,CACZ,IAAMc,EAAqB,CACzB,GAAI,OAAOd,CAAS,EACpB,SAAAK,EACA,UAAW,IAAI,KACf,QAAS,EACX,EAGA,YAAK,YAAY,KAAKS,CAAM,EAGxB,KAAK,YAAY,OAAS,KAAK,gBACjC,KAAK,YAAY,MAAM,EAGlBA,CACT,CAKQ,cACNA,EACAC,EACAZ,EACAC,EACM,CACNU,EAAO,QAAU,IAAI,KACrBA,EAAO,SAAWA,EAAO,QAAQ,QAAQ,EAAIA,EAAO,UAAU,QAAQ,EACtEA,EAAO,QAAUC,EACjBD,EAAO,UAAYX,EACnBW,EAAO,aAAeV,EAGtB,KAAK,yBAAyBU,CAAM,CACtC,CAKQ,yBAAyBA,EAA0B,CASzD,GARA,KAAK,mBAAmB,aAEpBA,EAAO,QACT,KAAK,mBAAmB,kBAExB,KAAK,mBAAmB,cAGtBA,EAAO,WAAa,OAAW,CAE7BA,EAAO,SAAW,KAAK,mBAAmB,kBAC5C,KAAK,mBAAmB,gBAAkBA,EAAO,UAE/CA,EAAO,SAAW,KAAK,mBAAmB,kBAC5C,KAAK,mBAAmB,gBAAkBA,EAAO,UAInD,IAAME,EAAY,KAAK,YACpB,OAAQC,GAAMA,EAAE,WAAa,MAAS,EACtC,OAAO,CAACC,EAAKD,IAAMC,GAAOD,EAAE,UAAY,GAAI,CAAC,EAC1CE,EAAiB,KAAK,YAAY,OACrCF,GAAMA,EAAE,WAAa,MACxB,EAAE,OACF,KAAK,mBAAmB,oBACtBE,EAAiB,EAAIH,EAAYG,EAAiB,CACtD,CAGA,KAAK,mBAAmB,YACtB,KAAK,mBAAmB,WAAa,EAChC,KAAK,mBAAmB,gBACvB,KAAK,mBAAmB,WAC1B,IACA,EAEN,KAAK,mBAAmB,YAAc,IAAI,IAC5C,CAKO,uBAA4C,CACjD,MAAO,CAAE,GAAG,KAAK,kBAAmB,CACtC,CAKO,eAAeC,EAA8B,CAClD,IAAMC,EAAU,CAAC,GAAG,KAAK,WAAW,EAAE,QAAQ,EAC9C,OAAOD,EAAQC,EAAQ,MAAM,EAAGD,CAAK,EAAIC,CAC3C,CAKO,yBAAgC,CACrC,KAAK,mBAAqB,CACxB,WAAY,EACZ,gBAAiB,EACjB,YAAa,EACb,oBAAqB,EACrB,gBAAiB,OAAO,UACxB,gBAAiB,EACjB,YAAa,EACb,YAAa,IAAI,IACnB,EACA,KAAK,YAAc,CAAC,CACtB,CAKO,qBAAqBC,EAAwC,CAClE,KAAK,eAAiB,CAAE,GAAG,KAAK,eAAgB,GAAGA,CAAO,EAC1D,KAAK,OAAO,KAAK,yDAAa,KAAK,cAAc,CACnD,CAKO,kBAAkBA,EAAoC,CAC3D,KAAK,YAAc,CAAE,GAAG,KAAK,YAAa,GAAGA,CAAO,EACpD,KAAK,OAAO,KAAK,6CAAW,KAAK,WAAW,CAC9C,CAKO,kBAGL,CACA,MAAO,CACL,SAAU,CAAE,GAAG,KAAK,cAAe,EACnC,MAAO,CAAE,GAAG,KAAK,WAAY,CAC/B,CACF,CAKO,mBAML,CACA,MAAO,CACL,UAAW,KAAK,YAChB,YAAa,KAAK,kBAClB,IAAK,KAAK,YACV,eAAgB,KAAK,MAAM,KAC3B,gBAAiB,KAAK,gBACtB,kBAAmB,KAAK,eAAe,SACvC,UAAW,KAAK,eAAe,WAAW,SAAW,KACrD,YAAa,KAAK,sBAAsB,EACxC,cAAe,KAAK,iBAAiB,CACvC,CACF,CACF,ICrxCA,OACE,sBAAAC,OAEK,0CACP,OAAS,wBAAAC,OAA4B,4CACrC,OACE,iCAAAC,OAEK,qDACP,OAAS,eAAAC,OAAmB,cAgB5B,SAASC,IAAoB,CAC3B,OAAOC,CACT,CAOO,SAASC,GAAgBC,EAA+B,CAM7D,OALeH,GAAU,EAClB,KACL,mCAAyBG,EAAO,IAAI,kBAAkBA,EAAO,IAAI,EACnE,EAEQA,EAAO,KAAM,CACnB,YACE,OAAOC,GAAqBD,CAAM,EAEpC,UACE,OAAOE,GAAmBF,CAAM,EAElC,qBACE,OAAOG,GAA6BH,CAAM,EAE5C,sBACE,OAAOI,GAA8BJ,CAAM,EAE7C,QACE,MAAM,IAAI,MAAM,qDAAaA,EAAO,IAAI,EAAE,CAC9C,CACF,CAKA,SAASC,GAAqBD,EAAgD,CAC5E,GAAI,CAACA,EAAO,QACV,MAAM,IAAI,MAAM,mDAA+B,EAGjD,OAAO,IAAIN,GAAqB,CAC9B,QAASM,EAAO,QAChB,KAAMA,EAAO,MAAQ,CAAC,EACtB,IAAKA,EAAO,GACd,CAAC,CACH,CAKA,SAASE,GAAmBF,EAA8C,CACxE,GAAI,CAACA,EAAO,IACV,MAAM,IAAI,MAAM,6CAAyB,EAG3C,IAAMK,EAAM,IAAI,IAAIL,EAAO,GAAG,EACxBM,EAAUC,GAAiBP,CAAM,EAEvC,OAAO,IAAIP,GAAmBY,EAAKC,CAAO,CAC5C,CAKA,SAASH,GACPH,EACoB,CACpB,GAAI,CAACA,EAAO,IACV,MAAM,IAAI,MAAM,wDAAoC,EAGtD,GAAI,CAACA,EAAO,OACV,MAAM,IAAI,MAAM,2DAAuC,EAGzD,IAAMK,EAAM,IAAI,IAAIL,EAAO,GAAG,EACxBM,EAAUE,GAA2BR,CAAM,EAEjD,OAAO,IAAIP,GAAmBY,EAAKC,CAAO,CAC5C,CAEA,SAASF,GACPJ,EAC+B,CAC/B,GAAI,CAACA,EAAO,IACV,MAAM,IAAI,MAAM,wDAAoC,EAGtD,IAAMK,EAAM,IAAI,IAAIL,EAAO,GAAG,EACxBM,EAAUG,GAA4BT,CAAM,EAClD,OAAO,IAAIL,GAA8BU,EAAKC,CAAO,CACvD,CAKA,SAASC,GAAiBP,EAAqD,CAC7E,IAAMM,EAAe,CAAC,EAGtB,OAAIN,EAAO,OACTM,EAAQ,QAAU,CAChB,cAAe,UAAUN,EAAO,MAAM,GACtC,GAAGA,EAAO,OACZ,EACSA,EAAO,UAChBM,EAAQ,QAAUN,EAAO,SAGpBM,CACT,CAKA,SAASE,GAA2BR,EAA+B,CACjE,IAAMU,EAAQV,EAAO,OAGrB,OAAIA,EAAO,iBACFA,EAAO,iBAIT,CACL,gBAAiB,CACf,MAAOW,EAAA,MAAON,EAA6BO,IAAuB,CAEhE,IAAMC,EAAU,CACd,GAAGD,GAAM,QACT,cAAe,UAAUF,CAAK,EAChC,EAEA,OAAO,MAAML,EAAK,CAAE,GAAGO,EAAM,QAAAC,CAAQ,CAAC,CACxC,EARO,QAST,EACA,YAAa,CACX,QAAS,CACP,cAAe,UAAUH,CAAK,GAC9B,GAAGV,EAAO,OACZ,CACF,CACF,CACF,CAEA,SAASS,GACPT,EACsC,CACtC,IAAMM,EAAe,CAAC,EAGtB,OAAIN,EAAO,OACTM,EAAQ,QAAU,CAChB,cAAe,UAAUN,EAAO,MAAM,GACtC,GAAGA,EAAO,OACZ,EACSA,EAAO,UAChBM,EAAQ,QAAUN,EAAO,SAGpBM,CACT,CAKO,SAASQ,GAAed,EAAgC,CAC7D,GAAI,CAACA,EAAO,MAAQ,OAAOA,EAAO,MAAS,SACzC,MAAM,IAAI,MAAM,0EAAmB,EAGrC,GAAI,CAACA,EAAO,KACV,MAAM,IAAI,MAAM,wDAAgB,EAGlC,OAAQA,EAAO,KAAM,CACnB,YACE,GAAI,CAACA,EAAO,QACV,MAAM,IAAI,MAAM,qDAAuB,EAEzC,MAEF,UACA,sBACE,GAAI,CAACA,EAAO,IACV,MAAM,IAAI,MAAM,GAAGA,EAAO,IAAI,4CAAc,EAE9C,MAEF,qBACE,GAAI,CAACA,EAAO,IACV,MAAM,IAAI,MAAM,0DAA4B,EAE9C,GAAI,CAACA,EAAO,OACV,MAAM,IAAI,MACR,yMACF,EAEF,MAEF,QACE,MAAM,IAAI,MAAM,qDAAaA,EAAO,IAAI,EAAE,CAC9C,CACF,CAKO,SAASe,IAAwC,CACtD,MAAO,iDAKP,CACF,CAjPA,IAsPaC,GAtPbC,GAAAC,EAAA,kBAUAC,IACAC,KAGI,OAAO,OAAW,KAAe,CAAC,OAAO,cAC1C,OAAe,YAAcxB,IAUvBe,EAAAd,GAAA,aASOc,EAAAZ,GAAA,mBA2BPY,EAAAV,GAAA,wBAeAU,EAAAT,GAAA,sBAcAS,EAAAR,GAAA,gCAiBAQ,EAAAP,GAAA,iCAeAO,EAAAJ,GAAA,oBAmBAI,EAAAH,GAAA,8BA8BAG,EAAAF,GAAA,+BAqBOE,EAAAG,GAAA,kBA0CAH,EAAAI,GAAA,qBAYHC,GAAmB,CAC9B,OAAQjB,GACR,eAAAe,GACA,kBAAAC,EACF,IC1PA,OAAS,UAAAM,OAAc,4CAAvB,IAMYC,GAsHCC,GA5HbC,GAAAC,EAAA,kBAEAC,IACAC,KAGYL,QACVA,EAAA,MAAQ,QACRA,EAAA,IAAM,MACNA,EAAA,gBAAkB,kBAClBA,EAAA,eAAiB,iBAJPA,QAAA,IAsHCC,GAAN,KAAiB,CA5HxB,MA4HwB,CAAAK,EAAA,mBACd,OACA,OAAwB,KACxB,UAAiB,KACjB,MAA2B,IAAI,IAC/B,gBAAmC,eACnC,iBACA,eACA,OACA,kBAA2C,KAC3C,YAAc,GAGd,YACA,UAAmC,KACnC,iBAAmB,EACnB,aAA4B,KAC5B,UAAY,GAEpB,YAAYC,EAA0BC,EAA6B,CACjE,KAAK,OAASD,EACd,KAAK,OAASE,EAGd,KAAK,eAAe,EAGpB,KAAK,iBAAmB,CACtB,QAAS,GACT,YAAa,GACb,gBAAiB,IACjB,YAAa,IACb,gBAAiB,cACjB,kBAAmB,IACnB,QAAS,IACT,OAAQ,GACR,GAAGD,GAAS,UACZ,GAAGD,EAAO,SACZ,EAGA,KAAK,YAAc,CACjB,QAAS,GACT,SAAU,IACV,QAAS,IACT,YAAa,EACb,WAAY,IACZ,GAAGA,EAAO,IACZ,EAGA,KAAK,eAAiB,CACpB,SAAU,EACV,aAAc,KAAK,iBAAiB,gBACpC,MAAO,KACP,UAAW,KACX,mBAAoB,EACtB,CACF,CAKQ,WACNG,EACAC,KACGC,EACG,CACN,IAAMC,EAAgB,QAAQ,KAAK,OAAO,IAAI,KAAKF,CAAO,GAC1D,KAAK,OAAOD,CAAK,EAAEG,EAAe,GAAGD,CAAI,CAC3C,CAKQ,gBAAuB,CAE7BE,GAAiB,eAAe,KAAK,MAAM,CAC7C,CAKA,MAAM,SAAyB,CAE7B,GAAI,KAAK,kBAAoB,aAC3B,MAAM,IAAI,MAAM,4FAAiB,EAInC,YAAK,kBAAkB,EAGvB,KAAK,eAAe,mBAAqB,GAElC,KAAK,kBAAkB,CAChC,CAKA,MAAc,mBAAmC,CAC/C,YAAK,gBAAkB,aACvB,KAAK,WACH,OACA,8CAAgB,KAAK,OAAO,IAAI,kBAC9B,KAAK,eAAe,SAAW,CACjC,IAAI,KAAK,iBAAiB,WAAW,GACvC,EAEO,IAAI,QAAQ,CAACC,EAASC,IAAW,CAEtC,KAAK,kBAAoB,WAAW,IAAM,CACxC,IAAMC,EAAQ,IAAI,MAChB,6BAAS,KAAK,iBAAiB,OAAO,KACxC,EACA,KAAK,sBAAsBA,CAAK,EAChCD,EAAOC,CAAK,CACd,EAAG,KAAK,iBAAiB,OAAO,EAEhC,GAAI,CACF,KAAK,OAAS,IAAIlB,GAChB,CACE,KAAM,WAAW,KAAK,OAAO,IAAI,UACjC,QAAS,OACX,EACA,CACE,aAAc,CACZ,MAAO,CAAC,CACV,CACF,CACF,EAGA,KAAK,UAAYe,GAAiB,OAAO,KAAK,MAAM,EAGpD,KAAK,OACF,QAAQ,KAAK,SAAS,EACtB,KAAK,SAAY,CAChB,KAAK,wBAAwB,EAG7B,MAAM,KAAK,aAAa,EAExBC,EAAQ,CACV,CAAC,EACA,MAAOE,GAAU,CAChB,KAAK,sBAAsBA,CAAK,EAChCD,EAAOC,CAAK,CACd,CAAC,CACL,OAASA,EAAO,CACd,KAAK,sBAAsBA,CAAc,EACzCD,EAAOC,CAAK,CACd,CACF,CAAC,CACH,CAKQ,yBAAgC,CAElC,KAAK,oBACP,aAAa,KAAK,iBAAiB,EACnC,KAAK,kBAAoB,MAG3B,KAAK,gBAAkB,YACvB,KAAK,YAAc,GAGnB,KAAK,eAAe,SAAW,EAC/B,KAAK,eAAe,aAAe,KAAK,iBAAiB,gBACzD,KAAK,eAAe,UAAY,KAGhC,KAAK,eAAe,EAEpB,KAAK,WAAW,OAAQ,oBAAU,KAAK,OAAO,IAAI,iCAAQ,EAG1D,KAAK,oBAAoB,CAC3B,CAKQ,sBAAsBA,EAAoB,CAE5C,KAAK,oBACP,aAAa,KAAK,iBAAiB,EACnC,KAAK,kBAAoB,MAG3B,KAAK,eAAe,UAAYA,EAChC,KAAK,OAAO,MAAM,oBAAU,KAAK,OAAO,IAAI,6BAAUA,EAAM,OAAO,EAGnE,KAAK,kBAAkB,EAGnB,KAAK,gBAAgB,EACvB,KAAK,kBAAkB,GAEvB,KAAK,gBAAkB,SACvB,KAAK,OAAO,KACV,GAAG,KAAK,OAAO,IAAI,4DAAe,KAAK,iBAAiB,WAAW,iCACrE,EAEJ,CAKQ,iBAA2B,CACjC,OACE,KAAK,iBAAiB,SACtB,KAAK,eAAe,SAAW,KAAK,iBAAiB,aACrD,CAAC,KAAK,eAAe,kBAEzB,CAKQ,mBAA0B,CAChC,KAAK,gBAAkB,eACvB,KAAK,eAAe,WAGpB,KAAK,sBAAsB,EAE3B,KAAK,OAAO,KACV,GAAG,KAAK,OAAO,IAAI,iBAAO,KAAK,eAAe,YAAY,+BAAW,KAAK,eAAe,QAAQ,qBACnG,EAGI,KAAK,eAAe,OACtB,aAAa,KAAK,eAAe,KAAK,EAIxC,KAAK,eAAe,MAAQ,WAAW,SAAY,CACjD,GAAI,CACF,MAAM,KAAK,kBAAkB,CAC/B,MAAgB,CAEhB,CACF,EAAG,KAAK,eAAe,YAAY,CACrC,CAKQ,uBAA8B,CACpC,IAAIC,EAEJ,OAAQ,KAAK,iBAAiB,gBAAiB,CAC7C,IAAK,QACHA,EAAW,KAAK,iBAAiB,gBACjC,MAEF,IAAK,SACHA,EACE,KAAK,iBAAiB,gBACtB,KAAK,eAAe,SAClB,KAAK,iBAAiB,kBACtB,IACJ,MAEF,IAAK,cACHA,EACE,KAAK,iBAAiB,gBACtB,KAAK,iBAAiB,oBACnB,KAAK,eAAe,SAAW,GACpC,MAEF,QACEA,EAAW,KAAK,iBAAiB,eACrC,CAMA,GAHAA,EAAW,KAAK,IAAIA,EAAU,KAAK,iBAAiB,WAAW,EAG3D,KAAK,iBAAiB,OAAQ,CAChC,IAAMC,EAAcD,EAAW,GACzBE,GAAU,KAAK,OAAO,EAAI,IAAO,EAAID,EAC3CD,GAAYE,CACd,CAEA,KAAK,eAAe,aAAe,KAAK,IAAIF,EAAU,GAAI,CAC5D,CAKQ,mBAA0B,CAKhC,GAHA,KAAK,mBAAmB,EAGpB,KAAK,OAAQ,CACf,GAAI,CACF,KAAK,OAAO,MAAM,EAAE,MAAM,IAAM,CAEhC,CAAC,CACH,MAAgB,CAEhB,CACA,KAAK,OAAS,IAChB,CAGA,KAAK,UAAY,KAGb,KAAK,oBACP,aAAa,KAAK,iBAAiB,EACnC,KAAK,kBAAoB,MAI3B,KAAK,YAAc,EACrB,CAKQ,eAAsB,CACxB,KAAK,eAAe,QACtB,aAAa,KAAK,eAAe,KAAK,EACtC,KAAK,eAAe,MAAQ,KAEhC,CAKA,MAAc,cAA8B,CAC1C,GAAI,CAAC,KAAK,OACR,MAAM,IAAI,MAAM,4CAAS,EAG3B,GAAI,CAEF,IAAMG,GADc,MAAM,KAAK,OAAO,UAAU,GACd,OAAS,CAAC,EAG5C,KAAK,MAAM,MAAM,EAGjB,QAAWC,KAAQD,EACjB,KAAK,MAAM,IAAIC,EAAK,KAAMA,CAAI,EAGhC,KAAK,OAAO,KACV,GAAG,KAAK,OAAO,IAAI,mCAAUD,EAAM,MAAM,wBAASA,EAC/C,IAAKE,GAAMA,EAAE,IAAI,EACjB,KAAK,IAAI,CAAC,EACf,CACF,OAASN,EAAO,CACd,WAAK,OAAO,MACV,GAAG,KAAK,OAAO,IAAI,qDACnBA,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CACvD,EACMA,CACR,CACF,CAKA,MAAM,YAA4B,CAChC,KAAK,OAAO,KAAK,6CAAe,KAAK,OAAO,IAAI,eAAK,EAGrD,KAAK,eAAe,mBAAqB,GAGzC,KAAK,mBAAmB,EAGxB,KAAK,cAAc,EAGnB,KAAK,kBAAkB,EAGvB,KAAK,gBAAkB,cACzB,CAKA,MAAM,WAA2B,CAC/B,KAAK,OAAO,KAAK,6CAAe,KAAK,OAAO,IAAI,EAAE,EAGlD,KAAK,cAAc,EAGnB,KAAK,eAAe,SAAW,EAC/B,KAAK,eAAe,aAAe,KAAK,iBAAiB,gBACzD,KAAK,eAAe,mBAAqB,GAGzC,KAAK,kBAAkB,EAGvB,MAAM,KAAK,QAAQ,CACrB,CAKA,UAAmB,CACjB,OAAO,MAAM,KAAK,KAAK,MAAM,OAAO,CAAC,CACvC,CAKA,MAAM,SAASO,EAAcC,EAA0C,CACrE,GAAI,CAAC,KAAK,OACR,MAAM,IAAI,MAAM,gBAAM,KAAK,OAAO,IAAI,qBAAM,EAG9C,GAAI,CAAC,KAAK,MAAM,IAAID,CAAI,EACtB,MAAM,IAAI,MAAM,gBAAMA,CAAI,uBAAQ,KAAK,OAAO,IAAI,2BAAO,EAG3D,KAAK,OAAO,KACV,gBAAM,KAAK,OAAO,IAAI,mCAAUA,CAAI,sBACpC,KAAK,UAAUC,CAAU,CAC3B,EAEA,GAAI,CACF,IAAMC,EAAS,MAAM,KAAK,OAAO,SAAS,CACxC,KAAAF,EACA,UAAWC,GAAc,CAAC,CAC5B,CAAC,EAED,YAAK,OAAO,KACV,gBAAMD,CAAI,+CACV,GAAG,KAAK,UAAUE,CAAM,EAAE,UAAU,EAAG,GAAG,CAAC,KAC7C,EAEOA,CACT,OAAST,EAAO,CACd,WAAK,OAAO,MACV,gBAAMO,CAAI,6BACVP,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CACvD,EACMA,CACR,CACF,CAKA,WAA8B,CAC5B,OAAO,KAAK,MACd,CAKA,WAA8B,CAC5B,MAAO,CACL,KAAM,KAAK,OAAO,KAClB,UAAW,KAAK,kBAAoB,YACpC,YAAa,KAAK,YAClB,cAAe,KAAK,OAAO,KAC3B,UAAW,KAAK,MAAM,KACtB,UAAW,KAAK,eAAe,WAAW,QAC1C,kBAAmB,KAAK,eAAe,SACvC,gBAAiB,KAAK,gBAEtB,YAAa,KAAK,YAAY,QAC9B,aAAc,KAAK,cAAgB,OACnC,iBAAkB,KAAK,iBACvB,UAAW,KAAK,SAClB,CACF,CAKA,aAAuB,CACrB,OACE,KAAK,kBAAoB,aAA6B,KAAK,WAE/D,CAKA,iBAAwB,CACtB,KAAK,iBAAiB,QAAU,GAChC,KAAK,OAAO,KAAK,GAAG,KAAK,OAAO,IAAI,6CAAU,CAChD,CAKA,kBAAyB,CACvB,KAAK,iBAAiB,QAAU,GAChC,KAAK,cAAc,EACnB,KAAK,OAAO,KAAK,GAAG,KAAK,OAAO,IAAI,6CAAU,CAChD,CAKA,uBAAuBT,EAA0C,CAC/D,KAAK,iBAAmB,CAAE,GAAG,KAAK,iBAAkB,GAAGA,CAAQ,EAC/D,KAAK,OAAO,KAAK,GAAG,KAAK,OAAO,IAAI,8CAAYA,CAAO,CACzD,CAKA,qBAAwC,CACtC,MAAO,CAAE,GAAG,KAAK,gBAAiB,CACpC,CAKA,qBAA4B,CAC1B,KAAK,cAAc,EACnB,KAAK,eAAe,SAAW,EAC/B,KAAK,eAAe,aAAe,KAAK,iBAAiB,gBACzD,KAAK,eAAe,UAAY,KAChC,KAAK,OAAO,KAAK,GAAG,KAAK,OAAO,IAAI,6CAAU,CAChD,CAKQ,qBAA4B,CAC9B,CAAC,KAAK,YAAY,SAAW,KAAK,WAAa,CAAC,KAAK,YAAY,IAIrE,KAAK,OAAO,KACV,GAAG,KAAK,OAAO,IAAI,oDAAiB,KAAK,YAAY,QAAQ,IAC/D,EAGA,WAAW,IAAM,CACX,KAAK,YAAY,GAAK,CAAC,KAAK,YAC9B,KAAK,UAAY,YAAY,IAAM,CACjC,KAAK,YAAY,CACnB,EAAG,KAAK,YAAY,QAAQ,EAEhC,EAAG,KAAK,YAAY,UAAU,EAChC,CAKQ,oBAA2B,CAC7B,KAAK,YACP,cAAc,KAAK,SAAS,EAC5B,KAAK,UAAY,KACjB,KAAK,OAAO,MAAM,GAAG,KAAK,OAAO,IAAI,+BAAW,EAEpD,CAKA,MAAc,aAA6B,CACzC,GAAI,CAAC,KAAK,QAAU,KAAK,WAAa,CAAC,KAAK,YAAY,EACtD,OAGF,KAAK,UAAY,GACjB,IAAMmB,EAAY,YAAY,IAAI,EAElC,GAAI,CACF,KAAK,OAAO,MACV,GAAG,KAAK,OAAO,IAAI,wFACrB,EAKA,IAAMC,EAAc,KAAK,OAAO,UAAU,EAEpCC,EAAiB,IAAI,QAAQ,CAACC,EAAGd,IAAW,CAChD,WAAW,IAAM,CACfA,EAAO,IAAI,MAAM,qBAAW,KAAK,YAAY,OAAO,KAAK,CAAC,CAC5D,EAAG,KAAK,YAAY,OAAO,CAC7B,CAAC,EAED,MAAM,QAAQ,KAAK,CAACY,EAAaC,CAAc,CAAC,EAEhD,IAAME,EAAW,YAAY,IAAI,EAAIJ,EACrC,KAAK,kBAAkBI,CAAQ,CACjC,OAASd,EAAO,CACd,IAAMc,EAAW,YAAY,IAAI,EAAIJ,EACrC,KAAK,kBAAkBV,EAAgBc,CAAQ,CACjD,QAAE,CACA,KAAK,UAAY,EACnB,CACF,CAKQ,kBAAkBA,EAAwB,CAChD,KAAK,iBAAmB,EACxB,KAAK,aAAe,IAAI,KACxB,KAAK,OAAO,MACV,GAAG,KAAK,OAAO,IAAI,wCAAeA,EAAS,QAAQ,CAAC,CAAC,IACvD,CACF,CAKQ,kBAAkBd,EAAcc,EAAwB,CAQ9D,GAPA,KAAK,mBACL,KAAK,OAAO,KACV,GAAG,KAAK,OAAO,IAAI,sBAAY,KAAK,gBAAgB,IAAI,KAAK,YAAY,WAAW,wBAC3EA,EAAS,QAAQ,CAAC,CAAC,yBAAUd,EAAM,OAAO,EACrD,EAGI,KAAK,kBAAoB,KAAK,YAAY,YAAa,CACzD,KAAK,OAAO,MACV,GAAG,KAAK,OAAO,IAAI,iGACrB,EAGA,KAAK,mBAAmB,EAGxB,IAAMe,EAAkB,IAAI,MAC1B,6DAAgB,KAAK,gBAAgB,wDACvC,EACA,KAAK,sBAAsBA,CAAe,CAC5C,CACF,CAKQ,gBAAuB,CAC7B,KAAK,iBAAmB,EACxB,KAAK,aAAe,KACpB,KAAK,UAAY,EACnB,CAKA,YAAmB,CACjB,KAAK,YAAY,QAAU,GAC3B,KAAK,OAAO,KAAK,GAAG,KAAK,OAAO,IAAI,qCAAY,EAG5C,KAAK,YAAY,GACnB,KAAK,oBAAoB,CAE7B,CAKA,aAAoB,CAClB,KAAK,YAAY,QAAU,GAC3B,KAAK,mBAAmB,EACxB,KAAK,OAAO,KAAK,GAAG,KAAK,OAAO,IAAI,qCAAY,CAClD,CAKA,kBAAkBxB,EAAqC,CACrD,IAAMyB,EAAa,KAAK,YAAY,QACpC,KAAK,YAAc,CAAE,GAAG,KAAK,YAAa,GAAGzB,CAAQ,EAErD,KAAK,OAAO,KAAK,GAAG,KAAK,OAAO,IAAI,sCAAcA,CAAO,EAGrDyB,IAAe,KAAK,YAAY,UAC9B,KAAK,YAAY,SAAW,KAAK,YAAY,EAC/C,KAAK,oBAAoB,EACf,KAAK,YAAY,SAC3B,KAAK,mBAAmB,EAG9B,CAKA,gBAA8B,CAC5B,MAAO,CAAE,GAAG,KAAK,WAAY,CAC/B,CACF,ICxzBA,OAAS,cAAAC,GAAY,WAAAC,OAAe,OA8B7B,SAASC,GACdC,EACAC,EACkB,CAClBC,GAAO,MAAM,6BAASF,CAAW,GAAIC,CAAY,EAEjD,GAAI,CAEF,GAAI,CAACD,GAAe,OAAOA,GAAgB,SACzC,MAAM,IAAIG,EAAsB,0EAAc,EAGhD,GAAI,CAACF,GAAgB,OAAOA,GAAiB,SAC3C,MAAM,IAAIE,EAAsB,mDAAYH,CAAW,EAIzD,IAAMI,EAAYC,GAAoBL,EAAaC,CAAY,EAG/D,OAAAK,GAAkBF,CAAS,EAE3BF,GAAO,KAAK,yCAAWF,CAAW,OAAOI,EAAU,IAAI,EAAE,EAClDA,CACT,OAASG,EAAO,CACd,MAAAL,GAAO,MAAM,yCAAWF,CAAW,GAAIO,CAAK,EACtCA,aAAiBJ,EACnBI,EACA,IAAIJ,EACF,yCAAWI,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,GACjEP,CACF,CACN,CACF,CAKA,SAASK,GACPL,EACAC,EACkB,CAElB,GAAIO,GAAcP,CAAY,EAC5B,OAAOQ,GAAmBT,EAAaC,CAAY,EAIrD,GAAIS,GAAYT,CAAY,EAC1B,OAAOU,GAAiBX,EAAaC,CAAY,EAInD,GAAIW,GAAuBX,CAAY,EACrC,OAAOY,GAA4Bb,EAAaC,CAAY,EAG9D,MAAM,IAAIE,EAAsB,yDAAaH,CAAW,CAC1D,CAKA,SAASS,GACPT,EACAc,EACkB,CAClB,GAAI,CAACA,EAAO,QACV,MAAM,IAAIX,EACR,wEACAH,CACF,EAIF,IAAMe,EAAa,QAAQ,IAAI,oBAAsB,QAAQ,IAAI,EAG3DC,GAAgBF,EAAO,MAAQ,CAAC,GAAG,IAAKG,GAAQ,CAEpD,GAAIC,GAAeD,CAAG,EAAG,CACvB,IAAME,EAAerB,GAAQiB,EAAYE,CAAG,EAC5C,OAAAf,GAAO,MAAM,yCAAWe,CAAG,OAAOE,CAAY,EAAE,EACzCA,CACT,CACA,OAAOF,CACT,CAAC,EAED,MAAO,CACL,KAAMjB,EACN,aACA,QAASc,EAAO,QAChB,KAAME,EACN,IAAKF,EAAO,IAEZ,UAAW,CACT,QAAS,GACT,YAAa,EACb,gBAAiB,IACjB,YAAa,IACb,gBAAiB,cACjB,kBAAmB,IACnB,QAAS,IACT,OAAQ,EACV,EAEA,KAAM,CACJ,QAAS,GACT,SAAU,IACV,QAAS,IACT,YAAa,EACb,WAAY,GACd,EACA,QAAS,GACX,CACF,CAKA,SAASH,GACPX,EACAc,EACkB,CAClB,GAAI,CAACA,EAAO,IACV,MAAM,IAAIX,EAAsB,4DAAqBH,CAAW,EAIlE,IAAMoB,EAAeC,GAAgBP,EAAO,GAAG,EAEzCQ,EAA+B,CACnC,KAAMtB,EACN,KAAMoB,yBACN,IAAKN,EAAO,IAEZ,UAAW,CACT,QAAS,GACT,YAAa,GACb,gBAAiB,IACjB,YAAa,IACb,gBAAiB,cACjB,kBAAmB,IACnB,QAAS,KACT,OAAQ,EACV,EAEA,KAAM,CACJ,QAAS,GACT,SAAU,IACV,QAAS,IACT,YAAa,EACb,WAAY,GACd,EACA,QAAS,GACX,EAGA,OAAIM,IACFE,EAAW,eAAiB,IAGvBA,CACT,CAKA,SAAST,GACPb,EACAc,EACkB,CAClB,GAAI,CAACA,EAAO,IACV,MAAM,IAAIX,EACR,wEACAH,CACF,EAGF,MAAO,CACL,KAAMA,EACN,uBACA,IAAKc,EAAO,IAEZ,UAAW,CACT,QAAS,GACT,YAAa,EACb,gBAAiB,IACjB,YAAa,IACb,gBAAiB,cACjB,kBAAmB,IACnB,QAAS,KACT,OAAQ,EACV,EAEA,KAAM,CACJ,QAAS,GACT,SAAU,IACV,QAAS,IACT,YAAa,EACb,WAAY,GACd,EACA,QAAS,GACX,CACF,CAsCA,SAASI,GAAeK,EAAuB,CAG7C,OAAI1B,GAAW0B,CAAI,EACV,GAML,GAAAA,EAAK,WAAW,IAAI,GAAKA,EAAK,WAAW,KAAK,GAK9C,yBAAyB,KAAKA,CAAI,EAKxC,CAKA,SAASf,GACPM,EACgC,CAChC,MAAO,YAAaA,GAAU,OAAOA,EAAO,SAAY,QAC1D,CAKA,SAASJ,GAAYI,EAAuD,CAC1E,MAAO,SAAUA,GAAUA,EAAO,OAAS,OAAS,QAASA,CAC/D,CAKA,SAASF,GACPE,EACyC,CACzC,MACE,QAASA,IACR,EAAE,SAAUA,IAAWA,EAAO,OAAS,kBAE5C,CAKA,SAASO,GAAgBG,EAAsB,CAC7C,OAAOA,EAAI,SAAS,gBAAgB,GAAKA,EAAI,SAAS,eAAe,CACvE,CAKA,SAASlB,GAAkBQ,EAAgC,CACzD,GAAI,CAACA,EAAO,MAAQ,OAAOA,EAAO,MAAS,SACzC,MAAM,IAAIX,EAAsB,0EAAmB,EAGrD,GAAI,CAAC,OAAO,OAAOsB,EAAgB,EAAE,SAASX,EAAO,IAAI,EACvD,MAAM,IAAIX,EAAsB,+CAAYW,EAAO,IAAI,EAAE,EAI3D,OAAQA,EAAO,KAAM,CACnB,YACE,GAAI,CAACA,EAAO,QACV,MAAM,IAAIX,EAAsB,iEAAyB,EAE3D,MAEF,UACA,qBACA,sBACE,GAAI,CAACW,EAAO,IACV,MAAM,IAAIX,EAAsB,GAAGW,EAAO,IAAI,wDAAgB,EAEhE,MAEF,QACE,MAAM,IAAIX,EAAsB,qDAAaW,EAAO,IAAI,EAAE,CAC9D,CACF,CA7WA,IAiBMZ,GAKOC,EAtBbuB,GAAAC,EAAA,kBAMAC,IAQAC,KAGM3B,GAASA,EAAa,QAAQ,eAAe,EAKtCC,EAAN,cAAoC,KAAM,CAC/C,YACE2B,EACgBC,EAChB,CACA,MAAMD,CAAO,EAFG,gBAAAC,EAGhB,KAAK,KAAO,uBACd,CA7BF,MAsBiD,CAAAC,EAAA,8BAQjD,EAKgBA,EAAAjC,GAAA,sBAsCPiC,EAAA3B,GAAA,uBAyBA2B,EAAAvB,GAAA,sBAyDAuB,EAAArB,GAAA,oBAgDAqB,EAAAnB,GAAA,+BA0EAmB,EAAAd,GAAA,kBAyBAc,EAAAxB,GAAA,iBASAwB,EAAAtB,GAAA,eAOAsB,EAAApB,GAAA,0BAYAoB,EAAAX,GAAA,mBAOAW,EAAA1B,GAAA,uBCjRF,SAAS2B,GACdC,EACsB,CAEtB,GAAI,CAACA,GAAgB,OAAOA,GAAiB,SAC3C,MAAM,IAAI,MAAM,sFAAgB,EAIlC,GAAI,YAAaA,GAAgB,OAAOA,EAAa,SAAY,SAC/D,MAAO,QAIT,GAAI,SAAUA,GAAgBA,EAAa,OAAS,MAClD,MAAO,MAIT,GACG,SAAUA,GAAgBA,EAAa,OAAS,mBAChD,QAASA,GAAgB,OAAOA,EAAa,KAAQ,SAEtD,MAAO,kBAIT,MAAM,IAAI,MACR,wPACF,CACF,CAsDO,SAASC,GACdC,EACAF,EACoC,CACpC,GAAI,CAACA,GAAgB,OAAOA,GAAiB,SAC3C,MAAO,CACL,MAAO,GACP,MAAO,iBAAOE,CAAU,gEAC1B,EAGF,GAAI,CAGF,OAF0BH,GAA8BC,CAAY,EAEzC,CACzB,IAAK,QACH,GAAI,CAACA,EAAa,SAAW,OAAOA,EAAa,SAAY,SAC3D,MAAO,CACL,MAAO,GACP,MAAO,iBAAOE,CAAU,uGAC1B,EAEF,GAAI,CAAC,MAAM,QAAQF,EAAa,IAAI,EAClC,MAAO,CACL,MAAO,GACP,MAAO,iBAAOE,CAAU,0DAC1B,EAEF,GAAIF,EAAa,KAAO,OAAOA,EAAa,KAAQ,SAClD,MAAO,CACL,MAAO,GACP,MAAO,iBAAOE,CAAU,yDAC1B,EAEF,MAEF,IAAK,MACH,GAAIF,EAAa,OAAS,MACxB,MAAO,CACL,MAAO,GACP,MAAO,iBAAOE,CAAU,oDAC1B,EAEF,GAAI,CAACF,EAAa,KAAO,OAAOA,EAAa,KAAQ,SACnD,MAAO,CACL,MAAO,GACP,MAAO,iBAAOE,CAAU,mGAC1B,EAEF,MAEF,IAAK,kBACH,GAAI,CAACF,EAAa,KAAO,OAAOA,EAAa,KAAQ,SACnD,MAAO,CACL,MAAO,GACP,MAAO,iBAAOE,CAAU,mGAC1B,EAEF,GAAIF,EAAa,MAAQA,EAAa,OAAS,kBAC7C,MAAO,CACL,MAAO,GACP,MAAO,iBAAOE,CAAU,8FAC1B,EAEF,MAEF,QACE,MAAO,CACL,MAAO,GACP,MAAO,iBAAOA,CAAU,0DAC1B,CACJ,CAEA,MAAO,CAAE,MAAO,EAAK,CACvB,OAASC,EAAO,CACd,MAAO,CACL,MAAO,GACP,MAAO,iBAAOD,CAAU,qCACtBC,aAAiB,MAAQA,EAAM,QAAU,0BAC3C,EACF,CACF,CACF,CAtOA,IAAAC,GAAAC,EAAA,kBAgEgBC,EAAAP,GAAA,iCAoFAO,EAAAL,GAAA,6BCpJhB,IAAAM,GAAA,GAAAC,EAAAD,GAAA,mBAAAE,GAAA,kBAAAC,IAAA,OAAS,gBAAAC,GAAc,cAAAC,GAAY,gBAAAC,GAAc,iBAAAC,OAAqB,KACtE,OAAS,WAAAC,GAAS,WAAAC,MAAe,OACjC,OAAS,iBAAAC,OAAqB,MAC9B,UAAYC,OAAiB,eAC7B,OAAOC,OAAW,QAClB,OAAOC,OAAW,QAClB,UAAYC,OAAiB,eAN7B,IAWMC,GAGAC,GAuEOd,GAi4BAC,EAt9Bbc,EAAAC,EAAA,kBAOAC,IACAC,KAGML,GAAYP,GAAQE,GAAc,YAAY,GAAG,CAAC,EAGlDM,GAAwD,CAC5D,kBAAmB,IACnB,iBAAkB,IAClB,kBAAmB,GACrB,EAmEad,GAAN,MAAMmB,CAAc,CArF3B,MAqF2B,CAAAC,EAAA,sBACzB,OAAe,SACP,kBACA,OAA2B,KAC3B,kBAAmC,KACnC,YAAmB,KAEnB,aAAc,CAGpB,IAAMC,EAAgB,CAEpBd,EAAQM,GAAW,YAAa,UAAW,qBAAqB,EAEhEN,EAAQM,GAAW,KAAM,YAAa,UAAW,qBAAqB,EAEtEN,EAAQ,QAAQ,IAAI,EAAG,YAAa,UAAW,qBAAqB,CACtE,EAGA,KAAK,kBACHc,EAAc,KAAMC,GAASnB,GAAWmB,CAAI,CAAC,GAAKD,EAAc,CAAC,CACrE,CAMQ,mBAA4B,CAElC,IAAME,EAAY,QAAQ,IAAI,oBAAsB,QAAQ,IAAI,EAG1DC,EAAkB,CACtB,uBACA,uBACA,qBACF,EAEA,QAAWC,KAAYD,EAAiB,CACtC,IAAME,EAAWnB,EAAQgB,EAAWE,CAAQ,EAC5C,GAAItB,GAAWuB,CAAQ,EACrB,OAAOA,CAEX,CAGA,OAAOnB,EAAQgB,EAAW,qBAAqB,CACjD,CAKQ,oBAAoBG,EAA8C,CACxE,OAAIA,EAAS,SAAS,QAAQ,EACrB,QAGLA,EAAS,SAAS,QAAQ,EACrB,QAGF,MACT,CAKA,OAAc,aAA6B,CACzC,OAAKP,EAAc,WACjBA,EAAc,SAAW,IAAIA,GAExBA,EAAc,QACvB,CAKO,cAAwB,CAE7B,IAAMI,EAAY,QAAQ,IAAI,oBAAsB,QAAQ,IAAI,EAG1DC,EAAkB,CACtB,uBACA,uBACA,qBACF,EAEA,QAAWC,KAAYD,EAAiB,CACtC,IAAME,EAAWnB,EAAQgB,EAAWE,CAAQ,EAC5C,GAAItB,GAAWuB,CAAQ,EACrB,MAAO,EAEX,CAEA,MAAO,EACT,CAOO,WAAWC,EAAqC,OAAc,CACnE,GAAI,CAACxB,GAAW,KAAK,iBAAiB,EACpC,MAAM,IAAI,MAAM,uEAAgB,KAAK,iBAAiB,EAAE,EAI1D,GAAI,KAAK,aAAa,EACpB,MAAM,IAAI,MAAM,4FAAiB,EAInC,IAAMoB,EAAY,QAAQ,IAAI,oBAAsB,QAAQ,IAAI,EAC1DK,EAAiB,kBAAkBD,CAAM,GACzCE,EAAatB,EAAQgB,EAAWK,CAAc,EAGpD1B,GAAa,KAAK,kBAAmB2B,CAAU,EAC/C,KAAK,OAAS,KACd,KAAK,YAAc,IACrB,CAKQ,YAAwB,CAC9B,GAAI,CAAC,KAAK,aAAa,EACrB,MAAM,IAAI,MAAM,sHAAiC,EAGnD,GAAI,CACF,IAAMA,EAAa,KAAK,kBAAkB,EAC1C,KAAK,kBAAoBA,EACzB,IAAMC,EAAmB,KAAK,oBAAoBD,CAAU,EAMtDE,EALgB3B,GAAayB,EAAY,MAAM,EAKpB,QAAQ,UAAW,EAAE,EAElDG,EAGJ,OAAQF,EAAkB,CACxB,IAAK,QAEHE,EAASrB,GAAM,MAAMoB,CAAU,EAE/B,KAAK,YAA0B,QAAKA,CAAU,EAC9C,MACF,IAAK,QAEHC,EAAqB,SAAMD,CAAU,EACrC,MACF,QACEC,EAAS,KAAK,MAAMD,CAAU,EAC9B,KACJ,CAGA,YAAK,eAAeC,CAAM,EAEnBA,CACT,OAASC,EAAO,CACd,MAAIA,aAAiB,YACb,IAAI,MAAM,qDAAaA,EAAM,OAAO,EAAE,EAExCA,CACR,CACF,CAKQ,eAAeD,EAAuB,CAC5C,GAAI,CAACA,GAAU,OAAOA,GAAW,SAC/B,MAAM,IAAI,MAAM,sFAAgB,EAGlC,IAAME,EAAYF,EAElB,GAAIE,EAAU,cAAgB,QAAaA,EAAU,cAAgB,KACnE,MAAM,IAAI,MAAM,4FAA2B,EAI7C,GAAI,OAAOA,EAAU,aAAgB,SAE9B,GAAI,MAAM,QAAQA,EAAU,WAAW,EAAG,CAC/C,GAAIA,EAAU,YAAY,SAAW,EACnC,MAAM,IAAI,MAAM,wGAA6B,EAE/C,QAAWC,KAAYD,EAAU,YAC/B,GAAI,OAAOC,GAAa,UAAYA,EAAS,KAAK,IAAM,GACtD,MAAM,IAAI,MACR,oKACF,CAGN,KACE,OAAM,IAAI,MAAM,4IAAmC,EAGrD,GAAI,CAACD,EAAU,YAAc,OAAOA,EAAU,YAAe,SAC3D,MAAM,IAAI,MAAM,2FAA0B,EAI5C,OAAW,CAACE,EAAYC,CAAY,IAAK,OAAO,QAC9CH,EAAU,UACZ,EAAG,CACD,GAAI,CAACG,GAAgB,OAAOA,GAAiB,SAC3C,MAAM,IAAI,MAAM,oEAAuBD,CAAU,eAAK,EAIxD,IAAME,EAAaC,GAAwBH,EAAYC,CAAY,EACnE,GAAI,CAACC,EAAW,MACd,MAAM,IAAI,MAAM,yDAAYA,EAAW,KAAK,EAAE,CAElD,CACF,CAKO,WAAiC,CACtC,YAAK,OAAS,KAAK,WAAW,EAGvB,KAAK,MAAM,KAAK,UAAU,KAAK,MAAM,CAAC,CAC/C,CAKQ,kBAA8B,CACpC,OAAK,KAAK,SACR,KAAK,OAAS,KAAK,WAAW,GAEzB,KAAK,MACd,CAMO,gBAAyB,CAC9B,IAAMN,EAAS,KAAK,UAAU,EAC9B,OAAI,MAAM,QAAQA,EAAO,WAAW,EAC3BA,EAAO,YAAY,CAAC,GAAK,GAE3BA,EAAO,WAChB,CAKO,iBAA4B,CACjC,IAAMA,EAAS,KAAK,UAAU,EAC9B,OAAI,MAAM,QAAQA,EAAO,WAAW,EAC3B,CAAC,GAAGA,EAAO,WAAW,EAExBA,EAAO,YAAc,CAACA,EAAO,WAAW,EAAI,CAAC,CACtD,CAKO,eAA2D,CAEhE,OADe,KAAK,UAAU,EAChB,UAChB,CAKO,oBAAqE,CAE1E,OADe,KAAK,UAAU,EAChB,iBAAmB,CAAC,CACpC,CAKO,qBACLI,EACyC,CAEzC,OADqB,KAAK,mBAAmB,EACzBA,CAAU,GAAG,OAAS,CAAC,CAC7C,CAKO,cAAcA,EAAoBI,EAA2B,CAGlE,OAFoB,KAAK,qBAAqBJ,CAAU,EACzBI,CAAQ,GACpB,SAAW,EAChC,CAKO,kBAAkBL,EAAmC,CAC1D,GAAI,MAAM,QAAQA,CAAQ,EAAG,CAC3B,GAAIA,EAAS,SAAW,EACtB,MAAM,IAAI,MAAM,sDAAc,EAEhC,QAAWM,KAAMN,EACf,GAAI,CAACM,GAAM,OAAOA,GAAO,SACvB,MAAM,IAAI,MAAM,kHAAwB,CAG9C,SACM,CAACN,GAAY,OAAOA,GAAa,SACnC,MAAM,IAAI,MAAM,kEAAgB,EAIpC,IAAMH,EAAS,KAAK,iBAAiB,EACrCA,EAAO,YAAcG,EACrB,KAAK,WAAWH,CAAM,CACxB,CAKO,eAAeG,EAAwB,CAC5C,GAAI,CAACA,GAAY,OAAOA,GAAa,SACnC,MAAM,IAAI,MAAM,kEAAgB,EAGlC,IAAMH,EAAS,KAAK,iBAAiB,EAC/BU,EAAmB,KAAK,gBAAgB,EAG9C,GAAIA,EAAiB,SAASP,CAAQ,EACpC,MAAM,IAAI,MAAM,oBAAUA,CAAQ,qBAAM,EAG1C,IAAMQ,EAAe,CAAC,GAAGD,EAAkBP,CAAQ,EACnDH,EAAO,YAAcW,EACrB,KAAK,WAAWX,CAAM,CACxB,CAKO,kBAAkBG,EAAwB,CAC/C,GAAI,CAACA,GAAY,OAAOA,GAAa,SACnC,MAAM,IAAI,MAAM,kEAAgB,EAGlC,IAAMH,EAAS,KAAK,iBAAiB,EAC/BU,EAAmB,KAAK,gBAAgB,EAI9C,GADcA,EAAiB,QAAQP,CAAQ,IACjC,GACZ,MAAM,IAAI,MAAM,oBAAUA,CAAQ,qBAAM,EAI1C,GAAIO,EAAiB,SAAW,EAC9B,MAAM,IAAI,MAAM,mEAAiB,EAGnC,IAAMC,EAAeD,EAAiB,OAAQD,GAAOA,IAAON,CAAQ,EACpEH,EAAO,YAAcW,EACrB,KAAK,WAAWX,CAAM,CACxB,CAKO,gBACLI,EACAC,EACM,CACN,GAAI,CAACD,GAAc,OAAOA,GAAe,SACvC,MAAM,IAAI,MAAM,0EAAc,EAIhC,IAAME,EAAaC,GAAwBH,EAAYC,CAAY,EACnE,GAAI,CAACC,EAAW,MACd,MAAM,IAAI,MAAMA,EAAW,OAAS,kDAAU,EAEhD,IAAMN,EAAS,KAAK,iBAAiB,EAErCA,EAAO,WAAWI,CAAU,EAAIC,EAChC,KAAK,WAAWL,CAAM,CACxB,CAKO,gBAAgBI,EAA0B,CAC/C,GAAI,CAACA,GAAc,OAAOA,GAAe,SACvC,MAAM,IAAI,MAAM,0EAAc,EAGhC,IAAMJ,EAAS,KAAK,UAAU,EAC9B,GAAI,CAACA,EAAO,WAAWI,CAAU,EAC/B,MAAM,IAAI,MAAM,gBAAMA,CAAU,qBAAM,EAGxC,IAAMQ,EAAgB,CAAE,GAAGZ,EAAO,UAAW,EAC7C,OAAOY,EAAcR,CAAU,EAE/B,IAAMS,EAAY,CAChB,GAAGb,EACH,WAAYY,CACd,EACA,KAAK,WAAWC,CAAS,CAC3B,CAKO,wBACLT,EACAU,EACM,CACN,IAAMd,EAAS,KAAK,iBAAiB,EAGhCA,EAAO,kBACVA,EAAO,gBAAkB,CAAC,GAIxB,OAAO,KAAKc,CAAW,EAAE,SAAW,EACtC,OAAOd,EAAO,gBAAgBI,CAAU,EAGxCJ,EAAO,gBAAgBI,CAAU,EAAI,CACnC,MAAOU,CACT,EAGF,KAAK,WAAWd,CAAM,CACxB,CAKO,wBAAwBI,EAA0B,CAEvD,IAAMS,EAAY,CAAE,GADL,KAAK,UAAU,CACA,EAG1BA,EAAU,kBAEZ,OAAOA,EAAU,gBAAgBT,CAAU,EAC3C,KAAK,WAAWS,CAAS,EAE7B,CAMO,iCAAwC,CAC7C,IAAMb,EAAS,KAAK,iBAAiB,EAGrC,GAAI,CAACA,EAAO,gBACV,OAGF,IAAMe,EAAmB,OAAO,KAAKf,EAAO,UAAU,EAIhDgB,EAHwB,OAAO,KAAKhB,EAAO,eAAe,EAGf,OAC9CI,GAAe,CAACW,EAAiB,SAASX,CAAU,CACvD,EAEA,GAAIY,EAAmB,OAAS,EAAG,CAEjC,QAAWZ,KAAcY,EACvB,OAAOhB,EAAO,gBAAgBI,CAAU,EAG1C,KAAK,WAAWJ,CAAM,EAEtBiB,EAAO,KACL,sBAAOD,EAAmB,MAAM,kEAAgBA,EAAmB,KAAK,IAAI,CAAC,EAC/E,CACF,CACF,CAKO,eACLZ,EACAI,EACAU,EACAC,EACM,CACN,IAAMnB,EAAS,KAAK,iBAAiB,EAGhCA,EAAO,kBACVA,EAAO,gBAAkB,CAAC,GAIvBA,EAAO,gBAAgBI,CAAU,IACpCJ,EAAO,gBAAgBI,CAAU,EAAI,CAAE,MAAO,CAAC,CAAE,GAInDJ,EAAO,gBAAgBI,CAAU,EAAE,MAAMI,CAAQ,EAAI,CACnD,GAAGR,EAAO,gBAAgBI,CAAU,EAAE,MAAMI,CAAQ,EACpD,OAAQU,EACR,GAAIC,GAAe,CAAE,YAAAA,CAAY,CACnC,EAEA,KAAK,WAAWnB,CAAM,CACxB,CAMQ,WAAWA,EAAyB,CAC1C,GAAI,CAEF,KAAK,eAAeA,CAAM,EAG1B,IAAIH,EACA,KAAK,kBACPA,EAAa,KAAK,mBAGlBA,EAAa,KAAK,kBAAkB,EACpC,KAAK,kBAAoBA,GAI3B,IAAMC,EAAmB,KAAK,oBAAoBD,CAAU,EACxDuB,EAEJ,OAAQtB,EAAkB,CACxB,IAAK,QAEH,GAAI,CACE,KAAK,aAEP,KAAK,YAAY,MAAME,CAAM,EAC7BoB,EAAgB,KAAK,YAAY,SAAS,IAG1C,QAAQ,KAAK,8FAAkC,EAC/CA,EAAgBzC,GAAM,UAAUqB,EAAQ,KAAM,CAAC,EAEnD,OAASqB,EAAkB,CAEzB,QAAQ,KACN,6GACAA,CACF,EACAD,EAAgBzC,GAAM,UAAUqB,EAAQ,KAAM,CAAC,CACjD,CACA,MACF,IAAK,QAEH,GAAI,CAGFoB,EAA4B,aAAUpB,EAAQ,KAAM,CAAC,CACvD,OAASsB,EAAkB,CAEzB,QAAQ,KACN,4GACAA,CACF,EACAF,EAAgB,KAAK,UAAUpB,EAAQ,KAAM,CAAC,CAChD,CACA,MACF,QACEoB,EAAgB,KAAK,UAAUpB,EAAQ,KAAM,CAAC,EAC9C,KACJ,CAGA3B,GAAcwB,EAAYuB,EAAe,MAAM,EAG/C,KAAK,OAASpB,EAGd,KAAK,mBAAmBA,CAAM,CAChC,OAASC,EAAO,CACd,MAAM,IAAI,MACR,yCACEA,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CACvD,EACF,CACF,CACF,CAKO,cAAqB,CAC1B,KAAK,OAAS,KACd,KAAK,kBAAoB,KACzB,KAAK,YAAc,IACrB,CAKO,eAAwB,CAC7B,OAAO,KAAK,kBAAkB,CAChC,CAKO,sBAA+B,CACpC,OAAO,KAAK,iBACd,CAKO,qBAAkD,CAEvD,IAAMsB,EADS,KAAK,UAAU,EACE,YAAc,CAAC,EAE/C,MAAO,CACL,kBACEA,EAAiB,mBACjBzC,GAA0B,kBAC5B,iBACEyC,EAAiB,kBACjBzC,GAA0B,iBAC5B,kBACEyC,EAAiB,mBACjBzC,GAA0B,iBAC9B,CACF,CAKO,sBAA+B,CACpC,OAAO,KAAK,oBAAoB,EAAE,iBACpC,CAKO,qBAA8B,CACnC,OAAO,KAAK,oBAAoB,EAAE,gBACpC,CAKO,sBAA+B,CACpC,OAAO,KAAK,oBAAoB,EAAE,iBACpC,CAKO,uBACLyC,EACM,CACN,IAAMvB,EAAS,KAAK,iBAAiB,EAGhCA,EAAO,aACVA,EAAO,WAAa,CAAC,GAIvB,OAAO,OAAOA,EAAO,WAAYuB,CAAgB,EACjD,KAAK,WAAWvB,CAAM,CACxB,CAQA,MAAa,qBACXI,EACAI,EACAgB,EACe,CACf,GAAI,CACF,IAAMxB,EAAS,KAAK,iBAAiB,EAGhCA,EAAO,kBACVA,EAAO,gBAAkB,CAAC,GAIvBA,EAAO,gBAAgBI,CAAU,IACpCJ,EAAO,gBAAgBI,CAAU,EAAI,CAAE,MAAO,CAAC,CAAE,GAI9CJ,EAAO,gBAAgBI,CAAU,EAAE,MAAMI,CAAQ,IACpDR,EAAO,gBAAgBI,CAAU,EAAE,MAAMI,CAAQ,EAAI,CACnD,OAAQ,EACV,GAGF,IAAMiB,EAAazB,EAAO,gBAAgBI,CAAU,EAAE,MAAMI,CAAQ,EAC9DkB,EAAoBD,EAAW,YAAc,EAC7CE,EAAsBF,EAAW,aAGvCA,EAAW,WAAaC,EAAoB,GAI1C,CAACC,GACD,IAAI,KAAKH,CAAQ,EAAI,IAAI,KAAKG,CAAmB,KAGjDF,EAAW,aAAe/C,GAAM8C,CAAQ,EAAE,OAAO,qBAAqB,GAIxE,KAAK,WAAWxB,CAAM,EAEtBiB,EAAO,MACL,2DAAcb,CAAU,IAAII,CAAQ,+BAAWiB,EAAW,UAAU,EACtE,CACF,OAASxB,EAAO,CAEdgB,EAAO,MACL,iEAAeb,CAAU,IAAII,CAAQ,MACnCP,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CACvD,EACF,CACF,CACF,CAKO,qBAAqB2B,EAAwB,CAClD,GAAIA,GAAY,EACd,MAAM,IAAI,MAAM,+DAAa,EAE/B,KAAK,uBAAuB,CAAE,kBAAmBA,CAAS,CAAC,CAC7D,CAKO,oBAAoBC,EAAuB,CAChD,GAAIA,GAAW,EACb,MAAM,IAAI,MAAM,+DAAa,EAE/B,KAAK,uBAAuB,CAAE,iBAAkBA,CAAQ,CAAC,CAC3D,CAKO,qBAAqBD,EAAwB,CAClD,GAAIA,GAAY,EACd,MAAM,IAAI,MAAM,mDAAW,EAE7B,KAAK,uBAAuB,CAAE,kBAAmBA,CAAS,CAAC,CAC7D,CAKO,qBAAkD,CAEvD,OADe,KAAK,UAAU,EAChB,YAAc,CAAC,CAC/B,CAMO,qBAA0C,CAE/C,OADyB,KAAK,oBAAoB,EAC1B,QAAU,QAAQ,IAAI,oBAChD,CAKO,uBACLE,EACM,CACN,IAAM9B,EAAS,KAAK,iBAAiB,EAGhCA,EAAO,aACVA,EAAO,WAAa,CAAC,GAIvB,OAAO,OAAOA,EAAO,WAAY8B,CAAgB,EACjD,KAAK,WAAW9B,CAAM,CACxB,CAKO,oBAAoB+B,EAAsB,CAC/C,GAAI,CAACA,GAAU,OAAOA,GAAW,SAC/B,MAAM,IAAI,MAAM,0DAAkB,EAEpC,KAAK,uBAAuB,CAAE,OAAAA,CAAO,CAAC,CACxC,CAKO,gBAAwC,CAE7C,OADe,KAAK,UAAU,EAChB,OAAS,CAAC,CAC1B,CAKO,cAAuB,CAE5B,OADoB,KAAK,eAAe,EACrB,MAAQ,IAC7B,CAMQ,mBAAmB/B,EAAyB,CAClD,GAAI,CAEF,IAAMgC,EAAa,OAAe,YAC9BA,GAAa,OAAOA,EAAU,uBAA0B,aAE1DA,EAAU,sBAAsBhC,CAAM,EACtC,QAAQ,IAAI,mEAAsB,EAEtC,OAASC,EAAO,CAEd,QAAQ,KACN,qEACAA,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CACvD,CACF,CACF,CAKO,kBAAkBgC,EAAyC,CAChE,IAAMjC,EAAS,KAAK,iBAAiB,EAGhCA,EAAO,QACVA,EAAO,MAAQ,CAAC,GAIlB,OAAO,OAAOA,EAAO,MAAOiC,CAAW,EACvC,KAAK,WAAWjC,CAAM,CACxB,CAKO,aAAakC,EAAoB,CACtC,GAAI,CAAC,OAAO,UAAUA,CAAI,GAAKA,GAAQ,GAAKA,EAAO,MACjD,MAAM,IAAI,MAAM,6EAAsB,EAExC,KAAK,kBAAkB,CAAE,KAAAA,CAAK,CAAC,CACjC,CACF,EAGajE,EAAgBD,GAAc,YAAY,ICt9BvD,IA8CamE,GA4eNC,GA1hBPC,GAAAC,EAAA,kBASAC,IACAC,IACAC,KAmCaN,GAAN,KAAwB,CA9C/B,MA8C+B,CAAAO,EAAA,0BACrB,SAAoC,IAAI,IACxC,QAA4C,CAAC,EAC7C,OACA,MAA+B,IAAI,IAM3C,YAAYC,EAA4C,CACtD,KAAK,OAASC,EACd,KAAK,QAAUD,GAAW,CAAC,CAC7B,CAKA,MAAM,kBAAkC,CACtC,KAAK,OAAO,KAAK,uEAA+B,EAEhD,IAAME,EAAgB,OAAO,QAAQ,KAAK,OAAO,EACjD,GAAIA,EAAc,SAAW,EAAG,CAC9B,KAAK,OAAO,KACV,oJACF,EACA,MACF,CAEA,OAAW,CAACC,CAAW,IAAKD,EAC1B,MAAM,KAAK,aAAaC,CAAW,EAGrC,KAAK,OAAO,KAAK,oEAA4B,CAC/C,CAKA,MAAM,aAAaA,EAAoC,CACrD,KAAK,OAAO,KAAK,+CAA2BA,CAAW,EAAE,EAEzD,IAAMC,EAAS,KAAK,QAAQD,CAAW,EACvC,GAAI,CAACC,EACH,MAAM,IAAI,MAAM,+CAAYD,CAAW,EAAE,EAG3C,GAAI,CAEE,KAAK,SAAS,IAAIA,CAAW,GAC/B,MAAM,KAAK,YAAYA,CAAW,EAIpC,IAAME,EAAU,IAAIC,GAAWF,CAAM,EAGrC,MAAMC,EAAQ,QAAQ,EAGtB,KAAK,SAAS,IAAIF,EAAaE,CAAO,EAGtC,MAAM,KAAK,kBAAkB,EAE7B,IAAME,EAAQF,EAAQ,SAAS,EAC/B,KAAK,OAAO,KACV,gBAAgBF,CAAW,iEAAeI,EAAM,MAAM,uBACtDA,EAAM,IAAKC,GAAMA,EAAE,IAAI,EAAE,KAAK,IAAI,CACpC,CACF,OAASC,EAAO,CACd,WAAK,OAAO,MACV,6BAAmBN,CAAW,6BAC7BM,EAAgB,OACnB,EACMA,CACR,CACF,CAKA,MAAM,YAAYN,EAAoC,CACpD,KAAK,OAAO,KAAK,+CAA2BA,CAAW,EAAE,EAEzD,IAAME,EAAU,KAAK,SAAS,IAAIF,CAAW,EAC7C,GAAI,CAACE,EAAS,CACZ,KAAK,OAAO,KAAK,6BAAmBF,CAAW,6CAAU,EACzD,MACF,CAEA,GAAI,CACF,MAAME,EAAQ,WAAW,EACzB,KAAK,SAAS,OAAOF,CAAW,EAGhC,MAAM,KAAK,kBAAkB,EAE7B,KAAK,OAAO,KAAK,gBAAgBA,CAAW,iCAAQ,CACtD,OAASM,EAAO,CACd,WAAK,OAAO,MACV,6BAAmBN,CAAW,6BAC7BM,EAAgB,OACnB,EACMA,CACR,CACF,CAKA,MAAc,mBAAmC,CAC/C,KAAK,MAAM,MAAM,EAEjB,OAAW,CAACN,EAAaE,CAAO,IAAK,KAAK,SACxC,GAAIA,EAAQ,YAAY,EAAG,CACzB,IAAME,EAAQF,EAAQ,SAAS,EAC/B,QAAWK,KAAQH,EAAO,CACxB,IAAMI,EAAU,GAAGR,CAAW,KAAKO,EAAK,IAAI,GAC5C,KAAK,MAAM,IAAIC,EAAS,CACtB,YAAAR,EACA,aAAcO,EAAK,KACnB,KAAAA,CACF,CAAC,CACH,CACF,CAIF,MAAM,KAAK,sBAAsB,CACnC,CAKA,aAMG,CACD,IAAME,EAMD,CAAC,EAEN,OAAW,CAACD,EAASE,CAAQ,IAAK,KAAK,MAEnBC,EAAc,cAC9BD,EAAS,YACTA,EAAS,YACX,GAIED,EAAS,KAAK,CACZ,KAAMD,EACN,YAAaE,EAAS,KAAK,aAAe,GAC1C,YAAaA,EAAS,KAAK,YAC3B,YAAaA,EAAS,YACtB,aAAcA,EAAS,YACzB,CAAC,EAGL,OAAOD,CACT,CAKA,MAAM,SAASG,EAAkBC,EAA0C,CACzE,KAAK,OAAO,KAAK,0CAAsBD,CAAQ,sBAAQC,CAAU,EAEjE,IAAMH,EAAW,KAAK,MAAM,IAAIE,CAAQ,EACxC,GAAI,CAACF,EACH,MAAM,IAAI,MAAM,mCAAUE,CAAQ,EAAE,EAGtC,IAAMV,EAAU,KAAK,SAAS,IAAIQ,EAAS,WAAW,EACtD,GAAI,CAACR,EACH,MAAM,IAAI,MAAM,gBAAMQ,EAAS,WAAW,qBAAM,EAGlD,GAAI,CAACR,EAAQ,YAAY,EACvB,MAAM,IAAI,MAAM,gBAAMQ,EAAS,WAAW,qBAAM,EAGlD,GAAI,CACF,IAAMI,EAAS,MAAMZ,EAAQ,SAC3BQ,EAAS,aACTG,GAAc,CAAC,CACjB,EAEA,YAAK,OAAO,KAAK,6BAAmBD,CAAQ,+CAAaE,CAAM,EACxDA,CACT,OAASR,EAAO,CACd,WAAK,OAAO,MACV,6BAAmBM,CAAQ,6BAC1BN,EAAgB,OACnB,EACMA,CACR,CACF,CAKA,MAAM,iBAAiC,CACrC,KAAK,OAAO,KAAK,uEAA+B,EAGhD,OAAW,CAACN,EAAaE,CAAO,IAAK,KAAK,SACxC,GAAI,CACF,MAAMA,EAAQ,WAAW,EACzB,KAAK,OAAO,KAAK,gBAAgBF,CAAW,iCAAQ,CACtD,OAASM,EAAO,CACd,KAAK,OAAO,MACV,6BAAmBN,CAAW,6BAC7BM,EAAgB,OACnB,CACF,CAGF,KAAK,SAAS,MAAM,EACpB,KAAK,MAAM,MAAM,EAEjB,KAAK,OAAO,KAAK,8DAA2B,CAC9C,CAKA,WAA2B,CACzB,IAAMS,EAAwB,CAC5B,SAAU,CAAC,EACX,WAAY,KAAK,MAAM,KACvB,eAAgB,MAAM,KAAK,KAAK,MAAM,KAAK,CAAC,CAC9C,EAEA,OAAW,CAACf,EAAaE,CAAO,IAAK,KAAK,SAAU,CAClD,IAAMc,EAAgBd,EAAQ,UAAU,EACxCa,EAAO,SAASf,CAAW,EAAI,CAC7B,UAAWgB,EAAc,UACzB,WAAY,WAAWhB,CAAW,SACpC,CACF,CAEA,OAAOe,CACT,CAKA,WAAWE,EAAsC,CAC/C,OAAO,KAAK,SAAS,IAAIA,CAAI,CAC/B,CAKA,gBAA0C,CACxC,OAAO,IAAI,IAAI,KAAK,QAAQ,CAC9B,CAMQ,qBAAqBhB,EAA4C,CACvE,IAAMiB,EAAiB,CAAE,GAAGjB,CAAO,EAEnC,GAAI,CAEF,GAAIA,EAAO,OAAS,iBAAiC,CACnD,IAAMkB,EAAmBR,EAAc,oBAAoB,EAC3D,GAAIQ,EACFD,EAAe,OAASC,EACxB,KAAK,OAAO,KACV,uBAAkBlB,EAAO,IAAI,8CAC/B,MAEA,YAAK,OAAO,KACV,gBAAgBA,EAAO,IAAI,oGAC7B,EACM,IAAI,MACR,+BAAqBA,EAAO,IAAI,qGAClC,CAEJ,CAEA,OAAOiB,CACT,OAASZ,EAAO,CACd,WAAK,OAAO,MAAM,sDAAwBL,EAAO,IAAI,GAAIK,CAAK,EACxDA,CACR,CACF,CAOA,iBACEc,EACAnB,EACM,CACN,IAAIoB,EACArB,EAEJ,GAAI,OAAOoB,GAAiB,UAAYnB,EAEtCD,EAAcoB,EACdC,EAAcpB,UACL,OAAOmB,GAAiB,SAEjCpB,EAAcoB,EAAa,KAC3BC,EAAcD,MAEd,OAAM,IAAI,MAAM,wCAAwC,EAI1D,IAAMF,EAAiB,KAAK,qBAAqBG,CAAW,EAG5D,KAAK,QAAQrB,CAAW,EAAIkB,EAC5B,KAAK,OAAO,KAAK,4DAAyBlB,CAAW,EAAE,CACzD,CAKA,oBAAoBiB,EAAchB,EAAgC,CAEhE,IAAMiB,EAAiB,KAAK,qBAAqBjB,CAAM,EAGvD,KAAK,QAAQgB,CAAI,EAAIC,EACrB,KAAK,OAAO,KAAK,8EAA4BD,CAAI,EAAE,CACrD,CAKA,oBAAoBA,EAAoB,CACtC,OAAO,KAAK,QAAQA,CAAI,EACxB,KAAK,OAAO,KAAK,4DAAyBA,CAAI,EAAE,CAClD,CAMA,MAAc,uBAAuC,CACnD,GAAI,CACF,KAAK,OAAO,MAAM,6FAA4B,EAG9C,IAAMK,EAAuBX,EAAc,mBAAmB,EAG9D,OAAW,CAACX,EAAaE,CAAO,IAAK,KAAK,SAAU,CAClD,GAAI,CAACA,EAAQ,YAAY,EACvB,SAGF,IAAME,EAAQF,EAAQ,SAAS,EAC/B,GAAIE,EAAM,SAAW,EACnB,SAIF,IAAMmB,EACJD,EAAqBtB,CAAW,GAAG,OAAS,CAAC,EAGzCwB,EAAgD,CAAC,EAEvD,QAAWjB,KAAQH,EAAO,CACxB,IAAMqB,GAAoBF,EAAmBhB,EAAK,IAAI,EAGlDkB,GACFD,EAAejB,EAAK,IAAI,EAAI,CAC1B,GAAGkB,GACH,YACElB,EAAK,aAAekB,GAAkB,aAAe,EACzD,EAGAD,EAAejB,EAAK,IAAI,EAAI,CAC1B,YAAaA,EAAK,aAAe,GACjC,OAAQ,EACV,CAEJ,CAGA,IAAMmB,EAAmBtB,EAAM,IAAKC,GAAMA,EAAE,IAAI,EAE1CsB,EADkB,OAAO,KAAKJ,CAAkB,EACjB,OAClCN,GAAS,CAACS,EAAiB,SAAST,CAAI,CAC3C,EAcA,GAZIU,EAAa,OAAS,GACxB,KAAK,OAAO,KACV,+CAAsB3B,CAAW,uBAAQ2B,EAAa,MAAM,wBAASA,EAAa,KAAK,IAAI,CAAC,EAC9F,EAIiB,KAAK,sBACtBJ,EACAC,CACF,EAEgB,CAEdb,EAAc,wBAAwBX,EAAawB,CAAc,EAEjE,IAAMI,EAAa,OAAO,KAAKJ,CAAc,EAAE,OAC5CP,IAAS,CAACM,EAAmBN,EAAI,CACpC,EACMY,GAAe,OAAO,KAAKL,CAAc,EAAE,OAAQP,IAAS,CAChE,IAAMa,GAAUP,EAAmBN,EAAI,EACjCc,GAAUP,EAAeP,EAAI,EACnC,OAAOa,IAAWA,GAAQ,cAAgBC,GAAQ,WACpD,CAAC,EAED,KAAK,OAAO,KACV,+CAAsB/B,CAAW,kCACnC,EACI4B,EAAW,OAAS,GACtB,KAAK,OAAO,KAAK,iCAAaA,EAAW,KAAK,IAAI,CAAC,EAAE,EAEnDC,GAAa,OAAS,GACxB,KAAK,OAAO,KAAK,iCAAaA,GAAa,KAAK,IAAI,CAAC,EAAE,EAErDF,EAAa,OAAS,GACxB,KAAK,OAAO,KAAK,iCAAaA,EAAa,KAAK,IAAI,CAAC,EAAE,CAE3D,CACF,CAEA,KAAK,OAAO,MAAM,+DAAuB,CAC3C,OAASrB,EAAO,CACd,KAAK,OAAO,MAAM,+FAA+BA,CAAK,CAExD,CACF,CAKQ,sBACN0B,EACAC,EACS,CACT,IAAMC,EAAc,OAAO,KAAKF,CAAa,EACvCG,EAAU,OAAO,KAAKF,CAAS,EAGrC,GAAIC,EAAY,SAAWC,EAAQ,OACjC,MAAO,GAIT,IAAMP,EAAaO,EAAQ,OAAQC,GAAQ,CAACF,EAAY,SAASE,CAAG,CAAC,EAC/DT,EAAeO,EAAY,OAAQE,GAAQ,CAACD,EAAQ,SAASC,CAAG,CAAC,EAEvE,GAAIR,EAAW,OAAS,GAAKD,EAAa,OAAS,EACjD,MAAO,GAIT,QAAWf,KAAYsB,EAAa,CAClC,IAAMG,EAAcL,EAAcpB,CAAQ,EACpC0B,EAAUL,EAAUrB,CAAQ,EAElC,GAAIyB,EAAY,cAAgBC,EAAQ,YACtC,MAAO,EAEX,CAEA,MAAO,EACT,CACF,EAEOhD,GAAQD,KCpff,eAAekD,IAA6C,CAC1D,eAAQ,IAAI,4EAAkC,EAE9B,IAAIC,EAGtB,CAQA,eAAeC,IAA0C,CAEvD,GAAIC,GAAYC,IAAU,cACxB,OAAOD,EAIT,GAAIE,GAAeD,IAAU,eAC3B,OAAOC,EAILD,IAAU,UACZE,GAAM,EAIRF,EAAQ,eACRC,EAAcL,GAAe,EAE7B,GAAI,CACF,OAAAG,EAAW,MAAME,EACjBD,EAAQ,cACRG,GAAa,eAAe,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,EAAG,EAAE,CAAC,GACrFC,GAAY,KAEZ,QAAQ,IAAI,4FAAqCD,EAAU,EAAE,EACtDJ,CACT,OAASM,EAAO,CACd,MAAAL,EAAQ,SACRI,GAAYC,EACZJ,EAAc,KAEd,QAAQ,MACN,uEACCI,EAAgB,OACnB,EACMA,CACR,CACF,CAOA,eAAeC,IAAyB,CACtC,GAAIN,IAAU,UAAwB,CACpC,QAAQ,IAAI,sHAAsC,EAClD,MACF,CAEA,QAAQ,IAAI,kFAAmC,EAC/CA,EAAQ,UAER,GAAI,CAEF,GAAIC,EAAa,CACf,GAAI,CAEF,MAD4B,MAAMA,GACR,gBAAgB,CAC5C,OAASI,EAAO,CACd,QAAQ,MAAM,sEAAiBA,EAAgB,OAAO,CACxD,CACAJ,EAAc,IAChB,CAGIF,IACF,MAAMA,EAAS,gBAAgB,EAC/BA,EAAW,MAGbC,EAAQ,kBACRI,GAAY,KACZD,GAAa,KAEb,QAAQ,IAAI,2EAA8B,CAC5C,OAASE,EAAO,CACd,cAAQ,MACN,iEACCA,EAAgB,OACnB,EAEAH,GAAM,EACAG,CACR,CACF,CAQA,SAASH,IAAc,CACrB,QAAQ,IAAI,mEAA8B,EAE1CH,EAAW,KACXE,EAAc,KACdD,EAAQ,kBACRI,GAAY,KACZD,GAAa,IACf,CAOA,SAASI,IAAyB,CAChC,OAAOP,IAAU,eAA8BD,IAAa,IAC9D,CAOA,SAASS,IAA6B,CACpC,MAAO,CACL,MAAOR,EACP,mBAAoBG,GAAa,IAAI,KAAS,OAC9C,UAAWC,IAAa,OACxB,WAAYD,IAAc,MAC5B,CACF,CASA,eAAeM,IAAgD,CAC7D,eAAQ,IAAI,wFAAoC,EAEhD,MAAMH,GAAQ,EACPR,GAAY,CACrB,CAOA,SAASY,IAA+C,CACtD,OAAOX,CACT,CAOA,eAAeY,IAA0C,CACvD,GAAIX,IAAU,cACZ,MAAO,GAGT,GAAIA,IAAU,gBAA+BC,EAC3C,GAAI,CACF,aAAMA,EACC,EACT,MAAgB,CACd,MAAO,EACT,CAGF,MAAO,EACT,CA/NA,IA6BIF,EACAE,EACAD,EACAI,GACAD,GAqMSS,GAtObC,GAAAC,EAAA,kBAKAC,KAwBIhB,EAAqC,KACrCE,EAAiD,KACjDD,EAAwB,kBACxBI,GAA0B,KAC1BD,GAA4B,KAKjBa,EAAApB,GAAA,kBAcAoB,EAAAlB,GAAA,eA8CAkB,EAAAV,GAAA,WAiDNU,EAAAd,GAAA,SAeAc,EAAAT,GAAA,iBASAS,EAAAR,GAAA,aAgBMQ,EAAAP,GAAA,qBAYNO,EAAAN,GAAA,sBASMM,EAAAL,GAAA,yBAsBFC,GAA6B,CACxC,YAAAd,GACA,QAAAQ,GACA,MAAAJ,GACA,cAAAK,GACA,UAAAC,GACA,kBAAAC,GACA,mBAAAC,GACA,sBAAAC,EACF,EAMA,QAAQ,GAAG,OAAQ,IAAM,CACnBC,GAA2B,cAAc,IAC3C,QAAQ,IAAI,oGAAsC,EAElDA,GAA2B,MAAM,EAErC,CAAC,EAGD,QAAQ,GAAG,oBAAqB,MAAOP,GAAU,CAC/C,QAAQ,MAAM,mGAAsCA,CAAK,EACzD,GAAI,CACF,MAAMO,GAA2B,QAAQ,CAC3C,OAASK,EAAc,CACrB,QAAQ,MAAM,0DAAcA,CAAY,CAC1C,CACF,CAAC,EAGD,QAAQ,GAAG,qBAAsB,MAAOC,GAAW,CACjD,QAAQ,MAAM,0GAA6CA,CAAM,EACjE,GAAI,CACF,MAAMN,GAA2B,QAAQ,CAC3C,OAASK,EAAc,CACrB,QAAQ,MAAM,0DAAcA,CAAY,CAC1C,CACF,CAAC,IC/QD,OAAS,gBAAAE,OAAoB,SAA7B,IA4BYC,GAsENC,GAgBOC,GAlHbC,GAAAC,EAAA,kBAEAC,IACAC,KAyBYN,QACVA,EAAA,oBAAsB,sBACtBA,EAAA,eAAiB,iBACjBA,EAAA,eAAiB,iBACjBA,EAAA,SAAW,WAJDA,QAAA,IAsENC,GAAsD,CAC1D,oBAAqB,IACrB,kBAAmB,IACnB,qBAAsB,GACtB,oBAAqB,cACrB,kBAAmB,IACnB,kBAAmB,sBACnB,kBAAmB,IACnB,2BAA4B,EAC5B,cAAe,EACjB,EAMaC,GAAN,cAAuCH,EAAa,CAlH3D,MAkH2D,CAAAQ,EAAA,iCAEjD,YAA2C,IAAI,IAC/C,iBAAkD,IAAI,IAGtD,kBAA+C,KAC/C,OAGA,cAAgB,GAChB,aAAe,GAGf,QAGA,oBAA6C,KAC7C,gBAA+C,IAAI,IAGnD,gBAAkB,EAClB,qBAAsC,KAGtC,mBAAqB,CAC3B,oBAAqB,EACrB,oBAAqB,EACrB,sBAAuB,EACvB,gBAAiB,EACjB,YAAa,CACX,QAAS,EACT,QAAS,EACT,KAAM,CACR,EACA,qBAAsB,IAAI,GAC5B,EAEA,YAAYC,EAAoC,CAC9C,MAAM,EACN,KAAK,OAASC,EACd,KAAK,QAAU,CAAE,GAAGR,GAAiB,GAAGO,CAAQ,EAEhD,KAAK,OAAO,KAAK,2DAAkC,EACnD,KAAK,OAAO,MAAM,uDAAoC,KAAK,OAAO,CACpE,CAOA,MAAM,WAAWE,EAAqBC,EAA8B,CAClE,GAAI,KAAK,cAAe,CACtB,KAAK,OAAO,KAAK,yGAAwC,EACzD,MACF,CAEA,KAAK,OAAO,KACV,0FAAwCD,EAAU,MAAM,EAC1D,EAEA,GAAI,CAEF,KAAK,yBAAyBA,EAAWC,CAAK,EAG9C,MAAM,KAAK,QAAQ,EAGnB,QAAWC,KAAYF,EACrB,MAAM,KAAK,iBAAiBE,EAAUD,CAAK,EAG7C,KAAK,cAAgB,GAGrB,KAAK,mBAAmB,YAAY,QAClC,QAAQ,YAAY,EAAE,SACxB,KAAK,mBAAmB,YAAY,QAClC,KAAK,mBAAmB,YAAY,QACtC,KAAK,mBAAmB,YAAY,KAClC,KAAK,mBAAmB,YAAY,QAEtC,KAAK,OAAO,KACV,6EAAqC,KAAK,YAAY,IAAI,qBAC5D,CACF,OAASE,EAAO,CACd,WAAK,OAAO,MAAM,2DAAmCA,CAAK,EAC1D,MAAM,KAAK,QAAQ,EACbA,CACR,CACF,CAKA,MAAM,SAAyB,CAC7B,GAAI,CAAC,KAAK,cACR,MAAM,IAAI,MACR,8FACF,EAGF,GAAI,KAAK,aAAc,CACrB,KAAK,OAAO,KAAK,4FAAiB,EAClC,MACF,CAEA,KAAK,aAAe,GACpB,KAAK,mBAAmB,oBAAsB,KAAK,IAAI,EACvD,KAAK,OAAO,KAAK,uEAAgB,KAAK,YAAY,IAAI,EAAE,EAExD,GAAI,CACF,IAAMC,EAAsC,CAAC,EAG7C,OAAW,CAACF,EAAUG,CAAW,IAAK,KAAK,YACzCD,EAAmB,KACjB,KAAK,sBAAsBF,EAAUG,CAAW,CAClD,EAIF,IAAMC,EAAU,MAAM,QAAQ,WAAWF,CAAkB,EAGrDG,EAAeD,EAAQ,OAC1BE,GAAWA,EAAO,SAAW,WAChC,EAAE,OACIC,EAAeH,EAAQ,OAASC,EAGhCG,EACJ,KAAK,IAAI,EAAI,KAAK,mBAAmB,oBAYvC,GAXA,KAAK,mBAAmB,qBAAuBA,EAC/C,KAAK,mBAAmB,kBACxB,KAAK,mBAAmB,sBACtB,KAAK,mBAAmB,oBACxB,KAAK,mBAAmB,gBAE1B,KAAK,OAAO,KACV,4CAAcH,CAAY,mBAASE,CAAY,mBAASC,CAAc,IACxE,EAGIH,IAAiB,EACnB,MAAM,IAAI,MAAM,oEAAa,EAI/B,KAAK,iBAAiB,CACxB,QAAE,CACA,KAAK,aAAe,EACtB,CACF,CAKA,MAAM,YAA4B,CAChC,KAAK,OAAO,KAAK,kDAAU,EAG3B,KAAK,gBAAgB,EAGrB,KAAK,wBAAwB,EAG7B,IAAMI,EAAsC,CAAC,EAC7C,OAAW,CAACT,EAAUG,CAAW,IAAK,KAAK,YACzCM,EAAmB,KACjB,KAAK,yBAAyBT,EAAUG,CAAW,CACrD,EAGF,MAAM,QAAQ,WAAWM,CAAkB,EAC3C,KAAK,OAAO,KAAK,4CAAS,CAC5B,CAMA,MAAM,YAAYT,EAAiC,CACjD,GAAI,CAAC,KAAK,cACR,MAAM,IAAI,MAAM,mDAA+B,EAGjD,GAAI,KAAK,YAAY,IAAIA,CAAQ,EAAG,CAClC,KAAK,OAAO,KAAK,gBAAMA,CAAQ,mDAAW,EAC1C,MACF,CAEA,KAAK,OAAO,KAAK,yCAAWA,CAAQ,EAAE,EAEtC,GAAI,CAEF,IAAMD,EAAQ,KAAK,gBAAgB,EAMnC,GAHA,MAAM,KAAK,iBAAiBC,EAAUD,CAAK,EAGvC,KAAK,eAAe,EAAG,CACzB,IAAMI,EAAc,KAAK,YAAY,IAAIH,CAAQ,EACjD,MAAM,KAAK,sBAAsBA,EAAUG,CAAW,CACxD,CAEA,KAAK,OAAO,KAAK,gBAAMH,CAAQ,2BAAO,CACxC,OAASC,EAAO,CACd,WAAK,OAAO,MAAM,4BAAQD,CAAQ,iBAAQC,CAAK,EAE/C,KAAK,YAAY,OAAOD,CAAQ,EAChC,KAAK,iBAAiB,OAAOA,CAAQ,EAC/BC,CACR,CACF,CAMA,MAAM,eAAeD,EAAiC,CACpD,GAAI,CAAC,KAAK,YAAY,IAAIA,CAAQ,EAAG,CACnC,KAAK,OAAO,KAAK,gBAAMA,CAAQ,mDAAW,EAC1C,MACF,CAEA,KAAK,OAAO,KAAK,yCAAWA,CAAQ,EAAE,EAEtC,GAAI,CACF,IAAMG,EAAc,KAAK,YAAY,IAAIH,CAAQ,EAGjD,MAAM,KAAK,yBAAyBA,EAAUG,CAAW,EAGzD,KAAK,YAAY,OAAOH,CAAQ,EAChC,KAAK,iBAAiB,OAAOA,CAAQ,EAGrC,IAAMU,EAAQ,KAAK,gBAAgB,IAAIV,CAAQ,EAC3CU,IACF,aAAaA,CAAK,EAClB,KAAK,gBAAgB,OAAOV,CAAQ,GAGtC,KAAK,OAAO,KAAK,gBAAMA,CAAQ,2BAAO,CACxC,OAASC,EAAO,CACd,WAAK,OAAO,MAAM,4BAAQD,CAAQ,iBAAQC,CAAK,EACzCA,CACR,CACF,CAKA,uBAA0C,CACxC,IAAMU,EAAuC,CAAC,EAE9C,OAAW,CAACX,EAAUG,CAAW,IAAK,KAAK,YAAa,CACtD,IAAMS,EAAS,KAAK,iBAAiB,IAAIZ,CAAQ,EAC7CY,GAAQ,WAAaA,EAAO,YAAc,IAC5CD,EAAmB,KAAKR,CAAW,CAEvC,CAEA,OAAOQ,CACT,CAKA,qBAA0C,CACxC,OAAO,MAAM,KAAK,KAAK,iBAAiB,OAAO,CAAC,CAClD,CAKA,gBAA0B,CACxB,QAAWC,KAAU,KAAK,iBAAiB,OAAO,EAChD,GAAIA,EAAO,UACT,MAAO,GAGX,MAAO,EACT,CAMA,kBAAkBC,EAAmC,CACnD,KAAK,kBAAoBA,EACzB,KAAK,OAAO,KAAK,sCAAuB,EAGpC,KAAK,YAAY,KAAO,GAC1B,KAAK,0BAA0B,CAEnC,CAOA,sBAAsBb,EAAkBc,EAAwB,CAC9D,IAAMF,EAAS,KAAK,iBAAiB,IAAIZ,CAAQ,EAC7CY,GACFA,EAAO,mBAAqBE,EAC5B,KAAK,OAAO,KACV,gBAAMd,CAAQ,kCAASc,EAAU,eAAO,cAAI,EAC9C,GAEA,KAAK,OAAO,KAAK,gBAAMd,CAAQ,uFAAiB,CAEpD,CAKA,qBAWE,CACA,IAAMe,EAA6B,CAAC,EAEpC,OAAW,CAACf,EAAUY,CAAM,IAAK,KAAK,iBAAkB,CACtD,IAAMI,EACJJ,EAAO,cAAgB,EAClBA,EAAO,mBAAqBA,EAAO,cAAiB,IACrD,EAENG,EAAMf,CAAQ,EAAI,CAChB,SAAAA,EACA,YAAaY,EAAO,YACpB,YAAa,KAAK,MAAMI,EAAc,GAAG,EAAI,IAC7C,oBAAqBJ,EAAO,cAAgB,EAC5C,oBAAqBA,EAAO,oBAC5B,gBAAiBA,EAAO,gBACxB,gBAAiBA,EAAO,eAC1B,CACF,CAEA,OAAOG,CACT,CAKA,MAAM,oBAAoC,CACxC,KAAK,OAAO,KAAK,kDAAU,EAC3B,MAAM,KAAK,mBAAmB,CAChC,CAMA,MAAM,iBAAiBf,EAAiC,CACtD,IAAMY,EAAS,KAAK,iBAAiB,IAAIZ,CAAQ,EACjD,GAAI,CAACY,EACH,MAAM,IAAI,MAAM,gBAAMZ,CAAQ,qBAAM,EAGtC,GAAIY,EAAO,UAAW,CACpB,KAAK,OAAO,KAAK,gBAAMZ,CAAQ,mDAAW,EAC1C,MACF,CAEA,KAAK,OAAO,KAAK,yCAAWA,CAAQ,EAAE,EAGtC,IAAMiB,EAAgB,KAAK,gBAAgB,IAAIjB,CAAQ,EACnDiB,IACF,aAAaA,CAAa,EAC1B,KAAK,gBAAgB,OAAOjB,CAAQ,GAItC,MAAM,KAAK,iBAAiBA,CAAQ,CACtC,CAMA,cAAcA,EAAwB,CACpC,IAAMY,EAAS,KAAK,iBAAiB,IAAIZ,CAAQ,EACjD,GAAI,CAACY,EAAQ,CACX,KAAK,OAAO,KAAK,gBAAMZ,CAAQ,qBAAM,EACrC,MACF,CAEA,IAAMU,EAAQ,KAAK,gBAAgB,IAAIV,CAAQ,EAC3CU,IACF,aAAaA,CAAK,EAClB,KAAK,gBAAgB,OAAOV,CAAQ,EACpCY,EAAO,eAAiB,GACxBA,EAAO,kBAAoB,OAC3B,KAAK,OAAO,KAAK,kCAASZ,CAAQ,qBAAM,EAE5C,CAKA,mBAA0B,CACxB,KAAK,OAAO,KAAK,wDAAW,EAE5B,OAAW,CAACA,CAAQ,IAAK,KAAK,gBAC5B,KAAK,cAAcA,CAAQ,CAE/B,CAKA,mBAiBE,CACA,IAAMe,EAA6B,CAAC,EAEpC,OAAW,CAACf,EAAUY,CAAM,IAAK,KAAK,iBACpCG,EAAMf,CAAQ,EAAI,CAChB,SAAAA,EACA,kBAAmBY,EAAO,kBAC1B,eAAgBA,EAAO,eACvB,kBAAmBA,EAAO,kBAC1B,qBAAsBA,EAAO,qBAC7B,eAAgBA,EAAO,eACvB,UAAWA,EAAO,UAClB,uBAAwBA,EAAO,iBAAiB,MAAM,EAAE,CAC1D,EAGF,OAAOG,CACT,CAKQ,kBAAkBjB,EAGxB,CACA,IAAMoB,EAAkB,CAAC,EACnBC,EAAoB,CAAC,EAE3B,QAAWnB,KAAYF,EAAW,CAChC,GAAI,CAACE,GAAY,OAAOA,GAAa,SAAU,CAC7CmB,EAAQ,KAAKnB,CAAQ,EACrB,QACF,CAEA,GAAI,CAACA,EAAS,WAAW,OAAO,GAAK,CAACA,EAAS,WAAW,QAAQ,EAAG,CACnEmB,EAAQ,KAAKnB,CAAQ,EACrB,QACF,CAGA,GAAI,CACF,IAAI,IAAIA,CAAQ,EAChBkB,EAAM,KAAKlB,CAAQ,CACrB,MAAQ,CACNmB,EAAQ,KAAKnB,CAAQ,CACvB,CACF,CAEA,MAAO,CAAE,MAAAkB,EAAO,QAAAC,CAAQ,CAC1B,CAKQ,gBAAgBvB,EAGtB,CACA,IAAMwB,EAAmB,CAAC,EAwD1B,GAtDIxB,EAAQ,sBAAwB,SAEhC,OAAOA,EAAQ,qBAAwB,UACvCA,EAAQ,oBAAsB,MAE9BwB,EAAO,KAAK,wFAAsC,EAIlDxB,EAAQ,oBAAsB,SAE9B,OAAOA,EAAQ,mBAAsB,UACrCA,EAAQ,kBAAoB,MAE5BwB,EAAO,KAAK,qFAAmC,EAI/CxB,EAAQ,uBAAyB,SAEjC,OAAOA,EAAQ,sBAAyB,UACxCA,EAAQ,qBAAuB,IAE/BwB,EAAO,KAAK,sFAAoC,EAIhDxB,EAAQ,oBAAsB,SAE9B,OAAOA,EAAQ,mBAAsB,UACrCA,EAAQ,kBAAoB,MAE5BwB,EAAO,KAAK,sFAAoC,EAIhDxB,EAAQ,oBAAsB,SAE9B,OAAOA,EAAQ,mBAAsB,UACrCA,EAAQ,kBAAoB,MAE5BwB,EAAO,KAAK,sFAAoC,EAIhDxB,EAAQ,6BAA+B,SAEvC,OAAOA,EAAQ,4BAA+B,UAC9CA,EAAQ,2BAA6B,IAErCwB,EAAO,KAAK,4FAA0C,EAItDxB,EAAQ,sBAAwB,OAAW,CAC7C,IAAMyB,EAAkB,CAAC,cAAe,SAAU,cAAc,EAC3DA,EAAgB,SAASzB,EAAQ,mBAAmB,GACvDwB,EAAO,KACL,yEAAiCC,EAAgB,KAAK,IAAI,CAAC,EAC7D,CAEJ,CAEA,GAAIzB,EAAQ,oBAAsB,OAAW,CAC3C,IAAMyB,EAAkB,OAAO,OAAOjC,EAAiB,EAClDiC,EAAgB,SAASzB,EAAQ,iBAAiB,GACrDwB,EAAO,KACL,uEAA+BC,EAAgB,KAAK,IAAI,CAAC,EAC3D,CAEJ,CAEA,MAAO,CAAE,MAAOD,EAAO,SAAW,EAAG,OAAAA,CAAO,CAC9C,CAOA,MAAM,gBACJE,EACAvB,EAAgB,CAAC,EACF,CACf,GAAI,CAAC,KAAK,cACR,MAAM,IAAI,MAAM,mDAA+B,EAGjD,KAAK,OAAO,KAAK,6EAAiBuB,EAAa,MAAM,EAAE,EAGvD,GAAM,CAAE,MAAOC,EAAgB,QAASC,CAAiB,EACvD,KAAK,kBAAkBF,CAAY,EAMrC,GAJIE,EAAiB,OAAS,GAC5B,KAAK,OAAO,KAAK,yCAAWA,EAAiB,KAAK,IAAI,CAAC,EAAE,EAGvDD,EAAe,SAAW,EAC5B,MAAM,IAAI,MAAM,4CAAS,EAI3B,IAAME,EAAmB,MAAM,KAAK,KAAK,YAAY,KAAK,CAAC,EACrDC,EAAQH,EAAe,OAAQI,GAAO,CAACF,EAAiB,SAASE,CAAE,CAAC,EACpEC,EAAWH,EAAiB,OAC/BE,GAAO,CAACJ,EAAe,SAASI,CAAE,CACrC,EACME,EAASJ,EAAiB,OAAQE,GAAOJ,EAAe,SAASI,CAAE,CAAC,EAE1E,KAAK,OAAO,KACV,4CAAcD,EAAM,MAAM,mBAASE,EAAS,MAAM,mBAASC,EAAO,MAAM,EAC1E,EAEA,GAAI,CAEF,QAAW7B,KAAY4B,EACrB,MAAM,KAAK,eAAe5B,CAAQ,EAIpC,QAAWA,KAAY0B,EACrB,MAAM,KAAK,YAAY1B,CAAQ,EAIjC,IAAM8B,EAAiC,CACrC,KACEJ,EAAM,OAAS,GAAKE,EAAS,OAAS,EAClC,oBACAF,EAAM,OAAS,EACb,kBACA,oBACR,KAAM,CACJ,MAAOA,EAAM,OAAS,EAAIA,EAAQ,OAClC,QAASE,EAAS,OAAS,EAAIA,EAAW,OAC1C,QACEF,EAAM,OAAS,GAAKE,EAAS,OAAS,EAClCL,EACA,MACR,EACA,UAAW,IAAI,IACjB,EAEA,KAAK,KAAK,eAAgBO,CAAW,EACrC,KAAK,OAAO,KAAK,kDAAU,CAC7B,OAAS7B,EAAO,CACd,WAAK,OAAO,MAAM,oDAAaA,CAAK,EAC9BA,CACR,CACF,CAMA,cAAc8B,EAAqD,CACjE,KAAK,OAAO,KAAK,sCAAQ,EAGzB,GAAM,CAAE,MAAAb,EAAO,OAAAE,CAAO,EAAI,KAAK,gBAAgBW,CAAU,EAEzD,GAAI,CAACb,EACH,MAAM,IAAI,MAAM,+CAAYE,EAAO,KAAK,IAAI,CAAC,EAAE,EAGjD,IAAMY,EAAa,CAAE,GAAG,KAAK,OAAQ,EAGrC,KAAK,QAAU,CAAE,GAAG,KAAK,QAAS,GAAGD,CAAW,EAGhD,IAAMD,EAAiC,CACrC,KAAM,kBACN,KAAM,CACJ,WAAAE,EACA,WAAAD,CACF,EACA,UAAW,IAAI,IACjB,EAEA,KAAK,KAAK,eAAgBD,CAAW,EACrC,KAAK,OAAO,KAAK,kDAAU,EAC3B,KAAK,OAAO,MAAM,wCAAW,KAAK,OAAO,CAC3C,CAKA,kBAGE,CACA,MAAO,CACL,UAAW,MAAM,KAAK,KAAK,YAAY,KAAK,CAAC,EAC7C,QAAS,CAAE,GAAG,KAAK,OAAQ,CAC7B,CACF,CAMA,MAAM,aAAaG,EAID,CAChB,KAAK,OAAO,KAAK,4CAAS,EAE1B,GAAI,CAEEA,EAAO,SACT,KAAK,cAAcA,EAAO,OAAO,EAI/BA,EAAO,WACT,MAAM,KAAK,gBAAgBA,EAAO,UAAWA,EAAO,OAAS,CAAC,CAAC,EAGjE,KAAK,OAAO,KAAK,4CAAS,CAC5B,OAAShC,EAAO,CACd,WAAK,OAAO,MAAM,8CAAYA,CAAK,EAC7BA,CACR,CACF,CAMA,qBAAqBiC,EAA6B,CAAC,EAA0B,CAC3E,IAAMvB,EAAqB,KAAK,sBAAsB,EAEtD,GAAIA,EAAmB,SAAW,EAChC,YAAK,OAAO,KAAK,wDAAW,EACrB,KAIT,IAAMwB,EAAuBxB,EAAmB,OAAQyB,GAAe,CACrE,IAAMpC,EAAW,KAAK,wBAAwBoC,CAAU,EACxD,OAAOpC,GAAY,CAACkC,EAAiB,SAASlC,CAAQ,CACxD,CAAC,EAED,GAAImC,EAAqB,SAAW,EAClC,YAAK,OAAO,KAAK,kGAAkB,EAC5B,KAGT,IAAIE,EAEJ,OAAQ,KAAK,QAAQ,oBAAqB,CACxC,IAAK,cACHA,EAAqB,KAAK,iBAAiBF,CAAoB,EAC/D,MAEF,IAAK,SACHE,EAAqB,KAAK,aAAaF,CAAoB,EAC3D,MAEF,IAAK,eACHE,EAAqB,KAAK,kBAAkBF,CAAoB,EAChE,MAEF,QACEE,EAAqB,KAAK,iBAAiBF,CAAoB,CACnE,CAGA,YAAK,qBACH,KAAK,wBAAwBE,CAAkB,EAE1CA,CACT,CAKQ,iBAAiBC,EAA+C,CACtE,GAAIA,EAAY,SAAW,EACzB,MAAM,IAAI,MAAM,4CAAS,EAG3B,IAAMF,EAAaE,EAAY,KAAK,gBAAkBA,EAAY,MAAM,EACxE,YAAK,iBAAmB,KAAK,gBAAkB,GAAKA,EAAY,OAEzDF,CACT,CAKQ,aAAaE,EAA+C,CAClE,GAAIA,EAAY,SAAW,EACzB,MAAM,IAAI,MAAM,4CAAS,EAG3B,IAAMC,EAAc,KAAK,MAAM,KAAK,OAAO,EAAID,EAAY,MAAM,EACjE,OAAOA,EAAYC,CAAW,CAChC,CAKQ,kBAAkBD,EAA+C,CACvE,GAAIA,EAAY,SAAW,EACzB,MAAM,IAAI,MAAM,4CAAS,EAI3B,IAAME,EAAoBF,EAAY,IAAKF,GAAe,CACxD,IAAMpC,EAAW,KAAK,wBAAwBoC,CAAU,EAClDxB,EAASZ,EAAW,KAAK,iBAAiB,IAAIA,CAAQ,EAAI,KAChE,MAAO,CACL,WAAAoC,EACA,SAAApC,EACA,YAAaY,GAAQ,aAAe,EACpC,aAAcA,GAAQ,cAAgB,OAAO,kBAC7C,YACEA,GAAUA,EAAO,cAAgB,EAC5BA,EAAO,mBAAqBA,EAAO,cAAiB,IACrD,CACR,CACF,CAAC,EAGD4B,EAAkB,KAAK,CAACC,EAAGC,IAErBD,EAAE,cAAgBC,EAAE,YACfA,EAAE,YAAcD,EAAE,YAIvBA,EAAE,cAAgBC,EAAE,YACfA,EAAE,YAAcD,EAAE,YAIpBA,EAAE,aAAeC,EAAE,YAC3B,EAGD,IAAMC,EAAcH,EAAkB,OACpC,CAACI,EAAKC,IAASD,GAAOC,EAAK,YAAc,GACzC,CACF,EACIC,EAAe,KAAK,OAAO,EAAIH,EAEnC,QAAWE,KAAQL,EAEjB,GADAM,GAAgBD,EAAK,YAAc,EAC/BC,GAAgB,EAClB,OAAOD,EAAK,WAKhB,OAAOL,EAAkB,CAAC,EAAE,UAC9B,CAKQ,wBAAwBJ,EAA2C,CACzE,OAAW,CAACpC,EAAU+C,CAAI,IAAK,KAAK,YAClC,GAAIA,IAASX,EACX,OAAOpC,EAGX,OAAO,IACT,CAKA,qBAeE,CACA,IAAMW,EAAqB,KAAK,sBAAsB,EAChDqC,EAAyC,CAAC,EAEhD,OAAW,CAAChD,EAAUY,CAAM,IAAK,KAAK,iBAAkB,CACtD,IAAMI,EACJJ,EAAO,cAAgB,EAClBA,EAAO,mBAAqBA,EAAO,cAAiB,IACrD,EAGAqC,EAASrC,EAAO,YAAc,EAEpCoC,EAAkBhD,CAAQ,EAAI,CAC5B,YAAaY,EAAO,YACpB,aAAcA,EAAO,cAAgB,EACrC,YAAa,KAAK,MAAMI,EAAc,GAAG,EAAI,IAC7C,OAAAiC,CACF,CACF,CAEA,MAAO,CACL,SAAU,KAAK,QAAQ,oBACvB,iBAAkB,KAAK,YAAY,KACnC,mBAAoBtC,EAAmB,OACvC,qBAAsB,KAAK,qBAC3B,gBAAiB,KAAK,gBACtB,kBAAAqC,CACF,CACF,CAMA,uBACEE,EACM,CACN,IAAMC,EAAc,KAAK,QAAQ,oBACjC,KAAK,QAAQ,oBAAsBD,EAG/BA,IAAa,gBACf,KAAK,gBAAkB,GAGzB,KAAK,OAAO,KAAK,oDAAYC,CAAW,uBAAQD,CAAQ,EAAE,EAG1D,IAAMpB,EAAiC,CACrC,KAAM,kBACN,KAAM,CACJ,WAAY,CAAE,oBAAqBqB,CAAY,EAC/C,WAAY,CAAE,oBAAqBD,CAAS,CAC9C,EACA,UAAW,IAAI,IACjB,EAEA,KAAK,KAAK,eAAgBpB,CAAW,CACvC,CAMA,MAAM,gBACJsB,EACgC,CAChC,KAAK,OAAO,KAAK,uEAAgBA,CAAc,EAAE,EAGjD,IAAMC,EAAmB,KAAK,qBAAqB,CAACD,CAAc,CAAC,EAEnE,GAAI,CAACC,EACH,YAAK,OAAO,MAAM,kGAAkB,EAC7B,KAGT,IAAMC,EAAiB,KAAK,wBAAwBD,CAAgB,EACpE,YAAK,OAAO,KAAK,6EAAiBC,CAAc,EAAE,EAE3CD,CACT,CAMA,MAAM,mBAAmBvD,EAAsB,CAAC,EAAkB,CAChE,IAAMyD,EACJzD,EAAU,OAAS,EAAIA,EAAY,MAAM,KAAK,KAAK,YAAY,KAAK,CAAC,EAEvE,KAAK,OAAO,KAAK,uEAAgByD,EAAgB,MAAM,EAAE,EAEzD,IAAMC,EAAkBD,EAAgB,IAAI,MAAOvD,GAAa,CAC9D,GAAI,KAAK,mBAAmB,qBAAqB,IAAIA,CAAQ,EAAG,CAC9D,KAAK,OAAO,MAAM,gBAAMA,CAAQ,uCAAS,EACzC,MACF,CAEA,GAAI,CACiB,KAAK,YAAY,IAAIA,CAAQ,IAG9C,MAAM,KAAK,mBAAmB,EAC9B,KAAK,mBAAmB,qBAAqB,IAAIA,CAAQ,EACzD,KAAK,OAAO,MAAM,gBAAMA,CAAQ,2BAAO,EAE3C,OAASC,EAAO,CACd,KAAK,OAAO,KAAK,gBAAMD,CAAQ,6BAAUC,CAAK,CAChD,CACF,CAAC,EAED,MAAM,QAAQ,IAAIuD,CAAe,EACjC,KAAK,OAAO,KACV,sEAAe,KAAK,mBAAmB,qBAAqB,IAAI,qBAClE,CACF,CAKQ,0BAAiC,CACvC,IAAMC,EAAgB,QAAQ,YAAY,EAAE,SAC5C,KAAK,mBAAmB,YAAY,QAAUA,EAE1CA,EAAgB,KAAK,mBAAmB,YAAY,OACtD,KAAK,mBAAmB,YAAY,KAAOA,EAE/C,CAKA,uBAgBE,CACA,KAAK,yBAAyB,EAE9B,IAAMC,EACJ,KAAK,mBAAmB,YAAY,QACpC,KAAK,mBAAmB,YAAY,QAChCC,EACJ,KAAK,mBAAmB,YAAY,QAAU,EACzCD,EAAe,KAAK,mBAAmB,YAAY,QAAW,IAC/D,EAEN,MAAO,CACL,eAAgB,CACd,MAAO,KAAK,mBAAmB,oBAC/B,QAAS,KAAK,mBAAmB,sBACjC,MAAO,KAAK,mBAAmB,eACjC,EACA,YAAa,CACX,QAAS,KAAK,mBAAmB,YAAY,QAC7C,QAAS,KAAK,mBAAmB,YAAY,QAC7C,KAAM,KAAK,mBAAmB,YAAY,KAC1C,OAAQA,EACR,iBAAkB,KAAK,MAAMC,EAAmB,GAAG,EAAI,GACzD,EACA,qBAAsB,KAAK,mBAAmB,qBAAqB,KACnE,iBAAkB,KAAK,YAAY,KACnC,mBAAoB,KAAK,sBAAsB,EAAE,MACnD,CACF,CAKA,qBAA4B,CAC1B,KAAK,OAAO,KAAK,sCAAQ,EAGzB,OAAW,CAAC,CAAE/C,CAAM,IAAK,KAAK,iBAQ5B,GAPIA,EAAO,kBAAoBA,EAAO,iBAAiB,OAAS,KAE9DA,EAAO,iBAAmBA,EAAO,iBAAiB,MAAM,GAAG,GAKzDA,EAAO,cAAgB,IAAO,CAEhC,IAAMI,EAAcJ,EAAO,mBAAqBA,EAAO,cACvDA,EAAO,cAAgB,IACvBA,EAAO,mBAAqB,KAAK,MAAMI,EAAc,GAAI,CAC3D,CAIE,OAAO,IACT,OAAO,GAAG,EAGZ,KAAK,yBAAyB,EAC9B,KAAK,OAAO,KAAK,sCAAQ,CAC3B,CAKA,MAAM,SAAyB,CAC7B,KAAK,OAAO,KAAK,gEAAkC,EAEnD,GAAI,CAEF,MAAM,KAAK,WAAW,EAGtB,KAAK,YAAY,MAAM,EACvB,KAAK,iBAAiB,MAAM,EAG5B,KAAK,cAAgB,GACrB,KAAK,aAAe,GACpB,KAAK,gBAAkB,EACvB,KAAK,qBAAuB,KAE5B,KAAK,OAAO,KAAK,+DAAiC,CACpD,OAASf,EAAO,CACd,WAAK,OAAO,MAAM,iEAAoCA,CAAK,EACrDA,CACR,CACF,CAOQ,yBAAyBH,EAAqBC,EAAqB,CACzE,GAAI,CAAC,MAAM,QAAQD,CAAS,GAAKA,EAAU,SAAW,EACpD,MAAM,IAAI,MAAM,kDAAU,EAG5B,GAAI,CAAC,MAAM,QAAQC,CAAK,EACtB,MAAM,IAAI,MAAM,wDAAW,EAI7B,QAAWC,KAAYF,EAAW,CAChC,GAAI,CAACE,GAAY,OAAOA,GAAa,SACnC,MAAM,IAAI,MAAM,+CAAYA,CAAQ,EAAE,EAGxC,GAAI,CAACA,EAAS,WAAW,OAAO,GAAK,CAACA,EAAS,WAAW,QAAQ,EAChE,MAAM,IAAI,MAAM,6DAA0BA,CAAQ,EAAE,CAExD,CACF,CAKA,MAAc,iBACZA,EACAD,EACe,CACf,KAAK,OAAO,MAAM,yCAAWC,CAAQ,EAAE,EAEvC,GAAI,CAEF,IAAMG,EAAc,IAAIyD,EAAe5D,CAAQ,EAG3C,KAAK,mBACPG,EAAY,kBAAkB,KAAK,iBAAiB,EAItD,KAAK,YAAY,IAAIH,EAAUG,CAAW,EAG1C,KAAK,iBAAiB,IAAIH,EAAU,CAClC,SAAAA,EACA,UAAW,GACX,YAAa,GACb,kBAAmB,EACnB,YAAa,IACb,oBAAqB,EACrB,cAAe,EACf,mBAAoB,EACpB,mBAAoB,GACpB,eAAgB,GAChB,eAAgB,KAAK,QAAQ,kBAC7B,iBAAkB,CAAC,CACrB,CAAC,EAED,KAAK,OAAO,MAAM,qDAAaA,CAAQ,EAAE,CAC3C,OAASC,EAAO,CACd,WAAK,OAAO,MAAM,oDAAYD,CAAQ,IAAKC,CAAK,EAC1CA,CACR,CACF,CAKA,MAAc,sBACZD,EACAG,EACe,CACf,IAAMS,EAAS,KAAK,iBAAiB,IAAIZ,CAAQ,EACjD,GAAI,CAACY,EACH,MAAM,IAAI,MAAM,+CAAYZ,CAAQ,EAAE,EAGxC,KAAK,OAAO,MAAM,6BAASA,CAAQ,EAAE,EAErC,GAAI,CAEFY,EAAO,UAAY,GACnBA,EAAO,YAAc,GAGrB,MAAMT,EAAY,QAAQ,EAG1BS,EAAO,UAAY,GACnBA,EAAO,YAAc,GACrBA,EAAO,cAAgB,IAAI,KAC3BA,EAAO,UAAY,OACnBA,EAAO,kBAAoB,EAC3BA,EAAO,YAAc,IAErB,KAAK,OAAO,KAAK,yCAAWZ,CAAQ,EAAE,CACxC,OAASC,EAAO,CAEd,MAAAW,EAAO,UAAY,GACnBA,EAAO,YAAc,GACrBA,EAAO,UAAYX,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,EACxEW,EAAO,oBACPA,EAAO,YAAc,KAAK,IAAI,EAAGA,EAAO,YAAc,EAAE,EAExD,KAAK,OAAO,MAAM,wCAAUZ,CAAQ,IAAKC,CAAK,EAG9C,KAAK,kBAAkBD,CAAQ,EAEzBC,CACR,CACF,CAKA,MAAc,yBACZD,EACAG,EACe,CACf,IAAMS,EAAS,KAAK,iBAAiB,IAAIZ,CAAQ,EACjD,GAAKY,EAIL,MAAK,OAAO,MAAM,6BAASZ,CAAQ,EAAE,EAErC,GAAI,CAEFG,EAAY,WAAW,EAGvBS,EAAO,UAAY,GACnBA,EAAO,YAAc,GAErB,KAAK,OAAO,MAAM,yCAAWZ,CAAQ,EAAE,CACzC,OAASC,EAAO,CACd,KAAK,OAAO,MAAM,wCAAUD,CAAQ,IAAKC,CAAK,EAE9CW,EAAO,UAAY,GACnBA,EAAO,YAAc,EACvB,EACF,CAKQ,iBAA0B,CAChC,GAAI,CAAC,KAAK,kBACR,MAAO,CAAC,EAGV,GAAI,CACF,OAAO,KAAK,kBAAkB,YAAY,CAC5C,OAASX,EAAO,CACd,YAAK,OAAO,MAAM,oDAAaA,CAAK,EAC7B,CAAC,CACV,CACF,CAKQ,2BAAkC,CACxC,GAAK,KAAK,kBAIV,MAAK,OAAO,MAAM,wDAAW,EAE7B,OAAW,CAACD,EAAUG,CAAW,IAAK,KAAK,YACzC,GAAI,CACFA,EAAY,kBAAkB,KAAK,iBAAiB,EACpD,KAAK,OAAO,MAAM,yCAAWH,CAAQ,EAAE,CACzC,OAASC,EAAO,CACd,KAAK,OAAO,MAAM,wCAAUD,CAAQ,IAAKC,CAAK,CAChD,EAEJ,CAKQ,kBAAyB,CAC3B,KAAK,sBAIT,KAAK,OAAO,MACV,2DAAc,KAAK,QAAQ,mBAAmB,IAChD,EAEA,KAAK,oBAAsB,YAAY,IAAM,CAC3C,KAAK,mBAAmB,CAC1B,EAAG,KAAK,QAAQ,mBAAmB,EACrC,CAKQ,iBAAwB,CAC1B,KAAK,sBACP,cAAc,KAAK,mBAAmB,EACtC,KAAK,oBAAsB,KAC3B,KAAK,OAAO,MAAM,4CAAS,EAE/B,CAKA,MAAc,oBAAoC,CAChD,KAAK,OAAO,MAAM,sCAAQ,EAE1B,IAAM4D,EAAuC,CAAC,EAE9C,OAAW,CAAC7D,EAAUY,CAAM,IAAK,KAAK,iBAC/BA,EAAO,oBAIZiD,EAAoB,KAAK,KAAK,yBAAyB7D,EAAUY,CAAM,CAAC,EAI1E,MAAM,QAAQ,WAAWiD,CAAmB,CAC9C,CAKA,MAAc,yBACZ7D,EACAY,EACe,CACf,IAAMkD,EAAY,KAAK,IAAI,EAC3BlD,EAAO,gBAAkB,IAAI,KAC7BA,EAAO,gBAEP,GAAI,CACF,IAAMT,EAAc,KAAK,YAAY,IAAIH,CAAQ,EACjD,GAAI,CAACG,EACH,MAAM,IAAI,MAAM,+CAAYH,CAAQ,EAAE,EAKxC,MAAM,KAAK,sBAAsBG,EAAaH,CAAQ,EAGtD,IAAM+D,EAAe,KAAK,IAAI,EAAID,EAClC,KAAK,yBAAyBlD,EAAQmD,CAAY,CACpD,OAAS9D,EAAO,CAEd,IAAM8D,EAAe,KAAK,IAAI,EAAID,EAClC,KAAK,yBAAyBlD,EAAQX,EAAgB8D,CAAY,CACpE,CACF,CAKA,MAAc,sBACZ5D,EACAH,EACe,CAEf,GAAI,CAACG,EACH,MAAM,IAAI,MAAM,4CAAS,EAW3B,GAJA,MAAM,IAAI,QAAS6D,GAAY,WAAWA,EAAS,EAAE,CAAC,EAIlD,CADW,KAAK,iBAAiB,IAAIhE,CAAQ,GACpC,UACX,MAAM,IAAI,MAAM,gCAAO,CAE3B,CAKQ,yBACNY,EACAmD,EACM,CACNnD,EAAO,qBACPA,EAAO,oBAAsB,EAC7BA,EAAO,aAAemD,EACtBnD,EAAO,gBAAkB,IAAI,KAG7B,KAAK,kBAAkBA,EAAQ,GAAMmD,CAAY,EAEjD,KAAK,OAAO,MACV,yCAAWnD,EAAO,QAAQ,+BAAWmD,CAAY,2BAAYnD,EAAO,WAAW,EACjF,CACF,CAKQ,yBACNA,EACAX,EACA8D,EACM,CACNnD,EAAO,sBACPA,EAAO,aAAemD,EACtBnD,EAAO,UAAYX,EAAM,QAGzB,KAAK,kBAAkBW,EAAQ,GAAOmD,CAAY,EAElD,KAAK,OAAO,KACV,yCAAWnD,EAAO,QAAQ,mBAASX,EAAM,OAAO,+BAAWW,EAAO,mBAAmB,yBAAUA,EAAO,WAAW,EACnH,EAGIA,EAAO,qBAAuB,GAAKA,EAAO,WAC5C,KAAK,OAAO,KACV,gBAAMA,EAAO,QAAQ,6BAASA,EAAO,mBAAmB,mDAC1D,CAGJ,CAKQ,kBACNA,EACAqD,EACAF,EACM,CACN,IAAMG,EAAYtD,EAAO,YAEzB,GAAIqD,EAAS,CAEX,IAAIE,EAAY,EAGZJ,EAAe,IACjBI,EAAY,GACHJ,EAAe,IACxBI,EAAY,EACHJ,EAAe,IACxBI,EAAY,EAEZA,EAAY,EAGdvD,EAAO,YAAc,KAAK,IAAI,IAAKsD,EAAYC,CAAS,CAC1D,KAAO,CAEL,IAAIC,EAAY,GAGZxD,EAAO,qBAAuB,EAChCwD,EAAY,GACHxD,EAAO,qBAAuB,IACvCwD,EAAY,IAGdxD,EAAO,YAAc,KAAK,IAAI,EAAGsD,EAAYE,CAAS,CACxD,CAGA,GAAIxD,EAAO,cAAgB,EAAG,CAC5B,IAAMI,EAAcJ,EAAO,mBAAqBA,EAAO,cAGnDI,EAAc,GAChBJ,EAAO,YAAc,KAAK,IAAI,EAAGA,EAAO,YAAc,EAAE,EAGjDI,EAAc,KACrBJ,EAAO,YAAc,KAAK,IAAI,IAAKA,EAAO,YAAc,CAAC,EAE7D,CACF,CAKQ,wBAAwBX,EAAmC,CACjE,IAAMoE,EAAepE,EAAM,QAAQ,YAAY,EAE/C,OACEoE,EAAa,SAAS,SAAS,GAC/BA,EAAa,SAAS,WAAW,EAE1B,gBAIPA,EAAa,SAAS,SAAS,GAC/BA,EAAa,SAAS,oBAAoB,GAC1CA,EAAa,SAAS,cAAc,GACpCA,EAAa,SAAS,WAAW,EAE1B,gBAIPA,EAAa,SAAS,MAAM,GAC5BA,EAAa,SAAS,cAAc,GACpCA,EAAa,SAAS,WAAW,GACjCA,EAAa,SAAS,KAAK,GAC3BA,EAAa,SAAS,KAAK,EAEpB,uBAIPA,EAAa,SAAS,QAAQ,GAC9BA,EAAa,SAAS,KAAK,GAC3BA,EAAa,SAAS,KAAK,GAC3BA,EAAa,SAAS,KAAK,GAC3BA,EAAa,SAAS,KAAK,EAEpB,eAGF,eACT,CAKQ,wBAAwBzD,EAAkC,CAChE,IAAM0D,EAAY,KAAK,QAAQ,kBACzBC,EAAW,KAAK,QAAQ,kBACxBC,EAAa,KAAK,QAAQ,2BAC1BC,EAAW7D,EAAO,kBAEpB8D,EAEJ,OAAQ,KAAK,QAAQ,kBAAmB,CACtC,IAAK,iBACHA,EAAQJ,EACR,MAEF,IAAK,iBACHI,EAAQJ,GAAaG,EAAW,GAChC,MAEF,IAAK,sBACHC,EAAQJ,EAAYE,GAAcC,EAClC,MAEF,IAAK,WAEHC,EAAQ,KAAK,uBACX9D,EACA0D,EACAE,EACAC,CACF,EACA,MAEF,QACEC,EAAQJ,EAAYE,GAAcC,CACtC,CAMA,GAHAC,EAAQ,KAAK,IAAIA,EAAOH,CAAQ,EAG5B,KAAK,QAAQ,cAAe,CAC9B,IAAMI,EAASD,EAAQ,GAAM,KAAK,OAAO,EACzCA,GAASC,CACX,CAEA,OAAO,KAAK,MAAMD,CAAK,CACzB,CAKQ,uBACN9D,EACA0D,EACAE,EACAC,EACQ,CACR,IAAIC,EAAQJ,EAGZ,OAAQ1D,EAAO,UAAW,CACxB,IAAK,gBAEH8D,EAAQJ,EAAYE,GAAcC,EAClC,MAEF,IAAK,uBAEHC,EAAQJ,EAAYE,GAAcC,EAAW,EAC7C,MAEF,IAAK,eAEHC,EAAQJ,GAAa,EAAIG,GACzB,MAEF,IAAK,gBAEHC,EAAQJ,GAAa,EAAIG,EAAW,IACpC,MAEF,QACEC,EAAQJ,EAAYE,GAAcC,CACtC,CAGA,GAAI7D,EAAO,iBAAiB,OAAS,EAAG,CACtC,IAAMgE,EAAgBhE,EAAO,iBAAiB,MAAM,EAAE,EAChDI,EACJ4D,EAAc,OAAQC,GAAMA,EAAE,OAAO,EAAE,OAASD,EAAc,OAE5D5D,EAAc,GAEhB0D,GAAS,IACA1D,EAAc,KAEvB0D,GAAS,GAEb,CAEA,OAAOA,CACT,CAKQ,gBAAgB9D,EAAmC,CAEzD,OAAIA,EAAO,mBAAqB,KAAK,QAAQ,sBAC3C,KAAK,OAAO,KACV,gBAAMA,EAAO,QAAQ,2DAAc,KAAK,QAAQ,oBAAoB,EACtE,EACO,IAILA,EAAO,YAAc,wBAEnBA,EAAO,mBAAqB,GAC9B,KAAK,OAAO,KAAK,gBAAMA,EAAO,QAAQ,yDAAY,EAC3C,IAKPA,EAAO,qBAAuB,IAChC,KAAK,OAAO,KAAK,gBAAMA,EAAO,QAAQ,iFAAgB,EAC/C,IAGF,EACT,CAKQ,kBAAkBZ,EAAwB,CAChD,IAAMY,EAAS,KAAK,iBAAiB,IAAIZ,CAAQ,EACjD,GAAI,CAACY,EACH,OAWF,GAPIA,EAAO,YACTA,EAAO,UAAY,KAAK,wBACtB,IAAI,MAAMA,EAAO,SAAS,CAC5B,GAIE,CAAC,KAAK,gBAAgBA,CAAM,EAAG,CACjCA,EAAO,eAAiB,GACxB,MACF,CAGA,IAAMK,EAAgB,KAAK,gBAAgB,IAAIjB,CAAQ,EACnDiB,GACF,aAAaA,CAAa,EAI5B,IAAMyD,EAAQ,KAAK,wBAAwB9D,CAAM,EACjDA,EAAO,eAAiB8D,EACxB9D,EAAO,eAAiB,GACxBA,EAAO,kBAAoB,IAAI,KAAK,KAAK,IAAI,EAAI8D,CAAK,EAEtD,KAAK,OAAO,KACV,4BAAQ1E,CAAQ,uBAAQ0E,CAAK,qCAAY9D,EAAO,kBAAoB,CAAC,mCAAUA,EAAO,SAAS,EACjG,EAEA,IAAMF,EAAQ,WAAW,SAAY,CACnC,KAAK,gBAAgB,OAAOV,CAAQ,EACpC,MAAM,KAAK,iBAAiBA,CAAQ,CACtC,EAAG0E,CAAK,EAER,KAAK,gBAAgB,IAAI1E,EAAUU,CAAK,CAC1C,CAKA,MAAc,iBAAiBV,EAAiC,CAC9D,IAAMY,EAAS,KAAK,iBAAiB,IAAIZ,CAAQ,EAC3CG,EAAc,KAAK,YAAY,IAAIH,CAAQ,EAEjD,GAAI,GAACY,GAAU,CAACT,GAIhB,CAAAS,EAAO,qBAAuB,IAAI,KAClCA,EAAO,eAAiB,GAExB,KAAK,OAAO,KACV,4BAAQZ,CAAQ,gBAAMY,EAAO,kBAAoB,CAAC,qBACpD,EAEA,GAAI,CACF,MAAM,KAAK,sBAAsBZ,EAAUG,CAAW,EAGtDS,EAAO,eAAiB,GACxBA,EAAO,iBAAiB,KAAK,CAC3B,UAAW,IAAI,KACf,QAAS,GACT,MAAOA,EAAO,cAChB,CAAC,EAED,KAAK,OAAO,KAAK,4BAAQZ,CAAQ,EAAE,CACrC,OAASC,EAAO,CAEdW,EAAO,eAAiB,GACxBA,EAAO,iBAAiB,KAAK,CAC3B,UAAW,IAAI,KACf,QAAS,GACT,MAAOX,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,EAC5D,MAAOW,EAAO,cAChB,CAAC,EAED,KAAK,OAAO,MAAM,4BAAQZ,CAAQ,IAAKC,CAAK,EAG5C,KAAK,kBAAkBD,CAAQ,CACjC,CAGIY,EAAO,iBAAiB,OAAS,KACnCA,EAAO,iBAAmBA,EAAO,iBAAiB,MAAM,GAAG,GAE/D,CAKQ,yBAAgC,CACtC,OAAW,CAAC,CAAEF,CAAK,IAAK,KAAK,gBAC3B,aAAaA,CAAK,EAEpB,KAAK,gBAAgB,MAAM,CAC7B,CACF,IC/1DA,eAAeoE,GACbC,EACmC,CACnC,eAAQ,IAAI,mFAAyC,EAErC,IAAIC,GAAyBD,CAAO,CAGtD,CASA,eAAeE,GACbF,EACmC,CAEnC,GAAIG,GAAYC,IAAU,cACxB,OAAOD,EAIT,GAAIE,GAAeD,IAAU,eAC3B,OAAOC,EAILD,IAAU,UACZE,GAAM,EAIRF,EAAQ,eACRC,EAAcN,GAAeC,CAAO,EAEpC,GAAI,CACF,OAAAG,EAAW,MAAME,EACjBD,EAAQ,cACRG,GAAa,8BAA8B,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,EAAG,EAAE,CAAC,GACpGC,GAAY,KAEZ,QAAQ,IACN,mGAA4CD,EAAU,EACxD,EACOJ,CACT,OAASM,EAAO,CACd,MAAAL,EAAQ,SACRI,GAAYC,EACZJ,EAAc,KAEd,QAAQ,MACN,8EACCI,EAAgB,OACnB,EACMA,CACR,CACF,CAOA,eAAeC,IAAyB,CACtC,GAAIN,IAAU,UAAwB,CACpC,QAAQ,IAAI,6HAA6C,EACzD,MACF,CAEA,QAAQ,IAAI,yFAA0C,EACtDA,EAAQ,UAER,GAAI,CAEF,GAAIC,EAAa,CACf,GAAI,CAEF,MAD4B,MAAMA,GACR,QAAQ,CACpC,OAASI,EAAO,CACd,QAAQ,MAAM,sEAAiBA,EAAgB,OAAO,CACxD,CACAJ,EAAc,IAChB,CAGIF,IACF,MAAMA,EAAS,QAAQ,EACvBA,EAAW,MAGbC,EAAQ,kBACRI,GAAY,KACZD,GAAa,KAEb,QAAQ,IAAI,kFAAqC,CACnD,OAASE,EAAO,CACd,cAAQ,MACN,wEACCA,EAAgB,OACnB,EAEAH,GAAM,EACAG,CACR,CACF,CAQA,SAASH,IAAc,CACrB,QAAQ,IAAI,6EAAwC,EAGhDD,IACFA,EAAc,MAIhBF,EAAW,KACXC,EAAQ,kBACRI,GAAY,KACZD,GAAa,KAEb,QAAQ,IAAI,4EAAoC,CAClD,CAOA,SAASI,IAAyB,CAChC,OAAOP,IAAU,eAA8BD,IAAa,IAC9D,CAOA,SAASS,IAA6B,CACpC,MAAO,CACL,MAAAR,EACA,mBAAoBG,GAAa,IAAI,KAAS,OAC9C,UAAWC,IAAa,OACxB,WAAYD,IAAc,MAC5B,CACF,CAUA,eAAeM,GACbb,EACmC,CACnC,eAAQ,IAAI,+FAA2C,EAEvD,MAAMU,GAAQ,EACPR,GAAYF,CAAO,CAC5B,CAOA,SAASc,IAAsD,CAC7D,OAAOX,CACT,CAOA,eAAeY,IAA0C,CACvD,GAAIX,IAAU,cACZ,MAAO,GAGT,GAAIA,IAAU,gBAA+BC,EAC3C,GAAI,CACF,aAAMA,EACC,EACT,MAAgB,CACd,MAAO,EACT,CAGF,MAAO,EACT,CAtPA,IAmCIF,EACAE,EACAD,EACAI,GACAD,GAsNSS,GA7PbC,GAAAC,EAAA,kBAKAC,KA8BIhB,EAA4C,KAC5CE,EAAwD,KACxDD,EAAwB,kBACxBI,GAA0B,KAC1BD,GAA4B,KAKjBa,EAAArB,GAAA,kBAiBAqB,EAAAlB,GAAA,eAkDAkB,EAAAV,GAAA,WAiDNU,EAAAd,GAAA,SAsBAc,EAAAT,GAAA,iBASAS,EAAAR,GAAA,aAiBMQ,EAAAP,GAAA,qBAcNO,EAAAN,GAAA,sBASMM,EAAAL,GAAA,yBAsBFC,GAAoC,CAC/C,YAAAd,GACA,QAAAQ,GACA,MAAAJ,GACA,cAAAK,GACA,UAAAC,GACA,kBAAAC,GACA,mBAAAC,GACA,sBAAAC,EACF,EAMA,QAAQ,GAAG,OAAQ,IAAM,CACnBC,GAAkC,cAAc,IAClD,QAAQ,IAAI,2GAA6C,EAEzDA,GAAkC,MAAM,EAE5C,CAAC,EAGD,QAAQ,GAAG,oBAAqB,MAAOP,GAAU,CAC/C,QAAQ,MAAM,0GAA6CA,CAAK,EAChE,GAAI,CACF,MAAMO,GAAkC,QAAQ,CAClD,OAASK,EAAc,CACrB,QAAQ,MAAM,0DAAcA,CAAY,CAC1C,CACF,CAAC,EAGD,QAAQ,GAAG,qBAAsB,MAAOC,GAAW,CACjD,QAAQ,MACN,iHACAA,CACF,EACA,GAAI,CACF,MAAMN,GAAkC,QAAQ,CAClD,OAASK,EAAc,CACrB,QAAQ,MAAM,0DAAcA,CAAY,CAC1C,CACF,CAAC,ICzSD,OAAS,gBAAAE,OAAoB,SAmMtB,SAASC,GAAwB,CACtC,OAAKC,KACHA,GAAmB,IAAIC,IAElBD,EACT,CAKO,SAASE,IAAwB,CAClCF,KACFA,GAAiB,QAAQ,EACzBA,GAAmB,KAEvB,CAlNA,IAkCaC,GA4JTD,GA9LJG,EAAAC,EAAA,kBACAC,IAiCaJ,GAAN,cAAuBH,EAAa,CAlC3C,MAkC2C,CAAAQ,EAAA,iBACjC,OACA,WACN,IAAI,IACE,aAAe,GAEvB,aAAc,CACZ,MAAM,EACN,KAAK,OAASC,EAAO,QAAQ,UAAU,EACvC,KAAK,gBAAgB,KAAK,YAAY,EACtC,KAAK,mBAAmB,CAC1B,CAKQ,oBAA2B,CACjC,KAAK,GAAG,QAAUC,GAAU,CAC1B,KAAK,OAAO,MAAM,qCAAkBA,CAAK,CAC3C,CAAC,EAGD,KAAK,GAAG,cAAgBC,GAAc,CACpC,IAAMC,EAAgB,KAAK,cAAcD,CAAS,EAC9CC,EAAgB,KAAK,aAAe,IACtC,KAAK,OAAO,KACV,gBAAMD,CAAS,sDAAcC,CAAa,EAC5C,CAEJ,CAAC,CACH,CAKA,UACED,EACAE,EACS,CACT,GAAI,CACF,YAAK,iBAAiBF,CAAmB,EACzC,KAAK,OAAO,MAAM,6BAASA,CAAS,GAAIE,CAAI,EACrC,KAAK,KAAKF,EAAWE,CAAI,CAClC,OAASH,EAAO,CACd,YAAK,OAAO,MAAM,yCAAWC,CAAS,GAAID,CAAK,EACxC,EACT,CACF,CAKA,QACEC,EACAG,EACM,CACN,YAAK,OAAO,MAAM,+CAAYH,CAAS,EAAE,EAClC,KAAK,GAAGA,EAAWG,CAAQ,CACpC,CAKA,UACEH,EACAG,EACM,CACN,YAAK,OAAO,MAAM,iEAAeH,CAAS,EAAE,EACrC,KAAK,KAAKA,EAAWG,CAAQ,CACtC,CAKA,SACEH,EACAG,EACM,CACN,YAAK,OAAO,MAAM,+CAAYH,CAAS,EAAE,EAClC,KAAK,IAAIA,EAAWG,CAAQ,CACrC,CAKQ,iBAAiBH,EAAyB,CAChD,IAAMI,EAAQ,KAAK,WAAW,IAAIJ,CAAS,GAAK,CAC9C,MAAO,EACP,YAAa,IAAI,IACnB,EACAI,EAAM,QACNA,EAAM,YAAc,IAAI,KACxB,KAAK,WAAW,IAAIJ,EAAWI,CAAK,CACtC,CAKA,eAAsE,CACpE,IAAMA,EAA8D,CAAC,EACrE,OAAW,CAACJ,EAAWK,CAAI,IAAK,KAAK,WACnCD,EAAMJ,CAAS,EAAI,CAAE,GAAGK,CAAK,EAE/B,OAAOD,CACT,CAKA,kBAA2C,CACzC,IAAMA,EAAgC,CAAC,EACvC,QAAWJ,KAAa,KAAK,WAAW,EACtCI,EAAMJ,CAAmB,EAAI,KAAK,cAAcA,CAAS,EAE3D,OAAOI,CACT,CAKA,iBAAwB,CACtB,KAAK,WAAW,MAAM,EACtB,KAAK,OAAO,KAAK,4CAAS,CAC5B,CAKA,WAKE,CACA,MAAO,CACL,YAAa,KAAK,WAAW,KAC7B,eAAgB,OAAO,OAAO,KAAK,iBAAiB,CAAC,EAAE,OACrD,CAACE,EAAKC,IAAUD,EAAMC,EACtB,CACF,EACA,WAAY,KAAK,cAAc,EAC/B,cAAe,KAAK,iBAAiB,CACvC,CACF,CAKA,SAAgB,CACd,KAAK,mBAAmB,EACxB,KAAK,WAAW,MAAM,EACtB,KAAK,OAAO,KAAK,6BAAc,CACjC,CACF,EAGIhB,GAAoC,KAKxBM,EAAAP,EAAA,eAUAO,EAAAJ,GAAA,qBC7MhB,IAOae,EAPbC,GAAAC,EAAA,kBAAAC,IACAC,IACAC,IAKaL,EAAN,KAAoB,CAP3B,MAO2B,CAAAM,EAAA,sBACjB,OACA,SAER,aAAc,CACZ,KAAK,OAASC,EAAO,QAAQ,eAAe,EAC5C,KAAK,SAAWC,EAAY,CAC9B,CAKA,MAAM,WAAgC,CACpC,GAAI,CACF,IAAMC,EAASC,EAAc,UAAU,EACvC,YAAK,OAAO,MAAM,sCAAQ,EACnBD,CACT,OAASE,EAAO,CACd,WAAK,OAAO,MAAM,wCAAWA,CAAK,EAClC,KAAK,SAAS,UAAU,eAAgB,CACtC,MAAOA,aAAiB,MAAQA,EAAQ,IAAI,MAAM,OAAOA,CAAK,CAAC,EAC/D,UAAW,WACb,CAAC,EACKA,CACR,CACF,CAKA,MAAM,aAAaC,EAAsBC,EAAS,UAA0B,CAC1E,GAAI,CACF,KAAK,OAAO,KAAK,2DAAcA,CAAM,EAAE,EAGvC,KAAK,eAAeD,CAAS,EAGzBA,EAAU,cAAgBF,EAAc,eAAe,GACzDA,EAAc,kBAAkBE,EAAU,WAAW,EAIvD,IAAME,EAAiBJ,EAAc,cAAc,EACnD,OAAW,CAACK,EAAMN,CAAM,IAAK,OAAO,QAAQG,EAAU,UAAU,EAC1D,KAAK,UAAUE,EAAeC,CAAI,CAAC,IAAM,KAAK,UAAUN,CAAM,GAChEC,EAAc,gBAAgBK,EAAMN,CAAM,EAK9C,QAAWM,KAAQ,OAAO,KAAKD,CAAc,EACrCC,KAAQH,EAAU,aACtBF,EAAc,gBAAgBK,CAAI,EAElCL,EAAc,wBAAwBK,CAAI,GAoB9C,GAfIH,EAAU,YACZF,EAAc,uBAAuBE,EAAU,UAAU,EAIvDA,EAAU,YACZF,EAAc,uBAAuBE,EAAU,UAAU,EAIvDA,EAAU,OACZF,EAAc,kBAAkBE,EAAU,KAAK,EAI7CA,EAAU,gBACZ,OAAW,CAACI,EAAYC,CAAW,IAAK,OAAO,QAC7CL,EAAU,eACZ,EACE,OAAW,CAACM,EAAUC,CAAU,IAAK,OAAO,QAC1CF,EAAY,KACd,EACEP,EAAc,eACZM,EACAE,EACAC,EAAW,MACb,EAKN,KAAK,OAAO,KAAK,sCAAQ,EAGzB,KAAK,SAAS,UAAU,iBAAkB,CACxC,OAAQP,EACR,OAAAC,CACF,CAAC,CACH,OAASF,EAAO,CACd,WAAK,OAAO,MAAM,wCAAWA,CAAK,EAClC,KAAK,SAAS,UAAU,eAAgB,CACtC,MAAOA,aAAiB,MAAQA,EAAQ,IAAI,MAAM,OAAOA,CAAK,CAAC,EAC/D,UAAW,cACb,CAAC,EACKA,CACR,CACF,CAKA,gBAAyB,CACvB,GAAI,CACF,OAAOD,EAAc,eAAe,CACtC,OAASC,EAAO,CACd,WAAK,OAAO,MAAM,6CAAgBA,CAAK,EACjCA,CACR,CACF,CAKA,iBAA4B,CAC1B,GAAI,CACF,OAAOD,EAAc,gBAAgB,CACvC,OAASC,EAAO,CACd,WAAK,OAAO,MAAM,yDAAkBA,CAAK,EACnCA,CACR,CACF,CAKA,eAAqC,CACnC,GAAI,CACF,OAAOD,EAAc,cAAc,CACrC,OAASC,EAAO,CACd,WAAK,OAAO,MAAM,yDAAkBA,CAAK,EACnCA,CACR,CACF,CAKA,qBAA2B,CACzB,GAAI,CACF,OAAOD,EAAc,oBAAoB,CAC3C,OAASC,EAAO,CACd,WAAK,OAAO,MAAM,oDAAaA,CAAK,EAC9BA,CACR,CACF,CAKA,cAAuB,CACrB,GAAI,CACF,OAAOD,EAAc,aAAa,GAAK,IACzC,OAASC,EAAO,CACd,YAAK,OAAO,MAAM,gDAAmBA,CAAK,EACnC,IACT,CACF,CAKQ,eAAeF,EAAyB,CAC9C,GAAI,CAACA,GAAU,OAAOA,GAAW,SAC/B,MAAM,IAAI,MAAM,8DAAY,EAG9B,GAAI,CAACA,EAAO,YACV,MAAM,IAAI,MAAM,kDAAoB,EAGtC,GAAI,CAACA,EAAO,YAAc,OAAOA,EAAO,YAAe,SACrD,MAAM,IAAI,MAAM,mEAAsB,CAE1C,CAKA,cAAwB,CACtB,OAAOC,EAAc,aAAa,CACpC,CAKA,MAAM,cAAmC,CACvC,GAAI,CACF,KAAK,OAAO,KAAK,sCAAQ,EACzBA,EAAc,aAAa,EAC3B,IAAMD,EAAS,MAAM,KAAK,UAAU,EAEpC,YAAK,SAAS,UAAU,iBAAkB,CACxC,OAAAA,EACA,OAAQ,QACV,CAAC,EAEMA,CACT,OAASE,EAAO,CACd,WAAK,OAAO,MAAM,oDAAaA,CAAK,EACpC,KAAK,SAAS,UAAU,eAAgB,CACtC,MAAOA,aAAiB,MAAQA,EAAQ,IAAI,MAAM,OAAOA,CAAK,CAAC,EAC/D,UAAW,cACb,CAAC,EACKA,CACR,CACF,CAKA,eAAwB,CACtB,OAAOD,EAAc,cAAc,CACrC,CACF,ICtOA,IAyBaU,GAzBbC,GAAAC,EAAA,kBACAC,IAEAC,KAsBaJ,GAAN,KAAuB,CAzB9B,MAyB8B,CAAAK,EAAA,yBACpB,OACA,cAER,aAAc,CACZ,KAAK,OAASC,EAAO,QAAQ,kBAAkB,EAC/C,KAAK,cAAgB,IAAIC,CAC3B,CAKQ,oBACNC,EACAC,EACAC,EACkB,CAClB,MAAO,CACL,MAAO,CACL,KAAAF,EACA,QAAAC,EACA,QAAAC,CACF,CACF,CACF,CAKQ,sBACNC,EACAF,EACuB,CACvB,MAAO,CACL,QAAS,GACT,KAAAE,EACA,QAAAF,CACF,CACF,CAMA,MAAM,UAAUG,EAA+B,CAC7C,GAAI,CACF,KAAK,OAAO,MAAM,kDAAU,EAC5B,IAAMC,EAAS,MAAM,KAAK,cAAc,UAAU,EAClD,YAAK,OAAO,KAAK,sCAAQ,EAClBD,EAAE,KAAK,KAAK,sBAAsBC,CAAM,CAAC,CAClD,OAASC,EAAO,CACd,KAAK,OAAO,MAAM,wCAAWA,CAAK,EAClC,IAAMC,EAAgB,KAAK,oBACzB,oBACAD,aAAiB,MAAQA,EAAM,QAAU,sCAC3C,EACA,OAAOF,EAAE,KAAKG,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,aAAaH,EAA+B,CAChD,GAAI,CACF,KAAK,OAAO,MAAM,kDAAU,EAC5B,IAAMI,EAAuB,MAAMJ,EAAE,IAAI,KAAK,EAG9C,GAAI,CAACI,GAAa,OAAOA,GAAc,SAAU,CAC/C,IAAMD,EAAgB,KAAK,oBACzB,uBACA,gFACF,EACA,OAAOH,EAAE,KAAKG,EAAe,GAAG,CAClC,CAEA,aAAM,KAAK,cAAc,aAAaC,EAAW,UAAU,EAC3D,KAAK,OAAO,KAAK,sCAAQ,EAElBJ,EAAE,KAAK,KAAK,sBAAsB,KAAM,sCAAQ,CAAC,CAC1D,OAASE,EAAO,CACd,KAAK,OAAO,MAAM,wCAAWA,CAAK,EAClC,IAAMC,EAAgB,KAAK,oBACzB,sBACAD,aAAiB,MAAQA,EAAM,QAAU,sCAC3C,EACA,OAAOF,EAAE,KAAKG,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,eAAeH,EAA+B,CAClD,GAAI,CACF,KAAK,OAAO,MAAM,uDAAe,EACjC,IAAMK,EAAW,KAAK,cAAc,eAAe,EACnD,YAAK,OAAO,MAAM,2CAAa,EACxBL,EAAE,KAAK,KAAK,sBAAsB,CAAE,SAAAK,CAAS,CAAC,CAAC,CACxD,OAASH,EAAO,CACd,KAAK,OAAO,MAAM,6CAAgBA,CAAK,EACvC,IAAMC,EAAgB,KAAK,oBACzB,0BACAD,aAAiB,MAAQA,EAAM,QAAU,2CAC3C,EACA,OAAOF,EAAE,KAAKG,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,gBAAgBH,EAA+B,CACnD,GAAI,CACF,KAAK,OAAO,MAAM,mEAAiB,EACnC,IAAMM,EAAY,KAAK,cAAc,gBAAgB,EACrD,YAAK,OAAO,MAAM,uDAAe,EAC1BN,EAAE,KAAK,KAAK,sBAAsB,CAAE,UAAAM,CAAU,CAAC,CAAC,CACzD,OAASJ,EAAO,CACd,KAAK,OAAO,MAAM,yDAAkBA,CAAK,EACzC,IAAMC,EAAgB,KAAK,oBACzB,2BACAD,aAAiB,MAAQA,EAAM,QAAU,uDAC3C,EACA,OAAOF,EAAE,KAAKG,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,cAAcH,EAA+B,CACjD,GAAI,CACF,KAAK,OAAO,MAAM,mEAAiB,EACnC,IAAMO,EAAU,KAAK,cAAc,cAAc,EACjD,YAAK,OAAO,MAAM,uDAAe,EAC1BP,EAAE,KAAK,KAAK,sBAAsB,CAAE,QAAAO,CAAQ,CAAC,CAAC,CACvD,OAASL,EAAO,CACd,KAAK,OAAO,MAAM,yDAAkBA,CAAK,EACzC,IAAMC,EAAgB,KAAK,oBACzB,yBACAD,aAAiB,MAAQA,EAAM,QAAU,uDAC3C,EACA,OAAOF,EAAE,KAAKG,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,oBAAoBH,EAA+B,CACvD,GAAI,CACF,KAAK,OAAO,MAAM,8DAAY,EAC9B,IAAMQ,EAAa,KAAK,cAAc,oBAAoB,EAC1D,YAAK,OAAO,MAAM,kDAAU,EACrBR,EAAE,KAAK,KAAK,sBAAsB,CAAE,WAAAQ,CAAW,CAAC,CAAC,CAC1D,OAASN,EAAO,CACd,KAAK,OAAO,MAAM,oDAAaA,CAAK,EACpC,IAAMC,EAAgB,KAAK,oBACzB,+BACAD,aAAiB,MAAQA,EAAM,QAAU,kDAC3C,EACA,OAAOF,EAAE,KAAKG,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,aAAaH,EAA+B,CAChD,GAAI,CACF,KAAK,OAAO,KAAK,8DAAY,EAC7B,IAAMC,EAAS,MAAM,KAAK,cAAc,aAAa,EACrD,YAAK,OAAO,KAAK,kDAAU,EACpBD,EAAE,KAAK,KAAK,sBAAsBC,EAAQ,kDAAU,CAAC,CAC9D,OAASC,EAAO,CACd,KAAK,OAAO,MAAM,oDAAaA,CAAK,EACpC,IAAMC,EAAgB,KAAK,oBACzB,sBACAD,aAAiB,MAAQA,EAAM,QAAU,kDAC3C,EACA,OAAOF,EAAE,KAAKG,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,cAAcH,EAA+B,CACjD,GAAI,CACF,KAAK,OAAO,MAAM,0EAAc,EAChC,IAAMS,EAAO,KAAK,cAAc,cAAc,EAC9C,YAAK,OAAO,MAAM,8DAAY,EACvBT,EAAE,KAAK,KAAK,sBAAsB,CAAE,KAAAS,CAAK,CAAC,CAAC,CACpD,OAASP,EAAO,CACd,KAAK,OAAO,MAAM,gEAAeA,CAAK,EACtC,IAAMC,EAAgB,KAAK,oBACzB,yBACAD,aAAiB,MAAQA,EAAM,QAAU,8DAC3C,EACA,OAAOF,EAAE,KAAKG,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,kBAAkBH,EAA+B,CACrD,GAAI,CACF,KAAK,OAAO,MAAM,0EAAc,EAChC,IAAMU,EAAS,KAAK,cAAc,aAAa,EAC/C,YAAK,OAAO,MAAM,qDAAaA,CAAM,EAAE,EAChCV,EAAE,KAAK,KAAK,sBAAsB,CAAE,OAAAU,CAAO,CAAC,CAAC,CACtD,OAASR,EAAO,CACd,KAAK,OAAO,MAAM,gEAAeA,CAAK,EACtC,IAAMC,EAAgB,KAAK,oBACzB,4BACAD,aAAiB,MAAQA,EAAM,QAAU,8DAC3C,EACA,OAAOF,EAAE,KAAKG,EAAe,GAAG,CAClC,CACF,CACF,IChQA,IAqBaQ,GArBbC,GAAAC,EAAA,kBAAAC,IACAC,KAoBaJ,GAAN,KAAuB,CArB9B,MAqB8B,CAAAK,EAAA,yBACpB,OACA,cACA,oBACA,cAER,YACEC,EACAC,EACA,CACA,KAAK,OAASC,EAAO,QAAQ,kBAAkB,EAC/C,KAAK,cAAgBF,EACrB,KAAK,oBAAsBC,EAC3B,KAAK,cAAgB,IAAIE,CAC3B,CAKA,MAAM,mBACJC,EACAC,EACAC,EACe,CACf,GAAI,CACF,KAAK,OAAO,MAAM,2DAAcA,CAAQ,GAAID,EAAQ,IAAI,EAGxD,IAAME,EAAe,CACnB,GAAGF,EAAQ,KACX,cAAe,KAAK,IAAI,CAC1B,EAEA,KAAK,cAAc,iBACjBE,EACA,aAAaD,CAAQ,EACvB,EAGA,MAAM,KAAK,iBAAiBF,EAAIE,CAAQ,EAExC,KAAK,OAAO,MAAM,2DAAcA,CAAQ,EAAE,CAC5C,OAASE,EAAO,CACd,KAAK,OAAO,MAAM,uEAAgBF,CAAQ,GAAIE,CAAK,EACnD,KAAK,UACHJ,EACA,sBACAI,aAAiB,MAAQA,EAAM,QAAU,wDAC3C,CACF,CACF,CAKA,MAAc,iBAAiBJ,EAASE,EAAiC,CACvE,GAAI,CAEF,IAAMD,EAAU,CACd,KAAM,eACN,KAHmB,MAAM,KAAK,cAAc,UAAU,EAItD,UAAW,KAAK,IAAI,CACtB,EAEAD,EAAG,KAAK,KAAK,UAAUC,CAAO,CAAC,EAC/B,KAAK,OAAO,MAAM,uEAAgBC,CAAQ,EAAE,CAC9C,OAASE,EAAO,CACd,KAAK,OAAO,MAAM,qDAAaF,CAAQ,GAAIE,CAAK,CAElD,CACF,CAKQ,UAAUJ,EAASK,EAAcJ,EAAuB,CAC9D,GAAI,CACF,IAAMK,EAAgB,CACpB,KAAM,QACN,MAAO,CACL,KAAAD,EACA,QAAAJ,EACA,UAAW,KAAK,IAAI,CACtB,CACF,EACAD,EAAG,KAAK,KAAK,UAAUM,CAAa,CAAC,CACvC,OAASF,EAAO,CACd,KAAK,OAAO,MAAM,oDAAaA,CAAK,CACtC,CACF,CAKA,uBAA8B,CAC5B,IAAMG,EAAgB,KAAK,cAAc,iBAAiB,EACpDC,EAAM,KAAK,IAAI,EAGjBD,GAAiBC,EAAMD,EAFD,OAGxB,KAAK,OAAO,KAAK,4FAAiB,EAClC,KAAK,cAAc,iBACjB,CAAE,OAAQ,cAAe,EACzB,mBACF,EAEJ,CAKA,0BAA2C,CAGzC,YAAK,OAAO,KAAK,sCAAQ,EAElB,YAAY,IAAM,CACvB,KAAK,sBAAsB,EAC3B,KAAK,2BAA2B,CAClC,EAAG,GAAgB,CACrB,CAKQ,4BAAmC,CACzC,GAAI,CACF,KAAK,oBAAoB,2BAA2B,CACtD,OAASH,EAAO,CACd,KAAK,OAAO,MAAM,4EAAiBA,CAAK,CAC1C,CACF,CAKA,wBAAwBK,EAAkC,CACxD,KAAK,OAAO,KAAK,sCAAQ,EACzB,cAAcA,CAAU,CAC1B,CAKA,mBAQE,CACA,MAAO,CACL,cAAe,KAAK,cAAc,iBAAiB,EACnD,YAAa,KAAK,cAAc,kBAAkB,EAClD,YAAa,KAAK,oBAAoB,eAAe,CACvD,CACF,CAKA,oBAAoBP,EAAwB,CAC1C,KAAK,OAAO,KAAK,+CAAYA,CAAQ,EAAE,EAGvC,KAAK,cAAc,iBACjB,CACE,OAAQ,YACR,cAAe,KAAK,IAAI,CAC1B,EACA,qBAAqBA,CAAQ,EAC/B,CACF,CAKA,uBAAuBA,EAAwB,CAC7C,KAAK,OAAO,KAAK,+CAAYA,CAAQ,EAAE,EAGvC,KAAK,cAAc,iBACjB,CAAE,OAAQ,cAAe,EACzB,wBAAwBA,CAAQ,EAClC,CACF,CAKA,sBAAsBF,EAASE,EAAwB,CACrD,GAAI,CACF,IAAMQ,EAAW,CACf,KAAM,oBACN,KAAM,CACJ,UAAW,KAAK,IAAI,EACpB,OAAQ,IACV,CACF,EAEAV,EAAG,KAAK,KAAK,UAAUU,CAAQ,CAAC,EAChC,KAAK,OAAO,MAAM,+CAAYR,CAAQ,EAAE,CAC1C,OAASE,EAAO,CACd,KAAK,OAAO,MAAM,qDAAaF,CAAQ,GAAIE,CAAK,CAClD,CACF,CAKA,yBAAyBH,EAA2C,CAClE,OACEA,GACA,OAAOA,GAAY,UACnBA,EAAQ,OAAS,gBACjBA,EAAQ,MACR,OAAOA,EAAQ,MAAS,QAE5B,CACF,IClPA,IAkBaU,GAlBbC,GAAAC,EAAA,kBAAAC,IACAC,KACAC,IAgBaL,GAAN,KAAkC,CAlBzC,MAkByC,CAAAM,EAAA,oCAC/B,OACA,oBACA,cACA,cACA,SAER,YACEC,EACAC,EACA,CACA,KAAK,OAASC,EAAO,QAAQ,6BAA6B,EAC1D,KAAK,oBAAsBF,EAC3B,KAAK,cAAgB,IAAIG,EACzB,KAAK,cAAgBF,EACrB,KAAK,SAAWG,EAAY,CAC9B,CAMA,MAAM,cACJC,EACAC,EACAC,EACe,CACf,GAAI,CAUF,OATA,KAAK,OAAO,MAAM,wCAAoBD,EAAQ,IAAI,GAAI,CAAE,SAAAC,CAAS,CAAC,EAGlE,KAAK,SAAS,UAAU,6BAA8B,CACpD,KAAMD,EAAQ,KACd,KAAMA,EAAQ,KACd,SAAAC,CACF,CAAC,EAEOD,EAAQ,KAAM,CACpB,IAAK,YACH,MAAM,KAAK,gBAAgBD,EAAIE,CAAQ,EACvC,MAEF,IAAK,eACH,MAAM,KAAK,mBAAmBF,EAAIC,EAAQ,KAAMC,CAAQ,EACxD,MAEF,IAAK,YACH,MAAM,KAAK,gBAAgBF,EAAIE,CAAQ,EACvC,MAEF,IAAK,iBACH,MAAM,KAAK,qBAAqBF,EAAIE,CAAQ,EAC5C,MAEF,QACE,KAAK,OAAO,KAAK,0DAAuBD,EAAQ,IAAI,GAAI,CACtD,SAAAC,CACF,CAAC,EACD,KAAK,UACHF,EACA,uBACA,+CAAYC,EAAQ,IAAI,EAC1B,CACJ,CACF,OAASE,EAAO,CACd,KAAK,OAAO,MAAM,oDAAsBF,EAAQ,IAAI,GAAIE,CAAK,EAC7D,KAAK,UACHH,EACA,2BACAG,aAAiB,MAAQA,EAAM,QAAU,sCAC3C,CACF,CACF,CAMA,MAAc,gBAAgBH,EAASE,EAAiC,CACtE,KAAK,sBAAsB,sBAAuB,iBAAiB,EAEnE,GAAI,CACF,IAAME,EAAS,MAAM,KAAK,cAAc,UAAU,EAClD,KAAK,OAAO,MAAM,4DAA+B,CAAE,SAAAF,CAAS,CAAC,EAC7DF,EAAG,KAAK,KAAK,UAAU,CAAE,KAAM,SAAU,KAAMI,CAAO,CAAC,CAAC,CAC1D,OAASD,EAAO,CACd,KAAK,OAAO,MAAM,4DAA+BA,CAAK,EACtD,KAAK,UACHH,EACA,oBACAG,aAAiB,MAAQA,EAAM,QAAU,sCAC3C,CACF,CACF,CAMA,MAAc,mBACZH,EACAK,EACAH,EACe,CACf,KAAK,sBAAsB,yBAA0B,iBAAiB,EAEtE,GAAI,CACF,MAAM,KAAK,cAAc,aACvBG,EACA,aAAaH,CAAQ,EACvB,EACA,KAAK,OAAO,MAAM,+DAAkC,CAAE,SAAAA,CAAS,CAAC,CAClE,OAASC,EAAO,CACd,KAAK,OAAO,MAAM,+DAAkCA,CAAK,EACzD,KAAK,UACHH,EACA,sBACAG,aAAiB,MAAQA,EAAM,QAAU,sCAC3C,CACF,CACF,CAMA,MAAc,gBAAgBH,EAASE,EAAiC,CACtE,KAAK,sBAAsB,sBAAuB,iBAAiB,EAEnE,GAAI,CACF,IAAMI,EAAS,KAAK,cAAc,cAAc,EAChDN,EAAG,KAAK,KAAK,UAAU,CAAE,KAAM,SAAU,KAAMM,EAAO,MAAO,CAAC,CAAC,EAC/D,KAAK,OAAO,MAAM,4DAA+B,CAAE,SAAAJ,CAAS,CAAC,CAC/D,OAASC,EAAO,CACd,KAAK,OAAO,MAAM,4DAA+BA,CAAK,EACtD,KAAK,UACHH,EACA,oBACAG,aAAiB,MAAQA,EAAM,QAAU,sCAC3C,CACF,CACF,CAMA,MAAc,qBAAqBH,EAASE,EAAiC,CAC3E,KAAK,sBACH,2BACA,4BACF,EAEA,GAAI,CACF,KAAK,OAAO,KAAK,8DAAuB,CAAE,SAAAA,CAAS,CAAC,EAGpD,KAAK,SAAS,UAAU,4BAA6B,CACnD,OAAQ,aAAaA,CAAQ,EAC/B,CAAC,EAGD,KAAK,cAAc,oBAAoB,YAAY,CACrD,OAASC,EAAO,CACd,KAAK,OAAO,MAAM,8DAAuBA,CAAK,EAC9C,KAAK,UACHH,EACA,wBACAG,aAAiB,MAAQA,EAAM,QAAU,kDAC3C,CACF,CACF,CAKQ,UAAUH,EAASO,EAAcN,EAAuB,CAC9D,GAAI,CACF,IAAMO,EAAgB,CACpB,KAAM,QACN,MAAO,CACL,KAAAD,EACA,QAAAN,EACA,UAAW,KAAK,IAAI,CACtB,CACF,EACAD,EAAG,KAAK,KAAK,UAAUQ,CAAa,CAAC,CACvC,OAASL,EAAO,CACd,KAAK,OAAO,MAAM,oDAAaA,CAAK,CACtC,CACF,CAKQ,sBAAsBM,EAAiBC,EAA2B,CACxE,KAAK,OAAO,KACV,gBAAgBD,CAAO,2DAAcC,CAAW,eAClD,CACF,CAKA,MAAM,gBAAgBV,EAASE,EAAiC,CAC9D,GAAI,CACF,KAAK,OAAO,MAAM,+DAAc,CAAE,SAAAA,CAAS,CAAC,EAG5C,IAAME,EAAS,MAAM,KAAK,cAAc,UAAU,EAClDJ,EAAG,KAAK,KAAK,UAAU,CAAE,KAAM,eAAgB,KAAMI,CAAO,CAAC,CAAC,EAG9D,IAAME,EAAS,KAAK,cAAc,cAAc,EAChDN,EAAG,KAAK,KAAK,UAAU,CAAE,KAAM,eAAgB,KAAMM,EAAO,MAAO,CAAC,CAAC,EAGjEA,EAAO,SACTN,EAAG,KACD,KAAK,UAAU,CAAE,KAAM,gBAAiB,KAAMM,EAAO,OAAQ,CAAC,CAChE,EAGF,KAAK,OAAO,MAAM,mDAAY,CAAE,SAAAJ,CAAS,CAAC,CAC5C,OAASC,EAAO,CACd,KAAK,OAAO,MAAM,oDAAaA,CAAK,EACpC,KAAK,UACHH,EACA,qBACAG,aAAiB,MAAQA,EAAM,QAAU,kDAC3C,CACF,CACF,CAKA,uBAAuBD,EAAwB,CAC7C,KAAK,OAAO,KAAK,+CAAYA,CAAQ,EAAE,EACvC,KAAK,oBAAoB,iBAAiBA,CAAQ,CACpD,CAKA,oBAAoBF,EAASE,EAAwB,CACnD,KAAK,OAAO,KAAK,mCAAUA,CAAQ,EAAE,EACrC,KAAK,oBAAoB,eAAeA,EAAUF,CAAE,CACtD,CACF,IC3QA,IAOaW,GAgBAC,GAgBAC,GAYAC,EAsBAC,GAzEbC,GAAAC,EAAA,kBAOaN,GAAoB,CAE/B,KAAM,sBAEN,aAAc,IAEd,oBAAqB,KAErB,SAAU,cAEV,SAAU,aACZ,EAKaC,GAAmB,CAE9B,WAAY,CACV,uBACA,uBACA,qBACF,EAEA,aAAc,8BAEd,YAAa,oBACf,EAKaC,GAAiB,CAE5B,SAAU,WAEV,cAAe,YAEf,SAAU,MACZ,EAKaC,EAAc,CAEzB,cAAe,gBAEf,aAAc,eAEd,cAAe,gBAEf,iBAAkB,mBAElB,WAAY,aAEZ,cAAe,gBAEf,cAAe,gBAEf,iBAAkB,kBACpB,EAKaC,GAAoB,CAE/B,aAAc,IAEd,cAAe,IAEf,gBAAiB,IAEjB,eAAgB,GAClB,IClFA,IASMG,GAaAC,GA0BOC,GAhDbC,GAAAC,EAAA,kBAIAC,KAKML,GAA8C,CAClD,CAACM,EAAY,YAAY,EAAG,iFAC5B,CAACA,EAAY,aAAa,EAAG,qEAC7B,CAACA,EAAY,gBAAgB,EAAG,+DAChC,CAACA,EAAY,UAAU,EAAG,yDAC1B,CAACA,EAAY,aAAa,EAAG,yDAC7B,CAACA,EAAY,aAAa,EAAG,2EAC7B,CAACA,EAAY,gBAAgB,EAAG,oEAClC,EAKML,GAA6C,CACjD,iBAAkB,CAChB,yEACA,uFACA,8FACF,EACA,sBAAuB,CACrB,iFACA,8FACA,0EACF,EACA,kBAAmB,CACjB,yDACA,qEACA,0EACF,EACA,qBAAsB,CACpB,2EACA,uFACA,0EACF,CACF,EAKaC,GAAN,KAAqB,CAhD5B,MAgD4B,CAAAK,EAAA,uBAI1B,OAAO,eAAeC,EAAuC,CAC3D,OAAOR,GAAoBQ,CAAS,CACtC,CAKA,OAAO,aAAaC,EAA8B,CAChD,OAAOR,GAAiBQ,CAAU,GAAK,CAAC,CAC1C,CAKA,OAAO,YAAYC,EAAcC,EAA0B,CAEzD,MAAO,GADeA,EAAU,IAAIA,CAAO,KAAO,EAC3B,GAAGD,EAAM,OAAO,EACzC,CAKA,OAAO,mBAAmBF,EAA2B,CAWnD,MAViD,CAC/C,CAACF,EAAY,YAAY,EAAG,mDAC5B,CAACA,EAAY,aAAa,EAAG,mDAC7B,CAACA,EAAY,gBAAgB,EAAG,uCAChC,CAACA,EAAY,UAAU,EAAG,uCAC1B,CAACA,EAAY,aAAa,EAAG,uCAC7B,CAACA,EAAY,aAAa,EAAG,uCAC7B,CAACA,EAAY,gBAAgB,EAAG,sCAClC,EAEwBE,CAAS,GAAK,0BACxC,CAKA,OAAO,cAAcA,EAA4B,CAO/C,MANoC,CAClCF,EAAY,cACZA,EAAY,WACZA,EAAY,aACd,EAEyB,SAASE,CAAS,CAC7C,CAKA,OAAO,YACLA,EACwC,CAYxC,MAVE,CACE,CAACF,EAAY,gBAAgB,EAAG,MAChC,CAACA,EAAY,UAAU,EAAG,SAC1B,CAACA,EAAY,YAAY,EAAG,SAC5B,CAACA,EAAY,aAAa,EAAG,SAC7B,CAACA,EAAY,aAAa,EAAG,OAC7B,CAACA,EAAY,aAAa,EAAG,OAC7B,CAACA,EAAY,gBAAgB,EAAG,UAClC,EAEiBE,CAAS,GAAK,QACnC,CACF,ICxHA,IASaI,EA+BAC,EAsBAC,EAoCAC,EAqBAC,EA2BAC,EAlJbC,EAAAC,EAAA,kBAIAC,KAKaR,EAAN,MAAMS,UAAiB,KAAM,CAClC,YACEC,EACOC,EACAC,EAAW,EACXC,EACP,CACA,MAAMH,CAAO,EAJN,UAAAC,EACA,cAAAC,EACA,iBAAAC,EAGP,KAAK,KAAO,WAGR,MAAM,mBACR,MAAM,kBAAkB,KAAMJ,CAAQ,CAE1C,CAvBF,MASoC,CAAAK,EAAA,iBAmBlC,OAAO,gBACLJ,EACAC,EACAE,EACU,CACV,OAAO,IAAIJ,EAASC,EAASC,EAAM,EAAGE,CAAW,CACnD,CACF,EAKaZ,EAAN,MAAMc,UAAoBf,CAAS,CAxC1C,MAwC0C,CAAAc,EAAA,oBACxC,YAAYJ,EAAiBG,EAAwB,CACnD,MAAMH,EAASM,EAAY,aAAc,EAAGH,CAAW,EACvD,KAAK,KAAO,aACd,CAEA,OAAO,gBAA8B,CACnC,OAAO,IAAIE,EAAY,6CAAW,CAChC,8EACF,CAAC,CACH,CAEA,OAAO,cAAcE,EAA6B,CAChD,OAAO,IAAIF,EAAY,2DAAcE,CAAM,GAAI,CAC7C,oDACF,CAAC,CACH,CACF,EAKaf,EAAN,MAAMgB,UAAqBlB,CAAS,CA9D3C,MA8D2C,CAAAc,EAAA,qBACzC,YAAYJ,EAAiBG,EAAwB,CACnD,MAAMH,EAASM,EAAY,cAAe,EAAGH,CAAW,EACxD,KAAK,KAAO,cACd,CAEA,OAAO,eAAeM,EAA2B,CAC/C,OAAO,IAAID,EAAa,oDAAiBC,CAAG,IAAK,CAC/C,+EACA,qEACF,CAAC,CACH,CAEA,OAAO,eAAeA,EAA2B,CAC/C,OAAO,IAAID,EACT,gEAAmBC,CAAG,iDACtB,CAAC,kIAAmC,CACtC,CACF,CAEA,OAAO,YAA2B,CAChC,OAAO,IAAID,EAAa,iCAAS,CAAC,6DAA0B,CAAC,CAC/D,CAEA,OAAO,YAAYE,EAA8B,CAC/C,OAAO,IAAIF,EAAa,yCAAWE,CAAM,GAAI,CAC3C,+DACA,mDACA,0EACF,CAAC,CACH,CACF,EAKajB,EAAN,MAAMkB,UAAwBrB,CAAS,CAlG9C,MAkG8C,CAAAc,EAAA,wBAC5C,YAAYJ,EAAiBY,EAAe,CAC1C,MAAM,6BAASA,CAAK,MAAMZ,CAAO,GAAIM,EAAY,iBAAkB,CAAC,EACpE,KAAK,KAAO,iBACd,CAEA,OAAO,YAAYO,EAA+B,CAChD,OAAO,IAAIF,EACT,4FAA2BE,CAAI,GAC/B,MACF,CACF,CAEA,OAAO,cAAcD,EAAgC,CACnD,OAAO,IAAID,EAAgB,mDAAYC,CAAK,CAC9C,CACF,EAKalB,EAAN,MAAMoB,UAAkBxB,CAAS,CAvHxC,MAuHwC,CAAAc,EAAA,kBACtC,YAAYJ,EAAiBe,EAAmBZ,EAAwB,CACtE,IAAMa,EAAcD,EAAW,GAAGf,CAAO,KAAKe,CAAQ,GAAKf,EAC3D,MAAMgB,EAAaV,EAAY,WAAY,EAAGH,CAAW,EACzD,KAAK,KAAO,WACd,CAEA,OAAO,SAASY,EAA6B,CAC3C,OAAO,IAAID,EAAU,iCAASC,EAAU,CAAC,8DAAY,CAAC,CACxD,CAEA,OAAO,iBAAiBA,EAA6B,CACnD,OAAO,IAAID,EAAU,2BAAQC,EAAU,CACrC,kGACF,CAAC,CACH,CAEA,OAAO,cAAcA,EAA6B,CAChD,OAAO,IAAID,EAAU,iCAASC,EAAU,CACtC,4FACF,CAAC,CACH,CACF,EAKapB,EAAN,MAAMsB,UAAqB3B,CAAS,CAlJ3C,MAkJ2C,CAAAc,EAAA,qBACzC,YAAYJ,EAAiBS,EAAcN,EAAwB,CACjE,IAAMa,EAAcP,EAAM,GAAGT,CAAO,UAAUS,CAAG,IAAMT,EACvD,MAAMgB,EAAaV,EAAY,cAAe,EAAGH,CAAW,EAC5D,KAAK,KAAO,cACd,CAEA,OAAO,WAAWM,EAA2B,CAC3C,OAAO,IAAIQ,EAAa,uCAAUR,EAAK,CACrC,gFACF,CAAC,CACH,CAEA,OAAO,SAASA,EAA2B,CACzC,OAAO,IAAIQ,EAAa,iCAASR,CAAG,CACtC,CACF,IC9JA,OAAOS,MAAW,QAJlB,IAWaC,GAXbC,GAAAC,EAAA,kBAKAC,KACAC,IAKaJ,GAAN,MAAMK,CAAa,CAX1B,MAW0B,CAAAC,EAAA,qBAIxB,OAAO,OAAOC,EAAqB,CAC7BA,aAAiBC,EACnBH,EAAa,eAAeE,CAAK,EAEjCF,EAAa,mBAAmBE,CAAK,EAGvC,QAAQ,KAAK,CAAC,CAChB,CAKA,OAAe,eAAeA,EAAuB,CASnD,GARA,QAAQ,MAAMR,EAAM,IAAI,wBAASQ,EAAM,OAAO,EAAE,CAAC,EAG7C,QAAQ,IAAI,OACd,QAAQ,MAAMR,EAAM,KAAK,uBAAQQ,EAAM,IAAI,EAAE,CAAC,EAI5CA,EAAM,aAAeA,EAAM,YAAY,OAAS,EAAG,CACrD,QAAQ,IAAIR,EAAM,OAAO,yBAAQ,CAAC,EAClC,QAAWU,KAAcF,EAAM,YAC7B,QAAQ,IAAIR,EAAM,KAAK,MAAMU,CAAU,EAAE,CAAC,CAE9C,CAGA,IAAMC,EAAcC,GAAe,eAAeJ,EAAM,IAAI,EACxDG,GACF,QAAQ,IAAIX,EAAM,KAAK,iBAAOW,CAAW,EAAE,CAAC,CAEhD,CAKA,OAAe,mBAAmBH,EAAoB,CACpD,QAAQ,MAAMR,EAAM,IAAI,oCAAWQ,EAAM,OAAO,EAAE,CAAC,EAG/C,QAAQ,IAAI,OAAS,QAAQ,IAAI,WAAa,eAChD,QAAQ,MAAMR,EAAM,KAAK,2BAAO,CAAC,EACjC,QAAQ,MAAMA,EAAM,KAAKQ,EAAM,KAAK,CAAC,GAErC,QAAQ,IACNR,EAAM,OAAO,uHAAgC,CAC/C,CAEJ,CAKA,aAAa,YACXa,EACAC,EACY,CACZ,GAAI,CACF,OAAO,MAAMD,EAAU,CACzB,OAASL,EAAO,CACd,MAAIA,aAAiBC,EACbD,EAEJA,aAAiB,MACb,IAAIC,EACR,GAAGK,CAAO,iBAAON,EAAM,OAAO,GAC9B,mBACA,CACF,EAEI,IAAIC,EAAS,GAAGK,CAAO,yCAAY,mBAAoB,CAAC,CAChE,CACF,CAKA,OAAO,WAAcD,EAAoBC,EAAoB,CAC3D,GAAI,CACF,OAAOD,EAAU,CACnB,OAASL,EAAO,CACd,MAAIA,aAAiBC,EACbD,EAEJA,aAAiB,MACb,IAAIC,EACR,GAAGK,CAAO,iBAAON,EAAM,OAAO,GAC9B,mBACA,CACF,EAEI,IAAIC,EAAS,GAAGK,CAAO,yCAAY,mBAAoB,CAAC,CAChE,CACF,CAKA,OAAO,KAAKC,EAAiBC,EAA8B,CAGzD,GAFA,QAAQ,KAAKhB,EAAM,OAAO,+BAAWe,CAAO,EAAE,CAAC,EAE3CC,GAAeA,EAAY,OAAS,EAAG,CACzC,QAAQ,IAAIhB,EAAM,OAAO,yBAAQ,CAAC,EAClC,QAAWU,KAAcM,EACvB,QAAQ,IAAIhB,EAAM,KAAK,MAAMU,CAAU,EAAE,CAAC,CAE9C,CACF,CAKA,OAAO,KAAKK,EAAuB,CACjC,QAAQ,IAAIf,EAAM,KAAK,iBAAOe,CAAO,EAAE,CAAC,CAC1C,CAKA,OAAO,QAAQA,EAAuB,CACpC,QAAQ,IAAIf,EAAM,MAAM,UAAKe,CAAO,EAAE,CAAC,CACzC,CACF,ICxIA,OAAOE,MAAQ,KACf,OAAOC,MAAU,OALjB,IAYaC,EAZbC,GAAAC,EAAA,kBAOAC,IAKaH,EAAN,MAAMI,CAAU,CAZvB,MAYuB,CAAAC,EAAA,kBAIrB,OAAO,OAAOC,EAA2B,CACvC,GAAI,CACF,OAAOR,EAAG,WAAWQ,CAAQ,CAC/B,MAAQ,CACN,MAAO,EACT,CACF,CAKA,OAAO,UAAUC,EAAuB,CACtC,GAAI,CACGT,EAAG,WAAWS,CAAO,GACxBT,EAAG,UAAUS,EAAS,CAAE,UAAW,EAAK,CAAC,CAE7C,MAAgB,CACd,MAAM,IAAIC,EAAU,uCAAUD,CAAO,CACvC,CACF,CAKA,OAAO,SAASD,EAAkBG,EAA2B,OAAgB,CAC3E,GAAI,CACF,GAAI,CAACL,EAAU,OAAOE,CAAQ,EAC5B,MAAME,EAAU,SAASF,CAAQ,EAEnC,OAAOR,EAAG,aAAaQ,EAAUG,CAAQ,CAC3C,OAASC,EAAO,CACd,MAAIA,aAAiBF,EACbE,EAEF,IAAIF,EAAU,uCAAUF,CAAQ,CACxC,CACF,CAKA,OAAO,UACLA,EACAK,EACAC,EACM,CACN,GAAI,CACF,GAAI,CAACA,GAAS,WAAaR,EAAU,OAAOE,CAAQ,EAClD,MAAME,EAAU,cAAcF,CAAQ,EAIxC,IAAMO,EAAMd,EAAK,QAAQO,CAAQ,EACjCF,EAAU,UAAUS,CAAG,EAEvBf,EAAG,cAAcQ,EAAUK,EAAS,MAAM,CAC5C,OAASD,EAAO,CACd,MAAIA,aAAiBF,EACbE,EAEF,IAAIF,EAAU,uCAAUF,CAAQ,CACxC,CACF,CAKA,OAAO,SACLQ,EACAC,EACAH,EACM,CACN,GAAI,CACF,GAAI,CAACR,EAAU,OAAOU,CAAO,EAC3B,MAAMN,EAAU,SAASM,CAAO,EAGlC,GAAI,CAACF,GAAS,WAAaR,EAAU,OAAOW,CAAQ,EAClD,MAAMP,EAAU,cAAcO,CAAQ,EAIxC,IAAMC,EAAUjB,EAAK,QAAQgB,CAAQ,EACrCX,EAAU,UAAUY,CAAO,EAE3BlB,EAAG,aAAagB,EAASC,CAAQ,CACnC,OAASL,EAAO,CACd,MAAIA,aAAiBF,EACbE,EAEF,IAAIF,EAAU,uCAAUM,CAAO,CACvC,CACF,CAKA,OAAO,WAAWR,EAAwB,CACxC,GAAI,CACEF,EAAU,OAAOE,CAAQ,GAC3BR,EAAG,WAAWQ,CAAQ,CAE1B,MAAgB,CACd,MAAM,IAAIE,EAAU,uCAAUF,CAAQ,CACxC,CACF,CAKA,OAAO,cACLW,EACAD,EACAJ,EAAgC,CAAC,EAC3B,CACN,GAAI,CACF,GAAI,CAACR,EAAU,OAAOa,CAAM,EAC1B,MAAMT,EAAU,SAASS,CAAM,EAIjCb,EAAU,UAAUY,CAAO,EAE3B,IAAME,EAAQpB,EAAG,YAAYmB,CAAM,EAEnC,QAAWE,KAAQD,EAAO,CAExB,GAAIN,EAAQ,SAAS,SAASO,CAAI,EAChC,SAGF,IAAML,EAAUf,EAAK,KAAKkB,EAAQE,CAAI,EAChCJ,EAAWhB,EAAK,KAAKiB,EAASG,CAAI,EAC3BrB,EAAG,SAASgB,CAAO,EAEvB,YAAY,EACfF,EAAQ,YAAc,IACxBR,EAAU,cAAcU,EAASC,EAAUH,CAAO,EAGpDR,EAAU,SAASU,EAASC,EAAU,CACpC,UAAWH,EAAQ,SACrB,CAAC,CAEL,CACF,OAASF,EAAO,CACd,MAAIA,aAAiBF,EACbE,EAEF,IAAIF,EAAU,uCAAUS,CAAM,CACtC,CACF,CAKA,OAAO,gBACLV,EACAK,EAAmC,CAAC,EAC9B,CACN,GAAI,CACER,EAAU,OAAOG,CAAO,GAC1BT,EAAG,OAAOS,EAAS,CACjB,UAAWK,EAAQ,WAAa,GAChC,MAAO,EACT,CAAC,CAEL,MAAgB,CACd,MAAM,IAAIJ,EAAU,uCAAUD,CAAO,CACvC,CACF,CAKA,OAAO,YAAYD,EAMjB,CACA,GAAI,CACF,GAAI,CAACF,EAAU,OAAOE,CAAQ,EAC5B,MAAME,EAAU,SAASF,CAAQ,EAGnC,IAAMc,EAAQtB,EAAG,SAASQ,CAAQ,EAClC,MAAO,CACL,KAAMc,EAAM,KACZ,OAAQA,EAAM,OAAO,EACrB,YAAaA,EAAM,YAAY,EAC/B,MAAOA,EAAM,MACb,MAAOA,EAAM,KACf,CACF,OAASV,EAAO,CACd,MAAIA,aAAiBF,EACbE,EAEF,IAAIF,EAAU,mDAAYF,CAAQ,CAC1C,CACF,CAKA,OAAO,cACLC,EACAK,EAGI,CAAC,EACK,CACV,GAAI,CACF,GAAI,CAACR,EAAU,OAAOG,CAAO,EAC3B,MAAMC,EAAU,SAASD,CAAO,EAGlC,IAAMW,EAAQpB,EAAG,YAAYS,CAAO,EAChCc,EAAmB,CAAC,EAExB,QAAWF,KAAQD,EAAO,CAExB,GAAI,CAACN,EAAQ,eAAiBO,EAAK,WAAW,GAAG,EAC/C,SAGF,IAAMG,EAAWvB,EAAK,KAAKQ,EAASY,CAAI,EAIxC,GAHAE,EAAO,KAAKC,CAAQ,EAGhBV,EAAQ,WAAad,EAAG,SAASwB,CAAQ,EAAE,YAAY,EAAG,CAC5D,IAAMC,EAAWnB,EAAU,cAAckB,EAAUV,CAAO,EAC1DS,EAASA,EAAO,OAAOE,CAAQ,CACjC,CACF,CAEA,OAAOF,CACT,OAASX,EAAO,CACd,MAAIA,aAAiBF,EACbE,EAEF,IAAIF,EAAU,mDAAYD,CAAO,CACzC,CACF,CAKA,OAAO,eAAeiB,EAAS,WAAYC,EAAS,OAAgB,CAClE,IAAMC,EAAU,QAAQ,IAAI,QAAU,QAAQ,IAAI,MAAQ,OACpDC,EAAY,KAAK,IAAI,EACrBC,EAAS,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,CAAC,EAC/CC,EAAW,GAAGL,CAAM,GAAGG,CAAS,IAAIC,CAAM,GAAGH,CAAM,GACzD,OAAO1B,EAAK,KAAK2B,EAASG,CAAQ,CACpC,CAKA,OAAO,iBACLvB,EACAwB,EAAehC,EAAG,UAAU,KAAOA,EAAG,UAAU,KACvC,CACT,GAAI,CACF,OAAAA,EAAG,WAAWQ,EAAUwB,CAAI,EACrB,EACT,MAAQ,CACN,MAAO,EACT,CACF,CAKA,OAAO,aAAaxB,EAA0B,CAC5C,OAAOP,EAAK,QAAQO,CAAQ,EAAE,YAAY,CAC5C,CAKA,OAAO,YAAYA,EAA0B,CAC3C,OAAOP,EAAK,SAASO,EAAUP,EAAK,QAAQO,CAAQ,CAAC,CACvD,CAKA,OAAO,cAAcA,EAA0B,CAC7C,OAAOP,EAAK,UAAUO,CAAQ,CAChC,CAKA,OAAO,YAAYA,EAAkByB,EAA2B,CAC9D,OAAIA,EACKhC,EAAK,QAAQgC,EAAUzB,CAAQ,EAEjCP,EAAK,QAAQO,CAAQ,CAC9B,CACF,IC9TA,IAOa0B,GAPbC,GAAAC,EAAA,kBAOaF,GAAN,KAAkB,CAPzB,MAOyB,CAAAG,EAAA,oBAIvB,OAAO,aAAaC,EAAoB,CACtC,IAAMC,EAAU,KAAK,MAAMD,EAAK,GAAI,EAC9BE,EAAU,KAAK,MAAMD,EAAU,EAAE,EACjCE,EAAQ,KAAK,MAAMD,EAAU,EAAE,EAC/BE,EAAO,KAAK,MAAMD,EAAQ,EAAE,EAElC,OAAIC,EAAO,EACF,GAAGA,CAAI,UAAKD,EAAQ,EAAE,gBAAMD,EAAU,EAAE,eAE7CC,EAAQ,EACH,GAAGA,CAAK,gBAAMD,EAAU,EAAE,eAE/BA,EAAU,EACL,GAAGA,CAAO,gBAAMD,EAAU,EAAE,SAE9B,GAAGA,CAAO,QACnB,CAKA,OAAO,eAAeI,EAAuB,CAC3C,IAAMC,EAAQ,CAAC,IAAK,KAAM,KAAM,KAAM,IAAI,EACtCC,EAAOF,EACPG,EAAY,EAEhB,KAAOD,GAAQ,MAAQC,EAAYF,EAAM,OAAS,GAChDC,GAAQ,KACRC,IAGF,MAAO,GAAGD,EAAK,QAAQC,IAAc,EAAI,EAAI,CAAC,CAAC,IAAIF,EAAME,CAAS,CAAC,EACrE,CAKA,OAAO,gBACLC,EACAC,EAAmC,OAC3B,CACR,IAAMC,EAAO,IAAI,KAAKF,CAAS,EAE/B,OAAQC,EAAQ,CACd,IAAK,OACH,OAAOC,EAAK,mBAAmB,OAAO,EACxC,IAAK,OACH,OAAOA,EAAK,mBAAmB,OAAO,EACxC,QACE,OAAOA,EAAK,eAAe,OAAO,CACtC,CACF,CAKA,OAAO,UAAUC,EAAqB,CACpC,MAAO,QAAQA,CAAG,EACpB,CAKA,OAAO,WAAWC,EAAsB,CACtC,MAAO,iBAAOA,CAAI,EACpB,CAKA,OAAO,UACLC,EACAC,EACAF,EACAG,EACQ,CACR,IAAMC,EAAM,GAAGH,CAAQ,MAAMC,CAAI,IAAIF,CAAI,GACzC,OAAOG,EAAO,GAAGC,CAAG,GAAGD,CAAI,GAAKC,CAClC,CAKA,OAAO,iBAAiBC,EAAaC,EAAoB,CACvD,OAAI,OAAOA,GAAU,SACZ,GAAGD,CAAG,KAAK,KAAK,UAAUC,EAAO,KAAM,CAAC,CAAC,GAE3C,GAAGD,CAAG,KAAKC,CAAK,EACzB,CAKA,OAAO,YAAYC,EAAcC,EAAe,GAAe,CAC7D,IAAIC,EAAU,iBAAOF,EAAM,OAAO,GAElC,OAAIC,GAAgBD,EAAM,QACxBE,GAAW;AAAA;AAAA,EAAYF,EAAM,KAAK,IAG7BE,CACT,CAKA,OAAO,WAAWC,EAAiBC,EAAS,SAAa,CACvD,OAAOD,EAAM,IAAKE,GAAS,GAAGD,CAAM,IAAIC,CAAI,EAAE,EAAE,KAAK;AAAA,CAAI,CAC3D,CAKA,OAAO,YAAYC,EAAqC,CACtD,GAAIA,EAAK,SAAW,EAAG,MAAO,GAE9B,IAAMC,EAAO,OAAO,KAAKD,EAAK,CAAC,CAAC,EAC1BE,EAAYD,EAAK,IAAKT,GAC1B,KAAK,IAAIA,EAAI,OAAQ,GAAGQ,EAAK,IAAKG,GAAQ,OAAOA,EAAIX,CAAG,CAAC,EAAE,MAAM,CAAC,CACpE,EAGMY,EAASH,EAAK,IAAI,CAACT,EAAKa,IAAMb,EAAI,OAAOU,EAAUG,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,EAClEC,EAAYJ,EAAU,IAAKK,GAAU,IAAI,OAAOA,CAAK,CAAC,EAAE,KAAK,KAAK,EAGlEC,EAAOR,EAAK,IAAKG,GACrBF,EAAK,IAAI,CAACT,EAAKa,IAAM,OAAOF,EAAIX,CAAG,CAAC,EAAE,OAAOU,EAAUG,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,CACxE,EAEA,MAAO,CAACD,EAAQE,EAAW,GAAGE,CAAI,EAAE,KAAK;AAAA,CAAI,CAC/C,CAKA,OAAO,kBAAkBC,EAAiBC,EAAeH,EAAQ,GAAY,CAC3E,IAAMI,EAAa,KAAK,IAAIF,EAAUC,EAAO,CAAC,EACxCE,EAAS,KAAK,MAAMD,EAAaJ,CAAK,EACtCM,EAAQN,EAAQK,EAEhBE,EAAM,SAAI,OAAOF,CAAM,EAAI,SAAI,OAAOC,CAAK,EAC3CE,EAAU,KAAK,MAAMJ,EAAa,GAAG,EAE3C,MAAO,IAAIG,CAAG,KAAKC,CAAO,MAAMN,CAAO,IAAIC,CAAK,GAClD,CAKA,OAAO,kBAAkBM,EAAiBC,EAAwB,CAChE,IAAMC,EAAaD,EAAK,IAAKE,GAC3BA,EAAI,SAAS,GAAG,EAAI,IAAIA,CAAG,IAAMA,CACnC,EACA,MAAO,GAAGH,CAAO,IAAIE,EAAW,KAAK,GAAG,CAAC,EAC3C,CAKA,OAAO,aAAaE,EAAcC,EAAmBC,EAAS,MAAe,CAC3E,OAAIF,EAAK,QAAUC,EAAkBD,EAC9BA,EAAK,UAAU,EAAGC,EAAYC,EAAO,MAAM,EAAIA,CACxD,CAKA,OAAO,WAAWC,EAAUC,EAAS,EAAW,CAC9C,GAAI,CACF,OAAO,KAAK,UAAUD,EAAK,KAAMC,CAAM,CACzC,MAAgB,CACd,OAAO,OAAOD,CAAG,CACnB,CACF,CAKA,OAAO,cACL9B,EACAgC,EAAW,SACXC,EAAY,SACJ,CACR,OAAOjC,EAAQgC,EAAWC,CAC5B,CACF,ICjMA,OAAS,gBAAAC,OAAoB,KAC7B,OAAS,UAAAC,OAAc,KACvB,OAAOC,MAAU,OACjB,OAAS,iBAAAC,OAAqB,MAP9B,IAkBaC,EAlBbC,GAAAC,EAAA,kBAQAC,KAKAC,KAKaJ,EAAN,MAAMK,CAAU,CAlBvB,MAkBuB,CAAAC,EAAA,kBAIrB,OAAO,YAAqB,CAE1B,IAAMC,EACJ,QAAQ,IAAIC,GAAiB,WAAW,GAAK,QAAQ,IAAI,EAC3D,OAAOV,EAAK,KAAKS,EAAW,IAAIE,GAAkB,IAAI,MAAM,CAC9D,CAKA,OAAO,WAAWC,EAA6B,CAC7C,IAAMC,EAAUD,GAAc,QAAQ,IAAI,EAC1C,OAAOZ,EAAK,KAAKa,EAASF,GAAkB,QAAQ,CACtD,CAKA,OAAO,cAAuB,CAC5B,OAAO,QAAQ,IAAID,GAAiB,WAAW,GAAK,QAAQ,IAAI,CAClE,CAKA,OAAO,YAAqB,CAC1B,IAAMD,EAAYF,EAAU,aAAa,EACzC,OAAOP,EAAK,KAAKS,EAAWK,GAAe,QAAQ,CACrD,CAKA,OAAO,iBAA4B,CAEjC,IAAMC,EAAad,GAAc,YAAY,GAAG,EAC1Ce,EAAYhB,EAAK,QAAQe,CAAU,EAEzC,MAAO,CAELf,EAAK,KAAKgB,EAAWF,GAAe,aAAa,EAEjDd,EAAK,KAAKgB,EAAW,KAAM,KAAM,KAAMF,GAAe,aAAa,EAEnEd,EAAK,KACHgB,EACA,KACA,KACA,KACA,KACAF,GAAe,aACjB,CACF,CACF,CAKA,OAAO,kBAAkC,CACvC,IAAMG,EAAgBV,EAAU,gBAAgB,EAEhD,QAAWW,KAAgBD,EACzB,GAAIE,EAAU,OAAOD,CAAY,EAC/B,OAAOA,EAIX,OAAO,IACT,CAKA,OAAO,gBAAgBE,EAAqC,CAC1D,IAAMF,EAAeX,EAAU,iBAAiB,EAChD,GAAI,CAACW,EACH,OAAO,KAGT,IAAMG,EAAerB,EAAK,KAAKkB,EAAcE,CAAY,EACzD,OAAOD,EAAU,OAAOE,CAAY,EAAIA,EAAe,IACzD,CAKA,OAAO,cAAuB,CAC5B,IAAMN,EAAad,GAAc,YAAY,GAAG,EAChD,OAAOD,EAAK,QAAQe,CAAU,CAChC,CAKA,OAAO,gBAAyB,CAC9B,IAAMC,EAAYT,EAAU,aAAa,EAEzC,OAAOP,EAAK,KAAKgB,EAAW,KAAM,KAAM,IAAI,CAC9C,CAKA,OAAO,YAAqB,CAC1B,IAAMM,EAAcf,EAAU,eAAe,EAC7C,OAAOP,EAAK,KAAKsB,EAAa,MAAM,CACtC,CAKA,OAAO,gBAAgBC,EAA0B,CAC/C,IAAMD,EAAcf,EAAU,eAAe,EAC7C,OAAOP,EAAK,SAASsB,EAAaC,CAAQ,CAC5C,CAKA,OAAO,kBAAkBC,EAA6C,CACpE,IAAMf,EAAYF,EAAU,aAAa,EAEzC,GAAIiB,EACF,OAAOxB,EAAK,KAAKS,EAAW,kBAAkBe,CAAM,EAAE,EAIxD,QAAWC,KAAYf,GAAiB,WAAY,CAClD,IAAMa,EAAWvB,EAAK,KAAKS,EAAWgB,CAAQ,EAC9C,GAAIN,EAAU,OAAOI,CAAQ,EAC3B,OAAOA,CAEX,CAGA,OAAOvB,EAAK,KAAKS,EAAWC,GAAiB,WAAW,CAAC,CAAC,CAC5D,CAKA,OAAO,sBAA+B,CACpC,IAAMY,EAAcf,EAAU,eAAe,EAC7C,OAAOP,EAAK,KAAKsB,EAAaZ,GAAiB,YAAY,CAC7D,CAKA,OAAO,aAAagB,EAA4B,CAE9C,MAAO,CADgB1B,EAAK,UAAU0B,CAAS,EACxB,SAAS,IAAI,CACtC,CAKA,OAAO,iBAAiBA,EAAmBb,EAAyB,CAClE,IAAMc,EAAe3B,EAAK,QAAQa,EAASa,CAAS,EAC9CE,EAAe5B,EAAK,QAAQa,CAAO,EAEzC,GAAI,CAACc,EAAa,WAAWC,CAAY,EACvC,MAAM,IAAI,MAAM,gBAAMF,CAAS,mDAAW,EAG5C,OAAOC,CACT,CAKA,OAAO,kBAAkBE,EAAsB,CAE7C,IAAMC,EAAU,QAAQ,KAAK,CAAC,EAG9B,GAAI,CAACA,EAEH,OAAO9B,EAAK,KAAK,QAAQ,IAAI,EAAG,GAAG6B,CAAI,KAAK,EAI9C,IAAIE,EACJ,GAAI,CACFA,EAAcjC,GAAagC,CAAO,CACpC,MAAgB,CAEdC,EAAcD,CAChB,CAGA,IAAME,EAAUhC,EAAK,QAAQ+B,CAAW,EACxC,OAAO/B,EAAK,KAAKgC,EAAS,GAAGH,CAAI,KAAK,CACxC,CAKA,OAAO,uBAAgC,CACrC,OAAOtB,EAAU,kBAAkB,gBAAgB,CACrD,CAKA,OAAO,4BAAqC,CAC1C,OAAOA,EAAU,kBAAkB,qBAAqB,CAC1D,CAKA,OAAO,kBAAkB0B,EAA4B,CACnD,IAAMC,EAAalC,EAAK,KAAK,GAAGiC,CAAQ,EAClCE,EAAiBnC,EAAK,UAAUkC,CAAU,EAGhD,GAAIC,EAAe,SAAS,IAAI,GAAKA,EAAe,SAAS,GAAG,EAC9D,MAAM,IAAI,MAAM,yCAAWA,CAAc,EAAE,EAG7C,OAAOA,CACT,CAKA,OAAO,YAAqB,CAE1B,OAAO,QAAQ,IAAI,QAAU,QAAQ,IAAI,MAAQpC,GAAO,CAC1D,CAKA,OAAO,YAAqB,CAC1B,OAAO,QAAQ,IAAI,MAAQ,QAAQ,IAAI,aAAe,EACxD,CACF,IChQA,OAAS,YAAAqC,OAAgB,gBAJzB,IAYaC,EAZbC,GAAAC,EAAA,kBAKAC,KAEAC,IAKaJ,EAAN,MAAMK,CAAc,CAZ3B,MAY2B,CAAAC,EAAA,sBAIzB,OAAO,oBAA+B,CACpC,OAAO,QAAQ,QACjB,CAKA,OAAO,WAAqB,CAC1B,OAAO,QAAQ,WAAa,OAC9B,CAKA,OAAO,SAAmB,CACxB,OAAO,QAAQ,WAAa,QAC9B,CAKA,OAAO,SAAmB,CACxB,OAAO,QAAQ,WAAa,OAC9B,CAKA,OAAO,YAAsB,CAC3B,MAAO,CAACD,EAAc,UAAU,CAClC,CAKA,OAAO,iBAAiBE,EAAsB,CAC5C,GAAI,CAEF,GACE,QAAQ,IAAI,oBAAsB,QAClC,QAAQ,IAAI,WAAa,OAIzB,eAAQ,KAAKA,EAAK,CAAC,EACZ,GAIT,GAAI,CACF,IAAIC,EAAU,GACd,OAAIH,EAAc,UAAU,EAM1BG,EAJeT,GAAS,wBAAwBQ,CAAG,gBAAiB,CAClE,SAAU,OACV,QAASE,GAAkB,YAC7B,CAAC,EACgB,YAAY,EAO7BD,EAJeT,GAAS,SAASQ,CAAG,YAAa,CAC/C,SAAU,OACV,QAASE,GAAkB,YAC7B,CAAC,EACgB,YAAY,EAIxBD,EAAQ,SAAS,MAAM,GAAKA,EAAQ,SAAS,SAAS,CAC/D,MAAgB,CAEd,eAAQ,KAAKD,EAAK,CAAC,EACZ,EACT,CACF,MAAgB,CACd,MAAO,EACT,CACF,CAKA,aAAa,YACXA,EACAG,EAAyB,UACV,CACf,GAAI,CACF,QAAQ,KAAKH,EAAKG,CAAM,EAGxB,IAAIC,EAAW,EACTC,EAAc,GAEpB,KAAOD,EAAWC,GAAa,CAC7B,MAAM,IAAI,QAASC,GAAY,WAAWA,EAAS,GAAG,CAAC,EAEvD,GAAI,CACF,QAAQ,KAAKN,EAAK,CAAC,EACnBI,GACF,MAAQ,CAEN,MACF,CACF,CAGA,GAAI,CACF,QAAQ,KAAKJ,EAAK,CAAC,EACnB,QAAQ,KAAKA,EAAK,SAAS,EAC3B,MAAM,IAAI,QAASM,GAAY,WAAWA,EAAS,GAAG,CAAC,CACzD,MAAQ,CAER,CACF,OAASC,EAAO,CACd,MAAM,IAAIC,EACR,yCAAWD,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,GACjEP,CACF,CACF,CACF,CAKA,OAAO,cAAcA,EAAsB,CACzC,GAAI,CACF,eAAQ,KAAKA,EAAK,CAAC,EACZ,EACT,MAAQ,CACN,MAAO,EACT,CACF,CAKA,OAAO,eAKL,CACA,MAAO,CACL,SAAUF,EAAc,mBAAmB,EAC3C,KAAM,QAAQ,KACd,YAAa,QAAQ,QACrB,YAAa,QAAQ,IAAI,oBAAsB,MACjD,CACF,CAKA,OAAO,UAAUW,EAAcC,EAA2C,CACxE,OAAO,QAAQ,IAAID,CAAI,GAAKC,CAC9B,CAKA,OAAO,UAAUD,EAAcE,EAAqB,CAClD,QAAQ,IAAIF,CAAI,EAAIE,CACtB,CAKA,OAAO,wBAAkC,CACvC,OAAO,QAAQ,IAAI,oBAAsB,MAC3C,CAKA,OAAO,mBAA6B,CAClC,OAAO,QAAQ,IAAI,WAAa,MAClC,CAKA,OAAO,0BAAoC,CACzC,OAAO,QAAQ,IAAI,WAAa,aAClC,CAKA,OAAO,eAAeC,EAAuD,CAC3E,OAAId,EAAc,UAAU,EACnB,CACL,QAAS,aACT,KAAM,CAAC,WAAY,sBAAsBc,CAAQ,SAAS,CAC5D,EAEK,CACL,QAAS,OACT,KAAM,CAAC,KAAMA,CAAQ,CACvB,CACF,CACF,ICxNA,IAUaC,EAVbC,GAAAC,EAAA,kBAKAC,IAKaH,EAAN,MAAMI,CAAW,CAVxB,MAUwB,CAAAC,EAAA,mBAItB,OAAO,aAAaC,EAAoB,CACtC,GAAI,CAAC,OAAO,UAAUA,CAAI,GAAKA,EAAO,GAAKA,EAAO,MAChD,MAAMC,EAAgB,YAAYD,CAAI,CAE1C,CAKA,OAAO,qBAAqBE,EAA8B,CACxD,IAAMC,EAA+B,CAAC,OAAQ,QAAS,OAAO,EAE9D,GAAI,CAACA,EAAa,SAASD,CAAsB,EAC/C,MAAM,IAAID,EACR,2DAAcC,CAAM,yCAAWC,EAAa,KAAK,IAAI,CAAC,GACtD,QACF,EAGF,OAAOD,CACT,CAKA,OAAO,iBAAiBE,EAAYC,EAAyB,CAC3D,GAA2BD,GAAU,MAAQA,IAAU,GACrD,MAAMH,EAAgB,cAAcI,CAAS,CAEjD,CAKA,OAAO,qBACLD,EACAC,EACAC,EAA0C,CAAC,EACrC,CACN,GAAIA,EAAQ,MAAQ,QAAaF,EAAM,OAASE,EAAQ,IACtD,MAAM,IAAIL,EACR,wCAAUK,EAAQ,GAAG,sDAAcF,EAAM,MAAM,GAC/CC,CACF,EAGF,GAAIC,EAAQ,MAAQ,QAAaF,EAAM,OAASE,EAAQ,IACtD,MAAM,IAAIL,EACR,wCAAUK,EAAQ,GAAG,sDAAcF,EAAM,MAAM,GAC/CC,CACF,CAEJ,CAKA,OAAO,YAAYE,EAAaF,EAAY,MAAa,CACvD,GAAI,CACF,IAAI,IAAIE,CAAG,CACb,MAAQ,CACN,MAAM,IAAIN,EAAgB,wCAAeM,CAAG,GAAIF,CAAS,CAC3D,CACF,CAKA,OAAO,qBAAqBE,EAAaF,EAAY,gBAAuB,CAC1EP,EAAW,YAAYS,EAAKF,CAAS,EAErC,IAAMG,EAAY,IAAI,IAAID,CAAG,EAC7B,GAAI,CAAC,CAAC,MAAO,MAAM,EAAE,SAASC,EAAU,QAAQ,EAC9C,MAAM,IAAIP,EACR,0GAA8CO,EAAU,QAAQ,GAChEH,CACF,CAEJ,CAKA,OAAO,gBAAgBE,EAAaF,EAAY,WAAkB,CAChEP,EAAW,YAAYS,EAAKF,CAAS,EAErC,IAAMG,EAAY,IAAI,IAAID,CAAG,EAC7B,GAAI,CAAC,CAAC,QAAS,QAAQ,EAAE,SAASC,EAAU,QAAQ,EAClD,MAAM,IAAIP,EACR,yGAA6CO,EAAU,QAAQ,GAC/DH,CACF,CAEJ,CAKA,OAAO,oBAAoBI,EAAoB,CAC7CX,EAAW,iBAAiBW,EAAM,aAAa,EAC/CX,EAAW,qBAAqBW,EAAM,cAAe,CAAE,IAAK,EAAG,IAAK,GAAI,CAAC,EAGzE,IAAMC,EAAe,eACfC,EAAkBF,EACrB,MAAM,EAAE,EACR,KAAMG,GAASA,EAAK,WAAW,CAAC,EAAI,EAAE,EAEzC,GAAIF,EAAa,KAAKD,CAAI,GAAKE,EAC7B,MAAM,IAAIV,EACR,oIACA,aACF,EAIF,GAAIQ,EAAK,WAAW,GAAG,EACrB,MAAM,IAAIR,EAAgB,+DAAc,aAAa,CAEzD,CAKA,OAAO,qBAAqBQ,EAAoB,CAM9C,GALAX,EAAW,iBAAiBW,EAAM,cAAc,EAChDX,EAAW,qBAAqBW,EAAM,eAAgB,CAAE,IAAK,EAAG,IAAK,EAAG,CAAC,EAIrE,CADiB,mBACH,KAAKA,CAAI,EACzB,MAAM,IAAIR,EACR,iIACA,cACF,CAEJ,CAKA,OAAO,mBAAmBQ,EAAoB,CAK5C,GAJAX,EAAW,iBAAiBW,EAAM,YAAY,EAI1C,CADiB,qBACH,KAAKA,CAAI,EACzB,MAAM,IAAIR,EACR,uLACA,YACF,CAEJ,CAKA,OAAO,aAAaY,EAAoBR,EAAY,OAAa,CAC/D,GAAI,CACF,OAAO,KAAK,MAAMQ,CAAU,CAC9B,OAASC,EAAO,CACd,MAAM,IAAIb,EACR,yCAAgBa,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,GACtET,CACF,CACF,CACF,CAKA,OAAO,oBACLD,EACAC,EACAC,EAA0C,CAAC,EACrC,CACN,GAAIA,EAAQ,MAAQ,QAAaF,EAAQE,EAAQ,IAC/C,MAAM,IAAIL,EACR,kCAASK,EAAQ,GAAG,6BAASF,CAAK,GAClCC,CACF,EAGF,GAAIC,EAAQ,MAAQ,QAAaF,EAAQE,EAAQ,IAC/C,MAAM,IAAIL,EACR,kCAASK,EAAQ,GAAG,6BAASF,CAAK,GAClCC,CACF,CAEJ,CAKA,OAAO,oBACLU,EACAV,EACAC,EAA0C,CAAC,EACrC,CACN,GAAIA,EAAQ,MAAQ,QAAaS,EAAM,OAAST,EAAQ,IACtD,MAAM,IAAIL,EACR,oDAAYK,EAAQ,GAAG,mCAAUS,EAAM,MAAM,GAC7CV,CACF,EAGF,GAAIC,EAAQ,MAAQ,QAAaS,EAAM,OAAST,EAAQ,IACtD,MAAM,IAAIL,EACR,oDAAYK,EAAQ,GAAG,mCAAUS,EAAM,MAAM,GAC7CV,CACF,CAEJ,CAKA,OAAO,yBACLW,EACAC,EACAZ,EAAY,SACN,CACN,QAAWa,KAAQD,EACjB,GAAI,EAAEC,KAAQF,GACZ,MAAM,IAAIf,EAAgB,+CAAYiB,CAAI,GAAIb,CAAS,CAG7D,CAKA,OAAO,aACLD,EACAe,EACAd,EACG,CACH,GAAI,CAACc,EAAY,SAASf,CAAU,EAClC,MAAM,IAAIH,EACR,6BAASG,CAAK,6BAASe,EAAY,KAAK,IAAI,CAAC,GAC7Cd,CACF,EAEF,OAAOD,CACT,CAKA,OAAO,cAAcgB,EAAiBf,EAAY,QAAiB,CACjE,GAAI,CACF,OAAO,IAAI,OAAOe,CAAO,CAC3B,OAASN,EAAO,CACd,MAAM,IAAIb,EACR,qDAAaa,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,GACnET,CACF,CACF,CACF,CACF,IC7QA,OAAOgB,OAAQ,KACf,OAAOC,MAAU,OACjB,OAAS,iBAAAC,OAAqB,MAN9B,IAsBaC,GAtBbC,GAAAC,EAAA,kBAOAC,IAeaH,GAAN,MAAMI,CAAa,CAtB1B,MAsB0B,CAAAC,EAAA,qBACxB,OAAe,cAA+B,KAK9C,OAAO,YAAqB,CAC1B,GAAID,EAAa,cACf,OAAOA,EAAa,cAGtB,GAAI,CAEF,IAAME,EAAaP,GAAc,YAAY,GAAG,EAC1CQ,EAAaT,EAAK,QAAQQ,CAAU,EAGpCE,EAAgB,CAEpBV,EAAK,KAAKS,EAAY,cAAc,EAEpCT,EAAK,KAAKS,EAAY,KAAM,cAAc,EAE1CT,EAAK,KAAKS,EAAY,KAAM,KAAM,KAAM,cAAc,EAEtDT,EAAK,KAAKS,EAAY,KAAM,KAAM,KAAM,KAAM,cAAc,CAC9D,EAEA,QAAWE,KAAeD,EACxB,GAAIX,GAAG,WAAWY,CAAW,EAAG,CAC9B,IAAMC,EAAc,KAAK,MAAMb,GAAG,aAAaY,EAAa,MAAM,CAAC,EACnE,GAAIC,EAAY,QACd,OAAAN,EAAa,cAAgBM,EAAY,QAClCA,EAAY,OAEvB,CAIF,OAAAN,EAAa,cAAgB,UACtB,SACT,OAASO,EAAO,CACd,eAAQ,KAAK,wEAA4BA,CAAK,EAC9CP,EAAa,cAAgB,UACtB,SACT,CACF,CAKA,OAAO,gBAA8B,CACnC,GAAI,CACF,IAAME,EAAaP,GAAc,YAAY,GAAG,EAC1CQ,EAAaT,EAAK,QAAQQ,CAAU,EAEpCE,EAAgB,CAEpBV,EAAK,KAAKS,EAAY,cAAc,EAEpCT,EAAK,KAAKS,EAAY,KAAM,cAAc,EAE1CT,EAAK,KAAKS,EAAY,KAAM,KAAM,KAAM,cAAc,EAEtDT,EAAK,KAAKS,EAAY,KAAM,KAAM,KAAM,KAAM,cAAc,CAC9D,EAEA,QAAWE,KAAeD,EACxB,GAAIX,GAAG,WAAWY,CAAW,EAAG,CAC9B,IAAMC,EAAc,KAAK,MAAMb,GAAG,aAAaY,EAAa,MAAM,CAAC,EACnE,MAAO,CACL,QAASC,EAAY,SAAW,UAChC,KAAMA,EAAY,KAClB,YAAaA,EAAY,YACzB,OAAQA,EAAY,MACtB,CACF,CAGF,MAAO,CAAE,QAAS,SAAU,CAC9B,MAAgB,CACd,MAAM,IAAIE,EAAU,mDAAY,cAAc,CAChD,CACF,CAKA,OAAO,gBAAgBC,EAAkBC,EAA0B,CACjE,IAAMC,EAAUF,EAAS,MAAM,GAAG,EAAE,IAAI,MAAM,EACxCG,EAAUF,EAAS,MAAM,GAAG,EAAE,IAAI,MAAM,EACxCG,EAAY,KAAK,IAAIF,EAAQ,OAAQC,EAAQ,MAAM,EAEzD,QAASE,EAAI,EAAGA,EAAID,EAAWC,IAAK,CAClC,IAAMC,EAASJ,EAAQG,CAAC,GAAK,EACvBE,EAASJ,EAAQE,CAAC,GAAK,EAE7B,GAAIC,EAASC,EAAQ,MAAO,GAC5B,GAAID,EAASC,EAAQ,MAAO,EAC9B,CAEA,MAAO,EACT,CAKA,OAAO,eAAeC,EAA0B,CAE9C,MADqB,oCACD,KAAKA,CAAO,CAClC,CAKA,OAAO,YAAmB,CACxBjB,EAAa,cAAgB,IAC/B,CACF,IC5IA,IAAAkB,GAAA,GAAAC,EAAAD,GAAA,wBAAAE,KAAA,IA4BaA,GA5BbC,GAAAC,EAAA,kBAMAC,IAKAC,KACAC,KACAC,KACAC,KAcaP,GAAN,KAAoD,CA5B3D,MA4B2D,CAAAQ,EAAA,2BAIjD,gBAAyB,CAC/B,OAAOC,EAAU,WAAW,CAC9B,CAKQ,aAAkC,CACxC,GAAI,CACF,IAAMC,EAAc,KAAK,eAAe,EAExC,GAAI,CAACC,EAAU,OAAOD,CAAW,EAC/B,OAAO,KAGT,IAAME,EAAaD,EAAU,SAASD,CAAW,EAAE,KAAK,EAClD,CAACG,EAAQC,EAAcC,CAAI,EAAIH,EAAW,MAAM,GAAG,EAEnDI,EAAM,OAAO,SAASH,CAAM,EAC5BI,EAAY,OAAO,SAASH,CAAY,EAE9C,OAAI,OAAO,MAAME,CAAG,GAAK,OAAO,MAAMC,CAAS,GAE7C,KAAK,eAAe,EACb,MAGF,CACL,IAAAD,EACA,UAAAC,EACA,KAAOF,GAAoC,YAC7C,CACF,MAAgB,CAEd,YAAK,eAAe,EACb,IACT,CACF,CAKQ,aAAaC,EAAaD,EAAqC,CACrE,GAAI,CACF,IAAMG,EAAU,GAAGF,CAAG,IAAI,KAAK,IAAI,CAAC,IAAID,CAAI,GACtCL,EAAc,KAAK,eAAe,EACxCC,EAAU,UAAUD,EAAaQ,EAAS,CAAE,UAAW,EAAK,CAAC,CAC/D,MAAgB,CACd,MAAM,IAAIC,EAAU,4CAAe,KAAK,eAAe,CAAC,CAC1D,CACF,CAKA,iBAAiBH,EAAsB,CACrC,OAAOI,EAAc,iBAAiBJ,CAAG,CAC3C,CAKA,kBAAkC,CAChC,GAAI,CACF,IAAME,EAAU,KAAK,YAAY,EAEjC,GAAI,CAACA,EACH,MAAO,CAAE,QAAS,EAAM,EAI1B,GAAI,CAAC,KAAK,iBAAiBA,EAAQ,GAAG,EAEpC,YAAK,eAAe,EACb,CAAE,QAAS,EAAM,EAI1B,IAAMG,EAASC,GAAY,aAAa,KAAK,IAAI,EAAIJ,EAAQ,SAAS,EAEtE,MAAO,CACL,QAAS,GACT,IAAKA,EAAQ,IACb,OAAAG,EACA,KAAMH,EAAQ,IAChB,CACF,MAAgB,CACd,MAAO,CAAE,QAAS,EAAM,CAC1B,CACF,CAKA,YAAYF,EAAaD,EAAqC,CAC5D,KAAK,aAAaC,EAAKD,CAAI,CAC7B,CAKA,MAAM,YAAYC,EAA4B,CAC5C,GAAI,CACF,MAAMI,EAAc,YAAYJ,CAAG,CACrC,OAASO,EAAO,CACd,MAAM,IAAIC,EACR,yCAAWD,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,GACjEP,CACF,CACF,CACF,CAKA,MAAM,oBAAoBA,EAA4B,CACpD,GAAI,CAEF,QAAQ,KAAKA,EAAK,SAAS,EAG3B,IAAIS,EAAW,EACTC,EAAc,GAEpB,KAAOD,EAAWC,GAAa,CAC7B,MAAM,IAAI,QAASC,GAAY,WAAWA,EAAS,GAAG,CAAC,EAEvD,GAAI,CACF,QAAQ,KAAKX,EAAK,CAAC,EACnBS,GACF,MAAQ,CAEN,MACF,CACF,CAGA,GAAI,CACF,QAAQ,KAAKT,EAAK,CAAC,EACnB,QAAQ,KAAKA,EAAK,SAAS,EAC3B,MAAM,IAAI,QAASW,GAAY,WAAWA,EAAS,GAAG,CAAC,CACzD,MAAQ,CAER,CACF,OAASJ,EAAO,CACd,MAAM,IAAIC,EACR,yCAAWD,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,GACjEP,CACF,CACF,CACF,CAKA,gBAAuB,CACrB,GAAI,CACF,IAAMN,EAAc,KAAK,eAAe,EACpCC,EAAU,OAAOD,CAAW,GAC9BC,EAAU,WAAWD,CAAW,CAEpC,OAASa,EAAO,CAEd,QAAQ,KAAK,6CAAgBA,CAAK,CACpC,CACF,CAKA,cAAcP,EAAsB,CAClC,OAAOI,EAAc,cAAcJ,CAAG,CACxC,CAKA,uBAA8B,CAC5B,GAAII,EAAc,uBAAuB,EACvC,GAAI,CACF,KAAK,eAAe,CACtB,MAAgB,CAEhB,CAEJ,CAKA,eAAeJ,EAAsD,CACnE,IAAMY,EAAS,KAAK,cAAcZ,CAAG,EAC/Ba,EAAYD,EAAS,KAAK,iBAAiBZ,CAAG,EAAI,GAExD,MAAO,CAAE,OAAAY,EAAQ,UAAAC,CAAU,CAC7B,CAKA,iBAA2B,CACzB,GAAI,CAEF,OADgB,KAAK,YAAY,IACd,IACrB,MAAQ,CACN,MAAO,EACT,CACF,CACF,IChPA,IAAAC,GAAA,GAAAC,EAAAD,GAAA,uBAAAE,KAIA,OAA4B,SAAAC,OAAa,gBACzC,OAAOC,OAAQ,KALf,IA+BaF,GA/BbG,GAAAC,EAAA,kBAMAC,IAKAC,KACAC,KAmBaP,GAAN,KAAkD,CAGvD,YACUQ,EACAC,EACR,CAFQ,oBAAAD,EACA,YAAAC,CACP,CArCL,MA+ByD,CAAAC,EAAA,0BAC/C,cAAqC,KAU7C,MAAM,YACJC,EACAC,EAAyB,CAAC,EACX,CACf,GAAI,CAEF,IAAMC,EAAS,KAAK,eAAe,iBAAiB,EACpD,GAAIA,EAAO,QACT,MAAMC,EAAa,eAAeD,EAAO,GAAI,EAI/C,IAAME,EAAQ,MAAM,KAAK,mBAAmBJ,EAAeC,CAAO,EAClE,KAAK,cAAgBG,EAGrB,KAAK,eAAe,YAAYA,EAAM,IAAM,QAAQ,EAGpD,MAAM,KAAK,aAAaA,EAAOH,EAAQ,aAAe,aAAa,EAGnE,KAAK,mBAAmBG,CAAK,EAG7BA,EAAM,MAAM,EAEZ,KAAK,OAAO,KAAK,oDAAiBA,EAAM,GAAG,GAAG,CAChD,OAASC,EAAO,CACd,MAAM,IAAIF,EACR,qDAAaE,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACrE,CACF,CACF,CAKA,MAAM,YAA4B,CAChC,GAAI,CACF,IAAMH,EAAS,KAAK,eAAe,iBAAiB,EAEpD,GAAI,CAACA,EAAO,QACV,MAAMC,EAAa,WAAW,EAIhC,MAAM,KAAK,eAAe,oBAAoBD,EAAO,GAAI,EAGzD,KAAK,eAAe,eAAe,EAGnC,KAAK,cAAgB,KAErB,KAAK,OAAO,KAAK,4CAAS,CAC5B,OAASG,EAAO,CACd,MAAM,IAAIF,EACR,qDAAaE,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACrE,CACF,CACF,CAKA,MAAM,cACJL,EACAC,EAAyB,CAAC,EACX,CACf,GAAI,CAEa,KAAK,eAAe,iBAAiB,EACzC,UACT,MAAM,KAAK,WAAW,EAEtB,MAAM,IAAI,QAASK,GAAY,WAAWA,EAAS,GAAI,CAAC,GAI1D,MAAM,KAAK,YAAYN,EAAeC,CAAO,CAC/C,OAASI,EAAO,CACd,MAAM,IAAIF,EACR,qDAAaE,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACrE,CACF,CACF,CAKA,iBAAuE,CACrE,OAAO,KAAK,eAAe,iBAAiB,CAC9C,CAKA,MAAM,aAAaE,EAAc,cAA8B,CAC7D,GAAI,CACF,IAAMC,EAAcC,EAAU,WAAW,EAEzC,GAAI,CAAClB,GAAG,WAAWiB,CAAW,EAC5B,MAAM,IAAIL,EAAa,4CAAS,EAIlC,GAAM,CAAE,QAAAO,EAAS,KAAAC,CAAK,EAAIC,EAAc,eAAeJ,CAAW,EAC5DK,EAAOvB,GAAMoB,EAASC,EAAM,CAAE,MAAO,SAAU,CAAC,EAGtD,QAAQ,GAAG,SAAU,IAAM,CACzB,QAAQ,IAAI;AAAA,qFAAkB,EAC9BE,EAAK,KAAK,EACV,QAAQ,KAAK,CAAC,CAChB,CAAC,EAEDA,EAAK,GAAG,OAAQ,IAAM,CACpB,QAAQ,KAAK,CAAC,CAChB,CAAC,EAEDA,EAAK,GAAG,QAAUR,GAAU,CAC1B,MAAM,IAAIF,EAAa,yCAAWE,EAAM,OAAO,EAAE,CACnD,CAAC,CACH,OAASA,EAAO,CACd,MAAM,IAAIF,EACR,yCAAWE,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACnE,CACF,CACF,CAKA,MAAc,mBACZL,EACAC,EACuB,CAKvB,IAAMU,EAAO,CAHMF,EAAU,2BAA2B,CAGhC,EACpBR,EAAQ,aACVU,EAAK,KAAK,gBAAgB,EAI5B,IAAMG,EAAM,CACV,GAAG,QAAQ,IACX,mBAAoBL,EAAU,aAAa,EAC3C,eAAgB,OAChB,GAAGR,EAAQ,GACb,EAGMG,EAAQd,GAAM,OAAQqB,EAAM,CAChC,SAAU,GACV,MAAO,CAAC,SAAU,OAAQ,MAAM,EAChC,IAAAG,EACA,IAAKb,EAAQ,KAAO,QAAQ,IAAI,CAClC,CAAC,EAED,GAAI,CAACG,EAAM,IACT,MAAM,IAAIW,EAAa,mDAAY,CAAC,EAGtC,OAAOX,CACT,CAKA,MAAc,aACZA,EACAG,EACe,CACf,GAAI,CACF,IAAMC,EAAcC,EAAU,WAAW,EAInCO,GADO,KAAM,QAAO,MAAW,GACjB,QAAQR,CAAW,EAClCjB,GAAG,WAAWyB,CAAM,GACvBzB,GAAG,UAAUyB,EAAQ,CAAE,UAAW,EAAK,CAAC,EAI1C,IAAMC,EAAY1B,GAAG,kBAAkBiB,EAAa,CAAE,MAAO,GAAI,CAAC,EAGlEJ,EAAM,QAAQ,KAAKa,CAAS,EAC5Bb,EAAM,QAAQ,KAAKa,CAAS,EAG5B,IAAMC,EAAY,IAAI,KAAK,EAAE,YAAY,EACzCD,EAAU,MAAM;AAAA,GAAMC,CAAS,gDAAkBd,EAAM,GAAG;AAAA,CAAK,CACjE,OAASC,EAAO,CACd,KAAK,OAAO,KACV,2DAAcA,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACtE,CACF,CACF,CAKQ,mBAAmBD,EAA2B,CAEpDA,EAAM,GAAG,OAAQ,CAACe,EAAMC,IAAW,CAC7BD,IAAS,GAAKA,IAAS,KACzB,KAAK,OAAO,MAAM,mEAAiBA,CAAI,mBAASC,CAAM,GAAG,EAEzD,KAAK,OAAO,KAAK,kDAAU,EAI7B,KAAK,eAAe,eAAe,EACnC,KAAK,cAAgB,IACvB,CAAC,EAGDhB,EAAM,GAAG,QAAUC,GAAU,CAC3B,KAAK,OAAO,MAAM,yCAAWA,EAAM,OAAO,EAAE,EAC5C,KAAK,eAAe,eAAe,EACnC,KAAK,cAAgB,IACvB,CAAC,EAGDD,EAAM,GAAG,aAAc,IAAM,CAC3B,KAAK,OAAO,KAAK,kDAAU,CAC7B,CAAC,CACH,CAKA,MAAM,aAAgC,CACpC,GAAI,CACF,IAAMF,EAAS,KAAK,gBAAgB,EAEpC,GAAI,CAACA,EAAO,SAAW,CAACA,EAAO,IAC7B,MAAO,GAIT,IAAMmB,EAAc,KAAK,eAAe,eAAenB,EAAO,GAAG,EACjE,OAAOmB,EAAY,QAAUA,EAAY,SAC3C,MAAQ,CACN,MAAO,EACT,CACF,CAKA,kBAAwC,CACtC,OAAO,KAAK,aACd,CAKA,SAAgB,CACd,GAAI,KAAK,cAAe,CACtB,GAAI,CACF,KAAK,cAAc,KAAK,SAAS,CACnC,OAAShB,EAAO,CACd,KAAK,OAAO,KACV,qDAAaA,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACrE,CACF,CACA,KAAK,cAAgB,IACvB,CACF,CACF,IC7TA,IAoDsBiB,GApDtBC,GAAAC,EAAA,kBAMAC,IA8CsBH,GAAf,KAAgC,CApDvC,MAoDuC,CAAAI,EAAA,yBAC3B,OACA,eACA,aACA,OACA,MAAyB,eAEnC,YAAYC,EAAmCC,EAAyB,CACtE,KAAK,eAAiBD,EACtB,KAAK,OAASC,EACd,KAAK,aAAe,KAAK,qBAAqB,EAC9C,KAAK,OAASC,CAChB,CA8BA,MAAgB,sBAAsBC,EAAoC,CACxE,GAAI,CACF,KAAK,OAAO,MAAM,qDAAaA,EAAQ,MAAM,GAAIA,CAAO,EAExD,IAAMC,EAAW,MAAM,KAAK,eAAe,cAAcD,CAAO,EAEhE,KAAK,OAAO,MAAM,wCAAWC,CAAQ,EACrC,MAAM,KAAK,YAAYA,CAAQ,CACjC,OAASC,EAAO,CACd,KAAK,OAAO,MAAM,+CAAYF,EAAQ,MAAM,GAAIE,CAAK,EAErD,IAAMC,EAAgB,KAAK,oBACzBD,EACAF,EAAQ,EACV,EACA,MAAM,KAAK,YAAYG,CAAa,CACtC,CACF,CAMU,oBACRD,EACAE,EACa,CAEb,IAAIC,EAAY,OAEhB,OACEH,EAAM,QAAQ,SAAS,gCAAO,GAC9BA,EAAM,QAAQ,SAAS,gCAAO,EAE9BG,EAAY,QAEZH,EAAM,QAAQ,SAAS,cAAI,GAC3BA,EAAM,QAAQ,SAAS,0BAAM,KAE7BG,EAAY,QAGP,CACL,QAAS,MACT,MAAO,CACL,KAAMA,EACN,QAASH,EAAM,QACf,KAAM,CACJ,MAAOA,EAAM,KACf,CACF,EACA,GAAIE,GAAM,IACZ,CACF,CAKQ,sBAA+B,CACrC,IAAME,EAAY,KAAK,IAAI,EACrBC,EAAS,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,OAAO,EAAG,CAAC,EACrD,MAAO,GAAG,KAAK,OAAO,IAAI,IAAID,CAAS,IAAIC,CAAM,EACnD,CAKA,iBAA0B,CACxB,OAAO,KAAK,YACd,CAKA,UAA4B,CAC1B,OAAO,KAAK,KACd,CAKU,SAASC,EAA8B,CAC/C,IAAMC,EAAW,KAAK,MACtB,KAAK,MAAQD,EAETC,IAAaD,IACf,KAAK,OAAO,KAAK,yCAAWC,CAAQ,OAAOD,CAAK,EAAE,EAClD,KAAK,cAAcC,EAAUD,CAAK,EAEtC,CAMU,cACRC,EACAC,EACM,CAER,CAKA,WAA6B,CAC3B,MAAO,CAAE,GAAG,KAAK,MAAO,CAC1B,CAKA,mBAAuC,CACrC,OAAO,KAAK,cACd,CAMU,aAAaC,EAAiC,CACtD,GAAI,CACF,IAAMX,EAAU,KAAK,MAAMW,EAAK,KAAK,CAAC,EAGtC,MAAI,CAACX,EAAQ,SAAWA,EAAQ,UAAY,OAC1C,KAAK,OAAO,KAAK,iEAA0BA,CAAO,EAC3C,MAGJA,EAAQ,OAKNA,GAJL,KAAK,OAAO,KAAK,iEAAqBA,CAAO,EACtC,KAIX,OAASE,EAAO,CACd,YAAK,OAAO,MAAM,6CAAgB,CAAE,KAAAS,EAAM,MAAAT,CAAM,CAAC,EAC1C,IACT,CACF,CAMU,iBAAiBF,EAA2C,CACpE,GAAI,CACF,OAAO,KAAK,UAAUA,CAAO,CAC/B,OAASE,EAAO,CACd,KAAK,OAAO,MAAM,6CAAW,CAAE,QAAAF,EAAS,MAAAE,CAAM,CAAC,EAC/C,IAAMU,EACJV,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,EACvD,MAAM,IAAI,MAAM,+CAAYU,CAAY,EAAE,CAC5C,CACF,CAMU,gBAAgBZ,EAAuB,CAe/C,MAdI,GAACA,GAAW,OAAOA,GAAY,UAI/BA,EAAQ,UAAY,OAKpBA,EAAQ,QAAU,OAAOA,EAAQ,QAAW,UAK5C,CAACA,EAAQ,QAAU,CAACA,EAAQ,QAAU,CAACA,EAAQ,MAKrD,CAMU,qBACRa,EACAC,EACY,CACZ,OAAO,QAAQ,KAAK,CAClBD,EACA,IAAI,QAAW,CAACE,EAAGC,IAAW,CAC5B,WAAW,IAAM,CACfA,EAAO,IAAI,MAAM,6BAASF,CAAS,IAAI,CAAC,CAC1C,EAAGA,CAAS,CACd,CAAC,CACH,CAAC,CACH,CACF,IChSA,OAAS,cAAAG,OAAkB,SAE3B,OAAOC,OAAa,UARpB,IA4CaC,GA5CbC,GAAAC,EAAA,kBAWAC,KAiCaH,GAAN,cAA0BI,EAAiB,CA5ClD,MA4CkD,CAAAC,EAAA,oBACxC,IACA,OAAwB,KACxB,QAAkC,IAAI,IACtC,KACA,KACA,UACA,UACA,WACA,WAER,YACEC,EACAC,EAAqB,CAAE,KAAM,MAAO,EACpC,CACA,MAAMD,EAAgBC,CAAM,EAE5B,KAAK,KAAOA,EAAO,MAAQ,IAC3B,KAAK,KAAOA,EAAO,MAAQ,UAC3B,KAAK,UAAYA,EAAO,YAAc,GACtC,KAAK,UAAYA,EAAO,YAAc,GACtC,KAAK,WAAaA,EAAO,YAAc,IACvC,KAAK,WAAaA,EAAO,aAAe,OAAYA,EAAO,WAAa,IAExE,KAAK,IAAMR,GAAQ,EACnB,KAAK,gBAAgB,CACvB,CAKA,MAAM,YAA4B,CAChC,KAAK,OAAO,KAAK,4CAAc,EAE/B,GAAI,CACF,KAAK,YAAY,EACjB,KAAK,qBAAmC,EACxC,KAAK,OAAO,KAAK,uDAAe,CAClC,OAASS,EAAO,CACd,WAAK,OAAO,MAAM,wDAAiBA,CAAK,EACxC,KAAK,gBAA8B,EAC7BA,CACR,CACF,CAKA,MAAM,OAAuB,CAC3B,GAAI,KAAK,OAAQ,CACf,KAAK,OAAO,KAAK,iDAAc,EAC/B,MACF,CAEA,YAAK,OAAO,KAAK,8CAAgB,KAAK,IAAI,IAAI,KAAK,IAAI,EAAE,EAElD,IAAI,QAAQ,CAACC,EAASC,IAAW,CACtC,KAAK,OAAS,KAAK,IAAI,OAAO,KAAK,KAAM,KAAK,KAAM,IAAM,CACxD,KAAK,oBAAkC,EACvC,KAAK,OAAO,KAAK,iDAAc,EAC/B,KAAK,OAAO,KAAK,8BAAoB,KAAK,IAAI,IAAI,KAAK,IAAI,MAAM,EAC7D,KAAK,YACP,KAAK,OAAO,KAAK,8BAAoB,KAAK,IAAI,IAAI,KAAK,IAAI,MAAM,EACjE,KAAK,OAAO,KACV,sCAAkB,KAAK,IAAI,IAAI,KAAK,IAAI,WAC1C,GAEFD,EAAQ,CACV,CAAC,EAED,KAAK,QAAQ,GAAG,QAAUD,GAAU,CAClC,KAAK,OAAO,MAAM,sCAAcA,CAAK,EACrC,KAAK,gBAA8B,EACnCE,EAAOF,CAAK,CACd,CAAC,CACH,CAAC,CACH,CAKA,MAAM,MAAsB,CAC1B,GAAK,KAAK,OAIV,YAAK,OAAO,KAAK,sCAAa,EAEvB,IAAI,QAASC,GAAY,CAE9B,QAAWE,KAAU,KAAK,QAAQ,OAAO,EACvCA,EAAO,SAAS,IAAI,EAEtB,KAAK,QAAQ,MAAM,EAEnB,KAAK,OAAQ,MAAM,IAAM,CACvB,KAAK,OAAS,KACd,KAAK,uBAAqC,EAC1C,KAAK,OAAO,KAAK,2CAAa,EAC9BF,EAAQ,CACV,CAAC,CACH,CAAC,CACH,CAKA,MAAM,YAAYG,EAAkD,CAG9D,KAAK,QAAQ,KAAO,GACtB,KAAK,mBAAmBA,CAAO,CAEnC,CAKQ,iBAAwB,CAE9B,KAAK,IAAI,IAAIb,GAAQ,KAAK,CAAE,MAAO,MAAO,CAAC,CAAC,EAC5C,KAAK,IAAI,IAAIA,GAAQ,WAAW,CAAE,SAAU,EAAK,CAAC,CAAC,EAGnD,KAAK,IAAI,IAAI,CAACc,EAAKC,EAAKC,IAAS,CAC/BD,EAAI,OAAO,8BAA+B,KAAK,UAAU,EACzDA,EAAI,OAAO,+BAAgC,oBAAoB,EAC/DA,EAAI,OAAO,+BAAgC,sBAAsB,EACjEA,EAAI,OAAO,gBAAiB,UAAU,EACtCC,EAAK,CACP,CAAC,EAGD,KAAK,IAAI,IAAI,CAACF,EAAKC,EAAKC,IAAS,CAC/B,KAAK,OAAO,MAAM,GAAGF,EAAI,MAAM,IAAIA,EAAI,IAAI,GAAI,CAC7C,MAAOA,EAAI,MACX,QAASA,EAAI,OACf,CAAC,EACDE,EAAK,CACP,CAAC,CACH,CAKQ,aAAoB,CAEtB,KAAK,YACP,KAAK,IAAI,IAAI,OAAQ,KAAK,UAAU,KAAK,IAAI,CAAC,EAC9C,KAAK,IAAI,KAAK,YAAa,KAAK,eAAe,KAAK,IAAI,CAAC,GAIvD,KAAK,WACP,KAAK,IAAI,KAAK,OAAQ,KAAK,UAAU,KAAK,IAAI,CAAC,EAIjD,KAAK,IAAI,IAAI,UAAW,KAAK,aAAa,KAAK,IAAI,CAAC,EAGpD,KAAK,IAAI,IAAI,UAAW,KAAK,aAAa,KAAK,IAAI,CAAC,CACtD,CAKQ,UAAUF,EAAcC,EAAqB,CAEnD,GAAI,KAAK,QAAQ,MAAQ,KAAK,WAAY,CACxCA,EAAI,OAAO,GAAG,EAAE,KAAK,CACnB,MAAO,mGACP,WAAY,KAAK,UACnB,CAAC,EACD,MACF,CAEA,IAAME,EAAW,KAAK,IAAI,EAAE,SAAS,EAC/BC,EAAYnB,GAAW,EAG7BgB,EAAI,UAAU,eAAgB,mBAAmB,EACjDA,EAAI,UAAU,gBAAiB,wBAAwB,EACvDA,EAAI,UAAU,aAAc,YAAY,EACxCA,EAAI,UAAU,oBAAqB,IAAI,EAGvC,IAAMH,EAAoB,CACxB,GAAIK,EACJ,UAAAC,EACA,SAAUH,EACV,YAAa,IAAI,IACnB,EAEA,KAAK,QAAQ,IAAIG,EAAWN,CAAM,EAClC,KAAK,OAAO,KAAK,6CAAeK,CAAQ,mBAASC,CAAS,GAAG,EAG7DH,EAAI,MAAM;AAAA,4BAA8CG,CAAS;AAAA;AAAA,CAAM,EAGvEJ,EAAI,GAAG,QAAS,IAAM,CACpB,KAAK,QAAQ,OAAOI,CAAS,EAC7B,KAAK,OAAO,KACV,yDAAiBD,CAAQ,mBAASC,CAAS,GAC7C,CACF,CAAC,EAGDJ,EAAI,GAAG,QAAUL,GAAU,CACzB,KAAK,OAAO,MAAM,mDAAgBQ,CAAQ,GAAIR,CAAK,EACnD,KAAK,QAAQ,OAAOS,CAAS,CAC/B,CAAC,CACH,CAKA,MAAc,eAAeJ,EAAcC,EAA8B,CACvE,GAAI,CACF,IAAMG,EAAYJ,EAAI,MAAM,UACtBD,EAAUC,EAAI,KAIpB,GAFA,KAAK,OAAO,MAAM,gDAAkBI,CAAS,KAAML,CAAO,EAEtD,CAACK,GAAa,CAAC,KAAK,QAAQ,IAAIA,CAAS,EAAG,CAC9CH,EAAI,OAAO,GAAG,EAAE,KAAK,CACnB,QAAS,MACT,MAAO,CACL,KAAM,OACN,QAAS,0CACX,EACA,GAAIF,EAAQ,EACd,CAAC,EACD,MACF,CAGA,IAAMM,EAAW,MAAM,KAAK,eAAe,cAAcN,CAAO,EAChE,KAAK,OAAO,MAAM,4CAAeM,CAAQ,EAGzC,IAAMP,EAAS,KAAK,QAAQ,IAAIM,CAAS,EACrCN,GACF,KAAK,aAAaA,EAAQO,CAAQ,EAIpCJ,EAAI,OAAO,GAAG,EAAE,KAAK,CACvB,OAASN,EAAO,CACd,KAAK,OAAO,MAAM,kDAAgBA,CAAK,EACvCM,EAAI,OAAO,GAAG,EAAE,KAAK,CACnB,QAAS,MACT,MAAO,CACL,KAAM,OACN,QAAUN,EAAgB,OAC5B,CACF,CAAC,CACH,CACF,CAKA,MAAc,UAAUK,EAAcC,EAA8B,CAClE,GAAI,CACF,IAAMF,EAAUC,EAAI,KACpB,KAAK,OAAO,MAAM,iCAAcD,CAAO,EAGvC,IAAMM,EAAW,MAAM,KAAK,eAAe,cAAcN,CAAO,EAChEE,EAAI,KAAKI,CAAQ,CACnB,OAASV,EAAO,CACd,KAAK,OAAO,MAAM,kDAAgBA,CAAK,EACvCM,EAAI,OAAO,GAAG,EAAE,KAAK,CACnB,QAAS,MACT,MAAO,CACL,KAAM,OACN,QAAUN,EAAgB,OAC5B,EACA,GAAIK,EAAI,MAAM,IAAM,IACtB,CAAC,CACH,CACF,CAKQ,aAAaA,EAAcC,EAAqB,CACtDA,EAAI,KAAK,CACP,OAAQ,KACR,KAAM,aACN,eAAgB,UAChB,QAAS,KAAK,QAAQ,KACtB,MAAO,EACP,WAAY,KAAK,WACjB,UAAW,KAAK,UAChB,UAAW,KAAK,UAChB,OAAQ,QAAQ,OAAO,CACzB,CAAC,CACH,CAKQ,aAAaD,EAAcC,EAAqB,CACtDA,EAAI,KAAK,CACP,OAAQ,KACR,KAAM,aACN,UAAW,IAAI,KAAK,EAAE,YAAY,CACpC,CAAC,CACH,CAKQ,aACNH,EACAC,EACM,CACN,GAAI,CACF,IAAMO,EAAO,KAAK,iBAAiBP,CAAO,EAC1CD,EAAO,SAAS,MAAM,SAASQ,CAAI;AAAA;AAAA,CAAM,EAEzC,KAAK,OAAO,MAAM,0DAAaR,EAAO,EAAE,GAAI,CAC1C,UAAWA,EAAO,UAClB,UAAWC,EAAQ,EACrB,CAAC,CACH,OAASJ,EAAO,CACd,KAAK,OAAO,MAAM,4BAAQG,EAAO,EAAE,wCAAWH,CAAK,EAEnD,KAAK,QAAQ,OAAOG,EAAO,SAAS,CACtC,CACF,CAKQ,mBAAmBC,EAAyC,CAClE,QAAWD,KAAU,KAAK,QAAQ,OAAO,EACvC,KAAK,aAAaA,EAAQC,CAAO,CAErC,CAKA,WAUE,CACA,MAAO,CACL,UAAW,KAAK,SAAW,KAC3B,KAAM,KAAK,KACX,KAAM,KAAK,KACX,YAAa,KAAK,QAAQ,KAC1B,WAAY,KAAK,WACjB,UAAW,KAAK,UAChB,UAAW,KAAK,UAChB,aAAc,KAAK,aACnB,MAAO,KAAK,KACd,CACF,CAKA,YAIG,CACD,OAAO,MAAM,KAAK,KAAK,QAAQ,OAAO,CAAC,EAAE,IAAKD,IAAY,CACxD,GAAIA,EAAO,GACX,UAAWA,EAAO,UAClB,YAAaA,EAAO,WACtB,EAAE,CACJ,CACF,IC7aA,IAAAS,GAAAC,EAAA,kBAOAC,OCIA,OAAOC,IAAa,mBAAAC,OAAuB,KAX3C,IAAAC,GAAAC,EAAA,kBAaAC,OCbA,IAgDaC,GAhDbC,GAAAC,EAAA,kBAMAC,IA0CaH,GAAN,KAAwB,CAhD/B,MAgD+B,CAAAI,EAAA,0BACrB,OACA,eAER,YAAYC,EAAmC,CAC7C,KAAK,eAAiBA,EACtB,KAAK,OAASC,CAChB,CAOA,MAAM,cAAcC,EAA2C,CAC7D,KAAK,OAAO,MAAM,kCAAcA,EAAQ,MAAM,GAAIA,CAAO,EAEzD,GAAI,CACF,OAAQA,EAAQ,OAAQ,CACtB,IAAK,aACH,OAAO,MAAM,KAAK,iBAAiBA,EAAQ,OAAQA,EAAQ,EAAE,EAC/D,IAAK,aACH,OAAO,MAAM,KAAK,gBAAgBA,EAAQ,EAAE,EAC9C,IAAK,aACH,OAAO,MAAM,KAAK,eAAeA,EAAQ,OAAQA,EAAQ,EAAE,EAC7D,IAAK,OACH,OAAO,MAAM,KAAK,WAAWA,EAAQ,EAAE,EACzC,QACE,MAAM,IAAI,MAAM,mCAAUA,EAAQ,MAAM,EAAE,CAC9C,CACF,OAASC,EAAO,CACd,YAAK,OAAO,MAAM,+CAAYD,EAAQ,MAAM,GAAIC,CAAK,EAC9C,KAAK,oBAAoBA,EAAgBD,EAAQ,EAAE,CAC5D,CACF,CAQA,MAAc,iBACZE,EACAC,EACsB,CACtB,YAAK,OAAO,KAAK,uCAAoBD,CAAM,EAEpC,CACL,QAAS,MACT,OAAQ,CACN,WAAY,CACV,KAAM,qBACN,QAAS,OACX,EACA,aAAc,CACZ,MAAO,CAAC,EACR,QAAS,CAAC,CACZ,EACA,gBAAiB,YACnB,EACA,GAAIC,GAAM,IACZ,CACF,CAOA,MAAc,gBAAgBA,EAA4C,CACxE,KAAK,OAAO,KAAK,sCAAkB,EAEnC,GAAI,CAIF,IAAMC,EAHQ,KAAK,eAAe,YAAY,EAGvB,IAAKC,IAAU,CACpC,KAAMA,EAAK,KACX,YAAaA,EAAK,YAClB,YAAaA,EAAK,WACpB,EAAE,EAEF,YAAK,OAAO,KAAK,gBAAMD,EAAS,MAAM,qBAAM,EAErC,CACL,QAAS,MACT,OAAQ,CACN,MAAOA,CACT,EACA,GAAID,GAAM,IACZ,CACF,OAASF,EAAO,CACd,WAAK,OAAO,MAAM,mDAAYA,CAAK,EAC7BA,CACR,CACF,CAQA,MAAc,eACZC,EACAC,EACsB,CACtB,KAAK,OAAO,KAAK,yCAAqBD,EAAO,IAAI,GAAIA,CAAM,EAE3D,GAAI,CACF,GAAI,CAACA,EAAO,KACV,MAAM,IAAI,MAAM,kDAAU,EAG5B,IAAMI,EAAS,MAAM,KAAK,eAAe,SACvCJ,EAAO,KACPA,EAAO,WAAa,CAAC,CACvB,EAEA,YAAK,OAAO,KAAK,gBAAMA,EAAO,IAAI,2BAAO,EAElC,CACL,QAAS,MACT,OAAQ,CACN,QAASI,EAAO,QAChB,QAASA,EAAO,SAAW,EAC7B,EACA,GAAIH,GAAM,IACZ,CACF,OAASF,EAAO,CACd,WAAK,OAAO,MAAM,yCAAWC,EAAO,IAAI,GAAID,CAAK,EAC3CA,CACR,CACF,CAOA,MAAc,WAAWE,EAA4C,CACnE,YAAK,OAAO,MAAM,gCAAY,EAEvB,CACL,QAAS,MACT,OAAQ,CACN,OAAQ,KACR,UAAW,IAAI,KAAK,EAAE,YAAY,CACpC,EACA,GAAIA,GAAM,IACZ,CACF,CAQQ,oBAAoBF,EAAcE,EAAmC,CAE3E,IAAII,EAAY,OAEhB,OACEN,EAAM,QAAQ,SAAS,gCAAO,GAC9BA,EAAM,QAAQ,SAAS,gCAAO,EAE9BM,EAAY,QAEZN,EAAM,QAAQ,SAAS,cAAI,GAC3BA,EAAM,QAAQ,SAAS,0BAAM,KAE7BM,EAAY,QAGP,CACL,QAAS,MACT,MAAO,CACL,KAAMA,EACN,QAASN,EAAM,QACf,KAAM,CACJ,MAAOA,EAAM,KACf,CACF,EACA,GAAIE,GAAM,IACZ,CACF,CAMA,mBAAuC,CACrC,OAAO,KAAK,cACd,CACF,ICzOA,OAAS,gBAAAK,OAAoB,SAX7B,IA6DaC,GA+CAC,GAyFAC,GArMbC,GAAAC,EAAA,kBAYAC,IACAC,KACAC,KAQAC,KAuCaR,GAAN,KAAmB,CA7D1B,MA6D0B,CAAAS,EAAA,qBAChB,eACA,OAER,YAAYC,EAAmC,CAC7C,KAAK,eAAiBA,EACtB,KAAK,OAASC,CAChB,CAEA,MAAM,YAA4B,CAChC,KAAK,OAAO,KAAK,kDAAU,CAE7B,CAKA,aAA0B,CACxB,OAAO,KAAK,eAAe,YAAY,EAAE,IAAKC,IAAU,CACtD,KAAMA,EAAK,KACX,YAAaA,EAAK,YAClB,YAAaA,EAAK,YAClB,YAAaA,EAAK,YAClB,aAAcA,EAAK,YACrB,EAAE,CACJ,CAKA,SAASC,EAAmC,CAE1C,OADc,KAAK,YAAY,EAClB,KAAMD,GAASA,EAAK,OAASC,CAAQ,GAAK,IACzD,CAKA,QAAQA,EAA2B,CACjC,OAAO,KAAK,SAASA,CAAQ,IAAM,IACrC,CACF,EAMaZ,GAAN,cAAgCF,EAAa,CA5GpD,MA4GoD,CAAAU,EAAA,0BAC1C,YAA2C,IAAI,IAC/C,OAER,aAAc,CACZ,MAAM,EACN,KAAK,OAASE,CAChB,CAEA,MAAM,YAA4B,CAChC,KAAK,OAAO,KAAK,kDAAU,CAC7B,CAKA,mBACEG,EACAC,EACAC,EACM,CACN,IAAMC,EAAiC,CACrC,GAAAH,EACA,cAAAC,EACA,MAAAC,EACA,YAAa,IAAI,KACjB,aAAc,IAAI,IACpB,EAEA,KAAK,YAAY,IAAIF,EAAIG,CAAc,EACvC,KAAK,KAAK,uBAAwBA,CAAc,EAChD,KAAK,OAAO,MAAM,mCAAUH,CAAE,KAAKC,CAAa,GAAG,CACrD,CAKA,sBAAsBD,EAAYE,EAA8B,CAC9D,IAAME,EAAa,KAAK,YAAY,IAAIJ,CAAE,EACtCI,IACFA,EAAW,MAAQF,EACnBE,EAAW,aAAe,IAAI,KAC9B,KAAK,KAAK,yBAA0BA,CAAU,EAC9C,KAAK,OAAO,MAAM,yCAAWJ,CAAE,OAAOE,CAAK,EAAE,EAEjD,CAKA,iBAAiBF,EAAkB,CACjC,IAAMI,EAAa,KAAK,YAAY,IAAIJ,CAAE,EACtCI,IACF,KAAK,YAAY,OAAOJ,CAAE,EAC1B,KAAK,KAAK,oBAAqBI,CAAU,EACzC,KAAK,OAAO,MAAM,mCAAUJ,CAAE,EAAE,EAEpC,CAKA,mBAAsC,CACpC,OAAO,MAAM,KAAK,KAAK,YAAY,OAAO,CAAC,CAC7C,CAKA,0BAAmC,CACjC,OAAO,MAAM,KAAK,KAAK,YAAY,OAAO,CAAC,EAAE,OAC1CK,GAASA,EAAK,QAAU,WAC3B,EAAE,MACJ,CAKA,MAAM,qBAAqC,CACzC,KAAK,OAAO,KAAK,sCAAQ,EACzB,KAAK,YAAY,MAAM,EACvB,KAAK,KAAK,sBAAsB,CAClC,CACF,EAMajB,GAAN,cAA+BH,EAAa,CArMnD,MAqMmD,CAAAU,EAAA,yBACzC,eACA,eACA,kBAAmD,IAAI,IACvD,aACA,kBACA,UAAY,GACZ,OACA,OAER,YAAYW,EAA8B,CAAC,EAAG,CAC5C,MAAM,EAEN,KAAK,OAAS,CACZ,KAAM,mBACN,cAAe,GACf,SAAU,OACV,eAAgB,IAChB,kBAAmB,IACnB,GAAGA,CACL,EAEA,KAAK,OAAST,EAGd,KAAK,eAAiB,IAAIU,GAC1B,KAAK,eAAiB,IAAIC,GAAkB,KAAK,cAAc,EAC/D,KAAK,aAAe,IAAItB,GAAa,KAAK,cAAc,EACxD,KAAK,kBAAoB,IAAIC,GAG7B,KAAK,oBAAoB,CAC3B,CAKQ,qBAA4B,CAElC,KAAK,kBAAkB,GACrB,uBACCiB,GAA+B,CAC9B,KAAK,KAAK,uBAAwBA,CAAU,CAC9C,CACF,EAEA,KAAK,kBAAkB,GACrB,yBACCA,GAA+B,CAC9B,KAAK,KAAK,yBAA0BA,CAAU,CAChD,CACF,EAEA,KAAK,kBAAkB,GACrB,oBACCA,GAA+B,CAC9B,KAAK,KAAK,oBAAqBA,CAAU,CAC3C,CACF,CACF,CAKA,MAAM,YAA4B,CAChC,KAAK,OAAO,KAAK,uDAAe,EAEhC,GAAI,CAEF,MAAM,KAAK,eAAe,iBAAiB,EAC3C,MAAM,KAAK,aAAa,WAAW,EACnC,MAAM,KAAK,kBAAkB,WAAW,EAExC,KAAK,OAAO,KAAK,mEAAiB,EAClC,KAAK,KAAK,aAAa,CACzB,OAASK,EAAO,CACd,WAAK,OAAO,MAAM,oEAAmBA,CAAK,EACpCA,CACR,CACF,CAKA,MAAM,kBACJC,EACAC,EACe,CACf,GAAI,KAAK,kBAAkB,IAAID,CAAI,EACjC,MAAM,IAAI,MAAM,kCAASA,CAAI,qBAAM,EAGrC,KAAK,OAAO,KAAK,+CAAYA,CAAI,EAAE,EAEnC,GAAI,CAEF,MAAMC,EAAQ,WAAW,EAGzB,KAAK,kBAAkB,IAAID,EAAMC,CAAO,EAGxC,KAAK,kBAAkB,mBACrBA,EAAQ,gBAAgB,EACxBD,EACAC,EAAQ,SAAS,CACnB,EAEA,KAAK,OAAO,KAAK,kCAASD,CAAI,2BAAO,EACrC,KAAK,KAAK,sBAAuB,CAAE,KAAAA,EAAM,QAAAC,CAAQ,CAAC,CACpD,OAASF,EAAO,CACd,WAAK,OAAO,MAAM,8CAAWC,CAAI,gBAAOD,CAAK,EACvCA,CACR,CACF,CAKA,MAAM,OAAuB,CAC3B,GAAI,KAAK,UACP,MAAM,IAAI,MAAM,4CAAS,EAG3B,KAAK,OAAO,KAAK,iDAAc,EAE/B,GAAI,CAEF,OAAW,CAACC,EAAMC,CAAO,IAAK,KAAK,kBACjC,GAAI,CACF,MAAMA,EAAQ,MAAM,EAGpB,KAAK,kBAAkB,sBACrBA,EAAQ,gBAAgB,EACxBA,EAAQ,SAAS,CACnB,EAEA,KAAK,OAAO,KAAK,kCAASD,CAAI,2BAAO,CACvC,OAASD,EAAO,CACd,WAAK,OAAO,MAAM,kCAASC,CAAI,4BAASD,CAAK,EACvCA,CACR,CAGF,KAAK,UAAY,GACjB,KAAK,OAAO,KAAK,6DAAgB,EACjC,KAAK,KAAK,SAAS,CACrB,OAASA,EAAO,CACd,WAAK,OAAO,MAAM,8DAAkBA,CAAK,EACnCA,CACR,CACF,CAKA,MAAM,MAAsB,CAC1B,GAAK,KAAK,UAIV,MAAK,OAAO,KAAK,iDAAc,EAE/B,GAAI,CAEF,OAAW,CAACC,EAAMC,CAAO,IAAK,KAAK,kBACjC,GAAI,CACF,MAAMA,EAAQ,KAAK,EAGnB,KAAK,kBAAkB,sBACrBA,EAAQ,gBAAgB,EACxBA,EAAQ,SAAS,CACnB,EAEA,KAAK,OAAO,KAAK,kCAASD,CAAI,2BAAO,CACvC,OAASD,EAAO,CACd,KAAK,OAAO,MAAM,kCAASC,CAAI,4BAASD,CAAK,CAC/C,CAIF,MAAM,KAAK,kBAAkB,oBAAoB,EAGjD,MAAM,KAAK,eAAe,gBAAgB,EAE1C,KAAK,UAAY,GACjB,KAAK,OAAO,KAAK,6DAAgB,EACjC,KAAK,KAAK,SAAS,CACrB,OAASA,EAAO,CACd,WAAK,OAAO,MAAM,8DAAkBA,CAAK,EACnCA,CACR,EACF,CAKA,mBAAuC,CACrC,OAAO,KAAK,cACd,CAKA,iBAAgC,CAC9B,OAAO,KAAK,YACd,CAKA,sBAA0C,CACxC,OAAO,KAAK,iBACd,CAKA,mBAAuC,CACrC,OAAO,KAAK,cACd,CAKA,WAME,CACA,MAAO,CACL,UAAW,KAAK,UAChB,eAAgB,KAAK,kBAAkB,KACvC,kBAAmB,KAAK,kBAAkB,yBAAyB,EACnE,UAAW,KAAK,aAAa,YAAY,EAAE,OAC3C,OAAQ,KAAK,MACf,CACF,CAKA,sBAAsD,CACpD,OAAO,IAAI,IAAI,KAAK,iBAAiB,CACvC,CAKA,iBAA2B,CACzB,OAAO,KAAK,SACd,CACF,IC/UA,eAAsBG,GACpBC,EAAqB,CAAE,KAAM,MAAO,EACT,CAC3BC,EAAO,KAAK,kDAAe,EAE3B,IAAMC,EAAS,IAAIC,GACnB,MAAMD,EAAO,WAAW,EAExB,IAAME,EAAiBF,EAAO,kBAAkB,EAC1CG,EAAc,IAAIC,GAAYF,EAAgBJ,CAAM,EAE1D,aAAME,EAAO,kBAAkB,OAAQG,CAAW,EAElDJ,EAAO,KAAK,6DAAgB,EACrBC,CACT,CAtIA,IAAAK,GAAAC,EAAA,kBAWAC,IACAC,KACAC,KAEAC,KAKAC,KAmGsBC,EAAAf,GAAA,sBCvHtB,IAAAgB,GAAA,GAAAC,EAAAD,GAAA,eAAAE,KAAA,OAAS,gBAAAC,OAAoB,SAA7B,IAQMC,EAOOF,GAfbG,GAAAC,EAAA,kBACAC,IACAC,KACAC,IACAC,KAIMN,EAAS,IAAIO,GAONT,GAAN,cAAwBC,EAAa,CAf5C,MAe4C,CAAAS,EAAA,kBAClC,cAAyC,KACzC,eAAwC,KACxC,KACA,UAAY,GAEpB,YAAYC,EAAO,IAAM,CACvB,MAAM,EACN,KAAK,KAAOA,CACd,CAKA,MAAc,yBAAyC,CACrD,GAAI,MAAK,cAIT,CAAAT,EAAO,KAAK,uDAAe,EAE3B,GAAI,CAEF,IAAMU,EAAyB,CAC7B,KAAM,OACN,KAAM,KAAK,KACX,KAAM,UACN,UAAW,GACX,UAAW,EACb,EAEA,KAAK,cAAgB,MAAMC,GAAiBD,CAAU,EAGtD,KAAK,cAAc,GAAG,UAAW,IAAM,KAAK,KAAK,SAAS,CAAC,EAC3D,KAAK,cAAc,GAAG,UAAW,IAAM,KAAK,KAAK,SAAS,CAAC,EAC3D,KAAK,cAAc,GAAG,uBAAyBE,GAAe,CAC5D,KAAK,KAAK,uBAAwBA,CAAU,CAC9C,CAAC,EAEDZ,EAAO,KAAK,mEAAiB,CAC/B,OAASa,EAAO,CACd,MAAAb,EAAO,MAAM,oEAAmBa,CAAK,EAC/BA,CACR,EACF,CAKA,MAAc,qBAAqC,CACjD,GAAI,CAEF,IAAIC,EAA6B,KACjC,GAAI,CACEC,EAAc,aAAa,IAE7BD,EADkBC,EAAc,gBAAgB,EAEpC,KAAMC,GAAOA,GAAM,CAACA,EAAG,SAAS,qBAAM,CAAC,GAAK,KAE5D,OAASH,EAAO,CACdb,EAAO,KAAK,kFAAkBa,CAAK,CACrC,CAGIC,GACF,KAAK,eAAiB,IAAIG,EAAeH,CAAW,EAGhD,KAAK,eACP,KAAK,eAAe,kBAClB,KAAK,cAAc,kBAAkB,CACvC,EAGF,MAAM,KAAK,eAAe,QAAQ,EAClCd,EAAO,KAAK,wDAAW,GAEvBA,EAAO,KAAK,kGAAkB,CAElC,OAASa,EAAO,CACdb,EAAO,MAAM,4EAAiBa,CAAK,CACrC,CACF,CAKA,MAAa,OAAuB,CAClC,GAAI,KAAK,UAAW,CAClBb,EAAO,KAAK,sCAAQ,EACpB,MACF,CAEA,GAAI,CACFA,EAAO,KAAK,qCAAY,EAGxB,MAAM,KAAK,wBAAwB,EAG/B,KAAK,eACP,MAAM,KAAK,cAAc,MAAM,EAIjC,KAAK,oBAAoB,EAAE,MAAOa,GAAU,CAC1Cb,EAAO,MAAM,4EAAiBa,CAAK,CACrC,CAAC,EAED,KAAK,UAAY,GACjB,KAAK,KAAK,SAAS,EACnBb,EAAO,KAAK,gDAAa,CAC3B,OAASa,EAAO,CACd,MAAAb,EAAO,MAAM,mDAAiBa,CAAK,EAC7BA,CACR,CACF,CAKA,MAAa,MAAsB,CACjC,GAAI,CAAC,KAAK,UAAW,CACnBb,EAAO,KAAK,sCAAQ,EACpB,MACF,CAEA,GAAI,CACFA,EAAO,KAAK,qCAAY,EAGpB,KAAK,eACP,MAAM,KAAK,cAAc,KAAK,EAI5B,KAAK,iBACP,KAAK,eAAe,WAAW,EAC/B,KAAK,eAAiB,MAGxB,KAAK,UAAY,GACjB,KAAK,KAAK,SAAS,EACnBA,EAAO,KAAK,0CAAY,CAC1B,OAASa,EAAO,CACd,MAAAb,EAAO,MAAM,mDAAiBa,CAAK,EAC7BA,CACR,CACF,CAKA,mBAAoB,CAClB,OAAO,KAAK,eAAe,kBAAkB,GAAK,IACpD,CAKA,mBAAoB,CAClB,OAAO,KAAK,eAAe,kBAAkB,GAAK,IACpD,CAKA,WAAY,CACV,OAAK,KAAK,cASH,CACL,GAFa,KAAK,cAAc,UAAU,EAG1C,KAAM,KAAK,KACX,KAAM,aACN,eAAgB,KAAK,iBAAmB,IAC1C,EAbS,CACL,UAAW,GACX,KAAM,KAAK,KACX,KAAM,YACR,CAUJ,CAKA,WAAqB,CACnB,OAAO,KAAK,YAAc,KAAK,eAAe,gBAAgB,GAAK,GACrE,CACF,IC/MA,IAAAK,GAAA,GAAAC,EAAAD,GAAA,wBAAAE,KAAA,IAkBaA,GAlBbC,GAAAC,EAAA,kBAIAC,IAOAC,KACAC,KACAC,KAKaN,GAAN,KAAoD,CACzD,YACUO,EACAC,EACAC,EACR,CAHQ,oBAAAF,EACA,mBAAAC,EACA,YAAAC,CACP,CAvBL,MAkB2D,CAAAC,EAAA,2BAUzD,MAAM,MAAMC,EAA6C,CACvD,GAAI,CAEF,KAAK,qBAAqBA,CAAO,EAGjC,KAAK,eAAe,sBAAsB,EAG1C,IAAMC,EAAS,KAAK,UAAU,EAC9B,GAAIA,EAAO,QAAS,CAElB,QAAQ,IAAI,gEAAmBA,EAAO,GAAG,gDAAa,EAEtD,GAAI,CAEF,MAAM,KAAK,eAAe,oBAAoBA,EAAO,GAAI,EAGzD,KAAK,eAAe,eAAe,EAGnC,MAAM,IAAI,QAASC,GAAY,WAAWA,EAAS,GAAI,CAAC,EAExD,QAAQ,IAAI,+FAAoB,CAClC,OAASC,EAAW,CAClB,QAAQ,KACN,uEAAgBA,aAAqB,MAAQA,EAAU,QAAU,OAAOA,CAAS,CAAC,EACpF,CAEF,CACF,CAMA,OAHA,KAAK,iBAAiB,EAGdH,EAAQ,KAAM,CACpB,IAAK,aACH,MAAM,KAAK,mBAAmBA,CAAO,EACrC,MACF,IAAK,QACH,MAAM,KAAK,eAAeA,CAAO,EACjC,MACF,IAAK,SACH,MAAM,KAAK,gBAAgBA,CAAO,EAClC,MACF,QACE,MAAM,KAAK,gBAAgBA,CAAO,EAClC,KACJ,CACF,OAASI,EAAO,CACd,MAAIA,aAAiBC,EACbD,EAEFC,EAAa,YACjBD,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CACvD,CACF,CACF,CAKA,MAAM,MAAsB,CAC1B,GAAI,CACF,IAAMH,EAAS,KAAK,UAAU,EAE9B,GAAI,CAACA,EAAO,QACV,MAAMI,EAAa,WAAW,EAIhC,MAAM,KAAK,eAAe,oBAAoBJ,EAAO,GAAI,EAGzD,KAAK,eAAe,eAAe,CACrC,OAASG,EAAO,CACd,MAAIA,aAAiBC,EACbD,EAEF,IAAIC,EACR,yCAAWD,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACnE,CACF,CACF,CAKA,MAAM,QAAQJ,EAA6C,CACzD,GAAI,CAEa,KAAK,UAAU,EACnB,UACT,MAAM,KAAK,KAAK,EAEhB,MAAM,IAAI,QAASE,GAAY,WAAWA,EAAS,GAAI,CAAC,GAI1D,MAAM,KAAK,MAAMF,CAAO,CAC1B,OAASI,EAAO,CACd,MAAM,IAAIC,EACR,yCAAWD,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACnE,CACF,CACF,CAKA,WAA2B,CACzB,OAAO,KAAK,eAAe,iBAAiB,CAC9C,CAKQ,qBAAqBJ,EAAoC,CAK/D,GAJIA,EAAQ,OAAS,QACnBM,EAAW,aAAaN,EAAQ,IAAI,EAIpCA,EAAQ,MACR,CAAC,CAAC,SAAU,aAAc,OAAO,EAAE,SAASA,EAAQ,IAAI,EAExD,MAAM,IAAIK,EAAa,+CAAYL,EAAQ,IAAI,EAAE,CAErD,CAKQ,kBAAyB,CAE/B,GAAI,CAAC,KAAK,cAAc,aAAa,EACnC,MAAMO,EAAY,eAAe,EAInC,GAAI,CAEF,GAAI,CADW,KAAK,cAAc,UAAU,EAE1C,MAAM,IAAIA,EAAY,sCAAQ,CAElC,OAASH,EAAO,CACd,MAAIA,aAAiBG,EACbH,EAEF,IAAIG,EACR,yCAAWH,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACnE,CACF,CACF,CAKA,MAAc,gBAAgBJ,EAA6C,CACzE,GAAM,CAAE,MAAAQ,CAAM,EAAI,KAAM,QAAO,eAAoB,EAE/CR,EAAQ,OAEV,MAAM,KAAK,uBAAuBA,EAAQ,IAAM,EAAK,EAGrD,MAAM,KAAK,2BAA2BA,EAAQ,IAAM,EAAK,CAE7D,CAKA,MAAc,mBACZA,EACe,CACf,IAAMS,EAAOT,EAAQ,MAAQ,IACvB,CAAE,MAAAQ,CAAM,EAAI,KAAM,QAAO,eAAoB,EAEnD,GAAIR,EAAQ,OAAQ,CAElB,IAAMU,EAAaC,EAAU,kBAAkB,KAAK,EAC9CC,EAAQJ,EACZ,OACA,CAACE,EAAY,QAAS,WAAYD,EAAK,SAAS,CAAC,EACjD,CACE,SAAU,GACV,MAAO,CAAC,SAAU,SAAU,QAAQ,EACpC,IAAK,CACH,GAAG,QAAQ,IACX,mBAAoBE,EAAU,aAAa,EAC3C,eAAgB,OAChB,gBAAiB,MACnB,CACF,CACF,EAGA,KAAK,eAAe,YAAYC,EAAM,IAAM,QAAQ,EAGpDA,EAAM,MAAM,EAGZ,QAAQ,IACN,gEAA6BA,EAAM,GAAG,WAAWH,CAAI,GACvD,EACA,QAAQ,IAAI,kEAA6B,EAGzC,QAAQ,KAAK,CAAC,CAChB,KAAO,CAEL,GAAM,CAAE,UAAAI,CAAU,EAAI,KAAM,uCACtBC,EAAS,IAAID,EAAUJ,CAAI,EAG3BM,EAAUhB,EAAA,SAAY,CAC1B,MAAMe,EAAO,KAAK,EAClB,QAAQ,KAAK,CAAC,CAChB,EAHgB,WAKhB,QAAQ,GAAG,SAAUC,CAAO,EAC5B,QAAQ,GAAG,UAAWA,CAAO,EAE7B,MAAMD,EAAO,MAAM,CACrB,CACF,CAKA,MAAc,eAAed,EAA6C,CACxE,GAAM,CAAE,MAAAQ,CAAM,EAAI,KAAM,QAAO,eAAoB,EAC7CQ,EAAeL,EAAU,sBAAsB,EAG/CC,EAAQJ,EAAM,OAAQ,CAACQ,CAAY,EAAG,CAC1C,MAAO,UACP,IAAK,CACH,GAAG,QAAQ,IACX,mBAAoBL,EAAU,aAAa,CAC7C,CACF,CAAC,EAGD,KAAK,eAAe,YAAYC,EAAM,IAAM,YAAY,CAC1D,CAKA,MAAc,uBAAuBK,EAAqC,CACxE,GAAM,CAAE,MAAAT,CAAM,EAAI,KAAM,QAAO,eAAoB,EAC7CU,EAAgBP,EAAU,2BAA2B,EAG3D,GAAI,EADO,KAAM,QAAO,IAAS,GACzB,QAAQ,WAAWO,CAAa,EACtC,MAAM,IAAIb,EAAa,6CAAoBa,CAAa,EAAE,EAG5D,IAAMC,EAAO,CAACD,CAAa,EACvBD,GACFE,EAAK,KAAK,gBAAgB,EAG5B,IAAMP,EAAQJ,EAAM,OAAQW,EAAM,CAChC,SAAU,GACV,MAAO,CAAC,SAAU,SAAU,QAAQ,EACpC,IAAK,CACH,GAAG,QAAQ,IACX,mBAAoBR,EAAU,aAAa,EAC3C,eAAgB,MAClB,CACF,CAAC,EAGD,KAAK,eAAe,YAAYC,EAAM,IAAM,QAAQ,EAGpDA,EAAM,MAAM,EAGZ,QAAQ,IAAI,2DAAmBA,EAAM,GAAG,GAAG,EAC3C,QAAQ,IAAI,kEAA6B,EACzC,QAAQ,IAAI,kEAA6B,EAGzC,QAAQ,KAAK,CAAC,CAChB,CAKA,MAAc,2BACZK,EACe,CACf,GAAM,CAAE,UAAAG,CAAU,EAAI,KAAM,uCACtBN,EAAS,IAAIM,EAGbL,EAAUhB,EAAA,SAAY,CAC1B,MAAMe,EAAO,KAAK,EAClB,KAAK,eAAe,eAAe,EACnC,QAAQ,KAAK,CAAC,CAChB,EAJgB,WAchB,GARA,QAAQ,GAAG,SAAUC,CAAO,EAC5B,QAAQ,GAAG,UAAWA,CAAO,EAG7B,KAAK,eAAe,YAAY,QAAQ,IAAK,YAAY,EAEzD,MAAMD,EAAO,MAAM,EAEfG,EAAa,CAEf,IAAMR,EADS,KAAK,cAAc,UAAU,GACvB,WAAW,MAAQ,KACxC,MAAM,KAAK,eAAe,oBAAoBA,CAAI,EAAE,CACtD,CACF,CAKA,MAAc,eAAeY,EAA4B,CACvD,GAAI,CACF,GAAM,CAAE,MAAAb,CAAM,EAAI,KAAM,QAAO,eAAoB,EAC7Cc,EAAWC,EAAc,mBAAmB,EAE9CC,EACAL,EAEAG,IAAa,UACfE,EAAU,OACVL,EAAO,CAACE,CAAG,GACFC,IAAa,SACtBE,EAAU,QACVL,EAAO,CAAC,GAAIE,CAAG,IAEfG,EAAU,WACVL,EAAO,CAACE,CAAG,GAGbb,EAAMgB,EAASL,EAAM,CAAE,SAAU,GAAM,MAAO,QAAS,CAAC,EACxD,QAAQ,IAAI,+DAAgBE,CAAG,EAAE,CACnC,MAAgB,CACd,QAAQ,IAAI,6GAAwBA,CAAG,EAAE,CAC3C,CACF,CACF,IC5XA,IAAAI,GAAA,GAAAC,EAAAD,GAAA,yBAAAE,KAIA,OAAOC,OAAQ,KACf,OAAOC,OAAU,OALjB,IAqCaF,GArCbG,GAAAC,EAAA,kBAMAC,IAEAC,KACAC,KACAC,KA2BaR,GAAN,KAAsD,CArC7D,MAqC6D,CAAAS,EAAA,4BACnD,cAAgB,IAAI,IAK5B,MAAM,uBAAiD,CACrD,GAAI,CACF,IAAMC,EAAeC,EAAU,iBAAiB,EAEhD,GAAI,CAACD,EACH,MAAO,CAAC,EAGV,IAAME,EAA4B,CAAC,EAC7BC,EAAeZ,GAClB,YAAYS,EAAc,CAAE,cAAe,EAAK,CAAC,EACjD,OAAQI,GAAWA,EAAO,YAAY,CAAC,EACvC,IAAKA,GAAWA,EAAO,IAAI,EAE9B,QAAWC,KAAgBF,EACzB,GAAI,CACF,IAAMG,EAAe,MAAM,KAAK,gBAAgBD,CAAY,EACxDC,GACFJ,EAAU,KAAKI,CAAY,CAE/B,MAAgB,CAEd,QAAQ,KAAK,yCAAWD,CAAY,EAAE,CACxC,CAGF,OAAOH,CACT,MAAgB,CACd,MAAM,IAAIK,EACR,mDACAN,EAAU,iBAAiB,GAAK,EAClC,CACF,CACF,CAKA,MAAM,gBAAgBI,EAAoD,CACxE,GAAI,CAKF,GAHAG,EAAW,qBAAqBH,CAAY,EAGxC,KAAK,cAAc,IAAIA,CAAY,EACrC,OAAO,KAAK,cAAc,IAAIA,CAAY,EAG5C,IAAMI,EAAeR,EAAU,gBAAgBI,CAAY,EAC3D,GAAI,CAACI,EACH,OAAO,KAIT,IAAMC,EAAalB,GAAK,KAAKiB,EAAc,eAAe,EACtDE,EAAc,CAAC,EAEnB,GAAIC,EAAU,OAAOF,CAAU,EAC7B,GAAI,CACF,IAAMG,EAAgBD,EAAU,SAASF,CAAU,EACnDC,EAAS,KAAK,MAAME,CAAa,CACnC,MAAgB,CACd,QAAQ,KAAK,iEAAeR,CAAY,EAAE,CAC5C,CAIF,IAAMS,EAAQ,KAAK,iBAAiBL,CAAY,EAE1CH,EAA6B,CACjC,KAAMD,EACN,KAAMI,EACN,YAAaE,EAAO,aAAe,GAAGN,CAAY,gBAClD,QAASM,EAAO,SAAW,QAC3B,OAAQA,EAAO,OACf,MAAAG,CACF,EAGA,YAAK,cAAc,IAAIT,EAAcC,CAAY,EAE1CA,CACT,OAASS,EAAO,CACd,MAAIA,aAAiBC,EACbD,EAEF,IAAIR,EAAU,qDAAaF,CAAY,GAAI,EAAE,CACrD,CACF,CAKA,MAAM,aAAaA,EAAsBY,EAAmC,CAC1E,MAAM,KAAK,cAAc,CACvB,aAAAZ,EACA,WAAAY,EACA,YAAazB,GAAK,SAASyB,CAAU,CACvC,CAAC,CACH,CAKA,MAAM,cAAcC,EAA+C,CACjE,GAAI,CAEF,KAAK,sBAAsBA,CAAO,EAGlC,IAAMb,EAAea,EAAQ,cAAgB,UACvCZ,EAAe,MAAM,KAAK,gBAAgBD,CAAY,EAE5D,GAAI,CAACC,EACH,MAAM,IAAIC,EAAU,mCAAUF,CAAY,GAAI,EAAE,EAIlD,IAAMY,EAAazB,GAAK,QAAQ0B,EAAQ,UAAU,EAClD,GAAIN,EAAU,OAAOK,CAAU,EAC7B,MAAMV,EAAU,cAAcU,CAAU,EAI1CL,EAAU,UAAUK,CAAU,EAG9B,MAAM,KAAK,kBAAkBX,EAAcW,EAAYC,CAAO,EAG9D,MAAM,KAAK,yBAAyBD,EAAYC,CAAO,EAEvD,QAAQ,IAAI,gDAAaD,CAAU,EAAE,CACvC,OAASF,EAAO,CACd,MAAIA,aAAiBR,GAAaQ,aAAiBC,EAC3CD,EAEF,IAAIR,EACR,yCAAWQ,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,GACjEG,EAAQ,UACV,CACF,CACF,CAKA,MAAM,iBAAiBb,EAAwC,CAC7D,GAAI,CACF,IAAMC,EAAe,MAAM,KAAK,gBAAgBD,CAAY,EAE5D,GAAI,CAACC,EACH,MAAO,GAIT,IAAMa,EAAgB,CAAC,cAAc,EAErC,QAAWC,KAAgBD,EAAe,CACxC,IAAME,EAAW7B,GAAK,KAAKc,EAAa,KAAMc,CAAY,EAC1D,GAAI,CAACR,EAAU,OAAOS,CAAQ,EAC5B,eAAQ,KAAK,qDAAaD,CAAY,EAAE,EACjC,EAEX,CAEA,MAAO,EACT,MAAQ,CACN,MAAO,EACT,CACF,CAKA,YAAmB,CACjB,KAAK,cAAc,MAAM,CAC3B,CAKQ,iBAAiBX,EAAgC,CACvD,GAAI,CAOF,OANcG,EAAU,cAAcH,EAAc,CAClD,UAAW,GACX,cAAe,EACjB,CAAC,EAGY,OAAQa,GAAS,CAC5B,IAAMC,EAAe/B,GAAK,SAASiB,EAAca,CAAI,EACrD,MACE,CAACC,EAAa,WAAW,GAAG,GAC5BA,IAAiB,iBACjB,CAACA,EAAa,SAAS,cAAc,CAEzC,CAAC,CACH,MAAQ,CACN,MAAO,CAAC,CACV,CACF,CAKQ,sBAAsBL,EAAsC,CAClEV,EAAW,iBAAiBU,EAAQ,WAAY,YAAY,EAC5DV,EAAW,iBAAiBU,EAAQ,YAAa,aAAa,EAC9DV,EAAW,oBAAoBU,EAAQ,WAAW,EAE9CA,EAAQ,cACVV,EAAW,qBAAqBU,EAAQ,YAAY,CAExD,CAKA,MAAc,kBACZZ,EACAW,EACAC,EACe,CACf,GAAI,CAEFN,EAAU,cAAcN,EAAa,KAAMW,EAAY,CACrD,QAAS,CAAC,gBAAiB,OAAQ,cAAc,EACjD,UAAW,GACX,UAAW,EACb,CAAC,CACH,OAASF,EAAO,CACd,MAAM,IAAIR,EACR,qDAAaQ,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,GACnET,EAAa,IACf,CACF,CACF,CAKA,MAAc,yBACZW,EACAC,EACe,CACf,GAAI,CAEF,IAAMM,EAAY,CAChB,aAAcN,EAAQ,YACtB,mBAAoBA,EAAQ,YAAY,YAAY,EACpD,mBAAoBA,EAAQ,YAAY,YAAY,EACpD,GAAGA,EAAQ,SACb,EAGMO,EAAiB,CACrB,eACA,YACA,cACA,cACA,eACF,EAEA,QAAWC,KAAWD,EAAgB,CACpC,IAAMX,EAAQ,KAAK,mBAAmBG,EAAYS,CAAO,EAEzD,QAAWL,KAAYP,EACrB,MAAM,KAAK,uBAAuBO,EAAUG,CAAS,CAEzD,CACF,OAAST,EAAO,CACd,QAAQ,KACN,qDAAaA,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACrE,CACF,CACF,CAKQ,mBAAmBY,EAAkBD,EAA2B,CACtE,GAAI,CACF,GAAI,CAACA,EAAQ,SAAS,GAAG,EAAG,CAE1B,IAAML,EAAW7B,GAAK,KAAKmC,EAAUD,CAAO,EAC5C,OAAOd,EAAU,OAAOS,CAAQ,EAAI,CAACA,CAAQ,EAAI,CAAC,CACpD,CAGA,IAAMP,EAAQF,EAAU,cAAce,EAAU,CAAE,UAAW,EAAK,CAAC,EAC7DC,EAAQ,IAAI,OAChBF,EAAQ,QAAQ,QAAS,IAAI,EAAE,QAAQ,MAAO,OAAO,CACvD,EAEA,OAAOZ,EAAM,OAAQQ,GAAS,CAC5B,IAAMC,EAAe/B,GAAK,SAASmC,EAAUL,CAAI,EACjD,OAAOM,EAAM,KAAKL,CAAY,CAChC,CAAC,CACH,MAAQ,CACN,MAAO,CAAC,CACV,CACF,CAKA,MAAc,uBACZF,EACAG,EACe,CACf,GAAI,CACF,IAAIK,EAAUjB,EAAU,SAASS,CAAQ,EACrCS,EAAa,GAGjB,OAAW,CAACC,EAAKC,CAAK,IAAK,OAAO,QAAQR,CAAS,EAAG,CACpD,IAAMI,EAAQ,IAAI,OAAO,SAASG,CAAG,SAAU,GAAG,EAC9CH,EAAM,KAAKC,CAAO,IACpBA,EAAUA,EAAQ,QAAQD,EAAOI,CAAK,EACtCF,EAAa,GAEjB,CAGIA,GACFlB,EAAU,UAAUS,EAAUQ,EAAS,CAAE,UAAW,EAAK,CAAC,CAE9D,OAASd,EAAO,CACd,QAAQ,KACN,oDAAYM,CAAQ,KAAKN,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACjF,CACF,CACF,CACF,IC/JA,eAAsBkB,IAAyC,CAC7D,OAAOC,GAAY,OAAO,CAC5B,CA5NA,IAkBaA,GAlBbC,GAAAC,EAAA,kBAIAC,IACAC,IACAC,KAEAC,KACAC,KACAC,KACAC,KACAC,KACAC,KAKaX,GAAN,MAAMY,CAAoC,CAlBjD,MAkBiD,CAAAC,EAAA,oBACvC,UAAY,IAAI,IAChB,UAAY,IAAI,IAChB,eAAiB,IAAI,IACrB,WAAa,IAAI,IAKzB,SAAYC,EAAaC,EAAkBC,EAAY,GAAa,CAClE,KAAK,UAAU,IAAIF,EAAKC,CAAO,EAC3BC,GACF,KAAK,WAAW,IAAIF,CAAG,CAE3B,CAKA,kBAAqBA,EAAaC,EAAwB,CACxD,KAAK,SAASD,EAAKC,EAAS,EAAI,CAClC,CAKA,iBAAoBD,EAAaG,EAAmB,CAClD,KAAK,UAAU,IAAIH,EAAKG,CAAQ,EAChC,KAAK,WAAW,IAAIH,CAAG,CACzB,CAKA,IAAOA,EAAgB,CAErB,GAAI,KAAK,WAAW,IAAIA,CAAG,GAAK,KAAK,UAAU,IAAIA,CAAG,EACpD,OAAO,KAAK,UAAU,IAAIA,CAAG,EAI/B,IAAMC,EAAU,KAAK,UAAU,IAAID,CAAG,EACtC,GAAI,CAACC,EACH,MAAM,IAAI,MAAM,WAAWD,CAAG,iBAAiB,EAIjD,IAAMG,EAAWF,EAAQ,EAGzB,OAAI,KAAK,WAAW,IAAID,CAAG,GACzB,KAAK,UAAU,IAAIA,EAAKG,CAAQ,EAG3BA,CACT,CAKA,IAAIH,EAAsB,CACxB,OAAO,KAAK,UAAU,IAAIA,CAAG,GAAK,KAAK,UAAU,IAAIA,CAAG,CAC1D,CAKA,OAAc,CACZ,KAAK,UAAU,MAAM,EACrB,KAAK,UAAU,MAAM,EACrB,KAAK,WAAW,MAAM,CACxB,CAKA,mBAA8B,CAC5B,IAAMI,EAAc,MAAM,KAAK,KAAK,UAAU,KAAK,CAAC,EAC9CC,EAAe,MAAM,KAAK,KAAK,UAAU,KAAK,CAAC,EACrD,MAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAGD,EAAa,GAAGC,CAAY,CAAC,CAAC,CACvD,CAKA,OAAO,QAAsB,CAC3B,IAAMC,EAAY,IAAIR,EAGtB,OAAAQ,EAAU,kBAAkB,eAAgB,IACnCC,EACR,EAEDD,EAAU,kBAAkB,gBAAiB,IACpCE,CACR,EAEDF,EAAU,kBAAkB,cAAe,IAClCG,EACR,EAEDH,EAAU,kBAAkB,YAAa,IAChCI,CACR,EAEDJ,EAAU,kBAAkB,YAAa,IAChCK,CACR,EAEDL,EAAU,kBAAkB,aAAc,IACjCM,CACR,EAGDN,EAAU,kBAAkB,gBAAiB,IACpCO,CACR,EAGDP,EAAU,kBAAkB,SAAU,IAC7BQ,CACR,EAGDR,EAAU,kBAAkB,eAAgB,IACnCS,EACR,EAGDT,EAAU,kBAAkB,iBAAkB,IAAM,CAClD,IAAMU,EAAuB,cAC7B,OAAO,IAAIA,EAAqB,kBAClC,CAAC,EAEDV,EAAU,kBAAkB,gBAAiB,IAAM,CACjD,IAAMW,EAAsB,cACtBC,EAAiBZ,EAAU,IAAI,gBAAgB,EAC/CQ,EAASR,EAAU,IAAI,QAAQ,EACrC,OAAO,IAAIW,EAAoB,kBAAkBC,EAAgBJ,CAAM,CACzE,CAAC,EAEDR,EAAU,kBAAkB,iBAAkB,IAAM,CAClD,IAAMa,EAAuB,cACvBD,EAAiBZ,EAAU,IAAI,gBAAgB,EAC/CO,EAAgBP,EAAU,IAAI,eAAe,EAC7CQ,EAASR,EAAU,IAAI,QAAQ,EACrC,OAAO,IAAIa,EAAqB,mBAC9BD,EACAL,EACAC,CACF,CACF,CAAC,EAEDR,EAAU,kBAAkB,kBAAmB,IAAM,CAEnD,IAAMc,EAAwB,cAC9B,OAAO,IAAIA,EAAsB,mBACnC,CAAC,EAoCMd,CACT,CACF,EAKsBP,EAAAd,GAAA,qBC1NtB,OAAS,SAAAoC,OAAa,gBAAtB,IA2BaC,GA3BbC,GAAAC,EAAA,kBAEAC,IACAC,KACAC,IAuBaL,GAAN,KAAwB,CA3B/B,MA2B+B,CAAAM,EAAA,0BACrB,OACA,cACA,SAER,YAAYC,EAA8B,CACxC,KAAK,OAASC,EAAO,QAAQ,mBAAmB,EAChD,KAAK,cAAgBD,EACrB,KAAK,SAAWE,EAAY,CAC9B,CAKQ,oBACNC,EACAC,EACAC,EACkB,CAClB,MAAO,CACL,MAAO,CACL,KAAAF,EACA,QAAAC,EACA,QAAAC,CACF,CACF,CACF,CAKQ,sBACNC,EACAF,EACuB,CACvB,MAAO,CACL,QAAS,GACT,KAAAE,EACA,QAAAF,CACF,CACF,CAMA,MAAM,eAAeG,EAA+B,CAClD,GAAI,CACF,YAAK,OAAO,KAAK,kDAAU,EAG3B,KAAK,SAAS,UAAU,4BAA6B,CACnD,OAAQ,UACV,CAAC,EAGD,KAAK,cAAc,oBAAoB,YAAY,EAGnD,WAAW,SAAY,CACrB,GAAI,CACF,MAAM,KAAK,eAAe,EAE1B,WAAW,IAAM,CACf,KAAK,cAAc,oBAAoB,WAAW,CACpD,EAAG,GAAI,CACT,OAASC,EAAO,CACd,KAAK,OAAO,MAAM,wCAAWA,CAAK,EAClC,KAAK,cAAc,oBACjB,SACAA,aAAiB,MAAQA,EAAM,QAAU,0BAC3C,CACF,CACF,EAAG,GAAG,EAECD,EAAE,KAAK,KAAK,sBAAsB,KAAM,4CAAS,CAAC,CAC3D,OAASC,EAAO,CACd,KAAK,OAAO,MAAM,oDAAaA,CAAK,EACpC,IAAMC,EAAgB,KAAK,oBACzB,wBACAD,aAAiB,MAAQA,EAAM,QAAU,kDAC3C,EACA,OAAOD,EAAE,KAAKE,EAAe,GAAG,CAClC,CACF,CAKA,MAAc,gBAAgC,CAC5C,KAAK,OAAO,KAAK,8CAAgB,EAEjC,GAAI,CAIF,IAAMC,EAAS,MAFG,MAAMC,GAAgB,GACP,IAAI,gBAAgB,EACjB,UAAU,EAE9C,GAAI,CAACD,EAAO,QAAS,CACnB,KAAK,OAAO,KAAK,8EAAkB,EAIrBlB,GAAM,UADF,CAAC,QAAS,UAAU,EACI,CACxC,SAAU,GACV,MAAO,SACP,IAAK,CACH,GAAG,QAAQ,IACX,mBAAoB,QAAQ,IAAI,oBAAsB,QAAQ,IAAI,CACpE,CACF,CAAC,EACK,MAAM,EACZ,KAAK,OAAO,KAAK,4DAAe,EAChC,MACF,CAGA,IAAMoB,EAAWF,EAAO,OAAS,SAG3BG,EAAc,CAAC,SAAS,EAC1BD,GACFC,EAAY,KAAK,UAAU,EAIfrB,GAAM,UAAWqB,EAAa,CAC1C,SAAU,GACV,MAAO,SACP,IAAK,CACH,GAAG,QAAQ,IACX,mBAAoB,QAAQ,IAAI,oBAAsB,QAAQ,IAAI,CACpE,CACF,CAAC,EAEK,MAAM,EACZ,KAAK,OAAO,KAAK,4DAAe,CAClC,OAASL,EAAO,CACd,WAAK,OAAO,MAAM,wCAAWA,CAAK,EAC5BA,CACR,CACF,CAMA,MAAM,YAAYD,EAA+B,CAC/C,GAAI,CACF,YAAK,OAAO,KAAK,kDAAU,EAIbf,GAAM,UADH,CAAC,MAAM,EACiB,CACvC,SAAU,GACV,MAAO,SACP,IAAK,CACH,GAAG,QAAQ,IACX,mBAAoB,QAAQ,IAAI,oBAAsB,QAAQ,IAAI,CACpE,CACF,CAAC,EAEK,MAAM,EACZ,KAAK,OAAO,KAAK,4DAAe,EAEzBe,EAAE,KAAK,KAAK,sBAAsB,KAAM,4CAAS,CAAC,CAC3D,OAASC,EAAO,CACd,KAAK,OAAO,MAAM,oDAAaA,CAAK,EACpC,IAAMC,EAAgB,KAAK,oBACzB,qBACAD,aAAiB,MAAQA,EAAM,QAAU,kDAC3C,EACA,OAAOD,EAAE,KAAKE,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,aAAaF,EAA+B,CAChD,GAAI,CACF,YAAK,OAAO,KAAK,kDAAU,EAIbf,GAAM,UADF,CAAC,QAAS,UAAU,EACI,CACxC,SAAU,GACV,MAAO,SACP,IAAK,CACH,GAAG,QAAQ,IACX,mBAAoB,QAAQ,IAAI,oBAAsB,QAAQ,IAAI,CACpE,CACF,CAAC,EAEK,MAAM,EACZ,KAAK,OAAO,KAAK,4DAAe,EAEzBe,EAAE,KAAK,KAAK,sBAAsB,KAAM,4CAAS,CAAC,CAC3D,OAASC,EAAO,CACd,KAAK,OAAO,MAAM,oDAAaA,CAAK,EACpC,IAAMC,EAAgB,KAAK,oBACzB,sBACAD,aAAiB,MAAQA,EAAM,QAAU,kDAC3C,EACA,OAAOD,EAAE,KAAKE,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,iBAAiBF,EAA+B,CACpD,GAAI,CACF,KAAK,OAAO,MAAM,8DAAY,EAI9B,IAAMG,EAAS,MAFG,MAAMC,GAAgB,GACP,IAAI,gBAAgB,EACjB,UAAU,EAE9C,YAAK,OAAO,MAAM,kDAAU,EACrBJ,EAAE,KAAK,KAAK,sBAAsBG,CAAM,CAAC,CAClD,OAASF,EAAO,CACd,KAAK,OAAO,MAAM,oDAAaA,CAAK,EACpC,IAAMC,EAAgB,KAAK,oBACzB,4BACAD,aAAiB,MAAQA,EAAM,QAAU,kDAC3C,EACA,OAAOD,EAAE,KAAKE,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,iBAAiBF,EAA+B,CACpD,GAAI,CACF,KAAK,OAAO,MAAM,0EAAc,EAGhC,IAAMO,EAAS,CACb,OAAQ,UACR,UAAW,KAAK,IAAI,EACpB,OAAQ,QAAQ,OAAO,EACvB,OAAQ,QAAQ,YAAY,EAC5B,QAAS,QAAQ,OACnB,EAEA,YAAK,OAAO,MAAM,8DAAY,EACvBP,EAAE,KAAK,KAAK,sBAAsBO,CAAM,CAAC,CAClD,OAASN,EAAO,CACd,KAAK,OAAO,MAAM,gEAAeA,CAAK,EACtC,IAAMC,EAAgB,KAAK,oBACzB,4BACAD,aAAiB,MAAQA,EAAM,QAAU,8DAC3C,EACA,OAAOD,EAAE,KAAKE,EAAe,GAAG,CAClC,CACF,CACF,IChSA,OAAS,cAAAM,OAAkB,KAC3B,OAAS,YAAAC,OAAgB,cACzB,OAAS,WAAAC,GAAS,QAAAC,MAAY,OAC9B,OAAS,iBAAAC,OAAqB,MAH9B,IAUaC,GAVbC,GAAAC,EAAA,kBAKAC,IAKaH,GAAN,KAAwB,CAV/B,MAU+B,CAAAI,EAAA,0BACrB,OACA,QAAyB,KAEjC,aAAc,CACZ,KAAK,OAASC,EAAO,QAAQ,mBAAmB,EAChD,KAAK,kBAAkB,CACzB,CAKQ,mBAA0B,CAChC,GAAI,CAEF,IAAMC,EAAYT,GAAQE,GAAc,YAAY,GAAG,CAAC,EAExD,KAAK,OAAO,MAAM,yCAAWO,CAAS,EAAE,EAKxC,IAAMC,EAAmB,CAIvBT,EAAKQ,EAAW,KAAM,KAAM,MAAO,MAAM,EACzCR,EAAKQ,EAAW,KAAM,MAAO,MAAM,EAGnCR,EAAKQ,EAAW,KAAM,KAAM,KAAK,EACjCR,EAAKQ,EAAW,KAAM,KAAK,EAG3BR,EAAKQ,EAAW,KAAM,KAAM,KAAM,MAAO,MAAM,EAC/CR,EAAKQ,EAAW,KAAM,KAAM,KAAM,KAAK,CACzC,EAGA,KAAK,QACHC,EAAiB,KAAMC,GAAM,CAC3B,IAAMC,EAASd,GAAWa,CAAC,EAC3B,YAAK,OAAO,MAAM,4BAAQA,CAAC,KAAKC,EAAS,eAAO,oBAAK,EAAE,EAChDA,CACT,CAAC,GAAK,KAEJ,KAAK,QACP,KAAK,OAAO,KAAK,qDAAa,KAAK,OAAO,EAAE,GAE5C,KAAK,OAAO,KAAK,wDAAW,EAC5B,KAAK,OAAO,MAAM,kCAAUF,CAAgB,EAEhD,OAASG,EAAO,CACd,KAAK,OAAO,MAAM,sEAAgBA,CAAK,CACzC,CACF,CAMA,MAAM,iBAAiBC,EAA+B,CACpD,IAAMC,EAAW,IAAI,IAAID,EAAE,IAAI,GAAG,EAAE,SAEpC,GAAI,CAGF,GAFA,KAAK,OAAO,MAAM,qDAAaC,CAAQ,EAAE,EAErC,CAAC,KAAK,QACR,OAAO,KAAK,gBAAgBD,EAAG,wDAAW,EAI5C,IAAIE,EAAWD,EAMf,GALIC,IAAa,MACfA,EAAW,eAITA,EAAS,SAAS,IAAI,EACxB,YAAK,OAAO,KAAK,qDAAaA,CAAQ,EAAE,EACjCF,EAAE,KAAK,YAAa,GAAG,EAGhC,IAAMG,EAAWhB,EAAK,KAAK,QAASe,CAAQ,EAG5C,GAAI,CAAClB,GAAWmB,CAAQ,EAAG,CAEzB,IAAMC,EAAYjB,EAAK,KAAK,QAAS,YAAY,EACjD,OAAIH,GAAWoB,CAAS,GACtB,KAAK,OAAO,MAAM,sCAAuBH,CAAQ,EAAE,EAC5C,KAAK,UAAUD,EAAGI,EAAW,WAAW,IAGjD,KAAK,OAAO,MAAM,mCAAUD,CAAQ,EAAE,EAC/BH,EAAE,KAAK,YAAa,GAAG,EAChC,CAGA,IAAMK,EAAc,KAAK,eAAeF,CAAQ,EAEhD,YAAK,OAAO,MACV,yCAAWA,CAAQ,mBAAmBE,CAAW,EACnD,EACO,KAAK,UAAUL,EAAGG,EAAUE,CAAW,CAChD,OAASN,EAAO,CACd,YAAK,OAAO,MAAM,qDAAaE,CAAQ,KAAMF,CAAK,EAC3CC,EAAE,KAAK,wBAAyB,GAAG,CAC5C,CACF,CAKA,MAAc,UACZA,EACAE,EACAG,EACmB,CACnB,GAAI,CACF,IAAMC,EAAU,MAAMrB,GAASiB,CAAQ,EAGvC,OACEG,EAAY,WAAW,OAAO,GAC9BA,EAAY,SAAS,YAAY,GACjCA,EAAY,SAAS,MAAM,EAEpBL,EAAE,KAAKM,EAAQ,SAAS,EAAG,IAAK,CAAE,eAAgBD,CAAY,CAAC,EAGjEL,EAAE,KAAKM,EAAS,IAAK,CAAE,eAAgBD,CAAY,CAAC,CAC7D,OAASN,EAAO,CACd,WAAK,OAAO,MAAM,yCAAWG,CAAQ,GAAIH,CAAK,EACxCA,CACR,CACF,CAKQ,eAAeG,EAA0B,CAC/C,IAAMK,EAAML,EAAS,MAAM,GAAG,EAAE,IAAI,GAAG,YAAY,EA2BnD,MAzB6C,CAC3C,KAAM,YACN,IAAK,YACL,GAAI,yBACJ,IAAK,yBACL,IAAK,WACL,KAAM,mBACN,IAAK,YACL,IAAK,aACL,KAAM,aACN,IAAK,YACL,IAAK,gBACL,IAAK,eACL,KAAM,YACN,MAAO,aACP,IAAK,WACL,IAAK,gCACL,IAAK,kBACL,IAAK,aACL,IAAK,kBACL,IAAK,kBACL,IAAK,oBACL,GAAI,kBACN,EAEoBK,GAAO,EAAE,GAAK,0BACpC,CAKQ,gBAAgBP,EAAYQ,EAA2B,CAC7D,IAAMC,EAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kDA6CaD,CAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAYtC,OAAOR,EAAE,KAAKS,CAAS,CACzB,CAKA,oBAA8B,CAC5B,OAAO,KAAK,UAAY,MAAQzB,GAAW,KAAK,OAAO,CACzD,CAKA,YAA4B,CAC1B,OAAO,KAAK,OACd,CAKA,qBAA4B,CAC1B,KAAK,kBAAkB,CACzB,CACF,IC1QA,IAwBa0B,GAxBbC,GAAAC,EAAA,kBACAC,IAuBaH,GAAN,KAAuB,CAxB9B,MAwB8B,CAAAI,EAAA,yBACpB,OACA,cAER,YAAYC,EAA8B,CACxC,KAAK,OAASC,EAAO,QAAQ,kBAAkB,EAC/C,KAAK,cAAgBD,CACvB,CAKQ,oBACNE,EACAC,EACAC,EACkB,CAClB,MAAO,CACL,MAAO,CACL,KAAAF,EACA,QAAAC,EACA,QAAAC,CACF,CACF,CACF,CAKQ,sBACNC,EACAF,EACuB,CACvB,MAAO,CACL,QAAS,GACT,KAAAE,EACA,QAAAF,CACF,CACF,CAMA,MAAM,UAAUG,EAA+B,CAC7C,GAAI,CACF,KAAK,OAAO,MAAM,kDAAU,EAC5B,IAAMC,EAAS,KAAK,cAAc,cAAc,EAChD,YAAK,OAAO,MAAM,sCAAQ,EACnBD,EAAE,KAAK,KAAK,sBAAsBC,CAAM,CAAC,CAClD,OAASC,EAAO,CACd,KAAK,OAAO,MAAM,wCAAWA,CAAK,EAClC,IAAMC,EAAgB,KAAK,oBACzB,oBACAD,aAAiB,MAAQA,EAAM,QAAU,sCAC3C,EACA,OAAOF,EAAE,KAAKG,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,gBAAgBH,EAA+B,CACnD,GAAI,CACF,KAAK,OAAO,MAAM,oEAAa,EAC/B,IAAMI,EAAe,KAAK,cAAc,gBAAgB,EACxD,YAAK,OAAO,MAAM,wDAAW,EACtBJ,EAAE,KAAK,KAAK,sBAAsBI,CAAY,CAAC,CACxD,OAASF,EAAO,CACd,KAAK,OAAO,MAAM,0DAAcA,CAAK,EACrC,IAAMC,EAAgB,KAAK,oBACzB,2BACAD,aAAiB,MAAQA,EAAM,QAAU,wDAC3C,EACA,OAAOF,EAAE,KAAKG,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,iBAAiBH,EAA+B,CACpD,GAAI,CACF,KAAK,OAAO,MAAM,8DAAY,EAC9B,IAAMK,EAAgB,KAAK,cAAc,iBAAiB,EAC1D,YAAK,OAAO,MAAM,kDAAU,EACrBL,EAAE,KAAK,KAAK,sBAAsBK,CAAa,CAAC,CACzD,OAASH,EAAO,CACd,KAAK,OAAO,MAAM,oDAAaA,CAAK,EACpC,IAAMC,EAAgB,KAAK,oBACzB,4BACAD,aAAiB,MAAQA,EAAM,QAAU,kDAC3C,EACA,OAAOF,EAAE,KAAKG,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,qBAAqBH,EAA+B,CACxD,GAAI,CACF,KAAK,OAAO,MAAM,oEAAa,EAC/B,IAAMM,EAAY,KAAK,cAAc,kBAAkB,EACvD,YAAK,OAAO,MAAM,+CAAYA,CAAS,EAAE,EAClCN,EAAE,KAAK,KAAK,sBAAsB,CAAE,UAAAM,CAAU,CAAC,CAAC,CACzD,OAASJ,EAAO,CACd,KAAK,OAAO,MAAM,0DAAcA,CAAK,EACrC,IAAMC,EAAgB,KAAK,oBACzB,gCACAD,aAAiB,MAAQA,EAAM,QAAU,wDAC3C,EACA,OAAOF,EAAE,KAAKG,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,iBAAiBH,EAA+B,CACpD,GAAI,CACF,KAAK,OAAO,MAAM,0EAAc,EAChC,IAAMO,EAAgB,KAAK,cAAc,iBAAiB,EAC1D,YAAK,OAAO,MAAM,8DAAY,EACvBP,EAAE,KAAK,KAAK,sBAAsB,CAAE,cAAAO,CAAc,CAAC,CAAC,CAC7D,OAASL,EAAO,CACd,KAAK,OAAO,MAAM,gEAAeA,CAAK,EACtC,IAAMC,EAAgB,KAAK,oBACzB,uBACAD,aAAiB,MAAQA,EAAM,QAAU,8DAC3C,EACA,OAAOF,EAAE,KAAKG,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,oBAAoBH,EAA+B,CACvD,GAAI,CACF,KAAK,OAAO,MAAM,yEAAkB,EACpC,IAAMQ,EAAU,KAAK,cAAc,oBAAoB,EACvD,YAAK,OAAO,MAAM,6DAAgB,EAC3BR,EAAE,KAAK,KAAK,sBAAsB,CAAE,QAAAQ,CAAQ,CAAC,CAAC,CACvD,OAASN,EAAO,CACd,KAAK,OAAO,MAAM,+DAAmBA,CAAK,EAC1C,IAAMC,EAAgB,KAAK,oBACzB,gCACAD,aAAiB,MAAQA,EAAM,QAAU,6DAC3C,EACA,OAAOF,EAAE,KAAKG,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,mBAAmBH,EAA+B,CACtD,GAAI,CACF,KAAK,OAAO,MAAM,oEAAa,EAC/B,IAAMS,EAAe,MAAMT,EAAE,IAAI,KAAK,EAGtC,GAAI,CAACS,GAAgB,OAAOA,GAAiB,SAAU,CACrD,IAAMN,EAAgB,KAAK,oBACzB,uBACA,gFACF,EACA,OAAOH,EAAE,KAAKG,EAAe,GAAG,CAClC,CAEA,YAAK,cAAc,iBAAiBM,EAAc,UAAU,EAC5D,KAAK,OAAO,KAAK,wDAAW,EAErBT,EAAE,KAAK,KAAK,sBAAsB,KAAM,wDAAW,CAAC,CAC7D,OAASE,EAAO,CACd,KAAK,OAAO,MAAM,0DAAcA,CAAK,EACrC,IAAMC,EAAgB,KAAK,oBACzB,6BACAD,aAAiB,MAAQA,EAAM,QAAU,wDAC3C,EACA,OAAOF,EAAE,KAAKG,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,oBAAoBH,EAA+B,CACvD,GAAI,CACF,KAAK,OAAO,MAAM,yEAAkB,EACpC,GAAM,CAAE,QAAAQ,CAAQ,EAAI,MAAMR,EAAE,IAAI,KAAK,EAGrC,GAAI,CAAC,MAAM,QAAQQ,CAAO,EAAG,CAC3B,IAAML,EAAgB,KAAK,oBACzB,uBACA,0DACF,EACA,OAAOH,EAAE,KAAKG,EAAe,GAAG,CAClC,CAEA,YAAK,cAAc,oBAAoBK,CAAO,EAC9C,KAAK,OAAO,KAAK,6DAAgB,EAE1BR,EAAE,KACP,KAAK,sBAAsB,KAAM,6DAAgB,CACnD,CACF,OAASE,EAAO,CACd,KAAK,OAAO,MAAM,+DAAmBA,CAAK,EAC1C,IAAMC,EAAgB,KAAK,oBACzB,kCACAD,aAAiB,MAAQA,EAAM,QAAU,6DAC3C,EACA,OAAOF,EAAE,KAAKG,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,YAAYH,EAA+B,CAC/C,GAAI,CACF,YAAK,OAAO,KAAK,kDAAU,EAC3B,KAAK,cAAc,MAAM,EACzB,KAAK,OAAO,KAAK,sCAAQ,EAClBA,EAAE,KAAK,KAAK,sBAAsB,KAAM,sCAAQ,CAAC,CAC1D,OAASE,EAAO,CACd,KAAK,OAAO,MAAM,wCAAWA,CAAK,EAClC,IAAMC,EAAgB,KAAK,oBACzB,qBACAD,aAAiB,MAAQA,EAAM,QAAU,sCAC3C,EACA,OAAOF,EAAE,KAAKG,EAAe,GAAG,CAClC,CACF,CACF,IC7QA,IA2BaO,GA3BbC,GAAAC,EAAA,kBAAAC,IAEAC,IAyBaJ,GAAN,KAA0B,CA3BjC,MA2BiC,CAAAK,EAAA,4BACvB,OACA,SACA,QAAwC,IAAI,IAC5C,aAAmD,IAAI,IACvD,aAAe,IAEvB,aAAc,CACZ,KAAK,OAASC,EAAO,QAAQ,qBAAqB,EAClD,KAAK,SAAWC,EAAY,EAC5B,KAAK,oBAAoB,CAC3B,CAKQ,qBAA4B,CAElC,KAAK,SAAS,QAAQ,iBAAmBC,GAAS,CAChD,KAAK,sBAAsBA,EAAK,MAAM,CACxC,CAAC,EAGD,KAAK,SAAS,QAAQ,iBAAmBA,GAAS,CAChD,KAAK,sBAAsBA,EAAK,MAAM,CACxC,CAAC,EAGD,KAAK,SAAS,QAAQ,0BAA4BA,GAAS,CACzD,KAAK,uBAAuB,aAAc,OAAWA,EAAK,SAAS,CACrE,CAAC,EAED,KAAK,SAAS,QAAQ,4BAA8BA,GAAS,CAC3D,KAAK,uBAAuB,YAAa,OAAWA,EAAK,SAAS,CACpE,CAAC,EAED,KAAK,SAAS,QAAQ,yBAA2BA,GAAS,CACxD,KAAK,uBAAuB,SAAUA,EAAK,MAAM,QAASA,EAAK,SAAS,CAC1E,CAAC,EAGD,KAAK,SAAS,QAAQ,yBAA2BA,GAAS,CACpDA,EAAK,OACP,KAAK,aAAaA,EAAK,OAAQA,EAAK,KAAMA,EAAK,IAAI,EAEnD,KAAK,UAAUA,EAAK,KAAMA,EAAK,IAAI,CAEvC,CAAC,CACH,CAKA,eAAeC,EAAkBC,EAAe,CAC9C,GAAI,CACF,IAAMC,EAA0B,CAC9B,GAAIF,EACJ,GAAAC,EACA,WAAYA,EAAG,WACf,KAAML,EAACG,GAAiB,CAClBE,EAAG,aAAe,GAEpBA,EAAG,KAAKF,CAAI,CAEhB,EALM,OAMR,EAEA,KAAK,QAAQ,IAAIC,EAAUE,CAAM,EACjC,KAAK,OAAO,KAAK,mDAAqBF,CAAQ,EAAE,EAChD,KAAK,OAAO,MAAM,+CAAY,KAAK,QAAQ,IAAI,EAAE,EAGjD,KAAK,mBAAmBA,CAAQ,EAGhC,KAAK,SAAS,UAAU,6BAA8B,CACpD,SAAAA,EACA,UAAW,KAAK,IAAI,CACtB,CAAC,CACH,OAASG,EAAO,CACd,KAAK,OAAO,MAAM,+CAAYH,CAAQ,GAAIG,CAAK,EAC/C,KAAK,SAAS,UAAU,qBAAsB,CAC5C,MAAOA,aAAiB,MAAQA,EAAQ,IAAI,MAAM,OAAOA,CAAK,CAAC,EAC/D,KAAM,iBACR,CAAC,CACH,CACF,CAKA,iBAAiBH,EAAwB,CACvC,GAAI,CACE,KAAK,QAAQ,IAAIA,CAAQ,IAC3B,KAAK,QAAQ,OAAOA,CAAQ,EAC5B,KAAK,aAAa,OAAOA,CAAQ,EACjC,KAAK,OAAO,KAAK,mDAAqBA,CAAQ,EAAE,EAChD,KAAK,OAAO,MAAM,+CAAY,KAAK,QAAQ,IAAI,EAAE,EAGjD,KAAK,SAAS,UAAU,gCAAiC,CACvD,SAAAA,EACA,UAAW,KAAK,IAAI,CACtB,CAAC,EAEL,OAASG,EAAO,CACd,KAAK,OAAO,MAAM,+CAAYH,CAAQ,GAAIG,CAAK,CACjD,CACF,CAKA,UAAUC,EAAcL,EAAkB,CACxC,IAAMM,EAA+B,CACnC,KAAAD,EACA,KAAAL,EACA,UAAW,KAAK,IAAI,CACtB,EAEA,KAAK,OAAO,MAAM,6BAASK,CAAI,GAAI,CAAE,YAAa,KAAK,QAAQ,IAAK,CAAC,EAErE,OAAW,CAACJ,EAAUE,CAAM,IAAK,KAAK,QACpC,KAAK,oBAAoBA,EAAQG,EAASL,CAAQ,CAEtD,CAKA,aAAaA,EAAkBI,EAAcL,EAAkB,CAC7D,IAAMM,EAA+B,CACnC,KAAAD,EACA,KAAAL,EACA,UAAW,KAAK,IAAI,CACtB,EAEMG,EAAS,KAAK,QAAQ,IAAIF,CAAQ,EACpCE,EACF,KAAK,oBAAoBA,EAAQG,EAASL,CAAQ,EAGlD,KAAK,aAAaA,EAAUK,CAAO,CAEvC,CAKQ,oBACNH,EACAG,EACAL,EACM,CACN,GAAI,CACF,GAAIE,EAAO,GAAG,aAAe,EAAG,CAE9B,IAAMI,EAAa,KAAK,UAAUD,CAAO,EACzCH,EAAO,KAAKI,CAAU,EACtB,KAAK,OAAO,MAAM,0DAAaN,CAAQ,KAAKK,EAAQ,IAAI,EAAE,CAC5D,MAEE,KAAK,aAAaL,EAAUK,CAAO,EACnC,KAAK,OAAO,KAAK,sBAAOL,CAAQ,iFAAgB,CAEpD,OAASG,EAAO,CACd,KAAK,OAAO,MAAM,oDAAYH,CAAQ,iBAAQG,CAAK,EACnD,KAAK,aAAaH,EAAUK,CAAO,EACnC,KAAK,SAAS,UAAU,qBAAsB,CAC5C,MAAOF,aAAiB,MAAQA,EAAQ,IAAI,MAAM,OAAOA,CAAK,CAAC,EAC/D,KAAM,cACR,CAAC,CACH,CACF,CAKQ,aAAaH,EAAkBK,EAAoC,CACpE,KAAK,aAAa,IAAIL,CAAQ,GACjC,KAAK,aAAa,IAAIA,EAAU,CAAC,CAAC,EAGpC,IAAMO,EAAQ,KAAK,aAAa,IAAIP,CAAQ,EAC5CO,EAAM,KAAKF,CAAO,EAGdE,EAAM,OAAS,KAAK,eACtBA,EAAM,MAAM,EACZ,KAAK,OAAO,KAAK,sBAAOP,CAAQ,iFAAgB,EAEpD,CAKQ,mBAAmBA,EAAwB,CACjD,IAAMO,EAAQ,KAAK,aAAa,IAAIP,CAAQ,EAC5C,GAAI,CAACO,GAASA,EAAM,SAAW,EAC7B,OAGF,IAAML,EAAS,KAAK,QAAQ,IAAIF,CAAQ,EACxC,GAAKE,EAIL,MAAK,OAAO,KAAK,gBAAMK,EAAM,MAAM,2DAAcP,CAAQ,EAAE,EAE3D,QAAWK,KAAWE,EACpB,KAAK,oBAAoBL,EAAQG,EAASL,CAAQ,EAIpD,KAAK,aAAa,OAAOA,CAAQ,EACnC,CAKA,sBAAsBQ,EAAyB,CAC7C,KAAK,UAAU,eAAgBA,CAAM,CACvC,CAKA,sBAAsBC,EAA0B,CAC9C,KAAK,UAAU,eAAgBA,CAAM,CACvC,CAKA,uBACEA,EACAN,EACAO,EACM,CACN,IAAMC,EAA+B,CACnC,OAAAF,EACA,MAAAN,EACA,UAAWO,GAAa,KAAK,IAAI,CACnC,EAEA,KAAK,UAAU,gBAAiBC,CAAa,CAC/C,CAKA,gBAIE,CACA,IAAMC,EAAmB,MAAM,KAAK,KAAK,QAAQ,OAAO,CAAC,EAAE,OACxDV,GAAWA,EAAO,GAAG,aAAe,CACvC,EAAE,OAEIW,EAAiB,MAAM,KAAK,KAAK,aAAa,OAAO,CAAC,EAAE,OAC5D,CAACC,EAAOP,IAAUO,EAAQP,EAAM,OAChC,CACF,EAEA,MAAO,CACL,aAAc,KAAK,QAAQ,KAC3B,iBAAAK,EACA,eAAAC,CACF,CACF,CAKA,4BAAmC,CACjC,IAAME,EAAgC,CAAC,EAEvC,OAAW,CAACf,EAAUE,CAAM,IAAK,KAAK,QAChCA,EAAO,GAAG,aAAe,GAE3Ba,EAAoB,KAAKf,CAAQ,EAIrC,QAAWA,KAAYe,EACrB,KAAK,iBAAiBf,CAAQ,EAG5Be,EAAoB,OAAS,GAC/B,KAAK,OAAO,KAAK,sBAAOA,EAAoB,MAAM,6CAAU,CAEhE,CAKA,SAAgB,CACd,KAAK,OAAO,KAAK,sCAAQ,EACzB,KAAK,QAAQ,MAAM,EACnB,KAAK,aAAa,MAAM,CAC1B,CACF,ICzUA,IAyBaC,GAzBbC,GAAAC,EAAA,kBAAAC,IACAC,IAwBaJ,GAAN,KAAoB,CAzB3B,MAyB2B,CAAAK,EAAA,sBACjB,OACA,SACA,WAAyB,CAC/B,OAAQ,eACR,YAAa,GACb,iBAAkB,CAAC,CACrB,EACQ,cACA,iBACS,kBAAoB,KAErC,aAAc,CACZ,KAAK,OAASC,EAAO,QAAQ,eAAe,EAC5C,KAAK,SAAWC,EAAY,CAC9B,CAKA,iBAA8B,CAC5B,MAAO,CAAE,GAAG,KAAK,UAAW,CAC9B,CAKA,iBAAiBC,EAA2BC,EAAS,UAAiB,CACpE,GAAI,CACF,IAAMC,EAAY,CAAE,GAAG,KAAK,UAAW,EACvC,KAAK,WAAa,CAAE,GAAG,KAAK,WAAY,GAAGF,CAAK,EAE5CA,EAAK,gBACP,KAAK,WAAW,cAAgB,KAAK,IAAI,GAIvCA,EAAK,SAAW,aAClB,KAAK,sBAAsB,EAG7B,KAAK,OAAO,MAAM,iEAAeC,CAAM,GAAI,CACzC,IAAKC,EACL,IAAK,KAAK,UACZ,CAAC,EAGD,KAAK,SAAS,UAAU,iBAAkB,CACxC,OAAQ,KAAK,WACb,OAAAD,CACF,CAAC,CACH,OAASE,EAAO,CACd,KAAK,OAAO,MAAM,0DAAcA,CAAK,EACrC,KAAK,SAAS,UAAU,eAAgB,CACtC,MAAOA,aAAiB,MAAQA,EAAQ,IAAI,MAAM,OAAOA,CAAK,CAAC,EAC/D,UAAW,kBACb,CAAC,CACH,CACF,CAKA,kBAA8C,CAC5C,OAAO,KAAK,cAAgB,CAAE,GAAG,KAAK,aAAc,EAAI,MAC1D,CAKA,oBACEC,EACAD,EACM,CACN,GAAI,CAUF,OATA,KAAK,cAAgB,CACnB,OAAAC,EACA,MAAAD,EACA,UAAW,KAAK,IAAI,CACtB,EAEA,KAAK,OAAO,KAAK,yCAAWC,CAAM,GAAI,CAAE,MAAAD,CAAM,CAAC,EAGvCC,EAAQ,CACd,IAAK,aACH,KAAK,SAAS,UAAU,0BAA2B,CACjD,UAAW,KAAK,cAAc,SAChC,CAAC,EACD,MACF,IAAK,YACH,KAAK,SAAS,UAAU,4BAA6B,CACnD,UAAW,KAAK,cAAc,SAChC,CAAC,EACD,MACF,IAAK,SACH,KAAK,SAAS,UAAU,yBAA0B,CAChD,MAAO,IAAI,MAAMD,GAAS,0BAAM,EAChC,UAAW,KAAK,cAAc,SAChC,CAAC,EACD,KACJ,CACF,OAASA,EAAO,CACd,KAAK,OAAO,MAAM,oDAAaA,CAAK,EACpC,KAAK,SAAS,UAAU,eAAgB,CACtC,MAAOA,aAAiB,MAAQA,EAAQ,IAAI,MAAM,OAAOA,CAAK,CAAC,EAC/D,UAAW,qBACb,CAAC,CACH,CACF,CAKA,eAIE,CACA,MAAO,CACL,OAAQ,KAAK,gBAAgB,EAC7B,QAAS,KAAK,iBAAiB,EAC/B,UAAW,KAAK,IAAI,CACtB,CACF,CAKQ,uBAA8B,CAEhC,KAAK,kBACP,aAAa,KAAK,gBAAgB,EAIpC,KAAK,iBAAmB,WAAW,IAAM,CACvC,KAAK,OAAO,KAAK,4FAAiB,EAClC,KAAK,iBAAiB,CAAE,OAAQ,cAAe,EAAG,mBAAmB,CACvE,EAAG,KAAK,iBAAiB,CAC3B,CAKA,uBAA8B,CACxB,KAAK,mBACP,aAAa,KAAK,gBAAgB,EAClC,KAAK,iBAAmB,OAE5B,CAKA,mBAA6B,CAC3B,OAAO,KAAK,WAAW,SAAW,WACpC,CAKA,kBAAuC,CACrC,OAAO,KAAK,WAAW,aACzB,CAKA,qBAAgC,CAC9B,MAAO,CAAC,GAAG,KAAK,WAAW,gBAAgB,CAC7C,CAKA,oBAAoBE,EAAyB,CAC3C,KAAK,iBACH,CAAE,iBAAkB,CAAC,GAAGA,CAAO,CAAE,EACjC,oBACF,CACF,CAKA,eAAeC,EAAwB,CACrC,KAAK,iBAAiB,CAAE,YAAaA,CAAS,EAAG,qBAAqB,CACxE,CAKA,OAAc,CACZ,KAAK,OAAO,KAAK,sCAAQ,EACzB,KAAK,sBAAsB,EAC3B,KAAK,WAAa,CAChB,OAAQ,eACR,YAAa,GACb,iBAAkB,CAAC,CACrB,EACA,KAAK,cAAgB,MACvB,CAKA,SAAgB,CACd,KAAK,OAAO,KAAK,sCAAQ,EACzB,KAAK,sBAAsB,EAC3B,KAAK,MAAM,CACb,CACF,IC7OA,IAAAC,GAAA,GAAAC,EAAAD,GAAA,eAAAE,KAAA,OAAS,gBAAAC,OAAoB,OAC7B,OAAS,SAAAC,OAAa,oBACtB,OAAS,QAAAC,OAAY,OACrB,OAAS,QAAAC,OAAY,YACrB,OAAS,mBAAAC,OAAuB,KAJhC,IA4DaL,GA5DbM,GAAAC,EAAA,kBAKAC,IACAC,KACAC,KAEAC,IAIAC,KAEAC,KAEAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KAEAC,IAKAC,KACAC,KA6BavB,GAAN,KAAgB,CA5DvB,MA4DuB,CAAAwB,EAAA,kBACb,IACA,WAAkB,KAClB,IAA8B,KAC9B,OACA,KAGA,SAGA,cACA,cACA,oBAGA,iBACA,iBACA,kBACA,kBAGA,4BACA,iBAGA,yBAGA,eACA,yBACA,kBAMA,oBACNC,EACAC,EACAC,EACkB,CAClB,MAAO,CACL,MAAO,CACL,KAAAF,EACA,QAAAC,EACA,QAAAC,CACF,CACF,CACF,CAMQ,sBACNC,EACAF,EACuB,CACvB,MAAO,CACL,QAAS,GACT,KAAAE,EACA,QAAAF,CACF,CACF,CAMQ,sBAAsBG,EAAiBC,EAA2B,CACxE,KAAK,OAAO,KACV,gBAAgBD,CAAO,2DAAcC,CAAW,eAClD,CACF,CAEA,YAAYC,EAAe,CAEzB,GAAI,CACF,KAAK,KAAOA,GAAQC,EAAc,aAAa,GAAK,IACtD,MAAgB,CAEd,KAAK,KAAOD,GAAQ,IACtB,CACA,KAAK,OAASE,EAAO,QAAQ,WAAW,EAGxC,KAAK,SAAWC,EAAY,EAG5B,KAAK,cAAgB,IAAIC,EACzB,KAAK,cAAgB,IAAIC,GACzB,KAAK,oBAAsB,IAAIC,GAG/B,KAAK,iBAAmB,IAAIC,GAC5B,KAAK,iBAAmB,IAAIC,GAAiB,KAAK,aAAa,EAC/D,KAAK,kBAAoB,IAAIC,GAAkB,KAAK,aAAa,EACjE,KAAK,kBAAoB,IAAIC,GAG7B,KAAK,4BAA8B,IAAIC,GACrC,KAAK,oBACL,KAAK,aACP,EACA,KAAK,iBAAmB,IAAIC,GAC1B,KAAK,cACL,KAAK,mBACP,EAGA,KAAK,IAAM,IAAIxC,GACf,KAAK,gBAAgB,EACrB,KAAK,YAAY,EAEjB,KAAK,OAAO,KAAK,+GAA+B,CAGlD,CAKA,MAAc,uBAAuC,CACnD,GAAI,CACF,KAAK,OAAO,KAAK,+CAAY,EAG7B,IAAMyC,EAAS,MAAM,KAAK,kBAAkB,EAG5C,KAAK,kBAAoB,MAAMC,GAA2B,YAAY,EAGtE,MAAM,KAAK,0BAA0BD,EAAO,UAAU,EAGtD,IAAME,EAAQ,KAAK,kBAAkB,YAAY,EACjD,KAAK,OAAO,KAAK,sBAAOA,EAAM,MAAM,qBAAM,EAG1C,MAAM,KAAK,4BAA4BF,EAAO,YAAaE,CAAK,EAEhE,KAAK,OAAO,KAAK,wDAAW,CAC9B,OAASC,EAAO,CACd,WAAK,OAAO,MAAM,8CAAYA,CAAK,EAC7BA,CACR,CACF,CAKA,MAAc,mBAIX,CACD,GAAI,CAACf,EAAc,aAAa,EAC9B,MAAM,IAAI,MAAM,wHAAmC,EAKrDA,EAAc,gCAAgC,EAE9C,IAAMY,EAASZ,EAAc,UAAU,EAEvC,MAAO,CACL,YAAaY,EAAO,YACpB,WAAYA,EAAO,WACnB,UAAWA,EAAO,OAAO,MAAQ,IACnC,CACF,CAKA,MAAc,0BACZI,EACe,CACf,GAAI,CAAC,KAAK,kBACR,MAAM,IAAI,MAAM,4CAAwB,EAG1C,OAAW,CAACC,EAAML,CAAM,IAAK,OAAO,QAAQI,CAAU,EAAG,CACvD,KAAK,OAAO,KAAK,8CAAgBC,CAAI,EAAE,EAEvC,IAAMC,EAAgBC,GAAmBF,EAAML,CAAM,EACrD,KAAK,kBAAkB,iBAAiBK,EAAMC,CAAa,CAC7D,CAEA,MAAM,KAAK,kBAAkB,iBAAiB,EAC9C,KAAK,OAAO,KAAK,iDAAc,CACjC,CAKA,MAAc,4BACZE,EACAN,EACe,CAGf,IAAMO,GADY,MAAM,QAAQD,CAAW,EAAIA,EAAc,CAACA,CAAW,GACxC,OAC9BE,GAAOA,GAAM,CAACA,EAAG,SAAS,qBAAM,CACnC,EAEA,GAAID,EAAe,SAAW,EAAG,CAC/B,KAAK,OAAO,KAAK,kGAAkB,EACnC,MACF,CAEA,KAAK,OAAO,KACV,iHAAuBA,EAAe,MAAM,EAC9C,EACA,KAAK,OAAO,MAAM,wCAAWA,CAAc,EAE3C,GAAI,CAEF,KAAK,yBACH,MAAME,GAAkC,YAAY,CAClD,oBAAqB,IACrB,kBAAmB,IACnB,qBAAsB,GACtB,oBAAqB,cACrB,kBAAmB,GACrB,CAAC,EAGC,KAAK,mBACP,KAAK,yBAAyB,kBAAkB,KAAK,iBAAiB,EAIxE,MAAM,KAAK,yBAAyB,WAAWF,EAAgBP,CAAK,EAGpE,MAAM,KAAK,yBAAyB,QAAQ,EAG5C,KAAK,yBAAyB,GAAG,eAAiBU,GAAe,CAC/D,KAAK,OAAO,KAAK,qDAAaA,EAAM,IAAI,GAAIA,EAAM,IAAI,CACxD,CAAC,EAED,KAAK,OAAO,KACV,gHAAsBH,EAAe,MAAM,qBAC7C,CACF,OAASN,EAAO,CACd,KAAK,OAAO,MAAM,8FAAoBA,CAAK,EAG3C,KAAK,OAAO,KAAK,kDAAU,EAC3B,IAAMU,EAAgBJ,EAAe,CAAC,EAEtC,KAAK,OAAO,KAAK,6EAAiBI,CAAa,EAAE,EACjD,KAAK,eAAiB,IAAIC,EAAeD,CAAa,EAElD,KAAK,mBACP,KAAK,eAAe,kBAAkB,KAAK,iBAAiB,EAI9D,MAAM,KAAK,iBACT,IAAM,KAAK,eAAgB,QAAQ,EACnC,4CACF,EACA,KAAK,OAAO,KAAK,kGAAkB,CACrC,CACF,CAKQ,0BAAkD,CACxD,OAAI,KAAK,yBACA,KAAK,yBAAyB,qBAAqB,EAErD,KAAK,gBAAkB,IAChC,CAKA,4BAAkC,CAChC,OAAI,KAAK,yBACA,CACL,KAAM,iBACN,QAAS,CACP,mBACE,KAAK,yBAAyB,sBAAsB,EAAE,OACxD,iBACE,KAAK,yBAAyB,oBAAoB,EAAE,OACtD,iBAAkB,KAAK,yBAAyB,oBAAoB,EACpE,iBAAkB,KAAK,yBAAyB,oBAAoB,EACpE,eAAgB,KAAK,yBAAyB,kBAAkB,CAClE,EACA,YAAa,KAAK,yBAAyB,oBAAoB,CACjE,EAGE,KAAK,eACA,CACL,KAAM,kBACN,UAAW,GACX,SAAU,SACZ,EAGK,CACL,KAAM,OACN,UAAW,EACb,CACF,CAKA,MAAc,iBACZE,EACAC,EACAC,EAAc,EACdC,EAAe,IACfC,EAAW,IACXC,EAAoB,EACR,CACZ,IAAIC,EAA0B,KAE9B,QAASC,EAAU,EAAGA,GAAWL,EAAaK,IAC5C,GAAI,CACF,YAAK,OAAO,KAAK,GAAGN,CAAO,gCAAYM,CAAO,IAAIL,CAAW,GAAG,EACzD,MAAMF,EAAa,CAC5B,OAASZ,EAAO,CAId,GAHAkB,EAAYlB,EACZ,KAAK,OAAO,KAAK,GAAGa,CAAO,+BAAYb,CAAK,EAExCmB,EAAUL,EAAa,CACzB,IAAMM,EAAQ,KAAK,IACjBL,EAAeE,IAAsBE,EAAU,GAC/CH,CACF,EACA,KAAK,OAAO,KAAK,GAAGH,CAAO,MAAMO,CAAK,0BAAW,EACjD,MAAM,KAAK,MAAMA,CAAK,CACxB,CACF,CAGF,MAAM,IAAI,MACR,GAAGP,CAAO,4FAAsBK,GAAW,OAAO,EACpD,CACF,CAKQ,MAAMG,EAA2B,CACvC,OAAO,IAAI,QAASC,GAAY,WAAWA,EAASD,CAAE,CAAC,CACzD,CAEQ,iBAAkB,CAExB,KAAK,KAAK,IACR,IACAhE,GAAK,CACH,OAAQ,IACR,aAAc,CAAC,MAAO,OAAQ,MAAO,SAAS,EAC9C,aAAc,CAAC,cAAc,CAC/B,CAAC,CACH,EAGA,KAAK,KAAK,QAAQ,CAACkE,EAAKC,IAAM,CAC5B,KAAK,OAAO,MAAM,sBAAuBD,CAAG,EAC5C,IAAME,EAAgB,KAAK,oBACzB,wBACA,6CACA,QAAQ,IAAI,WAAa,cAAgBF,EAAI,MAAQ,MACvD,EACA,OAAOC,EAAE,KAAKC,EAAe,GAAG,CAClC,CAAC,CACH,CAEQ,aAAc,CAEpB,KAAK,KAAK,IAAI,cAAgBD,GAAM,KAAK,iBAAiB,UAAUA,CAAC,CAAC,EACtE,KAAK,KAAK,IAAI,cAAgBA,GAAM,KAAK,iBAAiB,aAAaA,CAAC,CAAC,EACzE,KAAK,KAAK,IAAI,2BAA6BA,GACzC,KAAK,iBAAiB,eAAeA,CAAC,CACxC,EACA,KAAK,KAAK,IAAI,4BAA8BA,GAC1C,KAAK,iBAAiB,gBAAgBA,CAAC,CACzC,EACA,KAAK,KAAK,IAAI,0BAA4BA,GACxC,KAAK,iBAAiB,cAAcA,CAAC,CACvC,EACA,KAAK,KAAK,IAAI,yBAA2BA,GACvC,KAAK,iBAAiB,oBAAoBA,CAAC,CAC7C,EACA,KAAK,KAAK,KAAK,qBAAuBA,GACpC,KAAK,iBAAiB,aAAaA,CAAC,CACtC,EACA,KAAK,KAAK,IAAI,mBAAqBA,GACjC,KAAK,iBAAiB,cAAcA,CAAC,CACvC,EACA,KAAK,KAAK,IAAI,qBAAuBA,GACnC,KAAK,iBAAiB,kBAAkBA,CAAC,CAC3C,EAGA,KAAK,KAAK,IAAI,cAAgBA,GAAM,KAAK,iBAAiB,UAAUA,CAAC,CAAC,EACtE,KAAK,KAAK,IAAI,qBAAuBA,GACnC,KAAK,iBAAiB,gBAAgBA,CAAC,CACzC,EACA,KAAK,KAAK,IAAI,sBAAwBA,GACpC,KAAK,iBAAiB,iBAAiBA,CAAC,CAC1C,EACA,KAAK,KAAK,IAAI,wBAA0BA,GACtC,KAAK,iBAAiB,qBAAqBA,CAAC,CAC9C,EACA,KAAK,KAAK,IAAI,wBAA0BA,GACtC,KAAK,iBAAiB,iBAAiBA,CAAC,CAC1C,EACA,KAAK,KAAK,IAAI,0BAA4BA,GACxC,KAAK,iBAAiB,oBAAoBA,CAAC,CAC7C,EACA,KAAK,KAAK,IAAI,qBAAuBA,GACnC,KAAK,iBAAiB,mBAAmBA,CAAC,CAC5C,EACA,KAAK,KAAK,IAAI,0BAA4BA,GACxC,KAAK,iBAAiB,oBAAoBA,CAAC,CAC7C,EACA,KAAK,KAAK,KAAK,oBAAsBA,GACnC,KAAK,iBAAiB,YAAYA,CAAC,CACrC,EAGA,KAAK,KAAK,KAAK,wBAA0BA,GACvC,KAAK,kBAAkB,eAAeA,CAAC,CACzC,EACA,KAAK,KAAK,KAAK,qBAAuBA,GACpC,KAAK,kBAAkB,YAAYA,CAAC,CACtC,EACA,KAAK,KAAK,KAAK,sBAAwBA,GACrC,KAAK,kBAAkB,aAAaA,CAAC,CACvC,EACA,KAAK,KAAK,IAAI,uBAAyBA,GACrC,KAAK,kBAAkB,iBAAiBA,CAAC,CAC3C,EACA,KAAK,KAAK,IAAI,uBAAyBA,GACrC,KAAK,kBAAkB,iBAAiBA,CAAC,CAC3C,EAGA,KAAK,KAAK,IAAI,SAAU,MAAOA,GAAM,CACnC,IAAMC,EAAgB,KAAK,oBACzB,gBACA,uCAAcD,EAAE,IAAI,IAAI,EAC1B,EACA,OAAOA,EAAE,KAAKC,EAAe,GAAG,CAClC,CAAC,EAGD,KAAK,IAAI,IAAI,IAAMD,GAAM,KAAK,kBAAkB,iBAAiBA,CAAC,CAAC,CACrE,CAEQ,gBAAiB,CAClB,KAAK,KAEV,KAAK,IAAI,GAAG,aAAeE,GAAO,CAEhC,IAAMC,EAAW,UAAU,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,OAAO,EAAG,CAAC,CAAC,GAEhF,KAAK,OAAO,KAAK,mDAAqBA,CAAQ,EAAE,EAChD,KAAK,OAAO,MACV,8CAAqB,KAAK,KAAK,QAAQ,MAAQ,CAAC,EAClD,EAGA,KAAK,4BAA4B,oBAAoBD,EAAIC,CAAQ,EACjE,KAAK,iBAAiB,oBAAoBA,CAAQ,EAElDD,EAAG,GAAG,UAAW,MAAO/C,GAAY,CAClC,GAAI,CACF,IAAME,EAAO,KAAK,MAAMF,EAAQ,SAAS,CAAC,EAGtCE,EAAK,OAAS,eAChB,MAAM,KAAK,iBAAiB,mBAAmB6C,EAAI7C,EAAM8C,CAAQ,EAEjE,MAAM,KAAK,4BAA4B,cACrCD,EACA7C,EACA8C,CACF,CAEJ,OAAS3B,EAAO,CACd,KAAK,OAAO,MAAM,2BAA4BA,CAAK,EACnD,IAAMyB,EAAgB,CACpB,KAAM,QACN,MAAO,CACL,KAAM,sBACN,QAASzB,aAAiB,MAAQA,EAAM,QAAU,uCAClD,UAAW,KAAK,IAAI,CACtB,CACF,EACA0B,EAAG,KAAK,KAAK,UAAUD,CAAa,CAAC,CACvC,CACF,CAAC,EAEDC,EAAG,GAAG,QAAS,IAAM,CACnB,KAAK,OAAO,KAAK,+DAAuBC,CAAQ,EAAE,EAClD,KAAK,OAAO,MACV,8CAAqB,KAAK,KAAK,QAAQ,MAAQ,CAAC,EAClD,EAGA,KAAK,4BAA4B,uBAAuBA,CAAQ,EAChE,KAAK,iBAAiB,uBAAuBA,CAAQ,CACvD,CAAC,EAEDD,EAAG,GAAG,QAAU1B,GAAU,CACxB,KAAK,OAAO,MAAM,uCAAmB2B,CAAQ,KAAM3B,CAAK,CAC1D,CAAC,EAGD,KAAK,4BAA4B,gBAAgB0B,EAAIC,CAAQ,CAC/D,CAAC,CACH,CAEA,MAAa,OAAuB,CAElC,GAAI,KAAK,WAAY,CACnB,KAAK,OAAO,KAAK,+BAA+B,EAChD,MACF,CAGA,IAAMC,EAASzE,GAAM,CACnB,MAAO,KAAK,IAAI,MAChB,KAAM,KAAK,KACX,SAAU,UACV,aAAAD,EACF,CAAC,EAGD,KAAK,WAAa0E,EAGlB,KAAK,IAAM,IAAItE,GAAgB,CAAE,OAAQ,KAAK,UAAW,CAAC,EAC1D,KAAK,eAAe,EAGpB,KAAK,yBACH,KAAK,iBAAiB,yBAAyB,EAEjD,KAAK,OAAO,KAAK,0CAA0C,KAAK,IAAI,EAAE,EACtE,KAAK,OAAO,KAAK,kCAAkC,KAAK,IAAI,EAAE,EAG9D,KAAK,OAAO,KAAK,iGAA2B,EAC5C,KAAK,OAAO,KAAK,sFAA+B,EAChD,KAAK,OAAO,KACV,0FACF,EACA,KAAK,OAAO,KAAK,8GAA8B,EAC/C,KAAK,OAAO,KAAK,oHAA+B,EAChD,KAAK,OAAO,KAAK,qHAAgC,EACjD,KAAK,OAAO,KACV,mHACF,EACA,KAAK,OAAO,KAAK,qHAAwC,EACzD,KAAK,OAAO,KAAK,kDAAkD,EAGnE,GAAI,CACF,MAAM,KAAK,sBAAsB,EACjC,KAAK,OAAO,KAAK,wDAAW,CAC9B,OAAS0C,EAAO,CACd,KAAK,OAAO,MAAM,yGAA0BA,CAAK,CAEnD,CACF,CAEO,MAAsB,CAC3B,OAAO,IAAI,QAASsB,GAAY,CAC9B,IAAIO,EAAW,GAETC,EAAYrD,EAAA,IAAM,CACjBoD,IACHA,EAAW,GACXP,EAAQ,EAEZ,EALkB,aAmBlB,GAXA,KAAK,gBAAgB,WAAW,EAG5B,KAAK,2BACP,KAAK,iBAAiB,wBACpB,KAAK,wBACP,EACA,KAAK,yBAA2B,QAI9B,KAAK,IAAK,CACZ,QAAWS,KAAU,KAAK,IAAI,QAC5BA,EAAO,UAAU,EAInB,KAAK,IAAI,MAAM,IAAM,CAEf,KAAK,WACP,KAAK,WAAW,MAAM,IAAM,CAC1B,KAAK,OAAO,KAAK,oBAAoB,EACrCD,EAAU,CACZ,CAAC,GAED,KAAK,OAAO,KAAK,oBAAoB,EACrCA,EAAU,GAIZ,WAAW,IAAM,CACf,KAAK,OAAO,KAAK,0BAA0B,EAC3CA,EAAU,CACZ,EAAG,GAAI,CACT,CAAC,CACH,MACE,KAAK,OAAO,KAAK,oBAAoB,EACrCA,EAAU,CAEd,CAAC,CACH,CAKO,SAAgB,CACrB,KAAK,OAAO,KAAK,qCAAiB,EAG9B,KAAK,2BACP,KAAK,iBAAiB,wBACpB,KAAK,wBACP,EACA,KAAK,yBAA2B,QAIlC,KAAK,cAAc,QAAQ,EAC3B,KAAK,oBAAoB,QAAQ,EAGjCE,GAAgB,EAGhB,KAAK,gBAAgB,WAAW,EAEhC,KAAK,OAAO,KAAK,0CAAiB,CACpC,CACF,ICjsBA,OAAS,SAAAC,OAAa,gBAXtB,eAAeC,IAAgB,CAC7B,IAAMC,EAAkB,KAAM,uCACxBC,EAAe,KAAM,sCACrBC,EAAe,KAAM,sCAC3B,MAAO,CACL,UAAWF,EAAgB,UAC3B,cAAeC,EAAa,cAC5B,OAAQC,EAAa,MACvB,CACF,CATeC,EAAAJ,GAAA,iBAaf,eAAeK,IAAO,CAEpB,IAAMC,EADO,QAAQ,KAAK,MAAM,CAAC,EACR,SAAS,gBAAgB,EAElD,GAAI,CAEF,GAAM,CAAE,UAAAC,EAAW,cAAAC,EAAe,OAAAC,CAAO,EAAI,MAAMT,GAAc,EAG7D,QAAQ,IAAI,qBACdS,EAAO,YAAY,QAAQ,IAAI,kBAAkB,EACjDA,EAAO,kBAAkB,EAAI,GAI/B,IAAMC,EAAY,IAAIH,EAMtB,GALA,MAAMG,EAAU,MAAM,EAEtBD,EAAO,KAAK,2DAAuC,EAG/CH,EAAa,CAEf,IAAMK,EAAM,oBADCH,EAAc,aAAa,CACJ,GACpC,MAAMI,GAAeD,CAAG,CAC1B,CAGA,IAAME,EAAUT,EAAA,SAAY,CAC1BK,EAAO,KAAK,8DAA0C,EACtD,MAAMC,EAAU,KAAK,EACrB,QAAQ,KAAK,CAAC,CAChB,EAJgB,WAMhB,QAAQ,GAAG,SAAUG,CAAO,EAC5B,QAAQ,GAAG,UAAWA,CAAO,CAC/B,OAASC,EAAO,CACd,QAAQ,MAAM,sCAAmBA,CAAK,EACtC,QAAQ,KAAK,CAAC,CAChB,CACF,CAxCeV,EAAAC,GAAA,QA6Cf,eAAeO,GAAeD,EAA4B,CACxD,GAAI,CACF,IAAMI,EAAW,QAAQ,SAErBC,EACAC,EAEAF,IAAa,UACfC,EAAU,OACVC,EAAO,CAACN,CAAG,GACFI,IAAa,SACtBC,EAAU,QACVC,EAAO,CAAC,GAAIN,CAAG,IAEfK,EAAU,WACVC,EAAO,CAACN,CAAG,GAGbO,GAAMF,EAASC,EAAM,CAAE,SAAU,GAAM,MAAO,QAAS,CAAC,EACxD,QAAQ,IAAI,qDAAaN,CAAG,EAAE,CAChC,OAASG,EAAO,CACd,QAAQ,KAAK,0DAAcA,CAAK,CAClC,CACF,CAvBeV,EAAAQ,GAAA,kBA0BX,YAAY,MAAQ,UAAU,QAAQ,KAAK,CAAC,CAAC,IAC/CP,GAAK","names":["Logger_exports","__export","Logger","logger","fs","path","chalk","pino","formatDateTime","date","year","month","day","hours","minutes","seconds","init_Logger","__esmMin","__name","streams","consoleStream","_label","number","err","levelMap","chunk","logObj","message","content","timestamp","levelInfo","text","coloredLevel","argsStr","arg","projectDir","enable","messageOrObj","args","errorArgs","enhancedObj","obj","enhanced","key","value","logDir","logName","i","oldFile","newFile","firstRotatedFile","maxSize","maxFiles","_tag","WebSocket","ToolCallError","ProxyMCPServer","init_ProxyMCPServer","__esmMin","init_Logger","code","message","data","__name","endpointUrl","options","logger","serviceManager","allTools","newTools","toolInfo","error","name","tool","tools","resolve","reject","reason","interval","jitterRange","jitter","request","toolsList","id","result","response","requestId","callRecord","params","errorCode","errorMessage","toolName","arguments_","lastError","attempt","delay","timeoutMs","timeoutId","duration","errorResponse","record","success","totalTime","r","sum","completedCalls","limit","records","config","SSEClientTransport","StdioClientTransport","StreamableHTTPClientTransport","EventSource","getLogger","logger","createTransport","config","createStdioTransport","createSSETransport","createModelScopeSSETransport","createStreamableHTTPTransport","url","options","createSSEOptions","createModelScopeSSEOptions","createStreamableHTTPOptions","token","__name","init","headers","validateConfig","getSupportedTypes","TransportFactory","init_TransportFactory","__esmMin","init_Logger","init_MCPService","Client","MCPTransportType","MCPService","init_MCPService","__esmMin","init_Logger","init_TransportFactory","__name","config","options","logger","level","message","args","taggedMessage","TransportFactory","resolve","reject","error","interval","jitterRange","jitter","tools","tool","t","name","arguments_","result","startTime","pingPromise","timeoutPromise","_","duration","connectionError","wasEnabled","isAbsolute","resolve","convertLegacyToNew","serviceName","legacyConfig","logger","ConfigValidationError","newConfig","convertByConfigType","validateNewConfig","error","isLocalConfig","convertLocalConfig","isSSEConfig","convertSSEConfig","isStreamableHTTPConfig","convertStreamableHTTPConfig","config","workingDir","resolvedArgs","arg","isRelativePath","resolvedPath","isModelScope","isModelScopeURL","baseConfig","path","url","MCPTransportType","init_ConfigAdapter","__esmMin","init_Logger","init_MCPService","message","configName","__name","getMcpServerCommunicationType","serverConfig","validateMcpServerConfig","serverName","error","init_mcpServerUtils","__esmMin","__name","configManager_exports","__export","ConfigManager","configManager","copyFileSync","existsSync","readFileSync","writeFileSync","dirname","resolve","fileURLToPath","commentJson","dayjs","JSON5","json5Writer","__dirname","DEFAULT_CONNECTION_CONFIG","init_configManager","__esmMin","init_Logger","init_mcpServerUtils","_ConfigManager","__name","possiblePaths","path","configDir","configFileNames","fileName","filePath","format","targetFileName","configPath","configFileFormat","configData","config","error","configObj","endpoint","serverName","serverConfig","validation","validateMcpServerConfig","toolName","ep","currentEndpoints","newEndpoints","newMcpServers","newConfig","toolsConfig","validServerNames","invalidServerNames","logger","enabled","description","configContent","json5WriterError","commentJsonError","connectionConfig","callTime","toolConfig","currentUsageCount","currentLastUsedTime","interval","timeout","modelScopeConfig","apiKey","webServer","webUIConfig","port","MCPServiceManager","MCPServiceManager_default","init_MCPServiceManager","__esmMin","init_Logger","init_configManager","init_MCPService","__name","configs","logger","configEntries","serviceName","config","service","MCPService","tools","t","error","tool","toolKey","allTools","toolInfo","configManager","toolName","arguments_","result","status","serviceStatus","name","enhancedConfig","modelScopeApiKey","nameOrConfig","finalConfig","currentServerConfigs","currentToolsConfig","newToolsConfig","currentToolConfig","currentToolNames","removedTools","addedTools","updatedTools","current","updated","currentConfig","newConfig","currentKeys","newKeys","key","currentTool","newTool","createInstance","MCPServiceManager_default","getInstance","instance","state","initPromise","reset","instanceId","lastError","error","cleanup","isInitialized","getStatus","forceReinitialize","getCurrentInstance","waitForInitialization","MCPServiceManagerSingleton","init_MCPServiceManagerSingleton","__esmMin","init_MCPServiceManager","__name","cleanupError","reason","EventEmitter","ReconnectStrategy","DEFAULT_OPTIONS","XiaozhiConnectionManager","init_XiaozhiConnectionManager","__esmMin","init_Logger","init_ProxyMCPServer","__name","options","logger","endpoints","tools","endpoint","error","connectionPromises","proxyServer","results","successCount","result","failureCount","connectionTime","disconnectPromises","timer","healthyConnections","status","manager","enabled","stats","successRate","existingTimer","valid","invalid","errors","validStrategies","newEndpoints","validEndpoints","invalidEndpoints","currentEndpoints","toAdd","ep","toRemove","toKeep","changeEvent","newOptions","oldOptions","config","excludeEndpoints","availableConnections","connection","selectedConnection","connections","randomIndex","connectionHealths","a","b","totalWeight","sum","item","randomWeight","conn","connectionWeights","weight","strategy","oldStrategy","failedEndpoint","backupConnection","backupEndpoint","targetEndpoints","prewarmPromises","currentMemory","memoryGrowth","growthPercentage","ProxyMCPServer","healthCheckPromises","startTime","responseTime","resolve","success","baseScore","increment","decrement","errorMessage","baseDelay","maxDelay","multiplier","attempts","delay","jitter","recentHistory","h","createInstance","options","XiaozhiConnectionManager","getInstance","instance","state","initPromise","reset","instanceId","lastError","error","cleanup","isInitialized","getStatus","forceReinitialize","getCurrentInstance","waitForInitialization","XiaozhiConnectionManagerSingleton","init_XiaozhiConnectionManagerSingleton","__esmMin","init_XiaozhiConnectionManager","__name","cleanupError","reason","EventEmitter","getEventBus","eventBusInstance","EventBus","destroyEventBus","init_EventBus","__esmMin","init_Logger","__name","logger","error","eventName","listenerCount","data","listener","stats","stat","sum","count","ConfigService","init_ConfigService","__esmMin","init_Logger","init_configManager","init_EventBus","__name","logger","getEventBus","config","configManager","error","newConfig","source","currentServers","name","serverName","toolsConfig","toolName","toolConfig","ConfigApiHandler","init_ConfigApiHandler","__esmMin","init_Logger","init_ConfigService","__name","logger","ConfigService","code","message","details","data","c","config","error","errorResponse","newConfig","endpoint","endpoints","servers","connection","path","exists","HeartbeatHandler","init_HeartbeatHandler","__esmMin","init_Logger","init_ConfigService","__name","statusService","notificationService","logger","ConfigService","ws","message","clientId","statusUpdate","error","code","errorResponse","lastHeartbeat","now","intervalId","response","RealtimeNotificationHandler","init_RealtimeNotificationHandler","__esmMin","init_Logger","init_ConfigService","init_EventBus","__name","notificationService","statusService","logger","ConfigService","getEventBus","ws","message","clientId","error","config","configData","status","code","errorResponse","feature","alternative","SERVICE_CONSTANTS","CONFIG_CONSTANTS","PATH_CONSTANTS","ERROR_CODES","TIMEOUT_CONSTANTS","init_Constants","__esmMin","ERROR_HELP_MESSAGES","COMMON_SOLUTIONS","ERROR_MESSAGES","init_ErrorMessages","__esmMin","init_Constants","ERROR_CODES","__name","errorCode","problemKey","error","context","CLIError","ConfigError","ServiceError","ValidationError","FileError","ProcessError","init_errors","__esmMin","init_Constants","_CLIError","message","code","exitCode","suggestions","__name","_ConfigError","ERROR_CODES","format","_ServiceError","pid","reason","_ValidationError","field","port","_FileError","filePath","fullMessage","_ProcessError","chalk","ErrorHandler","init_ErrorHandlers","__esmMin","init_ErrorMessages","init_errors","_ErrorHandler","__name","error","CLIError","suggestion","helpMessage","ERROR_MESSAGES","operation","context","message","suggestions","fs","path","FileUtils","init_FileUtils","__esmMin","init_errors","_FileUtils","__name","filePath","dirPath","FileError","encoding","error","content","options","dir","srcPath","destPath","destDir","srcDir","items","item","stats","result","itemPath","subItems","prefix","suffix","tempDir","timestamp","random","fileName","mode","basePath","FormatUtils","init_FormatUtils","__esmMin","__name","ms","seconds","minutes","hours","days","bytes","units","size","unitIndex","timestamp","format","date","pid","port","protocol","host","path","url","key","value","error","includeStack","message","items","bullet","item","data","keys","maxWidths","row","header","i","separator","width","rows","current","total","percentage","filled","empty","bar","percent","command","args","quotedArgs","arg","text","maxLength","suffix","obj","indent","trueText","falseText","realpathSync","tmpdir","path","fileURLToPath","PathUtils","init_PathUtils","__esmMin","init_Constants","init_FileUtils","_PathUtils","__name","configDir","CONFIG_CONSTANTS","SERVICE_CONSTANTS","projectDir","baseDir","PATH_CONSTANTS","__filename","scriptDir","possiblePaths","templatesDir","FileUtils","templateName","templatePath","projectRoot","filePath","format","fileName","inputPath","resolvedPath","resolvedBase","name","cliPath","realCliPath","distDir","segments","joinedPath","normalizedPath","execSync","PlatformUtils","init_PlatformUtils","__esmMin","init_Constants","init_errors","_PlatformUtils","__name","pid","cmdline","TIMEOUT_CONSTANTS","signal","attempts","maxAttempts","resolve","error","ProcessError","name","defaultValue","value","filePath","Validation","init_Validation","__esmMin","init_errors","_Validation","__name","port","ValidationError","format","validFormats","value","fieldName","options","url","parsedUrl","name","invalidChars","hasControlChars","char","jsonString","error","array","obj","requiredProps","prop","validValues","pattern","fs","path","fileURLToPath","VersionUtils","init_VersionUtils","__esmMin","init_errors","_VersionUtils","__name","__filename","currentDir","possiblePaths","packagePath","packageJson","error","FileError","version1","version2","v1Parts","v2Parts","maxLength","i","v1Part","v2Part","version","ProcessManager_exports","__export","ProcessManagerImpl","init_ProcessManager","__esmMin","init_errors","init_FileUtils","init_FormatUtils","init_PathUtils","init_PlatformUtils","__name","PathUtils","pidFilePath","FileUtils","pidContent","pidStr","startTimeStr","mode","pid","startTime","pidInfo","FileError","PlatformUtils","uptime","FormatUtils","error","ProcessError","attempts","maxAttempts","resolve","exists","isXiaozhi","DaemonManager_exports","__export","DaemonManagerImpl","spawn","fs","init_DaemonManager","__esmMin","init_errors","init_PathUtils","init_PlatformUtils","processManager","logger","__name","serverFactory","options","status","ServiceError","child","error","resolve","logFileName","logFilePath","PathUtils","command","args","PlatformUtils","tail","env","ProcessError","logDir","logStream","timestamp","code","signal","processInfo","TransportAdapter","init_TransportAdapter","__esmMin","init_Logger","__name","messageHandler","config","logger","message","response","error","errorResponse","id","errorCode","timestamp","random","state","oldState","newState","data","errorMessage","promise","timeoutMs","_","reject","randomUUID","express","HTTPAdapter","init_HTTPAdapter","__esmMin","init_TransportAdapter","TransportAdapter","__name","messageHandler","config","error","resolve","reject","client","message","req","res","next","clientId","sessionId","response","data","init_StdioAdapter","__esmMin","init_TransportAdapter","WebSocket","WebSocketServer","init_WebSocketAdapter","__esmMin","init_TransportAdapter","MCPMessageHandler","init_MCPMessageHandler","__esmMin","init_Logger","__name","serviceManager","logger","message","error","params","id","mcpTools","tool","result","errorCode","EventEmitter","ToolRegistry","ConnectionManager","UnifiedMCPServer","init_UnifiedMCPServer","__esmMin","init_Logger","init_MCPServiceManager","init_TransportAdapter","init_MCPMessageHandler","__name","serviceManager","logger","tool","toolName","id","transportName","state","connectionInfo","connection","conn","config","MCPServiceManager","MCPMessageHandler","error","name","adapter","createHTTPServer","config","logger","server","UnifiedMCPServer","messageHandler","httpAdapter","HTTPAdapter","init_ServerFactory","__esmMin","init_Logger","init_HTTPAdapter","init_StdioAdapter","init_WebSocketAdapter","init_UnifiedMCPServer","__name","MCPServer_exports","__export","MCPServer","EventEmitter","logger","init_MCPServer","__esmMin","init_Logger","init_ProxyMCPServer","init_configManager","init_ServerFactory","Logger","__name","port","httpConfig","createHTTPServer","connection","error","mcpEndpoint","configManager","ep","ProxyMCPServer","ServiceManager_exports","__export","ServiceManagerImpl","init_ServiceManager","__esmMin","init_errors","init_PathUtils","init_PlatformUtils","init_Validation","processManager","configManager","logger","__name","options","status","resolve","stopError","error","ServiceError","Validation","ConfigError","spawn","port","scriptPath","PathUtils","child","MCPServer","server","cleanup","mcpProxyPath","openBrowser","webServerPath","args","WebServer","url","platform","PlatformUtils","command","TemplateManager_exports","__export","TemplateManagerImpl","fs","path","init_TemplateManager","__esmMin","init_errors","init_FileUtils","init_PathUtils","init_Validation","__name","templatesDir","PathUtils","templates","templateDirs","dirent","templateName","templateInfo","FileError","Validation","templatePath","configPath","config","FileUtils","configContent","files","error","ValidationError","targetPath","options","requiredFiles","requiredFile","filePath","file","relativePath","variables","filesToProcess","pattern","basePath","regex","content","hasChanges","key","value","createContainer","DIContainer","init_Container","__esmMin","init_Logger","init_configManager","init_ErrorHandlers","init_FileUtils","init_FormatUtils","init_PathUtils","init_PlatformUtils","init_Validation","init_VersionUtils","_DIContainer","__name","key","factory","singleton","instance","factoryKeys","instanceKeys","container","VersionUtils","PlatformUtils","FormatUtils","FileUtils","PathUtils","Validation","configManager","logger","ErrorHandler","ProcessManagerModule","DaemonManagerModule","processManager","ServiceManagerModule","TemplateManagerModule","spawn","ServiceApiHandler","init_ServiceApiHandler","__esmMin","init_Logger","init_Container","init_EventBus","__name","statusService","logger","getEventBus","code","message","details","data","c","error","errorResponse","status","createContainer","isDaemon","restartArgs","health","existsSync","readFile","dirname","join","fileURLToPath","StaticFileHandler","init_StaticFileHandler","__esmMin","init_Logger","__name","logger","__dirname","possibleWebPaths","p","exists","error","c","pathname","filePath","fullPath","indexPath","contentType","content","ext","message","errorHtml","StatusApiHandler","init_StatusApiHandler","__esmMin","init_Logger","__name","statusService","logger","code","message","details","data","c","status","error","errorResponse","clientStatus","restartStatus","connected","lastHeartbeat","servers","statusUpdate","NotificationService","init_NotificationService","__esmMin","init_Logger","init_EventBus","__name","logger","getEventBus","data","clientId","ws","client","error","type","message","messageStr","queue","config","status","timestamp","restartStatus","connectedClients","queuedMessages","total","disconnectedClients","StatusService","init_StatusService","__esmMin","init_Logger","init_EventBus","__name","logger","getEventBus","info","source","oldStatus","error","status","servers","endpoint","WebServer_exports","__export","WebServer","createServer","serve","Hono","cors","WebSocketServer","init_WebServer","__esmMin","init_Logger","init_ProxyMCPServer","init_ConfigAdapter","init_configManager","init_MCPServiceManagerSingleton","init_XiaozhiConnectionManagerSingleton","init_ConfigApiHandler","init_HeartbeatHandler","init_RealtimeNotificationHandler","init_ServiceApiHandler","init_StaticFileHandler","init_StatusApiHandler","init_ConfigService","init_EventBus","init_NotificationService","init_StatusService","__name","code","message","details","data","feature","alternative","port","configManager","logger","getEventBus","ConfigService","StatusService","NotificationService","ConfigApiHandler","StatusApiHandler","ServiceApiHandler","StaticFileHandler","RealtimeNotificationHandler","HeartbeatHandler","config","MCPServiceManagerSingleton","tools","error","mcpServers","name","serviceConfig","convertLegacyToNew","mcpEndpoint","validEndpoints","ep","XiaozhiConnectionManagerSingleton","event","validEndpoint","ProxyMCPServer","connectionFn","context","maxAttempts","initialDelay","maxDelay","backoffMultiplier","lastError","attempt","delay","ms","resolve","err","c","errorResponse","ws","clientId","server","resolved","doResolve","client","destroyEventBus","spawn","importModules","webServerModule","configModule","loggerModule","__name","main","openBrowser","WebServer","configManager","logger","webServer","url","openBrowserUrl","cleanup","error","platform","command","args","spawn"]}