xiaozhi-client 1.9.4-beta.4 → 1.9.4-beta.8

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 (41) hide show
  1. package/dist/backend/WebServer.js +12 -12
  2. package/dist/backend/WebServer.js.map +1 -1
  3. package/dist/backend/WebServerLauncher.js +11 -11
  4. package/dist/backend/WebServerLauncher.js.map +1 -1
  5. package/dist/backend/managers/MCPServiceManagerSingleton.js +5 -5
  6. package/dist/backend/managers/MCPServiceManagerSingleton.js.map +1 -1
  7. package/dist/backend/package.json +11 -11
  8. package/dist/cli/index.js +13 -4448
  9. package/dist/cli/index.js.map +1 -1
  10. package/dist/config/index.js +2 -0
  11. package/dist/config/index.js.map +1 -0
  12. package/dist/frontend/assets/index-88NfCOo9.js.map +1 -1
  13. package/dist/shared-types/api-aP8BHcbg.d.ts +97 -0
  14. package/dist/shared-types/api.d.ts +202 -0
  15. package/dist/shared-types/api.js +50 -0
  16. package/dist/shared-types/api.js.map +1 -0
  17. package/dist/shared-types/app-oAmColIN.d.ts +91 -0
  18. package/dist/shared-types/chunk-BMOKIX3Q.js +51 -0
  19. package/dist/shared-types/chunk-BMOKIX3Q.js.map +1 -0
  20. package/dist/shared-types/config.d.ts +97 -0
  21. package/dist/shared-types/config.js +1 -0
  22. package/dist/shared-types/config.js.map +1 -0
  23. package/dist/shared-types/coze.d.ts +30 -0
  24. package/dist/shared-types/coze.js +1 -0
  25. package/dist/shared-types/coze.js.map +1 -0
  26. package/dist/shared-types/index.d.ts +186 -0
  27. package/dist/shared-types/index.js +4 -17
  28. package/dist/shared-types/index.js.map +1 -1
  29. package/dist/shared-types/mcp.d.ts +91 -0
  30. package/dist/shared-types/mcp.js +22 -0
  31. package/dist/shared-types/mcp.js.map +1 -0
  32. package/dist/shared-types/message-xoOM7ZuT.d.ts +154 -0
  33. package/dist/shared-types/timeout-CCp_IFHg.d.ts +39 -0
  34. package/dist/shared-types/toolApi-DYSy8ebd.d.ts +208 -0
  35. package/dist/shared-types/utils.d.ts +115 -0
  36. package/dist/shared-types/utils.js +15 -0
  37. package/dist/shared-types/utils.js.map +1 -0
  38. package/dist/shared-types/workflow-DDqq5Jgp.d.ts +83 -0
  39. package/package.json +11 -11
  40. package/dist/backend/lib/config/manager.js +0 -3
  41. package/dist/backend/lib/config/manager.js.map +0 -1
