@xubill/xx-cli 2.0.4
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/README.md +181 -0
- package/bin/cli.js +89 -0
- package/lib/core/base-plugin.js +292 -0
- package/lib/core/index.js +550 -0
- package/lib/plugins/ai.js +295 -0
- package/lib/plugins/config-manager.js +165 -0
- package/lib/plugins/history.js +108 -0
- package/lib/plugins/plugin-manager.js +700 -0
- package/lib/utils/config-manager.js +185 -0
- package/lib/utils/history-manager.js +119 -0
- package/lib/utils/logger.js +28 -0
- package/lib/utils/plugin-config.js +158 -0
- package/lib/utils/plugins-helper.js +276 -0
- package/lib/utils/transformers/getInput.js +76 -0
- package/lib/utils/transformers/index.js +43 -0
- package/lib/utils/transformers/renderLists.js +94 -0
- package/lib/utils/transformers/sfcMaterial.js +113 -0
- package/lib/utils/transformers/transformFilter.js +95 -0
- package/lib/utils/transformers/transformList.js +120 -0
- package/lib/utils/transformers/transformMock.js +43 -0
- package/lib/utils/transformers/transformRoutes.js +36 -0
- package/lib/utils/transformers/transformTable.js +81 -0
- package/lib/utils/transformers/transformTemplate.js +129 -0
- package/lib/utils/validator.js +96 -0
- package/package.json +68 -0
- package/plugin-development-new.md +565 -0
- package/plugin-development-old.md +447 -0
|
@@ -0,0 +1,550 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* xx 核心模块
|
|
3
|
+
* 负责初始化系统、注册命令、管理插件等
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const fs = require("fs");
|
|
7
|
+
const path = require("path");
|
|
8
|
+
const logger = require("../utils/logger");
|
|
9
|
+
const pkg = require("../../package.json");
|
|
10
|
+
const pluginConfig = require("../utils/plugin-config");
|
|
11
|
+
const { createPluginsHelper } = require('../utils/plugins-helper');
|
|
12
|
+
|
|
13
|
+
class Core {
|
|
14
|
+
constructor() {
|
|
15
|
+
this.plugins = [];
|
|
16
|
+
this.commands = [];
|
|
17
|
+
this.version = pkg.version;
|
|
18
|
+
this.pluginFiles = [];
|
|
19
|
+
this.pluginCache = new Map(); // 插件缓存
|
|
20
|
+
this.hooks = {}; // 全局钩子
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* 初始化核心功能
|
|
25
|
+
*/
|
|
26
|
+
async init() {
|
|
27
|
+
//logger.info('正在初始化 xx 核心...');
|
|
28
|
+
this.loadPlugins();
|
|
29
|
+
|
|
30
|
+
// 触发初始化完成钩子
|
|
31
|
+
await this.triggerHook("init", { core: this });
|
|
32
|
+
|
|
33
|
+
//logger.info('xx 核心初始化完成');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* 加载插件
|
|
38
|
+
*/
|
|
39
|
+
loadPlugins() {
|
|
40
|
+
// 内置插件目录(会被重新安装覆盖)
|
|
41
|
+
const builtinPluginsDir = path.join(__dirname, "../plugins");
|
|
42
|
+
// 用户插件目录(不会被重新安装影响)
|
|
43
|
+
const userPluginsDir = path.join(
|
|
44
|
+
process.env.HOME || process.env.USERPROFILE,
|
|
45
|
+
".xx-cli",
|
|
46
|
+
"plugins",
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
// 确保用户插件目录存在
|
|
50
|
+
if (!fs.existsSync(userPluginsDir)) {
|
|
51
|
+
fs.mkdirSync(userPluginsDir, { recursive: true });
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// 收集内置插件
|
|
55
|
+
let pluginFiles = [];
|
|
56
|
+
if (fs.existsSync(builtinPluginsDir)) {
|
|
57
|
+
const builtinFiles = fs.readdirSync(builtinPluginsDir);
|
|
58
|
+
pluginFiles = builtinFiles.filter((file) => file.endsWith(".js"));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// 收集用户插件
|
|
62
|
+
if (fs.existsSync(userPluginsDir)) {
|
|
63
|
+
const userFiles = fs.readdirSync(userPluginsDir);
|
|
64
|
+
const userPluginFiles = userFiles.filter((file) => file.endsWith(".js"));
|
|
65
|
+
// 将用户插件添加到插件文件列表中
|
|
66
|
+
pluginFiles = [...pluginFiles, ...userPluginFiles];
|
|
67
|
+
}
|
|
68
|
+
// 只收集插件文件信息,不立即加载
|
|
69
|
+
this.pluginFiles = pluginFiles;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* 加载单个插件
|
|
74
|
+
* @param {string} pluginFile - 插件文件名
|
|
75
|
+
* @returns {Object|null} 插件实例或null
|
|
76
|
+
*/
|
|
77
|
+
loadPlugin(pluginFile) {
|
|
78
|
+
// 检查缓存中是否已存在插件实例
|
|
79
|
+
if (this.pluginCache.has(pluginFile)) {
|
|
80
|
+
return this.pluginCache.get(pluginFile);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// 内置插件目录
|
|
84
|
+
const builtinPluginsDir = path.join(__dirname, "../plugins");
|
|
85
|
+
// 用户插件目录
|
|
86
|
+
const userPluginsDir = path.join(
|
|
87
|
+
process.env.HOME || process.env.USERPROFILE,
|
|
88
|
+
".xx-cli",
|
|
89
|
+
"plugins",
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
// 优先从内置插件目录加载
|
|
93
|
+
let pluginPath = path.join(builtinPluginsDir, pluginFile);
|
|
94
|
+
|
|
95
|
+
// 如果内置插件目录中不存在,则从用户插件目录加载
|
|
96
|
+
if (!fs.existsSync(pluginPath)) {
|
|
97
|
+
pluginPath = path.join(userPluginsDir, pluginFile);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// 如果两个目录中都不存在,则返回null
|
|
101
|
+
if (!fs.existsSync(pluginPath)) {
|
|
102
|
+
logger.error(`插件文件 ${pluginFile} 不存在`);
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
try {
|
|
107
|
+
// 读取插件文件内容
|
|
108
|
+
let pluginContent = fs.readFileSync(pluginPath, "utf8");
|
|
109
|
+
|
|
110
|
+
// 替换插件文件中的相对路径导入为绝对路径导入
|
|
111
|
+
// 替换 ../core 为绝对路径
|
|
112
|
+
const coreDir = path.join(__dirname, "../core");
|
|
113
|
+
pluginContent = pluginContent.replace(
|
|
114
|
+
/require\('\.\.\/core\//g,
|
|
115
|
+
`require('${coreDir}/`,
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
// 替换 ../utils 为绝对路径
|
|
119
|
+
const utilsDir = path.join(__dirname, "../utils");
|
|
120
|
+
pluginContent = pluginContent.replace(
|
|
121
|
+
/require\('\.\.\/utils\//g,
|
|
122
|
+
`require('${utilsDir}/`,
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
// 创建一个临时模块来加载修改后的插件内容
|
|
126
|
+
const Module = require("module");
|
|
127
|
+
const tempModule = new Module(pluginPath);
|
|
128
|
+
tempModule.filename = pluginPath;
|
|
129
|
+
tempModule.paths = module.paths;
|
|
130
|
+
|
|
131
|
+
// 编译并执行修改后的插件内容
|
|
132
|
+
tempModule._compile(pluginContent, pluginPath);
|
|
133
|
+
|
|
134
|
+
const Plugin = tempModule.exports;
|
|
135
|
+
|
|
136
|
+
// 检查是否为新格式的插件对象
|
|
137
|
+
if (
|
|
138
|
+
Plugin &&
|
|
139
|
+
typeof Plugin === "object" &&
|
|
140
|
+
Plugin.name &&
|
|
141
|
+
(Plugin.action || Plugin.subcommands)
|
|
142
|
+
) {
|
|
143
|
+
// 新格式插件对象,不需要实例化
|
|
144
|
+
this.pluginCache.set(pluginFile, Plugin);
|
|
145
|
+
return Plugin;
|
|
146
|
+
} else if (typeof Plugin === "function" && Plugin.prototype) {
|
|
147
|
+
// 实例化类插件
|
|
148
|
+
const pluginInstance = new Plugin();
|
|
149
|
+
pluginInstance.pluginName =
|
|
150
|
+
pluginInstance.pluginName || pluginFile.replace(".js", "");
|
|
151
|
+
|
|
152
|
+
// 缓存插件实例
|
|
153
|
+
this.pluginCache.set(pluginFile, pluginInstance);
|
|
154
|
+
return pluginInstance;
|
|
155
|
+
} else {
|
|
156
|
+
// 保持非类插件的兼容性
|
|
157
|
+
// 对于函数式插件,也可能是新格式
|
|
158
|
+
if (
|
|
159
|
+
Plugin &&
|
|
160
|
+
typeof Plugin === "object" &&
|
|
161
|
+
Plugin.name &&
|
|
162
|
+
(Plugin.action || Plugin.subcommands)
|
|
163
|
+
) {
|
|
164
|
+
// 新格式插件对象
|
|
165
|
+
this.pluginCache.set(pluginFile, Plugin);
|
|
166
|
+
return Plugin;
|
|
167
|
+
} else {
|
|
168
|
+
// 旧格式函数式插件
|
|
169
|
+
this.pluginCache.set(pluginFile, Plugin);
|
|
170
|
+
return Plugin;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
} catch (error) {
|
|
174
|
+
logger.error(`加载插件 ${pluginFile} 失败: ${error.message}`);
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* 获取所有插件信息
|
|
181
|
+
* @returns {Array} 插件信息数组
|
|
182
|
+
*/
|
|
183
|
+
getPluginsInfo() {
|
|
184
|
+
return this.pluginFiles.map((pluginFile) => {
|
|
185
|
+
const pluginName = pluginFile.replace(".js", "");
|
|
186
|
+
return {
|
|
187
|
+
name: pluginName,
|
|
188
|
+
file: pluginFile,
|
|
189
|
+
};
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* 注册命令到 Commander
|
|
195
|
+
* @param {Object} program - Commander 实例
|
|
196
|
+
*/
|
|
197
|
+
registerCommands(program) {
|
|
198
|
+
// 注册核心命令
|
|
199
|
+
this.registerCoreCommands(program);
|
|
200
|
+
|
|
201
|
+
// 注册插件命令
|
|
202
|
+
if (this.pluginFiles) {
|
|
203
|
+
this.pluginFiles.forEach((pluginFile) => {
|
|
204
|
+
const pluginName = pluginFile.replace(".js", "");
|
|
205
|
+
|
|
206
|
+
// 检查插件是否已禁用
|
|
207
|
+
if (pluginConfig.isPluginDisabled(pluginName)) {
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const plugin = this.loadPlugin(pluginFile);
|
|
212
|
+
if (plugin) {
|
|
213
|
+
try {
|
|
214
|
+
// 检查是否为新格式插件
|
|
215
|
+
if (
|
|
216
|
+
plugin.name &&
|
|
217
|
+
(typeof plugin.action === "function" ||
|
|
218
|
+
(plugin.subcommands && Array.isArray(plugin.subcommands)))
|
|
219
|
+
) {
|
|
220
|
+
this.registerNewFormatPlugin(program, plugin, pluginName);
|
|
221
|
+
} else if (plugin.registerCommands) {
|
|
222
|
+
// 旧格式插件
|
|
223
|
+
plugin.registerCommands(program);
|
|
224
|
+
}
|
|
225
|
+
} catch (error) {
|
|
226
|
+
// 捕获命令别名冲突等错误,确保其他插件能够正常注册
|
|
227
|
+
if (error.message && error.message.includes("cannot add alias")) {
|
|
228
|
+
console.warn(
|
|
229
|
+
`警告: 插件 ${pluginName} 的命令别名与其他插件冲突,已跳过此插件的命令注册`,
|
|
230
|
+
);
|
|
231
|
+
} else {
|
|
232
|
+
console.log(error)
|
|
233
|
+
console.error(
|
|
234
|
+
`错误: 插件 ${pluginName} 注册命令失败: ${error.message}`,
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// 注册命令自动建议功能
|
|
243
|
+
this.registerCommandSuggestions(program);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* 注册新格式插件命令
|
|
248
|
+
* @param {Object} program - Commander 实例
|
|
249
|
+
* @param {Object} plugin - 插件对象
|
|
250
|
+
* @param {string} pluginName - 插件名称
|
|
251
|
+
*/
|
|
252
|
+
registerNewFormatPlugin(program, plugin, pluginName) {
|
|
253
|
+
const cmd = program.command(plugin.name);
|
|
254
|
+
|
|
255
|
+
// 设置描述
|
|
256
|
+
if (plugin.description) {
|
|
257
|
+
cmd.description(plugin.description);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// 设置别名
|
|
261
|
+
if (plugin.alias) {
|
|
262
|
+
cmd.alias(plugin.alias);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// 添加选项
|
|
266
|
+
if (plugin.options && Array.isArray(plugin.options)) {
|
|
267
|
+
plugin.options.forEach((option) => {
|
|
268
|
+
if (option.name && option.description) {
|
|
269
|
+
cmd.option(option.name, option.description);
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// 如果插件定义了子命令,则注册它们
|
|
275
|
+
if (plugin.subcommands && Array.isArray(plugin.subcommands)) {
|
|
276
|
+
plugin.subcommands.forEach((subcmd) => {
|
|
277
|
+
const subCommand = cmd.command(subcmd.name);
|
|
278
|
+
|
|
279
|
+
if (subcmd.description) {
|
|
280
|
+
subCommand.description(subcmd.description);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (subcmd.options && Array.isArray(subcmd.options)) {
|
|
284
|
+
subcmd.options.forEach((option) => {
|
|
285
|
+
if (option.name && option.description) {
|
|
286
|
+
subCommand.option(option.name, option.description);
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
subCommand.action(async (...args) => {
|
|
292
|
+
let commandArgs = [];
|
|
293
|
+
let options = {};
|
|
294
|
+
|
|
295
|
+
if (args.length > 0) {
|
|
296
|
+
const lastArg = args[args.length - 1];
|
|
297
|
+
if (lastArg && typeof lastArg === 'object' && typeof lastArg.opts === 'function') {
|
|
298
|
+
options = { ...lastArg.opts() };
|
|
299
|
+
commandArgs = lastArg.args || [];
|
|
300
|
+
} else {
|
|
301
|
+
commandArgs = [...args];
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// 创建插件帮助器实例
|
|
306
|
+
const helper = createPluginsHelper(plugin.name);
|
|
307
|
+
// 调用子命令的 action 方法
|
|
308
|
+
await subcmd.action(commandArgs, options, helper);
|
|
309
|
+
});
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// 设置主命令的 action
|
|
314
|
+
if (plugin.action) {
|
|
315
|
+
cmd.action(async (...args) => {
|
|
316
|
+
// Commander.js 会将参数和选项作为单独的参数传递
|
|
317
|
+
// 最后一个参数通常是 Command 对象,其中包含选项
|
|
318
|
+
let commandArgs = [];
|
|
319
|
+
let options = {};
|
|
320
|
+
|
|
321
|
+
// 如果有参数,需要正确识别哪个是 Command 对象
|
|
322
|
+
if (args.length > 0) {
|
|
323
|
+
// 从后往前检查,找到 Command 对象
|
|
324
|
+
let commandObjIndex = -1;
|
|
325
|
+
for (let i = args.length - 1; i >= 0; i--) {
|
|
326
|
+
const arg = args[i];
|
|
327
|
+
if (
|
|
328
|
+
arg &&
|
|
329
|
+
typeof arg === "object" &&
|
|
330
|
+
typeof arg.opts === "function"
|
|
331
|
+
) {
|
|
332
|
+
commandObjIndex = i;
|
|
333
|
+
break;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if (commandObjIndex !== -1) {
|
|
338
|
+
// 找到了 Command 对象
|
|
339
|
+
options = { ...args[commandObjIndex].opts() };
|
|
340
|
+
// 从 Command 对象的 args 属性获取命令参数
|
|
341
|
+
const commandObj = args[commandObjIndex];
|
|
342
|
+
commandArgs = commandObj.args || [];
|
|
343
|
+
} else {
|
|
344
|
+
// 没有 Command 对象,所有参数都是命令参数
|
|
345
|
+
commandArgs = [...args];
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// 创建插件帮助器实例
|
|
350
|
+
const helper = createPluginsHelper(plugin.name);
|
|
351
|
+
// 调用插件的 action 方法
|
|
352
|
+
await plugin.action(commandArgs, options, helper);
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* 注册命令自动建议功能
|
|
359
|
+
* @param {Object} program - Commander 实例
|
|
360
|
+
*/
|
|
361
|
+
registerCommandSuggestions(program) {
|
|
362
|
+
// 收集所有命令信息
|
|
363
|
+
const allCommands = this.collectAllCommands(program);
|
|
364
|
+
|
|
365
|
+
// 添加命令自动建议
|
|
366
|
+
program.on("command:*", async (args) => {
|
|
367
|
+
const inputCommand = args[0];
|
|
368
|
+
const suggestions = this.getCommandSuggestions(inputCommand, allCommands);
|
|
369
|
+
|
|
370
|
+
if (suggestions.length > 0) {
|
|
371
|
+
console.log(`\n未找到命令 "${inputCommand}",您可能想要:`);
|
|
372
|
+
suggestions.forEach((suggestion) => {
|
|
373
|
+
console.log(` - ${suggestion}`);
|
|
374
|
+
});
|
|
375
|
+
console.log("");
|
|
376
|
+
process.exit(1);
|
|
377
|
+
} else {
|
|
378
|
+
// 如果没有建议,也显示错误信息
|
|
379
|
+
console.log(`\n未找到命令 "${inputCommand}"。`);
|
|
380
|
+
console.log('使用 "xx help" 查看所有可用命令。');
|
|
381
|
+
|
|
382
|
+
// 自动调用 AI 解释命令作为兜底
|
|
383
|
+
console.log('\n正在调用 AI 解释您的输入...');
|
|
384
|
+
|
|
385
|
+
try {
|
|
386
|
+
// 动态导入 ai 插件
|
|
387
|
+
const aiPath = path.join(__dirname, '../plugins/ai.js');
|
|
388
|
+
if (fs.existsSync(aiPath)) {
|
|
389
|
+
const AIPlugin = require(aiPath);
|
|
390
|
+
if (AIPlugin.prototype && typeof AIPlugin === 'function') {
|
|
391
|
+
// 类继承格式插件
|
|
392
|
+
const pluginInstance = new AIPlugin();
|
|
393
|
+
if (pluginInstance.handleAI) {
|
|
394
|
+
await pluginInstance.handleAI(args, {});
|
|
395
|
+
}
|
|
396
|
+
} else if (AIPlugin.action) {
|
|
397
|
+
// 配置对象格式插件
|
|
398
|
+
await AIPlugin.action(args, {});
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
} catch (error) {
|
|
402
|
+
// AI 调用失败时不影响主流程
|
|
403
|
+
console.log('AI 解释失败:', error.message);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
console.log("");
|
|
407
|
+
process.exit(1);
|
|
408
|
+
}
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* 收集所有命令信息
|
|
414
|
+
* @param {Object} program - Commander 实例
|
|
415
|
+
* @returns {Array} 命令数组
|
|
416
|
+
*/
|
|
417
|
+
collectAllCommands(program) {
|
|
418
|
+
const commands = [];
|
|
419
|
+
|
|
420
|
+
// 收集核心命令
|
|
421
|
+
if (program.commands) {
|
|
422
|
+
program.commands.forEach((command) => {
|
|
423
|
+
// 直接使用 _name 获取命令名称
|
|
424
|
+
const commandName = command._name;
|
|
425
|
+
|
|
426
|
+
// 添加命令名称
|
|
427
|
+
if (commandName && commandName !== "*") {
|
|
428
|
+
commands.push(commandName);
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
return commands;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* 获取命令建议
|
|
438
|
+
* @param {string} input - 用户输入
|
|
439
|
+
* @param {Array} commands - 命令数组
|
|
440
|
+
* @returns {Array} 建议的命令数组
|
|
441
|
+
*/
|
|
442
|
+
getCommandSuggestions(input, commands) {
|
|
443
|
+
return commands
|
|
444
|
+
.filter((command) => {
|
|
445
|
+
// 确保 command 是字符串类型
|
|
446
|
+
if (typeof command !== 'string') {
|
|
447
|
+
return false;
|
|
448
|
+
}
|
|
449
|
+
return command.toLowerCase().startsWith(input.toLowerCase());
|
|
450
|
+
})
|
|
451
|
+
.slice(0, 5); // 最多返回5个建议
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* 注册全局钩子
|
|
456
|
+
* @param {string} event - 事件名称
|
|
457
|
+
* @param {Function} callback - 回调函数
|
|
458
|
+
*/
|
|
459
|
+
registerHook(event, callback) {
|
|
460
|
+
if (!this.hooks[event]) {
|
|
461
|
+
this.hooks[event] = [];
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
this.hooks[event].push(callback);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* 触发全局钩子
|
|
469
|
+
* @param {string} event - 事件名称
|
|
470
|
+
* @param {*} data - 事件数据
|
|
471
|
+
* @returns {Promise<Array>} 钩子执行结果
|
|
472
|
+
*/
|
|
473
|
+
async triggerHook(event, data) {
|
|
474
|
+
const results = [];
|
|
475
|
+
|
|
476
|
+
// 触发全局钩子
|
|
477
|
+
if (this.hooks[event]) {
|
|
478
|
+
for (const callback of this.hooks[event]) {
|
|
479
|
+
try {
|
|
480
|
+
const result = await callback(data);
|
|
481
|
+
results.push(result);
|
|
482
|
+
} catch (error) {
|
|
483
|
+
console.error(`执行全局钩子 ${event} 时出错:`, error.message);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// 触发所有插件的钩子
|
|
489
|
+
if (this.pluginFiles) {
|
|
490
|
+
for (const pluginFile of this.pluginFiles) {
|
|
491
|
+
const pluginName = pluginFile.replace(".js", "");
|
|
492
|
+
|
|
493
|
+
// 检查插件是否已禁用
|
|
494
|
+
if (pluginConfig.isPluginDisabled(pluginName)) {
|
|
495
|
+
continue;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
const plugin = this.loadPlugin(pluginFile);
|
|
499
|
+
if (plugin && plugin.triggerHook) {
|
|
500
|
+
try {
|
|
501
|
+
const pluginResults = await plugin.triggerHook(event, data);
|
|
502
|
+
results.push(...pluginResults);
|
|
503
|
+
} catch (error) {
|
|
504
|
+
console.error(
|
|
505
|
+
`执行插件 ${pluginName} 的钩子 ${event} 时出错:`,
|
|
506
|
+
error.message,
|
|
507
|
+
);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
return results;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* 检查是否注册了指定全局钩子
|
|
518
|
+
* @param {string} event - 事件名称
|
|
519
|
+
* @returns {boolean} 是否注册了钩子
|
|
520
|
+
*/
|
|
521
|
+
hasHook(event) {
|
|
522
|
+
return this.hooks[event] && this.hooks[event].length > 0;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* 注册核心命令
|
|
527
|
+
* @param {Object} program - Commander 实例
|
|
528
|
+
*/
|
|
529
|
+
registerCoreCommands(program) {
|
|
530
|
+
// 帮助命令
|
|
531
|
+
program
|
|
532
|
+
.command("help")
|
|
533
|
+
.description("显示帮助信息")
|
|
534
|
+
.action(() => {
|
|
535
|
+
program.outputHelp();
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
// 版本命令
|
|
539
|
+
program
|
|
540
|
+
.command("version")
|
|
541
|
+
.alias("v")
|
|
542
|
+
.description("显示版本信息")
|
|
543
|
+
.action(() => {
|
|
544
|
+
console.log(this.version);
|
|
545
|
+
});
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
// 导出单例实例
|
|
550
|
+
module.exports = new Core();
|