xiaozhi-client 2.3.0 → 2.3.1-beta.1

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/config/json5-adapter.ts","../../src/config/resolver.ts","../../src/config/manager.ts","../../src/mcp-core/types.ts","../../src/mcp-core/transport-factory.ts","../../src/mcp-core/utils/type-normalizer.ts","../../src/mcp-core/utils/validators.ts","../../src/mcp-core/utils/index.ts","../../src/mcp-core/connection.ts","../../src/mcp-core/manager.ts","../../src/mcp-core/index.ts","../../src/config/adapter.ts","../../src/config/initializer.ts","../../src/config/index.ts","../../src/cli/Constants.ts","../../src/cli/errors/index.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/services/ProcessManager.ts","../../src/cli/services/DaemonManager.ts","../../src/cli/services/ServiceManager.ts","../../src/cli/services/TemplateManager.ts","../../src/cli/interfaces/Command.ts","../../src/cli/commands/ServiceCommandHandler.ts","../../src/cli/commands/ConfigCommandHandler.ts","../../src/cli/commands/ProjectCommandHandler.ts","../../src/cli/interfaces/CommandTypes.ts","../../src/cli/commands/McpCommandHandler.ts","../../src/cli/commands/EndpointCommandHandler.ts","../../src/cli/index.ts","../../src/cli/Container.ts","../../src/utils/version.ts","../../src/cli/errors/ErrorHandlers.ts","../../src/cli/errors/ErrorMessages.ts","../../src/cli/commands/CommandHandlerFactory.ts","../../src/cli/commands/index.ts"],"sourcesContent":["/**\n * JSON5 注释保留适配器\n * 使用 comment-json 实现 JSON5/JSONC 注释保留功能\n *\n * 注意:为了使用 comment-json 保留注释,JSON5 配置文件的键需要带引号。\n * 这与 JSON5 标准语法允许不带引号的键略有不同,但能实现注释保留功能。\n */\nimport * as commentJson from \"comment-json\";\n\n/**\n * JSON5 写入器适配器接口\n * 保持与 json5-writer 兼容的 API\n */\nexport interface Json5WriterAdapter {\n write(data: unknown): void;\n toSource(): string;\n}\n\n/**\n * 创建 JSON5 写入器适配器\n * @param content 原始 JSON5 内容字符串\n * @returns Json5WriterAdapter 实例\n */\nexport function createJson5Writer(content: string): Json5WriterAdapter {\n // 使用 comment-json 解析原始内容\n // comment-json 会保留注释信息在返回的对象中\n const parsedData = commentJson.parse(content) as Record<string, unknown>;\n\n return {\n write(data: unknown): void {\n // 通过 Object.assign 合并新数据\n if (parsedData && typeof parsedData === \"object\" && data) {\n Object.assign(parsedData, data);\n }\n },\n\n toSource(): string {\n // 使用 comment-json 序列化,保留注释和格式\n return commentJson.stringify(parsedData, null, 2);\n },\n };\n}\n\n/**\n * 解析 JSON5 内容(带注释保留)\n * @param content JSON5 内容字符串\n * @returns 解析后的对象\n */\nexport function parseJson5(content: string): unknown {\n // 使用 comment-json 解析,支持注释保留\n return commentJson.parse(content);\n}\n","/**\n * 配置解析器\n * 负责按优先级查找配置文件\n */\n\nimport { existsSync } from \"node:fs\";\nimport path from \"node:path\";\n\n/**\n * 配置解析器类\n * 实现配置文件查找优先级逻辑\n */\nexport class ConfigResolver {\n /**\n * 按优先级解析配置文件路径\n *\n * 优先级顺序:\n * 1. 环境变量 XIAOZHI_CONFIG_DIR 指定的目录\n * 2. 当前工作目录\n * 3. 用户家目录/.xiaozhi-client/\n *\n * @returns 找到的配置文件路径,如果都不存在则返回 null\n */\n static resolveConfigPath(): string | null {\n // 优先级 1: 环境变量指定(向后兼容)\n if (process.env.XIAOZHI_CONFIG_DIR) {\n const configPath = ConfigResolver.findConfigInDir(\n process.env.XIAOZHI_CONFIG_DIR\n );\n if (configPath) {\n return configPath;\n }\n }\n\n // 优先级 2: 当前目录\n const currentDirConfig = ConfigResolver.findConfigInDir(process.cwd());\n if (currentDirConfig) {\n return currentDirConfig;\n }\n\n // 优先级 3: 用户家目录/.xiaozhi-client/\n const homeDir = process.env.HOME || process.env.USERPROFILE;\n if (homeDir) {\n const xiaozhiClientDir = path.join(homeDir, \".xiaozhi-client\");\n const homeDirConfig = ConfigResolver.findConfigInDir(xiaozhiClientDir);\n if (homeDirConfig) {\n return homeDirConfig;\n }\n }\n\n return null;\n }\n\n /**\n * 在指定目录中查找配置文件\n *\n * 按优先级查找:xiaozhi.config.json5 > xiaozhi.config.jsonc > xiaozhi.config.json\n *\n * @param dir - 要搜索的目录\n * @returns 找到的配置文件路径,如果不存在则返回 null\n */\n static findConfigInDir(dir: string): string | null {\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 = path.join(dir, fileName);\n if (existsSync(filePath)) {\n return filePath;\n }\n }\n\n return null;\n }\n\n /**\n * 获取默认配置目录路径\n *\n * @returns 用户家目录下的 .xiaozhi-client 目录路径,如果无法获取家目录则返回 null\n */\n static getDefaultConfigDir(): string | null {\n const homeDir = process.env.HOME || process.env.USERPROFILE;\n if (!homeDir) {\n return null;\n }\n return path.join(homeDir, \".xiaozhi-client\");\n }\n}\n","/**\n * 配置管理器\n *\n * 核心配置管理模块,负责:\n * - 配置文件的读取和解析(支持 JSON、JSON5、JSONC 格式)\n * - 配置验证和类型检查\n * - 配置更新和持久化\n * - 配置变更事件通知\n * - 配置文件路径解析\n *\n * @example\n * ```typescript\n * import { configManager } from '../config';\n *\n * // 获取配置\n * const config = configManager.getConfig();\n *\n * // 更新配置\n * configManager.updateConfig({ mcpEndpoint: 'wss://...' });\n *\n * // 监听配置更新事件\n * configManager.on('config:updated', (payload) => {\n * // payload 示例结构:\n * // {\n * // type: 'endpoint' | 'customMCP' | 'config' | 'serverTools' | 'connection' | 'modelscope' | 'webui' | 'platform';\n * // timestamp: Date;\n * // serviceName?: string;\n * // platformName?: string;\n * // }\n * console.log('配置已更新事件:', payload);\n *\n * // 如果需要获取最新的完整配置对象,可在回调中调用 getConfig()\n * const latestConfig = configManager.getConfig();\n * console.log('最新配置对象:', latestConfig);\n * });\n * ```\n */\nimport { 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 { createJson5Writer, parseJson5 } from \"./json5-adapter.js\";\nimport { ConfigResolver } from \"./resolver.js\";\n\n// 在 ESM 中,需要从 import.meta.url 获取当前文件目录\n// 迁移后:src/config/manager.ts → __dirname = src/config/\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 headers?: Record<string, string>;\n}\n\n// HTTP MCP 服务配置\nexport interface HTTPMCPServerConfig {\n type?: \"http\" | \"streamable-http\"; // 可选,默认就是 http\n url: string;\n headers?: Record<string, string>;\n}\n\n// 向后兼容的别名\n/** @deprecated 使用 HTTPMCPServerConfig 代替 */\nexport type StreamableHTTPMCPServerConfig = HTTPMCPServerConfig;\n\n// 统一的 MCP 服务配置\nexport type MCPServerConfig =\n | LocalMCPServerConfig\n | SSEMCPServerConfig\n | HTTPMCPServerConfig;\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\n// 工具调用日志配置接口\n// TTS 配置接口\nexport interface TTSConfig {\n appid?: string; // 应用 ID\n accessToken?: string; // 访问令牌\n voice_type?: string; // 声音类型\n encoding?: string; // 编码格式(默认 wav)\n cluster?: string; // 集群类型\n endpoint?: string; // WebSocket 端点\n}\n\n// ASR 配置接口\nexport interface ASRConfig {\n appid?: string; // 应用 ID\n accessToken?: string; // 访问令牌\n cluster?: string; // 集群类型(默认:volcengine_streaming_common)\n wsUrl?: string; // WebSocket 端点\n}\n\n// LLM 配置接口\nexport interface LLMConfig {\n model: string; // 模型名称\n apiKey: string; // API 密钥\n baseURL: string; // API 基础地址\n prompt?: string; // 自定义系统提示词(支持纯字符串或文件路径)\n}\n\nexport interface ToolCallLogConfig {\n maxRecords?: number; // 最大记录条数,默认 100\n logFilePath?: string; // 自定义日志文件路径(可选)\n}\n\n// CustomMCP 相关接口定义\n\n// 代理处理器配置\nexport interface ProxyHandlerConfig {\n type: \"proxy\";\n platform: \"coze\" | \"openai\" | \"anthropic\" | \"custom\";\n config: {\n // Coze 平台配置\n workflow_id?: string;\n bot_id?: string;\n api_key?: string;\n base_url?: string;\n // 通用配置\n timeout?: number;\n retry_count?: number;\n retry_delay?: number;\n headers?: Record<string, unknown>;\n params?: Record<string, unknown>;\n };\n}\n\n// HTTP 处理器配置\nexport interface HttpHandlerConfig {\n type: \"http\";\n url: string;\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n headers?: Record<string, string>;\n timeout?: number;\n retry_count?: number;\n retry_delay?: number;\n auth?: {\n type: \"bearer\" | \"basic\" | \"api_key\";\n token?: string;\n username?: string;\n password?: string;\n api_key?: string;\n api_key_header?: string;\n };\n body_template?: string; // 支持模板变量替换\n response_mapping?: {\n success_path?: string; // JSONPath 表达式\n error_path?: string;\n data_path?: string;\n };\n}\n\n// 函数处理器配置\nexport interface FunctionHandlerConfig {\n type: \"function\";\n module: string; // 模块路径\n function: string; // 函数名\n timeout?: number;\n context?: Record<string, unknown>; // 函数执行上下文\n}\n\n// 脚本处理器配置\nexport interface ScriptHandlerConfig {\n type: \"script\";\n script: string; // 脚本内容或文件路径\n interpreter?: \"node\" | \"python\" | \"bash\";\n timeout?: number;\n env?: Record<string, string>; // 环境变量\n}\n\n// 链式处理器配置\nexport interface ChainHandlerConfig {\n type: \"chain\";\n tools: string[]; // 要链式调用的工具名称\n mode: \"sequential\" | \"parallel\"; // 执行模式\n error_handling: \"stop\" | \"continue\" | \"retry\"; // 错误处理策略\n}\n\n// MCP 处理器配置(用于同步的工具)\nexport interface MCPHandlerConfig {\n type: \"mcp\";\n config: {\n serviceName: string;\n toolName: string;\n };\n}\n\nexport type HandlerConfig =\n | ProxyHandlerConfig\n | HttpHandlerConfig\n | FunctionHandlerConfig\n | ScriptHandlerConfig\n | ChainHandlerConfig\n | MCPHandlerConfig;\n\n// CustomMCP 工具接口\n// TODO: 注意:此定义应与 @/types 中的 CustomMCPToolConfig 保持一致\n// 未来将迁移到从 shared-types 导入\nexport interface CustomMCPTool {\n // 确保必填字段\n name: string;\n description: string;\n inputSchema: Record<string, unknown>;\n handler: HandlerConfig;\n\n // 使用统计信息(可选)\n stats?: {\n usageCount?: number; // 工具使用次数\n lastUsedTime?: string; // 最后使用时间(ISO 8601格式)\n };\n}\n\n// CustomMCP 配置接口\nexport interface CustomMCPConfig {\n tools: CustomMCPTool[];\n}\n\n// Web 服务器实例接口(用于配置更新通知)\nexport interface WebServerInstance {\n broadcastConfigUpdate(config: AppConfig): void;\n}\n\nexport interface PlatformsConfig {\n [platformName: string]: PlatformConfig;\n}\n\nexport interface PlatformConfig {\n token?: string;\n}\n\n/**\n * 扣子平台配置接口\n */\nexport interface CozePlatformConfig extends PlatformConfig {\n /** 扣子 API Token */\n token: string;\n}\n\nexport interface AppConfig {\n mcpEndpoint: string | string[];\n mcpServers: Record<string, MCPServerConfig>;\n mcpServerConfig?: Record<string, MCPServerToolsConfig>;\n customMCP?: CustomMCPConfig; // 新增 customMCP 配置支持\n connection?: ConnectionConfig; // 连接配置(可选,用于向后兼容)\n modelscope?: ModelScopeConfig; // ModelScope 配置(可选)\n webUI?: WebUIConfig; // Web UI 配置(可选)\n platforms?: PlatformsConfig; // 平台配置(可选)\n toolCallLog?: ToolCallLogConfig; // 工具调用日志配置(可选)\n tts?: TTSConfig; // TTS 配置(可选)\n asr?: ASRConfig; // ASR 配置(可选)\n llm?: LLMConfig; // LLM 配置(可选)\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: {\n write(data: unknown): void;\n toSource(): string;\n } | null = null; // json5-writer 实例,用于保留 JSON5 注释\n\n // 统计更新并发控制\n private statsUpdateLocks: Map<string, Promise<void>> = new Map();\n private statsUpdateLockTimeouts: Map<string, NodeJS.Timeout> = new Map();\n private readonly STATS_UPDATE_TIMEOUT = 5000; // 5秒超时\n\n // 事件回调(用于解耦 EventBus 依赖)\n private eventCallbacks: Map<string, Array<(data: unknown) => void>> =\n new Map();\n\n private constructor() {\n // 使用模板目录中的默认配置文件\n // 在不同环境中尝试不同的路径\n //\n // 迁移后 __dirname = src/config/(开发环境)或 dist/config/(构建后)\n // 项目根目录的 templates/default/ 在 __dirname 的上两级\n const possiblePaths = [\n // src/config/ 或 dist/config/ → 项目根 templates/default/xiaozhi.config.json\n resolve(\n __dirname,\n \"..\",\n \"..\",\n \"templates\",\n \"default\",\n \"xiaozhi.config.json\"\n ),\n // 从 CWD 查找(兼容各种启动场景)\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 */\n public on(eventName: string, callback: (data: unknown) => void): void {\n if (!this.eventCallbacks.has(eventName)) {\n this.eventCallbacks.set(eventName, []);\n }\n this.eventCallbacks.get(eventName)?.push(callback);\n }\n\n /**\n * 发射事件\n */\n private emitEvent(eventName: string, data: unknown): void {\n const callbacks = this.eventCallbacks.get(eventName);\n if (callbacks) {\n for (const callback of callbacks) {\n try {\n callback(data);\n } catch (error) {\n console.error(`事件回调执行失败 [${eventName}]:`, error);\n }\n }\n }\n }\n\n /**\n * 获取配置文件路径(动态计算)\n * 支持多种配置文件格式:json5 > jsonc > json\n *\n * 查找优先级:\n * 1. 环境变量 XIAOZHI_CONFIG_DIR 指定的目录\n * 2. 当前工作目录\n * 3. 用户家目录/.xiaozhi-client/\n */\n private getConfigFilePath(): string {\n // 优先使用 ConfigResolver 解析配置路径\n const resolvedPath = ConfigResolver.resolveConfigPath();\n\n if (resolvedPath) {\n return resolvedPath;\n }\n\n // 如果都找不到,返回用户家目录的默认路径\n const defaultDir = ConfigResolver.getDefaultConfigDir();\n if (defaultDir) {\n return resolve(defaultDir, \"xiaozhi.config.json\");\n }\n\n // 最后回退到当前目录\n const configDir = process.env.XIAOZHI_CONFIG_DIR || process.cwd();\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 * 按优先级检查配置文件是否存在:\n * 1. 环境变量 XIAOZHI_CONFIG_DIR 指定的目录\n * 2. 当前工作目录\n * 3. 用户家目录/.xiaozhi-client/\n */\n public configExists(): boolean {\n return ConfigResolver.resolveConfigPath() !== null;\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 const error = new Error(\n \"配置文件不存在,请先运行 xiaozhi init 初始化配置\"\n );\n this.emitEvent(\"config:error\", {\n error,\n operation: \"loadConfig\",\n });\n throw error;\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 解析配置对象,同时使用适配器保留注释信息\n config = parseJson5(configData) as AppConfig;\n // 创建适配器实例用于后续保存时保留注释\n this.json5Writer = createJson5Writer(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 // 发射配置错误事件\n this.emitEvent(\"config:error\", {\n error: error instanceof Error ? error : new Error(String(error)),\n operation: \"loadConfig\",\n });\n if (error instanceof SyntaxError) {\n throw new Error(`配置文件格式错误: ${error.message}`);\n }\n throw error;\n }\n }\n\n /**\n * 验证配置文件结构\n */\n public 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 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 // 更详细的验证应该由调用方完成\n }\n }\n\n /**\n * 获取配置(只读)\n * 使用缓存机制避免频繁的文件 I/O 操作\n */\n public getConfig(): Readonly<AppConfig> {\n // 使用缓存,避免每次都重新加载文件\n if (!this.config) {\n this.config = this.loadConfig();\n }\n\n // 使用 structuredClone 进行更高效的深拷贝\n // 如果不支持则降级到 JSON.parse(JSON.stringify())\n return structuredClone(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 for (const ep of endpoint) {\n if (!ep || typeof ep !== \"string\") {\n throw new Error(\"MCP 端点数组中的每个元素必须是非空字符串\");\n }\n }\n }\n\n const config = this.getMutableConfig();\n config.mcpEndpoint = endpoint;\n this.saveConfig(config);\n\n // 发射配置更新事件\n this.emitEvent(\"config:updated\", {\n type: \"endpoint\",\n timestamp: new Date(),\n });\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 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 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.getMutableConfig();\n\n // 检查服务是否存在\n if (!config.mcpServers[serverName]) {\n throw new Error(`服务 ${serverName} 不存在`);\n }\n\n // 1. 清理 mcpServers 字段(现有逻辑)\n delete config.mcpServers[serverName];\n\n // 2. 清理 mcpServerConfig 字段(复用现有方法)\n if (config.mcpServerConfig?.[serverName]) {\n delete config.mcpServerConfig[serverName];\n }\n\n // 3. 清理 customMCP 字段中相关的工具定义\n if (config.customMCP?.tools) {\n // 查找与该服务相关的 CustomMCP 工具\n const relatedTools = config.customMCP.tools.filter(\n (tool) =>\n tool.handler?.type === \"mcp\" &&\n tool.handler.config?.serviceName === serverName\n );\n\n // 移除相关工具\n for (const tool of relatedTools) {\n const toolIndex = config.customMCP.tools.findIndex(\n (t) => t.name === tool.name\n );\n if (toolIndex !== -1) {\n config.customMCP.tools.splice(toolIndex, 1);\n }\n }\n\n // 如果没有工具了,可以清理整个 customMCP 对象\n if (config.customMCP.tools.length === 0) {\n config.customMCP = undefined;\n }\n }\n\n // 4. 保存配置(单次原子性操作)\n this.saveConfig(config);\n\n // 5. 发射配置更新事件,通知 CustomMCPHandler 重新初始化\n this.emitEvent(\"config:updated\", {\n type: \"customMCP\",\n timestamp: new Date(),\n });\n\n // 记录清理结果\n console.log(\"成功移除 MCP 服务\", { serverName });\n }\n\n /**\n * 批量更新配置(由 Handler 调用)\n */\n public updateConfig(newConfig: Partial<AppConfig>): void {\n const config = this.getMutableConfig();\n\n // 更新 MCP 端点\n if (newConfig.mcpEndpoint !== undefined) {\n config.mcpEndpoint = newConfig.mcpEndpoint;\n }\n\n // 更新 MCP 服务\n if (newConfig.mcpServers) {\n const currentServers = { ...config.mcpServers };\n for (const [name, serverConfig] of Object.entries(newConfig.mcpServers)) {\n config.mcpServers[name] = serverConfig;\n }\n // 删除不存在的服务\n for (const name of Object.keys(currentServers)) {\n if (!(name in newConfig.mcpServers)) {\n delete config.mcpServers[name];\n // 同时清理工具配置\n if (config.mcpServerConfig?.[name]) {\n delete config.mcpServerConfig[name];\n }\n }\n }\n }\n\n // 更新连接配置\n if (newConfig.connection) {\n if (!config.connection) {\n config.connection = {};\n }\n Object.assign(config.connection, newConfig.connection);\n }\n\n // 更新 ModelScope 配置\n if (newConfig.modelscope) {\n if (!config.modelscope) {\n config.modelscope = {};\n }\n Object.assign(config.modelscope, newConfig.modelscope);\n }\n\n // 更新 Web UI 配置\n if (newConfig.webUI) {\n if (!config.webUI) {\n config.webUI = {};\n }\n Object.assign(config.webUI, newConfig.webUI);\n }\n\n // 更新服务工具配置\n if (newConfig.mcpServerConfig) {\n for (const [serverName, toolsConfig] of Object.entries(\n newConfig.mcpServerConfig\n )) {\n if (config.mcpServerConfig?.[serverName]) {\n config.mcpServerConfig[serverName] = toolsConfig;\n }\n }\n }\n\n // 更新平台配置\n if (newConfig.platforms) {\n for (const [platformName, platformConfig] of Object.entries(\n newConfig.platforms\n )) {\n if (!config.platforms) {\n config.platforms = {};\n }\n config.platforms[platformName] = platformConfig;\n }\n }\n\n // 更新 ASR 配置(使用 \"asr\" in newConfig 检测字段是否存在,支持清空配置)\n if (\"asr\" in newConfig) {\n config.asr = newConfig.asr;\n }\n\n // 更新 TTS 配置\n if (\"tts\" in newConfig) {\n config.tts = newConfig.tts;\n }\n\n // 更新 LLM 配置\n if (\"llm\" in newConfig) {\n config.llm = newConfig.llm;\n }\n\n this.saveConfig(config);\n\n // 发射配置更新事件\n this.emitEvent(\"config:updated\", {\n type: \"config\",\n timestamp: new Date(),\n });\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 this.emitEvent(\"config:updated\", {\n type: \"serverTools\",\n serviceName: serverName,\n timestamp: new Date(),\n });\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 console.log(\"已清理无效的服务工具配置\", {\n count: invalidServerNames.length,\n serverNames: invalidServerNames,\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 格式,使用适配器保留注释\n try {\n if (this.json5Writer) {\n // 使用适配器更新配置并保留注释\n this.json5Writer.write(config);\n configContent = this.json5Writer.toSource();\n } else {\n // 如果没有适配器实例,回退到 comment-json 序列化\n console.warn(\"没有 JSON5 适配器实例,使用 comment-json 序列化\");\n configContent = commentJson.stringify(config, null, 2);\n }\n } catch (json5Error) {\n // 如果适配器序列化失败,回退到 comment-json 序列化\n console.warn(\n \"使用 JSON5 适配器保存失败,回退到 comment-json 序列化:\",\n json5Error\n );\n configContent = commentJson.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 console.log(\"配置保存成功\");\n\n // 通知 Web 界面配置已更新(如果 Web 服务器正在运行)\n this.notifyConfigUpdate(config);\n } catch (error) {\n // 发射配置错误事件\n this.emitEvent(\"config:error\", {\n error: error instanceof Error ? error : new Error(String(error)),\n operation: \"saveConfig\",\n });\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 this.emitEvent(\"config:updated\", {\n type: \"connection\",\n timestamp: new Date(),\n });\n }\n\n /**\n * 更新工具使用统计信息(MCP 服务工具)\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\n /**\n * 更新工具使用统计信息(CustomMCP 工具)\n * @param toolName 工具名称(customMCP 工具名称)\n * @param incrementUsageCount 是否增加使用计数,默认为 true\n */\n public async updateToolUsageStats(\n toolName: string,\n incrementUsageCount?: boolean\n ): Promise<void>;\n\n /**\n * 更新工具使用统计信息的实现\n */\n public async updateToolUsageStats(\n arg1: string,\n arg2: string | boolean | undefined,\n arg3?: string\n ): Promise<void> {\n try {\n // 判断参数类型来区分不同的重载\n if (typeof arg2 === \"string\" && arg3) {\n // 三个参数的情况:updateToolUsageStats(serverName, toolName, callTime)\n const serverName = arg1;\n const toolName = arg2;\n const callTime = arg3;\n\n // 双写机制:同时更新 mcpServerConfig 和 customMCP 中的统计信息\n await Promise.all([\n this._updateMCPServerToolStats(serverName, toolName, callTime),\n this.updateCustomMCPToolStats(serverName, toolName, callTime),\n ]);\n\n console.log(\"工具使用统计已更新\", { serverName, toolName });\n } else {\n // 两个参数的情况:updateToolUsageStats(toolName, incrementUsageCount)\n const toolName = arg1;\n const incrementUsageCount = arg2 as boolean;\n const callTime = new Date().toISOString();\n\n // 只更新 customMCP 中的统计信息\n await this.updateCustomMCPToolStats(\n toolName,\n callTime,\n incrementUsageCount\n );\n\n console.log(\"CustomMCP 工具使用统计已更新\", { toolName });\n }\n } catch (error) {\n // 错误不应该影响主要的工具调用流程\n if (typeof arg2 === \"string\" && arg3) {\n const serverName = arg1;\n const toolName = arg2;\n console.error(\"更新工具使用统计失败\", { serverName, toolName, error });\n } else {\n const toolName = arg1;\n console.error(\"更新 CustomMCP 工具使用统计失败\", { toolName, error });\n }\n }\n }\n\n /**\n * 更新 MCP 服务工具统计信息(重载方法)\n * @param serviceName 服务名称\n * @param toolName 工具名称\n * @param callTime 调用时间(ISO 8601 格式)\n * @param incrementUsageCount 是否增加使用计数,默认为 true\n */\n public async updateMCPServerToolStats(\n serviceName: string,\n toolName: string,\n callTime: string,\n incrementUsageCount = true\n ): Promise<void> {\n await this._updateMCPServerToolStats(\n serviceName,\n toolName,\n callTime,\n incrementUsageCount\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 this.emitEvent(\"config:updated\", {\n type: \"modelscope\",\n timestamp: new Date(),\n });\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 * 获取 customMCP 配置\n */\n public getCustomMCPConfig(): CustomMCPConfig | null {\n const config = this.getConfig();\n return config.customMCP || null;\n }\n\n /**\n * 获取 customMCP 工具列表\n */\n public getCustomMCPTools(): CustomMCPTool[] {\n const customMCPConfig = this.getCustomMCPConfig();\n if (!customMCPConfig || !customMCPConfig.tools) {\n return [];\n }\n\n return customMCPConfig.tools;\n }\n\n /**\n * 验证 customMCP 工具配置\n */\n public validateCustomMCPTools(tools: CustomMCPTool[]): boolean {\n if (!Array.isArray(tools)) {\n return false;\n }\n\n for (const tool of tools) {\n // 检查必需字段\n if (!tool.name || typeof tool.name !== \"string\") {\n console.warn(\"CustomMCP 工具缺少有效的 name 字段\", { tool });\n return false;\n }\n\n if (!tool.description || typeof tool.description !== \"string\") {\n console.warn(\"CustomMCP 工具缺少有效的 description 字段\", {\n toolName: tool.name,\n });\n return false;\n }\n\n if (!tool.inputSchema || typeof tool.inputSchema !== \"object\") {\n console.warn(\"CustomMCP 工具缺少有效的 inputSchema 字段\", {\n toolName: tool.name,\n });\n return false;\n }\n\n if (!tool.handler || typeof tool.handler !== \"object\") {\n console.warn(\"CustomMCP 工具缺少有效的 handler 字段\", {\n toolName: tool.name,\n });\n return false;\n }\n\n // 检查 handler 类型\n if (\n ![\"proxy\", \"function\", \"http\", \"script\", \"chain\", \"mcp\"].includes(\n tool.handler.type\n )\n ) {\n console.warn(\"CustomMCP 工具的 handler.type 类型无效\", {\n toolName: tool.name,\n type: tool.handler.type,\n });\n return false;\n }\n\n // 根据处理器类型进行特定验证\n if (!this.validateHandlerConfig(tool.name, tool.handler)) {\n return false;\n }\n }\n\n return true;\n }\n\n /**\n * 验证处理器配置\n */\n private validateHandlerConfig(\n toolName: string,\n handler: HandlerConfig\n ): boolean {\n switch (handler.type) {\n case \"proxy\":\n return this.validateProxyHandler(toolName, handler);\n case \"http\":\n return this.validateHttpHandler(toolName, handler);\n case \"function\":\n return this.validateFunctionHandler(toolName, handler);\n case \"script\":\n return this.validateScriptHandler(toolName, handler);\n case \"chain\":\n return this.validateChainHandler(toolName, handler);\n case \"mcp\":\n return this.validateMCPHandler(toolName, handler);\n default:\n console.warn(\"CustomMCP 工具使用了未知的处理器类型\", {\n toolName,\n handlerType: (handler as HandlerConfig).type,\n });\n return false;\n }\n }\n\n /**\n * 验证代理处理器配置\n */\n private validateProxyHandler(\n toolName: string,\n handler: ProxyHandlerConfig\n ): boolean {\n if (!handler.platform) {\n console.warn(\"CustomMCP 工具的 proxy 处理器缺少 platform 字段\", {\n toolName,\n });\n return false;\n }\n\n if (![\"coze\", \"openai\", \"anthropic\", \"custom\"].includes(handler.platform)) {\n console.warn(\"CustomMCP 工具的 proxy 处理器使用了不支持的平台\", {\n toolName,\n platform: handler.platform,\n });\n return false;\n }\n\n if (!handler.config || typeof handler.config !== \"object\") {\n console.warn(\"CustomMCP 工具的 proxy 处理器缺少 config 字段\", {\n toolName,\n });\n return false;\n }\n\n // Coze 平台特定验证\n if (handler.platform === \"coze\") {\n if (!handler.config.workflow_id && !handler.config.bot_id) {\n console.warn(\n \"CustomMCP 工具的 Coze 处理器必须提供 workflow_id 或 bot_id\",\n { toolName }\n );\n return false;\n }\n }\n\n return true;\n }\n\n /**\n * 验证 HTTP 处理器配置\n */\n private validateHttpHandler(\n toolName: string,\n handler: HttpHandlerConfig\n ): boolean {\n if (!handler.url || typeof handler.url !== \"string\") {\n console.warn(\"CustomMCP 工具的 http 处理器缺少有效的 url 字段\", {\n toolName,\n });\n return false;\n }\n\n try {\n new URL(handler.url);\n } catch {\n console.warn(\"CustomMCP 工具的 http 处理器 url 格式无效\", {\n toolName,\n url: handler.url,\n });\n return false;\n }\n\n if (\n handler.method &&\n ![\"GET\", \"POST\", \"PUT\", \"DELETE\", \"PATCH\"].includes(handler.method)\n ) {\n console.warn(\"CustomMCP 工具的 http 处理器使用了不支持的 HTTP 方法\", {\n toolName,\n method: handler.method,\n });\n return false;\n }\n\n return true;\n }\n\n /**\n * 验证函数处理器配置\n */\n private validateFunctionHandler(\n toolName: string,\n handler: FunctionHandlerConfig\n ): boolean {\n if (!handler.module || typeof handler.module !== \"string\") {\n console.warn(\"CustomMCP 工具的 function 处理器缺少有效的 module 字段\", {\n toolName,\n });\n return false;\n }\n\n if (!handler.function || typeof handler.function !== \"string\") {\n console.warn(\"CustomMCP 工具的 function 处理器缺少有效的 function 字段\", {\n toolName,\n });\n return false;\n }\n\n return true;\n }\n\n /**\n * 验证脚本处理器配置\n */\n private validateScriptHandler(\n toolName: string,\n handler: ScriptHandlerConfig\n ): boolean {\n if (!handler.script || typeof handler.script !== \"string\") {\n console.warn(\"CustomMCP 工具的 script 处理器缺少有效的 script 字段\", {\n toolName,\n });\n return false;\n }\n\n if (\n handler.interpreter &&\n ![\"node\", \"python\", \"bash\"].includes(handler.interpreter)\n ) {\n console.warn(\"CustomMCP 工具的 script 处理器使用了不支持的解释器\", {\n toolName,\n interpreter: handler.interpreter,\n });\n return false;\n }\n\n return true;\n }\n\n /**\n * 验证链式处理器配置\n */\n private validateChainHandler(\n toolName: string,\n handler: ChainHandlerConfig\n ): boolean {\n if (\n !handler.tools ||\n !Array.isArray(handler.tools) ||\n handler.tools.length === 0\n ) {\n console.warn(\"CustomMCP 工具的 chain 处理器缺少有效的 tools 数组\", {\n toolName,\n });\n return false;\n }\n\n if (![\"sequential\", \"parallel\"].includes(handler.mode)) {\n console.warn(\"CustomMCP 工具的 chain 处理器使用了不支持的执行模式\", {\n toolName,\n mode: handler.mode,\n });\n return false;\n }\n\n if (![\"stop\", \"continue\", \"retry\"].includes(handler.error_handling)) {\n console.warn(\"CustomMCP 工具的 chain 处理器使用了不支持的错误处理策略\", {\n toolName,\n errorHandling: handler.error_handling,\n });\n return false;\n }\n\n return true;\n }\n\n /**\n * 验证 MCP 处理器配置\n */\n private validateMCPHandler(\n toolName: string,\n handler: MCPHandlerConfig\n ): boolean {\n if (!handler.config || typeof handler.config !== \"object\") {\n console.warn(\"CustomMCP 工具的 mcp 处理器缺少 config 字段\", { toolName });\n return false;\n }\n\n if (\n !handler.config.serviceName ||\n typeof handler.config.serviceName !== \"string\"\n ) {\n console.warn(\"CustomMCP 工具的 mcp 处理器缺少有效的 serviceName\", {\n toolName,\n });\n return false;\n }\n\n if (\n !handler.config.toolName ||\n typeof handler.config.toolName !== \"string\"\n ) {\n console.warn(\"CustomMCP 工具的 mcp 处理器缺少有效的 toolName\", {\n toolName,\n });\n return false;\n }\n\n return true;\n }\n\n /**\n * 检查是否配置了有效的 customMCP 工具\n */\n public hasValidCustomMCPTools(): boolean {\n try {\n const tools = this.getCustomMCPTools();\n if (tools.length === 0) {\n return false;\n }\n\n return this.validateCustomMCPTools(tools);\n } catch (error) {\n console.error(\"检查 customMCP 工具配置时出错\", { error });\n return false;\n }\n }\n\n /**\n * 添加自定义 MCP 工具\n */\n public addCustomMCPTool(tool: CustomMCPTool): void {\n if (!tool || typeof tool !== \"object\") {\n throw new Error(\"工具配置不能为空\");\n }\n\n const config = this.getMutableConfig();\n\n // 确保 customMCP 配置存在\n if (!config.customMCP) {\n config.customMCP = { tools: [] };\n }\n\n // 检查工具名称是否已存在\n const existingTool = config.customMCP.tools.find(\n (t) => t.name === tool.name\n );\n if (existingTool) {\n throw new Error(`工具 \"${tool.name}\" 已存在`);\n }\n\n // 验证工具配置\n if (!this.validateCustomMCPTools([tool])) {\n throw new Error(\"工具配置验证失败\");\n }\n\n // 添加工具\n config.customMCP.tools.unshift(tool);\n this.saveConfig(config);\n\n console.log(\"成功添加自定义 MCP 工具\", { toolName: tool.name });\n }\n\n /**\n * 批量添加自定义 MCP 工具\n * @param tools 要添加的工具数组\n */\n public async addCustomMCPTools(tools: CustomMCPTool[]): Promise<void> {\n if (!Array.isArray(tools)) {\n throw new Error(\"工具配置必须是数组\");\n }\n\n if (tools.length === 0) {\n return; // 空数组,无需处理\n }\n\n const config = this.getMutableConfig();\n\n // 确保 customMCP 配置存在\n if (!config.customMCP) {\n config.customMCP = { tools: [] };\n }\n\n // 添加新工具,避免重复\n const existingNames = new Set(\n config.customMCP.tools.map((tool) => tool.name)\n );\n const newTools = tools.filter((tool) => !existingNames.has(tool.name));\n\n if (newTools.length > 0) {\n // 验证新工具配置\n if (!this.validateCustomMCPTools(newTools)) {\n throw new Error(\"工具配置验证失败\");\n }\n\n // 添加工具\n config.customMCP.tools.push(...newTools);\n this.saveConfig(config);\n\n // 发射配置更新事件\n this.emitEvent(\"config:updated\", {\n type: \"customMCP\",\n timestamp: new Date(),\n });\n\n console.log(\"成功批量添加自定义 MCP 工具\", {\n count: newTools.length,\n toolNames: newTools.map((t) => t.name),\n });\n }\n }\n\n /**\n * 删除自定义 MCP 工具\n */\n public removeCustomMCPTool(toolName: string): void {\n if (!toolName || typeof toolName !== \"string\") {\n throw new Error(\"工具名称不能为空\");\n }\n\n const config = this.getMutableConfig();\n\n if (!config.customMCP || !config.customMCP.tools) {\n throw new Error(\"未配置自定义 MCP 工具\");\n }\n\n const toolIndex = config.customMCP.tools.findIndex(\n (t) => t.name === toolName\n );\n if (toolIndex === -1) {\n throw new Error(`工具 \"${toolName}\" 不存在`);\n }\n\n // 删除工具\n config.customMCP.tools.splice(toolIndex, 1);\n this.saveConfig(config);\n\n console.log(\"成功删除自定义 MCP 工具\", { toolName });\n }\n\n /**\n * 更新单个自定义 MCP 工具配置\n * @param toolName 工具名称\n * @param updatedTool 更新后的工具配置\n */\n public updateCustomMCPTool(\n toolName: string,\n updatedTool: CustomMCPTool\n ): void {\n if (!toolName || typeof toolName !== \"string\") {\n throw new Error(\"工具名称不能为空\");\n }\n if (!updatedTool || typeof updatedTool !== \"object\") {\n throw new Error(\"更新后的工具配置不能为空\");\n }\n\n const config = this.getMutableConfig();\n\n if (!config.customMCP || !config.customMCP.tools) {\n throw new Error(\"未配置自定义 MCP 工具\");\n }\n\n const toolIndex = config.customMCP.tools.findIndex(\n (t) => t.name === toolName\n );\n if (toolIndex === -1) {\n throw new Error(`工具 \"${toolName}\" 不存在`);\n }\n\n // 验证更新后的工具配置\n if (!this.validateCustomMCPTools([updatedTool])) {\n throw new Error(\"更新后的工具配置验证失败\");\n }\n\n // 更新工具配置\n config.customMCP.tools[toolIndex] = updatedTool;\n this.saveConfig(config);\n\n console.log(\"成功更新自定义 MCP 工具\", { toolName });\n }\n\n /**\n * 更新自定义 MCP 工具配置\n */\n public updateCustomMCPTools(tools: CustomMCPTool[]): void {\n if (!Array.isArray(tools)) {\n throw new Error(\"工具配置必须是数组\");\n }\n\n // 验证工具配置\n if (!this.validateCustomMCPTools(tools)) {\n throw new Error(\"工具配置验证失败\");\n }\n\n const config = this.getMutableConfig();\n\n // 确保 customMCP 配置存在\n if (!config.customMCP) {\n config.customMCP = { tools: [] };\n }\n\n config.customMCP.tools = tools;\n this.saveConfig(config);\n\n // 发射配置更新事件\n this.emitEvent(\"config:updated\", {\n type: \"customMCP\",\n timestamp: new Date(),\n });\n\n console.log(\"成功更新自定义 MCP 工具配置\", { count: tools.length });\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 = (\n global as typeof global & { __webServer?: WebServerInstance }\n ).__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 this.emitEvent(\"config:updated\", {\n type: \"webui\",\n timestamp: new Date(),\n });\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 public updatePlatformConfig(\n platformName: string,\n platformConfig: PlatformConfig\n ): void {\n const config = this.getMutableConfig();\n if (!config.platforms) {\n config.platforms = {};\n }\n config.platforms[platformName] = platformConfig;\n // 注意:Web UI 可能需要刷新才能看到更新后的数据\n this.saveConfig(config);\n\n // 发射配置更新事件\n this.emitEvent(\"config:updated\", {\n type: \"platform\",\n platformName,\n timestamp: new Date(),\n });\n }\n\n /**\n * 获取扣子平台配置\n */\n public getCozePlatformConfig(): CozePlatformConfig | null {\n const config = this.getConfig();\n const cozeConfig = config.platforms?.coze;\n\n if (!cozeConfig || !cozeConfig.token) {\n return null;\n }\n\n return {\n token: cozeConfig.token,\n };\n }\n\n /**\n * 获取扣子 API Token\n */\n public getCozeToken(): string | null {\n const cozeConfig = this.getCozePlatformConfig();\n return cozeConfig?.token || null;\n }\n\n /**\n * 设置扣子平台配置\n */\n public setCozePlatformConfig(config: CozePlatformConfig): void {\n if (\n !config.token ||\n typeof config.token !== \"string\" ||\n config.token.trim() === \"\"\n ) {\n throw new Error(\"扣子 API Token 不能为空\");\n }\n\n this.updatePlatformConfig(\"coze\", {\n token: config.token.trim(),\n });\n }\n\n /**\n * 检查扣子平台配置是否有效\n */\n public isCozeConfigValid(): boolean {\n const cozeConfig = this.getCozePlatformConfig();\n return (\n cozeConfig !== null &&\n typeof cozeConfig.token === \"string\" &&\n cozeConfig.token.trim() !== \"\"\n );\n }\n\n /**\n * 更新 mcpServerConfig 中的工具使用统计信息(内部实现)\n * @param serverName 服务名称\n * @param toolName 工具名称\n * @param callTime 调用时间(ISO 8601 格式)\n * @param incrementUsageCount 是否增加使用计数\n * @private\n */\n private async _updateMCPServerToolStats(\n serverName: string,\n toolName: string,\n callTime: string,\n incrementUsageCount = true\n ): Promise<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 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 if (incrementUsageCount) {\n toolConfig.usageCount = currentUsageCount + 1;\n }\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\n /**\n * 更新 customMCP 中的工具使用统计信息(服务名+工具名版本)\n * @param serverName 服务名称\n * @param toolName 工具名称\n * @param callTime 调用时间(ISO 8601 格式)\n * @private\n */\n private async updateCustomMCPToolStats(\n serverName: string,\n toolName: string,\n callTime: string\n ): Promise<void>;\n\n /**\n * 更新 customMCP 中的工具使用统计信息(工具名版本)\n * @param toolName 工具名称(customMCP 工具名称)\n * @param callTime 调用时间(ISO 8601 格式)\n * @param incrementUsageCount 是否增加使用计数,默认为 true\n * @private\n */\n private async updateCustomMCPToolStats(\n toolName: string,\n callTime: string,\n incrementUsageCount?: boolean\n ): Promise<void>;\n\n /**\n * 更新 customMCP 工具使用统计信息的实现\n * @private\n */\n private async updateCustomMCPToolStats(\n arg1: string,\n arg2: string,\n arg3?: string | boolean\n ): Promise<void> {\n try {\n let toolName: string;\n let callTime: string;\n let incrementUsageCount = true;\n let logPrefix: string;\n\n // 判断参数类型来区分不同的重载\n if (typeof arg3 === \"string\") {\n // 三个字符串参数的情况:updateCustomMCPToolStats(serverName, toolName, callTime)\n const serverName = arg1;\n toolName = `${serverName}__${arg2}`;\n callTime = arg3;\n logPrefix = `${serverName}/${arg2}`;\n } else {\n // 两个或三个参数的情况:updateCustomMCPToolStats(toolName, callTime, incrementUsageCount?)\n toolName = arg1;\n callTime = arg2;\n incrementUsageCount = (arg3 as boolean) || true;\n logPrefix = toolName;\n }\n\n const customTools = this.getCustomMCPTools();\n const toolIndex = customTools.findIndex((tool) => tool.name === toolName);\n\n if (toolIndex === -1) {\n // 如果 customMCP 中没有对应的工具,跳过更新\n return;\n }\n\n const updatedTools = [...customTools];\n const tool = updatedTools[toolIndex];\n\n // 确保 stats 对象存在\n if (!tool.stats) {\n tool.stats = {};\n }\n\n const currentUsageCount = tool.stats.usageCount || 0;\n const currentLastUsedTime = tool.stats.lastUsedTime;\n\n // 根据参数决定是否更新使用次数\n if (incrementUsageCount) {\n tool.stats.usageCount = currentUsageCount + 1;\n }\n\n // 时间校验:只有新时间晚于现有时间才更新 lastUsedTime\n if (\n !currentLastUsedTime ||\n new Date(callTime) > new Date(currentLastUsedTime)\n ) {\n tool.stats.lastUsedTime = dayjs(callTime).format(\"YYYY-MM-DD HH:mm:ss\");\n }\n\n // 保存更新后的工具配置\n await this.updateCustomMCPTools(updatedTools);\n } catch (error) {\n // 根据参数类型决定错误日志的前缀\n if (typeof arg3 === \"string\") {\n const serverName = arg1;\n const toolName = arg2;\n console.error(\"更新 customMCP 工具统计信息失败\", {\n serverName,\n toolName,\n error,\n });\n } else {\n const toolName = arg1;\n console.error(\"更新 customMCP 工具统计信息失败\", { toolName, error });\n }\n // customMCP 统计更新失败不应该影响主要流程\n }\n }\n\n /**\n * 获取统计更新锁(确保同一工具的统计更新串行执行)\n * @param toolKey 工具键\n * @private\n */\n private async acquireStatsUpdateLock(toolKey: string): Promise<boolean> {\n if (this.statsUpdateLocks.has(toolKey)) {\n console.log(\"工具统计更新正在进行中,跳过本次更新\", { toolKey });\n return false;\n }\n\n const updatePromise = new Promise<void>((resolve) => {\n // 锁定逻辑在调用者中实现\n });\n\n this.statsUpdateLocks.set(toolKey, updatePromise);\n\n // 设置超时自动释放锁\n const timeout = setTimeout(() => {\n this.releaseStatsUpdateLock(toolKey);\n }, this.STATS_UPDATE_TIMEOUT);\n\n this.statsUpdateLockTimeouts.set(toolKey, timeout);\n\n return true;\n }\n\n /**\n * 释放统计更新锁\n * @param toolKey 工具键\n * @private\n */\n private releaseStatsUpdateLock(toolKey: string): void {\n this.statsUpdateLocks.delete(toolKey);\n\n const timeout = this.statsUpdateLockTimeouts.get(toolKey);\n if (timeout) {\n clearTimeout(timeout);\n }\n this.statsUpdateLockTimeouts.delete(toolKey);\n\n console.log(\"已释放工具的统计更新锁\", { toolKey });\n }\n\n /**\n * 带并发控制的工具统计更新(CustomMCP 工具)\n * @param toolName 工具名称\n * @param incrementUsageCount 是否增加使用计数\n */\n public async updateToolUsageStatsWithLock(\n toolName: string,\n incrementUsageCount = true\n ): Promise<void> {\n const toolKey = `custommcp_${toolName}`;\n\n if (!(await this.acquireStatsUpdateLock(toolKey))) {\n return; // 已有其他更新在进行\n }\n\n try {\n await this.updateToolUsageStats(toolName, incrementUsageCount);\n console.log(\"工具统计更新完成\", { toolName });\n } catch (error) {\n console.error(\"工具统计更新失败\", { toolName, error });\n throw error;\n } finally {\n this.releaseStatsUpdateLock(toolKey);\n }\n }\n\n /**\n * 带并发控制的工具统计更新(MCP 服务工具)\n * @param serviceName 服务名称\n * @param toolName 工具名称\n * @param callTime 调用时间\n * @param incrementUsageCount 是否增加使用计数\n */\n public async updateMCPServerToolStatsWithLock(\n serviceName: string,\n toolName: string,\n callTime: string,\n incrementUsageCount = true\n ): Promise<void> {\n const toolKey = `mcpserver_${serviceName}_${toolName}`;\n\n if (!(await this.acquireStatsUpdateLock(toolKey))) {\n return; // 已有其他更新在进行\n }\n\n try {\n await this.updateMCPServerToolStats(\n serviceName,\n toolName,\n callTime,\n incrementUsageCount\n );\n console.log(\"MCP 服务工具统计更新完成\", { serviceName, toolName });\n } catch (error) {\n console.error(\"MCP 服务工具统计更新失败\", {\n serviceName,\n toolName,\n error,\n });\n throw error;\n } finally {\n this.releaseStatsUpdateLock(toolKey);\n }\n }\n\n /**\n * 清理所有统计更新锁(用于异常恢复)\n */\n public clearAllStatsUpdateLocks(): void {\n const lockCount = this.statsUpdateLocks.size;\n this.statsUpdateLocks.clear();\n\n // 清理所有超时定时器\n for (const timeout of this.statsUpdateLockTimeouts.values()) {\n clearTimeout(timeout);\n }\n this.statsUpdateLockTimeouts.clear();\n\n if (lockCount > 0) {\n console.log(\"已清理统计更新锁\", { count: lockCount });\n }\n }\n\n /**\n * 获取统计更新锁状态(用于调试和监控)\n */\n public getStatsUpdateLocks(): string[] {\n return Array.from(this.statsUpdateLocks.keys());\n }\n\n /**\n * 获取工具调用日志配置\n */\n public getToolCallLogConfig(): Readonly<ToolCallLogConfig> {\n const config = this.getConfig();\n return config.toolCallLog || {};\n }\n\n /**\n * 更新工具调用日志配置\n */\n public updateToolCallLogConfig(\n toolCallLogConfig: Partial<ToolCallLogConfig>\n ): void {\n const config = this.getMutableConfig();\n\n // 确保 toolCallLog 对象存在\n if (!config.toolCallLog) {\n config.toolCallLog = {};\n }\n\n // 直接修改现有的 toolCallLog 对象以保留注释\n Object.assign(config.toolCallLog, toolCallLogConfig);\n this.saveConfig(config);\n }\n\n /**\n * 获取配置目录路径(与配置文件同级目录)\n */\n public getConfigDir(): string {\n // 配置文件路径 - 优先使用环境变量指定的目录,否则使用当前工作目录\n return process.env.XIAOZHI_CONFIG_DIR || process.cwd();\n }\n\n /**\n * 获取 TTS 配置\n */\n public getTTSConfig(): Readonly<TTSConfig> {\n const config = this.getConfig();\n return config.tts || {};\n }\n\n /**\n * 获取 ASR 配置\n */\n public getASRConfig(): Readonly<ASRConfig> {\n const config = this.getConfig();\n return config.asr || {};\n }\n\n /**\n * 获取 LLM 配置\n */\n public getLLMConfig(): LLMConfig | null {\n const config = this.getConfig();\n return config.llm || null;\n }\n\n /**\n * 检查 LLM 配置是否有效\n */\n public isLLMConfigValid(): boolean {\n const llmConfig = this.getLLMConfig();\n return (\n llmConfig !== null &&\n typeof llmConfig.model === \"string\" &&\n llmConfig.model.trim() !== \"\" &&\n typeof llmConfig.apiKey === \"string\" &&\n llmConfig.apiKey.trim() !== \"\" &&\n typeof llmConfig.baseURL === \"string\" &&\n llmConfig.baseURL.trim() !== \"\"\n );\n }\n\n /**\n * 更新 TTS 配置\n */\n public updateTTSConfig(ttsConfig: Partial<TTSConfig>): void {\n const config = this.getMutableConfig();\n\n // 确保 tts 对象存在\n if (!config.tts) {\n config.tts = {};\n }\n\n // 直接修改现有的 tts 对象以保留注释\n Object.assign(config.tts, ttsConfig);\n this.saveConfig(config);\n\n // 发射配置更新事件\n this.emitEvent(\"config:updated\", {\n type: \"tts\",\n timestamp: new Date(),\n });\n }\n}\n\n// 导出单例实例\nexport const configManager = ConfigManager.getInstance();\n","/**\n * MCP 核心库类型定义\n * 统一管理所有 MCP 相关的类型定义\n */\n\nimport type { SSEClientTransport } from \"@modelcontextprotocol/sdk/client/sse.js\";\nimport type { StdioClientTransport } from \"@modelcontextprotocol/sdk/client/stdio.js\";\nimport type { StreamableHTTPClientTransport } from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\n\n// =========================\n// 1. 基础传输类型\n// =========================\n\n/**\n * MCP 传输层联合类型定义\n * 支持 STDIO、SSE、StreamableHTTP 三种传输协议\n */\nexport type MCPServerTransport =\n | StdioClientTransport\n | SSEClientTransport\n | StreamableHTTPClientTransport;\n\n/**\n * 通信方式枚举\n * 定义 MCP 支持的传输类型\n */\nexport enum MCPTransportType {\n STDIO = \"stdio\",\n SSE = \"sse\",\n HTTP = \"http\",\n}\n\n/**\n * 传输类型字符串字面量\n * 方便外部用户直接使用字符串而不需要导入枚举\n */\nexport type MCPTransportTypeString = \"stdio\" | \"sse\" | \"http\";\n\n/**\n * 传输类型输入值(枚举或字符串字面量)\n */\nexport type MCPTransportTypeInput = MCPTransportType | MCPTransportTypeString;\n\n// =========================\n// 1.1 事件回调接口\n// =========================\n\n/**\n * MCP 服务事件回调接口\n * 用于替代 EventBus 依赖,提供灵活的事件处理机制\n */\nexport interface MCPServiceEventCallbacks {\n /** 连接成功回调 */\n onConnected?: (data: {\n serviceName: string;\n tools: Tool[];\n connectionTime: Date;\n }) => void;\n /** 断开连接回调 */\n onDisconnected?: (data: {\n serviceName: string;\n reason?: string;\n disconnectionTime: Date;\n }) => void;\n /** 连接失败回调 */\n onConnectionFailed?: (data: {\n serviceName: string;\n error: Error;\n attempt: number;\n }) => void;\n}\n\n// =========================\n// 2. 配置接口类型\n// =========================\n\n/**\n * ModelScope SSE 自定义选项接口\n */\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/**\n * 心跳检测配置接口\n */\nexport interface HeartbeatConfig {\n /** 是否启用心跳检测(默认 true) */\n enabled?: boolean;\n /** 心跳间隔(毫秒,默认 30000 = 30秒) */\n interval?: number;\n}\n\n/**\n * MCP 服务配置接口\n * 包含所有 MCP 服务的配置选项(不包含服务名称)\n *\n * @description\n * 与 MCP 官方配置格式保持一致,支持三种传输类型:\n * - stdio: 本地进程通信 { command, args, env }\n * - sse: Server-Sent Events { url, headers }\n * - http: Streamable HTTP { url, headers }\n *\n * 向后兼容:自动将 streamable-http/streamable_http/streamableHttp 转换为 http\n */\nexport interface MCPServiceConfig {\n // name 字段已从配置中移除,应作为独立参数传递\n type?: MCPTransportTypeInput; // 支持枚举或字符串字面量,如 \"stdio\" | \"sse\" | \"http\"\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 customSSEOptions?: ModelScopeSSEOptions;\n // 心跳配置\n heartbeat?: HeartbeatConfig;\n}\n\n/**\n * 旧版 MCP 服务配置接口(包含 name 字段)\n * 用于向后兼容\n */\nexport interface LegacyMCPServiceConfig extends MCPServiceConfig {\n name: string;\n}\n\n/**\n * 内部使用的 MCP 服务配置接口(包含 name 字段)\n * 用于 TransportFactory 等内部函数\n */\nexport interface InternalMCPServiceConfig extends MCPServiceConfig {\n name: string;\n}\n\n// =========================\n// 3. 状态枚举类型\n// =========================\n\n/**\n * 连接状态枚举\n */\nexport enum ConnectionState {\n DISCONNECTED = \"disconnected\",\n CONNECTING = \"connecting\",\n CONNECTED = \"connected\",\n RECONNECTING = \"reconnecting\",\n FAILED = \"failed\",\n ERROR = \"error\",\n}\n\n/**\n * MCP 服务状态接口\n */\nexport interface MCPServiceStatus {\n name: string;\n connected: boolean;\n initialized: boolean;\n transportType: MCPTransportType;\n toolCount: number;\n lastError?: string;\n connectionState: ConnectionState;\n}\n\n// =========================\n// 4. 工具调用相关类型\n// =========================\n\n// 从 MCP SDK 重新导出工具调用结果类型\n// 使用 CompatibilityCallToolResult 以支持新旧协议版本\nexport type { CompatibilityCallToolResult as ToolCallResult } from \"@modelcontextprotocol/sdk/types.js\";\n\n/**\n * JSON Schema 类型定义\n */\nexport type JSONSchema =\n | (Record<string, unknown> & {\n type: \"object\";\n properties?: Record<string, unknown>;\n required?: string[];\n additionalProperties?: boolean;\n })\n | Record<string, unknown>;\n\n/**\n * 类型守卫:检查对象是否为有效的 MCP Tool JSON Schema\n */\nexport function isValidToolJSONSchema(obj: unknown): obj is {\n type: \"object\";\n properties?: Record<string, unknown>;\n required?: string[];\n additionalProperties?: boolean;\n} {\n return (\n typeof obj === \"object\" &&\n obj !== null &&\n \"type\" in obj &&\n (obj as { type?: unknown }).type === \"object\"\n );\n}\n\n/**\n * 确保对象符合 MCP Tool JSON Schema 格式\n */\nexport function ensureToolJSONSchema(schema: JSONSchema): {\n type: \"object\";\n properties?: Record<string, object>;\n required?: string[];\n additionalProperties?: boolean;\n} {\n if (isValidToolJSONSchema(schema)) {\n return schema as {\n type: \"object\";\n properties?: Record<string, object>;\n required?: string[];\n additionalProperties?: boolean;\n };\n }\n\n return {\n type: \"object\",\n properties: {} as Record<string, object>,\n required: [],\n additionalProperties: true,\n };\n}\n\n/**\n * CustomMCP 工具类型定义\n */\nexport interface CustomMCPTool {\n name: string;\n description?: string;\n inputSchema: JSONSchema;\n handler?: {\n type: string;\n config?: Record<string, unknown>;\n };\n}\n\n/**\n * 工具信息接口\n */\nexport interface ToolInfo {\n serviceName: string;\n originalName: string;\n tool: Tool;\n}\n\n// =========================\n// 5. 增强工具信息类型\n// =========================\n\n/**\n * 工具状态过滤选项\n */\nexport type ToolStatusFilter = \"enabled\" | \"disabled\" | \"all\";\n\n/**\n * 增强的工具信息接口\n */\nexport interface EnhancedToolInfo {\n /** 工具唯一标识符,格式为 \"{serviceName}__{originalName}\" */\n name: string;\n /** 工具描述信息 */\n description: string;\n /** 工具输入参数的 JSON Schema 定义 */\n inputSchema: JSONSchema;\n /** 工具所属的 MCP 服务名称 */\n serviceName: string;\n /** 工具在 MCP 服务中的原始名称 */\n originalName: string;\n /** 工具是否启用 */\n enabled: boolean;\n /** 工具使用次数统计 */\n usageCount: number;\n /** 工具最后使用时间 */\n lastUsedTime: string;\n}\n\n// =========================\n// 6. 服务器配置类型\n// =========================\n\n/**\n * 统一服务器配置接口\n */\nexport interface UnifiedServerConfig {\n name?: string;\n enableLogging?: boolean;\n logLevel?: string;\n configs?: Record<string, MCPServiceConfig>;\n}\n\n/**\n * 统一服务器状态接口\n */\nexport interface UnifiedServerStatus {\n isRunning: boolean;\n serviceStatus: ManagerStatus;\n transportCount: number;\n activeConnections: number;\n config: UnifiedServerConfig;\n services?: Record<string, MCPServiceConnectionStatus>;\n totalTools?: number;\n availableTools?: string[];\n}\n\n// =========================\n// 7. 管理器相关类型\n// =========================\n\n/**\n * MCP 服务连接状态接口\n */\nexport interface MCPServiceConnectionStatus {\n connected: boolean;\n clientName: string;\n}\n\n/**\n * 管理器状态接口\n */\nexport interface ManagerStatus {\n services: Record<string, MCPServiceConnectionStatus>;\n totalTools: number;\n availableTools: string[];\n}\n\n// =========================\n// 8. 参数校验相关类型\n// =========================\n\n/**\n * 工具调用参数接口\n */\nexport interface ToolCallParams {\n name: string;\n arguments?: Record<string, unknown>;\n}\n\n/**\n * 验证后的工具调用参数\n */\nexport interface ValidatedToolCallParams {\n name: string;\n arguments?: Record<string, unknown>;\n}\n\n/**\n * 工具调用验证选项\n */\nexport interface ToolCallValidationOptions {\n validateName?: boolean;\n validateArguments?: boolean;\n allowEmptyArguments?: boolean;\n customValidator?: (params: ToolCallParams) => string | null;\n}\n\n/**\n * 工具调用错误码枚举\n */\nexport enum ToolCallErrorCode {\n INVALID_PARAMS = -32602,\n TOOL_NOT_FOUND = -32601,\n SERVICE_UNAVAILABLE = -32001,\n TIMEOUT = -32002,\n TOOL_EXECUTION_ERROR = -32000,\n}\n\n/**\n * 工具调用错误类\n */\nexport class ToolCallError extends Error {\n constructor(\n public code: ToolCallErrorCode,\n message: string,\n public data?: unknown\n ) {\n super(message);\n this.name = \"ToolCallError\";\n }\n}\n","/**\n * MCP 传输层工厂模块\n *\n * 提供创建不同类型传输层实例的工厂函数\n * 支持 STDIO、SSE、StreamableHTTP 三种传输协议\n *\n * @module transport-factory\n */\n\nimport type { SSEClientTransportOptions } from \"@modelcontextprotocol/sdk/client/sse.js\";\nimport { SSEClientTransport } from \"@modelcontextprotocol/sdk/client/sse.js\";\nimport { StdioClientTransport } from \"@modelcontextprotocol/sdk/client/stdio.js\";\nimport type { StreamableHTTPClientTransportOptions } from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\nimport { StreamableHTTPClientTransport } from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\nimport { EventSource } from \"eventsource\";\nimport type { InternalMCPServiceConfig, MCPServerTransport } from \"./types.js\";\nimport { MCPTransportType } from \"./types.js\";\n\n// 全局 polyfill EventSource(用于 SSE)\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst globalThisAny: any =\n typeof globalThis !== \"undefined\" ? globalThis : global;\nif (typeof globalThisAny !== \"undefined\" && !globalThisAny.EventSource) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n globalThisAny.EventSource = EventSource;\n}\n\n// Transport 基础接口\nexport interface Transport {\n connect?(): Promise<void>;\n close?(): Promise<void>;\n}\n\n/**\n * 创建 transport 实例\n * @param config MCP 服务配置(包含 name)\n * @returns transport 实例\n */\nexport function createTransport(\n config: InternalMCPServiceConfig\n): MCPServerTransport {\n console.debug(\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.HTTP:\n return createHTTPTransport(config);\n\n default:\n throw new Error(`不支持的传输类型: ${config.type}`);\n }\n}\n\n/**\n * 创建 Stdio transport\n */\nfunction createStdioTransport(\n config: InternalMCPServiceConfig\n): 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(\n config: InternalMCPServiceConfig\n): 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\nfunction createHTTPTransport(\n config: InternalMCPServiceConfig\n): StreamableHTTPClientTransport {\n if (!config.url) {\n throw new Error(\"HTTP 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 * 创建认证请求头\n */\nfunction createAuthHeaders(\n config: InternalMCPServiceConfig\n): Record<string, string> | undefined {\n if (config.apiKey) {\n return {\n Authorization: `Bearer ${config.apiKey}`,\n ...config.headers,\n };\n }\n return config.headers;\n}\n\n/**\n * 创建 SSE 选项\n */\nfunction createSSEOptions(\n config: InternalMCPServiceConfig\n): SSEClientTransportOptions {\n const options: SSEClientTransportOptions = {};\n\n const headers = createAuthHeaders(config);\n if (headers) {\n options.requestInit = {\n headers,\n };\n }\n\n return options;\n}\n\nfunction createStreamableHTTPOptions(\n config: InternalMCPServiceConfig\n): StreamableHTTPClientTransportOptions {\n const options: StreamableHTTPClientTransportOptions = {};\n\n const headers = createAuthHeaders(config);\n if (headers) {\n options.requestInit = {\n headers,\n };\n }\n\n return options;\n}\n\n/**\n * 验证配置\n * 注意:name 验证已在 MCPConnection 构造函数中进行\n * @param config MCP 服务配置(包含 name)\n */\nexport function validateConfig(config: InternalMCPServiceConfig): void {\n // name 验证已移至 MCPConnection 构造函数\n\n // type 字段现在是可选的,由 MCPService 自动推断\n // 这里我们只验证如果 type 存在,必须是有效的类型\n if (\n config.type &&\n !Object.values(MCPTransportType).includes(config.type as MCPTransportType)\n ) {\n throw new Error(`不支持的传输类型: ${config.type}`);\n }\n\n // 注意:这个验证方法在 MCPService.inferTransportType 之后调用\n // 此时 config.type 应该已经被推断或显式设置\n if (!config.type) {\n throw new Error(\"传输类型未设置,这应该在 inferTransportType 中处理\");\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 if (config.url === undefined || config.url === null) {\n throw new Error(`${config.type} 类型需要 url 字段`);\n }\n break;\n case MCPTransportType.HTTP:\n // HTTP 允许空 URL,会在后续处理中设置默认值\n if (config.url === undefined || config.url === null) {\n throw new Error(`${config.type} 类型需要 url 字段`);\n }\n break;\n\n default:\n throw new Error(`不支持的传输类型: ${config.type}`);\n }\n}\n\n/**\n * 获取支持的传输类型列表\n */\nexport function getSupportedTypes(): MCPTransportType[] {\n return [MCPTransportType.STDIO, MCPTransportType.SSE, MCPTransportType.HTTP];\n}\n\n/**\n * Transport 工厂对象(保持 API 兼容性)\n */\nexport const TransportFactory = {\n create: createTransport,\n validateConfig,\n getSupportedTypes,\n};\n","/**\n * MCP 服务器配置 Type 字段标准化工具\n * 支持将各种 type 字段格式转换为 MCP 官方标准格式\n *\n * @description\n * 标准格式与 MCP 官方保持一致:\n * - stdio: 本地进程通信\n * - sse: Server-Sent Events\n * - http: Streamable HTTP(推荐使用 http 而非 streamable-http)\n *\n * 向后兼容:自动转换各种变体格式\n */\n\n/**\n * MCP 服务器配置的基础接口\n * 定义包含可选 type 字段的配置对象结构\n */\nexport interface MCPBaseConfig {\n type?: string;\n [key: string]: unknown; // 允许其他配置属性\n}\n\n/**\n * MCP 服务器配置 Type 字段标准化工具类\n */\nexport namespace TypeFieldNormalizer {\n /**\n * 标准化 type 字段格式\n *\n * 支持的转换:\n * - http 变体:http → http(标准值)\n * - streamable-http → http\n * - streamable_http → http\n * - streamableHttp → http\n * - sse 变体:sse → sse(标准值)\n * - s_se → sse\n * - s-se → sse\n * - stdio 变体:stdio → stdio(标准值)\n */\n // 函数重载:泛型版本,用于类型安全的调用\n export function normalizeTypeField<T extends MCPBaseConfig>(config: T): T;\n\n // 函数重载:向后兼容版本,用于 unknown 类型输入\n export function normalizeTypeField(config: unknown): unknown;\n\n // 统一实现\n export function normalizeTypeField<T extends MCPBaseConfig>(\n config: T | unknown\n ): T | unknown {\n if (!config || typeof config !== \"object\") {\n return config;\n }\n\n // 如果配置中没有 type 字段,直接返回原始对象(无需拷贝)\n if (!(\"type\" in config)) {\n return config;\n }\n\n const originalType = (config as Record<string, unknown>).type;\n\n // 如果已经是标准格式,直接返回原始对象(无需拷贝)\n if (\n originalType === \"stdio\" ||\n originalType === \"sse\" ||\n originalType === \"http\"\n ) {\n return config;\n }\n\n // 转换为标准格式\n const normalizedType = normalizeTypeValue(originalType as string);\n\n // 验证转换后的类型是否有效\n if (\n normalizedType === \"stdio\" ||\n normalizedType === \"sse\" ||\n normalizedType === \"http\"\n ) {\n // 只在需要修改时创建浅拷贝,使用展开运算符只修改 type 字段\n return {\n ...config,\n type: normalizedType,\n };\n }\n\n return config;\n }\n\n /**\n * 标准化单个 type 值\n */\n export function normalizeTypeValue(type: string): string {\n // http 相关的变体全部转为 http\n if (\n type === \"http\" ||\n type === \"streamable-http\" ||\n type === \"streamable_http\" ||\n type === \"streamableHttp\"\n ) {\n return \"http\";\n }\n\n // sse 相关的变体转为 sse\n if (type === \"sse\" || type === \"s_se\" || type === \"s-se\") {\n return \"sse\";\n }\n\n // stdio 相关的变体转为 stdio\n if (type === \"stdio\") {\n return \"stdio\";\n }\n\n // 对于其他格式,尝试智能转换(转小写、下划线转中划线等)\n return convertToStandardFormat(type);\n }\n\n /**\n * 将字符串转换为标准格式\n */\n function convertToStandardFormat(str: string): string {\n const lowered = str.toLowerCase();\n\n // 处理 http 相关的变体\n if (lowered.includes(\"http\") || lowered.includes(\"streamable\")) {\n return \"http\";\n }\n\n // 处理 sse 相关的变体\n if (lowered.includes(\"sse\")) {\n return \"sse\";\n }\n\n // 处理 stdio 相关的变体\n if (lowered.includes(\"stdio\")) {\n return \"stdio\";\n }\n\n // 无法识别的格式,返回原值\n return str;\n }\n}\n\n/**\n * 导出便捷函数\n */\nexport function normalizeTypeField<T extends MCPBaseConfig>(config: T): T;\nexport function normalizeTypeField(config: unknown): unknown;\nexport function normalizeTypeField<T extends MCPBaseConfig>(\n config: T | unknown\n): T | unknown {\n return TypeFieldNormalizer.normalizeTypeField(config);\n}\n","/**\n * MCP 工具函数验证器\n *\n * 提供传输类型推断和工具调用参数验证功能:\n * - 根据 URL 路径自动推断传输类型(STDIO/SSE/HTTP)\n * - 基于 MCP 服务配置自动推断传输类型\n * - 验证工具调用参数的完整性和格式\n *\n * @module validators\n */\n\nimport {\n MCPTransportType,\n ToolCallError,\n ToolCallErrorCode,\n} from \"../types.js\";\nimport type {\n MCPServiceConfig,\n ToolCallParams,\n ToolCallValidationOptions,\n ValidatedToolCallParams,\n} from \"../types.js\";\nimport { TypeFieldNormalizer } from \"./type-normalizer.js\";\n\n/**\n * 根据 URL 路径推断传输类型\n * 基于路径末尾推断,支持包含多个 / 的复杂路径\n *\n * @param url - 要推断的 URL\n * @param options - 可选配置项\n * @returns 推断出的传输类型\n */\nexport function inferTransportTypeFromUrl(\n url: string,\n options?: {\n serviceName?: string;\n }\n): MCPTransportType {\n try {\n const parsedUrl = new URL(url);\n const pathname = parsedUrl.pathname;\n\n // 检查路径末尾\n if (pathname.endsWith(\"/sse\")) {\n return MCPTransportType.SSE;\n }\n if (pathname.endsWith(\"/mcp\")) {\n return MCPTransportType.HTTP;\n }\n\n // 默认类型 - 使用 console 输出\n if (options?.serviceName) {\n console.info(\n `[MCP-${options.serviceName}] URL 路径 ${pathname} 不匹配特定规则,默认推断为 http 类型`\n );\n }\n return MCPTransportType.HTTP;\n } catch (error) {\n if (options?.serviceName) {\n console.warn(\n `[MCP-${options.serviceName}] URL 解析失败,默认推断为 http 类型`,\n error\n );\n }\n return MCPTransportType.HTTP;\n }\n}\n\n/**\n * 完整的配置类型推断(包括 command 字段)\n *\n * @param config - MCP 服务配置\n * @param serviceName - 服务名称(用于日志输出)\n * @returns 完整的配置对象,包含推断出的类型\n */\nexport function inferTransportTypeFromConfig(\n config: MCPServiceConfig,\n serviceName?: string\n): MCPServiceConfig {\n // 如果已显式指定类型,先标准化然后返回\n if (config.type) {\n const normalizedConfig = TypeFieldNormalizer.normalizeTypeField(config);\n return normalizedConfig as MCPServiceConfig;\n }\n\n // 基于 command 字段推断\n if (config.command) {\n return {\n ...config,\n type: MCPTransportType.STDIO,\n };\n }\n\n // 基于 URL 字段推断(排除 null 和 undefined)\n if (config.url !== undefined && config.url !== null) {\n const inferredType = inferTransportTypeFromUrl(config.url, {\n serviceName,\n });\n return {\n ...config,\n type: inferredType,\n };\n }\n\n throw new Error(\n `无法为服务 ${serviceName || \"未知\"} 推断传输类型。请显式指定 type 字段,或提供 command/url 配置`\n );\n}\n\n// =========================\n// 参数校验工具函数\n// =========================\n\n/**\n * 验证工具调用参数\n * 对传入的参数进行完整性和格式验证\n *\n * @param params 待验证的参数\n * @param options 验证选项\n * @returns 验证后的参数\n * @throws ToolCallError 验证失败时抛出\n */\nexport function validateToolCallParams(\n params: unknown,\n options?: ToolCallValidationOptions\n): ValidatedToolCallParams {\n const opts = {\n validateName: true,\n validateArguments: true,\n allowEmptyArguments: true,\n ...options,\n };\n\n // 1. 验证参数必须是对象\n if (!params || typeof params !== \"object\") {\n throw new ToolCallError(\n ToolCallErrorCode.INVALID_PARAMS,\n \"请求参数必须是对象\"\n );\n }\n\n const paramsObj = params as Record<string, unknown>;\n\n // 2. 验证工具名称\n if (opts.validateName) {\n if (!paramsObj.name || typeof paramsObj.name !== \"string\") {\n throw new ToolCallError(\n ToolCallErrorCode.INVALID_PARAMS,\n \"工具名称必须是非空字符串\"\n );\n }\n }\n\n // 3. 验证工具参数格式\n if (\n opts.validateArguments &&\n paramsObj.arguments !== undefined &&\n paramsObj.arguments !== null\n ) {\n if (\n typeof paramsObj.arguments !== \"object\" ||\n Array.isArray(paramsObj.arguments)\n ) {\n throw new ToolCallError(\n ToolCallErrorCode.INVALID_PARAMS,\n \"工具参数必须是对象\"\n );\n }\n }\n\n // 4. 验证是否允许空参数\n if (\n !opts.allowEmptyArguments &&\n paramsObj.arguments !== undefined &&\n paramsObj.arguments !== null\n ) {\n const argsObj = paramsObj.arguments as Record<string, unknown>;\n if (Object.keys(argsObj).length === 0) {\n throw new ToolCallError(\n ToolCallErrorCode.INVALID_PARAMS,\n \"工具参数不能为空\"\n );\n }\n }\n\n // 5. 执行自定义验证\n if (opts.customValidator) {\n const error = opts.customValidator(paramsObj as unknown as ToolCallParams);\n if (error) {\n throw new ToolCallError(ToolCallErrorCode.INVALID_PARAMS, error);\n }\n }\n\n return {\n name: paramsObj.name as string,\n arguments: paramsObj.arguments as Record<string, unknown>,\n };\n}\n","/**\n * 工具函数统一导出\n */\n\n// 类型标准化\nexport { TypeFieldNormalizer, normalizeTypeField } from \"./type-normalizer.js\";\n\n// 参数校验和类型推断\nexport {\n validateToolCallParams,\n inferTransportTypeFromUrl,\n inferTransportTypeFromConfig,\n} from \"./validators.js\";\n","/**\n * MCP 连接管理模块\n *\n * 提供 MCPConnection 类,负责管理单个 MCP 服务的连接生命周期\n * 包括连接建立、工具列表管理、工具调用、心跳检测等功能\n *\n * @module connection\n */\n\nimport { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport { TransportFactory } from \"./transport-factory.js\";\nimport type {\n MCPServerTransport,\n MCPServiceConfig,\n MCPServiceStatus,\n ToolCallResult,\n} from \"./types.js\";\nimport { ConnectionState, MCPTransportType } from \"./types.js\";\nimport type {\n HeartbeatConfig,\n InternalMCPServiceConfig,\n MCPServiceEventCallbacks,\n} from \"./types.js\";\nimport { inferTransportTypeFromConfig } from \"./utils/index.js\";\n\n/**\n * MCP 连接类\n * 负责管理单个 MCP 服务的连接、工具管理和调用\n */\nexport class MCPConnection {\n private name: string; // 服务名称(独立字段)\n private config: MCPServiceConfig;\n private client: Client | null = null;\n private transport: MCPServerTransport | null = null;\n private tools: Map<string, Tool> = new Map();\n private connectionState: ConnectionState = ConnectionState.DISCONNECTED;\n private connectionTimeout: NodeJS.Timeout | null = null;\n private initialized = false;\n private callbacks?: MCPServiceEventCallbacks;\n // 心跳检测相关\n private heartbeatTimer: NodeJS.Timeout | null = null;\n private heartbeatConfig?: HeartbeatConfig;\n\n constructor(\n name: string,\n config: MCPServiceConfig,\n callbacks?: MCPServiceEventCallbacks\n ) {\n this.name = name;\n // 使用工具方法推断服务类型(传递服务名称用于日志)\n this.config = inferTransportTypeFromConfig(config, name);\n this.callbacks = callbacks;\n // 保存心跳配置 - 优先使用用户配置\n this.heartbeatConfig = {\n enabled: config.heartbeat?.enabled ?? true, // 默认启用\n interval: config.heartbeat?.interval ?? 30 * 1000, // 默认 30 秒\n };\n\n // 验证配置\n this.validateConfig();\n }\n\n /**\n * 验证配置\n */\n private validateConfig(): void {\n // 验证服务名称\n if (!this.name || typeof this.name !== \"string\") {\n throw new Error(\"服务名称必须是非空字符串\");\n }\n // 使用 TransportFactory 进行配置验证(传递包含 name 的完整配置)\n const fullConfig: InternalMCPServiceConfig = {\n name: this.name,\n ...this.config,\n };\n TransportFactory.validateConfig(fullConfig);\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 return this.attemptConnection();\n }\n\n /**\n * 尝试建立连接\n */\n private async attemptConnection(): Promise<void> {\n this.connectionState = ConnectionState.CONNECTING;\n console.debug(`[MCP-${this.name}] 正在连接 MCP 服务: ${this.name}`);\n\n return new Promise((resolve, reject) => {\n // 设置连接超时(使用固定默认值 30 秒)\n const CONNECTION_TIMEOUT = 30000;\n this.connectionTimeout = setTimeout(() => {\n const error = new Error(`连接超时 (${CONNECTION_TIMEOUT}ms)`);\n this.handleConnectionError(error);\n reject(error);\n }, CONNECTION_TIMEOUT);\n\n try {\n this.client = new Client(\n {\n name: `xiaozhi-${this.name}-client`,\n version: \"1.0.0\",\n },\n {\n capabilities: {},\n }\n );\n\n // 使用 TransportFactory 创建传输层(传递包含 name 的完整配置)\n const fullConfig: InternalMCPServiceConfig = {\n name: this.name,\n ...this.config,\n };\n this.transport = TransportFactory.create(fullConfig);\n\n // 连接到 MCP 服务\n this.client\n .connect(this.transport as MCPServerTransport)\n .then(async () => {\n this.handleConnectionSuccess();\n\n // 获取工具列表\n await this.refreshTools();\n\n // 发射连接成功事件\n this.callbacks?.onConnected?.({\n serviceName: this.name,\n tools: this.getTools(),\n connectionTime: new Date(),\n });\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 console.info(`[MCP-${this.name}] MCP 服务 ${this.name} 连接已建立`);\n\n // 启动心跳检测\n this.startHeartbeat();\n }\n\n /**\n * 处理连接错误\n */\n private handleConnectionError(error: Error): void {\n this.connectionState = ConnectionState.DISCONNECTED;\n this.initialized = false;\n\n console.debug(`MCP 服务 ${this.name} 连接错误:`, error.message);\n\n // 清理连接超时定时器\n if (this.connectionTimeout) {\n clearTimeout(this.connectionTimeout);\n this.connectionTimeout = null;\n }\n\n // 清理当前连接\n this.cleanupConnection();\n\n // 发射连接失败事件\n this.callbacks?.onConnectionFailed?.({\n serviceName: this.name,\n error,\n attempt: 0,\n });\n }\n\n /**\n * 清理连接资源\n */\n private cleanupConnection(): void {\n // 停止心跳\n this.stopHeartbeat();\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 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 console.debug(\n `${this.name} 服务加载了 ${tools.length} 个工具: ${tools\n .map((t) => t.name)\n .join(\", \")}`\n );\n } catch (error) {\n console.error(\n `${this.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 console.info(`主动断开 MCP 服务 ${this.name} 连接`);\n\n // 清理连接资源\n this.cleanupConnection();\n\n // 设置状态为已断开\n this.connectionState = ConnectionState.DISCONNECTED;\n\n // 发射断开连接事件\n this.callbacks?.onDisconnected?.({\n serviceName: this.name,\n reason: \"手动断开\",\n disconnectionTime: new Date(),\n });\n }\n\n /**\n * 获取工具列表\n */\n getTools(): Tool[] {\n return Array.from(this.tools.values());\n }\n\n /**\n * 检测是否为会话过期错误\n */\n private isSessionExpiredError(error: unknown): boolean {\n if (error instanceof Error) {\n const message = error.message.toLowerCase();\n return (\n message.includes(\"session expired\") ||\n message.includes(\"会话过期\") ||\n message.includes(\"401\") ||\n message.includes(\"unauthorized\")\n );\n }\n return false;\n }\n\n /**\n * 自动重连\n */\n private async reconnect(): Promise<void> {\n this.connectionState = ConnectionState.RECONNECTING;\n console.debug(`[MCP-${this.name}] 检测到会话过期,正在重新连接...`);\n\n // 清理旧连接\n this.cleanupConnection();\n\n // 建立新连接\n return this.attemptConnection();\n }\n\n /**\n * 启动心跳检测\n */\n private async startHeartbeat(): Promise<void> {\n // STDIO 不需要心跳(进程级连接稳定)\n if (this.config.type === \"stdio\") {\n return;\n }\n\n if (!this.heartbeatConfig?.enabled) {\n return;\n }\n const interval = this.heartbeatConfig?.interval ?? 30 * 1000;\n\n this.heartbeatTimer = setInterval(() => {\n this.performHeartbeat().catch((error) => {\n console.error(\n `[MCP-${this.name}] 心跳检测执行异常:`,\n error instanceof Error ? error.message : String(error)\n );\n });\n }, interval);\n\n console.debug(`[MCP-${this.name}] 心跳检测已启动,间隔: ${interval}ms`);\n }\n\n /**\n * 执行一次心跳检查\n */\n private async performHeartbeat(): Promise<void> {\n if (!this.client) {\n return;\n }\n\n try {\n // 调用 MCP SDK 的 ping() 方法\n await this.client.ping();\n console.debug(`[MCP-${this.name}] 心跳检测成功`);\n } catch (error) {\n console.warn(\n `[MCP-${this.name}] 心跳检测失败,尝试重连...`,\n error instanceof Error ? error.message : String(error)\n );\n // 心跳失败,尝试重连\n await this.reconnect();\n }\n }\n\n /**\n * 停止心跳检测\n */\n private stopHeartbeat(): void {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n console.debug(`[MCP-${this.name}] 心跳检测已停止`);\n }\n }\n\n /**\n * 调用工具\n */\n async callTool(\n name: string,\n arguments_: Record<string, unknown>\n ): Promise<ToolCallResult> {\n if (!this.client) {\n throw new Error(`服务 ${this.name} 未连接`);\n }\n\n if (!this.tools.has(name)) {\n throw new Error(`工具 ${name} 在服务 ${this.name} 中不存在`);\n }\n\n console.debug(\n `调用 ${this.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 console.debug(\n `工具 ${name} 调用成功,结果:`,\n `${JSON.stringify(result).substring(0, 500)}...`\n );\n\n return result as ToolCallResult;\n } catch (error) {\n // 检测是否为会话过期错误\n if (this.isSessionExpiredError(error)) {\n console.warn(\n `[MCP-${this.name}] 检测到会话过期,尝试重新连接并重试...`\n );\n\n // 自动重连\n await this.reconnect();\n\n // 重试工具调用\n return await this.client.callTool({\n name,\n arguments: arguments_ || {},\n });\n }\n\n // 其他错误正常抛出\n console.error(\n `工具 ${name} 调用失败:`,\n error instanceof Error ? error.message : String(error)\n );\n throw error;\n }\n }\n\n /**\n * 获取服务配置\n */\n getConfig(): MCPServiceConfig & { name: string } {\n return {\n name: this.name,\n ...this.config,\n };\n }\n\n /**\n * 获取服务状态\n */\n getStatus(): MCPServiceStatus {\n return {\n name: this.name,\n connected: this.connectionState === ConnectionState.CONNECTED,\n initialized: this.initialized,\n transportType:\n (this.config.type as MCPTransportType) || MCPTransportType.HTTP,\n toolCount: this.tools.size,\n connectionState: this.connectionState,\n };\n }\n\n /**\n * 检查是否已连接\n */\n isConnected(): boolean {\n return (\n this.connectionState === ConnectionState.CONNECTED && this.initialized\n );\n }\n}\n","/**\n * MCP 服务管理器\n * 提供简洁的 API 来管理多个 MCP 服务\n */\n\nimport { EventEmitter } from \"node:events\";\nimport { MCPConnection } from \"./connection.js\";\nimport type { MCPServiceConfig, ToolCallResult } from \"./types.js\";\nimport { MCPTransportType } from \"./types.js\";\n\n/**\n * MCP 服务管理器\n * 提供简洁的 API 来管理多个 MCP 服务\n *\n * @example\n * ```typescript\n * const manager = new MCPManager();\n *\n * // 添加服务\n * manager.addServer('datetime', {\n * type: 'stdio',\n * command: 'node',\n * args: ['datetime.js']\n * });\n *\n * // 连接所有服务\n * await manager.connect();\n *\n * // 调用工具\n * const result = await manager.callTool('datetime', 'get_current_time', {\n * format: 'YYYY-MM-DD HH:mm:ss'\n * });\n *\n * // 断开连接\n * await manager.disconnect();\n * ```\n */\nexport class MCPManager extends EventEmitter {\n private connections: Map<string, MCPConnection> = new Map();\n private configs: Map<string, MCPServiceConfig> = new Map();\n\n constructor() {\n super();\n }\n\n /**\n * 添加 MCP 服务器配置\n * @param name 服务器名称\n * @param config 服务器配置\n *\n * @example\n * ```typescript\n * // 添加 stdio 服务\n * manager.addServer('calculator', {\n * type: 'stdio',\n * command: 'node',\n * args: ['calculator.js']\n * });\n *\n * // 添加 HTTP 服务\n * manager.addServer('web-search', {\n * type: 'http',\n * url: 'https://api.example.com/mcp',\n * headers: {\n * Authorization: 'Bearer your-api-key'\n * }\n * });\n * ```\n */\n addServer(name: string, config: MCPServiceConfig): void {\n if (this.configs.has(name)) {\n throw new Error(`服务 ${name} 已存在`);\n }\n\n // 标准化 type 字段 - 将用户友好的类型映射到实际的枚举值\n const normalizedConfig: MCPServiceConfig = { ...config };\n\n if (config.type) {\n // 首先检查用户友好的字符串类型\n const typeStr = String(config.type);\n if (typeStr === \"http\") {\n normalizedConfig.type = MCPTransportType.HTTP;\n } else if (typeStr === \"sse\") {\n normalizedConfig.type = MCPTransportType.SSE;\n } else {\n // 已经是枚举值或正确格式\n normalizedConfig.type = config.type as MCPTransportType;\n }\n }\n\n // 存储 config(不包含 name,name 已作为 Map 的 key)\n this.configs.set(name, normalizedConfig);\n }\n\n /**\n * 移除服务器配置\n * @param name 服务器名称\n */\n removeServer(name: string): boolean {\n return this.configs.delete(name);\n }\n\n /**\n * 连接所有已添加的 MCP 服务\n * 所有服务并行连接,单个服务失败不会影响其他服务\n *\n * @example\n * ```typescript\n * await manager.connect();\n * ```\n */\n async connect(): Promise<void> {\n this.emit(\"connect\");\n\n const promises = Array.from(this.configs.entries()).map(\n async ([name, config]) => {\n try {\n const connection = new MCPConnection(name, config, {\n onConnected: (data) => {\n this.emit(\"connected\", {\n serverName: data.serviceName,\n tools: data.tools,\n });\n },\n onDisconnected: (data) => {\n this.emit(\"disconnected\", {\n serverName: data.serviceName,\n reason: data.reason,\n });\n },\n onConnectionFailed: (data) => {\n this.emit(\"error\", {\n serverName: data.serviceName,\n error: data.error,\n });\n },\n });\n\n await connection.connect();\n this.connections.set(name, connection);\n } catch (error) {\n this.emit(\"error\", { serverName: name, error });\n throw error;\n }\n }\n );\n\n await Promise.allSettled(promises);\n }\n\n /**\n * 断开所有 MCP 服务连接\n *\n * @example\n * ```typescript\n * await manager.disconnect();\n * ```\n */\n async disconnect(): Promise<void> {\n const promises = Array.from(this.connections.values()).map((conn) =>\n conn.disconnect()\n );\n\n await Promise.allSettled(promises);\n this.connections.clear();\n\n this.emit(\"disconnect\");\n }\n\n /**\n * 调用指定服务的工具\n * @param serverName 服务名称\n * @param toolName 工具名称\n * @param args 工具参数\n *\n * @example\n * ```typescript\n * const result = await manager.callTool('datetime', 'get_current_time', {\n * format: 'YYYY-MM-DD HH:mm:ss'\n * });\n * ```\n */\n async callTool(\n serverName: string,\n toolName: string,\n args: Record<string, unknown>\n ): Promise<ToolCallResult> {\n const connection = this.connections.get(serverName);\n if (!connection) {\n throw new Error(`服务 ${serverName} 不存在`);\n }\n\n if (!connection.isConnected()) {\n throw new Error(`服务 ${serverName} 未连接`);\n }\n\n return connection.callTool(toolName, args);\n }\n\n /**\n * 列出所有可用的工具\n * @returns 工具列表,格式为 [{ name, serverName, description, inputSchema }]\n *\n * @example\n * ```typescript\n * const tools = manager.listTools();\n * console.log('可用工具:', tools.map(t => `${t.serverName}/${t.name}`));\n * ```\n */\n listTools(): Array<{\n name: string;\n serverName: string;\n description: string;\n inputSchema: unknown;\n }> {\n const allTools: Array<{\n name: string;\n serverName: string;\n description: string;\n inputSchema: unknown;\n }> = [];\n\n for (const [serverName, connection] of this.connections) {\n if (connection.isConnected()) {\n const tools = connection.getTools();\n for (const tool of tools) {\n allTools.push({\n name: tool.name,\n serverName,\n description: tool.description || \"\",\n inputSchema: tool.inputSchema,\n });\n }\n }\n }\n\n return allTools;\n }\n\n /**\n * 获取服务状态\n * @param serverName 服务名称\n * @returns 服务状态,如果服务不存在则返回 null\n *\n * @example\n * ```typescript\n * const status = manager.getServerStatus('datetime');\n * if (status) {\n * console.log(`已连接: ${status.connected}, 工具数: ${status.toolCount}`);\n * }\n * ```\n */\n getServerStatus(serverName: string): {\n connected: boolean;\n toolCount: number;\n } | null {\n const connection = this.connections.get(serverName);\n if (!connection) {\n return null;\n }\n\n const status = connection.getStatus();\n return {\n connected: status.connected,\n toolCount: status.toolCount,\n };\n }\n\n /**\n * 获取所有服务的状态\n * @returns 所有服务的状态映射\n *\n * @example\n * ```typescript\n * const statuses = manager.getAllServerStatus();\n * console.log(statuses);\n * // {\n * // datetime: { connected: true, toolCount: 3 },\n * // calculator: { connected: true, toolCount: 1 }\n * // }\n * ```\n */\n getAllServerStatus(): Record<\n string,\n { connected: boolean; toolCount: number }\n > {\n const statuses: Record<string, { connected: boolean; toolCount: number }> =\n {};\n\n for (const [serverName, connection] of this.connections) {\n const status = connection.getStatus();\n statuses[serverName] = {\n connected: status.connected,\n toolCount: status.toolCount,\n };\n }\n\n return statuses;\n }\n\n /**\n * 检查服务是否已连接\n * @param serverName 服务名称\n *\n * @example\n * ```typescript\n * if (manager.isConnected('datetime')) {\n * console.log('datetime 服务已连接');\n * }\n * ```\n */\n isConnected(serverName: string): boolean {\n const connection = this.connections.get(serverName);\n return connection ? connection.isConnected() : false;\n }\n\n /**\n * 获取已配置的服务列表\n * @returns 服务名称数组\n *\n * @example\n * ```typescript\n * const servers = manager.getServerNames();\n * console.log('已配置的服务:', servers);\n * ```\n */\n getServerNames(): string[] {\n return Array.from(this.configs.keys());\n }\n\n /**\n * 获取已连接的服务列表\n * @returns 已连接的服务名称数组\n *\n * @example\n * ```typescript\n * const connectedServers = manager.getConnectedServerNames();\n * console.log('已连接的服务:', connectedServers);\n * ```\n */\n getConnectedServerNames(): string[] {\n const connected: string[] = [];\n for (const [serverName, connection] of this.connections) {\n if (connection.isConnected()) {\n connected.push(serverName);\n }\n }\n return connected;\n }\n}\n\n// 为了向后兼容,保留旧的 MCPServiceManager 类名作为别名\nexport { MCPManager as MCPServiceManager };\n","/**\n * @/mcp-core\n *\n * MCP 协议核心实现库\n * 提供 MCP 服务管理、连接和工具调用的核心功能\n */\n\n// =========================\n// 类型导出\n// =========================\n\nexport type {\n // 配置相关\n MCPServiceConfig,\n ModelScopeSSEOptions,\n UnifiedServerConfig,\n // 状态相关\n MCPServiceStatus,\n MCPServiceConnectionStatus,\n ManagerStatus,\n UnifiedServerStatus,\n // 工具相关\n ToolInfo,\n EnhancedToolInfo,\n ToolCallResult,\n ToolCallParams,\n ValidatedToolCallParams,\n ToolCallValidationOptions,\n CustomMCPTool,\n JSONSchema,\n // 传输相关\n MCPServerTransport,\n // 事件相关\n MCPServiceEventCallbacks,\n} from \"./types.js\";\n\n// =========================\n// 枚举导出\n// =========================\n\nexport {\n MCPTransportType,\n ConnectionState,\n ToolCallErrorCode,\n} from \"./types.js\";\n\n// =========================\n// 类导出\n// =========================\n\nexport { ToolCallError } from \"./types.js\";\nexport { MCPConnection } from \"./connection.js\";\nexport { MCPManager, MCPServiceManager } from \"./manager.js\";\n\n// =========================\n// 传输工厂导出\n// =========================\n\nexport { TransportFactory } from \"./transport-factory.js\";\n\n// =========================\n// 工具函数导出\n// =========================\n\nexport {\n TypeFieldNormalizer,\n normalizeTypeField,\n validateToolCallParams,\n inferTransportTypeFromUrl,\n inferTransportTypeFromConfig,\n} from \"./utils/index.js\";\n\n// =========================\n// 类型守卫导出\n// =========================\n\nexport {\n isValidToolJSONSchema,\n ensureToolJSONSchema,\n} from \"./types.js\";\n","/**\n * 配置适配器\n * 将旧的配置格式转换为新的 MCPServiceConfig 格式,确保向后兼容性\n */\n\nimport { dirname, isAbsolute, resolve } from \"node:path\";\nimport { MCPTransportType, inferTransportTypeFromUrl } from \"@/mcp-core\";\nimport type {\n HTTPMCPServerConfig,\n LocalMCPServerConfig,\n MCPServerConfig,\n SSEMCPServerConfig,\n} from \"./manager.js\";\nimport { ConfigResolver } from \"./resolver.js\";\n\n// 从外部导入 MCP 类型(这些类型将在运行时从 backend 包解析)\n// 为了避免循环依赖,这里使用动态导入的方式\n// 在实际使用时,adapter 将作为 config 包的一部分被使用\n\n/**\n * 配置验证错误类\n */\nexport class ConfigValidationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ConfigValidationError\";\n }\n}\n\n// 定义简化的 MCPServiceConfig 接口\nexport interface MCPServiceConfig {\n type: MCPTransportType;\n command?: string;\n args?: string[];\n env?: Record<string, string>;\n url?: string;\n headers?: Record<string, string>;\n}\n\n/**\n * 将各种配置格式标准化为统一的服务配置格式\n */\nexport function normalizeServiceConfig(\n config: MCPServerConfig\n): MCPServiceConfig {\n console.log(\"转换配置\", { config });\n\n try {\n // 验证输入参数\n if (!config || typeof config !== \"object\") {\n throw new ConfigValidationError(\"配置对象不能为空\");\n }\n\n // 根据配置类型进行转换\n const newConfig = convertByConfigType(config);\n\n // 验证转换后的配置\n validateNewConfig(newConfig);\n\n console.log(\"配置转换成功\", { type: newConfig.type });\n return newConfig;\n } catch (error) {\n console.error(\"配置转换失败\", { error });\n throw error instanceof ConfigValidationError\n ? error\n : new ConfigValidationError(\n `配置转换失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n}\n\n/**\n * 根据配置类型进行转换\n */\nfunction convertByConfigType(config: MCPServerConfig): MCPServiceConfig {\n // 检查是否为本地 stdio 配置(最高优先级)\n if (isLocalConfig(config)) {\n return convertLocalConfig(config);\n }\n\n // 检查是否有显式指定的类型\n if (\"type\" in config) {\n switch (config.type) {\n case \"sse\":\n return convertSSEConfig(config);\n case \"http\":\n case \"streamable-http\": // 向后兼容\n return convertHTTPConfig(config);\n default:\n throw new ConfigValidationError(`不支持的传输类型: ${config.type}`);\n }\n }\n\n // 检查是否为网络配置(自动推断类型)\n if (\"url\" in config) {\n // 如果 URL 是 undefined 或 null,抛出错误\n if (config.url === undefined || config.url === null) {\n throw new ConfigValidationError(\"网络配置必须包含有效的 url 字段\");\n }\n\n // 先推断类型,然后根据推断的类型选择正确的转换函数\n const inferredType = inferTransportTypeFromUrl(config.url || \"\");\n\n if (inferredType === MCPTransportType.SSE) {\n // 为SSE类型添加显式type字段\n const sseConfig = { ...config, type: \"sse\" as const };\n return convertSSEConfig(sseConfig);\n }\n // 为HTTP类型添加显式type字段\n const httpConfig = { ...config, type: \"http\" as const };\n return convertHTTPConfig(httpConfig);\n }\n\n throw new ConfigValidationError(\"无法识别的配置类型\");\n}\n\n/**\n * 转换本地 stdio 配置\n */\nfunction convertLocalConfig(config: MCPServerConfig): MCPServiceConfig {\n // 类型守卫:确保是 LocalMCPServerConfig\n if (!isLocalConfig(config)) {\n throw new ConfigValidationError(\"无效的本地配置类型\");\n }\n\n const { command, args, env } = config;\n\n if (!command) {\n throw new ConfigValidationError(\"本地配置必须包含 command 字段\");\n }\n\n // 获取配置文件所在目录作为工作目录\n // 优先使用环境变量,否则查找配置文件所在目录,最后回退到当前工作目录\n let workingDir: string;\n if (process.env.XIAOZHI_CONFIG_DIR) {\n workingDir = process.env.XIAOZHI_CONFIG_DIR;\n } else {\n // 使用 ConfigResolver 查找配置文件路径\n const configPath = ConfigResolver.resolveConfigPath();\n if (configPath) {\n // 获取配置文件所在目录\n workingDir = dirname(configPath);\n } else {\n // 回退到当前工作目录\n workingDir = process.cwd();\n }\n }\n\n // 解析 command 中的相对路径\n let resolvedCommand = command;\n if (isRelativePath(command)) {\n resolvedCommand = resolve(workingDir, command);\n console.log(\"解析 command 相对路径\", {\n command,\n resolvedCommand,\n workingDir,\n });\n }\n\n // 解析 args 中的相对路径\n const resolvedArgs = (args || []).map((arg: string) => {\n // 检查是否为相对路径(以 ./ 开头或不以 / 开头且包含文件扩展名)\n if (isRelativePath(arg)) {\n const resolvedPath = resolve(workingDir, arg);\n console.log(\"解析相对路径\", { arg, resolvedPath, workingDir });\n return resolvedPath;\n }\n return arg;\n });\n\n return {\n type: MCPTransportType.STDIO,\n command: resolvedCommand,\n args: resolvedArgs,\n ...(env !== undefined && { env }), // 只在 env 存在时添加该属性\n };\n}\n\n/**\n * 转换 SSE 配置\n */\nfunction convertSSEConfig(config: MCPServerConfig): MCPServiceConfig {\n // 使用类型守卫确保 config 包含必要的属性\n if (!isURLConfig(config)) {\n throw new ConfigValidationError(\"SSE 配置必须包含 url 字段\");\n }\n\n const url = config.url;\n const type = \"type\" in config ? config.type : undefined;\n const headers = \"headers\" in config ? config.headers : undefined;\n\n // 优先使用显式指定的类型,如果没有则进行推断\n const inferredType =\n type === \"sse\"\n ? MCPTransportType.SSE\n : inferTransportTypeFromUrl(url || \"\");\n const isModelScope = url ? isModelScopeURL(url) : false;\n\n console.log(\"SSE配置转换\", {\n url,\n inferredType,\n isModelScope,\n });\n\n return {\n type: inferredType,\n url,\n headers,\n };\n}\n\n/**\n * 转换 HTTP 配置\n */\nfunction convertHTTPConfig(config: MCPServerConfig): MCPServiceConfig {\n // 使用类型守卫确保 config 包含必要的属性\n if (!isURLConfig(config)) {\n throw new ConfigValidationError(\"HTTP 配置必须包含 url 字段\");\n }\n\n const url = config.url;\n const headers = \"headers\" in config ? config.headers : undefined;\n\n return {\n type: MCPTransportType.HTTP,\n url: url || \"\",\n headers,\n };\n}\n\n/**\n * 批量标准化配置\n */\nexport function normalizeServiceConfigBatch(\n legacyConfigs: Record<string, MCPServerConfig>\n): Record<string, MCPServiceConfig> {\n const newConfigs: Record<string, MCPServiceConfig> = {};\n const errors: Array<{ error: Error }> = [];\n\n for (const [name, config] of Object.entries(legacyConfigs)) {\n try {\n newConfigs[name] = normalizeServiceConfig(config);\n } catch (error) {\n errors.push({\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(({ error }, index) => `[${index}]: ${error.message}`)\n .join(\"; \");\n throw new ConfigValidationError(`批量配置转换失败: ${errorMessages}`);\n }\n\n console.log(\"批量配置转换成功\", { count: Object.keys(newConfigs).length });\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 * 检查是否为 URL 配置(SSE 或 HTTP)\n * 类型守卫函数,用于验证配置包含 url 属性\n */\nfunction isURLConfig(\n config: MCPServerConfig\n): config is (SSEMCPServerConfig | HTTPMCPServerConfig) & { url: string } {\n return \"url\" in config && typeof config.url === \"string\";\n}\n\n/**\n * 检查是否为 ModelScope URL\n * 使用 URL hostname 检测而非简单的字符串包含检查,防止安全绕过\n */\nexport function isModelScopeURL(url: string): boolean {\n try {\n const parsedUrl = new URL(url);\n const hostname = parsedUrl.hostname.toLowerCase();\n return (\n hostname.endsWith(\".modelscope.net\") ||\n hostname.endsWith(\".modelscope.cn\") ||\n hostname === \"modelscope.net\" ||\n hostname === \"modelscope.cn\"\n );\n } catch {\n return false;\n }\n}\n\n/**\n * 验证新配置格式\n */\nfunction validateNewConfig(config: MCPServiceConfig): void {\n if (config.type && !Object.values(MCPTransportType).includes(config.type)) {\n throw new ConfigValidationError(`无效的传输类型: ${config.type}`);\n }\n\n // 根据传输类型验证必需字段\n if (!config.type) {\n throw new ConfigValidationError(\"传输类型未指定,请检查配置或启用自动推断\");\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 // SSE 配置必须有 URL(即使是空字符串也会被推断为 HTTP)\n if (config.url === undefined || config.url === null) {\n throw new ConfigValidationError(\"SSE 配置必须包含 url 字段\");\n }\n break;\n\n case MCPTransportType.HTTP:\n // HTTP 配置允许空 URL,会在后续处理中设置默认值\n // 只有当 URL 完全不存在时才报错\n if (config.url === undefined || config.url === null) {\n throw new ConfigValidationError(\"HTTP 配置必须包含 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\n if (\"url\" in config) {\n // 检查是否为显式 http 配置\n if (\n \"type\" in config &&\n (config.type === \"http\" || config.type === \"streamable-http\")\n ) {\n return `HTTP (${config.url})`;\n }\n\n // 检查是否为显式 sse 配置\n if (\"type\" in config && config.type === \"sse\") {\n const isModelScope = isModelScopeURL(config.url);\n return `SSE${isModelScope ? \" (ModelScope)\" : \"\"} (${config.url})`;\n }\n\n // 对于只有 url 的配置,根据路径推断类型\n const inferredType = inferTransportTypeFromUrl(config.url);\n const isModelScope = isModelScopeURL(config.url);\n\n if (inferredType === MCPTransportType.SSE) {\n return `SSE${isModelScope ? \" (ModelScope)\" : \"\"} (${config.url})`;\n }\n return `HTTP (${config.url})`;\n }\n\n return \"未知\";\n}\n\n// 重新导出 MCPTransportType 以保持向后兼容\nexport { MCPTransportType };\n","/**\n * 配置初始化器\n * 负责在用户家目录创建默认配置\n */\n\nimport {\n copyFileSync,\n existsSync,\n mkdirSync,\n readdirSync,\n statSync,\n} from \"node:fs\";\nimport path from \"node:path\";\nimport { dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n/**\n * 配置初始化器类\n * 负责在用户家目录创建完整的默认项目目录\n */\nexport class ConfigInitializer {\n /**\n * 初始化默认配置\n *\n * 复制整个默认模板目录到用户家目录的 .xiaozhi-client\n * 这包括 mcpServers/ 目录和其他必要文件\n *\n * @returns 创建的项目目录路径\n * @throws 如果无法获取用户家目录或默认配置模板不存在\n */\n static async initializeDefaultConfig(): Promise<string> {\n const homeDir = process.env.HOME || process.env.USERPROFILE;\n if (!homeDir) {\n throw new Error(\"无法获取用户家目录\");\n }\n\n const xiaozhiClientDir = path.join(homeDir, \".xiaozhi-client\");\n\n // 如果目录已存在,直接使用现有配置目录,避免删除用户数据\n if (existsSync(xiaozhiClientDir)) {\n return xiaozhiClientDir;\n }\n\n // 创建目录\n mkdirSync(xiaozhiClientDir, { recursive: true });\n\n // 获取默认模板目录路径\n const defaultTemplateDir = ConfigInitializer.getDefaultTemplateDir();\n if (!defaultTemplateDir) {\n throw new Error(\"默认配置模板不存在,请检查项目模板文件是否存在\");\n }\n\n // 复制整个模板目录\n ConfigInitializer.copyDirectoryRecursive(\n defaultTemplateDir,\n xiaozhiClientDir,\n [\"template.json\", \".git\", \"node_modules\"]\n );\n\n return xiaozhiClientDir;\n }\n\n /**\n * 递归复制目录\n *\n * @param srcDir 源目录\n * @param destDir 目标目录\n * @param exclude 要排除的文件/目录列表\n */\n private static copyDirectoryRecursive(\n srcDir: string,\n destDir: string,\n exclude: string[] = []\n ): void {\n const items = readdirSync(srcDir);\n\n for (const item of items) {\n // 跳过排除列表中的项\n if (exclude.includes(item)) {\n continue;\n }\n\n const srcPath = path.join(srcDir, item);\n const destPath = path.join(destDir, item);\n const stat = statSync(srcPath);\n\n if (stat.isDirectory()) {\n // 递归复制子目录\n mkdirSync(destPath, { recursive: true });\n ConfigInitializer.copyDirectoryRecursive(srcPath, destPath, exclude);\n } else {\n // 复制文件\n copyFileSync(srcPath, destPath);\n }\n }\n }\n\n /**\n * 获取默认模板目录路径\n *\n * 在多个可能的路径中查找默认模板目录\n *\n * @returns 找到的默认模板目录路径,如果都不存在则返回 null\n */\n private static getDefaultTemplateDir(): string | null {\n const possiblePaths = [\n // 迁移后:src/config/ 或 dist/config/ → 项目根 templates/default/\n resolve(__dirname, \"..\", \"..\", \"templates\", \"default\"),\n // 从 CWD 查找(兼容各种启动场景)\n resolve(process.cwd(), \"templates\", \"default\"),\n ];\n\n for (const p of possiblePaths) {\n if (existsSync(p)) {\n return p;\n }\n }\n\n return null;\n }\n}\n","/**\n * @/config\n *\n * 小智客户端配置管理库\n *\n * 此库提供了配置文件解析、验证和管理的完整功能,包括:\n * - ConfigManager: 配置管理器,负责配置文件的加载、保存和验证\n * - ConfigResolver: 配置解析器,按优先级查找配置文件\n * - ConfigInitializer: 配置初始化器,负责创建默认配置\n * - 配置适配与转换工具: 提供旧配置向新格式迁移、规范化(例如 normalizeServiceConfig 等)\n * - JSON5 读写工具: 提供 JSON5 格式的读写支持\n *\n * @example\n * ```typescript\n * import { configManager } from '@/config';\n *\n * // 获取配置\n * const config = configManager.getConfig();\n *\n * // 更新 MCP 端点配置\n * configManager.updateMcpEndpoint('wss://api.example.com/mcp');\n * ```\n */\n\n// =========================\n// 导出\n// =========================\n\nexport * from \"./manager.js\";\nexport * from \"./adapter.js\";\nexport * from \"./resolver.js\";\nexport * from \"./initializer.js\";\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 PAGINATION_CONSTANTS = {\n /** 默认每页记录数 */\n DEFAULT_LIMIT: 50,\n /** 最大每页记录数 */\n MAX_LIMIT: 200,\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\";\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 fs from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport path from \"node:path\";\nimport type { FileOperationOptions } from \"../Types\";\nimport { FileError } from \"../errors/index\";\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 || tmpdir();\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\";\nimport { FileUtils } from \"./FileUtils\";\n\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 // 构建环境:dist/cli/index.js -> dist/backend/templates\n path.join(scriptDir, \"..\", \"backend\", 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 * 同时支持 Unix (/) 和 Windows (\\) 分隔符\n */\n static validatePath(inputPath: string): boolean {\n const normalizedPath = path.normalize(inputPath);\n // 按多种分隔符拆分路径段,检查是否包含严格等于 \"..\" 的段\n const segments = normalizedPath.split(/[/\\\\]/);\n return !segments.includes(\"..\");\n }\n\n /**\n * 确保路径在指定目录内\n * 使用 path.relative 判断,避免前缀匹配被绕过(如 /safe/base2 匹配 /safe/base)\n */\n static ensurePathWithin(inputPath: string, baseDir: string): string {\n const resolvedPath = path.resolve(baseDir, inputPath);\n const resolvedBase = path.resolve(baseDir);\n\n // 使用 path.relative 检查相对路径是否以 \"..\" 开头或为绝对路径\n const relativePath = path.relative(resolvedBase, resolvedPath);\n if (relativePath.startsWith(\"..\") || path.isAbsolute(relativePath)) {\n throw new Error(`路径 ${inputPath} 超出了允许的范围`);\n }\n\n return resolvedPath;\n }\n\n /**\n * 获取可执行文件路径\n * 对于 CLI 自身复用,直接返回当前脚本路径;其他名称从项目根目录的 dist 中查找\n */\n static getExecutablePath(name: string): string {\n // CLI 自身复用:直接返回当前执行的脚本路径\n if (name === \"cli\") {\n const cliPath = process.argv[1];\n if (cliPath) {\n try {\n return realpathSync(cliPath);\n } catch {\n return cliPath;\n }\n }\n // 回退:无法获取时抛出明确错误\n throw new Error(\"无法确定 CLI 脚本路径\");\n }\n\n // 其他可执行文件:从项目根目录的 dist 中查找\n const projectRoot = PathUtils.getProjectRoot();\n return path.join(projectRoot, \"dist\", `${name}.js`);\n }\n\n /**\n * 获取 Web 服务器启动器路径\n * 返回项目根目录 dist 下的 WebServerLauncher.js(向后兼容包装脚本)\n */\n static getWebServerLauncherPath(): string {\n const projectRoot = PathUtils.getProjectRoot();\n return path.join(projectRoot, \"dist\", \"WebServerLauncher.js\");\n }\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 const hasTraversal = normalizedPath.split(/[/\\\\]/).includes(\"..\");\n if (hasTraversal || 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\";\nimport type { Platform } from \"../Types\";\nimport { ProcessError } from \"../errors/index\";\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\";\nimport { ValidationError } from \"../errors/index\";\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(\n value: string | number | boolean | object | null | undefined,\n fieldName: string\n ): 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\"): unknown {\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<T>(\n array: T[],\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, unknown>,\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 * 负责管理 xiaozhi 服务的进程生命周期,包括:\n * - 进程启动和停止\n * - PID 文件管理\n * - 进程状态查询\n * - 优雅关闭进程\n *\n * @module src/cli/services/ProcessManager\n */\n\nimport { FileError, ProcessError } from \"../errors/index\";\nimport type {\n ProcessManager as IProcessManager,\n ServiceStatus,\n} from \"../interfaces/Service\";\nimport { FileUtils } from \"../utils/FileUtils\";\nimport { FormatUtils } from \"../utils/FormatUtils\";\nimport { PathUtils } from \"../utils/PathUtils\";\nimport { PlatformUtils } from \"../utils/PlatformUtils\";\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 await PlatformUtils.killProcess(pid, \"SIGTERM\");\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 * 负责管理 xiaozhi 服务的守护进程,包括:\n * - 守护进程启动和停止\n * - 日志文件管理\n * - 进程状态监控\n * - 支持手动重启\n *\n * @module src/cli/services/DaemonManager\n */\n\nimport type { ChildProcess } from \"node:child_process\";\nimport { spawn } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport type { WebServer } from \"@/server/WebServer\";\nimport consola from \"consola\";\nimport { RETRY_CONSTANTS } from \"../Constants\";\nimport { ProcessError, ServiceError } from \"../errors/index\";\nimport type {\n DaemonManager as IDaemonManager,\n ProcessManager,\n} from \"../interfaces/Service\";\nimport { PathUtils } from \"../utils/PathUtils\";\nimport { PlatformUtils } from \"../utils/PlatformUtils\";\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(private processManager: ProcessManager) {}\n\n /**\n * 启动守护进程\n */\n async startDaemon(\n serverFactory: () => Promise<WebServer>,\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 consola.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 consola.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<WebServer>,\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) =>\n setTimeout(resolve, RETRY_CONSTANTS.DEFAULT_INTERVAL)\n );\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.once(\"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<WebServer>,\n options: DaemonOptions\n ): Promise<ChildProcess> {\n // 获取启动脚本路径\n const scriptPath = PathUtils.getWebServerLauncherPath();\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 consola.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 consola.error(`守护进程异常退出 (代码: ${code}, 信号: ${signal})`);\n } else {\n consola.info(\"守护进程正常退出\");\n }\n\n // 清理 PID 文件\n this.processManager.cleanupPidFile();\n this.currentDaemon = null;\n });\n\n // 监听进程错误\n child.on(\"error\", (error) => {\n consola.error(`守护进程错误: ${error.message}`);\n this.processManager.cleanupPidFile();\n this.currentDaemon = null;\n });\n\n // 监听进程断开连接\n child.on(\"disconnect\", () => {\n consola.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 consola.warn(\n `清理守护进程失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n this.currentDaemon = null;\n }\n }\n}\n","/**\n * 服务管理服务\n *\n * 负责管理 xiaozhi 服务的生命周期,包括:\n * - 服务启动和停止\n * - 进程状态查询\n * - 配置验证和初始化\n * - 多种运行模式支持(normal、mcp-server)\n *\n * @module src/cli/services/ServiceManager\n */\n\nimport consola from \"consola\";\nimport type { ConfigManager } from \"../../config\";\nimport { ConfigInitializer } from \"../../config\";\nimport { RETRY_CONSTANTS } from \"../Constants\";\nimport { ConfigError, ServiceError } from \"../errors/index\";\nimport type {\n ServiceManager as IServiceManager,\n ProcessManager,\n ServiceStartOptions,\n ServiceStatus,\n} from \"../interfaces/Service\";\nimport { PathUtils } from \"../utils/PathUtils\";\nimport { Validation } from \"../utils/Validation\";\n\n/**\n * 服务管理器实现\n */\nexport class ServiceManagerImpl implements IServiceManager {\n constructor(\n private processManager: ProcessManager,\n private configManager: ConfigManager\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 consola.info(\n `检测到服务已在运行 (PID: ${status.pid}),正在自动重启...`\n );\n\n try {\n // 优雅停止现有进程\n await this.processManager.gracefulKillProcess(status.pid || 0);\n\n // 清理 PID 文件\n this.processManager.cleanupPidFile();\n\n // 等待一下确保完全停止\n await new Promise((resolve) =>\n setTimeout(resolve, RETRY_CONSTANTS.DEFAULT_INTERVAL)\n );\n\n consola.success(\"现有服务已停止,正在启动新服务...\");\n } catch (stopError) {\n consola.warn(\n `停止现有服务时出现警告: ${stopError instanceof Error ? stopError.message : String(stopError)}`\n );\n // 继续尝试启动新服务,因为旧进程可能已经不存在了\n }\n }\n\n // 检查环境配置\n await this.checkEnvironment();\n\n // 根据模式启动服务\n switch (options.mode) {\n case \"mcp-server\":\n await this.startMcpServerMode(options);\n break;\n case \"stdio\":\n // stdio 模式已废弃,改为启动 Web 服务\n await this.startNormalMode(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 || 0);\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) =>\n setTimeout(resolve, RETRY_CONSTANTS.DEFAULT_INTERVAL)\n );\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 async checkEnvironment(): Promise<void> {\n // 检查配置文件是否存在\n if (!this.configManager.configExists()) {\n // 尝试初始化默认配置\n try {\n consola.info(\"未找到配置文件,正在创建默认配置...\");\n\n const configPath = await ConfigInitializer.initializeDefaultConfig();\n\n consola.success(`默认配置已创建: ${configPath}`);\n consola.info(\"提示: 您可以稍后编辑此配置文件以自定义设置\");\n\n // 重新加载配置管理器\n this.configManager.reloadConfig();\n } catch (error) {\n // 保留原始错误信息,方便调试\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n consola.error(`创建默认配置失败: ${errorMessage}`);\n\n // 抛出包含原始错误信息的异常\n throw new ConfigError(\n `无法创建默认配置: ${errorMessage}\\n请手动运行 'xiaozhi create' 创建配置文件`\n );\n }\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 if (options.daemon) {\n // 后台模式 - 默认启动 WebUI\n await this.startWebServerInDaemon();\n } else {\n // 前台模式 - 默认启动 WebUI\n await this.startWebServerInForeground();\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 || 0, \"daemon\");\n\n // 完全分离子进程\n child.unref();\n\n // 输出启动信息后立即退出父进程\n consola.success(\n `MCP Server 已在后台启动 (PID: ${child.pid}, Port: ${port})`\n );\n consola.info(\"使用 'xiaozhi status' 查看状态\");\n\n // 立即退出父进程,释放终端控制权\n process.exit(0);\n } else {\n // 前台模式 - 直接启动 Web Server\n const { WebServer } = await import(\"@/server/WebServer.js\");\n const server = new WebServer(port);\n\n // 处理退出信号\n const cleanup = async () => {\n await server.stop();\n process.exit(0);\n };\n\n process.once(\"SIGINT\", cleanup);\n process.once(\"SIGTERM\", cleanup);\n\n await server.start();\n }\n }\n\n /**\n * 后台模式启动 WebServer\n */\n private async startWebServerInDaemon(): Promise<void> {\n const { spawn } = await import(\"node:child_process\");\n const webServerPath = PathUtils.getWebServerLauncherPath();\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\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 || 0, \"daemon\");\n\n // 完全分离子进程\n child.unref();\n\n // 输出启动信息后立即退出父进程\n consola.success(`后台服务已启动 (PID: ${child.pid})`);\n consola.info(\"使用 'xiaozhi status' 查看状态\");\n consola.info(\"使用 'xiaozhi attach' 查看日志\");\n\n // 立即退出父进程,释放终端控制权\n process.exit(0);\n }\n\n /**\n * 前台模式启动 WebServer\n */\n private async startWebServerInForeground(): Promise<void> {\n const { WebServer } = await import(\"@/server/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.once(\"SIGINT\", cleanup);\n process.once(\"SIGTERM\", cleanup);\n\n // 保存 PID 信息\n this.processManager.savePidInfo(process.pid, \"foreground\");\n\n await server.start();\n }\n}\n","/**\n * 模板管理服务\n *\n * 负责管理项目模板,包括:\n * - 模板列表查询\n * - 模板信息获取\n * - 项目创建和复制\n * - 模板变量替换\n * - 模板验证\n *\n * @module src/cli/services/TemplateManager\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { FileError, ValidationError } from \"../errors/index\";\nimport type {\n TemplateManager as ITemplateManager,\n TemplateCreateOptions,\n TemplateInfo,\n} from \"../interfaces/Service\";\nimport { FileUtils } from \"../utils/FileUtils\";\nimport { PathUtils } from \"../utils/PathUtils\";\nimport { Validation } from \"../utils/Validation\";\n\n// 重新导出类型以保持向后兼容\nexport type { TemplateInfo, TemplateCreateOptions };\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 * 当 templateName 为 undefined 时使用默认模板,为 null 时创建基本项目(仅配置文件)\n */\n async createProject(options: TemplateCreateOptions): Promise<void> {\n try {\n // 验证输入参数\n this.validateCreateOptions(options);\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 const templateName = options.templateName ?? \"default\";\n\n if (options.templateName === null) {\n // 基本项目模式:仅创建基础配置文件\n await this.createBasicProjectFiles(targetPath, options);\n } else {\n // 模板模式:使用指定或默认模板\n const templateInfo = await this.getTemplateInfo(templateName);\n\n if (!templateInfo) {\n throw new FileError(`模板不存在: ${templateName}`, \"\");\n }\n\n // 复制模板文件\n await this.copyTemplateFiles(templateInfo, targetPath, options);\n\n // 处理模板变量替换\n await this.processTemplateVariables(targetPath, options);\n }\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 // 仅当 templateName 有值时验证(null 表示基本项目模式,不验证)\n if (options.templateName !== undefined && options.templateName !== null) {\n Validation.validateTemplateName(options.templateName);\n }\n }\n\n /**\n * 创建基本项目文件(无模板,仅基础配置文件)\n */\n private async createBasicProjectFiles(\n targetPath: string,\n options: TemplateCreateOptions\n ): Promise<void> {\n // 创建基本配置文件\n const configContent = JSON.stringify(\n {\n name: options.projectName,\n version: \"1.0.0\",\n description: `${options.projectName} 项目`,\n },\n null,\n 2\n );\n FileUtils.writeFile(\n path.join(targetPath, \"xiaozhi.config.json\"),\n configContent,\n { overwrite: true }\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 // 将路径分隔符统一为 /,确保在 Windows 上也能正确匹配\n const relativePath = path\n .relative(basePath, file)\n .split(path.sep)\n .join(\"/\");\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 type { Command } from \"commander\";\nimport type { CommandArguments, CommandOptions } from \"./CommandTypes\";\nimport type { IDIContainer } from \"./Config\";\n\n/**\n * 命令处理器接口\n */\nexport interface CommandHandler {\n /** 命令名称 */\n name: string;\n /** 命令描述 */\n description: string;\n /** 命令选项 */\n options?: CommandOption[];\n /** 子命令 */\n subcommands?: SubCommand[];\n /** 执行命令 */\n execute(args: CommandArguments, options: CommandOptions): Promise<void>;\n}\n\n/**\n * 命令选项接口\n */\nexport interface CommandOption {\n /** 选项标志 */\n flags: string;\n /** 选项描述 */\n description: string;\n /** 默认值(限制为 Commander.js 支持的类型) */\n defaultValue?: string | boolean | string[];\n}\n\n/**\n * 子命令接口\n */\nexport interface SubCommand {\n /** 子命令名称 */\n name: string;\n /** 子命令描述 */\n description: string;\n /** 子命令选项 */\n options?: CommandOption[];\n /** 执行子命令 */\n execute(args: CommandArguments, options: CommandOptions): Promise<void>;\n}\n\n/**\n * 命令执行上下文\n */\nexport interface CommandContext {\n /** DI 容器 */\n container: IDIContainer;\n /** 命令行参数 */\n args: CommandArguments;\n /** 命令选项 */\n options: CommandOptions;\n}\n\n/**\n * 基础命令处理器抽象类\n */\nexport abstract class BaseCommandHandler implements CommandHandler {\n abstract name: string;\n abstract description: string;\n options?: CommandOption[];\n subcommands?: SubCommand[];\n\n constructor(protected container: IDIContainer) {}\n\n abstract execute(\n args: CommandArguments,\n options: CommandOptions\n ): Promise<void>;\n\n /**\n * 获取服务实例\n */\n protected getService<T>(serviceName: string): T {\n return this.container.get(serviceName) as T;\n }\n\n /**\n * 处理错误\n */\n protected handleError(error: Error): void {\n const errorHandler = this.getService<unknown>(\"errorHandler\");\n // 类型断言:errorHandler 应该有 handle 方法\n const handler = errorHandler as { handle: (error: Error) => void };\n handler.handle(error);\n }\n\n /**\n * 验证参数\n */\n protected validateArgs(args: CommandArguments, expectedCount: number): void {\n if (args.length < expectedCount) {\n throw new Error(\n `命令需要至少 ${expectedCount} 个参数,但只提供了 ${args.length} 个`\n );\n }\n }\n}\n\n/**\n * 命令注册器接口\n */\nexport interface ICommandRegistry {\n /** 注册所有命令到 Commander 程序 */\n registerCommands(program: Command): Promise<void>;\n /** 注册单个命令 */\n registerCommand(program: Command, handler: CommandHandler): void;\n /** 注册命令处理器 */\n registerHandler(handler: CommandHandler): void;\n}\n\n/**\n * 命令处理器工厂接口\n */\nexport interface ICommandHandlerFactory {\n /** 创建所有命令处理器 */\n createHandlers(): CommandHandler[];\n /** 创建指定类型的命令处理器 */\n createHandler(type: string): CommandHandler;\n}\n","/**\n * 服务管理命令处理器\n */\n\nimport consola from \"consola\";\nimport type { SubCommand } from \"../interfaces/Command\";\nimport { BaseCommandHandler } from \"../interfaces/Command\";\nimport type {\n CommandArguments,\n CommandOptions,\n} from \"../interfaces/CommandTypes\";\nimport type { IDIContainer } from \"../interfaces/Config\";\n\n/**\n * 服务管理命令处理器\n */\nexport class ServiceCommandHandler extends BaseCommandHandler {\n override name = \"service\";\n override description = \"服务管理命令\";\n\n override subcommands: SubCommand[] = [\n {\n name: \"start\",\n description: \"启动服务\",\n options: [\n { flags: \"-d, --daemon\", description: \"在后台运行服务\" },\n { flags: \"--debug\", description: \"启用调试模式 (输出DEBUG级别日志)\" },\n {\n flags: \"--stdio\",\n description: \"以 stdio 模式运行 MCP Server (用于 Cursor 等客户端)\",\n },\n ],\n execute: async (args: CommandArguments, options: CommandOptions) => {\n await this.handleStart(options);\n },\n },\n {\n name: \"stop\",\n description: \"停止服务\",\n execute: async (args: CommandArguments, options: CommandOptions) => {\n await this.handleStop();\n },\n },\n {\n name: \"status\",\n description: \"检查服务状态\",\n execute: async (args: CommandArguments, options: CommandOptions) => {\n await this.handleStatus();\n },\n },\n {\n name: \"restart\",\n description: \"重启服务\",\n options: [{ flags: \"-d, --daemon\", description: \"在后台运行服务\" }],\n execute: async (args: CommandArguments, options: CommandOptions) => {\n await this.handleRestart(options);\n },\n },\n {\n name: \"attach\",\n description: \"连接到后台服务查看日志\",\n execute: async (args: CommandArguments, options: CommandOptions) => {\n await this.handleAttach();\n },\n },\n ];\n\n constructor(container: IDIContainer) {\n super(container);\n }\n\n /**\n * 主命令执行(显示帮助)\n */\n override async execute(\n args: CommandArguments,\n options: CommandOptions\n ): Promise<void> {\n console.log(\"服务管理命令。使用 --help 查看可用的子命令。\");\n }\n\n /**\n * 处理启动命令\n */\n private async handleStart(options: CommandOptions): Promise<void> {\n try {\n // 处理--debug参数\n if (options.debug) {\n consola.level = 5; // debug 级别\n }\n\n const serviceManager = this.getService<any>(\"serviceManager\");\n\n if (options.stdio) {\n // stdio 模式已迁移到 HTTP 方式\n this.showStdioMigrationGuide();\n return;\n }\n\n // 传统模式\n await serviceManager.start({\n daemon: options.daemon || false,\n });\n } catch (error) {\n this.handleError(error as Error);\n }\n }\n\n /**\n * 处理停止命令\n */\n private async handleStop(): Promise<void> {\n try {\n const serviceManager = this.getService<any>(\"serviceManager\");\n await serviceManager.stop();\n } catch (error) {\n this.handleError(error as Error);\n }\n }\n\n /**\n * 处理状态检查命令\n */\n private async handleStatus(): Promise<void> {\n try {\n const serviceManager = this.getService<any>(\"serviceManager\");\n const status = await serviceManager.getStatus();\n\n if (status.running) {\n console.log(`✅ 服务正在运行 (PID: ${status.pid})`);\n if (status.uptime) {\n console.log(`⏱️ 运行时间: ${status.uptime}`);\n }\n if (status.mode) {\n console.log(`🔧 运行模式: ${status.mode}`);\n }\n } else {\n console.log(\"❌ 服务未运行\");\n }\n } catch (error) {\n this.handleError(error as Error);\n }\n }\n\n /**\n * 处理重启命令\n */\n private async handleRestart(options: CommandOptions): Promise<void> {\n try {\n const serviceManager = this.getService<any>(\"serviceManager\");\n await serviceManager.restart({\n daemon: options.daemon || false,\n });\n } catch (error) {\n this.handleError(error as Error);\n }\n }\n\n /**\n * 处理附加命令\n */\n private async handleAttach(): Promise<void> {\n try {\n const daemonManager = this.getService<any>(\"daemonManager\");\n await daemonManager.attachToLogs();\n } catch (error) {\n this.handleError(error as Error);\n }\n }\n\n /**\n * 显示 stdio 模式迁移指南\n */\n private showStdioMigrationGuide(): void {\n console.log(\"\\n❌ stdio 模式已废弃\\n\");\n console.log(\"小智客户端已迁移到纯 HTTP 架构,请使用以下方式:\\n\");\n\n console.log(\"1. 启动 Web 服务:\");\n console.log(\" xiaozhi start\\n\");\n\n console.log(\"2. 在 Cursor 中配置 HTTP 端点:\");\n console.log(' \"mcpServers\": {');\n console.log(' \"xiaozhi-client\": {');\n console.log(' \"type\": \"streamableHttp\",');\n console.log(' \"url\": \"http://localhost:9999/mcp\"');\n console.log(\" }\");\n console.log(\" }\\n\");\n }\n}\n","/**\n * 配置管理命令处理器\n */\n\nimport path from \"node:path\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport type { Ora } from \"ora\";\nimport type { SubCommand } from \"../interfaces/Command\";\nimport { BaseCommandHandler } from \"../interfaces/Command\";\nimport type {\n CommandArguments,\n CommandOptions,\n} from \"../interfaces/CommandTypes\";\nimport type { IDIContainer } from \"../interfaces/Config\";\n\n/**\n * 配置管理命令处理器\n */\nexport class ConfigCommandHandler extends BaseCommandHandler {\n override name = \"config\";\n override description = \"配置管理命令\";\n\n override subcommands: SubCommand[] = [\n {\n name: \"init\",\n description: \"初始化配置文件\",\n options: [\n {\n flags: \"-f, --format <format>\",\n description: \"配置文件格式 (json, json5, jsonc)\",\n defaultValue: \"json\",\n },\n ],\n execute: async (args: CommandArguments, options: CommandOptions) => {\n await this.handleInit(options);\n },\n },\n {\n name: \"get\",\n description: \"查看配置值\",\n execute: async (args: CommandArguments, options: CommandOptions) => {\n this.validateArgs(args, 1);\n await this.handleGet(args[0]);\n },\n },\n {\n name: \"set\",\n description: \"设置配置值\",\n execute: async (args: CommandArguments, options: CommandOptions) => {\n this.validateArgs(args, 2);\n await this.handleSet(args[0], args[1]);\n },\n },\n ];\n\n constructor(container: IDIContainer) {\n super(container);\n }\n\n /**\n * 主命令执行(显示帮助)\n */\n override async execute(\n args: CommandArguments,\n options: CommandOptions\n ): Promise<void> {\n console.log(\"配置管理命令。使用 --help 查看可用的子命令。\");\n }\n\n /**\n * 处理初始化命令\n */\n private async handleInit(options: CommandOptions): Promise<void> {\n const spinner = ora(\"初始化配置...\").start();\n\n try {\n const format = options.format as \"json\" | \"json5\" | \"jsonc\";\n if (format !== \"json\" && format !== \"json5\" && format !== \"jsonc\") {\n throw new Error(\"格式必须是 json, json5 或 jsonc\");\n }\n\n const configManager = this.getService<any>(\"configManager\");\n\n if (configManager.configExists()) {\n spinner.warn(\"配置文件已存在\");\n console.log(chalk.yellow(\"如需重新初始化,请先删除现有的配置文件\"));\n return;\n }\n\n configManager.initConfig(format);\n spinner.succeed(\"配置文件初始化成功\");\n\n // 获取实际创建的配置文件路径\n const configDir = process.env.XIAOZHI_CONFIG_DIR || process.cwd();\n const configFileName = `xiaozhi.config.${format}`;\n const configPath = path.join(configDir, configFileName);\n\n console.log(chalk.green(`✅ 配置文件已创建: ${configFileName}`));\n console.log(chalk.yellow(\"📝 请编辑配置文件设置你的 MCP 端点:\"));\n console.log(chalk.gray(` 配置文件路径: ${configPath}`));\n console.log(chalk.yellow(\"💡 或者使用命令设置:\"));\n console.log(\n chalk.gray(\" xiaozhi config set mcpEndpoint <your-endpoint-url>\")\n );\n } catch (error) {\n spinner.fail(\n `初始化配置失败: ${error instanceof Error ? error.message : String(error)}`\n );\n this.handleError(error as Error);\n }\n }\n\n /**\n * 确保配置文件存在,如果不存在则显示提示并返回 false\n */\n private async ensureConfigExists(spinner: Ora): Promise<boolean> {\n const configManager = this.getService<any>(\"configManager\");\n\n if (!configManager.configExists()) {\n spinner.fail(\"配置文件不存在\");\n console.log(\n chalk.yellow('💡 提示: 请先运行 \"xiaozhi config init\" 初始化配置')\n );\n return false;\n }\n\n return true;\n }\n\n /**\n * 处理获取配置命令\n */\n private async handleGet(key: string): Promise<void> {\n const spinner = ora(\"读取配置...\").start();\n\n try {\n if (!(await this.ensureConfigExists(spinner))) {\n return;\n }\n\n const configManager = this.getService<any>(\"configManager\");\n const config = configManager.getConfig();\n\n switch (key) {\n case \"mcpEndpoint\": {\n spinner.succeed(\"配置信息\");\n const endpoints = configManager.getMcpEndpoints();\n if (endpoints.length === 0) {\n console.log(chalk.yellow(\"未配置任何 MCP 端点\"));\n } else if (endpoints.length === 1) {\n console.log(chalk.green(`MCP 端点: ${endpoints[0]}`));\n } else {\n console.log(chalk.green(`MCP 端点 (${endpoints.length} 个):`));\n endpoints.forEach((ep: string, index: number) => {\n console.log(chalk.gray(` ${index + 1}. ${ep}`));\n });\n }\n break;\n }\n case \"mcpServers\":\n spinner.succeed(\"配置信息\");\n console.log(chalk.green(\"MCP 服务:\"));\n for (const [name, serverConfig] of Object.entries(\n config.mcpServers\n )) {\n const server = serverConfig as any;\n // 检查是否是 SSE 类型\n if (\"type\" in server && server.type === \"sse\") {\n console.log(chalk.gray(` ${name}: [SSE] ${server.url}`));\n } else {\n console.log(\n chalk.gray(\n ` ${name}: ${server.command} ${server.args.join(\" \")}`\n )\n );\n }\n }\n break;\n case \"connection\": {\n spinner.succeed(\"配置信息\");\n const connectionConfig = configManager.getConnectionConfig();\n console.log(chalk.green(\"连接配置:\"));\n console.log(\n chalk.gray(\n ` 心跳检测间隔: ${connectionConfig.heartbeatInterval}ms`\n )\n );\n console.log(\n chalk.gray(` 心跳超时时间: ${connectionConfig.heartbeatTimeout}ms`)\n );\n console.log(\n chalk.gray(` 重连间隔: ${connectionConfig.reconnectInterval}ms`)\n );\n break;\n }\n case \"heartbeatInterval\":\n spinner.succeed(\"配置信息\");\n console.log(\n chalk.green(\n `心跳检测间隔: ${configManager.getHeartbeatInterval()}ms`\n )\n );\n break;\n case \"heartbeatTimeout\":\n spinner.succeed(\"配置信息\");\n console.log(\n chalk.green(\n `心跳超时时间: ${configManager.getHeartbeatTimeout()}ms`\n )\n );\n break;\n case \"reconnectInterval\":\n spinner.succeed(\"配置信息\");\n console.log(\n chalk.green(`重连间隔: ${configManager.getReconnectInterval()}ms`)\n );\n break;\n default:\n spinner.fail(`未知的配置项: ${key}`);\n console.log(\n chalk.yellow(\n \"支持的配置项: mcpEndpoint, mcpServers, connection, heartbeatInterval, heartbeatTimeout, reconnectInterval\"\n )\n );\n }\n } catch (error) {\n spinner.fail(\n `读取配置失败: ${error instanceof Error ? error.message : String(error)}`\n );\n this.handleError(error as Error);\n }\n }\n\n /**\n * 处理设置配置命令\n */\n private async handleSet(key: string, value: string): Promise<void> {\n const spinner = ora(\"更新配置...\").start();\n\n try {\n if (!(await this.ensureConfigExists(spinner))) {\n return;\n }\n\n const configManager = this.getService<any>(\"configManager\");\n\n switch (key) {\n case \"mcpEndpoint\":\n configManager.updateMcpEndpoint(value);\n spinner.succeed(`MCP 端点已设置为: ${value}`);\n break;\n case \"heartbeatInterval\": {\n const interval = Number.parseInt(value);\n if (Number.isNaN(interval) || interval <= 0) {\n throw new Error(\"心跳检测间隔必须是正整数\");\n }\n configManager.updateHeartbeatInterval(interval);\n spinner.succeed(`心跳检测间隔已设置为: ${interval}ms`);\n break;\n }\n case \"heartbeatTimeout\": {\n const timeout = Number.parseInt(value);\n if (Number.isNaN(timeout) || timeout <= 0) {\n throw new Error(\"心跳超时时间必须是正整数\");\n }\n configManager.updateHeartbeatTimeout(timeout);\n spinner.succeed(`心跳超时时间已设置为: ${timeout}ms`);\n break;\n }\n case \"reconnectInterval\": {\n const interval = Number.parseInt(value);\n if (Number.isNaN(interval) || interval <= 0) {\n throw new Error(\"重连间隔必须是正整数\");\n }\n configManager.updateReconnectInterval(interval);\n spinner.succeed(`重连间隔已设置为: ${interval}ms`);\n break;\n }\n default:\n spinner.fail(`不支持设置的配置项: ${key}`);\n console.log(\n chalk.yellow(\n \"支持设置的配置项: mcpEndpoint, heartbeatInterval, heartbeatTimeout, reconnectInterval\"\n )\n );\n }\n } catch (error) {\n spinner.fail(\n `设置配置失败: ${error instanceof Error ? error.message : String(error)}`\n );\n this.handleError(error as Error);\n }\n }\n}\n","/**\n * 项目管理命令处理器\n */\n\nimport path from \"node:path\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport type { CommandOption } from \"../interfaces/Command\";\nimport { BaseCommandHandler } from \"../interfaces/Command\";\nimport type {\n CommandArguments,\n CommandOptions,\n} from \"../interfaces/CommandTypes\";\nimport type { IDIContainer } from \"../interfaces/Config\";\nimport type { TemplateInfo } from \"../interfaces/Service\";\n\n/**\n * 项目管理命令处理器\n */\nexport class ProjectCommandHandler extends BaseCommandHandler {\n override name = \"create\";\n override description = \"创建项目\";\n\n override options: CommandOption[] = [\n {\n flags: \"-t, --template <templateName>\",\n description: \"使用指定模板创建项目\",\n },\n ];\n\n constructor(container: IDIContainer) {\n super(container);\n }\n\n /**\n * 执行创建项目命令\n */\n override async execute(\n args: CommandArguments,\n options: CommandOptions\n ): Promise<void> {\n this.validateArgs(args, 1);\n const projectName = args[0];\n\n await this.handleCreate(projectName, options);\n }\n\n /**\n * 处理创建项目命令\n */\n protected async handleCreate(\n projectName: string,\n options: CommandOptions\n ): Promise<void> {\n const spinner = ora(\"初始化项目...\").start();\n\n try {\n const templateManager = this.getService<any>(\"templateManager\");\n const fileUtils = this.getService<any>(\"fileUtils\");\n\n // 确定目标目录\n const targetPath = path.join(process.cwd(), projectName);\n\n // 检查目标目录是否已存在\n if (await fileUtils.exists(targetPath)) {\n spinner.fail(`目录 \"${projectName}\" 已存在`);\n console.log(\n chalk.yellow(\"💡 提示: 请选择不同的项目名称或删除现有目录\")\n );\n return;\n }\n\n if (options.template) {\n // 使用模板创建项目\n await this.createFromTemplate(\n projectName,\n options.template as string,\n targetPath,\n spinner,\n templateManager\n );\n } else {\n // 创建基本项目(只有配置文件)\n await this.createBasicProject(\n projectName,\n targetPath,\n spinner,\n templateManager\n );\n }\n } catch (error) {\n spinner.fail(\n `创建项目失败: ${error instanceof Error ? error.message : String(error)}`\n );\n this.handleError(error as Error);\n }\n }\n\n /**\n * 从模板创建项目\n */\n private async createFromTemplate(\n projectName: string,\n templateName: string,\n targetPath: string,\n spinner: any,\n templateManager: any\n ): Promise<void> {\n spinner.text = \"检查模板...\";\n\n // 获取可用模板列表\n const availableTemplates = await templateManager.getAvailableTemplates();\n\n if (availableTemplates.length === 0) {\n spinner.fail(\"找不到可用模板\");\n console.log(chalk.yellow(\"💡 提示: 请确保 xiaozhi-client 正确安装\"));\n return;\n }\n\n // 使用局部变量避免重新赋值函数参数\n let actualTemplateName = templateName;\n\n // 验证模板是否存在\n const isValidTemplate =\n await templateManager.validateTemplate(actualTemplateName);\n if (!isValidTemplate) {\n spinner.fail(`模板 \"${actualTemplateName}\" 不存在`);\n\n // 尝试找到相似的模板\n const similarTemplate = this.findSimilarTemplate(\n actualTemplateName,\n availableTemplates\n );\n\n if (similarTemplate) {\n console.log(\n chalk.yellow(`💡 你是想使用模板 \"${similarTemplate}\" 吗?`)\n );\n const confirmed = await this.askUserConfirmation(\n chalk.cyan(\"确认使用此模板?(y/n): \")\n );\n\n if (confirmed) {\n actualTemplateName = similarTemplate;\n } else {\n this.showAvailableTemplates(availableTemplates);\n return;\n }\n } else {\n this.showAvailableTemplates(availableTemplates);\n return;\n }\n }\n\n spinner.text = `从模板 \"${actualTemplateName}\" 创建项目 \"${projectName}\"...`;\n\n // 使用模板管理器创建项目\n await templateManager.createProject({\n templateName: actualTemplateName,\n targetPath,\n projectName,\n });\n\n spinner.succeed(`项目 \"${projectName}\" 创建成功`);\n\n console.log(chalk.green(\"✅ 项目创建完成!\"));\n console.log(chalk.yellow(\"📝 接下来的步骤:\"));\n console.log(chalk.gray(` cd ${projectName}`));\n console.log(chalk.gray(\" pnpm install # 安装依赖\"));\n console.log(chalk.gray(\" # 编辑 xiaozhi.config.json 设置你的 MCP 端点\"));\n console.log(chalk.gray(\" xiaozhi start # 启动服务\"));\n }\n\n /**\n * 创建基本项目\n */\n private async createBasicProject(\n projectName: string,\n targetPath: string,\n spinner: any,\n templateManager: any\n ): Promise<void> {\n spinner.text = `创建基本项目 \"${projectName}\"...`;\n\n // 使用模板管理器创建基本项目\n await templateManager.createProject({\n templateName: null, // 表示创建基本项目\n targetPath,\n projectName,\n });\n\n spinner.succeed(`项目 \"${projectName}\" 创建成功`);\n\n console.log(chalk.green(\"✅ 基本项目创建完成!\"));\n console.log(chalk.yellow(\"📝 接下来的步骤:\"));\n console.log(chalk.gray(` cd ${projectName}`));\n console.log(\n chalk.gray(\" # 编辑 xiaozhi.config.json 设置你的 MCP 端点和服务\")\n );\n console.log(chalk.gray(\" xiaozhi start # 启动服务\"));\n console.log(\n chalk.yellow(\"💡 提示: 使用 --template 选项可以从模板创建项目\")\n );\n }\n\n /**\n * 显示可用模板\n */\n private showAvailableTemplates(templates: TemplateInfo[]): void {\n console.log(chalk.yellow(\"可用的模板:\"));\n for (const template of templates) {\n console.log(\n chalk.gray(\n ` - ${template.name}${template.description ? ` - ${template.description}` : \"\"}`\n )\n );\n }\n }\n\n /**\n * 查找相似模板\n */\n private findSimilarTemplate(\n input: string,\n templates: TemplateInfo[]\n ): string | null {\n const formatUtils = this.getService<any>(\"formatUtils\");\n\n let bestMatch: string | null = null;\n let bestSimilarity = 0;\n\n for (const template of templates) {\n const similarity = formatUtils.calculateSimilarity(\n input.toLowerCase(),\n template.name.toLowerCase()\n );\n if (similarity > bestSimilarity && similarity > 0.6) {\n bestSimilarity = similarity;\n bestMatch = template.name;\n }\n }\n\n return bestMatch;\n }\n\n /**\n * 询问用户确认\n */\n private async askUserConfirmation(prompt: string): Promise<boolean> {\n const readline = await import(\"node:readline\");\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n return new Promise((resolve) => {\n rl.question(prompt, (answer) => {\n rl.close();\n resolve(\n answer.toLowerCase().trim() === \"y\" ||\n answer.toLowerCase().trim() === \"yes\"\n );\n });\n });\n }\n}\n","/**\n * CLI 命令相关类型定义\n * 用于替代命令处理器中的 any 类型使用,提供类型安全保障\n */\n\nimport type { LocalMCPServerConfig, MCPServerConfig } from \"../../config\";\n\n// =========================\n// 基础命令参数和选项类型\n// =========================\n\n/**\n * 命令行参数类型\n * 替代 any[] 类型\n */\nexport type CommandArguments = string[];\n\n/**\n * 命令选项类型\n * 替代 any 类型\n */\nexport type CommandOptions = Record<string, unknown>;\n\n// =========================\n// 子命令具体选项类型\n// =========================\n\n/**\n * list 子命令选项\n */\nexport interface ListOptions {\n /** 是否显示所有服务的工具列表 */\n tools?: boolean;\n}\n\n/**\n * call 子命令选项\n */\nexport interface CallOptions {\n /** 工具参数 (JSON 格式) */\n args?: string;\n}\n\n// =========================\n// 类型守卫函数\n// =========================\n\n/**\n * 检查对象是否为本地 MCP 服务配置\n * @param obj 待检查的对象\n * @returns 是否为本地服务配置\n */\nexport function isLocalMCPServerConfig(\n obj: unknown\n): obj is LocalMCPServerConfig {\n const config = obj as MCPServerConfig;\n return (\n typeof config === \"object\" &&\n config !== null &&\n \"command\" in config &&\n \"args\" in config &&\n typeof config.command === \"string\" &&\n Array.isArray(config.args) &&\n config.args.every((arg: unknown) => typeof arg === \"string\")\n );\n}\n\n// =========================\n// 类型化子命令接口\n// =========================\n\n/**\n * 类型化子命令接口\n * 提供类型安全的子命令定义\n */\nexport interface TypedSubCommand<TOptions = CommandOptions> {\n /** 子命令名称 */\n name: string;\n /** 子命令描述 */\n description: string;\n /** 子命令选项 */\n options?: Array<{\n /** 选项标志 */\n flags: string;\n /** 选项描述 */\n description: string;\n /** 默认值 */\n defaultValue?: unknown;\n }>;\n /** 执行子命令 */\n execute: (args: CommandArguments, options: TOptions) => Promise<void>;\n}\n","/**\n * MCP管理命令处理器\n */\n\nimport chalk from \"chalk\";\nimport Table from \"cli-table3\";\nimport consola from \"consola\";\nimport ora from \"ora\";\nimport { configManager } from \"../../config\";\nimport type { SubCommand } from \"../interfaces/Command\";\nimport { BaseCommandHandler } from \"../interfaces/Command\";\nimport type {\n CallOptions,\n CommandArguments,\n CommandOptions,\n ListOptions,\n} from \"../interfaces/CommandTypes\";\nimport { isLocalMCPServerConfig } from \"../interfaces/CommandTypes\";\nimport { ProcessManagerImpl } from \"../services/ProcessManager\";\n\n// 工具调用结果接口\ninterface ToolCallResult {\n content: Array<{\n type: string;\n text: string;\n }>;\n isError?: boolean;\n}\n\n/**\n * MCP管理命令处理器\n */\nexport class McpCommandHandler extends BaseCommandHandler {\n private processManager: ProcessManagerImpl;\n private baseUrl: string;\n\n constructor(...args: ConstructorParameters<typeof BaseCommandHandler>) {\n super(...args);\n this.processManager = new ProcessManagerImpl();\n\n // 获取 Web 服务器的端口\n try {\n const webPort = configManager.getWebUIPort() ?? 9999;\n this.baseUrl = `http://localhost:${webPort}`;\n } catch {\n this.baseUrl = \"http://localhost:9999\";\n }\n }\n\n /**\n * 中文字符正则表达式\n *\n * Unicode 范围说明:\n * - \\u4e00-\\u9fff: CJK 统一汉字(基本汉字)\n * - \\u3400-\\u4dbf: CJK 扩展 A(扩展汉字)\n * - \\uff00-\\uffef: 全角字符和半角片假名(包括中文标点符号)\n *\n * 注意:此范围可能不完全覆盖所有中日韩字符(如 CJK 扩展 B-F 等),\n * 但已覆盖绝大多数常用中文场景。\n */\n private static readonly CHINESE_CHAR_REGEX =\n /[\\u4e00-\\u9fff\\u3400-\\u4dbf\\uff00-\\uffef]/;\n\n /**\n * 计算字符串的显示宽度(中文字符占2个宽度,英文字符占1个宽度)\n */\n private static getDisplayWidth(str: string): number {\n let width = 0;\n for (const char of str) {\n // 判断是否为中文字符(包括中文标点符号)\n if (McpCommandHandler.CHINESE_CHAR_REGEX.test(char)) {\n width += 2;\n } else {\n width += 1;\n }\n }\n return width;\n }\n\n /**\n * 截断字符串到指定的显示宽度\n */\n private static truncateToWidth(str: string, maxWidth: number): string {\n if (McpCommandHandler.getDisplayWidth(str) <= maxWidth) {\n return str;\n }\n\n // 如果最大宽度小于等于省略号的宽度,返回空字符串\n if (maxWidth <= 3) {\n return \"\";\n }\n\n let result = \"\";\n let currentWidth = 0;\n let hasAddedChar = false;\n\n for (const char of str) {\n const charWidth = McpCommandHandler.CHINESE_CHAR_REGEX.test(char) ? 2 : 1;\n\n // 如果加上当前字符会超出限制\n if (currentWidth + charWidth > maxWidth - 3) {\n // 如果还没有添加任何字符,说明连一个字符都放不下,返回空字符串\n if (!hasAddedChar) {\n return \"\";\n }\n // 否则添加省略号并退出\n result += \"...\";\n break;\n }\n\n result += char;\n currentWidth += charWidth;\n hasAddedChar = true;\n }\n\n return result;\n }\n\n /**\n * 解析 JSON 参数\n * @param argsString JSON 字符串\n * @returns 解析后的参数对象\n */\n private static parseJsonArgs(argsString: string): Record<string, unknown> {\n try {\n return JSON.parse(argsString);\n } catch (error) {\n throw new Error(\n `参数格式错误,请使用有效的 JSON 格式。错误详情: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n\n /**\n * 格式化工具调用结果输出\n * @param result 工具调用结果\n * @returns 格式化后的字符串\n */\n private static formatToolCallResult(result: ToolCallResult): string {\n return JSON.stringify(result);\n }\n\n override name = \"mcp\";\n override description = \"MCP 服务和工具管理\";\n\n override subcommands: SubCommand[] = [\n {\n name: \"list\",\n description: \"列出 MCP 服务\",\n options: [{ flags: \"--tools\", description: \"显示所有服务的工具列表\" }],\n execute: async (args: CommandArguments, options: CommandOptions) => {\n await this.handleList(options as ListOptions);\n },\n },\n {\n name: \"server\",\n description: \"管理指定的 MCP 服务\",\n execute: async (args: CommandArguments, options: CommandOptions) => {\n this.validateArgs(args, 1);\n await this.handleServer(args[0]);\n },\n },\n {\n name: \"tool\",\n description: \"启用或禁用指定服务的工具\",\n execute: async (args: CommandArguments, options: CommandOptions) => {\n this.validateArgs(args, 3);\n const [serverName, toolName, action] = args;\n\n if (action !== \"enable\" && action !== \"disable\") {\n console.error(chalk.red(\"错误: 操作必须是 'enable' 或 'disable'\"));\n process.exit(1);\n }\n\n const enabled = action === \"enable\";\n await this.handleTool(serverName, toolName, enabled);\n },\n },\n {\n name: \"call\",\n description: \"调用指定服务的工具\",\n options: [\n {\n flags: \"--args <json>\",\n description: \"工具参数 (JSON 格式)\",\n defaultValue: \"{}\",\n },\n ],\n execute: async (args: CommandArguments, options: CommandOptions) => {\n this.validateArgs(args, 2);\n const [serviceName, toolName] = args;\n await this.handleCall(\n serviceName,\n toolName,\n (options as CallOptions).args ?? \"{}\"\n );\n },\n },\n ];\n\n /**\n * 主命令执行(显示帮助)\n */\n async execute(\n args: CommandArguments,\n options: CommandOptions\n ): Promise<void> {\n console.log(\"MCP 服务和工具管理命令。使用 --help 查看可用的子命令。\");\n }\n\n /**\n * 处理列出服务命令\n */\n private async handleList(options: ListOptions): Promise<void> {\n try {\n await this.handleListInternal(options);\n } catch (error) {\n this.handleError(error as Error);\n }\n }\n\n /**\n * 处理服务管理命令\n */\n private async handleServer(serverName: string): Promise<void> {\n try {\n await this.handleServerInternal(serverName);\n } catch (error) {\n this.handleError(error as Error);\n }\n }\n\n /**\n * 处理工具管理命令\n */\n private async handleTool(\n serverName: string,\n toolName: string,\n enabled: boolean\n ): Promise<void> {\n try {\n await this.handleToolInternal(serverName, toolName, enabled);\n } catch (error) {\n this.handleError(error as Error);\n }\n }\n\n /**\n * 验证服务状态\n * @private\n */\n private async validateServiceStatus(): Promise<void> {\n // 检查进程级别的服务状态\n const processStatus = this.processManager.getServiceStatus();\n if (!processStatus.running) {\n throw new Error(\n \"xiaozhi 服务未启动。请先运行 'xiaozhi start' 或 'xiaozhi start -d' 启动服务。\"\n );\n }\n\n // 检查 Web 服务器是否可访问\n try {\n const response = await fetch(`${this.baseUrl}/api/status`, {\n method: \"GET\",\n signal: AbortSignal.timeout(5000), // 5秒超时\n });\n\n if (!response.ok) {\n throw new Error(`Web 服务器响应错误: ${response.status}`);\n }\n } catch (error: unknown) {\n // 超时单独提示\n if (error instanceof Error && error.name === \"AbortError\") {\n throw new Error(\"连接 xiaozhi 服务超时。请检查服务是否正常运行。\");\n }\n\n // 已知的 Error 实例,区分网络错误与其他错误\n if (error instanceof Error) {\n const isNetworkError =\n error instanceof TypeError &&\n /fetch|network|failed/i.test(error.message);\n\n if (isNetworkError) {\n throw new Error(\n `无法连接到 xiaozhi 服务(网络请求失败)。请检查网络连接或服务地址是否正确。原始错误: ${error.message}`\n );\n }\n\n throw new Error(\n `无法连接到 xiaozhi 服务。请检查服务状态。原始错误: ${error.message}`\n );\n }\n\n // 非 Error 对象的兜底处理,避免出现 [object Object]\n let detail: string;\n try {\n detail = JSON.stringify(error);\n } catch {\n detail = String(error);\n }\n\n throw new Error(\n `无法连接到 xiaozhi 服务。请检查服务状态。错误详情: ${detail}`\n );\n }\n }\n\n /**\n * 调用 MCP 工具的内部实现\n * @param serviceName 服务名称\n * @param toolName 工具名称\n * @param args 工具参数\n * @returns 工具调用结果\n */\n private async callToolInternal(\n serviceName: string,\n toolName: string,\n args: Record<string, unknown>\n ): Promise<ToolCallResult> {\n // 1. 检查服务状态\n await this.validateServiceStatus();\n\n // 2. 通过 HTTP API 调用工具\n try {\n const response = await fetch(`${this.baseUrl}/api/tools/call`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n serviceName,\n toolName,\n args,\n }),\n });\n\n if (!response.ok) {\n let errorMessage = `HTTP ${response.status}: ${response.statusText}`;\n try {\n const errorData = await response.json();\n const detailedMessage =\n errorData?.error?.message ?? errorData?.message;\n if (typeof detailedMessage === \"string\" && detailedMessage.trim()) {\n errorMessage = detailedMessage;\n }\n } catch {\n // 响应体不是 JSON 时,保留默认的 HTTP 错误信息\n }\n throw new Error(errorMessage);\n }\n\n const responseData = await response.json();\n\n if (!responseData.success) {\n throw new Error(responseData.error?.message || \"工具调用失败\");\n }\n\n return responseData.data;\n } catch (error) {\n consola.error(\n `工具调用失败: ${serviceName}/${toolName}`,\n error instanceof Error ? error.message : String(error)\n );\n throw error;\n }\n }\n\n /**\n * 处理工具调用命令\n */\n private async handleCall(\n serviceName: string,\n toolName: string,\n argsString: string\n ): Promise<void> {\n try {\n // 解析参数\n const args = McpCommandHandler.parseJsonArgs(argsString);\n\n // 调用工具\n const result = await this.callToolInternal(serviceName, toolName, args);\n\n console.log(McpCommandHandler.formatToolCallResult(result));\n } catch (error) {\n console.log(`工具调用失败: ${serviceName}/${toolName}`);\n console.error(chalk.red(\"错误:\"), (error as Error).message);\n\n // 提供有用的提示\n const errorMessage = (error as Error).message;\n if (errorMessage.includes(\"服务未启动\")) {\n console.log();\n console.log(chalk.yellow(\"💡 请先启动服务:\"));\n console.log(chalk.gray(\" xiaozhi start # 前台启动\"));\n console.log(chalk.gray(\" xiaozhi start -d # 后台启动\"));\n } else if (errorMessage.includes(\"参数格式错误\")) {\n console.log();\n console.log(chalk.yellow(\"💡 正确格式示例:\"));\n console.log(\n chalk.gray(\n ` xiaozhi mcp call ${serviceName} ${toolName} --args '{\"param\": \"value\"}'`\n )\n );\n }\n\n // 测试环境:通过抛出错误让测试可以捕获并断言\n if (process.env.NODE_ENV === \"test\") {\n throw new Error(\"process.exit called\");\n }\n\n process.exit(1);\n }\n }\n\n /**\n * 列出所有 MCP 服务\n */\n private async handleListInternal(\n options: { tools?: boolean } = {}\n ): Promise<void> {\n const spinner = ora(\"获取 MCP 服务列表...\").start();\n\n try {\n const mcpServers = configManager.getMcpServers();\n const serverNames = Object.keys(mcpServers);\n\n // 检查是否有 customMCP 工具\n const customMCPTools = configManager.getCustomMCPTools();\n const hasCustomMCP = customMCPTools.length > 0;\n\n // 计算总服务数(包括 customMCP)\n const totalServices = serverNames.length + (hasCustomMCP ? 1 : 0);\n\n if (totalServices === 0) {\n spinner.warn(\"未配置任何 MCP 服务或 customMCP 工具\");\n console.log(\n chalk.yellow(\n \"💡 提示: 使用 'xiaozhi config' 命令配置 MCP 服务或在 xiaozhi.config.json 中配置 customMCP 工具\"\n )\n );\n return;\n }\n\n spinner.succeed(\n `找到 ${totalServices} 个 MCP 服务${hasCustomMCP ? \" (包括 customMCP)\" : \"\"}`\n );\n\n if (options.tools) {\n // 显示所有服务的工具列表\n console.log();\n console.log(chalk.bold(\"MCP 服务工具列表:\"));\n console.log();\n\n // 计算所有工具名称的最大长度,用于动态设置列宽\n let maxToolNameWidth = 8; // 默认最小宽度\n const allToolNames: string[] = [];\n\n // 添加标准 MCP 服务的工具名称\n for (const serverName of serverNames) {\n const toolsConfig = configManager.getServerToolsConfig(serverName);\n const toolNames = Object.keys(toolsConfig);\n allToolNames.push(...toolNames);\n }\n\n // 添加 customMCP 工具名称\n if (hasCustomMCP) {\n const customToolNames = customMCPTools.map((tool) => tool.name);\n allToolNames.push(...customToolNames);\n }\n\n // 计算最长工具名称的显示宽度\n for (const toolName of allToolNames) {\n const width = McpCommandHandler.getDisplayWidth(toolName);\n if (width > maxToolNameWidth) {\n maxToolNameWidth = width;\n }\n }\n\n // 确保工具名称列宽度至少为10,最多为30\n maxToolNameWidth = Math.max(10, Math.min(maxToolNameWidth + 2, 30));\n\n // 使用 cli-table3 创建表格\n const table = new Table({\n head: [\n chalk.bold(\"MCP\"),\n chalk.bold(\"工具名称\"),\n chalk.bold(\"状态\"),\n chalk.bold(\"描述\"),\n ],\n colWidths: [15, maxToolNameWidth, 8, 40], // MCP | 工具名称 | 状态 | 描述\n wordWrap: true,\n style: {\n head: [],\n border: [],\n },\n });\n\n // 首先添加 customMCP 工具(如果存在)\n if (hasCustomMCP) {\n for (const customTool of customMCPTools) {\n const description = McpCommandHandler.truncateToWidth(\n customTool.description || \"\",\n 32\n );\n\n table.push([\n \"customMCP\",\n customTool.name,\n chalk.green(\"启用\"), // customMCP 工具默认启用\n description,\n ]);\n }\n }\n\n // 然后添加标准 MCP 服务的工具\n for (const serverName of serverNames) {\n const toolsConfig = configManager.getServerToolsConfig(serverName);\n const toolNames = Object.keys(toolsConfig);\n\n if (toolNames.length === 0) {\n // 服务没有工具时显示提示信息\n table.push([\n chalk.gray(serverName),\n chalk.gray(\"-\"),\n chalk.gray(\"-\"),\n chalk.gray(\"暂未识别到相关工具\"),\n ]);\n } else {\n // 添加服务分隔行(如果表格不为空)\n if (table.length > 0) {\n table.push([{ colSpan: 4, content: \"\" }]);\n }\n\n for (const toolName of toolNames) {\n const toolConfig = toolsConfig[toolName];\n const status = toolConfig.enable\n ? chalk.green(\"启用\")\n : chalk.red(\"禁用\");\n\n // 截断描述到最大32个字符宽度(约16个中文字符)\n const description = McpCommandHandler.truncateToWidth(\n toolConfig.description || \"\",\n 32\n );\n\n // 只显示工具名称,不包含服务名前缀\n table.push([serverName, toolName, status, description]);\n }\n }\n }\n\n console.log(table.toString());\n } else {\n // 只显示服务列表\n console.log();\n console.log(chalk.bold(\"MCP 服务列表:\"));\n console.log();\n\n // 首先显示 customMCP 服务(如果存在)\n if (hasCustomMCP) {\n console.log(`${chalk.cyan(\"•\")} ${chalk.bold(\"customMCP\")}`);\n console.log(` 类型: ${chalk.gray(\"自定义 MCP 工具\")}`);\n console.log(` 配置: ${chalk.gray(\"xiaozhi.config.json\")}`);\n console.log(\n ` 工具: ${chalk.green(customMCPTools.length)} 启用 / ${chalk.yellow(\n customMCPTools.length\n )} 总计`\n );\n console.log();\n }\n\n // 然后显示标准 MCP 服务\n for (const serverName of serverNames) {\n const serverConfig = mcpServers[serverName];\n const toolsConfig = configManager.getServerToolsConfig(serverName);\n const toolCount = Object.keys(toolsConfig).length;\n const enabledCount = Object.values(toolsConfig).filter(\n (t) => t.enable !== false\n ).length;\n\n console.log(`${chalk.cyan(\"•\")} ${chalk.bold(serverName)}`);\n\n // 检查服务类型并显示相应信息\n if (\"url\" in serverConfig) {\n // URL 类型的服务(SSE 或 Streamable HTTP)\n if (\"type\" in serverConfig && serverConfig.type === \"sse\") {\n console.log(` 类型: ${chalk.gray(\"SSE\")}`);\n } else {\n console.log(` 类型: ${chalk.gray(\"Streamable HTTP\")}`);\n }\n console.log(` URL: ${chalk.gray(serverConfig.url)}`);\n } else if (isLocalMCPServerConfig(serverConfig)) {\n // 本地服务\n console.log(\n ` 命令: ${chalk.gray(serverConfig.command)} ${chalk.gray(\n serverConfig.args.join(\" \")\n )}`\n );\n }\n if (toolCount > 0) {\n console.log(\n ` 工具: ${chalk.green(enabledCount)} 启用 / ${chalk.yellow(\n toolCount\n )} 总计`\n );\n } else {\n console.log(` 工具: ${chalk.gray(\"未扫描 (请先启动服务)\")}`);\n }\n console.log();\n }\n }\n\n console.log(chalk.gray(\"💡 提示:\"));\n console.log(\n chalk.gray(\" - 使用 'xiaozhi mcp list --tools' 查看所有工具\")\n );\n console.log(\n chalk.gray(\" - 使用 'xiaozhi mcp <服务名> list' 查看指定服务的工具\")\n );\n console.log(\n chalk.gray(\n \" - 使用 'xiaozhi mcp <服务名> <工具名> enable/disable' 启用/禁用工具\"\n )\n );\n } catch (error) {\n spinner.fail(\"获取 MCP 服务列表失败\");\n console.error(\n chalk.red(\n `错误: ${error instanceof Error ? error.message : String(error)}`\n )\n );\n process.exit(1);\n }\n }\n\n /**\n * 验证服务是否存在\n * @param serverName 服务名称\n * @param spinner Ora 加载动画实例\n * @returns 服务是否存在\n * @private\n */\n private validateServerExists(\n serverName: string,\n spinner: ReturnType<typeof ora>\n ): boolean {\n const mcpServers = configManager.getMcpServers();\n\n if (!mcpServers[serverName]) {\n spinner.fail(`服务 '${serverName}' 不存在`);\n console.log(\n chalk.yellow(\"💡 提示: 使用 'xiaozhi mcp list' 查看所有可用服务\")\n );\n return false;\n }\n\n return true;\n }\n\n /**\n * 列出指定服务的工具\n */\n private async handleServerInternal(serverName: string): Promise<void> {\n const spinner = ora(`获取 ${serverName} 服务的工具列表...`).start();\n\n try {\n if (!this.validateServerExists(serverName, spinner)) {\n return;\n }\n\n const toolsConfig = configManager.getServerToolsConfig(serverName);\n const toolNames = Object.keys(toolsConfig);\n\n if (toolNames.length === 0) {\n spinner.warn(`服务 '${serverName}' 暂无工具信息`);\n console.log(chalk.yellow(\"💡 提示: 请先启动服务以扫描工具列表\"));\n return;\n }\n\n spinner.succeed(`服务 '${serverName}' 共有 ${toolNames.length} 个工具`);\n\n console.log();\n console.log(chalk.bold(`${serverName} 服务工具列表:`));\n console.log();\n\n // 使用 cli-table3 创建表格\n const table = new Table({\n head: [chalk.bold(\"工具名称\"), chalk.bold(\"状态\"), chalk.bold(\"描述\")],\n colWidths: [30, 8, 50], // 工具名称 | 状态 | 描述\n wordWrap: true,\n style: {\n head: [],\n border: [],\n },\n });\n\n for (const toolName of toolNames) {\n const toolConfig = toolsConfig[toolName];\n const status = toolConfig.enable\n ? chalk.green(\"启用\")\n : chalk.red(\"禁用\");\n\n // 截断描述到最大40个字符宽度(约20个中文字符)\n const description = McpCommandHandler.truncateToWidth(\n toolConfig.description || \"\",\n 40\n );\n\n table.push([toolName, status, description]);\n }\n\n console.log(table.toString());\n\n console.log();\n console.log(chalk.gray(\"💡 提示:\"));\n console.log(\n chalk.gray(\n ` - 使用 'xiaozhi mcp ${serverName} <工具名> enable' 启用工具`\n )\n );\n console.log(\n chalk.gray(\n ` - 使用 'xiaozhi mcp ${serverName} <工具名> disable' 禁用工具`\n )\n );\n } catch (error) {\n spinner.fail(\"获取工具列表失败\");\n console.error(\n chalk.red(\n `错误: ${error instanceof Error ? error.message : String(error)}`\n )\n );\n process.exit(1);\n }\n }\n\n /**\n * 启用或禁用工具\n */\n private async handleToolInternal(\n serverName: string,\n toolName: string,\n enabled: boolean\n ): Promise<void> {\n const action = enabled ? \"启用\" : \"禁用\";\n const spinner = ora(`${action}工具 ${serverName}/${toolName}...`).start();\n\n try {\n if (!this.validateServerExists(serverName, spinner)) {\n return;\n }\n\n const toolsConfig = configManager.getServerToolsConfig(serverName);\n\n if (!toolsConfig[toolName]) {\n spinner.fail(`工具 '${toolName}' 在服务 '${serverName}' 中不存在`);\n console.log(\n chalk.yellow(\n `💡 提示: 使用 'xiaozhi mcp ${serverName} list' 查看该服务的所有工具`\n )\n );\n return;\n }\n\n // 更新工具状态\n configManager.setToolEnabled(\n serverName,\n toolName,\n enabled,\n toolsConfig[toolName].description\n );\n\n spinner.succeed(\n `成功${action}工具 ${chalk.cyan(serverName)}/${chalk.cyan(toolName)}`\n );\n\n console.log();\n console.log(chalk.gray(\"💡 提示: 工具状态更改将在下次启动服务时生效\"));\n } catch (error) {\n spinner.fail(`${action}工具失败`);\n console.error(\n chalk.red(\n `错误: ${error instanceof Error ? error.message : String(error)}`\n )\n );\n process.exit(1);\n }\n }\n}\n","/**\n * 端点管理命令处理器\n */\n\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport type { SubCommand } from \"../interfaces/Command\";\nimport { BaseCommandHandler } from \"../interfaces/Command\";\nimport type {\n CommandArguments,\n CommandOptions,\n} from \"../interfaces/CommandTypes\";\nimport type { IDIContainer } from \"../interfaces/Config\";\n\n/**\n * 端点管理命令处理器\n */\nexport class EndpointCommandHandler extends BaseCommandHandler {\n override name = \"endpoint\";\n override description = \"管理 MCP 端点\";\n\n override subcommands: SubCommand[] = [\n {\n name: \"list\",\n description: \"列出所有 MCP 端点\",\n execute: async (args: CommandArguments, options: CommandOptions) => {\n await this.handleList();\n },\n },\n {\n name: \"add\",\n description: \"添加新的 MCP 端点\",\n execute: async (args: CommandArguments, options: CommandOptions) => {\n this.validateArgs(args, 1);\n await this.handleAdd(args[0]);\n },\n },\n {\n name: \"remove\",\n description: \"移除指定的 MCP 端点\",\n execute: async (args: CommandArguments, options: CommandOptions) => {\n this.validateArgs(args, 1);\n await this.handleRemove(args[0]);\n },\n },\n {\n name: \"set\",\n description: \"设置 MCP 端点(可以是单个或多个)\",\n execute: async (args: CommandArguments, options: CommandOptions) => {\n this.validateArgs(args, 1);\n await this.handleSet(args);\n },\n },\n ];\n\n constructor(container: IDIContainer) {\n super(container);\n }\n\n /**\n * 主命令执行(显示帮助)\n */\n override async execute(\n args: CommandArguments,\n options: CommandOptions\n ): Promise<void> {\n console.log(\"MCP 端点管理命令。使用 --help 查看可用的子命令。\");\n }\n\n /**\n * 处理列出端点命令\n */\n protected async handleList(): Promise<void> {\n const spinner = ora(\"读取端点配置...\").start();\n\n try {\n const configManager = this.getService<any>(\"configManager\");\n const endpoints = configManager.getMcpEndpoints();\n spinner.succeed(\"端点列表\");\n\n if (endpoints.length === 0) {\n console.log(chalk.yellow(\"未配置任何 MCP 端点\"));\n } else {\n console.log(chalk.green(`共 ${endpoints.length} 个端点:`));\n endpoints.forEach((ep: string, index: number) => {\n console.log(chalk.gray(` ${index + 1}. ${ep}`));\n });\n }\n } catch (error) {\n spinner.fail(\n `读取端点失败: ${error instanceof Error ? error.message : String(error)}`\n );\n this.handleError(error as Error);\n }\n }\n\n /**\n * 处理添加端点命令\n */\n protected async handleAdd(url: string): Promise<void> {\n const spinner = ora(\"添加端点...\").start();\n\n try {\n const configManager = this.getService<any>(\"configManager\");\n configManager.addMcpEndpoint(url);\n spinner.succeed(`成功添加端点: ${url}`);\n\n const endpoints = configManager.getMcpEndpoints();\n console.log(chalk.gray(`当前共 ${endpoints.length} 个端点`));\n } catch (error) {\n spinner.fail(\n `添加端点失败: ${error instanceof Error ? error.message : String(error)}`\n );\n this.handleError(error as Error);\n }\n }\n\n /**\n * 处理移除端点命令\n */\n protected async handleRemove(url: string): Promise<void> {\n const spinner = ora(\"移除端点...\").start();\n\n try {\n const configManager = this.getService<any>(\"configManager\");\n configManager.removeMcpEndpoint(url);\n spinner.succeed(`成功移除端点: ${url}`);\n\n const endpoints = configManager.getMcpEndpoints();\n console.log(chalk.gray(`当前剩余 ${endpoints.length} 个端点`));\n } catch (error) {\n spinner.fail(\n `移除端点失败: ${error instanceof Error ? error.message : String(error)}`\n );\n this.handleError(error as Error);\n }\n }\n\n /**\n * 处理设置端点命令\n */\n protected async handleSet(urls: string[]): Promise<void> {\n const spinner = ora(\"设置端点...\").start();\n\n try {\n const configManager = this.getService<any>(\"configManager\");\n\n if (urls.length === 1) {\n configManager.updateMcpEndpoint(urls[0]);\n spinner.succeed(`成功设置端点: ${urls[0]}`);\n } else {\n configManager.updateMcpEndpoint(urls);\n spinner.succeed(`成功设置 ${urls.length} 个端点`);\n for (const [index, url] of urls.entries()) {\n console.log(chalk.gray(` ${index + 1}. ${url}`));\n }\n }\n } catch (error) {\n spinner.fail(\n `设置端点失败: ${error instanceof Error ? error.message : String(error)}`\n );\n this.handleError(error as Error);\n }\n }\n}\n","#!/usr/bin/env node\n\n/**\n * CLI 入口文件\n * 负责初始化依赖注入容器和启动命令处理器\n */\n\nimport { Command } from \"commander\";\nimport { DIContainer } from \"./Container\";\nimport { CommandRegistry } from \"./commands/index\";\nimport { ErrorHandler } from \"./errors/ErrorHandlers\";\n\nconst program = new Command();\n\n/**\n * 初始化 CLI 应用\n */\nasync function initializeCLI(): Promise<void> {\n try {\n // 创建依赖注入容器\n const container = DIContainer.create();\n\n // 创建命令注册器\n const commandRegistry = new CommandRegistry(container);\n\n // 注册所有命令\n await commandRegistry.registerCommands(program);\n\n // 配置程序基本信息\n program\n .name(\"xiaozhi\")\n .description(\"小智 MCP 客户端\")\n .helpOption(\"-h, --help\", \"显示帮助信息\");\n\n // 解析命令行参数\n await program.parseAsync(process.argv);\n } catch (error) {\n ErrorHandler.handle(error as Error);\n }\n}\n\ninitializeCLI();\n\nexport { initializeCLI };\n","/**\n * 依赖注入容器\n *\n * 负责管理 CLI 的依赖注入,包括:\n * - 服务注册(工厂、单例、实例)\n * - 服务获取\n * - 单例模式管理\n * - 默认服务配置\n *\n * @module src/cli/Container\n */\n\nimport { configManager } from \"../config\";\nimport { VersionUtils } from \"../utils/version\";\nimport { ErrorHandler } from \"./errors/ErrorHandlers\";\nimport type { IDIContainer } from \"./interfaces/Config\";\nimport { FileUtils } from \"./utils/FileUtils\";\nimport { FormatUtils } from \"./utils/FormatUtils\";\nimport { PathUtils } from \"./utils/PathUtils\";\nimport { PlatformUtils } from \"./utils/PlatformUtils\";\nimport { Validation } from \"./utils/Validation\";\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(\"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 return new DaemonManagerModule.DaemonManagerImpl(processManager);\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 return new ServiceManagerModule.ServiceManagerImpl(\n processManager,\n configManager\n );\n });\n\n container.registerSingleton(\"templateManager\", () => {\n // 使用动态导入的同步版本\n const TemplateManagerModule = require(\"./services/TemplateManager.js\");\n return new TemplateManagerModule.TemplateManagerImpl();\n });\n\n return container;\n }\n}\n\n/**\n * 创建并配置 DI 容器\n */\nexport async function createContainer(): Promise<IDIContainer> {\n return DIContainer.create();\n}\n","/**\n * 全局常量类型声明\n *\n * 这些常量由构建工具在构建时注入\n */\ndeclare global {\n const __VERSION__: string;\n const __APP_NAME__: string;\n}\n\n/**\n * 版本号常量(构建时注入)\n *\n * 如果构建时能读取到 package.json,则为真实版本号\n * 否则为占位符,运行时从 package.json 读取\n */\nexport const VERSION = __VERSION__;\nexport const APP_NAME = __APP_NAME__;\n\n/**\n * 版本管理工具\n *\n * 提供版本号获取、比较、验证等功能\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\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 private static cachedVersionInfo: VersionInfo | null = null;\n\n /**\n * 获取版本号\n *\n * 优先使用构建时注入的版本号常量\n * 如果是占位符,则运行时从 package.json 读取\n */\n static getVersion(): string {\n // 如果版本号是占位符,则运行时读取\n if (VERSION === \"__VERSION__\") {\n return VersionUtils.getRuntimeVersion();\n }\n\n // 使用构建时注入的版本号\n return VERSION;\n }\n\n /**\n * 获取完整版本信息\n */\n static getVersionInfo(): VersionInfo {\n // 如果有缓存,直接返回\n if (VersionUtils.cachedVersionInfo) {\n return VersionUtils.cachedVersionInfo;\n }\n\n // 如果版本号是占位符,则运行时读取\n if (VERSION === \"__VERSION__\") {\n VersionUtils.cachedVersionInfo = VersionUtils.getRuntimeVersionInfo();\n return VersionUtils.cachedVersionInfo;\n }\n\n // 使用构建时注入的版本号\n VersionUtils.cachedVersionInfo = {\n version: VERSION,\n name: APP_NAME === \"__APP_NAME__\" ? undefined : APP_NAME,\n };\n\n return VersionUtils.cachedVersionInfo;\n }\n\n /**\n * 比较版本号\n *\n * @param version1 第一个版本号\n * @param version2 第二个版本号\n * @returns 返回值:1 表示 version1 > version2,-1 表示 version1 < version2,0 表示相等\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 * @param version 版本号字符串\n * @returns 是否为有效的语义化版本号\n */\n static isValidVersion(version: string): boolean {\n // 支持语义化版本号:1.2.3 或 1.2.3-alpha.1 或 1.2.3-beta.1+build.123\n const versionRegex = /^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9.-]+)?(\\+[a-zA-Z0-9.-]+)?$/;\n return versionRegex.test(version);\n }\n\n /**\n * 查找 package.json 文件路径\n *\n * 尝试从多个可能的路径中查找 package.json 文件\n *\n * @returns package.json 文件路径,如果找不到则返回 null\n */\n private static findPackageJsonPath(): string | null {\n const __filename = fileURLToPath(import.meta.url);\n const currentDir = path.dirname(__filename);\n\n const possiblePaths = [\n // 从 src/utils/version.js 到项目根目录的 package.json\n path.join(currentDir, \"..\", \"..\", \"package.json\"),\n // 从 dist/utils/version.js 到项目根目录的 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 return packagePath;\n }\n }\n\n return null;\n }\n\n /**\n * 运行时从 package.json 读取版本号\n */\n private static getRuntimeVersion(): string {\n // 如果有缓存,直接返回\n if (VersionUtils.cachedVersion) {\n return VersionUtils.cachedVersion;\n }\n\n try {\n const packagePath = VersionUtils.findPackageJsonPath();\n if (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 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 * 运行时从 package.json 读取完整版本信息\n */\n private static getRuntimeVersionInfo(): VersionInfo {\n try {\n const packagePath = VersionUtils.findPackageJsonPath();\n if (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 return { version: \"unknown\" };\n } catch (error) {\n console.warn(\"无法读取版本信息:\", error);\n return { version: \"unknown\" };\n }\n }\n\n /**\n * 清除版本缓存\n *\n * 主要用于测试场景\n */\n static clearCache(): void {\n VersionUtils.cachedVersion = null;\n VersionUtils.cachedVersionInfo = null;\n }\n}\n","/**\n * 错误处理器\n */\n\nimport chalk from \"chalk\";\nimport { ERROR_MESSAGES } from \"./ErrorMessages\";\nimport { CLIError } from \"./index\";\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 private static wrapError(error: unknown, context: string): CLIError {\n if (error instanceof CLIError) {\n return error;\n }\n if (error instanceof Error) {\n return new CLIError(\n `${context}失败: ${error.message}`,\n \"OPERATION_FAILED\",\n 1\n );\n }\n return new CLIError(`${context}失败: 未知错误`, \"OPERATION_FAILED\", 1);\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 throw ErrorHandler.wrapError(error, context);\n }\n }\n\n /**\n * 同步操作错误处理包装器\n */\n static handleSync<T>(operation: () => T, context: string): T {\n try {\n return operation();\n } catch (error) {\n throw ErrorHandler.wrapError(error, context);\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 { ERROR_CODES } from \"../Constants\";\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 * 负责创建和管理命令处理器,包括:\n * - 服务命令处理器\n * - 配置命令处理器\n * - 项目命令处理器\n * - MCP 命令处理器\n * - 端点命令处理器\n *\n * @module src/cli/commands/CommandHandlerFactory\n */\n\nimport type {\n CommandHandler,\n ICommandHandlerFactory,\n} from \"../interfaces/Command\";\nimport type { IDIContainer } from \"../interfaces/Config\";\n\n/**\n * 命令处理器工厂实现\n */\nexport class CommandHandlerFactory implements ICommandHandlerFactory {\n constructor(private container: IDIContainer) {}\n\n /**\n * 创建所有命令处理器\n */\n createHandlers(): CommandHandler[] {\n return [\n this.createHandler(\"service\"),\n this.createHandler(\"config\"),\n this.createHandler(\"project\"),\n this.createHandler(\"mcp\"),\n this.createHandler(\"endpoint\"),\n ];\n }\n\n /**\n * 创建指定类型的命令处理器\n */\n createHandler(type: string): CommandHandler {\n switch (type) {\n case \"service\":\n return this.createServiceCommandHandler();\n case \"config\":\n return this.createConfigCommandHandler();\n case \"project\":\n return this.createProjectCommandHandler();\n case \"mcp\":\n return this.createMcpCommandHandler();\n case \"endpoint\":\n return this.createEndpointCommandHandler();\n default:\n throw new Error(`未知的命令处理器类型: ${type}`);\n }\n }\n\n /**\n * 创建服务命令处理器\n */\n private createServiceCommandHandler(): CommandHandler {\n // 动态导入以避免循环依赖\n const { ServiceCommandHandler } = require(\"./ServiceCommandHandler.js\");\n return new ServiceCommandHandler(this.container);\n }\n\n /**\n * 创建配置命令处理器\n */\n private createConfigCommandHandler(): CommandHandler {\n const { ConfigCommandHandler } = require(\"./ConfigCommandHandler.js\");\n return new ConfigCommandHandler(this.container);\n }\n\n /**\n * 创建项目命令处理器\n */\n private createProjectCommandHandler(): CommandHandler {\n const { ProjectCommandHandler } = require(\"./ProjectCommandHandler.js\");\n return new ProjectCommandHandler(this.container);\n }\n\n /**\n * 创建MCP命令处理器\n */\n private createMcpCommandHandler(): CommandHandler {\n const { McpCommandHandler } = require(\"./McpCommandHandler.js\");\n return new McpCommandHandler(this.container);\n }\n\n /**\n * 创建端点命令处理器\n */\n private createEndpointCommandHandler(): CommandHandler {\n const { EndpointCommandHandler } = require(\"./EndpointCommandHandler.js\");\n return new EndpointCommandHandler(this.container);\n }\n}\n","/**\n * 命令注册器\n */\n\nimport type { Command } from \"commander\";\nimport { ErrorHandler } from \"../errors/ErrorHandlers\";\nimport type {\n CommandHandler,\n ICommandHandlerFactory,\n ICommandRegistry,\n} from \"../interfaces/Command\";\nimport type { IDIContainer } from \"../interfaces/Config\";\nimport { CommandHandlerFactory } from \"./CommandHandlerFactory\";\n\n/**\n * 命令注册器实现\n */\nexport class CommandRegistry implements ICommandRegistry {\n private handlers: CommandHandler[] = [];\n private handlerFactory: ICommandHandlerFactory;\n\n constructor(private container: IDIContainer) {\n this.handlerFactory = new CommandHandlerFactory(container);\n }\n\n /**\n * 包装命令处理函数,统一处理错误\n * @param handler 命令处理函数\n * @returns 包装后的处理函数\n */\n private wrapCommandHandler(\n handler: (args: string[], options: Record<string, unknown>) => Promise<void>\n ) {\n return async (...args: unknown[]) => {\n try {\n // Commander.js 传递的最后一个参数是 Command 对象,包含选项值\n const command = args[args.length - 1] as {\n opts: () => Record<string, unknown>;\n };\n const options = command.opts();\n await handler(args.slice(0, -1) as string[], options);\n } catch (error) {\n ErrorHandler.handle(error as Error);\n }\n };\n }\n\n /**\n * 注册所有命令到 Commander 程序\n */\n async registerCommands(program: Command): Promise<void> {\n try {\n // 注册基本命令\n this.registerVersionCommand(program);\n this.registerHelpCommand(program);\n\n // 创建并注册所有功能命令处理器\n const handlers = this.handlerFactory.createHandlers();\n for (const handler of handlers) {\n this.registerHandler(handler);\n this.registerCommand(program, handler);\n }\n\n // 注册向后兼容的顶级服务命令\n this.registerLegacyServiceCommands(program, handlers);\n } catch (error) {\n ErrorHandler.handle(error as Error);\n }\n }\n\n /**\n * 注册命令处理器\n */\n registerHandler(handler: CommandHandler): void {\n this.handlers.push(handler);\n }\n\n /**\n * 注册单个命令\n */\n registerCommand(program: Command, handler: CommandHandler): void {\n // 如果有子命令,创建命令组\n if (handler.subcommands && handler.subcommands.length > 0) {\n const commandGroup = program\n .command(handler.name)\n .description(handler.description);\n\n for (const subcommand of handler.subcommands) {\n let subcommandName = subcommand.name;\n\n // 特殊处理需要参数的子命令\n if (subcommand.name === \"get\") {\n subcommandName = \"get <key>\";\n } else if (subcommand.name === \"set\") {\n subcommandName = \"set <key> <value>\";\n } else if (subcommand.name === \"call\") {\n subcommandName = \"call <serviceName> <toolName>\";\n }\n\n const cmd = commandGroup\n .command(subcommandName)\n .description(subcommand.description);\n\n // 添加子命令选项\n if (subcommand.options) {\n for (const option of subcommand.options) {\n cmd.option(option.flags, option.description, option.defaultValue);\n }\n }\n\n // 设置子命令处理函数\n cmd.action(\n this.wrapCommandHandler(async (args, options) => {\n await subcommand.execute(args, options);\n })\n );\n }\n\n // 设置主命令的默认行为\n commandGroup.action(\n this.wrapCommandHandler(async (args, options) => {\n await handler.execute(args, options);\n })\n );\n } else {\n // 没有子命令,注册为普通命令\n let commandName = handler.name;\n\n // 特殊处理 create 命令,需要接受项目名称参数\n if (handler.name === \"create\") {\n commandName = \"create <projectName>\";\n }\n\n const command = program\n .command(commandName)\n .description(handler.description);\n\n // 添加选项\n if (handler.options) {\n for (const option of handler.options) {\n command.option(option.flags, option.description, option.defaultValue);\n }\n }\n\n // 设置主命令处理函数\n command.action(\n this.wrapCommandHandler(async (args, options) => {\n await handler.execute(args, options);\n })\n );\n }\n }\n\n /**\n * 注册版本命令\n */\n private registerVersionCommand(program: Command): void {\n const versionUtils = this.container.get(\"versionUtils\") as any;\n\n program.version(versionUtils.getVersion(), \"-v, --version\", \"显示版本信息\");\n\n // 注册 --info 选项\n program.option(\"--info\", \"显示详细信息\");\n\n // 注册 --version-info 选项\n program.option(\"--version-info\", \"显示详细版本信息\");\n }\n\n /**\n * 注册帮助命令\n */\n private registerHelpCommand(program: Command): void {\n program.helpOption(\"-h, --help\", \"显示帮助信息\").addHelpText(\n \"after\",\n `\n示例:\n xiaozhi init # 初始化配置文件\n xiaozhi start # 启动服务(包含 Web UI)\n xiaozhi start -d # 后台启动服务\n xiaozhi start -s 3000 # 以 MCP Server 模式启动\n xiaozhi stop # 停止服务\n xiaozhi status # 检查服务状态\n xiaozhi restart -d # 重启服务(后台模式)\n xiaozhi config mcpEndpoint <url> # 设置 MCP 端点\n xiaozhi create my-project # 创建项目\n xiaozhi mcp list # 列出 MCP 服务\n\n更多信息请访问: https://github.com/your-org/xiaozhi-client\n`\n );\n }\n\n /**\n * 注册向后兼容的顶级服务命令\n */\n private registerLegacyServiceCommands(\n program: Command,\n handlers: CommandHandler[]\n ): void {\n // 找到服务命令处理器\n const serviceHandler = handlers.find((h) => h.name === \"service\");\n if (!serviceHandler || !serviceHandler.subcommands) {\n return;\n }\n\n // 为每个服务子命令创建顶级命令\n for (const subcommand of serviceHandler.subcommands) {\n const command = program\n .command(subcommand.name)\n .description(subcommand.description);\n\n // 添加选项\n if (subcommand.options) {\n for (const option of subcommand.options) {\n command.option(option.flags, option.description, option.defaultValue);\n }\n }\n\n // 设置命令处理函数\n command.action(\n this.wrapCommandHandler(async (args, options) => {\n await subcommand.execute(args, options);\n })\n );\n }\n }\n\n /**\n * 注册服务管理命令(稍后实现)\n */\n // private async registerServiceCommands(program: Command): Promise<void> {\n // const serviceCommand = this.container.get('serviceCommand');\n\n // // start 命令\n // program\n // .command('start')\n // .description('启动服务')\n // .option('-d, --daemon', '在后台运行服务')\n // .option('-u, --ui', '同时启动 Web UI 服务')\n // .option('-s, --server [port]', '以 MCP Server 模式启动 (可选指定端口,默认 3000)')\n // .option('--stdio', '以 stdio 模式运行 MCP Server (用于 Cursor 等客户端)')\n // .action(async (options) => {\n // await serviceCommand.start(options);\n // });\n\n // // stop 命令\n // program\n // .command('stop')\n // .description('停止服务')\n // .action(async () => {\n // await serviceCommand.stop();\n // });\n\n // // status 命令\n // program\n // .command('status')\n // .description('检查服务状态')\n // .action(async () => {\n // await serviceCommand.status();\n // });\n\n // // restart 命令\n // program\n // .command('restart')\n // .description('重启服务')\n // .option('-d, --daemon', '在后台运行服务')\n // .option('-u, --ui', '同时启动 Web UI 服务')\n // .action(async (options) => {\n // await serviceCommand.restart(options);\n // });\n\n // // attach 命令\n // program\n // .command('attach')\n // .description('连接到后台服务查看日志')\n // .action(async () => {\n // await serviceCommand.attach();\n // });\n // }\n\n /**\n * 注册配置管理命令(稍后实现)\n */\n // private async registerConfigCommands(program: Command): Promise<void> {\n // const configCommand = this.container.get('configCommand');\n\n // // init 命令\n // program\n // .command('init')\n // .description('初始化配置文件')\n // .option('-f, --format <format>', '配置文件格式 (json, json5, jsonc)', 'json')\n // .action(async (options) => {\n // await configCommand.init(options);\n // });\n\n // // config 命令\n // program\n // .command('config <key> [value]')\n // .description('查看或设置配置')\n // .action(async (key, value) => {\n // await configCommand.manage(key, value);\n // });\n // }\n\n /**\n * 注册项目管理命令(稍后实现)\n */\n // private async registerProjectCommands(program: Command): Promise<void> {\n // const projectCommand = this.container.get('projectCommand');\n\n // // create 命令\n // program\n // .command('create <projectName>')\n // .description('创建项目')\n // .option('-t, --template <templateName>', '使用指定模板创建项目')\n // .action(async (projectName, options) => {\n // await projectCommand.create(projectName, options);\n // });\n // }\n\n /**\n * 注册 MCP 管理命令(稍后实现)\n */\n // private async registerMcpCommands(program: Command): Promise<void> {\n // const mcpCommand = this.container.get('mcpCommand');\n\n // // mcp 命令组\n // const mcpGroup = program.command('mcp').description('MCP 服务和工具管理');\n\n // // mcp list 命令\n // mcpGroup\n // .command('list')\n // .description('列出 MCP 服务')\n // .option('--tools', '显示所有服务的工具列表')\n // .action(async (options) => {\n // await mcpCommand.list(options);\n // });\n\n // // mcp server 命令\n // mcpGroup\n // .command('server <serverName>')\n // .description('管理指定的 MCP 服务')\n // .action(async (serverName) => {\n // await mcpCommand.server(serverName);\n // });\n\n // // mcp tool 命令\n // mcpGroup\n // .command('tool <serverName> <toolName> <action>')\n // .description('管理 MCP 工具 (enable/disable)')\n // .action(async (serverName, toolName, action) => {\n // await mcpCommand.tool(serverName, toolName, action);\n // });\n // }\n}\n"],"mappings":"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","names":["existsSync","commentJson","path","tool","resolve","TypeFieldNormalizer","normalizeTypeField","init_manager","init_manager","dirname","resolve","copyFileSync","existsSync","path","dirname","resolve","fileURLToPath","__dirname","fs","path","path","tmpdir","path","fileURLToPath","resolve","fs","resolve","path","consola","configManager","resolve","spawn","fs","fs","path","consola","path","chalk","configManager","path","chalk","ora","resolve","chalk","consola","ora","chalk","ora","configManager","path","fileURLToPath","fileURLToPath","path","configManager","ServiceCommandHandler","ConfigCommandHandler","ProjectCommandHandler","McpCommandHandler","EndpointCommandHandler","program"]}
1
+ {"version":3,"sources":["../../src/config/json5-adapter.ts","../../src/config/resolver.ts","../../src/config/manager.ts","../../src/mcp-core/types.ts","../../src/mcp-core/transport-factory.ts","../../src/mcp-core/utils/type-normalizer.ts","../../src/mcp-core/utils/validators.ts","../../src/mcp-core/utils/index.ts","../../src/mcp-core/connection.ts","../../src/mcp-core/manager.ts","../../src/mcp-core/index.ts","../../src/config/adapter.ts","../../src/config/initializer.ts","../../src/config/index.ts","../../src/cli/Constants.ts","../../src/cli/errors/index.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/services/ProcessManager.ts","../../src/cli/services/DaemonManager.ts","../../src/cli/services/ServiceManager.ts","../../src/cli/services/TemplateManager.ts","../../src/cli/interfaces/Command.ts","../../src/cli/commands/ServiceCommandHandler.ts","../../src/cli/commands/ConfigCommandHandler.ts","../../src/cli/commands/ProjectCommandHandler.ts","../../src/cli/interfaces/CommandTypes.ts","../../src/cli/commands/McpCommandHandler.ts","../../src/cli/commands/EndpointCommandHandler.ts","../../src/cli/index.ts","../../src/cli/Container.ts","../../src/utils/version.ts","../../src/cli/errors/ErrorHandlers.ts","../../src/cli/errors/ErrorMessages.ts","../../src/cli/commands/CommandHandlerFactory.ts","../../src/cli/commands/index.ts"],"sourcesContent":["/**\n * JSON5 注释保留适配器\n * 使用 comment-json 实现 JSON5/JSONC 注释保留功能\n *\n * 注意:为了使用 comment-json 保留注释,JSON5 配置文件的键需要带引号。\n * 这与 JSON5 标准语法允许不带引号的键略有不同,但能实现注释保留功能。\n */\nimport * as commentJson from \"comment-json\";\n\n/**\n * JSON5 写入器适配器接口\n * 保持与 json5-writer 兼容的 API\n */\nexport interface Json5WriterAdapter {\n write(data: unknown): void;\n toSource(): string;\n}\n\n/**\n * 创建 JSON5 写入器适配器\n * @param content 原始 JSON5 内容字符串\n * @returns Json5WriterAdapter 实例\n */\nexport function createJson5Writer(content: string): Json5WriterAdapter {\n // 使用 comment-json 解析原始内容\n // comment-json 会保留注释信息在返回的对象中\n const parsedData = commentJson.parse(content) as Record<string, unknown>;\n\n return {\n write(data: unknown): void {\n // 通过 Object.assign 合并新数据\n if (parsedData && typeof parsedData === \"object\" && data) {\n Object.assign(parsedData, data);\n }\n },\n\n toSource(): string {\n // 使用 comment-json 序列化,保留注释和格式\n return commentJson.stringify(parsedData, null, 2);\n },\n };\n}\n\n/**\n * 解析 JSON5 内容(带注释保留)\n * @param content JSON5 内容字符串\n * @returns 解析后的对象\n */\nexport function parseJson5(content: string): unknown {\n // 使用 comment-json 解析,支持注释保留\n return commentJson.parse(content);\n}\n","/**\n * 配置解析器\n * 负责按优先级查找配置文件\n */\n\nimport { existsSync } from \"node:fs\";\nimport path from \"node:path\";\n\n/**\n * 配置解析器类\n * 实现配置文件查找优先级逻辑\n */\nexport class ConfigResolver {\n /**\n * 按优先级解析配置文件路径\n *\n * 优先级顺序:\n * 1. 环境变量 XIAOZHI_CONFIG_DIR 指定的目录\n * 2. 当前工作目录\n * 3. 用户家目录/.xiaozhi-client/\n *\n * @returns 找到的配置文件路径,如果都不存在则返回 null\n */\n static resolveConfigPath(): string | null {\n // 优先级 1: 环境变量指定(向后兼容)\n if (process.env.XIAOZHI_CONFIG_DIR) {\n const configPath = ConfigResolver.findConfigInDir(\n process.env.XIAOZHI_CONFIG_DIR\n );\n if (configPath) {\n return configPath;\n }\n }\n\n // 优先级 2: 当前目录\n const currentDirConfig = ConfigResolver.findConfigInDir(process.cwd());\n if (currentDirConfig) {\n return currentDirConfig;\n }\n\n // 优先级 3: 用户家目录/.xiaozhi-client/\n const homeDir = process.env.HOME || process.env.USERPROFILE;\n if (homeDir) {\n const xiaozhiClientDir = path.join(homeDir, \".xiaozhi-client\");\n const homeDirConfig = ConfigResolver.findConfigInDir(xiaozhiClientDir);\n if (homeDirConfig) {\n return homeDirConfig;\n }\n }\n\n return null;\n }\n\n /**\n * 在指定目录中查找配置文件\n *\n * 按优先级查找:xiaozhi.config.json5 > xiaozhi.config.jsonc > xiaozhi.config.json\n *\n * @param dir - 要搜索的目录\n * @returns 找到的配置文件路径,如果不存在则返回 null\n */\n static findConfigInDir(dir: string): string | null {\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 = path.join(dir, fileName);\n if (existsSync(filePath)) {\n return filePath;\n }\n }\n\n return null;\n }\n\n /**\n * 获取默认配置目录路径\n *\n * @returns 用户家目录下的 .xiaozhi-client 目录路径,如果无法获取家目录则返回 null\n */\n static getDefaultConfigDir(): string | null {\n const homeDir = process.env.HOME || process.env.USERPROFILE;\n if (!homeDir) {\n return null;\n }\n return path.join(homeDir, \".xiaozhi-client\");\n }\n}\n","/**\n * 配置管理器\n *\n * 核心配置管理模块,负责:\n * - 配置文件的读取和解析(支持 JSON、JSON5、JSONC 格式)\n * - 配置验证和类型检查\n * - 配置更新和持久化\n * - 配置变更事件通知\n * - 配置文件路径解析\n *\n * @example\n * ```typescript\n * import { configManager } from '../config';\n *\n * // 获取配置\n * const config = configManager.getConfig();\n *\n * // 更新配置\n * configManager.updateConfig({ mcpEndpoint: 'wss://...' });\n *\n * // 监听配置更新事件\n * configManager.on('config:updated', (payload) => {\n * // payload 示例结构:\n * // {\n * // type: 'endpoint' | 'customMCP' | 'config' | 'serverTools' | 'connection' | 'modelscope' | 'webui' | 'platform';\n * // timestamp: Date;\n * // serviceName?: string;\n * // platformName?: string;\n * // }\n * console.log('配置已更新事件:', payload);\n *\n * // 如果需要获取最新的完整配置对象,可在回调中调用 getConfig()\n * const latestConfig = configManager.getConfig();\n * console.log('最新配置对象:', latestConfig);\n * });\n * ```\n */\nimport { 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 { createJson5Writer, parseJson5 } from \"./json5-adapter.js\";\nimport { ConfigResolver } from \"./resolver.js\";\n\n// 在 ESM 中,需要从 import.meta.url 获取当前文件目录\n// 迁移后:src/config/manager.ts → __dirname = src/config/\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 headers?: Record<string, string>;\n}\n\n// HTTP MCP 服务配置\nexport interface HTTPMCPServerConfig {\n type?: \"http\" | \"streamable-http\"; // 可选,默认就是 http\n url: string;\n headers?: Record<string, string>;\n}\n\n// 向后兼容的别名\n/** @deprecated 使用 HTTPMCPServerConfig 代替 */\nexport type StreamableHTTPMCPServerConfig = HTTPMCPServerConfig;\n\n// 统一的 MCP 服务配置\nexport type MCPServerConfig =\n | LocalMCPServerConfig\n | SSEMCPServerConfig\n | HTTPMCPServerConfig;\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\n// 工具调用日志配置接口\n// TTS 配置接口\nexport interface TTSConfig {\n appid?: string; // 应用 ID\n accessToken?: string; // 访问令牌\n voice_type?: string; // 声音类型\n encoding?: string; // 编码格式(默认 wav)\n cluster?: string; // 集群类型\n endpoint?: string; // WebSocket 端点\n}\n\n// ASR 配置接口\nexport interface ASRConfig {\n appid?: string; // 应用 ID\n accessToken?: string; // 访问令牌\n cluster?: string; // 集群类型(默认:volcengine_streaming_common)\n wsUrl?: string; // WebSocket 端点\n}\n\n// LLM 配置接口\nexport interface LLMConfig {\n model: string; // 模型名称\n apiKey: string; // API 密钥\n baseURL: string; // API 基础地址\n prompt?: string; // 自定义系统提示词(支持纯字符串或文件路径)\n}\n\nexport interface ToolCallLogConfig {\n maxRecords?: number; // 最大记录条数,默认 100\n logFilePath?: string; // 自定义日志文件路径(可选)\n}\n\n// CustomMCP 相关接口定义\n\n// 代理处理器配置\nexport interface ProxyHandlerConfig {\n type: \"proxy\";\n platform: \"coze\" | \"openai\" | \"anthropic\" | \"custom\";\n config: {\n // Coze 平台配置\n workflow_id?: string;\n bot_id?: string;\n api_key?: string;\n base_url?: string;\n // 通用配置\n timeout?: number;\n retry_count?: number;\n retry_delay?: number;\n headers?: Record<string, unknown>;\n params?: Record<string, unknown>;\n };\n}\n\n// HTTP 处理器配置\nexport interface HttpHandlerConfig {\n type: \"http\";\n url: string;\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n headers?: Record<string, string>;\n timeout?: number;\n retry_count?: number;\n retry_delay?: number;\n auth?: {\n type: \"bearer\" | \"basic\" | \"api_key\";\n token?: string;\n username?: string;\n password?: string;\n api_key?: string;\n api_key_header?: string;\n };\n body_template?: string; // 支持模板变量替换\n response_mapping?: {\n success_path?: string; // JSONPath 表达式\n error_path?: string;\n data_path?: string;\n };\n}\n\n// 函数处理器配置\nexport interface FunctionHandlerConfig {\n type: \"function\";\n module: string; // 模块路径\n function: string; // 函数名\n timeout?: number;\n context?: Record<string, unknown>; // 函数执行上下文\n}\n\n// 脚本处理器配置\nexport interface ScriptHandlerConfig {\n type: \"script\";\n script: string; // 脚本内容或文件路径\n interpreter?: \"node\" | \"python\" | \"bash\";\n timeout?: number;\n env?: Record<string, string>; // 环境变量\n}\n\n// 链式处理器配置\nexport interface ChainHandlerConfig {\n type: \"chain\";\n tools: string[]; // 要链式调用的工具名称\n mode: \"sequential\" | \"parallel\"; // 执行模式\n error_handling: \"stop\" | \"continue\" | \"retry\"; // 错误处理策略\n}\n\n// MCP 处理器配置(用于同步的工具)\nexport interface MCPHandlerConfig {\n type: \"mcp\";\n config: {\n serviceName: string;\n toolName: string;\n };\n}\n\nexport type HandlerConfig =\n | ProxyHandlerConfig\n | HttpHandlerConfig\n | FunctionHandlerConfig\n | ScriptHandlerConfig\n | ChainHandlerConfig\n | MCPHandlerConfig;\n\n// CustomMCP 工具接口\n// TODO: 注意:此定义应与 @/types 中的 CustomMCPToolConfig 保持一致\n// 未来将迁移到从 shared-types 导入\nexport interface CustomMCPTool {\n // 确保必填字段\n name: string;\n description: string;\n inputSchema: Record<string, unknown>;\n handler: HandlerConfig;\n\n // 使用统计信息(可选)\n stats?: {\n usageCount?: number; // 工具使用次数\n lastUsedTime?: string; // 最后使用时间(ISO 8601格式)\n };\n}\n\n// CustomMCP 配置接口\nexport interface CustomMCPConfig {\n tools: CustomMCPTool[];\n}\n\n// Web 服务器实例接口(用于配置更新通知)\nexport interface WebServerInstance {\n broadcastConfigUpdate(config: AppConfig): void;\n}\n\nexport interface PlatformsConfig {\n [platformName: string]: PlatformConfig;\n}\n\nexport interface PlatformConfig {\n token?: string;\n}\n\n/**\n * 扣子平台配置接口\n */\nexport interface CozePlatformConfig extends PlatformConfig {\n /** 扣子 API Token */\n token: string;\n}\n\nexport interface AppConfig {\n mcpEndpoint: string | string[];\n mcpServers: Record<string, MCPServerConfig>;\n mcpServerConfig?: Record<string, MCPServerToolsConfig>;\n customMCP?: CustomMCPConfig; // 新增 customMCP 配置支持\n connection?: ConnectionConfig; // 连接配置(可选,用于向后兼容)\n modelscope?: ModelScopeConfig; // ModelScope 配置(可选)\n webUI?: WebUIConfig; // Web UI 配置(可选)\n platforms?: PlatformsConfig; // 平台配置(可选)\n toolCallLog?: ToolCallLogConfig; // 工具调用日志配置(可选)\n tts?: TTSConfig; // TTS 配置(可选)\n asr?: ASRConfig; // ASR 配置(可选)\n llm?: LLMConfig; // LLM 配置(可选)\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: {\n write(data: unknown): void;\n toSource(): string;\n } | null = null; // json5-writer 实例,用于保留 JSON5 注释\n\n // 统计更新并发控制\n private statsUpdateLocks: Map<string, Promise<void>> = new Map();\n private statsUpdateLockTimeouts: Map<string, NodeJS.Timeout> = new Map();\n private readonly STATS_UPDATE_TIMEOUT = 5000; // 5秒超时\n\n // 事件回调(用于解耦 EventBus 依赖)\n private eventCallbacks: Map<string, Array<(data: unknown) => void>> =\n new Map();\n\n private constructor() {\n // 使用模板目录中的默认配置文件\n // 在不同环境中尝试不同的路径\n //\n // 迁移后 __dirname = src/config/(开发环境)或 dist/config/(构建后)\n // 项目根目录的 templates/default/ 在 __dirname 的上两级\n const possiblePaths = [\n // src/config/ 或 dist/config/ → 项目根 templates/default/xiaozhi.config.json\n resolve(\n __dirname,\n \"..\",\n \"..\",\n \"templates\",\n \"default\",\n \"xiaozhi.config.json\"\n ),\n // 从 CWD 查找(兼容各种启动场景)\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 */\n public on(eventName: string, callback: (data: unknown) => void): void {\n if (!this.eventCallbacks.has(eventName)) {\n this.eventCallbacks.set(eventName, []);\n }\n this.eventCallbacks.get(eventName)?.push(callback);\n }\n\n /**\n * 发射事件\n */\n private emitEvent(eventName: string, data: unknown): void {\n const callbacks = this.eventCallbacks.get(eventName);\n if (callbacks) {\n for (const callback of callbacks) {\n try {\n callback(data);\n } catch (error) {\n console.error(`事件回调执行失败 [${eventName}]:`, error);\n }\n }\n }\n }\n\n /**\n * 获取配置文件路径(动态计算)\n * 支持多种配置文件格式:json5 > jsonc > json\n *\n * 查找优先级:\n * 1. 环境变量 XIAOZHI_CONFIG_DIR 指定的目录\n * 2. 当前工作目录\n * 3. 用户家目录/.xiaozhi-client/\n */\n private getConfigFilePath(): string {\n // 优先使用 ConfigResolver 解析配置路径\n const resolvedPath = ConfigResolver.resolveConfigPath();\n\n if (resolvedPath) {\n return resolvedPath;\n }\n\n // 如果都找不到,返回用户家目录的默认路径\n const defaultDir = ConfigResolver.getDefaultConfigDir();\n if (defaultDir) {\n return resolve(defaultDir, \"xiaozhi.config.json\");\n }\n\n // 最后回退到当前目录\n const configDir = process.env.XIAOZHI_CONFIG_DIR || process.cwd();\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 * 按优先级检查配置文件是否存在:\n * 1. 环境变量 XIAOZHI_CONFIG_DIR 指定的目录\n * 2. 当前工作目录\n * 3. 用户家目录/.xiaozhi-client/\n */\n public configExists(): boolean {\n return ConfigResolver.resolveConfigPath() !== null;\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 const error = new Error(\n \"配置文件不存在,请先运行 xiaozhi init 初始化配置\"\n );\n this.emitEvent(\"config:error\", {\n error,\n operation: \"loadConfig\",\n });\n throw error;\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 解析配置对象,同时使用适配器保留注释信息\n config = parseJson5(configData) as AppConfig;\n // 创建适配器实例用于后续保存时保留注释\n this.json5Writer = createJson5Writer(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 // 发射配置错误事件\n this.emitEvent(\"config:error\", {\n error: error instanceof Error ? error : new Error(String(error)),\n operation: \"loadConfig\",\n });\n if (error instanceof SyntaxError) {\n throw new Error(`配置文件格式错误: ${error.message}`);\n }\n throw error;\n }\n }\n\n /**\n * 验证配置文件结构\n */\n public 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 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 // 更详细的验证应该由调用方完成\n }\n }\n\n /**\n * 获取配置(只读)\n * 使用缓存机制避免频繁的文件 I/O 操作\n */\n public getConfig(): Readonly<AppConfig> {\n // 使用缓存,避免每次都重新加载文件\n if (!this.config) {\n this.config = this.loadConfig();\n }\n\n // 使用 structuredClone 进行更高效的深拷贝\n // 如果不支持则降级到 JSON.parse(JSON.stringify())\n return structuredClone(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 for (const ep of endpoint) {\n if (!ep || typeof ep !== \"string\") {\n throw new Error(\"MCP 端点数组中的每个元素必须是非空字符串\");\n }\n }\n }\n\n const config = this.getMutableConfig();\n config.mcpEndpoint = endpoint;\n this.saveConfig(config);\n\n // 发射配置更新事件\n this.emitEvent(\"config:updated\", {\n type: \"endpoint\",\n timestamp: new Date(),\n });\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 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 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.getMutableConfig();\n\n // 检查服务是否存在\n if (!config.mcpServers[serverName]) {\n throw new Error(`服务 ${serverName} 不存在`);\n }\n\n // 1. 清理 mcpServers 字段(现有逻辑)\n delete config.mcpServers[serverName];\n\n // 2. 清理 mcpServerConfig 字段(复用现有方法)\n if (config.mcpServerConfig?.[serverName]) {\n delete config.mcpServerConfig[serverName];\n }\n\n // 3. 清理 customMCP 字段中相关的工具定义\n if (config.customMCP?.tools) {\n // 查找与该服务相关的 CustomMCP 工具\n const relatedTools = config.customMCP.tools.filter(\n (tool) =>\n tool.handler?.type === \"mcp\" &&\n tool.handler.config?.serviceName === serverName\n );\n\n // 移除相关工具\n for (const tool of relatedTools) {\n const toolIndex = config.customMCP.tools.findIndex(\n (t) => t.name === tool.name\n );\n if (toolIndex !== -1) {\n config.customMCP.tools.splice(toolIndex, 1);\n }\n }\n\n // 如果没有工具了,可以清理整个 customMCP 对象\n if (config.customMCP.tools.length === 0) {\n config.customMCP = undefined;\n }\n }\n\n // 4. 保存配置(单次原子性操作)\n this.saveConfig(config);\n\n // 5. 发射配置更新事件,通知 CustomMCPHandler 重新初始化\n this.emitEvent(\"config:updated\", {\n type: \"customMCP\",\n timestamp: new Date(),\n });\n\n // 记录清理结果\n console.log(\"成功移除 MCP 服务\", { serverName });\n }\n\n /**\n * 批量更新配置(由 Handler 调用)\n */\n public updateConfig(newConfig: Partial<AppConfig>): void {\n const config = this.getMutableConfig();\n\n // 更新 MCP 端点\n if (newConfig.mcpEndpoint !== undefined) {\n config.mcpEndpoint = newConfig.mcpEndpoint;\n }\n\n // 更新 MCP 服务\n if (newConfig.mcpServers) {\n const currentServers = { ...config.mcpServers };\n for (const [name, serverConfig] of Object.entries(newConfig.mcpServers)) {\n config.mcpServers[name] = serverConfig;\n }\n // 删除不存在的服务\n for (const name of Object.keys(currentServers)) {\n if (!(name in newConfig.mcpServers)) {\n delete config.mcpServers[name];\n // 同时清理工具配置\n if (config.mcpServerConfig?.[name]) {\n delete config.mcpServerConfig[name];\n }\n }\n }\n }\n\n // 更新连接配置\n if (newConfig.connection) {\n if (!config.connection) {\n config.connection = {};\n }\n Object.assign(config.connection, newConfig.connection);\n }\n\n // 更新 ModelScope 配置\n if (newConfig.modelscope) {\n if (!config.modelscope) {\n config.modelscope = {};\n }\n Object.assign(config.modelscope, newConfig.modelscope);\n }\n\n // 更新 Web UI 配置\n if (newConfig.webUI) {\n if (!config.webUI) {\n config.webUI = {};\n }\n Object.assign(config.webUI, newConfig.webUI);\n }\n\n // 更新服务工具配置\n if (newConfig.mcpServerConfig) {\n for (const [serverName, toolsConfig] of Object.entries(\n newConfig.mcpServerConfig\n )) {\n if (config.mcpServerConfig?.[serverName]) {\n config.mcpServerConfig[serverName] = toolsConfig;\n }\n }\n }\n\n // 更新平台配置\n if (newConfig.platforms) {\n for (const [platformName, platformConfig] of Object.entries(\n newConfig.platforms\n )) {\n if (!config.platforms) {\n config.platforms = {};\n }\n config.platforms[platformName] = platformConfig;\n }\n }\n\n // 更新 ASR 配置(使用 \"asr\" in newConfig 检测字段是否存在,支持清空配置)\n if (\"asr\" in newConfig) {\n config.asr = newConfig.asr;\n }\n\n // 更新 TTS 配置\n if (\"tts\" in newConfig) {\n config.tts = newConfig.tts;\n }\n\n // 更新 LLM 配置\n if (\"llm\" in newConfig) {\n config.llm = newConfig.llm;\n }\n\n this.saveConfig(config);\n\n // 发射配置更新事件\n this.emitEvent(\"config:updated\", {\n type: \"config\",\n timestamp: new Date(),\n });\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 this.emitEvent(\"config:updated\", {\n type: \"serverTools\",\n serviceName: serverName,\n timestamp: new Date(),\n });\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 console.log(\"已清理无效的服务工具配置\", {\n count: invalidServerNames.length,\n serverNames: invalidServerNames,\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 格式,使用适配器保留注释\n try {\n if (this.json5Writer) {\n // 使用适配器更新配置并保留注释\n this.json5Writer.write(config);\n configContent = this.json5Writer.toSource();\n } else {\n // 如果没有适配器实例,回退到 comment-json 序列化\n console.warn(\"没有 JSON5 适配器实例,使用 comment-json 序列化\");\n configContent = commentJson.stringify(config, null, 2);\n }\n } catch (json5Error) {\n // 如果适配器序列化失败,回退到 comment-json 序列化\n console.warn(\n \"使用 JSON5 适配器保存失败,回退到 comment-json 序列化:\",\n json5Error\n );\n configContent = commentJson.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 console.log(\"配置保存成功\");\n\n // 通知 Web 界面配置已更新(如果 Web 服务器正在运行)\n this.notifyConfigUpdate(config);\n } catch (error) {\n // 发射配置错误事件\n this.emitEvent(\"config:error\", {\n error: error instanceof Error ? error : new Error(String(error)),\n operation: \"saveConfig\",\n });\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 this.emitEvent(\"config:updated\", {\n type: \"connection\",\n timestamp: new Date(),\n });\n }\n\n /**\n * 更新工具使用统计信息(MCP 服务工具)\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\n /**\n * 更新工具使用统计信息(CustomMCP 工具)\n * @param toolName 工具名称(customMCP 工具名称)\n * @param incrementUsageCount 是否增加使用计数,默认为 true\n */\n public async updateToolUsageStats(\n toolName: string,\n incrementUsageCount?: boolean\n ): Promise<void>;\n\n /**\n * 更新工具使用统计信息的实现\n */\n public async updateToolUsageStats(\n arg1: string,\n arg2: string | boolean | undefined,\n arg3?: string\n ): Promise<void> {\n try {\n // 判断参数类型来区分不同的重载\n if (typeof arg2 === \"string\" && arg3) {\n // 三个参数的情况:updateToolUsageStats(serverName, toolName, callTime)\n const serverName = arg1;\n const toolName = arg2;\n const callTime = arg3;\n\n // 双写机制:同时更新 mcpServerConfig 和 customMCP 中的统计信息\n await Promise.all([\n this._updateMCPServerToolStats(serverName, toolName, callTime),\n this.updateCustomMCPToolStats(serverName, toolName, callTime),\n ]);\n\n console.log(\"工具使用统计已更新\", { serverName, toolName });\n } else {\n // 两个参数的情况:updateToolUsageStats(toolName, incrementUsageCount)\n const toolName = arg1;\n const incrementUsageCount = arg2 as boolean;\n const callTime = new Date().toISOString();\n\n // 只更新 customMCP 中的统计信息\n await this.updateCustomMCPToolStats(\n toolName,\n callTime,\n incrementUsageCount\n );\n\n console.log(\"CustomMCP 工具使用统计已更新\", { toolName });\n }\n } catch (error) {\n // 错误不应该影响主要的工具调用流程\n if (typeof arg2 === \"string\" && arg3) {\n const serverName = arg1;\n const toolName = arg2;\n console.error(\"更新工具使用统计失败\", { serverName, toolName, error });\n } else {\n const toolName = arg1;\n console.error(\"更新 CustomMCP 工具使用统计失败\", { toolName, error });\n }\n }\n }\n\n /**\n * 更新 MCP 服务工具统计信息(重载方法)\n * @param serviceName 服务名称\n * @param toolName 工具名称\n * @param callTime 调用时间(ISO 8601 格式)\n * @param incrementUsageCount 是否增加使用计数,默认为 true\n */\n public async updateMCPServerToolStats(\n serviceName: string,\n toolName: string,\n callTime: string,\n incrementUsageCount = true\n ): Promise<void> {\n await this._updateMCPServerToolStats(\n serviceName,\n toolName,\n callTime,\n incrementUsageCount\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 this.emitEvent(\"config:updated\", {\n type: \"modelscope\",\n timestamp: new Date(),\n });\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 * 获取 customMCP 配置\n */\n public getCustomMCPConfig(): CustomMCPConfig | null {\n const config = this.getConfig();\n return config.customMCP || null;\n }\n\n /**\n * 获取 customMCP 工具列表\n */\n public getCustomMCPTools(): CustomMCPTool[] {\n const customMCPConfig = this.getCustomMCPConfig();\n if (!customMCPConfig || !customMCPConfig.tools) {\n return [];\n }\n\n return customMCPConfig.tools;\n }\n\n /**\n * 验证 customMCP 工具配置\n */\n public validateCustomMCPTools(tools: CustomMCPTool[]): boolean {\n if (!Array.isArray(tools)) {\n return false;\n }\n\n for (const tool of tools) {\n // 检查必需字段\n if (!tool.name || typeof tool.name !== \"string\") {\n console.warn(\"CustomMCP 工具缺少有效的 name 字段\", { tool });\n return false;\n }\n\n if (!tool.description || typeof tool.description !== \"string\") {\n console.warn(\"CustomMCP 工具缺少有效的 description 字段\", {\n toolName: tool.name,\n });\n return false;\n }\n\n if (!tool.inputSchema || typeof tool.inputSchema !== \"object\") {\n console.warn(\"CustomMCP 工具缺少有效的 inputSchema 字段\", {\n toolName: tool.name,\n });\n return false;\n }\n\n if (!tool.handler || typeof tool.handler !== \"object\") {\n console.warn(\"CustomMCP 工具缺少有效的 handler 字段\", {\n toolName: tool.name,\n });\n return false;\n }\n\n // 检查 handler 类型\n if (\n ![\"proxy\", \"function\", \"http\", \"script\", \"chain\", \"mcp\"].includes(\n tool.handler.type\n )\n ) {\n console.warn(\"CustomMCP 工具的 handler.type 类型无效\", {\n toolName: tool.name,\n type: tool.handler.type,\n });\n return false;\n }\n\n // 根据处理器类型进行特定验证\n if (!this.validateHandlerConfig(tool.name, tool.handler)) {\n return false;\n }\n }\n\n return true;\n }\n\n /**\n * 验证处理器配置\n */\n private validateHandlerConfig(\n toolName: string,\n handler: HandlerConfig\n ): boolean {\n switch (handler.type) {\n case \"proxy\":\n return this.validateProxyHandler(toolName, handler);\n case \"http\":\n return this.validateHttpHandler(toolName, handler);\n case \"function\":\n return this.validateFunctionHandler(toolName, handler);\n case \"script\":\n return this.validateScriptHandler(toolName, handler);\n case \"chain\":\n return this.validateChainHandler(toolName, handler);\n case \"mcp\":\n return this.validateMCPHandler(toolName, handler);\n default:\n console.warn(\"CustomMCP 工具使用了未知的处理器类型\", {\n toolName,\n handlerType: (handler as HandlerConfig).type,\n });\n return false;\n }\n }\n\n /**\n * 验证代理处理器配置\n */\n private validateProxyHandler(\n toolName: string,\n handler: ProxyHandlerConfig\n ): boolean {\n if (!handler.platform) {\n console.warn(\"CustomMCP 工具的 proxy 处理器缺少 platform 字段\", {\n toolName,\n });\n return false;\n }\n\n if (![\"coze\", \"openai\", \"anthropic\", \"custom\"].includes(handler.platform)) {\n console.warn(\"CustomMCP 工具的 proxy 处理器使用了不支持的平台\", {\n toolName,\n platform: handler.platform,\n });\n return false;\n }\n\n if (!handler.config || typeof handler.config !== \"object\") {\n console.warn(\"CustomMCP 工具的 proxy 处理器缺少 config 字段\", {\n toolName,\n });\n return false;\n }\n\n // Coze 平台特定验证\n if (handler.platform === \"coze\") {\n if (!handler.config.workflow_id && !handler.config.bot_id) {\n console.warn(\n \"CustomMCP 工具的 Coze 处理器必须提供 workflow_id 或 bot_id\",\n { toolName }\n );\n return false;\n }\n }\n\n return true;\n }\n\n /**\n * 验证 HTTP 处理器配置\n */\n private validateHttpHandler(\n toolName: string,\n handler: HttpHandlerConfig\n ): boolean {\n if (!handler.url || typeof handler.url !== \"string\") {\n console.warn(\"CustomMCP 工具的 http 处理器缺少有效的 url 字段\", {\n toolName,\n });\n return false;\n }\n\n try {\n new URL(handler.url);\n } catch {\n console.warn(\"CustomMCP 工具的 http 处理器 url 格式无效\", {\n toolName,\n url: handler.url,\n });\n return false;\n }\n\n if (\n handler.method &&\n ![\"GET\", \"POST\", \"PUT\", \"DELETE\", \"PATCH\"].includes(handler.method)\n ) {\n console.warn(\"CustomMCP 工具的 http 处理器使用了不支持的 HTTP 方法\", {\n toolName,\n method: handler.method,\n });\n return false;\n }\n\n return true;\n }\n\n /**\n * 验证函数处理器配置\n */\n private validateFunctionHandler(\n toolName: string,\n handler: FunctionHandlerConfig\n ): boolean {\n if (!handler.module || typeof handler.module !== \"string\") {\n console.warn(\"CustomMCP 工具的 function 处理器缺少有效的 module 字段\", {\n toolName,\n });\n return false;\n }\n\n if (!handler.function || typeof handler.function !== \"string\") {\n console.warn(\"CustomMCP 工具的 function 处理器缺少有效的 function 字段\", {\n toolName,\n });\n return false;\n }\n\n return true;\n }\n\n /**\n * 验证脚本处理器配置\n */\n private validateScriptHandler(\n toolName: string,\n handler: ScriptHandlerConfig\n ): boolean {\n if (!handler.script || typeof handler.script !== \"string\") {\n console.warn(\"CustomMCP 工具的 script 处理器缺少有效的 script 字段\", {\n toolName,\n });\n return false;\n }\n\n if (\n handler.interpreter &&\n ![\"node\", \"python\", \"bash\"].includes(handler.interpreter)\n ) {\n console.warn(\"CustomMCP 工具的 script 处理器使用了不支持的解释器\", {\n toolName,\n interpreter: handler.interpreter,\n });\n return false;\n }\n\n return true;\n }\n\n /**\n * 验证链式处理器配置\n */\n private validateChainHandler(\n toolName: string,\n handler: ChainHandlerConfig\n ): boolean {\n if (\n !handler.tools ||\n !Array.isArray(handler.tools) ||\n handler.tools.length === 0\n ) {\n console.warn(\"CustomMCP 工具的 chain 处理器缺少有效的 tools 数组\", {\n toolName,\n });\n return false;\n }\n\n if (![\"sequential\", \"parallel\"].includes(handler.mode)) {\n console.warn(\"CustomMCP 工具的 chain 处理器使用了不支持的执行模式\", {\n toolName,\n mode: handler.mode,\n });\n return false;\n }\n\n if (![\"stop\", \"continue\", \"retry\"].includes(handler.error_handling)) {\n console.warn(\"CustomMCP 工具的 chain 处理器使用了不支持的错误处理策略\", {\n toolName,\n errorHandling: handler.error_handling,\n });\n return false;\n }\n\n return true;\n }\n\n /**\n * 验证 MCP 处理器配置\n */\n private validateMCPHandler(\n toolName: string,\n handler: MCPHandlerConfig\n ): boolean {\n if (!handler.config || typeof handler.config !== \"object\") {\n console.warn(\"CustomMCP 工具的 mcp 处理器缺少 config 字段\", { toolName });\n return false;\n }\n\n if (\n !handler.config.serviceName ||\n typeof handler.config.serviceName !== \"string\"\n ) {\n console.warn(\"CustomMCP 工具的 mcp 处理器缺少有效的 serviceName\", {\n toolName,\n });\n return false;\n }\n\n if (\n !handler.config.toolName ||\n typeof handler.config.toolName !== \"string\"\n ) {\n console.warn(\"CustomMCP 工具的 mcp 处理器缺少有效的 toolName\", {\n toolName,\n });\n return false;\n }\n\n return true;\n }\n\n /**\n * 检查是否配置了有效的 customMCP 工具\n */\n public hasValidCustomMCPTools(): boolean {\n try {\n const tools = this.getCustomMCPTools();\n if (tools.length === 0) {\n return false;\n }\n\n return this.validateCustomMCPTools(tools);\n } catch (error) {\n console.error(\"检查 customMCP 工具配置时出错\", { error });\n return false;\n }\n }\n\n /**\n * 添加自定义 MCP 工具\n */\n public addCustomMCPTool(tool: CustomMCPTool): void {\n if (!tool || typeof tool !== \"object\") {\n throw new Error(\"工具配置不能为空\");\n }\n\n const config = this.getMutableConfig();\n\n // 确保 customMCP 配置存在\n if (!config.customMCP) {\n config.customMCP = { tools: [] };\n }\n\n // 检查工具名称是否已存在\n const existingTool = config.customMCP.tools.find(\n (t) => t.name === tool.name\n );\n if (existingTool) {\n throw new Error(`工具 \"${tool.name}\" 已存在`);\n }\n\n // 验证工具配置\n if (!this.validateCustomMCPTools([tool])) {\n throw new Error(\"工具配置验证失败\");\n }\n\n // 添加工具\n config.customMCP.tools.unshift(tool);\n this.saveConfig(config);\n\n console.log(\"成功添加自定义 MCP 工具\", { toolName: tool.name });\n }\n\n /**\n * 批量添加自定义 MCP 工具\n * @param tools 要添加的工具数组\n */\n public async addCustomMCPTools(tools: CustomMCPTool[]): Promise<void> {\n if (!Array.isArray(tools)) {\n throw new Error(\"工具配置必须是数组\");\n }\n\n if (tools.length === 0) {\n return; // 空数组,无需处理\n }\n\n const config = this.getMutableConfig();\n\n // 确保 customMCP 配置存在\n if (!config.customMCP) {\n config.customMCP = { tools: [] };\n }\n\n // 添加新工具,避免重复\n const existingNames = new Set(\n config.customMCP.tools.map((tool) => tool.name)\n );\n const newTools = tools.filter((tool) => !existingNames.has(tool.name));\n\n if (newTools.length > 0) {\n // 验证新工具配置\n if (!this.validateCustomMCPTools(newTools)) {\n throw new Error(\"工具配置验证失败\");\n }\n\n // 添加工具\n config.customMCP.tools.push(...newTools);\n this.saveConfig(config);\n\n // 发射配置更新事件\n this.emitEvent(\"config:updated\", {\n type: \"customMCP\",\n timestamp: new Date(),\n });\n\n console.log(\"成功批量添加自定义 MCP 工具\", {\n count: newTools.length,\n toolNames: newTools.map((t) => t.name),\n });\n }\n }\n\n /**\n * 删除自定义 MCP 工具\n */\n public removeCustomMCPTool(toolName: string): void {\n if (!toolName || typeof toolName !== \"string\") {\n throw new Error(\"工具名称不能为空\");\n }\n\n const config = this.getMutableConfig();\n\n if (!config.customMCP || !config.customMCP.tools) {\n throw new Error(\"未配置自定义 MCP 工具\");\n }\n\n const toolIndex = config.customMCP.tools.findIndex(\n (t) => t.name === toolName\n );\n if (toolIndex === -1) {\n throw new Error(`工具 \"${toolName}\" 不存在`);\n }\n\n // 删除工具\n config.customMCP.tools.splice(toolIndex, 1);\n this.saveConfig(config);\n\n console.log(\"成功删除自定义 MCP 工具\", { toolName });\n }\n\n /**\n * 更新单个自定义 MCP 工具配置\n * @param toolName 工具名称\n * @param updatedTool 更新后的工具配置\n */\n public updateCustomMCPTool(\n toolName: string,\n updatedTool: CustomMCPTool\n ): void {\n if (!toolName || typeof toolName !== \"string\") {\n throw new Error(\"工具名称不能为空\");\n }\n if (!updatedTool || typeof updatedTool !== \"object\") {\n throw new Error(\"更新后的工具配置不能为空\");\n }\n\n const config = this.getMutableConfig();\n\n if (!config.customMCP || !config.customMCP.tools) {\n throw new Error(\"未配置自定义 MCP 工具\");\n }\n\n const toolIndex = config.customMCP.tools.findIndex(\n (t) => t.name === toolName\n );\n if (toolIndex === -1) {\n throw new Error(`工具 \"${toolName}\" 不存在`);\n }\n\n // 验证更新后的工具配置\n if (!this.validateCustomMCPTools([updatedTool])) {\n throw new Error(\"更新后的工具配置验证失败\");\n }\n\n // 更新工具配置\n config.customMCP.tools[toolIndex] = updatedTool;\n this.saveConfig(config);\n\n console.log(\"成功更新自定义 MCP 工具\", { toolName });\n }\n\n /**\n * 更新自定义 MCP 工具配置\n */\n public updateCustomMCPTools(tools: CustomMCPTool[]): void {\n if (!Array.isArray(tools)) {\n throw new Error(\"工具配置必须是数组\");\n }\n\n // 验证工具配置\n if (!this.validateCustomMCPTools(tools)) {\n throw new Error(\"工具配置验证失败\");\n }\n\n const config = this.getMutableConfig();\n\n // 确保 customMCP 配置存在\n if (!config.customMCP) {\n config.customMCP = { tools: [] };\n }\n\n config.customMCP.tools = tools;\n this.saveConfig(config);\n\n // 发射配置更新事件\n this.emitEvent(\"config:updated\", {\n type: \"customMCP\",\n timestamp: new Date(),\n });\n\n console.log(\"成功更新自定义 MCP 工具配置\", { count: tools.length });\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 = (\n global as typeof global & { __webServer?: WebServerInstance }\n ).__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 this.emitEvent(\"config:updated\", {\n type: \"webui\",\n timestamp: new Date(),\n });\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 public updatePlatformConfig(\n platformName: string,\n platformConfig: PlatformConfig\n ): void {\n const config = this.getMutableConfig();\n if (!config.platforms) {\n config.platforms = {};\n }\n config.platforms[platformName] = platformConfig;\n // 注意:Web UI 可能需要刷新才能看到更新后的数据\n this.saveConfig(config);\n\n // 发射配置更新事件\n this.emitEvent(\"config:updated\", {\n type: \"platform\",\n platformName,\n timestamp: new Date(),\n });\n }\n\n /**\n * 获取扣子平台配置\n */\n public getCozePlatformConfig(): CozePlatformConfig | null {\n const config = this.getConfig();\n const cozeConfig = config.platforms?.coze;\n\n if (!cozeConfig || !cozeConfig.token) {\n return null;\n }\n\n return {\n token: cozeConfig.token,\n };\n }\n\n /**\n * 获取扣子 API Token\n */\n public getCozeToken(): string | null {\n const cozeConfig = this.getCozePlatformConfig();\n return cozeConfig?.token || null;\n }\n\n /**\n * 设置扣子平台配置\n */\n public setCozePlatformConfig(config: CozePlatformConfig): void {\n if (\n !config.token ||\n typeof config.token !== \"string\" ||\n config.token.trim() === \"\"\n ) {\n throw new Error(\"扣子 API Token 不能为空\");\n }\n\n this.updatePlatformConfig(\"coze\", {\n token: config.token.trim(),\n });\n }\n\n /**\n * 检查扣子平台配置是否有效\n */\n public isCozeConfigValid(): boolean {\n const cozeConfig = this.getCozePlatformConfig();\n return (\n cozeConfig !== null &&\n typeof cozeConfig.token === \"string\" &&\n cozeConfig.token.trim() !== \"\"\n );\n }\n\n /**\n * 更新 mcpServerConfig 中的工具使用统计信息(内部实现)\n * @param serverName 服务名称\n * @param toolName 工具名称\n * @param callTime 调用时间(ISO 8601 格式)\n * @param incrementUsageCount 是否增加使用计数\n * @private\n */\n private async _updateMCPServerToolStats(\n serverName: string,\n toolName: string,\n callTime: string,\n incrementUsageCount = true\n ): Promise<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 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 if (incrementUsageCount) {\n toolConfig.usageCount = currentUsageCount + 1;\n }\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\n /**\n * 更新 customMCP 中的工具使用统计信息(服务名+工具名版本)\n * @param serverName 服务名称\n * @param toolName 工具名称\n * @param callTime 调用时间(ISO 8601 格式)\n * @private\n */\n private async updateCustomMCPToolStats(\n serverName: string,\n toolName: string,\n callTime: string\n ): Promise<void>;\n\n /**\n * 更新 customMCP 中的工具使用统计信息(工具名版本)\n * @param toolName 工具名称(customMCP 工具名称)\n * @param callTime 调用时间(ISO 8601 格式)\n * @param incrementUsageCount 是否增加使用计数,默认为 true\n * @private\n */\n private async updateCustomMCPToolStats(\n toolName: string,\n callTime: string,\n incrementUsageCount?: boolean\n ): Promise<void>;\n\n /**\n * 更新 customMCP 工具使用统计信息的实现\n * @private\n */\n private async updateCustomMCPToolStats(\n arg1: string,\n arg2: string,\n arg3?: string | boolean\n ): Promise<void> {\n try {\n let toolName: string;\n let callTime: string;\n let incrementUsageCount = true;\n let logPrefix: string;\n\n // 判断参数类型来区分不同的重载\n if (typeof arg3 === \"string\") {\n // 三个字符串参数的情况:updateCustomMCPToolStats(serverName, toolName, callTime)\n const serverName = arg1;\n toolName = `${serverName}__${arg2}`;\n callTime = arg3;\n logPrefix = `${serverName}/${arg2}`;\n } else {\n // 两个或三个参数的情况:updateCustomMCPToolStats(toolName, callTime, incrementUsageCount?)\n toolName = arg1;\n callTime = arg2;\n incrementUsageCount = (arg3 as boolean) || true;\n logPrefix = toolName;\n }\n\n const customTools = this.getCustomMCPTools();\n const toolIndex = customTools.findIndex((tool) => tool.name === toolName);\n\n if (toolIndex === -1) {\n // 如果 customMCP 中没有对应的工具,跳过更新\n return;\n }\n\n const updatedTools = [...customTools];\n const tool = updatedTools[toolIndex];\n\n // 确保 stats 对象存在\n if (!tool.stats) {\n tool.stats = {};\n }\n\n const currentUsageCount = tool.stats.usageCount || 0;\n const currentLastUsedTime = tool.stats.lastUsedTime;\n\n // 根据参数决定是否更新使用次数\n if (incrementUsageCount) {\n tool.stats.usageCount = currentUsageCount + 1;\n }\n\n // 时间校验:只有新时间晚于现有时间才更新 lastUsedTime\n if (\n !currentLastUsedTime ||\n new Date(callTime) > new Date(currentLastUsedTime)\n ) {\n tool.stats.lastUsedTime = dayjs(callTime).format(\"YYYY-MM-DD HH:mm:ss\");\n }\n\n // 保存更新后的工具配置\n await this.updateCustomMCPTools(updatedTools);\n } catch (error) {\n // 根据参数类型决定错误日志的前缀\n if (typeof arg3 === \"string\") {\n const serverName = arg1;\n const toolName = arg2;\n console.error(\"更新 customMCP 工具统计信息失败\", {\n serverName,\n toolName,\n error,\n });\n } else {\n const toolName = arg1;\n console.error(\"更新 customMCP 工具统计信息失败\", { toolName, error });\n }\n // customMCP 统计更新失败不应该影响主要流程\n }\n }\n\n /**\n * 获取统计更新锁(确保同一工具的统计更新串行执行)\n * @param toolKey 工具键\n * @private\n */\n private async acquireStatsUpdateLock(toolKey: string): Promise<boolean> {\n if (this.statsUpdateLocks.has(toolKey)) {\n console.log(\"工具统计更新正在进行中,跳过本次更新\", { toolKey });\n return false;\n }\n\n const updatePromise = new Promise<void>((resolve) => {\n // 锁定逻辑在调用者中实现\n });\n\n this.statsUpdateLocks.set(toolKey, updatePromise);\n\n // 设置超时自动释放锁\n const timeout = setTimeout(() => {\n this.releaseStatsUpdateLock(toolKey);\n }, this.STATS_UPDATE_TIMEOUT);\n\n this.statsUpdateLockTimeouts.set(toolKey, timeout);\n\n return true;\n }\n\n /**\n * 释放统计更新锁\n * @param toolKey 工具键\n * @private\n */\n private releaseStatsUpdateLock(toolKey: string): void {\n this.statsUpdateLocks.delete(toolKey);\n\n const timeout = this.statsUpdateLockTimeouts.get(toolKey);\n if (timeout) {\n clearTimeout(timeout);\n }\n this.statsUpdateLockTimeouts.delete(toolKey);\n\n console.log(\"已释放工具的统计更新锁\", { toolKey });\n }\n\n /**\n * 带并发控制的工具统计更新(CustomMCP 工具)\n * @param toolName 工具名称\n * @param incrementUsageCount 是否增加使用计数\n */\n public async updateToolUsageStatsWithLock(\n toolName: string,\n incrementUsageCount = true\n ): Promise<void> {\n const toolKey = `custommcp_${toolName}`;\n\n if (!(await this.acquireStatsUpdateLock(toolKey))) {\n return; // 已有其他更新在进行\n }\n\n try {\n await this.updateToolUsageStats(toolName, incrementUsageCount);\n console.log(\"工具统计更新完成\", { toolName });\n } catch (error) {\n console.error(\"工具统计更新失败\", { toolName, error });\n throw error;\n } finally {\n this.releaseStatsUpdateLock(toolKey);\n }\n }\n\n /**\n * 带并发控制的工具统计更新(MCP 服务工具)\n * @param serviceName 服务名称\n * @param toolName 工具名称\n * @param callTime 调用时间\n * @param incrementUsageCount 是否增加使用计数\n */\n public async updateMCPServerToolStatsWithLock(\n serviceName: string,\n toolName: string,\n callTime: string,\n incrementUsageCount = true\n ): Promise<void> {\n const toolKey = `mcpserver_${serviceName}_${toolName}`;\n\n if (!(await this.acquireStatsUpdateLock(toolKey))) {\n return; // 已有其他更新在进行\n }\n\n try {\n await this.updateMCPServerToolStats(\n serviceName,\n toolName,\n callTime,\n incrementUsageCount\n );\n console.log(\"MCP 服务工具统计更新完成\", { serviceName, toolName });\n } catch (error) {\n console.error(\"MCP 服务工具统计更新失败\", {\n serviceName,\n toolName,\n error,\n });\n throw error;\n } finally {\n this.releaseStatsUpdateLock(toolKey);\n }\n }\n\n /**\n * 清理所有统计更新锁(用于异常恢复)\n */\n public clearAllStatsUpdateLocks(): void {\n const lockCount = this.statsUpdateLocks.size;\n this.statsUpdateLocks.clear();\n\n // 清理所有超时定时器\n for (const timeout of this.statsUpdateLockTimeouts.values()) {\n clearTimeout(timeout);\n }\n this.statsUpdateLockTimeouts.clear();\n\n if (lockCount > 0) {\n console.log(\"已清理统计更新锁\", { count: lockCount });\n }\n }\n\n /**\n * 获取统计更新锁状态(用于调试和监控)\n */\n public getStatsUpdateLocks(): string[] {\n return Array.from(this.statsUpdateLocks.keys());\n }\n\n /**\n * 获取工具调用日志配置\n */\n public getToolCallLogConfig(): Readonly<ToolCallLogConfig> {\n const config = this.getConfig();\n return config.toolCallLog || {};\n }\n\n /**\n * 更新工具调用日志配置\n */\n public updateToolCallLogConfig(\n toolCallLogConfig: Partial<ToolCallLogConfig>\n ): void {\n const config = this.getMutableConfig();\n\n // 确保 toolCallLog 对象存在\n if (!config.toolCallLog) {\n config.toolCallLog = {};\n }\n\n // 直接修改现有的 toolCallLog 对象以保留注释\n Object.assign(config.toolCallLog, toolCallLogConfig);\n this.saveConfig(config);\n }\n\n /**\n * 获取配置目录路径(与配置文件同级目录)\n */\n public getConfigDir(): string {\n // 配置文件路径 - 优先使用环境变量指定的目录,否则使用当前工作目录\n return process.env.XIAOZHI_CONFIG_DIR || process.cwd();\n }\n\n /**\n * 获取 TTS 配置\n */\n public getTTSConfig(): Readonly<TTSConfig> {\n const config = this.getConfig();\n return config.tts || {};\n }\n\n /**\n * 获取 ASR 配置\n */\n public getASRConfig(): Readonly<ASRConfig> {\n const config = this.getConfig();\n return config.asr || {};\n }\n\n /**\n * 获取 LLM 配置\n */\n public getLLMConfig(): LLMConfig | null {\n const config = this.getConfig();\n return config.llm || null;\n }\n\n /**\n * 检查 LLM 配置是否有效\n */\n public isLLMConfigValid(): boolean {\n const llmConfig = this.getLLMConfig();\n return (\n llmConfig !== null &&\n typeof llmConfig.model === \"string\" &&\n llmConfig.model.trim() !== \"\" &&\n typeof llmConfig.apiKey === \"string\" &&\n llmConfig.apiKey.trim() !== \"\" &&\n typeof llmConfig.baseURL === \"string\" &&\n llmConfig.baseURL.trim() !== \"\"\n );\n }\n\n /**\n * 更新 TTS 配置\n */\n public updateTTSConfig(ttsConfig: Partial<TTSConfig>): void {\n const config = this.getMutableConfig();\n\n // 确保 tts 对象存在\n if (!config.tts) {\n config.tts = {};\n }\n\n // 直接修改现有的 tts 对象以保留注释\n Object.assign(config.tts, ttsConfig);\n this.saveConfig(config);\n\n // 发射配置更新事件\n this.emitEvent(\"config:updated\", {\n type: \"tts\",\n timestamp: new Date(),\n });\n }\n}\n\n// 导出单例实例\nexport const configManager = ConfigManager.getInstance();\n","/**\n * MCP 核心库类型定义\n * 统一管理所有 MCP 相关的类型定义\n */\n\nimport type { SSEClientTransport } from \"@modelcontextprotocol/sdk/client/sse.js\";\nimport type { StdioClientTransport } from \"@modelcontextprotocol/sdk/client/stdio.js\";\nimport type { StreamableHTTPClientTransport } from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\n\n// =========================\n// 1. 基础传输类型\n// =========================\n\n/**\n * MCP 传输层联合类型定义\n * 支持 STDIO、SSE、StreamableHTTP 三种传输协议\n */\nexport type MCPServerTransport =\n | StdioClientTransport\n | SSEClientTransport\n | StreamableHTTPClientTransport;\n\n/**\n * 通信方式枚举\n * 定义 MCP 支持的传输类型\n */\nexport enum MCPTransportType {\n STDIO = \"stdio\",\n SSE = \"sse\",\n HTTP = \"http\",\n}\n\n/**\n * 传输类型字符串字面量\n * 方便外部用户直接使用字符串而不需要导入枚举\n */\nexport type MCPTransportTypeString = \"stdio\" | \"sse\" | \"http\";\n\n/**\n * 传输类型输入值(枚举或字符串字面量)\n */\nexport type MCPTransportTypeInput = MCPTransportType | MCPTransportTypeString;\n\n// =========================\n// 1.1 事件回调接口\n// =========================\n\n/**\n * MCP 服务事件回调接口\n * 用于替代 EventBus 依赖,提供灵活的事件处理机制\n */\nexport interface MCPServiceEventCallbacks {\n /** 连接成功回调 */\n onConnected?: (data: {\n serviceName: string;\n tools: Tool[];\n connectionTime: Date;\n }) => void;\n /** 断开连接回调 */\n onDisconnected?: (data: {\n serviceName: string;\n reason?: string;\n disconnectionTime: Date;\n }) => void;\n /** 连接失败回调 */\n onConnectionFailed?: (data: {\n serviceName: string;\n error: Error;\n attempt: number;\n }) => void;\n}\n\n// =========================\n// 2. 配置接口类型\n// =========================\n\n/**\n * ModelScope SSE 自定义选项接口\n */\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/**\n * 心跳检测配置接口\n */\nexport interface HeartbeatConfig {\n /** 是否启用心跳检测(默认 true) */\n enabled?: boolean;\n /** 心跳间隔(毫秒,默认 30000 = 30秒) */\n interval?: number;\n}\n\n/**\n * MCP 服务配置接口\n * 包含所有 MCP 服务的配置选项(不包含服务名称)\n *\n * @description\n * 与 MCP 官方配置格式保持一致,支持三种传输类型:\n * - stdio: 本地进程通信 { command, args, env }\n * - sse: Server-Sent Events { url, headers }\n * - http: Streamable HTTP { url, headers }\n *\n * 向后兼容:自动将 streamable-http/streamable_http/streamableHttp 转换为 http\n */\nexport interface MCPServiceConfig {\n // name 字段已从配置中移除,应作为独立参数传递\n type?: MCPTransportTypeInput; // 支持枚举或字符串字面量,如 \"stdio\" | \"sse\" | \"http\"\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 customSSEOptions?: ModelScopeSSEOptions;\n // 心跳配置\n heartbeat?: HeartbeatConfig;\n}\n\n/**\n * 旧版 MCP 服务配置接口(包含 name 字段)\n * 用于向后兼容\n */\nexport interface LegacyMCPServiceConfig extends MCPServiceConfig {\n name: string;\n}\n\n/**\n * 内部使用的 MCP 服务配置接口(包含 name 字段)\n * 用于 TransportFactory 等内部函数\n */\nexport interface InternalMCPServiceConfig extends MCPServiceConfig {\n name: string;\n}\n\n// =========================\n// 3. 状态枚举类型\n// =========================\n\n/**\n * 连接状态枚举\n */\nexport enum ConnectionState {\n DISCONNECTED = \"disconnected\",\n CONNECTING = \"connecting\",\n CONNECTED = \"connected\",\n RECONNECTING = \"reconnecting\",\n FAILED = \"failed\",\n ERROR = \"error\",\n}\n\n/**\n * MCP 服务状态接口\n */\nexport interface MCPServiceStatus {\n name: string;\n connected: boolean;\n initialized: boolean;\n transportType: MCPTransportType;\n toolCount: number;\n lastError?: string;\n connectionState: ConnectionState;\n}\n\n// =========================\n// 4. 工具调用相关类型\n// =========================\n\n// 从 MCP SDK 重新导出工具调用结果类型\n// 使用 CompatibilityCallToolResult 以支持新旧协议版本\nexport type { CompatibilityCallToolResult as ToolCallResult } from \"@modelcontextprotocol/sdk/types.js\";\n\n/**\n * JSON Schema 类型定义\n */\nexport type JSONSchema =\n | (Record<string, unknown> & {\n type: \"object\";\n properties?: Record<string, unknown>;\n required?: string[];\n additionalProperties?: boolean;\n })\n | Record<string, unknown>;\n\n/**\n * 类型守卫:检查对象是否为有效的 MCP Tool JSON Schema\n */\nexport function isValidToolJSONSchema(obj: unknown): obj is {\n type: \"object\";\n properties?: Record<string, unknown>;\n required?: string[];\n additionalProperties?: boolean;\n} {\n return (\n typeof obj === \"object\" &&\n obj !== null &&\n \"type\" in obj &&\n (obj as { type?: unknown }).type === \"object\"\n );\n}\n\n/**\n * 确保对象符合 MCP Tool JSON Schema 格式\n */\nexport function ensureToolJSONSchema(schema: JSONSchema): {\n type: \"object\";\n properties?: Record<string, object>;\n required?: string[];\n additionalProperties?: boolean;\n} {\n if (isValidToolJSONSchema(schema)) {\n return schema as {\n type: \"object\";\n properties?: Record<string, object>;\n required?: string[];\n additionalProperties?: boolean;\n };\n }\n\n return {\n type: \"object\",\n properties: {} as Record<string, object>,\n required: [],\n additionalProperties: true,\n };\n}\n\n/**\n * CustomMCP 工具类型定义\n */\nexport interface CustomMCPTool {\n name: string;\n description?: string;\n inputSchema: JSONSchema;\n handler?: {\n type: string;\n config?: Record<string, unknown>;\n };\n}\n\n/**\n * 工具信息接口\n */\nexport interface ToolInfo {\n serviceName: string;\n originalName: string;\n tool: Tool;\n}\n\n// =========================\n// 5. 增强工具信息类型\n// =========================\n\n/**\n * 工具状态过滤选项\n */\nexport type ToolStatusFilter = \"enabled\" | \"disabled\" | \"all\";\n\n/**\n * 增强的工具信息接口\n */\nexport interface EnhancedToolInfo {\n /** 工具唯一标识符,格式为 \"{serviceName}__{originalName}\" */\n name: string;\n /** 工具描述信息 */\n description: string;\n /** 工具输入参数的 JSON Schema 定义 */\n inputSchema: JSONSchema;\n /** 工具所属的 MCP 服务名称 */\n serviceName: string;\n /** 工具在 MCP 服务中的原始名称 */\n originalName: string;\n /** 工具是否启用 */\n enabled: boolean;\n /** 工具使用次数统计 */\n usageCount: number;\n /** 工具最后使用时间 */\n lastUsedTime: string;\n}\n\n// =========================\n// 6. 服务器配置类型\n// =========================\n\n/**\n * 统一服务器配置接口\n */\nexport interface UnifiedServerConfig {\n name?: string;\n enableLogging?: boolean;\n logLevel?: string;\n configs?: Record<string, MCPServiceConfig>;\n}\n\n/**\n * 统一服务器状态接口\n */\nexport interface UnifiedServerStatus {\n isRunning: boolean;\n serviceStatus: ManagerStatus;\n transportCount: number;\n activeConnections: number;\n config: UnifiedServerConfig;\n services?: Record<string, MCPServiceConnectionStatus>;\n totalTools?: number;\n availableTools?: string[];\n}\n\n// =========================\n// 7. 管理器相关类型\n// =========================\n\n/**\n * MCP 服务连接状态接口\n */\nexport interface MCPServiceConnectionStatus {\n connected: boolean;\n clientName: string;\n}\n\n/**\n * 管理器状态接口\n */\nexport interface ManagerStatus {\n services: Record<string, MCPServiceConnectionStatus>;\n totalTools: number;\n availableTools: string[];\n}\n\n// =========================\n// 8. 参数校验相关类型\n// =========================\n\n/**\n * 工具调用参数接口\n */\nexport interface ToolCallParams {\n name: string;\n arguments?: Record<string, unknown>;\n}\n\n/**\n * 验证后的工具调用参数\n */\nexport interface ValidatedToolCallParams {\n name: string;\n arguments?: Record<string, unknown>;\n}\n\n/**\n * 工具调用验证选项\n */\nexport interface ToolCallValidationOptions {\n validateName?: boolean;\n validateArguments?: boolean;\n allowEmptyArguments?: boolean;\n customValidator?: (params: ToolCallParams) => string | null;\n}\n\n/**\n * 工具调用错误码枚举\n */\nexport enum ToolCallErrorCode {\n INVALID_PARAMS = -32602,\n TOOL_NOT_FOUND = -32601,\n SERVICE_UNAVAILABLE = -32001,\n TIMEOUT = -32002,\n TOOL_EXECUTION_ERROR = -32000,\n}\n\n/**\n * 工具调用错误类\n */\nexport class ToolCallError extends Error {\n constructor(\n public code: ToolCallErrorCode,\n message: string,\n public data?: unknown\n ) {\n super(message);\n this.name = \"ToolCallError\";\n }\n}\n","/**\n * MCP 传输层工厂模块\n *\n * 提供创建不同类型传输层实例的工厂函数\n * 支持 STDIO、SSE、StreamableHTTP 三种传输协议\n *\n * @module transport-factory\n */\n\nimport type { SSEClientTransportOptions } from \"@modelcontextprotocol/sdk/client/sse.js\";\nimport { SSEClientTransport } from \"@modelcontextprotocol/sdk/client/sse.js\";\nimport { StdioClientTransport } from \"@modelcontextprotocol/sdk/client/stdio.js\";\nimport type { StreamableHTTPClientTransportOptions } from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\nimport { StreamableHTTPClientTransport } from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\nimport { EventSource } from \"eventsource\";\nimport type { InternalMCPServiceConfig, MCPServerTransport } from \"./types.js\";\nimport { MCPTransportType } from \"./types.js\";\n\n// 全局 polyfill EventSource(用于 SSE)\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst globalThisAny: any =\n typeof globalThis !== \"undefined\" ? globalThis : global;\nif (typeof globalThisAny !== \"undefined\" && !globalThisAny.EventSource) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n globalThisAny.EventSource = EventSource;\n}\n\n// Transport 基础接口\nexport interface Transport {\n connect?(): Promise<void>;\n close?(): Promise<void>;\n}\n\n/**\n * 创建 transport 实例\n * @param config MCP 服务配置(包含 name)\n * @returns transport 实例\n */\nexport function createTransport(\n config: InternalMCPServiceConfig\n): MCPServerTransport {\n console.debug(\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.HTTP:\n return createHTTPTransport(config);\n\n default:\n throw new Error(`不支持的传输类型: ${config.type}`);\n }\n}\n\n/**\n * 创建 Stdio transport\n */\nfunction createStdioTransport(\n config: InternalMCPServiceConfig\n): 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(\n config: InternalMCPServiceConfig\n): 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\nfunction createHTTPTransport(\n config: InternalMCPServiceConfig\n): StreamableHTTPClientTransport {\n if (!config.url) {\n throw new Error(\"HTTP 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 * 创建认证请求头\n */\nfunction createAuthHeaders(\n config: InternalMCPServiceConfig\n): Record<string, string> | undefined {\n if (config.apiKey) {\n return {\n Authorization: `Bearer ${config.apiKey}`,\n ...config.headers,\n };\n }\n return config.headers;\n}\n\n/**\n * 创建 SSE 选项\n */\nfunction createSSEOptions(\n config: InternalMCPServiceConfig\n): SSEClientTransportOptions {\n const options: SSEClientTransportOptions = {};\n\n const headers = createAuthHeaders(config);\n if (headers) {\n options.requestInit = {\n headers,\n };\n }\n\n return options;\n}\n\nfunction createStreamableHTTPOptions(\n config: InternalMCPServiceConfig\n): StreamableHTTPClientTransportOptions {\n const options: StreamableHTTPClientTransportOptions = {};\n\n const headers = createAuthHeaders(config);\n if (headers) {\n options.requestInit = {\n headers,\n };\n }\n\n return options;\n}\n\n/**\n * 验证配置\n * 注意:name 验证已在 MCPConnection 构造函数中进行\n * @param config MCP 服务配置(包含 name)\n */\nexport function validateConfig(config: InternalMCPServiceConfig): void {\n // name 验证已移至 MCPConnection 构造函数\n\n // type 字段现在是可选的,由 MCPService 自动推断\n // 这里我们只验证如果 type 存在,必须是有效的类型\n if (\n config.type &&\n !Object.values(MCPTransportType).includes(config.type as MCPTransportType)\n ) {\n throw new Error(`不支持的传输类型: ${config.type}`);\n }\n\n // 注意:这个验证方法在 MCPService.inferTransportType 之后调用\n // 此时 config.type 应该已经被推断或显式设置\n if (!config.type) {\n throw new Error(\"传输类型未设置,这应该在 inferTransportType 中处理\");\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 if (config.url === undefined || config.url === null) {\n throw new Error(`${config.type} 类型需要 url 字段`);\n }\n break;\n case MCPTransportType.HTTP:\n // HTTP 允许空 URL,会在后续处理中设置默认值\n if (config.url === undefined || config.url === null) {\n throw new Error(`${config.type} 类型需要 url 字段`);\n }\n break;\n\n default:\n throw new Error(`不支持的传输类型: ${config.type}`);\n }\n}\n\n/**\n * 获取支持的传输类型列表\n */\nexport function getSupportedTypes(): MCPTransportType[] {\n return [MCPTransportType.STDIO, MCPTransportType.SSE, MCPTransportType.HTTP];\n}\n\n/**\n * Transport 工厂对象(保持 API 兼容性)\n */\nexport const TransportFactory = {\n create: createTransport,\n validateConfig,\n getSupportedTypes,\n};\n","/**\n * MCP 服务器配置 Type 字段标准化工具\n * 支持将各种 type 字段格式转换为 MCP 官方标准格式\n *\n * @description\n * 标准格式与 MCP 官方保持一致:\n * - stdio: 本地进程通信\n * - sse: Server-Sent Events\n * - http: Streamable HTTP(推荐使用 http 而非 streamable-http)\n *\n * 向后兼容:自动转换各种变体格式\n */\n\n/**\n * MCP 服务器配置的基础接口\n * 定义包含可选 type 字段的配置对象结构\n */\nexport interface MCPBaseConfig {\n type?: string;\n [key: string]: unknown; // 允许其他配置属性\n}\n\n/**\n * MCP 服务器配置 Type 字段标准化工具类\n */\nexport namespace TypeFieldNormalizer {\n /**\n * 标准化 type 字段格式\n *\n * 支持的转换:\n * - http 变体:http → http(标准值)\n * - streamable-http → http\n * - streamable_http → http\n * - streamableHttp → http\n * - sse 变体:sse → sse(标准值)\n * - s_se → sse\n * - s-se → sse\n * - stdio 变体:stdio → stdio(标准值)\n */\n // 函数重载:泛型版本,用于类型安全的调用\n export function normalizeTypeField<T extends MCPBaseConfig>(config: T): T;\n\n // 函数重载:向后兼容版本,用于 unknown 类型输入\n export function normalizeTypeField(config: unknown): unknown;\n\n // 统一实现\n export function normalizeTypeField<T extends MCPBaseConfig>(\n config: T | unknown\n ): T | unknown {\n if (!config || typeof config !== \"object\") {\n return config;\n }\n\n // 如果配置中没有 type 字段,直接返回原始对象(无需拷贝)\n if (!(\"type\" in config)) {\n return config;\n }\n\n const originalType = (config as Record<string, unknown>).type;\n\n // 如果已经是标准格式,直接返回原始对象(无需拷贝)\n if (\n originalType === \"stdio\" ||\n originalType === \"sse\" ||\n originalType === \"http\"\n ) {\n return config;\n }\n\n // 转换为标准格式\n const normalizedType = normalizeTypeValue(originalType as string);\n\n // 验证转换后的类型是否有效\n if (\n normalizedType === \"stdio\" ||\n normalizedType === \"sse\" ||\n normalizedType === \"http\"\n ) {\n // 只在需要修改时创建浅拷贝,使用展开运算符只修改 type 字段\n return {\n ...config,\n type: normalizedType,\n };\n }\n\n return config;\n }\n\n /**\n * 标准化单个 type 值\n */\n export function normalizeTypeValue(type: string): string {\n // http 相关的变体全部转为 http\n if (\n type === \"http\" ||\n type === \"streamable-http\" ||\n type === \"streamable_http\" ||\n type === \"streamableHttp\"\n ) {\n return \"http\";\n }\n\n // sse 相关的变体转为 sse\n if (type === \"sse\" || type === \"s_se\" || type === \"s-se\") {\n return \"sse\";\n }\n\n // stdio 相关的变体转为 stdio\n if (type === \"stdio\") {\n return \"stdio\";\n }\n\n // 对于其他格式,尝试智能转换(转小写、下划线转中划线等)\n return convertToStandardFormat(type);\n }\n\n /**\n * 将字符串转换为标准格式\n */\n function convertToStandardFormat(str: string): string {\n const lowered = str.toLowerCase();\n\n // 处理 http 相关的变体\n if (lowered.includes(\"http\") || lowered.includes(\"streamable\")) {\n return \"http\";\n }\n\n // 处理 sse 相关的变体\n if (lowered.includes(\"sse\")) {\n return \"sse\";\n }\n\n // 处理 stdio 相关的变体\n if (lowered.includes(\"stdio\")) {\n return \"stdio\";\n }\n\n // 无法识别的格式,返回原值\n return str;\n }\n}\n\n/**\n * 导出便捷函数\n */\nexport function normalizeTypeField<T extends MCPBaseConfig>(config: T): T;\nexport function normalizeTypeField(config: unknown): unknown;\nexport function normalizeTypeField<T extends MCPBaseConfig>(\n config: T | unknown\n): T | unknown {\n return TypeFieldNormalizer.normalizeTypeField(config);\n}\n","/**\n * MCP 工具函数验证器\n *\n * 提供传输类型推断和工具调用参数验证功能:\n * - 根据 URL 路径自动推断传输类型(STDIO/SSE/HTTP)\n * - 基于 MCP 服务配置自动推断传输类型\n * - 验证工具调用参数的完整性和格式\n *\n * @module validators\n */\n\nimport {\n MCPTransportType,\n ToolCallError,\n ToolCallErrorCode,\n} from \"../types.js\";\nimport type {\n MCPServiceConfig,\n ToolCallParams,\n ToolCallValidationOptions,\n ValidatedToolCallParams,\n} from \"../types.js\";\nimport { TypeFieldNormalizer } from \"./type-normalizer.js\";\n\n/**\n * 根据 URL 路径推断传输类型\n * 基于路径末尾推断,支持包含多个 / 的复杂路径\n *\n * @param url - 要推断的 URL\n * @param options - 可选配置项\n * @returns 推断出的传输类型\n */\nexport function inferTransportTypeFromUrl(\n url: string,\n options?: {\n serviceName?: string;\n }\n): MCPTransportType {\n try {\n const parsedUrl = new URL(url);\n const pathname = parsedUrl.pathname;\n\n // 检查路径末尾\n if (pathname.endsWith(\"/sse\")) {\n return MCPTransportType.SSE;\n }\n if (pathname.endsWith(\"/mcp\")) {\n return MCPTransportType.HTTP;\n }\n\n // 默认类型 - 使用 console 输出\n if (options?.serviceName) {\n console.info(\n `[MCP-${options.serviceName}] URL 路径 ${pathname} 不匹配特定规则,默认推断为 http 类型`\n );\n }\n return MCPTransportType.HTTP;\n } catch (error) {\n if (options?.serviceName) {\n console.warn(\n `[MCP-${options.serviceName}] URL 解析失败,默认推断为 http 类型`,\n error\n );\n }\n return MCPTransportType.HTTP;\n }\n}\n\n/**\n * 完整的配置类型推断(包括 command 字段)\n *\n * @param config - MCP 服务配置\n * @param serviceName - 服务名称(用于日志输出)\n * @returns 完整的配置对象,包含推断出的类型\n */\nexport function inferTransportTypeFromConfig(\n config: MCPServiceConfig,\n serviceName?: string\n): MCPServiceConfig {\n // 如果已显式指定类型,先标准化然后返回\n if (config.type) {\n const normalizedConfig = TypeFieldNormalizer.normalizeTypeField(config);\n return normalizedConfig as MCPServiceConfig;\n }\n\n // 基于 command 字段推断\n if (config.command) {\n return {\n ...config,\n type: MCPTransportType.STDIO,\n };\n }\n\n // 基于 URL 字段推断(排除 null 和 undefined)\n if (config.url !== undefined && config.url !== null) {\n const inferredType = inferTransportTypeFromUrl(config.url, {\n serviceName,\n });\n return {\n ...config,\n type: inferredType,\n };\n }\n\n throw new Error(\n `无法为服务 ${serviceName || \"未知\"} 推断传输类型。请显式指定 type 字段,或提供 command/url 配置`\n );\n}\n\n// =========================\n// 参数校验工具函数\n// =========================\n\n/**\n * 验证工具调用参数\n * 对传入的参数进行完整性和格式验证\n *\n * @param params 待验证的参数\n * @param options 验证选项\n * @returns 验证后的参数\n * @throws ToolCallError 验证失败时抛出\n */\nexport function validateToolCallParams(\n params: unknown,\n options?: ToolCallValidationOptions\n): ValidatedToolCallParams {\n const opts = {\n validateName: true,\n validateArguments: true,\n allowEmptyArguments: true,\n ...options,\n };\n\n // 1. 验证参数必须是对象\n if (!params || typeof params !== \"object\") {\n throw new ToolCallError(\n ToolCallErrorCode.INVALID_PARAMS,\n \"请求参数必须是对象\"\n );\n }\n\n const paramsObj = params as Record<string, unknown>;\n\n // 2. 验证工具名称\n if (opts.validateName) {\n if (!paramsObj.name || typeof paramsObj.name !== \"string\") {\n throw new ToolCallError(\n ToolCallErrorCode.INVALID_PARAMS,\n \"工具名称必须是非空字符串\"\n );\n }\n }\n\n // 3. 验证工具参数格式\n if (\n opts.validateArguments &&\n paramsObj.arguments !== undefined &&\n paramsObj.arguments !== null\n ) {\n if (\n typeof paramsObj.arguments !== \"object\" ||\n Array.isArray(paramsObj.arguments)\n ) {\n throw new ToolCallError(\n ToolCallErrorCode.INVALID_PARAMS,\n \"工具参数必须是对象\"\n );\n }\n }\n\n // 4. 验证是否允许空参数\n if (\n !opts.allowEmptyArguments &&\n paramsObj.arguments !== undefined &&\n paramsObj.arguments !== null\n ) {\n const argsObj = paramsObj.arguments as Record<string, unknown>;\n if (Object.keys(argsObj).length === 0) {\n throw new ToolCallError(\n ToolCallErrorCode.INVALID_PARAMS,\n \"工具参数不能为空\"\n );\n }\n }\n\n // 5. 执行自定义验证\n if (opts.customValidator) {\n const error = opts.customValidator(paramsObj as unknown as ToolCallParams);\n if (error) {\n throw new ToolCallError(ToolCallErrorCode.INVALID_PARAMS, error);\n }\n }\n\n return {\n name: paramsObj.name as string,\n arguments: paramsObj.arguments as Record<string, unknown>,\n };\n}\n","/**\n * 工具函数统一导出\n */\n\n// 类型标准化\nexport { TypeFieldNormalizer, normalizeTypeField } from \"./type-normalizer.js\";\n\n// 参数校验和类型推断\nexport {\n validateToolCallParams,\n inferTransportTypeFromUrl,\n inferTransportTypeFromConfig,\n} from \"./validators.js\";\n","/**\n * MCP 连接管理模块\n *\n * 提供 MCPConnection 类,负责管理单个 MCP 服务的连接生命周期\n * 包括连接建立、工具列表管理、工具调用、心跳检测等功能\n *\n * @module connection\n */\n\nimport { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport { TransportFactory } from \"./transport-factory.js\";\nimport type {\n MCPServerTransport,\n MCPServiceConfig,\n MCPServiceStatus,\n ToolCallResult,\n} from \"./types.js\";\nimport { ConnectionState, MCPTransportType } from \"./types.js\";\nimport type {\n HeartbeatConfig,\n InternalMCPServiceConfig,\n MCPServiceEventCallbacks,\n} from \"./types.js\";\nimport { inferTransportTypeFromConfig } from \"./utils/index.js\";\n\n/**\n * MCP 连接类\n * 负责管理单个 MCP 服务的连接、工具管理和调用\n */\nexport class MCPConnection {\n private name: string; // 服务名称(独立字段)\n private config: MCPServiceConfig;\n private client: Client | null = null;\n private transport: MCPServerTransport | null = null;\n private tools: Map<string, Tool> = new Map();\n private connectionState: ConnectionState = ConnectionState.DISCONNECTED;\n private connectionTimeout: NodeJS.Timeout | null = null;\n private initialized = false;\n private callbacks?: MCPServiceEventCallbacks;\n // 心跳检测相关\n private heartbeatTimer: NodeJS.Timeout | null = null;\n private heartbeatConfig?: HeartbeatConfig;\n\n constructor(\n name: string,\n config: MCPServiceConfig,\n callbacks?: MCPServiceEventCallbacks\n ) {\n this.name = name;\n // 使用工具方法推断服务类型(传递服务名称用于日志)\n this.config = inferTransportTypeFromConfig(config, name);\n this.callbacks = callbacks;\n // 保存心跳配置 - 优先使用用户配置\n this.heartbeatConfig = {\n enabled: config.heartbeat?.enabled ?? true, // 默认启用\n interval: config.heartbeat?.interval ?? 30 * 1000, // 默认 30 秒\n };\n\n // 验证配置\n this.validateConfig();\n }\n\n /**\n * 验证配置\n */\n private validateConfig(): void {\n // 验证服务名称\n if (!this.name || typeof this.name !== \"string\") {\n throw new Error(\"服务名称必须是非空字符串\");\n }\n // 使用 TransportFactory 进行配置验证(传递包含 name 的完整配置)\n const fullConfig: InternalMCPServiceConfig = {\n name: this.name,\n ...this.config,\n };\n TransportFactory.validateConfig(fullConfig);\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 return this.attemptConnection();\n }\n\n /**\n * 尝试建立连接\n */\n private async attemptConnection(): Promise<void> {\n this.connectionState = ConnectionState.CONNECTING;\n console.debug(`[MCP-${this.name}] 正在连接 MCP 服务: ${this.name}`);\n\n return new Promise((resolve, reject) => {\n // 设置连接超时(使用固定默认值 30 秒)\n const CONNECTION_TIMEOUT = 30000;\n this.connectionTimeout = setTimeout(() => {\n const error = new Error(`连接超时 (${CONNECTION_TIMEOUT}ms)`);\n this.handleConnectionError(error);\n reject(error);\n }, CONNECTION_TIMEOUT);\n\n try {\n this.client = new Client(\n {\n name: `xiaozhi-${this.name}-client`,\n version: \"1.0.0\",\n },\n {\n capabilities: {},\n }\n );\n\n // 使用 TransportFactory 创建传输层(传递包含 name 的完整配置)\n const fullConfig: InternalMCPServiceConfig = {\n name: this.name,\n ...this.config,\n };\n this.transport = TransportFactory.create(fullConfig);\n\n // 连接到 MCP 服务\n this.client\n .connect(this.transport as MCPServerTransport)\n .then(async () => {\n this.handleConnectionSuccess();\n\n // 获取工具列表\n await this.refreshTools();\n\n // 发射连接成功事件\n this.callbacks?.onConnected?.({\n serviceName: this.name,\n tools: this.getTools(),\n connectionTime: new Date(),\n });\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 console.info(`[MCP-${this.name}] MCP 服务 ${this.name} 连接已建立`);\n\n // 启动心跳检测\n this.startHeartbeat();\n }\n\n /**\n * 处理连接错误\n */\n private handleConnectionError(error: Error): void {\n this.connectionState = ConnectionState.DISCONNECTED;\n this.initialized = false;\n\n console.debug(`MCP 服务 ${this.name} 连接错误:`, error.message);\n\n // 清理连接超时定时器\n if (this.connectionTimeout) {\n clearTimeout(this.connectionTimeout);\n this.connectionTimeout = null;\n }\n\n // 清理当前连接\n this.cleanupConnection();\n\n // 发射连接失败事件\n this.callbacks?.onConnectionFailed?.({\n serviceName: this.name,\n error,\n attempt: 0,\n });\n }\n\n /**\n * 清理连接资源\n */\n private cleanupConnection(): void {\n // 停止心跳\n this.stopHeartbeat();\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 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 console.debug(\n `${this.name} 服务加载了 ${tools.length} 个工具: ${tools\n .map((t) => t.name)\n .join(\", \")}`\n );\n } catch (error) {\n console.error(\n `${this.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 console.info(`主动断开 MCP 服务 ${this.name} 连接`);\n\n // 清理连接资源\n this.cleanupConnection();\n\n // 设置状态为已断开\n this.connectionState = ConnectionState.DISCONNECTED;\n\n // 发射断开连接事件\n this.callbacks?.onDisconnected?.({\n serviceName: this.name,\n reason: \"手动断开\",\n disconnectionTime: new Date(),\n });\n }\n\n /**\n * 获取工具列表\n */\n getTools(): Tool[] {\n return Array.from(this.tools.values());\n }\n\n /**\n * 检测是否为会话过期错误\n */\n private isSessionExpiredError(error: unknown): boolean {\n if (error instanceof Error) {\n const message = error.message.toLowerCase();\n return (\n message.includes(\"session expired\") ||\n message.includes(\"会话过期\") ||\n message.includes(\"401\") ||\n message.includes(\"unauthorized\")\n );\n }\n return false;\n }\n\n /**\n * 自动重连\n */\n private async reconnect(): Promise<void> {\n this.connectionState = ConnectionState.RECONNECTING;\n console.debug(`[MCP-${this.name}] 检测到会话过期,正在重新连接...`);\n\n // 清理旧连接\n this.cleanupConnection();\n\n // 建立新连接\n return this.attemptConnection();\n }\n\n /**\n * 启动心跳检测\n */\n private async startHeartbeat(): Promise<void> {\n // STDIO 不需要心跳(进程级连接稳定)\n if (this.config.type === \"stdio\") {\n return;\n }\n\n if (!this.heartbeatConfig?.enabled) {\n return;\n }\n const interval = this.heartbeatConfig?.interval ?? 30 * 1000;\n\n this.heartbeatTimer = setInterval(() => {\n this.performHeartbeat().catch((error) => {\n console.error(\n `[MCP-${this.name}] 心跳检测执行异常:`,\n error instanceof Error ? error.message : String(error)\n );\n });\n }, interval);\n\n console.debug(`[MCP-${this.name}] 心跳检测已启动,间隔: ${interval}ms`);\n }\n\n /**\n * 执行一次心跳检查\n */\n private async performHeartbeat(): Promise<void> {\n if (!this.client) {\n return;\n }\n\n try {\n // 调用 MCP SDK 的 ping() 方法\n await this.client.ping();\n console.debug(`[MCP-${this.name}] 心跳检测成功`);\n } catch (error) {\n console.warn(\n `[MCP-${this.name}] 心跳检测失败,尝试重连...`,\n error instanceof Error ? error.message : String(error)\n );\n // 心跳失败,尝试重连\n await this.reconnect();\n }\n }\n\n /**\n * 停止心跳检测\n */\n private stopHeartbeat(): void {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n console.debug(`[MCP-${this.name}] 心跳检测已停止`);\n }\n }\n\n /**\n * 调用工具\n */\n async callTool(\n name: string,\n arguments_: Record<string, unknown>\n ): Promise<ToolCallResult> {\n if (!this.client) {\n throw new Error(`服务 ${this.name} 未连接`);\n }\n\n if (!this.tools.has(name)) {\n throw new Error(`工具 ${name} 在服务 ${this.name} 中不存在`);\n }\n\n console.debug(\n `调用 ${this.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 console.debug(\n `工具 ${name} 调用成功,结果:`,\n `${JSON.stringify(result).substring(0, 500)}...`\n );\n\n return result as ToolCallResult;\n } catch (error) {\n // 检测是否为会话过期错误\n if (this.isSessionExpiredError(error)) {\n console.warn(\n `[MCP-${this.name}] 检测到会话过期,尝试重新连接并重试...`\n );\n\n // 自动重连\n await this.reconnect();\n\n // 重试工具调用\n return await this.client.callTool({\n name,\n arguments: arguments_ || {},\n });\n }\n\n // 其他错误正常抛出\n console.error(\n `工具 ${name} 调用失败:`,\n error instanceof Error ? error.message : String(error)\n );\n throw error;\n }\n }\n\n /**\n * 获取服务配置\n */\n getConfig(): MCPServiceConfig & { name: string } {\n return {\n name: this.name,\n ...this.config,\n };\n }\n\n /**\n * 获取服务状态\n */\n getStatus(): MCPServiceStatus {\n return {\n name: this.name,\n connected: this.connectionState === ConnectionState.CONNECTED,\n initialized: this.initialized,\n transportType:\n (this.config.type as MCPTransportType) || MCPTransportType.HTTP,\n toolCount: this.tools.size,\n connectionState: this.connectionState,\n };\n }\n\n /**\n * 检查是否已连接\n */\n isConnected(): boolean {\n return (\n this.connectionState === ConnectionState.CONNECTED && this.initialized\n );\n }\n}\n","/**\n * MCP 服务管理器\n * 提供简洁的 API 来管理多个 MCP 服务\n */\n\nimport { EventEmitter } from \"node:events\";\nimport { MCPConnection } from \"./connection.js\";\nimport type { MCPServiceConfig, ToolCallResult } from \"./types.js\";\nimport { MCPTransportType } from \"./types.js\";\n\n/**\n * MCP 服务管理器\n * 提供简洁的 API 来管理多个 MCP 服务\n *\n * @example\n * ```typescript\n * const manager = new MCPManager();\n *\n * // 添加服务\n * manager.addServer('datetime', {\n * type: 'stdio',\n * command: 'node',\n * args: ['datetime.js']\n * });\n *\n * // 连接所有服务\n * await manager.connect();\n *\n * // 调用工具\n * const result = await manager.callTool('datetime', 'get_current_time', {\n * format: 'YYYY-MM-DD HH:mm:ss'\n * });\n *\n * // 断开连接\n * await manager.disconnect();\n * ```\n */\nexport class MCPManager extends EventEmitter {\n private connections: Map<string, MCPConnection> = new Map();\n private configs: Map<string, MCPServiceConfig> = new Map();\n\n constructor() {\n super();\n }\n\n /**\n * 添加 MCP 服务器配置\n * @param name 服务器名称\n * @param config 服务器配置\n *\n * @example\n * ```typescript\n * // 添加 stdio 服务\n * manager.addServer('calculator', {\n * type: 'stdio',\n * command: 'node',\n * args: ['calculator.js']\n * });\n *\n * // 添加 HTTP 服务\n * manager.addServer('web-search', {\n * type: 'http',\n * url: 'https://api.example.com/mcp',\n * headers: {\n * Authorization: 'Bearer your-api-key'\n * }\n * });\n * ```\n */\n addServer(name: string, config: MCPServiceConfig): void {\n if (this.configs.has(name)) {\n throw new Error(`服务 ${name} 已存在`);\n }\n\n // 标准化 type 字段 - 将用户友好的类型映射到实际的枚举值\n const normalizedConfig: MCPServiceConfig = { ...config };\n\n if (config.type) {\n // 首先检查用户友好的字符串类型\n const typeStr = String(config.type);\n if (typeStr === \"http\") {\n normalizedConfig.type = MCPTransportType.HTTP;\n } else if (typeStr === \"sse\") {\n normalizedConfig.type = MCPTransportType.SSE;\n } else {\n // 已经是枚举值或正确格式\n normalizedConfig.type = config.type as MCPTransportType;\n }\n }\n\n // 存储 config(不包含 name,name 已作为 Map 的 key)\n this.configs.set(name, normalizedConfig);\n }\n\n /**\n * 移除服务器配置\n * @param name 服务器名称\n */\n removeServer(name: string): boolean {\n return this.configs.delete(name);\n }\n\n /**\n * 连接所有已添加的 MCP 服务\n * 所有服务并行连接,单个服务失败不会影响其他服务\n *\n * @example\n * ```typescript\n * await manager.connect();\n * ```\n */\n async connect(): Promise<void> {\n this.emit(\"connect\");\n\n const promises = Array.from(this.configs.entries()).map(\n async ([name, config]) => {\n try {\n const connection = new MCPConnection(name, config, {\n onConnected: (data) => {\n this.emit(\"connected\", {\n serverName: data.serviceName,\n tools: data.tools,\n });\n },\n onDisconnected: (data) => {\n this.emit(\"disconnected\", {\n serverName: data.serviceName,\n reason: data.reason,\n });\n },\n onConnectionFailed: (data) => {\n this.emit(\"error\", {\n serverName: data.serviceName,\n error: data.error,\n });\n },\n });\n\n await connection.connect();\n this.connections.set(name, connection);\n } catch (error) {\n this.emit(\"error\", { serverName: name, error });\n throw error;\n }\n }\n );\n\n await Promise.allSettled(promises);\n }\n\n /**\n * 断开所有 MCP 服务连接\n *\n * @example\n * ```typescript\n * await manager.disconnect();\n * ```\n */\n async disconnect(): Promise<void> {\n const promises = Array.from(this.connections.values()).map((conn) =>\n conn.disconnect()\n );\n\n await Promise.allSettled(promises);\n this.connections.clear();\n\n this.emit(\"disconnect\");\n }\n\n /**\n * 调用指定服务的工具\n * @param serverName 服务名称\n * @param toolName 工具名称\n * @param args 工具参数\n *\n * @example\n * ```typescript\n * const result = await manager.callTool('datetime', 'get_current_time', {\n * format: 'YYYY-MM-DD HH:mm:ss'\n * });\n * ```\n */\n async callTool(\n serverName: string,\n toolName: string,\n args: Record<string, unknown>\n ): Promise<ToolCallResult> {\n const connection = this.connections.get(serverName);\n if (!connection) {\n throw new Error(`服务 ${serverName} 不存在`);\n }\n\n if (!connection.isConnected()) {\n throw new Error(`服务 ${serverName} 未连接`);\n }\n\n return connection.callTool(toolName, args);\n }\n\n /**\n * 列出所有可用的工具\n * @returns 工具列表,格式为 [{ name, serverName, description, inputSchema }]\n *\n * @example\n * ```typescript\n * const tools = manager.listTools();\n * console.log('可用工具:', tools.map(t => `${t.serverName}/${t.name}`));\n * ```\n */\n listTools(): Array<{\n name: string;\n serverName: string;\n description: string;\n inputSchema: unknown;\n }> {\n const allTools: Array<{\n name: string;\n serverName: string;\n description: string;\n inputSchema: unknown;\n }> = [];\n\n for (const [serverName, connection] of this.connections) {\n if (connection.isConnected()) {\n const tools = connection.getTools();\n for (const tool of tools) {\n allTools.push({\n name: tool.name,\n serverName,\n description: tool.description || \"\",\n inputSchema: tool.inputSchema,\n });\n }\n }\n }\n\n return allTools;\n }\n\n /**\n * 获取服务状态\n * @param serverName 服务名称\n * @returns 服务状态,如果服务不存在则返回 null\n *\n * @example\n * ```typescript\n * const status = manager.getServerStatus('datetime');\n * if (status) {\n * console.log(`已连接: ${status.connected}, 工具数: ${status.toolCount}`);\n * }\n * ```\n */\n getServerStatus(serverName: string): {\n connected: boolean;\n toolCount: number;\n } | null {\n const connection = this.connections.get(serverName);\n if (!connection) {\n return null;\n }\n\n const status = connection.getStatus();\n return {\n connected: status.connected,\n toolCount: status.toolCount,\n };\n }\n\n /**\n * 获取所有服务的状态\n * @returns 所有服务的状态映射\n *\n * @example\n * ```typescript\n * const statuses = manager.getAllServerStatus();\n * console.log(statuses);\n * // {\n * // datetime: { connected: true, toolCount: 3 },\n * // calculator: { connected: true, toolCount: 1 }\n * // }\n * ```\n */\n getAllServerStatus(): Record<\n string,\n { connected: boolean; toolCount: number }\n > {\n const statuses: Record<string, { connected: boolean; toolCount: number }> =\n {};\n\n for (const [serverName, connection] of this.connections) {\n const status = connection.getStatus();\n statuses[serverName] = {\n connected: status.connected,\n toolCount: status.toolCount,\n };\n }\n\n return statuses;\n }\n\n /**\n * 检查服务是否已连接\n * @param serverName 服务名称\n *\n * @example\n * ```typescript\n * if (manager.isConnected('datetime')) {\n * console.log('datetime 服务已连接');\n * }\n * ```\n */\n isConnected(serverName: string): boolean {\n const connection = this.connections.get(serverName);\n return connection ? connection.isConnected() : false;\n }\n\n /**\n * 获取已配置的服务列表\n * @returns 服务名称数组\n *\n * @example\n * ```typescript\n * const servers = manager.getServerNames();\n * console.log('已配置的服务:', servers);\n * ```\n */\n getServerNames(): string[] {\n return Array.from(this.configs.keys());\n }\n\n /**\n * 获取已连接的服务列表\n * @returns 已连接的服务名称数组\n *\n * @example\n * ```typescript\n * const connectedServers = manager.getConnectedServerNames();\n * console.log('已连接的服务:', connectedServers);\n * ```\n */\n getConnectedServerNames(): string[] {\n const connected: string[] = [];\n for (const [serverName, connection] of this.connections) {\n if (connection.isConnected()) {\n connected.push(serverName);\n }\n }\n return connected;\n }\n}\n\n// 为了向后兼容,保留旧的 MCPServiceManager 类名作为别名\nexport { MCPManager as MCPServiceManager };\n","/**\n * @/mcp-core\n *\n * MCP 协议核心实现库\n * 提供 MCP 服务管理、连接和工具调用的核心功能\n */\n\n// =========================\n// 类型导出\n// =========================\n\nexport type {\n // 配置相关\n MCPServiceConfig,\n ModelScopeSSEOptions,\n UnifiedServerConfig,\n // 状态相关\n MCPServiceStatus,\n MCPServiceConnectionStatus,\n ManagerStatus,\n UnifiedServerStatus,\n // 工具相关\n ToolInfo,\n EnhancedToolInfo,\n ToolCallResult,\n ToolCallParams,\n ValidatedToolCallParams,\n ToolCallValidationOptions,\n CustomMCPTool,\n JSONSchema,\n // 传输相关\n MCPServerTransport,\n // 事件相关\n MCPServiceEventCallbacks,\n} from \"./types.js\";\n\n// =========================\n// 枚举导出\n// =========================\n\nexport {\n MCPTransportType,\n ConnectionState,\n ToolCallErrorCode,\n} from \"./types.js\";\n\n// =========================\n// 类导出\n// =========================\n\nexport { ToolCallError } from \"./types.js\";\nexport { MCPConnection } from \"./connection.js\";\nexport { MCPManager, MCPServiceManager } from \"./manager.js\";\n\n// =========================\n// 传输工厂导出\n// =========================\n\nexport { TransportFactory } from \"./transport-factory.js\";\n\n// =========================\n// 工具函数导出\n// =========================\n\nexport {\n TypeFieldNormalizer,\n normalizeTypeField,\n validateToolCallParams,\n inferTransportTypeFromUrl,\n inferTransportTypeFromConfig,\n} from \"./utils/index.js\";\n\n// =========================\n// 类型守卫导出\n// =========================\n\nexport {\n isValidToolJSONSchema,\n ensureToolJSONSchema,\n} from \"./types.js\";\n","/**\n * 配置适配器\n * 将旧的配置格式转换为新的 MCPServiceConfig 格式,确保向后兼容性\n */\n\nimport { dirname, isAbsolute, resolve } from \"node:path\";\nimport { MCPTransportType, inferTransportTypeFromUrl } from \"@/mcp-core\";\nimport type {\n HTTPMCPServerConfig,\n LocalMCPServerConfig,\n MCPServerConfig,\n SSEMCPServerConfig,\n} from \"./manager.js\";\nimport { ConfigResolver } from \"./resolver.js\";\n\n// 从外部导入 MCP 类型(这些类型将在运行时从 backend 包解析)\n// 为了避免循环依赖,这里使用动态导入的方式\n// 在实际使用时,adapter 将作为 config 包的一部分被使用\n\n/**\n * 配置验证错误类\n */\nexport class ConfigValidationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ConfigValidationError\";\n }\n}\n\n// 定义简化的 MCPServiceConfig 接口\nexport interface MCPServiceConfig {\n type: MCPTransportType;\n command?: string;\n args?: string[];\n env?: Record<string, string>;\n url?: string;\n headers?: Record<string, string>;\n}\n\n/**\n * 将各种配置格式标准化为统一的服务配置格式\n */\nexport function normalizeServiceConfig(\n config: MCPServerConfig\n): MCPServiceConfig {\n console.log(\"转换配置\", { config });\n\n try {\n // 验证输入参数\n if (!config || typeof config !== \"object\") {\n throw new ConfigValidationError(\"配置对象不能为空\");\n }\n\n // 根据配置类型进行转换\n const newConfig = convertByConfigType(config);\n\n // 验证转换后的配置\n validateNewConfig(newConfig);\n\n console.log(\"配置转换成功\", { type: newConfig.type });\n return newConfig;\n } catch (error) {\n console.error(\"配置转换失败\", { error });\n throw error instanceof ConfigValidationError\n ? error\n : new ConfigValidationError(\n `配置转换失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n}\n\n/**\n * 根据配置类型进行转换\n */\nfunction convertByConfigType(config: MCPServerConfig): MCPServiceConfig {\n // 检查是否为本地 stdio 配置(最高优先级)\n if (isLocalConfig(config)) {\n return convertLocalConfig(config);\n }\n\n // 检查是否有显式指定的类型\n if (\"type\" in config) {\n switch (config.type) {\n case \"sse\":\n return convertSSEConfig(config);\n case \"http\":\n case \"streamable-http\": // 向后兼容\n return convertHTTPConfig(config);\n default:\n throw new ConfigValidationError(`不支持的传输类型: ${config.type}`);\n }\n }\n\n // 检查是否为网络配置(自动推断类型)\n if (\"url\" in config) {\n // 如果 URL 是 undefined 或 null,抛出错误\n if (config.url === undefined || config.url === null) {\n throw new ConfigValidationError(\"网络配置必须包含有效的 url 字段\");\n }\n\n // 先推断类型,然后根据推断的类型选择正确的转换函数\n const inferredType = inferTransportTypeFromUrl(config.url || \"\");\n\n if (inferredType === MCPTransportType.SSE) {\n // 为SSE类型添加显式type字段\n const sseConfig = { ...config, type: \"sse\" as const };\n return convertSSEConfig(sseConfig);\n }\n // 为HTTP类型添加显式type字段\n const httpConfig = { ...config, type: \"http\" as const };\n return convertHTTPConfig(httpConfig);\n }\n\n throw new ConfigValidationError(\"无法识别的配置类型\");\n}\n\n/**\n * 转换本地 stdio 配置\n */\nfunction convertLocalConfig(config: MCPServerConfig): MCPServiceConfig {\n // 类型守卫:确保是 LocalMCPServerConfig\n if (!isLocalConfig(config)) {\n throw new ConfigValidationError(\"无效的本地配置类型\");\n }\n\n const { command, args, env } = config;\n\n if (!command) {\n throw new ConfigValidationError(\"本地配置必须包含 command 字段\");\n }\n\n // 获取配置文件所在目录作为工作目录\n // 优先使用环境变量,否则查找配置文件所在目录,最后回退到当前工作目录\n let workingDir: string;\n if (process.env.XIAOZHI_CONFIG_DIR) {\n workingDir = process.env.XIAOZHI_CONFIG_DIR;\n } else {\n // 使用 ConfigResolver 查找配置文件路径\n const configPath = ConfigResolver.resolveConfigPath();\n if (configPath) {\n // 获取配置文件所在目录\n workingDir = dirname(configPath);\n } else {\n // 回退到当前工作目录\n workingDir = process.cwd();\n }\n }\n\n // 解析 command 中的相对路径\n let resolvedCommand = command;\n if (isRelativePath(command)) {\n resolvedCommand = resolve(workingDir, command);\n console.log(\"解析 command 相对路径\", {\n command,\n resolvedCommand,\n workingDir,\n });\n }\n\n // 解析 args 中的相对路径\n const resolvedArgs = (args || []).map((arg: string) => {\n // 检查是否为相对路径(以 ./ 开头或不以 / 开头且包含文件扩展名)\n if (isRelativePath(arg)) {\n const resolvedPath = resolve(workingDir, arg);\n console.log(\"解析相对路径\", { arg, resolvedPath, workingDir });\n return resolvedPath;\n }\n return arg;\n });\n\n return {\n type: MCPTransportType.STDIO,\n command: resolvedCommand,\n args: resolvedArgs,\n ...(env !== undefined && { env }), // 只在 env 存在时添加该属性\n };\n}\n\n/**\n * 转换 SSE 配置\n */\nfunction convertSSEConfig(config: MCPServerConfig): MCPServiceConfig {\n // 使用类型守卫确保 config 包含必要的属性\n if (!isURLConfig(config)) {\n throw new ConfigValidationError(\"SSE 配置必须包含 url 字段\");\n }\n\n const url = config.url;\n const type = \"type\" in config ? config.type : undefined;\n const headers = \"headers\" in config ? config.headers : undefined;\n\n // 优先使用显式指定的类型,如果没有则进行推断\n const inferredType =\n type === \"sse\"\n ? MCPTransportType.SSE\n : inferTransportTypeFromUrl(url || \"\");\n const isModelScope = url ? isModelScopeURL(url) : false;\n\n console.log(\"SSE配置转换\", {\n url,\n inferredType,\n isModelScope,\n });\n\n return {\n type: inferredType,\n url,\n headers,\n };\n}\n\n/**\n * 转换 HTTP 配置\n */\nfunction convertHTTPConfig(config: MCPServerConfig): MCPServiceConfig {\n // 使用类型守卫确保 config 包含必要的属性\n if (!isURLConfig(config)) {\n throw new ConfigValidationError(\"HTTP 配置必须包含 url 字段\");\n }\n\n const url = config.url;\n const headers = \"headers\" in config ? config.headers : undefined;\n\n return {\n type: MCPTransportType.HTTP,\n url: url || \"\",\n headers,\n };\n}\n\n/**\n * 批量标准化配置\n */\nexport function normalizeServiceConfigBatch(\n legacyConfigs: Record<string, MCPServerConfig>\n): Record<string, MCPServiceConfig> {\n const newConfigs: Record<string, MCPServiceConfig> = {};\n const errors: Array<{ error: Error }> = [];\n\n for (const [name, config] of Object.entries(legacyConfigs)) {\n try {\n newConfigs[name] = normalizeServiceConfig(config);\n } catch (error) {\n errors.push({\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(({ error }, index) => `[${index}]: ${error.message}`)\n .join(\"; \");\n throw new ConfigValidationError(`批量配置转换失败: ${errorMessages}`);\n }\n\n console.log(\"批量配置转换成功\", { count: Object.keys(newConfigs).length });\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 * 检查是否为 URL 配置(SSE 或 HTTP)\n * 类型守卫函数,用于验证配置包含 url 属性\n */\nfunction isURLConfig(\n config: MCPServerConfig\n): config is (SSEMCPServerConfig | HTTPMCPServerConfig) & { url: string } {\n return \"url\" in config && typeof config.url === \"string\";\n}\n\n/**\n * 检查是否为 ModelScope URL\n * 使用 URL hostname 检测而非简单的字符串包含检查,防止安全绕过\n */\nexport function isModelScopeURL(url: string): boolean {\n try {\n const parsedUrl = new URL(url);\n const hostname = parsedUrl.hostname.toLowerCase();\n return (\n hostname.endsWith(\".modelscope.net\") ||\n hostname.endsWith(\".modelscope.cn\") ||\n hostname === \"modelscope.net\" ||\n hostname === \"modelscope.cn\"\n );\n } catch {\n return false;\n }\n}\n\n/**\n * 验证新配置格式\n */\nfunction validateNewConfig(config: MCPServiceConfig): void {\n if (config.type && !Object.values(MCPTransportType).includes(config.type)) {\n throw new ConfigValidationError(`无效的传输类型: ${config.type}`);\n }\n\n // 根据传输类型验证必需字段\n if (!config.type) {\n throw new ConfigValidationError(\"传输类型未指定,请检查配置或启用自动推断\");\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 // SSE 配置必须有 URL(即使是空字符串也会被推断为 HTTP)\n if (config.url === undefined || config.url === null) {\n throw new ConfigValidationError(\"SSE 配置必须包含 url 字段\");\n }\n break;\n\n case MCPTransportType.HTTP:\n // HTTP 配置允许空 URL,会在后续处理中设置默认值\n // 只有当 URL 完全不存在时才报错\n if (config.url === undefined || config.url === null) {\n throw new ConfigValidationError(\"HTTP 配置必须包含 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\n if (\"url\" in config) {\n // 检查是否为显式 http 配置\n if (\n \"type\" in config &&\n (config.type === \"http\" || config.type === \"streamable-http\")\n ) {\n return `HTTP (${config.url})`;\n }\n\n // 检查是否为显式 sse 配置\n if (\"type\" in config && config.type === \"sse\") {\n const isModelScope = isModelScopeURL(config.url);\n return `SSE${isModelScope ? \" (ModelScope)\" : \"\"} (${config.url})`;\n }\n\n // 对于只有 url 的配置,根据路径推断类型\n const inferredType = inferTransportTypeFromUrl(config.url);\n const isModelScope = isModelScopeURL(config.url);\n\n if (inferredType === MCPTransportType.SSE) {\n return `SSE${isModelScope ? \" (ModelScope)\" : \"\"} (${config.url})`;\n }\n return `HTTP (${config.url})`;\n }\n\n return \"未知\";\n}\n\n// 重新导出 MCPTransportType 以保持向后兼容\nexport { MCPTransportType };\n","/**\n * 配置初始化器\n * 负责在用户家目录创建默认配置\n */\n\nimport {\n copyFileSync,\n existsSync,\n mkdirSync,\n readdirSync,\n statSync,\n} from \"node:fs\";\nimport path from \"node:path\";\nimport { dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n/**\n * 配置初始化器类\n * 负责在用户家目录创建完整的默认项目目录\n */\nexport class ConfigInitializer {\n /**\n * 初始化默认配置\n *\n * 复制整个默认模板目录到用户家目录的 .xiaozhi-client\n * 这包括 mcpServers/ 目录和其他必要文件\n *\n * @returns 创建的项目目录路径\n * @throws 如果无法获取用户家目录或默认配置模板不存在\n */\n static async initializeDefaultConfig(): Promise<string> {\n const homeDir = process.env.HOME || process.env.USERPROFILE;\n if (!homeDir) {\n throw new Error(\"无法获取用户家目录\");\n }\n\n const xiaozhiClientDir = path.join(homeDir, \".xiaozhi-client\");\n\n // 如果目录已存在,直接使用现有配置目录,避免删除用户数据\n if (existsSync(xiaozhiClientDir)) {\n return xiaozhiClientDir;\n }\n\n // 创建目录\n mkdirSync(xiaozhiClientDir, { recursive: true });\n\n // 获取默认模板目录路径\n const defaultTemplateDir = ConfigInitializer.getDefaultTemplateDir();\n if (!defaultTemplateDir) {\n throw new Error(\"默认配置模板不存在,请检查项目模板文件是否存在\");\n }\n\n // 复制整个模板目录\n ConfigInitializer.copyDirectoryRecursive(\n defaultTemplateDir,\n xiaozhiClientDir,\n [\"template.json\", \".git\", \"node_modules\"]\n );\n\n return xiaozhiClientDir;\n }\n\n /**\n * 递归复制目录\n *\n * @param srcDir 源目录\n * @param destDir 目标目录\n * @param exclude 要排除的文件/目录列表\n */\n private static copyDirectoryRecursive(\n srcDir: string,\n destDir: string,\n exclude: string[] = []\n ): void {\n const items = readdirSync(srcDir);\n\n for (const item of items) {\n // 跳过排除列表中的项\n if (exclude.includes(item)) {\n continue;\n }\n\n const srcPath = path.join(srcDir, item);\n const destPath = path.join(destDir, item);\n const stat = statSync(srcPath);\n\n if (stat.isDirectory()) {\n // 递归复制子目录\n mkdirSync(destPath, { recursive: true });\n ConfigInitializer.copyDirectoryRecursive(srcPath, destPath, exclude);\n } else {\n // 复制文件\n copyFileSync(srcPath, destPath);\n }\n }\n }\n\n /**\n * 获取默认模板目录路径\n *\n * 在多个可能的路径中查找默认模板目录\n *\n * @returns 找到的默认模板目录路径,如果都不存在则返回 null\n */\n private static getDefaultTemplateDir(): string | null {\n const possiblePaths = [\n // 迁移后:src/config/ 或 dist/config/ → 项目根 templates/default/\n resolve(__dirname, \"..\", \"..\", \"templates\", \"default\"),\n // 从 CWD 查找(兼容各种启动场景)\n resolve(process.cwd(), \"templates\", \"default\"),\n ];\n\n for (const p of possiblePaths) {\n if (existsSync(p)) {\n return p;\n }\n }\n\n return null;\n }\n}\n","/**\n * @/config\n *\n * 小智客户端配置管理库\n *\n * 此库提供了配置文件解析、验证和管理的完整功能,包括:\n * - ConfigManager: 配置管理器,负责配置文件的加载、保存和验证\n * - ConfigResolver: 配置解析器,按优先级查找配置文件\n * - ConfigInitializer: 配置初始化器,负责创建默认配置\n * - 配置适配与转换工具: 提供旧配置向新格式迁移、规范化(例如 normalizeServiceConfig 等)\n * - JSON5 读写工具: 提供 JSON5 格式的读写支持\n *\n * @example\n * ```typescript\n * import { configManager } from '@/config';\n *\n * // 获取配置\n * const config = configManager.getConfig();\n *\n * // 更新 MCP 端点配置\n * configManager.updateMcpEndpoint('wss://api.example.com/mcp');\n * ```\n */\n\n// =========================\n// 导出\n// =========================\n\nexport * from \"./manager.js\";\nexport * from \"./adapter.js\";\nexport * from \"./resolver.js\";\nexport * from \"./initializer.js\";\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 PAGINATION_CONSTANTS = {\n /** 默认每页记录数 */\n DEFAULT_LIMIT: 50,\n /** 最大每页记录数 */\n MAX_LIMIT: 200,\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\";\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 fs from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport path from \"node:path\";\nimport type { FileOperationOptions } from \"../Types\";\nimport { FileError } from \"../errors/index\";\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 || tmpdir();\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\";\nimport { FileUtils } from \"./FileUtils\";\n\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 // 构建环境:dist/cli/index.js -> dist/backend/templates\n path.join(scriptDir, \"..\", \"backend\", 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 * 兼容开发和构建两种环境:\n * - 开发环境:脚本位于 src/cli/ 下,需向上 3 级\n * - 构建环境:脚本位于 dist/cli/ 下,需向上 2 级\n */\n static getProjectRoot(): string {\n const scriptDir = PathUtils.getScriptDir();\n // 构建产物在 dist/cli/ 下,向上 2 级即可到达项目根\n if (scriptDir.endsWith(\"/dist/cli\") || scriptDir.endsWith(\"\\\\dist\\\\cli\")) {\n return path.join(scriptDir, \"..\", \"..\");\n }\n // 开发环境 src/cli/utils 下,向上 3 级到达项目根\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 * 同时支持 Unix (/) 和 Windows (\\) 分隔符\n */\n static validatePath(inputPath: string): boolean {\n const normalizedPath = path.normalize(inputPath);\n // 按多种分隔符拆分路径段,检查是否包含严格等于 \"..\" 的段\n const segments = normalizedPath.split(/[/\\\\]/);\n return !segments.includes(\"..\");\n }\n\n /**\n * 确保路径在指定目录内\n * 使用 path.relative 判断,避免前缀匹配被绕过(如 /safe/base2 匹配 /safe/base)\n */\n static ensurePathWithin(inputPath: string, baseDir: string): string {\n const resolvedPath = path.resolve(baseDir, inputPath);\n const resolvedBase = path.resolve(baseDir);\n\n // 使用 path.relative 检查相对路径是否以 \"..\" 开头或为绝对路径\n const relativePath = path.relative(resolvedBase, resolvedPath);\n if (relativePath.startsWith(\"..\") || path.isAbsolute(relativePath)) {\n throw new Error(`路径 ${inputPath} 超出了允许的范围`);\n }\n\n return resolvedPath;\n }\n\n /**\n * 获取可执行文件路径\n * 对于 CLI 自身复用,直接返回当前脚本路径;其他名称从项目根目录的 dist 中查找\n */\n static getExecutablePath(name: string): string {\n // CLI 自身复用:直接返回当前执行的脚本路径\n if (name === \"cli\") {\n const cliPath = process.argv[1];\n if (cliPath) {\n try {\n return realpathSync(cliPath);\n } catch {\n return cliPath;\n }\n }\n // 回退:无法获取时抛出明确错误\n throw new Error(\"无法确定 CLI 脚本路径\");\n }\n\n // 其他可执行文件:从项目根目录的 dist 中查找\n const projectRoot = PathUtils.getProjectRoot();\n return path.join(projectRoot, \"dist\", `${name}.js`);\n }\n\n /**\n * 获取 Web 服务器启动器路径\n * 返回项目根目录 dist/backend 下的 WebServerLauncher.js\n */\n static getWebServerLauncherPath(): string {\n const projectRoot = PathUtils.getProjectRoot();\n return path.join(projectRoot, \"dist\", \"backend\", \"WebServerLauncher.js\");\n }\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 const hasTraversal = normalizedPath.split(/[/\\\\]/).includes(\"..\");\n if (hasTraversal || 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\";\nimport type { Platform } from \"../Types\";\nimport { ProcessError } from \"../errors/index\";\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\";\nimport { ValidationError } from \"../errors/index\";\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(\n value: string | number | boolean | object | null | undefined,\n fieldName: string\n ): 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\"): unknown {\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<T>(\n array: T[],\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, unknown>,\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 * 负责管理 xiaozhi 服务的进程生命周期,包括:\n * - 进程启动和停止\n * - PID 文件管理\n * - 进程状态查询\n * - 优雅关闭进程\n *\n * @module src/cli/services/ProcessManager\n */\n\nimport { FileError, ProcessError } from \"../errors/index\";\nimport type {\n ProcessManager as IProcessManager,\n ServiceStatus,\n} from \"../interfaces/Service\";\nimport { FileUtils } from \"../utils/FileUtils\";\nimport { FormatUtils } from \"../utils/FormatUtils\";\nimport { PathUtils } from \"../utils/PathUtils\";\nimport { PlatformUtils } from \"../utils/PlatformUtils\";\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 await PlatformUtils.killProcess(pid, \"SIGTERM\");\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 * 负责管理 xiaozhi 服务的守护进程,包括:\n * - 守护进程启动和停止\n * - 日志文件管理\n * - 进程状态监控\n * - 支持手动重启\n *\n * @module src/cli/services/DaemonManager\n */\n\nimport type { ChildProcess } from \"node:child_process\";\nimport { spawn } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport consola from \"consola\";\nimport { RETRY_CONSTANTS } from \"../Constants\";\nimport { ProcessError, ServiceError } from \"../errors/index\";\nimport type {\n DaemonManager as IDaemonManager,\n ProcessManager,\n} from \"../interfaces/Service\";\nimport { PathUtils } from \"../utils/PathUtils\";\nimport { PlatformUtils } from \"../utils/PlatformUtils\";\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(private processManager: ProcessManager) {}\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 consola.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 consola.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) =>\n setTimeout(resolve, RETRY_CONSTANTS.DEFAULT_INTERVAL)\n );\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.once(\"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.getWebServerLauncherPath();\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 consola.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 consola.error(`守护进程异常退出 (代码: ${code}, 信号: ${signal})`);\n } else {\n consola.info(\"守护进程正常退出\");\n }\n\n // 清理 PID 文件\n this.processManager.cleanupPidFile();\n this.currentDaemon = null;\n });\n\n // 监听进程错误\n child.on(\"error\", (error) => {\n consola.error(`守护进程错误: ${error.message}`);\n this.processManager.cleanupPidFile();\n this.currentDaemon = null;\n });\n\n // 监听进程断开连接\n child.on(\"disconnect\", () => {\n consola.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 consola.warn(\n `清理守护进程失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n this.currentDaemon = null;\n }\n }\n}\n","/**\n * 服务管理服务\n *\n * 负责管理 xiaozhi 服务的生命周期,包括:\n * - 服务启动和停止\n * - 进程状态查询\n * - 配置验证和初始化\n * - 多种运行模式支持(normal、mcp-server,均以守护进程方式运行)\n *\n * @module src/cli/services/ServiceManager\n */\n\nimport consola from \"consola\";\nimport type { ConfigManager } from \"../../config\";\nimport { ConfigInitializer } from \"../../config\";\nimport { RETRY_CONSTANTS } from \"../Constants\";\nimport { ConfigError, ServiceError } from \"../errors/index\";\nimport type {\n ServiceManager as IServiceManager,\n ProcessManager,\n ServiceStartOptions,\n ServiceStatus,\n} from \"../interfaces/Service\";\nimport { PathUtils } from \"../utils/PathUtils\";\nimport { Validation } from \"../utils/Validation\";\n\n/**\n * 服务管理器实现\n */\nexport class ServiceManagerImpl implements IServiceManager {\n constructor(\n private processManager: ProcessManager,\n private configManager: ConfigManager\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 consola.info(\n `检测到服务已在运行 (PID: ${status.pid}),正在自动重启...`\n );\n\n try {\n // 优雅停止现有进程\n await this.processManager.gracefulKillProcess(status.pid || 0);\n\n // 清理 PID 文件\n this.processManager.cleanupPidFile();\n\n // 等待一下确保完全停止\n await new Promise((resolve) =>\n setTimeout(resolve, RETRY_CONSTANTS.DEFAULT_INTERVAL)\n );\n\n consola.success(\"现有服务已停止,正在启动新服务...\");\n } catch (stopError) {\n consola.warn(\n `停止现有服务时出现警告: ${stopError instanceof Error ? stopError.message : String(stopError)}`\n );\n // 继续尝试启动新服务,因为旧进程可能已经不存在了\n }\n }\n\n // 检查环境配置\n await this.checkEnvironment();\n\n // 根据模式启动服务\n switch (options.mode) {\n case \"mcp-server\":\n await this.startMcpServerMode(options);\n break;\n case \"stdio\":\n // stdio 模式已废弃,改为启动 Web 服务\n await this.startNormalMode(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 || 0);\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) =>\n setTimeout(resolve, RETRY_CONSTANTS.DEFAULT_INTERVAL)\n );\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 async checkEnvironment(): Promise<void> {\n // 检查配置文件是否存在\n if (!this.configManager.configExists()) {\n // 尝试初始化默认配置\n try {\n consola.info(\"未找到配置文件,正在创建默认配置...\");\n\n const configPath = await ConfigInitializer.initializeDefaultConfig();\n\n consola.success(`默认配置已创建: ${configPath}`);\n consola.info(\"提示: 您可以稍后编辑此配置文件以自定义设置\");\n\n // 重新加载配置管理器\n this.configManager.reloadConfig();\n } catch (error) {\n // 保留原始错误信息,方便调试\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n consola.error(`创建默认配置失败: ${errorMessage}`);\n\n // 抛出包含原始错误信息的异常\n throw new ConfigError(\n `无法创建默认配置: ${errorMessage}\\n请手动运行 'xiaozhi create' 创建配置文件`\n );\n }\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 await this.startWebServerInDaemon();\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 // 始终以守护进程方式启动\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 || 0, \"daemon\");\n\n // 完全分离子进程\n child.unref();\n\n // 输出启动信息后立即退出父进程\n consola.success(\n `MCP Server 已在后台启动 (PID: ${child.pid}, Port: ${port})`\n );\n consola.info(\"使用 'xiaozhi status' 查看状态\");\n\n // 立即退出父进程,释放终端控制权\n process.exit(0);\n }\n\n /**\n * 后台模式启动 WebServer\n */\n private async startWebServerInDaemon(): Promise<void> {\n const { spawn } = await import(\"node:child_process\");\n const webServerPath = PathUtils.getWebServerLauncherPath();\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\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 // 同步检查 spawn 是否成功(失败时 pid 为 undefined)\n if (!child.pid) {\n throw new ServiceError(\n \"无法创建守护进程(node 启动失败),请检查 Node.js 安装是否正常\"\n );\n }\n\n // 保存 PID 信息\n this.processManager.savePidInfo(child.pid, \"daemon\");\n\n // 完全分离子进程\n child.unref();\n\n // 输出启动信息后立即退出父进程\n consola.success(`后台服务已启动 (PID: ${child.pid})`);\n consola.info(\"使用 'xiaozhi status' 查看状态\");\n consola.info(\"使用 'xiaozhi attach' 查看日志\");\n\n // 立即退出父进程,释放终端控制权\n process.exit(0);\n }\n}\n","/**\n * 模板管理服务\n *\n * 负责管理项目模板,包括:\n * - 模板列表查询\n * - 模板信息获取\n * - 项目创建和复制\n * - 模板变量替换\n * - 模板验证\n *\n * @module src/cli/services/TemplateManager\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { FileError, ValidationError } from \"../errors/index\";\nimport type {\n TemplateManager as ITemplateManager,\n TemplateCreateOptions,\n TemplateInfo,\n} from \"../interfaces/Service\";\nimport { FileUtils } from \"../utils/FileUtils\";\nimport { PathUtils } from \"../utils/PathUtils\";\nimport { Validation } from \"../utils/Validation\";\n\n// 重新导出类型以保持向后兼容\nexport type { TemplateInfo, TemplateCreateOptions };\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 * 当 templateName 为 undefined 时使用默认模板,为 null 时创建基本项目(仅配置文件)\n */\n async createProject(options: TemplateCreateOptions): Promise<void> {\n try {\n // 验证输入参数\n this.validateCreateOptions(options);\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 const templateName = options.templateName ?? \"default\";\n\n if (options.templateName === null) {\n // 基本项目模式:仅创建基础配置文件\n await this.createBasicProjectFiles(targetPath, options);\n } else {\n // 模板模式:使用指定或默认模板\n const templateInfo = await this.getTemplateInfo(templateName);\n\n if (!templateInfo) {\n throw new FileError(`模板不存在: ${templateName}`, \"\");\n }\n\n // 复制模板文件\n await this.copyTemplateFiles(templateInfo, targetPath, options);\n\n // 处理模板变量替换\n await this.processTemplateVariables(targetPath, options);\n }\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 // 仅当 templateName 有值时验证(null 表示基本项目模式,不验证)\n if (options.templateName !== undefined && options.templateName !== null) {\n Validation.validateTemplateName(options.templateName);\n }\n }\n\n /**\n * 创建基本项目文件(无模板,仅基础配置文件)\n */\n private async createBasicProjectFiles(\n targetPath: string,\n options: TemplateCreateOptions\n ): Promise<void> {\n // 创建基本配置文件\n const configContent = JSON.stringify(\n {\n name: options.projectName,\n version: \"1.0.0\",\n description: `${options.projectName} 项目`,\n },\n null,\n 2\n );\n FileUtils.writeFile(\n path.join(targetPath, \"xiaozhi.config.json\"),\n configContent,\n { overwrite: true }\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 // 将路径分隔符统一为 /,确保在 Windows 上也能正确匹配\n const relativePath = path\n .relative(basePath, file)\n .split(path.sep)\n .join(\"/\");\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 type { Command } from \"commander\";\nimport type { CommandArguments, CommandOptions } from \"./CommandTypes\";\nimport type { IDIContainer } from \"./Config\";\n\n/**\n * 命令处理器接口\n */\nexport interface CommandHandler {\n /** 命令名称 */\n name: string;\n /** 命令描述 */\n description: string;\n /** 命令选项 */\n options?: CommandOption[];\n /** 子命令 */\n subcommands?: SubCommand[];\n /** 执行命令 */\n execute(args: CommandArguments, options: CommandOptions): Promise<void>;\n}\n\n/**\n * 命令选项接口\n */\nexport interface CommandOption {\n /** 选项标志 */\n flags: string;\n /** 选项描述 */\n description: string;\n /** 默认值(限制为 Commander.js 支持的类型) */\n defaultValue?: string | boolean | string[];\n}\n\n/**\n * 子命令接口\n */\nexport interface SubCommand {\n /** 子命令名称 */\n name: string;\n /** 子命令描述 */\n description: string;\n /** 子命令选项 */\n options?: CommandOption[];\n /** 执行子命令 */\n execute(args: CommandArguments, options: CommandOptions): Promise<void>;\n}\n\n/**\n * 命令执行上下文\n */\nexport interface CommandContext {\n /** DI 容器 */\n container: IDIContainer;\n /** 命令行参数 */\n args: CommandArguments;\n /** 命令选项 */\n options: CommandOptions;\n}\n\n/**\n * 基础命令处理器抽象类\n */\nexport abstract class BaseCommandHandler implements CommandHandler {\n abstract name: string;\n abstract description: string;\n options?: CommandOption[];\n subcommands?: SubCommand[];\n\n constructor(protected container: IDIContainer) {}\n\n abstract execute(\n args: CommandArguments,\n options: CommandOptions\n ): Promise<void>;\n\n /**\n * 获取服务实例\n */\n protected getService<T>(serviceName: string): T {\n return this.container.get(serviceName) as T;\n }\n\n /**\n * 处理错误\n */\n protected handleError(error: Error): void {\n const errorHandler = this.getService<unknown>(\"errorHandler\");\n // 类型断言:errorHandler 应该有 handle 方法\n const handler = errorHandler as { handle: (error: Error) => void };\n handler.handle(error);\n }\n\n /**\n * 验证参数\n */\n protected validateArgs(args: CommandArguments, expectedCount: number): void {\n if (args.length < expectedCount) {\n throw new Error(\n `命令需要至少 ${expectedCount} 个参数,但只提供了 ${args.length} 个`\n );\n }\n }\n}\n\n/**\n * 命令注册器接口\n */\nexport interface ICommandRegistry {\n /** 注册所有命令到 Commander 程序 */\n registerCommands(program: Command): Promise<void>;\n /** 注册单个命令 */\n registerCommand(program: Command, handler: CommandHandler): void;\n /** 注册命令处理器 */\n registerHandler(handler: CommandHandler): void;\n}\n\n/**\n * 命令处理器工厂接口\n */\nexport interface ICommandHandlerFactory {\n /** 创建所有命令处理器 */\n createHandlers(): CommandHandler[];\n /** 创建指定类型的命令处理器 */\n createHandler(type: string): CommandHandler;\n}\n","/**\n * 服务管理命令处理器\n */\n\nimport consola from \"consola\";\nimport type { SubCommand } from \"../interfaces/Command\";\nimport { BaseCommandHandler } from \"../interfaces/Command\";\nimport type {\n CommandArguments,\n CommandOptions,\n} from \"../interfaces/CommandTypes\";\nimport type { IDIContainer } from \"../interfaces/Config\";\n\n/**\n * 服务管理命令处理器\n */\nexport class ServiceCommandHandler extends BaseCommandHandler {\n override name = \"service\";\n override description = \"服务管理命令\";\n\n override subcommands: SubCommand[] = [\n {\n name: \"start\",\n description: \"启动服务\",\n options: [\n { flags: \"-d, --daemon\", description: \"在后台运行服务\" },\n { flags: \"--debug\", description: \"启用调试模式 (输出DEBUG级别日志)\" },\n {\n flags: \"--stdio\",\n description: \"以 stdio 模式运行 MCP Server (用于 Cursor 等客户端)\",\n },\n ],\n execute: async (args: CommandArguments, options: CommandOptions) => {\n await this.handleStart(options);\n },\n },\n {\n name: \"stop\",\n description: \"停止服务\",\n execute: async (args: CommandArguments, options: CommandOptions) => {\n await this.handleStop();\n },\n },\n {\n name: \"status\",\n description: \"检查服务状态\",\n execute: async (args: CommandArguments, options: CommandOptions) => {\n await this.handleStatus();\n },\n },\n {\n name: \"restart\",\n description: \"重启服务\",\n options: [{ flags: \"-d, --daemon\", description: \"在后台运行服务\" }],\n execute: async (args: CommandArguments, options: CommandOptions) => {\n await this.handleRestart(options);\n },\n },\n {\n name: \"attach\",\n description: \"连接到后台服务查看日志\",\n execute: async (args: CommandArguments, options: CommandOptions) => {\n await this.handleAttach();\n },\n },\n ];\n\n constructor(container: IDIContainer) {\n super(container);\n }\n\n /**\n * 主命令执行(显示帮助)\n */\n override async execute(\n args: CommandArguments,\n options: CommandOptions\n ): Promise<void> {\n console.log(\"服务管理命令。使用 --help 查看可用的子命令。\");\n }\n\n /**\n * 处理启动命令\n */\n private async handleStart(options: CommandOptions): Promise<void> {\n try {\n // 处理--debug参数\n if (options.debug) {\n consola.level = 5; // debug 级别\n }\n\n const serviceManager = this.getService<any>(\"serviceManager\");\n\n if (options.stdio) {\n // stdio 模式已迁移到 HTTP 方式\n this.showStdioMigrationGuide();\n return;\n }\n\n // 传统模式\n await serviceManager.start({\n daemon: options.daemon || false,\n });\n } catch (error) {\n this.handleError(error as Error);\n }\n }\n\n /**\n * 处理停止命令\n */\n private async handleStop(): Promise<void> {\n try {\n const serviceManager = this.getService<any>(\"serviceManager\");\n await serviceManager.stop();\n } catch (error) {\n this.handleError(error as Error);\n }\n }\n\n /**\n * 处理状态检查命令\n */\n private async handleStatus(): Promise<void> {\n try {\n const serviceManager = this.getService<any>(\"serviceManager\");\n const status = await serviceManager.getStatus();\n\n if (status.running) {\n console.log(`✅ 服务正在运行 (PID: ${status.pid})`);\n if (status.uptime) {\n console.log(`⏱️ 运行时间: ${status.uptime}`);\n }\n if (status.mode) {\n console.log(`🔧 运行模式: ${status.mode}`);\n }\n } else {\n console.log(\"❌ 服务未运行\");\n }\n } catch (error) {\n this.handleError(error as Error);\n }\n }\n\n /**\n * 处理重启命令\n */\n private async handleRestart(options: CommandOptions): Promise<void> {\n try {\n const serviceManager = this.getService<any>(\"serviceManager\");\n await serviceManager.restart({\n daemon: options.daemon || false,\n });\n } catch (error) {\n this.handleError(error as Error);\n }\n }\n\n /**\n * 处理附加命令\n */\n private async handleAttach(): Promise<void> {\n try {\n const daemonManager = this.getService<any>(\"daemonManager\");\n await daemonManager.attachToLogs();\n } catch (error) {\n this.handleError(error as Error);\n }\n }\n\n /**\n * 显示 stdio 模式迁移指南\n */\n private showStdioMigrationGuide(): void {\n console.log(\"\\n❌ stdio 模式已废弃\\n\");\n console.log(\"小智客户端已迁移到纯 HTTP 架构,请使用以下方式:\\n\");\n\n console.log(\"1. 启动 Web 服务:\");\n console.log(\" xiaozhi start\\n\");\n\n console.log(\"2. 在 Cursor 中配置 HTTP 端点:\");\n console.log(' \"mcpServers\": {');\n console.log(' \"xiaozhi-client\": {');\n console.log(' \"type\": \"streamableHttp\",');\n console.log(' \"url\": \"http://localhost:9999/mcp\"');\n console.log(\" }\");\n console.log(\" }\\n\");\n }\n}\n","/**\n * 配置管理命令处理器\n */\n\nimport path from \"node:path\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport type { Ora } from \"ora\";\nimport type { SubCommand } from \"../interfaces/Command\";\nimport { BaseCommandHandler } from \"../interfaces/Command\";\nimport type {\n CommandArguments,\n CommandOptions,\n} from \"../interfaces/CommandTypes\";\nimport type { IDIContainer } from \"../interfaces/Config\";\n\n/**\n * 配置管理命令处理器\n */\nexport class ConfigCommandHandler extends BaseCommandHandler {\n override name = \"config\";\n override description = \"配置管理命令\";\n\n override subcommands: SubCommand[] = [\n {\n name: \"init\",\n description: \"初始化配置文件\",\n options: [\n {\n flags: \"-f, --format <format>\",\n description: \"配置文件格式 (json, json5, jsonc)\",\n defaultValue: \"json\",\n },\n ],\n execute: async (args: CommandArguments, options: CommandOptions) => {\n await this.handleInit(options);\n },\n },\n {\n name: \"get\",\n description: \"查看配置值\",\n execute: async (args: CommandArguments, options: CommandOptions) => {\n this.validateArgs(args, 1);\n await this.handleGet(args[0]);\n },\n },\n {\n name: \"set\",\n description: \"设置配置值\",\n execute: async (args: CommandArguments, options: CommandOptions) => {\n this.validateArgs(args, 2);\n await this.handleSet(args[0], args[1]);\n },\n },\n ];\n\n constructor(container: IDIContainer) {\n super(container);\n }\n\n /**\n * 主命令执行(显示帮助)\n */\n override async execute(\n args: CommandArguments,\n options: CommandOptions\n ): Promise<void> {\n console.log(\"配置管理命令。使用 --help 查看可用的子命令。\");\n }\n\n /**\n * 处理初始化命令\n */\n private async handleInit(options: CommandOptions): Promise<void> {\n const spinner = ora(\"初始化配置...\").start();\n\n try {\n const format = options.format as \"json\" | \"json5\" | \"jsonc\";\n if (format !== \"json\" && format !== \"json5\" && format !== \"jsonc\") {\n throw new Error(\"格式必须是 json, json5 或 jsonc\");\n }\n\n const configManager = this.getService<any>(\"configManager\");\n\n if (configManager.configExists()) {\n spinner.warn(\"配置文件已存在\");\n console.log(chalk.yellow(\"如需重新初始化,请先删除现有的配置文件\"));\n return;\n }\n\n configManager.initConfig(format);\n spinner.succeed(\"配置文件初始化成功\");\n\n // 获取实际创建的配置文件路径\n const configDir = process.env.XIAOZHI_CONFIG_DIR || process.cwd();\n const configFileName = `xiaozhi.config.${format}`;\n const configPath = path.join(configDir, configFileName);\n\n console.log(chalk.green(`✅ 配置文件已创建: ${configFileName}`));\n console.log(chalk.yellow(\"📝 请编辑配置文件设置你的 MCP 端点:\"));\n console.log(chalk.gray(` 配置文件路径: ${configPath}`));\n console.log(chalk.yellow(\"💡 或者使用命令设置:\"));\n console.log(\n chalk.gray(\" xiaozhi config set mcpEndpoint <your-endpoint-url>\")\n );\n } catch (error) {\n spinner.fail(\n `初始化配置失败: ${error instanceof Error ? error.message : String(error)}`\n );\n this.handleError(error as Error);\n }\n }\n\n /**\n * 确保配置文件存在,如果不存在则显示提示并返回 false\n */\n private async ensureConfigExists(spinner: Ora): Promise<boolean> {\n const configManager = this.getService<any>(\"configManager\");\n\n if (!configManager.configExists()) {\n spinner.fail(\"配置文件不存在\");\n console.log(\n chalk.yellow('💡 提示: 请先运行 \"xiaozhi config init\" 初始化配置')\n );\n return false;\n }\n\n return true;\n }\n\n /**\n * 处理获取配置命令\n */\n private async handleGet(key: string): Promise<void> {\n const spinner = ora(\"读取配置...\").start();\n\n try {\n if (!(await this.ensureConfigExists(spinner))) {\n return;\n }\n\n const configManager = this.getService<any>(\"configManager\");\n const config = configManager.getConfig();\n\n switch (key) {\n case \"mcpEndpoint\": {\n spinner.succeed(\"配置信息\");\n const endpoints = configManager.getMcpEndpoints();\n if (endpoints.length === 0) {\n console.log(chalk.yellow(\"未配置任何 MCP 端点\"));\n } else if (endpoints.length === 1) {\n console.log(chalk.green(`MCP 端点: ${endpoints[0]}`));\n } else {\n console.log(chalk.green(`MCP 端点 (${endpoints.length} 个):`));\n endpoints.forEach((ep: string, index: number) => {\n console.log(chalk.gray(` ${index + 1}. ${ep}`));\n });\n }\n break;\n }\n case \"mcpServers\":\n spinner.succeed(\"配置信息\");\n console.log(chalk.green(\"MCP 服务:\"));\n for (const [name, serverConfig] of Object.entries(\n config.mcpServers\n )) {\n const server = serverConfig as any;\n // 检查是否是 SSE 类型\n if (\"type\" in server && server.type === \"sse\") {\n console.log(chalk.gray(` ${name}: [SSE] ${server.url}`));\n } else {\n console.log(\n chalk.gray(\n ` ${name}: ${server.command} ${server.args.join(\" \")}`\n )\n );\n }\n }\n break;\n case \"connection\": {\n spinner.succeed(\"配置信息\");\n const connectionConfig = configManager.getConnectionConfig();\n console.log(chalk.green(\"连接配置:\"));\n console.log(\n chalk.gray(\n ` 心跳检测间隔: ${connectionConfig.heartbeatInterval}ms`\n )\n );\n console.log(\n chalk.gray(` 心跳超时时间: ${connectionConfig.heartbeatTimeout}ms`)\n );\n console.log(\n chalk.gray(` 重连间隔: ${connectionConfig.reconnectInterval}ms`)\n );\n break;\n }\n case \"heartbeatInterval\":\n spinner.succeed(\"配置信息\");\n console.log(\n chalk.green(\n `心跳检测间隔: ${configManager.getHeartbeatInterval()}ms`\n )\n );\n break;\n case \"heartbeatTimeout\":\n spinner.succeed(\"配置信息\");\n console.log(\n chalk.green(\n `心跳超时时间: ${configManager.getHeartbeatTimeout()}ms`\n )\n );\n break;\n case \"reconnectInterval\":\n spinner.succeed(\"配置信息\");\n console.log(\n chalk.green(`重连间隔: ${configManager.getReconnectInterval()}ms`)\n );\n break;\n default:\n spinner.fail(`未知的配置项: ${key}`);\n console.log(\n chalk.yellow(\n \"支持的配置项: mcpEndpoint, mcpServers, connection, heartbeatInterval, heartbeatTimeout, reconnectInterval\"\n )\n );\n }\n } catch (error) {\n spinner.fail(\n `读取配置失败: ${error instanceof Error ? error.message : String(error)}`\n );\n this.handleError(error as Error);\n }\n }\n\n /**\n * 处理设置配置命令\n */\n private async handleSet(key: string, value: string): Promise<void> {\n const spinner = ora(\"更新配置...\").start();\n\n try {\n if (!(await this.ensureConfigExists(spinner))) {\n return;\n }\n\n const configManager = this.getService<any>(\"configManager\");\n\n switch (key) {\n case \"mcpEndpoint\":\n configManager.updateMcpEndpoint(value);\n spinner.succeed(`MCP 端点已设置为: ${value}`);\n break;\n case \"heartbeatInterval\": {\n const interval = Number.parseInt(value);\n if (Number.isNaN(interval) || interval <= 0) {\n throw new Error(\"心跳检测间隔必须是正整数\");\n }\n configManager.updateHeartbeatInterval(interval);\n spinner.succeed(`心跳检测间隔已设置为: ${interval}ms`);\n break;\n }\n case \"heartbeatTimeout\": {\n const timeout = Number.parseInt(value);\n if (Number.isNaN(timeout) || timeout <= 0) {\n throw new Error(\"心跳超时时间必须是正整数\");\n }\n configManager.updateHeartbeatTimeout(timeout);\n spinner.succeed(`心跳超时时间已设置为: ${timeout}ms`);\n break;\n }\n case \"reconnectInterval\": {\n const interval = Number.parseInt(value);\n if (Number.isNaN(interval) || interval <= 0) {\n throw new Error(\"重连间隔必须是正整数\");\n }\n configManager.updateReconnectInterval(interval);\n spinner.succeed(`重连间隔已设置为: ${interval}ms`);\n break;\n }\n default:\n spinner.fail(`不支持设置的配置项: ${key}`);\n console.log(\n chalk.yellow(\n \"支持设置的配置项: mcpEndpoint, heartbeatInterval, heartbeatTimeout, reconnectInterval\"\n )\n );\n }\n } catch (error) {\n spinner.fail(\n `设置配置失败: ${error instanceof Error ? error.message : String(error)}`\n );\n this.handleError(error as Error);\n }\n }\n}\n","/**\n * 项目管理命令处理器\n */\n\nimport path from \"node:path\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport type { CommandOption } from \"../interfaces/Command\";\nimport { BaseCommandHandler } from \"../interfaces/Command\";\nimport type {\n CommandArguments,\n CommandOptions,\n} from \"../interfaces/CommandTypes\";\nimport type { IDIContainer } from \"../interfaces/Config\";\nimport type { TemplateInfo } from \"../interfaces/Service\";\n\n/**\n * 项目管理命令处理器\n */\nexport class ProjectCommandHandler extends BaseCommandHandler {\n override name = \"create\";\n override description = \"创建项目\";\n\n override options: CommandOption[] = [\n {\n flags: \"-t, --template <templateName>\",\n description: \"使用指定模板创建项目\",\n },\n ];\n\n constructor(container: IDIContainer) {\n super(container);\n }\n\n /**\n * 执行创建项目命令\n */\n override async execute(\n args: CommandArguments,\n options: CommandOptions\n ): Promise<void> {\n this.validateArgs(args, 1);\n const projectName = args[0];\n\n await this.handleCreate(projectName, options);\n }\n\n /**\n * 处理创建项目命令\n */\n protected async handleCreate(\n projectName: string,\n options: CommandOptions\n ): Promise<void> {\n const spinner = ora(\"初始化项目...\").start();\n\n try {\n const templateManager = this.getService<any>(\"templateManager\");\n const fileUtils = this.getService<any>(\"fileUtils\");\n\n // 确定目标目录\n const targetPath = path.join(process.cwd(), projectName);\n\n // 检查目标目录是否已存在\n if (await fileUtils.exists(targetPath)) {\n spinner.fail(`目录 \"${projectName}\" 已存在`);\n console.log(\n chalk.yellow(\"💡 提示: 请选择不同的项目名称或删除现有目录\")\n );\n return;\n }\n\n if (options.template) {\n // 使用模板创建项目\n await this.createFromTemplate(\n projectName,\n options.template as string,\n targetPath,\n spinner,\n templateManager\n );\n } else {\n // 创建基本项目(只有配置文件)\n await this.createBasicProject(\n projectName,\n targetPath,\n spinner,\n templateManager\n );\n }\n } catch (error) {\n spinner.fail(\n `创建项目失败: ${error instanceof Error ? error.message : String(error)}`\n );\n this.handleError(error as Error);\n }\n }\n\n /**\n * 从模板创建项目\n */\n private async createFromTemplate(\n projectName: string,\n templateName: string,\n targetPath: string,\n spinner: any,\n templateManager: any\n ): Promise<void> {\n spinner.text = \"检查模板...\";\n\n // 获取可用模板列表\n const availableTemplates = await templateManager.getAvailableTemplates();\n\n if (availableTemplates.length === 0) {\n spinner.fail(\"找不到可用模板\");\n console.log(chalk.yellow(\"💡 提示: 请确保 xiaozhi-client 正确安装\"));\n return;\n }\n\n // 使用局部变量避免重新赋值函数参数\n let actualTemplateName = templateName;\n\n // 验证模板是否存在\n const isValidTemplate =\n await templateManager.validateTemplate(actualTemplateName);\n if (!isValidTemplate) {\n spinner.fail(`模板 \"${actualTemplateName}\" 不存在`);\n\n // 尝试找到相似的模板\n const similarTemplate = this.findSimilarTemplate(\n actualTemplateName,\n availableTemplates\n );\n\n if (similarTemplate) {\n console.log(\n chalk.yellow(`💡 你是想使用模板 \"${similarTemplate}\" 吗?`)\n );\n const confirmed = await this.askUserConfirmation(\n chalk.cyan(\"确认使用此模板?(y/n): \")\n );\n\n if (confirmed) {\n actualTemplateName = similarTemplate;\n } else {\n this.showAvailableTemplates(availableTemplates);\n return;\n }\n } else {\n this.showAvailableTemplates(availableTemplates);\n return;\n }\n }\n\n spinner.text = `从模板 \"${actualTemplateName}\" 创建项目 \"${projectName}\"...`;\n\n // 使用模板管理器创建项目\n await templateManager.createProject({\n templateName: actualTemplateName,\n targetPath,\n projectName,\n });\n\n spinner.succeed(`项目 \"${projectName}\" 创建成功`);\n\n console.log(chalk.green(\"✅ 项目创建完成!\"));\n console.log(chalk.yellow(\"📝 接下来的步骤:\"));\n console.log(chalk.gray(` cd ${projectName}`));\n console.log(chalk.gray(\" pnpm install # 安装依赖\"));\n console.log(chalk.gray(\" # 编辑 xiaozhi.config.json 设置你的 MCP 端点\"));\n console.log(chalk.gray(\" xiaozhi start # 启动服务\"));\n }\n\n /**\n * 创建基本项目\n */\n private async createBasicProject(\n projectName: string,\n targetPath: string,\n spinner: any,\n templateManager: any\n ): Promise<void> {\n spinner.text = `创建基本项目 \"${projectName}\"...`;\n\n // 使用模板管理器创建基本项目\n await templateManager.createProject({\n templateName: null, // 表示创建基本项目\n targetPath,\n projectName,\n });\n\n spinner.succeed(`项目 \"${projectName}\" 创建成功`);\n\n console.log(chalk.green(\"✅ 基本项目创建完成!\"));\n console.log(chalk.yellow(\"📝 接下来的步骤:\"));\n console.log(chalk.gray(` cd ${projectName}`));\n console.log(\n chalk.gray(\" # 编辑 xiaozhi.config.json 设置你的 MCP 端点和服务\")\n );\n console.log(chalk.gray(\" xiaozhi start # 启动服务\"));\n console.log(\n chalk.yellow(\"💡 提示: 使用 --template 选项可以从模板创建项目\")\n );\n }\n\n /**\n * 显示可用模板\n */\n private showAvailableTemplates(templates: TemplateInfo[]): void {\n console.log(chalk.yellow(\"可用的模板:\"));\n for (const template of templates) {\n console.log(\n chalk.gray(\n ` - ${template.name}${template.description ? ` - ${template.description}` : \"\"}`\n )\n );\n }\n }\n\n /**\n * 查找相似模板\n */\n private findSimilarTemplate(\n input: string,\n templates: TemplateInfo[]\n ): string | null {\n const formatUtils = this.getService<any>(\"formatUtils\");\n\n let bestMatch: string | null = null;\n let bestSimilarity = 0;\n\n for (const template of templates) {\n const similarity = formatUtils.calculateSimilarity(\n input.toLowerCase(),\n template.name.toLowerCase()\n );\n if (similarity > bestSimilarity && similarity > 0.6) {\n bestSimilarity = similarity;\n bestMatch = template.name;\n }\n }\n\n return bestMatch;\n }\n\n /**\n * 询问用户确认\n */\n private async askUserConfirmation(prompt: string): Promise<boolean> {\n const readline = await import(\"node:readline\");\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n return new Promise((resolve) => {\n rl.question(prompt, (answer) => {\n rl.close();\n resolve(\n answer.toLowerCase().trim() === \"y\" ||\n answer.toLowerCase().trim() === \"yes\"\n );\n });\n });\n }\n}\n","/**\n * CLI 命令相关类型定义\n * 用于替代命令处理器中的 any 类型使用,提供类型安全保障\n */\n\nimport type { LocalMCPServerConfig, MCPServerConfig } from \"../../config\";\n\n// =========================\n// 基础命令参数和选项类型\n// =========================\n\n/**\n * 命令行参数类型\n * 替代 any[] 类型\n */\nexport type CommandArguments = string[];\n\n/**\n * 命令选项类型\n * 替代 any 类型\n */\nexport type CommandOptions = Record<string, unknown>;\n\n// =========================\n// 子命令具体选项类型\n// =========================\n\n/**\n * list 子命令选项\n */\nexport interface ListOptions {\n /** 是否显示所有服务的工具列表 */\n tools?: boolean;\n}\n\n/**\n * call 子命令选项\n */\nexport interface CallOptions {\n /** 工具参数 (JSON 格式) */\n args?: string;\n}\n\n// =========================\n// 类型守卫函数\n// =========================\n\n/**\n * 检查对象是否为本地 MCP 服务配置\n * @param obj 待检查的对象\n * @returns 是否为本地服务配置\n */\nexport function isLocalMCPServerConfig(\n obj: unknown\n): obj is LocalMCPServerConfig {\n const config = obj as MCPServerConfig;\n return (\n typeof config === \"object\" &&\n config !== null &&\n \"command\" in config &&\n \"args\" in config &&\n typeof config.command === \"string\" &&\n Array.isArray(config.args) &&\n config.args.every((arg: unknown) => typeof arg === \"string\")\n );\n}\n\n// =========================\n// 类型化子命令接口\n// =========================\n\n/**\n * 类型化子命令接口\n * 提供类型安全的子命令定义\n */\nexport interface TypedSubCommand<TOptions = CommandOptions> {\n /** 子命令名称 */\n name: string;\n /** 子命令描述 */\n description: string;\n /** 子命令选项 */\n options?: Array<{\n /** 选项标志 */\n flags: string;\n /** 选项描述 */\n description: string;\n /** 默认值 */\n defaultValue?: unknown;\n }>;\n /** 执行子命令 */\n execute: (args: CommandArguments, options: TOptions) => Promise<void>;\n}\n","/**\n * MCP管理命令处理器\n */\n\nimport chalk from \"chalk\";\nimport Table from \"cli-table3\";\nimport consola from \"consola\";\nimport ora from \"ora\";\nimport { configManager } from \"../../config\";\nimport type { SubCommand } from \"../interfaces/Command\";\nimport { BaseCommandHandler } from \"../interfaces/Command\";\nimport type {\n CallOptions,\n CommandArguments,\n CommandOptions,\n ListOptions,\n} from \"../interfaces/CommandTypes\";\nimport { isLocalMCPServerConfig } from \"../interfaces/CommandTypes\";\nimport { ProcessManagerImpl } from \"../services/ProcessManager\";\n\n// 工具调用结果接口\ninterface ToolCallResult {\n content: Array<{\n type: string;\n text: string;\n }>;\n isError?: boolean;\n}\n\n/**\n * MCP管理命令处理器\n */\nexport class McpCommandHandler extends BaseCommandHandler {\n private processManager: ProcessManagerImpl;\n private baseUrl: string;\n\n constructor(...args: ConstructorParameters<typeof BaseCommandHandler>) {\n super(...args);\n this.processManager = new ProcessManagerImpl();\n\n // 获取 Web 服务器的端口\n try {\n const webPort = configManager.getWebUIPort() ?? 9999;\n this.baseUrl = `http://localhost:${webPort}`;\n } catch {\n this.baseUrl = \"http://localhost:9999\";\n }\n }\n\n /**\n * 中文字符正则表达式\n *\n * Unicode 范围说明:\n * - \\u4e00-\\u9fff: CJK 统一汉字(基本汉字)\n * - \\u3400-\\u4dbf: CJK 扩展 A(扩展汉字)\n * - \\uff00-\\uffef: 全角字符和半角片假名(包括中文标点符号)\n *\n * 注意:此范围可能不完全覆盖所有中日韩字符(如 CJK 扩展 B-F 等),\n * 但已覆盖绝大多数常用中文场景。\n */\n private static readonly CHINESE_CHAR_REGEX =\n /[\\u4e00-\\u9fff\\u3400-\\u4dbf\\uff00-\\uffef]/;\n\n /**\n * 计算字符串的显示宽度(中文字符占2个宽度,英文字符占1个宽度)\n */\n private static getDisplayWidth(str: string): number {\n let width = 0;\n for (const char of str) {\n // 判断是否为中文字符(包括中文标点符号)\n if (McpCommandHandler.CHINESE_CHAR_REGEX.test(char)) {\n width += 2;\n } else {\n width += 1;\n }\n }\n return width;\n }\n\n /**\n * 截断字符串到指定的显示宽度\n */\n private static truncateToWidth(str: string, maxWidth: number): string {\n if (McpCommandHandler.getDisplayWidth(str) <= maxWidth) {\n return str;\n }\n\n // 如果最大宽度小于等于省略号的宽度,返回空字符串\n if (maxWidth <= 3) {\n return \"\";\n }\n\n let result = \"\";\n let currentWidth = 0;\n let hasAddedChar = false;\n\n for (const char of str) {\n const charWidth = McpCommandHandler.CHINESE_CHAR_REGEX.test(char) ? 2 : 1;\n\n // 如果加上当前字符会超出限制\n if (currentWidth + charWidth > maxWidth - 3) {\n // 如果还没有添加任何字符,说明连一个字符都放不下,返回空字符串\n if (!hasAddedChar) {\n return \"\";\n }\n // 否则添加省略号并退出\n result += \"...\";\n break;\n }\n\n result += char;\n currentWidth += charWidth;\n hasAddedChar = true;\n }\n\n return result;\n }\n\n /**\n * 解析 JSON 参数\n * @param argsString JSON 字符串\n * @returns 解析后的参数对象\n */\n private static parseJsonArgs(argsString: string): Record<string, unknown> {\n try {\n return JSON.parse(argsString);\n } catch (error) {\n throw new Error(\n `参数格式错误,请使用有效的 JSON 格式。错误详情: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n\n /**\n * 格式化工具调用结果输出\n * @param result 工具调用结果\n * @returns 格式化后的字符串\n */\n private static formatToolCallResult(result: ToolCallResult): string {\n return JSON.stringify(result);\n }\n\n override name = \"mcp\";\n override description = \"MCP 服务和工具管理\";\n\n override subcommands: SubCommand[] = [\n {\n name: \"list\",\n description: \"列出 MCP 服务\",\n options: [{ flags: \"--tools\", description: \"显示所有服务的工具列表\" }],\n execute: async (args: CommandArguments, options: CommandOptions) => {\n await this.handleList(options as ListOptions);\n },\n },\n {\n name: \"server\",\n description: \"管理指定的 MCP 服务\",\n execute: async (args: CommandArguments, options: CommandOptions) => {\n this.validateArgs(args, 1);\n await this.handleServer(args[0]);\n },\n },\n {\n name: \"tool\",\n description: \"启用或禁用指定服务的工具\",\n execute: async (args: CommandArguments, options: CommandOptions) => {\n this.validateArgs(args, 3);\n const [serverName, toolName, action] = args;\n\n if (action !== \"enable\" && action !== \"disable\") {\n console.error(chalk.red(\"错误: 操作必须是 'enable' 或 'disable'\"));\n process.exit(1);\n }\n\n const enabled = action === \"enable\";\n await this.handleTool(serverName, toolName, enabled);\n },\n },\n {\n name: \"call\",\n description: \"调用指定服务的工具\",\n options: [\n {\n flags: \"--args <json>\",\n description: \"工具参数 (JSON 格式)\",\n defaultValue: \"{}\",\n },\n ],\n execute: async (args: CommandArguments, options: CommandOptions) => {\n this.validateArgs(args, 2);\n const [serviceName, toolName] = args;\n await this.handleCall(\n serviceName,\n toolName,\n (options as CallOptions).args ?? \"{}\"\n );\n },\n },\n ];\n\n /**\n * 主命令执行(显示帮助)\n */\n async execute(\n args: CommandArguments,\n options: CommandOptions\n ): Promise<void> {\n console.log(\"MCP 服务和工具管理命令。使用 --help 查看可用的子命令。\");\n }\n\n /**\n * 处理列出服务命令\n */\n private async handleList(options: ListOptions): Promise<void> {\n try {\n await this.handleListInternal(options);\n } catch (error) {\n this.handleError(error as Error);\n }\n }\n\n /**\n * 处理服务管理命令\n */\n private async handleServer(serverName: string): Promise<void> {\n try {\n await this.handleServerInternal(serverName);\n } catch (error) {\n this.handleError(error as Error);\n }\n }\n\n /**\n * 处理工具管理命令\n */\n private async handleTool(\n serverName: string,\n toolName: string,\n enabled: boolean\n ): Promise<void> {\n try {\n await this.handleToolInternal(serverName, toolName, enabled);\n } catch (error) {\n this.handleError(error as Error);\n }\n }\n\n /**\n * 验证服务状态\n * @private\n */\n private async validateServiceStatus(): Promise<void> {\n // 检查进程级别的服务状态\n const processStatus = this.processManager.getServiceStatus();\n if (!processStatus.running) {\n throw new Error(\n \"xiaozhi 服务未启动。请先运行 'xiaozhi start' 或 'xiaozhi start -d' 启动服务。\"\n );\n }\n\n // 检查 Web 服务器是否可访问\n try {\n const response = await fetch(`${this.baseUrl}/api/status`, {\n method: \"GET\",\n signal: AbortSignal.timeout(5000), // 5秒超时\n });\n\n if (!response.ok) {\n throw new Error(`Web 服务器响应错误: ${response.status}`);\n }\n } catch (error: unknown) {\n // 超时单独提示\n if (error instanceof Error && error.name === \"AbortError\") {\n throw new Error(\"连接 xiaozhi 服务超时。请检查服务是否正常运行。\");\n }\n\n // 已知的 Error 实例,区分网络错误与其他错误\n if (error instanceof Error) {\n const isNetworkError =\n error instanceof TypeError &&\n /fetch|network|failed/i.test(error.message);\n\n if (isNetworkError) {\n throw new Error(\n `无法连接到 xiaozhi 服务(网络请求失败)。请检查网络连接或服务地址是否正确。原始错误: ${error.message}`\n );\n }\n\n throw new Error(\n `无法连接到 xiaozhi 服务。请检查服务状态。原始错误: ${error.message}`\n );\n }\n\n // 非 Error 对象的兜底处理,避免出现 [object Object]\n let detail: string;\n try {\n detail = JSON.stringify(error);\n } catch {\n detail = String(error);\n }\n\n throw new Error(\n `无法连接到 xiaozhi 服务。请检查服务状态。错误详情: ${detail}`\n );\n }\n }\n\n /**\n * 调用 MCP 工具的内部实现\n * @param serviceName 服务名称\n * @param toolName 工具名称\n * @param args 工具参数\n * @returns 工具调用结果\n */\n private async callToolInternal(\n serviceName: string,\n toolName: string,\n args: Record<string, unknown>\n ): Promise<ToolCallResult> {\n // 1. 检查服务状态\n await this.validateServiceStatus();\n\n // 2. 通过 HTTP API 调用工具\n try {\n const response = await fetch(`${this.baseUrl}/api/tools/call`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n serviceName,\n toolName,\n args,\n }),\n });\n\n if (!response.ok) {\n let errorMessage = `HTTP ${response.status}: ${response.statusText}`;\n try {\n const errorData = await response.json();\n const detailedMessage =\n errorData?.error?.message ?? errorData?.message;\n if (typeof detailedMessage === \"string\" && detailedMessage.trim()) {\n errorMessage = detailedMessage;\n }\n } catch {\n // 响应体不是 JSON 时,保留默认的 HTTP 错误信息\n }\n throw new Error(errorMessage);\n }\n\n const responseData = await response.json();\n\n if (!responseData.success) {\n throw new Error(responseData.error?.message || \"工具调用失败\");\n }\n\n return responseData.data;\n } catch (error) {\n consola.error(\n `工具调用失败: ${serviceName}/${toolName}`,\n error instanceof Error ? error.message : String(error)\n );\n throw error;\n }\n }\n\n /**\n * 处理工具调用命令\n */\n private async handleCall(\n serviceName: string,\n toolName: string,\n argsString: string\n ): Promise<void> {\n try {\n // 解析参数\n const args = McpCommandHandler.parseJsonArgs(argsString);\n\n // 调用工具\n const result = await this.callToolInternal(serviceName, toolName, args);\n\n console.log(McpCommandHandler.formatToolCallResult(result));\n } catch (error) {\n console.log(`工具调用失败: ${serviceName}/${toolName}`);\n console.error(chalk.red(\"错误:\"), (error as Error).message);\n\n // 提供有用的提示\n const errorMessage = (error as Error).message;\n if (errorMessage.includes(\"服务未启动\")) {\n console.log();\n console.log(chalk.yellow(\"💡 请先启动服务:\"));\n console.log(chalk.gray(\" xiaozhi start # 前台启动\"));\n console.log(chalk.gray(\" xiaozhi start -d # 后台启动\"));\n } else if (errorMessage.includes(\"参数格式错误\")) {\n console.log();\n console.log(chalk.yellow(\"💡 正确格式示例:\"));\n console.log(\n chalk.gray(\n ` xiaozhi mcp call ${serviceName} ${toolName} --args '{\"param\": \"value\"}'`\n )\n );\n }\n\n // 测试环境:通过抛出错误让测试可以捕获并断言\n if (process.env.NODE_ENV === \"test\") {\n throw new Error(\"process.exit called\");\n }\n\n process.exit(1);\n }\n }\n\n /**\n * 列出所有 MCP 服务\n */\n private async handleListInternal(\n options: { tools?: boolean } = {}\n ): Promise<void> {\n const spinner = ora(\"获取 MCP 服务列表...\").start();\n\n try {\n const mcpServers = configManager.getMcpServers();\n const serverNames = Object.keys(mcpServers);\n\n // 检查是否有 customMCP 工具\n const customMCPTools = configManager.getCustomMCPTools();\n const hasCustomMCP = customMCPTools.length > 0;\n\n // 计算总服务数(包括 customMCP)\n const totalServices = serverNames.length + (hasCustomMCP ? 1 : 0);\n\n if (totalServices === 0) {\n spinner.warn(\"未配置任何 MCP 服务或 customMCP 工具\");\n console.log(\n chalk.yellow(\n \"💡 提示: 使用 'xiaozhi config' 命令配置 MCP 服务或在 xiaozhi.config.json 中配置 customMCP 工具\"\n )\n );\n return;\n }\n\n spinner.succeed(\n `找到 ${totalServices} 个 MCP 服务${hasCustomMCP ? \" (包括 customMCP)\" : \"\"}`\n );\n\n if (options.tools) {\n // 显示所有服务的工具列表\n console.log();\n console.log(chalk.bold(\"MCP 服务工具列表:\"));\n console.log();\n\n // 计算所有工具名称的最大长度,用于动态设置列宽\n let maxToolNameWidth = 8; // 默认最小宽度\n const allToolNames: string[] = [];\n\n // 添加标准 MCP 服务的工具名称\n for (const serverName of serverNames) {\n const toolsConfig = configManager.getServerToolsConfig(serverName);\n const toolNames = Object.keys(toolsConfig);\n allToolNames.push(...toolNames);\n }\n\n // 添加 customMCP 工具名称\n if (hasCustomMCP) {\n const customToolNames = customMCPTools.map((tool) => tool.name);\n allToolNames.push(...customToolNames);\n }\n\n // 计算最长工具名称的显示宽度\n for (const toolName of allToolNames) {\n const width = McpCommandHandler.getDisplayWidth(toolName);\n if (width > maxToolNameWidth) {\n maxToolNameWidth = width;\n }\n }\n\n // 确保工具名称列宽度至少为10,最多为30\n maxToolNameWidth = Math.max(10, Math.min(maxToolNameWidth + 2, 30));\n\n // 使用 cli-table3 创建表格\n const table = new Table({\n head: [\n chalk.bold(\"MCP\"),\n chalk.bold(\"工具名称\"),\n chalk.bold(\"状态\"),\n chalk.bold(\"描述\"),\n ],\n colWidths: [15, maxToolNameWidth, 8, 40], // MCP | 工具名称 | 状态 | 描述\n wordWrap: true,\n style: {\n head: [],\n border: [],\n },\n });\n\n // 首先添加 customMCP 工具(如果存在)\n if (hasCustomMCP) {\n for (const customTool of customMCPTools) {\n const description = McpCommandHandler.truncateToWidth(\n customTool.description || \"\",\n 32\n );\n\n table.push([\n \"customMCP\",\n customTool.name,\n chalk.green(\"启用\"), // customMCP 工具默认启用\n description,\n ]);\n }\n }\n\n // 然后添加标准 MCP 服务的工具\n for (const serverName of serverNames) {\n const toolsConfig = configManager.getServerToolsConfig(serverName);\n const toolNames = Object.keys(toolsConfig);\n\n if (toolNames.length === 0) {\n // 服务没有工具时显示提示信息\n table.push([\n chalk.gray(serverName),\n chalk.gray(\"-\"),\n chalk.gray(\"-\"),\n chalk.gray(\"暂未识别到相关工具\"),\n ]);\n } else {\n // 添加服务分隔行(如果表格不为空)\n if (table.length > 0) {\n table.push([{ colSpan: 4, content: \"\" }]);\n }\n\n for (const toolName of toolNames) {\n const toolConfig = toolsConfig[toolName];\n const status = toolConfig.enable\n ? chalk.green(\"启用\")\n : chalk.red(\"禁用\");\n\n // 截断描述到最大32个字符宽度(约16个中文字符)\n const description = McpCommandHandler.truncateToWidth(\n toolConfig.description || \"\",\n 32\n );\n\n // 只显示工具名称,不包含服务名前缀\n table.push([serverName, toolName, status, description]);\n }\n }\n }\n\n console.log(table.toString());\n } else {\n // 只显示服务列表\n console.log();\n console.log(chalk.bold(\"MCP 服务列表:\"));\n console.log();\n\n // 首先显示 customMCP 服务(如果存在)\n if (hasCustomMCP) {\n console.log(`${chalk.cyan(\"•\")} ${chalk.bold(\"customMCP\")}`);\n console.log(` 类型: ${chalk.gray(\"自定义 MCP 工具\")}`);\n console.log(` 配置: ${chalk.gray(\"xiaozhi.config.json\")}`);\n console.log(\n ` 工具: ${chalk.green(customMCPTools.length)} 启用 / ${chalk.yellow(\n customMCPTools.length\n )} 总计`\n );\n console.log();\n }\n\n // 然后显示标准 MCP 服务\n for (const serverName of serverNames) {\n const serverConfig = mcpServers[serverName];\n const toolsConfig = configManager.getServerToolsConfig(serverName);\n const toolCount = Object.keys(toolsConfig).length;\n const enabledCount = Object.values(toolsConfig).filter(\n (t) => t.enable !== false\n ).length;\n\n console.log(`${chalk.cyan(\"•\")} ${chalk.bold(serverName)}`);\n\n // 检查服务类型并显示相应信息\n if (\"url\" in serverConfig) {\n // URL 类型的服务(SSE 或 Streamable HTTP)\n if (\"type\" in serverConfig && serverConfig.type === \"sse\") {\n console.log(` 类型: ${chalk.gray(\"SSE\")}`);\n } else {\n console.log(` 类型: ${chalk.gray(\"Streamable HTTP\")}`);\n }\n console.log(` URL: ${chalk.gray(serverConfig.url)}`);\n } else if (isLocalMCPServerConfig(serverConfig)) {\n // 本地服务\n console.log(\n ` 命令: ${chalk.gray(serverConfig.command)} ${chalk.gray(\n serverConfig.args.join(\" \")\n )}`\n );\n }\n if (toolCount > 0) {\n console.log(\n ` 工具: ${chalk.green(enabledCount)} 启用 / ${chalk.yellow(\n toolCount\n )} 总计`\n );\n } else {\n console.log(` 工具: ${chalk.gray(\"未扫描 (请先启动服务)\")}`);\n }\n console.log();\n }\n }\n\n console.log(chalk.gray(\"💡 提示:\"));\n console.log(\n chalk.gray(\" - 使用 'xiaozhi mcp list --tools' 查看所有工具\")\n );\n console.log(\n chalk.gray(\" - 使用 'xiaozhi mcp <服务名> list' 查看指定服务的工具\")\n );\n console.log(\n chalk.gray(\n \" - 使用 'xiaozhi mcp <服务名> <工具名> enable/disable' 启用/禁用工具\"\n )\n );\n } catch (error) {\n spinner.fail(\"获取 MCP 服务列表失败\");\n console.error(\n chalk.red(\n `错误: ${error instanceof Error ? error.message : String(error)}`\n )\n );\n process.exit(1);\n }\n }\n\n /**\n * 验证服务是否存在\n * @param serverName 服务名称\n * @param spinner Ora 加载动画实例\n * @returns 服务是否存在\n * @private\n */\n private validateServerExists(\n serverName: string,\n spinner: ReturnType<typeof ora>\n ): boolean {\n const mcpServers = configManager.getMcpServers();\n\n if (!mcpServers[serverName]) {\n spinner.fail(`服务 '${serverName}' 不存在`);\n console.log(\n chalk.yellow(\"💡 提示: 使用 'xiaozhi mcp list' 查看所有可用服务\")\n );\n return false;\n }\n\n return true;\n }\n\n /**\n * 列出指定服务的工具\n */\n private async handleServerInternal(serverName: string): Promise<void> {\n const spinner = ora(`获取 ${serverName} 服务的工具列表...`).start();\n\n try {\n if (!this.validateServerExists(serverName, spinner)) {\n return;\n }\n\n const toolsConfig = configManager.getServerToolsConfig(serverName);\n const toolNames = Object.keys(toolsConfig);\n\n if (toolNames.length === 0) {\n spinner.warn(`服务 '${serverName}' 暂无工具信息`);\n console.log(chalk.yellow(\"💡 提示: 请先启动服务以扫描工具列表\"));\n return;\n }\n\n spinner.succeed(`服务 '${serverName}' 共有 ${toolNames.length} 个工具`);\n\n console.log();\n console.log(chalk.bold(`${serverName} 服务工具列表:`));\n console.log();\n\n // 使用 cli-table3 创建表格\n const table = new Table({\n head: [chalk.bold(\"工具名称\"), chalk.bold(\"状态\"), chalk.bold(\"描述\")],\n colWidths: [30, 8, 50], // 工具名称 | 状态 | 描述\n wordWrap: true,\n style: {\n head: [],\n border: [],\n },\n });\n\n for (const toolName of toolNames) {\n const toolConfig = toolsConfig[toolName];\n const status = toolConfig.enable\n ? chalk.green(\"启用\")\n : chalk.red(\"禁用\");\n\n // 截断描述到最大40个字符宽度(约20个中文字符)\n const description = McpCommandHandler.truncateToWidth(\n toolConfig.description || \"\",\n 40\n );\n\n table.push([toolName, status, description]);\n }\n\n console.log(table.toString());\n\n console.log();\n console.log(chalk.gray(\"💡 提示:\"));\n console.log(\n chalk.gray(\n ` - 使用 'xiaozhi mcp ${serverName} <工具名> enable' 启用工具`\n )\n );\n console.log(\n chalk.gray(\n ` - 使用 'xiaozhi mcp ${serverName} <工具名> disable' 禁用工具`\n )\n );\n } catch (error) {\n spinner.fail(\"获取工具列表失败\");\n console.error(\n chalk.red(\n `错误: ${error instanceof Error ? error.message : String(error)}`\n )\n );\n process.exit(1);\n }\n }\n\n /**\n * 启用或禁用工具\n */\n private async handleToolInternal(\n serverName: string,\n toolName: string,\n enabled: boolean\n ): Promise<void> {\n const action = enabled ? \"启用\" : \"禁用\";\n const spinner = ora(`${action}工具 ${serverName}/${toolName}...`).start();\n\n try {\n if (!this.validateServerExists(serverName, spinner)) {\n return;\n }\n\n const toolsConfig = configManager.getServerToolsConfig(serverName);\n\n if (!toolsConfig[toolName]) {\n spinner.fail(`工具 '${toolName}' 在服务 '${serverName}' 中不存在`);\n console.log(\n chalk.yellow(\n `💡 提示: 使用 'xiaozhi mcp ${serverName} list' 查看该服务的所有工具`\n )\n );\n return;\n }\n\n // 更新工具状态\n configManager.setToolEnabled(\n serverName,\n toolName,\n enabled,\n toolsConfig[toolName].description\n );\n\n spinner.succeed(\n `成功${action}工具 ${chalk.cyan(serverName)}/${chalk.cyan(toolName)}`\n );\n\n console.log();\n console.log(chalk.gray(\"💡 提示: 工具状态更改将在下次启动服务时生效\"));\n } catch (error) {\n spinner.fail(`${action}工具失败`);\n console.error(\n chalk.red(\n `错误: ${error instanceof Error ? error.message : String(error)}`\n )\n );\n process.exit(1);\n }\n }\n}\n","/**\n * 端点管理命令处理器\n */\n\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport type { SubCommand } from \"../interfaces/Command\";\nimport { BaseCommandHandler } from \"../interfaces/Command\";\nimport type {\n CommandArguments,\n CommandOptions,\n} from \"../interfaces/CommandTypes\";\nimport type { IDIContainer } from \"../interfaces/Config\";\n\n/**\n * 端点管理命令处理器\n */\nexport class EndpointCommandHandler extends BaseCommandHandler {\n override name = \"endpoint\";\n override description = \"管理 MCP 端点\";\n\n override subcommands: SubCommand[] = [\n {\n name: \"list\",\n description: \"列出所有 MCP 端点\",\n execute: async (args: CommandArguments, options: CommandOptions) => {\n await this.handleList();\n },\n },\n {\n name: \"add\",\n description: \"添加新的 MCP 端点\",\n execute: async (args: CommandArguments, options: CommandOptions) => {\n this.validateArgs(args, 1);\n await this.handleAdd(args[0]);\n },\n },\n {\n name: \"remove\",\n description: \"移除指定的 MCP 端点\",\n execute: async (args: CommandArguments, options: CommandOptions) => {\n this.validateArgs(args, 1);\n await this.handleRemove(args[0]);\n },\n },\n {\n name: \"set\",\n description: \"设置 MCP 端点(可以是单个或多个)\",\n execute: async (args: CommandArguments, options: CommandOptions) => {\n this.validateArgs(args, 1);\n await this.handleSet(args);\n },\n },\n ];\n\n constructor(container: IDIContainer) {\n super(container);\n }\n\n /**\n * 主命令执行(显示帮助)\n */\n override async execute(\n args: CommandArguments,\n options: CommandOptions\n ): Promise<void> {\n console.log(\"MCP 端点管理命令。使用 --help 查看可用的子命令。\");\n }\n\n /**\n * 处理列出端点命令\n */\n protected async handleList(): Promise<void> {\n const spinner = ora(\"读取端点配置...\").start();\n\n try {\n const configManager = this.getService<any>(\"configManager\");\n const endpoints = configManager.getMcpEndpoints();\n spinner.succeed(\"端点列表\");\n\n if (endpoints.length === 0) {\n console.log(chalk.yellow(\"未配置任何 MCP 端点\"));\n } else {\n console.log(chalk.green(`共 ${endpoints.length} 个端点:`));\n endpoints.forEach((ep: string, index: number) => {\n console.log(chalk.gray(` ${index + 1}. ${ep}`));\n });\n }\n } catch (error) {\n spinner.fail(\n `读取端点失败: ${error instanceof Error ? error.message : String(error)}`\n );\n this.handleError(error as Error);\n }\n }\n\n /**\n * 处理添加端点命令\n */\n protected async handleAdd(url: string): Promise<void> {\n const spinner = ora(\"添加端点...\").start();\n\n try {\n const configManager = this.getService<any>(\"configManager\");\n configManager.addMcpEndpoint(url);\n spinner.succeed(`成功添加端点: ${url}`);\n\n const endpoints = configManager.getMcpEndpoints();\n console.log(chalk.gray(`当前共 ${endpoints.length} 个端点`));\n } catch (error) {\n spinner.fail(\n `添加端点失败: ${error instanceof Error ? error.message : String(error)}`\n );\n this.handleError(error as Error);\n }\n }\n\n /**\n * 处理移除端点命令\n */\n protected async handleRemove(url: string): Promise<void> {\n const spinner = ora(\"移除端点...\").start();\n\n try {\n const configManager = this.getService<any>(\"configManager\");\n configManager.removeMcpEndpoint(url);\n spinner.succeed(`成功移除端点: ${url}`);\n\n const endpoints = configManager.getMcpEndpoints();\n console.log(chalk.gray(`当前剩余 ${endpoints.length} 个端点`));\n } catch (error) {\n spinner.fail(\n `移除端点失败: ${error instanceof Error ? error.message : String(error)}`\n );\n this.handleError(error as Error);\n }\n }\n\n /**\n * 处理设置端点命令\n */\n protected async handleSet(urls: string[]): Promise<void> {\n const spinner = ora(\"设置端点...\").start();\n\n try {\n const configManager = this.getService<any>(\"configManager\");\n\n if (urls.length === 1) {\n configManager.updateMcpEndpoint(urls[0]);\n spinner.succeed(`成功设置端点: ${urls[0]}`);\n } else {\n configManager.updateMcpEndpoint(urls);\n spinner.succeed(`成功设置 ${urls.length} 个端点`);\n for (const [index, url] of urls.entries()) {\n console.log(chalk.gray(` ${index + 1}. ${url}`));\n }\n }\n } catch (error) {\n spinner.fail(\n `设置端点失败: ${error instanceof Error ? error.message : String(error)}`\n );\n this.handleError(error as Error);\n }\n }\n}\n","#!/usr/bin/env node\n\n/**\n * CLI 入口文件\n * 负责初始化依赖注入容器和启动命令处理器\n */\n\nimport { Command } from \"commander\";\nimport { DIContainer } from \"./Container\";\nimport { CommandRegistry } from \"./commands/index\";\nimport { ErrorHandler } from \"./errors/ErrorHandlers\";\n\nconst program = new Command();\n\n/**\n * 初始化 CLI 应用\n */\nasync function initializeCLI(): Promise<void> {\n try {\n // 创建依赖注入容器\n const container = DIContainer.create();\n\n // 创建命令注册器\n const commandRegistry = new CommandRegistry(container);\n\n // 注册所有命令\n await commandRegistry.registerCommands(program);\n\n // 配置程序基本信息\n program\n .name(\"xiaozhi\")\n .description(\"小智 MCP 客户端\")\n .helpOption(\"-h, --help\", \"显示帮助信息\");\n\n // 解析命令行参数\n await program.parseAsync(process.argv);\n } catch (error) {\n ErrorHandler.handle(error as Error);\n }\n}\n\ninitializeCLI();\n\nexport { initializeCLI };\n","/**\n * 依赖注入容器\n *\n * 负责管理 CLI 的依赖注入,包括:\n * - 服务注册(工厂、单例、实例)\n * - 服务获取\n * - 单例模式管理\n * - 默认服务配置\n *\n * @module src/cli/Container\n */\n\nimport { configManager } from \"../config\";\nimport { VersionUtils } from \"../utils/version\";\nimport { ErrorHandler } from \"./errors/ErrorHandlers\";\nimport type { IDIContainer } from \"./interfaces/Config\";\nimport { FileUtils } from \"./utils/FileUtils\";\nimport { FormatUtils } from \"./utils/FormatUtils\";\nimport { PathUtils } from \"./utils/PathUtils\";\nimport { PlatformUtils } from \"./utils/PlatformUtils\";\nimport { Validation } from \"./utils/Validation\";\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(\"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 return new DaemonManagerModule.DaemonManagerImpl(processManager);\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 return new ServiceManagerModule.ServiceManagerImpl(\n processManager,\n configManager\n );\n });\n\n container.registerSingleton(\"templateManager\", () => {\n // 使用动态导入的同步版本\n const TemplateManagerModule = require(\"./services/TemplateManager.js\");\n return new TemplateManagerModule.TemplateManagerImpl();\n });\n\n return container;\n }\n}\n\n/**\n * 创建并配置 DI 容器\n */\nexport async function createContainer(): Promise<IDIContainer> {\n return DIContainer.create();\n}\n","/**\n * 全局常量类型声明\n *\n * 这些常量由构建工具在构建时注入\n */\ndeclare global {\n const __VERSION__: string;\n const __APP_NAME__: string;\n}\n\n/**\n * 版本号常量(构建时注入)\n *\n * 如果构建时能读取到 package.json,则为真实版本号\n * 否则为占位符,运行时从 package.json 读取\n */\nexport const VERSION = __VERSION__;\nexport const APP_NAME = __APP_NAME__;\n\n/**\n * 版本管理工具\n *\n * 提供版本号获取、比较、验证等功能\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\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 private static cachedVersionInfo: VersionInfo | null = null;\n\n /**\n * 获取版本号\n *\n * 优先使用构建时注入的版本号常量\n * 如果是占位符,则运行时从 package.json 读取\n */\n static getVersion(): string {\n // 如果版本号是占位符,则运行时读取\n if (VERSION === \"__VERSION__\") {\n return VersionUtils.getRuntimeVersion();\n }\n\n // 使用构建时注入的版本号\n return VERSION;\n }\n\n /**\n * 获取完整版本信息\n */\n static getVersionInfo(): VersionInfo {\n // 如果有缓存,直接返回\n if (VersionUtils.cachedVersionInfo) {\n return VersionUtils.cachedVersionInfo;\n }\n\n // 如果版本号是占位符,则运行时读取\n if (VERSION === \"__VERSION__\") {\n VersionUtils.cachedVersionInfo = VersionUtils.getRuntimeVersionInfo();\n return VersionUtils.cachedVersionInfo;\n }\n\n // 使用构建时注入的版本号\n VersionUtils.cachedVersionInfo = {\n version: VERSION,\n name: APP_NAME === \"__APP_NAME__\" ? undefined : APP_NAME,\n };\n\n return VersionUtils.cachedVersionInfo;\n }\n\n /**\n * 比较版本号\n *\n * @param version1 第一个版本号\n * @param version2 第二个版本号\n * @returns 返回值:1 表示 version1 > version2,-1 表示 version1 < version2,0 表示相等\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 * @param version 版本号字符串\n * @returns 是否为有效的语义化版本号\n */\n static isValidVersion(version: string): boolean {\n // 支持语义化版本号:1.2.3 或 1.2.3-alpha.1 或 1.2.3-beta.1+build.123\n const versionRegex = /^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9.-]+)?(\\+[a-zA-Z0-9.-]+)?$/;\n return versionRegex.test(version);\n }\n\n /**\n * 查找 package.json 文件路径\n *\n * 尝试从多个可能的路径中查找 package.json 文件\n *\n * @returns package.json 文件路径,如果找不到则返回 null\n */\n private static findPackageJsonPath(): string | null {\n const __filename = fileURLToPath(import.meta.url);\n const currentDir = path.dirname(__filename);\n\n const possiblePaths = [\n // 从 src/utils/version.js 到项目根目录的 package.json\n path.join(currentDir, \"..\", \"..\", \"package.json\"),\n // 从 dist/utils/version.js 到项目根目录的 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 return packagePath;\n }\n }\n\n return null;\n }\n\n /**\n * 运行时从 package.json 读取版本号\n */\n private static getRuntimeVersion(): string {\n // 如果有缓存,直接返回\n if (VersionUtils.cachedVersion) {\n return VersionUtils.cachedVersion;\n }\n\n try {\n const packagePath = VersionUtils.findPackageJsonPath();\n if (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 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 * 运行时从 package.json 读取完整版本信息\n */\n private static getRuntimeVersionInfo(): VersionInfo {\n try {\n const packagePath = VersionUtils.findPackageJsonPath();\n if (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 return { version: \"unknown\" };\n } catch (error) {\n console.warn(\"无法读取版本信息:\", error);\n return { version: \"unknown\" };\n }\n }\n\n /**\n * 清除版本缓存\n *\n * 主要用于测试场景\n */\n static clearCache(): void {\n VersionUtils.cachedVersion = null;\n VersionUtils.cachedVersionInfo = null;\n }\n}\n","/**\n * 错误处理器\n */\n\nimport chalk from \"chalk\";\nimport { ERROR_MESSAGES } from \"./ErrorMessages\";\nimport { CLIError } from \"./index\";\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 private static wrapError(error: unknown, context: string): CLIError {\n if (error instanceof CLIError) {\n return error;\n }\n if (error instanceof Error) {\n return new CLIError(\n `${context}失败: ${error.message}`,\n \"OPERATION_FAILED\",\n 1\n );\n }\n return new CLIError(`${context}失败: 未知错误`, \"OPERATION_FAILED\", 1);\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 throw ErrorHandler.wrapError(error, context);\n }\n }\n\n /**\n * 同步操作错误处理包装器\n */\n static handleSync<T>(operation: () => T, context: string): T {\n try {\n return operation();\n } catch (error) {\n throw ErrorHandler.wrapError(error, context);\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 { ERROR_CODES } from \"../Constants\";\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 * 负责创建和管理命令处理器,包括:\n * - 服务命令处理器\n * - 配置命令处理器\n * - 项目命令处理器\n * - MCP 命令处理器\n * - 端点命令处理器\n *\n * @module src/cli/commands/CommandHandlerFactory\n */\n\nimport type {\n CommandHandler,\n ICommandHandlerFactory,\n} from \"../interfaces/Command\";\nimport type { IDIContainer } from \"../interfaces/Config\";\n\n/**\n * 命令处理器工厂实现\n */\nexport class CommandHandlerFactory implements ICommandHandlerFactory {\n constructor(private container: IDIContainer) {}\n\n /**\n * 创建所有命令处理器\n */\n createHandlers(): CommandHandler[] {\n return [\n this.createHandler(\"service\"),\n this.createHandler(\"config\"),\n this.createHandler(\"project\"),\n this.createHandler(\"mcp\"),\n this.createHandler(\"endpoint\"),\n ];\n }\n\n /**\n * 创建指定类型的命令处理器\n */\n createHandler(type: string): CommandHandler {\n switch (type) {\n case \"service\":\n return this.createServiceCommandHandler();\n case \"config\":\n return this.createConfigCommandHandler();\n case \"project\":\n return this.createProjectCommandHandler();\n case \"mcp\":\n return this.createMcpCommandHandler();\n case \"endpoint\":\n return this.createEndpointCommandHandler();\n default:\n throw new Error(`未知的命令处理器类型: ${type}`);\n }\n }\n\n /**\n * 创建服务命令处理器\n */\n private createServiceCommandHandler(): CommandHandler {\n // 动态导入以避免循环依赖\n const { ServiceCommandHandler } = require(\"./ServiceCommandHandler.js\");\n return new ServiceCommandHandler(this.container);\n }\n\n /**\n * 创建配置命令处理器\n */\n private createConfigCommandHandler(): CommandHandler {\n const { ConfigCommandHandler } = require(\"./ConfigCommandHandler.js\");\n return new ConfigCommandHandler(this.container);\n }\n\n /**\n * 创建项目命令处理器\n */\n private createProjectCommandHandler(): CommandHandler {\n const { ProjectCommandHandler } = require(\"./ProjectCommandHandler.js\");\n return new ProjectCommandHandler(this.container);\n }\n\n /**\n * 创建MCP命令处理器\n */\n private createMcpCommandHandler(): CommandHandler {\n const { McpCommandHandler } = require(\"./McpCommandHandler.js\");\n return new McpCommandHandler(this.container);\n }\n\n /**\n * 创建端点命令处理器\n */\n private createEndpointCommandHandler(): CommandHandler {\n const { EndpointCommandHandler } = require(\"./EndpointCommandHandler.js\");\n return new EndpointCommandHandler(this.container);\n }\n}\n","/**\n * 命令注册器\n */\n\nimport type { Command } from \"commander\";\nimport { ErrorHandler } from \"../errors/ErrorHandlers\";\nimport type {\n CommandHandler,\n ICommandHandlerFactory,\n ICommandRegistry,\n} from \"../interfaces/Command\";\nimport type { IDIContainer } from \"../interfaces/Config\";\nimport { CommandHandlerFactory } from \"./CommandHandlerFactory\";\n\n/**\n * 命令注册器实现\n */\nexport class CommandRegistry implements ICommandRegistry {\n private handlers: CommandHandler[] = [];\n private handlerFactory: ICommandHandlerFactory;\n\n constructor(private container: IDIContainer) {\n this.handlerFactory = new CommandHandlerFactory(container);\n }\n\n /**\n * 包装命令处理函数,统一处理错误\n * @param handler 命令处理函数\n * @returns 包装后的处理函数\n */\n private wrapCommandHandler(\n handler: (args: string[], options: Record<string, unknown>) => Promise<void>\n ) {\n return async (...args: unknown[]) => {\n try {\n // Commander.js 传递的最后一个参数是 Command 对象,包含选项值\n const command = args[args.length - 1] as {\n opts: () => Record<string, unknown>;\n };\n const options = command.opts();\n await handler(args.slice(0, -1) as string[], options);\n } catch (error) {\n ErrorHandler.handle(error as Error);\n }\n };\n }\n\n /**\n * 注册所有命令到 Commander 程序\n */\n async registerCommands(program: Command): Promise<void> {\n try {\n // 注册基本命令\n this.registerVersionCommand(program);\n this.registerHelpCommand(program);\n\n // 创建并注册所有功能命令处理器\n const handlers = this.handlerFactory.createHandlers();\n for (const handler of handlers) {\n this.registerHandler(handler);\n this.registerCommand(program, handler);\n }\n\n // 注册向后兼容的顶级服务命令\n this.registerLegacyServiceCommands(program, handlers);\n } catch (error) {\n ErrorHandler.handle(error as Error);\n }\n }\n\n /**\n * 注册命令处理器\n */\n registerHandler(handler: CommandHandler): void {\n this.handlers.push(handler);\n }\n\n /**\n * 注册单个命令\n */\n registerCommand(program: Command, handler: CommandHandler): void {\n // 如果有子命令,创建命令组\n if (handler.subcommands && handler.subcommands.length > 0) {\n const commandGroup = program\n .command(handler.name)\n .description(handler.description);\n\n for (const subcommand of handler.subcommands) {\n let subcommandName = subcommand.name;\n\n // 特殊处理需要参数的子命令\n if (subcommand.name === \"get\") {\n subcommandName = \"get <key>\";\n } else if (subcommand.name === \"set\") {\n subcommandName = \"set <key> <value>\";\n } else if (subcommand.name === \"call\") {\n subcommandName = \"call <serviceName> <toolName>\";\n }\n\n const cmd = commandGroup\n .command(subcommandName)\n .description(subcommand.description);\n\n // 添加子命令选项\n if (subcommand.options) {\n for (const option of subcommand.options) {\n cmd.option(option.flags, option.description, option.defaultValue);\n }\n }\n\n // 设置子命令处理函数\n cmd.action(\n this.wrapCommandHandler(async (args, options) => {\n await subcommand.execute(args, options);\n })\n );\n }\n\n // 设置主命令的默认行为\n commandGroup.action(\n this.wrapCommandHandler(async (args, options) => {\n await handler.execute(args, options);\n })\n );\n } else {\n // 没有子命令,注册为普通命令\n let commandName = handler.name;\n\n // 特殊处理 create 命令,需要接受项目名称参数\n if (handler.name === \"create\") {\n commandName = \"create <projectName>\";\n }\n\n const command = program\n .command(commandName)\n .description(handler.description);\n\n // 添加选项\n if (handler.options) {\n for (const option of handler.options) {\n command.option(option.flags, option.description, option.defaultValue);\n }\n }\n\n // 设置主命令处理函数\n command.action(\n this.wrapCommandHandler(async (args, options) => {\n await handler.execute(args, options);\n })\n );\n }\n }\n\n /**\n * 注册版本命令\n */\n private registerVersionCommand(program: Command): void {\n const versionUtils = this.container.get(\"versionUtils\") as any;\n\n program.version(versionUtils.getVersion(), \"-v, --version\", \"显示版本信息\");\n\n // 注册 --info 选项\n program.option(\"--info\", \"显示详细信息\");\n\n // 注册 --version-info 选项\n program.option(\"--version-info\", \"显示详细版本信息\");\n }\n\n /**\n * 注册帮助命令\n */\n private registerHelpCommand(program: Command): void {\n program.helpOption(\"-h, --help\", \"显示帮助信息\").addHelpText(\n \"after\",\n `\n示例:\n xiaozhi init # 初始化配置文件\n xiaozhi start # 启动服务(包含 Web UI)\n xiaozhi start -d # 后台启动服务\n xiaozhi start -s 3000 # 以 MCP Server 模式启动\n xiaozhi stop # 停止服务\n xiaozhi status # 检查服务状态\n xiaozhi restart -d # 重启服务(后台模式)\n xiaozhi config mcpEndpoint <url> # 设置 MCP 端点\n xiaozhi create my-project # 创建项目\n xiaozhi mcp list # 列出 MCP 服务\n\n更多信息请访问: https://github.com/your-org/xiaozhi-client\n`\n );\n }\n\n /**\n * 注册向后兼容的顶级服务命令\n */\n private registerLegacyServiceCommands(\n program: Command,\n handlers: CommandHandler[]\n ): void {\n // 找到服务命令处理器\n const serviceHandler = handlers.find((h) => h.name === \"service\");\n if (!serviceHandler || !serviceHandler.subcommands) {\n return;\n }\n\n // 为每个服务子命令创建顶级命令\n for (const subcommand of serviceHandler.subcommands) {\n const command = program\n .command(subcommand.name)\n .description(subcommand.description);\n\n // 添加选项\n if (subcommand.options) {\n for (const option of subcommand.options) {\n command.option(option.flags, option.description, option.defaultValue);\n }\n }\n\n // 设置命令处理函数\n command.action(\n this.wrapCommandHandler(async (args, options) => {\n await subcommand.execute(args, options);\n })\n );\n }\n }\n\n /**\n * 注册服务管理命令(稍后实现)\n */\n // private async registerServiceCommands(program: Command): Promise<void> {\n // const serviceCommand = this.container.get('serviceCommand');\n\n // // start 命令\n // program\n // .command('start')\n // .description('启动服务')\n // .option('-d, --daemon', '在后台运行服务')\n // .option('-u, --ui', '同时启动 Web UI 服务')\n // .option('-s, --server [port]', '以 MCP Server 模式启动 (可选指定端口,默认 3000)')\n // .option('--stdio', '以 stdio 模式运行 MCP Server (用于 Cursor 等客户端)')\n // .action(async (options) => {\n // await serviceCommand.start(options);\n // });\n\n // // stop 命令\n // program\n // .command('stop')\n // .description('停止服务')\n // .action(async () => {\n // await serviceCommand.stop();\n // });\n\n // // status 命令\n // program\n // .command('status')\n // .description('检查服务状态')\n // .action(async () => {\n // await serviceCommand.status();\n // });\n\n // // restart 命令\n // program\n // .command('restart')\n // .description('重启服务')\n // .option('-d, --daemon', '在后台运行服务')\n // .option('-u, --ui', '同时启动 Web UI 服务')\n // .action(async (options) => {\n // await serviceCommand.restart(options);\n // });\n\n // // attach 命令\n // program\n // .command('attach')\n // .description('连接到后台服务查看日志')\n // .action(async () => {\n // await serviceCommand.attach();\n // });\n // }\n\n /**\n * 注册配置管理命令(稍后实现)\n */\n // private async registerConfigCommands(program: Command): Promise<void> {\n // const configCommand = this.container.get('configCommand');\n\n // // init 命令\n // program\n // .command('init')\n // .description('初始化配置文件')\n // .option('-f, --format <format>', '配置文件格式 (json, json5, jsonc)', 'json')\n // .action(async (options) => {\n // await configCommand.init(options);\n // });\n\n // // config 命令\n // program\n // .command('config <key> [value]')\n // .description('查看或设置配置')\n // .action(async (key, value) => {\n // await configCommand.manage(key, value);\n // });\n // }\n\n /**\n * 注册项目管理命令(稍后实现)\n */\n // private async registerProjectCommands(program: Command): Promise<void> {\n // const projectCommand = this.container.get('projectCommand');\n\n // // create 命令\n // program\n // .command('create <projectName>')\n // .description('创建项目')\n // .option('-t, --template <templateName>', '使用指定模板创建项目')\n // .action(async (projectName, options) => {\n // await projectCommand.create(projectName, options);\n // });\n // }\n\n /**\n * 注册 MCP 管理命令(稍后实现)\n */\n // private async registerMcpCommands(program: Command): Promise<void> {\n // const mcpCommand = this.container.get('mcpCommand');\n\n // // mcp 命令组\n // const mcpGroup = program.command('mcp').description('MCP 服务和工具管理');\n\n // // mcp list 命令\n // mcpGroup\n // .command('list')\n // .description('列出 MCP 服务')\n // .option('--tools', '显示所有服务的工具列表')\n // .action(async (options) => {\n // await mcpCommand.list(options);\n // });\n\n // // mcp server 命令\n // mcpGroup\n // .command('server <serverName>')\n // .description('管理指定的 MCP 服务')\n // .action(async (serverName) => {\n // await mcpCommand.server(serverName);\n // });\n\n // // mcp tool 命令\n // mcpGroup\n // .command('tool <serverName> <toolName> <action>')\n // .description('管理 MCP 工具 (enable/disable)')\n // .action(async (serverName, toolName, action) => {\n // await mcpCommand.tool(serverName, toolName, action);\n // });\n // }\n}\n"],"mappings":"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","names":["existsSync","commentJson","path","tool","resolve","TypeFieldNormalizer","normalizeTypeField","init_manager","init_manager","dirname","resolve","copyFileSync","existsSync","path","dirname","resolve","fileURLToPath","__dirname","fs","path","path","tmpdir","path","fileURLToPath","resolve","fs","resolve","path","consola","configManager","resolve","spawn","fs","fs","path","consola","path","chalk","configManager","path","chalk","ora","resolve","chalk","consola","ora","chalk","ora","configManager","path","fileURLToPath","fileURLToPath","path","configManager","ServiceCommandHandler","ConfigCommandHandler","ProjectCommandHandler","McpCommandHandler","EndpointCommandHandler","program"]}