@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.
Files changed (3) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/dist/index.js +425 -557
  3. 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 inquirer2 from "inquirer";
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 inquirer from "inquirer";
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") return `${cleanUrl}/archive/refs/heads/${branch}.zip`;
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 TIMEOUT_PRIMARY = 12e4;
342
- var TIMEOUT_MIRROR = 6e4;
343
- var MAX_RETRIES = 3;
344
- function getGitHubMirrors(repoUrl) {
345
- return [
346
- repoUrl,
347
- // 1. 原始 GitHub
348
- repoUrl.replace("github.com", "hub.gitmirror.com"),
349
- // 2. gitmirror
350
- `https://ghproxy.net/${repoUrl}`
351
- // 3. ghproxy.net
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
- headers: { "User-Agent": "Robot-CLI" }
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, 2e3 * attempt));
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 url = new URL(repoUrl);
379
- const host = url.hostname;
380
- const mirrors = host === "github.com" ? getGitHubMirrors(repoUrl) : [repoUrl];
381
- for (let i = 0; i < mirrors.length; i++) {
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 ${sourceName} ...`;
392
- const downloadUrl = current.endsWith(".zip") ? current : buildDownloadUrl(current, branch);
393
- const timeout = isOriginal ? TIMEOUT_PRIMARY : TIMEOUT_MIRROR;
394
- if (spinner) spinner.text = `\u4ECE ${sourceName} \u4E0B\u8F7D\u6A21\u677F (\u6700\u591A\u91CD\u8BD5${MAX_RETRIES}\u6B21)...`;
395
- const response = await fetchWithRetry(downloadUrl, timeout, MAX_RETRIES);
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}(${sourceName})`;
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
- if (i === mirrors.length - 1) throw error;
404
- if (spinner) spinner.text = `${sourceName} \u4E0D\u53EF\u7528\uFF0C\u5207\u6362\u4E0B\u4E00\u4E2A\u6E90...`;
405
- await new Promise((r) => setTimeout(r, 1e3));
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("\u6240\u6709\u4E0B\u8F7D\u6E90\u5747\u4E0D\u53EF\u7528");
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 buffer = Buffer.from(await response.arrayBuffer());
428
- await fs.writeFile(tempZip, buffer);
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
- console.log();
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
- console.log(chalk3.red("\u9879\u76EE\u540D\u79F0\u4E0D\u5408\u6CD5:"));
846
- v.errors.forEach((e) => console.log(chalk3.red(` ${e}`)));
847
- console.log();
848
- const { newName } = await inquirer.prompt([
849
- {
850
- type: "input",
851
- name: "newName",
852
- message: "\u8BF7\u8F93\u5165\u65B0\u7684\u9879\u76EE\u540D\u79F0:",
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 { name } = await inquirer.prompt([
865
- {
866
- type: "input",
867
- name: "name",
868
- message: "\u8BF7\u8F93\u5165\u9879\u76EE\u540D\u79F0:",
869
- default: defaultName,
870
- validate: (input) => {
871
- if (!input.trim()) return "\u9879\u76EE\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A";
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
- console.log();
898
- console.log(chalk3.bold(" \u9009\u62E9\u6A21\u677F\u521B\u5EFA\u65B9\u5F0F"));
899
- console.log(chalk3.dim(" \u8BF7\u9009\u62E9\u6700\u9002\u5408\u4F60\u7684\u6A21\u677F\u6D4F\u89C8\u65B9\u5F0F"));
900
- console.log();
901
- const { selectionMode } = await inquirer.prompt([
902
- {
903
- type: "list",
904
- name: "selectionMode",
905
- message: "\u6A21\u677F\u9009\u62E9\u65B9\u5F0F:",
906
- choices: [
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
- console.log(chalk3.yellow("\u6682\u65E0\u63A8\u8350\u6A21\u677F"));
993
+ p.log.warn("\u6682\u65E0\u63A8\u8350\u6A21\u677F");
944
994
  return await selectTemplateMethod();
945
995
  }
946
- console.log();
947
- console.log(chalk3.bold(" \u63A8\u8350\u6A21\u677F"));
948
- console.log(chalk3.dim(" \u57FA\u4E8E\u56E2\u961F\u4F7F\u7528\u9891\u7387\u548C\u9879\u76EE\u6210\u719F\u5EA6\u63A8\u8350"));
949
- console.log();
950
- const choices = [];
951
- const entries = Object.entries(recommended);
952
- entries.forEach(([key, template], index) => {
953
- const tags = template.features.slice(0, 3).map((f) => chalk3.dim(`[${f}]`)).join(" ");
954
- const ver = getVersionLabel(template.version);
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
- if (index < entries.length - 1) {
962
- choices.push({
963
- name: chalk3.dim("\u2500".repeat(70)),
964
- value: `sep_${index}`,
965
- disabled: true
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
- choices.push({ name: chalk3.dim(" <- \u8FD4\u56DE\u9009\u62E9\u5176\u4ED6\u65B9\u5F0F"), value: "back" });
970
- const { selectedTemplate } = await inquirer.prompt([
971
- {
972
- type: "list",
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 cat = await selectCategory();
986
- if (cat === "back_to_method") return await selectTemplateMethod();
987
- const stack = await selectStack(cat);
988
- if (stack === "back_to_category") continue;
989
- if (stack === "back_to_method") return await selectTemplateMethod();
990
- const pattern = await selectPattern(cat, stack);
991
- if (pattern === "back_to_stack" || pattern === "back_to_category") continue;
992
- if (pattern === "back_to_method") return await selectTemplateMethod();
993
- const tpl = await selectSpecificTemplate(cat, stack, pattern);
994
- if (typeof tpl === "string") continue;
995
- return tpl;
996
- }
997
- }
998
- async function selectCategory() {
999
- const choices = Object.entries(TEMPLATE_CATEGORIES).map(([key, c]) => ({
1000
- name: c.name,
1001
- value: key
1002
- }));
1003
- choices.push({
1004
- name: chalk3.dim("\u2190 \u8FD4\u56DE\u6A21\u677F\u9009\u62E9\u65B9\u5F0F"),
1005
- value: "back_to_method"
1006
- });
1007
- const { categoryKey } = await inquirer.prompt([
1008
- { type: "list", name: "categoryKey", message: "\u8BF7\u9009\u62E9\u9879\u76EE\u7C7B\u578B:", choices }
1009
- ]);
1010
- return categoryKey;
1011
- }
1012
- async function selectStack(categoryKey) {
1013
- const category = TEMPLATE_CATEGORIES[categoryKey];
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
- return selectedTemplate;
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 { keyword } = await inquirer.prompt([
1091
- {
1092
- type: "input",
1093
- name: "keyword",
1094
- message: "\u8BF7\u8F93\u5165\u641C\u7D22\u5173\u952E\u8BCD (\u540D\u79F0\u3001\u63CF\u8FF0\u3001\u6280\u672F\u6808):",
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
- console.log();
1101
- console.log(chalk3.yellow("\u6CA1\u6709\u627E\u5230\u5339\u914D\u7684\u6A21\u677F"));
1102
- console.log(chalk3.dim(`\u641C\u7D22\u5173\u952E\u8BCD: "${keyword}"`));
1103
- console.log();
1104
- const { action } = await inquirer.prompt([
1105
- {
1106
- type: "list",
1107
- name: "action",
1108
- message: "\u8BF7\u9009\u62E9\u4E0B\u4E00\u6B65\u64CD\u4F5C:",
1109
- choices: [
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
- console.log();
1119
- console.log(chalk3.bold(" \u641C\u7D22\u7ED3\u679C"));
1120
- console.log(
1121
- chalk3.dim(
1122
- `\u5173\u952E\u8BCD: "${keyword}" \u2022 \u627E\u5230 ${Object.keys(results).length} \u4E2A\u5339\u914D\u6A21\u677F`
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
- console.log();
1126
- const choices = Object.entries(results).map(([key, t]) => {
1127
- const hl = (text) => text.replace(
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
- choices.push(
1143
- { name: chalk3.dim("\u2501".repeat(70)), value: "separator", disabled: true },
1144
- { name: "\u91CD\u65B0\u641C\u7D22", value: "search_again" },
1145
- { name: chalk3.dim("<- \u8FD4\u56DE\u6A21\u677F\u9009\u62E9\u65B9\u5F0F"), value: "back_to_mode" }
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
- console.log();
1166
- console.log(chalk3.bold(" \u6240\u6709\u53EF\u7528\u6A21\u677F"));
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, t] of Object.entries(_pattern.templates)) {
1179
- const ver = getVersionLabel(t.version);
1180
- categorizedChoices.push({
1181
- name: ` \u25CF ${chalk3.bold(t.name.replace(STRIP_VERSION_RE, ""))} ${ver} - ${chalk3.dim(t.description)}
1182
- ${chalk3.dim(`\u6280\u672F\u6808: ${stack.name} \u2022 \u547D\u4EE4: robot create my-app -t ${key}`)}`,
1183
- value: { key, ...t },
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
- categorizedChoices.push(
1196
- { name: chalk3.dim("\u2501".repeat(70)), value: "separator", disabled: true },
1197
- { name: chalk3.dim("<- \u8FD4\u56DE\u6A21\u677F\u9009\u62E9\u65B9\u5F0F"), value: "back_to_mode" }
1198
- );
1199
- const { selectedTemplate } = await inquirer.prompt([
1200
- {
1201
- type: "list",
1202
- name: "selectedTemplate",
1203
- message: "\u9009\u62E9\u6A21\u677F:",
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
- console.log();
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 managerChoices = [];
1220
- if (available.includes("bun"))
1221
- managerChoices.push({
1222
- name: "bun (\u63A8\u8350 - \u6781\u901F\u5B89\u88C5\uFF0C\u73B0\u4EE3\u5316\uFF0C\u6027\u80FD\u6700\u4F73)",
1223
- value: "bun"
1224
- });
1225
- if (available.includes("pnpm"))
1226
- managerChoices.push({
1227
- name: "pnpm (\u63A8\u8350 - \u5FEB\u901F\u5B89\u88C5\uFF0C\u8282\u7701\u78C1\u76D8\u7A7A\u95F4)",
1228
- value: "pnpm"
1229
- });
1230
- if (available.includes("yarn"))
1231
- managerChoices.push({
1232
- name: "yarn (\u517C\u5BB9\u6027\u597D - \u9002\u7528\u4E8E\u73B0\u6709yarn\u9879\u76EE)",
1233
- value: "yarn"
1234
- });
1235
- if (available.includes("npm"))
1236
- managerChoices.push({
1237
- name: "npm (\u9ED8\u8BA4 - Node.js\u5185\u7F6E\uFF0C\u517C\u5BB9\u6027\u6700\u597D)",
1238
- value: "npm"
1239
- });
1240
- if (managerChoices.length === 0) {
1241
- managerChoices.push(
1242
- { name: "npm (\u9ED8\u8BA4)", value: "npm" },
1243
- { name: "bun (\u5982\u5DF2\u5B89\u88C5)", value: "bun" },
1244
- { name: "pnpm (\u5982\u5DF2\u5B89\u88C5)", value: "pnpm" },
1245
- { name: "yarn (\u5982\u5DF2\u5B89\u88C5)", value: "yarn" }
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
- if (!config.confirmConfig) {
1289
- const { action } = await inquirer.prompt([
1290
- {
1291
- type: "list",
1292
- name: "action",
1293
- message: "\u8BF7\u9009\u62E9\u64CD\u4F5C:",
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
- return config;
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
- console.log();
1308
- console.log(chalk3.bold(" \u9879\u76EE\u521B\u5EFA\u4FE1\u606F\u786E\u8BA4:"));
1309
- console.log();
1310
- console.log(` \u9879\u76EE\u540D\u79F0: ${chalk3.cyan(projectName)}`);
1311
- console.log(` \u9009\u62E9\u6A21\u677F: ${chalk3.cyan(template.name)}`);
1312
- console.log(` \u6A21\u677F\u63CF\u8FF0: ${chalk3.dim(template.description)}`);
1313
- console.log(
1314
- ` \u5305\u542B\u529F\u80FD: ${chalk3.dim(template.features.join(", ") || "\u81EA\u5B9A\u4E49\u6A21\u677F")}`
1315
- );
1316
- if (config.description)
1317
- console.log(` \u9879\u76EE\u63CF\u8FF0: ${chalk3.dim(config.description)}`);
1318
- if (config.author) console.log(` \u4F5C\u3000\u3000\u8005: ${chalk3.dim(config.author)}`);
1319
- console.log(
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
- console.log(
1323
- ` \u5B89\u88C5\u4F9D\u8D56: ${config.installDeps ? chalk3.green("\u662F") + chalk3.dim(` (${config.packageManager})`) : chalk3.dim("\u5426")}`
1324
- );
1325
- console.log(` \u6E90\u7801\u4ED3\u5E93: ${chalk3.dim(template.repoUrl)}`);
1326
- console.log();
1327
- const { confirmed } = await inquirer.prompt([
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
- console.log(chalk3.yellow("\u9879\u76EE\u76EE\u5F55\u5DF2\u5B58\u5728"));
1356
- const { overwrite } = await inquirer.prompt([
1357
- {
1358
- type: "confirm",
1359
- name: "overwrite",
1360
- message: "\u76EE\u5F55\u5DF2\u5B58\u5728\uFF0C\u662F\u5426\u8986\u76D6?",
1361
- default: false
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
- if (cmd) console.log(chalk3.cyan(` ${cmd}`));
1425
- if (pm === "bun")
1426
- console.log(chalk3.dim(" # \u6216\u4F7F\u7528 npm: npm install && npm run dev"));
1427
- else if (pm === "npm")
1428
- console.log(
1429
- chalk3.dim(" # \u6216\u4F7F\u7528 bun: bun install && bun run dev (\u5982\u5DF2\u5B89\u88C5)")
1430
- );
1431
- console.log();
1432
- spinner.start("\u7EDF\u8BA1\u9879\u76EE\u4FE1\u606F...");
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
- spinner.stop();
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
- if (supportsColor) {
1603
- console.log(chalk5.bold.cyan(" R O B O T C L I"));
1604
- } else {
1605
- console.log(" R O B O T C L I");
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
- console.log(
1617
- chalk5.dim(
1618
- ` ${count} \u4E2A\u6A21\u677F\u53EF\u7528 \xB7 Node ${process.version} \xB7 v${VERSION}`
1619
- )
1620
- );
1621
- console.log();
1622
- const { action } = await inquirer2.prompt([
1623
- {
1624
- type: "list",
1625
- name: "action",
1626
- message: "\u8BF7\u9009\u62E9\u64CD\u4F5C:",
1627
- choices: [
1628
- {
1629
- name: `${chalk5.cyan(">")} ${chalk5.bold("\u521B\u5EFA\u65B0\u9879\u76EE")} ${chalk5.dim("\u2014 \u9009\u62E9\u6A21\u677F\u521B\u5EFA\u9879\u76EE")}`,
1630
- value: "create"
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
- console.log(chalk5.dim(" \u518D\u89C1!"));
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 { keyword } = await inquirer2.prompt([
1688
- {
1689
- type: "input",
1690
- name: "keyword",
1691
- message: "\u641C\u7D22\u5173\u952E\u8BCD:",
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": "2.3.0",
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",