daodou-command 1.2.0 → 1.2.2

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.
@@ -0,0 +1,202 @@
1
+ # AI智能体快速参考卡片
2
+
3
+ > 为AI智能体提供项目快速理解和开发指导
4
+
5
+ ## 🎯 项目核心信息
6
+
7
+ - **项目名称**: daodou-command (刀豆命令行工具)
8
+ - **主命令**: `dao`
9
+ - **当前版本**: 1.2.1
10
+ - **主要功能**: 构建、多语言管理、自动更新
11
+
12
+ ## 📁 关键文件位置
13
+
14
+ ```
15
+ bin/daodou.js # 主程序入口,命令注册
16
+ lib/commands/ # 命令实现目录
17
+ ├── build.js # 构建命令
18
+ ├── lang.js # 多语言命令
19
+ └── upgrade.js # 更新命令
20
+ lib/utils/ # 工具模块
21
+ ├── update-checker.js # 后台更新检查
22
+ ├── git.js # Git操作
23
+ └── ... # 其他工具
24
+ ```
25
+
26
+ ## ⚡ 快速添加新命令
27
+
28
+ ### 1. 在 `bin/daodou.js` 中注册
29
+ ```javascript
30
+ program
31
+ .command('new-command')
32
+ .description('新命令描述')
33
+ .option('-o, --option <value>', '选项描述')
34
+ .action(async (options) => {
35
+ try {
36
+ const commandModule = require('../lib/commands/new-command');
37
+ await commandModule.execute(options);
38
+ } catch (error) {
39
+ console.error(chalk.red('执行失败:'), error.message);
40
+ process.exit(1);
41
+ }
42
+ });
43
+ ```
44
+
45
+ ### 2. 创建命令文件 `lib/commands/new-command.js`
46
+ ```javascript
47
+ const chalk = require('chalk');
48
+ const ora = require('ora');
49
+
50
+ async function execute(options) {
51
+ const spinner = ora('执行中...').start();
52
+ try {
53
+ // 业务逻辑
54
+ spinner.succeed('执行成功');
55
+ } catch (error) {
56
+ spinner.fail('执行失败');
57
+ throw error;
58
+ }
59
+ }
60
+
61
+ module.exports = { execute };
62
+ ```
63
+
64
+ ## 🔧 常用工具模块
65
+
66
+ ### 更新检查器
67
+ ```javascript
68
+ const updateChecker = require('../lib/utils/update-checker');
69
+ updateChecker.startBackgroundCheck(); // 启动后台检查
70
+ updateChecker.shouldRemindUpdate(); // 检查是否需要提醒
71
+ ```
72
+
73
+ ### Git工具
74
+ ```javascript
75
+ const git = require('../lib/utils/git');
76
+ const branch = await git.getCurrentBranch();
77
+ const hasChanges = await git.hasUncommittedChanges();
78
+ ```
79
+
80
+ ## 📝 代码规范要点
81
+
82
+ ### 必须遵循
83
+ - ✅ 使用 `async/await` 处理异步
84
+ - ✅ 使用 `chalk` 进行彩色输出
85
+ - ✅ 使用 `ora` 显示加载状态
86
+ - ✅ 统一的错误处理模式
87
+ - ✅ 详细的JSDoc注释
88
+
89
+ ### 避免的做法
90
+ - ❌ 同步阻塞操作
91
+ - ❌ 未处理的Promise
92
+ - ❌ 硬编码的配置
93
+ - ❌ 缺少错误处理
94
+
95
+ ## 🚨 错误处理模板
96
+
97
+ ```javascript
98
+ async function execute(options) {
99
+ try {
100
+ // 参数验证
101
+ if (!options.param) {
102
+ throw new Error('缺少必需参数');
103
+ }
104
+
105
+ // 业务逻辑
106
+ const result = await performAction(options);
107
+ console.log(chalk.green('成功:'), result);
108
+
109
+ } catch (error) {
110
+ console.error(chalk.red('错误:'), error.message);
111
+ throw error; // 重新抛出供上层处理
112
+ }
113
+ }
114
+ ```
115
+
116
+ ## ⚠️ 重要注意事项
117
+
118
+ ### 🚨 必须遵循的规则
119
+ - **新命令自动获得更新检查功能** - 无需手动实现
120
+ - **不要修改主程序中的更新检查逻辑**
121
+ - **不要重复实现更新检查功能**
122
+ - **避免在命令中直接调用 `process.exit()`**
123
+ - **不要阻塞主事件循环**
124
+ - **网络请求必须设置超时时间**
125
+
126
+ ### 🔄 命令执行流程
127
+ ```
128
+ 1. 启动后台更新检查(异步)
129
+ 2. 检查并显示更新提醒(如有新版本)
130
+ 3. 执行具体命令逻辑
131
+ 4. 返回执行结果
132
+ ```
133
+
134
+ ## 📋 命令开发检查清单
135
+
136
+ - [ ] 在 `bin/daodou.js` 中注册命令
137
+ - [ ] 创建 `lib/commands/命令名.js` 文件
138
+ - [ ] 实现 `execute(options)` 函数
139
+ - [ ] 添加参数验证
140
+ - [ ] 添加错误处理
141
+ - [ ] 使用彩色输出
142
+ - [ ] 添加加载状态
143
+ - [ ] 更新帮助信息
144
+ - [ ] 更新 README.md
145
+ - [ ] 更新 CHANGELOG.md
146
+ - [ ] 确保不干扰更新检查机制
147
+ - [ ] 设置网络请求超时
148
+ - [ ] 处理文件操作权限错误
149
+
150
+ ## 🔄 发布流程
151
+
152
+ 1. 更新版本号: `npm version patch/minor/major`
153
+ 2. 更新 CHANGELOG.md
154
+ 3. 提交代码: `git commit -m "描述"`
155
+ 4. 发布: `npm publish`
156
+
157
+ ## 🚫 禁止事项
158
+
159
+ ### ❌ 绝对不要做
160
+ - 修改 `bin/daodou.js` 中的更新检查逻辑
161
+ - 重复实现更新检查功能
162
+ - 直接调用 `process.exit()`
163
+ - 阻塞主事件循环
164
+ - 硬编码配置信息
165
+
166
+ ### ⚠️ 需要特别注意
167
+ - 网络请求必须设置超时(5-10秒)
168
+ - 文件操作要处理权限错误
169
+ - 大量数据要分块处理
170
+ - 避免内存泄漏
171
+ - 验证所有用户输入
172
+
173
+ ## 💡 开发提示
174
+
175
+ - 新命令会自动获得后台更新检查功能
176
+ - 使用 `--help` 查看命令帮助
177
+ - 错误信息要用户友好
178
+ - 长时间操作要显示进度
179
+ - 网络请求要设置超时
180
+
181
+ ## 🎨 输出样式
182
+
183
+ ```javascript
184
+ // 成功信息
185
+ console.log(chalk.green('✅ 操作成功'));
186
+
187
+ // 错误信息
188
+ console.error(chalk.red('❌ 操作失败'));
189
+
190
+ // 警告信息
191
+ console.log(chalk.yellow('⚠️ 警告信息'));
192
+
193
+ // 信息提示
194
+ console.log(chalk.blue('ℹ️ 提示信息'));
195
+ ```
196
+
197
+ ## 🔍 调试技巧
198
+
199
+ - 使用 `console.log` 输出调试信息
200
+ - 检查 `~/.daodou-update-state.json` 更新状态
201
+ - 使用 `node bin/daodou.js 命令名` 直接测试
202
+ - 检查网络连接和npm registry状态
@@ -0,0 +1,504 @@
1
+ # 刀豆命令行工具 - 命令开发规范
2
+
3
+ > 本文档为AI智能体提供详细的命令开发指南,确保新命令符合项目规范和最佳实践。
4
+
5
+ ## 📋 目录
6
+
7
+ - [项目架构](#项目架构)
8
+ - [命令开发规范](#命令开发规范)
9
+ - [文件结构规范](#文件结构规范)
10
+ - [代码规范](#代码规范)
11
+ - [错误处理规范](#错误处理规范)
12
+ - [测试规范](#测试规范)
13
+ - [发布规范](#发布规范)
14
+ - [常见问题](#常见问题)
15
+
16
+ ## 🏗️ 项目架构
17
+
18
+ ### 核心文件结构
19
+ ```
20
+ daodou-command/
21
+ ├── bin/
22
+ │ └── daodou.js # 主程序入口,命令注册中心
23
+ ├── lib/
24
+ │ ├── commands/ # 命令实现目录
25
+ │ │ ├── build.js # 构建命令
26
+ │ │ ├── lang.js # 多语言命令
27
+ │ │ └── upgrade.js # 更新命令
28
+ │ └── utils/ # 工具模块目录
29
+ │ ├── update-checker.js # 更新检查器
30
+ │ ├── git.js # Git工具
31
+ │ └── ... # 其他工具模块
32
+ ├── package.json # 项目配置
33
+ ├── CHANGELOG.md # 更新日志
34
+ └── README.md # 项目说明
35
+ ```
36
+
37
+ ### 命令注册流程
38
+ 1. 在 `bin/daodou.js` 中注册命令
39
+ 2. 在 `lib/commands/` 中实现命令逻辑
40
+ 3. 在 `lib/utils/` 中实现工具函数
41
+ 4. 更新帮助信息和文档
42
+
43
+ ## 📝 命令开发规范
44
+
45
+ ### 1. 命令注册规范
46
+
47
+ #### 基本命令注册
48
+ ```javascript
49
+ // 在 bin/daodou.js 中添加命令
50
+ program
51
+ .command('command-name')
52
+ .description('命令描述 - 简洁明了的功能说明')
53
+ .option('-o, --option <value>', '选项描述')
54
+ .action(async (options) => {
55
+ try {
56
+ const commandModule = require('../lib/commands/command-name');
57
+ await commandModule.execute(options);
58
+ } catch (error) {
59
+ console.error(chalk.red('命令执行失败:'), error.message);
60
+ process.exit(1);
61
+ }
62
+ });
63
+ ```
64
+
65
+ #### 子命令注册
66
+ ```javascript
67
+ // 子命令模式(如 lang 命令)
68
+ const subCmd = program
69
+ .command('parent-command')
70
+ .description('父命令描述');
71
+
72
+ subCmd
73
+ .command('sub-command <param>')
74
+ .description('子命令描述')
75
+ .option('-o, --option <value>', '选项描述')
76
+ .action(async (param, options) => {
77
+ try {
78
+ const commandModule = require('../lib/commands/parent-command');
79
+ await commandModule.subCommand(param, options);
80
+ } catch (error) {
81
+ console.error(chalk.red('子命令执行失败:'), error.message);
82
+ process.exit(1);
83
+ }
84
+ });
85
+ ```
86
+
87
+ ### 2. 命令实现规范
88
+
89
+ #### 命令模块结构
90
+ ```javascript
91
+ // lib/commands/example.js
92
+ const chalk = require('chalk');
93
+ const ora = require('ora');
94
+
95
+ /**
96
+ * 执行示例命令
97
+ * @param {Object} options - 命令选项
98
+ * @param {string} options.param - 参数值
99
+ * @param {boolean} options.flag - 标志选项
100
+ */
101
+ async function execute(options) {
102
+ const spinner = ora('执行中...').start();
103
+
104
+ try {
105
+ // 1. 参数验证
106
+ validateOptions(options);
107
+
108
+ // 2. 业务逻辑
109
+ const result = await performAction(options);
110
+
111
+ // 3. 结果输出
112
+ spinner.succeed('执行成功');
113
+ console.log(chalk.green('结果:'), result);
114
+
115
+ } catch (error) {
116
+ spinner.fail('执行失败');
117
+ throw error;
118
+ }
119
+ }
120
+
121
+ /**
122
+ * 验证命令选项
123
+ * @param {Object} options - 命令选项
124
+ */
125
+ function validateOptions(options) {
126
+ if (!options.param) {
127
+ throw new Error('缺少必需参数 --param');
128
+ }
129
+ }
130
+
131
+ /**
132
+ * 执行具体业务逻辑
133
+ * @param {Object} options - 命令选项
134
+ * @returns {Promise<any>} 执行结果
135
+ */
136
+ async function performAction(options) {
137
+ // 实现具体逻辑
138
+ return '执行结果';
139
+ }
140
+
141
+ module.exports = {
142
+ execute,
143
+ validateOptions,
144
+ performAction
145
+ };
146
+ ```
147
+
148
+ ### 3. 选项设计规范
149
+
150
+ #### 选项命名规范
151
+ - 短选项:单个字母,如 `-v`, `-h`
152
+ - 长选项:描述性名称,如 `--version`, `--help`
153
+ - 参数选项:使用尖括号,如 `--file <path>`
154
+ - 布尔选项:不使用参数,如 `--force`, `--verbose`
155
+
156
+ #### 常用选项模式
157
+ ```javascript
158
+ // 帮助选项(自动添加)
159
+ .option('-h, --help', '显示帮助信息')
160
+
161
+ // 版本选项(自动添加)
162
+ .option('-v, --version', '显示版本号')
163
+
164
+ // 文件路径选项
165
+ .option('-f, --file <path>', '指定文件路径')
166
+
167
+ // 布尔标志选项
168
+ .option('--force', '强制执行,跳过确认')
169
+
170
+ // 多值选项
171
+ .option('-e, --env <environment>', '指定环境', 'development')
172
+
173
+ // 必需参数
174
+ .argument('<required-param>', '必需参数描述')
175
+ ```
176
+
177
+ ## 📁 文件结构规范
178
+
179
+ ### 命令文件命名
180
+ - 文件名:使用小写字母和连字符,如 `build.js`, `upgrade.js`
181
+ - 目录名:使用小写字母和连字符,如 `commands/`, `utils/`
182
+
183
+ ### 工具模块命名
184
+ - 功能模块:`功能名.js`,如 `git.js`, `config.js`
185
+ - 工具模块:`工具名-manager.js`,如 `proxy-manager.js`
186
+
187
+ ### 文件组织原则
188
+ 1. **单一职责**:每个文件只负责一个功能
189
+ 2. **模块化**:相关功能组织在一起
190
+ 3. **可复用**:工具函数独立成模块
191
+ 4. **可测试**:每个函数都可以独立测试
192
+
193
+ ## 🚫 开发约束
194
+
195
+ ### 1. 系统级约束
196
+ - **禁止修改主程序更新检查逻辑** - 所有更新检查都在 `bin/daodou.js` 中统一处理
197
+ - **禁止重复实现更新检查** - 新命令自动获得更新检查功能
198
+ - **禁止直接调用 `process.exit()`** - 使用统一的错误处理机制
199
+ - **禁止阻塞主事件循环** - 所有长时间操作必须异步执行
200
+
201
+ ### 2. 性能约束
202
+ - **网络请求超时** - 必须设置合理的超时时间(建议5-10秒)
203
+ - **内存使用** - 避免大量数据同时加载到内存
204
+ - **文件操作** - 处理权限错误和磁盘空间不足
205
+ - **并发限制** - 避免同时发起过多网络请求
206
+
207
+ ### 3. 兼容性约束
208
+ - **Node.js版本** - 支持 Node.js >= 14.0.0
209
+ - **向后兼容** - 新版本不能破坏现有功能
210
+ - **跨平台** - 确保在 Windows、macOS、Linux 上都能正常运行
211
+ - **依赖管理** - 新增依赖需要评估影响
212
+
213
+ ### 4. 安全约束
214
+ - **输入验证** - 所有用户输入必须验证
215
+ - **文件路径** - 防止路径遍历攻击
216
+ - **网络请求** - 验证响应数据格式
217
+ - **权限检查** - 确保有足够权限执行操作
218
+
219
+ ## 💻 代码规范
220
+
221
+ ### 1. 代码风格
222
+ ```javascript
223
+ // ✅ 好的示例
224
+ const chalk = require('chalk');
225
+ const ora = require('ora');
226
+
227
+ /**
228
+ * 执行命令的主要函数
229
+ * @param {Object} options - 命令选项
230
+ * @returns {Promise<void>}
231
+ */
232
+ async function execute(options) {
233
+ try {
234
+ // 业务逻辑
235
+ const result = await performAction(options);
236
+ console.log(chalk.green('成功:'), result);
237
+ } catch (error) {
238
+ console.error(chalk.red('错误:'), error.message);
239
+ throw error;
240
+ }
241
+ }
242
+
243
+ // ❌ 避免的写法
244
+ function execute(options) {
245
+ // 缺少注释
246
+ // 没有错误处理
247
+ // 没有类型说明
248
+ }
249
+ ```
250
+
251
+ ### 2. 注释规范
252
+ ```javascript
253
+ /**
254
+ * 函数描述
255
+ * @param {类型} 参数名 - 参数描述
256
+ * @param {类型} [可选参数] - 可选参数描述
257
+ * @returns {类型} 返回值描述
258
+ * @throws {Error} 可能抛出的错误
259
+ * @example
260
+ * // 使用示例
261
+ * await functionName(options);
262
+ */
263
+ ```
264
+
265
+ ### 3. 错误处理规范
266
+ ```javascript
267
+ // ✅ 统一的错误处理
268
+ try {
269
+ await riskyOperation();
270
+ } catch (error) {
271
+ // 记录详细错误信息
272
+ console.error(chalk.red('操作失败:'), error.message);
273
+
274
+ // 提供解决建议
275
+ if (error.code === 'ENOENT') {
276
+ console.log(chalk.yellow('建议: 检查文件路径是否正确'));
277
+ }
278
+
279
+ // 重新抛出错误供上层处理
280
+ throw error;
281
+ }
282
+ ```
283
+
284
+ ### 4. 异步操作规范
285
+ ```javascript
286
+ // ✅ 使用 async/await
287
+ async function performAsyncOperation() {
288
+ try {
289
+ const result = await someAsyncFunction();
290
+ return result;
291
+ } catch (error) {
292
+ throw new Error(`异步操作失败: ${error.message}`);
293
+ }
294
+ }
295
+
296
+ // ✅ 并行操作
297
+ async function performParallelOperations() {
298
+ const [result1, result2] = await Promise.all([
299
+ operation1(),
300
+ operation2()
301
+ ]);
302
+ return { result1, result2 };
303
+ }
304
+ ```
305
+
306
+ ## 🚨 错误处理规范
307
+
308
+ ### 1. 错误类型分类
309
+ ```javascript
310
+ // 参数错误
311
+ class ValidationError extends Error {
312
+ constructor(message) {
313
+ super(message);
314
+ this.name = 'ValidationError';
315
+ }
316
+ }
317
+
318
+ // 网络错误
319
+ class NetworkError extends Error {
320
+ constructor(message) {
321
+ super(message);
322
+ this.name = 'NetworkError';
323
+ }
324
+ }
325
+
326
+ // 业务逻辑错误
327
+ class BusinessError extends Error {
328
+ constructor(message) {
329
+ super(message);
330
+ this.name = 'BusinessError';
331
+ }
332
+ }
333
+ ```
334
+
335
+ ### 2. 错误处理模式
336
+ ```javascript
337
+ async function execute(options) {
338
+ try {
339
+ // 参数验证
340
+ if (!options.param) {
341
+ throw new ValidationError('缺少必需参数');
342
+ }
343
+
344
+ // 业务逻辑
345
+ const result = await performAction(options);
346
+ return result;
347
+
348
+ } catch (error) {
349
+ // 根据错误类型处理
350
+ if (error instanceof ValidationError) {
351
+ console.error(chalk.red('参数错误:'), error.message);
352
+ console.log(chalk.yellow('使用 --help 查看正确用法'));
353
+ } else if (error instanceof NetworkError) {
354
+ console.error(chalk.red('网络错误:'), error.message);
355
+ console.log(chalk.yellow('请检查网络连接'));
356
+ } else {
357
+ console.error(chalk.red('未知错误:'), error.message);
358
+ }
359
+
360
+ throw error;
361
+ }
362
+ }
363
+ ```
364
+
365
+ ## 🧪 测试规范
366
+
367
+ ### 1. 测试文件结构
368
+ ```
369
+ tests/
370
+ ├── commands/
371
+ │ ├── build.test.js
372
+ │ ├── lang.test.js
373
+ │ └── upgrade.test.js
374
+ ├── utils/
375
+ │ ├── git.test.js
376
+ │ └── update-checker.test.js
377
+ └── fixtures/
378
+ └── test-data.json
379
+ ```
380
+
381
+ ### 2. 测试用例规范
382
+ ```javascript
383
+ // tests/commands/example.test.js
384
+ const { execute } = require('../../lib/commands/example');
385
+
386
+ describe('Example Command', () => {
387
+ test('应该成功执行命令', async () => {
388
+ const options = { param: 'test' };
389
+ const result = await execute(options);
390
+ expect(result).toBeDefined();
391
+ });
392
+
393
+ test('应该处理参数错误', async () => {
394
+ const options = {};
395
+ await expect(execute(options)).rejects.toThrow('缺少必需参数');
396
+ });
397
+ });
398
+ ```
399
+
400
+ ## 📦 发布规范
401
+
402
+ ### 1. 版本更新流程
403
+ 1. 更新 `package.json` 版本号
404
+ 2. 更新 `CHANGELOG.md` 记录变更
405
+ 3. 更新 `README.md` 文档(如需要)
406
+ 4. 提交代码并创建标签
407
+ 5. 发布到 npm
408
+
409
+ ### 2. 变更日志规范
410
+ ```markdown
411
+ ## [版本号] - 日期
412
+
413
+ ### 新增
414
+ - 新功能描述
415
+
416
+ ### 更改
417
+ - 功能改进描述
418
+
419
+ ### 修复
420
+ - 问题修复描述
421
+
422
+ ### 移除
423
+ - 移除功能描述
424
+ ```
425
+
426
+ ## ⚠️ 重要注意事项
427
+
428
+ ### 1. 自动更新检查机制
429
+ - **所有新命令都会自动获得后台更新检查功能**
430
+ - 无需手动实现更新检查逻辑
431
+ - 系统会在命令执行时自动检查并提醒用户更新
432
+ - `upgrade` 命令本身不会触发更新提醒
433
+
434
+ ### 2. 命令执行流程
435
+ ```javascript
436
+ // 每个命令执行时都会经过以下流程:
437
+ // 1. 启动后台更新检查(异步)
438
+ // 2. 检查并显示更新提醒(如有新版本)
439
+ // 3. 执行具体命令逻辑
440
+ // 4. 返回执行结果
441
+ ```
442
+
443
+ ### 3. 必须遵循的规则
444
+ - **不要修改主程序中的更新检查逻辑**
445
+ - **不要重复实现更新检查功能**
446
+ - **确保命令不会干扰更新检查机制**
447
+ - **长时间运行的命令要支持中断**
448
+
449
+ ### 4. 命令开发限制
450
+ - 避免在命令中直接调用 `process.exit()`
451
+ - 不要阻塞主事件循环
452
+ - 网络请求必须设置超时时间
453
+ - 文件操作要处理权限错误
454
+
455
+ ### 5. 性能考虑
456
+ - 命令执行时间应控制在合理范围内
457
+ - 大量数据处理要显示进度
458
+ - 避免内存泄漏
459
+ - 合理使用缓存
460
+
461
+ ## ❓ 常见问题
462
+
463
+ ### Q1: 如何添加新的命令选项?
464
+ A: 在命令注册时添加 `.option()` 调用,在命令实现中处理该选项。
465
+
466
+ ### Q2: 如何处理异步操作?
467
+ A: 使用 `async/await` 语法,确保错误被正确捕获和处理。
468
+
469
+ ### Q3: 如何添加子命令?
470
+ A: 使用 `program.command()` 创建父命令,然后使用 `.command()` 添加子命令。
471
+
472
+ ### Q4: 如何确保命令的向后兼容性?
473
+ A: 避免删除现有选项,使用弃用警告而不是直接删除。
474
+
475
+ ### Q5: 如何处理网络请求?
476
+ A: 使用 `axios` 库,设置合理的超时时间,添加错误处理。
477
+
478
+ ### Q6: 新命令会自动获得更新检查功能吗?
479
+ A: 是的,所有新命令都会自动获得后台更新检查功能,无需手动实现。
480
+
481
+ ### Q7: 如何确保命令不会干扰更新检查?
482
+ A: 不要修改主程序中的更新检查逻辑,不要重复实现更新检查功能。
483
+
484
+ ## 🔧 开发工具推荐
485
+
486
+ ### 代码质量工具
487
+ - ESLint: 代码风格检查
488
+ - Prettier: 代码格式化
489
+ - Jest: 单元测试
490
+
491
+ ### 调试工具
492
+ - Node.js 内置调试器
493
+ - VS Code 调试配置
494
+ - 日志输出工具
495
+
496
+ ## 📚 参考资源
497
+
498
+ - [Commander.js 文档](https://github.com/tj/commander.js)
499
+ - [Node.js 最佳实践](https://github.com/goldbergyoni/nodebestpractices)
500
+ - [语义化版本规范](https://semver.org/lang/zh-CN/)
501
+
502
+ ---
503
+
504
+ **注意**: 本文档会随着项目发展持续更新,请确保使用最新版本。
package/README.md CHANGED
@@ -20,6 +20,11 @@ npm install -g daodou-command
20
20
  - 自动翻译功能(Google Translate API)
21
21
  - 多代理轮换绕过API限制
22
22
 
23
+ ### 🔄 自动更新
24
+ - 智能版本检查和更新
25
+ - 一键升级到最新版本
26
+ - 支持强制更新和仅检查模式
27
+
23
28
  ## 快速开始
24
29
 
25
30
  ### 构建项目
@@ -29,6 +34,18 @@ cd your-project
29
34
  dao build
30
35
  ```
31
36
 
37
+ ### 检查更新
38
+ ```bash
39
+ # 检查是否有新版本
40
+ dao upgrade --check
41
+
42
+ # 更新到最新版本
43
+ dao upgrade
44
+
45
+ # 强制更新
46
+ dao upgrade --force
47
+ ```
48
+
32
49
  ### 多语言管理
33
50
  ```bash
34
51
  # 添加多语言项(自动翻译)
@@ -79,6 +96,14 @@ dao build --branch feature # 指定分支构建
79
96
  dao build --help # 查看帮助
80
97
  ```
81
98
 
99
+ ### 更新命令
100
+ ```bash
101
+ dao upgrade # 检查并更新到最新版本
102
+ dao upgrade --check # 仅检查是否有新版本
103
+ dao upgrade --force # 强制更新到最新版本
104
+ dao upgrade --help # 查看帮助
105
+ ```
106
+
82
107
  ### 多语言命令
83
108
  ```bash
84
109
  dao lang add "key" "value" # 添加多语言项
package/bin/daodou.js CHANGED
@@ -6,9 +6,28 @@ const path = require('path');
6
6
  const packageJson = require('../package.json');
7
7
  const buildCommand = require('../lib/commands/build');
8
8
  const langCommand = require('../lib/commands/lang');
9
+ const updateChecker = require('../lib/utils/update-checker');
9
10
 
10
11
  const program = new Command();
11
12
 
13
+ // 异步启动后台更新检查,不阻塞主程序
14
+ setImmediate(() => {
15
+ updateChecker.startBackgroundCheck();
16
+ });
17
+
18
+ // 检查并显示更新提醒(upgrade命令除外)
19
+ const args = process.argv.slice(2);
20
+ const isUpgradeCommand = args[0] === 'upgrade';
21
+
22
+ if (!isUpgradeCommand && updateChecker.shouldRemindUpdate()) {
23
+ const reminder = updateChecker.getUpdateReminder();
24
+ if (reminder) {
25
+ console.log(chalk.yellow(reminder));
26
+ console.log(); // 空行
27
+ // 不标记为已提醒,允许重复提醒
28
+ }
29
+ }
30
+
12
31
  // 设置程序信息
13
32
  program
14
33
  .name('dao')
@@ -0,0 +1,183 @@
1
+ const axios = require('axios');
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+ const os = require('os');
5
+ const packageJson = require('../../package.json');
6
+
7
+ // 全局状态文件路径
8
+ const STATE_FILE = path.join(os.homedir(), '.daodou-update-state.json');
9
+
10
+ /**
11
+ * 获取npm上的最新版本号
12
+ * @returns {Promise<string>} 最新版本号
13
+ */
14
+ async function getLatestVersion() {
15
+ try {
16
+ const response = await axios.get(`https://registry.npmjs.org/${packageJson.name}/latest`, {
17
+ timeout: 5000 // 5秒超时,避免阻塞
18
+ });
19
+ return response.data.version;
20
+ } catch (error) {
21
+ // 静默失败,不影响主命令执行
22
+ return null;
23
+ }
24
+ }
25
+
26
+ /**
27
+ * 比较版本号
28
+ * @param {string} current 当前版本
29
+ * @param {string} latest 最新版本
30
+ * @returns {boolean} 是否有更新
31
+ */
32
+ function hasUpdate(current, latest) {
33
+ if (!latest) return false;
34
+
35
+ const currentParts = current.split('.').map(Number);
36
+ const latestParts = latest.split('.').map(Number);
37
+
38
+ for (let i = 0; i < Math.max(currentParts.length, latestParts.length); i++) {
39
+ const currentPart = currentParts[i] || 0;
40
+ const latestPart = latestParts[i] || 0;
41
+
42
+ if (latestPart > currentPart) {
43
+ return true;
44
+ } else if (latestPart < currentPart) {
45
+ return false;
46
+ }
47
+ }
48
+
49
+ return false;
50
+ }
51
+
52
+ /**
53
+ * 读取全局状态
54
+ * @returns {Object} 状态对象
55
+ */
56
+ function readState() {
57
+ try {
58
+ if (fs.existsSync(STATE_FILE)) {
59
+ const content = fs.readFileSync(STATE_FILE, 'utf8');
60
+ return JSON.parse(content);
61
+ }
62
+ } catch (error) {
63
+ // 忽略读取错误
64
+ }
65
+
66
+ return {
67
+ lastCheck: 0,
68
+ hasUpdate: false,
69
+ latestVersion: null,
70
+ reminded: false
71
+ };
72
+ }
73
+
74
+ /**
75
+ * 写入全局状态
76
+ * @param {Object} state 状态对象
77
+ */
78
+ function writeState(state) {
79
+ try {
80
+ fs.writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
81
+ } catch (error) {
82
+ // 忽略写入错误
83
+ }
84
+ }
85
+
86
+ /**
87
+ * 检查是否需要提醒更新
88
+ * @returns {boolean} 是否需要提醒
89
+ */
90
+ function shouldRemindUpdate() {
91
+ const state = readState();
92
+ return state.hasUpdate && !state.reminded;
93
+ }
94
+
95
+ /**
96
+ * 标记已提醒
97
+ */
98
+ function markAsReminded() {
99
+ const state = readState();
100
+ state.reminded = true;
101
+ writeState(state);
102
+ }
103
+
104
+ /**
105
+ * 后台检查更新(完全异步,不阻塞主命令)
106
+ */
107
+ async function checkUpdateInBackground() {
108
+ // 使用setTimeout确保完全异步执行
109
+ setTimeout(async () => {
110
+ try {
111
+ const currentVersion = packageJson.version;
112
+ const latestVersion = await getLatestVersion();
113
+
114
+ if (latestVersion && hasUpdate(currentVersion, latestVersion)) {
115
+ const state = readState();
116
+ state.lastCheck = Date.now();
117
+ state.hasUpdate = true;
118
+ state.latestVersion = latestVersion;
119
+ state.reminded = false; // 重置提醒状态
120
+ writeState(state);
121
+ } else {
122
+ // 更新状态,标记没有更新
123
+ const state = readState();
124
+ state.lastCheck = Date.now();
125
+ state.hasUpdate = false;
126
+ state.latestVersion = latestVersion;
127
+ writeState(state);
128
+ }
129
+ } catch (error) {
130
+ // 静默失败,不影响主程序
131
+ }
132
+ }, 0);
133
+ }
134
+
135
+ /**
136
+ * 获取更新提醒消息
137
+ * @returns {string|null} 提醒消息
138
+ */
139
+ function getUpdateReminder() {
140
+ const state = readState();
141
+
142
+ if (!state.hasUpdate || state.reminded) {
143
+ return null;
144
+ }
145
+
146
+ return `🔄 发现新版本 ${state.latestVersion}!使用 "dao upgrade" 更新到最新版本。`;
147
+ }
148
+
149
+ /**
150
+ * 检查是否需要执行后台更新检查
151
+ * @returns {boolean} 是否需要检查
152
+ */
153
+ function shouldCheckUpdate() {
154
+ const state = readState();
155
+ const now = Date.now();
156
+ const oneHour = 60 * 60 * 1000; // 1小时
157
+
158
+ // 如果从未检查过,或者距离上次检查超过1小时,则检查
159
+ return !state.lastCheck || (now - state.lastCheck) > oneHour;
160
+ }
161
+
162
+ /**
163
+ * 启动后台更新检查(完全异步)
164
+ */
165
+ function startBackgroundCheck() {
166
+ // 使用setImmediate确保在下一个事件循环中执行
167
+ setImmediate(() => {
168
+ if (shouldCheckUpdate()) {
169
+ // 异步执行,不等待结果
170
+ checkUpdateInBackground().catch(() => {
171
+ // 静默失败,不影响主程序
172
+ });
173
+ }
174
+ });
175
+ }
176
+
177
+ module.exports = {
178
+ startBackgroundCheck,
179
+ shouldRemindUpdate,
180
+ getUpdateReminder,
181
+ markAsReminded,
182
+ checkUpdateInBackground
183
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "daodou-command",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "description": "刀豆命令行工具 - 自动化构建和部署",
5
5
  "main": "index.js",
6
6
  "bin": {