@agile-team/robot-cli 1.0.4 → 1.0.6

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/bin/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { fileURLToPath } from 'url';
3
+ import { fileURLToPath, pathToFileURL } from 'url';
4
4
  import { dirname, join, resolve } from 'path';
5
5
  import { existsSync } from 'fs';
6
6
 
@@ -61,6 +61,12 @@ async function loadModules() {
61
61
  try {
62
62
  const libPath = resolveLibPath();
63
63
 
64
+ // 将路径转换为 file:// URL 格式(Windows 兼容)
65
+ const createUrl = pathToFileURL(join(libPath, 'create.js')).href;
66
+ const cacheUrl = pathToFileURL(join(libPath, 'cache.js')).href;
67
+ const templatesUrl = pathToFileURL(join(libPath, 'templates.js')).href;
68
+ const utilsUrl = pathToFileURL(join(libPath, 'utils.js')).href;
69
+
64
70
  // 动态导入所有需要的模块
65
71
  const [
66
72
  { Command },
@@ -76,10 +82,10 @@ async function loadModules() {
76
82
  import('chalk'),
77
83
  import('boxen'),
78
84
  import('inquirer'),
79
- import(join(libPath, 'create.js')),
80
- import(join(libPath, 'cache.js')),
81
- import(join(libPath, 'templates.js')),
82
- import(join(libPath, 'utils.js'))
85
+ import(createUrl),
86
+ import(cacheUrl),
87
+ import(templatesUrl),
88
+ import(utilsUrl)
83
89
  ]);
84
90
 
85
91
  return {
@@ -153,7 +159,7 @@ async function main() {
153
159
 
154
160
  const titleBox = boxen(
155
161
  logo + '\n\n' +
156
- ' 🤖 Robot 项目脚手架工具 v1.0.3\n' +
162
+ ' 🤖 Robot 项目脚手架工具 v1.0.4\n' +
157
163
  ' 兼容 npm/yarn/pnpm/bun',
158
164
  {
159
165
  padding: { top: 1, bottom: 1, left: 2, right: 2 },
@@ -227,7 +233,7 @@ async function main() {
227
233
  program
228
234
  .name('robot')
229
235
  .description('🤖 Robot 项目脚手架工具 - @agile-team/robot-cli')
230
- .version('1.0.3')
236
+ .version('1.0.4')
231
237
  .hook('preAction', () => {
232
238
  showWelcome();
233
239
  });
package/lib/create.js CHANGED
@@ -1,4 +1,4 @@
1
- // lib/create.js
1
+ // lib/create.js - 增强版本,改进进度显示
2
2
  import fs from "fs-extra";
3
3
  import path from "path";
4
4
  import chalk from "chalk";
@@ -104,7 +104,7 @@ function generateDefaultProjectName(template) {
104
104
  const timestamp = Date.now().toString().slice(-4);
105
105
 
106
106
  // 移除版本后缀 (-full, -lite)
107
- const baseName = templateKey.replace(/-(full|lite)$/, "");
107
+ const baseName = templateKey.replace(/-(full|lite|base)$/, "");
108
108
 
109
109
  return `my-${baseName}-${timestamp}`;
110
110
  }
@@ -671,7 +671,7 @@ async function confirmCreation(projectName, template, projectConfig) {
671
671
  }
672
672
 
673
673
  /**
674
- * 执行创建流程
674
+ * 执行创建流程 - 增强版本,改进进度显示
675
675
  */
676
676
  async function executeCreation(projectName, template, projectConfig) {
677
677
  // 调试信息 - 确保参数正确
@@ -683,13 +683,20 @@ async function executeCreation(projectName, template, projectConfig) {
683
683
  throw new Error(`模板数据无效: ${JSON.stringify(template)}`);
684
684
  }
685
685
 
686
- const spinner = ora("准备创建项目...").start();
686
+ // 使用更详细的 spinner 配置
687
+ const spinner = ora({
688
+ text: "🚀 准备创建项目...",
689
+ spinner: 'dots',
690
+ color: 'cyan'
691
+ }).start();
687
692
 
688
693
  try {
689
694
  // 1. 检查目录是否存在
695
+ spinner.text = "📁 检查项目目录...";
690
696
  const projectPath = path.resolve(projectName);
691
697
  if (fs.existsSync(projectPath)) {
692
- spinner.fail("项目目录已存在");
698
+ spinner.stop();
699
+ console.log(chalk.yellow("⚠️ 项目目录已存在"));
693
700
 
694
701
  const { overwrite } = await inquirer.prompt([
695
702
  {
@@ -705,18 +712,19 @@ async function executeCreation(projectName, template, projectConfig) {
705
712
  process.exit(0);
706
713
  }
707
714
 
715
+ spinner.start("🗑️ 清理现有目录...");
708
716
  await fs.remove(projectPath);
709
- spinner.start("准备创建项目...");
717
+ spinner.text = "📁 准备创建新目录...";
710
718
  }
711
719
 
712
- // 2. 下载模板
713
- spinner.text = "下载模板中...";
720
+ // 2. 下载模板 - download.js 会自动更新 spinner 状态
721
+ spinner.text = "🌐 开始下载模板...";
714
722
  let templatePath;
715
723
 
716
724
  try {
717
725
  templatePath = await downloadTemplate(template, {
718
726
  useCache: projectConfig.useCache,
719
- spinner,
727
+ spinner, // 传递 spinner,让 download 函数更新进度
720
728
  });
721
729
 
722
730
  // 验证模板路径
@@ -737,16 +745,17 @@ async function executeCreation(projectName, template, projectConfig) {
737
745
  console.log(chalk.dim(" 1. 检查网络连接"));
738
746
  console.log(chalk.dim(" 2. 使用 robot cache --clear 清除缓存"));
739
747
  console.log(chalk.dim(" 3. 重试: robot create --no-cache"));
748
+ console.log(chalk.dim(" 4. 检查仓库地址是否正确"));
740
749
  console.log();
741
750
  throw error;
742
751
  }
743
752
 
744
753
  // 3. 复制模板文件
745
- spinner.text = "复制项目文件...";
754
+ spinner.text = "📋 复制项目文件...";
746
755
  await copyTemplate(templatePath, projectPath);
747
756
 
748
757
  // 4. 处理项目配置
749
- spinner.text = "处理项目配置...";
758
+ spinner.text = "⚙️ 处理项目配置...";
750
759
  await processProjectConfig(
751
760
  projectPath,
752
761
  projectName,
@@ -756,13 +765,13 @@ async function executeCreation(projectName, template, projectConfig) {
756
765
 
757
766
  // 5. 初始化Git仓库
758
767
  if (projectConfig.initGit) {
759
- spinner.text = "初始化 Git 仓库...";
768
+ spinner.text = "📝 初始化 Git 仓库...";
760
769
  await initializeGitRepository(projectPath);
761
770
  }
762
771
 
763
772
  // 6. 安装依赖
764
773
  if (projectConfig.installDeps) {
765
- spinner.text = `使用 ${projectConfig.packageManager} 安装依赖...`;
774
+ spinner.text = `📦 使用 ${projectConfig.packageManager} 安装依赖...`;
766
775
  await installDependencies(
767
776
  projectPath,
768
777
  spinner,
@@ -771,7 +780,7 @@ async function executeCreation(projectName, template, projectConfig) {
771
780
  }
772
781
 
773
782
  // 7. 创建成功
774
- spinner.succeed("项目创建成功!");
783
+ spinner.succeed(chalk.green("🎉 项目创建成功!"));
775
784
 
776
785
  console.log();
777
786
  console.log(chalk.green("🎉 项目创建完成!"));
@@ -808,7 +817,10 @@ async function executeCreation(projectName, template, projectConfig) {
808
817
  console.log();
809
818
 
810
819
  // 显示项目统计
820
+ spinner.start("📊 统计项目信息...");
811
821
  const stats = await generateProjectStats(projectPath);
822
+ spinner.stop();
823
+
812
824
  if (stats) {
813
825
  printProjectStats(stats);
814
826
  console.log();
@@ -943,4 +955,4 @@ function getStartCommand(template) {
943
955
  };
944
956
 
945
957
  return startCommands[template.key] || "bun run dev";
946
- }
958
+ }
package/lib/download.js CHANGED
@@ -1,4 +1,4 @@
1
- // lib/download.js - 修复版本
1
+ // lib/download.js - 增强版本,添加详细进度显示
2
2
  import fs from 'fs-extra';
3
3
  import path from 'path';
4
4
  import os from 'os';
@@ -44,6 +44,9 @@ export async function downloadTemplate(template, options = {}) {
44
44
  // 验证缓存完整性
45
45
  const packageJsonPath = path.join(cachePath, 'package.json');
46
46
  if (fs.existsSync(packageJsonPath)) {
47
+ if (spinner) {
48
+ spinner.text = '✅ 缓存模板验证通过';
49
+ }
47
50
  return cachePath;
48
51
  } else {
49
52
  // 缓存损坏,删除重新下载
@@ -79,7 +82,7 @@ export async function downloadTemplate(template, options = {}) {
79
82
 
80
83
  // 下载远程模板
81
84
  if (spinner) {
82
- spinner.text = '📥 ' + template.repo + ' 下载最新模板...';
85
+ spinner.text = `🌐 连接到 GitHub (${template.repo})...`;
83
86
  }
84
87
 
85
88
  try {
@@ -87,25 +90,34 @@ export async function downloadTemplate(template, options = {}) {
87
90
  const tempZipPath = path.join(os.tmpdir(), cacheKey + '-' + Date.now() + '.zip');
88
91
  const tempExtractPath = path.join(os.tmpdir(), cacheKey + '-extract-' + Date.now());
89
92
 
90
- // 检查网络连接
93
+ // 检查网络连接和获取文件信息
91
94
  if (spinner) {
92
- spinner.text = '🌐 检查网络连接...';
95
+ spinner.text = `🔗 检查仓库 ${template.repo} 可用性...`;
93
96
  }
94
97
 
95
98
  // 下载zip文件
96
99
  const response = await fetch(downloadUrl, {
97
- timeout: 30000, // 30秒超时
100
+ timeout: 60000, // 60秒超时,给大文件更多时间
98
101
  headers: {
99
- 'User-Agent': 'Robot-CLI/1.0.0'
102
+ 'User-Agent': 'Robot-CLI/1.0.4'
100
103
  }
101
104
  });
102
105
 
103
106
  if (!response.ok) {
107
+ if (response.status === 404) {
108
+ throw new Error(`仓库不存在或私有: ${template.repo}\n请检查仓库地址是否正确且为公开仓库`);
109
+ }
104
110
  throw new Error(`HTTP ${response.status}: ${response.statusText}`);
105
111
  }
106
112
 
107
- if (spinner) {
108
- spinner.text = '📦 下载中...';
113
+ // 显示下载进度
114
+ const contentLength = response.headers.get('content-length');
115
+ if (spinner && contentLength) {
116
+ const totalSize = parseInt(contentLength);
117
+ const sizeInMB = (totalSize / 1024 / 1024).toFixed(1);
118
+ spinner.text = `📦 下载模板中... (${sizeInMB}MB)`;
119
+ } else if (spinner) {
120
+ spinner.text = '📦 下载模板中...';
109
121
  }
110
122
 
111
123
  const buffer = await response.buffer();
@@ -118,10 +130,14 @@ export async function downloadTemplate(template, options = {}) {
118
130
  // 解压文件
119
131
  await extract(tempZipPath, { dir: tempExtractPath });
120
132
 
133
+ if (spinner) {
134
+ spinner.text = '🔍 查找项目结构...';
135
+ }
136
+
121
137
  // 找到解压后的项目目录 (通常是 reponame-main/)
122
138
  const extractedItems = await fs.readdir(tempExtractPath);
123
139
  const projectDir = extractedItems.find(item =>
124
- item.endsWith('-main') || item.endsWith('-master')
140
+ item.endsWith('-main') || item.endsWith('-master') || item === template.repo.split('/')[1]
125
141
  );
126
142
 
127
143
  if (!projectDir) {
@@ -130,10 +146,28 @@ export async function downloadTemplate(template, options = {}) {
130
146
 
131
147
  const sourcePath = path.join(tempExtractPath, projectDir);
132
148
 
149
+ if (spinner) {
150
+ spinner.text = '✅ 验证模板完整性...';
151
+ }
152
+
133
153
  // 验证模板完整性
134
154
  const packageJsonPath = path.join(sourcePath, 'package.json');
135
155
  if (!fs.existsSync(packageJsonPath)) {
136
- throw new Error(`模板缺少 package.json 文件`);
156
+ throw new Error(`模板缺少 package.json 文件,这可能不是一个有效的项目模板`);
157
+ }
158
+
159
+ // 读取并验证 package.json
160
+ try {
161
+ const packageJson = await fs.readJson(packageJsonPath);
162
+ if (!packageJson.name) {
163
+ console.log(chalk.yellow('⚠️ 模板 package.json 缺少 name 字段'));
164
+ }
165
+ } catch (error) {
166
+ throw new Error(`package.json 格式错误: ${error.message}`);
167
+ }
168
+
169
+ if (spinner) {
170
+ spinner.text = '💾 保存到缓存...';
137
171
  }
138
172
 
139
173
  // 确保缓存目录存在
@@ -149,6 +183,10 @@ export async function downloadTemplate(template, options = {}) {
149
183
  await fs.remove(tempZipPath).catch(() => {});
150
184
  await fs.remove(tempExtractPath).catch(() => {});
151
185
 
186
+ if (spinner) {
187
+ spinner.text = '🎉 模板下载完成';
188
+ }
189
+
152
190
  return cachePath;
153
191
 
154
192
  } catch (error) {
package/lib/templates.js CHANGED
@@ -1,4 +1,4 @@
1
- // lib/templates.js - 统一Robot命名风格
1
+ // lib/templates.js - 统一Robot命名风格,移除测试标记
2
2
  export const TEMPLATE_CATEGORIES = {
3
3
  frontend: {
4
4
  name: '🎨 前端项目',
@@ -14,16 +14,14 @@ export const TEMPLATE_CATEGORIES = {
14
14
  description: '包含30+完整示例、权限管理、图表组件、最佳实践等等',
15
15
  repo: 'ChenyCHENYU/Robot_Admin',
16
16
  features: ['Naive UI', 'Vue Router', 'Pinia', '权限管理', '动态路由', '图表组件', '性能优化等等'],
17
- version: 'full',
18
- localTest: true // 标记为测试模板
17
+ version: 'full'
19
18
  },
20
19
  'robot-admin-base': {
21
20
  name: 'Robot Admin 精简版',
22
21
  description: '基础架构、核心功能、快速启动',
23
22
  repo: 'ChenyCHENYU/Robot_Admin_Base',
24
23
  features: ['Naive UI', 'Vue Router', 'Pinia', '基础布局'],
25
- version: 'base',
26
- localTest: true // 标记为测试模板
24
+ version: 'base'
27
25
  }
28
26
  }
29
27
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agile-team/robot-cli",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "🤖 现代化项目脚手架工具,支持多技术栈快速创建项目",
5
5
  "type": "module",
6
6
  "bin": {