xiaozhi-client 2.3.0-beta.6 → 2.3.0

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.
package/dist/cli/index.js CHANGED
@@ -21,10 +21,1922 @@ var __copyProps = (to, from, except, desc) => {
21
21
  };
22
22
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
23
23
 
24
- // src/Constants.ts
24
+ // ../config/json5-adapter.ts
25
+ import * as commentJson from "comment-json";
26
+ function createJson5Writer(content) {
27
+ const parsedData = commentJson.parse(content);
28
+ return {
29
+ write(data) {
30
+ if (parsedData && typeof parsedData === "object" && data) {
31
+ Object.assign(parsedData, data);
32
+ }
33
+ },
34
+ toSource() {
35
+ return commentJson.stringify(parsedData, null, 2);
36
+ }
37
+ };
38
+ }
39
+ function parseJson5(content) {
40
+ return commentJson.parse(content);
41
+ }
42
+ var init_json5_adapter = __esm({
43
+ "../config/json5-adapter.ts"() {
44
+ "use strict";
45
+ __name(createJson5Writer, "createJson5Writer");
46
+ __name(parseJson5, "parseJson5");
47
+ }
48
+ });
49
+
50
+ // ../config/resolver.ts
51
+ import { existsSync } from "fs";
52
+ import path from "path";
53
+ var ConfigResolver;
54
+ var init_resolver = __esm({
55
+ "../config/resolver.ts"() {
56
+ "use strict";
57
+ ConfigResolver = class _ConfigResolver {
58
+ static {
59
+ __name(this, "ConfigResolver");
60
+ }
61
+ /**
62
+ * 按优先级解析配置文件路径
63
+ *
64
+ * 优先级顺序:
65
+ * 1. 环境变量 XIAOZHI_CONFIG_DIR 指定的目录
66
+ * 2. 当前工作目录
67
+ * 3. 用户家目录/.xiaozhi-client/
68
+ *
69
+ * @returns 找到的配置文件路径,如果都不存在则返回 null
70
+ */
71
+ static resolveConfigPath() {
72
+ if (process.env.XIAOZHI_CONFIG_DIR) {
73
+ const configPath = _ConfigResolver.findConfigInDir(
74
+ process.env.XIAOZHI_CONFIG_DIR
75
+ );
76
+ if (configPath) {
77
+ return configPath;
78
+ }
79
+ }
80
+ const currentDirConfig = _ConfigResolver.findConfigInDir(process.cwd());
81
+ if (currentDirConfig) {
82
+ return currentDirConfig;
83
+ }
84
+ const homeDir = process.env.HOME || process.env.USERPROFILE;
85
+ if (homeDir) {
86
+ const xiaozhiClientDir = path.join(homeDir, ".xiaozhi-client");
87
+ const homeDirConfig = _ConfigResolver.findConfigInDir(xiaozhiClientDir);
88
+ if (homeDirConfig) {
89
+ return homeDirConfig;
90
+ }
91
+ }
92
+ return null;
93
+ }
94
+ /**
95
+ * 在指定目录中查找配置文件
96
+ *
97
+ * 按优先级查找:xiaozhi.config.json5 > xiaozhi.config.jsonc > xiaozhi.config.json
98
+ *
99
+ * @param dir - 要搜索的目录
100
+ * @returns 找到的配置文件路径,如果不存在则返回 null
101
+ */
102
+ static findConfigInDir(dir) {
103
+ const configFileNames = [
104
+ "xiaozhi.config.json5",
105
+ "xiaozhi.config.jsonc",
106
+ "xiaozhi.config.json"
107
+ ];
108
+ for (const fileName of configFileNames) {
109
+ const filePath = path.join(dir, fileName);
110
+ if (existsSync(filePath)) {
111
+ return filePath;
112
+ }
113
+ }
114
+ return null;
115
+ }
116
+ /**
117
+ * 获取默认配置目录路径
118
+ *
119
+ * @returns 用户家目录下的 .xiaozhi-client 目录路径,如果无法获取家目录则返回 null
120
+ */
121
+ static getDefaultConfigDir() {
122
+ const homeDir = process.env.HOME || process.env.USERPROFILE;
123
+ if (!homeDir) {
124
+ return null;
125
+ }
126
+ return path.join(homeDir, ".xiaozhi-client");
127
+ }
128
+ };
129
+ }
130
+ });
131
+
132
+ // ../config/manager.ts
133
+ import { copyFileSync, existsSync as existsSync2, readFileSync, writeFileSync } from "fs";
134
+ import { dirname, resolve } from "path";
135
+ import { fileURLToPath } from "url";
136
+ import * as commentJson2 from "comment-json";
137
+ import dayjs from "dayjs";
138
+ var __dirname, DEFAULT_CONNECTION_CONFIG, ConfigManager, configManager;
139
+ var init_manager = __esm({
140
+ "../config/manager.ts"() {
141
+ "use strict";
142
+ init_json5_adapter();
143
+ init_resolver();
144
+ __dirname = dirname(fileURLToPath(import.meta.url));
145
+ DEFAULT_CONNECTION_CONFIG = {
146
+ heartbeatInterval: 3e4,
147
+ // 30秒心跳间隔
148
+ heartbeatTimeout: 1e4,
149
+ // 10秒心跳超时
150
+ reconnectInterval: 5e3
151
+ // 5秒重连间隔
152
+ };
153
+ ConfigManager = class _ConfigManager {
154
+ static {
155
+ __name(this, "ConfigManager");
156
+ }
157
+ static instance;
158
+ defaultConfigPath;
159
+ config = null;
160
+ currentConfigPath = null;
161
+ // 跟踪当前使用的配置文件路径
162
+ json5Writer = null;
163
+ // json5-writer 实例,用于保留 JSON5 注释
164
+ // 统计更新并发控制
165
+ statsUpdateLocks = /* @__PURE__ */ new Map();
166
+ statsUpdateLockTimeouts = /* @__PURE__ */ new Map();
167
+ STATS_UPDATE_TIMEOUT = 5e3;
168
+ // 5秒超时
169
+ // 事件回调(用于解耦 EventBus 依赖)
170
+ eventCallbacks = /* @__PURE__ */ new Map();
171
+ constructor() {
172
+ const possiblePaths = [
173
+ // src/config/ 或 dist/config/ → 项目根 templates/default/xiaozhi.config.json
174
+ resolve(
175
+ __dirname,
176
+ "..",
177
+ "..",
178
+ "templates",
179
+ "default",
180
+ "xiaozhi.config.json"
181
+ ),
182
+ // 从 CWD 查找(兼容各种启动场景)
183
+ resolve(process.cwd(), "templates", "default", "xiaozhi.config.json")
184
+ ];
185
+ this.defaultConfigPath = possiblePaths.find((path9) => existsSync2(path9)) || possiblePaths[0];
186
+ }
187
+ /**
188
+ * 注册事件监听器
189
+ */
190
+ on(eventName, callback) {
191
+ if (!this.eventCallbacks.has(eventName)) {
192
+ this.eventCallbacks.set(eventName, []);
193
+ }
194
+ this.eventCallbacks.get(eventName)?.push(callback);
195
+ }
196
+ /**
197
+ * 发射事件
198
+ */
199
+ emitEvent(eventName, data) {
200
+ const callbacks = this.eventCallbacks.get(eventName);
201
+ if (callbacks) {
202
+ for (const callback of callbacks) {
203
+ try {
204
+ callback(data);
205
+ } catch (error) {
206
+ console.error(`\u4E8B\u4EF6\u56DE\u8C03\u6267\u884C\u5931\u8D25 [${eventName}]:`, error);
207
+ }
208
+ }
209
+ }
210
+ }
211
+ /**
212
+ * 获取配置文件路径(动态计算)
213
+ * 支持多种配置文件格式:json5 > jsonc > json
214
+ *
215
+ * 查找优先级:
216
+ * 1. 环境变量 XIAOZHI_CONFIG_DIR 指定的目录
217
+ * 2. 当前工作目录
218
+ * 3. 用户家目录/.xiaozhi-client/
219
+ */
220
+ getConfigFilePath() {
221
+ const resolvedPath = ConfigResolver.resolveConfigPath();
222
+ if (resolvedPath) {
223
+ return resolvedPath;
224
+ }
225
+ const defaultDir = ConfigResolver.getDefaultConfigDir();
226
+ if (defaultDir) {
227
+ return resolve(defaultDir, "xiaozhi.config.json");
228
+ }
229
+ const configDir = process.env.XIAOZHI_CONFIG_DIR || process.cwd();
230
+ return resolve(configDir, "xiaozhi.config.json");
231
+ }
232
+ /**
233
+ * 获取配置文件格式
234
+ */
235
+ getConfigFileFormat(filePath) {
236
+ if (filePath.endsWith(".json5")) {
237
+ return "json5";
238
+ }
239
+ if (filePath.endsWith(".jsonc")) {
240
+ return "jsonc";
241
+ }
242
+ return "json";
243
+ }
244
+ /**
245
+ * 获取配置管理器单例实例
246
+ */
247
+ static getInstance() {
248
+ if (!_ConfigManager.instance) {
249
+ _ConfigManager.instance = new _ConfigManager();
250
+ }
251
+ return _ConfigManager.instance;
252
+ }
253
+ /**
254
+ * 检查配置文件是否存在
255
+ *
256
+ * 按优先级检查配置文件是否存在:
257
+ * 1. 环境变量 XIAOZHI_CONFIG_DIR 指定的目录
258
+ * 2. 当前工作目录
259
+ * 3. 用户家目录/.xiaozhi-client/
260
+ */
261
+ configExists() {
262
+ return ConfigResolver.resolveConfigPath() !== null;
263
+ }
264
+ /**
265
+ * 初始化配置文件
266
+ * 从 config.default.json 复制到 config.json
267
+ * @param format 配置文件格式,默认为 json
268
+ */
269
+ initConfig(format = "json") {
270
+ if (!existsSync2(this.defaultConfigPath)) {
271
+ throw new Error(`\u9ED8\u8BA4\u914D\u7F6E\u6A21\u677F\u6587\u4EF6\u4E0D\u5B58\u5728: ${this.defaultConfigPath}`);
272
+ }
273
+ if (this.configExists()) {
274
+ throw new Error("\u914D\u7F6E\u6587\u4EF6\u5DF2\u5B58\u5728\uFF0C\u65E0\u9700\u91CD\u590D\u521D\u59CB\u5316");
275
+ }
276
+ const configDir = process.env.XIAOZHI_CONFIG_DIR || process.cwd();
277
+ const targetFileName = `xiaozhi.config.${format}`;
278
+ const configPath = resolve(configDir, targetFileName);
279
+ copyFileSync(this.defaultConfigPath, configPath);
280
+ this.config = null;
281
+ this.json5Writer = null;
282
+ }
283
+ /**
284
+ * 加载配置文件
285
+ */
286
+ loadConfig() {
287
+ if (!this.configExists()) {
288
+ const error = new Error(
289
+ "\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728\uFF0C\u8BF7\u5148\u8FD0\u884C xiaozhi init \u521D\u59CB\u5316\u914D\u7F6E"
290
+ );
291
+ this.emitEvent("config:error", {
292
+ error,
293
+ operation: "loadConfig"
294
+ });
295
+ throw error;
296
+ }
297
+ try {
298
+ const configPath = this.getConfigFilePath();
299
+ this.currentConfigPath = configPath;
300
+ const configFileFormat = this.getConfigFileFormat(configPath);
301
+ const rawConfigData = readFileSync(configPath, "utf8");
302
+ const configData = rawConfigData.replace(/^\uFEFF/, "");
303
+ let config;
304
+ switch (configFileFormat) {
305
+ case "json5":
306
+ config = parseJson5(configData);
307
+ this.json5Writer = createJson5Writer(configData);
308
+ break;
309
+ case "jsonc":
310
+ config = commentJson2.parse(configData);
311
+ break;
312
+ default:
313
+ config = JSON.parse(configData);
314
+ break;
315
+ }
316
+ this.validateConfig(config);
317
+ return config;
318
+ } catch (error) {
319
+ this.emitEvent("config:error", {
320
+ error: error instanceof Error ? error : new Error(String(error)),
321
+ operation: "loadConfig"
322
+ });
323
+ if (error instanceof SyntaxError) {
324
+ throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF: ${error.message}`);
325
+ }
326
+ throw error;
327
+ }
328
+ }
329
+ /**
330
+ * 验证配置文件结构
331
+ */
332
+ validateConfig(config) {
333
+ if (!config || typeof config !== "object") {
334
+ throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1A\u6839\u5BF9\u8C61\u65E0\u6548");
335
+ }
336
+ const configObj = config;
337
+ if (configObj.mcpEndpoint === void 0 || configObj.mcpEndpoint === null) {
338
+ throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpEndpoint \u5B57\u6BB5\u65E0\u6548");
339
+ }
340
+ if (typeof configObj.mcpEndpoint === "string") {
341
+ } else if (Array.isArray(configObj.mcpEndpoint)) {
342
+ for (const endpoint of configObj.mcpEndpoint) {
343
+ if (typeof endpoint !== "string" || endpoint.trim() === "") {
344
+ throw new Error(
345
+ "\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"
346
+ );
347
+ }
348
+ }
349
+ } else {
350
+ throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpEndpoint \u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u6216\u5B57\u7B26\u4E32\u6570\u7EC4");
351
+ }
352
+ if (!configObj.mcpServers || typeof configObj.mcpServers !== "object") {
353
+ throw new Error("\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers \u5B57\u6BB5\u65E0\u6548");
354
+ }
355
+ for (const [serverName, serverConfig] of Object.entries(
356
+ configObj.mcpServers
357
+ )) {
358
+ if (!serverConfig || typeof serverConfig !== "object") {
359
+ throw new Error(`\u914D\u7F6E\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF\uFF1AmcpServers.${serverName} \u65E0\u6548`);
360
+ }
361
+ }
362
+ }
363
+ /**
364
+ * 获取配置(只读)
365
+ * 使用缓存机制避免频繁的文件 I/O 操作
366
+ */
367
+ getConfig() {
368
+ if (!this.config) {
369
+ this.config = this.loadConfig();
370
+ }
371
+ return structuredClone(this.config);
372
+ }
373
+ /**
374
+ * 获取可修改的配置对象(内部使用,保留注释信息)
375
+ */
376
+ getMutableConfig() {
377
+ if (!this.config) {
378
+ this.config = this.loadConfig();
379
+ }
380
+ return this.config;
381
+ }
382
+ /**
383
+ * 获取 MCP 端点(向后兼容)
384
+ * @deprecated 使用 getMcpEndpoints() 获取所有端点
385
+ */
386
+ getMcpEndpoint() {
387
+ const config = this.getConfig();
388
+ if (Array.isArray(config.mcpEndpoint)) {
389
+ return config.mcpEndpoint[0] || "";
390
+ }
391
+ return config.mcpEndpoint;
392
+ }
393
+ /**
394
+ * 获取所有 MCP 端点
395
+ */
396
+ getMcpEndpoints() {
397
+ const config = this.getConfig();
398
+ if (Array.isArray(config.mcpEndpoint)) {
399
+ return [...config.mcpEndpoint];
400
+ }
401
+ return config.mcpEndpoint ? [config.mcpEndpoint] : [];
402
+ }
403
+ /**
404
+ * 获取 MCP 服务配置
405
+ */
406
+ getMcpServers() {
407
+ const config = this.getConfig();
408
+ return config.mcpServers;
409
+ }
410
+ /**
411
+ * 获取 MCP 服务工具配置
412
+ */
413
+ getMcpServerConfig() {
414
+ const config = this.getConfig();
415
+ return config.mcpServerConfig || {};
416
+ }
417
+ /**
418
+ * 获取指定服务的工具配置
419
+ */
420
+ getServerToolsConfig(serverName) {
421
+ const serverConfig = this.getMcpServerConfig();
422
+ return serverConfig[serverName]?.tools || {};
423
+ }
424
+ /**
425
+ * 检查工具是否启用
426
+ */
427
+ isToolEnabled(serverName, toolName) {
428
+ const toolsConfig = this.getServerToolsConfig(serverName);
429
+ const toolConfig = toolsConfig[toolName];
430
+ return toolConfig?.enable !== false;
431
+ }
432
+ /**
433
+ * 更新 MCP 端点(支持字符串或数组)
434
+ */
435
+ updateMcpEndpoint(endpoint) {
436
+ if (Array.isArray(endpoint)) {
437
+ for (const ep of endpoint) {
438
+ if (!ep || typeof ep !== "string") {
439
+ throw new Error("MCP \u7AEF\u70B9\u6570\u7EC4\u4E2D\u7684\u6BCF\u4E2A\u5143\u7D20\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");
440
+ }
441
+ }
442
+ }
443
+ const config = this.getMutableConfig();
444
+ config.mcpEndpoint = endpoint;
445
+ this.saveConfig(config);
446
+ this.emitEvent("config:updated", {
447
+ type: "endpoint",
448
+ timestamp: /* @__PURE__ */ new Date()
449
+ });
450
+ }
451
+ /**
452
+ * 添加 MCP 端点
453
+ */
454
+ addMcpEndpoint(endpoint) {
455
+ if (!endpoint || typeof endpoint !== "string") {
456
+ throw new Error("MCP \u7AEF\u70B9\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");
457
+ }
458
+ const config = this.getMutableConfig();
459
+ const currentEndpoints = this.getMcpEndpoints();
460
+ if (currentEndpoints.includes(endpoint)) {
461
+ throw new Error(`MCP \u7AEF\u70B9 ${endpoint} \u5DF2\u5B58\u5728`);
462
+ }
463
+ const newEndpoints = [...currentEndpoints, endpoint];
464
+ config.mcpEndpoint = newEndpoints;
465
+ this.saveConfig(config);
466
+ }
467
+ /**
468
+ * 移除 MCP 端点
469
+ */
470
+ removeMcpEndpoint(endpoint) {
471
+ if (!endpoint || typeof endpoint !== "string") {
472
+ throw new Error("MCP \u7AEF\u70B9\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");
473
+ }
474
+ const config = this.getMutableConfig();
475
+ const currentEndpoints = this.getMcpEndpoints();
476
+ const index = currentEndpoints.indexOf(endpoint);
477
+ if (index === -1) {
478
+ throw new Error(`MCP \u7AEF\u70B9 ${endpoint} \u4E0D\u5B58\u5728`);
479
+ }
480
+ const newEndpoints = currentEndpoints.filter((ep) => ep !== endpoint);
481
+ config.mcpEndpoint = newEndpoints;
482
+ this.saveConfig(config);
483
+ }
484
+ /**
485
+ * 更新 MCP 服务配置
486
+ */
487
+ updateMcpServer(serverName, serverConfig) {
488
+ if (!serverName || typeof serverName !== "string") {
489
+ throw new Error("\u670D\u52A1\u540D\u79F0\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");
490
+ }
491
+ const config = this.getMutableConfig();
492
+ config.mcpServers[serverName] = serverConfig;
493
+ this.saveConfig(config);
494
+ }
495
+ /**
496
+ * 删除 MCP 服务配置
497
+ */
498
+ removeMcpServer(serverName) {
499
+ if (!serverName || typeof serverName !== "string") {
500
+ throw new Error("\u670D\u52A1\u540D\u79F0\u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");
501
+ }
502
+ const config = this.getMutableConfig();
503
+ if (!config.mcpServers[serverName]) {
504
+ throw new Error(`\u670D\u52A1 ${serverName} \u4E0D\u5B58\u5728`);
505
+ }
506
+ delete config.mcpServers[serverName];
507
+ if (config.mcpServerConfig?.[serverName]) {
508
+ delete config.mcpServerConfig[serverName];
509
+ }
510
+ if (config.customMCP?.tools) {
511
+ const relatedTools = config.customMCP.tools.filter(
512
+ (tool) => tool.handler?.type === "mcp" && tool.handler.config?.serviceName === serverName
513
+ );
514
+ for (const tool of relatedTools) {
515
+ const toolIndex = config.customMCP.tools.findIndex(
516
+ (t) => t.name === tool.name
517
+ );
518
+ if (toolIndex !== -1) {
519
+ config.customMCP.tools.splice(toolIndex, 1);
520
+ }
521
+ }
522
+ if (config.customMCP.tools.length === 0) {
523
+ config.customMCP = void 0;
524
+ }
525
+ }
526
+ this.saveConfig(config);
527
+ this.emitEvent("config:updated", {
528
+ type: "customMCP",
529
+ timestamp: /* @__PURE__ */ new Date()
530
+ });
531
+ console.log("\u6210\u529F\u79FB\u9664 MCP \u670D\u52A1", { serverName });
532
+ }
533
+ /**
534
+ * 批量更新配置(由 Handler 调用)
535
+ */
536
+ updateConfig(newConfig) {
537
+ const config = this.getMutableConfig();
538
+ if (newConfig.mcpEndpoint !== void 0) {
539
+ config.mcpEndpoint = newConfig.mcpEndpoint;
540
+ }
541
+ if (newConfig.mcpServers) {
542
+ const currentServers = { ...config.mcpServers };
543
+ for (const [name, serverConfig] of Object.entries(newConfig.mcpServers)) {
544
+ config.mcpServers[name] = serverConfig;
545
+ }
546
+ for (const name of Object.keys(currentServers)) {
547
+ if (!(name in newConfig.mcpServers)) {
548
+ delete config.mcpServers[name];
549
+ if (config.mcpServerConfig?.[name]) {
550
+ delete config.mcpServerConfig[name];
551
+ }
552
+ }
553
+ }
554
+ }
555
+ if (newConfig.connection) {
556
+ if (!config.connection) {
557
+ config.connection = {};
558
+ }
559
+ Object.assign(config.connection, newConfig.connection);
560
+ }
561
+ if (newConfig.modelscope) {
562
+ if (!config.modelscope) {
563
+ config.modelscope = {};
564
+ }
565
+ Object.assign(config.modelscope, newConfig.modelscope);
566
+ }
567
+ if (newConfig.webUI) {
568
+ if (!config.webUI) {
569
+ config.webUI = {};
570
+ }
571
+ Object.assign(config.webUI, newConfig.webUI);
572
+ }
573
+ if (newConfig.mcpServerConfig) {
574
+ for (const [serverName, toolsConfig] of Object.entries(
575
+ newConfig.mcpServerConfig
576
+ )) {
577
+ if (config.mcpServerConfig?.[serverName]) {
578
+ config.mcpServerConfig[serverName] = toolsConfig;
579
+ }
580
+ }
581
+ }
582
+ if (newConfig.platforms) {
583
+ for (const [platformName, platformConfig] of Object.entries(
584
+ newConfig.platforms
585
+ )) {
586
+ if (!config.platforms) {
587
+ config.platforms = {};
588
+ }
589
+ config.platforms[platformName] = platformConfig;
590
+ }
591
+ }
592
+ if ("asr" in newConfig) {
593
+ config.asr = newConfig.asr;
594
+ }
595
+ if ("tts" in newConfig) {
596
+ config.tts = newConfig.tts;
597
+ }
598
+ if ("llm" in newConfig) {
599
+ config.llm = newConfig.llm;
600
+ }
601
+ this.saveConfig(config);
602
+ this.emitEvent("config:updated", {
603
+ type: "config",
604
+ timestamp: /* @__PURE__ */ new Date()
605
+ });
606
+ }
607
+ /**
608
+ * 更新服务工具配置
609
+ */
610
+ updateServerToolsConfig(serverName, toolsConfig) {
611
+ const config = this.getMutableConfig();
612
+ if (!config.mcpServerConfig) {
613
+ config.mcpServerConfig = {};
614
+ }
615
+ if (Object.keys(toolsConfig).length === 0) {
616
+ delete config.mcpServerConfig[serverName];
617
+ } else {
618
+ config.mcpServerConfig[serverName] = {
619
+ tools: toolsConfig
620
+ };
621
+ }
622
+ this.saveConfig(config);
623
+ this.emitEvent("config:updated", {
624
+ type: "serverTools",
625
+ serviceName: serverName,
626
+ timestamp: /* @__PURE__ */ new Date()
627
+ });
628
+ }
629
+ /**
630
+ * 删除指定服务器的工具配置
631
+ */
632
+ removeServerToolsConfig(serverName) {
633
+ const config = this.getConfig();
634
+ const newConfig = { ...config };
635
+ if (newConfig.mcpServerConfig) {
636
+ delete newConfig.mcpServerConfig[serverName];
637
+ this.saveConfig(newConfig);
638
+ }
639
+ }
640
+ /**
641
+ * 清理无效的服务器工具配置
642
+ * 删除在 mcpServerConfig 中存在但在 mcpServers 中不存在的服务配置
643
+ */
644
+ cleanupInvalidServerToolsConfig() {
645
+ const config = this.getMutableConfig();
646
+ if (!config.mcpServerConfig) {
647
+ return;
648
+ }
649
+ const validServerNames = Object.keys(config.mcpServers);
650
+ const configuredServerNames = Object.keys(config.mcpServerConfig);
651
+ const invalidServerNames = configuredServerNames.filter(
652
+ (serverName) => !validServerNames.includes(serverName)
653
+ );
654
+ if (invalidServerNames.length > 0) {
655
+ for (const serverName of invalidServerNames) {
656
+ delete config.mcpServerConfig[serverName];
657
+ }
658
+ this.saveConfig(config);
659
+ console.log("\u5DF2\u6E05\u7406\u65E0\u6548\u7684\u670D\u52A1\u5DE5\u5177\u914D\u7F6E", {
660
+ count: invalidServerNames.length,
661
+ serverNames: invalidServerNames
662
+ });
663
+ }
664
+ }
665
+ /**
666
+ * 设置工具启用状态
667
+ */
668
+ setToolEnabled(serverName, toolName, enabled, description) {
669
+ const config = this.getMutableConfig();
670
+ if (!config.mcpServerConfig) {
671
+ config.mcpServerConfig = {};
672
+ }
673
+ if (!config.mcpServerConfig[serverName]) {
674
+ config.mcpServerConfig[serverName] = { tools: {} };
675
+ }
676
+ config.mcpServerConfig[serverName].tools[toolName] = {
677
+ ...config.mcpServerConfig[serverName].tools[toolName],
678
+ enable: enabled,
679
+ ...description && { description }
680
+ };
681
+ this.saveConfig(config);
682
+ }
683
+ /**
684
+ * 保存配置到文件
685
+ * 保存到原始配置文件路径,保持文件格式一致性
686
+ */
687
+ saveConfig(config) {
688
+ try {
689
+ this.validateConfig(config);
690
+ let configPath;
691
+ if (this.currentConfigPath) {
692
+ configPath = this.currentConfigPath;
693
+ } else {
694
+ configPath = this.getConfigFilePath();
695
+ this.currentConfigPath = configPath;
696
+ }
697
+ const configFileFormat = this.getConfigFileFormat(configPath);
698
+ let configContent;
699
+ switch (configFileFormat) {
700
+ case "json5":
701
+ try {
702
+ if (this.json5Writer) {
703
+ this.json5Writer.write(config);
704
+ configContent = this.json5Writer.toSource();
705
+ } else {
706
+ console.warn("\u6CA1\u6709 JSON5 \u9002\u914D\u5668\u5B9E\u4F8B\uFF0C\u4F7F\u7528 comment-json \u5E8F\u5217\u5316");
707
+ configContent = commentJson2.stringify(config, null, 2);
708
+ }
709
+ } catch (json5Error) {
710
+ console.warn(
711
+ "\u4F7F\u7528 JSON5 \u9002\u914D\u5668\u4FDD\u5B58\u5931\u8D25\uFF0C\u56DE\u9000\u5230 comment-json \u5E8F\u5217\u5316:",
712
+ json5Error
713
+ );
714
+ configContent = commentJson2.stringify(config, null, 2);
715
+ }
716
+ break;
717
+ case "jsonc":
718
+ try {
719
+ configContent = commentJson2.stringify(config, null, 2);
720
+ } catch (commentJsonError) {
721
+ console.warn(
722
+ "\u4F7F\u7528 comment-json \u4FDD\u5B58\u5931\u8D25\uFF0C\u56DE\u9000\u5230\u6807\u51C6 JSON \u683C\u5F0F:",
723
+ commentJsonError
724
+ );
725
+ configContent = JSON.stringify(config, null, 2);
726
+ }
727
+ break;
728
+ default:
729
+ configContent = JSON.stringify(config, null, 2);
730
+ break;
731
+ }
732
+ writeFileSync(configPath, configContent, "utf8");
733
+ this.config = config;
734
+ console.log("\u914D\u7F6E\u4FDD\u5B58\u6210\u529F");
735
+ this.notifyConfigUpdate(config);
736
+ } catch (error) {
737
+ this.emitEvent("config:error", {
738
+ error: error instanceof Error ? error : new Error(String(error)),
739
+ operation: "saveConfig"
740
+ });
741
+ throw new Error(
742
+ `\u4FDD\u5B58\u914D\u7F6E\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`
743
+ );
744
+ }
745
+ }
746
+ /**
747
+ * 重新加载配置(清除缓存)
748
+ */
749
+ reloadConfig() {
750
+ this.config = null;
751
+ this.currentConfigPath = null;
752
+ this.json5Writer = null;
753
+ }
754
+ /**
755
+ * 获取配置文件路径
756
+ */
757
+ getConfigPath() {
758
+ return this.getConfigFilePath();
759
+ }
760
+ /**
761
+ * 获取默认配置文件路径
762
+ */
763
+ getDefaultConfigPath() {
764
+ return this.defaultConfigPath;
765
+ }
766
+ /**
767
+ * 获取连接配置(包含默认值)
768
+ */
769
+ getConnectionConfig() {
770
+ const config = this.getConfig();
771
+ const connectionConfig = config.connection || {};
772
+ return {
773
+ heartbeatInterval: connectionConfig.heartbeatInterval ?? DEFAULT_CONNECTION_CONFIG.heartbeatInterval,
774
+ heartbeatTimeout: connectionConfig.heartbeatTimeout ?? DEFAULT_CONNECTION_CONFIG.heartbeatTimeout,
775
+ reconnectInterval: connectionConfig.reconnectInterval ?? DEFAULT_CONNECTION_CONFIG.reconnectInterval
776
+ };
777
+ }
778
+ /**
779
+ * 获取心跳检测间隔(毫秒)
780
+ */
781
+ getHeartbeatInterval() {
782
+ return this.getConnectionConfig().heartbeatInterval;
783
+ }
784
+ /**
785
+ * 获取心跳超时时间(毫秒)
786
+ */
787
+ getHeartbeatTimeout() {
788
+ return this.getConnectionConfig().heartbeatTimeout;
789
+ }
790
+ /**
791
+ * 获取重连间隔(毫秒)
792
+ */
793
+ getReconnectInterval() {
794
+ return this.getConnectionConfig().reconnectInterval;
795
+ }
796
+ /**
797
+ * 更新连接配置
798
+ */
799
+ updateConnectionConfig(connectionConfig) {
800
+ const config = this.getMutableConfig();
801
+ if (!config.connection) {
802
+ config.connection = {};
803
+ }
804
+ Object.assign(config.connection, connectionConfig);
805
+ this.saveConfig(config);
806
+ this.emitEvent("config:updated", {
807
+ type: "connection",
808
+ timestamp: /* @__PURE__ */ new Date()
809
+ });
810
+ }
811
+ /**
812
+ * 更新工具使用统计信息的实现
813
+ */
814
+ async updateToolUsageStats(arg1, arg2, arg3) {
815
+ try {
816
+ if (typeof arg2 === "string" && arg3) {
817
+ const serverName = arg1;
818
+ const toolName = arg2;
819
+ const callTime = arg3;
820
+ await Promise.all([
821
+ this._updateMCPServerToolStats(serverName, toolName, callTime),
822
+ this.updateCustomMCPToolStats(serverName, toolName, callTime)
823
+ ]);
824
+ console.log("\u5DE5\u5177\u4F7F\u7528\u7EDF\u8BA1\u5DF2\u66F4\u65B0", { serverName, toolName });
825
+ } else {
826
+ const toolName = arg1;
827
+ const incrementUsageCount = arg2;
828
+ const callTime = (/* @__PURE__ */ new Date()).toISOString();
829
+ await this.updateCustomMCPToolStats(
830
+ toolName,
831
+ callTime,
832
+ incrementUsageCount
833
+ );
834
+ console.log("CustomMCP \u5DE5\u5177\u4F7F\u7528\u7EDF\u8BA1\u5DF2\u66F4\u65B0", { toolName });
835
+ }
836
+ } catch (error) {
837
+ if (typeof arg2 === "string" && arg3) {
838
+ const serverName = arg1;
839
+ const toolName = arg2;
840
+ console.error("\u66F4\u65B0\u5DE5\u5177\u4F7F\u7528\u7EDF\u8BA1\u5931\u8D25", { serverName, toolName, error });
841
+ } else {
842
+ const toolName = arg1;
843
+ console.error("\u66F4\u65B0 CustomMCP \u5DE5\u5177\u4F7F\u7528\u7EDF\u8BA1\u5931\u8D25", { toolName, error });
844
+ }
845
+ }
846
+ }
847
+ /**
848
+ * 更新 MCP 服务工具统计信息(重载方法)
849
+ * @param serviceName 服务名称
850
+ * @param toolName 工具名称
851
+ * @param callTime 调用时间(ISO 8601 格式)
852
+ * @param incrementUsageCount 是否增加使用计数,默认为 true
853
+ */
854
+ async updateMCPServerToolStats(serviceName, toolName, callTime, incrementUsageCount = true) {
855
+ await this._updateMCPServerToolStats(
856
+ serviceName,
857
+ toolName,
858
+ callTime,
859
+ incrementUsageCount
860
+ );
861
+ }
862
+ /**
863
+ * 设置心跳检测间隔
864
+ */
865
+ setHeartbeatInterval(interval) {
866
+ if (interval <= 0) {
867
+ throw new Error("\u5FC3\u8DF3\u68C0\u6D4B\u95F4\u9694\u5FC5\u987B\u5927\u4E8E0");
868
+ }
869
+ this.updateConnectionConfig({ heartbeatInterval: interval });
870
+ }
871
+ /**
872
+ * 设置心跳超时时间
873
+ */
874
+ setHeartbeatTimeout(timeout) {
875
+ if (timeout <= 0) {
876
+ throw new Error("\u5FC3\u8DF3\u8D85\u65F6\u65F6\u95F4\u5FC5\u987B\u5927\u4E8E0");
877
+ }
878
+ this.updateConnectionConfig({ heartbeatTimeout: timeout });
879
+ }
880
+ /**
881
+ * 设置重连间隔
882
+ */
883
+ setReconnectInterval(interval) {
884
+ if (interval <= 0) {
885
+ throw new Error("\u91CD\u8FDE\u95F4\u9694\u5FC5\u987B\u5927\u4E8E0");
886
+ }
887
+ this.updateConnectionConfig({ reconnectInterval: interval });
888
+ }
889
+ /**
890
+ * 获取 ModelScope 配置
891
+ */
892
+ getModelScopeConfig() {
893
+ const config = this.getConfig();
894
+ return config.modelscope || {};
895
+ }
896
+ /**
897
+ * 获取 ModelScope API Key
898
+ * 优先从配置文件读取,其次从环境变量读取
899
+ */
900
+ getModelScopeApiKey() {
901
+ const modelScopeConfig = this.getModelScopeConfig();
902
+ return modelScopeConfig.apiKey || process.env.MODELSCOPE_API_TOKEN;
903
+ }
904
+ /**
905
+ * 更新 ModelScope 配置
906
+ */
907
+ updateModelScopeConfig(modelScopeConfig) {
908
+ const config = this.getMutableConfig();
909
+ if (!config.modelscope) {
910
+ config.modelscope = {};
911
+ }
912
+ Object.assign(config.modelscope, modelScopeConfig);
913
+ this.saveConfig(config);
914
+ this.emitEvent("config:updated", {
915
+ type: "modelscope",
916
+ timestamp: /* @__PURE__ */ new Date()
917
+ });
918
+ }
919
+ /**
920
+ * 设置 ModelScope API Key
921
+ */
922
+ setModelScopeApiKey(apiKey) {
923
+ if (!apiKey || typeof apiKey !== "string") {
924
+ throw new Error("API Key \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");
925
+ }
926
+ this.updateModelScopeConfig({ apiKey });
927
+ }
928
+ /**
929
+ * 获取 customMCP 配置
930
+ */
931
+ getCustomMCPConfig() {
932
+ const config = this.getConfig();
933
+ return config.customMCP || null;
934
+ }
935
+ /**
936
+ * 获取 customMCP 工具列表
937
+ */
938
+ getCustomMCPTools() {
939
+ const customMCPConfig = this.getCustomMCPConfig();
940
+ if (!customMCPConfig || !customMCPConfig.tools) {
941
+ return [];
942
+ }
943
+ return customMCPConfig.tools;
944
+ }
945
+ /**
946
+ * 验证 customMCP 工具配置
947
+ */
948
+ validateCustomMCPTools(tools) {
949
+ if (!Array.isArray(tools)) {
950
+ return false;
951
+ }
952
+ for (const tool of tools) {
953
+ if (!tool.name || typeof tool.name !== "string") {
954
+ console.warn("CustomMCP \u5DE5\u5177\u7F3A\u5C11\u6709\u6548\u7684 name \u5B57\u6BB5", { tool });
955
+ return false;
956
+ }
957
+ if (!tool.description || typeof tool.description !== "string") {
958
+ console.warn("CustomMCP \u5DE5\u5177\u7F3A\u5C11\u6709\u6548\u7684 description \u5B57\u6BB5", {
959
+ toolName: tool.name
960
+ });
961
+ return false;
962
+ }
963
+ if (!tool.inputSchema || typeof tool.inputSchema !== "object") {
964
+ console.warn("CustomMCP \u5DE5\u5177\u7F3A\u5C11\u6709\u6548\u7684 inputSchema \u5B57\u6BB5", {
965
+ toolName: tool.name
966
+ });
967
+ return false;
968
+ }
969
+ if (!tool.handler || typeof tool.handler !== "object") {
970
+ console.warn("CustomMCP \u5DE5\u5177\u7F3A\u5C11\u6709\u6548\u7684 handler \u5B57\u6BB5", {
971
+ toolName: tool.name
972
+ });
973
+ return false;
974
+ }
975
+ if (!["proxy", "function", "http", "script", "chain", "mcp"].includes(
976
+ tool.handler.type
977
+ )) {
978
+ console.warn("CustomMCP \u5DE5\u5177\u7684 handler.type \u7C7B\u578B\u65E0\u6548", {
979
+ toolName: tool.name,
980
+ type: tool.handler.type
981
+ });
982
+ return false;
983
+ }
984
+ if (!this.validateHandlerConfig(tool.name, tool.handler)) {
985
+ return false;
986
+ }
987
+ }
988
+ return true;
989
+ }
990
+ /**
991
+ * 验证处理器配置
992
+ */
993
+ validateHandlerConfig(toolName, handler) {
994
+ switch (handler.type) {
995
+ case "proxy":
996
+ return this.validateProxyHandler(toolName, handler);
997
+ case "http":
998
+ return this.validateHttpHandler(toolName, handler);
999
+ case "function":
1000
+ return this.validateFunctionHandler(toolName, handler);
1001
+ case "script":
1002
+ return this.validateScriptHandler(toolName, handler);
1003
+ case "chain":
1004
+ return this.validateChainHandler(toolName, handler);
1005
+ case "mcp":
1006
+ return this.validateMCPHandler(toolName, handler);
1007
+ default:
1008
+ console.warn("CustomMCP \u5DE5\u5177\u4F7F\u7528\u4E86\u672A\u77E5\u7684\u5904\u7406\u5668\u7C7B\u578B", {
1009
+ toolName,
1010
+ handlerType: handler.type
1011
+ });
1012
+ return false;
1013
+ }
1014
+ }
1015
+ /**
1016
+ * 验证代理处理器配置
1017
+ */
1018
+ validateProxyHandler(toolName, handler) {
1019
+ if (!handler.platform) {
1020
+ console.warn("CustomMCP \u5DE5\u5177\u7684 proxy \u5904\u7406\u5668\u7F3A\u5C11 platform \u5B57\u6BB5", {
1021
+ toolName
1022
+ });
1023
+ return false;
1024
+ }
1025
+ if (!["coze", "openai", "anthropic", "custom"].includes(handler.platform)) {
1026
+ console.warn("CustomMCP \u5DE5\u5177\u7684 proxy \u5904\u7406\u5668\u4F7F\u7528\u4E86\u4E0D\u652F\u6301\u7684\u5E73\u53F0", {
1027
+ toolName,
1028
+ platform: handler.platform
1029
+ });
1030
+ return false;
1031
+ }
1032
+ if (!handler.config || typeof handler.config !== "object") {
1033
+ console.warn("CustomMCP \u5DE5\u5177\u7684 proxy \u5904\u7406\u5668\u7F3A\u5C11 config \u5B57\u6BB5", {
1034
+ toolName
1035
+ });
1036
+ return false;
1037
+ }
1038
+ if (handler.platform === "coze") {
1039
+ if (!handler.config.workflow_id && !handler.config.bot_id) {
1040
+ console.warn(
1041
+ "CustomMCP \u5DE5\u5177\u7684 Coze \u5904\u7406\u5668\u5FC5\u987B\u63D0\u4F9B workflow_id \u6216 bot_id",
1042
+ { toolName }
1043
+ );
1044
+ return false;
1045
+ }
1046
+ }
1047
+ return true;
1048
+ }
1049
+ /**
1050
+ * 验证 HTTP 处理器配置
1051
+ */
1052
+ validateHttpHandler(toolName, handler) {
1053
+ if (!handler.url || typeof handler.url !== "string") {
1054
+ console.warn("CustomMCP \u5DE5\u5177\u7684 http \u5904\u7406\u5668\u7F3A\u5C11\u6709\u6548\u7684 url \u5B57\u6BB5", {
1055
+ toolName
1056
+ });
1057
+ return false;
1058
+ }
1059
+ try {
1060
+ new URL(handler.url);
1061
+ } catch {
1062
+ console.warn("CustomMCP \u5DE5\u5177\u7684 http \u5904\u7406\u5668 url \u683C\u5F0F\u65E0\u6548", {
1063
+ toolName,
1064
+ url: handler.url
1065
+ });
1066
+ return false;
1067
+ }
1068
+ if (handler.method && !["GET", "POST", "PUT", "DELETE", "PATCH"].includes(handler.method)) {
1069
+ console.warn("CustomMCP \u5DE5\u5177\u7684 http \u5904\u7406\u5668\u4F7F\u7528\u4E86\u4E0D\u652F\u6301\u7684 HTTP \u65B9\u6CD5", {
1070
+ toolName,
1071
+ method: handler.method
1072
+ });
1073
+ return false;
1074
+ }
1075
+ return true;
1076
+ }
1077
+ /**
1078
+ * 验证函数处理器配置
1079
+ */
1080
+ validateFunctionHandler(toolName, handler) {
1081
+ if (!handler.module || typeof handler.module !== "string") {
1082
+ console.warn("CustomMCP \u5DE5\u5177\u7684 function \u5904\u7406\u5668\u7F3A\u5C11\u6709\u6548\u7684 module \u5B57\u6BB5", {
1083
+ toolName
1084
+ });
1085
+ return false;
1086
+ }
1087
+ if (!handler.function || typeof handler.function !== "string") {
1088
+ console.warn("CustomMCP \u5DE5\u5177\u7684 function \u5904\u7406\u5668\u7F3A\u5C11\u6709\u6548\u7684 function \u5B57\u6BB5", {
1089
+ toolName
1090
+ });
1091
+ return false;
1092
+ }
1093
+ return true;
1094
+ }
1095
+ /**
1096
+ * 验证脚本处理器配置
1097
+ */
1098
+ validateScriptHandler(toolName, handler) {
1099
+ if (!handler.script || typeof handler.script !== "string") {
1100
+ console.warn("CustomMCP \u5DE5\u5177\u7684 script \u5904\u7406\u5668\u7F3A\u5C11\u6709\u6548\u7684 script \u5B57\u6BB5", {
1101
+ toolName
1102
+ });
1103
+ return false;
1104
+ }
1105
+ if (handler.interpreter && !["node", "python", "bash"].includes(handler.interpreter)) {
1106
+ console.warn("CustomMCP \u5DE5\u5177\u7684 script \u5904\u7406\u5668\u4F7F\u7528\u4E86\u4E0D\u652F\u6301\u7684\u89E3\u91CA\u5668", {
1107
+ toolName,
1108
+ interpreter: handler.interpreter
1109
+ });
1110
+ return false;
1111
+ }
1112
+ return true;
1113
+ }
1114
+ /**
1115
+ * 验证链式处理器配置
1116
+ */
1117
+ validateChainHandler(toolName, handler) {
1118
+ if (!handler.tools || !Array.isArray(handler.tools) || handler.tools.length === 0) {
1119
+ console.warn("CustomMCP \u5DE5\u5177\u7684 chain \u5904\u7406\u5668\u7F3A\u5C11\u6709\u6548\u7684 tools \u6570\u7EC4", {
1120
+ toolName
1121
+ });
1122
+ return false;
1123
+ }
1124
+ if (!["sequential", "parallel"].includes(handler.mode)) {
1125
+ console.warn("CustomMCP \u5DE5\u5177\u7684 chain \u5904\u7406\u5668\u4F7F\u7528\u4E86\u4E0D\u652F\u6301\u7684\u6267\u884C\u6A21\u5F0F", {
1126
+ toolName,
1127
+ mode: handler.mode
1128
+ });
1129
+ return false;
1130
+ }
1131
+ if (!["stop", "continue", "retry"].includes(handler.error_handling)) {
1132
+ console.warn("CustomMCP \u5DE5\u5177\u7684 chain \u5904\u7406\u5668\u4F7F\u7528\u4E86\u4E0D\u652F\u6301\u7684\u9519\u8BEF\u5904\u7406\u7B56\u7565", {
1133
+ toolName,
1134
+ errorHandling: handler.error_handling
1135
+ });
1136
+ return false;
1137
+ }
1138
+ return true;
1139
+ }
1140
+ /**
1141
+ * 验证 MCP 处理器配置
1142
+ */
1143
+ validateMCPHandler(toolName, handler) {
1144
+ if (!handler.config || typeof handler.config !== "object") {
1145
+ console.warn("CustomMCP \u5DE5\u5177\u7684 mcp \u5904\u7406\u5668\u7F3A\u5C11 config \u5B57\u6BB5", { toolName });
1146
+ return false;
1147
+ }
1148
+ if (!handler.config.serviceName || typeof handler.config.serviceName !== "string") {
1149
+ console.warn("CustomMCP \u5DE5\u5177\u7684 mcp \u5904\u7406\u5668\u7F3A\u5C11\u6709\u6548\u7684 serviceName", {
1150
+ toolName
1151
+ });
1152
+ return false;
1153
+ }
1154
+ if (!handler.config.toolName || typeof handler.config.toolName !== "string") {
1155
+ console.warn("CustomMCP \u5DE5\u5177\u7684 mcp \u5904\u7406\u5668\u7F3A\u5C11\u6709\u6548\u7684 toolName", {
1156
+ toolName
1157
+ });
1158
+ return false;
1159
+ }
1160
+ return true;
1161
+ }
1162
+ /**
1163
+ * 检查是否配置了有效的 customMCP 工具
1164
+ */
1165
+ hasValidCustomMCPTools() {
1166
+ try {
1167
+ const tools = this.getCustomMCPTools();
1168
+ if (tools.length === 0) {
1169
+ return false;
1170
+ }
1171
+ return this.validateCustomMCPTools(tools);
1172
+ } catch (error) {
1173
+ console.error("\u68C0\u67E5 customMCP \u5DE5\u5177\u914D\u7F6E\u65F6\u51FA\u9519", { error });
1174
+ return false;
1175
+ }
1176
+ }
1177
+ /**
1178
+ * 添加自定义 MCP 工具
1179
+ */
1180
+ addCustomMCPTool(tool) {
1181
+ if (!tool || typeof tool !== "object") {
1182
+ throw new Error("\u5DE5\u5177\u914D\u7F6E\u4E0D\u80FD\u4E3A\u7A7A");
1183
+ }
1184
+ const config = this.getMutableConfig();
1185
+ if (!config.customMCP) {
1186
+ config.customMCP = { tools: [] };
1187
+ }
1188
+ const existingTool = config.customMCP.tools.find(
1189
+ (t) => t.name === tool.name
1190
+ );
1191
+ if (existingTool) {
1192
+ throw new Error(`\u5DE5\u5177 "${tool.name}" \u5DF2\u5B58\u5728`);
1193
+ }
1194
+ if (!this.validateCustomMCPTools([tool])) {
1195
+ throw new Error("\u5DE5\u5177\u914D\u7F6E\u9A8C\u8BC1\u5931\u8D25");
1196
+ }
1197
+ config.customMCP.tools.unshift(tool);
1198
+ this.saveConfig(config);
1199
+ console.log("\u6210\u529F\u6DFB\u52A0\u81EA\u5B9A\u4E49 MCP \u5DE5\u5177", { toolName: tool.name });
1200
+ }
1201
+ /**
1202
+ * 批量添加自定义 MCP 工具
1203
+ * @param tools 要添加的工具数组
1204
+ */
1205
+ async addCustomMCPTools(tools) {
1206
+ if (!Array.isArray(tools)) {
1207
+ throw new Error("\u5DE5\u5177\u914D\u7F6E\u5FC5\u987B\u662F\u6570\u7EC4");
1208
+ }
1209
+ if (tools.length === 0) {
1210
+ return;
1211
+ }
1212
+ const config = this.getMutableConfig();
1213
+ if (!config.customMCP) {
1214
+ config.customMCP = { tools: [] };
1215
+ }
1216
+ const existingNames = new Set(
1217
+ config.customMCP.tools.map((tool) => tool.name)
1218
+ );
1219
+ const newTools = tools.filter((tool) => !existingNames.has(tool.name));
1220
+ if (newTools.length > 0) {
1221
+ if (!this.validateCustomMCPTools(newTools)) {
1222
+ throw new Error("\u5DE5\u5177\u914D\u7F6E\u9A8C\u8BC1\u5931\u8D25");
1223
+ }
1224
+ config.customMCP.tools.push(...newTools);
1225
+ this.saveConfig(config);
1226
+ this.emitEvent("config:updated", {
1227
+ type: "customMCP",
1228
+ timestamp: /* @__PURE__ */ new Date()
1229
+ });
1230
+ console.log("\u6210\u529F\u6279\u91CF\u6DFB\u52A0\u81EA\u5B9A\u4E49 MCP \u5DE5\u5177", {
1231
+ count: newTools.length,
1232
+ toolNames: newTools.map((t) => t.name)
1233
+ });
1234
+ }
1235
+ }
1236
+ /**
1237
+ * 删除自定义 MCP 工具
1238
+ */
1239
+ removeCustomMCPTool(toolName) {
1240
+ if (!toolName || typeof toolName !== "string") {
1241
+ throw new Error("\u5DE5\u5177\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A");
1242
+ }
1243
+ const config = this.getMutableConfig();
1244
+ if (!config.customMCP || !config.customMCP.tools) {
1245
+ throw new Error("\u672A\u914D\u7F6E\u81EA\u5B9A\u4E49 MCP \u5DE5\u5177");
1246
+ }
1247
+ const toolIndex = config.customMCP.tools.findIndex(
1248
+ (t) => t.name === toolName
1249
+ );
1250
+ if (toolIndex === -1) {
1251
+ throw new Error(`\u5DE5\u5177 "${toolName}" \u4E0D\u5B58\u5728`);
1252
+ }
1253
+ config.customMCP.tools.splice(toolIndex, 1);
1254
+ this.saveConfig(config);
1255
+ console.log("\u6210\u529F\u5220\u9664\u81EA\u5B9A\u4E49 MCP \u5DE5\u5177", { toolName });
1256
+ }
1257
+ /**
1258
+ * 更新单个自定义 MCP 工具配置
1259
+ * @param toolName 工具名称
1260
+ * @param updatedTool 更新后的工具配置
1261
+ */
1262
+ updateCustomMCPTool(toolName, updatedTool) {
1263
+ if (!toolName || typeof toolName !== "string") {
1264
+ throw new Error("\u5DE5\u5177\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A");
1265
+ }
1266
+ if (!updatedTool || typeof updatedTool !== "object") {
1267
+ throw new Error("\u66F4\u65B0\u540E\u7684\u5DE5\u5177\u914D\u7F6E\u4E0D\u80FD\u4E3A\u7A7A");
1268
+ }
1269
+ const config = this.getMutableConfig();
1270
+ if (!config.customMCP || !config.customMCP.tools) {
1271
+ throw new Error("\u672A\u914D\u7F6E\u81EA\u5B9A\u4E49 MCP \u5DE5\u5177");
1272
+ }
1273
+ const toolIndex = config.customMCP.tools.findIndex(
1274
+ (t) => t.name === toolName
1275
+ );
1276
+ if (toolIndex === -1) {
1277
+ throw new Error(`\u5DE5\u5177 "${toolName}" \u4E0D\u5B58\u5728`);
1278
+ }
1279
+ if (!this.validateCustomMCPTools([updatedTool])) {
1280
+ throw new Error("\u66F4\u65B0\u540E\u7684\u5DE5\u5177\u914D\u7F6E\u9A8C\u8BC1\u5931\u8D25");
1281
+ }
1282
+ config.customMCP.tools[toolIndex] = updatedTool;
1283
+ this.saveConfig(config);
1284
+ console.log("\u6210\u529F\u66F4\u65B0\u81EA\u5B9A\u4E49 MCP \u5DE5\u5177", { toolName });
1285
+ }
1286
+ /**
1287
+ * 更新自定义 MCP 工具配置
1288
+ */
1289
+ updateCustomMCPTools(tools) {
1290
+ if (!Array.isArray(tools)) {
1291
+ throw new Error("\u5DE5\u5177\u914D\u7F6E\u5FC5\u987B\u662F\u6570\u7EC4");
1292
+ }
1293
+ if (!this.validateCustomMCPTools(tools)) {
1294
+ throw new Error("\u5DE5\u5177\u914D\u7F6E\u9A8C\u8BC1\u5931\u8D25");
1295
+ }
1296
+ const config = this.getMutableConfig();
1297
+ if (!config.customMCP) {
1298
+ config.customMCP = { tools: [] };
1299
+ }
1300
+ config.customMCP.tools = tools;
1301
+ this.saveConfig(config);
1302
+ this.emitEvent("config:updated", {
1303
+ type: "customMCP",
1304
+ timestamp: /* @__PURE__ */ new Date()
1305
+ });
1306
+ console.log("\u6210\u529F\u66F4\u65B0\u81EA\u5B9A\u4E49 MCP \u5DE5\u5177\u914D\u7F6E", { count: tools.length });
1307
+ }
1308
+ /**
1309
+ * 获取 Web UI 配置
1310
+ */
1311
+ getWebUIConfig() {
1312
+ const config = this.getConfig();
1313
+ return config.webUI || {};
1314
+ }
1315
+ /**
1316
+ * 获取 Web UI 端口号
1317
+ */
1318
+ getWebUIPort() {
1319
+ const webUIConfig = this.getWebUIConfig();
1320
+ return webUIConfig.port ?? 9999;
1321
+ }
1322
+ /**
1323
+ * 通知 Web 界面配置已更新
1324
+ * 如果 Web 服务器正在运行,通过 WebSocket 广播配置更新
1325
+ */
1326
+ notifyConfigUpdate(config) {
1327
+ try {
1328
+ const webServer = global.__webServer;
1329
+ if (webServer && typeof webServer.broadcastConfigUpdate === "function") {
1330
+ webServer.broadcastConfigUpdate(config);
1331
+ console.log("\u5DF2\u901A\u8FC7 WebSocket \u5E7F\u64AD\u914D\u7F6E\u66F4\u65B0");
1332
+ }
1333
+ } catch (error) {
1334
+ console.warn(
1335
+ "\u901A\u77E5 Web \u754C\u9762\u914D\u7F6E\u66F4\u65B0\u5931\u8D25:",
1336
+ error instanceof Error ? error.message : String(error)
1337
+ );
1338
+ }
1339
+ }
1340
+ /**
1341
+ * 更新 Web UI 配置
1342
+ */
1343
+ updateWebUIConfig(webUIConfig) {
1344
+ const config = this.getMutableConfig();
1345
+ if (!config.webUI) {
1346
+ config.webUI = {};
1347
+ }
1348
+ Object.assign(config.webUI, webUIConfig);
1349
+ this.saveConfig(config);
1350
+ this.emitEvent("config:updated", {
1351
+ type: "webui",
1352
+ timestamp: /* @__PURE__ */ new Date()
1353
+ });
1354
+ }
1355
+ /**
1356
+ * 设置 Web UI 端口号
1357
+ */
1358
+ setWebUIPort(port) {
1359
+ if (!Number.isInteger(port) || port <= 0 || port > 65535) {
1360
+ throw new Error("\u7AEF\u53E3\u53F7\u5FC5\u987B\u662F 1-65535 \u4E4B\u95F4\u7684\u6574\u6570");
1361
+ }
1362
+ this.updateWebUIConfig({ port });
1363
+ }
1364
+ updatePlatformConfig(platformName, platformConfig) {
1365
+ const config = this.getMutableConfig();
1366
+ if (!config.platforms) {
1367
+ config.platforms = {};
1368
+ }
1369
+ config.platforms[platformName] = platformConfig;
1370
+ this.saveConfig(config);
1371
+ this.emitEvent("config:updated", {
1372
+ type: "platform",
1373
+ platformName,
1374
+ timestamp: /* @__PURE__ */ new Date()
1375
+ });
1376
+ }
1377
+ /**
1378
+ * 获取扣子平台配置
1379
+ */
1380
+ getCozePlatformConfig() {
1381
+ const config = this.getConfig();
1382
+ const cozeConfig = config.platforms?.coze;
1383
+ if (!cozeConfig || !cozeConfig.token) {
1384
+ return null;
1385
+ }
1386
+ return {
1387
+ token: cozeConfig.token
1388
+ };
1389
+ }
1390
+ /**
1391
+ * 获取扣子 API Token
1392
+ */
1393
+ getCozeToken() {
1394
+ const cozeConfig = this.getCozePlatformConfig();
1395
+ return cozeConfig?.token || null;
1396
+ }
1397
+ /**
1398
+ * 设置扣子平台配置
1399
+ */
1400
+ setCozePlatformConfig(config) {
1401
+ if (!config.token || typeof config.token !== "string" || config.token.trim() === "") {
1402
+ throw new Error("\u6263\u5B50 API Token \u4E0D\u80FD\u4E3A\u7A7A");
1403
+ }
1404
+ this.updatePlatformConfig("coze", {
1405
+ token: config.token.trim()
1406
+ });
1407
+ }
1408
+ /**
1409
+ * 检查扣子平台配置是否有效
1410
+ */
1411
+ isCozeConfigValid() {
1412
+ const cozeConfig = this.getCozePlatformConfig();
1413
+ return cozeConfig !== null && typeof cozeConfig.token === "string" && cozeConfig.token.trim() !== "";
1414
+ }
1415
+ /**
1416
+ * 更新 mcpServerConfig 中的工具使用统计信息(内部实现)
1417
+ * @param serverName 服务名称
1418
+ * @param toolName 工具名称
1419
+ * @param callTime 调用时间(ISO 8601 格式)
1420
+ * @param incrementUsageCount 是否增加使用计数
1421
+ * @private
1422
+ */
1423
+ async _updateMCPServerToolStats(serverName, toolName, callTime, incrementUsageCount = true) {
1424
+ const config = this.getMutableConfig();
1425
+ if (!config.mcpServerConfig) {
1426
+ config.mcpServerConfig = {};
1427
+ }
1428
+ if (!config.mcpServerConfig[serverName]) {
1429
+ config.mcpServerConfig[serverName] = { tools: {} };
1430
+ }
1431
+ if (!config.mcpServerConfig[serverName].tools[toolName]) {
1432
+ config.mcpServerConfig[serverName].tools[toolName] = {
1433
+ enable: true
1434
+ // 默认启用
1435
+ };
1436
+ }
1437
+ const toolConfig = config.mcpServerConfig[serverName].tools[toolName];
1438
+ const currentUsageCount = toolConfig.usageCount || 0;
1439
+ const currentLastUsedTime = toolConfig.lastUsedTime;
1440
+ if (incrementUsageCount) {
1441
+ toolConfig.usageCount = currentUsageCount + 1;
1442
+ }
1443
+ if (!currentLastUsedTime || new Date(callTime) > new Date(currentLastUsedTime)) {
1444
+ toolConfig.lastUsedTime = dayjs(callTime).format("YYYY-MM-DD HH:mm:ss");
1445
+ }
1446
+ this.saveConfig(config);
1447
+ }
1448
+ /**
1449
+ * 更新 customMCP 工具使用统计信息的实现
1450
+ * @private
1451
+ */
1452
+ async updateCustomMCPToolStats(arg1, arg2, arg3) {
1453
+ try {
1454
+ let toolName;
1455
+ let callTime;
1456
+ let incrementUsageCount = true;
1457
+ let logPrefix;
1458
+ if (typeof arg3 === "string") {
1459
+ const serverName = arg1;
1460
+ toolName = `${serverName}__${arg2}`;
1461
+ callTime = arg3;
1462
+ logPrefix = `${serverName}/${arg2}`;
1463
+ } else {
1464
+ toolName = arg1;
1465
+ callTime = arg2;
1466
+ incrementUsageCount = arg3 || true;
1467
+ logPrefix = toolName;
1468
+ }
1469
+ const customTools = this.getCustomMCPTools();
1470
+ const toolIndex = customTools.findIndex((tool2) => tool2.name === toolName);
1471
+ if (toolIndex === -1) {
1472
+ return;
1473
+ }
1474
+ const updatedTools = [...customTools];
1475
+ const tool = updatedTools[toolIndex];
1476
+ if (!tool.stats) {
1477
+ tool.stats = {};
1478
+ }
1479
+ const currentUsageCount = tool.stats.usageCount || 0;
1480
+ const currentLastUsedTime = tool.stats.lastUsedTime;
1481
+ if (incrementUsageCount) {
1482
+ tool.stats.usageCount = currentUsageCount + 1;
1483
+ }
1484
+ if (!currentLastUsedTime || new Date(callTime) > new Date(currentLastUsedTime)) {
1485
+ tool.stats.lastUsedTime = dayjs(callTime).format("YYYY-MM-DD HH:mm:ss");
1486
+ }
1487
+ await this.updateCustomMCPTools(updatedTools);
1488
+ } catch (error) {
1489
+ if (typeof arg3 === "string") {
1490
+ const serverName = arg1;
1491
+ const toolName = arg2;
1492
+ console.error("\u66F4\u65B0 customMCP \u5DE5\u5177\u7EDF\u8BA1\u4FE1\u606F\u5931\u8D25", {
1493
+ serverName,
1494
+ toolName,
1495
+ error
1496
+ });
1497
+ } else {
1498
+ const toolName = arg1;
1499
+ console.error("\u66F4\u65B0 customMCP \u5DE5\u5177\u7EDF\u8BA1\u4FE1\u606F\u5931\u8D25", { toolName, error });
1500
+ }
1501
+ }
1502
+ }
1503
+ /**
1504
+ * 获取统计更新锁(确保同一工具的统计更新串行执行)
1505
+ * @param toolKey 工具键
1506
+ * @private
1507
+ */
1508
+ async acquireStatsUpdateLock(toolKey) {
1509
+ if (this.statsUpdateLocks.has(toolKey)) {
1510
+ console.log("\u5DE5\u5177\u7EDF\u8BA1\u66F4\u65B0\u6B63\u5728\u8FDB\u884C\u4E2D\uFF0C\u8DF3\u8FC7\u672C\u6B21\u66F4\u65B0", { toolKey });
1511
+ return false;
1512
+ }
1513
+ const updatePromise = new Promise((resolve4) => {
1514
+ });
1515
+ this.statsUpdateLocks.set(toolKey, updatePromise);
1516
+ const timeout = setTimeout(() => {
1517
+ this.releaseStatsUpdateLock(toolKey);
1518
+ }, this.STATS_UPDATE_TIMEOUT);
1519
+ this.statsUpdateLockTimeouts.set(toolKey, timeout);
1520
+ return true;
1521
+ }
1522
+ /**
1523
+ * 释放统计更新锁
1524
+ * @param toolKey 工具键
1525
+ * @private
1526
+ */
1527
+ releaseStatsUpdateLock(toolKey) {
1528
+ this.statsUpdateLocks.delete(toolKey);
1529
+ const timeout = this.statsUpdateLockTimeouts.get(toolKey);
1530
+ if (timeout) {
1531
+ clearTimeout(timeout);
1532
+ }
1533
+ this.statsUpdateLockTimeouts.delete(toolKey);
1534
+ console.log("\u5DF2\u91CA\u653E\u5DE5\u5177\u7684\u7EDF\u8BA1\u66F4\u65B0\u9501", { toolKey });
1535
+ }
1536
+ /**
1537
+ * 带并发控制的工具统计更新(CustomMCP 工具)
1538
+ * @param toolName 工具名称
1539
+ * @param incrementUsageCount 是否增加使用计数
1540
+ */
1541
+ async updateToolUsageStatsWithLock(toolName, incrementUsageCount = true) {
1542
+ const toolKey = `custommcp_${toolName}`;
1543
+ if (!await this.acquireStatsUpdateLock(toolKey)) {
1544
+ return;
1545
+ }
1546
+ try {
1547
+ await this.updateToolUsageStats(toolName, incrementUsageCount);
1548
+ console.log("\u5DE5\u5177\u7EDF\u8BA1\u66F4\u65B0\u5B8C\u6210", { toolName });
1549
+ } catch (error) {
1550
+ console.error("\u5DE5\u5177\u7EDF\u8BA1\u66F4\u65B0\u5931\u8D25", { toolName, error });
1551
+ throw error;
1552
+ } finally {
1553
+ this.releaseStatsUpdateLock(toolKey);
1554
+ }
1555
+ }
1556
+ /**
1557
+ * 带并发控制的工具统计更新(MCP 服务工具)
1558
+ * @param serviceName 服务名称
1559
+ * @param toolName 工具名称
1560
+ * @param callTime 调用时间
1561
+ * @param incrementUsageCount 是否增加使用计数
1562
+ */
1563
+ async updateMCPServerToolStatsWithLock(serviceName, toolName, callTime, incrementUsageCount = true) {
1564
+ const toolKey = `mcpserver_${serviceName}_${toolName}`;
1565
+ if (!await this.acquireStatsUpdateLock(toolKey)) {
1566
+ return;
1567
+ }
1568
+ try {
1569
+ await this.updateMCPServerToolStats(
1570
+ serviceName,
1571
+ toolName,
1572
+ callTime,
1573
+ incrementUsageCount
1574
+ );
1575
+ console.log("MCP \u670D\u52A1\u5DE5\u5177\u7EDF\u8BA1\u66F4\u65B0\u5B8C\u6210", { serviceName, toolName });
1576
+ } catch (error) {
1577
+ console.error("MCP \u670D\u52A1\u5DE5\u5177\u7EDF\u8BA1\u66F4\u65B0\u5931\u8D25", {
1578
+ serviceName,
1579
+ toolName,
1580
+ error
1581
+ });
1582
+ throw error;
1583
+ } finally {
1584
+ this.releaseStatsUpdateLock(toolKey);
1585
+ }
1586
+ }
1587
+ /**
1588
+ * 清理所有统计更新锁(用于异常恢复)
1589
+ */
1590
+ clearAllStatsUpdateLocks() {
1591
+ const lockCount = this.statsUpdateLocks.size;
1592
+ this.statsUpdateLocks.clear();
1593
+ for (const timeout of this.statsUpdateLockTimeouts.values()) {
1594
+ clearTimeout(timeout);
1595
+ }
1596
+ this.statsUpdateLockTimeouts.clear();
1597
+ if (lockCount > 0) {
1598
+ console.log("\u5DF2\u6E05\u7406\u7EDF\u8BA1\u66F4\u65B0\u9501", { count: lockCount });
1599
+ }
1600
+ }
1601
+ /**
1602
+ * 获取统计更新锁状态(用于调试和监控)
1603
+ */
1604
+ getStatsUpdateLocks() {
1605
+ return Array.from(this.statsUpdateLocks.keys());
1606
+ }
1607
+ /**
1608
+ * 获取工具调用日志配置
1609
+ */
1610
+ getToolCallLogConfig() {
1611
+ const config = this.getConfig();
1612
+ return config.toolCallLog || {};
1613
+ }
1614
+ /**
1615
+ * 更新工具调用日志配置
1616
+ */
1617
+ updateToolCallLogConfig(toolCallLogConfig) {
1618
+ const config = this.getMutableConfig();
1619
+ if (!config.toolCallLog) {
1620
+ config.toolCallLog = {};
1621
+ }
1622
+ Object.assign(config.toolCallLog, toolCallLogConfig);
1623
+ this.saveConfig(config);
1624
+ }
1625
+ /**
1626
+ * 获取配置目录路径(与配置文件同级目录)
1627
+ */
1628
+ getConfigDir() {
1629
+ return process.env.XIAOZHI_CONFIG_DIR || process.cwd();
1630
+ }
1631
+ /**
1632
+ * 获取 TTS 配置
1633
+ */
1634
+ getTTSConfig() {
1635
+ const config = this.getConfig();
1636
+ return config.tts || {};
1637
+ }
1638
+ /**
1639
+ * 获取 ASR 配置
1640
+ */
1641
+ getASRConfig() {
1642
+ const config = this.getConfig();
1643
+ return config.asr || {};
1644
+ }
1645
+ /**
1646
+ * 获取 LLM 配置
1647
+ */
1648
+ getLLMConfig() {
1649
+ const config = this.getConfig();
1650
+ return config.llm || null;
1651
+ }
1652
+ /**
1653
+ * 检查 LLM 配置是否有效
1654
+ */
1655
+ isLLMConfigValid() {
1656
+ const llmConfig = this.getLLMConfig();
1657
+ return llmConfig !== null && typeof llmConfig.model === "string" && llmConfig.model.trim() !== "" && typeof llmConfig.apiKey === "string" && llmConfig.apiKey.trim() !== "" && typeof llmConfig.baseURL === "string" && llmConfig.baseURL.trim() !== "";
1658
+ }
1659
+ /**
1660
+ * 更新 TTS 配置
1661
+ */
1662
+ updateTTSConfig(ttsConfig) {
1663
+ const config = this.getMutableConfig();
1664
+ if (!config.tts) {
1665
+ config.tts = {};
1666
+ }
1667
+ Object.assign(config.tts, ttsConfig);
1668
+ this.saveConfig(config);
1669
+ this.emitEvent("config:updated", {
1670
+ type: "tts",
1671
+ timestamp: /* @__PURE__ */ new Date()
1672
+ });
1673
+ }
1674
+ };
1675
+ configManager = ConfigManager.getInstance();
1676
+ }
1677
+ });
1678
+
1679
+ // ../mcp-core/types.ts
1680
+ var init_types = __esm({
1681
+ "../mcp-core/types.ts"() {
1682
+ "use strict";
1683
+ }
1684
+ });
1685
+
1686
+ // ../mcp-core/transport-factory.ts
1687
+ import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
1688
+ import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
1689
+ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
1690
+ import { EventSource } from "eventsource";
1691
+ var globalThisAny;
1692
+ var init_transport_factory = __esm({
1693
+ "../mcp-core/transport-factory.ts"() {
1694
+ "use strict";
1695
+ init_types();
1696
+ globalThisAny = typeof globalThis !== "undefined" ? globalThis : global;
1697
+ if (typeof globalThisAny !== "undefined" && !globalThisAny.EventSource) {
1698
+ globalThisAny.EventSource = EventSource;
1699
+ }
1700
+ }
1701
+ });
1702
+
1703
+ // ../mcp-core/utils/type-normalizer.ts
1704
+ var TypeFieldNormalizer;
1705
+ var init_type_normalizer = __esm({
1706
+ "../mcp-core/utils/type-normalizer.ts"() {
1707
+ "use strict";
1708
+ ((TypeFieldNormalizer2) => {
1709
+ function normalizeTypeField2(config) {
1710
+ if (!config || typeof config !== "object") {
1711
+ return config;
1712
+ }
1713
+ if (!("type" in config)) {
1714
+ return config;
1715
+ }
1716
+ const originalType = config.type;
1717
+ if (originalType === "stdio" || originalType === "sse" || originalType === "http") {
1718
+ return config;
1719
+ }
1720
+ const normalizedType = normalizeTypeValue(originalType);
1721
+ if (normalizedType === "stdio" || normalizedType === "sse" || normalizedType === "http") {
1722
+ return {
1723
+ ...config,
1724
+ type: normalizedType
1725
+ };
1726
+ }
1727
+ return config;
1728
+ }
1729
+ TypeFieldNormalizer2.normalizeTypeField = normalizeTypeField2;
1730
+ __name(normalizeTypeField2, "normalizeTypeField");
1731
+ function normalizeTypeValue(type) {
1732
+ if (type === "http" || type === "streamable-http" || type === "streamable_http" || type === "streamableHttp") {
1733
+ return "http";
1734
+ }
1735
+ if (type === "sse" || type === "s_se" || type === "s-se") {
1736
+ return "sse";
1737
+ }
1738
+ if (type === "stdio") {
1739
+ return "stdio";
1740
+ }
1741
+ return convertToStandardFormat(type);
1742
+ }
1743
+ TypeFieldNormalizer2.normalizeTypeValue = normalizeTypeValue;
1744
+ __name(normalizeTypeValue, "normalizeTypeValue");
1745
+ function convertToStandardFormat(str) {
1746
+ const lowered = str.toLowerCase();
1747
+ if (lowered.includes("http") || lowered.includes("streamable")) {
1748
+ return "http";
1749
+ }
1750
+ if (lowered.includes("sse")) {
1751
+ return "sse";
1752
+ }
1753
+ if (lowered.includes("stdio")) {
1754
+ return "stdio";
1755
+ }
1756
+ return str;
1757
+ }
1758
+ __name(convertToStandardFormat, "convertToStandardFormat");
1759
+ })(TypeFieldNormalizer || (TypeFieldNormalizer = {}));
1760
+ }
1761
+ });
1762
+
1763
+ // ../mcp-core/utils/validators.ts
1764
+ var init_validators = __esm({
1765
+ "../mcp-core/utils/validators.ts"() {
1766
+ "use strict";
1767
+ init_types();
1768
+ init_type_normalizer();
1769
+ }
1770
+ });
1771
+
1772
+ // ../mcp-core/utils/index.ts
1773
+ var init_utils = __esm({
1774
+ "../mcp-core/utils/index.ts"() {
1775
+ "use strict";
1776
+ init_type_normalizer();
1777
+ init_validators();
1778
+ }
1779
+ });
1780
+
1781
+ // ../mcp-core/connection.ts
1782
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
1783
+ var init_connection = __esm({
1784
+ "../mcp-core/connection.ts"() {
1785
+ "use strict";
1786
+ init_transport_factory();
1787
+ init_types();
1788
+ init_utils();
1789
+ }
1790
+ });
1791
+
1792
+ // ../mcp-core/manager.ts
1793
+ import { EventEmitter } from "events";
1794
+ var init_manager2 = __esm({
1795
+ "../mcp-core/manager.ts"() {
1796
+ "use strict";
1797
+ init_connection();
1798
+ init_types();
1799
+ }
1800
+ });
1801
+
1802
+ // ../mcp-core/index.ts
1803
+ var init_mcp_core = __esm({
1804
+ "../mcp-core/index.ts"() {
1805
+ "use strict";
1806
+ init_types();
1807
+ init_types();
1808
+ init_connection();
1809
+ init_manager2();
1810
+ init_transport_factory();
1811
+ init_utils();
1812
+ init_types();
1813
+ }
1814
+ });
1815
+
1816
+ // ../config/adapter.ts
1817
+ import { dirname as dirname2, isAbsolute, resolve as resolve2 } from "path";
1818
+ var init_adapter = __esm({
1819
+ "../config/adapter.ts"() {
1820
+ "use strict";
1821
+ init_mcp_core();
1822
+ init_resolver();
1823
+ }
1824
+ });
1825
+
1826
+ // ../config/initializer.ts
1827
+ import {
1828
+ copyFileSync as copyFileSync2,
1829
+ existsSync as existsSync3,
1830
+ mkdirSync,
1831
+ readdirSync,
1832
+ statSync
1833
+ } from "fs";
1834
+ import path2 from "path";
1835
+ import { dirname as dirname3, resolve as resolve3 } from "path";
1836
+ import { fileURLToPath as fileURLToPath2 } from "url";
1837
+ var __dirname2, ConfigInitializer;
1838
+ var init_initializer = __esm({
1839
+ "../config/initializer.ts"() {
1840
+ "use strict";
1841
+ __dirname2 = dirname3(fileURLToPath2(import.meta.url));
1842
+ ConfigInitializer = class _ConfigInitializer {
1843
+ static {
1844
+ __name(this, "ConfigInitializer");
1845
+ }
1846
+ /**
1847
+ * 初始化默认配置
1848
+ *
1849
+ * 复制整个默认模板目录到用户家目录的 .xiaozhi-client
1850
+ * 这包括 mcpServers/ 目录和其他必要文件
1851
+ *
1852
+ * @returns 创建的项目目录路径
1853
+ * @throws 如果无法获取用户家目录或默认配置模板不存在
1854
+ */
1855
+ static async initializeDefaultConfig() {
1856
+ const homeDir = process.env.HOME || process.env.USERPROFILE;
1857
+ if (!homeDir) {
1858
+ throw new Error("\u65E0\u6CD5\u83B7\u53D6\u7528\u6237\u5BB6\u76EE\u5F55");
1859
+ }
1860
+ const xiaozhiClientDir = path2.join(homeDir, ".xiaozhi-client");
1861
+ if (existsSync3(xiaozhiClientDir)) {
1862
+ return xiaozhiClientDir;
1863
+ }
1864
+ mkdirSync(xiaozhiClientDir, { recursive: true });
1865
+ const defaultTemplateDir = _ConfigInitializer.getDefaultTemplateDir();
1866
+ if (!defaultTemplateDir) {
1867
+ throw new Error("\u9ED8\u8BA4\u914D\u7F6E\u6A21\u677F\u4E0D\u5B58\u5728\uFF0C\u8BF7\u68C0\u67E5\u9879\u76EE\u6A21\u677F\u6587\u4EF6\u662F\u5426\u5B58\u5728");
1868
+ }
1869
+ _ConfigInitializer.copyDirectoryRecursive(
1870
+ defaultTemplateDir,
1871
+ xiaozhiClientDir,
1872
+ ["template.json", ".git", "node_modules"]
1873
+ );
1874
+ return xiaozhiClientDir;
1875
+ }
1876
+ /**
1877
+ * 递归复制目录
1878
+ *
1879
+ * @param srcDir 源目录
1880
+ * @param destDir 目标目录
1881
+ * @param exclude 要排除的文件/目录列表
1882
+ */
1883
+ static copyDirectoryRecursive(srcDir, destDir, exclude = []) {
1884
+ const items = readdirSync(srcDir);
1885
+ for (const item of items) {
1886
+ if (exclude.includes(item)) {
1887
+ continue;
1888
+ }
1889
+ const srcPath = path2.join(srcDir, item);
1890
+ const destPath = path2.join(destDir, item);
1891
+ const stat = statSync(srcPath);
1892
+ if (stat.isDirectory()) {
1893
+ mkdirSync(destPath, { recursive: true });
1894
+ _ConfigInitializer.copyDirectoryRecursive(srcPath, destPath, exclude);
1895
+ } else {
1896
+ copyFileSync2(srcPath, destPath);
1897
+ }
1898
+ }
1899
+ }
1900
+ /**
1901
+ * 获取默认模板目录路径
1902
+ *
1903
+ * 在多个可能的路径中查找默认模板目录
1904
+ *
1905
+ * @returns 找到的默认模板目录路径,如果都不存在则返回 null
1906
+ */
1907
+ static getDefaultTemplateDir() {
1908
+ const possiblePaths = [
1909
+ // 迁移后:src/config/ 或 dist/config/ → 项目根 templates/default/
1910
+ resolve3(__dirname2, "..", "..", "templates", "default"),
1911
+ // 从 CWD 查找(兼容各种启动场景)
1912
+ resolve3(process.cwd(), "templates", "default")
1913
+ ];
1914
+ for (const p of possiblePaths) {
1915
+ if (existsSync3(p)) {
1916
+ return p;
1917
+ }
1918
+ }
1919
+ return null;
1920
+ }
1921
+ };
1922
+ }
1923
+ });
1924
+
1925
+ // ../config/index.ts
1926
+ var init_config = __esm({
1927
+ "../config/index.ts"() {
1928
+ "use strict";
1929
+ init_manager();
1930
+ init_adapter();
1931
+ init_resolver();
1932
+ init_initializer();
1933
+ }
1934
+ });
1935
+
1936
+ // Constants.ts
25
1937
  var SERVICE_CONSTANTS, CONFIG_CONSTANTS, PATH_CONSTANTS, ERROR_CODES, TIMEOUT_CONSTANTS, RETRY_CONSTANTS;
26
1938
  var init_Constants = __esm({
27
- "src/Constants.ts"() {
1939
+ "Constants.ts"() {
28
1940
  "use strict";
29
1941
  SERVICE_CONSTANTS = {
30
1942
  /** 服务名称 */
@@ -97,10 +2009,10 @@ var init_Constants = __esm({
97
2009
  }
98
2010
  });
99
2011
 
100
- // src/errors/index.ts
2012
+ // errors/index.ts
101
2013
  var CLIError, ConfigError, ServiceError, ValidationError, FileError, ProcessError;
102
2014
  var init_errors = __esm({
103
- "src/errors/index.ts"() {
2015
+ "errors/index.ts"() {
104
2016
  "use strict";
105
2017
  init_Constants();
106
2018
  CLIError = class _CLIError extends Error {
@@ -236,13 +2148,13 @@ var init_errors = __esm({
236
2148
  }
237
2149
  });
238
2150
 
239
- // src/utils/FileUtils.ts
240
- import fs from "fs";
2151
+ // utils/FileUtils.ts
2152
+ import fs2 from "fs";
241
2153
  import { tmpdir } from "os";
242
- import path from "path";
2154
+ import path4 from "path";
243
2155
  var FileUtils;
244
2156
  var init_FileUtils = __esm({
245
- "src/utils/FileUtils.ts"() {
2157
+ "utils/FileUtils.ts"() {
246
2158
  "use strict";
247
2159
  init_errors();
248
2160
  FileUtils = class _FileUtils {
@@ -254,7 +2166,7 @@ var init_FileUtils = __esm({
254
2166
  */
255
2167
  static exists(filePath) {
256
2168
  try {
257
- return fs.existsSync(filePath);
2169
+ return fs2.existsSync(filePath);
258
2170
  } catch {
259
2171
  return false;
260
2172
  }
@@ -264,8 +2176,8 @@ var init_FileUtils = __esm({
264
2176
  */
265
2177
  static ensureDir(dirPath) {
266
2178
  try {
267
- if (!fs.existsSync(dirPath)) {
268
- fs.mkdirSync(dirPath, { recursive: true });
2179
+ if (!fs2.existsSync(dirPath)) {
2180
+ fs2.mkdirSync(dirPath, { recursive: true });
269
2181
  }
270
2182
  } catch (error) {
271
2183
  throw new FileError("\u65E0\u6CD5\u521B\u5EFA\u76EE\u5F55", dirPath);
@@ -279,7 +2191,7 @@ var init_FileUtils = __esm({
279
2191
  if (!_FileUtils.exists(filePath)) {
280
2192
  throw FileError.notFound(filePath);
281
2193
  }
282
- return fs.readFileSync(filePath, encoding);
2194
+ return fs2.readFileSync(filePath, encoding);
283
2195
  } catch (error) {
284
2196
  if (error instanceof FileError) {
285
2197
  throw error;
@@ -295,9 +2207,9 @@ var init_FileUtils = __esm({
295
2207
  if (!options?.overwrite && _FileUtils.exists(filePath)) {
296
2208
  throw FileError.alreadyExists(filePath);
297
2209
  }
298
- const dir = path.dirname(filePath);
2210
+ const dir = path4.dirname(filePath);
299
2211
  _FileUtils.ensureDir(dir);
300
- fs.writeFileSync(filePath, content, "utf8");
2212
+ fs2.writeFileSync(filePath, content, "utf8");
301
2213
  } catch (error) {
302
2214
  if (error instanceof FileError) {
303
2215
  throw error;
@@ -316,9 +2228,9 @@ var init_FileUtils = __esm({
316
2228
  if (!options?.overwrite && _FileUtils.exists(destPath)) {
317
2229
  throw FileError.alreadyExists(destPath);
318
2230
  }
319
- const destDir = path.dirname(destPath);
2231
+ const destDir = path4.dirname(destPath);
320
2232
  _FileUtils.ensureDir(destDir);
321
- fs.copyFileSync(srcPath, destPath);
2233
+ fs2.copyFileSync(srcPath, destPath);
322
2234
  } catch (error) {
323
2235
  if (error instanceof FileError) {
324
2236
  throw error;
@@ -332,7 +2244,7 @@ var init_FileUtils = __esm({
332
2244
  static deleteFile(filePath) {
333
2245
  try {
334
2246
  if (_FileUtils.exists(filePath)) {
335
- fs.unlinkSync(filePath);
2247
+ fs2.unlinkSync(filePath);
336
2248
  }
337
2249
  } catch (error) {
338
2250
  throw new FileError("\u65E0\u6CD5\u5220\u9664\u6587\u4EF6", filePath);
@@ -347,14 +2259,14 @@ var init_FileUtils = __esm({
347
2259
  throw FileError.notFound(srcDir);
348
2260
  }
349
2261
  _FileUtils.ensureDir(destDir);
350
- const items = fs.readdirSync(srcDir);
2262
+ const items = fs2.readdirSync(srcDir);
351
2263
  for (const item of items) {
352
2264
  if (options.exclude?.includes(item)) {
353
2265
  continue;
354
2266
  }
355
- const srcPath = path.join(srcDir, item);
356
- const destPath = path.join(destDir, item);
357
- const stat = fs.statSync(srcPath);
2267
+ const srcPath = path4.join(srcDir, item);
2268
+ const destPath = path4.join(destDir, item);
2269
+ const stat = fs2.statSync(srcPath);
358
2270
  if (stat.isDirectory()) {
359
2271
  if (options.recursive !== false) {
360
2272
  _FileUtils.copyDirectory(srcPath, destPath, options);
@@ -378,7 +2290,7 @@ var init_FileUtils = __esm({
378
2290
  static deleteDirectory(dirPath, options = {}) {
379
2291
  try {
380
2292
  if (_FileUtils.exists(dirPath)) {
381
- fs.rmSync(dirPath, {
2293
+ fs2.rmSync(dirPath, {
382
2294
  recursive: options.recursive ?? true,
383
2295
  force: true
384
2296
  });
@@ -395,7 +2307,7 @@ var init_FileUtils = __esm({
395
2307
  if (!_FileUtils.exists(filePath)) {
396
2308
  throw FileError.notFound(filePath);
397
2309
  }
398
- const stats = fs.statSync(filePath);
2310
+ const stats = fs2.statSync(filePath);
399
2311
  return {
400
2312
  size: stats.size,
401
2313
  isFile: stats.isFile(),
@@ -418,15 +2330,15 @@ var init_FileUtils = __esm({
418
2330
  if (!_FileUtils.exists(dirPath)) {
419
2331
  throw FileError.notFound(dirPath);
420
2332
  }
421
- const items = fs.readdirSync(dirPath);
2333
+ const items = fs2.readdirSync(dirPath);
422
2334
  let result = [];
423
2335
  for (const item of items) {
424
2336
  if (!options.includeHidden && item.startsWith(".")) {
425
2337
  continue;
426
2338
  }
427
- const itemPath = path.join(dirPath, item);
2339
+ const itemPath = path4.join(dirPath, item);
428
2340
  result.push(itemPath);
429
- if (options.recursive && fs.statSync(itemPath).isDirectory()) {
2341
+ if (options.recursive && fs2.statSync(itemPath).isDirectory()) {
430
2342
  const subItems = _FileUtils.listDirectory(itemPath, options);
431
2343
  result = result.concat(subItems);
432
2344
  }
@@ -447,14 +2359,14 @@ var init_FileUtils = __esm({
447
2359
  const timestamp = Date.now();
448
2360
  const random = Math.random().toString(36).substring(2);
449
2361
  const fileName = `${prefix}${timestamp}-${random}${suffix}`;
450
- return path.join(tempDir, fileName);
2362
+ return path4.join(tempDir, fileName);
451
2363
  }
452
2364
  /**
453
2365
  * 检查文件权限
454
2366
  */
455
- static checkPermissions(filePath, mode = fs.constants.R_OK | fs.constants.W_OK) {
2367
+ static checkPermissions(filePath, mode = fs2.constants.R_OK | fs2.constants.W_OK) {
456
2368
  try {
457
- fs.accessSync(filePath, mode);
2369
+ fs2.accessSync(filePath, mode);
458
2370
  return true;
459
2371
  } catch {
460
2372
  return false;
@@ -464,37 +2376,37 @@ var init_FileUtils = __esm({
464
2376
  * 获取文件扩展名
465
2377
  */
466
2378
  static getExtension(filePath) {
467
- return path.extname(filePath).toLowerCase();
2379
+ return path4.extname(filePath).toLowerCase();
468
2380
  }
469
2381
  /**
470
2382
  * 获取文件名(不含扩展名)
471
2383
  */
472
2384
  static getBaseName(filePath) {
473
- return path.basename(filePath, path.extname(filePath));
2385
+ return path4.basename(filePath, path4.extname(filePath));
474
2386
  }
475
2387
  /**
476
2388
  * 规范化路径
477
2389
  */
478
2390
  static normalizePath(filePath) {
479
- return path.normalize(filePath);
2391
+ return path4.normalize(filePath);
480
2392
  }
481
2393
  /**
482
2394
  * 解析相对路径为绝对路径
483
2395
  */
484
2396
  static resolvePath(filePath, basePath) {
485
2397
  if (basePath) {
486
- return path.resolve(basePath, filePath);
2398
+ return path4.resolve(basePath, filePath);
487
2399
  }
488
- return path.resolve(filePath);
2400
+ return path4.resolve(filePath);
489
2401
  }
490
2402
  };
491
2403
  }
492
2404
  });
493
2405
 
494
- // src/utils/FormatUtils.ts
2406
+ // utils/FormatUtils.ts
495
2407
  var FormatUtils;
496
2408
  var init_FormatUtils = __esm({
497
- "src/utils/FormatUtils.ts"() {
2409
+ "utils/FormatUtils.ts"() {
498
2410
  "use strict";
499
2411
  FormatUtils = class {
500
2412
  static {
@@ -561,9 +2473,9 @@ var init_FormatUtils = __esm({
561
2473
  /**
562
2474
  * 格式化 URL
563
2475
  */
564
- static formatUrl(protocol, host, port, path6) {
2476
+ static formatUrl(protocol, host, port, path9) {
565
2477
  const url = `${protocol}://${host}:${port}`;
566
- return path6 ? `${url}${path6}` : url;
2478
+ return path9 ? `${url}${path9}` : url;
567
2479
  }
568
2480
  /**
569
2481
  * 格式化配置键值对
@@ -655,14 +2567,14 @@ ${error.stack}`;
655
2567
  }
656
2568
  });
657
2569
 
658
- // src/utils/PathUtils.ts
2570
+ // utils/PathUtils.ts
659
2571
  import { realpathSync } from "fs";
660
2572
  import { tmpdir as tmpdir2 } from "os";
661
- import path2 from "path";
662
- import { fileURLToPath } from "url";
2573
+ import path5 from "path";
2574
+ import { fileURLToPath as fileURLToPath4 } from "url";
663
2575
  var PathUtils;
664
2576
  var init_PathUtils = __esm({
665
- "src/utils/PathUtils.ts"() {
2577
+ "utils/PathUtils.ts"() {
666
2578
  "use strict";
667
2579
  init_Constants();
668
2580
  init_FileUtils();
@@ -675,14 +2587,14 @@ var init_PathUtils = __esm({
675
2587
  */
676
2588
  static getPidFile() {
677
2589
  const configDir = process.env[CONFIG_CONSTANTS.DIR_ENV_VAR] || process.cwd();
678
- return path2.join(configDir, `.${SERVICE_CONSTANTS.NAME}.pid`);
2590
+ return path5.join(configDir, `.${SERVICE_CONSTANTS.NAME}.pid`);
679
2591
  }
680
2592
  /**
681
2593
  * 获取日志文件路径
682
2594
  */
683
2595
  static getLogFile(projectDir) {
684
2596
  const baseDir = projectDir || process.cwd();
685
- return path2.join(baseDir, SERVICE_CONSTANTS.LOG_FILE);
2597
+ return path5.join(baseDir, SERVICE_CONSTANTS.LOG_FILE);
686
2598
  }
687
2599
  /**
688
2600
  * 获取配置目录路径
@@ -695,21 +2607,21 @@ var init_PathUtils = __esm({
695
2607
  */
696
2608
  static getWorkDir() {
697
2609
  const configDir = _PathUtils.getConfigDir();
698
- return path2.join(configDir, PATH_CONSTANTS.WORK_DIR);
2610
+ return path5.join(configDir, PATH_CONSTANTS.WORK_DIR);
699
2611
  }
700
2612
  /**
701
2613
  * 获取模板目录路径
702
2614
  */
703
2615
  static getTemplatesDir() {
704
- const __filename = fileURLToPath(import.meta.url);
705
- const scriptDir = path2.dirname(__filename);
2616
+ const __filename = fileURLToPath4(import.meta.url);
2617
+ const scriptDir = path5.dirname(__filename);
706
2618
  return [
707
2619
  // 构建后的环境:dist/cli.js -> dist/templates
708
- path2.join(scriptDir, PATH_CONSTANTS.TEMPLATES_DIR),
2620
+ path5.join(scriptDir, PATH_CONSTANTS.TEMPLATES_DIR),
709
2621
  // 构建环境:dist/cli/index.js -> dist/backend/templates
710
- path2.join(scriptDir, "..", "backend", PATH_CONSTANTS.TEMPLATES_DIR),
2622
+ path5.join(scriptDir, "..", "backend", PATH_CONSTANTS.TEMPLATES_DIR),
711
2623
  // npm 全局安装
712
- path2.join(
2624
+ path5.join(
713
2625
  scriptDir,
714
2626
  "..",
715
2627
  "..",
@@ -739,36 +2651,36 @@ var init_PathUtils = __esm({
739
2651
  if (!templatesDir) {
740
2652
  return null;
741
2653
  }
742
- const templatePath = path2.join(templatesDir, templateName);
2654
+ const templatePath = path5.join(templatesDir, templateName);
743
2655
  return FileUtils.exists(templatePath) ? templatePath : null;
744
2656
  }
745
2657
  /**
746
2658
  * 获取脚本目录路径
747
2659
  */
748
2660
  static getScriptDir() {
749
- const __filename = fileURLToPath(import.meta.url);
750
- return path2.dirname(__filename);
2661
+ const __filename = fileURLToPath4(import.meta.url);
2662
+ return path5.dirname(__filename);
751
2663
  }
752
2664
  /**
753
2665
  * 获取项目根目录路径
754
2666
  */
755
2667
  static getProjectRoot() {
756
2668
  const scriptDir = _PathUtils.getScriptDir();
757
- return path2.join(scriptDir, "..", "..", "..");
2669
+ return path5.join(scriptDir, "..", "..", "..");
758
2670
  }
759
2671
  /**
760
2672
  * 获取构建输出目录路径
761
2673
  */
762
2674
  static getDistDir() {
763
2675
  const projectRoot = _PathUtils.getProjectRoot();
764
- return path2.join(projectRoot, "dist");
2676
+ return path5.join(projectRoot, "dist");
765
2677
  }
766
2678
  /**
767
2679
  * 获取相对于项目根目录的路径
768
2680
  */
769
2681
  static getRelativePath(filePath) {
770
2682
  const projectRoot = _PathUtils.getProjectRoot();
771
- return path2.relative(projectRoot, filePath);
2683
+ return path5.relative(projectRoot, filePath);
772
2684
  }
773
2685
  /**
774
2686
  * 解析配置文件路径
@@ -776,71 +2688,82 @@ var init_PathUtils = __esm({
776
2688
  static resolveConfigPath(format) {
777
2689
  const configDir = _PathUtils.getConfigDir();
778
2690
  if (format) {
779
- return path2.join(configDir, `xiaozhi.config.${format}`);
2691
+ return path5.join(configDir, `xiaozhi.config.${format}`);
780
2692
  }
781
2693
  for (const fileName of CONFIG_CONSTANTS.FILE_NAMES) {
782
- const filePath = path2.join(configDir, fileName);
2694
+ const filePath = path5.join(configDir, fileName);
783
2695
  if (FileUtils.exists(filePath)) {
784
2696
  return filePath;
785
2697
  }
786
2698
  }
787
- return path2.join(configDir, CONFIG_CONSTANTS.FILE_NAMES[2]);
2699
+ return path5.join(configDir, CONFIG_CONSTANTS.FILE_NAMES[2]);
788
2700
  }
789
2701
  /**
790
2702
  * 获取默认配置文件路径
791
2703
  */
792
2704
  static getDefaultConfigPath() {
793
2705
  const projectRoot = _PathUtils.getProjectRoot();
794
- return path2.join(projectRoot, CONFIG_CONSTANTS.DEFAULT_FILE);
2706
+ return path5.join(projectRoot, CONFIG_CONSTANTS.DEFAULT_FILE);
795
2707
  }
796
2708
  /**
797
2709
  * 验证路径安全性(防止路径遍历攻击)
2710
+ * 通过路径段判断是否存在严格等于 ".." 的段,避免误杀包含 ".." 子串的合法文件名
2711
+ * 同时支持 Unix (/) 和 Windows (\) 分隔符
798
2712
  */
799
2713
  static validatePath(inputPath) {
800
- const normalizedPath = path2.normalize(inputPath);
801
- return !normalizedPath.includes("..");
2714
+ const normalizedPath = path5.normalize(inputPath);
2715
+ const segments = normalizedPath.split(/[/\\]/);
2716
+ return !segments.includes("..");
802
2717
  }
803
2718
  /**
804
2719
  * 确保路径在指定目录内
2720
+ * 使用 path.relative 判断,避免前缀匹配被绕过(如 /safe/base2 匹配 /safe/base)
805
2721
  */
806
2722
  static ensurePathWithin(inputPath, baseDir) {
807
- const resolvedPath = path2.resolve(baseDir, inputPath);
808
- const resolvedBase = path2.resolve(baseDir);
809
- if (!resolvedPath.startsWith(resolvedBase)) {
2723
+ const resolvedPath = path5.resolve(baseDir, inputPath);
2724
+ const resolvedBase = path5.resolve(baseDir);
2725
+ const relativePath = path5.relative(resolvedBase, resolvedPath);
2726
+ if (relativePath.startsWith("..") || path5.isAbsolute(relativePath)) {
810
2727
  throw new Error(`\u8DEF\u5F84 ${inputPath} \u8D85\u51FA\u4E86\u5141\u8BB8\u7684\u8303\u56F4`);
811
2728
  }
812
2729
  return resolvedPath;
813
2730
  }
814
2731
  /**
815
2732
  * 获取可执行文件路径
2733
+ * 对于 CLI 自身复用,直接返回当前脚本路径;其他名称从项目根目录的 dist 中查找
816
2734
  */
817
2735
  static getExecutablePath(name) {
818
- const cliPath = process.argv[1];
819
- if (!cliPath) {
820
- return path2.join(process.cwd(), `${name}.js`);
821
- }
822
- let realCliPath;
823
- try {
824
- realCliPath = realpathSync(cliPath);
825
- } catch (error) {
826
- realCliPath = cliPath;
2736
+ if (name === "cli") {
2737
+ const cliPath = process.argv[1];
2738
+ if (cliPath) {
2739
+ try {
2740
+ return realpathSync(cliPath);
2741
+ } catch {
2742
+ return cliPath;
2743
+ }
2744
+ }
2745
+ throw new Error("\u65E0\u6CD5\u786E\u5B9A CLI \u811A\u672C\u8DEF\u5F84");
827
2746
  }
828
- const distDir = path2.dirname(realCliPath);
829
- return path2.join(distDir, `${name}.js`);
2747
+ const projectRoot = _PathUtils.getProjectRoot();
2748
+ return path5.join(projectRoot, "dist", `${name}.js`);
830
2749
  }
831
2750
  /**
832
2751
  * 获取 Web 服务器启动器路径
2752
+ * 返回项目根目录 dist 下的 WebServerLauncher.js(向后兼容包装脚本)
833
2753
  */
834
2754
  static getWebServerLauncherPath() {
835
- return _PathUtils.getExecutablePath("WebServerLauncher");
2755
+ const projectRoot = _PathUtils.getProjectRoot();
2756
+ return path5.join(projectRoot, "dist", "WebServerLauncher.js");
836
2757
  }
837
2758
  /**
838
2759
  * 创建安全的文件路径
2760
+ * 通过路径段判断是否存在严格等于 ".." 的段,避免误杀合法文件名
839
2761
  */
840
2762
  static createSafePath(...segments) {
841
- const joinedPath = path2.join(...segments);
842
- const normalizedPath = path2.normalize(joinedPath);
843
- if (normalizedPath.includes("..") || normalizedPath.includes("~")) {
2763
+ const joinedPath = path5.join(...segments);
2764
+ const normalizedPath = path5.normalize(joinedPath);
2765
+ const hasTraversal = normalizedPath.split(/[/\\]/).includes("..");
2766
+ if (hasTraversal || normalizedPath.includes("~")) {
844
2767
  throw new Error(`\u4E0D\u5B89\u5168\u7684\u8DEF\u5F84: ${normalizedPath}`);
845
2768
  }
846
2769
  return normalizedPath;
@@ -861,11 +2784,11 @@ var init_PathUtils = __esm({
861
2784
  }
862
2785
  });
863
2786
 
864
- // src/utils/PlatformUtils.ts
2787
+ // utils/PlatformUtils.ts
865
2788
  import { execSync } from "child_process";
866
2789
  var PlatformUtils;
867
2790
  var init_PlatformUtils = __esm({
868
- "src/utils/PlatformUtils.ts"() {
2791
+ "utils/PlatformUtils.ts"() {
869
2792
  "use strict";
870
2793
  init_Constants();
871
2794
  init_errors();
@@ -945,7 +2868,7 @@ var init_PlatformUtils = __esm({
945
2868
  let attempts = 0;
946
2869
  const maxAttempts = 30;
947
2870
  while (attempts < maxAttempts) {
948
- await new Promise((resolve) => setTimeout(resolve, 100));
2871
+ await new Promise((resolve4) => setTimeout(resolve4, 100));
949
2872
  try {
950
2873
  process.kill(pid, 0);
951
2874
  attempts++;
@@ -956,7 +2879,7 @@ var init_PlatformUtils = __esm({
956
2879
  try {
957
2880
  process.kill(pid, 0);
958
2881
  process.kill(pid, "SIGKILL");
959
- await new Promise((resolve) => setTimeout(resolve, 500));
2882
+ await new Promise((resolve4) => setTimeout(resolve4, 500));
960
2883
  } catch {
961
2884
  }
962
2885
  } catch (error) {
@@ -1037,10 +2960,10 @@ var init_PlatformUtils = __esm({
1037
2960
  }
1038
2961
  });
1039
2962
 
1040
- // src/utils/Validation.ts
2963
+ // utils/Validation.ts
1041
2964
  var Validation;
1042
2965
  var init_Validation = __esm({
1043
- "src/utils/Validation.ts"() {
2966
+ "utils/Validation.ts"() {
1044
2967
  "use strict";
1045
2968
  init_errors();
1046
2969
  Validation = class _Validation {
@@ -1260,14 +3183,14 @@ var init_Validation = __esm({
1260
3183
  }
1261
3184
  });
1262
3185
 
1263
- // src/services/ProcessManager.ts
3186
+ // services/ProcessManager.ts
1264
3187
  var ProcessManager_exports = {};
1265
3188
  __export(ProcessManager_exports, {
1266
3189
  ProcessManagerImpl: () => ProcessManagerImpl
1267
3190
  });
1268
3191
  var ProcessManagerImpl;
1269
3192
  var init_ProcessManager = __esm({
1270
- "src/services/ProcessManager.ts"() {
3193
+ "services/ProcessManager.ts"() {
1271
3194
  "use strict";
1272
3195
  init_errors();
1273
3196
  init_FileUtils();
@@ -1438,17 +3361,17 @@ var init_ProcessManager = __esm({
1438
3361
  }
1439
3362
  });
1440
3363
 
1441
- // src/services/DaemonManager.ts
3364
+ // services/DaemonManager.ts
1442
3365
  var DaemonManager_exports = {};
1443
3366
  __export(DaemonManager_exports, {
1444
3367
  DaemonManagerImpl: () => DaemonManagerImpl
1445
3368
  });
1446
3369
  import { spawn } from "child_process";
1447
- import fs2 from "fs";
3370
+ import fs3 from "fs";
1448
3371
  import consola from "consola";
1449
3372
  var DaemonManagerImpl;
1450
3373
  var init_DaemonManager = __esm({
1451
- "src/services/DaemonManager.ts"() {
3374
+ "services/DaemonManager.ts"() {
1452
3375
  "use strict";
1453
3376
  init_Constants();
1454
3377
  init_errors();
@@ -1512,7 +3435,7 @@ var init_DaemonManager = __esm({
1512
3435
  if (status.running) {
1513
3436
  await this.stopDaemon();
1514
3437
  await new Promise(
1515
- (resolve) => setTimeout(resolve, RETRY_CONSTANTS.DEFAULT_INTERVAL)
3438
+ (resolve4) => setTimeout(resolve4, RETRY_CONSTANTS.DEFAULT_INTERVAL)
1516
3439
  );
1517
3440
  }
1518
3441
  await this.startDaemon(serverFactory, options);
@@ -1534,7 +3457,7 @@ var init_DaemonManager = __esm({
1534
3457
  async attachToLogs(logFileName = "xiaozhi.log") {
1535
3458
  try {
1536
3459
  const logFilePath = PathUtils.getLogFile();
1537
- if (!fs2.existsSync(logFilePath)) {
3460
+ if (!fs3.existsSync(logFilePath)) {
1538
3461
  throw new ServiceError("\u65E5\u5FD7\u6587\u4EF6\u4E0D\u5B58\u5728");
1539
3462
  }
1540
3463
  const { command, args } = PlatformUtils.getTailCommand(logFilePath);
@@ -1588,12 +3511,12 @@ var init_DaemonManager = __esm({
1588
3511
  async setupLogging(child, logFileName) {
1589
3512
  try {
1590
3513
  const logFilePath = PathUtils.getLogFile();
1591
- const path6 = await import("path");
1592
- const logDir = path6.dirname(logFilePath);
1593
- if (!fs2.existsSync(logDir)) {
1594
- fs2.mkdirSync(logDir, { recursive: true });
3514
+ const path9 = await import("path");
3515
+ const logDir = path9.dirname(logFilePath);
3516
+ if (!fs3.existsSync(logDir)) {
3517
+ fs3.mkdirSync(logDir, { recursive: true });
1595
3518
  }
1596
- const logStream = fs2.createWriteStream(logFilePath, { flags: "a" });
3519
+ const logStream = fs3.createWriteStream(logFilePath, { flags: "a" });
1597
3520
  child.stdout?.pipe(logStream);
1598
3521
  child.stderr?.pipe(logStream);
1599
3522
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
@@ -1668,25 +3591,25 @@ var init_DaemonManager = __esm({
1668
3591
  }
1669
3592
  });
1670
3593
 
1671
- // src/services/ServiceManager.ts
3594
+ // services/ServiceManager.ts
1672
3595
  var ServiceManager_exports = {};
1673
3596
  __export(ServiceManager_exports, {
1674
3597
  ServiceManagerImpl: () => ServiceManagerImpl
1675
3598
  });
1676
- import { ConfigInitializer } from "@xiaozhi-client/config";
1677
3599
  import consola2 from "consola";
1678
3600
  var ServiceManagerImpl;
1679
3601
  var init_ServiceManager = __esm({
1680
- "src/services/ServiceManager.ts"() {
3602
+ "services/ServiceManager.ts"() {
1681
3603
  "use strict";
3604
+ init_config();
1682
3605
  init_Constants();
1683
3606
  init_errors();
1684
3607
  init_PathUtils();
1685
3608
  init_Validation();
1686
3609
  ServiceManagerImpl = class {
1687
- constructor(processManager, configManager3) {
3610
+ constructor(processManager, configManager2) {
1688
3611
  this.processManager = processManager;
1689
- this.configManager = configManager3;
3612
+ this.configManager = configManager2;
1690
3613
  }
1691
3614
  static {
1692
3615
  __name(this, "ServiceManagerImpl");
@@ -1707,7 +3630,7 @@ var init_ServiceManager = __esm({
1707
3630
  await this.processManager.gracefulKillProcess(status.pid || 0);
1708
3631
  this.processManager.cleanupPidFile();
1709
3632
  await new Promise(
1710
- (resolve) => setTimeout(resolve, RETRY_CONSTANTS.DEFAULT_INTERVAL)
3633
+ (resolve4) => setTimeout(resolve4, RETRY_CONSTANTS.DEFAULT_INTERVAL)
1711
3634
  );
1712
3635
  consola2.success("\u73B0\u6709\u670D\u52A1\u5DF2\u505C\u6B62\uFF0C\u6B63\u5728\u542F\u52A8\u65B0\u670D\u52A1...");
1713
3636
  } catch (stopError) {
@@ -1769,7 +3692,7 @@ var init_ServiceManager = __esm({
1769
3692
  if (status.running) {
1770
3693
  await this.stop();
1771
3694
  await new Promise(
1772
- (resolve) => setTimeout(resolve, RETRY_CONSTANTS.DEFAULT_INTERVAL)
3695
+ (resolve4) => setTimeout(resolve4, RETRY_CONSTANTS.DEFAULT_INTERVAL)
1773
3696
  );
1774
3697
  }
1775
3698
  await this.start(options);
@@ -1888,8 +3811,8 @@ var init_ServiceManager = __esm({
1888
3811
  async startWebServerInDaemon() {
1889
3812
  const { spawn: spawn2 } = await import("child_process");
1890
3813
  const webServerPath = PathUtils.getWebServerLauncherPath();
1891
- const fs4 = await import("fs");
1892
- if (!fs4.default.existsSync(webServerPath)) {
3814
+ const fs5 = await import("fs");
3815
+ if (!fs5.default.existsSync(webServerPath)) {
1893
3816
  throw new ServiceError(`WebServer \u6587\u4EF6\u4E0D\u5B58\u5728: ${webServerPath}`);
1894
3817
  }
1895
3818
  const args = [webServerPath];
@@ -1930,16 +3853,16 @@ var init_ServiceManager = __esm({
1930
3853
  }
1931
3854
  });
1932
3855
 
1933
- // src/services/TemplateManager.ts
3856
+ // services/TemplateManager.ts
1934
3857
  var TemplateManager_exports = {};
1935
3858
  __export(TemplateManager_exports, {
1936
3859
  TemplateManagerImpl: () => TemplateManagerImpl
1937
3860
  });
1938
- import fs3 from "fs";
1939
- import path3 from "path";
3861
+ import fs4 from "fs";
3862
+ import path6 from "path";
1940
3863
  var TemplateManagerImpl;
1941
3864
  var init_TemplateManager = __esm({
1942
- "src/services/TemplateManager.ts"() {
3865
+ "services/TemplateManager.ts"() {
1943
3866
  "use strict";
1944
3867
  init_errors();
1945
3868
  init_FileUtils();
@@ -1960,7 +3883,7 @@ var init_TemplateManager = __esm({
1960
3883
  return [];
1961
3884
  }
1962
3885
  const templates = [];
1963
- const templateDirs = fs3.readdirSync(templatesDir, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
3886
+ const templateDirs = fs4.readdirSync(templatesDir, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
1964
3887
  for (const templateName of templateDirs) {
1965
3888
  try {
1966
3889
  const templateInfo = await this.getTemplateInfo(templateName);
@@ -1992,7 +3915,7 @@ var init_TemplateManager = __esm({
1992
3915
  if (!templatePath) {
1993
3916
  return null;
1994
3917
  }
1995
- const configPath = path3.join(templatePath, "template.json");
3918
+ const configPath = path6.join(templatePath, "template.json");
1996
3919
  let config = {};
1997
3920
  if (FileUtils.exists(configPath)) {
1998
3921
  try {
@@ -2027,27 +3950,32 @@ var init_TemplateManager = __esm({
2027
3950
  await this.createProject({
2028
3951
  templateName,
2029
3952
  targetPath,
2030
- projectName: path3.basename(targetPath)
3953
+ projectName: path6.basename(targetPath)
2031
3954
  });
2032
3955
  }
2033
3956
  /**
2034
3957
  * 创建项目
3958
+ * 当 templateName 为 undefined 时使用默认模板,为 null 时创建基本项目(仅配置文件)
2035
3959
  */
2036
3960
  async createProject(options) {
2037
3961
  try {
2038
3962
  this.validateCreateOptions(options);
2039
- const templateName = options.templateName || "default";
2040
- const templateInfo = await this.getTemplateInfo(templateName);
2041
- if (!templateInfo) {
2042
- throw new FileError(`\u6A21\u677F\u4E0D\u5B58\u5728: ${templateName}`, "");
2043
- }
2044
- const targetPath = path3.resolve(options.targetPath);
3963
+ const targetPath = path6.resolve(options.targetPath);
2045
3964
  if (FileUtils.exists(targetPath)) {
2046
3965
  throw FileError.alreadyExists(targetPath);
2047
3966
  }
2048
3967
  FileUtils.ensureDir(targetPath);
2049
- await this.copyTemplateFiles(templateInfo, targetPath, options);
2050
- await this.processTemplateVariables(targetPath, options);
3968
+ const templateName = options.templateName ?? "default";
3969
+ if (options.templateName === null) {
3970
+ await this.createBasicProjectFiles(targetPath, options);
3971
+ } else {
3972
+ const templateInfo = await this.getTemplateInfo(templateName);
3973
+ if (!templateInfo) {
3974
+ throw new FileError(`\u6A21\u677F\u4E0D\u5B58\u5728: ${templateName}`, "");
3975
+ }
3976
+ await this.copyTemplateFiles(templateInfo, targetPath, options);
3977
+ await this.processTemplateVariables(targetPath, options);
3978
+ }
2051
3979
  console.log(`\u2705 \u9879\u76EE\u521B\u5EFA\u6210\u529F: ${targetPath}`);
2052
3980
  } catch (error) {
2053
3981
  if (error instanceof FileError || error instanceof ValidationError) {
@@ -2070,7 +3998,7 @@ var init_TemplateManager = __esm({
2070
3998
  }
2071
3999
  const requiredFiles = ["package.json"];
2072
4000
  for (const requiredFile of requiredFiles) {
2073
- const filePath = path3.join(templateInfo.path, requiredFile);
4001
+ const filePath = path6.join(templateInfo.path, requiredFile);
2074
4002
  if (!FileUtils.exists(filePath)) {
2075
4003
  console.warn(`\u6A21\u677F\u7F3A\u5C11\u5FC5\u8981\u6587\u4EF6: ${requiredFile}`);
2076
4004
  return false;
@@ -2097,7 +4025,7 @@ var init_TemplateManager = __esm({
2097
4025
  includeHidden: false
2098
4026
  });
2099
4027
  return files.filter((file) => {
2100
- const relativePath = path3.relative(templatePath, file);
4028
+ const relativePath = path6.relative(templatePath, file);
2101
4029
  return !relativePath.startsWith(".") && relativePath !== "template.json" && !relativePath.includes("node_modules");
2102
4030
  });
2103
4031
  } catch {
@@ -2111,10 +4039,29 @@ var init_TemplateManager = __esm({
2111
4039
  Validation.validateRequired(options.targetPath, "targetPath");
2112
4040
  Validation.validateRequired(options.projectName, "projectName");
2113
4041
  Validation.validateProjectName(options.projectName);
2114
- if (options.templateName) {
4042
+ if (options.templateName !== void 0 && options.templateName !== null) {
2115
4043
  Validation.validateTemplateName(options.templateName);
2116
4044
  }
2117
4045
  }
4046
+ /**
4047
+ * 创建基本项目文件(无模板,仅基础配置文件)
4048
+ */
4049
+ async createBasicProjectFiles(targetPath, options) {
4050
+ const configContent = JSON.stringify(
4051
+ {
4052
+ name: options.projectName,
4053
+ version: "1.0.0",
4054
+ description: `${options.projectName} \u9879\u76EE`
4055
+ },
4056
+ null,
4057
+ 2
4058
+ );
4059
+ FileUtils.writeFile(
4060
+ path6.join(targetPath, "xiaozhi.config.json"),
4061
+ configContent,
4062
+ { overwrite: true }
4063
+ );
4064
+ }
2118
4065
  /**
2119
4066
  * 复制模板文件
2120
4067
  */
@@ -2168,7 +4115,7 @@ var init_TemplateManager = __esm({
2168
4115
  findFilesByPattern(basePath, pattern) {
2169
4116
  try {
2170
4117
  if (!pattern.includes("*")) {
2171
- const filePath = path3.join(basePath, pattern);
4118
+ const filePath = path6.join(basePath, pattern);
2172
4119
  return FileUtils.exists(filePath) ? [filePath] : [];
2173
4120
  }
2174
4121
  const files = FileUtils.listDirectory(basePath, { recursive: true });
@@ -2176,7 +4123,7 @@ var init_TemplateManager = __esm({
2176
4123
  pattern.replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*")
2177
4124
  );
2178
4125
  return files.filter((file) => {
2179
- const relativePath = path3.relative(basePath, file).split(path3.sep).join("/");
4126
+ const relativePath = path6.relative(basePath, file).split(path6.sep).join("/");
2180
4127
  return regex.test(relativePath);
2181
4128
  });
2182
4129
  } catch {
@@ -2210,10 +4157,10 @@ var init_TemplateManager = __esm({
2210
4157
  }
2211
4158
  });
2212
4159
 
2213
- // src/interfaces/Command.ts
4160
+ // interfaces/Command.ts
2214
4161
  var BaseCommandHandler;
2215
4162
  var init_Command = __esm({
2216
- "src/interfaces/Command.ts"() {
4163
+ "interfaces/Command.ts"() {
2217
4164
  "use strict";
2218
4165
  BaseCommandHandler = class {
2219
4166
  constructor(container) {
@@ -2252,7 +4199,7 @@ var init_Command = __esm({
2252
4199
  }
2253
4200
  });
2254
4201
 
2255
- // src/commands/ServiceCommandHandler.ts
4202
+ // commands/ServiceCommandHandler.ts
2256
4203
  var ServiceCommandHandler_exports = {};
2257
4204
  __export(ServiceCommandHandler_exports, {
2258
4205
  ServiceCommandHandler: () => ServiceCommandHandler
@@ -2260,7 +4207,7 @@ __export(ServiceCommandHandler_exports, {
2260
4207
  import consola3 from "consola";
2261
4208
  var ServiceCommandHandler;
2262
4209
  var init_ServiceCommandHandler = __esm({
2263
- "src/commands/ServiceCommandHandler.ts"() {
4210
+ "commands/ServiceCommandHandler.ts"() {
2264
4211
  "use strict";
2265
4212
  init_Command();
2266
4213
  ServiceCommandHandler = class extends BaseCommandHandler {
@@ -2421,17 +4368,17 @@ var init_ServiceCommandHandler = __esm({
2421
4368
  }
2422
4369
  });
2423
4370
 
2424
- // src/commands/ConfigCommandHandler.ts
4371
+ // commands/ConfigCommandHandler.ts
2425
4372
  var ConfigCommandHandler_exports = {};
2426
4373
  __export(ConfigCommandHandler_exports, {
2427
4374
  ConfigCommandHandler: () => ConfigCommandHandler
2428
4375
  });
2429
- import path4 from "path";
4376
+ import path7 from "path";
2430
4377
  import chalk2 from "chalk";
2431
4378
  import ora from "ora";
2432
4379
  var ConfigCommandHandler;
2433
4380
  var init_ConfigCommandHandler = __esm({
2434
- "src/commands/ConfigCommandHandler.ts"() {
4381
+ "commands/ConfigCommandHandler.ts"() {
2435
4382
  "use strict";
2436
4383
  init_Command();
2437
4384
  ConfigCommandHandler = class extends BaseCommandHandler {
@@ -2491,17 +4438,17 @@ var init_ConfigCommandHandler = __esm({
2491
4438
  if (format !== "json" && format !== "json5" && format !== "jsonc") {
2492
4439
  throw new Error("\u683C\u5F0F\u5FC5\u987B\u662F json, json5 \u6216 jsonc");
2493
4440
  }
2494
- const configManager3 = this.getService("configManager");
2495
- if (configManager3.configExists()) {
4441
+ const configManager2 = this.getService("configManager");
4442
+ if (configManager2.configExists()) {
2496
4443
  spinner.warn("\u914D\u7F6E\u6587\u4EF6\u5DF2\u5B58\u5728");
2497
4444
  console.log(chalk2.yellow("\u5982\u9700\u91CD\u65B0\u521D\u59CB\u5316\uFF0C\u8BF7\u5148\u5220\u9664\u73B0\u6709\u7684\u914D\u7F6E\u6587\u4EF6"));
2498
4445
  return;
2499
4446
  }
2500
- configManager3.initConfig(format);
4447
+ configManager2.initConfig(format);
2501
4448
  spinner.succeed("\u914D\u7F6E\u6587\u4EF6\u521D\u59CB\u5316\u6210\u529F");
2502
4449
  const configDir = process.env.XIAOZHI_CONFIG_DIR || process.cwd();
2503
4450
  const configFileName = `xiaozhi.config.${format}`;
2504
- const configPath = path4.join(configDir, configFileName);
4451
+ const configPath = path7.join(configDir, configFileName);
2505
4452
  console.log(chalk2.green(`\u2705 \u914D\u7F6E\u6587\u4EF6\u5DF2\u521B\u5EFA: ${configFileName}`));
2506
4453
  console.log(chalk2.yellow("\u{1F4DD} \u8BF7\u7F16\u8F91\u914D\u7F6E\u6587\u4EF6\u8BBE\u7F6E\u4F60\u7684 MCP \u7AEF\u70B9:"));
2507
4454
  console.log(chalk2.gray(` \u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84: ${configPath}`));
@@ -2520,8 +4467,8 @@ var init_ConfigCommandHandler = __esm({
2520
4467
  * 确保配置文件存在,如果不存在则显示提示并返回 false
2521
4468
  */
2522
4469
  async ensureConfigExists(spinner) {
2523
- const configManager3 = this.getService("configManager");
2524
- if (!configManager3.configExists()) {
4470
+ const configManager2 = this.getService("configManager");
4471
+ if (!configManager2.configExists()) {
2525
4472
  spinner.fail("\u914D\u7F6E\u6587\u4EF6\u4E0D\u5B58\u5728");
2526
4473
  console.log(
2527
4474
  chalk2.yellow('\u{1F4A1} \u63D0\u793A: \u8BF7\u5148\u8FD0\u884C "xiaozhi config init" \u521D\u59CB\u5316\u914D\u7F6E')
@@ -2539,12 +4486,12 @@ var init_ConfigCommandHandler = __esm({
2539
4486
  if (!await this.ensureConfigExists(spinner)) {
2540
4487
  return;
2541
4488
  }
2542
- const configManager3 = this.getService("configManager");
2543
- const config = configManager3.getConfig();
4489
+ const configManager2 = this.getService("configManager");
4490
+ const config = configManager2.getConfig();
2544
4491
  switch (key) {
2545
4492
  case "mcpEndpoint": {
2546
4493
  spinner.succeed("\u914D\u7F6E\u4FE1\u606F");
2547
- const endpoints = configManager3.getMcpEndpoints();
4494
+ const endpoints = configManager2.getMcpEndpoints();
2548
4495
  if (endpoints.length === 0) {
2549
4496
  console.log(chalk2.yellow("\u672A\u914D\u7F6E\u4EFB\u4F55 MCP \u7AEF\u70B9"));
2550
4497
  } else if (endpoints.length === 1) {
@@ -2577,7 +4524,7 @@ var init_ConfigCommandHandler = __esm({
2577
4524
  break;
2578
4525
  case "connection": {
2579
4526
  spinner.succeed("\u914D\u7F6E\u4FE1\u606F");
2580
- const connectionConfig = configManager3.getConnectionConfig();
4527
+ const connectionConfig = configManager2.getConnectionConfig();
2581
4528
  console.log(chalk2.green("\u8FDE\u63A5\u914D\u7F6E:"));
2582
4529
  console.log(
2583
4530
  chalk2.gray(
@@ -2596,7 +4543,7 @@ var init_ConfigCommandHandler = __esm({
2596
4543
  spinner.succeed("\u914D\u7F6E\u4FE1\u606F");
2597
4544
  console.log(
2598
4545
  chalk2.green(
2599
- `\u5FC3\u8DF3\u68C0\u6D4B\u95F4\u9694: ${configManager3.getHeartbeatInterval()}ms`
4546
+ `\u5FC3\u8DF3\u68C0\u6D4B\u95F4\u9694: ${configManager2.getHeartbeatInterval()}ms`
2600
4547
  )
2601
4548
  );
2602
4549
  break;
@@ -2604,14 +4551,14 @@ var init_ConfigCommandHandler = __esm({
2604
4551
  spinner.succeed("\u914D\u7F6E\u4FE1\u606F");
2605
4552
  console.log(
2606
4553
  chalk2.green(
2607
- `\u5FC3\u8DF3\u8D85\u65F6\u65F6\u95F4: ${configManager3.getHeartbeatTimeout()}ms`
4554
+ `\u5FC3\u8DF3\u8D85\u65F6\u65F6\u95F4: ${configManager2.getHeartbeatTimeout()}ms`
2608
4555
  )
2609
4556
  );
2610
4557
  break;
2611
4558
  case "reconnectInterval":
2612
4559
  spinner.succeed("\u914D\u7F6E\u4FE1\u606F");
2613
4560
  console.log(
2614
- chalk2.green(`\u91CD\u8FDE\u95F4\u9694: ${configManager3.getReconnectInterval()}ms`)
4561
+ chalk2.green(`\u91CD\u8FDE\u95F4\u9694: ${configManager2.getReconnectInterval()}ms`)
2615
4562
  );
2616
4563
  break;
2617
4564
  default:
@@ -2638,10 +4585,10 @@ var init_ConfigCommandHandler = __esm({
2638
4585
  if (!await this.ensureConfigExists(spinner)) {
2639
4586
  return;
2640
4587
  }
2641
- const configManager3 = this.getService("configManager");
4588
+ const configManager2 = this.getService("configManager");
2642
4589
  switch (key) {
2643
4590
  case "mcpEndpoint":
2644
- configManager3.updateMcpEndpoint(value);
4591
+ configManager2.updateMcpEndpoint(value);
2645
4592
  spinner.succeed(`MCP \u7AEF\u70B9\u5DF2\u8BBE\u7F6E\u4E3A: ${value}`);
2646
4593
  break;
2647
4594
  case "heartbeatInterval": {
@@ -2649,7 +4596,7 @@ var init_ConfigCommandHandler = __esm({
2649
4596
  if (Number.isNaN(interval) || interval <= 0) {
2650
4597
  throw new Error("\u5FC3\u8DF3\u68C0\u6D4B\u95F4\u9694\u5FC5\u987B\u662F\u6B63\u6574\u6570");
2651
4598
  }
2652
- configManager3.updateHeartbeatInterval(interval);
4599
+ configManager2.updateHeartbeatInterval(interval);
2653
4600
  spinner.succeed(`\u5FC3\u8DF3\u68C0\u6D4B\u95F4\u9694\u5DF2\u8BBE\u7F6E\u4E3A: ${interval}ms`);
2654
4601
  break;
2655
4602
  }
@@ -2658,7 +4605,7 @@ var init_ConfigCommandHandler = __esm({
2658
4605
  if (Number.isNaN(timeout) || timeout <= 0) {
2659
4606
  throw new Error("\u5FC3\u8DF3\u8D85\u65F6\u65F6\u95F4\u5FC5\u987B\u662F\u6B63\u6574\u6570");
2660
4607
  }
2661
- configManager3.updateHeartbeatTimeout(timeout);
4608
+ configManager2.updateHeartbeatTimeout(timeout);
2662
4609
  spinner.succeed(`\u5FC3\u8DF3\u8D85\u65F6\u65F6\u95F4\u5DF2\u8BBE\u7F6E\u4E3A: ${timeout}ms`);
2663
4610
  break;
2664
4611
  }
@@ -2667,7 +4614,7 @@ var init_ConfigCommandHandler = __esm({
2667
4614
  if (Number.isNaN(interval) || interval <= 0) {
2668
4615
  throw new Error("\u91CD\u8FDE\u95F4\u9694\u5FC5\u987B\u662F\u6B63\u6574\u6570");
2669
4616
  }
2670
- configManager3.updateReconnectInterval(interval);
4617
+ configManager2.updateReconnectInterval(interval);
2671
4618
  spinner.succeed(`\u91CD\u8FDE\u95F4\u9694\u5DF2\u8BBE\u7F6E\u4E3A: ${interval}ms`);
2672
4619
  break;
2673
4620
  }
@@ -2690,17 +4637,17 @@ var init_ConfigCommandHandler = __esm({
2690
4637
  }
2691
4638
  });
2692
4639
 
2693
- // src/commands/ProjectCommandHandler.ts
4640
+ // commands/ProjectCommandHandler.ts
2694
4641
  var ProjectCommandHandler_exports = {};
2695
4642
  __export(ProjectCommandHandler_exports, {
2696
4643
  ProjectCommandHandler: () => ProjectCommandHandler
2697
4644
  });
2698
- import path5 from "path";
4645
+ import path8 from "path";
2699
4646
  import chalk3 from "chalk";
2700
4647
  import ora2 from "ora";
2701
4648
  var ProjectCommandHandler;
2702
4649
  var init_ProjectCommandHandler = __esm({
2703
- "src/commands/ProjectCommandHandler.ts"() {
4650
+ "commands/ProjectCommandHandler.ts"() {
2704
4651
  "use strict";
2705
4652
  init_Command();
2706
4653
  ProjectCommandHandler = class extends BaseCommandHandler {
@@ -2734,7 +4681,7 @@ var init_ProjectCommandHandler = __esm({
2734
4681
  try {
2735
4682
  const templateManager = this.getService("templateManager");
2736
4683
  const fileUtils = this.getService("fileUtils");
2737
- const targetPath = path5.join(process.cwd(), projectName);
4684
+ const targetPath = path8.join(process.cwd(), projectName);
2738
4685
  if (await fileUtils.exists(targetPath)) {
2739
4686
  spinner.fail(`\u76EE\u5F55 "${projectName}" \u5DF2\u5B58\u5728`);
2740
4687
  console.log(
@@ -2845,7 +4792,11 @@ var init_ProjectCommandHandler = __esm({
2845
4792
  showAvailableTemplates(templates) {
2846
4793
  console.log(chalk3.yellow("\u53EF\u7528\u7684\u6A21\u677F:"));
2847
4794
  for (const template of templates) {
2848
- console.log(chalk3.gray(` - ${template}`));
4795
+ console.log(
4796
+ chalk3.gray(
4797
+ ` - ${template.name}${template.description ? ` - ${template.description}` : ""}`
4798
+ )
4799
+ );
2849
4800
  }
2850
4801
  }
2851
4802
  /**
@@ -2858,11 +4809,11 @@ var init_ProjectCommandHandler = __esm({
2858
4809
  for (const template of templates) {
2859
4810
  const similarity = formatUtils.calculateSimilarity(
2860
4811
  input.toLowerCase(),
2861
- template.toLowerCase()
4812
+ template.name.toLowerCase()
2862
4813
  );
2863
4814
  if (similarity > bestSimilarity && similarity > 0.6) {
2864
4815
  bestSimilarity = similarity;
2865
- bestMatch = template;
4816
+ bestMatch = template.name;
2866
4817
  }
2867
4818
  }
2868
4819
  return bestMatch;
@@ -2876,10 +4827,10 @@ var init_ProjectCommandHandler = __esm({
2876
4827
  input: process.stdin,
2877
4828
  output: process.stdout
2878
4829
  });
2879
- return new Promise((resolve) => {
4830
+ return new Promise((resolve4) => {
2880
4831
  rl.question(prompt, (answer) => {
2881
4832
  rl.close();
2882
- resolve(
4833
+ resolve4(
2883
4834
  answer.toLowerCase().trim() === "y" || answer.toLowerCase().trim() === "yes"
2884
4835
  );
2885
4836
  });
@@ -2889,32 +4840,32 @@ var init_ProjectCommandHandler = __esm({
2889
4840
  }
2890
4841
  });
2891
4842
 
2892
- // src/interfaces/CommandTypes.ts
4843
+ // interfaces/CommandTypes.ts
2893
4844
  function isLocalMCPServerConfig(obj) {
2894
4845
  const config = obj;
2895
4846
  return typeof config === "object" && config !== null && "command" in config && "args" in config && typeof config.command === "string" && Array.isArray(config.args) && config.args.every((arg) => typeof arg === "string");
2896
4847
  }
2897
4848
  var init_CommandTypes = __esm({
2898
- "src/interfaces/CommandTypes.ts"() {
4849
+ "interfaces/CommandTypes.ts"() {
2899
4850
  "use strict";
2900
4851
  __name(isLocalMCPServerConfig, "isLocalMCPServerConfig");
2901
4852
  }
2902
4853
  });
2903
4854
 
2904
- // src/commands/McpCommandHandler.ts
4855
+ // commands/McpCommandHandler.ts
2905
4856
  var McpCommandHandler_exports = {};
2906
4857
  __export(McpCommandHandler_exports, {
2907
4858
  McpCommandHandler: () => McpCommandHandler
2908
4859
  });
2909
- import { configManager as configManager2 } from "@xiaozhi-client/config";
2910
4860
  import chalk4 from "chalk";
2911
4861
  import Table from "cli-table3";
2912
4862
  import consola4 from "consola";
2913
4863
  import ora3 from "ora";
2914
4864
  var McpCommandHandler;
2915
4865
  var init_McpCommandHandler = __esm({
2916
- "src/commands/McpCommandHandler.ts"() {
4866
+ "commands/McpCommandHandler.ts"() {
2917
4867
  "use strict";
4868
+ init_config();
2918
4869
  init_Command();
2919
4870
  init_CommandTypes();
2920
4871
  init_ProcessManager();
@@ -2928,7 +4879,7 @@ var init_McpCommandHandler = __esm({
2928
4879
  super(...args);
2929
4880
  this.processManager = new ProcessManagerImpl();
2930
4881
  try {
2931
- const webPort = configManager2.getWebUIPort() ?? 9999;
4882
+ const webPort = configManager.getWebUIPort() ?? 9999;
2932
4883
  this.baseUrl = `http://localhost:${webPort}`;
2933
4884
  } catch {
2934
4885
  this.baseUrl = "http://localhost:9999";
@@ -3230,9 +5181,9 @@ var init_McpCommandHandler = __esm({
3230
5181
  async handleListInternal(options = {}) {
3231
5182
  const spinner = ora3("\u83B7\u53D6 MCP \u670D\u52A1\u5217\u8868...").start();
3232
5183
  try {
3233
- const mcpServers = configManager2.getMcpServers();
5184
+ const mcpServers = configManager.getMcpServers();
3234
5185
  const serverNames = Object.keys(mcpServers);
3235
- const customMCPTools = configManager2.getCustomMCPTools();
5186
+ const customMCPTools = configManager.getCustomMCPTools();
3236
5187
  const hasCustomMCP = customMCPTools.length > 0;
3237
5188
  const totalServices = serverNames.length + (hasCustomMCP ? 1 : 0);
3238
5189
  if (totalServices === 0) {
@@ -3254,7 +5205,7 @@ var init_McpCommandHandler = __esm({
3254
5205
  let maxToolNameWidth = 8;
3255
5206
  const allToolNames = [];
3256
5207
  for (const serverName of serverNames) {
3257
- const toolsConfig = configManager2.getServerToolsConfig(serverName);
5208
+ const toolsConfig = configManager.getServerToolsConfig(serverName);
3258
5209
  const toolNames = Object.keys(toolsConfig);
3259
5210
  allToolNames.push(...toolNames);
3260
5211
  }
@@ -3300,7 +5251,7 @@ var init_McpCommandHandler = __esm({
3300
5251
  }
3301
5252
  }
3302
5253
  for (const serverName of serverNames) {
3303
- const toolsConfig = configManager2.getServerToolsConfig(serverName);
5254
+ const toolsConfig = configManager.getServerToolsConfig(serverName);
3304
5255
  const toolNames = Object.keys(toolsConfig);
3305
5256
  if (toolNames.length === 0) {
3306
5257
  table.push([
@@ -3342,7 +5293,7 @@ var init_McpCommandHandler = __esm({
3342
5293
  }
3343
5294
  for (const serverName of serverNames) {
3344
5295
  const serverConfig = mcpServers[serverName];
3345
- const toolsConfig = configManager2.getServerToolsConfig(serverName);
5296
+ const toolsConfig = configManager.getServerToolsConfig(serverName);
3346
5297
  const toolCount = Object.keys(toolsConfig).length;
3347
5298
  const enabledCount = Object.values(toolsConfig).filter(
3348
5299
  (t) => t.enable !== false
@@ -3404,7 +5355,7 @@ var init_McpCommandHandler = __esm({
3404
5355
  * @private
3405
5356
  */
3406
5357
  validateServerExists(serverName, spinner) {
3407
- const mcpServers = configManager2.getMcpServers();
5358
+ const mcpServers = configManager.getMcpServers();
3408
5359
  if (!mcpServers[serverName]) {
3409
5360
  spinner.fail(`\u670D\u52A1 '${serverName}' \u4E0D\u5B58\u5728`);
3410
5361
  console.log(
@@ -3423,7 +5374,7 @@ var init_McpCommandHandler = __esm({
3423
5374
  if (!this.validateServerExists(serverName, spinner)) {
3424
5375
  return;
3425
5376
  }
3426
- const toolsConfig = configManager2.getServerToolsConfig(serverName);
5377
+ const toolsConfig = configManager.getServerToolsConfig(serverName);
3427
5378
  const toolNames = Object.keys(toolsConfig);
3428
5379
  if (toolNames.length === 0) {
3429
5380
  spinner.warn(`\u670D\u52A1 '${serverName}' \u6682\u65E0\u5DE5\u5177\u4FE1\u606F`);
@@ -3486,7 +5437,7 @@ var init_McpCommandHandler = __esm({
3486
5437
  if (!this.validateServerExists(serverName, spinner)) {
3487
5438
  return;
3488
5439
  }
3489
- const toolsConfig = configManager2.getServerToolsConfig(serverName);
5440
+ const toolsConfig = configManager.getServerToolsConfig(serverName);
3490
5441
  if (!toolsConfig[toolName]) {
3491
5442
  spinner.fail(`\u5DE5\u5177 '${toolName}' \u5728\u670D\u52A1 '${serverName}' \u4E2D\u4E0D\u5B58\u5728`);
3492
5443
  console.log(
@@ -3496,7 +5447,7 @@ var init_McpCommandHandler = __esm({
3496
5447
  );
3497
5448
  return;
3498
5449
  }
3499
- configManager2.setToolEnabled(
5450
+ configManager.setToolEnabled(
3500
5451
  serverName,
3501
5452
  toolName,
3502
5453
  enabled,
@@ -3521,7 +5472,7 @@ var init_McpCommandHandler = __esm({
3521
5472
  }
3522
5473
  });
3523
5474
 
3524
- // src/commands/EndpointCommandHandler.ts
5475
+ // commands/EndpointCommandHandler.ts
3525
5476
  var EndpointCommandHandler_exports = {};
3526
5477
  __export(EndpointCommandHandler_exports, {
3527
5478
  EndpointCommandHandler: () => EndpointCommandHandler
@@ -3530,7 +5481,7 @@ import chalk5 from "chalk";
3530
5481
  import ora4 from "ora";
3531
5482
  var EndpointCommandHandler;
3532
5483
  var init_EndpointCommandHandler = __esm({
3533
- "src/commands/EndpointCommandHandler.ts"() {
5484
+ "commands/EndpointCommandHandler.ts"() {
3534
5485
  "use strict";
3535
5486
  init_Command();
3536
5487
  EndpointCommandHandler = class extends BaseCommandHandler {
@@ -3587,8 +5538,8 @@ var init_EndpointCommandHandler = __esm({
3587
5538
  async handleList() {
3588
5539
  const spinner = ora4("\u8BFB\u53D6\u7AEF\u70B9\u914D\u7F6E...").start();
3589
5540
  try {
3590
- const configManager3 = this.getService("configManager");
3591
- const endpoints = configManager3.getMcpEndpoints();
5541
+ const configManager2 = this.getService("configManager");
5542
+ const endpoints = configManager2.getMcpEndpoints();
3592
5543
  spinner.succeed("\u7AEF\u70B9\u5217\u8868");
3593
5544
  if (endpoints.length === 0) {
3594
5545
  console.log(chalk5.yellow("\u672A\u914D\u7F6E\u4EFB\u4F55 MCP \u7AEF\u70B9"));
@@ -3611,10 +5562,10 @@ var init_EndpointCommandHandler = __esm({
3611
5562
  async handleAdd(url) {
3612
5563
  const spinner = ora4("\u6DFB\u52A0\u7AEF\u70B9...").start();
3613
5564
  try {
3614
- const configManager3 = this.getService("configManager");
3615
- configManager3.addMcpEndpoint(url);
5565
+ const configManager2 = this.getService("configManager");
5566
+ configManager2.addMcpEndpoint(url);
3616
5567
  spinner.succeed(`\u6210\u529F\u6DFB\u52A0\u7AEF\u70B9: ${url}`);
3617
- const endpoints = configManager3.getMcpEndpoints();
5568
+ const endpoints = configManager2.getMcpEndpoints();
3618
5569
  console.log(chalk5.gray(`\u5F53\u524D\u5171 ${endpoints.length} \u4E2A\u7AEF\u70B9`));
3619
5570
  } catch (error) {
3620
5571
  spinner.fail(
@@ -3629,10 +5580,10 @@ var init_EndpointCommandHandler = __esm({
3629
5580
  async handleRemove(url) {
3630
5581
  const spinner = ora4("\u79FB\u9664\u7AEF\u70B9...").start();
3631
5582
  try {
3632
- const configManager3 = this.getService("configManager");
3633
- configManager3.removeMcpEndpoint(url);
5583
+ const configManager2 = this.getService("configManager");
5584
+ configManager2.removeMcpEndpoint(url);
3634
5585
  spinner.succeed(`\u6210\u529F\u79FB\u9664\u7AEF\u70B9: ${url}`);
3635
- const endpoints = configManager3.getMcpEndpoints();
5586
+ const endpoints = configManager2.getMcpEndpoints();
3636
5587
  console.log(chalk5.gray(`\u5F53\u524D\u5269\u4F59 ${endpoints.length} \u4E2A\u7AEF\u70B9`));
3637
5588
  } catch (error) {
3638
5589
  spinner.fail(
@@ -3647,12 +5598,12 @@ var init_EndpointCommandHandler = __esm({
3647
5598
  async handleSet(urls) {
3648
5599
  const spinner = ora4("\u8BBE\u7F6E\u7AEF\u70B9...").start();
3649
5600
  try {
3650
- const configManager3 = this.getService("configManager");
5601
+ const configManager2 = this.getService("configManager");
3651
5602
  if (urls.length === 1) {
3652
- configManager3.updateMcpEndpoint(urls[0]);
5603
+ configManager2.updateMcpEndpoint(urls[0]);
3653
5604
  spinner.succeed(`\u6210\u529F\u8BBE\u7F6E\u7AEF\u70B9: ${urls[0]}`);
3654
5605
  } else {
3655
- configManager3.updateMcpEndpoint(urls);
5606
+ configManager2.updateMcpEndpoint(urls);
3656
5607
  spinner.succeed(`\u6210\u529F\u8BBE\u7F6E ${urls.length} \u4E2A\u7AEF\u70B9`);
3657
5608
  for (const [index, url] of urls.entries()) {
3658
5609
  console.log(chalk5.gray(` ${index + 1}. ${url}`));
@@ -3669,17 +5620,167 @@ var init_EndpointCommandHandler = __esm({
3669
5620
  }
3670
5621
  });
3671
5622
 
3672
- // src/index.ts
5623
+ // index.ts
3673
5624
  import { Command } from "commander";
3674
5625
 
3675
- // src/Container.ts
3676
- import { configManager } from "@xiaozhi-client/config";
3677
- import { VersionUtils } from "@xiaozhi-client/version";
5626
+ // Container.ts
5627
+ init_config();
5628
+
5629
+ // ../utils/version.ts
5630
+ import fs from "fs";
5631
+ import path3 from "path";
5632
+ import { fileURLToPath as fileURLToPath3 } from "url";
5633
+ var VERSION = "2.3.0";
5634
+ var APP_NAME = "xiaozhi-client";
5635
+ var VersionUtils = class _VersionUtils {
5636
+ static {
5637
+ __name(this, "VersionUtils");
5638
+ }
5639
+ static cachedVersion = null;
5640
+ static cachedVersionInfo = null;
5641
+ /**
5642
+ * 获取版本号
5643
+ *
5644
+ * 优先使用构建时注入的版本号常量
5645
+ * 如果是占位符,则运行时从 package.json 读取
5646
+ */
5647
+ static getVersion() {
5648
+ if (VERSION === "__VERSION__") {
5649
+ return _VersionUtils.getRuntimeVersion();
5650
+ }
5651
+ return VERSION;
5652
+ }
5653
+ /**
5654
+ * 获取完整版本信息
5655
+ */
5656
+ static getVersionInfo() {
5657
+ if (_VersionUtils.cachedVersionInfo) {
5658
+ return _VersionUtils.cachedVersionInfo;
5659
+ }
5660
+ if (VERSION === "__VERSION__") {
5661
+ _VersionUtils.cachedVersionInfo = _VersionUtils.getRuntimeVersionInfo();
5662
+ return _VersionUtils.cachedVersionInfo;
5663
+ }
5664
+ _VersionUtils.cachedVersionInfo = {
5665
+ version: VERSION,
5666
+ name: APP_NAME === "__APP_NAME__" ? void 0 : APP_NAME
5667
+ };
5668
+ return _VersionUtils.cachedVersionInfo;
5669
+ }
5670
+ /**
5671
+ * 比较版本号
5672
+ *
5673
+ * @param version1 第一个版本号
5674
+ * @param version2 第二个版本号
5675
+ * @returns 返回值:1 表示 version1 > version2,-1 表示 version1 < version2,0 表示相等
5676
+ */
5677
+ static compareVersions(version1, version2) {
5678
+ const v1Parts = version1.split(".").map(Number);
5679
+ const v2Parts = version2.split(".").map(Number);
5680
+ const maxLength = Math.max(v1Parts.length, v2Parts.length);
5681
+ for (let i = 0; i < maxLength; i++) {
5682
+ const v1Part = v1Parts[i] || 0;
5683
+ const v2Part = v2Parts[i] || 0;
5684
+ if (v1Part > v2Part) return 1;
5685
+ if (v1Part < v2Part) return -1;
5686
+ }
5687
+ return 0;
5688
+ }
5689
+ /**
5690
+ * 检查版本是否有效
5691
+ *
5692
+ * @param version 版本号字符串
5693
+ * @returns 是否为有效的语义化版本号
5694
+ */
5695
+ static isValidVersion(version) {
5696
+ const versionRegex = /^\d+\.\d+\.\d+(-[a-zA-Z0-9.-]+)?(\+[a-zA-Z0-9.-]+)?$/;
5697
+ return versionRegex.test(version);
5698
+ }
5699
+ /**
5700
+ * 查找 package.json 文件路径
5701
+ *
5702
+ * 尝试从多个可能的路径中查找 package.json 文件
5703
+ *
5704
+ * @returns package.json 文件路径,如果找不到则返回 null
5705
+ */
5706
+ static findPackageJsonPath() {
5707
+ const __filename = fileURLToPath3(import.meta.url);
5708
+ const currentDir = path3.dirname(__filename);
5709
+ const possiblePaths = [
5710
+ // 从 src/utils/version.js 到项目根目录的 package.json
5711
+ path3.join(currentDir, "..", "..", "package.json"),
5712
+ // 从 dist/utils/version.js 到项目根目录的 package.json
5713
+ path3.join(currentDir, "..", "..", "..", "package.json"),
5714
+ // 全局安装环境
5715
+ path3.join(currentDir, "..", "..", "..", "..", "package.json")
5716
+ ];
5717
+ for (const packagePath of possiblePaths) {
5718
+ if (fs.existsSync(packagePath)) {
5719
+ return packagePath;
5720
+ }
5721
+ }
5722
+ return null;
5723
+ }
5724
+ /**
5725
+ * 运行时从 package.json 读取版本号
5726
+ */
5727
+ static getRuntimeVersion() {
5728
+ if (_VersionUtils.cachedVersion) {
5729
+ return _VersionUtils.cachedVersion;
5730
+ }
5731
+ try {
5732
+ const packagePath = _VersionUtils.findPackageJsonPath();
5733
+ if (packagePath) {
5734
+ const packageJson = JSON.parse(fs.readFileSync(packagePath, "utf8"));
5735
+ if (packageJson.version) {
5736
+ _VersionUtils.cachedVersion = packageJson.version;
5737
+ return packageJson.version;
5738
+ }
5739
+ }
5740
+ _VersionUtils.cachedVersion = "unknown";
5741
+ return "unknown";
5742
+ } catch (error) {
5743
+ console.warn("\u65E0\u6CD5\u4ECE package.json \u8BFB\u53D6\u7248\u672C\u4FE1\u606F:", error);
5744
+ _VersionUtils.cachedVersion = "unknown";
5745
+ return "unknown";
5746
+ }
5747
+ }
5748
+ /**
5749
+ * 运行时从 package.json 读取完整版本信息
5750
+ */
5751
+ static getRuntimeVersionInfo() {
5752
+ try {
5753
+ const packagePath = _VersionUtils.findPackageJsonPath();
5754
+ if (packagePath) {
5755
+ const packageJson = JSON.parse(fs.readFileSync(packagePath, "utf8"));
5756
+ return {
5757
+ version: packageJson.version || "unknown",
5758
+ name: packageJson.name,
5759
+ description: packageJson.description,
5760
+ author: packageJson.author
5761
+ };
5762
+ }
5763
+ return { version: "unknown" };
5764
+ } catch (error) {
5765
+ console.warn("\u65E0\u6CD5\u8BFB\u53D6\u7248\u672C\u4FE1\u606F:", error);
5766
+ return { version: "unknown" };
5767
+ }
5768
+ }
5769
+ /**
5770
+ * 清除版本缓存
5771
+ *
5772
+ * 主要用于测试场景
5773
+ */
5774
+ static clearCache() {
5775
+ _VersionUtils.cachedVersion = null;
5776
+ _VersionUtils.cachedVersionInfo = null;
5777
+ }
5778
+ };
3678
5779
 
3679
- // src/errors/ErrorHandlers.ts
5780
+ // errors/ErrorHandlers.ts
3680
5781
  import chalk from "chalk";
3681
5782
 
3682
- // src/errors/ErrorMessages.ts
5783
+ // errors/ErrorMessages.ts
3683
5784
  init_Constants();
3684
5785
  var ERROR_HELP_MESSAGES = {
3685
5786
  [ERROR_CODES.CONFIG_ERROR]: '\u8FD0\u884C "xiaozhi --help" \u67E5\u770B\u914D\u7F6E\u76F8\u5173\u547D\u4EE4',
@@ -3778,7 +5879,7 @@ var ERROR_MESSAGES = class {
3778
5879
  }
3779
5880
  };
3780
5881
 
3781
- // src/errors/ErrorHandlers.ts
5882
+ // errors/ErrorHandlers.ts
3782
5883
  init_errors();
3783
5884
  var ErrorHandler = class _ErrorHandler {
3784
5885
  static {
@@ -3890,7 +5991,7 @@ var ErrorHandler = class _ErrorHandler {
3890
5991
  }
3891
5992
  };
3892
5993
 
3893
- // src/Container.ts
5994
+ // Container.ts
3894
5995
  init_FileUtils();
3895
5996
  init_FormatUtils();
3896
5997
  init_PathUtils();
@@ -4006,10 +6107,10 @@ var DIContainer = class _DIContainer {
4006
6107
  container.registerSingleton("serviceManager", () => {
4007
6108
  const ServiceManagerModule = (init_ServiceManager(), __toCommonJS(ServiceManager_exports));
4008
6109
  const processManager = container.get("processManager");
4009
- const configManager3 = container.get("configManager");
6110
+ const configManager2 = container.get("configManager");
4010
6111
  return new ServiceManagerModule.ServiceManagerImpl(
4011
6112
  processManager,
4012
- configManager3
6113
+ configManager2
4013
6114
  );
4014
6115
  });
4015
6116
  container.registerSingleton("templateManager", () => {
@@ -4020,7 +6121,7 @@ var DIContainer = class _DIContainer {
4020
6121
  }
4021
6122
  };
4022
6123
 
4023
- // src/commands/CommandHandlerFactory.ts
6124
+ // commands/CommandHandlerFactory.ts
4024
6125
  var CommandHandlerFactory = class {
4025
6126
  constructor(container) {
4026
6127
  this.container = container;
@@ -4096,7 +6197,7 @@ var CommandHandlerFactory = class {
4096
6197
  }
4097
6198
  };
4098
6199
 
4099
- // src/commands/index.ts
6200
+ // commands/index.ts
4100
6201
  var CommandRegistry = class {
4101
6202
  constructor(container) {
4102
6203
  this.container = container;
@@ -4364,7 +6465,7 @@ var CommandRegistry = class {
4364
6465
  // }
4365
6466
  };
4366
6467
 
4367
- // src/index.ts
6468
+ // index.ts
4368
6469
  var program = new Command();
4369
6470
  async function initializeCLI() {
4370
6471
  try {