@agile-team/robot-cli 2.3.0 → 3.0.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/CHANGELOG.md +44 -0
- package/dist/index.js +425 -557
- package/package.json +2 -3
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,50 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
7
7
|
|
|
8
|
+
## [3.0.1] - 2026-03-28
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- **下载策略全面重写** — 参考 giget (unjs/giget, 306k+ 项目使用) 的下载方式:
|
|
13
|
+
- Gitee 备用源提升为首选 (国内用户最快)
|
|
14
|
+
- 使用 `codeload.github.com` 直连 CDN 替代 `github.com/archive/` (跳过 302 重定向)
|
|
15
|
+
- 使用 `api.github.com` REST API 作为二级备选 (与 giget 一致)
|
|
16
|
+
- `github.com` 原始链接降为最后兜底
|
|
17
|
+
- **移除不稳定第三方镜像** — 移除 `hub.gitmirror.com` 和 `ghproxy.net` (不可控第三方代理)
|
|
18
|
+
- **超时优化** — 快速源 (Gitee/codeload) 30s, 慢速源 (API/github.com) 60s, 不再需要 120s
|
|
19
|
+
- **重试缩减** — 每源 2 次重试 (原 3 次), 退避时间 1s/2s (原 2s/4s), 快速失败切换下一源
|
|
20
|
+
- **错误信息增强** — 失败时列出每个源的具体错误原因
|
|
21
|
+
|
|
22
|
+
## [3.0.0] - 2026-03-28
|
|
23
|
+
|
|
24
|
+
### ⚠️ BREAKING CHANGES
|
|
25
|
+
|
|
26
|
+
- 交互界面从 `inquirer` 全面迁移至 `@clack/prompts`,视觉体验完全不同
|
|
27
|
+
- 移除 `inquirer` 和 `@types/inquirer` 依赖
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
|
|
31
|
+
- **@clack/prompts 现代化 UI**:使用 `p.select`、`p.text`、`p.confirm`、`p.note`、`p.intro`/`p.outro` 等,交互体验对齐 create-vue
|
|
32
|
+
- **Banner 框框展示**:双线框 `╔══╗` 样式包裹 ROBOT CLI 标题,信息分区更清晰
|
|
33
|
+
- **下载进度条**:基于 `content-length` 的流式进度条 `[████████░░░░] 40% 1.0MB/2.6MB`
|
|
34
|
+
- **Gitee 备用源**:模板配置新增 `giteeUrl` 字段,GitHub 不可达时自动切换 Gitee 下载
|
|
35
|
+
- robot-admin / monorepo / micro-app / module-federation → `gitee.com/ycyplus163/Robot_Admin`
|
|
36
|
+
- robot-uniapp → `gitee.com/ycyplus163/Robot_uniApp`
|
|
37
|
+
- **取消操作支持**:所有交互步骤支持 Ctrl+C 优雅退出 (`p.isCancel`)
|
|
38
|
+
|
|
39
|
+
### Changed
|
|
40
|
+
|
|
41
|
+
- 主菜单、模板选择、项目配置、确认创建等全部替换为 @clack/prompts 组件
|
|
42
|
+
- 项目创建完成信息使用 `p.note` 卡片式展示
|
|
43
|
+
- 分类浏览流程简化:自动跳过只有单一选项的层级
|
|
44
|
+
- 项目配置不再需要最后的"确认配置"步骤(逐项确认更自然)
|
|
45
|
+
- 构建产物从 ~63KB 减小至 ~59KB
|
|
46
|
+
|
|
47
|
+
### Removed
|
|
48
|
+
|
|
49
|
+
- `inquirer` 依赖及其 `@types/inquirer` 类型定义
|
|
50
|
+
- `getVersionLabel()` 辅助函数(改为内联 `VERSION_LABELS` 查找)
|
|
51
|
+
|
|
8
52
|
## [2.3.0] - 2026-03-28
|
|
9
53
|
|
|
10
54
|
### Fixed (Root-Cause)
|
package/dist/index.js
CHANGED
|
@@ -3,14 +3,14 @@ import { readFileSync } from "fs";
|
|
|
3
3
|
import { fileURLToPath } from "url";
|
|
4
4
|
import { dirname, join } from "path";
|
|
5
5
|
import chalk5 from "chalk";
|
|
6
|
-
import
|
|
6
|
+
import * as p2 from "@clack/prompts";
|
|
7
7
|
import { Command } from "commander";
|
|
8
8
|
|
|
9
9
|
// src/create.ts
|
|
10
10
|
import fs3 from "fs-extra";
|
|
11
11
|
import path3 from "path";
|
|
12
12
|
import chalk3 from "chalk";
|
|
13
|
-
import
|
|
13
|
+
import * as p from "@clack/prompts";
|
|
14
14
|
import ora from "ora";
|
|
15
15
|
import { execSync as execSync2 } from "child_process";
|
|
16
16
|
|
|
@@ -36,6 +36,7 @@ var TEMPLATE_CATEGORIES = {
|
|
|
36
36
|
name: "Robot Admin \u5B8C\u6574\u7248",
|
|
37
37
|
description: "\u5305\u542B50+\u5B8C\u6574\u793A\u4F8B\u3001\u6743\u9650\u7BA1\u7406\u3001\u56FE\u8868\u7EC4\u4EF6\u3001\u6700\u4F73\u5B9E\u8DF5\u7B49\u7B49",
|
|
38
38
|
repoUrl: "https://github.com/ChenyCHENYU/Robot_Admin",
|
|
39
|
+
giteeUrl: "https://gitee.com/ycyplus163/Robot_Admin",
|
|
39
40
|
features: [
|
|
40
41
|
"Naive UI",
|
|
41
42
|
"Vue Router",
|
|
@@ -63,6 +64,7 @@ var TEMPLATE_CATEGORIES = {
|
|
|
63
64
|
name: "Robot Monorepo",
|
|
64
65
|
description: "bun workspace + Monorepo \u591A\u5305\u7BA1\u7406\u67B6\u6784",
|
|
65
66
|
repoUrl: "https://github.com/ChenyCHENYU/Robot_Admin",
|
|
67
|
+
giteeUrl: "https://gitee.com/ycyplus163/Robot_Admin",
|
|
66
68
|
branch: "monorepo",
|
|
67
69
|
features: ["bun workspace", "Monorepo", "\u591A\u5305\u7BA1\u7406", "\u5171\u4EAB\u7EC4\u4EF6"],
|
|
68
70
|
version: "full"
|
|
@@ -76,6 +78,7 @@ var TEMPLATE_CATEGORIES = {
|
|
|
76
78
|
name: "Robot MicroApp \u5FAE\u524D\u7AEF",
|
|
77
79
|
description: "\u57FA\u4E8E MicroApp \u7684\u5FAE\u524D\u7AEF\u67B6\u6784\u65B9\u6848",
|
|
78
80
|
repoUrl: "https://github.com/ChenyCHENYU/Robot_Admin",
|
|
81
|
+
giteeUrl: "https://gitee.com/ycyplus163/Robot_Admin",
|
|
79
82
|
branch: "micro-app",
|
|
80
83
|
features: ["MicroApp", "\u5FAE\u524D\u7AEF", "\u4E3B\u5B50\u5E94\u7528", "\u8DEF\u7531\u5171\u4EAB"],
|
|
81
84
|
version: "full"
|
|
@@ -84,6 +87,7 @@ var TEMPLATE_CATEGORIES = {
|
|
|
84
87
|
name: "Robot Module Federation \u6A21\u5757\u8054\u90A6",
|
|
85
88
|
description: "\u57FA\u4E8E Vite Module Federation \u7684\u6A21\u5757\u8054\u90A6\u65B9\u6848",
|
|
86
89
|
repoUrl: "https://github.com/ChenyCHENYU/Robot_Admin",
|
|
90
|
+
giteeUrl: "https://gitee.com/ycyplus163/Robot_Admin",
|
|
87
91
|
branch: "module-federation",
|
|
88
92
|
features: ["Module Federation", "\u6A21\u5757\u8054\u90A6", "Vite", "\u8FDC\u7A0B\u6A21\u5757"],
|
|
89
93
|
version: "full"
|
|
@@ -131,6 +135,7 @@ var TEMPLATE_CATEGORIES = {
|
|
|
131
135
|
name: "Robot uni-app \u5B8C\u6574\u7248",
|
|
132
136
|
description: "\u591A\u7AEF\u9002\u914D + \u63D2\u4EF6\u5E02\u573A + \u5B8C\u6574\u793A\u4F8B",
|
|
133
137
|
repoUrl: "https://github.com/ChenyCHENYU/Robot_Uniapp",
|
|
138
|
+
giteeUrl: "https://gitee.com/ycyplus163/Robot_uniApp",
|
|
134
139
|
features: ["\u591A\u7AEF\u53D1\u5E03", "uView UI", "\u63D2\u4EF6\u96C6\u6210"],
|
|
135
140
|
version: "full"
|
|
136
141
|
},
|
|
@@ -261,12 +266,29 @@ var START_COMMAND_MAP = {
|
|
|
261
266
|
// src/download.ts
|
|
262
267
|
var CACHE_DIR = path.join(os.homedir(), ".robot-cli", CACHE_DIR_NAME);
|
|
263
268
|
var CACHE_INDEX_PATH = path.join(CACHE_DIR, "index.json");
|
|
269
|
+
function parseGitHubRepo(repoUrl) {
|
|
270
|
+
try {
|
|
271
|
+
const url = new URL(repoUrl);
|
|
272
|
+
if (url.hostname !== "github.com") return null;
|
|
273
|
+
const parts = url.pathname.replace(/^\/|\/$/g, "").split("/");
|
|
274
|
+
if (parts.length >= 2) return { owner: parts[0], repo: parts[1] };
|
|
275
|
+
return null;
|
|
276
|
+
} catch {
|
|
277
|
+
return null;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
264
280
|
function buildDownloadUrl(repoUrl, branch = "main") {
|
|
265
281
|
try {
|
|
266
282
|
const url = new URL(repoUrl);
|
|
267
283
|
const host = url.hostname;
|
|
268
284
|
const cleanUrl = repoUrl.replace(/\/+$/, "");
|
|
269
|
-
if (host === "github.com")
|
|
285
|
+
if (host === "github.com") {
|
|
286
|
+
const gh = parseGitHubRepo(cleanUrl);
|
|
287
|
+
if (gh) return `https://codeload.github.com/${gh.owner}/${gh.repo}/zip/refs/heads/${branch}`;
|
|
288
|
+
return `${cleanUrl}/archive/refs/heads/${branch}.zip`;
|
|
289
|
+
}
|
|
290
|
+
if (host === "codeload.github.com") return `${cleanUrl}/zip/refs/heads/${branch}`;
|
|
291
|
+
if (host === "api.github.com") return cleanUrl;
|
|
270
292
|
if (host === "gitee.com")
|
|
271
293
|
return `${cleanUrl}/repository/archive/${branch}.zip`;
|
|
272
294
|
if (host === "gitlab.com") {
|
|
@@ -338,26 +360,61 @@ async function getCacheStats() {
|
|
|
338
360
|
async function clearCache() {
|
|
339
361
|
await fs.remove(CACHE_DIR);
|
|
340
362
|
}
|
|
341
|
-
var
|
|
342
|
-
var
|
|
343
|
-
var MAX_RETRIES =
|
|
344
|
-
function
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
363
|
+
var TIMEOUT_FAST = 3e4;
|
|
364
|
+
var TIMEOUT_SLOW = 6e4;
|
|
365
|
+
var MAX_RETRIES = 2;
|
|
366
|
+
function buildDownloadSources(repoUrl, branch, giteeUrl) {
|
|
367
|
+
const sources = [];
|
|
368
|
+
const gh = parseGitHubRepo(repoUrl);
|
|
369
|
+
if (giteeUrl) {
|
|
370
|
+
sources.push({
|
|
371
|
+
url: giteeUrl,
|
|
372
|
+
name: "gitee.com",
|
|
373
|
+
timeout: TIMEOUT_FAST
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
if (gh) {
|
|
377
|
+
sources.push({
|
|
378
|
+
url: `https://codeload.github.com/${gh.owner}/${gh.repo}/zip/refs/heads/${branch}`,
|
|
379
|
+
name: "codeload.github.com",
|
|
380
|
+
timeout: TIMEOUT_FAST,
|
|
381
|
+
isDirect: true
|
|
382
|
+
});
|
|
383
|
+
sources.push({
|
|
384
|
+
url: `https://api.github.com/repos/${gh.owner}/${gh.repo}/zipball/${branch}`,
|
|
385
|
+
name: "api.github.com",
|
|
386
|
+
timeout: TIMEOUT_SLOW,
|
|
387
|
+
isDirect: true,
|
|
388
|
+
headers: {
|
|
389
|
+
Accept: "application/vnd.github+json",
|
|
390
|
+
"X-GitHub-Api-Version": "2022-11-28"
|
|
391
|
+
}
|
|
392
|
+
});
|
|
393
|
+
sources.push({
|
|
394
|
+
url: repoUrl,
|
|
395
|
+
name: "github.com",
|
|
396
|
+
timeout: TIMEOUT_SLOW
|
|
397
|
+
});
|
|
398
|
+
} else {
|
|
399
|
+
sources.push({
|
|
400
|
+
url: repoUrl,
|
|
401
|
+
name: new URL(repoUrl).hostname,
|
|
402
|
+
timeout: TIMEOUT_SLOW
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
return sources;
|
|
353
406
|
}
|
|
354
|
-
async function fetchWithRetry(downloadUrl, timeout, retries) {
|
|
407
|
+
async function fetchWithRetry(downloadUrl, timeout, retries, extraHeaders) {
|
|
355
408
|
let lastError;
|
|
356
409
|
for (let attempt = 1; attempt <= retries; attempt++) {
|
|
357
410
|
try {
|
|
358
411
|
const response = await fetch(downloadUrl, {
|
|
359
412
|
signal: AbortSignal.timeout(timeout),
|
|
360
|
-
|
|
413
|
+
redirect: "follow",
|
|
414
|
+
headers: {
|
|
415
|
+
"User-Agent": "Robot-CLI/3.0",
|
|
416
|
+
...extraHeaders
|
|
417
|
+
}
|
|
361
418
|
});
|
|
362
419
|
if (!response.ok) {
|
|
363
420
|
if (response.status === 404) throw new Error(`\u4ED3\u5E93\u4E0D\u5B58\u5728 (404)`);
|
|
@@ -368,48 +425,51 @@ async function fetchWithRetry(downloadUrl, timeout, retries) {
|
|
|
368
425
|
lastError = error;
|
|
369
426
|
if (lastError.message.includes("404")) throw lastError;
|
|
370
427
|
if (attempt < retries) {
|
|
371
|
-
await new Promise((r) => setTimeout(r,
|
|
428
|
+
await new Promise((r) => setTimeout(r, 1e3 * attempt));
|
|
372
429
|
}
|
|
373
430
|
}
|
|
374
431
|
}
|
|
375
432
|
throw lastError;
|
|
376
433
|
}
|
|
377
|
-
async function tryDownload(repoUrl, branch = "main", spinner) {
|
|
378
|
-
const
|
|
379
|
-
const
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
const current = mirrors[i];
|
|
383
|
-
const isOriginal = i === 0;
|
|
384
|
-
let sourceName;
|
|
385
|
-
try {
|
|
386
|
-
sourceName = isOriginal ? host : new URL(current.replace(/^(https?:\/\/[^/]+)\/.*/, "$1")).hostname;
|
|
387
|
-
} catch {
|
|
388
|
-
sourceName = `\u955C\u50CF ${i}`;
|
|
389
|
-
}
|
|
434
|
+
async function tryDownload(repoUrl, branch = "main", spinner, giteeUrl) {
|
|
435
|
+
const sources = buildDownloadSources(repoUrl, branch, giteeUrl);
|
|
436
|
+
const errors = [];
|
|
437
|
+
for (let i = 0; i < sources.length; i++) {
|
|
438
|
+
const source = sources[i];
|
|
390
439
|
try {
|
|
391
|
-
if (spinner) spinner.text = `\u8FDE\u63A5 ${
|
|
392
|
-
const downloadUrl =
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
440
|
+
if (spinner) spinner.text = `\u8FDE\u63A5 ${source.name} ...`;
|
|
441
|
+
const downloadUrl = source.isDirect ? source.url : buildDownloadUrl(source.url, branch);
|
|
442
|
+
if (spinner) spinner.text = `\u4ECE ${source.name} \u4E0B\u8F7D\u6A21\u677F...`;
|
|
443
|
+
const response = await fetchWithRetry(
|
|
444
|
+
downloadUrl,
|
|
445
|
+
source.timeout,
|
|
446
|
+
MAX_RETRIES,
|
|
447
|
+
source.headers
|
|
448
|
+
);
|
|
396
449
|
if (spinner) {
|
|
397
450
|
const len = response.headers.get("content-length");
|
|
398
451
|
const sizeInfo = len ? `${(parseInt(len) / 1024 / 1024).toFixed(1)}MB ` : "";
|
|
399
|
-
spinner.text = `\u4E0B\u8F7D\u4E2D ${sizeInfo}(${
|
|
452
|
+
spinner.text = `\u4E0B\u8F7D\u4E2D ${sizeInfo}(${source.name})`;
|
|
400
453
|
}
|
|
401
|
-
return { response, sourceName };
|
|
454
|
+
return { response, sourceName: source.name };
|
|
402
455
|
} catch (error) {
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
456
|
+
const errMsg = error.message || String(error);
|
|
457
|
+
errors.push(`${source.name}: ${errMsg}`);
|
|
458
|
+
if (i < sources.length - 1 && spinner) {
|
|
459
|
+
spinner.text = `${source.name} \u4E0D\u53EF\u7528\uFF0C\u5207\u6362\u5230 ${sources[i + 1].name}...`;
|
|
460
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
461
|
+
}
|
|
406
462
|
}
|
|
407
463
|
}
|
|
408
|
-
throw new Error(
|
|
464
|
+
throw new Error(
|
|
465
|
+
`\u6240\u6709\u4E0B\u8F7D\u6E90\u5747\u4E0D\u53EF\u7528:
|
|
466
|
+
${errors.map((e) => ` - ${e}`).join("\n")}`
|
|
467
|
+
);
|
|
409
468
|
}
|
|
410
469
|
async function downloadTemplate(template, options = {}) {
|
|
411
|
-
const { spinner, noCache } = options;
|
|
470
|
+
const { spinner, noCache, giteeUrl: optGiteeUrl } = options;
|
|
412
471
|
const branch = template.branch || "main";
|
|
472
|
+
const giteeUrl = optGiteeUrl || template.giteeUrl;
|
|
413
473
|
if (!template?.repoUrl) {
|
|
414
474
|
throw new Error(`\u6A21\u677F\u914D\u7F6E\u65E0\u6548: ${JSON.stringify(template)}`);
|
|
415
475
|
}
|
|
@@ -418,14 +478,37 @@ async function downloadTemplate(template, options = {}) {
|
|
|
418
478
|
const { response, sourceName } = await tryDownload(
|
|
419
479
|
template.repoUrl,
|
|
420
480
|
branch,
|
|
421
|
-
spinner
|
|
481
|
+
spinner,
|
|
482
|
+
giteeUrl
|
|
422
483
|
);
|
|
423
484
|
if (spinner) spinner.text = "\u4FDD\u5B58\u4E0B\u8F7D\u6587\u4EF6...";
|
|
424
485
|
const timestamp = Date.now();
|
|
425
486
|
const tempZip = path.join(os.tmpdir(), `robot-template-${timestamp}.zip`);
|
|
426
487
|
const tempExtract = path.join(os.tmpdir(), `robot-extract-${timestamp}`);
|
|
427
|
-
const
|
|
428
|
-
|
|
488
|
+
const contentLength = response.headers.get("content-length");
|
|
489
|
+
const totalSize = contentLength ? parseInt(contentLength, 10) : 0;
|
|
490
|
+
if (totalSize > 0 && response.body && spinner) {
|
|
491
|
+
const reader = response.body.getReader();
|
|
492
|
+
const chunks = [];
|
|
493
|
+
let received = 0;
|
|
494
|
+
while (true) {
|
|
495
|
+
const { done, value } = await reader.read();
|
|
496
|
+
if (done) break;
|
|
497
|
+
chunks.push(value);
|
|
498
|
+
received += value.length;
|
|
499
|
+
const pct = Math.round(received / totalSize * 100);
|
|
500
|
+
const filled = Math.round(pct / 5);
|
|
501
|
+
const bar = "\u2588".repeat(filled) + "\u2591".repeat(20 - filled);
|
|
502
|
+
const sizeMB = (received / 1024 / 1024).toFixed(1);
|
|
503
|
+
const totalMB = (totalSize / 1024 / 1024).toFixed(1);
|
|
504
|
+
spinner.text = `\u4E0B\u8F7D\u4E2D [${bar}] ${pct}% ${sizeMB}MB/${totalMB}MB (${sourceName})`;
|
|
505
|
+
}
|
|
506
|
+
const buffer = Buffer.concat(chunks);
|
|
507
|
+
await fs.writeFile(tempZip, buffer);
|
|
508
|
+
} else {
|
|
509
|
+
const buffer = Buffer.from(await response.arrayBuffer());
|
|
510
|
+
await fs.writeFile(tempZip, buffer);
|
|
511
|
+
}
|
|
429
512
|
if (spinner) spinner.text = "\u89E3\u538B\u6A21\u677F\u6587\u4EF6...";
|
|
430
513
|
await extract(tempZip, { dir: tempExtract });
|
|
431
514
|
if (spinner) spinner.text = "\u67E5\u627E\u9879\u76EE\u7ED3\u6784...";
|
|
@@ -778,17 +861,9 @@ function formatBytes(bytes) {
|
|
|
778
861
|
}
|
|
779
862
|
|
|
780
863
|
// src/create.ts
|
|
781
|
-
function getVersionLabel(version) {
|
|
782
|
-
const label = VERSION_LABELS[version] || version;
|
|
783
|
-
if (version === "full") return chalk3.green(`[${label}]`);
|
|
784
|
-
if (version === "micro") return chalk3.blue(`[${label}]`);
|
|
785
|
-
return chalk3.yellow(`[${label}]`);
|
|
786
|
-
}
|
|
787
864
|
var STRIP_VERSION_RE = /\s*(完整版|精简版|微服务版)\s*$/;
|
|
788
865
|
async function createProject(projectName, options = {}) {
|
|
789
|
-
|
|
790
|
-
console.log(chalk3.cyan(" Robot CLI - \u5F00\u59CB\u521B\u5EFA\u9879\u76EE"));
|
|
791
|
-
console.log();
|
|
866
|
+
p.intro(chalk3.bgCyan.black(" Robot CLI - \u5F00\u59CB\u521B\u5EFA\u9879\u76EE "));
|
|
792
867
|
let template;
|
|
793
868
|
if (options.from) {
|
|
794
869
|
template = {
|
|
@@ -842,38 +917,33 @@ async function handleProjectName(projectName, template) {
|
|
|
842
917
|
if (projectName) {
|
|
843
918
|
const v = validateProjectName(projectName);
|
|
844
919
|
if (!v.valid) {
|
|
845
|
-
|
|
846
|
-
v.errors.forEach((e) =>
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
{
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
validate: (input) => {
|
|
854
|
-
const r = validateProjectName(input);
|
|
855
|
-
return r.valid || r.errors[0];
|
|
856
|
-
}
|
|
920
|
+
p.log.error("\u9879\u76EE\u540D\u79F0\u4E0D\u5408\u6CD5:");
|
|
921
|
+
v.errors.forEach((e) => p.log.warn(` ${e}`));
|
|
922
|
+
const newName = await p.text({
|
|
923
|
+
message: "\u8BF7\u8F93\u5165\u65B0\u7684\u9879\u76EE\u540D\u79F0:",
|
|
924
|
+
validate: (input) => {
|
|
925
|
+
if (!input) return "\u9879\u76EE\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A";
|
|
926
|
+
const r = validateProjectName(input);
|
|
927
|
+
return r.valid ? void 0 : r.errors[0];
|
|
857
928
|
}
|
|
858
|
-
|
|
929
|
+
});
|
|
930
|
+
if (p.isCancel(newName)) process.exit(0);
|
|
859
931
|
return newName;
|
|
860
932
|
}
|
|
861
933
|
return projectName;
|
|
862
934
|
}
|
|
863
935
|
const defaultName = generateDefaultProjectName(template);
|
|
864
|
-
const
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
const r = validateProjectName(input);
|
|
873
|
-
return r.valid || r.errors[0];
|
|
874
|
-
}
|
|
936
|
+
const name = await p.text({
|
|
937
|
+
message: "\u8BF7\u8F93\u5165\u9879\u76EE\u540D\u79F0:",
|
|
938
|
+
defaultValue: defaultName,
|
|
939
|
+
placeholder: defaultName,
|
|
940
|
+
validate: (input) => {
|
|
941
|
+
if (!input?.trim()) return "\u9879\u76EE\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A";
|
|
942
|
+
const r = validateProjectName(input);
|
|
943
|
+
return r.valid ? void 0 : r.errors[0];
|
|
875
944
|
}
|
|
876
|
-
|
|
945
|
+
});
|
|
946
|
+
if (p.isCancel(name)) process.exit(0);
|
|
877
947
|
return name;
|
|
878
948
|
}
|
|
879
949
|
function generateDefaultProjectName(template) {
|
|
@@ -894,36 +964,16 @@ async function selectTemplate(templateOption) {
|
|
|
894
964
|
return await selectTemplateMethod();
|
|
895
965
|
}
|
|
896
966
|
async function selectTemplateMethod() {
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
{
|
|
908
|
-
name: `${chalk3.cyan(">")} ${chalk3.bold("\u63A8\u8350\u6A21\u677F")} ${chalk3.dim("\u2014 \u57FA\u4E8E\u56E2\u961F\u4F7F\u7528\u9891\u7387\u63A8\u8350\u7684\u70ED\u95E8\u6A21\u677F")}`,
|
|
909
|
-
value: "recommended"
|
|
910
|
-
},
|
|
911
|
-
{
|
|
912
|
-
name: `${chalk3.cyan(">")} ${chalk3.bold("\u5206\u7C7B\u6D4F\u89C8")} ${chalk3.dim("\u2014 \u524D\u7AEF\u3001\u540E\u7AEF\u3001\u79FB\u52A8\u7AEF\u3001\u684C\u9762\u7AEF\u5206\u7C7B")}`,
|
|
913
|
-
value: "category"
|
|
914
|
-
},
|
|
915
|
-
{
|
|
916
|
-
name: `${chalk3.cyan(">")} ${chalk3.bold("\u5173\u952E\u8BCD\u641C\u7D22")} ${chalk3.dim("\u2014 \u6309\u6280\u672F\u6808\u3001\u529F\u80FD\u7279\u6027\u67E5\u627E")}`,
|
|
917
|
-
value: "search"
|
|
918
|
-
},
|
|
919
|
-
{
|
|
920
|
-
name: `${chalk3.cyan(">")} ${chalk3.bold("\u5168\u90E8\u6A21\u677F")} ${chalk3.dim("\u2014 \u67E5\u770B\u6240\u6709\u53EF\u7528\u6A21\u677F")}`,
|
|
921
|
-
value: "all"
|
|
922
|
-
}
|
|
923
|
-
],
|
|
924
|
-
pageSize: 10
|
|
925
|
-
}
|
|
926
|
-
]);
|
|
967
|
+
const selectionMode = await p.select({
|
|
968
|
+
message: "\u6A21\u677F\u9009\u62E9\u65B9\u5F0F:",
|
|
969
|
+
options: [
|
|
970
|
+
{ value: "recommended", label: "\u63A8\u8350\u6A21\u677F", hint: "\u57FA\u4E8E\u56E2\u961F\u4F7F\u7528\u9891\u7387\u63A8\u8350\u7684\u70ED\u95E8\u6A21\u677F" },
|
|
971
|
+
{ value: "category", label: "\u5206\u7C7B\u6D4F\u89C8", hint: "\u524D\u7AEF\u3001\u540E\u7AEF\u3001\u79FB\u52A8\u7AEF\u3001\u684C\u9762\u7AEF\u5206\u7C7B" },
|
|
972
|
+
{ value: "search", label: "\u5173\u952E\u8BCD\u641C\u7D22", hint: "\u6309\u6280\u672F\u6808\u3001\u529F\u80FD\u7279\u6027\u67E5\u627E" },
|
|
973
|
+
{ value: "all", label: "\u5168\u90E8\u6A21\u677F", hint: "\u67E5\u770B\u6240\u6709\u53EF\u7528\u6A21\u677F" }
|
|
974
|
+
]
|
|
975
|
+
});
|
|
976
|
+
if (p.isCancel(selectionMode)) process.exit(0);
|
|
927
977
|
switch (selectionMode) {
|
|
928
978
|
case "recommended":
|
|
929
979
|
return await selectFromRecommended();
|
|
@@ -940,400 +990,258 @@ async function selectTemplateMethod() {
|
|
|
940
990
|
async function selectFromRecommended() {
|
|
941
991
|
const recommended = getRecommendedTemplates();
|
|
942
992
|
if (Object.keys(recommended).length === 0) {
|
|
943
|
-
|
|
993
|
+
p.log.warn("\u6682\u65E0\u63A8\u8350\u6A21\u677F");
|
|
944
994
|
return await selectTemplateMethod();
|
|
945
995
|
}
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
choices.push({
|
|
956
|
-
name: `${chalk3.bold.white(template.name.replace(STRIP_VERSION_RE, ""))} ${ver} - ${chalk3.dim(template.description)}
|
|
957
|
-
${tags}${template.features.length > 3 ? chalk3.dim(` +${template.features.length - 3}more`) : ""}`,
|
|
958
|
-
value: { key, ...template },
|
|
959
|
-
short: template.name
|
|
996
|
+
p.log.info(chalk3.bold("\u63A8\u8350\u6A21\u677F") + chalk3.dim(" \u2014 \u57FA\u4E8E\u56E2\u961F\u4F7F\u7528\u9891\u7387\u548C\u9879\u76EE\u6210\u719F\u5EA6\u63A8\u8350"));
|
|
997
|
+
const options = [];
|
|
998
|
+
for (const [key, template] of Object.entries(recommended)) {
|
|
999
|
+
const ver = VERSION_LABELS[template.version] || template.version;
|
|
1000
|
+
const tags = template.features.slice(0, 3).join(", ");
|
|
1001
|
+
options.push({
|
|
1002
|
+
value: key,
|
|
1003
|
+
label: `${template.name.replace(STRIP_VERSION_RE, "")} [${ver}]`,
|
|
1004
|
+
hint: `${template.description} | ${tags}`
|
|
960
1005
|
});
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
});
|
|
967
|
-
}
|
|
1006
|
+
}
|
|
1007
|
+
options.push({ value: "back", label: "<- \u8FD4\u56DE\u9009\u62E9\u5176\u4ED6\u65B9\u5F0F" });
|
|
1008
|
+
const selected = await p.select({
|
|
1009
|
+
message: "\u9009\u62E9\u63A8\u8350\u6A21\u677F:",
|
|
1010
|
+
options
|
|
968
1011
|
});
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
name: "selectedTemplate",
|
|
974
|
-
message: "\u9009\u62E9\u63A8\u8350\u6A21\u677F:",
|
|
975
|
-
choices,
|
|
976
|
-
pageSize: 15,
|
|
977
|
-
loop: false
|
|
978
|
-
}
|
|
979
|
-
]);
|
|
980
|
-
if (selectedTemplate === "back") return await selectTemplateMethod();
|
|
981
|
-
return selectedTemplate;
|
|
1012
|
+
if (p.isCancel(selected)) process.exit(0);
|
|
1013
|
+
if (selected === "back") return await selectTemplateMethod();
|
|
1014
|
+
const t = recommended[selected];
|
|
1015
|
+
return { key: selected, ...t };
|
|
982
1016
|
}
|
|
983
1017
|
async function selectByCategory() {
|
|
984
1018
|
while (true) {
|
|
985
|
-
const
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
const
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
if (
|
|
995
|
-
return
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
const choices = Object.entries(category.stacks).map(([key, s]) => ({
|
|
1015
|
-
name: s.name,
|
|
1016
|
-
value: key
|
|
1017
|
-
}));
|
|
1018
|
-
choices.push(
|
|
1019
|
-
{
|
|
1020
|
-
name: chalk3.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),
|
|
1021
|
-
value: "separator",
|
|
1022
|
-
disabled: true
|
|
1023
|
-
},
|
|
1024
|
-
{ name: chalk3.dim("\u2190 \u8FD4\u56DE\u9879\u76EE\u7C7B\u578B\u9009\u62E9"), value: "back_to_category" },
|
|
1025
|
-
{ name: chalk3.dim("\u2190 \u8FD4\u56DE\u6A21\u677F\u9009\u62E9\u65B9\u5F0F"), value: "back_to_method" }
|
|
1026
|
-
);
|
|
1027
|
-
if (choices.length === 4) return choices[0].value;
|
|
1028
|
-
const { stackKey } = await inquirer.prompt([
|
|
1029
|
-
{ type: "list", name: "stackKey", message: "\u8BF7\u9009\u62E9\u6280\u672F\u6808:", choices }
|
|
1030
|
-
]);
|
|
1031
|
-
return stackKey;
|
|
1032
|
-
}
|
|
1033
|
-
async function selectPattern(catKey, stackKey) {
|
|
1034
|
-
if (["back_to_category", "back_to_method"].includes(stackKey))
|
|
1035
|
-
return stackKey;
|
|
1036
|
-
const stack = TEMPLATE_CATEGORIES[catKey].stacks[stackKey];
|
|
1037
|
-
const choices = Object.entries(stack.patterns).map(([key, p]) => ({
|
|
1038
|
-
name: p.name,
|
|
1039
|
-
value: key
|
|
1040
|
-
}));
|
|
1041
|
-
choices.push(
|
|
1042
|
-
{
|
|
1043
|
-
name: chalk3.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),
|
|
1044
|
-
value: "separator",
|
|
1045
|
-
disabled: true
|
|
1046
|
-
},
|
|
1047
|
-
{ name: chalk3.dim("\u2190 \u8FD4\u56DE\u6280\u672F\u6808\u9009\u62E9"), value: "back_to_stack" },
|
|
1048
|
-
{ name: chalk3.dim("\u2190 \u8FD4\u56DE\u9879\u76EE\u7C7B\u578B\u9009\u62E9"), value: "back_to_category" },
|
|
1049
|
-
{ name: chalk3.dim("\u2190 \u8FD4\u56DE\u6A21\u677F\u9009\u62E9\u65B9\u5F0F"), value: "back_to_method" }
|
|
1050
|
-
);
|
|
1051
|
-
if (choices.length === 5) return choices[0].value;
|
|
1052
|
-
const { patternKey } = await inquirer.prompt([
|
|
1053
|
-
{ type: "list", name: "patternKey", message: "\u8BF7\u9009\u62E9\u67B6\u6784\u6A21\u5F0F:", choices }
|
|
1054
|
-
]);
|
|
1055
|
-
return patternKey;
|
|
1056
|
-
}
|
|
1057
|
-
async function selectSpecificTemplate(catKey, stackKey, patternKey) {
|
|
1058
|
-
if (["back_to_stack", "back_to_category", "back_to_method"].includes(patternKey)) {
|
|
1059
|
-
return patternKey;
|
|
1060
|
-
}
|
|
1061
|
-
const templates = getTemplatesByCategory(catKey, stackKey, patternKey);
|
|
1062
|
-
const choices = Object.entries(templates).map(([key, t]) => ({
|
|
1063
|
-
name: `${t.name} - ${chalk3.dim(t.description)}`,
|
|
1064
|
-
value: { key, ...t },
|
|
1065
|
-
short: t.name
|
|
1066
|
-
}));
|
|
1067
|
-
choices.push(
|
|
1068
|
-
{
|
|
1069
|
-
name: chalk3.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),
|
|
1070
|
-
value: "separator",
|
|
1071
|
-
disabled: true
|
|
1072
|
-
},
|
|
1073
|
-
{ name: chalk3.dim("\u2190 \u8FD4\u56DE\u67B6\u6784\u6A21\u5F0F\u9009\u62E9"), value: "back_to_pattern" },
|
|
1074
|
-
{ name: chalk3.dim("\u2190 \u8FD4\u56DE\u6280\u672F\u6808\u9009\u62E9"), value: "back_to_stack" },
|
|
1075
|
-
{ name: chalk3.dim("\u2190 \u8FD4\u56DE\u9879\u76EE\u7C7B\u578B\u9009\u62E9"), value: "back_to_category" },
|
|
1076
|
-
{ name: chalk3.dim("\u2190 \u8FD4\u56DE\u6A21\u677F\u9009\u62E9\u65B9\u5F0F"), value: "back_to_method" }
|
|
1077
|
-
);
|
|
1078
|
-
const { selectedTemplate } = await inquirer.prompt([
|
|
1079
|
-
{
|
|
1080
|
-
type: "list",
|
|
1081
|
-
name: "selectedTemplate",
|
|
1082
|
-
message: "\u8BF7\u9009\u62E9\u6A21\u677F\u7248\u672C:",
|
|
1083
|
-
choices
|
|
1019
|
+
const catOptions = Object.entries(TEMPLATE_CATEGORIES).map(([key, c]) => ({
|
|
1020
|
+
value: key,
|
|
1021
|
+
label: c.name
|
|
1022
|
+
}));
|
|
1023
|
+
catOptions.push({ value: "back_to_method", label: "<- \u8FD4\u56DE\u6A21\u677F\u9009\u62E9\u65B9\u5F0F" });
|
|
1024
|
+
const catKey = await p.select({
|
|
1025
|
+
message: "\u8BF7\u9009\u62E9\u9879\u76EE\u7C7B\u578B:",
|
|
1026
|
+
options: catOptions
|
|
1027
|
+
});
|
|
1028
|
+
if (p.isCancel(catKey)) process.exit(0);
|
|
1029
|
+
if (catKey === "back_to_method") return await selectTemplateMethod();
|
|
1030
|
+
const category = TEMPLATE_CATEGORIES[catKey];
|
|
1031
|
+
const stackEntries = Object.entries(category.stacks);
|
|
1032
|
+
let stackKey;
|
|
1033
|
+
if (stackEntries.length === 1) {
|
|
1034
|
+
stackKey = stackEntries[0][0];
|
|
1035
|
+
} else {
|
|
1036
|
+
const stackOptions = stackEntries.map(([key, s]) => ({
|
|
1037
|
+
value: key,
|
|
1038
|
+
label: s.name
|
|
1039
|
+
}));
|
|
1040
|
+
stackOptions.push({ value: "back", label: "<- \u8FD4\u56DE" });
|
|
1041
|
+
const sk = await p.select({
|
|
1042
|
+
message: "\u8BF7\u9009\u62E9\u6280\u672F\u6808:",
|
|
1043
|
+
options: stackOptions
|
|
1044
|
+
});
|
|
1045
|
+
if (p.isCancel(sk)) process.exit(0);
|
|
1046
|
+
if (sk === "back") continue;
|
|
1047
|
+
stackKey = sk;
|
|
1084
1048
|
}
|
|
1085
|
-
|
|
1086
|
-
|
|
1049
|
+
const stack = category.stacks[stackKey];
|
|
1050
|
+
const patternEntries = Object.entries(stack.patterns);
|
|
1051
|
+
let patternKey;
|
|
1052
|
+
if (patternEntries.length === 1) {
|
|
1053
|
+
patternKey = patternEntries[0][0];
|
|
1054
|
+
} else {
|
|
1055
|
+
const patternOptions = patternEntries.map(([key, pt]) => ({
|
|
1056
|
+
value: key,
|
|
1057
|
+
label: pt.name
|
|
1058
|
+
}));
|
|
1059
|
+
patternOptions.push({ value: "back", label: "<- \u8FD4\u56DE" });
|
|
1060
|
+
const pk = await p.select({
|
|
1061
|
+
message: "\u8BF7\u9009\u62E9\u67B6\u6784\u6A21\u5F0F:",
|
|
1062
|
+
options: patternOptions
|
|
1063
|
+
});
|
|
1064
|
+
if (p.isCancel(pk)) process.exit(0);
|
|
1065
|
+
if (pk === "back") continue;
|
|
1066
|
+
patternKey = pk;
|
|
1067
|
+
}
|
|
1068
|
+
const templates = getTemplatesByCategory(catKey, stackKey, patternKey);
|
|
1069
|
+
const tplOptions = Object.entries(templates).map(([key, t2]) => {
|
|
1070
|
+
const ver = VERSION_LABELS[t2.version] || t2.version;
|
|
1071
|
+
return {
|
|
1072
|
+
value: key,
|
|
1073
|
+
label: `${t2.name} [${ver}]`,
|
|
1074
|
+
hint: t2.description
|
|
1075
|
+
};
|
|
1076
|
+
});
|
|
1077
|
+
tplOptions.push({ value: "back", label: "<- \u8FD4\u56DE", hint: "" });
|
|
1078
|
+
const tplKey = await p.select({
|
|
1079
|
+
message: "\u8BF7\u9009\u62E9\u6A21\u677F\u7248\u672C:",
|
|
1080
|
+
options: tplOptions
|
|
1081
|
+
});
|
|
1082
|
+
if (p.isCancel(tplKey)) process.exit(0);
|
|
1083
|
+
if (tplKey === "back") continue;
|
|
1084
|
+
const t = templates[tplKey];
|
|
1085
|
+
return { key: tplKey, ...t };
|
|
1086
|
+
}
|
|
1087
1087
|
}
|
|
1088
1088
|
async function selectBySearch() {
|
|
1089
1089
|
while (true) {
|
|
1090
|
-
const
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
validate: (input) => input.trim() ? true : "\u5173\u952E\u8BCD\u4E0D\u80FD\u4E3A\u7A7A"
|
|
1096
|
-
}
|
|
1097
|
-
]);
|
|
1090
|
+
const keyword = await p.text({
|
|
1091
|
+
message: "\u8BF7\u8F93\u5165\u641C\u7D22\u5173\u952E\u8BCD (\u540D\u79F0\u3001\u63CF\u8FF0\u3001\u6280\u672F\u6808):",
|
|
1092
|
+
validate: (input) => input?.trim() ? void 0 : "\u5173\u952E\u8BCD\u4E0D\u80FD\u4E3A\u7A7A"
|
|
1093
|
+
});
|
|
1094
|
+
if (p.isCancel(keyword)) return await selectTemplateMethod();
|
|
1098
1095
|
const results = searchTemplates(keyword);
|
|
1099
1096
|
if (Object.keys(results).length === 0) {
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
{ name: "\u91CD\u65B0\u641C\u7D22", value: "retry" },
|
|
1111
|
-
{ name: chalk3.dim("<- \u8FD4\u56DE\u6A21\u677F\u9009\u62E9\u65B9\u5F0F"), value: "back" }
|
|
1112
|
-
]
|
|
1113
|
-
}
|
|
1114
|
-
]);
|
|
1115
|
-
if (action === "retry") continue;
|
|
1116
|
-
return await selectTemplateMethod();
|
|
1097
|
+
p.log.warn(`\u6CA1\u6709\u627E\u5230\u5339\u914D\u7684\u6A21\u677F (\u5173\u952E\u8BCD: "${keyword}")`);
|
|
1098
|
+
const action = await p.select({
|
|
1099
|
+
message: "\u8BF7\u9009\u62E9\u4E0B\u4E00\u6B65\u64CD\u4F5C:",
|
|
1100
|
+
options: [
|
|
1101
|
+
{ value: "retry", label: "\u91CD\u65B0\u641C\u7D22" },
|
|
1102
|
+
{ value: "back", label: "<- \u8FD4\u56DE\u6A21\u677F\u9009\u62E9\u65B9\u5F0F" }
|
|
1103
|
+
]
|
|
1104
|
+
});
|
|
1105
|
+
if (p.isCancel(action) || action === "back") return await selectTemplateMethod();
|
|
1106
|
+
continue;
|
|
1117
1107
|
}
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1108
|
+
p.log.info(`\u5173\u952E\u8BCD: "${keyword}" -- \u627E\u5230 ${Object.keys(results).length} \u4E2A\u5339\u914D\u6A21\u677F`);
|
|
1109
|
+
const options = [];
|
|
1110
|
+
for (const [key, t2] of Object.entries(results)) {
|
|
1111
|
+
const ver = VERSION_LABELS[t2.version] || t2.version;
|
|
1112
|
+
const info = t2.features.slice(0, 3).join(", ");
|
|
1113
|
+
options.push({
|
|
1114
|
+
value: key,
|
|
1115
|
+
label: `${t2.name.replace(STRIP_VERSION_RE, "")} [${ver}]`,
|
|
1116
|
+
hint: `${t2.description} | ${info}`
|
|
1117
|
+
});
|
|
1118
|
+
}
|
|
1119
|
+
options.push(
|
|
1120
|
+
{ value: "search_again", label: "\u91CD\u65B0\u641C\u7D22" },
|
|
1121
|
+
{ value: "back_to_mode", label: "<- \u8FD4\u56DE\u6A21\u677F\u9009\u62E9\u65B9\u5F0F" }
|
|
1124
1122
|
);
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
new RegExp(`(${keyword})`, "gi"),
|
|
1129
|
-
chalk3.bgYellow.black("$1")
|
|
1130
|
-
);
|
|
1131
|
-
const ver = getVersionLabel(t.version);
|
|
1132
|
-
const info = t.features.slice(0, 2).join(" \u2022 ");
|
|
1133
|
-
return {
|
|
1134
|
-
name: `${chalk3.bold(hl(t.name.replace(STRIP_VERSION_RE, "")))} ${ver}
|
|
1135
|
-
${chalk3.dim(hl(t.description))}
|
|
1136
|
-
${chalk3.dim(`${info} \u2022 key: ${key}`)}
|
|
1137
|
-
${chalk3.dim("\u2500".repeat(60))}`,
|
|
1138
|
-
value: { key, ...t },
|
|
1139
|
-
short: t.name
|
|
1140
|
-
};
|
|
1123
|
+
const selected = await p.select({
|
|
1124
|
+
message: "\u9009\u62E9\u6A21\u677F:",
|
|
1125
|
+
options
|
|
1141
1126
|
});
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
const { selectedTemplate } = await inquirer.prompt([
|
|
1148
|
-
{
|
|
1149
|
-
type: "list",
|
|
1150
|
-
name: "selectedTemplate",
|
|
1151
|
-
message: "\u9009\u62E9\u6A21\u677F:",
|
|
1152
|
-
choices,
|
|
1153
|
-
pageSize: 15,
|
|
1154
|
-
loop: false
|
|
1155
|
-
}
|
|
1156
|
-
]);
|
|
1157
|
-
if (selectedTemplate === "search_again") continue;
|
|
1158
|
-
if (selectedTemplate === "back_to_mode")
|
|
1159
|
-
return await selectTemplateMethod();
|
|
1160
|
-
return selectedTemplate;
|
|
1127
|
+
if (p.isCancel(selected)) process.exit(0);
|
|
1128
|
+
if (selected === "search_again") continue;
|
|
1129
|
+
if (selected === "back_to_mode") return await selectTemplateMethod();
|
|
1130
|
+
const t = results[selected];
|
|
1131
|
+
return { key: selected, ...t };
|
|
1161
1132
|
}
|
|
1162
1133
|
}
|
|
1163
1134
|
async function selectFromAll() {
|
|
1164
1135
|
const allTemplates = getAllTemplates();
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
console.log(chalk3.dim(` \u5171 ${Object.keys(allTemplates).length} \u4E2A\u6A21\u677F\u53EF\u9009`));
|
|
1168
|
-
console.log();
|
|
1169
|
-
const categorizedChoices = [];
|
|
1136
|
+
p.log.info(chalk3.bold("\u6240\u6709\u53EF\u7528\u6A21\u677F") + chalk3.dim(` -- \u5171 ${Object.keys(allTemplates).length} \u4E2A\u6A21\u677F\u53EF\u9009`));
|
|
1137
|
+
const options = [];
|
|
1170
1138
|
for (const [_catKey, category] of Object.entries(TEMPLATE_CATEGORIES)) {
|
|
1171
|
-
categorizedChoices.push({
|
|
1172
|
-
name: chalk3.yellow.bold(category.name),
|
|
1173
|
-
value: `${_catKey}_header`,
|
|
1174
|
-
disabled: true
|
|
1175
|
-
});
|
|
1176
1139
|
for (const [_sKey, stack] of Object.entries(category.stacks)) {
|
|
1177
1140
|
for (const _pattern of Object.values(stack.patterns)) {
|
|
1178
|
-
for (const [key,
|
|
1179
|
-
const ver =
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
short: t.name
|
|
1185
|
-
});
|
|
1186
|
-
categorizedChoices.push({
|
|
1187
|
-
name: chalk3.dim(" " + "\u2500".repeat(66)),
|
|
1188
|
-
value: `sep_${key}`,
|
|
1189
|
-
disabled: true
|
|
1141
|
+
for (const [key, t2] of Object.entries(_pattern.templates)) {
|
|
1142
|
+
const ver = VERSION_LABELS[t2.version] || t2.version;
|
|
1143
|
+
options.push({
|
|
1144
|
+
value: key,
|
|
1145
|
+
label: `${t2.name.replace(STRIP_VERSION_RE, "")} [${ver}]`,
|
|
1146
|
+
hint: `${category.name} > ${stack.name} | ${t2.description}`
|
|
1190
1147
|
});
|
|
1191
1148
|
}
|
|
1192
1149
|
}
|
|
1193
1150
|
}
|
|
1194
1151
|
}
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
choices: categorizedChoices,
|
|
1205
|
-
pageSize: 25,
|
|
1206
|
-
loop: false
|
|
1207
|
-
}
|
|
1208
|
-
]);
|
|
1209
|
-
if (selectedTemplate === "back_to_mode") return await selectTemplateMethod();
|
|
1210
|
-
return selectedTemplate;
|
|
1152
|
+
options.push({ value: "back_to_mode", label: "<- \u8FD4\u56DE\u6A21\u677F\u9009\u62E9\u65B9\u5F0F" });
|
|
1153
|
+
const selected = await p.select({
|
|
1154
|
+
message: "\u9009\u62E9\u6A21\u677F:",
|
|
1155
|
+
options
|
|
1156
|
+
});
|
|
1157
|
+
if (p.isCancel(selected)) process.exit(0);
|
|
1158
|
+
if (selected === "back_to_mode") return await selectTemplateMethod();
|
|
1159
|
+
const t = allTemplates[selected];
|
|
1160
|
+
return { key: selected, ...t };
|
|
1211
1161
|
}
|
|
1212
1162
|
async function configureProject(options) {
|
|
1213
|
-
|
|
1214
|
-
console.log(chalk3.bold(" \u9879\u76EE\u914D\u7F6E"));
|
|
1215
|
-
console.log();
|
|
1163
|
+
p.log.step(chalk3.bold("\u9879\u76EE\u914D\u7F6E"));
|
|
1216
1164
|
const available = detectPackageManager();
|
|
1217
1165
|
const hasBun = available.includes("bun");
|
|
1218
1166
|
const hasPnpm = available.includes("pnpm");
|
|
1219
|
-
const
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
if (
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
value: "
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
}
|
|
1248
|
-
const config = await inquirer.prompt([
|
|
1249
|
-
{
|
|
1250
|
-
type: "confirm",
|
|
1251
|
-
name: "initGit",
|
|
1252
|
-
message: "\u662F\u5426\u521D\u59CB\u5316 Git \u4ED3\u5E93?",
|
|
1253
|
-
default: true
|
|
1254
|
-
},
|
|
1255
|
-
{
|
|
1256
|
-
type: "confirm",
|
|
1257
|
-
name: "installDeps",
|
|
1258
|
-
message: "\u662F\u5426\u7ACB\u5373\u5B89\u88C5\u4F9D\u8D56?",
|
|
1259
|
-
default: !options.skipInstall
|
|
1260
|
-
},
|
|
1261
|
-
{
|
|
1262
|
-
type: "list",
|
|
1263
|
-
name: "packageManager",
|
|
1264
|
-
message: "\u9009\u62E9\u5305\u7BA1\u7406\u5668:",
|
|
1265
|
-
choices: managerChoices,
|
|
1266
|
-
default: hasBun ? "bun" : hasPnpm ? "pnpm" : "npm",
|
|
1267
|
-
when: (a) => a.installDeps
|
|
1268
|
-
},
|
|
1269
|
-
{
|
|
1270
|
-
type: "input",
|
|
1271
|
-
name: "description",
|
|
1272
|
-
message: "\u9879\u76EE\u63CF\u8FF0 (\u53EF\u9009):",
|
|
1273
|
-
default: ""
|
|
1274
|
-
},
|
|
1275
|
-
{
|
|
1276
|
-
type: "input",
|
|
1277
|
-
name: "author",
|
|
1278
|
-
message: "\u4F5C\u8005 (\u53EF\u9009):",
|
|
1279
|
-
default: getGitUser()
|
|
1280
|
-
},
|
|
1281
|
-
{
|
|
1282
|
-
type: "confirm",
|
|
1283
|
-
name: "confirmConfig",
|
|
1284
|
-
message: "\u786E\u8BA4\u4EE5\u4E0A\u914D\u7F6E?",
|
|
1285
|
-
default: true
|
|
1167
|
+
const initGit = await p.confirm({
|
|
1168
|
+
message: "\u662F\u5426\u521D\u59CB\u5316 Git \u4ED3\u5E93?",
|
|
1169
|
+
initialValue: true
|
|
1170
|
+
});
|
|
1171
|
+
if (p.isCancel(initGit)) process.exit(0);
|
|
1172
|
+
const installDeps = await p.confirm({
|
|
1173
|
+
message: "\u662F\u5426\u7ACB\u5373\u5B89\u88C5\u4F9D\u8D56?",
|
|
1174
|
+
initialValue: !options.skipInstall
|
|
1175
|
+
});
|
|
1176
|
+
if (p.isCancel(installDeps)) process.exit(0);
|
|
1177
|
+
let packageManager = hasBun ? "bun" : hasPnpm ? "pnpm" : "npm";
|
|
1178
|
+
if (installDeps) {
|
|
1179
|
+
const managerOptions = [];
|
|
1180
|
+
if (available.includes("bun"))
|
|
1181
|
+
managerOptions.push({ value: "bun", label: "bun", hint: "\u63A8\u8350 - \u6781\u901F\u5B89\u88C5" });
|
|
1182
|
+
if (available.includes("pnpm"))
|
|
1183
|
+
managerOptions.push({ value: "pnpm", label: "pnpm", hint: "\u63A8\u8350 - \u8282\u7701\u78C1\u76D8\u7A7A\u95F4" });
|
|
1184
|
+
if (available.includes("yarn"))
|
|
1185
|
+
managerOptions.push({ value: "yarn", label: "yarn", hint: "\u517C\u5BB9\u6027\u597D" });
|
|
1186
|
+
if (available.includes("npm"))
|
|
1187
|
+
managerOptions.push({ value: "npm", label: "npm", hint: "Node.js \u5185\u7F6E" });
|
|
1188
|
+
if (managerOptions.length === 0) {
|
|
1189
|
+
managerOptions.push(
|
|
1190
|
+
{ value: "npm", label: "npm" },
|
|
1191
|
+
{ value: "bun", label: "bun" },
|
|
1192
|
+
{ value: "pnpm", label: "pnpm" },
|
|
1193
|
+
{ value: "yarn", label: "yarn" }
|
|
1194
|
+
);
|
|
1286
1195
|
}
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
choices: [
|
|
1295
|
-
{ name: "\u91CD\u65B0\u914D\u7F6E", value: "reconfigure" },
|
|
1296
|
-
{ name: "\u53D6\u6D88\u521B\u5EFA", value: "cancel" }
|
|
1297
|
-
]
|
|
1298
|
-
}
|
|
1299
|
-
]);
|
|
1300
|
-
if (action === "reconfigure") return await configureProject(options);
|
|
1301
|
-
console.log(chalk3.yellow("\u53D6\u6D88\u521B\u5EFA\u9879\u76EE"));
|
|
1302
|
-
process.exit(0);
|
|
1196
|
+
const pm = await p.select({
|
|
1197
|
+
message: "\u9009\u62E9\u5305\u7BA1\u7406\u5668:",
|
|
1198
|
+
options: managerOptions,
|
|
1199
|
+
initialValue: hasBun ? "bun" : hasPnpm ? "pnpm" : "npm"
|
|
1200
|
+
});
|
|
1201
|
+
if (p.isCancel(pm)) process.exit(0);
|
|
1202
|
+
packageManager = pm;
|
|
1303
1203
|
}
|
|
1304
|
-
|
|
1204
|
+
const description = await p.text({
|
|
1205
|
+
message: "\u9879\u76EE\u63CF\u8FF0 (\u53EF\u9009):",
|
|
1206
|
+
defaultValue: "",
|
|
1207
|
+
placeholder: "\u8F93\u5165\u9879\u76EE\u63CF\u8FF0\u6216\u76F4\u63A5\u56DE\u8F66\u8DF3\u8FC7"
|
|
1208
|
+
});
|
|
1209
|
+
if (p.isCancel(description)) process.exit(0);
|
|
1210
|
+
const author = await p.text({
|
|
1211
|
+
message: "\u4F5C\u8005 (\u53EF\u9009):",
|
|
1212
|
+
defaultValue: getGitUser(),
|
|
1213
|
+
placeholder: getGitUser() || "\u8F93\u5165\u4F5C\u8005\u540D"
|
|
1214
|
+
});
|
|
1215
|
+
if (p.isCancel(author)) process.exit(0);
|
|
1216
|
+
return {
|
|
1217
|
+
initGit,
|
|
1218
|
+
installDeps,
|
|
1219
|
+
packageManager,
|
|
1220
|
+
description,
|
|
1221
|
+
author
|
|
1222
|
+
};
|
|
1305
1223
|
}
|
|
1306
1224
|
async function confirmCreation(projectName, template, config) {
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
` \u521D\u59CB\u5316Git: ${config.initGit ? chalk3.green("\u662F") : chalk3.dim("\u5426")}`
|
|
1225
|
+
p.note(
|
|
1226
|
+
[
|
|
1227
|
+
`${chalk3.dim("\u9879\u76EE\u540D\u79F0:")} ${chalk3.cyan(projectName)}`,
|
|
1228
|
+
`${chalk3.dim("\u9009\u62E9\u6A21\u677F:")} ${chalk3.cyan(template.name)}`,
|
|
1229
|
+
`${chalk3.dim("\u6A21\u677F\u63CF\u8FF0:")} ${template.description}`,
|
|
1230
|
+
`${chalk3.dim("\u5305\u542B\u529F\u80FD:")} ${template.features.join(", ") || "\u81EA\u5B9A\u4E49\u6A21\u677F"}`,
|
|
1231
|
+
config.description ? `${chalk3.dim("\u9879\u76EE\u63CF\u8FF0:")} ${config.description}` : "",
|
|
1232
|
+
config.author ? `${chalk3.dim("\u4F5C \u8005:")} ${config.author}` : "",
|
|
1233
|
+
`${chalk3.dim("\u521D\u59CB\u5316Git:")} ${config.initGit ? chalk3.green("\u662F") : "\u5426"}`,
|
|
1234
|
+
`${chalk3.dim("\u5B89\u88C5\u4F9D\u8D56:")} ${config.installDeps ? chalk3.green("\u662F") + ` (${config.packageManager})` : "\u5426"}`,
|
|
1235
|
+
`${chalk3.dim("\u6E90\u7801\u4ED3\u5E93:")} ${template.repoUrl}`
|
|
1236
|
+
].filter(Boolean).join("\n"),
|
|
1237
|
+
"\u9879\u76EE\u521B\u5EFA\u4FE1\u606F\u786E\u8BA4"
|
|
1321
1238
|
);
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
{
|
|
1329
|
-
type: "confirm",
|
|
1330
|
-
name: "confirmed",
|
|
1331
|
-
message: "\u786E\u8BA4\u521B\u5EFA\u9879\u76EE?",
|
|
1332
|
-
default: true
|
|
1333
|
-
}
|
|
1334
|
-
]);
|
|
1335
|
-
if (!confirmed) {
|
|
1336
|
-
console.log(chalk3.yellow("\u53D6\u6D88\u521B\u5EFA"));
|
|
1239
|
+
const confirmed = await p.confirm({
|
|
1240
|
+
message: "\u786E\u8BA4\u521B\u5EFA\u9879\u76EE?",
|
|
1241
|
+
initialValue: true
|
|
1242
|
+
});
|
|
1243
|
+
if (p.isCancel(confirmed) || !confirmed) {
|
|
1244
|
+
p.outro(chalk3.yellow("\u53D6\u6D88\u521B\u5EFA"));
|
|
1337
1245
|
process.exit(0);
|
|
1338
1246
|
}
|
|
1339
1247
|
}
|
|
@@ -1352,17 +1260,13 @@ async function executeCreation(projectName, template, config, options) {
|
|
|
1352
1260
|
const projectPath = path3.resolve(projectName);
|
|
1353
1261
|
if (fs3.existsSync(projectPath)) {
|
|
1354
1262
|
spinner.stop();
|
|
1355
|
-
|
|
1356
|
-
const
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
}
|
|
1363
|
-
]);
|
|
1364
|
-
if (!overwrite) {
|
|
1365
|
-
console.log(chalk3.yellow("\u53D6\u6D88\u521B\u5EFA"));
|
|
1263
|
+
p.log.warn("\u9879\u76EE\u76EE\u5F55\u5DF2\u5B58\u5728");
|
|
1264
|
+
const overwrite = await p.confirm({
|
|
1265
|
+
message: "\u76EE\u5F55\u5DF2\u5B58\u5728\uFF0C\u662F\u5426\u8986\u76D6?",
|
|
1266
|
+
initialValue: false
|
|
1267
|
+
});
|
|
1268
|
+
if (p.isCancel(overwrite) || !overwrite) {
|
|
1269
|
+
p.outro(chalk3.yellow("\u53D6\u6D88\u521B\u5EFA"));
|
|
1366
1270
|
process.exit(0);
|
|
1367
1271
|
}
|
|
1368
1272
|
spinner.start("\u6E05\u7406\u73B0\u6709\u76EE\u5F55...");
|
|
@@ -1401,41 +1305,31 @@ async function executeCreation(projectName, template, config, options) {
|
|
|
1401
1305
|
});
|
|
1402
1306
|
}
|
|
1403
1307
|
spinner.succeed(chalk3.green("\u9879\u76EE\u521B\u5EFA\u6210\u529F!"));
|
|
1404
|
-
console.log();
|
|
1405
|
-
console.log(chalk3.green("\u9879\u76EE\u521B\u5EFA\u5B8C\u6210!"));
|
|
1406
|
-
console.log();
|
|
1407
|
-
console.log(chalk3.blue("\u9879\u76EE\u4FE1\u606F:"));
|
|
1408
|
-
console.log(` \u4F4D\u7F6E: ${chalk3.cyan(projectPath)}`);
|
|
1409
|
-
console.log(` \u6A21\u677F: ${chalk3.cyan(template.name)}`);
|
|
1410
|
-
console.log(
|
|
1411
|
-
` Git\u4ED3\u5E93: ${config.initGit ? chalk3.green("\u5DF2\u521D\u59CB\u5316") : chalk3.dim("\u672A\u521D\u59CB\u5316")}`
|
|
1412
|
-
);
|
|
1413
|
-
console.log(
|
|
1414
|
-
` \u4F9D\u8D56\u5B89\u88C5: ${config.installDeps ? chalk3.green("\u5DF2\u5B8C\u6210") : chalk3.dim("\u9700\u624B\u52A8\u5B89\u88C5")}`
|
|
1415
|
-
);
|
|
1416
|
-
console.log();
|
|
1417
|
-
console.log(chalk3.blue("\u5FEB\u901F\u5F00\u59CB:"));
|
|
1418
|
-
console.log(chalk3.cyan(` cd ${projectName}`));
|
|
1419
1308
|
const pm = config.packageManager || "bun";
|
|
1420
|
-
if (!config.installDeps) {
|
|
1421
|
-
console.log(chalk3.cyan(` ${pm} install`));
|
|
1422
|
-
}
|
|
1423
1309
|
const cmd = getStartCommand(template, pm);
|
|
1424
|
-
|
|
1425
|
-
if (pm
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
chalk3.dim("
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1310
|
+
const steps = [`cd ${projectName}`];
|
|
1311
|
+
if (!config.installDeps) steps.push(`${pm} install`);
|
|
1312
|
+
if (cmd) steps.push(cmd);
|
|
1313
|
+
p.note(
|
|
1314
|
+
[
|
|
1315
|
+
`${chalk3.dim("\u4F4D\u7F6E:")} ${chalk3.cyan(projectPath)}`,
|
|
1316
|
+
`${chalk3.dim("\u6A21\u677F:")} ${chalk3.cyan(template.name)}`,
|
|
1317
|
+
`${chalk3.dim("Git:")} ${config.initGit ? chalk3.green("\u5DF2\u521D\u59CB\u5316") : "\u672A\u521D\u59CB\u5316"}`,
|
|
1318
|
+
`${chalk3.dim("\u4F9D\u8D56:")} ${config.installDeps ? chalk3.green("\u5DF2\u5B8C\u6210") : "\u9700\u624B\u52A8\u5B89\u88C5"}`,
|
|
1319
|
+
"",
|
|
1320
|
+
chalk3.bold("\u5FEB\u901F\u5F00\u59CB:"),
|
|
1321
|
+
...steps.map((s) => ` ${chalk3.cyan(s)}`)
|
|
1322
|
+
].join("\n"),
|
|
1323
|
+
"\u9879\u76EE\u521B\u5EFA\u5B8C\u6210"
|
|
1324
|
+
);
|
|
1325
|
+
const statsSpinner = ora("\u7EDF\u8BA1\u9879\u76EE\u4FE1\u606F...").start();
|
|
1433
1326
|
const stats = await generateProjectStats(projectPath);
|
|
1434
|
-
|
|
1327
|
+
statsSpinner.stop();
|
|
1435
1328
|
if (stats) {
|
|
1436
1329
|
printProjectStats(stats);
|
|
1437
1330
|
console.log();
|
|
1438
1331
|
}
|
|
1332
|
+
p.outro(chalk3.green("Happy coding!"));
|
|
1439
1333
|
} catch (error) {
|
|
1440
1334
|
if (tempPath) await fs3.remove(tempPath).catch(() => {
|
|
1441
1335
|
});
|
|
@@ -1597,55 +1491,32 @@ function getPackageVersion() {
|
|
|
1597
1491
|
}
|
|
1598
1492
|
var VERSION = getPackageVersion();
|
|
1599
1493
|
function showWelcome() {
|
|
1600
|
-
const supportsColor = process.stdout.isTTY && process.stdout.getColorDepth() > 1;
|
|
1601
1494
|
console.log();
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
}
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
console.log(
|
|
1608
|
-
chalk5.dim(` v${VERSION} | ${chalk5.reset.dim("\u5DE5\u7A0B\u5316\u9879\u76EE\u811A\u624B\u67B6")}`)
|
|
1609
|
-
);
|
|
1610
|
-
console.log(chalk5.dim(" \u524D\u7AEF / \u540E\u7AEF / \u79FB\u52A8\u7AEF / \u684C\u9762\u7AEF"));
|
|
1495
|
+
console.log(chalk5.cyan(" \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"));
|
|
1496
|
+
console.log(chalk5.cyan(" \u2551") + chalk5.bold.cyan(" R O B O T C L I ") + chalk5.cyan("\u2551"));
|
|
1497
|
+
console.log(chalk5.cyan(" \u2551") + chalk5.dim(` v${VERSION} | \u5DE5\u7A0B\u5316\u9879\u76EE\u811A\u624B\u67B6`.padEnd(38)) + chalk5.cyan("\u2551"));
|
|
1498
|
+
console.log(chalk5.cyan(" \u2551") + chalk5.dim(" \u524D\u7AEF / \u540E\u7AEF / \u79FB\u52A8\u7AEF / \u684C\u9762\u7AEF".padEnd(38)) + chalk5.cyan("\u2551"));
|
|
1499
|
+
console.log(chalk5.cyan(" \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"));
|
|
1611
1500
|
console.log();
|
|
1612
1501
|
}
|
|
1613
1502
|
async function showMainMenu() {
|
|
1614
1503
|
const allTemplates = getAllTemplates();
|
|
1615
1504
|
const count = Object.keys(allTemplates).length;
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
},
|
|
1632
|
-
{
|
|
1633
|
-
name: `${chalk5.cyan(">")} ${chalk5.bold("\u67E5\u770B\u6A21\u677F\u5217\u8868")} ${chalk5.dim("\u2014 \u6D4F\u89C8\u6240\u6709\u53EF\u7528\u6A21\u677F")}`,
|
|
1634
|
-
value: "list"
|
|
1635
|
-
},
|
|
1636
|
-
{
|
|
1637
|
-
name: `${chalk5.cyan(">")} ${chalk5.bold("\u641C\u7D22\u6A21\u677F")} ${chalk5.dim("\u2014 \u6309\u5173\u952E\u8BCD\u641C\u7D22\u6A21\u677F")}`,
|
|
1638
|
-
value: "search"
|
|
1639
|
-
},
|
|
1640
|
-
{
|
|
1641
|
-
name: `${chalk5.cyan(">")} ${chalk5.bold("\u73AF\u5883\u8BCA\u65AD")} ${chalk5.dim("\u2014 \u68C0\u67E5\u5F00\u53D1\u73AF\u5883")}`,
|
|
1642
|
-
value: "doctor"
|
|
1643
|
-
},
|
|
1644
|
-
{ name: chalk5.dim("\u2500".repeat(50)), value: "sep", disabled: true },
|
|
1645
|
-
{ name: `${chalk5.dim(" \u9000\u51FA")}`, value: "exit" }
|
|
1646
|
-
]
|
|
1647
|
-
}
|
|
1648
|
-
]);
|
|
1505
|
+
p2.intro(chalk5.bgCyan.black(` ${count} \u4E2A\u6A21\u677F\u53EF\u7528 \xB7 Node ${process.version} \xB7 v${VERSION} `));
|
|
1506
|
+
const action = await p2.select({
|
|
1507
|
+
message: "\u8BF7\u9009\u62E9\u64CD\u4F5C:",
|
|
1508
|
+
options: [
|
|
1509
|
+
{ value: "create", label: "\u521B\u5EFA\u65B0\u9879\u76EE", hint: "\u9009\u62E9\u6A21\u677F\u521B\u5EFA\u9879\u76EE" },
|
|
1510
|
+
{ value: "list", label: "\u67E5\u770B\u6A21\u677F\u5217\u8868", hint: "\u6D4F\u89C8\u6240\u6709\u53EF\u7528\u6A21\u677F" },
|
|
1511
|
+
{ value: "search", label: "\u641C\u7D22\u6A21\u677F", hint: "\u6309\u5173\u952E\u8BCD\u641C\u7D22\u6A21\u677F" },
|
|
1512
|
+
{ value: "doctor", label: "\u73AF\u5883\u8BCA\u65AD", hint: "\u68C0\u67E5\u5F00\u53D1\u73AF\u5883" },
|
|
1513
|
+
{ value: "exit", label: "\u9000\u51FA" }
|
|
1514
|
+
]
|
|
1515
|
+
});
|
|
1516
|
+
if (p2.isCancel(action)) {
|
|
1517
|
+
p2.outro(chalk5.dim("\u518D\u89C1!"));
|
|
1518
|
+
process.exit(0);
|
|
1519
|
+
}
|
|
1649
1520
|
switch (action) {
|
|
1650
1521
|
case "create":
|
|
1651
1522
|
await createProject(void 0, {});
|
|
@@ -1660,7 +1531,7 @@ async function showMainMenu() {
|
|
|
1660
1531
|
await runDoctor();
|
|
1661
1532
|
break;
|
|
1662
1533
|
case "exit":
|
|
1663
|
-
|
|
1534
|
+
p2.outro(chalk5.dim("\u518D\u89C1!"));
|
|
1664
1535
|
process.exit(0);
|
|
1665
1536
|
}
|
|
1666
1537
|
}
|
|
@@ -1684,14 +1555,11 @@ function showTemplateList(recommended) {
|
|
|
1684
1555
|
}
|
|
1685
1556
|
}
|
|
1686
1557
|
async function searchInteractive() {
|
|
1687
|
-
const
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
validate: (i) => i.trim() ? true : "\u8BF7\u8F93\u5165\u5173\u952E\u8BCD"
|
|
1693
|
-
}
|
|
1694
|
-
]);
|
|
1558
|
+
const keyword = await p2.text({
|
|
1559
|
+
message: "\u641C\u7D22\u5173\u952E\u8BCD:",
|
|
1560
|
+
validate: (i) => i?.trim() ? void 0 : "\u8BF7\u8F93\u5165\u5173\u952E\u8BCD"
|
|
1561
|
+
});
|
|
1562
|
+
if (p2.isCancel(keyword)) return;
|
|
1695
1563
|
showSearchResults(keyword);
|
|
1696
1564
|
}
|
|
1697
1565
|
function showSearchResults(keyword) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agile-team/robot-cli",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.1",
|
|
4
4
|
"description": "现代化项目脚手架工具,支持多技术栈快速创建项目 - 优先 bun,兼容 npm/pnpm/yarn",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -20,16 +20,15 @@
|
|
|
20
20
|
"release:major": "bun version major && bunx npm publish --access public"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
+
"@clack/prompts": "^1.1.0",
|
|
23
24
|
"chalk": "^5.3.0",
|
|
24
25
|
"commander": "^11.0.0",
|
|
25
26
|
"extract-zip": "^2.0.1",
|
|
26
27
|
"fs-extra": "^11.1.0",
|
|
27
|
-
"inquirer": "^9.2.0",
|
|
28
28
|
"ora": "^7.0.0"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@types/fs-extra": "^11.0.4",
|
|
32
|
-
"@types/inquirer": "^9.0.9",
|
|
33
32
|
"@types/node": "^22.0.0",
|
|
34
33
|
"oxlint": "^0.16.0",
|
|
35
34
|
"tsup": "^8.4.0",
|