@xubill/xx-cli 1.0.3 → 1.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/lib/core/index.js CHANGED
@@ -3,13 +3,11 @@
3
3
  * 负责初始化系统、注册命令、管理插件等
4
4
  */
5
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 validator = require('../utils/validator');
11
- const pluginConfig = require('../utils/plugin-config');
12
- const coreCommands = require('./commands');
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");
13
11
 
14
12
  class Core {
15
13
  constructor() {
@@ -27,10 +25,10 @@ class Core {
27
25
  async init() {
28
26
  //logger.info('正在初始化 xx 核心...');
29
27
  this.loadPlugins();
30
-
28
+
31
29
  // 触发初始化完成钩子
32
- await this.triggerHook('init', { core: this });
33
-
30
+ await this.triggerHook("init", { core: this });
31
+
34
32
  //logger.info('xx 核心初始化完成');
35
33
  }
36
34
 
@@ -38,12 +36,37 @@ class Core {
38
36
  * 加载插件
39
37
  */
40
38
  loadPlugins() {
41
- const pluginsDir = path.join(__dirname, '../plugins');
42
- if (fs.existsSync(pluginsDir)) {
43
- const pluginFiles = fs.readdirSync(pluginsDir);
44
- // 只收集插件文件信息,不立即加载
45
- this.pluginFiles = pluginFiles.filter(file => file.endsWith('.js'));
39
+ // 内置插件目录(会被重新安装覆盖)
40
+ const builtinPluginsDir = path.join(__dirname, "../plugins");
41
+ // 用户插件目录(不会被重新安装影响)
42
+ const userPluginsDir = path.join(
43
+ process.env.HOME || process.env.USERPROFILE,
44
+ ".xx-cli",
45
+ "plugins"
46
+ );
47
+
48
+ // 确保用户插件目录存在
49
+ if (!fs.existsSync(userPluginsDir)) {
50
+ fs.mkdirSync(userPluginsDir, { recursive: true });
51
+ }
52
+
53
+ // 收集内置插件
54
+ let pluginFiles = [];
55
+ if (fs.existsSync(builtinPluginsDir)) {
56
+ const builtinFiles = fs.readdirSync(builtinPluginsDir);
57
+ pluginFiles = builtinFiles.filter((file) => file.endsWith(".js"));
58
+ }
59
+
60
+ // 收集用户插件
61
+ if (fs.existsSync(userPluginsDir)) {
62
+ const userFiles = fs.readdirSync(userPluginsDir);
63
+ const userPluginFiles = userFiles.filter((file) => file.endsWith(".js"));
64
+ // 将用户插件添加到插件文件列表中
65
+ pluginFiles = [...pluginFiles, ...userPluginFiles];
46
66
  }
67
+
68
+ // 只收集插件文件信息,不立即加载
69
+ this.pluginFiles = pluginFiles;
47
70
  }
48
71
  /**
49
72
  * 加载单个插件
@@ -55,23 +78,73 @@ class Core {
55
78
  if (this.pluginCache.has(pluginFile)) {
56
79
  return this.pluginCache.get(pluginFile);
57
80
  }
58
-
59
- const pluginPath = path.join(__dirname, '../plugins', pluginFile);
81
+
82
+ // 内置插件目录
83
+ const builtinPluginsDir = path.join(__dirname, "../plugins");
84
+ // 用户插件目录
85
+ const userPluginsDir = path.join(
86
+ process.env.HOME || process.env.USERPROFILE,
87
+ ".xx-cli",
88
+ "plugins"
89
+ );
90
+
91
+ // 优先从内置插件目录加载
92
+ let pluginPath = path.join(builtinPluginsDir, pluginFile);
93
+
94
+ // 如果内置插件目录中不存在,则从用户插件目录加载
95
+ if (!fs.existsSync(pluginPath)) {
96
+ pluginPath = path.join(userPluginsDir, pluginFile);
97
+ }
98
+
99
+ // 如果两个目录中都不存在,则返回null
100
+ if (!fs.existsSync(pluginPath)) {
101
+ logger.error(`插件文件 ${pluginFile} 不存在`);
102
+ return null;
103
+ }
104
+
60
105
  try {
61
- const Plugin = require(pluginPath);
62
-
106
+ // 读取插件文件内容
107
+ let pluginContent = fs.readFileSync(pluginPath, "utf8");
108
+
109
+ // 替换插件文件中的相对路径导入为绝对路径导入
110
+ // 替换 ../core 为绝对路径
111
+ const coreDir = path.join(__dirname, "../core");
112
+ pluginContent = pluginContent.replace(
113
+ /require\('\.\.\/core\//g,
114
+ `require('${coreDir}/`
115
+ );
116
+
117
+ // 替换 ../utils 为绝对路径
118
+ const utilsDir = path.join(__dirname, "../utils");
119
+ pluginContent = pluginContent.replace(
120
+ /require\('\.\.\/utils\//g,
121
+ `require('${utilsDir}/`
122
+ );
123
+
124
+ // 创建一个临时模块来加载修改后的插件内容
125
+ const Module = require("module");
126
+ const tempModule = new Module(pluginPath);
127
+ tempModule.filename = pluginPath;
128
+ tempModule.paths = module.paths;
129
+
130
+ // 编译并执行修改后的插件内容
131
+ tempModule._compile(pluginContent, pluginPath);
132
+
133
+ const Plugin = tempModule.exports;
134
+
63
135
  // 检查是否为类
64
- if (typeof Plugin === 'function' && Plugin.prototype) {
136
+ if (typeof Plugin === "function" && Plugin.prototype) {
65
137
  // 实例化类插件
66
138
  const pluginInstance = new Plugin();
67
- pluginInstance.pluginName = pluginInstance.pluginName || pluginFile.replace('.js', '');
68
-
139
+ pluginInstance.pluginName =
140
+ pluginInstance.pluginName || pluginFile.replace(".js", "");
141
+
69
142
  // 缓存插件实例
70
143
  this.pluginCache.set(pluginFile, pluginInstance);
71
144
  return pluginInstance;
72
145
  } else {
73
146
  // 保持非类插件的兼容性
74
-
147
+
75
148
  // 缓存插件
76
149
  this.pluginCache.set(pluginFile, Plugin);
77
150
  return Plugin;
@@ -86,11 +159,11 @@ class Core {
86
159
  * @returns {Array} 插件信息数组
87
160
  */
88
161
  getPluginsInfo() {
89
- return this.pluginFiles.map(pluginFile => {
90
- const pluginName = pluginFile.replace('.js', '');
162
+ return this.pluginFiles.map((pluginFile) => {
163
+ const pluginName = pluginFile.replace(".js", "");
91
164
  return {
92
165
  name: pluginName,
93
- file: pluginFile
166
+ file: pluginFile,
94
167
  };
95
168
  });
96
169
  }
@@ -102,24 +175,33 @@ class Core {
102
175
  registerCommands(program) {
103
176
  // 注册核心命令
104
177
  this.registerCoreCommands(program);
105
-
178
+
106
179
  // 注册插件命令
107
180
  if (this.pluginFiles) {
108
- this.pluginFiles.forEach(pluginFile => {
109
- const pluginName = pluginFile.replace('.js', '');
110
-
181
+ this.pluginFiles.forEach((pluginFile) => {
182
+ const pluginName = pluginFile.replace(".js", "");
183
+
111
184
  // 检查插件是否已禁用
112
185
  if (pluginConfig.isPluginDisabled(pluginName)) {
113
186
  return;
114
187
  }
115
-
188
+
116
189
  const plugin = this.loadPlugin(pluginFile);
117
190
  if (plugin && plugin.registerCommands) {
118
- plugin.registerCommands(program);
191
+ try {
192
+ plugin.registerCommands(program);
193
+ } catch (error) {
194
+ // 捕获命令别名冲突等错误,确保其他插件能够正常注册
195
+ if (error.message && error.message.includes('cannot add alias')) {
196
+ console.warn(`警告: 插件 ${pluginName} 的命令别名与其他插件冲突,已跳过此插件的命令注册`);
197
+ } else {
198
+ console.error(`错误: 插件 ${pluginName} 注册命令失败: ${error.message}`);
199
+ }
200
+ }
119
201
  }
120
202
  });
121
203
  }
122
-
204
+
123
205
  // 注册命令自动建议功能
124
206
  this.registerCommandSuggestions(program);
125
207
  }
@@ -131,18 +213,18 @@ class Core {
131
213
  registerCommandSuggestions(program) {
132
214
  // 收集所有命令信息
133
215
  const allCommands = this.collectAllCommands(program);
134
-
216
+
135
217
  // 添加命令自动建议
136
- program.on('command:*', (args) => {
218
+ program.on("command:*", (args) => {
137
219
  const inputCommand = args[0];
138
220
  const suggestions = this.getCommandSuggestions(inputCommand, allCommands);
139
-
221
+
140
222
  if (suggestions.length > 0) {
141
223
  console.log(`\n未找到命令 "${inputCommand}",您可能想要:`);
142
- suggestions.forEach(suggestion => {
224
+ suggestions.forEach((suggestion) => {
143
225
  console.log(` - ${suggestion}`);
144
226
  });
145
- console.log('');
227
+ console.log("");
146
228
  process.exit(1);
147
229
  }
148
230
  });
@@ -155,22 +237,22 @@ class Core {
155
237
  */
156
238
  collectAllCommands(program) {
157
239
  const commands = [];
158
-
240
+
159
241
  // 收集核心命令
160
242
  if (program.commands) {
161
- program.commands.forEach(command => {
243
+ program.commands.forEach((command) => {
162
244
  // 添加命令名称
163
- if (command._name && command._name !== '*') {
245
+ if (command._name && command._name !== "*") {
164
246
  commands.push(command._name);
165
247
  }
166
-
248
+
167
249
  // 添加命令别名
168
250
  if (command._alias) {
169
251
  commands.push(command._alias);
170
252
  }
171
253
  });
172
254
  }
173
-
255
+
174
256
  return commands;
175
257
  }
176
258
 
@@ -181,9 +263,11 @@ class Core {
181
263
  * @returns {Array} 建议的命令数组
182
264
  */
183
265
  getCommandSuggestions(input, commands) {
184
- return commands.filter(command => {
185
- return command.startsWith(input.toLowerCase());
186
- }).slice(0, 5); // 最多返回5个建议
266
+ return commands
267
+ .filter((command) => {
268
+ return command.startsWith(input.toLowerCase());
269
+ })
270
+ .slice(0, 5); // 最多返回5个建议
187
271
  }
188
272
 
189
273
  /**
@@ -195,7 +279,7 @@ class Core {
195
279
  if (!this.hooks[event]) {
196
280
  this.hooks[event] = [];
197
281
  }
198
-
282
+
199
283
  this.hooks[event].push(callback);
200
284
  }
201
285
 
@@ -207,7 +291,7 @@ class Core {
207
291
  */
208
292
  async triggerHook(event, data) {
209
293
  const results = [];
210
-
294
+
211
295
  // 触发全局钩子
212
296
  if (this.hooks[event]) {
213
297
  for (const callback of this.hooks[event]) {
@@ -219,29 +303,32 @@ class Core {
219
303
  }
220
304
  }
221
305
  }
222
-
306
+
223
307
  // 触发所有插件的钩子
224
308
  if (this.pluginFiles) {
225
309
  for (const pluginFile of this.pluginFiles) {
226
- const pluginName = pluginFile.replace('.js', '');
227
-
310
+ const pluginName = pluginFile.replace(".js", "");
311
+
228
312
  // 检查插件是否已禁用
229
313
  if (pluginConfig.isPluginDisabled(pluginName)) {
230
314
  continue;
231
315
  }
232
-
316
+
233
317
  const plugin = this.loadPlugin(pluginFile);
234
318
  if (plugin && plugin.triggerHook) {
235
319
  try {
236
320
  const pluginResults = await plugin.triggerHook(event, data);
237
321
  results.push(...pluginResults);
238
322
  } catch (error) {
239
- console.error(`执行插件 ${pluginName} 的钩子 ${event} 时出错:`, error.message);
323
+ console.error(
324
+ `执行插件 ${pluginName} 的钩子 ${event} 时出错:`,
325
+ error.message
326
+ );
240
327
  }
241
328
  }
242
329
  }
243
330
  }
244
-
331
+
245
332
  return results;
246
333
  }
247
334
 
@@ -254,54 +341,6 @@ class Core {
254
341
  return this.hooks[event] && this.hooks[event].length > 0;
255
342
  }
256
343
 
257
- /**
258
- * 显示命令历史记录
259
- * @param {Object} options - 选项
260
- */
261
- showHistory(options) {
262
- const historyManager = require('../utils/history-manager');
263
-
264
- if (options.clear) {
265
- // 清除命令历史记录
266
- historyManager.clearHistory();
267
- console.log('命令历史记录已清除');
268
- return;
269
- }
270
-
271
- if (options.search) {
272
- // 搜索命令历史记录
273
- const searchResults = historyManager.searchHistory(options.search);
274
- if (searchResults.length > 0) {
275
- console.log('\n搜索结果:');
276
- console.log('=====================================');
277
- searchResults.forEach((item, index) => {
278
- const date = new Date(item.timestamp).toLocaleString();
279
- console.log(`${index + 1}. ${item.command} (${date})`);
280
- });
281
- console.log('=====================================');
282
- console.log(`总计: ${searchResults.length} 条记录\n`);
283
- } else {
284
- console.log(`\n未找到匹配 "${options.search}" 的命令历史记录\n`);
285
- }
286
- return;
287
- }
288
-
289
- // 显示命令历史记录
290
- const history = historyManager.getHistory(options.limit);
291
- if (history.length > 0) {
292
- console.log('\n命令历史记录:');
293
- console.log('=====================================');
294
- history.forEach((item, index) => {
295
- const date = new Date(item.timestamp).toLocaleString();
296
- console.log(`${index + 1}. ${item.command} (${date})`);
297
- });
298
- console.log('=====================================');
299
- console.log(`总计: ${history.length} 条记录\n`);
300
- } else {
301
- console.log('\n命令历史记录为空\n');
302
- }
303
- }
304
-
305
344
  /**
306
345
  * 注册核心命令
307
346
  * @param {Object} program - Commander 实例
@@ -309,163 +348,20 @@ class Core {
309
348
  registerCoreCommands(program) {
310
349
  // 帮助命令
311
350
  program
312
- .command('help')
313
- .description('显示帮助信息')
351
+ .command("help")
352
+ .description("显示帮助信息")
314
353
  .action(() => {
315
354
  program.outputHelp();
316
355
  });
317
356
 
318
- // 版本命令
357
+ // 版本命令
319
358
  program
320
- .command('version')
321
- .alias('v')
322
- .description('显示版本信息')
359
+ .command("version")
360
+ .alias("v")
361
+ .description("显示版本信息")
323
362
  .action(() => {
324
363
  console.log(this.version);
325
364
  });
326
-
327
- // 命令历史记录
328
- program
329
- .command('history')
330
- .alias('h')
331
- .description('查看命令历史记录')
332
- .option('-l, --limit <number>', '限制显示的历史记录数量', parseInt, 10)
333
- .option('-c, --clear', '清除命令历史记录')
334
- .option('-s, --search <keyword>', '搜索命令历史记录')
335
- .action((options) => this.showHistory(options));
336
-
337
- // 创建插件命令
338
- program
339
- .command('create-plugin <name>')
340
- .alias('crp')
341
- .description('创建指定名称的插件模板')
342
- .action(async (name, options) => this.createPlugin(name, options));
343
-
344
- // 配置管理命令
345
- const configCommand = program.command('config-manager')
346
- .alias('conf')
347
- .description('管理所有插件的配置文件');
348
-
349
- // 导出配置命令
350
- configCommand.command('export [target]')
351
- .description('导出所有插件配置到指定目录,默认导出到当前目录的 config-backup 文件夹')
352
- .action((target) => this.configManager('export', target));
353
-
354
- // 导入配置命令
355
- configCommand.command('import [source]')
356
- .description('从指定目录导入配置并覆盖,默认从当前目录的 config-backup 文件夹导入')
357
- .action((source) => this.configManager('import', source));
358
-
359
- // 列出配置命令
360
- configCommand.command('list')
361
- .description('列出所有插件的配置文件位置和状态')
362
- .action(() => this.configManager('list'));
363
-
364
- // 插件管理命令
365
- const pluginCommand = program.command('plugin')
366
- .alias('p')
367
- .description('插件管理');
368
-
369
- // 列出插件
370
- pluginCommand.command('list')
371
- .alias('ls')
372
- .description('列出所有插件')
373
- .action(() => this.listPlugins());
374
-
375
- // 启用插件
376
- pluginCommand.command('enable <plugin>')
377
- .alias('en')
378
- .description('启用插件')
379
- .action((plugin) => this.enablePlugin(plugin));
380
-
381
- // 禁用插件
382
- pluginCommand.command('disable <plugin>')
383
- .alias('dis')
384
- .description('禁用插件')
385
- .action((plugin) => this.disablePlugin(plugin));
386
-
387
- // 添加外部自定义插件
388
- pluginCommand.command('add <url>')
389
- .description('添加外部自定义插件')
390
- .action((url) => this.addExternalPlugin(url));
391
-
392
- pluginCommand.command('remove <plugin>')
393
- .alias('rm')
394
- .description('删除指定插件')
395
- .action((plugin) => this.removePlugin(plugin));
396
-
397
- // 插件配置管理
398
- pluginCommand.command('config <plugin> [key] [value]')
399
- .alias('c')
400
- .description('查看和设置插件配置')
401
- .action((plugin, key, value) => this.managePluginConfig(plugin, key, value));
402
- }
403
-
404
- /**
405
- * 创建插件
406
- * @param {string} name - 插件名称
407
- * @param {Object} options - 选项
408
- */
409
- async createPlugin(name, options) {
410
- await coreCommands.createPlugin(name, options);
411
- }
412
-
413
- /**
414
- * 配置管理
415
- * @param {string} action - 操作类型
416
- * @param {string} target - 目标路径
417
- */
418
- configManager(action, target) {
419
- coreCommands.configManager(action, target);
420
- }
421
-
422
- /**
423
- * 列出所有插件
424
- */
425
- listPlugins() {
426
- coreCommands.listPlugins(this);
427
- }
428
-
429
- /**
430
- * 启用插件
431
- * @param {string} pluginName - 插件名称
432
- */
433
- enablePlugin(pluginName) {
434
- coreCommands.enablePlugin(pluginName);
435
- }
436
-
437
- /**
438
- * 禁用插件
439
- * @param {string} pluginName - 插件名称
440
- */
441
- disablePlugin(pluginName) {
442
- coreCommands.disablePlugin(pluginName);
443
- }
444
-
445
- /**
446
- * 删除插件
447
- * @param {string} pluginName - 插件名称
448
- */
449
- removePlugin(pluginName) {
450
- coreCommands.removePlugin(pluginName);
451
- }
452
-
453
- /**
454
- * 管理插件配置
455
- * @param {string} pluginName - 插件名称
456
- * @param {string} key - 配置键
457
- * @param {string} value - 配置值
458
- */
459
- managePluginConfig(pluginName, key, value) {
460
- coreCommands.managePluginConfig(pluginName, key, value);
461
- }
462
-
463
- /**
464
- * 添加外部自定义插件
465
- * @param {string} url - 插件URL或本地文件路径
466
- */
467
- async addExternalPlugin(url) {
468
- await coreCommands.addExternalPlugin(url);
469
365
  }
470
366
  }
471
367
 
@@ -0,0 +1,140 @@
1
+ /**
2
+ * 配置管理插件
3
+ * 用于管理所有插件的配置文件
4
+ *
5
+ * 命令说明:
6
+ * - config-manager [options]:管理所有插件的配置文件
7
+ * - 示例:config-manager export
8
+ * - 示例:config-manager import
9
+ * - 示例:config-manager list
10
+ *
11
+ * 功能说明:
12
+ * - 导出所有插件配置到指定目录
13
+ * - 从指定目录导入配置并覆盖
14
+ * - 列出所有插件的配置文件位置和状态
15
+ *
16
+ * 用户体验:
17
+ * - 使用标准化的用户提示
18
+ * - 提供清晰的错误提示
19
+ * - 支持命令行参数
20
+ */
21
+
22
+ const fs = require('fs-extra');
23
+ const path = require('path');
24
+ const BasePlugin = require('../core/base-plugin');
25
+
26
+ class ConfigManagerPlugin extends BasePlugin {
27
+ constructor(options = {}) {
28
+ super(options);
29
+ this.pluginName = 'config-manager';
30
+ }
31
+
32
+ /**
33
+ * 注册命令
34
+ * @param {Object} program - Commander.js 实例
35
+ */
36
+ registerCommands(program) {
37
+ // 配置管理命令
38
+ const configCommand = program.command('config-manager')
39
+ .alias('conf')
40
+ .description('管理所有插件的配置文件');
41
+
42
+ // 导出配置命令
43
+ configCommand.command('export [target]')
44
+ .description('导出所有插件配置到指定目录,默认导出到当前目录的 config-backup 文件夹')
45
+ .action((target) => this.exportConfig(target));
46
+
47
+ // 导入配置命令
48
+ configCommand.command('import [source]')
49
+ .description('从指定目录导入配置并覆盖,默认从当前目录的 config-backup 文件夹导入')
50
+ .action((source) => this.importConfig(source));
51
+
52
+ // 列出配置命令
53
+ configCommand.command('list')
54
+ .description('列出所有插件的配置文件位置和状态')
55
+ .action(() => this.listConfig());
56
+ }
57
+
58
+ /**
59
+ * 导出配置
60
+ * @param {string} target - 目标路径
61
+ */
62
+ exportConfig(target) {
63
+ const homeDir = process.env.HOME || process.env.USERPROFILE;
64
+ const xxDir = path.join(homeDir, '.xx-cli');
65
+ const exportDir = target || path.join(process.cwd(), 'config-backup');
66
+ console.log(`开始导出配置到: ${exportDir}`);
67
+
68
+ // 确保导出目录存在
69
+ fs.ensureDirSync(exportDir);
70
+
71
+ // 复制 .xx 目录
72
+ if (fs.existsSync(xxDir)) {
73
+ const exportPath = path.join(exportDir, '.xx-cli');
74
+ fs.ensureDirSync(path.dirname(exportPath));
75
+ fs.copySync(xxDir, exportPath);
76
+ console.log(`导出目录: ${xxDir}`);
77
+ }
78
+
79
+ console.log('配置导出完成!');
80
+ }
81
+
82
+ /**
83
+ * 导入配置
84
+ * @param {string} source - 源路径
85
+ */
86
+ importConfig(source) {
87
+ const homeDir = process.env.HOME || process.env.USERPROFILE;
88
+ const xxDir = path.join(homeDir, '.xx-cli');
89
+ const importDir = source || path.join(process.cwd(), 'config-backup');
90
+ console.log(`开始从 ${importDir} 导入配置...`);
91
+
92
+ // 检查导入目录是否存在
93
+ if (!fs.existsSync(importDir)) {
94
+ console.log(`导入目录不存在: ${importDir}`);
95
+ return;
96
+ }
97
+
98
+ // 复制配置到 .xx 目录
99
+ const importPath = path.join(importDir, '.xx-cli');
100
+ if (fs.existsSync(importPath)) {
101
+ fs.ensureDirSync(path.dirname(xxDir));
102
+ fs.copySync(importPath, xxDir, { overwrite: true });
103
+ console.log(`导入目录: ${importPath}`);
104
+ }
105
+
106
+ console.log('配置导入完成!');
107
+ }
108
+
109
+ /**
110
+ * 列出配置
111
+ */
112
+ listConfig() {
113
+ const homeDir = process.env.HOME || process.env.USERPROFILE;
114
+ const xxDir = path.join(homeDir, '.xx-cli');
115
+ console.log('列出所有插件配置文件...\n');
116
+
117
+ if (fs.existsSync(xxDir)) {
118
+ const items = fs.readdirSync(xxDir).filter(item => !item.startsWith('.') && item !== 'plugins');
119
+ items.forEach(item => {
120
+ const itemPath = path.join(xxDir, item);
121
+ const stat = fs.statSync(itemPath);
122
+ if (stat.isDirectory()) {
123
+ console.log(`插件配置目录: ${itemPath}`);
124
+ const configFiles = fs.readdirSync(itemPath).filter(file => !file.startsWith('.'));
125
+ configFiles.forEach(file => {
126
+ console.log(` - ${file}`);
127
+ });
128
+ } else if (stat.isFile()) {
129
+ console.log(`配置文件: ${itemPath}`);
130
+ }
131
+ });
132
+ } else {
133
+ console.log('配置目录不存在');
134
+ }
135
+
136
+ console.log('配置列表完成!');
137
+ }
138
+ }
139
+
140
+ module.exports = ConfigManagerPlugin;
@@ -0,0 +1,97 @@
1
+ /**
2
+ * 历史记录插件
3
+ * 用于查看命令历史记录
4
+ *
5
+ * 命令说明:
6
+ * - history [options]:查看命令历史记录
7
+ * - 示例:history
8
+ * - 示例:history --limit 20
9
+ * - 示例:history --clear
10
+ * - 示例:history --search <keyword>
11
+ *
12
+ * 功能说明:
13
+ * - 查看命令历史记录
14
+ * - 限制显示的历史记录数量
15
+ * - 清除命令历史记录
16
+ * - 搜索命令历史记录
17
+ *
18
+ * 用户体验:
19
+ * - 使用标准化的用户提示
20
+ * - 提供清晰的错误提示
21
+ * - 支持命令行参数
22
+ */
23
+
24
+ const BasePlugin = require('../core/base-plugin');
25
+
26
+ class HistoryPlugin extends BasePlugin {
27
+ constructor(options = {}) {
28
+ super(options);
29
+ this.pluginName = 'history';
30
+ }
31
+
32
+ /**
33
+ * 注册命令
34
+ * @param {Object} program - Commander.js 实例
35
+ */
36
+ registerCommands(program) {
37
+ // 命令历史记录
38
+ program
39
+ .command('history')
40
+ .alias('h')
41
+ .description('查看命令历史记录')
42
+ .option('-l, --limit <number>', '限制显示的历史记录数量', parseInt, 10)
43
+ .option('-c, --clear', '清除命令历史记录')
44
+ .option('-s, --search <keyword>', '搜索命令历史记录')
45
+ .action((options) => this.showHistory(options));
46
+ }
47
+
48
+ /**
49
+ * 显示命令历史记录
50
+ * @param {Object} options - 选项
51
+ */
52
+ showHistory(options) {
53
+ const historyManager = require('../utils/history-manager');
54
+
55
+ if (options.clear) {
56
+ // 清除命令历史记录
57
+ historyManager.clearHistory();
58
+ console.log('命令历史记录已清除');
59
+ return;
60
+ }
61
+
62
+ if (options.search) {
63
+ // 搜索命令历史记录
64
+ const searchResults = historyManager.searchHistory(options.search);
65
+ if (searchResults.length > 0) {
66
+ console.log('\n搜索结果:');
67
+ console.log('=====================================');
68
+ searchResults.forEach((item, index) => {
69
+ const date = new Date(item.timestamp).toLocaleString();
70
+ console.log(`${index + 1}. ${item.command} (${date})`);
71
+ });
72
+ console.log('=====================================');
73
+ console.log(`总计: ${searchResults.length} 条记录\n`);
74
+ } else {
75
+ console.log(`\n未找到匹配 "${options.search}" 的命令历史记录\n`);
76
+ }
77
+ return;
78
+ }
79
+
80
+ // 显示命令历史记录
81
+ const history = historyManager.getHistory(options.limit);
82
+ if (history.length > 0) {
83
+ console.log('\n命令历史记录:');
84
+ console.log('=====================================');
85
+ history.forEach((item, index) => {
86
+ const date = new Date(item.timestamp).toLocaleString();
87
+ console.log(`${index + 1}. ${item.command} (${date})`);
88
+ });
89
+ console.log('=====================================');
90
+ console.log(`总计: ${history.length} 条记录\n`);
91
+ } else {
92
+ console.log('\n命令历史记录为空\n');
93
+ }
94
+ }
95
+ }
96
+
97
+ module.exports = HistoryPlugin;
@@ -1,14 +1,194 @@
1
1
  /**
2
- * 核心命令实现
3
- * 存放具体的命令实现逻辑,保持 index.js 清晰
2
+ * 插件管理插件
3
+ * 用于管理所有插件
4
+ *
5
+ * 命令说明:
6
+ * - plugin [options]:管理所有插件
7
+ * - 示例:plugin list
8
+ * - 示例:plugin enable <plugin>
9
+ * - 示例:plugin disable <plugin>
10
+ * - 示例:plugin add <url>
11
+ * - 示例:plugin remove <plugin>
12
+ * - 示例:plugin create <name>
13
+ * - 示例:plugin config <plugin> [key] [value]
14
+ *
15
+ * 功能说明:
16
+ * - 列出所有插件
17
+ * - 启用指定插件
18
+ * - 禁用指定插件
19
+ * - 添加外部插件
20
+ * - 删除指定插件
21
+ * - 创建指定名称的插件模板
22
+ * - 查看和设置插件配置
23
+ *
24
+ * 用户体验:
25
+ * - 使用标准化的用户提示
26
+ * - 提供清晰的错误提示
27
+ * - 支持命令行参数
4
28
  */
5
29
 
6
30
  const fs = require('fs-extra');
7
31
  const path = require('path');
32
+ const https = require('https');
33
+ const http = require('http');
34
+ const BasePlugin = require('../core/base-plugin');
8
35
  const validator = require('../utils/validator');
9
36
  const pluginConfig = require('../utils/plugin-config');
10
37
 
11
- class CoreCommands {
38
+ class PluginManagerPlugin extends BasePlugin {
39
+ constructor(options = {}) {
40
+ super(options);
41
+ this.pluginName = 'plugin-manager';
42
+ }
43
+
44
+ /**
45
+ * 注册命令
46
+ * @param {Object} program - Commander.js 实例
47
+ */
48
+ registerCommands(program) {
49
+ // 插件管理命令
50
+ const pluginCommand = program.command('plugin')
51
+ .alias('p')
52
+ .description('插件管理');
53
+
54
+ // 列出插件
55
+ pluginCommand.command('list')
56
+ .alias('ls')
57
+ .description('列出所有插件')
58
+ .action(() => this.listPlugins());
59
+
60
+ // 启用插件
61
+ pluginCommand.command('enable <plugin>')
62
+ .alias('en')
63
+ .description('启用插件')
64
+ .action((plugin) => this.enablePlugin(plugin));
65
+
66
+ // 禁用插件
67
+ pluginCommand.command('disable <plugin>')
68
+ .alias('dis')
69
+ .description('禁用插件')
70
+ .action((plugin) => this.disablePlugin(plugin));
71
+
72
+ // 添加外部自定义插件
73
+ pluginCommand.command('add <url>')
74
+ .description('添加外部自定义插件')
75
+ .action((url) => this.addExternalPlugin(url));
76
+
77
+ // 删除插件
78
+ pluginCommand.command('remove <plugin>')
79
+ .alias('rm')
80
+ .description('删除指定插件')
81
+ .action((plugin) => this.removePlugin(plugin));
82
+
83
+ // 创建插件
84
+ pluginCommand.command('create <name>')
85
+ .alias('cr')
86
+ .description('创建指定名称的插件模板')
87
+ .action(async (name, options) => this.createPlugin(name, options));
88
+
89
+ // 插件配置管理
90
+ pluginCommand.command('config <plugin> [key] [value]')
91
+ .alias('c')
92
+ .description('查看和设置插件配置')
93
+ .action((plugin, key, value) => this.managePluginConfig(plugin, key, value));
94
+ }
95
+
96
+ /**
97
+ * 列出所有插件
98
+ */
99
+ listPlugins() {
100
+ const core = require('../core');
101
+ const pluginsInfo = core.getPluginsInfo();
102
+ console.log('\n可用插件列表:');
103
+ console.log('=====================================');
104
+ pluginsInfo.forEach(plugin => {
105
+ const isDisabled = pluginConfig.isPluginDisabled(plugin.name);
106
+ const status = isDisabled ? '[已禁用]' : '[已启用]';
107
+ console.log(`- ${plugin.name} ${status}`);
108
+ });
109
+ console.log('=====================================');
110
+ console.log(`总计: ${pluginsInfo.length} 个插件\n`);
111
+ }
112
+
113
+ /**
114
+ * 启用插件
115
+ * @param {string} pluginName - 插件名称
116
+ */
117
+ enablePlugin(pluginName) {
118
+ // 验证插件名称
119
+ if (!validator.validateCommandParam(pluginName)) {
120
+ console.error('错误: 插件名称包含无效字符');
121
+ return;
122
+ }
123
+
124
+ // 启用插件
125
+ pluginConfig.enablePlugin(pluginName);
126
+ console.log(`已启用插件: ${pluginName}`);
127
+ console.log('提示: 请重新运行命令以应用更改');
128
+ }
129
+
130
+ /**
131
+ * 禁用插件
132
+ * @param {string} pluginName - 插件名称
133
+ */
134
+ disablePlugin(pluginName) {
135
+ // 验证插件名称
136
+ if (!validator.validateCommandParam(pluginName)) {
137
+ console.error('错误: 插件名称包含无效字符');
138
+ return;
139
+ }
140
+
141
+ // 禁用插件
142
+ pluginConfig.disablePlugin(pluginName);
143
+ console.log(`已禁用插件: ${pluginName}`);
144
+ console.log('提示: 请重新运行命令以应用更改');
145
+ }
146
+
147
+ /**
148
+ * 删除插件
149
+ * @param {string} pluginName - 插件名称
150
+ */
151
+ removePlugin(pluginName) {
152
+ // 验证插件名称
153
+ if (!validator.validateCommandParam(pluginName)) {
154
+ console.error('错误: 插件名称包含无效字符');
155
+ return;
156
+ }
157
+
158
+ // 内置插件目录
159
+ const builtinPluginsDir = path.join(__dirname, '../plugins');
160
+ // 用户插件目录
161
+ const userPluginsDir = path.join(process.env.HOME || process.env.USERPROFILE, '.xx-cli', 'plugins');
162
+
163
+ // 构建插件文件路径
164
+ const pluginFileName = `${pluginName}.js`;
165
+ let pluginPath = path.join(builtinPluginsDir, pluginFileName);
166
+
167
+ // 如果内置插件目录中不存在,则从用户插件目录查找
168
+ if (!fs.existsSync(pluginPath)) {
169
+ pluginPath = path.join(userPluginsDir, pluginFileName);
170
+ }
171
+
172
+ // 检查插件文件是否存在
173
+ if (!fs.existsSync(pluginPath)) {
174
+ console.error(`错误: 插件文件不存在`);
175
+ return;
176
+ }
177
+
178
+ try {
179
+ // 删除插件文件
180
+ fs.unlinkSync(pluginPath);
181
+
182
+ // 从配置中移除插件的禁用状态
183
+ pluginConfig.removePluginFromConfig(pluginName);
184
+
185
+ console.log(`已成功删除插件: ${pluginName}`);
186
+ console.log('提示: 请重新运行命令以应用更改');
187
+ } catch (error) {
188
+ console.error(`删除插件失败: ${error.message}`);
189
+ }
190
+ }
191
+
12
192
  /**
13
193
  * 创建插件
14
194
  * @param {string} name - 插件名称
@@ -18,8 +198,8 @@ class CoreCommands {
18
198
  try {
19
199
  console.log('创建插件模板...');
20
200
 
21
- // 插件目录路径
22
- const pluginsDir = path.join(__dirname, '../plugins');
201
+ // 插件目录路径(用户插件目录,不会被重新安装影响)
202
+ const pluginsDir = path.join(process.env.HOME || process.env.USERPROFILE, '.xx-cli', 'plugins');
23
203
  const pluginFileName = `${name}.js`;
24
204
  const pluginPath = path.join(pluginsDir, pluginFileName);
25
205
 
@@ -39,6 +219,32 @@ class CoreCommands {
39
219
  console.log('提示:请编辑插件文件,实现具体功能');
40
220
  console.log('测试方法:运行 "node bin/cli.js <插件命令>"');
41
221
 
222
+ // 使用 vscode 打开创建的插件文件
223
+ try {
224
+ const { exec } = require('child_process');
225
+ const os = require('os');
226
+ let command;
227
+
228
+ // 根据操作系统类型构建不同的命令
229
+ if (os.platform() === 'win32') {
230
+ // Windows 系统
231
+ command = `start code "${pluginPath}"`;
232
+ } else {
233
+ // macOS 和 Linux 系统
234
+ command = `code "${pluginPath}"`;
235
+ }
236
+
237
+ exec(command, (error) => {
238
+ if (error) {
239
+ console.log('提示:无法自动打开 vscode,请手动打开插件文件进行编辑');
240
+ } else {
241
+ console.log('已自动打开 vscode 编辑插件文件');
242
+ }
243
+ });
244
+ } catch (error) {
245
+ console.log('提示:无法自动打开 vscode,请手动打开插件文件进行编辑');
246
+ }
247
+
42
248
  } catch (error) {
43
249
  console.error('创建插件模板失败:', error.message);
44
250
  }
@@ -120,170 +326,6 @@ module.exports = ${this.toCamelCase(name)}Plugin;
120
326
  return str.replace(/-([a-z])/g, (g) => g[1].toUpperCase()).replace(/^[a-z]/, (g) => g.toUpperCase());
121
327
  }
122
328
 
123
- /**
124
- * 配置管理
125
- * @param {string} action - 操作类型
126
- * @param {string} target - 目标路径
127
- */
128
- configManager(action, target) {
129
- const homeDir = process.env.HOME || process.env.USERPROFILE;
130
- const xxDir = path.join(homeDir, '.xx-cli');
131
-
132
- if (action === 'export') {
133
- // 导出配置
134
- const exportDir = target || path.join(process.cwd(), 'config-backup');
135
- console.log(`开始导出配置到: ${exportDir}`);
136
-
137
- // 确保导出目录存在
138
- fs.ensureDirSync(exportDir);
139
-
140
- // 复制 .xx 目录
141
- if (fs.existsSync(xxDir)) {
142
- const exportPath = path.join(exportDir, '.xx-cli');
143
- fs.ensureDirSync(path.dirname(exportPath));
144
- fs.copySync(xxDir, exportPath);
145
- console.log(`导出目录: ${xxDir}`);
146
- }
147
-
148
- console.log('配置导出完成!');
149
- } else if (action === 'import') {
150
- // 导入配置
151
- const importDir = target || path.join(process.cwd(), 'config-backup');
152
- console.log(`开始从 ${importDir} 导入配置...`);
153
-
154
- // 检查导入目录是否存在
155
- if (!fs.existsSync(importDir)) {
156
- console.log(`导入目录不存在: ${importDir}`);
157
- return;
158
- }
159
-
160
- // 复制配置到 .xx 目录
161
- const importPath = path.join(importDir, '.xx-cli');
162
- if (fs.existsSync(importPath)) {
163
- fs.ensureDirSync(path.dirname(xxDir));
164
- fs.copySync(importPath, xxDir, { overwrite: true });
165
- console.log(`导入目录: ${importPath}`);
166
- }
167
-
168
- console.log('配置导入完成!');
169
- } else if (action === 'list') {
170
- // 列出配置
171
- console.log('列出所有插件配置文件...\n');
172
-
173
- if (fs.existsSync(xxDir)) {
174
- const items = fs.readdirSync(xxDir).filter(item => !item.startsWith('.'));
175
- items.forEach(item => {
176
- const itemPath = path.join(xxDir, item);
177
- const stat = fs.statSync(itemPath);
178
- if (stat.isDirectory()) {
179
- console.log(`插件配置目录: ${itemPath}`);
180
- const configFiles = fs.readdirSync(itemPath).filter(file => !file.startsWith('.'));
181
- configFiles.forEach(file => {
182
- console.log(` - ${file}`);
183
- });
184
- } else if (stat.isFile()) {
185
- console.log(`配置文件: ${itemPath}`);
186
- }
187
- });
188
- } else {
189
- console.log('配置目录不存在');
190
- }
191
-
192
- console.log('配置列表完成!');
193
- }
194
- }
195
-
196
- /**
197
- * 列出所有插件
198
- */
199
- listPlugins(core) {
200
- const pluginsInfo = core.getPluginsInfo();
201
- console.log('\n可用插件列表:');
202
- console.log('=====================================');
203
- pluginsInfo.forEach(plugin => {
204
- const isDisabled = pluginConfig.isPluginDisabled(plugin.name);
205
- const status = isDisabled ? '[已禁用]' : '[已启用]';
206
- console.log(`- ${plugin.name} ${status}`);
207
- });
208
- console.log('=====================================');
209
- console.log(`总计: ${pluginsInfo.length} 个插件\n`);
210
- }
211
-
212
- /**
213
- * 启用插件
214
- * @param {string} pluginName - 插件名称
215
- */
216
- enablePlugin(pluginName) {
217
- // 验证插件名称
218
- if (!validator.validateCommandParam(pluginName)) {
219
- console.error('错误: 插件名称包含无效字符');
220
- return;
221
- }
222
-
223
- // 启用插件
224
- pluginConfig.enablePlugin(pluginName);
225
- console.log(`已启用插件: ${pluginName}`);
226
- console.log('提示: 请重新运行命令以应用更改');
227
- }
228
-
229
- /**
230
- * 禁用插件
231
- * @param {string} pluginName - 插件名称
232
- */
233
- disablePlugin(pluginName) {
234
- // 验证插件名称
235
- if (!validator.validateCommandParam(pluginName)) {
236
- console.error('错误: 插件名称包含无效字符');
237
- return;
238
- }
239
-
240
- // 禁用插件
241
- pluginConfig.disablePlugin(pluginName);
242
- console.log(`已禁用插件: ${pluginName}`);
243
- console.log('提示: 请重新运行命令以应用更改');
244
- }
245
-
246
- /**
247
- * 删除插件
248
- * @param {string} pluginName - 插件名称
249
- */
250
- removePlugin(pluginName) {
251
- // 验证插件名称
252
- if (!validator.validateCommandParam(pluginName)) {
253
- console.error('错误: 插件名称包含无效字符');
254
- return;
255
- }
256
-
257
- const fs = require('fs');
258
- const path = require('path');
259
-
260
- // 插件目录路径
261
- const pluginsDir = path.join(__dirname, '../plugins');
262
-
263
- // 构建插件文件路径
264
- const pluginFileName = `${pluginName}.js`;
265
- const pluginPath = path.join(pluginsDir, pluginFileName);
266
-
267
- // 检查插件文件是否存在
268
- if (!fs.existsSync(pluginPath)) {
269
- console.error(`错误: 插件文件不存在: ${pluginPath}`);
270
- return;
271
- }
272
-
273
- try {
274
- // 删除插件文件
275
- fs.unlinkSync(pluginPath);
276
-
277
- // 从配置中移除插件的禁用状态
278
- pluginConfig.removePluginFromConfig(pluginName);
279
-
280
- console.log(`已成功删除插件: ${pluginName}`);
281
- console.log('提示: 请重新运行命令以应用更改');
282
- } catch (error) {
283
- console.error(`删除插件失败: ${error.message}`);
284
- }
285
- }
286
-
287
329
  /**
288
330
  * 管理插件配置
289
331
  * @param {string} pluginName - 插件名称
@@ -347,20 +389,15 @@ module.exports = ${this.toCamelCase(name)}Plugin;
347
389
  */
348
390
  async addExternalPlugin(url) {
349
391
  try {
350
- const fs = require('fs');
351
- const path = require('path');
352
- const https = require('https');
353
- const http = require('http');
392
+ // 用户插件目录(不会被重新安装影响)
393
+ const userPluginsDir = path.join(process.env.HOME || process.env.USERPROFILE, '.xx-cli', 'plugins');
354
394
 
355
- // 插件目录路径
356
- const pluginsDir = path.join(__dirname, '../plugins');
357
-
358
- // 确保插件目录存在
359
- fs.ensureDirSync(pluginsDir);
395
+ // 确保用户插件目录存在
396
+ fs.ensureDirSync(userPluginsDir);
360
397
 
361
398
  // 提取插件名称
362
399
  const pluginFileName = path.basename(url);
363
- const pluginPath = path.join(pluginsDir, pluginFileName);
400
+ const pluginPath = path.join(userPluginsDir, pluginFileName);
364
401
 
365
402
  // 检查插件是否已存在
366
403
  if (fs.existsSync(pluginPath)) {
@@ -425,7 +462,7 @@ module.exports = ${this.toCamelCase(name)}Plugin;
425
462
 
426
463
  // 提取文件名
427
464
  const pluginFileName = path.basename(url);
428
- const pluginPath = path.join(pluginsDir, pluginFileName);
465
+ const pluginPath = path.join(userPluginsDir, pluginFileName);
429
466
 
430
467
  // 拷贝文件
431
468
  await fs.copy(url, pluginPath);
@@ -435,10 +472,17 @@ module.exports = ${this.toCamelCase(name)}Plugin;
435
472
  console.error('错误: 无效的插件URL或本地文件路径');
436
473
  return;
437
474
  }
475
+
476
+ // 提示用户
477
+ console.log('\n提示:');
478
+ console.log('- 插件已自动注册到命令系统');
479
+ console.log('- 可以使用 "xx plugin list" 命令查看已安装的插件');
480
+ console.log('- 可以使用 "xx <plugin-command>" 命令使用插件功能');
481
+ console.log('- 此插件保存在用户目录中,不会被重新安装影响');
438
482
  } catch (error) {
439
483
  console.error('添加插件失败:', error.message);
440
484
  }
441
485
  }
442
486
  }
443
487
 
444
- module.exports = new CoreCommands();
488
+ module.exports = PluginManagerPlugin;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xubill/xx-cli",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "个人工具集",
5
5
  "main": "lib/core/index.js",
6
6
  "bin": {
package/readme.md CHANGED
@@ -30,6 +30,10 @@ xx <command> [options]
30
30
  - 创建插件和配置管理插件移动壳功能
31
31
  - 完善文档
32
32
 
33
+ ### v1.0.4
34
+ - 修复原生插件和用户插件区别
35
+ - 壳功能移动到原生插件目录
36
+
33
37
  ## 框架自带命令
34
38
 
35
39
  xx-cli 框架自带以下核心命令(位于 core 模块中):
@@ -46,12 +50,12 @@ xx-cli 框架自带以下核心命令(位于 core 模块中):
46
50
 
47
51
  | 命令 | 别名 | 描述 |
48
52
  |------|------|------|
49
- | `create-plugin <name>` | `crp <name>` | 创建指定名称的插件模板 |
50
53
  | `plugin list` | `p ls` | 列出所有插件 |
51
54
  | `plugin enable <plugin>` | `p en <plugin>` | 启用插件 |
52
55
  | `plugin disable <plugin>` | `p dis <plugin>` | 禁用插件 |
53
56
  | `plugin add <url>` | `p add <url>` | 添加外部自定义插件 |
54
57
  | `plugin remove <plugin>` | `p rm <plugin>` | 删除指定插件 |
58
+ | `plugin create <name>` | `p cr <name>` | 创建指定名称的插件模板 |
55
59
  | `plugin config <plugin> [key] [value]` | `p c <plugin> [key] [value]` | 查看和设置插件配置 |
56
60
 
57
61
  ### 配置管理命令
@@ -62,37 +66,81 @@ xx-cli 框架自带以下核心命令(位于 core 模块中):
62
66
  | `config-manager import [source]` | `conf import [source]` | 从指定目录导入配置并覆盖 |
63
67
  | `config-manager list` | `conf list` | 列出所有插件的配置文件位置和状态 |
64
68
 
69
+ ## 项目结构
70
+
71
+ xx-cli 项目采用模块化设计,主要包含以下核心目录:
72
+
73
+ ### 核心模块目录 (`/Users/hthj/xx-cli/lib/core`)
74
+
75
+ 核心模块目录包含 xx-cli 的核心功能实现,负责初始化系统、注册命令、管理插件等。
76
+
77
+ #### 文件结构
78
+
79
+ ```
80
+ lib/core/
81
+ ├── index.js # 核心模块,负责初始化系统、注册命令、管理插件等
82
+ └── base-plugin.js # 插件基础类,提供标准化的插件接口和通用功能
83
+ ```
84
+
85
+ #### 核心文件说明
86
+
87
+ - **index.js**:核心模块,负责初始化系统、注册命令、管理插件等。它包含了插件加载、命令注册、钩子管理等核心功能。
88
+ - **base-plugin.js**:插件基础类,提供标准化的插件接口和通用功能。所有插件应该继承此类以确保一致性,它提供了命令注册、配置管理、用户界面等通用功能。
89
+
90
+ ### 插件目录 (`/Users/hthj/xx-cli/lib/plugins`)
91
+
92
+ 插件目录包含 xx-cli 的内置插件,这些插件提供了各种功能,如配置管理、历史记录管理、插件管理等。
93
+
94
+ #### 文件结构
95
+
96
+ ```
97
+ lib/plugins/
98
+ ├── config-manager.js # 配置管理插件,用于管理所有插件的配置文件
99
+ ├── history.js # 历史记录插件,用于查看命令历史记录
100
+ └── plugin-manager.js # 插件管理插件,用于管理所有插件
101
+ ```
102
+
103
+ #### 内置插件说明
104
+
105
+ - **config-manager.js**:配置管理插件,用于管理所有插件的配置文件。它提供了导出、导入、列出配置等功能。
106
+ - **history.js**:历史记录插件,用于查看命令历史记录。它提供了查看、清除、搜索历史记录等功能。
107
+ - **plugin-manager.js**:插件管理插件,用于管理所有插件。它提供了列出、启用、禁用、添加、删除、创建插件等功能。
108
+
65
109
  ## 插件开发
66
110
 
67
111
  本部分将详细介绍如何在 xx-cli 中创建、开发和部署插件。
68
112
 
69
113
  ### 创建插件
70
114
 
71
- #### 使用 create-plugin 命令
115
+ #### 使用 plugin create 命令
72
116
 
73
- xx-cli 提供了 `create-plugin` 命令,可以快速生成插件模板。这是推荐的创建插件的方式。
117
+ xx-cli 提供了 `plugin create` 命令,可以快速生成插件模板。这是推荐的创建插件的方式。
74
118
 
75
119
  ##### 基本用法
76
120
 
77
121
  ```bash
78
122
  # 创建插件到插件目录
79
- xx create-plugin <plugin-name>
123
+ xx plugin create <plugin-name>
80
124
 
81
125
  # 或者使用别名
82
- xx crp <plugin-name>
126
+ xx p create <plugin-name>
127
+
128
+ # 或者使用更短的别名
129
+ xx p cr <plugin-name>
83
130
  ```
84
131
 
85
132
  ##### 示例
86
133
 
87
134
  ```bash
88
135
  # 创建一个名为 `hello-world` 的插件
89
- xx create-plugin hello-world
136
+ xx plugin create hello-world
90
137
 
91
138
  # 输出:
92
139
  # 创建插件模板...
93
- # 插件模板已成功创建到:/Users/hthj/xx-cli/lib/plugins/hello-world.js
140
+ # 插件模板已成功创建到:/Users/hthj/.xx-cli/plugins/hello-world.js
94
141
  # 提示:请编辑插件文件,实现具体功能
95
142
  # 测试方法:运行 "node bin/cli.js <插件命令>"
143
+ # 已自动打开 vscode 编辑插件文件
96
144
  ```
97
145
 
98
146
  #### 手动创建插件
@@ -106,7 +154,7 @@ xx create-plugin hello-world
106
154
 
107
155
  #### 基本插件结构
108
156
 
109
- 使用 `create-plugin` 命令生成的插件模板包含以下结构:
157
+ 使用 `plugin create` 命令生成的插件模板包含以下结构:
110
158
 
111
159
  ```javascript
112
160
  /**
@@ -380,7 +428,7 @@ module.exports = MyPlugin;
380
428
 
381
429
  1. 创建插件:
382
430
  ```bash
383
- xx create-plugin <plugin-name>
431
+ xx plugin create <plugin-name>
384
432
  ```
385
433
 
386
434
  2. 编辑插件文件,实现具体功能