xiaozhi-client 1.9.4-beta.1 → 1.9.4-beta.10

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.
Files changed (114) hide show
  1. package/dist/backend/Logger.js +3 -0
  2. package/dist/backend/Logger.js.map +1 -0
  3. package/dist/backend/WebServer.js +93 -0
  4. package/dist/backend/WebServer.js.map +1 -0
  5. package/dist/backend/WebServerLauncher.js +11 -17
  6. package/dist/backend/WebServerLauncher.js.map +1 -1
  7. package/dist/backend/managers/MCPServiceManagerSingleton.js +27 -0
  8. package/dist/backend/managers/MCPServiceManagerSingleton.js.map +1 -0
  9. package/dist/backend/package.json +31 -50
  10. package/dist/backend/templates/json5/xiaozhi.config.json5 +14 -14
  11. package/dist/cli/index.js +29 -0
  12. package/dist/cli/index.js.map +1 -0
  13. package/dist/config/index.js +2 -0
  14. package/dist/config/index.js.map +1 -0
  15. package/dist/frontend/assets/index-88NfCOo9.js.map +1 -1
  16. package/dist/shared-types/api-aP8BHcbg.d.ts +97 -0
  17. package/dist/shared-types/api.d.ts +202 -0
  18. package/dist/shared-types/api.js +50 -0
  19. package/dist/shared-types/api.js.map +1 -0
  20. package/dist/shared-types/app-oAmColIN.d.ts +91 -0
  21. package/dist/shared-types/chunk-BMOKIX3Q.js +51 -0
  22. package/dist/shared-types/chunk-BMOKIX3Q.js.map +1 -0
  23. package/dist/shared-types/config.d.ts +97 -0
  24. package/dist/shared-types/config.js +1 -0
  25. package/dist/shared-types/config.js.map +1 -0
  26. package/dist/shared-types/coze.d.ts +30 -0
  27. package/dist/shared-types/coze.js +1 -0
  28. package/dist/shared-types/coze.js.map +1 -0
  29. package/dist/shared-types/index.d.ts +186 -0
  30. package/dist/shared-types/index.js +4 -17
  31. package/dist/shared-types/index.js.map +1 -1
  32. package/dist/shared-types/mcp.d.ts +91 -0
  33. package/dist/shared-types/mcp.js +22 -0
  34. package/dist/shared-types/mcp.js.map +1 -0
  35. package/dist/shared-types/message-xoOM7ZuT.d.ts +154 -0
  36. package/dist/shared-types/timeout-CCp_IFHg.d.ts +39 -0
  37. package/dist/shared-types/toolApi-DYSy8ebd.d.ts +208 -0
  38. package/dist/shared-types/utils.d.ts +115 -0
  39. package/dist/shared-types/utils.js +15 -0
  40. package/dist/shared-types/utils.js.map +1 -0
  41. package/dist/shared-types/workflow-DDqq5Jgp.d.ts +83 -0
  42. package/package.json +31 -50
  43. package/templates/json5/xiaozhi.config.json5 +14 -14
  44. package/dist/backend/WebServerLauncher.d.ts +0 -1
  45. package/dist/backend/cli.d.ts +0 -1
  46. package/dist/backend/cli.js +0 -129
  47. package/dist/backend/cli.js.map +0 -1
  48. package/dist/cli.js +0 -2
  49. package/dist/docs/404/index.html +0 -19
  50. package/dist/docs/404.html +0 -19
  51. package/dist/docs/_next/static/JZ0ESgtaHnsqkxSabOqqU/_buildManifest.js +0 -1
  52. package/dist/docs/_next/static/JZ0ESgtaHnsqkxSabOqqU/_ssgManifest.js +0 -1
  53. package/dist/docs/_next/static/chunks/112-c9cbd8401d35f825.js +0 -4
  54. package/dist/docs/_next/static/chunks/2a9bc5d7-4c434acf20ba934a.js +0 -1
  55. package/dist/docs/_next/static/chunks/782-c26ca6c69e488d48.js +0 -1
  56. package/dist/docs/_next/static/chunks/799-fe0d35806fd12012.js +0 -1
  57. package/dist/docs/_next/static/chunks/9b1cb2c3-cc9ed703e6aef1a2.js +0 -1
  58. package/dist/docs/_next/static/chunks/app/[[...mdxPath]]/page-48f5c8f3210e0a8a.js +0 -1
  59. package/dist/docs/_next/static/chunks/app/_not-found/page-2e38866a1cbb77e4.js +0 -1
  60. package/dist/docs/_next/static/chunks/app/layout-e8f420537fd59e8d.js +0 -1
  61. package/dist/docs/_next/static/chunks/framework-b73126dabbf07067.js +0 -1
  62. package/dist/docs/_next/static/chunks/main-75dc65850b89d90d.js +0 -1
  63. package/dist/docs/_next/static/chunks/main-app-3303134270964ce6.js +0 -1
  64. package/dist/docs/_next/static/chunks/pages/_app-e698a68d07c8993d.js +0 -1
  65. package/dist/docs/_next/static/chunks/pages/_error-189a41ab5833da03.js +0 -1
  66. package/dist/docs/_next/static/chunks/polyfills-42372ed130431b0a.js +0 -1
  67. package/dist/docs/_next/static/chunks/webpack-10e2bf7d852ddb6e.js +0 -1
  68. package/dist/docs/_next/static/css/2d82b615fcca1590.css +0 -1
  69. package/dist/docs/_next/static/css/b03484a3c350cf6e.css +0 -1
  70. package/dist/docs/_next/static/css/b289318ef4b60b0a.css +0 -1
  71. package/dist/docs/_next/static/media/get-parameter.62eee93d.png +0 -0
  72. package/dist/docs/changelog/index.html +0 -585
  73. package/dist/docs/changelog/index.txt +0 -1079
  74. package/dist/docs/images/add-to-cherry-studio/step-1.png +0 -0
  75. package/dist/docs/images/add-to-cherry-studio/step-2.png +0 -0
  76. package/dist/docs/images/add-to-cherry-studio/step-3.png +0 -0
  77. package/dist/docs/images/add-to-cherry-studio/step-4.png +0 -0
  78. package/dist/docs/images/add-to-cherry-studio/step-5.png +0 -0
  79. package/dist/docs/images/add-to-cursor/step-1.png +0 -0
  80. package/dist/docs/images/add-to-cursor/step-2.png +0 -0
  81. package/dist/docs/images/add-to-cursor/step-3.png +0 -0
  82. package/dist/docs/images/coze-workflow/config-workflow-step-1.png +0 -0
  83. package/dist/docs/images/coze-workflow/config-workflow-step-2.png +0 -0
  84. package/dist/docs/images/coze-workflow/config-workflow-step-3.png +0 -0
  85. package/dist/docs/images/coze-workflow/get-parameter.png +0 -0
  86. package/dist/docs/images/integrate-to-cherry-studio.png +0 -0
  87. package/dist/docs/images/integrate-to-cursor.png +0 -0
  88. package/dist/docs/images/modelscope/step-1.png +0 -0
  89. package/dist/docs/images/modelscope/step-2.png +0 -0
  90. package/dist/docs/images/modelscope/step-3.png +0 -0
  91. package/dist/docs/images/modelscope/step-4.png +0 -0
  92. package/dist/docs/images/preview.png +0 -0
  93. package/dist/docs/images/use-multi-xiaozhi-mcp-endpoints/step-1.png +0 -0
  94. package/dist/docs/images/use-multi-xiaozhi-mcp-endpoints/step-2.png +0 -0
  95. package/dist/docs/images/use-multi-xiaozhi-mcp-endpoints/step-3.png +0 -0
  96. package/dist/docs/images/use-multi-xiaozhi-mcp-endpoints/step-4.png +0 -0
  97. package/dist/docs/images/use-multi-xiaozhi-mcp-endpoints/step-5.png +0 -0
  98. package/dist/docs/images/web-ui-preview.png +0 -0
  99. package/dist/docs/index.html +0 -22
  100. package/dist/docs/index.txt +0 -41
  101. package/dist/docs/quickstart/index.html +0 -64
  102. package/dist/docs/quickstart/index.txt +0 -185
  103. package/dist/docs/reference/command/index.html +0 -20
  104. package/dist/docs/reference/command/index.txt +0 -42
  105. package/dist/docs/usage/as-mcp/index.html +0 -36
  106. package/dist/docs/usage/as-mcp/index.txt +0 -101
  107. package/dist/docs/usage/coze-workflow/index.html +0 -35
  108. package/dist/docs/usage/coze-workflow/index.txt +0 -120
  109. package/dist/docs/usage/docker/index.html +0 -40
  110. package/dist/docs/usage/docker/index.txt +0 -154
  111. package/dist/docs/usage/modelscope/index.html +0 -32
  112. package/dist/docs/usage/modelscope/index.txt +0 -109
  113. package/dist/docs/usage/multi-endpoint/index.html +0 -32
  114. package/dist/docs/usage/multi-endpoint/index.txt +0 -118
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../apps/backend/Logger.ts","../../apps/backend/services/EventBus.ts","../../apps/backend/utils/TypeFieldNormalizer.ts","../../apps/backend/utils/mcpServerUtils.ts","../../apps/backend/lib/config/manager.ts","../../apps/backend/cli/Constants.ts","../../apps/backend/cli/errors/ErrorMessages.ts","../../apps/backend/cli/errors/index.ts","../../apps/backend/cli/errors/ErrorHandlers.ts","../../apps/backend/cli/utils/FileUtils.ts","../../apps/backend/cli/utils/FormatUtils.ts","../../apps/backend/cli/utils/PathUtils.ts","../../apps/backend/cli/utils/PlatformUtils.ts","../../apps/backend/cli/utils/Validation.ts","../../apps/backend/cli/utils/VersionUtils.ts","../../apps/backend/cli/services/ProcessManager.ts","../../apps/backend/cli/services/DaemonManager.ts","../../apps/backend/lib/mcp/types.ts","../../apps/backend/lib/mcp/utils.ts","../../apps/backend/lib/config/adapter.ts","../../apps/backend/lib/endpoint/connection.ts","../../apps/backend/lib/endpoint/manager.ts","../../apps/backend/lib/endpoint/index.ts","../../apps/backend/lib/coze/config.ts","../../apps/backend/lib/coze/client.ts","../../apps/backend/lib/coze/service.ts","../../apps/backend/lib/coze/index.ts","../../apps/backend/types/mcp.ts","../../apps/backend/types/timeout.ts","../../apps/backend/lib/mcp/custom.ts","../../apps/backend/lib/mcp/log.ts","../../apps/backend/lib/mcp/message.ts","../../apps/backend/lib/mcp/transports/TransportAdapter.ts","../../apps/backend/lib/mcp/transports/StdioAdapter.ts","../../apps/backend/lib/mcp/transports/WebSocketAdapter.ts","../../apps/backend/lib/mcp/transports/index.ts","../../apps/backend/lib/mcp/manager.ts","../../apps/backend/lib/mcp/transport-factory.ts","../../apps/backend/lib/mcp/connection.ts","../../apps/backend/types/coze.ts","../../apps/backend/types/hono.context.ts","../../apps/backend/types/index.ts","../../apps/backend/lib/mcp/cache.ts","../../apps/backend/lib/mcp/index.ts","../../apps/backend/middlewares/logger.middleware.ts","../../apps/backend/middlewares/cors.middleware.ts","../../apps/backend/middlewares/error.middleware.ts","../../apps/backend/errors/MCPErrors.middleware.ts","../../apps/backend/middlewares/mcpServiceManager.middleware.ts","../../apps/backend/middlewares/endpointManager.middleware.ts","../../apps/backend/handlers/MCPEndpointApiHandler.ts","../../apps/backend/middlewares/endpoints.middleware.ts","../../apps/backend/middlewares/index.ts","../../apps/backend/handlers/AbstractApiHandler.ts","../../apps/backend/handlers/ConfigApiHandler.ts","../../apps/backend/handlers/CozeApiHandler.ts","../../apps/backend/handlers/HeartbeatHandler.ts","../../apps/backend/handlers/MCPRouteHandler.ts","../../apps/backend/errors/MCPErrors.ts","../../apps/backend/handlers/MCPServerApiHandler.ts","../../apps/backend/handlers/RealtimeNotificationHandler.ts","../../apps/backend/handlers/ServiceApiHandler.ts","../../apps/backend/handlers/StaticFileHandler.ts","../../apps/backend/handlers/StatusApiHandler.ts","../../apps/backend/types/toolApi.ts","../../apps/backend/handlers/ToolApiHandler.ts","../../apps/backend/handlers/ToolCallLogApiHandler.ts","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/constants.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/debug.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/re.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/parse-options.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/identifiers.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/classes/semver.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/parse.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/valid.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/clean.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/inc.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/diff.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/major.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/minor.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/patch.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/prerelease.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/compare.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/rcompare.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/compare-loose.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/compare-build.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/sort.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/rsort.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/gt.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/lt.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/eq.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/neq.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/gte.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/lte.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/cmp.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/coerce.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/internal/lrucache.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/classes/range.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/classes/comparator.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/functions/satisfies.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/to-comparators.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/max-satisfying.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/min-satisfying.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/min-version.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/valid.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/outside.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/gtr.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/ltr.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/intersects.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/simplify.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/ranges/subset.js","../../node_modules/.pnpm/semver@7.7.3/node_modules/semver/index.js","../../apps/backend/lib/npm/manager.ts","../../apps/backend/lib/npm/index.ts","../../apps/backend/handlers/UpdateApiHandler.ts","../../apps/backend/handlers/VersionApiHandler.ts","../../apps/backend/handlers/index.ts","../../apps/backend/services/StatusService.ts","../../apps/backend/services/NotificationService.ts","../../apps/backend/services/ErrorHandler.ts","../../apps/backend/services/index.ts","../../apps/backend/routes/RouteManager.ts","../../apps/backend/routes/domains/config.route.ts","../../apps/backend/routes/domains/status.route.ts","../../apps/backend/routes/domains/tools.route.ts","../../apps/backend/routes/domains/mcp.route.ts","../../apps/backend/routes/domains/version.route.ts","../../apps/backend/routes/domains/services.route.ts","../../apps/backend/routes/domains/update.route.ts","../../apps/backend/routes/domains/static.route.ts","../../apps/backend/routes/domains/coze.route.ts","../../apps/backend/routes/domains/tool-logs.route.ts","../../apps/backend/routes/domains/mcpserver.route.ts","../../apps/backend/routes/domains/endpoint.route.ts","../../apps/backend/routes/domains/misc.route.ts","../../apps/backend/routes/domains/index.ts","../../apps/backend/routes/index.ts","../../apps/backend/WebServer.ts","../../apps/backend/cli/services/ServiceManager.ts","../../apps/backend/cli/services/TemplateManager.ts","../../apps/backend/cli/Container.ts","../../apps/backend/cli/interfaces/Command.ts","../../apps/backend/cli/commands/ServiceCommandHandler.ts","../../apps/backend/cli/commands/ConfigCommandHandler.ts","../../apps/backend/cli/commands/ProjectCommandHandler.ts","../../apps/backend/cli/interfaces/CommandTypes.ts","../../apps/backend/cli/commands/McpCommandHandler.ts","../../apps/backend/cli/commands/EndpointCommandHandler.ts","../../apps/backend/cli.ts","../../apps/backend/cli/commands/CommandHandlerFactory.ts","../../apps/backend/cli/commands/index.ts"],"sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport chalk from \"chalk\";\nimport pino from \"pino\";\nimport type { Logger as PinoLogger } from \"pino\";\nimport { z } from \"zod\";\n\nconst LogLevelSchema = z.enum([\n \"fatal\",\n \"error\",\n \"warn\",\n \"info\",\n \"debug\",\n \"trace\",\n]);\ntype Level = z.infer<typeof LogLevelSchema>;\n\n/**\n * 格式化日期时间为 YYYY-MM-DD HH:mm:ss 格式\n * @param date 要格式化的日期对象\n * @returns 格式化后的日期时间字符串\n */\nfunction formatDateTime(date: Date): string {\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, \"0\");\n const day = String(date.getDate()).padStart(2, \"0\");\n const hours = String(date.getHours()).padStart(2, \"0\");\n const minutes = String(date.getMinutes()).padStart(2, \"0\");\n const seconds = String(date.getSeconds()).padStart(2, \"0\");\n\n return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;\n}\n\n/**\n * 高性能日志记录器,基于 pino 实现\n *\n * 特性:\n * - 支持控制台和文件双重输出\n * - 支持守护进程模式(仅文件输出)\n * - 支持结构化日志记录\n * - 自动日志文件轮转和管理\n * - 高性能异步写入\n * - 完整的错误堆栈跟踪\n */\nexport class Logger {\n private logFilePath: string | null = null;\n private pinoInstance: PinoLogger;\n private isDaemonMode: boolean;\n private logLevel: Level; // 新增:动态日志级别\n private maxLogFileSize = 10 * 1024 * 1024; // 10MB 默认最大文件大小\n private maxLogFiles = 5; // 最多保留5个日志文件\n\n constructor(level: Level = \"info\") {\n // 检查是否为守护进程模式\n this.isDaemonMode = process.env.XIAOZHI_DAEMON === \"true\";\n\n // 设置并验证日志级别\n this.logLevel = this.validateLogLevel(level);\n\n // 创建 pino 实例\n this.pinoInstance = this.createPinoInstance();\n }\n\n /**\n * 验证日志级别\n * @param level 日志级别\n * @returns 验证后的日志级别\n */\n private validateLogLevel(level: string): Level {\n const normalizedLevel = level.toLowerCase();\n const result = LogLevelSchema.safeParse(normalizedLevel);\n\n if (result.success) {\n return result.data;\n }\n\n return \"info\";\n }\n\n private createPinoInstance(): PinoLogger {\n const streams: pino.StreamEntry[] = [];\n\n // 控制台流 - 只在非守护进程模式下添加\n if (!this.isDaemonMode) {\n // 使用高性能的控制台输出流\n const consoleStream = this.createOptimizedConsoleStream();\n streams.push({\n level: this.logLevel, // 修改:使用动态日志级别\n stream: consoleStream,\n });\n }\n\n // 文件流 - 如果有日志文件路径,使用高性能异步写入\n if (this.logFilePath) {\n streams.push({\n level: this.logLevel, // 修改:使用动态日志级别\n stream: pino.destination({\n dest: this.logFilePath,\n sync: false, // 异步写入提升性能\n append: true,\n mkdir: true,\n }),\n });\n }\n\n // 如果没有流,创建一个空的流避免错误\n if (streams.length === 0) {\n streams.push({\n level: this.logLevel, // 修改:使用动态日志级别\n stream: pino.destination({ dest: \"/dev/null\" }),\n });\n }\n\n return pino(\n {\n level: this.logLevel, // 修改:使用动态日志级别\n // 高性能配置\n timestamp:\n pino.stdTimeFunctions?.isoTime || (() => `,\"time\":${Date.now()}`),\n formatters: {\n // 优化级别格式化\n level: (_label: string, number: number) => ({ level: number }),\n },\n // 禁用不必要的功能以提升性能\n base: null, // 不包含 pid 和 hostname\n serializers: {\n // 优化错误序列化,在测试环境中安全处理\n err: pino.stdSerializers?.err || ((err: any) => err),\n },\n },\n pino.multistream(streams, { dedupe: true })\n );\n }\n\n private createOptimizedConsoleStream() {\n // 预编译级别映射以提升性能\n const levelMap = new Map([\n [20, { name: \"DEBUG\", color: chalk.gray }],\n [30, { name: \"INFO\", color: chalk.blue }],\n [40, { name: \"WARN\", color: chalk.yellow }],\n [50, { name: \"ERROR\", color: chalk.red }],\n [60, { name: \"FATAL\", color: chalk.red }],\n ]);\n\n return {\n write: (chunk: string) => {\n try {\n const logObj = JSON.parse(chunk);\n const message = this.formatConsoleMessageOptimized(logObj, levelMap);\n // 在测试环境中安全地写入\n this.safeWrite(`${message}\\n`);\n } catch (error) {\n // 如果解析失败,直接输出原始内容\n this.safeWrite(chunk);\n }\n },\n };\n }\n\n /**\n * 安全地写入到 stderr,在测试环境中避免错误\n */\n private safeWrite(content: string): void {\n try {\n if (process.stderr && typeof process.stderr.write === \"function\") {\n process.stderr.write(content);\n } else if (console && typeof console.error === \"function\") {\n // 在测试环境中回退到 console.error\n console.error(content.trim());\n }\n } catch (error) {\n // 在极端情况下静默失败,避免测试中断\n }\n }\n\n private formatConsoleMessageOptimized(\n logObj: any,\n levelMap: Map<number, { name: string; color: (text: string) => string }>\n ): string {\n const timestamp = formatDateTime(new Date());\n\n const levelInfo = levelMap.get(logObj.level) || {\n name: \"UNKNOWN\",\n color: (text: string) => text,\n };\n const coloredLevel = levelInfo.color(`[${levelInfo.name}]`);\n\n // 处理结构化日志中的 args,保持兼容性\n let message = logObj.msg;\n if (logObj.args && Array.isArray(logObj.args)) {\n const argsStr = logObj.args\n .map((arg: any) =>\n typeof arg === \"object\" ? JSON.stringify(arg) : String(arg)\n )\n .join(\" \");\n message = `${message} ${argsStr}`;\n }\n\n return `[${timestamp}] ${coloredLevel} ${message}`;\n }\n\n /**\n * 初始化日志文件\n * @param projectDir 项目目录\n */\n initLogFile(projectDir: string): void {\n this.logFilePath = path.join(projectDir, \"xiaozhi.log\");\n\n // 检查并轮转日志文件\n this.rotateLogFileIfNeeded();\n\n // 确保日志文件存在\n if (!fs.existsSync(this.logFilePath)) {\n fs.writeFileSync(this.logFilePath, \"\");\n }\n\n // 重新创建 pino 实例以包含文件流\n this.pinoInstance = this.createPinoInstance();\n }\n\n /**\n * 设置是否启用文件日志\n * @param enable 是否启用\n */\n enableFileLogging(enable: boolean): void {\n // 在 pino 实现中,文件日志的启用/禁用通过重新创建实例来实现\n // 这里保持方法兼容性,但实际上文件日志在 initLogFile 时就已经启用\n if (enable && this.logFilePath) {\n // 重新创建 pino 实例以确保文件流正确配置\n this.pinoInstance = this.createPinoInstance();\n }\n }\n\n /**\n * 记录信息级别日志\n * @param message 日志消息\n * @param args 额外参数\n * @example\n * logger.info('用户登录', 'userId', 12345);\n * logger.info({ userId: 12345, action: 'login' }, '用户登录');\n */\n info(message: string, ...args: any[]): void;\n /**\n * 记录结构化信息级别日志\n * @param obj 结构化日志对象\n * @param message 可选的日志消息\n */\n info(obj: object, message?: string): void;\n info(messageOrObj: string | object, ...args: any[]): void {\n if (typeof messageOrObj === \"string\") {\n if (args.length === 0) {\n this.pinoInstance.info(messageOrObj);\n } else {\n this.pinoInstance.info({ args }, messageOrObj);\n }\n } else {\n // 结构化日志支持\n this.pinoInstance.info(messageOrObj, args[0] || \"\");\n }\n }\n\n success(message: string, ...args: any[]): void;\n success(obj: object, message?: string): void;\n success(messageOrObj: string | object, ...args: any[]): void {\n // success 映射为 info 级别,保持 API 兼容性\n if (typeof messageOrObj === \"string\") {\n if (args.length === 0) {\n this.pinoInstance.info(messageOrObj);\n } else {\n this.pinoInstance.info({ args }, messageOrObj);\n }\n } else {\n this.pinoInstance.info(messageOrObj, args[0] || \"\");\n }\n }\n\n warn(message: string, ...args: any[]): void;\n warn(obj: object, message?: string): void;\n warn(messageOrObj: string | object, ...args: any[]): void {\n if (typeof messageOrObj === \"string\") {\n if (args.length === 0) {\n this.pinoInstance.warn(messageOrObj);\n } else {\n this.pinoInstance.warn({ args }, messageOrObj);\n }\n } else {\n this.pinoInstance.warn(messageOrObj, args[0] || \"\");\n }\n }\n\n error(message: string, ...args: any[]): void;\n error(obj: object, message?: string): void;\n error(messageOrObj: string | object, ...args: any[]): void {\n if (typeof messageOrObj === \"string\") {\n if (args.length === 0) {\n this.pinoInstance.error(messageOrObj);\n } else {\n // 改进错误处理 - 特殊处理 Error 对象\n const errorArgs = args.map((arg) => {\n if (arg instanceof Error) {\n if (this.pinoInstance.level === \"debug\") return arg.message;\n return {\n message: arg.message,\n stack: arg.stack,\n name: arg.name,\n cause: arg.cause,\n };\n }\n return arg;\n });\n this.pinoInstance.error({ args: errorArgs }, messageOrObj);\n }\n } else {\n // 结构化错误日志,自动提取错误信息\n const enhancedObj = this.enhanceErrorObject(messageOrObj);\n this.pinoInstance.error(enhancedObj, args[0] || \"\");\n }\n }\n\n debug(message: string, ...args: any[]): void;\n debug(obj: object, message?: string): void;\n debug(messageOrObj: string | object, ...args: any[]): void {\n if (typeof messageOrObj === \"string\") {\n if (args.length === 0) {\n this.pinoInstance.debug(messageOrObj);\n } else {\n this.pinoInstance.debug({ args }, messageOrObj);\n }\n } else {\n this.pinoInstance.debug(messageOrObj, args[0] || \"\");\n }\n }\n\n log(message: string, ...args: any[]): void;\n log(obj: object, message?: string): void;\n log(messageOrObj: string | object, ...args: any[]): void {\n // log 方法使用 info 级别\n if (typeof messageOrObj === \"string\") {\n if (args.length === 0) {\n this.pinoInstance.info(messageOrObj);\n } else {\n this.pinoInstance.info({ args }, messageOrObj);\n }\n } else {\n this.pinoInstance.info(messageOrObj, args[0] || \"\");\n }\n }\n\n /**\n * 增强错误对象,提取更多错误信息\n */\n private enhanceErrorObject(obj: any): any {\n const enhanced = { ...obj };\n\n // 遍历对象属性,查找 Error 实例\n for (const [key, value] of Object.entries(enhanced)) {\n if (value instanceof Error) {\n enhanced[key] = {\n message: value.message,\n stack: value.stack,\n name: value.name,\n cause: value.cause,\n };\n }\n }\n\n return enhanced;\n }\n\n /**\n * 检查并轮转日志文件(如果需要)\n */\n private rotateLogFileIfNeeded(): void {\n if (!this.logFilePath || !fs.existsSync(this.logFilePath)) {\n return;\n }\n\n try {\n const stats = fs.statSync(this.logFilePath);\n if (stats.size > this.maxLogFileSize) {\n this.rotateLogFile();\n }\n } catch (error) {\n // 忽略文件状态检查错误\n }\n }\n\n /**\n * 轮转日志文件\n */\n private rotateLogFile(): void {\n if (!this.logFilePath) return;\n\n try {\n const logDir = path.dirname(this.logFilePath);\n const logName = path.basename(this.logFilePath, \".log\");\n\n // 移动现有的编号日志文件\n for (let i = this.maxLogFiles - 1; i >= 1; i--) {\n const oldFile = path.join(logDir, `${logName}.${i}.log`);\n const newFile = path.join(logDir, `${logName}.${i + 1}.log`);\n\n if (fs.existsSync(oldFile)) {\n if (i === this.maxLogFiles - 1) {\n // 删除最老的文件\n fs.unlinkSync(oldFile);\n } else {\n fs.renameSync(oldFile, newFile);\n }\n }\n }\n\n // 将当前日志文件重命名为 .1.log\n const firstRotatedFile = path.join(logDir, `${logName}.1.log`);\n fs.renameSync(this.logFilePath, firstRotatedFile);\n } catch (error) {\n // 轮转失败时忽略错误,继续使用当前文件\n }\n }\n\n /**\n * 清理旧的日志文件\n */\n cleanupOldLogs(): void {\n if (!this.logFilePath) return;\n\n try {\n const logDir = path.dirname(this.logFilePath);\n const logName = path.basename(this.logFilePath, \".log\");\n\n // 删除超过最大数量的日志文件\n for (let i = this.maxLogFiles + 1; i <= this.maxLogFiles + 10; i++) {\n const oldFile = path.join(logDir, `${logName}.${i}.log`);\n if (fs.existsSync(oldFile)) {\n fs.unlinkSync(oldFile);\n }\n }\n } catch (error) {\n // 忽略清理错误\n }\n }\n\n /**\n * 设置日志文件管理参数\n */\n setLogFileOptions(maxSize: number, maxFiles: number): void {\n this.maxLogFileSize = maxSize;\n this.maxLogFiles = maxFiles;\n }\n\n /**\n * 关闭日志文件流\n */\n close(): void {\n // pino 实例会自动处理流的关闭\n // 这里保持方法兼容性\n }\n\n /**\n * 动态设置日志级别\n * @param level 新的日志级别\n * @description 动态更新Logger实例的日志级别\n */\n setLevel(level: Level): void {\n this.logLevel = this.validateLogLevel(level);\n\n // 重新创建pino实例以应用新的日志级别\n this.pinoInstance = this.createPinoInstance();\n }\n\n /**\n * 获取当前日志级别\n * @returns 当前日志级别\n */\n getLevel(): Level {\n return this.logLevel;\n }\n}\n\n// 全局Logger实例管理\nlet globalLogger: Logger | null = null;\nlet globalLogLevel: Level = \"info\"; // 全局日志级别\n\n/**\n * 创建Logger实例\n * @param level 日志级别,默认为全局级别\n * @returns Logger实例\n */\nexport function createLogger(level?: Level): Logger {\n return new Logger(level || globalLogLevel);\n}\n\n/**\n * 获取全局Logger实例\n * @returns 全局Logger实例\n */\nexport function getLogger(): Logger {\n if (!globalLogger) {\n globalLogger = new Logger(globalLogLevel); // 使用全局级别\n }\n return globalLogger;\n}\n\n/**\n * 设置全局Logger实例\n * @param logger 新的Logger实例\n */\nexport function setGlobalLogger(logger: Logger): void {\n globalLogger = logger;\n}\n\n/**\n * 设置全局日志级别\n * @param level 新的日志级别\n * @description 更新全局日志级别,并影响现有和未来的Logger实例\n */\nexport function setGlobalLogLevel(level: Level): void {\n globalLogLevel = level;\n\n // 如果已存在全局Logger实例,更新其级别\n if (globalLogger) {\n globalLogger.setLevel(level);\n }\n}\n\n/**\n * 获取当前全局日志级别\n * @returns 当前日志级别\n */\nexport function getGlobalLogLevel(): Level {\n return globalLogLevel;\n}\n\n// 导出默认实例(向后兼容)\nexport const logger = getLogger();\n","import { EventEmitter } from \"node:events\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport type { Logger } from \"@root/Logger.js\";\nimport { logger } from \"@root/Logger.js\";\n\n/**\n * 事件类型定义\n */\nexport interface EventBusEvents {\n // 配置相关事件\n \"config:updated\": {\n type: string;\n serviceName?: string;\n platformName?: string;\n timestamp: Date;\n };\n \"config:error\": { error: Error; operation: string };\n\n // 状态相关事件\n \"status:updated\": { status: any; source: string };\n \"status:error\": { error: Error; operation: string };\n\n // 接入点状态变更事件\n \"endpoint:status:changed\": {\n endpoint: string;\n connected: boolean;\n operation: \"connect\" | \"disconnect\" | \"reconnect\" | \"add\" | \"remove\";\n success: boolean;\n message?: string;\n timestamp: number;\n source: string;\n };\n\n // 服务相关事件\n \"service:restart:requested\": {\n serviceName: string;\n reason?: string;\n delay: number;\n attempt: number;\n timestamp: number;\n source?: string;\n };\n \"service:restart:started\": {\n serviceName: string;\n reason?: string;\n attempt: number;\n timestamp: number;\n };\n \"service:restart:completed\": {\n serviceName: string;\n reason?: string;\n attempt: number;\n timestamp: number;\n };\n \"service:restart:failed\": {\n serviceName: string;\n error: Error;\n attempt: number;\n timestamp: number;\n };\n \"service:restart:execute\": {\n serviceName: string;\n reason?: string;\n attempt: number;\n timestamp: number;\n };\n \"service:health:changed\": {\n serviceName: string;\n oldStatus: string;\n newStatus: string;\n timestamp: number;\n };\n\n // WebSocket 相关事件\n \"websocket:client:connected\": { clientId: string; timestamp: number };\n \"websocket:client:disconnected\": { clientId: string; timestamp: number };\n \"websocket:message:received\": { type: string; data: any; clientId: string };\n\n // 通知相关事件\n \"notification:broadcast\": { type: string; data: any; target?: string };\n \"notification:error\": { error: Error; type: string };\n\n // MCP服务相关事件\n \"mcp:service:connected\": {\n serviceName: string;\n tools: Tool[];\n connectionTime: Date;\n };\n \"mcp:service:disconnected\": {\n serviceName: string;\n reason?: string;\n disconnectionTime: Date;\n };\n \"mcp:service:connection:failed\": {\n serviceName: string;\n error: Error;\n attempt: number;\n };\n \"mcp:server:added\": {\n serverName: string;\n config: any;\n tools: string[];\n timestamp: Date;\n };\n \"mcp:server:removed\": {\n serverName: string;\n affectedTools: string[];\n timestamp: Date;\n };\n \"mcp:server:status_changed\": {\n serverName: string;\n oldStatus: \"connected\" | \"disconnected\" | \"connecting\" | \"error\";\n newStatus: \"connected\" | \"disconnected\" | \"connecting\" | \"error\";\n timestamp: Date;\n reason?: string;\n };\n \"mcp:server:connection:attempt\": {\n serverName: string;\n attempt: number;\n maxAttempts: number;\n timestamp: Date;\n };\n \"mcp:server:tools:updated\": {\n serverName: string;\n tools: string[];\n addedTools: string[];\n removedTools: string[];\n timestamp: Date;\n };\n \"mcp:server:batch_added\": {\n totalServers: number;\n addedCount: number;\n failedCount: number;\n successfullyAddedServers: string[];\n results: any[];\n timestamp: Date;\n };\n \"mcp:server:rollback\": {\n serverName: string;\n timestamp: Date;\n };\n\n // 连接相关事件\n \"connection:reconnect:completed\": {\n success: boolean;\n reason: string;\n timestamp: Date;\n };\n\n // NPM 安装相关事件\n \"npm:install:started\": {\n version: string;\n installId: string;\n timestamp: number;\n };\n \"npm:install:log\": {\n version: string;\n installId: string;\n type: \"stdout\" | \"stderr\";\n message: string;\n timestamp: number;\n };\n \"npm:install:completed\": {\n version: string;\n installId: string;\n success: boolean;\n duration: number;\n timestamp: number;\n };\n \"npm:install:failed\": {\n version: string;\n installId: string;\n error: string;\n duration: number;\n timestamp: number;\n };\n\n // 测试相关事件(仅用于测试)\n \"high-frequency\": {\n id: number;\n timestamp: number;\n };\n \"bulk-test\": {\n id: number;\n timestamp: number;\n };\n \"error-test\": {\n error: string;\n timestamp: number;\n };\n \"large-data-test\": {\n data: any;\n timestamp: number;\n };\n \"destroy-test\": {\n message: string;\n timestamp: number;\n };\n \"chain-event-1\": {\n value: number;\n timestamp: number;\n };\n \"chain-event-2\": {\n value: number;\n timestamp: number;\n };\n \"chain-event-3\": {\n value: number;\n timestamp: number;\n };\n \"performance-test\": {\n data: any;\n timestamp: number;\n };\n \"test:performance\": {\n id: number;\n timestamp: number;\n };\n \"chain:start\": {\n value: number;\n timestamp: number;\n };\n \"chain:middle\": {\n value: number;\n timestamp: number;\n };\n \"chain:end\": {\n value: number;\n timestamp: number;\n };\n \"test:error\": {\n error: boolean;\n timestamp: number;\n };\n \"test:remove\": {\n id: number;\n timestamp: number;\n };\n}\n\n/**\n * 事件总线 - 用于模块间的解耦通信\n */\nexport class EventBus extends EventEmitter {\n private logger: Logger;\n private eventStats: Map<string, { count: number; lastEmitted: Date }> =\n new Map();\n private maxListeners = 50; // 增加最大监听器数量\n\n constructor() {\n super();\n this.logger = logger;\n this.setMaxListeners(this.maxListeners);\n this.setupErrorHandling();\n }\n\n /**\n * 设置错误处理\n */\n private setupErrorHandling(): void {\n this.on(\"error\", (error) => {\n this.logger.error(\"EventBus 内部错误:\", error);\n });\n\n // 监听器数量警告\n this.on(\"newListener\", (eventName) => {\n const listenerCount = this.listenerCount(eventName);\n if (listenerCount > this.maxListeners * 0.8) {\n this.logger.warn(\n `事件 ${eventName} 的监听器数量过多: ${listenerCount}`\n );\n }\n });\n }\n\n /**\n * 发射事件(类型安全)\n */\n emitEvent<K extends keyof EventBusEvents>(\n eventName: K,\n data: EventBusEvents[K]\n ): boolean {\n try {\n this.updateEventStats(eventName as string);\n this.logger.debug(`发射事件: ${eventName}`, data);\n\n // 使用原始emit方法,保持EventEmitter的所有特性\n return super.emit(eventName, data);\n } catch (error) {\n this.logger.error(`发射事件失败: ${eventName}`, error);\n // 将监听器错误发射到error事件\n if (error instanceof Error) {\n this.emit(\"error\", error);\n }\n return false;\n }\n }\n\n /**\n * 监听事件(类型安全)\n */\n onEvent<K extends keyof EventBusEvents>(\n eventName: K,\n listener: (data: EventBusEvents[K]) => void\n ): this {\n this.logger.debug(`添加事件监听器: ${eventName}`);\n return this.on(eventName, listener);\n }\n\n /**\n * 一次性监听事件(类型安全)\n */\n onceEvent<K extends keyof EventBusEvents>(\n eventName: K,\n listener: (data: EventBusEvents[K]) => void\n ): this {\n this.logger.debug(`添加一次性事件监听器: ${eventName}`);\n\n // 创建包装器来实现一次性监听\n const onceListener = (data: EventBusEvents[K]) => {\n try {\n listener(data);\n } catch (error) {\n // 监听器抛出错误,发射到错误事件\n this.emit(\"error\", error);\n throw error;\n } finally {\n // 在任何情况下都移除监听器\n this.offEvent(eventName, onceListener);\n }\n };\n\n return this.on(eventName, onceListener);\n }\n\n /**\n * 移除事件监听器(类型安全)\n */\n offEvent<K extends keyof EventBusEvents>(\n eventName: K,\n listener: (data: EventBusEvents[K]) => void\n ): this {\n this.logger.debug(`移除事件监听器: ${eventName}`);\n return this.off(eventName, listener);\n }\n\n /**\n * 更新事件统计\n */\n private updateEventStats(eventName: string): void {\n const stats = this.eventStats.get(eventName) || {\n count: 0,\n lastEmitted: new Date(),\n };\n stats.count++;\n stats.lastEmitted = new Date();\n this.eventStats.set(eventName, stats);\n }\n\n /**\n * 获取事件统计信息\n */\n getEventStats(): Record<string, { count: number; lastEmitted: Date }> {\n const stats: Record<string, { count: number; lastEmitted: Date }> = {};\n for (const [eventName, stat] of this.eventStats) {\n stats[eventName] = { ...stat };\n }\n return stats;\n }\n\n /**\n * 获取监听器统计信息\n */\n getListenerStats(): Record<string, number> {\n const stats: Record<string, number> = {};\n for (const eventName of this.eventNames()) {\n stats[eventName as string] = this.listenerCount(eventName);\n }\n return stats;\n }\n\n /**\n * 清理事件统计\n */\n clearEventStats(): void {\n this.eventStats.clear();\n this.logger.info(\"事件统计已清理\");\n }\n\n /**\n * 获取事件总线状态\n */\n getStatus(): {\n totalEvents: number;\n totalListeners: number;\n eventStats: Record<string, { count: number; lastEmitted: Date }>;\n listenerStats: Record<string, number>;\n } {\n return {\n totalEvents: this.eventStats.size,\n totalListeners: Object.values(this.getListenerStats()).reduce(\n (sum, count) => sum + count,\n 0\n ),\n eventStats: this.getEventStats(),\n listenerStats: this.getListenerStats(),\n };\n }\n\n /**\n * 销毁事件总线\n */\n destroy(): void {\n this.removeAllListeners();\n this.eventStats.clear();\n this.logger.info(\"EventBus 已销毁\");\n }\n}\n\n// 单例实例\nlet eventBusInstance: EventBus | null = null;\n\n/**\n * 获取事件总线单例\n */\nexport function getEventBus(): EventBus {\n if (!eventBusInstance) {\n eventBusInstance = new EventBus();\n }\n return eventBusInstance;\n}\n\n/**\n * 销毁事件总线单例\n */\nexport function destroyEventBus(): void {\n if (eventBusInstance) {\n eventBusInstance.destroy();\n eventBusInstance = null;\n }\n}\n","/**\n * MCP 服务器配置 Type 字段标准化工具\n * 支持将各种 type 字段格式转换为标准的中划线格式\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 // 函数重载:泛型版本,用于类型安全的调用\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 // 创建配置的深拷贝以避免修改原始对象\n const normalizedConfig = JSON.parse(JSON.stringify(config));\n\n // 如果配置中没有type字段,直接返回\n if (!(\"type\" in normalizedConfig)) {\n return normalizedConfig;\n }\n\n const originalType = normalizedConfig.type;\n\n // 如果已经是标准格式,直接返回\n if (originalType === \"sse\" || originalType === \"streamable-http\") {\n return normalizedConfig;\n }\n\n // 转换为标准格式\n let normalizedType: string;\n\n if (\n originalType === \"streamableHttp\" ||\n originalType === \"streamable_http\"\n ) {\n normalizedType = \"streamable-http\";\n } else if (originalType === \"s_se\" || originalType === \"s-se\") {\n normalizedType = \"sse\";\n } else {\n // 对于其他格式,尝试智能转换\n normalizedType = convertToKebabCase(originalType);\n }\n\n // 验证转换后的类型是否有效\n if (normalizedType === \"sse\" || normalizedType === \"streamable-http\") {\n normalizedConfig.type = normalizedType;\n // 记录转换日志(如果有的话)\n if (originalType !== normalizedType) {\n // 可以在需要时添加日志记录\n }\n }\n\n return normalizedConfig;\n }\n\n /**\n * 将字符串转换为kebab-case格式\n */\n function convertToKebabCase(str: string): string {\n return str\n .replace(/([a-z])([A-Z])/g, \"$1-$2\") // 驼峰转中划线\n .replace(/_/g, \"-\") // 下划线转中划线\n .toLowerCase(); // 转小写\n }\n}\n","/**\n * MCP 服务工具函数 - 服务端版本\n * 用于判断 MCP 服务的通信类型和其他相关操作\n */\n\n// 定义通信类型\nexport type MCPCommunicationType = \"stdio\" | \"sse\" | \"streamable-http\";\n\n// 定义 MCP 服务配置类型(与客户端保持一致)\nexport interface LocalMCPServerConfig {\n command: string;\n args: string[];\n env?: Record<string, string>;\n}\n\nexport interface SSEMCPServerConfig {\n type: \"sse\";\n url: string;\n headers?: Record<string, string>;\n}\n\nexport interface StreamableHTTPMCPServerConfig {\n type?: \"streamable-http\"; // 可选,因为默认就是 streamable-http\n url: string;\n headers?: Record<string, string>;\n}\n\nexport type MCPServerConfig =\n | LocalMCPServerConfig\n | SSEMCPServerConfig\n | StreamableHTTPMCPServerConfig;\n\n/**\n * 判断 MCP 服务的通信类型\n *\n * @param serverConfig MCP 服务配置对象\n * @returns 通信类型:'stdio' | 'sse' | 'streamable-http'\n *\n * 判断逻辑:\n * 1. 如果配置对象有 command 字段 → stdio\n * 2. 如果配置对象有 type 字段且值为 \"sse\" → sse\n * 3. 如果配置对象有 url 字段但没有 type 字段,或者 type 字段不是 \"sse\" → streamable-http\n *\n * @example\n * ```typescript\n * // stdio 类型\n * const stdioConfig = {\n * command: \"node\",\n * args: [\"./mcpServers/calculator.js\"]\n * };\n * getMcpServerCommunicationType(stdioConfig); // \"stdio\"\n *\n * // sse 类型\n * const sseConfig = {\n * type: \"sse\" as const,\n * url: \"https://mcp.api-inference.modelscope.net/d3cfd34529ae4e/sse\"\n * };\n * getMcpServerCommunicationType(sseConfig); // \"sse\"\n *\n * // streamable-http 类型\n * const httpConfig = {\n * url: \"https://mcp.amap.com/mcp?key=1ec31da021b2702787841ea4ee822de3\"\n * };\n * getMcpServerCommunicationType(httpConfig); // \"streamable-http\"\n * ```\n */\nexport function getMcpServerCommunicationType(\n serverConfig: MCPServerConfig | Record<string, unknown>\n): MCPCommunicationType {\n // 参数验证\n if (!serverConfig || typeof serverConfig !== \"object\") {\n throw new Error(\"服务配置必须是一个有效的对象\");\n }\n\n // 1. 检查是否为 stdio 类型(有 command 字段)\n if (\"command\" in serverConfig && typeof serverConfig.command === \"string\") {\n return \"stdio\";\n }\n\n // 2. 检查是否为 sse 类型(有 type: \"sse\" 字段)\n if (\"type\" in serverConfig && serverConfig.type === \"sse\") {\n return \"sse\";\n }\n\n // 3. 检查是否为 streamable-http 类型(有 type: \"streamable-http\" 字段或有 url 字段)\n if (\n (\"type\" in serverConfig && serverConfig.type === \"streamable-http\") ||\n (\"url\" in serverConfig && typeof serverConfig.url === \"string\")\n ) {\n return \"streamable-http\";\n }\n\n // 如果都不匹配,抛出错误\n throw new Error(\n \"无法识别的 MCP 服务配置类型。配置必须包含 command 字段(stdio)、type: 'sse' 字段(sse)或 url 字段(streamable-http)\"\n );\n}\n\n/**\n * 检查 MCP 服务配置是否为 stdio 类型\n */\nexport function isStdioMcpServer(\n serverConfig: MCPServerConfig | Record<string, unknown>\n): serverConfig is LocalMCPServerConfig {\n return getMcpServerCommunicationType(serverConfig) === \"stdio\";\n}\n\n/**\n * 检查 MCP 服务配置是否为 sse 类型\n */\nexport function isSSEMcpServer(\n serverConfig: MCPServerConfig | Record<string, unknown>\n): serverConfig is SSEMCPServerConfig {\n return getMcpServerCommunicationType(serverConfig) === \"sse\";\n}\n\n/**\n * 检查 MCP 服务配置是否为 streamable-http 类型\n */\nexport function isStreamableHTTPMcpServer(\n serverConfig: MCPServerConfig | Record<string, unknown>\n): serverConfig is StreamableHTTPMCPServerConfig {\n return getMcpServerCommunicationType(serverConfig) === \"streamable-http\";\n}\n\n/**\n * 获取 MCP 服务配置的显示名称\n * 用于在日志中显示更友好的通信类型名称\n */\nexport function getMcpServerTypeDisplayName(\n serverConfig: MCPServerConfig | Record<string, unknown>\n): string {\n const type = getMcpServerCommunicationType(serverConfig);\n\n switch (type) {\n case \"stdio\":\n return \"本地进程 (stdio)\";\n case \"sse\":\n return \"服务器推送 (SSE)\";\n case \"streamable-http\":\n return \"流式 HTTP\";\n default:\n return \"未知类型\";\n }\n}\n\n/**\n * 验证 MCP 服务配置的完整性\n * 根据不同的通信类型验证必需的字段\n */\nexport function validateMcpServerConfig(\n serverName: string,\n serverConfig: unknown\n): { valid: boolean; error?: string } {\n if (\n !serverConfig ||\n typeof serverConfig !== \"object\" ||\n Array.isArray(serverConfig)\n ) {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 的配置必须是一个对象`,\n };\n }\n\n try {\n const communicationType = getMcpServerCommunicationType(\n serverConfig as Record<string, unknown>\n );\n\n const config = serverConfig as Record<string, unknown>;\n\n switch (communicationType) {\n case \"stdio\":\n if (!config.command || typeof config.command !== \"string\") {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 缺少必需的 command 字段或字段类型不正确`,\n };\n }\n if (!Array.isArray(config.args)) {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 的 args 字段必须是数组`,\n };\n }\n if (\n config.env &&\n (typeof config.env !== \"object\" || Array.isArray(config.env))\n ) {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 的 env 字段必须是对象`,\n };\n }\n break;\n\n case \"sse\":\n if (config.type !== \"sse\") {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 的 type 字段必须是 \"sse\"`,\n };\n }\n if (!config.url || typeof config.url !== \"string\") {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 缺少必需的 url 字段或字段类型不正确`,\n };\n }\n if (\n config.headers &&\n (typeof config.headers !== \"object\" || Array.isArray(config.headers))\n ) {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 的 headers 字段必须是对象`,\n };\n }\n break;\n\n case \"streamable-http\":\n if (!config.url || typeof config.url !== \"string\") {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 缺少必需的 url 字段或字段类型不正确`,\n };\n }\n if (config.type && config.type !== \"streamable-http\") {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 的 type 字段如果存在,必须是 \"streamable-http\"`,\n };\n }\n if (\n config.headers &&\n (typeof config.headers !== \"object\" || Array.isArray(config.headers))\n ) {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 的 headers 字段必须是对象`,\n };\n }\n break;\n\n default:\n return {\n valid: false,\n error: `服务 \"${serverName}\" 的配置类型无法识别`,\n };\n }\n\n return { valid: true };\n } catch (error) {\n return {\n valid: false,\n error: `服务 \"${serverName}\" 的配置无效: ${\n error instanceof Error ? error.message : \"未知错误\"\n }`,\n };\n }\n}\n\nexport function sliceEndpoint(endpoint: string) {\n return `${endpoint.slice(0, 30)}...${endpoint.slice(-10)}`;\n}\n","import { copyFileSync, existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { CustomMCPTool as CoreCustomMCPTool } from \"@/lib/mcp/types.js\";\nimport { getEventBus } from \"@services/EventBus.js\";\nimport { TypeFieldNormalizer } from \"@utils/TypeFieldNormalizer.js\";\nimport { validateMcpServerConfig } from \"@utils/mcpServerUtils\";\nimport * as commentJson from \"comment-json\";\nimport dayjs from \"dayjs\";\nimport JSON5 from \"json5\";\nimport * as json5Writer from \"json5-writer\";\n\n// 在 ESM 中,需要从 import.meta.url 获取当前文件目录\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\n// 默认连接配置\nconst DEFAULT_CONNECTION_CONFIG: Required<ConnectionConfig> = {\n heartbeatInterval: 30000, // 30秒心跳间隔\n heartbeatTimeout: 10000, // 10秒心跳超时\n reconnectInterval: 5000, // 5秒重连间隔\n};\n\n// 配置文件接口定义\n// 本地 MCP 服务配置\nexport interface LocalMCPServerConfig {\n command: string;\n args: string[];\n env?: Record<string, string>;\n}\n\n// SSE MCP 服务配置\nexport interface SSEMCPServerConfig {\n type: \"sse\";\n url: string;\n headers?: Record<string, string>;\n}\n\n// Streamable HTTP MCP 服务配置\nexport interface StreamableHTTPMCPServerConfig {\n type?: \"streamable-http\"; // 可选,因为默认就是 streamable-http\n url: string;\n headers?: Record<string, string>;\n}\n\n// 统一的 MCP 服务配置\nexport type MCPServerConfig =\n | LocalMCPServerConfig\n | SSEMCPServerConfig\n | StreamableHTTPMCPServerConfig;\n\nexport interface MCPToolConfig {\n description?: string;\n enable: boolean;\n usageCount?: number; // 工具使用次数\n lastUsedTime?: string; // 最后使用时间(ISO 8601 格式)\n}\n\nexport interface MCPServerToolsConfig {\n tools: Record<string, MCPToolConfig>;\n}\n\nexport interface ConnectionConfig {\n heartbeatInterval?: number; // 心跳检测间隔(毫秒),默认30000\n heartbeatTimeout?: number; // 心跳超时时间(毫秒),默认10000\n reconnectInterval?: number; // 重连间隔(毫秒),默认5000\n}\n\nexport interface ModelScopeConfig {\n apiKey?: string; // ModelScope API 密钥\n}\n\nexport interface WebUIConfig {\n port?: number; // Web UI 端口号,默认 9999\n autoRestart?: boolean; // 是否在配置更新后自动重启服务,默认 true\n}\n\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, string>;\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// 扩展核心库的 CustomMCPTool 接口,添加使用统计信息\nexport interface CustomMCPTool extends CoreCustomMCPTool {\n // 确保必填字段\n description: string;\n handler: HandlerConfig;\n\n // 使用统计信息(可选)\n stats?: {\n usageCount?: number; // 工具使用次数\n lastUsedTime?: string; // 最后使用时间(ISO 8601格式)\n };\n}\n\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}\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 private eventBus = getEventBus(); // 事件总线\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 private constructor() {\n // 使用模板目录中的默认配置文件\n // 在不同环境中尝试不同的路径\n const possiblePaths = [\n // 构建后的环境:dist/configManager.js -> dist/templates/default/xiaozhi.config.json\n resolve(__dirname, \"templates\", \"default\", \"xiaozhi.config.json\"),\n // 开发环境:src/configManager.ts -> templates/default/xiaozhi.config.json\n resolve(__dirname, \"..\", \"templates\", \"default\", \"xiaozhi.config.json\"),\n // 测试环境或其他情况\n resolve(process.cwd(), \"templates\", \"default\", \"xiaozhi.config.json\"),\n ];\n\n // 找到第一个存在的路径\n this.defaultConfigPath =\n possiblePaths.find((path) => existsSync(path)) || possiblePaths[0];\n }\n\n /**\n * 获取配置文件路径(动态计算)\n * 支持多种配置文件格式:json5 > jsonc > json\n */\n private getConfigFilePath(): string {\n // 配置文件路径 - 优先使用环境变量指定的目录,否则使用当前工作目录\n const configDir = process.env.XIAOZHI_CONFIG_DIR || process.cwd();\n\n // 按优先级检查配置文件是否存在\n const configFileNames = [\n \"xiaozhi.config.json5\",\n \"xiaozhi.config.jsonc\",\n \"xiaozhi.config.json\",\n ];\n\n for (const fileName of configFileNames) {\n const filePath = resolve(configDir, fileName);\n if (existsSync(filePath)) {\n return filePath;\n }\n }\n\n // 如果都不存在,返回默认的 JSON 文件路径\n return resolve(configDir, \"xiaozhi.config.json\");\n }\n\n /**\n * 获取配置文件格式\n */\n private getConfigFileFormat(filePath: string): \"json5\" | \"jsonc\" | \"json\" {\n if (filePath.endsWith(\".json5\")) {\n return \"json5\";\n }\n\n if (filePath.endsWith(\".jsonc\")) {\n return \"jsonc\";\n }\n\n return \"json\";\n }\n\n /**\n * 获取配置管理器单例实例\n */\n public static getInstance(): ConfigManager {\n if (!ConfigManager.instance) {\n ConfigManager.instance = new ConfigManager();\n }\n return ConfigManager.instance;\n }\n\n /**\n * 检查配置文件是否存在\n */\n public configExists(): boolean {\n // 配置文件路径 - 优先使用环境变量指定的目录,否则使用当前工作目录\n const configDir = process.env.XIAOZHI_CONFIG_DIR || process.cwd();\n\n // 按优先级检查配置文件是否存在\n const configFileNames = [\n \"xiaozhi.config.json5\",\n \"xiaozhi.config.jsonc\",\n \"xiaozhi.config.json\",\n ];\n\n for (const fileName of configFileNames) {\n const filePath = resolve(configDir, fileName);\n if (existsSync(filePath)) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * 初始化配置文件\n * 从 config.default.json 复制到 config.json\n * @param format 配置文件格式,默认为 json\n */\n public initConfig(format: \"json\" | \"json5\" | \"jsonc\" = \"json\"): void {\n if (!existsSync(this.defaultConfigPath)) {\n throw new Error(`默认配置模板文件不存在: ${this.defaultConfigPath}`);\n }\n\n // 检查是否已有任何格式的配置文件\n if (this.configExists()) {\n throw new Error(\"配置文件已存在,无需重复初始化\");\n }\n\n // 确定目标配置文件路径\n const configDir = process.env.XIAOZHI_CONFIG_DIR || process.cwd();\n const targetFileName = `xiaozhi.config.${format}`;\n const configPath = resolve(configDir, targetFileName);\n\n // 复制默认配置文件\n copyFileSync(this.defaultConfigPath, configPath);\n this.config = null; // 重置缓存\n this.json5Writer = null; // 重置 json5Writer 实例\n }\n\n /**\n * 加载配置文件\n */\n private loadConfig(): AppConfig {\n if (!this.configExists()) {\n const error = new Error(\n \"配置文件不存在,请先运行 xiaozhi init 初始化配置\"\n );\n this.eventBus.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 解析配置对象,同时使用 json5-writer 保留注释信息\n config = JSON5.parse(configData) as AppConfig;\n // 创建 json5-writer 实例用于后续保存时保留注释\n this.json5Writer = json5Writer.load(configData);\n break;\n case \"jsonc\":\n // 使用 comment-json 解析 JSONC 格式,保留注释信息\n config = commentJson.parse(configData) as unknown as AppConfig;\n break;\n default:\n config = JSON.parse(configData) as AppConfig;\n break;\n }\n\n // 验证配置结构\n this.validateConfig(config);\n\n return config;\n } catch (error) {\n // 发射配置错误事件\n this.eventBus.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 // 使用 TypeFieldNormalizer 标准化 type 字段\n const normalizedConfig =\n TypeFieldNormalizer.normalizeTypeField(serverConfig);\n\n // 使用统一的验证逻辑验证标准化后的配置\n const validation = validateMcpServerConfig(serverName, normalizedConfig);\n if (!validation.valid) {\n throw new Error(`配置文件格式错误:${validation.error}`);\n }\n }\n }\n\n /**\n * 获取配置(只读)\n */\n public getConfig(): Readonly<AppConfig> {\n this.config = this.loadConfig();\n\n console.log(\"获取配置成功\");\n // 返回深度只读副本\n return JSON.parse(JSON.stringify(this.config));\n }\n\n /**\n * 获取可修改的配置对象(内部使用,保留注释信息)\n */\n private getMutableConfig(): AppConfig {\n if (!this.config) {\n this.config = this.loadConfig();\n }\n return this.config;\n }\n\n /**\n * 获取 MCP 端点(向后兼容)\n * @deprecated 使用 getMcpEndpoints() 获取所有端点\n */\n public getMcpEndpoint(): string {\n const config = this.getConfig();\n if (Array.isArray(config.mcpEndpoint)) {\n return config.mcpEndpoint[0] || \"\";\n }\n return config.mcpEndpoint;\n }\n\n /**\n * 获取所有 MCP 端点\n */\n public getMcpEndpoints(): string[] {\n const config = this.getConfig();\n if (Array.isArray(config.mcpEndpoint)) {\n return [...config.mcpEndpoint];\n }\n return config.mcpEndpoint ? [config.mcpEndpoint] : [];\n }\n\n /**\n * 获取 MCP 服务配置\n */\n public getMcpServers(): Readonly<Record<string, MCPServerConfig>> {\n const config = this.getConfig();\n return config.mcpServers;\n }\n\n /**\n * 获取 MCP 服务工具配置\n */\n public getMcpServerConfig(): Readonly<Record<string, MCPServerToolsConfig>> {\n const config = this.getConfig();\n return config.mcpServerConfig || {};\n }\n\n /**\n * 获取指定服务的工具配置\n */\n public getServerToolsConfig(\n serverName: string\n ): Readonly<Record<string, MCPToolConfig>> {\n const serverConfig = this.getMcpServerConfig();\n return serverConfig[serverName]?.tools || {};\n }\n\n /**\n * 检查工具是否启用\n */\n public isToolEnabled(serverName: string, toolName: string): boolean {\n const toolsConfig = this.getServerToolsConfig(serverName);\n const toolConfig = toolsConfig[toolName];\n return toolConfig?.enable !== false; // 默认启用\n }\n\n /**\n * 更新 MCP 端点(支持字符串或数组)\n */\n public updateMcpEndpoint(endpoint: string | string[]): void {\n if (Array.isArray(endpoint)) {\n 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.eventBus.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 // 使用统一的验证逻辑\n const validation = validateMcpServerConfig(serverName, serverConfig);\n if (!validation.valid) {\n throw new Error(validation.error || \"服务配置验证失败\");\n }\n const config = this.getMutableConfig();\n // 直接修改配置对象以保留注释信息\n config.mcpServers[serverName] = serverConfig;\n this.saveConfig(config);\n }\n\n /**\n * 删除 MCP 服务配置\n */\n public removeMcpServer(serverName: string): void {\n if (!serverName || typeof serverName !== \"string\") {\n throw new Error(\"服务名称必须是非空字符串\");\n }\n\n const config = this.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.eventBus.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 this.saveConfig(config);\n\n // 发射配置更新事件\n this.eventBus.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.eventBus.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 格式,使用 json5-writer 库保留注释\n try {\n if (this.json5Writer) {\n // 使用 json5-writer 更新配置并保留注释\n this.json5Writer.write(config);\n configContent = this.json5Writer.toSource();\n } else {\n // 如果没有 json5Writer 实例,回退到标准 JSON5\n console.warn(\"没有 json5Writer 实例,回退到标准 JSON5 格式\");\n configContent = JSON5.stringify(config, null, 2);\n }\n } catch (json5WriterError) {\n // 如果 json5-writer 序列化失败,回退到标准 JSON5\n console.warn(\n \"使用 json5-writer 保存失败,回退到标准 JSON5 格式:\",\n json5WriterError\n );\n configContent = JSON5.stringify(config, null, 2);\n }\n break;\n case \"jsonc\":\n // 对于 JSONC 格式,使用 comment-json 库保留注释\n try {\n // 直接使用 comment-json 的 stringify 方法\n // 如果 config 是通过 comment-json.parse 解析的,注释信息会被保留\n configContent = commentJson.stringify(config, null, 2);\n } catch (commentJsonError) {\n // 如果 comment-json 序列化失败,回退到标准 JSON\n console.warn(\n \"使用 comment-json 保存失败,回退到标准 JSON 格式:\",\n commentJsonError\n );\n configContent = JSON.stringify(config, null, 2);\n }\n break;\n default:\n configContent = JSON.stringify(config, null, 2);\n break;\n }\n\n // 保存到文件\n writeFileSync(configPath, configContent, \"utf8\");\n\n // 更新缓存\n this.config = config;\n\n console.log(\"配置保存成功\");\n\n // 通知 Web 界面配置已更新(如果 Web 服务器正在运行)\n this.notifyConfigUpdate(config);\n } catch (error) {\n // 发射配置错误事件\n this.eventBus.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.eventBus.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.eventBus.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.eventBus.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.eventBus.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.eventBus.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.eventBus.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 this.statsUpdateLockTimeouts.delete(toolKey);\n }\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// 导出单例实例\nexport const configManager = ConfigManager.getInstance();\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 \"@cli/Constants.js\";\n\n/**\n * 错误消息映射\n */\nconst ERROR_HELP_MESSAGES: Record<string, string> = {\n [ERROR_CODES.CONFIG_ERROR]: '运行 \"xiaozhi --help\" 查看配置相关命令',\n [ERROR_CODES.SERVICE_ERROR]: '运行 \"xiaozhi status\" 检查服务状态',\n [ERROR_CODES.VALIDATION_ERROR]: \"检查输入参数是否正确\",\n [ERROR_CODES.FILE_ERROR]: \"检查文件路径和权限\",\n [ERROR_CODES.PROCESS_ERROR]: \"检查进程状态和权限\",\n [ERROR_CODES.NETWORK_ERROR]: \"检查网络连接和防火墙设置\",\n [ERROR_CODES.PERMISSION_ERROR]: \"尝试使用管理员权限运行\",\n};\n\n/**\n * 常见问题解决方案\n */\nconst COMMON_SOLUTIONS: Record<string, string[]> = {\n config_not_found: [\n '运行 \"xiaozhi init\" 初始化配置文件',\n \"检查当前目录是否为项目根目录\",\n \"设置 XIAOZHI_CONFIG_DIR 环境变量指定配置目录\",\n ],\n service_port_occupied: [\n \"检查端口是否被其他程序占用\",\n '使用 \"lsof -i :端口号\" 查看端口使用情况',\n \"更改配置文件中的端口设置\",\n ],\n permission_denied: [\n \"检查文件和目录权限\",\n \"使用 sudo 或管理员权限运行\",\n \"确保当前用户有足够的权限\",\n ],\n service_start_failed: [\n \"检查配置文件格式是否正确\",\n \"查看日志文件获取详细错误信息\",\n \"确保所有依赖服务正常运行\",\n ],\n};\n\n/**\n * 错误消息管理类\n */\nexport class ERROR_MESSAGES {\n /**\n * 获取错误码对应的帮助信息\n */\n static getHelpMessage(errorCode: string): string | undefined {\n return ERROR_HELP_MESSAGES[errorCode];\n }\n\n /**\n * 获取常见问题的解决方案\n */\n static getSolutions(problemKey: string): string[] {\n return COMMON_SOLUTIONS[problemKey] || [];\n }\n\n /**\n * 格式化错误消息\n */\n static formatError(error: Error, context?: string): string {\n const contextPrefix = context ? `[${context}] ` : \"\";\n return `${contextPrefix}${error.message}`;\n }\n\n /**\n * 获取友好的错误描述\n */\n static getFriendlyMessage(errorCode: string): string {\n const friendlyMessages: Record<string, string> = {\n [ERROR_CODES.CONFIG_ERROR]: \"配置文件相关错误\",\n [ERROR_CODES.SERVICE_ERROR]: \"服务运行相关错误\",\n [ERROR_CODES.VALIDATION_ERROR]: \"输入验证错误\",\n [ERROR_CODES.FILE_ERROR]: \"文件操作错误\",\n [ERROR_CODES.PROCESS_ERROR]: \"进程管理错误\",\n [ERROR_CODES.NETWORK_ERROR]: \"网络连接错误\",\n [ERROR_CODES.PERMISSION_ERROR]: \"权限不足错误\",\n };\n\n return friendlyMessages[errorCode] || \"未知错误\";\n }\n\n /**\n * 检查是否为可恢复错误\n */\n static isRecoverable(errorCode: string): boolean {\n const recoverableErrors: string[] = [\n ERROR_CODES.NETWORK_ERROR,\n ERROR_CODES.FILE_ERROR,\n ERROR_CODES.SERVICE_ERROR,\n ];\n\n return recoverableErrors.includes(errorCode);\n }\n\n /**\n * 获取错误的严重程度\n */\n static getSeverity(\n errorCode: string\n ): \"low\" | \"medium\" | \"high\" | \"critical\" {\n const severityMap: Record<string, \"low\" | \"medium\" | \"high\" | \"critical\"> =\n {\n [ERROR_CODES.VALIDATION_ERROR]: \"low\",\n [ERROR_CODES.FILE_ERROR]: \"medium\",\n [ERROR_CODES.CONFIG_ERROR]: \"medium\",\n [ERROR_CODES.NETWORK_ERROR]: \"medium\",\n [ERROR_CODES.SERVICE_ERROR]: \"high\",\n [ERROR_CODES.PROCESS_ERROR]: \"high\",\n [ERROR_CODES.PERMISSION_ERROR]: \"critical\",\n };\n\n return severityMap[errorCode] || \"medium\";\n }\n}\n","/**\n * 统一错误处理系统\n */\n\nimport { ERROR_CODES } from \"@cli/Constants.js\";\n\n/**\n * CLI 基础错误类\n */\nexport class CLIError extends Error {\n constructor(\n message: string,\n public code: string,\n public exitCode = 1,\n public suggestions?: string[]\n ) {\n super(message);\n this.name = \"CLIError\";\n\n // 确保错误堆栈正确显示\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, CLIError);\n }\n }\n\n /**\n * 创建带建议的错误\n */\n static withSuggestions(\n message: string,\n code: string,\n suggestions: string[]\n ): CLIError {\n return new CLIError(message, code, 1, suggestions);\n }\n}\n\n/**\n * 配置错误\n */\nexport class ConfigError extends CLIError {\n constructor(message: string, suggestions?: string[]) {\n super(message, ERROR_CODES.CONFIG_ERROR, 1, suggestions);\n this.name = \"ConfigError\";\n }\n\n static configNotFound(): ConfigError {\n return new ConfigError(\"配置文件不存在\", [\n '请运行 \"xiaozhi init\" 初始化配置文件',\n ]);\n }\n\n static invalidFormat(format: string): ConfigError {\n return new ConfigError(`无效的配置文件格式: ${format}`, [\n \"支持的格式: json, json5, jsonc\",\n ]);\n }\n}\n\n/**\n * 服务错误\n */\nexport class ServiceError extends CLIError {\n constructor(message: string, suggestions?: string[]) {\n super(message, ERROR_CODES.SERVICE_ERROR, 1, suggestions);\n this.name = \"ServiceError\";\n }\n\n static alreadyRunning(pid: number): ServiceError {\n return new ServiceError(`服务已经在运行 (PID: ${pid})`, [\n '请先运行 \"xiaozhi stop\" 停止现有服务',\n '或者使用 \"xiaozhi restart\" 重启服务',\n ]);\n }\n\n static autoRestarting(pid: number): ServiceError {\n return new ServiceError(\n `检测到服务已在运行 (PID: ${pid}),正在自动重启...`,\n [\"如果不希望自动重启,请使用 xiaozhi stop 手动停止服务\"]\n );\n }\n\n static notRunning(): ServiceError {\n return new ServiceError(\"服务未运行\", ['请运行 \"xiaozhi start\" 启动服务']);\n }\n\n static startFailed(reason: string): ServiceError {\n return new ServiceError(`服务启动失败: ${reason}`, [\n \"检查配置文件是否正确\",\n \"确保端口未被占用\",\n \"查看日志文件获取详细信息\",\n ]);\n }\n}\n\n/**\n * 验证错误\n */\nexport class ValidationError extends CLIError {\n constructor(message: string, field: string) {\n super(`验证失败: ${field} - ${message}`, ERROR_CODES.VALIDATION_ERROR, 1);\n this.name = \"ValidationError\";\n }\n\n static invalidPort(port: number): ValidationError {\n return new ValidationError(\n `端口号必须在 1-65535 范围内,当前值: ${port}`,\n \"port\"\n );\n }\n\n static requiredField(field: string): ValidationError {\n return new ValidationError(\"必填字段不能为空\", field);\n }\n}\n\n/**\n * 文件操作错误\n */\nexport class FileError extends CLIError {\n constructor(message: string, filePath?: string, suggestions?: string[]) {\n const fullMessage = filePath ? `${message}: ${filePath}` : message;\n super(fullMessage, ERROR_CODES.FILE_ERROR, 1, suggestions);\n this.name = \"FileError\";\n }\n\n static notFound(filePath: string): FileError {\n return new FileError(\"文件不存在\", filePath, [\"检查文件路径是否正确\"]);\n }\n\n static permissionDenied(filePath: string): FileError {\n return new FileError(\"权限不足\", filePath, [\n \"检查文件权限或使用管理员权限运行\",\n ]);\n }\n\n static alreadyExists(filePath: string): FileError {\n return new FileError(\"文件已存在\", filePath, [\n \"使用不同的文件名或删除现有文件\",\n ]);\n }\n}\n\n/**\n * 进程错误\n */\nexport class ProcessError extends CLIError {\n constructor(message: string, pid?: number, suggestions?: string[]) {\n const fullMessage = pid ? `${message} (PID: ${pid})` : message;\n super(fullMessage, ERROR_CODES.PROCESS_ERROR, 1, suggestions);\n this.name = \"ProcessError\";\n }\n\n static killFailed(pid: number): ProcessError {\n return new ProcessError(\"无法终止进程\", pid, [\n \"进程可能已经停止或权限不足\",\n ]);\n }\n\n static notFound(pid: number): ProcessError {\n return new ProcessError(\"进程不存在\", pid);\n }\n}\n","/**\n * 错误处理器\n */\n\nimport { ERROR_MESSAGES } from \"@cli/errors/ErrorMessages.js\";\nimport { CLIError } from \"@cli/errors/index.js\";\nimport chalk from \"chalk\";\n\n/**\n * 错误处理器类\n */\nexport class ErrorHandler {\n /**\n * 处理错误并退出程序\n */\n static handle(error: Error): never {\n if (error instanceof CLIError) {\n ErrorHandler.handleCLIError(error);\n } else {\n ErrorHandler.handleUnknownError(error);\n }\n\n process.exit(1);\n }\n\n /**\n * 处理 CLI 错误\n */\n private static handleCLIError(error: CLIError): void {\n console.error(chalk.red(`❌ 错误: ${error.message}`));\n\n // 显示错误码(调试模式)\n if (process.env.DEBUG) {\n console.error(chalk.gray(`错误码: ${error.code}`));\n }\n\n // 显示建议\n if (error.suggestions && error.suggestions.length > 0) {\n console.log(chalk.yellow(\"💡 建议:\"));\n for (const suggestion of error.suggestions) {\n console.log(chalk.gray(` ${suggestion}`));\n }\n }\n\n // 显示相关帮助信息\n const helpMessage = ERROR_MESSAGES.getHelpMessage(error.code);\n if (helpMessage) {\n console.log(chalk.blue(`ℹ️ ${helpMessage}`));\n }\n }\n\n /**\n * 处理未知错误\n */\n private static handleUnknownError(error: Error): void {\n console.error(chalk.red(`❌ 未知错误: ${error.message}`));\n\n // 在调试模式下显示完整堆栈\n if (process.env.DEBUG || process.env.NODE_ENV === \"development\") {\n console.error(chalk.gray(\"堆栈信息:\"));\n console.error(chalk.gray(error.stack));\n } else {\n console.log(\n chalk.yellow(\"💡 提示: 设置 DEBUG=1 环境变量查看详细错误信息\")\n );\n }\n }\n\n /**\n * 异步操作错误处理包装器\n */\n static async handleAsync<T>(\n operation: () => Promise<T>,\n context: string\n ): Promise<T> {\n try {\n return await operation();\n } catch (error) {\n if (error instanceof CLIError) {\n throw error;\n }\n if (error instanceof Error) {\n throw new CLIError(\n `${context}失败: ${error.message}`,\n \"OPERATION_FAILED\",\n 1\n );\n }\n throw new CLIError(`${context}失败: 未知错误`, \"OPERATION_FAILED\", 1);\n }\n }\n\n /**\n * 同步操作错误处理包装器\n */\n static handleSync<T>(operation: () => T, context: string): T {\n try {\n return operation();\n } catch (error) {\n if (error instanceof CLIError) {\n throw error;\n }\n if (error instanceof Error) {\n throw new CLIError(\n `${context}失败: ${error.message}`,\n \"OPERATION_FAILED\",\n 1\n );\n }\n throw new CLIError(`${context}失败: 未知错误`, \"OPERATION_FAILED\", 1);\n }\n }\n\n /**\n * 警告处理\n */\n static warn(message: string, suggestions?: string[]): void {\n console.warn(chalk.yellow(`⚠️ 警告: ${message}`));\n\n if (suggestions && suggestions.length > 0) {\n console.log(chalk.yellow(\"💡 建议:\"));\n for (const suggestion of suggestions) {\n console.log(chalk.gray(` ${suggestion}`));\n }\n }\n }\n\n /**\n * 信息提示\n */\n static info(message: string): void {\n console.log(chalk.blue(`ℹ️ ${message}`));\n }\n\n /**\n * 成功提示\n */\n static success(message: string): void {\n console.log(chalk.green(`✅ ${message}`));\n }\n}\n","/**\n * 文件操作工具\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport type { FileOperationOptions } from \"@cli/Types.js\";\nimport { FileError } from \"@cli/errors/index.js\";\n\n/**\n * 文件工具类\n */\nexport class FileUtils {\n /**\n * 检查文件是否存在\n */\n static exists(filePath: string): boolean {\n try {\n return fs.existsSync(filePath);\n } catch {\n return false;\n }\n }\n\n /**\n * 确保目录存在\n */\n static ensureDir(dirPath: string): void {\n try {\n if (!fs.existsSync(dirPath)) {\n fs.mkdirSync(dirPath, { recursive: true });\n }\n } catch (error) {\n throw new FileError(\"无法创建目录\", dirPath);\n }\n }\n\n /**\n * 读取文件内容\n */\n static readFile(filePath: string, encoding: BufferEncoding = \"utf8\"): string {\n try {\n if (!FileUtils.exists(filePath)) {\n throw FileError.notFound(filePath);\n }\n return fs.readFileSync(filePath, encoding);\n } catch (error) {\n if (error instanceof FileError) {\n throw error;\n }\n throw new FileError(\"无法读取文件\", filePath);\n }\n }\n\n /**\n * 写入文件内容\n */\n static writeFile(\n filePath: string,\n content: string,\n options?: { overwrite?: boolean }\n ): void {\n try {\n if (!options?.overwrite && FileUtils.exists(filePath)) {\n throw FileError.alreadyExists(filePath);\n }\n\n // 确保目录存在\n const dir = path.dirname(filePath);\n FileUtils.ensureDir(dir);\n\n fs.writeFileSync(filePath, content, \"utf8\");\n } catch (error) {\n if (error instanceof FileError) {\n throw error;\n }\n throw new FileError(\"无法写入文件\", filePath);\n }\n }\n\n /**\n * 复制文件\n */\n static copyFile(\n srcPath: string,\n destPath: string,\n options?: { overwrite?: boolean }\n ): void {\n try {\n if (!FileUtils.exists(srcPath)) {\n throw FileError.notFound(srcPath);\n }\n\n if (!options?.overwrite && FileUtils.exists(destPath)) {\n throw FileError.alreadyExists(destPath);\n }\n\n // 确保目标目录存在\n const destDir = path.dirname(destPath);\n FileUtils.ensureDir(destDir);\n\n fs.copyFileSync(srcPath, destPath);\n } catch (error) {\n if (error instanceof FileError) {\n throw error;\n }\n throw new FileError(\"无法复制文件\", srcPath);\n }\n }\n\n /**\n * 删除文件\n */\n static deleteFile(filePath: string): void {\n try {\n if (FileUtils.exists(filePath)) {\n fs.unlinkSync(filePath);\n }\n } catch (error) {\n throw new FileError(\"无法删除文件\", filePath);\n }\n }\n\n /**\n * 复制目录\n */\n static copyDirectory(\n srcDir: string,\n destDir: string,\n options: FileOperationOptions = {}\n ): void {\n try {\n if (!FileUtils.exists(srcDir)) {\n throw FileError.notFound(srcDir);\n }\n\n // 确保目标目录存在\n FileUtils.ensureDir(destDir);\n\n const items = fs.readdirSync(srcDir);\n\n for (const item of items) {\n // 检查是否在排除列表中\n if (options.exclude?.includes(item)) {\n continue;\n }\n\n const srcPath = path.join(srcDir, item);\n const destPath = path.join(destDir, item);\n const stat = fs.statSync(srcPath);\n\n if (stat.isDirectory()) {\n if (options.recursive !== false) {\n FileUtils.copyDirectory(srcPath, destPath, options);\n }\n } else {\n FileUtils.copyFile(srcPath, destPath, {\n overwrite: options.overwrite,\n });\n }\n }\n } catch (error) {\n if (error instanceof FileError) {\n throw error;\n }\n throw new FileError(\"无法复制目录\", srcDir);\n }\n }\n\n /**\n * 删除目录\n */\n static deleteDirectory(\n dirPath: string,\n options: { recursive?: boolean } = {}\n ): void {\n try {\n if (FileUtils.exists(dirPath)) {\n fs.rmSync(dirPath, {\n recursive: options.recursive ?? true,\n force: true,\n });\n }\n } catch (error) {\n throw new FileError(\"无法删除目录\", dirPath);\n }\n }\n\n /**\n * 获取文件信息\n */\n static getFileInfo(filePath: string): {\n size: number;\n isFile: boolean;\n isDirectory: boolean;\n mtime: Date;\n ctime: Date;\n } {\n try {\n if (!FileUtils.exists(filePath)) {\n throw FileError.notFound(filePath);\n }\n\n const stats = fs.statSync(filePath);\n return {\n size: stats.size,\n isFile: stats.isFile(),\n isDirectory: stats.isDirectory(),\n mtime: stats.mtime,\n ctime: stats.ctime,\n };\n } catch (error) {\n if (error instanceof FileError) {\n throw error;\n }\n throw new FileError(\"无法获取文件信息\", filePath);\n }\n }\n\n /**\n * 列出目录内容\n */\n static listDirectory(\n dirPath: string,\n options: {\n recursive?: boolean;\n includeHidden?: boolean;\n } = {}\n ): string[] {\n try {\n if (!FileUtils.exists(dirPath)) {\n throw FileError.notFound(dirPath);\n }\n\n const items = fs.readdirSync(dirPath);\n let result: string[] = [];\n\n for (const item of items) {\n // 跳过隐藏文件(除非明确要求包含)\n if (!options.includeHidden && item.startsWith(\".\")) {\n continue;\n }\n\n const itemPath = path.join(dirPath, item);\n result.push(itemPath);\n\n // 递归处理子目录\n if (options.recursive && fs.statSync(itemPath).isDirectory()) {\n const subItems = FileUtils.listDirectory(itemPath, options);\n result = result.concat(subItems);\n }\n }\n\n return result;\n } catch (error) {\n if (error instanceof FileError) {\n throw error;\n }\n throw new FileError(\"无法列出目录内容\", dirPath);\n }\n }\n\n /**\n * 创建临时文件\n */\n static createTempFile(prefix = \"xiaozhi-\", suffix = \".tmp\"): string {\n const tempDir = process.env.TMPDIR || process.env.TEMP || \"/tmp\";\n const timestamp = Date.now();\n const random = Math.random().toString(36).substring(2);\n const fileName = `${prefix}${timestamp}-${random}${suffix}`;\n return path.join(tempDir, fileName);\n }\n\n /**\n * 检查文件权限\n */\n static checkPermissions(\n filePath: string,\n mode: number = fs.constants.R_OK | fs.constants.W_OK\n ): boolean {\n try {\n fs.accessSync(filePath, mode);\n return true;\n } catch {\n return false;\n }\n }\n\n /**\n * 获取文件扩展名\n */\n static getExtension(filePath: string): string {\n return path.extname(filePath).toLowerCase();\n }\n\n /**\n * 获取文件名(不含扩展名)\n */\n static getBaseName(filePath: string): string {\n return path.basename(filePath, path.extname(filePath));\n }\n\n /**\n * 规范化路径\n */\n static normalizePath(filePath: string): string {\n return path.normalize(filePath);\n }\n\n /**\n * 解析相对路径为绝对路径\n */\n static resolvePath(filePath: string, basePath?: string): string {\n if (basePath) {\n return path.resolve(basePath, filePath);\n }\n return path.resolve(filePath);\n }\n}\n","/**\n * 格式化工具\n */\n\n/**\n * 格式化工具类\n */\nexport class FormatUtils {\n /**\n * 格式化运行时间\n */\n static formatUptime(ms: number): string {\n const seconds = Math.floor(ms / 1000);\n const minutes = Math.floor(seconds / 60);\n const hours = Math.floor(minutes / 60);\n const days = Math.floor(hours / 24);\n\n if (days > 0) {\n return `${days}天 ${hours % 24}小时 ${minutes % 60}分钟`;\n }\n if (hours > 0) {\n return `${hours}小时 ${minutes % 60}分钟`;\n }\n if (minutes > 0) {\n return `${minutes}分钟 ${seconds % 60}秒`;\n }\n return `${seconds}秒`;\n }\n\n /**\n * 格式化文件大小\n */\n static formatFileSize(bytes: number): string {\n const units = [\"B\", \"KB\", \"MB\", \"GB\", \"TB\"];\n let size = bytes;\n let unitIndex = 0;\n\n while (size >= 1024 && unitIndex < units.length - 1) {\n size /= 1024;\n unitIndex++;\n }\n\n return `${size.toFixed(unitIndex === 0 ? 0 : 1)} ${units[unitIndex]}`;\n }\n\n /**\n * 格式化时间戳\n */\n static formatTimestamp(\n timestamp: number,\n format: \"full\" | \"date\" | \"time\" = \"full\"\n ): string {\n const date = new Date(timestamp);\n\n switch (format) {\n case \"date\":\n return date.toLocaleDateString(\"zh-CN\");\n case \"time\":\n return date.toLocaleTimeString(\"zh-CN\");\n default:\n return date.toLocaleString(\"zh-CN\");\n }\n }\n\n /**\n * 格式化进程 ID\n */\n static formatPid(pid: number): string {\n return `PID: ${pid}`;\n }\n\n /**\n * 格式化端口号\n */\n static formatPort(port: number): string {\n return `端口: ${port}`;\n }\n\n /**\n * 格式化 URL\n */\n static formatUrl(\n protocol: string,\n host: string,\n port: number,\n path?: string\n ): string {\n const url = `${protocol}://${host}:${port}`;\n return path ? `${url}${path}` : url;\n }\n\n /**\n * 格式化配置键值对\n */\n static formatConfigPair(key: string, value: any): string {\n if (typeof value === \"object\") {\n return `${key}: ${JSON.stringify(value, null, 2)}`;\n }\n return `${key}: ${value}`;\n }\n\n /**\n * 格式化错误消息\n */\n static formatError(error: Error, includeStack = false): string {\n let message = `错误: ${error.message}`;\n\n if (includeStack && error.stack) {\n message += `\\n堆栈信息:\\n${error.stack}`;\n }\n\n return message;\n }\n\n /**\n * 格式化列表\n */\n static formatList(items: string[], bullet = \"•\"): string {\n return items.map((item) => `${bullet} ${item}`).join(\"\\n\");\n }\n\n /**\n * 格式化表格数据\n */\n static formatTable(data: Record<string, any>[]): string {\n if (data.length === 0) return \"\";\n\n const keys = Object.keys(data[0]);\n const maxWidths = keys.map((key) =>\n Math.max(key.length, ...data.map((row) => String(row[key]).length))\n );\n\n // 表头\n const header = keys.map((key, i) => key.padEnd(maxWidths[i])).join(\" | \");\n const separator = maxWidths.map((width) => \"-\".repeat(width)).join(\"-|-\");\n\n // 数据行\n const rows = data.map((row) =>\n keys.map((key, i) => String(row[key]).padEnd(maxWidths[i])).join(\" | \")\n );\n\n return [header, separator, ...rows].join(\"\\n\");\n }\n\n /**\n * 格式化进度条\n */\n static formatProgressBar(current: number, total: number, width = 20): string {\n const percentage = Math.min(current / total, 1);\n const filled = Math.floor(percentage * width);\n const empty = width - filled;\n\n const bar = \"█\".repeat(filled) + \"░\".repeat(empty);\n const percent = Math.floor(percentage * 100);\n\n return `[${bar}] ${percent}% (${current}/${total})`;\n }\n\n /**\n * 格式化命令行参数\n */\n static formatCommandArgs(command: string, args: string[]): string {\n const quotedArgs = args.map((arg) =>\n arg.includes(\" \") ? `\"${arg}\"` : arg\n );\n return `${command} ${quotedArgs.join(\" \")}`;\n }\n\n /**\n * 截断长文本\n */\n static truncateText(text: string, maxLength: number, suffix = \"...\"): string {\n if (text.length <= maxLength) return text;\n return text.substring(0, maxLength - suffix.length) + suffix;\n }\n\n /**\n * 格式化 JSON\n */\n static formatJson(obj: any, indent = 2): string {\n try {\n return JSON.stringify(obj, null, indent);\n } catch (error) {\n return String(obj);\n }\n }\n\n /**\n * 格式化布尔值\n */\n static formatBoolean(\n value: boolean,\n trueText = \"是\",\n falseText = \"否\"\n ): string {\n return value ? trueText : falseText;\n }\n}\n","/**\n * 路径处理工具\n */\n\nimport { realpathSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport {\n CONFIG_CONSTANTS,\n PATH_CONSTANTS,\n SERVICE_CONSTANTS,\n} from \"@cli/Constants.js\";\nimport { FileUtils } from \"@cli/utils/FileUtils.js\";\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 // 开发环境:src/cli/utils/PathUtils.ts -> templates\n path.join(scriptDir, \"..\", \"..\", \"..\", PATH_CONSTANTS.TEMPLATES_DIR),\n // npm 全局安装\n path.join(\n scriptDir,\n \"..\",\n \"..\",\n \"..\",\n \"..\",\n PATH_CONSTANTS.TEMPLATES_DIR\n ),\n ];\n }\n\n /**\n * 查找模板目录\n */\n static findTemplatesDir(): string | null {\n const possiblePaths = PathUtils.getTemplatesDir();\n\n for (const templatesDir of possiblePaths) {\n if (FileUtils.exists(templatesDir)) {\n return templatesDir;\n }\n }\n\n return null;\n }\n\n /**\n * 获取模板路径\n */\n static getTemplatePath(templateName: string): string | null {\n const templatesDir = PathUtils.findTemplatesDir();\n if (!templatesDir) {\n return null;\n }\n\n const templatePath = path.join(templatesDir, templateName);\n return FileUtils.exists(templatePath) ? templatePath : null;\n }\n\n /**\n * 获取脚本目录路径\n */\n static getScriptDir(): string {\n const __filename = fileURLToPath(import.meta.url);\n return path.dirname(__filename);\n }\n\n /**\n * 获取项目根目录路径\n */\n static getProjectRoot(): string {\n const scriptDir = PathUtils.getScriptDir();\n // 从 src/cli/utils 回到项目根目录\n return path.join(scriptDir, \"..\", \"..\", \"..\");\n }\n\n /**\n * 获取构建输出目录路径\n */\n static getDistDir(): string {\n const projectRoot = PathUtils.getProjectRoot();\n return path.join(projectRoot, \"dist\");\n }\n\n /**\n * 获取相对于项目根目录的路径\n */\n static getRelativePath(filePath: string): string {\n const projectRoot = PathUtils.getProjectRoot();\n return path.relative(projectRoot, filePath);\n }\n\n /**\n * 解析配置文件路径\n */\n static resolveConfigPath(format?: \"json\" | \"json5\" | \"jsonc\"): string {\n const configDir = PathUtils.getConfigDir();\n\n if (format) {\n return path.join(configDir, `xiaozhi.config.${format}`);\n }\n\n // 按优先级查找配置文件\n for (const fileName of CONFIG_CONSTANTS.FILE_NAMES) {\n const filePath = path.join(configDir, fileName);\n if (FileUtils.exists(filePath)) {\n return filePath;\n }\n }\n\n // 返回默认配置文件路径\n return path.join(configDir, CONFIG_CONSTANTS.FILE_NAMES[2]); // xiaozhi.config.json\n }\n\n /**\n * 获取默认配置文件路径\n */\n static getDefaultConfigPath(): string {\n const projectRoot = PathUtils.getProjectRoot();\n return path.join(projectRoot, CONFIG_CONSTANTS.DEFAULT_FILE);\n }\n\n /**\n * 验证路径安全性(防止路径遍历攻击)\n */\n static validatePath(inputPath: string): boolean {\n const normalizedPath = path.normalize(inputPath);\n return !normalizedPath.includes(\"..\");\n }\n\n /**\n * 确保路径在指定目录内\n */\n static ensurePathWithin(inputPath: string, baseDir: string): string {\n const resolvedPath = path.resolve(baseDir, inputPath);\n const resolvedBase = path.resolve(baseDir);\n\n if (!resolvedPath.startsWith(resolvedBase)) {\n throw new Error(`路径 ${inputPath} 超出了允许的范围`);\n }\n\n return resolvedPath;\n }\n\n /**\n * 获取可执行文件路径\n */\n static getExecutablePath(name: string): string {\n // 获取当前执行的 CLI 脚本路径\n const cliPath = process.argv[1];\n\n // 处理 cliPath 为 undefined 的情况\n if (!cliPath) {\n // 如果没有脚本路径,使用当前工作目录\n return path.join(process.cwd(), `${name}.js`);\n }\n\n // 解析符号链接,获取真实路径\n let realCliPath: string;\n try {\n realCliPath = realpathSync(cliPath);\n } catch (error) {\n // 如果无法解析符号链接,使用原路径\n realCliPath = cliPath;\n }\n\n // 获取 dist 目录\n const distDir = path.dirname(realCliPath);\n return path.join(distDir, `${name}.js`);\n }\n\n /**\n * 获取 Web 服务器启动器路径\n */\n static getWebServerLauncherPath(): string {\n return PathUtils.getExecutablePath(\"WebServerLauncher\");\n }\n\n /**\n * 创建安全的文件路径\n */\n static createSafePath(...segments: string[]): string {\n const joinedPath = path.join(...segments);\n const normalizedPath = path.normalize(joinedPath);\n\n // 检查路径是否包含危险字符\n if (normalizedPath.includes(\"..\") || normalizedPath.includes(\"~\")) {\n throw new Error(`不安全的路径: ${normalizedPath}`);\n }\n\n return normalizedPath;\n }\n\n /**\n * 获取临时目录路径\n */\n static getTempDir(): string {\n // 使用 Node.js 的 os.tmpdir() 来获取跨平台的临时目录\n return process.env.TMPDIR || process.env.TEMP || tmpdir();\n }\n\n /**\n * 获取用户主目录路径\n */\n static getHomeDir(): string {\n return process.env.HOME || process.env.USERPROFILE || \"\";\n }\n}\n","/**\n * 平台相关工具\n */\n\nimport { execSync } from \"node:child_process\";\nimport { TIMEOUT_CONSTANTS } from \"@cli/Constants.js\";\nimport type { Platform } from \"@cli/Types.js\";\nimport { ProcessError } from \"@cli/errors/index.js\";\n\n/**\n * 平台工具类\n */\nexport class PlatformUtils {\n /**\n * 获取当前平台\n */\n static getCurrentPlatform(): Platform {\n return process.platform as Platform;\n }\n\n /**\n * 检查是否为 Windows 平台\n */\n static isWindows(): boolean {\n return process.platform === \"win32\";\n }\n\n /**\n * 检查是否为 macOS 平台\n */\n static isMacOS(): boolean {\n return process.platform === \"darwin\";\n }\n\n /**\n * 检查是否为 Linux 平台\n */\n static isLinux(): boolean {\n return process.platform === \"linux\";\n }\n\n /**\n * 检查是否为类 Unix 系统\n */\n static isUnixLike(): boolean {\n return !PlatformUtils.isWindows();\n }\n\n /**\n * 检查进程是否为 xiaozhi-client 进程\n */\n static isXiaozhiProcess(pid: number): boolean {\n try {\n // 在容器环境或测试环境中,使用更宽松的检查策略\n if (\n process.env.XIAOZHI_CONTAINER === \"true\" ||\n process.env.NODE_ENV === \"test\"\n ) {\n // 容器环境或测试环境中,如果 PID 存在就认为是有效的\n // 因为容器通常只运行一个主要应用,测试环境中mock了进程检查\n process.kill(pid, 0);\n return true;\n }\n\n // 非容器环境中,尝试更严格的进程检查\n try {\n let cmdline = \"\";\n if (PlatformUtils.isWindows()) {\n // Windows 系统\n const result = execSync(`tasklist /FI \"PID eq ${pid}\" /FO CSV /NH`, {\n encoding: \"utf8\",\n timeout: TIMEOUT_CONSTANTS.PROCESS_STOP,\n });\n cmdline = result.toLowerCase();\n } else {\n // Unix-like 系统\n const result = execSync(`ps -p ${pid} -o comm=`, {\n encoding: \"utf8\",\n timeout: TIMEOUT_CONSTANTS.PROCESS_STOP,\n });\n cmdline = result.toLowerCase();\n }\n\n // 检查是否包含 node 或 xiaozhi 相关关键词\n return cmdline.includes(\"node\") || cmdline.includes(\"xiaozhi\");\n } catch (error) {\n // 如果无法获取进程信息,回退到简单的 PID 检查\n process.kill(pid, 0);\n return true;\n }\n } catch (error) {\n return false;\n }\n }\n\n /**\n * 杀死进程\n */\n static async killProcess(\n pid: number,\n signal: NodeJS.Signals = \"SIGTERM\"\n ): Promise<void> {\n try {\n process.kill(pid, signal);\n\n // 等待进程停止\n let attempts = 0;\n const maxAttempts = 30; // 3秒超时\n\n while (attempts < maxAttempts) {\n await new Promise((resolve) => setTimeout(resolve, 100));\n\n try {\n process.kill(pid, 0);\n attempts++;\n } catch {\n // 进程已停止\n return;\n }\n }\n\n // 如果还在运行,强制停止\n try {\n process.kill(pid, 0);\n process.kill(pid, \"SIGKILL\");\n await new Promise((resolve) => setTimeout(resolve, 500));\n } catch {\n // 进程已停止\n }\n } catch (error) {\n throw new ProcessError(\n `无法终止进程: ${error instanceof Error ? error.message : String(error)}`,\n pid\n );\n }\n }\n\n /**\n * 检查进程是否存在\n */\n static processExists(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n }\n\n /**\n * 获取系统信息\n */\n static getSystemInfo(): {\n platform: Platform;\n arch: string;\n nodeVersion: string;\n isContainer: boolean;\n } {\n return {\n platform: PlatformUtils.getCurrentPlatform(),\n arch: process.arch,\n nodeVersion: process.version,\n isContainer: process.env.XIAOZHI_CONTAINER === \"true\",\n };\n }\n\n /**\n * 获取环境变量\n */\n static getEnvVar(name: string, defaultValue?: string): string | undefined {\n return process.env[name] || defaultValue;\n }\n\n /**\n * 设置环境变量\n */\n static setEnvVar(name: string, value: string): void {\n process.env[name] = value;\n }\n\n /**\n * 检查是否在容器环境中运行\n */\n static isContainerEnvironment(): boolean {\n return process.env.XIAOZHI_CONTAINER === \"true\";\n }\n\n /**\n * 检查是否在测试环境中运行\n */\n static isTestEnvironment(): boolean {\n return process.env.NODE_ENV === \"test\";\n }\n\n /**\n * 检查是否在开发环境中运行\n */\n static isDevelopmentEnvironment(): boolean {\n return process.env.NODE_ENV === \"development\";\n }\n\n /**\n * 获取合适的 tail 命令\n */\n static getTailCommand(filePath: string): { command: string; args: string[] } {\n if (PlatformUtils.isWindows()) {\n return {\n command: \"powershell\",\n args: [\"-Command\", `Get-Content -Path \"${filePath}\" -Wait`],\n };\n }\n return {\n command: \"tail\",\n args: [\"-f\", filePath],\n };\n }\n}\n","/**\n * 输入验证工具\n */\n\nimport type { ConfigFormat } from \"@cli/Types.js\";\nimport { ValidationError } from \"@cli/errors/index.js\";\n\n/**\n * 验证工具类\n */\nexport class Validation {\n /**\n * 验证端口号\n */\n static validatePort(port: number): void {\n if (!Number.isInteger(port) || port < 1 || port > 65535) {\n throw ValidationError.invalidPort(port);\n }\n }\n\n /**\n * 验证配置文件格式\n */\n static validateConfigFormat(format: string): ConfigFormat {\n const validFormats: ConfigFormat[] = [\"json\", \"json5\", \"jsonc\"];\n\n if (!validFormats.includes(format as ConfigFormat)) {\n throw new ValidationError(\n `无效的配置文件格式: ${format},支持的格式: ${validFormats.join(\", \")}`,\n \"format\"\n );\n }\n\n return format as ConfigFormat;\n }\n\n /**\n * 验证必填字段\n */\n static validateRequired(value: any, fieldName: string): void {\n if (value === undefined || value === null || value === \"\") {\n throw ValidationError.requiredField(fieldName);\n }\n }\n\n /**\n * 验证字符串长度\n */\n static validateStringLength(\n value: string,\n fieldName: string,\n options: { min?: number; max?: number } = {}\n ): void {\n if (options.min !== undefined && value.length < options.min) {\n throw new ValidationError(\n `长度不能少于 ${options.min} 个字符,当前长度: ${value.length}`,\n fieldName\n );\n }\n\n if (options.max !== undefined && value.length > options.max) {\n throw new ValidationError(\n `长度不能超过 ${options.max} 个字符,当前长度: ${value.length}`,\n fieldName\n );\n }\n }\n\n /**\n * 验证 URL 格式\n */\n static validateUrl(url: string, fieldName = \"url\"): void {\n try {\n new URL(url);\n } catch {\n throw new ValidationError(`无效的 URL 格式: ${url}`, fieldName);\n }\n }\n\n /**\n * 验证 WebSocket URL 格式\n */\n static validateWebSocketUrl(url: string, fieldName = \"websocket_url\"): void {\n Validation.validateUrl(url, fieldName);\n\n const parsedUrl = new URL(url);\n if (![\"ws:\", \"wss:\"].includes(parsedUrl.protocol)) {\n throw new ValidationError(\n `WebSocket URL 必须使用 ws:// 或 wss:// 协议,当前协议: ${parsedUrl.protocol}`,\n fieldName\n );\n }\n }\n\n /**\n * 验证 HTTP URL 格式\n */\n static validateHttpUrl(url: string, fieldName = \"http_url\"): void {\n Validation.validateUrl(url, fieldName);\n\n const parsedUrl = new URL(url);\n if (![\"http:\", \"https:\"].includes(parsedUrl.protocol)) {\n throw new ValidationError(\n `HTTP URL 必须使用 http:// 或 https:// 协议,当前协议: ${parsedUrl.protocol}`,\n fieldName\n );\n }\n }\n\n /**\n * 验证项目名称\n */\n static validateProjectName(name: string): void {\n Validation.validateRequired(name, \"projectName\");\n Validation.validateStringLength(name, \"projectName\", { min: 1, max: 100 });\n\n // 检查是否包含非法字符\n const invalidChars = /[<>:\"/\\\\|?*]/;\n const hasControlChars = name\n .split(\"\")\n .some((char) => char.charCodeAt(0) < 32);\n\n if (invalidChars.test(name) || hasControlChars) {\n throw new ValidationError(\n '项目名称不能包含以下字符: < > : \" / \\\\ | ? * 以及控制字符',\n \"projectName\"\n );\n }\n\n // 检查是否以点开头\n if (name.startsWith(\".\")) {\n throw new ValidationError(\"项目名称不能以点开头\", \"projectName\");\n }\n }\n\n /**\n * 验证模板名称\n */\n static validateTemplateName(name: string): void {\n Validation.validateRequired(name, \"templateName\");\n Validation.validateStringLength(name, \"templateName\", { min: 1, max: 50 });\n\n // 模板名称只能包含字母、数字、连字符和下划线\n const validPattern = /^[a-zA-Z0-9_-]+$/;\n if (!validPattern.test(name)) {\n throw new ValidationError(\n \"模板名称只能包含字母、数字、连字符和下划线\",\n \"templateName\"\n );\n }\n }\n\n /**\n * 验证环境变量名称\n */\n static validateEnvVarName(name: string): void {\n Validation.validateRequired(name, \"envVarName\");\n\n // 环境变量名称只能包含大写字母、数字和下划线,且不能以数字开头\n const validPattern = /^[A-Z_][A-Z0-9_]*$/;\n if (!validPattern.test(name)) {\n throw new ValidationError(\n \"环境变量名称只能包含大写字母、数字和下划线,且不能以数字开头\",\n \"envVarName\"\n );\n }\n }\n\n /**\n * 验证 JSON 格式\n */\n static validateJson(jsonString: string, fieldName = \"json\"): any {\n try {\n return JSON.parse(jsonString);\n } catch (error) {\n throw new ValidationError(\n `无效的 JSON 格式: ${error instanceof Error ? error.message : String(error)}`,\n fieldName\n );\n }\n }\n\n /**\n * 验证数字范围\n */\n static validateNumberRange(\n value: number,\n fieldName: string,\n options: { min?: number; max?: number } = {}\n ): void {\n if (options.min !== undefined && value < options.min) {\n throw new ValidationError(\n `值不能小于 ${options.min},当前值: ${value}`,\n fieldName\n );\n }\n\n if (options.max !== undefined && value > options.max) {\n throw new ValidationError(\n `值不能大于 ${options.max},当前值: ${value}`,\n fieldName\n );\n }\n }\n\n /**\n * 验证数组长度\n */\n static validateArrayLength(\n array: any[],\n fieldName: string,\n options: { min?: number; max?: number } = {}\n ): void {\n if (options.min !== undefined && array.length < options.min) {\n throw new ValidationError(\n `数组长度不能少于 ${options.min},当前长度: ${array.length}`,\n fieldName\n );\n }\n\n if (options.max !== undefined && array.length > options.max) {\n throw new ValidationError(\n `数组长度不能超过 ${options.max},当前长度: ${array.length}`,\n fieldName\n );\n }\n }\n\n /**\n * 验证对象属性\n */\n static validateObjectProperties(\n obj: Record<string, any>,\n requiredProps: string[],\n fieldName = \"object\"\n ): void {\n for (const prop of requiredProps) {\n if (!(prop in obj)) {\n throw new ValidationError(`缺少必需的属性: ${prop}`, fieldName);\n }\n }\n }\n\n /**\n * 验证枚举值\n */\n static validateEnum<T extends string>(\n value: string,\n validValues: T[],\n fieldName: string\n ): T {\n if (!validValues.includes(value as T)) {\n throw new ValidationError(\n `无效的值: ${value},有效值: ${validValues.join(\", \")}`,\n fieldName\n );\n }\n return value as T;\n }\n\n /**\n * 验证正则表达式\n */\n static validateRegex(pattern: string, fieldName = \"regex\"): RegExp {\n try {\n return new RegExp(pattern);\n } catch (error) {\n throw new ValidationError(\n `无效的正则表达式: ${error instanceof Error ? error.message : String(error)}`,\n fieldName\n );\n }\n }\n}\n","/**\n * 版本管理工具\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { FileError } from \"@cli/errors/index.js\";\n\n/**\n * 版本信息接口\n */\nexport interface VersionInfo {\n version: string;\n name?: string;\n description?: string;\n author?: string;\n}\n\n/**\n * 版本工具类\n */\nexport class VersionUtils {\n private static cachedVersion: string | null = null;\n\n /**\n * 获取版本号\n */\n static getVersion(): string {\n if (VersionUtils.cachedVersion) {\n return VersionUtils.cachedVersion;\n }\n\n try {\n // 在 ES 模块环境中获取当前目录\n const __filename = fileURLToPath(import.meta.url);\n const currentDir = path.dirname(__filename);\n\n // 尝试多个可能的 package.json 路径\n const possiblePaths = [\n // 构建后环境:dist/cli.js -> dist/package.json (优先)\n path.join(currentDir, \"package.json\"),\n // 构建后环境:dist/cli.js -> package.json\n path.join(currentDir, \"..\", \"package.json\"),\n // 开发环境:src/cli/utils/VersionUtils.ts -> package.json\n path.join(currentDir, \"..\", \"..\", \"..\", \"package.json\"),\n // 全局安装环境\n path.join(currentDir, \"..\", \"..\", \"..\", \"..\", \"package.json\"),\n ];\n\n for (const packagePath of possiblePaths) {\n if (fs.existsSync(packagePath)) {\n const packageJson = JSON.parse(fs.readFileSync(packagePath, \"utf8\"));\n if (packageJson.version) {\n VersionUtils.cachedVersion = packageJson.version;\n return packageJson.version;\n }\n }\n }\n\n // 如果都找不到,返回默认版本\n VersionUtils.cachedVersion = \"unknown\";\n return \"unknown\";\n } catch (error) {\n console.warn(\"无法从 package.json 读取版本信息:\", error);\n VersionUtils.cachedVersion = \"unknown\";\n return \"unknown\";\n }\n }\n\n /**\n * 获取完整版本信息\n */\n static getVersionInfo(): VersionInfo {\n try {\n const __filename = fileURLToPath(import.meta.url);\n const currentDir = path.dirname(__filename);\n\n const possiblePaths = [\n // 构建后环境:dist/cli.js -> dist/package.json (优先)\n path.join(currentDir, \"package.json\"),\n // 构建后环境:dist/cli.js -> package.json\n path.join(currentDir, \"..\", \"package.json\"),\n // 开发环境:src/cli/utils/VersionUtils.ts -> package.json\n path.join(currentDir, \"..\", \"..\", \"..\", \"package.json\"),\n // 全局安装环境\n path.join(currentDir, \"..\", \"..\", \"..\", \"..\", \"package.json\"),\n ];\n\n for (const packagePath of possiblePaths) {\n if (fs.existsSync(packagePath)) {\n const packageJson = JSON.parse(fs.readFileSync(packagePath, \"utf8\"));\n return {\n version: packageJson.version || \"unknown\",\n name: packageJson.name,\n description: packageJson.description,\n author: packageJson.author,\n };\n }\n }\n\n return { version: \"unknown\" };\n } catch (error) {\n throw new FileError(\"无法读取版本信息\", \"package.json\");\n }\n }\n\n /**\n * 比较版本号\n */\n static compareVersions(version1: string, version2: string): number {\n const v1Parts = version1.split(\".\").map(Number);\n const v2Parts = version2.split(\".\").map(Number);\n const maxLength = Math.max(v1Parts.length, v2Parts.length);\n\n for (let i = 0; i < maxLength; i++) {\n const v1Part = v1Parts[i] || 0;\n const v2Part = v2Parts[i] || 0;\n\n if (v1Part > v2Part) return 1;\n if (v1Part < v2Part) return -1;\n }\n\n return 0;\n }\n\n /**\n * 检查版本是否有效\n */\n static isValidVersion(version: string): boolean {\n const versionRegex = /^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9.-]+)?$/;\n return versionRegex.test(version);\n }\n\n /**\n * 清除版本缓存\n */\n static clearCache(): void {\n VersionUtils.cachedVersion = null;\n }\n}\n","import { FileError, ProcessError } from \"@cli/errors/index.js\";\nimport type {\n ProcessManager as IProcessManager,\n ServiceStatus,\n} from \"@cli/interfaces/Service.js\";\nimport { FileUtils } from \"@cli/utils/FileUtils.js\";\nimport { FormatUtils } from \"@cli/utils/FormatUtils.js\";\nimport { PathUtils } from \"@cli/utils/PathUtils.js\";\nimport { PlatformUtils } from \"@cli/utils/PlatformUtils.js\";\n\n/**\n * PID 文件信息接口\n */\ninterface PidFileInfo {\n pid: number;\n startTime: number;\n mode: \"foreground\" | \"daemon\";\n}\n\n/**\n * 进程管理器实现\n */\nexport class ProcessManagerImpl implements IProcessManager {\n /**\n * 获取 PID 文件路径\n */\n private getPidFilePath(): string {\n return PathUtils.getPidFile();\n }\n\n /**\n * 读取 PID 文件信息\n */\n private readPidFile(): PidFileInfo | null {\n try {\n const pidFilePath = this.getPidFilePath();\n\n if (!FileUtils.exists(pidFilePath)) {\n return null;\n }\n\n const pidContent = FileUtils.readFile(pidFilePath).trim();\n const [pidStr, startTimeStr, mode] = pidContent.split(\"|\");\n\n const pid = Number.parseInt(pidStr);\n const startTime = Number.parseInt(startTimeStr);\n\n if (Number.isNaN(pid) || Number.isNaN(startTime)) {\n // PID 文件损坏,删除它\n this.cleanupPidFile();\n return null;\n }\n\n return {\n pid,\n startTime,\n mode: (mode as \"foreground\" | \"daemon\") || \"foreground\",\n };\n } catch (error) {\n // 读取失败,可能文件损坏\n this.cleanupPidFile();\n return null;\n }\n }\n\n /**\n * 写入 PID 文件信息\n */\n private writePidFile(pid: number, mode: \"foreground\" | \"daemon\"): void {\n try {\n const pidInfo = `${pid}|${Date.now()}|${mode}`;\n const pidFilePath = this.getPidFilePath();\n FileUtils.writeFile(pidFilePath, pidInfo, { overwrite: true });\n } catch (error) {\n throw new FileError(\"无法写入 PID 文件\", this.getPidFilePath());\n }\n }\n\n /**\n * 检查是否为 xiaozhi 进程\n */\n isXiaozhiProcess(pid: number): boolean {\n return PlatformUtils.isXiaozhiProcess(pid);\n }\n\n /**\n * 获取服务状态\n */\n getServiceStatus(): ServiceStatus {\n try {\n const pidInfo = this.readPidFile();\n\n if (!pidInfo) {\n return { running: false };\n }\n\n // 检查进程是否还在运行且是 xiaozhi 进程\n if (!this.isXiaozhiProcess(pidInfo.pid)) {\n // 进程不存在或不是 xiaozhi 进程,删除 PID 文件\n this.cleanupPidFile();\n return { running: false };\n }\n\n // 计算运行时间\n const uptime = FormatUtils.formatUptime(Date.now() - pidInfo.startTime);\n\n return {\n running: true,\n pid: pidInfo.pid,\n uptime,\n mode: pidInfo.mode,\n };\n } catch (error) {\n return { running: false };\n }\n }\n\n /**\n * 保存进程信息\n */\n savePidInfo(pid: number, mode: \"foreground\" | \"daemon\"): void {\n this.writePidFile(pid, mode);\n }\n\n /**\n * 杀死进程\n */\n async killProcess(pid: number): Promise<void> {\n try {\n await PlatformUtils.killProcess(pid);\n } catch (error) {\n throw new ProcessError(\n `无法终止进程: ${error instanceof Error ? error.message : String(error)}`,\n pid\n );\n }\n }\n\n /**\n * 优雅停止进程\n */\n async gracefulKillProcess(pid: number): Promise<void> {\n try {\n // 尝试优雅停止\n process.kill(pid, \"SIGTERM\");\n\n // 等待进程停止\n let attempts = 0;\n const maxAttempts = 30; // 3秒超时\n\n while (attempts < maxAttempts) {\n await new Promise((resolve) => setTimeout(resolve, 100));\n\n try {\n process.kill(pid, 0);\n attempts++;\n } catch {\n // 进程已停止\n return;\n }\n }\n\n // 如果还在运行,强制停止\n try {\n process.kill(pid, 0);\n process.kill(pid, \"SIGKILL\");\n await new Promise((resolve) => setTimeout(resolve, 500));\n } catch {\n // 进程已停止\n }\n } catch (error) {\n throw new ProcessError(\n `无法停止进程: ${error instanceof Error ? error.message : String(error)}`,\n pid\n );\n }\n }\n\n /**\n * 清理 PID 文件\n */\n cleanupPidFile(): void {\n try {\n const pidFilePath = this.getPidFilePath();\n if (FileUtils.exists(pidFilePath)) {\n FileUtils.deleteFile(pidFilePath);\n }\n } catch (error) {\n // 忽略清理错误,但可以记录日志\n console.warn(\"清理 PID 文件失败:\", error);\n }\n }\n\n /**\n * 检查进程是否存在\n */\n processExists(pid: number): boolean {\n return PlatformUtils.processExists(pid);\n }\n\n /**\n * 清理容器环境的旧状态\n */\n cleanupContainerState(): void {\n if (PlatformUtils.isContainerEnvironment()) {\n try {\n this.cleanupPidFile();\n } catch (error) {\n // 忽略清理错误\n }\n }\n }\n\n /**\n * 获取进程信息\n */\n getProcessInfo(pid: number): { exists: boolean; isXiaozhi: boolean } {\n const exists = this.processExists(pid);\n const isXiaozhi = exists ? this.isXiaozhiProcess(pid) : false;\n\n return { exists, isXiaozhi };\n }\n\n /**\n * 验证 PID 文件完整性\n */\n validatePidFile(): boolean {\n try {\n const pidInfo = this.readPidFile();\n return pidInfo !== null;\n } catch {\n return false;\n }\n }\n}\n","/**\n * 守护进程管理服务\n */\n\nimport type { ChildProcess } from \"node:child_process\";\nimport { spawn } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport { ProcessError, ServiceError } from \"@cli/errors/index.js\";\nimport type {\n DaemonManager as IDaemonManager,\n ProcessManager,\n} from \"@cli/interfaces/Service.js\";\nimport { PathUtils } from \"@cli/utils/PathUtils.js\";\nimport { PlatformUtils } from \"@cli/utils/PlatformUtils.js\";\nimport type { Logger } from \"@root/Logger.js\";\nimport type { WebServer } from \"@root/WebServer.js\";\n\n/**\n * 守护进程选项\n */\nexport interface DaemonOptions {\n /** 日志文件名 */\n logFileName?: string;\n /** 环境变量 */\n env?: Record<string, string>;\n /** 是否打开浏览器 */\n openBrowser?: boolean;\n /** 工作目录 */\n cwd?: string;\n}\n\n/**\n * 守护进程管理器实现\n */\nexport class DaemonManagerImpl implements IDaemonManager {\n private currentDaemon: ChildProcess | null = null;\n\n constructor(\n private processManager: ProcessManager,\n private logger: Logger\n ) {}\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 this.logger.info(`守护进程已启动 (PID: ${child.pid})`);\n } catch (error) {\n throw new ServiceError(\n `启动守护进程失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * 停止守护进程\n */\n async stopDaemon(): Promise<void> {\n try {\n const status = this.processManager.getServiceStatus();\n\n if (!status.running) {\n throw ServiceError.notRunning();\n }\n\n // 优雅停止守护进程\n await this.processManager.gracefulKillProcess(status.pid!);\n\n // 清理 PID 文件\n this.processManager.cleanupPidFile();\n\n // 清理当前守护进程引用\n this.currentDaemon = null;\n\n this.logger.info(\"守护进程已停止\");\n } catch (error) {\n throw new ServiceError(\n `停止守护进程失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * 重启守护进程\n */\n async restartDaemon(\n serverFactory: () => Promise<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) => setTimeout(resolve, 1000));\n }\n\n // 重新启动守护进程\n await this.startDaemon(serverFactory, options);\n } catch (error) {\n throw new ServiceError(\n `重启守护进程失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * 获取守护进程状态\n */\n getDaemonStatus(): { running: boolean; pid?: number; uptime?: string } {\n return this.processManager.getServiceStatus();\n }\n\n /**\n * 连接到守护进程日志\n */\n async attachToLogs(logFileName = \"xiaozhi.log\"): Promise<void> {\n try {\n const logFilePath = PathUtils.getLogFile();\n\n if (!fs.existsSync(logFilePath)) {\n throw new ServiceError(\"日志文件不存在\");\n }\n\n // 使用平台相关的 tail 命令\n const { command, args } = PlatformUtils.getTailCommand(logFilePath);\n const tail = spawn(command, args, { stdio: \"inherit\" });\n\n // 处理中断信号\n process.on(\"SIGINT\", () => {\n console.log(\"\\n断开连接,服务继续在后台运行\");\n tail.kill();\n process.exit(0);\n });\n\n tail.on(\"exit\", () => {\n process.exit(0);\n });\n\n tail.on(\"error\", (error) => {\n throw new ServiceError(`连接日志失败: ${error.message}`);\n });\n } catch (error) {\n throw new ServiceError(\n `连接日志失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * 生成守护进程\n */\n private async spawnDaemonProcess(\n serverFactory: () => Promise<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 this.logger.warn(\n `设置日志重定向失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * 设置事件处理器\n */\n private setupEventHandlers(child: ChildProcess): void {\n // 监听进程退出\n child.on(\"exit\", (code, signal) => {\n if (code !== 0 && code !== null) {\n this.logger.error(`守护进程异常退出 (代码: ${code}, 信号: ${signal})`);\n } else {\n this.logger.info(\"守护进程正常退出\");\n }\n\n // 清理 PID 文件\n this.processManager.cleanupPidFile();\n this.currentDaemon = null;\n });\n\n // 监听进程错误\n child.on(\"error\", (error) => {\n this.logger.error(`守护进程错误: ${error.message}`);\n this.processManager.cleanupPidFile();\n this.currentDaemon = null;\n });\n\n // 监听进程断开连接\n child.on(\"disconnect\", () => {\n this.logger.info(\"守护进程断开连接\");\n });\n }\n\n /**\n * 检查守护进程健康状态\n */\n async checkHealth(): Promise<boolean> {\n try {\n const status = this.getDaemonStatus();\n\n if (!status.running || !status.pid) {\n return false;\n }\n\n // 检查进程是否真的在运行\n const processInfo = this.processManager.getProcessInfo(status.pid);\n return processInfo.exists && processInfo.isXiaozhi;\n } catch {\n return false;\n }\n }\n\n /**\n * 获取当前守护进程引用\n */\n getCurrentDaemon(): ChildProcess | null {\n return this.currentDaemon;\n }\n\n /**\n * 清理守护进程资源\n */\n cleanup(): void {\n if (this.currentDaemon) {\n try {\n this.currentDaemon.kill(\"SIGTERM\");\n } catch (error) {\n this.logger.warn(\n `清理守护进程失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n this.currentDaemon = null;\n }\n }\n}\n","/**\n * 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 STREAMABLE_HTTP = \"streamable-http\",\n}\n\n// =========================\n// 2. 配置接口类型\n// =========================\n\n/**\n * ModelScope SSE 自定义选项接口\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 * MCP 服务配置接口\n * 包含所有 MCP 服务的配置选项\n */\nexport interface MCPServiceConfig {\n name: string;\n type?: MCPTransportType; // 现在是可选的,支持自动推断\n // stdio 配置\n command?: string;\n args?: string[];\n env?: Record<string, string>; // 环境变量配置\n // 网络配置\n url?: string;\n // 认证配置\n apiKey?: string;\n headers?: Record<string, string>;\n // ModelScope 特有配置\n modelScopeAuth?: boolean;\n customSSEOptions?: ModelScopeSSEOptions;\n // 超时配置\n timeout?: number;\n // 重试配置\n retryAttempts?: number;\n}\n\n// =========================\n// 3. 状态枚举类型\n// =========================\n\n/**\n * 连接状态枚举\n * 合并了 connection.ts 和 TransportAdapter.ts 中的定义\n */\nexport enum ConnectionState {\n DISCONNECTED = \"disconnected\",\n CONNECTING = \"connecting\",\n CONNECTED = \"connected\",\n RECONNECTING = \"reconnecting\",\n FAILED = \"failed\",\n ERROR = \"error\", // 从 TransportAdapter.ts 合并的额外状态\n}\n\n/**\n * MCP 服务状态接口\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/**\n * 工具调用结果接口\n * 统一了 connection.ts、manager.ts 和 CustomMCPHandler.ts 中的定义\n */\nexport interface ToolCallResult {\n content: Array<{\n type: string;\n text: string;\n }>;\n isError?: boolean;\n}\n\n/**\n * JSON Schema 类型定义\n * 兼容 MCP SDK 的 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 * 如果不符合,会返回一个默认的空对象 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 // 如果不符合标准格式,返回默认的空对象 schema\n return {\n type: \"object\",\n properties: {} as Record<string, object>,\n required: [],\n additionalProperties: true,\n };\n}\n\n/**\n * CustomMCP 工具类型定义\n * 统一了 manager.ts 和 configManager.ts 中的定义\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 * 用于缓存工具映射关系,保持向后兼容性\n */\nexport interface ToolInfo {\n serviceName: string;\n originalName: string;\n tool: Tool;\n}\n\n// =========================\n// 5. 服务器配置类型\n// =========================\n\n/**\n * 统一服务器配置接口\n * 从 UnifiedMCPServer 移入,用于统一服务器配置管理\n */\nexport interface UnifiedServerConfig {\n name?: string;\n enableLogging?: boolean;\n logLevel?: string;\n configs?: Record<string, MCPServiceConfig>; // MCPService 配置\n}\n\n/**\n * 统一服务器状态接口\n * 从 UnifiedMCPServer 移入,用于统一服务器状态管理\n */\nexport interface UnifiedServerStatus {\n isRunning: boolean;\n serviceStatus: ManagerStatus;\n transportCount: number;\n activeConnections: number;\n config: UnifiedServerConfig;\n // 添加对 serviceStatus 的便捷访问属性\n services?: Record<string, MCPServiceConnectionStatus>;\n totalTools?: number;\n availableTools?: string[];\n}\n\n// =========================\n// 6. 管理器相关类型\n// =========================\n\n/**\n * MCP 服务连接状态接口\n * 重命名原 ServiceStatus 为 MCPServiceConnectionStatus 避免与 CLI 的 ServiceStatus 冲突\n */\nexport interface MCPServiceConnectionStatus {\n connected: boolean;\n clientName: string;\n}\n\n/**\n * 管理器状态接口\n * 描述 MCP 服务管理器的整体状态\n */\nexport interface ManagerStatus {\n services: Record<string, MCPServiceConnectionStatus>;\n totalTools: number;\n availableTools: string[];\n}\n\n// =========================\n// 7. 参数校验相关类型\n// =========================\n\n/**\n * 工具调用参数接口\n * 定义标准工具调用参数结构\n */\nexport interface ToolCallParams {\n name: string;\n arguments?: Record<string, unknown>;\n}\n\n/**\n * 验证后的工具调用参数\n * 参数校验通过后的标准化参数结构\n */\nexport interface ValidatedToolCallParams {\n name: string;\n arguments?: Record<string, unknown>;\n}\n\n/**\n * 工具调用验证选项\n * 提供灵活的参数校验配置\n */\nexport interface ToolCallValidationOptions {\n /** 是否验证工具名称,默认为 true */\n validateName?: boolean;\n /** 是否验证参数格式,默认为 true */\n validateArguments?: boolean;\n /** 是否允许空参数,默认为 true */\n allowEmptyArguments?: boolean;\n /** 自定义验证函数 */\n customValidator?: (params: ToolCallParams) => string | null;\n}\n\n/**\n * 工具调用错误码枚举\n * 统一的工具调用错误码定义\n */\nexport enum ToolCallErrorCode {\n /** 无效参数 */\n INVALID_PARAMS = -32602,\n /** 工具不存在 */\n TOOL_NOT_FOUND = -32601,\n /** 服务不可用 */\n SERVICE_UNAVAILABLE = -32001,\n /** 调用超时 */\n TIMEOUT = -32002,\n /** 工具执行错误 */\n TOOL_EXECUTION_ERROR = -32000,\n}\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// =========================\n// 向后兼容性别名\n// =========================\n\n/**\n * 向后兼容:ServiceStatus 别名\n * 为了与现有代码保持兼容,暂时保留此别名\n * @deprecated 请使用 MCPServiceConnectionStatus\n */\nexport type ServiceStatus = MCPServiceConnectionStatus;\n","import { TypeFieldNormalizer } from \"@utils/TypeFieldNormalizer.js\";\nimport { MCPTransportType, ToolCallError, ToolCallErrorCode } from \"./types.js\";\nimport type {\n MCPServiceConfig,\n ToolCallParams,\n ToolCallValidationOptions,\n ValidatedToolCallParams,\n} from \"./types.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.STREAMABLE_HTTP;\n }\n\n // 默认类型 - 使用 console 输出\n if (options?.serviceName) {\n console.info(\n `[MCP-${options.serviceName}] URL 路径 ${pathname} 不匹配特定规则,默认推断为 streamable-http 类型`\n );\n }\n return MCPTransportType.STREAMABLE_HTTP;\n } catch (error) {\n if (options?.serviceName) {\n console.warn(\n `[MCP-${options.serviceName}] URL 解析失败,默认推断为 streamable-http 类型`,\n error\n );\n }\n return MCPTransportType.STREAMABLE_HTTP;\n }\n}\n\n/**\n * 完整的配置类型推断(包括 command 字段)\n *\n * @param config - MCP 服务配置\n * @returns 完整的配置对象,包含推断出的类型\n */\nexport function inferTransportTypeFromConfig(\n config: MCPServiceConfig\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: config.name,\n });\n return {\n ...config,\n type: inferredType,\n };\n }\n\n throw new Error(\n `无法为服务 ${config.name} 推断传输类型。请显式指定 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 * 将旧的配置格式转换为新的 MCPServiceConfig 格式,确保向后兼容性\n */\n\nimport { isAbsolute, resolve } from \"node:path\";\nimport type {\n LocalMCPServerConfig,\n MCPServerConfig,\n SSEMCPServerConfig,\n StreamableHTTPMCPServerConfig,\n} from \"@/lib/config/manager.js\";\nimport type { MCPServiceConfig } from \"@/lib/mcp/types\";\nimport { MCPTransportType } from \"@/lib/mcp/types\";\nimport { inferTransportTypeFromUrl } from \"@/lib/mcp/utils\";\nimport { TypeFieldNormalizer } from \"@utils/TypeFieldNormalizer.js\";\n\n/**\n * 配置验证错误类\n */\nexport class ConfigValidationError extends Error {\n constructor(\n message: string,\n public readonly configName?: string\n ) {\n super(message);\n this.name = \"ConfigValidationError\";\n }\n}\n\n/**\n * 将旧的 MCPServerConfig 转换为新的 MCPServiceConfig\n */\nexport function convertLegacyToNew(\n serviceName: string,\n legacyConfig: MCPServerConfig\n): MCPServiceConfig {\n console.log(\"转换配置\", { serviceName, legacyConfig });\n\n try {\n // 验证输入参数\n if (!serviceName || typeof serviceName !== \"string\") {\n throw new ConfigValidationError(\"服务名称必须是非空字符串\");\n }\n\n if (!legacyConfig || typeof legacyConfig !== \"object\") {\n throw new ConfigValidationError(\"配置对象不能为空\", serviceName);\n }\n\n // 首先标准化配置中的 type 字段\n const normalizedConfig = TypeFieldNormalizer.normalizeTypeField(\n legacyConfig\n ) as MCPServerConfig;\n\n // 根据配置类型进行转换\n const newConfig = convertByConfigType(serviceName, normalizedConfig);\n\n // 验证转换后的配置\n validateNewConfig(newConfig);\n\n console.log(\"配置转换成功\", { serviceName, type: newConfig.type });\n return newConfig;\n } catch (error) {\n console.error(\"配置转换失败\", { serviceName, error });\n throw error instanceof ConfigValidationError\n ? error\n : new ConfigValidationError(\n `配置转换失败: ${error instanceof Error ? error.message : String(error)}`,\n serviceName\n );\n }\n}\n\n/**\n * 根据配置类型进行转换\n */\nfunction convertByConfigType(\n serviceName: string,\n legacyConfig: MCPServerConfig\n): MCPServiceConfig {\n // 检查是否为本地 stdio 配置(最高优先级)\n if (isLocalConfig(legacyConfig)) {\n return convertLocalConfig(serviceName, legacyConfig);\n }\n\n // 检查是否有显式指定的类型\n if (\"type\" in legacyConfig) {\n switch (legacyConfig.type) {\n case \"sse\":\n return convertSSEConfig(serviceName, legacyConfig);\n case \"streamable-http\":\n return convertStreamableHTTPConfig(serviceName, legacyConfig);\n default:\n throw new ConfigValidationError(\n `不支持的传输类型: ${legacyConfig.type}`,\n serviceName\n );\n }\n }\n\n // 检查是否为网络配置(自动推断类型)\n if (\"url\" in legacyConfig) {\n // 如果 URL 是 undefined 或 null,抛出错误\n if (legacyConfig.url === undefined || legacyConfig.url === null) {\n throw new ConfigValidationError(\n \"网络配置必须包含有效的 url 字段\",\n serviceName\n );\n }\n\n // 先推断类型,然后根据推断的类型选择正确的转换函数\n const inferredType = inferTransportTypeFromUrl(legacyConfig.url || \"\");\n\n if (inferredType === MCPTransportType.SSE) {\n // 为SSE类型添加显式type字段\n const sseConfig = { ...legacyConfig, type: \"sse\" as const };\n return convertSSEConfig(serviceName, sseConfig);\n }\n // 为STREAMABLE_HTTP类型添加显式type字段\n const httpConfig = { ...legacyConfig, type: \"streamable-http\" as const };\n return convertStreamableHTTPConfig(serviceName, httpConfig);\n }\n\n throw new ConfigValidationError(\"无法识别的配置类型\", serviceName);\n}\n\n/** * 转换本地 stdio 配置 */\nfunction convertLocalConfig(\n serviceName: string,\n config: LocalMCPServerConfig\n): MCPServiceConfig {\n if (!config.command) {\n throw new ConfigValidationError(\n \"本地配置必须包含 command 字段\",\n serviceName\n );\n }\n\n // 获取用户的工作目录(优先使用环境变量,否则使用当前工作目录)\n const workingDir = process.env.XIAOZHI_CONFIG_DIR || process.cwd();\n\n // 解析 args 中的相对路径\n const resolvedArgs = (config.args || []).map((arg) => {\n // 检查是否为相对路径(以 ./ 开头或不以 / 开头且包含文件扩展名)\n if (isRelativePath(arg)) {\n const resolvedPath = resolve(workingDir, arg);\n console.log(\"解析相对路径\", { arg, resolvedPath });\n return resolvedPath;\n }\n return arg;\n });\n\n return {\n name: serviceName,\n type: MCPTransportType.STDIO,\n command: config.command,\n args: resolvedArgs,\n env: config.env, // 传递环境变量\n timeout: 30000,\n };\n}\n\n/**\n * 转换 SSE 配置\n */\nfunction convertSSEConfig(\n serviceName: string,\n config: SSEMCPServerConfig\n): MCPServiceConfig {\n if (config.url === undefined || config.url === null) {\n throw new ConfigValidationError(\"SSE 配置必须包含 url 字段\", serviceName);\n }\n\n // 优先使用显式指定的类型,如果没有则进行推断\n const inferredType =\n config.type === \"sse\"\n ? MCPTransportType.SSE\n : inferTransportTypeFromUrl(config.url || \"\");\n const isModelScope = config.url ? isModelScopeURL(config.url) : false;\n\n const baseConfig: MCPServiceConfig = {\n name: serviceName,\n type: inferredType,\n url: config.url,\n timeout: 30000,\n headers: config.headers,\n };\n\n // 如果是 ModelScope 服务,添加特殊配置\n if (isModelScope) {\n baseConfig.modelScopeAuth = true;\n }\n\n console.log(\"SSE配置转换\", {\n serviceName,\n url: config.url,\n inferredType,\n isModelScope,\n });\n\n return baseConfig;\n}\n\n/**\n * 转换 Streamable HTTP 配置\n */\nfunction convertStreamableHTTPConfig(\n serviceName: string,\n config: StreamableHTTPMCPServerConfig\n): MCPServiceConfig {\n // 检查 URL 是否存在\n if (config.url === undefined || config.url === null) {\n throw new ConfigValidationError(\n \"STREAMABLE_HTTP 配置必须包含 url 字段\",\n serviceName\n );\n }\n\n const url = config.url || \"\";\n\n return {\n name: serviceName,\n type: MCPTransportType.STREAMABLE_HTTP,\n url,\n timeout: 30000,\n headers: config.headers,\n };\n}\n\n/**\n * 批量转换配置\n */\nexport function convertLegacyConfigBatch(\n legacyConfigs: Record<string, MCPServerConfig>\n): Record<string, MCPServiceConfig> {\n const newConfigs: Record<string, MCPServiceConfig> = {};\n const errors: Array<{ serviceName: string; error: Error }> = [];\n\n for (const [serviceName, legacyConfig] of Object.entries(legacyConfigs)) {\n try {\n newConfigs[serviceName] = convertLegacyToNew(serviceName, legacyConfig);\n } catch (error) {\n errors.push({\n serviceName,\n error: error instanceof Error ? error : new Error(String(error)),\n });\n }\n }\n\n if (errors.length > 0) {\n const errorMessages = errors\n .map(({ serviceName, error }) => `${serviceName}: ${error.message}`)\n .join(\"; \");\n throw new ConfigValidationError(`批量配置转换失败: ${errorMessages}`);\n }\n\n 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 * 检查是否为 ModelScope URL\n */\nexport function isModelScopeURL(url: string): boolean {\n return url.includes(\"modelscope.net\") || url.includes(\"modelscope.cn\");\n}\n\n/**\n * 验证新配置格式\n */\nfunction validateNewConfig(config: MCPServiceConfig): void {\n if (!config.name || typeof config.name !== \"string\") {\n throw new ConfigValidationError(\"配置必须包含有效的 name 字段\");\n }\n\n if (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(即使是空字符串也会被推断为 STREAMABLE_HTTP)\n if (config.url === undefined || config.url === null) {\n throw new ConfigValidationError(\"SSE 配置必须包含 url 字段\");\n }\n break;\n\n case MCPTransportType.STREAMABLE_HTTP:\n // STREAMABLE_HTTP 配置允许空 URL,会在后续处理中设置默认值\n // 只有当 URL 完全不存在时才报错\n if (config.url === undefined || config.url === null) {\n throw new ConfigValidationError(\n \"STREAMABLE_HTTP 配置必须包含 url 字段\"\n );\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 // 检查是否为显式 streamable-http 配置\n if (\"type\" in config && config.type === \"streamable-http\") {\n return `Streamable 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 `Streamable HTTP (${config.url})`;\n }\n\n return \"未知类型\";\n}\n","import type { ToolCallResult } from \"@/lib/mcp/types.js\";\n\n// 定义接口避免循环依赖\ninterface IMCPServiceManager {\n getAllTools(): Array<{\n name: string;\n description: string;\n inputSchema: import(\"@/lib/mcp/types.js\").JSONSchema;\n serviceName?: string;\n originalName?: string;\n }>;\n callTool(\n toolName: string,\n arguments_: Record<string, unknown>\n ): Promise<ToolCallResult>;\n}\nimport {\n ToolCallError,\n ToolCallErrorCode,\n ensureToolJSONSchema,\n} from \"@/lib/mcp/types.js\";\nimport { validateToolCallParams } from \"@/lib/mcp/utils.js\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport type { MCPMessage } from \"@root/types/mcp.js\";\nimport { sliceEndpoint } from \"@utils/mcpServerUtils.js\";\nimport WebSocket from \"ws\";\nexport { ToolCallErrorCode, ToolCallError } from \"@/lib/mcp/types.js\";\n\n// 扩展的 MCP 消息接口,用于响应消息\ninterface ExtendedMCPMessage {\n jsonrpc: \"2.0\";\n id: string | number;\n result?: unknown;\n}\n\n// 连接状态枚举\nenum ConnectionState {\n DISCONNECTED = \"disconnected\",\n CONNECTING = \"connecting\",\n CONNECTED = \"connected\",\n FAILED = \"failed\",\n}\n\n// 服务器状态接口\ninterface EndpointConnectionStatus {\n connected: boolean;\n initialized: boolean;\n url: string;\n availableTools: number;\n connectionState: ConnectionState;\n lastError: string | null;\n}\n\nexport class EndpointConnection {\n private endpointUrl: string;\n private ws: WebSocket | null = null;\n private connectionStatus = false;\n private serverInitialized = false;\n private serviceManager: IMCPServiceManager | null = null;\n\n // 连接状态管理\n private connectionState: ConnectionState = ConnectionState.DISCONNECTED;\n\n // 最后一次错误信息\n private lastError: string | null = null;\n\n // 连接超时定时器\n private connectionTimeout: NodeJS.Timeout | null = null;\n\n // 工具调用超时配置\n private toolCallTimeout = 30000;\n private reconnectDelay = 2000; // 默认重连延迟 2000ms\n\n constructor(endpointUrl: string, reconnectDelay?: number) {\n this.endpointUrl = endpointUrl;\n if (reconnectDelay !== undefined) {\n this.reconnectDelay = reconnectDelay;\n }\n }\n\n /**\n * 设置 MCPServiceManager 实例\n * @param serviceManager MCPServiceManager 实例\n */\n setServiceManager(serviceManager: IMCPServiceManager): void {\n this.serviceManager = serviceManager;\n }\n\n /**\n * 获取当前所有工具列表\n * @returns 工具数组\n */\n getTools(): Tool[] {\n if (!this.serviceManager) {\n console.debug(\"MCPServiceManager 未设置,返回空工具列表\");\n return [];\n }\n\n try {\n // 直接从 MCPServiceManager 获取所有工具\n const allTools = this.serviceManager.getAllTools();\n\n // 转换为 Tool 格式\n return allTools.map((toolInfo) => ({\n name: toolInfo.name,\n description: toolInfo.description,\n inputSchema: ensureToolJSONSchema(toolInfo.inputSchema),\n }));\n } catch (error) {\n console.error(\n `获取工具列表失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return [];\n }\n }\n\n /**\n * 连接小智接入点\n * @returns 连接成功后的 Promise\n */\n public async connect(): Promise<void> {\n // 连接前验证\n if (!this.serviceManager) {\n throw new Error(\"MCPServiceManager 未设置。请在连接前先设置服务管理器。\");\n }\n\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 * @returns 连接成功后的 Promise\n */\n private async attemptConnection(): Promise<void> {\n this.connectionState = ConnectionState.CONNECTING;\n console.debug(`正在连接小智接入点: ${sliceEndpoint(this.endpointUrl)}`);\n\n return new Promise((resolve, reject) => {\n // 设置连接超时\n this.connectionTimeout = setTimeout(() => {\n const error = new Error(\"连接超时 (10000ms)\");\n this.handleConnectionError(error);\n reject(error);\n }, 10000);\n\n this.ws = new WebSocket(this.endpointUrl);\n\n this.ws.on(\"open\", () => {\n this.handleConnectionSuccess();\n resolve();\n });\n\n this.ws.on(\"message\", (data) => {\n try {\n const message: MCPMessage = JSON.parse(data.toString());\n this.handleMessage(message);\n } catch (error) {\n console.error(\"MCP 消息解析错误:\", error);\n }\n });\n\n this.ws.on(\"close\", (code, reason) => {\n this.handleConnectionClose(code, reason.toString());\n });\n\n this.ws.on(\"error\", (error) => {\n this.handleConnectionError(error);\n reject(error);\n });\n });\n }\n\n /**\n * 处理连接成功\n */\n private handleConnectionSuccess(): void {\n // 清理连接超时定时器\n if (this.connectionTimeout) {\n clearTimeout(this.connectionTimeout);\n this.connectionTimeout = null;\n }\n\n this.connectionStatus = true;\n this.connectionState = ConnectionState.CONNECTED;\n\n console.debug(\"MCP WebSocket 连接已建立\");\n }\n\n /**\n * 处理连接错误\n */\n private handleConnectionError(error: Error): void {\n // 记录最后一次错误信息\n this.lastError = error.message;\n\n // 清理连接超时定时器\n if (this.connectionTimeout) {\n clearTimeout(this.connectionTimeout);\n this.connectionTimeout = null;\n }\n\n console.error(\"MCP WebSocket 错误:\", error.message);\n\n // 清理当前连接\n this.cleanupConnection();\n }\n\n /**\n * 处理连接关闭\n */\n private handleConnectionClose(code: number, reason: string): void {\n this.connectionStatus = false;\n this.serverInitialized = false;\n this.connectionState = ConnectionState.DISCONNECTED;\n console.info(`小智连接已关闭 (代码: ${code}, 原因: ${reason})`);\n }\n\n /**\n * 清理连接资源\n */\n private cleanupConnection(): void {\n // 清理 WebSocket\n if (this.ws) {\n // 移除所有事件监听器,防止在关闭时触发错误事件\n this.ws.removeAllListeners();\n\n // 安全关闭 WebSocket\n try {\n if (this.ws.readyState === WebSocket.OPEN) {\n this.ws.close(1000, \"Cleaning up connection\");\n } else if (this.ws.readyState === WebSocket.CONNECTING) {\n this.ws.terminate(); // 强制终止正在连接的 WebSocket\n }\n } catch (error) {\n // 忽略关闭时的错误\n console.debug(\"WebSocket 关闭时出现错误(已忽略):\", error);\n }\n\n this.ws = null;\n }\n\n // 清理连接超时定时器\n if (this.connectionTimeout) {\n clearTimeout(this.connectionTimeout);\n this.connectionTimeout = null;\n }\n\n // 重置连接状态\n this.connectionStatus = false;\n this.serverInitialized = false;\n\n // 重置连接状态为已断开\n this.connectionState = ConnectionState.DISCONNECTED;\n }\n\n private handleMessage(message: MCPMessage): void {\n console.debug(\"收到 MCP 消息:\", JSON.stringify(message, null, 2));\n\n // 如果没有 method 字段,忽略该消息\n if (!message.method) {\n console.debug(\"收到没有 method 字段的消息,忽略\");\n return;\n }\n\n // 直接处理请求\n switch (message.method) {\n case \"initialize\":\n case \"notifications/initialized\":\n this.sendResponse(message.id, {\n protocolVersion: \"2024-11-05\",\n capabilities: {\n tools: { listChanged: true },\n logging: {},\n },\n serverInfo: {\n name: \"xiaozhi-mcp-server\",\n version: \"1.0.0\",\n },\n });\n this.serverInitialized = true;\n console.debug(\"MCP 服务器初始化完成\");\n break;\n\n case \"tools/list\": {\n const toolsList = this.getTools();\n this.sendResponse(message.id, { tools: toolsList });\n console.debug(`MCP 工具列表已发送 (${toolsList.length}个工具)`);\n break;\n }\n\n case \"tools/call\": {\n // 异步处理工具调用,避免阻塞其他消息\n this.handleToolCall(message).catch((error) => {\n console.error(\"处理工具调用时发生未捕获错误:\", error);\n });\n break;\n }\n\n case \"ping\":\n this.sendResponse(message.id, {});\n console.debug(\"回应 MCP ping 消息\");\n break;\n\n default:\n console.warn(`未知的 MCP 请求: ${message.method}`);\n }\n }\n\n private sendResponse(id: number | string, result: unknown): void {\n console.debug(\n `尝试发送响应: id=${id}, isConnected=${this.connectionStatus}, wsReadyState=${this.ws?.readyState}`\n );\n\n if (this.connectionStatus && this.ws?.readyState === WebSocket.OPEN) {\n const response: ExtendedMCPMessage = {\n jsonrpc: \"2.0\",\n id,\n result,\n };\n\n try {\n this.ws.send(JSON.stringify(response));\n console.debug(\"响应已发送\", {\n id,\n responseSize: JSON.stringify(response).length,\n });\n } catch (error) {\n console.error(\"发送响应失败\", {\n id,\n error,\n });\n }\n } else {\n console.error(\"无法发送响应\", {\n id,\n isConnected: this.connectionStatus,\n wsReadyState: this.ws?.readyState,\n wsReadyStateText:\n this.ws?.readyState === WebSocket.OPEN\n ? \"OPEN\"\n : this.ws?.readyState === WebSocket.CONNECTING\n ? \"CONNECTING\"\n : this.ws?.readyState === WebSocket.CLOSING\n ? \"CLOSING\"\n : this.ws?.readyState === WebSocket.CLOSED\n ? \"CLOSED\"\n : \"UNKNOWN\",\n });\n }\n }\n\n /**\n * 获取服务器状态\n * @returns 服务器状态\n */\n public getStatus(): EndpointConnectionStatus {\n // 从 MCPServiceManager 获取工具数量\n const availableTools = this.serviceManager\n ? this.serviceManager.getAllTools().length\n : 0;\n\n return {\n connected: this.connectionStatus,\n initialized: this.serverInitialized,\n url: this.endpointUrl,\n availableTools,\n connectionState: this.connectionState,\n lastError: this.lastError,\n };\n }\n\n /**\n * 检查连接状态\n * @returns 是否已连接\n */\n public isConnected(): boolean {\n return this.connectionStatus;\n }\n\n /**\n * 主动断开 小智连接\n */\n public disconnect(): void {\n console.info(\"主动断开 小智连接\");\n\n // 清理连接资源\n this.cleanupConnection();\n }\n\n /**\n * 重连小智接入点\n * @returns 重连成功后的 Promise\n */\n public async reconnect(): Promise<void> {\n console.info(`重连小智接入点: ${sliceEndpoint(this.endpointUrl)}`);\n\n // 检查服务管理器是否已设置\n if (!this.serviceManager) {\n throw new Error(\"MCPServiceManager 未设置。请在重连前先设置服务管理器。\");\n }\n\n // 先断开连接\n this.disconnect();\n\n // 等待可配置的时间确保连接完全断开\n await new Promise((resolve) => setTimeout(resolve, this.reconnectDelay));\n\n // 重新连接\n await this.connect();\n }\n\n /**\n * 处理工具调用请求\n */\n private async handleToolCall(request: MCPMessage): Promise<void> {\n // 确保 request.id 存在且类型正确\n if (request.id === undefined || request.id === null) {\n throw new ToolCallError(\n ToolCallErrorCode.INVALID_PARAMS,\n \"请求 ID 不能为空\"\n );\n }\n\n // 保持原始 ID 类型(number | string),不进行类型转换\n const requestId = request.id;\n // 记录开始时间用于计算持续时间\n const startTime = Date.now();\n\n try {\n // 1. 验证请求格式\n const params = validateToolCallParams(request.params);\n\n console.info(\"开始处理工具调用\", {\n requestId,\n toolName: params.name,\n hasArguments: !!params.arguments,\n });\n\n // 2. 检查服务管理器是否可用\n if (!this.serviceManager) {\n throw new ToolCallError(\n ToolCallErrorCode.SERVICE_UNAVAILABLE,\n \"MCPServiceManager 未设置\"\n );\n }\n\n // 3. 执行工具调用\n const result = await this.executeToolWithTimeout(\n params.name,\n params.arguments || {},\n this.toolCallTimeout\n );\n\n // 4. 发送成功响应\n this.sendResponse(requestId, {\n content: result.content || [\n { type: \"text\", text: JSON.stringify(result) },\n ],\n isError: result.isError || false,\n });\n\n // 5. 记录调用成功\n console.info(\"工具调用成功\", {\n requestId,\n toolName: params.name,\n duration: `${Date.now() - startTime}ms`,\n });\n } catch (error) {\n // 6. 处理错误并发送错误响应\n this.handleToolCallError(error, requestId, Date.now() - startTime);\n }\n }\n\n /**\n * 带超时控制的工具执行\n */\n private async executeToolWithTimeout(\n toolName: string,\n arguments_: Record<string, unknown>,\n timeoutMs = 30000\n ): Promise<ToolCallResult> {\n return new Promise((resolve, reject) => {\n // 设置超时定时器\n const timeoutId = setTimeout(() => {\n reject(\n new ToolCallError(\n ToolCallErrorCode.TIMEOUT,\n `工具调用超时 (${timeoutMs}ms): ${toolName}`\n )\n );\n }, timeoutMs);\n\n // 检查 serviceManager 是否可用\n if (!this.serviceManager) {\n clearTimeout(timeoutId);\n reject(\n new ToolCallError(\n ToolCallErrorCode.SERVICE_UNAVAILABLE,\n \"MCPServiceManager 未设置\"\n )\n );\n return;\n }\n\n // 执行工具调用\n this.serviceManager\n .callTool(toolName, arguments_)\n .then((result: ToolCallResult) => {\n clearTimeout(timeoutId);\n resolve(result);\n })\n .catch((error: unknown) => {\n clearTimeout(timeoutId);\n\n // 将内部错误转换为工具调用错误\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n\n if (errorMessage.includes(\"未找到工具\")) {\n reject(\n new ToolCallError(\n ToolCallErrorCode.TOOL_NOT_FOUND,\n `工具不存在: ${toolName}`\n )\n );\n } else if (\n errorMessage.includes(\"服务\") &&\n errorMessage.includes(\"不可用\")\n ) {\n reject(\n new ToolCallError(\n ToolCallErrorCode.SERVICE_UNAVAILABLE,\n errorMessage\n )\n );\n } else if (errorMessage.includes(\"暂时不可用\")) {\n // 标记为服务不可用错误\n reject(\n new ToolCallError(\n ToolCallErrorCode.SERVICE_UNAVAILABLE,\n errorMessage\n )\n );\n } else if (errorMessage.includes(\"持续不可用\")) {\n // 标记为服务不可用错误\n reject(\n new ToolCallError(\n ToolCallErrorCode.SERVICE_UNAVAILABLE,\n errorMessage\n )\n );\n } else {\n reject(\n new ToolCallError(\n ToolCallErrorCode.TOOL_EXECUTION_ERROR,\n `工具执行失败: ${errorMessage}`\n )\n );\n }\n });\n });\n }\n\n /**\n * 处理工具调用错误\n */\n private handleToolCallError(\n error: unknown,\n requestId: string | number | undefined,\n duration: number\n ): void {\n let errorResponse: {\n code: number;\n message: string;\n data?: unknown;\n };\n\n if (error instanceof ToolCallError) {\n // 标准工具调用错误\n errorResponse = {\n code: error.code,\n message: error.message,\n data: error.data,\n };\n } else {\n // 未知错误\n const errorMessage = error instanceof Error ? error.message : \"未知错误\";\n errorResponse = {\n code: ToolCallErrorCode.TOOL_EXECUTION_ERROR,\n message: errorMessage,\n data: { originalError: String(error) || \"null\" },\n };\n }\n\n // 发送错误响应\n this.sendErrorResponse(requestId, errorResponse);\n\n // 记录错误日志\n console.error(\"工具调用失败\", {\n requestId,\n duration: `${duration}ms`,\n error: errorResponse,\n });\n }\n\n /**\n * 发送错误响应\n */\n private sendErrorResponse(\n id: string | number | undefined,\n error: { code: number; message: string; data?: unknown }\n ): void {\n if (this.connectionStatus && this.ws?.readyState === WebSocket.OPEN) {\n const response = {\n jsonrpc: \"2.0\",\n id,\n error,\n };\n this.ws.send(JSON.stringify(response));\n console.debug(\"已发送错误响应:\", response);\n }\n }\n}\n","import { EventEmitter } from \"node:events\";\nimport type { ConfigManager } from \"@/lib/config/manager.js\";\nimport { ensureToolJSONSchema } from \"@/lib/mcp/types.js\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport type { ToolCallResult } from \"@root/types/mcp.js\";\nimport type { EventBus } from \"@services/EventBus.js\";\nimport { getEventBus } from \"@services/EventBus.js\";\nimport { sliceEndpoint } from \"@utils/mcpServerUtils.js\";\nimport { z } from \"zod\";\nimport { EndpointConnection } from \"./connection.js\";\n\n// 使用接口定义避免循环依赖\ninterface IMCPServiceManager {\n getAllTools(): Array<{\n name: string;\n description: string;\n inputSchema: import(\"@/lib/mcp/types.js\").JSONSchema;\n serviceName?: string;\n originalName?: string;\n }>;\n callTool(\n toolName: string,\n arguments_: Record<string, unknown>\n ): Promise<ToolCallResult>;\n}\n\n// 配置变更事件类型\nexport interface ConfigChangeEvent {\n type:\n | \"endpoints_added\"\n | \"endpoints_removed\"\n | \"endpoints_updated\"\n | \"options_updated\";\n data: {\n added?: string[];\n removed?: string[];\n updated?: string[];\n oldOptions?: Partial<IndependentConnectionOptions>;\n newOptions?: Partial<IndependentConnectionOptions>;\n };\n timestamp: Date;\n}\n\n// 错误类型枚举\n// 独立连接选项接口\nexport interface IndependentConnectionOptions {\n connectionTimeout?: number; // 连接超时时间(毫秒),默认 10000\n reconnectDelay?: number; // 重连延迟时间(毫秒),默认 2000\n}\n\n// 连接状态接口\nexport interface SimpleConnectionStatus {\n endpoint: string;\n connected: boolean;\n initialized: boolean;\n lastConnected?: Date;\n lastError?: string;\n}\n\n// 保持向后兼容的连接状态接口\nexport interface ConnectionStatus extends SimpleConnectionStatus {\n // 移除所有重连相关字段\n}\n\n// 连接状态枚举\nexport enum XiaozhiConnectionState {\n DISCONNECTED = \"disconnected\",\n CONNECTING = \"connecting\",\n CONNECTED = \"connected\",\n}\n\n// 默认配置\nconst DEFAULT_OPTIONS: Required<IndependentConnectionOptions> = {\n connectionTimeout: 10000,\n reconnectDelay: 2000,\n};\n\n// zod 验证 schema\nconst IndependentConnectionOptionsSchema = z\n .object({\n connectionTimeout: z\n .number()\n .min(1000, \"connectionTimeout 必须是大于等于 1000 的数字\")\n .optional(),\n reconnectDelay: z\n .number()\n .min(500, \"reconnectDelay 必须是大于等于 500 的数字\")\n .optional(),\n })\n .strict();\n\n/**\n * 小智接入点管理器\n * 负责管理多个小智接入点的连接,每个小智接入点独立运行\n */\nexport class EndpointManager extends EventEmitter {\n // 连接实例管理\n private connections: Map<string, EndpointConnection> = new Map();\n private connectionStates: Map<string, ConnectionStatus> = new Map();\n\n // 核心依赖\n private mcpServiceManager: IMCPServiceManager | null = null;\n private configManager: ConfigManager;\n private eventBus: EventBus;\n\n // 状态管理\n private isInitialized = false;\n private isConnecting = false;\n\n // 配置选项\n private options: Required<IndependentConnectionOptions>;\n\n constructor(\n configManager: ConfigManager,\n options?: IndependentConnectionOptions\n ) {\n super();\n this.configManager = configManager;\n this.eventBus = getEventBus();\n this.options = { ...DEFAULT_OPTIONS, ...options };\n\n console.debug(\"[EndpointManager] 实例已创建\");\n console.debug(\"[EndpointManager] 配置选项:\", this.options);\n }\n\n /**\n * 初始化连接管理器\n * @param endpoints 小智接入点列表\n * @param tools 工具列表\n */\n async initialize(endpoints: string[], tools: Tool[]): Promise<void> {\n if (this.isInitialized) return;\n\n console.debug(\n `开始初始化 EndpointManager,小智接入点数量: ${endpoints.length}`\n );\n\n try {\n // 验证输入参数\n this.validateInitializeParams(endpoints, tools);\n\n // 清理现有连接(如果有)\n await this.cleanup();\n\n // 为每个小智接入点创建连接实例\n for (const endpoint of endpoints) {\n await this.createConnection(endpoint, tools);\n }\n\n this.isInitialized = true;\n\n console.debug(\n `EndpointManager 初始化完成,管理 ${this.connections.size} 个连接`\n );\n } catch (error) {\n console.error(\"EndpointManager 初始化失败:\", error);\n await this.cleanup(); // 清理部分创建的连接\n throw error;\n }\n }\n\n /**\n * 连接所有小智接入点\n */\n async connect(): Promise<void> {\n if (!this.isInitialized) {\n throw new Error(\"EndpointManager 未初始化,请先调用 initialize()\");\n }\n\n if (this.isConnecting) return;\n\n this.isConnecting = true;\n console.debug(`开始连接所有小智接入点,总数: ${this.connections.size}`);\n\n try {\n const connectionPromises: Promise<void>[] = [];\n\n // 并发连接所有小智接入点\n for (const [endpoint, endpointConnection] of this.connections) {\n connectionPromises.push(\n this.connectSingleEndpoint(endpoint, endpointConnection)\n );\n }\n\n // 等待所有连接完成(允许部分失败)\n const results = await Promise.allSettled(connectionPromises);\n\n // 统计连接结果\n const successCount = results.filter(\n (result) => result.status === \"fulfilled\"\n ).length;\n\n // 如果所有连接都失败,抛出错误\n if (successCount === 0) {\n throw new Error(\"所有小智接入点连接失败\");\n }\n } finally {\n this.isConnecting = false;\n }\n }\n\n /**\n * 断开所有连接\n */\n async disconnect(): Promise<void> {\n console.debug(\"开始断开所有连接\");\n\n // 断开所有连接\n const disconnectPromises: Promise<void>[] = [];\n for (const [endpoint, endpointConnection] of this.connections) {\n disconnectPromises.push(\n this.disconnectSingleEndpoint(endpoint, endpointConnection)\n );\n }\n\n await Promise.allSettled(disconnectPromises);\n console.debug(\"所有小智接入点已断开连接\");\n }\n\n /**\n * 动态添加小智接入点\n * @param endpoint 小智接入点地址\n */\n async addEndpoint(endpoint: string): Promise<void> {\n if (!this.isInitialized) {\n throw new Error(\"EndpointManager 未初始化\");\n }\n\n // 检查连接管理器中的重复性\n if (this.connections.has(endpoint)) {\n console.debug(\n `小智接入点 ${sliceEndpoint(endpoint)} 已存在于连接管理器中,跳过添加`\n );\n return;\n }\n\n // 检查配置文件中的重复性\n if (this.checkConfigDuplicate(endpoint)) {\n throw new Error(`接入点 ${sliceEndpoint(endpoint)} 已存在于配置文件中`);\n }\n\n console.debug(`动态添加小智接入点: ${sliceEndpoint(endpoint)}`);\n\n try {\n // 先更新配置文件\n this.configManager.addMcpEndpoint(endpoint);\n\n try {\n // 获取当前工具列表\n const tools = this.getCurrentTools();\n\n // 创建新连接\n await this.createConnection(endpoint, tools);\n\n // 自动连接新添加的接入点\n const endpointConnection = this.connections.get(endpoint);\n if (!endpointConnection) {\n throw new Error(`无法获取接入点连接: ${endpoint}`);\n }\n await this.connectSingleEndpoint(endpoint, endpointConnection);\n\n console.info(`添加接入点成功: ${sliceEndpoint(endpoint)}`);\n } catch (error) {\n // 回滚配置文件更改\n try {\n this.configManager.removeMcpEndpoint(endpoint);\n console.debug(`配置文件回滚成功: ${sliceEndpoint(endpoint)}`);\n } catch (rollbackError) {\n console.error(\n `配置文件回滚失败: ${sliceEndpoint(endpoint)}`,\n rollbackError\n );\n }\n\n // 清理失败的连接\n this.connections.delete(endpoint);\n this.connectionStates.delete(endpoint);\n\n console.error(`添加小智接入点失败: ${sliceEndpoint(endpoint)}`, error);\n throw error;\n }\n } catch (error) {\n console.error(\n `添加小智接入点失败(配置文件操作): ${sliceEndpoint(endpoint)}`,\n error\n );\n throw error;\n }\n }\n\n /**\n * 动态移除小智接入点\n * @param endpoint 小智接入点地址\n */\n async removeEndpoint(endpoint: string): Promise<void> {\n if (!this.connections.has(endpoint)) {\n console.debug(\n `小智接入点 ${sliceEndpoint(endpoint)} 不存在于连接管理器中,跳过移除`\n );\n return;\n }\n\n console.debug(`动态移除小智接入点: ${sliceEndpoint(endpoint)}`);\n\n try {\n const endpointConnection = this.connections.get(endpoint);\n if (!endpointConnection) {\n throw new Error(`无法获取接入点连接: ${endpoint}`);\n }\n\n // 先更新配置文件\n this.configManager.removeMcpEndpoint(endpoint);\n\n try {\n // 断开连接\n await this.disconnectSingleEndpoint(endpoint, endpointConnection);\n\n // 清理资源\n this.connections.delete(endpoint);\n this.connectionStates.delete(endpoint);\n\n console.info(`移除小智接入点成功:${sliceEndpoint(endpoint)}`);\n } catch (error) {\n // 回滚配置文件更改\n try {\n this.configManager.addMcpEndpoint(endpoint);\n console.debug(`配置文件回滚成功: ${sliceEndpoint(endpoint)}`);\n } catch (rollbackError) {\n console.error(\n `配置文件回滚失败: ${sliceEndpoint(endpoint)}`,\n rollbackError\n );\n }\n\n console.error(`移除小智接入点失败: ${sliceEndpoint(endpoint)}`, error);\n throw error;\n }\n } catch (error) {\n console.error(\n `移除小智接入点失败(配置文件操作): ${sliceEndpoint(endpoint)}`,\n error\n );\n throw error;\n }\n }\n\n /**\n * 获取所有小智接入点\n */\n getEndpoints(): string[] {\n // 同时返回connections和connectionStates中的小智接入点\n const connectionEndpoints = Array.from(this.connections.keys());\n const stateEndpoints = Array.from(this.connectionStates.keys());\n return Array.from(new Set([...connectionEndpoints, ...stateEndpoints]));\n }\n\n /**\n * 断开指定小智接入点连接\n * @param endpoint 要断开的小智接入点\n */\n async disconnectEndpoint(endpoint: string): Promise<void> {\n const endpointConnection = this.connections.get(endpoint);\n if (!endpointConnection) {\n console.debug(`接入点不存在,跳过断开: ${sliceEndpoint(endpoint)}`);\n return;\n }\n\n console.info(`断开连接接入点: ${sliceEndpoint(endpoint)}`);\n\n try {\n await this.disconnectSingleEndpoint(endpoint, endpointConnection);\n } catch (error) {\n console.error(`断开连接接入点失败: ${sliceEndpoint(endpoint)}`, error);\n throw error;\n }\n }\n\n /**\n * 清除所有小智接入点\n */\n async clearEndpoints(): Promise<void> {\n console.debug(\"清除所有接入点\");\n\n // 断开所有连接\n const disconnectPromises = Array.from(this.connections.keys()).map(\n (endpoint) => this.removeEndpoint(endpoint)\n );\n await Promise.allSettled(disconnectPromises);\n\n console.info(\"所有接入点已清除\");\n }\n\n /**\n * 获取所有连接状态\n */\n getConnectionStatus(): ConnectionStatus[] {\n return Array.from(this.connectionStates.values());\n }\n\n /**\n * 检查是否有任何连接处于连接状态\n */\n isAnyConnected(): boolean {\n for (const status of this.connectionStates.values()) {\n if (status.connected) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * 检查指定端点是否已连接\n * @param endpoint 端点地址\n * @returns 是否已连接\n */\n isEndpointConnected(endpoint: string): boolean {\n const status = this.connectionStates.get(endpoint);\n return status?.connected ?? false;\n }\n\n /**\n * 获取指定端点的状态\n * @param endpoint 端点地址\n * @returns 端点状态\n */\n getEndpointStatus(endpoint: string): SimpleConnectionStatus | undefined {\n return this.connectionStates.get(endpoint);\n }\n\n /**\n * 设置 MCP 服务管理器\n * @param manager MCP 服务管理器实例\n */\n setServiceManager(manager: IMCPServiceManager): void {\n this.mcpServiceManager = manager;\n console.debug(\"已设置 MCPServiceManager\");\n }\n\n /**\n * 发射接入点状态变更事件\n */\n private emitEndpointStatusChanged(\n endpoint: string,\n connected: boolean,\n operation: \"connect\" | \"disconnect\" | \"reconnect\",\n success: boolean,\n message?: string,\n source = \"connection-manager\"\n ): void {\n this.eventBus.emitEvent(\"endpoint:status:changed\", {\n endpoint,\n connected,\n operation,\n success,\n message,\n timestamp: Date.now(),\n source,\n });\n }\n\n /**\n * 连接已存在的接入点(不创建新实例)\n * @param endpoint 要连接的接入点地址\n * @throws Error 如果接入点不存在或已连接\n */\n async connectExistingEndpoint(endpoint: string): Promise<void> {\n if (!this.isInitialized) {\n throw new Error(\"EndpointManager 未初始化\");\n }\n\n const endpointConnection = this.connections.get(endpoint);\n if (!endpointConnection) {\n throw new Error(\n `接入点 ${sliceEndpoint(endpoint)} 不存在,请先添加接入点`\n );\n }\n\n const currentState = this.connectionStates.get(endpoint);\n if (currentState?.connected) {\n console.debug(`接入点 ${sliceEndpoint(endpoint)} 已连接,跳过连接`);\n return;\n }\n\n console.info(`连接已存在的接入点: ${sliceEndpoint(endpoint)}`);\n await this.connectSingleEndpoint(endpoint, endpointConnection);\n }\n\n /**\n * 重连所有接入点\n * @returns 重连结果统计\n */\n async reconnectAll(): Promise<{\n successCount: number;\n failureCount: number;\n results: Array<{\n endpoint: string;\n success: boolean;\n error?: string;\n }>;\n }> {\n if (!this.isInitialized) {\n throw new Error(\"EndpointManager 未初始化,请先调用 initialize()\");\n }\n\n console.info(`开始重连所有接入点,总数: ${this.connections.size}`);\n\n const reconnectPromises: Promise<void>[] = [];\n const results: Array<{\n endpoint: string;\n success: boolean;\n error?: string;\n }> = [];\n\n // 并发重连所有接入点\n for (const [endpoint, endpointConnection] of this.connections) {\n const promise = this.reconnectSingleEndpoint(endpoint, endpointConnection)\n .then(() => {\n results.push({ endpoint, success: true });\n })\n .catch((error) => {\n results.push({\n endpoint,\n success: false,\n error: error instanceof Error ? error.message : String(error),\n });\n });\n\n reconnectPromises.push(promise);\n }\n\n // 等待所有重连完成\n await Promise.allSettled(reconnectPromises);\n\n // 统计结果\n const successCount = results.filter((r) => r.success).length;\n const failureCount = results.filter((r) => !r.success).length;\n\n console.info(`重连完成: 成功 ${successCount}, 失败 ${failureCount}`);\n\n // 如果有失败的,输出错误信息\n if (failureCount > 0) {\n const failures = results.filter((r) => !r.success);\n console.error(\"重连失败的接入点:\");\n for (const f of failures) {\n console.error(` - ${sliceEndpoint(f.endpoint)}: ${f.error}`);\n }\n }\n\n return {\n successCount,\n failureCount,\n results,\n };\n }\n\n /**\n * 重连指定的接入点\n * @param endpoint 要重连的接入点地址\n */\n async reconnectEndpoint(endpoint: string): Promise<void> {\n if (!this.isInitialized) {\n throw new Error(\"EndpointManager 未初始化\");\n }\n\n const endpointConnection = this.connections.get(endpoint);\n if (!endpointConnection) {\n throw new Error(\n `接入点 ${sliceEndpoint(endpoint)} 不存在,请先添加接入点`\n );\n }\n\n console.info(`重连接入点: ${sliceEndpoint(endpoint)}`);\n await this.reconnectSingleEndpoint(endpoint, endpointConnection);\n }\n\n /**\n * 等待指定时间(用于状态同步)\n * @param ms 等待时间(毫秒)\n */\n private async sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n /**\n * 验证小智接入点配置\n */\n private validateEndpoints(endpoints: string[]): {\n valid: string[];\n invalid: string[];\n } {\n const valid: string[] = [];\n const invalid: string[] = [];\n\n for (const endpoint of endpoints) {\n if (!endpoint || typeof endpoint !== \"string\") {\n invalid.push(endpoint);\n continue;\n }\n\n if (!endpoint.startsWith(\"ws://\") && !endpoint.startsWith(\"wss://\")) {\n invalid.push(endpoint);\n continue;\n }\n\n // 检查是否是有效的 URL\n try {\n new URL(endpoint);\n valid.push(endpoint);\n } catch {\n invalid.push(endpoint);\n }\n }\n\n return { valid, invalid };\n }\n\n /**\n * 验证连接选项 (使用 zod 实现)\n */\n private validateOptions(options: Partial<IndependentConnectionOptions>): {\n valid: boolean;\n errors: string[];\n } {\n const result = IndependentConnectionOptionsSchema.safeParse(options);\n\n if (result.success) {\n return { valid: true, errors: [] };\n }\n\n const errors = result.error.errors.map((err) => err.message);\n return { valid: false, errors };\n }\n\n /**\n * 更新小智接入点配置\n * @param newEndpoints 新的小智接入点列表\n * @param tools 工具列表\n */\n async updateEndpoints(\n newEndpoints: string[],\n tools: Tool[] = []\n ): Promise<void> {\n if (!this.isInitialized) {\n throw new Error(\"EndpointManager 未初始化\");\n }\n\n console.info(\n `更新小智接入点配置,新小智接入点数量: ${newEndpoints.length}`\n );\n\n // 验证新小智接入点\n const { valid: validEndpoints, invalid: invalidEndpoints } =\n this.validateEndpoints(newEndpoints);\n\n if (invalidEndpoints.length > 0) {\n console.warn(`发现无效小智接入点: ${invalidEndpoints.join(\", \")}`);\n }\n\n if (validEndpoints.length === 0) {\n throw new Error(\"没有有效的小智接入点\");\n }\n\n // 计算变更\n const currentEndpoints = Array.from(this.connections.keys());\n const toAdd = validEndpoints.filter((ep) => !currentEndpoints.includes(ep));\n const toRemove = currentEndpoints.filter(\n (ep) => !validEndpoints.includes(ep)\n );\n const toKeep = currentEndpoints.filter((ep) => validEndpoints.includes(ep));\n\n console.info(\n `小智接入点变更 - 添加: ${toAdd.length}, 移除: ${toRemove.length}, 保持: ${toKeep.length}`\n );\n\n try {\n // 移除不需要的小智接入点\n for (const endpoint of toRemove) {\n await this.removeEndpoint(endpoint);\n }\n\n // 添加新小智接入点\n for (const endpoint of toAdd) {\n await this.addEndpoint(endpoint);\n }\n\n // 发送配置变更事件\n const changeEvent: ConfigChangeEvent = {\n type:\n toAdd.length > 0 && toRemove.length > 0\n ? \"endpoints_updated\"\n : toAdd.length > 0\n ? \"endpoints_added\"\n : \"endpoints_removed\",\n data: {\n added: toAdd.length > 0 ? toAdd : undefined,\n removed: toRemove.length > 0 ? toRemove : undefined,\n updated:\n toAdd.length > 0 && toRemove.length > 0\n ? validEndpoints\n : undefined,\n },\n timestamp: new Date(),\n };\n\n this.emit(\"configChange\", changeEvent);\n console.info(\"小智接入点配置更新完成\");\n } catch (error) {\n console.error(\"小智接入点配置更新失败:\", error);\n throw error;\n }\n }\n\n /**\n * 更新连接选项\n * @param newOptions 新的连接选项\n */\n updateOptions(newOptions: Partial<IndependentConnectionOptions>): void {\n console.info(\"更新连接选项\");\n\n // 验证新选项\n const { valid, errors } = this.validateOptions(newOptions);\n\n if (!valid) {\n throw new Error(`无效的连接选项: ${errors.join(\", \")}`);\n }\n\n const oldOptions = { ...this.options };\n\n // 更新选项\n this.options = { ...this.options, ...newOptions };\n\n // 发送配置变更事件\n const changeEvent: ConfigChangeEvent = {\n type: \"options_updated\",\n data: {\n oldOptions,\n newOptions,\n },\n timestamp: new Date(),\n };\n\n this.emit(\"configChange\", changeEvent);\n console.info(\"连接选项更新完成\");\n console.debug(\"新的配置选项:\", this.options);\n }\n\n /**\n * 获取当前配置\n */\n getCurrentConfig(): {\n endpoints: string[];\n options: Required<IndependentConnectionOptions>;\n } {\n return {\n endpoints: Array.from(this.connections.keys()),\n options: { ...this.options },\n };\n }\n\n /**\n * 热重载配置\n * @param config 新配置\n */\n async reloadConfig(config: {\n endpoints?: string[];\n options?: Partial<IndependentConnectionOptions>;\n tools?: Tool[];\n }): Promise<void> {\n console.info(\"开始热重载配置\");\n\n try {\n // 更新选项(如果提供)\n if (config.options) {\n this.updateOptions(config.options);\n }\n\n // 更新小智接入点(如果提供)\n if (config.endpoints) {\n await this.updateEndpoints(config.endpoints, config.tools || []);\n }\n\n console.info(\"配置热重载完成\");\n } catch (error) {\n console.error(\"配置热重载失败:\", error);\n throw error;\n }\n }\n\n /**\n * 连接预热机制\n * @param endpoints 要预热的小智接入点列表\n */\n async prewarmConnections(endpoints: string[] = []): Promise<void> {\n const targetEndpoints =\n endpoints.length > 0 ? endpoints : Array.from(this.connections.keys());\n\n console.info(`开始预热连接,小智接入点数量: ${targetEndpoints.length}`);\n\n const prewarmPromises = targetEndpoints.map(async (endpoint) => {\n try {\n const connection = this.connections.get(endpoint);\n if (connection) {\n // 执行预热操作(例如建立连接、验证状态等)\n console.debug(`小智接入点 ${sliceEndpoint(endpoint)} 预热完成`);\n }\n } catch (error) {\n console.warn(`小智接入点 ${sliceEndpoint(endpoint)} 预热失败:`, error);\n }\n });\n\n await Promise.all(prewarmPromises);\n console.info(\"连接预热完成\");\n }\n\n /**\n * 资源清理\n */\n async cleanup(): Promise<void> {\n console.debug(\"开始清理 EndpointManager 资源\");\n\n try {\n // 断开所有连接\n await this.disconnect();\n\n // 清理连接实例\n this.connections.clear();\n this.connectionStates.clear();\n\n // 重置状态\n this.isInitialized = false;\n this.isConnecting = false;\n\n console.debug(\"EndpointManager 资源清理完成\");\n } catch (error) {\n console.error(\"EndpointManager 资源清理失败:\", error);\n throw error;\n }\n }\n\n // ==================== 私有方法 ====================\n\n /**\n * 检查配置文件中的重复接入点\n * @param endpoint 要检查的接入点地址\n * @returns 如果接入点已存在于配置文件中,返回 true\n */\n private checkConfigDuplicate(endpoint: string): boolean {\n try {\n const configEndpoints = this.configManager.getMcpEndpoints();\n return configEndpoints.includes(endpoint);\n } catch (error) {\n console.error(`检查配置文件重复性失败: ${error}`);\n // 如果配置文件读取失败,保守起见认为接入点已存在\n return true;\n }\n }\n\n /**\n * 验证初始化参数\n */\n private validateInitializeParams(endpoints: string[], tools: Tool[]): void {\n if (!Array.isArray(endpoints)) {\n throw new Error(\"小智接入点列表必须是数组\");\n }\n\n if (!Array.isArray(tools)) {\n throw new Error(\"工具列表必须是数组\");\n }\n\n // 验证小智接入点格式\n for (const endpoint of endpoints) {\n if (!endpoint || typeof endpoint !== \"string\") {\n throw new Error(`无效的小智接入点地址: ${endpoint}`);\n }\n\n if (!endpoint.startsWith(\"ws://\") && !endpoint.startsWith(\"wss://\")) {\n throw new Error(`小智接入点地址必须是 WebSocket URL: ${endpoint}`);\n }\n }\n }\n\n /**\n * 创建单个连接\n */\n private async createConnection(\n endpoint: string,\n tools: Tool[]\n ): Promise<void> {\n console.debug(`创建连接实例: ${sliceEndpoint(endpoint)}`);\n\n try {\n // 创建 EndpointConnection 实例,传递重连延迟配置\n const endpointConnection = new EndpointConnection(\n endpoint,\n this.options.reconnectDelay\n );\n\n // 设置 MCP 服务管理器\n if (this.mcpServiceManager) {\n endpointConnection.setServiceManager(this.mcpServiceManager);\n }\n\n // 存储连接实例\n this.connections.set(endpoint, endpointConnection);\n\n // 初始化连接状态\n this.connectionStates.set(endpoint, {\n endpoint,\n connected: false,\n initialized: false,\n });\n\n console.debug(`连接实例创建成功: ${sliceEndpoint(endpoint)}`);\n } catch (error) {\n console.error(`创建连接实例失败 ${sliceEndpoint(endpoint)}:`, error);\n throw error;\n }\n }\n\n /**\n * 连接单个小智接入点\n */\n private async connectSingleEndpoint(\n endpoint: string,\n endpointConnection: EndpointConnection\n ): Promise<void> {\n const status = this.connectionStates.get(endpoint);\n if (!status) {\n throw new Error(`小智接入点状态不存在: ${sliceEndpoint(endpoint)}`);\n }\n\n console.debug(`连接小智接入点: ${sliceEndpoint(endpoint)}`);\n\n try {\n // 更新状态为连接中\n status.connected = false;\n status.initialized = false;\n\n // 执行连接\n await endpointConnection.connect();\n\n // 更新连接成功状态\n status.connected = true;\n status.initialized = true;\n status.lastConnected = new Date();\n status.lastError = undefined;\n\n // 发射连接成功事件\n this.emitEndpointStatusChanged(\n endpoint,\n true,\n \"connect\",\n true,\n \"接入点连接成功\",\n \"connection-manager\"\n );\n\n console.info(`小智接入点连接成功: ${sliceEndpoint(endpoint)}`);\n } catch (error) {\n // 更新连接失败状态\n status.connected = false;\n status.initialized = false;\n status.lastError = error instanceof Error ? error.message : String(error);\n\n // 发射连接失败事件\n this.emitEndpointStatusChanged(\n endpoint,\n false,\n \"connect\",\n false,\n error instanceof Error ? error.message : \"连接失败\",\n \"connection-manager\"\n );\n\n console.error(`连接失败 ${sliceEndpoint(endpoint)}:`, error);\n\n // 直接抛出错误,不再重连\n throw error;\n }\n }\n\n /**\n * 断开单个小智接入点\n */\n private async disconnectSingleEndpoint(\n endpoint: string,\n endpointConnection: EndpointConnection\n ): Promise<void> {\n const status = this.connectionStates.get(endpoint);\n if (!status) {\n return;\n }\n\n console.debug(`断开小智接入点: ${sliceEndpoint(endpoint)}`);\n\n try {\n // 执行断开连接(EndpointConnection.disconnect 是同步方法)\n endpointConnection.disconnect();\n\n // 更新状态\n status.connected = false;\n status.initialized = false;\n\n // 发射断开连接成功事件\n this.emitEndpointStatusChanged(\n endpoint,\n false,\n \"disconnect\",\n true,\n \"接入点断开成功\",\n \"connection-manager\"\n );\n\n console.debug(`小智接入点断开成功: ${sliceEndpoint(endpoint)}`);\n } catch (error) {\n console.error(`小智接入点断开失败 ${sliceEndpoint(endpoint)}:`, error);\n // 即使断开失败,也要更新状态\n status.connected = false;\n status.initialized = false;\n\n // 发射断开连接失败事件\n this.emitEndpointStatusChanged(\n endpoint,\n false,\n \"disconnect\",\n false,\n error instanceof Error ? error.message : \"断开失败\",\n \"connection-manager\"\n );\n }\n }\n\n /**\n * 重连单个小智接入点\n */\n private async reconnectSingleEndpoint(\n endpoint: string,\n endpointConnection: EndpointConnection\n ): Promise<void> {\n const status = this.connectionStates.get(endpoint);\n if (!status) {\n throw new Error(`小智接入点状态不存在: ${sliceEndpoint(endpoint)}`);\n }\n\n console.debug(`重连小智接入点: ${sliceEndpoint(endpoint)}`);\n\n try {\n // 执行重连\n await endpointConnection.reconnect();\n\n // 更新连接成功状态\n status.connected = true;\n status.initialized = true;\n status.lastConnected = new Date();\n status.lastError = undefined;\n\n // 发射重连成功事件\n this.emitEndpointStatusChanged(\n endpoint,\n true,\n \"reconnect\",\n true,\n \"接入点重连成功\",\n \"connection-manager\"\n );\n\n console.info(`小智接入点重连成功: ${sliceEndpoint(endpoint)}`);\n } catch (error) {\n // 更新连接失败状态\n status.connected = false;\n status.initialized = false;\n status.lastError = error instanceof Error ? error.message : String(error);\n\n // 发射重连失败事件\n this.emitEndpointStatusChanged(\n endpoint,\n false,\n \"reconnect\",\n false,\n error instanceof Error ? error.message : \"重连失败\",\n \"connection-manager\"\n );\n\n console.error(`重连失败 ${sliceEndpoint(endpoint)}:`, error);\n throw error;\n }\n }\n\n /**\n * 获取当前工具列表\n */\n private getCurrentTools(): Tool[] {\n if (!this.mcpServiceManager) {\n return [];\n }\n\n try {\n const rawTools = this.mcpServiceManager.getAllTools();\n // 转换工具格式以符合 MCP SDK 的 Tool 类型\n return rawTools.map((tool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: ensureToolJSONSchema(tool.inputSchema),\n }));\n } catch (error) {\n console.error(\"获取工具列表失败:\", error);\n return [];\n }\n }\n}\n","/**\n * 小智接入点连接管理模块\n *\n * 此模块负责管理小智接入点的连接,包括:\n * - EndpointConnection: 单个 WebSocket 连接实现\n * - EndpointManager: 多个连接的管理器\n */\n\n// 核心类导出\nexport { EndpointConnection } from \"./connection.js\";\nexport { EndpointManager } from \"./manager.js\";\n\n// 类型导出\nexport type {\n IndependentConnectionOptions,\n SimpleConnectionStatus,\n ConnectionStatus,\n ConfigChangeEvent as EndpointConfigChangeEvent,\n} from \"./manager.js\";\n\n// 枚举导出\nexport { XiaozhiConnectionState } from \"./manager.js\";\n\n// EndpointConnection 相关导出\nexport { ToolCallErrorCode, ToolCallError } from \"./connection.js\";\n","export default {\n zh: {\n COZE_BASE_URL: \"https://api.coze.cn\",\n COZE_BASE_WS_URL: \"wss://ws.coze.cn\",\n },\n en: {\n COZE_BASE_URL: \"https://api.coze.com\",\n COZE_BASE_WS_URL: \"wss://ws.coze.com\",\n },\n};\n","/**\n * 扣子 API 客户端封装\n * 提供统一的客户端创建和配置\n */\n\nimport { CozeAPI } from \"@/lib/coze\";\nimport config from \"./config\";\n\nexport type Language = \"zh\" | \"en\";\n\n/**\n * 创建 Coze API 客户端\n * @param token - API 访问令牌\n * @param language - API 环境语言,默认为 \"zh\"(中文),可选 \"en\"(英文)\n */\nexport function createCozeClient(\n token: string,\n language: Language = \"zh\"\n): CozeAPI {\n if (!token || typeof token !== \"string\" || token.trim() === \"\") {\n throw new Error(\"扣子 API Token 不能为空\");\n }\n\n const env = config[language] || config.zh;\n\n return new CozeAPI({\n baseURL: env.COZE_BASE_URL,\n token: token.trim(),\n baseWsURL: env.COZE_BASE_WS_URL,\n debug: false,\n });\n}\n","/**\n * 扣子 API 服务类\n * 负责与扣子 API 的交互,包括工作空间和工作流的获取\n */\n\nimport type { RunWorkflowData, WorkSpace } from \"@/lib/coze\";\nimport type {\n CozeWorkflowsData,\n CozeWorkflowsParams,\n CozeWorkflowsResponse,\n} from \"@root/types/coze\";\nimport NodeCache from \"node-cache\";\nimport { createCozeClient } from \"./client\";\n\n/**\n * 扣子 API 服务类\n */\nexport class CozeApiService {\n private cache: NodeCache;\n private token: string; // 保留 token 字段用于可能的后续扩展(如 token 刷新)\n private client: ReturnType<typeof createCozeClient>;\n\n constructor(token: string) {\n this.token = token.trim();\n this.client = createCozeClient(this.token);\n\n // 初始化缓存\n this.cache = new NodeCache({\n stdTTL: 5 * 60, // 默认5分钟(工作流缓存使用此默认值)\n });\n }\n\n /**\n * 获取工作空间列表\n */\n async getWorkspaces(): Promise<WorkSpace[]> {\n const cacheKey = \"workspaces\";\n const cached = this.cache.get<WorkSpace[]>(cacheKey);\n if (cached) return cached;\n\n const { workspaces = [] } = await this.client.workspaces.list();\n\n // 设置缓存,过期时间30分钟\n this.cache.set(cacheKey, workspaces, 30 * 60);\n\n return workspaces;\n }\n\n /**\n * 获取工作流列表\n */\n async getWorkflows(params: CozeWorkflowsParams): Promise<CozeWorkflowsData> {\n const { workspace_id, page_num = 1, page_size = 20 } = params;\n\n if (!workspace_id || typeof workspace_id !== \"string\") {\n throw new Error(\"工作空间ID不能为空\");\n }\n\n const cacheKey = `workflows:${workspace_id}:${page_num}:${page_size}`;\n const cached = this.cache.get<CozeWorkflowsData>(cacheKey);\n if (cached) return cached;\n\n const response = await this.client.get<\n CozeWorkflowsParams,\n CozeWorkflowsResponse\n >(\"/v1/workflows\", {\n workspace_id,\n page_num: page_num,\n page_size: page_size,\n workflow_mode: \"workflow\",\n });\n\n const result = response.data;\n\n // 设置缓存,使用默认的5分钟过期时间\n this.cache.set(cacheKey, result);\n\n return result;\n }\n\n /**\n * 运行工作流\n * @param workflowId - 工作流ID\n * @param parameters - 参数\n * @returns 运行工作流数据\n */\n callWorkflow(\n workflowId: string,\n parameters: Record<string, unknown>\n ): Promise<RunWorkflowData> {\n return this.client.workflows.runs.create({\n workflow_id: workflowId,\n parameters,\n });\n }\n\n /**\n * 清除缓存\n * @param pattern 可选的模式字符串,清除所有以该模式开头的缓存键\n */\n clearCache(pattern?: string): void {\n if (!pattern) {\n // 清除所有缓存\n this.cache.flushAll();\n return;\n }\n\n // node-cache 不支持模式匹配,需要手动实现\n // 使用前缀匹配,避免意外匹配\n const keys = this.cache.keys();\n const keysToDelete = keys.filter((key) => key.startsWith(pattern));\n this.cache.del(keysToDelete);\n }\n\n /**\n * 获取缓存统计信息\n */\n getCacheStats(): {\n size: number;\n keys: string[];\n hits: number;\n misses: number;\n hitRate: number;\n ksize: number;\n vsize: number;\n } {\n const stats = this.cache.getStats();\n const keys = this.cache.keys();\n const totalRequests = stats.hits + stats.misses;\n const hitRate = totalRequests > 0 ? stats.hits / totalRequests : 0;\n\n return {\n size: stats.keys,\n keys,\n hits: stats.hits,\n misses: stats.misses,\n hitRate,\n ksize: stats.ksize,\n vsize: stats.vsize,\n };\n }\n}\n","export { default as config } from \"./config\";\nexport * from \"@coze/api\";\nexport { createCozeClient } from \"./client\";\nexport { CozeApiService } from \"./service\";\n","/**\n * MCP 相关类型定义\n */\n\nimport { createHash } from \"node:crypto\";\nimport type { MCPToolsCache } from \"@/lib/mcp\";\nimport type { TimeoutResponse } from \"./timeout.js\";\n\n// 工具调用结果接口(与 MCPServiceManager 保持一致)\nexport interface ToolCallResult {\n content: Array<{\n type: string;\n text: string;\n }>;\n isError?: boolean;\n}\n\n// MCP 消息接口 - 定义 JSON-RPC 2.0 标准消息格式\nexport interface MCPMessage {\n jsonrpc: \"2.0\";\n method: string;\n params?: unknown;\n id: string | number;\n}\n\n// MCP 响应接口 - 定义 JSON-RPC 2.0 标准响应格式\nexport interface MCPResponse {\n jsonrpc: \"2.0\";\n id: string | number;\n result?: unknown;\n error?: MCPError;\n}\n\n// MCP 错误接口 - 定义 JSON-RPC 2.0 标准错误格式\nexport interface MCPError {\n code: number;\n message: string;\n data?: unknown;\n}\n\n/**\n * 扩展的 MCP 工具缓存接口\n * 增加对 CustomMCP 执行结果的支持\n */\nexport interface ExtendedMCPToolsCache extends MCPToolsCache {\n customMCPResults?: Record<string, EnhancedToolResultCache>; // 增强的工具执行结果缓存\n}\n\n/**\n * 增强的工具执行结果缓存\n * 用于存储 CustomMCP 工具的执行结果和状态\n */\nexport interface EnhancedToolResultCache {\n result: ToolCallResult;\n timestamp: string; // ISO 8601 格式时间戳\n ttl: number; // 过期时间(毫秒)\n status: TaskStatus; // 任务状态\n consumed: boolean; // 是否已被消费(一次性缓存机制)\n taskId?: string; // 任务ID,用于查询\n retryCount: number; // 重试次数\n}\n\n/**\n * 任务状态类型\n */\nexport type TaskStatus =\n | \"pending\"\n | \"completed\"\n | \"failed\"\n | \"consumed\"\n | \"deleted\";\n\n/**\n * 缓存状态转换接口\n */\nexport interface CacheStateTransition {\n from: TaskStatus;\n to: TaskStatus;\n reason: string;\n timestamp: string;\n}\n\n/**\n * 工具调用选项\n */\nexport interface ToolCallOptions {\n timeout?: number; // 超时时间(毫秒)\n retries?: number; // 重试次数\n retryDelay?: number; // 重试延迟(毫秒)\n enableCache?: boolean; // 是否启用缓存\n taskId?: string; // 任务ID\n}\n\n/**\n * 缓存配置选项\n */\nexport interface CacheConfig {\n ttl?: number; // 缓存过期时间(毫秒),默认5分钟\n cleanupInterval?: number; // 清理间隔(毫秒),默认1分钟\n maxCacheSize?: number; // 最大缓存条目数\n enableOneTimeCache?: boolean; // 是否启用一次性缓存\n}\n\n/**\n * 超时配置选项\n */\nexport interface TimeoutConfig {\n timeout?: number; // 超时时间(毫秒),默认8秒\n enableFriendlyTimeout?: boolean; // 是否启用友好超时响应\n backgroundProcessing?: boolean; // 是否启用后台处理\n}\n\n/**\n * 任务信息接口\n */\nexport interface TaskInfo {\n taskId: string;\n toolName: string;\n arguments: Record<string, unknown>;\n status: TaskStatus;\n startTime: string;\n endTime?: string;\n error?: string;\n result?: ToolCallResult;\n}\n\n/**\n * 缓存统计信息\n */\nexport interface CacheStatistics {\n totalEntries: number;\n pendingTasks: number;\n completedTasks: number;\n failedTasks: number;\n consumedEntries: number;\n cacheHitRate: number;\n lastCleanupTime: string;\n memoryUsage: number;\n}\n\n/**\n * 工具调用结果联合类型\n * 包含正常结果和超时响应\n */\nexport type ToolCallResponse = ToolCallResult | TimeoutResponse;\n\n/**\n * 验证是否为工具调用结果\n */\nexport function isToolCallResult(\n response: unknown\n): response is ToolCallResult {\n return (\n !!response &&\n typeof response === \"object\" &&\n response !== null &&\n \"content\" in response &&\n Array.isArray((response as ToolCallResult).content) &&\n (response as ToolCallResult).content.length > 0 &&\n (response as ToolCallResult).content[0]?.type === \"text\" &&\n typeof (response as ToolCallResult).content[0]?.text === \"string\"\n );\n}\n\n/**\n * 验证是否为增强的工具结果缓存\n */\nexport function isEnhancedToolResultCache(\n cache: unknown\n): cache is EnhancedToolResultCache {\n const cacheObj = cache as EnhancedToolResultCache;\n return (\n !!cache &&\n typeof cache === \"object\" &&\n cache !== null &&\n typeof cacheObj.timestamp === \"string\" &&\n typeof cacheObj.ttl === \"number\" &&\n typeof cacheObj.status === \"string\" &&\n [\"completed\", \"pending\", \"failed\", \"consumed\"].includes(cacheObj.status) &&\n typeof cacheObj.consumed === \"boolean\" &&\n typeof cacheObj.retryCount === \"number\"\n );\n}\n\n/**\n * 验证是否为扩展的 MCP 工具缓存\n */\nexport function isExtendedMCPToolsCache(\n cache: unknown\n): cache is ExtendedMCPToolsCache {\n const cacheObj = cache as ExtendedMCPToolsCache;\n return (\n !!cache &&\n typeof cache === \"object\" &&\n cache !== null &&\n typeof cacheObj.version === \"string\" &&\n typeof cacheObj.mcpServers === \"object\" &&\n cacheObj.mcpServers !== null &&\n typeof cacheObj.metadata === \"object\" &&\n cacheObj.metadata !== null\n );\n}\n\n/**\n * 生成缓存键的工具函数\n */\nexport function generateCacheKey(\n toolName: string,\n arguments_: Record<string, unknown>\n): string {\n const argsHash = createHash(\"md5\")\n .update(JSON.stringify(arguments_ || {}))\n .digest(\"hex\");\n return `${toolName}_${argsHash}`;\n}\n\n/**\n * 格式化时间戳的工具函数\n */\nexport function formatTimestamp(timestamp: number | Date = Date.now()): string {\n return new Date(timestamp).toISOString();\n}\n\n/**\n * 检查缓存是否过期\n */\nexport function isCacheExpired(timestamp: string, ttl: number): boolean {\n const cachedTime = new Date(timestamp).getTime();\n const now = Date.now();\n return now - cachedTime > ttl;\n}\n\n/**\n * 检查是否应该清理缓存条目\n */\nexport function shouldCleanupCache(cache: EnhancedToolResultCache): boolean {\n const now = Date.now();\n const cachedTime = new Date(cache.timestamp).getTime();\n\n // 已消费且超过清理时间(1分钟)\n if (cache.consumed && now - cachedTime > 60000) {\n return true;\n }\n\n // 已过期\n if (now - cachedTime > cache.ttl) {\n return true;\n }\n\n // 失败的任务立即清理\n if (cache.status === \"failed\") {\n return true;\n }\n\n return false;\n}\n\n/**\n * 默认配置常量\n */\nexport const DEFAULT_CONFIG = {\n TIMEOUT: 8000, // 8秒超时\n CACHE_TTL: 300000, // 5分钟缓存\n CLEANUP_INTERVAL: 60000, // 1分钟清理间隔\n MAX_CACHE_SIZE: 1000, // 最大缓存条目数\n ENABLE_ONE_TIME_CACHE: true, // 启用一次性缓存\n} as const;\n","/**\n * 超时错误类型\n */\nexport class TimeoutError extends Error {\n public override readonly name = \"TimeoutError\" as const;\n\n constructor(message: string) {\n super(message);\n this.name = \"TimeoutError\";\n Error.captureStackTrace(this, TimeoutError);\n }\n\n toJSON() {\n return {\n name: this.name,\n message: this.message,\n stack: this.stack,\n };\n }\n}\n\n/**\n * 超时响应接口\n */\nexport interface TimeoutResponse {\n content: Array<{\n type: \"text\";\n text: string;\n }>;\n isError: boolean;\n taskId: string;\n status: \"timeout\";\n message: string;\n nextAction: string;\n}\n\n/**\n * 创建超时响应的工具函数\n */\nexport function createTimeoutResponse(\n taskId: string,\n toolName?: string\n): TimeoutResponse {\n const toolSpecificMessage = toolName\n ? getToolSpecificTimeoutMessage(toolName, taskId)\n : getDefaultTimeoutMessage(taskId);\n\n return {\n content: [\n {\n type: \"text\",\n text: toolSpecificMessage,\n },\n ],\n isError: false,\n taskId,\n status: \"timeout\",\n message: \"工具调用超时,正在后台处理中\",\n nextAction: \"请稍后重试或等待任务完成\",\n };\n}\n\n/**\n * 获取工具特定的超时提示信息\n */\nfunction getToolSpecificTimeoutMessage(\n toolName: string,\n taskId: string\n): string {\n const toolMessages: Record<string, string> = {\n coze_workflow: `⏱️ 扣子工作流执行超时,正在后台处理中...\n \n📋 任务信息:\n- 任务ID: ${taskId}\n- 工具类型: 扣子工作流\n- 状态: 处理中\n- 建议: 请等待30-60秒后重试查询\n\n🔄 后续操作:\n1. 使用相同参数重新调用工具\n2. 系统会自动返回已完成的任务结果\n3. 复杂工作流可能需要更长时间处理`,\n\n default: getDefaultTimeoutMessage(taskId),\n };\n\n return toolMessages[toolName] || toolMessages.default;\n}\n\n/**\n * 获取默认超时提示信息\n */\nfunction getDefaultTimeoutMessage(taskId: string): string {\n return `⏱️ 工具调用超时,正在后台处理中...\n \n📋 任务信息:\n- 任务ID: ${taskId}\n- 状态: 处理中\n- 建议: 请等待30秒后重试查询\n\n🔄 后续操作:\n1. 使用相同的参数重新调用工具\n2. 系统会自动返回已完成的任务结果\n3. 如果长时间未完成,请联系管理员`;\n}\n\n/**\n * 验证是否为超时响应\n */\nexport function isTimeoutResponse(response: any): response is TimeoutResponse {\n return !!(\n response &&\n response.status === \"timeout\" &&\n typeof response.taskId === \"string\" &&\n Array.isArray(response.content) &&\n response.content.length > 0 &&\n response.content[0].type === \"text\"\n );\n}\n\n/**\n * 验证是否为超时错误\n */\nexport function isTimeoutError(error: any): error is TimeoutError {\n return !!(\n error &&\n error.name === \"TimeoutError\" &&\n error instanceof TimeoutError\n );\n}\n","#!/usr/bin/env node\nimport type {\n CustomMCPTool,\n HandlerConfig,\n ProxyHandlerConfig,\n} from \"@/lib/config/manager.js\";\nimport { configManager } from \"@/lib/config/manager.js\";\nimport { CozeApiService } from \"@/lib/coze\";\nimport type { RunWorkflowData } from \"@/lib/coze\";\nimport type { MCPServiceManager } from \"@/lib/mcp\";\nimport { MCPCacheManager } from \"@/lib/mcp\";\nimport { ensureToolJSONSchema } from \"@/lib/mcp/types.js\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport type { Logger } from \"@root/Logger.js\";\nimport { logger } from \"@root/Logger.js\";\nimport { getEventBus } from \"@root/services/EventBus.js\";\nimport type {\n EnhancedToolResultCache,\n ExtendedMCPToolsCache,\n ToolCallResponse,\n ToolCallResult,\n} from \"@root/types/mcp.js\";\nimport {\n DEFAULT_CONFIG,\n generateCacheKey,\n isCacheExpired,\n shouldCleanupCache,\n} from \"@root/types/mcp.js\";\nimport { TimeoutError, createTimeoutResponse } from \"@root/types/timeout.js\";\n\n// 工具调用参数类型\ntype ToolArguments = Record<string, unknown>;\n\n// 类型守卫函数:检查是否为代理处理器\nfunction isProxyHandler(handler: HandlerConfig): handler is ProxyHandlerConfig {\n return handler.type === \"proxy\";\n}\n\n// 扩展的工具调用选项\ninterface ToolCallOptions {\n timeout?: number; // 超时时间(毫秒)\n enableCache?: boolean; // 是否启用缓存\n taskId?: string; // 任务ID\n}\n\n/**\n * 简化版的 CustomMCPHandler\n * 专门用于处理 Coze 工作流工具,保持超时友好响应机制\n */\nexport class CustomMCPHandler {\n private logger: Logger;\n private tools: Map<string, CustomMCPTool> = new Map();\n private cacheManager: MCPCacheManager;\n private mcpServiceManager?: MCPServiceManager;\n private readonly TIMEOUT = DEFAULT_CONFIG.TIMEOUT; // 统一8秒超时\n private readonly CACHE_TTL = DEFAULT_CONFIG.CACHE_TTL; // 5分钟缓存过期\n\n constructor(\n cacheManager?: MCPCacheManager,\n mcpServiceManager?: MCPServiceManager\n ) {\n this.logger = logger;\n this.cacheManager = cacheManager || new MCPCacheManager();\n this.mcpServiceManager = mcpServiceManager;\n\n // 设置事件监听器\n this.setupEventListeners();\n }\n\n /**\n * 获取 CozeApiService 实例\n */\n private getCozeApiService(): CozeApiService {\n const token = configManager.getConfig().platforms?.coze?.token;\n\n if (!token) {\n throw new Error(\"Coze Token 配置不存在\");\n }\n\n return new CozeApiService(token);\n }\n\n /**\n * 设置事件监听器\n */\n private setupEventListeners(): void {\n const eventBus = getEventBus();\n\n // 监听配置更新事件\n eventBus.onEvent(\"config:updated\", async (data) => {\n if (data.type === \"customMCP\") {\n this.logger.info(\"[CustomMCP] 检测到配置更新,重新初始化...\");\n try {\n this.reinitialize();\n } catch (error) {\n this.logger.error(\"[CustomMCP] 配置更新处理失败:\", error);\n }\n }\n });\n }\n\n /**\n * 初始化 CustomMCP 处理器\n * 加载配置中的 customMCP 工具\n * @param tools 可选的工具数组,如果提供则使用该数组,否则从配置管理器获取\n */\n public initialize(tools?: CustomMCPTool[]): void {\n this.logger.debug(\"[CustomMCP] 初始化 CustomMCP 处理器...\");\n\n try {\n const customTools = tools || configManager.getCustomMCPTools();\n\n // 清空现有工具\n this.tools.clear();\n\n // 只加载 coze 代理工具\n for (const tool of customTools) {\n if (isProxyHandler(tool.handler) && tool.handler.platform === \"coze\") {\n this.tools.set(tool.name, tool);\n this.logger.debug(\n `[CustomMCP] 已加载 Coze 工具: ${tool.name} (workflow_id: ${tool.handler.config.workflow_id})`\n );\n } else {\n // 根据是否为 proxy 类型显示不同的警告信息\n const platformInfo = isProxyHandler(tool.handler)\n ? `/${tool.handler.platform}`\n : \"\";\n this.logger.warn(\n `[CustomMCP] 跳过不支持的工具类型: ${tool.name} (${tool.handler.type}${platformInfo})`\n );\n }\n }\n\n this.logger.debug(\n `[CustomMCP] 初始化完成,共加载 ${this.tools.size} 个 Coze 工具`\n );\n } catch (error) {\n this.logger.error(\"[CustomMCP] 初始化失败:\", error);\n throw error;\n }\n }\n\n /**\n * 获取所有工具(标准 MCP 格式)\n */\n public getTools(): Tool[] {\n return Array.from(this.tools.values()).map((tool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: ensureToolJSONSchema(tool.inputSchema),\n }));\n }\n\n /**\n * 检查是否存在指定工具\n */\n public hasTool(toolName: string): boolean {\n return this.tools.has(toolName);\n }\n\n /**\n * 获取工具数量\n */\n public getToolCount(): number {\n return this.tools.size;\n }\n\n /**\n * 获取所有工具名称\n */\n public getToolNames(): string[] {\n return Array.from(this.tools.keys());\n }\n\n /**\n * 获取工具详细信息(用于调试)\n */\n public getToolInfo(toolName: string): CustomMCPTool | undefined {\n return this.tools.get(toolName);\n }\n\n /**\n * 重新初始化 CustomMCP 处理器\n * 重新加载配置中的 customMCP 工具\n */\n public reinitialize(): void {\n this.logger.debug(\"[CustomMCP] 重新初始化 CustomMCP 处理器...\");\n this.initialize();\n }\n\n /**\n * 调用工具(支持超时友好响应和缓存管理)\n */\n public async callTool(\n toolName: string,\n arguments_: ToolArguments,\n options?: ToolCallOptions\n ): Promise<ToolCallResponse> {\n const tool = this.tools.get(toolName);\n if (!tool) {\n throw new Error(`未找到工具: ${toolName}`);\n }\n\n // 首先检查是否有已完成的任务结果(一次性缓存)\n const completedResult = await this.getCompletedResult(toolName, arguments_);\n if (completedResult) {\n this.logger.debug(`[CustomMCP] 返回已完成的任务结果: ${toolName}`);\n // 立即清理已消费的缓存\n await this.clearConsumedCache(toolName, arguments_);\n return completedResult;\n }\n\n try {\n const timeout = options?.timeout || this.TIMEOUT;\n const result = await Promise.race([\n this.callCozeWorkflow(tool, arguments_),\n this.createTimeoutPromise(toolName, timeout),\n ]);\n\n // 缓存结果(标记为未消费)\n await this.cacheResult(toolName, arguments_, result);\n\n return result;\n } catch (error) {\n // 如果是超时错误,返回友好提示\n if (error instanceof TimeoutError) {\n const taskId = await this.generateTaskId(toolName, arguments_);\n this.logger.info(\n `[CustomMCP] 工具超时,返回友好提示: ${toolName}, taskId: ${taskId}`\n );\n return createTimeoutResponse(taskId, toolName);\n }\n\n throw error;\n }\n }\n\n /**\n * 创建超时 Promise\n */\n private async createTimeoutPromise(\n toolName: string,\n timeout: number\n ): Promise<never> {\n return new Promise((_, reject) => {\n setTimeout(() => {\n reject(new TimeoutError(`工具调用超时: ${toolName}`));\n }, timeout);\n });\n }\n\n /**\n * 获取已完成的任务结果(一次性缓存)\n */\n private async getCompletedResult(\n toolName: string,\n arguments_: ToolArguments\n ): Promise<ToolCallResult | null> {\n try {\n const cacheKey = this.generateCacheKey(toolName, arguments_);\n const cache = await this.loadExtendedCache();\n\n if (!cache.customMCPResults || !cache.customMCPResults[cacheKey]) {\n return null;\n }\n\n const cached = cache.customMCPResults[cacheKey];\n\n // 只返回已完成且未消费的结果\n if (cached.status === \"completed\" && !cached.consumed) {\n // 检查是否过期\n if (!isCacheExpired(cached.timestamp, cached.ttl)) {\n return cached.result;\n }\n }\n\n return null;\n } catch (error) {\n this.logger.warn(`[CustomMCP] 获取缓存失败: ${error}`);\n return null;\n }\n }\n\n /**\n * 处理工作流响应\n */\n private processWorkflowResponse(\n toolName: string,\n workflowData: RunWorkflowData\n ): ToolCallResult {\n try {\n // 根据 RunWorkflowData 的实际结构进行处理\n // 假设 workflowData 有 data 字段或其他响应数据字段\n const responseData = workflowData.data || workflowData;\n\n if (typeof responseData === \"string\") {\n return {\n content: [\n {\n type: \"text\",\n text: responseData,\n },\n ],\n isError: false,\n };\n }\n\n // 如果是对象,转换为 JSON 字符串\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(responseData, null, 2),\n },\n ],\n isError: false,\n };\n } catch (error) {\n this.logger.error(`[CustomMCP] 处理工作流响应失败: ${toolName}`, error);\n\n return {\n content: [\n {\n type: \"text\",\n text: `处理响应失败: ${\n error instanceof Error ? error.message : String(error)\n }`,\n },\n ],\n isError: true,\n };\n }\n }\n\n /**\n * 调用 Coze 工作流\n */\n private async callCozeWorkflow(\n tool: CustomMCPTool,\n arguments_: ToolArguments\n ): Promise<ToolCallResult> {\n const handler = tool.handler as ProxyHandlerConfig;\n const config = handler.config;\n\n this.logger.info(`[CustomMCP] 调用 Coze 工作流: ${tool.name}`, {\n workflow_id: config.workflow_id,\n });\n\n try {\n // 使用 CozeApiService\n const cozeApiService = this.getCozeApiService();\n\n // 检查 workflow_id 是否存在\n if (!config.workflow_id) {\n throw new Error(\"工作流ID未配置\");\n }\n\n // 调用 callWorkflow 方法\n const workflowResult = await cozeApiService.callWorkflow(\n config.workflow_id,\n arguments_\n );\n\n this.logger.info(`[CustomMCP] Coze 工作流调用成功: ${tool.name}`);\n\n // 转换响应格式为 ToolCallResult\n return this.processWorkflowResponse(tool.name, workflowResult);\n } catch (error) {\n this.logger.error(`[CustomMCP] Coze 工作流调用失败: ${tool.name}`, error);\n\n return {\n content: [\n {\n type: \"text\",\n text: `Coze 工作流调用失败: ${\n error instanceof Error ? error.message : String(error)\n }`,\n },\n ],\n isError: true,\n };\n }\n }\n\n /**\n * 清理已消费的缓存\n */\n private async clearConsumedCache(\n toolName: string,\n arguments_: ToolArguments\n ): Promise<void> {\n try {\n const cacheKey = this.generateCacheKey(toolName, arguments_);\n const cache = await this.loadExtendedCache();\n\n if (cache.customMCPResults?.[cacheKey]) {\n // 标记为已消费\n cache.customMCPResults[cacheKey].consumed = true;\n\n // 如果已消费且已过期,直接删除\n const cached = cache.customMCPResults[cacheKey];\n if (shouldCleanupCache(cached)) {\n delete cache.customMCPResults[cacheKey];\n }\n\n // 保存缓存更改\n await this.saveCache(cache);\n this.logger.debug(`[CustomMCP] 清理已消费缓存: ${cacheKey}`);\n }\n } catch (error) {\n this.logger.warn(`[CustomMCP] 清理缓存失败: ${error}`);\n }\n }\n\n /**\n * 生成任务ID\n */\n private async generateTaskId(\n toolName: string,\n arguments_: ToolArguments\n ): Promise<string> {\n return generateCacheKey(toolName, arguments_);\n }\n\n /**\n * 生成缓存键\n */\n private generateCacheKey(\n toolName: string,\n arguments_: ToolArguments\n ): string {\n return generateCacheKey(toolName, arguments_);\n }\n\n /**\n * 加载扩展缓存\n */\n private async loadExtendedCache(): Promise<ExtendedMCPToolsCache> {\n try {\n const cacheData = await this.cacheManager.loadExistingCache();\n return cacheData as ExtendedMCPToolsCache;\n } catch (error) {\n return {\n version: \"1.0.0\",\n mcpServers: {},\n metadata: {\n lastGlobalUpdate: new Date().toISOString(),\n totalWrites: 0,\n createdAt: new Date().toISOString(),\n },\n customMCPResults: {},\n };\n }\n }\n\n /**\n * 更新缓存结果\n */\n private async updateCacheWithResult(\n cacheKey: string,\n cacheData: EnhancedToolResultCache\n ): Promise<void> {\n try {\n const cache = await this.loadExtendedCache();\n\n if (!cache.customMCPResults) {\n cache.customMCPResults = {};\n }\n\n cache.customMCPResults[cacheKey] = cacheData;\n\n // 使用 MCPCacheManager 的保存方法\n await this.saveCache(cache);\n } catch (error) {\n this.logger.warn(`[CustomMCP] 更新缓存失败: ${error}`);\n }\n }\n\n /**\n * 缓存结果\n */\n private async cacheResult(\n toolName: string,\n arguments_: ToolArguments,\n result: ToolCallResult\n ): Promise<void> {\n try {\n const cacheKey = this.generateCacheKey(toolName, arguments_);\n const cacheData: EnhancedToolResultCache = {\n result,\n timestamp: new Date().toISOString(),\n ttl: this.CACHE_TTL,\n status: \"completed\",\n consumed: false, // 初始状态为未消费\n retryCount: 0,\n };\n\n await this.updateCacheWithResult(cacheKey, cacheData);\n this.logger.debug(`[CustomMCP] 缓存工具结果: ${toolName}`);\n } catch (error) {\n this.logger.warn(`[CustomMCP] 缓存结果失败: ${error}`);\n }\n }\n\n /**\n * 保存缓存\n */\n private async saveCache(cache: ExtendedMCPToolsCache): Promise<void> {\n try {\n await this.cacheManager.saveCache(cache);\n } catch (error) {\n this.logger.warn(`[CustomMCP] 保存缓存失败: ${error}`);\n }\n }\n\n /**\n * 清理资源\n */\n public cleanup(): void {\n this.logger.info(\"[CustomMCP] 清理 CustomMCP 处理器资源\");\n this.tools.clear();\n this.cacheManager.cleanup();\n }\n}\n","/**\n * MCP 工具调用日志模块\n * 提供工具调用的写入和查询功能\n */\n\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { PathUtils } from \"@cli/utils/PathUtils.js\";\nimport pino from \"pino\";\nimport type { Logger as PinoLogger } from \"pino\";\n\n// ==================== 类型定义 ====================\n\n/**\n * Pino 日志对象类型(内部使用)\n * 用于 formatConsoleMessage 方法的参数类型\n */\ninterface PinoLogObject {\n toolName?: string;\n success?: boolean;\n duration?: number;\n [key: string]: unknown;\n}\n\n/**\n * 工具调用记录接口\n */\nexport interface ToolCallRecord {\n toolName: string; // 工具名称\n originalToolName?: string; // 原始工具名称(未格式化的)\n serverName?: string; // 服务器名称(coze、dify、n8n、custom等)\n arguments?: Record<string, unknown>; // 调用参数\n result?: unknown; // 响应结果\n success: boolean; // 是否成功\n duration?: number; // 调用耗时(毫秒)\n error?: string; // 错误信息(如果有)\n timestamp?: number; // 时间戳(毫秒)\n}\n\n/**\n * 工具调用日志配置接口\n */\nexport interface ToolCallLogConfig {\n maxRecords?: number; // 最大记录条数,默认 100\n logFilePath?: string; // 自定义日志文件路径(可选)\n}\n\n/**\n * 查询参数接口\n */\nexport interface ToolCallQuery {\n limit?: number;\n offset?: number;\n toolName?: string;\n serverName?: string;\n success?: boolean;\n startDate?: string;\n endDate?: string;\n}\n\n// ==================== ToolCallLogger 类(写入功能)====================\n\n/**\n * MCP 工具调用记录器\n * 提供工具调用的 JSONL 格式记录功能\n */\nexport class ToolCallLogger {\n private pinoLogger: PinoLogger;\n private maxRecords: number;\n private logFilePath: string;\n\n constructor(config: ToolCallLogConfig, configDir: string) {\n this.maxRecords = config?.maxRecords ?? 100;\n\n // 确定日志文件路径 - 使用更健壮的路径处理\n if (config?.logFilePath) {\n this.logFilePath = path.resolve(path.normalize(config.logFilePath));\n } else {\n // 使用 PathUtils 的跨平台临时目录处理\n const baseDir = configDir || PathUtils.getTempDir();\n this.logFilePath = path.join(path.normalize(baseDir), \"tool-calls.jsonl\");\n }\n\n // 创建 Pino 实例\n this.pinoLogger = this.createPinoLogger(this.logFilePath);\n\n console.log(\"ToolCallLogger 初始化\", {\n maxRecords: this.maxRecords,\n path: this.logFilePath,\n });\n }\n\n /**\n * 创建 Pino Logger 实例\n */\n private createPinoLogger(logFilePath: string): PinoLogger {\n const streams: pino.StreamEntry[] = [];\n\n // 控制台流 - 使用彩色输出\n streams.push({\n level: \"info\",\n stream: {\n write: (chunk: string) => {\n try {\n const logObj = JSON.parse(chunk);\n const message = this.formatConsoleMessage(logObj);\n console.log(\"[工具调用]\", { message });\n } catch {\n console.log(\"[工具调用]\", { chunk: chunk.trim() });\n }\n },\n },\n });\n\n // 文件流 - JSONL 格式,带错误处理\n try {\n streams.push({\n level: \"info\",\n stream: pino.destination({\n dest: logFilePath,\n sync: true, // 同步写入确保测试可靠性\n append: true,\n mkdir: true,\n }),\n });\n } catch (error) {\n // 如果文件路径无效,记录错误但不抛出异常\n console.error(\"无法创建工具调用日志文件\", { error });\n }\n\n return pino(\n {\n level: \"info\",\n timestamp:\n pino.stdTimeFunctions?.isoTime || (() => `,\"time\":${Date.now()}`),\n formatters: {\n level: (_label: string, number: number) => ({ level: number }),\n },\n base: null, // 不包含 pid 和 hostname\n },\n pino.multistream(streams, { dedupe: true })\n );\n }\n\n /**\n * 格式化控制台消息\n */\n private formatConsoleMessage(logObj: PinoLogObject): string {\n const toolName = logObj.toolName || \"未知工具\";\n const success = logObj.success !== false;\n const duration = logObj.duration ? ` (${logObj.duration}ms)` : \"\";\n const status = success ? \"✅\" : \"❌\";\n\n return `${status} ${toolName}${duration}`;\n }\n\n /**\n * 清理旧的日志记录,确保不超过最大记录数量\n */\n private async cleanupOldRecords(): Promise<void> {\n try {\n // 检查日志文件是否存在\n if (!fs.existsSync(this.logFilePath)) {\n return;\n }\n\n // 读取文件内容\n const content = fs.readFileSync(this.logFilePath, \"utf8\");\n const lines = content\n .trim()\n .split(\"\\n\")\n .filter((line) => line.trim() !== \"\");\n\n // 如果记录数量未超过限制,直接返回\n if (lines.length <= this.maxRecords) {\n return;\n }\n\n // 计算需要删除的记录数量\n const recordsToRemove = lines.length - this.maxRecords + 1; // +1 为即将写入的新记录预留空间\n\n // 删除最旧的记录(从文件开头删除)\n const linesToKeep = lines.slice(recordsToRemove);\n\n // 重新写入文件\n const newContent =\n linesToKeep.join(\"\\n\") + (linesToKeep.length > 0 ? \"\\n\" : \"\");\n fs.writeFileSync(this.logFilePath, newContent, \"utf8\");\n\n console.log(\"已清理旧的工具调用记录\", {\n recordsToRemove,\n maxRecords: this.maxRecords,\n });\n } catch (error) {\n console.error(\"清理旧工具调用记录失败\", { error });\n }\n }\n\n /**\n * 记录工具调用\n */\n async recordToolCall(record: ToolCallRecord): Promise<void> {\n try {\n // 在写入新记录前,先清理旧记录以确保不超过最大记录数量\n await this.cleanupOldRecords();\n\n // 使用 Pino 记录日志,自动处理并发和文件写入\n this.pinoLogger.info(record, record.toolName);\n } catch (error) {\n // 记录失败不应该影响主流程,只记录错误日志\n console.error(\"记录工具调用失败\", { error });\n }\n }\n\n /**\n * 获取日志文件路径\n */\n getLogFilePath(): string {\n return this.logFilePath;\n }\n\n /**\n * 获取最大记录数量\n */\n getMaxRecords(): number {\n return this.maxRecords;\n }\n}\n\n// ==================== ToolCallLogService 类(查询功能)====================\n\n/**\n * 工具调用日志服务类\n * 负责读取和查询工具调用日志\n */\nexport class ToolCallLogService {\n private configDir: string;\n\n constructor(configDir?: string) {\n this.configDir = configDir || PathUtils.getConfigDir();\n }\n\n /**\n * 获取工具调用日志文件路径\n */\n private getLogFilePath(): string {\n const toolCallLogger = new ToolCallLogger({}, this.configDir);\n return toolCallLogger.getLogFilePath();\n }\n\n /**\n * 检查日志文件是否存在\n */\n private checkLogFile(): void {\n const logFilePath = this.getLogFilePath();\n if (!fs.existsSync(logFilePath)) {\n throw new Error(\"工具调用日志文件不存在\");\n }\n }\n\n /**\n * 读取并解析工具调用日志\n */\n private parseLogFile(): ToolCallRecord[] {\n const logFilePath = this.getLogFilePath();\n\n try {\n const content = fs.readFileSync(logFilePath, \"utf8\");\n const lines = content\n .trim()\n .split(\"\\n\")\n .filter((line) => line.trim() !== \"\");\n\n const records: ToolCallRecord[] = [];\n\n for (const line of lines) {\n try {\n const record = JSON.parse(line);\n // 添加时间戳字段(如果 pino 添加了时间信息)\n if (record.time) {\n record.timestamp = new Date(record.time).getTime();\n }\n // 如果没有时间戳,记录警告信息提示数据质量问题\n if (!record.timestamp) {\n console.warn(\"日志记录缺少时间戳\", { line });\n }\n records.push(record);\n } catch {\n console.warn(\"跳过无效的日志行\", { line });\n }\n }\n\n // 按时间戳倒序排列(最新的在前)\n records.sort((a, b) => (b.timestamp || 0) - (a.timestamp || 0));\n\n return records;\n } catch (error) {\n console.error(\"读取日志文件失败\", { error });\n throw new Error(\"无法读取工具调用日志文件\");\n }\n }\n\n /**\n * 过滤工具调用记录\n */\n private filterRecords(\n records: ToolCallRecord[],\n query: ToolCallQuery\n ): ToolCallRecord[] {\n let filtered = [...records];\n\n // 按工具名称过滤\n if (query.toolName) {\n filtered = filtered.filter((record) =>\n record.toolName\n .toLowerCase()\n .includes(query.toolName?.toLowerCase() ?? \"\")\n );\n }\n\n // 按服务器名称过滤\n if (query.serverName) {\n filtered = filtered.filter((record) =>\n record.serverName\n ?.toLowerCase()\n .includes(query.serverName?.toLowerCase() ?? \"\")\n );\n }\n\n // 按成功状态过滤\n if (query.success !== undefined) {\n filtered = filtered.filter((record) => record.success === query.success);\n }\n\n // 按时间范围过滤\n if (query.startDate || query.endDate) {\n const startTime = query.startDate\n ? new Date(query.startDate).getTime()\n : 0;\n const endTime = query.endDate\n ? new Date(query.endDate).getTime()\n : Date.now();\n\n filtered = filtered.filter((record) => {\n const recordTime = record.timestamp || 0;\n return recordTime >= startTime && recordTime <= endTime;\n });\n }\n\n return filtered;\n }\n\n /**\n * 获取工具调用日志\n */\n async getToolCallLogs(query: ToolCallQuery = {}): Promise<{\n records: ToolCallRecord[];\n total: number;\n hasMore: boolean;\n }> {\n this.checkLogFile();\n\n const records = this.parseLogFile();\n const filtered = this.filterRecords(records, query);\n const total = filtered.length;\n\n // 分页处理\n const limit = Math.min(\n query.limit || 50,\n 1000 // 最大限制 1000\n );\n const offset = query.offset || 0;\n const paginated = filtered.slice(offset, offset + limit);\n const hasMore = offset + limit < total;\n\n console.log(\"返回工具调用日志\", {\n count: paginated.length,\n total,\n });\n\n return {\n records: paginated,\n total,\n hasMore,\n };\n }\n}\n","/**\n * 统一的 MCP 消息处理器\n * 负责处理所有 MCP 协议消息,包括 initialize、tools/list、tools/call、resources/list、prompts/list 等\n * 这是阶段一重构的核心组件,用于消除双层代理架构\n */\n\nimport type { MCPServiceManager } from \"@/lib/mcp\";\nimport { validateToolCallParams } from \"@/lib/mcp\";\nimport type {\n ClientCapabilities,\n InitializedNotification,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport type { Logger } from \"@root/Logger.js\";\nimport { logger } from \"@root/Logger.js\";\nimport type { MCPMessage, MCPResponse } from \"@root/types/mcp.js\";\n\n// 初始化参数接口\ninterface InitializeParams {\n protocolVersion: string;\n capabilities: ClientCapabilities;\n clientInfo: {\n name: string;\n version: string;\n };\n}\n\n// 工具调用参数接口\ninterface ToolCallParams {\n name: string;\n arguments?: Record<string, unknown>;\n}\n\n// MCP 资源接口\ninterface MCPResource {\n uri: string;\n name: string;\n description?: string;\n mimeType?: string;\n}\n\n// MCP 提示接口\ninterface MCPPrompt {\n name: string;\n description?: string;\n arguments?: Array<{\n name: string;\n description?: string;\n required?: boolean;\n }>;\n}\n\nexport class MCPMessageHandler {\n private logger: Logger;\n private serviceManager: MCPServiceManager;\n\n constructor(serviceManager: MCPServiceManager) {\n this.serviceManager = serviceManager;\n this.logger = logger;\n }\n\n /**\n * 处理 MCP 消息的统一入口\n * @param message MCP 消息\n * @returns MCP 响应(对于通知消息返回 null)\n */\n async handleMessage(message: MCPMessage): Promise<MCPResponse | null> {\n this.logger.debug(`处理 MCP 消息: ${message.method}`, message);\n\n try {\n // 检查是否为通知消息(没有 id 字段)\n const isNotification = message.id === undefined;\n\n switch (message.method) {\n case \"initialize\":\n return await this.handleInitialize(\n message.params as InitializeParams,\n message.id\n );\n case \"notifications/initialized\":\n return await this.handleInitializedNotification(\n message.params as InitializedNotification[\"params\"]\n );\n case \"tools/list\":\n return await this.handleToolsList(message.id);\n case \"tools/call\":\n return await this.handleToolCall(\n message.params as ToolCallParams,\n message.id\n );\n case \"resources/list\":\n return await this.handleResourcesList(message.id);\n case \"prompts/list\":\n return await this.handlePromptsList(message.id);\n case \"ping\":\n return await this.handlePing(message.id);\n default:\n if (isNotification) {\n // 对于未知的通知消息,记录警告但不抛出错误\n this.logger.warn(`收到未知的通知消息: ${message.method}`, message);\n return null;\n }\n throw new Error(`未知的方法: ${message.method}`);\n }\n } catch (error) {\n this.logger.error(`处理消息时出错: ${message.method}`, error);\n // 通知消息不需要错误响应\n if (message.id === undefined) {\n return null;\n }\n return this.createErrorResponse(error as Error, message.id);\n }\n }\n\n /**\n * 处理 initialize 请求\n * @param params 初始化参数\n * @param id 消息ID\n * @returns 初始化响应\n */\n private async handleInitialize(\n params: InitializeParams,\n id?: string | number\n ): Promise<MCPResponse> {\n this.logger.debug(\"处理 initialize 请求\", params);\n\n // 支持多个协议版本,优先使用客户端请求的版本\n const supportedVersions = [\"2024-11-05\", \"2025-06-18\"];\n const clientVersion = params.protocolVersion;\n const responseVersion = supportedVersions.includes(clientVersion)\n ? clientVersion\n : \"2024-11-05\";\n\n this.logger.debug(\n `协议版本协商: 客户端=${clientVersion}, 服务器响应=${responseVersion}`\n );\n\n return {\n jsonrpc: \"2.0\",\n result: {\n serverInfo: {\n name: \"xiaozhi-mcp-server\",\n version: \"1.0.0\",\n },\n capabilities: {\n tools: {},\n logging: {},\n },\n protocolVersion: responseVersion,\n },\n id: id !== undefined ? id : 1,\n };\n }\n\n /**\n * 处理 notifications/initialized 通知\n * @param params 通知参数\n * @returns null(通知消息不需要响应)\n */\n private async handleInitializedNotification(\n params?: InitializedNotification[\"params\"]\n ): Promise<null> {\n this.logger.debug(\"收到 initialized 通知,客户端初始化完成\", params);\n\n // 可以在这里执行一些初始化完成后的逻辑\n // 例如:记录客户端连接状态、触发事件等\n\n return null;\n }\n\n /**\n * 处理 tools/list 请求\n * @param id 消息ID\n * @returns 工具列表响应\n */\n private async handleToolsList(id?: string | number): Promise<MCPResponse> {\n this.logger.debug(\"处理 tools/list 请求\");\n\n try {\n const tools = this.serviceManager.getAllTools();\n\n // 转换为 MCP 标准格式\n const mcpTools = tools.map((tool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema,\n }));\n\n return {\n jsonrpc: \"2.0\",\n result: {\n tools: mcpTools,\n },\n id: id !== undefined ? id : 1,\n };\n } catch (error) {\n this.logger.error(\"获取工具列表失败\", error);\n throw error;\n }\n }\n\n /**\n * 处理 tools/call 请求\n * @param params 工具调用参数\n * @param id 消息ID\n * @returns 工具调用响应\n */\n private async handleToolCall(\n params: ToolCallParams,\n id?: string | number\n ): Promise<MCPResponse> {\n try {\n // 参数校验\n const validatedParams = validateToolCallParams(params);\n\n const result = await this.serviceManager.callTool(\n validatedParams.name,\n validatedParams.arguments || {}\n );\n\n return {\n jsonrpc: \"2.0\",\n result: {\n content: result.content,\n isError: result.isError || false,\n },\n id: id !== undefined ? id : 1,\n };\n } catch (error) {\n this.logger.error(`工具调用失败: ${params.name}`, error);\n throw error;\n }\n }\n\n /**\n * 处理 ping 请求\n * @param id 消息ID\n * @returns ping 响应\n */\n private async handlePing(id?: string | number): Promise<MCPResponse> {\n this.logger.debug(\"处理 ping 请求\");\n\n return {\n jsonrpc: \"2.0\",\n result: {\n status: \"ok\",\n timestamp: new Date().toISOString(),\n },\n id: id !== undefined ? id : 1,\n };\n }\n\n /**\n * 处理 resources/list 请求\n * @param id 消息ID\n * @returns 资源列表响应\n */\n private async handleResourcesList(\n id?: string | number\n ): Promise<MCPResponse> {\n this.logger.debug(\"处理 resources/list 请求\");\n\n // 目前返回空的资源列表\n // 如果将来需要提供资源功能,可以在这里扩展\n const resources: MCPResource[] = [];\n\n this.logger.debug(`返回 ${resources.length} 个资源`);\n\n return {\n jsonrpc: \"2.0\",\n result: {\n resources: resources,\n },\n id: id !== undefined ? id : 1,\n };\n }\n\n /**\n * 处理 prompts/list 请求\n * @param id 消息ID\n * @returns 提示列表响应\n */\n private async handlePromptsList(id?: string | number): Promise<MCPResponse> {\n this.logger.debug(\"处理 prompts/list 请求\");\n\n // 目前返回空的提示列表\n // 如果将来需要提供提示模板功能,可以在这里扩展\n const prompts: MCPPrompt[] = [];\n\n this.logger.debug(`返回 ${prompts.length} 个提示模板`);\n\n return {\n jsonrpc: \"2.0\",\n result: {\n prompts: prompts,\n },\n id: id !== undefined ? id : 1,\n };\n }\n\n /**\n * 创建错误响应\n * @param error 错误对象\n * @param id 消息ID\n * @returns 错误响应\n */\n private createErrorResponse(error: Error, id?: string | number): MCPResponse {\n // 根据错误类型确定错误代码\n let errorCode = -32603; // Internal error\n\n if (\n error.message.includes(\"未找到工具\") ||\n error.message.includes(\"未知的方法\")\n ) {\n errorCode = -32601; // Method not found\n } else if (\n error.message.includes(\"参数\") ||\n error.message.includes(\"不能为空\")\n ) {\n errorCode = -32602; // Invalid params\n }\n\n return {\n jsonrpc: \"2.0\",\n error: {\n code: errorCode,\n message: error.message,\n data: {\n stack: error.stack,\n },\n },\n id: id !== undefined ? id : 1,\n };\n }\n\n /**\n * 获取服务管理器实例\n * @returns MCPServiceManager 实例\n */\n getServiceManager(): MCPServiceManager {\n return this.serviceManager;\n }\n}\n","/**\n * 传输适配器抽象基类\n * 定义了所有传输协议的统一接口,支持 stdio、SSE、HTTP、WebSocket 等多种传输方式\n * 这是阶段二重构的核心组件,用于抽象不同的传输层实现\n */\n\nimport type { MCPMessageHandler } from \"@/lib/mcp/message.js\";\nimport type { MCPError, MCPMessage, MCPResponse } from \"@root/types/mcp.js\";\n\n// 重新导出接口以保持向后兼容\nexport type { MCPMessage, MCPResponse, MCPError };\n\n// 连接状态枚举\nexport enum ConnectionState {\n DISCONNECTED = \"disconnected\",\n CONNECTING = \"connecting\",\n CONNECTED = \"connected\",\n ERROR = \"error\",\n}\n\n// 传输适配器配置接口\nexport interface TransportConfig {\n name: string;\n timeout?: number;\n retryAttempts?: number;\n retryDelay?: number;\n}\n\n/**\n * 传输适配器抽象基类\n * 所有具体的传输适配器都必须继承此类并实现抽象方法\n */\nexport abstract class TransportAdapter {\n protected messageHandler: MCPMessageHandler;\n protected connectionId: string;\n protected config: TransportConfig;\n protected state: ConnectionState = ConnectionState.DISCONNECTED;\n\n constructor(messageHandler: MCPMessageHandler, config: TransportConfig) {\n this.messageHandler = messageHandler;\n this.config = config;\n this.connectionId = this.generateConnectionId();\n }\n\n /**\n * 初始化传输适配器\n * 子类应该在此方法中进行必要的初始化工作\n */\n abstract initialize(): Promise<void>;\n\n /**\n * 启动传输适配器\n * 子类应该在此方法中启动监听或连接\n */\n abstract start(): Promise<void>;\n\n /**\n * 停止传输适配器\n * 子类应该在此方法中清理资源和关闭连接\n */\n abstract stop(): Promise<void>;\n\n /**\n * 发送消息\n * 子类应该实现具体的消息发送逻辑\n */\n abstract sendMessage(message: MCPMessage | MCPResponse): Promise<void>;\n\n /**\n * 处理接收到的消息\n * 这是一个通用的消息处理方法,子类可以直接使用\n */\n protected async handleIncomingMessage(message: MCPMessage): Promise<void> {\n try {\n console.debug(\"[TransportAdapter] 处理接收到的消息\", {\n method: message.method,\n message,\n });\n\n const response = await this.messageHandler.handleMessage(message);\n\n // 仅对非通知消息发送响应\n if (response !== null) {\n console.debug(\"发送响应消息:\", response);\n await this.sendMessage(response);\n } else {\n console.debug(\"收到通知消息,无需响应\");\n }\n } catch (error) {\n console.error(\"处理消息时出错\", { error, message });\n\n const errorResponse = this.createErrorResponse(\n error as Error,\n message.id\n );\n await this.sendMessage(errorResponse);\n }\n }\n\n /**\n * 创建错误响应\n * 统一的错误响应创建方法\n */\n protected createErrorResponse(\n error: Error,\n id: string | number\n ): MCPResponse {\n // 根据错误类型确定错误代码\n let errorCode = -32603; // Internal error\n\n if (\n error.message.includes(\"未找到工具\") ||\n error.message.includes(\"未知的方法\")\n ) {\n errorCode = -32601; // Method not found\n } else if (\n error.message.includes(\"参数\") ||\n error.message.includes(\"不能为空\")\n ) {\n errorCode = -32602; // Invalid params\n }\n\n return {\n jsonrpc: \"2.0\",\n error: {\n code: errorCode,\n message: error.message,\n data: {\n stack: error.stack,\n },\n },\n id,\n };\n }\n\n /**\n * 生成唯一的连接ID\n */\n private generateConnectionId(): string {\n const timestamp = Date.now();\n const random = Math.random().toString(36).substr(2, 9);\n return `${this.config.name}_${timestamp}_${random}`;\n }\n\n /**\n * 获取连接ID\n */\n getConnectionId(): string {\n return this.connectionId;\n }\n\n /**\n * 获取连接状态\n */\n getState(): ConnectionState {\n return this.state;\n }\n\n /**\n * 设置连接状态\n */\n protected setState(state: ConnectionState): void {\n const oldState = this.state;\n this.state = state;\n\n if (oldState !== state) {\n console.info(`连接状态变更: ${oldState} -> ${state}`);\n this.onStateChange(oldState, state);\n }\n }\n\n /**\n * 状态变更回调\n * 子类可以重写此方法来处理状态变更事件\n */\n protected onStateChange(\n oldState: ConnectionState,\n newState: ConnectionState\n ): void {\n // 默认实现为空,子类可以重写\n }\n\n /**\n * 获取配置\n */\n getConfig(): TransportConfig {\n return { ...this.config };\n }\n\n /**\n * 获取消息处理器\n */\n getMessageHandler(): MCPMessageHandler {\n return this.messageHandler;\n }\n\n /**\n * 解析 JSON 消息\n * 统一的 JSON 解析方法,包含错误处理\n */\n protected parseMessage(data: string): MCPMessage | null {\n try {\n const message = JSON.parse(data.trim());\n\n // 验证基本的 JSON-RPC 格式\n if (!message.jsonrpc || message.jsonrpc !== \"2.0\") {\n console.warn(\"收到非 JSON-RPC 2.0 格式的消息\", message);\n return null;\n }\n\n if (!message.method) {\n console.warn(\"收到没有 method 字段的消息\", message);\n return null;\n }\n\n return message;\n } catch (error) {\n console.error(\"解析 JSON 消息失败\", { data, error });\n return null;\n }\n }\n\n /**\n * 序列化消息\n * 统一的消息序列化方法\n */\n protected serializeMessage(message: MCPMessage | MCPResponse): string {\n try {\n return JSON.stringify(message);\n } catch (error) {\n console.error(\"序列化消息失败\", { message, error });\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n throw new Error(`消息序列化失败: ${errorMessage}`);\n }\n }\n\n /**\n * 验证消息格式\n * 验证消息是否符合 MCP 协议规范\n */\n protected validateMessage(message: unknown): boolean {\n if (!message || typeof message !== \"object\") {\n return false;\n }\n\n const messageObj = message as Record<string, unknown>;\n\n if (messageObj.jsonrpc !== \"2.0\") {\n return false;\n }\n\n // 请求消息必须有 method 字段\n if (messageObj.method && typeof messageObj.method !== \"string\") {\n return false;\n }\n\n // 响应消息必须有 result 或 error 字段\n if (!messageObj.method && !messageObj.result && !messageObj.error) {\n return false;\n }\n\n return true;\n }\n\n /**\n * 处理超时\n * 统一的超时处理方法\n */\n protected createTimeoutPromise<T>(\n promise: Promise<T>,\n timeoutMs: number\n ): Promise<T> {\n return Promise.race([\n promise,\n new Promise<T>((_, reject) => {\n setTimeout(() => {\n reject(new Error(`操作超时: ${timeoutMs}ms`));\n }, timeoutMs);\n }),\n ]);\n }\n}\n","/**\n * Stdio 传输适配器\n * 处理通过标准输入输出进行的 MCP 通信,主要用于 Cursor 等客户端\n * 从 mcpServerProxy.ts 中抽取的 stdio 处理逻辑\n */\n\nimport type { MCPMessageHandler } from \"@/lib/mcp/message.js\";\nimport { ConnectionState, TransportAdapter } from \"./TransportAdapter.js\";\nimport type {\n MCPMessage,\n MCPResponse,\n TransportConfig,\n} from \"./TransportAdapter.js\";\n\n/**\n * Stdio 适配器配置\n */\nexport interface StdioConfig extends TransportConfig {\n encoding?: BufferEncoding;\n bufferSize?: number;\n}\n\n/**\n * Stdio 传输适配器实现\n * 处理标准输入输出的 JSON-RPC 消息通信\n */\nexport class StdioAdapter extends TransportAdapter {\n private messageBuffer = \"\";\n private isRunning = false;\n private encoding: BufferEncoding;\n private bufferSize: number;\n\n constructor(\n messageHandler: MCPMessageHandler,\n config: StdioConfig = { name: \"stdio\" }\n ) {\n super(messageHandler, config);\n this.encoding = config.encoding || \"utf8\";\n this.bufferSize = config.bufferSize || 1024 * 1024; // 1MB default buffer\n }\n\n /**\n * 初始化 Stdio 适配器\n */\n async initialize(): Promise<void> {\n console.info(\"初始化 Stdio 适配器\");\n\n try {\n // 设置标准输入编码\n process.stdin.setEncoding(this.encoding);\n\n // 设置进程退出处理\n this.setupProcessHandlers();\n\n this.setState(ConnectionState.CONNECTING);\n console.info(\"Stdio 适配器初始化完成\");\n } catch (error) {\n console.error(\"Stdio 适配器初始化失败\", error);\n this.setState(ConnectionState.ERROR);\n throw error;\n }\n }\n\n /**\n * 启动 Stdio 适配器\n */\n async start(): Promise<void> {\n if (this.isRunning) {\n console.warn(\"Stdio 适配器已在运行\");\n return;\n }\n\n console.info(\"启动 Stdio 适配器\");\n\n try {\n this.isRunning = true;\n this.setupStdioHandlers();\n this.setState(ConnectionState.CONNECTED);\n\n console.info(\"Stdio 适配器启动成功,等待消息...\");\n } catch (error) {\n console.error(\"启动 Stdio 适配器失败\", error);\n this.setState(ConnectionState.ERROR);\n this.isRunning = false;\n throw error;\n }\n }\n\n /**\n * 停止 Stdio 适配器\n */\n async stop(): Promise<void> {\n if (!this.isRunning) {\n return;\n }\n\n console.info(\"停止 Stdio 适配器\");\n\n try {\n this.isRunning = false;\n this.removeStdioHandlers();\n this.setState(ConnectionState.DISCONNECTED);\n\n console.info(\"Stdio 适配器已停止\");\n } catch (error) {\n console.error(\"停止 Stdio 适配器时出错\", error);\n throw error;\n }\n }\n\n /**\n * 发送消息到标准输出\n */\n async sendMessage(message: MCPMessage | MCPResponse): Promise<void> {\n try {\n const serializedMessage = this.serializeMessage(message);\n\n // 写入到标准输出,添加换行符\n process.stdout.write(`${serializedMessage}\\n`);\n\n console.debug(\"消息已发送到 stdout\", {\n messageId: message.id,\n method: \"method\" in message ? message.method : \"response\",\n });\n } catch (error) {\n console.error(\"发送消息失败\", error);\n throw error;\n }\n }\n\n /**\n * 设置标准输入输出处理器\n */\n private setupStdioHandlers(): void {\n // 处理标准输入数据\n process.stdin.on(\"data\", this.handleStdinData.bind(this));\n\n // 处理标准输入结束\n process.stdin.on(\"end\", this.handleStdinEnd.bind(this));\n\n // 处理标准输入错误\n process.stdin.on(\"error\", this.handleStdinError.bind(this));\n }\n\n /**\n * 移除标准输入输出处理器\n */\n private removeStdioHandlers(): void {\n process.stdin.removeListener(\"data\", this.handleStdinData.bind(this));\n process.stdin.removeListener(\"end\", this.handleStdinEnd.bind(this));\n process.stdin.removeListener(\"error\", this.handleStdinError.bind(this));\n }\n\n /**\n * 处理标准输入数据\n */\n private async handleStdinData(data: Buffer | string): Promise<void> {\n try {\n // 将数据添加到缓冲区\n this.messageBuffer += data.toString();\n\n // 检查缓冲区大小\n if (this.messageBuffer.length > this.bufferSize) {\n console.warn(\n `消息缓冲区超过限制 (${this.bufferSize} bytes),清空缓冲区`\n );\n this.messageBuffer = \"\";\n return;\n }\n\n // 按换行符分割消息\n const lines = this.messageBuffer.split(\"\\n\");\n\n // 保留最后一个不完整的行在缓冲区中\n this.messageBuffer = lines.pop() || \"\";\n\n // 处理完整的消息行\n for (const line of lines) {\n const trimmedLine = line.trim();\n if (trimmedLine) {\n await this.processMessageLine(trimmedLine);\n }\n }\n } catch (error) {\n console.error(\"处理 stdin 数据时出错\", error);\n }\n }\n\n /**\n * 处理单行消息\n */\n private async processMessageLine(line: string): Promise<void> {\n try {\n console.debug(`处理消息行: ${line.substring(0, 200)}...`);\n\n const message = this.parseMessage(line);\n if (message) {\n await this.handleIncomingMessage(message);\n }\n } catch (error) {\n console.error(`处理消息行失败: ${line.substring(0, 100)}...`, error);\n\n // 尝试从原始消息中提取ID,如果失败则生成默认ID\n let messageId: string | number = `parse-error-${Date.now()}`;\n try {\n const parsedMessage = JSON.parse(line.trim());\n if (\n parsedMessage &&\n (typeof parsedMessage.id === \"string\" ||\n typeof parsedMessage.id === \"number\")\n ) {\n messageId = parsedMessage.id;\n }\n } catch {\n // 如果无法解析消息,使用生成的默认ID\n }\n\n // 发送错误响应\n const errorResponse: MCPResponse = {\n jsonrpc: \"2.0\",\n error: {\n code: -32700,\n message: \"解析错误\",\n data: { originalLine: line.substring(0, 100) },\n },\n id: messageId,\n };\n\n await this.sendMessage(errorResponse);\n }\n }\n\n /**\n * 处理标准输入结束\n */\n private handleStdinEnd(): void {\n console.info(\"标准输入已关闭,停止适配器\");\n this.stop().catch((error) => {\n console.error(\"停止适配器时出错\", error);\n });\n }\n\n /**\n * 处理标准输入错误\n */\n private handleStdinError(error: Error): void {\n console.error(\"标准输入错误\", error);\n this.setState(ConnectionState.ERROR);\n }\n\n /**\n * 设置进程处理器\n */\n private setupProcessHandlers(): void {\n // 处理进程退出信号\n const handleExit = () => {\n console.info(\"收到退出信号,清理资源\");\n this.stop().finally(() => {\n process.exit(0);\n });\n };\n\n process.on(\"SIGINT\", handleExit);\n process.on(\"SIGTERM\", handleExit);\n\n // 处理未捕获的异常\n process.on(\"uncaughtException\", (error) => {\n console.error(\"未捕获的异常\", error);\n this.setState(ConnectionState.ERROR);\n });\n\n // 处理未处理的 Promise 拒绝\n process.on(\"unhandledRejection\", (reason, promise) => {\n console.error(\"未处理的 Promise 拒绝\", { reason, promise });\n });\n }\n\n /**\n * 获取适配器状态信息\n */\n getStatus(): {\n isRunning: boolean;\n bufferSize: number;\n encoding: string;\n connectionId: string;\n state: ConnectionState;\n } {\n return {\n isRunning: this.isRunning,\n bufferSize: this.messageBuffer.length,\n encoding: this.encoding,\n connectionId: this.connectionId,\n state: this.state,\n };\n }\n\n /**\n * 清空消息缓冲区\n */\n clearBuffer(): void {\n this.messageBuffer = \"\";\n console.debug(\"消息缓冲区已清空\");\n }\n}\n","/**\n * WebSocket 传输适配器\n * 阶段四重构:支持 WebSocket 双向通信和自动重连\n *\n * 主要功能:\n * 1. WebSocket 连接管理和自动重连\n * 2. 双向实时通信支持\n * 3. 连接池管理和性能优化\n * 4. 消息压缩和批量处理\n */\n\nimport type { IncomingMessage } from \"node:http\";\nimport type { MCPMessageHandler } from \"@/lib/mcp/message.js\";\nimport WebSocket, { WebSocketServer } from \"ws\";\nimport { ConnectionState, TransportAdapter } from \"./TransportAdapter.js\";\nimport type {\n MCPMessage,\n MCPResponse,\n TransportConfig,\n} from \"./TransportAdapter.js\";\n\n/**\n * WebSocket 连接状态枚举\n */\nexport enum WebSocketState {\n DISCONNECTED = \"disconnected\",\n CONNECTING = \"connecting\",\n CONNECTED = \"connected\",\n RECONNECTING = \"reconnecting\",\n FAILED = \"failed\",\n}\n\n/**\n * 重连配置接口\n */\nexport interface ReconnectOptions {\n enabled: boolean;\n maxAttempts: number;\n initialInterval: number;\n maxInterval: number;\n backoffStrategy: \"linear\" | \"exponential\" | \"fixed\";\n backoffMultiplier: number;\n timeout: number;\n jitter: boolean;\n}\n\n/**\n * WebSocket 适配器配置\n */\nexport interface WebSocketConfig extends TransportConfig {\n endpointUrl: string;\n mode?: \"client\" | \"server\";\n reconnect?: Partial<ReconnectOptions>;\n compression?: boolean;\n batchSize?: number;\n batchTimeout?: number;\n maxConnections?: number;\n}\n\n/**\n * 重连状态接口\n */\ninterface ReconnectState {\n attempts: number;\n nextInterval: number;\n timer: NodeJS.Timeout | null;\n lastError: Error | null;\n isManualDisconnect: boolean;\n}\n\n/**\n * 消息批处理队列项\n */\ninterface BatchQueueItem {\n message: MCPMessage | MCPResponse;\n timestamp: number;\n resolve: () => void;\n reject: (error: Error) => void;\n}\n\n/**\n * WebSocket 传输适配器实现\n * 支持客户端和服务器模式的 WebSocket 通信\n */\nexport class WebSocketAdapter extends TransportAdapter {\n private ws: WebSocket | null = null;\n private wsServer: WebSocketServer | null = null;\n private endpointUrl: string;\n private mode: \"client\" | \"server\";\n private wsState: WebSocketState = WebSocketState.DISCONNECTED;\n\n // 重连相关\n private reconnectOptions: ReconnectOptions;\n private reconnectState: ReconnectState;\n private connectionTimeout: NodeJS.Timeout | null = null;\n\n // 性能优化相关\n private compression: boolean;\n private batchQueue: BatchQueueItem[] = [];\n private batchTimer: NodeJS.Timeout | null = null;\n private batchSize: number;\n private batchTimeout: number;\n\n // 连接池管理\n private connections: Map<string, WebSocket> = new Map();\n private maxConnections: number;\n\n constructor(messageHandler: MCPMessageHandler, config: WebSocketConfig) {\n super(messageHandler, config);\n\n this.endpointUrl = config.endpointUrl;\n this.mode = config.mode || \"client\";\n this.compression = config.compression || false;\n this.batchSize = config.batchSize || 10;\n this.batchTimeout = config.batchTimeout || 100;\n this.maxConnections = config.maxConnections || 100;\n\n // 初始化重连配置\n this.reconnectOptions = {\n enabled: true,\n maxAttempts: 5,\n initialInterval: 1000,\n maxInterval: 30000,\n backoffStrategy: \"exponential\",\n backoffMultiplier: 1.5,\n timeout: 10000,\n jitter: true,\n ...config.reconnect,\n };\n\n // 初始化重连状态\n this.reconnectState = {\n attempts: 0,\n nextInterval: this.reconnectOptions.initialInterval,\n timer: null,\n lastError: null,\n isManualDisconnect: false,\n };\n }\n\n /**\n * 初始化 WebSocket 适配器\n */\n async initialize(): Promise<void> {\n console.info(`初始化 WebSocket 适配器 (${this.mode} 模式)`);\n\n try {\n this.setState(ConnectionState.CONNECTING);\n this.wsState = WebSocketState.CONNECTING;\n\n if (this.mode === \"client\") {\n await this.initializeClient();\n } else {\n await this.initializeServer();\n }\n\n console.info(\"WebSocket 适配器初始化完成\");\n } catch (error) {\n console.error(\"WebSocket 适配器初始化失败\", error);\n this.setState(ConnectionState.ERROR);\n this.wsState = WebSocketState.FAILED;\n throw error;\n }\n }\n\n /**\n * 初始化客户端模式\n */\n private async initializeClient(): Promise<void> {\n return new Promise((resolve, reject) => {\n // 设置连接超时\n this.connectionTimeout = setTimeout(() => {\n const error = new Error(\n `连接超时 (${this.reconnectOptions.timeout}ms)`\n );\n this.handleConnectionError(error);\n reject(error);\n }, this.reconnectOptions.timeout);\n\n this.ws = new WebSocket(this.endpointUrl);\n\n // 启用压缩\n if (this.compression) {\n // WebSocket 压缩扩展会自动处理\n }\n\n this.ws.on(\"open\", () => {\n this.handleConnectionSuccess();\n resolve();\n });\n\n this.ws.on(\"message\", (data) => {\n this.handleIncomingData(data);\n });\n\n this.ws.on(\"close\", (code, reason) => {\n this.handleConnectionClose(code, reason.toString());\n });\n\n this.ws.on(\"error\", (error) => {\n this.handleConnectionError(error);\n reject(error);\n });\n });\n }\n\n /**\n * 初始化服务器模式\n */\n private async initializeServer(): Promise<void> {\n return new Promise((resolve, reject) => {\n try {\n const url = new URL(this.endpointUrl);\n const port = Number.parseInt(url.port) || 8080;\n\n this.wsServer = new WebSocketServer({\n port,\n perMessageDeflate: this.compression,\n });\n\n this.wsServer.on(\"connection\", (ws, request) => {\n this.handleNewConnection(ws, request);\n });\n\n this.wsServer.on(\"error\", (error) => {\n console.error(\"WebSocket 服务器错误\", error);\n reject(error);\n });\n\n console.info(`WebSocket 服务器监听端口 ${port}`);\n resolve();\n } catch (error) {\n reject(error);\n }\n });\n }\n\n /**\n * 启动 WebSocket 适配器\n */\n async start(): Promise<void> {\n if (this.wsState === WebSocketState.CONNECTED) {\n console.warn(\"WebSocket 适配器已启动\");\n return;\n }\n\n console.info(\"启动 WebSocket 适配器\");\n\n try {\n this.setState(ConnectionState.CONNECTED);\n this.wsState = WebSocketState.CONNECTED;\n\n console.info(\"WebSocket 适配器启动成功\");\n } catch (error) {\n console.error(\"启动 WebSocket 适配器失败\", error);\n this.setState(ConnectionState.ERROR);\n this.wsState = WebSocketState.FAILED;\n throw error;\n }\n }\n\n /**\n * 停止 WebSocket 适配器\n */\n async stop(): Promise<void> {\n console.info(\"停止 WebSocket 适配器\");\n\n try {\n // 标记为手动断开\n this.reconnectState.isManualDisconnect = true;\n\n // 清理重连定时器\n if (this.reconnectState.timer) {\n clearTimeout(this.reconnectState.timer);\n this.reconnectState.timer = null;\n }\n\n // 清理批处理定时器\n if (this.batchTimer) {\n clearTimeout(this.batchTimer);\n this.batchTimer = null;\n }\n\n // 处理剩余的批处理消息\n await this.flushBatchQueue();\n\n // 关闭客户端连接\n if (this.ws) {\n this.ws.close();\n this.ws = null;\n }\n\n // 关闭服务器\n if (this.wsServer) {\n this.wsServer.close();\n this.wsServer = null;\n }\n\n // 关闭所有连接\n for (const [id, connection] of this.connections) {\n connection.close();\n }\n this.connections.clear();\n\n this.setState(ConnectionState.DISCONNECTED);\n this.wsState = WebSocketState.DISCONNECTED;\n\n console.info(\"WebSocket 适配器已停止\");\n } catch (error) {\n console.error(\"停止 WebSocket 适配器时出错\", error);\n throw error;\n }\n }\n\n /**\n * 发送消息\n */\n async sendMessage(message: MCPMessage | MCPResponse): Promise<void> {\n if (this.wsState !== WebSocketState.CONNECTED) {\n throw new Error(`WebSocket 未连接 (状态: ${this.wsState})`);\n }\n\n // 如果启用了批处理,添加到队列\n if (this.batchSize > 1) {\n return this.addToBatchQueue(message);\n }\n\n // 直接发送\n return this.sendMessageDirect(message);\n }\n\n /**\n * 直接发送消息\n */\n private async sendMessageDirect(\n message: MCPMessage | MCPResponse\n ): Promise<void> {\n try {\n const serializedMessage = this.serializeMessage(message);\n\n if (this.mode === \"client\" && this.ws) {\n this.ws.send(serializedMessage);\n } else if (this.mode === \"server\") {\n // 广播到所有连接\n for (const connection of this.connections.values()) {\n if (connection.readyState === WebSocket.OPEN) {\n connection.send(serializedMessage);\n }\n }\n }\n\n console.debug(\"消息已发送\", {\n messageId: message.id,\n method: \"method\" in message ? message.method : \"response\",\n });\n } catch (error) {\n console.error(\"发送消息失败\", error);\n throw error;\n }\n }\n\n /**\n * 添加消息到批处理队列\n */\n private async addToBatchQueue(\n message: MCPMessage | MCPResponse\n ): Promise<void> {\n return new Promise((resolve, reject) => {\n this.batchQueue.push({\n message,\n timestamp: Date.now(),\n resolve,\n reject,\n });\n\n // 如果队列达到批处理大小,立即处理\n if (this.batchQueue.length >= this.batchSize) {\n this.flushBatchQueue();\n } else if (!this.batchTimer) {\n // 设置批处理超时\n this.batchTimer = setTimeout(() => {\n this.flushBatchQueue();\n }, this.batchTimeout);\n }\n });\n }\n\n /**\n * 刷新批处理队列\n */\n private async flushBatchQueue(): Promise<void> {\n if (this.batchQueue.length === 0) {\n return;\n }\n\n // 清理定时器\n if (this.batchTimer) {\n clearTimeout(this.batchTimer);\n this.batchTimer = null;\n }\n\n const batch = this.batchQueue.splice(0);\n\n try {\n // 批量发送消息\n const messages = batch.map((item) => item.message);\n const batchMessage = {\n jsonrpc: \"2.0\" as const,\n method: \"batch\",\n params: { messages },\n id: `batch_${Date.now()}`,\n };\n\n await this.sendMessageDirect(batchMessage);\n\n // 解析所有 Promise\n for (const item of batch) {\n item.resolve();\n }\n\n console.debug(`批处理发送 ${batch.length} 条消息`);\n } catch (error) {\n // 拒绝所有 Promise\n for (const item of batch) {\n item.reject(error as Error);\n }\n console.error(\"批处理发送失败\", error);\n }\n }\n\n /**\n * 处理接收到的数据\n */\n private async handleIncomingData(data: WebSocket.Data): Promise<void> {\n try {\n const messageStr = data.toString();\n const message = this.parseMessage(messageStr);\n\n if (message) {\n // 检查是否是批处理消息\n if (\n message.method === \"batch\" &&\n message.params &&\n typeof message.params === \"object\" &&\n \"messages\" in message.params &&\n Array.isArray((message.params as { messages: unknown[] }).messages)\n ) {\n // 处理批处理消息\n const batchMessages = (message.params as { messages: unknown[] })\n .messages;\n for (const batchedMessage of batchMessages) {\n await this.handleIncomingMessage(batchedMessage as MCPMessage);\n }\n } else {\n await this.handleIncomingMessage(message);\n }\n }\n } catch (error) {\n console.error(\"处理接收数据失败\", error);\n }\n }\n\n /**\n * 处理连接成功\n */\n private handleConnectionSuccess(): void {\n // 清理连接超时定时器\n if (this.connectionTimeout) {\n clearTimeout(this.connectionTimeout);\n this.connectionTimeout = null;\n }\n\n this.setState(ConnectionState.CONNECTED);\n this.wsState = WebSocketState.CONNECTED;\n\n // 重置重连状态\n this.reconnectState.attempts = 0;\n this.reconnectState.nextInterval = this.reconnectOptions.initialInterval;\n this.reconnectState.lastError = null;\n\n console.info(\"WebSocket 连接已建立\");\n }\n\n /**\n * 处理连接错误\n */\n private handleConnectionError(error: Error): void {\n // 清理连接超时定时器\n if (this.connectionTimeout) {\n clearTimeout(this.connectionTimeout);\n this.connectionTimeout = null;\n }\n\n this.reconnectState.lastError = error;\n console.error(\"WebSocket 连接错误\", error);\n\n this.setState(ConnectionState.ERROR);\n this.wsState = WebSocketState.FAILED;\n\n // 清理当前连接\n this.cleanupConnection();\n }\n\n /**\n * 处理连接关闭\n */\n private handleConnectionClose(code: number, reason: string): void {\n this.setState(ConnectionState.DISCONNECTED);\n this.wsState = WebSocketState.DISCONNECTED;\n\n console.info(`WebSocket 连接已关闭 (代码: ${code}, 原因: ${reason})`);\n\n // 如果是手动断开,不进行重连\n if (this.reconnectState.isManualDisconnect) {\n return;\n }\n\n // 检查是否需要重连\n if (this.shouldReconnect()) {\n this.scheduleReconnect();\n } else {\n this.wsState = WebSocketState.FAILED;\n console.warn(\n `已达到最大重连次数 (${this.reconnectOptions.maxAttempts}),停止重连`\n );\n }\n }\n\n /**\n * 处理新连接(服务器模式)\n */\n private handleNewConnection(ws: WebSocket, request: IncomingMessage): void {\n // 检查连接数限制\n if (this.connections.size >= this.maxConnections) {\n console.warn(\"达到最大连接数限制,拒绝新连接\");\n ws.close(1013, \"服务器繁忙\");\n return;\n }\n\n const connectionId = `${this.getConnectionId()}_${this.connections.size}`;\n this.connections.set(connectionId, ws);\n\n console.info(`新 WebSocket 连接: ${connectionId}`);\n\n ws.on(\"message\", (data) => {\n this.handleIncomingData(data);\n });\n\n ws.on(\"close\", () => {\n this.connections.delete(connectionId);\n console.info(`WebSocket 连接已断开: ${connectionId}`);\n });\n\n ws.on(\"error\", (error) => {\n console.error(`WebSocket 连接错误 ${connectionId}:`, error);\n this.connections.delete(connectionId);\n });\n }\n\n /**\n * 清理连接\n */\n private cleanupConnection(): void {\n if (this.ws) {\n this.ws.removeAllListeners();\n this.ws = null;\n }\n }\n\n /**\n * 检查是否应该重连\n */\n private shouldReconnect(): boolean {\n return (\n this.reconnectOptions.enabled &&\n this.reconnectState.attempts < this.reconnectOptions.maxAttempts &&\n !this.reconnectState.isManualDisconnect\n );\n }\n\n /**\n * 安排重连\n */\n private scheduleReconnect(): void {\n this.wsState = WebSocketState.RECONNECTING;\n this.reconnectState.attempts++;\n\n // 计算重连间隔\n let interval = this.calculateReconnectInterval();\n\n // 添加随机抖动\n if (this.reconnectOptions.jitter) {\n interval += Math.random() * 1000;\n }\n\n console.info(\n `安排重连 (第 ${this.reconnectState.attempts} 次,${interval}ms 后)`\n );\n\n this.reconnectState.timer = setTimeout(async () => {\n try {\n await this.initializeClient();\n } catch (error) {\n console.error(\"重连失败\", error);\n\n if (this.shouldReconnect()) {\n this.scheduleReconnect();\n } else {\n this.wsState = WebSocketState.FAILED;\n }\n }\n }, interval);\n }\n\n /**\n * 计算重连间隔\n */\n private calculateReconnectInterval(): number {\n const { backoffStrategy, initialInterval, maxInterval, backoffMultiplier } =\n this.reconnectOptions;\n const attempts = this.reconnectState.attempts;\n\n let interval: number;\n\n switch (backoffStrategy) {\n case \"linear\":\n interval = initialInterval + attempts * 1000;\n break;\n case \"exponential\":\n interval = initialInterval * backoffMultiplier ** attempts;\n break;\n default:\n interval = initialInterval;\n break;\n }\n\n return Math.min(interval, maxInterval);\n }\n\n /**\n * 获取适配器状态\n */\n getStatus(): {\n wsState: WebSocketState;\n connectionState: ConnectionState;\n mode: string;\n endpointUrl: string;\n connectionCount: number;\n reconnectAttempts: number;\n batchQueueSize: number;\n compression: boolean;\n } {\n return {\n wsState: this.wsState,\n connectionState: this.state,\n mode: this.mode,\n endpointUrl: this.endpointUrl,\n connectionCount: this.connections.size,\n reconnectAttempts: this.reconnectState.attempts,\n batchQueueSize: this.batchQueue.length,\n compression: this.compression,\n };\n }\n\n /**\n * 强制重连\n */\n async forceReconnect(): Promise<void> {\n if (this.mode !== \"client\") {\n throw new Error(\"只有客户端模式支持重连\");\n }\n\n console.info(\"强制重连\");\n\n // 重置重连状态\n this.reconnectState.attempts = 0;\n this.reconnectState.isManualDisconnect = false;\n\n // 关闭当前连接\n if (this.ws) {\n this.ws.close();\n }\n\n // 立即重连\n await this.initializeClient();\n }\n}\n","export {\n TransportAdapter,\n ConnectionState,\n type MCPMessage,\n type MCPResponse,\n type MCPError,\n type TransportConfig,\n} from \"./TransportAdapter.js\";\nexport { StdioAdapter, type StdioConfig } from \"./StdioAdapter.js\";\nexport { WebSocketAdapter, type WebSocketConfig } from \"./WebSocketAdapter.js\";\n","#!/usr/bin/env node\n\n/**\n * MCP 服务管理器\n * 使用 MCPService 实例管理多个 MCP 服务\n * 专注于实例管理、工具聚合和路由调用\n */\n\nimport { EventEmitter } from \"node:events\";\nimport { isModelScopeURL } from \"@/lib/config/adapter.js\";\nimport type { MCPToolConfig } from \"@/lib/config/manager.js\";\nimport { configManager } from \"@/lib/config/manager.js\";\nimport { MCPService } from \"@/lib/mcp\";\nimport { MCPCacheManager } from \"@/lib/mcp\";\nimport type {\n CustomMCPTool,\n JSONSchema,\n MCPServiceConfig,\n ManagerStatus,\n ToolCallResult,\n ToolInfo,\n UnifiedServerConfig,\n UnifiedServerStatus,\n} from \"@/lib/mcp/types\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport { getEventBus } from \"@root/services/EventBus.js\";\nimport type { MCPMessage } from \"@root/types/mcp.js\";\nimport { CustomMCPHandler } from \"./custom.js\";\nimport { ToolCallLogger } from \"./log.js\";\nimport { MCPMessageHandler } from \"./message.js\";\nimport { ConnectionState, type TransportAdapter } from \"./transports/index.js\";\n\nexport class MCPServiceManager extends EventEmitter {\n private services: Map<string, MCPService> = new Map();\n private configs: Record<string, MCPServiceConfig> = {};\n private tools: Map<string, ToolInfo> = new Map(); // 缓存工具信息,保持向后兼容\n private customMCPHandler: CustomMCPHandler; // CustomMCP 工具处理器\n private cacheManager: MCPCacheManager; // 缓存管理器\n private eventBus = getEventBus(); // 事件总线\n private toolCallLogger: ToolCallLogger; // 工具调用记录器\n private retryTimers: Map<string, NodeJS.Timeout> = new Map(); // 重试定时器\n private failedServices: Set<string> = new Set(); // 失败的服务集合\n\n // 新增:传输适配器管理\n private transportAdapters: Map<string, TransportAdapter> = new Map();\n private messageHandler: MCPMessageHandler;\n\n // 新增:服务器状态管理(从 UnifiedMCPServer 移入)\n private isRunning = false;\n private config: UnifiedServerConfig;\n\n /**\n * 创建 MCPServiceManager 实例\n * @param configs 可选的初始服务配置或服务器配置\n */\n constructor(\n configs?: Record<string, MCPServiceConfig> | UnifiedServerConfig\n ) {\n super();\n\n // 处理参数,支持 UnifiedServerConfig 格式\n if (configs && this.isUnifiedServerConfig(configs)) {\n // UnifiedServerConfig 格式\n this.config = {\n name: \"MCPServiceManager\",\n enableLogging: true,\n logLevel: \"info\",\n ...configs,\n };\n this.configs = configs.configs || {};\n } else {\n // 原有的 configs 格式\n this.config = {\n name: \"MCPServiceManager\",\n enableLogging: true,\n logLevel: \"info\",\n };\n this.configs = configs || {};\n }\n\n // 在测试环境中使用临时目录,避免在项目根目录创建缓存文件\n const isTestEnv =\n process.env.NODE_ENV === \"test\" || process.env.VITEST === \"true\";\n const cachePath = isTestEnv\n ? `/tmp/xiaozhi-test-${Date.now()}-${Math.random()\n .toString(36)\n .substring(2, 11)}/xiaozhi.cache.json`\n : undefined;\n\n this.cacheManager = new MCPCacheManager(cachePath);\n this.customMCPHandler = new CustomMCPHandler(this.cacheManager, this);\n\n // 初始化工具调用记录器\n const toolCallLogConfig = configManager.getToolCallLogConfig();\n const configDir = configManager.getConfigDir();\n this.toolCallLogger = new ToolCallLogger(toolCallLogConfig, configDir);\n\n // 设置事件监听器\n this.setupEventListeners();\n\n // 初始化消息处理器(确保在其他组件初始化完成后)\n this.messageHandler = new MCPMessageHandler(this);\n }\n\n /**\n * 设置事件监听器\n */\n private setupEventListeners(): void {\n // 监听MCP服务连接成功事件\n this.eventBus.onEvent(\"mcp:service:connected\", async (data) => {\n await this.handleServiceConnected(data);\n });\n\n // 监听MCP服务断开连接事件\n this.eventBus.onEvent(\"mcp:service:disconnected\", async (data) => {\n await this.handleServiceDisconnected(data);\n });\n\n // 监听MCP服务连接失败事件\n this.eventBus.onEvent(\"mcp:service:connection:failed\", async (data) => {\n await this.handleServiceConnectionFailed(data);\n });\n }\n\n /**\n * 处理MCP服务连接成功事件\n */\n private async handleServiceConnected(data: {\n serviceName: string;\n tools: Tool[];\n connectionTime: Date;\n }): Promise<void> {\n console.debug(`服务 ${data.serviceName} 连接成功,开始刷新工具缓存`);\n\n try {\n // 获取最新的工具列表\n const service = this.services.get(data.serviceName);\n if (service) {\n // 重新初始化CustomMCPHandler\n await this.refreshCustomMCPHandlerPublic();\n\n console.info(`服务 ${data.serviceName} 工具缓存刷新完成`);\n }\n } catch (error) {\n console.error(`刷新服务 ${data.serviceName} 工具缓存失败:`, error);\n }\n }\n\n /**\n * 处理MCP服务断开连接事件\n */\n private async handleServiceDisconnected(data: {\n serviceName: string;\n reason?: string;\n disconnectionTime: Date;\n }): Promise<void> {\n console.info(\n `服务 ${data.serviceName} 断开连接,原因: ${data.reason || \"未知\"}`\n );\n\n try {\n // 更新工具缓存\n await this.refreshToolsCache();\n\n // 重新初始化CustomMCPHandler\n await this.refreshCustomMCPHandlerPublic();\n\n console.info(`服务 ${data.serviceName} 断开连接处理完成`);\n } catch (error) {\n console.error(`服务 ${data.serviceName} 断开连接处理失败:`, error);\n }\n }\n\n /**\n * 处理MCP服务连接失败事件\n */\n private async handleServiceConnectionFailed(data: {\n serviceName: string;\n error: Error;\n attempt: number;\n }): Promise<void> {\n try {\n await this.refreshCustomMCPHandlerPublic();\n } catch (error) {\n console.error(\"刷新CustomMCPHandler失败:\", error);\n }\n }\n\n /**\n * 启动所有 MCP 服务\n */\n async startAllServices(): Promise<void> {\n console.debug(\"[MCPManager] 正在启动所有 MCP 服务...\");\n\n // 初始化 CustomMCP 处理器\n try {\n this.customMCPHandler.initialize();\n console.debug(\"[MCPManager] CustomMCP 处理器初始化完成\");\n } catch (error) {\n console.error(\"[MCPManager] CustomMCP 处理器初始化失败:\", error);\n // CustomMCP 初始化失败不应该阻止标准 MCP 服务启动\n }\n\n const configEntries = Object.entries(this.configs);\n if (configEntries.length === 0) {\n console.warn(\n \"[MCPManager] 没有配置任何 MCP 服务,请使用 addServiceConfig() 添加服务配置\"\n );\n // 即使没有标准 MCP 服务,也可能有 CustomMCP 工具\n return;\n }\n\n // 记录启动开始\n console.info(\n `[MCPManager] 开始并行启动 ${configEntries.length} 个 MCP 服务`\n );\n\n // 并行启动所有服务,实现服务隔离\n const startPromises = configEntries.map(async ([serviceName]) => {\n try {\n await this.startService(serviceName);\n return { serviceName, success: true, error: null };\n } catch (error) {\n return {\n serviceName,\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n });\n\n // 等待所有服务启动完成\n const results = await Promise.allSettled(startPromises);\n\n // 统计启动结果\n let successCount = 0;\n let failureCount = 0;\n const failedServices: string[] = [];\n\n for (const result of results) {\n if (result.status === \"fulfilled\") {\n if (result.value.success) {\n successCount++;\n } else {\n failureCount++;\n failedServices.push(result.value.serviceName);\n }\n } else {\n failureCount++;\n }\n }\n\n // 记录启动完成统计\n console.info(\n `[MCPManager] 服务启动完成 - 成功: ${successCount}, 失败: ${failureCount}`\n );\n\n // 记录失败的服务列表\n if (failedServices.length > 0) {\n console.warn(\n `[MCPManager] 以下服务启动失败: ${failedServices.join(\", \")}`\n );\n\n // 如果所有服务都失败了,发出警告但系统继续运行以便重试\n if (failureCount === configEntries.length) {\n console.warn(\n \"[MCPManager] 所有 MCP 服务启动失败,但系统将继续运行以便重试\"\n );\n }\n }\n\n // 启动失败服务重试机制\n if (failedServices.length > 0) {\n this.scheduleFailedServicesRetry(failedServices);\n }\n }\n\n /**\n * 启动单个 MCP 服务\n */\n async startService(serviceName: string): Promise<void> {\n const config = this.configs[serviceName];\n if (!config) {\n throw new Error(`未找到服务配置: ${serviceName}`);\n }\n\n try {\n // 如果服务已存在,先停止它\n if (this.services.has(serviceName)) {\n await this.stopService(serviceName);\n }\n\n // 创建 MCPService 实例\n const service = new MCPService(config);\n\n // 连接到服务\n await service.connect();\n\n // 存储服务实例\n this.services.set(serviceName, service);\n\n // 更新工具缓存\n await this.refreshToolsCache();\n\n // 注意:工具缓存刷新现在通过事件监听器自动处理,不需要在这里手动调用\n // MCPService.connect() 成功后会发射 mcp:service:connected 事件\n // 事件监听器会自动触发工具缓存刷新和CustomMCPHandler刷新\n\n const tools = service.getTools();\n console.debug(\n `[MCPManager] ${serviceName} 服务启动成功,加载了 ${tools.length} 个工具:`,\n tools.map((t) => t.name).join(\", \")\n );\n } catch (error) {\n console.error(\n `[MCPManager] 启动 ${serviceName} 服务失败:`,\n (error as Error).message\n );\n // 清理可能的部分状态\n this.services.delete(serviceName);\n throw error;\n }\n }\n\n /**\n * 停止单个服务\n */\n async stopService(serviceName: string): Promise<void> {\n console.info(`[MCPManager] 停止 MCP 服务: ${serviceName}`);\n\n const service = this.services.get(serviceName);\n if (!service) {\n console.warn(`[MCPManager] 服务 ${serviceName} 不存在或未启动`);\n return;\n }\n\n try {\n await service.disconnect();\n this.services.delete(serviceName);\n\n // 更新工具缓存\n await this.refreshToolsCache();\n\n console.info(`[MCPManager] ${serviceName} 服务已停止`);\n } catch (error) {\n console.error(\n `[MCPManager] 停止 ${serviceName} 服务失败:`,\n (error as Error).message\n );\n throw error;\n }\n }\n\n /**\n * 刷新工具缓存\n */\n private async refreshToolsCache(): Promise<void> {\n this.tools.clear();\n\n for (const [serviceName, service] of this.services) {\n if (service.isConnected()) {\n const tools = service.getTools();\n const config = this.configs[serviceName];\n\n // 异步写入缓存(不阻塞主流程)\n if (config) {\n this.cacheManager\n .writeCacheEntry(serviceName, tools, config)\n .then(() => {\n console.debug(\n `[MCPManager] 已将 ${serviceName} 工具列表写入缓存`\n );\n })\n .catch((error) => {\n console.warn(\n `[MCPManager] 写入缓存失败: ${serviceName}, 错误: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n });\n }\n\n // 原有逻辑保持不变\n for (const tool of tools) {\n const toolKey = `${serviceName}__${tool.name}`;\n this.tools.set(toolKey, {\n serviceName,\n originalName: tool.name,\n tool,\n });\n }\n }\n }\n\n // 同步工具配置到配置文件\n await this.syncToolsConfigToFile();\n }\n\n /**\n * 获取所有可用工具(优化版本,移除阻塞逻辑,添加工具启用状态过滤)\n */\n getAllTools(): Array<{\n name: string;\n description: string;\n inputSchema: JSONSchema;\n serviceName: string;\n originalName: string;\n }> {\n const allTools: Array<{\n name: string;\n description: string;\n inputSchema: JSONSchema;\n serviceName: string;\n originalName: string;\n }> = [];\n\n // 1. 收集所有已连接服务的工具(包含启用状态过滤)\n for (const [serviceName, service] of this.services) {\n try {\n if (service.isConnected()) {\n const serviceTools = service.getTools();\n for (const tool of serviceTools) {\n try {\n // 检查工具启用状态 - 这个调用可能会抛出异常\n const isEnabled = configManager.isToolEnabled(\n serviceName,\n tool.name\n );\n if (!isEnabled) {\n continue; // 跳过禁用的工具\n }\n\n const toolKey = `${serviceName}__${tool.name}`;\n allTools.push({\n name: toolKey,\n description: tool.description || \"\",\n inputSchema: tool.inputSchema,\n serviceName,\n originalName: tool.name,\n });\n } catch (toolError) {\n console.warn(\n `[MCPManager] 检查工具 ${serviceName}.${tool.name} 启用状态失败,跳过该工具:`,\n toolError\n );\n }\n }\n }\n } catch (serviceError) {\n console.warn(\n `[MCPManager] 获取服务 ${serviceName} 的工具失败,跳过该服务:`,\n serviceError\n );\n }\n }\n\n // 2. 添加CustomMCP工具(添加异常处理确保优雅降级)\n let customTools: Tool[] = [];\n try {\n customTools = this.customMCPHandler.getTools();\n console.debug(\n `[MCPManager] 成功获取 ${customTools.length} 个 customMCP 工具`\n );\n } catch (error) {\n console.warn(\n \"[MCPManager] 获取 CustomMCP 工具失败,将只返回标准 MCP 工具:\",\n error\n );\n // 根据技术方案要求,CustomMCP 工具获取失败时不应该影响标准 MCP 工具的返回\n customTools = [];\n }\n\n for (const tool of customTools) {\n try {\n allTools.push({\n name: tool.name,\n description: tool.description || \"\",\n inputSchema: tool.inputSchema,\n serviceName: this.getServiceNameForTool(tool),\n originalName: tool.name,\n });\n } catch (toolError) {\n console.warn(\n `[MCPManager] 处理 CustomMCP 工具 ${tool.name} 失败,跳过该工具:`,\n toolError\n );\n }\n }\n\n console.debug(`[MCPManager] 成功获取 ${allTools.length} 个可用工具`);\n return allTools;\n }\n\n /**\n * 根据工具配置确定服务名称\n * @param tool 工具对象\n * @returns 服务名称\n */\n private getServiceNameForTool(tool: CustomMCPTool): string {\n if (tool.handler?.type === \"mcp\") {\n // 如果是从 MCP 同步的工具,返回原始服务名称\n const config = tool.handler.config as\n | { serviceName?: string; toolName?: string }\n | undefined;\n return config?.serviceName || \"customMCP\";\n }\n return \"customMCP\";\n }\n\n /**\n * 根据工具信息获取日志记录用的服务名称\n * @param customTool CustomMCP 工具信息\n * @returns 用于日志记录的服务名称\n */\n private getLogServerName(customTool: CustomMCPTool): string {\n if (!customTool?.handler) {\n return \"custom\";\n }\n\n switch (customTool.handler.type) {\n case \"mcp\": {\n const config = customTool.handler.config as\n | { serviceName?: string; toolName?: string }\n | undefined;\n return config?.serviceName || \"customMCP\";\n }\n case \"coze\":\n return \"coze\";\n case \"dify\":\n return \"dify\";\n case \"n8n\":\n return \"n8n\";\n default:\n return \"custom\";\n }\n }\n\n /**\n * 根据工具信息获取原始工具名称\n * @param toolName 格式化后的工具名称\n * @param customTool CustomMCP 工具信息\n * @param toolInfo 标准工具信息\n * @returns 原始工具名称\n */\n private getOriginalToolName(\n toolName: string,\n customTool: CustomMCPTool | undefined,\n toolInfo?: ToolInfo\n ): string {\n if (customTool) {\n // CustomMCP 工具\n if (customTool.handler?.type === \"mcp\") {\n const config = customTool.handler.config as\n | { serviceName?: string; toolName?: string }\n | undefined;\n return config?.toolName || toolName;\n }\n return toolName;\n }\n\n // 标准 MCP 工具\n return toolInfo?.originalName || toolName;\n }\n\n /**\n * 调用 MCP 工具(支持标准 MCP 工具和 customMCP 工具)\n */\n async callTool(\n toolName: string,\n arguments_: Record<string, unknown>,\n options?: { timeout?: number }\n ): Promise<ToolCallResult> {\n const startTime = Date.now();\n\n // 初始化日志信息\n let logServerName = \"unknown\";\n let originalToolName: string = toolName;\n\n try {\n let result: ToolCallResult;\n\n // 检查是否是 customMCP 工具\n if (this.customMCPHandler.hasTool(toolName)) {\n const customTool = this.customMCPHandler.getToolInfo(toolName);\n\n // 设置日志信息(添加空值检查)\n if (customTool) {\n logServerName = this.getLogServerName(customTool);\n originalToolName = this.getOriginalToolName(toolName, customTool);\n }\n\n if (customTool?.handler?.type === \"mcp\") {\n // 对于 mcp 类型的工具,直接路由到对应的 MCP 服务\n result = await this.callMCPTool(\n toolName,\n customTool.handler.config,\n arguments_\n );\n\n // 异步更新工具调用统计(成功调用)\n this.updateToolStatsSafe(\n toolName,\n customTool.handler.config.serviceName,\n customTool.handler.config.toolName,\n true\n );\n } else {\n // 其他类型的 customMCP 工具正常处理,传递options参数\n result = await this.customMCPHandler.callTool(\n toolName,\n arguments_,\n options\n );\n console.info(`[MCPManager] CustomMCP 工具 ${toolName} 调用成功`);\n\n // 异步更新工具调用统计(成功调用)\n this.updateToolStatsSafe(toolName, \"customMCP\", toolName, true);\n }\n } else {\n // 如果不是 customMCP 工具,则查找标准 MCP 工具\n const toolInfo = this.tools.get(toolName);\n if (!toolInfo) {\n throw new Error(`未找到工具: ${toolName}`);\n }\n\n // 设置日志信息\n logServerName = toolInfo.serviceName;\n originalToolName = toolInfo.originalName;\n\n const service = this.services.get(toolInfo.serviceName);\n if (!service) {\n throw new Error(`服务 ${toolInfo.serviceName} 不可用`);\n }\n\n if (!service.isConnected()) {\n throw new Error(`服务 ${toolInfo.serviceName} 未连接`);\n }\n\n result = await service.callTool(\n toolInfo.originalName,\n arguments_ || {}\n );\n\n console.debug(\"[MCPManager] 工具调用成功\", {\n toolName: toolName,\n result: result,\n });\n\n // 异步更新工具调用统计(成功调用)\n this.updateToolStatsSafe(\n toolName,\n toolInfo.serviceName,\n toolInfo.originalName,\n true\n );\n }\n\n // 记录成功的工具调用\n this.toolCallLogger.recordToolCall({\n toolName: originalToolName,\n serverName: logServerName,\n arguments: arguments_,\n result: result,\n success: result.isError !== true,\n duration: Date.now() - startTime,\n });\n\n return result as ToolCallResult;\n } catch (error) {\n // 记录失败的工具调用\n this.toolCallLogger.recordToolCall({\n toolName: originalToolName,\n serverName: logServerName,\n arguments: arguments_,\n result: null,\n success: false,\n duration: Date.now() - startTime,\n error: error instanceof Error ? error.message : String(error),\n });\n\n // 更新失败统计\n if (this.customMCPHandler.hasTool(toolName)) {\n const customTool = this.customMCPHandler.getToolInfo(toolName);\n if (customTool?.handler?.type === \"mcp\") {\n this.updateToolStatsSafe(\n toolName,\n customTool.handler.config.serviceName,\n customTool.handler.config.toolName,\n false\n );\n } else {\n this.updateToolStatsSafe(toolName, \"customMCP\", toolName, false);\n console.error(\n `[MCPManager] CustomMCP 工具 ${toolName} 调用失败:`,\n (error as Error).message\n );\n }\n } else {\n const toolInfo = this.tools.get(toolName);\n if (toolInfo) {\n this.updateToolStatsSafe(\n toolName,\n toolInfo.serviceName,\n toolInfo.originalName,\n false\n );\n console.error(\n `[MCPManager] 工具 ${toolName} 调用失败:`,\n (error as Error).message\n );\n }\n }\n\n throw error;\n }\n }\n\n /**\n * 更新工具调用统计信息的通用方法\n * @param toolName 工具名称\n * @param serviceName 服务名称\n * @param originalToolName 原始工具名称\n * @param isSuccess 是否调用成功\n * @private\n */\n private async updateToolStats(\n toolName: string,\n serviceName: string,\n originalToolName: string,\n isSuccess: boolean\n ): Promise<void> {\n try {\n const currentTime = new Date().toISOString();\n\n if (isSuccess) {\n // 成功调用:更新使用统计\n await this.updateCustomMCPToolStats(toolName, currentTime);\n\n // 如果是 MCP 服务工具,同时更新 mcpServerConfig 配置(双写机制)\n if (serviceName !== \"customMCP\") {\n await this.updateMCPServerToolStats(\n serviceName,\n originalToolName,\n currentTime\n );\n }\n\n console.debug(`[MCPManager] 已更新工具 ${toolName} 的统计信息`);\n } else {\n // 失败调用:只更新最后使用时间\n await this.updateCustomMCPToolLastUsedTime(toolName, currentTime);\n\n // 如果是 MCP 服务工具,同时更新 mcpServerConfig 配置(双写机制)\n if (serviceName !== \"customMCP\") {\n await this.updateMCPServerToolLastUsedTime(\n serviceName,\n originalToolName,\n currentTime\n );\n }\n\n console.debug(\"[MCPManager] 已更新工具的失败调用统计信息\", {\n toolName,\n });\n }\n } catch (error) {\n console.error(\"[MCPManager] 更新工具统计信息失败:\", { toolName, error });\n throw error;\n }\n }\n\n /**\n * 统一的统计更新处理方法(带错误处理)\n * @param toolName 工具名称\n * @param serviceName 服务名称\n * @param originalToolName 原始工具名称\n * @param isSuccess 是否调用成功\n * @private\n */\n private async updateToolStatsSafe(\n toolName: string,\n serviceName: string,\n originalToolName: string,\n isSuccess: boolean\n ): Promise<void> {\n try {\n await this.updateToolStats(\n toolName,\n serviceName,\n originalToolName,\n isSuccess\n );\n } catch (error) {\n const action = isSuccess ? \"统计信息\" : \"失败统计信息\";\n console.warn(\"[MCPManager] 更新工具统计信息失败:\", {\n toolName,\n action,\n error,\n });\n // 统计更新失败不应该影响主流程,所以这里只记录警告\n }\n }\n\n /**\n * 更新 customMCP 工具统计信息\n * @param toolName 工具名称\n * @param currentTime 当前时间\n * @private\n */\n private async updateCustomMCPToolStats(\n toolName: string,\n currentTime: string\n ): Promise<void> {\n try {\n await configManager.updateToolUsageStatsWithLock(toolName, true);\n console.debug(`[MCPManager] 已更新 customMCP 工具 ${toolName} 使用统计`);\n } catch (error) {\n console.error(\n `[MCPManager] 更新 customMCP 工具 ${toolName} 统计失败:`,\n error\n );\n throw error;\n }\n }\n\n /**\n * 更新 customMCP 工具最后使用时间\n * @param toolName 工具名称\n * @param currentTime 当前时间\n * @private\n */\n private async updateCustomMCPToolLastUsedTime(\n toolName: string,\n currentTime: string\n ): Promise<void> {\n try {\n await configManager.updateToolUsageStatsWithLock(toolName, false); // 只更新时间,不增加计数\n console.debug(\n `[MCPManager] 已更新 customMCP 工具 ${toolName} 最后使用时间`\n );\n } catch (error) {\n console.error(\n `[MCPManager] 更新 customMCP 工具 ${toolName} 最后使用时间失败:`,\n error\n );\n throw error;\n }\n }\n\n /**\n * 更新 MCP 服务工具统计信息\n * @param serviceName 服务名称\n * @param toolName 工具名称\n * @param currentTime 当前时间\n * @private\n */\n private async updateMCPServerToolStats(\n serviceName: string,\n toolName: string,\n currentTime: string\n ): Promise<void> {\n try {\n await configManager.updateMCPServerToolStatsWithLock(\n serviceName,\n toolName,\n currentTime,\n true\n );\n console.debug(\n `[MCPManager] 已更新 MCP 服务工具 ${serviceName}/${toolName} 统计`\n );\n } catch (error) {\n console.error(\n `[MCPManager] 更新 MCP 服务工具 ${serviceName}/${toolName} 统计失败:`,\n error\n );\n throw error;\n }\n }\n\n /**\n * 更新 MCP 服务工具最后使用时间\n * @param serviceName 服务名称\n * @param toolName 工具名称\n * @param currentTime 当前时间\n * @private\n */\n private async updateMCPServerToolLastUsedTime(\n serviceName: string,\n toolName: string,\n currentTime: string\n ): Promise<void> {\n try {\n await configManager.updateMCPServerToolStatsWithLock(\n serviceName,\n toolName,\n currentTime,\n false\n ); // 只更新时间,不增加计数\n console.debug(\n `[MCPManager] 已更新 MCP 服务工具 ${serviceName}/${toolName} 最后使用时间`\n );\n } catch (error) {\n console.error(\n `[MCPManager] 更新 MCP 服务工具 ${serviceName}/${toolName} 最后使用时间失败:`,\n error\n );\n throw error;\n }\n }\n\n /**\n * 调用 MCP 工具(用于从 mcpServerConfig 同步的工具)\n * @param toolName 工具名称\n * @param config MCP handler 配置\n * @param arguments_ 工具参数\n */\n private async callMCPTool(\n toolName: string,\n config: { serviceName: string; toolName: string },\n arguments_: Record<string, unknown>\n ): Promise<ToolCallResult> {\n const { serviceName, toolName: originalToolName } = config;\n\n console.debug(\n `[MCPManager] 调用 MCP 同步工具 ${toolName} -> ${serviceName}.${originalToolName}`\n );\n\n const service = this.services.get(serviceName);\n if (!service) {\n throw new Error(`服务 ${serviceName} 不可用`);\n }\n\n if (!service.isConnected()) {\n throw new Error(`服务 ${serviceName} 未连接`);\n }\n\n try {\n const result = await service.callTool(originalToolName, arguments_ || {});\n console.debug(`[MCPManager] MCP 同步工具 ${toolName} 调用成功`);\n return result as ToolCallResult;\n } catch (error) {\n console.error(\n `[MCPManager] MCP 同步工具 ${toolName} 调用失败:`,\n (error as Error).message\n );\n throw error;\n }\n }\n\n /**\n * 检查是否存在指定工具(包括标准 MCP 工具和 customMCP 工具)\n */\n hasTool(toolName: string): boolean {\n // 检查是否是 customMCP 工具\n if (this.customMCPHandler.hasTool(toolName)) {\n return true;\n }\n\n // 检查是否是标准 MCP 工具\n return this.tools.has(toolName);\n }\n\n /**\n * 停止所有服务\n */\n async stopAllServices(): Promise<void> {\n console.info(\"[MCPManager] 正在停止所有 MCP 服务...\");\n\n // 停止所有服务重试\n this.stopAllServiceRetries();\n\n // 停止所有服务实例\n for (const [serviceName, service] of this.services) {\n try {\n await service.disconnect();\n console.info(`[MCPManager] ${serviceName} 服务已停止`);\n } catch (error) {\n console.error(\n `[MCPManager] 停止 ${serviceName} 服务失败:`,\n (error as Error).message\n );\n }\n }\n\n // 清理 CustomMCP 处理器\n try {\n this.customMCPHandler.cleanup();\n console.info(\"[MCPManager] CustomMCP 处理器已清理\");\n } catch (error) {\n console.error(\"[MCPManager] CustomMCP 处理器清理失败:\", error);\n }\n\n // 清理统计更新锁\n try {\n configManager.clearAllStatsUpdateLocks();\n console.info(\"[MCPManager] 统计更新锁已清理\");\n } catch (error) {\n console.error(\"[MCPManager] 清理统计更新锁失败:\", error);\n }\n\n this.services.clear();\n this.tools.clear();\n\n console.info(\"[MCPManager] 所有 MCP 服务已停止\");\n }\n\n /**\n * 获取服务器状态(兼容 UnifiedServerStatus 格式)\n */\n getStatus(): UnifiedServerStatus {\n return this.getUnifiedStatus();\n }\n\n /**\n * 获取统计更新监控信息\n */\n getStatsUpdateInfo(): {\n activeLocks: string[];\n totalLocks: number;\n } {\n try {\n const activeLocks = configManager.getStatsUpdateLocks();\n return {\n activeLocks,\n totalLocks: activeLocks.length,\n };\n } catch (error) {\n console.warn(\"[MCPManager] 获取统计更新监控信息失败:\", error);\n return {\n activeLocks: [],\n totalLocks: 0,\n };\n }\n }\n\n /**\n * 获取指定服务实例\n */\n getService(name: string): MCPService | undefined {\n return this.services.get(name);\n }\n\n /**\n * 获取所有已连接的服务名称\n */\n getConnectedServices(): string[] {\n const connectedServices: string[] = [];\n for (const [serviceName, service] of this.services) {\n if (service.isConnected()) {\n connectedServices.push(serviceName);\n }\n }\n return connectedServices;\n }\n\n /**\n * 刷新CustomMCPHandler的私有方法\n */\n private async refreshCustomMCPHandler(): Promise<void> {\n try {\n console.debug(\"重新初始化CustomMCPHandler\");\n this.customMCPHandler.initialize();\n console.debug(\"CustomMCPHandler重新初始化完成\");\n } catch (error) {\n console.error(\"CustomMCPHandler重新初始化失败:\", error);\n throw error;\n }\n }\n\n /**\n * 公开的CustomMCPHandler刷新方法,供外部调用\n */\n async refreshCustomMCPHandlerPublic(): Promise<void> {\n return this.refreshCustomMCPHandler();\n }\n\n /**\n * 获取所有服务实例\n */\n getAllServices(): Map<string, MCPService> {\n return new Map(this.services);\n }\n\n /**\n * 获取 CustomMCP 处理器实例\n */\n getCustomMCPHandler(): CustomMCPHandler {\n return this.customMCPHandler;\n }\n\n /**\n * 检查指定的 customMCP 工具是否存在\n * @param toolName 工具名称\n * @returns 如果工具存在返回 true,否则返回 false\n */\n hasCustomMCPTool(toolName: string): boolean {\n try {\n return this.customMCPHandler.hasTool(toolName);\n } catch (error) {\n console.warn(\n `[MCPManager] 检查 CustomMCP 工具 ${toolName} 是否存在失败:`,\n error\n );\n // 异常情况下返回 false,表示工具不存在\n return false;\n }\n }\n\n /**\n * 获取所有 customMCP 工具列表\n * @returns customMCP 工具数组\n */\n getCustomMCPTools(): Tool[] {\n try {\n return this.customMCPHandler.getTools();\n } catch (error) {\n console.warn(\n \"[MCPManager] 获取 CustomMCP 工具列表失败,返回空数组:\",\n error\n );\n // 异常情况下返回空数组,避免影响调用方\n return [];\n }\n }\n\n /**\n * 检查是否为 ModelScope 服务\n * 统一使用 ConfigAdapter 的 isModelScopeURL 函数\n */\n private isModelScopeService(config: MCPServiceConfig): boolean {\n return config.url ? isModelScopeURL(config.url) : false;\n }\n\n /**\n * 处理 ModelScope 服务认证\n * 智能检查现有认证信息,按优先级处理\n */\n private handleModelScopeAuth(\n originalConfig: MCPServiceConfig,\n enhancedConfig: MCPServiceConfig\n ): void {\n // 1. 检查是否已有 Authorization header\n const existingAuthHeader = originalConfig.headers?.Authorization;\n\n if (existingAuthHeader) {\n // 已有认证信息,直接使用\n console.info(\n `[MCPManager] 服务 ${originalConfig.name} 使用已有的 Authorization header`\n );\n return;\n }\n\n // 2. 检查全局 ModelScope API Key\n const modelScopeApiKey = configManager.getModelScopeApiKey();\n\n if (modelScopeApiKey) {\n // 注入全局 API Key\n enhancedConfig.apiKey = modelScopeApiKey;\n console.info(\n `[MCPManager] 为 ${originalConfig.name} 服务添加 ModelScope API Key`\n );\n return;\n }\n\n // 3. 无法获取认证信息,提供详细错误信息\n const serviceUrl = originalConfig.url || \"未知\";\n const serviceName = originalConfig.name || \"未知\";\n\n throw new Error(\n `ModelScope 服务 \"${serviceName}\" 需要认证信息,但未找到有效的认证配置。服务 URL: ${serviceUrl}请选择以下任一方式配置认证:1. 在服务配置中添加 headers.Authorization2. 或者在全局配置中设置 modelscope.apiKey3. 或者设置环境变量 MODELSCOPE_API_TOKEN获取 ModelScope API Key: https://modelscope.cn/my?myInfo=true`\n );\n }\n\n /**\n * 增强服务配置\n * 根据服务类型添加必要的全局配置,智能处理认证信息\n */\n private enhanceServiceConfig(config: MCPServiceConfig): MCPServiceConfig {\n const enhancedConfig = { ...config };\n\n try {\n // 处理 ModelScope 服务(智能认证检查)\n if (this.isModelScopeService(config)) {\n this.handleModelScopeAuth(config, enhancedConfig);\n }\n\n return enhancedConfig;\n } catch (error) {\n console.error(`[MCPManager] 配置增强失败: ${config.name}`, error);\n throw error;\n }\n }\n\n /**\n * 添加服务配置(重载方法以支持两种调用方式)\n */\n addServiceConfig(name: string, config: MCPServiceConfig): void;\n addServiceConfig(config: MCPServiceConfig): void;\n addServiceConfig(\n nameOrConfig: string | MCPServiceConfig,\n config?: MCPServiceConfig\n ): void {\n let finalConfig: MCPServiceConfig;\n let serviceName: string;\n\n if (typeof nameOrConfig === \"string\" && config) {\n // 两参数版本\n serviceName = nameOrConfig;\n finalConfig = config;\n } else if (typeof nameOrConfig === \"object\") {\n // 单参数版本\n serviceName = nameOrConfig.name;\n finalConfig = nameOrConfig;\n } else {\n throw new Error(\"Invalid arguments for addServiceConfig\");\n }\n\n // 增强配置\n const enhancedConfig = this.enhanceServiceConfig(finalConfig);\n\n // 存储增强后的配置\n this.configs[serviceName] = enhancedConfig;\n console.debug(`[MCPManager] 已添加服务配置: ${serviceName}`);\n }\n\n /**\n * 更新服务配置\n */\n updateServiceConfig(name: string, config: MCPServiceConfig): void {\n // 增强配置\n const enhancedConfig = this.enhanceServiceConfig(config);\n\n // 存储增强后的配置\n this.configs[name] = enhancedConfig;\n console.debug(`[MCPManager] 已更新并增强服务配置: ${name}`);\n }\n\n /**\n * 移除服务配置\n */\n removeServiceConfig(name: string): void {\n delete this.configs[name];\n console.debug(`[MCPManager] 已移除服务配置: ${name}`);\n }\n\n /**\n * 同步工具配置到配置文件\n * 实现自动同步 MCP 服务工具配置到 xiaozhi.config.json\n */\n private async syncToolsConfigToFile(): Promise<void> {\n try {\n console.debug(\"[MCPManager] 开始同步工具配置到配置文件\");\n\n // 获取当前配置文件中的 mcpServerConfig\n const currentServerConfigs = configManager.getMcpServerConfig();\n\n // 遍历所有已连接的服务\n for (const [serviceName, service] of this.services) {\n if (!service.isConnected()) {\n continue;\n }\n\n const tools = service.getTools();\n if (tools.length === 0) {\n continue;\n }\n\n // 获取当前服务在配置文件中的工具配置\n const currentToolsConfig =\n currentServerConfigs[serviceName]?.tools || {};\n\n // 构建新的工具配置\n const newToolsConfig: Record<string, MCPToolConfig> = {};\n\n for (const tool of tools) {\n const currentToolConfig = currentToolsConfig[tool.name];\n\n // 如果工具已存在,保留用户设置的 enable 状态,但更新描述\n if (currentToolConfig) {\n newToolsConfig[tool.name] = {\n ...currentToolConfig,\n description:\n tool.description || currentToolConfig.description || \"\",\n };\n } else {\n // 新工具,默认启用\n newToolsConfig[tool.name] = {\n description: tool.description || \"\",\n enable: true,\n };\n }\n }\n\n // 检查是否有工具被移除(在配置文件中存在但在当前工具列表中不存在)\n const currentToolNames = tools.map((t) => t.name);\n const configToolNames = Object.keys(currentToolsConfig);\n const removedTools = configToolNames.filter(\n (name) => !currentToolNames.includes(name)\n );\n\n if (removedTools.length > 0) {\n console.info(\n `[MCPManager] 检测到服务 ${serviceName} 移除了 ${\n removedTools.length\n } 个工具: ${removedTools.join(\", \")}`\n );\n }\n\n // 检查配置是否有变化\n const hasChanges = this.hasToolsConfigChanged(\n currentToolsConfig,\n newToolsConfig\n );\n\n if (hasChanges) {\n // 更新配置文件\n configManager.updateServerToolsConfig(serviceName, newToolsConfig);\n\n const addedTools = Object.keys(newToolsConfig).filter(\n (name) => !currentToolsConfig[name]\n );\n const updatedTools = Object.keys(newToolsConfig).filter((name) => {\n const current = currentToolsConfig[name];\n const updated = newToolsConfig[name];\n return current && current.description !== updated.description;\n });\n\n console.debug(`[MCPManager] 已同步服务 ${serviceName} 的工具配置:`);\n if (addedTools.length > 0) {\n console.debug(` - 新增工具: ${addedTools.join(\", \")}`);\n }\n if (updatedTools.length > 0) {\n console.debug(` - 更新工具: ${updatedTools.join(\", \")}`);\n }\n if (removedTools.length > 0) {\n console.debug(` - 移除工具: ${removedTools.join(\", \")}`);\n }\n }\n }\n\n console.debug(\"[MCPManager] 工具配置同步完成\");\n } catch (error) {\n console.error(\"[MCPManager] 同步工具配置到配置文件失败:\", error);\n // 不抛出错误,避免影响服务正常运行\n }\n }\n\n /**\n * 检查工具配置是否有变化\n */\n private hasToolsConfigChanged(\n currentConfig: Record<string, MCPToolConfig>,\n newConfig: Record<string, MCPToolConfig>\n ): boolean {\n const currentKeys = Object.keys(currentConfig);\n const newKeys = Object.keys(newConfig);\n\n // 检查工具数量是否变化\n if (currentKeys.length !== newKeys.length) {\n return true;\n }\n\n // 检查是否有新增或删除的工具\n const addedTools = newKeys.filter((key) => !currentKeys.includes(key));\n const removedTools = currentKeys.filter((key) => !newKeys.includes(key));\n\n if (addedTools.length > 0 || removedTools.length > 0) {\n return true;\n }\n\n // 检查现有工具的描述是否有变化\n for (const toolName of currentKeys) {\n const currentTool = currentConfig[toolName];\n const newTool = newConfig[toolName];\n\n if (currentTool.description !== newTool.description) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * 安排失败服务的重试\n * @param failedServices 失败的服务列表\n */\n private scheduleFailedServicesRetry(failedServices: string[]): void {\n if (failedServices.length === 0) return;\n\n // 记录重试安排\n console.info(`[MCPManager] 安排 ${failedServices.length} 个失败服务的重试`);\n\n // 初始重试延迟:30秒\n const initialDelay = 30000;\n\n for (const serviceName of failedServices) {\n this.failedServices.add(serviceName);\n this.scheduleServiceRetry(serviceName, initialDelay);\n }\n }\n\n /**\n * 安排单个服务的重试\n * @param serviceName 服务名称\n * @param delay 延迟时间(毫秒)\n */\n private scheduleServiceRetry(serviceName: string, delay: number): void {\n // 清除现有定时器\n const existingTimer = this.retryTimers.get(serviceName);\n if (existingTimer) {\n clearTimeout(existingTimer);\n this.retryTimers.delete(serviceName);\n }\n\n console.debug(`[MCPManager] 安排服务 ${serviceName} 在 ${delay}ms 后重试`);\n\n const timer = setTimeout(async () => {\n this.retryTimers.delete(serviceName);\n await this.retryFailedService(serviceName);\n }, delay);\n\n this.retryTimers.set(serviceName, timer);\n }\n\n /**\n * 重试失败的服务\n * @param serviceName 服务名称\n */\n private async retryFailedService(serviceName: string): Promise<void> {\n if (!this.failedServices.has(serviceName)) {\n return; // 服务已经成功启动或不再需要重试\n }\n\n try {\n await this.startService(serviceName);\n\n // 重试成功\n this.failedServices.delete(serviceName);\n console.info(`[MCPManager] 服务 ${serviceName} 重试启动成功`);\n\n // 重新初始化CustomMCPHandler以包含新启动的服务工具\n try {\n await this.refreshCustomMCPHandlerPublic();\n } catch (error) {\n console.error(\"[MCPManager] 刷新CustomMCPHandler失败:\", error);\n }\n } catch (error) {\n console.error(\n `[MCPManager] 服务 ${serviceName} 重试启动失败:`,\n (error as Error).message\n );\n\n // 指数退避重试策略:延迟时间翻倍,最大不超过5分钟\n const currentDelay = this.getRetryDelay(serviceName);\n const nextDelay = Math.min(currentDelay * 2, 300000); // 最大5分钟\n\n console.debug(\n `[MCPManager] 服务 ${serviceName} 下次重试将在 ${nextDelay}ms 后进行`\n );\n\n this.scheduleServiceRetry(serviceName, nextDelay);\n }\n }\n\n /**\n * 获取当前重试延迟时间\n * @param serviceName 服务名称\n * @returns 当前延迟时间\n */\n private getRetryDelay(serviceName: string): number {\n // 这里可以实现更复杂的状态跟踪来计算准确的延迟\n // 简化实现:返回一个基于服务名称的哈希值的初始延迟\n const hash = serviceName\n .split(\"\")\n .reduce((acc, char) => acc + char.charCodeAt(0), 0);\n return 30000 + (hash % 60000); // 30-90秒之间的初始延迟\n }\n\n /**\n * 停止指定服务的重试\n * @param serviceName 服务名称\n */\n public stopServiceRetry(serviceName: string): void {\n const timer = this.retryTimers.get(serviceName);\n if (timer) {\n clearTimeout(timer);\n this.retryTimers.delete(serviceName);\n console.debug(`[MCPManager] 已停止服务 ${serviceName} 的重试`);\n }\n this.failedServices.delete(serviceName);\n }\n\n /**\n * 停止所有服务的重试\n */\n public stopAllServiceRetries(): void {\n console.info(\"[MCPManager] 停止所有服务重试\");\n\n for (const [serviceName, timer] of this.retryTimers) {\n clearTimeout(timer);\n console.debug(`[MCPManager] 已停止服务 ${serviceName} 的重试`);\n }\n\n this.retryTimers.clear();\n this.failedServices.clear();\n }\n\n /**\n * 获取失败服务列表\n * @returns 失败的服务名称数组\n */\n public getFailedServices(): string[] {\n return Array.from(this.failedServices);\n }\n\n /**\n * 检查服务是否失败\n * @param serviceName 服务名称\n * @returns 如果服务失败返回true\n */\n public isServiceFailed(serviceName: string): boolean {\n return this.failedServices.has(serviceName);\n }\n\n /**\n * 获取重试统计信息\n * @returns 重试统计信息\n */\n public getRetryStats(): {\n failedServices: string[];\n activeRetries: string[];\n totalFailed: number;\n totalActiveRetries: number;\n } {\n return {\n failedServices: Array.from(this.failedServices),\n activeRetries: Array.from(this.retryTimers.keys()),\n totalFailed: this.failedServices.size,\n totalActiveRetries: this.retryTimers.size,\n };\n }\n\n // ===== 传输适配器管理方法(从 UnifiedMCPServer 移入) =====\n\n /**\n * 注册传输适配器\n * @param name 传输适配器名称\n * @param adapter 传输适配器实例\n */\n public async registerTransport(\n name: string,\n adapter: TransportAdapter\n ): Promise<void> {\n if (this.transportAdapters.has(name)) {\n throw new Error(`传输适配器 ${name} 已存在`);\n }\n\n console.info(`注册传输适配器: ${name}`);\n\n try {\n await adapter.initialize();\n this.transportAdapters.set(name, adapter);\n\n console.info(`传输适配器 ${name} 注册成功`);\n this.emit(\"transportRegistered\", { name, adapter });\n } catch (error) {\n console.error(`注册传输适配器 ${name} 失败`, error);\n throw error;\n }\n }\n\n /**\n * 启动所有传输适配器\n *\n * 改进的错误处理策略:\n * - 单个适配器启动失败不会中断其他适配器的启动\n * - 记录失败的适配器,但继续启动其他适配器\n * - 如果所有适配器都失败,则抛出错误\n * - 如果部分适配器成功,则记录警告但继续运行\n */\n public async startTransports(): Promise<void> {\n console.info(\"启动所有传输适配器\");\n\n const successfulAdapters: string[] = [];\n const failedAdapters: string[] = [];\n\n for (const [name, adapter] of this.transportAdapters) {\n try {\n await adapter.start();\n successfulAdapters.push(name);\n console.info(`传输适配器 ${name} 启动成功`);\n } catch (error) {\n failedAdapters.push(name);\n console.error(`传输适配器 ${name} 启动失败`, error);\n // 不立即抛出错误,继续尝试启动其他适配器\n }\n }\n\n // 评估启动结果\n if (successfulAdapters.length === 0 && failedAdapters.length > 0) {\n // 所有适配器都失败了\n const errorMessage = `所有传输适配器启动失败,失败的适配器: ${failedAdapters.join(\n \", \"\n )}`;\n console.error(errorMessage);\n throw new Error(errorMessage);\n }\n\n if (failedAdapters.length > 0) {\n // 部分适配器失败\n console.warn(\n `部分传输适配器启动失败,成功: ${successfulAdapters.join(\n \", \"\n )}, 失败: ${failedAdapters.join(\", \")}`\n );\n // 继续运行,因为至少有一个适配器成功\n }\n\n console.info(\n `传输适配器启动完成,成功: ${successfulAdapters.length}, 失败: ${failedAdapters.length}`\n );\n }\n\n /**\n * 停止所有传输适配器\n */\n public async stopTransports(): Promise<void> {\n console.info(\"停止所有传输适配器\");\n\n try {\n for (const [name, adapter] of this.transportAdapters) {\n try {\n await adapter.stop();\n console.info(`传输适配器 ${name} 停止成功`);\n } catch (error) {\n console.error(`传输适配器 ${name} 停止失败`, error);\n }\n }\n } catch (error) {\n console.error(\"传输适配器停止失败\", error);\n throw error;\n }\n }\n\n /**\n * 获取所有传输适配器\n * @returns 传输适配器映射表\n */\n public getTransportAdapters(): Map<string, TransportAdapter> {\n return new Map(this.transportAdapters);\n }\n\n /**\n * 获取消息处理器(供外部使用)\n * @returns 消息处理器实例\n */\n public getMessageHandler(): MCPMessageHandler {\n return this.messageHandler;\n }\n\n /**\n * 启动管理器(包含服务和传输)\n */\n public async start(): Promise<void> {\n if (this.isRunning) {\n throw new Error(\"服务器已在运行\");\n }\n\n console.info(\"启动 MCP 服务管理器\");\n\n try {\n await this.startAllServices();\n await this.startTransports();\n this.isRunning = true;\n\n console.info(\"MCP 服务管理器启动成功\");\n this.emit(\"started\");\n } catch (error) {\n console.error(\"MCP 服务管理器启动失败\", error);\n throw error;\n }\n }\n\n /**\n * 停止管理器(包含传输和服务)\n */\n public async stop(): Promise<void> {\n if (!this.isRunning) {\n return;\n }\n\n console.info(\"停止 MCP 服务管理器\");\n\n try {\n await this.stopTransports();\n await this.stopAllServices();\n this.isRunning = false;\n\n console.info(\"MCP 服务管理器停止成功\");\n this.emit(\"stopped\");\n } catch (error) {\n console.error(\"MCP 服务管理器停止失败\", error);\n throw error;\n }\n }\n\n /**\n * 获取所有连接信息\n * @returns 连接信息列表\n */\n public getAllConnections(): Array<{\n id: string;\n name: string;\n state: ConnectionState;\n }> {\n const connections: Array<{\n id: string;\n name: string;\n state: ConnectionState;\n }> = [];\n\n // 收集服务连接\n for (const [serviceName, service] of this.services) {\n if (service.isConnected()) {\n connections.push({\n id: `service-${serviceName}`,\n name: serviceName,\n state: ConnectionState.CONNECTED,\n });\n }\n }\n\n // 收集传输适配器连接\n for (const [adapterName, adapter] of this.transportAdapters) {\n connections.push({\n id: adapter.getConnectionId(),\n name: adapterName,\n state: adapter.getState(),\n });\n }\n\n return connections;\n }\n\n /**\n * 获取活跃连接数\n * @returns 活跃连接数量\n */\n public getActiveConnectionCount(): number {\n return this.getAllConnections().filter(\n (conn) => conn.state === ConnectionState.CONNECTED\n ).length;\n }\n\n // ===== 从 UnifiedMCPServer 移入的方法 =====\n\n /**\n * 获取服务器状态(从 UnifiedMCPServer 移入)\n */\n getUnifiedStatus(): UnifiedServerStatus {\n const serviceStatus = this.getServiceManagerStatus();\n return {\n isRunning: this.isRunning,\n serviceStatus,\n transportCount: this.getTransportAdapters().size,\n activeConnections: this.getActiveConnectionCount(),\n config: this.config,\n // 便捷访问属性\n services: serviceStatus.services,\n totalTools: serviceStatus.totalTools,\n availableTools: serviceStatus.availableTools,\n };\n }\n\n /**\n * 获取管理器状态(原有的 getStatus 方法重命名)\n */\n getServiceManagerStatus(): ManagerStatus {\n // 计算总工具数量(包括 customMCP 工具,添加异常处理)\n let customMCPToolCount = 0;\n let customToolNames: string[] = [];\n\n try {\n customMCPToolCount = this.customMCPHandler.getToolCount();\n customToolNames = this.customMCPHandler.getToolNames();\n console.debug(\n `[MCPManager] 成功获取 customMCP 状态: ${customMCPToolCount} 个工具`\n );\n } catch (error) {\n console.warn(\n \"[MCPManager] 获取 CustomMCP 状态失败,将只包含标准 MCP 工具:\",\n error\n );\n // 异常情况下,customMCP 工具数量为0,不影响标准 MCP 工具\n customMCPToolCount = 0;\n customToolNames = [];\n }\n\n const totalTools = this.tools.size + customMCPToolCount;\n\n // 获取所有可用工具名称\n const standardToolNames = Array.from(this.tools.keys());\n const availableTools = [...standardToolNames, ...customToolNames];\n\n const status: ManagerStatus = {\n services: {},\n totalTools,\n availableTools,\n };\n\n // 添加标准 MCP 服务状态\n for (const [serviceName, service] of this.services) {\n const serviceStatus = service.getStatus();\n status.services[serviceName] = {\n connected: serviceStatus.connected,\n clientName: `xiaozhi-${serviceName}-client`,\n };\n }\n\n // 添加 CustomMCP 服务状态\n if (customMCPToolCount > 0) {\n status.services.customMCP = {\n connected: true, // CustomMCP 工具总是可用的\n clientName: \"xiaozhi-customMCP-handler\",\n };\n }\n\n return status;\n }\n\n /**\n * 检查服务器是否正在运行(从 UnifiedMCPServer 移入)\n */\n isServerRunning(): boolean {\n return this.isRunning;\n }\n\n /**\n * 类型守卫:检查是否为 UnifiedServerConfig\n */\n private isUnifiedServerConfig(\n configs: unknown\n ): configs is UnifiedServerConfig {\n return (\n configs !== null && typeof configs === \"object\" && \"configs\" in configs\n );\n }\n\n /**\n * 消息路由核心功能(从 UnifiedMCPServer 移入)\n */\n async routeMessage(message: MCPMessage): Promise<MCPMessage | null> {\n const response = await this.messageHandler.handleMessage(message);\n // 如果响应是 null,直接返回\n if (response === null) {\n return null;\n }\n // 将 MCPResponse 转换为 MCPMessage 格式\n return {\n jsonrpc: \"2.0\",\n method: \"response\", // 标识这是一个响应消息\n params: response,\n id: response.id, // 使用响应中的ID\n };\n }\n\n // ===== 向后兼容方法 =====\n\n /**\n * 初始化方法(向后兼容,实际调用 start)\n *\n * 注意:此方法仅为向后兼容而保留\n * 实际功能:调用 start() 方法并设置 isRunning 状态\n * 建议新代码直接使用 start() 方法\n */\n async initialize(): Promise<void> {\n // 为了向后兼容,初始化时调用 start\n // 会设置 isRunning 状态为 true\n await this.start();\n }\n\n /**\n * 获取工具注册表(向后兼容,返回自身)\n */\n getToolRegistry(): MCPServiceManager {\n return this;\n }\n\n /**\n * 获取连接管理器(向后兼容,返回自身)\n */\n getConnectionManager(): MCPServiceManager {\n return this;\n }\n}\n\nexport default MCPServiceManager;\n","import type { MCPServerTransport, MCPServiceConfig } from \"@/lib/mcp/types\";\nimport { MCPTransportType } from \"@/lib/mcp/types\";\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\";\n\n// 全局 polyfill EventSource(用于 SSE)\n// 使用类型断言避免与已有 EventSource 类型冲突\nif (\n typeof global !== \"undefined\" &&\n !(global as typeof global & { EventSource?: unknown }).EventSource\n) {\n (global as typeof global & { EventSource: typeof EventSource }).EventSource =\n 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 服务配置\n * @returns transport 实例\n */\nexport function createTransport(config: MCPServiceConfig): 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.STREAMABLE_HTTP:\n return createStreamableHTTPTransport(config);\n\n default:\n throw new Error(`不支持的传输类型: ${config.type}`);\n }\n}\n\n/**\n * 创建 Stdio transport\n */\nfunction createStdioTransport(config: MCPServiceConfig): StdioClientTransport {\n if (!config.command) {\n throw new Error(\"stdio transport 需要 command 配置\");\n }\n\n return new StdioClientTransport({\n command: config.command,\n args: config.args || [],\n env: config.env, // 传递环境变量\n });\n}\n\n/**\n * 创建 SSE transport\n */\nfunction createSSETransport(config: MCPServiceConfig): SSEClientTransport {\n if (!config.url) {\n throw new Error(\"SSE transport 需要 URL 配置\");\n }\n\n const url = new URL(config.url);\n const options = createSSEOptions(config);\n\n return new SSEClientTransport(url, options);\n}\n\n/**\n * 创建 ModelScope SSE transport\n */\nfunction createModelScopeSSETransport(\n config: MCPServiceConfig\n): SSEClientTransport {\n if (!config.url) {\n throw new Error(\"ModelScope SSE transport 需要 URL 配置\");\n }\n\n if (!config.apiKey) {\n throw new Error(\"ModelScope SSE transport 需要 apiKey 配置\");\n }\n\n const url = new URL(config.url);\n const options = createModelScopeSSEOptions(config);\n\n return new SSEClientTransport(url, options);\n}\n\nfunction createStreamableHTTPTransport(\n config: MCPServiceConfig\n): StreamableHTTPClientTransport {\n if (!config.url) {\n throw new Error(\"StreamableHTTP transport 需要 URL 配置\");\n }\n\n const url = new URL(config.url);\n const options = createStreamableHTTPOptions(config);\n return new StreamableHTTPClientTransport(url, options);\n}\n\n/**\n * 创建 SSE 选项\n */\nfunction createSSEOptions(config: MCPServiceConfig): SSEClientTransportOptions {\n const options: SSEClientTransportOptions = {};\n\n // 添加认证头\n if (config.apiKey) {\n options.requestInit = {\n headers: {\n Authorization: `Bearer ${config.apiKey}`,\n ...config.headers,\n },\n };\n } else if (config.headers) {\n options.requestInit = {\n headers: config.headers,\n };\n }\n\n return options;\n}\n\n/**\n * 创建 ModelScope SSE 选项\n */\nfunction createModelScopeSSEOptions(\n config: MCPServiceConfig\n): SSEClientTransportOptions {\n // 添加防御性空值检查\n if (!config.apiKey) {\n throw new Error(\"ModelScope SSE transport 需要 apiKey 配置\");\n }\n\n const token = config.apiKey;\n\n // 如果有自定义SSE选项,使用它们\n if (config.customSSEOptions) {\n return config.customSSEOptions;\n }\n\n // 默认的ModelScope SSE选项配置\n return {\n eventSourceInit: {\n fetch: async (url: string | URL | Request, init?: RequestInit) => {\n // 添加认证头\n const headers = {\n ...init?.headers,\n Authorization: `Bearer ${token}`,\n };\n\n return fetch(url, { ...init, headers });\n },\n },\n requestInit: {\n headers: {\n Authorization: `Bearer ${token}`,\n ...config.headers,\n },\n },\n };\n}\n\nfunction createStreamableHTTPOptions(\n config: MCPServiceConfig\n): StreamableHTTPClientTransportOptions {\n const options: StreamableHTTPClientTransportOptions = {};\n\n // 添加认证头\n if (config.apiKey) {\n options.requestInit = {\n headers: {\n Authorization: `Bearer ${config.apiKey}`,\n ...config.headers,\n },\n };\n } else if (config.headers) {\n options.requestInit = {\n headers: config.headers,\n };\n }\n\n return options;\n}\n\n/**\n * 验证配置\n */\nexport function validateConfig(config: MCPServiceConfig): void {\n if (!config.name || typeof config.name !== \"string\") {\n throw new Error(\"配置必须包含有效的 name 字段\");\n }\n\n // type 字段现在是可选的,由 MCPService 自动推断\n // 这里我们只验证如果 type 存在,必须是有效的类型\n if (config.type && !Object.values(MCPTransportType).includes(config.type)) {\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.STREAMABLE_HTTP:\n // STREAMABLE_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 [\n MCPTransportType.STDIO,\n MCPTransportType.SSE,\n MCPTransportType.STREAMABLE_HTTP,\n ];\n}\n\n/**\n * Transport 工厂对象(保持 API 兼容性)\n */\nexport const TransportFactory = {\n create: createTransport,\n validateConfig,\n getSupportedTypes,\n};\n","import { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport { getEventBus } from \"@root/services/EventBus.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 { inferTransportTypeFromConfig } from \"./utils.js\";\n\n/**\n * MCP 服务类\n * 负责管理单个 MCP 服务的连接、工具管理和调用\n */\nexport class MCPService {\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 eventBus = getEventBus();\n\n constructor(config: MCPServiceConfig) {\n // 使用工具方法推断服务类型\n this.config = inferTransportTypeFromConfig(config);\n\n // 验证配置\n this.validateConfig();\n }\n\n /**\n * 验证配置\n */\n private validateConfig(): void {\n // 使用 TransportFactory 进行配置验证\n TransportFactory.validateConfig(this.config);\n }\n\n /**\n * 连接到 MCP 服务\n */\n async connect(): Promise<void> {\n // 如果正在连接中,等待当前连接完成\n if (this.connectionState === ConnectionState.CONNECTING) {\n throw new Error(\"连接正在进行中,请等待连接完成\");\n }\n\n // 清理之前的连接\n this.cleanupConnection();\n\n return this.attemptConnection();\n }\n\n /**\n * 尝试建立连接\n */\n private async attemptConnection(): Promise<void> {\n this.connectionState = ConnectionState.CONNECTING;\n console.debug(\n `[MCP-${this.config.name}] 正在连接 MCP 服务: ${this.config.name}`\n );\n\n return new Promise((resolve, reject) => {\n // 设置连接超时\n this.connectionTimeout = setTimeout(() => {\n const error = new Error(`连接超时 (${this.config.timeout || 10000}ms)`);\n this.handleConnectionError(error);\n reject(error);\n }, this.config.timeout || 10000);\n\n try {\n this.client = new Client(\n {\n name: `xiaozhi-${this.config.name}-client`,\n version: \"1.0.0\",\n },\n {\n capabilities: {},\n }\n );\n\n // 使用 TransportFactory 创建传输层\n this.transport = TransportFactory.create(this.config);\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.eventBus.emitEvent(\"mcp:service:connected\", {\n serviceName: this.config.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(\n `[MCP-${this.config.name}] MCP 服务 ${this.config.name} 连接已建立`\n );\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.config.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.eventBus.emitEvent(\"mcp:service:connection:failed\", {\n serviceName: this.config.name,\n error,\n attempt: 0,\n });\n }\n\n /**\n * 清理连接资源\n */\n private cleanupConnection(): void {\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.config.name} 服务加载了 ${tools.length} 个工具: ${tools\n .map((t) => t.name)\n .join(\", \")}`\n );\n } catch (error) {\n console.error(\n `${this.config.name} 获取工具列表失败:`,\n error instanceof Error ? error.message : String(error)\n );\n throw error;\n }\n }\n\n /**\n * 断开连接\n */\n async disconnect(): Promise<void> {\n console.info(`主动断开 MCP 服务 ${this.config.name} 连接`);\n\n // 清理连接资源\n this.cleanupConnection();\n\n // 设置状态为已断开\n this.connectionState = ConnectionState.DISCONNECTED;\n\n // 发射断开连接事件\n this.eventBus.emitEvent(\"mcp:service:disconnected\", {\n serviceName: this.config.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 async callTool(\n name: string,\n arguments_: Record<string, unknown>\n ): Promise<ToolCallResult> {\n if (!this.client) {\n throw new Error(`服务 ${this.config.name} 未连接`);\n }\n\n if (!this.tools.has(name)) {\n throw new Error(`工具 ${name} 在服务 ${this.config.name} 中不存在`);\n }\n\n console.debug(\n `调用 ${this.config.name} 服务的工具 ${name},参数:`,\n JSON.stringify(arguments_)\n );\n\n try {\n const result = await this.client.callTool({\n name,\n arguments: arguments_ || {},\n });\n\n console.debug(\n `工具 ${name} 调用成功,结果:`,\n `${JSON.stringify(result).substring(0, 500)}...`\n );\n\n return result as ToolCallResult;\n } catch (error) {\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 {\n return this.config;\n }\n\n /**\n * 获取服务状态\n */\n getStatus(): MCPServiceStatus {\n return {\n name: this.config.name,\n connected: this.connectionState === ConnectionState.CONNECTED,\n initialized: this.initialized,\n transportType: this.config.type || MCPTransportType.STREAMABLE_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 * 扣子 API 相关类型定义\n * 基于 docs/coze-api.md 中的 API 文档\n */\n\n/**\n * 扣子工作空间接口\n */\nexport interface CozeWorkspace {\n /** 工作空间ID */\n id: string;\n /** 工作空间名称 */\n name: string;\n /** 工作空间描述 */\n description: string;\n /** 工作空间类型 */\n workspace_type: \"personal\" | \"team\";\n /** 企业ID */\n enterprise_id: string;\n /** 管理员用户ID列表 */\n admin_uids: string[];\n /** 工作空间图标URL */\n icon_url: string;\n /** 用户在工作空间中的角色类型 */\n role_type: \"owner\" | \"admin\" | \"member\";\n /** 加入状态 */\n joined_status: \"joined\" | \"pending\" | \"rejected\";\n /** 所有者用户ID */\n owner_uid: string;\n}\n\n/**\n * 扣子工作流创建者信息\n */\nexport interface CozeWorkflowCreator {\n /** 创建者ID */\n id: string;\n /** 创建者名称 */\n name: string;\n}\n\n/**\n * 扣子工作流接口\n */\nexport interface CozeWorkflow {\n /** 工作流ID */\n workflow_id: string;\n /** 工作流名称 */\n workflow_name: string;\n /** 工作流描述 */\n description: string;\n /** 工作流图标URL */\n icon_url: string;\n /** 关联应用ID */\n app_id: string;\n /** 创建者信息 */\n creator: CozeWorkflowCreator;\n /** 创建时间戳 */\n created_at: number;\n /** 更新时间戳 */\n updated_at: number;\n}\n\n/**\n * 扣子 API 响应详情\n */\nexport interface CozeApiDetail {\n /** 日志ID */\n logid: string;\n}\n\n/**\n * 扣子 API 基础响应接口\n */\nexport interface CozeApiResponse<T = any> {\n /** 响应状态码,0表示成功 */\n code: number;\n /** 响应数据 */\n data: T;\n /** 响应消息 */\n msg: string;\n /** 响应详情 */\n detail: CozeApiDetail;\n}\n\n/**\n * 获取工作空间列表的响应数据\n */\nexport interface CozeWorkspacesData {\n /** 工作空间总数 */\n total_count: number;\n /** 工作空间列表 */\n workspaces: CozeWorkspace[];\n}\n\n/**\n * 获取工作空间列表的完整响应\n */\nexport interface CozeWorkspacesResponse\n extends CozeApiResponse<CozeWorkspacesData> {}\n\n/**\n * 获取工作流列表的响应数据\n */\nexport interface CozeWorkflowsData {\n /** 是否有更多数据 */\n has_more: boolean;\n /** 工作流列表 */\n items: CozeWorkflow[];\n}\n\n/**\n * 获取工作流列表的完整响应\n */\nexport interface CozeWorkflowsResponse\n extends CozeApiResponse<CozeWorkflowsData> {}\n\n/**\n * 获取工作流列表的请求参数\n */\nexport interface CozeWorkflowsParams {\n /** 工作空间ID */\n workspace_id: string;\n /** 页码,从1开始 */\n page_num?: number;\n /** 每页数量,默认20 */\n page_size?: number;\n /** 工作流模式,默认为 workflow */\n workflow_mode?: \"workflow\";\n}\n\n/**\n * 扣子 API 错误响应\n */\nexport interface CozeApiError extends Error {\n /** 错误代码 */\n code: string;\n /** HTTP 状态码 */\n statusCode?: number;\n /** 原始响应数据 */\n response?: any;\n}\n\n/**\n * 扣子平台配置接口\n */\nexport interface CozePlatformConfig {\n /** 扣子 API Token */\n token: string;\n}\n\n/**\n * 扣子 API 服务配置\n */\nexport interface CozeApiServiceConfig {\n /** API Token */\n token: string;\n /** API 基础URL,默认 https://api.coze.cn */\n apiBaseUrl?: string;\n /** 请求超时时间,默认 10000ms */\n timeout?: number;\n /** 重试次数,默认 3 次 */\n retryAttempts?: number;\n /** 是否启用缓存,默认 true */\n cacheEnabled?: boolean;\n}\n\n// ==================== 工作流参数配置相关类型 ====================\n\n/**\n * 工作流参数定义\n */\nexport interface WorkflowParameter {\n /** 英文字段名,用作参数标识符 */\n fieldName: string;\n /** 中英文描述,说明参数用途 */\n description: string;\n /** 参数类型 */\n type: \"string\" | \"number\" | \"boolean\";\n /** 是否必填参数 */\n required: boolean;\n}\n\n/**\n * 工作流参数配置\n */\nexport interface WorkflowParameterConfig {\n /** 参数列表 */\n parameters: WorkflowParameter[];\n}\n","/**\n * Hono Context 类型扩展\n * 为 Hono Context 添加项目特定的变量类型定义\n */\n\nimport type { EndpointManager } from \"@/lib/endpoint/index.js\";\nimport type { MCPServiceManager } from \"@/lib/mcp\";\nimport type { Logger } from \"@root/Logger.js\";\nimport type { Context } from \"hono\";\nimport { Hono } from \"hono\";\nimport type {\n HandlerDependencies,\n MCPEndpointApiHandler,\n} from \"../routes/index.js\";\n\n/**\n * WebServer 实例类型定义\n * 避免与 WebServer 实现类的循环引用\n * 使用类型断言的方式来定义接口\n */\nexport interface IWebServer {\n /**\n * 获取小智连接管理器实例\n * 在 endpointManagerMiddleware 中使用\n * WebServer 启动后始终返回有效的连接管理器实例\n * 如果在启动前调用,会抛出错误\n */\n getEndpointManager(): EndpointManager;\n\n /**\n * 获取 MCP 服务管理器实例\n * 在 mcpServiceManagerMiddleware 中使用\n * WebServer 启动后始终返回有效的服务管理器实例\n * 如果在启动前调用,会抛出错误\n */\n getMCPServiceManager(): MCPServiceManager;\n}\n\n/**\n * 扩展 Hono Context 的 Variables 类型\n * 定义了项目中所有通过中间件注入的变量\n */\nexport type AppContextVariables = {\n /**\n * 日志记录器实例\n * 由 loggerMiddleware 注入\n */\n logger?: Logger;\n\n /**\n * MCP 服务管理器实例\n * 由 mcpServiceManagerMiddleware 注入\n */\n mcpServiceManager?: MCPServiceManager;\n\n /**\n * 路由处理器依赖\n * 由 RouteManager 注入\n */\n dependencies?: HandlerDependencies;\n\n /**\n * WebServer 实例引用\n * 用于获取运行时依赖\n */\n webServer?: IWebServer;\n\n /**\n * 小智连接管理器实例\n * 由 endpointManagerMiddleware 注入\n * WebServer 启动后始终可用的连接管理器实例\n * 可能为 null(初始化失败时)\n */\n endpointManager: EndpointManager | null;\n\n /**\n * 端点处理器实例\n * 由 endpointsMiddleware 注入\n */\n endpointHandler?: MCPEndpointApiHandler | null;\n};\n\n/**\n * 扩展的 Hono Context 类型\n * 包含项目中所有自定义变量\n */\nexport type AppContext = {\n Variables: AppContextVariables;\n};\n\n/**\n * 创建类型化的 Hono 实例\n * 使用这个类型来创建新的 Hono 应用,确保 Context 类型安全\n */\nexport const createApp = (): Hono<AppContext> => {\n return new Hono<AppContext>();\n};\n\n/**\n * 从 Context 中获取日志记录器的类型安全方法\n */\nexport const getLogger = (c: Context<AppContext>): Logger | undefined => {\n return c.get(\"logger\");\n};\n\n/**\n * 从 Context 中获取 MCPServiceManager 的类型安全方法\n */\nexport const getMCPServiceManager = (\n c: Context<AppContext>\n): MCPServiceManager | undefined => {\n return c.get(\"mcpServiceManager\");\n};\n\n/**\n * 要求必须存在 MCPServiceManager 的类型安全方法\n */\nexport const requireMCPServiceManager = (\n c: Context<AppContext>\n): MCPServiceManager => {\n const serviceManager = c.get(\"mcpServiceManager\");\n\n if (!serviceManager) {\n throw new Error(\n \"MCPServiceManager 未初始化,请检查 mcpServiceManagerMiddleware 是否正确配置\"\n );\n }\n\n return serviceManager;\n};\n","export type {\n MCPMessage,\n MCPResponse,\n MCPError,\n ExtendedMCPToolsCache,\n EnhancedToolResultCache,\n TaskStatus,\n CacheStatistics,\n CacheStateTransition,\n ToolCallOptions,\n CacheConfig,\n TimeoutConfig,\n TaskInfo,\n ToolCallResponse,\n ToolCallResult,\n} from \"./mcp.js\";\nexport {\n generateCacheKey,\n formatTimestamp,\n isCacheExpired,\n shouldCleanupCache,\n isToolCallResult,\n isEnhancedToolResultCache,\n isExtendedMCPToolsCache,\n DEFAULT_CONFIG,\n} from \"./mcp.js\";\nexport * from \"./coze.js\";\nexport * from \"./timeout.js\";\nexport * from \"./hono.context.js\";\n","/**\n * MCP 缓存管理器\n * 负责 MCP 服务工具列表的缓存写入功能\n * 专注于缓存文件管理和数据写入的基础设施\n */\n\nimport { createHash } from \"node:crypto\";\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n renameSync,\n writeFileSync,\n} from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\nimport type { MCPServiceConfig } from \"@/lib/mcp/types\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport type { Logger } from \"@root/Logger.js\";\nimport { logger } from \"@root/Logger.js\";\nimport type {\n CacheStatistics,\n EnhancedToolResultCache,\n ExtendedMCPToolsCache,\n TaskStatus,\n ToolCallResult,\n} from \"@root/types/index.js\";\nimport { generateCacheKey, shouldCleanupCache } from \"@root/types/index.js\";\nimport dayjs from \"dayjs\";\n\n// 缓存条目接口\nexport interface MCPToolsCacheEntry {\n tools: Tool[]; // 工具列表\n lastUpdated: string; // 最后更新时间 (YYYY-MM-DD HH:mm:ss)\n serverConfig: MCPServiceConfig; // 服务配置快照\n configHash: string; // 配置哈希值,用于快速变更检测\n version: string; // 缓存条目版本\n}\n\n// 缓存文件接口\nexport interface MCPToolsCache {\n version: string; // 缓存文件格式版本 \"1.0.0\"\n mcpServers: Record<string, MCPToolsCacheEntry>;\n metadata: {\n lastGlobalUpdate: string; // 全局最后更新时间 (YYYY-MM-DD HH:mm:ss)\n totalWrites: number; // 总写入次数\n createdAt: string; // 缓存文件创建时间 (YYYY-MM-DD HH:mm:ss)\n };\n}\n\n// 缓存统计接口\nexport interface CacheStats {\n totalWrites: number;\n lastUpdate: string;\n serverCount: number;\n cacheFileSize: number;\n}\n\n// 重新导出相关类型\nexport type {\n CacheStatistics,\n EnhancedToolResultCache,\n ExtendedMCPToolsCache,\n} from \"@root/types/index.js\";\n\nexport class MCPCacheManager {\n private cachePath: string;\n private logger: Logger;\n private readonly CACHE_VERSION = \"1.0.0\";\n private readonly CACHE_ENTRY_VERSION = \"1.0.0\";\n private cleanupInterval?: NodeJS.Timeout;\n private readonly CLEANUP_INTERVAL = 60000; // 1分钟清理间隔\n\n constructor(customCachePath?: string) {\n this.logger = logger;\n this.cachePath = customCachePath || this.getCacheFilePath();\n this.startCleanupTimer();\n }\n\n /**\n * 格式化时间戳为 YYYY-MM-DD HH:mm:ss 格式\n */\n private formatTimestamp(): string {\n return dayjs().format(\"YYYY-MM-DD HH:mm:ss\");\n }\n\n /**\n * 获取缓存文件路径\n * 与 xiaozhi.config.json 同级目录\n */\n private getCacheFilePath(): string {\n try {\n const configDir = process.env.XIAOZHI_CONFIG_DIR || process.cwd();\n return resolve(configDir, \"xiaozhi.cache.json\");\n } catch (error) {\n // 在某些测试环境中 process.cwd() 可能不可用,使用默认路径\n const configDir = process.env.XIAOZHI_CONFIG_DIR || \"/tmp\";\n return resolve(configDir, \"xiaozhi.cache.json\");\n }\n }\n\n /**\n * 确保缓存文件存在,如不存在则创建\n */\n async ensureCacheFile(): Promise<void> {\n try {\n if (!existsSync(this.cachePath)) {\n // 确保缓存文件的目录存在\n const cacheDir = dirname(this.cachePath);\n if (!existsSync(cacheDir)) {\n mkdirSync(cacheDir, { recursive: true });\n this.logger.debug(`[CacheManager] 已创建缓存目录: ${cacheDir}`);\n }\n\n this.logger.debug(\"[CacheManager] 缓存文件不存在,创建初始缓存文件\");\n const initialCache = await this.createInitialCache();\n await this.saveCache(initialCache);\n this.logger.info(`[CacheManager] 已创建缓存文件: ${this.cachePath}`);\n }\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 创建缓存文件失败: ${error instanceof Error ? error.message : String(error)}`\n );\n // 不抛出异常,确保不影响主流程\n }\n }\n\n /**\n * 创建初始缓存结构\n */\n private async createInitialCache(): Promise<MCPToolsCache> {\n const now = this.formatTimestamp();\n return {\n version: this.CACHE_VERSION,\n mcpServers: {},\n metadata: {\n lastGlobalUpdate: now,\n totalWrites: 0,\n createdAt: now,\n },\n };\n }\n\n /**\n * 写入缓存条目\n * @param serverName 服务名称\n * @param tools 工具列表\n * @param config 服务配置\n */\n async writeCacheEntry(\n serverName: string,\n tools: Tool[],\n config: MCPServiceConfig\n ): Promise<void> {\n try {\n this.logger.debug(`[CacheManager] 开始写入缓存: ${serverName}`);\n\n // 确保缓存文件存在\n await this.ensureCacheFile();\n\n // 加载现有缓存\n const cache = await this.loadExistingCache();\n\n // 生成配置哈希\n const configHash = this.generateConfigHash(config);\n\n // 创建缓存条目\n const cacheEntry: MCPToolsCacheEntry = {\n tools: tools.map((tool) => ({\n name: tool.name,\n description: tool.description || \"\",\n inputSchema: tool.inputSchema,\n })),\n lastUpdated: this.formatTimestamp(),\n serverConfig: { ...config }, // 深拷贝配置\n configHash,\n version: this.CACHE_ENTRY_VERSION,\n };\n\n // 更新缓存\n cache.mcpServers[serverName] = cacheEntry;\n cache.metadata.lastGlobalUpdate = this.formatTimestamp();\n cache.metadata.totalWrites += 1;\n\n // 保存缓存\n await this.saveCache(cache);\n\n this.logger.debug(\n `[CacheManager] 缓存写入成功: ${serverName}, 工具数量: ${tools.length}`\n );\n } catch (error) {\n // 记录错误但不抛出异常,确保不影响主流程\n this.logger.warn(\n `[CacheManager] 缓存写入失败: ${serverName}, 错误: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n\n /**\n * 加载现有缓存\n */\n public async loadExistingCache(): Promise<MCPToolsCache> {\n try {\n if (!existsSync(this.cachePath)) {\n return await this.createInitialCache();\n }\n\n const cacheData = readFileSync(this.cachePath, \"utf8\");\n const cache: unknown = JSON.parse(cacheData);\n\n // 验证缓存结构\n if (!this.validateCacheStructure(cache)) {\n this.logger.warn(\"[CacheManager] 缓存文件结构无效,重新创建\");\n return await this.createInitialCache();\n }\n\n return cache;\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 加载缓存失败,创建新缓存: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return await this.createInitialCache();\n }\n }\n\n /**\n * 保存缓存到文件(原子写入)\n */\n public async saveCache(cache: MCPToolsCache): Promise<void> {\n const cacheContent = JSON.stringify(cache, null, 2);\n await this.atomicWrite(this.cachePath, cacheContent);\n }\n\n /**\n * 原子写入文件\n * 使用临时文件确保写入操作的原子性\n */\n private async atomicWrite(filePath: string, data: string): Promise<void> {\n const tempPath = `${filePath}.tmp`;\n try {\n // 写入临时文件\n writeFileSync(tempPath, data, \"utf8\");\n // 原子性重命名\n renameSync(tempPath, filePath);\n } catch (error) {\n // 清理临时文件\n try {\n if (existsSync(tempPath)) {\n writeFileSync(tempPath, \"\", \"utf8\"); // 清空后删除\n }\n } catch {\n // 忽略清理错误\n }\n throw error;\n }\n }\n\n /**\n * 生成配置哈希\n * 用于快速检测配置变更\n */\n private generateConfigHash(config: MCPServiceConfig): string {\n try {\n return createHash(\"sha256\").update(JSON.stringify(config)).digest(\"hex\");\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 生成配置哈希失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return \"\";\n }\n }\n\n /**\n * 验证缓存数据结构\n * 使用类型谓词确保类型安全\n */\n private validateCacheStructure(cache: unknown): cache is MCPToolsCache {\n try {\n if (!cache || typeof cache !== \"object\") {\n return false;\n }\n\n const cacheObj = cache as Record<string, unknown>;\n const metadata = cacheObj.metadata as Record<string, unknown>;\n\n return (\n typeof cacheObj.version === \"string\" &&\n typeof cacheObj.mcpServers === \"object\" &&\n cacheObj.mcpServers !== null &&\n cacheObj.metadata !== null &&\n cacheObj.metadata !== undefined &&\n typeof metadata === \"object\" &&\n metadata !== null &&\n typeof metadata.lastGlobalUpdate === \"string\" &&\n typeof metadata.totalWrites === \"number\" &&\n typeof metadata.createdAt === \"string\"\n );\n } catch {\n return false;\n }\n }\n\n /**\n * 获取缓存统计信息\n */\n async getStats(): Promise<CacheStats | null> {\n try {\n const cache = await this.loadExistingCache();\n const stats: CacheStats = {\n totalWrites: cache.metadata.totalWrites,\n lastUpdate: cache.metadata.lastGlobalUpdate,\n serverCount: Object.keys(cache.mcpServers).length,\n cacheFileSize: existsSync(this.cachePath)\n ? readFileSync(this.cachePath, \"utf8\").length\n : 0,\n };\n return stats;\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 获取缓存统计失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return null;\n }\n }\n\n /**\n * 获取缓存文件路径(用于测试和调试)\n */\n getFilePath(): string {\n return this.cachePath;\n }\n\n /**\n * 获取所有缓存中的工具\n * 返回所有服务中的所有工具列表\n */\n async getAllCachedTools(): Promise<Tool[]> {\n try {\n const cache = await this.loadExistingCache();\n const allTools: Tool[] = [];\n\n // 遍历所有服务,收集所有工具\n for (const [serverName, cacheEntry] of Object.entries(cache.mcpServers)) {\n for (const tool of cacheEntry.tools) {\n // 为每个工具添加服务名称信息\n allTools.push({\n ...tool,\n name: `${serverName}__${tool.name}`, // 格式: serviceName__toolName\n });\n }\n }\n\n this.logger.debug(\n `[CacheManager] 获取到所有缓存工具,共 ${allTools.length} 个`\n );\n return allTools;\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 获取所有缓存工具失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return [];\n }\n }\n\n // ==================== CustomMCP 结果缓存管理方法 ====================\n\n /**\n * 写入 CustomMCP 工具执行结果缓存\n */\n async writeCustomMCPResult(\n toolName: string,\n arguments_: Record<string, unknown>,\n result: ToolCallResult,\n status: TaskStatus = \"completed\",\n taskId?: string,\n ttl = 300000\n ): Promise<void> {\n try {\n const cache = await this.loadExtendedCache();\n const cacheKey = generateCacheKey(toolName, arguments_);\n\n // 创建缓存条目\n const cacheEntry: EnhancedToolResultCache = {\n result,\n timestamp: new Date().toISOString(),\n ttl,\n status,\n consumed: false,\n taskId,\n retryCount: 0,\n };\n\n // 确保customMCPResults存在\n if (!cache.customMCPResults) {\n cache.customMCPResults = {};\n }\n\n cache.customMCPResults[cacheKey] = cacheEntry;\n await this.saveExtendedCache(cache);\n\n this.logger.debug(\n `[CacheManager] 写入CustomMCP结果缓存: ${toolName}, 状态: ${status}`\n );\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 写入CustomMCP结果缓存失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n\n /**\n * 读取 CustomMCP 工具执行结果缓存\n */\n async readCustomMCPResult(\n toolName: string,\n arguments_: Record<string, unknown>\n ): Promise<EnhancedToolResultCache | null> {\n try {\n const cache = await this.loadExtendedCache();\n const cacheKey = generateCacheKey(toolName, arguments_);\n\n if (!cache.customMCPResults || !cache.customMCPResults[cacheKey]) {\n return null;\n }\n\n const cacheEntry = cache.customMCPResults[cacheKey];\n\n // 检查是否过期\n const now = Date.now();\n const cachedTime = new Date(cacheEntry.timestamp).getTime();\n if (now - cachedTime > cacheEntry.ttl) {\n this.logger.debug(`[CacheManager] 缓存已过期: ${toolName}`);\n return null;\n }\n\n return cacheEntry;\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 读取CustomMCP结果缓存失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return null;\n }\n }\n\n /**\n * 更新 CustomMCP 缓存状态\n */\n async updateCustomMCPStatus(\n toolName: string,\n arguments_: Record<string, unknown>,\n newStatus: TaskStatus,\n result?: ToolCallResult,\n error?: string\n ): Promise<boolean> {\n try {\n const cache = await this.loadExtendedCache();\n const cacheKey = generateCacheKey(toolName, arguments_);\n\n if (!cache.customMCPResults || !cache.customMCPResults[cacheKey]) {\n return false;\n }\n\n const cacheEntry = cache.customMCPResults[cacheKey];\n const oldStatus = cacheEntry.status;\n\n // 更新状态\n cacheEntry.status = newStatus;\n cacheEntry.timestamp = new Date().toISOString();\n\n // 更新结果或错误信息\n if (result) {\n cacheEntry.result = result;\n }\n\n if (error && newStatus === \"failed\") {\n cacheEntry.result = {\n content: [{ type: \"text\", text: `任务失败: ${error}` }],\n };\n cacheEntry.consumed = true; // 失败的任务自动标记为已消费\n }\n\n // 特殊状态处理\n if (newStatus === \"completed\") {\n cacheEntry.consumed = false; // 完成的任务初始状态为未消费\n }\n\n await this.saveExtendedCache(cache);\n\n this.logger.debug(\n `[CacheManager] 更新缓存状态: ${toolName} ${oldStatus} -> ${newStatus}`\n );\n return true;\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 更新CustomMCP缓存状态失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return false;\n }\n }\n\n /**\n * 标记 CustomMCP 缓存为已消费\n */\n async markCustomMCPAsConsumed(\n toolName: string,\n arguments_: Record<string, unknown>\n ): Promise<boolean> {\n try {\n const cache = await this.loadExtendedCache();\n const cacheKey = generateCacheKey(toolName, arguments_);\n\n if (!cache.customMCPResults || !cache.customMCPResults[cacheKey]) {\n return false;\n }\n\n const cacheEntry = cache.customMCPResults[cacheKey];\n if (cacheEntry.consumed) {\n return true;\n }\n\n cacheEntry.consumed = true;\n cacheEntry.timestamp = new Date().toISOString();\n\n await this.saveExtendedCache(cache);\n\n this.logger.debug(`[CacheManager] 标记缓存为已消费: ${toolName}`);\n return true;\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 标记CustomMCP缓存为已消费失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return false;\n }\n }\n\n /**\n * 删除 CustomMCP 缓存条目\n */\n async deleteCustomMCPResult(\n toolName: string,\n arguments_: Record<string, unknown>\n ): Promise<boolean> {\n try {\n const cache = await this.loadExtendedCache();\n const cacheKey = generateCacheKey(toolName, arguments_);\n\n if (!cache.customMCPResults || !cache.customMCPResults[cacheKey]) {\n return false;\n }\n\n delete cache.customMCPResults[cacheKey];\n await this.saveExtendedCache(cache);\n\n this.logger.debug(`[CacheManager] 删除缓存条目: ${toolName}`);\n return true;\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 删除CustomMCP缓存条目失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return false;\n }\n }\n\n /**\n * 批量清理 CustomMCP 缓存\n */\n async cleanupCustomMCPResults(): Promise<{ cleaned: number; total: number }> {\n try {\n const cache = await this.loadExtendedCache();\n\n if (!cache.customMCPResults) {\n return { cleaned: 0, total: 0 };\n }\n\n const entries = Object.entries(cache.customMCPResults);\n let cleanedCount = 0;\n\n for (const [cacheKey, cacheEntry] of entries) {\n if (shouldCleanupCache(cacheEntry)) {\n delete cache.customMCPResults[cacheKey];\n cleanedCount++;\n }\n }\n\n if (cleanedCount > 0) {\n await this.saveExtendedCache(cache);\n this.logger.info(\n `[CacheManager] 清理CustomMCP缓存: ${cleanedCount}/${entries.length}`\n );\n }\n\n return { cleaned: cleanedCount, total: entries.length };\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 清理CustomMCP缓存失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return { cleaned: 0, total: 0 };\n }\n }\n\n /**\n * 获取 CustomMCP 缓存统计信息\n */\n async getCustomMCPStatistics(): Promise<CacheStatistics> {\n try {\n const cache = await this.loadExtendedCache();\n\n if (!cache.customMCPResults) {\n return {\n totalEntries: 0,\n pendingTasks: 0,\n completedTasks: 0,\n failedTasks: 0,\n consumedEntries: 0,\n cacheHitRate: 0,\n lastCleanupTime: new Date().toISOString(),\n memoryUsage: 0,\n };\n }\n\n const entries = Object.values(cache.customMCPResults);\n const totalEntries = entries.length;\n const pendingTasks = entries.filter((e) => e.status === \"pending\").length;\n const completedTasks = entries.filter(\n (e) => e.status === \"completed\"\n ).length;\n const failedTasks = entries.filter((e) => e.status === \"failed\").length;\n const consumedEntries = entries.filter((e) => e.consumed).length;\n\n // 计算缓存命中率\n const cacheHitRate =\n completedTasks > 0 ? (consumedEntries / completedTasks) * 100 : 0;\n\n // 估算内存使用\n const memoryUsage = JSON.stringify(cache.customMCPResults).length;\n\n return {\n totalEntries,\n pendingTasks,\n completedTasks,\n failedTasks,\n consumedEntries,\n cacheHitRate,\n lastCleanupTime: new Date().toISOString(),\n memoryUsage,\n };\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 获取CustomMCP缓存统计失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return {\n totalEntries: 0,\n pendingTasks: 0,\n completedTasks: 0,\n failedTasks: 0,\n consumedEntries: 0,\n cacheHitRate: 0,\n lastCleanupTime: new Date().toISOString(),\n memoryUsage: 0,\n };\n }\n }\n\n /**\n * 加载扩展缓存(包含 CustomMCP 结果)\n */\n async loadExtendedCache(): Promise<ExtendedMCPToolsCache> {\n try {\n const cache = await this.loadExistingCache();\n return cache as ExtendedMCPToolsCache;\n } catch (error) {\n this.logger.warn(\n `[CacheManager] 加载扩展缓存失败: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n return {\n version: this.CACHE_VERSION,\n mcpServers: {},\n metadata: {\n lastGlobalUpdate: this.formatTimestamp(),\n totalWrites: 0,\n createdAt: this.formatTimestamp(),\n },\n customMCPResults: {},\n };\n }\n }\n\n /**\n * 保存扩展缓存(包含 CustomMCP 结果)\n */\n async saveExtendedCache(cache: ExtendedMCPToolsCache): Promise<void> {\n await this.saveCache(cache);\n }\n\n /**\n * 启动清理定时器\n */\n private startCleanupTimer(): void {\n this.cleanupInterval = setInterval(() => {\n this.cleanupCustomMCPResults().catch((error) => {\n this.logger.warn(`[CacheManager] 自动清理失败: ${error}`);\n });\n }, this.CLEANUP_INTERVAL);\n\n this.logger.debug(\n `[CacheManager] 启动清理定时器,间隔: ${this.CLEANUP_INTERVAL}ms`\n );\n }\n\n /**\n * 停止清理定时器\n */\n public stopCleanupTimer(): void {\n if (this.cleanupInterval) {\n clearInterval(this.cleanupInterval);\n this.cleanupInterval = undefined;\n this.logger.debug(\"[CacheManager] 停止清理定时器\");\n }\n }\n\n /**\n * 清理资源\n */\n public cleanup(): void {\n this.stopCleanupTimer();\n this.logger.debug(\"[CacheManager] 清理资源完成\");\n }\n}\n","export * from \"@/lib/mcp/manager.js\";\nexport * from \"@/lib/mcp/connection.js\";\nexport * from \"@/lib/mcp/types.js\";\nexport * from \"@/lib/mcp/utils.js\";\nexport * from \"@/lib/mcp/transport-factory.js\";\nexport * from \"./message.js\";\nexport * from \"@/lib/mcp/cache.js\";\nexport * from \"./custom.js\";\nexport * from \"./log.js\";\n// 选择性导出transports,避免重复的ConnectionState\nexport {\n TransportAdapter,\n StdioAdapter,\n WebSocketAdapter,\n type MCPMessage,\n type MCPResponse,\n type MCPError,\n type TransportConfig,\n type StdioConfig,\n type WebSocketConfig,\n} from \"@/lib/mcp/transports/index.js\";\n","import { logger } from \"@root/Logger.js\";\nimport type { Context, Next } from \"hono\";\n\n/**\n * Logger 中间件 - 将 logger 实例挂载到 Hono context\n * 使所有请求处理器可以通过 context 访问 logger\n */\nexport const loggerMiddleware = async (c: Context, next: Next) => {\n c.set(\"logger\", logger);\n await next();\n};\n","import { cors } from \"hono/cors\";\n\n/**\n * CORS 中间件配置\n * 支持通过环境变量 ALLOWED_ORIGINS 配置允许的来源列表\n * 多个来源用逗号分隔,例如:https://example.com,https://app.example.com\n * 未配置时默认允许所有来源(开发环境)\n */\nexport const corsMiddleware = cors({\n origin: process.env.ALLOWED_ORIGINS\n ? process.env.ALLOWED_ORIGINS.split(\",\").map((origin) => origin.trim())\n : \"*\",\n allowMethods: [\"GET\", \"POST\", \"PUT\", \"OPTIONS\"],\n allowHeaders: [\"Content-Type\"],\n});\n","import { logger } from \"@root/Logger.js\";\nimport type { Logger } from \"@root/Logger.js\";\nimport type { Context } from \"hono\";\n\n// 统一错误响应格式\nexport interface ApiErrorResponse {\n error: {\n code: string;\n message: string;\n details?: unknown;\n };\n}\n\nexport interface ApiSuccessResponse<T> {\n success: boolean;\n data?: T;\n message?: string;\n}\n\n/**\n * 创建统一的错误响应\n */\nexport const createErrorResponse = (\n code: string,\n message: string,\n details?: unknown\n): ApiErrorResponse => {\n return {\n error: {\n code,\n message,\n details,\n },\n };\n};\n\n/**\n * 创建统一的成功响应\n */\nexport const createSuccessResponse = <T>(\n data?: T,\n message?: string\n): ApiSuccessResponse<T> => {\n return {\n success: true,\n data,\n message,\n };\n};\n\n/**\n * 错误处理中间件\n */\nexport const errorHandlerMiddleware = (err: Error, c: Context) => {\n // 尝试从 context 获取 logger,如果失败则使用全局 logger\n let loggerInstance: Logger;\n try {\n const contextLogger = c.get(\"logger\");\n if (contextLogger) {\n loggerInstance = contextLogger as Logger;\n } else {\n loggerInstance = logger;\n }\n } catch {\n // 如果无法从 context 获取,使用全局 logger\n loggerInstance = logger;\n }\n\n // 在开发环境中打印详细错误信息\n if (process.env.NODE_ENV === \"development\") {\n console.error(\"HTTP Request Error:\", {\n error: err.message,\n stack: err.stack,\n path: c.req.path,\n method: c.req.method,\n });\n }\n\n loggerInstance.error(\"HTTP request error:\", err);\n const errorResponse = createErrorResponse(\n \"INTERNAL_SERVER_ERROR\",\n \"服务器内部错误\",\n process.env.NODE_ENV === \"development\" ? err.stack : undefined\n );\n return c.json(errorResponse, 500);\n};\n\n/**\n * 404 Not Found 处理中间件\n */\nexport const notFoundHandlerMiddleware = (c: Context) => {\n // 如果是 API 路径,返回 API_NOT_FOUND\n if (c.req.path.startsWith(\"/api/\")) {\n const errorResponse = createErrorResponse(\n \"API_NOT_FOUND\",\n \"请求的资源不存在\",\n {\n path: c.req.path,\n method: c.req.method,\n }\n );\n return c.json(errorResponse, 404);\n }\n\n // 非 API 路径返回通用的 NOT_FOUND\n const errorResponse = createErrorResponse(\"NOT_FOUND\", \"请求的资源不存在\", {\n path: c.req.path,\n method: c.req.method,\n });\n return c.json(errorResponse, 404);\n};\n","/**\n * MCP 中间件相关的错误定义\n */\n\n/**\n * MCPServiceManager 未初始化错误\n */\nexport class MCPServiceManagerNotInitializedError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"MCPServiceManagerNotInitializedError\";\n }\n}\n\n/**\n * WebServer 不可用错误\n */\nexport class WebServerNotAvailableError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"WebServerNotAvailableError\";\n }\n}\n","/**\n * MCP Service Manager 中间件\n * 将 MCPServiceManager 实例注入到 Hono Context 中\n * 提供统一的依赖注入模式,从 WebServer 获取实例而非 Singleton\n */\n\nimport { logger } from \"@root/Logger.js\";\nimport type { Context, Next } from \"hono\";\nimport {\n MCPServiceManagerNotInitializedError,\n WebServerNotAvailableError,\n} from \"../errors/MCPErrors.middleware.js\";\nimport type { AppContextVariables } from \"../types/hono.context.js\";\n\n/**\n * MCP Service Manager 中间件\n *\n * 功能:\n * 1. 从 WebServer 获取 MCPServiceManager 实例\n * 2. 将实例注入到 Hono Context\n * 3. 提供错误处理和日志记录\n * 4. 与 WebServer 生命周期绑定\n * 5. 使用 Hono Context 中的 logger 实现统一的日志配置\n *\n * @param c Hono Context\n * @param next 下一个中间件函数\n */\nexport const mcpServiceManagerMiddleware = async (\n c: Context<{ Variables: AppContextVariables }>,\n next: Next\n): Promise<void> => {\n // 检查是否已经注入,避免重复初始化\n if (!c.get(\"mcpServiceManager\")) {\n try {\n // 尝试从 Context 获取 logger,如果不存在则使用全局 logger\n const contextLogger = c.get(\"logger\") || logger;\n\n contextLogger.debug(\n \"[MCPMiddleware] 正在从 WebServer 获取 MCPServiceManager 实例\"\n );\n\n // 从 WebServer 获取实例\n const webServer = c.get(\"webServer\");\n if (!webServer) {\n throw new WebServerNotAvailableError(\"WebServer 未注入到 Context\");\n }\n\n const serviceManager = webServer.getMCPServiceManager();\n\n // 将实例注入到 Context\n c.set(\"mcpServiceManager\", serviceManager);\n\n contextLogger.debug(\n \"[MCPMiddleware] MCPServiceManager 实例已成功注入到 Context\"\n );\n } catch (error) {\n // 记录错误但不阻断请求处理\n const errorLogger = c.get(\"logger\") || logger;\n\n // 根据错误类型进行不同的处理\n if (error instanceof MCPServiceManagerNotInitializedError) {\n // MCPServiceManager 未初始化是临时状态,允许通过\n errorLogger.debug(\n \"[MCPMiddleware] MCPServiceManager 尚未初始化,允许通过\"\n );\n // 不设置实例,Handler 中需要处理未初始化的情况\n } else if (error instanceof WebServerNotAvailableError) {\n // WebServer 未注入是配置错误,应该抛出\n errorLogger.error(\"[MCPMiddleware] WebServer 配置错误:\", error.message);\n throw error;\n } else {\n // 其他未知错误,记录并抛出\n errorLogger.error(\n \"[MCPMiddleware] 获取 MCPServiceManager 时发生未知错误:\",\n error\n );\n throw error;\n }\n }\n }\n\n await next();\n};\n\n/**\n * 类型守卫:检查 Context 中是否存在 MCPServiceManager 实例\n *\n * @param c Hono Context\n * @returns 是否存在 MCPServiceManager 实例\n */\nexport const hasMCPServiceManager = (\n c: Context<{ Variables: AppContextVariables }>\n): boolean => {\n return c.get(\"mcpServiceManager\") !== undefined;\n};\n","/**\n * 小智连接管理器中间件\n * 负责将 endpointManager 注入到请求上下文中\n */\n\nimport type { MiddlewareHandler } from \"hono\";\nimport type { AppContext } from \"../types/hono.context.js\";\n\n/**\n * 小智连接管理器中间件\n * 从 WebServer 实例获取连接管理器并注入到上下文中\n */\nexport const endpointManagerMiddleware = (): MiddlewareHandler<AppContext> => {\n return async (c, next) => {\n // 从 WebServer 实例获取连接管理器\n const webServer = c.get(\"webServer\");\n if (!webServer) {\n throw new Error(\n \"WebServer 实例未注入到上下文中,请确保 webServerMiddleware 已正确配置\"\n );\n }\n\n if (!webServer.getEndpointManager) {\n throw new Error(\"WebServer 实例缺少 getEndpointManager 方法\");\n }\n\n try {\n const connectionManager = webServer.getEndpointManager();\n c.set(\"endpointManager\", connectionManager);\n } catch (error) {\n // 记录错误但不阻断请求\n if (error instanceof Error && error.message.includes(\"未初始化\")) {\n console.warn(\"小智连接管理器未初始化,使用 null 值:\", error.message);\n c.set(\"endpointManager\", null);\n } else {\n throw error;\n }\n }\n\n await next();\n };\n};\n","import type { ConfigManager } from \"@/lib/config/manager.js\";\nimport type { EndpointManager } from \"@/lib/endpoint/index.js\";\nimport type { ConnectionStatus } from \"@/lib/endpoint/index.js\";\nimport type { Logger } from \"@root/Logger.js\";\nimport { logger } from \"@root/Logger.js\";\nimport type { EventBus } from \"@services/EventBus.js\";\nimport { getEventBus } from \"@services/EventBus.js\";\nimport type { Context } from \"hono\";\n\n/**\n * HTTP 状态码类型定义\n */\ntype HttpStatusCode =\n | 200 // OK\n | 400 // Bad Request\n | 401 // Unauthorized\n | 403 // Forbidden\n | 404 // Not Found\n | 409 // Conflict\n | 500 // Internal Server Error\n | 503; // Service Unavailable;\n\n/**\n * 错误详情类型定义\n */\ninterface ErrorDetails {\n endpoint?: string;\n [key: string]: unknown;\n}\n\n/**\n * 统一响应格式接口\n */\ninterface ApiErrorResponse {\n error: {\n code: string;\n message: string;\n details?: ErrorDetails;\n };\n}\n\ninterface ApiSuccessResponse<T = unknown> {\n success: boolean;\n data?: T;\n message?: string;\n}\n\n/**\n * 端点操作成功响应接口\n */\ninterface EndpointOperationResponse {\n success: boolean;\n message: string;\n data: {\n endpoint: string;\n status: ConnectionStatus;\n operation: \"connect\" | \"disconnect\" | \"reconnect\" | \"add\" | \"remove\";\n };\n}\n\n/**\n * MCP 端点 API 处理器\n */\nexport class MCPEndpointApiHandler {\n private logger: Logger;\n private endpointManager: EndpointManager;\n private configManager: ConfigManager;\n private eventBus: EventBus;\n\n constructor(endpointManager: EndpointManager, configManager: ConfigManager) {\n this.logger = logger;\n this.endpointManager = endpointManager;\n this.configManager = configManager;\n this.eventBus = getEventBus();\n }\n\n /**\n * 创建统一的错误响应\n */\n private createErrorResponse(\n code: string,\n message: string,\n endpoint?: string,\n details?: Record<string, unknown>\n ): ApiErrorResponse {\n return {\n error: {\n code,\n message,\n details: endpoint ? { endpoint, ...details } : details,\n },\n };\n }\n\n /**\n * 创建统一的成功响应\n */\n private createSuccessResponse<T>(\n data?: T,\n message?: string\n ): ApiSuccessResponse<T> {\n return {\n success: true,\n data,\n message,\n };\n }\n\n /**\n * 从请求体中解析端点参数\n * @param c Hono 上下文\n * @param errorErrorCode 错误码,用于区分不同操作的错误\n * @returns 解析结果,成功时包含 endpoint,失败时包含可直接返回的 Response\n */\n private async parseEndpointFromBody(\n c: Context,\n errorErrorCode: string\n ): Promise<\n { ok: true; endpoint: string } | { ok: false; response: Response }\n > {\n let body: { endpoint: string };\n try {\n body = await c.req.json();\n } catch (error) {\n this.logger.error(\"JSON解析失败:\", error);\n const errorResponse = this.createErrorResponse(\n errorErrorCode,\n error instanceof Error ? error.message : \"JSON解析失败\"\n );\n return { ok: false, response: c.json(errorResponse, 500) };\n }\n\n const endpoint = body.endpoint;\n\n // 验证端点参数\n if (!endpoint || typeof endpoint !== \"string\") {\n const errorResponse = this.createErrorResponse(\n \"INVALID_ENDPOINT\",\n \"端点参数无效\",\n endpoint\n );\n return { ok: false, response: c.json(errorResponse, 400) };\n }\n\n return { ok: true, endpoint };\n }\n\n /**\n * 获取接入点状态\n * POST /api/endpoint/status\n */\n async getEndpointStatus(c: Context): Promise<Response> {\n const parseResult = await this.parseEndpointFromBody(\n c,\n \"ENDPOINT_STATUS_READ_ERROR\"\n );\n if (!parseResult.ok) {\n return parseResult.response;\n }\n\n const endpoint = parseResult.endpoint;\n this.logger.debug(`处理获取接入点状态请求: ${endpoint}`);\n try {\n // 获取连接状态\n const connectionStatus = this.endpointManager.getConnectionStatus();\n const endpointStatus = connectionStatus.find(\n (status) => status.endpoint === endpoint\n );\n\n if (!endpointStatus) {\n const errorResponse = this.createErrorResponse(\n \"ENDPOINT_NOT_FOUND\",\n \"端点不存在\",\n endpoint\n );\n return c.json(errorResponse, 404);\n }\n\n this.logger.debug(`获取接入点状态成功: ${endpoint}`);\n return c.json(this.createSuccessResponse(endpointStatus));\n } catch (error) {\n this.logger.error(\"获取接入点状态失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"ENDPOINT_STATUS_READ_ERROR\",\n error instanceof Error ? error.message : \"获取接入点状态失败\",\n endpoint\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 连接指定接入点\n * POST /api/endpoint/connect\n */\n async connectEndpoint(c: Context): Promise<Response> {\n const parseResult = await this.parseEndpointFromBody(\n c,\n \"ENDPOINT_CONNECT_ERROR\"\n );\n if (!parseResult.ok) {\n return parseResult.response;\n }\n\n const endpoint = parseResult.endpoint;\n this.logger.info(`处理接入点连接请求: ${endpoint}`);\n try {\n // 检查端点是否存在\n const connectionStatus = this.endpointManager.getConnectionStatus();\n const existingStatus = connectionStatus.find(\n (status) => status.endpoint === endpoint\n );\n\n if (!existingStatus) {\n const errorResponse = this.createErrorResponse(\n \"ENDPOINT_NOT_FOUND\",\n \"端点不存在,请先添加接入点\",\n endpoint\n );\n return c.json(errorResponse, 404);\n }\n\n if (existingStatus.connected) {\n const errorResponse = this.createErrorResponse(\n \"ENDPOINT_ALREADY_CONNECTED\",\n \"端点已连接\",\n endpoint\n );\n return c.json(errorResponse, 409);\n }\n\n // 执行连接操作 - 连接已存在的端点\n await this.endpointManager.connectExistingEndpoint(endpoint);\n\n // 获取连接后的状态\n const updatedConnectionStatus =\n this.endpointManager.getConnectionStatus();\n const endpointStatus = updatedConnectionStatus.find(\n (status) => status.endpoint === endpoint\n );\n\n if (!endpointStatus) {\n const errorResponse = this.createErrorResponse(\n \"ENDPOINT_STATUS_NOT_FOUND\",\n \"无法获取端点连接状态\",\n endpoint\n );\n return c.json(errorResponse, 500);\n }\n\n // 发送连接成功事件\n this.eventBus.emitEvent(\"endpoint:status:changed\", {\n endpoint,\n connected: true,\n operation: \"connect\",\n success: true,\n message: \"接入点连接成功\",\n timestamp: Date.now(),\n source: \"http-api\",\n });\n\n this.logger.info(`接入点连接成功: ${endpoint}`);\n const response = this.createSuccessResponse(endpointStatus);\n return c.json(response);\n } catch (error) {\n this.logger.error(\"接入点连接失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"ENDPOINT_CONNECT_ERROR\",\n error instanceof Error ? error.message : \"接入点连接失败\",\n endpoint\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 断开指定接入点\n * POST /api/endpoint/disconnect\n */\n async disconnectEndpoint(c: Context): Promise<Response> {\n const parseResult = await this.parseEndpointFromBody(\n c,\n \"ENDPOINT_DISCONNECT_ERROR\"\n );\n if (!parseResult.ok) {\n return parseResult.response;\n }\n\n const endpoint = parseResult.endpoint;\n this.logger.info(`处理接入点断开请求: ${endpoint}`);\n try {\n // 检查端点是否存在且已连接\n const connectionStatus = this.endpointManager.getConnectionStatus();\n const existingStatus = connectionStatus.find(\n (status) => status.endpoint === endpoint\n );\n\n if (!existingStatus) {\n const errorResponse = this.createErrorResponse(\n \"ENDPOINT_NOT_FOUND\",\n \"端点不存在\",\n endpoint\n );\n return c.json(errorResponse, 404);\n }\n\n if (!existingStatus.connected) {\n const errorResponse = this.createErrorResponse(\n \"ENDPOINT_NOT_CONNECTED\",\n \"端点未连接\",\n endpoint\n );\n return c.json(errorResponse, 409);\n }\n\n // 执行断开操作\n await this.endpointManager.disconnectEndpoint(endpoint);\n\n // 获取断开后的状态\n const updatedConnectionStatus =\n this.endpointManager.getConnectionStatus();\n const endpointStatus = updatedConnectionStatus.find(\n (status) => status.endpoint === endpoint\n );\n\n // 发送断开成功事件\n this.eventBus.emitEvent(\"endpoint:status:changed\", {\n endpoint,\n connected: false,\n operation: \"disconnect\",\n success: true,\n message: \"接入点断开成功\",\n timestamp: Date.now(),\n source: \"http-api\",\n });\n\n this.logger.info(`接入点断开成功: ${endpoint}`);\n const fallbackStatus: ConnectionStatus = {\n endpoint,\n connected: false,\n initialized: true,\n };\n const response = this.createSuccessResponse(\n endpointStatus || fallbackStatus\n );\n return c.json(response);\n } catch (error) {\n this.logger.error(\"接入点断开失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"ENDPOINT_DISCONNECT_ERROR\",\n error instanceof Error ? error.message : \"接入点断开失败\",\n endpoint\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 添加新接入点\n * POST /api/endpoint/add\n */\n async addEndpoint(c: Context): Promise<Response> {\n const parseResult = await this.parseEndpointFromBody(\n c,\n \"ENDPOINT_ADD_ERROR\"\n );\n if (!parseResult.ok) {\n return parseResult.response;\n }\n\n const endpoint = parseResult.endpoint;\n try {\n // 检查端点是否已存在\n const connectionStatus = this.endpointManager.getConnectionStatus();\n const existingStatus = connectionStatus.find(\n (status) => status.endpoint === endpoint\n );\n\n if (existingStatus) {\n const errorResponse = this.createErrorResponse(\n \"ENDPOINT_ALREADY_EXISTS\",\n \"接入点已存在\",\n endpoint\n );\n return c.json(errorResponse, 409);\n }\n\n // 执行添加操作\n await this.endpointManager.addEndpoint(endpoint);\n\n // 获取添加后的状态\n const updatedConnectionStatus =\n this.endpointManager.getConnectionStatus();\n const endpointStatus = updatedConnectionStatus.find(\n (status) => status.endpoint === endpoint\n );\n\n if (!endpointStatus) {\n const errorResponse = this.createErrorResponse(\n \"ENDPOINT_STATUS_NOT_FOUND\",\n \"无法获取端点状态\",\n endpoint\n );\n return c.json(errorResponse, 500);\n }\n\n // 发送添加成功事件\n this.eventBus.emitEvent(\"endpoint:status:changed\", {\n endpoint,\n connected: false,\n operation: \"add\",\n success: true,\n message: \"接入点添加成功\",\n timestamp: Date.now(),\n source: \"http-api\",\n });\n\n this.logger.info(`接入点添加成功: ${endpoint}`);\n const response = this.createSuccessResponse(endpointStatus);\n return c.json(response);\n } catch (error) {\n this.logger.error(\"接入点添加失败:\", error);\n let errorCode = \"ENDPOINT_ADD_ERROR\";\n let httpStatus = 500;\n\n // 处理特定错误类型\n if (error instanceof Error) {\n if (error.message.includes(\"已存在于配置文件中\")) {\n errorCode = \"ENDPOINT_ALREADY_IN_CONFIG\";\n httpStatus = 409;\n } else if (error.message.includes(\"已存在\")) {\n errorCode = \"ENDPOINT_ALREADY_EXISTS\";\n httpStatus = 409;\n } else if (error.message.includes(\"端点必须是非空字符串\")) {\n errorCode = \"INVALID_ENDPOINT\";\n httpStatus = 400;\n }\n }\n\n const errorResponse = this.createErrorResponse(\n errorCode,\n error instanceof Error ? error.message : \"接入点添加失败\",\n undefined\n );\n return c.json(errorResponse, httpStatus as HttpStatusCode);\n }\n }\n\n /**\n * 移除接入点\n * POST /api/endpoint/remove\n */\n async removeEndpoint(c: Context): Promise<Response> {\n const parseResult = await this.parseEndpointFromBody(\n c,\n \"ENDPOINT_REMOVE_ERROR\"\n );\n if (!parseResult.ok) {\n return parseResult.response;\n }\n\n const endpoint = parseResult.endpoint;\n this.logger.info(`处理接入点移除请求: ${endpoint}`);\n try {\n // 检查端点是否存在\n const connectionStatus = this.endpointManager.getConnectionStatus();\n const existingStatus = connectionStatus.find(\n (status) => status.endpoint === endpoint\n );\n\n if (!existingStatus) {\n const errorResponse = this.createErrorResponse(\n \"ENDPOINT_NOT_FOUND\",\n \"端点不存在\",\n endpoint\n );\n return c.json(errorResponse, 404);\n }\n\n // 如果端点已连接,先断开连接\n if (existingStatus.connected) {\n await this.endpointManager.disconnectEndpoint(endpoint);\n }\n\n // 执行移除操作\n await this.endpointManager.removeEndpoint(endpoint);\n\n // 发送移除成功事件\n this.eventBus.emitEvent(\"endpoint:status:changed\", {\n endpoint,\n connected: false,\n operation: \"remove\",\n success: true,\n message: \"接入点移除成功\",\n timestamp: Date.now(),\n source: \"http-api\",\n });\n\n this.logger.info(`接入点移除成功: ${endpoint}`);\n const response = this.createSuccessResponse({\n endpoint,\n operation: \"remove\",\n success: true,\n message: \"接入点移除成功\",\n });\n return c.json(response);\n } catch (error) {\n this.logger.error(\"接入点移除失败:\", error);\n let errorCode = \"ENDPOINT_REMOVE_ERROR\";\n let httpStatus = 500;\n\n // 处理特定错误类型\n if (error instanceof Error) {\n if (error.message.includes(\"不存在\")) {\n errorCode = \"ENDPOINT_NOT_FOUND\";\n httpStatus = 404;\n } else if (error.message.includes(\"端点必须是非空字符串\")) {\n errorCode = \"INVALID_ENDPOINT\";\n httpStatus = 400;\n }\n }\n\n const errorResponse = this.createErrorResponse(\n errorCode,\n error instanceof Error ? error.message : \"接入点移除失败\",\n endpoint\n );\n return c.json(errorResponse, httpStatus as HttpStatusCode);\n }\n }\n}\n","/**\n * 小智端点处理器中间件\n * 负责创建和管理 MCPEndpointApiHandler 实例\n */\n\nimport { configManager } from \"@/lib/config/manager.js\";\nimport type { EndpointManager } from \"@/lib/endpoint/index.js\";\nimport { MCPEndpointApiHandler } from \"@handlers/MCPEndpointApiHandler.js\";\nimport type { MiddlewareHandler } from \"hono\";\nimport type { AppContext } from \"../types/hono.context.js\";\n\n/**\n * 小智端点处理器中间件\n * 创建单例的 MCPEndpointApiHandler 并注入到上下文中\n */\nexport const endpointsMiddleware = (): MiddlewareHandler<AppContext> => {\n // 使用闭包缓存 handler 实例和 manager\n let endpointHandler: MCPEndpointApiHandler | null = null;\n let lastManager: EndpointManager | null | undefined = undefined;\n\n return async (c, next) => {\n const endpointManager = c.get(\"endpointManager\");\n\n // 如果 manager 发生变化,则重建 handler\n // 注意:使用引用相等检查(!==)确保使用最新的 manager 实例\n // 即使 manager 内容相同,但对象引用不同时也会重建 handler\n // 这是期望的行为,确保 handler 总是使用最新的连接管理\n if (endpointManager !== lastManager) {\n lastManager = endpointManager;\n if (endpointManager) {\n endpointHandler = new MCPEndpointApiHandler(\n endpointManager,\n configManager\n );\n } else {\n endpointHandler = null;\n }\n }\n\n // 将 handler 注入到上下文中\n c.set(\"endpointHandler\", endpointHandler);\n\n await next();\n };\n};\n","export { loggerMiddleware } from \"./logger.middleware.js\";\nexport { corsMiddleware } from \"./cors.middleware.js\";\nexport {\n errorHandlerMiddleware,\n notFoundHandlerMiddleware,\n createErrorResponse,\n createSuccessResponse,\n} from \"./error.middleware.js\";\nexport {\n mcpServiceManagerMiddleware,\n hasMCPServiceManager,\n} from \"./mcpServiceManager.middleware.js\";\nexport { endpointManagerMiddleware } from \"./endpointManager.middleware.js\";\nexport { endpointsMiddleware } from \"./endpoints.middleware.js\";\n\n// 重新导出 context 相关函数\nexport {\n getMCPServiceManager,\n requireMCPServiceManager,\n} from \"../types/hono.context.js\";\n","import type { Logger } from \"@root/Logger.js\";\nimport type { Context } from \"hono\";\n\n/**\n * 抽象 API Handler 基类\n * 提供统一的 Logger 获取方法\n */\nexport abstract class AbstractApiHandler {\n /**\n * 从 context 获取 logger 实例\n * @param c - Hono context\n * @returns Logger 实例\n * @throws Error 如果 logger 未在 context 中设置\n */\n protected getLogger(c: Context): Logger {\n const logger = c.get(\"logger\");\n if (!logger) {\n throw new Error(\n \"Logger not found in context. Ensure loggerMiddleware is registered.\"\n );\n }\n return logger as Logger;\n }\n}\n","import type { AppConfig } from \"@/lib/config/manager.js\";\nimport { configManager } from \"@/lib/config/manager.js\";\nimport {\n createErrorResponse,\n createSuccessResponse,\n} from \"@middlewares/index.js\";\nimport type { Context } from \"hono\";\nimport { AbstractApiHandler } from \"./AbstractApiHandler.js\";\n\n/**\n * 配置 API 处理器\n */\nexport class ConfigApiHandler extends AbstractApiHandler {\n constructor() {\n super();\n }\n\n /**\n * 获取配置\n * GET /api/config\n */\n async getConfig(c: Context): Promise<Response> {\n const logger = this.getLogger(c);\n try {\n logger.debug(\"处理获取配置请求\");\n const config = configManager.getConfig();\n logger.info(\"获取配置成功\");\n return c.json(createSuccessResponse(config));\n } catch (error) {\n logger.error(\"获取配置失败:\", error);\n const errorResponse = createErrorResponse(\n \"CONFIG_READ_ERROR\",\n error instanceof Error ? error.message : \"获取配置失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 更新配置\n * PUT /api/config\n */\n async updateConfig(c: Context): Promise<Response> {\n const logger = this.getLogger(c);\n try {\n logger.debug(\"处理更新配置请求\");\n const newConfig: AppConfig = await c.req.json();\n\n // 使用 configManager 的验证方法\n configManager.validateConfig(newConfig);\n\n // 使用 configManager 的批量更新方法\n configManager.updateConfig(newConfig);\n\n // 更新服务工具配置(单独处理,因为 updateConfig 只更新已存在的配置)\n if (newConfig.mcpServerConfig) {\n for (const [serverName, toolsConfig] of Object.entries(\n newConfig.mcpServerConfig\n )) {\n for (const [toolName, toolConfig] of Object.entries(\n toolsConfig.tools\n )) {\n configManager.setToolEnabled(\n serverName,\n toolName,\n toolConfig.enable\n );\n }\n }\n }\n\n logger.info(\"配置更新成功\");\n return c.json(createSuccessResponse(null, \"配置更新成功\"));\n } catch (error) {\n logger.error(\"配置更新失败:\", error);\n const errorResponse = createErrorResponse(\n \"CONFIG_UPDATE_ERROR\",\n error instanceof Error ? error.message : \"配置更新失败\"\n );\n return c.json(errorResponse, 400);\n }\n }\n\n /**\n * 获取 MCP 端点\n * GET /api/config/mcp-endpoint\n */\n async getMcpEndpoint(c: Context): Promise<Response> {\n const logger = this.getLogger(c);\n try {\n logger.debug(\"处理获取 MCP 端点请求\");\n const endpoint = configManager.getMcpEndpoint();\n logger.debug(\"获取 MCP 端点成功\");\n return c.json(createSuccessResponse({ endpoint }));\n } catch (error) {\n logger.error(\"获取 MCP 端点失败:\", error);\n const errorResponse = createErrorResponse(\n \"MCP_ENDPOINT_READ_ERROR\",\n error instanceof Error ? error.message : \"获取 MCP 端点失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 获取 MCP 端点列表\n * GET /api/config/mcp-endpoints\n */\n async getMcpEndpoints(c: Context): Promise<Response> {\n const logger = this.getLogger(c);\n try {\n logger.debug(\"处理获取 MCP 端点列表请求\");\n const endpoints = configManager.getMcpEndpoints();\n logger.debug(\"获取 MCP 端点列表成功\");\n return c.json(createSuccessResponse({ endpoints }));\n } catch (error) {\n logger.error(\"获取 MCP 端点列表失败:\", error);\n const errorResponse = createErrorResponse(\n \"MCP_ENDPOINTS_READ_ERROR\",\n error instanceof Error ? error.message : \"获取 MCP 端点列表失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 获取 MCP 服务配置\n * GET /api/config/mcp-servers\n */\n async getMcpServers(c: Context): Promise<Response> {\n const logger = this.getLogger(c);\n try {\n logger.debug(\"处理获取 MCP 服务配置请求\");\n const servers = configManager.getMcpServers();\n logger.debug(\"获取 MCP 服务配置成功\");\n return c.json(createSuccessResponse({ servers }));\n } catch (error) {\n logger.error(\"获取 MCP 服务配置失败:\", error);\n const errorResponse = createErrorResponse(\n \"MCP_SERVERS_READ_ERROR\",\n error instanceof Error ? error.message : \"获取 MCP 服务配置失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 获取连接配置\n * GET /api/config/connection\n */\n async getConnectionConfig(c: Context): Promise<Response> {\n const logger = this.getLogger(c);\n try {\n logger.debug(\"处理获取连接配置请求\");\n const connection = configManager.getConnectionConfig();\n logger.debug(\"获取连接配置成功\");\n return c.json(createSuccessResponse({ connection }));\n } catch (error) {\n logger.error(\"获取连接配置失败:\", error);\n const errorResponse = createErrorResponse(\n \"CONNECTION_CONFIG_READ_ERROR\",\n error instanceof Error ? error.message : \"获取连接配置失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 重新加载配置\n * POST /api/config/reload\n */\n async reloadConfig(c: Context): Promise<Response> {\n const logger = this.getLogger(c);\n try {\n logger.info(\"处理重新加载配置请求\");\n configManager.reloadConfig();\n const config = configManager.getConfig();\n logger.info(\"重新加载配置成功\");\n return c.json(createSuccessResponse(config, \"配置重新加载成功\"));\n } catch (error) {\n logger.error(\"重新加载配置失败:\", error);\n const errorResponse = createErrorResponse(\n \"CONFIG_RELOAD_ERROR\",\n error instanceof Error ? error.message : \"重新加载配置失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 获取配置文件路径\n * GET /api/config/path\n */\n async getConfigPath(c: Context): Promise<Response> {\n const logger = this.getLogger(c);\n try {\n logger.debug(\"处理获取配置文件路径请求\");\n const path = configManager.getConfigPath();\n logger.debug(\"获取配置文件路径成功\");\n return c.json(createSuccessResponse({ path }));\n } catch (error) {\n logger.error(\"获取配置文件路径失败:\", error);\n const errorResponse = createErrorResponse(\n \"CONFIG_PATH_READ_ERROR\",\n error instanceof Error ? error.message : \"获取配置文件路径失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 检查配置是否存在\n * GET /api/config/exists\n */\n async checkConfigExists(c: Context): Promise<Response> {\n const logger = this.getLogger(c);\n try {\n logger.debug(\"处理检查配置是否存在请求\");\n const exists = configManager.configExists();\n logger.debug(`配置存在检查结果: ${exists}`);\n return c.json(createSuccessResponse({ exists }));\n } catch (error) {\n logger.error(\"检查配置是否存在失败:\", error);\n const errorResponse = createErrorResponse(\n \"CONFIG_EXISTS_CHECK_ERROR\",\n error instanceof Error ? error.message : \"检查配置是否存在失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n}\n","/**\n * 扣子 API HTTP 路由处理器\n * 提供扣子工作空间和工作流相关的 RESTful API 接口\n */\n\nimport { configManager } from \"@/lib/config/manager.js\";\nimport { CozeApiService } from \"@/lib/coze\";\nimport { logger } from \"@root/Logger\";\nimport type { CozeWorkflowsParams } from \"@root/types/coze\";\nimport type { Context } from \"hono\";\n\n/**\n * 错误代码类型\n */\ntype CozeErrorCode =\n | \"AUTH_FAILED\"\n | \"RATE_LIMITED\"\n | \"TIMEOUT\"\n | \"API_ERROR\"\n | \"NETWORK_ERROR\";\n\n/**\n * 带 code 属性的错误接口\n */\ninterface ErrorWithCode {\n code: CozeErrorCode;\n message: string;\n statusCode?: number;\n response?: unknown;\n}\n\n/**\n * 类型守卫函数:检查错误是否带有 code 属性\n */\nfunction isErrorWithCode(error: unknown): error is ErrorWithCode {\n if (!(error instanceof Error && \"code\" in error)) {\n return false;\n }\n\n const code = (error as ErrorWithCode).code;\n const validCodes: CozeErrorCode[] = [\n \"AUTH_FAILED\",\n \"RATE_LIMITED\",\n \"TIMEOUT\",\n \"API_ERROR\",\n \"NETWORK_ERROR\",\n ];\n\n return typeof code === \"string\" && validCodes.includes(code as CozeErrorCode);\n}\n\n/**\n * 统一的 API 响应格式\n */\ninterface ApiResponse<T = unknown> {\n success: boolean;\n data?: T;\n message?: string;\n}\n\n/**\n * 错误响应格式\n */\ninterface ErrorResponse {\n success: false;\n message: string;\n error?: {\n code: string;\n details?: unknown;\n };\n}\n\n/**\n * 创建成功响应\n */\nfunction createSuccessResponse<T>(data: T, message?: string): ApiResponse<T> {\n return {\n success: true,\n data,\n message,\n };\n}\n\n/**\n * 创建错误响应\n */\nfunction createErrorResponse(\n message: string,\n code?: string,\n details?: unknown\n): ErrorResponse {\n return {\n success: false,\n message,\n error: code ? { code, details } : undefined,\n };\n}\n\n/**\n * 获取扣子 API 服务实例\n */\nfunction getCozeApiService(): CozeApiService {\n const token = configManager.getCozeToken();\n\n if (!token) {\n throw new Error(\n \"扣子 API Token 未配置,请在配置文件中设置 platforms.coze.token\"\n );\n }\n\n return new CozeApiService(token);\n}\n\n/**\n * 扣子 API 路由处理器类\n */\nexport class CozeApiHandler {\n /**\n * 获取工作空间列表\n * GET /api/coze/workspaces\n */\n async getWorkspaces(c: Context): Promise<Response> {\n try {\n logger.info(\"处理获取工作空间列表请求\");\n\n // 检查扣子配置\n if (!configManager.isCozeConfigValid()) {\n logger.debug(\"扣子配置无效\");\n return c.json(\n createErrorResponse(\n \"扣子配置无效,请检查 platforms.coze.token 配置\",\n \"CONFIG_INVALID\"\n ),\n 400\n );\n }\n\n const cozeApiService = getCozeApiService();\n\n logger.info(\"调用 Coze API 获取工作空间列表\");\n const workspaces = await cozeApiService.getWorkspaces();\n logger.info(`成功获取 ${workspaces.length} 个工作空间`);\n\n return c.json(\n createSuccessResponse({\n workspaces,\n })\n );\n } catch (error) {\n logger.error(\"获取工作空间列表失败:\", error);\n\n // 根据错误类型返回不同的响应\n if (isErrorWithCode(error) && error.code === \"AUTH_FAILED\") {\n return c.json(\n createErrorResponse(\n \"扣子 API 认证失败,请检查 Token 配置\",\n \"AUTH_FAILED\"\n ),\n 401\n );\n }\n\n if (isErrorWithCode(error) && error.code === \"RATE_LIMITED\") {\n return c.json(\n createErrorResponse(\"请求过于频繁,请稍后重试\", \"RATE_LIMITED\"),\n 429\n );\n }\n\n if (isErrorWithCode(error) && error.code === \"TIMEOUT\") {\n return c.json(\n createErrorResponse(\"请求超时,请稍后重试\", \"TIMEOUT\"),\n 408\n );\n }\n\n return c.json(\n createErrorResponse(\n error instanceof Error ? error.message : \"获取工作空间列表失败\",\n \"INTERNAL_ERROR\",\n process.env.NODE_ENV === \"development\" && error instanceof Error\n ? error.stack\n : undefined\n ),\n 500\n );\n }\n }\n\n /**\n * 获取工作流列表\n * GET /api/coze/workflows?workspace_id=xxx&page_num=1&page_size=20\n */\n async getWorkflows(c: Context): Promise<Response> {\n try {\n logger.info(\"处理获取工作流列表请求\");\n\n // 检查扣子配置\n if (!configManager.isCozeConfigValid()) {\n logger.debug(\"扣子配置无效\");\n return c.json(\n createErrorResponse(\n \"扣子配置无效,请检查 platforms.coze.token 配置\",\n \"CONFIG_INVALID\"\n ),\n 400\n );\n }\n\n // 解析查询参数\n const workspace_id = c.req.query(\"workspace_id\");\n const page_num = Number.parseInt(c.req.query(\"page_num\") || \"1\", 10);\n const page_size = Number.parseInt(c.req.query(\"page_size\") || \"20\", 10);\n\n // 验证必需参数\n if (!workspace_id) {\n logger.warn(\"缺少 workspace_id 参数\");\n return c.json(\n createErrorResponse(\n \"缺少必需参数: workspace_id\",\n \"MISSING_PARAMETER\"\n ),\n 400\n );\n }\n\n // 验证分页参数\n if (page_num < 1 || page_num > 1000) {\n return c.json(\n createErrorResponse(\n \"page_num 必须在 1-1000 之间\",\n \"INVALID_PARAMETER\"\n ),\n 400\n );\n }\n\n if (page_size < 1 || page_size > 100) {\n return c.json(\n createErrorResponse(\n \"page_size 必须在 1-100 之间\",\n \"INVALID_PARAMETER\"\n ),\n 400\n );\n }\n\n const params: CozeWorkflowsParams = {\n workspace_id,\n page_num,\n page_size,\n };\n\n const cozeApiService = getCozeApiService();\n\n logger.info(\n `开始获取工作空间 ${workspace_id} 的工作流列表,页码: ${page_num},每页: ${page_size}`\n );\n const result = await cozeApiService.getWorkflows(params);\n logger.info(\n `成功获取工作空间 ${workspace_id} 的 ${result.items.length} 个工作流`\n );\n\n // 获取已添加的自定义工具列表,检查工作流是否已被添加为工具\n const customMCPTools = configManager.getCustomMCPTools();\n\n // 为每个工作流添加工具状态信息\n const enhancedItems = result.items.map((item) => {\n // 查找对应的自定义工具\n const addedTool = customMCPTools.find(\n (tool) =>\n tool.handler.type === \"proxy\" &&\n tool.handler.platform === \"coze\" &&\n tool.handler.config.workflow_id === item.workflow_id\n );\n\n return {\n ...item,\n isAddedAsTool: !!addedTool,\n toolName: addedTool?.name || null,\n };\n });\n\n logger.info(\n `工作流工具状态检查完成,共 ${enhancedItems.filter((item) => item.isAddedAsTool).length} 个工作流已添加为工具`\n );\n\n return c.json(\n createSuccessResponse({\n items: enhancedItems,\n has_more: result.has_more,\n page_num,\n page_size,\n total_count: result.items.length, // 当前页的数量\n })\n );\n } catch (error) {\n logger.error(\"获取工作流列表失败:\", error);\n\n // 根据错误类型返回不同的响应\n if (isErrorWithCode(error) && error.code === \"AUTH_FAILED\") {\n return c.json(\n createErrorResponse(\n \"扣子 API 认证失败,请检查 Token 配置\",\n \"AUTH_FAILED\"\n ),\n 401\n );\n }\n\n if (isErrorWithCode(error) && error.code === \"RATE_LIMITED\") {\n return c.json(\n createErrorResponse(\"请求过于频繁,请稍后重试\", \"RATE_LIMITED\"),\n 429\n );\n }\n\n if (isErrorWithCode(error) && error.code === \"TIMEOUT\") {\n return c.json(\n createErrorResponse(\"请求超时,请稍后重试\", \"TIMEOUT\"),\n 408\n );\n }\n\n return c.json(\n createErrorResponse(\n error instanceof Error ? error.message : \"获取工作流列表失败\",\n \"INTERNAL_ERROR\",\n process.env.NODE_ENV === \"development\" && error instanceof Error\n ? error.stack\n : undefined\n ),\n 500\n );\n }\n }\n\n /**\n * 清除扣子 API 缓存\n * POST /api/coze/cache/clear\n */\n async clearCache(c: Context): Promise<Response> {\n try {\n logger.info(\"处理清除扣子 API 缓存请求\");\n\n // 检查扣子配置\n if (!configManager.isCozeConfigValid()) {\n logger.debug(\"扣子配置无效\");\n return c.json(\n createErrorResponse(\n \"扣子配置无效,请检查 platforms.coze.token 配置\",\n \"CONFIG_INVALID\"\n ),\n 400\n );\n }\n\n const pattern = c.req.query(\"pattern\"); // 可选的缓存模式参数\n\n const cozeApiService = getCozeApiService();\n\n const statsBefore = cozeApiService.getCacheStats();\n logger.info(`开始清除缓存${pattern ? ` (模式: ${pattern})` : \"\"}`);\n\n cozeApiService.clearCache(pattern);\n\n const statsAfter = cozeApiService.getCacheStats();\n\n logger.info(\n `缓存清除完成,清除前: ${statsBefore.size} 项,清除后: ${statsAfter.size} 项`\n );\n\n return c.json(\n createSuccessResponse(\n {\n cleared: statsBefore.size - statsAfter.size,\n remaining: statsAfter.size,\n pattern: pattern || \"all\",\n },\n \"缓存清除成功\"\n )\n );\n } catch (error) {\n logger.error(\"清除缓存失败:\", error);\n\n return c.json(\n createErrorResponse(\n error instanceof Error ? error.message : \"清除缓存失败\",\n \"INTERNAL_ERROR\",\n process.env.NODE_ENV === \"development\" && error instanceof Error\n ? error.stack\n : undefined\n ),\n 500\n );\n }\n }\n\n /**\n * 获取缓存统计信息\n * GET /api/coze/cache/stats\n */\n async getCacheStats(c: Context): Promise<Response> {\n try {\n logger.info(\"处理获取缓存统计信息请求\");\n\n // 检查扣子配置\n if (!configManager.isCozeConfigValid()) {\n logger.debug(\"扣子配置无效\");\n return c.json(\n createErrorResponse(\n \"扣子配置无效,请检查 platforms.coze.token 配置\",\n \"CONFIG_INVALID\"\n ),\n 400\n );\n }\n\n const cozeApiService = getCozeApiService();\n const stats = cozeApiService.getCacheStats();\n\n return c.json(createSuccessResponse(stats));\n } catch (error) {\n logger.error(\"获取缓存统计信息失败:\", error);\n\n return c.json(\n createErrorResponse(\n error instanceof Error ? error.message : \"获取缓存统计信息失败\",\n \"INTERNAL_ERROR\",\n process.env.NODE_ENV === \"development\" && error instanceof Error\n ? error.stack\n : undefined\n ),\n 500\n );\n }\n }\n}\n","import { configManager } from \"@/lib/config/manager.js\";\nimport type { Logger } from \"@root/Logger.js\";\nimport { logger } from \"@root/Logger.js\";\nimport type { NotificationService } from \"@services/NotificationService.js\";\nimport type { StatusService } from \"@services/StatusService.js\";\n\n/**\n * 心跳消息接口\n */\ninterface HeartbeatMessage {\n type: \"clientStatus\";\n data: {\n status?: \"connected\" | \"disconnected\";\n mcpEndpoint?: string;\n activeMCPServers?: string[];\n timestamp?: number;\n };\n}\n\n/**\n * 心跳处理器\n */\nexport class HeartbeatHandler {\n private logger: Logger;\n private statusService: StatusService;\n private notificationService: NotificationService;\n\n constructor(\n statusService: StatusService,\n notificationService: NotificationService\n ) {\n this.logger = logger;\n this.statusService = statusService;\n this.notificationService = notificationService;\n }\n\n /**\n * 处理客户端状态更新(心跳)\n */\n async handleClientStatus(\n ws: any,\n message: HeartbeatMessage,\n clientId: string\n ): Promise<void> {\n try {\n this.logger.debug(`处理客户端状态更新: ${clientId}`, message.data);\n\n // 更新客户端信息\n const statusUpdate = {\n ...message.data,\n lastHeartbeat: Date.now(),\n };\n\n this.statusService.updateClientInfo(\n statusUpdate,\n `websocket-${clientId}`\n );\n\n // 发送最新配置给客户端(心跳响应)\n await this.sendLatestConfig(ws, clientId);\n\n this.logger.debug(`客户端状态更新成功: ${clientId}`);\n } catch (error) {\n this.logger.error(`处理客户端状态更新失败: ${clientId}`, error);\n this.sendError(\n ws,\n \"CLIENT_STATUS_ERROR\",\n error instanceof Error ? error.message : \"客户端状态更新失败\"\n );\n }\n }\n\n /**\n * 发送最新配置给客户端\n */\n private async sendLatestConfig(ws: any, clientId: string): Promise<void> {\n try {\n const latestConfig = configManager.getConfig();\n const message = {\n type: \"configUpdate\",\n data: latestConfig,\n timestamp: Date.now(),\n };\n\n ws.send(JSON.stringify(message));\n this.logger.debug(`最新配置已发送给客户端: ${clientId}`);\n } catch (error) {\n this.logger.error(`发送最新配置失败: ${clientId}`, error);\n // 不抛出错误,避免影响心跳处理\n }\n }\n\n /**\n * 发送错误消息\n */\n private sendError(ws: any, code: string, message: string): void {\n try {\n const errorResponse = {\n type: \"error\",\n error: {\n code,\n message,\n timestamp: Date.now(),\n },\n };\n ws.send(JSON.stringify(errorResponse));\n } catch (error) {\n this.logger.error(\"发送错误消息失败:\", error);\n }\n }\n\n /**\n * 检查客户端心跳超时\n */\n checkHeartbeatTimeout(): void {\n const lastHeartbeat = this.statusService.getLastHeartbeat();\n const now = Date.now();\n const HEARTBEAT_TIMEOUT = 35000; // 35 seconds\n\n if (lastHeartbeat && now - lastHeartbeat > HEARTBEAT_TIMEOUT) {\n this.logger.warn(\"客户端心跳超时,标记为断开连接\");\n this.statusService.updateClientInfo(\n { status: \"disconnected\" },\n \"heartbeat-timeout\"\n );\n }\n }\n\n /**\n * 启动心跳监控\n */\n startHeartbeatMonitoring(): NodeJS.Timeout {\n const MONITOR_INTERVAL = 10000; // 10 seconds\n\n this.logger.debug(\"启动心跳监控\");\n\n return setInterval(() => {\n this.checkHeartbeatTimeout();\n this.cleanupDisconnectedClients();\n }, MONITOR_INTERVAL);\n }\n\n /**\n * 清理断开连接的客户端\n */\n private cleanupDisconnectedClients(): void {\n try {\n this.notificationService.cleanupDisconnectedClients();\n } catch (error) {\n this.logger.error(\"清理断开连接的客户端失败:\", error);\n }\n }\n\n /**\n * 停止心跳监控\n */\n stopHeartbeatMonitoring(intervalId: NodeJS.Timeout): void {\n this.logger.info(\"停止心跳监控\");\n clearInterval(intervalId);\n }\n\n /**\n * 获取心跳统计信息\n */\n getHeartbeatStats(): {\n lastHeartbeat?: number;\n isConnected: boolean;\n clientStats: {\n totalClients: number;\n connectedClients: number;\n queuedMessages: number;\n };\n } {\n return {\n lastHeartbeat: this.statusService.getLastHeartbeat(),\n isConnected: this.statusService.isClientConnected(),\n clientStats: this.notificationService.getClientStats(),\n };\n }\n\n /**\n * 处理客户端连接建立\n */\n handleClientConnect(clientId: string): void {\n this.logger.info(`客户端连接建立: ${clientId}`);\n\n // 更新状态为连接\n this.statusService.updateClientInfo(\n {\n status: \"connected\",\n lastHeartbeat: Date.now(),\n },\n `websocket-connect-${clientId}`\n );\n }\n\n /**\n * 处理客户端连接断开\n */\n handleClientDisconnect(clientId: string): void {\n this.logger.info(`客户端连接断开: ${clientId}`);\n\n // 更新状态为断开连接\n this.statusService.updateClientInfo(\n { status: \"disconnected\" },\n `websocket-disconnect-${clientId}`\n );\n }\n\n /**\n * 发送心跳响应\n */\n sendHeartbeatResponse(ws: any, clientId: string): void {\n try {\n const response = {\n type: \"heartbeatResponse\",\n data: {\n timestamp: Date.now(),\n status: \"ok\",\n },\n };\n\n ws.send(JSON.stringify(response));\n this.logger.debug(`心跳响应已发送: ${clientId}`);\n } catch (error) {\n this.logger.error(`发送心跳响应失败: ${clientId}`, error);\n }\n }\n\n /**\n * 验证心跳消息格式\n */\n validateHeartbeatMessage(message: any): message is HeartbeatMessage {\n return (\n message &&\n typeof message === \"object\" &&\n message.type === \"clientStatus\" &&\n message.data &&\n typeof message.data === \"object\"\n );\n }\n}\n","/**\n * MCP 路由处理器\n * 处理符合 MCP Streamable HTTP 规范的单一 /mcp 端点\n * 支持 POST 请求(JSON-RPC 消息)和 GET 请求(SSE 连接)\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport type { MCPServiceManager } from \"@/lib/mcp\";\nimport { MCPMessageHandler } from \"@/lib/mcp/message.js\";\nimport type { Logger } from \"@root/Logger.js\";\nimport { logger } from \"@root/Logger.js\";\nimport type { MCPMessage, MCPResponse } from \"@root/types/mcp.js\";\nimport type { Context } from \"hono\";\n\n/**\n * SSE 客户端接口\n */\ninterface SSEClient {\n id: string;\n sessionId: string;\n response: Response;\n connectedAt: Date;\n lastActivity: Date;\n writer?: WritableStreamDefaultWriter<Uint8Array>;\n abortController?: AbortController;\n heartbeatInterval?: NodeJS.Timeout;\n isAlive: boolean;\n messageCount: number;\n userAgent?: string;\n remoteAddress?: string;\n}\n\n/**\n * MCP 路由处理器配置接口\n */\ninterface MCPRouteHandlerConfig {\n maxClients?: number;\n connectionTimeout?: number;\n heartbeatInterval?: number;\n maxMessageSize?: number;\n enableMetrics?: boolean;\n}\n\n/**\n * 连接统计信息\n */\ninterface ConnectionMetrics {\n totalConnections: number;\n activeConnections: number;\n totalMessages: number;\n errorCount: number;\n averageResponseTime: number;\n uptime: number;\n}\n\n/**\n * MCP 路由处理器\n * 实现符合 MCP Streamable HTTP 规范的单一端点处理\n */\nexport class MCPRouteHandler {\n private logger: Logger;\n private mcpMessageHandler: MCPMessageHandler | null = null;\n private clients: Map<string, SSEClient> = new Map();\n private config: Required<MCPRouteHandlerConfig>;\n private metrics: ConnectionMetrics;\n private cleanupInterval: NodeJS.Timeout | null = null;\n private startTime: Date;\n\n constructor(config: MCPRouteHandlerConfig = {}) {\n this.logger = logger;\n this.config = {\n maxClients: config.maxClients ?? 100,\n connectionTimeout: config.connectionTimeout ?? 300000, // 5分钟\n heartbeatInterval: config.heartbeatInterval ?? 30000, // 30秒\n maxMessageSize: config.maxMessageSize ?? 1024 * 1024, // 1MB\n enableMetrics: config.enableMetrics ?? true,\n };\n\n this.metrics = {\n totalConnections: 0,\n activeConnections: 0,\n totalMessages: 0,\n errorCount: 0,\n averageResponseTime: 0,\n uptime: 0,\n };\n\n this.startTime = new Date();\n\n // 启动清理任务\n this.startCleanupTask();\n\n this.logger.debug(\"MCPRouteHandler 初始化完成\", {\n maxClients: this.config.maxClients,\n connectionTimeout: this.config.connectionTimeout,\n heartbeatInterval: this.config.heartbeatInterval,\n });\n }\n\n /**\n * 启动清理任务\n */\n private startCleanupTask(): void {\n this.cleanupInterval = setInterval(() => {\n this.cleanupStaleConnections();\n this.updateMetrics();\n }, 60000); // 每分钟执行一次清理\n }\n\n /**\n * 停止清理任务\n */\n private stopCleanupTask(): void {\n if (this.cleanupInterval) {\n clearInterval(this.cleanupInterval);\n this.cleanupInterval = null;\n }\n }\n\n /**\n * 清理过期连接\n */\n private cleanupStaleConnections(): void {\n const now = new Date();\n const staleClients: string[] = [];\n\n for (const [sessionId, client] of this.clients.entries()) {\n const timeSinceLastActivity =\n now.getTime() - client.lastActivity.getTime();\n\n if (\n timeSinceLastActivity > this.config.connectionTimeout ||\n !client.isAlive\n ) {\n staleClients.push(sessionId);\n }\n }\n\n for (const sessionId of staleClients) {\n this.logger.info(`清理过期连接: ${sessionId}`);\n this.handleClientDisconnect(sessionId, \"cleanup\");\n }\n\n if (staleClients.length > 0) {\n this.logger.info(`清理了 ${staleClients.length} 个过期连接`);\n }\n }\n\n /**\n * 更新统计信息\n */\n private updateMetrics(): void {\n if (!this.config.enableMetrics) return;\n\n this.metrics.activeConnections = this.clients.size;\n this.metrics.uptime = Date.now() - this.startTime.getTime();\n\n this.logger.debug(\"连接统计\", {\n activeConnections: this.metrics.activeConnections,\n totalConnections: this.metrics.totalConnections,\n totalMessages: this.metrics.totalMessages,\n errorCount: this.metrics.errorCount,\n });\n }\n\n /**\n * 获取 MCP 服务管理器实例\n * 优先从 Context 获取,如果不存在则从 WebServer 获取\n */\n private getMCPServiceManager(c: Context): MCPServiceManager {\n // 首先尝试从 Context 获取\n const serviceManager = c.get(\"mcpServiceManager\");\n if (serviceManager) {\n return serviceManager;\n }\n\n // 如果 Context 中没有,则从 WebServer 获取\n const webServer = c.get(\"webServer\");\n if (!webServer) {\n throw new Error(\"WebServer 未在 Context 中找到,请检查中间件配置\");\n }\n\n const mcpServiceManager = webServer.getMCPServiceManager();\n this.logger.debug(\n \"MCPServiceManager 从 WebServer 获取(Context 中未找到)\"\n );\n\n return mcpServiceManager;\n }\n\n /**\n * 初始化 MCP 消息处理器\n */\n private async initializeMessageHandler(c: Context): Promise<void> {\n if (this.mcpMessageHandler) {\n return;\n }\n\n try {\n const serviceManager = this.getMCPServiceManager(c);\n this.mcpMessageHandler = new MCPMessageHandler(serviceManager);\n this.logger.debug(\"MCP 消息处理器初始化成功\");\n } catch (error) {\n this.logger.error(\"MCP 消息处理器初始化失败:\", error);\n this.metrics.errorCount++;\n throw error;\n }\n }\n\n /**\n * 处理 POST 请求(JSON-RPC 消息)\n * 符合 MCP Streamable HTTP 规范\n * 支持直接 JSON-RPC 调用和 SSE 消息处理\n */\n async handlePost(c: Context): Promise<Response> {\n const startTime = Date.now();\n let messageId: string | number | null = null;\n\n try {\n this.logger.debug(\"处理 MCP POST 请求\");\n\n // 检查是否是 SSE 消息(通过 sessionId 查询参数)\n const sessionId = c.req.query(\"sessionId\");\n if (sessionId) {\n return await this.handleSSEMessage(c, sessionId);\n }\n\n // 验证请求大小\n const contentLength = c.req.header(\"content-length\");\n if (\n contentLength &&\n Number.parseInt(contentLength) > this.config.maxMessageSize\n ) {\n this.metrics.errorCount++;\n return this.createErrorResponse(\n -32600,\n `Request too large: Maximum size is ${this.config.maxMessageSize} bytes`\n );\n }\n\n // 验证 Content-Type\n const contentType = c.req.header(\"content-type\");\n if (!contentType?.includes(\"application/json\")) {\n this.metrics.errorCount++;\n return this.createErrorResponse(\n -32600,\n \"Invalid Request: Content-Type must be application/json\"\n );\n }\n\n // 验证 MCP 协议版本头(可选)\n // 支持多种大小写格式的协议版本头\n const protocolVersion =\n c.req.header(\"mcp-protocol-version\") ||\n c.req.header(\"MCP-Protocol-Version\") ||\n c.req.header(\"Mcp-Protocol-Version\");\n const supportedVersions = [\"2024-11-05\", \"2025-06-18\"];\n if (protocolVersion && !supportedVersions.includes(protocolVersion)) {\n this.logger.warn(\n `不支持的 MCP 协议版本: ${protocolVersion},支持的版本: ${supportedVersions.join(\n \", \"\n )}`\n );\n }\n\n // 解析请求体\n let message: MCPMessage;\n try {\n const rawBody = await c.req.text();\n if (rawBody.length > this.config.maxMessageSize) {\n this.metrics.errorCount++;\n return this.createErrorResponse(\n -32600,\n `Message too large: Maximum size is ${this.config.maxMessageSize} bytes`,\n null\n );\n }\n message = JSON.parse(rawBody);\n messageId = message.id || null;\n } catch (error) {\n this.metrics.errorCount++;\n return this.createErrorResponse(-32700, \"Parse error: Invalid JSON\");\n }\n\n // 验证 JSON-RPC 格式\n if (!this.validateMessage(message)) {\n this.metrics.errorCount++;\n return this.createErrorResponse(\n -32600,\n \"Invalid Request: Message does not conform to JSON-RPC 2.0\",\n messageId\n );\n }\n\n // 初始化消息处理器\n await this.initializeMessageHandler(c);\n\n // 处理消息\n if (!this.mcpMessageHandler) {\n throw new Error(\"消息处理器初始化失败\");\n }\n const response = await this.mcpMessageHandler.handleMessage(message);\n\n // 更新统计信息\n this.metrics.totalMessages++;\n const responseTime = Date.now() - startTime;\n this.metrics.averageResponseTime =\n (this.metrics.averageResponseTime * (this.metrics.totalMessages - 1) +\n responseTime) /\n this.metrics.totalMessages;\n\n this.logger.debug(\"MCP POST 请求处理成功\", {\n method: message.method,\n messageId: messageId,\n responseTime: responseTime,\n isNotification: response === null,\n });\n\n // 对于通知消息,返回 204 No Content\n if (response === null) {\n return new Response(null, {\n status: 204,\n headers: {\n \"MCP-Protocol-Version\": \"2024-11-05\",\n \"X-Response-Time\": responseTime.toString(),\n },\n });\n }\n\n // 返回 JSON-RPC 响应\n return c.json(response, 200, {\n \"Content-Type\": \"application/json\",\n \"MCP-Protocol-Version\": \"2024-11-05\",\n \"X-Response-Time\": responseTime.toString(),\n });\n } catch (error) {\n this.metrics.errorCount++;\n const responseTime = Date.now() - startTime;\n\n this.logger.error(\"处理 MCP POST 请求时出错:\", {\n error: error instanceof Error ? error.message : String(error),\n messageId: messageId,\n responseTime: responseTime,\n stack: error instanceof Error ? error.stack : undefined,\n });\n\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n return this.createErrorResponse(\n -32603,\n `Internal error: ${errorMessage}`,\n messageId\n );\n }\n }\n\n /**\n * 处理 SSE 消息\n * 用于处理通过 SSE 连接发送的 JSON-RPC 消息\n */\n private async handleSSEMessage(\n c: Context,\n sessionId: string\n ): Promise<Response> {\n const startTime = Date.now();\n let messageId: string | number | null = null;\n\n try {\n this.logger.debug(`处理 SSE 消息 (会话: ${sessionId})`);\n\n // 验证会话是否存在\n const client = this.clients.get(sessionId);\n if (!client) {\n this.metrics.errorCount++;\n return this.createErrorResponse(\n -32600,\n \"Invalid Request: Invalid or missing sessionId\",\n null\n );\n }\n\n // 更新客户端活动时间\n client.lastActivity = new Date();\n\n // 验证请求大小\n const contentLength = c.req.header(\"content-length\");\n if (\n contentLength &&\n Number.parseInt(contentLength) > this.config.maxMessageSize\n ) {\n this.metrics.errorCount++;\n return this.createErrorResponse(\n -32600,\n `Message too large: Maximum size is ${this.config.maxMessageSize} bytes`\n );\n }\n\n // 解析消息\n let message: MCPMessage;\n try {\n const rawBody = await c.req.text();\n if (rawBody.length > this.config.maxMessageSize) {\n this.metrics.errorCount++;\n return this.createErrorResponse(\n -32600,\n `Message too large: Maximum size is ${this.config.maxMessageSize} bytes`,\n null\n );\n }\n message = JSON.parse(rawBody);\n messageId = message.id || null;\n } catch (error) {\n this.metrics.errorCount++;\n return this.createErrorResponse(-32700, \"Parse error: Invalid JSON\");\n }\n\n // 验证消息格式\n if (!this.validateMessage(message)) {\n this.metrics.errorCount++;\n return this.createErrorResponse(\n -32600,\n \"Invalid Request: Message does not conform to JSON-RPC 2.0\",\n messageId\n );\n }\n\n // 初始化消息处理器\n await this.initializeMessageHandler(c);\n\n // 处理消息\n if (!this.mcpMessageHandler) {\n throw new Error(\"消息处理器初始化失败\");\n }\n const response = await this.mcpMessageHandler.handleMessage(message);\n\n // 更新客户端统计\n client.messageCount++;\n this.metrics.totalMessages++;\n\n // 通过 SSE 发送响应(仅对非通知消息)\n if (response !== null && client.writer && client.isAlive) {\n try {\n await this.sendSSEEvent(\n client.writer,\n \"message\",\n JSON.stringify(response)\n );\n } catch (writeError) {\n this.logger.warn(\n `SSE 写入失败,标记客户端为不活跃: ${sessionId}`,\n writeError\n );\n client.isAlive = false;\n }\n }\n\n const responseTime = Date.now() - startTime;\n this.logger.debug(`SSE 消息处理完成 (会话: ${sessionId})`, {\n method: message.method,\n messageId: messageId,\n responseTime: responseTime,\n messageCount: client.messageCount,\n isNotification: response === null,\n });\n\n // 返回 202 Accepted 确认\n return new Response(null, {\n status: 202,\n headers: {\n \"MCP-Protocol-Version\": \"2024-11-05\",\n \"X-Response-Time\": responseTime.toString(),\n },\n });\n } catch (error) {\n this.metrics.errorCount++;\n const responseTime = Date.now() - startTime;\n\n this.logger.error(`处理 SSE 消息时出错 (会话: ${sessionId}):`, {\n error: error instanceof Error ? error.message : String(error),\n messageId: messageId,\n responseTime: responseTime,\n stack: error instanceof Error ? error.stack : undefined,\n });\n\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n return this.createErrorResponse(\n -32603,\n `Internal error: ${errorMessage}`,\n messageId\n );\n }\n }\n\n /**\n * 处理 GET 请求(SSE 连接)\n * 符合 MCP Streamable HTTP 规范\n */\n async handleGet(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理 MCP GET 请求(SSE 连接)\");\n\n // 检查客户端数量限制\n if (this.clients.size >= this.config.maxClients) {\n this.metrics.errorCount++;\n return c.json(\n {\n jsonrpc: \"2.0\",\n error: {\n code: -32000,\n message: \"Server busy: Maximum client connections reached\",\n data: { maxClients: this.config.maxClients },\n },\n id: null,\n },\n 503\n );\n }\n\n // 生成客户端标识\n const clientId = Date.now().toString();\n const sessionId = randomUUID();\n const now = new Date();\n\n // 获取客户端信息\n const userAgent = c.req.header(\"user-agent\");\n const remoteAddress =\n c.req.header(\"x-forwarded-for\") ||\n c.req.header(\"x-real-ip\") ||\n \"unknown\";\n\n this.logger.info(`SSE 客户端连接: ${clientId} (会话: ${sessionId})`, {\n userAgent: userAgent,\n remoteAddress: remoteAddress,\n });\n\n // 创建 SSE 流\n const { readable, writable } = new TransformStream();\n const writer = writable.getWriter();\n\n // 创建 AbortController 用于连接管理\n const abortController = new AbortController();\n\n // 注册客户端\n const client: SSEClient = {\n id: clientId,\n sessionId,\n response: new Response(readable),\n connectedAt: now,\n lastActivity: now,\n writer,\n abortController,\n isAlive: true,\n messageCount: 0,\n userAgent,\n remoteAddress,\n };\n\n this.clients.set(sessionId, client);\n this.metrics.totalConnections++;\n this.metrics.activeConnections = this.clients.size;\n\n // 发送 SSE 头部和初始事件\n try {\n await this.sendSSEEvent(\n writer,\n \"connected\",\n JSON.stringify({\n sessionId: sessionId,\n endpoint: `/mcp?sessionId=${sessionId}`,\n timestamp: now.toISOString(),\n protocolVersion: \"2024-11-05\",\n })\n );\n } catch (writeError) {\n this.logger.error(`初始 SSE 事件发送失败: ${sessionId}`, writeError);\n client.isAlive = false;\n }\n\n // 启动心跳机制\n this.startHeartbeat(client);\n\n // 设置响应头\n const response = new Response(readable, {\n status: 200,\n headers: {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache, no-transform\",\n Connection: \"keep-alive\",\n \"X-Accel-Buffering\": \"no\",\n \"MCP-Protocol-Version\": \"2024-11-05\",\n \"Access-Control-Allow-Origin\": \"*\",\n \"Access-Control-Allow-Headers\": \"Content-Type, MCP-Protocol-Version\",\n },\n });\n\n // 处理连接关闭\n const handleDisconnect = () => {\n this.handleClientDisconnect(sessionId, clientId);\n };\n\n c.req.raw.signal?.addEventListener(\"abort\", handleDisconnect);\n abortController.signal.addEventListener(\"abort\", handleDisconnect);\n\n return response;\n } catch (error) {\n this.metrics.errorCount++;\n this.logger.error(\"处理 MCP GET 请求时出错:\", {\n error: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n });\n\n return c.json(\n {\n jsonrpc: \"2.0\",\n error: {\n code: -32603,\n message: \"Internal error\",\n },\n id: null,\n },\n 500\n );\n }\n }\n\n /**\n * 启动心跳机制\n */\n private startHeartbeat(client: SSEClient): void {\n if (client.heartbeatInterval) {\n clearInterval(client.heartbeatInterval);\n }\n\n client.heartbeatInterval = setInterval(async () => {\n if (!client.isAlive || !client.writer) {\n this.stopHeartbeat(client);\n return;\n }\n\n try {\n await this.sendSSEEvent(\n client.writer,\n \"heartbeat\",\n JSON.stringify({\n timestamp: new Date().toISOString(),\n sessionId: client.sessionId,\n })\n );\n\n this.logger.debug(`心跳发送成功: ${client.sessionId}`);\n } catch (error) {\n this.logger.warn(\n `心跳发送失败,标记客户端为不活跃: ${client.sessionId}`,\n error\n );\n client.isAlive = false;\n this.stopHeartbeat(client);\n }\n }, this.config.heartbeatInterval);\n }\n\n /**\n * 停止心跳机制\n */\n private stopHeartbeat(client: SSEClient): void {\n if (client.heartbeatInterval) {\n clearInterval(client.heartbeatInterval);\n client.heartbeatInterval = undefined;\n }\n }\n\n /**\n * 发送 SSE 事件\n */\n private async sendSSEEvent(\n writer: WritableStreamDefaultWriter<Uint8Array>,\n event: string,\n data: string\n ): Promise<void> {\n try {\n const eventData = `event: ${event}\\ndata: ${data}\\n\\n`;\n await writer.write(new TextEncoder().encode(eventData));\n } catch (error) {\n this.logger.error(\"发送 SSE 事件失败:\", error);\n throw error; // 重新抛出错误,让调用者处理\n }\n }\n\n /**\n * 处理客户端断开连接\n */\n private handleClientDisconnect(sessionId: string, reason: string): void {\n const client = this.clients.get(sessionId);\n if (!client) {\n return;\n }\n\n const connectionDuration = Date.now() - client.connectedAt.getTime();\n\n this.logger.debug(`SSE 客户端断开连接: ${client.id} (会话: ${sessionId})`, {\n reason: reason,\n duration: connectionDuration,\n messageCount: client.messageCount,\n userAgent: client.userAgent,\n remoteAddress: client.remoteAddress,\n });\n\n // 停止心跳\n this.stopHeartbeat(client);\n\n // 中止连接\n if (client.abortController) {\n client.abortController.abort();\n }\n\n // 关闭写入器\n try {\n if (client.writer) {\n client.writer.close();\n }\n } catch (error) {\n this.logger.debug(\"关闭 SSE writer 时出错:\", error);\n }\n\n // 从客户端列表中移除\n this.clients.delete(sessionId);\n this.metrics.activeConnections = this.clients.size;\n }\n\n /**\n * 验证 JSON-RPC 消息格式\n */\n private validateMessage(message: unknown): message is MCPMessage {\n if (!message || typeof message !== \"object\") {\n this.logger.debug(\"消息验证失败: 不是对象\");\n return false;\n }\n\n // 类型守卫:确保 message 是对象类型\n const msg = message as Record<string, unknown>;\n\n if (msg.jsonrpc !== \"2.0\") {\n this.logger.debug(\"消息验证失败: jsonrpc 版本不正确\", {\n jsonrpc: msg.jsonrpc,\n });\n return false;\n }\n\n if (!msg.method || typeof msg.method !== \"string\") {\n this.logger.debug(\"消息验证失败: method 字段无效\", {\n method: msg.method,\n });\n return false;\n }\n\n // 验证 id 字段(如果存在)\n if (\n msg.id !== undefined &&\n typeof msg.id !== \"string\" &&\n typeof msg.id !== \"number\" &&\n msg.id !== null\n ) {\n this.logger.debug(\"消息验证失败: id 字段类型无效\", { id: msg.id });\n return false;\n }\n\n // 验证 params 字段(如果存在)\n if (msg.params !== undefined && typeof msg.params !== \"object\") {\n this.logger.debug(\"消息验证失败: params 字段类型无效\", {\n params: msg.params,\n });\n return false;\n }\n\n return true;\n }\n\n /**\n * 创建错误响应\n */\n private createErrorResponse(\n code: number,\n message: string,\n id?: string | number | null\n ): Response {\n // 确保ID不为空,如果为空或未提供则生成默认ID\n const responseId = id ?? `error-${Date.now()}`;\n\n const errorResponse: MCPResponse = {\n jsonrpc: \"2.0\",\n error: {\n code,\n message,\n },\n id: responseId,\n };\n\n return new Response(JSON.stringify(errorResponse), {\n status: 400,\n headers: {\n \"Content-Type\": \"application/json\",\n \"MCP-Protocol-Version\": \"2024-11-05\",\n },\n });\n }\n\n /**\n * 获取连接状态\n */\n getStatus() {\n return {\n connectedClients: this.clients.size,\n maxClients: this.config.maxClients,\n isInitialized: this.mcpMessageHandler !== null,\n metrics: this.config.enableMetrics ? this.metrics : undefined,\n config: {\n maxClients: this.config.maxClients,\n connectionTimeout: this.config.connectionTimeout,\n heartbeatInterval: this.config.heartbeatInterval,\n maxMessageSize: this.config.maxMessageSize,\n },\n };\n }\n\n /**\n * 获取详细的连接信息\n */\n getDetailedStatus() {\n const clients = Array.from(this.clients.values()).map((client) => ({\n id: client.id,\n sessionId: client.sessionId,\n connectedAt: client.connectedAt.toISOString(),\n lastActivity: client.lastActivity.toISOString(),\n messageCount: client.messageCount,\n isAlive: client.isAlive,\n userAgent: client.userAgent,\n remoteAddress: client.remoteAddress,\n }));\n\n return {\n ...this.getStatus(),\n clients,\n startTime: this.startTime.toISOString(),\n };\n }\n\n /**\n * 广播消息到所有活跃客户端\n */\n async broadcastMessage(event: string, data: unknown): Promise<void> {\n let message: string;\n try {\n // 验证数据是否可以序列化\n message = JSON.stringify(data);\n } catch (error) {\n this.logger.error(\"广播消息序列化失败:\", {\n error: error instanceof Error ? error.message : String(error),\n data,\n });\n throw new Error(\n `广播消息无法序列化: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n\n const deadClients: string[] = [];\n\n for (const [sessionId, client] of this.clients.entries()) {\n if (!client.isAlive || !client.writer) {\n deadClients.push(sessionId);\n continue;\n }\n\n try {\n await this.sendSSEEvent(client.writer, event, message);\n } catch (error) {\n this.logger.warn(\n `广播消息失败,标记客户端为不活跃: ${sessionId}`,\n error\n );\n client.isAlive = false;\n deadClients.push(sessionId);\n }\n }\n\n // 清理死连接\n for (const sessionId of deadClients) {\n this.handleClientDisconnect(sessionId, \"broadcast-failed\");\n }\n }\n\n /**\n * 销毁处理器,清理所有资源\n */\n destroy(): void {\n this.logger.info(\"正在销毁 MCPRouteHandler\");\n\n // 停止清理任务\n this.stopCleanupTask();\n\n // 断开所有客户端连接\n for (const [sessionId] of this.clients.entries()) {\n this.handleClientDisconnect(sessionId, \"server-shutdown\");\n }\n\n // 清理消息处理器\n this.mcpMessageHandler = null;\n\n this.logger.info(\"MCPRouteHandler 销毁完成\");\n }\n}\n","#!/usr/bin/env node\n\n/**\n * MCP服务错误类型定义\n *\n * 本模块提供了统一的错误处理框架,包括:\n * - 标准化的错误代码和分类\n * - 结构化的错误信息\n * - 可扩展的错误处理器\n * - 错误转换和格式化工具\n *\n * @module MCPErrors\n */\n\n/**\n * MCP错误代码枚举\n *\n * 定义了所有MCP服务相关的错误代码,用于错误分类和处理。\n * 错误代码按功能区域分组:配置、连接、操作、系统等。\n */\nexport enum MCPErrorCode {\n // 配置错误 - 服务配置相关的问题\n /** 服务已存在,尝试添加重复服务时使用 */\n SERVER_ALREADY_EXISTS = \"SERVER_ALREADY_EXISTS\",\n /** 服务未找到,操作不存在的服务时使用 */\n SERVER_NOT_FOUND = \"SERVER_NOT_FOUND\",\n /** 配置格式无效或内容不正确 */\n INVALID_CONFIG = \"INVALID_CONFIG\",\n /** 服务名称不符合规范 */\n INVALID_SERVICE_NAME = \"INVALID_SERVICE_NAME\",\n\n // 连接错误 - 网络连接和服务通信问题\n /** 无法建立到服务的连接 */\n CONNECTION_FAILED = \"CONNECTION_FAILED\",\n /** 连接超时 */\n CONNECTION_TIMEOUT = \"CONNECTION_TIMEOUT\",\n /** 服务暂时不可用 */\n SERVICE_UNAVAILABLE = \"SERVICE_UNAVAILABLE\",\n\n // 操作错误 - 服务操作过程中的问题\n /** 一般操作失败 */\n OPERATION_FAILED = \"OPERATION_FAILED\",\n /** 服务添加操作失败 */\n ADD_FAILED = \"ADD_FAILED\",\n /** 服务移除操作失败 */\n REMOVE_FAILED = \"REMOVE_FAILED\",\n /** 工具同步操作失败 */\n SYNC_FAILED = \"SYNC_FAILED\",\n\n // 系统错误 - 内部系统问题\n /** 内部系统错误 */\n INTERNAL_ERROR = \"INTERNAL_ERROR\",\n /** 配置更新操作失败 */\n CONFIG_UPDATE_FAILED = \"CONFIG_UPDATE_FAILED\",\n\n // 工具同步错误 - 工具管理相关错误\n /** 工具同步失败 */\n TOOL_SYNC_FAILED = \"TOOL_SYNC_FAILED\",\n /** 工具验证失败 */\n TOOL_VALIDATION_FAILED = \"TOOL_VALIDATION_FAILED\",\n /** 工具未找到 */\n TOOL_NOT_FOUND = \"TOOL_NOT_FOUND\",\n}\n\n/**\n * MCP错误严重级别\n */\nexport enum ErrorSeverity {\n LOW = \"low\", // 轻微错误,不影响主要功能\n MEDIUM = \"medium\", // 中等错误,影响部分功能\n HIGH = \"high\", // 严重错误,影响核心功能\n CRITICAL = \"critical\", // 致命错误,系统无法继续运行\n}\n\n/**\n * MCP错误类别\n */\nexport enum ErrorCategory {\n CONFIGURATION = \"configuration\", // 配置相关错误\n CONNECTION = \"connection\", // 连接相关错误\n VALIDATION = \"validation\", // 验证相关错误\n OPERATION = \"operation\", // 操作相关错误\n SYSTEM = \"system\", // 系统相关错误\n EXTERNAL = \"external\", // 外部服务错误\n}\n\n/**\n * 错误详情接口\n */\nexport interface ErrorDetails {\n serverName?: string;\n config?: any;\n tools?: string[];\n timestamp: string;\n severity: ErrorSeverity;\n category: ErrorCategory;\n stack?: string;\n context?: Record<string, any>;\n operation?: string;\n errors?: string[];\n}\n\n/**\n * 标准化的MCP错误类\n */\nexport class MCPError extends Error {\n public readonly code: MCPErrorCode;\n public readonly severity: ErrorSeverity;\n public readonly category: ErrorCategory;\n public readonly details: ErrorDetails;\n public readonly timestamp: string;\n\n constructor(\n code: MCPErrorCode,\n message: string,\n severity: ErrorSeverity = ErrorSeverity.MEDIUM,\n category: ErrorCategory = ErrorCategory.SYSTEM,\n details: Partial<ErrorDetails> = {}\n ) {\n super(message);\n this.name = \"MCPError\";\n this.code = code;\n this.severity = severity;\n this.category = category;\n this.timestamp = new Date().toISOString();\n\n // 合并详情信息\n this.details = {\n ...details,\n timestamp: this.timestamp,\n severity: this.severity,\n category: this.category,\n stack: this.stack,\n };\n\n // 保持堆栈跟踪\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, MCPError);\n }\n }\n\n /**\n * 转换为JSON格式\n */\n toJSON() {\n return {\n name: this.name,\n code: this.code,\n message: this.message,\n severity: this.severity,\n category: this.category,\n details: this.details,\n timestamp: this.timestamp,\n };\n }\n\n /**\n * 创建配置错误\n */\n static configError(\n code: MCPErrorCode,\n message: string,\n details: Partial<ErrorDetails> = {}\n ): MCPError {\n return new MCPError(\n code,\n message,\n ErrorSeverity.MEDIUM,\n ErrorCategory.CONFIGURATION,\n details\n );\n }\n\n /**\n * 创建连接错误\n */\n static connectionError(\n code: MCPErrorCode,\n message: string,\n details: Partial<ErrorDetails> = {}\n ): MCPError {\n return new MCPError(\n code,\n message,\n ErrorSeverity.HIGH,\n ErrorCategory.CONNECTION,\n details\n );\n }\n\n /**\n * 创建操作错误\n */\n static operationError(\n code: MCPErrorCode,\n message: string,\n details: Partial<ErrorDetails> = {}\n ): MCPError {\n return new MCPError(\n code,\n message,\n ErrorSeverity.MEDIUM,\n ErrorCategory.OPERATION,\n details\n );\n }\n\n /**\n * 创建系统错误\n */\n static systemError(\n code: MCPErrorCode,\n message: string,\n details: Partial<ErrorDetails> = {}\n ): MCPError {\n return new MCPError(\n code,\n message,\n ErrorSeverity.HIGH,\n ErrorCategory.SYSTEM,\n details\n );\n }\n\n /**\n * 创建验证错误\n */\n static validationError(\n code: MCPErrorCode,\n message: string,\n details: Partial<ErrorDetails> = {}\n ): MCPError {\n return new MCPError(\n code,\n message,\n ErrorSeverity.LOW,\n ErrorCategory.VALIDATION,\n details\n );\n }\n\n /**\n * 从普通错误创建MCPError\n */\n static fromError(\n error: Error,\n defaultCode: MCPErrorCode = MCPErrorCode.INTERNAL_ERROR,\n category: ErrorCategory = ErrorCategory.SYSTEM\n ): MCPError {\n return new MCPError(\n defaultCode,\n error.message,\n ErrorSeverity.MEDIUM,\n category,\n {\n stack: error.stack,\n context: { originalError: error.name },\n }\n );\n }\n}\n\n/**\n * 错误处理器接口\n */\nexport interface ErrorHandler {\n canHandle(error: Error): boolean;\n handle(error: Error, context?: any): MCPError | null;\n}\n\n/**\n * 默认错误处理器\n */\nexport class DefaultErrorHandler implements ErrorHandler {\n canHandle(error: Error): boolean {\n return !(error instanceof MCPError);\n }\n\n handle(error: Error, context?: any): MCPError {\n return MCPError.fromError(\n error,\n MCPErrorCode.INTERNAL_ERROR,\n ErrorCategory.SYSTEM\n );\n }\n}\n\n/**\n * 配置错误处理器\n */\nexport class ConfigErrorHandler implements ErrorHandler {\n canHandle(error: Error): boolean {\n return (\n error.message.includes(\"配置\") ||\n error.message.includes(\"config\") ||\n error.message.includes(\"JSON\") ||\n error.message.includes(\"解析\")\n );\n }\n\n handle(error: Error, context?: any): MCPError {\n return MCPError.configError(\n MCPErrorCode.INVALID_CONFIG,\n `配置错误: ${error.message}`,\n { context }\n );\n }\n}\n\n/**\n * 连接错误处理器\n */\nexport class ConnectionErrorHandler implements ErrorHandler {\n canHandle(error: Error): boolean {\n return (\n error.message.includes(\"连接\") ||\n error.message.includes(\"connection\") ||\n error.message.includes(\"timeout\") ||\n error.message.includes(\"ECONNREFUSED\") ||\n error.message.includes(\"ENOTFOUND\")\n );\n }\n\n handle(error: Error, context?: any): MCPError {\n return MCPError.connectionError(\n MCPErrorCode.CONNECTION_FAILED,\n `连接失败: ${error.message}`,\n { context }\n );\n }\n}\n\n/**\n * 错误处理器注册表\n */\nexport class ErrorHandlerRegistry {\n private handlers: ErrorHandler[] = [];\n\n constructor() {\n // 注册默认处理器\n this.registerHandler(new ConfigErrorHandler());\n this.registerHandler(new ConnectionErrorHandler());\n this.registerHandler(new DefaultErrorHandler());\n }\n\n /**\n * 注册错误处理器\n */\n registerHandler(handler: ErrorHandler): void {\n this.handlers.unshift(handler); // 添加到前面,优先处理\n }\n\n /**\n * 处理错误\n */\n handleError(error: Error, context?: any): MCPError {\n // 如果已经是MCPError,直接返回\n if (error instanceof MCPError) {\n return error;\n }\n\n // 查找合适的处理器\n for (const handler of this.handlers) {\n if (handler.canHandle(error)) {\n const result = handler.handle(error, context);\n if (result) {\n return result;\n }\n }\n }\n\n // 如果没有处理器能处理,使用默认处理器\n return new DefaultErrorHandler().handle(error, context);\n }\n}\n\n/**\n * 全局错误处理器实例\n */\nexport const globalErrorHandler = new ErrorHandlerRegistry();\n","import type { ConfigManager, MCPServerConfig } from \"@/lib/config/manager.js\";\nimport type { MCPServiceManager } from \"@/lib/mcp\";\nimport type { MCPService } from \"@/lib/mcp\";\nimport type { MCPServiceConfig, MCPTransportType } from \"@/lib/mcp/types\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport type { Logger } from \"@root/Logger.js\";\nimport { logger } from \"@root/Logger.js\";\nimport {\n ErrorCategory,\n MCPError,\n MCPErrorCode,\n} from \"@root/errors/MCPErrors.js\";\nimport { getEventBus } from \"@services/EventBus.js\";\nimport { TypeFieldNormalizer } from \"@utils/TypeFieldNormalizer.js\";\nimport type { Context } from \"hono\";\n\n/**\n * MCPServiceManager 扩展接口,用于访问私有属性\n * 这个接口定义了我们需要访问但实际上是私有的属性\n */\ninterface MCPServiceManagerAccess {\n services: Map<string, MCPService>;\n}\n\n/**\n * MCPServerApiHandler 扩展接口,用于动态状态缓存\n */\ninterface MCPServerApiHandlerWithCache {\n statusCache?: Map<string, MCPServerStatus>;\n}\n\n/**\n * 配置详情接口,包含时间戳\n */\ninterface ConfigDetails {\n serverName?: string;\n config?: MCPServerConfig;\n tools?: string[];\n timestamp?: string;\n [key: string]: unknown; // 允许额外的属性\n}\n\n/**\n * MCP 服务添加请求接口(单服务格式)\n */\nexport interface MCPServerAddRequest {\n name: string;\n config: MCPServerConfig;\n}\n\n/**\n * MCP 服务批量添加请求接口(mcpServers 格式)\n */\nexport interface MCPServerBatchAddRequest {\n mcpServers: Record<string, MCPServerConfig>;\n}\n\n/**\n * MCP 服务添加操作结果\n */\nexport interface MCPServerAddResult {\n name: string;\n success: boolean;\n error?: string;\n config?: MCPServerConfig;\n tools?: string[];\n status?: string;\n}\n\n/**\n * MCP 服务批量添加响应\n */\nexport interface MCPServerBatchAddResponse {\n success: boolean;\n message: string;\n results: MCPServerAddResult[];\n addedCount: number;\n failedCount: number;\n}\n\n/**\n * MCP 服务状态接口\n */\nexport interface MCPServerStatus {\n name: string;\n status: \"connected\" | \"disconnected\" | \"connecting\" | \"error\";\n connected: boolean;\n tools: string[];\n lastUpdated?: string;\n config: MCPServerConfig;\n}\n\n/**\n * MCP 服务列表响应接口\n */\nexport interface MCPServerListResponse {\n servers: MCPServerStatus[];\n total: number;\n}\n\n/**\n * 统一响应格式接口\n */\nexport interface ApiErrorResponse {\n error: {\n code: MCPErrorCode;\n message: string;\n details?: {\n serverName?: string;\n config?: MCPServerConfig;\n tools?: string[];\n timestamp?: string;\n [key: string]: unknown;\n };\n };\n}\n\nexport interface ApiSuccessResponse<T = unknown> {\n success: boolean;\n data?: T;\n message?: string;\n}\n\n/**\n * 配置验证结果接口\n */\nexport interface ValidationResult {\n isValid: boolean;\n errors: string[];\n}\n\n/**\n * MCP 服务 API 处理器\n */\nexport class MCPServerApiHandler {\n protected logger: Logger;\n private mcpServiceManager: MCPServiceManager;\n private configManager: ConfigManager;\n\n constructor(\n mcpServiceManager: MCPServiceManager,\n configManager: ConfigManager\n ) {\n this.logger = logger;\n this.mcpServiceManager = mcpServiceManager;\n this.configManager = configManager;\n }\n\n /**\n * 创建统一的错误响应\n */\n protected createErrorResponse(\n code: MCPErrorCode,\n message: string,\n serverName?: string,\n details?: Record<string, unknown>\n ): ApiErrorResponse {\n return {\n error: {\n code,\n message,\n details: serverName ? { serverName, ...details } : details,\n },\n };\n }\n\n /**\n * 处理错误并返回MCPError\n */\n protected handleError(\n error: unknown,\n operation: string,\n context?: Record<string, unknown>\n ): MCPError {\n if (error instanceof MCPError) {\n this.logger.error(\"MCPError\", { error, operation, context });\n return error;\n }\n\n if (error instanceof Error) {\n let mcpError: MCPError;\n\n // 根据错误消息和操作类型确定错误类型\n if (\n error.message.includes(\"服务不存在\") ||\n error.message.includes(\"not found\")\n ) {\n mcpError = MCPError.configError(\n MCPErrorCode.SERVER_NOT_FOUND,\n error.message,\n { operation, context }\n );\n } else if (\n error.message.includes(\"已存在\") ||\n error.message.includes(\"already exists\")\n ) {\n mcpError = MCPError.configError(\n MCPErrorCode.SERVER_ALREADY_EXISTS,\n error.message,\n { operation, context }\n );\n } else if (\n error.message.includes(\"配置\") ||\n error.message.includes(\"config\")\n ) {\n mcpError = MCPError.configError(\n MCPErrorCode.INVALID_CONFIG,\n error.message,\n { operation, context }\n );\n } else if (\n error.message.includes(\"连接\") ||\n error.message.includes(\"connection\")\n ) {\n mcpError = MCPError.connectionError(\n MCPErrorCode.CONNECTION_FAILED,\n error.message,\n { operation, context }\n );\n } else {\n mcpError = MCPError.systemError(\n MCPErrorCode.INTERNAL_ERROR,\n error.message,\n { operation, context, stack: error.stack }\n );\n }\n\n this.logger.error(\"MCPError\", { error: mcpError, operation, context });\n return mcpError;\n }\n\n // 处理未知错误类型\n const mcpError = MCPError.systemError(\n MCPErrorCode.INTERNAL_ERROR,\n String(error),\n { operation, context }\n );\n this.logger.error(\"MCPError\", { error: mcpError, operation, context });\n return mcpError;\n }\n\n /**\n * 创建统一的成功响应\n */\n protected createSuccessResponse<T>(\n data?: T,\n message?: string\n ): ApiSuccessResponse<T> {\n return {\n success: true,\n data,\n message,\n };\n }\n\n /**\n * 创建 MCPServiceConfig 对象\n */\n private createMCPServiceConfig(\n name: string,\n config: MCPServerConfig\n ): MCPServiceConfig {\n // 根据配置类型创建 MCPServiceConfig\n if (\"command\" in config) {\n // LocalMCPServerConfig\n return {\n name,\n type: \"stdio\" as MCPTransportType,\n command: config.command,\n args: config.args || [],\n env: config.env || {},\n };\n }\n if (\"type\" in config && config.type === \"sse\") {\n // SSEMCPServerConfig\n return {\n name,\n type: \"sse\" as MCPTransportType,\n url: config.url,\n };\n }\n if (\"url\" in config) {\n // StreamableHTTPMCPServerConfig\n return {\n name,\n type: \"streamable-http\" as MCPTransportType,\n url: config.url,\n };\n }\n throw new Error(`不支持的配置格式: ${JSON.stringify(config)}`);\n }\n\n /**\n * 添加 MCP 服务\n * POST /api/mcp-servers\n * 支持两种格式:\n * 1. 单服务格式:{ name: string, config: MCPServerConfig }\n * 2. 批量格式:{ mcpServers: Record<string, MCPServerConfig> }\n */\n async addMCPServer(c: Context): Promise<Response> {\n const startTime = Date.now();\n const requestData = await c.req.json();\n\n this.logger.info(\"addMCPServer\", {\n requestData,\n method: \"POST\",\n path: \"/api/mcp-servers\",\n });\n\n try {\n // 检测请求格式\n if (\"mcpServers\" in requestData) {\n // 批量格式\n const batchRequest = requestData as MCPServerBatchAddRequest;\n const result = await this.addMCPServersBatch(batchRequest);\n\n const duration = Date.now() - startTime;\n this.logger.info(\"addMCPServer\", {\n batch: true,\n addedCount: result.addedCount,\n failedCount: result.failedCount,\n duration,\n });\n\n return c.json(this.createSuccessResponse(result, result.message), 201);\n }\n // 单服务格式\n const singleRequest = requestData as MCPServerAddRequest;\n const { name, config } = singleRequest;\n\n const result = await this.addMCPServerSingle(name, config);\n\n const duration = Date.now() - startTime;\n this.logger.info(\"addMCPServer\", {\n serverName: name,\n toolsCount: result.tools?.length || 0,\n duration,\n status: result.status,\n });\n\n const successResponse = this.createSuccessResponse(\n result,\n \"MCP 服务添加成功\"\n );\n return c.json(successResponse, 201);\n } catch (error) {\n const mcpError = this.handleError(error, \"addMCPServer\", {\n requestData,\n });\n\n const errorResponse = this.createErrorResponse(\n mcpError.code,\n mcpError.message,\n undefined,\n { error: mcpError.details }\n );\n\n // 根据错误类型确定HTTP状态码\n let statusCode = 500;\n if (mcpError.category === ErrorCategory.VALIDATION) {\n statusCode = 400;\n } else if (mcpError.category === ErrorCategory.CONFIGURATION) {\n if (mcpError.code === MCPErrorCode.SERVER_ALREADY_EXISTS) {\n statusCode = 409;\n } else {\n statusCode = 400;\n }\n } else if (mcpError.category === ErrorCategory.CONNECTION) {\n statusCode = 500; // 测试期望连接失败返回500而不是503\n }\n\n return c.json(errorResponse, statusCode as 400 | 404 | 409 | 500);\n }\n }\n\n /**\n * 处理单个 MCP 服务添加\n */\n private async addMCPServerSingle(\n name: string,\n config: MCPServerConfig\n ): Promise<MCPServerStatus> {\n this.logger.info(\"addMCPServerSingle\", {\n serverName: name,\n });\n\n // 标准化type字段格式(在try块外声明,确保catch块中可以访问)\n const normalizedConfig = TypeFieldNormalizer.normalizeTypeField(\n config\n ) as MCPServerConfig;\n\n try {\n // 1. 验证服务名称\n const nameValidation = MCPServerConfigValidator.validateServiceName(name);\n if (!nameValidation.isValid) {\n const validationError = MCPError.validationError(\n MCPErrorCode.INVALID_SERVICE_NAME,\n nameValidation.errors.join(\", \"),\n { serverName: name, errors: nameValidation.errors }\n );\n this.logger.error(\"addMCPServerSingle\", {\n validationError,\n serverName: name,\n phase: \"name_validation\",\n });\n throw validationError;\n }\n\n // 2. 检查服务是否已存在\n if (\n MCPServerConfigValidator.checkServiceExists(name, this.configManager)\n ) {\n const existsError = MCPError.configError(\n MCPErrorCode.SERVER_ALREADY_EXISTS,\n \"MCP 服务已存在\",\n { serverName: name }\n );\n this.logger.error(\"addMCPServerSingle\", {\n existsError,\n serverName: name,\n phase: \"existence_check\",\n });\n throw existsError;\n }\n\n // 3. 验证服务配置\n const configValidation =\n MCPServerConfigValidator.validateConfig(normalizedConfig);\n if (!configValidation.isValid) {\n const configError = MCPError.configError(\n MCPErrorCode.INVALID_CONFIG,\n configValidation.errors.join(\", \"),\n {\n serverName: name,\n config: normalizedConfig,\n errors: configValidation.errors,\n }\n );\n this.logger.error(\"addMCPServerSingle\", {\n configError,\n serverName: name,\n phase: \"config_validation\",\n });\n throw configError;\n }\n\n // 5. 添加服务到配置管理器\n this.configManager.updateMcpServer(name, normalizedConfig);\n this.logger.debug(\"服务配置已添加到配置管理器\", { serverName: name });\n\n // 6. 添加服务到 MCPServiceManager 并启动服务\n const mcpServiceConfig = this.createMCPServiceConfig(\n name,\n normalizedConfig\n );\n this.mcpServiceManager.addServiceConfig(mcpServiceConfig);\n await this.mcpServiceManager.startService(name);\n this.logger.debug(\"服务已启动\", { serverName: name });\n\n // 6. 获取服务状态和工具列表\n const serviceStatus = this.getServiceStatus(name);\n const tools = this.getServiceTools(name);\n\n // 7. 发送事件通知\n getEventBus().emitEvent(\"mcp:server:added\", {\n serverName: name,\n config: normalizedConfig,\n tools: tools.map((tool) => tool.name),\n timestamp: new Date(),\n });\n\n return {\n ...serviceStatus,\n tools: tools.map((tool) => tool.name),\n };\n } catch (error) {\n const mcpError = this.handleError(error, \"addMCPServerSingle\", {\n serverName: name,\n config: normalizedConfig,\n });\n this.logger.error(\"addMCPServerSingle\", {\n mcpError,\n serverName: name,\n });\n throw mcpError;\n }\n }\n\n /**\n * 获取服务状态信息\n */\n private getServiceStatus(serverName: string): MCPServerStatus {\n const config = this.configManager.getConfig();\n const serverConfig = config.mcpServers[serverName];\n\n if (!serverConfig) {\n return {\n name: serverName,\n status: \"disconnected\",\n connected: false,\n tools: [],\n config: {} as MCPServerConfig,\n };\n }\n\n // 尝试从 MCPServiceManager 获取实际状态\n try {\n const managerAccess = this\n .mcpServiceManager as unknown as MCPServiceManagerAccess;\n const service = managerAccess.services.get(serverName);\n\n if (service?.isConnected?.()) {\n const currentTools = service.getTools().map((tool: Tool) => tool.name);\n const status = {\n name: serverName,\n status: \"connected\" as const,\n connected: true,\n tools: currentTools,\n lastUpdated: new Date().toISOString(),\n config: serverConfig,\n };\n\n // 检查状态变化并发出事件\n this.checkAndEmitStatusChange(serverName, status);\n return status;\n }\n } catch (error) {\n this.logger.debug(`获取服务 ${serverName} 状态时出错:`, error);\n }\n\n const status = {\n name: serverName,\n status: \"disconnected\" as const,\n connected: false,\n tools: [],\n config: serverConfig,\n };\n\n // 检查状态变化并发出事件\n this.checkAndEmitStatusChange(serverName, status);\n return status;\n }\n\n /**\n * 检查状态变化并发出事件\n */\n private checkAndEmitStatusChange(\n serverName: string,\n newStatus: MCPServerStatus\n ): void {\n // 获取之前的状态(简单的内存缓存)\n const previousStatus = this.getPreviousStatus(serverName);\n\n if (previousStatus && previousStatus.status !== newStatus.status) {\n this.logger.info(\n `服务 ${serverName} 状态变化: ${previousStatus.status} -> ${newStatus.status}`\n );\n\n // 发射状态变化事件\n getEventBus().emitEvent(\"mcp:server:status_changed\", {\n serverName,\n oldStatus: previousStatus.status,\n newStatus: newStatus.status,\n timestamp: new Date(),\n reason:\n newStatus.status === \"connected\"\n ? \"connection_established\"\n : \"connection_lost\",\n });\n\n // 如果工具列表发生变化,发出工具更新事件\n if (previousStatus.tools !== newStatus.tools) {\n const addedTools = newStatus.tools.filter(\n (tool) => !previousStatus.tools.includes(tool)\n );\n const removedTools = previousStatus.tools.filter(\n (tool) => !newStatus.tools.includes(tool)\n );\n\n if (addedTools.length > 0 || removedTools.length > 0) {\n getEventBus().emitEvent(\"mcp:server:tools:updated\", {\n serverName,\n tools: newStatus.tools,\n addedTools,\n removedTools,\n timestamp: new Date(),\n });\n }\n }\n }\n\n // 更新状态缓存\n this.updateStatusCache(serverName, newStatus);\n }\n\n /**\n * 获取之前的状态(简化实现)\n */\n private getPreviousStatus(serverName: string): MCPServerStatus | null {\n // 这里使用一个简单的Map来缓存状态\n // 在实际生产环境中,可能需要更持久化的缓存方案\n const handlerWithCache = this as MCPServerApiHandlerWithCache;\n if (!handlerWithCache.statusCache) {\n handlerWithCache.statusCache = new Map();\n }\n return handlerWithCache.statusCache.get(serverName) || null;\n }\n\n /**\n * 更新状态缓存\n */\n private updateStatusCache(serverName: string, status: MCPServerStatus): void {\n const handlerWithCache = this as MCPServerApiHandlerWithCache;\n if (!handlerWithCache.statusCache) {\n handlerWithCache.statusCache = new Map();\n }\n handlerWithCache.statusCache.set(serverName, status);\n }\n\n /**\n * 获取服务工具列表\n */\n private getServiceTools(serverName: string): Tool[] {\n try {\n const managerAccess = this\n .mcpServiceManager as unknown as MCPServiceManagerAccess;\n const service = managerAccess.services.get(serverName);\n\n if (service?.getTools) {\n return service.getTools();\n }\n } catch (error) {\n this.logger.debug(`获取服务 ${serverName} 工具列表时出错:`, error);\n }\n\n return [];\n }\n\n /**\n * 移除 MCP 服务\n * DELETE /api/mcp-servers/:serverName\n */\n async removeMCPServer(c: Context): Promise<Response> {\n try {\n // 1. 从路径参数获取服务名称\n const serverName = c.req.param(\"serverName\");\n\n // 2. 验证服务名称\n const nameValidation =\n MCPServerConfigValidator.validateServiceName(serverName);\n if (!nameValidation.isValid) {\n const errorResponse = this.createErrorResponse(\n MCPErrorCode.INVALID_SERVICE_NAME,\n nameValidation.errors.join(\", \"),\n serverName\n );\n return c.json(errorResponse, 400);\n }\n\n // 3. 检查服务是否存在\n if (\n !MCPServerConfigValidator.checkServiceExists(\n serverName,\n this.configManager\n )\n ) {\n const errorResponse = this.createErrorResponse(\n MCPErrorCode.SERVER_NOT_FOUND,\n \"MCP 服务不存在\",\n serverName\n );\n return c.json(errorResponse, 404);\n }\n\n // 4. 获取服务当前的工具列表(用于事件通知)\n const currentTools = this.getServiceTools(serverName).map(\n (tool) => tool.name\n );\n\n // 5. 停止服务并清理资源\n try {\n await this.mcpServiceManager.stopService(serverName);\n } catch (error) {\n this.logger.warn(`停止服务 ${serverName} 失败:`, error);\n // 即使停止失败,也继续执行配置移除\n }\n\n // 6. 移除服务配置\n this.mcpServiceManager.removeServiceConfig(serverName);\n this.configManager.removeMcpServer(serverName);\n\n // 7. 发送事件通知\n getEventBus().emitEvent(\"mcp:server:removed\", {\n serverName,\n affectedTools: currentTools,\n timestamp: new Date(),\n });\n\n // 8. 返回成功响应\n const successResponse = this.createSuccessResponse(\n {\n name: serverName,\n operation: \"removed\",\n affectedTools: currentTools,\n },\n \"MCP 服务移除成功\"\n );\n return c.json(successResponse, 200);\n } catch (error) {\n this.logger.error(\"移除 MCP 服务失败:\", error);\n\n // 处理不同类型的错误\n if (error instanceof Error) {\n if (error.message.includes(\"服务不存在\")) {\n const errorResponse = this.createErrorResponse(\n MCPErrorCode.SERVER_NOT_FOUND,\n error.message\n );\n return c.json(errorResponse, 404);\n }\n\n if (error.message.includes(\"配置更新\")) {\n const errorResponse = this.createErrorResponse(\n MCPErrorCode.CONFIG_UPDATE_FAILED,\n error.message\n );\n return c.json(errorResponse, 500);\n }\n }\n\n // 其他未知错误\n const errorResponse = this.createErrorResponse(\n MCPErrorCode.REMOVE_FAILED,\n \"移除 MCP 服务时发生错误\",\n undefined,\n { error: error instanceof Error ? error.message : String(error) }\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 获取 MCP 服务状态\n * GET /api/mcp-servers/:serverName/status\n */\n async getMCPServerStatus(c: Context): Promise<Response> {\n try {\n // 1. 从路径参数获取服务名称\n const serverName = c.req.param(\"serverName\");\n\n // 2. 验证服务名称\n const nameValidation =\n MCPServerConfigValidator.validateServiceName(serverName);\n if (!nameValidation.isValid) {\n const errorResponse = this.createErrorResponse(\n MCPErrorCode.INVALID_SERVICE_NAME,\n nameValidation.errors.join(\", \"),\n serverName\n );\n return c.json(errorResponse, 400);\n }\n\n // 3. 检查服务是否存在\n if (\n !MCPServerConfigValidator.checkServiceExists(\n serverName,\n this.configManager\n )\n ) {\n const errorResponse = this.createErrorResponse(\n MCPErrorCode.SERVER_NOT_FOUND,\n \"MCP 服务不存在\",\n serverName\n );\n return c.json(errorResponse, 404);\n }\n\n // 4. 获取服务状态\n const serviceStatus = this.getServiceStatus(serverName);\n\n // 5. 返回成功响应\n const successResponse = this.createSuccessResponse(\n serviceStatus,\n \"MCP 服务状态获取成功\"\n );\n return c.json(successResponse, 200);\n } catch (error) {\n this.logger.error(\"获取 MCP 服务状态失败:\", error);\n\n // 处理不同类型的错误\n if (error instanceof Error) {\n if (error.message.includes(\"服务不存在\")) {\n const errorResponse = this.createErrorResponse(\n MCPErrorCode.SERVER_NOT_FOUND,\n error.message\n );\n return c.json(errorResponse, 404);\n }\n }\n\n // 其他未知错误\n const errorResponse = this.createErrorResponse(\n MCPErrorCode.INTERNAL_ERROR,\n \"获取 MCP 服务状态时发生内部错误\",\n undefined,\n { error: error instanceof Error ? error.message : String(error) }\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 列出所有 MCP 服务\n * GET /api/mcp-servers\n */\n async listMCPServers(c: Context): Promise<Response> {\n try {\n // 1. 获取所有配置的 MCP 服务\n const config = this.configManager.getConfig();\n const mcpServers = config.mcpServers || {};\n\n // 2. 构建服务列表\n const servers: MCPServerStatus[] = [];\n\n for (const [serverName, serverConfig] of Object.entries(mcpServers)) {\n const serviceStatus = this.getServiceStatus(serverName);\n servers.push(serviceStatus);\n }\n\n // 3. 构建响应数据\n const listResponse: MCPServerListResponse = {\n servers,\n total: servers.length,\n };\n\n // 4. 返回成功响应\n const successResponse = this.createSuccessResponse(\n listResponse,\n \"MCP 服务列表获取成功\"\n );\n return c.json(successResponse, 200);\n } catch (error) {\n this.logger.error(\"列出 MCP 服务失败:\", error);\n\n // 其他未知错误\n const errorResponse = this.createErrorResponse(\n MCPErrorCode.INTERNAL_ERROR,\n \"列出 MCP 服务时发生内部错误\",\n undefined,\n { error: error instanceof Error ? error.message : String(error) }\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 处理批量 MCP 服务添加\n */\n private async addMCPServersBatch(\n batchRequest: MCPServerBatchAddRequest\n ): Promise<MCPServerBatchAddResponse> {\n const { mcpServers } = batchRequest;\n const serverNames = Object.keys(mcpServers);\n\n this.logger.info(\"addMCPServersBatch\", {\n serverCount: serverNames.length,\n serverNames,\n });\n\n if (serverNames.length === 0) {\n throw MCPError.validationError(\n MCPErrorCode.INVALID_CONFIG,\n \"批量添加请求中的服务列表为空\"\n );\n }\n\n const results: MCPServerAddResult[] = [];\n const successfullyAddedServers: string[] = [];\n\n // 第一阶段:验证所有服务配置\n const validationResult = this.validateBatchServers(mcpServers);\n if (!validationResult.isValid) {\n throw MCPError.validationError(\n MCPErrorCode.INVALID_CONFIG,\n validationResult.errors.join(\", \")\n );\n }\n\n try {\n // 第二阶段:逐个添加服务,记录成功和失败\n for (const [serverName, serverConfig] of Object.entries(mcpServers)) {\n // 标准化type字段格式(在try块外声明,确保catch块中可以访问)\n const normalizedServerConfig = TypeFieldNormalizer.normalizeTypeField(\n serverConfig\n ) as MCPServerConfig;\n\n try {\n const result = await this.addMCPServerSingle(\n serverName,\n normalizedServerConfig\n );\n\n results.push({\n name: serverName,\n success: true,\n config: normalizedServerConfig,\n tools: result.tools,\n status: result.status,\n });\n\n successfullyAddedServers.push(serverName);\n\n this.logger.debug(\"批量添加:服务添加成功\", {\n serverName,\n toolsCount: result.tools?.length || 0,\n });\n } catch (error) {\n const mcpError = this.handleError(error, \"addMCPServersBatch\", {\n serverName,\n serverConfig: normalizedServerConfig,\n });\n\n results.push({\n name: serverName,\n success: false,\n error: mcpError.message,\n config: normalizedServerConfig,\n });\n\n this.logger.warn(\"批量添加:服务添加失败\", {\n serverName,\n error: mcpError.message,\n });\n }\n }\n\n // 第三阶段:统计结果\n const addedCount = successfullyAddedServers.length;\n const failedCount = serverNames.length - addedCount;\n\n // 第四阶段:如果完全失败,抛出异常;部分成功则返回结果\n if (addedCount === 0) {\n throw MCPError.configError(\n MCPErrorCode.ADD_FAILED,\n \"批量添加失败:所有服务都无法添加\"\n );\n }\n\n // 发送批量添加事件\n getEventBus().emitEvent(\"mcp:server:batch_added\", {\n totalServers: serverNames.length,\n addedCount,\n failedCount,\n successfullyAddedServers,\n results,\n timestamp: new Date(),\n });\n\n const response: MCPServerBatchAddResponse = {\n success: addedCount > 0,\n message:\n addedCount === serverNames.length\n ? `批量添加成功:已添加 ${addedCount} 个服务`\n : `批量添加部分成功:成功添加 ${addedCount} 个服务,失败 ${failedCount} 个服务`,\n results,\n addedCount,\n failedCount,\n };\n\n this.logger.info(\"addMCPServersBatch\", {\n totalServers: serverNames.length,\n addedCount,\n failedCount,\n });\n\n return response;\n } catch (error) {\n // 如果发生未处理的错误,尝试回滚已成功添加的服务\n if (successfullyAddedServers.length > 0) {\n await this.rollbackBatchAdd(successfullyAddedServers);\n }\n\n if (error instanceof MCPError) {\n throw error;\n }\n throw MCPError.systemError(\n MCPErrorCode.INTERNAL_ERROR,\n `批量添加过程中发生错误: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n\n /**\n * 验证批量服务配置\n */\n private validateBatchServers(\n mcpServers: Record<string, MCPServerConfig>\n ): ValidationResult {\n const errors: string[] = [];\n\n if (!mcpServers || typeof mcpServers !== \"object\") {\n errors.push(\"mcpServers 必须是一个对象\");\n return { isValid: false, errors };\n }\n\n const serverNames = Object.keys(mcpServers);\n if (serverNames.length === 0) {\n errors.push(\"mcpServers 对象不能为空\");\n return { isValid: false, errors };\n }\n\n if (serverNames.length > 50) {\n errors.push(\"批量添加的服务数量不能超过 50 个\");\n return { isValid: false, errors };\n }\n\n // 验证每个服务\n for (const [serverName, serverConfig] of Object.entries(mcpServers)) {\n // 验证服务名称\n const nameValidation =\n MCPServerConfigValidator.validateServiceName(serverName);\n if (!nameValidation.isValid) {\n errors.push(\n `服务 \"${serverName}\" 名称无效: ${nameValidation.errors.join(\", \")}`\n );\n continue;\n }\n\n // 检查是否已存在\n if (\n MCPServerConfigValidator.checkServiceExists(\n serverName,\n this.configManager\n )\n ) {\n errors.push(`服务 \"${serverName}\" 已存在`);\n continue;\n }\n\n // 标准化type字段格式\n const normalizedServerConfig = TypeFieldNormalizer.normalizeTypeField(\n serverConfig\n ) as MCPServerConfig;\n\n // 验证配置\n const configValidation = MCPServerConfigValidator.validateConfig(\n normalizedServerConfig\n );\n if (!configValidation.isValid) {\n errors.push(\n `服务 \"${serverName}\" 配置无效: ${configValidation.errors.join(\", \")}`\n );\n }\n }\n\n return { isValid: errors.length === 0, errors };\n }\n\n /**\n * 回滚批量添加的服务\n */\n private async rollbackBatchAdd(serverNames: string[]): Promise<void> {\n this.logger.info(\"开始回滚批量添加的服务\", { serverNames });\n\n const rollbackResults: string[] = [];\n const rollbackFailures: string[] = [];\n\n for (const serverName of serverNames) {\n try {\n // 停止服务\n try {\n await this.mcpServiceManager.stopService(serverName);\n } catch (error) {\n this.logger.warn(`回滚时停止服务 ${serverName} 失败:`, error);\n }\n\n // 移除服务配置\n this.mcpServiceManager.removeServiceConfig(serverName);\n this.configManager.removeMcpServer(serverName);\n\n rollbackResults.push(serverName);\n\n // 发送回滚事件\n getEventBus().emitEvent(\"mcp:server:rollback\", {\n serverName,\n timestamp: new Date(),\n });\n } catch (error) {\n const mcpError = this.handleError(error, \"rollbackBatchAdd\", {\n serverName,\n });\n rollbackFailures.push(serverName);\n\n this.logger.error(`回滚服务 ${serverName} 失败:`, mcpError.message);\n }\n }\n\n if (rollbackFailures.length > 0) {\n this.logger.warn(\"批量添加回滚部分失败\", {\n totalServers: serverNames.length,\n rollbackedCount: rollbackResults.length,\n failedCount: rollbackFailures.length,\n failedServers: rollbackFailures,\n });\n } else {\n this.logger.info(\"批量添加回滚成功\", {\n totalServers: serverNames.length,\n rollbackedCount: rollbackResults.length,\n });\n }\n }\n}\n\n/**\n * MCP 服务配置验证工具命名空间\n */\nexport namespace MCPServerConfigValidator {\n /**\n * 验证服务配置\n */\n export function validateConfig(config: MCPServerConfig): ValidationResult {\n const errors: string[] = [];\n\n // 验证配置基本结构\n if (!config || typeof config !== \"object\") {\n errors.push(\"配置必须是一个对象\");\n return { isValid: false, errors };\n }\n\n // 根据类型验证配置\n if (\"command\" in config) {\n // LocalMCPServerConfig\n if (!config.command || typeof config.command !== \"string\") {\n errors.push(\"本地服务必须提供有效的命令\");\n }\n if (config.args && !Array.isArray(config.args)) {\n errors.push(\"参数必须是数组\");\n }\n if (config.env && typeof config.env !== \"object\") {\n errors.push(\"环境变量必须是对象\");\n }\n } else if (\"url\" in config) {\n // SSEMCPServerConfig 或 StreamableHTTPMCPServerConfig\n if (!config.url || typeof config.url !== \"string\") {\n errors.push(\"远程服务必须提供有效的 URL\");\n }\n try {\n new URL(config.url);\n } catch {\n errors.push(\"URL 格式无效\");\n }\n } else {\n errors.push(\"配置必须包含 command 或 url 字段\");\n }\n\n return { isValid: errors.length === 0, errors };\n }\n\n /**\n * 验证服务名称\n */\n export function validateServiceName(name: string): ValidationResult {\n const errors: string[] = [];\n\n if (!name || typeof name !== \"string\") {\n errors.push(\"服务名称必须是非空字符串\");\n return { isValid: false, errors };\n }\n\n if (name.length < 1 || name.length > 50) {\n errors.push(\"服务名称长度必须在 1-50 个字符之间\");\n }\n\n if (!/^[a-zA-Z0-9_-]+$/.test(name)) {\n errors.push(\"服务名称只能包含字母、数字、下划线和连字符\");\n }\n\n return { isValid: errors.length === 0, errors };\n }\n\n /**\n * 检查服务是否已存在\n */\n export function checkServiceExists(\n name: string,\n configManager: ConfigManager\n ): boolean {\n const config = configManager.getConfig();\n return config.mcpServers && name in config.mcpServers;\n }\n}\n","import type { AppConfig } from \"@/lib/config/manager.js\";\nimport { configManager } from \"@/lib/config/manager.js\";\nimport type { Logger } from \"@root/Logger.js\";\nimport { logger } from \"@root/Logger.js\";\nimport type { EventBus } from \"@services/EventBus.js\";\nimport { getEventBus } from \"@services/EventBus.js\";\nimport type { NotificationService } from \"@services/NotificationService.js\";\nimport type { StatusService } from \"@services/StatusService.js\";\n\n/**\n * WebSocket 消息接口\n */\ninterface WebSocketMessage {\n type: string;\n data?: any;\n clientId?: string;\n}\n\n/**\n * 实时通知处理器\n */\nexport class RealtimeNotificationHandler {\n private logger: Logger;\n private notificationService: NotificationService;\n private statusService: StatusService;\n private eventBus: EventBus;\n\n constructor(\n notificationService: NotificationService,\n statusService: StatusService\n ) {\n this.logger = logger;\n this.notificationService = notificationService;\n this.statusService = statusService;\n this.eventBus = getEventBus();\n }\n\n /**\n * 处理 WebSocket 消息\n * @deprecated 部分消息类型已废弃,建议使用 HTTP API\n */\n async handleMessage(\n ws: any,\n message: WebSocketMessage,\n clientId: string\n ): Promise<void> {\n try {\n this.logger.debug(`处理 WebSocket 消息: ${message.type}`, { clientId });\n\n // 发射消息接收事件\n this.eventBus.emitEvent(\"websocket:message:received\", {\n type: message.type,\n data: message.data,\n clientId,\n });\n\n switch (message.type) {\n case \"getConfig\":\n await this.handleGetConfig(ws, clientId);\n break;\n\n case \"updateConfig\":\n await this.handleUpdateConfig(ws, message.data, clientId);\n break;\n\n case \"getStatus\":\n await this.handleGetStatus(ws, clientId);\n break;\n\n case \"restartService\":\n await this.handleRestartService(ws, clientId);\n break;\n\n default:\n this.logger.warn(`未知的 WebSocket 消息类型: ${message.type}`, {\n clientId,\n });\n this.sendError(\n ws,\n \"UNKNOWN_MESSAGE_TYPE\",\n `未知的消息类型: ${message.type}`\n );\n }\n } catch (error) {\n this.logger.error(`处理 WebSocket 消息失败: ${message.type}`, error);\n this.sendError(\n ws,\n \"MESSAGE_PROCESSING_ERROR\",\n error instanceof Error ? error.message : \"消息处理失败\"\n );\n }\n }\n\n /**\n * 处理获取配置请求\n * @deprecated 使用 GET /api/config 替代\n */\n private async handleGetConfig(ws: any, clientId: string): Promise<void> {\n this.logDeprecationWarning(\"WebSocket getConfig\", \"GET /api/config\");\n\n try {\n const config = configManager.getConfig();\n this.logger.debug(\"WebSocket: getConfig 请求处理成功\", { clientId });\n ws.send(JSON.stringify({ type: \"config\", data: config }));\n } catch (error) {\n this.logger.error(\"WebSocket: getConfig 请求处理失败\", error);\n this.sendError(\n ws,\n \"CONFIG_READ_ERROR\",\n error instanceof Error ? error.message : \"获取配置失败\"\n );\n }\n }\n\n /**\n * 处理更新配置请求\n * @deprecated 使用 PUT /api/config 替代\n */\n private async handleUpdateConfig(\n ws: any,\n configData: AppConfig,\n clientId: string\n ): Promise<void> {\n this.logDeprecationWarning(\"WebSocket updateConfig\", \"PUT /api/config\");\n\n try {\n // 使用 configManager 的验证方法\n configManager.validateConfig(configData);\n\n // 使用 configManager 的批量更新方法\n configManager.updateConfig(configData);\n\n // 更新服务工具配置(单独处理,因为 updateConfig 只更新已存在的配置)\n if (configData.mcpServerConfig) {\n for (const [serverName, toolsConfig] of Object.entries(\n configData.mcpServerConfig\n )) {\n for (const [toolName, toolConfig] of Object.entries(\n toolsConfig.tools\n )) {\n configManager.setToolEnabled(\n serverName,\n toolName,\n toolConfig.enable\n );\n }\n }\n }\n\n this.logger.debug(\"WebSocket: 配置更新成功\", { clientId });\n ws.send(JSON.stringify({ type: \"config:updated\", success: true }));\n } catch (error) {\n this.logger.error(\"WebSocket: 配置更新失败\", error);\n this.sendError(\n ws,\n \"CONFIG_UPDATE_ERROR\",\n error instanceof Error ? error.message : String(error)\n );\n }\n }\n\n /**\n * 处理获取状态请求\n * @deprecated 使用 GET /api/status 替代\n */\n private async handleGetStatus(ws: any, clientId: string): Promise<void> {\n this.logDeprecationWarning(\"WebSocket getStatus\", \"GET /api/status\");\n\n try {\n const status = this.statusService.getFullStatus();\n ws.send(JSON.stringify({ type: \"status\", data: status.client }));\n this.logger.debug(\"WebSocket: getStatus 请求处理成功\", { clientId });\n } catch (error) {\n this.logger.error(\"WebSocket: getStatus 请求处理失败\", error);\n this.sendError(\n ws,\n \"STATUS_READ_ERROR\",\n error instanceof Error ? error.message : \"获取状态失败\"\n );\n }\n }\n\n /**\n * 处理重启服务请求\n * @deprecated 使用 POST /api/services/restart 替代\n */\n private async handleRestartService(ws: any, clientId: string): Promise<void> {\n this.logDeprecationWarning(\n \"WebSocket restartService\",\n \"POST /api/services/restart\"\n );\n\n try {\n this.logger.info(\"WebSocket: 收到服务重启请求\", { clientId });\n\n // 发射重启请求事件\n this.eventBus.emitEvent(\"service:restart:requested\", {\n serviceName: \"unknown\", // 由于是WebSocket触发的,服务名未知\n source: `websocket-${clientId}`,\n delay: 0,\n attempt: 1,\n timestamp: Date.now(),\n });\n\n // 更新重启状态\n this.statusService.updateRestartStatus(\"restarting\");\n } catch (error) {\n this.logger.error(\"WebSocket: 处理重启请求失败\", error);\n this.sendError(\n ws,\n \"RESTART_REQUEST_ERROR\",\n error instanceof Error ? error.message : \"处理重启请求失败\"\n );\n }\n }\n\n /**\n * 发送错误消息\n */\n private sendError(ws: any, code: string, message: string): void {\n try {\n const errorResponse = {\n type: \"error\",\n error: {\n code,\n message,\n timestamp: Date.now(),\n },\n };\n ws.send(JSON.stringify(errorResponse));\n } catch (error) {\n this.logger.error(\"发送错误消息失败:\", error);\n }\n }\n\n /**\n * 记录废弃功能使用警告\n */\n private logDeprecationWarning(feature: string, alternative: string): void {\n this.logger.warn(\n `[DEPRECATED] ${feature} 功能已废弃,请使用 ${alternative} 替代`\n );\n }\n\n /**\n * 发送初始数据给新连接的客户端\n */\n async sendInitialData(ws: any, clientId: string): Promise<void> {\n try {\n this.logger.debug(\"发送初始数据给客户端\", { clientId });\n\n // 发送当前配置\n const config = configManager.getConfig();\n ws.send(JSON.stringify({ type: \"configUpdate\", data: config }));\n\n // 发送当前状态\n const status = this.statusService.getFullStatus();\n ws.send(JSON.stringify({ type: \"statusUpdate\", data: status.client }));\n\n // 如果有重启状态,也发送\n if (status.restart) {\n ws.send(\n JSON.stringify({ type: \"restartStatus\", data: status.restart })\n );\n }\n\n this.logger.debug(\"初始数据发送完成\", { clientId });\n } catch (error) {\n this.logger.error(\"发送初始数据失败:\", error);\n this.sendError(\n ws,\n \"INITIAL_DATA_ERROR\",\n error instanceof Error ? error.message : \"发送初始数据失败\"\n );\n }\n }\n\n /**\n * 处理客户端断开连接\n */\n handleClientDisconnect(clientId: string): void {\n this.logger.info(`客户端断开连接: ${clientId}`);\n this.notificationService.unregisterClient(clientId);\n }\n\n /**\n * 处理客户端连接\n */\n handleClientConnect(ws: any, clientId: string): void {\n this.logger.info(`客户端连接: ${clientId}`);\n this.notificationService.registerClient(clientId, ws);\n }\n}\n","import { spawn } from \"node:child_process\";\nimport { createContainer } from \"@cli/Container.js\";\nimport type { Logger } from \"@root/Logger.js\";\nimport { logger } from \"@root/Logger.js\";\nimport type { EventBus } from \"@services/EventBus.js\";\nimport { getEventBus } from \"@services/EventBus.js\";\nimport type { StatusService } from \"@services/StatusService.js\";\nimport type { Context } from \"hono\";\n\n/**\n * 统一响应格式接口\n */\ninterface ApiErrorResponse {\n error: {\n code: string;\n message: string;\n details?: any;\n };\n}\n\ninterface ApiSuccessResponse<T = any> {\n success: boolean;\n data?: T;\n message?: string;\n}\n\n/**\n * 服务 API 处理器\n */\nexport class ServiceApiHandler {\n private logger: Logger;\n private statusService: StatusService;\n private eventBus: EventBus;\n\n constructor(statusService: StatusService) {\n this.logger = logger;\n this.statusService = statusService;\n this.eventBus = getEventBus();\n }\n\n /**\n * 创建统一的错误响应\n */\n private createErrorResponse(\n code: string,\n message: string,\n details?: any\n ): ApiErrorResponse {\n return {\n error: {\n code,\n message,\n details,\n },\n };\n }\n\n /**\n * 创建统一的成功响应\n */\n private createSuccessResponse<T>(\n data?: T,\n message?: string\n ): ApiSuccessResponse<T> {\n return {\n success: true,\n data,\n message,\n };\n }\n\n /**\n * 重启服务\n * POST /api/services/restart\n */\n async restartService(c: Context): Promise<Response> {\n try {\n this.logger.info(\"处理服务重启请求\");\n\n // 发射重启请求事件\n this.eventBus.emitEvent(\"service:restart:requested\", {\n serviceName: \"unknown\", // 由于是HTTP API触发的,服务名未知\n source: \"http-api\",\n delay: 0,\n attempt: 1,\n timestamp: Date.now(),\n });\n\n // 更新重启状态\n this.statusService.updateRestartStatus(\"restarting\");\n\n // 异步执行重启,不阻塞响应\n setTimeout(async () => {\n try {\n await this.executeRestart();\n // 服务重启需要一些时间,延迟发送成功状态\n setTimeout(() => {\n this.statusService.updateRestartStatus(\"completed\");\n }, 5000);\n } catch (error) {\n this.logger.error(\"服务重启失败:\", error);\n this.statusService.updateRestartStatus(\n \"failed\",\n error instanceof Error ? error.message : \"未知错误\"\n );\n }\n }, 500);\n\n return c.json(this.createSuccessResponse(null, \"重启请求已接收\"));\n } catch (error) {\n this.logger.error(\"处理重启请求失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"RESTART_REQUEST_ERROR\",\n error instanceof Error ? error.message : \"处理重启请求失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 执行服务重启\n */\n private async executeRestart(): Promise<void> {\n this.logger.info(\"正在重启 MCP 服务...\");\n\n try {\n // 获取当前服务状态\n const container = await createContainer();\n const serviceManager = container.get(\"serviceManager\") as any;\n const status = await serviceManager.getStatus();\n\n if (!status.running) {\n this.logger.warn(\"MCP 服务未运行,尝试启动服务\");\n\n // 如果服务未运行,尝试启动服务\n const startArgs = [\"start\", \"--daemon\"];\n const child = spawn(\"xiaozhi\", startArgs, {\n detached: true,\n stdio: \"ignore\",\n env: {\n ...process.env,\n XIAOZHI_CONFIG_DIR: process.env.XIAOZHI_CONFIG_DIR || process.cwd(),\n },\n });\n child.unref();\n this.logger.info(\"MCP 服务启动命令已发送\");\n return;\n }\n\n // 获取服务运行模式\n const isDaemon = status.mode === \"daemon\";\n\n // 执行重启命令\n const restartArgs = [\"restart\"];\n if (isDaemon) {\n restartArgs.push(\"--daemon\");\n }\n\n // 在子进程中执行重启命令\n const child = spawn(\"xiaozhi\", restartArgs, {\n detached: true,\n stdio: \"ignore\",\n env: {\n ...process.env,\n XIAOZHI_CONFIG_DIR: process.env.XIAOZHI_CONFIG_DIR || process.cwd(),\n },\n });\n\n child.unref();\n this.logger.info(\"MCP 服务重启命令已发送\");\n } catch (error) {\n this.logger.error(\"重启服务失败:\", error);\n throw error;\n }\n }\n\n /**\n * 停止服务\n * POST /api/services/stop\n */\n async stopService(c: Context): Promise<Response> {\n try {\n this.logger.info(\"处理服务停止请求\");\n\n // 执行停止命令\n const stopArgs = [\"stop\"];\n const child = spawn(\"xiaozhi\", stopArgs, {\n detached: true,\n stdio: \"ignore\",\n env: {\n ...process.env,\n XIAOZHI_CONFIG_DIR: process.env.XIAOZHI_CONFIG_DIR || process.cwd(),\n },\n });\n\n child.unref();\n this.logger.info(\"MCP 服务停止命令已发送\");\n\n return c.json(this.createSuccessResponse(null, \"停止请求已接收\"));\n } catch (error) {\n this.logger.error(\"处理停止请求失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"STOP_REQUEST_ERROR\",\n error instanceof Error ? error.message : \"处理停止请求失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 启动服务\n * POST /api/services/start\n */\n async startService(c: Context): Promise<Response> {\n try {\n this.logger.info(\"处理服务启动请求\");\n\n // 执行启动命令\n const startArgs = [\"start\", \"--daemon\"];\n const child = spawn(\"xiaozhi\", startArgs, {\n detached: true,\n stdio: \"ignore\",\n env: {\n ...process.env,\n XIAOZHI_CONFIG_DIR: process.env.XIAOZHI_CONFIG_DIR || process.cwd(),\n },\n });\n\n child.unref();\n this.logger.info(\"MCP 服务启动命令已发送\");\n\n return c.json(this.createSuccessResponse(null, \"启动请求已接收\"));\n } catch (error) {\n this.logger.error(\"处理启动请求失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"START_REQUEST_ERROR\",\n error instanceof Error ? error.message : \"处理启动请求失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 获取服务状态\n * GET /api/services/status\n */\n async getServiceStatus(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理获取服务状态请求\");\n\n const container = await createContainer();\n const serviceManager = container.get(\"serviceManager\") as any;\n const status = await serviceManager.getStatus();\n\n this.logger.debug(\"获取服务状态成功\");\n return c.json(this.createSuccessResponse(status));\n } catch (error) {\n this.logger.error(\"获取服务状态失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"SERVICE_STATUS_READ_ERROR\",\n error instanceof Error ? error.message : \"获取服务状态失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 获取服务健康状态\n * GET /api/services/health\n */\n async getServiceHealth(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理获取服务健康状态请求\");\n\n // 简单的健康检查\n const health = {\n status: \"healthy\",\n timestamp: Date.now(),\n uptime: process.uptime(),\n memory: process.memoryUsage(),\n version: process.version,\n };\n\n this.logger.debug(\"获取服务健康状态成功\");\n return c.json(this.createSuccessResponse(health));\n } catch (error) {\n this.logger.error(\"获取服务健康状态失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"SERVICE_HEALTH_READ_ERROR\",\n error instanceof Error ? error.message : \"获取服务健康状态失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n}\n","import { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { Logger } from \"@root/Logger.js\";\nimport { logger } from \"@root/Logger.js\";\nimport type { Context } from \"hono\";\n\n/**\n * 静态文件处理器\n */\nexport class StaticFileHandler {\n private logger: Logger;\n private webPath: string | null = null;\n\n constructor() {\n this.logger = logger;\n this.initializeWebPath();\n }\n\n /**\n * 初始化 Web 路径\n */\n private initializeWebPath(): void {\n try {\n // 获取当前文件所在目录\n const __dirname = dirname(fileURLToPath(import.meta.url));\n\n this.logger.debug(`当前文件目录: ${__dirname}`);\n\n // 确定web目录路径\n // 支持 Nx 构建的 dist/frontend 目录结构\n const possibleWebPaths = [\n // Nx 构建的主要路径:dist/frontend/\n // 对于 dist/backend/handlers/StaticFileHandler.js -> ../../../frontend\n // 对于 dist/backend/cli.js -> ../../frontend\n // 对于 dist/cli.js -> ../frontend\n join(__dirname, \"..\", \"..\", \"..\", \"frontend\"),\n join(__dirname, \"..\", \"..\", \"frontend\"),\n join(__dirname, \"..\", \"frontend\"),\n\n // 兼容旧构建路径:从 dist 目录向上查找 apps/frontend/dist\n join(__dirname, \"..\", \"..\", \"apps\", \"frontend\", \"dist\"),\n join(__dirname, \"..\", \"apps\", \"frontend\", \"dist\"),\n\n // 备用路径:查找未构建的 apps/frontend 目录(开发模式)\n join(__dirname, \"..\", \"..\", \"apps\", \"frontend\"),\n join(__dirname, \"..\", \"apps\", \"frontend\"),\n\n // 兼容路径:保持对旧 web 目录的支持(向后兼容)\n join(__dirname, \"..\", \"..\", \"web\", \"dist\"),\n join(__dirname, \"..\", \"web\", \"dist\"),\n\n // 备用兼容路径:查找未构建的 web 目录(开发模式)\n join(__dirname, \"..\", \"..\", \"web\"),\n join(__dirname, \"..\", \"web\"),\n\n // 兜底路径:从源码目录查找(开发模式下的源码执行)\n join(__dirname, \"..\", \"..\", \"..\", \"apps\", \"frontend\", \"dist\"),\n join(__dirname, \"..\", \"..\", \"..\", \"apps\", \"frontend\"),\n join(__dirname, \"..\", \"..\", \"..\", \"web\", \"dist\"),\n join(__dirname, \"..\", \"..\", \"..\", \"web\"),\n ];\n\n // 查找第一个存在的路径\n this.webPath =\n possibleWebPaths.find((p) => {\n const exists = existsSync(p);\n this.logger.debug(`检查路径 ${p}: ${exists ? \"存在\" : \"不存在\"}`);\n return exists;\n }) || null;\n\n if (this.webPath) {\n this.logger.debug(`静态文件服务路径: ${this.webPath}`);\n } else {\n this.logger.warn(\"未找到静态文件目录\");\n this.logger.debug(\"尝试的路径:\", possibleWebPaths);\n }\n } catch (error) {\n this.logger.error(\"初始化静态文件路径失败:\", error);\n }\n }\n\n /**\n * 处理静态文件请求\n * GET /*\n */\n async handleStaticFile(c: Context): Promise<Response> {\n const pathname = new URL(c.req.url).pathname;\n\n try {\n this.logger.debug(`处理静态文件请求: ${pathname}`);\n\n if (!this.webPath) {\n return this.createErrorPage(c, \"找不到前端资源文件\");\n }\n\n // 处理路径\n let filePath = pathname;\n if (filePath === \"/\") {\n filePath = \"/index.html\";\n }\n\n // 安全性检查:防止路径遍历\n if (filePath.includes(\"..\")) {\n this.logger.warn(`路径遍历攻击尝试: ${filePath}`);\n return c.text(\"Forbidden\", 403);\n }\n\n const fullPath = join(this.webPath, filePath);\n\n // 检查文件是否存在\n if (!existsSync(fullPath)) {\n // 对于 SPA,返回 index.html\n const indexPath = join(this.webPath, \"index.html\");\n if (existsSync(indexPath)) {\n this.logger.debug(`SPA 回退到 index.html: ${pathname}`);\n return this.serveFile(c, indexPath, \"text/html\");\n }\n\n this.logger.debug(`文件不存在: ${fullPath}`);\n return c.text(\"Not Found\", 404);\n }\n\n // 确定 Content-Type\n const contentType = this.getContentType(fullPath);\n\n this.logger.debug(\n `服务静态文件: ${fullPath}, Content-Type: ${contentType}`\n );\n return this.serveFile(c, fullPath, contentType);\n } catch (error) {\n this.logger.error(`服务静态文件错误 (${pathname}):`, error);\n return c.text(\"Internal Server Error\", 500);\n }\n }\n\n /**\n * 服务文件\n */\n private async serveFile(\n c: Context,\n filePath: string,\n contentType: string\n ): Promise<Response> {\n try {\n const content = await readFile(filePath);\n\n // 对于文本文件,返回字符串;对于二进制文件,返回 ArrayBuffer\n if (\n contentType.startsWith(\"text/\") ||\n contentType.includes(\"javascript\") ||\n contentType.includes(\"json\")\n ) {\n return c.text(content.toString(), 200, { \"Content-Type\": contentType });\n }\n\n return c.body(new Uint8Array(content), 200, {\n \"Content-Type\": contentType,\n });\n } catch (error) {\n this.logger.error(`读取文件失败: ${filePath}`, error);\n throw error;\n }\n }\n\n /**\n * 获取文件的 Content-Type\n */\n private getContentType(filePath: string): string {\n const ext = filePath.split(\".\").pop()?.toLowerCase();\n\n const contentTypes: Record<string, string> = {\n html: \"text/html\",\n htm: \"text/html\",\n js: \"application/javascript\",\n mjs: \"application/javascript\",\n css: \"text/css\",\n json: \"application/json\",\n png: \"image/png\",\n jpg: \"image/jpeg\",\n jpeg: \"image/jpeg\",\n gif: \"image/gif\",\n svg: \"image/svg+xml\",\n ico: \"image/x-icon\",\n woff: \"font/woff\",\n woff2: \"font/woff2\",\n ttf: \"font/ttf\",\n eot: \"application/vnd.ms-fontobject\",\n pdf: \"application/pdf\",\n txt: \"text/plain\",\n xml: \"application/xml\",\n zip: \"application/zip\",\n tar: \"application/x-tar\",\n gz: \"application/gzip\",\n };\n\n return contentTypes[ext || \"\"] || \"application/octet-stream\";\n }\n\n /**\n * 创建错误页面\n */\n private createErrorPage(c: Context, message: string): Response {\n const errorHtml = `\n <!DOCTYPE html>\n <html>\n <head>\n <title>小智配置管理</title>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <style>\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n max-width: 800px;\n margin: 50px auto;\n padding: 20px;\n line-height: 1.6;\n color: #333;\n }\n .error {\n color: #e53e3e;\n background: #fed7d7;\n padding: 20px;\n border-radius: 8px;\n border-left: 4px solid #e53e3e;\n }\n .info {\n background: #e6f3ff;\n padding: 20px;\n border-radius: 8px;\n border-left: 4px solid #0066cc;\n margin-top: 20px;\n }\n pre {\n background: #f5f5f5;\n padding: 10px;\n border-radius: 4px;\n overflow-x: auto;\n }\n h1 {\n color: #2d3748;\n margin-bottom: 20px;\n }\n </style>\n </head>\n <body>\n <h1>小智配置管理</h1>\n <div class=\"error\">\n <p><strong>错误:</strong>${message}</p>\n </div>\n <div class=\"info\">\n <p><strong>解决方案:</strong></p>\n <p>请先构建前端项目:</p>\n <pre>cd apps/frontend && pnpm install && pnpm build</pre>\n <p><em>如果上面的路径不存在,可以尝试旧路径:</em></p>\n <pre>cd web && pnpm install && pnpm build</pre>\n <p>然后重新启动服务器。</p>\n </div>\n </body>\n </html>\n `;\n\n return c.html(errorHtml);\n }\n\n /**\n * 检查静态文件目录是否存在\n */\n isWebPathAvailable(): boolean {\n return this.webPath !== null && existsSync(this.webPath);\n }\n\n /**\n * 获取静态文件目录路径\n */\n getWebPath(): string | null {\n return this.webPath;\n }\n\n /**\n * 重新初始化 Web 路径\n */\n reinitializeWebPath(): void {\n this.initializeWebPath();\n }\n}\n","import type { Logger } from \"@root/Logger.js\";\nimport { logger } from \"@root/Logger.js\";\nimport type { StatusService } from \"@services/StatusService.js\";\nimport type { Context } from \"hono\";\n\n/**\n * 统一响应格式接口\n */\ninterface ApiErrorResponse {\n error: {\n code: string;\n message: string;\n details?: any;\n };\n}\n\ninterface ApiSuccessResponse<T = any> {\n success: boolean;\n data?: T;\n message?: string;\n}\n\n/**\n * 状态 API 处理器\n */\nexport class StatusApiHandler {\n private logger: Logger;\n private statusService: StatusService;\n\n constructor(statusService: StatusService) {\n this.logger = logger;\n this.statusService = statusService;\n }\n\n /**\n * 创建统一的错误响应\n */\n private createErrorResponse(\n code: string,\n message: string,\n details?: any\n ): ApiErrorResponse {\n return {\n error: {\n code,\n message,\n details,\n },\n };\n }\n\n /**\n * 创建统一的成功响应\n */\n private createSuccessResponse<T>(\n data?: T,\n message?: string\n ): ApiSuccessResponse<T> {\n return {\n success: true,\n data,\n message,\n };\n }\n\n /**\n * 获取完整状态\n * GET /api/status\n */\n async getStatus(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理获取状态请求\");\n const status = this.statusService.getFullStatus();\n this.logger.debug(\"获取状态成功\");\n return c.json(this.createSuccessResponse(status));\n } catch (error) {\n this.logger.error(\"获取状态失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"STATUS_READ_ERROR\",\n error instanceof Error ? error.message : \"获取状态失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 获取客户端状态\n * GET /api/status/client\n */\n async getClientStatus(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理获取客户端状态请求\");\n const clientStatus = this.statusService.getClientStatus();\n this.logger.debug(\"获取客户端状态成功\");\n return c.json(this.createSuccessResponse(clientStatus));\n } catch (error) {\n this.logger.error(\"获取客户端状态失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"CLIENT_STATUS_READ_ERROR\",\n error instanceof Error ? error.message : \"获取客户端状态失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 获取重启状态\n * GET /api/status/restart\n */\n async getRestartStatus(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理获取重启状态请求\");\n const restartStatus = this.statusService.getRestartStatus();\n this.logger.debug(\"获取重启状态成功\");\n return c.json(this.createSuccessResponse(restartStatus));\n } catch (error) {\n this.logger.error(\"获取重启状态失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"RESTART_STATUS_READ_ERROR\",\n error instanceof Error ? error.message : \"获取重启状态失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 检查客户端是否连接\n * GET /api/status/connected\n */\n async checkClientConnected(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理检查客户端连接请求\");\n const connected = this.statusService.isClientConnected();\n this.logger.debug(`客户端连接状态: ${connected}`);\n return c.json(this.createSuccessResponse({ connected }));\n } catch (error) {\n this.logger.error(\"检查客户端连接失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"CLIENT_CONNECTION_CHECK_ERROR\",\n error instanceof Error ? error.message : \"检查客户端连接失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 获取最后心跳时间\n * GET /api/status/heartbeat\n */\n async getLastHeartbeat(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理获取最后心跳时间请求\");\n const lastHeartbeat = this.statusService.getLastHeartbeat();\n this.logger.debug(\"获取最后心跳时间成功\");\n return c.json(this.createSuccessResponse({ lastHeartbeat }));\n } catch (error) {\n this.logger.error(\"获取最后心跳时间失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"HEARTBEAT_READ_ERROR\",\n error instanceof Error ? error.message : \"获取最后心跳时间失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 获取活跃的 MCP 服务器列表\n * GET /api/status/mcp-servers\n */\n async getActiveMCPServers(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理获取活跃 MCP 服务器请求\");\n const servers = this.statusService.getActiveMCPServers();\n this.logger.debug(\"获取活跃 MCP 服务器成功\");\n return c.json(this.createSuccessResponse({ servers }));\n } catch (error) {\n this.logger.error(\"获取活跃 MCP 服务器失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"ACTIVE_MCP_SERVERS_READ_ERROR\",\n error instanceof Error ? error.message : \"获取活跃 MCP 服务器失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 更新客户端状态\n * PUT /api/status/client\n */\n async updateClientStatus(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理更新客户端状态请求\");\n const statusUpdate = await c.req.json();\n\n // 验证请求体\n if (!statusUpdate || typeof statusUpdate !== \"object\") {\n const errorResponse = this.createErrorResponse(\n \"INVALID_REQUEST_BODY\",\n \"请求体必须是有效的状态对象\"\n );\n return c.json(errorResponse, 400);\n }\n\n this.statusService.updateClientInfo(statusUpdate, \"http-api\");\n this.logger.info(\"客户端状态更新成功\");\n\n return c.json(this.createSuccessResponse(null, \"客户端状态更新成功\"));\n } catch (error) {\n this.logger.error(\"更新客户端状态失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"CLIENT_STATUS_UPDATE_ERROR\",\n error instanceof Error ? error.message : \"更新客户端状态失败\"\n );\n return c.json(errorResponse, 400);\n }\n }\n\n /**\n * 设置活跃的 MCP 服务器列表\n * PUT /api/status/mcp-servers\n */\n async setActiveMCPServers(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理设置活跃 MCP 服务器请求\");\n const { servers } = await c.req.json();\n\n // 验证请求体\n if (!Array.isArray(servers)) {\n const errorResponse = this.createErrorResponse(\n \"INVALID_REQUEST_BODY\",\n \"servers 必须是字符串数组\"\n );\n return c.json(errorResponse, 400);\n }\n\n this.statusService.setActiveMCPServers(servers);\n this.logger.info(\"活跃 MCP 服务器设置成功\");\n\n return c.json(\n this.createSuccessResponse(null, \"活跃 MCP 服务器设置成功\")\n );\n } catch (error) {\n this.logger.error(\"设置活跃 MCP 服务器失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"ACTIVE_MCP_SERVERS_UPDATE_ERROR\",\n error instanceof Error ? error.message : \"设置活跃 MCP 服务器失败\"\n );\n return c.json(errorResponse, 400);\n }\n }\n\n /**\n * 重置状态\n * POST /api/status/reset\n */\n async resetStatus(c: Context): Promise<Response> {\n try {\n this.logger.info(\"处理重置状态请求\");\n this.statusService.reset();\n this.logger.info(\"状态重置成功\");\n return c.json(this.createSuccessResponse(null, \"状态重置成功\"));\n } catch (error) {\n this.logger.error(\"重置状态失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"STATUS_RESET_ERROR\",\n error instanceof Error ? error.message : \"重置状态失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n}\n","/**\n * 工具添加 API 相关类型定义\n * 支持多种工具类型的添加,包括 MCP 工具、Coze 工作流等\n */\n\nimport type { CozeWorkflow, WorkflowParameterConfig } from \"./coze.js\";\n\n/**\n * 工具类型枚举\n */\nexport enum ToolType {\n /** MCP 工具(标准 MCP 服务中的工具) */\n MCP = \"mcp\",\n /** Coze 工作流工具 */\n COZE = \"coze\",\n /** HTTP API 工具(预留) */\n HTTP = \"http\",\n /** 自定义函数工具(预留) */\n FUNCTION = \"function\",\n}\n\n/**\n * MCP 工具数据\n * 用于将标准 MCP 服务中的工具添加到 customMCP.tools 配置中\n */\nexport interface MCPToolData {\n /** MCP 服务名称 */\n serviceName: string;\n /** 工具名称 */\n toolName: string;\n /** 可选的自定义名称 */\n customName?: string;\n /** 可选的自定义描述 */\n customDescription?: string;\n}\n\n/**\n * Coze 工作流数据\n * 保持与现有格式的兼容性\n */\nexport interface CozeWorkflowData {\n /** Coze 工作流信息 */\n workflow: CozeWorkflow;\n /** 可选的自定义名称 */\n customName?: string;\n /** 可选的自定义描述 */\n customDescription?: string;\n /** 可选的参数配置 */\n parameterConfig?: WorkflowParameterConfig;\n}\n\n/**\n * HTTP API 工具数据(预留)\n */\nexport interface HttpApiToolData {\n /** API 地址 */\n url: string;\n /** HTTP 方法 */\n method?: \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n /** API 描述 */\n description: string;\n /** 请求头 */\n headers?: Record<string, string>;\n /** 请求体模板 */\n bodyTemplate?: string;\n /** 认证配置 */\n auth?: {\n type: \"bearer\" | \"basic\" | \"api_key\";\n token?: string;\n username?: string;\n password?: string;\n apiKey?: string;\n apiKeyHeader?: string;\n };\n /** 可选的自定义名称 */\n customName?: string;\n /** 可选的自定义描述 */\n customDescription?: string;\n}\n\n/**\n * 函数工具数据(预留)\n */\nexport interface FunctionToolData {\n /** 模块路径 */\n module: string;\n /** 函数名 */\n function: string;\n /** 函数描述 */\n description: string;\n /** 函数执行上下文 */\n context?: Record<string, any>;\n /** 超时时间 */\n timeout?: number;\n /** 可选的自定义名称 */\n customName?: string;\n /** 可选的自定义描述 */\n customDescription?: string;\n}\n\n/**\n * 添加自定义工具的统一请求接口\n */\nexport interface AddCustomToolRequest {\n /** 工具类型 */\n type: ToolType;\n /** 工具数据(根据类型不同而不同) */\n data: MCPToolData | CozeWorkflowData | HttpApiToolData | FunctionToolData;\n}\n\n/**\n * 工具验证错误类型\n */\nexport enum ToolValidationError {\n /** 无效的工具类型 */\n INVALID_TOOL_TYPE = \"INVALID_TOOL_TYPE\",\n /** 缺少必需字段 */\n MISSING_REQUIRED_FIELD = \"MISSING_REQUIRED_FIELD\",\n /** 工具不存在 */\n TOOL_NOT_FOUND = \"TOOL_NOT_FOUND\",\n /** 服务不存在 */\n SERVICE_NOT_FOUND = \"SERVICE_NOT_FOUND\",\n /** 工具名称冲突 */\n TOOL_NAME_CONFLICT = \"TOOL_NAME_CONFLICT\",\n /** 配置验证失败 */\n CONFIG_VALIDATION_FAILED = \"CONFIG_VALIDATION_FAILED\",\n /** 系统配置错误 */\n SYSTEM_CONFIG_ERROR = \"SYSTEM_CONFIG_ERROR\",\n /** 资源限制超出 */\n RESOURCE_LIMIT_EXCEEDED = \"RESOURCE_LIMIT_EXCEEDED\",\n}\n\n/**\n * 工具验证错误详情\n */\nexport interface ToolValidationErrorDetail {\n /** 错误类型 */\n error: ToolValidationError;\n /** 错误消息 */\n message: string;\n /** 错误详情 */\n details?: any;\n /** 建议的解决方案 */\n suggestions?: string[];\n}\n\n/**\n * 添加工具的响应数据\n */\nexport interface AddToolResponse {\n /** 成功添加的工具 */\n tool: any;\n /** 工具名称 */\n toolName: string;\n /** 工具类型 */\n toolType: ToolType;\n /** 添加时间戳 */\n addedAt: string;\n}\n\n/**\n * 工具元数据信息\n */\nexport interface ToolMetadata {\n /** 工具原始来源 */\n source: {\n type: \"mcp\" | \"coze\" | \"http\" | \"function\";\n serviceName?: string;\n toolName?: string;\n url?: string;\n };\n /** 添加时间 */\n addedAt: string;\n /** 最后更新时间 */\n updatedAt?: string;\n /** 版本信息 */\n version?: string;\n}\n\n/**\n * 工具配置选项\n */\nexport interface ToolConfigOptions {\n /** 是否启用工具(默认 true) */\n enabled?: boolean;\n /** 超时时间(毫秒) */\n timeout?: number;\n /** 重试次数 */\n retryCount?: number;\n /** 重试间隔(毫秒) */\n retryDelay?: number;\n /** 自定义标签 */\n tags?: string[];\n /** 工具分组 */\n group?: string;\n}\n\n/**\n * 扩展的 CustomMCPTool 接口\n * 包含额外的元数据信息\n */\nexport interface ExtendedCustomMCPTool {\n /** 基础工具配置 */\n name: string;\n description: string;\n inputSchema: any;\n handler: any;\n /** 使用统计信息 */\n stats?: {\n usageCount?: number;\n lastUsedTime?: string;\n };\n /** 工具元数据 */\n metadata?: ToolMetadata;\n /** 配置选项 */\n config?: ToolConfigOptions;\n}\n","/**\n * 工具调用 API 处理器\n * 处理通过 HTTP API 调用 MCP 工具的请求\n */\n\nimport { configManager } from \"@/lib/config/manager.js\";\nimport type {\n CustomMCPTool,\n ProxyHandlerConfig,\n} from \"@/lib/config/manager.js\";\nimport { MCPCacheManager } from \"@/lib/mcp\";\nimport type { MCPServiceManager } from \"@/lib/mcp\";\nimport type { JSONSchema } from \"@/lib/mcp/types.js\";\nimport type { Logger } from \"@root/Logger.js\";\nimport { logger } from \"@root/Logger.js\";\nimport type {\n CozeWorkflow,\n WorkflowParameterConfig,\n} from \"@root/types/coze.js\";\nimport type {\n AddCustomToolRequest,\n AddToolResponse,\n CozeWorkflowData,\n MCPToolData,\n} from \"@root/types/toolApi.js\";\nimport { ToolType } from \"@root/types/toolApi.js\";\nimport Ajv from \"ajv\";\nimport dayjs from \"dayjs\";\nimport type { Context } from \"hono\";\nimport type { ContentfulStatusCode } from \"hono/utils/http-status\";\n\n/**\n * 工具调用请求接口\n */\ninterface ToolCallRequest {\n serviceName: string;\n toolName: string;\n args: Record<string, unknown>;\n}\n\n/**\n * 工具调用响应接口\n */\ninterface ToolCallResponse {\n success: boolean;\n data?: unknown | CustomMCPTool[] | { list: CustomMCPTool[]; total: number };\n error?: {\n code: string;\n message: string;\n };\n message?: string;\n}\n\n/**\n * 添加自定义工具请求接口(向后兼容)\n * @deprecated 使用新的 AddCustomToolRequest 类型定义\n */\ninterface LegacyAddCustomToolRequest {\n workflow: CozeWorkflow;\n customName?: string;\n customDescription?: string;\n parameterConfig?: WorkflowParameterConfig;\n}\n\n/**\n * 工具调用 API 处理器\n */\nexport class ToolApiHandler {\n private logger: Logger;\n private ajv: Ajv;\n\n constructor() {\n this.logger = logger;\n this.ajv = new Ajv({ allErrors: true, verbose: true });\n }\n\n /**\n * 创建成功响应\n */\n private createSuccessResponse(\n data: unknown,\n message?: string\n ): ToolCallResponse {\n return {\n success: true,\n data,\n message,\n };\n }\n\n /**\n * 创建错误响应\n */\n private createErrorResponse(code: string, message: string): ToolCallResponse {\n return {\n success: false,\n error: {\n code,\n message,\n },\n };\n }\n\n /**\n * 确保 HTTP 状态码是有效的\n */\n private ensureValidStatusCode(code: number): number {\n // 确保状态码是有效的 HTTP 状态码\n if (code >= 100 && code < 600) {\n return code;\n }\n // 默认返回 500\n return 500;\n }\n\n /**\n * 创建 Hono 响应,正确处理状态码类型\n */\n private createHonoResponse(\n c: Context,\n data: ToolCallResponse,\n statusCode: number\n ): Response {\n return c.json(data, statusCode as ContentfulStatusCode);\n }\n\n /**\n * 调用 MCP 工具\n * POST /api/tools/call\n */\n async callTool(c: Context): Promise<Response> {\n try {\n this.logger.info(\"处理工具调用请求\");\n\n // 解析请求体\n const requestBody: ToolCallRequest = await c.req.json();\n const { serviceName, toolName, args } = requestBody;\n\n // 验证请求参数\n if (!serviceName || !toolName) {\n const errorResponse = this.createErrorResponse(\n \"INVALID_REQUEST\",\n \"serviceName 和 toolName 是必需的参数\"\n );\n return c.json(errorResponse, 400);\n }\n\n this.logger.info(\n `准备调用工具: ${serviceName}/${toolName},参数:`,\n JSON.stringify(args)\n );\n\n // 从 Context 中获取 MCPServiceManager 实例\n const serviceManager = c.get(\"mcpServiceManager\");\n if (!serviceManager) {\n const errorResponse = this.createErrorResponse(\n \"SERVICE_NOT_INITIALIZED\",\n \"MCP 服务管理器未初始化。请检查服务状态。\"\n );\n return c.json(errorResponse, 503);\n }\n\n // 验证服务和工具是否存在\n await this.validateServiceAndTool(serviceManager, serviceName, toolName);\n\n // 对于 customMCP 工具,进行参数验证\n if (serviceName === \"customMCP\") {\n await this.validateCustomMCPArguments(\n serviceManager,\n toolName,\n args || {}\n );\n }\n\n // 调用工具 - 特殊处理 customMCP 服务\n let result: unknown;\n if (serviceName === \"customMCP\") {\n // 对于 customMCP 服务,直接使用 toolName 调用,传递60秒超时\n result = await serviceManager.callTool(toolName, args || {}, {\n timeout: 60000,\n });\n } else {\n // 对于标准 MCP 服务,使用 serviceName__toolName 格式,保持8秒超时\n const toolKey = `${serviceName}__${toolName}`;\n result = await serviceManager.callTool(toolKey, args || {});\n }\n\n // this.logger.debug(`工具调用成功: ${serviceName}/${toolName}`);\n\n return c.json(this.createSuccessResponse(result, \"工具调用成功\"));\n } catch (error) {\n this.logger.error(\"工具调用失败:\", error);\n\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n let errorCode = \"TOOL_CALL_ERROR\";\n\n // 根据错误类型设置不同的错误码\n if (errorMessage.includes(\"不存在\")) {\n errorCode = \"SERVICE_OR_TOOL_NOT_FOUND\";\n } else if (\n errorMessage.includes(\"未启动\") ||\n errorMessage.includes(\"未连接\")\n ) {\n errorCode = \"SERVICE_NOT_AVAILABLE\";\n } else if (errorMessage.includes(\"已被禁用\")) {\n errorCode = \"TOOL_DISABLED\";\n } else if (errorMessage.includes(\"参数验证失败\")) {\n errorCode = \"INVALID_ARGUMENTS\";\n } else if (\n errorMessage.includes(\"CustomMCP\") ||\n errorMessage.includes(\"customMCP\")\n ) {\n errorCode = \"CUSTOM_MCP_ERROR\";\n } else if (\n errorMessage.includes(\"工作流调用失败\") ||\n errorMessage.includes(\"API 请求失败\")\n ) {\n errorCode = \"EXTERNAL_API_ERROR\";\n } else if (errorMessage.includes(\"超时\")) {\n errorCode = \"TIMEOUT_ERROR\";\n }\n\n const errorResponse = this.createErrorResponse(errorCode, errorMessage);\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 获取自定义 MCP 工具列表\n * GET /api/tools/custom\n */\n async getCustomTools(c: Context): Promise<Response> {\n try {\n this.logger.info(\"处理获取自定义 MCP 工具列表请求\");\n\n // 检查配置文件是否存在\n if (!configManager.configExists()) {\n const errorResponse = this.createErrorResponse(\n \"CONFIG_NOT_FOUND\",\n \"配置文件不存在,请先运行 'xiaozhi init' 初始化配置\"\n );\n return c.json(errorResponse, 404);\n }\n\n // 获取自定义 MCP 工具列表\n let customTools: CustomMCPTool[] = [];\n let configPath = \"\";\n\n try {\n customTools = configManager.getCustomMCPTools();\n configPath = configManager.getConfigPath();\n } catch (error) {\n this.logger.error(\"读取自定义 MCP 工具配置失败:\", error);\n const errorResponse = this.createErrorResponse(\n \"CONFIG_PARSE_ERROR\",\n `配置文件解析失败: ${error instanceof Error ? error.message : \"未知错误\"}`\n );\n return c.json(errorResponse, 500);\n }\n\n // 检查是否配置了自定义 MCP 工具\n if (!customTools || customTools.length === 0) {\n this.logger.info(\"未配置自定义 MCP 工具\");\n return c.json(\n this.createSuccessResponse(\n {\n tools: [],\n totalTools: 0,\n configPath,\n },\n \"未配置自定义 MCP 工具\"\n )\n );\n }\n\n // 验证工具配置的有效性\n const isValid = configManager.validateCustomMCPTools(customTools);\n if (!isValid) {\n this.logger.warn(\"自定义 MCP 工具配置验证失败\");\n const errorResponse = this.createErrorResponse(\n \"INVALID_TOOL_CONFIG\",\n \"自定义 MCP 工具配置验证失败,请检查配置文件中的工具定义\"\n );\n return c.json(errorResponse, 400);\n }\n\n this.logger.info(\n `获取自定义 MCP 工具列表成功,共 ${customTools.length} 个工具`\n );\n\n return c.json(\n this.createSuccessResponse(\n {\n tools: customTools,\n totalTools: customTools.length,\n configPath,\n },\n \"获取自定义 MCP 工具列表成功\"\n )\n );\n } catch (error) {\n this.logger.error(\"获取自定义 MCP 工具列表失败:\", error);\n\n const errorResponse = this.createErrorResponse(\n \"GET_CUSTOM_TOOLS_ERROR\",\n error instanceof Error ? error.message : \"获取自定义 MCP 工具列表失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 获取可用工具列表\n * GET /api/tools/list?status=enabled|disabled|all\n */\n async listTools(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理获取工具列表请求\");\n\n // 获取筛选参数\n const status =\n (c.req.query(\"status\") as \"enabled\" | \"disabled\" | \"all\") || \"all\";\n\n let tools: CustomMCPTool[] = [];\n\n switch (status) {\n case \"enabled\":\n // 已启用工具:从 xiaozhi.config.json 的 customMCP.tools 获取\n tools = configManager.getCustomMCPTools();\n this.logger.debug(`获取已启用工具,共 ${tools.length} 个`);\n break;\n\n case \"disabled\":\n // 未启用工具:从缓存中获取所有工具,过滤掉已启用的\n tools = await this.getDisabledTools();\n this.logger.debug(`获取未启用工具,共 ${tools.length} 个`);\n break;\n\n default:\n // 所有工具:从 xiaozhi.config.json 的 customMCP.tools 获取\n tools = configManager.getCustomMCPTools();\n this.logger.debug(`获取所有工具,共 ${tools.length} 个`);\n break;\n }\n\n // 返回对象格式的响应\n const responseData = {\n list: tools,\n total: tools.length,\n };\n\n return c.json(\n this.createSuccessResponse(\n responseData,\n `获取工具列表成功(${status})`\n )\n );\n } catch (error) {\n this.logger.error(\"获取工具列表失败:\", error);\n\n const errorResponse = this.createErrorResponse(\n \"GET_TOOLS_FAILED\",\n \"获取工具列表失败\"\n );\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 获取未启用工具\n * 从缓存中获取所有工具,过滤掉已启用的工具和已删除的 MCP 服务\n */\n private async getDisabledTools(): Promise<CustomMCPTool[]> {\n try {\n // 1. 获取已启用的工具名称集合\n const enabledTools = configManager.getCustomMCPTools();\n const enabledToolNames = new Set(enabledTools.map((tool) => tool.name));\n\n // 2. 从缓存中获取所有可用工具\n const cacheManager = new MCPCacheManager();\n const allCachedTools = await cacheManager.getAllCachedTools();\n\n // 3. 获取当前配置的 MCP 服务列表\n const config = configManager.getConfig();\n const configuredServers = new Set(Object.keys(config.mcpServers || {}));\n\n // 4. 过滤掉已启用的工具和已删除 MCP 服务的工具\n const disabledTools: CustomMCPTool[] = [];\n\n for (const cachedTool of allCachedTools) {\n // 如果工具已在启用列表中,跳过\n if (enabledToolNames.has(cachedTool.name)) {\n continue;\n }\n\n // 从工具名称中解析服务名称\n const serviceName = cachedTool.name.split(\"__\")[0];\n\n // 检查该 MCP 服务是否仍在配置中\n if (!configuredServers.has(serviceName)) {\n // 该 MCP 服务已从配置中删除,不显示为\"未启用工具\"\n this.logger.debug(\n `工具 ${cachedTool.name} 对应的 MCP 服务 ${serviceName} 已删除,跳过显示`\n );\n continue;\n }\n\n // 将缓存中的 Tool 格式转换为 CustomMCPTool 格式\n const customTool: CustomMCPTool = {\n name: cachedTool.name,\n description: cachedTool.description || \"\",\n inputSchema: cachedTool.inputSchema || {},\n handler: {\n type: \"mcp\",\n config: {\n serviceName: serviceName,\n toolName: cachedTool.name.split(\"__\").slice(1).join(\"__\"),\n },\n },\n };\n disabledTools.push(customTool);\n }\n\n this.logger.debug(\n `从 ${allCachedTools.length} 个缓存工具中筛选出 ${disabledTools.length} 个未启用工具`\n );\n return disabledTools;\n } catch (error) {\n this.logger.error(\"获取未启用工具失败:\", error);\n // 如果获取失败,返回空数组而不是抛出错误\n return [];\n }\n }\n\n /**\n * 验证服务和工具是否存在\n * @private\n */\n private async validateServiceAndTool(\n serviceManager: MCPServiceManager,\n serviceName: string,\n toolName: string\n ): Promise<void> {\n // 特殊处理 customMCP 服务\n if (serviceName === \"customMCP\") {\n // 验证 customMCP 工具是否存在\n if (!serviceManager.hasCustomMCPTool(toolName)) {\n const availableTools = serviceManager\n .getCustomMCPTools()\n .map((tool) => tool.name);\n\n if (availableTools.length === 0) {\n throw new Error(\n `customMCP 工具 '${toolName}' 不存在。当前没有配置任何 customMCP 工具。请检查 xiaozhi.config.json 中的 customMCP 配置。`\n );\n }\n\n throw new Error(\n `customMCP 工具 '${toolName}' 不存在。可用的 customMCP 工具: ${availableTools.join(\", \")}。请使用 'xiaozhi mcp list' 查看所有可用工具。`\n );\n }\n\n // 验证 customMCP 工具配置是否有效\n try {\n const customTools = serviceManager.getCustomMCPTools();\n const targetTool = customTools.find((tool) => tool.name === toolName);\n\n if (targetTool && !targetTool.description) {\n this.logger.warn(`customMCP 工具 '${toolName}' 缺少描述信息`);\n }\n\n if (targetTool && !targetTool.inputSchema) {\n this.logger.warn(`customMCP 工具 '${toolName}' 缺少输入参数定义`);\n }\n } catch (error) {\n this.logger.error(\n `验证 customMCP 工具 '${toolName}' 配置时出错:`,\n error\n );\n throw new Error(\n `customMCP 工具 '${toolName}' 配置验证失败。请检查配置文件中的工具定义。`\n );\n }\n\n return;\n }\n }\n\n /**\n * 验证 customMCP 工具的参数\n * @private\n */\n private async validateCustomMCPArguments(\n serviceManager: MCPServiceManager,\n toolName: string,\n args: Record<string, unknown>\n ): Promise<void> {\n try {\n // 获取工具的 inputSchema\n const customTools = serviceManager.getCustomMCPTools();\n const targetTool = customTools.find((tool) => tool.name === toolName);\n\n if (!targetTool) {\n throw new Error(`customMCP 工具 '${toolName}' 不存在`);\n }\n\n // 如果工具没有定义 inputSchema,跳过验证\n if (!targetTool.inputSchema) {\n this.logger.warn(\n `customMCP 工具 '${toolName}' 没有定义 inputSchema,跳过参数验证`\n );\n return;\n }\n\n // 使用 AJV 验证参数\n const validate = this.ajv.compile(targetTool.inputSchema);\n const valid = validate(args);\n\n if (!valid) {\n // 构建详细的错误信息\n const errors = validate.errors || [];\n const errorMessages = errors.map((error) => {\n const path = error.instancePath || error.schemaPath || \"\";\n const message = error.message || \"未知错误\";\n\n if (error.keyword === \"required\") {\n const missingProperty = error.params?.missingProperty || \"未知字段\";\n return `缺少必需参数: ${missingProperty}`;\n }\n\n if (error.keyword === \"type\") {\n const expectedType = error.params?.type || \"未知类型\";\n return `参数 ${path} 类型错误,期望: ${expectedType}`;\n }\n\n if (error.keyword === \"enum\") {\n const allowedValues = error.params?.allowedValues || [];\n return `参数 ${path} 值无效,允许的值: ${allowedValues.join(\", \")}`;\n }\n\n return `参数 ${path} ${message}`;\n });\n\n const errorMessage = `参数验证失败: ${errorMessages.join(\"; \")}`;\n this.logger.error(\n `customMCP 工具 '${toolName}' 参数验证失败:`,\n errorMessage\n );\n\n throw new Error(errorMessage);\n }\n\n this.logger.debug(`customMCP 工具 '${toolName}' 参数验证通过`);\n } catch (error) {\n if (error instanceof Error && error.message.includes(\"参数验证失败\")) {\n throw error;\n }\n\n this.logger.error(`验证 customMCP 工具 '${toolName}' 参数时出错:`, error);\n throw new Error(\n `参数验证过程中发生错误: ${error instanceof Error ? error.message : \"未知错误\"}`\n );\n }\n }\n\n /**\n * 添加自定义 MCP 工具\n * POST /api/tools/custom\n * 支持多种工具类型:MCP 工具、Coze 工作流等\n */\n async addCustomTool(c: Context): Promise<Response> {\n try {\n this.logger.info(\"处理添加自定义工具请求\");\n\n const requestBody = await c.req.json();\n\n // 检查是否为新格式的请求\n if (this.isNewFormatRequest(requestBody)) {\n // 新格式:支持多种工具类型\n return await this.handleNewFormatAddTool(\n c,\n requestBody as AddCustomToolRequest\n );\n }\n // 旧格式:向后兼容\n return await this.handleLegacyFormatAddTool(\n c,\n requestBody as LegacyAddCustomToolRequest\n );\n } catch (error) {\n this.logger.error(\"添加自定义工具失败:\", error);\n\n // 根据错误类型返回不同的HTTP状态码和错误信息\n const { statusCode, errorResponse } = this.handleAddToolError(error);\n return this.createHonoResponse(\n c,\n errorResponse,\n this.ensureValidStatusCode(statusCode)\n );\n }\n }\n\n /**\n * 判断是否为新格式的请求\n */\n private isNewFormatRequest(body: unknown): body is AddCustomToolRequest {\n return (\n body !== null &&\n typeof body === \"object\" &&\n !Array.isArray(body) &&\n \"type\" in body &&\n \"data\" in body\n );\n }\n\n /**\n * 处理新格式的添加工具请求\n */\n private async handleNewFormatAddTool(\n c: Context,\n request: AddCustomToolRequest\n ): Promise<Response> {\n const { type, data } = request;\n\n this.logger.info(`处理新格式工具添加请求,类型: ${type}`);\n\n // 验证工具类型\n if (!Object.values(ToolType).includes(type)) {\n const errorResponse = this.createErrorResponse(\n \"INVALID_TOOL_TYPE\",\n `不支持的工具类型: ${type}。支持的类型: ${Object.values(ToolType).join(\", \")}`\n );\n return c.json(errorResponse, 400);\n }\n\n // 根据工具类型分发处理\n switch (type) {\n case ToolType.MCP:\n return await this.handleAddMCPTool(c, data as MCPToolData);\n\n case ToolType.COZE:\n return await this.handleAddCozeTool(c, data as CozeWorkflowData);\n\n case ToolType.HTTP:\n case ToolType.FUNCTION: {\n const httpErrorResponse = this.createErrorResponse(\n \"TOOL_TYPE_NOT_IMPLEMENTED\",\n `工具类型 ${type} 暂未实现,请使用 MCP 或 Coze 类型`\n );\n return c.json(httpErrorResponse, 501);\n }\n\n default: {\n const defaultErrorResponse = this.createErrorResponse(\n \"UNKNOWN_TOOL_TYPE\",\n `未知的工具类型: ${type}`\n );\n return c.json(defaultErrorResponse, 400);\n }\n }\n }\n\n /**\n * 处理旧格式的添加工具请求(向后兼容)\n */\n private async handleLegacyFormatAddTool(\n c: Context,\n request: LegacyAddCustomToolRequest\n ): Promise<Response> {\n this.logger.info(\"处理旧格式工具添加请求(向后兼容)\");\n\n const { workflow, customName, customDescription, parameterConfig } =\n request;\n\n // 边界条件预检查\n const preCheckResult = this.performPreChecks(\n workflow,\n customName,\n customDescription\n );\n if (preCheckResult) {\n return this.createHonoResponse(\n c,\n preCheckResult.errorResponse,\n this.ensureValidStatusCode(preCheckResult.statusCode)\n );\n }\n\n // 转换工作流为工具配置\n const tool = this.convertWorkflowToTool(\n workflow,\n customName,\n customDescription,\n parameterConfig\n );\n\n // 添加工具到配置\n configManager.addCustomMCPTool(tool);\n\n this.logger.info(`成功添加自定义工具: ${tool.name}`);\n\n return c.json(\n this.createSuccessResponse({ tool }, `工具 \"${tool.name}\" 添加成功`)\n );\n }\n\n /**\n * 处理添加 MCP 工具\n */\n private async handleAddMCPTool(\n c: Context,\n data: MCPToolData\n ): Promise<Response> {\n const { serviceName, toolName, customName, customDescription } = data;\n\n this.logger.info(`处理添加 MCP 工具: ${serviceName}/${toolName}`);\n\n // 验证必需字段\n if (!serviceName || !toolName) {\n const errorResponse = this.createErrorResponse(\n \"MISSING_REQUIRED_FIELD\",\n \"serviceName 和 toolName 是必需字段\"\n );\n return c.json(errorResponse, 400);\n }\n\n // 从 Context 中获取 MCPServiceManager 实例\n const serviceManager = c.get(\"mcpServiceManager\");\n if (!serviceManager) {\n const errorResponse = this.createErrorResponse(\n \"SERVICE_NOT_INITIALIZED\",\n \"MCP 服务管理器未初始化。请检查服务状态。\"\n );\n return c.json(errorResponse, 503);\n }\n\n // 验证服务和工具是否存在\n try {\n await this.validateServiceAndTool(serviceManager, serviceName, toolName);\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n const errorResponse = this.createErrorResponse(\n \"SERVICE_OR_TOOL_NOT_FOUND\",\n errorMessage\n );\n return c.json(errorResponse, 404);\n }\n\n // 从缓存中获取工具信息\n const cacheManager = new MCPCacheManager();\n const cachedTools = await cacheManager.getAllCachedTools();\n\n // 查找对应的工具\n const fullToolName = `${serviceName}__${toolName}`;\n const cachedTool = cachedTools.find((tool) => tool.name === fullToolName);\n\n if (!cachedTool) {\n const errorResponse = this.createErrorResponse(\n \"TOOL_NOT_FOUND\",\n `在缓存中未找到工具: ${serviceName}/${toolName}`\n );\n return c.json(errorResponse, 404);\n }\n\n // 生成工具名称\n const finalToolName = customName || fullToolName;\n\n // 检查工具名称是否已存在\n const existingTools = configManager.getCustomMCPTools();\n const existingNames = new Set(existingTools.map((tool) => tool.name));\n\n if (existingNames.has(finalToolName)) {\n const errorResponse = this.createErrorResponse(\n \"TOOL_NAME_CONFLICT\",\n `工具名称 \"${finalToolName}\" 已存在,请使用不同的自定义名称`\n );\n return c.json(errorResponse, 409);\n }\n\n // 创建 CustomMCPTool 配置\n const tool: CustomMCPTool = {\n name: finalToolName,\n description:\n customDescription ||\n cachedTool.description ||\n `MCP 工具: ${serviceName}/${toolName}`,\n inputSchema: cachedTool.inputSchema || {},\n handler: {\n type: \"mcp\",\n config: {\n serviceName,\n toolName,\n },\n },\n stats: {\n usageCount: 0,\n lastUsedTime: dayjs().format(\"YYYY-MM-DD HH:mm:ss\"),\n },\n };\n\n // 添加工具到配置\n configManager.addCustomMCPTool(tool);\n\n // 对于 MCP 工具,需要在 mcpServerConfig 中同步启用\n this.logger.info(\n `检测到 MCP 工具添加,同步启用 mcpServerConfig 中的工具: ${serviceName}/${toolName}`\n );\n\n // 获取当前的服务工具配置\n const serverToolsConfig = configManager.getServerToolsConfig(serviceName);\n\n if (serverToolsConfig?.toolName) {\n // 更新配置,启用该工具\n serverToolsConfig[toolName].enable = true;\n\n // 保存更新后的配置\n configManager.updateServerToolsConfig(serviceName, serverToolsConfig);\n\n this.logger.info(\n `已同步启用 mcpServerConfig 中的工具: ${serviceName}/${toolName}`\n );\n }\n\n this.logger.info(`成功添加 MCP 工具: ${finalToolName}`);\n\n const responseData: AddToolResponse = {\n tool,\n toolName: finalToolName,\n toolType: ToolType.MCP,\n addedAt: dayjs().format(\"YYYY-MM-DD HH:mm:ss\"),\n };\n\n return c.json(\n this.createSuccessResponse(\n responseData,\n `MCP 工具 \"${finalToolName}\" 添加成功`\n )\n );\n }\n\n /**\n * 处理添加 Coze 工具\n */\n private async handleAddCozeTool(\n c: Context,\n data: CozeWorkflowData\n ): Promise<Response> {\n const { workflow, customName, customDescription, parameterConfig } = data;\n\n this.logger.info(`处理添加 Coze 工具: ${workflow.workflow_name}`);\n\n // 边界条件预检查\n const preCheckResult = this.performPreChecks(\n workflow,\n customName,\n customDescription\n );\n if (preCheckResult) {\n return this.createHonoResponse(\n c,\n preCheckResult.errorResponse,\n this.ensureValidStatusCode(preCheckResult.statusCode)\n );\n }\n\n // 转换工作流为工具配置\n const tool = this.convertWorkflowToTool(\n workflow,\n customName,\n customDescription,\n parameterConfig\n );\n\n // 添加工具到配置\n configManager.addCustomMCPTool(tool);\n\n this.logger.info(`成功添加 Coze 工具: ${tool.name}`);\n\n const responseData: AddToolResponse = {\n tool,\n toolName: tool.name,\n toolType: ToolType.COZE,\n addedAt: dayjs().format(\"YYYY-MM-DD HH:mm:ss\"),\n };\n\n return c.json(\n this.createSuccessResponse(\n responseData,\n `Coze 工具 \"${tool.name}\" 添加成功`\n )\n );\n }\n\n /**\n * 更新自定义 MCP 工具配置\n * PUT /api/tools/custom/:toolName\n */\n async updateCustomTool(c: Context): Promise<Response> {\n try {\n const toolName = c.req.param(\"toolName\");\n\n if (!toolName) {\n const errorResponse = this.createErrorResponse(\n \"INVALID_REQUEST\",\n \"工具名称不能为空\"\n );\n return c.json(errorResponse, 400);\n }\n\n this.logger.info(`处理更新自定义工具配置请求: ${toolName}`);\n\n const requestBody = await c.req.json();\n\n // 验证请求体\n if (!requestBody || typeof requestBody !== \"object\") {\n const errorResponse = this.createErrorResponse(\n \"INVALID_REQUEST\",\n \"请求体必须是有效对象\"\n );\n return c.json(errorResponse, 400);\n }\n\n // 检查是否为新格式的请求\n if (this.isNewFormatRequest(requestBody)) {\n // 新格式:支持多种工具类型\n return await this.handleNewFormatUpdateTool(\n c,\n toolName,\n requestBody as AddCustomToolRequest\n );\n }\n\n // 旧格式不支持更新操作\n const errorResponse = this.createErrorResponse(\n \"INVALID_REQUEST\",\n \"更新操作只支持新格式的请求\"\n );\n return c.json(errorResponse, 400);\n } catch (error) {\n this.logger.error(\"更新自定义工具配置失败:\", error);\n\n // 根据错误类型返回不同的HTTP状态码和错误信息\n const { statusCode, errorResponse } = this.handleUpdateToolError(error);\n return this.createHonoResponse(\n c,\n errorResponse,\n this.ensureValidStatusCode(statusCode)\n );\n }\n }\n\n /**\n * 处理新格式的更新工具请求\n */\n private async handleNewFormatUpdateTool(\n c: Context,\n toolName: string,\n request: AddCustomToolRequest\n ): Promise<Response> {\n const { type, data } = request;\n\n this.logger.info(`处理新格式工具更新请求,类型: ${type}`);\n\n // 验证工具类型\n if (!Object.values(ToolType).includes(type)) {\n const errorResponse = this.createErrorResponse(\n \"INVALID_TOOL_TYPE\",\n `不支持的工具类型: ${type}。支持的类型: ${Object.values(ToolType).join(\", \")}`\n );\n return c.json(errorResponse, 400);\n }\n\n // 根据工具类型分发处理\n switch (type) {\n case ToolType.COZE:\n return await this.handleUpdateCozeTool(\n c,\n toolName,\n data as CozeWorkflowData\n );\n\n case ToolType.MCP:\n case ToolType.HTTP:\n case ToolType.FUNCTION: {\n const errorResponse = this.createErrorResponse(\n \"TOOL_TYPE_NOT_IMPLEMENTED\",\n `工具类型 ${type} 暂不支持更新操作,目前仅支持 Coze 类型`\n );\n return c.json(errorResponse, 501);\n }\n\n default: {\n const errorResponse = this.createErrorResponse(\n \"UNKNOWN_TOOL_TYPE\",\n `未知的工具类型: ${type}`\n );\n return c.json(errorResponse, 400);\n }\n }\n }\n\n /**\n * 处理更新 Coze 工具\n */\n private async handleUpdateCozeTool(\n c: Context,\n toolName: string,\n data: CozeWorkflowData\n ): Promise<Response> {\n const { workflow, customName, customDescription, parameterConfig } = data;\n\n this.logger.info(`处理更新 Coze 工具: ${toolName}`);\n\n // 验证工具是否存在\n const existingTools = configManager.getCustomMCPTools();\n const existingTool = existingTools.find((tool) => tool.name === toolName);\n\n if (!existingTool) {\n const errorResponse = this.createErrorResponse(\n \"TOOL_NOT_FOUND\",\n `工具 \"${toolName}\" 不存在`\n );\n return c.json(errorResponse, 404);\n }\n\n // 验证是否为 Coze 工具\n if (\n existingTool.handler.type !== \"proxy\" ||\n existingTool.handler.platform !== \"coze\"\n ) {\n const errorResponse = this.createErrorResponse(\n \"INVALID_TOOL_TYPE\",\n `工具 \"${toolName}\" 不是 Coze 工作流工具,不支持参数配置更新`\n );\n return c.json(errorResponse, 400);\n }\n\n // 如果前端提供的 workflow 中没有 workflow_id,尝试从现有工具中获取\n if (!workflow.workflow_id && existingTool.handler?.config?.workflow_id) {\n workflow.workflow_id = existingTool.handler.config.workflow_id;\n }\n\n // 如果还没有 workflow_id,尝试从其他字段获取\n if (!workflow.workflow_id && workflow.app_id) {\n // 对于某些场景,app_id 可以作为替代标识\n // 但我们仍然需要 workflow_id 用于 Coze API 调用\n this.logger.warn(\n `工作流 ${toolName} 缺少 workflow_id,这可能会影响某些功能`\n );\n }\n\n // 验证工作流数据完整性\n this.validateWorkflowUpdateData(workflow);\n\n // 更新工具的 inputSchema\n const updatedInputSchema = this.generateInputSchema(\n workflow,\n parameterConfig\n );\n\n // 构建更新后的工具配置\n const updatedTool: CustomMCPTool = {\n ...existingTool,\n description: customDescription || existingTool.description,\n inputSchema: updatedInputSchema,\n };\n\n // 更新工具配置\n configManager.updateCustomMCPTool(toolName, updatedTool);\n\n this.logger.info(`成功更新 Coze 工具: ${toolName}`);\n\n const responseData = {\n tool: updatedTool,\n toolName: toolName,\n toolType: ToolType.COZE,\n updatedAt: dayjs().format(\"YYYY-MM-DD HH:mm:ss\"),\n };\n\n return c.json(\n this.createSuccessResponse(\n responseData,\n `Coze 工具 \"${toolName}\" 配置更新成功`\n )\n );\n }\n\n /**\n * 处理更新工具时的错误\n */\n private handleUpdateToolError(error: unknown): {\n statusCode: number;\n errorResponse: ToolCallResponse;\n } {\n const errorMessage =\n error instanceof Error ? error.message : \"更新自定义工具配置失败\";\n\n // 工具不存在错误 (404)\n if (errorMessage.includes(\"不存在\") || errorMessage.includes(\"未找到\")) {\n return {\n statusCode: 404,\n errorResponse: this.createErrorResponse(\n \"TOOL_NOT_FOUND\",\n `${errorMessage}。请检查工具名称是否正确`\n ),\n };\n }\n\n // 工具类型错误 (400)\n if (\n errorMessage.includes(\"工具类型\") ||\n errorMessage.includes(\"INVALID_TOOL_TYPE\")\n ) {\n return {\n statusCode: 400,\n errorResponse: this.createErrorResponse(\n \"INVALID_TOOL_TYPE\",\n errorMessage\n ),\n };\n }\n\n // 参数错误 (400)\n if (errorMessage.includes(\"不能为空\") || errorMessage.includes(\"无效\")) {\n return {\n statusCode: 400,\n errorResponse: this.createErrorResponse(\n \"INVALID_REQUEST\",\n `${errorMessage}。请提供有效的工具配置数据`\n ),\n };\n }\n\n // 配置错误 (422)\n if (errorMessage.includes(\"配置\") || errorMessage.includes(\"权限\")) {\n return {\n statusCode: 422,\n errorResponse: this.createErrorResponse(\n \"CONFIGURATION_ERROR\",\n `${errorMessage}。请检查配置文件权限和格式是否正确`\n ),\n };\n }\n\n // 未实现功能错误 (501)\n if (\n errorMessage.includes(\"未实现\") ||\n errorMessage.includes(\"NOT_IMPLEMENTED\")\n ) {\n return {\n statusCode: 501,\n errorResponse: this.createErrorResponse(\n \"TOOL_TYPE_NOT_IMPLEMENTED\",\n errorMessage\n ),\n };\n }\n\n // 系统错误 (500)\n return {\n statusCode: 500,\n errorResponse: this.createErrorResponse(\n \"UPDATE_CUSTOM_TOOL_ERROR\",\n `更新工具配置失败:${errorMessage}。请稍后重试,如问题持续存在请联系管理员`\n ),\n };\n }\n\n /**\n * 删除自定义 MCP 工具\n * DELETE /api/tools/custom/:toolName\n */\n async removeCustomTool(c: Context): Promise<Response> {\n try {\n const toolName = c.req.param(\"toolName\");\n\n if (!toolName) {\n const errorResponse = this.createErrorResponse(\n \"INVALID_REQUEST\",\n \"工具名称不能为空\"\n );\n return c.json(errorResponse, 400);\n }\n\n this.logger.info(`处理删除自定义工具请求: ${toolName}`);\n\n // 在删除之前,检查是否为 MCP 工具,如果是则需要在 mcpServerConfig 中同步禁用\n const existingTools = configManager.getCustomMCPTools();\n const toolToDelete = existingTools.find((tool) => tool.name === toolName);\n\n if (toolToDelete && toolToDelete.handler.type === \"mcp\") {\n // 这是 MCP 工具,需要在 mcpServerConfig 中同步禁用\n const mcpConfig = toolToDelete.handler.config;\n if (mcpConfig.serviceName && mcpConfig.toolName) {\n this.logger.info(\n `检测到 MCP 工具删除,同步禁用 mcpServerConfig 中的工具: ${mcpConfig.serviceName}/${mcpConfig.toolName}`\n );\n\n // 获取当前的服务工具配置\n const serverToolsConfig = configManager.getServerToolsConfig(\n mcpConfig.serviceName\n );\n\n if (serverToolsConfig?.[mcpConfig.toolName]) {\n // 更新配置,禁用该工具\n serverToolsConfig[mcpConfig.toolName].enable = false;\n\n // 保存更新后的配置\n configManager.updateServerToolsConfig(\n mcpConfig.serviceName,\n serverToolsConfig\n );\n\n this.logger.info(\n `已同步禁用 mcpServerConfig 中的工具: ${mcpConfig.serviceName}/${mcpConfig.toolName}`\n );\n }\n }\n }\n\n // 从配置中删除工具\n configManager.removeCustomMCPTool(toolName);\n\n this.logger.info(`成功删除自定义工具: ${toolName}`);\n\n return c.json(\n this.createSuccessResponse(null, `工具 \"${toolName}\" 删除成功`)\n );\n } catch (error) {\n this.logger.error(\"删除自定义工具失败:\", error);\n\n // 根据错误类型返回不同的HTTP状态码和错误信息\n const { statusCode, errorResponse } = this.handleRemoveToolError(error);\n return this.createHonoResponse(\n c,\n errorResponse,\n this.ensureValidStatusCode(statusCode)\n );\n }\n }\n\n /**\n * 将扣子工作流转换为自定义 MCP 工具\n */\n private convertWorkflowToTool(\n workflow: CozeWorkflow,\n customName?: string,\n customDescription?: string,\n parameterConfig?: WorkflowParameterConfig\n ): CustomMCPTool {\n // 验证工作流数据完整性\n this.validateWorkflowData(workflow);\n\n // 生成工具名称(处理冲突)\n const baseName =\n customName || this.sanitizeToolName(workflow.workflow_name);\n const toolName = this.resolveToolNameConflict(baseName);\n\n // 生成工具描述\n const description = this.generateToolDescription(\n workflow,\n customDescription\n );\n\n // 生成输入参数结构\n const inputSchema = this.generateInputSchema(workflow, parameterConfig);\n\n // 配置 HTTP 处理器\n const handler = this.createHttpHandler(workflow);\n\n // 创建工具配置\n const tool: CustomMCPTool = {\n name: toolName,\n description,\n inputSchema,\n handler,\n };\n\n // 验证生成的工具配置\n this.validateGeneratedTool(tool);\n\n return tool;\n }\n\n /**\n * 规范化工具名称\n */\n private sanitizeToolName(name: string): string {\n if (!name || typeof name !== \"string\") {\n return \"coze_workflow_unnamed\";\n }\n\n // 去除首尾空格\n let sanitized = name.trim();\n\n if (!sanitized) {\n return \"coze_workflow_empty\";\n }\n\n // 将中文转换为拼音或英文描述(简化处理)\n sanitized = this.convertChineseToEnglish(sanitized);\n\n // 移除特殊字符,只保留字母、数字和下划线\n sanitized = sanitized.replace(/[^a-zA-Z0-9_]/g, \"_\");\n\n // 移除连续的下划线\n sanitized = sanitized.replace(/_+/g, \"_\");\n\n // 移除开头和结尾的下划线\n sanitized = sanitized.replace(/^_+|_+$/g, \"\");\n\n // 确保以字母开头\n if (!/^[a-zA-Z]/.test(sanitized)) {\n sanitized = `coze_workflow_${sanitized}`;\n }\n\n // 限制长度(保留足够空间给数字后缀)\n if (sanitized.length > 45) {\n sanitized = sanitized.substring(0, 45);\n }\n\n // 确保不为空\n if (!sanitized) {\n sanitized = \"coze_workflow_tool\";\n }\n\n return sanitized;\n }\n\n /**\n * 简单的中文到英文转换(可以扩展为更复杂的拼音转换)\n */\n private convertChineseToEnglish(text: string): string {\n // 常见中文词汇的映射\n const chineseToEnglishMap: Record<string, string> = {\n 工作流: \"workflow\",\n 测试: \"test\",\n 数据: \"data\",\n 处理: \"process\",\n 分析: \"analysis\",\n 生成: \"generate\",\n 查询: \"query\",\n 搜索: \"search\",\n 转换: \"convert\",\n 计算: \"calculate\",\n 统计: \"statistics\",\n 报告: \"report\",\n 文档: \"document\",\n 图片: \"image\",\n 视频: \"video\",\n 音频: \"audio\",\n 文本: \"text\",\n 翻译: \"translate\",\n 识别: \"recognize\",\n 检测: \"detect\",\n 监控: \"monitor\",\n 管理: \"manage\",\n 配置: \"config\",\n 设置: \"setting\",\n 用户: \"user\",\n 系统: \"system\",\n 服务: \"service\",\n 接口: \"api\",\n 数据库: \"database\",\n 网络: \"network\",\n 安全: \"security\",\n 备份: \"backup\",\n 恢复: \"restore\",\n 同步: \"sync\",\n 导入: \"import\",\n 导出: \"export\",\n 上传: \"upload\",\n 下载: \"download\",\n };\n\n let result = text;\n\n // 替换常见中文词汇\n for (const [chinese, english] of Object.entries(chineseToEnglishMap)) {\n result = result.replace(new RegExp(chinese, \"g\"), english);\n }\n\n // 如果还有中文字符,用拼音前缀替代\n if (/[\\u4e00-\\u9fa5]/.test(result)) {\n result = `chinese_${result}`;\n }\n\n return result;\n }\n\n /**\n * 验证工作流数据完整性\n */\n private validateWorkflowData(workflow: CozeWorkflow): void {\n if (!workflow) {\n throw new Error(\"工作流数据不能为空\");\n }\n\n // 验证必需字段\n this.validateRequiredFields(workflow);\n\n // 验证字段格式\n this.validateFieldFormats(workflow);\n\n // 验证字段长度\n this.validateFieldLengths(workflow);\n\n // 验证业务逻辑\n this.validateBusinessLogic(workflow);\n }\n\n /**\n * 验证工作流更新数据完整性\n * 用于更新场景,只验证关键字段\n */\n private validateWorkflowUpdateData(workflow: Partial<CozeWorkflow>): void {\n if (!workflow) {\n throw new Error(\"工作流数据不能为空\");\n }\n\n // 对于更新操作,我们采用更灵活的验证策略\n // 因为这可能是参数配置更新,而不是工作流本身更新\n\n // 如果提供了 workflow_id,验证其格式\n if (workflow.workflow_id) {\n if (\n typeof workflow.workflow_id !== \"string\" ||\n workflow.workflow_id.trim() === \"\"\n ) {\n throw new Error(\"工作流ID必须是非空字符串\");\n }\n\n // 验证工作流ID格式(数字字符串)\n if (!/^\\d+$/.test(workflow.workflow_id)) {\n throw new Error(\"工作流ID格式无效,应为数字字符串\");\n }\n }\n\n // 如果存在 workflow_name,验证其格式\n if (workflow.workflow_name) {\n if (\n typeof workflow.workflow_name !== \"string\" ||\n workflow.workflow_name.trim() === \"\"\n ) {\n throw new Error(\"工作流名称必须是非空字符串\");\n }\n\n // 验证工作流名称长度\n if (workflow.workflow_name.length > 100) {\n throw new Error(\"工作流名称过长,不能超过100个字符\");\n }\n }\n\n // 如果存在 app_id,验证其格式\n if (workflow.app_id) {\n if (\n typeof workflow.app_id !== \"string\" ||\n workflow.app_id.trim() === \"\"\n ) {\n throw new Error(\"应用ID必须是非空字符串\");\n }\n\n // 验证应用ID格式\n if (!/^[a-zA-Z0-9_-]+$/.test(workflow.app_id)) {\n throw new Error(\"应用ID格式无效,只能包含字母、数字、下划线和连字符\");\n }\n\n // 验证应用ID长度\n if (workflow.app_id.length > 50) {\n throw new Error(\"应用ID过长,不能超过50个字符\");\n }\n }\n\n // 对于参数配置更新,workflow_id 可能不是必需的\n // 因为实际的工作流ID已经存储在工具配置中\n // 我们主要验证存在字段的格式,而不是强制要求所有字段都存在\n }\n\n /**\n * 验证必需字段\n */\n private validateRequiredFields(workflow: CozeWorkflow): void {\n const requiredFields = [\n { field: \"workflow_id\", name: \"工作流ID\" },\n { field: \"workflow_name\", name: \"工作流名称\" },\n { field: \"app_id\", name: \"应用ID\" },\n ];\n\n for (const { field, name } of requiredFields) {\n const value = workflow[field as keyof CozeWorkflow];\n if (!value || typeof value !== \"string\" || value.trim() === \"\") {\n throw new Error(`${name}不能为空且必须是非空字符串`);\n }\n }\n }\n\n /**\n * 验证字段格式\n */\n private validateFieldFormats(workflow: CozeWorkflow): void {\n // 验证工作流ID格式(数字字符串)\n if (!/^\\d+$/.test(workflow.workflow_id)) {\n throw new Error(\"工作流ID格式无效,应为数字字符串\");\n }\n\n // 验证应用ID格式\n if (!/^[a-zA-Z0-9_-]+$/.test(workflow.app_id)) {\n throw new Error(\"应用ID格式无效,只能包含字母、数字、下划线和连字符\");\n }\n\n // 验证图标URL格式(如果存在)\n if (workflow.icon_url?.trim()) {\n try {\n new URL(workflow.icon_url);\n } catch {\n throw new Error(\"图标URL格式无效\");\n }\n }\n\n // 验证时间戳格式\n if (\n workflow.created_at &&\n (!Number.isInteger(workflow.created_at) || workflow.created_at <= 0)\n ) {\n throw new Error(\"创建时间格式无效,应为正整数时间戳\");\n }\n\n if (\n workflow.updated_at &&\n (!Number.isInteger(workflow.updated_at) || workflow.updated_at <= 0)\n ) {\n throw new Error(\"更新时间格式无效,应为正整数时间戳\");\n }\n }\n\n /**\n * 验证字段长度\n */\n private validateFieldLengths(workflow: CozeWorkflow): void {\n const lengthLimits = [\n { field: \"workflow_name\", name: \"工作流名称\", max: 100 },\n { field: \"description\", name: \"工作流描述\", max: 500 },\n { field: \"app_id\", name: \"应用ID\", max: 50 },\n ];\n\n for (const { field, name, max } of lengthLimits) {\n const value = workflow[field as keyof CozeWorkflow] as string;\n if (value && value.length > max) {\n throw new Error(`${name}过长,不能超过${max}个字符`);\n }\n }\n }\n\n /**\n * 验证业务逻辑\n */\n private validateBusinessLogic(workflow: CozeWorkflow): void {\n // 验证创建者信息\n if (workflow.creator) {\n if (!workflow.creator.id || typeof workflow.creator.id !== \"string\") {\n throw new Error(\"创建者ID不能为空且必须是字符串\");\n }\n if (!workflow.creator.name || typeof workflow.creator.name !== \"string\") {\n throw new Error(\"创建者名称不能为空且必须是字符串\");\n }\n }\n\n // 验证时间逻辑\n if (\n workflow.created_at &&\n workflow.updated_at &&\n workflow.updated_at < workflow.created_at\n ) {\n throw new Error(\"更新时间不能早于创建时间\");\n }\n\n // 验证工作流名称不能包含敏感词\n const sensitiveWords = [\n \"admin\",\n \"root\",\n \"system\",\n \"config\",\n \"password\",\n \"token\",\n ];\n const lowerName = workflow.workflow_name.toLowerCase();\n for (const word of sensitiveWords) {\n if (lowerName.includes(word)) {\n throw new Error(`工作流名称不能包含敏感词: ${word}`);\n }\n }\n }\n\n /**\n * 解决工具名称冲突\n */\n private resolveToolNameConflict(baseName: string): string {\n const existingTools = configManager.getCustomMCPTools();\n const existingNames = new Set(existingTools.map((tool) => tool.name));\n\n let finalName = baseName;\n let counter = 1;\n\n // 如果名称已存在,添加数字后缀\n while (existingNames.has(finalName)) {\n finalName = `${baseName}_${counter}`;\n counter++;\n\n // 防止无限循环\n if (counter > 999) {\n throw new Error(`无法为工具生成唯一名称,基础名称: ${baseName}`);\n }\n }\n\n return finalName;\n }\n\n /**\n * 生成工具描述\n */\n private generateToolDescription(\n workflow: CozeWorkflow,\n customDescription?: string\n ): string {\n if (customDescription) {\n return customDescription;\n }\n\n if (workflow.description?.trim()) {\n return workflow.description.trim();\n }\n\n // 生成默认描述\n return `扣子工作流工具: ${workflow.workflow_name}`;\n }\n\n /**\n * 创建HTTP处理器配置\n */\n private createHttpHandler(workflow: CozeWorkflow): ProxyHandlerConfig {\n // 验证扣子API配置\n this.validateCozeApiConfig();\n\n return {\n type: \"proxy\",\n platform: \"coze\",\n config: {\n workflow_id: workflow.workflow_id,\n },\n };\n }\n\n /**\n * 验证扣子API配置\n */\n private validateCozeApiConfig(): void {\n // 检查是否配置了扣子token\n const cozeConfig = configManager.getCozePlatformConfig();\n if (!cozeConfig || !cozeConfig.token) {\n throw new Error(\n \"未配置扣子API Token,请先在配置中设置 platforms.coze.token\"\n );\n }\n }\n\n /**\n * 验证生成的工具配置\n */\n private validateGeneratedTool(tool: CustomMCPTool): void {\n // 基础结构验证\n this.validateToolStructure(tool);\n\n // 使用configManager的验证方法\n if (!configManager.validateCustomMCPTools([tool])) {\n throw new Error(\"生成的工具配置验证失败,请检查工具定义\");\n }\n\n // JSON Schema验证\n this.validateJsonSchema(tool.inputSchema);\n\n // HTTP处理器验证\n if (tool.handler) {\n this.validateProxyHandler(tool.handler as ProxyHandlerConfig);\n }\n }\n\n /**\n * 验证工具基础结构\n */\n private validateToolStructure(tool: CustomMCPTool): void {\n if (!tool || typeof tool !== \"object\") {\n throw new Error(\"工具配置必须是有效对象\");\n }\n\n // 验证必需字段\n const requiredFields = [\"name\", \"description\", \"inputSchema\", \"handler\"];\n for (const field of requiredFields) {\n if (!(field in tool) || tool[field as keyof CustomMCPTool] == null) {\n throw new Error(`工具配置缺少必需字段: ${field}`);\n }\n }\n\n // 验证字段类型\n if (typeof tool.name !== \"string\" || tool.name.trim() === \"\") {\n throw new Error(\"工具名称必须是非空字符串\");\n }\n\n if (\n typeof tool.description !== \"string\" ||\n tool.description.trim() === \"\"\n ) {\n throw new Error(\"工具描述必须是非空字符串\");\n }\n\n if (typeof tool.inputSchema !== \"object\") {\n throw new Error(\"输入参数结构必须是对象\");\n }\n\n if (typeof tool.handler !== \"object\") {\n throw new Error(\"处理器配置必须是对象\");\n }\n }\n\n /**\n * 验证HTTP处理器配置\n */\n private validateProxyHandler(handler: ProxyHandlerConfig): void {\n if (!handler || typeof handler !== \"object\") {\n throw new Error(\"HTTP处理器配置不能为空\");\n }\n\n // 验证处理器类型\n if (handler.type !== \"proxy\") {\n throw new Error(\"处理器类型必须是'proxy'\");\n }\n\n if (handler.platform === \"coze\") {\n if (!handler.config.workflow_id) {\n throw new Error(\"Coze处理器必须包含有效的workflow_id\");\n }\n } else {\n throw new Error(\"不支持的工作流平台\");\n }\n }\n\n /**\n * 验证认证配置\n */\n private validateAuthConfig(auth: { type: string; token?: string }): void {\n if (!auth || typeof auth !== \"object\") {\n throw new Error(\"认证配置必须是对象\");\n }\n\n if (!auth.type || typeof auth.type !== \"string\") {\n throw new Error(\"认证类型不能为空\");\n }\n\n const validAuthTypes = [\"bearer\", \"basic\", \"api_key\"];\n if (!validAuthTypes.includes(auth.type)) {\n throw new Error(`认证类型必须是以下之一: ${validAuthTypes.join(\", \")}`);\n }\n\n // 验证token格式\n if (auth.type === \"bearer\") {\n if (!auth.token || typeof auth.token !== \"string\") {\n throw new Error(\"Bearer认证必须包含有效的token\");\n }\n\n // 验证token格式(应该是环境变量引用或实际token)\n if (\n !auth.token.startsWith(\"${\") &&\n !auth.token.match(/^[a-zA-Z0-9_-]+$/)\n ) {\n throw new Error(\"Bearer token格式无效\");\n }\n }\n }\n\n /**\n * 验证请求体模板\n */\n private validateBodyTemplate(bodyTemplate: string): void {\n if (typeof bodyTemplate !== \"string\") {\n throw new Error(\"请求体模板必须是字符串\");\n }\n\n try {\n JSON.parse(bodyTemplate);\n } catch {\n throw new Error(\"请求体模板必须是有效的JSON格式\");\n }\n\n // 验证模板变量格式\n const templateVars = bodyTemplate.match(/\\{\\{[^}]+\\}\\}/g);\n if (templateVars) {\n for (const templateVar of templateVars) {\n const varName = templateVar.slice(2, -2).trim();\n if (!varName || !/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(varName)) {\n throw new Error(`模板变量格式无效: ${templateVar}`);\n }\n }\n }\n }\n\n /**\n * 验证JSON Schema格式\n */\n private validateJsonSchema(schema: JSONSchema): void {\n if (!schema || typeof schema !== \"object\") {\n throw new Error(\"输入参数结构必须是有效的对象\");\n }\n\n if (!schema.type || schema.type !== \"object\") {\n throw new Error(\"输入参数结构的type必须是'object'\");\n }\n\n if (!schema.properties || typeof schema.properties !== \"object\") {\n throw new Error(\"输入参数结构必须包含properties字段\");\n }\n\n // 验证required字段\n if (schema.required && !Array.isArray(schema.required)) {\n throw new Error(\"输入参数结构的required字段必须是数组\");\n }\n }\n\n /**\n * 生成输入参数结构\n */\n private generateInputSchema(\n workflow: CozeWorkflow,\n parameterConfig?: WorkflowParameterConfig\n ): JSONSchema {\n // 如果提供了参数配置,使用参数配置生成schema\n if (parameterConfig && parameterConfig.parameters.length > 0) {\n return this.generateInputSchemaFromConfig(parameterConfig);\n }\n\n // 否则使用默认的基础参数结构\n const baseSchema = {\n type: \"object\",\n properties: {\n input: {\n type: \"string\",\n description: \"输入内容\",\n },\n },\n required: [\"input\"],\n additionalProperties: false,\n };\n\n return baseSchema;\n }\n\n /**\n * 根据参数配置生成输入参数结构\n */\n private generateInputSchemaFromConfig(\n parameterConfig: WorkflowParameterConfig\n ): JSONSchema {\n const properties: Record<string, unknown> = {};\n const required: string[] = [];\n\n for (const param of parameterConfig.parameters) {\n properties[param.fieldName] = {\n type: param.type,\n description: param.description,\n };\n\n if (param.required) {\n required.push(param.fieldName);\n }\n }\n\n return {\n type: \"object\",\n properties,\n required: required.length > 0 ? required : undefined,\n additionalProperties: false,\n };\n }\n\n /**\n * 处理添加工具时的错误\n */\n private handleAddToolError(error: unknown): {\n statusCode: number;\n errorResponse: ToolCallResponse;\n } {\n const errorMessage =\n error instanceof Error ? error.message : \"添加自定义工具失败\";\n\n // 工具类型错误 (400)\n if (\n errorMessage.includes(\"工具类型\") ||\n errorMessage.includes(\"TOOL_TYPE\")\n ) {\n return {\n statusCode: 400,\n errorResponse: this.createErrorResponse(\n \"INVALID_TOOL_TYPE\",\n errorMessage\n ),\n };\n }\n\n // 缺少必需字段错误 (400)\n if (\n errorMessage.includes(\"必需字段\") ||\n errorMessage.includes(\"MISSING_REQUIRED_FIELD\")\n ) {\n return {\n statusCode: 400,\n errorResponse: this.createErrorResponse(\n \"MISSING_REQUIRED_FIELD\",\n errorMessage\n ),\n };\n }\n\n // 工具或服务不存在错误 (404)\n if (\n errorMessage.includes(\"不存在\") ||\n errorMessage.includes(\"NOT_FOUND\") ||\n errorMessage.includes(\"未找到\")\n ) {\n return {\n statusCode: 404,\n errorResponse: this.createErrorResponse(\n \"SERVICE_OR_TOOL_NOT_FOUND\",\n errorMessage\n ),\n };\n }\n\n // 服务未初始化错误 (503)\n if (\n errorMessage.includes(\"未初始化\") ||\n errorMessage.includes(\"SERVICE_NOT_INITIALIZED\")\n ) {\n return {\n statusCode: 503,\n errorResponse: this.createErrorResponse(\n \"SERVICE_NOT_INITIALIZED\",\n errorMessage\n ),\n };\n }\n\n // 工具名称冲突错误 (409)\n if (\n errorMessage.includes(\"已存在\") ||\n errorMessage.includes(\"冲突\") ||\n errorMessage.includes(\"TOOL_NAME_CONFLICT\")\n ) {\n return {\n statusCode: 409,\n errorResponse: this.createErrorResponse(\n \"TOOL_NAME_CONFLICT\",\n `${errorMessage}。建议:1) 使用自定义名称;2) 删除现有同名工具后重试`\n ),\n };\n }\n\n // 数据验证错误 (400)\n if (this.isValidationError(errorMessage)) {\n return {\n statusCode: 400,\n errorResponse: this.createErrorResponse(\n \"VALIDATION_ERROR\",\n this.formatValidationError(errorMessage)\n ),\n };\n }\n\n // 配置错误 (422)\n if (\n errorMessage.includes(\"配置\") ||\n errorMessage.includes(\"token\") ||\n errorMessage.includes(\"API\") ||\n errorMessage.includes(\"CONFIGURATION_ERROR\")\n ) {\n return {\n statusCode: 422,\n errorResponse: this.createErrorResponse(\n \"CONFIGURATION_ERROR\",\n `${errorMessage}。请检查:1) 相关配置是否正确;2) 网络连接是否正常;3) 配置文件权限是否正确`\n ),\n };\n }\n\n // 资源限制错误 (429)\n if (\n errorMessage.includes(\"资源限制\") ||\n errorMessage.includes(\"RESOURCE_LIMIT_EXCEEDED\")\n ) {\n return {\n statusCode: 429,\n errorResponse: this.createErrorResponse(\n \"RESOURCE_LIMIT_EXCEEDED\",\n errorMessage\n ),\n };\n }\n\n // 未实现功能错误 (501)\n if (\n errorMessage.includes(\"未实现\") ||\n errorMessage.includes(\"NOT_IMPLEMENTED\")\n ) {\n return {\n statusCode: 501,\n errorResponse: this.createErrorResponse(\n \"TOOL_TYPE_NOT_IMPLEMENTED\",\n errorMessage\n ),\n };\n }\n\n // 系统错误 (500)\n return {\n statusCode: 500,\n errorResponse: this.createErrorResponse(\n \"ADD_CUSTOM_TOOL_ERROR\",\n `添加工具失败:${errorMessage}。请稍后重试,如问题持续存在请联系管理员`\n ),\n };\n }\n\n /**\n * 处理删除工具时的错误\n */\n private handleRemoveToolError(error: unknown): {\n statusCode: number;\n errorResponse: ToolCallResponse;\n } {\n const errorMessage =\n error instanceof Error ? error.message : \"删除自定义工具失败\";\n\n // 工具不存在错误 (404)\n if (errorMessage.includes(\"不存在\") || errorMessage.includes(\"未找到\")) {\n return {\n statusCode: 404,\n errorResponse: this.createErrorResponse(\n \"TOOL_NOT_FOUND\",\n `${errorMessage}。请检查工具名称是否正确,或刷新页面查看最新的工具列表`\n ),\n };\n }\n\n // 参数错误 (400)\n if (errorMessage.includes(\"不能为空\") || errorMessage.includes(\"无效\")) {\n return {\n statusCode: 400,\n errorResponse: this.createErrorResponse(\n \"INVALID_REQUEST\",\n `${errorMessage}。请提供有效的工具名称`\n ),\n };\n }\n\n // 配置错误 (422)\n if (errorMessage.includes(\"配置\") || errorMessage.includes(\"权限\")) {\n return {\n statusCode: 422,\n errorResponse: this.createErrorResponse(\n \"CONFIGURATION_ERROR\",\n `${errorMessage}。请检查配置文件权限和格式是否正确`\n ),\n };\n }\n\n // 系统错误 (500)\n return {\n statusCode: 500,\n errorResponse: this.createErrorResponse(\n \"REMOVE_CUSTOM_TOOL_ERROR\",\n `删除工具失败:${errorMessage}。请稍后重试,如问题持续存在请联系管理员`\n ),\n };\n }\n\n /**\n * 判断是否为数据验证错误\n */\n private isValidationError(errorMessage: string): boolean {\n const validationKeywords = [\n \"不能为空\",\n \"必须是\",\n \"格式无效\",\n \"过长\",\n \"过短\",\n \"验证失败\",\n \"无效\",\n \"不符合\",\n \"超过\",\n \"少于\",\n \"敏感词\",\n \"时间\",\n \"URL\",\n ];\n\n return validationKeywords.some((keyword) => errorMessage.includes(keyword));\n }\n\n /**\n * 格式化验证错误信息\n */\n private formatValidationError(errorMessage: string): string {\n // 为常见的验证错误提供更友好的提示\n const errorMappings: Record<string, string> = {\n 工作流ID不能为空: \"请提供有效的工作流ID\",\n 工作流名称不能为空: \"请提供有效的工作流名称\",\n 应用ID不能为空: \"请提供有效的应用ID\",\n 工作流ID格式无效: \"工作流ID应为数字格式,请检查工作流配置\",\n 应用ID格式无效: \"应用ID只能包含字母、数字、下划线和连字符\",\n 工作流名称过长: \"工作流名称不能超过100个字符,请缩短名称\",\n 工作流描述过长: \"工作流描述不能超过500个字符,请缩短描述\",\n 图标URL格式无效: \"请提供有效的图标URL地址\",\n 更新时间不能早于创建时间: \"工作流的时间信息有误,请检查工作流数据\",\n 敏感词: \"工作流名称包含敏感词汇,请修改后重试\",\n };\n\n // 查找匹配的错误映射\n for (const [key, value] of Object.entries(errorMappings)) {\n if (errorMessage.includes(key)) {\n return value;\n }\n }\n\n return errorMessage;\n }\n\n /**\n * 执行边界条件预检查\n */\n private performPreChecks(\n workflow: unknown,\n customName?: string,\n customDescription?: string\n ): { statusCode: number; errorResponse: ToolCallResponse } | null {\n // 检查基础参数\n const basicCheckResult = this.checkBasicParameters(\n workflow,\n customName,\n customDescription\n );\n if (basicCheckResult) return basicCheckResult;\n\n // 检查系统状态\n const systemCheckResult = this.checkSystemStatus();\n if (systemCheckResult) return systemCheckResult;\n\n // 检查资源限制\n const resourceCheckResult = this.checkResourceLimits();\n if (resourceCheckResult) return resourceCheckResult;\n\n return null; // 所有检查通过\n }\n\n /**\n * 检查基础参数\n */\n private checkBasicParameters(\n workflow: unknown,\n customName?: string,\n customDescription?: string\n ): { statusCode: number; errorResponse: ToolCallResponse } | null {\n // 检查workflow参数\n if (!workflow) {\n return {\n statusCode: 400,\n errorResponse: this.createErrorResponse(\n \"INVALID_REQUEST\",\n \"请求体中缺少 workflow 参数\"\n ),\n };\n }\n\n if (typeof workflow !== \"object\") {\n return {\n statusCode: 400,\n errorResponse: this.createErrorResponse(\n \"INVALID_REQUEST\",\n \"workflow 参数必须是对象类型\"\n ),\n };\n }\n\n // 类型守卫:确保 workflow 不是数组\n if (!Array.isArray(workflow)) {\n const workflowObj = workflow as Record<string, unknown>;\n\n // 检查必需字段\n if (\n !workflowObj.workflow_id ||\n typeof workflowObj.workflow_id !== \"string\" ||\n !workflowObj.workflow_id.trim()\n ) {\n return {\n statusCode: 400,\n errorResponse: this.createErrorResponse(\n \"INVALID_REQUEST\",\n \"workflow_id 不能为空且必须是非空字符串\"\n ),\n };\n }\n\n if (\n !workflowObj.workflow_name ||\n typeof workflowObj.workflow_name !== \"string\" ||\n !workflowObj.workflow_name.trim()\n ) {\n return {\n statusCode: 400,\n errorResponse: this.createErrorResponse(\n \"INVALID_REQUEST\",\n \"workflow_name 不能为空且必须是非空字符串\"\n ),\n };\n }\n }\n\n // 检查自定义参数\n if (customName !== undefined) {\n if (typeof customName !== \"string\") {\n return {\n statusCode: 400,\n errorResponse: this.createErrorResponse(\n \"INVALID_REQUEST\",\n \"customName 必须是字符串类型\"\n ),\n };\n }\n\n if (customName.trim() === \"\") {\n return {\n statusCode: 400,\n errorResponse: this.createErrorResponse(\n \"INVALID_REQUEST\",\n \"customName 不能为空字符串\"\n ),\n };\n }\n\n if (customName.length > 50) {\n return {\n statusCode: 400,\n errorResponse: this.createErrorResponse(\n \"INVALID_REQUEST\",\n \"customName 长度不能超过50个字符\"\n ),\n };\n }\n }\n\n if (customDescription !== undefined) {\n if (typeof customDescription !== \"string\") {\n return {\n statusCode: 400,\n errorResponse: this.createErrorResponse(\n \"INVALID_REQUEST\",\n \"customDescription 必须是字符串类型\"\n ),\n };\n }\n\n if (customDescription.length > 200) {\n return {\n statusCode: 400,\n errorResponse: this.createErrorResponse(\n \"INVALID_REQUEST\",\n \"customDescription 长度不能超过200个字符\"\n ),\n };\n }\n }\n\n return null;\n }\n\n /**\n * 检查系统状态\n */\n private checkSystemStatus(): {\n statusCode: number;\n errorResponse: ToolCallResponse;\n } | null {\n // 检查扣子API配置\n try {\n const cozeConfig = configManager.getCozePlatformConfig();\n if (!cozeConfig || !cozeConfig.token) {\n return {\n statusCode: 422,\n errorResponse: this.createErrorResponse(\n \"CONFIGURATION_ERROR\",\n \"未配置扣子API Token。请在系统设置中配置 platforms.coze.token\"\n ),\n };\n }\n\n // 检查token格式\n if (\n typeof cozeConfig.token !== \"string\" ||\n cozeConfig.token.trim() === \"\"\n ) {\n return {\n statusCode: 422,\n errorResponse: this.createErrorResponse(\n \"CONFIGURATION_ERROR\",\n \"扣子API Token格式无效。请检查配置中的 platforms.coze.token\"\n ),\n };\n }\n } catch (error) {\n return {\n statusCode: 500,\n errorResponse: this.createErrorResponse(\n \"SYSTEM_ERROR\",\n \"系统配置检查失败,请稍后重试\"\n ),\n };\n }\n\n return null;\n }\n\n /**\n * 检查资源限制\n */\n private checkResourceLimits(): {\n statusCode: number;\n errorResponse: ToolCallResponse;\n } | null {\n try {\n // 检查现有工具数量限制\n const existingTools = configManager.getCustomMCPTools();\n const maxTools = 100; // 设置最大工具数量限制\n\n if (existingTools.length >= maxTools) {\n return {\n statusCode: 429,\n errorResponse: this.createErrorResponse(\n \"RESOURCE_LIMIT_EXCEEDED\",\n `已达到最大工具数量限制 (${maxTools})。请删除一些不需要的工具后重试`\n ),\n };\n }\n\n // 检查配置文件大小(简单估算)\n const configSizeEstimate = JSON.stringify(existingTools).length;\n const maxConfigSize = 1024 * 1024; // 1MB限制\n\n if (configSizeEstimate > maxConfigSize) {\n return {\n statusCode: 413,\n errorResponse: this.createErrorResponse(\n \"PAYLOAD_TOO_LARGE\",\n \"配置文件过大。请删除一些不需要的工具以释放空间\"\n ),\n };\n }\n } catch (error) {\n // 资源检查失败不应阻止操作,只记录警告\n this.logger.warn(\"资源限制检查失败:\", error);\n }\n\n return null;\n }\n}\n","/**\n * 工具调用日志 API 处理器\n * 负责处理工具调用日志相关的 HTTP API 请求\n */\n\nimport type { ToolCallQuery } from \"@/lib/mcp/log.js\";\nimport { ToolCallLogService } from \"@/lib/mcp/log.js\";\nimport { PAGINATION_CONSTANTS } from \"@cli/Constants.js\";\nimport { logger } from \"@root/Logger.js\";\nimport type { Context } from \"hono\";\nimport { z } from \"zod\";\n\n/**\n * 统一响应接口\n */\ninterface ApiResponse<T = unknown> {\n success: boolean;\n data?: T;\n error?: {\n code: string;\n message: string;\n details?: unknown;\n };\n}\n\n/**\n * Zod 验证错误详细信息\n */\ninterface ValidationErrorDetail {\n field: string;\n message: string;\n}\n\n/**\n * 工具调用查询参数 Zod Schema\n */\nconst ToolCallQuerySchema = z\n .object({\n limit: z\n .string()\n .optional()\n .transform((val) => (val ? Number.parseInt(val, 10) : undefined))\n .refine(\n (val) =>\n val === undefined ||\n (val >= 1 && val <= PAGINATION_CONSTANTS.MAX_LIMIT),\n {\n message: `limit 参数必须是 1-${PAGINATION_CONSTANTS.MAX_LIMIT} 之间的数字`,\n }\n ),\n offset: z\n .string()\n .optional()\n .transform((val) => (val ? Number.parseInt(val, 10) : undefined))\n .refine((val) => val === undefined || val >= 0, {\n message: \"offset 参数必须是非负数\",\n }),\n toolName: z.string().optional(),\n serverName: z.string().optional(),\n success: z\n .string()\n .optional()\n .transform((val) => (val ? val.toLowerCase() === \"true\" : undefined)),\n startDate: z\n .string()\n .optional()\n .refine(\n (val) => {\n if (!val) return true;\n const date = Date.parse(val);\n return !Number.isNaN(date);\n },\n {\n message: \"startDate 参数格式无效\",\n }\n ),\n endDate: z\n .string()\n .optional()\n .refine(\n (val) => {\n if (!val) return true;\n const date = Date.parse(val);\n return !Number.isNaN(date);\n },\n {\n message: \"endDate 参数格式无效\",\n }\n ),\n })\n .refine(\n (data) => {\n if (!data.startDate || !data.endDate) return true;\n return new Date(data.startDate) <= new Date(data.endDate);\n },\n {\n message: \"startDate 不能晚于 endDate\",\n path: [\"startDate\"],\n }\n );\n\n/**\n * 工具调用日志 API 处理器\n */\nexport class ToolCallLogApiHandler {\n private toolCallLogService: ToolCallLogService;\n\n constructor() {\n this.toolCallLogService = new ToolCallLogService();\n }\n\n /**\n * 创建成功响应\n */\n private createSuccessResponse<T>(data?: T): Response {\n const response: ApiResponse<T> = {\n success: true,\n data,\n };\n return Response.json(response);\n }\n\n /**\n * 创建错误响应\n */\n private createErrorResponse(\n code: string,\n message: string,\n details?: unknown\n ): Response {\n const response: ApiResponse = {\n success: false,\n error: {\n code,\n message,\n details,\n },\n };\n return Response.json(response, { status: this.getHttpStatusCode(code) });\n }\n\n /**\n * 根据错误代码获取 HTTP 状态码\n */\n private getHttpStatusCode(code: string): number {\n switch (code) {\n case \"INVALID_QUERY_PARAMETERS\":\n return 400;\n case \"LOG_FILE_NOT_FOUND\":\n return 404;\n case \"LOG_FILE_READ_ERROR\":\n return 500;\n default:\n return 500;\n }\n }\n\n /**\n * 解析和验证查询参数\n */\n private parseAndValidateQueryParams(c: Context): {\n success: boolean;\n data?: ToolCallQuery;\n error?: ValidationErrorDetail[];\n } {\n const query = c.req.query();\n const result = ToolCallQuerySchema.safeParse(query);\n\n if (!result.success) {\n return {\n success: false,\n error: result.error.errors.map((err) => ({\n field: err.path.join(\".\"),\n message: err.message,\n })),\n };\n }\n\n return {\n success: true,\n data: result.data as ToolCallQuery,\n };\n }\n\n /**\n * 获取工具调用日志\n */\n async getToolCallLogs(c: Context): Promise<Response> {\n try {\n const validation = this.parseAndValidateQueryParams(c);\n\n if (!validation.success) {\n return this.createErrorResponse(\n \"INVALID_QUERY_PARAMETERS\",\n \"查询参数格式错误\",\n validation.error\n );\n }\n\n const result = await this.toolCallLogService.getToolCallLogs(\n validation.data!\n );\n\n logger.debug(`API: 返回 ${result.records.length} 条工具调用日志记录`);\n return this.createSuccessResponse(result);\n } catch (error) {\n logger.error(\"获取工具调用日志失败:\", error);\n\n const message = error instanceof Error ? error.message : \"未知错误\";\n if (message.includes(\"不存在\")) {\n return this.createErrorResponse(\"LOG_FILE_NOT_FOUND\", message);\n }\n if (message.includes(\"无法读取\")) {\n return this.createErrorResponse(\"LOG_FILE_READ_ERROR\", message);\n }\n\n return this.createErrorResponse(\n \"INTERNAL_ERROR\",\n \"获取工具调用日志失败\",\n {\n details: message,\n }\n );\n }\n }\n}\n","'use strict'\n\n// Note: this is the semver.org version of the spec that it implements\n// Not necessarily the package version of this code.\nconst SEMVER_SPEC_VERSION = '2.0.0'\n\nconst MAX_LENGTH = 256\nconst MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER ||\n/* istanbul ignore next */ 9007199254740991\n\n// Max safe segment length for coercion.\nconst MAX_SAFE_COMPONENT_LENGTH = 16\n\n// Max safe length for a build identifier. The max length minus 6 characters for\n// the shortest version with a build 0.0.0+BUILD.\nconst MAX_SAFE_BUILD_LENGTH = MAX_LENGTH - 6\n\nconst RELEASE_TYPES = [\n 'major',\n 'premajor',\n 'minor',\n 'preminor',\n 'patch',\n 'prepatch',\n 'prerelease',\n]\n\nmodule.exports = {\n MAX_LENGTH,\n MAX_SAFE_COMPONENT_LENGTH,\n MAX_SAFE_BUILD_LENGTH,\n MAX_SAFE_INTEGER,\n RELEASE_TYPES,\n SEMVER_SPEC_VERSION,\n FLAG_INCLUDE_PRERELEASE: 0b001,\n FLAG_LOOSE: 0b010,\n}\n","'use strict'\n\nconst debug = (\n typeof process === 'object' &&\n process.env &&\n process.env.NODE_DEBUG &&\n /\\bsemver\\b/i.test(process.env.NODE_DEBUG)\n) ? (...args) => console.error('SEMVER', ...args)\n : () => {}\n\nmodule.exports = debug\n","'use strict'\n\nconst {\n MAX_SAFE_COMPONENT_LENGTH,\n MAX_SAFE_BUILD_LENGTH,\n MAX_LENGTH,\n} = require('./constants')\nconst debug = require('./debug')\nexports = module.exports = {}\n\n// The actual regexps go on exports.re\nconst re = exports.re = []\nconst safeRe = exports.safeRe = []\nconst src = exports.src = []\nconst safeSrc = exports.safeSrc = []\nconst t = exports.t = {}\nlet R = 0\n\nconst LETTERDASHNUMBER = '[a-zA-Z0-9-]'\n\n// Replace some greedy regex tokens to prevent regex dos issues. These regex are\n// used internally via the safeRe object since all inputs in this library get\n// normalized first to trim and collapse all extra whitespace. The original\n// regexes are exported for userland consumption and lower level usage. A\n// future breaking change could export the safer regex only with a note that\n// all input should have extra whitespace removed.\nconst safeRegexReplacements = [\n ['\\\\s', 1],\n ['\\\\d', MAX_LENGTH],\n [LETTERDASHNUMBER, MAX_SAFE_BUILD_LENGTH],\n]\n\nconst makeSafeRegex = (value) => {\n for (const [token, max] of safeRegexReplacements) {\n value = value\n .split(`${token}*`).join(`${token}{0,${max}}`)\n .split(`${token}+`).join(`${token}{1,${max}}`)\n }\n return value\n}\n\nconst createToken = (name, value, isGlobal) => {\n const safe = makeSafeRegex(value)\n const index = R++\n debug(name, index, value)\n t[name] = index\n src[index] = value\n safeSrc[index] = safe\n re[index] = new RegExp(value, isGlobal ? 'g' : undefined)\n safeRe[index] = new RegExp(safe, isGlobal ? 'g' : undefined)\n}\n\n// The following Regular Expressions can be used for tokenizing,\n// validating, and parsing SemVer version strings.\n\n// ## Numeric Identifier\n// A single `0`, or a non-zero digit followed by zero or more digits.\n\ncreateToken('NUMERICIDENTIFIER', '0|[1-9]\\\\d*')\ncreateToken('NUMERICIDENTIFIERLOOSE', '\\\\d+')\n\n// ## Non-numeric Identifier\n// Zero or more digits, followed by a letter or hyphen, and then zero or\n// more letters, digits, or hyphens.\n\ncreateToken('NONNUMERICIDENTIFIER', `\\\\d*[a-zA-Z-]${LETTERDASHNUMBER}*`)\n\n// ## Main Version\n// Three dot-separated numeric identifiers.\n\ncreateToken('MAINVERSION', `(${src[t.NUMERICIDENTIFIER]})\\\\.` +\n `(${src[t.NUMERICIDENTIFIER]})\\\\.` +\n `(${src[t.NUMERICIDENTIFIER]})`)\n\ncreateToken('MAINVERSIONLOOSE', `(${src[t.NUMERICIDENTIFIERLOOSE]})\\\\.` +\n `(${src[t.NUMERICIDENTIFIERLOOSE]})\\\\.` +\n `(${src[t.NUMERICIDENTIFIERLOOSE]})`)\n\n// ## Pre-release Version Identifier\n// A numeric identifier, or a non-numeric identifier.\n// Non-numberic identifiers include numberic identifiers but can be longer.\n// Therefore non-numberic identifiers must go first.\n\ncreateToken('PRERELEASEIDENTIFIER', `(?:${src[t.NONNUMERICIDENTIFIER]\n}|${src[t.NUMERICIDENTIFIER]})`)\n\ncreateToken('PRERELEASEIDENTIFIERLOOSE', `(?:${src[t.NONNUMERICIDENTIFIER]\n}|${src[t.NUMERICIDENTIFIERLOOSE]})`)\n\n// ## Pre-release Version\n// Hyphen, followed by one or more dot-separated pre-release version\n// identifiers.\n\ncreateToken('PRERELEASE', `(?:-(${src[t.PRERELEASEIDENTIFIER]\n}(?:\\\\.${src[t.PRERELEASEIDENTIFIER]})*))`)\n\ncreateToken('PRERELEASELOOSE', `(?:-?(${src[t.PRERELEASEIDENTIFIERLOOSE]\n}(?:\\\\.${src[t.PRERELEASEIDENTIFIERLOOSE]})*))`)\n\n// ## Build Metadata Identifier\n// Any combination of digits, letters, or hyphens.\n\ncreateToken('BUILDIDENTIFIER', `${LETTERDASHNUMBER}+`)\n\n// ## Build Metadata\n// Plus sign, followed by one or more period-separated build metadata\n// identifiers.\n\ncreateToken('BUILD', `(?:\\\\+(${src[t.BUILDIDENTIFIER]\n}(?:\\\\.${src[t.BUILDIDENTIFIER]})*))`)\n\n// ## Full Version String\n// A main version, followed optionally by a pre-release version and\n// build metadata.\n\n// Note that the only major, minor, patch, and pre-release sections of\n// the version string are capturing groups. The build metadata is not a\n// capturing group, because it should not ever be used in version\n// comparison.\n\ncreateToken('FULLPLAIN', `v?${src[t.MAINVERSION]\n}${src[t.PRERELEASE]}?${\n src[t.BUILD]}?`)\n\ncreateToken('FULL', `^${src[t.FULLPLAIN]}$`)\n\n// like full, but allows v1.2.3 and =1.2.3, which people do sometimes.\n// also, 1.0.0alpha1 (prerelease without the hyphen) which is pretty\n// common in the npm registry.\ncreateToken('LOOSEPLAIN', `[v=\\\\s]*${src[t.MAINVERSIONLOOSE]\n}${src[t.PRERELEASELOOSE]}?${\n src[t.BUILD]}?`)\n\ncreateToken('LOOSE', `^${src[t.LOOSEPLAIN]}$`)\n\ncreateToken('GTLT', '((?:<|>)?=?)')\n\n// Something like \"2.*\" or \"1.2.x\".\n// Note that \"x.x\" is a valid xRange identifer, meaning \"any version\"\n// Only the first item is strictly required.\ncreateToken('XRANGEIDENTIFIERLOOSE', `${src[t.NUMERICIDENTIFIERLOOSE]}|x|X|\\\\*`)\ncreateToken('XRANGEIDENTIFIER', `${src[t.NUMERICIDENTIFIER]}|x|X|\\\\*`)\n\ncreateToken('XRANGEPLAIN', `[v=\\\\s]*(${src[t.XRANGEIDENTIFIER]})` +\n `(?:\\\\.(${src[t.XRANGEIDENTIFIER]})` +\n `(?:\\\\.(${src[t.XRANGEIDENTIFIER]})` +\n `(?:${src[t.PRERELEASE]})?${\n src[t.BUILD]}?` +\n `)?)?`)\n\ncreateToken('XRANGEPLAINLOOSE', `[v=\\\\s]*(${src[t.XRANGEIDENTIFIERLOOSE]})` +\n `(?:\\\\.(${src[t.XRANGEIDENTIFIERLOOSE]})` +\n `(?:\\\\.(${src[t.XRANGEIDENTIFIERLOOSE]})` +\n `(?:${src[t.PRERELEASELOOSE]})?${\n src[t.BUILD]}?` +\n `)?)?`)\n\ncreateToken('XRANGE', `^${src[t.GTLT]}\\\\s*${src[t.XRANGEPLAIN]}$`)\ncreateToken('XRANGELOOSE', `^${src[t.GTLT]}\\\\s*${src[t.XRANGEPLAINLOOSE]}$`)\n\n// Coercion.\n// Extract anything that could conceivably be a part of a valid semver\ncreateToken('COERCEPLAIN', `${'(^|[^\\\\d])' +\n '(\\\\d{1,'}${MAX_SAFE_COMPONENT_LENGTH}})` +\n `(?:\\\\.(\\\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?` +\n `(?:\\\\.(\\\\d{1,${MAX_SAFE_COMPONENT_LENGTH}}))?`)\ncreateToken('COERCE', `${src[t.COERCEPLAIN]}(?:$|[^\\\\d])`)\ncreateToken('COERCEFULL', src[t.COERCEPLAIN] +\n `(?:${src[t.PRERELEASE]})?` +\n `(?:${src[t.BUILD]})?` +\n `(?:$|[^\\\\d])`)\ncreateToken('COERCERTL', src[t.COERCE], true)\ncreateToken('COERCERTLFULL', src[t.COERCEFULL], true)\n\n// Tilde ranges.\n// Meaning is \"reasonably at or greater than\"\ncreateToken('LONETILDE', '(?:~>?)')\n\ncreateToken('TILDETRIM', `(\\\\s*)${src[t.LONETILDE]}\\\\s+`, true)\nexports.tildeTrimReplace = '$1~'\n\ncreateToken('TILDE', `^${src[t.LONETILDE]}${src[t.XRANGEPLAIN]}$`)\ncreateToken('TILDELOOSE', `^${src[t.LONETILDE]}${src[t.XRANGEPLAINLOOSE]}$`)\n\n// Caret ranges.\n// Meaning is \"at least and backwards compatible with\"\ncreateToken('LONECARET', '(?:\\\\^)')\n\ncreateToken('CARETTRIM', `(\\\\s*)${src[t.LONECARET]}\\\\s+`, true)\nexports.caretTrimReplace = '$1^'\n\ncreateToken('CARET', `^${src[t.LONECARET]}${src[t.XRANGEPLAIN]}$`)\ncreateToken('CARETLOOSE', `^${src[t.LONECARET]}${src[t.XRANGEPLAINLOOSE]}$`)\n\n// A simple gt/lt/eq thing, or just \"\" to indicate \"any version\"\ncreateToken('COMPARATORLOOSE', `^${src[t.GTLT]}\\\\s*(${src[t.LOOSEPLAIN]})$|^$`)\ncreateToken('COMPARATOR', `^${src[t.GTLT]}\\\\s*(${src[t.FULLPLAIN]})$|^$`)\n\n// An expression to strip any whitespace between the gtlt and the thing\n// it modifies, so that `> 1.2.3` ==> `>1.2.3`\ncreateToken('COMPARATORTRIM', `(\\\\s*)${src[t.GTLT]\n}\\\\s*(${src[t.LOOSEPLAIN]}|${src[t.XRANGEPLAIN]})`, true)\nexports.comparatorTrimReplace = '$1$2$3'\n\n// Something like `1.2.3 - 1.2.4`\n// Note that these all use the loose form, because they'll be\n// checked against either the strict or loose comparator form\n// later.\ncreateToken('HYPHENRANGE', `^\\\\s*(${src[t.XRANGEPLAIN]})` +\n `\\\\s+-\\\\s+` +\n `(${src[t.XRANGEPLAIN]})` +\n `\\\\s*$`)\n\ncreateToken('HYPHENRANGELOOSE', `^\\\\s*(${src[t.XRANGEPLAINLOOSE]})` +\n `\\\\s+-\\\\s+` +\n `(${src[t.XRANGEPLAINLOOSE]})` +\n `\\\\s*$`)\n\n// Star ranges basically just allow anything at all.\ncreateToken('STAR', '(<|>)?=?\\\\s*\\\\*')\n// >=0.0.0 is like a star\ncreateToken('GTE0', '^\\\\s*>=\\\\s*0\\\\.0\\\\.0\\\\s*$')\ncreateToken('GTE0PRE', '^\\\\s*>=\\\\s*0\\\\.0\\\\.0-0\\\\s*$')\n","'use strict'\n\n// parse out just the options we care about\nconst looseOption = Object.freeze({ loose: true })\nconst emptyOpts = Object.freeze({ })\nconst parseOptions = options => {\n if (!options) {\n return emptyOpts\n }\n\n if (typeof options !== 'object') {\n return looseOption\n }\n\n return options\n}\nmodule.exports = parseOptions\n","'use strict'\n\nconst numeric = /^[0-9]+$/\nconst compareIdentifiers = (a, b) => {\n if (typeof a === 'number' && typeof b === 'number') {\n return a === b ? 0 : a < b ? -1 : 1\n }\n\n const anum = numeric.test(a)\n const bnum = numeric.test(b)\n\n if (anum && bnum) {\n a = +a\n b = +b\n }\n\n return a === b ? 0\n : (anum && !bnum) ? -1\n : (bnum && !anum) ? 1\n : a < b ? -1\n : 1\n}\n\nconst rcompareIdentifiers = (a, b) => compareIdentifiers(b, a)\n\nmodule.exports = {\n compareIdentifiers,\n rcompareIdentifiers,\n}\n","'use strict'\n\nconst debug = require('../internal/debug')\nconst { MAX_LENGTH, MAX_SAFE_INTEGER } = require('../internal/constants')\nconst { safeRe: re, t } = require('../internal/re')\n\nconst parseOptions = require('../internal/parse-options')\nconst { compareIdentifiers } = require('../internal/identifiers')\nclass SemVer {\n constructor (version, options) {\n options = parseOptions(options)\n\n if (version instanceof SemVer) {\n if (version.loose === !!options.loose &&\n version.includePrerelease === !!options.includePrerelease) {\n return version\n } else {\n version = version.version\n }\n } else if (typeof version !== 'string') {\n throw new TypeError(`Invalid version. Must be a string. Got type \"${typeof version}\".`)\n }\n\n if (version.length > MAX_LENGTH) {\n throw new TypeError(\n `version is longer than ${MAX_LENGTH} characters`\n )\n }\n\n debug('SemVer', version, options)\n this.options = options\n this.loose = !!options.loose\n // this isn't actually relevant for versions, but keep it so that we\n // don't run into trouble passing this.options around.\n this.includePrerelease = !!options.includePrerelease\n\n const m = version.trim().match(options.loose ? re[t.LOOSE] : re[t.FULL])\n\n if (!m) {\n throw new TypeError(`Invalid Version: ${version}`)\n }\n\n this.raw = version\n\n // these are actually numbers\n this.major = +m[1]\n this.minor = +m[2]\n this.patch = +m[3]\n\n if (this.major > MAX_SAFE_INTEGER || this.major < 0) {\n throw new TypeError('Invalid major version')\n }\n\n if (this.minor > MAX_SAFE_INTEGER || this.minor < 0) {\n throw new TypeError('Invalid minor version')\n }\n\n if (this.patch > MAX_SAFE_INTEGER || this.patch < 0) {\n throw new TypeError('Invalid patch version')\n }\n\n // numberify any prerelease numeric ids\n if (!m[4]) {\n this.prerelease = []\n } else {\n this.prerelease = m[4].split('.').map((id) => {\n if (/^[0-9]+$/.test(id)) {\n const num = +id\n if (num >= 0 && num < MAX_SAFE_INTEGER) {\n return num\n }\n }\n return id\n })\n }\n\n this.build = m[5] ? m[5].split('.') : []\n this.format()\n }\n\n format () {\n this.version = `${this.major}.${this.minor}.${this.patch}`\n if (this.prerelease.length) {\n this.version += `-${this.prerelease.join('.')}`\n }\n return this.version\n }\n\n toString () {\n return this.version\n }\n\n compare (other) {\n debug('SemVer.compare', this.version, this.options, other)\n if (!(other instanceof SemVer)) {\n if (typeof other === 'string' && other === this.version) {\n return 0\n }\n other = new SemVer(other, this.options)\n }\n\n if (other.version === this.version) {\n return 0\n }\n\n return this.compareMain(other) || this.comparePre(other)\n }\n\n compareMain (other) {\n if (!(other instanceof SemVer)) {\n other = new SemVer(other, this.options)\n }\n\n if (this.major < other.major) {\n return -1\n }\n if (this.major > other.major) {\n return 1\n }\n if (this.minor < other.minor) {\n return -1\n }\n if (this.minor > other.minor) {\n return 1\n }\n if (this.patch < other.patch) {\n return -1\n }\n if (this.patch > other.patch) {\n return 1\n }\n return 0\n }\n\n comparePre (other) {\n if (!(other instanceof SemVer)) {\n other = new SemVer(other, this.options)\n }\n\n // NOT having a prerelease is > having one\n if (this.prerelease.length && !other.prerelease.length) {\n return -1\n } else if (!this.prerelease.length && other.prerelease.length) {\n return 1\n } else if (!this.prerelease.length && !other.prerelease.length) {\n return 0\n }\n\n let i = 0\n do {\n const a = this.prerelease[i]\n const b = other.prerelease[i]\n debug('prerelease compare', i, a, b)\n if (a === undefined && b === undefined) {\n return 0\n } else if (b === undefined) {\n return 1\n } else if (a === undefined) {\n return -1\n } else if (a === b) {\n continue\n } else {\n return compareIdentifiers(a, b)\n }\n } while (++i)\n }\n\n compareBuild (other) {\n if (!(other instanceof SemVer)) {\n other = new SemVer(other, this.options)\n }\n\n let i = 0\n do {\n const a = this.build[i]\n const b = other.build[i]\n debug('build compare', i, a, b)\n if (a === undefined && b === undefined) {\n return 0\n } else if (b === undefined) {\n return 1\n } else if (a === undefined) {\n return -1\n } else if (a === b) {\n continue\n } else {\n return compareIdentifiers(a, b)\n }\n } while (++i)\n }\n\n // preminor will bump the version up to the next minor release, and immediately\n // down to pre-release. premajor and prepatch work the same way.\n inc (release, identifier, identifierBase) {\n if (release.startsWith('pre')) {\n if (!identifier && identifierBase === false) {\n throw new Error('invalid increment argument: identifier is empty')\n }\n // Avoid an invalid semver results\n if (identifier) {\n const match = `-${identifier}`.match(this.options.loose ? re[t.PRERELEASELOOSE] : re[t.PRERELEASE])\n if (!match || match[1] !== identifier) {\n throw new Error(`invalid identifier: ${identifier}`)\n }\n }\n }\n\n switch (release) {\n case 'premajor':\n this.prerelease.length = 0\n this.patch = 0\n this.minor = 0\n this.major++\n this.inc('pre', identifier, identifierBase)\n break\n case 'preminor':\n this.prerelease.length = 0\n this.patch = 0\n this.minor++\n this.inc('pre', identifier, identifierBase)\n break\n case 'prepatch':\n // If this is already a prerelease, it will bump to the next version\n // drop any prereleases that might already exist, since they are not\n // relevant at this point.\n this.prerelease.length = 0\n this.inc('patch', identifier, identifierBase)\n this.inc('pre', identifier, identifierBase)\n break\n // If the input is a non-prerelease version, this acts the same as\n // prepatch.\n case 'prerelease':\n if (this.prerelease.length === 0) {\n this.inc('patch', identifier, identifierBase)\n }\n this.inc('pre', identifier, identifierBase)\n break\n case 'release':\n if (this.prerelease.length === 0) {\n throw new Error(`version ${this.raw} is not a prerelease`)\n }\n this.prerelease.length = 0\n break\n\n case 'major':\n // If this is a pre-major version, bump up to the same major version.\n // Otherwise increment major.\n // 1.0.0-5 bumps to 1.0.0\n // 1.1.0 bumps to 2.0.0\n if (\n this.minor !== 0 ||\n this.patch !== 0 ||\n this.prerelease.length === 0\n ) {\n this.major++\n }\n this.minor = 0\n this.patch = 0\n this.prerelease = []\n break\n case 'minor':\n // If this is a pre-minor version, bump up to the same minor version.\n // Otherwise increment minor.\n // 1.2.0-5 bumps to 1.2.0\n // 1.2.1 bumps to 1.3.0\n if (this.patch !== 0 || this.prerelease.length === 0) {\n this.minor++\n }\n this.patch = 0\n this.prerelease = []\n break\n case 'patch':\n // If this is not a pre-release version, it will increment the patch.\n // If it is a pre-release it will bump up to the same patch version.\n // 1.2.0-5 patches to 1.2.0\n // 1.2.0 patches to 1.2.1\n if (this.prerelease.length === 0) {\n this.patch++\n }\n this.prerelease = []\n break\n // This probably shouldn't be used publicly.\n // 1.0.0 'pre' would become 1.0.0-0 which is the wrong direction.\n case 'pre': {\n const base = Number(identifierBase) ? 1 : 0\n\n if (this.prerelease.length === 0) {\n this.prerelease = [base]\n } else {\n let i = this.prerelease.length\n while (--i >= 0) {\n if (typeof this.prerelease[i] === 'number') {\n this.prerelease[i]++\n i = -2\n }\n }\n if (i === -1) {\n // didn't increment anything\n if (identifier === this.prerelease.join('.') && identifierBase === false) {\n throw new Error('invalid increment argument: identifier already exists')\n }\n this.prerelease.push(base)\n }\n }\n if (identifier) {\n // 1.2.0-beta.1 bumps to 1.2.0-beta.2,\n // 1.2.0-beta.fooblz or 1.2.0-beta bumps to 1.2.0-beta.0\n let prerelease = [identifier, base]\n if (identifierBase === false) {\n prerelease = [identifier]\n }\n if (compareIdentifiers(this.prerelease[0], identifier) === 0) {\n if (isNaN(this.prerelease[1])) {\n this.prerelease = prerelease\n }\n } else {\n this.prerelease = prerelease\n }\n }\n break\n }\n default:\n throw new Error(`invalid increment argument: ${release}`)\n }\n this.raw = this.format()\n if (this.build.length) {\n this.raw += `+${this.build.join('.')}`\n }\n return this\n }\n}\n\nmodule.exports = SemVer\n","'use strict'\n\nconst SemVer = require('../classes/semver')\nconst parse = (version, options, throwErrors = false) => {\n if (version instanceof SemVer) {\n return version\n }\n try {\n return new SemVer(version, options)\n } catch (er) {\n if (!throwErrors) {\n return null\n }\n throw er\n }\n}\n\nmodule.exports = parse\n","'use strict'\n\nconst parse = require('./parse')\nconst valid = (version, options) => {\n const v = parse(version, options)\n return v ? v.version : null\n}\nmodule.exports = valid\n","'use strict'\n\nconst parse = require('./parse')\nconst clean = (version, options) => {\n const s = parse(version.trim().replace(/^[=v]+/, ''), options)\n return s ? s.version : null\n}\nmodule.exports = clean\n","'use strict'\n\nconst SemVer = require('../classes/semver')\n\nconst inc = (version, release, options, identifier, identifierBase) => {\n if (typeof (options) === 'string') {\n identifierBase = identifier\n identifier = options\n options = undefined\n }\n\n try {\n return new SemVer(\n version instanceof SemVer ? version.version : version,\n options\n ).inc(release, identifier, identifierBase).version\n } catch (er) {\n return null\n }\n}\nmodule.exports = inc\n","'use strict'\n\nconst parse = require('./parse.js')\n\nconst diff = (version1, version2) => {\n const v1 = parse(version1, null, true)\n const v2 = parse(version2, null, true)\n const comparison = v1.compare(v2)\n\n if (comparison === 0) {\n return null\n }\n\n const v1Higher = comparison > 0\n const highVersion = v1Higher ? v1 : v2\n const lowVersion = v1Higher ? v2 : v1\n const highHasPre = !!highVersion.prerelease.length\n const lowHasPre = !!lowVersion.prerelease.length\n\n if (lowHasPre && !highHasPre) {\n // Going from prerelease -> no prerelease requires some special casing\n\n // If the low version has only a major, then it will always be a major\n // Some examples:\n // 1.0.0-1 -> 1.0.0\n // 1.0.0-1 -> 1.1.1\n // 1.0.0-1 -> 2.0.0\n if (!lowVersion.patch && !lowVersion.minor) {\n return 'major'\n }\n\n // If the main part has no difference\n if (lowVersion.compareMain(highVersion) === 0) {\n if (lowVersion.minor && !lowVersion.patch) {\n return 'minor'\n }\n return 'patch'\n }\n }\n\n // add the `pre` prefix if we are going to a prerelease version\n const prefix = highHasPre ? 'pre' : ''\n\n if (v1.major !== v2.major) {\n return prefix + 'major'\n }\n\n if (v1.minor !== v2.minor) {\n return prefix + 'minor'\n }\n\n if (v1.patch !== v2.patch) {\n return prefix + 'patch'\n }\n\n // high and low are preleases\n return 'prerelease'\n}\n\nmodule.exports = diff\n","'use strict'\n\nconst SemVer = require('../classes/semver')\nconst major = (a, loose) => new SemVer(a, loose).major\nmodule.exports = major\n","'use strict'\n\nconst SemVer = require('../classes/semver')\nconst minor = (a, loose) => new SemVer(a, loose).minor\nmodule.exports = minor\n","'use strict'\n\nconst SemVer = require('../classes/semver')\nconst patch = (a, loose) => new SemVer(a, loose).patch\nmodule.exports = patch\n","'use strict'\n\nconst parse = require('./parse')\nconst prerelease = (version, options) => {\n const parsed = parse(version, options)\n return (parsed && parsed.prerelease.length) ? parsed.prerelease : null\n}\nmodule.exports = prerelease\n","'use strict'\n\nconst SemVer = require('../classes/semver')\nconst compare = (a, b, loose) =>\n new SemVer(a, loose).compare(new SemVer(b, loose))\n\nmodule.exports = compare\n","'use strict'\n\nconst compare = require('./compare')\nconst rcompare = (a, b, loose) => compare(b, a, loose)\nmodule.exports = rcompare\n","'use strict'\n\nconst compare = require('./compare')\nconst compareLoose = (a, b) => compare(a, b, true)\nmodule.exports = compareLoose\n","'use strict'\n\nconst SemVer = require('../classes/semver')\nconst compareBuild = (a, b, loose) => {\n const versionA = new SemVer(a, loose)\n const versionB = new SemVer(b, loose)\n return versionA.compare(versionB) || versionA.compareBuild(versionB)\n}\nmodule.exports = compareBuild\n","'use strict'\n\nconst compareBuild = require('./compare-build')\nconst sort = (list, loose) => list.sort((a, b) => compareBuild(a, b, loose))\nmodule.exports = sort\n","'use strict'\n\nconst compareBuild = require('./compare-build')\nconst rsort = (list, loose) => list.sort((a, b) => compareBuild(b, a, loose))\nmodule.exports = rsort\n","'use strict'\n\nconst compare = require('./compare')\nconst gt = (a, b, loose) => compare(a, b, loose) > 0\nmodule.exports = gt\n","'use strict'\n\nconst compare = require('./compare')\nconst lt = (a, b, loose) => compare(a, b, loose) < 0\nmodule.exports = lt\n","'use strict'\n\nconst compare = require('./compare')\nconst eq = (a, b, loose) => compare(a, b, loose) === 0\nmodule.exports = eq\n","'use strict'\n\nconst compare = require('./compare')\nconst neq = (a, b, loose) => compare(a, b, loose) !== 0\nmodule.exports = neq\n","'use strict'\n\nconst compare = require('./compare')\nconst gte = (a, b, loose) => compare(a, b, loose) >= 0\nmodule.exports = gte\n","'use strict'\n\nconst compare = require('./compare')\nconst lte = (a, b, loose) => compare(a, b, loose) <= 0\nmodule.exports = lte\n","'use strict'\n\nconst eq = require('./eq')\nconst neq = require('./neq')\nconst gt = require('./gt')\nconst gte = require('./gte')\nconst lt = require('./lt')\nconst lte = require('./lte')\n\nconst cmp = (a, op, b, loose) => {\n switch (op) {\n case '===':\n if (typeof a === 'object') {\n a = a.version\n }\n if (typeof b === 'object') {\n b = b.version\n }\n return a === b\n\n case '!==':\n if (typeof a === 'object') {\n a = a.version\n }\n if (typeof b === 'object') {\n b = b.version\n }\n return a !== b\n\n case '':\n case '=':\n case '==':\n return eq(a, b, loose)\n\n case '!=':\n return neq(a, b, loose)\n\n case '>':\n return gt(a, b, loose)\n\n case '>=':\n return gte(a, b, loose)\n\n case '<':\n return lt(a, b, loose)\n\n case '<=':\n return lte(a, b, loose)\n\n default:\n throw new TypeError(`Invalid operator: ${op}`)\n }\n}\nmodule.exports = cmp\n","'use strict'\n\nconst SemVer = require('../classes/semver')\nconst parse = require('./parse')\nconst { safeRe: re, t } = require('../internal/re')\n\nconst coerce = (version, options) => {\n if (version instanceof SemVer) {\n return version\n }\n\n if (typeof version === 'number') {\n version = String(version)\n }\n\n if (typeof version !== 'string') {\n return null\n }\n\n options = options || {}\n\n let match = null\n if (!options.rtl) {\n match = version.match(options.includePrerelease ? re[t.COERCEFULL] : re[t.COERCE])\n } else {\n // Find the right-most coercible string that does not share\n // a terminus with a more left-ward coercible string.\n // Eg, '1.2.3.4' wants to coerce '2.3.4', not '3.4' or '4'\n // With includePrerelease option set, '1.2.3.4-rc' wants to coerce '2.3.4-rc', not '2.3.4'\n //\n // Walk through the string checking with a /g regexp\n // Manually set the index so as to pick up overlapping matches.\n // Stop when we get a match that ends at the string end, since no\n // coercible string can be more right-ward without the same terminus.\n const coerceRtlRegex = options.includePrerelease ? re[t.COERCERTLFULL] : re[t.COERCERTL]\n let next\n while ((next = coerceRtlRegex.exec(version)) &&\n (!match || match.index + match[0].length !== version.length)\n ) {\n if (!match ||\n next.index + next[0].length !== match.index + match[0].length) {\n match = next\n }\n coerceRtlRegex.lastIndex = next.index + next[1].length + next[2].length\n }\n // leave it in a clean state\n coerceRtlRegex.lastIndex = -1\n }\n\n if (match === null) {\n return null\n }\n\n const major = match[2]\n const minor = match[3] || '0'\n const patch = match[4] || '0'\n const prerelease = options.includePrerelease && match[5] ? `-${match[5]}` : ''\n const build = options.includePrerelease && match[6] ? `+${match[6]}` : ''\n\n return parse(`${major}.${minor}.${patch}${prerelease}${build}`, options)\n}\nmodule.exports = coerce\n","'use strict'\n\nclass LRUCache {\n constructor () {\n this.max = 1000\n this.map = new Map()\n }\n\n get (key) {\n const value = this.map.get(key)\n if (value === undefined) {\n return undefined\n } else {\n // Remove the key from the map and add it to the end\n this.map.delete(key)\n this.map.set(key, value)\n return value\n }\n }\n\n delete (key) {\n return this.map.delete(key)\n }\n\n set (key, value) {\n const deleted = this.delete(key)\n\n if (!deleted && value !== undefined) {\n // If cache is full, delete the least recently used item\n if (this.map.size >= this.max) {\n const firstKey = this.map.keys().next().value\n this.delete(firstKey)\n }\n\n this.map.set(key, value)\n }\n\n return this\n }\n}\n\nmodule.exports = LRUCache\n","'use strict'\n\nconst SPACE_CHARACTERS = /\\s+/g\n\n// hoisted class for cyclic dependency\nclass Range {\n constructor (range, options) {\n options = parseOptions(options)\n\n if (range instanceof Range) {\n if (\n range.loose === !!options.loose &&\n range.includePrerelease === !!options.includePrerelease\n ) {\n return range\n } else {\n return new Range(range.raw, options)\n }\n }\n\n if (range instanceof Comparator) {\n // just put it in the set and return\n this.raw = range.value\n this.set = [[range]]\n this.formatted = undefined\n return this\n }\n\n this.options = options\n this.loose = !!options.loose\n this.includePrerelease = !!options.includePrerelease\n\n // First reduce all whitespace as much as possible so we do not have to rely\n // on potentially slow regexes like \\s*. This is then stored and used for\n // future error messages as well.\n this.raw = range.trim().replace(SPACE_CHARACTERS, ' ')\n\n // First, split on ||\n this.set = this.raw\n .split('||')\n // map the range to a 2d array of comparators\n .map(r => this.parseRange(r.trim()))\n // throw out any comparator lists that are empty\n // this generally means that it was not a valid range, which is allowed\n // in loose mode, but will still throw if the WHOLE range is invalid.\n .filter(c => c.length)\n\n if (!this.set.length) {\n throw new TypeError(`Invalid SemVer Range: ${this.raw}`)\n }\n\n // if we have any that are not the null set, throw out null sets.\n if (this.set.length > 1) {\n // keep the first one, in case they're all null sets\n const first = this.set[0]\n this.set = this.set.filter(c => !isNullSet(c[0]))\n if (this.set.length === 0) {\n this.set = [first]\n } else if (this.set.length > 1) {\n // if we have any that are *, then the range is just *\n for (const c of this.set) {\n if (c.length === 1 && isAny(c[0])) {\n this.set = [c]\n break\n }\n }\n }\n }\n\n this.formatted = undefined\n }\n\n get range () {\n if (this.formatted === undefined) {\n this.formatted = ''\n for (let i = 0; i < this.set.length; i++) {\n if (i > 0) {\n this.formatted += '||'\n }\n const comps = this.set[i]\n for (let k = 0; k < comps.length; k++) {\n if (k > 0) {\n this.formatted += ' '\n }\n this.formatted += comps[k].toString().trim()\n }\n }\n }\n return this.formatted\n }\n\n format () {\n return this.range\n }\n\n toString () {\n return this.range\n }\n\n parseRange (range) {\n // memoize range parsing for performance.\n // this is a very hot path, and fully deterministic.\n const memoOpts =\n (this.options.includePrerelease && FLAG_INCLUDE_PRERELEASE) |\n (this.options.loose && FLAG_LOOSE)\n const memoKey = memoOpts + ':' + range\n const cached = cache.get(memoKey)\n if (cached) {\n return cached\n }\n\n const loose = this.options.loose\n // `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4`\n const hr = loose ? re[t.HYPHENRANGELOOSE] : re[t.HYPHENRANGE]\n range = range.replace(hr, hyphenReplace(this.options.includePrerelease))\n debug('hyphen replace', range)\n\n // `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5`\n range = range.replace(re[t.COMPARATORTRIM], comparatorTrimReplace)\n debug('comparator trim', range)\n\n // `~ 1.2.3` => `~1.2.3`\n range = range.replace(re[t.TILDETRIM], tildeTrimReplace)\n debug('tilde trim', range)\n\n // `^ 1.2.3` => `^1.2.3`\n range = range.replace(re[t.CARETTRIM], caretTrimReplace)\n debug('caret trim', range)\n\n // At this point, the range is completely trimmed and\n // ready to be split into comparators.\n\n let rangeList = range\n .split(' ')\n .map(comp => parseComparator(comp, this.options))\n .join(' ')\n .split(/\\s+/)\n // >=0.0.0 is equivalent to *\n .map(comp => replaceGTE0(comp, this.options))\n\n if (loose) {\n // in loose mode, throw out any that are not valid comparators\n rangeList = rangeList.filter(comp => {\n debug('loose invalid filter', comp, this.options)\n return !!comp.match(re[t.COMPARATORLOOSE])\n })\n }\n debug('range list', rangeList)\n\n // if any comparators are the null set, then replace with JUST null set\n // if more than one comparator, remove any * comparators\n // also, don't include the same comparator more than once\n const rangeMap = new Map()\n const comparators = rangeList.map(comp => new Comparator(comp, this.options))\n for (const comp of comparators) {\n if (isNullSet(comp)) {\n return [comp]\n }\n rangeMap.set(comp.value, comp)\n }\n if (rangeMap.size > 1 && rangeMap.has('')) {\n rangeMap.delete('')\n }\n\n const result = [...rangeMap.values()]\n cache.set(memoKey, result)\n return result\n }\n\n intersects (range, options) {\n if (!(range instanceof Range)) {\n throw new TypeError('a Range is required')\n }\n\n return this.set.some((thisComparators) => {\n return (\n isSatisfiable(thisComparators, options) &&\n range.set.some((rangeComparators) => {\n return (\n isSatisfiable(rangeComparators, options) &&\n thisComparators.every((thisComparator) => {\n return rangeComparators.every((rangeComparator) => {\n return thisComparator.intersects(rangeComparator, options)\n })\n })\n )\n })\n )\n })\n }\n\n // if ANY of the sets match ALL of its comparators, then pass\n test (version) {\n if (!version) {\n return false\n }\n\n if (typeof version === 'string') {\n try {\n version = new SemVer(version, this.options)\n } catch (er) {\n return false\n }\n }\n\n for (let i = 0; i < this.set.length; i++) {\n if (testSet(this.set[i], version, this.options)) {\n return true\n }\n }\n return false\n }\n}\n\nmodule.exports = Range\n\nconst LRU = require('../internal/lrucache')\nconst cache = new LRU()\n\nconst parseOptions = require('../internal/parse-options')\nconst Comparator = require('./comparator')\nconst debug = require('../internal/debug')\nconst SemVer = require('./semver')\nconst {\n safeRe: re,\n t,\n comparatorTrimReplace,\n tildeTrimReplace,\n caretTrimReplace,\n} = require('../internal/re')\nconst { FLAG_INCLUDE_PRERELEASE, FLAG_LOOSE } = require('../internal/constants')\n\nconst isNullSet = c => c.value === '<0.0.0-0'\nconst isAny = c => c.value === ''\n\n// take a set of comparators and determine whether there\n// exists a version which can satisfy it\nconst isSatisfiable = (comparators, options) => {\n let result = true\n const remainingComparators = comparators.slice()\n let testComparator = remainingComparators.pop()\n\n while (result && remainingComparators.length) {\n result = remainingComparators.every((otherComparator) => {\n return testComparator.intersects(otherComparator, options)\n })\n\n testComparator = remainingComparators.pop()\n }\n\n return result\n}\n\n// comprised of xranges, tildes, stars, and gtlt's at this point.\n// already replaced the hyphen ranges\n// turn into a set of JUST comparators.\nconst parseComparator = (comp, options) => {\n comp = comp.replace(re[t.BUILD], '')\n debug('comp', comp, options)\n comp = replaceCarets(comp, options)\n debug('caret', comp)\n comp = replaceTildes(comp, options)\n debug('tildes', comp)\n comp = replaceXRanges(comp, options)\n debug('xrange', comp)\n comp = replaceStars(comp, options)\n debug('stars', comp)\n return comp\n}\n\nconst isX = id => !id || id.toLowerCase() === 'x' || id === '*'\n\n// ~, ~> --> * (any, kinda silly)\n// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0 <3.0.0-0\n// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0 <2.1.0-0\n// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0 <1.3.0-0\n// ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0-0\n// ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0-0\n// ~0.0.1 --> >=0.0.1 <0.1.0-0\nconst replaceTildes = (comp, options) => {\n return comp\n .trim()\n .split(/\\s+/)\n .map((c) => replaceTilde(c, options))\n .join(' ')\n}\n\nconst replaceTilde = (comp, options) => {\n const r = options.loose ? re[t.TILDELOOSE] : re[t.TILDE]\n return comp.replace(r, (_, M, m, p, pr) => {\n debug('tilde', comp, _, M, m, p, pr)\n let ret\n\n if (isX(M)) {\n ret = ''\n } else if (isX(m)) {\n ret = `>=${M}.0.0 <${+M + 1}.0.0-0`\n } else if (isX(p)) {\n // ~1.2 == >=1.2.0 <1.3.0-0\n ret = `>=${M}.${m}.0 <${M}.${+m + 1}.0-0`\n } else if (pr) {\n debug('replaceTilde pr', pr)\n ret = `>=${M}.${m}.${p}-${pr\n } <${M}.${+m + 1}.0-0`\n } else {\n // ~1.2.3 == >=1.2.3 <1.3.0-0\n ret = `>=${M}.${m}.${p\n } <${M}.${+m + 1}.0-0`\n }\n\n debug('tilde return', ret)\n return ret\n })\n}\n\n// ^ --> * (any, kinda silly)\n// ^2, ^2.x, ^2.x.x --> >=2.0.0 <3.0.0-0\n// ^2.0, ^2.0.x --> >=2.0.0 <3.0.0-0\n// ^1.2, ^1.2.x --> >=1.2.0 <2.0.0-0\n// ^1.2.3 --> >=1.2.3 <2.0.0-0\n// ^1.2.0 --> >=1.2.0 <2.0.0-0\n// ^0.0.1 --> >=0.0.1 <0.0.2-0\n// ^0.1.0 --> >=0.1.0 <0.2.0-0\nconst replaceCarets = (comp, options) => {\n return comp\n .trim()\n .split(/\\s+/)\n .map((c) => replaceCaret(c, options))\n .join(' ')\n}\n\nconst replaceCaret = (comp, options) => {\n debug('caret', comp, options)\n const r = options.loose ? re[t.CARETLOOSE] : re[t.CARET]\n const z = options.includePrerelease ? '-0' : ''\n return comp.replace(r, (_, M, m, p, pr) => {\n debug('caret', comp, _, M, m, p, pr)\n let ret\n\n if (isX(M)) {\n ret = ''\n } else if (isX(m)) {\n ret = `>=${M}.0.0${z} <${+M + 1}.0.0-0`\n } else if (isX(p)) {\n if (M === '0') {\n ret = `>=${M}.${m}.0${z} <${M}.${+m + 1}.0-0`\n } else {\n ret = `>=${M}.${m}.0${z} <${+M + 1}.0.0-0`\n }\n } else if (pr) {\n debug('replaceCaret pr', pr)\n if (M === '0') {\n if (m === '0') {\n ret = `>=${M}.${m}.${p}-${pr\n } <${M}.${m}.${+p + 1}-0`\n } else {\n ret = `>=${M}.${m}.${p}-${pr\n } <${M}.${+m + 1}.0-0`\n }\n } else {\n ret = `>=${M}.${m}.${p}-${pr\n } <${+M + 1}.0.0-0`\n }\n } else {\n debug('no pr')\n if (M === '0') {\n if (m === '0') {\n ret = `>=${M}.${m}.${p\n }${z} <${M}.${m}.${+p + 1}-0`\n } else {\n ret = `>=${M}.${m}.${p\n }${z} <${M}.${+m + 1}.0-0`\n }\n } else {\n ret = `>=${M}.${m}.${p\n } <${+M + 1}.0.0-0`\n }\n }\n\n debug('caret return', ret)\n return ret\n })\n}\n\nconst replaceXRanges = (comp, options) => {\n debug('replaceXRanges', comp, options)\n return comp\n .split(/\\s+/)\n .map((c) => replaceXRange(c, options))\n .join(' ')\n}\n\nconst replaceXRange = (comp, options) => {\n comp = comp.trim()\n const r = options.loose ? re[t.XRANGELOOSE] : re[t.XRANGE]\n return comp.replace(r, (ret, gtlt, M, m, p, pr) => {\n debug('xRange', comp, ret, gtlt, M, m, p, pr)\n const xM = isX(M)\n const xm = xM || isX(m)\n const xp = xm || isX(p)\n const anyX = xp\n\n if (gtlt === '=' && anyX) {\n gtlt = ''\n }\n\n // if we're including prereleases in the match, then we need\n // to fix this to -0, the lowest possible prerelease value\n pr = options.includePrerelease ? '-0' : ''\n\n if (xM) {\n if (gtlt === '>' || gtlt === '<') {\n // nothing is allowed\n ret = '<0.0.0-0'\n } else {\n // nothing is forbidden\n ret = '*'\n }\n } else if (gtlt && anyX) {\n // we know patch is an x, because we have any x at all.\n // replace X with 0\n if (xm) {\n m = 0\n }\n p = 0\n\n if (gtlt === '>') {\n // >1 => >=2.0.0\n // >1.2 => >=1.3.0\n gtlt = '>='\n if (xm) {\n M = +M + 1\n m = 0\n p = 0\n } else {\n m = +m + 1\n p = 0\n }\n } else if (gtlt === '<=') {\n // <=0.7.x is actually <0.8.0, since any 0.7.x should\n // pass. Similarly, <=7.x is actually <8.0.0, etc.\n gtlt = '<'\n if (xm) {\n M = +M + 1\n } else {\n m = +m + 1\n }\n }\n\n if (gtlt === '<') {\n pr = '-0'\n }\n\n ret = `${gtlt + M}.${m}.${p}${pr}`\n } else if (xm) {\n ret = `>=${M}.0.0${pr} <${+M + 1}.0.0-0`\n } else if (xp) {\n ret = `>=${M}.${m}.0${pr\n } <${M}.${+m + 1}.0-0`\n }\n\n debug('xRange return', ret)\n\n return ret\n })\n}\n\n// Because * is AND-ed with everything else in the comparator,\n// and '' means \"any version\", just remove the *s entirely.\nconst replaceStars = (comp, options) => {\n debug('replaceStars', comp, options)\n // Looseness is ignored here. star is always as loose as it gets!\n return comp\n .trim()\n .replace(re[t.STAR], '')\n}\n\nconst replaceGTE0 = (comp, options) => {\n debug('replaceGTE0', comp, options)\n return comp\n .trim()\n .replace(re[options.includePrerelease ? t.GTE0PRE : t.GTE0], '')\n}\n\n// This function is passed to string.replace(re[t.HYPHENRANGE])\n// M, m, patch, prerelease, build\n// 1.2 - 3.4.5 => >=1.2.0 <=3.4.5\n// 1.2.3 - 3.4 => >=1.2.0 <3.5.0-0 Any 3.4.x will do\n// 1.2 - 3.4 => >=1.2.0 <3.5.0-0\n// TODO build?\nconst hyphenReplace = incPr => ($0,\n from, fM, fm, fp, fpr, fb,\n to, tM, tm, tp, tpr) => {\n if (isX(fM)) {\n from = ''\n } else if (isX(fm)) {\n from = `>=${fM}.0.0${incPr ? '-0' : ''}`\n } else if (isX(fp)) {\n from = `>=${fM}.${fm}.0${incPr ? '-0' : ''}`\n } else if (fpr) {\n from = `>=${from}`\n } else {\n from = `>=${from}${incPr ? '-0' : ''}`\n }\n\n if (isX(tM)) {\n to = ''\n } else if (isX(tm)) {\n to = `<${+tM + 1}.0.0-0`\n } else if (isX(tp)) {\n to = `<${tM}.${+tm + 1}.0-0`\n } else if (tpr) {\n to = `<=${tM}.${tm}.${tp}-${tpr}`\n } else if (incPr) {\n to = `<${tM}.${tm}.${+tp + 1}-0`\n } else {\n to = `<=${to}`\n }\n\n return `${from} ${to}`.trim()\n}\n\nconst testSet = (set, version, options) => {\n for (let i = 0; i < set.length; i++) {\n if (!set[i].test(version)) {\n return false\n }\n }\n\n if (version.prerelease.length && !options.includePrerelease) {\n // Find the set of versions that are allowed to have prereleases\n // For example, ^1.2.3-pr.1 desugars to >=1.2.3-pr.1 <2.0.0\n // That should allow `1.2.3-pr.2` to pass.\n // However, `1.2.4-alpha.notready` should NOT be allowed,\n // even though it's within the range set by the comparators.\n for (let i = 0; i < set.length; i++) {\n debug(set[i].semver)\n if (set[i].semver === Comparator.ANY) {\n continue\n }\n\n if (set[i].semver.prerelease.length > 0) {\n const allowed = set[i].semver\n if (allowed.major === version.major &&\n allowed.minor === version.minor &&\n allowed.patch === version.patch) {\n return true\n }\n }\n }\n\n // Version has a -pre, but it's not one of the ones we like.\n return false\n }\n\n return true\n}\n","'use strict'\n\nconst ANY = Symbol('SemVer ANY')\n// hoisted class for cyclic dependency\nclass Comparator {\n static get ANY () {\n return ANY\n }\n\n constructor (comp, options) {\n options = parseOptions(options)\n\n if (comp instanceof Comparator) {\n if (comp.loose === !!options.loose) {\n return comp\n } else {\n comp = comp.value\n }\n }\n\n comp = comp.trim().split(/\\s+/).join(' ')\n debug('comparator', comp, options)\n this.options = options\n this.loose = !!options.loose\n this.parse(comp)\n\n if (this.semver === ANY) {\n this.value = ''\n } else {\n this.value = this.operator + this.semver.version\n }\n\n debug('comp', this)\n }\n\n parse (comp) {\n const r = this.options.loose ? re[t.COMPARATORLOOSE] : re[t.COMPARATOR]\n const m = comp.match(r)\n\n if (!m) {\n throw new TypeError(`Invalid comparator: ${comp}`)\n }\n\n this.operator = m[1] !== undefined ? m[1] : ''\n if (this.operator === '=') {\n this.operator = ''\n }\n\n // if it literally is just '>' or '' then allow anything.\n if (!m[2]) {\n this.semver = ANY\n } else {\n this.semver = new SemVer(m[2], this.options.loose)\n }\n }\n\n toString () {\n return this.value\n }\n\n test (version) {\n debug('Comparator.test', version, this.options.loose)\n\n if (this.semver === ANY || version === ANY) {\n return true\n }\n\n if (typeof version === 'string') {\n try {\n version = new SemVer(version, this.options)\n } catch (er) {\n return false\n }\n }\n\n return cmp(version, this.operator, this.semver, this.options)\n }\n\n intersects (comp, options) {\n if (!(comp instanceof Comparator)) {\n throw new TypeError('a Comparator is required')\n }\n\n if (this.operator === '') {\n if (this.value === '') {\n return true\n }\n return new Range(comp.value, options).test(this.value)\n } else if (comp.operator === '') {\n if (comp.value === '') {\n return true\n }\n return new Range(this.value, options).test(comp.semver)\n }\n\n options = parseOptions(options)\n\n // Special cases where nothing can possibly be lower\n if (options.includePrerelease &&\n (this.value === '<0.0.0-0' || comp.value === '<0.0.0-0')) {\n return false\n }\n if (!options.includePrerelease &&\n (this.value.startsWith('<0.0.0') || comp.value.startsWith('<0.0.0'))) {\n return false\n }\n\n // Same direction increasing (> or >=)\n if (this.operator.startsWith('>') && comp.operator.startsWith('>')) {\n return true\n }\n // Same direction decreasing (< or <=)\n if (this.operator.startsWith('<') && comp.operator.startsWith('<')) {\n return true\n }\n // same SemVer and both sides are inclusive (<= or >=)\n if (\n (this.semver.version === comp.semver.version) &&\n this.operator.includes('=') && comp.operator.includes('=')) {\n return true\n }\n // opposite directions less than\n if (cmp(this.semver, '<', comp.semver, options) &&\n this.operator.startsWith('>') && comp.operator.startsWith('<')) {\n return true\n }\n // opposite directions greater than\n if (cmp(this.semver, '>', comp.semver, options) &&\n this.operator.startsWith('<') && comp.operator.startsWith('>')) {\n return true\n }\n return false\n }\n}\n\nmodule.exports = Comparator\n\nconst parseOptions = require('../internal/parse-options')\nconst { safeRe: re, t } = require('../internal/re')\nconst cmp = require('../functions/cmp')\nconst debug = require('../internal/debug')\nconst SemVer = require('./semver')\nconst Range = require('./range')\n","'use strict'\n\nconst Range = require('../classes/range')\nconst satisfies = (version, range, options) => {\n try {\n range = new Range(range, options)\n } catch (er) {\n return false\n }\n return range.test(version)\n}\nmodule.exports = satisfies\n","'use strict'\n\nconst Range = require('../classes/range')\n\n// Mostly just for testing and legacy API reasons\nconst toComparators = (range, options) =>\n new Range(range, options).set\n .map(comp => comp.map(c => c.value).join(' ').trim().split(' '))\n\nmodule.exports = toComparators\n","'use strict'\n\nconst SemVer = require('../classes/semver')\nconst Range = require('../classes/range')\n\nconst maxSatisfying = (versions, range, options) => {\n let max = null\n let maxSV = null\n let rangeObj = null\n try {\n rangeObj = new Range(range, options)\n } catch (er) {\n return null\n }\n versions.forEach((v) => {\n if (rangeObj.test(v)) {\n // satisfies(v, range, options)\n if (!max || maxSV.compare(v) === -1) {\n // compare(max, v, true)\n max = v\n maxSV = new SemVer(max, options)\n }\n }\n })\n return max\n}\nmodule.exports = maxSatisfying\n","'use strict'\n\nconst SemVer = require('../classes/semver')\nconst Range = require('../classes/range')\nconst minSatisfying = (versions, range, options) => {\n let min = null\n let minSV = null\n let rangeObj = null\n try {\n rangeObj = new Range(range, options)\n } catch (er) {\n return null\n }\n versions.forEach((v) => {\n if (rangeObj.test(v)) {\n // satisfies(v, range, options)\n if (!min || minSV.compare(v) === 1) {\n // compare(min, v, true)\n min = v\n minSV = new SemVer(min, options)\n }\n }\n })\n return min\n}\nmodule.exports = minSatisfying\n","'use strict'\n\nconst SemVer = require('../classes/semver')\nconst Range = require('../classes/range')\nconst gt = require('../functions/gt')\n\nconst minVersion = (range, loose) => {\n range = new Range(range, loose)\n\n let minver = new SemVer('0.0.0')\n if (range.test(minver)) {\n return minver\n }\n\n minver = new SemVer('0.0.0-0')\n if (range.test(minver)) {\n return minver\n }\n\n minver = null\n for (let i = 0; i < range.set.length; ++i) {\n const comparators = range.set[i]\n\n let setMin = null\n comparators.forEach((comparator) => {\n // Clone to avoid manipulating the comparator's semver object.\n const compver = new SemVer(comparator.semver.version)\n switch (comparator.operator) {\n case '>':\n if (compver.prerelease.length === 0) {\n compver.patch++\n } else {\n compver.prerelease.push(0)\n }\n compver.raw = compver.format()\n /* fallthrough */\n case '':\n case '>=':\n if (!setMin || gt(compver, setMin)) {\n setMin = compver\n }\n break\n case '<':\n case '<=':\n /* Ignore maximum versions */\n break\n /* istanbul ignore next */\n default:\n throw new Error(`Unexpected operation: ${comparator.operator}`)\n }\n })\n if (setMin && (!minver || gt(minver, setMin))) {\n minver = setMin\n }\n }\n\n if (minver && range.test(minver)) {\n return minver\n }\n\n return null\n}\nmodule.exports = minVersion\n","'use strict'\n\nconst Range = require('../classes/range')\nconst validRange = (range, options) => {\n try {\n // Return '*' instead of '' so that truthiness works.\n // This will throw if it's invalid anyway\n return new Range(range, options).range || '*'\n } catch (er) {\n return null\n }\n}\nmodule.exports = validRange\n","'use strict'\n\nconst SemVer = require('../classes/semver')\nconst Comparator = require('../classes/comparator')\nconst { ANY } = Comparator\nconst Range = require('../classes/range')\nconst satisfies = require('../functions/satisfies')\nconst gt = require('../functions/gt')\nconst lt = require('../functions/lt')\nconst lte = require('../functions/lte')\nconst gte = require('../functions/gte')\n\nconst outside = (version, range, hilo, options) => {\n version = new SemVer(version, options)\n range = new Range(range, options)\n\n let gtfn, ltefn, ltfn, comp, ecomp\n switch (hilo) {\n case '>':\n gtfn = gt\n ltefn = lte\n ltfn = lt\n comp = '>'\n ecomp = '>='\n break\n case '<':\n gtfn = lt\n ltefn = gte\n ltfn = gt\n comp = '<'\n ecomp = '<='\n break\n default:\n throw new TypeError('Must provide a hilo val of \"<\" or \">\"')\n }\n\n // If it satisfies the range it is not outside\n if (satisfies(version, range, options)) {\n return false\n }\n\n // From now on, variable terms are as if we're in \"gtr\" mode.\n // but note that everything is flipped for the \"ltr\" function.\n\n for (let i = 0; i < range.set.length; ++i) {\n const comparators = range.set[i]\n\n let high = null\n let low = null\n\n comparators.forEach((comparator) => {\n if (comparator.semver === ANY) {\n comparator = new Comparator('>=0.0.0')\n }\n high = high || comparator\n low = low || comparator\n if (gtfn(comparator.semver, high.semver, options)) {\n high = comparator\n } else if (ltfn(comparator.semver, low.semver, options)) {\n low = comparator\n }\n })\n\n // If the edge version comparator has a operator then our version\n // isn't outside it\n if (high.operator === comp || high.operator === ecomp) {\n return false\n }\n\n // If the lowest version comparator has an operator and our version\n // is less than it then it isn't higher than the range\n if ((!low.operator || low.operator === comp) &&\n ltefn(version, low.semver)) {\n return false\n } else if (low.operator === ecomp && ltfn(version, low.semver)) {\n return false\n }\n }\n return true\n}\n\nmodule.exports = outside\n","'use strict'\n\n// Determine if version is greater than all the versions possible in the range.\nconst outside = require('./outside')\nconst gtr = (version, range, options) => outside(version, range, '>', options)\nmodule.exports = gtr\n","'use strict'\n\nconst outside = require('./outside')\n// Determine if version is less than all the versions possible in the range\nconst ltr = (version, range, options) => outside(version, range, '<', options)\nmodule.exports = ltr\n","'use strict'\n\nconst Range = require('../classes/range')\nconst intersects = (r1, r2, options) => {\n r1 = new Range(r1, options)\n r2 = new Range(r2, options)\n return r1.intersects(r2, options)\n}\nmodule.exports = intersects\n","'use strict'\n\n// given a set of versions and a range, create a \"simplified\" range\n// that includes the same versions that the original range does\n// If the original range is shorter than the simplified one, return that.\nconst satisfies = require('../functions/satisfies.js')\nconst compare = require('../functions/compare.js')\nmodule.exports = (versions, range, options) => {\n const set = []\n let first = null\n let prev = null\n const v = versions.sort((a, b) => compare(a, b, options))\n for (const version of v) {\n const included = satisfies(version, range, options)\n if (included) {\n prev = version\n if (!first) {\n first = version\n }\n } else {\n if (prev) {\n set.push([first, prev])\n }\n prev = null\n first = null\n }\n }\n if (first) {\n set.push([first, null])\n }\n\n const ranges = []\n for (const [min, max] of set) {\n if (min === max) {\n ranges.push(min)\n } else if (!max && min === v[0]) {\n ranges.push('*')\n } else if (!max) {\n ranges.push(`>=${min}`)\n } else if (min === v[0]) {\n ranges.push(`<=${max}`)\n } else {\n ranges.push(`${min} - ${max}`)\n }\n }\n const simplified = ranges.join(' || ')\n const original = typeof range.raw === 'string' ? range.raw : String(range)\n return simplified.length < original.length ? simplified : range\n}\n","'use strict'\n\nconst Range = require('../classes/range.js')\nconst Comparator = require('../classes/comparator.js')\nconst { ANY } = Comparator\nconst satisfies = require('../functions/satisfies.js')\nconst compare = require('../functions/compare.js')\n\n// Complex range `r1 || r2 || ...` is a subset of `R1 || R2 || ...` iff:\n// - Every simple range `r1, r2, ...` is a null set, OR\n// - Every simple range `r1, r2, ...` which is not a null set is a subset of\n// some `R1, R2, ...`\n//\n// Simple range `c1 c2 ...` is a subset of simple range `C1 C2 ...` iff:\n// - If c is only the ANY comparator\n// - If C is only the ANY comparator, return true\n// - Else if in prerelease mode, return false\n// - else replace c with `[>=0.0.0]`\n// - If C is only the ANY comparator\n// - if in prerelease mode, return true\n// - else replace C with `[>=0.0.0]`\n// - Let EQ be the set of = comparators in c\n// - If EQ is more than one, return true (null set)\n// - Let GT be the highest > or >= comparator in c\n// - Let LT be the lowest < or <= comparator in c\n// - If GT and LT, and GT.semver > LT.semver, return true (null set)\n// - If any C is a = range, and GT or LT are set, return false\n// - If EQ\n// - If GT, and EQ does not satisfy GT, return true (null set)\n// - If LT, and EQ does not satisfy LT, return true (null set)\n// - If EQ satisfies every C, return true\n// - Else return false\n// - If GT\n// - If GT.semver is lower than any > or >= comp in C, return false\n// - If GT is >=, and GT.semver does not satisfy every C, return false\n// - If GT.semver has a prerelease, and not in prerelease mode\n// - If no C has a prerelease and the GT.semver tuple, return false\n// - If LT\n// - If LT.semver is greater than any < or <= comp in C, return false\n// - If LT is <=, and LT.semver does not satisfy every C, return false\n// - If GT.semver has a prerelease, and not in prerelease mode\n// - If no C has a prerelease and the LT.semver tuple, return false\n// - Else return true\n\nconst subset = (sub, dom, options = {}) => {\n if (sub === dom) {\n return true\n }\n\n sub = new Range(sub, options)\n dom = new Range(dom, options)\n let sawNonNull = false\n\n OUTER: for (const simpleSub of sub.set) {\n for (const simpleDom of dom.set) {\n const isSub = simpleSubset(simpleSub, simpleDom, options)\n sawNonNull = sawNonNull || isSub !== null\n if (isSub) {\n continue OUTER\n }\n }\n // the null set is a subset of everything, but null simple ranges in\n // a complex range should be ignored. so if we saw a non-null range,\n // then we know this isn't a subset, but if EVERY simple range was null,\n // then it is a subset.\n if (sawNonNull) {\n return false\n }\n }\n return true\n}\n\nconst minimumVersionWithPreRelease = [new Comparator('>=0.0.0-0')]\nconst minimumVersion = [new Comparator('>=0.0.0')]\n\nconst simpleSubset = (sub, dom, options) => {\n if (sub === dom) {\n return true\n }\n\n if (sub.length === 1 && sub[0].semver === ANY) {\n if (dom.length === 1 && dom[0].semver === ANY) {\n return true\n } else if (options.includePrerelease) {\n sub = minimumVersionWithPreRelease\n } else {\n sub = minimumVersion\n }\n }\n\n if (dom.length === 1 && dom[0].semver === ANY) {\n if (options.includePrerelease) {\n return true\n } else {\n dom = minimumVersion\n }\n }\n\n const eqSet = new Set()\n let gt, lt\n for (const c of sub) {\n if (c.operator === '>' || c.operator === '>=') {\n gt = higherGT(gt, c, options)\n } else if (c.operator === '<' || c.operator === '<=') {\n lt = lowerLT(lt, c, options)\n } else {\n eqSet.add(c.semver)\n }\n }\n\n if (eqSet.size > 1) {\n return null\n }\n\n let gtltComp\n if (gt && lt) {\n gtltComp = compare(gt.semver, lt.semver, options)\n if (gtltComp > 0) {\n return null\n } else if (gtltComp === 0 && (gt.operator !== '>=' || lt.operator !== '<=')) {\n return null\n }\n }\n\n // will iterate one or zero times\n for (const eq of eqSet) {\n if (gt && !satisfies(eq, String(gt), options)) {\n return null\n }\n\n if (lt && !satisfies(eq, String(lt), options)) {\n return null\n }\n\n for (const c of dom) {\n if (!satisfies(eq, String(c), options)) {\n return false\n }\n }\n\n return true\n }\n\n let higher, lower\n let hasDomLT, hasDomGT\n // if the subset has a prerelease, we need a comparator in the superset\n // with the same tuple and a prerelease, or it's not a subset\n let needDomLTPre = lt &&\n !options.includePrerelease &&\n lt.semver.prerelease.length ? lt.semver : false\n let needDomGTPre = gt &&\n !options.includePrerelease &&\n gt.semver.prerelease.length ? gt.semver : false\n // exception: <1.2.3-0 is the same as <1.2.3\n if (needDomLTPre && needDomLTPre.prerelease.length === 1 &&\n lt.operator === '<' && needDomLTPre.prerelease[0] === 0) {\n needDomLTPre = false\n }\n\n for (const c of dom) {\n hasDomGT = hasDomGT || c.operator === '>' || c.operator === '>='\n hasDomLT = hasDomLT || c.operator === '<' || c.operator === '<='\n if (gt) {\n if (needDomGTPre) {\n if (c.semver.prerelease && c.semver.prerelease.length &&\n c.semver.major === needDomGTPre.major &&\n c.semver.minor === needDomGTPre.minor &&\n c.semver.patch === needDomGTPre.patch) {\n needDomGTPre = false\n }\n }\n if (c.operator === '>' || c.operator === '>=') {\n higher = higherGT(gt, c, options)\n if (higher === c && higher !== gt) {\n return false\n }\n } else if (gt.operator === '>=' && !satisfies(gt.semver, String(c), options)) {\n return false\n }\n }\n if (lt) {\n if (needDomLTPre) {\n if (c.semver.prerelease && c.semver.prerelease.length &&\n c.semver.major === needDomLTPre.major &&\n c.semver.minor === needDomLTPre.minor &&\n c.semver.patch === needDomLTPre.patch) {\n needDomLTPre = false\n }\n }\n if (c.operator === '<' || c.operator === '<=') {\n lower = lowerLT(lt, c, options)\n if (lower === c && lower !== lt) {\n return false\n }\n } else if (lt.operator === '<=' && !satisfies(lt.semver, String(c), options)) {\n return false\n }\n }\n if (!c.operator && (lt || gt) && gtltComp !== 0) {\n return false\n }\n }\n\n // if there was a < or >, and nothing in the dom, then must be false\n // UNLESS it was limited by another range in the other direction.\n // Eg, >1.0.0 <1.0.1 is still a subset of <2.0.0\n if (gt && hasDomLT && !lt && gtltComp !== 0) {\n return false\n }\n\n if (lt && hasDomGT && !gt && gtltComp !== 0) {\n return false\n }\n\n // we needed a prerelease range in a specific tuple, but didn't get one\n // then this isn't a subset. eg >=1.2.3-pre is not a subset of >=1.0.0,\n // because it includes prereleases in the 1.2.3 tuple\n if (needDomGTPre || needDomLTPre) {\n return false\n }\n\n return true\n}\n\n// >=1.2.3 is lower than >1.2.3\nconst higherGT = (a, b, options) => {\n if (!a) {\n return b\n }\n const comp = compare(a.semver, b.semver, options)\n return comp > 0 ? a\n : comp < 0 ? b\n : b.operator === '>' && a.operator === '>=' ? b\n : a\n}\n\n// <=1.2.3 is higher than <1.2.3\nconst lowerLT = (a, b, options) => {\n if (!a) {\n return b\n }\n const comp = compare(a.semver, b.semver, options)\n return comp < 0 ? a\n : comp > 0 ? b\n : b.operator === '<' && a.operator === '<=' ? b\n : a\n}\n\nmodule.exports = subset\n","'use strict'\n\n// just pre-load all the stuff that index.js lazily exports\nconst internalRe = require('./internal/re')\nconst constants = require('./internal/constants')\nconst SemVer = require('./classes/semver')\nconst identifiers = require('./internal/identifiers')\nconst parse = require('./functions/parse')\nconst valid = require('./functions/valid')\nconst clean = require('./functions/clean')\nconst inc = require('./functions/inc')\nconst diff = require('./functions/diff')\nconst major = require('./functions/major')\nconst minor = require('./functions/minor')\nconst patch = require('./functions/patch')\nconst prerelease = require('./functions/prerelease')\nconst compare = require('./functions/compare')\nconst rcompare = require('./functions/rcompare')\nconst compareLoose = require('./functions/compare-loose')\nconst compareBuild = require('./functions/compare-build')\nconst sort = require('./functions/sort')\nconst rsort = require('./functions/rsort')\nconst gt = require('./functions/gt')\nconst lt = require('./functions/lt')\nconst eq = require('./functions/eq')\nconst neq = require('./functions/neq')\nconst gte = require('./functions/gte')\nconst lte = require('./functions/lte')\nconst cmp = require('./functions/cmp')\nconst coerce = require('./functions/coerce')\nconst Comparator = require('./classes/comparator')\nconst Range = require('./classes/range')\nconst satisfies = require('./functions/satisfies')\nconst toComparators = require('./ranges/to-comparators')\nconst maxSatisfying = require('./ranges/max-satisfying')\nconst minSatisfying = require('./ranges/min-satisfying')\nconst minVersion = require('./ranges/min-version')\nconst validRange = require('./ranges/valid')\nconst outside = require('./ranges/outside')\nconst gtr = require('./ranges/gtr')\nconst ltr = require('./ranges/ltr')\nconst intersects = require('./ranges/intersects')\nconst simplifyRange = require('./ranges/simplify')\nconst subset = require('./ranges/subset')\nmodule.exports = {\n parse,\n valid,\n clean,\n inc,\n diff,\n major,\n minor,\n patch,\n prerelease,\n compare,\n rcompare,\n compareLoose,\n compareBuild,\n sort,\n rsort,\n gt,\n lt,\n eq,\n neq,\n gte,\n lte,\n cmp,\n coerce,\n Comparator,\n Range,\n satisfies,\n toComparators,\n maxSatisfying,\n minSatisfying,\n minVersion,\n validRange,\n outside,\n gtr,\n ltr,\n intersects,\n simplifyRange,\n subset,\n SemVer,\n re: internalRe.re,\n src: internalRe.src,\n tokens: internalRe.t,\n SEMVER_SPEC_VERSION: constants.SEMVER_SPEC_VERSION,\n RELEASE_TYPES: constants.RELEASE_TYPES,\n compareIdentifiers: identifiers.compareIdentifiers,\n rcompareIdentifiers: identifiers.rcompareIdentifiers,\n}\n","import { exec, spawn } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport type { EventBus } from \"@services/EventBus.js\";\nimport { getEventBus } from \"@services/EventBus.js\";\nimport semver from \"semver\";\n\nconst execAsync = promisify(exec);\n\nexport class NPMManager {\n private eventBus: EventBus;\n\n constructor(eventBus?: EventBus) {\n this.eventBus = eventBus || getEventBus();\n }\n\n /**\n * 安装指定版本 - 这是核心功能\n */\n async installVersion(version: string): Promise<void> {\n const installId = `install-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n const startTime = Date.now();\n\n console.log(\"开始安装\", { version, installId });\n\n // 发射安装开始事件\n this.eventBus.emitEvent(\"npm:install:started\", {\n version,\n installId,\n timestamp: Date.now(),\n });\n\n const npmProcess = spawn(\"npm\", [\n \"install\",\n \"-g\",\n `xiaozhi-client@${version}`,\n \"--registry=https://registry.npmmirror.com\",\n ]);\n\n return new Promise((resolve, reject) => {\n npmProcess.stdout.on(\"data\", (data) => {\n const message = data.toString();\n\n // 发射日志事件\n this.eventBus.emitEvent(\"npm:install:log\", {\n version,\n installId,\n type: \"stdout\",\n message,\n timestamp: Date.now(),\n });\n });\n\n npmProcess.stderr.on(\"data\", (data) => {\n const message = data.toString();\n\n // 发射日志事件\n this.eventBus.emitEvent(\"npm:install:log\", {\n version,\n installId,\n type: \"stderr\",\n message,\n timestamp: Date.now(),\n });\n });\n\n npmProcess.on(\"close\", (code) => {\n const duration = Date.now() - startTime;\n\n if (code === 0) {\n // 发射安装完成事件\n this.eventBus.emitEvent(\"npm:install:completed\", {\n version,\n installId,\n success: true,\n duration,\n timestamp: Date.now(),\n });\n\n resolve();\n } else {\n const error = `安装失败,退出码: ${code}`;\n console.log(error);\n\n // 发射安装失败事件\n this.eventBus.emitEvent(\"npm:install:failed\", {\n version,\n installId,\n error,\n duration,\n timestamp: Date.now(),\n });\n\n reject(new Error(error));\n }\n });\n });\n }\n\n /**\n * 获取当前版本\n */\n async getCurrentVersion(): Promise<string> {\n const { stdout } = await execAsync(\n \"npm list -g xiaozhi-client --depth=0 --json --registry=https://registry.npmmirror.com\"\n );\n const info = JSON.parse(stdout);\n return info.dependencies?.[\"xiaozhi-client\"]?.version || \"unknown\";\n }\n\n /**\n * 版本类型枚举\n */\n static readonly VERSION_TYPES = {\n STABLE: \"stable\",\n RC: \"rc\",\n BETA: \"beta\",\n ALL: \"all\",\n } as const;\n\n /**\n * 获取可用版本列表\n */\n async getAvailableVersions(type = \"stable\"): Promise<string[]> {\n try {\n const { stdout } = await execAsync(\n \"npm view xiaozhi-client versions --json --registry=https://registry.npmmirror.com\"\n );\n\n const versions = JSON.parse(stdout) as string[];\n\n // 使用 semver 验证并过滤有效版本\n let filteredVersions = versions.filter((version) => {\n return version && typeof version === \"string\" && semver.valid(version);\n });\n\n // 根据类型过滤版本\n if (type !== \"all\") {\n filteredVersions = filteredVersions.filter((version) => {\n const prerelease = semver.prerelease(version);\n\n if (type === \"stable\") {\n // 正式版:没有预发布标识符的版本 (x.y.z)\n return prerelease === null;\n }\n\n if (type === \"rc\") {\n // 预览版:预发布标识符以 rc 开头\n return (\n prerelease !== null &&\n prerelease[0]?.toString()?.toLowerCase()?.startsWith(\"rc\") ===\n true\n );\n }\n\n if (type === \"beta\") {\n // 测试版:预发布标识符以 beta 开头\n return (\n prerelease !== null &&\n prerelease[0]?.toString()?.toLowerCase()?.startsWith(\"beta\") ===\n true\n );\n }\n\n return true;\n });\n }\n\n // 进行降序排列(最新的在前)\n return filteredVersions.sort((a, b) => semver.rcompare(a, b));\n } catch (error) {\n console.log(\"获取版本列表失败\", { error });\n // 如果获取失败,返回一些默认版本\n return [];\n }\n }\n\n /**\n * 检查是否有最新版本\n * 返回当前版本、最新版本以及是否有更新\n */\n async checkForLatestVersion(): Promise<{\n currentVersion: string;\n latestVersion: string | null;\n hasUpdate: boolean;\n error?: string;\n }> {\n try {\n // 获取当前版本\n const currentVersion = await this.getCurrentVersion();\n\n // 如果无法获取当前版本,返回错误\n if (!currentVersion || currentVersion === \"unknown\") {\n return {\n currentVersion: \"unknown\",\n latestVersion: null,\n hasUpdate: false,\n error: \"无法获取当前版本信息\",\n };\n }\n\n // 获取最新的正式版本\n const stableVersions = await this.getAvailableVersions(\"stable\");\n\n if (stableVersions.length === 0) {\n return {\n currentVersion,\n latestVersion: null,\n hasUpdate: false,\n error: \"无法获取可用版本列表\",\n };\n }\n\n // 获取最新的正式版本(第一个元素)\n const latestVersion = stableVersions[0];\n\n // 比较版本\n let hasUpdate = false;\n try {\n // 使用 semver 比较版本\n hasUpdate = semver.gt(latestVersion, currentVersion);\n } catch (error) {\n console.log(\"版本比较失败\", { error });\n // 如果比较失败,尝试字符串比较\n hasUpdate = latestVersion !== currentVersion;\n }\n\n console.log(\"版本检查完成\", { currentVersion, latestVersion, hasUpdate });\n\n return {\n currentVersion,\n latestVersion,\n hasUpdate,\n };\n } catch (error) {\n console.log(\"检查最新版本失败\", { error });\n return {\n currentVersion: \"unknown\",\n latestVersion: null,\n hasUpdate: false,\n error:\n error instanceof Error ? error.message : \"检查更新时发生未知错误\",\n };\n }\n }\n}\n","export * from \"./manager.js\";\n","import { NPMManager } from \"@/lib/npm\";\nimport { logger } from \"@root/Logger.js\";\nimport { getEventBus } from \"@services/EventBus.js\";\nimport type { Context } from \"hono\";\nimport { z } from \"zod\";\n\n// 版本号请求格式验证\nconst UpdateRequestSchema = z.object({\n version: z.string().min(1, \"版本号不能为空\"),\n});\n\nexport class UpdateApiHandler {\n private npmManager: NPMManager;\n private logger = logger;\n private eventBus = getEventBus();\n private activeInstalls: Map<string, boolean> = new Map();\n\n constructor() {\n this.npmManager = new NPMManager(this.eventBus);\n }\n\n /**\n * 执行版本更新\n * POST /api/update\n * Body: { version: string }\n */\n async performUpdate(c: Context): Promise<Response> {\n try {\n const body = await c.req.json();\n\n // 使用 zod 进行参数验证\n const parseResult = UpdateRequestSchema.safeParse(body);\n if (!parseResult.success) {\n return c.json(\n {\n success: false,\n error: {\n code: \"INVALID_VERSION\",\n message: \"请求参数格式错误\",\n details: parseResult.error.errors.map((err) => ({\n field: err.path.join(\".\"),\n message: err.message,\n })),\n },\n },\n 400\n );\n }\n\n const { version } = parseResult.data;\n\n // 检查是否有正在进行的安装\n const hasActiveInstall = Array.from(this.activeInstalls.values()).some(\n (v) => v\n );\n if (hasActiveInstall) {\n return c.json(\n {\n success: false,\n error: {\n code: \"INSTALL_IN_PROGRESS\",\n message: \"已有安装进程正在进行,请等待完成后再试\",\n },\n },\n 409\n );\n }\n\n // 立即返回响应,安装过程通过 WebSocket 推送\n this.npmManager.installVersion(version).catch((error) => {\n this.logger.error(\"安装过程失败:\", error);\n });\n\n return c.json({\n success: true,\n data: {\n version: version,\n message: \"安装已启动,请查看实时日志\",\n },\n message: \"安装请求已接受\",\n });\n } catch (error) {\n this.logger.error(\"处理安装请求失败:\", error);\n return c.json(\n {\n success: false,\n error: {\n code: \"REQUEST_FAILED\",\n message: error instanceof Error ? error.message : \"请求处理失败\",\n },\n },\n 500\n );\n }\n }\n}\n","import { NPMManager } from \"@/lib/npm\";\nimport { VersionUtils } from \"@cli/utils/VersionUtils.js\";\nimport type { Logger } from \"@root/Logger.js\";\nimport { logger } from \"@root/Logger.js\";\nimport type { Context } from \"hono\";\n\n/**\n * 统一响应格式接口\n */\ninterface ApiErrorResponse {\n error: {\n code: string;\n message: string;\n details?: unknown;\n };\n}\n\ninterface ApiSuccessResponse<T = unknown> {\n success: boolean;\n data?: T;\n message?: string;\n}\n\n/**\n * 版本 API 处理器\n */\nexport class VersionApiHandler {\n private logger: Logger;\n\n constructor() {\n this.logger = logger;\n }\n\n /**\n * 创建统一的错误响应\n */\n private createErrorResponse(\n code: string,\n message: string,\n details?: unknown\n ): ApiErrorResponse {\n return {\n error: {\n code,\n message,\n details,\n },\n };\n }\n\n /**\n * 创建统一的成功响应\n */\n private createSuccessResponse<T>(\n data?: T,\n message?: string\n ): ApiSuccessResponse<T> {\n return {\n success: true,\n data,\n message,\n };\n }\n\n /**\n * 获取版本信息\n * GET /api/version\n */\n async getVersion(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理获取版本信息请求\");\n\n // 使用 VersionUtils 获取完整版本信息\n const versionInfo = VersionUtils.getVersionInfo();\n\n this.logger.debug(\"获取版本信息成功:\", versionInfo);\n\n return c.json(this.createSuccessResponse(versionInfo));\n } catch (error) {\n this.logger.error(\"获取版本信息失败:\", error);\n\n const errorResponse = this.createErrorResponse(\n \"VERSION_READ_ERROR\",\n error instanceof Error ? error.message : \"获取版本信息失败\"\n );\n\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 获取版本号(简化接口)\n * GET /api/version/simple\n */\n async getVersionSimple(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理获取版本号请求\");\n\n const version = VersionUtils.getVersion();\n this.logger.debug(`获取版本号成功: ${version}`);\n\n return c.json(this.createSuccessResponse({ version }));\n } catch (error) {\n this.logger.error(\"获取版本号失败:\", error);\n\n const errorResponse = this.createErrorResponse(\n \"VERSION_READ_ERROR\",\n error instanceof Error ? error.message : \"获取版本号失败\"\n );\n\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 清除版本缓存\n * POST /api/version/cache/clear\n */\n async clearVersionCache(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理清除版本缓存请求\");\n\n VersionUtils.clearCache();\n this.logger.info(\"版本缓存已清除\");\n\n return c.json(this.createSuccessResponse(null, \"版本缓存已清除\"));\n } catch (error) {\n this.logger.error(\"清除版本缓存失败:\", error);\n\n const errorResponse = this.createErrorResponse(\n \"CACHE_CLEAR_ERROR\",\n error instanceof Error ? error.message : \"清除版本缓存失败\"\n );\n\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 获取可用版本列表\n * GET /api/version/available?type=stable|rc|beta|all\n */\n async getAvailableVersions(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理获取可用版本列表请求\");\n\n // 获取查询参数\n const type = (c.req.query(\"type\") as unknown) || \"stable\";\n\n // 验证版本类型参数\n const validTypes = [\"stable\", \"rc\", \"beta\", \"all\"];\n if (!validTypes.includes(type as string)) {\n const errorResponse = this.createErrorResponse(\n \"INVALID_VERSION_TYPE\",\n `无效的版本类型: ${type}。支持的类型: ${validTypes.join(\", \")}`\n );\n return c.json(errorResponse, 400);\n }\n\n const npmManager = new NPMManager();\n const versions = await npmManager.getAvailableVersions(type as string);\n\n this.logger.debug(`获取到 ${versions.length} 个可用版本 (类型: ${type})`);\n\n return c.json(\n this.createSuccessResponse({\n versions,\n type,\n total: versions.length,\n })\n );\n } catch (error) {\n this.logger.error(\"获取可用版本列表失败:\", error);\n\n const errorResponse = this.createErrorResponse(\n \"VERSIONS_FETCH_ERROR\",\n error instanceof Error ? error.message : \"获取可用版本列表失败\"\n );\n\n return c.json(errorResponse, 500);\n }\n }\n\n /**\n * 检查最新版本\n * GET /api/version/latest\n */\n async checkLatestVersion(c: Context): Promise<Response> {\n try {\n this.logger.debug(\"处理检查最新版本请求\");\n\n const npmManager = new NPMManager();\n const result = await npmManager.checkForLatestVersion();\n\n this.logger.debug(\"版本检查结果:\", result);\n\n if (result.error) {\n // 如果有错误,但仍返回部分信息\n return c.json(\n this.createSuccessResponse({\n currentVersion: result.currentVersion,\n latestVersion: result.latestVersion,\n hasUpdate: result.hasUpdate,\n error: result.error,\n })\n );\n }\n\n return c.json(\n this.createSuccessResponse({\n currentVersion: result.currentVersion,\n latestVersion: result.latestVersion,\n hasUpdate: result.hasUpdate,\n })\n );\n } catch (error) {\n this.logger.error(\"检查最新版本失败:\", error);\n\n const errorResponse = this.createErrorResponse(\n \"LATEST_VERSION_CHECK_ERROR\",\n error instanceof Error ? error.message : \"检查最新版本失败\"\n );\n\n return c.json(errorResponse, 500);\n }\n }\n}\n","export * from \"./ConfigApiHandler.js\";\nexport * from \"./CozeApiHandler.js\";\nexport * from \"./HeartbeatHandler.js\";\nexport * from \"./MCPEndpointApiHandler.js\";\nexport * from \"./MCPRouteHandler.js\";\nexport * from \"./MCPServerApiHandler.js\";\nexport * from \"./RealtimeNotificationHandler.js\";\nexport * from \"./ServiceApiHandler.js\";\nexport * from \"./StaticFileHandler.js\";\nexport * from \"./StatusApiHandler.js\";\nexport * from \"./ToolApiHandler.js\";\nexport * from \"./ToolCallLogApiHandler.js\";\nexport * from \"./UpdateApiHandler.js\";\nexport * from \"./VersionApiHandler.js\";\n","import type { Logger } from \"@root/Logger.js\";\nimport { logger } from \"@root/Logger.js\";\nimport type { EventBus } from \"@services/EventBus.js\";\nimport { getEventBus } from \"@services/EventBus.js\";\n\n/**\n * 客户端信息接口\n */\nexport interface ClientInfo {\n status: \"connected\" | \"disconnected\";\n mcpEndpoint: string;\n activeMCPServers: string[];\n lastHeartbeat?: number;\n}\n\n/**\n * 重启状态接口\n */\nexport interface RestartStatus {\n status: \"restarting\" | \"completed\" | \"failed\";\n error?: string;\n timestamp: number;\n serviceName?: string;\n attempt?: number;\n}\n\n/**\n * 状态服务 - 统一的状态管理服务\n */\nexport class StatusService {\n private logger: Logger;\n private eventBus: EventBus;\n private clientInfo: ClientInfo = {\n status: \"disconnected\",\n mcpEndpoint: \"\",\n activeMCPServers: [],\n };\n private restartStatus?: RestartStatus;\n private heartbeatTimeout?: NodeJS.Timeout;\n private readonly HEARTBEAT_TIMEOUT = 35000; // 35 seconds\n\n constructor() {\n this.logger = logger;\n this.eventBus = getEventBus();\n }\n\n /**\n * 获取客户端状态\n */\n getClientStatus(): ClientInfo {\n return { ...this.clientInfo };\n }\n\n /**\n * 更新客户端信息\n */\n updateClientInfo(info: Partial<ClientInfo>, source = \"unknown\"): void {\n try {\n const oldStatus = { ...this.clientInfo };\n this.clientInfo = { ...this.clientInfo, ...info };\n\n if (info.lastHeartbeat) {\n this.clientInfo.lastHeartbeat = Date.now();\n }\n\n // Reset heartbeat timeout when receiving client status\n if (info.status === \"connected\") {\n this.resetHeartbeatTimeout();\n }\n\n this.logger.debug(`客户端状态更新,来源: ${source}`, {\n old: oldStatus,\n new: this.clientInfo,\n });\n\n // 发射状态更新事件\n this.eventBus.emitEvent(\"status:updated\", {\n status: this.clientInfo,\n source,\n });\n } catch (error) {\n this.logger.error(\"更新客户端状态失败:\", error);\n this.eventBus.emitEvent(\"status:error\", {\n error: error instanceof Error ? error : new Error(String(error)),\n operation: \"updateClientInfo\",\n });\n }\n }\n\n /**\n * 获取重启状态\n */\n getRestartStatus(): RestartStatus | undefined {\n return this.restartStatus ? { ...this.restartStatus } : undefined;\n }\n\n /**\n * 更新重启状态\n */\n updateRestartStatus(\n status: \"restarting\" | \"completed\" | \"failed\",\n error?: string\n ): void {\n try {\n this.restartStatus = {\n status,\n error,\n timestamp: Date.now(),\n };\n\n this.logger.info(`重启状态更新: ${status}`, { error });\n\n // 根据状态发射不同的事件\n switch (status) {\n case \"restarting\":\n this.eventBus.emitEvent(\"service:restart:started\", {\n serviceName: this.restartStatus.serviceName || \"\",\n attempt: this.restartStatus.attempt || 1,\n timestamp: this.restartStatus.timestamp,\n });\n break;\n case \"completed\":\n this.eventBus.emitEvent(\"service:restart:completed\", {\n serviceName: this.restartStatus.serviceName || \"\",\n attempt: this.restartStatus.attempt || 1,\n timestamp: this.restartStatus.timestamp,\n });\n break;\n case \"failed\":\n this.eventBus.emitEvent(\"service:restart:failed\", {\n serviceName: this.restartStatus.serviceName || \"\",\n error: new Error(error || \"重启失败\"),\n attempt: this.restartStatus.attempt || 1,\n timestamp: this.restartStatus.timestamp,\n });\n break;\n }\n } catch (error) {\n this.logger.error(\"更新重启状态失败:\", error);\n this.eventBus.emitEvent(\"status:error\", {\n error: error instanceof Error ? error : new Error(String(error)),\n operation: \"updateRestartStatus\",\n });\n }\n }\n\n /**\n * 获取完整状态信息\n */\n getFullStatus(): {\n client: ClientInfo;\n restart?: RestartStatus;\n timestamp: number;\n } {\n return {\n client: this.getClientStatus(),\n restart: this.getRestartStatus(),\n timestamp: Date.now(),\n };\n }\n\n /**\n * 重置心跳超时\n */\n private resetHeartbeatTimeout(): void {\n // Clear existing timeout\n if (this.heartbeatTimeout) {\n clearTimeout(this.heartbeatTimeout);\n }\n\n // Set new timeout\n this.heartbeatTimeout = setTimeout(() => {\n this.logger.warn(\"客户端心跳超时,标记为断开连接\");\n this.updateClientInfo({ status: \"disconnected\" }, \"heartbeat-timeout\");\n }, this.HEARTBEAT_TIMEOUT);\n }\n\n /**\n * 清除心跳超时\n */\n clearHeartbeatTimeout(): void {\n if (this.heartbeatTimeout) {\n clearTimeout(this.heartbeatTimeout);\n this.heartbeatTimeout = undefined;\n }\n }\n\n /**\n * 检查客户端是否连接\n */\n isClientConnected(): boolean {\n return this.clientInfo.status === \"connected\";\n }\n\n /**\n * 获取最后心跳时间\n */\n getLastHeartbeat(): number | undefined {\n return this.clientInfo.lastHeartbeat;\n }\n\n /**\n * 获取活跃的 MCP 服务器列表\n */\n getActiveMCPServers(): string[] {\n return [...this.clientInfo.activeMCPServers];\n }\n\n /**\n * 设置活跃的 MCP 服务器列表\n */\n setActiveMCPServers(servers: string[]): void {\n this.updateClientInfo(\n { activeMCPServers: [...servers] },\n \"mcp-servers-update\"\n );\n }\n\n /**\n * 设置 MCP 端点\n */\n setMcpEndpoint(endpoint: string): void {\n this.updateClientInfo({ mcpEndpoint: endpoint }, \"mcp-endpoint-update\");\n }\n\n /**\n * 重置状态\n */\n reset(): void {\n this.logger.info(\"重置状态服务\");\n this.clearHeartbeatTimeout();\n this.clientInfo = {\n status: \"disconnected\",\n mcpEndpoint: \"\",\n activeMCPServers: [],\n };\n this.restartStatus = undefined;\n }\n\n /**\n * 销毁状态服务\n */\n destroy(): void {\n this.logger.info(\"销毁状态服务\");\n this.clearHeartbeatTimeout();\n this.reset();\n }\n}\n","import type { AppConfig } from \"@/lib/config/manager.js\";\nimport { configManager } from \"@/lib/config/manager.js\";\nimport type { Logger } from \"@root/Logger.js\";\nimport { logger } from \"@root/Logger.js\";\nimport type { EventBus } from \"@services/EventBus.js\";\nimport { getEventBus } from \"@services/EventBus.js\";\nimport type { ClientInfo, RestartStatus } from \"@services/StatusService.js\";\n\n/**\n * WebSocket 客户端接口\n */\nexport interface WebSocketClient {\n id: string;\n ws: any; // WebSocket 实例\n readyState: number;\n send: (data: string) => void;\n}\n\n/**\n * 通知消息接口\n */\nexport interface NotificationMessage {\n type: string;\n data?: any;\n timestamp?: number;\n}\n\n/**\n * 通知服务 - 统一的通知管理服务\n */\nexport class NotificationService {\n private logger: Logger;\n private eventBus: EventBus;\n private clients: Map<string, WebSocketClient> = new Map();\n private messageQueue: Map<string, NotificationMessage[]> = new Map();\n private maxQueueSize = 100;\n\n constructor() {\n this.logger = logger;\n this.eventBus = getEventBus();\n this.setupEventListeners();\n }\n\n /**\n * 设置事件监听器\n */\n private setupEventListeners(): void {\n // 监听配置更新事件\n this.eventBus.onEvent(\"config:updated\", (data) => {\n // 获取最新的配置\n const config = configManager.getConfig();\n this.broadcastConfigUpdate(config);\n });\n\n // 监听状态更新事件\n this.eventBus.onEvent(\"status:updated\", (data) => {\n this.broadcastStatusUpdate(data.status);\n });\n\n // 监听重启状态事件\n this.eventBus.onEvent(\"service:restart:started\", (data) => {\n this.broadcastRestartStatus(\"restarting\", undefined, data.timestamp);\n });\n\n this.eventBus.onEvent(\"service:restart:completed\", (data) => {\n this.broadcastRestartStatus(\"completed\", undefined, data.timestamp);\n });\n\n this.eventBus.onEvent(\"service:restart:failed\", (data) => {\n this.broadcastRestartStatus(\"failed\", data.error.message, data.timestamp);\n });\n\n // 监听 NPM 安装事件\n this.eventBus.onEvent(\"npm:install:started\", (data) => {\n this.broadcast(\"npm:install:started\", data);\n });\n\n this.eventBus.onEvent(\"npm:install:log\", (data) => {\n this.broadcast(\"npm:install:log\", data);\n });\n\n this.eventBus.onEvent(\"npm:install:completed\", (data) => {\n this.broadcast(\"npm:install:completed\", data);\n });\n\n this.eventBus.onEvent(\"npm:install:failed\", (data) => {\n this.broadcast(\"npm:install:failed\", data);\n });\n\n // 监听通知广播事件\n this.eventBus.onEvent(\"notification:broadcast\", (data) => {\n if (data.target) {\n this.sendToClient(data.target, data.type, data.data);\n } else {\n this.broadcast(data.type, data.data);\n }\n });\n }\n\n /**\n * 注册 WebSocket 客户端\n */\n registerClient(clientId: string, ws: any): void {\n try {\n const client: WebSocketClient = {\n id: clientId,\n ws,\n readyState: ws.readyState,\n send: (data: string) => {\n if (ws.readyState === 1) {\n // WebSocket.OPEN\n ws.send(data);\n }\n },\n };\n\n this.clients.set(clientId, client);\n this.logger.info(`WebSocket 客户端已注册: ${clientId}`);\n this.logger.debug(`当前客户端数量: ${this.clients.size}`);\n\n // 发送排队的消息\n this.sendQueuedMessages(clientId);\n\n // 发射客户端连接事件\n this.eventBus.emitEvent(\"websocket:client:connected\", {\n clientId,\n timestamp: Date.now(),\n });\n } catch (error) {\n this.logger.error(`注册客户端失败: ${clientId}`, error);\n this.eventBus.emitEvent(\"notification:error\", {\n error: error instanceof Error ? error : new Error(String(error)),\n type: \"client:register\",\n });\n }\n }\n\n /**\n * 注销 WebSocket 客户端\n */\n unregisterClient(clientId: string): void {\n try {\n if (this.clients.has(clientId)) {\n this.clients.delete(clientId);\n this.messageQueue.delete(clientId);\n this.logger.info(`WebSocket 客户端已注销: ${clientId}`);\n this.logger.debug(`剩余客户端数量: ${this.clients.size}`);\n\n // 发射客户端断开事件\n this.eventBus.emitEvent(\"websocket:client:disconnected\", {\n clientId,\n timestamp: Date.now(),\n });\n }\n } catch (error) {\n this.logger.error(`注销客户端失败: ${clientId}`, error);\n }\n }\n\n /**\n * 广播消息给所有客户端\n */\n broadcast(type: string, data?: any): void {\n const message: NotificationMessage = {\n type,\n data,\n timestamp: Date.now(),\n };\n\n this.logger.debug(`广播消息: ${type}`, { clientCount: this.clients.size });\n\n for (const [clientId, client] of this.clients) {\n this.sendMessageToClient(client, message, clientId);\n }\n }\n\n /**\n * 发送消息给特定客户端\n */\n sendToClient(clientId: string, type: string, data?: any): void {\n const message: NotificationMessage = {\n type,\n data,\n timestamp: Date.now(),\n };\n\n const client = this.clients.get(clientId);\n if (client) {\n this.sendMessageToClient(client, message, clientId);\n } else {\n // 客户端不在线,将消息加入队列\n this.queueMessage(clientId, message);\n }\n }\n\n /**\n * 发送消息给客户端\n */\n private sendMessageToClient(\n client: WebSocketClient,\n message: NotificationMessage,\n clientId: string\n ): void {\n try {\n if (client.ws.readyState === 1) {\n // WebSocket.OPEN\n const messageStr = JSON.stringify(message);\n client.send(messageStr);\n this.logger.debug(`消息已发送给客户端 ${clientId}: ${message.type}`);\n } else {\n // 连接不可用,将消息加入队列\n this.queueMessage(clientId, message);\n this.logger.warn(`客户端 ${clientId} 连接不可用,消息已加入队列`);\n }\n } catch (error) {\n this.logger.error(`发送消息给客户端 ${clientId} 失败:`, error);\n this.queueMessage(clientId, message);\n this.eventBus.emitEvent(\"notification:error\", {\n error: error instanceof Error ? error : new Error(String(error)),\n type: \"message:send\",\n });\n }\n }\n\n /**\n * 将消息加入队列\n */\n private queueMessage(clientId: string, message: NotificationMessage): void {\n if (!this.messageQueue.has(clientId)) {\n this.messageQueue.set(clientId, []);\n }\n\n const queue = this.messageQueue.get(clientId)!;\n queue.push(message);\n\n // 限制队列大小\n if (queue.length > this.maxQueueSize) {\n queue.shift(); // 移除最旧的消息\n this.logger.warn(`客户端 ${clientId} 消息队列已满,移除最旧消息`);\n }\n }\n\n /**\n * 发送排队的消息\n */\n private sendQueuedMessages(clientId: string): void {\n const queue = this.messageQueue.get(clientId);\n if (!queue || queue.length === 0) {\n return;\n }\n\n const client = this.clients.get(clientId);\n if (!client) {\n return;\n }\n\n this.logger.info(`发送 ${queue.length} 条排队消息给客户端 ${clientId}`);\n\n for (const message of queue) {\n this.sendMessageToClient(client, message, clientId);\n }\n\n // 清空队列\n this.messageQueue.delete(clientId);\n }\n\n /**\n * 广播配置更新\n */\n broadcastConfigUpdate(config: AppConfig): void {\n this.broadcast(\"configUpdate\", config);\n }\n\n /**\n * 广播状态更新\n */\n broadcastStatusUpdate(status: ClientInfo): void {\n this.broadcast(\"statusUpdate\", status);\n }\n\n /**\n * 广播重启状态\n */\n broadcastRestartStatus(\n status: \"restarting\" | \"completed\" | \"failed\",\n error?: string,\n timestamp?: number\n ): void {\n const restartStatus: RestartStatus = {\n status,\n error,\n timestamp: timestamp || Date.now(),\n };\n\n this.broadcast(\"restartStatus\", restartStatus);\n }\n\n /**\n * 获取客户端统计信息\n */\n getClientStats(): {\n totalClients: number;\n connectedClients: number;\n queuedMessages: number;\n } {\n const connectedClients = Array.from(this.clients.values()).filter(\n (client) => client.ws.readyState === 1\n ).length;\n\n const queuedMessages = Array.from(this.messageQueue.values()).reduce(\n (total, queue) => total + queue.length,\n 0\n );\n\n return {\n totalClients: this.clients.size,\n connectedClients,\n queuedMessages,\n };\n }\n\n /**\n * 清理断开的客户端\n */\n cleanupDisconnectedClients(): void {\n const disconnectedClients: string[] = [];\n\n for (const [clientId, client] of this.clients) {\n if (client.ws.readyState !== 1) {\n // Not WebSocket.OPEN\n disconnectedClients.push(clientId);\n }\n }\n\n for (const clientId of disconnectedClients) {\n this.unregisterClient(clientId);\n }\n\n if (disconnectedClients.length > 0) {\n this.logger.info(`清理了 ${disconnectedClients.length} 个断开的客户端`);\n }\n }\n\n /**\n * 销毁通知服务\n */\n destroy(): void {\n this.logger.info(\"销毁通知服务\");\n this.clients.clear();\n this.messageQueue.clear();\n }\n}\n","import type { Logger } from \"@root/Logger.js\";\nimport { logger } from \"@root/Logger.js\";\n\n/**\n * 错误分类枚举\n */\nexport enum ErrorCategory {\n CONNECTION = \"connection\",\n TRANSPORT = \"transport\",\n TOOL_CALL = \"tool_call\",\n CONFIGURATION = \"configuration\",\n TIMEOUT = \"timeout\",\n AUTHENTICATION = \"authentication\",\n NETWORK = \"network\",\n UNKNOWN = \"unknown\",\n}\n\n/**\n * 恢复策略枚举\n */\nexport enum RecoveryStrategy {\n RETRY = \"retry\",\n RECONNECT = \"reconnect\",\n RESTART_SERVICE = \"restart_service\",\n IGNORE = \"ignore\",\n MANUAL_INTERVENTION = \"manual_intervention\",\n}\n\n/**\n * MCP 错误接口\n */\nexport interface MCPError {\n category: ErrorCategory;\n code: string;\n message: string;\n serviceName: string;\n timestamp: Date;\n recoverable: boolean;\n recoveryStrategy: RecoveryStrategy;\n originalError?: Error;\n context?: Record<string, any>;\n}\n\n/**\n * 错误统计接口\n */\nexport interface ErrorStatistics {\n serviceName: string;\n totalErrors: number;\n errorsByCategory: Map<ErrorCategory, number>;\n errorsByCode: Map<string, number>;\n lastError?: MCPError;\n errorRate: number; // 错误率(过去1小时)\n}\n\n// 错误历史存储\nconst errorHistory: Map<string, MCPError[]> = new Map();\nconst MAX_ERROR_HISTORY = 100;\n\nfunction getLogger(): Logger {\n return logger;\n}\n\n/**\n * 分类错误\n */\nexport function categorizeError(\n error: Error,\n serviceName: string,\n context?: Record<string, any>\n): MCPError {\n const timestamp = new Date();\n const message = error.message.toLowerCase();\n\n let category = ErrorCategory.UNKNOWN;\n let code = \"UNKNOWN_ERROR\";\n let recoverable = false;\n let recoveryStrategy = RecoveryStrategy.MANUAL_INTERVENTION;\n\n // 连接相关错误\n if (\n message.includes(\"connection\") ||\n message.includes(\"connect\") ||\n message.includes(\"econnrefused\") ||\n message.includes(\"enotfound\")\n ) {\n category = ErrorCategory.CONNECTION;\n code = \"CONNECTION_FAILED\";\n recoverable = true;\n recoveryStrategy = RecoveryStrategy.RECONNECT;\n }\n // 传输层错误\n else if (\n message.includes(\"transport\") ||\n message.includes(\"stdio\") ||\n message.includes(\"sse\") ||\n message.includes(\"http\")\n ) {\n category = ErrorCategory.TRANSPORT;\n code = \"TRANSPORT_ERROR\";\n recoverable = true;\n recoveryStrategy = RecoveryStrategy.RESTART_SERVICE;\n }\n // 工具调用错误\n else if (\n message.includes(\"tool\") ||\n message.includes(\"method not found\") ||\n message.includes(\"invalid params\")\n ) {\n category = ErrorCategory.TOOL_CALL;\n code = \"TOOL_CALL_ERROR\";\n recoverable = true;\n recoveryStrategy = RecoveryStrategy.RETRY;\n }\n // 配置错误\n else if (\n message.includes(\"config\") ||\n message.includes(\"invalid\") ||\n message.includes(\"missing\")\n ) {\n category = ErrorCategory.CONFIGURATION;\n code = \"CONFIG_ERROR\";\n recoverable = false;\n recoveryStrategy = RecoveryStrategy.MANUAL_INTERVENTION;\n }\n // 超时错误\n else if (message.includes(\"timeout\") || message.includes(\"timed out\")) {\n category = ErrorCategory.TIMEOUT;\n code = \"TIMEOUT_ERROR\";\n recoverable = true;\n recoveryStrategy = RecoveryStrategy.RETRY;\n }\n // 认证错误\n else if (\n message.includes(\"auth\") ||\n message.includes(\"unauthorized\") ||\n message.includes(\"forbidden\")\n ) {\n category = ErrorCategory.AUTHENTICATION;\n code = \"AUTH_ERROR\";\n recoverable = false;\n recoveryStrategy = RecoveryStrategy.MANUAL_INTERVENTION;\n }\n // 网络错误\n else if (\n message.includes(\"network\") ||\n message.includes(\"fetch\") ||\n message.includes(\"request failed\")\n ) {\n category = ErrorCategory.NETWORK;\n code = \"NETWORK_ERROR\";\n recoverable = true;\n recoveryStrategy = RecoveryStrategy.RETRY;\n }\n\n const mcpError: MCPError = {\n category,\n code,\n message: error.message,\n serviceName,\n timestamp,\n recoverable,\n recoveryStrategy,\n originalError: error,\n context,\n };\n\n // 记录错误历史\n recordError(serviceName, mcpError);\n\n return mcpError;\n}\n\n/**\n * 获取恢复策略\n */\nexport function getRecoveryStrategy(error: MCPError): RecoveryStrategy {\n return error.recoveryStrategy;\n}\n\n/**\n * 格式化用户友好的错误消息\n */\nexport function formatUserFriendlyMessage(error: MCPError): string {\n const baseMessage = `服务 ${error.serviceName} 发生错误`;\n\n switch (error.category) {\n case ErrorCategory.CONNECTION:\n return `${baseMessage}:连接失败,正在尝试重新连接...`;\n case ErrorCategory.TRANSPORT:\n return `${baseMessage}:通信异常,正在重启服务...`;\n case ErrorCategory.TOOL_CALL:\n return `${baseMessage}:工具调用失败,请检查参数后重试`;\n case ErrorCategory.CONFIGURATION:\n return `${baseMessage}:配置错误,请检查服务配置`;\n case ErrorCategory.TIMEOUT:\n return `${baseMessage}:请求超时,正在重试...`;\n case ErrorCategory.AUTHENTICATION:\n return `${baseMessage}:认证失败,请检查 API 密钥`;\n case ErrorCategory.NETWORK:\n return `${baseMessage}:网络异常,正在重试...`;\n default:\n return `${baseMessage}:${error.message}`;\n }\n}\n\n/**\n * 记录错误历史\n */\nfunction recordError(serviceName: string, error: MCPError): void {\n if (!errorHistory.has(serviceName)) {\n errorHistory.set(serviceName, []);\n }\n\n const errors = errorHistory.get(serviceName)!;\n errors.push(error);\n\n // 限制历史记录数量\n if (errors.length > MAX_ERROR_HISTORY) {\n errors.shift();\n }\n\n getLogger().debug(\n `[ErrorHandler] 记录错误历史: ${serviceName} - ${error.code}`\n );\n}\n\n/**\n * 获取错误统计\n */\nexport function getErrorStatistics(serviceName: string): ErrorStatistics {\n const errors = errorHistory.get(serviceName) || [];\n const now = Date.now();\n const oneHourAgo = now - 60 * 60 * 1000;\n\n // 计算过去1小时的错误\n const recentErrors = errors.filter(\n (error) => error.timestamp.getTime() > oneHourAgo\n );\n\n const errorsByCategory = new Map<ErrorCategory, number>();\n const errorsByCode = new Map<string, number>();\n\n for (const error of errors) {\n errorsByCategory.set(\n error.category,\n (errorsByCategory.get(error.category) || 0) + 1\n );\n errorsByCode.set(error.code, (errorsByCode.get(error.code) || 0) + 1);\n }\n\n return {\n serviceName,\n totalErrors: errors.length,\n errorsByCategory,\n errorsByCode,\n lastError: errors[errors.length - 1],\n errorRate: recentErrors.length, // 过去1小时的错误数量\n };\n}\n\n/**\n * 获取所有服务的错误统计\n */\nexport function getAllErrorStatistics(): Map<string, ErrorStatistics> {\n const statistics = new Map<string, ErrorStatistics>();\n\n for (const serviceName of errorHistory.keys()) {\n statistics.set(serviceName, getErrorStatistics(serviceName));\n }\n\n return statistics;\n}\n\n/**\n * 清理错误历史\n */\nexport function clearErrorHistory(serviceName?: string): void {\n if (serviceName) {\n errorHistory.delete(serviceName);\n getLogger().info(`[ErrorHandler] 已清理服务 ${serviceName} 的错误历史`);\n } else {\n errorHistory.clear();\n getLogger().info(\"[ErrorHandler] 已清理所有错误历史\");\n }\n}\n\n/**\n * 判断错误是否应该触发告警\n */\nexport function shouldAlert(error: MCPError): boolean {\n const statistics = getErrorStatistics(error.serviceName);\n\n // 如果错误率过高,触发告警\n if (statistics.errorRate > 10) {\n return true;\n }\n\n // 如果是不可恢复的错误,触发告警\n if (!error.recoverable) {\n return true;\n }\n\n // 如果是认证或配置错误,触发告警\n if (\n error.category === ErrorCategory.AUTHENTICATION ||\n error.category === ErrorCategory.CONFIGURATION\n ) {\n return true;\n }\n\n return false;\n}\n","export * from \"./StatusService.js\";\nexport * from \"./NotificationService.js\";\nexport * from \"./EventBus.js\";\n\n// 新增导出 - 高优先级服务模块\nexport * from \"./ErrorHandler.js\";\n\n// CustomMCPHandler 重新导出 - 保持向后兼容性\nexport { CustomMCPHandler } from \"@/lib/mcp/custom.js\";\n","/**\n * 路由管理器\n * 提供直接、高效的路由注册和管理功能\n */\n\nimport type { Context, Hono, Next } from \"hono\";\nimport { createErrorResponse } from \"../middlewares/error.middleware.js\";\nimport type { AppContext } from \"../types/hono.context.js\";\nimport type { RouteConfig } from \"./types.js\";\n\n/**\n * 路由管理器\n * 直接管理路由配置,提供路由注册和应用功能\n * 注意:依赖注入现在通过 WebServer 的中间件处理,RouteManager 不再直接管理依赖\n */\nexport class RouteManager {\n private routes: Map<string, RouteConfig> = new Map();\n\n /**\n * 注册单个路由模块\n */\n registerRoute(name: string, config: RouteConfig): void {\n if (this.routes.has(name)) {\n console.warn(`路由域 '${name}' 已存在,将被覆盖`);\n }\n this.routes.set(name, config);\n console.log(`已注册路由域: ${name} (${config.routes.length} 个路由)`);\n }\n\n /**\n * 批量注册路由模块\n */\n registerRoutes(routeConfigs: Record<string, RouteConfig>): void {\n console.log(`开始批量注册 ${Object.keys(routeConfigs).length} 个路由域...`);\n\n for (const [name, config] of Object.entries(routeConfigs)) {\n this.registerRoute(name, config);\n }\n\n console.log(`批量注册完成,共注册 ${this.routes.size} 个路由域`);\n }\n\n /**\n * 获取所有注册的路由配置\n */\n getAllRoutes(): Map<string, RouteConfig> {\n return new Map(this.routes);\n }\n\n /**\n * 获取指定名称的路由配置\n */\n getRoute(name: string): RouteConfig | undefined {\n return this.routes.get(name);\n }\n\n /**\n * 将路由应用到 Hono 应用实例\n */\n applyToApp(app: Hono<AppContext>): void {\n console.log(`开始将 ${this.routes.size} 个路由域应用到 Hono 应用...`);\n\n // 注意:全局依赖注入中间件已移至 WebServer.ts 的 setupMiddleware(),避免中间件顺序冲突\n\n // 获取所有路由并排序,确保 static 路由最后应用\n const routeEntries = Array.from(this.routes.entries());\n routeEntries.sort(([nameA], [nameB]) => {\n // static 路由永远排在最后\n if (nameA === \"static\") return 1;\n if (nameB === \"static\") return -1;\n return 0;\n });\n\n for (const [domainName, config] of routeEntries) {\n try {\n this.applyRouteConfig(app, config);\n console.log(`✓ 成功应用路由域: ${domainName}`);\n } catch (error) {\n console.error(`✗ 应用路由域失败: ${domainName}`, error);\n }\n }\n\n console.log(\"路由应用完成\");\n }\n\n /**\n * 应用单个路由配置到 Hono 应用\n */\n private applyRouteConfig(app: Hono<AppContext>, config: RouteConfig): void {\n // 注册每个具体的路由\n for (const route of config.routes) {\n const fullPath = config.path + route.path;\n\n // 应用域级别的中间件和路由级别的中间件\n const allMiddleware = [\n ...(config.middleware || []),\n ...(route.middleware || []),\n ];\n\n // 创建包装的处理器,添加错误处理\n const wrappedHandler = async (c: Context<AppContext>, next: Next) => {\n try {\n const result = await route.handler(c);\n // 直接返回结果,不管是 Response 还是什么\n // Hono 会处理 Response 对象\n return result;\n } catch (error) {\n console.error(`路由处理错误 [${route.method} ${fullPath}]:`, error);\n const errorResponse = createErrorResponse(\n \"HANDLER_ERROR\",\n \"处理器执行失败\",\n error instanceof Error ? error.message : String(error)\n );\n return c.json(errorResponse, 500);\n }\n };\n\n // 使用方法映射简化注册逻辑,减少重复\n const methodHandlers = {\n GET: app.get.bind(app),\n POST: app.post.bind(app),\n PUT: app.put.bind(app),\n DELETE: app.delete.bind(app),\n PATCH: app.patch.bind(app),\n } as const;\n\n const handler =\n methodHandlers[route.method as keyof typeof methodHandlers];\n if (!handler) {\n throw new Error(`不支持的 HTTP 方法: ${route.method}`);\n }\n\n if (allMiddleware.length > 0) {\n handler(fullPath, ...allMiddleware, wrappedHandler);\n } else {\n handler(fullPath, wrappedHandler);\n }\n }\n }\n\n /**\n * 清除所有路由(主要用于测试)\n */\n clear(): void {\n this.routes.clear();\n console.log(\"已清除所有路由配置\");\n }\n\n /**\n * 检查路由是否已注册\n */\n hasRoute(name: string): boolean {\n return this.routes.has(name);\n }\n\n /**\n * 列出所有已注册的路由域名称\n */\n getRouteNames(): string[] {\n return Array.from(this.routes.keys());\n }\n}\n","/**\n * 配置管理路由模块\n * 处理所有配置相关的 API 路由\n * 简化版本:移除继承,直接导出路由配置\n */\n\nimport type { Context } from \"hono\";\nimport type { AppContext } from \"../../types/hono.context.js\";\nimport type { HandlerDependencies, RouteConfig } from \"../types.js\";\n\n/**\n * 配置管理路由配置\n * 从原有的 ConfigRoutes 类迁移而来,保持功能完全一致\n */\nexport const configRoutes: RouteConfig = {\n name: \"config\",\n path: \"/api/config\",\n description: \"配置管理相关 API\",\n routes: [\n {\n method: \"GET\",\n path: \"\",\n handler: (c: Context<AppContext>) => {\n const dependencies = c.get(\"dependencies\") as HandlerDependencies;\n const { configApiHandler } = dependencies;\n return configApiHandler.getConfig(c);\n },\n },\n {\n method: \"PUT\",\n path: \"\",\n handler: (c: Context<AppContext>) => {\n const dependencies = c.get(\"dependencies\") as HandlerDependencies;\n const { configApiHandler } = dependencies;\n return configApiHandler.updateConfig(c);\n },\n },\n {\n method: \"GET\",\n path: \"/mcp-endpoint\",\n handler: (c: Context<AppContext>) => {\n const dependencies = c.get(\"dependencies\") as HandlerDependencies;\n const { configApiHandler } = dependencies;\n return configApiHandler.getMcpEndpoint(c);\n },\n },\n {\n method: \"GET\",\n path: \"/mcp-endpoints\",\n handler: (c: Context<AppContext>) => {\n const dependencies = c.get(\"dependencies\") as HandlerDependencies;\n const { configApiHandler } = dependencies;\n return configApiHandler.getMcpEndpoints(c);\n },\n },\n {\n method: \"GET\",\n path: \"/mcp-servers\",\n handler: (c: Context<AppContext>) => {\n const dependencies = c.get(\"dependencies\") as HandlerDependencies;\n const { configApiHandler } = dependencies;\n return configApiHandler.getMcpServers(c);\n },\n },\n {\n method: \"GET\",\n path: \"/connection\",\n handler: (c: Context<AppContext>) => {\n const dependencies = c.get(\"dependencies\") as HandlerDependencies;\n const { configApiHandler } = dependencies;\n return configApiHandler.getConnectionConfig(c);\n },\n },\n {\n method: \"POST\",\n path: \"/reload\",\n handler: (c: Context<AppContext>) => {\n const dependencies = c.get(\"dependencies\") as HandlerDependencies;\n const { configApiHandler } = dependencies;\n return configApiHandler.reloadConfig(c);\n },\n },\n {\n method: \"GET\",\n path: \"/path\",\n handler: (c: Context<AppContext>) => {\n const dependencies = c.get(\"dependencies\") as HandlerDependencies;\n const { configApiHandler } = dependencies;\n return configApiHandler.getConfigPath(c);\n },\n },\n {\n method: \"GET\",\n path: \"/exists\",\n handler: (c: Context<AppContext>) => {\n const dependencies = c.get(\"dependencies\") as HandlerDependencies;\n const { configApiHandler } = dependencies;\n return configApiHandler.checkConfigExists(c);\n },\n },\n ],\n};\n","/**\n * 状态查询路由模块\n * 处理所有状态相关的 API 路由\n * 简化版本:移除继承,直接导出路由配置\n */\n\nimport type { Context } from \"hono\";\nimport type { HandlerDependencies, RouteConfig } from \"../types.js\";\n\n/**\n * 状态查询路由配置\n * 从原有的 StatusRoutes 类迁移而来,保持功能完全一致\n */\nexport const statusRoutes: RouteConfig = {\n name: \"status\",\n path: \"/api/status\",\n description: \"状态查询相关 API\",\n routes: [\n {\n method: \"GET\",\n path: \"\",\n handler: (c: Context) => {\n const { statusApiHandler } = c.get(\n \"dependencies\"\n ) as HandlerDependencies;\n return statusApiHandler.getStatus(c);\n },\n },\n {\n method: \"GET\",\n path: \"/client\",\n handler: (c: Context) => {\n const { statusApiHandler } = c.get(\n \"dependencies\"\n ) as HandlerDependencies;\n return statusApiHandler.getClientStatus(c);\n },\n },\n {\n method: \"PUT\",\n path: \"/client\",\n handler: (c: Context) => {\n const { statusApiHandler } = c.get(\n \"dependencies\"\n ) as HandlerDependencies;\n return statusApiHandler.updateClientStatus(c);\n },\n },\n {\n method: \"POST\",\n path: \"/reset\",\n handler: (c: Context) => {\n const { statusApiHandler } = c.get(\n \"dependencies\"\n ) as HandlerDependencies;\n return statusApiHandler.resetStatus(c);\n },\n },\n {\n method: \"GET\",\n path: \"/mcp-servers\",\n handler: (c: Context) => {\n const { statusApiHandler } = c.get(\n \"dependencies\"\n ) as HandlerDependencies;\n return statusApiHandler.getActiveMCPServers(c);\n },\n },\n {\n method: \"PUT\",\n path: \"/mcp-servers\",\n handler: (c: Context) => {\n const { statusApiHandler } = c.get(\n \"dependencies\"\n ) as HandlerDependencies;\n return statusApiHandler.setActiveMCPServers(c);\n },\n },\n ],\n};\n","/**\n * 工具调用路由模块\n * 处理所有工具相关的 API 路由\n * 简化版本:移除继承,直接导出路由配置\n */\n\nimport type { Context } from \"hono\";\nimport type { HandlerDependencies, RouteConfig } from \"../types.js\";\n\n/**\n * 工具调用路由配置\n * 从原有的 ToolsRoutes 类迁移而来,保持功能完全一致\n */\nexport const toolsRoutes: RouteConfig = {\n name: \"tools\",\n path: \"/api/tools\",\n description: \"工具调用相关 API\",\n routes: [\n {\n method: \"POST\",\n path: \"/call\",\n handler: (c: Context) => {\n const { toolApiHandler } = c.get(\"dependencies\") as HandlerDependencies;\n return toolApiHandler.callTool(c);\n },\n },\n {\n method: \"GET\",\n path: \"/list\",\n handler: (c: Context) => {\n const { toolApiHandler } = c.get(\"dependencies\") as HandlerDependencies;\n return toolApiHandler.listTools(c);\n },\n },\n {\n method: \"GET\",\n path: \"/custom\",\n handler: (c: Context) => {\n const { toolApiHandler } = c.get(\"dependencies\") as HandlerDependencies;\n return toolApiHandler.getCustomTools(c);\n },\n },\n {\n method: \"POST\",\n path: \"/custom\",\n handler: (c: Context) => {\n const { toolApiHandler } = c.get(\"dependencies\") as HandlerDependencies;\n return toolApiHandler.addCustomTool(c);\n },\n },\n {\n method: \"PUT\",\n path: \"/custom/:toolName\",\n handler: (c: Context) => {\n const { toolApiHandler } = c.get(\"dependencies\") as HandlerDependencies;\n return toolApiHandler.updateCustomTool(c);\n },\n },\n {\n method: \"DELETE\",\n path: \"/custom/:toolName\",\n handler: (c: Context) => {\n const { toolApiHandler } = c.get(\"dependencies\") as HandlerDependencies;\n return toolApiHandler.removeCustomTool(c);\n },\n },\n ],\n};\n","/**\n * MCP 协议路由模块\n * 处理 MCP 协议相关的 API 路由\n * 简化版本:移除继承,直接导出路由配置\n */\n\nimport type { Context } from \"hono\";\nimport type { HandlerDependencies, RouteConfig } from \"../types.js\";\n\n/**\n * MCP 协议路由配置\n * 从原有的 MCPRoutes 类迁移而来,保持功能完全一致\n */\nexport const mcpRoutes: RouteConfig = {\n name: \"mcp\",\n path: \"/mcp\",\n description: \"MCP 协议相关 API\",\n routes: [\n {\n method: \"POST\",\n path: \"\",\n handler: (c: Context) => {\n const { mcpRouteHandler } = c.get(\n \"dependencies\"\n ) as HandlerDependencies;\n return mcpRouteHandler.handlePost(c);\n },\n },\n {\n method: \"GET\",\n path: \"\",\n handler: (c: Context) => {\n const { mcpRouteHandler } = c.get(\n \"dependencies\"\n ) as HandlerDependencies;\n return mcpRouteHandler.handleGet(c);\n },\n },\n ],\n};\n","/**\n * 版本信息路由模块\n * 处理所有版本相关的 API 路由\n * 简化版本:移除继承,直接导出路由配置\n */\n\nimport type { Context } from \"hono\";\nimport type { HandlerDependencies, RouteConfig } from \"../types.js\";\n\n/**\n * 版本信息路由配置\n * 从原有的 VersionRoutes 类迁移而来,保持功能完全一致\n */\nexport const versionRoutes: RouteConfig = {\n name: \"version\",\n path: \"/api/version\",\n description: \"版本信息相关 API\",\n routes: [\n {\n method: \"GET\",\n path: \"\",\n handler: (c: Context) => {\n const { versionApiHandler } = c.get(\n \"dependencies\"\n ) as HandlerDependencies;\n return versionApiHandler.getVersion(c);\n },\n },\n {\n method: \"GET\",\n path: \"/simple\",\n handler: (c: Context) => {\n const { versionApiHandler } = c.get(\n \"dependencies\"\n ) as HandlerDependencies;\n return versionApiHandler.getVersionSimple(c);\n },\n },\n {\n method: \"DELETE\",\n path: \"/cache\",\n handler: (c: Context) => {\n const { versionApiHandler } = c.get(\n \"dependencies\"\n ) as HandlerDependencies;\n return versionApiHandler.clearVersionCache(c);\n },\n },\n {\n method: \"GET\",\n path: \"/latest\",\n handler: (c: Context) => {\n const { versionApiHandler } = c.get(\n \"dependencies\"\n ) as HandlerDependencies;\n return versionApiHandler.checkLatestVersion(c);\n },\n },\n ],\n};\n","/**\n * 服务管理路由配置\n * 处理所有服务管理相关的 API 路由\n */\n\nimport type { Context } from \"hono\";\nimport type { HandlerDependencies, RouteConfig } from \"../types.js\";\n\nexport const servicesRoutes: RouteConfig = {\n name: \"services\",\n path: \"/api/services\",\n description: \"服务管理相关 API\",\n routes: [\n {\n method: \"POST\",\n path: \"/restart\",\n handler: (c: Context) => {\n const { serviceApiHandler } = c.get(\n \"dependencies\"\n ) as HandlerDependencies;\n return serviceApiHandler.restartService(c);\n },\n },\n {\n method: \"POST\",\n path: \"/stop\",\n handler: (c: Context) => {\n const { serviceApiHandler } = c.get(\n \"dependencies\"\n ) as HandlerDependencies;\n return serviceApiHandler.stopService(c);\n },\n },\n {\n method: \"POST\",\n path: \"/start\",\n handler: (c: Context) => {\n const { serviceApiHandler } = c.get(\n \"dependencies\"\n ) as HandlerDependencies;\n return serviceApiHandler.startService(c);\n },\n },\n {\n method: \"GET\",\n path: \"/status\",\n handler: (c: Context) => {\n const { serviceApiHandler } = c.get(\n \"dependencies\"\n ) as HandlerDependencies;\n return serviceApiHandler.getServiceStatus(c);\n },\n },\n {\n method: \"GET\",\n path: \"/health\",\n handler: (c: Context) => {\n const { serviceApiHandler } = c.get(\n \"dependencies\"\n ) as HandlerDependencies;\n return serviceApiHandler.getServiceHealth(c);\n },\n },\n ],\n};\n","/**\n * 更新管理路由配置\n * 处理更新相关的 API 路由\n */\n\nimport type { Context } from \"hono\";\nimport type { HandlerDependencies, RouteConfig } from \"../types.js\";\n\nexport const updateRoutes: RouteConfig = {\n name: \"update\",\n path: \"/api\",\n description: \"更新管理相关 API\",\n routes: [\n {\n method: \"POST\",\n path: \"/update\",\n handler: (c: Context) => {\n const { updateApiHandler } = c.get(\n \"dependencies\"\n ) as HandlerDependencies;\n return updateApiHandler.performUpdate(c);\n },\n },\n ],\n};\n","/**\n * 静态文件路由配置\n * 处理静态文件服务相关的路由\n */\n\nimport type { Context } from \"hono\";\nimport type { HandlerDependencies, RouteConfig } from \"../types.js\";\n\nexport const staticRoutes: RouteConfig = {\n name: \"static\",\n path: \"/\", // 静态文件服务使用根路径\n description: \"静态文件服务路由\",\n routes: [\n {\n method: \"GET\",\n path: \"*\",\n handler: async (c: Context) => {\n // 如果路径以 /api/ 开头,不处理静态文件,直接返回 404\n if (c.req.path.startsWith(\"/api/\")) {\n return c.notFound();\n }\n const dependencies = c.get(\"dependencies\") as HandlerDependencies;\n return await dependencies.staticFileHandler.handleStaticFile(c);\n },\n },\n ],\n};\n","/**\n * 扣子 API 路由配置\n * 处理所有扣子相关的 API 路由\n */\n\nimport type { Context } from \"hono\";\nimport type { HandlerDependencies, RouteConfig } from \"../types.js\";\n\nexport const cozeRoutes: RouteConfig = {\n name: \"coze\",\n path: \"/api/coze\",\n description: \"扣子 API 相关路由\",\n routes: [\n {\n method: \"GET\",\n path: \"/workspaces\",\n handler: (c: Context) => {\n const { cozeApiHandler } = c.get(\"dependencies\") as HandlerDependencies;\n return cozeApiHandler.getWorkspaces(c);\n },\n },\n {\n method: \"GET\",\n path: \"/workflows\",\n handler: (c: Context) => {\n const { cozeApiHandler } = c.get(\"dependencies\") as HandlerDependencies;\n return cozeApiHandler.getWorkflows(c);\n },\n },\n {\n method: \"POST\",\n path: \"/cache/clear\",\n handler: (c: Context) => {\n const { cozeApiHandler } = c.get(\"dependencies\") as HandlerDependencies;\n return cozeApiHandler.clearCache(c);\n },\n },\n {\n method: \"GET\",\n path: \"/cache/stats\",\n handler: (c: Context) => {\n const { cozeApiHandler } = c.get(\"dependencies\") as HandlerDependencies;\n return cozeApiHandler.getCacheStats(c);\n },\n },\n ],\n};\n","/**\n * 工具调用日志路由配置\n * 处理工具调用日志相关的 API 路由\n */\n\nimport type { Context } from \"hono\";\nimport type { HandlerDependencies, RouteConfig } from \"../types.js\";\n\nexport const toolLogsRoutes: RouteConfig = {\n name: \"tool-logs\",\n path: \"/api/tool-calls\",\n description: \"工具调用日志相关 API\",\n routes: [\n {\n method: \"GET\",\n path: \"/logs\",\n handler: (c: Context) => {\n const { toolCallLogApiHandler } = c.get(\n \"dependencies\"\n ) as HandlerDependencies;\n return toolCallLogApiHandler.getToolCallLogs(c);\n },\n },\n ],\n};\n","/**\n * MCP 服务器管理路由配置\n * 处理 MCP 服务器管理相关的 API 路由\n */\n\nimport type { Context } from \"hono\";\nimport type { HandlerDependencies, RouteConfig } from \"../types.js\";\n\n/**\n * MCP 服务器处理器包装函数\n * 统一处理 MCP Server API Handler 的错误检查\n */\nconst withMCPServerHandler = async (\n c: Context,\n handlerFn: (\n handler: NonNullable<HandlerDependencies[\"mcpServerApiHandler\"]>\n ) => Promise<Response>\n): Promise<Response> => {\n const dependencies = c.get(\"dependencies\") as HandlerDependencies;\n const handler = dependencies.mcpServerApiHandler;\n\n if (!handler) {\n return c.json({ error: \"MCP Server API Handler not initialized\" }, 503);\n }\n\n return await handlerFn(handler);\n};\n\nexport const mcpserverRoutes: RouteConfig = {\n name: \"mcpserver\",\n path: \"/api/mcp-servers\",\n description: \"MCP 服务器管理相关 API\",\n routes: [\n {\n method: \"POST\",\n path: \"\",\n handler: (c: Context) =>\n withMCPServerHandler(c, (h) => h.addMCPServer(c)),\n },\n {\n method: \"DELETE\",\n path: \"/:serverName\",\n handler: (c: Context) =>\n withMCPServerHandler(c, (h) => h.removeMCPServer(c)),\n },\n {\n method: \"GET\",\n path: \"/:serverName/status\",\n handler: (c: Context) =>\n withMCPServerHandler(c, (h) => h.getMCPServerStatus(c)),\n },\n {\n method: \"GET\",\n path: \"\",\n handler: (c: Context) =>\n withMCPServerHandler(c, (h) => h.listMCPServers(c)),\n },\n ],\n};\n","/**\n * 端点管理路由配置\n * 处理所有端点管理相关的 API 路由\n * 使用中间件动态注入的 endpointHandler\n */\n\nimport type { Context } from \"hono\";\nimport type { AppContext } from \"../../types/hono.context.js\";\nimport type { RouteConfig } from \"../types.js\";\n\n/**\n * 端点处理器方法名类型\n */\ntype EndpointHandlerMethod =\n | \"getEndpointStatus\"\n | \"connectEndpoint\"\n | \"disconnectEndpoint\"\n | \"addEndpoint\"\n | \"removeEndpoint\";\n\n/**\n * 统一的错误响应函数\n */\nconst createErrorResponse = (code: string, message: string) => {\n return {\n error: {\n code,\n message,\n },\n };\n};\n\n/**\n * 端点处理器包装函数\n * 从中间件获取 endpointHandler 并调用相应方法\n */\nconst withEndpointHandler = async (\n c: Context<AppContext>,\n handlerName: EndpointHandlerMethod\n): Promise<Response> => {\n // 从中间件获取 endpointHandler\n const endpointHandler = c.get(\"endpointHandler\");\n\n if (!endpointHandler) {\n const errorResponse = createErrorResponse(\n \"ENDPOINT_HANDLER_NOT_AVAILABLE\",\n \"端点处理器尚未初始化,请稍后再试\"\n );\n return c.json(errorResponse, 503);\n }\n\n // 调用对应的处理方法\n try {\n // 使用类型安全的方式调用方法\n return await endpointHandler[handlerName](c);\n } catch (error) {\n console.error(`端点处理器错误 [${handlerName}]:`, error);\n const errorResponse = createErrorResponse(\n \"ENDPOINT_HANDLER_ERROR\",\n error instanceof Error ? error.message : \"端点处理失败\"\n );\n return c.json(errorResponse, 500);\n }\n};\n\n/**\n * 端点管理路由配置\n * 所有端点管理相关 API 的路由定义\n */\nexport const endpointRoutes: RouteConfig = {\n name: \"endpoint\",\n path: \"/api/endpoint\",\n description: \"端点管理相关 API\",\n routes: [\n {\n method: \"POST\",\n path: \"/status\",\n handler: (c: Context<AppContext>) =>\n withEndpointHandler(c, \"getEndpointStatus\"),\n },\n {\n method: \"POST\",\n path: \"/connect\",\n handler: (c: Context<AppContext>) =>\n withEndpointHandler(c, \"connectEndpoint\"),\n },\n {\n method: \"POST\",\n path: \"/disconnect\",\n handler: (c: Context<AppContext>) =>\n withEndpointHandler(c, \"disconnectEndpoint\"),\n },\n {\n method: \"POST\",\n path: \"/add\",\n handler: (c: Context<AppContext>) =>\n withEndpointHandler(c, \"addEndpoint\"),\n },\n {\n method: \"POST\",\n path: \"/remove\",\n handler: (c: Context<AppContext>) =>\n withEndpointHandler(c, \"removeEndpoint\"),\n },\n ],\n};\n","/**\n * 通用API路由配置\n * 处理不特定于某个模块的通用 API 路由\n */\n\nimport type { Context } from \"hono\";\nimport type { HandlerDependencies, RouteConfig } from \"../types.js\";\n\nexport const miscRoutes: RouteConfig = {\n name: \"misc\",\n path: \"/api\",\n description: \"通用 API 路由\",\n routes: [\n {\n method: \"POST\",\n path: \"/restart\",\n handler: (c: Context) => {\n const { serviceApiHandler } = c.get(\n \"dependencies\"\n ) as HandlerDependencies;\n return serviceApiHandler.restartService(c);\n },\n // 注意:此路由是为了向后兼容保留,与 /api/services/restart 功能重复\n },\n ],\n};\n","/**\n * 路由域统一导出文件\n * 简化版本:直接导出所有路由配置对象\n * 替代原有的复杂的域索引文件结构\n */\n\n// 导入所有可用的路由配置\nexport { configRoutes } from \"./config.route.js\";\nexport { statusRoutes } from \"./status.route.js\";\nexport { toolsRoutes } from \"./tools.route.js\";\nexport { mcpRoutes } from \"./mcp.route.js\";\nexport { versionRoutes } from \"./version.route.js\";\nexport { servicesRoutes } from \"./services.route.js\";\nexport { updateRoutes } from \"./update.route.js\";\nexport { staticRoutes } from \"./static.route.js\";\nexport { cozeRoutes } from \"./coze.route.js\";\nexport { toolLogsRoutes } from \"./tool-logs.route.js\";\nexport { mcpserverRoutes } from \"./mcpserver.route.js\";\nexport { endpointRoutes } from \"./endpoint.route.js\";\nexport { miscRoutes } from \"./misc.route.js\";\n\n/**\n * 路由域名列表\n */\nexport const routeNames = [\n \"config\",\n \"status\",\n \"tools\",\n \"mcp\",\n \"version\",\n \"services\",\n \"update\",\n \"static\",\n \"coze\",\n \"tool-logs\",\n \"mcpserver\",\n \"endpoint\",\n \"misc\",\n] as const;\n\n/**\n * 路由域名类型\n */\nexport type RouteName = (typeof routeNames)[number];\n","// 类型定义\nexport type {\n HandlerDependencies,\n RouteRegistryOptions,\n RouteStatistics,\n HTTPMethod,\n RouteDefinition,\n RouteConfig,\n} from \"./types.js\";\n\n// 核心类\nexport { RouteManager } from \"./RouteManager.js\";\n\n// 路由域导出\nexport * from \"./domains/index.js\";\n\n// 重新导出 Hono 相关类型以方便使用\nexport type { Context } from \"hono\";\nexport type { AppContext } from \"../types/hono.context.js\";\n\n// 重新导出处理器类型\nexport type { MCPEndpointApiHandler } from \"../handlers/index.js\";\n","import { createServer } from \"node:http\";\nimport type { IncomingMessage, Server, ServerResponse } from \"node:http\";\nimport { convertLegacyToNew } from \"@/lib/config/adapter.js\";\nimport { configManager } from \"@/lib/config/manager.js\";\nimport type { MCPServerConfig } from \"@/lib/config/manager.js\";\nimport type { EndpointConnection } from \"@/lib/endpoint/connection.js\";\nimport { EndpointManager } from \"@/lib/endpoint/index.js\";\nimport type {\n EndpointConfigChangeEvent,\n SimpleConnectionStatus,\n} from \"@/lib/endpoint/index.js\";\nimport { MCPServiceManager } from \"@/lib/mcp\";\nimport { ensureToolJSONSchema } from \"@/lib/mcp/types.js\";\nimport {\n ConfigApiHandler,\n CozeApiHandler,\n HeartbeatHandler,\n MCPRouteHandler,\n MCPServerApiHandler,\n RealtimeNotificationHandler,\n ServiceApiHandler,\n StaticFileHandler,\n StatusApiHandler,\n ToolApiHandler,\n ToolCallLogApiHandler,\n UpdateApiHandler,\n VersionApiHandler,\n} from \"@handlers/index.js\";\nimport type { ServerType } from \"@hono/node-server\";\nimport { serve } from \"@hono/node-server\";\nimport {\n corsMiddleware,\n endpointManagerMiddleware,\n endpointsMiddleware,\n errorHandlerMiddleware,\n loggerMiddleware,\n mcpServiceManagerMiddleware,\n notFoundHandlerMiddleware,\n} from \"@middlewares/index.js\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport type { Logger } from \"@root/Logger.js\";\nimport { logger } from \"@root/Logger.js\";\nimport type { AppContext } from \"@root/types/index.js\";\nimport { createApp } from \"@root/types/index.js\";\nimport type { EventBus, EventBusEvents } from \"@services/index.js\";\nimport {\n NotificationService,\n StatusService,\n destroyEventBus,\n getEventBus,\n} from \"@services/index.js\";\nimport type { Hono } from \"hono\";\nimport { WebSocketServer } from \"ws\";\n\nimport { MCPServiceManagerNotInitializedError } from \"./errors/MCPErrors.middleware.js\";\n// 路由系统导入\nimport {\n type HandlerDependencies,\n RouteManager,\n // 导入所有路由配置\n configRoutes,\n cozeRoutes,\n endpointRoutes,\n mcpRoutes,\n mcpserverRoutes,\n miscRoutes,\n servicesRoutes,\n staticRoutes,\n statusRoutes,\n toolLogsRoutes,\n toolsRoutes,\n updateRoutes,\n versionRoutes,\n} from \"./routes/index.js\";\n\n// 统一成功响应格式\ninterface ApiSuccessResponse<T = unknown> {\n success: boolean;\n data?: T;\n message?: string;\n}\n\n// 小智连接状态响应格式\ninterface XiaozhiConnectionStatusResponse {\n type: \"multi-endpoint\" | \"single-endpoint\" | \"none\";\n connected?: boolean;\n endpoint?: string;\n manager?: {\n connectedConnections: number;\n totalConnections: number;\n healthCheckStats: Record<string, unknown>;\n };\n connections?: SimpleConnectionStatus[];\n}\n\n/**\n * WebServer - 主控制器,协调各个服务和处理器\n */\nexport class WebServer {\n private app: Hono<AppContext>;\n private httpServer: ServerType | null = null;\n private wss: WebSocketServer | null = null;\n private logger: Logger;\n private port: number;\n\n // 事件总线\n private eventBus: EventBus;\n\n // 服务层\n private statusService: StatusService;\n private notificationService: NotificationService;\n\n // HTTP API 处理器\n private configApiHandler: ConfigApiHandler;\n private statusApiHandler: StatusApiHandler;\n private serviceApiHandler: ServiceApiHandler;\n private toolApiHandler: ToolApiHandler;\n private toolCallLogApiHandler: ToolCallLogApiHandler;\n private versionApiHandler: VersionApiHandler;\n private staticFileHandler: StaticFileHandler;\n private mcpRouteHandler: MCPRouteHandler;\n private mcpServerApiHandler?: MCPServerApiHandler;\n private updateApiHandler: UpdateApiHandler;\n private cozeApiHandler: CozeApiHandler;\n\n // WebSocket 处理器\n private realtimeNotificationHandler: RealtimeNotificationHandler;\n private heartbeatHandler: HeartbeatHandler;\n\n // 心跳监控\n private heartbeatMonitorInterval?: NodeJS.Timeout;\n\n // 路由系统\n private routeManager?: RouteManager;\n\n // 连接管理相关属性\n private endpointConnection: EndpointConnection | undefined;\n private endpointManager: EndpointManager | null = null;\n private mcpServiceManager: MCPServiceManager | null = null; // WebServer 直接管理的实例\n\n constructor(port?: number) {\n // 端口配置\n try {\n this.port = port ?? configManager.getWebUIPort() ?? 9999;\n } catch (error) {\n // 配置读取失败时使用默认端口\n this.port = port ?? 9999;\n }\n this.logger = logger;\n\n // 初始化事件总线\n this.eventBus = getEventBus();\n\n // 初始化服务层\n this.statusService = new StatusService();\n this.notificationService = new NotificationService();\n\n // 初始化 HTTP API 处理器\n this.configApiHandler = new ConfigApiHandler();\n this.statusApiHandler = new StatusApiHandler(this.statusService);\n this.serviceApiHandler = new ServiceApiHandler(this.statusService);\n this.toolApiHandler = new ToolApiHandler();\n this.toolCallLogApiHandler = new ToolCallLogApiHandler();\n this.versionApiHandler = new VersionApiHandler();\n this.staticFileHandler = new StaticFileHandler();\n this.mcpRouteHandler = new MCPRouteHandler();\n this.updateApiHandler = new UpdateApiHandler();\n this.cozeApiHandler = new CozeApiHandler();\n\n // MCPServerApiHandler 将在 start() 方法中初始化,因为它需要 mcpServiceManager\n\n // 初始化 WebSocket 处理器\n this.realtimeNotificationHandler = new RealtimeNotificationHandler(\n this.notificationService,\n this.statusService\n );\n this.heartbeatHandler = new HeartbeatHandler(\n this.statusService,\n this.notificationService\n );\n\n // 初始化 Hono 应用\n this.app = createApp();\n this.setupMiddleware();\n\n // 在所有路由设置完成后,设置 404 处理\n this.app.notFound(notFoundHandlerMiddleware);\n\n // 监听接入点状态变更事件\n this.setupEndpointStatusListener();\n }\n\n /**\n * 初始化所有连接(配置驱动)\n */\n private async initializeConnections(): Promise<void> {\n try {\n this.logger.debug(\"开始初始化连接...\");\n\n // 2. 初始化 MCP 服务管理器(WebServer 直接管理)\n if (!this.mcpServiceManager) {\n this.logger.debug(\"创建新的 MCPServiceManager 实例\");\n this.mcpServiceManager = new MCPServiceManager();\n // 启动服务管理器,确保它可以正常工作\n await this.mcpServiceManager.start();\n } else {\n this.logger.debug(\"使用现有的 MCPServiceManager 实例,跳过创建\");\n }\n\n // 1. 读取配置\n const config = await this.loadConfiguration();\n\n // 2.1. 初始化 MCP 服务器 API 处理器\n this.mcpServerApiHandler = new MCPServerApiHandler(\n this.mcpServiceManager,\n configManager\n );\n\n // 3. 从配置加载 MCP 服务\n await this.loadMCPServicesFromConfig(config.mcpServers);\n\n // 4. 获取工具列表\n const rawTools = this.mcpServiceManager.getAllTools();\n this.logger.debug(`已加载 ${rawTools.length} 个工具`);\n\n // 5. 转换工具格式以符合 MCP SDK 要求\n const tools: Tool[] = rawTools.map((tool) => ({\n name: tool.name,\n description: tool.description || \"\",\n inputSchema: ensureToolJSONSchema(tool.inputSchema),\n }));\n\n // 6. 初始化小智接入点连接\n await this.initializeXiaozhiConnection(config.mcpEndpoint, tools);\n\n this.logger.debug(\"所有连接初始化完成\");\n } catch (error) {\n this.logger.error(\"连接初始化失败:\", error);\n // 降级模式:即使配置加载失败,也确保 MCPServiceManager 可用\n if (!this.mcpServiceManager) {\n this.logger.warn(\n \"配置加载失败,正在进入降级模式。在降级模式下:\\n\" +\n \"1. 将创建一个空配置的 MCPServiceManager 实例\\n\" +\n \"2. 不会加载任何 MCP 服务器或端点\\n\" +\n \"3. WebServer 仍然可以启动并提供基础 API 服务\\n\" +\n \"4. 用户需要通过 API 重新配置端点或服务器\\n\" +\n \"5. 建议尽快运行 'xiaozhi init' 初始化配置文件\"\n );\n this.mcpServiceManager = new MCPServiceManager();\n await this.mcpServiceManager.start();\n this.logger.info(\"降级模式已激活,MCPServiceManager 使用空配置启动\");\n }\n }\n }\n\n /**\n * 加载配置文件\n */\n private async loadConfiguration(): Promise<{\n mcpEndpoint: string | string[];\n mcpServers: Record<string, MCPServerConfig>;\n webUIPort: number;\n }> {\n if (!configManager.configExists()) {\n throw new Error(\"配置文件不存在,请先运行 'xiaozhi init' 初始化配置\");\n }\n\n // 在加载配置前,先清理无效的服务器工具配置\n // 确保 mcpServerConfig 与 mcpServers 保持同步\n configManager.cleanupInvalidServerToolsConfig();\n\n const config = configManager.getConfig();\n\n return {\n mcpEndpoint: config.mcpEndpoint,\n mcpServers: config.mcpServers,\n webUIPort: config.webUI?.port ?? 9999,\n };\n }\n\n /**\n * 从配置加载 MCP 服务\n */\n private async loadMCPServicesFromConfig(\n mcpServers: Record<string, MCPServerConfig>\n ): Promise<void> {\n if (!this.mcpServiceManager) {\n throw new Error(\"MCPServiceManager 未初始化\");\n }\n\n for (const [name, config] of Object.entries(mcpServers)) {\n this.logger.debug(`添加 MCP 服务配置: ${name}`);\n // 使用配置适配器转换配置格式\n const serviceConfig = convertLegacyToNew(name, config);\n this.mcpServiceManager.addServiceConfig(name, serviceConfig);\n }\n\n await this.mcpServiceManager.startAllServices();\n }\n\n /**\n * 初始化小智接入点连接\n */\n private async initializeXiaozhiConnection(\n mcpEndpoint: string | string[],\n tools: Tool[]\n ): Promise<void> {\n // 处理多端点配置\n const endpoints = Array.isArray(mcpEndpoint) ? mcpEndpoint : [mcpEndpoint];\n const validEndpoints = endpoints.filter(\n (ep) => ep && !ep.includes(\"<请填写\")\n );\n\n // 1. 初始化连接管理器(无论是否有有效端点)\n this.logger.debug(\n `初始化小智接入点连接管理器,端点数量: ${validEndpoints.length}`\n );\n\n try {\n // 创建连接管理器实例(总是创建)\n if (!this.endpointManager) {\n this.endpointManager = new EndpointManager(configManager, {\n connectionTimeout: 10000,\n });\n this.logger.debug(\"✅ 新建连接管理器实例\");\n }\n\n // 设置 MCP 服务管理器\n if (this.mcpServiceManager) {\n this.endpointManager.setServiceManager(this.mcpServiceManager);\n }\n\n this.logger.debug(\"✅ 连接管理器设置完成\");\n\n // 2. 只有在有有效端点时才进行连接和初始化\n if (validEndpoints.length > 0) {\n this.logger.debug(\"有效端点列表:\", validEndpoints);\n\n // 初始化连接管理器(传入端点列表)\n await this.endpointManager.initialize(validEndpoints, tools);\n\n // 连接所有端点\n await this.endpointManager.connect();\n\n // 设置配置变更监听器\n this.endpointManager.on(\n \"configChange\",\n (event: EndpointConfigChangeEvent) => {\n this.logger.debug(`小智连接配置变更: ${event.type}`, event.data);\n }\n );\n\n this.logger.debug(\n `小智接入点连接管理器初始化完成,管理 ${validEndpoints.length} 个端点`\n );\n } else {\n // 即使没有端点,也需要调用 initialize 以完成内部设置\n await this.endpointManager.initialize([], tools);\n this.logger.debug(\"小智接入点连接管理器初始化完成(无端点)\");\n }\n } catch (error) {\n this.logger.error(\"小智接入点连接管理器初始化失败:\", error);\n // 抛出错误,让调用者知道初始化失败\n throw error;\n }\n }\n\n /**\n * 设置连接管理器实例(主要用于测试依赖注入)\n */\n public setXiaozhiConnectionManager(manager: EndpointManager): void {\n this.endpointManager = manager;\n }\n\n /**\n * 获取小智连接管理器实例\n * 提供给中间件使用\n * WebServer 启动后始终返回有效的连接管理器实例\n * @throws {Error} 如果连接管理器未初始化\n */\n public getEndpointManager(): EndpointManager {\n if (!this.endpointManager) {\n throw new Error(\n \"小智连接管理器未初始化,请确保 WebServer 已调用 start() 方法完成初始化\"\n );\n }\n return this.endpointManager;\n }\n\n /**\n * 设置 MCP 服务管理器实例(主要用于测试依赖注入)\n * 警告:如果要替换现有实例,调用者需要负责清理原有实例的资源\n */\n public setMCPServiceManager(manager: MCPServiceManager): void {\n // 如果已有实例且它正在运行,先清理它\n if (this.mcpServiceManager && this.mcpServiceManager !== manager) {\n this.logger.warn(\n \"替换现有的 MCPServiceManager 实例,注意清理原有实例的资源\"\n );\n // 注意:这里不直接调用 stopAllServices,因为调用者可能还在使用它\n // 调用者应该负责清理原有实例\n }\n\n this.mcpServiceManager = manager;\n this.logger.debug(\"MCPServiceManager 实例已更新\");\n }\n\n /**\n * 获取 MCP 服务管理器实例\n * 提供给中间件使用\n * WebServer 启动后始终返回有效的服务管理器实例\n * @throws {MCPServiceManagerNotInitializedError} 如果服务管理器未初始化\n */\n public getMCPServiceManager(): MCPServiceManager {\n if (!this.mcpServiceManager) {\n throw new MCPServiceManagerNotInitializedError(\n \"MCPServiceManager 未初始化,请确保 WebServer 已调用 start() 方法完成初始化\"\n );\n }\n return this.mcpServiceManager;\n }\n\n /**\n * 获取小智连接状态信息\n */\n getEndpointConnectionStatus(): XiaozhiConnectionStatusResponse {\n if (this.endpointManager) {\n return {\n type: \"multi-endpoint\",\n manager: {\n connectedConnections: this.endpointManager\n .getConnectionStatus()\n .filter((status) => status.connected).length,\n totalConnections: this.endpointManager.getConnectionStatus().length,\n healthCheckStats: {}, // 简化后不再提供复杂的健康检查统计\n },\n connections: this.endpointManager.getConnectionStatus(),\n };\n }\n\n if (this.endpointConnection) {\n return {\n type: \"single-endpoint\",\n connected: true,\n endpoint: \"unknown\",\n };\n }\n\n return {\n type: \"none\",\n connected: false,\n };\n }\n\n /**\n * 带重试的连接方法\n */\n private async connectWithRetry<T>(\n connectionFn: () => Promise<T>,\n context: string,\n maxAttempts = 5,\n initialDelay = 1000,\n maxDelay = 30000,\n backoffMultiplier = 2\n ): Promise<T> {\n let lastError: Error | null = null;\n\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n this.logger.info(`${context} - 尝试连接 (${attempt}/${maxAttempts})`);\n return await connectionFn();\n } catch (error) {\n lastError = error as Error;\n this.logger.warn(`${context} - 连接失败:`, error);\n\n if (attempt < maxAttempts) {\n const delay = Math.min(\n initialDelay * backoffMultiplier ** (attempt - 1),\n maxDelay\n );\n this.logger.info(`${context} - ${delay}ms 后重试...`);\n await this.sleep(delay);\n }\n }\n }\n\n throw new Error(\n `${context} - 连接失败,已达到最大重试次数: ${lastError?.message}`\n );\n }\n\n /**\n * 延迟工具方法\n */\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n private setupMiddleware() {\n // Logger 中间件 - 必须在最前面\n this.app?.use(\"*\", loggerMiddleware);\n\n // 注入 WebServer 实例到上下文\n // 使用类型断言避免循环引用问题\n this.app?.use(\"*\", async (c, next) => {\n c.set(\n \"webServer\",\n this as unknown as import(\"./types/hono.context.js\").IWebServer\n );\n await next();\n });\n\n // MCP Service Manager 中间件 - 必须在 WebServer 注入之后\n this.app?.use(\"*\", mcpServiceManagerMiddleware);\n\n // 小智连接管理器中间件\n this.app?.use(\"*\", endpointManagerMiddleware());\n\n // 小智接入点处理器中间件(在连接管理器中间件之后)\n this.app?.use(\"*\", endpointsMiddleware());\n\n // CORS 中间件\n this.app?.use(\"*\", corsMiddleware);\n\n // 错误处理中间件\n this.app?.onError(errorHandlerMiddleware);\n\n // 注入路由系统依赖\n // 注意:这个中间件必须在路由注册之前设置\n this.app?.use(\"*\", async (c, next) => {\n const dependencies = this.createHandlerDependencies();\n c.set(\"dependencies\", dependencies);\n await next();\n });\n }\n\n /**\n * 创建处理器依赖对象\n * 统一管理依赖对象的创建,避免代码重复\n */\n private createHandlerDependencies(): HandlerDependencies {\n return {\n configApiHandler: this.configApiHandler,\n statusApiHandler: this.statusApiHandler,\n serviceApiHandler: this.serviceApiHandler,\n toolApiHandler: this.toolApiHandler,\n toolCallLogApiHandler: this.toolCallLogApiHandler,\n versionApiHandler: this.versionApiHandler,\n staticFileHandler: this.staticFileHandler,\n mcpRouteHandler: this.mcpRouteHandler,\n mcpServerApiHandler: this.mcpServerApiHandler,\n updateApiHandler: this.updateApiHandler,\n cozeApiHandler: this.cozeApiHandler,\n // endpointHandler 通过中间件动态注入,不在此初始化\n };\n }\n\n /**\n * 设置路由系统\n */\n private setupRouteSystem(): void {\n // 初始化路由管理器\n // 注意:RouteManager 不再需要依赖参数,因为依赖通过中间件动态注入\n this.routeManager = new RouteManager();\n }\n\n /**\n * 从路由配置设置路由\n */\n private setupRoutesFromRegistry(): void {\n if (!this.routeManager || !this.app) {\n throw new Error(\"路由系统未初始化\");\n }\n\n try {\n // 注册所有路由配置 - static 放在最后,作为回退\n this.routeManager.registerRoutes({\n config: configRoutes,\n status: statusRoutes,\n tools: toolsRoutes,\n mcp: mcpRoutes,\n version: versionRoutes,\n services: servicesRoutes,\n update: updateRoutes,\n coze: cozeRoutes,\n \"tool-logs\": toolLogsRoutes,\n mcpserver: mcpserverRoutes,\n endpoint: endpointRoutes,\n misc: miscRoutes,\n static: staticRoutes, // 放在最后作为回退\n });\n\n // 应用路由到 Hono 应用\n this.routeManager.applyToApp(this.app);\n\n this.logger.info(\"路由系统注册完成\");\n } catch (error) {\n this.logger.error(\"路由系统注册失败:\", error);\n }\n }\n\n private setupWebSocket() {\n if (!this.wss) return;\n\n this.wss.on(\"connection\", (ws) => {\n // 生成客户端 ID\n const clientId = `client-${Date.now()}-${Math.random()\n .toString(36)\n .substr(2, 9)}`;\n\n this.logger.debug(`WebSocket 客户端已连接: ${clientId}`);\n this.logger.debug(\n `当前 WebSocket 连接数: ${this.wss?.clients.size || 0}`\n );\n\n // 注册客户端到通知服务\n this.realtimeNotificationHandler.handleClientConnect(ws, clientId);\n this.heartbeatHandler.handleClientConnect(clientId);\n\n ws.on(\"message\", async (message) => {\n try {\n const data = JSON.parse(message.toString());\n\n // 根据消息类型分发到不同的处理器\n if (data.type === \"clientStatus\") {\n await this.heartbeatHandler.handleClientStatus(ws, data, clientId);\n } else {\n await this.realtimeNotificationHandler.handleMessage(\n ws,\n data,\n clientId\n );\n }\n } catch (error) {\n this.logger.error(\"WebSocket message error:\", error);\n const errorResponse = {\n type: \"error\",\n error: {\n code: \"MESSAGE_PARSE_ERROR\",\n message: error instanceof Error ? error.message : \"消息解析失败\",\n timestamp: Date.now(),\n },\n };\n ws.send(JSON.stringify(errorResponse));\n }\n });\n\n ws.on(\"close\", () => {\n this.logger.debug(`WebSocket 客户端已断开连接: ${clientId}`);\n this.logger.debug(\n `剩余 WebSocket 连接数: ${this.wss?.clients.size || 0}`\n );\n\n // 处理客户端断开连接\n this.realtimeNotificationHandler.handleClientDisconnect(clientId);\n this.heartbeatHandler.handleClientDisconnect(clientId);\n });\n\n ws.on(\"error\", (error) => {\n this.logger.error(`WebSocket 连接错误 (${clientId}):`, error);\n });\n\n // 发送初始数据\n this.realtimeNotificationHandler.sendInitialData(ws, clientId);\n });\n }\n\n /**\n * 设置接入点状态变更事件监听\n */\n private setupEndpointStatusListener(): void {\n this.eventBus.onEvent(\n \"endpoint:status:changed\",\n (eventData: EventBusEvents[\"endpoint:status:changed\"]) => {\n // 向所有连接的 WebSocket 客户端广播接入点状态变更事件\n const message = {\n type: \"endpoint_status_changed\",\n data: {\n endpoint: eventData.endpoint,\n connected: eventData.connected,\n operation: eventData.operation,\n success: eventData.success,\n message: eventData.message,\n timestamp: eventData.timestamp,\n },\n };\n\n this.notificationService.broadcast(\"endpoint_status_changed\", message);\n this.logger.debug(\n `广播接入点状态变更事件: ${eventData.endpoint} - ${eventData.operation}`\n );\n }\n );\n }\n\n public async start(): Promise<void> {\n // 检查服务器是否已经启动\n if (this.httpServer) {\n this.logger.warn(\"Web server is already running\");\n return;\n }\n\n // 1. 初始化所有连接(配置驱动)\n // 这必须在启动服务器之前完成,确保 MCPServiceManager 可用\n await this.initializeConnections();\n\n // 2. 设置路由系统(在连接初始化之后)\n this.setupRouteSystem();\n this.setupRoutesFromRegistry();\n\n // 3. 启动 HTTP 服务器\n const server = serve({\n fetch: this.app.fetch,\n port: this.port,\n hostname: \"0.0.0.0\", // 绑定到所有网络接口,支持 Docker 部署\n createServer,\n });\n\n // 保存服务器实例\n this.httpServer = server;\n\n // 设置 WebSocket 服务器\n if (!this.httpServer) {\n throw new Error(\"HTTP server 未初始化\");\n }\n this.wss = new WebSocketServer({\n server: this.httpServer as Server<\n typeof IncomingMessage,\n typeof ServerResponse\n >,\n });\n this.setupWebSocket();\n\n // 启动心跳监控\n this.heartbeatMonitorInterval =\n this.heartbeatHandler.startHeartbeatMonitoring();\n\n this.logger.info(`Web server listening on http://0.0.0.0:${this.port}`);\n this.logger.info(`Local access: http://localhost:${this.port}`);\n }\n\n public stop(): Promise<void> {\n return new Promise((resolve) => {\n let resolved = false;\n\n const doResolve = () => {\n if (!resolved) {\n resolved = true;\n resolve();\n }\n };\n\n // 停止 MCP 客户端\n this.endpointConnection?.disconnect();\n\n // 清理连接管理器和 MCPServiceManager\n (async () => {\n try {\n if (this.endpointManager) {\n await this.endpointManager.cleanup();\n this.logger.debug(\"连接管理器已清理\");\n }\n } catch (error) {\n this.logger.error(\"连接管理器清理失败:\", error);\n }\n\n try {\n if (this.mcpServiceManager) {\n await this.mcpServiceManager.stopAllServices();\n this.mcpServiceManager = null;\n this.logger.debug(\"MCPServiceManager 已清理\");\n }\n } catch (error) {\n this.logger.error(\"MCPServiceManager 清理失败:\", error);\n }\n\n // 停止心跳监控\n if (this.heartbeatMonitorInterval) {\n this.heartbeatHandler.stopHeartbeatMonitoring(\n this.heartbeatMonitorInterval\n );\n this.heartbeatMonitorInterval = undefined;\n }\n\n // 强制断开所有 WebSocket 客户端连接\n if (this.wss) {\n for (const client of this.wss.clients) {\n client.terminate();\n }\n\n // 关闭 WebSocket 服务器\n this.wss.close(() => {\n // 强制关闭 HTTP 服务器,不等待现有连接\n if (this.httpServer) {\n this.httpServer.close(() => {\n this.logger.info(\"Web 服务器已停止\");\n doResolve();\n });\n } else {\n this.logger.info(\"Web 服务器已停止\");\n doResolve();\n }\n\n // 设置超时,如果 2 秒内没有关闭则强制退出\n setTimeout(() => {\n this.logger.info(\"Web 服务器已强制停止\");\n doResolve();\n }, 2000);\n });\n } else {\n this.logger.info(\"Web 服务器已停止\");\n doResolve();\n }\n })();\n });\n }\n\n /**\n * 销毁 WebServer 实例,清理所有资源\n */\n public destroy(): void {\n this.logger.debug(\"销毁 WebServer 实例\");\n\n // 停止心跳监控\n if (this.heartbeatMonitorInterval) {\n this.heartbeatHandler.stopHeartbeatMonitoring(\n this.heartbeatMonitorInterval\n );\n this.heartbeatMonitorInterval = undefined;\n }\n\n // 销毁服务层\n this.statusService.destroy();\n this.notificationService.destroy();\n\n // 销毁事件总线\n destroyEventBus();\n\n // 断开 MCP 连接\n this.endpointConnection?.disconnect();\n\n this.logger.debug(\"WebServer 实例已销毁\");\n }\n}\n","/**\n * 服务管理服务\n */\n\nimport type { ConfigManager } from \"@/lib/config/manager.js\";\nimport { ConfigError, ServiceError } from \"@cli/errors/index.js\";\nimport type {\n ServiceManager as IServiceManager,\n ProcessManager,\n ServiceStartOptions,\n ServiceStatus,\n} from \"@cli/interfaces/Service.js\";\nimport { PathUtils } from \"@cli/utils/PathUtils.js\";\nimport { Validation } from \"@cli/utils/Validation.js\";\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 console.log(`检测到服务已在运行 (PID: ${status.pid}),正在自动重启...`);\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) => setTimeout(resolve, 1000));\n\n console.log(\"现有服务已停止,正在启动新服务...\");\n } catch (stopError) {\n console.warn(\n `停止现有服务时出现警告: ${stopError instanceof Error ? stopError.message : String(stopError)}`\n );\n // 继续尝试启动新服务,因为旧进程可能已经不存在了\n }\n }\n\n // 检查环境配置\n this.checkEnvironment();\n\n // 根据模式启动服务\n switch (options.mode) {\n case \"mcp-server\":\n await this.startMcpServerMode(options);\n break;\n case \"stdio\":\n // 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) => setTimeout(resolve, 1000));\n }\n\n // 重新启动服务\n await this.start(options);\n } catch (error) {\n throw new ServiceError(\n `重启服务失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * 获取服务状态\n */\n getStatus(): ServiceStatus {\n return this.processManager.getServiceStatus();\n }\n\n /**\n * 验证启动选项\n */\n private validateStartOptions(options: ServiceStartOptions): void {\n if (options.port !== undefined) {\n Validation.validatePort(options.port);\n }\n\n if (\n options.mode &&\n ![\"normal\", \"mcp-server\", \"stdio\"].includes(options.mode)\n ) {\n throw new ServiceError(`无效的运行模式: ${options.mode}`);\n }\n }\n\n /**\n * 检查环境配置\n */\n private checkEnvironment(): void {\n // 检查配置文件是否存在\n if (!this.configManager.configExists()) {\n throw ConfigError.configNotFound();\n }\n\n // 可以添加更多环境检查\n try {\n const config = this.configManager.getConfig();\n if (!config) {\n throw new ConfigError(\"配置文件无效\");\n }\n } catch (error) {\n if (error instanceof ConfigError) {\n throw error;\n }\n throw new ConfigError(\n `配置文件错误: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * 启动普通模式\n */\n private async startNormalMode(options: ServiceStartOptions): Promise<void> {\n 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 console.log(\n `✅ MCP Server 已在后台启动 (PID: ${child.pid}, Port: ${port})`\n );\n console.log(`💡 使用 'xiaozhi status' 查看状态`);\n\n // 立即退出父进程,释放终端控制权\n process.exit(0);\n } else {\n // 前台模式 - 直接启动 Web Server\n const { WebServer } = await import(\"@root/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.on(\"SIGINT\", cleanup);\n process.on(\"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 console.log(`✅ 后台服务已启动 (PID: ${child.pid})`);\n console.log(`💡 使用 'xiaozhi status' 查看状态`);\n console.log(`💡 使用 'xiaozhi attach' 查看日志`);\n\n // 立即退出父进程,释放终端控制权\n process.exit(0);\n }\n\n /**\n * 前台模式启动 WebServer\n */\n private async startWebServerInForeground(): Promise<void> {\n const { WebServer } = await import(\"../../WebServer.js\");\n const server = new WebServer();\n\n // 处理退出信号\n const cleanup = async () => {\n await server.stop();\n this.processManager.cleanupPidFile();\n process.exit(0);\n };\n\n process.on(\"SIGINT\", cleanup);\n process.on(\"SIGTERM\", cleanup);\n\n // 保存 PID 信息\n this.processManager.savePidInfo(process.pid, \"foreground\");\n\n await server.start();\n }\n}\n","/**\n * 模板管理服务\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { FileError, ValidationError } from \"@cli/errors/index.js\";\nimport type { TemplateManager as ITemplateManager } from \"@cli/interfaces/Service.js\";\nimport { FileUtils } from \"@cli/utils/FileUtils.js\";\nimport { PathUtils } from \"@cli/utils/PathUtils.js\";\nimport { Validation } from \"@cli/utils/Validation.js\";\n\n/**\n * 模板信息接口\n */\nexport interface TemplateInfo {\n name: string;\n path: string;\n description?: string;\n version?: string;\n author?: string;\n files: string[];\n}\n\n/**\n * 模板创建选项\n */\nexport interface TemplateCreateOptions {\n templateName?: string;\n targetPath: string;\n projectName: string;\n variables?: Record<string, string>;\n}\n\n/**\n * 模板管理器实现\n */\nexport class TemplateManagerImpl implements ITemplateManager {\n private templateCache = new Map<string, TemplateInfo>();\n\n /**\n * 获取可用模板列表\n */\n async getAvailableTemplates(): Promise<TemplateInfo[]> {\n try {\n const templatesDir = PathUtils.findTemplatesDir();\n\n if (!templatesDir) {\n return [];\n }\n\n const templates: TemplateInfo[] = [];\n const templateDirs = fs\n .readdirSync(templatesDir, { withFileTypes: true })\n .filter((dirent) => dirent.isDirectory())\n .map((dirent) => dirent.name);\n\n for (const templateName of templateDirs) {\n try {\n const templateInfo = await this.getTemplateInfo(templateName);\n if (templateInfo) {\n templates.push(templateInfo);\n }\n } catch (error) {\n // 跳过无效的模板目录\n console.warn(`跳过无效模板: ${templateName}`);\n }\n }\n\n return templates;\n } catch (error) {\n throw new FileError(\n \"无法读取模板目录\",\n PathUtils.findTemplatesDir() || \"\"\n );\n }\n }\n\n /**\n * 获取模板信息\n */\n async getTemplateInfo(templateName: string): Promise<TemplateInfo | null> {\n try {\n // 验证模板名称\n Validation.validateTemplateName(templateName);\n\n // 检查缓存\n if (this.templateCache.has(templateName)) {\n return this.templateCache.get(templateName)!;\n }\n\n const templatePath = PathUtils.getTemplatePath(templateName);\n if (!templatePath) {\n return null;\n }\n\n // 读取模板配置文件\n const configPath = path.join(templatePath, \"template.json\");\n let config: any = {};\n\n if (FileUtils.exists(configPath)) {\n try {\n const configContent = FileUtils.readFile(configPath);\n config = JSON.parse(configContent);\n } catch (error) {\n console.warn(`模板配置文件解析失败: ${templateName}`);\n }\n }\n\n // 获取模板文件列表\n const files = this.getTemplateFiles(templatePath);\n\n const templateInfo: TemplateInfo = {\n name: templateName,\n path: templatePath,\n description: config.description || `${templateName} 模板`,\n version: config.version || \"1.0.0\",\n author: config.author,\n files,\n };\n\n // 缓存模板信息\n this.templateCache.set(templateName, templateInfo);\n\n return templateInfo;\n } catch (error) {\n if (error instanceof ValidationError) {\n throw error;\n }\n throw new FileError(`无法获取模板信息: ${templateName}`, \"\");\n }\n }\n\n /**\n * 复制模板到目标目录\n */\n async copyTemplate(templateName: string, targetPath: string): Promise<void> {\n await this.createProject({\n templateName,\n targetPath,\n projectName: path.basename(targetPath),\n });\n }\n\n /**\n * 创建项目\n */\n async createProject(options: TemplateCreateOptions): Promise<void> {\n try {\n // 验证输入参数\n this.validateCreateOptions(options);\n\n // 获取模板信息\n const templateName = options.templateName || \"default\";\n const templateInfo = await this.getTemplateInfo(templateName);\n\n if (!templateInfo) {\n throw new FileError(`模板不存在: ${templateName}`, \"\");\n }\n\n // 检查目标路径\n const targetPath = path.resolve(options.targetPath);\n if (FileUtils.exists(targetPath)) {\n throw FileError.alreadyExists(targetPath);\n }\n\n // 创建项目目录\n FileUtils.ensureDir(targetPath);\n\n // 复制模板文件\n await this.copyTemplateFiles(templateInfo, targetPath, options);\n\n // 处理模板变量替换\n await this.processTemplateVariables(targetPath, options);\n\n console.log(`✅ 项目创建成功: ${targetPath}`);\n } catch (error) {\n if (error instanceof FileError || error instanceof ValidationError) {\n throw error;\n }\n throw new FileError(\n `创建项目失败: ${error instanceof Error ? error.message : String(error)}`,\n options.targetPath\n );\n }\n }\n\n /**\n * 验证模板\n */\n async validateTemplate(templateName: string): Promise<boolean> {\n try {\n const templateInfo = await this.getTemplateInfo(templateName);\n\n if (!templateInfo) {\n return false;\n }\n\n // 检查必要文件是否存在\n const requiredFiles = [\"package.json\"]; // 可以根据需要调整\n\n for (const requiredFile of requiredFiles) {\n const filePath = path.join(templateInfo.path, requiredFile);\n if (!FileUtils.exists(filePath)) {\n console.warn(`模板缺少必要文件: ${requiredFile}`);\n return false;\n }\n }\n\n return true;\n } catch {\n return false;\n }\n }\n\n /**\n * 清除模板缓存\n */\n clearCache(): void {\n this.templateCache.clear();\n }\n\n /**\n * 获取模板文件列表\n */\n private getTemplateFiles(templatePath: string): string[] {\n try {\n const files = FileUtils.listDirectory(templatePath, {\n recursive: true,\n includeHidden: false,\n });\n\n // 过滤掉模板配置文件和其他不需要的文件\n return files.filter((file) => {\n const relativePath = path.relative(templatePath, file);\n return (\n !relativePath.startsWith(\".\") &&\n relativePath !== \"template.json\" &&\n !relativePath.includes(\"node_modules\")\n );\n });\n } catch {\n return [];\n }\n }\n\n /**\n * 验证创建选项\n */\n private validateCreateOptions(options: TemplateCreateOptions): void {\n Validation.validateRequired(options.targetPath, \"targetPath\");\n Validation.validateRequired(options.projectName, \"projectName\");\n Validation.validateProjectName(options.projectName);\n\n if (options.templateName) {\n Validation.validateTemplateName(options.templateName);\n }\n }\n\n /**\n * 复制模板文件\n */\n private async copyTemplateFiles(\n templateInfo: TemplateInfo,\n targetPath: string,\n options: TemplateCreateOptions\n ): Promise<void> {\n try {\n // 复制所有模板文件\n FileUtils.copyDirectory(templateInfo.path, targetPath, {\n exclude: [\"template.json\", \".git\", \"node_modules\"],\n overwrite: false,\n recursive: true,\n });\n } catch (error) {\n throw new FileError(\n `复制模板文件失败: ${error instanceof Error ? error.message : String(error)}`,\n templateInfo.path\n );\n }\n }\n\n /**\n * 处理模板变量替换\n */\n private async processTemplateVariables(\n targetPath: string,\n options: TemplateCreateOptions\n ): Promise<void> {\n try {\n // 默认变量\n const variables = {\n PROJECT_NAME: options.projectName,\n PROJECT_NAME_LOWER: options.projectName.toLowerCase(),\n PROJECT_NAME_UPPER: options.projectName.toUpperCase(),\n ...options.variables,\n };\n\n // 获取需要处理的文件\n const filesToProcess = [\n \"package.json\",\n \"README.md\",\n \"src/**/*.ts\",\n \"src/**/*.js\",\n \"src/**/*.json\",\n ];\n\n for (const pattern of filesToProcess) {\n const files = this.findFilesByPattern(targetPath, pattern);\n\n for (const filePath of files) {\n await this.replaceVariablesInFile(filePath, variables);\n }\n }\n } catch (error) {\n console.warn(\n `处理模板变量失败: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n\n /**\n * 根据模式查找文件\n */\n private findFilesByPattern(basePath: string, pattern: string): string[] {\n try {\n if (!pattern.includes(\"*\")) {\n // 简单文件路径\n const filePath = path.join(basePath, pattern);\n return FileUtils.exists(filePath) ? [filePath] : [];\n }\n\n // 简单的通配符支持\n const files = FileUtils.listDirectory(basePath, { recursive: true });\n const regex = new RegExp(\n pattern.replace(/\\*\\*/g, \".*\").replace(/\\*/g, \"[^/]*\")\n );\n\n return files.filter((file) => {\n const relativePath = path.relative(basePath, file);\n return regex.test(relativePath);\n });\n } catch {\n return [];\n }\n }\n\n /**\n * 替换文件中的变量\n */\n private async replaceVariablesInFile(\n filePath: string,\n variables: Record<string, string>\n ): Promise<void> {\n try {\n let content = FileUtils.readFile(filePath);\n let hasChanges = false;\n\n // 替换变量 {{VARIABLE_NAME}}\n for (const [key, value] of Object.entries(variables)) {\n const regex = new RegExp(`{{\\\\s*${key}\\\\s*}}`, \"g\");\n if (regex.test(content)) {\n content = content.replace(regex, value);\n hasChanges = true;\n }\n }\n\n // 如果有变更,写回文件\n if (hasChanges) {\n FileUtils.writeFile(filePath, content, { overwrite: true });\n }\n } catch (error) {\n console.warn(\n `替换文件变量失败 ${filePath}: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n }\n}\n","/**\n * 依赖注入容器\n */\n\nimport { configManager } from \"@/lib/config/manager.js\";\nimport { ErrorHandler } from \"@cli/errors/ErrorHandlers.js\";\nimport type { IDIContainer } from \"@cli/interfaces/Config.js\";\nimport { FileUtils } from \"@cli/utils/FileUtils.js\";\nimport { FormatUtils } from \"@cli/utils/FormatUtils.js\";\nimport { PathUtils } from \"@cli/utils/PathUtils.js\";\nimport { PlatformUtils } from \"@cli/utils/PlatformUtils.js\";\nimport { Validation } from \"@cli/utils/Validation.js\";\nimport { VersionUtils } from \"@cli/utils/VersionUtils.js\";\nimport { logger } from \"@root/Logger.js\";\n\n/**\n * 依赖注入容器实现\n */\nexport class DIContainer implements IDIContainer {\n private instances = new Map<string, any>();\n private factories = new Map<string, () => any>();\n private asyncFactories = new Map<string, () => Promise<any>>();\n private singletons = new Set<string>();\n\n /**\n * 注册服务工厂\n */\n register<T>(key: string, factory: () => T, singleton = false): void {\n this.factories.set(key, factory);\n if (singleton) {\n this.singletons.add(key);\n }\n }\n\n /**\n * 注册单例服务\n */\n registerSingleton<T>(key: string, factory: () => T): void {\n this.register(key, factory, true);\n }\n\n /**\n * 注册实例\n */\n registerInstance<T>(key: string, instance: T): void {\n this.instances.set(key, instance);\n this.singletons.add(key);\n }\n\n /**\n * 获取服务实例\n */\n get<T>(key: string): T {\n // 如果是单例且已经创建过实例,直接返回\n if (this.singletons.has(key) && this.instances.has(key)) {\n return this.instances.get(key);\n }\n\n // 获取工厂函数\n const factory = this.factories.get(key);\n if (!factory) {\n throw new Error(`Service ${key} not registered`);\n }\n\n // 创建实例\n const instance = factory();\n\n // 如果是单例,缓存实例\n if (this.singletons.has(key)) {\n this.instances.set(key, instance);\n }\n\n return instance;\n }\n\n /**\n * 检查服务是否已注册\n */\n has(key: string): boolean {\n return this.factories.has(key) || this.instances.has(key);\n }\n\n /**\n * 清除所有注册的服务\n */\n clear(): void {\n this.instances.clear();\n this.factories.clear();\n this.singletons.clear();\n }\n\n /**\n * 获取所有已注册的服务键\n */\n getRegisteredKeys(): string[] {\n const factoryKeys = Array.from(this.factories.keys());\n const instanceKeys = Array.from(this.instances.keys());\n return [...new Set([...factoryKeys, ...instanceKeys])];\n }\n\n /**\n * 创建默认容器实例\n */\n static create(): DIContainer {\n const container = new DIContainer();\n\n // 注册工具类(单例)\n container.registerSingleton(\"versionUtils\", () => {\n return VersionUtils;\n });\n\n container.registerSingleton(\"platformUtils\", () => {\n return PlatformUtils;\n });\n\n container.registerSingleton(\"formatUtils\", () => {\n return FormatUtils;\n });\n\n container.registerSingleton(\"fileUtils\", () => {\n return FileUtils;\n });\n\n container.registerSingleton(\"pathUtils\", () => {\n return PathUtils;\n });\n\n container.registerSingleton(\"validation\", () => {\n return Validation;\n });\n\n // 注册配置管理器(单例)\n container.registerSingleton(\"configManager\", () => {\n return configManager;\n });\n\n // 注册日志管理器(单例)\n container.registerSingleton(\"logger\", () => {\n return logger;\n });\n\n // 注册错误处理器(单例)\n container.registerSingleton(\"errorHandler\", () => {\n return ErrorHandler;\n });\n\n // 注册服务层\n container.registerSingleton(\"processManager\", () => {\n const ProcessManagerModule = require(\"@cli/services/ProcessManager.js\");\n return new ProcessManagerModule.ProcessManagerImpl();\n });\n\n container.registerSingleton(\"daemonManager\", () => {\n const DaemonManagerModule = require(\"@cli/services/DaemonManager.js\");\n const processManager = container.get(\"processManager\") as any;\n const logger = container.get(\"logger\") as any;\n return new DaemonManagerModule.DaemonManagerImpl(processManager, logger);\n });\n\n container.registerSingleton(\"serviceManager\", () => {\n const ServiceManagerModule = require(\"@cli/services/ServiceManager.js\");\n const processManager = container.get(\"processManager\") as any;\n const configManager = container.get(\"configManager\") as any;\n const logger = container.get(\"logger\") as any;\n return new ServiceManagerModule.ServiceManagerImpl(\n processManager,\n configManager,\n logger\n );\n });\n\n container.registerSingleton(\"templateManager\", () => {\n // 使用动态导入的同步版本\n const TemplateManagerModule = require(\"@cli/services/TemplateManager.js\");\n return new TemplateManagerModule.TemplateManagerImpl();\n });\n\n // 注册命令层(稍后在命令层实现时添加)\n // container.register('serviceCommand', () => {\n // const { ServiceCommand } = require('./commands/ServiceCommand.js');\n // const serviceManager = container.get('serviceManager');\n // const processManager = container.get('processManager');\n // return new ServiceCommand(serviceManager, processManager);\n // });\n\n // container.register('configCommand', () => {\n // const { ConfigCommand } = require('./commands/ConfigCommand.js');\n // const configManager = container.get('configManager');\n // const validation = container.get('validation');\n // return new ConfigCommand(configManager, validation);\n // });\n\n // container.register('projectCommand', () => {\n // const { ProjectCommand } = require('./commands/ProjectCommand.js');\n // const templateManager = container.get('templateManager');\n // const fileUtils = container.get('fileUtils');\n // return new ProjectCommand(templateManager, fileUtils);\n // });\n\n // container.register('mcpCommand', () => {\n // const { McpCommand } = require('./commands/McpCommand.js');\n // return new McpCommand();\n // });\n\n // container.register('infoCommand', () => {\n // const { InfoCommand } = require('./commands/InfoCommand.js');\n // const versionUtils = container.get('versionUtils');\n // const platformUtils = container.get('platformUtils');\n // return new InfoCommand(versionUtils, platformUtils);\n // });\n\n return container;\n }\n}\n\n/**\n * 创建并配置 DI 容器\n */\nexport async function createContainer(): Promise<IDIContainer> {\n return DIContainer.create();\n}\n","/**\n * 命令接口定义\n */\n\nimport type {\n CommandArguments,\n CommandOptions,\n} from \"@cli/interfaces/CommandTypes.js\";\nimport type { IDIContainer } from \"@cli/interfaces/Config.js\";\nimport type { Command } from \"commander\";\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 type { SubCommand } from \"@cli/interfaces/Command.js\";\nimport { BaseCommandHandler } from \"@cli/interfaces/Command.js\";\nimport type { IDIContainer } from \"@cli/interfaces/Config.js\";\nimport { setGlobalLogLevel } from \"@root/Logger.js\";\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: any[], options: any) => {\n await this.handleStart(options);\n },\n },\n {\n name: \"stop\",\n description: \"停止服务\",\n execute: async (args: any[], options: any) => {\n await this.handleStop();\n },\n },\n {\n name: \"status\",\n description: \"检查服务状态\",\n execute: async (args: any[], options: any) => {\n await this.handleStatus();\n },\n },\n {\n name: \"restart\",\n description: \"重启服务\",\n options: [{ flags: \"-d, --daemon\", description: \"在后台运行服务\" }],\n execute: async (args: any[], options: any) => {\n await this.handleRestart(options);\n },\n },\n {\n name: \"attach\",\n description: \"连接到后台服务查看日志\",\n execute: async (args: any[], options: any) => {\n await this.handleAttach();\n },\n },\n ];\n\n constructor(container: IDIContainer) {\n super(container);\n }\n\n /**\n * 主命令执行(显示帮助)\n */\n async execute(args: any[], options: any): Promise<void> {\n console.log(\"服务管理命令。使用 --help 查看可用的子命令。\");\n }\n\n /**\n * 处理启动命令\n */\n private async handleStart(options: any): Promise<void> {\n try {\n // 处理--debug参数\n if (options.debug) {\n // 设置全局日志级别为debug,这将影响所有现有的和新的Logger实例\n setGlobalLogLevel(\"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: any): 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 type { SubCommand } from \"@cli/interfaces/Command.js\";\nimport { BaseCommandHandler } from \"@cli/interfaces/Command.js\";\nimport type { IDIContainer } from \"@cli/interfaces/Config.js\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\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: any[], options: any) => {\n await this.handleInit(options);\n },\n },\n {\n name: \"get\",\n description: \"查看配置值\",\n execute: async (args: any[], options: any) => {\n this.validateArgs(args, 1);\n await this.handleGet(args[0]);\n },\n },\n {\n name: \"set\",\n description: \"设置配置值\",\n execute: async (args: any[], options: any) => {\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 async execute(args: any[], options: any): Promise<void> {\n console.log(\"配置管理命令。使用 --help 查看可用的子命令。\");\n }\n\n /**\n * 处理初始化命令\n */\n private async handleInit(options: any): 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 * 处理获取配置命令\n */\n private async handleGet(key: string): Promise<void> {\n const spinner = ora(\"读取配置...\").start();\n\n try {\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;\n }\n\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 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;\n }\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 type { CommandOption } from \"@cli/interfaces/Command.js\";\nimport { BaseCommandHandler } from \"@cli/interfaces/Command.js\";\nimport type { IDIContainer } from \"@cli/interfaces/Config.js\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\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 async execute(args: any[], options: any): 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: any\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,\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: string[]): void {\n console.log(chalk.yellow(\"可用的模板:\"));\n for (const template of templates) {\n console.log(chalk.gray(` - ${template}`));\n }\n }\n\n /**\n * 查找相似模板\n */\n private findSimilarTemplate(\n input: string,\n templates: string[]\n ): string | null {\n const formatUtils = this.getService<any>(\"formatUtils\");\n\n let bestMatch = null;\n let bestSimilarity = 0;\n\n for (const template of templates) {\n const similarity = formatUtils.calculateSimilarity(\n input.toLowerCase(),\n template.toLowerCase()\n );\n if (similarity > bestSimilarity && similarity > 0.6) {\n bestSimilarity = similarity;\n bestMatch = template;\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 {\n LocalMCPServerConfig,\n MCPServerConfig,\n} from \"@/lib/config/manager.js\";\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 { configManager } from \"@/lib/config/manager.js\";\nimport type { SubCommand } from \"@cli/interfaces/Command.js\";\nimport { BaseCommandHandler } from \"@cli/interfaces/Command.js\";\nimport type {\n CallOptions,\n CommandArguments,\n CommandOptions,\n ListOptions,\n} from \"@cli/interfaces/CommandTypes.js\";\nimport { isLocalMCPServerConfig } from \"@cli/interfaces/CommandTypes.js\";\nimport { ProcessManagerImpl } from \"@cli/services/ProcessManager.js\";\nimport type { Logger } from \"@root/Logger.js\";\nimport { logger } from \"@root/Logger.js\";\nimport chalk from \"chalk\";\nimport Table from \"cli-table3\";\nimport ora from \"ora\";\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 logger: Logger;\n private processManager: ProcessManagerImpl;\n private baseUrl: string;\n\n constructor(...args: ConstructorParameters<typeof BaseCommandHandler>) {\n super(...args);\n this.logger = logger;\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 this.logger.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 */\n private async handleServerInternal(serverName: string): Promise<void> {\n const spinner = ora(`获取 ${serverName} 服务的工具列表...`).start();\n\n try {\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;\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 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;\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 type { SubCommand } from \"@cli/interfaces/Command.js\";\nimport { BaseCommandHandler } from \"@cli/interfaces/Command.js\";\nimport type { IDIContainer } from \"@cli/interfaces/Config.js\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\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: any[], options: any) => {\n await this.handleList();\n },\n },\n {\n name: \"add\",\n description: \"添加新的 MCP 端点\",\n execute: async (args: any[], options: any) => {\n this.validateArgs(args, 1);\n await this.handleAdd(args[0]);\n },\n },\n {\n name: \"remove\",\n description: \"移除指定的 MCP 端点\",\n execute: async (args: any[], options: any) => {\n this.validateArgs(args, 1);\n await this.handleRemove(args[0]);\n },\n },\n {\n name: \"set\",\n description: \"设置 MCP 端点(可以是单个或多个)\",\n execute: async (args: any[], options: any) => {\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 async execute(args: any[], options: any): 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\nimport { createContainer } from \"@cli/Container.js\";\nimport { CommandRegistry } from \"@cli/commands/index.js\";\nimport chalk from \"chalk\";\nimport { Command } from \"commander\";\n\nconst program = new Command();\n\n/**\n * 显示帮助信息\n */\nfunction showHelp(): void {\n console.log(chalk.blue(\"🤖 小智 MCP 客户端\"));\n console.log();\n console.log(\n \"一个强大的 MCP (Model Context Protocol) 客户端,支持多种连接方式和服务管理。\"\n );\n console.log();\n console.log(chalk.yellow(\"主要功能:\"));\n console.log(\" • 支持 WebSocket 和 HTTP 连接\");\n console.log(\" • 多 MCP 服务管理\");\n console.log(\" • 工具调用和资源访问\");\n console.log(\" • 配置管理和模板创建\");\n console.log(\" • 后台服务和 Web UI\");\n console.log();\n console.log(chalk.yellow(\"快速开始:\"));\n console.log(\" xiaozhi config init # 初始化配置\");\n console.log(\" xiaozhi start # 启动服务(包含 Web UI)\");\n console.log();\n console.log(\"使用 'xiaozhi --help' 查看所有可用命令\");\n}\n\n/**\n * 显示详细信息\n */\nfunction showDetailedInfo(container: any): void {\n const versionUtils = container.get(\"versionUtils\") as any;\n const platformUtils = container.get(\"platformUtils\") as any;\n\n const versionInfo = versionUtils.getVersionInfo();\n const systemInfo = platformUtils.getSystemInfo();\n\n console.log(chalk.blue(\"🤖 小智 MCP 客户端 - 详细信息\"));\n console.log();\n console.log(chalk.green(\"版本信息:\"));\n console.log(` 名称: ${versionInfo.name || \"xiaozhi\"}`);\n console.log(` 版本: ${versionInfo.version}`);\n if (versionInfo.description) {\n console.log(` 描述: ${versionInfo.description}`);\n }\n console.log();\n console.log(chalk.green(\"系统信息:\"));\n console.log(` Node.js: ${systemInfo.nodeVersion}`);\n console.log(` 平台: ${systemInfo.platform} ${systemInfo.arch}`);\n if (systemInfo.isContainer) {\n console.log(\" 环境: Container\");\n }\n console.log();\n console.log(chalk.green(\"配置信息:\"));\n const configManager = container.get(\"configManager\") as any;\n if (configManager.configExists()) {\n const configPath = configManager.getConfigPath();\n console.log(` 配置文件: ${configPath}`);\n\n try {\n const endpoints = configManager.getMcpEndpoints();\n console.log(` MCP 端点: ${endpoints.length} 个`);\n } catch (error) {\n console.log(\" MCP 端点: 读取失败\");\n }\n } else {\n console.log(\" 配置文件: 未初始化\");\n }\n}\n\n/**\n * 主函数\n */\nasync function main(): Promise<void> {\n try {\n // 检查是否有 --info 参数,如果有则直接处理\n if (process.argv.includes(\"--info\")) {\n const container = await createContainer();\n showDetailedInfo(container);\n process.exit(0);\n }\n\n // 检查是否有 --version-info 参数,如果有则直接处理\n if (process.argv.includes(\"--version-info\")) {\n const container = await createContainer();\n const versionUtils = container.get(\"versionUtils\") as any;\n const platformUtils = container.get(\"platformUtils\") as any;\n\n const versionInfo = versionUtils.getVersionInfo();\n const systemInfo = platformUtils.getSystemInfo();\n\n console.log(`${versionInfo.name || \"xiaozhi\"} v${versionInfo.version}`);\n if (versionInfo.description) {\n console.log(versionInfo.description);\n }\n console.log(`Node.js: ${systemInfo.nodeVersion}`);\n console.log(`Platform: ${systemInfo.platform} ${systemInfo.arch}`);\n if (systemInfo.isContainer) {\n console.log(\"Environment: Container\");\n }\n process.exit(0);\n }\n\n // 创建 DI 容器\n const container = await createContainer();\n\n // 创建命令注册器\n const commandRegistry = new CommandRegistry(container);\n\n // 设置程序基本信息\n program\n .name(\"xiaozhi\")\n .description(\"小智 MCP 客户端 - 强大的 Model Context Protocol 客户端\");\n\n // 注册所有命令\n await commandRegistry.registerCommands(program);\n\n // 自定义帮助信息\n program.helpOption(\"-h, --help\", \"显示帮助信息\").addHelpText(\n \"after\",\n `\n示例:\n xiaozhi config 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 set mcpEndpoint <url> # 设置 MCP 端点\n xiaozhi create my-project # 创建项目\n xiaozhi mcp list # 列出 MCP 服务\n xiaozhi endpoint list # 列出 MCP 端点\n\n更多信息请访问: https://github.com/your-org/xiaozhi-client\n`\n );\n\n // 处理无参数情况,显示帮助\n if (process.argv.length <= 2) {\n showHelp();\n process.exit(0);\n }\n\n // 解析命令行参数\n await program.parseAsync(process.argv);\n } catch (error) {\n console.error(\n chalk.red(\"程序启动失败:\"),\n error instanceof Error ? error.message : String(error)\n );\n process.exit(1);\n }\n}\n\n// 启动程序\nmain().catch((error) => {\n console.error(\n chalk.red(\"程序执行失败:\"),\n error instanceof Error ? error.message : String(error)\n );\n process.exit(1);\n});\n","/**\n * 命令处理器工厂\n */\n\nimport type {\n CommandHandler,\n ICommandHandlerFactory,\n} from \"@cli/interfaces/Command.js\";\nimport type { IDIContainer } from \"@cli/interfaces/Config.js\";\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 {\n ServiceCommandHandler,\n } = require(\"@cli/commands/ServiceCommandHandler.js\");\n return new ServiceCommandHandler(this.container);\n }\n\n /**\n * 创建配置命令处理器\n */\n private createConfigCommandHandler(): CommandHandler {\n const {\n ConfigCommandHandler,\n } = require(\"@cli/commands/ConfigCommandHandler.js\");\n return new ConfigCommandHandler(this.container);\n }\n\n /**\n * 创建项目命令处理器\n */\n private createProjectCommandHandler(): CommandHandler {\n const {\n ProjectCommandHandler,\n } = require(\"@cli/commands/ProjectCommandHandler.js\");\n return new ProjectCommandHandler(this.container);\n }\n\n /**\n * 创建MCP命令处理器\n */\n private createMcpCommandHandler(): CommandHandler {\n const { McpCommandHandler } = require(\"@cli/commands/McpCommandHandler.js\");\n return new McpCommandHandler(this.container);\n }\n\n /**\n * 创建端点命令处理器\n */\n private createEndpointCommandHandler(): CommandHandler {\n const {\n EndpointCommandHandler,\n } = require(\"@cli/commands/EndpointCommandHandler.js\");\n return new EndpointCommandHandler(this.container);\n }\n}\n","/**\n * 命令注册器\n */\n\nimport { CommandHandlerFactory } from \"@cli/commands/CommandHandlerFactory.js\";\nimport { ErrorHandler } from \"@cli/errors/ErrorHandlers.js\";\nimport type {\n CommandHandler,\n ICommandHandlerFactory,\n ICommandRegistry,\n} from \"@cli/interfaces/Command.js\";\nimport type { IDIContainer } from \"@cli/interfaces/Config.js\";\nimport type { Command } from \"commander\";\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 * 注册所有命令到 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(async (...args) => {\n try {\n // Commander.js 传递的最后一个参数是 Command 对象,包含选项值\n const command = args[args.length - 1];\n const options = command.opts(); // 获取解析后的选项\n await subcommand.execute(args.slice(0, -1), options);\n } catch (error) {\n ErrorHandler.handle(error as Error);\n }\n });\n }\n\n // 设置主命令的默认行为\n commandGroup.action(async (...args) => {\n try {\n const command = args[args.length - 1];\n const options = command.opts(); // 获取解析后的选项\n await handler.execute(args.slice(0, -1), options);\n } catch (error) {\n ErrorHandler.handle(error as Error);\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(async (...args) => {\n try {\n const command = args[args.length - 1];\n const options = command.opts(); // 获取解析后的选项\n await handler.execute(args.slice(0, -1), options);\n } catch (error) {\n ErrorHandler.handle(error as Error);\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(async (...args) => {\n try {\n // Commander.js 传递的最后一个参数是 Command 对象,包含选项值\n const command = args[args.length - 1];\n const options = command.opts(); // 获取解析后的选项\n await subcommand.execute(args.slice(0, -1), options);\n } catch (error) {\n ErrorHandler.handle(error as Error);\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":";owBAAA,UAAYA,MAAQ,KACpB,UAAYC,MAAU,OACtB,OAAOC,OAAW,QAClB,OAAOC,OAAU,OAEjB,OAAS,KAAAC,OAAS,MAiBlB,SAASC,GAAeC,EAAoB,CAC1C,IAAMC,EAAOD,EAAK,YAAY,EACxBE,EAAQ,OAAOF,EAAK,SAAS,EAAI,CAAC,EAAE,SAAS,EAAG,GAAG,EACnDG,EAAM,OAAOH,EAAK,QAAQ,CAAC,EAAE,SAAS,EAAG,GAAG,EAC5CI,EAAQ,OAAOJ,EAAK,SAAS,CAAC,EAAE,SAAS,EAAG,GAAG,EAC/CK,EAAU,OAAOL,EAAK,WAAW,CAAC,EAAE,SAAS,EAAG,GAAG,EACnDM,EAAU,OAAON,EAAK,WAAW,CAAC,EAAE,SAAS,EAAG,GAAG,EAEzD,MAAO,GAAGC,CAAI,IAAIC,CAAK,IAAIC,CAAG,IAAIC,CAAK,IAAIC,CAAO,IAAIC,CAAO,EAC/D,CAidO,SAASC,IAAoB,CAClC,OAAKC,KACHA,GAAe,IAAIC,GAAOC,EAAc,GAEnCF,EACT,CAeO,SAASG,GAAkBC,EAAoB,CACpDF,GAAiBE,EAGbJ,IACFA,GAAa,SAASI,CAAK,CAE/B,CA3gBA,IAOMC,GAqCOJ,GAobTD,GACAE,GAqDSI,EAthBbC,EAAAC,EAAA,kBAOMH,GAAiBf,GAAE,KAAK,CAC5B,QACA,QACA,OACA,OACA,QACA,OACF,CAAC,EAQQmB,EAAAlB,GAAA,kBAsBIU,GAAN,KAAa,CA5CpB,MA4CoB,CAAAQ,EAAA,eACV,YAA6B,KAC7B,aACA,aACA,SACA,eAAiB,GAAK,KAAO,KAC7B,YAAc,EAEtB,YAAYL,EAAe,OAAQ,CAEjC,KAAK,aAAe,QAAQ,IAAI,iBAAmB,OAGnD,KAAK,SAAW,KAAK,iBAAiBA,CAAK,EAG3C,KAAK,aAAe,KAAK,mBAAmB,CAC9C,CAOQ,iBAAiBA,EAAsB,CAC7C,IAAMM,EAAkBN,EAAM,YAAY,EACpCO,EAASN,GAAe,UAAUK,CAAe,EAEvD,OAAIC,EAAO,QACFA,EAAO,KAGT,MACT,CAEQ,oBAAiC,CACvC,IAAMC,EAA8B,CAAC,EAGrC,GAAI,CAAC,KAAK,aAAc,CAEtB,IAAMC,EAAgB,KAAK,6BAA6B,EACxDD,EAAQ,KAAK,CACX,MAAO,KAAK,SACZ,OAAQC,CACV,CAAC,CACH,CAGA,OAAI,KAAK,aACPD,EAAQ,KAAK,CACX,MAAO,KAAK,SACZ,OAAQvB,GAAK,YAAY,CACvB,KAAM,KAAK,YACX,KAAM,GACN,OAAQ,GACR,MAAO,EACT,CAAC,CACH,CAAC,EAICuB,EAAQ,SAAW,GACrBA,EAAQ,KAAK,CACX,MAAO,KAAK,SACZ,OAAQvB,GAAK,YAAY,CAAE,KAAM,WAAY,CAAC,CAChD,CAAC,EAGIA,GACL,CACE,MAAO,KAAK,SAEZ,UACEA,GAAK,kBAAkB,UAAY,IAAM,WAAW,KAAK,IAAI,CAAC,IAChE,WAAY,CAEV,MAAOoB,EAAA,CAACK,EAAgBC,KAAoB,CAAE,MAAOA,CAAO,GAArD,QACT,EAEA,KAAM,KACN,YAAa,CAEX,IAAK1B,GAAK,gBAAgB,MAAS2B,GAAaA,EAClD,CACF,EACA3B,GAAK,YAAYuB,EAAS,CAAE,OAAQ,EAAK,CAAC,CAC5C,CACF,CAEQ,8BAA+B,CAErC,IAAMK,EAAW,IAAI,IAAI,CACvB,CAAC,GAAI,CAAE,KAAM,QAAS,MAAO7B,GAAM,IAAK,CAAC,EACzC,CAAC,GAAI,CAAE,KAAM,OAAQ,MAAOA,GAAM,IAAK,CAAC,EACxC,CAAC,GAAI,CAAE,KAAM,OAAQ,MAAOA,GAAM,MAAO,CAAC,EAC1C,CAAC,GAAI,CAAE,KAAM,QAAS,MAAOA,GAAM,GAAI,CAAC,EACxC,CAAC,GAAI,CAAE,KAAM,QAAS,MAAOA,GAAM,GAAI,CAAC,CAC1C,CAAC,EAED,MAAO,CACL,MAAOqB,EAACS,GAAkB,CACxB,GAAI,CACF,IAAMC,EAAS,KAAK,MAAMD,CAAK,EACzBE,EAAU,KAAK,8BAA8BD,EAAQF,CAAQ,EAEnE,KAAK,UAAU,GAAGG,CAAO;AAAA,CAAI,CAC/B,MAAgB,CAEd,KAAK,UAAUF,CAAK,CACtB,CACF,EAVO,QAWT,CACF,CAKQ,UAAUG,EAAuB,CACvC,GAAI,CACE,QAAQ,QAAU,OAAO,QAAQ,OAAO,OAAU,YACpD,QAAQ,OAAO,MAAMA,CAAO,CAKhC,MAAgB,CAEhB,CACF,CAEQ,8BACNF,EACAF,EACQ,CACR,IAAMK,EAAY/B,GAAe,IAAI,IAAM,EAErCgC,EAAYN,EAAS,IAAIE,EAAO,KAAK,GAAK,CAC9C,KAAM,UACN,MAAOV,EAACe,GAAiBA,EAAlB,QACT,EACMC,EAAeF,EAAU,MAAM,IAAIA,EAAU,IAAI,GAAG,EAGtDH,EAAUD,EAAO,IACrB,GAAIA,EAAO,MAAQ,MAAM,QAAQA,EAAO,IAAI,EAAG,CAC7C,IAAMO,EAAUP,EAAO,KACpB,IAAKQ,GACJ,OAAOA,GAAQ,SAAW,KAAK,UAAUA,CAAG,EAAI,OAAOA,CAAG,CAC5D,EACC,KAAK,GAAG,EACXP,EAAU,GAAGA,CAAO,IAAIM,CAAO,EACjC,CAEA,MAAO,IAAIJ,CAAS,KAAKG,CAAY,IAAIL,CAAO,EAClD,CAMA,YAAYQ,EAA0B,CACpC,KAAK,YAAmB,OAAKA,EAAY,aAAa,EAGtD,KAAK,sBAAsB,EAGnB,aAAW,KAAK,WAAW,GAC9B,gBAAc,KAAK,YAAa,EAAE,EAIvC,KAAK,aAAe,KAAK,mBAAmB,CAC9C,CAMA,kBAAkBC,EAAuB,CAGnCA,GAAU,KAAK,cAEjB,KAAK,aAAe,KAAK,mBAAmB,EAEhD,CAiBA,KAAKC,KAAkCC,EAAmB,CACpD,OAAOD,GAAiB,SACtBC,EAAK,SAAW,EAClB,KAAK,aAAa,KAAKD,CAAY,EAEnC,KAAK,aAAa,KAAK,CAAE,KAAAC,CAAK,EAAGD,CAAY,EAI/C,KAAK,aAAa,KAAKA,EAAcC,EAAK,CAAC,GAAK,EAAE,CAEtD,CAIA,QAAQD,KAAkCC,EAAmB,CAEvD,OAAOD,GAAiB,SACtBC,EAAK,SAAW,EAClB,KAAK,aAAa,KAAKD,CAAY,EAEnC,KAAK,aAAa,KAAK,CAAE,KAAAC,CAAK,EAAGD,CAAY,EAG/C,KAAK,aAAa,KAAKA,EAAcC,EAAK,CAAC,GAAK,EAAE,CAEtD,CAIA,KAAKD,KAAkCC,EAAmB,CACpD,OAAOD,GAAiB,SACtBC,EAAK,SAAW,EAClB,KAAK,aAAa,KAAKD,CAAY,EAEnC,KAAK,aAAa,KAAK,CAAE,KAAAC,CAAK,EAAGD,CAAY,EAG/C,KAAK,aAAa,KAAKA,EAAcC,EAAK,CAAC,GAAK,EAAE,CAEtD,CAIA,MAAMD,KAAkCC,EAAmB,CACzD,GAAI,OAAOD,GAAiB,SAC1B,GAAIC,EAAK,SAAW,EAClB,KAAK,aAAa,MAAMD,CAAY,MAC/B,CAEL,IAAME,EAAYD,EAAK,IAAKJ,GACtBA,aAAe,MACb,KAAK,aAAa,QAAU,QAAgBA,EAAI,QAC7C,CACL,QAASA,EAAI,QACb,MAAOA,EAAI,MACX,KAAMA,EAAI,KACV,MAAOA,EAAI,KACb,EAEKA,CACR,EACD,KAAK,aAAa,MAAM,CAAE,KAAMK,CAAU,EAAGF,CAAY,CAC3D,KACK,CAEL,IAAMG,EAAc,KAAK,mBAAmBH,CAAY,EACxD,KAAK,aAAa,MAAMG,EAAaF,EAAK,CAAC,GAAK,EAAE,CACpD,CACF,CAIA,MAAMD,KAAkCC,EAAmB,CACrD,OAAOD,GAAiB,SACtBC,EAAK,SAAW,EAClB,KAAK,aAAa,MAAMD,CAAY,EAEpC,KAAK,aAAa,MAAM,CAAE,KAAAC,CAAK,EAAGD,CAAY,EAGhD,KAAK,aAAa,MAAMA,EAAcC,EAAK,CAAC,GAAK,EAAE,CAEvD,CAIA,IAAID,KAAkCC,EAAmB,CAEnD,OAAOD,GAAiB,SACtBC,EAAK,SAAW,EAClB,KAAK,aAAa,KAAKD,CAAY,EAEnC,KAAK,aAAa,KAAK,CAAE,KAAAC,CAAK,EAAGD,CAAY,EAG/C,KAAK,aAAa,KAAKA,EAAcC,EAAK,CAAC,GAAK,EAAE,CAEtD,CAKQ,mBAAmBG,EAAe,CACxC,IAAMC,EAAW,CAAE,GAAGD,CAAI,EAG1B,OAAW,CAACE,EAAKC,CAAK,IAAK,OAAO,QAAQF,CAAQ,EAC5CE,aAAiB,QACnBF,EAASC,CAAG,EAAI,CACd,QAASC,EAAM,QACf,MAAOA,EAAM,MACb,KAAMA,EAAM,KACZ,MAAOA,EAAM,KACf,GAIJ,OAAOF,CACT,CAKQ,uBAA8B,CACpC,GAAI,GAAC,KAAK,aAAe,CAAI,aAAW,KAAK,WAAW,GAIxD,GAAI,CACe,WAAS,KAAK,WAAW,EAChC,KAAO,KAAK,gBACpB,KAAK,cAAc,CAEvB,MAAgB,CAEhB,CACF,CAKQ,eAAsB,CAC5B,GAAK,KAAK,YAEV,GAAI,CACF,IAAMG,EAAc,UAAQ,KAAK,WAAW,EACtCC,EAAe,WAAS,KAAK,YAAa,MAAM,EAGtD,QAASC,EAAI,KAAK,YAAc,EAAGA,GAAK,EAAGA,IAAK,CAC9C,IAAMC,EAAe,OAAKH,EAAQ,GAAGC,CAAO,IAAIC,CAAC,MAAM,EACjDE,EAAe,OAAKJ,EAAQ,GAAGC,CAAO,IAAIC,EAAI,CAAC,MAAM,EAEpD,aAAWC,CAAO,IACnBD,IAAM,KAAK,YAAc,EAExB,aAAWC,CAAO,EAElB,aAAWA,EAASC,CAAO,EAGpC,CAGA,IAAMC,EAAwB,OAAKL,EAAQ,GAAGC,CAAO,QAAQ,EAC1D,aAAW,KAAK,YAAaI,CAAgB,CAClD,MAAgB,CAEhB,CACF,CAKA,gBAAuB,CACrB,GAAK,KAAK,YAEV,GAAI,CACF,IAAML,EAAc,UAAQ,KAAK,WAAW,EACtCC,EAAe,WAAS,KAAK,YAAa,MAAM,EAGtD,QAASC,EAAI,KAAK,YAAc,EAAGA,GAAK,KAAK,YAAc,GAAIA,IAAK,CAClE,IAAMC,EAAe,OAAKH,EAAQ,GAAGC,CAAO,IAAIC,CAAC,MAAM,EAChD,aAAWC,CAAO,GACpB,aAAWA,CAAO,CAEzB,CACF,MAAgB,CAEhB,CACF,CAKA,kBAAkBG,EAAiBC,EAAwB,CACzD,KAAK,eAAiBD,EACtB,KAAK,YAAcC,CACrB,CAKA,OAAc,CAGd,CAOA,SAASzC,EAAoB,CAC3B,KAAK,SAAW,KAAK,iBAAiBA,CAAK,EAG3C,KAAK,aAAe,KAAK,mBAAmB,CAC9C,CAMA,UAAkB,CAChB,OAAO,KAAK,QACd,CACF,EAGIJ,GAA8B,KAC9BE,GAAwB,OAeZO,EAAAV,GAAA,aAoBAU,EAAAN,GAAA,qBAkBHG,EAASP,GAAU,ICthBhC,OAAS,gBAAA+C,OAAoB,SAyatB,SAASC,GAAwB,CACtC,OAAKC,KACHA,GAAmB,IAAIC,IAElBD,EACT,CAKO,SAASE,IAAwB,CAClCF,KACFA,GAAiB,QAAQ,EACzBA,GAAmB,KAEvB,CAxbA,IAmPaC,GAiLTD,GApaJG,EAAAC,EAAA,kBAGAC,IAgPaJ,GAAN,cAAuBH,EAAa,CAnP3C,MAmP2C,CAAAQ,EAAA,iBACjC,OACA,WACN,IAAI,IACE,aAAe,GAEvB,aAAc,CACZ,MAAM,EACN,KAAK,OAASC,EACd,KAAK,gBAAgB,KAAK,YAAY,EACtC,KAAK,mBAAmB,CAC1B,CAKQ,oBAA2B,CACjC,KAAK,GAAG,QAAUC,GAAU,CAC1B,KAAK,OAAO,MAAM,qCAAkBA,CAAK,CAC3C,CAAC,EAGD,KAAK,GAAG,cAAgBC,GAAc,CACpC,IAAMC,EAAgB,KAAK,cAAcD,CAAS,EAC9CC,EAAgB,KAAK,aAAe,IACtC,KAAK,OAAO,KACV,gBAAMD,CAAS,sDAAcC,CAAa,EAC5C,CAEJ,CAAC,CACH,CAKA,UACED,EACAE,EACS,CACT,GAAI,CACF,YAAK,iBAAiBF,CAAmB,EACzC,KAAK,OAAO,MAAM,6BAASA,CAAS,GAAIE,CAAI,EAGrC,MAAM,KAAKF,EAAWE,CAAI,CACnC,OAASH,EAAO,CACd,YAAK,OAAO,MAAM,yCAAWC,CAAS,GAAID,CAAK,EAE3CA,aAAiB,OACnB,KAAK,KAAK,QAASA,CAAK,EAEnB,EACT,CACF,CAKA,QACEC,EACAG,EACM,CACN,YAAK,OAAO,MAAM,+CAAYH,CAAS,EAAE,EAClC,KAAK,GAAGA,EAAWG,CAAQ,CACpC,CAKA,UACEH,EACAG,EACM,CACN,KAAK,OAAO,MAAM,iEAAeH,CAAS,EAAE,EAG5C,IAAMI,EAAeP,EAACK,GAA4B,CAChD,GAAI,CACFC,EAASD,CAAI,CACf,OAASH,EAAO,CAEd,WAAK,KAAK,QAASA,CAAK,EAClBA,CACR,QAAE,CAEA,KAAK,SAASC,EAAWI,CAAY,CACvC,CACF,EAXqB,gBAarB,OAAO,KAAK,GAAGJ,EAAWI,CAAY,CACxC,CAKA,SACEJ,EACAG,EACM,CACN,YAAK,OAAO,MAAM,+CAAYH,CAAS,EAAE,EAClC,KAAK,IAAIA,EAAWG,CAAQ,CACrC,CAKQ,iBAAiBH,EAAyB,CAChD,IAAMK,EAAQ,KAAK,WAAW,IAAIL,CAAS,GAAK,CAC9C,MAAO,EACP,YAAa,IAAI,IACnB,EACAK,EAAM,QACNA,EAAM,YAAc,IAAI,KACxB,KAAK,WAAW,IAAIL,EAAWK,CAAK,CACtC,CAKA,eAAsE,CACpE,IAAMA,EAA8D,CAAC,EACrE,OAAW,CAACL,EAAWM,CAAI,IAAK,KAAK,WACnCD,EAAML,CAAS,EAAI,CAAE,GAAGM,CAAK,EAE/B,OAAOD,CACT,CAKA,kBAA2C,CACzC,IAAMA,EAAgC,CAAC,EACvC,QAAWL,KAAa,KAAK,WAAW,EACtCK,EAAML,CAAmB,EAAI,KAAK,cAAcA,CAAS,EAE3D,OAAOK,CACT,CAKA,iBAAwB,CACtB,KAAK,WAAW,MAAM,EACtB,KAAK,OAAO,KAAK,4CAAS,CAC5B,CAKA,WAKE,CACA,MAAO,CACL,YAAa,KAAK,WAAW,KAC7B,eAAgB,OAAO,OAAO,KAAK,iBAAiB,CAAC,EAAE,OACrD,CAACE,EAAKC,IAAUD,EAAMC,EACtB,CACF,EACA,WAAY,KAAK,cAAc,EAC/B,cAAe,KAAK,iBAAiB,CACvC,CACF,CAKA,SAAgB,CACd,KAAK,mBAAmB,EACxB,KAAK,WAAW,MAAM,EACtB,KAAK,OAAO,KAAK,6BAAc,CACjC,CACF,EAGIjB,GAAoC,KAKxBM,EAAAP,EAAA,eAUAO,EAAAJ,GAAA,qBCnbhB,IAiBiBgB,GAjBjBC,GAAAC,EAAA,mBAiBiBF,GAAV,CAYE,SAASG,EACdC,EACa,CACb,GAAI,CAACA,GAAU,OAAOA,GAAW,SAC/B,OAAOA,EAIT,IAAMC,EAAmB,KAAK,MAAM,KAAK,UAAUD,CAAM,CAAC,EAG1D,GAAI,EAAE,SAAUC,GACd,OAAOA,EAGT,IAAMC,EAAeD,EAAiB,KAGtC,GAAIC,IAAiB,OAASA,IAAiB,kBAC7C,OAAOD,EAIT,IAAIE,EAEJ,OACED,IAAiB,kBACjBA,IAAiB,kBAEjBC,EAAiB,kBACRD,IAAiB,QAAUA,IAAiB,OACrDC,EAAiB,MAGjBA,EAAiBC,EAAmBF,CAAY,GAI9CC,IAAmB,OAASA,IAAmB,qBACjDF,EAAiB,KAAOE,GAOnBF,CACT,CA/COL,EAAS,mBAAAG,EAAAM,EAAAN,EAAA,sBAoDhB,SAASK,EAAmBE,EAAqB,CAC/C,OAAOA,EACJ,QAAQ,kBAAmB,OAAO,EAClC,QAAQ,KAAM,GAAG,EACjB,YAAY,CACjB,CALSD,EAAAD,EAAA,wBAhEMR,KAAA,MCiDV,SAASW,GACdC,EACsB,CAEtB,GAAI,CAACA,GAAgB,OAAOA,GAAiB,SAC3C,MAAM,IAAI,MAAM,sFAAgB,EAIlC,GAAI,YAAaA,GAAgB,OAAOA,EAAa,SAAY,SAC/D,MAAO,QAIT,GAAI,SAAUA,GAAgBA,EAAa,OAAS,MAClD,MAAO,MAIT,GACG,SAAUA,GAAgBA,EAAa,OAAS,mBAChD,QAASA,GAAgB,OAAOA,EAAa,KAAQ,SAEtD,MAAO,kBAIT,MAAM,IAAI,MACR,wPACF,CACF,CAsDO,SAASC,GACdC,EACAF,EACoC,CACpC,GACE,CAACA,GACD,OAAOA,GAAiB,UACxB,MAAM,QAAQA,CAAY,EAE1B,MAAO,CACL,MAAO,GACP,MAAO,iBAAOE,CAAU,gEAC1B,EAGF,GAAI,CACF,IAAMC,EAAoBJ,GACxBC,CACF,EAEMI,EAASJ,EAEf,OAAQG,EAAmB,CACzB,IAAK,QACH,GAAI,CAACC,EAAO,SAAW,OAAOA,EAAO,SAAY,SAC/C,MAAO,CACL,MAAO,GACP,MAAO,iBAAOF,CAAU,uGAC1B,EAEF,GAAI,CAAC,MAAM,QAAQE,EAAO,IAAI,EAC5B,MAAO,CACL,MAAO,GACP,MAAO,iBAAOF,CAAU,0DAC1B,EAEF,GACEE,EAAO,MACN,OAAOA,EAAO,KAAQ,UAAY,MAAM,QAAQA,EAAO,GAAG,GAE3D,MAAO,CACL,MAAO,GACP,MAAO,iBAAOF,CAAU,yDAC1B,EAEF,MAEF,IAAK,MACH,GAAIE,EAAO,OAAS,MAClB,MAAO,CACL,MAAO,GACP,MAAO,iBAAOF,CAAU,oDAC1B,EAEF,GAAI,CAACE,EAAO,KAAO,OAAOA,EAAO,KAAQ,SACvC,MAAO,CACL,MAAO,GACP,MAAO,iBAAOF,CAAU,mGAC1B,EAEF,GACEE,EAAO,UACN,OAAOA,EAAO,SAAY,UAAY,MAAM,QAAQA,EAAO,OAAO,GAEnE,MAAO,CACL,MAAO,GACP,MAAO,iBAAOF,CAAU,6DAC1B,EAEF,MAEF,IAAK,kBACH,GAAI,CAACE,EAAO,KAAO,OAAOA,EAAO,KAAQ,SACvC,MAAO,CACL,MAAO,GACP,MAAO,iBAAOF,CAAU,mGAC1B,EAEF,GAAIE,EAAO,MAAQA,EAAO,OAAS,kBACjC,MAAO,CACL,MAAO,GACP,MAAO,iBAAOF,CAAU,8FAC1B,EAEF,GACEE,EAAO,UACN,OAAOA,EAAO,SAAY,UAAY,MAAM,QAAQA,EAAO,OAAO,GAEnE,MAAO,CACL,MAAO,GACP,MAAO,iBAAOF,CAAU,6DAC1B,EAEF,MAEF,QACE,MAAO,CACL,MAAO,GACP,MAAO,iBAAOA,CAAU,0DAC1B,CACJ,CAEA,MAAO,CAAE,MAAO,EAAK,CACvB,OAASG,EAAO,CACd,MAAO,CACL,MAAO,GACP,MAAO,iBAAOH,CAAU,qCACtBG,aAAiB,MAAQA,EAAM,QAAU,0BAC3C,EACF,CACF,CACF,CAEO,SAASC,GAAcC,EAAkB,CAC9C,MAAO,GAAGA,EAAS,MAAM,EAAG,EAAE,CAAC,MAAMA,EAAS,MAAM,GAAG,CAAC,EAC1D,CAzQA,IAAAC,GAAAC,EAAA,kBAkEgBC,EAAAX,GAAA,iCAoFAW,EAAAT,GAAA,2BAiHAS,EAAAJ,GAAA,mBCvQhB,OAAS,gBAAAK,GAAc,cAAAC,GAAY,gBAAAC,GAAc,iBAAAC,OAAqB,KACtE,OAAS,WAAAC,GAAS,WAAAC,OAAe,OACjC,OAAS,iBAAAC,OAAqB,MAK9B,UAAYC,OAAiB,eAC7B,OAAOC,OAAW,QAClB,OAAOC,OAAW,QAClB,UAAYC,OAAiB,eAV7B,IAaMC,GAGAC,GAiNOC,GAq+DAC,EAtsEbC,EAAAC,EAAA,kBAIAC,IACAC,KACAC,KAOMR,GAAYP,GAAQE,GAAc,YAAY,GAAG,CAAC,EAGlDM,GAAwD,CAC5D,kBAAmB,IACnB,iBAAkB,IAClB,kBAAmB,GACrB,EA6MaC,GAAN,MAAMO,CAAc,CAjO3B,MAiO2B,CAAAC,EAAA,sBACzB,OAAe,SACP,kBACA,OAA2B,KAC3B,kBAAmC,KACnC,YAGG,KACH,SAAWC,EAAY,EAGvB,iBAA+C,IAAI,IACnD,wBAAuD,IAAI,IAClD,qBAAuB,IAEhC,aAAc,CAGpB,IAAMC,EAAgB,CAEpBlB,GAAQM,GAAW,YAAa,UAAW,qBAAqB,EAEhEN,GAAQM,GAAW,KAAM,YAAa,UAAW,qBAAqB,EAEtEN,GAAQ,QAAQ,IAAI,EAAG,YAAa,UAAW,qBAAqB,CACtE,EAGA,KAAK,kBACHkB,EAAc,KAAMC,GAASvB,GAAWuB,CAAI,CAAC,GAAKD,EAAc,CAAC,CACrE,CAMQ,mBAA4B,CAElC,IAAME,EAAY,QAAQ,IAAI,oBAAsB,QAAQ,IAAI,EAG1DC,EAAkB,CACtB,uBACA,uBACA,qBACF,EAEA,QAAWC,KAAYD,EAAiB,CACtC,IAAME,EAAWvB,GAAQoB,EAAWE,CAAQ,EAC5C,GAAI1B,GAAW2B,CAAQ,EACrB,OAAOA,CAEX,CAGA,OAAOvB,GAAQoB,EAAW,qBAAqB,CACjD,CAKQ,oBAAoBG,EAA8C,CACxE,OAAIA,EAAS,SAAS,QAAQ,EACrB,QAGLA,EAAS,SAAS,QAAQ,EACrB,QAGF,MACT,CAKA,OAAc,aAA6B,CACzC,OAAKR,EAAc,WACjBA,EAAc,SAAW,IAAIA,GAExBA,EAAc,QACvB,CAKO,cAAwB,CAE7B,IAAMK,EAAY,QAAQ,IAAI,oBAAsB,QAAQ,IAAI,EAG1DC,EAAkB,CACtB,uBACA,uBACA,qBACF,EAEA,QAAWC,KAAYD,EAAiB,CACtC,IAAME,EAAWvB,GAAQoB,EAAWE,CAAQ,EAC5C,GAAI1B,GAAW2B,CAAQ,EACrB,MAAO,EAEX,CAEA,MAAO,EACT,CAOO,WAAWC,EAAqC,OAAc,CACnE,GAAI,CAAC5B,GAAW,KAAK,iBAAiB,EACpC,MAAM,IAAI,MAAM,uEAAgB,KAAK,iBAAiB,EAAE,EAI1D,GAAI,KAAK,aAAa,EACpB,MAAM,IAAI,MAAM,4FAAiB,EAInC,IAAMwB,EAAY,QAAQ,IAAI,oBAAsB,QAAQ,IAAI,EAC1DK,EAAiB,kBAAkBD,CAAM,GACzCE,EAAa1B,GAAQoB,EAAWK,CAAc,EAGpD9B,GAAa,KAAK,kBAAmB+B,CAAU,EAC/C,KAAK,OAAS,KACd,KAAK,YAAc,IACrB,CAKQ,YAAwB,CAC9B,GAAI,CAAC,KAAK,aAAa,EAAG,CACxB,IAAMC,EAAQ,IAAI,MAChB,sHACF,EACA,WAAK,SAAS,UAAU,eAAgB,CACtC,MAAAA,EACA,UAAW,YACb,CAAC,EACKA,CACR,CAEA,GAAI,CACF,IAAMD,EAAa,KAAK,kBAAkB,EAC1C,KAAK,kBAAoBA,EACzB,IAAME,EAAmB,KAAK,oBAAoBF,CAAU,EAMtDG,EALgBhC,GAAa6B,EAAY,MAAM,EAKpB,QAAQ,UAAW,EAAE,EAElDI,EAGJ,OAAQF,EAAkB,CACxB,IAAK,QAEHE,EAAS1B,GAAM,MAAMyB,CAAU,EAE/B,KAAK,YAA0B,QAAKA,CAAU,EAC9C,MACF,IAAK,QAEHC,EAAqB,SAAMD,CAAU,EACrC,MACF,QACEC,EAAS,KAAK,MAAMD,CAAU,EAC9B,KACJ,CAGA,YAAK,eAAeC,CAAM,EAEnBA,CACT,OAASH,EAAO,CAMd,MAJA,KAAK,SAAS,UAAU,eAAgB,CACtC,MAAOA,aAAiB,MAAQA,EAAQ,IAAI,MAAM,OAAOA,CAAK,CAAC,EAC/D,UAAW,YACb,CAAC,EACGA,aAAiB,YACb,IAAI,MAAM,qDAAaA,EAAM,OAAO,EAAE,EAExCA,CACR,CACF,CAKO,eAAeG,EAAuB,CAC3C,GAAI,CAACA,GAAU,OAAOA,GAAW,SAC/B,MAAM,IAAI,MAAM,sFAAgB,EAGlC,IAAMC,EAAYD,EAElB,GAAIC,EAAU,cAAgB,QAAaA,EAAU,cAAgB,KACnE,MAAM,IAAI,MAAM,4FAA2B,EAI7C,GAAI,OAAOA,EAAU,aAAgB,SAE9B,GAAI,MAAM,QAAQA,EAAU,WAAW,GAC5C,QAAWC,KAAYD,EAAU,YAC/B,GAAI,OAAOC,GAAa,UAAYA,EAAS,KAAK,IAAM,GACtD,MAAM,IAAI,MACR,oKACF,MAIJ,OAAM,IAAI,MAAM,4IAAmC,EAGrD,GAAI,CAACD,EAAU,YAAc,OAAOA,EAAU,YAAe,SAC3D,MAAM,IAAI,MAAM,2FAA0B,EAI5C,OAAW,CAACE,EAAYC,CAAY,IAAK,OAAO,QAC9CH,EAAU,UACZ,EAAG,CACD,GAAI,CAACG,GAAgB,OAAOA,GAAiB,SAC3C,MAAM,IAAI,MAAM,oEAAuBD,CAAU,eAAK,EAIxD,IAAME,EACJC,GAAoB,mBAAmBF,CAAY,EAG/CG,EAAaC,GAAwBL,EAAYE,CAAgB,EACvE,GAAI,CAACE,EAAW,MACd,MAAM,IAAI,MAAM,yDAAYA,EAAW,KAAK,EAAE,CAElD,CACF,CAKO,WAAiC,CACtC,YAAK,OAAS,KAAK,WAAW,EAIvB,KAAK,MAAM,KAAK,UAAU,KAAK,MAAM,CAAC,CAC/C,CAKQ,kBAA8B,CACpC,OAAK,KAAK,SACR,KAAK,OAAS,KAAK,WAAW,GAEzB,KAAK,MACd,CAMO,gBAAyB,CAC9B,IAAMP,EAAS,KAAK,UAAU,EAC9B,OAAI,MAAM,QAAQA,EAAO,WAAW,EAC3BA,EAAO,YAAY,CAAC,GAAK,GAE3BA,EAAO,WAChB,CAKO,iBAA4B,CACjC,IAAMA,EAAS,KAAK,UAAU,EAC9B,OAAI,MAAM,QAAQA,EAAO,WAAW,EAC3B,CAAC,GAAGA,EAAO,WAAW,EAExBA,EAAO,YAAc,CAACA,EAAO,WAAW,EAAI,CAAC,CACtD,CAKO,eAA2D,CAEhE,OADe,KAAK,UAAU,EAChB,UAChB,CAKO,oBAAqE,CAE1E,OADe,KAAK,UAAU,EAChB,iBAAmB,CAAC,CACpC,CAKO,qBACLG,EACyC,CAEzC,OADqB,KAAK,mBAAmB,EACzBA,CAAU,GAAG,OAAS,CAAC,CAC7C,CAKO,cAAcA,EAAoBM,EAA2B,CAGlE,OAFoB,KAAK,qBAAqBN,CAAU,EACzBM,CAAQ,GACpB,SAAW,EAChC,CAKO,kBAAkBP,EAAmC,CAC1D,GAAI,MAAM,QAAQA,CAAQ,GACxB,QAAWQ,KAAMR,EACf,GAAI,CAACQ,GAAM,OAAOA,GAAO,SACvB,MAAM,IAAI,MAAM,kHAAwB,EAK9C,IAAMV,EAAS,KAAK,iBAAiB,EACrCA,EAAO,YAAcE,EACrB,KAAK,WAAWF,CAAM,EAGtB,KAAK,SAAS,UAAU,iBAAkB,CACxC,KAAM,WACN,UAAW,IAAI,IACjB,CAAC,CACH,CAKO,eAAeE,EAAwB,CAC5C,GAAI,CAACA,GAAY,OAAOA,GAAa,SACnC,MAAM,IAAI,MAAM,kEAAgB,EAGlC,IAAMF,EAAS,KAAK,iBAAiB,EAC/BW,EAAmB,KAAK,gBAAgB,EAG9C,GAAIA,EAAiB,SAAST,CAAQ,EACpC,MAAM,IAAI,MAAM,oBAAUA,CAAQ,qBAAM,EAG1C,IAAMU,EAAe,CAAC,GAAGD,EAAkBT,CAAQ,EACnDF,EAAO,YAAcY,EACrB,KAAK,WAAWZ,CAAM,CACxB,CAKO,kBAAkBE,EAAwB,CAC/C,GAAI,CAACA,GAAY,OAAOA,GAAa,SACnC,MAAM,IAAI,MAAM,kEAAgB,EAGlC,IAAMF,EAAS,KAAK,iBAAiB,EAC/BW,EAAmB,KAAK,gBAAgB,EAI9C,GADcA,EAAiB,QAAQT,CAAQ,IACjC,GACZ,MAAM,IAAI,MAAM,oBAAUA,CAAQ,qBAAM,EAG1C,IAAMU,EAAeD,EAAiB,OAAQD,GAAOA,IAAOR,CAAQ,EACpEF,EAAO,YAAcY,EACrB,KAAK,WAAWZ,CAAM,CACxB,CAKO,gBACLG,EACAC,EACM,CACN,GAAI,CAACD,GAAc,OAAOA,GAAe,SACvC,MAAM,IAAI,MAAM,0EAAc,EAIhC,IAAMI,EAAaC,GAAwBL,EAAYC,CAAY,EACnE,GAAI,CAACG,EAAW,MACd,MAAM,IAAI,MAAMA,EAAW,OAAS,kDAAU,EAEhD,IAAMP,EAAS,KAAK,iBAAiB,EAErCA,EAAO,WAAWG,CAAU,EAAIC,EAChC,KAAK,WAAWJ,CAAM,CACxB,CAKO,gBAAgBG,EAA0B,CAC/C,GAAI,CAACA,GAAc,OAAOA,GAAe,SACvC,MAAM,IAAI,MAAM,0EAAc,EAGhC,IAAMH,EAAS,KAAK,iBAAiB,EAGrC,GAAI,CAACA,EAAO,WAAWG,CAAU,EAC/B,MAAM,IAAI,MAAM,gBAAMA,CAAU,qBAAM,EAYxC,GARA,OAAOH,EAAO,WAAWG,CAAU,EAG/BH,EAAO,kBAAkBG,CAAU,GACrC,OAAOH,EAAO,gBAAgBG,CAAU,EAItCH,EAAO,WAAW,MAAO,CAE3B,IAAMa,EAAeb,EAAO,UAAU,MAAM,OACzCc,GACCA,EAAK,SAAS,OAAS,OACvBA,EAAK,QAAQ,QAAQ,cAAgBX,CACzC,EAGA,QAAWW,KAAQD,EAAc,CAC/B,IAAME,EAAYf,EAAO,UAAU,MAAM,UACtCgB,GAAMA,EAAE,OAASF,EAAK,IACzB,EACIC,IAAc,IAChBf,EAAO,UAAU,MAAM,OAAOe,EAAW,CAAC,CAE9C,CAGIf,EAAO,UAAU,MAAM,SAAW,IACpCA,EAAO,UAAY,OAEvB,CAGA,KAAK,WAAWA,CAAM,EAGtB,KAAK,SAAS,UAAU,iBAAkB,CACxC,KAAM,YACN,UAAW,IAAI,IACjB,CAAC,CAIH,CAKO,aAAaiB,EAAqC,CACvD,IAAMjB,EAAS,KAAK,iBAAiB,EAQrC,GALIiB,EAAU,cAAgB,SAC5BjB,EAAO,YAAciB,EAAU,aAI7BA,EAAU,WAAY,CACxB,IAAMC,EAAiB,CAAE,GAAGlB,EAAO,UAAW,EAC9C,OAAW,CAACmB,EAAMf,CAAY,IAAK,OAAO,QAAQa,EAAU,UAAU,EACpEjB,EAAO,WAAWmB,CAAI,EAAIf,EAG5B,QAAWe,KAAQ,OAAO,KAAKD,CAAc,EACrCC,KAAQF,EAAU,aACtB,OAAOjB,EAAO,WAAWmB,CAAI,EAEzBnB,EAAO,kBAAkBmB,CAAI,GAC/B,OAAOnB,EAAO,gBAAgBmB,CAAI,EAI1C,CA2BA,GAxBIF,EAAU,aACPjB,EAAO,aACVA,EAAO,WAAa,CAAC,GAEvB,OAAO,OAAOA,EAAO,WAAYiB,EAAU,UAAU,GAInDA,EAAU,aACPjB,EAAO,aACVA,EAAO,WAAa,CAAC,GAEvB,OAAO,OAAOA,EAAO,WAAYiB,EAAU,UAAU,GAInDA,EAAU,QACPjB,EAAO,QACVA,EAAO,MAAQ,CAAC,GAElB,OAAO,OAAOA,EAAO,MAAOiB,EAAU,KAAK,GAIzCA,EAAU,gBACZ,OAAW,CAACd,EAAYiB,CAAW,IAAK,OAAO,QAC7CH,EAAU,eACZ,EACMjB,EAAO,kBAAkBG,CAAU,IACrCH,EAAO,gBAAgBG,CAAU,EAAIiB,GAM3C,GAAIH,EAAU,UACZ,OAAW,CAACI,EAAcC,CAAc,IAAK,OAAO,QAClDL,EAAU,SACZ,EACOjB,EAAO,YACVA,EAAO,UAAY,CAAC,GAEtBA,EAAO,UAAUqB,CAAY,EAAIC,EAIrC,KAAK,WAAWtB,CAAM,EAGtB,KAAK,SAAS,UAAU,iBAAkB,CACxC,KAAM,SACN,UAAW,IAAI,IACjB,CAAC,CACH,CAKO,wBACLG,EACAiB,EACM,CACN,IAAMpB,EAAS,KAAK,iBAAiB,EAGhCA,EAAO,kBACVA,EAAO,gBAAkB,CAAC,GAIxB,OAAO,KAAKoB,CAAW,EAAE,SAAW,EACtC,OAAOpB,EAAO,gBAAgBG,CAAU,EAGxCH,EAAO,gBAAgBG,CAAU,EAAI,CACnC,MAAOiB,CACT,EAGF,KAAK,WAAWpB,CAAM,EAGtB,KAAK,SAAS,UAAU,iBAAkB,CACxC,KAAM,cACN,YAAaG,EACb,UAAW,IAAI,IACjB,CAAC,CACH,CAKO,wBAAwBA,EAA0B,CAEvD,IAAMc,EAAY,CAAE,GADL,KAAK,UAAU,CACA,EAG1BA,EAAU,kBAEZ,OAAOA,EAAU,gBAAgBd,CAAU,EAC3C,KAAK,WAAWc,CAAS,EAE7B,CAMO,iCAAwC,CAC7C,IAAMjB,EAAS,KAAK,iBAAiB,EAGrC,GAAI,CAACA,EAAO,gBACV,OAGF,IAAMuB,EAAmB,OAAO,KAAKvB,EAAO,UAAU,EAIhDwB,EAHwB,OAAO,KAAKxB,EAAO,eAAe,EAGf,OAC9CG,GAAe,CAACoB,EAAiB,SAASpB,CAAU,CACvD,EAEA,GAAIqB,EAAmB,OAAS,EAAG,CAEjC,QAAWrB,KAAcqB,EACvB,OAAOxB,EAAO,gBAAgBG,CAAU,EAG1C,KAAK,WAAWH,CAAM,CAMxB,CACF,CAKO,eACLG,EACAM,EACAgB,EACAC,EACM,CACN,IAAM1B,EAAS,KAAK,iBAAiB,EAGhCA,EAAO,kBACVA,EAAO,gBAAkB,CAAC,GAIvBA,EAAO,gBAAgBG,CAAU,IACpCH,EAAO,gBAAgBG,CAAU,EAAI,CAAE,MAAO,CAAC,CAAE,GAInDH,EAAO,gBAAgBG,CAAU,EAAE,MAAMM,CAAQ,EAAI,CACnD,GAAGT,EAAO,gBAAgBG,CAAU,EAAE,MAAMM,CAAQ,EACpD,OAAQgB,EACR,GAAIC,GAAe,CAAE,YAAAA,CAAY,CACnC,EAEA,KAAK,WAAW1B,CAAM,CACxB,CAMQ,WAAWA,EAAyB,CAC1C,GAAI,CAEF,KAAK,eAAeA,CAAM,EAG1B,IAAIJ,EACA,KAAK,kBACPA,EAAa,KAAK,mBAGlBA,EAAa,KAAK,kBAAkB,EACpC,KAAK,kBAAoBA,GAI3B,IAAME,EAAmB,KAAK,oBAAoBF,CAAU,EACxD+B,EAEJ,OAAQ7B,EAAkB,CACxB,IAAK,QAEH,GAAI,CACE,KAAK,aAEP,KAAK,YAAY,MAAME,CAAM,EAC7B2B,EAAgB,KAAK,YAAY,SAAS,GAI1CA,EAAgBrD,GAAM,UAAU0B,EAAQ,KAAM,CAAC,CAEnD,MAA2B,CAMzB2B,EAAgBrD,GAAM,UAAU0B,EAAQ,KAAM,CAAC,CACjD,CACA,MACF,IAAK,QAEH,GAAI,CAGF2B,EAA4B,aAAU3B,EAAQ,KAAM,CAAC,CACvD,MAA2B,CAMzB2B,EAAgB,KAAK,UAAU3B,EAAQ,KAAM,CAAC,CAChD,CACA,MACF,QACE2B,EAAgB,KAAK,UAAU3B,EAAQ,KAAM,CAAC,EAC9C,KACJ,CAGAhC,GAAc4B,EAAY+B,EAAe,MAAM,EAG/C,KAAK,OAAS3B,EAKd,KAAK,mBAAmBA,CAAM,CAChC,OAASH,EAAO,CAEd,WAAK,SAAS,UAAU,eAAgB,CACtC,MAAOA,aAAiB,MAAQA,EAAQ,IAAI,MAAM,OAAOA,CAAK,CAAC,EAC/D,UAAW,YACb,CAAC,EACK,IAAI,MACR,yCACEA,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CACvD,EACF,CACF,CACF,CAKO,cAAqB,CAC1B,KAAK,OAAS,KACd,KAAK,kBAAoB,KACzB,KAAK,YAAc,IACrB,CAKO,eAAwB,CAC7B,OAAO,KAAK,kBAAkB,CAChC,CAKO,sBAA+B,CACpC,OAAO,KAAK,iBACd,CAKO,qBAAkD,CAEvD,IAAM+B,EADS,KAAK,UAAU,EACE,YAAc,CAAC,EAE/C,MAAO,CACL,kBACEA,EAAiB,mBACjBnD,GAA0B,kBAC5B,iBACEmD,EAAiB,kBACjBnD,GAA0B,iBAC5B,kBACEmD,EAAiB,mBACjBnD,GAA0B,iBAC9B,CACF,CAKO,sBAA+B,CACpC,OAAO,KAAK,oBAAoB,EAAE,iBACpC,CAKO,qBAA8B,CACnC,OAAO,KAAK,oBAAoB,EAAE,gBACpC,CAKO,sBAA+B,CACpC,OAAO,KAAK,oBAAoB,EAAE,iBACpC,CAKO,uBACLmD,EACM,CACN,IAAM5B,EAAS,KAAK,iBAAiB,EAGhCA,EAAO,aACVA,EAAO,WAAa,CAAC,GAIvB,OAAO,OAAOA,EAAO,WAAY4B,CAAgB,EACjD,KAAK,WAAW5B,CAAM,EAGtB,KAAK,SAAS,UAAU,iBAAkB,CACxC,KAAM,aACN,UAAW,IAAI,IACjB,CAAC,CACH,CA2BA,MAAa,qBACX6B,EACAC,EACAC,EACe,CACf,GAAI,CAEF,GAAI,OAAOD,GAAS,UAAYC,EAAM,CAEpC,IAAM5B,EAAa0B,EACbpB,EAAWqB,EACXE,EAAWD,EAGjB,MAAM,QAAQ,IAAI,CAChB,KAAK,0BAA0B5B,EAAYM,EAAUuB,CAAQ,EAC7D,KAAK,yBAAyB7B,EAAYM,EAAUuB,CAAQ,CAC9D,CAAC,CAGH,KAAO,CAEL,IAAMvB,EAAWoB,EACXI,EAAsBH,EACtBE,EAAW,IAAI,KAAK,EAAE,YAAY,EAGxC,MAAM,KAAK,yBACTvB,EACAuB,EACAC,CACF,CAGF,CACF,MAAgB,CAEd,GAAI,OAAOH,GAAS,UAAYC,EAAM,CACpC,IAAM5B,EAAa0B,EACbpB,EAAWqB,CAEnB,KAAO,CACL,IAAMrB,EAAWoB,CAEnB,CACF,CACF,CASA,MAAa,yBACXK,EACAzB,EACAuB,EACAC,EAAsB,GACP,CACf,MAAM,KAAK,0BACTC,EACAzB,EACAuB,EACAC,CACF,CACF,CAKO,qBAAqBE,EAAwB,CAClD,GAAIA,GAAY,EACd,MAAM,IAAI,MAAM,+DAAa,EAE/B,KAAK,uBAAuB,CAAE,kBAAmBA,CAAS,CAAC,CAC7D,CAKO,oBAAoBC,EAAuB,CAChD,GAAIA,GAAW,EACb,MAAM,IAAI,MAAM,+DAAa,EAE/B,KAAK,uBAAuB,CAAE,iBAAkBA,CAAQ,CAAC,CAC3D,CAKO,qBAAqBD,EAAwB,CAClD,GAAIA,GAAY,EACd,MAAM,IAAI,MAAM,mDAAW,EAE7B,KAAK,uBAAuB,CAAE,kBAAmBA,CAAS,CAAC,CAC7D,CAKO,qBAAkD,CAEvD,OADe,KAAK,UAAU,EAChB,YAAc,CAAC,CAC/B,CAMO,qBAA0C,CAE/C,OADyB,KAAK,oBAAoB,EAC1B,QAAU,QAAQ,IAAI,oBAChD,CAKO,uBACLE,EACM,CACN,IAAMrC,EAAS,KAAK,iBAAiB,EAGhCA,EAAO,aACVA,EAAO,WAAa,CAAC,GAIvB,OAAO,OAAOA,EAAO,WAAYqC,CAAgB,EACjD,KAAK,WAAWrC,CAAM,EAGtB,KAAK,SAAS,UAAU,iBAAkB,CACxC,KAAM,aACN,UAAW,IAAI,IACjB,CAAC,CACH,CAKO,oBAAoBsC,EAAsB,CAC/C,GAAI,CAACA,GAAU,OAAOA,GAAW,SAC/B,MAAM,IAAI,MAAM,0DAAkB,EAEpC,KAAK,uBAAuB,CAAE,OAAAA,CAAO,CAAC,CACxC,CAKO,oBAA6C,CAElD,OADe,KAAK,UAAU,EAChB,WAAa,IAC7B,CAKO,mBAAqC,CAC1C,IAAMC,EAAkB,KAAK,mBAAmB,EAChD,MAAI,CAACA,GAAmB,CAACA,EAAgB,MAChC,CAAC,EAGHA,EAAgB,KACzB,CAKO,uBAAuBC,EAAiC,CAC7D,GAAI,CAAC,MAAM,QAAQA,CAAK,EACtB,MAAO,GAGT,QAAW1B,KAAQ0B,EA0CjB,GAxCI,CAAC1B,EAAK,MAAQ,OAAOA,EAAK,MAAS,UAKnC,CAACA,EAAK,aAAe,OAAOA,EAAK,aAAgB,UAOjD,CAACA,EAAK,aAAe,OAAOA,EAAK,aAAgB,UAOjD,CAACA,EAAK,SAAW,OAAOA,EAAK,SAAY,UAS3C,CAAC,CAAC,QAAS,WAAY,OAAQ,SAAU,QAAS,KAAK,EAAE,SACvDA,EAAK,QAAQ,IACf,GAUE,CAAC,KAAK,sBAAsBA,EAAK,KAAMA,EAAK,OAAO,EACrD,MAAO,GAIX,MAAO,EACT,CAKQ,sBACNL,EACAgC,EACS,CACT,OAAQA,EAAQ,KAAM,CACpB,IAAK,QACH,OAAO,KAAK,qBAAqBhC,EAAUgC,CAAO,EACpD,IAAK,OACH,OAAO,KAAK,oBAAoBhC,EAAUgC,CAAO,EACnD,IAAK,WACH,OAAO,KAAK,wBAAwBhC,EAAUgC,CAAO,EACvD,IAAK,SACH,OAAO,KAAK,sBAAsBhC,EAAUgC,CAAO,EACrD,IAAK,QACH,OAAO,KAAK,qBAAqBhC,EAAUgC,CAAO,EACpD,IAAK,MACH,OAAO,KAAK,mBAAmBhC,EAAUgC,CAAO,EAClD,QAKE,MAAO,EACX,CACF,CAKQ,qBACNhC,EACAgC,EACS,CAwBT,MAvBI,GAACA,EAAQ,UAOT,CAAC,CAAC,OAAQ,SAAU,YAAa,QAAQ,EAAE,SAASA,EAAQ,QAAQ,GAQpE,CAACA,EAAQ,QAAU,OAAOA,EAAQ,QAAW,UAQ7CA,EAAQ,WAAa,QACnB,CAACA,EAAQ,OAAO,aAAe,CAACA,EAAQ,OAAO,OAUvD,CAKQ,oBACNhC,EACAgC,EACS,CACT,GAAI,CAACA,EAAQ,KAAO,OAAOA,EAAQ,KAAQ,SAIzC,MAAO,GAGT,GAAI,CACF,IAAI,IAAIA,EAAQ,GAAG,CACrB,MAAQ,CAKN,MAAO,EACT,CAEA,MACE,EAAAA,EAAQ,QACR,CAAC,CAAC,MAAO,OAAQ,MAAO,SAAU,OAAO,EAAE,SAASA,EAAQ,MAAM,EAUtE,CAKQ,wBACNhC,EACAgC,EACS,CAQT,MAPI,GAACA,EAAQ,QAAU,OAAOA,EAAQ,QAAW,UAO7C,CAACA,EAAQ,UAAY,OAAOA,EAAQ,UAAa,SAQvD,CAKQ,sBACNhC,EACAgC,EACS,CAQT,MAPI,GAACA,EAAQ,QAAU,OAAOA,EAAQ,QAAW,UAQ/CA,EAAQ,aACR,CAAC,CAAC,OAAQ,SAAU,MAAM,EAAE,SAASA,EAAQ,WAAW,EAU5D,CAKQ,qBACNhC,EACAgC,EACS,CAoBT,MAlBE,GAACA,EAAQ,OACT,CAAC,MAAM,QAAQA,EAAQ,KAAK,GAC5BA,EAAQ,MAAM,SAAW,GAQvB,CAAC,CAAC,aAAc,UAAU,EAAE,SAASA,EAAQ,IAAI,GAQjD,CAAC,CAAC,OAAQ,WAAY,OAAO,EAAE,SAASA,EAAQ,cAAc,EASpE,CAKQ,mBACNhC,EACAgC,EACS,CAgBT,MAfI,GAACA,EAAQ,QAAU,OAAOA,EAAQ,QAAW,UAM/C,CAACA,EAAQ,OAAO,aAChB,OAAOA,EAAQ,OAAO,aAAgB,UAStC,CAACA,EAAQ,OAAO,UAChB,OAAOA,EAAQ,OAAO,UAAa,SASvC,CAKO,wBAAkC,CACvC,GAAI,CACF,IAAMD,EAAQ,KAAK,kBAAkB,EACrC,OAAIA,EAAM,SAAW,EACZ,GAGF,KAAK,uBAAuBA,CAAK,CAC1C,MAAgB,CAEd,MAAO,EACT,CACF,CAKO,iBAAiB1B,EAA2B,CACjD,GAAI,CAACA,GAAQ,OAAOA,GAAS,SAC3B,MAAM,IAAI,MAAM,kDAAU,EAG5B,IAAMd,EAAS,KAAK,iBAAiB,EAWrC,GARKA,EAAO,YACVA,EAAO,UAAY,CAAE,MAAO,CAAC,CAAE,GAIZA,EAAO,UAAU,MAAM,KACzCgB,GAAMA,EAAE,OAASF,EAAK,IACzB,EAEE,MAAM,IAAI,MAAM,iBAAOA,EAAK,IAAI,sBAAO,EAIzC,GAAI,CAAC,KAAK,uBAAuB,CAACA,CAAI,CAAC,EACrC,MAAM,IAAI,MAAM,kDAAU,EAI5Bd,EAAO,UAAU,MAAM,QAAQc,CAAI,EACnC,KAAK,WAAWd,CAAM,CAGxB,CAMA,MAAa,kBAAkBwC,EAAuC,CACpE,GAAI,CAAC,MAAM,QAAQA,CAAK,EACtB,MAAM,IAAI,MAAM,wDAAW,EAG7B,GAAIA,EAAM,SAAW,EACnB,OAGF,IAAMxC,EAAS,KAAK,iBAAiB,EAGhCA,EAAO,YACVA,EAAO,UAAY,CAAE,MAAO,CAAC,CAAE,GAIjC,IAAM0C,EAAgB,IAAI,IACxB1C,EAAO,UAAU,MAAM,IAAKc,GAASA,EAAK,IAAI,CAChD,EACM6B,EAAWH,EAAM,OAAQ1B,GAAS,CAAC4B,EAAc,IAAI5B,EAAK,IAAI,CAAC,EAErE,GAAI6B,EAAS,OAAS,EAAG,CAEvB,GAAI,CAAC,KAAK,uBAAuBA,CAAQ,EACvC,MAAM,IAAI,MAAM,kDAAU,EAI5B3C,EAAO,UAAU,MAAM,KAAK,GAAG2C,CAAQ,EACvC,KAAK,WAAW3C,CAAM,EAGtB,KAAK,SAAS,UAAU,iBAAkB,CACxC,KAAM,YACN,UAAW,IAAI,IACjB,CAAC,CAMH,CACF,CAKO,oBAAoBS,EAAwB,CACjD,GAAI,CAACA,GAAY,OAAOA,GAAa,SACnC,MAAM,IAAI,MAAM,kDAAU,EAG5B,IAAMT,EAAS,KAAK,iBAAiB,EAErC,GAAI,CAACA,EAAO,WAAa,CAACA,EAAO,UAAU,MACzC,MAAM,IAAI,MAAM,uDAAe,EAGjC,IAAMe,EAAYf,EAAO,UAAU,MAAM,UACtCgB,GAAMA,EAAE,OAASP,CACpB,EACA,GAAIM,IAAc,GAChB,MAAM,IAAI,MAAM,iBAAON,CAAQ,sBAAO,EAIxCT,EAAO,UAAU,MAAM,OAAOe,EAAW,CAAC,EAC1C,KAAK,WAAWf,CAAM,CAGxB,CAOO,oBACLS,EACAmC,EACM,CACN,GAAI,CAACnC,GAAY,OAAOA,GAAa,SACnC,MAAM,IAAI,MAAM,kDAAU,EAE5B,GAAI,CAACmC,GAAe,OAAOA,GAAgB,SACzC,MAAM,IAAI,MAAM,0EAAc,EAGhC,IAAM5C,EAAS,KAAK,iBAAiB,EAErC,GAAI,CAACA,EAAO,WAAa,CAACA,EAAO,UAAU,MACzC,MAAM,IAAI,MAAM,uDAAe,EAGjC,IAAMe,EAAYf,EAAO,UAAU,MAAM,UACtCgB,GAAMA,EAAE,OAASP,CACpB,EACA,GAAIM,IAAc,GAChB,MAAM,IAAI,MAAM,iBAAON,CAAQ,sBAAO,EAIxC,GAAI,CAAC,KAAK,uBAAuB,CAACmC,CAAW,CAAC,EAC5C,MAAM,IAAI,MAAM,0EAAc,EAIhC5C,EAAO,UAAU,MAAMe,CAAS,EAAI6B,EACpC,KAAK,WAAW5C,CAAM,CAGxB,CAKO,qBAAqBwC,EAA8B,CACxD,GAAI,CAAC,MAAM,QAAQA,CAAK,EACtB,MAAM,IAAI,MAAM,wDAAW,EAI7B,GAAI,CAAC,KAAK,uBAAuBA,CAAK,EACpC,MAAM,IAAI,MAAM,kDAAU,EAG5B,IAAMxC,EAAS,KAAK,iBAAiB,EAGhCA,EAAO,YACVA,EAAO,UAAY,CAAE,MAAO,CAAC,CAAE,GAGjCA,EAAO,UAAU,MAAQwC,EACzB,KAAK,WAAWxC,CAAM,EAGtB,KAAK,SAAS,UAAU,iBAAkB,CACxC,KAAM,YACN,UAAW,IAAI,IACjB,CAAC,CAGH,CAKO,gBAAwC,CAE7C,OADe,KAAK,UAAU,EAChB,OAAS,CAAC,CAC1B,CAKO,cAAuB,CAE5B,OADoB,KAAK,eAAe,EACrB,MAAQ,IAC7B,CAMQ,mBAAmBA,EAAyB,CAClD,GAAI,CAEF,IAAM6C,EACJ,OACA,YACEA,GAAa,OAAOA,EAAU,uBAA0B,YAE1DA,EAAU,sBAAsB7C,CAAM,CAG1C,MAAgB,CAMhB,CACF,CAKO,kBAAkB8C,EAAyC,CAChE,IAAM9C,EAAS,KAAK,iBAAiB,EAGhCA,EAAO,QACVA,EAAO,MAAQ,CAAC,GAIlB,OAAO,OAAOA,EAAO,MAAO8C,CAAW,EACvC,KAAK,WAAW9C,CAAM,EAGtB,KAAK,SAAS,UAAU,iBAAkB,CACxC,KAAM,QACN,UAAW,IAAI,IACjB,CAAC,CACH,CAKO,aAAa+C,EAAoB,CACtC,GAAI,CAAC,OAAO,UAAUA,CAAI,GAAKA,GAAQ,GAAKA,EAAO,MACjD,MAAM,IAAI,MAAM,6EAAsB,EAExC,KAAK,kBAAkB,CAAE,KAAAA,CAAK,CAAC,CACjC,CAEO,qBACL1B,EACAC,EACM,CACN,IAAMtB,EAAS,KAAK,iBAAiB,EAChCA,EAAO,YACVA,EAAO,UAAY,CAAC,GAEtBA,EAAO,UAAUqB,CAAY,EAAIC,EAEjC,KAAK,WAAWtB,CAAM,EAGtB,KAAK,SAAS,UAAU,iBAAkB,CACxC,KAAM,WACN,aAAAqB,EACA,UAAW,IAAI,IACjB,CAAC,CACH,CAKO,uBAAmD,CAExD,IAAM2B,EADS,KAAK,UAAU,EACJ,WAAW,KAErC,MAAI,CAACA,GAAc,CAACA,EAAW,MACtB,KAGF,CACL,MAAOA,EAAW,KACpB,CACF,CAKO,cAA8B,CAEnC,OADmB,KAAK,sBAAsB,GAC3B,OAAS,IAC9B,CAKO,sBAAsBhD,EAAkC,CAC7D,GACE,CAACA,EAAO,OACR,OAAOA,EAAO,OAAU,UACxBA,EAAO,MAAM,KAAK,IAAM,GAExB,MAAM,IAAI,MAAM,iDAAmB,EAGrC,KAAK,qBAAqB,OAAQ,CAChC,MAAOA,EAAO,MAAM,KAAK,CAC3B,CAAC,CACH,CAKO,mBAA6B,CAClC,IAAMgD,EAAa,KAAK,sBAAsB,EAC9C,OACEA,IAAe,MACf,OAAOA,EAAW,OAAU,UAC5BA,EAAW,MAAM,KAAK,IAAM,EAEhC,CAUA,MAAc,0BACZ7C,EACAM,EACAuB,EACAC,EAAsB,GACP,CACf,IAAMjC,EAAS,KAAK,iBAAiB,EAGhCA,EAAO,kBACVA,EAAO,gBAAkB,CAAC,GAIvBA,EAAO,gBAAgBG,CAAU,IACpCH,EAAO,gBAAgBG,CAAU,EAAI,CAAE,MAAO,CAAC,CAAE,GAI9CH,EAAO,gBAAgBG,CAAU,EAAE,MAAMM,CAAQ,IACpDT,EAAO,gBAAgBG,CAAU,EAAE,MAAMM,CAAQ,EAAI,CACnD,OAAQ,EACV,GAGF,IAAMwC,EAAajD,EAAO,gBAAgBG,CAAU,EAAE,MAAMM,CAAQ,EAC9DyC,EAAoBD,EAAW,YAAc,EAC7CE,EAAsBF,EAAW,aAGnChB,IACFgB,EAAW,WAAaC,EAAoB,IAK5C,CAACC,GACD,IAAI,KAAKnB,CAAQ,EAAI,IAAI,KAAKmB,CAAmB,KAGjDF,EAAW,aAAe5E,GAAM2D,CAAQ,EAAE,OAAO,qBAAqB,GAIxE,KAAK,WAAWhC,CAAM,CACxB,CAgCA,MAAc,yBACZ6B,EACAC,EACAC,EACe,CACf,GAAI,CACF,IAAItB,EACAuB,EACAC,EAAsB,GACtBmB,EAGJ,GAAI,OAAOrB,GAAS,SAAU,CAE5B,IAAM5B,EAAa0B,EACnBpB,EAAW,GAAGN,CAAU,KAAK2B,CAAI,GACjCE,EAAWD,EACXqB,EAAY,GAAGjD,CAAU,IAAI2B,CAAI,EACnC,MAEErB,EAAWoB,EACXG,EAAWF,EACXG,EAAuBF,GAAoB,GAC3CqB,EAAY3C,EAGd,IAAM4C,EAAc,KAAK,kBAAkB,EACrCtC,EAAYsC,EAAY,UAAWvC,GAASA,EAAK,OAASL,CAAQ,EAExE,GAAIM,IAAc,GAEhB,OAGF,IAAMuC,EAAe,CAAC,GAAGD,CAAW,EAC9BvC,EAAOwC,EAAavC,CAAS,EAG9BD,EAAK,QACRA,EAAK,MAAQ,CAAC,GAGhB,IAAMoC,EAAoBpC,EAAK,MAAM,YAAc,EAC7CqC,EAAsBrC,EAAK,MAAM,aAGnCmB,IACFnB,EAAK,MAAM,WAAaoC,EAAoB,IAK5C,CAACC,GACD,IAAI,KAAKnB,CAAQ,EAAI,IAAI,KAAKmB,CAAmB,KAEjDrC,EAAK,MAAM,aAAezC,GAAM2D,CAAQ,EAAE,OAAO,qBAAqB,GAIxE,MAAM,KAAK,qBAAqBsB,CAAY,CAC9C,MAAgB,CAEd,GAAI,OAAOvB,GAAS,SAAU,CAC5B,IAAM5B,EAAa0B,EACbpB,EAAWqB,CAMnB,KAAO,CACL,IAAMrB,EAAWoB,CAEnB,CAEF,CACF,CAOA,MAAc,uBAAuB0B,EAAmC,CACtE,GAAI,KAAK,iBAAiB,IAAIA,CAAO,EAEnC,MAAO,GAGT,IAAMC,EAAgB,IAAI,QAAetF,GAAY,CAErD,CAAC,EAED,KAAK,iBAAiB,IAAIqF,EAASC,CAAa,EAGhD,IAAMpB,EAAU,WAAW,IAAM,CAC/B,KAAK,uBAAuBmB,CAAO,CACrC,EAAG,KAAK,oBAAoB,EAE5B,YAAK,wBAAwB,IAAIA,EAASnB,CAAO,EAE1C,EACT,CAOQ,uBAAuBmB,EAAuB,CACpD,KAAK,iBAAiB,OAAOA,CAAO,EAEpC,IAAMnB,EAAU,KAAK,wBAAwB,IAAImB,CAAO,EACpDnB,IACF,aAAaA,CAAO,EACpB,KAAK,wBAAwB,OAAOmB,CAAO,EAI/C,CAOA,MAAa,6BACX9C,EACAwB,EAAsB,GACP,CACf,IAAMsB,EAAU,aAAa9C,CAAQ,GAErC,GAAM,MAAM,KAAK,uBAAuB8C,CAAO,EAI/C,GAAI,CACF,MAAM,KAAK,qBAAqB9C,EAAUwB,CAAmB,CAE/D,OAASpC,EAAO,CAEd,MAAMA,CACR,QAAE,CACA,KAAK,uBAAuB0D,CAAO,CACrC,CACF,CASA,MAAa,iCACXrB,EACAzB,EACAuB,EACAC,EAAsB,GACP,CACf,IAAMsB,EAAU,aAAarB,CAAW,IAAIzB,CAAQ,GAEpD,GAAM,MAAM,KAAK,uBAAuB8C,CAAO,EAI/C,GAAI,CACF,MAAM,KAAK,yBACTrB,EACAzB,EACAuB,EACAC,CACF,CAEF,OAASpC,EAAO,CAMd,MAAMA,CACR,QAAE,CACA,KAAK,uBAAuB0D,CAAO,CACrC,CACF,CAKO,0BAAiC,CACtC,IAAME,EAAY,KAAK,iBAAiB,KACxC,KAAK,iBAAiB,MAAM,EAG5B,QAAWrB,KAAW,KAAK,wBAAwB,OAAO,EACxD,aAAaA,CAAO,EAEtB,KAAK,wBAAwB,MAAM,EAE/BqB,EAAY,CAGlB,CAKO,qBAAgC,CACrC,OAAO,MAAM,KAAK,KAAK,iBAAiB,KAAK,CAAC,CAChD,CAKO,sBAAoD,CAEzD,OADe,KAAK,UAAU,EAChB,aAAe,CAAC,CAChC,CAKO,wBACLC,EACM,CACN,IAAM1D,EAAS,KAAK,iBAAiB,EAGhCA,EAAO,cACVA,EAAO,YAAc,CAAC,GAIxB,OAAO,OAAOA,EAAO,YAAa0D,CAAiB,EACnD,KAAK,WAAW1D,CAAM,CACxB,CAKO,cAAuB,CAE5B,OAAO,QAAQ,IAAI,oBAAsB,QAAQ,IAAI,CACvD,CACF,EAGarB,EAAgBD,GAAc,YAAY,ICtsEvD,IAOaiF,GAgBAC,GAgBAC,GAYAC,EAsBAC,GAcAC,GAvFbC,GAAAC,EAAA,kBAOaP,GAAoB,CAE/B,KAAM,sBAEN,aAAc,IAEd,oBAAqB,KAErB,SAAU,cAEV,SAAU,aACZ,EAKaC,GAAmB,CAE9B,WAAY,CACV,uBACA,uBACA,qBACF,EAEA,aAAc,8BAEd,YAAa,oBACf,EAKaC,GAAiB,CAE5B,SAAU,WAEV,cAAe,YAEf,SAAU,MACZ,EAKaC,EAAc,CAEzB,cAAe,gBAEf,aAAc,eAEd,cAAe,gBAEf,iBAAkB,mBAElB,WAAY,aAEZ,cAAe,gBAEf,cAAe,gBAEf,iBAAkB,kBACpB,EAKaC,GAAoB,CAE/B,aAAc,IAEd,cAAe,IAEf,gBAAiB,IAEjB,eAAgB,GAClB,EAKaC,GAAuB,CAElC,cAAe,GAEf,UAAW,GACb,IC5FA,IASMG,GAaAC,GA0BOC,GAhDbC,GAAAC,EAAA,kBAIAC,KAKML,GAA8C,CAClD,CAACM,EAAY,YAAY,EAAG,iFAC5B,CAACA,EAAY,aAAa,EAAG,qEAC7B,CAACA,EAAY,gBAAgB,EAAG,+DAChC,CAACA,EAAY,UAAU,EAAG,yDAC1B,CAACA,EAAY,aAAa,EAAG,yDAC7B,CAACA,EAAY,aAAa,EAAG,2EAC7B,CAACA,EAAY,gBAAgB,EAAG,oEAClC,EAKML,GAA6C,CACjD,iBAAkB,CAChB,yEACA,uFACA,8FACF,EACA,sBAAuB,CACrB,iFACA,8FACA,0EACF,EACA,kBAAmB,CACjB,yDACA,qEACA,0EACF,EACA,qBAAsB,CACpB,2EACA,uFACA,0EACF,CACF,EAKaC,GAAN,KAAqB,CAhD5B,MAgD4B,CAAAK,EAAA,uBAI1B,OAAO,eAAeC,EAAuC,CAC3D,OAAOR,GAAoBQ,CAAS,CACtC,CAKA,OAAO,aAAaC,EAA8B,CAChD,OAAOR,GAAiBQ,CAAU,GAAK,CAAC,CAC1C,CAKA,OAAO,YAAYC,EAAcC,EAA0B,CAEzD,MAAO,GADeA,EAAU,IAAIA,CAAO,KAAO,EAC3B,GAAGD,EAAM,OAAO,EACzC,CAKA,OAAO,mBAAmBF,EAA2B,CAWnD,MAViD,CAC/C,CAACF,EAAY,YAAY,EAAG,mDAC5B,CAACA,EAAY,aAAa,EAAG,mDAC7B,CAACA,EAAY,gBAAgB,EAAG,uCAChC,CAACA,EAAY,UAAU,EAAG,uCAC1B,CAACA,EAAY,aAAa,EAAG,uCAC7B,CAACA,EAAY,aAAa,EAAG,uCAC7B,CAACA,EAAY,gBAAgB,EAAG,sCAClC,EAEwBE,CAAS,GAAK,0BACxC,CAKA,OAAO,cAAcA,EAA4B,CAO/C,MANoC,CAClCF,EAAY,cACZA,EAAY,WACZA,EAAY,aACd,EAEyB,SAASE,CAAS,CAC7C,CAKA,OAAO,YACLA,EACwC,CAYxC,MAVE,CACE,CAACF,EAAY,gBAAgB,EAAG,MAChC,CAACA,EAAY,UAAU,EAAG,SAC1B,CAACA,EAAY,YAAY,EAAG,SAC5B,CAACA,EAAY,aAAa,EAAG,SAC7B,CAACA,EAAY,aAAa,EAAG,OAC7B,CAACA,EAAY,aAAa,EAAG,OAC7B,CAACA,EAAY,gBAAgB,EAAG,UAClC,EAEiBE,CAAS,GAAK,QACnC,CACF,ICxHA,IASaI,EA+BAC,GAsBAC,EAoCAC,EAqBAC,EA2BAC,GAlJbC,GAAAC,EAAA,kBAIAC,KAKaR,EAAN,MAAMS,UAAiB,KAAM,CAClC,YACEC,EACOC,EACAC,EAAW,EACXC,EACP,CACA,MAAMH,CAAO,EAJN,UAAAC,EACA,cAAAC,EACA,iBAAAC,EAGP,KAAK,KAAO,WAGR,MAAM,mBACR,MAAM,kBAAkB,KAAMJ,CAAQ,CAE1C,CAvBF,MASoC,CAAAK,EAAA,iBAmBlC,OAAO,gBACLJ,EACAC,EACAE,EACU,CACV,OAAO,IAAIJ,EAASC,EAASC,EAAM,EAAGE,CAAW,CACnD,CACF,EAKaZ,GAAN,MAAMc,UAAoBf,CAAS,CAxC1C,MAwC0C,CAAAc,EAAA,oBACxC,YAAYJ,EAAiBG,EAAwB,CACnD,MAAMH,EAASM,EAAY,aAAc,EAAGH,CAAW,EACvD,KAAK,KAAO,aACd,CAEA,OAAO,gBAA8B,CACnC,OAAO,IAAIE,EAAY,6CAAW,CAChC,8EACF,CAAC,CACH,CAEA,OAAO,cAAcE,EAA6B,CAChD,OAAO,IAAIF,EAAY,2DAAcE,CAAM,GAAI,CAC7C,oDACF,CAAC,CACH,CACF,EAKaf,EAAN,MAAMgB,UAAqBlB,CAAS,CA9D3C,MA8D2C,CAAAc,EAAA,qBACzC,YAAYJ,EAAiBG,EAAwB,CACnD,MAAMH,EAASM,EAAY,cAAe,EAAGH,CAAW,EACxD,KAAK,KAAO,cACd,CAEA,OAAO,eAAeM,EAA2B,CAC/C,OAAO,IAAID,EAAa,oDAAiBC,CAAG,IAAK,CAC/C,+EACA,qEACF,CAAC,CACH,CAEA,OAAO,eAAeA,EAA2B,CAC/C,OAAO,IAAID,EACT,gEAAmBC,CAAG,iDACtB,CAAC,kIAAmC,CACtC,CACF,CAEA,OAAO,YAA2B,CAChC,OAAO,IAAID,EAAa,iCAAS,CAAC,6DAA0B,CAAC,CAC/D,CAEA,OAAO,YAAYE,EAA8B,CAC/C,OAAO,IAAIF,EAAa,yCAAWE,CAAM,GAAI,CAC3C,+DACA,mDACA,0EACF,CAAC,CACH,CACF,EAKajB,EAAN,MAAMkB,UAAwBrB,CAAS,CAlG9C,MAkG8C,CAAAc,EAAA,wBAC5C,YAAYJ,EAAiBY,EAAe,CAC1C,MAAM,6BAASA,CAAK,MAAMZ,CAAO,GAAIM,EAAY,iBAAkB,CAAC,EACpE,KAAK,KAAO,iBACd,CAEA,OAAO,YAAYO,EAA+B,CAChD,OAAO,IAAIF,EACT,4FAA2BE,CAAI,GAC/B,MACF,CACF,CAEA,OAAO,cAAcD,EAAgC,CACnD,OAAO,IAAID,EAAgB,mDAAYC,CAAK,CAC9C,CACF,EAKalB,EAAN,MAAMoB,UAAkBxB,CAAS,CAvHxC,MAuHwC,CAAAc,EAAA,kBACtC,YAAYJ,EAAiBe,EAAmBZ,EAAwB,CACtE,IAAMa,EAAcD,EAAW,GAAGf,CAAO,KAAKe,CAAQ,GAAKf,EAC3D,MAAMgB,EAAaV,EAAY,WAAY,EAAGH,CAAW,EACzD,KAAK,KAAO,WACd,CAEA,OAAO,SAASY,EAA6B,CAC3C,OAAO,IAAID,EAAU,iCAASC,EAAU,CAAC,8DAAY,CAAC,CACxD,CAEA,OAAO,iBAAiBA,EAA6B,CACnD,OAAO,IAAID,EAAU,2BAAQC,EAAU,CACrC,kGACF,CAAC,CACH,CAEA,OAAO,cAAcA,EAA6B,CAChD,OAAO,IAAID,EAAU,iCAASC,EAAU,CACtC,4FACF,CAAC,CACH,CACF,EAKapB,GAAN,MAAMsB,UAAqB3B,CAAS,CAlJ3C,MAkJ2C,CAAAc,EAAA,qBACzC,YAAYJ,EAAiBS,EAAcN,EAAwB,CACjE,IAAMa,EAAcP,EAAM,GAAGT,CAAO,UAAUS,CAAG,IAAMT,EACvD,MAAMgB,EAAaV,EAAY,cAAe,EAAGH,CAAW,EAC5D,KAAK,KAAO,cACd,CAEA,OAAO,WAAWM,EAA2B,CAC3C,OAAO,IAAIQ,EAAa,uCAAUR,EAAK,CACrC,gFACF,CAAC,CACH,CAEA,OAAO,SAASA,EAA2B,CACzC,OAAO,IAAIQ,EAAa,iCAASR,CAAG,CACtC,CACF,IC5JA,MAAkB,QANlB,IAWaS,GAXbC,GAAAC,EAAA,kBAIAC,KACAC,KAMaJ,GAAN,MAAMK,CAAa,CAX1B,MAW0B,CAAAC,EAAA,qBAIxB,OAAO,OAAOC,EAAqB,CAC7BA,aAAiBC,EACnBH,EAAa,eAAeE,CAAK,EAEjCF,EAAa,mBAAmBE,CAAK,EAGvC,QAAQ,KAAK,CAAC,CAChB,CAKA,OAAe,eAAeA,EAAuB,CASnD,GALI,QAAQ,IAAI,MAKZA,EAAM,aAAeA,EAAM,YAAY,OAAS,EAElD,QAAWE,KAAcF,EAAM,YAAa,CAM9C,IAAMG,EAAcC,GAAe,eAAeJ,EAAM,IAAI,CAI9D,CAKA,OAAe,mBAAmBA,EAAoB,CAIhD,QAAQ,IAAI,OAAS,QAAQ,IAAI,QAQvC,CAKA,aAAa,YACXK,EACAC,EACY,CACZ,GAAI,CACF,OAAO,MAAMD,EAAU,CACzB,OAASL,EAAO,CACd,MAAIA,aAAiBC,EACbD,EAEJA,aAAiB,MACb,IAAIC,EACR,GAAGK,CAAO,iBAAON,EAAM,OAAO,GAC9B,mBACA,CACF,EAEI,IAAIC,EAAS,GAAGK,CAAO,yCAAY,mBAAoB,CAAC,CAChE,CACF,CAKA,OAAO,WAAcD,EAAoBC,EAAoB,CAC3D,GAAI,CACF,OAAOD,EAAU,CACnB,OAASL,EAAO,CACd,MAAIA,aAAiBC,EACbD,EAEJA,aAAiB,MACb,IAAIC,EACR,GAAGK,CAAO,iBAAON,EAAM,OAAO,GAC9B,mBACA,CACF,EAEI,IAAIC,EAAS,GAAGK,CAAO,yCAAY,mBAAoB,CAAC,CAChE,CACF,CAKA,OAAO,KAAKC,EAAiBC,EAA8B,CAGzD,GAAIA,GAAeA,EAAY,OAAS,EAEtC,QAAWN,KAAcM,EAAa,CAI1C,CAKA,OAAO,KAAKD,EAAuB,CAEnC,CAKA,OAAO,QAAQA,EAAuB,CAEtC,CACF,ICxIA,OAAOE,MAAQ,KACf,OAAOC,MAAU,OALjB,IAYaC,EAZbC,GAAAC,EAAA,kBAOAC,KAKaH,EAAN,MAAMI,CAAU,CAZvB,MAYuB,CAAAC,EAAA,kBAIrB,OAAO,OAAOC,EAA2B,CACvC,GAAI,CACF,OAAOR,EAAG,WAAWQ,CAAQ,CAC/B,MAAQ,CACN,MAAO,EACT,CACF,CAKA,OAAO,UAAUC,EAAuB,CACtC,GAAI,CACGT,EAAG,WAAWS,CAAO,GACxBT,EAAG,UAAUS,EAAS,CAAE,UAAW,EAAK,CAAC,CAE7C,MAAgB,CACd,MAAM,IAAIC,EAAU,uCAAUD,CAAO,CACvC,CACF,CAKA,OAAO,SAASD,EAAkBG,EAA2B,OAAgB,CAC3E,GAAI,CACF,GAAI,CAACL,EAAU,OAAOE,CAAQ,EAC5B,MAAME,EAAU,SAASF,CAAQ,EAEnC,OAAOR,EAAG,aAAaQ,EAAUG,CAAQ,CAC3C,OAASC,EAAO,CACd,MAAIA,aAAiBF,EACbE,EAEF,IAAIF,EAAU,uCAAUF,CAAQ,CACxC,CACF,CAKA,OAAO,UACLA,EACAK,EACAC,EACM,CACN,GAAI,CACF,GAAI,CAACA,GAAS,WAAaR,EAAU,OAAOE,CAAQ,EAClD,MAAME,EAAU,cAAcF,CAAQ,EAIxC,IAAMO,EAAMd,EAAK,QAAQO,CAAQ,EACjCF,EAAU,UAAUS,CAAG,EAEvBf,EAAG,cAAcQ,EAAUK,EAAS,MAAM,CAC5C,OAASD,EAAO,CACd,MAAIA,aAAiBF,EACbE,EAEF,IAAIF,EAAU,uCAAUF,CAAQ,CACxC,CACF,CAKA,OAAO,SACLQ,EACAC,EACAH,EACM,CACN,GAAI,CACF,GAAI,CAACR,EAAU,OAAOU,CAAO,EAC3B,MAAMN,EAAU,SAASM,CAAO,EAGlC,GAAI,CAACF,GAAS,WAAaR,EAAU,OAAOW,CAAQ,EAClD,MAAMP,EAAU,cAAcO,CAAQ,EAIxC,IAAMC,EAAUjB,EAAK,QAAQgB,CAAQ,EACrCX,EAAU,UAAUY,CAAO,EAE3BlB,EAAG,aAAagB,EAASC,CAAQ,CACnC,OAASL,EAAO,CACd,MAAIA,aAAiBF,EACbE,EAEF,IAAIF,EAAU,uCAAUM,CAAO,CACvC,CACF,CAKA,OAAO,WAAWR,EAAwB,CACxC,GAAI,CACEF,EAAU,OAAOE,CAAQ,GAC3BR,EAAG,WAAWQ,CAAQ,CAE1B,MAAgB,CACd,MAAM,IAAIE,EAAU,uCAAUF,CAAQ,CACxC,CACF,CAKA,OAAO,cACLW,EACAD,EACAJ,EAAgC,CAAC,EAC3B,CACN,GAAI,CACF,GAAI,CAACR,EAAU,OAAOa,CAAM,EAC1B,MAAMT,EAAU,SAASS,CAAM,EAIjCb,EAAU,UAAUY,CAAO,EAE3B,IAAME,EAAQpB,EAAG,YAAYmB,CAAM,EAEnC,QAAWE,KAAQD,EAAO,CAExB,GAAIN,EAAQ,SAAS,SAASO,CAAI,EAChC,SAGF,IAAML,EAAUf,EAAK,KAAKkB,EAAQE,CAAI,EAChCJ,EAAWhB,EAAK,KAAKiB,EAASG,CAAI,EAC3BrB,EAAG,SAASgB,CAAO,EAEvB,YAAY,EACfF,EAAQ,YAAc,IACxBR,EAAU,cAAcU,EAASC,EAAUH,CAAO,EAGpDR,EAAU,SAASU,EAASC,EAAU,CACpC,UAAWH,EAAQ,SACrB,CAAC,CAEL,CACF,OAASF,EAAO,CACd,MAAIA,aAAiBF,EACbE,EAEF,IAAIF,EAAU,uCAAUS,CAAM,CACtC,CACF,CAKA,OAAO,gBACLV,EACAK,EAAmC,CAAC,EAC9B,CACN,GAAI,CACER,EAAU,OAAOG,CAAO,GAC1BT,EAAG,OAAOS,EAAS,CACjB,UAAWK,EAAQ,WAAa,GAChC,MAAO,EACT,CAAC,CAEL,MAAgB,CACd,MAAM,IAAIJ,EAAU,uCAAUD,CAAO,CACvC,CACF,CAKA,OAAO,YAAYD,EAMjB,CACA,GAAI,CACF,GAAI,CAACF,EAAU,OAAOE,CAAQ,EAC5B,MAAME,EAAU,SAASF,CAAQ,EAGnC,IAAMc,EAAQtB,EAAG,SAASQ,CAAQ,EAClC,MAAO,CACL,KAAMc,EAAM,KACZ,OAAQA,EAAM,OAAO,EACrB,YAAaA,EAAM,YAAY,EAC/B,MAAOA,EAAM,MACb,MAAOA,EAAM,KACf,CACF,OAASV,EAAO,CACd,MAAIA,aAAiBF,EACbE,EAEF,IAAIF,EAAU,mDAAYF,CAAQ,CAC1C,CACF,CAKA,OAAO,cACLC,EACAK,EAGI,CAAC,EACK,CACV,GAAI,CACF,GAAI,CAACR,EAAU,OAAOG,CAAO,EAC3B,MAAMC,EAAU,SAASD,CAAO,EAGlC,IAAMW,EAAQpB,EAAG,YAAYS,CAAO,EAChCc,EAAmB,CAAC,EAExB,QAAWF,KAAQD,EAAO,CAExB,GAAI,CAACN,EAAQ,eAAiBO,EAAK,WAAW,GAAG,EAC/C,SAGF,IAAMG,EAAWvB,EAAK,KAAKQ,EAASY,CAAI,EAIxC,GAHAE,EAAO,KAAKC,CAAQ,EAGhBV,EAAQ,WAAad,EAAG,SAASwB,CAAQ,EAAE,YAAY,EAAG,CAC5D,IAAMC,EAAWnB,EAAU,cAAckB,EAAUV,CAAO,EAC1DS,EAASA,EAAO,OAAOE,CAAQ,CACjC,CACF,CAEA,OAAOF,CACT,OAASX,EAAO,CACd,MAAIA,aAAiBF,EACbE,EAEF,IAAIF,EAAU,mDAAYD,CAAO,CACzC,CACF,CAKA,OAAO,eAAeiB,EAAS,WAAYC,EAAS,OAAgB,CAClE,IAAMC,EAAU,QAAQ,IAAI,QAAU,QAAQ,IAAI,MAAQ,OACpDC,EAAY,KAAK,IAAI,EACrBC,EAAS,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,CAAC,EAC/CC,EAAW,GAAGL,CAAM,GAAGG,CAAS,IAAIC,CAAM,GAAGH,CAAM,GACzD,OAAO1B,EAAK,KAAK2B,EAASG,CAAQ,CACpC,CAKA,OAAO,iBACLvB,EACAwB,EAAehC,EAAG,UAAU,KAAOA,EAAG,UAAU,KACvC,CACT,GAAI,CACF,OAAAA,EAAG,WAAWQ,EAAUwB,CAAI,EACrB,EACT,MAAQ,CACN,MAAO,EACT,CACF,CAKA,OAAO,aAAaxB,EAA0B,CAC5C,OAAOP,EAAK,QAAQO,CAAQ,EAAE,YAAY,CAC5C,CAKA,OAAO,YAAYA,EAA0B,CAC3C,OAAOP,EAAK,SAASO,EAAUP,EAAK,QAAQO,CAAQ,CAAC,CACvD,CAKA,OAAO,cAAcA,EAA0B,CAC7C,OAAOP,EAAK,UAAUO,CAAQ,CAChC,CAKA,OAAO,YAAYA,EAAkByB,EAA2B,CAC9D,OAAIA,EACKhC,EAAK,QAAQgC,EAAUzB,CAAQ,EAEjCP,EAAK,QAAQO,CAAQ,CAC9B,CACF,IC9TA,IAOa0B,GAPbC,GAAAC,EAAA,kBAOaF,GAAN,KAAkB,CAPzB,MAOyB,CAAAG,EAAA,oBAIvB,OAAO,aAAaC,EAAoB,CACtC,IAAMC,EAAU,KAAK,MAAMD,EAAK,GAAI,EAC9BE,EAAU,KAAK,MAAMD,EAAU,EAAE,EACjCE,EAAQ,KAAK,MAAMD,EAAU,EAAE,EAC/BE,EAAO,KAAK,MAAMD,EAAQ,EAAE,EAElC,OAAIC,EAAO,EACF,GAAGA,CAAI,UAAKD,EAAQ,EAAE,gBAAMD,EAAU,EAAE,eAE7CC,EAAQ,EACH,GAAGA,CAAK,gBAAMD,EAAU,EAAE,eAE/BA,EAAU,EACL,GAAGA,CAAO,gBAAMD,EAAU,EAAE,SAE9B,GAAGA,CAAO,QACnB,CAKA,OAAO,eAAeI,EAAuB,CAC3C,IAAMC,EAAQ,CAAC,IAAK,KAAM,KAAM,KAAM,IAAI,EACtCC,EAAOF,EACPG,EAAY,EAEhB,KAAOD,GAAQ,MAAQC,EAAYF,EAAM,OAAS,GAChDC,GAAQ,KACRC,IAGF,MAAO,GAAGD,EAAK,QAAQC,IAAc,EAAI,EAAI,CAAC,CAAC,IAAIF,EAAME,CAAS,CAAC,EACrE,CAKA,OAAO,gBACLC,EACAC,EAAmC,OAC3B,CACR,IAAMC,EAAO,IAAI,KAAKF,CAAS,EAE/B,OAAQC,EAAQ,CACd,IAAK,OACH,OAAOC,EAAK,mBAAmB,OAAO,EACxC,IAAK,OACH,OAAOA,EAAK,mBAAmB,OAAO,EACxC,QACE,OAAOA,EAAK,eAAe,OAAO,CACtC,CACF,CAKA,OAAO,UAAUC,EAAqB,CACpC,MAAO,QAAQA,CAAG,EACpB,CAKA,OAAO,WAAWC,EAAsB,CACtC,MAAO,iBAAOA,CAAI,EACpB,CAKA,OAAO,UACLC,EACAC,EACAF,EACAG,EACQ,CACR,IAAMC,EAAM,GAAGH,CAAQ,MAAMC,CAAI,IAAIF,CAAI,GACzC,OAAOG,EAAO,GAAGC,CAAG,GAAGD,CAAI,GAAKC,CAClC,CAKA,OAAO,iBAAiBC,EAAaC,EAAoB,CACvD,OAAI,OAAOA,GAAU,SACZ,GAAGD,CAAG,KAAK,KAAK,UAAUC,EAAO,KAAM,CAAC,CAAC,GAE3C,GAAGD,CAAG,KAAKC,CAAK,EACzB,CAKA,OAAO,YAAYC,EAAcC,EAAe,GAAe,CAC7D,IAAIC,EAAU,iBAAOF,EAAM,OAAO,GAElC,OAAIC,GAAgBD,EAAM,QACxBE,GAAW;AAAA;AAAA,EAAYF,EAAM,KAAK,IAG7BE,CACT,CAKA,OAAO,WAAWC,EAAiBC,EAAS,SAAa,CACvD,OAAOD,EAAM,IAAKE,GAAS,GAAGD,CAAM,IAAIC,CAAI,EAAE,EAAE,KAAK;AAAA,CAAI,CAC3D,CAKA,OAAO,YAAYC,EAAqC,CACtD,GAAIA,EAAK,SAAW,EAAG,MAAO,GAE9B,IAAMC,EAAO,OAAO,KAAKD,EAAK,CAAC,CAAC,EAC1BE,EAAYD,EAAK,IAAKT,GAC1B,KAAK,IAAIA,EAAI,OAAQ,GAAGQ,EAAK,IAAKG,GAAQ,OAAOA,EAAIX,CAAG,CAAC,EAAE,MAAM,CAAC,CACpE,EAGMY,EAASH,EAAK,IAAI,CAACT,EAAKa,IAAMb,EAAI,OAAOU,EAAUG,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,EAClEC,EAAYJ,EAAU,IAAKK,GAAU,IAAI,OAAOA,CAAK,CAAC,EAAE,KAAK,KAAK,EAGlEC,EAAOR,EAAK,IAAKG,GACrBF,EAAK,IAAI,CAACT,EAAKa,IAAM,OAAOF,EAAIX,CAAG,CAAC,EAAE,OAAOU,EAAUG,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,CACxE,EAEA,MAAO,CAACD,EAAQE,EAAW,GAAGE,CAAI,EAAE,KAAK;AAAA,CAAI,CAC/C,CAKA,OAAO,kBAAkBC,EAAiBC,EAAeH,EAAQ,GAAY,CAC3E,IAAMI,EAAa,KAAK,IAAIF,EAAUC,EAAO,CAAC,EACxCE,EAAS,KAAK,MAAMD,EAAaJ,CAAK,EACtCM,EAAQN,EAAQK,EAEhBE,EAAM,SAAI,OAAOF,CAAM,EAAI,SAAI,OAAOC,CAAK,EAC3CE,EAAU,KAAK,MAAMJ,EAAa,GAAG,EAE3C,MAAO,IAAIG,CAAG,KAAKC,CAAO,MAAMN,CAAO,IAAIC,CAAK,GAClD,CAKA,OAAO,kBAAkBM,EAAiBC,EAAwB,CAChE,IAAMC,EAAaD,EAAK,IAAKE,GAC3BA,EAAI,SAAS,GAAG,EAAI,IAAIA,CAAG,IAAMA,CACnC,EACA,MAAO,GAAGH,CAAO,IAAIE,EAAW,KAAK,GAAG,CAAC,EAC3C,CAKA,OAAO,aAAaE,EAAcC,EAAmBC,EAAS,MAAe,CAC3E,OAAIF,EAAK,QAAUC,EAAkBD,EAC9BA,EAAK,UAAU,EAAGC,EAAYC,EAAO,MAAM,EAAIA,CACxD,CAKA,OAAO,WAAWC,EAAUC,EAAS,EAAW,CAC9C,GAAI,CACF,OAAO,KAAK,UAAUD,EAAK,KAAMC,CAAM,CACzC,MAAgB,CACd,OAAO,OAAOD,CAAG,CACnB,CACF,CAKA,OAAO,cACL9B,EACAgC,EAAW,SACXC,EAAY,SACJ,CACR,OAAOjC,EAAQgC,EAAWC,CAC5B,CACF,ICjMA,OAAS,gBAAAC,OAAoB,KAC7B,OAAS,UAAAC,OAAc,KACvB,OAAOC,MAAU,OACjB,OAAS,iBAAAC,OAAqB,MAP9B,IAmBaC,EAnBbC,GAAAC,EAAA,kBAQAC,KAKAC,KAMaJ,EAAN,MAAMK,CAAU,CAnBvB,MAmBuB,CAAAC,EAAA,kBAIrB,OAAO,YAAqB,CAE1B,IAAMC,EACJ,QAAQ,IAAIC,GAAiB,WAAW,GAAK,QAAQ,IAAI,EAC3D,OAAOV,EAAK,KAAKS,EAAW,IAAIE,GAAkB,IAAI,MAAM,CAC9D,CAKA,OAAO,WAAWC,EAA6B,CAC7C,IAAMC,EAAUD,GAAc,QAAQ,IAAI,EAC1C,OAAOZ,EAAK,KAAKa,EAASF,GAAkB,QAAQ,CACtD,CAKA,OAAO,cAAuB,CAC5B,OAAO,QAAQ,IAAID,GAAiB,WAAW,GAAK,QAAQ,IAAI,CAClE,CAKA,OAAO,YAAqB,CAC1B,IAAMD,EAAYF,EAAU,aAAa,EACzC,OAAOP,EAAK,KAAKS,EAAWK,GAAe,QAAQ,CACrD,CAKA,OAAO,iBAA4B,CAEjC,IAAMC,EAAad,GAAc,YAAY,GAAG,EAC1Ce,EAAYhB,EAAK,QAAQe,CAAU,EAEzC,MAAO,CAELf,EAAK,KAAKgB,EAAWF,GAAe,aAAa,EAEjDd,EAAK,KAAKgB,EAAW,KAAM,KAAM,KAAMF,GAAe,aAAa,EAEnEd,EAAK,KACHgB,EACA,KACA,KACA,KACA,KACAF,GAAe,aACjB,CACF,CACF,CAKA,OAAO,kBAAkC,CACvC,IAAMG,EAAgBV,EAAU,gBAAgB,EAEhD,QAAWW,KAAgBD,EACzB,GAAIE,EAAU,OAAOD,CAAY,EAC/B,OAAOA,EAIX,OAAO,IACT,CAKA,OAAO,gBAAgBE,EAAqC,CAC1D,IAAMF,EAAeX,EAAU,iBAAiB,EAChD,GAAI,CAACW,EACH,OAAO,KAGT,IAAMG,EAAerB,EAAK,KAAKkB,EAAcE,CAAY,EACzD,OAAOD,EAAU,OAAOE,CAAY,EAAIA,EAAe,IACzD,CAKA,OAAO,cAAuB,CAC5B,IAAMN,EAAad,GAAc,YAAY,GAAG,EAChD,OAAOD,EAAK,QAAQe,CAAU,CAChC,CAKA,OAAO,gBAAyB,CAC9B,IAAMC,EAAYT,EAAU,aAAa,EAEzC,OAAOP,EAAK,KAAKgB,EAAW,KAAM,KAAM,IAAI,CAC9C,CAKA,OAAO,YAAqB,CAC1B,IAAMM,EAAcf,EAAU,eAAe,EAC7C,OAAOP,EAAK,KAAKsB,EAAa,MAAM,CACtC,CAKA,OAAO,gBAAgBC,EAA0B,CAC/C,IAAMD,EAAcf,EAAU,eAAe,EAC7C,OAAOP,EAAK,SAASsB,EAAaC,CAAQ,CAC5C,CAKA,OAAO,kBAAkBC,EAA6C,CACpE,IAAMf,EAAYF,EAAU,aAAa,EAEzC,GAAIiB,EACF,OAAOxB,EAAK,KAAKS,EAAW,kBAAkBe,CAAM,EAAE,EAIxD,QAAWC,KAAYf,GAAiB,WAAY,CAClD,IAAMa,EAAWvB,EAAK,KAAKS,EAAWgB,CAAQ,EAC9C,GAAIN,EAAU,OAAOI,CAAQ,EAC3B,OAAOA,CAEX,CAGA,OAAOvB,EAAK,KAAKS,EAAWC,GAAiB,WAAW,CAAC,CAAC,CAC5D,CAKA,OAAO,sBAA+B,CACpC,IAAMY,EAAcf,EAAU,eAAe,EAC7C,OAAOP,EAAK,KAAKsB,EAAaZ,GAAiB,YAAY,CAC7D,CAKA,OAAO,aAAagB,EAA4B,CAE9C,MAAO,CADgB1B,EAAK,UAAU0B,CAAS,EACxB,SAAS,IAAI,CACtC,CAKA,OAAO,iBAAiBA,EAAmBb,EAAyB,CAClE,IAAMc,EAAe3B,EAAK,QAAQa,EAASa,CAAS,EAC9CE,EAAe5B,EAAK,QAAQa,CAAO,EAEzC,GAAI,CAACc,EAAa,WAAWC,CAAY,EACvC,MAAM,IAAI,MAAM,gBAAMF,CAAS,mDAAW,EAG5C,OAAOC,CACT,CAKA,OAAO,kBAAkBE,EAAsB,CAE7C,IAAMC,EAAU,QAAQ,KAAK,CAAC,EAG9B,GAAI,CAACA,EAEH,OAAO9B,EAAK,KAAK,QAAQ,IAAI,EAAG,GAAG6B,CAAI,KAAK,EAI9C,IAAIE,EACJ,GAAI,CACFA,EAAcjC,GAAagC,CAAO,CACpC,MAAgB,CAEdC,EAAcD,CAChB,CAGA,IAAME,EAAUhC,EAAK,QAAQ+B,CAAW,EACxC,OAAO/B,EAAK,KAAKgC,EAAS,GAAGH,CAAI,KAAK,CACxC,CAKA,OAAO,0BAAmC,CACxC,OAAOtB,EAAU,kBAAkB,mBAAmB,CACxD,CAKA,OAAO,kBAAkB0B,EAA4B,CACnD,IAAMC,EAAalC,EAAK,KAAK,GAAGiC,CAAQ,EAClCE,EAAiBnC,EAAK,UAAUkC,CAAU,EAGhD,GAAIC,EAAe,SAAS,IAAI,GAAKA,EAAe,SAAS,GAAG,EAC9D,MAAM,IAAI,MAAM,yCAAWA,CAAc,EAAE,EAG7C,OAAOA,CACT,CAKA,OAAO,YAAqB,CAE1B,OAAO,QAAQ,IAAI,QAAU,QAAQ,IAAI,MAAQpC,GAAO,CAC1D,CAKA,OAAO,YAAqB,CAC1B,OAAO,QAAQ,IAAI,MAAQ,QAAQ,IAAI,aAAe,EACxD,CACF,IC1PA,OAAS,YAAAqC,OAAgB,gBAJzB,IAYaC,GAZbC,GAAAC,EAAA,kBAKAC,KAEAC,KAKaJ,GAAN,MAAMK,CAAc,CAZ3B,MAY2B,CAAAC,EAAA,sBAIzB,OAAO,oBAA+B,CACpC,OAAO,QAAQ,QACjB,CAKA,OAAO,WAAqB,CAC1B,OAAO,QAAQ,WAAa,OAC9B,CAKA,OAAO,SAAmB,CACxB,OAAO,QAAQ,WAAa,QAC9B,CAKA,OAAO,SAAmB,CACxB,OAAO,QAAQ,WAAa,OAC9B,CAKA,OAAO,YAAsB,CAC3B,MAAO,CAACD,EAAc,UAAU,CAClC,CAKA,OAAO,iBAAiBE,EAAsB,CAC5C,GAAI,CAEF,GACE,QAAQ,IAAI,oBAAsB,QAClC,QAAQ,IAAI,WAAa,OAIzB,eAAQ,KAAKA,EAAK,CAAC,EACZ,GAIT,GAAI,CACF,IAAIC,EAAU,GACd,OAAIH,EAAc,UAAU,EAM1BG,EAJeT,GAAS,wBAAwBQ,CAAG,gBAAiB,CAClE,SAAU,OACV,QAASE,GAAkB,YAC7B,CAAC,EACgB,YAAY,EAO7BD,EAJeT,GAAS,SAASQ,CAAG,YAAa,CAC/C,SAAU,OACV,QAASE,GAAkB,YAC7B,CAAC,EACgB,YAAY,EAIxBD,EAAQ,SAAS,MAAM,GAAKA,EAAQ,SAAS,SAAS,CAC/D,MAAgB,CAEd,eAAQ,KAAKD,EAAK,CAAC,EACZ,EACT,CACF,MAAgB,CACd,MAAO,EACT,CACF,CAKA,aAAa,YACXA,EACAG,EAAyB,UACV,CACf,GAAI,CACF,QAAQ,KAAKH,EAAKG,CAAM,EAGxB,IAAIC,EAAW,EACTC,EAAc,GAEpB,KAAOD,EAAWC,GAAa,CAC7B,MAAM,IAAI,QAASC,GAAY,WAAWA,EAAS,GAAG,CAAC,EAEvD,GAAI,CACF,QAAQ,KAAKN,EAAK,CAAC,EACnBI,GACF,MAAQ,CAEN,MACF,CACF,CAGA,GAAI,CACF,QAAQ,KAAKJ,EAAK,CAAC,EACnB,QAAQ,KAAKA,EAAK,SAAS,EAC3B,MAAM,IAAI,QAASM,GAAY,WAAWA,EAAS,GAAG,CAAC,CACzD,MAAQ,CAER,CACF,OAASC,EAAO,CACd,MAAM,IAAIC,GACR,yCAAWD,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,GACjEP,CACF,CACF,CACF,CAKA,OAAO,cAAcA,EAAsB,CACzC,GAAI,CACF,eAAQ,KAAKA,EAAK,CAAC,EACZ,EACT,MAAQ,CACN,MAAO,EACT,CACF,CAKA,OAAO,eAKL,CACA,MAAO,CACL,SAAUF,EAAc,mBAAmB,EAC3C,KAAM,QAAQ,KACd,YAAa,QAAQ,QACrB,YAAa,QAAQ,IAAI,oBAAsB,MACjD,CACF,CAKA,OAAO,UAAUW,EAAcC,EAA2C,CACxE,OAAO,QAAQ,IAAID,CAAI,GAAKC,CAC9B,CAKA,OAAO,UAAUD,EAAcE,EAAqB,CAClD,QAAQ,IAAIF,CAAI,EAAIE,CACtB,CAKA,OAAO,wBAAkC,CACvC,OAAO,QAAQ,IAAI,oBAAsB,MAC3C,CAKA,OAAO,mBAA6B,CAClC,OAAO,QAAQ,IAAI,WAAa,MAClC,CAKA,OAAO,0BAAoC,CACzC,OAAO,QAAQ,IAAI,WAAa,aAClC,CAKA,OAAO,eAAeC,EAAuD,CAC3E,OAAId,EAAc,UAAU,EACnB,CACL,QAAS,aACT,KAAM,CAAC,WAAY,sBAAsBc,CAAQ,SAAS,CAC5D,EAEK,CACL,QAAS,OACT,KAAM,CAAC,KAAMA,CAAQ,CACvB,CACF,CACF,ICxNA,IAUaC,EAVbC,GAAAC,EAAA,kBAKAC,KAKaH,EAAN,MAAMI,CAAW,CAVxB,MAUwB,CAAAC,EAAA,mBAItB,OAAO,aAAaC,EAAoB,CACtC,GAAI,CAAC,OAAO,UAAUA,CAAI,GAAKA,EAAO,GAAKA,EAAO,MAChD,MAAMC,EAAgB,YAAYD,CAAI,CAE1C,CAKA,OAAO,qBAAqBE,EAA8B,CACxD,IAAMC,EAA+B,CAAC,OAAQ,QAAS,OAAO,EAE9D,GAAI,CAACA,EAAa,SAASD,CAAsB,EAC/C,MAAM,IAAID,EACR,2DAAcC,CAAM,yCAAWC,EAAa,KAAK,IAAI,CAAC,GACtD,QACF,EAGF,OAAOD,CACT,CAKA,OAAO,iBAAiBE,EAAYC,EAAyB,CAC3D,GAA2BD,GAAU,MAAQA,IAAU,GACrD,MAAMH,EAAgB,cAAcI,CAAS,CAEjD,CAKA,OAAO,qBACLD,EACAC,EACAC,EAA0C,CAAC,EACrC,CACN,GAAIA,EAAQ,MAAQ,QAAaF,EAAM,OAASE,EAAQ,IACtD,MAAM,IAAIL,EACR,wCAAUK,EAAQ,GAAG,sDAAcF,EAAM,MAAM,GAC/CC,CACF,EAGF,GAAIC,EAAQ,MAAQ,QAAaF,EAAM,OAASE,EAAQ,IACtD,MAAM,IAAIL,EACR,wCAAUK,EAAQ,GAAG,sDAAcF,EAAM,MAAM,GAC/CC,CACF,CAEJ,CAKA,OAAO,YAAYE,EAAaF,EAAY,MAAa,CACvD,GAAI,CACF,IAAI,IAAIE,CAAG,CACb,MAAQ,CACN,MAAM,IAAIN,EAAgB,wCAAeM,CAAG,GAAIF,CAAS,CAC3D,CACF,CAKA,OAAO,qBAAqBE,EAAaF,EAAY,gBAAuB,CAC1EP,EAAW,YAAYS,EAAKF,CAAS,EAErC,IAAMG,EAAY,IAAI,IAAID,CAAG,EAC7B,GAAI,CAAC,CAAC,MAAO,MAAM,EAAE,SAASC,EAAU,QAAQ,EAC9C,MAAM,IAAIP,EACR,0GAA8CO,EAAU,QAAQ,GAChEH,CACF,CAEJ,CAKA,OAAO,gBAAgBE,EAAaF,EAAY,WAAkB,CAChEP,EAAW,YAAYS,EAAKF,CAAS,EAErC,IAAMG,EAAY,IAAI,IAAID,CAAG,EAC7B,GAAI,CAAC,CAAC,QAAS,QAAQ,EAAE,SAASC,EAAU,QAAQ,EAClD,MAAM,IAAIP,EACR,yGAA6CO,EAAU,QAAQ,GAC/DH,CACF,CAEJ,CAKA,OAAO,oBAAoBI,EAAoB,CAC7CX,EAAW,iBAAiBW,EAAM,aAAa,EAC/CX,EAAW,qBAAqBW,EAAM,cAAe,CAAE,IAAK,EAAG,IAAK,GAAI,CAAC,EAGzE,IAAMC,EAAe,eACfC,EAAkBF,EACrB,MAAM,EAAE,EACR,KAAMG,GAASA,EAAK,WAAW,CAAC,EAAI,EAAE,EAEzC,GAAIF,EAAa,KAAKD,CAAI,GAAKE,EAC7B,MAAM,IAAIV,EACR,oIACA,aACF,EAIF,GAAIQ,EAAK,WAAW,GAAG,EACrB,MAAM,IAAIR,EAAgB,+DAAc,aAAa,CAEzD,CAKA,OAAO,qBAAqBQ,EAAoB,CAM9C,GALAX,EAAW,iBAAiBW,EAAM,cAAc,EAChDX,EAAW,qBAAqBW,EAAM,eAAgB,CAAE,IAAK,EAAG,IAAK,EAAG,CAAC,EAIrE,CADiB,mBACH,KAAKA,CAAI,EACzB,MAAM,IAAIR,EACR,iIACA,cACF,CAEJ,CAKA,OAAO,mBAAmBQ,EAAoB,CAK5C,GAJAX,EAAW,iBAAiBW,EAAM,YAAY,EAI1C,CADiB,qBACH,KAAKA,CAAI,EACzB,MAAM,IAAIR,EACR,uLACA,YACF,CAEJ,CAKA,OAAO,aAAaY,EAAoBR,EAAY,OAAa,CAC/D,GAAI,CACF,OAAO,KAAK,MAAMQ,CAAU,CAC9B,OAASC,EAAO,CACd,MAAM,IAAIb,EACR,yCAAgBa,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,GACtET,CACF,CACF,CACF,CAKA,OAAO,oBACLD,EACAC,EACAC,EAA0C,CAAC,EACrC,CACN,GAAIA,EAAQ,MAAQ,QAAaF,EAAQE,EAAQ,IAC/C,MAAM,IAAIL,EACR,kCAASK,EAAQ,GAAG,6BAASF,CAAK,GAClCC,CACF,EAGF,GAAIC,EAAQ,MAAQ,QAAaF,EAAQE,EAAQ,IAC/C,MAAM,IAAIL,EACR,kCAASK,EAAQ,GAAG,6BAASF,CAAK,GAClCC,CACF,CAEJ,CAKA,OAAO,oBACLU,EACAV,EACAC,EAA0C,CAAC,EACrC,CACN,GAAIA,EAAQ,MAAQ,QAAaS,EAAM,OAAST,EAAQ,IACtD,MAAM,IAAIL,EACR,oDAAYK,EAAQ,GAAG,mCAAUS,EAAM,MAAM,GAC7CV,CACF,EAGF,GAAIC,EAAQ,MAAQ,QAAaS,EAAM,OAAST,EAAQ,IACtD,MAAM,IAAIL,EACR,oDAAYK,EAAQ,GAAG,mCAAUS,EAAM,MAAM,GAC7CV,CACF,CAEJ,CAKA,OAAO,yBACLW,EACAC,EACAZ,EAAY,SACN,CACN,QAAWa,KAAQD,EACjB,GAAI,EAAEC,KAAQF,GACZ,MAAM,IAAIf,EAAgB,+CAAYiB,CAAI,GAAIb,CAAS,CAG7D,CAKA,OAAO,aACLD,EACAe,EACAd,EACG,CACH,GAAI,CAACc,EAAY,SAASf,CAAU,EAClC,MAAM,IAAIH,EACR,6BAASG,CAAK,6BAASe,EAAY,KAAK,IAAI,CAAC,GAC7Cd,CACF,EAEF,OAAOD,CACT,CAKA,OAAO,cAAcgB,EAAiBf,EAAY,QAAiB,CACjE,GAAI,CACF,OAAO,IAAI,OAAOe,CAAO,CAC3B,OAASN,EAAO,CACd,MAAM,IAAIb,EACR,qDAAaa,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,GACnET,CACF,CACF,CACF,CACF,IC7QA,OAAOgB,OAAQ,KACf,OAAOC,OAAU,OACjB,OAAS,iBAAAC,OAAqB,MAN9B,IAsBaC,GAtBbC,GAAAC,EAAA,kBAOAC,KAeaH,GAAN,MAAMI,CAAa,CAtB1B,MAsB0B,CAAAC,EAAA,qBACxB,OAAe,cAA+B,KAK9C,OAAO,YAAqB,CAC1B,GAAID,EAAa,cACf,OAAOA,EAAa,cAGtB,GAAI,CAEF,IAAME,EAAaP,GAAc,YAAY,GAAG,EAC1CQ,EAAaT,GAAK,QAAQQ,CAAU,EAGpCE,EAAgB,CAEpBV,GAAK,KAAKS,EAAY,cAAc,EAEpCT,GAAK,KAAKS,EAAY,KAAM,cAAc,EAE1CT,GAAK,KAAKS,EAAY,KAAM,KAAM,KAAM,cAAc,EAEtDT,GAAK,KAAKS,EAAY,KAAM,KAAM,KAAM,KAAM,cAAc,CAC9D,EAEA,QAAWE,KAAeD,EACxB,GAAIX,GAAG,WAAWY,CAAW,EAAG,CAC9B,IAAMC,EAAc,KAAK,MAAMb,GAAG,aAAaY,EAAa,MAAM,CAAC,EACnE,GAAIC,EAAY,QACd,OAAAN,EAAa,cAAgBM,EAAY,QAClCA,EAAY,OAEvB,CAIF,OAAAN,EAAa,cAAgB,UACtB,SACT,MAAgB,CAEd,OAAAA,EAAa,cAAgB,UACtB,SACT,CACF,CAKA,OAAO,gBAA8B,CACnC,GAAI,CACF,IAAME,EAAaP,GAAc,YAAY,GAAG,EAC1CQ,EAAaT,GAAK,QAAQQ,CAAU,EAEpCE,EAAgB,CAEpBV,GAAK,KAAKS,EAAY,cAAc,EAEpCT,GAAK,KAAKS,EAAY,KAAM,cAAc,EAE1CT,GAAK,KAAKS,EAAY,KAAM,KAAM,KAAM,cAAc,EAEtDT,GAAK,KAAKS,EAAY,KAAM,KAAM,KAAM,KAAM,cAAc,CAC9D,EAEA,QAAWE,KAAeD,EACxB,GAAIX,GAAG,WAAWY,CAAW,EAAG,CAC9B,IAAMC,EAAc,KAAK,MAAMb,GAAG,aAAaY,EAAa,MAAM,CAAC,EACnE,MAAO,CACL,QAASC,EAAY,SAAW,UAChC,KAAMA,EAAY,KAClB,YAAaA,EAAY,YACzB,OAAQA,EAAY,MACtB,CACF,CAGF,MAAO,CAAE,QAAS,SAAU,CAC9B,MAAgB,CACd,MAAM,IAAIC,EAAU,mDAAY,cAAc,CAChD,CACF,CAKA,OAAO,gBAAgBC,EAAkBC,EAA0B,CACjE,IAAMC,EAAUF,EAAS,MAAM,GAAG,EAAE,IAAI,MAAM,EACxCG,EAAUF,EAAS,MAAM,GAAG,EAAE,IAAI,MAAM,EACxCG,EAAY,KAAK,IAAIF,EAAQ,OAAQC,EAAQ,MAAM,EAEzD,QAAS,EAAI,EAAG,EAAIC,EAAW,IAAK,CAClC,IAAMC,EAASH,EAAQ,CAAC,GAAK,EACvBI,EAASH,EAAQ,CAAC,GAAK,EAE7B,GAAIE,EAASC,EAAQ,MAAO,GAC5B,GAAID,EAASC,EAAQ,MAAO,EAC9B,CAEA,MAAO,EACT,CAKA,OAAO,eAAeC,EAA0B,CAE9C,MADqB,oCACD,KAAKA,CAAO,CAClC,CAKA,OAAO,YAAmB,CACxBf,EAAa,cAAgB,IAC/B,CACF,IC5IA,IAAAgB,GAAA,GAAAC,GAAAD,GAAA,wBAAAE,KAAA,IAsBaA,GAtBbC,GAAAC,EAAA,kBAAAC,KAKAC,KACAC,KACAC,KACAC,KAcaP,GAAN,KAAoD,CAtB3D,MAsB2D,CAAAQ,EAAA,2BAIjD,gBAAyB,CAC/B,OAAOC,EAAU,WAAW,CAC9B,CAKQ,aAAkC,CACxC,GAAI,CACF,IAAMC,EAAc,KAAK,eAAe,EAExC,GAAI,CAACC,EAAU,OAAOD,CAAW,EAC/B,OAAO,KAGT,IAAME,EAAaD,EAAU,SAASD,CAAW,EAAE,KAAK,EAClD,CAACG,EAAQC,EAAcC,CAAI,EAAIH,EAAW,MAAM,GAAG,EAEnDI,EAAM,OAAO,SAASH,CAAM,EAC5BI,EAAY,OAAO,SAASH,CAAY,EAE9C,OAAI,OAAO,MAAME,CAAG,GAAK,OAAO,MAAMC,CAAS,GAE7C,KAAK,eAAe,EACb,MAGF,CACL,IAAAD,EACA,UAAAC,EACA,KAAOF,GAAoC,YAC7C,CACF,MAAgB,CAEd,YAAK,eAAe,EACb,IACT,CACF,CAKQ,aAAaC,EAAaD,EAAqC,CACrE,GAAI,CACF,IAAMG,EAAU,GAAGF,CAAG,IAAI,KAAK,IAAI,CAAC,IAAID,CAAI,GACtCL,EAAc,KAAK,eAAe,EACxCC,EAAU,UAAUD,EAAaQ,EAAS,CAAE,UAAW,EAAK,CAAC,CAC/D,MAAgB,CACd,MAAM,IAAIC,EAAU,4CAAe,KAAK,eAAe,CAAC,CAC1D,CACF,CAKA,iBAAiBH,EAAsB,CACrC,OAAOI,GAAc,iBAAiBJ,CAAG,CAC3C,CAKA,kBAAkC,CAChC,GAAI,CACF,IAAME,EAAU,KAAK,YAAY,EAEjC,GAAI,CAACA,EACH,MAAO,CAAE,QAAS,EAAM,EAI1B,GAAI,CAAC,KAAK,iBAAiBA,EAAQ,GAAG,EAEpC,YAAK,eAAe,EACb,CAAE,QAAS,EAAM,EAI1B,IAAMG,EAASC,GAAY,aAAa,KAAK,IAAI,EAAIJ,EAAQ,SAAS,EAEtE,MAAO,CACL,QAAS,GACT,IAAKA,EAAQ,IACb,OAAAG,EACA,KAAMH,EAAQ,IAChB,CACF,MAAgB,CACd,MAAO,CAAE,QAAS,EAAM,CAC1B,CACF,CAKA,YAAYF,EAAaD,EAAqC,CAC5D,KAAK,aAAaC,EAAKD,CAAI,CAC7B,CAKA,MAAM,YAAYC,EAA4B,CAC5C,GAAI,CACF,MAAMI,GAAc,YAAYJ,CAAG,CACrC,OAASO,EAAO,CACd,MAAM,IAAIC,GACR,yCAAWD,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,GACjEP,CACF,CACF,CACF,CAKA,MAAM,oBAAoBA,EAA4B,CACpD,GAAI,CAEF,QAAQ,KAAKA,EAAK,SAAS,EAG3B,IAAIS,EAAW,EACTC,EAAc,GAEpB,KAAOD,EAAWC,GAAa,CAC7B,MAAM,IAAI,QAASC,GAAY,WAAWA,EAAS,GAAG,CAAC,EAEvD,GAAI,CACF,QAAQ,KAAKX,EAAK,CAAC,EACnBS,GACF,MAAQ,CAEN,MACF,CACF,CAGA,GAAI,CACF,QAAQ,KAAKT,EAAK,CAAC,EACnB,QAAQ,KAAKA,EAAK,SAAS,EAC3B,MAAM,IAAI,QAASW,GAAY,WAAWA,EAAS,GAAG,CAAC,CACzD,MAAQ,CAER,CACF,OAASJ,EAAO,CACd,MAAM,IAAIC,GACR,yCAAWD,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,GACjEP,CACF,CACF,CACF,CAKA,gBAAuB,CACrB,GAAI,CACF,IAAMN,EAAc,KAAK,eAAe,EACpCC,EAAU,OAAOD,CAAW,GAC9BC,EAAU,WAAWD,CAAW,CAEpC,MAAgB,CAGhB,CACF,CAKA,cAAcM,EAAsB,CAClC,OAAOI,GAAc,cAAcJ,CAAG,CACxC,CAKA,uBAA8B,CAC5B,GAAII,GAAc,uBAAuB,EACvC,GAAI,CACF,KAAK,eAAe,CACtB,MAAgB,CAEhB,CAEJ,CAKA,eAAeJ,EAAsD,CACnE,IAAMY,EAAS,KAAK,cAAcZ,CAAG,EAC/Ba,EAAYD,EAAS,KAAK,iBAAiBZ,CAAG,EAAI,GAExD,MAAO,CAAE,OAAAY,EAAQ,UAAAC,CAAU,CAC7B,CAKA,iBAA2B,CACzB,GAAI,CAEF,OADgB,KAAK,YAAY,IACd,IACrB,MAAQ,CACN,MAAO,EACT,CACF,CACF,IC1OA,IAAAC,GAAA,GAAAC,GAAAD,GAAA,uBAAAE,KAKA,OAAS,SAAAC,OAAa,gBACtB,OAAOC,OAAQ,KANf,IAkCaF,GAlCbG,GAAAC,EAAA,kBAOAC,KAKAC,KACAC,KAqBaP,GAAN,KAAkD,CAGvD,YACUQ,EACAC,EACR,CAFQ,oBAAAD,EACA,YAAAC,CACP,CAxCL,MAkCyD,CAAAC,EAAA,0BAC/C,cAAqC,KAU7C,MAAM,YACJC,EACAC,EAAyB,CAAC,EACX,CACf,GAAI,CAEF,IAAMC,EAAS,KAAK,eAAe,iBAAiB,EACpD,GAAIA,EAAO,QACT,MAAMC,EAAa,eAAeD,EAAO,GAAI,EAI/C,IAAME,EAAQ,MAAM,KAAK,mBAAmBJ,EAAeC,CAAO,EAClE,KAAK,cAAgBG,EAGrB,KAAK,eAAe,YAAYA,EAAM,IAAM,QAAQ,EAGpD,MAAM,KAAK,aAAaA,EAAOH,EAAQ,aAAe,aAAa,EAGnE,KAAK,mBAAmBG,CAAK,EAG7BA,EAAM,MAAM,EAEZ,KAAK,OAAO,KAAK,oDAAiBA,EAAM,GAAG,GAAG,CAChD,OAASC,EAAO,CACd,MAAM,IAAIF,EACR,qDAAaE,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACrE,CACF,CACF,CAKA,MAAM,YAA4B,CAChC,GAAI,CACF,IAAMH,EAAS,KAAK,eAAe,iBAAiB,EAEpD,GAAI,CAACA,EAAO,QACV,MAAMC,EAAa,WAAW,EAIhC,MAAM,KAAK,eAAe,oBAAoBD,EAAO,GAAI,EAGzD,KAAK,eAAe,eAAe,EAGnC,KAAK,cAAgB,KAErB,KAAK,OAAO,KAAK,4CAAS,CAC5B,OAASG,EAAO,CACd,MAAM,IAAIF,EACR,qDAAaE,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACrE,CACF,CACF,CAKA,MAAM,cACJL,EACAC,EAAyB,CAAC,EACX,CACf,GAAI,CAEa,KAAK,eAAe,iBAAiB,EACzC,UACT,MAAM,KAAK,WAAW,EAEtB,MAAM,IAAI,QAASK,GAAY,WAAWA,EAAS,GAAI,CAAC,GAI1D,MAAM,KAAK,YAAYN,EAAeC,CAAO,CAC/C,OAASI,EAAO,CACd,MAAM,IAAIF,EACR,qDAAaE,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACrE,CACF,CACF,CAKA,iBAAuE,CACrE,OAAO,KAAK,eAAe,iBAAiB,CAC9C,CAKA,MAAM,aAAaE,EAAc,cAA8B,CAC7D,GAAI,CACF,IAAMC,EAAcC,EAAU,WAAW,EAEzC,GAAI,CAAClB,GAAG,WAAWiB,CAAW,EAC5B,MAAM,IAAIL,EAAa,4CAAS,EAIlC,GAAM,CAAE,QAAAO,EAAS,KAAAC,CAAK,EAAIC,GAAc,eAAeJ,CAAW,EAC5DK,EAAOvB,GAAMoB,EAASC,EAAM,CAAE,MAAO,SAAU,CAAC,EAGtD,QAAQ,GAAG,SAAU,IAAM,CAEzBE,EAAK,KAAK,EACV,QAAQ,KAAK,CAAC,CAChB,CAAC,EAEDA,EAAK,GAAG,OAAQ,IAAM,CACpB,QAAQ,KAAK,CAAC,CAChB,CAAC,EAEDA,EAAK,GAAG,QAAUR,GAAU,CAC1B,MAAM,IAAIF,EAAa,yCAAWE,EAAM,OAAO,EAAE,CACnD,CAAC,CACH,OAASA,EAAO,CACd,MAAM,IAAIF,EACR,yCAAWE,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACnE,CACF,CACF,CAKA,MAAc,mBACZL,EACAC,EACuB,CAKvB,IAAMU,EAAO,CAHMF,EAAU,yBAAyB,CAG9B,EACpBR,EAAQ,aACVU,EAAK,KAAK,gBAAgB,EAI5B,IAAMG,EAAM,CACV,GAAG,QAAQ,IACX,mBAAoBL,EAAU,aAAa,EAC3C,eAAgB,OAChB,GAAGR,EAAQ,GACb,EAGMG,EAAQd,GAAM,OAAQqB,EAAM,CAChC,SAAU,GACV,MAAO,CAAC,SAAU,OAAQ,MAAM,EAChC,IAAAG,EACA,IAAKb,EAAQ,KAAO,QAAQ,IAAI,CAClC,CAAC,EAED,GAAI,CAACG,EAAM,IACT,MAAM,IAAIW,GAAa,mDAAY,CAAC,EAGtC,OAAOX,CACT,CAKA,MAAc,aACZA,EACAG,EACe,CACf,GAAI,CACF,IAAMC,EAAcC,EAAU,WAAW,EAInCO,GADO,KAAM,QAAO,MAAW,GACjB,QAAQR,CAAW,EAClCjB,GAAG,WAAWyB,CAAM,GACvBzB,GAAG,UAAUyB,EAAQ,CAAE,UAAW,EAAK,CAAC,EAI1C,IAAMC,EAAY1B,GAAG,kBAAkBiB,EAAa,CAAE,MAAO,GAAI,CAAC,EAGlEJ,EAAM,QAAQ,KAAKa,CAAS,EAC5Bb,EAAM,QAAQ,KAAKa,CAAS,EAG5B,IAAMC,EAAY,IAAI,KAAK,EAAE,YAAY,EACzCD,EAAU,MAAM;AAAA,GAAMC,CAAS,gDAAkBd,EAAM,GAAG;AAAA,CAAK,CACjE,OAASC,EAAO,CACd,KAAK,OAAO,KACV,2DAAcA,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACtE,CACF,CACF,CAKQ,mBAAmBD,EAA2B,CAEpDA,EAAM,GAAG,OAAQ,CAACe,EAAMC,IAAW,CAC7BD,IAAS,GAAKA,IAAS,KACzB,KAAK,OAAO,MAAM,mEAAiBA,CAAI,mBAASC,CAAM,GAAG,EAEzD,KAAK,OAAO,KAAK,kDAAU,EAI7B,KAAK,eAAe,eAAe,EACnC,KAAK,cAAgB,IACvB,CAAC,EAGDhB,EAAM,GAAG,QAAUC,GAAU,CAC3B,KAAK,OAAO,MAAM,yCAAWA,EAAM,OAAO,EAAE,EAC5C,KAAK,eAAe,eAAe,EACnC,KAAK,cAAgB,IACvB,CAAC,EAGDD,EAAM,GAAG,aAAc,IAAM,CAC3B,KAAK,OAAO,KAAK,kDAAU,CAC7B,CAAC,CACH,CAKA,MAAM,aAAgC,CACpC,GAAI,CACF,IAAMF,EAAS,KAAK,gBAAgB,EAEpC,GAAI,CAACA,EAAO,SAAW,CAACA,EAAO,IAC7B,MAAO,GAIT,IAAMmB,EAAc,KAAK,eAAe,eAAenB,EAAO,GAAG,EACjE,OAAOmB,EAAY,QAAUA,EAAY,SAC3C,MAAQ,CACN,MAAO,EACT,CACF,CAKA,kBAAwC,CACtC,OAAO,KAAK,aACd,CAKA,SAAgB,CACd,GAAI,KAAK,cAAe,CACtB,GAAI,CACF,KAAK,cAAc,KAAK,SAAS,CACnC,OAAShB,EAAO,CACd,KAAK,OAAO,KACV,qDAAaA,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACrE,CACF,CACA,KAAK,cAAgB,IACvB,CACF,CACF,ICrLO,SAASiB,GAAsBC,EAKpC,CACA,OACE,OAAOA,GAAQ,UACfA,IAAQ,MACR,SAAUA,GACTA,EAA2B,OAAS,QAEzC,CAMO,SAASC,GAAqBC,EAKnC,CACA,OAAIH,GAAsBG,CAAM,EACvBA,EASF,CACL,KAAM,SACN,WAAY,CAAC,EACb,SAAU,CAAC,EACX,qBAAsB,EACxB,CACF,CAnLA,IA2BYC,GAkSCC,EA7TbC,GAAAC,EAAA,kBA2BYH,QACVA,EAAA,MAAQ,QACRA,EAAA,IAAM,MACNA,EAAA,gBAAkB,kBAHRA,QAAA,IAgHII,EAAAR,GAAA,yBAkBAQ,EAAAN,GAAA,wBAgKHG,EAAN,cAA4B,KAAM,CACvC,YACSI,EACPC,EACOC,EACP,CACA,MAAMD,CAAO,EAJN,UAAAD,EAEA,UAAAE,EAGP,KAAK,KAAO,eACd,CArUF,MA6TyC,CAAAH,EAAA,sBASzC,ICrTO,SAASI,GACdC,EACAC,EAGkB,CAClB,GAAI,CAEF,IAAMC,EADY,IAAI,IAAIF,CAAG,EACF,SAG3B,OAAIE,EAAS,SAAS,MAAM,QAGxBA,EAAS,SAAS,MAAM,qBAKxBD,GAAS,YAKN,kBACT,MAAgB,CACd,OAAIA,GAAS,YAMN,iBACT,CACF,CAQO,SAASE,GACdC,EACkB,CAElB,GAAIA,EAAO,KAET,OADyBC,GAAoB,mBAAmBD,CAAM,EAKxE,GAAIA,EAAO,QACT,MAAO,CACL,GAAGA,EACH,YACF,EAIF,GAAIA,EAAO,MAAQ,QAAaA,EAAO,MAAQ,KAAM,CACnD,IAAME,EAAeP,GAA0BK,EAAO,IAAK,CACzD,YAAaA,EAAO,IACtB,CAAC,EACD,MAAO,CACL,GAAGA,EACH,KAAME,CACR,CACF,CAEA,MAAM,IAAI,MACR,kCAASF,EAAO,IAAI,8IACtB,CACF,CAeO,SAASG,GACdC,EACAP,EACyB,CACzB,IAAMQ,EAAO,CACX,aAAc,GACd,kBAAmB,GACnB,oBAAqB,GACrB,GAAGR,CACL,EAGA,GAAI,CAACO,GAAU,OAAOA,GAAW,SAC/B,MAAM,IAAIE,SAER,wDACF,EAGF,IAAMC,EAAYH,EAGlB,GAAIC,EAAK,eACH,CAACE,EAAU,MAAQ,OAAOA,EAAU,MAAS,UAC/C,MAAM,IAAID,SAER,0EACF,EAKJ,GACED,EAAK,mBACLE,EAAU,YAAc,QACxBA,EAAU,YAAc,OAGtB,OAAOA,EAAU,WAAc,UAC/B,MAAM,QAAQA,EAAU,SAAS,GAEjC,MAAM,IAAID,SAER,wDACF,EAKJ,GACE,CAACD,EAAK,qBACNE,EAAU,YAAc,QACxBA,EAAU,YAAc,KACxB,CACA,IAAMC,EAAUD,EAAU,UAC1B,GAAI,OAAO,KAAKC,CAAO,EAAE,SAAW,EAClC,MAAM,IAAIF,SAER,kDACF,CAEJ,CAGA,GAAID,EAAK,gBAAiB,CACxB,IAAMI,EAAQJ,EAAK,gBAAgBE,CAAsC,EACzE,GAAIE,EACF,MAAM,IAAIH,SAAgDG,CAAK,CAEnE,CAEA,MAAO,CACL,KAAMF,EAAU,KAChB,UAAWA,EAAU,SACvB,CACF,CApLA,IAAAG,GAAAC,EAAA,kBAAAC,KACAC,KAgBgBC,EAAAnB,GAAA,6BA0CAmB,EAAAf,GAAA,gCA8CAe,EAAAX,GAAA,4BCpGhB,OAAS,cAAAY,GAAY,WAAAC,OAAe,OA4B7B,SAASC,GACdC,EACAC,EACkB,CAGlB,GAAI,CAEF,GAAI,CAACD,GAAe,OAAOA,GAAgB,SACzC,MAAM,IAAIE,EAAsB,0EAAc,EAGhD,GAAI,CAACD,GAAgB,OAAOA,GAAiB,SAC3C,MAAM,IAAIC,EAAsB,mDAAYF,CAAW,EAIzD,IAAMG,EAAmBC,GAAoB,mBAC3CH,CACF,EAGMI,EAAYC,GAAoBN,EAAaG,CAAgB,EAGnE,OAAAI,GAAkBF,CAAS,EAGpBA,CACT,OAASG,EAAO,CAEd,MAAMA,aAAiBN,EACnBM,EACA,IAAIN,EACF,yCAAWM,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,GACjER,CACF,CACN,CACF,CAKA,SAASM,GACPN,EACAC,EACkB,CAElB,GAAIQ,GAAcR,CAAY,EAC5B,OAAOS,GAAmBV,EAAaC,CAAY,EAIrD,GAAI,SAAUA,EACZ,OAAQA,EAAa,KAAM,CACzB,IAAK,MACH,OAAOU,GAAiBX,EAAaC,CAAY,EACnD,IAAK,kBACH,OAAOW,GAA4BZ,EAAaC,CAAY,EAC9D,QACE,MAAM,IAAIC,EACR,qDAAaD,EAAa,IAAI,GAC9BD,CACF,CACJ,CAIF,GAAI,QAASC,EAAc,CAEzB,GAAIA,EAAa,MAAQ,QAAaA,EAAa,MAAQ,KACzD,MAAM,IAAIC,EACR,sFACAF,CACF,EAMF,GAFqBa,GAA0BZ,EAAa,KAAO,EAAE,IAEhD,MAAsB,CAEzC,IAAMa,EAAY,CAAE,GAAGb,EAAc,KAAM,KAAe,EAC1D,OAAOU,GAAiBX,EAAac,CAAS,CAChD,CAEA,IAAMC,EAAa,CAAE,GAAGd,EAAc,KAAM,iBAA2B,EACvE,OAAOW,GAA4BZ,EAAae,CAAU,CAC5D,CAEA,MAAM,IAAIb,EAAsB,yDAAaF,CAAW,CAC1D,CAGA,SAASU,GACPV,EACAgB,EACkB,CAClB,GAAI,CAACA,EAAO,QACV,MAAM,IAAId,EACR,wEACAF,CACF,EAIF,IAAMiB,EAAa,QAAQ,IAAI,oBAAsB,QAAQ,IAAI,EAG3DC,GAAgBF,EAAO,MAAQ,CAAC,GAAG,IAAKG,GAExCC,GAAeD,CAAG,EACCrB,GAAQmB,EAAYE,CAAG,EAIvCA,CACR,EAED,MAAO,CACL,KAAMnB,EACN,aACA,QAASgB,EAAO,QAChB,KAAME,EACN,IAAKF,EAAO,IACZ,QAAS,GACX,CACF,CAKA,SAASL,GACPX,EACAgB,EACkB,CAClB,GAAIA,EAAO,MAAQ,QAAaA,EAAO,MAAQ,KAC7C,MAAM,IAAId,EAAsB,4DAAqBF,CAAW,EAIlE,IAAMqB,EACJL,EAAO,OAAS,YAEZH,GAA0BG,EAAO,KAAO,EAAE,EAC1CM,EAAeN,EAAO,IAAMO,GAAgBP,EAAO,GAAG,EAAI,GAE1DQ,EAA+B,CACnC,KAAMxB,EACN,KAAMqB,EACN,IAAKL,EAAO,IACZ,QAAS,IACT,QAASA,EAAO,OAClB,EAGA,OAAIM,IACFE,EAAW,eAAiB,IAUvBA,CACT,CAKA,SAASZ,GACPZ,EACAgB,EACkB,CAElB,GAAIA,EAAO,MAAQ,QAAaA,EAAO,MAAQ,KAC7C,MAAM,IAAId,EACR,wEACAF,CACF,EAGF,IAAMyB,EAAMT,EAAO,KAAO,GAE1B,MAAO,CACL,KAAMhB,EACN,uBACA,IAAAyB,EACA,QAAS,IACT,QAAST,EAAO,OAClB,CACF,CAoCA,SAASI,GAAeM,EAAuB,CAG7C,OAAI7B,GAAW6B,CAAI,EACV,GAML,GAAAA,EAAK,WAAW,IAAI,GAAKA,EAAK,WAAW,KAAK,GAK9C,yBAAyB,KAAKA,CAAI,EAKxC,CAKA,SAASjB,GACPO,EACgC,CAChC,MAAO,YAAaA,GAAU,OAAOA,EAAO,SAAY,QAC1D,CAKO,SAASO,GAAgBE,EAAsB,CACpD,OAAOA,EAAI,SAAS,gBAAgB,GAAKA,EAAI,SAAS,eAAe,CACvE,CAKA,SAASlB,GAAkBS,EAAgC,CACzD,GAAI,CAACA,EAAO,MAAQ,OAAOA,EAAO,MAAS,SACzC,MAAM,IAAId,EAAsB,0EAAmB,EAGrD,GAAIc,EAAO,MAAQ,CAAC,OAAO,OAAOW,EAAgB,EAAE,SAASX,EAAO,IAAI,EACtE,MAAM,IAAId,EAAsB,+CAAYc,EAAO,IAAI,EAAE,EAI3D,GAAI,CAACA,EAAO,KACV,MAAM,IAAId,EAAsB,0HAAsB,EAGxD,OAAQc,EAAO,KAAM,CACnB,YACE,GAAI,CAACA,EAAO,QACV,MAAM,IAAId,EAAsB,iEAAyB,EAE3D,MAEF,UAEE,GAAIc,EAAO,MAAQ,QAAaA,EAAO,MAAQ,KAC7C,MAAM,IAAId,EAAsB,2DAAmB,EAErD,MAEF,sBAGE,GAAIc,EAAO,MAAQ,QAAaA,EAAO,MAAQ,KAC7C,MAAM,IAAId,EACR,uEACF,EAEF,MAEF,QACE,MAAM,IAAIA,EAAsB,qDAAac,EAAO,IAAI,EAAE,CAC9D,CACF,CAzVA,IAoBad,EApBb0B,GAAAC,EAAA,kBAaAC,KACAC,KACAC,KAKa9B,EAAN,cAAoC,KAAM,CAC/C,YACE+B,EACgBC,EAChB,CACA,MAAMD,CAAO,EAFG,gBAAAC,EAGhB,KAAK,KAAO,uBACd,CA3BF,MAoBiD,CAAAC,EAAA,8BAQjD,EAKgBA,EAAApC,GAAA,sBA2CPoC,EAAA7B,GAAA,uBAmDA6B,EAAAzB,GAAA,sBAsCAyB,EAAAxB,GAAA,oBAyCAwB,EAAAvB,GAAA,+BAyDAuB,EAAAf,GAAA,kBAyBAe,EAAA1B,GAAA,iBASO0B,EAAAZ,GAAA,mBAOPY,EAAA5B,GAAA,uBCvRT,OAAO6B,OAAe,KAzBtB,IAqDaC,GArDbC,GAAAC,EAAA,kBAgBAC,KAKAC,KAGAC,KAEAF,KA2BaH,GAAN,KAAyB,CArDhC,MAqDgC,CAAAM,EAAA,2BACtB,YACA,GAAuB,KACvB,iBAAmB,GACnB,kBAAoB,GACpB,eAA4C,KAG5C,gBAAmC,eAGnC,UAA2B,KAG3B,kBAA2C,KAG3C,gBAAkB,IAClB,eAAiB,IAEzB,YAAYC,EAAqBC,EAAyB,CACxD,KAAK,YAAcD,EACfC,IAAmB,SACrB,KAAK,eAAiBA,EAE1B,CAMA,kBAAkBC,EAA0C,CAC1D,KAAK,eAAiBA,CACxB,CAMA,UAAmB,CACjB,GAAI,CAAC,KAAK,eAER,MAAO,CAAC,EAGV,GAAI,CAKF,OAHiB,KAAK,eAAe,YAAY,EAGjC,IAAKC,IAAc,CACjC,KAAMA,EAAS,KACf,YAAaA,EAAS,YACtB,YAAaC,GAAqBD,EAAS,WAAW,CACxD,EAAE,CACJ,MAAgB,CAMd,MAAO,CAAC,CACV,CACF,CAMA,MAAa,SAAyB,CAEpC,GAAI,CAAC,KAAK,eACR,MAAM,IAAI,MAAM,gIAAsC,EAIxD,GAAI,KAAK,kBAAoB,aAC3B,MAAM,IAAI,MAAM,4FAAiB,EAInC,YAAK,kBAAkB,EAEhB,KAAK,kBAAkB,CAChC,CAMA,MAAc,mBAAmC,CAC/C,YAAK,gBAAkB,aAGhB,IAAI,QAAQ,CAACE,EAASC,IAAW,CAEtC,KAAK,kBAAoB,WAAW,IAAM,CACxC,IAAMC,EAAQ,IAAI,MAAM,oCAAgB,EACxC,KAAK,sBAAsBA,CAAK,EAChCD,EAAOC,CAAK,CACd,EAAG,GAAK,EAER,KAAK,GAAK,IAAIf,GAAU,KAAK,WAAW,EAExC,KAAK,GAAG,GAAG,OAAQ,IAAM,CACvB,KAAK,wBAAwB,EAC7Ba,EAAQ,CACV,CAAC,EAED,KAAK,GAAG,GAAG,UAAYG,GAAS,CAC9B,GAAI,CACF,IAAMC,EAAsB,KAAK,MAAMD,EAAK,SAAS,CAAC,EACtD,KAAK,cAAcC,CAAO,CAC5B,MAAgB,CAEhB,CACF,CAAC,EAED,KAAK,GAAG,GAAG,QAAS,CAACC,EAAMC,IAAW,CACpC,KAAK,sBAAsBD,EAAMC,EAAO,SAAS,CAAC,CACpD,CAAC,EAED,KAAK,GAAG,GAAG,QAAUJ,GAAU,CAC7B,KAAK,sBAAsBA,CAAK,EAChCD,EAAOC,CAAK,CACd,CAAC,CACH,CAAC,CACH,CAKQ,yBAAgC,CAElC,KAAK,oBACP,aAAa,KAAK,iBAAiB,EACnC,KAAK,kBAAoB,MAG3B,KAAK,iBAAmB,GACxB,KAAK,gBAAkB,WAGzB,CAKQ,sBAAsBA,EAAoB,CAEhD,KAAK,UAAYA,EAAM,QAGnB,KAAK,oBACP,aAAa,KAAK,iBAAiB,EACnC,KAAK,kBAAoB,MAM3B,KAAK,kBAAkB,CACzB,CAKQ,sBAAsBG,EAAcC,EAAsB,CAChE,KAAK,iBAAmB,GACxB,KAAK,kBAAoB,GACzB,KAAK,gBAAkB,cAEzB,CAKQ,mBAA0B,CAEhC,GAAI,KAAK,GAAI,CAEX,KAAK,GAAG,mBAAmB,EAG3B,GAAI,CACE,KAAK,GAAG,aAAenB,GAAU,KACnC,KAAK,GAAG,MAAM,IAAM,wBAAwB,EACnC,KAAK,GAAG,aAAeA,GAAU,YAC1C,KAAK,GAAG,UAAU,CAEtB,MAAgB,CAGhB,CAEA,KAAK,GAAK,IACZ,CAGI,KAAK,oBACP,aAAa,KAAK,iBAAiB,EACnC,KAAK,kBAAoB,MAI3B,KAAK,iBAAmB,GACxB,KAAK,kBAAoB,GAGzB,KAAK,gBAAkB,cACzB,CAEQ,cAAciB,EAA2B,CAI/C,GAAKA,EAAQ,OAMb,OAAQA,EAAQ,OAAQ,CACtB,IAAK,aACL,IAAK,4BACH,KAAK,aAAaA,EAAQ,GAAI,CAC5B,gBAAiB,aACjB,aAAc,CACZ,MAAO,CAAE,YAAa,EAAK,EAC3B,QAAS,CAAC,CACZ,EACA,WAAY,CACV,KAAM,qBACN,QAAS,OACX,CACF,CAAC,EACD,KAAK,kBAAoB,GAEzB,MAEF,IAAK,aAAc,CACjB,IAAMG,EAAY,KAAK,SAAS,EAChC,KAAK,aAAaH,EAAQ,GAAI,CAAE,MAAOG,CAAU,CAAC,EAElD,KACF,CAEA,IAAK,aAAc,CAEjB,KAAK,eAAeH,CAAO,EAAE,MAAOF,GAAU,CAE9C,CAAC,EACD,KACF,CAEA,IAAK,OACH,KAAK,aAAaE,EAAQ,GAAI,CAAC,CAAC,EAEhC,MAEF,QAEF,CACF,CAEQ,aAAaI,EAAqBC,EAAuB,CAK/D,GAAI,KAAK,kBAAoB,KAAK,IAAI,aAAetB,GAAU,KAAM,CACnE,IAAMuB,EAA+B,CACnC,QAAS,MACT,GAAAF,EACA,OAAAC,CACF,EAEA,GAAI,CACF,KAAK,GAAG,KAAK,KAAK,UAAUC,CAAQ,CAAC,CAKvC,MAAgB,CAKhB,CACF,CAiBF,CAMO,WAAsC,CAE3C,IAAMC,EAAiB,KAAK,eACxB,KAAK,eAAe,YAAY,EAAE,OAClC,EAEJ,MAAO,CACL,UAAW,KAAK,iBAChB,YAAa,KAAK,kBAClB,IAAK,KAAK,YACV,eAAAA,EACA,gBAAiB,KAAK,gBACtB,UAAW,KAAK,SAClB,CACF,CAMO,aAAuB,CAC5B,OAAO,KAAK,gBACd,CAKO,YAAmB,CAIxB,KAAK,kBAAkB,CACzB,CAMA,MAAa,WAA2B,CAItC,GAAI,CAAC,KAAK,eACR,MAAM,IAAI,MAAM,gIAAsC,EAIxD,KAAK,WAAW,EAGhB,MAAM,IAAI,QAASX,GAAY,WAAWA,EAAS,KAAK,cAAc,CAAC,EAGvE,MAAM,KAAK,QAAQ,CACrB,CAKA,MAAc,eAAeY,EAAoC,CAE/D,GAAIA,EAAQ,KAAO,QAAaA,EAAQ,KAAO,KAC7C,MAAM,IAAIC,SAER,0CACF,EAIF,IAAMC,EAAYF,EAAQ,GAEpBG,EAAY,KAAK,IAAI,EAE3B,GAAI,CAEF,IAAMC,EAASC,GAAuBL,EAAQ,MAAM,EASpD,GAAI,CAAC,KAAK,eACR,MAAM,IAAIC,SAER,sCACF,EAIF,IAAMJ,EAAS,MAAM,KAAK,uBACxBO,EAAO,KACPA,EAAO,WAAa,CAAC,EACrB,KAAK,eACP,EAGA,KAAK,aAAaF,EAAW,CAC3B,QAASL,EAAO,SAAW,CACzB,CAAE,KAAM,OAAQ,KAAM,KAAK,UAAUA,CAAM,CAAE,CAC/C,EACA,QAASA,EAAO,SAAW,EAC7B,CAAC,CAQH,OAASP,EAAO,CAEd,KAAK,oBAAoBA,EAAOY,EAAW,KAAK,IAAI,EAAIC,CAAS,CACnE,CACF,CAKA,MAAc,uBACZG,EACAC,EACAC,EAAY,IACa,CACzB,OAAO,IAAI,QAAQ,CAACpB,EAASC,IAAW,CAEtC,IAAMoB,EAAY,WAAW,IAAM,CACjCpB,EACE,IAAIY,SAEF,yCAAWO,CAAS,QAAQF,CAAQ,EACtC,CACF,CACF,EAAGE,CAAS,EAGZ,GAAI,CAAC,KAAK,eAAgB,CACxB,aAAaC,CAAS,EACtBpB,EACE,IAAIY,SAEF,sCACF,CACF,EACA,MACF,CAGA,KAAK,eACF,SAASK,EAAUC,CAAU,EAC7B,KAAMV,GAA2B,CAChC,aAAaY,CAAS,EACtBrB,EAAQS,CAAM,CAChB,CAAC,EACA,MAAOP,GAAmB,CACzB,aAAamB,CAAS,EAGtB,IAAMC,EACJpB,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,EAEnDoB,EAAa,SAAS,gCAAO,EAC/BrB,EACE,IAAIY,SAEF,mCAAUK,CAAQ,EACpB,CACF,EAEAI,EAAa,SAAS,cAAI,GAC1BA,EAAa,SAAS,oBAAK,EAE3BrB,EACE,IAAIY,SAEFS,CACF,CACF,EACSA,EAAa,SAAS,gCAAO,EAEtCrB,EACE,IAAIY,SAEFS,CACF,CACF,EACSA,EAAa,SAAS,gCAAO,EAEtCrB,EACE,IAAIY,SAEFS,CACF,CACF,EAEArB,EACE,IAAIY,QAEF,yCAAWS,CAAY,EACzB,CACF,CAEJ,CAAC,CACL,CAAC,CACH,CAKQ,oBACNpB,EACAY,EACAS,EACM,CACN,IAAIC,EAMJ,GAAItB,aAAiBW,EAEnBW,EAAgB,CACd,KAAMtB,EAAM,KACZ,QAASA,EAAM,QACf,KAAMA,EAAM,IACd,MACK,CAEL,IAAMoB,EAAepB,aAAiB,MAAQA,EAAM,QAAU,2BAC9DsB,EAAgB,CACd,WACA,QAASF,EACT,KAAM,CAAE,cAAe,OAAOpB,CAAK,GAAK,MAAO,CACjD,CACF,CAGA,KAAK,kBAAkBY,EAAWU,CAAa,CAQjD,CAKQ,kBACNhB,EACAN,EACM,CACN,GAAI,KAAK,kBAAoB,KAAK,IAAI,aAAef,GAAU,KAAM,CACnE,IAAMuB,EAAW,CACf,QAAS,MACT,GAAAF,EACA,MAAAN,CACF,EACA,KAAK,GAAG,KAAK,KAAK,UAAUQ,CAAQ,CAAC,CAEvC,CACF,CACF,ICxnBA,OAAS,gBAAAe,OAAoB,SAQ7B,OAAS,KAAAC,OAAS,MARlB,IAwEMC,GAMAC,GAiBOC,GA/FbC,GAAAC,EAAA,kBAEAC,KAIAC,IACAC,KAEAC,KA+DMR,GAA0D,CAC9D,kBAAmB,IACnB,eAAgB,GAClB,EAGMC,GAAqCF,GACxC,OAAO,CACN,kBAAmBA,GAChB,OAAO,EACP,IAAI,IAAM,sFAAoC,EAC9C,SAAS,EACZ,eAAgBA,GACb,OAAO,EACP,IAAI,IAAK,kFAAgC,EACzC,SAAS,CACd,CAAC,EACA,OAAO,EAMGG,GAAN,cAA8BJ,EAAa,CA/FlD,MA+FkD,CAAAW,EAAA,wBAExC,YAA+C,IAAI,IACnD,iBAAkD,IAAI,IAGtD,kBAA+C,KAC/C,cACA,SAGA,cAAgB,GAChB,aAAe,GAGf,QAER,YACEC,EACAC,EACA,CACA,MAAM,EACN,KAAK,cAAgBD,EACrB,KAAK,SAAWE,EAAY,EAC5B,KAAK,QAAU,CAAE,GAAGZ,GAAiB,GAAGW,CAAQ,CAIlD,CAOA,MAAM,WAAWE,EAAqBC,EAA8B,CAClE,GAAI,MAAK,cAMT,GAAI,CAEF,KAAK,yBAAyBD,EAAWC,CAAK,EAG9C,MAAM,KAAK,QAAQ,EAGnB,QAAWC,KAAYF,EACrB,MAAM,KAAK,iBAAiBE,EAAUD,CAAK,EAG7C,KAAK,cAAgB,EAKvB,OAASE,EAAO,CAEd,YAAM,KAAK,QAAQ,EACbA,CACR,CACF,CAKA,MAAM,SAAyB,CAC7B,GAAI,CAAC,KAAK,cACR,MAAM,IAAI,MAAM,qFAAwC,EAG1D,GAAI,MAAK,aAET,MAAK,aAAe,GAGpB,GAAI,CACF,IAAMC,EAAsC,CAAC,EAG7C,OAAW,CAACF,EAAUG,CAAkB,IAAK,KAAK,YAChDD,EAAmB,KACjB,KAAK,sBAAsBF,EAAUG,CAAkB,CACzD,EAYF,IARgB,MAAM,QAAQ,WAAWD,CAAkB,GAG9B,OAC1BE,GAAWA,EAAO,SAAW,WAChC,EAAE,SAGmB,EACnB,MAAM,IAAI,MAAM,oEAAa,CAEjC,QAAE,CACA,KAAK,aAAe,EACtB,EACF,CAKA,MAAM,YAA4B,CAIhC,IAAMC,EAAsC,CAAC,EAC7C,OAAW,CAACL,EAAUG,CAAkB,IAAK,KAAK,YAChDE,EAAmB,KACjB,KAAK,yBAAyBL,EAAUG,CAAkB,CAC5D,EAGF,MAAM,QAAQ,WAAWE,CAAkB,CAE7C,CAMA,MAAM,YAAYL,EAAiC,CACjD,GAAI,CAAC,KAAK,cACR,MAAM,IAAI,MAAM,0CAAsB,EAIxC,GAAI,MAAK,YAAY,IAAIA,CAAQ,EAQjC,IAAI,KAAK,qBAAqBA,CAAQ,EACpC,MAAM,IAAI,MAAM,sBAAOM,GAAcN,CAAQ,CAAC,yDAAY,EAK5D,GAAI,CAEF,KAAK,cAAc,eAAeA,CAAQ,EAE1C,GAAI,CAEF,IAAMD,EAAQ,KAAK,gBAAgB,EAGnC,MAAM,KAAK,iBAAiBC,EAAUD,CAAK,EAG3C,IAAMI,EAAqB,KAAK,YAAY,IAAIH,CAAQ,EACxD,GAAI,CAACG,EACH,MAAM,IAAI,MAAM,2DAAcH,CAAQ,EAAE,EAE1C,MAAM,KAAK,sBAAsBA,EAAUG,CAAkB,CAG/D,OAASF,EAAO,CAEd,GAAI,CACF,KAAK,cAAc,kBAAkBD,CAAQ,CAE/C,MAAwB,CAKxB,CAGA,WAAK,YAAY,OAAOA,CAAQ,EAChC,KAAK,iBAAiB,OAAOA,CAAQ,EAG/BC,CACR,CACF,OAASA,EAAO,CAKd,MAAMA,CACR,EACF,CAMA,MAAM,eAAeD,EAAiC,CACpD,GAAK,KAAK,YAAY,IAAIA,CAAQ,EASlC,GAAI,CACF,IAAMG,EAAqB,KAAK,YAAY,IAAIH,CAAQ,EACxD,GAAI,CAACG,EACH,MAAM,IAAI,MAAM,2DAAcH,CAAQ,EAAE,EAI1C,KAAK,cAAc,kBAAkBA,CAAQ,EAE7C,GAAI,CAEF,MAAM,KAAK,yBAAyBA,EAAUG,CAAkB,EAGhE,KAAK,YAAY,OAAOH,CAAQ,EAChC,KAAK,iBAAiB,OAAOA,CAAQ,CAGvC,OAASC,EAAO,CAEd,GAAI,CACF,KAAK,cAAc,eAAeD,CAAQ,CAE5C,MAAwB,CAKxB,CAGA,MAAMC,CACR,CACF,OAASA,EAAO,CAKd,MAAMA,CACR,CACF,CAKA,cAAyB,CAEvB,IAAMM,EAAsB,MAAM,KAAK,KAAK,YAAY,KAAK,CAAC,EACxDC,EAAiB,MAAM,KAAK,KAAK,iBAAiB,KAAK,CAAC,EAC9D,OAAO,MAAM,KAAK,IAAI,IAAI,CAAC,GAAGD,EAAqB,GAAGC,CAAc,CAAC,CAAC,CACxE,CAMA,MAAM,mBAAmBR,EAAiC,CACxD,IAAMG,EAAqB,KAAK,YAAY,IAAIH,CAAQ,EACxD,GAAKG,EAOL,GAAI,CACF,MAAM,KAAK,yBAAyBH,EAAUG,CAAkB,CAClE,OAASF,EAAO,CAEd,MAAMA,CACR,CACF,CAKA,MAAM,gBAAgC,CAIpC,IAAMI,EAAqB,MAAM,KAAK,KAAK,YAAY,KAAK,CAAC,EAAE,IAC5DL,GAAa,KAAK,eAAeA,CAAQ,CAC5C,EACA,MAAM,QAAQ,WAAWK,CAAkB,CAG7C,CAKA,qBAA0C,CACxC,OAAO,MAAM,KAAK,KAAK,iBAAiB,OAAO,CAAC,CAClD,CAKA,gBAA0B,CACxB,QAAWI,KAAU,KAAK,iBAAiB,OAAO,EAChD,GAAIA,EAAO,UACT,MAAO,GAGX,MAAO,EACT,CAOA,oBAAoBT,EAA2B,CAE7C,OADe,KAAK,iBAAiB,IAAIA,CAAQ,GAClC,WAAa,EAC9B,CAOA,kBAAkBA,EAAsD,CACtE,OAAO,KAAK,iBAAiB,IAAIA,CAAQ,CAC3C,CAMA,kBAAkBU,EAAmC,CACnD,KAAK,kBAAoBA,CAE3B,CAKQ,0BACNV,EACAW,EACAC,EACAC,EACAC,EACAC,EAAS,qBACH,CACN,KAAK,SAAS,UAAU,0BAA2B,CACjD,SAAAf,EACA,UAAAW,EACA,UAAAC,EACA,QAAAC,EACA,QAAAC,EACA,UAAW,KAAK,IAAI,EACpB,OAAAC,CACF,CAAC,CACH,CAOA,MAAM,wBAAwBf,EAAiC,CAC7D,GAAI,CAAC,KAAK,cACR,MAAM,IAAI,MAAM,0CAAsB,EAGxC,IAAMG,EAAqB,KAAK,YAAY,IAAIH,CAAQ,EACxD,GAAI,CAACG,EACH,MAAM,IAAI,MACR,sBAAOG,GAAcN,CAAQ,CAAC,qEAChC,EAGmB,KAAK,iBAAiB,IAAIA,CAAQ,GACrC,WAMlB,MAAM,KAAK,sBAAsBA,EAAUG,CAAkB,CAC/D,CAMA,MAAM,cAQH,CACD,GAAI,CAAC,KAAK,cACR,MAAM,IAAI,MAAM,qFAAwC,EAK1D,IAAMa,EAAqC,CAAC,EACtCC,EAID,CAAC,EAGN,OAAW,CAACjB,EAAUG,CAAkB,IAAK,KAAK,YAAa,CAC7D,IAAMe,EAAU,KAAK,wBAAwBlB,EAAUG,CAAkB,EACtE,KAAK,IAAM,CACVc,EAAQ,KAAK,CAAE,SAAAjB,EAAU,QAAS,EAAK,CAAC,CAC1C,CAAC,EACA,MAAOC,GAAU,CAChBgB,EAAQ,KAAK,CACX,SAAAjB,EACA,QAAS,GACT,MAAOC,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAC9D,CAAC,CACH,CAAC,EAEHe,EAAkB,KAAKE,CAAO,CAChC,CAGA,MAAM,QAAQ,WAAWF,CAAiB,EAG1C,IAAMG,EAAeF,EAAQ,OAAQG,GAAMA,EAAE,OAAO,EAAE,OAChDC,EAAeJ,EAAQ,OAAQG,GAAM,CAACA,EAAE,OAAO,EAAE,OAKvD,GAAIC,EAAe,EAAG,CACpB,IAAMC,EAAWL,EAAQ,OAAQG,GAAM,CAACA,EAAE,OAAO,EAEjD,QAAWG,KAAKD,EAAU,CAG5B,CAEA,MAAO,CACL,aAAAH,EACA,aAAAE,EACA,QAAAJ,CACF,CACF,CAMA,MAAM,kBAAkBjB,EAAiC,CACvD,GAAI,CAAC,KAAK,cACR,MAAM,IAAI,MAAM,0CAAsB,EAGxC,IAAMG,EAAqB,KAAK,YAAY,IAAIH,CAAQ,EACxD,GAAI,CAACG,EACH,MAAM,IAAI,MACR,sBAAOG,GAAcN,CAAQ,CAAC,qEAChC,EAIF,MAAM,KAAK,wBAAwBA,EAAUG,CAAkB,CACjE,CAMA,MAAc,MAAMqB,EAA2B,CAC7C,OAAO,IAAI,QAASC,GAAY,WAAWA,EAASD,CAAE,CAAC,CACzD,CAKQ,kBAAkB1B,EAGxB,CACA,IAAM4B,EAAkB,CAAC,EACnBC,EAAoB,CAAC,EAE3B,QAAW3B,KAAYF,EAAW,CAChC,GAAI,CAACE,GAAY,OAAOA,GAAa,SAAU,CAC7C2B,EAAQ,KAAK3B,CAAQ,EACrB,QACF,CAEA,GAAI,CAACA,EAAS,WAAW,OAAO,GAAK,CAACA,EAAS,WAAW,QAAQ,EAAG,CACnE2B,EAAQ,KAAK3B,CAAQ,EACrB,QACF,CAGA,GAAI,CACF,IAAI,IAAIA,CAAQ,EAChB0B,EAAM,KAAK1B,CAAQ,CACrB,MAAQ,CACN2B,EAAQ,KAAK3B,CAAQ,CACvB,CACF,CAEA,MAAO,CAAE,MAAA0B,EAAO,QAAAC,CAAQ,CAC1B,CAKQ,gBAAgB/B,EAGtB,CACA,IAAMQ,EAASlB,GAAmC,UAAUU,CAAO,EAEnE,OAAIQ,EAAO,QACF,CAAE,MAAO,GAAM,OAAQ,CAAC,CAAE,EAI5B,CAAE,MAAO,GAAO,OADRA,EAAO,MAAM,OAAO,IAAKwB,GAAQA,EAAI,OAAO,CAC7B,CAChC,CAOA,MAAM,gBACJC,EACA9B,EAAgB,CAAC,EACF,CACf,GAAI,CAAC,KAAK,cACR,MAAM,IAAI,MAAM,0CAAsB,EAQxC,GAAM,CAAE,MAAO+B,EAAgB,QAASC,CAAiB,EACvD,KAAK,kBAAkBF,CAAY,EAMrC,GAJIE,EAAiB,OAAS,EAI1BD,EAAe,SAAW,EAC5B,MAAM,IAAI,MAAM,8DAAY,EAI9B,IAAME,EAAmB,MAAM,KAAK,KAAK,YAAY,KAAK,CAAC,EACrDC,EAAQH,EAAe,OAAQI,GAAO,CAACF,EAAiB,SAASE,CAAE,CAAC,EACpEC,EAAWH,EAAiB,OAC/BE,GAAO,CAACJ,EAAe,SAASI,CAAE,CACrC,EACME,EAASJ,EAAiB,OAAQE,GAAOJ,EAAe,SAASI,CAAE,CAAC,EAM1E,GAAI,CAEF,QAAWlC,KAAYmC,EACrB,MAAM,KAAK,eAAenC,CAAQ,EAIpC,QAAWA,KAAYiC,EACrB,MAAM,KAAK,YAAYjC,CAAQ,EAIjC,IAAMqC,EAAiC,CACrC,KACEJ,EAAM,OAAS,GAAKE,EAAS,OAAS,EAClC,oBACAF,EAAM,OAAS,EACb,kBACA,oBACR,KAAM,CACJ,MAAOA,EAAM,OAAS,EAAIA,EAAQ,OAClC,QAASE,EAAS,OAAS,EAAIA,EAAW,OAC1C,QACEF,EAAM,OAAS,GAAKE,EAAS,OAAS,EAClCL,EACA,MACR,EACA,UAAW,IAAI,IACjB,EAEA,KAAK,KAAK,eAAgBO,CAAW,CAEvC,OAASpC,EAAO,CAEd,MAAMA,CACR,CACF,CAMA,cAAcqC,EAAyD,CAIrE,GAAM,CAAE,MAAAZ,EAAO,OAAAa,CAAO,EAAI,KAAK,gBAAgBD,CAAU,EAEzD,GAAI,CAACZ,EACH,MAAM,IAAI,MAAM,+CAAYa,EAAO,KAAK,IAAI,CAAC,EAAE,EAGjD,IAAMC,EAAa,CAAE,GAAG,KAAK,OAAQ,EAGrC,KAAK,QAAU,CAAE,GAAG,KAAK,QAAS,GAAGF,CAAW,EAGhD,IAAMD,EAAiC,CACrC,KAAM,kBACN,KAAM,CACJ,WAAAG,EACA,WAAAF,CACF,EACA,UAAW,IAAI,IACjB,EAEA,KAAK,KAAK,eAAgBD,CAAW,CAGvC,CAKA,kBAGE,CACA,MAAO,CACL,UAAW,MAAM,KAAK,KAAK,YAAY,KAAK,CAAC,EAC7C,QAAS,CAAE,GAAG,KAAK,OAAQ,CAC7B,CACF,CAMA,MAAM,aAAaI,EAID,CAGhB,GAAI,CAEEA,EAAO,SACT,KAAK,cAAcA,EAAO,OAAO,EAI/BA,EAAO,WACT,MAAM,KAAK,gBAAgBA,EAAO,UAAWA,EAAO,OAAS,CAAC,CAAC,CAInE,OAASxC,EAAO,CAEd,MAAMA,CACR,CACF,CAMA,MAAM,mBAAmBH,EAAsB,CAAC,EAAkB,CAMhE,IAAM4C,GAJJ5C,EAAU,OAAS,EAAIA,EAAY,MAAM,KAAK,KAAK,YAAY,KAAK,CAAC,GAI/B,IAAI,MAAOE,GAAa,CAC9D,GAAI,CACF,IAAM2C,EAAa,KAAK,YAAY,IAAI3C,CAAQ,CAKlD,MAAgB,CAEhB,CACF,CAAC,EAED,MAAM,QAAQ,IAAI0C,CAAe,CAEnC,CAKA,MAAM,SAAyB,CAG7B,GAAI,CAEF,MAAM,KAAK,WAAW,EAGtB,KAAK,YAAY,MAAM,EACvB,KAAK,iBAAiB,MAAM,EAG5B,KAAK,cAAgB,GACrB,KAAK,aAAe,EAGtB,OAASzC,EAAO,CAEd,MAAMA,CACR,CACF,CASQ,qBAAqBD,EAA2B,CACtD,GAAI,CAEF,OADwB,KAAK,cAAc,gBAAgB,EACpC,SAASA,CAAQ,CAC1C,MAAgB,CAGd,MAAO,EACT,CACF,CAKQ,yBAAyBF,EAAqBC,EAAqB,CACzE,GAAI,CAAC,MAAM,QAAQD,CAAS,EAC1B,MAAM,IAAI,MAAM,0EAAc,EAGhC,GAAI,CAAC,MAAM,QAAQC,CAAK,EACtB,MAAM,IAAI,MAAM,wDAAW,EAI7B,QAAWC,KAAYF,EAAW,CAChC,GAAI,CAACE,GAAY,OAAOA,GAAa,SACnC,MAAM,IAAI,MAAM,iEAAeA,CAAQ,EAAE,EAG3C,GAAI,CAACA,EAAS,WAAW,OAAO,GAAK,CAACA,EAAS,WAAW,QAAQ,EAChE,MAAM,IAAI,MAAM,+EAA6BA,CAAQ,EAAE,CAE3D,CACF,CAKA,MAAc,iBACZA,EACAD,EACe,CAGf,GAAI,CAEF,IAAMI,EAAqB,IAAIyC,GAC7B5C,EACA,KAAK,QAAQ,cACf,EAGI,KAAK,mBACPG,EAAmB,kBAAkB,KAAK,iBAAiB,EAI7D,KAAK,YAAY,IAAIH,EAAUG,CAAkB,EAGjD,KAAK,iBAAiB,IAAIH,EAAU,CAClC,SAAAA,EACA,UAAW,GACX,YAAa,EACf,CAAC,CAGH,OAASC,EAAO,CAEd,MAAMA,CACR,CACF,CAKA,MAAc,sBACZD,EACAG,EACe,CACf,IAAMM,EAAS,KAAK,iBAAiB,IAAIT,CAAQ,EACjD,GAAI,CAACS,EACH,MAAM,IAAI,MAAM,iEAAeH,GAAcN,CAAQ,CAAC,EAAE,EAK1D,GAAI,CAEFS,EAAO,UAAY,GACnBA,EAAO,YAAc,GAGrB,MAAMN,EAAmB,QAAQ,EAGjCM,EAAO,UAAY,GACnBA,EAAO,YAAc,GACrBA,EAAO,cAAgB,IAAI,KAC3BA,EAAO,UAAY,OAGnB,KAAK,0BACHT,EACA,GACA,UACA,GACA,6CACA,oBACF,CAGF,OAASC,EAAO,CAEd,MAAAQ,EAAO,UAAY,GACnBA,EAAO,YAAc,GACrBA,EAAO,UAAYR,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,EAGxE,KAAK,0BACHD,EACA,GACA,UACA,GACAC,aAAiB,MAAQA,EAAM,QAAU,2BACzC,oBACF,EAKMA,CACR,CACF,CAKA,MAAc,yBACZD,EACAG,EACe,CACf,IAAMM,EAAS,KAAK,iBAAiB,IAAIT,CAAQ,EACjD,GAAKS,EAML,GAAI,CAEFN,EAAmB,WAAW,EAG9BM,EAAO,UAAY,GACnBA,EAAO,YAAc,GAGrB,KAAK,0BACHT,EACA,GACA,aACA,GACA,6CACA,oBACF,CAGF,OAASC,EAAO,CAGdQ,EAAO,UAAY,GACnBA,EAAO,YAAc,GAGrB,KAAK,0BACHT,EACA,GACA,aACA,GACAC,aAAiB,MAAQA,EAAM,QAAU,2BACzC,oBACF,CACF,CACF,CAKA,MAAc,wBACZD,EACAG,EACe,CACf,IAAMM,EAAS,KAAK,iBAAiB,IAAIT,CAAQ,EACjD,GAAI,CAACS,EACH,MAAM,IAAI,MAAM,iEAAeH,GAAcN,CAAQ,CAAC,EAAE,EAK1D,GAAI,CAEF,MAAMG,EAAmB,UAAU,EAGnCM,EAAO,UAAY,GACnBA,EAAO,YAAc,GACrBA,EAAO,cAAgB,IAAI,KAC3BA,EAAO,UAAY,OAGnB,KAAK,0BACHT,EACA,GACA,YACA,GACA,6CACA,oBACF,CAGF,OAASC,EAAO,CAEd,MAAAQ,EAAO,UAAY,GACnBA,EAAO,YAAc,GACrBA,EAAO,UAAYR,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,EAGxE,KAAK,0BACHD,EACA,GACA,YACA,GACAC,aAAiB,MAAQA,EAAM,QAAU,2BACzC,oBACF,EAGMA,CACR,CACF,CAKQ,iBAA0B,CAChC,GAAI,CAAC,KAAK,kBACR,MAAO,CAAC,EAGV,GAAI,CAGF,OAFiB,KAAK,kBAAkB,YAAY,EAEpC,IAAK4C,IAAU,CAC7B,KAAMA,EAAK,KACX,YAAaA,EAAK,YAClB,YAAaC,GAAqBD,EAAK,WAAW,CACpD,EAAE,CACJ,MAAgB,CAEd,MAAO,CAAC,CACV,CACF,CACF,ICtlCA,IAAAE,GAAAC,EAAA,kBASAC,KACAC,KAWAA,KAGAD,OCxBA,IAAOE,GAAPC,GAAAC,EAAA,kBAAOF,GAAQ,CACb,GAAI,CACF,cAAe,sBACf,iBAAkB,kBACpB,EACA,GAAI,CACF,cAAe,uBACf,iBAAkB,mBACpB,CACF,ICMO,SAASG,GACdC,EACAC,EAAqB,KACZ,CACT,GAAI,CAACD,GAAS,OAAOA,GAAU,UAAYA,EAAM,KAAK,IAAM,GAC1D,MAAM,IAAI,MAAM,iDAAmB,EAGrC,IAAME,EAAMC,GAAOF,CAAQ,GAAKE,GAAO,GAEvC,OAAO,IAAI,WAAQ,CACjB,QAASD,EAAI,cACb,MAAOF,EAAM,KAAK,EAClB,UAAWE,EAAI,iBACf,MAAO,EACT,CAAC,CACH,CA/BA,IAAAE,GAAAC,EAAA,kBAKAC,KACAC,KASgBC,EAAAT,GAAA,sBCJhB,OAAOU,OAAe,aAXtB,IAiBaC,GAjBbC,GAAAC,EAAA,kBAYAC,KAKaH,GAAN,KAAqB,CAjB5B,MAiB4B,CAAAI,EAAA,uBAClB,MACA,MACA,OAER,YAAYC,EAAe,CACzB,KAAK,MAAQA,EAAM,KAAK,EACxB,KAAK,OAASC,GAAiB,KAAK,KAAK,EAGzC,KAAK,MAAQ,IAAIP,GAAU,CACzB,OAAQ,GACV,CAAC,CACH,CAKA,MAAM,eAAsC,CAC1C,IAAMQ,EAAW,aACXC,EAAS,KAAK,MAAM,IAAiBD,CAAQ,EACnD,GAAIC,EAAQ,OAAOA,EAEnB,GAAM,CAAE,WAAAC,EAAa,CAAC,CAAE,EAAI,MAAM,KAAK,OAAO,WAAW,KAAK,EAG9D,YAAK,MAAM,IAAIF,EAAUE,EAAY,IAAO,EAErCA,CACT,CAKA,MAAM,aAAaC,EAAyD,CAC1E,GAAM,CAAE,aAAAC,EAAc,SAAAC,EAAW,EAAG,UAAAC,EAAY,EAAG,EAAIH,EAEvD,GAAI,CAACC,GAAgB,OAAOA,GAAiB,SAC3C,MAAM,IAAI,MAAM,oDAAY,EAG9B,IAAMJ,EAAW,aAAaI,CAAY,IAAIC,CAAQ,IAAIC,CAAS,GAC7DL,EAAS,KAAK,MAAM,IAAuBD,CAAQ,EACzD,GAAIC,EAAQ,OAAOA,EAYnB,IAAMM,GAVW,MAAM,KAAK,OAAO,IAGjC,gBAAiB,CACjB,aAAAH,EACA,SAAUC,EACV,UAAWC,EACX,cAAe,UACjB,CAAC,GAEuB,KAGxB,YAAK,MAAM,IAAIN,EAAUO,CAAM,EAExBA,CACT,CAQA,aACEC,EACAC,EAC0B,CAC1B,OAAO,KAAK,OAAO,UAAU,KAAK,OAAO,CACvC,YAAaD,EACb,WAAAC,CACF,CAAC,CACH,CAMA,WAAWC,EAAwB,CACjC,GAAI,CAACA,EAAS,CAEZ,KAAK,MAAM,SAAS,EACpB,MACF,CAKA,IAAMC,EADO,KAAK,MAAM,KAAK,EACH,OAAQC,GAAQA,EAAI,WAAWF,CAAO,CAAC,EACjE,KAAK,MAAM,IAAIC,CAAY,CAC7B,CAKA,eAQE,CACA,IAAME,EAAQ,KAAK,MAAM,SAAS,EAC5BC,EAAO,KAAK,MAAM,KAAK,EACvBC,EAAgBF,EAAM,KAAOA,EAAM,OACnCG,EAAUD,EAAgB,EAAIF,EAAM,KAAOE,EAAgB,EAEjE,MAAO,CACL,KAAMF,EAAM,KACZ,KAAAC,EACA,KAAMD,EAAM,KACZ,OAAQA,EAAM,OACd,QAAAG,EACA,MAAOH,EAAM,MACb,MAAOA,EAAM,KACf,CACF,CACF,IC7IA,IAAAI,GAAA,GAAAC,GAAAD,GAAA,oBAAAE,GAAA,WAAAC,GAAA,qBAAAC,KACA,UAAAC,OAAc,YADd,IAAAC,GAAAC,EAAA,kBAAAC,KACAC,GAAAT,GAAAK,IACAK,KACAC,OCCA,OAAS,cAAAC,OAAkB,SA0MpB,SAASC,GACdC,EACAC,EACQ,CACR,IAAMC,EAAWJ,GAAW,KAAK,EAC9B,OAAO,KAAK,UAAUG,GAAc,CAAC,CAAC,CAAC,EACvC,OAAO,KAAK,EACf,MAAO,GAAGD,CAAQ,IAAIE,CAAQ,EAChC,CAYO,SAASC,GAAeC,EAAmBC,EAAsB,CACtE,IAAMC,EAAa,IAAI,KAAKF,CAAS,EAAE,QAAQ,EAE/C,OADY,KAAK,IAAI,EACRE,EAAaD,CAC5B,CAKO,SAASE,GAAmBC,EAAyC,CAC1E,IAAMC,EAAM,KAAK,IAAI,EACfH,EAAa,IAAI,KAAKE,EAAM,SAAS,EAAE,QAAQ,EAarD,MAVI,GAAAA,EAAM,UAAYC,EAAMH,EAAa,KAKrCG,EAAMH,EAAaE,EAAM,KAKzBA,EAAM,SAAW,SAKvB,CA/PA,IAoQaE,GApQbC,GAAAC,EAAA,kBA8MgBC,EAAAd,GAAA,oBAoBAc,EAAAV,GAAA,kBASAU,EAAAN,GAAA,sBAyBHG,GAAiB,CAC5B,QAAS,IACT,UAAW,IACX,iBAAkB,IAClB,eAAgB,IAChB,sBAAuB,EACzB,ICnOO,SAASI,GACdC,EACAC,EACiB,CAKjB,MAAO,CACL,QAAS,CACP,CACE,KAAM,OACN,KARsBA,EACxBC,GAA8BD,EAAUD,CAAM,EAC9CG,GAAyBH,CAAM,CAO/B,CACF,EACA,QAAS,GACT,OAAAA,EACA,OAAQ,UACR,QAAS,uFACT,WAAY,0EACd,CACF,CAKA,SAASE,GACPD,EACAD,EACQ,CACR,IAAMI,EAAuC,CAC3C,cAAe;AAAA;AAAA;AAAA,oBAGTJ,CAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,+FAUZ,QAASG,GAAyBH,CAAM,CAC1C,EAEA,OAAOI,EAAaH,CAAQ,GAAKG,EAAa,OAChD,CAKA,SAASD,GAAyBH,EAAwB,CACxD,MAAO;AAAA;AAAA;AAAA,oBAGCA,CAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,8FAQhB,CAxGA,IAGaK,GAHbC,GAAAC,EAAA,kBAGaF,GAAN,MAAMG,UAAqB,KAAM,CAHxC,MAGwC,CAAAC,EAAA,qBACb,KAAO,eAEhC,YAAYC,EAAiB,CAC3B,MAAMA,CAAO,EACb,KAAK,KAAO,eACZ,MAAM,kBAAkB,KAAMF,CAAY,CAC5C,CAEA,QAAS,CACP,MAAO,CACL,KAAM,KAAK,KACX,QAAS,KAAK,QACd,MAAO,KAAK,KACd,CACF,CACF,EAoBgBC,EAAAV,GAAA,yBA0BPU,EAAAP,GAAA,iCA2BAO,EAAAN,GAAA,8BC1DT,SAASQ,GAAeC,EAAuD,CAC7E,OAAOA,EAAQ,OAAS,OAC1B,CApCA,IAiDaC,GAjDbC,GAAAC,EAAA,kBAMAC,IACAC,KAGAC,KACAC,KAGAC,IACAC,IAOAH,KAMAI,KAMSC,EAAAZ,GAAA,kBAeIE,GAAN,KAAuB,CAjD9B,MAiD8B,CAAAU,EAAA,yBACpB,OACA,MAAoC,IAAI,IACxC,aACA,kBACS,QAAUC,GAAe,QACzB,UAAYA,GAAe,UAE5C,YACEC,EACAC,EACA,CACA,KAAK,OAASC,EACd,KAAK,aAAeF,GAAgB,IAAIG,GACxC,KAAK,kBAAoBF,EAGzB,KAAK,oBAAoB,CAC3B,CAKQ,mBAAoC,CAC1C,IAAMG,EAAQC,EAAc,UAAU,EAAE,WAAW,MAAM,MAEzD,GAAI,CAACD,EACH,MAAM,IAAI,MAAM,2CAAkB,EAGpC,OAAO,IAAIE,GAAeF,CAAK,CACjC,CAKQ,qBAA4B,CACjBG,EAAY,EAGpB,QAAQ,iBAAkB,MAAOC,GAAS,CACjD,GAAIA,EAAK,OAAS,YAAa,CAC7B,KAAK,OAAO,KAAK,+FAA8B,EAC/C,GAAI,CACF,KAAK,aAAa,CACpB,OAASC,EAAO,CACd,KAAK,OAAO,MAAM,gEAAyBA,CAAK,CAClD,CACF,CACF,CAAC,CACH,CAOO,WAAWC,EAA+B,CAC/C,KAAK,OAAO,MAAM,gEAAkC,EAEpD,GAAI,CACF,IAAMC,EAAcD,GAASL,EAAc,kBAAkB,EAG7D,KAAK,MAAM,MAAM,EAGjB,QAAWO,KAAQD,EACjB,GAAIzB,GAAe0B,EAAK,OAAO,GAAKA,EAAK,QAAQ,WAAa,OAC5D,KAAK,MAAM,IAAIA,EAAK,KAAMA,CAAI,EAC9B,KAAK,OAAO,MACV,qDAA4BA,EAAK,IAAI,kBAAkBA,EAAK,QAAQ,OAAO,WAAW,GACxF,MACK,CAEL,IAAMC,EAAe3B,GAAe0B,EAAK,OAAO,EAC5C,IAAIA,EAAK,QAAQ,QAAQ,GACzB,GACJ,KAAK,OAAO,KACV,6EAA2BA,EAAK,IAAI,KAAKA,EAAK,QAAQ,IAAI,GAAGC,CAAY,GAC3E,CACF,CAGF,KAAK,OAAO,MACV,sEAAyB,KAAK,MAAM,IAAI,2BAC1C,CACF,OAASJ,EAAO,CACd,WAAK,OAAO,MAAM,8CAAsBA,CAAK,EACvCA,CACR,CACF,CAKO,UAAmB,CACxB,OAAO,MAAM,KAAK,KAAK,MAAM,OAAO,CAAC,EAAE,IAAKG,IAAU,CACpD,KAAMA,EAAK,KACX,YAAaA,EAAK,YAClB,YAAaE,GAAqBF,EAAK,WAAW,CACpD,EAAE,CACJ,CAKO,QAAQG,EAA2B,CACxC,OAAO,KAAK,MAAM,IAAIA,CAAQ,CAChC,CAKO,cAAuB,CAC5B,OAAO,KAAK,MAAM,IACpB,CAKO,cAAyB,CAC9B,OAAO,MAAM,KAAK,KAAK,MAAM,KAAK,CAAC,CACrC,CAKO,YAAYA,EAA6C,CAC9D,OAAO,KAAK,MAAM,IAAIA,CAAQ,CAChC,CAMO,cAAqB,CAC1B,KAAK,OAAO,MAAM,4EAAoC,EACtD,KAAK,WAAW,CAClB,CAKA,MAAa,SACXA,EACAC,EACAC,EAC2B,CAC3B,IAAML,EAAO,KAAK,MAAM,IAAIG,CAAQ,EACpC,GAAI,CAACH,EACH,MAAM,IAAI,MAAM,mCAAUG,CAAQ,EAAE,EAItC,IAAMG,EAAkB,MAAM,KAAK,mBAAmBH,EAAUC,CAAU,EAC1E,GAAIE,EACF,YAAK,OAAO,MAAM,6EAA2BH,CAAQ,EAAE,EAEvD,MAAM,KAAK,mBAAmBA,EAAUC,CAAU,EAC3CE,EAGT,GAAI,CACF,IAAMC,EAAUF,GAAS,SAAW,KAAK,QACnCG,EAAS,MAAM,QAAQ,KAAK,CAChC,KAAK,iBAAiBR,EAAMI,CAAU,EACtC,KAAK,qBAAqBD,EAAUI,CAAO,CAC7C,CAAC,EAGD,aAAM,KAAK,YAAYJ,EAAUC,EAAYI,CAAM,EAE5CA,CACT,OAASX,EAAO,CAEd,GAAIA,aAAiBY,GAAc,CACjC,IAAMC,EAAS,MAAM,KAAK,eAAeP,EAAUC,CAAU,EAC7D,YAAK,OAAO,KACV,mFAA4BD,CAAQ,aAAaO,CAAM,EACzD,EACOC,GAAsBD,EAAQP,CAAQ,CAC/C,CAEA,MAAMN,CACR,CACF,CAKA,MAAc,qBACZM,EACAI,EACgB,CAChB,OAAO,IAAI,QAAQ,CAACK,EAAGC,IAAW,CAChC,WAAW,IAAM,CACfA,EAAO,IAAIJ,GAAa,yCAAWN,CAAQ,EAAE,CAAC,CAChD,EAAGI,CAAO,CACZ,CAAC,CACH,CAKA,MAAc,mBACZJ,EACAC,EACgC,CAChC,GAAI,CACF,IAAMU,EAAW,KAAK,iBAAiBX,EAAUC,CAAU,EACrDW,EAAQ,MAAM,KAAK,kBAAkB,EAE3C,GAAI,CAACA,EAAM,kBAAoB,CAACA,EAAM,iBAAiBD,CAAQ,EAC7D,OAAO,KAGT,IAAME,EAASD,EAAM,iBAAiBD,CAAQ,EAG9C,OAAIE,EAAO,SAAW,aAAe,CAACA,EAAO,UAEvC,CAACC,GAAeD,EAAO,UAAWA,EAAO,GAAG,EACvCA,EAAO,OAIX,IACT,OAASnB,EAAO,CACd,YAAK,OAAO,KAAK,qDAAuBA,CAAK,EAAE,EACxC,IACT,CACF,CAKQ,wBACNM,EACAe,EACgB,CAChB,GAAI,CAGF,IAAMC,EAAeD,EAAa,MAAQA,EAE1C,OAAI,OAAOC,GAAiB,SACnB,CACL,QAAS,CACP,CACE,KAAM,OACN,KAAMA,CACR,CACF,EACA,QAAS,EACX,EAIK,CACL,QAAS,CACP,CACE,KAAM,OACN,KAAM,KAAK,UAAUA,EAAc,KAAM,CAAC,CAC5C,CACF,EACA,QAAS,EACX,CACF,OAAStB,EAAO,CACd,YAAK,OAAO,MAAM,uEAA0BM,CAAQ,GAAIN,CAAK,EAEtD,CACL,QAAS,CACP,CACE,KAAM,OACN,KAAM,yCACJA,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CACvD,EACF,CACF,EACA,QAAS,EACX,CACF,CACF,CAKA,MAAc,iBACZG,EACAI,EACyB,CAEzB,IAAMgB,EADUpB,EAAK,QACE,OAEvB,KAAK,OAAO,KAAK,qDAA4BA,EAAK,IAAI,GAAI,CACxD,YAAaoB,EAAO,WACtB,CAAC,EAED,GAAI,CAEF,IAAMC,EAAiB,KAAK,kBAAkB,EAG9C,GAAI,CAACD,EAAO,YACV,MAAM,IAAI,MAAM,wCAAU,EAI5B,IAAME,EAAiB,MAAMD,EAAe,aAC1CD,EAAO,YACPhB,CACF,EAEA,YAAK,OAAO,KAAK,gEAA6BJ,EAAK,IAAI,EAAE,EAGlD,KAAK,wBAAwBA,EAAK,KAAMsB,CAAc,CAC/D,OAASzB,EAAO,CACd,YAAK,OAAO,MAAM,gEAA6BG,EAAK,IAAI,GAAIH,CAAK,EAE1D,CACL,QAAS,CACP,CACE,KAAM,OACN,KAAM,oDACJA,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CACvD,EACF,CACF,EACA,QAAS,EACX,CACF,CACF,CAKA,MAAc,mBACZM,EACAC,EACe,CACf,GAAI,CACF,IAAMU,EAAW,KAAK,iBAAiBX,EAAUC,CAAU,EACrDW,EAAQ,MAAM,KAAK,kBAAkB,EAE3C,GAAIA,EAAM,mBAAmBD,CAAQ,EAAG,CAEtCC,EAAM,iBAAiBD,CAAQ,EAAE,SAAW,GAG5C,IAAME,EAASD,EAAM,iBAAiBD,CAAQ,EAC1CS,GAAmBP,CAAM,GAC3B,OAAOD,EAAM,iBAAiBD,CAAQ,EAIxC,MAAM,KAAK,UAAUC,CAAK,EAC1B,KAAK,OAAO,MAAM,2DAAwBD,CAAQ,EAAE,CACtD,CACF,OAASjB,EAAO,CACd,KAAK,OAAO,KAAK,qDAAuBA,CAAK,EAAE,CACjD,CACF,CAKA,MAAc,eACZM,EACAC,EACiB,CACjB,OAAOoB,GAAiBrB,EAAUC,CAAU,CAC9C,CAKQ,iBACND,EACAC,EACQ,CACR,OAAOoB,GAAiBrB,EAAUC,CAAU,CAC9C,CAKA,MAAc,mBAAoD,CAChE,GAAI,CAEF,OADkB,MAAM,KAAK,aAAa,kBAAkB,CAE9D,MAAgB,CACd,MAAO,CACL,QAAS,QACT,WAAY,CAAC,EACb,SAAU,CACR,iBAAkB,IAAI,KAAK,EAAE,YAAY,EACzC,YAAa,EACb,UAAW,IAAI,KAAK,EAAE,YAAY,CACpC,EACA,iBAAkB,CAAC,CACrB,CACF,CACF,CAKA,MAAc,sBACZU,EACAW,EACe,CACf,GAAI,CACF,IAAMV,EAAQ,MAAM,KAAK,kBAAkB,EAEtCA,EAAM,mBACTA,EAAM,iBAAmB,CAAC,GAG5BA,EAAM,iBAAiBD,CAAQ,EAAIW,EAGnC,MAAM,KAAK,UAAUV,CAAK,CAC5B,OAASlB,EAAO,CACd,KAAK,OAAO,KAAK,qDAAuBA,CAAK,EAAE,CACjD,CACF,CAKA,MAAc,YACZM,EACAC,EACAI,EACe,CACf,GAAI,CACF,IAAMM,EAAW,KAAK,iBAAiBX,EAAUC,CAAU,EACrDqB,EAAqC,CACzC,OAAAjB,EACA,UAAW,IAAI,KAAK,EAAE,YAAY,EAClC,IAAK,KAAK,UACV,OAAQ,YACR,SAAU,GACV,WAAY,CACd,EAEA,MAAM,KAAK,sBAAsBM,EAAUW,CAAS,EACpD,KAAK,OAAO,MAAM,qDAAuBtB,CAAQ,EAAE,CACrD,OAASN,EAAO,CACd,KAAK,OAAO,KAAK,qDAAuBA,CAAK,EAAE,CACjD,CACF,CAKA,MAAc,UAAUkB,EAA6C,CACnE,GAAI,CACF,MAAM,KAAK,aAAa,UAAUA,CAAK,CACzC,OAASlB,EAAO,CACd,KAAK,OAAO,KAAK,qDAAuBA,CAAK,EAAE,CACjD,CACF,CAKO,SAAgB,CACrB,KAAK,OAAO,KAAK,mEAAgC,EACjD,KAAK,MAAM,MAAM,EACjB,KAAK,aAAa,QAAQ,CAC5B,CACF,ICtgBA,UAAY6B,OAAQ,KACpB,UAAYC,OAAU,OAEtB,OAAOC,OAAU,OARjB,IAkEaC,GAyKAC,GA3ObC,GAAAC,EAAA,kBAOAC,KA2DaJ,GAAN,KAAqB,CAlE5B,MAkE4B,CAAAK,EAAA,uBAClB,WACA,WACA,YAER,YAAYC,EAA2BC,EAAmB,CAIxD,GAHA,KAAK,WAAaD,GAAQ,YAAc,IAGpCA,GAAQ,YACV,KAAK,YAAmB,WAAa,aAAUA,EAAO,WAAW,CAAC,MAC7D,CAEL,IAAME,EAAUD,GAAaE,EAAU,WAAW,EAClD,KAAK,YAAmB,QAAU,aAAUD,CAAO,EAAG,kBAAkB,CAC1E,CAGA,KAAK,WAAa,KAAK,iBAAiB,KAAK,WAAW,CAM1D,CAKQ,iBAAiBE,EAAiC,CACxD,IAAMC,EAA8B,CAAC,EAGrCA,EAAQ,KAAK,CACX,MAAO,OACP,OAAQ,CACN,MAAON,EAACO,GAAkB,CACxB,GAAI,CACF,IAAMC,EAAS,KAAK,MAAMD,CAAK,EACzBE,EAAU,KAAK,qBAAqBD,CAAM,CAElD,MAAQ,CAER,CACF,EARO,QAST,CACF,CAAC,EAGD,GAAI,CACFF,EAAQ,KAAK,CACX,MAAO,OACP,OAAQZ,GAAK,YAAY,CACvB,KAAMW,EACN,KAAM,GACN,OAAQ,GACR,MAAO,EACT,CAAC,CACH,CAAC,CACH,MAAgB,CAGhB,CAEA,OAAOX,GACL,CACE,MAAO,OACP,UACEA,GAAK,kBAAkB,UAAY,IAAM,WAAW,KAAK,IAAI,CAAC,IAChE,WAAY,CACV,MAAOM,EAAA,CAACU,EAAgBC,KAAoB,CAAE,MAAOA,CAAO,GAArD,QACT,EACA,KAAM,IACR,EACAjB,GAAK,YAAYY,EAAS,CAAE,OAAQ,EAAK,CAAC,CAC5C,CACF,CAKQ,qBAAqBE,EAA+B,CAC1D,IAAMI,EAAWJ,EAAO,UAAY,2BAC9BK,EAAUL,EAAO,UAAY,GAC7BM,EAAWN,EAAO,SAAW,KAAKA,EAAO,QAAQ,MAAQ,GAG/D,MAAO,GAFQK,EAAU,SAAM,QAEf,IAAID,CAAQ,GAAGE,CAAQ,EACzC,CAKA,MAAc,mBAAmC,CAC/C,GAAI,CAEF,GAAI,CAAI,cAAW,KAAK,WAAW,EACjC,OAKF,IAAMC,EADa,gBAAa,KAAK,YAAa,MAAM,EAErD,KAAK,EACL,MAAM;AAAA,CAAI,EACV,OAAQC,GAASA,EAAK,KAAK,IAAM,EAAE,EAGtC,GAAID,EAAM,QAAU,KAAK,WACvB,OAIF,IAAME,EAAkBF,EAAM,OAAS,KAAK,WAAa,EAGnDG,EAAcH,EAAM,MAAME,CAAe,EAGzCE,EACJD,EAAY,KAAK;AAAA,CAAI,GAAKA,EAAY,OAAS,EAAI;AAAA,EAAO,IACzD,iBAAc,KAAK,YAAaC,EAAY,MAAM,CAMvD,MAAgB,CAEhB,CACF,CAKA,MAAM,eAAeC,EAAuC,CAC1D,GAAI,CAEF,MAAM,KAAK,kBAAkB,EAG7B,KAAK,WAAW,KAAKA,EAAQA,EAAO,QAAQ,CAC9C,MAAgB,CAGhB,CACF,CAKA,gBAAyB,CACvB,OAAO,KAAK,WACd,CAKA,eAAwB,CACtB,OAAO,KAAK,UACd,CACF,EAQaxB,GAAN,KAAyB,CA3OhC,MA2OgC,CAAAI,EAAA,2BACtB,UAER,YAAYE,EAAoB,CAC9B,KAAK,UAAYA,GAAaE,EAAU,aAAa,CACvD,CAKQ,gBAAyB,CAE/B,OADuB,IAAIT,GAAe,CAAC,EAAG,KAAK,SAAS,EACtC,eAAe,CACvC,CAKQ,cAAqB,CAC3B,IAAMU,EAAc,KAAK,eAAe,EACxC,GAAI,CAAI,cAAWA,CAAW,EAC5B,MAAM,IAAI,MAAM,oEAAa,CAEjC,CAKQ,cAAiC,CACvC,IAAMA,EAAc,KAAK,eAAe,EAExC,GAAI,CAEF,IAAMU,EADa,gBAAaV,EAAa,MAAM,EAEhD,KAAK,EACL,MAAM;AAAA,CAAI,EACV,OAAQW,GAASA,EAAK,KAAK,IAAM,EAAE,EAEhCK,EAA4B,CAAC,EAEnC,QAAWL,KAAQD,EACjB,GAAI,CACF,IAAMK,EAAS,KAAK,MAAMJ,CAAI,EAE1BI,EAAO,OACTA,EAAO,UAAY,IAAI,KAAKA,EAAO,IAAI,EAAE,QAAQ,GAG9CA,EAAO,UAGZC,EAAQ,KAAKD,CAAM,CACrB,MAAQ,CAER,CAIF,OAAAC,EAAQ,KAAK,CAACC,EAAGC,KAAOA,EAAE,WAAa,IAAMD,EAAE,WAAa,EAAE,EAEvDD,CACT,MAAgB,CAEd,MAAM,IAAI,MAAM,0EAAc,CAChC,CACF,CAKQ,cACNA,EACAG,EACkB,CAClB,IAAIC,EAAW,CAAC,GAAGJ,CAAO,EA0B1B,GAvBIG,EAAM,WACRC,EAAWA,EAAS,OAAQL,GAC1BA,EAAO,SACJ,YAAY,EACZ,SAASI,EAAM,UAAU,YAAY,GAAK,EAAE,CACjD,GAIEA,EAAM,aACRC,EAAWA,EAAS,OAAQL,GAC1BA,EAAO,YACH,YAAY,EACb,SAASI,EAAM,YAAY,YAAY,GAAK,EAAE,CACnD,GAIEA,EAAM,UAAY,SACpBC,EAAWA,EAAS,OAAQL,GAAWA,EAAO,UAAYI,EAAM,OAAO,GAIrEA,EAAM,WAAaA,EAAM,QAAS,CACpC,IAAME,EAAYF,EAAM,UACpB,IAAI,KAAKA,EAAM,SAAS,EAAE,QAAQ,EAClC,EACEG,EAAUH,EAAM,QAClB,IAAI,KAAKA,EAAM,OAAO,EAAE,QAAQ,EAChC,KAAK,IAAI,EAEbC,EAAWA,EAAS,OAAQL,GAAW,CACrC,IAAMQ,EAAaR,EAAO,WAAa,EACvC,OAAOQ,GAAcF,GAAaE,GAAcD,CAClD,CAAC,CACH,CAEA,OAAOF,CACT,CAKA,MAAM,gBAAgBD,EAAuB,CAAC,EAI3C,CACD,KAAK,aAAa,EAElB,IAAMH,EAAU,KAAK,aAAa,EAC5BI,EAAW,KAAK,cAAcJ,EAASG,CAAK,EAC5CK,EAAQJ,EAAS,OAGjBK,EAAQ,KAAK,IACjBN,EAAM,OAAS,GACf,GACF,EACMO,EAASP,EAAM,QAAU,EACzBQ,EAAYP,EAAS,MAAMM,EAAQA,EAASD,CAAK,EACjDG,EAAUF,EAASD,EAAQD,EAOjC,MAAO,CACL,QAASG,EACT,MAAAH,EACA,QAAAI,CACF,CACF,CACF,IClYA,IAmDaC,GAnDbC,GAAAC,EAAA,kBAOAC,KAMAC,IAsCaJ,GAAN,KAAwB,CAnD/B,MAmD+B,CAAAK,EAAA,0BACrB,OACA,eAER,YAAYC,EAAmC,CAC7C,KAAK,eAAiBA,EACtB,KAAK,OAASC,CAChB,CAOA,MAAM,cAAcC,EAAkD,CACpE,KAAK,OAAO,MAAM,kCAAcA,EAAQ,MAAM,GAAIA,CAAO,EAEzD,GAAI,CAEF,IAAMC,EAAiBD,EAAQ,KAAO,OAEtC,OAAQA,EAAQ,OAAQ,CACtB,IAAK,aACH,OAAO,MAAM,KAAK,iBAChBA,EAAQ,OACRA,EAAQ,EACV,EACF,IAAK,4BACH,OAAO,MAAM,KAAK,8BAChBA,EAAQ,MACV,EACF,IAAK,aACH,OAAO,MAAM,KAAK,gBAAgBA,EAAQ,EAAE,EAC9C,IAAK,aACH,OAAO,MAAM,KAAK,eAChBA,EAAQ,OACRA,EAAQ,EACV,EACF,IAAK,iBACH,OAAO,MAAM,KAAK,oBAAoBA,EAAQ,EAAE,EAClD,IAAK,eACH,OAAO,MAAM,KAAK,kBAAkBA,EAAQ,EAAE,EAChD,IAAK,OACH,OAAO,MAAM,KAAK,WAAWA,EAAQ,EAAE,EACzC,QACE,GAAIC,EAEF,YAAK,OAAO,KAAK,2DAAcD,EAAQ,MAAM,GAAIA,CAAO,EACjD,KAET,MAAM,IAAI,MAAM,mCAAUA,EAAQ,MAAM,EAAE,CAC9C,CACF,OAASE,EAAO,CAGd,OAFA,KAAK,OAAO,MAAM,+CAAYF,EAAQ,MAAM,GAAIE,CAAK,EAEjDF,EAAQ,KAAO,OACV,KAEF,KAAK,oBAAoBE,EAAgBF,EAAQ,EAAE,CAC5D,CACF,CAQA,MAAc,iBACZG,EACAC,EACsB,CACtB,KAAK,OAAO,MAAM,uCAAoBD,CAAM,EAG5C,IAAME,EAAoB,CAAC,aAAc,YAAY,EAC/CC,EAAgBH,EAAO,gBACvBI,EAAkBF,EAAkB,SAASC,CAAa,EAC5DA,EACA,aAEJ,YAAK,OAAO,MACV,4DAAeA,CAAa,oCAAWC,CAAe,EACxD,EAEO,CACL,QAAS,MACT,OAAQ,CACN,WAAY,CACV,KAAM,qBACN,QAAS,OACX,EACA,aAAc,CACZ,MAAO,CAAC,EACR,QAAS,CAAC,CACZ,EACA,gBAAiBA,CACnB,EACA,GAAIH,IAAO,OAAYA,EAAK,CAC9B,CACF,CAOA,MAAc,8BACZD,EACe,CACf,YAAK,OAAO,MAAM,8FAA8BA,CAAM,EAK/C,IACT,CAOA,MAAc,gBAAgBC,EAA4C,CACxE,KAAK,OAAO,MAAM,sCAAkB,EAEpC,GAAI,CAUF,MAAO,CACL,QAAS,MACT,OAAQ,CACN,MAZU,KAAK,eAAe,YAAY,EAGvB,IAAKI,IAAU,CACpC,KAAMA,EAAK,KACX,YAAaA,EAAK,YAClB,YAAaA,EAAK,WACpB,EAAE,CAMA,EACA,GAAIJ,IAAO,OAAYA,EAAK,CAC9B,CACF,OAASF,EAAO,CACd,WAAK,OAAO,MAAM,mDAAYA,CAAK,EAC7BA,CACR,CACF,CAQA,MAAc,eACZC,EACAC,EACsB,CACtB,GAAI,CAEF,IAAMK,EAAkBC,GAAuBP,CAAM,EAE/CQ,EAAS,MAAM,KAAK,eAAe,SACvCF,EAAgB,KAChBA,EAAgB,WAAa,CAAC,CAChC,EAEA,MAAO,CACL,QAAS,MACT,OAAQ,CACN,QAASE,EAAO,QAChB,QAASA,EAAO,SAAW,EAC7B,EACA,GAAIP,IAAO,OAAYA,EAAK,CAC9B,CACF,OAASF,EAAO,CACd,WAAK,OAAO,MAAM,yCAAWC,EAAO,IAAI,GAAID,CAAK,EAC3CA,CACR,CACF,CAOA,MAAc,WAAWE,EAA4C,CACnE,YAAK,OAAO,MAAM,gCAAY,EAEvB,CACL,QAAS,MACT,OAAQ,CACN,OAAQ,KACR,UAAW,IAAI,KAAK,EAAE,YAAY,CACpC,EACA,GAAIA,IAAO,OAAYA,EAAK,CAC9B,CACF,CAOA,MAAc,oBACZA,EACsB,CACtB,KAAK,OAAO,MAAM,0CAAsB,EAIxC,IAAMQ,EAA2B,CAAC,EAElC,YAAK,OAAO,MAAM,gBAAMA,EAAU,MAAM,qBAAM,EAEvC,CACL,QAAS,MACT,OAAQ,CACN,UAAWA,CACb,EACA,GAAIR,IAAO,OAAYA,EAAK,CAC9B,CACF,CAOA,MAAc,kBAAkBA,EAA4C,CAC1E,KAAK,OAAO,MAAM,wCAAoB,EAItC,IAAMS,EAAuB,CAAC,EAE9B,YAAK,OAAO,MAAM,gBAAMA,EAAQ,MAAM,iCAAQ,EAEvC,CACL,QAAS,MACT,OAAQ,CACN,QAASA,CACX,EACA,GAAIT,IAAO,OAAYA,EAAK,CAC9B,CACF,CAQQ,oBAAoBF,EAAcE,EAAmC,CAE3E,IAAIU,EAAY,OAEhB,OACEZ,EAAM,QAAQ,SAAS,gCAAO,GAC9BA,EAAM,QAAQ,SAAS,gCAAO,EAE9BY,EAAY,QAEZZ,EAAM,QAAQ,SAAS,cAAI,GAC3BA,EAAM,QAAQ,SAAS,0BAAM,KAE7BY,EAAY,QAGP,CACL,QAAS,MACT,MAAO,CACL,KAAMA,EACN,QAASZ,EAAM,QACf,KAAM,CACJ,MAAOA,EAAM,KACf,CACF,EACA,GAAIE,IAAO,OAAYA,EAAK,CAC9B,CACF,CAMA,mBAAuC,CACrC,OAAO,KAAK,cACd,CACF,ICrVA,IAAAW,GAAAC,EAAA,oBCAA,IAAAC,GAAAC,EAAA,kBAOAC,OCMA,OAAOC,IAAa,mBAAAC,OAAuB,KAb3C,IAAAC,GAAAC,EAAA,kBAcAC,OCdA,IAAAC,GAAAC,EAAA,kBAAAC,KAQAC,KACAC,OCDA,OAAS,gBAAAC,OAAoB,SAR7B,IAgCaC,GAhCbC,GAAAC,EAAA,kBASAC,KAEAF,IACAG,KACAA,KAYAC,IAEAC,KACAC,KACAC,KACAC,KAEaT,GAAN,cAAgCD,EAAa,CAhCpD,MAgCoD,CAAAW,EAAA,0BAC1C,SAAoC,IAAI,IACxC,QAA4C,CAAC,EAC7C,MAA+B,IAAI,IACnC,iBACA,aACA,SAAWC,EAAY,EACvB,eACA,YAA2C,IAAI,IAC/C,eAA8B,IAAI,IAGlC,kBAAmD,IAAI,IACvD,eAGA,UAAY,GACZ,OAMR,YACEC,EACA,CACA,MAAM,EAGFA,GAAW,KAAK,sBAAsBA,CAAO,GAE/C,KAAK,OAAS,CACZ,KAAM,oBACN,cAAe,GACf,SAAU,OACV,GAAGA,CACL,EACA,KAAK,QAAUA,EAAQ,SAAW,CAAC,IAGnC,KAAK,OAAS,CACZ,KAAM,oBACN,cAAe,GACf,SAAU,MACZ,EACA,KAAK,QAAUA,GAAW,CAAC,GAM7B,IAAMC,EADJ,QAAQ,IAAI,WAAa,QAAU,QAAQ,IAAI,SAAW,OAExD,qBAAqB,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAC5C,SAAS,EAAE,EACX,UAAU,EAAG,EAAE,CAAC,sBACnB,OAEJ,KAAK,aAAe,IAAIC,GAAgBD,CAAS,EACjD,KAAK,iBAAmB,IAAIE,GAAiB,KAAK,aAAc,IAAI,EAGpE,IAAMC,EAAoBC,EAAc,qBAAqB,EACvDC,EAAYD,EAAc,aAAa,EAC7C,KAAK,eAAiB,IAAIE,GAAeH,EAAmBE,CAAS,EAGrE,KAAK,oBAAoB,EAGzB,KAAK,eAAiB,IAAIE,GAAkB,IAAI,CAClD,CAKQ,qBAA4B,CAElC,KAAK,SAAS,QAAQ,wBAAyB,MAAOC,GAAS,CAC7D,MAAM,KAAK,uBAAuBA,CAAI,CACxC,CAAC,EAGD,KAAK,SAAS,QAAQ,2BAA4B,MAAOA,GAAS,CAChE,MAAM,KAAK,0BAA0BA,CAAI,CAC3C,CAAC,EAGD,KAAK,SAAS,QAAQ,gCAAiC,MAAOA,GAAS,CACrE,MAAM,KAAK,8BAA8BA,CAAI,CAC/C,CAAC,CACH,CAKA,MAAc,uBAAuBA,EAInB,CAGhB,GAAI,CAEc,KAAK,SAAS,IAAIA,EAAK,WAAW,GAGhD,MAAM,KAAK,8BAA8B,CAI7C,MAAgB,CAEhB,CACF,CAKA,MAAc,0BAA0BA,EAItB,CAKhB,GAAI,CAEF,MAAM,KAAK,kBAAkB,EAG7B,MAAM,KAAK,8BAA8B,CAG3C,MAAgB,CAEhB,CACF,CAKA,MAAc,8BAA8BA,EAI1B,CAChB,GAAI,CACF,MAAM,KAAK,8BAA8B,CAC3C,MAAgB,CAEhB,CACF,CAKA,MAAM,kBAAkC,CAItC,GAAI,CACF,KAAK,iBAAiB,WAAW,CAEnC,MAAgB,CAGhB,CAEA,IAAMC,EAAgB,OAAO,QAAQ,KAAK,OAAO,EACjD,GAAIA,EAAc,SAAW,EAK3B,OASF,IAAMC,EAAgBD,EAAc,IAAI,MAAO,CAACE,CAAW,IAAM,CAC/D,GAAI,CACF,aAAM,KAAK,aAAaA,CAAW,EAC5B,CAAE,YAAAA,EAAa,QAAS,GAAM,MAAO,IAAK,CACnD,OAASC,EAAO,CACd,MAAO,CACL,YAAAD,EACA,QAAS,GACT,MAAOC,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAC9D,CACF,CACF,CAAC,EAGKC,EAAU,MAAM,QAAQ,WAAWH,CAAa,EAGlDI,EAAe,EACfC,EAAe,EACbC,EAA2B,CAAC,EAElC,QAAWC,KAAUJ,EACfI,EAAO,SAAW,YAChBA,EAAO,MAAM,QACfH,KAEAC,IACAC,EAAe,KAAKC,EAAO,MAAM,WAAW,GAG9CF,IAUAC,EAAe,OAAS,GAMLP,EAAc,OAQjCO,EAAe,OAAS,GAC1B,KAAK,4BAA4BA,CAAc,CAEnD,CAKA,MAAM,aAAaL,EAAoC,CACrD,IAAMO,EAAS,KAAK,QAAQP,CAAW,EACvC,GAAI,CAACO,EACH,MAAM,IAAI,MAAM,+CAAYP,CAAW,EAAE,EAG3C,GAAI,CAEE,KAAK,SAAS,IAAIA,CAAW,GAC/B,MAAM,KAAK,YAAYA,CAAW,EAIpC,IAAMQ,EAAU,IAAIC,GAAWF,CAAM,EAGrC,MAAMC,EAAQ,QAAQ,EAGtB,KAAK,SAAS,IAAIR,EAAaQ,CAAO,EAGtC,MAAM,KAAK,kBAAkB,EAM7B,IAAME,EAAQF,EAAQ,SAAS,CAKjC,OAASP,EAAO,CAMd,WAAK,SAAS,OAAOD,CAAW,EAC1BC,CACR,CACF,CAKA,MAAM,YAAYD,EAAoC,CAGpD,IAAMQ,EAAU,KAAK,SAAS,IAAIR,CAAW,EAC7C,GAAKQ,EAKL,GAAI,CACF,MAAMA,EAAQ,WAAW,EACzB,KAAK,SAAS,OAAOR,CAAW,EAGhC,MAAM,KAAK,kBAAkB,CAG/B,OAASC,EAAO,CAKd,MAAMA,CACR,CACF,CAKA,MAAc,mBAAmC,CAC/C,KAAK,MAAM,MAAM,EAEjB,OAAW,CAACD,EAAaQ,CAAO,IAAK,KAAK,SACxC,GAAIA,EAAQ,YAAY,EAAG,CACzB,IAAME,EAAQF,EAAQ,SAAS,EACzBD,EAAS,KAAK,QAAQP,CAAW,EAGnCO,GACF,KAAK,aACF,gBAAgBP,EAAaU,EAAOH,CAAM,EAC1C,KAAK,IAAM,CAIZ,CAAC,EACA,MAAON,GAAU,CAMlB,CAAC,EAIL,QAAWU,KAAQD,EAAO,CACxB,IAAME,EAAU,GAAGZ,CAAW,KAAKW,EAAK,IAAI,GAC5C,KAAK,MAAM,IAAIC,EAAS,CACtB,YAAAZ,EACA,aAAcW,EAAK,KACnB,KAAAA,CACF,CAAC,CACH,CACF,CAIF,MAAM,KAAK,sBAAsB,CACnC,CAKA,aAMG,CACD,IAAME,EAMD,CAAC,EAGN,OAAW,CAACb,EAAaQ,CAAO,IAAK,KAAK,SACxC,GAAI,CACF,GAAIA,EAAQ,YAAY,EAAG,CACzB,IAAMM,EAAeN,EAAQ,SAAS,EACtC,QAAWG,KAAQG,EACjB,GAAI,CAMF,GAAI,CAJcrB,EAAc,cAC9BO,EACAW,EAAK,IACP,EAEE,SAGF,IAAMC,EAAU,GAAGZ,CAAW,KAAKW,EAAK,IAAI,GAC5CE,EAAS,KAAK,CACZ,KAAMD,EACN,YAAaD,EAAK,aAAe,GACjC,YAAaA,EAAK,YAClB,YAAAX,EACA,aAAcW,EAAK,IACrB,CAAC,CACH,MAAoB,CAKpB,CAEJ,CACF,MAAuB,CAKvB,CAIF,IAAII,EAAsB,CAAC,EAC3B,GAAI,CACFA,EAAc,KAAK,iBAAiB,SAAS,CAI/C,MAAgB,CAMdA,EAAc,CAAC,CACjB,CAEA,QAAWJ,KAAQI,EACjB,GAAI,CACFF,EAAS,KAAK,CACZ,KAAMF,EAAK,KACX,YAAaA,EAAK,aAAe,GACjC,YAAaA,EAAK,YAClB,YAAa,KAAK,sBAAsBA,CAAI,EAC5C,aAAcA,EAAK,IACrB,CAAC,CACH,MAAoB,CAKpB,CAIF,OAAOE,CACT,CAOQ,sBAAsBF,EAA6B,CACzD,OAAIA,EAAK,SAAS,OAAS,OAEVA,EAAK,QAAQ,QAGb,aAAe,WAGlC,CAOQ,iBAAiBK,EAAmC,CAC1D,GAAI,CAACA,GAAY,QACf,MAAO,SAGT,OAAQA,EAAW,QAAQ,KAAM,CAC/B,IAAK,MAIH,OAHeA,EAAW,QAAQ,QAGnB,aAAe,YAEhC,IAAK,OACH,MAAO,OACT,IAAK,OACH,MAAO,OACT,IAAK,MACH,MAAO,MACT,QACE,MAAO,QACX,CACF,CASQ,oBACNC,EACAD,EACAE,EACQ,CACR,OAAIF,EAEEA,EAAW,SAAS,OAAS,OAChBA,EAAW,QAAQ,QAGnB,UAAYC,EAMxBC,GAAU,cAAgBD,CACnC,CAKA,MAAM,SACJA,EACAE,EACAC,EACyB,CACzB,IAAMC,EAAY,KAAK,IAAI,EAGvBC,EAAgB,UAChBC,EAA2BN,EAE/B,GAAI,CACF,IAAIX,EAGJ,GAAI,KAAK,iBAAiB,QAAQW,CAAQ,EAAG,CAC3C,IAAMD,EAAa,KAAK,iBAAiB,YAAYC,CAAQ,EAGzDD,IACFM,EAAgB,KAAK,iBAAiBN,CAAU,EAChDO,EAAmB,KAAK,oBAAoBN,EAAUD,CAAU,GAG9DA,GAAY,SAAS,OAAS,OAEhCV,EAAS,MAAM,KAAK,YAClBW,EACAD,EAAW,QAAQ,OACnBG,CACF,EAGA,KAAK,oBACHF,EACAD,EAAW,QAAQ,OAAO,YAC1BA,EAAW,QAAQ,OAAO,SAC1B,EACF,IAGAV,EAAS,MAAM,KAAK,iBAAiB,SACnCW,EACAE,EACAC,CACF,EAIA,KAAK,oBAAoBH,EAAU,YAAaA,EAAU,EAAI,EAElE,KAAO,CAEL,IAAMC,EAAW,KAAK,MAAM,IAAID,CAAQ,EACxC,GAAI,CAACC,EACH,MAAM,IAAI,MAAM,mCAAUD,CAAQ,EAAE,EAItCK,EAAgBJ,EAAS,YACzBK,EAAmBL,EAAS,aAE5B,IAAMV,EAAU,KAAK,SAAS,IAAIU,EAAS,WAAW,EACtD,GAAI,CAACV,EACH,MAAM,IAAI,MAAM,gBAAMU,EAAS,WAAW,qBAAM,EAGlD,GAAI,CAACV,EAAQ,YAAY,EACvB,MAAM,IAAI,MAAM,gBAAMU,EAAS,WAAW,qBAAM,EAGlDZ,EAAS,MAAME,EAAQ,SACrBU,EAAS,aACTC,GAAc,CAAC,CACjB,EAQA,KAAK,oBACHF,EACAC,EAAS,YACTA,EAAS,aACT,EACF,CACF,CAGA,YAAK,eAAe,eAAe,CACjC,SAAUK,EACV,WAAYD,EACZ,UAAWH,EACX,OAAQb,EACR,QAASA,EAAO,UAAY,GAC5B,SAAU,KAAK,IAAI,EAAIe,CACzB,CAAC,EAEMf,CACT,OAASL,EAAO,CAad,GAXA,KAAK,eAAe,eAAe,CACjC,SAAUsB,EACV,WAAYD,EACZ,UAAWH,EACX,OAAQ,KACR,QAAS,GACT,SAAU,KAAK,IAAI,EAAIE,EACvB,MAAOpB,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAC9D,CAAC,EAGG,KAAK,iBAAiB,QAAQgB,CAAQ,EAAG,CAC3C,IAAMD,EAAa,KAAK,iBAAiB,YAAYC,CAAQ,EACzDD,GAAY,SAAS,OAAS,MAChC,KAAK,oBACHC,EACAD,EAAW,QAAQ,OAAO,YAC1BA,EAAW,QAAQ,OAAO,SAC1B,EACF,EAEA,KAAK,oBAAoBC,EAAU,YAAaA,EAAU,EAAK,CAMnE,KAAO,CACL,IAAMC,EAAW,KAAK,MAAM,IAAID,CAAQ,EACpCC,GACF,KAAK,oBACHD,EACAC,EAAS,YACTA,EAAS,aACT,EACF,CAMJ,CAEA,MAAMjB,CACR,CACF,CAUA,MAAc,gBACZgB,EACAjB,EACAuB,EACAC,EACe,CACf,GAAI,CACF,IAAMC,EAAc,IAAI,KAAK,EAAE,YAAY,EAEvCD,GAEF,MAAM,KAAK,yBAAyBP,EAAUQ,CAAW,EAGrDzB,IAAgB,aAClB,MAAM,KAAK,yBACTA,EACAuB,EACAE,CACF,IAMF,MAAM,KAAK,gCAAgCR,EAAUQ,CAAW,EAG5DzB,IAAgB,aAClB,MAAM,KAAK,gCACTA,EACAuB,EACAE,CACF,EAON,OAASxB,EAAO,CAEd,MAAMA,CACR,CACF,CAUA,MAAc,oBACZgB,EACAjB,EACAuB,EACAC,EACe,CACf,GAAI,CACF,MAAM,KAAK,gBACTP,EACAjB,EACAuB,EACAC,CACF,CACF,MAAgB,CACd,IAAME,EAASF,EAAY,2BAAS,sCAOtC,CACF,CAQA,MAAc,yBACZP,EACAQ,EACe,CACf,GAAI,CACF,MAAMhC,EAAc,6BAA6BwB,EAAU,EAAI,CAEjE,OAAShB,EAAO,CAKd,MAAMA,CACR,CACF,CAQA,MAAc,gCACZgB,EACAQ,EACe,CACf,GAAI,CACF,MAAMhC,EAAc,6BAA6BwB,EAAU,EAAK,CAIlE,OAAShB,EAAO,CAKd,MAAMA,CACR,CACF,CASA,MAAc,yBACZD,EACAiB,EACAQ,EACe,CACf,GAAI,CACF,MAAMhC,EAAc,iCAClBO,EACAiB,EACAQ,EACA,EACF,CAIF,OAASxB,EAAO,CAKd,MAAMA,CACR,CACF,CASA,MAAc,gCACZD,EACAiB,EACAQ,EACe,CACf,GAAI,CACF,MAAMhC,EAAc,iCAClBO,EACAiB,EACAQ,EACA,EACF,CAIF,OAASxB,EAAO,CAKd,MAAMA,CACR,CACF,CAQA,MAAc,YACZgB,EACAV,EACAY,EACyB,CACzB,GAAM,CAAE,YAAAnB,EAAa,SAAUuB,CAAiB,EAAIhB,EAM9CC,EAAU,KAAK,SAAS,IAAIR,CAAW,EAC7C,GAAI,CAACQ,EACH,MAAM,IAAI,MAAM,gBAAMR,CAAW,qBAAM,EAGzC,GAAI,CAACQ,EAAQ,YAAY,EACvB,MAAM,IAAI,MAAM,gBAAMR,CAAW,qBAAM,EAGzC,GAAI,CAGF,OAFe,MAAMQ,EAAQ,SAASe,EAAkBJ,GAAc,CAAC,CAAC,CAG1E,OAASlB,EAAO,CAKd,MAAMA,CACR,CACF,CAKA,QAAQgB,EAA2B,CAEjC,OAAI,KAAK,iBAAiB,QAAQA,CAAQ,EACjC,GAIF,KAAK,MAAM,IAAIA,CAAQ,CAChC,CAKA,MAAM,iBAAiC,CAIrC,KAAK,sBAAsB,EAG3B,OAAW,CAACjB,EAAaQ,CAAO,IAAK,KAAK,SACxC,GAAI,CACF,MAAMA,EAAQ,WAAW,CAE3B,MAAgB,CAKhB,CAIF,GAAI,CACF,KAAK,iBAAiB,QAAQ,CAEhC,MAAgB,CAEhB,CAGA,GAAI,CACFf,EAAc,yBAAyB,CAEzC,MAAgB,CAEhB,CAEA,KAAK,SAAS,MAAM,EACpB,KAAK,MAAM,MAAM,CAGnB,CAKA,WAAiC,CAC/B,OAAO,KAAK,iBAAiB,CAC/B,CAKA,oBAGE,CACA,GAAI,CACF,IAAMkC,EAAclC,EAAc,oBAAoB,EACtD,MAAO,CACL,YAAAkC,EACA,WAAYA,EAAY,MAC1B,CACF,MAAgB,CAEd,MAAO,CACL,YAAa,CAAC,EACd,WAAY,CACd,CACF,CACF,CAKA,WAAWC,EAAsC,CAC/C,OAAO,KAAK,SAAS,IAAIA,CAAI,CAC/B,CAKA,sBAAiC,CAC/B,IAAMC,EAA8B,CAAC,EACrC,OAAW,CAAC7B,EAAaQ,CAAO,IAAK,KAAK,SACpCA,EAAQ,YAAY,GACtBqB,EAAkB,KAAK7B,CAAW,EAGtC,OAAO6B,CACT,CAKA,MAAc,yBAAyC,CACrD,GAAI,CAEF,KAAK,iBAAiB,WAAW,CAEnC,OAAS5B,EAAO,CAEd,MAAMA,CACR,CACF,CAKA,MAAM,+BAA+C,CACnD,OAAO,KAAK,wBAAwB,CACtC,CAKA,gBAA0C,CACxC,OAAO,IAAI,IAAI,KAAK,QAAQ,CAC9B,CAKA,qBAAwC,CACtC,OAAO,KAAK,gBACd,CAOA,iBAAiBgB,EAA2B,CAC1C,GAAI,CACF,OAAO,KAAK,iBAAiB,QAAQA,CAAQ,CAC/C,MAAgB,CAMd,MAAO,EACT,CACF,CAMA,mBAA4B,CAC1B,GAAI,CACF,OAAO,KAAK,iBAAiB,SAAS,CACxC,MAAgB,CAMd,MAAO,CAAC,CACV,CACF,CAMQ,oBAAoBV,EAAmC,CAC7D,OAAOA,EAAO,IAAMuB,GAAgBvB,EAAO,GAAG,EAAI,EACpD,CAMQ,qBACNwB,EACAC,EACM,CAIN,GAF2BD,EAAe,SAAS,cAOjD,OAIF,IAAME,EAAmBxC,EAAc,oBAAoB,EAE3D,GAAIwC,EAAkB,CAEpBD,EAAe,OAASC,EAIxB,MACF,CAGA,IAAMC,EAAaH,EAAe,KAAO,eACnC/B,EAAc+B,EAAe,MAAQ,eAE3C,MAAM,IAAI,MACR,4BAAkB/B,CAAW,yIAAgCkC,CAAU,6XACzE,CACF,CAMQ,qBAAqB3B,EAA4C,CACvE,IAAMyB,EAAiB,CAAE,GAAGzB,CAAO,EAEnC,GAAI,CAEF,OAAI,KAAK,oBAAoBA,CAAM,GACjC,KAAK,qBAAqBA,EAAQyB,CAAc,EAG3CA,CACT,OAAS/B,EAAO,CAEd,MAAMA,CACR,CACF,CAOA,iBACEkC,EACA5B,EACM,CACN,IAAI6B,EACApC,EAEJ,GAAI,OAAOmC,GAAiB,UAAY5B,EAEtCP,EAAcmC,EACdC,EAAc7B,UACL,OAAO4B,GAAiB,SAEjCnC,EAAcmC,EAAa,KAC3BC,EAAcD,MAEd,OAAM,IAAI,MAAM,wCAAwC,EAI1D,IAAMH,EAAiB,KAAK,qBAAqBI,CAAW,EAG5D,KAAK,QAAQpC,CAAW,EAAIgC,CAE9B,CAKA,oBAAoBJ,EAAcrB,EAAgC,CAEhE,IAAMyB,EAAiB,KAAK,qBAAqBzB,CAAM,EAGvD,KAAK,QAAQqB,CAAI,EAAII,CAEvB,CAKA,oBAAoBJ,EAAoB,CACtC,OAAO,KAAK,QAAQA,CAAI,CAE1B,CAMA,MAAc,uBAAuC,CACnD,GAAI,CAIF,IAAMS,EAAuB5C,EAAc,mBAAmB,EAG9D,OAAW,CAACO,EAAaQ,CAAO,IAAK,KAAK,SAAU,CAClD,GAAI,CAACA,EAAQ,YAAY,EACvB,SAGF,IAAME,EAAQF,EAAQ,SAAS,EAC/B,GAAIE,EAAM,SAAW,EACnB,SAIF,IAAM4B,EACJD,EAAqBrC,CAAW,GAAG,OAAS,CAAC,EAGzCuC,EAAgD,CAAC,EAEvD,QAAW5B,KAAQD,EAAO,CACxB,IAAM8B,EAAoBF,EAAmB3B,EAAK,IAAI,EAGlD6B,EACFD,EAAe5B,EAAK,IAAI,EAAI,CAC1B,GAAG6B,EACH,YACE7B,EAAK,aAAe6B,EAAkB,aAAe,EACzD,EAGAD,EAAe5B,EAAK,IAAI,EAAI,CAC1B,YAAaA,EAAK,aAAe,GACjC,OAAQ,EACV,CAEJ,CAGA,IAAM8B,EAAmB/B,EAAM,IAAKgC,GAAMA,EAAE,IAAI,EAE1CC,EADkB,OAAO,KAAKL,CAAkB,EACjB,OAClCV,GAAS,CAACa,EAAiB,SAASb,CAAI,CAC3C,EAgBA,GAdIe,EAAa,OAAS,EASP,KAAK,sBACtBL,EACAC,CACF,EAEgB,CAEd9C,EAAc,wBAAwBO,EAAauC,CAAc,EAEjE,IAAMK,EAAa,OAAO,KAAKL,CAAc,EAAE,OAC5CX,GAAS,CAACU,EAAmBV,CAAI,CACpC,EACMiB,EAAe,OAAO,KAAKN,CAAc,EAAE,OAAQX,GAAS,CAChE,IAAMkB,EAAUR,EAAmBV,CAAI,EACjCmB,GAAUR,EAAeX,CAAI,EACnC,OAAOkB,GAAWA,EAAQ,cAAgBC,GAAQ,WACpD,CAAC,EAGGH,EAAW,OAAS,EAGpBC,EAAa,OAAS,EAGtBF,EAAa,OAAS,CAG5B,CACF,CAGF,MAAgB,CAGhB,CACF,CAKQ,sBACNK,EACAC,EACS,CACT,IAAMC,EAAc,OAAO,KAAKF,CAAa,EACvCG,EAAU,OAAO,KAAKF,CAAS,EAGrC,GAAIC,EAAY,SAAWC,EAAQ,OACjC,MAAO,GAIT,IAAMP,EAAaO,EAAQ,OAAQC,GAAQ,CAACF,EAAY,SAASE,CAAG,CAAC,EAC/DT,EAAeO,EAAY,OAAQE,GAAQ,CAACD,EAAQ,SAASC,CAAG,CAAC,EAEvE,GAAIR,EAAW,OAAS,GAAKD,EAAa,OAAS,EACjD,MAAO,GAIT,QAAW1B,KAAYiC,EAAa,CAClC,IAAMG,EAAcL,EAAc/B,CAAQ,EACpCqC,EAAUL,EAAUhC,CAAQ,EAElC,GAAIoC,EAAY,cAAgBC,EAAQ,YACtC,MAAO,EAEX,CAEA,MAAO,EACT,CAMQ,4BAA4BjD,EAAgC,CAClE,GAAIA,EAAe,SAAW,EAAG,OAMjC,IAAMkD,EAAe,IAErB,QAAWvD,KAAeK,EACxB,KAAK,eAAe,IAAIL,CAAW,EACnC,KAAK,qBAAqBA,EAAauD,CAAY,CAEvD,CAOQ,qBAAqBvD,EAAqBwD,EAAqB,CAErE,IAAMC,EAAgB,KAAK,YAAY,IAAIzD,CAAW,EAClDyD,IACF,aAAaA,CAAa,EAC1B,KAAK,YAAY,OAAOzD,CAAW,GAKrC,IAAM0D,EAAQ,WAAW,SAAY,CACnC,KAAK,YAAY,OAAO1D,CAAW,EACnC,MAAM,KAAK,mBAAmBA,CAAW,CAC3C,EAAGwD,CAAK,EAER,KAAK,YAAY,IAAIxD,EAAa0D,CAAK,CACzC,CAMA,MAAc,mBAAmB1D,EAAoC,CACnE,GAAK,KAAK,eAAe,IAAIA,CAAW,EAIxC,GAAI,CACF,MAAM,KAAK,aAAaA,CAAW,EAGnC,KAAK,eAAe,OAAOA,CAAW,EAItC,GAAI,CACF,MAAM,KAAK,8BAA8B,CAC3C,MAAgB,CAEhB,CACF,MAAgB,CAOd,IAAM2D,EAAe,KAAK,cAAc3D,CAAW,EAC7C4D,EAAY,KAAK,IAAID,EAAe,EAAG,GAAM,EAMnD,KAAK,qBAAqB3D,EAAa4D,CAAS,CAClD,CACF,CAOQ,cAAc5D,EAA6B,CAMjD,MAAO,KAHMA,EACV,MAAM,EAAE,EACR,OAAO,CAAC6D,EAAKC,IAASD,EAAMC,EAAK,WAAW,CAAC,EAAG,CAAC,EAC7B,GACzB,CAMO,iBAAiB9D,EAA2B,CACjD,IAAM0D,EAAQ,KAAK,YAAY,IAAI1D,CAAW,EAC1C0D,IACF,aAAaA,CAAK,EAClB,KAAK,YAAY,OAAO1D,CAAW,GAGrC,KAAK,eAAe,OAAOA,CAAW,CACxC,CAKO,uBAA8B,CAGnC,OAAW,CAACA,EAAa0D,CAAK,IAAK,KAAK,YACtC,aAAaA,CAAK,EAIpB,KAAK,YAAY,MAAM,EACvB,KAAK,eAAe,MAAM,CAC5B,CAMO,mBAA8B,CACnC,OAAO,MAAM,KAAK,KAAK,cAAc,CACvC,CAOO,gBAAgB1D,EAA8B,CACnD,OAAO,KAAK,eAAe,IAAIA,CAAW,CAC5C,CAMO,eAKL,CACA,MAAO,CACL,eAAgB,MAAM,KAAK,KAAK,cAAc,EAC9C,cAAe,MAAM,KAAK,KAAK,YAAY,KAAK,CAAC,EACjD,YAAa,KAAK,eAAe,KACjC,mBAAoB,KAAK,YAAY,IACvC,CACF,CASA,MAAa,kBACX4B,EACAmC,EACe,CACf,GAAI,KAAK,kBAAkB,IAAInC,CAAI,EACjC,MAAM,IAAI,MAAM,kCAASA,CAAI,qBAAM,EAKrC,GAAI,CACF,MAAMmC,EAAQ,WAAW,EACzB,KAAK,kBAAkB,IAAInC,EAAMmC,CAAO,EAGxC,KAAK,KAAK,sBAAuB,CAAE,KAAAnC,EAAM,QAAAmC,CAAQ,CAAC,CACpD,OAAS9D,EAAO,CAEd,MAAMA,CACR,CACF,CAWA,MAAa,iBAAiC,CAG5C,IAAM+D,EAA+B,CAAC,EAChCC,EAA2B,CAAC,EAElC,OAAW,CAACrC,EAAMmC,CAAO,IAAK,KAAK,kBACjC,GAAI,CACF,MAAMA,EAAQ,MAAM,EACpBC,EAAmB,KAAKpC,CAAI,CAE9B,MAAgB,CACdqC,EAAe,KAAKrC,CAAI,CAG1B,CAIF,GAAIoC,EAAmB,SAAW,GAAKC,EAAe,OAAS,EAAG,CAEhE,IAAMC,EAAe,iHAAuBD,EAAe,KACzD,IACF,CAAC,GAED,MAAM,IAAI,MAAMC,CAAY,CAC9B,CAEID,EAAe,OAAS,CAa9B,CAKA,MAAa,gBAAgC,CAG3C,GAAI,CACF,OAAW,CAACrC,EAAMmC,CAAO,IAAK,KAAK,kBACjC,GAAI,CACF,MAAMA,EAAQ,KAAK,CAErB,MAAgB,CAEhB,CAEJ,OAAS9D,EAAO,CAEd,MAAMA,CACR,CACF,CAMO,sBAAsD,CAC3D,OAAO,IAAI,IAAI,KAAK,iBAAiB,CACvC,CAMO,mBAAuC,CAC5C,OAAO,KAAK,cACd,CAKA,MAAa,OAAuB,CAClC,GAAI,KAAK,UACP,MAAM,IAAI,MAAM,4CAAS,EAK3B,GAAI,CACF,MAAM,KAAK,iBAAiB,EAC5B,MAAM,KAAK,gBAAgB,EAC3B,KAAK,UAAY,GAGjB,KAAK,KAAK,SAAS,CACrB,OAASA,EAAO,CAEd,MAAMA,CACR,CACF,CAKA,MAAa,MAAsB,CACjC,GAAK,KAAK,UAMV,GAAI,CACF,MAAM,KAAK,eAAe,EAC1B,MAAM,KAAK,gBAAgB,EAC3B,KAAK,UAAY,GAGjB,KAAK,KAAK,SAAS,CACrB,OAASA,EAAO,CAEd,MAAMA,CACR,CACF,CAMO,mBAIJ,CACD,IAAMkE,EAID,CAAC,EAGN,OAAW,CAACnE,EAAaQ,CAAO,IAAK,KAAK,SACpCA,EAAQ,YAAY,GACtB2D,EAAY,KAAK,CACf,GAAI,WAAWnE,CAAW,GAC1B,KAAMA,EACN,iBACF,CAAC,EAKL,OAAW,CAACoE,EAAaL,CAAO,IAAK,KAAK,kBACxCI,EAAY,KAAK,CACf,GAAIJ,EAAQ,gBAAgB,EAC5B,KAAMK,EACN,MAAOL,EAAQ,SAAS,CAC1B,CAAC,EAGH,OAAOI,CACT,CAMO,0BAAmC,CACxC,OAAO,KAAK,kBAAkB,EAAE,OAC7BE,GAASA,EAAK,QAAU,WAC3B,EAAE,MACJ,CAOA,kBAAwC,CACtC,IAAMC,EAAgB,KAAK,wBAAwB,EACnD,MAAO,CACL,UAAW,KAAK,UAChB,cAAAA,EACA,eAAgB,KAAK,qBAAqB,EAAE,KAC5C,kBAAmB,KAAK,yBAAyB,EACjD,OAAQ,KAAK,OAEb,SAAUA,EAAc,SACxB,WAAYA,EAAc,WAC1B,eAAgBA,EAAc,cAChC,CACF,CAKA,yBAAyC,CAEvC,IAAIC,EAAqB,EACrBC,EAA4B,CAAC,EAEjC,GAAI,CACFD,EAAqB,KAAK,iBAAiB,aAAa,EACxDC,EAAkB,KAAK,iBAAiB,aAAa,CAIvD,MAAgB,CAMdD,EAAqB,EACrBC,EAAkB,CAAC,CACrB,CAEA,IAAMC,EAAa,KAAK,MAAM,KAAOF,EAI/BG,EAAiB,CAAC,GADE,MAAM,KAAK,KAAK,MAAM,KAAK,CAAC,EACR,GAAGF,CAAe,EAE1DG,EAAwB,CAC5B,SAAU,CAAC,EACX,WAAAF,EACA,eAAAC,CACF,EAGA,OAAW,CAAC1E,EAAaQ,CAAO,IAAK,KAAK,SAAU,CAClD,IAAM8D,EAAgB9D,EAAQ,UAAU,EACxCmE,EAAO,SAAS3E,CAAW,EAAI,CAC7B,UAAWsE,EAAc,UACzB,WAAY,WAAWtE,CAAW,SACpC,CACF,CAGA,OAAIuE,EAAqB,IACvBI,EAAO,SAAS,UAAY,CAC1B,UAAW,GACX,WAAY,2BACd,GAGKA,CACT,CAKA,iBAA2B,CACzB,OAAO,KAAK,SACd,CAKQ,sBACNvF,EACgC,CAChC,OACEA,IAAY,MAAQ,OAAOA,GAAY,UAAY,YAAaA,CAEpE,CAKA,MAAM,aAAawF,EAAiD,CAClE,IAAMC,EAAW,MAAM,KAAK,eAAe,cAAcD,CAAO,EAEhE,OAAIC,IAAa,KACR,KAGF,CACL,QAAS,MACT,OAAQ,WACR,OAAQA,EACR,GAAIA,EAAS,EACf,CACF,CAWA,MAAM,YAA4B,CAGhC,MAAM,KAAK,MAAM,CACnB,CAKA,iBAAqC,CACnC,OAAO,IACT,CAKA,sBAA0C,CACxC,OAAO,IACT,CACF,ICr2DA,OAAS,sBAAAC,OAA0B,0CACnC,OAAS,wBAAAC,OAA4B,4CAErC,OAAS,iCAAAC,OAAqC,qDAC9C,OAAS,eAAAC,OAAmB,cAuBrB,SAASC,GAAgBC,EAA8C,CAK5E,OAAQA,EAAO,KAAM,CACnB,YACE,OAAOC,GAAqBD,CAAM,EAEpC,UACE,OAAOE,GAAmBF,CAAM,EAElC,sBACE,OAAOG,GAA8BH,CAAM,EAE7C,QACE,MAAM,IAAI,MAAM,qDAAaA,EAAO,IAAI,EAAE,CAC9C,CACF,CAKA,SAASC,GAAqBD,EAAgD,CAC5E,GAAI,CAACA,EAAO,QACV,MAAM,IAAI,MAAM,mDAA+B,EAGjD,OAAO,IAAIJ,GAAqB,CAC9B,QAASI,EAAO,QAChB,KAAMA,EAAO,MAAQ,CAAC,EACtB,IAAKA,EAAO,GACd,CAAC,CACH,CAKA,SAASE,GAAmBF,EAA8C,CACxE,GAAI,CAACA,EAAO,IACV,MAAM,IAAI,MAAM,6CAAyB,EAG3C,IAAMI,EAAM,IAAI,IAAIJ,EAAO,GAAG,EACxBK,EAAUC,GAAiBN,CAAM,EAEvC,OAAO,IAAIL,GAAmBS,EAAKC,CAAO,CAC5C,CAsBA,SAASF,GACPH,EAC+B,CAC/B,GAAI,CAACA,EAAO,IACV,MAAM,IAAI,MAAM,wDAAoC,EAGtD,IAAMI,EAAM,IAAI,IAAIJ,EAAO,GAAG,EACxBK,EAAUE,GAA4BP,CAAM,EAClD,OAAO,IAAIH,GAA8BO,EAAKC,CAAO,CACvD,CAKA,SAASC,GAAiBN,EAAqD,CAC7E,IAAMK,EAAqC,CAAC,EAG5C,OAAIL,EAAO,OACTK,EAAQ,YAAc,CACpB,QAAS,CACP,cAAe,UAAUL,EAAO,MAAM,GACtC,GAAGA,EAAO,OACZ,CACF,EACSA,EAAO,UAChBK,EAAQ,YAAc,CACpB,QAASL,EAAO,OAClB,GAGKK,CACT,CA0CA,SAASE,GACPP,EACsC,CACtC,IAAMK,EAAgD,CAAC,EAGvD,OAAIL,EAAO,OACTK,EAAQ,YAAc,CACpB,QAAS,CACP,cAAe,UAAUL,EAAO,MAAM,GACtC,GAAGA,EAAO,OACZ,CACF,EACSA,EAAO,UAChBK,EAAQ,YAAc,CACpB,QAASL,EAAO,OAClB,GAGKK,CACT,CAKO,SAASG,GAAeR,EAAgC,CAC7D,GAAI,CAACA,EAAO,MAAQ,OAAOA,EAAO,MAAS,SACzC,MAAM,IAAI,MAAM,0EAAmB,EAKrC,GAAIA,EAAO,MAAQ,CAAC,OAAO,OAAOS,EAAgB,EAAE,SAAST,EAAO,IAAI,EACtE,MAAM,IAAI,MAAM,qDAAaA,EAAO,IAAI,EAAE,EAK5C,GAAI,CAACA,EAAO,KACV,MAAM,IAAI,MAAM,gHAAqC,EAGvD,OAAQA,EAAO,KAAM,CACnB,YACE,GAAI,CAACA,EAAO,QACV,MAAM,IAAI,MAAM,qDAAuB,EAEzC,MAEF,UACE,GAAIA,EAAO,MAAQ,QAAaA,EAAO,MAAQ,KAC7C,MAAM,IAAI,MAAM,GAAGA,EAAO,IAAI,4CAAc,EAE9C,MACF,sBAEE,GAAIA,EAAO,MAAQ,QAAaA,EAAO,MAAQ,KAC7C,MAAM,IAAI,MAAM,GAAGA,EAAO,IAAI,4CAAc,EAE9C,MAEF,QACE,MAAM,IAAI,MAAM,qDAAaA,EAAO,IAAI,EAAE,CAC9C,CACF,CAKO,SAASU,IAAwC,CACtD,MAAO,gCAIP,CACF,CAzPA,IA8PaC,GA9PbC,GAAAC,EAAA,kBACAC,KAWE,OAAO,OAAW,KAClB,CAAE,OAAqD,cAEtD,OAA+D,YAC9DhB,IAcYiB,EAAAhB,GAAA,mBAuBPgB,EAAAd,GAAA,wBAeAc,EAAAb,GAAA,sBA+BAa,EAAAZ,GAAA,iCAeAY,EAAAT,GAAA,oBA4DAS,EAAAR,GAAA,+BAyBOQ,EAAAP,GAAA,kBA4CAO,EAAAL,GAAA,qBAWHC,GAAmB,CAC9B,OAAQZ,GACR,eAAAS,GACA,kBAAAE,EACF,IClQA,OAAS,UAAAM,OAAc,4CAAvB,IAiBaC,GAjBbC,GAAAC,EAAA,kBAEAC,IACAC,KAOAC,KACAC,KAMaN,GAAN,KAAiB,CAjBxB,MAiBwB,CAAAO,EAAA,mBACd,OACA,OAAwB,KACxB,UAAuC,KACvC,MAA2B,IAAI,IAC/B,+BACA,kBAA2C,KAC3C,YAAc,GACd,SAAWC,EAAY,EAE/B,YAAYC,EAA0B,CAEpC,KAAK,OAASC,GAA6BD,CAAM,EAGjD,KAAK,eAAe,CACtB,CAKQ,gBAAuB,CAE7BE,GAAiB,eAAe,KAAK,MAAM,CAC7C,CAKA,MAAM,SAAyB,CAE7B,GAAI,KAAK,kBAAoB,aAC3B,MAAM,IAAI,MAAM,4FAAiB,EAInC,YAAK,kBAAkB,EAEhB,KAAK,kBAAkB,CAChC,CAKA,MAAc,mBAAmC,CAC/C,YAAK,gBAAkB,aAKhB,IAAI,QAAQ,CAACC,EAASC,IAAW,CAEtC,KAAK,kBAAoB,WAAW,IAAM,CACxC,IAAMC,EAAQ,IAAI,MAAM,6BAAS,KAAK,OAAO,SAAW,GAAK,KAAK,EAClE,KAAK,sBAAsBA,CAAK,EAChCD,EAAOC,CAAK,CACd,EAAG,KAAK,OAAO,SAAW,GAAK,EAE/B,GAAI,CACF,KAAK,OAAS,IAAIf,GAChB,CACE,KAAM,WAAW,KAAK,OAAO,IAAI,UACjC,QAAS,OACX,EACA,CACE,aAAc,CAAC,CACjB,CACF,EAGA,KAAK,UAAYY,GAAiB,OAAO,KAAK,MAAM,EAGpD,KAAK,OACF,QAAQ,KAAK,SAA+B,EAC5C,KAAK,SAAY,CAChB,KAAK,wBAAwB,EAG7B,MAAM,KAAK,aAAa,EAGxB,KAAK,SAAS,UAAU,wBAAyB,CAC/C,YAAa,KAAK,OAAO,KACzB,MAAO,KAAK,SAAS,EACrB,eAAgB,IAAI,IACtB,CAAC,EAEDC,EAAQ,CACV,CAAC,EACA,MAAOE,GAAU,CAChB,KAAK,sBAAsBA,CAAK,EAChCD,EAAOC,CAAK,CACd,CAAC,CACL,OAASA,EAAO,CACd,KAAK,sBAAsBA,CAAc,EACzCD,EAAOC,CAAK,CACd,CACF,CAAC,CACH,CAKQ,yBAAgC,CAElC,KAAK,oBACP,aAAa,KAAK,iBAAiB,EACnC,KAAK,kBAAoB,MAG3B,KAAK,gBAAkB,YACvB,KAAK,YAAc,EAKrB,CAKQ,sBAAsBA,EAAoB,CAChD,KAAK,gBAAkB,eACvB,KAAK,YAAc,GAKf,KAAK,oBACP,aAAa,KAAK,iBAAiB,EACnC,KAAK,kBAAoB,MAI3B,KAAK,kBAAkB,EAGvB,KAAK,SAAS,UAAU,gCAAiC,CACvD,YAAa,KAAK,OAAO,KACzB,MAAAA,EACA,QAAS,CACX,CAAC,CACH,CAKQ,mBAA0B,CAEhC,GAAI,KAAK,OAAQ,CACf,GAAI,CACF,KAAK,OAAO,MAAM,EAAE,MAAM,IAAM,CAEhC,CAAC,CACH,MAAgB,CAEhB,CACA,KAAK,OAAS,IAChB,CAGA,KAAK,UAAY,KAGb,KAAK,oBACP,aAAa,KAAK,iBAAiB,EACnC,KAAK,kBAAoB,MAI3B,KAAK,YAAc,EACrB,CAKA,MAAc,cAA8B,CAC1C,GAAI,CAAC,KAAK,OACR,MAAM,IAAI,MAAM,4CAAS,EAG3B,GAAI,CAEF,IAAMC,GADc,MAAM,KAAK,OAAO,UAAU,GACd,OAAS,CAAC,EAG5C,KAAK,MAAM,MAAM,EAGjB,QAAWC,KAAQD,EACjB,KAAK,MAAM,IAAIC,EAAK,KAAMA,CAAI,CAQlC,OAASF,EAAO,CAKd,MAAMA,CACR,CACF,CAKA,MAAM,YAA4B,CAIhC,KAAK,kBAAkB,EAGvB,KAAK,gBAAkB,eAGvB,KAAK,SAAS,UAAU,2BAA4B,CAClD,YAAa,KAAK,OAAO,KACzB,OAAQ,2BACR,kBAAmB,IAAI,IACzB,CAAC,CACH,CAKA,UAAmB,CACjB,OAAO,MAAM,KAAK,KAAK,MAAM,OAAO,CAAC,CACvC,CAKA,MAAM,SACJG,EACAC,EACyB,CACzB,GAAI,CAAC,KAAK,OACR,MAAM,IAAI,MAAM,gBAAM,KAAK,OAAO,IAAI,qBAAM,EAG9C,GAAI,CAAC,KAAK,MAAM,IAAID,CAAI,EACtB,MAAM,IAAI,MAAM,gBAAMA,CAAI,uBAAQ,KAAK,OAAO,IAAI,2BAAO,EAQ3D,GAAI,CAWF,OAVe,MAAM,KAAK,OAAO,SAAS,CACxC,KAAAA,EACA,UAAWC,GAAc,CAAC,CAC5B,CAAC,CAQH,OAASJ,EAAO,CAKd,MAAMA,CACR,CACF,CAKA,WAA8B,CAC5B,OAAO,KAAK,MACd,CAKA,WAA8B,CAC5B,MAAO,CACL,KAAM,KAAK,OAAO,KAClB,UAAW,KAAK,kBAAoB,YACpC,YAAa,KAAK,YAClB,cAAe,KAAK,OAAO,MAAQ,kBACnC,UAAW,KAAK,MAAM,KACtB,gBAAiB,KAAK,eACxB,CACF,CAKA,aAAuB,CACrB,OACE,KAAK,kBAAoB,aAA6B,KAAK,WAE/D,CACF,IClUA,IAAAK,GAAAC,EAAA,oBCSA,OAAS,QAAAC,OAAY,OATrB,IA8FaC,GA9FbC,GAAAC,EAAA,kBA8FaF,GAAYG,EAAA,IAChB,IAAIJ,GADY,eC9FzB,IAAAK,GAAAC,EAAA,kBAgBAC,KAUAC,KACAC,KACAC,OCtBA,OAAS,cAAAC,OAAkB,SAC3B,OACE,cAAAC,GACA,aAAAC,GACA,gBAAAC,GACA,cAAAC,GACA,iBAAAC,OACK,KACP,OAAS,WAAAC,GAAS,WAAAC,OAAe,OAajC,OAAOC,OAAW,QA3BlB,IAgEaC,GAhEbC,GAAAC,EAAA,kBAkBAC,IAQAC,KAsCaJ,GAAN,KAAsB,CAhE7B,MAgE6B,CAAAK,EAAA,wBACnB,UACA,OACS,cAAgB,QAChB,oBAAsB,QAC/B,gBACS,iBAAmB,IAEpC,YAAYC,EAA0B,CACpC,KAAK,OAASC,EACd,KAAK,UAAYD,GAAmB,KAAK,iBAAiB,EAC1D,KAAK,kBAAkB,CACzB,CAKQ,iBAA0B,CAChC,OAAOP,GAAM,EAAE,OAAO,qBAAqB,CAC7C,CAMQ,kBAA2B,CACjC,GAAI,CACF,IAAMS,EAAY,QAAQ,IAAI,oBAAsB,QAAQ,IAAI,EAChE,OAAOV,GAAQU,EAAW,oBAAoB,CAChD,MAAgB,CAEd,IAAMA,EAAY,QAAQ,IAAI,oBAAsB,OACpD,OAAOV,GAAQU,EAAW,oBAAoB,CAChD,CACF,CAKA,MAAM,iBAAiC,CACrC,GAAI,CACF,GAAI,CAAChB,GAAW,KAAK,SAAS,EAAG,CAE/B,IAAMiB,EAAWZ,GAAQ,KAAK,SAAS,EAClCL,GAAWiB,CAAQ,IACtBhB,GAAUgB,EAAU,CAAE,UAAW,EAAK,CAAC,EACvC,KAAK,OAAO,MAAM,8DAA2BA,CAAQ,EAAE,GAGzD,KAAK,OAAO,MAAM,iHAAiC,EACnD,IAAMC,EAAe,MAAM,KAAK,mBAAmB,EACnD,MAAM,KAAK,UAAUA,CAAY,EACjC,KAAK,OAAO,KAAK,8DAA2B,KAAK,SAAS,EAAE,CAC9D,CACF,OAASC,EAAO,CACd,KAAK,OAAO,KACV,oEAA4BA,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACpF,CAEF,CACF,CAKA,MAAc,oBAA6C,CACzD,IAAMC,EAAM,KAAK,gBAAgB,EACjC,MAAO,CACL,QAAS,KAAK,cACd,WAAY,CAAC,EACb,SAAU,CACR,iBAAkBA,EAClB,YAAa,EACb,UAAWA,CACb,CACF,CACF,CAQA,MAAM,gBACJC,EACAC,EACAC,EACe,CACf,GAAI,CACF,KAAK,OAAO,MAAM,wDAA0BF,CAAU,EAAE,EAGxD,MAAM,KAAK,gBAAgB,EAG3B,IAAMG,EAAQ,MAAM,KAAK,kBAAkB,EAGrCC,EAAa,KAAK,mBAAmBF,CAAM,EAG3CG,EAAiC,CACrC,MAAOJ,EAAM,IAAKK,IAAU,CAC1B,KAAMA,EAAK,KACX,YAAaA,EAAK,aAAe,GACjC,YAAaA,EAAK,WACpB,EAAE,EACF,YAAa,KAAK,gBAAgB,EAClC,aAAc,CAAE,GAAGJ,CAAO,EAC1B,WAAAE,EACA,QAAS,KAAK,mBAChB,EAGAD,EAAM,WAAWH,CAAU,EAAIK,EAC/BF,EAAM,SAAS,iBAAmB,KAAK,gBAAgB,EACvDA,EAAM,SAAS,aAAe,EAG9B,MAAM,KAAK,UAAUA,CAAK,EAE1B,KAAK,OAAO,MACV,wDAA0BH,CAAU,+BAAWC,EAAM,MAAM,EAC7D,CACF,OAASH,EAAO,CAEd,KAAK,OAAO,KACV,wDAA0BE,CAAU,mBAClCF,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CACvD,EACF,CACF,CACF,CAKA,MAAa,mBAA4C,CACvD,GAAI,CACF,GAAI,CAACnB,GAAW,KAAK,SAAS,EAC5B,OAAO,MAAM,KAAK,mBAAmB,EAGvC,IAAM4B,EAAY1B,GAAa,KAAK,UAAW,MAAM,EAC/CsB,EAAiB,KAAK,MAAMI,CAAS,EAG3C,OAAK,KAAK,uBAAuBJ,CAAK,EAK/BA,GAJL,KAAK,OAAO,KAAK,+FAA8B,EACxC,MAAM,KAAK,mBAAmB,EAIzC,OAASL,EAAO,CACd,YAAK,OAAO,KACV,4FACEA,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CACvD,EACF,EACO,MAAM,KAAK,mBAAmB,CACvC,CACF,CAKA,MAAa,UAAUK,EAAqC,CAC1D,IAAMK,EAAe,KAAK,UAAUL,EAAO,KAAM,CAAC,EAClD,MAAM,KAAK,YAAY,KAAK,UAAWK,CAAY,CACrD,CAMA,MAAc,YAAYC,EAAkBC,EAA6B,CACvE,IAAMC,EAAW,GAAGF,CAAQ,OAC5B,GAAI,CAEF1B,GAAc4B,EAAUD,EAAM,MAAM,EAEpC5B,GAAW6B,EAAUF,CAAQ,CAC/B,OAASX,EAAO,CAEd,GAAI,CACEnB,GAAWgC,CAAQ,GACrB5B,GAAc4B,EAAU,GAAI,MAAM,CAEtC,MAAQ,CAER,CACA,MAAMb,CACR,CACF,CAMQ,mBAAmBI,EAAkC,CAC3D,GAAI,CACF,OAAOxB,GAAW,QAAQ,EAAE,OAAO,KAAK,UAAUwB,CAAM,CAAC,EAAE,OAAO,KAAK,CACzE,OAASJ,EAAO,CACd,YAAK,OAAO,KACV,oEACEA,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CACvD,EACF,EACO,EACT,CACF,CAMQ,uBAAuBK,EAAwC,CACrE,GAAI,CACF,GAAI,CAACA,GAAS,OAAOA,GAAU,SAC7B,MAAO,GAGT,IAAMS,EAAWT,EACXU,EAAWD,EAAS,SAE1B,OACE,OAAOA,EAAS,SAAY,UAC5B,OAAOA,EAAS,YAAe,UAC/BA,EAAS,aAAe,MACxBA,EAAS,WAAa,MACtBA,EAAS,WAAa,QACtB,OAAOC,GAAa,UACpBA,IAAa,MACb,OAAOA,EAAS,kBAAqB,UACrC,OAAOA,EAAS,aAAgB,UAChC,OAAOA,EAAS,WAAc,QAElC,MAAQ,CACN,MAAO,EACT,CACF,CAKA,MAAM,UAAuC,CAC3C,GAAI,CACF,IAAMV,EAAQ,MAAM,KAAK,kBAAkB,EAS3C,MAR0B,CACxB,YAAaA,EAAM,SAAS,YAC5B,WAAYA,EAAM,SAAS,iBAC3B,YAAa,OAAO,KAAKA,EAAM,UAAU,EAAE,OAC3C,cAAexB,GAAW,KAAK,SAAS,EACpCE,GAAa,KAAK,UAAW,MAAM,EAAE,OACrC,CACN,CAEF,OAASiB,EAAO,CACd,YAAK,OAAO,KACV,oEACEA,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CACvD,EACF,EACO,IACT,CACF,CAKA,aAAsB,CACpB,OAAO,KAAK,SACd,CAMA,MAAM,mBAAqC,CACzC,GAAI,CACF,IAAMK,EAAQ,MAAM,KAAK,kBAAkB,EACrCW,EAAmB,CAAC,EAG1B,OAAW,CAACd,EAAYK,CAAU,IAAK,OAAO,QAAQF,EAAM,UAAU,EACpE,QAAWG,KAAQD,EAAW,MAE5BS,EAAS,KAAK,CACZ,GAAGR,EACH,KAAM,GAAGN,CAAU,KAAKM,EAAK,IAAI,EACnC,CAAC,EAIL,YAAK,OAAO,MACV,qFAA8BQ,EAAS,MAAM,SAC/C,EACOA,CACT,OAAShB,EAAO,CACd,YAAK,OAAO,KACV,gFACEA,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CACvD,EACF,EACO,CAAC,CACV,CACF,CAOA,MAAM,qBACJiB,EACAC,EACAC,EACAC,EAAqB,YACrBC,EACAC,EAAM,IACS,CACf,GAAI,CACF,IAAMjB,EAAQ,MAAM,KAAK,kBAAkB,EACrCkB,EAAWC,GAAiBP,EAAUC,CAAU,EAGhDX,EAAsC,CAC1C,OAAAY,EACA,UAAW,IAAI,KAAK,EAAE,YAAY,EAClC,IAAAG,EACA,OAAAF,EACA,SAAU,GACV,OAAAC,EACA,WAAY,CACd,EAGKhB,EAAM,mBACTA,EAAM,iBAAmB,CAAC,GAG5BA,EAAM,iBAAiBkB,CAAQ,EAAIhB,EACnC,MAAM,KAAK,kBAAkBF,CAAK,EAElC,KAAK,OAAO,MACV,iEAAmCY,CAAQ,mBAASG,CAAM,EAC5D,CACF,OAASpB,EAAO,CACd,KAAK,OAAO,KACV,6EACEA,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CACvD,EACF,CACF,CACF,CAKA,MAAM,oBACJiB,EACAC,EACyC,CACzC,GAAI,CACF,IAAMb,EAAQ,MAAM,KAAK,kBAAkB,EACrCkB,EAAWC,GAAiBP,EAAUC,CAAU,EAEtD,GAAI,CAACb,EAAM,kBAAoB,CAACA,EAAM,iBAAiBkB,CAAQ,EAC7D,OAAO,KAGT,IAAMhB,EAAaF,EAAM,iBAAiBkB,CAAQ,EAG5CtB,EAAM,KAAK,IAAI,EACfwB,EAAa,IAAI,KAAKlB,EAAW,SAAS,EAAE,QAAQ,EAC1D,OAAIN,EAAMwB,EAAalB,EAAW,KAChC,KAAK,OAAO,MAAM,kDAAyBU,CAAQ,EAAE,EAC9C,MAGFV,CACT,OAASP,EAAO,CACd,YAAK,OAAO,KACV,6EACEA,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CACvD,EACF,EACO,IACT,CACF,CAKA,MAAM,sBACJiB,EACAC,EACAQ,EACAP,EACAnB,EACkB,CAClB,GAAI,CACF,IAAMK,EAAQ,MAAM,KAAK,kBAAkB,EACrCkB,EAAWC,GAAiBP,EAAUC,CAAU,EAEtD,GAAI,CAACb,EAAM,kBAAoB,CAACA,EAAM,iBAAiBkB,CAAQ,EAC7D,MAAO,GAGT,IAAMhB,EAAaF,EAAM,iBAAiBkB,CAAQ,EAC5CI,EAAYpB,EAAW,OAG7B,OAAAA,EAAW,OAASmB,EACpBnB,EAAW,UAAY,IAAI,KAAK,EAAE,YAAY,EAG1CY,IACFZ,EAAW,OAASY,GAGlBnB,GAAS0B,IAAc,WACzBnB,EAAW,OAAS,CAClB,QAAS,CAAC,CAAE,KAAM,OAAQ,KAAM,6BAASP,CAAK,EAAG,CAAC,CACpD,EACAO,EAAW,SAAW,IAIpBmB,IAAc,cAChBnB,EAAW,SAAW,IAGxB,MAAM,KAAK,kBAAkBF,CAAK,EAElC,KAAK,OAAO,MACV,wDAA0BY,CAAQ,IAAIU,CAAS,OAAOD,CAAS,EACjE,EACO,EACT,OAAS1B,EAAO,CACd,YAAK,OAAO,KACV,6EACEA,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CACvD,EACF,EACO,EACT,CACF,CAKA,MAAM,wBACJiB,EACAC,EACkB,CAClB,GAAI,CACF,IAAMb,EAAQ,MAAM,KAAK,kBAAkB,EACrCkB,EAAWC,GAAiBP,EAAUC,CAAU,EAEtD,GAAI,CAACb,EAAM,kBAAoB,CAACA,EAAM,iBAAiBkB,CAAQ,EAC7D,MAAO,GAGT,IAAMhB,EAAaF,EAAM,iBAAiBkB,CAAQ,EAClD,OAAIhB,EAAW,WAIfA,EAAW,SAAW,GACtBA,EAAW,UAAY,IAAI,KAAK,EAAE,YAAY,EAE9C,MAAM,KAAK,kBAAkBF,CAAK,EAElC,KAAK,OAAO,MAAM,oEAA4BY,CAAQ,EAAE,GACjD,EACT,OAASjB,EAAO,CACd,YAAK,OAAO,KACV,yFACEA,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CACvD,EACF,EACO,EACT,CACF,CAKA,MAAM,sBACJiB,EACAC,EACkB,CAClB,GAAI,CACF,IAAMb,EAAQ,MAAM,KAAK,kBAAkB,EACrCkB,EAAWC,GAAiBP,EAAUC,CAAU,EAEtD,MAAI,CAACb,EAAM,kBAAoB,CAACA,EAAM,iBAAiBkB,CAAQ,EACtD,IAGT,OAAOlB,EAAM,iBAAiBkB,CAAQ,EACtC,MAAM,KAAK,kBAAkBlB,CAAK,EAElC,KAAK,OAAO,MAAM,wDAA0BY,CAAQ,EAAE,EAC/C,GACT,OAASjB,EAAO,CACd,YAAK,OAAO,KACV,6EACEA,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CACvD,EACF,EACO,EACT,CACF,CAKA,MAAM,yBAAuE,CAC3E,GAAI,CACF,IAAMK,EAAQ,MAAM,KAAK,kBAAkB,EAE3C,GAAI,CAACA,EAAM,iBACT,MAAO,CAAE,QAAS,EAAG,MAAO,CAAE,EAGhC,IAAMuB,EAAU,OAAO,QAAQvB,EAAM,gBAAgB,EACjDwB,EAAe,EAEnB,OAAW,CAACN,EAAUhB,CAAU,IAAKqB,EAC/BE,GAAmBvB,CAAU,IAC/B,OAAOF,EAAM,iBAAiBkB,CAAQ,EACtCM,KAIJ,OAAIA,EAAe,IACjB,MAAM,KAAK,kBAAkBxB,CAAK,EAClC,KAAK,OAAO,KACV,qDAAiCwB,CAAY,IAAID,EAAQ,MAAM,EACjE,GAGK,CAAE,QAASC,EAAc,MAAOD,EAAQ,MAAO,CACxD,OAAS5B,EAAO,CACd,YAAK,OAAO,KACV,iEACEA,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CACvD,EACF,EACO,CAAE,QAAS,EAAG,MAAO,CAAE,CAChC,CACF,CAKA,MAAM,wBAAmD,CACvD,GAAI,CACF,IAAMK,EAAQ,MAAM,KAAK,kBAAkB,EAE3C,GAAI,CAACA,EAAM,iBACT,MAAO,CACL,aAAc,EACd,aAAc,EACd,eAAgB,EAChB,YAAa,EACb,gBAAiB,EACjB,aAAc,EACd,gBAAiB,IAAI,KAAK,EAAE,YAAY,EACxC,YAAa,CACf,EAGF,IAAMuB,EAAU,OAAO,OAAOvB,EAAM,gBAAgB,EAC9C0B,EAAeH,EAAQ,OACvBI,EAAeJ,EAAQ,OAAQK,GAAMA,EAAE,SAAW,SAAS,EAAE,OAC7DC,EAAiBN,EAAQ,OAC5BK,GAAMA,EAAE,SAAW,WACtB,EAAE,OACIE,EAAcP,EAAQ,OAAQK,GAAMA,EAAE,SAAW,QAAQ,EAAE,OAC3DG,EAAkBR,EAAQ,OAAQK,GAAMA,EAAE,QAAQ,EAAE,OAGpDI,EACJH,EAAiB,EAAKE,EAAkBF,EAAkB,IAAM,EAG5DI,EAAc,KAAK,UAAUjC,EAAM,gBAAgB,EAAE,OAE3D,MAAO,CACL,aAAA0B,EACA,aAAAC,EACA,eAAAE,EACA,YAAAC,EACA,gBAAAC,EACA,aAAAC,EACA,gBAAiB,IAAI,KAAK,EAAE,YAAY,EACxC,YAAAC,CACF,CACF,OAAStC,EAAO,CACd,YAAK,OAAO,KACV,6EACEA,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CACvD,EACF,EACO,CACL,aAAc,EACd,aAAc,EACd,eAAgB,EAChB,YAAa,EACb,gBAAiB,EACjB,aAAc,EACd,gBAAiB,IAAI,KAAK,EAAE,YAAY,EACxC,YAAa,CACf,CACF,CACF,CAKA,MAAM,mBAAoD,CACxD,GAAI,CAEF,OADc,MAAM,KAAK,kBAAkB,CAE7C,OAASA,EAAO,CACd,YAAK,OAAO,KACV,oEACEA,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CACvD,EACF,EACO,CACL,QAAS,KAAK,cACd,WAAY,CAAC,EACb,SAAU,CACR,iBAAkB,KAAK,gBAAgB,EACvC,YAAa,EACb,UAAW,KAAK,gBAAgB,CAClC,EACA,iBAAkB,CAAC,CACrB,CACF,CACF,CAKA,MAAM,kBAAkBK,EAA6C,CACnE,MAAM,KAAK,UAAUA,CAAK,CAC5B,CAKQ,mBAA0B,CAChC,KAAK,gBAAkB,YAAY,IAAM,CACvC,KAAK,wBAAwB,EAAE,MAAOL,GAAU,CAC9C,KAAK,OAAO,KAAK,wDAA0BA,CAAK,EAAE,CACpD,CAAC,CACH,EAAG,KAAK,gBAAgB,EAExB,KAAK,OAAO,MACV,gFAA8B,KAAK,gBAAgB,IACrD,CACF,CAKO,kBAAyB,CAC1B,KAAK,kBACP,cAAc,KAAK,eAAe,EAClC,KAAK,gBAAkB,OACvB,KAAK,OAAO,MAAM,2DAAwB,EAE9C,CAKO,SAAgB,CACrB,KAAK,iBAAiB,EACtB,KAAK,OAAO,MAAM,qDAAuB,CAC3C,CACF,IChvBA,IAAAuC,GAAAC,EAAA,kBAAAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KAEAC,OCVA,IAOaC,GAPbC,GAAAC,EAAA,kBAAAC,IAOaH,GAAmBI,EAAA,MAAOC,EAAYC,IAAe,CAChED,EAAE,IAAI,SAAUE,CAAM,EACtB,MAAMD,EAAK,CACb,EAHgC,sBCPhC,OAAS,QAAAE,OAAY,YAArB,IAQaC,GARbC,GAAAC,EAAA,kBAQaF,GAAiBD,GAAK,CACjC,OAAQ,QAAQ,IAAI,gBAChB,QAAQ,IAAI,gBAAgB,MAAM,GAAG,EAAE,IAAKI,GAAWA,EAAO,KAAK,CAAC,EACpE,IACJ,aAAc,CAAC,MAAO,OAAQ,MAAO,SAAS,EAC9C,aAAc,CAAC,cAAc,CAC/B,CAAC,ICdD,IAsBaC,EAiBAC,GAcAC,GAqCAC,GA1FbC,GAAAC,EAAA,kBAAAC,IAsBaN,EAAsBO,EAAA,CACjCC,EACAC,EACAC,KAEO,CACL,MAAO,CACL,KAAAF,EACA,QAAAC,EACA,QAAAC,CACF,CACF,GAXiC,uBAiBtBT,GAAwBM,EAAA,CACnCI,EACAF,KAEO,CACL,QAAS,GACT,KAAAE,EACA,QAAAF,CACF,GARmC,yBAcxBP,GAAyBK,EAAA,CAACK,EAAYC,IAAe,CAEhE,IAAIC,EACJ,GAAI,CACF,IAAMC,EAAgBF,EAAE,IAAI,QAAQ,EAChCE,EACFD,EAAiBC,EAEjBD,EAAiBE,CAErB,MAAQ,CAENF,EAAiBE,CACnB,CAGI,QAAQ,IAAI,SAShBF,EAAe,MAAM,sBAAuBF,CAAG,EAC/C,IAAMK,EAAgBjB,EACpB,wBACA,6CACA,QAAQ,IAAI,WAAa,cAAgBY,EAAI,MAAQ,MACvD,EACA,OAAOC,EAAE,KAAKI,EAAe,GAAG,CAClC,EAhCsC,0BAqCzBd,GAA4BI,EAACM,GAAe,CAEvD,GAAIA,EAAE,IAAI,KAAK,WAAW,OAAO,EAAG,CAClC,IAAMI,EAAgBjB,EACpB,gBACA,mDACA,CACE,KAAMa,EAAE,IAAI,KACZ,OAAQA,EAAE,IAAI,MAChB,CACF,EACA,OAAOA,EAAE,KAAKI,EAAe,GAAG,CAClC,CAGA,IAAMA,EAAgBjB,EAAoB,YAAa,mDAAY,CACjE,KAAMa,EAAE,IAAI,KACZ,OAAQA,EAAE,IAAI,MAChB,CAAC,EACD,OAAOA,EAAE,KAAKI,EAAe,GAAG,CAClC,EApByC,+BC1FzC,IAOaC,GAUAC,GAjBbC,GAAAC,EAAA,kBAOaH,GAAN,cAAmD,KAAM,CAPhE,MAOgE,CAAAI,EAAA,6CAC9D,YAAYC,EAAiB,CAC3B,MAAMA,CAAO,EACb,KAAK,KAAO,sCACd,CACF,EAKaJ,GAAN,cAAyC,KAAM,CAjBtD,MAiBsD,CAAAG,EAAA,mCACpD,YAAYC,EAAiB,CAC3B,MAAMA,CAAO,EACb,KAAK,KAAO,4BACd,CACF,ICtBA,IA2BaC,GA3BbC,GAAAC,EAAA,kBAMAC,IAEAC,KAmBaJ,GAA8BK,EAAA,MACzCC,EACAC,IACkB,CAElB,GAAI,CAACD,EAAE,IAAI,mBAAmB,EAC5B,GAAI,CAEF,IAAME,EAAgBF,EAAE,IAAI,QAAQ,GAAKG,EAEzCD,EAAc,MACZ,0FACF,EAGA,IAAME,EAAYJ,EAAE,IAAI,WAAW,EACnC,GAAI,CAACI,EACH,MAAM,IAAIC,GAA2B,4CAAwB,EAG/D,IAAMC,EAAiBF,EAAU,qBAAqB,EAGtDJ,EAAE,IAAI,oBAAqBM,CAAc,EAEzCJ,EAAc,MACZ,4FACF,CACF,OAASK,EAAO,CAEd,IAAMC,EAAcR,EAAE,IAAI,QAAQ,GAAKG,EAGvC,GAAII,aAAiBE,GAEnBD,EAAY,MACV,gGACF,MAEK,OAAID,aAAiBF,IAE1BG,EAAY,MAAM,sDAAmCD,EAAM,OAAO,EAC5DA,IAGNC,EAAY,MACV,6FACAD,CACF,EACMA,EAEV,CAGF,MAAMN,EAAK,CACb,EAvD2C,iCC3B3C,IAYaS,GAZbC,GAAAC,EAAA,kBAYaF,GAA4BG,EAAA,IAChC,MAAOC,EAAGC,IAAS,CAExB,IAAMC,EAAYF,EAAE,IAAI,WAAW,EACnC,GAAI,CAACE,EACH,MAAM,IAAI,MACR,mJACF,EAGF,GAAI,CAACA,EAAU,mBACb,MAAM,IAAI,MAAM,oEAAsC,EAGxD,GAAI,CACF,IAAMC,EAAoBD,EAAU,mBAAmB,EACvDF,EAAE,IAAI,kBAAmBG,CAAiB,CAC5C,OAASC,EAAO,CAEd,GAAIA,aAAiB,OAASA,EAAM,QAAQ,SAAS,0BAAM,EAEzDJ,EAAE,IAAI,kBAAmB,IAAI,MAE7B,OAAMI,CAEV,CAEA,MAAMH,EAAK,CACb,EA5BuC,+BCZzC,IA+DaI,GA/DbC,GAAAC,EAAA,kBAIAC,IAEAC,IAyDaJ,GAAN,KAA4B,CA/DnC,MA+DmC,CAAAK,EAAA,8BACzB,OACA,gBACA,cACA,SAER,YAAYC,EAAkCC,EAA8B,CAC1E,KAAK,OAASC,EACd,KAAK,gBAAkBF,EACvB,KAAK,cAAgBC,EACrB,KAAK,SAAWE,EAAY,CAC9B,CAKQ,oBACNC,EACAC,EACAC,EACAC,EACkB,CAClB,MAAO,CACL,MAAO,CACL,KAAAH,EACA,QAAAC,EACA,QAASC,EAAW,CAAE,SAAAA,EAAU,GAAGC,CAAQ,EAAIA,CACjD,CACF,CACF,CAKQ,sBACNC,EACAH,EACuB,CACvB,MAAO,CACL,QAAS,GACT,KAAAG,EACA,QAAAH,CACF,CACF,CAQA,MAAc,sBACZI,EACAC,EAGA,CACA,IAAIC,EACJ,GAAI,CACFA,EAAO,MAAMF,EAAE,IAAI,KAAK,CAC1B,OAASG,EAAO,CACd,KAAK,OAAO,MAAM,gCAAaA,CAAK,EACpC,IAAMC,EAAgB,KAAK,oBACzBH,EACAE,aAAiB,MAAQA,EAAM,QAAU,8BAC3C,EACA,MAAO,CAAE,GAAI,GAAO,SAAUH,EAAE,KAAKI,EAAe,GAAG,CAAE,CAC3D,CAEA,IAAMP,EAAWK,EAAK,SAGtB,GAAI,CAACL,GAAY,OAAOA,GAAa,SAAU,CAC7C,IAAMO,EAAgB,KAAK,oBACzB,mBACA,uCACAP,CACF,EACA,MAAO,CAAE,GAAI,GAAO,SAAUG,EAAE,KAAKI,EAAe,GAAG,CAAE,CAC3D,CAEA,MAAO,CAAE,GAAI,GAAM,SAAAP,CAAS,CAC9B,CAMA,MAAM,kBAAkBG,EAA+B,CACrD,IAAMK,EAAc,MAAM,KAAK,sBAC7BL,EACA,4BACF,EACA,GAAI,CAACK,EAAY,GACf,OAAOA,EAAY,SAGrB,IAAMR,EAAWQ,EAAY,SAC7B,KAAK,OAAO,MAAM,uEAAgBR,CAAQ,EAAE,EAC5C,GAAI,CAGF,IAAMS,EADmB,KAAK,gBAAgB,oBAAoB,EAC1B,KACrCC,GAAWA,EAAO,WAAaV,CAClC,EAEA,GAAI,CAACS,EAAgB,CACnB,IAAMF,EAAgB,KAAK,oBACzB,qBACA,iCACAP,CACF,EACA,OAAOG,EAAE,KAAKI,EAAe,GAAG,CAClC,CAEA,YAAK,OAAO,MAAM,2DAAcP,CAAQ,EAAE,EACnCG,EAAE,KAAK,KAAK,sBAAsBM,CAAc,CAAC,CAC1D,OAASH,EAAO,CACd,KAAK,OAAO,MAAM,0DAAcA,CAAK,EACrC,IAAMC,EAAgB,KAAK,oBACzB,6BACAD,aAAiB,MAAQA,EAAM,QAAU,yDACzCN,CACF,EACA,OAAOG,EAAE,KAAKI,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,gBAAgBJ,EAA+B,CACnD,IAAMK,EAAc,MAAM,KAAK,sBAC7BL,EACA,wBACF,EACA,GAAI,CAACK,EAAY,GACf,OAAOA,EAAY,SAGrB,IAAMR,EAAWQ,EAAY,SAC7B,KAAK,OAAO,KAAK,2DAAcR,CAAQ,EAAE,EACzC,GAAI,CAGF,IAAMW,EADmB,KAAK,gBAAgB,oBAAoB,EAC1B,KACrCD,GAAWA,EAAO,WAAaV,CAClC,EAEA,GAAI,CAACW,EAAgB,CACnB,IAAMJ,EAAgB,KAAK,oBACzB,qBACA,iFACAP,CACF,EACA,OAAOG,EAAE,KAAKI,EAAe,GAAG,CAClC,CAEA,GAAII,EAAe,UAAW,CAC5B,IAAMJ,EAAgB,KAAK,oBACzB,6BACA,iCACAP,CACF,EACA,OAAOG,EAAE,KAAKI,EAAe,GAAG,CAClC,CAGA,MAAM,KAAK,gBAAgB,wBAAwBP,CAAQ,EAK3D,IAAMS,EADJ,KAAK,gBAAgB,oBAAoB,EACI,KAC5CC,GAAWA,EAAO,WAAaV,CAClC,EAEA,GAAI,CAACS,EAAgB,CACnB,IAAMF,EAAgB,KAAK,oBACzB,4BACA,+DACAP,CACF,EACA,OAAOG,EAAE,KAAKI,EAAe,GAAG,CAClC,CAGA,KAAK,SAAS,UAAU,0BAA2B,CACjD,SAAAP,EACA,UAAW,GACX,UAAW,UACX,QAAS,GACT,QAAS,6CACT,UAAW,KAAK,IAAI,EACpB,OAAQ,UACV,CAAC,EAED,KAAK,OAAO,KAAK,+CAAYA,CAAQ,EAAE,EACvC,IAAMY,EAAW,KAAK,sBAAsBH,CAAc,EAC1D,OAAON,EAAE,KAAKS,CAAQ,CACxB,OAASN,EAAO,CACd,KAAK,OAAO,MAAM,8CAAYA,CAAK,EACnC,IAAMC,EAAgB,KAAK,oBACzB,yBACAD,aAAiB,MAAQA,EAAM,QAAU,6CACzCN,CACF,EACA,OAAOG,EAAE,KAAKI,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,mBAAmBJ,EAA+B,CACtD,IAAMK,EAAc,MAAM,KAAK,sBAC7BL,EACA,2BACF,EACA,GAAI,CAACK,EAAY,GACf,OAAOA,EAAY,SAGrB,IAAMR,EAAWQ,EAAY,SAC7B,KAAK,OAAO,KAAK,2DAAcR,CAAQ,EAAE,EACzC,GAAI,CAGF,IAAMW,EADmB,KAAK,gBAAgB,oBAAoB,EAC1B,KACrCD,GAAWA,EAAO,WAAaV,CAClC,EAEA,GAAI,CAACW,EAAgB,CACnB,IAAMJ,EAAgB,KAAK,oBACzB,qBACA,iCACAP,CACF,EACA,OAAOG,EAAE,KAAKI,EAAe,GAAG,CAClC,CAEA,GAAI,CAACI,EAAe,UAAW,CAC7B,IAAMJ,EAAgB,KAAK,oBACzB,yBACA,iCACAP,CACF,EACA,OAAOG,EAAE,KAAKI,EAAe,GAAG,CAClC,CAGA,MAAM,KAAK,gBAAgB,mBAAmBP,CAAQ,EAKtD,IAAMS,EADJ,KAAK,gBAAgB,oBAAoB,EACI,KAC5CC,GAAWA,EAAO,WAAaV,CAClC,EAGA,KAAK,SAAS,UAAU,0BAA2B,CACjD,SAAAA,EACA,UAAW,GACX,UAAW,aACX,QAAS,GACT,QAAS,6CACT,UAAW,KAAK,IAAI,EACpB,OAAQ,UACV,CAAC,EAED,KAAK,OAAO,KAAK,+CAAYA,CAAQ,EAAE,EACvC,IAAMa,EAAmC,CACvC,SAAAb,EACA,UAAW,GACX,YAAa,EACf,EACMY,EAAW,KAAK,sBACpBH,GAAkBI,CACpB,EACA,OAAOV,EAAE,KAAKS,CAAQ,CACxB,OAASN,EAAO,CACd,KAAK,OAAO,MAAM,8CAAYA,CAAK,EACnC,IAAMC,EAAgB,KAAK,oBACzB,4BACAD,aAAiB,MAAQA,EAAM,QAAU,6CACzCN,CACF,EACA,OAAOG,EAAE,KAAKI,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,YAAYJ,EAA+B,CAC/C,IAAMK,EAAc,MAAM,KAAK,sBAC7BL,EACA,oBACF,EACA,GAAI,CAACK,EAAY,GACf,OAAOA,EAAY,SAGrB,IAAMR,EAAWQ,EAAY,SAC7B,GAAI,CAOF,GALyB,KAAK,gBAAgB,oBAAoB,EAC1B,KACrCE,GAAWA,EAAO,WAAaV,CAClC,EAEoB,CAClB,IAAMO,EAAgB,KAAK,oBACzB,0BACA,uCACAP,CACF,EACA,OAAOG,EAAE,KAAKI,EAAe,GAAG,CAClC,CAGA,MAAM,KAAK,gBAAgB,YAAYP,CAAQ,EAK/C,IAAMS,EADJ,KAAK,gBAAgB,oBAAoB,EACI,KAC5CC,GAAWA,EAAO,WAAaV,CAClC,EAEA,GAAI,CAACS,EAAgB,CACnB,IAAMF,EAAgB,KAAK,oBACzB,4BACA,mDACAP,CACF,EACA,OAAOG,EAAE,KAAKI,EAAe,GAAG,CAClC,CAGA,KAAK,SAAS,UAAU,0BAA2B,CACjD,SAAAP,EACA,UAAW,GACX,UAAW,MACX,QAAS,GACT,QAAS,6CACT,UAAW,KAAK,IAAI,EACpB,OAAQ,UACV,CAAC,EAED,KAAK,OAAO,KAAK,+CAAYA,CAAQ,EAAE,EACvC,IAAMY,EAAW,KAAK,sBAAsBH,CAAc,EAC1D,OAAON,EAAE,KAAKS,CAAQ,CACxB,OAASN,EAAO,CACd,KAAK,OAAO,MAAM,8CAAYA,CAAK,EACnC,IAAIQ,EAAY,qBACZC,EAAa,IAGbT,aAAiB,QACfA,EAAM,QAAQ,SAAS,wDAAW,GACpCQ,EAAY,6BACZC,EAAa,KACJT,EAAM,QAAQ,SAAS,oBAAK,GACrCQ,EAAY,0BACZC,EAAa,KACJT,EAAM,QAAQ,SAAS,8DAAY,IAC5CQ,EAAY,mBACZC,EAAa,MAIjB,IAAMR,EAAgB,KAAK,oBACzBO,EACAR,aAAiB,MAAQA,EAAM,QAAU,6CACzC,MACF,EACA,OAAOH,EAAE,KAAKI,EAAeQ,CAA4B,CAC3D,CACF,CAMA,MAAM,eAAeZ,EAA+B,CAClD,IAAMK,EAAc,MAAM,KAAK,sBAC7BL,EACA,uBACF,EACA,GAAI,CAACK,EAAY,GACf,OAAOA,EAAY,SAGrB,IAAMR,EAAWQ,EAAY,SAC7B,KAAK,OAAO,KAAK,2DAAcR,CAAQ,EAAE,EACzC,GAAI,CAGF,IAAMW,EADmB,KAAK,gBAAgB,oBAAoB,EAC1B,KACrCD,GAAWA,EAAO,WAAaV,CAClC,EAEA,GAAI,CAACW,EAAgB,CACnB,IAAMJ,EAAgB,KAAK,oBACzB,qBACA,iCACAP,CACF,EACA,OAAOG,EAAE,KAAKI,EAAe,GAAG,CAClC,CAGII,EAAe,WACjB,MAAM,KAAK,gBAAgB,mBAAmBX,CAAQ,EAIxD,MAAM,KAAK,gBAAgB,eAAeA,CAAQ,EAGlD,KAAK,SAAS,UAAU,0BAA2B,CACjD,SAAAA,EACA,UAAW,GACX,UAAW,SACX,QAAS,GACT,QAAS,6CACT,UAAW,KAAK,IAAI,EACpB,OAAQ,UACV,CAAC,EAED,KAAK,OAAO,KAAK,+CAAYA,CAAQ,EAAE,EACvC,IAAMY,EAAW,KAAK,sBAAsB,CAC1C,SAAAZ,EACA,UAAW,SACX,QAAS,GACT,QAAS,4CACX,CAAC,EACD,OAAOG,EAAE,KAAKS,CAAQ,CACxB,OAASN,EAAO,CACd,KAAK,OAAO,MAAM,8CAAYA,CAAK,EACnC,IAAIQ,EAAY,wBACZC,EAAa,IAGbT,aAAiB,QACfA,EAAM,QAAQ,SAAS,oBAAK,GAC9BQ,EAAY,qBACZC,EAAa,KACJT,EAAM,QAAQ,SAAS,8DAAY,IAC5CQ,EAAY,mBACZC,EAAa,MAIjB,IAAMR,EAAgB,KAAK,oBACzBO,EACAR,aAAiB,MAAQA,EAAM,QAAU,6CACzCN,CACF,EACA,OAAOG,EAAE,KAAKI,EAAeQ,CAA4B,CAC3D,CACF,CACF,IClhBA,IAeaC,GAfbC,GAAAC,EAAA,kBAKAC,IAEAC,KAQaJ,GAAsBK,EAAA,IAAqC,CAEtE,IAAIC,EAAgD,KAChDC,EAEJ,MAAO,OAAOC,EAAGC,IAAS,CACxB,IAAMC,EAAkBF,EAAE,IAAI,iBAAiB,EAM3CE,IAAoBH,IACtBA,EAAcG,EACVA,EACFJ,EAAkB,IAAIK,GACpBD,EACAE,CACF,EAEAN,EAAkB,MAKtBE,EAAE,IAAI,kBAAmBF,CAAe,EAExC,MAAMG,EAAK,CACb,CACF,EA7BmC,yBCfnC,IAAAI,GAAAC,EAAA,kBAAAC,KACAC,KACAC,KAMAC,KAIAC,KACAC,KAGAC,OChBA,IAOsBC,GAPtBC,GAAAC,EAAA,kBAOsBF,GAAf,KAAkC,CAPzC,MAOyC,CAAAG,EAAA,2BAO7B,UAAUC,EAAoB,CACtC,IAAMC,EAASD,EAAE,IAAI,QAAQ,EAC7B,GAAI,CAACC,EACH,MAAM,IAAI,MACR,qEACF,EAEF,OAAOA,CACT,CACF,ICvBA,IAYaC,GAZbC,GAAAC,EAAA,kBACAC,IACAC,KAKAC,KAKaL,GAAN,cAA+BM,EAAmB,CAZzD,MAYyD,CAAAC,EAAA,yBACvD,aAAc,CACZ,MAAM,CACR,CAMA,MAAM,UAAUC,EAA+B,CAC7C,IAAMC,EAAS,KAAK,UAAUD,CAAC,EAC/B,GAAI,CACFC,EAAO,MAAM,kDAAU,EACvB,IAAMC,EAASC,EAAc,UAAU,EACvC,OAAAF,EAAO,KAAK,sCAAQ,EACbD,EAAE,KAAKI,GAAsBF,CAAM,CAAC,CAC7C,OAASG,EAAO,CACdJ,EAAO,MAAM,wCAAWI,CAAK,EAC7B,IAAMC,EAAgBC,EACpB,oBACAF,aAAiB,MAAQA,EAAM,QAAU,sCAC3C,EACA,OAAOL,EAAE,KAAKM,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,aAAaN,EAA+B,CAChD,IAAMC,EAAS,KAAK,UAAUD,CAAC,EAC/B,GAAI,CACFC,EAAO,MAAM,kDAAU,EACvB,IAAMO,EAAuB,MAAMR,EAAE,IAAI,KAAK,EAS9C,GANAG,EAAc,eAAeK,CAAS,EAGtCL,EAAc,aAAaK,CAAS,EAGhCA,EAAU,gBACZ,OAAW,CAACC,EAAYC,CAAW,IAAK,OAAO,QAC7CF,EAAU,eACZ,EACE,OAAW,CAACG,EAAUC,CAAU,IAAK,OAAO,QAC1CF,EAAY,KACd,EACEP,EAAc,eACZM,EACAE,EACAC,EAAW,MACb,EAKN,OAAAX,EAAO,KAAK,sCAAQ,EACbD,EAAE,KAAKI,GAAsB,KAAM,sCAAQ,CAAC,CACrD,OAASC,EAAO,CACdJ,EAAO,MAAM,wCAAWI,CAAK,EAC7B,IAAMC,EAAgBC,EACpB,sBACAF,aAAiB,MAAQA,EAAM,QAAU,sCAC3C,EACA,OAAOL,EAAE,KAAKM,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,eAAeN,EAA+B,CAClD,IAAMC,EAAS,KAAK,UAAUD,CAAC,EAC/B,GAAI,CACFC,EAAO,MAAM,uDAAe,EAC5B,IAAMY,EAAWV,EAAc,eAAe,EAC9C,OAAAF,EAAO,MAAM,2CAAa,EACnBD,EAAE,KAAKI,GAAsB,CAAE,SAAAS,CAAS,CAAC,CAAC,CACnD,OAASR,EAAO,CACdJ,EAAO,MAAM,6CAAgBI,CAAK,EAClC,IAAMC,EAAgBC,EACpB,0BACAF,aAAiB,MAAQA,EAAM,QAAU,2CAC3C,EACA,OAAOL,EAAE,KAAKM,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,gBAAgBN,EAA+B,CACnD,IAAMC,EAAS,KAAK,UAAUD,CAAC,EAC/B,GAAI,CACFC,EAAO,MAAM,mEAAiB,EAC9B,IAAMa,EAAYX,EAAc,gBAAgB,EAChD,OAAAF,EAAO,MAAM,uDAAe,EACrBD,EAAE,KAAKI,GAAsB,CAAE,UAAAU,CAAU,CAAC,CAAC,CACpD,OAAST,EAAO,CACdJ,EAAO,MAAM,yDAAkBI,CAAK,EACpC,IAAMC,EAAgBC,EACpB,2BACAF,aAAiB,MAAQA,EAAM,QAAU,uDAC3C,EACA,OAAOL,EAAE,KAAKM,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,cAAcN,EAA+B,CACjD,IAAMC,EAAS,KAAK,UAAUD,CAAC,EAC/B,GAAI,CACFC,EAAO,MAAM,mEAAiB,EAC9B,IAAMc,EAAUZ,EAAc,cAAc,EAC5C,OAAAF,EAAO,MAAM,uDAAe,EACrBD,EAAE,KAAKI,GAAsB,CAAE,QAAAW,CAAQ,CAAC,CAAC,CAClD,OAASV,EAAO,CACdJ,EAAO,MAAM,yDAAkBI,CAAK,EACpC,IAAMC,EAAgBC,EACpB,yBACAF,aAAiB,MAAQA,EAAM,QAAU,uDAC3C,EACA,OAAOL,EAAE,KAAKM,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,oBAAoBN,EAA+B,CACvD,IAAMC,EAAS,KAAK,UAAUD,CAAC,EAC/B,GAAI,CACFC,EAAO,MAAM,8DAAY,EACzB,IAAMe,EAAab,EAAc,oBAAoB,EACrD,OAAAF,EAAO,MAAM,kDAAU,EAChBD,EAAE,KAAKI,GAAsB,CAAE,WAAAY,CAAW,CAAC,CAAC,CACrD,OAASX,EAAO,CACdJ,EAAO,MAAM,oDAAaI,CAAK,EAC/B,IAAMC,EAAgBC,EACpB,+BACAF,aAAiB,MAAQA,EAAM,QAAU,kDAC3C,EACA,OAAOL,EAAE,KAAKM,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,aAAaN,EAA+B,CAChD,IAAMC,EAAS,KAAK,UAAUD,CAAC,EAC/B,GAAI,CACFC,EAAO,KAAK,8DAAY,EACxBE,EAAc,aAAa,EAC3B,IAAMD,EAASC,EAAc,UAAU,EACvC,OAAAF,EAAO,KAAK,kDAAU,EACfD,EAAE,KAAKI,GAAsBF,EAAQ,kDAAU,CAAC,CACzD,OAASG,EAAO,CACdJ,EAAO,MAAM,oDAAaI,CAAK,EAC/B,IAAMC,EAAgBC,EACpB,sBACAF,aAAiB,MAAQA,EAAM,QAAU,kDAC3C,EACA,OAAOL,EAAE,KAAKM,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,cAAcN,EAA+B,CACjD,IAAMC,EAAS,KAAK,UAAUD,CAAC,EAC/B,GAAI,CACFC,EAAO,MAAM,0EAAc,EAC3B,IAAMgB,EAAOd,EAAc,cAAc,EACzC,OAAAF,EAAO,MAAM,8DAAY,EAClBD,EAAE,KAAKI,GAAsB,CAAE,KAAAa,CAAK,CAAC,CAAC,CAC/C,OAASZ,EAAO,CACdJ,EAAO,MAAM,gEAAeI,CAAK,EACjC,IAAMC,EAAgBC,EACpB,yBACAF,aAAiB,MAAQA,EAAM,QAAU,8DAC3C,EACA,OAAOL,EAAE,KAAKM,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,kBAAkBN,EAA+B,CACrD,IAAMC,EAAS,KAAK,UAAUD,CAAC,EAC/B,GAAI,CACFC,EAAO,MAAM,0EAAc,EAC3B,IAAMiB,EAASf,EAAc,aAAa,EAC1C,OAAAF,EAAO,MAAM,qDAAaiB,CAAM,EAAE,EAC3BlB,EAAE,KAAKI,GAAsB,CAAE,OAAAc,CAAO,CAAC,CAAC,CACjD,OAASb,EAAO,CACdJ,EAAO,MAAM,gEAAeI,CAAK,EACjC,IAAMC,EAAgBC,EACpB,4BACAF,aAAiB,MAAQA,EAAM,QAAU,8DAC3C,EACA,OAAOL,EAAE,KAAKM,EAAe,GAAG,CAClC,CACF,CACF,ICpMA,SAASa,GAAgBC,EAAwC,CAC/D,GAAI,EAAEA,aAAiB,OAAS,SAAUA,GACxC,MAAO,GAGT,IAAMC,EAAQD,EAAwB,KAStC,OAAO,OAAOC,GAAS,UARa,CAClC,cACA,eACA,UACA,YACA,eACF,EAE8C,SAASA,CAAqB,CAC9E,CA0BA,SAASC,GAAyBC,EAASC,EAAkC,CAC3E,MAAO,CACL,QAAS,GACT,KAAAD,EACA,QAAAC,CACF,CACF,CAKA,SAASC,EACPD,EACAH,EACAK,EACe,CACf,MAAO,CACL,QAAS,GACT,QAAAF,EACA,MAAOH,EAAO,CAAE,KAAAA,EAAM,QAAAK,CAAQ,EAAI,MACpC,CACF,CAKA,SAASC,IAAoC,CAC3C,IAAMC,EAAQC,EAAc,aAAa,EAEzC,GAAI,CAACD,EACH,MAAM,IAAI,MACR,4HACF,EAGF,OAAO,IAAIE,GAAeF,CAAK,CACjC,CA/GA,IAoHaG,GApHbC,GAAAC,EAAA,kBAKAC,IACAC,KACAC,IA2BSC,EAAAlB,GAAA,mBAyCAkB,EAAAf,GAAA,yBAWAe,EAAAZ,EAAA,uBAeAY,EAAAV,GAAA,qBAeII,GAAN,KAAqB,CApH5B,MAoH4B,CAAAM,EAAA,uBAK1B,MAAM,cAAcC,EAA+B,CACjD,GAAI,CAIF,GAHAC,EAAO,KAAK,0EAAc,EAGtB,CAACV,EAAc,kBAAkB,EACnC,OAAAU,EAAO,MAAM,sCAAQ,EACdD,EAAE,KACPb,EACE,iGACA,gBACF,EACA,GACF,EAGF,IAAMe,EAAiBb,GAAkB,EAEzCY,EAAO,KAAK,wEAAsB,EAClC,IAAME,EAAa,MAAMD,EAAe,cAAc,EACtD,OAAAD,EAAO,KAAK,4BAAQE,EAAW,MAAM,iCAAQ,EAEtCH,EAAE,KACPhB,GAAsB,CACpB,WAAAmB,CACF,CAAC,CACH,CACF,OAASrB,EAAO,CAId,OAHAmB,EAAO,MAAM,gEAAenB,CAAK,EAG7BD,GAAgBC,CAAK,GAAKA,EAAM,OAAS,cACpCkB,EAAE,KACPb,EACE,uFACA,aACF,EACA,GACF,EAGEN,GAAgBC,CAAK,GAAKA,EAAM,OAAS,eACpCkB,EAAE,KACPb,EAAoB,2EAAgB,cAAc,EAClD,GACF,EAGEN,GAAgBC,CAAK,GAAKA,EAAM,OAAS,UACpCkB,EAAE,KACPb,EAAoB,+DAAc,SAAS,EAC3C,GACF,EAGKa,EAAE,KACPb,EACEL,aAAiB,MAAQA,EAAM,QAAU,+DACzC,iBACA,QAAQ,IAAI,WAAa,eAAiBA,aAAiB,MACvDA,EAAM,MACN,MACN,EACA,GACF,CACF,CACF,CAMA,MAAM,aAAakB,EAA+B,CAChD,GAAI,CAIF,GAHAC,EAAO,KAAK,oEAAa,EAGrB,CAACV,EAAc,kBAAkB,EACnC,OAAAU,EAAO,MAAM,sCAAQ,EACdD,EAAE,KACPb,EACE,iGACA,gBACF,EACA,GACF,EAIF,IAAMiB,EAAeJ,EAAE,IAAI,MAAM,cAAc,EACzCK,EAAW,OAAO,SAASL,EAAE,IAAI,MAAM,UAAU,GAAK,IAAK,EAAE,EAC7DM,EAAY,OAAO,SAASN,EAAE,IAAI,MAAM,WAAW,GAAK,KAAM,EAAE,EAGtE,GAAI,CAACI,EACH,OAAAH,EAAO,KAAK,wCAAoB,EACzBD,EAAE,KACPb,EACE,qDACA,mBACF,EACA,GACF,EAIF,GAAIkB,EAAW,GAAKA,EAAW,IAC7B,OAAOL,EAAE,KACPb,EACE,kDACA,mBACF,EACA,GACF,EAGF,GAAImB,EAAY,GAAKA,EAAY,IAC/B,OAAON,EAAE,KACPb,EACE,kDACA,mBACF,EACA,GACF,EAGF,IAAMoB,EAA8B,CAClC,aAAAH,EACA,SAAAC,EACA,UAAAC,CACF,EAEMJ,EAAiBb,GAAkB,EAEzCY,EAAO,KACL,oDAAYG,CAAY,4DAAeC,CAAQ,uBAAQC,CAAS,EAClE,EACA,IAAME,EAAS,MAAMN,EAAe,aAAaK,CAAM,EACvDN,EAAO,KACL,oDAAYG,CAAY,WAAMI,EAAO,MAAM,MAAM,2BACnD,EAGA,IAAMC,EAAiBlB,EAAc,kBAAkB,EAGjDmB,EAAgBF,EAAO,MAAM,IAAKG,GAAS,CAE/C,IAAMC,EAAYH,EAAe,KAC9BI,GACCA,EAAK,QAAQ,OAAS,SACtBA,EAAK,QAAQ,WAAa,QAC1BA,EAAK,QAAQ,OAAO,cAAgBF,EAAK,WAC7C,EAEA,MAAO,CACL,GAAGA,EACH,cAAe,CAAC,CAACC,EACjB,SAAUA,GAAW,MAAQ,IAC/B,CACF,CAAC,EAED,OAAAX,EAAO,KACL,kFAAiBS,EAAc,OAAQC,GAASA,EAAK,aAAa,EAAE,MAAM,+DAC5E,EAEOX,EAAE,KACPhB,GAAsB,CACpB,MAAO0B,EACP,SAAUF,EAAO,SACjB,SAAAH,EACA,UAAAC,EACA,YAAaE,EAAO,MAAM,MAC5B,CAAC,CACH,CACF,OAAS1B,EAAO,CAId,OAHAmB,EAAO,MAAM,0DAAcnB,CAAK,EAG5BD,GAAgBC,CAAK,GAAKA,EAAM,OAAS,cACpCkB,EAAE,KACPb,EACE,uFACA,aACF,EACA,GACF,EAGEN,GAAgBC,CAAK,GAAKA,EAAM,OAAS,eACpCkB,EAAE,KACPb,EAAoB,2EAAgB,cAAc,EAClD,GACF,EAGEN,GAAgBC,CAAK,GAAKA,EAAM,OAAS,UACpCkB,EAAE,KACPb,EAAoB,+DAAc,SAAS,EAC3C,GACF,EAGKa,EAAE,KACPb,EACEL,aAAiB,MAAQA,EAAM,QAAU,yDACzC,iBACA,QAAQ,IAAI,WAAa,eAAiBA,aAAiB,MACvDA,EAAM,MACN,MACN,EACA,GACF,CACF,CACF,CAMA,MAAM,WAAWkB,EAA+B,CAC9C,GAAI,CAIF,GAHAC,EAAO,KAAK,mEAAiB,EAGzB,CAACV,EAAc,kBAAkB,EACnC,OAAAU,EAAO,MAAM,sCAAQ,EACdD,EAAE,KACPb,EACE,iGACA,gBACF,EACA,GACF,EAGF,IAAM2B,EAAUd,EAAE,IAAI,MAAM,SAAS,EAE/BE,EAAiBb,GAAkB,EAEnC0B,EAAcb,EAAe,cAAc,EACjDD,EAAO,KAAK,uCAASa,EAAU,mBAASA,CAAO,IAAM,EAAE,EAAE,EAEzDZ,EAAe,WAAWY,CAAO,EAEjC,IAAME,EAAad,EAAe,cAAc,EAEhD,OAAAD,EAAO,KACL,iEAAec,EAAY,IAAI,oCAAWC,EAAW,IAAI,SAC3D,EAEOhB,EAAE,KACPhB,GACE,CACE,QAAS+B,EAAY,KAAOC,EAAW,KACvC,UAAWA,EAAW,KACtB,QAASF,GAAW,KACtB,EACA,sCACF,CACF,CACF,OAAShC,EAAO,CACd,OAAAmB,EAAO,MAAM,wCAAWnB,CAAK,EAEtBkB,EAAE,KACPb,EACEL,aAAiB,MAAQA,EAAM,QAAU,uCACzC,iBACA,QAAQ,IAAI,WAAa,eAAiBA,aAAiB,MACvDA,EAAM,MACN,MACN,EACA,GACF,CACF,CACF,CAMA,MAAM,cAAckB,EAA+B,CACjD,GAAI,CAIF,GAHAC,EAAO,KAAK,0EAAc,EAGtB,CAACV,EAAc,kBAAkB,EACnC,OAAAU,EAAO,MAAM,sCAAQ,EACdD,EAAE,KACPb,EACE,iGACA,gBACF,EACA,GACF,EAIF,IAAM8B,EADiB5B,GAAkB,EACZ,cAAc,EAE3C,OAAOW,EAAE,KAAKhB,GAAsBiC,CAAK,CAAC,CAC5C,OAASnC,EAAO,CACd,OAAAmB,EAAO,MAAM,gEAAenB,CAAK,EAE1BkB,EAAE,KACPb,EACEL,aAAiB,MAAQA,EAAM,QAAU,+DACzC,iBACA,QAAQ,IAAI,WAAa,eAAiBA,aAAiB,MACvDA,EAAM,MACN,MACN,EACA,GACF,CACF,CACF,CACF,ICrbA,IAsBaoC,GAtBbC,GAAAC,EAAA,kBAAAC,IAEAC,IAoBaJ,GAAN,KAAuB,CAtB9B,MAsB8B,CAAAK,EAAA,yBACpB,OACA,cACA,oBAER,YACEC,EACAC,EACA,CACA,KAAK,OAASC,EACd,KAAK,cAAgBF,EACrB,KAAK,oBAAsBC,CAC7B,CAKA,MAAM,mBACJE,EACAC,EACAC,EACe,CACf,GAAI,CACF,KAAK,OAAO,MAAM,2DAAcA,CAAQ,GAAID,EAAQ,IAAI,EAGxD,IAAME,EAAe,CACnB,GAAGF,EAAQ,KACX,cAAe,KAAK,IAAI,CAC1B,EAEA,KAAK,cAAc,iBACjBE,EACA,aAAaD,CAAQ,EACvB,EAGA,MAAM,KAAK,iBAAiBF,EAAIE,CAAQ,EAExC,KAAK,OAAO,MAAM,2DAAcA,CAAQ,EAAE,CAC5C,OAASE,EAAO,CACd,KAAK,OAAO,MAAM,uEAAgBF,CAAQ,GAAIE,CAAK,EACnD,KAAK,UACHJ,EACA,sBACAI,aAAiB,MAAQA,EAAM,QAAU,wDAC3C,CACF,CACF,CAKA,MAAc,iBAAiBJ,EAASE,EAAiC,CACvE,GAAI,CAEF,IAAMD,EAAU,CACd,KAAM,eACN,KAHmBI,EAAc,UAAU,EAI3C,UAAW,KAAK,IAAI,CACtB,EAEAL,EAAG,KAAK,KAAK,UAAUC,CAAO,CAAC,EAC/B,KAAK,OAAO,MAAM,uEAAgBC,CAAQ,EAAE,CAC9C,OAASE,EAAO,CACd,KAAK,OAAO,MAAM,qDAAaF,CAAQ,GAAIE,CAAK,CAElD,CACF,CAKQ,UAAUJ,EAASM,EAAcL,EAAuB,CAC9D,GAAI,CACF,IAAMM,EAAgB,CACpB,KAAM,QACN,MAAO,CACL,KAAAD,EACA,QAAAL,EACA,UAAW,KAAK,IAAI,CACtB,CACF,EACAD,EAAG,KAAK,KAAK,UAAUO,CAAa,CAAC,CACvC,OAASH,EAAO,CACd,KAAK,OAAO,MAAM,oDAAaA,CAAK,CACtC,CACF,CAKA,uBAA8B,CAC5B,IAAMI,EAAgB,KAAK,cAAc,iBAAiB,EACpDC,EAAM,KAAK,IAAI,EAGjBD,GAAiBC,EAAMD,EAFD,OAGxB,KAAK,OAAO,KAAK,4FAAiB,EAClC,KAAK,cAAc,iBACjB,CAAE,OAAQ,cAAe,EACzB,mBACF,EAEJ,CAKA,0BAA2C,CAGzC,YAAK,OAAO,MAAM,sCAAQ,EAEnB,YAAY,IAAM,CACvB,KAAK,sBAAsB,EAC3B,KAAK,2BAA2B,CAClC,EAAG,GAAgB,CACrB,CAKQ,4BAAmC,CACzC,GAAI,CACF,KAAK,oBAAoB,2BAA2B,CACtD,OAASJ,EAAO,CACd,KAAK,OAAO,MAAM,4EAAiBA,CAAK,CAC1C,CACF,CAKA,wBAAwBM,EAAkC,CACxD,KAAK,OAAO,KAAK,sCAAQ,EACzB,cAAcA,CAAU,CAC1B,CAKA,mBAQE,CACA,MAAO,CACL,cAAe,KAAK,cAAc,iBAAiB,EACnD,YAAa,KAAK,cAAc,kBAAkB,EAClD,YAAa,KAAK,oBAAoB,eAAe,CACvD,CACF,CAKA,oBAAoBR,EAAwB,CAC1C,KAAK,OAAO,KAAK,+CAAYA,CAAQ,EAAE,EAGvC,KAAK,cAAc,iBACjB,CACE,OAAQ,YACR,cAAe,KAAK,IAAI,CAC1B,EACA,qBAAqBA,CAAQ,EAC/B,CACF,CAKA,uBAAuBA,EAAwB,CAC7C,KAAK,OAAO,KAAK,+CAAYA,CAAQ,EAAE,EAGvC,KAAK,cAAc,iBACjB,CAAE,OAAQ,cAAe,EACzB,wBAAwBA,CAAQ,EAClC,CACF,CAKA,sBAAsBF,EAASE,EAAwB,CACrD,GAAI,CACF,IAAMS,EAAW,CACf,KAAM,oBACN,KAAM,CACJ,UAAW,KAAK,IAAI,EACpB,OAAQ,IACV,CACF,EAEAX,EAAG,KAAK,KAAK,UAAUW,CAAQ,CAAC,EAChC,KAAK,OAAO,MAAM,+CAAYT,CAAQ,EAAE,CAC1C,OAASE,EAAO,CACd,KAAK,OAAO,MAAM,qDAAaF,CAAQ,GAAIE,CAAK,CAClD,CACF,CAKA,yBAAyBH,EAA2C,CAClE,OACEA,GACA,OAAOA,GAAY,UACnBA,EAAQ,OAAS,gBACjBA,EAAQ,MACR,OAAOA,EAAQ,MAAS,QAE5B,CACF,IC3OA,OAAS,cAAAW,OAAkB,SAN3B,IA2DaC,GA3DbC,GAAAC,EAAA,kBAQAC,KAEAC,IAiDaJ,GAAN,KAAsB,CA3D7B,MA2D6B,CAAAK,EAAA,wBACnB,OACA,kBAA8C,KAC9C,QAAkC,IAAI,IACtC,OACA,QACA,gBAAyC,KACzC,UAER,YAAYC,EAAgC,CAAC,EAAG,CAC9C,KAAK,OAASC,EACd,KAAK,OAAS,CACZ,WAAYD,EAAO,YAAc,IACjC,kBAAmBA,EAAO,mBAAqB,IAC/C,kBAAmBA,EAAO,mBAAqB,IAC/C,eAAgBA,EAAO,gBAAkB,KAAO,KAChD,cAAeA,EAAO,eAAiB,EACzC,EAEA,KAAK,QAAU,CACb,iBAAkB,EAClB,kBAAmB,EACnB,cAAe,EACf,WAAY,EACZ,oBAAqB,EACrB,OAAQ,CACV,EAEA,KAAK,UAAY,IAAI,KAGrB,KAAK,iBAAiB,EAEtB,KAAK,OAAO,MAAM,iDAAyB,CACzC,WAAY,KAAK,OAAO,WACxB,kBAAmB,KAAK,OAAO,kBAC/B,kBAAmB,KAAK,OAAO,iBACjC,CAAC,CACH,CAKQ,kBAAyB,CAC/B,KAAK,gBAAkB,YAAY,IAAM,CACvC,KAAK,wBAAwB,EAC7B,KAAK,cAAc,CACrB,EAAG,GAAK,CACV,CAKQ,iBAAwB,CAC1B,KAAK,kBACP,cAAc,KAAK,eAAe,EAClC,KAAK,gBAAkB,KAE3B,CAKQ,yBAAgC,CACtC,IAAME,EAAM,IAAI,KACVC,EAAyB,CAAC,EAEhC,OAAW,CAACC,EAAWC,CAAM,IAAK,KAAK,QAAQ,QAAQ,GAEnDH,EAAI,QAAQ,EAAIG,EAAO,aAAa,QAAQ,EAGpB,KAAK,OAAO,mBACpC,CAACA,EAAO,UAERF,EAAa,KAAKC,CAAS,EAI/B,QAAWA,KAAaD,EACtB,KAAK,OAAO,KAAK,yCAAWC,CAAS,EAAE,EACvC,KAAK,uBAAuBA,EAAW,SAAS,EAG9CD,EAAa,OAAS,GACxB,KAAK,OAAO,KAAK,sBAAOA,EAAa,MAAM,iCAAQ,CAEvD,CAKQ,eAAsB,CACvB,KAAK,OAAO,gBAEjB,KAAK,QAAQ,kBAAoB,KAAK,QAAQ,KAC9C,KAAK,QAAQ,OAAS,KAAK,IAAI,EAAI,KAAK,UAAU,QAAQ,EAE1D,KAAK,OAAO,MAAM,2BAAQ,CACxB,kBAAmB,KAAK,QAAQ,kBAChC,iBAAkB,KAAK,QAAQ,iBAC/B,cAAe,KAAK,QAAQ,cAC5B,WAAY,KAAK,QAAQ,UAC3B,CAAC,EACH,CAMQ,qBAAqBG,EAA+B,CAE1D,IAAMC,EAAiBD,EAAE,IAAI,mBAAmB,EAChD,GAAIC,EACF,OAAOA,EAIT,IAAMC,EAAYF,EAAE,IAAI,WAAW,EACnC,GAAI,CAACE,EACH,MAAM,IAAI,MAAM,yGAAmC,EAGrD,IAAMC,EAAoBD,EAAU,qBAAqB,EACzD,YAAK,OAAO,MACV,6FACF,EAEOC,CACT,CAKA,MAAc,yBAAyBH,EAA2B,CAChE,GAAI,MAAK,kBAIT,GAAI,CACF,IAAMC,EAAiB,KAAK,qBAAqBD,CAAC,EAClD,KAAK,kBAAoB,IAAII,GAAkBH,CAAc,EAC7D,KAAK,OAAO,MAAM,kEAAgB,CACpC,OAASI,EAAO,CACd,WAAK,OAAO,MAAM,oEAAmBA,CAAK,EAC1C,KAAK,QAAQ,aACPA,CACR,CACF,CAOA,MAAM,WAAWL,EAA+B,CAC9C,IAAMM,EAAY,KAAK,IAAI,EACvBC,EAAoC,KAExC,GAAI,CACF,KAAK,OAAO,MAAM,oCAAgB,EAGlC,IAAMT,EAAYE,EAAE,IAAI,MAAM,WAAW,EACzC,GAAIF,EACF,OAAO,MAAM,KAAK,iBAAiBE,EAAGF,CAAS,EAIjD,IAAMU,EAAgBR,EAAE,IAAI,OAAO,gBAAgB,EACnD,GACEQ,GACA,OAAO,SAASA,CAAa,EAAI,KAAK,OAAO,eAE7C,YAAK,QAAQ,aACN,KAAK,oBACV,OACA,sCAAsC,KAAK,OAAO,cAAc,QAClE,EAKF,GAAI,CADgBR,EAAE,IAAI,OAAO,cAAc,GAC7B,SAAS,kBAAkB,EAC3C,YAAK,QAAQ,aACN,KAAK,oBACV,OACA,wDACF,EAKF,IAAMS,EACJT,EAAE,IAAI,OAAO,sBAAsB,GACnCA,EAAE,IAAI,OAAO,sBAAsB,GACnCA,EAAE,IAAI,OAAO,sBAAsB,EAC/BU,EAAoB,CAAC,aAAc,YAAY,EACjDD,GAAmB,CAACC,EAAkB,SAASD,CAAe,GAChE,KAAK,OAAO,KACV,0DAAkBA,CAAe,yCAAWC,EAAkB,KAC5D,IACF,CAAC,EACH,EAIF,IAAIC,EACJ,GAAI,CACF,IAAMC,EAAU,MAAMZ,EAAE,IAAI,KAAK,EACjC,GAAIY,EAAQ,OAAS,KAAK,OAAO,eAC/B,YAAK,QAAQ,aACN,KAAK,oBACV,OACA,sCAAsC,KAAK,OAAO,cAAc,SAChE,IACF,EAEFD,EAAU,KAAK,MAAMC,CAAO,EAC5BL,EAAYI,EAAQ,IAAM,IAC5B,MAAgB,CACd,YAAK,QAAQ,aACN,KAAK,oBAAoB,OAAQ,2BAA2B,CACrE,CAGA,GAAI,CAAC,KAAK,gBAAgBA,CAAO,EAC/B,YAAK,QAAQ,aACN,KAAK,oBACV,OACA,4DACAJ,CACF,EAOF,GAHA,MAAM,KAAK,yBAAyBP,CAAC,EAGjC,CAAC,KAAK,kBACR,MAAM,IAAI,MAAM,8DAAY,EAE9B,IAAMa,EAAW,MAAM,KAAK,kBAAkB,cAAcF,CAAO,EAGnE,KAAK,QAAQ,gBACb,IAAMG,EAAe,KAAK,IAAI,EAAIR,EAclC,OAbA,KAAK,QAAQ,qBACV,KAAK,QAAQ,qBAAuB,KAAK,QAAQ,cAAgB,GAChEQ,GACF,KAAK,QAAQ,cAEf,KAAK,OAAO,MAAM,gDAAmB,CACnC,OAAQH,EAAQ,OAChB,UAAWJ,EACX,aAAcO,EACd,eAAgBD,IAAa,IAC/B,CAAC,EAGGA,IAAa,KACR,IAAI,SAAS,KAAM,CACxB,OAAQ,IACR,QAAS,CACP,uBAAwB,aACxB,kBAAmBC,EAAa,SAAS,CAC3C,CACF,CAAC,EAIId,EAAE,KAAKa,EAAU,IAAK,CAC3B,eAAgB,mBAChB,uBAAwB,aACxB,kBAAmBC,EAAa,SAAS,CAC3C,CAAC,CACH,OAAST,EAAO,CACd,KAAK,QAAQ,aACb,IAAMS,EAAe,KAAK,IAAI,EAAIR,EAElC,KAAK,OAAO,MAAM,wDAAsB,CACtC,MAAOD,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,EAC5D,UAAWE,EACX,aAAcO,EACd,MAAOT,aAAiB,MAAQA,EAAM,MAAQ,MAChD,CAAC,EAED,IAAMU,EACJV,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,EACvD,OAAO,KAAK,oBACV,OACA,mBAAmBU,CAAY,GAC/BR,CACF,CACF,CACF,CAMA,MAAc,iBACZP,EACAF,EACmB,CACnB,IAAMQ,EAAY,KAAK,IAAI,EACvBC,EAAoC,KAExC,GAAI,CACF,KAAK,OAAO,MAAM,gDAAkBT,CAAS,GAAG,EAGhD,IAAMC,EAAS,KAAK,QAAQ,IAAID,CAAS,EACzC,GAAI,CAACC,EACH,YAAK,QAAQ,aACN,KAAK,oBACV,OACA,gDACA,IACF,EAIFA,EAAO,aAAe,IAAI,KAG1B,IAAMS,EAAgBR,EAAE,IAAI,OAAO,gBAAgB,EACnD,GACEQ,GACA,OAAO,SAASA,CAAa,EAAI,KAAK,OAAO,eAE7C,YAAK,QAAQ,aACN,KAAK,oBACV,OACA,sCAAsC,KAAK,OAAO,cAAc,QAClE,EAIF,IAAIG,EACJ,GAAI,CACF,IAAMC,EAAU,MAAMZ,EAAE,IAAI,KAAK,EACjC,GAAIY,EAAQ,OAAS,KAAK,OAAO,eAC/B,YAAK,QAAQ,aACN,KAAK,oBACV,OACA,sCAAsC,KAAK,OAAO,cAAc,SAChE,IACF,EAEFD,EAAU,KAAK,MAAMC,CAAO,EAC5BL,EAAYI,EAAQ,IAAM,IAC5B,MAAgB,CACd,YAAK,QAAQ,aACN,KAAK,oBAAoB,OAAQ,2BAA2B,CACrE,CAGA,GAAI,CAAC,KAAK,gBAAgBA,CAAO,EAC/B,YAAK,QAAQ,aACN,KAAK,oBACV,OACA,4DACAJ,CACF,EAOF,GAHA,MAAM,KAAK,yBAAyBP,CAAC,EAGjC,CAAC,KAAK,kBACR,MAAM,IAAI,MAAM,8DAAY,EAE9B,IAAMa,EAAW,MAAM,KAAK,kBAAkB,cAAcF,CAAO,EAOnE,GAJAZ,EAAO,eACP,KAAK,QAAQ,gBAGTc,IAAa,MAAQd,EAAO,QAAUA,EAAO,QAC/C,GAAI,CACF,MAAM,KAAK,aACTA,EAAO,OACP,UACA,KAAK,UAAUc,CAAQ,CACzB,CACF,OAASG,EAAY,CACnB,KAAK,OAAO,KACV,6FAAuBlB,CAAS,GAChCkB,CACF,EACAjB,EAAO,QAAU,EACnB,CAGF,IAAMe,EAAe,KAAK,IAAI,EAAIR,EAClC,YAAK,OAAO,MAAM,2DAAmBR,CAAS,IAAK,CACjD,OAAQa,EAAQ,OAChB,UAAWJ,EACX,aAAcO,EACd,aAAcf,EAAO,aACrB,eAAgBc,IAAa,IAC/B,CAAC,EAGM,IAAI,SAAS,KAAM,CACxB,OAAQ,IACR,QAAS,CACP,uBAAwB,aACxB,kBAAmBC,EAAa,SAAS,CAC3C,CACF,CAAC,CACH,OAAST,EAAO,CACd,KAAK,QAAQ,aACb,IAAMS,EAAe,KAAK,IAAI,EAAIR,EAElC,KAAK,OAAO,MAAM,kEAAqBR,CAAS,KAAM,CACpD,MAAOO,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,EAC5D,UAAWE,EACX,aAAcO,EACd,MAAOT,aAAiB,MAAQA,EAAM,MAAQ,MAChD,CAAC,EAED,IAAMU,EACJV,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,EACvD,OAAO,KAAK,oBACV,OACA,mBAAmBU,CAAY,GAC/BR,CACF,CACF,CACF,CAMA,MAAM,UAAUP,EAA+B,CAC7C,GAAI,CAIF,GAHA,KAAK,OAAO,MAAM,+DAAuB,EAGrC,KAAK,QAAQ,MAAQ,KAAK,OAAO,WACnC,YAAK,QAAQ,aACNA,EAAE,KACP,CACE,QAAS,MACT,MAAO,CACL,KAAM,MACN,QAAS,kDACT,KAAM,CAAE,WAAY,KAAK,OAAO,UAAW,CAC7C,EACA,GAAI,IACN,EACA,GACF,EAIF,IAAMiB,EAAW,KAAK,IAAI,EAAE,SAAS,EAC/BnB,EAAYX,GAAW,EACvBS,EAAM,IAAI,KAGVsB,EAAYlB,EAAE,IAAI,OAAO,YAAY,EACrCmB,EACJnB,EAAE,IAAI,OAAO,iBAAiB,GAC9BA,EAAE,IAAI,OAAO,WAAW,GACxB,UAEF,KAAK,OAAO,KAAK,uCAAciB,CAAQ,mBAASnB,CAAS,IAAK,CAC5D,UAAWoB,EACX,cAAeC,CACjB,CAAC,EAGD,GAAM,CAAE,SAAAC,EAAU,SAAAC,CAAS,EAAI,IAAI,gBAC7BC,EAASD,EAAS,UAAU,EAG5BE,EAAkB,IAAI,gBAGtBxB,EAAoB,CACxB,GAAIkB,EACJ,UAAAnB,EACA,SAAU,IAAI,SAASsB,CAAQ,EAC/B,YAAaxB,EACb,aAAcA,EACd,OAAA0B,EACA,gBAAAC,EACA,QAAS,GACT,aAAc,EACd,UAAAL,EACA,cAAAC,CACF,EAEA,KAAK,QAAQ,IAAIrB,EAAWC,CAAM,EAClC,KAAK,QAAQ,mBACb,KAAK,QAAQ,kBAAoB,KAAK,QAAQ,KAG9C,GAAI,CACF,MAAM,KAAK,aACTuB,EACA,YACA,KAAK,UAAU,CACb,UAAWxB,EACX,SAAU,kBAAkBA,CAAS,GACrC,UAAWF,EAAI,YAAY,EAC3B,gBAAiB,YACnB,CAAC,CACH,CACF,OAASoB,EAAY,CACnB,KAAK,OAAO,MAAM,0DAAkBlB,CAAS,GAAIkB,CAAU,EAC3DjB,EAAO,QAAU,EACnB,CAGA,KAAK,eAAeA,CAAM,EAG1B,IAAMc,EAAW,IAAI,SAASO,EAAU,CACtC,OAAQ,IACR,QAAS,CACP,eAAgB,oBAChB,gBAAiB,yBACjB,WAAY,aACZ,oBAAqB,KACrB,uBAAwB,aACxB,8BAA+B,IAC/B,+BAAgC,oCAClC,CACF,CAAC,EAGKI,EAAmB/B,EAAA,IAAM,CAC7B,KAAK,uBAAuBK,EAAWmB,CAAQ,CACjD,EAFyB,oBAIzB,OAAAjB,EAAE,IAAI,IAAI,QAAQ,iBAAiB,QAASwB,CAAgB,EAC5DD,EAAgB,OAAO,iBAAiB,QAASC,CAAgB,EAE1DX,CACT,OAASR,EAAO,CACd,YAAK,QAAQ,aACb,KAAK,OAAO,MAAM,uDAAqB,CACrC,MAAOA,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,EAC5D,MAAOA,aAAiB,MAAQA,EAAM,MAAQ,MAChD,CAAC,EAEML,EAAE,KACP,CACE,QAAS,MACT,MAAO,CACL,KAAM,OACN,QAAS,gBACX,EACA,GAAI,IACN,EACA,GACF,CACF,CACF,CAKQ,eAAeD,EAAyB,CAC1CA,EAAO,mBACT,cAAcA,EAAO,iBAAiB,EAGxCA,EAAO,kBAAoB,YAAY,SAAY,CACjD,GAAI,CAACA,EAAO,SAAW,CAACA,EAAO,OAAQ,CACrC,KAAK,cAAcA,CAAM,EACzB,MACF,CAEA,GAAI,CACF,MAAM,KAAK,aACTA,EAAO,OACP,YACA,KAAK,UAAU,CACb,UAAW,IAAI,KAAK,EAAE,YAAY,EAClC,UAAWA,EAAO,SACpB,CAAC,CACH,EAEA,KAAK,OAAO,MAAM,yCAAWA,EAAO,SAAS,EAAE,CACjD,OAASM,EAAO,CACd,KAAK,OAAO,KACV,qGAAqBN,EAAO,SAAS,GACrCM,CACF,EACAN,EAAO,QAAU,GACjB,KAAK,cAAcA,CAAM,CAC3B,CACF,EAAG,KAAK,OAAO,iBAAiB,CAClC,CAKQ,cAAcA,EAAyB,CACzCA,EAAO,oBACT,cAAcA,EAAO,iBAAiB,EACtCA,EAAO,kBAAoB,OAE/B,CAKA,MAAc,aACZuB,EACAG,EACAC,EACe,CACf,GAAI,CACF,IAAMC,EAAY,UAAUF,CAAK;AAAA,QAAWC,CAAI;AAAA;AAAA,EAChD,MAAMJ,EAAO,MAAM,IAAI,YAAY,EAAE,OAAOK,CAAS,CAAC,CACxD,OAAStB,EAAO,CACd,WAAK,OAAO,MAAM,6CAAgBA,CAAK,EACjCA,CACR,CACF,CAKQ,uBAAuBP,EAAmB8B,EAAsB,CACtE,IAAM7B,EAAS,KAAK,QAAQ,IAAID,CAAS,EACzC,GAAI,CAACC,EACH,OAGF,IAAM8B,EAAqB,KAAK,IAAI,EAAI9B,EAAO,YAAY,QAAQ,EAEnE,KAAK,OAAO,MAAM,mDAAgBA,EAAO,EAAE,mBAASD,CAAS,IAAK,CAChE,OAAQ8B,EACR,SAAUC,EACV,aAAc9B,EAAO,aACrB,UAAWA,EAAO,UAClB,cAAeA,EAAO,aACxB,CAAC,EAGD,KAAK,cAAcA,CAAM,EAGrBA,EAAO,iBACTA,EAAO,gBAAgB,MAAM,EAI/B,GAAI,CACEA,EAAO,QACTA,EAAO,OAAO,MAAM,CAExB,OAASM,EAAO,CACd,KAAK,OAAO,MAAM,8CAAsBA,CAAK,CAC/C,CAGA,KAAK,QAAQ,OAAOP,CAAS,EAC7B,KAAK,QAAQ,kBAAoB,KAAK,QAAQ,IAChD,CAKQ,gBAAgBa,EAAyC,CAC/D,GAAI,CAACA,GAAW,OAAOA,GAAY,SACjC,YAAK,OAAO,MAAM,gEAAc,EACzB,GAIT,IAAMmB,EAAMnB,EAEZ,OAAImB,EAAI,UAAY,OAClB,KAAK,OAAO,MAAM,+EAAyB,CACzC,QAASA,EAAI,OACf,CAAC,EACM,IAGL,CAACA,EAAI,QAAU,OAAOA,EAAI,QAAW,UACvC,KAAK,OAAO,MAAM,wEAAuB,CACvC,OAAQA,EAAI,MACd,CAAC,EACM,IAKPA,EAAI,KAAO,QACX,OAAOA,EAAI,IAAO,UAClB,OAAOA,EAAI,IAAO,UAClBA,EAAI,KAAO,MAEX,KAAK,OAAO,MAAM,gFAAqB,CAAE,GAAIA,EAAI,EAAG,CAAC,EAC9C,IAILA,EAAI,SAAW,QAAa,OAAOA,EAAI,QAAW,UACpD,KAAK,OAAO,MAAM,oFAAyB,CACzC,OAAQA,EAAI,MACd,CAAC,EACM,IAGF,EACT,CAKQ,oBACNC,EACApB,EACAqB,EACU,CAEV,IAAMC,EAAaD,GAAM,SAAS,KAAK,IAAI,CAAC,GAEtCE,EAA6B,CACjC,QAAS,MACT,MAAO,CACL,KAAAH,EACA,QAAApB,CACF,EACA,GAAIsB,CACN,EAEA,OAAO,IAAI,SAAS,KAAK,UAAUC,CAAa,EAAG,CACjD,OAAQ,IACR,QAAS,CACP,eAAgB,mBAChB,uBAAwB,YAC1B,CACF,CAAC,CACH,CAKA,WAAY,CACV,MAAO,CACL,iBAAkB,KAAK,QAAQ,KAC/B,WAAY,KAAK,OAAO,WACxB,cAAe,KAAK,oBAAsB,KAC1C,QAAS,KAAK,OAAO,cAAgB,KAAK,QAAU,OACpD,OAAQ,CACN,WAAY,KAAK,OAAO,WACxB,kBAAmB,KAAK,OAAO,kBAC/B,kBAAmB,KAAK,OAAO,kBAC/B,eAAgB,KAAK,OAAO,cAC9B,CACF,CACF,CAKA,mBAAoB,CAClB,IAAMC,EAAU,MAAM,KAAK,KAAK,QAAQ,OAAO,CAAC,EAAE,IAAKpC,IAAY,CACjE,GAAIA,EAAO,GACX,UAAWA,EAAO,UAClB,YAAaA,EAAO,YAAY,YAAY,EAC5C,aAAcA,EAAO,aAAa,YAAY,EAC9C,aAAcA,EAAO,aACrB,QAASA,EAAO,QAChB,UAAWA,EAAO,UAClB,cAAeA,EAAO,aACxB,EAAE,EAEF,MAAO,CACL,GAAG,KAAK,UAAU,EAClB,QAAAoC,EACA,UAAW,KAAK,UAAU,YAAY,CACxC,CACF,CAKA,MAAM,iBAAiBV,EAAeC,EAA8B,CAClE,IAAIf,EACJ,GAAI,CAEFA,EAAU,KAAK,UAAUe,CAAI,CAC/B,OAASrB,EAAO,CACd,WAAK,OAAO,MAAM,0DAAc,CAC9B,MAAOA,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,EAC5D,KAAAqB,CACF,CAAC,EACK,IAAI,MACR,2DACErB,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CACvD,EACF,CACF,CAEA,IAAM+B,EAAwB,CAAC,EAE/B,OAAW,CAACtC,EAAWC,CAAM,IAAK,KAAK,QAAQ,QAAQ,EAAG,CACxD,GAAI,CAACA,EAAO,SAAW,CAACA,EAAO,OAAQ,CACrCqC,EAAY,KAAKtC,CAAS,EAC1B,QACF,CAEA,GAAI,CACF,MAAM,KAAK,aAAaC,EAAO,OAAQ0B,EAAOd,CAAO,CACvD,OAASN,EAAO,CACd,KAAK,OAAO,KACV,qGAAqBP,CAAS,GAC9BO,CACF,EACAN,EAAO,QAAU,GACjBqC,EAAY,KAAKtC,CAAS,CAC5B,CACF,CAGA,QAAWA,KAAasC,EACtB,KAAK,uBAAuBtC,EAAW,kBAAkB,CAE7D,CAKA,SAAgB,CACd,KAAK,OAAO,KAAK,0CAAsB,EAGvC,KAAK,gBAAgB,EAGrB,OAAW,CAACA,CAAS,IAAK,KAAK,QAAQ,QAAQ,EAC7C,KAAK,uBAAuBA,EAAW,iBAAiB,EAI1D,KAAK,kBAAoB,KAEzB,KAAK,OAAO,KAAK,0CAAsB,CACzC,CACF,ICh5BA,IAyGauC,EAwKAC,GAiBAC,GAsBAC,GAuBAC,GA4CAC,GA3XbC,GAAAC,EAAA,kBAyGaP,EAAN,MAAMQ,UAAiB,KAAM,CAzGpC,MAyGoC,CAAAC,EAAA,iBAClB,KACA,SACA,SACA,QACA,UAEhB,YACEC,EACAC,EACAC,EAA0B,SAC1BC,EAA0B,SAC1BC,EAAiC,CAAC,EAClC,CACA,MAAMH,CAAO,EACb,KAAK,KAAO,WACZ,KAAK,KAAOD,EACZ,KAAK,SAAWE,EAChB,KAAK,SAAWC,EAChB,KAAK,UAAY,IAAI,KAAK,EAAE,YAAY,EAGxC,KAAK,QAAU,CACb,GAAGC,EACH,UAAW,KAAK,UAChB,SAAU,KAAK,SACf,SAAU,KAAK,SACf,MAAO,KAAK,KACd,EAGI,MAAM,mBACR,MAAM,kBAAkB,KAAMN,CAAQ,CAE1C,CAKA,QAAS,CACP,MAAO,CACL,KAAM,KAAK,KACX,KAAM,KAAK,KACX,QAAS,KAAK,QACd,SAAU,KAAK,SACf,SAAU,KAAK,SACf,QAAS,KAAK,QACd,UAAW,KAAK,SAClB,CACF,CAKA,OAAO,YACLE,EACAC,EACAG,EAAiC,CAAC,EACxB,CACV,OAAO,IAAIN,EACTE,EACAC,EACA,SACA,gBACAG,CACF,CACF,CAKA,OAAO,gBACLJ,EACAC,EACAG,EAAiC,CAAC,EACxB,CACV,OAAO,IAAIN,EACTE,EACAC,EACA,OACA,aACAG,CACF,CACF,CAKA,OAAO,eACLJ,EACAC,EACAG,EAAiC,CAAC,EACxB,CACV,OAAO,IAAIN,EACTE,EACAC,EACA,SACA,YACAG,CACF,CACF,CAKA,OAAO,YACLJ,EACAC,EACAG,EAAiC,CAAC,EACxB,CACV,OAAO,IAAIN,EACTE,EACAC,EACA,OACA,SACAG,CACF,CACF,CAKA,OAAO,gBACLJ,EACAC,EACAG,EAAiC,CAAC,EACxB,CACV,OAAO,IAAIN,EACTE,EACAC,EACA,MACA,aACAG,CACF,CACF,CAKA,OAAO,UACLC,EACAC,EAA4B,iBAC5BH,EAA0B,SAChB,CACV,OAAO,IAAIL,EACTQ,EACAD,EAAM,QACN,SACAF,EACA,CACE,MAAOE,EAAM,MACb,QAAS,CAAE,cAAeA,EAAM,IAAK,CACvC,CACF,CACF,CACF,EAaad,GAAN,KAAkD,CAjRzD,MAiRyD,CAAAQ,EAAA,4BACvD,UAAUM,EAAuB,CAC/B,MAAO,EAAEA,aAAiBf,EAC5B,CAEA,OAAOe,EAAcE,EAAyB,CAC5C,OAAOjB,EAAS,UACde,EACA,iBACA,QACF,CACF,CACF,EAKab,GAAN,KAAiD,CAlSxD,MAkSwD,CAAAO,EAAA,2BACtD,UAAUM,EAAuB,CAC/B,OACEA,EAAM,QAAQ,SAAS,cAAI,GAC3BA,EAAM,QAAQ,SAAS,QAAQ,GAC/BA,EAAM,QAAQ,SAAS,MAAM,GAC7BA,EAAM,QAAQ,SAAS,cAAI,CAE/B,CAEA,OAAOA,EAAcE,EAAyB,CAC5C,OAAOjB,EAAS,YACd,iBACA,6BAASe,EAAM,OAAO,GACtB,CAAE,QAAAE,CAAQ,CACZ,CACF,CACF,EAKad,GAAN,KAAqD,CAxT5D,MAwT4D,CAAAM,EAAA,+BAC1D,UAAUM,EAAuB,CAC/B,OACEA,EAAM,QAAQ,SAAS,cAAI,GAC3BA,EAAM,QAAQ,SAAS,YAAY,GACnCA,EAAM,QAAQ,SAAS,SAAS,GAChCA,EAAM,QAAQ,SAAS,cAAc,GACrCA,EAAM,QAAQ,SAAS,WAAW,CAEtC,CAEA,OAAOA,EAAcE,EAAyB,CAC5C,OAAOjB,EAAS,gBACd,oBACA,6BAASe,EAAM,OAAO,GACtB,CAAE,QAAAE,CAAQ,CACZ,CACF,CACF,EAKab,GAAN,KAA2B,CA/UlC,MA+UkC,CAAAK,EAAA,6BACxB,SAA2B,CAAC,EAEpC,aAAc,CAEZ,KAAK,gBAAgB,IAAIP,EAAoB,EAC7C,KAAK,gBAAgB,IAAIC,EAAwB,EACjD,KAAK,gBAAgB,IAAIF,EAAqB,CAChD,CAKA,gBAAgBiB,EAA6B,CAC3C,KAAK,SAAS,QAAQA,CAAO,CAC/B,CAKA,YAAYH,EAAcE,EAAyB,CAEjD,GAAIF,aAAiBf,EACnB,OAAOe,EAIT,QAAWG,KAAW,KAAK,SACzB,GAAIA,EAAQ,UAAUH,CAAK,EAAG,CAC5B,IAAMI,EAASD,EAAQ,OAAOH,EAAOE,CAAO,EAC5C,GAAIE,EACF,OAAOA,CAEX,CAIF,OAAO,IAAIlB,GAAoB,EAAE,OAAOc,EAAOE,CAAO,CACxD,CACF,EAKaZ,GAAqB,IAAID,KC3XtC,IAsIagB,GAw9BIC,GA9lCjBC,GAAAC,EAAA,kBAMAC,IACAC,KAKAC,IACAC,KAyHaP,GAAN,KAA0B,CAtIjC,MAsIiC,CAAAQ,EAAA,4BACrB,OACF,kBACA,cAER,YACEC,EACAC,EACA,CACA,KAAK,OAASC,EACd,KAAK,kBAAoBF,EACzB,KAAK,cAAgBC,CACvB,CAKU,oBACRE,EACAC,EACAC,EACAC,EACkB,CAClB,MAAO,CACL,MAAO,CACL,KAAAH,EACA,QAAAC,EACA,QAASC,EAAa,CAAE,WAAAA,EAAY,GAAGC,CAAQ,EAAIA,CACrD,CACF,CACF,CAKU,YACRC,EACAC,EACAC,EACU,CACV,GAAIF,aAAiBG,EACnB,YAAK,OAAO,MAAM,WAAY,CAAE,MAAAH,EAAO,UAAAC,EAAW,QAAAC,CAAQ,CAAC,EACpDF,EAGT,GAAIA,aAAiB,MAAO,CAC1B,IAAII,EAGJ,OACEJ,EAAM,QAAQ,SAAS,gCAAO,GAC9BA,EAAM,QAAQ,SAAS,WAAW,EAElCI,EAAWD,EAAS,+BAElBH,EAAM,QACN,CAAE,UAAAC,EAAW,QAAAC,CAAQ,CACvB,EAEAF,EAAM,QAAQ,SAAS,oBAAK,GAC5BA,EAAM,QAAQ,SAAS,gBAAgB,EAEvCI,EAAWD,EAAS,oCAElBH,EAAM,QACN,CAAE,UAAAC,EAAW,QAAAC,CAAQ,CACvB,EAEAF,EAAM,QAAQ,SAAS,cAAI,GAC3BA,EAAM,QAAQ,SAAS,QAAQ,EAE/BI,EAAWD,EAAS,6BAElBH,EAAM,QACN,CAAE,UAAAC,EAAW,QAAAC,CAAQ,CACvB,EAEAF,EAAM,QAAQ,SAAS,cAAI,GAC3BA,EAAM,QAAQ,SAAS,YAAY,EAEnCI,EAAWD,EAAS,oCAElBH,EAAM,QACN,CAAE,UAAAC,EAAW,QAAAC,CAAQ,CACvB,EAEAE,EAAWD,EAAS,6BAElBH,EAAM,QACN,CAAE,UAAAC,EAAW,QAAAC,EAAS,MAAOF,EAAM,KAAM,CAC3C,EAGF,KAAK,OAAO,MAAM,WAAY,CAAE,MAAOI,EAAU,UAAAH,EAAW,QAAAC,CAAQ,CAAC,EAC9DE,CACT,CAGA,IAAMA,EAAWD,EAAS,6BAExB,OAAOH,CAAK,EACZ,CAAE,UAAAC,EAAW,QAAAC,CAAQ,CACvB,EACA,YAAK,OAAO,MAAM,WAAY,CAAE,MAAOE,EAAU,UAAAH,EAAW,QAAAC,CAAQ,CAAC,EAC9DE,CACT,CAKU,sBACRC,EACAR,EACuB,CACvB,MAAO,CACL,QAAS,GACT,KAAAQ,EACA,QAAAR,CACF,CACF,CAKQ,uBACNS,EACAC,EACkB,CAElB,GAAI,YAAaA,EAEf,MAAO,CACL,KAAAD,EACA,KAAM,QACN,QAASC,EAAO,QAChB,KAAMA,EAAO,MAAQ,CAAC,EACtB,IAAKA,EAAO,KAAO,CAAC,CACtB,EAEF,GAAI,SAAUA,GAAUA,EAAO,OAAS,MAEtC,MAAO,CACL,KAAAD,EACA,KAAM,MACN,IAAKC,EAAO,GACd,EAEF,GAAI,QAASA,EAEX,MAAO,CACL,KAAAD,EACA,KAAM,kBACN,IAAKC,EAAO,GACd,EAEF,MAAM,IAAI,MAAM,qDAAa,KAAK,UAAUA,CAAM,CAAC,EAAE,CACvD,CASA,MAAM,aAAaC,EAA+B,CAChD,IAAMC,EAAY,KAAK,IAAI,EACrBC,EAAc,MAAMF,EAAE,IAAI,KAAK,EAErC,KAAK,OAAO,KAAK,eAAgB,CAC/B,YAAAE,EACA,OAAQ,OACR,KAAM,kBACR,CAAC,EAED,GAAI,CAEF,GAAI,eAAgBA,EAAa,CAE/B,IAAMC,EAAeD,EACfE,EAAS,MAAM,KAAK,mBAAmBD,CAAY,EAEnDE,EAAW,KAAK,IAAI,EAAIJ,EAC9B,YAAK,OAAO,KAAK,eAAgB,CAC/B,MAAO,GACP,WAAYG,EAAO,WACnB,YAAaA,EAAO,YACpB,SAAAC,CACF,CAAC,EAEML,EAAE,KAAK,KAAK,sBAAsBI,EAAQA,EAAO,OAAO,EAAG,GAAG,CACvE,CAEA,IAAME,EAAgBJ,EAChB,CAAE,KAAAJ,EAAM,OAAAC,CAAO,EAAIO,EAEnBF,EAAS,MAAM,KAAK,mBAAmBN,EAAMC,CAAM,EAEnDM,EAAW,KAAK,IAAI,EAAIJ,EAC9B,KAAK,OAAO,KAAK,eAAgB,CAC/B,WAAYH,EACZ,WAAYM,EAAO,OAAO,QAAU,EACpC,SAAAC,EACA,OAAQD,EAAO,MACjB,CAAC,EAED,IAAMG,EAAkB,KAAK,sBAC3BH,EACA,0CACF,EACA,OAAOJ,EAAE,KAAKO,EAAiB,GAAG,CACpC,OAASf,EAAO,CACd,IAAMI,EAAW,KAAK,YAAYJ,EAAO,eAAgB,CACvD,YAAAU,CACF,CAAC,EAEKM,EAAgB,KAAK,oBACzBZ,EAAS,KACTA,EAAS,QACT,OACA,CAAE,MAAOA,EAAS,OAAQ,CAC5B,EAGIa,EAAa,IACjB,OAAIb,EAAS,WAAa,aACxBa,EAAa,IACJb,EAAS,WAAa,gBAC3BA,EAAS,OAAS,wBACpBa,EAAa,IAEbA,EAAa,IAENb,EAAS,WAAa,eAC/Ba,EAAa,KAGRT,EAAE,KAAKQ,EAAeC,CAAmC,CAClE,CACF,CAKA,MAAc,mBACZX,EACAC,EAC0B,CAC1B,KAAK,OAAO,KAAK,qBAAsB,CACrC,WAAYD,CACd,CAAC,EAGD,IAAMY,EAAmBC,GAAoB,mBAC3CZ,CACF,EAEA,GAAI,CAEF,IAAMa,EAAiBnC,GAAyB,oBAAoBqB,CAAI,EACxE,GAAI,CAACc,EAAe,QAAS,CAC3B,IAAMC,EAAkBlB,EAAS,uCAE/BiB,EAAe,OAAO,KAAK,IAAI,EAC/B,CAAE,WAAYd,EAAM,OAAQc,EAAe,MAAO,CACpD,EACA,WAAK,OAAO,MAAM,qBAAsB,CACtC,gBAAAC,EACA,WAAYf,EACZ,MAAO,iBACT,CAAC,EACKe,CACR,CAGA,GACEpC,GAAyB,mBAAmBqB,EAAM,KAAK,aAAa,EACpE,CACA,IAAMgB,EAAcnB,EAAS,oCAE3B,qCACA,CAAE,WAAYG,CAAK,CACrB,EACA,WAAK,OAAO,MAAM,qBAAsB,CACtC,YAAAgB,EACA,WAAYhB,EACZ,MAAO,iBACT,CAAC,EACKgB,CACR,CAGA,IAAMC,EACJtC,GAAyB,eAAeiC,CAAgB,EAC1D,GAAI,CAACK,EAAiB,QAAS,CAC7B,IAAMC,EAAcrB,EAAS,6BAE3BoB,EAAiB,OAAO,KAAK,IAAI,EACjC,CACE,WAAYjB,EACZ,OAAQY,EACR,OAAQK,EAAiB,MAC3B,CACF,EACA,WAAK,OAAO,MAAM,qBAAsB,CACtC,YAAAC,EACA,WAAYlB,EACZ,MAAO,mBACT,CAAC,EACKkB,CACR,CAGA,KAAK,cAAc,gBAAgBlB,EAAMY,CAAgB,EACzD,KAAK,OAAO,MAAM,iFAAiB,CAAE,WAAYZ,CAAK,CAAC,EAGvD,IAAMmB,EAAmB,KAAK,uBAC5BnB,EACAY,CACF,EACA,KAAK,kBAAkB,iBAAiBO,CAAgB,EACxD,MAAM,KAAK,kBAAkB,aAAanB,CAAI,EAC9C,KAAK,OAAO,MAAM,iCAAS,CAAE,WAAYA,CAAK,CAAC,EAG/C,IAAMoB,EAAgB,KAAK,iBAAiBpB,CAAI,EAC1CqB,EAAQ,KAAK,gBAAgBrB,CAAI,EAGvC,OAAAsB,EAAY,EAAE,UAAU,mBAAoB,CAC1C,WAAYtB,EACZ,OAAQY,EACR,MAAOS,EAAM,IAAKE,GAASA,EAAK,IAAI,EACpC,UAAW,IAAI,IACjB,CAAC,EAEM,CACL,GAAGH,EACH,MAAOC,EAAM,IAAKE,GAASA,EAAK,IAAI,CACtC,CACF,OAAS7B,EAAO,CACd,IAAMI,EAAW,KAAK,YAAYJ,EAAO,qBAAsB,CAC7D,WAAYM,EACZ,OAAQY,CACV,CAAC,EACD,WAAK,OAAO,MAAM,qBAAsB,CACtC,SAAAd,EACA,WAAYE,CACd,CAAC,EACKF,CACR,CACF,CAKQ,iBAAiBN,EAAqC,CAE5D,IAAMgC,EADS,KAAK,cAAc,UAAU,EAChB,WAAWhC,CAAU,EAEjD,GAAI,CAACgC,EACH,MAAO,CACL,KAAMhC,EACN,OAAQ,eACR,UAAW,GACX,MAAO,CAAC,EACR,OAAQ,CAAC,CACX,EAIF,GAAI,CAGF,IAAMiC,EAFgB,KACnB,kBAC2B,SAAS,IAAIjC,CAAU,EAErD,GAAIiC,GAAS,cAAc,EAAG,CAC5B,IAAMC,EAAeD,EAAQ,SAAS,EAAE,IAAKF,GAAeA,EAAK,IAAI,EAC/DI,EAAS,CACb,KAAMnC,EACN,OAAQ,YACR,UAAW,GACX,MAAOkC,EACP,YAAa,IAAI,KAAK,EAAE,YAAY,EACpC,OAAQF,CACV,EAGA,YAAK,yBAAyBhC,EAAYmC,CAAM,EACzCA,CACT,CACF,OAASjC,EAAO,CACd,KAAK,OAAO,MAAM,4BAAQF,CAAU,mCAAWE,CAAK,CACtD,CAEA,IAAMiC,EAAS,CACb,KAAMnC,EACN,OAAQ,eACR,UAAW,GACX,MAAO,CAAC,EACR,OAAQgC,CACV,EAGA,YAAK,yBAAyBhC,EAAYmC,CAAM,EACzCA,CACT,CAKQ,yBACNnC,EACAoC,EACM,CAEN,IAAMC,EAAiB,KAAK,kBAAkBrC,CAAU,EAExD,GAAIqC,GAAkBA,EAAe,SAAWD,EAAU,SACxD,KAAK,OAAO,KACV,gBAAMpC,CAAU,8BAAUqC,EAAe,MAAM,OAAOD,EAAU,MAAM,EACxE,EAGAN,EAAY,EAAE,UAAU,4BAA6B,CACnD,WAAA9B,EACA,UAAWqC,EAAe,OAC1B,UAAWD,EAAU,OACrB,UAAW,IAAI,KACf,OACEA,EAAU,SAAW,YACjB,yBACA,iBACR,CAAC,EAGGC,EAAe,QAAUD,EAAU,OAAO,CAC5C,IAAME,EAAaF,EAAU,MAAM,OAChCL,GAAS,CAACM,EAAe,MAAM,SAASN,CAAI,CAC/C,EACMQ,EAAeF,EAAe,MAAM,OACvCN,GAAS,CAACK,EAAU,MAAM,SAASL,CAAI,CAC1C,GAEIO,EAAW,OAAS,GAAKC,EAAa,OAAS,IACjDT,EAAY,EAAE,UAAU,2BAA4B,CAClD,WAAA9B,EACA,MAAOoC,EAAU,MACjB,WAAAE,EACA,aAAAC,EACA,UAAW,IAAI,IACjB,CAAC,CAEL,CAIF,KAAK,kBAAkBvC,EAAYoC,CAAS,CAC9C,CAKQ,kBAAkBpC,EAA4C,CAGpE,IAAMwC,EAAmB,KACzB,OAAKA,EAAiB,cACpBA,EAAiB,YAAc,IAAI,KAE9BA,EAAiB,YAAY,IAAIxC,CAAU,GAAK,IACzD,CAKQ,kBAAkBA,EAAoBmC,EAA+B,CAC3E,IAAMK,EAAmB,KACpBA,EAAiB,cACpBA,EAAiB,YAAc,IAAI,KAErCA,EAAiB,YAAY,IAAIxC,EAAYmC,CAAM,CACrD,CAKQ,gBAAgBnC,EAA4B,CAClD,GAAI,CAGF,IAAMiC,EAFgB,KACnB,kBAC2B,SAAS,IAAIjC,CAAU,EAErD,GAAIiC,GAAS,SACX,OAAOA,EAAQ,SAAS,CAE5B,OAAS/B,EAAO,CACd,KAAK,OAAO,MAAM,4BAAQF,CAAU,+CAAaE,CAAK,CACxD,CAEA,MAAO,CAAC,CACV,CAMA,MAAM,gBAAgBQ,EAA+B,CACnD,GAAI,CAEF,IAAMV,EAAaU,EAAE,IAAI,MAAM,YAAY,EAGrCY,EACJnC,GAAyB,oBAAoBa,CAAU,EACzD,GAAI,CAACsB,EAAe,QAAS,CAC3B,IAAMJ,EAAgB,KAAK,2CAEzBI,EAAe,OAAO,KAAK,IAAI,EAC/BtB,CACF,EACA,OAAOU,EAAE,KAAKQ,EAAe,GAAG,CAClC,CAGA,GACE,CAAC/B,GAAyB,mBACxBa,EACA,KAAK,aACP,EACA,CACA,IAAMkB,EAAgB,KAAK,uCAEzB,qCACAlB,CACF,EACA,OAAOU,EAAE,KAAKQ,EAAe,GAAG,CAClC,CAGA,IAAMgB,EAAe,KAAK,gBAAgBlC,CAAU,EAAE,IACnD+B,GAASA,EAAK,IACjB,EAGA,GAAI,CACF,MAAM,KAAK,kBAAkB,YAAY/B,CAAU,CACrD,OAASE,EAAO,CACd,KAAK,OAAO,KAAK,4BAAQF,CAAU,iBAAQE,CAAK,CAElD,CAGA,KAAK,kBAAkB,oBAAoBF,CAAU,EACrD,KAAK,cAAc,gBAAgBA,CAAU,EAG7C8B,EAAY,EAAE,UAAU,qBAAsB,CAC5C,WAAA9B,EACA,cAAekC,EACf,UAAW,IAAI,IACjB,CAAC,EAGD,IAAMjB,EAAkB,KAAK,sBAC3B,CACE,KAAMjB,EACN,UAAW,UACX,cAAekC,CACjB,EACA,0CACF,EACA,OAAOxB,EAAE,KAAKO,EAAiB,GAAG,CACpC,OAASf,EAAO,CAId,GAHA,KAAK,OAAO,MAAM,6CAAgBA,CAAK,EAGnCA,aAAiB,MAAO,CAC1B,GAAIA,EAAM,QAAQ,SAAS,gCAAO,EAAG,CACnC,IAAMgB,EAAgB,KAAK,uCAEzBhB,EAAM,OACR,EACA,OAAOQ,EAAE,KAAKQ,EAAe,GAAG,CAClC,CAEA,GAAIhB,EAAM,QAAQ,SAAS,0BAAM,EAAG,CAClC,IAAMgB,EAAgB,KAAK,2CAEzBhB,EAAM,OACR,EACA,OAAOQ,EAAE,KAAKQ,EAAe,GAAG,CAClC,CACF,CAGA,IAAMA,EAAgB,KAAK,oCAEzB,8DACA,OACA,CAAE,MAAOhB,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAE,CAClE,EACA,OAAOQ,EAAE,KAAKQ,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,mBAAmBR,EAA+B,CACtD,GAAI,CAEF,IAAMV,EAAaU,EAAE,IAAI,MAAM,YAAY,EAGrCY,EACJnC,GAAyB,oBAAoBa,CAAU,EACzD,GAAI,CAACsB,EAAe,QAAS,CAC3B,IAAMJ,EAAgB,KAAK,2CAEzBI,EAAe,OAAO,KAAK,IAAI,EAC/BtB,CACF,EACA,OAAOU,EAAE,KAAKQ,EAAe,GAAG,CAClC,CAGA,GACE,CAAC/B,GAAyB,mBACxBa,EACA,KAAK,aACP,EACA,CACA,IAAMkB,EAAgB,KAAK,uCAEzB,qCACAlB,CACF,EACA,OAAOU,EAAE,KAAKQ,EAAe,GAAG,CAClC,CAGA,IAAMU,EAAgB,KAAK,iBAAiB5B,CAAU,EAGhDiB,EAAkB,KAAK,sBAC3BW,EACA,sDACF,EACA,OAAOlB,EAAE,KAAKO,EAAiB,GAAG,CACpC,OAASf,EAAO,CAId,GAHA,KAAK,OAAO,MAAM,yDAAkBA,CAAK,EAGrCA,aAAiB,OACfA,EAAM,QAAQ,SAAS,gCAAO,EAAG,CACnC,IAAMgB,EAAgB,KAAK,uCAEzBhB,EAAM,OACR,EACA,OAAOQ,EAAE,KAAKQ,EAAe,GAAG,CAClC,CAIF,IAAMA,EAAgB,KAAK,qCAEzB,sFACA,OACA,CAAE,MAAOhB,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAE,CAClE,EACA,OAAOQ,EAAE,KAAKQ,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,eAAeR,EAA+B,CAClD,GAAI,CAGF,IAAM+B,EADS,KAAK,cAAc,UAAU,EAClB,YAAc,CAAC,EAGnCC,EAA6B,CAAC,EAEpC,OAAW,CAAC1C,EAAYgC,CAAY,IAAK,OAAO,QAAQS,CAAU,EAAG,CACnE,IAAMb,EAAgB,KAAK,iBAAiB5B,CAAU,EACtD0C,EAAQ,KAAKd,CAAa,CAC5B,CAGA,IAAMe,EAAsC,CAC1C,QAAAD,EACA,MAAOA,EAAQ,MACjB,EAGMzB,EAAkB,KAAK,sBAC3B0B,EACA,sDACF,EACA,OAAOjC,EAAE,KAAKO,EAAiB,GAAG,CACpC,OAASf,EAAO,CACd,KAAK,OAAO,MAAM,6CAAgBA,CAAK,EAGvC,IAAMgB,EAAgB,KAAK,qCAEzB,0EACA,OACA,CAAE,MAAOhB,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAE,CAClE,EACA,OAAOQ,EAAE,KAAKQ,EAAe,GAAG,CAClC,CACF,CAKA,MAAc,mBACZL,EACoC,CACpC,GAAM,CAAE,WAAA4B,CAAW,EAAI5B,EACjB+B,EAAc,OAAO,KAAKH,CAAU,EAO1C,GALA,KAAK,OAAO,KAAK,qBAAsB,CACrC,YAAaG,EAAY,OACzB,YAAAA,CACF,CAAC,EAEGA,EAAY,SAAW,EACzB,MAAMvC,EAAS,iCAEb,sFACF,EAGF,IAAMwC,EAAgC,CAAC,EACjCC,EAAqC,CAAC,EAGtCC,EAAmB,KAAK,qBAAqBN,CAAU,EAC7D,GAAI,CAACM,EAAiB,QACpB,MAAM1C,EAAS,iCAEb0C,EAAiB,OAAO,KAAK,IAAI,CACnC,EAGF,GAAI,CAEF,OAAW,CAAC/C,EAAYgC,CAAY,IAAK,OAAO,QAAQS,CAAU,EAAG,CAEnE,IAAMO,EAAyB3B,GAAoB,mBACjDW,CACF,EAEA,GAAI,CACF,IAAMlB,EAAS,MAAM,KAAK,mBACxBd,EACAgD,CACF,EAEAH,EAAQ,KAAK,CACX,KAAM7C,EACN,QAAS,GACT,OAAQgD,EACR,MAAOlC,EAAO,MACd,OAAQA,EAAO,MACjB,CAAC,EAEDgC,EAAyB,KAAK9C,CAAU,EAExC,KAAK,OAAO,MAAM,qEAAe,CAC/B,WAAAA,EACA,WAAYc,EAAO,OAAO,QAAU,CACtC,CAAC,CACH,OAASZ,EAAO,CACd,IAAMI,EAAW,KAAK,YAAYJ,EAAO,qBAAsB,CAC7D,WAAAF,EACA,aAAcgD,CAChB,CAAC,EAEDH,EAAQ,KAAK,CACX,KAAM7C,EACN,QAAS,GACT,MAAOM,EAAS,QAChB,OAAQ0C,CACV,CAAC,EAED,KAAK,OAAO,KAAK,qEAAe,CAC9B,WAAAhD,EACA,MAAOM,EAAS,OAClB,CAAC,CACH,CACF,CAGA,IAAM2C,EAAaH,EAAyB,OACtCI,EAAcN,EAAY,OAASK,EAGzC,GAAIA,IAAe,EACjB,MAAM5C,EAAS,yBAEb,kGACF,EAIFyB,EAAY,EAAE,UAAU,yBAA0B,CAChD,aAAcc,EAAY,OAC1B,WAAAK,EACA,YAAAC,EACA,yBAAAJ,EACA,QAAAD,EACA,UAAW,IAAI,IACjB,CAAC,EAED,IAAMM,EAAsC,CAC1C,QAASF,EAAa,EACtB,QACEA,IAAeL,EAAY,OACvB,gEAAcK,CAAU,sBACxB,kFAAiBA,CAAU,yCAAWC,CAAW,sBACvD,QAAAL,EACA,WAAAI,EACA,YAAAC,CACF,EAEA,YAAK,OAAO,KAAK,qBAAsB,CACrC,aAAcN,EAAY,OAC1B,WAAAK,EACA,YAAAC,CACF,CAAC,EAEMC,CACT,OAASjD,EAAO,CAMd,MAJI4C,EAAyB,OAAS,GACpC,MAAM,KAAK,iBAAiBA,CAAwB,EAGlD5C,aAAiBG,EACbH,EAEFG,EAAS,6BAEb,uEACEH,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CACvD,EACF,CACF,CACF,CAKQ,qBACNuC,EACkB,CAClB,IAAMW,EAAmB,CAAC,EAE1B,GAAI,CAACX,GAAc,OAAOA,GAAe,SACvC,OAAAW,EAAO,KAAK,uDAAoB,EACzB,CAAE,QAAS,GAAO,OAAAA,CAAO,EAGlC,IAAMR,EAAc,OAAO,KAAKH,CAAU,EAC1C,GAAIG,EAAY,SAAW,EACzB,OAAAQ,EAAO,KAAK,iDAAmB,EACxB,CAAE,QAAS,GAAO,OAAAA,CAAO,EAGlC,GAAIR,EAAY,OAAS,GACvB,OAAAQ,EAAO,KAAK,0FAAoB,EACzB,CAAE,QAAS,GAAO,OAAAA,CAAO,EAIlC,OAAW,CAACpD,EAAYgC,CAAY,IAAK,OAAO,QAAQS,CAAU,EAAG,CAEnE,IAAMnB,EACJnC,GAAyB,oBAAoBa,CAAU,EACzD,GAAI,CAACsB,EAAe,QAAS,CAC3B8B,EAAO,KACL,iBAAOpD,CAAU,+BAAWsB,EAAe,OAAO,KAAK,IAAI,CAAC,EAC9D,EACA,QACF,CAGA,GACEnC,GAAyB,mBACvBa,EACA,KAAK,aACP,EACA,CACAoD,EAAO,KAAK,iBAAOpD,CAAU,sBAAO,EACpC,QACF,CAGA,IAAMgD,EAAyB3B,GAAoB,mBACjDW,CACF,EAGMP,EAAmBtC,GAAyB,eAChD6D,CACF,EACKvB,EAAiB,SACpB2B,EAAO,KACL,iBAAOpD,CAAU,+BAAWyB,EAAiB,OAAO,KAAK,IAAI,CAAC,EAChE,CAEJ,CAEA,MAAO,CAAE,QAAS2B,EAAO,SAAW,EAAG,OAAAA,CAAO,CAChD,CAKA,MAAc,iBAAiBR,EAAsC,CACnE,KAAK,OAAO,KAAK,qEAAe,CAAE,YAAAA,CAAY,CAAC,EAE/C,IAAMS,EAA4B,CAAC,EAC7BC,EAA6B,CAAC,EAEpC,QAAWtD,KAAc4C,EACvB,GAAI,CAEF,GAAI,CACF,MAAM,KAAK,kBAAkB,YAAY5C,CAAU,CACrD,OAASE,EAAO,CACd,KAAK,OAAO,KAAK,8CAAWF,CAAU,iBAAQE,CAAK,CACrD,CAGA,KAAK,kBAAkB,oBAAoBF,CAAU,EACrD,KAAK,cAAc,gBAAgBA,CAAU,EAE7CqD,EAAgB,KAAKrD,CAAU,EAG/B8B,EAAY,EAAE,UAAU,sBAAuB,CAC7C,WAAA9B,EACA,UAAW,IAAI,IACjB,CAAC,CACH,OAASE,EAAO,CACd,IAAMI,EAAW,KAAK,YAAYJ,EAAO,mBAAoB,CAC3D,WAAAF,CACF,CAAC,EACDsD,EAAiB,KAAKtD,CAAU,EAEhC,KAAK,OAAO,MAAM,4BAAQA,CAAU,iBAAQM,EAAS,OAAO,CAC9D,CAGEgD,EAAiB,OAAS,EAC5B,KAAK,OAAO,KAAK,+DAAc,CAC7B,aAAcV,EAAY,OAC1B,gBAAiBS,EAAgB,OACjC,YAAaC,EAAiB,OAC9B,cAAeA,CACjB,CAAC,EAED,KAAK,OAAO,KAAK,mDAAY,CAC3B,aAAcV,EAAY,OAC1B,gBAAiBS,EAAgB,MACnC,CAAC,CAEL,CACF,GAKiBlE,GAAV,CAIE,SAASoE,EAAe9C,EAA2C,CACxE,IAAM2C,EAAmB,CAAC,EAG1B,GAAI,CAAC3C,GAAU,OAAOA,GAAW,SAC/B,OAAA2C,EAAO,KAAK,wDAAW,EAChB,CAAE,QAAS,GAAO,OAAAA,CAAO,EAIlC,GAAI,YAAa3C,GAEX,CAACA,EAAO,SAAW,OAAOA,EAAO,SAAY,WAC/C2C,EAAO,KAAK,gFAAe,EAEzB3C,EAAO,MAAQ,CAAC,MAAM,QAAQA,EAAO,IAAI,GAC3C2C,EAAO,KAAK,4CAAS,EAEnB3C,EAAO,KAAO,OAAOA,EAAO,KAAQ,UACtC2C,EAAO,KAAK,wDAAW,UAEhB,QAAS3C,EAAQ,EAEtB,CAACA,EAAO,KAAO,OAAOA,EAAO,KAAQ,WACvC2C,EAAO,KAAK,wEAAiB,EAE/B,GAAI,CACF,IAAI,IAAI3C,EAAO,GAAG,CACpB,MAAQ,CACN2C,EAAO,KAAK,8BAAU,CACxB,CACF,MACEA,EAAO,KAAK,sEAAyB,EAGvC,MAAO,CAAE,QAASA,EAAO,SAAW,EAAG,OAAAA,CAAO,CAChD,CApCOjE,EAAS,eAAAoE,EAAA7D,EAAA6D,EAAA,kBAyCT,SAASC,EAAoBhD,EAAgC,CAClE,IAAM4C,EAAmB,CAAC,EAE1B,MAAI,CAAC5C,GAAQ,OAAOA,GAAS,UAC3B4C,EAAO,KAAK,0EAAc,EACnB,CAAE,QAAS,GAAO,OAAAA,CAAO,KAG9B5C,EAAK,OAAS,GAAKA,EAAK,OAAS,KACnC4C,EAAO,KAAK,4FAAsB,EAG/B,mBAAmB,KAAK5C,CAAI,GAC/B4C,EAAO,KAAK,gIAAuB,EAG9B,CAAE,QAASA,EAAO,SAAW,EAAG,OAAAA,CAAO,EAChD,CAjBOjE,EAAS,oBAAAqE,EAAA9D,EAAA8D,EAAA,uBAsBT,SAASC,EACdjD,EACAZ,EACS,CACT,IAAMa,EAASb,EAAc,UAAU,EACvC,OAAOa,EAAO,YAAcD,KAAQC,EAAO,UAC7C,CANOtB,EAAS,mBAAAsE,EAAA/D,EAAA+D,EAAA,wBAnEDtE,KAAA,MC9lCjB,IAqBauE,GArBbC,GAAAC,EAAA,kBACAC,IAEAC,IAEAC,IAgBaL,GAAN,KAAkC,CArBzC,MAqByC,CAAAM,EAAA,oCAC/B,OACA,oBACA,cACA,SAER,YACEC,EACAC,EACA,CACA,KAAK,OAASC,EACd,KAAK,oBAAsBF,EAC3B,KAAK,cAAgBC,EACrB,KAAK,SAAWE,EAAY,CAC9B,CAMA,MAAM,cACJC,EACAC,EACAC,EACe,CACf,GAAI,CAUF,OATA,KAAK,OAAO,MAAM,wCAAoBD,EAAQ,IAAI,GAAI,CAAE,SAAAC,CAAS,CAAC,EAGlE,KAAK,SAAS,UAAU,6BAA8B,CACpD,KAAMD,EAAQ,KACd,KAAMA,EAAQ,KACd,SAAAC,CACF,CAAC,EAEOD,EAAQ,KAAM,CACpB,IAAK,YACH,MAAM,KAAK,gBAAgBD,EAAIE,CAAQ,EACvC,MAEF,IAAK,eACH,MAAM,KAAK,mBAAmBF,EAAIC,EAAQ,KAAMC,CAAQ,EACxD,MAEF,IAAK,YACH,MAAM,KAAK,gBAAgBF,EAAIE,CAAQ,EACvC,MAEF,IAAK,iBACH,MAAM,KAAK,qBAAqBF,EAAIE,CAAQ,EAC5C,MAEF,QACE,KAAK,OAAO,KAAK,0DAAuBD,EAAQ,IAAI,GAAI,CACtD,SAAAC,CACF,CAAC,EACD,KAAK,UACHF,EACA,uBACA,+CAAYC,EAAQ,IAAI,EAC1B,CACJ,CACF,OAASE,EAAO,CACd,KAAK,OAAO,MAAM,oDAAsBF,EAAQ,IAAI,GAAIE,CAAK,EAC7D,KAAK,UACHH,EACA,2BACAG,aAAiB,MAAQA,EAAM,QAAU,sCAC3C,CACF,CACF,CAMA,MAAc,gBAAgBH,EAASE,EAAiC,CACtE,KAAK,sBAAsB,sBAAuB,iBAAiB,EAEnE,GAAI,CACF,IAAME,EAASC,EAAc,UAAU,EACvC,KAAK,OAAO,MAAM,4DAA+B,CAAE,SAAAH,CAAS,CAAC,EAC7DF,EAAG,KAAK,KAAK,UAAU,CAAE,KAAM,SAAU,KAAMI,CAAO,CAAC,CAAC,CAC1D,OAASD,EAAO,CACd,KAAK,OAAO,MAAM,4DAA+BA,CAAK,EACtD,KAAK,UACHH,EACA,oBACAG,aAAiB,MAAQA,EAAM,QAAU,sCAC3C,CACF,CACF,CAMA,MAAc,mBACZH,EACAM,EACAJ,EACe,CACf,KAAK,sBAAsB,yBAA0B,iBAAiB,EAEtE,GAAI,CAQF,GANAG,EAAc,eAAeC,CAAU,EAGvCD,EAAc,aAAaC,CAAU,EAGjCA,EAAW,gBACb,OAAW,CAACC,EAAYC,CAAW,IAAK,OAAO,QAC7CF,EAAW,eACb,EACE,OAAW,CAACG,EAAUC,CAAU,IAAK,OAAO,QAC1CF,EAAY,KACd,EACEH,EAAc,eACZE,EACAE,EACAC,EAAW,MACb,EAKN,KAAK,OAAO,MAAM,kDAAqB,CAAE,SAAAR,CAAS,CAAC,EACnDF,EAAG,KAAK,KAAK,UAAU,CAAE,KAAM,iBAAkB,QAAS,EAAK,CAAC,CAAC,CACnE,OAASG,EAAO,CACd,KAAK,OAAO,MAAM,kDAAqBA,CAAK,EAC5C,KAAK,UACHH,EACA,sBACAG,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CACvD,CACF,CACF,CAMA,MAAc,gBAAgBH,EAASE,EAAiC,CACtE,KAAK,sBAAsB,sBAAuB,iBAAiB,EAEnE,GAAI,CACF,IAAMS,EAAS,KAAK,cAAc,cAAc,EAChDX,EAAG,KAAK,KAAK,UAAU,CAAE,KAAM,SAAU,KAAMW,EAAO,MAAO,CAAC,CAAC,EAC/D,KAAK,OAAO,MAAM,4DAA+B,CAAE,SAAAT,CAAS,CAAC,CAC/D,OAASC,EAAO,CACd,KAAK,OAAO,MAAM,4DAA+BA,CAAK,EACtD,KAAK,UACHH,EACA,oBACAG,aAAiB,MAAQA,EAAM,QAAU,sCAC3C,CACF,CACF,CAMA,MAAc,qBAAqBH,EAASE,EAAiC,CAC3E,KAAK,sBACH,2BACA,4BACF,EAEA,GAAI,CACF,KAAK,OAAO,KAAK,8DAAuB,CAAE,SAAAA,CAAS,CAAC,EAGpD,KAAK,SAAS,UAAU,4BAA6B,CACnD,YAAa,UACb,OAAQ,aAAaA,CAAQ,GAC7B,MAAO,EACP,QAAS,EACT,UAAW,KAAK,IAAI,CACtB,CAAC,EAGD,KAAK,cAAc,oBAAoB,YAAY,CACrD,OAASC,EAAO,CACd,KAAK,OAAO,MAAM,8DAAuBA,CAAK,EAC9C,KAAK,UACHH,EACA,wBACAG,aAAiB,MAAQA,EAAM,QAAU,kDAC3C,CACF,CACF,CAKQ,UAAUH,EAASY,EAAcX,EAAuB,CAC9D,GAAI,CACF,IAAMY,EAAgB,CACpB,KAAM,QACN,MAAO,CACL,KAAAD,EACA,QAAAX,EACA,UAAW,KAAK,IAAI,CACtB,CACF,EACAD,EAAG,KAAK,KAAK,UAAUa,CAAa,CAAC,CACvC,OAASV,EAAO,CACd,KAAK,OAAO,MAAM,oDAAaA,CAAK,CACtC,CACF,CAKQ,sBAAsBW,EAAiBC,EAA2B,CACxE,KAAK,OAAO,KACV,gBAAgBD,CAAO,2DAAcC,CAAW,eAClD,CACF,CAKA,MAAM,gBAAgBf,EAASE,EAAiC,CAC9D,GAAI,CACF,KAAK,OAAO,MAAM,+DAAc,CAAE,SAAAA,CAAS,CAAC,EAG5C,IAAME,EAASC,EAAc,UAAU,EACvCL,EAAG,KAAK,KAAK,UAAU,CAAE,KAAM,eAAgB,KAAMI,CAAO,CAAC,CAAC,EAG9D,IAAMO,EAAS,KAAK,cAAc,cAAc,EAChDX,EAAG,KAAK,KAAK,UAAU,CAAE,KAAM,eAAgB,KAAMW,EAAO,MAAO,CAAC,CAAC,EAGjEA,EAAO,SACTX,EAAG,KACD,KAAK,UAAU,CAAE,KAAM,gBAAiB,KAAMW,EAAO,OAAQ,CAAC,CAChE,EAGF,KAAK,OAAO,MAAM,mDAAY,CAAE,SAAAT,CAAS,CAAC,CAC5C,OAASC,EAAO,CACd,KAAK,OAAO,MAAM,oDAAaA,CAAK,EACpC,KAAK,UACHH,EACA,qBACAG,aAAiB,MAAQA,EAAM,QAAU,kDAC3C,CACF,CACF,CAKA,uBAAuBD,EAAwB,CAC7C,KAAK,OAAO,KAAK,+CAAYA,CAAQ,EAAE,EACvC,KAAK,oBAAoB,iBAAiBA,CAAQ,CACpD,CAKA,oBAAoBF,EAASE,EAAwB,CACnD,KAAK,OAAO,KAAK,mCAAUA,CAAQ,EAAE,EACrC,KAAK,oBAAoB,eAAeA,EAAUF,CAAE,CACtD,CACF,ICpSA,OAAS,SAAAgB,OAAa,gBAAtB,IA6BaC,GA7BbC,GAAAC,EAAA,kBACAC,KAEAC,IAEAC,IAwBaL,GAAN,KAAwB,CA7B/B,MA6B+B,CAAAM,EAAA,0BACrB,OACA,cACA,SAER,YAAYC,EAA8B,CACxC,KAAK,OAASC,EACd,KAAK,cAAgBD,EACrB,KAAK,SAAWE,EAAY,CAC9B,CAKQ,oBACNC,EACAC,EACAC,EACkB,CAClB,MAAO,CACL,MAAO,CACL,KAAAF,EACA,QAAAC,EACA,QAAAC,CACF,CACF,CACF,CAKQ,sBACNC,EACAF,EACuB,CACvB,MAAO,CACL,QAAS,GACT,KAAAE,EACA,QAAAF,CACF,CACF,CAMA,MAAM,eAAeG,EAA+B,CAClD,GAAI,CACF,YAAK,OAAO,KAAK,kDAAU,EAG3B,KAAK,SAAS,UAAU,4BAA6B,CACnD,YAAa,UACb,OAAQ,WACR,MAAO,EACP,QAAS,EACT,UAAW,KAAK,IAAI,CACtB,CAAC,EAGD,KAAK,cAAc,oBAAoB,YAAY,EAGnD,WAAW,SAAY,CACrB,GAAI,CACF,MAAM,KAAK,eAAe,EAE1B,WAAW,IAAM,CACf,KAAK,cAAc,oBAAoB,WAAW,CACpD,EAAG,GAAI,CACT,OAASC,EAAO,CACd,KAAK,OAAO,MAAM,wCAAWA,CAAK,EAClC,KAAK,cAAc,oBACjB,SACAA,aAAiB,MAAQA,EAAM,QAAU,0BAC3C,CACF,CACF,EAAG,GAAG,EAECD,EAAE,KAAK,KAAK,sBAAsB,KAAM,4CAAS,CAAC,CAC3D,OAASC,EAAO,CACd,KAAK,OAAO,MAAM,oDAAaA,CAAK,EACpC,IAAMC,EAAgB,KAAK,oBACzB,wBACAD,aAAiB,MAAQA,EAAM,QAAU,kDAC3C,EACA,OAAOD,EAAE,KAAKE,EAAe,GAAG,CAClC,CACF,CAKA,MAAc,gBAAgC,CAC5C,KAAK,OAAO,KAAK,8CAAgB,EAEjC,GAAI,CAIF,IAAMC,EAAS,MAFG,MAAMC,GAAgB,GACP,IAAI,gBAAgB,EACjB,UAAU,EAE9C,GAAI,CAACD,EAAO,QAAS,CACnB,KAAK,OAAO,KAAK,8EAAkB,EAIrBlB,GAAM,UADF,CAAC,QAAS,UAAU,EACI,CACxC,SAAU,GACV,MAAO,SACP,IAAK,CACH,GAAG,QAAQ,IACX,mBAAoB,QAAQ,IAAI,oBAAsB,QAAQ,IAAI,CACpE,CACF,CAAC,EACK,MAAM,EACZ,KAAK,OAAO,KAAK,4DAAe,EAChC,MACF,CAGA,IAAMoB,EAAWF,EAAO,OAAS,SAG3BG,EAAc,CAAC,SAAS,EAC1BD,GACFC,EAAY,KAAK,UAAU,EAIfrB,GAAM,UAAWqB,EAAa,CAC1C,SAAU,GACV,MAAO,SACP,IAAK,CACH,GAAG,QAAQ,IACX,mBAAoB,QAAQ,IAAI,oBAAsB,QAAQ,IAAI,CACpE,CACF,CAAC,EAEK,MAAM,EACZ,KAAK,OAAO,KAAK,4DAAe,CAClC,OAASL,EAAO,CACd,WAAK,OAAO,MAAM,wCAAWA,CAAK,EAC5BA,CACR,CACF,CAMA,MAAM,YAAYD,EAA+B,CAC/C,GAAI,CACF,YAAK,OAAO,KAAK,kDAAU,EAIbf,GAAM,UADH,CAAC,MAAM,EACiB,CACvC,SAAU,GACV,MAAO,SACP,IAAK,CACH,GAAG,QAAQ,IACX,mBAAoB,QAAQ,IAAI,oBAAsB,QAAQ,IAAI,CACpE,CACF,CAAC,EAEK,MAAM,EACZ,KAAK,OAAO,KAAK,4DAAe,EAEzBe,EAAE,KAAK,KAAK,sBAAsB,KAAM,4CAAS,CAAC,CAC3D,OAASC,EAAO,CACd,KAAK,OAAO,MAAM,oDAAaA,CAAK,EACpC,IAAMC,EAAgB,KAAK,oBACzB,qBACAD,aAAiB,MAAQA,EAAM,QAAU,kDAC3C,EACA,OAAOD,EAAE,KAAKE,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,aAAaF,EAA+B,CAChD,GAAI,CACF,YAAK,OAAO,KAAK,kDAAU,EAIbf,GAAM,UADF,CAAC,QAAS,UAAU,EACI,CACxC,SAAU,GACV,MAAO,SACP,IAAK,CACH,GAAG,QAAQ,IACX,mBAAoB,QAAQ,IAAI,oBAAsB,QAAQ,IAAI,CACpE,CACF,CAAC,EAEK,MAAM,EACZ,KAAK,OAAO,KAAK,4DAAe,EAEzBe,EAAE,KAAK,KAAK,sBAAsB,KAAM,4CAAS,CAAC,CAC3D,OAASC,EAAO,CACd,KAAK,OAAO,MAAM,oDAAaA,CAAK,EACpC,IAAMC,EAAgB,KAAK,oBACzB,sBACAD,aAAiB,MAAQA,EAAM,QAAU,kDAC3C,EACA,OAAOD,EAAE,KAAKE,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,iBAAiBF,EAA+B,CACpD,GAAI,CACF,KAAK,OAAO,MAAM,8DAAY,EAI9B,IAAMG,EAAS,MAFG,MAAMC,GAAgB,GACP,IAAI,gBAAgB,EACjB,UAAU,EAE9C,YAAK,OAAO,MAAM,kDAAU,EACrBJ,EAAE,KAAK,KAAK,sBAAsBG,CAAM,CAAC,CAClD,OAASF,EAAO,CACd,KAAK,OAAO,MAAM,oDAAaA,CAAK,EACpC,IAAMC,EAAgB,KAAK,oBACzB,4BACAD,aAAiB,MAAQA,EAAM,QAAU,kDAC3C,EACA,OAAOD,EAAE,KAAKE,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,iBAAiBF,EAA+B,CACpD,GAAI,CACF,KAAK,OAAO,MAAM,0EAAc,EAGhC,IAAMO,EAAS,CACb,OAAQ,UACR,UAAW,KAAK,IAAI,EACpB,OAAQ,QAAQ,OAAO,EACvB,OAAQ,QAAQ,YAAY,EAC5B,QAAS,QAAQ,OACnB,EAEA,YAAK,OAAO,MAAM,8DAAY,EACvBP,EAAE,KAAK,KAAK,sBAAsBO,CAAM,CAAC,CAClD,OAASN,EAAO,CACd,KAAK,OAAO,MAAM,gEAAeA,CAAK,EACtC,IAAMC,EAAgB,KAAK,oBACzB,4BACAD,aAAiB,MAAQA,EAAM,QAAU,8DAC3C,EACA,OAAOD,EAAE,KAAKE,EAAe,GAAG,CAClC,CACF,CACF,ICtSA,OAAS,cAAAM,OAAkB,KAC3B,OAAS,YAAAC,OAAgB,cACzB,OAAS,WAAAC,GAAS,QAAAC,MAAY,OAC9B,OAAS,iBAAAC,OAAqB,MAH9B,IAWaC,GAXbC,GAAAC,EAAA,kBAKAC,IAMaH,GAAN,KAAwB,CAX/B,MAW+B,CAAAI,EAAA,0BACrB,OACA,QAAyB,KAEjC,aAAc,CACZ,KAAK,OAASC,EACd,KAAK,kBAAkB,CACzB,CAKQ,mBAA0B,CAChC,GAAI,CAEF,IAAMC,EAAYT,GAAQE,GAAc,YAAY,GAAG,CAAC,EAExD,KAAK,OAAO,MAAM,yCAAWO,CAAS,EAAE,EAIxC,IAAMC,EAAmB,CAKvBT,EAAKQ,EAAW,KAAM,KAAM,KAAM,UAAU,EAC5CR,EAAKQ,EAAW,KAAM,KAAM,UAAU,EACtCR,EAAKQ,EAAW,KAAM,UAAU,EAGhCR,EAAKQ,EAAW,KAAM,KAAM,OAAQ,WAAY,MAAM,EACtDR,EAAKQ,EAAW,KAAM,OAAQ,WAAY,MAAM,EAGhDR,EAAKQ,EAAW,KAAM,KAAM,OAAQ,UAAU,EAC9CR,EAAKQ,EAAW,KAAM,OAAQ,UAAU,EAGxCR,EAAKQ,EAAW,KAAM,KAAM,MAAO,MAAM,EACzCR,EAAKQ,EAAW,KAAM,MAAO,MAAM,EAGnCR,EAAKQ,EAAW,KAAM,KAAM,KAAK,EACjCR,EAAKQ,EAAW,KAAM,KAAK,EAG3BR,EAAKQ,EAAW,KAAM,KAAM,KAAM,OAAQ,WAAY,MAAM,EAC5DR,EAAKQ,EAAW,KAAM,KAAM,KAAM,OAAQ,UAAU,EACpDR,EAAKQ,EAAW,KAAM,KAAM,KAAM,MAAO,MAAM,EAC/CR,EAAKQ,EAAW,KAAM,KAAM,KAAM,KAAK,CACzC,EAGA,KAAK,QACHC,EAAiB,KAAMC,GAAM,CAC3B,IAAMC,EAASd,GAAWa,CAAC,EAC3B,YAAK,OAAO,MAAM,4BAAQA,CAAC,KAAKC,EAAS,eAAO,oBAAK,EAAE,EAChDA,CACT,CAAC,GAAK,KAEJ,KAAK,QACP,KAAK,OAAO,MAAM,qDAAa,KAAK,OAAO,EAAE,GAE7C,KAAK,OAAO,KAAK,wDAAW,EAC5B,KAAK,OAAO,MAAM,kCAAUF,CAAgB,EAEhD,OAASG,EAAO,CACd,KAAK,OAAO,MAAM,sEAAgBA,CAAK,CACzC,CACF,CAMA,MAAM,iBAAiBC,EAA+B,CACpD,IAAMC,EAAW,IAAI,IAAID,EAAE,IAAI,GAAG,EAAE,SAEpC,GAAI,CAGF,GAFA,KAAK,OAAO,MAAM,qDAAaC,CAAQ,EAAE,EAErC,CAAC,KAAK,QACR,OAAO,KAAK,gBAAgBD,EAAG,wDAAW,EAI5C,IAAIE,EAAWD,EAMf,GALIC,IAAa,MACfA,EAAW,eAITA,EAAS,SAAS,IAAI,EACxB,YAAK,OAAO,KAAK,qDAAaA,CAAQ,EAAE,EACjCF,EAAE,KAAK,YAAa,GAAG,EAGhC,IAAMG,EAAWhB,EAAK,KAAK,QAASe,CAAQ,EAG5C,GAAI,CAAClB,GAAWmB,CAAQ,EAAG,CAEzB,IAAMC,EAAYjB,EAAK,KAAK,QAAS,YAAY,EACjD,OAAIH,GAAWoB,CAAS,GACtB,KAAK,OAAO,MAAM,sCAAuBH,CAAQ,EAAE,EAC5C,KAAK,UAAUD,EAAGI,EAAW,WAAW,IAGjD,KAAK,OAAO,MAAM,mCAAUD,CAAQ,EAAE,EAC/BH,EAAE,KAAK,YAAa,GAAG,EAChC,CAGA,IAAMK,EAAc,KAAK,eAAeF,CAAQ,EAEhD,YAAK,OAAO,MACV,yCAAWA,CAAQ,mBAAmBE,CAAW,EACnD,EACO,KAAK,UAAUL,EAAGG,EAAUE,CAAW,CAChD,OAASN,EAAO,CACd,YAAK,OAAO,MAAM,qDAAaE,CAAQ,KAAMF,CAAK,EAC3CC,EAAE,KAAK,wBAAyB,GAAG,CAC5C,CACF,CAKA,MAAc,UACZA,EACAE,EACAG,EACmB,CACnB,GAAI,CACF,IAAMC,EAAU,MAAMrB,GAASiB,CAAQ,EAGvC,OACEG,EAAY,WAAW,OAAO,GAC9BA,EAAY,SAAS,YAAY,GACjCA,EAAY,SAAS,MAAM,EAEpBL,EAAE,KAAKM,EAAQ,SAAS,EAAG,IAAK,CAAE,eAAgBD,CAAY,CAAC,EAGjEL,EAAE,KAAK,IAAI,WAAWM,CAAO,EAAG,IAAK,CAC1C,eAAgBD,CAClB,CAAC,CACH,OAASN,EAAO,CACd,WAAK,OAAO,MAAM,yCAAWG,CAAQ,GAAIH,CAAK,EACxCA,CACR,CACF,CAKQ,eAAeG,EAA0B,CAC/C,IAAMK,EAAML,EAAS,MAAM,GAAG,EAAE,IAAI,GAAG,YAAY,EA2BnD,MAzB6C,CAC3C,KAAM,YACN,IAAK,YACL,GAAI,yBACJ,IAAK,yBACL,IAAK,WACL,KAAM,mBACN,IAAK,YACL,IAAK,aACL,KAAM,aACN,IAAK,YACL,IAAK,gBACL,IAAK,eACL,KAAM,YACN,MAAO,aACP,IAAK,WACL,IAAK,gCACL,IAAK,kBACL,IAAK,aACL,IAAK,kBACL,IAAK,kBACL,IAAK,oBACL,GAAI,kBACN,EAEoBK,GAAO,EAAE,GAAK,0BACpC,CAKQ,gBAAgBP,EAAYQ,EAA2B,CAC7D,IAAMC,EAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kDA6CaD,CAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MActC,OAAOR,EAAE,KAAKS,CAAS,CACzB,CAKA,oBAA8B,CAC5B,OAAO,KAAK,UAAY,MAAQzB,GAAW,KAAK,OAAO,CACzD,CAKA,YAA4B,CAC1B,OAAO,KAAK,OACd,CAKA,qBAA4B,CAC1B,KAAK,kBAAkB,CACzB,CACF,IC9RA,IAyBa0B,GAzBbC,GAAAC,EAAA,kBACAC,IAwBaH,GAAN,KAAuB,CAzB9B,MAyB8B,CAAAI,EAAA,yBACpB,OACA,cAER,YAAYC,EAA8B,CACxC,KAAK,OAASC,EACd,KAAK,cAAgBD,CACvB,CAKQ,oBACNE,EACAC,EACAC,EACkB,CAClB,MAAO,CACL,MAAO,CACL,KAAAF,EACA,QAAAC,EACA,QAAAC,CACF,CACF,CACF,CAKQ,sBACNC,EACAF,EACuB,CACvB,MAAO,CACL,QAAS,GACT,KAAAE,EACA,QAAAF,CACF,CACF,CAMA,MAAM,UAAUG,EAA+B,CAC7C,GAAI,CACF,KAAK,OAAO,MAAM,kDAAU,EAC5B,IAAMC,EAAS,KAAK,cAAc,cAAc,EAChD,YAAK,OAAO,MAAM,sCAAQ,EACnBD,EAAE,KAAK,KAAK,sBAAsBC,CAAM,CAAC,CAClD,OAASC,EAAO,CACd,KAAK,OAAO,MAAM,wCAAWA,CAAK,EAClC,IAAMC,EAAgB,KAAK,oBACzB,oBACAD,aAAiB,MAAQA,EAAM,QAAU,sCAC3C,EACA,OAAOF,EAAE,KAAKG,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,gBAAgBH,EAA+B,CACnD,GAAI,CACF,KAAK,OAAO,MAAM,oEAAa,EAC/B,IAAMI,EAAe,KAAK,cAAc,gBAAgB,EACxD,YAAK,OAAO,MAAM,wDAAW,EACtBJ,EAAE,KAAK,KAAK,sBAAsBI,CAAY,CAAC,CACxD,OAASF,EAAO,CACd,KAAK,OAAO,MAAM,0DAAcA,CAAK,EACrC,IAAMC,EAAgB,KAAK,oBACzB,2BACAD,aAAiB,MAAQA,EAAM,QAAU,wDAC3C,EACA,OAAOF,EAAE,KAAKG,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,iBAAiBH,EAA+B,CACpD,GAAI,CACF,KAAK,OAAO,MAAM,8DAAY,EAC9B,IAAMK,EAAgB,KAAK,cAAc,iBAAiB,EAC1D,YAAK,OAAO,MAAM,kDAAU,EACrBL,EAAE,KAAK,KAAK,sBAAsBK,CAAa,CAAC,CACzD,OAASH,EAAO,CACd,KAAK,OAAO,MAAM,oDAAaA,CAAK,EACpC,IAAMC,EAAgB,KAAK,oBACzB,4BACAD,aAAiB,MAAQA,EAAM,QAAU,kDAC3C,EACA,OAAOF,EAAE,KAAKG,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,qBAAqBH,EAA+B,CACxD,GAAI,CACF,KAAK,OAAO,MAAM,oEAAa,EAC/B,IAAMM,EAAY,KAAK,cAAc,kBAAkB,EACvD,YAAK,OAAO,MAAM,+CAAYA,CAAS,EAAE,EAClCN,EAAE,KAAK,KAAK,sBAAsB,CAAE,UAAAM,CAAU,CAAC,CAAC,CACzD,OAASJ,EAAO,CACd,KAAK,OAAO,MAAM,0DAAcA,CAAK,EACrC,IAAMC,EAAgB,KAAK,oBACzB,gCACAD,aAAiB,MAAQA,EAAM,QAAU,wDAC3C,EACA,OAAOF,EAAE,KAAKG,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,iBAAiBH,EAA+B,CACpD,GAAI,CACF,KAAK,OAAO,MAAM,0EAAc,EAChC,IAAMO,EAAgB,KAAK,cAAc,iBAAiB,EAC1D,YAAK,OAAO,MAAM,8DAAY,EACvBP,EAAE,KAAK,KAAK,sBAAsB,CAAE,cAAAO,CAAc,CAAC,CAAC,CAC7D,OAASL,EAAO,CACd,KAAK,OAAO,MAAM,gEAAeA,CAAK,EACtC,IAAMC,EAAgB,KAAK,oBACzB,uBACAD,aAAiB,MAAQA,EAAM,QAAU,8DAC3C,EACA,OAAOF,EAAE,KAAKG,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,oBAAoBH,EAA+B,CACvD,GAAI,CACF,KAAK,OAAO,MAAM,yEAAkB,EACpC,IAAMQ,EAAU,KAAK,cAAc,oBAAoB,EACvD,YAAK,OAAO,MAAM,6DAAgB,EAC3BR,EAAE,KAAK,KAAK,sBAAsB,CAAE,QAAAQ,CAAQ,CAAC,CAAC,CACvD,OAASN,EAAO,CACd,KAAK,OAAO,MAAM,+DAAmBA,CAAK,EAC1C,IAAMC,EAAgB,KAAK,oBACzB,gCACAD,aAAiB,MAAQA,EAAM,QAAU,6DAC3C,EACA,OAAOF,EAAE,KAAKG,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,mBAAmBH,EAA+B,CACtD,GAAI,CACF,KAAK,OAAO,MAAM,oEAAa,EAC/B,IAAMS,EAAe,MAAMT,EAAE,IAAI,KAAK,EAGtC,GAAI,CAACS,GAAgB,OAAOA,GAAiB,SAAU,CACrD,IAAMN,EAAgB,KAAK,oBACzB,uBACA,gFACF,EACA,OAAOH,EAAE,KAAKG,EAAe,GAAG,CAClC,CAEA,YAAK,cAAc,iBAAiBM,EAAc,UAAU,EAC5D,KAAK,OAAO,KAAK,wDAAW,EAErBT,EAAE,KAAK,KAAK,sBAAsB,KAAM,wDAAW,CAAC,CAC7D,OAASE,EAAO,CACd,KAAK,OAAO,MAAM,0DAAcA,CAAK,EACrC,IAAMC,EAAgB,KAAK,oBACzB,6BACAD,aAAiB,MAAQA,EAAM,QAAU,wDAC3C,EACA,OAAOF,EAAE,KAAKG,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,oBAAoBH,EAA+B,CACvD,GAAI,CACF,KAAK,OAAO,MAAM,yEAAkB,EACpC,GAAM,CAAE,QAAAQ,CAAQ,EAAI,MAAMR,EAAE,IAAI,KAAK,EAGrC,GAAI,CAAC,MAAM,QAAQQ,CAAO,EAAG,CAC3B,IAAML,EAAgB,KAAK,oBACzB,uBACA,0DACF,EACA,OAAOH,EAAE,KAAKG,EAAe,GAAG,CAClC,CAEA,YAAK,cAAc,oBAAoBK,CAAO,EAC9C,KAAK,OAAO,KAAK,6DAAgB,EAE1BR,EAAE,KACP,KAAK,sBAAsB,KAAM,6DAAgB,CACnD,CACF,OAASE,EAAO,CACd,KAAK,OAAO,MAAM,+DAAmBA,CAAK,EAC1C,IAAMC,EAAgB,KAAK,oBACzB,kCACAD,aAAiB,MAAQA,EAAM,QAAU,6DAC3C,EACA,OAAOF,EAAE,KAAKG,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,YAAYH,EAA+B,CAC/C,GAAI,CACF,YAAK,OAAO,KAAK,kDAAU,EAC3B,KAAK,cAAc,MAAM,EACzB,KAAK,OAAO,KAAK,sCAAQ,EAClBA,EAAE,KAAK,KAAK,sBAAsB,KAAM,sCAAQ,CAAC,CAC1D,OAASE,EAAO,CACd,KAAK,OAAO,MAAM,wCAAWA,CAAK,EAClC,IAAMC,EAAgB,KAAK,oBACzB,qBACAD,aAAiB,MAAQA,EAAM,QAAU,sCAC3C,EACA,OAAOF,EAAE,KAAKG,EAAe,GAAG,CAClC,CACF,CACF,IC9QA,IAUYO,GAVZC,GAAAC,EAAA,kBAUYF,QAEVA,EAAA,IAAM,MAENA,EAAA,KAAO,OAEPA,EAAA,KAAO,OAEPA,EAAA,SAAW,WARDA,QAAA,MCgBZ,OAAOG,OAAS,MAChB,OAAOC,OAAW,QA3BlB,IAmEaC,GAnEbC,GAAAC,EAAA,kBAKAC,IAKAC,KAIAC,IAWAC,KA0CaN,GAAN,KAAqB,CAnE5B,MAmE4B,CAAAO,EAAA,uBAClB,OACA,IAER,aAAc,CACZ,KAAK,OAASC,EACd,KAAK,IAAM,IAAIV,GAAI,CAAE,UAAW,GAAM,QAAS,EAAK,CAAC,CACvD,CAKQ,sBACNW,EACAC,EACkB,CAClB,MAAO,CACL,QAAS,GACT,KAAAD,EACA,QAAAC,CACF,CACF,CAKQ,oBAAoBC,EAAcD,EAAmC,CAC3E,MAAO,CACL,QAAS,GACT,MAAO,CACL,KAAAC,EACA,QAAAD,CACF,CACF,CACF,CAKQ,sBAAsBC,EAAsB,CAElD,OAAIA,GAAQ,KAAOA,EAAO,IACjBA,EAGF,GACT,CAKQ,mBACNC,EACAH,EACAI,EACU,CACV,OAAOD,EAAE,KAAKH,EAAMI,CAAkC,CACxD,CAMA,MAAM,SAASD,EAA+B,CAC5C,GAAI,CACF,KAAK,OAAO,KAAK,kDAAU,EAG3B,IAAME,EAA+B,MAAMF,EAAE,IAAI,KAAK,EAChD,CAAE,YAAAG,EAAa,SAAAC,EAAU,KAAAC,CAAK,EAAIH,EAGxC,GAAI,CAACC,GAAe,CAACC,EAAU,CAC7B,IAAME,EAAgB,KAAK,oBACzB,kBACA,kEACF,EACA,OAAON,EAAE,KAAKM,EAAe,GAAG,CAClC,CAEA,KAAK,OAAO,KACV,yCAAWH,CAAW,IAAIC,CAAQ,sBAClC,KAAK,UAAUC,CAAI,CACrB,EAGA,IAAME,EAAiBP,EAAE,IAAI,mBAAmB,EAChD,GAAI,CAACO,EAAgB,CACnB,IAAMD,EAAgB,KAAK,oBACzB,0BACA,kHACF,EACA,OAAON,EAAE,KAAKM,EAAe,GAAG,CAClC,CAGA,MAAM,KAAK,uBAAuBC,EAAgBJ,EAAaC,CAAQ,EAGnED,IAAgB,aAClB,MAAM,KAAK,2BACTI,EACAH,EACAC,GAAQ,CAAC,CACX,EAIF,IAAIG,EACJ,GAAIL,IAAgB,YAElBK,EAAS,MAAMD,EAAe,SAASH,EAAUC,GAAQ,CAAC,EAAG,CAC3D,QAAS,GACX,CAAC,MACI,CAEL,IAAMI,EAAU,GAAGN,CAAW,KAAKC,CAAQ,GAC3CI,EAAS,MAAMD,EAAe,SAASE,EAASJ,GAAQ,CAAC,CAAC,CAC5D,CAIA,OAAOL,EAAE,KAAK,KAAK,sBAAsBQ,EAAQ,sCAAQ,CAAC,CAC5D,OAASE,EAAO,CACd,KAAK,OAAO,MAAM,wCAAWA,CAAK,EAElC,IAAMC,EACJD,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,EACnDE,EAAY,kBAGZD,EAAa,SAAS,oBAAK,EAC7BC,EAAY,4BAEZD,EAAa,SAAS,oBAAK,GAC3BA,EAAa,SAAS,oBAAK,EAE3BC,EAAY,wBACHD,EAAa,SAAS,0BAAM,EACrCC,EAAY,gBACHD,EAAa,SAAS,sCAAQ,EACvCC,EAAY,oBAEZD,EAAa,SAAS,WAAW,GACjCA,EAAa,SAAS,WAAW,EAEjCC,EAAY,mBAEZD,EAAa,SAAS,4CAAS,GAC/BA,EAAa,SAAS,8BAAU,EAEhCC,EAAY,qBACHD,EAAa,SAAS,cAAI,IACnCC,EAAY,iBAGd,IAAMN,EAAgB,KAAK,oBAAoBM,EAAWD,CAAY,EACtE,OAAOX,EAAE,KAAKM,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,eAAeN,EAA+B,CAClD,GAAI,CAIF,GAHA,KAAK,OAAO,KAAK,qFAAoB,EAGjC,CAACa,EAAc,aAAa,EAAG,CACjC,IAAMP,EAAgB,KAAK,oBACzB,mBACA,wHACF,EACA,OAAON,EAAE,KAAKM,EAAe,GAAG,CAClC,CAGA,IAAIQ,EAA+B,CAAC,EAChCC,EAAa,GAEjB,GAAI,CACFD,EAAcD,EAAc,kBAAkB,EAC9CE,EAAaF,EAAc,cAAc,CAC3C,OAASH,EAAO,CACd,KAAK,OAAO,MAAM,2EAAqBA,CAAK,EAC5C,IAAMJ,EAAgB,KAAK,oBACzB,qBACA,qDAAaI,aAAiB,MAAQA,EAAM,QAAU,0BAAM,EAC9D,EACA,OAAOV,EAAE,KAAKM,EAAe,GAAG,CAClC,CAGA,GAAI,CAACQ,GAAeA,EAAY,SAAW,EACzC,YAAK,OAAO,KAAK,uDAAe,EACzBd,EAAE,KACP,KAAK,sBACH,CACE,MAAO,CAAC,EACR,WAAY,EACZ,WAAAe,CACF,EACA,uDACF,CACF,EAKF,GAAI,CADYF,EAAc,uBAAuBC,CAAW,EAClD,CACZ,KAAK,OAAO,KAAK,yEAAkB,EACnC,IAAMR,EAAgB,KAAK,oBACzB,sBACA,6JACF,EACA,OAAON,EAAE,KAAKM,EAAe,GAAG,CAClC,CAEA,YAAK,OAAO,KACV,uFAAsBQ,EAAY,MAAM,qBAC1C,EAEOd,EAAE,KACP,KAAK,sBACH,CACE,MAAOc,EACP,WAAYA,EAAY,OACxB,WAAAC,CACF,EACA,yEACF,CACF,CACF,OAASL,EAAO,CACd,KAAK,OAAO,MAAM,2EAAqBA,CAAK,EAE5C,IAAMJ,EAAgB,KAAK,oBACzB,yBACAI,aAAiB,MAAQA,EAAM,QAAU,yEAC3C,EACA,OAAOV,EAAE,KAAKM,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,UAAUN,EAA+B,CAC7C,GAAI,CACF,KAAK,OAAO,MAAM,8DAAY,EAG9B,IAAMgB,EACHhB,EAAE,IAAI,MAAM,QAAQ,GAAwC,MAE3DiB,EAAyB,CAAC,EAE9B,OAAQD,EAAQ,CACd,IAAK,UAEHC,EAAQJ,EAAc,kBAAkB,EACxC,KAAK,OAAO,MAAM,0DAAaI,EAAM,MAAM,SAAI,EAC/C,MAEF,IAAK,WAEHA,EAAQ,MAAM,KAAK,iBAAiB,EACpC,KAAK,OAAO,MAAM,0DAAaA,EAAM,MAAM,SAAI,EAC/C,MAEF,QAEEA,EAAQJ,EAAc,kBAAkB,EACxC,KAAK,OAAO,MAAM,oDAAYI,EAAM,MAAM,SAAI,EAC9C,KACJ,CAGA,IAAMC,EAAe,CACnB,KAAMD,EACN,MAAOA,EAAM,MACf,EAEA,OAAOjB,EAAE,KACP,KAAK,sBACHkB,EACA,yDAAYF,CAAM,QACpB,CACF,CACF,OAASN,EAAO,CACd,KAAK,OAAO,MAAM,oDAAaA,CAAK,EAEpC,IAAMJ,EAAgB,KAAK,oBACzB,mBACA,kDACF,EACA,OAAON,EAAE,KAAKM,EAAe,GAAG,CAClC,CACF,CAMA,MAAc,kBAA6C,CACzD,GAAI,CAEF,IAAMa,EAAeN,EAAc,kBAAkB,EAC/CO,EAAmB,IAAI,IAAID,EAAa,IAAKE,GAASA,EAAK,IAAI,CAAC,EAIhEC,EAAiB,MADF,IAAIC,GAAgB,EACC,kBAAkB,EAGtDC,EAASX,EAAc,UAAU,EACjCY,EAAoB,IAAI,IAAI,OAAO,KAAKD,EAAO,YAAc,CAAC,CAAC,CAAC,EAGhEE,EAAiC,CAAC,EAExC,QAAWC,KAAcL,EAAgB,CAEvC,GAAIF,EAAiB,IAAIO,EAAW,IAAI,EACtC,SAIF,IAAMxB,EAAcwB,EAAW,KAAK,MAAM,IAAI,EAAE,CAAC,EAGjD,GAAI,CAACF,EAAkB,IAAItB,CAAW,EAAG,CAEvC,KAAK,OAAO,MACV,gBAAMwB,EAAW,IAAI,wCAAexB,CAAW,mDACjD,EACA,QACF,CAGA,IAAMyB,EAA4B,CAChC,KAAMD,EAAW,KACjB,YAAaA,EAAW,aAAe,GACvC,YAAaA,EAAW,aAAe,CAAC,EACxC,QAAS,CACP,KAAM,MACN,OAAQ,CACN,YAAaxB,EACb,SAAUwB,EAAW,KAAK,MAAM,IAAI,EAAE,MAAM,CAAC,EAAE,KAAK,IAAI,CAC1D,CACF,CACF,EACAD,EAAc,KAAKE,CAAU,CAC/B,CAEA,YAAK,OAAO,MACV,UAAKN,EAAe,MAAM,2DAAcI,EAAc,MAAM,uCAC9D,EACOA,CACT,OAAShB,EAAO,CACd,YAAK,OAAO,MAAM,0DAAcA,CAAK,EAE9B,CAAC,CACV,CACF,CAMA,MAAc,uBACZH,EACAJ,EACAC,EACe,CAEf,GAAID,IAAgB,YAAa,CAE/B,GAAI,CAACI,EAAe,iBAAiBH,CAAQ,EAAG,CAC9C,IAAMyB,EAAiBtB,EACpB,kBAAkB,EAClB,IAAKc,GAASA,EAAK,IAAI,EAE1B,MAAIQ,EAAe,SAAW,EACtB,IAAI,MACR,2BAAiBzB,CAAQ,yLAC3B,EAGI,IAAI,MACR,2BAAiBA,CAAQ,wEAA2ByB,EAAe,KAAK,IAAI,CAAC,oGAC/E,CACF,CAGA,GAAI,CAEF,IAAMC,EADcvB,EAAe,kBAAkB,EACtB,KAAMc,GAASA,EAAK,OAASjB,CAAQ,EAEhE0B,GAAc,CAACA,EAAW,aAC5B,KAAK,OAAO,KAAK,2BAAiB1B,CAAQ,wCAAU,EAGlD0B,GAAc,CAACA,EAAW,aAC5B,KAAK,OAAO,KAAK,2BAAiB1B,CAAQ,oDAAY,CAE1D,OAASM,EAAO,CACd,WAAK,OAAO,MACV,wCAAoBN,CAAQ,oCAC5BM,CACF,EACM,IAAI,MACR,2BAAiBN,CAAQ,kIAC3B,CACF,CAEA,MACF,CACF,CAMA,MAAc,2BACZG,EACAH,EACAC,EACe,CACf,GAAI,CAGF,IAAMyB,EADcvB,EAAe,kBAAkB,EACtB,KAAMc,GAASA,EAAK,OAASjB,CAAQ,EAEpE,GAAI,CAAC0B,EACH,MAAM,IAAI,MAAM,2BAAiB1B,CAAQ,sBAAO,EAIlD,GAAI,CAAC0B,EAAW,YAAa,CAC3B,KAAK,OAAO,KACV,2BAAiB1B,CAAQ,kFAC3B,EACA,MACF,CAGA,IAAM2B,EAAW,KAAK,IAAI,QAAQD,EAAW,WAAW,EAGxD,GAAI,CAFUC,EAAS1B,CAAI,EAEf,CAyBV,IAAMM,EAAe,0CAvBNoB,EAAS,QAAU,CAAC,GACN,IAAKrB,GAAU,CAC1C,IAAMsB,EAAOtB,EAAM,cAAgBA,EAAM,YAAc,GACjDZ,EAAUY,EAAM,SAAW,2BAEjC,GAAIA,EAAM,UAAY,WAEpB,MAAO,yCADiBA,EAAM,QAAQ,iBAAmB,0BACxB,GAGnC,GAAIA,EAAM,UAAY,OAAQ,CAC5B,IAAMuB,EAAevB,EAAM,QAAQ,MAAQ,2BAC3C,MAAO,gBAAMsB,CAAI,gDAAaC,CAAY,EAC5C,CAEA,GAAIvB,EAAM,UAAY,OAAQ,CAC5B,IAAMwB,EAAgBxB,EAAM,QAAQ,eAAiB,CAAC,EACtD,MAAO,gBAAMsB,CAAI,sDAAcE,EAAc,KAAK,IAAI,CAAC,EACzD,CAEA,MAAO,gBAAMF,CAAI,IAAIlC,CAAO,EAC9B,CAAC,EAE6C,KAAK,IAAI,CAAC,GACxD,WAAK,OAAO,MACV,2BAAiBM,CAAQ,0CACzBO,CACF,EAEM,IAAI,MAAMA,CAAY,CAC9B,CAEA,KAAK,OAAO,MAAM,2BAAiBP,CAAQ,wCAAU,CACvD,OAASM,EAAO,CACd,MAAIA,aAAiB,OAASA,EAAM,QAAQ,SAAS,sCAAQ,EACrDA,GAGR,KAAK,OAAO,MAAM,wCAAoBN,CAAQ,oCAAYM,CAAK,EACzD,IAAI,MACR,uEAAgBA,aAAiB,MAAQA,EAAM,QAAU,0BAAM,EACjE,EACF,CACF,CAOA,MAAM,cAAcV,EAA+B,CACjD,GAAI,CACF,KAAK,OAAO,KAAK,oEAAa,EAE9B,IAAME,EAAc,MAAMF,EAAE,IAAI,KAAK,EAGrC,OAAI,KAAK,mBAAmBE,CAAW,EAE9B,MAAM,KAAK,uBAChBF,EACAE,CACF,EAGK,MAAM,KAAK,0BAChBF,EACAE,CACF,CACF,OAASQ,EAAO,CACd,KAAK,OAAO,MAAM,0DAAcA,CAAK,EAGrC,GAAM,CAAE,WAAAT,EAAY,cAAAK,CAAc,EAAI,KAAK,mBAAmBI,CAAK,EACnE,OAAO,KAAK,mBACVV,EACAM,EACA,KAAK,sBAAsBL,CAAU,CACvC,CACF,CACF,CAKQ,mBAAmBkC,EAA6C,CACtE,OACEA,IAAS,MACT,OAAOA,GAAS,UAChB,CAAC,MAAM,QAAQA,CAAI,GACnB,SAAUA,GACV,SAAUA,CAEd,CAKA,MAAc,uBACZnC,EACAoC,EACmB,CACnB,GAAM,CAAE,KAAAC,EAAM,KAAAxC,CAAK,EAAIuC,EAKvB,GAHA,KAAK,OAAO,KAAK,yFAAmBC,CAAI,EAAE,EAGtC,CAAC,OAAO,OAAOC,EAAQ,EAAE,SAASD,CAAI,EAAG,CAC3C,IAAM/B,EAAgB,KAAK,oBACzB,oBACA,qDAAa+B,CAAI,yCAAW,OAAO,OAAOC,EAAQ,EAAE,KAAK,IAAI,CAAC,EAChE,EACA,OAAOtC,EAAE,KAAKM,EAAe,GAAG,CAClC,CAGA,OAAQ+B,EAAM,CACZ,UACE,OAAO,MAAM,KAAK,iBAAiBrC,EAAGH,CAAmB,EAE3D,WACE,OAAO,MAAM,KAAK,kBAAkBG,EAAGH,CAAwB,EAEjE,WACA,eAAwB,CACtB,IAAM0C,EAAoB,KAAK,oBAC7B,4BACA,4BAAQF,CAAI,gFACd,EACA,OAAOrC,EAAE,KAAKuC,EAAmB,GAAG,CACtC,CAEA,QAAS,CACP,IAAMC,EAAuB,KAAK,oBAChC,oBACA,+CAAYH,CAAI,EAClB,EACA,OAAOrC,EAAE,KAAKwC,EAAsB,GAAG,CACzC,CACF,CACF,CAKA,MAAc,0BACZxC,EACAoC,EACmB,CACnB,KAAK,OAAO,KAAK,wGAAmB,EAEpC,GAAM,CAAE,SAAAK,EAAU,WAAAC,EAAY,kBAAAC,EAAmB,gBAAAC,CAAgB,EAC/DR,EAGIS,EAAiB,KAAK,iBAC1BJ,EACAC,EACAC,CACF,EACA,GAAIE,EACF,OAAO,KAAK,mBACV7C,EACA6C,EAAe,cACf,KAAK,sBAAsBA,EAAe,UAAU,CACtD,EAIF,IAAMxB,EAAO,KAAK,sBAChBoB,EACAC,EACAC,EACAC,CACF,EAGA,OAAA/B,EAAc,iBAAiBQ,CAAI,EAEnC,KAAK,OAAO,KAAK,2DAAcA,EAAK,IAAI,EAAE,EAEnCrB,EAAE,KACP,KAAK,sBAAsB,CAAE,KAAAqB,CAAK,EAAG,iBAAOA,EAAK,IAAI,4BAAQ,CAC/D,CACF,CAKA,MAAc,iBACZrB,EACAH,EACmB,CACnB,GAAM,CAAE,YAAAM,EAAa,SAAAC,EAAU,WAAAsC,EAAY,kBAAAC,CAAkB,EAAI9C,EAKjE,GAHA,KAAK,OAAO,KAAK,8CAAgBM,CAAW,IAAIC,CAAQ,EAAE,EAGtD,CAACD,GAAe,CAACC,EAAU,CAC7B,IAAME,EAAgB,KAAK,oBACzB,yBACA,4DACF,EACA,OAAON,EAAE,KAAKM,EAAe,GAAG,CAClC,CAGA,IAAMC,EAAiBP,EAAE,IAAI,mBAAmB,EAChD,GAAI,CAACO,EAAgB,CACnB,IAAMD,EAAgB,KAAK,oBACzB,0BACA,kHACF,EACA,OAAON,EAAE,KAAKM,EAAe,GAAG,CAClC,CAGA,GAAI,CACF,MAAM,KAAK,uBAAuBC,EAAgBJ,EAAaC,CAAQ,CACzE,OAASM,EAAO,CACd,IAAMC,GACJD,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,EACjDJ,GAAgB,KAAK,oBACzB,4BACAK,EACF,EACA,OAAOX,EAAE,KAAKM,GAAe,GAAG,CAClC,CAIA,IAAMwC,EAAc,MADC,IAAIvB,GAAgB,EACF,kBAAkB,EAGnDwB,EAAe,GAAG5C,CAAW,KAAKC,CAAQ,GAC1CuB,EAAamB,EAAY,KAAMzB,GAASA,EAAK,OAAS0B,CAAY,EAExE,GAAI,CAACpB,EAAY,CACf,IAAMrB,EAAgB,KAAK,oBACzB,iBACA,2DAAcH,CAAW,IAAIC,CAAQ,EACvC,EACA,OAAOJ,EAAE,KAAKM,EAAe,GAAG,CAClC,CAGA,IAAM0C,EAAgBN,GAAcK,EAG9BE,EAAgBpC,EAAc,kBAAkB,EAGtD,GAFsB,IAAI,IAAIoC,EAAc,IAAK5B,GAASA,EAAK,IAAI,CAAC,EAElD,IAAI2B,CAAa,EAAG,CACpC,IAAM1C,EAAgB,KAAK,oBACzB,qBACA,6BAAS0C,CAAa,8FACxB,EACA,OAAOhD,EAAE,KAAKM,EAAe,GAAG,CAClC,CAGA,IAAMe,GAAsB,CAC1B,KAAM2B,EACN,YACEL,GACAhB,EAAW,aACX,qBAAWxB,CAAW,IAAIC,CAAQ,GACpC,YAAauB,EAAW,aAAe,CAAC,EACxC,QAAS,CACP,KAAM,MACN,OAAQ,CACN,YAAAxB,EACA,SAAAC,CACF,CACF,EACA,MAAO,CACL,WAAY,EACZ,aAAcjB,GAAM,EAAE,OAAO,qBAAqB,CACpD,CACF,EAGA0B,EAAc,iBAAiBQ,EAAI,EAGnC,KAAK,OAAO,KACV,2HAA2ClB,CAAW,IAAIC,CAAQ,EACpE,EAGA,IAAM8C,GAAoBrC,EAAc,qBAAqBV,CAAW,EAEpE+C,IAAmB,WAErBA,GAAkB9C,CAAQ,EAAE,OAAS,GAGrCS,EAAc,wBAAwBV,EAAa+C,EAAiB,EAEpE,KAAK,OAAO,KACV,4EAA+B/C,CAAW,IAAIC,CAAQ,EACxD,GAGF,KAAK,OAAO,KAAK,8CAAgB4C,CAAa,EAAE,EAEhD,IAAM9B,GAAgC,CACpC,KAAAG,GACA,SAAU2B,EACV,eACA,QAAS7D,GAAM,EAAE,OAAO,qBAAqB,CAC/C,EAEA,OAAOa,EAAE,KACP,KAAK,sBACHkB,GACA,qBAAW8B,CAAa,4BAC1B,CACF,CACF,CAKA,MAAc,kBACZhD,EACAH,EACmB,CACnB,GAAM,CAAE,SAAA4C,EAAU,WAAAC,EAAY,kBAAAC,EAAmB,gBAAAC,CAAgB,EAAI/C,EAErE,KAAK,OAAO,KAAK,+CAAiB4C,EAAS,aAAa,EAAE,EAG1D,IAAMI,EAAiB,KAAK,iBAC1BJ,EACAC,EACAC,CACF,EACA,GAAIE,EACF,OAAO,KAAK,mBACV7C,EACA6C,EAAe,cACf,KAAK,sBAAsBA,EAAe,UAAU,CACtD,EAIF,IAAMxB,EAAO,KAAK,sBAChBoB,EACAC,EACAC,EACAC,CACF,EAGA/B,EAAc,iBAAiBQ,CAAI,EAEnC,KAAK,OAAO,KAAK,+CAAiBA,EAAK,IAAI,EAAE,EAE7C,IAAMH,EAAgC,CACpC,KAAAG,EACA,SAAUA,EAAK,KACf,gBACA,QAASlC,GAAM,EAAE,OAAO,qBAAqB,CAC/C,EAEA,OAAOa,EAAE,KACP,KAAK,sBACHkB,EACA,sBAAYG,EAAK,IAAI,4BACvB,CACF,CACF,CAMA,MAAM,iBAAiBrB,EAA+B,CACpD,GAAI,CACF,IAAMI,EAAWJ,EAAE,IAAI,MAAM,UAAU,EAEvC,GAAI,CAACI,EAAU,CACb,IAAME,EAAgB,KAAK,oBACzB,kBACA,kDACF,EACA,OAAON,EAAE,KAAKM,EAAe,GAAG,CAClC,CAEA,KAAK,OAAO,KAAK,mFAAkBF,CAAQ,EAAE,EAE7C,IAAMF,EAAc,MAAMF,EAAE,IAAI,KAAK,EAGrC,GAAI,CAACE,GAAe,OAAOA,GAAgB,SAAU,CACnD,IAAMI,EAAgB,KAAK,oBACzB,kBACA,8DACF,EACA,OAAON,EAAE,KAAKM,EAAe,GAAG,CAClC,CAGA,GAAI,KAAK,mBAAmBJ,CAAW,EAErC,OAAO,MAAM,KAAK,0BAChBF,EACAI,EACAF,CACF,EAIF,IAAMI,EAAgB,KAAK,oBACzB,kBACA,gFACF,EACA,OAAON,EAAE,KAAKM,EAAe,GAAG,CAClC,OAASI,EAAO,CACd,KAAK,OAAO,MAAM,sEAAgBA,CAAK,EAGvC,GAAM,CAAE,WAAAT,EAAY,cAAAK,CAAc,EAAI,KAAK,sBAAsBI,CAAK,EACtE,OAAO,KAAK,mBACVV,EACAM,EACA,KAAK,sBAAsBL,CAAU,CACvC,CACF,CACF,CAKA,MAAc,0BACZD,EACAI,EACAgC,EACmB,CACnB,GAAM,CAAE,KAAAC,EAAM,KAAAxC,CAAK,EAAIuC,EAKvB,GAHA,KAAK,OAAO,KAAK,yFAAmBC,CAAI,EAAE,EAGtC,CAAC,OAAO,OAAOC,EAAQ,EAAE,SAASD,CAAI,EAAG,CAC3C,IAAM/B,EAAgB,KAAK,oBACzB,oBACA,qDAAa+B,CAAI,yCAAW,OAAO,OAAOC,EAAQ,EAAE,KAAK,IAAI,CAAC,EAChE,EACA,OAAOtC,EAAE,KAAKM,EAAe,GAAG,CAClC,CAGA,OAAQ+B,EAAM,CACZ,WACE,OAAO,MAAM,KAAK,qBAChBrC,EACAI,EACAP,CACF,EAEF,UACA,WACA,eAAwB,CACtB,IAAMS,EAAgB,KAAK,oBACzB,4BACA,4BAAQ+B,CAAI,yGACd,EACA,OAAOrC,EAAE,KAAKM,EAAe,GAAG,CAClC,CAEA,QAAS,CACP,IAAMA,EAAgB,KAAK,oBACzB,oBACA,+CAAY+B,CAAI,EAClB,EACA,OAAOrC,EAAE,KAAKM,EAAe,GAAG,CAClC,CACF,CACF,CAKA,MAAc,qBACZN,EACAI,EACAP,EACmB,CACnB,GAAM,CAAE,SAAA4C,EAAU,WAAAC,EAAY,kBAAAC,EAAmB,gBAAAC,CAAgB,EAAI/C,EAErE,KAAK,OAAO,KAAK,+CAAiBO,CAAQ,EAAE,EAI5C,IAAM+C,EADgBtC,EAAc,kBAAkB,EACnB,KAAMQ,GAASA,EAAK,OAASjB,CAAQ,EAExE,GAAI,CAAC+C,EAAc,CACjB,IAAM7C,EAAgB,KAAK,oBACzB,iBACA,iBAAOF,CAAQ,sBACjB,EACA,OAAOJ,EAAE,KAAKM,EAAe,GAAG,CAClC,CAGA,GACE6C,EAAa,QAAQ,OAAS,SAC9BA,EAAa,QAAQ,WAAa,OAClC,CACA,IAAM7C,EAAgB,KAAK,oBACzB,oBACA,iBAAOF,CAAQ,gHACjB,EACA,OAAOJ,EAAE,KAAKM,EAAe,GAAG,CAClC,CAGI,CAACmC,EAAS,aAAeU,EAAa,SAAS,QAAQ,cACzDV,EAAS,YAAcU,EAAa,QAAQ,OAAO,aAIjD,CAACV,EAAS,aAAeA,EAAS,QAGpC,KAAK,OAAO,KACV,sBAAOrC,CAAQ,6FACjB,EAIF,KAAK,2BAA2BqC,CAAQ,EAGxC,IAAMW,EAAqB,KAAK,oBAC9BX,EACAG,CACF,EAGMS,EAA6B,CACjC,GAAGF,EACH,YAAaR,GAAqBQ,EAAa,YAC/C,YAAaC,CACf,EAGAvC,EAAc,oBAAoBT,EAAUiD,CAAW,EAEvD,KAAK,OAAO,KAAK,+CAAiBjD,CAAQ,EAAE,EAE5C,IAAMc,EAAe,CACnB,KAAMmC,EACN,SAAUjD,EACV,gBACA,UAAWjB,GAAM,EAAE,OAAO,qBAAqB,CACjD,EAEA,OAAOa,EAAE,KACP,KAAK,sBACHkB,EACA,sBAAYd,CAAQ,wCACtB,CACF,CACF,CAKQ,sBAAsBM,EAG5B,CACA,IAAMC,EACJD,aAAiB,MAAQA,EAAM,QAAU,qEAG3C,OAAIC,EAAa,SAAS,oBAAK,GAAKA,EAAa,SAAS,oBAAK,EACtD,CACL,WAAY,IACZ,cAAe,KAAK,oBAClB,iBACA,GAAGA,CAAY,0EACjB,CACF,EAKAA,EAAa,SAAS,0BAAM,GAC5BA,EAAa,SAAS,mBAAmB,EAElC,CACL,WAAY,IACZ,cAAe,KAAK,oBAClB,oBACAA,CACF,CACF,EAIEA,EAAa,SAAS,0BAAM,GAAKA,EAAa,SAAS,cAAI,EACtD,CACL,WAAY,IACZ,cAAe,KAAK,oBAClB,kBACA,GAAGA,CAAY,gFACjB,CACF,EAIEA,EAAa,SAAS,cAAI,GAAKA,EAAa,SAAS,cAAI,EACpD,CACL,WAAY,IACZ,cAAe,KAAK,oBAClB,sBACA,GAAGA,CAAY,wGACjB,CACF,EAKAA,EAAa,SAAS,oBAAK,GAC3BA,EAAa,SAAS,iBAAiB,EAEhC,CACL,WAAY,IACZ,cAAe,KAAK,oBAClB,4BACAA,CACF,CACF,EAIK,CACL,WAAY,IACZ,cAAe,KAAK,oBAClB,2BACA,yDAAYA,CAAY,0HAC1B,CACF,CACF,CAMA,MAAM,iBAAiBX,EAA+B,CACpD,GAAI,CACF,IAAMI,EAAWJ,EAAE,IAAI,MAAM,UAAU,EAEvC,GAAI,CAACI,EAAU,CACb,IAAME,EAAgB,KAAK,oBACzB,kBACA,kDACF,EACA,OAAON,EAAE,KAAKM,EAAe,GAAG,CAClC,CAEA,KAAK,OAAO,KAAK,uEAAgBF,CAAQ,EAAE,EAI3C,IAAMkD,EADgBzC,EAAc,kBAAkB,EACnB,KAAMQ,GAASA,EAAK,OAASjB,CAAQ,EAExE,GAAIkD,GAAgBA,EAAa,QAAQ,OAAS,MAAO,CAEvD,IAAMC,EAAYD,EAAa,QAAQ,OACvC,GAAIC,EAAU,aAAeA,EAAU,SAAU,CAC/C,KAAK,OAAO,KACV,2HAA2CA,EAAU,WAAW,IAAIA,EAAU,QAAQ,EACxF,EAGA,IAAML,EAAoBrC,EAAc,qBACtC0C,EAAU,WACZ,EAEIL,IAAoBK,EAAU,QAAQ,IAExCL,EAAkBK,EAAU,QAAQ,EAAE,OAAS,GAG/C1C,EAAc,wBACZ0C,EAAU,YACVL,CACF,EAEA,KAAK,OAAO,KACV,4EAA+BK,EAAU,WAAW,IAAIA,EAAU,QAAQ,EAC5E,EAEJ,CACF,CAGA,OAAA1C,EAAc,oBAAoBT,CAAQ,EAE1C,KAAK,OAAO,KAAK,2DAAcA,CAAQ,EAAE,EAElCJ,EAAE,KACP,KAAK,sBAAsB,KAAM,iBAAOI,CAAQ,4BAAQ,CAC1D,CACF,OAASM,EAAO,CACd,KAAK,OAAO,MAAM,0DAAcA,CAAK,EAGrC,GAAM,CAAE,WAAAT,EAAY,cAAAK,CAAc,EAAI,KAAK,sBAAsBI,CAAK,EACtE,OAAO,KAAK,mBACVV,EACAM,EACA,KAAK,sBAAsBL,CAAU,CACvC,CACF,CACF,CAKQ,sBACNwC,EACAC,EACAC,EACAC,EACe,CAEf,KAAK,qBAAqBH,CAAQ,EAGlC,IAAMe,EACJd,GAAc,KAAK,iBAAiBD,EAAS,aAAa,EACtDrC,EAAW,KAAK,wBAAwBoD,CAAQ,EAGhDC,EAAc,KAAK,wBACvBhB,EACAE,CACF,EAGMe,EAAc,KAAK,oBAAoBjB,EAAUG,CAAe,EAGhEe,EAAU,KAAK,kBAAkBlB,CAAQ,EAGzCpB,EAAsB,CAC1B,KAAMjB,EACN,YAAAqD,EACA,YAAAC,EACA,QAAAC,CACF,EAGA,YAAK,sBAAsBtC,CAAI,EAExBA,CACT,CAKQ,iBAAiBuC,EAAsB,CAC7C,GAAI,CAACA,GAAQ,OAAOA,GAAS,SAC3B,MAAO,wBAIT,IAAIC,EAAYD,EAAK,KAAK,EAE1B,OAAKC,GAKLA,EAAY,KAAK,wBAAwBA,CAAS,EAGlDA,EAAYA,EAAU,QAAQ,iBAAkB,GAAG,EAGnDA,EAAYA,EAAU,QAAQ,MAAO,GAAG,EAGxCA,EAAYA,EAAU,QAAQ,WAAY,EAAE,EAGvC,YAAY,KAAKA,CAAS,IAC7BA,EAAY,iBAAiBA,CAAS,IAIpCA,EAAU,OAAS,KACrBA,EAAYA,EAAU,UAAU,EAAG,EAAE,GAIlCA,IACHA,EAAY,sBAGPA,GA9BE,qBA+BX,CAKQ,wBAAwBC,EAAsB,CAEpD,IAAMC,EAA8C,CAClD,mBAAK,WACL,aAAI,OACJ,aAAI,OACJ,aAAI,UACJ,aAAI,WACJ,aAAI,WACJ,aAAI,QACJ,aAAI,SACJ,aAAI,UACJ,aAAI,YACJ,aAAI,aACJ,aAAI,SACJ,aAAI,WACJ,aAAI,QACJ,aAAI,QACJ,aAAI,QACJ,aAAI,OACJ,aAAI,YACJ,aAAI,YACJ,aAAI,SACJ,aAAI,UACJ,aAAI,SACJ,aAAI,SACJ,aAAI,UACJ,aAAI,OACJ,aAAI,SACJ,aAAI,UACJ,aAAI,MACJ,mBAAK,WACL,aAAI,UACJ,aAAI,WACJ,aAAI,SACJ,aAAI,UACJ,aAAI,OACJ,aAAI,SACJ,aAAI,SACJ,aAAI,SACJ,aAAI,UACN,EAEIvD,EAASsD,EAGb,OAAW,CAACE,EAASC,CAAO,IAAK,OAAO,QAAQF,CAAmB,EACjEvD,EAASA,EAAO,QAAQ,IAAI,OAAOwD,EAAS,GAAG,EAAGC,CAAO,EAI3D,MAAI,kBAAkB,KAAKzD,CAAM,IAC/BA,EAAS,WAAWA,CAAM,IAGrBA,CACT,CAKQ,qBAAqBiC,EAA8B,CACzD,GAAI,CAACA,EACH,MAAM,IAAI,MAAM,wDAAW,EAI7B,KAAK,uBAAuBA,CAAQ,EAGpC,KAAK,qBAAqBA,CAAQ,EAGlC,KAAK,qBAAqBA,CAAQ,EAGlC,KAAK,sBAAsBA,CAAQ,CACrC,CAMQ,2BAA2BA,EAAuC,CACxE,GAAI,CAACA,EACH,MAAM,IAAI,MAAM,wDAAW,EAO7B,GAAIA,EAAS,YAAa,CACxB,GACE,OAAOA,EAAS,aAAgB,UAChCA,EAAS,YAAY,KAAK,IAAM,GAEhC,MAAM,IAAI,MAAM,sEAAe,EAIjC,GAAI,CAAC,QAAQ,KAAKA,EAAS,WAAW,EACpC,MAAM,IAAI,MAAM,8FAAmB,CAEvC,CAGA,GAAIA,EAAS,cAAe,CAC1B,GACE,OAAOA,EAAS,eAAkB,UAClCA,EAAS,cAAc,KAAK,IAAM,GAElC,MAAM,IAAI,MAAM,gFAAe,EAIjC,GAAIA,EAAS,cAAc,OAAS,IAClC,MAAM,IAAI,MAAM,+FAAoB,CAExC,CAGA,GAAIA,EAAS,OAAQ,CACnB,GACE,OAAOA,EAAS,QAAW,UAC3BA,EAAS,OAAO,KAAK,IAAM,GAE3B,MAAM,IAAI,MAAM,gEAAc,EAIhC,GAAI,CAAC,mBAAmB,KAAKA,EAAS,MAAM,EAC1C,MAAM,IAAI,MAAM,oJAA4B,EAI9C,GAAIA,EAAS,OAAO,OAAS,GAC3B,MAAM,IAAI,MAAM,8EAAkB,CAEtC,CAKF,CAKQ,uBAAuBA,EAA8B,CAC3D,IAAMyB,EAAiB,CACrB,CAAE,MAAO,cAAe,KAAM,sBAAQ,EACtC,CAAE,MAAO,gBAAiB,KAAM,gCAAQ,EACxC,CAAE,MAAO,SAAU,KAAM,gBAAO,CAClC,EAEA,OAAW,CAAE,MAAAC,EAAO,KAAAP,CAAK,IAAKM,EAAgB,CAC5C,IAAME,EAAQ3B,EAAS0B,CAA2B,EAClD,GAAI,CAACC,GAAS,OAAOA,GAAU,UAAYA,EAAM,KAAK,IAAM,GAC1D,MAAM,IAAI,MAAM,GAAGR,CAAI,gFAAe,CAE1C,CACF,CAKQ,qBAAqBnB,EAA8B,CAEzD,GAAI,CAAC,QAAQ,KAAKA,EAAS,WAAW,EACpC,MAAM,IAAI,MAAM,8FAAmB,EAIrC,GAAI,CAAC,mBAAmB,KAAKA,EAAS,MAAM,EAC1C,MAAM,IAAI,MAAM,oJAA4B,EAI9C,GAAIA,EAAS,UAAU,KAAK,EAC1B,GAAI,CACF,IAAI,IAAIA,EAAS,QAAQ,CAC3B,MAAQ,CACN,MAAM,IAAI,MAAM,yCAAW,CAC7B,CAIF,GACEA,EAAS,aACR,CAAC,OAAO,UAAUA,EAAS,UAAU,GAAKA,EAAS,YAAc,GAElE,MAAM,IAAI,MAAM,wGAAmB,EAGrC,GACEA,EAAS,aACR,CAAC,OAAO,UAAUA,EAAS,UAAU,GAAKA,EAAS,YAAc,GAElE,MAAM,IAAI,MAAM,wGAAmB,CAEvC,CAKQ,qBAAqBA,EAA8B,CACzD,IAAM4B,EAAe,CACnB,CAAE,MAAO,gBAAiB,KAAM,iCAAS,IAAK,GAAI,EAClD,CAAE,MAAO,cAAe,KAAM,iCAAS,IAAK,GAAI,EAChD,CAAE,MAAO,SAAU,KAAM,iBAAQ,IAAK,EAAG,CAC3C,EAEA,OAAW,CAAE,MAAAF,EAAO,KAAAP,EAAM,IAAAU,CAAI,IAAKD,EAAc,CAC/C,IAAMD,EAAQ3B,EAAS0B,CAA2B,EAClD,GAAIC,GAASA,EAAM,OAASE,EAC1B,MAAM,IAAI,MAAM,GAAGV,CAAI,6CAAUU,CAAG,oBAAK,CAE7C,CACF,CAKQ,sBAAsB7B,EAA8B,CAE1D,GAAIA,EAAS,QAAS,CACpB,GAAI,CAACA,EAAS,QAAQ,IAAM,OAAOA,EAAS,QAAQ,IAAO,SACzD,MAAM,IAAI,MAAM,wFAAkB,EAEpC,GAAI,CAACA,EAAS,QAAQ,MAAQ,OAAOA,EAAS,QAAQ,MAAS,SAC7D,MAAM,IAAI,MAAM,kGAAkB,CAEtC,CAGA,GACEA,EAAS,YACTA,EAAS,YACTA,EAAS,WAAaA,EAAS,WAE/B,MAAM,IAAI,MAAM,0EAAc,EAIhC,IAAM8B,EAAiB,CACrB,QACA,OACA,SACA,SACA,WACA,OACF,EACMC,EAAY/B,EAAS,cAAc,YAAY,EACrD,QAAWgC,KAAQF,EACjB,GAAIC,EAAU,SAASC,CAAI,EACzB,MAAM,IAAI,MAAM,6EAAiBA,CAAI,EAAE,CAG7C,CAKQ,wBAAwBjB,EAA0B,CACxD,IAAMP,EAAgBpC,EAAc,kBAAkB,EAChD6D,EAAgB,IAAI,IAAIzB,EAAc,IAAK5B,GAASA,EAAK,IAAI,CAAC,EAEhEsD,EAAYnB,EACZoB,EAAU,EAGd,KAAOF,EAAc,IAAIC,CAAS,GAKhC,GAJAA,EAAY,GAAGnB,CAAQ,IAAIoB,CAAO,GAClCA,IAGIA,EAAU,IACZ,MAAM,IAAI,MAAM,qGAAqBpB,CAAQ,EAAE,EAInD,OAAOmB,CACT,CAKQ,wBACNlC,EACAE,EACQ,CACR,OAAIA,IAIAF,EAAS,aAAa,KAAK,EACtBA,EAAS,YAAY,KAAK,EAI5B,+CAAYA,EAAS,aAAa,GAC3C,CAKQ,kBAAkBA,EAA4C,CAEpE,YAAK,sBAAsB,EAEpB,CACL,KAAM,QACN,SAAU,OACV,OAAQ,CACN,YAAaA,EAAS,WACxB,CACF,CACF,CAKQ,uBAA8B,CAEpC,IAAMoC,EAAahE,EAAc,sBAAsB,EACvD,GAAI,CAACgE,GAAc,CAACA,EAAW,MAC7B,MAAM,IAAI,MACR,oHACF,CAEJ,CAKQ,sBAAsBxD,EAA2B,CAKvD,GAHA,KAAK,sBAAsBA,CAAI,EAG3B,CAACR,EAAc,uBAAuB,CAACQ,CAAI,CAAC,EAC9C,MAAM,IAAI,MAAM,oHAAqB,EAIvC,KAAK,mBAAmBA,EAAK,WAAW,EAGpCA,EAAK,SACP,KAAK,qBAAqBA,EAAK,OAA6B,CAEhE,CAKQ,sBAAsBA,EAA2B,CACvD,GAAI,CAACA,GAAQ,OAAOA,GAAS,SAC3B,MAAM,IAAI,MAAM,oEAAa,EAI/B,IAAM6C,EAAiB,CAAC,OAAQ,cAAe,cAAe,SAAS,EACvE,QAAWC,KAASD,EAClB,GAAI,EAAEC,KAAS9C,IAASA,EAAK8C,CAA4B,GAAK,KAC5D,MAAM,IAAI,MAAM,iEAAeA,CAAK,EAAE,EAK1C,GAAI,OAAO9C,EAAK,MAAS,UAAYA,EAAK,KAAK,KAAK,IAAM,GACxD,MAAM,IAAI,MAAM,0EAAc,EAGhC,GACE,OAAOA,EAAK,aAAgB,UAC5BA,EAAK,YAAY,KAAK,IAAM,GAE5B,MAAM,IAAI,MAAM,0EAAc,EAGhC,GAAI,OAAOA,EAAK,aAAgB,SAC9B,MAAM,IAAI,MAAM,oEAAa,EAG/B,GAAI,OAAOA,EAAK,SAAY,SAC1B,MAAM,IAAI,MAAM,8DAAY,CAEhC,CAKQ,qBAAqBsC,EAAmC,CAC9D,GAAI,CAACA,GAAW,OAAOA,GAAY,SACjC,MAAM,IAAI,MAAM,4DAAe,EAIjC,GAAIA,EAAQ,OAAS,QACnB,MAAM,IAAI,MAAM,yDAAiB,EAGnC,GAAIA,EAAQ,WAAa,QACvB,GAAI,CAACA,EAAQ,OAAO,YAClB,MAAM,IAAI,MAAM,6EAA2B,MAG7C,OAAM,IAAI,MAAM,wDAAW,CAE/B,CAKQ,mBAAmBmB,EAA8C,CACvE,GAAI,CAACA,GAAQ,OAAOA,GAAS,SAC3B,MAAM,IAAI,MAAM,wDAAW,EAG7B,GAAI,CAACA,EAAK,MAAQ,OAAOA,EAAK,MAAS,SACrC,MAAM,IAAI,MAAM,kDAAU,EAG5B,IAAMC,EAAiB,CAAC,SAAU,QAAS,SAAS,EACpD,GAAI,CAACA,EAAe,SAASD,EAAK,IAAI,EACpC,MAAM,IAAI,MAAM,uEAAgBC,EAAe,KAAK,IAAI,CAAC,EAAE,EAI7D,GAAID,EAAK,OAAS,SAAU,CAC1B,GAAI,CAACA,EAAK,OAAS,OAAOA,EAAK,OAAU,SACvC,MAAM,IAAI,MAAM,mEAAsB,EAIxC,GACE,CAACA,EAAK,MAAM,WAAW,IAAI,GAC3B,CAACA,EAAK,MAAM,MAAM,kBAAkB,EAEpC,MAAM,IAAI,MAAM,sCAAkB,CAEtC,CACF,CAKQ,qBAAqBE,EAA4B,CACvD,GAAI,OAAOA,GAAiB,SAC1B,MAAM,IAAI,MAAM,oEAAa,EAG/B,GAAI,CACF,KAAK,MAAMA,CAAY,CACzB,MAAQ,CACN,MAAM,IAAI,MAAM,oFAAmB,CACrC,CAGA,IAAMC,EAAeD,EAAa,MAAM,gBAAgB,EACxD,GAAIC,EACF,QAAWC,KAAeD,EAAc,CACtC,IAAME,EAAUD,EAAY,MAAM,EAAG,EAAE,EAAE,KAAK,EAC9C,GAAI,CAACC,GAAW,CAAC,2BAA2B,KAAKA,CAAO,EACtD,MAAM,IAAI,MAAM,qDAAaD,CAAW,EAAE,CAE9C,CAEJ,CAKQ,mBAAmBE,EAA0B,CACnD,GAAI,CAACA,GAAU,OAAOA,GAAW,SAC/B,MAAM,IAAI,MAAM,sFAAgB,EAGlC,GAAI,CAACA,EAAO,MAAQA,EAAO,OAAS,SAClC,MAAM,IAAI,MAAM,0EAAwB,EAG1C,GAAI,CAACA,EAAO,YAAc,OAAOA,EAAO,YAAe,SACrD,MAAM,IAAI,MAAM,oFAAwB,EAI1C,GAAIA,EAAO,UAAY,CAAC,MAAM,QAAQA,EAAO,QAAQ,EACnD,MAAM,IAAI,MAAM,8FAAwB,CAE5C,CAKQ,oBACN3C,EACAG,EACY,CAEZ,OAAIA,GAAmBA,EAAgB,WAAW,OAAS,EAClD,KAAK,8BAA8BA,CAAe,EAIxC,CACjB,KAAM,SACN,WAAY,CACV,MAAO,CACL,KAAM,SACN,YAAa,0BACf,CACF,EACA,SAAU,CAAC,OAAO,EAClB,qBAAsB,EACxB,CAGF,CAKQ,8BACNA,EACY,CACZ,IAAMyC,EAAsC,CAAC,EACvCC,EAAqB,CAAC,EAE5B,QAAWC,KAAS3C,EAAgB,WAClCyC,EAAWE,EAAM,SAAS,EAAI,CAC5B,KAAMA,EAAM,KACZ,YAAaA,EAAM,WACrB,EAEIA,EAAM,UACRD,EAAS,KAAKC,EAAM,SAAS,EAIjC,MAAO,CACL,KAAM,SACN,WAAAF,EACA,SAAUC,EAAS,OAAS,EAAIA,EAAW,OAC3C,qBAAsB,EACxB,CACF,CAKQ,mBAAmB5E,EAGzB,CACA,IAAMC,EACJD,aAAiB,MAAQA,EAAM,QAAU,yDAG3C,OACEC,EAAa,SAAS,0BAAM,GAC5BA,EAAa,SAAS,WAAW,EAE1B,CACL,WAAY,IACZ,cAAe,KAAK,oBAClB,oBACAA,CACF,CACF,EAKAA,EAAa,SAAS,0BAAM,GAC5BA,EAAa,SAAS,wBAAwB,EAEvC,CACL,WAAY,IACZ,cAAe,KAAK,oBAClB,yBACAA,CACF,CACF,EAKAA,EAAa,SAAS,oBAAK,GAC3BA,EAAa,SAAS,WAAW,GACjCA,EAAa,SAAS,oBAAK,EAEpB,CACL,WAAY,IACZ,cAAe,KAAK,oBAClB,4BACAA,CACF,CACF,EAKAA,EAAa,SAAS,0BAAM,GAC5BA,EAAa,SAAS,yBAAyB,EAExC,CACL,WAAY,IACZ,cAAe,KAAK,oBAClB,0BACAA,CACF,CACF,EAKAA,EAAa,SAAS,oBAAK,GAC3BA,EAAa,SAAS,cAAI,GAC1BA,EAAa,SAAS,oBAAoB,EAEnC,CACL,WAAY,IACZ,cAAe,KAAK,oBAClB,qBACA,GAAGA,CAAY,kJACjB,CACF,EAIE,KAAK,kBAAkBA,CAAY,EAC9B,CACL,WAAY,IACZ,cAAe,KAAK,oBAClB,mBACA,KAAK,sBAAsBA,CAAY,CACzC,CACF,EAKAA,EAAa,SAAS,cAAI,GAC1BA,EAAa,SAAS,OAAO,GAC7BA,EAAa,SAAS,KAAK,GAC3BA,EAAa,SAAS,qBAAqB,EAEpC,CACL,WAAY,IACZ,cAAe,KAAK,oBAClB,sBACA,GAAGA,CAAY,iNACjB,CACF,EAKAA,EAAa,SAAS,0BAAM,GAC5BA,EAAa,SAAS,yBAAyB,EAExC,CACL,WAAY,IACZ,cAAe,KAAK,oBAClB,0BACAA,CACF,CACF,EAKAA,EAAa,SAAS,oBAAK,GAC3BA,EAAa,SAAS,iBAAiB,EAEhC,CACL,WAAY,IACZ,cAAe,KAAK,oBAClB,4BACAA,CACF,CACF,EAIK,CACL,WAAY,IACZ,cAAe,KAAK,oBAClB,wBACA,6CAAUA,CAAY,0HACxB,CACF,CACF,CAKQ,sBAAsBD,EAG5B,CACA,IAAMC,EACJD,aAAiB,MAAQA,EAAM,QAAU,yDAG3C,OAAIC,EAAa,SAAS,oBAAK,GAAKA,EAAa,SAAS,oBAAK,EACtD,CACL,WAAY,IACZ,cAAe,KAAK,oBAClB,iBACA,GAAGA,CAAY,oKACjB,CACF,EAIEA,EAAa,SAAS,0BAAM,GAAKA,EAAa,SAAS,cAAI,EACtD,CACL,WAAY,IACZ,cAAe,KAAK,oBAClB,kBACA,GAAGA,CAAY,oEACjB,CACF,EAIEA,EAAa,SAAS,cAAI,GAAKA,EAAa,SAAS,cAAI,EACpD,CACL,WAAY,IACZ,cAAe,KAAK,oBAClB,sBACA,GAAGA,CAAY,wGACjB,CACF,EAIK,CACL,WAAY,IACZ,cAAe,KAAK,oBAClB,2BACA,6CAAUA,CAAY,0HACxB,CACF,CACF,CAKQ,kBAAkBA,EAA+B,CAiBvD,MAhB2B,CACzB,2BACA,qBACA,2BACA,eACA,eACA,2BACA,eACA,qBACA,eACA,eACA,qBACA,eACA,KACF,EAE0B,KAAM6E,GAAY7E,EAAa,SAAS6E,CAAO,CAAC,CAC5E,CAKQ,sBAAsB7E,EAA8B,CAE1D,IAAM8E,EAAwC,CAC5C,6CAAW,2DACX,uDAAW,qEACX,uCAAU,qDACV,6CAAW,iHACX,uCAAU,uHACV,2CAAS,kHACT,2CAAS,kHACT,wCAAW,kEACX,yEAAc,qHACd,mBAAK,8GACP,EAGA,OAAW,CAACC,EAAKtB,CAAK,IAAK,OAAO,QAAQqB,CAAa,EACrD,GAAI9E,EAAa,SAAS+E,CAAG,EAC3B,OAAOtB,EAIX,OAAOzD,CACT,CAKQ,iBACN8B,EACAC,EACAC,EACgE,CAEhE,IAAMgD,EAAmB,KAAK,qBAC5BlD,EACAC,EACAC,CACF,EACA,GAAIgD,EAAkB,OAAOA,EAG7B,IAAMC,EAAoB,KAAK,kBAAkB,EACjD,GAAIA,EAAmB,OAAOA,EAG9B,IAAMC,EAAsB,KAAK,oBAAoB,EACrD,OAAIA,GAEG,IACT,CAKQ,qBACNpD,EACAC,EACAC,EACgE,CAEhE,GAAI,CAACF,EACH,MAAO,CACL,WAAY,IACZ,cAAe,KAAK,oBAClB,kBACA,4DACF,CACF,EAGF,GAAI,OAAOA,GAAa,SACtB,MAAO,CACL,WAAY,IACZ,cAAe,KAAK,oBAClB,kBACA,iEACF,CACF,EAIF,GAAI,CAAC,MAAM,QAAQA,CAAQ,EAAG,CAC5B,IAAMqD,EAAcrD,EAGpB,GACE,CAACqD,EAAY,aACb,OAAOA,EAAY,aAAgB,UACnC,CAACA,EAAY,YAAY,KAAK,EAE9B,MAAO,CACL,WAAY,IACZ,cAAe,KAAK,oBAClB,kBACA,4FACF,CACF,EAGF,GACE,CAACA,EAAY,eACb,OAAOA,EAAY,eAAkB,UACrC,CAACA,EAAY,cAAc,KAAK,EAEhC,MAAO,CACL,WAAY,IACZ,cAAe,KAAK,oBAClB,kBACA,8FACF,CACF,CAEJ,CAGA,GAAIpD,IAAe,OAAW,CAC5B,GAAI,OAAOA,GAAe,SACxB,MAAO,CACL,WAAY,IACZ,cAAe,KAAK,oBAClB,kBACA,6DACF,CACF,EAGF,GAAIA,EAAW,KAAK,IAAM,GACxB,MAAO,CACL,WAAY,IACZ,cAAe,KAAK,oBAClB,kBACA,uDACF,CACF,EAGF,GAAIA,EAAW,OAAS,GACtB,MAAO,CACL,WAAY,IACZ,cAAe,KAAK,oBAClB,kBACA,qEACF,CACF,CAEJ,CAEA,GAAIC,IAAsB,OAAW,CACnC,GAAI,OAAOA,GAAsB,SAC/B,MAAO,CACL,WAAY,IACZ,cAAe,KAAK,oBAClB,kBACA,oEACF,CACF,EAGF,GAAIA,EAAkB,OAAS,IAC7B,MAAO,CACL,WAAY,IACZ,cAAe,KAAK,oBAClB,kBACA,6EACF,CACF,CAEJ,CAEA,OAAO,IACT,CAKQ,mBAGC,CAEP,GAAI,CACF,IAAMkC,EAAahE,EAAc,sBAAsB,EACvD,GAAI,CAACgE,GAAc,CAACA,EAAW,MAC7B,MAAO,CACL,WAAY,IACZ,cAAe,KAAK,oBAClB,sBACA,0HACF,CACF,EAIF,GACE,OAAOA,EAAW,OAAU,UAC5BA,EAAW,MAAM,KAAK,IAAM,GAE5B,MAAO,CACL,WAAY,IACZ,cAAe,KAAK,oBAClB,sBACA,oHACF,CACF,CAEJ,MAAgB,CACd,MAAO,CACL,WAAY,IACZ,cAAe,KAAK,oBAClB,eACA,sFACF,CACF,CACF,CAEA,OAAO,IACT,CAKQ,qBAGC,CACP,GAAI,CAEF,IAAM5B,EAAgBpC,EAAc,kBAAkB,EAChDkF,EAAW,IAEjB,GAAI9C,EAAc,QAAU8C,EAC1B,MAAO,CACL,WAAY,IACZ,cAAe,KAAK,oBAClB,0BACA,uEAAgBA,CAAQ,6FAC1B,CACF,EAIF,IAAMC,EAAqB,KAAK,UAAU/C,CAAa,EAAE,OACnDgD,EAAgB,KAAO,KAE7B,GAAID,EAAqBC,EACvB,MAAO,CACL,WAAY,IACZ,cAAe,KAAK,oBAClB,oBACA,4IACF,CACF,CAEJ,OAASvF,EAAO,CAEd,KAAK,OAAO,KAAK,oDAAaA,CAAK,CACrC,CAEA,OAAO,IACT,CACF,ICzzEA,OAAS,KAAAwF,OAAS,MAVlB,IAoCMC,GAoEOC,GAxGbC,GAAAC,EAAA,kBAMAC,KACAC,KACAC,IA4BMN,GAAsBD,GACzB,OAAO,CACN,MAAOA,GACJ,OAAO,EACP,SAAS,EACT,UAAWQ,GAASA,EAAM,OAAO,SAASA,EAAK,EAAE,EAAI,MAAU,EAC/D,OACEA,GACCA,IAAQ,QACPA,GAAO,GAAKA,GAAOC,GAAqB,UAC3C,CACE,QAAS,0CAAiBA,GAAqB,SAAS,iCAC1D,CACF,EACF,OAAQT,GACL,OAAO,EACP,SAAS,EACT,UAAWQ,GAASA,EAAM,OAAO,SAASA,EAAK,EAAE,EAAI,MAAU,EAC/D,OAAQA,GAAQA,IAAQ,QAAaA,GAAO,EAAG,CAC9C,QAAS,yDACX,CAAC,EACH,SAAUR,GAAE,OAAO,EAAE,SAAS,EAC9B,WAAYA,GAAE,OAAO,EAAE,SAAS,EAChC,QAASA,GACN,OAAO,EACP,SAAS,EACT,UAAWQ,GAASA,EAAMA,EAAI,YAAY,IAAM,OAAS,MAAU,EACtE,UAAWR,GACR,OAAO,EACP,SAAS,EACT,OACEQ,GAAQ,CACP,GAAI,CAACA,EAAK,MAAO,GACjB,IAAME,EAAO,KAAK,MAAMF,CAAG,EAC3B,MAAO,CAAC,OAAO,MAAME,CAAI,CAC3B,EACA,CACE,QAAS,gDACX,CACF,EACF,QAASV,GACN,OAAO,EACP,SAAS,EACT,OACEQ,GAAQ,CACP,GAAI,CAACA,EAAK,MAAO,GACjB,IAAME,EAAO,KAAK,MAAMF,CAAG,EAC3B,MAAO,CAAC,OAAO,MAAME,CAAI,CAC3B,EACA,CACE,QAAS,8CACX,CACF,CACJ,CAAC,EACA,OACEC,GACK,CAACA,EAAK,WAAa,CAACA,EAAK,QAAgB,GACtC,IAAI,KAAKA,EAAK,SAAS,GAAK,IAAI,KAAKA,EAAK,OAAO,EAE1D,CACE,QAAS,6CACT,KAAM,CAAC,WAAW,CACpB,CACF,EAKWT,GAAN,KAA4B,CAxGnC,MAwGmC,CAAAU,EAAA,8BACzB,mBAER,aAAc,CACZ,KAAK,mBAAqB,IAAIC,EAChC,CAKQ,sBAAyBF,EAAoB,CACnD,IAAMG,EAA2B,CAC/B,QAAS,GACT,KAAAH,CACF,EACA,OAAO,SAAS,KAAKG,CAAQ,CAC/B,CAKQ,oBACNC,EACAC,EACAC,EACU,CACV,IAAMH,EAAwB,CAC5B,QAAS,GACT,MAAO,CACL,KAAAC,EACA,QAAAC,EACA,QAAAC,CACF,CACF,EACA,OAAO,SAAS,KAAKH,EAAU,CAAE,OAAQ,KAAK,kBAAkBC,CAAI,CAAE,CAAC,CACzE,CAKQ,kBAAkBA,EAAsB,CAC9C,OAAQA,EAAM,CACZ,IAAK,2BACH,MAAO,KACT,IAAK,qBACH,MAAO,KACT,IAAK,sBACH,MAAO,KACT,QACE,MAAO,IACX,CACF,CAKQ,4BAA4BG,EAIlC,CACA,IAAMC,EAAQD,EAAE,IAAI,MAAM,EACpBE,EAASnB,GAAoB,UAAUkB,CAAK,EAElD,OAAKC,EAAO,QAUL,CACL,QAAS,GACT,KAAMA,EAAO,IACf,EAZS,CACL,QAAS,GACT,MAAOA,EAAO,MAAM,OAAO,IAAKC,IAAS,CACvC,MAAOA,EAAI,KAAK,KAAK,GAAG,EACxB,QAASA,EAAI,OACf,EAAE,CACJ,CAOJ,CAKA,MAAM,gBAAgBH,EAA+B,CACnD,GAAI,CACF,IAAMI,EAAa,KAAK,4BAA4BJ,CAAC,EAErD,GAAI,CAACI,EAAW,QACd,OAAO,KAAK,oBACV,2BACA,mDACAA,EAAW,KACb,EAGF,IAAMF,EAAS,MAAM,KAAK,mBAAmB,gBAC3CE,EAAW,IACb,EAEA,OAAAC,EAAO,MAAM,qBAAWH,EAAO,QAAQ,MAAM,yDAAY,EAClD,KAAK,sBAAsBA,CAAM,CAC1C,OAASI,EAAO,CACdD,EAAO,MAAM,gEAAeC,CAAK,EAEjC,IAAMR,EAAUQ,aAAiB,MAAQA,EAAM,QAAU,2BACzD,OAAIR,EAAQ,SAAS,oBAAK,EACjB,KAAK,oBAAoB,qBAAsBA,CAAO,EAE3DA,EAAQ,SAAS,0BAAM,EAClB,KAAK,oBAAoB,sBAAuBA,CAAO,EAGzD,KAAK,oBACV,iBACA,+DACA,CACE,QAASA,CACX,CACF,CACF,CACF,CACF,ICjOA,IAAAS,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAIA,IAAMC,GAAsB,QAGtBC,GAAmB,OAAO,kBACL,iBAGrBC,GAA4B,GAI5BC,GAAwB,IAExBC,GAAgB,CACpB,QACA,WACA,QACA,WACA,QACA,WACA,YACF,EAEAL,GAAO,QAAU,CACf,eACA,0BAAAG,GACA,sBAAAC,GACA,iBAAAF,GACA,cAAAG,GACA,oBAAAJ,GACA,wBAAyB,EACzB,WAAY,CACd,ICpCA,IAAAK,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,IAAMC,GACJ,OAAO,SAAY,UACnB,QAAQ,KACR,QAAQ,IAAI,YACZ,cAAc,KAAK,QAAQ,IAAI,UAAU,EACvC,IAAIC,IAAM,GACV,IAAM,CAAC,EAEXF,GAAO,QAAUC,KCVjB,IAAAE,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,GAAM,CACJ,0BAAAC,GACA,sBAAAC,GACA,WAAAC,EACF,EAAI,KACEC,GAAQ,KACdL,GAAUC,GAAO,QAAU,CAAC,EAG5B,IAAMK,GAAKN,GAAQ,GAAK,CAAC,EACnBO,GAASP,GAAQ,OAAS,CAAC,EAC3BQ,EAAMR,GAAQ,IAAM,CAAC,EACrBS,GAAUT,GAAQ,QAAU,CAAC,EAC7BU,EAAIV,GAAQ,EAAI,CAAC,EACnBW,GAAI,EAEFC,GAAmB,eAQnBC,GAAwB,CAC5B,CAAC,MAAO,CAAC,EACT,CAAC,MAAOT,EAAU,EAClB,CAACQ,GAAkBT,EAAqB,CAC1C,EAEMW,GAAgBC,EAACC,GAAU,CAC/B,OAAW,CAACC,EAAOC,CAAG,IAAKL,GACzBG,EAAQA,EACL,MAAM,GAAGC,CAAK,GAAG,EAAE,KAAK,GAAGA,CAAK,MAAMC,CAAG,GAAG,EAC5C,MAAM,GAAGD,CAAK,GAAG,EAAE,KAAK,GAAGA,CAAK,MAAMC,CAAG,GAAG,EAEjD,OAAOF,CACT,EAPsB,iBAShBG,EAAcJ,EAAA,CAACK,EAAMJ,EAAOK,IAAa,CAC7C,IAAMC,EAAOR,GAAcE,CAAK,EAC1BO,EAAQZ,KACdN,GAAMe,EAAMG,EAAOP,CAAK,EACxBN,EAAEU,CAAI,EAAIG,EACVf,EAAIe,CAAK,EAAIP,EACbP,GAAQc,CAAK,EAAID,EACjBhB,GAAGiB,CAAK,EAAI,IAAI,OAAOP,EAAOK,EAAW,IAAM,MAAS,EACxDd,GAAOgB,CAAK,EAAI,IAAI,OAAOD,EAAMD,EAAW,IAAM,MAAS,CAC7D,EAToB,eAiBpBF,EAAY,oBAAqB,aAAa,EAC9CA,EAAY,yBAA0B,MAAM,EAM5CA,EAAY,uBAAwB,gBAAgBP,EAAgB,GAAG,EAKvEO,EAAY,cAAe,IAAIX,EAAIE,EAAE,iBAAiB,CAAC,QAChCF,EAAIE,EAAE,iBAAiB,CAAC,QACxBF,EAAIE,EAAE,iBAAiB,CAAC,GAAG,EAElDS,EAAY,mBAAoB,IAAIX,EAAIE,EAAE,sBAAsB,CAAC,QACrCF,EAAIE,EAAE,sBAAsB,CAAC,QAC7BF,EAAIE,EAAE,sBAAsB,CAAC,GAAG,EAO5DS,EAAY,uBAAwB,MAAMX,EAAIE,EAAE,oBAAoB,CACpE,IAAIF,EAAIE,EAAE,iBAAiB,CAAC,GAAG,EAE/BS,EAAY,4BAA6B,MAAMX,EAAIE,EAAE,oBAAoB,CACzE,IAAIF,EAAIE,EAAE,sBAAsB,CAAC,GAAG,EAMpCS,EAAY,aAAc,QAAQX,EAAIE,EAAE,oBAAoB,CAC5D,SAASF,EAAIE,EAAE,oBAAoB,CAAC,MAAM,EAE1CS,EAAY,kBAAmB,SAASX,EAAIE,EAAE,yBAAyB,CACvE,SAASF,EAAIE,EAAE,yBAAyB,CAAC,MAAM,EAK/CS,EAAY,kBAAmB,GAAGP,EAAgB,GAAG,EAMrDO,EAAY,QAAS,UAAUX,EAAIE,EAAE,eAAe,CACpD,SAASF,EAAIE,EAAE,eAAe,CAAC,MAAM,EAWrCS,EAAY,YAAa,KAAKX,EAAIE,EAAE,WAAW,CAC/C,GAAGF,EAAIE,EAAE,UAAU,CAAC,IAClBF,EAAIE,EAAE,KAAK,CAAC,GAAG,EAEjBS,EAAY,OAAQ,IAAIX,EAAIE,EAAE,SAAS,CAAC,GAAG,EAK3CS,EAAY,aAAc,WAAWX,EAAIE,EAAE,gBAAgB,CAC3D,GAAGF,EAAIE,EAAE,eAAe,CAAC,IACvBF,EAAIE,EAAE,KAAK,CAAC,GAAG,EAEjBS,EAAY,QAAS,IAAIX,EAAIE,EAAE,UAAU,CAAC,GAAG,EAE7CS,EAAY,OAAQ,cAAc,EAKlCA,EAAY,wBAAyB,GAAGX,EAAIE,EAAE,sBAAsB,CAAC,UAAU,EAC/ES,EAAY,mBAAoB,GAAGX,EAAIE,EAAE,iBAAiB,CAAC,UAAU,EAErES,EAAY,cAAe,YAAYX,EAAIE,EAAE,gBAAgB,CAAC,WACjCF,EAAIE,EAAE,gBAAgB,CAAC,WACvBF,EAAIE,EAAE,gBAAgB,CAAC,OAC3BF,EAAIE,EAAE,UAAU,CAAC,KACrBF,EAAIE,EAAE,KAAK,CAAC,OACR,EAEzBS,EAAY,mBAAoB,YAAYX,EAAIE,EAAE,qBAAqB,CAAC,WACtCF,EAAIE,EAAE,qBAAqB,CAAC,WAC5BF,EAAIE,EAAE,qBAAqB,CAAC,OAChCF,EAAIE,EAAE,eAAe,CAAC,KAC1BF,EAAIE,EAAE,KAAK,CAAC,OACR,EAE9BS,EAAY,SAAU,IAAIX,EAAIE,EAAE,IAAI,CAAC,OAAOF,EAAIE,EAAE,WAAW,CAAC,GAAG,EACjES,EAAY,cAAe,IAAIX,EAAIE,EAAE,IAAI,CAAC,OAAOF,EAAIE,EAAE,gBAAgB,CAAC,GAAG,EAI3ES,EAAY,cAAe,oBACDjB,EAAyB,kBACrBA,EAAyB,oBACzBA,EAAyB,MAAM,EAC7DiB,EAAY,SAAU,GAAGX,EAAIE,EAAE,WAAW,CAAC,cAAc,EACzDS,EAAY,aAAcX,EAAIE,EAAE,WAAW,EAC7B,MAAMF,EAAIE,EAAE,UAAU,CAAC,QACjBF,EAAIE,EAAE,KAAK,CAAC,gBACJ,EAC5BS,EAAY,YAAaX,EAAIE,EAAE,MAAM,EAAG,EAAI,EAC5CS,EAAY,gBAAiBX,EAAIE,EAAE,UAAU,EAAG,EAAI,EAIpDS,EAAY,YAAa,SAAS,EAElCA,EAAY,YAAa,SAASX,EAAIE,EAAE,SAAS,CAAC,OAAQ,EAAI,EAC9DV,GAAQ,iBAAmB,MAE3BmB,EAAY,QAAS,IAAIX,EAAIE,EAAE,SAAS,CAAC,GAAGF,EAAIE,EAAE,WAAW,CAAC,GAAG,EACjES,EAAY,aAAc,IAAIX,EAAIE,EAAE,SAAS,CAAC,GAAGF,EAAIE,EAAE,gBAAgB,CAAC,GAAG,EAI3ES,EAAY,YAAa,SAAS,EAElCA,EAAY,YAAa,SAASX,EAAIE,EAAE,SAAS,CAAC,OAAQ,EAAI,EAC9DV,GAAQ,iBAAmB,MAE3BmB,EAAY,QAAS,IAAIX,EAAIE,EAAE,SAAS,CAAC,GAAGF,EAAIE,EAAE,WAAW,CAAC,GAAG,EACjES,EAAY,aAAc,IAAIX,EAAIE,EAAE,SAAS,CAAC,GAAGF,EAAIE,EAAE,gBAAgB,CAAC,GAAG,EAG3ES,EAAY,kBAAmB,IAAIX,EAAIE,EAAE,IAAI,CAAC,QAAQF,EAAIE,EAAE,UAAU,CAAC,OAAO,EAC9ES,EAAY,aAAc,IAAIX,EAAIE,EAAE,IAAI,CAAC,QAAQF,EAAIE,EAAE,SAAS,CAAC,OAAO,EAIxES,EAAY,iBAAkB,SAASX,EAAIE,EAAE,IAAI,CACjD,QAAQF,EAAIE,EAAE,UAAU,CAAC,IAAIF,EAAIE,EAAE,WAAW,CAAC,IAAK,EAAI,EACxDV,GAAQ,sBAAwB,SAMhCmB,EAAY,cAAe,SAASX,EAAIE,EAAE,WAAW,CAAC,cAE/BF,EAAIE,EAAE,WAAW,CAAC,QACf,EAE1BS,EAAY,mBAAoB,SAASX,EAAIE,EAAE,gBAAgB,CAAC,cAEpCF,EAAIE,EAAE,gBAAgB,CAAC,QACpB,EAG/BS,EAAY,OAAQ,iBAAiB,EAErCA,EAAY,OAAQ,2BAA2B,EAC/CA,EAAY,UAAW,6BAA6B,IC9NpD,IAAAK,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAGA,IAAMC,GAAc,OAAO,OAAO,CAAE,MAAO,EAAK,CAAC,EAC3CC,GAAY,OAAO,OAAO,CAAE,CAAC,EAC7BC,GAAeC,EAAAC,GACdA,EAID,OAAOA,GAAY,SACdJ,GAGFI,EAPEH,GAFU,gBAWrBF,GAAO,QAAUG,KChBjB,IAAAG,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,IAAMC,GAAU,WACVC,GAAqBC,EAAA,CAACC,EAAGC,IAAM,CACnC,GAAI,OAAOD,GAAM,UAAY,OAAOC,GAAM,SACxC,OAAOD,IAAMC,EAAI,EAAID,EAAIC,EAAI,GAAK,EAGpC,IAAMC,EAAOL,GAAQ,KAAKG,CAAC,EACrBG,EAAON,GAAQ,KAAKI,CAAC,EAE3B,OAAIC,GAAQC,IACVH,EAAI,CAACA,EACLC,EAAI,CAACA,GAGAD,IAAMC,EAAI,EACZC,GAAQ,CAACC,EAAQ,GACjBA,GAAQ,CAACD,EAAQ,EAClBF,EAAIC,EAAI,GACR,CACN,EAlB2B,sBAoBrBG,GAAsBL,EAAA,CAACC,EAAGC,IAAMH,GAAmBG,EAAGD,CAAC,EAAjC,uBAE5BJ,GAAO,QAAU,CACf,mBAAAE,GACA,oBAAAM,EACF,IC5BA,IAAAC,EAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,IAAMC,GAAQ,KACR,CAAE,WAAAC,GAAY,iBAAAC,EAAiB,EAAI,KACnC,CAAE,OAAQC,GAAI,EAAAC,EAAE,EAAI,KAEpBC,GAAe,KACf,CAAE,mBAAAC,EAAmB,EAAI,KACzBC,GAAN,MAAMC,CAAO,CARb,MAQa,CAAAC,EAAA,eACX,YAAaC,EAASC,EAAS,CAG7B,GAFAA,EAAUN,GAAaM,CAAO,EAE1BD,aAAmBF,EAAQ,CAC7B,GAAIE,EAAQ,QAAU,CAAC,CAACC,EAAQ,OAC9BD,EAAQ,oBAAsB,CAAC,CAACC,EAAQ,kBACxC,OAAOD,EAEPA,EAAUA,EAAQ,OAEtB,SAAW,OAAOA,GAAY,SAC5B,MAAM,IAAI,UAAU,gDAAgD,OAAOA,CAAO,IAAI,EAGxF,GAAIA,EAAQ,OAAST,GACnB,MAAM,IAAI,UACR,0BAA0BA,EAAU,aACtC,EAGFD,GAAM,SAAUU,EAASC,CAAO,EAChC,KAAK,QAAUA,EACf,KAAK,MAAQ,CAAC,CAACA,EAAQ,MAGvB,KAAK,kBAAoB,CAAC,CAACA,EAAQ,kBAEnC,IAAMC,EAAIF,EAAQ,KAAK,EAAE,MAAMC,EAAQ,MAAQR,GAAGC,GAAE,KAAK,EAAID,GAAGC,GAAE,IAAI,CAAC,EAEvE,GAAI,CAACQ,EACH,MAAM,IAAI,UAAU,oBAAoBF,CAAO,EAAE,EAUnD,GAPA,KAAK,IAAMA,EAGX,KAAK,MAAQ,CAACE,EAAE,CAAC,EACjB,KAAK,MAAQ,CAACA,EAAE,CAAC,EACjB,KAAK,MAAQ,CAACA,EAAE,CAAC,EAEb,KAAK,MAAQV,IAAoB,KAAK,MAAQ,EAChD,MAAM,IAAI,UAAU,uBAAuB,EAG7C,GAAI,KAAK,MAAQA,IAAoB,KAAK,MAAQ,EAChD,MAAM,IAAI,UAAU,uBAAuB,EAG7C,GAAI,KAAK,MAAQA,IAAoB,KAAK,MAAQ,EAChD,MAAM,IAAI,UAAU,uBAAuB,EAIxCU,EAAE,CAAC,EAGN,KAAK,WAAaA,EAAE,CAAC,EAAE,MAAM,GAAG,EAAE,IAAKC,GAAO,CAC5C,GAAI,WAAW,KAAKA,CAAE,EAAG,CACvB,IAAMC,EAAM,CAACD,EACb,GAAIC,GAAO,GAAKA,EAAMZ,GACpB,OAAOY,CAEX,CACA,OAAOD,CACT,CAAC,EAVD,KAAK,WAAa,CAAC,EAarB,KAAK,MAAQD,EAAE,CAAC,EAAIA,EAAE,CAAC,EAAE,MAAM,GAAG,EAAI,CAAC,EACvC,KAAK,OAAO,CACd,CAEA,QAAU,CACR,YAAK,QAAU,GAAG,KAAK,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,KAAK,GACpD,KAAK,WAAW,SAClB,KAAK,SAAW,IAAI,KAAK,WAAW,KAAK,GAAG,CAAC,IAExC,KAAK,OACd,CAEA,UAAY,CACV,OAAO,KAAK,OACd,CAEA,QAASG,EAAO,CAEd,GADAf,GAAM,iBAAkB,KAAK,QAAS,KAAK,QAASe,CAAK,EACrD,EAAEA,aAAiBP,GAAS,CAC9B,GAAI,OAAOO,GAAU,UAAYA,IAAU,KAAK,QAC9C,MAAO,GAETA,EAAQ,IAAIP,EAAOO,EAAO,KAAK,OAAO,CACxC,CAEA,OAAIA,EAAM,UAAY,KAAK,QAClB,EAGF,KAAK,YAAYA,CAAK,GAAK,KAAK,WAAWA,CAAK,CACzD,CAEA,YAAaA,EAAO,CAKlB,OAJMA,aAAiBP,IACrBO,EAAQ,IAAIP,EAAOO,EAAO,KAAK,OAAO,GAGpC,KAAK,MAAQA,EAAM,MACd,GAEL,KAAK,MAAQA,EAAM,MACd,EAEL,KAAK,MAAQA,EAAM,MACd,GAEL,KAAK,MAAQA,EAAM,MACd,EAEL,KAAK,MAAQA,EAAM,MACd,GAEL,KAAK,MAAQA,EAAM,MACd,EAEF,CACT,CAEA,WAAYA,EAAO,CAMjB,GALMA,aAAiBP,IACrBO,EAAQ,IAAIP,EAAOO,EAAO,KAAK,OAAO,GAIpC,KAAK,WAAW,QAAU,CAACA,EAAM,WAAW,OAC9C,MAAO,GACF,GAAI,CAAC,KAAK,WAAW,QAAUA,EAAM,WAAW,OACrD,MAAO,GACF,GAAI,CAAC,KAAK,WAAW,QAAU,CAACA,EAAM,WAAW,OACtD,MAAO,GAGT,IAAIC,EAAI,EACR,EAAG,CACD,IAAMC,EAAI,KAAK,WAAWD,CAAC,EACrBE,EAAIH,EAAM,WAAWC,CAAC,EAE5B,GADAhB,GAAM,qBAAsBgB,EAAGC,EAAGC,CAAC,EAC/BD,IAAM,QAAaC,IAAM,OAC3B,MAAO,GACF,GAAIA,IAAM,OACf,MAAO,GACF,GAAID,IAAM,OACf,MAAO,GACF,GAAIA,IAAMC,EACf,SAEA,OAAOZ,GAAmBW,EAAGC,CAAC,CAElC,OAAS,EAAEF,EACb,CAEA,aAAcD,EAAO,CACbA,aAAiBP,IACrBO,EAAQ,IAAIP,EAAOO,EAAO,KAAK,OAAO,GAGxC,IAAIC,EAAI,EACR,EAAG,CACD,IAAMC,EAAI,KAAK,MAAMD,CAAC,EAChBE,EAAIH,EAAM,MAAMC,CAAC,EAEvB,GADAhB,GAAM,gBAAiBgB,EAAGC,EAAGC,CAAC,EAC1BD,IAAM,QAAaC,IAAM,OAC3B,MAAO,GACF,GAAIA,IAAM,OACf,MAAO,GACF,GAAID,IAAM,OACf,MAAO,GACF,GAAIA,IAAMC,EACf,SAEA,OAAOZ,GAAmBW,EAAGC,CAAC,CAElC,OAAS,EAAEF,EACb,CAIA,IAAKG,EAASC,EAAYC,EAAgB,CACxC,GAAIF,EAAQ,WAAW,KAAK,EAAG,CAC7B,GAAI,CAACC,GAAcC,IAAmB,GACpC,MAAM,IAAI,MAAM,iDAAiD,EAGnE,GAAID,EAAY,CACd,IAAME,EAAQ,IAAIF,CAAU,GAAG,MAAM,KAAK,QAAQ,MAAQjB,GAAGC,GAAE,eAAe,EAAID,GAAGC,GAAE,UAAU,CAAC,EAClG,GAAI,CAACkB,GAASA,EAAM,CAAC,IAAMF,EACzB,MAAM,IAAI,MAAM,uBAAuBA,CAAU,EAAE,CAEvD,CACF,CAEA,OAAQD,EAAS,CACf,IAAK,WACH,KAAK,WAAW,OAAS,EACzB,KAAK,MAAQ,EACb,KAAK,MAAQ,EACb,KAAK,QACL,KAAK,IAAI,MAAOC,EAAYC,CAAc,EAC1C,MACF,IAAK,WACH,KAAK,WAAW,OAAS,EACzB,KAAK,MAAQ,EACb,KAAK,QACL,KAAK,IAAI,MAAOD,EAAYC,CAAc,EAC1C,MACF,IAAK,WAIH,KAAK,WAAW,OAAS,EACzB,KAAK,IAAI,QAASD,EAAYC,CAAc,EAC5C,KAAK,IAAI,MAAOD,EAAYC,CAAc,EAC1C,MAGF,IAAK,aACC,KAAK,WAAW,SAAW,GAC7B,KAAK,IAAI,QAASD,EAAYC,CAAc,EAE9C,KAAK,IAAI,MAAOD,EAAYC,CAAc,EAC1C,MACF,IAAK,UACH,GAAI,KAAK,WAAW,SAAW,EAC7B,MAAM,IAAI,MAAM,WAAW,KAAK,GAAG,sBAAsB,EAE3D,KAAK,WAAW,OAAS,EACzB,MAEF,IAAK,SAMD,KAAK,QAAU,GACf,KAAK,QAAU,GACf,KAAK,WAAW,SAAW,IAE3B,KAAK,QAEP,KAAK,MAAQ,EACb,KAAK,MAAQ,EACb,KAAK,WAAa,CAAC,EACnB,MACF,IAAK,SAKC,KAAK,QAAU,GAAK,KAAK,WAAW,SAAW,IACjD,KAAK,QAEP,KAAK,MAAQ,EACb,KAAK,WAAa,CAAC,EACnB,MACF,IAAK,QAKC,KAAK,WAAW,SAAW,GAC7B,KAAK,QAEP,KAAK,WAAa,CAAC,EACnB,MAGF,IAAK,MAAO,CACV,IAAME,EAAO,OAAOF,CAAc,EAAI,EAAI,EAE1C,GAAI,KAAK,WAAW,SAAW,EAC7B,KAAK,WAAa,CAACE,CAAI,MAClB,CACL,IAAIP,EAAI,KAAK,WAAW,OACxB,KAAO,EAAEA,GAAK,GACR,OAAO,KAAK,WAAWA,CAAC,GAAM,WAChC,KAAK,WAAWA,CAAC,IACjBA,EAAI,IAGR,GAAIA,IAAM,GAAI,CAEZ,GAAII,IAAe,KAAK,WAAW,KAAK,GAAG,GAAKC,IAAmB,GACjE,MAAM,IAAI,MAAM,uDAAuD,EAEzE,KAAK,WAAW,KAAKE,CAAI,CAC3B,CACF,CACA,GAAIH,EAAY,CAGd,IAAII,EAAa,CAACJ,EAAYG,CAAI,EAC9BF,IAAmB,KACrBG,EAAa,CAACJ,CAAU,GAEtBd,GAAmB,KAAK,WAAW,CAAC,EAAGc,CAAU,IAAM,EACrD,MAAM,KAAK,WAAW,CAAC,CAAC,IAC1B,KAAK,WAAaI,GAGpB,KAAK,WAAaA,CAEtB,CACA,KACF,CACA,QACE,MAAM,IAAI,MAAM,+BAA+BL,CAAO,EAAE,CAC5D,CACA,YAAK,IAAM,KAAK,OAAO,EACnB,KAAK,MAAM,SACb,KAAK,KAAO,IAAI,KAAK,MAAM,KAAK,GAAG,CAAC,IAE/B,IACT,CACF,EAEApB,GAAO,QAAUQ,KC5UjB,IAAAkB,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,IAAMC,GAAS,IACTC,GAAQC,EAAA,CAACC,EAASC,EAASC,EAAc,KAAU,CACvD,GAAIF,aAAmBH,GACrB,OAAOG,EAET,GAAI,CACF,OAAO,IAAIH,GAAOG,EAASC,CAAO,CACpC,OAASE,EAAI,CACX,GAAI,CAACD,EACH,OAAO,KAET,MAAMC,CACR,CACF,EAZc,SAcdP,GAAO,QAAUE,KCjBjB,IAAAM,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,IAAMC,GAAQ,KACRC,GAAQC,EAAA,CAACC,EAASC,IAAY,CAClC,IAAMC,EAAIL,GAAMG,EAASC,CAAO,EAChC,OAAOC,EAAIA,EAAE,QAAU,IACzB,EAHc,SAIdN,GAAO,QAAUE,KCPjB,IAAAK,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,IAAMC,GAAQ,KACRC,GAAQC,EAAA,CAACC,EAASC,IAAY,CAClC,IAAMC,EAAIL,GAAMG,EAAQ,KAAK,EAAE,QAAQ,SAAU,EAAE,EAAGC,CAAO,EAC7D,OAAOC,EAAIA,EAAE,QAAU,IACzB,EAHc,SAIdN,GAAO,QAAUE,KCPjB,IAAAK,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,IAAMC,GAAS,IAETC,GAAMC,EAAA,CAACC,EAASC,EAASC,EAASC,EAAYC,IAAmB,CACjE,OAAQF,GAAa,WACvBE,EAAiBD,EACjBA,EAAaD,EACbA,EAAU,QAGZ,GAAI,CACF,OAAO,IAAIL,GACTG,aAAmBH,GAASG,EAAQ,QAAUA,EAC9CE,CACF,EAAE,IAAID,EAASE,EAAYC,CAAc,EAAE,OAC7C,MAAa,CACX,OAAO,IACT,CACF,EAfY,OAgBZR,GAAO,QAAUE,KCpBjB,IAAAO,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,IAAMC,GAAQ,KAERC,GAAOC,EAAA,CAACC,EAAUC,IAAa,CACnC,IAAMC,EAAKL,GAAMG,EAAU,KAAM,EAAI,EAC/BG,EAAKN,GAAMI,EAAU,KAAM,EAAI,EAC/BG,EAAaF,EAAG,QAAQC,CAAE,EAEhC,GAAIC,IAAe,EACjB,OAAO,KAGT,IAAMC,EAAWD,EAAa,EACxBE,EAAcD,EAAWH,EAAKC,EAC9BI,EAAaF,EAAWF,EAAKD,EAC7BM,EAAa,CAAC,CAACF,EAAY,WAAW,OAG5C,GAFkB,CAAC,CAACC,EAAW,WAAW,QAEzB,CAACC,EAAY,CAQ5B,GAAI,CAACD,EAAW,OAAS,CAACA,EAAW,MACnC,MAAO,QAIT,GAAIA,EAAW,YAAYD,CAAW,IAAM,EAC1C,OAAIC,EAAW,OAAS,CAACA,EAAW,MAC3B,QAEF,OAEX,CAGA,IAAME,EAASD,EAAa,MAAQ,GAEpC,OAAIN,EAAG,QAAUC,EAAG,MACXM,EAAS,QAGdP,EAAG,QAAUC,EAAG,MACXM,EAAS,QAGdP,EAAG,QAAUC,EAAG,MACXM,EAAS,QAIX,YACT,EArDa,QAuDbb,GAAO,QAAUE,KC3DjB,IAAAY,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,IAAMC,GAAS,IACTC,GAAQC,EAAA,CAACC,EAAGC,IAAU,IAAIJ,GAAOG,EAAGC,CAAK,EAAE,MAAnC,SACdL,GAAO,QAAUE,KCJjB,IAAAI,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,IAAMC,GAAS,IACTC,GAAQC,EAAA,CAACC,EAAGC,IAAU,IAAIJ,GAAOG,EAAGC,CAAK,EAAE,MAAnC,SACdL,GAAO,QAAUE,KCJjB,IAAAI,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,IAAMC,GAAS,IACTC,GAAQC,EAAA,CAACC,EAAGC,IAAU,IAAIJ,GAAOG,EAAGC,CAAK,EAAE,MAAnC,SACdL,GAAO,QAAUE,KCJjB,IAAAI,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,IAAMC,GAAQ,KACRC,GAAaC,EAAA,CAACC,EAASC,IAAY,CACvC,IAAMC,EAASL,GAAMG,EAASC,CAAO,EACrC,OAAQC,GAAUA,EAAO,WAAW,OAAUA,EAAO,WAAa,IACpE,EAHmB,cAInBN,GAAO,QAAUE,KCPjB,IAAAK,EAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,IAAMC,GAAS,IACTC,GAAUC,EAAA,CAACC,EAAGC,EAAGC,IACrB,IAAIL,GAAOG,EAAGE,CAAK,EAAE,QAAQ,IAAIL,GAAOI,EAAGC,CAAK,CAAC,EADnC,WAGhBN,GAAO,QAAUE,KCNjB,IAAAK,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,IAAMC,GAAU,IACVC,GAAWC,EAAA,CAACC,EAAGC,EAAGC,IAAUL,GAAQI,EAAGD,EAAGE,CAAK,EAApC,YACjBN,GAAO,QAAUE,KCJjB,IAAAK,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,IAAMC,GAAU,IACVC,GAAeC,EAAA,CAACC,EAAGC,IAAMJ,GAAQG,EAAGC,EAAG,EAAI,EAA5B,gBACrBL,GAAO,QAAUE,KCJjB,IAAAI,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,IAAMC,GAAS,IACTC,GAAeC,EAAA,CAACC,EAAGC,EAAGC,IAAU,CACpC,IAAMC,EAAW,IAAIN,GAAOG,EAAGE,CAAK,EAC9BE,EAAW,IAAIP,GAAOI,EAAGC,CAAK,EACpC,OAAOC,EAAS,QAAQC,CAAQ,GAAKD,EAAS,aAAaC,CAAQ,CACrE,EAJqB,gBAKrBR,GAAO,QAAUE,KCRjB,IAAAO,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,IAAMC,GAAe,KACfC,GAAOC,EAAA,CAACC,EAAMC,IAAUD,EAAK,KAAK,CAACE,EAAGC,IAAMN,GAAaK,EAAGC,EAAGF,CAAK,CAAC,EAA9D,QACbL,GAAO,QAAUE,KCJjB,IAAAM,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,IAAMC,GAAe,KACfC,GAAQC,EAAA,CAACC,EAAMC,IAAUD,EAAK,KAAK,CAACE,EAAGC,IAAMN,GAAaM,EAAGD,EAAGD,CAAK,CAAC,EAA9D,SACdL,GAAO,QAAUE,KCJjB,IAAAM,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,IAAMC,GAAU,IACVC,GAAKC,EAAA,CAACC,EAAGC,EAAGC,IAAUL,GAAQG,EAAGC,EAAGC,CAAK,EAAI,EAAxC,MACXN,GAAO,QAAUE,KCJjB,IAAAK,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,IAAMC,GAAU,IACVC,GAAKC,EAAA,CAACC,EAAGC,EAAGC,IAAUL,GAAQG,EAAGC,EAAGC,CAAK,EAAI,EAAxC,MACXN,GAAO,QAAUE,KCJjB,IAAAK,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,IAAMC,GAAU,IACVC,GAAKC,EAAA,CAACC,EAAGC,EAAGC,IAAUL,GAAQG,EAAGC,EAAGC,CAAK,IAAM,EAA1C,MACXN,GAAO,QAAUE,KCJjB,IAAAK,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,IAAMC,GAAU,IACVC,GAAMC,EAAA,CAACC,EAAGC,EAAGC,IAAUL,GAAQG,EAAGC,EAAGC,CAAK,IAAM,EAA1C,OACZN,GAAO,QAAUE,KCJjB,IAAAK,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,IAAMC,GAAU,IACVC,GAAMC,EAAA,CAACC,EAAGC,EAAGC,IAAUL,GAAQG,EAAGC,EAAGC,CAAK,GAAK,EAAzC,OACZN,GAAO,QAAUE,KCJjB,IAAAK,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,IAAMC,GAAU,IACVC,GAAMC,EAAA,CAACC,EAAGC,EAAGC,IAAUL,GAAQG,EAAGC,EAAGC,CAAK,GAAK,EAAzC,OACZN,GAAO,QAAUE,KCJjB,IAAAK,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,IAAMC,GAAK,KACLC,GAAM,KACNC,GAAK,KACLC,GAAM,KACNC,GAAK,KACLC,GAAM,KAENC,GAAMC,EAAA,CAACC,EAAGC,EAAIC,EAAGC,IAAU,CAC/B,OAAQF,EAAI,CACV,IAAK,MACH,OAAI,OAAOD,GAAM,WACfA,EAAIA,EAAE,SAEJ,OAAOE,GAAM,WACfA,EAAIA,EAAE,SAEDF,IAAME,EAEf,IAAK,MACH,OAAI,OAAOF,GAAM,WACfA,EAAIA,EAAE,SAEJ,OAAOE,GAAM,WACfA,EAAIA,EAAE,SAEDF,IAAME,EAEf,IAAK,GACL,IAAK,IACL,IAAK,KACH,OAAOV,GAAGQ,EAAGE,EAAGC,CAAK,EAEvB,IAAK,KACH,OAAOV,GAAIO,EAAGE,EAAGC,CAAK,EAExB,IAAK,IACH,OAAOT,GAAGM,EAAGE,EAAGC,CAAK,EAEvB,IAAK,KACH,OAAOR,GAAIK,EAAGE,EAAGC,CAAK,EAExB,IAAK,IACH,OAAOP,GAAGI,EAAGE,EAAGC,CAAK,EAEvB,IAAK,KACH,OAAON,GAAIG,EAAGE,EAAGC,CAAK,EAExB,QACE,MAAM,IAAI,UAAU,qBAAqBF,CAAE,EAAE,CACjD,CACF,EA3CY,OA4CZV,GAAO,QAAUO,KCrDjB,IAAAM,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,IAAMC,GAAS,IACTC,GAAQ,KACR,CAAE,OAAQC,GAAI,EAAAC,EAAE,EAAI,KAEpBC,GAASC,EAAA,CAACC,EAASC,IAAY,CACnC,GAAID,aAAmBN,GACrB,OAAOM,EAOT,GAJI,OAAOA,GAAY,WACrBA,EAAU,OAAOA,CAAO,GAGtB,OAAOA,GAAY,SACrB,OAAO,KAGTC,EAAUA,GAAW,CAAC,EAEtB,IAAIC,EAAQ,KACZ,GAAI,CAACD,EAAQ,IACXC,EAAQF,EAAQ,MAAMC,EAAQ,kBAAoBL,GAAGC,GAAE,UAAU,EAAID,GAAGC,GAAE,MAAM,CAAC,MAC5E,CAUL,IAAMM,EAAiBF,EAAQ,kBAAoBL,GAAGC,GAAE,aAAa,EAAID,GAAGC,GAAE,SAAS,EACnFO,EACJ,MAAQA,EAAOD,EAAe,KAAKH,CAAO,KACrC,CAACE,GAASA,EAAM,MAAQA,EAAM,CAAC,EAAE,SAAWF,EAAQ,UAEnD,CAACE,GACCE,EAAK,MAAQA,EAAK,CAAC,EAAE,SAAWF,EAAM,MAAQA,EAAM,CAAC,EAAE,UAC3DA,EAAQE,GAEVD,EAAe,UAAYC,EAAK,MAAQA,EAAK,CAAC,EAAE,OAASA,EAAK,CAAC,EAAE,OAGnED,EAAe,UAAY,EAC7B,CAEA,GAAID,IAAU,KACZ,OAAO,KAGT,IAAMG,EAAQH,EAAM,CAAC,EACfI,EAAQJ,EAAM,CAAC,GAAK,IACpBK,EAAQL,EAAM,CAAC,GAAK,IACpBM,EAAaP,EAAQ,mBAAqBC,EAAM,CAAC,EAAI,IAAIA,EAAM,CAAC,CAAC,GAAK,GACtEO,EAAQR,EAAQ,mBAAqBC,EAAM,CAAC,EAAI,IAAIA,EAAM,CAAC,CAAC,GAAK,GAEvE,OAAOP,GAAM,GAAGU,CAAK,IAAIC,CAAK,IAAIC,CAAK,GAAGC,CAAU,GAAGC,CAAK,GAAIR,CAAO,CACzE,EAtDe,UAuDfR,GAAO,QAAUK,KC7DjB,IAAAY,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,IAAMC,GAAN,KAAe,CAFf,MAEe,CAAAC,EAAA,iBACb,aAAe,CACb,KAAK,IAAM,IACX,KAAK,IAAM,IAAI,GACjB,CAEA,IAAKC,EAAK,CACR,IAAMC,EAAQ,KAAK,IAAI,IAAID,CAAG,EAC9B,GAAIC,IAAU,OAIZ,YAAK,IAAI,OAAOD,CAAG,EACnB,KAAK,IAAI,IAAIA,EAAKC,CAAK,EAChBA,CAEX,CAEA,OAAQD,EAAK,CACX,OAAO,KAAK,IAAI,OAAOA,CAAG,CAC5B,CAEA,IAAKA,EAAKC,EAAO,CAGf,GAAI,CAFY,KAAK,OAAOD,CAAG,GAEfC,IAAU,OAAW,CAEnC,GAAI,KAAK,IAAI,MAAQ,KAAK,IAAK,CAC7B,IAAMC,EAAW,KAAK,IAAI,KAAK,EAAE,KAAK,EAAE,MACxC,KAAK,OAAOA,CAAQ,CACtB,CAEA,KAAK,IAAI,IAAIF,EAAKC,CAAK,CACzB,CAEA,OAAO,IACT,CACF,EAEAJ,GAAO,QAAUC,KCzCjB,IAAAK,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,IAAMC,GAAmB,OAGnBC,GAAN,MAAMC,CAAM,CALZ,MAKY,CAAAC,EAAA,cACV,YAAaC,EAAOC,EAAS,CAG3B,GAFAA,EAAUC,GAAaD,CAAO,EAE1BD,aAAiBF,EACnB,OACEE,EAAM,QAAU,CAAC,CAACC,EAAQ,OAC1BD,EAAM,oBAAsB,CAAC,CAACC,EAAQ,kBAE/BD,EAEA,IAAIF,EAAME,EAAM,IAAKC,CAAO,EAIvC,GAAID,aAAiBG,GAEnB,YAAK,IAAMH,EAAM,MACjB,KAAK,IAAM,CAAC,CAACA,CAAK,CAAC,EACnB,KAAK,UAAY,OACV,KAsBT,GAnBA,KAAK,QAAUC,EACf,KAAK,MAAQ,CAAC,CAACA,EAAQ,MACvB,KAAK,kBAAoB,CAAC,CAACA,EAAQ,kBAKnC,KAAK,IAAMD,EAAM,KAAK,EAAE,QAAQJ,GAAkB,GAAG,EAGrD,KAAK,IAAM,KAAK,IACb,MAAM,IAAI,EAEV,IAAI,GAAK,KAAK,WAAW,EAAE,KAAK,CAAC,CAAC,EAIlC,OAAOQ,GAAKA,EAAE,MAAM,EAEnB,CAAC,KAAK,IAAI,OACZ,MAAM,IAAI,UAAU,yBAAyB,KAAK,GAAG,EAAE,EAIzD,GAAI,KAAK,IAAI,OAAS,EAAG,CAEvB,IAAMC,EAAQ,KAAK,IAAI,CAAC,EAExB,GADA,KAAK,IAAM,KAAK,IAAI,OAAOD,GAAK,CAACE,GAAUF,EAAE,CAAC,CAAC,CAAC,EAC5C,KAAK,IAAI,SAAW,EACtB,KAAK,IAAM,CAACC,CAAK,UACR,KAAK,IAAI,OAAS,GAE3B,QAAWD,KAAK,KAAK,IACnB,GAAIA,EAAE,SAAW,GAAKG,GAAMH,EAAE,CAAC,CAAC,EAAG,CACjC,KAAK,IAAM,CAACA,CAAC,EACb,KACF,EAGN,CAEA,KAAK,UAAY,MACnB,CAEA,IAAI,OAAS,CACX,GAAI,KAAK,YAAc,OAAW,CAChC,KAAK,UAAY,GACjB,QAASI,EAAI,EAAGA,EAAI,KAAK,IAAI,OAAQA,IAAK,CACpCA,EAAI,IACN,KAAK,WAAa,MAEpB,IAAMC,EAAQ,KAAK,IAAID,CAAC,EACxB,QAASE,EAAI,EAAGA,EAAID,EAAM,OAAQC,IAC5BA,EAAI,IACN,KAAK,WAAa,KAEpB,KAAK,WAAaD,EAAMC,CAAC,EAAE,SAAS,EAAE,KAAK,CAE/C,CACF,CACA,OAAO,KAAK,SACd,CAEA,QAAU,CACR,OAAO,KAAK,KACd,CAEA,UAAY,CACV,OAAO,KAAK,KACd,CAEA,WAAYV,EAAO,CAMjB,IAAMW,IAFH,KAAK,QAAQ,mBAAqBC,KAClC,KAAK,QAAQ,OAASC,KACE,IAAMb,EAC3Bc,EAASC,GAAM,IAAIJ,CAAO,EAChC,GAAIG,EACF,OAAOA,EAGT,IAAME,EAAQ,KAAK,QAAQ,MAErBC,EAAKD,EAAQE,EAAGC,EAAE,gBAAgB,EAAID,EAAGC,EAAE,WAAW,EAC5DnB,EAAQA,EAAM,QAAQiB,EAAIG,GAAc,KAAK,QAAQ,iBAAiB,CAAC,EACvEC,EAAM,iBAAkBrB,CAAK,EAG7BA,EAAQA,EAAM,QAAQkB,EAAGC,EAAE,cAAc,EAAGG,EAAqB,EACjED,EAAM,kBAAmBrB,CAAK,EAG9BA,EAAQA,EAAM,QAAQkB,EAAGC,EAAE,SAAS,EAAGI,EAAgB,EACvDF,EAAM,aAAcrB,CAAK,EAGzBA,EAAQA,EAAM,QAAQkB,EAAGC,EAAE,SAAS,EAAGK,EAAgB,EACvDH,EAAM,aAAcrB,CAAK,EAKzB,IAAIyB,EAAYzB,EACb,MAAM,GAAG,EACT,IAAI0B,GAAQC,GAAgBD,EAAM,KAAK,OAAO,CAAC,EAC/C,KAAK,GAAG,EACR,MAAM,KAAK,EAEX,IAAIA,GAAQE,GAAYF,EAAM,KAAK,OAAO,CAAC,EAE1CV,IAEFS,EAAYA,EAAU,OAAOC,IAC3BL,EAAM,uBAAwBK,EAAM,KAAK,OAAO,EACzC,CAAC,CAACA,EAAK,MAAMR,EAAGC,EAAE,eAAe,CAAC,EAC1C,GAEHE,EAAM,aAAcI,CAAS,EAK7B,IAAMI,EAAW,IAAI,IACfC,EAAcL,EAAU,IAAIC,GAAQ,IAAIvB,GAAWuB,EAAM,KAAK,OAAO,CAAC,EAC5E,QAAWA,KAAQI,EAAa,CAC9B,GAAIxB,GAAUoB,CAAI,EAChB,MAAO,CAACA,CAAI,EAEdG,EAAS,IAAIH,EAAK,MAAOA,CAAI,CAC/B,CACIG,EAAS,KAAO,GAAKA,EAAS,IAAI,EAAE,GACtCA,EAAS,OAAO,EAAE,EAGpB,IAAME,EAAS,CAAC,GAAGF,EAAS,OAAO,CAAC,EACpC,OAAAd,GAAM,IAAIJ,EAASoB,CAAM,EAClBA,CACT,CAEA,WAAY/B,EAAOC,EAAS,CAC1B,GAAI,EAAED,aAAiBF,GACrB,MAAM,IAAI,UAAU,qBAAqB,EAG3C,OAAO,KAAK,IAAI,KAAMkC,GAElBC,GAAcD,EAAiB/B,CAAO,GACtCD,EAAM,IAAI,KAAMkC,GAEZD,GAAcC,EAAkBjC,CAAO,GACvC+B,EAAgB,MAAOG,GACdD,EAAiB,MAAOE,GACtBD,EAAe,WAAWC,EAAiBnC,CAAO,CAC1D,CACF,CAEJ,CAEJ,CACH,CAGA,KAAMoC,EAAS,CACb,GAAI,CAACA,EACH,MAAO,GAGT,GAAI,OAAOA,GAAY,SACrB,GAAI,CACFA,EAAU,IAAIC,GAAOD,EAAS,KAAK,OAAO,CAC5C,MAAa,CACX,MAAO,EACT,CAGF,QAAS7B,EAAI,EAAGA,EAAI,KAAK,IAAI,OAAQA,IACnC,GAAI+B,GAAQ,KAAK,IAAI/B,CAAC,EAAG6B,EAAS,KAAK,OAAO,EAC5C,MAAO,GAGX,MAAO,EACT,CACF,EAEA1C,GAAO,QAAUE,GAEjB,IAAM2C,GAAM,KACNzB,GAAQ,IAAIyB,GAEZtC,GAAe,KACfC,GAAa,KACbkB,EAAQ,KACRiB,GAAS,IACT,CACJ,OAAQpB,EACR,EAAAC,EACA,sBAAAG,GACA,iBAAAC,GACA,iBAAAC,EACF,EAAI,KACE,CAAE,wBAAAZ,GAAyB,WAAAC,EAAW,EAAI,KAE1CP,GAAYP,EAAAK,GAAKA,EAAE,QAAU,WAAjB,aACZG,GAAQR,EAAAK,GAAKA,EAAE,QAAU,GAAjB,SAIR6B,GAAgBlC,EAAA,CAAC+B,EAAa7B,IAAY,CAC9C,IAAI8B,EAAS,GACPU,EAAuBX,EAAY,MAAM,EAC3CY,EAAiBD,EAAqB,IAAI,EAE9C,KAAOV,GAAUU,EAAqB,QACpCV,EAASU,EAAqB,MAAOE,GAC5BD,EAAe,WAAWC,EAAiB1C,CAAO,CAC1D,EAEDyC,EAAiBD,EAAqB,IAAI,EAG5C,OAAOV,CACT,EAdsB,iBAmBhBJ,GAAkB5B,EAAA,CAAC2B,EAAMzB,KAC7ByB,EAAOA,EAAK,QAAQR,EAAGC,EAAE,KAAK,EAAG,EAAE,EACnCE,EAAM,OAAQK,EAAMzB,CAAO,EAC3ByB,EAAOkB,GAAclB,EAAMzB,CAAO,EAClCoB,EAAM,QAASK,CAAI,EACnBA,EAAOmB,GAAcnB,EAAMzB,CAAO,EAClCoB,EAAM,SAAUK,CAAI,EACpBA,EAAOoB,GAAepB,EAAMzB,CAAO,EACnCoB,EAAM,SAAUK,CAAI,EACpBA,EAAOqB,GAAarB,EAAMzB,CAAO,EACjCoB,EAAM,QAASK,CAAI,EACZA,GAXe,mBAclBsB,EAAMjD,EAAAkD,GAAM,CAACA,GAAMA,EAAG,YAAY,IAAM,KAAOA,IAAO,IAAhD,OASNJ,GAAgB9C,EAAA,CAAC2B,EAAMzB,IACpByB,EACJ,KAAK,EACL,MAAM,KAAK,EACX,IAAKtB,GAAM8C,GAAa9C,EAAGH,CAAO,CAAC,EACnC,KAAK,GAAG,EALS,iBAQhBiD,GAAenD,EAAA,CAAC2B,EAAMzB,IAAY,CACtC,IAAMkD,EAAIlD,EAAQ,MAAQiB,EAAGC,EAAE,UAAU,EAAID,EAAGC,EAAE,KAAK,EACvD,OAAOO,EAAK,QAAQyB,EAAG,CAACC,EAAGC,EAAGC,EAAGC,EAAGC,IAAO,CACzCnC,EAAM,QAASK,EAAM0B,EAAGC,EAAGC,EAAGC,EAAGC,CAAE,EACnC,IAAIC,EAEJ,OAAIT,EAAIK,CAAC,EACPI,EAAM,GACGT,EAAIM,CAAC,EACdG,EAAM,KAAKJ,CAAC,SAAS,CAACA,EAAI,CAAC,SAClBL,EAAIO,CAAC,EAEdE,EAAM,KAAKJ,CAAC,IAAIC,CAAC,OAAOD,CAAC,IAAI,CAACC,EAAI,CAAC,OAC1BE,GACTnC,EAAM,kBAAmBmC,CAAE,EAC3BC,EAAM,KAAKJ,CAAC,IAAIC,CAAC,IAAIC,CAAC,IAAIC,CAC1B,KAAKH,CAAC,IAAI,CAACC,EAAI,CAAC,QAGhBG,EAAM,KAAKJ,CAAC,IAAIC,CAAC,IAAIC,CACrB,KAAKF,CAAC,IAAI,CAACC,EAAI,CAAC,OAGlBjC,EAAM,eAAgBoC,CAAG,EAClBA,CACT,CAAC,CACH,EA1BqB,gBAoCfb,GAAgB7C,EAAA,CAAC2B,EAAMzB,IACpByB,EACJ,KAAK,EACL,MAAM,KAAK,EACX,IAAKtB,GAAMsD,GAAatD,EAAGH,CAAO,CAAC,EACnC,KAAK,GAAG,EALS,iBAQhByD,GAAe3D,EAAA,CAAC2B,EAAMzB,IAAY,CACtCoB,EAAM,QAASK,EAAMzB,CAAO,EAC5B,IAAMkD,EAAIlD,EAAQ,MAAQiB,EAAGC,EAAE,UAAU,EAAID,EAAGC,EAAE,KAAK,EACjDwC,EAAI1D,EAAQ,kBAAoB,KAAO,GAC7C,OAAOyB,EAAK,QAAQyB,EAAG,CAACC,EAAGC,EAAGC,EAAGC,EAAGC,IAAO,CACzCnC,EAAM,QAASK,EAAM0B,EAAGC,EAAGC,EAAGC,EAAGC,CAAE,EACnC,IAAIC,EAEJ,OAAIT,EAAIK,CAAC,EACPI,EAAM,GACGT,EAAIM,CAAC,EACdG,EAAM,KAAKJ,CAAC,OAAOM,CAAC,KAAK,CAACN,EAAI,CAAC,SACtBL,EAAIO,CAAC,EACVF,IAAM,IACRI,EAAM,KAAKJ,CAAC,IAAIC,CAAC,KAAKK,CAAC,KAAKN,CAAC,IAAI,CAACC,EAAI,CAAC,OAEvCG,EAAM,KAAKJ,CAAC,IAAIC,CAAC,KAAKK,CAAC,KAAK,CAACN,EAAI,CAAC,SAE3BG,GACTnC,EAAM,kBAAmBmC,CAAE,EACvBH,IAAM,IACJC,IAAM,IACRG,EAAM,KAAKJ,CAAC,IAAIC,CAAC,IAAIC,CAAC,IAAIC,CAC1B,KAAKH,CAAC,IAAIC,CAAC,IAAI,CAACC,EAAI,CAAC,KAErBE,EAAM,KAAKJ,CAAC,IAAIC,CAAC,IAAIC,CAAC,IAAIC,CAC1B,KAAKH,CAAC,IAAI,CAACC,EAAI,CAAC,OAGlBG,EAAM,KAAKJ,CAAC,IAAIC,CAAC,IAAIC,CAAC,IAAIC,CAC1B,KAAK,CAACH,EAAI,CAAC,WAGbhC,EAAM,OAAO,EACTgC,IAAM,IACJC,IAAM,IACRG,EAAM,KAAKJ,CAAC,IAAIC,CAAC,IAAIC,CACrB,GAAGI,CAAC,KAAKN,CAAC,IAAIC,CAAC,IAAI,CAACC,EAAI,CAAC,KAEzBE,EAAM,KAAKJ,CAAC,IAAIC,CAAC,IAAIC,CACrB,GAAGI,CAAC,KAAKN,CAAC,IAAI,CAACC,EAAI,CAAC,OAGtBG,EAAM,KAAKJ,CAAC,IAAIC,CAAC,IAAIC,CACrB,KAAK,CAACF,EAAI,CAAC,UAIfhC,EAAM,eAAgBoC,CAAG,EAClBA,CACT,CAAC,CACH,EAnDqB,gBAqDfX,GAAiB/C,EAAA,CAAC2B,EAAMzB,KAC5BoB,EAAM,iBAAkBK,EAAMzB,CAAO,EAC9ByB,EACJ,MAAM,KAAK,EACX,IAAKtB,GAAMwD,GAAcxD,EAAGH,CAAO,CAAC,EACpC,KAAK,GAAG,GALU,kBAQjB2D,GAAgB7D,EAAA,CAAC2B,EAAMzB,IAAY,CACvCyB,EAAOA,EAAK,KAAK,EACjB,IAAMyB,EAAIlD,EAAQ,MAAQiB,EAAGC,EAAE,WAAW,EAAID,EAAGC,EAAE,MAAM,EACzD,OAAOO,EAAK,QAAQyB,EAAG,CAACM,EAAKI,EAAMR,EAAGC,EAAGC,EAAGC,IAAO,CACjDnC,EAAM,SAAUK,EAAM+B,EAAKI,EAAMR,EAAGC,EAAGC,EAAGC,CAAE,EAC5C,IAAMM,EAAKd,EAAIK,CAAC,EACVU,EAAKD,GAAMd,EAAIM,CAAC,EAChBU,EAAKD,GAAMf,EAAIO,CAAC,EAChBU,EAAOD,EAEb,OAAIH,IAAS,KAAOI,IAClBJ,EAAO,IAKTL,EAAKvD,EAAQ,kBAAoB,KAAO,GAEpC6D,EACED,IAAS,KAAOA,IAAS,IAE3BJ,EAAM,WAGNA,EAAM,IAECI,GAAQI,GAGbF,IACFT,EAAI,GAENC,EAAI,EAEAM,IAAS,KAGXA,EAAO,KACHE,GACFV,EAAI,CAACA,EAAI,EACTC,EAAI,EACJC,EAAI,IAEJD,EAAI,CAACA,EAAI,EACTC,EAAI,IAEGM,IAAS,OAGlBA,EAAO,IACHE,EACFV,EAAI,CAACA,EAAI,EAETC,EAAI,CAACA,EAAI,GAITO,IAAS,MACXL,EAAK,MAGPC,EAAM,GAAGI,EAAOR,CAAC,IAAIC,CAAC,IAAIC,CAAC,GAAGC,CAAE,IACvBO,EACTN,EAAM,KAAKJ,CAAC,OAAOG,CAAE,KAAK,CAACH,EAAI,CAAC,SACvBW,IACTP,EAAM,KAAKJ,CAAC,IAAIC,CAAC,KAAKE,CACtB,KAAKH,CAAC,IAAI,CAACC,EAAI,CAAC,QAGlBjC,EAAM,gBAAiBoC,CAAG,EAEnBA,CACT,CAAC,CACH,EAzEsB,iBA6EhBV,GAAehD,EAAA,CAAC2B,EAAMzB,KAC1BoB,EAAM,eAAgBK,EAAMzB,CAAO,EAE5ByB,EACJ,KAAK,EACL,QAAQR,EAAGC,EAAE,IAAI,EAAG,EAAE,GALN,gBAQfS,GAAc7B,EAAA,CAAC2B,EAAMzB,KACzBoB,EAAM,cAAeK,EAAMzB,CAAO,EAC3ByB,EACJ,KAAK,EACL,QAAQR,EAAGjB,EAAQ,kBAAoBkB,EAAE,QAAUA,EAAE,IAAI,EAAG,EAAE,GAJ/C,eAadC,GAAgBrB,EAAAmE,GAAS,CAACC,EAC9BC,EAAMC,EAAIC,EAAIC,EAAIC,EAAKC,EACvBC,EAAIC,EAAIC,EAAIC,EAAIC,KACZ9B,EAAIqB,CAAE,EACRD,EAAO,GACEpB,EAAIsB,CAAE,EACfF,EAAO,KAAKC,CAAE,OAAOH,EAAQ,KAAO,EAAE,GAC7BlB,EAAIuB,CAAE,EACfH,EAAO,KAAKC,CAAE,IAAIC,CAAE,KAAKJ,EAAQ,KAAO,EAAE,GACjCM,EACTJ,EAAO,KAAKA,CAAI,GAEhBA,EAAO,KAAKA,CAAI,GAAGF,EAAQ,KAAO,EAAE,GAGlClB,EAAI2B,CAAE,EACRD,EAAK,GACI1B,EAAI4B,CAAE,EACfF,EAAK,IAAI,CAACC,EAAK,CAAC,SACP3B,EAAI6B,CAAE,EACfH,EAAK,IAAIC,CAAE,IAAI,CAACC,EAAK,CAAC,OACbE,EACTJ,EAAK,KAAKC,CAAE,IAAIC,CAAE,IAAIC,CAAE,IAAIC,CAAG,GACtBZ,EACTQ,EAAK,IAAIC,CAAE,IAAIC,CAAE,IAAI,CAACC,EAAK,CAAC,KAE5BH,EAAK,KAAKA,CAAE,GAGP,GAAGN,CAAI,IAAIM,CAAE,GAAG,KAAK,GA7BR,iBAgChBnC,GAAUxC,EAAA,CAACgF,EAAK1C,EAASpC,IAAY,CACzC,QAASO,EAAI,EAAGA,EAAIuE,EAAI,OAAQvE,IAC9B,GAAI,CAACuE,EAAIvE,CAAC,EAAE,KAAK6B,CAAO,EACtB,MAAO,GAIX,GAAIA,EAAQ,WAAW,QAAU,CAACpC,EAAQ,kBAAmB,CAM3D,QAASO,EAAI,EAAGA,EAAIuE,EAAI,OAAQvE,IAE9B,GADAa,EAAM0D,EAAIvE,CAAC,EAAE,MAAM,EACfuE,EAAIvE,CAAC,EAAE,SAAWL,GAAW,KAI7B4E,EAAIvE,CAAC,EAAE,OAAO,WAAW,OAAS,EAAG,CACvC,IAAMwE,EAAUD,EAAIvE,CAAC,EAAE,OACvB,GAAIwE,EAAQ,QAAU3C,EAAQ,OAC1B2C,EAAQ,QAAU3C,EAAQ,OAC1B2C,EAAQ,QAAU3C,EAAQ,MAC5B,MAAO,EAEX,CAIF,MAAO,EACT,CAEA,MAAO,EACT,EAlCgB,aC1gBhB,IAAA4C,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,IAAMC,GAAM,OAAO,YAAY,EAEzBC,GAAN,MAAMC,CAAW,CAJjB,MAIiB,CAAAC,EAAA,mBACf,WAAW,KAAO,CAChB,OAAOH,EACT,CAEA,YAAaI,EAAMC,EAAS,CAG1B,GAFAA,EAAUC,GAAaD,CAAO,EAE1BD,aAAgBF,EAAY,CAC9B,GAAIE,EAAK,QAAU,CAAC,CAACC,EAAQ,MAC3B,OAAOD,EAEPA,EAAOA,EAAK,KAEhB,CAEAA,EAAOA,EAAK,KAAK,EAAE,MAAM,KAAK,EAAE,KAAK,GAAG,EACxCG,GAAM,aAAcH,EAAMC,CAAO,EACjC,KAAK,QAAUA,EACf,KAAK,MAAQ,CAAC,CAACA,EAAQ,MACvB,KAAK,MAAMD,CAAI,EAEX,KAAK,SAAWJ,GAClB,KAAK,MAAQ,GAEb,KAAK,MAAQ,KAAK,SAAW,KAAK,OAAO,QAG3CO,GAAM,OAAQ,IAAI,CACpB,CAEA,MAAOH,EAAM,CACX,IAAMI,EAAI,KAAK,QAAQ,MAAQC,GAAGC,GAAE,eAAe,EAAID,GAAGC,GAAE,UAAU,EAChEC,EAAIP,EAAK,MAAMI,CAAC,EAEtB,GAAI,CAACG,EACH,MAAM,IAAI,UAAU,uBAAuBP,CAAI,EAAE,EAGnD,KAAK,SAAWO,EAAE,CAAC,IAAM,OAAYA,EAAE,CAAC,EAAI,GACxC,KAAK,WAAa,MACpB,KAAK,SAAW,IAIbA,EAAE,CAAC,EAGN,KAAK,OAAS,IAAIC,GAAOD,EAAE,CAAC,EAAG,KAAK,QAAQ,KAAK,EAFjD,KAAK,OAASX,EAIlB,CAEA,UAAY,CACV,OAAO,KAAK,KACd,CAEA,KAAMa,EAAS,CAGb,GAFAN,GAAM,kBAAmBM,EAAS,KAAK,QAAQ,KAAK,EAEhD,KAAK,SAAWb,IAAOa,IAAYb,GACrC,MAAO,GAGT,GAAI,OAAOa,GAAY,SACrB,GAAI,CACFA,EAAU,IAAID,GAAOC,EAAS,KAAK,OAAO,CAC5C,MAAa,CACX,MAAO,EACT,CAGF,OAAOC,GAAID,EAAS,KAAK,SAAU,KAAK,OAAQ,KAAK,OAAO,CAC9D,CAEA,WAAYT,EAAMC,EAAS,CACzB,GAAI,EAAED,aAAgBF,GACpB,MAAM,IAAI,UAAU,0BAA0B,EAGhD,OAAI,KAAK,WAAa,GAChB,KAAK,QAAU,GACV,GAEF,IAAIa,GAAMX,EAAK,MAAOC,CAAO,EAAE,KAAK,KAAK,KAAK,EAC5CD,EAAK,WAAa,GACvBA,EAAK,QAAU,GACV,GAEF,IAAIW,GAAM,KAAK,MAAOV,CAAO,EAAE,KAAKD,EAAK,MAAM,GAGxDC,EAAUC,GAAaD,CAAO,EAG1BA,EAAQ,oBACT,KAAK,QAAU,YAAcD,EAAK,QAAU,aAG3C,CAACC,EAAQ,oBACV,KAAK,MAAM,WAAW,QAAQ,GAAKD,EAAK,MAAM,WAAW,QAAQ,GAC3D,GAIL,QAAK,SAAS,WAAW,GAAG,GAAKA,EAAK,SAAS,WAAW,GAAG,GAI7D,KAAK,SAAS,WAAW,GAAG,GAAKA,EAAK,SAAS,WAAW,GAAG,GAK9D,KAAK,OAAO,UAAYA,EAAK,OAAO,SACrC,KAAK,SAAS,SAAS,GAAG,GAAKA,EAAK,SAAS,SAAS,GAAG,GAIvDU,GAAI,KAAK,OAAQ,IAAKV,EAAK,OAAQC,CAAO,GAC5C,KAAK,SAAS,WAAW,GAAG,GAAKD,EAAK,SAAS,WAAW,GAAG,GAI3DU,GAAI,KAAK,OAAQ,IAAKV,EAAK,OAAQC,CAAO,GAC5C,KAAK,SAAS,WAAW,GAAG,GAAKD,EAAK,SAAS,WAAW,GAAG,GAIjE,CACF,EAEAL,GAAO,QAAUE,GAEjB,IAAMK,GAAe,KACf,CAAE,OAAQG,GAAI,EAAAC,EAAE,EAAI,KACpBI,GAAM,KACNP,GAAQ,KACRK,GAAS,IACTG,GAAQ,OC9Id,IAAAC,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,IAAMC,GAAQ,KACRC,GAAYC,EAAA,CAACC,EAASC,EAAOC,IAAY,CAC7C,GAAI,CACFD,EAAQ,IAAIJ,GAAMI,EAAOC,CAAO,CAClC,MAAa,CACX,MAAO,EACT,CACA,OAAOD,EAAM,KAAKD,CAAO,CAC3B,EAPkB,aAQlBJ,GAAO,QAAUE,KCXjB,IAAAK,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,IAAMC,GAAQ,KAGRC,GAAgBC,EAAA,CAACC,EAAOC,IAC5B,IAAIJ,GAAMG,EAAOC,CAAO,EAAE,IACvB,IAAIC,GAAQA,EAAK,IAAIC,GAAKA,EAAE,KAAK,EAAE,KAAK,GAAG,EAAE,KAAK,EAAE,MAAM,GAAG,CAAC,EAF7C,iBAItBP,GAAO,QAAUE,KCTjB,IAAAM,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,IAAMC,GAAS,IACTC,GAAQ,KAERC,GAAgBC,EAAA,CAACC,EAAUC,EAAOC,IAAY,CAClD,IAAIC,EAAM,KACNC,EAAQ,KACRC,EAAW,KACf,GAAI,CACFA,EAAW,IAAIR,GAAMI,EAAOC,CAAO,CACrC,MAAa,CACX,OAAO,IACT,CACA,OAAAF,EAAS,QAASM,GAAM,CAClBD,EAAS,KAAKC,CAAC,IAEb,CAACH,GAAOC,EAAM,QAAQE,CAAC,IAAM,MAE/BH,EAAMG,EACNF,EAAQ,IAAIR,GAAOO,EAAKD,CAAO,EAGrC,CAAC,EACMC,CACT,EApBsB,iBAqBtBR,GAAO,QAAUG,KC1BjB,IAAAS,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,IAAMC,GAAS,IACTC,GAAQ,KACRC,GAAgBC,EAAA,CAACC,EAAUC,EAAOC,IAAY,CAClD,IAAIC,EAAM,KACNC,EAAQ,KACRC,EAAW,KACf,GAAI,CACFA,EAAW,IAAIR,GAAMI,EAAOC,CAAO,CACrC,MAAa,CACX,OAAO,IACT,CACA,OAAAF,EAAS,QAASM,GAAM,CAClBD,EAAS,KAAKC,CAAC,IAEb,CAACH,GAAOC,EAAM,QAAQE,CAAC,IAAM,KAE/BH,EAAMG,EACNF,EAAQ,IAAIR,GAAOO,EAAKD,CAAO,EAGrC,CAAC,EACMC,CACT,EApBsB,iBAqBtBR,GAAO,QAAUG,KCzBjB,IAAAS,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,IAAMC,GAAS,IACTC,GAAQ,KACRC,GAAK,KAELC,GAAaC,EAAA,CAACC,EAAOC,IAAU,CACnCD,EAAQ,IAAIJ,GAAMI,EAAOC,CAAK,EAE9B,IAAIC,EAAS,IAAIP,GAAO,OAAO,EAM/B,GALIK,EAAM,KAAKE,CAAM,IAIrBA,EAAS,IAAIP,GAAO,SAAS,EACzBK,EAAM,KAAKE,CAAM,GACnB,OAAOA,EAGTA,EAAS,KACT,QAASC,EAAI,EAAGA,EAAIH,EAAM,IAAI,OAAQ,EAAEG,EAAG,CACzC,IAAMC,EAAcJ,EAAM,IAAIG,CAAC,EAE3BE,EAAS,KACbD,EAAY,QAASE,GAAe,CAElC,IAAMC,EAAU,IAAIZ,GAAOW,EAAW,OAAO,OAAO,EACpD,OAAQA,EAAW,SAAU,CAC3B,IAAK,IACCC,EAAQ,WAAW,SAAW,EAChCA,EAAQ,QAERA,EAAQ,WAAW,KAAK,CAAC,EAE3BA,EAAQ,IAAMA,EAAQ,OAAO,EAE/B,IAAK,GACL,IAAK,MACC,CAACF,GAAUR,GAAGU,EAASF,CAAM,KAC/BA,EAASE,GAEX,MACF,IAAK,IACL,IAAK,KAEH,MAEF,QACE,MAAM,IAAI,MAAM,yBAAyBD,EAAW,QAAQ,EAAE,CAClE,CACF,CAAC,EACGD,IAAW,CAACH,GAAUL,GAAGK,EAAQG,CAAM,KACzCH,EAASG,EAEb,CAEA,OAAIH,GAAUF,EAAM,KAAKE,CAAM,EACtBA,EAGF,IACT,EAvDmB,cAwDnBR,GAAO,QAAUI,KC9DjB,IAAAU,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,IAAMC,GAAQ,KACRC,GAAaC,EAAA,CAACC,EAAOC,IAAY,CACrC,GAAI,CAGF,OAAO,IAAIJ,GAAMG,EAAOC,CAAO,EAAE,OAAS,GAC5C,MAAa,CACX,OAAO,IACT,CACF,EARmB,cASnBL,GAAO,QAAUE,KCZjB,IAAAI,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,IAAMC,GAAS,IACTC,GAAa,KACb,CAAE,IAAAC,EAAI,EAAID,GACVE,GAAQ,KACRC,GAAY,KACZC,GAAK,KACLC,GAAK,KACLC,GAAM,KACNC,GAAM,KAENC,GAAUC,EAAA,CAACC,EAASC,EAAOC,EAAMC,IAAY,CACjDH,EAAU,IAAIX,GAAOW,EAASG,CAAO,EACrCF,EAAQ,IAAIT,GAAMS,EAAOE,CAAO,EAEhC,IAAIC,EAAMC,EAAOC,EAAMC,EAAMC,EAC7B,OAAQN,EAAM,CACZ,IAAK,IACHE,EAAOV,GACPW,EAAQT,GACRU,EAAOX,GACPY,EAAO,IACPC,EAAQ,KACR,MACF,IAAK,IACHJ,EAAOT,GACPU,EAAQR,GACRS,EAAOZ,GACPa,EAAO,IACPC,EAAQ,KACR,MACF,QACE,MAAM,IAAI,UAAU,uCAAuC,CAC/D,CAGA,GAAIf,GAAUO,EAASC,EAAOE,CAAO,EACnC,MAAO,GAMT,QAASM,EAAI,EAAGA,EAAIR,EAAM,IAAI,OAAQ,EAAEQ,EAAG,CACzC,IAAMC,EAAcT,EAAM,IAAIQ,CAAC,EAE3BE,EAAO,KACPC,EAAM,KAuBV,GArBAF,EAAY,QAASG,GAAe,CAC9BA,EAAW,SAAWtB,KACxBsB,EAAa,IAAIvB,GAAW,SAAS,GAEvCqB,EAAOA,GAAQE,EACfD,EAAMA,GAAOC,EACTT,EAAKS,EAAW,OAAQF,EAAK,OAAQR,CAAO,EAC9CQ,EAAOE,EACEP,EAAKO,EAAW,OAAQD,EAAI,OAAQT,CAAO,IACpDS,EAAMC,EAEV,CAAC,EAIGF,EAAK,WAAaJ,GAAQI,EAAK,WAAaH,IAM3C,CAACI,EAAI,UAAYA,EAAI,WAAaL,IACnCF,EAAML,EAASY,EAAI,MAAM,EAC3B,MAAO,GACF,GAAIA,EAAI,WAAaJ,GAASF,EAAKN,EAASY,EAAI,MAAM,EAC3D,MAAO,EAEX,CACA,MAAO,EACT,EAnEgB,WAqEhBxB,GAAO,QAAUU,KCjFjB,IAAAgB,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAGA,IAAMC,GAAU,KACVC,GAAMC,EAAA,CAACC,EAASC,EAAOC,IAAYL,GAAQG,EAASC,EAAO,IAAKC,CAAO,EAAjE,OACZN,GAAO,QAAUE,KCLjB,IAAAK,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,IAAMC,GAAU,KAEVC,GAAMC,EAAA,CAACC,EAASC,EAAOC,IAAYL,GAAQG,EAASC,EAAO,IAAKC,CAAO,EAAjE,OACZN,GAAO,QAAUE,KCLjB,IAAAK,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,IAAMC,GAAQ,KACRC,GAAaC,EAAA,CAACC,EAAIC,EAAIC,KAC1BF,EAAK,IAAIH,GAAMG,EAAIE,CAAO,EAC1BD,EAAK,IAAIJ,GAAMI,EAAIC,CAAO,EACnBF,EAAG,WAAWC,EAAIC,CAAO,GAHf,cAKnBN,GAAO,QAAUE,KCRjB,IAAAK,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAKA,IAAMC,GAAY,KACZC,GAAU,IAChBF,GAAO,QAAU,CAACG,EAAUC,EAAOC,IAAY,CAC7C,IAAMC,EAAM,CAAC,EACTC,EAAQ,KACRC,EAAO,KACLC,EAAIN,EAAS,KAAK,CAACO,EAAGC,IAAMT,GAAQQ,EAAGC,EAAGN,CAAO,CAAC,EACxD,QAAWO,KAAWH,EACHR,GAAUW,EAASR,EAAOC,CAAO,GAEhDG,EAAOI,EACFL,IACHA,EAAQK,KAGNJ,GACFF,EAAI,KAAK,CAACC,EAAOC,CAAI,CAAC,EAExBA,EAAO,KACPD,EAAQ,MAGRA,GACFD,EAAI,KAAK,CAACC,EAAO,IAAI,CAAC,EAGxB,IAAMM,EAAS,CAAC,EAChB,OAAW,CAACC,EAAKC,CAAG,IAAKT,EACnBQ,IAAQC,EACVF,EAAO,KAAKC,CAAG,EACN,CAACC,GAAOD,IAAQL,EAAE,CAAC,EAC5BI,EAAO,KAAK,GAAG,EACLE,EAEDD,IAAQL,EAAE,CAAC,EACpBI,EAAO,KAAK,KAAKE,CAAG,EAAE,EAEtBF,EAAO,KAAK,GAAGC,CAAG,MAAMC,CAAG,EAAE,EAJ7BF,EAAO,KAAK,KAAKC,CAAG,EAAE,EAO1B,IAAME,EAAaH,EAAO,KAAK,MAAM,EAC/BI,EAAW,OAAOb,EAAM,KAAQ,SAAWA,EAAM,IAAM,OAAOA,CAAK,EACzE,OAAOY,EAAW,OAASC,EAAS,OAASD,EAAaZ,CAC5D,IChDA,IAAAc,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,IAAMC,GAAQ,KACRC,GAAa,KACb,CAAE,IAAAC,EAAI,EAAID,GACVE,GAAY,KACZC,GAAU,IAsCVC,GAASC,EAAA,CAACC,EAAKC,EAAKC,EAAU,CAAC,IAAM,CACzC,GAAIF,IAAQC,EACV,MAAO,GAGTD,EAAM,IAAIP,GAAMO,EAAKE,CAAO,EAC5BD,EAAM,IAAIR,GAAMQ,EAAKC,CAAO,EAC5B,IAAIC,EAAa,GAEjBC,EAAO,QAAWC,KAAaL,EAAI,IAAK,CACtC,QAAWM,KAAaL,EAAI,IAAK,CAC/B,IAAMM,EAAQC,GAAaH,EAAWC,EAAWJ,CAAO,EAExD,GADAC,EAAaA,GAAcI,IAAU,KACjCA,EACF,SAASH,CAEb,CAKA,GAAID,EACF,MAAO,EAEX,CACA,MAAO,EACT,EA1Be,UA4BTM,GAA+B,CAAC,IAAIf,GAAW,WAAW,CAAC,EAC3DgB,GAAiB,CAAC,IAAIhB,GAAW,SAAS,CAAC,EAE3Cc,GAAeT,EAAA,CAACC,EAAKC,EAAKC,IAAY,CAC1C,GAAIF,IAAQC,EACV,MAAO,GAGT,GAAID,EAAI,SAAW,GAAKA,EAAI,CAAC,EAAE,SAAWL,GAAK,CAC7C,GAAIM,EAAI,SAAW,GAAKA,EAAI,CAAC,EAAE,SAAWN,GACxC,MAAO,GACEO,EAAQ,kBACjBF,EAAMS,GAENT,EAAMU,EAEV,CAEA,GAAIT,EAAI,SAAW,GAAKA,EAAI,CAAC,EAAE,SAAWN,GAAK,CAC7C,GAAIO,EAAQ,kBACV,MAAO,GAEPD,EAAMS,EAEV,CAEA,IAAMC,EAAQ,IAAI,IACdC,EAAIC,EACR,QAAWC,KAAKd,EACVc,EAAE,WAAa,KAAOA,EAAE,WAAa,KACvCF,EAAKG,GAASH,EAAIE,EAAGZ,CAAO,EACnBY,EAAE,WAAa,KAAOA,EAAE,WAAa,KAC9CD,EAAKG,GAAQH,EAAIC,EAAGZ,CAAO,EAE3BS,EAAM,IAAIG,EAAE,MAAM,EAItB,GAAIH,EAAM,KAAO,EACf,OAAO,KAGT,IAAIM,EACJ,GAAIL,GAAMC,EAAI,CAEZ,GADAI,EAAWpB,GAAQe,EAAG,OAAQC,EAAG,OAAQX,CAAO,EAC5Ce,EAAW,EACb,OAAO,KACF,GAAIA,IAAa,IAAML,EAAG,WAAa,MAAQC,EAAG,WAAa,MACpE,OAAO,IAEX,CAGA,QAAWK,KAAMP,EAAO,CAKtB,GAJIC,GAAM,CAAChB,GAAUsB,EAAI,OAAON,CAAE,EAAGV,CAAO,GAIxCW,GAAM,CAACjB,GAAUsB,EAAI,OAAOL,CAAE,EAAGX,CAAO,EAC1C,OAAO,KAGT,QAAWY,KAAKb,EACd,GAAI,CAACL,GAAUsB,EAAI,OAAOJ,CAAC,EAAGZ,CAAO,EACnC,MAAO,GAIX,MAAO,EACT,CAEA,IAAIiB,EAAQC,EACRC,EAAUC,EAGVC,EAAeV,GACjB,CAACX,EAAQ,mBACTW,EAAG,OAAO,WAAW,OAASA,EAAG,OAAS,GACxCW,EAAeZ,GACjB,CAACV,EAAQ,mBACTU,EAAG,OAAO,WAAW,OAASA,EAAG,OAAS,GAExCW,GAAgBA,EAAa,WAAW,SAAW,GACnDV,EAAG,WAAa,KAAOU,EAAa,WAAW,CAAC,IAAM,IACxDA,EAAe,IAGjB,QAAWT,KAAKb,EAAK,CAGnB,GAFAqB,EAAWA,GAAYR,EAAE,WAAa,KAAOA,EAAE,WAAa,KAC5DO,EAAWA,GAAYP,EAAE,WAAa,KAAOA,EAAE,WAAa,KACxDF,GASF,GARIY,GACEV,EAAE,OAAO,YAAcA,EAAE,OAAO,WAAW,QAC3CA,EAAE,OAAO,QAAUU,EAAa,OAChCV,EAAE,OAAO,QAAUU,EAAa,OAChCV,EAAE,OAAO,QAAUU,EAAa,QAClCA,EAAe,IAGfV,EAAE,WAAa,KAAOA,EAAE,WAAa,MAEvC,GADAK,EAASJ,GAASH,EAAIE,EAAGZ,CAAO,EAC5BiB,IAAWL,GAAKK,IAAWP,EAC7B,MAAO,WAEAA,EAAG,WAAa,MAAQ,CAAChB,GAAUgB,EAAG,OAAQ,OAAOE,CAAC,EAAGZ,CAAO,EACzE,MAAO,GAGX,GAAIW,GASF,GARIU,GACET,EAAE,OAAO,YAAcA,EAAE,OAAO,WAAW,QAC3CA,EAAE,OAAO,QAAUS,EAAa,OAChCT,EAAE,OAAO,QAAUS,EAAa,OAChCT,EAAE,OAAO,QAAUS,EAAa,QAClCA,EAAe,IAGfT,EAAE,WAAa,KAAOA,EAAE,WAAa,MAEvC,GADAM,EAAQJ,GAAQH,EAAIC,EAAGZ,CAAO,EAC1BkB,IAAUN,GAAKM,IAAUP,EAC3B,MAAO,WAEAA,EAAG,WAAa,MAAQ,CAACjB,GAAUiB,EAAG,OAAQ,OAAOC,CAAC,EAAGZ,CAAO,EACzE,MAAO,GAGX,GAAI,CAACY,EAAE,WAAaD,GAAMD,IAAOK,IAAa,EAC5C,MAAO,EAEX,CAgBA,MAXI,EAAAL,GAAMS,GAAY,CAACR,GAAMI,IAAa,GAItCJ,GAAMS,GAAY,CAACV,GAAMK,IAAa,GAOtCO,GAAgBD,EAKtB,EAnJqB,gBAsJfR,GAAWhB,EAAA,CAAC0B,EAAGC,EAAGxB,IAAY,CAClC,GAAI,CAACuB,EACH,OAAOC,EAET,IAAMC,EAAO9B,GAAQ4B,EAAE,OAAQC,EAAE,OAAQxB,CAAO,EAChD,OAAOyB,EAAO,EAAIF,EACdE,EAAO,GACPD,EAAE,WAAa,KAAOD,EAAE,WAAa,KAD1BC,EAEXD,CACN,EATiB,YAYXT,GAAUjB,EAAA,CAAC0B,EAAGC,EAAGxB,IAAY,CACjC,GAAI,CAACuB,EACH,OAAOC,EAET,IAAMC,EAAO9B,GAAQ4B,EAAE,OAAQC,EAAE,OAAQxB,CAAO,EAChD,OAAOyB,EAAO,EAAIF,EACdE,EAAO,GACPD,EAAE,WAAa,KAAOD,EAAE,WAAa,KAD1BC,EAEXD,CACN,EATgB,WAWhBjC,GAAO,QAAUM,KCxPjB,IAAA8B,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAGA,IAAMC,GAAa,KACbC,GAAY,KACZC,GAAS,IACTC,GAAc,KACdC,GAAQ,KACRC,GAAQ,KACRC,GAAQ,KACRC,GAAM,KACNC,GAAO,KACPC,GAAQ,KACRC,GAAQ,KACRC,GAAQ,KACRC,GAAa,KACbC,GAAU,IACVC,GAAW,KACXC,GAAe,KACfC,GAAe,KACfC,GAAO,KACPC,GAAQ,KACRC,GAAK,KACLC,GAAK,KACLC,GAAK,KACLC,GAAM,KACNC,GAAM,KACNC,GAAM,KACNC,GAAM,KACNC,GAAS,KACTC,GAAa,KACbC,GAAQ,KACRC,GAAY,KACZC,GAAgB,KAChBC,GAAgB,KAChBC,GAAgB,KAChBC,GAAa,KACbC,GAAa,KACbC,GAAU,KACVC,GAAM,KACNC,GAAM,KACNC,GAAa,KACbC,GAAgB,KAChBC,GAAS,KACfzC,GAAO,QAAU,CACf,MAAAK,GACA,MAAAC,GACA,MAAAC,GACA,IAAAC,GACA,KAAAC,GACA,MAAAC,GACA,MAAAC,GACA,MAAAC,GACA,WAAAC,GACA,QAAAC,GACA,SAAAC,GACA,aAAAC,GACA,aAAAC,GACA,KAAAC,GACA,MAAAC,GACA,GAAAC,GACA,GAAAC,GACA,GAAAC,GACA,IAAAC,GACA,IAAAC,GACA,IAAAC,GACA,IAAAC,GACA,OAAAC,GACA,WAAAC,GACA,MAAAC,GACA,UAAAC,GACA,cAAAC,GACA,cAAAC,GACA,cAAAC,GACA,WAAAC,GACA,WAAAC,GACA,QAAAC,GACA,IAAAC,GACA,IAAAC,GACA,WAAAC,GACA,cAAAC,GACA,OAAAC,GACA,OAAAtC,GACA,GAAIF,GAAW,GACf,IAAKA,GAAW,IAChB,OAAQA,GAAW,EACnB,oBAAqBC,GAAU,oBAC/B,cAAeA,GAAU,cACzB,mBAAoBE,GAAY,mBAChC,oBAAqBA,GAAY,mBACnC,IC1FA,OAAS,QAAAsC,GAAM,SAAAC,OAAa,gBAC5B,OAAS,aAAAC,OAAiB,OAD1B,IAIAC,GAEMC,GAEOC,GARbC,GAAAC,EAAA,kBAGAC,IACAL,GAAmB,WAEbC,GAAYF,GAAUF,EAAI,EAEnBK,GAAN,KAAiB,CARxB,MAQwB,CAAAI,EAAA,mBACd,SAER,YAAYC,EAAqB,CAC/B,KAAK,SAAWA,GAAYC,EAAY,CAC1C,CAKA,MAAM,eAAeC,EAAgC,CACnD,IAAMC,EAAY,WAAW,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,OAAO,EAAG,CAAC,CAAC,GAC5EC,EAAY,KAAK,IAAI,EAK3B,KAAK,SAAS,UAAU,sBAAuB,CAC7C,QAAAF,EACA,UAAAC,EACA,UAAW,KAAK,IAAI,CACtB,CAAC,EAED,IAAME,EAAad,GAAM,MAAO,CAC9B,UACA,KACA,kBAAkBW,CAAO,GACzB,2CACF,CAAC,EAED,OAAO,IAAI,QAAQ,CAACI,EAASC,IAAW,CACtCF,EAAW,OAAO,GAAG,OAASG,GAAS,CACrC,IAAMC,EAAUD,EAAK,SAAS,EAG9B,KAAK,SAAS,UAAU,kBAAmB,CACzC,QAAAN,EACA,UAAAC,EACA,KAAM,SACN,QAAAM,EACA,UAAW,KAAK,IAAI,CACtB,CAAC,CACH,CAAC,EAEDJ,EAAW,OAAO,GAAG,OAASG,GAAS,CACrC,IAAMC,EAAUD,EAAK,SAAS,EAG9B,KAAK,SAAS,UAAU,kBAAmB,CACzC,QAAAN,EACA,UAAAC,EACA,KAAM,SACN,QAAAM,EACA,UAAW,KAAK,IAAI,CACtB,CAAC,CACH,CAAC,EAEDJ,EAAW,GAAG,QAAUK,GAAS,CAC/B,IAAMC,EAAW,KAAK,IAAI,EAAIP,EAE9B,GAAIM,IAAS,EAEX,KAAK,SAAS,UAAU,wBAAyB,CAC/C,QAAAR,EACA,UAAAC,EACA,QAAS,GACT,SAAAQ,EACA,UAAW,KAAK,IAAI,CACtB,CAAC,EAEDL,EAAQ,MACH,CACL,IAAMM,EAAQ,qDAAaF,CAAI,GAI/B,KAAK,SAAS,UAAU,qBAAsB,CAC5C,QAAAR,EACA,UAAAC,EACA,MAAAS,EACA,SAAAD,EACA,UAAW,KAAK,IAAI,CACtB,CAAC,EAEDJ,EAAO,IAAI,MAAMK,CAAK,CAAC,CACzB,CACF,CAAC,CACH,CAAC,CACH,CAKA,MAAM,mBAAqC,CACzC,GAAM,CAAE,OAAAC,CAAO,EAAI,MAAMnB,GACvB,uFACF,EAEA,OADa,KAAK,MAAMmB,CAAM,EAClB,eAAe,gBAAgB,GAAG,SAAW,SAC3D,CAKA,OAAgB,cAAgB,CAC9B,OAAQ,SACR,GAAI,KACJ,KAAM,OACN,IAAK,KACP,EAKA,MAAM,qBAAqBC,EAAO,SAA6B,CAC7D,GAAI,CACF,GAAM,CAAE,OAAAD,CAAO,EAAI,MAAMnB,GACvB,mFACF,EAKIqB,EAHa,KAAK,MAAMF,CAAM,EAGF,OAAQX,GAC/BA,GAAW,OAAOA,GAAY,UAAY,GAAAc,QAAO,MAAMd,CAAO,CACtE,EAGD,OAAIY,IAAS,QACXC,EAAmBA,EAAiB,OAAQb,GAAY,CACtD,IAAMe,EAAa,GAAAD,QAAO,WAAWd,CAAO,EAE5C,OAAIY,IAAS,SAEJG,IAAe,KAGpBH,IAAS,KAGTG,IAAe,MACfA,EAAW,CAAC,GAAG,SAAS,GAAG,YAAY,GAAG,WAAW,IAAI,IACvD,GAIFH,IAAS,OAGTG,IAAe,MACfA,EAAW,CAAC,GAAG,SAAS,GAAG,YAAY,GAAG,WAAW,MAAM,IACzD,GAIC,EACT,CAAC,GAIIF,EAAiB,KAAK,CAACG,EAAGC,IAAM,GAAAH,QAAO,SAASE,EAAGC,CAAC,CAAC,CAC9D,MAAgB,CAGd,MAAO,CAAC,CACV,CACF,CAMA,MAAM,uBAKH,CACD,GAAI,CAEF,IAAMC,EAAiB,MAAM,KAAK,kBAAkB,EAGpD,GAAI,CAACA,GAAkBA,IAAmB,UACxC,MAAO,CACL,eAAgB,UAChB,cAAe,KACf,UAAW,GACX,MAAO,8DACT,EAIF,IAAMC,EAAiB,MAAM,KAAK,qBAAqB,QAAQ,EAE/D,GAAIA,EAAe,SAAW,EAC5B,MAAO,CACL,eAAAD,EACA,cAAe,KACf,UAAW,GACX,MAAO,8DACT,EAIF,IAAME,EAAgBD,EAAe,CAAC,EAGlCE,EAAY,GAChB,GAAI,CAEFA,EAAY,GAAAP,QAAO,GAAGM,EAAeF,CAAc,CACrD,MAAgB,CAGdG,EAAYD,IAAkBF,CAChC,CAIA,MAAO,CACL,eAAAA,EACA,cAAAE,EACA,UAAAC,CACF,CACF,OAASX,EAAO,CAEd,MAAO,CACL,eAAgB,UAChB,cAAe,KACf,UAAW,GACX,MACEA,aAAiB,MAAQA,EAAM,QAAU,oEAC7C,CACF,CACF,CACF,ICpPA,IAAAY,GAAAC,EAAA,kBAAAC,OCIA,OAAS,KAAAC,OAAS,MAJlB,IAOMC,GAIOC,GAXbC,GAAAC,EAAA,kBAAAC,KACAC,IACAC,IAKMN,GAAsBD,GAAE,OAAO,CACnC,QAASA,GAAE,OAAO,EAAE,IAAI,EAAG,4CAAS,CACtC,CAAC,EAEYE,GAAN,KAAuB,CAX9B,MAW8B,CAAAM,EAAA,yBACpB,WACA,OAASC,EACT,SAAWC,EAAY,EACvB,eAAuC,IAAI,IAEnD,aAAc,CACZ,KAAK,WAAa,IAAIC,GAAW,KAAK,QAAQ,CAChD,CAOA,MAAM,cAAcC,EAA+B,CACjD,GAAI,CACF,IAAMC,EAAO,MAAMD,EAAE,IAAI,KAAK,EAGxBE,EAAcb,GAAoB,UAAUY,CAAI,EACtD,GAAI,CAACC,EAAY,QACf,OAAOF,EAAE,KACP,CACE,QAAS,GACT,MAAO,CACL,KAAM,kBACN,QAAS,mDACT,QAASE,EAAY,MAAM,OAAO,IAAKC,IAAS,CAC9C,MAAOA,EAAI,KAAK,KAAK,GAAG,EACxB,QAASA,EAAI,OACf,EAAE,CACJ,CACF,EACA,GACF,EAGF,GAAM,CAAE,QAAAC,CAAQ,EAAIF,EAAY,KAMhC,OAHyB,MAAM,KAAK,KAAK,eAAe,OAAO,CAAC,EAAE,KAC/DG,GAAMA,CACT,EAESL,EAAE,KACP,CACE,QAAS,GACT,MAAO,CACL,KAAM,sBACN,QAAS,oHACX,CACF,EACA,GACF,GAIF,KAAK,WAAW,eAAeI,CAAO,EAAE,MAAOE,GAAU,CACvD,KAAK,OAAO,MAAM,wCAAWA,CAAK,CACpC,CAAC,EAEMN,EAAE,KAAK,CACZ,QAAS,GACT,KAAM,CACJ,QAASI,EACT,QAAS,gFACX,EACA,QAAS,4CACX,CAAC,EACH,OAASE,EAAO,CACd,YAAK,OAAO,MAAM,oDAAaA,CAAK,EAC7BN,EAAE,KACP,CACE,QAAS,GACT,MAAO,CACL,KAAM,iBACN,QAASM,aAAiB,MAAQA,EAAM,QAAU,sCACpD,CACF,EACA,GACF,CACF,CACF,CACF,IC/FA,IA0BaC,GA1BbC,GAAAC,EAAA,kBAAAC,KACAC,KAEAC,IAuBaL,GAAN,KAAwB,CA1B/B,MA0B+B,CAAAM,EAAA,0BACrB,OAER,aAAc,CACZ,KAAK,OAASC,CAChB,CAKQ,oBACNC,EACAC,EACAC,EACkB,CAClB,MAAO,CACL,MAAO,CACL,KAAAF,EACA,QAAAC,EACA,QAAAC,CACF,CACF,CACF,CAKQ,sBACNC,EACAF,EACuB,CACvB,MAAO,CACL,QAAS,GACT,KAAAE,EACA,QAAAF,CACF,CACF,CAMA,MAAM,WAAWG,EAA+B,CAC9C,GAAI,CACF,KAAK,OAAO,MAAM,8DAAY,EAG9B,IAAMC,EAAcC,GAAa,eAAe,EAEhD,YAAK,OAAO,MAAM,oDAAaD,CAAW,EAEnCD,EAAE,KAAK,KAAK,sBAAsBC,CAAW,CAAC,CACvD,OAASE,EAAO,CACd,KAAK,OAAO,MAAM,oDAAaA,CAAK,EAEpC,IAAMC,EAAgB,KAAK,oBACzB,qBACAD,aAAiB,MAAQA,EAAM,QAAU,kDAC3C,EAEA,OAAOH,EAAE,KAAKI,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,iBAAiBJ,EAA+B,CACpD,GAAI,CACF,KAAK,OAAO,MAAM,wDAAW,EAE7B,IAAMK,EAAUH,GAAa,WAAW,EACxC,YAAK,OAAO,MAAM,+CAAYG,CAAO,EAAE,EAEhCL,EAAE,KAAK,KAAK,sBAAsB,CAAE,QAAAK,CAAQ,CAAC,CAAC,CACvD,OAASF,EAAO,CACd,KAAK,OAAO,MAAM,8CAAYA,CAAK,EAEnC,IAAMC,EAAgB,KAAK,oBACzB,qBACAD,aAAiB,MAAQA,EAAM,QAAU,4CAC3C,EAEA,OAAOH,EAAE,KAAKI,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,kBAAkBJ,EAA+B,CACrD,GAAI,CACF,YAAK,OAAO,MAAM,8DAAY,EAE9BE,GAAa,WAAW,EACxB,KAAK,OAAO,KAAK,4CAAS,EAEnBF,EAAE,KAAK,KAAK,sBAAsB,KAAM,4CAAS,CAAC,CAC3D,OAASG,EAAO,CACd,KAAK,OAAO,MAAM,oDAAaA,CAAK,EAEpC,IAAMC,EAAgB,KAAK,oBACzB,oBACAD,aAAiB,MAAQA,EAAM,QAAU,kDAC3C,EAEA,OAAOH,EAAE,KAAKI,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,qBAAqBJ,EAA+B,CACxD,GAAI,CACF,KAAK,OAAO,MAAM,0EAAc,EAGhC,IAAMM,EAAQN,EAAE,IAAI,MAAM,MAAM,GAAiB,SAG3CO,EAAa,CAAC,SAAU,KAAM,OAAQ,KAAK,EACjD,GAAI,CAACA,EAAW,SAASD,CAAc,EAAG,CACxC,IAAMF,EAAgB,KAAK,oBACzB,uBACA,+CAAYE,CAAI,yCAAWC,EAAW,KAAK,IAAI,CAAC,EAClD,EACA,OAAOP,EAAE,KAAKI,EAAe,GAAG,CAClC,CAGA,IAAMI,EAAW,MADE,IAAIC,GAAW,EACA,qBAAqBH,CAAc,EAErE,YAAK,OAAO,MAAM,sBAAOE,EAAS,MAAM,kDAAeF,CAAI,GAAG,EAEvDN,EAAE,KACP,KAAK,sBAAsB,CACzB,SAAAQ,EACA,KAAAF,EACA,MAAOE,EAAS,MAClB,CAAC,CACH,CACF,OAASL,EAAO,CACd,KAAK,OAAO,MAAM,gEAAeA,CAAK,EAEtC,IAAMC,EAAgB,KAAK,oBACzB,uBACAD,aAAiB,MAAQA,EAAM,QAAU,8DAC3C,EAEA,OAAOH,EAAE,KAAKI,EAAe,GAAG,CAClC,CACF,CAMA,MAAM,mBAAmBJ,EAA+B,CACtD,GAAI,CACF,KAAK,OAAO,MAAM,8DAAY,EAG9B,IAAMU,EAAS,MADI,IAAID,GAAW,EACF,sBAAsB,EAItD,OAFA,KAAK,OAAO,MAAM,wCAAWC,CAAM,EAE/BA,EAAO,MAEFV,EAAE,KACP,KAAK,sBAAsB,CACzB,eAAgBU,EAAO,eACvB,cAAeA,EAAO,cACtB,UAAWA,EAAO,UAClB,MAAOA,EAAO,KAChB,CAAC,CACH,EAGKV,EAAE,KACP,KAAK,sBAAsB,CACzB,eAAgBU,EAAO,eACvB,cAAeA,EAAO,cACtB,UAAWA,EAAO,SACpB,CAAC,CACH,CACF,OAASP,EAAO,CACd,KAAK,OAAO,MAAM,oDAAaA,CAAK,EAEpC,IAAMC,EAAgB,KAAK,oBACzB,6BACAD,aAAiB,MAAQA,EAAM,QAAU,kDAC3C,EAEA,OAAOH,EAAE,KAAKI,EAAe,GAAG,CAClC,CACF,CACF,IClOA,IAAAO,GAAAC,EAAA,kBAAAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,OCbA,IA6BaC,GA7BbC,GAAAC,EAAA,kBACAC,IAEAC,IA0BaJ,GAAN,KAAoB,CA7B3B,MA6B2B,CAAAK,EAAA,sBACjB,OACA,SACA,WAAyB,CAC/B,OAAQ,eACR,YAAa,GACb,iBAAkB,CAAC,CACrB,EACQ,cACA,iBACS,kBAAoB,KAErC,aAAc,CACZ,KAAK,OAASC,EACd,KAAK,SAAWC,EAAY,CAC9B,CAKA,iBAA8B,CAC5B,MAAO,CAAE,GAAG,KAAK,UAAW,CAC9B,CAKA,iBAAiBC,EAA2BC,EAAS,UAAiB,CACpE,GAAI,CACF,IAAMC,EAAY,CAAE,GAAG,KAAK,UAAW,EACvC,KAAK,WAAa,CAAE,GAAG,KAAK,WAAY,GAAGF,CAAK,EAE5CA,EAAK,gBACP,KAAK,WAAW,cAAgB,KAAK,IAAI,GAIvCA,EAAK,SAAW,aAClB,KAAK,sBAAsB,EAG7B,KAAK,OAAO,MAAM,iEAAeC,CAAM,GAAI,CACzC,IAAKC,EACL,IAAK,KAAK,UACZ,CAAC,EAGD,KAAK,SAAS,UAAU,iBAAkB,CACxC,OAAQ,KAAK,WACb,OAAAD,CACF,CAAC,CACH,OAASE,EAAO,CACd,KAAK,OAAO,MAAM,0DAAcA,CAAK,EACrC,KAAK,SAAS,UAAU,eAAgB,CACtC,MAAOA,aAAiB,MAAQA,EAAQ,IAAI,MAAM,OAAOA,CAAK,CAAC,EAC/D,UAAW,kBACb,CAAC,CACH,CACF,CAKA,kBAA8C,CAC5C,OAAO,KAAK,cAAgB,CAAE,GAAG,KAAK,aAAc,EAAI,MAC1D,CAKA,oBACEC,EACAD,EACM,CACN,GAAI,CAUF,OATA,KAAK,cAAgB,CACnB,OAAAC,EACA,MAAAD,EACA,UAAW,KAAK,IAAI,CACtB,EAEA,KAAK,OAAO,KAAK,yCAAWC,CAAM,GAAI,CAAE,MAAAD,CAAM,CAAC,EAGvCC,EAAQ,CACd,IAAK,aACH,KAAK,SAAS,UAAU,0BAA2B,CACjD,YAAa,KAAK,cAAc,aAAe,GAC/C,QAAS,KAAK,cAAc,SAAW,EACvC,UAAW,KAAK,cAAc,SAChC,CAAC,EACD,MACF,IAAK,YACH,KAAK,SAAS,UAAU,4BAA6B,CACnD,YAAa,KAAK,cAAc,aAAe,GAC/C,QAAS,KAAK,cAAc,SAAW,EACvC,UAAW,KAAK,cAAc,SAChC,CAAC,EACD,MACF,IAAK,SACH,KAAK,SAAS,UAAU,yBAA0B,CAChD,YAAa,KAAK,cAAc,aAAe,GAC/C,MAAO,IAAI,MAAMD,GAAS,0BAAM,EAChC,QAAS,KAAK,cAAc,SAAW,EACvC,UAAW,KAAK,cAAc,SAChC,CAAC,EACD,KACJ,CACF,OAASA,EAAO,CACd,KAAK,OAAO,MAAM,oDAAaA,CAAK,EACpC,KAAK,SAAS,UAAU,eAAgB,CACtC,MAAOA,aAAiB,MAAQA,EAAQ,IAAI,MAAM,OAAOA,CAAK,CAAC,EAC/D,UAAW,qBACb,CAAC,CACH,CACF,CAKA,eAIE,CACA,MAAO,CACL,OAAQ,KAAK,gBAAgB,EAC7B,QAAS,KAAK,iBAAiB,EAC/B,UAAW,KAAK,IAAI,CACtB,CACF,CAKQ,uBAA8B,CAEhC,KAAK,kBACP,aAAa,KAAK,gBAAgB,EAIpC,KAAK,iBAAmB,WAAW,IAAM,CACvC,KAAK,OAAO,KAAK,4FAAiB,EAClC,KAAK,iBAAiB,CAAE,OAAQ,cAAe,EAAG,mBAAmB,CACvE,EAAG,KAAK,iBAAiB,CAC3B,CAKA,uBAA8B,CACxB,KAAK,mBACP,aAAa,KAAK,gBAAgB,EAClC,KAAK,iBAAmB,OAE5B,CAKA,mBAA6B,CAC3B,OAAO,KAAK,WAAW,SAAW,WACpC,CAKA,kBAAuC,CACrC,OAAO,KAAK,WAAW,aACzB,CAKA,qBAAgC,CAC9B,MAAO,CAAC,GAAG,KAAK,WAAW,gBAAgB,CAC7C,CAKA,oBAAoBE,EAAyB,CAC3C,KAAK,iBACH,CAAE,iBAAkB,CAAC,GAAGA,CAAO,CAAE,EACjC,oBACF,CACF,CAKA,eAAeC,EAAwB,CACrC,KAAK,iBAAiB,CAAE,YAAaA,CAAS,EAAG,qBAAqB,CACxE,CAKA,OAAc,CACZ,KAAK,OAAO,KAAK,sCAAQ,EACzB,KAAK,sBAAsB,EAC3B,KAAK,WAAa,CAChB,OAAQ,eACR,YAAa,GACb,iBAAkB,CAAC,CACrB,EACA,KAAK,cAAgB,MACvB,CAKA,SAAgB,CACd,KAAK,OAAO,KAAK,sCAAQ,EACzB,KAAK,sBAAsB,EAC3B,KAAK,MAAM,CACb,CACF,ICvPA,IA8BaC,GA9BbC,GAAAC,EAAA,kBACAC,IAEAC,IAEAC,IAyBaL,GAAN,KAA0B,CA9BjC,MA8BiC,CAAAM,EAAA,4BACvB,OACA,SACA,QAAwC,IAAI,IAC5C,aAAmD,IAAI,IACvD,aAAe,IAEvB,aAAc,CACZ,KAAK,OAASC,EACd,KAAK,SAAWC,EAAY,EAC5B,KAAK,oBAAoB,CAC3B,CAKQ,qBAA4B,CAElC,KAAK,SAAS,QAAQ,iBAAmBC,GAAS,CAEhD,IAAMC,EAASC,EAAc,UAAU,EACvC,KAAK,sBAAsBD,CAAM,CACnC,CAAC,EAGD,KAAK,SAAS,QAAQ,iBAAmBD,GAAS,CAChD,KAAK,sBAAsBA,EAAK,MAAM,CACxC,CAAC,EAGD,KAAK,SAAS,QAAQ,0BAA4BA,GAAS,CACzD,KAAK,uBAAuB,aAAc,OAAWA,EAAK,SAAS,CACrE,CAAC,EAED,KAAK,SAAS,QAAQ,4BAA8BA,GAAS,CAC3D,KAAK,uBAAuB,YAAa,OAAWA,EAAK,SAAS,CACpE,CAAC,EAED,KAAK,SAAS,QAAQ,yBAA2BA,GAAS,CACxD,KAAK,uBAAuB,SAAUA,EAAK,MAAM,QAASA,EAAK,SAAS,CAC1E,CAAC,EAGD,KAAK,SAAS,QAAQ,sBAAwBA,GAAS,CACrD,KAAK,UAAU,sBAAuBA,CAAI,CAC5C,CAAC,EAED,KAAK,SAAS,QAAQ,kBAAoBA,GAAS,CACjD,KAAK,UAAU,kBAAmBA,CAAI,CACxC,CAAC,EAED,KAAK,SAAS,QAAQ,wBAA0BA,GAAS,CACvD,KAAK,UAAU,wBAAyBA,CAAI,CAC9C,CAAC,EAED,KAAK,SAAS,QAAQ,qBAAuBA,GAAS,CACpD,KAAK,UAAU,qBAAsBA,CAAI,CAC3C,CAAC,EAGD,KAAK,SAAS,QAAQ,yBAA2BA,GAAS,CACpDA,EAAK,OACP,KAAK,aAAaA,EAAK,OAAQA,EAAK,KAAMA,EAAK,IAAI,EAEnD,KAAK,UAAUA,EAAK,KAAMA,EAAK,IAAI,CAEvC,CAAC,CACH,CAKA,eAAeG,EAAkBC,EAAe,CAC9C,GAAI,CACF,IAAMC,EAA0B,CAC9B,GAAIF,EACJ,GAAAC,EACA,WAAYA,EAAG,WACf,KAAMP,EAACG,GAAiB,CAClBI,EAAG,aAAe,GAEpBA,EAAG,KAAKJ,CAAI,CAEhB,EALM,OAMR,EAEA,KAAK,QAAQ,IAAIG,EAAUE,CAAM,EACjC,KAAK,OAAO,KAAK,mDAAqBF,CAAQ,EAAE,EAChD,KAAK,OAAO,MAAM,+CAAY,KAAK,QAAQ,IAAI,EAAE,EAGjD,KAAK,mBAAmBA,CAAQ,EAGhC,KAAK,SAAS,UAAU,6BAA8B,CACpD,SAAAA,EACA,UAAW,KAAK,IAAI,CACtB,CAAC,CACH,OAASG,EAAO,CACd,KAAK,OAAO,MAAM,+CAAYH,CAAQ,GAAIG,CAAK,EAC/C,KAAK,SAAS,UAAU,qBAAsB,CAC5C,MAAOA,aAAiB,MAAQA,EAAQ,IAAI,MAAM,OAAOA,CAAK,CAAC,EAC/D,KAAM,iBACR,CAAC,CACH,CACF,CAKA,iBAAiBH,EAAwB,CACvC,GAAI,CACE,KAAK,QAAQ,IAAIA,CAAQ,IAC3B,KAAK,QAAQ,OAAOA,CAAQ,EAC5B,KAAK,aAAa,OAAOA,CAAQ,EACjC,KAAK,OAAO,KAAK,mDAAqBA,CAAQ,EAAE,EAChD,KAAK,OAAO,MAAM,+CAAY,KAAK,QAAQ,IAAI,EAAE,EAGjD,KAAK,SAAS,UAAU,gCAAiC,CACvD,SAAAA,EACA,UAAW,KAAK,IAAI,CACtB,CAAC,EAEL,OAASG,EAAO,CACd,KAAK,OAAO,MAAM,+CAAYH,CAAQ,GAAIG,CAAK,CACjD,CACF,CAKA,UAAUC,EAAcP,EAAkB,CACxC,IAAMQ,EAA+B,CACnC,KAAAD,EACA,KAAAP,EACA,UAAW,KAAK,IAAI,CACtB,EAEA,KAAK,OAAO,MAAM,6BAASO,CAAI,GAAI,CAAE,YAAa,KAAK,QAAQ,IAAK,CAAC,EAErE,OAAW,CAACJ,EAAUE,CAAM,IAAK,KAAK,QACpC,KAAK,oBAAoBA,EAAQG,EAASL,CAAQ,CAEtD,CAKA,aAAaA,EAAkBI,EAAcP,EAAkB,CAC7D,IAAMQ,EAA+B,CACnC,KAAAD,EACA,KAAAP,EACA,UAAW,KAAK,IAAI,CACtB,EAEMK,EAAS,KAAK,QAAQ,IAAIF,CAAQ,EACpCE,EACF,KAAK,oBAAoBA,EAAQG,EAASL,CAAQ,EAGlD,KAAK,aAAaA,EAAUK,CAAO,CAEvC,CAKQ,oBACNH,EACAG,EACAL,EACM,CACN,GAAI,CACF,GAAIE,EAAO,GAAG,aAAe,EAAG,CAE9B,IAAMI,EAAa,KAAK,UAAUD,CAAO,EACzCH,EAAO,KAAKI,CAAU,EACtB,KAAK,OAAO,MAAM,0DAAaN,CAAQ,KAAKK,EAAQ,IAAI,EAAE,CAC5D,MAEE,KAAK,aAAaL,EAAUK,CAAO,EACnC,KAAK,OAAO,KAAK,sBAAOL,CAAQ,iFAAgB,CAEpD,OAASG,EAAO,CACd,KAAK,OAAO,MAAM,oDAAYH,CAAQ,iBAAQG,CAAK,EACnD,KAAK,aAAaH,EAAUK,CAAO,EACnC,KAAK,SAAS,UAAU,qBAAsB,CAC5C,MAAOF,aAAiB,MAAQA,EAAQ,IAAI,MAAM,OAAOA,CAAK,CAAC,EAC/D,KAAM,cACR,CAAC,CACH,CACF,CAKQ,aAAaH,EAAkBK,EAAoC,CACpE,KAAK,aAAa,IAAIL,CAAQ,GACjC,KAAK,aAAa,IAAIA,EAAU,CAAC,CAAC,EAGpC,IAAMO,EAAQ,KAAK,aAAa,IAAIP,CAAQ,EAC5CO,EAAM,KAAKF,CAAO,EAGdE,EAAM,OAAS,KAAK,eACtBA,EAAM,MAAM,EACZ,KAAK,OAAO,KAAK,sBAAOP,CAAQ,iFAAgB,EAEpD,CAKQ,mBAAmBA,EAAwB,CACjD,IAAMO,EAAQ,KAAK,aAAa,IAAIP,CAAQ,EAC5C,GAAI,CAACO,GAASA,EAAM,SAAW,EAC7B,OAGF,IAAML,EAAS,KAAK,QAAQ,IAAIF,CAAQ,EACxC,GAAKE,EAIL,MAAK,OAAO,KAAK,gBAAMK,EAAM,MAAM,2DAAcP,CAAQ,EAAE,EAE3D,QAAWK,KAAWE,EACpB,KAAK,oBAAoBL,EAAQG,EAASL,CAAQ,EAIpD,KAAK,aAAa,OAAOA,CAAQ,EACnC,CAKA,sBAAsBF,EAAyB,CAC7C,KAAK,UAAU,eAAgBA,CAAM,CACvC,CAKA,sBAAsBU,EAA0B,CAC9C,KAAK,UAAU,eAAgBA,CAAM,CACvC,CAKA,uBACEA,EACAL,EACAM,EACM,CACN,IAAMC,EAA+B,CACnC,OAAAF,EACA,MAAAL,EACA,UAAWM,GAAa,KAAK,IAAI,CACnC,EAEA,KAAK,UAAU,gBAAiBC,CAAa,CAC/C,CAKA,gBAIE,CACA,IAAMC,EAAmB,MAAM,KAAK,KAAK,QAAQ,OAAO,CAAC,EAAE,OACxDT,GAAWA,EAAO,GAAG,aAAe,CACvC,EAAE,OAEIU,EAAiB,MAAM,KAAK,KAAK,aAAa,OAAO,CAAC,EAAE,OAC5D,CAACC,EAAON,IAAUM,EAAQN,EAAM,OAChC,CACF,EAEA,MAAO,CACL,aAAc,KAAK,QAAQ,KAC3B,iBAAAI,EACA,eAAAC,CACF,CACF,CAKA,4BAAmC,CACjC,IAAME,EAAgC,CAAC,EAEvC,OAAW,CAACd,EAAUE,CAAM,IAAK,KAAK,QAChCA,EAAO,GAAG,aAAe,GAE3BY,EAAoB,KAAKd,CAAQ,EAIrC,QAAWA,KAAYc,EACrB,KAAK,iBAAiBd,CAAQ,EAG5Bc,EAAoB,OAAS,GAC/B,KAAK,OAAO,KAAK,sBAAOA,EAAoB,MAAM,6CAAU,CAEhE,CAKA,SAAgB,CACd,KAAK,OAAO,KAAK,sCAAQ,EACzB,KAAK,QAAQ,MAAM,EACnB,KAAK,aAAa,MAAM,CAC1B,CACF,IC/VA,IAAAC,GAAAC,EAAA,kBACAC,MCDA,IAAAC,GAAAC,EAAA,kBAAAC,KACAC,KACAC,IAGAC,KAGAC,OCRA,IAeaC,GAfbC,GAAAC,EAAA,kBAMAC,KASaH,GAAN,KAAmB,CAf1B,MAe0B,CAAAI,EAAA,qBAChB,OAAmC,IAAI,IAK/C,cAAcC,EAAcC,EAA2B,CACjD,KAAK,OAAO,IAAID,CAAI,EAGxB,KAAK,OAAO,IAAIA,EAAMC,CAAM,CAE9B,CAKA,eAAeC,EAAiD,CAG9D,OAAW,CAACF,EAAMC,CAAM,IAAK,OAAO,QAAQC,CAAY,EACtD,KAAK,cAAcF,EAAMC,CAAM,CAInC,CAKA,cAAyC,CACvC,OAAO,IAAI,IAAI,KAAK,MAAM,CAC5B,CAKA,SAASD,EAAuC,CAC9C,OAAO,KAAK,OAAO,IAAIA,CAAI,CAC7B,CAKA,WAAWG,EAA6B,CAMtC,IAAMC,EAAe,MAAM,KAAK,KAAK,OAAO,QAAQ,CAAC,EACrDA,EAAa,KAAK,CAAC,CAACC,CAAK,EAAG,CAACC,CAAK,IAE5BD,IAAU,SAAiB,EAC3BC,IAAU,SAAiB,GACxB,CACR,EAED,OAAW,CAACC,EAAYN,CAAM,IAAKG,EACjC,GAAI,CACF,KAAK,iBAAiBD,EAAKF,CAAM,CAEnC,MAAgB,CAEhB,CAIJ,CAKQ,iBAAiBE,EAAuBF,EAA2B,CAEzE,QAAWO,KAASP,EAAO,OAAQ,CACjC,IAAMQ,EAAWR,EAAO,KAAOO,EAAM,KAG/BE,EAAgB,CACpB,GAAIT,EAAO,YAAc,CAAC,EAC1B,GAAIO,EAAM,YAAc,CAAC,CAC3B,EAGMG,EAAiBZ,EAAA,MAAOa,EAAwBC,IAAe,CACnE,GAAI,CAIF,OAHe,MAAML,EAAM,QAAQI,CAAC,CAItC,OAASE,EAAO,CAEd,IAAMC,EAAgBC,EACpB,gBACA,6CACAF,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CACvD,EACA,OAAOF,EAAE,KAAKG,EAAe,GAAG,CAClC,CACF,EAfuB,kBA0BjBE,EARiB,CACrB,IAAKd,EAAI,IAAI,KAAKA,CAAG,EACrB,KAAMA,EAAI,KAAK,KAAKA,CAAG,EACvB,IAAKA,EAAI,IAAI,KAAKA,CAAG,EACrB,OAAQA,EAAI,OAAO,KAAKA,CAAG,EAC3B,MAAOA,EAAI,MAAM,KAAKA,CAAG,CAC3B,EAGiBK,EAAM,MAAqC,EAC5D,GAAI,CAACS,EACH,MAAM,IAAI,MAAM,+CAAiBT,EAAM,MAAM,EAAE,EAG7CE,EAAc,OAAS,EACzBO,EAAQR,EAAU,GAAGC,EAAeC,CAAc,EAElDM,EAAQR,EAAUE,CAAc,CAEpC,CACF,CAKA,OAAc,CACZ,KAAK,OAAO,MAAM,CAEpB,CAKA,SAASX,EAAuB,CAC9B,OAAO,KAAK,OAAO,IAAIA,CAAI,CAC7B,CAKA,eAA0B,CACxB,OAAO,MAAM,KAAK,KAAK,OAAO,KAAK,CAAC,CACtC,CACF,ICjKA,IAcakB,GAdbC,GAAAC,EAAA,kBAcaF,GAA4B,CACvC,KAAM,SACN,KAAM,cACN,YAAa,2CACb,OAAQ,CACN,CACE,OAAQ,MACR,KAAM,GACN,QAASG,EAACC,GAA2B,CACnC,IAAMC,EAAeD,EAAE,IAAI,cAAc,EACnC,CAAE,iBAAAE,CAAiB,EAAID,EAC7B,OAAOC,EAAiB,UAAUF,CAAC,CACrC,EAJS,UAKX,EACA,CACE,OAAQ,MACR,KAAM,GACN,QAASD,EAACC,GAA2B,CACnC,IAAMC,EAAeD,EAAE,IAAI,cAAc,EACnC,CAAE,iBAAAE,CAAiB,EAAID,EAC7B,OAAOC,EAAiB,aAAaF,CAAC,CACxC,EAJS,UAKX,EACA,CACE,OAAQ,MACR,KAAM,gBACN,QAASD,EAACC,GAA2B,CACnC,IAAMC,EAAeD,EAAE,IAAI,cAAc,EACnC,CAAE,iBAAAE,CAAiB,EAAID,EAC7B,OAAOC,EAAiB,eAAeF,CAAC,CAC1C,EAJS,UAKX,EACA,CACE,OAAQ,MACR,KAAM,iBACN,QAASD,EAACC,GAA2B,CACnC,IAAMC,EAAeD,EAAE,IAAI,cAAc,EACnC,CAAE,iBAAAE,CAAiB,EAAID,EAC7B,OAAOC,EAAiB,gBAAgBF,CAAC,CAC3C,EAJS,UAKX,EACA,CACE,OAAQ,MACR,KAAM,eACN,QAASD,EAACC,GAA2B,CACnC,IAAMC,EAAeD,EAAE,IAAI,cAAc,EACnC,CAAE,iBAAAE,CAAiB,EAAID,EAC7B,OAAOC,EAAiB,cAAcF,CAAC,CACzC,EAJS,UAKX,EACA,CACE,OAAQ,MACR,KAAM,cACN,QAASD,EAACC,GAA2B,CACnC,IAAMC,EAAeD,EAAE,IAAI,cAAc,EACnC,CAAE,iBAAAE,CAAiB,EAAID,EAC7B,OAAOC,EAAiB,oBAAoBF,CAAC,CAC/C,EAJS,UAKX,EACA,CACE,OAAQ,OACR,KAAM,UACN,QAASD,EAACC,GAA2B,CACnC,IAAMC,EAAeD,EAAE,IAAI,cAAc,EACnC,CAAE,iBAAAE,CAAiB,EAAID,EAC7B,OAAOC,EAAiB,aAAaF,CAAC,CACxC,EAJS,UAKX,EACA,CACE,OAAQ,MACR,KAAM,QACN,QAASD,EAACC,GAA2B,CACnC,IAAMC,EAAeD,EAAE,IAAI,cAAc,EACnC,CAAE,iBAAAE,CAAiB,EAAID,EAC7B,OAAOC,EAAiB,cAAcF,CAAC,CACzC,EAJS,UAKX,EACA,CACE,OAAQ,MACR,KAAM,UACN,QAASD,EAACC,GAA2B,CACnC,IAAMC,EAAeD,EAAE,IAAI,cAAc,EACnC,CAAE,iBAAAE,CAAiB,EAAID,EAC7B,OAAOC,EAAiB,kBAAkBF,CAAC,CAC7C,EAJS,UAKX,CACF,CACF,ICrGA,IAaaG,GAbbC,GAAAC,EAAA,kBAaaF,GAA4B,CACvC,KAAM,SACN,KAAM,cACN,YAAa,2CACb,OAAQ,CACN,CACE,OAAQ,MACR,KAAM,GACN,QAASG,EAACC,GAAe,CACvB,GAAM,CAAE,iBAAAC,CAAiB,EAAID,EAAE,IAC7B,cACF,EACA,OAAOC,EAAiB,UAAUD,CAAC,CACrC,EALS,UAMX,EACA,CACE,OAAQ,MACR,KAAM,UACN,QAASD,EAACC,GAAe,CACvB,GAAM,CAAE,iBAAAC,CAAiB,EAAID,EAAE,IAC7B,cACF,EACA,OAAOC,EAAiB,gBAAgBD,CAAC,CAC3C,EALS,UAMX,EACA,CACE,OAAQ,MACR,KAAM,UACN,QAASD,EAACC,GAAe,CACvB,GAAM,CAAE,iBAAAC,CAAiB,EAAID,EAAE,IAC7B,cACF,EACA,OAAOC,EAAiB,mBAAmBD,CAAC,CAC9C,EALS,UAMX,EACA,CACE,OAAQ,OACR,KAAM,SACN,QAASD,EAACC,GAAe,CACvB,GAAM,CAAE,iBAAAC,CAAiB,EAAID,EAAE,IAC7B,cACF,EACA,OAAOC,EAAiB,YAAYD,CAAC,CACvC,EALS,UAMX,EACA,CACE,OAAQ,MACR,KAAM,eACN,QAASD,EAACC,GAAe,CACvB,GAAM,CAAE,iBAAAC,CAAiB,EAAID,EAAE,IAC7B,cACF,EACA,OAAOC,EAAiB,oBAAoBD,CAAC,CAC/C,EALS,UAMX,EACA,CACE,OAAQ,MACR,KAAM,eACN,QAASD,EAACC,GAAe,CACvB,GAAM,CAAE,iBAAAC,CAAiB,EAAID,EAAE,IAC7B,cACF,EACA,OAAOC,EAAiB,oBAAoBD,CAAC,CAC/C,EALS,UAMX,CACF,CACF,IC/EA,IAaaE,GAbbC,GAAAC,EAAA,kBAaaF,GAA2B,CACtC,KAAM,QACN,KAAM,aACN,YAAa,2CACb,OAAQ,CACN,CACE,OAAQ,OACR,KAAM,QACN,QAASG,EAACC,GAAe,CACvB,GAAM,CAAE,eAAAC,CAAe,EAAID,EAAE,IAAI,cAAc,EAC/C,OAAOC,EAAe,SAASD,CAAC,CAClC,EAHS,UAIX,EACA,CACE,OAAQ,MACR,KAAM,QACN,QAASD,EAACC,GAAe,CACvB,GAAM,CAAE,eAAAC,CAAe,EAAID,EAAE,IAAI,cAAc,EAC/C,OAAOC,EAAe,UAAUD,CAAC,CACnC,EAHS,UAIX,EACA,CACE,OAAQ,MACR,KAAM,UACN,QAASD,EAACC,GAAe,CACvB,GAAM,CAAE,eAAAC,CAAe,EAAID,EAAE,IAAI,cAAc,EAC/C,OAAOC,EAAe,eAAeD,CAAC,CACxC,EAHS,UAIX,EACA,CACE,OAAQ,OACR,KAAM,UACN,QAASD,EAACC,GAAe,CACvB,GAAM,CAAE,eAAAC,CAAe,EAAID,EAAE,IAAI,cAAc,EAC/C,OAAOC,EAAe,cAAcD,CAAC,CACvC,EAHS,UAIX,EACA,CACE,OAAQ,MACR,KAAM,oBACN,QAASD,EAACC,GAAe,CACvB,GAAM,CAAE,eAAAC,CAAe,EAAID,EAAE,IAAI,cAAc,EAC/C,OAAOC,EAAe,iBAAiBD,CAAC,CAC1C,EAHS,UAIX,EACA,CACE,OAAQ,SACR,KAAM,oBACN,QAASD,EAACC,GAAe,CACvB,GAAM,CAAE,eAAAC,CAAe,EAAID,EAAE,IAAI,cAAc,EAC/C,OAAOC,EAAe,iBAAiBD,CAAC,CAC1C,EAHS,UAIX,CACF,CACF,ICnEA,IAaaE,GAbbC,GAAAC,EAAA,kBAaaF,GAAyB,CACpC,KAAM,MACN,KAAM,OACN,YAAa,mCACb,OAAQ,CACN,CACE,OAAQ,OACR,KAAM,GACN,QAASG,EAACC,GAAe,CACvB,GAAM,CAAE,gBAAAC,CAAgB,EAAID,EAAE,IAC5B,cACF,EACA,OAAOC,EAAgB,WAAWD,CAAC,CACrC,EALS,UAMX,EACA,CACE,OAAQ,MACR,KAAM,GACN,QAASD,EAACC,GAAe,CACvB,GAAM,CAAE,gBAAAC,CAAgB,EAAID,EAAE,IAC5B,cACF,EACA,OAAOC,EAAgB,UAAUD,CAAC,CACpC,EALS,UAMX,CACF,CACF,ICvCA,IAaaE,GAbbC,GAAAC,EAAA,kBAaaF,GAA6B,CACxC,KAAM,UACN,KAAM,eACN,YAAa,2CACb,OAAQ,CACN,CACE,OAAQ,MACR,KAAM,GACN,QAASG,EAACC,GAAe,CACvB,GAAM,CAAE,kBAAAC,CAAkB,EAAID,EAAE,IAC9B,cACF,EACA,OAAOC,EAAkB,WAAWD,CAAC,CACvC,EALS,UAMX,EACA,CACE,OAAQ,MACR,KAAM,UACN,QAASD,EAACC,GAAe,CACvB,GAAM,CAAE,kBAAAC,CAAkB,EAAID,EAAE,IAC9B,cACF,EACA,OAAOC,EAAkB,iBAAiBD,CAAC,CAC7C,EALS,UAMX,EACA,CACE,OAAQ,SACR,KAAM,SACN,QAASD,EAACC,GAAe,CACvB,GAAM,CAAE,kBAAAC,CAAkB,EAAID,EAAE,IAC9B,cACF,EACA,OAAOC,EAAkB,kBAAkBD,CAAC,CAC9C,EALS,UAMX,EACA,CACE,OAAQ,MACR,KAAM,UACN,QAASD,EAACC,GAAe,CACvB,GAAM,CAAE,kBAAAC,CAAkB,EAAID,EAAE,IAC9B,cACF,EACA,OAAOC,EAAkB,mBAAmBD,CAAC,CAC/C,EALS,UAMX,CACF,CACF,IC3DA,IAQaE,GARbC,GAAAC,EAAA,kBAQaF,GAA8B,CACzC,KAAM,WACN,KAAM,gBACN,YAAa,2CACb,OAAQ,CACN,CACE,OAAQ,OACR,KAAM,WACN,QAASG,EAACC,GAAe,CACvB,GAAM,CAAE,kBAAAC,CAAkB,EAAID,EAAE,IAC9B,cACF,EACA,OAAOC,EAAkB,eAAeD,CAAC,CAC3C,EALS,UAMX,EACA,CACE,OAAQ,OACR,KAAM,QACN,QAASD,EAACC,GAAe,CACvB,GAAM,CAAE,kBAAAC,CAAkB,EAAID,EAAE,IAC9B,cACF,EACA,OAAOC,EAAkB,YAAYD,CAAC,CACxC,EALS,UAMX,EACA,CACE,OAAQ,OACR,KAAM,SACN,QAASD,EAACC,GAAe,CACvB,GAAM,CAAE,kBAAAC,CAAkB,EAAID,EAAE,IAC9B,cACF,EACA,OAAOC,EAAkB,aAAaD,CAAC,CACzC,EALS,UAMX,EACA,CACE,OAAQ,MACR,KAAM,UACN,QAASD,EAACC,GAAe,CACvB,GAAM,CAAE,kBAAAC,CAAkB,EAAID,EAAE,IAC9B,cACF,EACA,OAAOC,EAAkB,iBAAiBD,CAAC,CAC7C,EALS,UAMX,EACA,CACE,OAAQ,MACR,KAAM,UACN,QAASD,EAACC,GAAe,CACvB,GAAM,CAAE,kBAAAC,CAAkB,EAAID,EAAE,IAC9B,cACF,EACA,OAAOC,EAAkB,iBAAiBD,CAAC,CAC7C,EALS,UAMX,CACF,CACF,IChEA,IAQaE,GARbC,GAAAC,EAAA,kBAQaF,GAA4B,CACvC,KAAM,SACN,KAAM,OACN,YAAa,2CACb,OAAQ,CACN,CACE,OAAQ,OACR,KAAM,UACN,QAASG,EAACC,GAAe,CACvB,GAAM,CAAE,iBAAAC,CAAiB,EAAID,EAAE,IAC7B,cACF,EACA,OAAOC,EAAiB,cAAcD,CAAC,CACzC,EALS,UAMX,CACF,CACF,ICxBA,IAQaE,GARbC,GAAAC,EAAA,kBAQaF,GAA4B,CACvC,KAAM,SACN,KAAM,IACN,YAAa,mDACb,OAAQ,CACN,CACE,OAAQ,MACR,KAAM,IACN,QAASG,EAAA,MAAOC,GAEVA,EAAE,IAAI,KAAK,WAAW,OAAO,EACxBA,EAAE,SAAS,EAGb,MADcA,EAAE,IAAI,cAAc,EACf,kBAAkB,iBAAiBA,CAAC,EANvD,UAQX,CACF,CACF,IC1BA,IAQaC,GARbC,GAAAC,EAAA,kBAQaF,GAA0B,CACrC,KAAM,OACN,KAAM,YACN,YAAa,4CACb,OAAQ,CACN,CACE,OAAQ,MACR,KAAM,cACN,QAASG,EAACC,GAAe,CACvB,GAAM,CAAE,eAAAC,CAAe,EAAID,EAAE,IAAI,cAAc,EAC/C,OAAOC,EAAe,cAAcD,CAAC,CACvC,EAHS,UAIX,EACA,CACE,OAAQ,MACR,KAAM,aACN,QAASD,EAACC,GAAe,CACvB,GAAM,CAAE,eAAAC,CAAe,EAAID,EAAE,IAAI,cAAc,EAC/C,OAAOC,EAAe,aAAaD,CAAC,CACtC,EAHS,UAIX,EACA,CACE,OAAQ,OACR,KAAM,eACN,QAASD,EAACC,GAAe,CACvB,GAAM,CAAE,eAAAC,CAAe,EAAID,EAAE,IAAI,cAAc,EAC/C,OAAOC,EAAe,WAAWD,CAAC,CACpC,EAHS,UAIX,EACA,CACE,OAAQ,MACR,KAAM,eACN,QAASD,EAACC,GAAe,CACvB,GAAM,CAAE,eAAAC,CAAe,EAAID,EAAE,IAAI,cAAc,EAC/C,OAAOC,EAAe,cAAcD,CAAC,CACvC,EAHS,UAIX,CACF,CACF,IC9CA,IAQaE,GARbC,GAAAC,EAAA,kBAQaF,GAA8B,CACzC,KAAM,YACN,KAAM,kBACN,YAAa,uDACb,OAAQ,CACN,CACE,OAAQ,MACR,KAAM,QACN,QAASG,EAACC,GAAe,CACvB,GAAM,CAAE,sBAAAC,CAAsB,EAAID,EAAE,IAClC,cACF,EACA,OAAOC,EAAsB,gBAAgBD,CAAC,CAChD,EALS,UAMX,CACF,CACF,ICxBA,IAYME,GAgBOC,GA5BbC,GAAAC,EAAA,kBAYMH,GAAuBI,EAAA,MAC3BC,EACAC,IAGsB,CAEtB,IAAMC,EADeF,EAAE,IAAI,cAAc,EACZ,oBAE7B,OAAKE,EAIE,MAAMD,EAAUC,CAAO,EAHrBF,EAAE,KAAK,CAAE,MAAO,wCAAyC,EAAG,GAAG,CAI1E,EAd6B,wBAgBhBJ,GAA+B,CAC1C,KAAM,YACN,KAAM,mBACN,YAAa,qDACb,OAAQ,CACN,CACE,OAAQ,OACR,KAAM,GACN,QAASG,EAACC,GACRL,GAAqBK,EAAIG,GAAMA,EAAE,aAAaH,CAAC,CAAC,EADzC,UAEX,EACA,CACE,OAAQ,SACR,KAAM,eACN,QAASD,EAACC,GACRL,GAAqBK,EAAIG,GAAMA,EAAE,gBAAgBH,CAAC,CAAC,EAD5C,UAEX,EACA,CACE,OAAQ,MACR,KAAM,sBACN,QAASD,EAACC,GACRL,GAAqBK,EAAIG,GAAMA,EAAE,mBAAmBH,CAAC,CAAC,EAD/C,UAEX,EACA,CACE,OAAQ,MACR,KAAM,GACN,QAASD,EAACC,GACRL,GAAqBK,EAAIG,GAAMA,EAAE,eAAeH,CAAC,CAAC,EAD3C,UAEX,CACF,CACF,IC1DA,IAuBMI,GAaAC,GAiCOC,GArEbC,GAAAC,EAAA,kBAuBMJ,GAAsBK,EAAA,CAACC,EAAcC,KAClC,CACL,MAAO,CACL,KAAAD,EACA,QAAAC,CACF,CACF,GAN0B,uBAatBN,GAAsBI,EAAA,MAC1BG,EACAC,IACsB,CAEtB,IAAMC,EAAkBF,EAAE,IAAI,iBAAiB,EAE/C,GAAI,CAACE,EAAiB,CACpB,IAAMC,EAAgBX,GACpB,iCACA,kGACF,EACA,OAAOQ,EAAE,KAAKG,EAAe,GAAG,CAClC,CAGA,GAAI,CAEF,OAAO,MAAMD,EAAgBD,CAAW,EAAED,CAAC,CAC7C,OAASI,EAAO,CAEd,IAAMD,EAAgBX,GACpB,yBACAY,aAAiB,MAAQA,EAAM,QAAU,sCAC3C,EACA,OAAOJ,EAAE,KAAKG,EAAe,GAAG,CAClC,CACF,EA3B4B,uBAiCfT,GAA8B,CACzC,KAAM,WACN,KAAM,gBACN,YAAa,2CACb,OAAQ,CACN,CACE,OAAQ,OACR,KAAM,UACN,QAASG,EAACG,GACRP,GAAoBO,EAAG,mBAAmB,EADnC,UAEX,EACA,CACE,OAAQ,OACR,KAAM,WACN,QAASH,EAACG,GACRP,GAAoBO,EAAG,iBAAiB,EADjC,UAEX,EACA,CACE,OAAQ,OACR,KAAM,cACN,QAASH,EAACG,GACRP,GAAoBO,EAAG,oBAAoB,EADpC,UAEX,EACA,CACE,OAAQ,OACR,KAAM,OACN,QAASH,EAACG,GACRP,GAAoBO,EAAG,aAAa,EAD7B,UAEX,EACA,CACE,OAAQ,OACR,KAAM,UACN,QAASH,EAACG,GACRP,GAAoBO,EAAG,gBAAgB,EADhC,UAEX,CACF,CACF,ICzGA,IAQaK,GARbC,GAAAC,EAAA,kBAQaF,GAA0B,CACrC,KAAM,OACN,KAAM,OACN,YAAa,gCACb,OAAQ,CACN,CACE,OAAQ,OACR,KAAM,WACN,QAASG,EAACC,GAAe,CACvB,GAAM,CAAE,kBAAAC,CAAkB,EAAID,EAAE,IAC9B,cACF,EACA,OAAOC,EAAkB,eAAeD,CAAC,CAC3C,EALS,UAOX,CACF,CACF,ICzBA,IAAAE,GAAAC,EAAA,kBAOAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,OCnBA,IAAAC,GAAAC,EAAA,kBAWAC,KAGAC,OCdA,IAAAC,GAAA,GAAAC,GAAAD,GAAA,eAAAE,KAAA,OAAS,gBAAAC,OAAoB,OA6B7B,OAAS,SAAAC,OAAa,oBAuBtB,OAAS,mBAAAC,OAAuB,KApDhC,IAkGaH,GAlGbI,GAAAC,EAAA,kBAEAC,KACAC,IAGAC,KAKAC,KACAC,KACAC,KAiBAC,KAWAC,IAEAH,KAEAI,KASAC,KAEAC,KA0CahB,GAAN,KAAgB,CAlGvB,MAkGuB,CAAAiB,EAAA,kBACb,IACA,WAAgC,KAChC,IAA8B,KAC9B,OACA,KAGA,SAGA,cACA,oBAGA,iBACA,iBACA,kBACA,eACA,sBACA,kBACA,kBACA,gBACA,oBACA,iBACA,eAGA,4BACA,iBAGA,yBAGA,aAGA,mBACA,gBAA0C,KAC1C,kBAA8C,KAEtD,YAAYC,EAAe,CAEzB,GAAI,CACF,KAAK,KAAOA,GAAQC,EAAc,aAAa,GAAK,IACtD,MAAgB,CAEd,KAAK,KAAOD,GAAQ,IACtB,CACA,KAAK,OAASE,EAGd,KAAK,SAAWC,EAAY,EAG5B,KAAK,cAAgB,IAAIC,GACzB,KAAK,oBAAsB,IAAIC,GAG/B,KAAK,iBAAmB,IAAIC,GAC5B,KAAK,iBAAmB,IAAIC,GAAiB,KAAK,aAAa,EAC/D,KAAK,kBAAoB,IAAIC,GAAkB,KAAK,aAAa,EACjE,KAAK,eAAiB,IAAIC,GAC1B,KAAK,sBAAwB,IAAIC,GACjC,KAAK,kBAAoB,IAAIC,GAC7B,KAAK,kBAAoB,IAAIC,GAC7B,KAAK,gBAAkB,IAAIC,GAC3B,KAAK,iBAAmB,IAAIC,GAC5B,KAAK,eAAiB,IAAIC,GAK1B,KAAK,4BAA8B,IAAIC,GACrC,KAAK,oBACL,KAAK,aACP,EACA,KAAK,iBAAmB,IAAIC,GAC1B,KAAK,cACL,KAAK,mBACP,EAGA,KAAK,IAAMC,GAAU,EACrB,KAAK,gBAAgB,EAGrB,KAAK,IAAI,SAASC,EAAyB,EAG3C,KAAK,4BAA4B,CACnC,CAKA,MAAc,uBAAuC,CACnD,GAAI,CACF,KAAK,OAAO,MAAM,+CAAY,EAGzB,KAAK,kBAMR,KAAK,OAAO,MAAM,6FAAiC,GALnD,KAAK,OAAO,MAAM,yDAA2B,EAC7C,KAAK,kBAAoB,IAAIC,GAE7B,MAAM,KAAK,kBAAkB,MAAM,GAMrC,IAAMC,EAAS,MAAM,KAAK,kBAAkB,EAG5C,KAAK,oBAAsB,IAAIC,GAC7B,KAAK,kBACLrB,CACF,EAGA,MAAM,KAAK,0BAA0BoB,EAAO,UAAU,EAGtD,IAAME,EAAW,KAAK,kBAAkB,YAAY,EACpD,KAAK,OAAO,MAAM,sBAAOA,EAAS,MAAM,qBAAM,EAG9C,IAAMC,EAAgBD,EAAS,IAAKE,IAAU,CAC5C,KAAMA,EAAK,KACX,YAAaA,EAAK,aAAe,GACjC,YAAaC,GAAqBD,EAAK,WAAW,CACpD,EAAE,EAGF,MAAM,KAAK,4BAA4BJ,EAAO,YAAaG,CAAK,EAEhE,KAAK,OAAO,MAAM,wDAAW,CAC/B,OAASG,EAAO,CACd,KAAK,OAAO,MAAM,8CAAYA,CAAK,EAE9B,KAAK,oBACR,KAAK,OAAO,KACV;AAAA;AAAA;AAAA;AAAA;AAAA,kGAMF,EACA,KAAK,kBAAoB,IAAIP,GAC7B,MAAM,KAAK,kBAAkB,MAAM,EACnC,KAAK,OAAO,KAAK,8GAAmC,EAExD,CACF,CAKA,MAAc,mBAIX,CACD,GAAI,CAACnB,EAAc,aAAa,EAC9B,MAAM,IAAI,MAAM,wHAAmC,EAKrDA,EAAc,gCAAgC,EAE9C,IAAMoB,EAASpB,EAAc,UAAU,EAEvC,MAAO,CACL,YAAaoB,EAAO,YACpB,WAAYA,EAAO,WACnB,UAAWA,EAAO,OAAO,MAAQ,IACnC,CACF,CAKA,MAAc,0BACZO,EACe,CACf,GAAI,CAAC,KAAK,kBACR,MAAM,IAAI,MAAM,4CAAwB,EAG1C,OAAW,CAACC,EAAMR,CAAM,IAAK,OAAO,QAAQO,CAAU,EAAG,CACvD,KAAK,OAAO,MAAM,8CAAgBC,CAAI,EAAE,EAExC,IAAMC,EAAgBC,GAAmBF,EAAMR,CAAM,EACrD,KAAK,kBAAkB,iBAAiBQ,EAAMC,CAAa,CAC7D,CAEA,MAAM,KAAK,kBAAkB,iBAAiB,CAChD,CAKA,MAAc,4BACZE,EACAR,EACe,CAGf,IAAMS,GADY,MAAM,QAAQD,CAAW,EAAIA,EAAc,CAACA,CAAW,GACxC,OAC9BE,GAAOA,GAAM,CAACA,EAAG,SAAS,qBAAM,CACnC,EAGA,KAAK,OAAO,MACV,iHAAuBD,EAAe,MAAM,EAC9C,EAEA,GAAI,CAEG,KAAK,kBACR,KAAK,gBAAkB,IAAIE,GAAgBlC,EAAe,CACxD,kBAAmB,GACrB,CAAC,EACD,KAAK,OAAO,MAAM,+DAAa,GAI7B,KAAK,mBACP,KAAK,gBAAgB,kBAAkB,KAAK,iBAAiB,EAG/D,KAAK,OAAO,MAAM,+DAAa,EAG3BgC,EAAe,OAAS,GAC1B,KAAK,OAAO,MAAM,wCAAWA,CAAc,EAG3C,MAAM,KAAK,gBAAgB,WAAWA,EAAgBT,CAAK,EAG3D,MAAM,KAAK,gBAAgB,QAAQ,EAGnC,KAAK,gBAAgB,GACnB,eACCY,GAAqC,CACpC,KAAK,OAAO,MAAM,qDAAaA,EAAM,IAAI,GAAIA,EAAM,IAAI,CACzD,CACF,EAEA,KAAK,OAAO,MACV,gHAAsBH,EAAe,MAAM,qBAC7C,IAGA,MAAM,KAAK,gBAAgB,WAAW,CAAC,EAAGT,CAAK,EAC/C,KAAK,OAAO,MAAM,0HAAsB,EAE5C,OAASG,EAAO,CACd,WAAK,OAAO,MAAM,8FAAoBA,CAAK,EAErCA,CACR,CACF,CAKO,4BAA4BU,EAAgC,CACjE,KAAK,gBAAkBA,CACzB,CAQO,oBAAsC,CAC3C,GAAI,CAAC,KAAK,gBACR,MAAM,IAAI,MACR,4KACF,EAEF,OAAO,KAAK,eACd,CAMO,qBAAqBA,EAAkC,CAExD,KAAK,mBAAqB,KAAK,oBAAsBA,GACvD,KAAK,OAAO,KACV,uIACF,EAKF,KAAK,kBAAoBA,EACzB,KAAK,OAAO,MAAM,kDAAyB,CAC7C,CAQO,sBAA0C,CAC/C,GAAI,CAAC,KAAK,kBACR,MAAM,IAAIC,GACR,oJACF,EAEF,OAAO,KAAK,iBACd,CAKA,6BAA+D,CAC7D,OAAI,KAAK,gBACA,CACL,KAAM,iBACN,QAAS,CACP,qBAAsB,KAAK,gBACxB,oBAAoB,EACpB,OAAQC,GAAWA,EAAO,SAAS,EAAE,OACxC,iBAAkB,KAAK,gBAAgB,oBAAoB,EAAE,OAC7D,iBAAkB,CAAC,CACrB,EACA,YAAa,KAAK,gBAAgB,oBAAoB,CACxD,EAGE,KAAK,mBACA,CACL,KAAM,kBACN,UAAW,GACX,SAAU,SACZ,EAGK,CACL,KAAM,OACN,UAAW,EACb,CACF,CAKA,MAAc,iBACZC,EACAC,EACAC,EAAc,EACdC,EAAe,IACfC,EAAW,IACXC,EAAoB,EACR,CACZ,IAAIC,EAA0B,KAE9B,QAASC,EAAU,EAAGA,GAAWL,EAAaK,IAC5C,GAAI,CACF,YAAK,OAAO,KAAK,GAAGN,CAAO,gCAAYM,CAAO,IAAIL,CAAW,GAAG,EACzD,MAAMF,EAAa,CAC5B,OAASb,EAAO,CAId,GAHAmB,EAAYnB,EACZ,KAAK,OAAO,KAAK,GAAGc,CAAO,+BAAYd,CAAK,EAExCoB,EAAUL,EAAa,CACzB,IAAMM,EAAQ,KAAK,IACjBL,EAAeE,IAAsBE,EAAU,GAC/CH,CACF,EACA,KAAK,OAAO,KAAK,GAAGH,CAAO,MAAMO,CAAK,0BAAW,EACjD,MAAM,KAAK,MAAMA,CAAK,CACxB,CACF,CAGF,MAAM,IAAI,MACR,GAAGP,CAAO,4FAAsBK,GAAW,OAAO,EACpD,CACF,CAKQ,MAAMG,EAA2B,CACvC,OAAO,IAAI,QAASC,GAAY,WAAWA,EAASD,CAAE,CAAC,CACzD,CAEQ,iBAAkB,CAExB,KAAK,KAAK,IAAI,IAAKE,EAAgB,EAInC,KAAK,KAAK,IAAI,IAAK,MAAOC,EAAGC,IAAS,CACpCD,EAAE,IACA,YACA,IACF,EACA,MAAMC,EAAK,CACb,CAAC,EAGD,KAAK,KAAK,IAAI,IAAKC,EAA2B,EAG9C,KAAK,KAAK,IAAI,IAAKC,GAA0B,CAAC,EAG9C,KAAK,KAAK,IAAI,IAAKC,GAAoB,CAAC,EAGxC,KAAK,KAAK,IAAI,IAAKC,EAAc,EAGjC,KAAK,KAAK,QAAQC,EAAsB,EAIxC,KAAK,KAAK,IAAI,IAAK,MAAON,EAAGC,IAAS,CACpC,IAAMM,EAAe,KAAK,0BAA0B,EACpDP,EAAE,IAAI,eAAgBO,CAAY,EAClC,MAAMN,EAAK,CACb,CAAC,CACH,CAMQ,2BAAiD,CACvD,MAAO,CACL,iBAAkB,KAAK,iBACvB,iBAAkB,KAAK,iBACvB,kBAAmB,KAAK,kBACxB,eAAgB,KAAK,eACrB,sBAAuB,KAAK,sBAC5B,kBAAmB,KAAK,kBACxB,kBAAmB,KAAK,kBACxB,gBAAiB,KAAK,gBACtB,oBAAqB,KAAK,oBAC1B,iBAAkB,KAAK,iBACvB,eAAgB,KAAK,cAEvB,CACF,CAKQ,kBAAyB,CAG/B,KAAK,aAAe,IAAIO,EAC1B,CAKQ,yBAAgC,CACtC,GAAI,CAAC,KAAK,cAAgB,CAAC,KAAK,IAC9B,MAAM,IAAI,MAAM,kDAAU,EAG5B,GAAI,CAEF,KAAK,aAAa,eAAe,CAC/B,OAAQC,GACR,OAAQC,GACR,MAAOC,GACP,IAAKC,GACL,QAASC,GACT,SAAUC,GACV,OAAQC,GACR,KAAMC,GACN,YAAaC,GACb,UAAWC,GACX,SAAUC,GACV,KAAMC,GACN,OAAQC,EACV,CAAC,EAGD,KAAK,aAAa,WAAW,KAAK,GAAG,EAErC,KAAK,OAAO,KAAK,kDAAU,CAC7B,OAAS9C,EAAO,CACd,KAAK,OAAO,MAAM,oDAAaA,CAAK,CACtC,CACF,CAEQ,gBAAiB,CAClB,KAAK,KAEV,KAAK,IAAI,GAAG,aAAe+C,GAAO,CAEhC,IAAMC,EAAW,UAAU,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAClD,SAAS,EAAE,EACX,OAAO,EAAG,CAAC,CAAC,GAEf,KAAK,OAAO,MAAM,mDAAqBA,CAAQ,EAAE,EACjD,KAAK,OAAO,MACV,8CAAqB,KAAK,KAAK,QAAQ,MAAQ,CAAC,EAClD,EAGA,KAAK,4BAA4B,oBAAoBD,EAAIC,CAAQ,EACjE,KAAK,iBAAiB,oBAAoBA,CAAQ,EAElDD,EAAG,GAAG,UAAW,MAAOE,GAAY,CAClC,GAAI,CACF,IAAMC,EAAO,KAAK,MAAMD,EAAQ,SAAS,CAAC,EAGtCC,EAAK,OAAS,eAChB,MAAM,KAAK,iBAAiB,mBAAmBH,EAAIG,EAAMF,CAAQ,EAEjE,MAAM,KAAK,4BAA4B,cACrCD,EACAG,EACAF,CACF,CAEJ,OAAShD,EAAO,CACd,KAAK,OAAO,MAAM,2BAA4BA,CAAK,EACnD,IAAMmD,EAAgB,CACpB,KAAM,QACN,MAAO,CACL,KAAM,sBACN,QAASnD,aAAiB,MAAQA,EAAM,QAAU,uCAClD,UAAW,KAAK,IAAI,CACtB,CACF,EACA+C,EAAG,KAAK,KAAK,UAAUI,CAAa,CAAC,CACvC,CACF,CAAC,EAEDJ,EAAG,GAAG,QAAS,IAAM,CACnB,KAAK,OAAO,MAAM,+DAAuBC,CAAQ,EAAE,EACnD,KAAK,OAAO,MACV,8CAAqB,KAAK,KAAK,QAAQ,MAAQ,CAAC,EAClD,EAGA,KAAK,4BAA4B,uBAAuBA,CAAQ,EAChE,KAAK,iBAAiB,uBAAuBA,CAAQ,CACvD,CAAC,EAEDD,EAAG,GAAG,QAAU/C,GAAU,CACxB,KAAK,OAAO,MAAM,uCAAmBgD,CAAQ,KAAMhD,CAAK,CAC1D,CAAC,EAGD,KAAK,4BAA4B,gBAAgB+C,EAAIC,CAAQ,CAC/D,CAAC,CACH,CAKQ,6BAAoC,CAC1C,KAAK,SAAS,QACZ,0BACCI,GAAyD,CAExD,IAAMH,EAAU,CACd,KAAM,0BACN,KAAM,CACJ,SAAUG,EAAU,SACpB,UAAWA,EAAU,UACrB,UAAWA,EAAU,UACrB,QAASA,EAAU,QACnB,QAASA,EAAU,QACnB,UAAWA,EAAU,SACvB,CACF,EAEA,KAAK,oBAAoB,UAAU,0BAA2BH,CAAO,EACrE,KAAK,OAAO,MACV,uEAAgBG,EAAU,QAAQ,MAAMA,EAAU,SAAS,EAC7D,CACF,CACF,CACF,CAEA,MAAa,OAAuB,CAElC,GAAI,KAAK,WAAY,CACnB,KAAK,OAAO,KAAK,+BAA+B,EAChD,MACF,CAIA,MAAM,KAAK,sBAAsB,EAGjC,KAAK,iBAAiB,EACtB,KAAK,wBAAwB,EAG7B,IAAMC,EAAShG,GAAM,CACnB,MAAO,KAAK,IAAI,MAChB,KAAM,KAAK,KACX,SAAU,UACV,aAAAD,EACF,CAAC,EAMD,GAHA,KAAK,WAAaiG,EAGd,CAAC,KAAK,WACR,MAAM,IAAI,MAAM,sCAAkB,EAEpC,KAAK,IAAM,IAAI/F,GAAgB,CAC7B,OAAQ,KAAK,UAIf,CAAC,EACD,KAAK,eAAe,EAGpB,KAAK,yBACH,KAAK,iBAAiB,yBAAyB,EAEjD,KAAK,OAAO,KAAK,0CAA0C,KAAK,IAAI,EAAE,EACtE,KAAK,OAAO,KAAK,kCAAkC,KAAK,IAAI,EAAE,CAChE,CAEO,MAAsB,CAC3B,OAAO,IAAI,QAASiE,GAAY,CAC9B,IAAI+B,EAAW,GAETC,EAAYnF,EAAA,IAAM,CACjBkF,IACHA,EAAW,GACX/B,EAAQ,EAEZ,EALkB,aAQlB,KAAK,oBAAoB,WAAW,GAGnC,SAAY,CACX,GAAI,CACE,KAAK,kBACP,MAAM,KAAK,gBAAgB,QAAQ,EACnC,KAAK,OAAO,MAAM,kDAAU,EAEhC,OAASvB,EAAO,CACd,KAAK,OAAO,MAAM,0DAAcA,CAAK,CACvC,CAEA,GAAI,CACE,KAAK,oBACP,MAAM,KAAK,kBAAkB,gBAAgB,EAC7C,KAAK,kBAAoB,KACzB,KAAK,OAAO,MAAM,sCAAuB,EAE7C,OAASA,EAAO,CACd,KAAK,OAAO,MAAM,8CAA2BA,CAAK,CACpD,CAWA,GARI,KAAK,2BACP,KAAK,iBAAiB,wBACpB,KAAK,wBACP,EACA,KAAK,yBAA2B,QAI9B,KAAK,IAAK,CACZ,QAAWwD,KAAU,KAAK,IAAI,QAC5BA,EAAO,UAAU,EAInB,KAAK,IAAI,MAAM,IAAM,CAEf,KAAK,WACP,KAAK,WAAW,MAAM,IAAM,CAC1B,KAAK,OAAO,KAAK,0CAAY,EAC7BD,EAAU,CACZ,CAAC,GAED,KAAK,OAAO,KAAK,0CAAY,EAC7BA,EAAU,GAIZ,WAAW,IAAM,CACf,KAAK,OAAO,KAAK,sDAAc,EAC/BA,EAAU,CACZ,EAAG,GAAI,CACT,CAAC,CACH,MACE,KAAK,OAAO,KAAK,0CAAY,EAC7BA,EAAU,CAEd,GAAG,CACL,CAAC,CACH,CAKO,SAAgB,CACrB,KAAK,OAAO,MAAM,qCAAiB,EAG/B,KAAK,2BACP,KAAK,iBAAiB,wBACpB,KAAK,wBACP,EACA,KAAK,yBAA2B,QAIlC,KAAK,cAAc,QAAQ,EAC3B,KAAK,oBAAoB,QAAQ,EAGjCE,GAAgB,EAGhB,KAAK,oBAAoB,WAAW,EAEpC,KAAK,OAAO,MAAM,0CAAiB,CACrC,CACF,IC30BA,IAAAC,GAAA,GAAAC,GAAAD,GAAA,wBAAAE,KAAA,IAkBaA,GAlBbC,GAAAC,EAAA,kBAKAC,KAOAC,KACAC,KAKaL,GAAN,KAAoD,CACzD,YACUM,EACAC,EACR,CAFQ,oBAAAD,EACA,mBAAAC,CACP,CAtBL,MAkB2D,CAAAC,EAAA,2BASzD,MAAM,MAAMC,EAA6C,CACvD,GAAI,CAEF,KAAK,qBAAqBA,CAAO,EAGjC,KAAK,eAAe,sBAAsB,EAG1C,IAAMC,EAAS,KAAK,UAAU,EAC9B,GAAIA,EAAO,QAIT,GAAI,CAEF,MAAM,KAAK,eAAe,oBAAoBA,EAAO,KAAO,CAAC,EAG7D,KAAK,eAAe,eAAe,EAGnC,MAAM,IAAI,QAASC,GAAY,WAAWA,EAAS,GAAI,CAAC,CAG1D,MAAoB,CAKpB,CAOF,OAHA,KAAK,iBAAiB,EAGdF,EAAQ,KAAM,CACpB,IAAK,aACH,MAAM,KAAK,mBAAmBA,CAAO,EACrC,MACF,IAAK,QAEH,MAAM,KAAK,gBAAgBA,CAAO,EAClC,MACF,IAAK,SACH,MAAM,KAAK,gBAAgBA,CAAO,EAClC,MACF,QACE,MAAM,KAAK,gBAAgBA,CAAO,EAClC,KACJ,CACF,OAASG,EAAO,CACd,MAAIA,aAAiBC,EACbD,EAEFC,EAAa,YACjBD,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CACvD,CACF,CACF,CAKA,MAAM,MAAsB,CAC1B,GAAI,CACF,IAAMF,EAAS,KAAK,UAAU,EAE9B,GAAI,CAACA,EAAO,QACV,MAAMG,EAAa,WAAW,EAIhC,MAAM,KAAK,eAAe,oBAAoBH,EAAO,KAAO,CAAC,EAG7D,KAAK,eAAe,eAAe,CACrC,OAASE,EAAO,CACd,MAAIA,aAAiBC,EACbD,EAEF,IAAIC,EACR,yCAAWD,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACnE,CACF,CACF,CAKA,MAAM,QAAQH,EAA6C,CACzD,GAAI,CAEa,KAAK,UAAU,EACnB,UACT,MAAM,KAAK,KAAK,EAEhB,MAAM,IAAI,QAASE,GAAY,WAAWA,EAAS,GAAI,CAAC,GAI1D,MAAM,KAAK,MAAMF,CAAO,CAC1B,OAASG,EAAO,CACd,MAAM,IAAIC,EACR,yCAAWD,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACnE,CACF,CACF,CAKA,WAA2B,CACzB,OAAO,KAAK,eAAe,iBAAiB,CAC9C,CAKQ,qBAAqBH,EAAoC,CAK/D,GAJIA,EAAQ,OAAS,QACnBK,EAAW,aAAaL,EAAQ,IAAI,EAIpCA,EAAQ,MACR,CAAC,CAAC,SAAU,aAAc,OAAO,EAAE,SAASA,EAAQ,IAAI,EAExD,MAAM,IAAII,EAAa,+CAAYJ,EAAQ,IAAI,EAAE,CAErD,CAKQ,kBAAyB,CAE/B,GAAI,CAAC,KAAK,cAAc,aAAa,EACnC,MAAMM,GAAY,eAAe,EAInC,GAAI,CAEF,GAAI,CADW,KAAK,cAAc,UAAU,EAE1C,MAAM,IAAIA,GAAY,sCAAQ,CAElC,OAASH,EAAO,CACd,MAAIA,aAAiBG,GACbH,EAEF,IAAIG,GACR,yCAAWH,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACnE,CACF,CACF,CAKA,MAAc,gBAAgBH,EAA6C,CACrEA,EAAQ,OAEV,MAAM,KAAK,uBAAuB,EAGlC,MAAM,KAAK,2BAA2B,CAE1C,CAKA,MAAc,mBACZA,EACe,CACf,IAAMO,EAAOP,EAAQ,MAAQ,IACvB,CAAE,MAAAQ,CAAM,EAAI,KAAM,QAAO,eAAoB,EAEnD,GAAIR,EAAQ,OAAQ,CAElB,IAAMS,EAAaC,EAAU,kBAAkB,KAAK,EAC9CC,EAAQH,EACZ,OACA,CAACC,EAAY,QAAS,WAAYF,EAAK,SAAS,CAAC,EACjD,CACE,SAAU,GACV,MAAO,CAAC,SAAU,SAAU,QAAQ,EACpC,IAAK,CACH,GAAG,QAAQ,IACX,mBAAoBG,EAAU,aAAa,EAC3C,eAAgB,OAChB,gBAAiB,MACnB,CACF,CACF,EAGA,KAAK,eAAe,YAAYC,EAAM,KAAO,EAAG,QAAQ,EAGxDA,EAAM,MAAM,EASZ,QAAQ,KAAK,CAAC,CAChB,KAAO,CAEL,GAAM,CAAE,UAAAC,CAAU,EAAI,KAAM,uCACtBC,EAAS,IAAID,EAAUL,CAAI,EAG3BO,EAAUf,EAAA,SAAY,CAC1B,MAAMc,EAAO,KAAK,EAClB,QAAQ,KAAK,CAAC,CAChB,EAHgB,WAKhB,QAAQ,GAAG,SAAUC,CAAO,EAC5B,QAAQ,GAAG,UAAWA,CAAO,EAE7B,MAAMD,EAAO,MAAM,CACrB,CACF,CAKA,MAAc,wBAAwC,CACpD,GAAM,CAAE,MAAAL,CAAM,EAAI,KAAM,QAAO,eAAoB,EAC7CO,EAAgBL,EAAU,yBAAyB,EAGzD,GAAI,EADO,KAAM,QAAO,IAAS,GACzB,QAAQ,WAAWK,CAAa,EACtC,MAAM,IAAIX,EAAa,6CAAoBW,CAAa,EAAE,EAK5D,IAAMJ,EAAQH,EAAM,OAFP,CAACO,CAAa,EAEO,CAChC,SAAU,GACV,MAAO,CAAC,SAAU,SAAU,QAAQ,EACpC,IAAK,CACH,GAAG,QAAQ,IACX,mBAAoBL,EAAU,aAAa,EAC3C,eAAgB,MAClB,CACF,CAAC,EAGD,KAAK,eAAe,YAAYC,EAAM,KAAO,EAAG,QAAQ,EAGxDA,EAAM,MAAM,EAQZ,QAAQ,KAAK,CAAC,CAChB,CAKA,MAAc,4BAA4C,CACxD,GAAM,CAAE,UAAAC,CAAU,EAAI,KAAM,uCACtBC,EAAS,IAAID,EAGbE,EAAUf,EAAA,SAAY,CAC1B,MAAMc,EAAO,KAAK,EAClB,KAAK,eAAe,eAAe,EACnC,QAAQ,KAAK,CAAC,CAChB,EAJgB,WAMhB,QAAQ,GAAG,SAAUC,CAAO,EAC5B,QAAQ,GAAG,UAAWA,CAAO,EAG7B,KAAK,eAAe,YAAY,QAAQ,IAAK,YAAY,EAEzD,MAAMD,EAAO,MAAM,CACrB,CACF,IC9TA,IAAAG,GAAA,GAAAC,GAAAD,GAAA,yBAAAE,KAIA,OAAOC,OAAQ,KACf,OAAOC,OAAU,OALjB,IAqCaF,GArCbG,GAAAC,EAAA,kBAMAC,KAEAC,KACAC,KACAC,KA2BaR,GAAN,KAAsD,CArC7D,MAqC6D,CAAAS,EAAA,4BACnD,cAAgB,IAAI,IAK5B,MAAM,uBAAiD,CACrD,GAAI,CACF,IAAMC,EAAeC,EAAU,iBAAiB,EAEhD,GAAI,CAACD,EACH,MAAO,CAAC,EAGV,IAAME,EAA4B,CAAC,EAC7BC,EAAeZ,GAClB,YAAYS,EAAc,CAAE,cAAe,EAAK,CAAC,EACjD,OAAQI,GAAWA,EAAO,YAAY,CAAC,EACvC,IAAKA,GAAWA,EAAO,IAAI,EAE9B,QAAWC,KAAgBF,EACzB,GAAI,CACF,IAAMG,EAAe,MAAM,KAAK,gBAAgBD,CAAY,EACxDC,GACFJ,EAAU,KAAKI,CAAY,CAE/B,MAAgB,CAGhB,CAGF,OAAOJ,CACT,MAAgB,CACd,MAAM,IAAIK,EACR,mDACAN,EAAU,iBAAiB,GAAK,EAClC,CACF,CACF,CAKA,MAAM,gBAAgBI,EAAoD,CACxE,GAAI,CAKF,GAHAG,EAAW,qBAAqBH,CAAY,EAGxC,KAAK,cAAc,IAAIA,CAAY,EACrC,OAAO,KAAK,cAAc,IAAIA,CAAY,EAG5C,IAAMI,EAAeR,EAAU,gBAAgBI,CAAY,EAC3D,GAAI,CAACI,EACH,OAAO,KAIT,IAAMC,EAAalB,GAAK,KAAKiB,EAAc,eAAe,EACtDE,EAAc,CAAC,EAEnB,GAAIC,EAAU,OAAOF,CAAU,EAC7B,GAAI,CACF,IAAMG,EAAgBD,EAAU,SAASF,CAAU,EACnDC,EAAS,KAAK,MAAME,CAAa,CACnC,MAAgB,CAEhB,CAIF,IAAMC,EAAQ,KAAK,iBAAiBL,CAAY,EAE1CH,EAA6B,CACjC,KAAMD,EACN,KAAMI,EACN,YAAaE,EAAO,aAAe,GAAGN,CAAY,gBAClD,QAASM,EAAO,SAAW,QAC3B,OAAQA,EAAO,OACf,MAAAG,CACF,EAGA,YAAK,cAAc,IAAIT,EAAcC,CAAY,EAE1CA,CACT,OAASS,EAAO,CACd,MAAIA,aAAiBC,EACbD,EAEF,IAAIR,EAAU,qDAAaF,CAAY,GAAI,EAAE,CACrD,CACF,CAKA,MAAM,aAAaA,EAAsBY,EAAmC,CAC1E,MAAM,KAAK,cAAc,CACvB,aAAAZ,EACA,WAAAY,EACA,YAAazB,GAAK,SAASyB,CAAU,CACvC,CAAC,CACH,CAKA,MAAM,cAAcC,EAA+C,CACjE,GAAI,CAEF,KAAK,sBAAsBA,CAAO,EAGlC,IAAMb,EAAea,EAAQ,cAAgB,UACvCZ,EAAe,MAAM,KAAK,gBAAgBD,CAAY,EAE5D,GAAI,CAACC,EACH,MAAM,IAAIC,EAAU,mCAAUF,CAAY,GAAI,EAAE,EAIlD,IAAMY,EAAazB,GAAK,QAAQ0B,EAAQ,UAAU,EAClD,GAAIN,EAAU,OAAOK,CAAU,EAC7B,MAAMV,EAAU,cAAcU,CAAU,EAI1CL,EAAU,UAAUK,CAAU,EAG9B,MAAM,KAAK,kBAAkBX,EAAcW,EAAYC,CAAO,EAG9D,MAAM,KAAK,yBAAyBD,EAAYC,CAAO,CAGzD,OAASH,EAAO,CACd,MAAIA,aAAiBR,GAAaQ,aAAiBC,EAC3CD,EAEF,IAAIR,EACR,yCAAWQ,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,GACjEG,EAAQ,UACV,CACF,CACF,CAKA,MAAM,iBAAiBb,EAAwC,CAC7D,GAAI,CACF,IAAMC,EAAe,MAAM,KAAK,gBAAgBD,CAAY,EAE5D,GAAI,CAACC,EACH,MAAO,GAIT,IAAMa,EAAgB,CAAC,cAAc,EAErC,QAAWC,KAAgBD,EAAe,CACxC,IAAME,EAAW7B,GAAK,KAAKc,EAAa,KAAMc,CAAY,EAC1D,GAAI,CAACR,EAAU,OAAOS,CAAQ,EAE5B,MAAO,EAEX,CAEA,MAAO,EACT,MAAQ,CACN,MAAO,EACT,CACF,CAKA,YAAmB,CACjB,KAAK,cAAc,MAAM,CAC3B,CAKQ,iBAAiBZ,EAAgC,CACvD,GAAI,CAOF,OANcG,EAAU,cAAcH,EAAc,CAClD,UAAW,GACX,cAAe,EACjB,CAAC,EAGY,OAAQa,GAAS,CAC5B,IAAMC,EAAe/B,GAAK,SAASiB,EAAca,CAAI,EACrD,MACE,CAACC,EAAa,WAAW,GAAG,GAC5BA,IAAiB,iBACjB,CAACA,EAAa,SAAS,cAAc,CAEzC,CAAC,CACH,MAAQ,CACN,MAAO,CAAC,CACV,CACF,CAKQ,sBAAsBL,EAAsC,CAClEV,EAAW,iBAAiBU,EAAQ,WAAY,YAAY,EAC5DV,EAAW,iBAAiBU,EAAQ,YAAa,aAAa,EAC9DV,EAAW,oBAAoBU,EAAQ,WAAW,EAE9CA,EAAQ,cACVV,EAAW,qBAAqBU,EAAQ,YAAY,CAExD,CAKA,MAAc,kBACZZ,EACAW,EACAC,EACe,CACf,GAAI,CAEFN,EAAU,cAAcN,EAAa,KAAMW,EAAY,CACrD,QAAS,CAAC,gBAAiB,OAAQ,cAAc,EACjD,UAAW,GACX,UAAW,EACb,CAAC,CACH,OAASF,EAAO,CACd,MAAM,IAAIR,EACR,qDAAaQ,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,GACnET,EAAa,IACf,CACF,CACF,CAKA,MAAc,yBACZW,EACAC,EACe,CACf,GAAI,CAEF,IAAMM,EAAY,CAChB,aAAcN,EAAQ,YACtB,mBAAoBA,EAAQ,YAAY,YAAY,EACpD,mBAAoBA,EAAQ,YAAY,YAAY,EACpD,GAAGA,EAAQ,SACb,EAGMO,EAAiB,CACrB,eACA,YACA,cACA,cACA,eACF,EAEA,QAAWC,KAAWD,EAAgB,CACpC,IAAMX,EAAQ,KAAK,mBAAmBG,EAAYS,CAAO,EAEzD,QAAWL,KAAYP,EACrB,MAAM,KAAK,uBAAuBO,EAAUG,CAAS,CAEzD,CACF,MAAgB,CAIhB,CACF,CAKQ,mBAAmBG,EAAkBD,EAA2B,CACtE,GAAI,CACF,GAAI,CAACA,EAAQ,SAAS,GAAG,EAAG,CAE1B,IAAML,EAAW7B,GAAK,KAAKmC,EAAUD,CAAO,EAC5C,OAAOd,EAAU,OAAOS,CAAQ,EAAI,CAACA,CAAQ,EAAI,CAAC,CACpD,CAGA,IAAMP,EAAQF,EAAU,cAAce,EAAU,CAAE,UAAW,EAAK,CAAC,EAC7DC,EAAQ,IAAI,OAChBF,EAAQ,QAAQ,QAAS,IAAI,EAAE,QAAQ,MAAO,OAAO,CACvD,EAEA,OAAOZ,EAAM,OAAQQ,GAAS,CAC5B,IAAMC,EAAe/B,GAAK,SAASmC,EAAUL,CAAI,EACjD,OAAOM,EAAM,KAAKL,CAAY,CAChC,CAAC,CACH,MAAQ,CACN,MAAO,CAAC,CACV,CACF,CAKA,MAAc,uBACZF,EACAG,EACe,CACf,GAAI,CACF,IAAIK,EAAUjB,EAAU,SAASS,CAAQ,EACrCS,EAAa,GAGjB,OAAW,CAACC,EAAKC,CAAK,IAAK,OAAO,QAAQR,CAAS,EAAG,CACpD,IAAMI,EAAQ,IAAI,OAAO,SAASG,CAAG,SAAU,GAAG,EAC9CH,EAAM,KAAKC,CAAO,IACpBA,EAAUA,EAAQ,QAAQD,EAAOI,CAAK,EACtCF,EAAa,GAEjB,CAGIA,GACFlB,EAAU,UAAUS,EAAUQ,EAAS,CAAE,UAAW,EAAK,CAAC,CAE9D,MAAgB,CAIhB,CACF,CACF,IC/JA,eAAsBI,IAAyC,CAC7D,OAAOC,GAAY,OAAO,CAC5B,CA5NA,IAkBaA,GAlBbC,GAAAC,EAAA,kBAIAC,IACAC,KAEAC,KACAC,KACAC,KACAC,KACAC,KACAC,KACAC,IAKaX,GAAN,MAAMY,CAAoC,CAlBjD,MAkBiD,CAAAC,EAAA,oBACvC,UAAY,IAAI,IAChB,UAAY,IAAI,IAChB,eAAiB,IAAI,IACrB,WAAa,IAAI,IAKzB,SAAYC,EAAaC,EAAkBC,EAAY,GAAa,CAClE,KAAK,UAAU,IAAIF,EAAKC,CAAO,EAC3BC,GACF,KAAK,WAAW,IAAIF,CAAG,CAE3B,CAKA,kBAAqBA,EAAaC,EAAwB,CACxD,KAAK,SAASD,EAAKC,EAAS,EAAI,CAClC,CAKA,iBAAoBD,EAAaG,EAAmB,CAClD,KAAK,UAAU,IAAIH,EAAKG,CAAQ,EAChC,KAAK,WAAW,IAAIH,CAAG,CACzB,CAKA,IAAOA,EAAgB,CAErB,GAAI,KAAK,WAAW,IAAIA,CAAG,GAAK,KAAK,UAAU,IAAIA,CAAG,EACpD,OAAO,KAAK,UAAU,IAAIA,CAAG,EAI/B,IAAMC,EAAU,KAAK,UAAU,IAAID,CAAG,EACtC,GAAI,CAACC,EACH,MAAM,IAAI,MAAM,WAAWD,CAAG,iBAAiB,EAIjD,IAAMG,EAAWF,EAAQ,EAGzB,OAAI,KAAK,WAAW,IAAID,CAAG,GACzB,KAAK,UAAU,IAAIA,EAAKG,CAAQ,EAG3BA,CACT,CAKA,IAAIH,EAAsB,CACxB,OAAO,KAAK,UAAU,IAAIA,CAAG,GAAK,KAAK,UAAU,IAAIA,CAAG,CAC1D,CAKA,OAAc,CACZ,KAAK,UAAU,MAAM,EACrB,KAAK,UAAU,MAAM,EACrB,KAAK,WAAW,MAAM,CACxB,CAKA,mBAA8B,CAC5B,IAAMI,EAAc,MAAM,KAAK,KAAK,UAAU,KAAK,CAAC,EAC9CC,EAAe,MAAM,KAAK,KAAK,UAAU,KAAK,CAAC,EACrD,MAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAGD,EAAa,GAAGC,CAAY,CAAC,CAAC,CACvD,CAKA,OAAO,QAAsB,CAC3B,IAAMC,EAAY,IAAIR,EAGtB,OAAAQ,EAAU,kBAAkB,eAAgB,IACnCC,EACR,EAEDD,EAAU,kBAAkB,gBAAiB,IACpCE,EACR,EAEDF,EAAU,kBAAkB,cAAe,IAClCG,EACR,EAEDH,EAAU,kBAAkB,YAAa,IAChCI,CACR,EAEDJ,EAAU,kBAAkB,YAAa,IAChCK,CACR,EAEDL,EAAU,kBAAkB,aAAc,IACjCM,CACR,EAGDN,EAAU,kBAAkB,gBAAiB,IACpCO,CACR,EAGDP,EAAU,kBAAkB,SAAU,IAC7BQ,CACR,EAGDR,EAAU,kBAAkB,eAAgB,IACnCS,EACR,EAGDT,EAAU,kBAAkB,iBAAkB,IAAM,CAClD,IAAMU,EAAuB,cAC7B,OAAO,IAAIA,EAAqB,kBAClC,CAAC,EAEDV,EAAU,kBAAkB,gBAAiB,IAAM,CACjD,IAAMW,EAAsB,cACtBC,EAAiBZ,EAAU,IAAI,gBAAgB,EAC/CQ,EAASR,EAAU,IAAI,QAAQ,EACrC,OAAO,IAAIW,EAAoB,kBAAkBC,EAAgBJ,CAAM,CACzE,CAAC,EAEDR,EAAU,kBAAkB,iBAAkB,IAAM,CAClD,IAAMa,EAAuB,cACvBD,EAAiBZ,EAAU,IAAI,gBAAgB,EAC/CO,EAAgBP,EAAU,IAAI,eAAe,EAC7CQ,EAASR,EAAU,IAAI,QAAQ,EACrC,OAAO,IAAIa,EAAqB,mBAC9BD,EACAL,EACAC,CACF,CACF,CAAC,EAEDR,EAAU,kBAAkB,kBAAmB,IAAM,CAEnD,IAAMc,EAAwB,cAC9B,OAAO,IAAIA,EAAsB,mBACnC,CAAC,EAoCMd,CACT,CACF,EAKsBP,EAAAd,GAAA,qBC1NtB,IAoEsBoC,GApEtBC,GAAAC,EAAA,kBAoEsBF,GAAf,KAA4D,CAMjE,YAAsBG,EAAyB,CAAzB,eAAAA,CAA0B,CA1ElD,MAoEmE,CAAAC,EAAA,2BAGjE,QACA,YAYU,WAAcC,EAAwB,CAC9C,OAAO,KAAK,UAAU,IAAIA,CAAW,CACvC,CAKU,YAAYC,EAAoB,CACnB,KAAK,WAAoB,cAAc,EAGpD,OAAOA,CAAK,CACtB,CAKU,aAAaC,EAAwBC,EAA6B,CAC1E,GAAID,EAAK,OAASC,EAChB,MAAM,IAAI,MACR,wCAAUA,CAAa,2DAAcD,EAAK,MAAM,SAClD,CAEJ,CACF,IC5GA,IAAAE,GAAA,GAAAC,GAAAD,GAAA,2BAAAE,KAAA,IAYaA,GAZbC,GAAAC,EAAA,kBAKAC,KAEAC,IAKaJ,GAAN,cAAoCK,EAAmB,CAZ9D,MAY8D,CAAAC,EAAA,8BACnD,KAAO,UACP,YAAc,uCAEd,YAA4B,CACnC,CACE,KAAM,QACN,YAAa,2BACb,QAAS,CACP,CAAE,MAAO,eAAgB,YAAa,4CAAU,EAChD,CAAE,MAAO,UAAW,YAAa,kFAAuB,EACxD,CACE,MAAO,UACP,YAAa,iGACf,CACF,EACA,QAASA,EAAA,MAAOC,EAAaC,IAAiB,CAC5C,MAAM,KAAK,YAAYA,CAAO,CAChC,EAFS,UAGX,EACA,CACE,KAAM,OACN,YAAa,2BACb,QAASF,EAAA,MAAOC,EAAaC,IAAiB,CAC5C,MAAM,KAAK,WAAW,CACxB,EAFS,UAGX,EACA,CACE,KAAM,SACN,YAAa,uCACb,QAASF,EAAA,MAAOC,EAAaC,IAAiB,CAC5C,MAAM,KAAK,aAAa,CAC1B,EAFS,UAGX,EACA,CACE,KAAM,UACN,YAAa,2BACb,QAAS,CAAC,CAAE,MAAO,eAAgB,YAAa,4CAAU,CAAC,EAC3D,QAASF,EAAA,MAAOC,EAAaC,IAAiB,CAC5C,MAAM,KAAK,cAAcA,CAAO,CAClC,EAFS,UAGX,EACA,CACE,KAAM,SACN,YAAa,qEACb,QAASF,EAAA,MAAOC,EAAaC,IAAiB,CAC5C,MAAM,KAAK,aAAa,CAC1B,EAFS,UAGX,CACF,EAEA,YAAYC,EAAyB,CACnC,MAAMA,CAAS,CACjB,CAKA,MAAM,QAAQF,EAAaC,EAA6B,CAExD,CAKA,MAAc,YAAYA,EAA6B,CACrD,GAAI,CAEEA,EAAQ,OAEVE,GAAkB,OAAO,EAG3B,IAAMC,EAAiB,KAAK,WAAgB,gBAAgB,EAE5D,GAAIH,EAAQ,MAAO,CAEjB,KAAK,wBAAwB,EAC7B,MACF,CAGA,MAAMG,EAAe,MAAM,CACzB,OAAQH,EAAQ,QAAU,EAC5B,CAAC,CACH,OAASI,EAAO,CACd,KAAK,YAAYA,CAAc,CACjC,CACF,CAKA,MAAc,YAA4B,CACxC,GAAI,CAEF,MADuB,KAAK,WAAgB,gBAAgB,EACvC,KAAK,CAC5B,OAASA,EAAO,CACd,KAAK,YAAYA,CAAc,CACjC,CACF,CAKA,MAAc,cAA8B,CAC1C,GAAI,CAEF,IAAMC,EAAS,MADQ,KAAK,WAAgB,gBAAgB,EACxB,UAAU,EAE1CA,EAAO,UAELA,EAAO,OAGPA,EAAO,KAMf,OAASD,EAAO,CACd,KAAK,YAAYA,CAAc,CACjC,CACF,CAKA,MAAc,cAAcJ,EAA6B,CACvD,GAAI,CAEF,MADuB,KAAK,WAAgB,gBAAgB,EACvC,QAAQ,CAC3B,OAAQA,EAAQ,QAAU,EAC5B,CAAC,CACH,OAASI,EAAO,CACd,KAAK,YAAYA,CAAc,CACjC,CACF,CAKA,MAAc,cAA8B,CAC1C,GAAI,CAEF,MADsB,KAAK,WAAgB,eAAe,EACtC,aAAa,CACnC,OAASA,EAAO,CACd,KAAK,YAAYA,CAAc,CACjC,CACF,CAKQ,yBAAgC,CAcxC,CACF,ICtLA,IAAAE,GAAA,GAAAC,GAAAD,GAAA,0BAAAE,KAIA,OAAOC,OAAU,OAIjB,MAAkB,QAClB,OAAOC,OAAS,MAThB,IAcaF,GAdbG,GAAAC,EAAA,kBAMAC,KAQaL,GAAN,cAAmCM,EAAmB,CAd7D,MAc6D,CAAAC,EAAA,6BAClD,KAAO,SACP,YAAc,uCAEd,YAA4B,CACnC,CACE,KAAM,OACN,YAAa,6CACb,QAAS,CACP,CACE,MAAO,wBACP,YAAa,4DACb,aAAc,MAChB,CACF,EACA,QAASA,EAAA,MAAOC,EAAaC,IAAiB,CAC5C,MAAM,KAAK,WAAWA,CAAO,CAC/B,EAFS,UAGX,EACA,CACE,KAAM,MACN,YAAa,iCACb,QAASF,EAAA,MAAOC,EAAaC,IAAiB,CAC5C,KAAK,aAAaD,EAAM,CAAC,EACzB,MAAM,KAAK,UAAUA,EAAK,CAAC,CAAC,CAC9B,EAHS,UAIX,EACA,CACE,KAAM,MACN,YAAa,iCACb,QAASD,EAAA,MAAOC,EAAaC,IAAiB,CAC5C,KAAK,aAAaD,EAAM,CAAC,EACzB,MAAM,KAAK,UAAUA,EAAK,CAAC,EAAGA,EAAK,CAAC,CAAC,CACvC,EAHS,UAIX,CACF,EAEA,YAAYE,EAAyB,CACnC,MAAMA,CAAS,CACjB,CAKA,MAAM,QAAQF,EAAaC,EAA6B,CAExD,CAKA,MAAc,WAAWA,EAA6B,CACpD,IAAME,EAAUT,GAAI,mCAAU,EAAE,MAAM,EAEtC,GAAI,CACF,IAAMU,EAASH,EAAQ,OACvB,GAAIG,IAAW,QAAUA,IAAW,SAAWA,IAAW,QACxD,MAAM,IAAI,MAAM,yDAA2B,EAG7C,IAAMC,EAAgB,KAAK,WAAgB,eAAe,EAE1D,GAAIA,EAAc,aAAa,EAAG,CAChCF,EAAQ,KAAK,4CAAS,EAEtB,MACF,CAEAE,EAAc,WAAWD,CAAM,EAC/BD,EAAQ,QAAQ,wDAAW,EAG3B,IAAMG,EAAY,QAAQ,IAAI,oBAAsB,QAAQ,IAAI,EAC1DC,EAAiB,kBAAkBH,CAAM,GACzCI,EAAaf,GAAK,KAAKa,EAAWC,CAAc,CASxD,OAASE,EAAO,CACdN,EAAQ,KACN,+CAAYM,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACpE,EACA,KAAK,YAAYA,CAAc,CACjC,CACF,CAKA,MAAc,UAAUC,EAA4B,CAClD,IAAMP,EAAUT,GAAI,6BAAS,EAAE,MAAM,EAErC,GAAI,CACF,IAAMW,EAAgB,KAAK,WAAgB,eAAe,EAE1D,GAAI,CAACA,EAAc,aAAa,EAAG,CACjCF,EAAQ,KAAK,4CAAS,EAItB,MACF,CAEA,IAAMQ,EAASN,EAAc,UAAU,EAEvC,OAAQK,EAAK,CACX,IAAK,cAAe,CAClBP,EAAQ,QAAQ,0BAAM,EACtB,IAAMS,EAAYP,EAAc,gBAAgB,EAC5CO,EAAU,SAAW,GAEdA,EAAU,SAAW,GAI9BA,EAAU,QAAQ,CAACC,EAAYC,IAAkB,CAEjD,CAAC,EAEH,KACF,CACA,IAAK,aACHX,EAAQ,QAAQ,0BAAM,EAEtB,OAAW,CAACY,EAAMC,CAAY,IAAK,OAAO,QACxCL,EAAO,UACT,EAAG,CACD,IAAMM,EAASD,EAEX,SAAUC,GAAUA,EAAO,IASjC,CACA,MACF,IAAK,aAAc,CACjBd,EAAQ,QAAQ,0BAAM,EACtB,IAAMe,EAAmBb,EAAc,oBAAoB,EAa3D,KACF,CACA,IAAK,oBACHF,EAAQ,QAAQ,0BAAM,EAMtB,MACF,IAAK,mBACHA,EAAQ,QAAQ,0BAAM,EAMtB,MACF,IAAK,oBACHA,EAAQ,QAAQ,0BAAM,EAItB,MACF,QACEA,EAAQ,KAAK,yCAAWO,CAAG,EAAE,CAMjC,CACF,OAASD,EAAO,CACdN,EAAQ,KACN,yCAAWM,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACnE,EACA,KAAK,YAAYA,CAAc,CACjC,CACF,CAKA,MAAc,UAAUC,EAAaS,EAA8B,CACjE,IAAMhB,EAAUT,GAAI,6BAAS,EAAE,MAAM,EAErC,GAAI,CACF,IAAMW,EAAgB,KAAK,WAAgB,eAAe,EAE1D,GAAI,CAACA,EAAc,aAAa,EAAG,CACjCF,EAAQ,KAAK,4CAAS,EAItB,MACF,CAEA,OAAQO,EAAK,CACX,IAAK,cACHL,EAAc,kBAAkBc,CAAK,EACrChB,EAAQ,QAAQ,6CAAegB,CAAK,EAAE,EACtC,MACF,IAAK,oBAAqB,CACxB,IAAMC,EAAW,OAAO,SAASD,CAAK,EACtC,GAAI,OAAO,MAAMC,CAAQ,GAAKA,GAAY,EACxC,MAAM,IAAI,MAAM,0EAAc,EAEhCf,EAAc,wBAAwBe,CAAQ,EAC9CjB,EAAQ,QAAQ,iEAAeiB,CAAQ,IAAI,EAC3C,KACF,CACA,IAAK,mBAAoB,CACvB,IAAMC,EAAU,OAAO,SAASF,CAAK,EACrC,GAAI,OAAO,MAAME,CAAO,GAAKA,GAAW,EACtC,MAAM,IAAI,MAAM,0EAAc,EAEhChB,EAAc,uBAAuBgB,CAAO,EAC5ClB,EAAQ,QAAQ,iEAAekB,CAAO,IAAI,EAC1C,KACF,CACA,IAAK,oBAAqB,CACxB,IAAMD,EAAW,OAAO,SAASD,CAAK,EACtC,GAAI,OAAO,MAAMC,CAAQ,GAAKA,GAAY,EACxC,MAAM,IAAI,MAAM,8DAAY,EAE9Bf,EAAc,wBAAwBe,CAAQ,EAC9CjB,EAAQ,QAAQ,qDAAaiB,CAAQ,IAAI,EACzC,KACF,CACA,QACEjB,EAAQ,KAAK,2DAAcO,CAAG,EAAE,CAMpC,CACF,OAASD,EAAO,CACdN,EAAQ,KACN,yCAAWM,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACnE,EACA,KAAK,YAAYA,CAAc,CACjC,CACF,CACF,ICtRA,IAAAa,GAAA,GAAAC,GAAAD,GAAA,2BAAAE,KAIA,OAAOC,OAAU,OAIjB,OAAOC,OAAW,QAClB,OAAOC,OAAS,MAThB,IAcaH,GAdbI,GAAAC,EAAA,kBAMAC,KAQaN,GAAN,cAAoCO,EAAmB,CAd9D,MAc8D,CAAAC,EAAA,8BACnD,KAAO,SACP,YAAc,2BAEd,QAA2B,CAClC,CACE,MAAO,gCACP,YAAa,8DACf,CACF,EAEA,YAAYC,EAAyB,CACnC,MAAMA,CAAS,CACjB,CAKA,MAAM,QAAQC,EAAaC,EAA6B,CACtD,KAAK,aAAaD,EAAM,CAAC,EACzB,IAAME,EAAcF,EAAK,CAAC,EAE1B,MAAM,KAAK,aAAaE,EAAaD,CAAO,CAC9C,CAKA,MAAgB,aACdC,EACAD,EACe,CACf,IAAME,EAAUV,GAAI,mCAAU,EAAE,MAAM,EAEtC,GAAI,CACF,IAAMW,EAAkB,KAAK,WAAgB,iBAAiB,EACxDC,EAAY,KAAK,WAAgB,WAAW,EAG5CC,EAAaf,GAAK,KAAK,QAAQ,IAAI,EAAGW,CAAW,EAGvD,GAAI,MAAMG,EAAU,OAAOC,CAAU,EAAG,CACtCH,EAAQ,KAAK,iBAAOD,CAAW,sBAAO,EAItC,MACF,CAEID,EAAQ,SAEV,MAAM,KAAK,mBACTC,EACAD,EAAQ,SACRK,EACAH,EACAC,CACF,EAGA,MAAM,KAAK,mBACTF,EACAI,EACAH,EACAC,CACF,CAEJ,OAASG,EAAO,CACdJ,EAAQ,KACN,yCAAWI,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACnE,EACA,KAAK,YAAYA,CAAc,CACjC,CACF,CAKA,MAAc,mBACZL,EACAM,EACAF,EACAH,EACAC,EACe,CACfD,EAAQ,KAAO,8BAGf,IAAMM,EAAqB,MAAML,EAAgB,sBAAsB,EAEvE,GAAIK,EAAmB,SAAW,EAAG,CACnCN,EAAQ,KAAK,4CAAS,EAEtB,MACF,CAGA,IAAIO,EAAqBF,EAKzB,GAAI,CADF,MAAMJ,EAAgB,iBAAiBM,CAAkB,EACrC,CACpBP,EAAQ,KAAK,iBAAOO,CAAkB,sBAAO,EAG7C,IAAMC,EAAkB,KAAK,oBAC3BD,EACAD,CACF,EAEA,GAAIE,EAQF,GAJkB,MAAM,KAAK,oBAC3BnB,GAAM,KAAK,yDAAiB,CAC9B,EAGEkB,EAAqBC,MAChB,CACL,KAAK,uBAAuBF,CAAkB,EAC9C,MACF,KACK,CACL,KAAK,uBAAuBA,CAAkB,EAC9C,MACF,CACF,CAEAN,EAAQ,KAAO,uBAAQO,CAAkB,+BAAWR,CAAW,OAG/D,MAAME,EAAgB,cAAc,CAClC,aAAcM,EACd,WAAAJ,EACA,YAAAJ,CACF,CAAC,EAEDC,EAAQ,QAAQ,iBAAOD,CAAW,4BAAQ,CAQ5C,CAKA,MAAc,mBACZA,EACAI,EACAH,EACAC,EACe,CACfD,EAAQ,KAAO,yCAAWD,CAAW,OAGrC,MAAME,EAAgB,cAAc,CAClC,aAAc,KACd,WAAAE,EACA,YAAAJ,CACF,CAAC,EAEDC,EAAQ,QAAQ,iBAAOD,CAAW,4BAAQ,CAY5C,CAKQ,uBAAuBU,EAA2B,CAExD,QAAWC,KAAYD,EAAW,CAGpC,CAKQ,oBACNE,EACAF,EACe,CACf,IAAMG,EAAc,KAAK,WAAgB,aAAa,EAElDC,EAAY,KACZC,EAAiB,EAErB,QAAWJ,KAAYD,EAAW,CAChC,IAAMM,EAAaH,EAAY,oBAC7BD,EAAM,YAAY,EAClBD,EAAS,YAAY,CACvB,EACIK,EAAaD,GAAkBC,EAAa,KAC9CD,EAAiBC,EACjBF,EAAYH,EAEhB,CAEA,OAAOG,CACT,CAKA,MAAc,oBAAoBG,EAAkC,CAElE,IAAMC,GADW,KAAM,QAAO,UAAe,GACzB,gBAAgB,CAClC,MAAO,QAAQ,MACf,OAAQ,QAAQ,MAClB,CAAC,EAED,OAAO,IAAI,QAASC,GAAY,CAC9BD,EAAG,SAASD,EAASG,GAAW,CAC9BF,EAAG,MAAM,EACTC,EACEC,EAAO,YAAY,EAAE,KAAK,IAAM,KAC9BA,EAAO,YAAY,EAAE,KAAK,IAAM,KACpC,CACF,CAAC,CACH,CAAC,CACH,CACF,ICtMO,SAASC,GACdC,EAC6B,CAC7B,IAAMC,EAASD,EACf,OACE,OAAOC,GAAW,UAClBA,IAAW,MACX,YAAaA,GACb,SAAUA,GACV,OAAOA,EAAO,SAAY,UAC1B,MAAM,QAAQA,EAAO,IAAI,GACzBA,EAAO,KAAK,MAAOC,GAAiB,OAAOA,GAAQ,QAAQ,CAE/D,CApEA,IAAAC,GAAAC,EAAA,kBAuDgBC,EAAAN,GAAA,4BCvDhB,IAAAO,GAAA,GAAAC,GAAAD,GAAA,uBAAAE,KAiBA,OAAOC,MAAW,QAClB,OAAOC,OAAW,aAClB,OAAOC,OAAS,MAnBhB,IAiCaH,GAjCbI,GAAAC,EAAA,kBAIAC,IAEAC,KAOAC,KACAC,KAEAC,IAiBaV,GAAN,MAAMW,UAA0BC,EAAmB,CAjC1D,MAiC0D,CAAAC,EAAA,0BAChD,OACA,eACA,QAER,eAAeC,EAAwD,CACrE,MAAM,GAAGA,CAAI,EACb,KAAK,OAASC,EACd,KAAK,eAAiB,IAAIC,GAG1B,GAAI,CACF,IAAMC,EAAUC,EAAc,aAAa,GAAK,KAChD,KAAK,QAAU,oBAAoBD,CAAO,EAC5C,MAAQ,CACN,KAAK,QAAU,uBACjB,CACF,CAaA,OAAwB,mBACtB,4CAKF,OAAe,gBAAgBE,EAAqB,CAClD,IAAIC,EAAQ,EACZ,QAAWC,KAAQF,EAEbR,EAAkB,mBAAmB,KAAKU,CAAI,EAChDD,GAAS,EAETA,GAAS,EAGb,OAAOA,CACT,CAKA,OAAe,gBAAgBD,EAAaG,EAA0B,CACpE,GAAIX,EAAkB,gBAAgBQ,CAAG,GAAKG,EAC5C,OAAOH,EAIT,GAAIG,GAAY,EACd,MAAO,GAGT,IAAIC,EAAS,GACTC,EAAe,EACfC,EAAe,GAEnB,QAAWJ,KAAQF,EAAK,CACtB,IAAMO,EAAYf,EAAkB,mBAAmB,KAAKU,CAAI,EAAI,EAAI,EAGxE,GAAIG,EAAeE,EAAYJ,EAAW,EAAG,CAE3C,GAAI,CAACG,EACH,MAAO,GAGTF,GAAU,MACV,KACF,CAEAA,GAAUF,EACVG,GAAgBE,EAChBD,EAAe,EACjB,CAEA,OAAOF,CACT,CAOA,OAAe,cAAcI,EAA6C,CACxE,GAAI,CACF,OAAO,KAAK,MAAMA,CAAU,CAC9B,OAASC,EAAO,CACd,MAAM,IAAI,MACR,mIACEA,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CACvD,EACF,CACF,CACF,CAOA,OAAe,qBAAqBL,EAAgC,CAClE,OAAO,KAAK,UAAUA,CAAM,CAC9B,CAES,KAAO,MACP,YAAc,iDAEd,YAA4B,CACnC,CACE,KAAM,OACN,YAAa,gCACb,QAAS,CAAC,CAAE,MAAO,UAAW,YAAa,oEAAc,CAAC,EAC1D,QAASV,EAAA,MAAOC,EAAwBe,IAA4B,CAClE,MAAM,KAAK,WAAWA,CAAsB,CAC9C,EAFS,UAGX,EACA,CACE,KAAM,SACN,YAAa,kDACb,QAAShB,EAAA,MAAOC,EAAwBe,IAA4B,CAClE,KAAK,aAAaf,EAAM,CAAC,EACzB,MAAM,KAAK,aAAaA,EAAK,CAAC,CAAC,CACjC,EAHS,UAIX,EACA,CACE,KAAM,OACN,YAAa,2EACb,QAASD,EAAA,MAAOC,EAAwBe,IAA4B,CAClE,KAAK,aAAaf,EAAM,CAAC,EACzB,GAAM,CAACgB,EAAYC,EAAUC,CAAM,EAAIlB,EAEnCkB,IAAW,UAAYA,IAAW,WAEpC,QAAQ,KAAK,CAAC,EAGhB,IAAMC,EAAUD,IAAW,SAC3B,MAAM,KAAK,WAAWF,EAAYC,EAAUE,CAAO,CACrD,EAXS,UAYX,EACA,CACE,KAAM,OACN,YAAa,yDACb,QAAS,CACP,CACE,MAAO,gBACP,YAAa,+CACb,aAAc,IAChB,CACF,EACA,QAASpB,EAAA,MAAOC,EAAwBe,IAA4B,CAClE,KAAK,aAAaf,EAAM,CAAC,EACzB,GAAM,CAACoB,EAAaH,CAAQ,EAAIjB,EAChC,MAAM,KAAK,WACToB,EACAH,EACCF,EAAwB,MAAQ,IACnC,CACF,EARS,UASX,CACF,EAKA,MAAM,QACJf,EACAe,EACe,CAEjB,CAKA,MAAc,WAAWA,EAAqC,CAC5D,GAAI,CACF,MAAM,KAAK,mBAAmBA,CAAO,CACvC,OAASD,EAAO,CACd,KAAK,YAAYA,CAAc,CACjC,CACF,CAKA,MAAc,aAAaE,EAAmC,CAC5D,GAAI,CACF,MAAM,KAAK,qBAAqBA,CAAU,CAC5C,OAASF,EAAO,CACd,KAAK,YAAYA,CAAc,CACjC,CACF,CAKA,MAAc,WACZE,EACAC,EACAE,EACe,CACf,GAAI,CACF,MAAM,KAAK,mBAAmBH,EAAYC,EAAUE,CAAO,CAC7D,OAASL,EAAO,CACd,KAAK,YAAYA,CAAc,CACjC,CACF,CAMA,MAAc,uBAAuC,CAGnD,GAAI,CADkB,KAAK,eAAe,iBAAiB,EACxC,QACjB,MAAM,IAAI,MACR,+IACF,EAIF,GAAI,CACF,IAAMO,EAAW,MAAM,MAAM,GAAG,KAAK,OAAO,cAAe,CACzD,OAAQ,MACR,OAAQ,YAAY,QAAQ,GAAI,CAClC,CAAC,EAED,GAAI,CAACA,EAAS,GACZ,MAAM,IAAI,MAAM,mDAAgBA,EAAS,MAAM,EAAE,CAErD,OAASP,EAAgB,CAEvB,GAAIA,aAAiB,OAASA,EAAM,OAAS,aAC3C,MAAM,IAAI,MAAM,6HAA8B,EAIhD,GAAIA,aAAiB,MAKnB,MAHEA,aAAiB,WACjB,wBAAwB,KAAKA,EAAM,OAAO,EAGpC,IAAI,MACR,4OAAmDA,EAAM,OAAO,EAClE,EAGI,IAAI,MACR,sIAAkCA,EAAM,OAAO,EACjD,EAIF,IAAIQ,EACJ,GAAI,CACFA,EAAS,KAAK,UAAUR,CAAK,CAC/B,MAAQ,CACNQ,EAAS,OAAOR,CAAK,CACvB,CAEA,MAAM,IAAI,MACR,sIAAkCQ,CAAM,EAC1C,CACF,CACF,CASA,MAAc,iBACZF,EACAH,EACAjB,EACyB,CAEzB,MAAM,KAAK,sBAAsB,EAGjC,GAAI,CACF,IAAMqB,EAAW,MAAM,MAAM,GAAG,KAAK,OAAO,kBAAmB,CAC7D,OAAQ,OACR,QAAS,CACP,eAAgB,kBAClB,EACA,KAAM,KAAK,UAAU,CACnB,YAAAD,EACA,SAAAH,EACA,KAAAjB,CACF,CAAC,CACH,CAAC,EAED,GAAI,CAACqB,EAAS,GAAI,CAChB,IAAIE,EAAe,QAAQF,EAAS,MAAM,KAAKA,EAAS,UAAU,GAClE,GAAI,CACF,IAAMG,EAAY,MAAMH,EAAS,KAAK,EAChCI,EACJD,GAAW,OAAO,SAAWA,GAAW,QACtC,OAAOC,GAAoB,UAAYA,EAAgB,KAAK,IAC9DF,EAAeE,EAEnB,MAAQ,CAER,CACA,MAAM,IAAI,MAAMF,CAAY,CAC9B,CAEA,IAAMG,EAAe,MAAML,EAAS,KAAK,EAEzC,GAAI,CAACK,EAAa,QAChB,MAAM,IAAI,MAAMA,EAAa,OAAO,SAAW,sCAAQ,EAGzD,OAAOA,EAAa,IACtB,OAASZ,EAAO,CACd,WAAK,OAAO,MACV,yCAAWM,CAAW,IAAIH,CAAQ,GAClCH,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CACvD,EACMA,CACR,CACF,CAKA,MAAc,WACZM,EACAH,EACAJ,EACe,CACf,GAAI,CAEF,IAAMb,EAAOH,EAAkB,cAAcgB,CAAU,EAGjDJ,EAAS,MAAM,KAAK,iBAAiBW,EAAaH,EAAUjB,CAAI,CAGxE,OAASc,EAAO,CAKd,IAAMS,EAAgBT,EAAgB,QAiBtC,GAhBIS,EAAa,SAAS,gCAAO,GAKtBA,EAAa,SAAS,sCAAQ,EAWrC,QAAQ,IAAI,WAAa,OAC3B,MAAM,IAAI,MAAM,qBAAqB,EAGvC,QAAQ,KAAK,CAAC,CAChB,CACF,CAKA,MAAc,mBACZR,EAA+B,CAAC,EACjB,CACf,IAAMY,EAAUtC,GAAI,8CAAgB,EAAE,MAAM,EAE5C,GAAI,CACF,IAAMuC,EAAaxB,EAAc,cAAc,EACzCyB,EAAc,OAAO,KAAKD,CAAU,EAGpCE,EAAiB1B,EAAc,kBAAkB,EACjD2B,EAAeD,EAAe,OAAS,EAGvCE,EAAgBH,EAAY,QAAUE,EAAe,EAAI,GAE/D,GAAIC,IAAkB,EAAG,CACvBL,EAAQ,KAAK,8EAA4B,EAMzC,MACF,CAMA,GAJAA,EAAQ,QACN,gBAAMK,CAAa,2BAAYD,EAAe,4BAAoB,EAAE,EACtE,EAEIhB,EAAQ,MAAO,CAOjB,IAAIkB,EAAmB,EACjBC,EAAyB,CAAC,EAGhC,QAAWlB,KAAca,EAAa,CACpC,IAAMM,EAAc/B,EAAc,qBAAqBY,CAAU,EAC3DoB,EAAY,OAAO,KAAKD,CAAW,EACzCD,EAAa,KAAK,GAAGE,CAAS,CAChC,CAGA,GAAIL,EAAc,CAChB,IAAMM,EAAkBP,EAAe,IAAKQ,GAASA,EAAK,IAAI,EAC9DJ,EAAa,KAAK,GAAGG,CAAe,CACtC,CAGA,QAAWpB,KAAYiB,EAAc,CACnC,IAAM5B,EAAQT,EAAkB,gBAAgBoB,CAAQ,EACpDX,EAAQ2B,IACVA,EAAmB3B,EAEvB,CAGA2B,EAAmB,KAAK,IAAI,GAAI,KAAK,IAAIA,EAAmB,EAAG,EAAE,CAAC,EAGlE,IAAMM,EAAQ,IAAInD,GAAM,CACtB,KAAM,CACJD,EAAM,KAAK,KAAK,EAChBA,EAAM,KAAK,0BAAM,EACjBA,EAAM,KAAK,cAAI,EACfA,EAAM,KAAK,cAAI,CACjB,EACA,UAAW,CAAC,GAAI8C,EAAkB,EAAG,EAAE,EACvC,SAAU,GACV,MAAO,CACL,KAAM,CAAC,EACP,OAAQ,CAAC,CACX,CACF,CAAC,EAGD,GAAIF,EACF,QAAWS,KAAcV,EAAgB,CACvC,IAAMW,EAAc5C,EAAkB,gBACpC2C,EAAW,aAAe,GAC1B,EACF,EAEAD,EAAM,KAAK,CACT,YACAC,EAAW,KACXrD,EAAM,MAAM,cAAI,EAChBsD,CACF,CAAC,CACH,CAIF,QAAWzB,KAAca,EAAa,CACpC,IAAMM,EAAc/B,EAAc,qBAAqBY,CAAU,EAC3DoB,EAAY,OAAO,KAAKD,CAAW,EAEzC,GAAIC,EAAU,SAAW,EAEvBG,EAAM,KAAK,CACTpD,EAAM,KAAK6B,CAAU,EACrB7B,EAAM,KAAK,GAAG,EACdA,EAAM,KAAK,GAAG,EACdA,EAAM,KAAK,wDAAW,CACxB,CAAC,MACI,CAEDoD,EAAM,OAAS,GACjBA,EAAM,KAAK,CAAC,CAAE,QAAS,EAAG,QAAS,EAAG,CAAC,CAAC,EAG1C,QAAWtB,KAAYmB,EAAW,CAChC,IAAMM,GAAaP,EAAYlB,CAAQ,EACjC0B,GAASD,GAAW,OACtBvD,EAAM,MAAM,cAAI,EAChBA,EAAM,IAAI,cAAI,EAGZsD,GAAc5C,EAAkB,gBACpC6C,GAAW,aAAe,GAC1B,EACF,EAGAH,EAAM,KAAK,CAACvB,EAAYC,EAAU0B,GAAQF,EAAW,CAAC,CACxD,CACF,CACF,CAGF,KAoBE,SAAWzB,KAAca,EAAa,CACpC,IAAMe,EAAehB,EAAWZ,CAAU,EACpCmB,EAAc/B,EAAc,qBAAqBY,CAAU,EAC3D6B,EAAY,OAAO,KAAKV,CAAW,EAAE,OACrCW,EAAe,OAAO,OAAOX,CAAW,EAAE,OAC7CY,GAAMA,EAAE,SAAW,EACtB,EAAE,OAKE,QAASH,EAEP,SAAUA,GAAgBA,EAAa,KAMlCI,GAAuBJ,CAAY,EAQ1CC,EAAY,CAUlB,CAeJ,MAAgB,CACdlB,EAAQ,KAAK,uDAAe,EAM5B,QAAQ,KAAK,CAAC,CAChB,CACF,CAKA,MAAc,qBAAqBX,EAAmC,CACpE,IAAMW,EAAUtC,GAAI,gBAAM2B,CAAU,gDAAa,EAAE,MAAM,EAEzD,GAAI,CAGF,GAAI,CAFeZ,EAAc,cAAc,EAE/BY,CAAU,EAAG,CAC3BW,EAAQ,KAAK,iBAAOX,CAAU,sBAAO,EAIrC,MACF,CAEA,IAAMmB,EAAc/B,EAAc,qBAAqBY,CAAU,EAC3DoB,EAAY,OAAO,KAAKD,CAAW,EAEzC,GAAIC,EAAU,SAAW,EAAG,CAC1BT,EAAQ,KAAK,iBAAOX,CAAU,wCAAU,EAExC,MACF,CAEAW,EAAQ,QAAQ,iBAAOX,CAAU,kBAAQoB,EAAU,MAAM,qBAAM,EAO/D,IAAMG,EAAQ,IAAInD,GAAM,CACtB,KAAM,CAACD,EAAM,KAAK,0BAAM,EAAGA,EAAM,KAAK,cAAI,EAAGA,EAAM,KAAK,cAAI,CAAC,EAC7D,UAAW,CAAC,GAAI,EAAG,EAAE,EACrB,SAAU,GACV,MAAO,CACL,KAAM,CAAC,EACP,OAAQ,CAAC,CACX,CACF,CAAC,EAED,QAAW8B,KAAYmB,EAAW,CAChC,IAAMM,EAAaP,EAAYlB,CAAQ,EACjC0B,EAASD,EAAW,OACtBvD,EAAM,MAAM,cAAI,EAChBA,EAAM,IAAI,cAAI,EAGZsD,EAAc5C,EAAkB,gBACpC6C,EAAW,aAAe,GAC1B,EACF,EAEAH,EAAM,KAAK,CAACtB,EAAU0B,EAAQF,CAAW,CAAC,CAC5C,CAgBF,MAAgB,CACdd,EAAQ,KAAK,kDAAU,EAMvB,QAAQ,KAAK,CAAC,CAChB,CACF,CAKA,MAAc,mBACZX,EACAC,EACAE,EACe,CACf,IAAMD,EAASC,EAAU,eAAO,eAC1BQ,EAAUtC,GAAI,GAAG6B,CAAM,gBAAMF,CAAU,IAAIC,CAAQ,KAAK,EAAE,MAAM,EAEtE,GAAI,CAGF,GAAI,CAFeb,EAAc,cAAc,EAE/BY,CAAU,EAAG,CAC3BW,EAAQ,KAAK,iBAAOX,CAAU,sBAAO,EAIrC,MACF,CAEA,IAAMmB,EAAc/B,EAAc,qBAAqBY,CAAU,EAEjE,GAAI,CAACmB,EAAYlB,CAAQ,EAAG,CAC1BU,EAAQ,KAAK,iBAAOV,CAAQ,yBAAUD,CAAU,4BAAQ,EAMxD,MACF,CAGAZ,EAAc,eACZY,EACAC,EACAE,EACAgB,EAAYlB,CAAQ,EAAE,WACxB,EAEAU,EAAQ,QACN,eAAKT,CAAM,gBAAM/B,EAAM,KAAK6B,CAAU,CAAC,IAAI7B,EAAM,KAAK8B,CAAQ,CAAC,EACjE,CAIF,MAAgB,CACdU,EAAQ,KAAK,GAAGT,CAAM,0BAAM,EAM5B,QAAQ,KAAK,CAAC,CAChB,CACF,CACF,IC5wBA,IAAA+B,GAAA,GAAAC,GAAAD,GAAA,4BAAAE,KAOA,MAAkB,QAClB,OAAOC,OAAS,MARhB,IAaaD,GAbbE,GAAAC,EAAA,kBAKAC,KAQaJ,GAAN,cAAqCK,EAAmB,CAb/D,MAa+D,CAAAC,EAAA,+BACpD,KAAO,WACP,YAAc,gCAEd,YAA4B,CACnC,CACE,KAAM,OACN,YAAa,4CACb,QAASA,EAAA,MAAOC,EAAaC,IAAiB,CAC5C,MAAM,KAAK,WAAW,CACxB,EAFS,UAGX,EACA,CACE,KAAM,MACN,YAAa,4CACb,QAASF,EAAA,MAAOC,EAAaC,IAAiB,CAC5C,KAAK,aAAaD,EAAM,CAAC,EACzB,MAAM,KAAK,UAAUA,EAAK,CAAC,CAAC,CAC9B,EAHS,UAIX,EACA,CACE,KAAM,SACN,YAAa,kDACb,QAASD,EAAA,MAAOC,EAAaC,IAAiB,CAC5C,KAAK,aAAaD,EAAM,CAAC,EACzB,MAAM,KAAK,aAAaA,EAAK,CAAC,CAAC,CACjC,EAHS,UAIX,EACA,CACE,KAAM,MACN,YAAa,4FACb,QAASD,EAAA,MAAOC,EAAaC,IAAiB,CAC5C,KAAK,aAAaD,EAAM,CAAC,EACzB,MAAM,KAAK,UAAUA,CAAI,CAC3B,EAHS,UAIX,CACF,EAEA,YAAYE,EAAyB,CACnC,MAAMA,CAAS,CACjB,CAKA,MAAM,QAAQF,EAAaC,EAA6B,CAExD,CAKA,MAAgB,YAA4B,CAC1C,IAAME,EAAUT,GAAI,yCAAW,EAAE,MAAM,EAEvC,GAAI,CAEF,IAAMU,EADgB,KAAK,WAAgB,eAAe,EAC1B,gBAAgB,EAChDD,EAAQ,QAAQ,0BAAM,EAElBC,EAAU,SAAW,GAIvBA,EAAU,QAAQ,CAACC,EAAYC,IAAkB,CAEjD,CAAC,CAEL,OAASC,EAAO,CACdJ,EAAQ,KACN,yCAAWI,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACnE,EACA,KAAK,YAAYA,CAAc,CACjC,CACF,CAKA,MAAgB,UAAUC,EAA4B,CACpD,IAAML,EAAUT,GAAI,6BAAS,EAAE,MAAM,EAErC,GAAI,CACF,IAAMe,EAAgB,KAAK,WAAgB,eAAe,EAC1DA,EAAc,eAAeD,CAAG,EAChCL,EAAQ,QAAQ,yCAAWK,CAAG,EAAE,EAEhC,IAAMJ,EAAYK,EAAc,gBAAgB,CAElD,OAASF,EAAO,CACdJ,EAAQ,KACN,yCAAWI,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACnE,EACA,KAAK,YAAYA,CAAc,CACjC,CACF,CAKA,MAAgB,aAAaC,EAA4B,CACvD,IAAML,EAAUT,GAAI,6BAAS,EAAE,MAAM,EAErC,GAAI,CACF,IAAMe,EAAgB,KAAK,WAAgB,eAAe,EAC1DA,EAAc,kBAAkBD,CAAG,EACnCL,EAAQ,QAAQ,yCAAWK,CAAG,EAAE,EAEhC,IAAMJ,EAAYK,EAAc,gBAAgB,CAElD,OAASF,EAAO,CACdJ,EAAQ,KACN,yCAAWI,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACnE,EACA,KAAK,YAAYA,CAAc,CACjC,CACF,CAKA,MAAgB,UAAUG,EAA+B,CACvD,IAAMP,EAAUT,GAAI,6BAAS,EAAE,MAAM,EAErC,GAAI,CACF,IAAMe,EAAgB,KAAK,WAAgB,eAAe,EAE1D,GAAIC,EAAK,SAAW,EAClBD,EAAc,kBAAkBC,EAAK,CAAC,CAAC,EACvCP,EAAQ,QAAQ,yCAAWO,EAAK,CAAC,CAAC,EAAE,MAC/B,CACLD,EAAc,kBAAkBC,CAAI,EACpCP,EAAQ,QAAQ,4BAAQO,EAAK,MAAM,qBAAM,EACzC,OAAW,CAACJ,EAAOE,CAAG,IAAKE,EAAK,QAAQ,EAAG,CAG7C,CACF,OAASH,EAAO,CACdJ,EAAQ,KACN,yCAAWI,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CAAC,EACnE,EACA,KAAK,YAAYA,CAAc,CACjC,CACF,CACF,ICvJAI,KCOO,IAAMC,GAAN,KAA8D,CACnE,YAAoBC,EAAyB,CAAzB,eAAAA,CAA0B,CAdhD,MAaqE,CAAAC,EAAA,8BAMnE,gBAAmC,CACjC,MAAO,CACL,KAAK,cAAc,SAAS,EAC5B,KAAK,cAAc,QAAQ,EAC3B,KAAK,cAAc,SAAS,EAC5B,KAAK,cAAc,KAAK,EACxB,KAAK,cAAc,UAAU,CAC/B,CACF,CAKA,cAAcC,EAA8B,CAC1C,OAAQA,EAAM,CACZ,IAAK,UACH,OAAO,KAAK,4BAA4B,EAC1C,IAAK,SACH,OAAO,KAAK,2BAA2B,EACzC,IAAK,UACH,OAAO,KAAK,4BAA4B,EAC1C,IAAK,MACH,OAAO,KAAK,wBAAwB,EACtC,IAAK,WACH,OAAO,KAAK,6BAA6B,EAC3C,QACE,MAAM,IAAI,MAAM,iEAAeA,CAAI,EAAE,CACzC,CACF,CAKQ,6BAA8C,CAEpD,GAAM,CACJ,sBAAAC,CACF,EAAI,cACJ,OAAO,IAAIA,EAAsB,KAAK,SAAS,CACjD,CAKQ,4BAA6C,CACnD,GAAM,CACJ,qBAAAC,CACF,EAAI,cACJ,OAAO,IAAIA,EAAqB,KAAK,SAAS,CAChD,CAKQ,6BAA8C,CACpD,GAAM,CACJ,sBAAAC,CACF,EAAI,cACJ,OAAO,IAAIA,EAAsB,KAAK,SAAS,CACjD,CAKQ,yBAA0C,CAChD,GAAM,CAAE,kBAAAC,CAAkB,EAAI,cAC9B,OAAO,IAAIA,EAAkB,KAAK,SAAS,CAC7C,CAKQ,8BAA+C,CACrD,GAAM,CACJ,uBAAAC,CACF,EAAI,cACJ,OAAO,IAAIA,EAAuB,KAAK,SAAS,CAClD,CACF,EC5FAC,KAYO,IAAMC,GAAN,KAAkD,CAIvD,YAAoBC,EAAyB,CAAzB,eAAAA,EAClB,KAAK,eAAiB,IAAIC,GAAsBD,CAAS,CAC3D,CAvBF,MAiByD,CAAAE,EAAA,wBAC/C,SAA6B,CAAC,EAC9B,eASR,MAAM,iBAAiBC,EAAiC,CACtD,GAAI,CAEF,KAAK,uBAAuBA,CAAO,EACnC,KAAK,oBAAoBA,CAAO,EAGhC,IAAMC,EAAW,KAAK,eAAe,eAAe,EACpD,QAAWC,KAAWD,EACpB,KAAK,gBAAgBC,CAAO,EAC5B,KAAK,gBAAgBF,EAASE,CAAO,EAIvC,KAAK,8BAA8BF,EAASC,CAAQ,CACtD,OAASE,EAAO,CACdC,GAAa,OAAOD,CAAc,CACpC,CACF,CAKA,gBAAgBD,EAA+B,CAC7C,KAAK,SAAS,KAAKA,CAAO,CAC5B,CAKA,gBAAgBF,EAAkBE,EAA+B,CAE/D,GAAIA,EAAQ,aAAeA,EAAQ,YAAY,OAAS,EAAG,CACzD,IAAMG,EAAeL,EAClB,QAAQE,EAAQ,IAAI,EACpB,YAAYA,EAAQ,WAAW,EAElC,QAAWI,KAAcJ,EAAQ,YAAa,CAC5C,IAAIK,EAAiBD,EAAW,KAG5BA,EAAW,OAAS,MACtBC,EAAiB,YACRD,EAAW,OAAS,MAC7BC,EAAiB,oBACRD,EAAW,OAAS,SAC7BC,EAAiB,iCAGnB,IAAMC,EAAMH,EACT,QAAQE,CAAc,EACtB,YAAYD,EAAW,WAAW,EAGrC,GAAIA,EAAW,QACb,QAAWG,KAAUH,EAAW,QAC9BE,EAAI,OAAOC,EAAO,MAAOA,EAAO,YAAaA,EAAO,YAAY,EAKpED,EAAI,OAAO,SAAUE,IAAS,CAC5B,GAAI,CAGF,IAAMC,EADUD,EAAKA,EAAK,OAAS,CAAC,EACZ,KAAK,EAC7B,MAAMJ,EAAW,QAAQI,EAAK,MAAM,EAAG,EAAE,EAAGC,CAAO,CACrD,OAASR,EAAO,CACdC,GAAa,OAAOD,CAAc,CACpC,CACF,CAAC,CACH,CAGAE,EAAa,OAAO,SAAUK,IAAS,CACrC,GAAI,CAEF,IAAMC,EADUD,EAAKA,EAAK,OAAS,CAAC,EACZ,KAAK,EAC7B,MAAMR,EAAQ,QAAQQ,EAAK,MAAM,EAAG,EAAE,EAAGC,CAAO,CAClD,OAASR,EAAO,CACdC,GAAa,OAAOD,CAAc,CACpC,CACF,CAAC,CACH,KAAO,CAEL,IAAIS,EAAcV,EAAQ,KAGtBA,EAAQ,OAAS,WACnBU,EAAc,wBAGhB,IAAMC,EAAUb,EACb,QAAQY,CAAW,EACnB,YAAYV,EAAQ,WAAW,EAGlC,GAAIA,EAAQ,QACV,QAAWO,KAAUP,EAAQ,QAC3BW,EAAQ,OAAOJ,EAAO,MAAOA,EAAO,YAAaA,EAAO,YAAY,EAKxEI,EAAQ,OAAO,SAAUH,IAAS,CAChC,GAAI,CAEF,IAAMC,EADUD,EAAKA,EAAK,OAAS,CAAC,EACZ,KAAK,EAC7B,MAAMR,EAAQ,QAAQQ,EAAK,MAAM,EAAG,EAAE,EAAGC,CAAO,CAClD,OAASR,EAAO,CACdC,GAAa,OAAOD,CAAc,CACpC,CACF,CAAC,CACH,CACF,CAKQ,uBAAuBH,EAAwB,CACrD,IAAMc,EAAe,KAAK,UAAU,IAAI,cAAc,EAEtDd,EAAQ,QAAQc,EAAa,WAAW,EAAG,gBAAiB,sCAAQ,EAGpEd,EAAQ,OAAO,SAAU,sCAAQ,EAGjCA,EAAQ,OAAO,iBAAkB,kDAAU,CAC7C,CAKQ,oBAAoBA,EAAwB,CAClDA,EAAQ,WAAW,aAAc,sCAAQ,EAAE,YACzC,QACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAeF,CACF,CAKQ,8BACNA,EACAC,EACM,CAEN,IAAMc,EAAiBd,EAAS,KAAMe,GAAMA,EAAE,OAAS,SAAS,EAChE,GAAI,GAACD,GAAkB,CAACA,EAAe,aAKvC,QAAWT,KAAcS,EAAe,YAAa,CACnD,IAAMF,EAAUb,EACb,QAAQM,EAAW,IAAI,EACvB,YAAYA,EAAW,WAAW,EAGrC,GAAIA,EAAW,QACb,QAAWG,KAAUH,EAAW,QAC9BO,EAAQ,OAAOJ,EAAO,MAAOA,EAAO,YAAaA,EAAO,YAAY,EAKxEI,EAAQ,OAAO,SAAUH,IAAS,CAChC,GAAI,CAGF,IAAMC,EADUD,EAAKA,EAAK,OAAS,CAAC,EACZ,KAAK,EAC7B,MAAMJ,EAAW,QAAQI,EAAK,MAAM,EAAG,EAAE,EAAGC,CAAO,CACrD,OAASR,EAAO,CACdC,GAAa,OAAOD,CAAc,CACpC,CACF,CAAC,CACH,CACF,CAiIF,EFtVA,MAAkB,QAClB,OAAS,WAAAc,OAAe,YAExB,IAAMC,GAAU,IAAIC,GA6BpB,SAASC,GAAiBC,EAAsB,CAC9C,IAAMC,EAAeD,EAAU,IAAI,cAAc,EAC3CE,EAAgBF,EAAU,IAAI,eAAe,EAE7CG,EAAcF,EAAa,eAAe,EAC1CG,EAAaF,EAAc,cAAc,EAO3CC,EAAY,YAOZC,EAAW,YAKf,IAAMC,EAAgBL,EAAU,IAAI,eAAe,EACnD,GAAIK,EAAc,aAAa,EAAG,CAChC,IAAMC,EAAaD,EAAc,cAAc,EAG/C,GAAI,CACF,IAAME,EAAYF,EAAc,gBAAgB,CAElD,MAAgB,CAEhB,CACF,CAGF,CAtCSG,EAAAT,GAAA,oBA2CT,eAAeU,IAAsB,CACnC,GAAI,CAEF,GAAI,QAAQ,KAAK,SAAS,QAAQ,EAAG,CACnC,IAAMT,EAAY,MAAMU,GAAgB,EACxCX,GAAiBC,CAAS,EAC1B,QAAQ,KAAK,CAAC,CAChB,CAGA,GAAI,QAAQ,KAAK,SAAS,gBAAgB,EAAG,CAC3C,IAAMA,EAAY,MAAMU,GAAgB,EAClCT,EAAeD,EAAU,IAAI,cAAc,EAC3CE,EAAgBF,EAAU,IAAI,eAAe,EAE7CG,EAAcF,EAAa,eAAe,EAC1CG,EAAaF,EAAc,cAAc,EAG3CC,EAAY,YAKZC,EAAW,YAGf,QAAQ,KAAK,CAAC,CAChB,CAGA,IAAMJ,EAAY,MAAMU,GAAgB,EAGlCC,EAAkB,IAAIC,GAAgBZ,CAAS,EAGrDa,GACG,KAAK,SAAS,EACd,YAAY,oGAA6C,EAG5D,MAAMF,EAAgB,iBAAiBE,EAAO,EAG9CA,GAAQ,WAAW,aAAc,sCAAQ,EAAE,YACzC,QACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAgBF,EAGI,QAAQ,KAAK,QAAU,GAEzB,QAAQ,KAAK,CAAC,EAIhB,MAAMA,GAAQ,WAAW,QAAQ,IAAI,CACvC,MAAgB,CAKd,QAAQ,KAAK,CAAC,CAChB,CACF,CAhFeL,EAAAC,GAAA,QAmFfA,GAAK,EAAE,MAAOK,GAAU,CAKtB,QAAQ,KAAK,CAAC,CAChB,CAAC","names":["fs","path","chalk","pino","z","formatDateTime","date","year","month","day","hours","minutes","seconds","getLogger","globalLogger","Logger","globalLogLevel","setGlobalLogLevel","level","LogLevelSchema","logger","init_Logger","__esmMin","__name","normalizedLevel","result","streams","consoleStream","_label","number","err","levelMap","chunk","logObj","message","content","timestamp","levelInfo","text","coloredLevel","argsStr","arg","projectDir","enable","messageOrObj","args","errorArgs","enhancedObj","obj","enhanced","key","value","logDir","logName","i","oldFile","newFile","firstRotatedFile","maxSize","maxFiles","EventEmitter","getEventBus","eventBusInstance","EventBus","destroyEventBus","init_EventBus","__esmMin","init_Logger","__name","logger","error","eventName","listenerCount","data","listener","onceListener","stats","stat","sum","count","TypeFieldNormalizer","init_TypeFieldNormalizer","__esmMin","normalizeTypeField","config","normalizedConfig","originalType","normalizedType","convertToKebabCase","__name","str","getMcpServerCommunicationType","serverConfig","validateMcpServerConfig","serverName","communicationType","config","error","sliceEndpoint","endpoint","init_mcpServerUtils","__esmMin","__name","copyFileSync","existsSync","readFileSync","writeFileSync","dirname","resolve","fileURLToPath","commentJson","dayjs","JSON5","json5Writer","__dirname","DEFAULT_CONNECTION_CONFIG","ConfigManager","configManager","init_manager","__esmMin","init_EventBus","init_TypeFieldNormalizer","init_mcpServerUtils","_ConfigManager","__name","getEventBus","possiblePaths","path","configDir","configFileNames","fileName","filePath","format","targetFileName","configPath","error","configFileFormat","configData","config","configObj","endpoint","serverName","serverConfig","normalizedConfig","TypeFieldNormalizer","validation","validateMcpServerConfig","toolName","ep","currentEndpoints","newEndpoints","relatedTools","tool","toolIndex","t","newConfig","currentServers","name","toolsConfig","platformName","platformConfig","validServerNames","invalidServerNames","enabled","description","configContent","connectionConfig","arg1","arg2","arg3","callTime","incrementUsageCount","serviceName","interval","timeout","modelScopeConfig","apiKey","customMCPConfig","tools","handler","existingNames","newTools","updatedTool","webServer","webUIConfig","port","cozeConfig","toolConfig","currentUsageCount","currentLastUsedTime","logPrefix","customTools","updatedTools","toolKey","updatePromise","lockCount","toolCallLogConfig","SERVICE_CONSTANTS","CONFIG_CONSTANTS","PATH_CONSTANTS","ERROR_CODES","TIMEOUT_CONSTANTS","PAGINATION_CONSTANTS","init_Constants","__esmMin","ERROR_HELP_MESSAGES","COMMON_SOLUTIONS","ERROR_MESSAGES","init_ErrorMessages","__esmMin","init_Constants","ERROR_CODES","__name","errorCode","problemKey","error","context","CLIError","ConfigError","ServiceError","ValidationError","FileError","ProcessError","init_errors","__esmMin","init_Constants","_CLIError","message","code","exitCode","suggestions","__name","_ConfigError","ERROR_CODES","format","_ServiceError","pid","reason","_ValidationError","field","port","_FileError","filePath","fullMessage","_ProcessError","ErrorHandler","init_ErrorHandlers","__esmMin","init_ErrorMessages","init_errors","_ErrorHandler","__name","error","CLIError","suggestion","helpMessage","ERROR_MESSAGES","operation","context","message","suggestions","fs","path","FileUtils","init_FileUtils","__esmMin","init_errors","_FileUtils","__name","filePath","dirPath","FileError","encoding","error","content","options","dir","srcPath","destPath","destDir","srcDir","items","item","stats","result","itemPath","subItems","prefix","suffix","tempDir","timestamp","random","fileName","mode","basePath","FormatUtils","init_FormatUtils","__esmMin","__name","ms","seconds","minutes","hours","days","bytes","units","size","unitIndex","timestamp","format","date","pid","port","protocol","host","path","url","key","value","error","includeStack","message","items","bullet","item","data","keys","maxWidths","row","header","i","separator","width","rows","current","total","percentage","filled","empty","bar","percent","command","args","quotedArgs","arg","text","maxLength","suffix","obj","indent","trueText","falseText","realpathSync","tmpdir","path","fileURLToPath","PathUtils","init_PathUtils","__esmMin","init_Constants","init_FileUtils","_PathUtils","__name","configDir","CONFIG_CONSTANTS","SERVICE_CONSTANTS","projectDir","baseDir","PATH_CONSTANTS","__filename","scriptDir","possiblePaths","templatesDir","FileUtils","templateName","templatePath","projectRoot","filePath","format","fileName","inputPath","resolvedPath","resolvedBase","name","cliPath","realCliPath","distDir","segments","joinedPath","normalizedPath","execSync","PlatformUtils","init_PlatformUtils","__esmMin","init_Constants","init_errors","_PlatformUtils","__name","pid","cmdline","TIMEOUT_CONSTANTS","signal","attempts","maxAttempts","resolve","error","ProcessError","name","defaultValue","value","filePath","Validation","init_Validation","__esmMin","init_errors","_Validation","__name","port","ValidationError","format","validFormats","value","fieldName","options","url","parsedUrl","name","invalidChars","hasControlChars","char","jsonString","error","array","obj","requiredProps","prop","validValues","pattern","fs","path","fileURLToPath","VersionUtils","init_VersionUtils","__esmMin","init_errors","_VersionUtils","__name","__filename","currentDir","possiblePaths","packagePath","packageJson","FileError","version1","version2","v1Parts","v2Parts","maxLength","v1Part","v2Part","version","ProcessManager_exports","__export","ProcessManagerImpl","init_ProcessManager","__esmMin","init_errors","init_FileUtils","init_FormatUtils","init_PathUtils","init_PlatformUtils","__name","PathUtils","pidFilePath","FileUtils","pidContent","pidStr","startTimeStr","mode","pid","startTime","pidInfo","FileError","PlatformUtils","uptime","FormatUtils","error","ProcessError","attempts","maxAttempts","resolve","exists","isXiaozhi","DaemonManager_exports","__export","DaemonManagerImpl","spawn","fs","init_DaemonManager","__esmMin","init_errors","init_PathUtils","init_PlatformUtils","processManager","logger","__name","serverFactory","options","status","ServiceError","child","error","resolve","logFileName","logFilePath","PathUtils","command","args","PlatformUtils","tail","env","ProcessError","logDir","logStream","timestamp","code","signal","processInfo","isValidToolJSONSchema","obj","ensureToolJSONSchema","schema","MCPTransportType","ToolCallError","init_types","__esmMin","__name","code","message","data","inferTransportTypeFromUrl","url","options","pathname","inferTransportTypeFromConfig","config","TypeFieldNormalizer","inferredType","validateToolCallParams","params","opts","ToolCallError","paramsObj","argsObj","error","init_utils","__esmMin","init_TypeFieldNormalizer","init_types","__name","isAbsolute","resolve","convertLegacyToNew","serviceName","legacyConfig","ConfigValidationError","normalizedConfig","TypeFieldNormalizer","newConfig","convertByConfigType","validateNewConfig","error","isLocalConfig","convertLocalConfig","convertSSEConfig","convertStreamableHTTPConfig","inferTransportTypeFromUrl","sseConfig","httpConfig","config","workingDir","resolvedArgs","arg","isRelativePath","inferredType","isModelScope","isModelScopeURL","baseConfig","url","path","MCPTransportType","init_adapter","__esmMin","init_types","init_utils","init_TypeFieldNormalizer","message","configName","__name","WebSocket","EndpointConnection","init_connection","__esmMin","init_types","init_utils","init_mcpServerUtils","__name","endpointUrl","reconnectDelay","serviceManager","toolInfo","ensureToolJSONSchema","resolve","reject","error","data","message","code","reason","toolsList","id","result","response","availableTools","request","ToolCallError","requestId","startTime","params","validateToolCallParams","toolName","arguments_","timeoutMs","timeoutId","errorMessage","duration","errorResponse","EventEmitter","z","DEFAULT_OPTIONS","IndependentConnectionOptionsSchema","EndpointManager","init_manager","__esmMin","init_types","init_EventBus","init_mcpServerUtils","init_connection","__name","configManager","options","getEventBus","endpoints","tools","endpoint","error","connectionPromises","endpointConnection","result","disconnectPromises","sliceEndpoint","connectionEndpoints","stateEndpoints","status","manager","connected","operation","success","message","source","reconnectPromises","results","promise","successCount","r","failureCount","failures","f","ms","resolve","valid","invalid","err","newEndpoints","validEndpoints","invalidEndpoints","currentEndpoints","toAdd","ep","toRemove","toKeep","changeEvent","newOptions","errors","oldOptions","config","prewarmPromises","connection","EndpointConnection","tool","ensureToolJSONSchema","init_endpoint","__esmMin","init_connection","init_manager","config_default","init_config","__esmMin","createCozeClient","token","language","env","config_default","init_client","__esmMin","init_coze","init_config","__name","NodeCache","CozeApiService","init_service","__esmMin","init_client","__name","token","createCozeClient","cacheKey","cached","workspaces","params","workspace_id","page_num","page_size","result","workflowId","parameters","pattern","keysToDelete","key","stats","keys","totalRequests","hitRate","coze_exports","__export","CozeApiService","config_default","createCozeClient","api_star","init_coze","__esmMin","init_config","__reExport","init_client","init_service","createHash","generateCacheKey","toolName","arguments_","argsHash","isCacheExpired","timestamp","ttl","cachedTime","shouldCleanupCache","cache","now","DEFAULT_CONFIG","init_mcp","__esmMin","__name","createTimeoutResponse","taskId","toolName","getToolSpecificTimeoutMessage","getDefaultTimeoutMessage","toolMessages","TimeoutError","init_timeout","__esmMin","_TimeoutError","__name","message","isProxyHandler","handler","CustomMCPHandler","init_custom","__esmMin","init_manager","init_coze","init_mcp","init_types","init_Logger","init_EventBus","init_timeout","__name","DEFAULT_CONFIG","cacheManager","mcpServiceManager","logger","MCPCacheManager","token","configManager","CozeApiService","getEventBus","data","error","tools","customTools","tool","platformInfo","ensureToolJSONSchema","toolName","arguments_","options","completedResult","timeout","result","TimeoutError","taskId","createTimeoutResponse","_","reject","cacheKey","cache","cached","isCacheExpired","workflowData","responseData","config","cozeApiService","workflowResult","shouldCleanupCache","generateCacheKey","cacheData","fs","path","pino","ToolCallLogger","ToolCallLogService","init_log","__esmMin","init_PathUtils","__name","config","configDir","baseDir","PathUtils","logFilePath","streams","chunk","logObj","message","_label","number","toolName","success","duration","lines","line","recordsToRemove","linesToKeep","newContent","record","records","a","b","query","filtered","startTime","endTime","recordTime","total","limit","offset","paginated","hasMore","MCPMessageHandler","init_message","__esmMin","init_mcp","init_Logger","__name","serviceManager","logger","message","isNotification","error","params","id","supportedVersions","clientVersion","responseVersion","tool","validatedParams","validateToolCallParams","result","resources","prompts","errorCode","init_TransportAdapter","__esmMin","init_StdioAdapter","__esmMin","init_TransportAdapter","WebSocket","WebSocketServer","init_WebSocketAdapter","__esmMin","init_TransportAdapter","init_transports","__esmMin","init_TransportAdapter","init_StdioAdapter","init_WebSocketAdapter","EventEmitter","MCPServiceManager","init_manager","__esmMin","init_adapter","init_mcp","init_EventBus","init_custom","init_log","init_message","init_transports","__name","getEventBus","configs","cachePath","MCPCacheManager","CustomMCPHandler","toolCallLogConfig","configManager","configDir","ToolCallLogger","MCPMessageHandler","data","configEntries","startPromises","serviceName","error","results","successCount","failureCount","failedServices","result","config","service","MCPService","tools","tool","toolKey","allTools","serviceTools","customTools","customTool","toolName","toolInfo","arguments_","options","startTime","logServerName","originalToolName","isSuccess","currentTime","action","activeLocks","name","connectedServices","isModelScopeURL","originalConfig","enhancedConfig","modelScopeApiKey","serviceUrl","nameOrConfig","finalConfig","currentServerConfigs","currentToolsConfig","newToolsConfig","currentToolConfig","currentToolNames","t","removedTools","addedTools","updatedTools","current","updated","currentConfig","newConfig","currentKeys","newKeys","key","currentTool","newTool","initialDelay","delay","existingTimer","timer","currentDelay","nextDelay","acc","char","adapter","successfulAdapters","failedAdapters","errorMessage","connections","adapterName","conn","serviceStatus","customMCPToolCount","customToolNames","totalTools","availableTools","status","message","response","SSEClientTransport","StdioClientTransport","StreamableHTTPClientTransport","EventSource","createTransport","config","createStdioTransport","createSSETransport","createStreamableHTTPTransport","url","options","createSSEOptions","createStreamableHTTPOptions","validateConfig","MCPTransportType","getSupportedTypes","TransportFactory","init_transport_factory","__esmMin","init_types","__name","Client","MCPService","init_connection","__esmMin","init_EventBus","init_transport_factory","init_types","init_utils","__name","getEventBus","config","inferTransportTypeFromConfig","TransportFactory","resolve","reject","error","tools","tool","name","arguments_","init_coze","__esmMin","Hono","createApp","init_hono_context","__esmMin","__name","init_types","__esmMin","init_mcp","init_coze","init_timeout","init_hono_context","createHash","existsSync","mkdirSync","readFileSync","renameSync","writeFileSync","dirname","resolve","dayjs","MCPCacheManager","init_cache","__esmMin","init_Logger","init_types","__name","customCachePath","logger","configDir","cacheDir","initialCache","error","now","serverName","tools","config","cache","configHash","cacheEntry","tool","cacheData","cacheContent","filePath","data","tempPath","cacheObj","metadata","allTools","toolName","arguments_","result","status","taskId","ttl","cacheKey","generateCacheKey","cachedTime","newStatus","oldStatus","entries","cleanedCount","shouldCleanupCache","totalEntries","pendingTasks","e","completedTasks","failedTasks","consumedEntries","cacheHitRate","memoryUsage","init_mcp","__esmMin","init_manager","init_connection","init_types","init_utils","init_transport_factory","init_message","init_cache","init_custom","init_log","init_transports","loggerMiddleware","init_logger_middleware","__esmMin","init_Logger","__name","c","next","logger","cors","corsMiddleware","init_cors_middleware","__esmMin","origin","createErrorResponse","createSuccessResponse","errorHandlerMiddleware","notFoundHandlerMiddleware","init_error_middleware","__esmMin","init_Logger","__name","code","message","details","data","err","c","loggerInstance","contextLogger","logger","errorResponse","MCPServiceManagerNotInitializedError","WebServerNotAvailableError","init_MCPErrors_middleware","__esmMin","__name","message","mcpServiceManagerMiddleware","init_mcpServiceManager_middleware","__esmMin","init_Logger","init_MCPErrors_middleware","__name","c","next","contextLogger","logger","webServer","WebServerNotAvailableError","serviceManager","error","errorLogger","MCPServiceManagerNotInitializedError","endpointManagerMiddleware","init_endpointManager_middleware","__esmMin","__name","c","next","webServer","connectionManager","error","MCPEndpointApiHandler","init_MCPEndpointApiHandler","__esmMin","init_Logger","init_EventBus","__name","endpointManager","configManager","logger","getEventBus","code","message","endpoint","details","data","c","errorErrorCode","body","error","errorResponse","parseResult","endpointStatus","status","existingStatus","response","fallbackStatus","errorCode","httpStatus","endpointsMiddleware","init_endpoints_middleware","__esmMin","init_manager","init_MCPEndpointApiHandler","__name","endpointHandler","lastManager","c","next","endpointManager","MCPEndpointApiHandler","configManager","init_middlewares","__esmMin","init_logger_middleware","init_cors_middleware","init_error_middleware","init_mcpServiceManager_middleware","init_endpointManager_middleware","init_endpoints_middleware","init_hono_context","AbstractApiHandler","init_AbstractApiHandler","__esmMin","__name","c","logger","ConfigApiHandler","init_ConfigApiHandler","__esmMin","init_manager","init_middlewares","init_AbstractApiHandler","AbstractApiHandler","__name","c","logger","config","configManager","createSuccessResponse","error","errorResponse","createErrorResponse","newConfig","serverName","toolsConfig","toolName","toolConfig","endpoint","endpoints","servers","connection","path","exists","isErrorWithCode","error","code","createSuccessResponse","data","message","createErrorResponse","details","getCozeApiService","token","configManager","CozeApiService","CozeApiHandler","init_CozeApiHandler","__esmMin","init_manager","init_coze","init_Logger","__name","c","logger","cozeApiService","workspaces","workspace_id","page_num","page_size","params","result","customMCPTools","enhancedItems","item","addedTool","tool","pattern","statsBefore","statsAfter","stats","HeartbeatHandler","init_HeartbeatHandler","__esmMin","init_manager","init_Logger","__name","statusService","notificationService","logger","ws","message","clientId","statusUpdate","error","configManager","code","errorResponse","lastHeartbeat","now","intervalId","response","randomUUID","MCPRouteHandler","init_MCPRouteHandler","__esmMin","init_message","init_Logger","__name","config","logger","now","staleClients","sessionId","client","c","serviceManager","webServer","mcpServiceManager","MCPMessageHandler","error","startTime","messageId","contentLength","protocolVersion","supportedVersions","message","rawBody","response","responseTime","errorMessage","writeError","clientId","userAgent","remoteAddress","readable","writable","writer","abortController","handleDisconnect","event","data","eventData","reason","connectionDuration","msg","code","id","responseId","errorResponse","clients","deadClients","MCPError","DefaultErrorHandler","ConfigErrorHandler","ConnectionErrorHandler","ErrorHandlerRegistry","globalErrorHandler","init_MCPErrors","__esmMin","_MCPError","__name","code","message","severity","category","details","error","defaultCode","context","handler","result","MCPServerApiHandler","MCPServerConfigValidator","init_MCPServerApiHandler","__esmMin","init_Logger","init_MCPErrors","init_EventBus","init_TypeFieldNormalizer","__name","mcpServiceManager","configManager","logger","code","message","serverName","details","error","operation","context","MCPError","mcpError","data","name","config","c","startTime","requestData","batchRequest","result","duration","singleRequest","successResponse","errorResponse","statusCode","normalizedConfig","TypeFieldNormalizer","nameValidation","validationError","existsError","configValidation","configError","mcpServiceConfig","serviceStatus","tools","getEventBus","tool","serverConfig","service","currentTools","status","newStatus","previousStatus","addedTools","removedTools","handlerWithCache","mcpServers","servers","listResponse","serverNames","results","successfullyAddedServers","validationResult","normalizedServerConfig","addedCount","failedCount","response","errors","rollbackResults","rollbackFailures","validateConfig","validateServiceName","checkServiceExists","RealtimeNotificationHandler","init_RealtimeNotificationHandler","__esmMin","init_manager","init_Logger","init_EventBus","__name","notificationService","statusService","logger","getEventBus","ws","message","clientId","error","config","configManager","configData","serverName","toolsConfig","toolName","toolConfig","status","code","errorResponse","feature","alternative","spawn","ServiceApiHandler","init_ServiceApiHandler","__esmMin","init_Container","init_Logger","init_EventBus","__name","statusService","logger","getEventBus","code","message","details","data","c","error","errorResponse","status","createContainer","isDaemon","restartArgs","health","existsSync","readFile","dirname","join","fileURLToPath","StaticFileHandler","init_StaticFileHandler","__esmMin","init_Logger","__name","logger","__dirname","possibleWebPaths","p","exists","error","c","pathname","filePath","fullPath","indexPath","contentType","content","ext","message","errorHtml","StatusApiHandler","init_StatusApiHandler","__esmMin","init_Logger","__name","statusService","logger","code","message","details","data","c","status","error","errorResponse","clientStatus","restartStatus","connected","lastHeartbeat","servers","statusUpdate","ToolType","init_toolApi","__esmMin","Ajv","dayjs","ToolApiHandler","init_ToolApiHandler","__esmMin","init_manager","init_mcp","init_Logger","init_toolApi","__name","logger","data","message","code","c","statusCode","requestBody","serviceName","toolName","args","errorResponse","serviceManager","result","toolKey","error","errorMessage","errorCode","configManager","customTools","configPath","status","tools","responseData","enabledTools","enabledToolNames","tool","allCachedTools","MCPCacheManager","config","configuredServers","disabledTools","cachedTool","customTool","availableTools","targetTool","validate","path","expectedType","allowedValues","body","request","type","ToolType","httpErrorResponse","defaultErrorResponse","workflow","customName","customDescription","parameterConfig","preCheckResult","cachedTools","fullToolName","finalToolName","existingTools","serverToolsConfig","existingTool","updatedInputSchema","updatedTool","toolToDelete","mcpConfig","baseName","description","inputSchema","handler","name","sanitized","text","chineseToEnglishMap","chinese","english","requiredFields","field","value","lengthLimits","max","sensitiveWords","lowerName","word","existingNames","finalName","counter","cozeConfig","auth","validAuthTypes","bodyTemplate","templateVars","templateVar","varName","schema","properties","required","param","keyword","errorMappings","key","basicCheckResult","systemCheckResult","resourceCheckResult","workflowObj","maxTools","configSizeEstimate","maxConfigSize","z","ToolCallQuerySchema","ToolCallLogApiHandler","init_ToolCallLogApiHandler","__esmMin","init_log","init_Constants","init_Logger","val","PAGINATION_CONSTANTS","date","data","__name","ToolCallLogService","response","code","message","details","c","query","result","err","validation","logger","error","require_constants","__commonJSMin","exports","module","SEMVER_SPEC_VERSION","MAX_SAFE_INTEGER","MAX_SAFE_COMPONENT_LENGTH","MAX_SAFE_BUILD_LENGTH","RELEASE_TYPES","require_debug","__commonJSMin","exports","module","debug","args","require_re","__commonJSMin","exports","module","MAX_SAFE_COMPONENT_LENGTH","MAX_SAFE_BUILD_LENGTH","MAX_LENGTH","debug","re","safeRe","src","safeSrc","t","R","LETTERDASHNUMBER","safeRegexReplacements","makeSafeRegex","__name","value","token","max","createToken","name","isGlobal","safe","index","require_parse_options","__commonJSMin","exports","module","looseOption","emptyOpts","parseOptions","__name","options","require_identifiers","__commonJSMin","exports","module","numeric","compareIdentifiers","__name","a","b","anum","bnum","rcompareIdentifiers","require_semver","__commonJSMin","exports","module","debug","MAX_LENGTH","MAX_SAFE_INTEGER","re","t","parseOptions","compareIdentifiers","SemVer","_SemVer","__name","version","options","m","id","num","other","i","a","b","release","identifier","identifierBase","match","base","prerelease","require_parse","__commonJSMin","exports","module","SemVer","parse","__name","version","options","throwErrors","er","require_valid","__commonJSMin","exports","module","parse","valid","__name","version","options","v","require_clean","__commonJSMin","exports","module","parse","clean","__name","version","options","s","require_inc","__commonJSMin","exports","module","SemVer","inc","__name","version","release","options","identifier","identifierBase","require_diff","__commonJSMin","exports","module","parse","diff","__name","version1","version2","v1","v2","comparison","v1Higher","highVersion","lowVersion","highHasPre","prefix","require_major","__commonJSMin","exports","module","SemVer","major","__name","a","loose","require_minor","__commonJSMin","exports","module","SemVer","minor","__name","a","loose","require_patch","__commonJSMin","exports","module","SemVer","patch","__name","a","loose","require_prerelease","__commonJSMin","exports","module","parse","prerelease","__name","version","options","parsed","require_compare","__commonJSMin","exports","module","SemVer","compare","__name","a","b","loose","require_rcompare","__commonJSMin","exports","module","compare","rcompare","__name","a","b","loose","require_compare_loose","__commonJSMin","exports","module","compare","compareLoose","__name","a","b","require_compare_build","__commonJSMin","exports","module","SemVer","compareBuild","__name","a","b","loose","versionA","versionB","require_sort","__commonJSMin","exports","module","compareBuild","sort","__name","list","loose","a","b","require_rsort","__commonJSMin","exports","module","compareBuild","rsort","__name","list","loose","a","b","require_gt","__commonJSMin","exports","module","compare","gt","__name","a","b","loose","require_lt","__commonJSMin","exports","module","compare","lt","__name","a","b","loose","require_eq","__commonJSMin","exports","module","compare","eq","__name","a","b","loose","require_neq","__commonJSMin","exports","module","compare","neq","__name","a","b","loose","require_gte","__commonJSMin","exports","module","compare","gte","__name","a","b","loose","require_lte","__commonJSMin","exports","module","compare","lte","__name","a","b","loose","require_cmp","__commonJSMin","exports","module","eq","neq","gt","gte","lt","lte","cmp","__name","a","op","b","loose","require_coerce","__commonJSMin","exports","module","SemVer","parse","re","t","coerce","__name","version","options","match","coerceRtlRegex","next","major","minor","patch","prerelease","build","require_lrucache","__commonJSMin","exports","module","LRUCache","__name","key","value","firstKey","require_range","__commonJSMin","exports","module","SPACE_CHARACTERS","Range","_Range","__name","range","options","parseOptions","Comparator","c","first","isNullSet","isAny","i","comps","k","memoKey","FLAG_INCLUDE_PRERELEASE","FLAG_LOOSE","cached","cache","loose","hr","re","t","hyphenReplace","debug","comparatorTrimReplace","tildeTrimReplace","caretTrimReplace","rangeList","comp","parseComparator","replaceGTE0","rangeMap","comparators","result","thisComparators","isSatisfiable","rangeComparators","thisComparator","rangeComparator","version","SemVer","testSet","LRU","remainingComparators","testComparator","otherComparator","replaceCarets","replaceTildes","replaceXRanges","replaceStars","isX","id","replaceTilde","r","_","M","m","p","pr","ret","replaceCaret","z","replaceXRange","gtlt","xM","xm","xp","anyX","incPr","$0","from","fM","fm","fp","fpr","fb","to","tM","tm","tp","tpr","set","allowed","require_comparator","__commonJSMin","exports","module","ANY","Comparator","_Comparator","__name","comp","options","parseOptions","debug","r","re","t","m","SemVer","version","cmp","Range","require_satisfies","__commonJSMin","exports","module","Range","satisfies","__name","version","range","options","require_to_comparators","__commonJSMin","exports","module","Range","toComparators","__name","range","options","comp","c","require_max_satisfying","__commonJSMin","exports","module","SemVer","Range","maxSatisfying","__name","versions","range","options","max","maxSV","rangeObj","v","require_min_satisfying","__commonJSMin","exports","module","SemVer","Range","minSatisfying","__name","versions","range","options","min","minSV","rangeObj","v","require_min_version","__commonJSMin","exports","module","SemVer","Range","gt","minVersion","__name","range","loose","minver","i","comparators","setMin","comparator","compver","require_valid","__commonJSMin","exports","module","Range","validRange","__name","range","options","require_outside","__commonJSMin","exports","module","SemVer","Comparator","ANY","Range","satisfies","gt","lt","lte","gte","outside","__name","version","range","hilo","options","gtfn","ltefn","ltfn","comp","ecomp","i","comparators","high","low","comparator","require_gtr","__commonJSMin","exports","module","outside","gtr","__name","version","range","options","require_ltr","__commonJSMin","exports","module","outside","ltr","__name","version","range","options","require_intersects","__commonJSMin","exports","module","Range","intersects","__name","r1","r2","options","require_simplify","__commonJSMin","exports","module","satisfies","compare","versions","range","options","set","first","prev","v","a","b","version","ranges","min","max","simplified","original","require_subset","__commonJSMin","exports","module","Range","Comparator","ANY","satisfies","compare","subset","__name","sub","dom","options","sawNonNull","OUTER","simpleSub","simpleDom","isSub","simpleSubset","minimumVersionWithPreRelease","minimumVersion","eqSet","gt","lt","c","higherGT","lowerLT","gtltComp","eq","higher","lower","hasDomLT","hasDomGT","needDomLTPre","needDomGTPre","a","b","comp","require_semver","__commonJSMin","exports","module","internalRe","constants","SemVer","identifiers","parse","valid","clean","inc","diff","major","minor","patch","prerelease","compare","rcompare","compareLoose","compareBuild","sort","rsort","gt","lt","eq","neq","gte","lte","cmp","coerce","Comparator","Range","satisfies","toComparators","maxSatisfying","minSatisfying","minVersion","validRange","outside","gtr","ltr","intersects","simplifyRange","subset","exec","spawn","promisify","import_semver","execAsync","NPMManager","init_manager","__esmMin","init_EventBus","__name","eventBus","getEventBus","version","installId","startTime","npmProcess","resolve","reject","data","message","code","duration","error","stdout","type","filteredVersions","semver","prerelease","a","b","currentVersion","stableVersions","latestVersion","hasUpdate","init_npm","__esmMin","init_manager","z","UpdateRequestSchema","UpdateApiHandler","init_UpdateApiHandler","__esmMin","init_npm","init_Logger","init_EventBus","__name","logger","getEventBus","NPMManager","c","body","parseResult","err","version","v","error","VersionApiHandler","init_VersionApiHandler","__esmMin","init_npm","init_VersionUtils","init_Logger","__name","logger","code","message","details","data","c","versionInfo","VersionUtils","error","errorResponse","version","type","validTypes","versions","NPMManager","result","init_handlers","__esmMin","init_ConfigApiHandler","init_CozeApiHandler","init_HeartbeatHandler","init_MCPEndpointApiHandler","init_MCPRouteHandler","init_MCPServerApiHandler","init_RealtimeNotificationHandler","init_ServiceApiHandler","init_StaticFileHandler","init_StatusApiHandler","init_ToolApiHandler","init_ToolCallLogApiHandler","init_UpdateApiHandler","init_VersionApiHandler","StatusService","init_StatusService","__esmMin","init_Logger","init_EventBus","__name","logger","getEventBus","info","source","oldStatus","error","status","servers","endpoint","NotificationService","init_NotificationService","__esmMin","init_manager","init_Logger","init_EventBus","__name","logger","getEventBus","data","config","configManager","clientId","ws","client","error","type","message","messageStr","queue","status","timestamp","restartStatus","connectedClients","queuedMessages","total","disconnectedClients","init_ErrorHandler","__esmMin","init_Logger","init_services","__esmMin","init_StatusService","init_NotificationService","init_EventBus","init_ErrorHandler","init_custom","RouteManager","init_RouteManager","__esmMin","init_error_middleware","__name","name","config","routeConfigs","app","routeEntries","nameA","nameB","domainName","route","fullPath","allMiddleware","wrappedHandler","c","next","error","errorResponse","createErrorResponse","handler","configRoutes","init_config_route","__esmMin","__name","c","dependencies","configApiHandler","statusRoutes","init_status_route","__esmMin","__name","c","statusApiHandler","toolsRoutes","init_tools_route","__esmMin","__name","c","toolApiHandler","mcpRoutes","init_mcp_route","__esmMin","__name","c","mcpRouteHandler","versionRoutes","init_version_route","__esmMin","__name","c","versionApiHandler","servicesRoutes","init_services_route","__esmMin","__name","c","serviceApiHandler","updateRoutes","init_update_route","__esmMin","__name","c","updateApiHandler","staticRoutes","init_static_route","__esmMin","__name","c","cozeRoutes","init_coze_route","__esmMin","__name","c","cozeApiHandler","toolLogsRoutes","init_tool_logs_route","__esmMin","__name","c","toolCallLogApiHandler","withMCPServerHandler","mcpserverRoutes","init_mcpserver_route","__esmMin","__name","c","handlerFn","handler","h","createErrorResponse","withEndpointHandler","endpointRoutes","init_endpoint_route","__esmMin","__name","code","message","c","handlerName","endpointHandler","errorResponse","error","miscRoutes","init_misc_route","__esmMin","__name","c","serviceApiHandler","init_domains","__esmMin","init_config_route","init_status_route","init_tools_route","init_mcp_route","init_version_route","init_services_route","init_update_route","init_static_route","init_coze_route","init_tool_logs_route","init_mcpserver_route","init_endpoint_route","init_misc_route","init_routes","__esmMin","init_RouteManager","init_domains","WebServer_exports","__export","WebServer","createServer","serve","WebSocketServer","init_WebServer","__esmMin","init_adapter","init_manager","init_endpoint","init_mcp","init_types","init_handlers","init_middlewares","init_Logger","init_services","init_MCPErrors_middleware","init_routes","__name","port","configManager","logger","getEventBus","StatusService","NotificationService","ConfigApiHandler","StatusApiHandler","ServiceApiHandler","ToolApiHandler","ToolCallLogApiHandler","VersionApiHandler","StaticFileHandler","MCPRouteHandler","UpdateApiHandler","CozeApiHandler","RealtimeNotificationHandler","HeartbeatHandler","createApp","notFoundHandlerMiddleware","MCPServiceManager","config","MCPServerApiHandler","rawTools","tools","tool","ensureToolJSONSchema","error","mcpServers","name","serviceConfig","convertLegacyToNew","mcpEndpoint","validEndpoints","ep","EndpointManager","event","manager","MCPServiceManagerNotInitializedError","status","connectionFn","context","maxAttempts","initialDelay","maxDelay","backoffMultiplier","lastError","attempt","delay","ms","resolve","loggerMiddleware","c","next","mcpServiceManagerMiddleware","endpointManagerMiddleware","endpointsMiddleware","corsMiddleware","errorHandlerMiddleware","dependencies","RouteManager","configRoutes","statusRoutes","toolsRoutes","mcpRoutes","versionRoutes","servicesRoutes","updateRoutes","cozeRoutes","toolLogsRoutes","mcpserverRoutes","endpointRoutes","miscRoutes","staticRoutes","ws","clientId","message","data","errorResponse","eventData","server","resolved","doResolve","client","destroyEventBus","ServiceManager_exports","__export","ServiceManagerImpl","init_ServiceManager","__esmMin","init_errors","init_PathUtils","init_Validation","processManager","configManager","__name","options","status","resolve","error","ServiceError","Validation","ConfigError","port","spawn","scriptPath","PathUtils","child","WebServer","server","cleanup","webServerPath","TemplateManager_exports","__export","TemplateManagerImpl","fs","path","init_TemplateManager","__esmMin","init_errors","init_FileUtils","init_PathUtils","init_Validation","__name","templatesDir","PathUtils","templates","templateDirs","dirent","templateName","templateInfo","FileError","Validation","templatePath","configPath","config","FileUtils","configContent","files","error","ValidationError","targetPath","options","requiredFiles","requiredFile","filePath","file","relativePath","variables","filesToProcess","pattern","basePath","regex","content","hasChanges","key","value","createContainer","DIContainer","init_Container","__esmMin","init_manager","init_ErrorHandlers","init_FileUtils","init_FormatUtils","init_PathUtils","init_PlatformUtils","init_Validation","init_VersionUtils","init_Logger","_DIContainer","__name","key","factory","singleton","instance","factoryKeys","instanceKeys","container","VersionUtils","PlatformUtils","FormatUtils","FileUtils","PathUtils","Validation","configManager","logger","ErrorHandler","ProcessManagerModule","DaemonManagerModule","processManager","ServiceManagerModule","TemplateManagerModule","BaseCommandHandler","init_Command","__esmMin","container","__name","serviceName","error","args","expectedCount","ServiceCommandHandler_exports","__export","ServiceCommandHandler","init_ServiceCommandHandler","__esmMin","init_Command","init_Logger","BaseCommandHandler","__name","args","options","container","setGlobalLogLevel","serviceManager","error","status","ConfigCommandHandler_exports","__export","ConfigCommandHandler","path","ora","init_ConfigCommandHandler","__esmMin","init_Command","BaseCommandHandler","__name","args","options","container","spinner","format","configManager","configDir","configFileName","configPath","error","key","config","endpoints","ep","index","name","serverConfig","server","connectionConfig","value","interval","timeout","ProjectCommandHandler_exports","__export","ProjectCommandHandler","path","chalk","ora","init_ProjectCommandHandler","__esmMin","init_Command","BaseCommandHandler","__name","container","args","options","projectName","spinner","templateManager","fileUtils","targetPath","error","templateName","availableTemplates","actualTemplateName","similarTemplate","templates","template","input","formatUtils","bestMatch","bestSimilarity","similarity","prompt","rl","resolve","answer","isLocalMCPServerConfig","obj","config","arg","init_CommandTypes","__esmMin","__name","McpCommandHandler_exports","__export","McpCommandHandler","chalk","Table","ora","init_McpCommandHandler","__esmMin","init_manager","init_Command","init_CommandTypes","init_ProcessManager","init_Logger","_McpCommandHandler","BaseCommandHandler","__name","args","logger","ProcessManagerImpl","webPort","configManager","str","width","char","maxWidth","result","currentWidth","hasAddedChar","charWidth","argsString","error","options","serverName","toolName","action","enabled","serviceName","response","detail","errorMessage","errorData","detailedMessage","responseData","spinner","mcpServers","serverNames","customMCPTools","hasCustomMCP","totalServices","maxToolNameWidth","allToolNames","toolsConfig","toolNames","customToolNames","tool","table","customTool","description","toolConfig","status","serverConfig","toolCount","enabledCount","t","isLocalMCPServerConfig","EndpointCommandHandler_exports","__export","EndpointCommandHandler","ora","init_EndpointCommandHandler","__esmMin","init_Command","BaseCommandHandler","__name","args","options","container","spinner","endpoints","ep","index","error","url","configManager","urls","init_Container","CommandHandlerFactory","container","__name","type","ServiceCommandHandler","ConfigCommandHandler","ProjectCommandHandler","McpCommandHandler","EndpointCommandHandler","init_ErrorHandlers","CommandRegistry","container","CommandHandlerFactory","__name","program","handlers","handler","error","ErrorHandler","commandGroup","subcommand","subcommandName","cmd","option","args","options","commandName","command","versionUtils","serviceHandler","h","Command","program","Command","showDetailedInfo","container","versionUtils","platformUtils","versionInfo","systemInfo","configManager","configPath","endpoints","__name","main","createContainer","commandRegistry","CommandRegistry","program","error"]}