@agile-team/robot-cli 1.0.9 → 1.1.1
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 +17 -21
- package/bin/index.js +14 -128
- package/lib/create.js +1124 -957
- package/lib/download.js +17 -101
- package/lib/utils.js +86 -92
- package/package.json +4 -6
- package/lib/cache.js +0 -120
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
- **🎯 智能模板分类** - 推荐模板、分类浏览、关键词搜索
|
|
10
10
|
- **⚡ 极速项目创建** - 一条命令创建完整项目架构
|
|
11
11
|
- **📦 现代包管理器** - 优先推荐 bun/pnpm,智能检测最佳选择
|
|
12
|
-
- **🌐
|
|
12
|
+
- **🌐 总是最新版本** - 每次创建都下载最新模板,无缓存困扰
|
|
13
13
|
- **🎨 友好用户界面** - 现代化终端交互,清晰进度提示
|
|
14
14
|
|
|
15
15
|
## 🚀 快速开始
|
|
@@ -70,9 +70,6 @@ robot create my-project --template robot-admin
|
|
|
70
70
|
|
|
71
71
|
# 跳过依赖安装
|
|
72
72
|
robot create my-project --skip-install
|
|
73
|
-
|
|
74
|
-
# 强制重新下载
|
|
75
|
-
robot create my-project --no-cache
|
|
76
73
|
```
|
|
77
74
|
|
|
78
75
|
### 模板管理
|
|
@@ -88,15 +85,6 @@ robot search vue
|
|
|
88
85
|
robot search admin
|
|
89
86
|
```
|
|
90
87
|
|
|
91
|
-
### 缓存管理
|
|
92
|
-
```bash
|
|
93
|
-
# 查看缓存信息
|
|
94
|
-
robot cache
|
|
95
|
-
|
|
96
|
-
# 清除缓存
|
|
97
|
-
robot cache --clear
|
|
98
|
-
```
|
|
99
|
-
|
|
100
88
|
## 📦 包管理器优先级
|
|
101
89
|
|
|
102
90
|
Robot CLI 智能选择最佳包管理器:
|
|
@@ -106,6 +94,15 @@ Robot CLI 智能选择最佳包管理器:
|
|
|
106
94
|
3. **yarn** ⚖️ - 兼容现有项目
|
|
107
95
|
4. **npm** ⚖️ - Node.js默认
|
|
108
96
|
|
|
97
|
+
## 🌐 为什么选择"总是最新"
|
|
98
|
+
|
|
99
|
+
Robot CLI 不使用本地缓存,每次创建项目都会下载最新版本的模板:
|
|
100
|
+
|
|
101
|
+
- ✅ **确保最新**: 总是获得最新的代码和依赖
|
|
102
|
+
- ✅ **避免冲突**: 无需担心缓存过期或版本不一致
|
|
103
|
+
- ✅ **简化维护**: 用户无需管理缓存,开发者无需考虑缓存策略
|
|
104
|
+
- ✅ **减少错误**: 避免因缓存损坏导致的创建失败
|
|
105
|
+
|
|
109
106
|
## 🛠 开发指南
|
|
110
107
|
|
|
111
108
|
### 项目结构
|
|
@@ -116,7 +113,6 @@ robot-cli/
|
|
|
116
113
|
│ ├── templates.js # 模板配置
|
|
117
114
|
│ ├── create.js # 创建流程
|
|
118
115
|
│ ├── download.js # 下载逻辑
|
|
119
|
-
│ ├── cache.js # 缓存管理
|
|
120
116
|
│ └── utils.js # 工具函数
|
|
121
117
|
└── test/local-test.js # 测试脚本
|
|
122
118
|
```
|
|
@@ -128,7 +124,7 @@ robot-cli/
|
|
|
128
124
|
'robot-new-template': {
|
|
129
125
|
name: 'Robot新模板',
|
|
130
126
|
description: '模板描述',
|
|
131
|
-
|
|
127
|
+
repoUrl: 'https://github.com/ChenyCHENYU/Robot_New_Template',
|
|
132
128
|
features: ['特性1', '特性2'],
|
|
133
129
|
version: 'full'
|
|
134
130
|
}
|
|
@@ -200,7 +196,7 @@ export const TEMPLATE_CATEGORIES = {
|
|
|
200
196
|
templates: {
|
|
201
197
|
'your-admin': {
|
|
202
198
|
name: '你的后台模板',
|
|
203
|
-
|
|
199
|
+
repoUrl: 'https://github.com/YOUR_ORG/Your_Admin_Template',
|
|
204
200
|
// ...
|
|
205
201
|
}
|
|
206
202
|
}
|
|
@@ -319,10 +315,7 @@ your-cli generate component MyComponent
|
|
|
319
315
|
{
|
|
320
316
|
"templateSource": "github",
|
|
321
317
|
"defaultOrg": "YourOrg",
|
|
322
|
-
"
|
|
323
|
-
"enabled": true,
|
|
324
|
-
"ttl": 86400000
|
|
325
|
-
}
|
|
318
|
+
"alwaysLatest": true
|
|
326
319
|
}
|
|
327
320
|
```
|
|
328
321
|
|
|
@@ -401,7 +394,7 @@ analytics.track('template_used', {
|
|
|
401
394
|
A: 全局安装CLI:`npm install -g @agile-team/robot-cli`
|
|
402
395
|
|
|
403
396
|
**Q: 模板下载失败?**
|
|
404
|
-
A:
|
|
397
|
+
A: 检查网络连接,确保能访问GitHub
|
|
405
398
|
|
|
406
399
|
**Q: 如何添加自定义模板?**
|
|
407
400
|
A: 创建模板仓库 → 添加配置 → 测试功能
|
|
@@ -409,6 +402,9 @@ A: 创建模板仓库 → 添加配置 → 测试功能
|
|
|
409
402
|
**Q: 支持私有仓库吗?**
|
|
410
403
|
A: 目前仅支持公开GitHub仓库
|
|
411
404
|
|
|
405
|
+
**Q: 为什么不使用缓存?**
|
|
406
|
+
A: 为了确保总是获得最新版本的模板,避免缓存相关的问题
|
|
407
|
+
|
|
412
408
|
## 🎉 快速体验
|
|
413
409
|
|
|
414
410
|
```bash
|
package/bin/index.js
CHANGED
|
@@ -14,7 +14,6 @@ const __dirname = dirname(__filename);
|
|
|
14
14
|
*/
|
|
15
15
|
function getPackageVersion() {
|
|
16
16
|
try {
|
|
17
|
-
// 尝试从多个位置读取 package.json
|
|
18
17
|
const possiblePaths = [
|
|
19
18
|
join(__dirname, '..', 'package.json'),
|
|
20
19
|
join(__dirname, 'package.json'),
|
|
@@ -28,49 +27,34 @@ function getPackageVersion() {
|
|
|
28
27
|
}
|
|
29
28
|
}
|
|
30
29
|
|
|
31
|
-
return '1.0.0';
|
|
30
|
+
return '1.0.0';
|
|
32
31
|
} catch (error) {
|
|
33
|
-
return '1.0.0';
|
|
32
|
+
return '1.0.0';
|
|
34
33
|
}
|
|
35
34
|
}
|
|
36
35
|
|
|
37
|
-
// 获取版本号
|
|
38
36
|
const PACKAGE_VERSION = getPackageVersion();
|
|
39
37
|
|
|
40
38
|
/**
|
|
41
|
-
* 智能路径解析
|
|
39
|
+
* 智能路径解析
|
|
42
40
|
*/
|
|
43
41
|
function resolveLibPath() {
|
|
44
|
-
// 可能的 lib 目录路径
|
|
45
42
|
const possiblePaths = [
|
|
46
|
-
// 1. 标准相对路径 (开发环境 + 大多数情况)
|
|
47
43
|
join(__dirname, '..', 'lib'),
|
|
48
|
-
|
|
49
|
-
// 2. 同级目录 (某些链接情况)
|
|
50
44
|
join(__dirname, 'lib'),
|
|
51
|
-
|
|
52
|
-
// 3. 向上查找 (深度嵌套情况)
|
|
53
45
|
join(__dirname, '..', '..', 'lib'),
|
|
54
|
-
|
|
55
|
-
// 4. 从 node_modules 查找 (npm/yarn)
|
|
56
46
|
join(__dirname, '..', 'node_modules', '@agile-team', 'robot-cli', 'lib'),
|
|
57
|
-
|
|
58
|
-
// 5. 全局安装的各种可能路径
|
|
59
47
|
resolve(__dirname, '..', 'lib'),
|
|
60
48
|
resolve(__dirname, '../../lib'),
|
|
61
|
-
|
|
62
|
-
// 6. bun 特殊路径处理
|
|
63
49
|
join(__dirname, '..', '..', '@agile-team', 'robot-cli', 'lib'),
|
|
64
50
|
];
|
|
65
51
|
|
|
66
|
-
// 查找第一个存在的路径
|
|
67
52
|
for (const libPath of possiblePaths) {
|
|
68
53
|
if (existsSync(libPath)) {
|
|
69
54
|
return libPath;
|
|
70
55
|
}
|
|
71
56
|
}
|
|
72
57
|
|
|
73
|
-
// 如果都找不到,抛出详细错误
|
|
74
58
|
throw new Error(`
|
|
75
59
|
无法找到 lib 目录,已尝试以下路径:
|
|
76
60
|
${possiblePaths.map(p => ` - ${p}`).join('\n')}
|
|
@@ -85,25 +69,21 @@ ${possiblePaths.map(p => ` - ${p}`).join('\n')}
|
|
|
85
69
|
`);
|
|
86
70
|
}
|
|
87
71
|
|
|
88
|
-
// 动态导入所需模块
|
|
72
|
+
// 动态导入所需模块 - 移除缓存相关模块
|
|
89
73
|
async function loadModules() {
|
|
90
74
|
try {
|
|
91
75
|
const libPath = resolveLibPath();
|
|
92
76
|
|
|
93
|
-
// 将路径转换为 file:// URL 格式(Windows 兼容)
|
|
94
77
|
const createUrl = pathToFileURL(join(libPath, 'create.js')).href;
|
|
95
|
-
const cacheUrl = pathToFileURL(join(libPath, 'cache.js')).href;
|
|
96
78
|
const templatesUrl = pathToFileURL(join(libPath, 'templates.js')).href;
|
|
97
79
|
const utilsUrl = pathToFileURL(join(libPath, 'utils.js')).href;
|
|
98
80
|
|
|
99
|
-
// 动态导入所有需要的模块
|
|
100
81
|
const [
|
|
101
82
|
{ Command },
|
|
102
83
|
chalk,
|
|
103
84
|
boxen,
|
|
104
85
|
inquirer,
|
|
105
86
|
{ createProject },
|
|
106
|
-
{ clearCache, getCacheInfo, formatSize },
|
|
107
87
|
{ getAllTemplates, searchTemplates, getRecommendedTemplates },
|
|
108
88
|
{ checkNetworkConnection }
|
|
109
89
|
] = await Promise.all([
|
|
@@ -112,7 +92,6 @@ async function loadModules() {
|
|
|
112
92
|
import('boxen'),
|
|
113
93
|
import('inquirer'),
|
|
114
94
|
import(createUrl),
|
|
115
|
-
import(cacheUrl),
|
|
116
95
|
import(templatesUrl),
|
|
117
96
|
import(utilsUrl)
|
|
118
97
|
]);
|
|
@@ -123,9 +102,6 @@ async function loadModules() {
|
|
|
123
102
|
boxen: boxen.default,
|
|
124
103
|
inquirer: inquirer.default,
|
|
125
104
|
createProject,
|
|
126
|
-
clearCache,
|
|
127
|
-
getCacheInfo,
|
|
128
|
-
formatSize,
|
|
129
105
|
getAllTemplates,
|
|
130
106
|
searchTemplates,
|
|
131
107
|
getRecommendedTemplates,
|
|
@@ -160,9 +136,6 @@ async function main() {
|
|
|
160
136
|
boxen,
|
|
161
137
|
inquirer,
|
|
162
138
|
createProject,
|
|
163
|
-
clearCache,
|
|
164
|
-
getCacheInfo,
|
|
165
|
-
formatSize,
|
|
166
139
|
getAllTemplates,
|
|
167
140
|
searchTemplates,
|
|
168
141
|
getRecommendedTemplates,
|
|
@@ -203,20 +176,18 @@ async function main() {
|
|
|
203
176
|
console.log();
|
|
204
177
|
}
|
|
205
178
|
|
|
206
|
-
// 显示主菜单
|
|
179
|
+
// 显示主菜单 - 移除缓存信息
|
|
207
180
|
async function showMainMenu() {
|
|
208
181
|
const title = chalk.white.bold('🚀 快速开始');
|
|
209
182
|
|
|
210
183
|
console.log(' ' + title);
|
|
211
184
|
console.log();
|
|
212
185
|
|
|
213
|
-
// 获取统计信息
|
|
214
186
|
const allTemplates = getAllTemplates();
|
|
215
187
|
const templateCount = Object.keys(allTemplates).length;
|
|
216
|
-
const cacheInfo = await getCacheInfo();
|
|
217
188
|
|
|
218
189
|
console.log(chalk.dim(` 📦 可用模板: ${templateCount} 个`));
|
|
219
|
-
console.log(chalk.dim(`
|
|
190
|
+
console.log(chalk.dim(` 🌐 总是下载最新版本`));
|
|
220
191
|
console.log();
|
|
221
192
|
|
|
222
193
|
const commands = [
|
|
@@ -239,11 +210,6 @@ async function main() {
|
|
|
239
210
|
cmd: 'robot search <keyword>',
|
|
240
211
|
desc: '搜索模板',
|
|
241
212
|
color: 'magenta'
|
|
242
|
-
},
|
|
243
|
-
{
|
|
244
|
-
cmd: 'robot cache',
|
|
245
|
-
desc: '缓存管理',
|
|
246
|
-
color: 'yellow'
|
|
247
213
|
}
|
|
248
214
|
];
|
|
249
215
|
|
|
@@ -262,29 +228,26 @@ async function main() {
|
|
|
262
228
|
program
|
|
263
229
|
.name('robot')
|
|
264
230
|
.description('🤖 Robot 项目脚手架工具 - @agile-team/robot-cli')
|
|
265
|
-
.version(PACKAGE_VERSION)
|
|
231
|
+
.version(PACKAGE_VERSION)
|
|
266
232
|
.hook('preAction', () => {
|
|
267
233
|
showWelcome();
|
|
268
234
|
});
|
|
269
235
|
|
|
270
|
-
// 创建项目命令
|
|
236
|
+
// 创建项目命令 - 移除缓存相关选项
|
|
271
237
|
program
|
|
272
238
|
.command('create [project-name]')
|
|
273
239
|
.description('创建新项目')
|
|
274
240
|
.option('-t, --template <template>', '指定模板类型')
|
|
275
|
-
.option('--no-cache', '强制重新下载模板')
|
|
276
241
|
.option('--skip-install', '跳过依赖安装')
|
|
277
242
|
.action(async (projectName, options) => {
|
|
278
243
|
try {
|
|
279
244
|
// 检查网络连接
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
process.exit(1);
|
|
287
|
-
}
|
|
245
|
+
console.log(chalk.blue('🌐 检查网络连接...'));
|
|
246
|
+
const hasNetwork = await checkNetworkConnection();
|
|
247
|
+
if (!hasNetwork) {
|
|
248
|
+
console.log(chalk.red('❌ 网络连接失败,无法下载模板'));
|
|
249
|
+
console.log(chalk.yellow('💡 请检查网络连接后重试'));
|
|
250
|
+
process.exit(1);
|
|
288
251
|
}
|
|
289
252
|
|
|
290
253
|
await createProject(projectName, options);
|
|
@@ -292,7 +255,6 @@ async function main() {
|
|
|
292
255
|
console.log();
|
|
293
256
|
console.log(chalk.red('✗'), chalk.red.bold('创建失败'));
|
|
294
257
|
|
|
295
|
-
// 根据错误类型提供不同的建议
|
|
296
258
|
if (error.message.includes('网络')) {
|
|
297
259
|
console.log(' ' + chalk.dim('网络相关问题,请检查网络连接'));
|
|
298
260
|
} else if (error.message.includes('权限')) {
|
|
@@ -337,7 +299,6 @@ async function main() {
|
|
|
337
299
|
// 按分类显示
|
|
338
300
|
const categories = {};
|
|
339
301
|
Object.entries(templates).forEach(([key, template]) => {
|
|
340
|
-
// 简单分类逻辑,根据模板名称前缀
|
|
341
302
|
const category = key.split('-')[0];
|
|
342
303
|
if (!categories[category]) {
|
|
343
304
|
categories[category] = [];
|
|
@@ -394,81 +355,6 @@ async function main() {
|
|
|
394
355
|
}
|
|
395
356
|
});
|
|
396
357
|
|
|
397
|
-
// 缓存管理
|
|
398
|
-
program
|
|
399
|
-
.command('cache')
|
|
400
|
-
.description('缓存管理')
|
|
401
|
-
.option('-c, --clear', '清除所有缓存')
|
|
402
|
-
.option('-i, --info', '显示缓存信息')
|
|
403
|
-
.action(async (options) => {
|
|
404
|
-
try {
|
|
405
|
-
if (options.clear) {
|
|
406
|
-
const { confirmed } = await inquirer.prompt([
|
|
407
|
-
{
|
|
408
|
-
type: 'confirm',
|
|
409
|
-
name: 'confirmed',
|
|
410
|
-
message: '确认清除所有模板缓存?',
|
|
411
|
-
default: false
|
|
412
|
-
}
|
|
413
|
-
]);
|
|
414
|
-
|
|
415
|
-
if (confirmed) {
|
|
416
|
-
await clearCache();
|
|
417
|
-
console.log();
|
|
418
|
-
console.log(chalk.green('✓'), chalk.green.bold('缓存清除成功'));
|
|
419
|
-
} else {
|
|
420
|
-
console.log(chalk.yellow('❌ 取消清除'));
|
|
421
|
-
}
|
|
422
|
-
} else {
|
|
423
|
-
// 显示缓存信息
|
|
424
|
-
const cacheInfo = await getCacheInfo();
|
|
425
|
-
|
|
426
|
-
console.log();
|
|
427
|
-
console.log(chalk.blue('💾 缓存信息:'));
|
|
428
|
-
console.log();
|
|
429
|
-
|
|
430
|
-
if (!cacheInfo.exists || cacheInfo.templates.length === 0) {
|
|
431
|
-
console.log(chalk.dim(' 暂无缓存模板'));
|
|
432
|
-
} else {
|
|
433
|
-
console.log(` 缓存目录: ${chalk.dim(cacheInfo.path)}`);
|
|
434
|
-
console.log(` 模板数量: ${chalk.cyan(cacheInfo.templates.length)} 个`);
|
|
435
|
-
console.log(` 总大小: ${chalk.cyan(formatSize(cacheInfo.size))}`);
|
|
436
|
-
console.log();
|
|
437
|
-
console.log(chalk.blue(' 缓存的模板:'));
|
|
438
|
-
|
|
439
|
-
cacheInfo.templates.forEach(template => {
|
|
440
|
-
const modifiedTime = template.modifiedTime.toLocaleDateString();
|
|
441
|
-
console.log(` ${chalk.green('●')} ${template.name}`);
|
|
442
|
-
console.log(` 大小: ${formatSize(template.size)} 更新: ${modifiedTime}`);
|
|
443
|
-
});
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
console.log();
|
|
447
|
-
console.log(chalk.dim(' 使用 robot cache --clear 清除缓存'));
|
|
448
|
-
}
|
|
449
|
-
} catch (error) {
|
|
450
|
-
console.log(chalk.red('❌ 缓存操作失败:'), error.message);
|
|
451
|
-
}
|
|
452
|
-
});
|
|
453
|
-
|
|
454
|
-
// 清除缓存命令 (向后兼容)
|
|
455
|
-
program
|
|
456
|
-
.command('clear-cache')
|
|
457
|
-
.description('清除模板缓存')
|
|
458
|
-
.action(async () => {
|
|
459
|
-
try {
|
|
460
|
-
await clearCache();
|
|
461
|
-
console.log();
|
|
462
|
-
console.log(chalk.green('✓'), chalk.green.bold('缓存清除成功'));
|
|
463
|
-
console.log();
|
|
464
|
-
} catch (error) {
|
|
465
|
-
console.log();
|
|
466
|
-
console.log(chalk.red('✗'), chalk.red.bold('清除缓存失败'));
|
|
467
|
-
console.log(' ' + chalk.dim(error.message));
|
|
468
|
-
console.log();
|
|
469
|
-
}
|
|
470
|
-
});
|
|
471
|
-
|
|
472
358
|
// 如果没有参数,显示主菜单
|
|
473
359
|
if (process.argv.length === 2) {
|
|
474
360
|
showWelcome();
|