@@ -0,0 +1,208 @@
1
+ import { C as CozeWorkflow, b as WorkflowParameterConfig } from './workflow-DDqq5Jgp.js';
2
+
3
+ /**
4
+ * 工具添加 API 相关类型定义
5
+ * 支持多种工具类型的添加,包括 MCP 工具、Coze 工作流等
6
+ */
7
+
8
+ /**
9
+ * 工具类型枚举
10
+ */
11
+ declare enum ToolType {
12
+ /** MCP 工具(标准 MCP 服务中的工具) */
13
+ MCP = "mcp",
14
+ /** Coze 工作流工具 */
15
+ COZE = "coze",
16
+ /** HTTP API 工具(预留) */
17
+ HTTP = "http",
18
+ /** 自定义函数工具(预留) */
19
+ FUNCTION = "function"
20
+ }
21
+ /**
22
+ * MCP 工具数据
23
+ * 用于将标准 MCP 服务中的工具添加到 customMCP.tools 配置中
24
+ */
25
+ interface MCPToolData {
26
+ /** MCP 服务名称 */
27
+ serviceName: string;
28
+ /** 工具名称 */
29
+ toolName: string;
30
+ /** 可选的自定义名称 */
31
+ customName?: string;
32
+ /** 可选的自定义描述 */
33
+ customDescription?: string;
34
+ }
35
+ /**
36
+ * Coze 工作流数据
37
+ * 保持与现有格式的兼容性
38
+ */
39
+ interface CozeWorkflowData {
40
+ /** Coze 工作流信息 */
41
+ workflow: CozeWorkflow;
42
+ /** 可选的自定义名称 */
43
+ customName?: string;
44
+ /** 可选的自定义描述 */
45
+ customDescription?: string;
46
+ /** 可选的参数配置 */
47
+ parameterConfig?: WorkflowParameterConfig;
48
+ }
49
+ /**
50
+ * HTTP API 工具数据(预留)
51
+ */
52
+ interface HttpApiToolData {
53
+ /** API 地址 */
54
+ url: string;
55
+ /** HTTP 方法 */
56
+ method?: "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
57
+ /** API 描述 */
58
+ description: string;
59
+ /** 请求头 */
60
+ headers?: Record<string, string>;
61
+ /** 请求体模板 */
62
+ bodyTemplate?: string;
63
+ /** 认证配置 */
64
+ auth?: {
65
+ type: "bearer" | "basic" | "api_key";
66
+ token?: string;
67
+ username?: string;
68
+ password?: string;
69
+ apiKey?: string;
70
+ apiKeyHeader?: string;
71
+ };
72
+ /** 可选的自定义名称 */
73
+ customName?: string;
74
+ /** 可选的自定义描述 */
75
+ customDescription?: string;
76
+ }
77
+ /**
78
+ * 函数工具数据(预留)
79
+ */
80
+ interface FunctionToolData {
81
+ /** 模块路径 */
82
+ module: string;
83
+ /** 函数名 */
84
+ function: string;
85
+ /** 函数描述 */
86
+ description: string;
87
+ /** 函数执行上下文 */
88
+ context?: Record<string, any>;
89
+ /** 超时时间 */
90
+ timeout?: number;
91
+ /** 可选的自定义名称 */
92
+ customName?: string;
93
+ /** 可选的自定义描述 */
94
+ customDescription?: string;
95
+ }
96
+ /**
97
+ * 添加自定义工具的统一请求接口
98
+ */
99
+ interface AddCustomToolRequest {
100
+ /** 工具类型 */
101
+ type: ToolType;
102
+ /** 工具数据(根据类型不同而不同) */
103
+ data: MCPToolData | CozeWorkflowData | HttpApiToolData | FunctionToolData;
104
+ }
105
+ /**
106
+ * 工具验证错误类型
107
+ */
108
+ declare enum ToolValidationError {
109
+ /** 无效的工具类型 */
110
+ INVALID_TOOL_TYPE = "INVALID_TOOL_TYPE",
111
+ /** 缺少必需字段 */
112
+ MISSING_REQUIRED_FIELD = "MISSING_REQUIRED_FIELD",
113
+ /** 工具不存在 */
114
+ TOOL_NOT_FOUND = "TOOL_NOT_FOUND",
115
+ /** 服务不存在 */
116
+ SERVICE_NOT_FOUND = "SERVICE_NOT_FOUND",
117
+ /** 工具名称冲突 */
118
+ TOOL_NAME_CONFLICT = "TOOL_NAME_CONFLICT",
119
+ /** 配置验证失败 */
120
+ CONFIG_VALIDATION_FAILED = "CONFIG_VALIDATION_FAILED",
121
+ /** 系统配置错误 */
122
+ SYSTEM_CONFIG_ERROR = "SYSTEM_CONFIG_ERROR",
123
+ /** 资源限制超出 */
124
+ RESOURCE_LIMIT_EXCEEDED = "RESOURCE_LIMIT_EXCEEDED"
125
+ }
126
+ /**
127
+ * 工具验证错误详情
128
+ */
129
+ interface ToolValidationErrorDetail {
130
+ /** 错误类型 */
131
+ error: ToolValidationError;
132
+ /** 错误消息 */
133
+ message: string;
134
+ /** 错误详情 */
135
+ details?: any;
136
+ /** 建议的解决方案 */
137
+ suggestions?: string[];
138
+ }
139
+ /**
140
+ * 添加工具的响应数据
141
+ */
142
+ interface AddToolResponse {
143
+ /** 成功添加的工具 */
144
+ tool: any;
145
+ /** 工具名称 */
146
+ toolName: string;
147
+ /** 工具类型 */
148
+ toolType: ToolType;
149
+ /** 添加时间戳 */
150
+ addedAt: string;
151
+ }
152
+ /**
153
+ * 工具元数据信息
154
+ */
155
+ interface ToolMetadata {
156
+ /** 工具原始来源 */
157
+ source: {
158
+ type: "mcp" | "coze" | "http" | "function";
159
+ serviceName?: string;
160
+ toolName?: string;
161
+ url?: string;
162
+ };
163
+ /** 添加时间 */
164
+ addedAt: string;
165
+ /** 最后更新时间 */
166
+ updatedAt?: string;
167
+ /** 版本信息 */
168
+ version?: string;
169
+ }
170
+ /**
171
+ * 工具配置选项
172
+ */
173
+ interface ToolConfigOptions {
174
+ /** 是否启用工具(默认 true) */
175
+ enabled?: boolean;
176
+ /** 超时时间(毫秒) */
177
+ timeout?: number;
178
+ /** 重试次数 */
179
+ retryCount?: number;
180
+ /** 重试间隔(毫秒) */
181
+ retryDelay?: number;
182
+ /** 自定义标签 */
183
+ tags?: string[];
184
+ /** 工具分组 */
185
+ group?: string;
186
+ }
187
+ /**
188
+ * 扩展的 CustomMCPTool 接口
189
+ * 包含额外的元数据信息
190
+ */
191
+ interface ExtendedCustomMCPTool {
192
+ /** 基础工具配置 */
193
+ name: string;
194
+ description: string;
195
+ inputSchema: any;
196
+ handler: any;
197
+ /** 使用统计信息 */
198
+ stats?: {
199
+ usageCount?: number;
200
+ lastUsedTime?: string;
201
+ };
202
+ /** 工具元数据 */
203
+ metadata?: ToolMetadata;
204
+ /** 配置选项 */
205
+ config?: ToolConfigOptions;
206
+ }
207
+
208
+ export { type AddCustomToolRequest as A, type CozeWorkflowData as C, type ExtendedCustomMCPTool as E, type FunctionToolData as F, type HttpApiToolData as H, type MCPToolData as M, ToolType as T, type AddToolResponse as a, type ToolMetadata as b, type ToolConfigOptions as c, type ToolValidationErrorDetail as d, ToolValidationError as e };
@@ -0,0 +1,115 @@
1
+ export { T as TimeoutError, a as TimeoutResponse, b as isTimeoutError, i as utilsIsTimeoutResponse } from './timeout-CCp_IFHg.js';
2
+
3
+ /**
4
+ * 性能监控相关类型定义
5
+ */
6
+ /**
7
+ * 性能指标接口
8
+ */
9
+ interface PerformanceMetrics {
10
+ serviceName: string;
11
+ connectionLatency: number;
12
+ averageToolCallLatency: number;
13
+ toolCallLatencies: Map<string, number[]>;
14
+ successRate: number;
15
+ errorRate: number;
16
+ totalOperations: number;
17
+ successfulOperations: number;
18
+ failedOperations: number;
19
+ lastUpdated: Date;
20
+ uptime: number;
21
+ startTime: Date;
22
+ }
23
+ /**
24
+ * 操作类型枚举
25
+ */
26
+ declare enum OperationType {
27
+ CONNECTION = "connection",
28
+ TOOL_CALL = "tool_call",
29
+ RECONNECTION = "reconnection",
30
+ HEALTH_CHECK = "health_check"
31
+ }
32
+ /**
33
+ * 计时器接口
34
+ */
35
+ interface Timer {
36
+ id: string;
37
+ operation: string;
38
+ serviceName: string;
39
+ startTime: number;
40
+ type: OperationType;
41
+ }
42
+ /**
43
+ * 性能统计摘要
44
+ */
45
+ interface PerformanceSummary {
46
+ /** 总连接数 */
47
+ totalConnections: number;
48
+ /** 活跃连接数 */
49
+ activeConnections: number;
50
+ /** 平均连接延迟 */
51
+ averageConnectionLatency: number;
52
+ /** 平均工具调用延迟 */
53
+ averageToolCallLatency: number;
54
+ /** 总体成功率 */
55
+ overallSuccessRate: number;
56
+ /** 总操作数 */
57
+ totalOperations: number;
58
+ /** 性能评分(0-100) */
59
+ performanceScore: number;
60
+ }
61
+
62
+ /**
63
+ * 日志相关类型定义
64
+ */
65
+ /**
66
+ * 工具调用记录接口
67
+ */
68
+ interface ToolCallRecord {
69
+ toolName: string;
70
+ originalToolName?: string;
71
+ serverName?: string;
72
+ arguments?: any;
73
+ result?: any;
74
+ success: boolean;
75
+ duration?: number;
76
+ error?: string;
77
+ timestamp?: number;
78
+ }
79
+ /**
80
+ * 工具调用日志配置接口
81
+ */
82
+ interface ToolCallLogConfig {
83
+ maxRecords?: number;
84
+ logFilePath?: string;
85
+ }
86
+ /**
87
+ * 日志级别枚举
88
+ */
89
+ declare enum LogLevel {
90
+ TRACE = "trace",
91
+ DEBUG = "debug",
92
+ INFO = "info",
93
+ WARN = "warn",
94
+ ERROR = "error",
95
+ FATAL = "fatal"
96
+ }
97
+ /**
98
+ * 日志配置接口
99
+ */
100
+ interface LogConfig {
101
+ /** 日志级别 */
102
+ level?: LogLevel;
103
+ /** 是否启用彩色输出 */
104
+ colorize?: boolean;
105
+ /** 是否启用时间戳 */
106
+ timestamp?: boolean;
107
+ /** 日志格式 */
108
+ format?: "json" | "pretty";
109
+ /** 日志输出路径 */
110
+ outputPath?: string;
111
+ /** 是否同时输出到文件和控制台 */
112
+ both?: boolean;
113
+ }
114
+
115
+ export { type LogConfig, LogLevel, OperationType, type PerformanceMetrics, type PerformanceSummary, type Timer, type ToolCallLogConfig, type ToolCallRecord };
@@ -0,0 +1,15 @@
1
+ import {
2
+ LogLevel,
3
+ OperationType,
4
+ TimeoutError,
5
+ isTimeoutError,
6
+ isTimeoutResponse
7
+ } from "./chunk-BMOKIX3Q.js";
8
+ export {
9
+ LogLevel,
10
+ OperationType,
11
+ TimeoutError,
12
+ isTimeoutError,
13
+ isTimeoutResponse as utilsIsTimeoutResponse
14
+ };
15
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * 扣子工作流相关类型定义
3
+ */
4
+ /**
5
+ * 扣子工作流创建者信息
6
+ */
7
+ interface CozeWorkflowCreator {
8
+ /** 创建者ID */
9
+ id: string;
10
+ /** 创建者名称 */
11
+ name: string;
12
+ }
13
+ /**
14
+ * 扣子工作流接口
15
+ */
16
+ interface CozeWorkflow {
17
+ /** 工作流ID */
18
+ workflow_id: string;
19
+ /** 工作流名称 */
20
+ workflow_name: string;
21
+ /** 工作流描述 */
22
+ description: string;
23
+ /** 工作流图标URL */
24
+ icon_url: string;
25
+ /** 关联应用ID */
26
+ app_id: string;
27
+ /** 创建者信息 */
28
+ creator: CozeWorkflowCreator;
29
+ /** 创建时间戳 */
30
+ created_at: number;
31
+ /** 更新时间戳 */
32
+ updated_at: number;
33
+ /** 是否已添加为工具(前端运行时属性) */
34
+ isAddedAsTool?: boolean;
35
+ /** 输入参数Schema(前端运行时属性) */
36
+ inputSchema?: any;
37
+ /** 工具名称(前端运行时属性) */
38
+ toolName?: string | null;
39
+ }
40
+ /**
41
+ * 获取工作流列表的响应数据
42
+ */
43
+ interface CozeWorkflowsData {
44
+ /** 是否有更多数据 */
45
+ has_more: boolean;
46
+ /** 工作流列表 */
47
+ items: CozeWorkflow[];
48
+ }
49
+ /**
50
+ * 获取工作流列表的请求参数
51
+ */
52
+ interface CozeWorkflowsParams {
53
+ /** 工作空间ID */
54
+ workspace_id: string;
55
+ /** 页码,从1开始 */
56
+ page_num?: number;
57
+ /** 每页数量,默认20 */
58
+ page_size?: number;
59
+ /** 工作流模式,默认为 workflow */
60
+ workflow_mode?: "workflow";
61
+ }
62
+ /**
63
+ * 工作流参数定义
64
+ */
65
+ interface WorkflowParameter {
66
+ /** 英文字段名,用作参数标识符 */
67
+ fieldName: string;
68
+ /** 中英文描述,说明参数用途 */
69
+ description: string;
70
+ /** 参数类型 */
71
+ type: "string" | "number" | "boolean";
72
+ /** 是否必填参数 */
73
+ required: boolean;
74
+ }
75
+ /**
76
+ * 工作流参数配置
77
+ */
78
+ interface WorkflowParameterConfig {
79
+ /** 参数列表 */
80
+ parameters: WorkflowParameter[];
81
+ }
82
+
83
+ export type { CozeWorkflow as C, WorkflowParameter as W, CozeWorkflowCreator as a, WorkflowParameterConfig as b, CozeWorkflowsParams as c, CozeWorkflowsData as d };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xiaozhi-client",
3
- "version": "1.9.4-beta.4",
3
+ "version": "1.9.4-beta.8",
4
4
  "description": "小智 AI 客户端 命令行工具",
