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/backend/Logger.js +14616 -2
- package/dist/backend/Logger.js.map +1 -1
- package/dist/backend/WebServer.js +60102 -23
- package/dist/backend/WebServer.js.map +1 -1
- package/dist/backend/WebServerLauncher.js +62160 -23
- package/dist/backend/WebServerLauncher.js.map +1 -1
- package/dist/backend/package.json +26 -24
- package/dist/cli/index.js +2303 -202
- package/dist/cli/index.js.map +1 -1
- package/dist/frontend/assets/index--4CLEU1w.css +1 -0
- package/dist/frontend/assets/{index-COIgGxBW.js → index-BJCmxT4H.js} +1 -1
- package/dist/frontend/assets/index-BJCmxT4H.js.map +1 -0
- package/dist/frontend/assets/utils-UasCLNM3.js.map +1 -1
- package/dist/frontend/index.html +2 -2
- package/package.json +27 -25
- package/dist/config/index.d.ts +0 -704
- package/dist/config/index.js +0 -1982
- package/dist/config/index.js.map +0 -1
- package/dist/frontend/assets/index-COIgGxBW.js.map +0 -1
- package/dist/frontend/assets/index-Cc1OJDGG.css +0 -1
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
|
-
//
|
|
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
|
-
"
|
|
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
|
-
//
|
|
2012
|
+
// errors/index.ts
|
|
101
2013
|
var CLIError, ConfigError, ServiceError, ValidationError, FileError, ProcessError;
|
|
102
2014
|
var init_errors = __esm({
|
|
103
|
-
"
|
|
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
|
-
//
|
|
240
|
-
import
|
|
2151
|
+
// utils/FileUtils.ts
|
|
2152
|
+
import fs2 from "fs";
|
|
241
2153
|
import { tmpdir } from "os";
|
|
242
|
-
import
|
|
2154
|
+
import path4 from "path";
|
|
243
2155
|
var FileUtils;
|
|
244
2156
|
var init_FileUtils = __esm({
|
|
245
|
-
"
|
|
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
|
|
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 (!
|
|
268
|
-
|
|
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
|
|
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 =
|
|
2210
|
+
const dir = path4.dirname(filePath);
|
|
299
2211
|
_FileUtils.ensureDir(dir);
|
|
300
|
-
|
|
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 =
|
|
2231
|
+
const destDir = path4.dirname(destPath);
|
|
320
2232
|
_FileUtils.ensureDir(destDir);
|
|
321
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
356
|
-
const destPath =
|
|
357
|
-
const stat =
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
2339
|
+
const itemPath = path4.join(dirPath, item);
|
|
428
2340
|
result.push(itemPath);
|
|
429
|
-
if (options.recursive &&
|
|
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
|
|
2362
|
+
return path4.join(tempDir, fileName);
|
|
451
2363
|
}
|
|
452
2364
|
/**
|
|
453
2365
|
* 检查文件权限
|
|
454
2366
|
*/
|
|
455
|
-
static checkPermissions(filePath, mode =
|
|
2367
|
+
static checkPermissions(filePath, mode = fs2.constants.R_OK | fs2.constants.W_OK) {
|
|
456
2368
|
try {
|
|
457
|
-
|
|
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
|
|
2379
|
+
return path4.extname(filePath).toLowerCase();
|
|
468
2380
|
}
|
|
469
2381
|
/**
|
|
470
2382
|
* 获取文件名(不含扩展名)
|
|
471
2383
|
*/
|
|
472
2384
|
static getBaseName(filePath) {
|
|
473
|
-
return
|
|
2385
|
+
return path4.basename(filePath, path4.extname(filePath));
|
|
474
2386
|
}
|
|
475
2387
|
/**
|
|
476
2388
|
* 规范化路径
|
|
477
2389
|
*/
|
|
478
2390
|
static normalizePath(filePath) {
|
|
479
|
-
return
|
|
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
|
|
2398
|
+
return path4.resolve(basePath, filePath);
|
|
487
2399
|
}
|
|
488
|
-
return
|
|
2400
|
+
return path4.resolve(filePath);
|
|
489
2401
|
}
|
|
490
2402
|
};
|
|
491
2403
|
}
|
|
492
2404
|
});
|
|
493
2405
|
|
|
494
|
-
//
|
|
2406
|
+
// utils/FormatUtils.ts
|
|
495
2407
|
var FormatUtils;
|
|
496
2408
|
var init_FormatUtils = __esm({
|
|
497
|
-
"
|
|
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,
|
|
2476
|
+
static formatUrl(protocol, host, port, path9) {
|
|
565
2477
|
const url = `${protocol}://${host}:${port}`;
|
|
566
|
-
return
|
|
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
|
-
//
|
|
2570
|
+
// utils/PathUtils.ts
|
|
659
2571
|
import { realpathSync } from "fs";
|
|
660
2572
|
import { tmpdir as tmpdir2 } from "os";
|
|
661
|
-
import
|
|
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
|
-
"
|
|
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
|
|
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
|
|
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
|
|
2610
|
+
return path5.join(configDir, PATH_CONSTANTS.WORK_DIR);
|
|
699
2611
|
}
|
|
700
2612
|
/**
|
|
701
2613
|
* 获取模板目录路径
|
|
702
2614
|
*/
|
|
703
2615
|
static getTemplatesDir() {
|
|
704
|
-
const __filename =
|
|
705
|
-
const scriptDir =
|
|
2616
|
+
const __filename = fileURLToPath4(import.meta.url);
|
|
2617
|
+
const scriptDir = path5.dirname(__filename);
|
|
706
2618
|
return [
|
|
707
2619
|
// 构建后的环境:dist/cli.js -> dist/templates
|
|
708
|
-
|
|
2620
|
+
path5.join(scriptDir, PATH_CONSTANTS.TEMPLATES_DIR),
|
|
709
2621
|
// 构建环境:dist/cli/index.js -> dist/backend/templates
|
|
710
|
-
|
|
2622
|
+
path5.join(scriptDir, "..", "backend", PATH_CONSTANTS.TEMPLATES_DIR),
|
|
711
2623
|
// npm 全局安装
|
|
712
|
-
|
|
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 =
|
|
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 =
|
|
750
|
-
return
|
|
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
|
|
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
|
|
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
|
|
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
|
|
2691
|
+
return path5.join(configDir, `xiaozhi.config.${format}`);
|
|
780
2692
|
}
|
|
781
2693
|
for (const fileName of CONFIG_CONSTANTS.FILE_NAMES) {
|
|
782
|
-
const filePath =
|
|
2694
|
+
const filePath = path5.join(configDir, fileName);
|
|
783
2695
|
if (FileUtils.exists(filePath)) {
|
|
784
2696
|
return filePath;
|
|
785
2697
|
}
|
|
786
2698
|
}
|
|
787
|
-
return
|
|
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
|
|
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 =
|
|
801
|
-
|
|
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 =
|
|
808
|
-
const resolvedBase =
|
|
809
|
-
|
|
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
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
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
|
|
829
|
-
return
|
|
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
|
-
|
|
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 =
|
|
842
|
-
const normalizedPath =
|
|
843
|
-
|
|
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
|
-
//
|
|
2787
|
+
// utils/PlatformUtils.ts
|
|
865
2788
|
import { execSync } from "child_process";
|
|
866
2789
|
var PlatformUtils;
|
|
867
2790
|
var init_PlatformUtils = __esm({
|
|
868
|
-
"
|
|
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((
|
|
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((
|
|
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
|
-
//
|
|
2963
|
+
// utils/Validation.ts
|
|
1041
2964
|
var Validation;
|
|
1042
2965
|
var init_Validation = __esm({
|
|
1043
|
-
"
|
|
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
|
-
//
|
|
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
|
-
"
|
|
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
|
-
//
|
|
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
|
|
3370
|
+
import fs3 from "fs";
|
|
1448
3371
|
import consola from "consola";
|
|
1449
3372
|
var DaemonManagerImpl;
|
|
1450
3373
|
var init_DaemonManager = __esm({
|
|
1451
|
-
"
|
|
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
|
-
(
|
|
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 (!
|
|
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
|
|
1592
|
-
const logDir =
|
|
1593
|
-
if (!
|
|
1594
|
-
|
|
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 =
|
|
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
|
-
//
|
|
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
|
-
"
|
|
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,
|
|
3610
|
+
constructor(processManager, configManager2) {
|
|
1688
3611
|
this.processManager = processManager;
|
|
1689
|
-
this.configManager =
|
|
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
|
-
(
|
|
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
|
-
(
|
|
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
|
|
1892
|
-
if (!
|
|
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
|
-
//
|
|
3856
|
+
// services/TemplateManager.ts
|
|
1934
3857
|
var TemplateManager_exports = {};
|
|
1935
3858
|
__export(TemplateManager_exports, {
|
|
1936
3859
|
TemplateManagerImpl: () => TemplateManagerImpl
|
|
1937
3860
|
});
|
|
1938
|
-
import
|
|
1939
|
-
import
|
|
3861
|
+
import fs4 from "fs";
|
|
3862
|
+
import path6 from "path";
|
|
1940
3863
|
var TemplateManagerImpl;
|
|
1941
3864
|
var init_TemplateManager = __esm({
|
|
1942
|
-
"
|
|
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 =
|
|
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 =
|
|
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:
|
|
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
|
|
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
|
-
|
|
2050
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
//
|
|
4160
|
+
// interfaces/Command.ts
|
|
2214
4161
|
var BaseCommandHandler;
|
|
2215
4162
|
var init_Command = __esm({
|
|
2216
|
-
"
|
|
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
|
-
//
|
|
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
|
-
"
|
|
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
|
-
//
|
|
4371
|
+
// commands/ConfigCommandHandler.ts
|
|
2425
4372
|
var ConfigCommandHandler_exports = {};
|
|
2426
4373
|
__export(ConfigCommandHandler_exports, {
|
|
2427
4374
|
ConfigCommandHandler: () => ConfigCommandHandler
|
|
2428
4375
|
});
|
|
2429
|
-
import
|
|
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
|
-
"
|
|
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
|
|
2495
|
-
if (
|
|
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
|
-
|
|
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 =
|
|
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
|
|
2524
|
-
if (!
|
|
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
|
|
2543
|
-
const config =
|
|
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 =
|
|
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 =
|
|
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: ${
|
|
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: ${
|
|
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: ${
|
|
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
|
|
4588
|
+
const configManager2 = this.getService("configManager");
|
|
2642
4589
|
switch (key) {
|
|
2643
4590
|
case "mcpEndpoint":
|
|
2644
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
4640
|
+
// commands/ProjectCommandHandler.ts
|
|
2694
4641
|
var ProjectCommandHandler_exports = {};
|
|
2695
4642
|
__export(ProjectCommandHandler_exports, {
|
|
2696
4643
|
ProjectCommandHandler: () => ProjectCommandHandler
|
|
2697
4644
|
});
|
|
2698
|
-
import
|
|
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
|
-
"
|
|
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 =
|
|
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(
|
|
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((
|
|
4830
|
+
return new Promise((resolve4) => {
|
|
2880
4831
|
rl.question(prompt, (answer) => {
|
|
2881
4832
|
rl.close();
|
|
2882
|
-
|
|
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
|
-
//
|
|
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
|
-
"
|
|
4849
|
+
"interfaces/CommandTypes.ts"() {
|
|
2899
4850
|
"use strict";
|
|
2900
4851
|
__name(isLocalMCPServerConfig, "isLocalMCPServerConfig");
|
|
2901
4852
|
}
|
|
2902
4853
|
});
|
|
2903
4854
|
|
|
2904
|
-
//
|
|
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
|
-
"
|
|
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 =
|
|
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 =
|
|
5184
|
+
const mcpServers = configManager.getMcpServers();
|
|
3234
5185
|
const serverNames = Object.keys(mcpServers);
|
|
3235
|
-
const customMCPTools =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
-
//
|
|
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
|
-
"
|
|
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
|
|
3591
|
-
const endpoints =
|
|
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
|
|
3615
|
-
|
|
5565
|
+
const configManager2 = this.getService("configManager");
|
|
5566
|
+
configManager2.addMcpEndpoint(url);
|
|
3616
5567
|
spinner.succeed(`\u6210\u529F\u6DFB\u52A0\u7AEF\u70B9: ${url}`);
|
|
3617
|
-
const endpoints =
|
|
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
|
|
3633
|
-
|
|
5583
|
+
const configManager2 = this.getService("configManager");
|
|
5584
|
+
configManager2.removeMcpEndpoint(url);
|
|
3634
5585
|
spinner.succeed(`\u6210\u529F\u79FB\u9664\u7AEF\u70B9: ${url}`);
|
|
3635
|
-
const endpoints =
|
|
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
|
|
5601
|
+
const configManager2 = this.getService("configManager");
|
|
3651
5602
|
if (urls.length === 1) {
|
|
3652
|
-
|
|
5603
|
+
configManager2.updateMcpEndpoint(urls[0]);
|
|
3653
5604
|
spinner.succeed(`\u6210\u529F\u8BBE\u7F6E\u7AEF\u70B9: ${urls[0]}`);
|
|
3654
5605
|
} else {
|
|
3655
|
-
|
|
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
|
-
//
|
|
5623
|
+
// index.ts
|
|
3673
5624
|
import { Command } from "commander";
|
|
3674
5625
|
|
|
3675
|
-
//
|
|
3676
|
-
|
|
3677
|
-
|
|
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
|
-
//
|
|
5780
|
+
// errors/ErrorHandlers.ts
|
|
3680
5781
|
import chalk from "chalk";
|
|
3681
5782
|
|
|
3682
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
|
6110
|
+
const configManager2 = container.get("configManager");
|
|
4010
6111
|
return new ServiceManagerModule.ServiceManagerImpl(
|
|
4011
6112
|
processManager,
|
|
4012
|
-
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
//
|
|
6468
|
+
// index.ts
|
|
4368
6469
|
var program = new Command();
|
|
4369
6470
|
async function initializeCLI() {
|
|
4370
6471
|
try {
|