5
5
  "repository": {
6
6
  "type": "git",
@@ -34,16 +34,20 @@
34
34
  "build": "nx reset && pnpm run clean:dist && nx run-many -t build --exclude=docs --parallel=false",
35
35
  "test": "nx run-many -t test",
36
36
  "test:coverage": "nx run-many -t test:coverage --parallel=false",
37
- "lint": "nx run-many -t lint --output-style=stream",
38
- "lint:fix": "nx run-many -t lint:fix --output-style=stream",
39
- "type-check": "nx run-many -t type-check",
37
+ "lint": "nx run-many -t lint",
38
+ "lint:fix": "nx run-many -t lint:fix",
39
+ "type-check": "nx run-many -t type-check --exclude=docs",
40
40
  "format": "biome format --write .",
41
41
  "check:all": "pnpm run lint && pnpm run type-check && pnpm run check:spell && pnpm run duplicate:check",
42
42
  "check:spell": "cspell .",
43
43
  "duplicate:check": "jscpd apps/backend/",
44
44
  "docker:update-version": "node docker/scripts/update-version.js",
45
- "release": "npx release-it",
46
- "release:dry": "npx release-it --dry-run",
45
+ "release": "nx release version && pnpm build && nx release publish",
46
+ "release:dry": "nx release version --dry-run",
47
+ "release:version": "nx release version",
48
+ "release:publish": "nx release publish",
49
+ "release:multi": "tsx scripts/publish.ts",
50
+ "release:multi:dry": "tsx scripts/publish.ts --dry-run",
47
51
  "dev": "nx run-many -t build --exclude=docs --parallel=false && concurrently \"nx run backend:dev\" \"nx run cli:dev\" \"nx run frontend:dev\" --prefix \"[{name}]\" --names \"BACKEND,CLI,FRONTEND\"",
48
52
  "dev:cli": "nx run cli:dev",
49
53
  "dev:docs": "nx run docs:dev",
@@ -60,8 +64,8 @@
60
64
  "ajv": "^8.17.1",
61
65
  "chalk": "^5.6.0",
62
66
  "cli-table3": "^0.6.5",
63
- "comment-json": "^4.2.5",
64
67
  "commander": "^14.0.0",
68
+ "comment-json": "^4.2.5",
65
69
  "consola": "^3.4.2",
66
70
  "dayjs": "^1.11.13",
67
71
  "dotenv": "^17.2.1",
@@ -81,12 +85,9 @@
81
85
  "@nx/vite": "^22.3.3",
82
86
  "@nx/vitest": "^22.3.3",
83
87
  "@nx/workspace": "^22.3.3",
84
- "@release-it/conventional-changelog": "^10.0.1",
85
88
  "@types/semver": "^7.7.1",
86
89
  "@vitest/coverage-v8": "^3.2.4",
87
90
  "concurrently": "^9.2.1",
88
- "conventional-changelog-cli": "^5.0.0",
89
- "conventional-changelog-conventionalcommits": "^9.1.0",
90
91
  "cross-env": "^10.0.0",
91
92
  "cspell": "^9.2.1",
92
93
  "esbuild": "^0.25.9",
@@ -94,7 +95,6 @@
94
95
  "glob": "^11.0.3",
95
96
  "jscpd": "^4.0.5",
96
97
  "nx": "^22.3.3",
97
- "release-it": "^19.0.4",
98
98
  "rimraf": "^6.1.2",
99
99
  "semver": "^7.7.2",
100
100
  "ts-node": "^10.9.2",
@@ -1,3 +0,0 @@
1
- var $=Object.defineProperty;var a=(i,e)=>$(i,"name",{value:e,configurable:!0});import{copyFileSync as K,existsSync as b,readFileSync as G,writeFileSync as q}from"fs";import{dirname as Y,resolve as p}from"path";import{fileURLToPath as Z}from"url";import{EventEmitter as J}from"events";import*as c from"fs";import*as l from"path";import C from"chalk";import u from"pino";import{z as R}from"zod";var _=R.enum(["fatal","error","warn","info","debug","trace"]);function z(i){let e=i.getFullYear(),t=String(i.getMonth()+1).padStart(2,"0"),o=String(i.getDate()).padStart(2,"0"),n=String(i.getHours()).padStart(2,"0"),r=String(i.getMinutes()).padStart(2,"0"),s=String(i.getSeconds()).padStart(2,"0");return`${e}-${t}-${o} ${n}:${r}:${s}`}a(z,"formatDateTime");var P=class{static{a(this,"Logger")}logFilePath=null;pinoInstance;isDaemonMode;logLevel;maxLogFileSize=10*1024*1024;maxLogFiles=5;constructor(e="info"){this.isDaemonMode=process.env.XIAOZHI_DAEMON==="true",this.logLevel=this.validateLogLevel(e),this.pinoInstance=this.createPinoInstance()}validateLogLevel(e){let t=e.toLowerCase(),o=_.safeParse(t);return o.success?o.data:"info"}createPinoInstance(){let e=[];if(!this.isDaemonMode){let t=this.createOptimizedConsoleStream();e.push({level:this.logLevel,stream:t})}return this.logFilePath&&e.push({level:this.logLevel,stream:u.destination({dest:this.logFilePath,sync:!1,append:!0,mkdir:!0})}),e.length===0&&e.push({level:this.logLevel,stream:u.destination({dest:"/dev/null"})}),u({level:this.logLevel,timestamp:u.stdTimeFunctions?.isoTime||(()=>`,"time":${Date.now()}`),formatters:{level:a((t,o)=>({level:o}),"level")},base:null,serializers:{err:u.stdSerializers?.err||(t=>t)}},u.multistream(e,{dedupe:!0}))}createOptimizedConsoleStream(){let e=new Map([[20,{name:"DEBUG",color:C.gray}],[30,{name:"INFO",color:C.blue}],[40,{name:"WARN",color:C.yellow}],[50,{name:"ERROR",color:C.red}],[60,{name:"FATAL",color:C.red}]]);return{write:a(t=>{try{let o=JSON.parse(t),n=this.formatConsoleMessageOptimized(o,e);this.safeWrite(`${n}
2
- `)}catch{this.safeWrite(t)}},"write")}}safeWrite(e){try{process.stderr&&typeof process.stderr.write=="function"&&process.stderr.write(e)}catch{}}formatConsoleMessageOptimized(e,t){let o=z(new Date),n=t.get(e.level)||{name:"UNKNOWN",color:a(f=>f,"color")},r=n.color(`[${n.name}]`),s=e.msg;if(e.args&&Array.isArray(e.args)){let f=e.args.map(g=>typeof g=="object"?JSON.stringify(g):String(g)).join(" ");s=`${s} ${f}`}return`[${o}] ${r} ${s}`}initLogFile(e){this.logFilePath=l.join(e,"xiaozhi.log"),this.rotateLogFileIfNeeded(),c.existsSync(this.logFilePath)||c.writeFileSync(this.logFilePath,""),this.pinoInstance=this.createPinoInstance()}enableFileLogging(e){e&&this.logFilePath&&(this.pinoInstance=this.createPinoInstance())}info(e,...t){typeof e=="string"?t.length===0?this.pinoInstance.info(e):this.pinoInstance.info({args:t},e):this.pinoInstance.info(e,t[0]||"")}success(e,...t){typeof e=="string"?t.length===0?this.pinoInstance.info(e):this.pinoInstance.info({args:t},e):this.pinoInstance.info(e,t[0]||"")}warn(e,...t){typeof e=="string"?t.length===0?this.pinoInstance.warn(e):this.pinoInstance.warn({args:t},e):this.pinoInstance.warn(e,t[0]||"")}error(e,...t){if(typeof e=="string")if(t.length===0)this.pinoInstance.error(e);else{let o=t.map(n=>n instanceof Error?this.pinoInstance.level==="debug"?n.message:{message:n.message,stack:n.stack,name:n.name,cause:n.cause}:n);this.pinoInstance.error({args:o},e)}else{let o=this.enhanceErrorObject(e);this.pinoInstance.error(o,t[0]||"")}}debug(e,...t){typeof e=="string"?t.length===0?this.pinoInstance.debug(e):this.pinoInstance.debug({args:t},e):this.pinoInstance.debug(e,t[0]||"")}log(e,...t){typeof e=="string"?t.length===0?this.pinoInstance.info(e):this.pinoInstance.info({args:t},e):this.pinoInstance.info(e,t[0]||"")}enhanceErrorObject(e){let t={...e};for(let[o,n]of Object.entries(t))n instanceof Error&&(t[o]={message:n.message,stack:n.stack,name:n.name,cause:n.cause});return t}rotateLogFileIfNeeded(){if(!(!this.logFilePath||!c.existsSync(this.logFilePath)))try{c.statSync(this.logFilePath).size>this.maxLogFileSize&&this.rotateLogFile()}catch{}}rotateLogFile(){if(this.logFilePath)try{let e=l.dirname(this.logFilePath),t=l.basename(this.logFilePath,".log");for(let n=this.maxLogFiles-1;n>=1;n--){let r=l.join(e,`${t}.${n}.log`),s=l.join(e,`${t}.${n+1}.log`);c.existsSync(r)&&(n===this.maxLogFiles-1?c.unlinkSync(r):c.renameSync(r,s))}let o=l.join(e,`${t}.1.log`);c.renameSync(this.logFilePath,o)}catch{}}cleanupOldLogs(){if(this.logFilePath)try{let e=l.dirname(this.logFilePath),t=l.basename(this.logFilePath,".log");for(let o=this.maxLogFiles+1;o<=this.maxLogFiles+10;o++){let n=l.join(e,`${t}.${o}.log`);c.existsSync(n)&&c.unlinkSync(n)}}catch{}}setLogFileOptions(e,t){this.maxLogFileSize=e,this.maxLogFiles=t}close(){}setLevel(e){this.logLevel=this.validateLogLevel(e),this.pinoInstance=this.createPinoInstance()}getLevel(){return this.logLevel}},y=null,B="info";function W(){return y||(y=new P(B)),y}a(W,"getLogger");var N=W();var w=class extends J{static{a(this,"EventBus")}logger;eventStats=new Map;maxListeners=50;constructor(){super(),this.logger=N,this.setMaxListeners(this.maxListeners),this.setupErrorHandling()}setupErrorHandling(){this.on("error",e=>{this.logger.error("EventBus \u5185\u90E8\u9519\u8BEF:",e)}),this.on("newListener",e=>{let t=this.listenerCount(e);t>this.maxListeners*.8&&this.logger.warn(`\u4E8B\u4EF6 ${e} \u7684\u76D1\u542C\u5668\u6570\u91CF\u8FC7\u591A: ${t}`)})}emitEvent(e,t){try{return this.updateEventStats(e),this.logger.debug(`\u53D1\u5C04\u4E8B\u4EF6: ${e}`,t),super.emit(e,t)}catch(o){return this.logger.error(`\u53D1\u5C04\u4E8B\u4EF6\u5931\u8D25: ${e}`,o),o instanceof Error&&this.emit("error",o),!1}}onEvent(e,t){return this.logger.debug(`\u6DFB\u52A0\u4E8B\u4EF6\u76D1\u542C\u5668: ${e}`),this.on(e,t)}onceEvent(e,t){this.logger.debug(`\u6DFB\u52A0\u4E00\u6B21\u6027\u4E8B\u4EF6\u76D1\u542C\u5668: ${e}`);let o=a(n=>{try{t(n)}catch(r){throw this.emit("error",r),r}finally{this.offEvent(e,o)}},"onceListener");return this.on(e,o)}offEvent(e,t){return this.logger.debug(`\u79FB\u9664\u4E8B\u4EF6\u76D1\u542C\u5668: ${e}`),this.off(e,t)}updateEventStats(e){let t=this.eventStats.get(e)||{count:0,lastEmitted:new Date};t.count++,t.lastEmitted=new Date,this.eventStats.set(e,t)}getEventStats(){let e={};for(let[t,o]of this.eventStats)e[t]={...o};return e}getListenerStats(){let e={};for(let t of this.eventNames())e[t]=this.listenerCount(t);return e}clearEventStats(){this.eventStats.clear(),this.logger.info("\u4E8B\u4EF6\u7EDF\u8BA1\u5DF2\u6E05\u7406")}getStatus(){return{totalEvents:this.eventStats.size,totalListeners:Object.values(this.getListenerStats()).reduce((e,t)=>e+t,0),eventStats:this.getEventStats(),listenerStats:this.getListenerStats()}}destroy(){this.removeAllListeners(),this.eventStats.clear(),this.logger.info("EventBus \u5DF2\u9500\u6BC1")}},S=null;function j(){return S||(S=new w),S}a(j,"getEventBus");var M;(t=>{function i(o){if(!o||typeof o!="object")return o;let n=JSON.parse(JSON.stringify(o));if(!("type"in n))return n;let r=n.type;if(r==="sse"||r==="streamable-http")return n;let s;return r==="streamableHttp"||r==="streamable_http"?s="streamable-http":r==="s_se"||r==="s-se"?s="sse":s=e(r),(s==="sse"||s==="streamable-http")&&(n.type=s),n}t.normalizeTypeField=i,a(i,"normalizeTypeField");function e(o){return o.replace(/([a-z])([A-Z])/g,"$1-$2").replace(/_/g,"-").toLowerCase()}a(e,"convertToKebabCase")})(M||={});function O(i){if(!i||typeof i!="object")throw new Error("\u670D\u52A1\u914D\u7F6E\u5FC5\u987B\u662F\u4E00\u4E2A\u6709\u6548\u7684\u5BF9\u8C61");if("command"in i&&typeof i.command=="string")return"stdio";if("type"in i&&i.type==="sse")return"sse";if("type"in i&&i.type==="streamable-http"||"url"in i&&typeof i.url=="string")return"streamable-http";throw new Error("\u65E0\u6CD5\u8BC6\u522B\u7684 MCP \u670D\u52A1\u914D\u7F6E\u7C7B\u578B\u3002\u914D\u7F6E\u5FC5\u987B\u5305\u542B command \u5B57\u6BB5\uFF08stdio\uFF09\u3001type: 'sse' \u5B57\u6BB5\uFF08sse\uFF09\u6216 url \u5B57\u6BB5\uFF08streamable-http\uFF09")}a(O,"getMcpServerCommunicationType");function E(i,e){if(!e||typeof e!="object"||Array.isArray(e))return{valid:!1,error:`\u670D\u52A1 "${i}" \u7684\u914D\u7F6E\u5FC5\u987B\u662F\u4E00\u4E2A\u5BF9\u8C61`};try{let t=O(e),o=e;switch(t){case"stdio":if(!o.command||typeof o.command!="string")return{valid:!1,error:`\u670D\u52A1 "${i}" \u7F3A\u5C11\u5FC5\u9700\u7684 command \u5B57\u6BB5\u6216\u5B57\u6BB5\u7C7B\u578B\u4E0D\u6B63\u786E`};if(!Array.isArray(o.args))return{valid:!1,error:`\u670D\u52A1 "${i}" \u7684 args \u5B57\u6BB5\u5FC5\u987B\u662F\u6570\u7EC4`};if(o.env&&(typeof o.env!="object"||Array.isArray(o.env)))return{valid:!1,error:`\u670D\u52A1 "${i}" \u7684 env \u5B57\u6BB5\u5FC5\u987B\u662F\u5BF9\u8C61`};break;case"sse":if(o.type!=="sse")return{valid:!1,error:`\u670D\u52A1 "${i}" \u7684 type \u5B57\u6BB5\u5FC5\u987B\u662F "sse"`};if(!o.url||typeof o.url!="string")return{valid:!1,error:`\u670D\u52A1 "${i}" \u7F3A\u5C11\u5FC5\u9700\u7684 url \u5B57\u6BB5\u6216\u5B57\u6BB5\u7C7B\u578B\u4E0D\u6B63\u786E`};if(o.headers&&(typeof o.headers!="object"||Array.isArray(o.headers)))return{valid:!1,error:`\u670D\u52A1 "${i}" \u7684 headers \u5B57\u6BB5\u5FC5\u987B\u662F\u5BF9\u8C61`};break;case"streamable-http":if(!o.url||typeof o.url!="string")return{valid:!1,error:`\u670D\u52A1 "${i}" \u7F3A\u5C11\u5FC5\u9700\u7684 url \u5B57\u6BB5\u6216\u5B57\u6BB5\u7C7B\u578B\u4E0D\u6B63\u786E`};if(o.type&&o.type!=="streamable-http")return{valid:!1,error:`\u670D\u52A1 "${i}" \u7684 type \u5B57\u6BB5\u5982\u679C\u5B58\u5728\uFF0C\u5FC5\u987B\u662F "streamable-http"`};if(o.headers&&(typeof o.headers!="object"||Array.isArray(o.headers)))return{valid:!1,error:`\u670D\u52A1 "${i}" \u7684 headers \u5B57\u6BB5\u5FC5\u987B\u662F\u5BF9\u8C61`};break;default:return{valid:!1,error:`\u670D\u52A1 "${i}" \u7684\u914D\u7F6E\u7C7B\u578B\u65E0\u6CD5\u8BC6\u522B`}}return{valid:!0}}catch(t){return{valid:!1,error:`\u670D\u52A1 "${i}" \u7684\u914D\u7F6E\u65E0\u6548: ${t instanceof Error?t.message:"\u672A\u77E5\u9519\u8BEF"}`}}}a(E,"validateMcpServerConfig");import*as d from"comment-json";import A from"dayjs";import*as h from"comment-json";function F(i){let e=h.parse(i);return{write(t){e&&typeof e=="object"&&t&&Object.assign(e,t)},toSource(){return h.stringify(e,null,2)}}}a(F,"createJson5Writer");function U(i){return h.parse(i)}a(U,"parseJson5");var H=Y(Z(import.meta.url)),T={heartbeatInterval:3e4,heartbeatTimeout:1e4,reconnectInterval:5e3},x=class i{static{a(this,"ConfigManager")}static instance;defaultConfigPath;config=null;currentConfigPath=null;json5Writer=null;eventBus=j();statsUpdateLocks=new Map;statsUpdateLockTimeouts=new Map;STATS_UPDATE_TIMEOUT=5e3;constructor(){let e=[p(H,"templates","default","xiaozhi.config.json"),p(H,"..","templates","default","xiaozhi.config.json"),p(process.cwd(),"templates","default","xiaozhi.config.json")];this.defaultConfigPath=e.find(t=>b(t))||e[0]}getConfigFilePath(){let e=process.env.XIAOZHI_CONFIG_DIR||process.cwd(),t=["xiaozhi.config.json5","xiaozhi.config.jsonc","xiaozhi.config.json"];for(let o of t){let n=p(e,o);if(b(n))return n}return p(e,"xiaozhi.config.json")}getConfigFileFormat(e){return e.endsWith(".json5")?"json5":e.endsWith(".jsonc")?"jsonc":"json"}static getInstance(){return i.instance||(i.instance=new i),i.instance}configExists(){let e=process.env.XIAOZHI_CONFIG_DIR||process.cwd(),t=["xiaozhi.config.json5","xiaozhi.config.jsonc","xiaozhi.config.json"];for(let o of t){let n=p(e,o);if(b(n))return!0}return!1}initConfig(e="json"){if(!b(this.defaultConfigPath))throw new Error(`\u9ED8\u8BA4\u914D\u7F6E\u6A21\u677F\u6587\u4EF6\u4E0D\u5B58\u5728: ${this.defaultConfigPath}`);if(this.configExists())throw new Error("\u914D\u7F6E\u6587\u4EF6\u5DF2\u5B58\u5728\uFF0C\u65E0\u9700\u91CD\u590D\u521D\u59CB\u5316");let t=process.env.XIAOZHI_CONFIG_DIR||process.cwd(),o=`xiaozhi.config.${e}`,n=p(t,o);K(this.defaultConfigPath,n),this.config=null,this.json5Writer=null}loadConfig(){if(!this.configExists()){let e=new Error("\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728\uFF0C\u8BF7\u5148\u8FD0\u884C xiaozhi init \u521D\u59CB\u5316\u914D\u7F6E");throw this.eventBus.emitEvent("config:error",{error:e,operation:"loadConfig"}),e}try{let e=this.getConfigFilePath();this.currentConfigPath=e;let t=this.getConfigFileFormat(e),n=G(e,"utf8").replace(/^\uFEFF/,""),r;switch(t){case"json5":r=U(n),this.json5Writer=F(n);break;case"jsonc":r=d.parse(n);break;default:r=JSON.parse(n);break}return this.validateConfig(r),r}catch(e){throw this.eventBus.emitEvent("config:error",{error:e instanceof Error?e:new Error(String(e)),operation:"loadConfig"}),e instanceof SyntaxError?new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF: ${e.message}`):e}}validateConfig(e){if(!e||typeof e!="object")throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1A\u6839\u5BF9\u8C61\u65E0\u6548");let t=e;if(t.mcpEndpoint===void 0||t.mcpEndpoint===null)throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpEndpoint \u5B57\u6BB5\u65E0\u6548");if(typeof t.mcpEndpoint!="string")if(Array.isArray(t.mcpEndpoint)){for(let o of t.mcpEndpoint)if(typeof o!="string"||o.trim()==="")throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpEndpoint \u6570\u7EC4\u4E2D\u7684\u6BCF\u4E2A\u5143\u7D20\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32")}else throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpEndpoint \u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u6216\u5B57\u7B26\u4E32\u6570\u7EC4");if(!t.mcpServers||typeof t.mcpServers!="object")throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers \u5B57\u6BB5\u65E0\u6548");for(let[o,n]of Object.entries(t.mcpServers)){if(!n||typeof n!="object")throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${o} \u65E0\u6548`);let r=M.normalizeTypeField(n),s=E(o,r);if(!s.valid)throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1A${s.error}`)}}getConfig(){return this.config=this.loadConfig(),JSON.parse(JSON.stringify(this.config))}getMutableConfig(){return this.config||(this.config=this.loadConfig()),this.config}getMcpEndpoint(){let e=this.getConfig();return Array.isArray(e.mcpEndpoint)?e.mcpEndpoint[0]||"":e.mcpEndpoint}getMcpEndpoints(){let e=this.getConfig();return Array.isArray(e.mcpEndpoint)?[...e.mcpEndpoint]:e.mcpEndpoint?[e.mcpEndpoint]:[]}getMcpServers(){return this.getConfig().mcpServers}getMcpServerConfig(){return this.getConfig().mcpServerConfig||{}}getServerToolsConfig(e){return this.getMcpServerConfig()[e]?.tools||{}}isToolEnabled(e,t){return this.getServerToolsConfig(e)[t]?.enable!==!1}updateMcpEndpoint(e){if(Array.isArray(e)){for(let o of e)if(!o||typeof o!="string")throw new Error("MCP \u7AEF\u70B9\u6570\u7EC4\u4E2D\u7684\u6BCF\u4E2A\u5143\u7D20\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32")}let t=this.getMutableConfig();t.mcpEndpoint=e,this.saveConfig(t),this.eventBus.emitEvent("config:updated",{type:"endpoint",timestamp:new Date})}addMcpEndpoint(e){if(!e||typeof e!="string")throw new Error("MCP \u7AEF\u70B9\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");let t=this.getMutableConfig(),o=this.getMcpEndpoints();if(o.includes(e))throw new Error(`MCP \u7AEF\u70B9 ${e} \u5DF2\u5B58\u5728`);let n=[...o,e];t.mcpEndpoint=n,this.saveConfig(t)}removeMcpEndpoint(e){if(!e||typeof e!="string")throw new Error("MCP \u7AEF\u70B9\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");let t=this.getMutableConfig(),o=this.getMcpEndpoints();if(o.indexOf(e)===-1)throw new Error(`MCP \u7AEF\u70B9 ${e} \u4E0D\u5B58\u5728`);let r=o.filter(s=>s!==e);t.mcpEndpoint=r,this.saveConfig(t)}updateMcpServer(e,t){if(!e||typeof e!="string")throw new Error("\u670D\u52A1\u540D\u79F0\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");let o=E(e,t);if(!o.valid)throw new Error(o.error||"\u670D\u52A1\u914D\u7F6E\u9A8C\u8BC1\u5931\u8D25");let n=this.getMutableConfig();n.mcpServers[e]=t,this.saveConfig(n)}removeMcpServer(e){if(!e||typeof e!="string")throw new Error("\u670D\u52A1\u540D\u79F0\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");let t=this.getMutableConfig();if(!t.mcpServers[e])throw new Error(`\u670D\u52A1 ${e} \u4E0D\u5B58\u5728`);if(delete t.mcpServers[e],t.mcpServerConfig?.[e]&&delete t.mcpServerConfig[e],t.customMCP?.tools){let o=t.customMCP.tools.filter(n=>n.handler?.type==="mcp"&&n.handler.config?.serviceName===e);for(let n of o){let r=t.customMCP.tools.findIndex(s=>s.name===n.name);r!==-1&&t.customMCP.tools.splice(r,1)}t.customMCP.tools.length===0&&(t.customMCP=void 0)}this.saveConfig(t),this.eventBus.emitEvent("config:updated",{type:"customMCP",timestamp:new Date})}updateConfig(e){let t=this.getMutableConfig();if(e.mcpEndpoint!==void 0&&(t.mcpEndpoint=e.mcpEndpoint),e.mcpServers){let o={...t.mcpServers};for(let[n,r]of Object.entries(e.mcpServers))t.mcpServers[n]=r;for(let n of Object.keys(o))n in e.mcpServers||(delete t.mcpServers[n],t.mcpServerConfig?.[n]&&delete t.mcpServerConfig[n])}if(e.connection&&(t.connection||(t.connection={}),Object.assign(t.connection,e.connection)),e.modelscope&&(t.modelscope||(t.modelscope={}),Object.assign(t.modelscope,e.modelscope)),e.webUI&&(t.webUI||(t.webUI={}),Object.assign(t.webUI,e.webUI)),e.mcpServerConfig)for(let[o,n]of Object.entries(e.mcpServerConfig))t.mcpServerConfig?.[o]&&(t.mcpServerConfig[o]=n);if(e.platforms)for(let[o,n]of Object.entries(e.platforms))t.platforms||(t.platforms={}),t.platforms[o]=n;this.saveConfig(t),this.eventBus.emitEvent("config:updated",{type:"config",timestamp:new Date})}updateServerToolsConfig(e,t){let o=this.getMutableConfig();o.mcpServerConfig||(o.mcpServerConfig={}),Object.keys(t).length===0?delete o.mcpServerConfig[e]:o.mcpServerConfig[e]={tools:t},this.saveConfig(o),this.eventBus.emitEvent("config:updated",{type:"serverTools",serviceName:e,timestamp:new Date})}removeServerToolsConfig(e){let o={...this.getConfig()};o.mcpServerConfig&&(delete o.mcpServerConfig[e],this.saveConfig(o))}cleanupInvalidServerToolsConfig(){let e=this.getMutableConfig();if(!e.mcpServerConfig)return;let t=Object.keys(e.mcpServers),n=Object.keys(e.mcpServerConfig).filter(r=>!t.includes(r));if(n.length>0){for(let r of n)delete e.mcpServerConfig[r];this.saveConfig(e)}}setToolEnabled(e,t,o,n){let r=this.getMutableConfig();r.mcpServerConfig||(r.mcpServerConfig={}),r.mcpServerConfig[e]||(r.mcpServerConfig[e]={tools:{}}),r.mcpServerConfig[e].tools[t]={...r.mcpServerConfig[e].tools[t],enable:o,...n&&{description:n}},this.saveConfig(r)}saveConfig(e){try{this.validateConfig(e);let t;this.currentConfigPath?t=this.currentConfigPath:(t=this.getConfigFilePath(),this.currentConfigPath=t);let o=this.getConfigFileFormat(t),n;switch(o){case"json5":try{this.json5Writer?(this.json5Writer.write(e),n=this.json5Writer.toSource()):n=d.stringify(e,null,2)}catch{n=d.stringify(e,null,2)}break;case"jsonc":try{n=d.stringify(e,null,2)}catch{n=JSON.stringify(e,null,2)}break;default:n=JSON.stringify(e,null,2);break}q(t,n,"utf8"),this.config=e,this.notifyConfigUpdate(e)}catch(t){throw this.eventBus.emitEvent("config:error",{error:t instanceof Error?t:new Error(String(t)),operation:"saveConfig"}),new Error(`\u4FDD\u5B58\u914D\u7F6E\u5931\u8D25: ${t instanceof Error?t.message:String(t)}`)}}reloadConfig(){this.config=null,this.currentConfigPath=null,this.json5Writer=null}getConfigPath(){return this.getConfigFilePath()}getDefaultConfigPath(){return this.defaultConfigPath}getConnectionConfig(){let t=this.getConfig().connection||{};return{heartbeatInterval:t.heartbeatInterval??T.heartbeatInterval,heartbeatTimeout:t.heartbeatTimeout??T.heartbeatTimeout,reconnectInterval:t.reconnectInterval??T.reconnectInterval}}getHeartbeatInterval(){return this.getConnectionConfig().heartbeatInterval}getHeartbeatTimeout(){return this.getConnectionConfig().heartbeatTimeout}getReconnectInterval(){return this.getConnectionConfig().reconnectInterval}updateConnectionConfig(e){let t=this.getMutableConfig();t.connection||(t.connection={}),Object.assign(t.connection,e),this.saveConfig(t),this.eventBus.emitEvent("config:updated",{type:"connection",timestamp:new Date})}async updateToolUsageStats(e,t,o){try{if(typeof t=="string"&&o){let n=e,r=t,s=o;await Promise.all([this._updateMCPServerToolStats(n,r,s),this.updateCustomMCPToolStats(n,r,s)])}else{let n=e,r=t,s=new Date().toISOString();await this.updateCustomMCPToolStats(n,s,r)}}catch{if(typeof t=="string"&&o){let r=e,s=t}else{let r=e}}}async updateMCPServerToolStats(e,t,o,n=!0){await this._updateMCPServerToolStats(e,t,o,n)}setHeartbeatInterval(e){if(e<=0)throw new Error("\u5FC3\u8DF3\u68C0\u6D4B\u95F4\u9694\u5FC5\u987B\u5927\u4E8E0");this.updateConnectionConfig({heartbeatInterval:e})}setHeartbeatTimeout(e){if(e<=0)throw new Error("\u5FC3\u8DF3\u8D85\u65F6\u65F6\u95F4\u5FC5\u987B\u5927\u4E8E0");this.updateConnectionConfig({heartbeatTimeout:e})}setReconnectInterval(e){if(e<=0)throw new Error("\u91CD\u8FDE\u95F4\u9694\u5FC5\u987B\u5927\u4E8E0");this.updateConnectionConfig({reconnectInterval:e})}getModelScopeConfig(){return this.getConfig().modelscope||{}}getModelScopeApiKey(){return this.getModelScopeConfig().apiKey||process.env.MODELSCOPE_API_TOKEN}updateModelScopeConfig(e){let t=this.getMutableConfig();t.modelscope||(t.modelscope={}),Object.assign(t.modelscope,e),this.saveConfig(t),this.eventBus.emitEvent("config:updated",{type:"modelscope",timestamp:new Date})}setModelScopeApiKey(e){if(!e||typeof e!="string")throw new Error("API Key \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");this.updateModelScopeConfig({apiKey:e})}getCustomMCPConfig(){return this.getConfig().customMCP||null}getCustomMCPTools(){let e=this.getCustomMCPConfig();return!e||!e.tools?[]:e.tools}validateCustomMCPTools(e){if(!Array.isArray(e))return!1;for(let t of e)if(!t.name||typeof t.name!="string"||!t.description||typeof t.description!="string"||!t.inputSchema||typeof t.inputSchema!="object"||!t.handler||typeof t.handler!="object"||!["proxy","function","http","script","chain","mcp"].includes(t.handler.type)||!this.validateHandlerConfig(t.name,t.handler))return!1;return!0}validateHandlerConfig(e,t){switch(t.type){case"proxy":return this.validateProxyHandler(e,t);case"http":return this.validateHttpHandler(e,t);case"function":return this.validateFunctionHandler(e,t);case"script":return this.validateScriptHandler(e,t);case"chain":return this.validateChainHandler(e,t);case"mcp":return this.validateMCPHandler(e,t);default:return!1}}validateProxyHandler(e,t){return!(!t.platform||!["coze","openai","anthropic","custom"].includes(t.platform)||!t.config||typeof t.config!="object"||t.platform==="coze"&&!t.config.workflow_id&&!t.config.bot_id)}validateHttpHandler(e,t){if(!t.url||typeof t.url!="string")return!1;try{new URL(t.url)}catch{return!1}return!(t.method&&!["GET","POST","PUT","DELETE","PATCH"].includes(t.method))}validateFunctionHandler(e,t){return!(!t.module||typeof t.module!="string"||!t.function||typeof t.function!="string")}validateScriptHandler(e,t){return!(!t.script||typeof t.script!="string"||t.interpreter&&!["node","python","bash"].includes(t.interpreter))}validateChainHandler(e,t){return!(!t.tools||!Array.isArray(t.tools)||t.tools.length===0||!["sequential","parallel"].includes(t.mode)||!["stop","continue","retry"].includes(t.error_handling))}validateMCPHandler(e,t){return!(!t.config||typeof t.config!="object"||!t.config.serviceName||typeof t.config.serviceName!="string"||!t.config.toolName||typeof t.config.toolName!="string")}hasValidCustomMCPTools(){try{let e=this.getCustomMCPTools();return e.length===0?!1:this.validateCustomMCPTools(e)}catch{return!1}}addCustomMCPTool(e){if(!e||typeof e!="object")throw new Error("\u5DE5\u5177\u914D\u7F6E\u4E0D\u80FD\u4E3A\u7A7A");let t=this.getMutableConfig();if(t.customMCP||(t.customMCP={tools:[]}),t.customMCP.tools.find(n=>n.name===e.name))throw new Error(`\u5DE5\u5177 "${e.name}" \u5DF2\u5B58\u5728`);if(!this.validateCustomMCPTools([e]))throw new Error("\u5DE5\u5177\u914D\u7F6E\u9A8C\u8BC1\u5931\u8D25");t.customMCP.tools.unshift(e),this.saveConfig(t)}async addCustomMCPTools(e){if(!Array.isArray(e))throw new Error("\u5DE5\u5177\u914D\u7F6E\u5FC5\u987B\u662F\u6570\u7EC4");if(e.length===0)return;let t=this.getMutableConfig();t.customMCP||(t.customMCP={tools:[]});let o=new Set(t.customMCP.tools.map(r=>r.name)),n=e.filter(r=>!o.has(r.name));if(n.length>0){if(!this.validateCustomMCPTools(n))throw new Error("\u5DE5\u5177\u914D\u7F6E\u9A8C\u8BC1\u5931\u8D25");t.customMCP.tools.push(...n),this.saveConfig(t),this.eventBus.emitEvent("config:updated",{type:"customMCP",timestamp:new Date})}}removeCustomMCPTool(e){if(!e||typeof e!="string")throw new Error("\u5DE5\u5177\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A");let t=this.getMutableConfig();if(!t.customMCP||!t.customMCP.tools)throw new Error("\u672A\u914D\u7F6E\u81EA\u5B9A\u4E49 MCP \u5DE5\u5177");let o=t.customMCP.tools.findIndex(n=>n.name===e);if(o===-1)throw new Error(`\u5DE5\u5177 "${e}" \u4E0D\u5B58\u5728`);t.customMCP.tools.splice(o,1),this.saveConfig(t)}updateCustomMCPTool(e,t){if(!e||typeof e!="string")throw new Error("\u5DE5\u5177\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A");if(!t||typeof t!="object")throw new Error("\u66F4\u65B0\u540E\u7684\u5DE5\u5177\u914D\u7F6E\u4E0D\u80FD\u4E3A\u7A7A");let o=this.getMutableConfig();if(!o.customMCP||!o.customMCP.tools)throw new Error("\u672A\u914D\u7F6E\u81EA\u5B9A\u4E49 MCP \u5DE5\u5177");let n=o.customMCP.tools.findIndex(r=>r.name===e);if(n===-1)throw new Error(`\u5DE5\u5177 "${e}" \u4E0D\u5B58\u5728`);if(!this.validateCustomMCPTools([t]))throw new Error("\u66F4\u65B0\u540E\u7684\u5DE5\u5177\u914D\u7F6E\u9A8C\u8BC1\u5931\u8D25");o.customMCP.tools[n]=t,this.saveConfig(o)}updateCustomMCPTools(e){if(!Array.isArray(e))throw new Error("\u5DE5\u5177\u914D\u7F6E\u5FC5\u987B\u662F\u6570\u7EC4");if(!this.validateCustomMCPTools(e))throw new Error("\u5DE5\u5177\u914D\u7F6E\u9A8C\u8BC1\u5931\u8D25");let t=this.getMutableConfig();t.customMCP||(t.customMCP={tools:[]}),t.customMCP.tools=e,this.saveConfig(t),this.eventBus.emitEvent("config:updated",{type:"customMCP",timestamp:new Date})}getWebUIConfig(){return this.getConfig().webUI||{}}getWebUIPort(){return this.getWebUIConfig().port??9999}notifyConfigUpdate(e){try{let t=global.__webServer;t&&typeof t.broadcastConfigUpdate=="function"&&t.broadcastConfigUpdate(e)}catch{}}updateWebUIConfig(e){let t=this.getMutableConfig();t.webUI||(t.webUI={}),Object.assign(t.webUI,e),this.saveConfig(t),this.eventBus.emitEvent("config:updated",{type:"webui",timestamp:new Date})}setWebUIPort(e){if(!Number.isInteger(e)||e<=0||e>65535)throw new Error("\u7AEF\u53E3\u53F7\u5FC5\u987B\u662F 1-65535 \u4E4B\u95F4\u7684\u6574\u6570");this.updateWebUIConfig({port:e})}updatePlatformConfig(e,t){let o=this.getMutableConfig();o.platforms||(o.platforms={}),o.platforms[e]=t,this.saveConfig(o),this.eventBus.emitEvent("config:updated",{type:"platform",platformName:e,timestamp:new Date})}getCozePlatformConfig(){let t=this.getConfig().platforms?.coze;return!t||!t.token?null:{token:t.token}}getCozeToken(){return this.getCozePlatformConfig()?.token||null}setCozePlatformConfig(e){if(!e.token||typeof e.token!="string"||e.token.trim()==="")throw new Error("\u6263\u5B50 API Token \u4E0D\u80FD\u4E3A\u7A7A");this.updatePlatformConfig("coze",{token:e.token.trim()})}isCozeConfigValid(){let e=this.getCozePlatformConfig();return e!==null&&typeof e.token=="string"&&e.token.trim()!==""}async _updateMCPServerToolStats(e,t,o,n=!0){let r=this.getMutableConfig();r.mcpServerConfig||(r.mcpServerConfig={}),r.mcpServerConfig[e]||(r.mcpServerConfig[e]={tools:{}}),r.mcpServerConfig[e].tools[t]||(r.mcpServerConfig[e].tools[t]={enable:!0});let s=r.mcpServerConfig[e].tools[t],f=s.usageCount||0,g=s.lastUsedTime;n&&(s.usageCount=f+1),(!g||new Date(o)>new Date(g))&&(s.lastUsedTime=A(o).format("YYYY-MM-DD HH:mm:ss")),this.saveConfig(r)}async updateCustomMCPToolStats(e,t,o){try{let n,r,s=!0,f;if(typeof o=="string"){let v=e;n=`${v}__${t}`,r=o,f=`${v}/${t}`}else n=e,r=t,s=o||!0,f=n;let g=this.getCustomMCPTools(),L=g.findIndex(v=>v.name===n);if(L===-1)return;let I=[...g],m=I[L];m.stats||(m.stats={});let D=m.stats.usageCount||0,k=m.stats.lastUsedTime;s&&(m.stats.usageCount=D+1),(!k||new Date(r)>new Date(k))&&(m.stats.lastUsedTime=A(r).format("YYYY-MM-DD HH:mm:ss")),await this.updateCustomMCPTools(I)}catch{if(typeof o=="string"){let r=e,s=t}else{let r=e}}}async acquireStatsUpdateLock(e){if(this.statsUpdateLocks.has(e))return!1;let t=new Promise(n=>{});this.statsUpdateLocks.set(e,t);let o=setTimeout(()=>{this.releaseStatsUpdateLock(e)},this.STATS_UPDATE_TIMEOUT);return this.statsUpdateLockTimeouts.set(e,o),!0}releaseStatsUpdateLock(e){this.statsUpdateLocks.delete(e);let t=this.statsUpdateLockTimeouts.get(e);t&&(clearTimeout(t),this.statsUpdateLockTimeouts.delete(e))}async updateToolUsageStatsWithLock(e,t=!0){let o=`custommcp_${e}`;if(await this.acquireStatsUpdateLock(o))try{await this.updateToolUsageStats(e,t)}catch(n){throw n}finally{this.releaseStatsUpdateLock(o)}}async updateMCPServerToolStatsWithLock(e,t,o,n=!0){let r=`mcpserver_${e}_${t}`;if(await this.acquireStatsUpdateLock(r))try{await this.updateMCPServerToolStats(e,t,o,n)}catch(s){throw s}finally{this.releaseStatsUpdateLock(r)}}clearAllStatsUpdateLocks(){let e=this.statsUpdateLocks.size;this.statsUpdateLocks.clear();for(let t of this.statsUpdateLockTimeouts.values())clearTimeout(t);this.statsUpdateLockTimeouts.clear(),e>0}getStatsUpdateLocks(){return Array.from(this.statsUpdateLocks.keys())}getToolCallLogConfig(){return this.getConfig().toolCallLog||{}}updateToolCallLogConfig(e){let t=this.getMutableConfig();t.toolCallLog||(t.toolCallLog={}),Object.assign(t.toolCallLog,e),this.saveConfig(t)}getConfigDir(){return process.env.XIAOZHI_CONFIG_DIR||process.cwd()}},Pe=x.getInstance();export{x as ConfigManager,Pe as configManager};
3
- //# sourceMappingURL=manager.js.map