@agile-team/jh4j-cloud-cli 0.5.0 → 0.6.0
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 +14 -0
- package/README.md +19 -15
- package/dist/index.js +205 -122
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.6.0
|
|
4
|
+
|
|
5
|
+
- 直接展示 PC 管理端与移动端 H5 模板,并为每个选项提供独立技术栈提示。
|
|
6
|
+
- 增加“快速创建”和“自定义创建”两种方式;快速创建直接采用模板推荐值,自定义创建才询问项目名、标题、端口和联调地址。
|
|
7
|
+
- 下载与初始化过程改为轻量加载状态,不再显示冗余计时标签。
|
|
8
|
+
- 新增创建完成结果面板,集中展示模板版本、实际配置、预设能力、依赖与 Git 状态以及下一步命令。
|
|
9
|
+
- 用户取消时正常收尾,生成异常使用统一终端样式展示。
|
|
10
|
+
|
|
11
|
+
## 0.5.1
|
|
12
|
+
|
|
13
|
+
- 默认交互只选择项目类型并确认项目名;项目名直接回车使用默认值,也可以现场修改。
|
|
14
|
+
- 标题、端口、本地服务地址和其他项目参数静默使用模板默认值。
|
|
15
|
+
- 精简创建完成输出,只保留项目结果、后续命令和配置文件位置。
|
|
16
|
+
|
|
3
17
|
## 0.5.0
|
|
4
18
|
|
|
5
19
|
- 精简交互流程:单模板自动选择,标准能力直接采用模板默认值。
|
package/README.md
CHANGED
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
JH4J Cloud 团队项目脚手架,用于从受控模板快速创建结构一致、配置完整、可追溯的工程。
|
|
4
4
|
|
|
5
|
-
当前版本:`@agile-team/jh4j-cloud-cli@0.
|
|
5
|
+
当前版本:`@agile-team/jh4j-cloud-cli@0.6.0`。
|
|
6
6
|
|
|
7
7
|
## 核心能力
|
|
8
8
|
|
|
9
9
|
| 能力 | 说明 |
|
|
10
10
|
| --- | --- |
|
|
11
|
-
|
|
|
12
|
-
|
|
|
13
|
-
|
|
|
11
|
+
| 模板直选 | 直接展示 PC 管理端与移动端 H5,技术栈提示互不混淆 |
|
|
12
|
+
| 两种方式 | 快速创建直接使用模板推荐配置;自定义创建才展开必要参数 |
|
|
13
|
+
| 结果面板 | 完成后展示模板版本、实际配置、预设能力和下一步命令 |
|
|
14
14
|
| 非交互创建 | 支持命令行参数和 JSON 配置文件,适用于 CI 与批量初始化 |
|
|
15
15
|
| 多源拉取 | 支持本地目录、Git、HTTP 压缩包和离线压缩包 |
|
|
16
16
|
| 源站容灾 | 内置模板按 GitHub → Gitee 顺序拉取,主源不可用时自动切换 |
|
|
@@ -24,7 +24,8 @@ JH4J Cloud 团队项目脚手架,用于从受控模板快速创建结构一致
|
|
|
24
24
|
```text
|
|
25
25
|
jh4j create
|
|
26
26
|
→ 读取 Catalog
|
|
27
|
-
→
|
|
27
|
+
→ 选择 PC 管理端或移动端 H5 模板
|
|
28
|
+
→ 选择快速创建或自定义创建
|
|
28
29
|
→ 解析可用模板源
|
|
29
30
|
→ 拉取或读取缓存
|
|
30
31
|
→ 校验 template.manifest.json
|
|
@@ -60,20 +61,21 @@ pnpm add -g @agile-team/jh4j-cloud-cli
|
|
|
60
61
|
jh4j create jh4j-ui-orders
|
|
61
62
|
```
|
|
62
63
|
|
|
63
|
-
|
|
64
|
+
默认交互提供两种创建方式:
|
|
64
65
|
|
|
65
66
|
```text
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
67
|
+
选择项目模板
|
|
68
|
+
├─ PC 管理端 Vue 3 · Vite · 微前端
|
|
69
|
+
└─ 移动端 H5 Vue 3 · Vite 7 · Vant 4
|
|
70
|
+
|
|
71
|
+
选择创建方式
|
|
72
|
+
├─ 快速创建(推荐) 使用模板推荐配置并立即生成
|
|
73
|
+
└─ 自定义创建 设置项目名、标题、端口和联调地址
|
|
72
74
|
```
|
|
73
75
|
|
|
74
|
-
|
|
76
|
+
快速创建不会继续提问:PC 使用 `jh4j-ui-app`,移动端使用 `jh4j-mobile-app`,标题、端口、联调地址、Registry、模块标识和各套环境配置全部采用模板推荐值。自定义创建中的输入框都带有可编辑默认值,直接回车接受,输入内容则覆盖默认值。
|
|
75
77
|
|
|
76
|
-
|
|
78
|
+
创建完成后会显示结果面板,列出技术栈、核心包、Git 与代码质量规范、多环境配置、开发地址、联调地址、依赖状态和下一步命令。默认不安装依赖,仍由开发者执行 `pnpm install`。需要后续调整时,直接修改项目中的 `project.config.json`、`.npmrc` 和 `.env*` 文件。
|
|
77
79
|
|
|
78
80
|
当前 Catalog 中可用模板:
|
|
79
81
|
|
|
@@ -88,9 +90,11 @@ jh4j create jh4j-ui-orders
|
|
|
88
90
|
### 交互创建
|
|
89
91
|
|
|
90
92
|
```bash
|
|
91
|
-
jh4j create
|
|
93
|
+
jh4j create
|
|
92
94
|
```
|
|
93
95
|
|
|
96
|
+
快速创建会直接使用模板默认项目名。需要在创建前修改项目名及运行参数时,选择“自定义创建”;也可以把项目名作为参数传入:`jh4j create jh4j-ui-orders`。
|
|
97
|
+
|
|
94
98
|
### 使用明确参数创建
|
|
95
99
|
|
|
96
100
|
```bash
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import * as prompts3 from "@clack/prompts";
|
|
5
|
+
|
|
3
6
|
// src/cli.ts
|
|
4
7
|
import { Command } from "commander";
|
|
5
8
|
|
|
6
9
|
// package.json
|
|
7
10
|
var package_default = {
|
|
8
11
|
name: "@agile-team/jh4j-cloud-cli",
|
|
9
|
-
version: "0.
|
|
12
|
+
version: "0.6.0",
|
|
10
13
|
description: "JH4J Cloud \u4F01\u4E1A\u5185\u90E8\u6807\u51C6\u5316\u9879\u76EE\u811A\u624B\u67B6",
|
|
11
14
|
repository: {
|
|
12
15
|
type: "git",
|
|
@@ -614,6 +617,7 @@ async function acquireTemplateFromSources(sources, ref, options = {}) {
|
|
|
614
617
|
|
|
615
618
|
// src/commands/create.ts
|
|
616
619
|
import * as prompts2 from "@clack/prompts";
|
|
620
|
+
import { styleText } from "util";
|
|
617
621
|
|
|
618
622
|
// src/core/project-generator.ts
|
|
619
623
|
import { existsSync as existsSync6 } from "fs";
|
|
@@ -622,6 +626,14 @@ import path7 from "path";
|
|
|
622
626
|
import * as prompts from "@clack/prompts";
|
|
623
627
|
import { satisfies } from "semver";
|
|
624
628
|
|
|
629
|
+
// src/core/errors.ts
|
|
630
|
+
var UserCancelledError = class extends Error {
|
|
631
|
+
constructor() {
|
|
632
|
+
super("\u7528\u6237\u53D6\u6D88\u521B\u5EFA");
|
|
633
|
+
this.name = "UserCancelledError";
|
|
634
|
+
}
|
|
635
|
+
};
|
|
636
|
+
|
|
625
637
|
// src/core/template-manifest.ts
|
|
626
638
|
import path6 from "path";
|
|
627
639
|
async function loadTemplateManifest(templateRoot) {
|
|
@@ -663,9 +675,6 @@ async function loadTemplateManifest(templateRoot) {
|
|
|
663
675
|
|
|
664
676
|
// src/core/project-generator.ts
|
|
665
677
|
var ENV_NAMES = ["dev", "sit", "uat", "pre", "prd"];
|
|
666
|
-
function cancelled(value) {
|
|
667
|
-
return prompts.isCancel(value);
|
|
668
|
-
}
|
|
669
678
|
function normalizeProjectName(value) {
|
|
670
679
|
return value.trim().toLowerCase().replace(/\s+/g, "-").replace(/^[._-]+/, "").replace(/[^a-z0-9._-]+/g, "-").replace(/-{2,}/g, "-").replace(/[-._]+$/, "");
|
|
671
680
|
}
|
|
@@ -706,11 +715,11 @@ function ensureHttpUrl(value, label) {
|
|
|
706
715
|
async function askText(message, initialValue, validate) {
|
|
707
716
|
const answer = await prompts.text({
|
|
708
717
|
message,
|
|
709
|
-
|
|
718
|
+
initialValue,
|
|
710
719
|
defaultValue: initialValue,
|
|
711
720
|
validate
|
|
712
721
|
});
|
|
713
|
-
if (
|
|
722
|
+
if (prompts.isCancel(answer)) throw new UserCancelledError();
|
|
714
723
|
return String(answer).trim() || initialValue;
|
|
715
724
|
}
|
|
716
725
|
async function loadCreateConfig(configFile, cwd) {
|
|
@@ -746,7 +755,7 @@ async function collectTemplateFeatures(manifest, fileConfig, options) {
|
|
|
746
755
|
}
|
|
747
756
|
return selected;
|
|
748
757
|
}
|
|
749
|
-
async function collectProjectInput(projectName,
|
|
758
|
+
async function collectProjectInput(projectName, sourceConfig, fileConfig, options, userConfig, features) {
|
|
750
759
|
let moduleName = options.module ?? fileConfig.moduleName ?? inferModuleName(projectName);
|
|
751
760
|
let title = options.title ?? fileConfig.title ?? sourceConfig.title;
|
|
752
761
|
let port = options.port ?? fileConfig.devServerPort ?? sourceConfig.devServerPort;
|
|
@@ -760,28 +769,24 @@ async function collectProjectInput(projectName, manifest, sourceConfig, fileConf
|
|
|
760
769
|
environments[env] = { ...environments[env], ...value };
|
|
761
770
|
}
|
|
762
771
|
}
|
|
763
|
-
if (!options.yes) {
|
|
772
|
+
if (options.customize && !options.yes) {
|
|
764
773
|
title = await askText(
|
|
765
|
-
|
|
774
|
+
"\u5E94\u7528\u6807\u9898",
|
|
766
775
|
title,
|
|
767
|
-
(value) => value?.trim() ? void 0 : "\u6807\u9898\u4E0D\u80FD\u4E3A\u7A7A"
|
|
776
|
+
(value) => value?.trim() ? void 0 : "\u5E94\u7528\u6807\u9898\u4E0D\u80FD\u4E3A\u7A7A"
|
|
768
777
|
);
|
|
769
778
|
port = await askText("\u5F00\u53D1\u7AEF\u53E3", String(port), (value) => {
|
|
770
779
|
const parsed = Number(value);
|
|
771
780
|
return Number.isInteger(parsed) && parsed >= 1024 && parsed <= 65535 ? void 0 : "\u8BF7\u8F93\u5165 1024 \u5230 65535 \u4E4B\u95F4\u7684\u7AEF\u53E3";
|
|
772
781
|
});
|
|
773
|
-
localBackendUrl = await askText(
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
return url.protocol === "http:" || url.protocol === "https:" ? void 0 : "\u8BF7\u8F93\u5165 http/https \u5730\u5740";
|
|
780
|
-
} catch {
|
|
781
|
-
return "\u8BF7\u8F93\u5165\u5B8C\u6574\u7684 http/https \u5730\u5740";
|
|
782
|
-
}
|
|
782
|
+
localBackendUrl = await askText("\u672C\u5730\u8054\u8C03\u5730\u5740", localBackendUrl, (value) => {
|
|
783
|
+
try {
|
|
784
|
+
const url = new URL(value ?? "");
|
|
785
|
+
return url.protocol === "http:" || url.protocol === "https:" ? void 0 : "\u8BF7\u8F93\u5165\u5B8C\u6574\u7684 http/https \u5730\u5740";
|
|
786
|
+
} catch {
|
|
787
|
+
return "\u8BF7\u8F93\u5165\u5B8C\u6574\u7684 http/https \u5730\u5740";
|
|
783
788
|
}
|
|
784
|
-
);
|
|
789
|
+
});
|
|
785
790
|
}
|
|
786
791
|
if (!title.trim()) throw new Error("\u7CFB\u7EDF\u6807\u9898\u4E0D\u80FD\u4E3A\u7A7A");
|
|
787
792
|
for (const env of ENV_NAMES) {
|
|
@@ -850,7 +855,7 @@ async function generateProject(catalogTemplate, requestedProjectName, options, c
|
|
|
850
855
|
options.source,
|
|
851
856
|
userConfig.templateSource
|
|
852
857
|
);
|
|
853
|
-
const acquisitionSpinner = options.yes ? void 0 : prompts.spinner({ indicator: "
|
|
858
|
+
const acquisitionSpinner = options.yes ? void 0 : prompts.spinner({ indicator: "dots" });
|
|
854
859
|
acquisitionSpinner?.start("\u6B63\u5728\u83B7\u53D6\u5E76\u6821\u9A8C\u6A21\u677F");
|
|
855
860
|
let acquired;
|
|
856
861
|
try {
|
|
@@ -858,7 +863,7 @@ async function generateProject(catalogTemplate, requestedProjectName, options, c
|
|
|
858
863
|
noCache: options.cache === false,
|
|
859
864
|
cacheTtlMinutes: userConfig.cacheTtlMinutes
|
|
860
865
|
});
|
|
861
|
-
acquisitionSpinner?.stop("\u6A21\u677F\
|
|
866
|
+
acquisitionSpinner?.stop("\u6A21\u677F\u5DF2\u5C31\u7EEA");
|
|
862
867
|
} catch (error) {
|
|
863
868
|
acquisitionSpinner?.error("\u6A21\u677F\u83B7\u53D6\u5931\u8D25");
|
|
864
869
|
throw error;
|
|
@@ -868,6 +873,7 @@ async function generateProject(catalogTemplate, requestedProjectName, options, c
|
|
|
868
873
|
`.${projectName}.jh4j-tmp-${process.pid}-${Date.now()}`
|
|
869
874
|
);
|
|
870
875
|
let promoted = false;
|
|
876
|
+
let generationSpinner;
|
|
871
877
|
try {
|
|
872
878
|
const manifest = await loadTemplateManifest(acquired.root);
|
|
873
879
|
if (manifest.id !== catalogTemplate.id) {
|
|
@@ -885,7 +891,6 @@ async function generateProject(catalogTemplate, requestedProjectName, options, c
|
|
|
885
891
|
const features = await collectTemplateFeatures(manifest, fileConfig, options);
|
|
886
892
|
const input = await collectProjectInput(
|
|
887
893
|
projectName,
|
|
888
|
-
manifest,
|
|
889
894
|
{
|
|
890
895
|
...sourceProjectConfig,
|
|
891
896
|
npmRegistry: manifest.defaults.npmRegistry,
|
|
@@ -915,13 +920,23 @@ async function generateProject(catalogTemplate, requestedProjectName, options, c
|
|
|
915
920
|
return {
|
|
916
921
|
targetRoot,
|
|
917
922
|
templateId: manifest.id,
|
|
923
|
+
templateName: manifest.name,
|
|
918
924
|
templateVersion: manifest.version,
|
|
925
|
+
category: manifest.category,
|
|
919
926
|
source: acquired.source,
|
|
920
927
|
features: input.features,
|
|
921
928
|
installed: false,
|
|
922
|
-
gitInitialized: false
|
|
929
|
+
gitInitialized: false,
|
|
930
|
+
configuration: {
|
|
931
|
+
title: input.title,
|
|
932
|
+
moduleName: input.moduleName,
|
|
933
|
+
devServerPort: input.devServerPort,
|
|
934
|
+
localBackendUrl: input.localBackendUrl
|
|
935
|
+
}
|
|
923
936
|
};
|
|
924
937
|
}
|
|
938
|
+
generationSpinner = options.yes ? void 0 : prompts.spinner({ indicator: "dots" });
|
|
939
|
+
generationSpinner?.start("\u6B63\u5728\u751F\u6210\u9879\u76EE\u6587\u4EF6");
|
|
925
940
|
await copyTemplateTree(acquired.root, stagingRoot);
|
|
926
941
|
const inputFile = path7.join(stagingRoot, ".jh4j-cli-input.json");
|
|
927
942
|
await writeJson(inputFile, input);
|
|
@@ -948,6 +963,7 @@ async function generateProject(catalogTemplate, requestedProjectName, options, c
|
|
|
948
963
|
promoted = true;
|
|
949
964
|
let gitInitialized = false;
|
|
950
965
|
if (shouldInitializeGit) {
|
|
966
|
+
generationSpinner?.message("\u6B63\u5728\u521D\u59CB\u5316 Git main \u4ED3\u5E93");
|
|
951
967
|
await runCommand("git", ["init", "-b", "main"], {
|
|
952
968
|
cwd: targetRoot,
|
|
953
969
|
stdio: "pipe"
|
|
@@ -955,8 +971,12 @@ async function generateProject(catalogTemplate, requestedProjectName, options, c
|
|
|
955
971
|
gitInitialized = true;
|
|
956
972
|
}
|
|
957
973
|
if (shouldInstall) {
|
|
974
|
+
generationSpinner?.message("\u6B63\u5728\u5B89\u88C5\u9879\u76EE\u4F9D\u8D56");
|
|
958
975
|
try {
|
|
959
|
-
await runCommand("pnpm", ["install"], {
|
|
976
|
+
await runCommand("pnpm", ["install"], {
|
|
977
|
+
cwd: targetRoot,
|
|
978
|
+
stdio: "pipe"
|
|
979
|
+
});
|
|
960
980
|
} catch (error) {
|
|
961
981
|
throw new Error(
|
|
962
982
|
`\u9879\u76EE\u5DF2\u751F\u6210\uFF0C\u4F46\u4F9D\u8D56\u5B89\u88C5\u5931\u8D25\uFF1B\u76EE\u5F55\u5DF2\u4FDD\u7559\u5728 ${targetRoot}
|
|
@@ -964,7 +984,9 @@ ${error.message}`
|
|
|
964
984
|
);
|
|
965
985
|
}
|
|
966
986
|
}
|
|
987
|
+
let initialCommitWarning;
|
|
967
988
|
if (shouldInitializeGit) {
|
|
989
|
+
generationSpinner?.message("\u6B63\u5728\u521B\u5EFA\u521D\u59CB\u63D0\u4EA4");
|
|
968
990
|
await runCommand("git", ["add", "-A"], { cwd: targetRoot, stdio: "pipe" });
|
|
969
991
|
try {
|
|
970
992
|
await runCommand(
|
|
@@ -977,18 +999,33 @@ ${error.message}`
|
|
|
977
999
|
}
|
|
978
1000
|
);
|
|
979
1001
|
} catch (error) {
|
|
980
|
-
|
|
1002
|
+
initialCommitWarning = `Git \u5DF2\u521D\u59CB\u5316\uFF0C\u4F46\u521D\u59CB\u63D0\u4EA4\u672A\u5B8C\u6210\uFF1A${error.message}`;
|
|
981
1003
|
}
|
|
982
1004
|
}
|
|
1005
|
+
generationSpinner?.stop("\u9879\u76EE\u6587\u4EF6\u521D\u59CB\u5316\u5B8C\u6210");
|
|
1006
|
+
if (initialCommitWarning) prompts.log.warn(initialCommitWarning);
|
|
983
1007
|
return {
|
|
984
1008
|
targetRoot,
|
|
985
1009
|
templateId: manifest.id,
|
|
1010
|
+
templateName: manifest.name,
|
|
986
1011
|
templateVersion: manifest.version,
|
|
1012
|
+
category: manifest.category,
|
|
987
1013
|
source: acquired.source,
|
|
988
1014
|
features: input.features,
|
|
989
1015
|
installed: shouldInstall,
|
|
990
|
-
gitInitialized
|
|
1016
|
+
gitInitialized,
|
|
1017
|
+
configuration: {
|
|
1018
|
+
title: input.title,
|
|
1019
|
+
moduleName: input.moduleName,
|
|
1020
|
+
devServerPort: input.devServerPort,
|
|
1021
|
+
localBackendUrl: input.localBackendUrl
|
|
1022
|
+
}
|
|
991
1023
|
};
|
|
1024
|
+
} catch (error) {
|
|
1025
|
+
generationSpinner?.error(
|
|
1026
|
+
promoted ? "\u9879\u76EE\u5DF2\u751F\u6210\uFF0C\u540E\u7EED\u6B65\u9AA4\u672A\u5B8C\u6210" : "\u9879\u76EE\u751F\u6210\u5931\u8D25"
|
|
1027
|
+
);
|
|
1028
|
+
throw error;
|
|
992
1029
|
} finally {
|
|
993
1030
|
if (!promoted && existsSync6(stagingRoot)) await removePath(stagingRoot);
|
|
994
1031
|
await acquired.cleanup();
|
|
@@ -996,50 +1033,53 @@ ${error.message}`
|
|
|
996
1033
|
}
|
|
997
1034
|
|
|
998
1035
|
// src/commands/create.ts
|
|
999
|
-
var
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1036
|
+
var TEMPLATE_PRESENTATION = {
|
|
1037
|
+
frontend: { label: "PC \u7BA1\u7406\u7AEF", hint: "Vue 3 \xB7 Vite \xB7 \u5FAE\u524D\u7AEF" },
|
|
1038
|
+
backend: { label: "\u540E\u7AEF\u670D\u52A1", hint: "Java \xB7 Spring Cloud \xB7 \u4E91\u539F\u751F" },
|
|
1039
|
+
mobile: { label: "\u79FB\u52A8\u7AEF H5", hint: "Vue 3 \xB7 Vite 7 \xB7 Vant 4" }
|
|
1040
|
+
};
|
|
1004
1041
|
function isCategory(value) {
|
|
1005
|
-
return
|
|
1042
|
+
return Object.hasOwn(TEMPLATE_PRESENTATION, value);
|
|
1006
1043
|
}
|
|
1007
1044
|
function templatesByCategory(templates, category) {
|
|
1008
1045
|
return templates.filter((template) => template.category === category);
|
|
1009
1046
|
}
|
|
1010
|
-
function
|
|
1011
|
-
return
|
|
1012
|
-
|
|
1013
|
-
|
|
1047
|
+
function templateOptionsFor(templates) {
|
|
1048
|
+
return templates.map((template) => ({
|
|
1049
|
+
value: template.id,
|
|
1050
|
+
label: TEMPLATE_PRESENTATION[template.category].label,
|
|
1051
|
+
hint: TEMPLATE_PRESENTATION[template.category].hint
|
|
1052
|
+
}));
|
|
1014
1053
|
}
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1054
|
+
function creationModeOptions() {
|
|
1055
|
+
return [
|
|
1056
|
+
{
|
|
1057
|
+
value: "quick",
|
|
1058
|
+
label: "\u5FEB\u901F\u521B\u5EFA\uFF08\u63A8\u8350\uFF09",
|
|
1059
|
+
hint: "\u91C7\u7528\u6A21\u677F\u63A8\u8350\u914D\u7F6E\uFF0C\u7ACB\u5373\u751F\u6210"
|
|
1060
|
+
},
|
|
1061
|
+
{
|
|
1062
|
+
value: "custom",
|
|
1063
|
+
label: "\u81EA\u5B9A\u4E49\u521B\u5EFA",
|
|
1064
|
+
hint: "\u8BBE\u7F6E\u9879\u76EE\u540D\u3001\u6807\u9898\u3001\u7AEF\u53E3\u548C\u8054\u8C03\u5730\u5740"
|
|
1021
1065
|
}
|
|
1022
|
-
|
|
1023
|
-
|
|
1066
|
+
];
|
|
1067
|
+
}
|
|
1068
|
+
function defaultProjectNameFor(category) {
|
|
1069
|
+
if (category === "mobile") return "jh4j-mobile-app";
|
|
1070
|
+
if (category === "backend") return "jh4j-service-app";
|
|
1071
|
+
return "jh4j-ui-app";
|
|
1072
|
+
}
|
|
1073
|
+
function projectNamePromptOptions(category) {
|
|
1074
|
+
const defaultProjectName = defaultProjectNameFor(category);
|
|
1075
|
+
return {
|
|
1076
|
+
message: "\u9879\u76EE\u540D\u79F0",
|
|
1077
|
+
initialValue: defaultProjectName,
|
|
1078
|
+
defaultValue: defaultProjectName,
|
|
1079
|
+
validate(value) {
|
|
1080
|
+
return !value || normalizeProjectName(value) ? void 0 : "\u8BF7\u8F93\u5165\u81F3\u5C11\u4E00\u4E2A\u5B57\u6BCD\u6216\u6570\u5B57\uFF0C\u4F8B\u5982 jh4j-mobile-app";
|
|
1024
1081
|
}
|
|
1025
|
-
|
|
1026
|
-
}
|
|
1027
|
-
const firstAvailable = CATEGORY_OPTIONS.find(
|
|
1028
|
-
(item) => templatesByCategory(templates, item.value).length > 0
|
|
1029
|
-
);
|
|
1030
|
-
if (!firstAvailable) throw new Error("Catalog \u4E2D\u6CA1\u6709\u53EF\u7528\u6A21\u677F");
|
|
1031
|
-
if (nonInteractive) return firstAvailable.value;
|
|
1032
|
-
const availableOptions = categoryOptionsFor(templates);
|
|
1033
|
-
if (availableOptions.length === 1) return availableOptions[0].value;
|
|
1034
|
-
const selected = await prompts2.select({
|
|
1035
|
-
message: "\u9009\u62E9\u9879\u76EE\u7C7B\u578B",
|
|
1036
|
-
options: availableOptions.map((item) => ({
|
|
1037
|
-
value: item.value,
|
|
1038
|
-
label: item.label
|
|
1039
|
-
}))
|
|
1040
|
-
});
|
|
1041
|
-
if (prompts2.isCancel(selected)) throw new Error("\u7528\u6237\u53D6\u6D88\u521B\u5EFA");
|
|
1042
|
-
return selected;
|
|
1082
|
+
};
|
|
1043
1083
|
}
|
|
1044
1084
|
async function selectTemplate(templates, options) {
|
|
1045
1085
|
if (options.template) {
|
|
@@ -1051,50 +1091,91 @@ async function selectTemplate(templates, options) {
|
|
|
1051
1091
|
}
|
|
1052
1092
|
return selected2;
|
|
1053
1093
|
}
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
const candidates = templatesByCategory(templates, category);
|
|
1060
|
-
if (
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
return selected2;
|
|
1094
|
+
if (options.category && !isCategory(options.category)) {
|
|
1095
|
+
throw new Error(
|
|
1096
|
+
`\u9879\u76EE\u7C7B\u578B\u65E0\u6548: ${options.category}\u3002\u53EF\u7528\u503C: frontend\u3001backend\u3001mobile`
|
|
1097
|
+
);
|
|
1098
|
+
}
|
|
1099
|
+
const candidates = options.category ? templatesByCategory(templates, options.category) : templates;
|
|
1100
|
+
if (!candidates.length) {
|
|
1101
|
+
throw new Error(
|
|
1102
|
+
options.category ? `\u9879\u76EE\u7C7B\u578B ${options.category} \u6682\u65E0\u53EF\u7528\u6A21\u677F` : "Catalog \u4E2D\u6CA1\u6709\u53EF\u7528\u6A21\u677F"
|
|
1103
|
+
);
|
|
1065
1104
|
}
|
|
1105
|
+
if (options.yes) return findTemplate(candidates);
|
|
1106
|
+
if (candidates.length === 1) return candidates[0];
|
|
1066
1107
|
const selected = await prompts2.select({
|
|
1067
1108
|
message: "\u9009\u62E9\u9879\u76EE\u6A21\u677F",
|
|
1068
|
-
options: candidates
|
|
1069
|
-
|
|
1070
|
-
label: `${template.name} \xB7 ${template.description}`
|
|
1071
|
-
}))
|
|
1109
|
+
options: templateOptionsFor(candidates),
|
|
1110
|
+
initialValue: candidates[0].id
|
|
1072
1111
|
});
|
|
1073
|
-
if (prompts2.isCancel(selected)) throw new
|
|
1112
|
+
if (prompts2.isCancel(selected)) throw new UserCancelledError();
|
|
1074
1113
|
return findTemplate(candidates, String(selected));
|
|
1075
1114
|
}
|
|
1076
|
-
async function
|
|
1077
|
-
|
|
1115
|
+
async function selectCreationMode(options) {
|
|
1116
|
+
if (options.yes) return "quick";
|
|
1117
|
+
const selected = await prompts2.select({
|
|
1118
|
+
message: "\u9009\u62E9\u521B\u5EFA\u65B9\u5F0F",
|
|
1119
|
+
options: creationModeOptions(),
|
|
1120
|
+
initialValue: "quick"
|
|
1121
|
+
});
|
|
1122
|
+
if (prompts2.isCancel(selected)) throw new UserCancelledError();
|
|
1123
|
+
return selected;
|
|
1124
|
+
}
|
|
1125
|
+
function presetsFor(category, features) {
|
|
1126
|
+
const presets = category === "mobile" ? [
|
|
1127
|
+
"Vue 3 / Vite 7 / Vant 4 / TypeScript",
|
|
1128
|
+
"@robot-h5/core \u79FB\u52A8\u7AEF\u6838\u5FC3\u80FD\u529B"
|
|
1129
|
+
] : category === "frontend" ? [
|
|
1130
|
+
"Vue 3 / Vite / Module Federation",
|
|
1131
|
+
"@jhlc/common-core \u4F01\u4E1A\u57FA\u7840\u80FD\u529B"
|
|
1132
|
+
] : ["Java / Spring Cloud \u4F01\u4E1A\u670D\u52A1\u57FA\u7840\u80FD\u529B"];
|
|
1133
|
+
if (features.includes("git-standards")) {
|
|
1134
|
+
presets.push("Git \u63D0\u4EA4\u89C4\u8303\u3001\u4EE3\u7801\u68C0\u67E5\u4E0E Git Hooks");
|
|
1135
|
+
}
|
|
1136
|
+
presets.push("DEV / SIT / UAT / PRE / PRD \u591A\u73AF\u5883\u914D\u7F6E");
|
|
1137
|
+
return presets;
|
|
1138
|
+
}
|
|
1139
|
+
function buildCompletionContent(projectName, mode, result) {
|
|
1140
|
+
const nextSteps = [
|
|
1141
|
+
`1. cd ${projectName}`,
|
|
1142
|
+
...!result.installed ? ["2. pnpm install", "3. pnpm dev"] : ["2. pnpm dev"]
|
|
1143
|
+
];
|
|
1144
|
+
return [
|
|
1145
|
+
`\u9879\u76EE\uFF1A${projectName}`,
|
|
1146
|
+
`\u6A21\u677F\uFF1A${result.templateName} \xB7 v${result.templateVersion}`,
|
|
1147
|
+
`\u65B9\u5F0F\uFF1A${mode === "quick" ? "\u5FEB\u901F\u521B\u5EFA" : "\u81EA\u5B9A\u4E49\u521B\u5EFA"}`,
|
|
1148
|
+
`\u6807\u9898\uFF1A${result.configuration.title}`,
|
|
1149
|
+
`\u5F00\u53D1\uFF1Ahttp://localhost:${result.configuration.devServerPort}`,
|
|
1150
|
+
`\u8054\u8C03\uFF1A${result.configuration.localBackendUrl}`,
|
|
1151
|
+
"",
|
|
1152
|
+
"\u5DF2\u9884\u8BBE",
|
|
1153
|
+
...presetsFor(result.category, result.features).map((item) => ` \u2713 ${item}`),
|
|
1154
|
+
` ${result.gitInitialized ? "\u2713 Git main \u4ED3\u5E93\u5DF2\u521D\u59CB\u5316" : "\u25CB \u672A\u521D\u59CB\u5316 Git \u4ED3\u5E93"}`,
|
|
1155
|
+
` ${result.installed ? "\u2713 \u9879\u76EE\u4F9D\u8D56\u5DF2\u5B89\u88C5" : "\u25CB \u9879\u76EE\u4F9D\u8D56\u672A\u5B89\u88C5\uFF08\u6309\u9700\u624B\u52A8\u5B89\u88C5\uFF09"}`,
|
|
1156
|
+
"",
|
|
1157
|
+
"\u4E0B\u4E00\u6B65",
|
|
1158
|
+
...nextSteps.map((step) => ` ${step}`),
|
|
1159
|
+
"",
|
|
1160
|
+
"\u914D\u7F6E\uFF1Aproject.config.json / .env*"
|
|
1161
|
+
].join("\n");
|
|
1162
|
+
}
|
|
1163
|
+
async function executeCreateCommand(requestedName, options) {
|
|
1078
1164
|
const userConfig = await loadUserConfig();
|
|
1079
1165
|
const catalog = await loadCatalog(userConfig);
|
|
1080
1166
|
const template = await selectTemplate(catalog, options);
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
const answer = await prompts2.text(
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
return !value || normalizeProjectName(value) ? void 0 : "\u8BF7\u8F93\u5165\u81F3\u5C11\u4E00\u4E2A\u5B57\u6BCD\u6216\u6570\u5B57\uFF0C\u4F8B\u5982 jh4j-mobile-app";
|
|
1091
|
-
}
|
|
1092
|
-
});
|
|
1093
|
-
if (prompts2.isCancel(answer)) throw new Error("\u7528\u6237\u53D6\u6D88\u521B\u5EFA");
|
|
1094
|
-
projectName = String(answer).trim() || defaultProjectName;
|
|
1167
|
+
const mode = await selectCreationMode(options);
|
|
1168
|
+
const defaultProjectName = defaultProjectNameFor(template.category);
|
|
1169
|
+
let rawProjectName = requestedName;
|
|
1170
|
+
if (mode === "custom" && !rawProjectName && !options.yes) {
|
|
1171
|
+
const answer = await prompts2.text(
|
|
1172
|
+
projectNamePromptOptions(template.category)
|
|
1173
|
+
);
|
|
1174
|
+
if (prompts2.isCancel(answer)) throw new UserCancelledError();
|
|
1175
|
+
rawProjectName = String(answer).trim() || defaultProjectName;
|
|
1095
1176
|
}
|
|
1096
|
-
|
|
1097
|
-
projectName = normalizeProjectName(rawProjectName);
|
|
1177
|
+
rawProjectName ??= defaultProjectName;
|
|
1178
|
+
const projectName = normalizeProjectName(rawProjectName);
|
|
1098
1179
|
if (!projectName) {
|
|
1099
1180
|
throw new Error("\u9879\u76EE\u540D\u79F0\u81F3\u5C11\u9700\u8981\u5305\u542B\u4E00\u4E2A\u5B57\u6BCD\u6216\u6570\u5B57");
|
|
1100
1181
|
}
|
|
@@ -1104,7 +1185,7 @@ async function createCommand(requestedName, options) {
|
|
|
1104
1185
|
const result = await generateProject(
|
|
1105
1186
|
template,
|
|
1106
1187
|
projectName,
|
|
1107
|
-
options,
|
|
1188
|
+
{ ...options, customize: mode === "custom" },
|
|
1108
1189
|
process.cwd(),
|
|
1109
1190
|
userConfig
|
|
1110
1191
|
);
|
|
@@ -1112,27 +1193,31 @@ async function createCommand(requestedName, options) {
|
|
|
1112
1193
|
prompts2.outro("Dry Run \u5B8C\u6210\uFF0C\u672A\u5199\u5165\u4EFB\u4F55\u9879\u76EE\u6587\u4EF6");
|
|
1113
1194
|
return;
|
|
1114
1195
|
}
|
|
1115
|
-
prompts2.
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
"",
|
|
1124
|
-
|
|
1125
|
-
" project.config.json \u9879\u76EE\u3001\u8054\u8C03\u4E0E\u73AF\u5883\u53C2\u6570",
|
|
1126
|
-
" .npmrc Registry \u914D\u7F6E",
|
|
1127
|
-
" .env* \u5404\u7AEF\u8FD0\u884C\u73AF\u5883\u914D\u7F6E\uFF08\u5982\u5B58\u5728\uFF09",
|
|
1128
|
-
"",
|
|
1129
|
-
`cd ${projectName}`,
|
|
1130
|
-
...!result.installed ? ["pnpm install"] : [],
|
|
1131
|
-
"pnpm dev"
|
|
1132
|
-
].join("\n"),
|
|
1133
|
-
"\u521B\u5EFA\u6210\u529F"
|
|
1196
|
+
prompts2.box(
|
|
1197
|
+
buildCompletionContent(projectName, mode, result),
|
|
1198
|
+
styleText(["bold", "green"], " JH4J \u9879\u76EE\u5DF2\u5C31\u7EEA "),
|
|
1199
|
+
{
|
|
1200
|
+
rounded: true,
|
|
1201
|
+
width: "auto",
|
|
1202
|
+
titleAlign: "center",
|
|
1203
|
+
withGuide: false,
|
|
1204
|
+
formatBorder: (value) => styleText("green", value)
|
|
1205
|
+
}
|
|
1134
1206
|
);
|
|
1135
|
-
prompts2.outro("\
|
|
1207
|
+
prompts2.outro(styleText("green", "\u521B\u5EFA\u5B8C\u6210\uFF0C\u6309\u4E0A\u9762\u7684\u6B65\u9AA4\u542F\u52A8\u9879\u76EE"));
|
|
1208
|
+
}
|
|
1209
|
+
async function createCommand(requestedName, options) {
|
|
1210
|
+
const brand = styleText(["bold", "black", "bgCyan"], " JH4J CLOUD ");
|
|
1211
|
+
prompts2.intro(`${brand} \u521B\u5EFA\u6807\u51C6\u9879\u76EE`);
|
|
1212
|
+
try {
|
|
1213
|
+
await executeCreateCommand(requestedName, options);
|
|
1214
|
+
} catch (error) {
|
|
1215
|
+
if (error instanceof UserCancelledError) {
|
|
1216
|
+
prompts2.cancel("\u5DF2\u53D6\u6D88\u521B\u5EFA\uFF0C\u672A\u5199\u5165\u4EFB\u4F55\u9879\u76EE\u6587\u4EF6");
|
|
1217
|
+
return;
|
|
1218
|
+
}
|
|
1219
|
+
throw error;
|
|
1220
|
+
}
|
|
1136
1221
|
}
|
|
1137
1222
|
|
|
1138
1223
|
// src/commands/doctor.ts
|
|
@@ -1383,9 +1468,7 @@ async function runCli(argv = process.argv) {
|
|
|
1383
1468
|
|
|
1384
1469
|
// src/index.ts
|
|
1385
1470
|
runCli().catch((error) => {
|
|
1386
|
-
|
|
1387
|
-
\u9519\u8BEF: ${error.message}
|
|
1388
|
-
`);
|
|
1471
|
+
prompts3.cancel(`\u64CD\u4F5C\u5931\u8D25\uFF1A${error.message}`);
|
|
1389
1472
|
process.exitCode = 1;
|
|
1390
1473
|
});
|
|
1391
1474
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts","../package.json","../src/constants.ts","../src/catalog.ts","../src/utils/fs.ts","../src/core/template-source.ts","../src/utils/process.ts","../src/core/template-cache.ts","../src/core/user-config.ts","../src/commands/create.ts","../src/core/project-generator.ts","../src/core/template-manifest.ts","../src/commands/doctor.ts","../src/commands/info.ts","../src/commands/list.ts","../src/commands/template.ts","../src/commands/config.ts","../src/commands/cache.ts","../src/index.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { COMMAND_NAME, CLI_VERSION } from \"./constants.js\";\nimport { findTemplate, loadCatalog } from \"./catalog.js\";\nimport {\n acquireTemplateFromSources,\n resolveTemplateSources\n} from \"./core/template-source.js\";\nimport { loadUserConfig } from \"./core/user-config.js\";\nimport { createCommand } from \"./commands/create.js\";\nimport { doctorCommand } from \"./commands/doctor.js\";\nimport { infoCommand } from \"./commands/info.js\";\nimport { listCommand } from \"./commands/list.js\";\nimport { validateTemplateCommand } from \"./commands/template.js\";\nimport {\n configGetCommand,\n configListCommand,\n configResetCommand,\n configSetCommand,\n configUnsetCommand\n} from \"./commands/config.js\";\nimport { cacheClearCommand, cacheListCommand } from \"./commands/cache.js\";\n\nexport function createProgram(): Command {\n const program = new Command();\n program\n .name(COMMAND_NAME)\n .description(\"JH4J Cloud 企业内部标准化项目脚手架\")\n .version(CLI_VERSION);\n\n program\n .command(\"create [name]\")\n .description(\"根据标准模板创建项目\")\n .option(\"-c, --category <category>\", \"项目类型:frontend、backend 或 mobile\")\n .option(\"-t, --template <id>\", \"模板 ID\")\n .option(\"--features <ids>\", \"启用的模板能力,多个 ID 使用逗号分隔\")\n .option(\"--no-standards\", \"不启用模板提供的 Git/代码标准化能力\")\n .option(\"--source <path-or-url>\", \"覆盖模板源(本地目录或 Git URL)\")\n .option(\"--ref <branch-or-tag>\", \"Git 分支或标签;默认使用模板 Catalog 配置\")\n .option(\"--module <name>\", \"平台模块标识\")\n .option(\"--title <title>\", \"系统标题\")\n .option(\"--port <port>\", \"开发端口\")\n .option(\"--npm-registry <url>\", \"npm registry(需包含企业定制包)\")\n .option(\"--jhlc-registry <url>\", \"@jhlc 私有 registry\")\n .option(\"--local-backend <url>\", \"本地后端地址\")\n .option(\"--local-public <url>\", \"本地 public 地址\")\n .option(\"--config <json-file>\", \"从 JSON 文件读取创建参数\")\n .option(\"-y, --yes\", \"接受模板默认值,非交互创建\")\n .option(\"--dry-run\", \"只预览,不写入文件\")\n .option(\"--install\", \"创建完成后安装依赖(默认不安装)\")\n .option(\"--skip-install\", \"不安装依赖(兼容旧命令)\")\n .option(\"--skip-git\", \"跳过 Git 初始化\")\n .option(\"--force\", \"覆盖已存在的同名目录\")\n .option(\"--no-cache\", \"不使用已有远程模板缓存\")\n .action(createCommand);\n\n program\n .command(\"list\")\n .description(\"列出可用模板\")\n .option(\"--json\", \"输出 JSON\")\n .action(listCommand);\n program\n .command(\"doctor\")\n .description(\"检查本机环境和模板可用性\")\n .option(\"--json\", \"输出 JSON\")\n .action(doctorCommand);\n program\n .command(\"info [path]\")\n .description(\"显示已生成项目的模板与版本信息\")\n .option(\"--json\", \"输出 JSON\")\n .action(infoCommand);\n\n const template = program.command(\"template\").description(\"模板维护命令\");\n template\n .command(\"validate [path]\")\n .description(\"校验模板 manifest 与模板契约\")\n .action(async (templatePath?: string) => {\n if (templatePath) return validateTemplateCommand(templatePath);\n const config = await loadUserConfig();\n const selected = findTemplate(await loadCatalog(config));\n const acquired = await acquireTemplateFromSources(\n resolveTemplateSources(selected, undefined, config.templateSource),\n config.templateRef ?? selected.defaultRef,\n { cacheTtlMinutes: config.cacheTtlMinutes }\n );\n try {\n return await validateTemplateCommand(acquired.root);\n } finally {\n await acquired.cleanup();\n }\n });\n\n const config = program.command(\"config\").description(\"管理用户默认配置\");\n config\n .command(\"list\")\n .option(\"--json\", \"输出 JSON\")\n .action(configListCommand);\n config.command(\"get <key>\").action(configGetCommand);\n config.command(\"set <key> <value>\").action(configSetCommand);\n config.command(\"unset <key>\").action(configUnsetCommand);\n config.command(\"reset\").action(configResetCommand);\n\n const cache = program.command(\"cache\").description(\"管理远程模板缓存\");\n cache\n .command(\"list\")\n .option(\"--json\", \"输出 JSON\")\n .action(cacheListCommand);\n cache.command(\"clear\").action(cacheClearCommand);\n\n return program;\n}\n\nexport async function runCli(argv = process.argv): Promise<void> {\n await createProgram().parseAsync(argv);\n}\n","{\n \"name\": \"@agile-team/jh4j-cloud-cli\",\n \"version\": \"0.5.0\",\n \"description\": \"JH4J Cloud 企业内部标准化项目脚手架\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/ChenyCHENYU/jh4j-cloud-cli.git\"\n },\n \"homepage\": \"https://github.com/ChenyCHENYU/jh4j-cloud-cli#readme\",\n \"bugs\": {\n \"url\": \"https://github.com/ChenyCHENYU/jh4j-cloud-cli/issues\"\n },\n \"type\": \"module\",\n \"engines\": {\n \"node\": \"^22.12.0 || ^24.0.0\",\n \"pnpm\": \">=11.8.0\"\n },\n \"packageManager\": \"pnpm@11.8.0\",\n \"bin\": {\n \"jh4j\": \"bin/jh4j.js\"\n },\n \"files\": [\n \"bin\",\n \"dist\",\n \"README.md\",\n \"CHANGELOG.md\",\n \"catalog.schema.json\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"tsup --watch\",\n \"typecheck\": \"tsc --noEmit\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"start\": \"node bin/jh4j.js\",\n \"check\": \"pnpm typecheck && pnpm test && pnpm build\",\n \"prepack\": \"pnpm check\"\n },\n \"dependencies\": {\n \"@clack/prompts\": \"^1.7.0\",\n \"commander\": \"^15.0.0\",\n \"semver\": \"^7.8.5\",\n \"tar\": \"^7.5.19\"\n },\n \"publishConfig\": {\n \"access\": \"public\",\n \"registry\": \"https://registry.npmjs.org/\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^24.13.3\",\n \"@types/semver\": \"7.7.1\",\n \"tsup\": \"8.5.1\",\n \"typescript\": \"7.0.2\",\n \"vitest\": \"4.1.10\"\n }\n}\n","import packageJson from \"../package.json\" with { type: \"json\" };\n\nexport const CLI_NAME = \"@agile-team/jh4j-cloud-cli\";\nexport const CLI_VERSION = packageJson.version;\nexport const COMMAND_NAME = \"jh4j\";\nexport const SUPPORTED_NODE_MAJORS = new Set([22, 24]);\nexport const TEMPLATE_SOURCE_ENV = \"JH4J_UI_TEMPLATE_SOURCE\";\nexport const JH4J_HOME_ENV = \"JH4J_HOME\";\nexport const CATALOG_FILE_ENV = \"JH4J_CATALOG_FILE\";\nexport const USER_CONFIG_SCHEMA_VERSION = 1;\n","import { fileURLToPath } from \"node:url\";\nimport path from \"node:path\";\nimport { existsSync } from \"node:fs\";\nimport { CATALOG_FILE_ENV, TEMPLATE_SOURCE_ENV } from \"./constants.js\";\nimport { readJson } from \"./utils/fs.js\";\nimport type { CatalogFile, CatalogTemplate, UserConfig } from \"./types.js\";\n\nconst siblingTemplatePath = fileURLToPath(\n new URL(\"../../jh4j-ui-template/\", import.meta.url)\n);\nconst siblingMobileTemplatePath = fileURLToPath(\n new URL(\"../../../Robot_H5/\", import.meta.url)\n);\nconst remoteTemplateSources = [\n \"https://github.com/ChenyCHENYU/jh4j-ui-template.git\",\n \"https://gitee.com/ycyplus163/jh4j-ui-template.git\"\n];\nconst remoteMobileTemplateSources = [\n \"https://github.com/ChenyCHENYU/Robot_H5.git\",\n \"https://gitee.com/ycyplus163/robot_-h5.git\"\n];\n\nexport const BUILTIN_TEMPLATES: CatalogTemplate[] = [\n {\n id: \"web.jh4j-mf-remote\",\n name: \"JH4J PC 微前端业务模板\",\n description: \"Vue 3 + Vite + Module Federation 标准业务子系统\",\n category: \"frontend\",\n sourceEnvironment: TEMPLATE_SOURCE_ENV,\n defaultSource: existsSync(siblingTemplatePath)\n ? siblingTemplatePath\n : remoteTemplateSources[0],\n sources: remoteTemplateSources,\n defaultRef: \"main\",\n status: \"beta\",\n tags: [\"vue\", \"vite\", \"module-federation\", \"pc\"]\n },\n {\n id: \"mobile.robot-h5\",\n name: \"JH4J 移动端 H5 模板\",\n description: \"Vue 3 + Vite 7 + Vant 4 企业级移动端 H5 应用\",\n category: \"mobile\",\n sourceEnvironment: TEMPLATE_SOURCE_ENV,\n defaultSource: existsSync(siblingMobileTemplatePath)\n ? siblingMobileTemplatePath\n : remoteMobileTemplateSources[0],\n sources: remoteMobileTemplateSources,\n defaultRef: \"v1.6.0\",\n status: \"beta\",\n tags: [\"vue\", \"vite\", \"vant\", \"h5\", \"mobile\"]\n }\n];\n\nfunction validateCatalogTemplate(template: CatalogTemplate): void {\n if (!template.id || !template.name || !template.category) {\n throw new Error(\"Catalog 模板缺少 id、name 或 category\");\n }\n if (!new Set([\"frontend\", \"backend\", \"mobile\"]).has(template.category)) {\n throw new Error(`Catalog 模板 ${template.id} 的 category 无效`);\n }\n if (!new Set([\"stable\", \"beta\"]).has(template.status)) {\n throw new Error(`Catalog 模板 ${template.id} 的 status 无效`);\n }\n if (!template.defaultRef) {\n throw new Error(`Catalog 模板 ${template.id} 缺少 defaultRef`);\n }\n if (!template.defaultSource && !template.sourceEnvironment) {\n throw new Error(`Catalog 模板 ${template.id} 没有可解析的模板源`);\n }\n if (template.sources?.some((source) => !source.trim())) {\n throw new Error(`Catalog 模板 ${template.id} 包含空的备用源`);\n }\n}\n\nfunction resolveCatalogSource(source: string, catalogDirectory: string): string {\n const isRemote =\n /^(?:https?|ssh|file):\\/\\//.test(source) || source.startsWith(\"git@\");\n return isRemote || path.isAbsolute(source)\n ? source\n : path.resolve(catalogDirectory, source);\n}\n\nexport async function loadCatalog(config?: UserConfig): Promise<CatalogTemplate[]> {\n const configuredFile = process.env[CATALOG_FILE_ENV] || config?.catalogFile;\n if (!configuredFile) return [...BUILTIN_TEMPLATES];\n\n const catalogPath = path.resolve(configuredFile);\n if (!existsSync(catalogPath)) {\n throw new Error(`Catalog 文件不存在: ${catalogPath}`);\n }\n const external = await readJson<CatalogFile>(catalogPath);\n if (external.schemaVersion !== 1 || !Array.isArray(external.templates)) {\n throw new Error(`Catalog 文件格式无效: ${catalogPath}`);\n }\n const catalogDirectory = path.dirname(catalogPath);\n external.templates = external.templates.map((template) => {\n return {\n ...template,\n defaultSource: resolveCatalogSource(\n template.defaultSource,\n catalogDirectory\n ),\n sources: template.sources?.map((source) =>\n resolveCatalogSource(source, catalogDirectory)\n )\n };\n });\n external.templates.forEach(validateCatalogTemplate);\n\n const merged = new Map(BUILTIN_TEMPLATES.map((item) => [item.id, item]));\n external.templates.forEach((item) => merged.set(item.id, item));\n return [...merged.values()];\n}\n\nexport function findTemplate(\n catalog: CatalogTemplate[],\n id?: string\n): CatalogTemplate {\n const selected = id ?? catalog[0]?.id;\n const template = catalog.find((item) => item.id === selected);\n if (!template) {\n throw new Error(\n `模板不存在: ${selected}。可用模板: ${catalog.map((item) => item.id).join(\", \")}`\n );\n }\n return template;\n}\n","import { cp, mkdir, readFile, rm, stat, writeFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport path from \"node:path\";\n\nconst EXCLUDED_TEMPLATE_PATHS = new Set([\n \".git\",\n \".jhlc\",\n \"dist\",\n \"node_modules\"\n]);\n\nexport async function readJson<T>(file: string): Promise<T> {\n return JSON.parse(await readFile(file, \"utf8\")) as T;\n}\n\nexport async function writeJson(file: string, value: unknown): Promise<void> {\n await mkdir(path.dirname(file), { recursive: true });\n await writeFile(file, `${JSON.stringify(value, null, 2)}\\n`, \"utf8\");\n}\n\nexport async function isDirectory(directory: string): Promise<boolean> {\n try {\n return (await stat(directory)).isDirectory();\n } catch {\n return false;\n }\n}\n\nexport async function isDirectoryEmpty(directory: string): Promise<boolean> {\n if (!existsSync(directory)) return true;\n const { readdir } = await import(\"node:fs/promises\");\n return (await readdir(directory)).length === 0;\n}\n\nexport async function copyTemplateTree(\n sourceRoot: string,\n targetRoot: string\n): Promise<void> {\n await mkdir(targetRoot, { recursive: true });\n await cp(sourceRoot, targetRoot, {\n recursive: true,\n force: true,\n filter(source) {\n const relative = path.relative(sourceRoot, source);\n if (!relative) return true;\n const [topLevel] = relative.split(path.sep);\n return !EXCLUDED_TEMPLATE_PATHS.has(topLevel);\n }\n });\n}\n\nexport async function removePath(target: string): Promise<void> {\n await rm(target, { recursive: true, force: true, maxRetries: 3 });\n}\n","import path from \"node:path\";\nimport { existsSync } from \"node:fs\";\nimport { mkdir, readdir, rename, rm, writeFile } from \"node:fs/promises\";\nimport { x as extractTar } from \"tar\";\nimport type { CatalogTemplate } from \"../types.js\";\nimport { isDirectory } from \"../utils/fs.js\";\nimport { runCommand } from \"../utils/process.js\";\nimport {\n createTemplateCacheStaging,\n isTemplateCacheFresh,\n readTemplateCacheEntry\n} from \"./template-cache.js\";\n\nconst MAX_ARCHIVE_BYTES = 200 * 1024 * 1024;\n\nexport interface AcquiredTemplate {\n root: string;\n source: string;\n cleanup(): Promise<void>;\n}\n\nexport function resolveTemplateSource(\n template: CatalogTemplate,\n override?: string,\n configuredSource?: string\n): string {\n return resolveTemplateSources(template, override, configuredSource)[0];\n}\n\nexport function resolveTemplateSources(\n template: CatalogTemplate,\n override?: string,\n configuredSource?: string\n): string[] {\n const exclusiveSource =\n override ||\n (template.sourceEnvironment\n ? process.env[template.sourceEnvironment]\n : undefined) ||\n configuredSource;\n if (exclusiveSource) return [exclusiveSource];\n return [...new Set([template.defaultSource, ...(template.sources ?? [])])];\n}\n\nfunction isGitSource(source: string): boolean {\n return (\n source.startsWith(\"git@\") ||\n source.startsWith(\"ssh://\") ||\n source.startsWith(\"file://\") ||\n source.startsWith(\"http://\") ||\n source.startsWith(\"https://\") ||\n source.endsWith(\".git\")\n );\n}\n\nfunction isArchiveSource(source: string): boolean {\n const pathname = source.split(/[?#]/, 1)[0].toLowerCase();\n return pathname.endsWith(\".tgz\") || pathname.endsWith(\".tar.gz\") || pathname.endsWith(\".tar\");\n}\n\nasync function getFreshCache(\n source: string,\n ref: string,\n options: { noCache?: boolean; cacheTtlMinutes?: number }\n): Promise<AcquiredTemplate | null> {\n const cacheEntry = await readTemplateCacheEntry(source, ref);\n if (\n !options.noCache &&\n cacheEntry &&\n isTemplateCacheFresh(cacheEntry, options.cacheTtlMinutes ?? 60)\n ) {\n return {\n root: cacheEntry.root,\n source: `${source}#${ref} (cache)`,\n async cleanup() {}\n };\n }\n return null;\n}\n\nasync function normalizeExtractedTemplate(\n stagingRoot: string,\n templateRoot: string\n): Promise<void> {\n if (existsSync(path.join(templateRoot, \"template.manifest.json\"))) return;\n const children = await readdir(templateRoot, { withFileTypes: true });\n const candidates = children.filter(\n (entry) =>\n entry.isDirectory() &&\n existsSync(path.join(templateRoot, entry.name, \"template.manifest.json\"))\n );\n if (candidates.length !== 1) {\n throw new Error(\"压缩包根目录或唯一一级目录中未找到 template.manifest.json\");\n }\n const normalizedRoot = path.join(stagingRoot, \".normalized-template\");\n await rename(path.join(templateRoot, candidates[0].name), normalizedRoot);\n await rm(templateRoot, { recursive: true, force: true });\n await rename(normalizedRoot, templateRoot);\n}\n\nasync function acquireArchiveTemplate(\n source: string,\n ref: string,\n options: { noCache?: boolean; cacheTtlMinutes?: number }\n): Promise<AcquiredTemplate> {\n const cached = await getFreshCache(source, ref, options);\n if (cached) return cached;\n\n const cacheStaging = await createTemplateCacheStaging(source, ref);\n const archiveFile = path.join(cacheStaging.stagingRoot, \"template.tgz\");\n try {\n if (source.startsWith(\"http://\") || source.startsWith(\"https://\")) {\n const response = await fetch(source, { signal: AbortSignal.timeout(60_000) });\n if (!response.ok) {\n throw new Error(`模板压缩包下载失败: HTTP ${response.status}`);\n }\n const declaredLength = Number(response.headers.get(\"content-length\") || 0);\n if (declaredLength > MAX_ARCHIVE_BYTES) {\n throw new Error(\"模板压缩包超过 200 MB 限制\");\n }\n const archiveBuffer = Buffer.from(await response.arrayBuffer());\n if (archiveBuffer.byteLength > MAX_ARCHIVE_BYTES) {\n throw new Error(\"模板压缩包超过 200 MB 限制\");\n }\n await writeFile(archiveFile, archiveBuffer);\n } else {\n const { copyFile } = await import(\"node:fs/promises\");\n await copyFile(path.resolve(source), archiveFile);\n }\n await mkdir(cacheStaging.templateRoot, { recursive: true });\n await extractTar({ file: archiveFile, cwd: cacheStaging.templateRoot });\n await normalizeExtractedTemplate(\n cacheStaging.stagingRoot,\n cacheStaging.templateRoot\n );\n await rm(archiveFile, { force: true });\n await cacheStaging.commit();\n return {\n root: path.join(cacheStaging.entryRoot, \"template\"),\n source: `${source} (archive)`,\n async cleanup() {}\n };\n } catch (error) {\n await cacheStaging.cleanup();\n throw error;\n }\n}\n\nexport async function acquireTemplate(\n source: string,\n ref: string,\n options: { noCache?: boolean; cacheTtlMinutes?: number } = {}\n): Promise<AcquiredTemplate> {\n const localPath = path.resolve(source);\n if (existsSync(localPath)) {\n if (await isDirectory(localPath)) {\n return {\n root: localPath,\n source: localPath,\n async cleanup() {}\n };\n }\n if (isArchiveSource(localPath)) {\n return acquireArchiveTemplate(localPath, ref, options);\n }\n throw new Error(`模板源不是目录或支持的 tar 压缩包: ${localPath}`);\n }\n\n if (isArchiveSource(source)) {\n return acquireArchiveTemplate(source, ref, options);\n }\n\n if (!isGitSource(source)) {\n throw new Error(`模板源不存在: ${source}`);\n }\n\n const cached = await getFreshCache(source, ref, options);\n if (cached) return cached;\n\n const cacheStaging = await createTemplateCacheStaging(source, ref);\n try {\n await runCommand(\n \"git\",\n [\n \"-c\",\n \"http.lowSpeedLimit=1024\",\n \"-c\",\n \"http.lowSpeedTime=15\",\n \"clone\",\n \"--depth\",\n \"1\",\n \"--branch\",\n ref,\n source,\n cacheStaging.templateRoot\n ],\n { stdio: \"pipe\", env: { GIT_TERMINAL_PROMPT: \"0\" } }\n );\n await cacheStaging.commit();\n return {\n root: path.join(cacheStaging.entryRoot, \"template\"),\n source: `${source}#${ref}`,\n async cleanup() {}\n };\n } catch (error) {\n await cacheStaging.cleanup();\n throw error;\n }\n}\n\nexport async function acquireTemplateFromSources(\n sources: string[],\n ref: string,\n options: { noCache?: boolean; cacheTtlMinutes?: number } = {}\n): Promise<AcquiredTemplate> {\n if (!sources.length) throw new Error(\"没有可用的模板源\");\n const failures: string[] = [];\n for (const source of [...new Set(sources)]) {\n try {\n return await acquireTemplate(source, ref, options);\n } catch (error) {\n failures.push(`${source}: ${(error as Error).message}`);\n }\n }\n throw new Error(`所有模板源均不可用:\\n- ${failures.join(\"\\n- \")}`);\n}\n","import { spawn } from \"node:child_process\";\n\nexport interface RunCommandOptions {\n cwd?: string;\n stdio?: \"inherit\" | \"pipe\";\n env?: NodeJS.ProcessEnv;\n}\n\nexport function platformCommand(command: string): string {\n if (process.platform !== \"win32\") return command;\n return command === \"pnpm\" || command === \"npm\" || command === \"npx\"\n ? `${command}.cmd`\n : command;\n}\n\nexport async function runCommand(\n command: string,\n args: string[],\n options: RunCommandOptions = {}\n): Promise<string> {\n const stdio = options.stdio ?? \"inherit\";\n return new Promise((resolve, reject) => {\n const executable = platformCommand(command);\n const isWindowsCommand =\n process.platform === \"win32\" && executable.endsWith(\".cmd\");\n const spawnExecutable = isWindowsCommand\n ? process.env.ComSpec || \"cmd.exe\"\n : executable;\n const spawnArgs = isWindowsCommand\n ? [\"/d\", \"/s\", \"/c\", executable, ...args]\n : args;\n const child = spawn(spawnExecutable, spawnArgs, {\n cwd: options.cwd,\n stdio,\n env: { ...process.env, ...options.env },\n windowsHide: true\n });\n\n let output = \"\";\n if (stdio === \"pipe\") {\n child.stdout?.on(\"data\", (chunk) => {\n output += chunk.toString();\n });\n child.stderr?.on(\"data\", (chunk) => {\n output += chunk.toString();\n });\n }\n\n child.on(\"error\", reject);\n child.on(\"exit\", (code) => {\n if (code === 0) {\n resolve(output.trim());\n return;\n }\n reject(\n new Error(\n `${command} ${args.join(\" \")} 执行失败(exit ${code ?? \"unknown\"})${output ? `\\n${output.trim()}` : \"\"}`\n )\n );\n });\n });\n}\n\nexport async function inspectCommand(\n command: string,\n args: string[] = [\"--version\"]\n): Promise<{ ok: boolean; output: string }> {\n try {\n return { ok: true, output: await runCommand(command, args, { stdio: \"pipe\" }) };\n } catch (error) {\n return { ok: false, output: (error as Error).message };\n }\n}\n","import { createHash } from \"node:crypto\";\nimport { existsSync } from \"node:fs\";\nimport { mkdir, readdir, rename, stat } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { getJh4jHome } from \"./user-config.js\";\nimport { readJson, removePath, writeJson } from \"../utils/fs.js\";\nimport type { TemplateCacheMetadata } from \"../types.js\";\n\nconst CACHE_SCHEMA_VERSION = 1;\n\nexport interface TemplateCacheEntry {\n key: string;\n root: string;\n metadata: TemplateCacheMetadata;\n sizeBytes: number;\n}\n\nexport function getTemplateCacheRoot(): string {\n return path.join(getJh4jHome(), \"cache\", \"templates\");\n}\n\nexport function getTemplateCacheKey(source: string, ref: string): string {\n return createHash(\"sha256\").update(`${source}\\0${ref}`).digest(\"hex\").slice(0, 20);\n}\n\nfunction getEntryPaths(key: string) {\n const entryRoot = path.join(getTemplateCacheRoot(), key);\n return {\n entryRoot,\n templateRoot: path.join(entryRoot, \"template\"),\n metadataPath: path.join(entryRoot, \"metadata.json\")\n };\n}\n\nexport async function readTemplateCacheEntry(\n source: string,\n ref: string\n): Promise<TemplateCacheEntry | null> {\n const key = getTemplateCacheKey(source, ref);\n const paths = getEntryPaths(key);\n if (!existsSync(paths.templateRoot) || !existsSync(paths.metadataPath)) return null;\n try {\n const metadata = await readJson<TemplateCacheMetadata>(paths.metadataPath);\n if (\n metadata.schemaVersion !== CACHE_SCHEMA_VERSION ||\n metadata.source !== source ||\n metadata.ref !== ref\n ) {\n return null;\n }\n return {\n key,\n root: paths.templateRoot,\n metadata,\n sizeBytes: await calculateDirectorySize(paths.entryRoot)\n };\n } catch {\n return null;\n }\n}\n\nexport function isTemplateCacheFresh(\n entry: TemplateCacheEntry,\n ttlMinutes: number\n): boolean {\n if (ttlMinutes <= 0) return false;\n const cachedAt = Date.parse(entry.metadata.cachedAt);\n return Number.isFinite(cachedAt) && Date.now() - cachedAt < ttlMinutes * 60_000;\n}\n\nexport async function createTemplateCacheStaging(\n source: string,\n ref: string\n): Promise<{\n key: string;\n entryRoot: string;\n stagingRoot: string;\n templateRoot: string;\n commit(): Promise<void>;\n cleanup(): Promise<void>;\n}> {\n const key = getTemplateCacheKey(source, ref);\n const cacheRoot = getTemplateCacheRoot();\n await mkdir(cacheRoot, { recursive: true });\n const stagingRoot = path.join(\n cacheRoot,\n `.${key}.tmp-${process.pid}-${Date.now()}`\n );\n const templateRoot = path.join(stagingRoot, \"template\");\n const entryRoot = path.join(cacheRoot, key);\n await mkdir(stagingRoot, { recursive: true });\n\n return {\n key,\n entryRoot,\n stagingRoot,\n templateRoot,\n async commit() {\n await writeJson(path.join(stagingRoot, \"metadata.json\"), {\n schemaVersion: CACHE_SCHEMA_VERSION,\n source,\n ref,\n cachedAt: new Date().toISOString()\n } satisfies TemplateCacheMetadata);\n await removePath(entryRoot);\n await rename(stagingRoot, entryRoot);\n },\n cleanup: () => removePath(stagingRoot)\n };\n}\n\nasync function calculateDirectorySize(directory: string): Promise<number> {\n let total = 0;\n const entries = await readdir(directory, { withFileTypes: true });\n for (const entry of entries) {\n const absolute = path.join(directory, entry.name);\n if (entry.isDirectory()) total += await calculateDirectorySize(absolute);\n else if (entry.isFile()) total += (await stat(absolute)).size;\n }\n return total;\n}\n\nexport async function listTemplateCache(): Promise<TemplateCacheEntry[]> {\n const cacheRoot = getTemplateCacheRoot();\n if (!existsSync(cacheRoot)) return [];\n const entries: TemplateCacheEntry[] = [];\n for (const directory of await readdir(cacheRoot, { withFileTypes: true })) {\n if (!directory.isDirectory() || directory.name.startsWith(\".\")) continue;\n const paths = getEntryPaths(directory.name);\n if (!existsSync(paths.metadataPath) || !existsSync(paths.templateRoot)) continue;\n try {\n entries.push({\n key: directory.name,\n root: paths.templateRoot,\n metadata: await readJson<TemplateCacheMetadata>(paths.metadataPath),\n sizeBytes: await calculateDirectorySize(paths.entryRoot)\n });\n } catch {\n // 损坏条目由 clear 或下一次拉取覆盖。\n }\n }\n return entries.sort((a, b) =>\n b.metadata.cachedAt.localeCompare(a.metadata.cachedAt)\n );\n}\n\nexport async function clearTemplateCache(): Promise<void> {\n await removePath(getTemplateCacheRoot());\n}\n","import os from \"node:os\";\nimport path from \"node:path\";\nimport { existsSync } from \"node:fs\";\nimport { JH4J_HOME_ENV, USER_CONFIG_SCHEMA_VERSION } from \"../constants.js\";\nimport { readJson, writeJson } from \"../utils/fs.js\";\nimport type { UserConfig } from \"../types.js\";\n\nexport const DEFAULT_USER_CONFIG: UserConfig = {\n schemaVersion: USER_CONFIG_SCHEMA_VERSION,\n autoInstall: false,\n autoGit: true,\n cacheTtlMinutes: 60\n};\n\nexport function getJh4jHome(): string {\n return path.resolve(process.env[JH4J_HOME_ENV] || path.join(os.homedir(), \".jh4j\"));\n}\n\nexport function getUserConfigPath(): string {\n return path.join(getJh4jHome(), \"config.json\");\n}\n\nexport async function loadUserConfig(): Promise<UserConfig> {\n const configPath = getUserConfigPath();\n if (!existsSync(configPath)) return { ...DEFAULT_USER_CONFIG };\n\n const stored = await readJson<Partial<UserConfig>>(configPath);\n if (\n stored.schemaVersion !== undefined &&\n stored.schemaVersion !== USER_CONFIG_SCHEMA_VERSION\n ) {\n throw new Error(\n `不支持的用户配置版本: ${stored.schemaVersion},当前要求 ${USER_CONFIG_SCHEMA_VERSION}`\n );\n }\n return { ...DEFAULT_USER_CONFIG, ...stored };\n}\n\nexport async function saveUserConfig(config: UserConfig): Promise<void> {\n await writeJson(getUserConfigPath(), {\n ...config,\n schemaVersion: USER_CONFIG_SCHEMA_VERSION\n });\n}\n\nconst CONFIG_KEYS = new Set<keyof UserConfig>([\n \"catalogFile\",\n \"templateSource\",\n \"templateRef\",\n \"npmRegistry\",\n \"jhlcRegistry\",\n \"autoInstall\",\n \"autoGit\",\n \"cacheTtlMinutes\"\n]);\n\nexport function parseUserConfigValue(\n key: string,\n rawValue: string\n): [keyof UserConfig, UserConfig[keyof UserConfig]] {\n if (!CONFIG_KEYS.has(key as keyof UserConfig)) {\n throw new Error(`不支持的配置项: ${key}`);\n }\n const typedKey = key as keyof UserConfig;\n if (typedKey === \"autoInstall\" || typedKey === \"autoGit\") {\n const normalized = rawValue.toLowerCase();\n if (!new Set([\"true\", \"false\"]).has(normalized)) {\n throw new Error(`${key} 只能是 true 或 false`);\n }\n return [typedKey, normalized === \"true\"];\n }\n if (typedKey === \"cacheTtlMinutes\") {\n const value = Number(rawValue);\n if (!Number.isInteger(value) || value < 0 || value > 10080) {\n throw new Error(\"cacheTtlMinutes 必须是 0 到 10080 之间的整数\");\n }\n return [typedKey, value];\n }\n return [typedKey, rawValue.trim()];\n}\n","import * as prompts from \"@clack/prompts\";\nimport { findTemplate, loadCatalog } from \"../catalog.js\";\nimport {\n generateProject,\n normalizeProjectName\n} from \"../core/project-generator.js\";\nimport { loadUserConfig } from \"../core/user-config.js\";\nimport type {\n CatalogTemplate,\n CreateOptions,\n TemplateCategory\n} from \"../types.js\";\n\nconst CATEGORY_OPTIONS: Array<{\n value: TemplateCategory;\n label: string;\n}> = [\n { value: \"frontend\", label: \"PC 前端 · Vue 3 / 微前端\" },\n { value: \"backend\", label: \"后端服务 · Java / 云原生\" },\n { value: \"mobile\", label: \"移动端 H5 · Vue 3 / Vant\" }\n];\n\nfunction isCategory(value: string): value is TemplateCategory {\n return CATEGORY_OPTIONS.some((item) => item.value === value);\n}\n\nexport function templatesByCategory(\n templates: CatalogTemplate[],\n category: TemplateCategory\n): CatalogTemplate[] {\n return templates.filter((template) => template.category === category);\n}\n\nexport function categoryOptionsFor(\n templates: CatalogTemplate[]\n): Array<{ value: TemplateCategory; label: string }> {\n return CATEGORY_OPTIONS.filter(\n (item) => templatesByCategory(templates, item.value).length > 0\n ).map(({ value, label }) => ({ value, label }));\n}\n\nasync function selectCategory(\n templates: CatalogTemplate[],\n requestedCategory: string | undefined,\n nonInteractive: boolean\n): Promise<TemplateCategory> {\n if (requestedCategory) {\n if (!isCategory(requestedCategory)) {\n throw new Error(\n `项目类型无效: ${requestedCategory}。可用值: frontend、backend、mobile`\n );\n }\n if (!templatesByCategory(templates, requestedCategory).length) {\n throw new Error(`项目类型 ${requestedCategory} 暂无可用模板`);\n }\n return requestedCategory;\n }\n\n const firstAvailable = CATEGORY_OPTIONS.find(\n (item) => templatesByCategory(templates, item.value).length > 0\n );\n if (!firstAvailable) throw new Error(\"Catalog 中没有可用模板\");\n if (nonInteractive) return firstAvailable.value;\n\n const availableOptions = categoryOptionsFor(templates);\n if (availableOptions.length === 1) return availableOptions[0].value;\n\n const selected = await prompts.select({\n message: \"选择项目类型\",\n options: availableOptions.map((item) => ({\n value: item.value,\n label: item.label\n }))\n });\n if (prompts.isCancel(selected)) throw new Error(\"用户取消创建\");\n return selected as TemplateCategory;\n}\n\nasync function selectTemplate(\n templates: CatalogTemplate[],\n options: CreateOptions\n): Promise<CatalogTemplate> {\n if (options.template) {\n const selected = findTemplate(templates, options.template);\n if (options.category && selected.category !== options.category) {\n throw new Error(\n `模板 ${selected.id} 属于 ${selected.category},与 --category ${options.category} 不一致`\n );\n }\n return selected;\n }\n\n const category = await selectCategory(\n templates,\n options.category,\n Boolean(options.yes)\n );\n const candidates = templatesByCategory(templates, category);\n if (options.yes) return findTemplate(candidates);\n if (candidates.length === 1) {\n const selected = candidates[0];\n prompts.log.info(`使用模板:${selected.name}`);\n return selected;\n }\n\n const selected = await prompts.select({\n message: \"选择项目模板\",\n options: candidates.map((template) => ({\n value: template.id,\n label: `${template.name} · ${template.description}`\n }))\n });\n if (prompts.isCancel(selected)) throw new Error(\"用户取消创建\");\n return findTemplate(candidates, String(selected));\n}\n\nexport async function createCommand(\n requestedName: string | undefined,\n options: CreateOptions\n): Promise<void> {\n prompts.intro(\"JH4J Cloud 项目创建\");\n const userConfig = await loadUserConfig();\n const catalog = await loadCatalog(userConfig);\n const template = await selectTemplate(catalog, options);\n\n let projectName = requestedName;\n if (!projectName) {\n if (options.yes) throw new Error(\"非交互模式必须指定项目名称\");\n const defaultProjectName =\n template.category === \"mobile\" ? \"jh4j-mobile-app\" : \"jh4j-ui-app\";\n const answer = await prompts.text({\n message: \"项目名称\",\n placeholder: defaultProjectName,\n defaultValue: defaultProjectName,\n validate(value) {\n return !value || normalizeProjectName(value)\n ? undefined\n : \"请输入至少一个字母或数字,例如 jh4j-mobile-app\";\n }\n });\n if (prompts.isCancel(answer)) throw new Error(\"用户取消创建\");\n projectName = String(answer).trim() || defaultProjectName;\n }\n\n const rawProjectName = projectName;\n projectName = normalizeProjectName(rawProjectName);\n if (!projectName) {\n throw new Error(\"项目名称至少需要包含一个字母或数字\");\n }\n if (projectName !== rawProjectName) {\n prompts.log.info(`项目名称已规范化:${projectName}`);\n }\n\n const result = await generateProject(\n template,\n projectName,\n options,\n process.cwd(),\n userConfig\n );\n if (options.dryRun) {\n prompts.outro(\"Dry Run 完成,未写入任何项目文件\");\n return;\n }\n\n prompts.note(\n [\n `目录: ${result.targetRoot}`,\n `模板: ${result.templateId}@${result.templateVersion}`,\n `来源: ${result.source}`,\n `默认能力: ${result.features.length ? result.features.join(\", \") : \"无\"}`,\n `依赖: ${result.installed ? \"已安装\" : \"未安装(默认由开发者手动安装)\"}`,\n `Git: ${result.gitInitialized ? \"main 已初始化\" : \"未初始化\"}`,\n \"\",\n \"需要调整配置时,直接修改生成项目中的:\",\n \" project.config.json 项目、联调与环境参数\",\n \" .npmrc Registry 配置\",\n \" .env* 各端运行环境配置(如存在)\",\n \"\",\n `cd ${projectName}`,\n ...(!result.installed ? [\"pnpm install\"] : []),\n \"pnpm dev\"\n ].join(\"\\n\"),\n \"创建成功\"\n );\n prompts.outro(\"项目已准备好\");\n}\n","import { existsSync } from \"node:fs\";\nimport { rename, rm } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport * as prompts from \"@clack/prompts\";\nimport { satisfies } from \"semver\";\nimport { CLI_NAME, CLI_VERSION } from \"../constants.js\";\nimport {\n copyTemplateTree,\n isDirectoryEmpty,\n readJson,\n removePath,\n writeJson\n} from \"../utils/fs.js\";\nimport { runCommand } from \"../utils/process.js\";\nimport {\n acquireTemplateFromSources,\n resolveTemplateSources\n} from \"./template-source.js\";\nimport { loadTemplateManifest } from \"./template-manifest.js\";\nimport { DEFAULT_USER_CONFIG } from \"./user-config.js\";\nimport type {\n CatalogTemplate,\n CreateOptions,\n ProjectInput,\n TemplateManifest,\n UserConfig\n} from \"../types.js\";\n\nconst ENV_NAMES = [\"dev\", \"sit\", \"uat\", \"pre\", \"prd\"] as const;\ntype PartialProjectInput = Partial<Omit<ProjectInput, \"environments\">> & {\n environments?: Partial<ProjectInput[\"environments\"]>;\n};\n\nfunction cancelled(value: unknown): value is symbol {\n return prompts.isCancel(value);\n}\n\nexport function normalizeProjectName(value: string): string {\n return value\n .trim()\n .toLowerCase()\n .replace(/\\s+/g, \"-\")\n .replace(/^[._-]+/, \"\")\n .replace(/[^a-z0-9._-]+/g, \"-\")\n .replace(/-{2,}/g, \"-\")\n .replace(/[-._]+$/, \"\");\n}\n\nfunction ensureProjectName(value: string): string {\n const name = normalizeProjectName(value);\n if (!/^[a-z0-9][a-z0-9._-]*$/.test(name)) {\n throw new Error(\"项目名称至少需要包含一个字母或数字\");\n }\n return name;\n}\n\nfunction inferModuleName(projectName: string): string {\n const inferred = projectName\n .replace(/^(?:jh4j|wl)-ui-/, \"\")\n .replace(/[^a-z0-9-]/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n return /^[a-z][a-z0-9-]*$/.test(inferred) ? inferred : \"app\";\n}\n\nfunction ensureModuleName(value: string): string {\n const name = value.trim();\n if (!/^[a-z][a-z0-9-]*$/.test(name)) {\n throw new Error(\"模块标识必须以小写字母开头,只能包含小写字母、数字和连字符\");\n }\n return name;\n}\n\nfunction ensurePort(value: string | number): number {\n const port = Number(value);\n if (!Number.isInteger(port) || port < 1024 || port > 65535) {\n throw new Error(\"开发端口必须是 1024 到 65535 之间的整数\");\n }\n return port;\n}\n\nfunction ensureHttpUrl(value: string, label: string): string {\n try {\n const url = new URL(value);\n if (url.protocol !== \"http:\" && url.protocol !== \"https:\") throw new Error();\n return value.replace(/\\/+$/, \"\");\n } catch {\n throw new Error(`${label} 必须是 http/https URL`);\n }\n}\n\nasync function askText(\n message: string,\n initialValue: string,\n validate?: (value: string | undefined) => string | undefined\n): Promise<string> {\n const answer = await prompts.text({\n message,\n placeholder: initialValue,\n defaultValue: initialValue,\n validate\n });\n if (cancelled(answer)) throw new Error(\"用户取消创建\");\n return String(answer).trim() || initialValue;\n}\n\nasync function loadCreateConfig(\n configFile: string | undefined,\n cwd: string\n): Promise<PartialProjectInput> {\n if (!configFile) return {};\n const resolved = path.resolve(cwd, configFile);\n if (!existsSync(resolved)) throw new Error(`创建配置文件不存在: ${resolved}`);\n return readJson<PartialProjectInput>(resolved);\n}\n\nfunction parseFeatureIds(value: string): string[] {\n return [...new Set(value.split(\",\").map((item) => item.trim()).filter(Boolean))];\n}\n\nasync function collectTemplateFeatures(\n manifest: TemplateManifest,\n fileConfig: PartialProjectInput,\n options: CreateOptions\n): Promise<string[]> {\n const available = manifest.features ?? [];\n if (!available.length) return [];\n\n const knownIds = new Set(available.map((feature) => feature.id));\n let selected = options.features\n ? parseFeatureIds(options.features)\n : Array.isArray(fileConfig.features)\n ? fileConfig.features\n : available\n .filter((feature) => feature.defaultEnabled || feature.required)\n .map((feature) => feature.id);\n\n const unknown = selected.filter((id) => !knownIds.has(id));\n if (unknown.length) {\n throw new Error(\n `模板不支持以下能力: ${unknown.join(\", \")}。可用能力: ${[...knownIds].join(\", \")}`\n );\n }\n\n if (options.standards === false) {\n selected = selected.filter((id) => {\n const feature = available.find((item) => item.id === id);\n return feature?.package !== \"@robot-admin/git-standards\";\n });\n }\n\n for (const feature of available) {\n if (feature.required && !selected.includes(feature.id)) {\n selected.push(feature.id);\n }\n }\n return selected;\n}\n\nasync function collectProjectInput(\n projectName: string,\n manifest: TemplateManifest,\n sourceConfig: ProjectInput,\n fileConfig: PartialProjectInput,\n options: CreateOptions,\n userConfig: UserConfig,\n features: string[]\n): Promise<ProjectInput> {\n let moduleName = options.module ?? fileConfig.moduleName ?? inferModuleName(projectName);\n let title = options.title ?? fileConfig.title ?? sourceConfig.title;\n let port: string | number =\n options.port ?? fileConfig.devServerPort ?? sourceConfig.devServerPort;\n let npmRegistry =\n options.npmRegistry ??\n fileConfig.npmRegistry ??\n userConfig.npmRegistry ??\n sourceConfig.npmRegistry;\n let jhlcRegistry =\n options.jhlcRegistry ??\n fileConfig.jhlcRegistry ??\n userConfig.jhlcRegistry ??\n sourceConfig.jhlcRegistry;\n let localBackendUrl =\n options.localBackend ?? fileConfig.localBackendUrl ?? sourceConfig.localBackendUrl;\n let localPublicUrl =\n options.localPublic ?? fileConfig.localPublicUrl ?? sourceConfig.localPublicUrl;\n const environments = structuredClone(sourceConfig.environments);\n for (const [env, value] of Object.entries(fileConfig.environments ?? {})) {\n if (value && environments[env]) {\n environments[env] = { ...environments[env], ...value };\n }\n }\n\n if (!options.yes) {\n title = await askText(\n manifest.category === \"mobile\" ? \"应用标题\" : \"系统标题\",\n title,\n (value) => (value?.trim() ? undefined : \"标题不能为空\")\n );\n port = await askText(\"开发端口\", String(port), (value) => {\n const parsed = Number(value);\n return Number.isInteger(parsed) && parsed >= 1024 && parsed <= 65535\n ? undefined\n : \"请输入 1024 到 65535 之间的端口\";\n });\n localBackendUrl = await askText(\n manifest.category === \"mobile\" ? \"本地 API 地址\" : \"本地后端地址\",\n localBackendUrl,\n (value) => {\n try {\n const url = new URL(value ?? \"\");\n return url.protocol === \"http:\" || url.protocol === \"https:\"\n ? undefined\n : \"请输入 http/https 地址\";\n } catch {\n return \"请输入完整的 http/https 地址\";\n }\n }\n );\n }\n\n if (!title.trim()) throw new Error(\"系统标题不能为空\");\n for (const env of ENV_NAMES) {\n if (!environments[env]) throw new Error(`缺少 ${env.toUpperCase()} 环境配置`);\n environments[env] = {\n webUrl: ensureHttpUrl(environments[env].webUrl, `${env.toUpperCase()} 平台地址`),\n apiPrefix: environments[env].apiPrefix.replace(/^\\/+|\\/+$/g, \"\")\n };\n if (!environments[env].apiPrefix) {\n throw new Error(`${env.toUpperCase()} API 前缀不能为空`);\n }\n }\n\n return {\n projectName,\n moduleName: ensureModuleName(moduleName),\n title: title.trim(),\n devServerPort: ensurePort(port),\n npmRegistry: ensureHttpUrl(npmRegistry, \"npm registry\"),\n jhlcRegistry: ensureHttpUrl(jhlcRegistry, \"@jhlc 私有 registry\"),\n localBackendUrl: ensureHttpUrl(localBackendUrl, \"本地后端地址\"),\n localPublicUrl: ensureHttpUrl(localPublicUrl, \"本地 public 地址\"),\n environments,\n features\n };\n}\n\nfunction assertSafeTarget(cwd: string, target: string): void {\n if (path.dirname(target) !== cwd || target === cwd) {\n throw new Error(\"仅允许在当前目录创建一级项目目录\");\n }\n}\n\nasync function promoteStaging(\n stagingRoot: string,\n targetRoot: string,\n force: boolean\n): Promise<void> {\n const targetExists = existsSync(targetRoot);\n if (!targetExists) {\n await rename(stagingRoot, targetRoot);\n return;\n }\n\n if (!(await isDirectoryEmpty(targetRoot)) && !force) {\n throw new Error(`目标目录已存在且非空: ${targetRoot}`);\n }\n\n const backupRoot = `${targetRoot}.jh4j-backup-${Date.now()}`;\n await rename(targetRoot, backupRoot);\n try {\n await rename(stagingRoot, targetRoot);\n } catch (error) {\n await rename(backupRoot, targetRoot);\n throw error;\n }\n try {\n await removePath(backupRoot);\n } catch {\n prompts.log.warn(`旧目录备份未能自动清理: ${backupRoot}`);\n }\n}\n\nexport interface GenerateProjectResult {\n targetRoot: string;\n templateId: string;\n templateVersion: string;\n source: string;\n features: string[];\n installed: boolean;\n gitInitialized: boolean;\n}\n\nexport async function generateProject(\n catalogTemplate: CatalogTemplate,\n requestedProjectName: string,\n options: CreateOptions,\n cwd = process.cwd(),\n configuredUserConfig: UserConfig = DEFAULT_USER_CONFIG\n): Promise<GenerateProjectResult> {\n const userConfig = { ...DEFAULT_USER_CONFIG, ...configuredUserConfig };\n const projectName = ensureProjectName(requestedProjectName);\n const resolvedCwd = path.resolve(cwd);\n const targetRoot = path.resolve(resolvedCwd, projectName);\n assertSafeTarget(resolvedCwd, targetRoot);\n if (\n existsSync(targetRoot) &&\n !(await isDirectoryEmpty(targetRoot)) &&\n !options.force\n ) {\n throw new Error(`目标目录已存在且非空: ${targetRoot}`);\n }\n\n const ref = options.ref ?? userConfig.templateRef ?? catalogTemplate.defaultRef;\n const sourceValues = resolveTemplateSources(\n catalogTemplate,\n options.source,\n userConfig.templateSource\n );\n const acquisitionSpinner = options.yes\n ? undefined\n : prompts.spinner({ indicator: \"timer\" });\n acquisitionSpinner?.start(\"正在获取并校验模板\");\n let acquired: Awaited<ReturnType<typeof acquireTemplateFromSources>>;\n try {\n acquired = await acquireTemplateFromSources(sourceValues, ref, {\n noCache: options.cache === false,\n cacheTtlMinutes: userConfig.cacheTtlMinutes\n });\n acquisitionSpinner?.stop(\"模板准备完成\");\n } catch (error) {\n acquisitionSpinner?.error(\"模板获取失败\");\n throw error;\n }\n const stagingRoot = path.join(\n resolvedCwd,\n `.${projectName}.jh4j-tmp-${process.pid}-${Date.now()}`\n );\n let promoted = false;\n\n try {\n const manifest = await loadTemplateManifest(acquired.root);\n if (manifest.id !== catalogTemplate.id) {\n throw new Error(\n `模板 ID 不匹配:Catalog=${catalogTemplate.id},Manifest=${manifest.id}`\n );\n }\n if (!satisfies(process.versions.node, manifest.runtime.node)) {\n throw new Error(\n `当前 Node ${process.versions.node} 不满足模板要求 ${manifest.runtime.node}`\n );\n }\n\n const sourceProjectConfig = await readJson<\n Omit<ProjectInput, \"npmRegistry\" | \"jhlcRegistry\">\n >(path.join(acquired.root, \"project.config.json\"));\n const fileConfig = await loadCreateConfig(options.config, resolvedCwd);\n const features = await collectTemplateFeatures(manifest, fileConfig, options);\n const input = await collectProjectInput(\n projectName,\n manifest,\n {\n ...sourceProjectConfig,\n npmRegistry: manifest.defaults.npmRegistry,\n jhlcRegistry: manifest.defaults.jhlcRegistry\n },\n fileConfig,\n options,\n userConfig,\n features\n );\n\n const shouldInstall =\n !options.skipInstall && (options.install === true || userConfig.autoInstall);\n const shouldInitializeGit = !options.skipGit && userConfig.autoGit;\n\n if (options.dryRun) {\n prompts.note(\n [\n `模板: ${manifest.id}@${manifest.version}`,\n `来源: ${acquired.source}`,\n `目标: ${targetRoot}`,\n `模块: ${input.moduleName}`,\n `端口: ${input.devServerPort}`,\n `能力: ${input.features.length ? input.features.join(\", \") : \"无可选能力\"}`,\n `安装依赖: ${shouldInstall ? \"是\" : \"否\"}`,\n `初始化 Git: ${shouldInitializeGit ? \"是\" : \"否\"}`\n ].join(\"\\n\"),\n \"Dry Run\"\n );\n return {\n targetRoot,\n templateId: manifest.id,\n templateVersion: manifest.version,\n source: acquired.source,\n features: input.features,\n installed: false,\n gitInitialized: false\n };\n }\n\n await copyTemplateTree(acquired.root, stagingRoot);\n const inputFile = path.join(stagingRoot, \".jh4j-cli-input.json\");\n await writeJson(inputFile, input);\n try {\n await runCommand(\n process.execPath,\n [\n path.join(stagingRoot, \"scripts\", \"setup-project.mjs\"),\n \"--yes\",\n \"--config\",\n inputFile,\n \"--created-by\",\n `${CLI_NAME}@${CLI_VERSION}`\n ],\n { cwd: stagingRoot, stdio: \"pipe\" }\n );\n } finally {\n await rm(inputFile, { force: true });\n }\n\n if (!existsSync(path.join(stagingRoot, manifest.generatedMetadata))) {\n throw new Error(`模板初始化未生成元数据: ${manifest.generatedMetadata}`);\n }\n await promoteStaging(stagingRoot, targetRoot, Boolean(options.force));\n promoted = true;\n\n let gitInitialized = false;\n if (shouldInitializeGit) {\n await runCommand(\"git\", [\"init\", \"-b\", \"main\"], {\n cwd: targetRoot,\n stdio: \"pipe\"\n });\n gitInitialized = true;\n }\n\n if (shouldInstall) {\n try {\n await runCommand(\"pnpm\", [\"install\"], { cwd: targetRoot });\n } catch (error) {\n throw new Error(\n `项目已生成,但依赖安装失败;目录已保留在 ${targetRoot}\\n${(error as Error).message}`\n );\n }\n }\n\n if (shouldInitializeGit) {\n await runCommand(\"git\", [\"add\", \"-A\"], { cwd: targetRoot, stdio: \"pipe\" });\n try {\n await runCommand(\n \"git\",\n [\"commit\", \"-m\", `feat(init): 基于 ${manifest.id}@${manifest.version} 初始化`],\n {\n cwd: targetRoot,\n stdio: \"pipe\",\n env: { HUSKY: \"0\" }\n }\n );\n } catch (error) {\n prompts.log.warn(`Git 已初始化,但初始提交未完成:${(error as Error).message}`);\n }\n }\n\n return {\n targetRoot,\n templateId: manifest.id,\n templateVersion: manifest.version,\n source: acquired.source,\n features: input.features,\n installed: shouldInstall,\n gitInitialized\n };\n } finally {\n if (!promoted && existsSync(stagingRoot)) await removePath(stagingRoot);\n await acquired.cleanup();\n }\n}\n","import path from \"node:path\";\nimport { readJson } from \"../utils/fs.js\";\nimport type { TemplateManifest } from \"../types.js\";\n\nexport async function loadTemplateManifest(\n templateRoot: string\n): Promise<TemplateManifest> {\n const manifest = await readJson<TemplateManifest>(\n path.join(templateRoot, \"template.manifest.json\")\n );\n const errors: string[] = [];\n\n if (manifest.schemaVersion !== 1) errors.push(\"schemaVersion 必须为 1\");\n if (!manifest.id) errors.push(\"缺少模板 id\");\n if (!manifest.name) errors.push(\"缺少模板名称\");\n if (!/^\\d+\\.\\d+\\.\\d+([+-].+)?$/.test(manifest.version ?? \"\")) {\n errors.push(\"模板 version 不是有效的语义化版本\");\n }\n if (!manifest.runtime?.node || !manifest.runtime?.packageManager) {\n errors.push(\"缺少模板运行时约束\");\n }\n if (!manifest.entry?.nonInteractive) {\n errors.push(\"缺少非交互初始化入口\");\n }\n const featureIds = new Set<string>();\n for (const feature of manifest.features ?? []) {\n if (!/^[a-z][a-z0-9-]*$/.test(feature.id)) {\n errors.push(`模板能力 id 无效: ${feature.id}`);\n }\n if (featureIds.has(feature.id)) {\n errors.push(`模板能力 id 重复: ${feature.id}`);\n }\n featureIds.add(feature.id);\n if (!feature.name || !feature.description) {\n errors.push(`模板能力 ${feature.id} 缺少名称或说明`);\n }\n }\n\n if (errors.length) {\n throw new Error(`模板 manifest 无效:\\n- ${errors.join(\"\\n- \")}`);\n }\n return manifest;\n}\n","import { existsSync } from \"node:fs\";\nimport { mkdir, writeFile, rm } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { coerce, gte, satisfies } from \"semver\";\nimport { loadCatalog } from \"../catalog.js\";\nimport { loadTemplateManifest } from \"../core/template-manifest.js\";\nimport { resolveTemplateSources } from \"../core/template-source.js\";\nimport { getJh4jHome, loadUserConfig } from \"../core/user-config.js\";\nimport { inspectCommand } from \"../utils/process.js\";\nimport type { CatalogTemplate, UserConfig } from \"../types.js\";\n\nexport interface CheckResult {\n name: string;\n ok: boolean;\n detail: string;\n}\n\nasync function checkHomeWritable(): Promise<CheckResult> {\n const home = getJh4jHome();\n const probe = path.join(home, `.write-probe-${process.pid}`);\n try {\n await mkdir(home, { recursive: true });\n await writeFile(probe, \"ok\", \"utf8\");\n await rm(probe, { force: true });\n return { name: \"JH4J_HOME\", ok: true, detail: home };\n } catch (error) {\n return { name: \"JH4J_HOME\", ok: false, detail: (error as Error).message };\n }\n}\n\nexport async function collectDoctorChecks(\n suppliedConfig?: UserConfig,\n suppliedCatalog?: CatalogTemplate[]\n): Promise<CheckResult[]> {\n const config = suppliedConfig ?? (await loadUserConfig());\n const catalog = suppliedCatalog ?? (await loadCatalog(config));\n const [git, pnpm, home] = await Promise.all([\n inspectCommand(\"git\"),\n inspectCommand(\"pnpm\"),\n checkHomeWritable()\n ]);\n const pnpmVersion = coerce(pnpm.output)?.version;\n const checks: CheckResult[] = [\n {\n name: \"Node.js\",\n ok: satisfies(process.versions.node, \"^22.12.0 || ^24.0.0\"),\n detail: `${process.versions.node}(要求 Node 22.12+ 或 24.x)`\n },\n { name: \"Git\", ok: git.ok, detail: git.output },\n {\n name: \"pnpm\",\n ok: pnpm.ok && Boolean(pnpmVersion && gte(pnpmVersion, \"11.8.0\")),\n detail: pnpm.output\n },\n home\n ];\n\n for (const template of catalog) {\n const sources = resolveTemplateSources(\n template,\n undefined,\n config.templateSource\n );\n const source = sources[0];\n if (!existsSync(source)) {\n checks.push({\n name: `模板 ${template.id}`,\n ok:\n source.startsWith(\"http://\") ||\n source.startsWith(\"https://\") ||\n source.startsWith(\"git@\"),\n detail: `远程候选源(创建时依次验证): ${sources.join(\" → \")}`\n });\n continue;\n }\n try {\n const manifest = await loadTemplateManifest(source);\n checks.push({\n name: `模板 ${template.id}`,\n ok:\n manifest.id === template.id &&\n satisfies(process.versions.node, manifest.runtime.node),\n detail: `${manifest.id}@${manifest.version} (${source})`\n });\n } catch (error) {\n checks.push({\n name: `模板 ${template.id}`,\n ok: false,\n detail: (error as Error).message\n });\n }\n }\n return checks;\n}\n\nexport async function doctorCommand(options: { json?: boolean } = {}): Promise<void> {\n const checks = await collectDoctorChecks();\n const failed = checks.filter((check) => !check.ok);\n if (options.json) {\n console.log(JSON.stringify({ ok: failed.length === 0, checks }, null, 2));\n } else {\n for (const check of checks) {\n console.log(`${check.ok ? \"✓\" : \"✗\"} ${check.name}: ${check.detail}`);\n }\n console.log(`\\n结果: ${checks.length - failed.length} 通过, ${failed.length} 失败`);\n }\n if (failed.length) process.exitCode = 1;\n}\n","import path from \"node:path\";\nimport { existsSync } from \"node:fs\";\nimport { readJson } from \"../utils/fs.js\";\nimport type { ProjectMetadata } from \"../types.js\";\n\nexport async function infoCommand(\n projectPath = process.cwd(),\n options: { json?: boolean } = {}\n): Promise<void> {\n const root = path.resolve(projectPath);\n const metadataPath = path.join(root, \".jhlc\", \"project.json\");\n if (!existsSync(metadataPath)) {\n throw new Error(`当前目录不是 JH4J CLI 创建的项目: ${metadataPath}`);\n }\n const metadata = await readJson<ProjectMetadata>(metadataPath);\n if (options.json) {\n console.log(JSON.stringify({ projectRoot: root, ...metadata }, null, 2));\n return;\n }\n console.log(`项目目录: ${root}`);\n console.log(`模板: ${metadata.template.id}@${metadata.template.version}`);\n console.log(`平台版本: ${metadata.platformVersion ?? \"未声明\"}`);\n console.log(`创建时间: ${metadata.createdAt}`);\n console.log(`创建工具: ${metadata.createdBy}`);\n console.log(\"项目参数:\");\n console.log(JSON.stringify(metadata.parameters, null, 2));\n}\n","import { loadCatalog } from \"../catalog.js\";\nimport { loadUserConfig } from \"../core/user-config.js\";\n\nexport async function listCommand(options: { json?: boolean } = {}): Promise<void> {\n const templates = await loadCatalog(await loadUserConfig());\n if (options.json) {\n console.log(JSON.stringify(templates, null, 2));\n return;\n }\n console.table(\n templates.map((template) => ({\n ID: template.id,\n 名称: template.name,\n 类型: template.category,\n 状态: template.status,\n 默认分支: template.defaultRef,\n 标签: template.tags?.join(\", \") ?? \"\"\n }))\n );\n}\n","import path from \"node:path\";\nimport { loadTemplateManifest } from \"../core/template-manifest.js\";\nimport { runCommand } from \"../utils/process.js\";\n\nexport async function validateTemplateCommand(templatePath: string): Promise<void> {\n const root = path.resolve(templatePath);\n const manifest = await loadTemplateManifest(root);\n await runCommand(process.execPath, [path.join(root, \"scripts\", \"validate-template.mjs\")], {\n cwd: root\n });\n console.log(`模板可用: ${manifest.id}@${manifest.version}`);\n}\n","import {\n DEFAULT_USER_CONFIG,\n getUserConfigPath,\n loadUserConfig,\n parseUserConfigValue,\n saveUserConfig\n} from \"../core/user-config.js\";\n\nexport async function configListCommand(options: { json?: boolean } = {}): Promise<void> {\n const config = await loadUserConfig();\n if (options.json) console.log(JSON.stringify(config, null, 2));\n else console.table(Object.entries(config).map(([key, value]) => ({ key, value })));\n console.log(`配置文件: ${getUserConfigPath()}`);\n}\n\nexport async function configGetCommand(key: string): Promise<void> {\n const config = await loadUserConfig();\n if (!(key in config)) throw new Error(`配置项不存在: ${key}`);\n console.log(String((config as unknown as Record<string, unknown>)[key]));\n}\n\nexport async function configSetCommand(key: string, value: string): Promise<void> {\n const config = await loadUserConfig();\n const [typedKey, typedValue] = parseUserConfigValue(key, value);\n (config as unknown as Record<string, unknown>)[typedKey] = typedValue;\n await saveUserConfig(config);\n console.log(`已设置 ${typedKey}=${String(typedValue)}`);\n}\n\nexport async function configUnsetCommand(key: string): Promise<void> {\n const config = await loadUserConfig();\n if (!(key in DEFAULT_USER_CONFIG) && !(key in config)) {\n throw new Error(`配置项不存在: ${key}`);\n }\n const defaults = DEFAULT_USER_CONFIG as unknown as Record<string, unknown>;\n const mutable = config as unknown as Record<string, unknown>;\n if (key in defaults) mutable[key] = defaults[key];\n else delete mutable[key];\n await saveUserConfig(config);\n console.log(`已重置配置项: ${key}`);\n}\n\nexport async function configResetCommand(): Promise<void> {\n await saveUserConfig({ ...DEFAULT_USER_CONFIG });\n console.log(`用户配置已恢复默认值: ${getUserConfigPath()}`);\n}\n","import {\n clearTemplateCache,\n getTemplateCacheRoot,\n listTemplateCache\n} from \"../core/template-cache.js\";\n\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 ** 2) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / 1024 ** 2).toFixed(1)} MB`;\n}\n\nexport async function cacheListCommand(options: { json?: boolean } = {}): Promise<void> {\n const entries = await listTemplateCache();\n if (options.json) {\n console.log(JSON.stringify(entries, null, 2));\n return;\n }\n if (!entries.length) {\n console.log(`模板缓存为空: ${getTemplateCacheRoot()}`);\n return;\n }\n console.table(\n entries.map((entry) => ({\n Key: entry.key,\n 来源: entry.metadata.source,\n Ref: entry.metadata.ref,\n 缓存时间: entry.metadata.cachedAt,\n 大小: formatBytes(entry.sizeBytes)\n }))\n );\n}\n\nexport async function cacheClearCommand(): Promise<void> {\n await clearTemplateCache();\n console.log(`模板缓存已清理: ${getTemplateCacheRoot()}`);\n}\n","import { runCli } from \"./cli.js\";\n\nrunCli().catch((error) => {\n console.error(`\\n错误: ${(error as Error).message}\\n`);\n process.exitCode = 1;\n});\n"],"mappings":";;;AAAA,SAAS,eAAe;;;ACAxB;AAAA,EACE,MAAQ;AAAA,EACR,SAAW;AAAA,EACX,aAAe;AAAA,EACf,YAAc;AAAA,IACZ,MAAQ;AAAA,IACR,KAAO;AAAA,EACT;AAAA,EACA,UAAY;AAAA,EACZ,MAAQ;AAAA,IACN,KAAO;AAAA,EACT;AAAA,EACA,MAAQ;AAAA,EACR,SAAW;AAAA,IACT,MAAQ;AAAA,IACR,MAAQ;AAAA,EACV;AAAA,EACA,gBAAkB;AAAA,EAClB,KAAO;AAAA,IACL,MAAQ;AAAA,EACV;AAAA,EACA,OAAS;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,SAAW;AAAA,IACT,OAAS;AAAA,IACT,KAAO;AAAA,IACP,WAAa;AAAA,IACb,MAAQ;AAAA,IACR,cAAc;AAAA,IACd,OAAS;AAAA,IACT,OAAS;AAAA,IACT,SAAW;AAAA,EACb;AAAA,EACA,cAAgB;AAAA,IACd,kBAAkB;AAAA,IAClB,WAAa;AAAA,IACb,QAAU;AAAA,IACV,KAAO;AAAA,EACT;AAAA,EACA,eAAiB;AAAA,IACf,QAAU;AAAA,IACV,UAAY;AAAA,EACd;AAAA,EACA,iBAAmB;AAAA,IACjB,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,MAAQ;AAAA,IACR,YAAc;AAAA,IACd,QAAU;AAAA,EACZ;AACF;;;ACrDO,IAAM,WAAW;AACjB,IAAM,cAAc,gBAAY;AAChC,IAAM,eAAe;AAErB,IAAM,sBAAsB;AAC5B,IAAM,gBAAgB;AACtB,IAAM,mBAAmB;AACzB,IAAM,6BAA6B;;;ACT1C,SAAS,qBAAqB;AAC9B,OAAOA,WAAU;AACjB,SAAS,cAAAC,mBAAkB;;;ACF3B,SAAS,IAAI,OAAO,UAAU,IAAI,MAAM,iBAAiB;AACzD,SAAS,kBAAkB;AAC3B,OAAO,UAAU;AAEjB,IAAM,0BAA0B,oBAAI,IAAI;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,eAAsB,SAAY,MAA0B;AAC1D,SAAO,KAAK,MAAM,MAAM,SAAS,MAAM,MAAM,CAAC;AAChD;AAEA,eAAsB,UAAU,MAAc,OAA+B;AAC3E,QAAM,MAAM,KAAK,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AACnD,QAAM,UAAU,MAAM,GAAG,KAAK,UAAU,OAAO,MAAM,CAAC,CAAC;AAAA,GAAM,MAAM;AACrE;AAEA,eAAsB,YAAY,WAAqC;AACrE,MAAI;AACF,YAAQ,MAAM,KAAK,SAAS,GAAG,YAAY;AAAA,EAC7C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,iBAAiB,WAAqC;AAC1E,MAAI,CAAC,WAAW,SAAS,EAAG,QAAO;AACnC,QAAM,EAAE,SAAAC,SAAQ,IAAI,MAAM,OAAO,aAAkB;AACnD,UAAQ,MAAMA,SAAQ,SAAS,GAAG,WAAW;AAC/C;AAEA,eAAsB,iBACpB,YACA,YACe;AACf,QAAM,MAAM,YAAY,EAAE,WAAW,KAAK,CAAC;AAC3C,QAAM,GAAG,YAAY,YAAY;AAAA,IAC/B,WAAW;AAAA,IACX,OAAO;AAAA,IACP,OAAO,QAAQ;AACb,YAAM,WAAW,KAAK,SAAS,YAAY,MAAM;AACjD,UAAI,CAAC,SAAU,QAAO;AACtB,YAAM,CAAC,QAAQ,IAAI,SAAS,MAAM,KAAK,GAAG;AAC1C,aAAO,CAAC,wBAAwB,IAAI,QAAQ;AAAA,IAC9C;AAAA,EACF,CAAC;AACH;AAEA,eAAsB,WAAW,QAA+B;AAC9D,QAAM,GAAG,QAAQ,EAAE,WAAW,MAAM,OAAO,MAAM,YAAY,EAAE,CAAC;AAClE;;;AD9CA,IAAM,sBAAsB;AAAA,EAC1B,IAAI,IAAI,2BAA2B,YAAY,GAAG;AACpD;AACA,IAAM,4BAA4B;AAAA,EAChC,IAAI,IAAI,sBAAsB,YAAY,GAAG;AAC/C;AACA,IAAM,wBAAwB;AAAA,EAC5B;AAAA,EACA;AACF;AACA,IAAM,8BAA8B;AAAA,EAClC;AAAA,EACA;AACF;AAEO,IAAM,oBAAuC;AAAA,EAClD;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,mBAAmB;AAAA,IACnB,eAAeC,YAAW,mBAAmB,IACzC,sBACA,sBAAsB,CAAC;AAAA,IAC3B,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,MAAM,CAAC,OAAO,QAAQ,qBAAqB,IAAI;AAAA,EACjD;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,mBAAmB;AAAA,IACnB,eAAeA,YAAW,yBAAyB,IAC/C,4BACA,4BAA4B,CAAC;AAAA,IACjC,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,MAAM,CAAC,OAAO,QAAQ,QAAQ,MAAM,QAAQ;AAAA,EAC9C;AACF;AAEA,SAAS,wBAAwB,UAAiC;AAChE,MAAI,CAAC,SAAS,MAAM,CAAC,SAAS,QAAQ,CAAC,SAAS,UAAU;AACxD,UAAM,IAAI,MAAM,+DAAiC;AAAA,EACnD;AACA,MAAI,EAAC,oBAAI,IAAI,CAAC,YAAY,WAAW,QAAQ,CAAC,GAAE,IAAI,SAAS,QAAQ,GAAG;AACtE,UAAM,IAAI,MAAM,wBAAc,SAAS,EAAE,+BAAgB;AAAA,EAC3D;AACA,MAAI,EAAC,oBAAI,IAAI,CAAC,UAAU,MAAM,CAAC,GAAE,IAAI,SAAS,MAAM,GAAG;AACrD,UAAM,IAAI,MAAM,wBAAc,SAAS,EAAE,6BAAc;AAAA,EACzD;AACA,MAAI,CAAC,SAAS,YAAY;AACxB,UAAM,IAAI,MAAM,wBAAc,SAAS,EAAE,0BAAgB;AAAA,EAC3D;AACA,MAAI,CAAC,SAAS,iBAAiB,CAAC,SAAS,mBAAmB;AAC1D,UAAM,IAAI,MAAM,wBAAc,SAAS,EAAE,yDAAY;AAAA,EACvD;AACA,MAAI,SAAS,SAAS,KAAK,CAAC,WAAW,CAAC,OAAO,KAAK,CAAC,GAAG;AACtD,UAAM,IAAI,MAAM,wBAAc,SAAS,EAAE,6CAAU;AAAA,EACrD;AACF;AAEA,SAAS,qBAAqB,QAAgB,kBAAkC;AAC9E,QAAM,WACJ,4BAA4B,KAAK,MAAM,KAAK,OAAO,WAAW,MAAM;AACtE,SAAO,YAAYC,MAAK,WAAW,MAAM,IACrC,SACAA,MAAK,QAAQ,kBAAkB,MAAM;AAC3C;AAEA,eAAsB,YAAY,QAAiD;AACjF,QAAM,iBAAiB,QAAQ,IAAI,gBAAgB,KAAK,QAAQ;AAChE,MAAI,CAAC,eAAgB,QAAO,CAAC,GAAG,iBAAiB;AAEjD,QAAM,cAAcA,MAAK,QAAQ,cAAc;AAC/C,MAAI,CAACD,YAAW,WAAW,GAAG;AAC5B,UAAM,IAAI,MAAM,2CAAkB,WAAW,EAAE;AAAA,EACjD;AACA,QAAM,WAAW,MAAM,SAAsB,WAAW;AACxD,MAAI,SAAS,kBAAkB,KAAK,CAAC,MAAM,QAAQ,SAAS,SAAS,GAAG;AACtE,UAAM,IAAI,MAAM,iDAAmB,WAAW,EAAE;AAAA,EAClD;AACA,QAAM,mBAAmBC,MAAK,QAAQ,WAAW;AACjD,WAAS,YAAY,SAAS,UAAU,IAAI,CAAC,aAAa;AACxD,WAAO;AAAA,MACL,GAAG;AAAA,MACH,eAAe;AAAA,QACb,SAAS;AAAA,QACT;AAAA,MACF;AAAA,MACA,SAAS,SAAS,SAAS;AAAA,QAAI,CAAC,WAC9B,qBAAqB,QAAQ,gBAAgB;AAAA,MAC/C;AAAA,IACF;AAAA,EACF,CAAC;AACD,WAAS,UAAU,QAAQ,uBAAuB;AAElD,QAAM,SAAS,IAAI,IAAI,kBAAkB,IAAI,CAAC,SAAS,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC;AACvE,WAAS,UAAU,QAAQ,CAAC,SAAS,OAAO,IAAI,KAAK,IAAI,IAAI,CAAC;AAC9D,SAAO,CAAC,GAAG,OAAO,OAAO,CAAC;AAC5B;AAEO,SAAS,aACd,SACA,IACiB;AACjB,QAAM,WAAW,MAAM,QAAQ,CAAC,GAAG;AACnC,QAAM,WAAW,QAAQ,KAAK,CAAC,SAAS,KAAK,OAAO,QAAQ;AAC5D,MAAI,CAAC,UAAU;AACb,UAAM,IAAI;AAAA,MACR,mCAAU,QAAQ,mCAAU,QAAQ,IAAI,CAAC,SAAS,KAAK,EAAE,EAAE,KAAK,IAAI,CAAC;AAAA,IACvE;AAAA,EACF;AACA,SAAO;AACT;;;AE9HA,OAAOC,WAAU;AACjB,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,SAAAC,QAAO,WAAAC,UAAS,UAAAC,SAAQ,MAAAC,KAAI,aAAAC,kBAAiB;AACtD,SAAS,KAAK,kBAAkB;;;ACHhC,SAAS,aAAa;AAQf,SAAS,gBAAgB,SAAyB;AACvD,MAAI,QAAQ,aAAa,QAAS,QAAO;AACzC,SAAO,YAAY,UAAU,YAAY,SAAS,YAAY,QAC1D,GAAG,OAAO,SACV;AACN;AAEA,eAAsB,WACpB,SACA,MACA,UAA6B,CAAC,GACb;AACjB,QAAM,QAAQ,QAAQ,SAAS;AAC/B,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,aAAa,gBAAgB,OAAO;AAC1C,UAAM,mBACJ,QAAQ,aAAa,WAAW,WAAW,SAAS,MAAM;AAC5D,UAAM,kBAAkB,mBACpB,QAAQ,IAAI,WAAW,YACvB;AACJ,UAAM,YAAY,mBACd,CAAC,MAAM,MAAM,MAAM,YAAY,GAAG,IAAI,IACtC;AACJ,UAAM,QAAQ,MAAM,iBAAiB,WAAW;AAAA,MAC9C,KAAK,QAAQ;AAAA,MACb;AAAA,MACA,KAAK,EAAE,GAAG,QAAQ,KAAK,GAAG,QAAQ,IAAI;AAAA,MACtC,aAAa;AAAA,IACf,CAAC;AAED,QAAI,SAAS;AACb,QAAI,UAAU,QAAQ;AACpB,YAAM,QAAQ,GAAG,QAAQ,CAAC,UAAU;AAClC,kBAAU,MAAM,SAAS;AAAA,MAC3B,CAAC;AACD,YAAM,QAAQ,GAAG,QAAQ,CAAC,UAAU;AAClC,kBAAU,MAAM,SAAS;AAAA,MAC3B,CAAC;AAAA,IACH;AAEA,UAAM,GAAG,SAAS,MAAM;AACxB,UAAM,GAAG,QAAQ,CAAC,SAAS;AACzB,UAAI,SAAS,GAAG;AACd,gBAAQ,OAAO,KAAK,CAAC;AACrB;AAAA,MACF;AACA;AAAA,QACE,IAAI;AAAA,UACF,GAAG,OAAO,IAAI,KAAK,KAAK,GAAG,CAAC,uCAAc,QAAQ,SAAS,SAAI,SAAS;AAAA,EAAK,OAAO,KAAK,CAAC,KAAK,EAAE;AAAA,QACnG;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AACH;AAEA,eAAsB,eACpB,SACA,OAAiB,CAAC,WAAW,GACa;AAC1C,MAAI;AACF,WAAO,EAAE,IAAI,MAAM,QAAQ,MAAM,WAAW,SAAS,MAAM,EAAE,OAAO,OAAO,CAAC,EAAE;AAAA,EAChF,SAAS,OAAO;AACd,WAAO,EAAE,IAAI,OAAO,QAAS,MAAgB,QAAQ;AAAA,EACvD;AACF;;;ACxEA,SAAS,kBAAkB;AAC3B,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,SAAAC,QAAO,SAAS,QAAQ,QAAAC,aAAY;AAC7C,OAAOC,WAAU;;;ACHjB,OAAO,QAAQ;AACf,OAAOC,WAAU;AACjB,SAAS,cAAAC,mBAAkB;AAKpB,IAAM,sBAAkC;AAAA,EAC7C,eAAe;AAAA,EACf,aAAa;AAAA,EACb,SAAS;AAAA,EACT,iBAAiB;AACnB;AAEO,SAAS,cAAsB;AACpC,SAAOC,MAAK,QAAQ,QAAQ,IAAI,aAAa,KAAKA,MAAK,KAAK,GAAG,QAAQ,GAAG,OAAO,CAAC;AACpF;AAEO,SAAS,oBAA4B;AAC1C,SAAOA,MAAK,KAAK,YAAY,GAAG,aAAa;AAC/C;AAEA,eAAsB,iBAAsC;AAC1D,QAAM,aAAa,kBAAkB;AACrC,MAAI,CAACC,YAAW,UAAU,EAAG,QAAO,EAAE,GAAG,oBAAoB;AAE7D,QAAM,SAAS,MAAM,SAA8B,UAAU;AAC7D,MACE,OAAO,kBAAkB,UACzB,OAAO,kBAAkB,4BACzB;AACA,UAAM,IAAI;AAAA,MACR,iEAAe,OAAO,aAAa,kCAAS,0BAA0B;AAAA,IACxE;AAAA,EACF;AACA,SAAO,EAAE,GAAG,qBAAqB,GAAG,OAAO;AAC7C;AAEA,eAAsB,eAAe,QAAmC;AACtE,QAAM,UAAU,kBAAkB,GAAG;AAAA,IACnC,GAAG;AAAA,IACH,eAAe;AAAA,EACjB,CAAC;AACH;AAEA,IAAM,cAAc,oBAAI,IAAsB;AAAA,EAC5C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,SAAS,qBACd,KACA,UACkD;AAClD,MAAI,CAAC,YAAY,IAAI,GAAuB,GAAG;AAC7C,UAAM,IAAI,MAAM,+CAAY,GAAG,EAAE;AAAA,EACnC;AACA,QAAM,WAAW;AACjB,MAAI,aAAa,iBAAiB,aAAa,WAAW;AACxD,UAAM,aAAa,SAAS,YAAY;AACxC,QAAI,EAAC,oBAAI,IAAI,CAAC,QAAQ,OAAO,CAAC,GAAE,IAAI,UAAU,GAAG;AAC/C,YAAM,IAAI,MAAM,GAAG,GAAG,uCAAmB;AAAA,IAC3C;AACA,WAAO,CAAC,UAAU,eAAe,MAAM;AAAA,EACzC;AACA,MAAI,aAAa,mBAAmB;AAClC,UAAM,QAAQ,OAAO,QAAQ;AAC7B,QAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,KAAK,QAAQ,OAAO;AAC1D,YAAM,IAAI,MAAM,kFAAqC;AAAA,IACvD;AACA,WAAO,CAAC,UAAU,KAAK;AAAA,EACzB;AACA,SAAO,CAAC,UAAU,SAAS,KAAK,CAAC;AACnC;;;ADvEA,IAAM,uBAAuB;AAStB,SAAS,uBAA+B;AAC7C,SAAOC,MAAK,KAAK,YAAY,GAAG,SAAS,WAAW;AACtD;AAEO,SAAS,oBAAoB,QAAgB,KAAqB;AACvE,SAAO,WAAW,QAAQ,EAAE,OAAO,GAAG,MAAM,KAAK,GAAG,EAAE,EAAE,OAAO,KAAK,EAAE,MAAM,GAAG,EAAE;AACnF;AAEA,SAAS,cAAc,KAAa;AAClC,QAAM,YAAYA,MAAK,KAAK,qBAAqB,GAAG,GAAG;AACvD,SAAO;AAAA,IACL;AAAA,IACA,cAAcA,MAAK,KAAK,WAAW,UAAU;AAAA,IAC7C,cAAcA,MAAK,KAAK,WAAW,eAAe;AAAA,EACpD;AACF;AAEA,eAAsB,uBACpB,QACA,KACoC;AACpC,QAAM,MAAM,oBAAoB,QAAQ,GAAG;AAC3C,QAAM,QAAQ,cAAc,GAAG;AAC/B,MAAI,CAACC,YAAW,MAAM,YAAY,KAAK,CAACA,YAAW,MAAM,YAAY,EAAG,QAAO;AAC/E,MAAI;AACF,UAAM,WAAW,MAAM,SAAgC,MAAM,YAAY;AACzE,QACE,SAAS,kBAAkB,wBAC3B,SAAS,WAAW,UACpB,SAAS,QAAQ,KACjB;AACA,aAAO;AAAA,IACT;AACA,WAAO;AAAA,MACL;AAAA,MACA,MAAM,MAAM;AAAA,MACZ;AAAA,MACA,WAAW,MAAM,uBAAuB,MAAM,SAAS;AAAA,IACzD;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,qBACd,OACA,YACS;AACT,MAAI,cAAc,EAAG,QAAO;AAC5B,QAAM,WAAW,KAAK,MAAM,MAAM,SAAS,QAAQ;AACnD,SAAO,OAAO,SAAS,QAAQ,KAAK,KAAK,IAAI,IAAI,WAAW,aAAa;AAC3E;AAEA,eAAsB,2BACpB,QACA,KAQC;AACD,QAAM,MAAM,oBAAoB,QAAQ,GAAG;AAC3C,QAAM,YAAY,qBAAqB;AACvC,QAAMC,OAAM,WAAW,EAAE,WAAW,KAAK,CAAC;AAC1C,QAAM,cAAcF,MAAK;AAAA,IACvB;AAAA,IACA,IAAI,GAAG,QAAQ,QAAQ,GAAG,IAAI,KAAK,IAAI,CAAC;AAAA,EAC1C;AACA,QAAM,eAAeA,MAAK,KAAK,aAAa,UAAU;AACtD,QAAM,YAAYA,MAAK,KAAK,WAAW,GAAG;AAC1C,QAAME,OAAM,aAAa,EAAE,WAAW,KAAK,CAAC;AAE5C,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,MAAM,SAAS;AACb,YAAM,UAAUF,MAAK,KAAK,aAAa,eAAe,GAAG;AAAA,QACvD,eAAe;AAAA,QACf;AAAA,QACA;AAAA,QACA,WAAU,oBAAI,KAAK,GAAE,YAAY;AAAA,MACnC,CAAiC;AACjC,YAAM,WAAW,SAAS;AAC1B,YAAM,OAAO,aAAa,SAAS;AAAA,IACrC;AAAA,IACA,SAAS,MAAM,WAAW,WAAW;AAAA,EACvC;AACF;AAEA,eAAe,uBAAuB,WAAoC;AACxE,MAAI,QAAQ;AACZ,QAAM,UAAU,MAAM,QAAQ,WAAW,EAAE,eAAe,KAAK,CAAC;AAChE,aAAW,SAAS,SAAS;AAC3B,UAAM,WAAWA,MAAK,KAAK,WAAW,MAAM,IAAI;AAChD,QAAI,MAAM,YAAY,EAAG,UAAS,MAAM,uBAAuB,QAAQ;AAAA,aAC9D,MAAM,OAAO,EAAG,WAAU,MAAMG,MAAK,QAAQ,GAAG;AAAA,EAC3D;AACA,SAAO;AACT;AAEA,eAAsB,oBAAmD;AACvE,QAAM,YAAY,qBAAqB;AACvC,MAAI,CAACF,YAAW,SAAS,EAAG,QAAO,CAAC;AACpC,QAAM,UAAgC,CAAC;AACvC,aAAW,aAAa,MAAM,QAAQ,WAAW,EAAE,eAAe,KAAK,CAAC,GAAG;AACzE,QAAI,CAAC,UAAU,YAAY,KAAK,UAAU,KAAK,WAAW,GAAG,EAAG;AAChE,UAAM,QAAQ,cAAc,UAAU,IAAI;AAC1C,QAAI,CAACA,YAAW,MAAM,YAAY,KAAK,CAACA,YAAW,MAAM,YAAY,EAAG;AACxE,QAAI;AACF,cAAQ,KAAK;AAAA,QACX,KAAK,UAAU;AAAA,QACf,MAAM,MAAM;AAAA,QACZ,UAAU,MAAM,SAAgC,MAAM,YAAY;AAAA,QAClE,WAAW,MAAM,uBAAuB,MAAM,SAAS;AAAA,MACzD,CAAC;AAAA,IACH,QAAQ;AAAA,IAER;AAAA,EACF;AACA,SAAO,QAAQ;AAAA,IAAK,CAAC,GAAG,MACtB,EAAE,SAAS,SAAS,cAAc,EAAE,SAAS,QAAQ;AAAA,EACvD;AACF;AAEA,eAAsB,qBAAoC;AACxD,QAAM,WAAW,qBAAqB,CAAC;AACzC;;;AFvIA,IAAM,oBAAoB,MAAM,OAAO;AAgBhC,SAAS,uBACd,UACA,UACA,kBACU;AACV,QAAM,kBACJ,aACC,SAAS,oBACN,QAAQ,IAAI,SAAS,iBAAiB,IACtC,WACJ;AACF,MAAI,gBAAiB,QAAO,CAAC,eAAe;AAC5C,SAAO,CAAC,GAAG,oBAAI,IAAI,CAAC,SAAS,eAAe,GAAI,SAAS,WAAW,CAAC,CAAE,CAAC,CAAC;AAC3E;AAEA,SAAS,YAAY,QAAyB;AAC5C,SACE,OAAO,WAAW,MAAM,KACxB,OAAO,WAAW,QAAQ,KAC1B,OAAO,WAAW,SAAS,KAC3B,OAAO,WAAW,SAAS,KAC3B,OAAO,WAAW,UAAU,KAC5B,OAAO,SAAS,MAAM;AAE1B;AAEA,SAAS,gBAAgB,QAAyB;AAChD,QAAM,WAAW,OAAO,MAAM,QAAQ,CAAC,EAAE,CAAC,EAAE,YAAY;AACxD,SAAO,SAAS,SAAS,MAAM,KAAK,SAAS,SAAS,SAAS,KAAK,SAAS,SAAS,MAAM;AAC9F;AAEA,eAAe,cACb,QACA,KACA,SACkC;AAClC,QAAM,aAAa,MAAM,uBAAuB,QAAQ,GAAG;AAC3D,MACE,CAAC,QAAQ,WACT,cACA,qBAAqB,YAAY,QAAQ,mBAAmB,EAAE,GAC9D;AACA,WAAO;AAAA,MACL,MAAM,WAAW;AAAA,MACjB,QAAQ,GAAG,MAAM,IAAI,GAAG;AAAA,MACxB,MAAM,UAAU;AAAA,MAAC;AAAA,IACnB;AAAA,EACF;AACA,SAAO;AACT;AAEA,eAAe,2BACb,aACA,cACe;AACf,MAAIG,YAAWC,MAAK,KAAK,cAAc,wBAAwB,CAAC,EAAG;AACnE,QAAM,WAAW,MAAMC,SAAQ,cAAc,EAAE,eAAe,KAAK,CAAC;AACpE,QAAM,aAAa,SAAS;AAAA,IAC1B,CAAC,UACC,MAAM,YAAY,KAClBF,YAAWC,MAAK,KAAK,cAAc,MAAM,MAAM,wBAAwB,CAAC;AAAA,EAC5E;AACA,MAAI,WAAW,WAAW,GAAG;AAC3B,UAAM,IAAI,MAAM,+HAA0C;AAAA,EAC5D;AACA,QAAM,iBAAiBA,MAAK,KAAK,aAAa,sBAAsB;AACpE,QAAME,QAAOF,MAAK,KAAK,cAAc,WAAW,CAAC,EAAE,IAAI,GAAG,cAAc;AACxE,QAAMG,IAAG,cAAc,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AACvD,QAAMD,QAAO,gBAAgB,YAAY;AAC3C;AAEA,eAAe,uBACb,QACA,KACA,SAC2B;AAC3B,QAAM,SAAS,MAAM,cAAc,QAAQ,KAAK,OAAO;AACvD,MAAI,OAAQ,QAAO;AAEnB,QAAM,eAAe,MAAM,2BAA2B,QAAQ,GAAG;AACjE,QAAM,cAAcF,MAAK,KAAK,aAAa,aAAa,cAAc;AACtE,MAAI;AACF,QAAI,OAAO,WAAW,SAAS,KAAK,OAAO,WAAW,UAAU,GAAG;AACjE,YAAM,WAAW,MAAM,MAAM,QAAQ,EAAE,QAAQ,YAAY,QAAQ,GAAM,EAAE,CAAC;AAC5E,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,IAAI,MAAM,gEAAmB,SAAS,MAAM,EAAE;AAAA,MACtD;AACA,YAAM,iBAAiB,OAAO,SAAS,QAAQ,IAAI,gBAAgB,KAAK,CAAC;AACzE,UAAI,iBAAiB,mBAAmB;AACtC,cAAM,IAAI,MAAM,gEAAmB;AAAA,MACrC;AACA,YAAM,gBAAgB,OAAO,KAAK,MAAM,SAAS,YAAY,CAAC;AAC9D,UAAI,cAAc,aAAa,mBAAmB;AAChD,cAAM,IAAI,MAAM,gEAAmB;AAAA,MACrC;AACA,YAAMI,WAAU,aAAa,aAAa;AAAA,IAC5C,OAAO;AACL,YAAM,EAAE,SAAS,IAAI,MAAM,OAAO,aAAkB;AACpD,YAAM,SAASJ,MAAK,QAAQ,MAAM,GAAG,WAAW;AAAA,IAClD;AACA,UAAMK,OAAM,aAAa,cAAc,EAAE,WAAW,KAAK,CAAC;AAC1D,UAAM,WAAW,EAAE,MAAM,aAAa,KAAK,aAAa,aAAa,CAAC;AACtE,UAAM;AAAA,MACJ,aAAa;AAAA,MACb,aAAa;AAAA,IACf;AACA,UAAMF,IAAG,aAAa,EAAE,OAAO,KAAK,CAAC;AACrC,UAAM,aAAa,OAAO;AAC1B,WAAO;AAAA,MACL,MAAMH,MAAK,KAAK,aAAa,WAAW,UAAU;AAAA,MAClD,QAAQ,GAAG,MAAM;AAAA,MACjB,MAAM,UAAU;AAAA,MAAC;AAAA,IACnB;AAAA,EACF,SAAS,OAAO;AACd,UAAM,aAAa,QAAQ;AAC3B,UAAM;AAAA,EACR;AACF;AAEA,eAAsB,gBACpB,QACA,KACA,UAA2D,CAAC,GACjC;AAC3B,QAAM,YAAYA,MAAK,QAAQ,MAAM;AACrC,MAAID,YAAW,SAAS,GAAG;AACzB,QAAI,MAAM,YAAY,SAAS,GAAG;AAChC,aAAO;AAAA,QACL,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,MAAM,UAAU;AAAA,QAAC;AAAA,MACnB;AAAA,IACF;AACA,QAAI,gBAAgB,SAAS,GAAG;AAC9B,aAAO,uBAAuB,WAAW,KAAK,OAAO;AAAA,IACvD;AACA,UAAM,IAAI,MAAM,8FAAwB,SAAS,EAAE;AAAA,EACrD;AAEA,MAAI,gBAAgB,MAAM,GAAG;AAC3B,WAAO,uBAAuB,QAAQ,KAAK,OAAO;AAAA,EACpD;AAEA,MAAI,CAAC,YAAY,MAAM,GAAG;AACxB,UAAM,IAAI,MAAM,yCAAW,MAAM,EAAE;AAAA,EACrC;AAEA,QAAM,SAAS,MAAM,cAAc,QAAQ,KAAK,OAAO;AACvD,MAAI,OAAQ,QAAO;AAEnB,QAAM,eAAe,MAAM,2BAA2B,QAAQ,GAAG;AACjE,MAAI;AACF,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,aAAa;AAAA,MACf;AAAA,MACA,EAAE,OAAO,QAAQ,KAAK,EAAE,qBAAqB,IAAI,EAAE;AAAA,IACrD;AACA,UAAM,aAAa,OAAO;AAC1B,WAAO;AAAA,MACL,MAAMC,MAAK,KAAK,aAAa,WAAW,UAAU;AAAA,MAClD,QAAQ,GAAG,MAAM,IAAI,GAAG;AAAA,MACxB,MAAM,UAAU;AAAA,MAAC;AAAA,IACnB;AAAA,EACF,SAAS,OAAO;AACd,UAAM,aAAa,QAAQ;AAC3B,UAAM;AAAA,EACR;AACF;AAEA,eAAsB,2BACpB,SACA,KACA,UAA2D,CAAC,GACjC;AAC3B,MAAI,CAAC,QAAQ,OAAQ,OAAM,IAAI,MAAM,kDAAU;AAC/C,QAAM,WAAqB,CAAC;AAC5B,aAAW,UAAU,CAAC,GAAG,IAAI,IAAI,OAAO,CAAC,GAAG;AAC1C,QAAI;AACF,aAAO,MAAM,gBAAgB,QAAQ,KAAK,OAAO;AAAA,IACnD,SAAS,OAAO;AACd,eAAS,KAAK,GAAG,MAAM,KAAM,MAAgB,OAAO,EAAE;AAAA,IACxD;AAAA,EACF;AACA,QAAM,IAAI,MAAM;AAAA,IAAiB,SAAS,KAAK,MAAM,CAAC,EAAE;AAC1D;;;AIjOA,YAAYM,cAAa;;;ACAzB,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,UAAAC,SAAQ,MAAAC,WAAU;AAC3B,OAAOC,WAAU;AACjB,YAAY,aAAa;AACzB,SAAS,iBAAiB;;;ACJ1B,OAAOC,WAAU;AAIjB,eAAsB,qBACpB,cAC2B;AAC3B,QAAM,WAAW,MAAM;AAAA,IACrBC,MAAK,KAAK,cAAc,wBAAwB;AAAA,EAClD;AACA,QAAM,SAAmB,CAAC;AAE1B,MAAI,SAAS,kBAAkB,EAAG,QAAO,KAAK,oCAAqB;AACnE,MAAI,CAAC,SAAS,GAAI,QAAO,KAAK,6BAAS;AACvC,MAAI,CAAC,SAAS,KAAM,QAAO,KAAK,sCAAQ;AACxC,MAAI,CAAC,2BAA2B,KAAK,SAAS,WAAW,EAAE,GAAG;AAC5D,WAAO,KAAK,mFAAuB;AAAA,EACrC;AACA,MAAI,CAAC,SAAS,SAAS,QAAQ,CAAC,SAAS,SAAS,gBAAgB;AAChE,WAAO,KAAK,wDAAW;AAAA,EACzB;AACA,MAAI,CAAC,SAAS,OAAO,gBAAgB;AACnC,WAAO,KAAK,8DAAY;AAAA,EAC1B;AACA,QAAM,aAAa,oBAAI,IAAY;AACnC,aAAW,WAAW,SAAS,YAAY,CAAC,GAAG;AAC7C,QAAI,CAAC,oBAAoB,KAAK,QAAQ,EAAE,GAAG;AACzC,aAAO,KAAK,6CAAe,QAAQ,EAAE,EAAE;AAAA,IACzC;AACA,QAAI,WAAW,IAAI,QAAQ,EAAE,GAAG;AAC9B,aAAO,KAAK,6CAAe,QAAQ,EAAE,EAAE;AAAA,IACzC;AACA,eAAW,IAAI,QAAQ,EAAE;AACzB,QAAI,CAAC,QAAQ,QAAQ,CAAC,QAAQ,aAAa;AACzC,aAAO,KAAK,4BAAQ,QAAQ,EAAE,6CAAU;AAAA,IAC1C;AAAA,EACF;AAEA,MAAI,OAAO,QAAQ;AACjB,UAAM,IAAI,MAAM;AAAA,IAAsB,OAAO,KAAK,MAAM,CAAC,EAAE;AAAA,EAC7D;AACA,SAAO;AACT;;;ADdA,IAAM,YAAY,CAAC,OAAO,OAAO,OAAO,OAAO,KAAK;AAKpD,SAAS,UAAU,OAAiC;AAClD,SAAe,iBAAS,KAAK;AAC/B;AAEO,SAAS,qBAAqB,OAAuB;AAC1D,SAAO,MACJ,KAAK,EACL,YAAY,EACZ,QAAQ,QAAQ,GAAG,EACnB,QAAQ,WAAW,EAAE,EACrB,QAAQ,kBAAkB,GAAG,EAC7B,QAAQ,UAAU,GAAG,EACrB,QAAQ,WAAW,EAAE;AAC1B;AAEA,SAAS,kBAAkB,OAAuB;AAChD,QAAM,OAAO,qBAAqB,KAAK;AACvC,MAAI,CAAC,yBAAyB,KAAK,IAAI,GAAG;AACxC,UAAM,IAAI,MAAM,wGAAmB;AAAA,EACrC;AACA,SAAO;AACT;AAEA,SAAS,gBAAgB,aAA6B;AACpD,QAAM,WAAW,YACd,QAAQ,oBAAoB,EAAE,EAC9B,QAAQ,eAAe,GAAG,EAC1B,QAAQ,YAAY,EAAE;AACzB,SAAO,oBAAoB,KAAK,QAAQ,IAAI,WAAW;AACzD;AAEA,SAAS,iBAAiB,OAAuB;AAC/C,QAAM,OAAO,MAAM,KAAK;AACxB,MAAI,CAAC,oBAAoB,KAAK,IAAI,GAAG;AACnC,UAAM,IAAI,MAAM,gLAA+B;AAAA,EACjD;AACA,SAAO;AACT;AAEA,SAAS,WAAW,OAAgC;AAClD,QAAM,OAAO,OAAO,KAAK;AACzB,MAAI,CAAC,OAAO,UAAU,IAAI,KAAK,OAAO,QAAQ,OAAO,OAAO;AAC1D,UAAM,IAAI,MAAM,6FAA4B;AAAA,EAC9C;AACA,SAAO;AACT;AAEA,SAAS,cAAc,OAAe,OAAuB;AAC3D,MAAI;AACF,UAAM,MAAM,IAAI,IAAI,KAAK;AACzB,QAAI,IAAI,aAAa,WAAW,IAAI,aAAa,SAAU,OAAM,IAAI,MAAM;AAC3E,WAAO,MAAM,QAAQ,QAAQ,EAAE;AAAA,EACjC,QAAQ;AACN,UAAM,IAAI,MAAM,GAAG,KAAK,oCAAqB;AAAA,EAC/C;AACF;AAEA,eAAe,QACb,SACA,cACA,UACiB;AACjB,QAAM,SAAS,MAAc,aAAK;AAAA,IAChC;AAAA,IACA,aAAa;AAAA,IACb,cAAc;AAAA,IACd;AAAA,EACF,CAAC;AACD,MAAI,UAAU,MAAM,EAAG,OAAM,IAAI,MAAM,sCAAQ;AAC/C,SAAO,OAAO,MAAM,EAAE,KAAK,KAAK;AAClC;AAEA,eAAe,iBACb,YACA,KAC8B;AAC9B,MAAI,CAAC,WAAY,QAAO,CAAC;AACzB,QAAM,WAAWC,MAAK,QAAQ,KAAK,UAAU;AAC7C,MAAI,CAACC,YAAW,QAAQ,EAAG,OAAM,IAAI,MAAM,2DAAc,QAAQ,EAAE;AACnE,SAAO,SAA8B,QAAQ;AAC/C;AAEA,SAAS,gBAAgB,OAAyB;AAChD,SAAO,CAAC,GAAG,IAAI,IAAI,MAAM,MAAM,GAAG,EAAE,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,EAAE,OAAO,OAAO,CAAC,CAAC;AACjF;AAEA,eAAe,wBACb,UACA,YACA,SACmB;AACnB,QAAM,YAAY,SAAS,YAAY,CAAC;AACxC,MAAI,CAAC,UAAU,OAAQ,QAAO,CAAC;AAE/B,QAAM,WAAW,IAAI,IAAI,UAAU,IAAI,CAAC,YAAY,QAAQ,EAAE,CAAC;AAC/D,MAAI,WAAW,QAAQ,WACnB,gBAAgB,QAAQ,QAAQ,IAChC,MAAM,QAAQ,WAAW,QAAQ,IAC/B,WAAW,WACX,UACG,OAAO,CAAC,YAAY,QAAQ,kBAAkB,QAAQ,QAAQ,EAC9D,IAAI,CAAC,YAAY,QAAQ,EAAE;AAEpC,QAAM,UAAU,SAAS,OAAO,CAAC,OAAO,CAAC,SAAS,IAAI,EAAE,CAAC;AACzD,MAAI,QAAQ,QAAQ;AAClB,UAAM,IAAI;AAAA,MACR,2DAAc,QAAQ,KAAK,IAAI,CAAC,mCAAU,CAAC,GAAG,QAAQ,EAAE,KAAK,IAAI,CAAC;AAAA,IACpE;AAAA,EACF;AAEA,MAAI,QAAQ,cAAc,OAAO;AAC/B,eAAW,SAAS,OAAO,CAAC,OAAO;AACjC,YAAM,UAAU,UAAU,KAAK,CAAC,SAAS,KAAK,OAAO,EAAE;AACvD,aAAO,SAAS,YAAY;AAAA,IAC9B,CAAC;AAAA,EACH;AAEA,aAAW,WAAW,WAAW;AAC/B,QAAI,QAAQ,YAAY,CAAC,SAAS,SAAS,QAAQ,EAAE,GAAG;AACtD,eAAS,KAAK,QAAQ,EAAE;AAAA,IAC1B;AAAA,EACF;AACA,SAAO;AACT;AAEA,eAAe,oBACb,aACA,UACA,cACA,YACA,SACA,YACA,UACuB;AACvB,MAAI,aAAa,QAAQ,UAAU,WAAW,cAAc,gBAAgB,WAAW;AACvF,MAAI,QAAQ,QAAQ,SAAS,WAAW,SAAS,aAAa;AAC9D,MAAI,OACF,QAAQ,QAAQ,WAAW,iBAAiB,aAAa;AAC3D,MAAI,cACF,QAAQ,eACR,WAAW,eACX,WAAW,eACX,aAAa;AACf,MAAI,eACF,QAAQ,gBACR,WAAW,gBACX,WAAW,gBACX,aAAa;AACf,MAAI,kBACF,QAAQ,gBAAgB,WAAW,mBAAmB,aAAa;AACrE,MAAI,iBACF,QAAQ,eAAe,WAAW,kBAAkB,aAAa;AACnE,QAAM,eAAe,gBAAgB,aAAa,YAAY;AAC9D,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,WAAW,gBAAgB,CAAC,CAAC,GAAG;AACxE,QAAI,SAAS,aAAa,GAAG,GAAG;AAC9B,mBAAa,GAAG,IAAI,EAAE,GAAG,aAAa,GAAG,GAAG,GAAG,MAAM;AAAA,IACvD;AAAA,EACF;AAEA,MAAI,CAAC,QAAQ,KAAK;AAChB,YAAQ,MAAM;AAAA,MACZ,SAAS,aAAa,WAAW,6BAAS;AAAA,MAC1C;AAAA,MACA,CAAC,UAAW,OAAO,KAAK,IAAI,SAAY;AAAA,IAC1C;AACA,WAAO,MAAM,QAAQ,4BAAQ,OAAO,IAAI,GAAG,CAAC,UAAU;AACpD,YAAM,SAAS,OAAO,KAAK;AAC3B,aAAO,OAAO,UAAU,MAAM,KAAK,UAAU,QAAQ,UAAU,QAC3D,SACA;AAAA,IACN,CAAC;AACD,sBAAkB,MAAM;AAAA,MACtB,SAAS,aAAa,WAAW,kCAAc;AAAA,MAC/C;AAAA,MACA,CAAC,UAAU;AACT,YAAI;AACF,gBAAM,MAAM,IAAI,IAAI,SAAS,EAAE;AAC/B,iBAAO,IAAI,aAAa,WAAW,IAAI,aAAa,WAChD,SACA;AAAA,QACN,QAAQ;AACN,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,MAAI,CAAC,MAAM,KAAK,EAAG,OAAM,IAAI,MAAM,kDAAU;AAC7C,aAAW,OAAO,WAAW;AAC3B,QAAI,CAAC,aAAa,GAAG,EAAG,OAAM,IAAI,MAAM,gBAAM,IAAI,YAAY,CAAC,2BAAO;AACtE,iBAAa,GAAG,IAAI;AAAA,MAClB,QAAQ,cAAc,aAAa,GAAG,EAAE,QAAQ,GAAG,IAAI,YAAY,CAAC,2BAAO;AAAA,MAC3E,WAAW,aAAa,GAAG,EAAE,UAAU,QAAQ,cAAc,EAAE;AAAA,IACjE;AACA,QAAI,CAAC,aAAa,GAAG,EAAE,WAAW;AAChC,YAAM,IAAI,MAAM,GAAG,IAAI,YAAY,CAAC,2CAAa;AAAA,IACnD;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA,YAAY,iBAAiB,UAAU;AAAA,IACvC,OAAO,MAAM,KAAK;AAAA,IAClB,eAAe,WAAW,IAAI;AAAA,IAC9B,aAAa,cAAc,aAAa,cAAc;AAAA,IACtD,cAAc,cAAc,cAAc,6BAAmB;AAAA,IAC7D,iBAAiB,cAAc,iBAAiB,sCAAQ;AAAA,IACxD,gBAAgB,cAAc,gBAAgB,kCAAc;AAAA,IAC5D;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,iBAAiB,KAAa,QAAsB;AAC3D,MAAID,MAAK,QAAQ,MAAM,MAAM,OAAO,WAAW,KAAK;AAClD,UAAM,IAAI,MAAM,kGAAkB;AAAA,EACpC;AACF;AAEA,eAAe,eACb,aACA,YACA,OACe;AACf,QAAM,eAAeC,YAAW,UAAU;AAC1C,MAAI,CAAC,cAAc;AACjB,UAAMC,QAAO,aAAa,UAAU;AACpC;AAAA,EACF;AAEA,MAAI,CAAE,MAAM,iBAAiB,UAAU,KAAM,CAAC,OAAO;AACnD,UAAM,IAAI,MAAM,iEAAe,UAAU,EAAE;AAAA,EAC7C;AAEA,QAAM,aAAa,GAAG,UAAU,gBAAgB,KAAK,IAAI,CAAC;AAC1D,QAAMA,QAAO,YAAY,UAAU;AACnC,MAAI;AACF,UAAMA,QAAO,aAAa,UAAU;AAAA,EACtC,SAAS,OAAO;AACd,UAAMA,QAAO,YAAY,UAAU;AACnC,UAAM;AAAA,EACR;AACA,MAAI;AACF,UAAM,WAAW,UAAU;AAAA,EAC7B,QAAQ;AACN,IAAQ,YAAI,KAAK,uEAAgB,UAAU,EAAE;AAAA,EAC/C;AACF;AAYA,eAAsB,gBACpB,iBACA,sBACA,SACA,MAAM,QAAQ,IAAI,GAClB,uBAAmC,qBACH;AAChC,QAAM,aAAa,EAAE,GAAG,qBAAqB,GAAG,qBAAqB;AACrE,QAAM,cAAc,kBAAkB,oBAAoB;AAC1D,QAAM,cAAcF,MAAK,QAAQ,GAAG;AACpC,QAAM,aAAaA,MAAK,QAAQ,aAAa,WAAW;AACxD,mBAAiB,aAAa,UAAU;AACxC,MACEC,YAAW,UAAU,KACrB,CAAE,MAAM,iBAAiB,UAAU,KACnC,CAAC,QAAQ,OACT;AACA,UAAM,IAAI,MAAM,iEAAe,UAAU,EAAE;AAAA,EAC7C;AAEA,QAAM,MAAM,QAAQ,OAAO,WAAW,eAAe,gBAAgB;AACrE,QAAM,eAAe;AAAA,IACnB;AAAA,IACA,QAAQ;AAAA,IACR,WAAW;AAAA,EACb;AACA,QAAM,qBAAqB,QAAQ,MAC/B,SACQ,gBAAQ,EAAE,WAAW,QAAQ,CAAC;AAC1C,sBAAoB,MAAM,wDAAW;AACrC,MAAI;AACJ,MAAI;AACF,eAAW,MAAM,2BAA2B,cAAc,KAAK;AAAA,MAC7D,SAAS,QAAQ,UAAU;AAAA,MAC3B,iBAAiB,WAAW;AAAA,IAC9B,CAAC;AACD,wBAAoB,KAAK,sCAAQ;AAAA,EACnC,SAAS,OAAO;AACd,wBAAoB,MAAM,sCAAQ;AAClC,UAAM;AAAA,EACR;AACA,QAAM,cAAcD,MAAK;AAAA,IACvB;AAAA,IACA,IAAI,WAAW,aAAa,QAAQ,GAAG,IAAI,KAAK,IAAI,CAAC;AAAA,EACvD;AACA,MAAI,WAAW;AAEf,MAAI;AACF,UAAM,WAAW,MAAM,qBAAqB,SAAS,IAAI;AACzD,QAAI,SAAS,OAAO,gBAAgB,IAAI;AACtC,YAAM,IAAI;AAAA,QACR,mDAAqB,gBAAgB,EAAE,kBAAa,SAAS,EAAE;AAAA,MACjE;AAAA,IACF;AACA,QAAI,CAAC,UAAU,QAAQ,SAAS,MAAM,SAAS,QAAQ,IAAI,GAAG;AAC5D,YAAM,IAAI;AAAA,QACR,qBAAW,QAAQ,SAAS,IAAI,+CAAY,SAAS,QAAQ,IAAI;AAAA,MACnE;AAAA,IACF;AAEA,UAAM,sBAAsB,MAAM,SAEhCA,MAAK,KAAK,SAAS,MAAM,qBAAqB,CAAC;AACjD,UAAM,aAAa,MAAM,iBAAiB,QAAQ,QAAQ,WAAW;AACrE,UAAM,WAAW,MAAM,wBAAwB,UAAU,YAAY,OAAO;AAC5E,UAAM,QAAQ,MAAM;AAAA,MAClB;AAAA,MACA;AAAA,MACA;AAAA,QACE,GAAG;AAAA,QACH,aAAa,SAAS,SAAS;AAAA,QAC/B,cAAc,SAAS,SAAS;AAAA,MAClC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,UAAM,gBACJ,CAAC,QAAQ,gBAAgB,QAAQ,YAAY,QAAQ,WAAW;AAClE,UAAM,sBAAsB,CAAC,QAAQ,WAAW,WAAW;AAE3D,QAAI,QAAQ,QAAQ;AAClB,MAAQ;AAAA,QACN;AAAA,UACE,iBAAO,SAAS,EAAE,IAAI,SAAS,OAAO;AAAA,UACtC,iBAAO,SAAS,MAAM;AAAA,UACtB,iBAAO,UAAU;AAAA,UACjB,iBAAO,MAAM,UAAU;AAAA,UACvB,iBAAO,MAAM,aAAa;AAAA,UAC1B,iBAAO,MAAM,SAAS,SAAS,MAAM,SAAS,KAAK,IAAI,IAAI,gCAAO;AAAA,UAClE,6BAAS,gBAAgB,WAAM,QAAG;AAAA,UAClC,2BAAY,sBAAsB,WAAM,QAAG;AAAA,QAC7C,EAAE,KAAK,IAAI;AAAA,QACX;AAAA,MACF;AACA,aAAO;AAAA,QACL;AAAA,QACA,YAAY,SAAS;AAAA,QACrB,iBAAiB,SAAS;AAAA,QAC1B,QAAQ,SAAS;AAAA,QACjB,UAAU,MAAM;AAAA,QAChB,WAAW;AAAA,QACX,gBAAgB;AAAA,MAClB;AAAA,IACF;AAEA,UAAM,iBAAiB,SAAS,MAAM,WAAW;AACjD,UAAM,YAAYA,MAAK,KAAK,aAAa,sBAAsB;AAC/D,UAAM,UAAU,WAAW,KAAK;AAChC,QAAI;AACF,YAAM;AAAA,QACJ,QAAQ;AAAA,QACR;AAAA,UACEA,MAAK,KAAK,aAAa,WAAW,mBAAmB;AAAA,UACrD;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,GAAG,QAAQ,IAAI,WAAW;AAAA,QAC5B;AAAA,QACA,EAAE,KAAK,aAAa,OAAO,OAAO;AAAA,MACpC;AAAA,IACF,UAAE;AACA,YAAMG,IAAG,WAAW,EAAE,OAAO,KAAK,CAAC;AAAA,IACrC;AAEA,QAAI,CAACF,YAAWD,MAAK,KAAK,aAAa,SAAS,iBAAiB,CAAC,GAAG;AACnE,YAAM,IAAI,MAAM,uEAAgB,SAAS,iBAAiB,EAAE;AAAA,IAC9D;AACA,UAAM,eAAe,aAAa,YAAY,QAAQ,QAAQ,KAAK,CAAC;AACpE,eAAW;AAEX,QAAI,iBAAiB;AACrB,QAAI,qBAAqB;AACvB,YAAM,WAAW,OAAO,CAAC,QAAQ,MAAM,MAAM,GAAG;AAAA,QAC9C,KAAK;AAAA,QACL,OAAO;AAAA,MACT,CAAC;AACD,uBAAiB;AAAA,IACnB;AAEA,QAAI,eAAe;AACjB,UAAI;AACF,cAAM,WAAW,QAAQ,CAAC,SAAS,GAAG,EAAE,KAAK,WAAW,CAAC;AAAA,MAC3D,SAAS,OAAO;AACd,cAAM,IAAI;AAAA,UACR,4HAAwB,UAAU;AAAA,EAAM,MAAgB,OAAO;AAAA,QACjE;AAAA,MACF;AAAA,IACF;AAEA,QAAI,qBAAqB;AACvB,YAAM,WAAW,OAAO,CAAC,OAAO,IAAI,GAAG,EAAE,KAAK,YAAY,OAAO,OAAO,CAAC;AACzE,UAAI;AACF,cAAM;AAAA,UACJ;AAAA,UACA,CAAC,UAAU,MAAM,4BAAkB,SAAS,EAAE,IAAI,SAAS,OAAO,qBAAM;AAAA,UACxE;AAAA,YACE,KAAK;AAAA,YACL,OAAO;AAAA,YACP,KAAK,EAAE,OAAO,IAAI;AAAA,UACpB;AAAA,QACF;AAAA,MACF,SAAS,OAAO;AACd,QAAQ,YAAI,KAAK,2FAAsB,MAAgB,OAAO,EAAE;AAAA,MAClE;AAAA,IACF;AAEA,WAAO;AAAA,MACL;AAAA,MACA,YAAY,SAAS;AAAA,MACrB,iBAAiB,SAAS;AAAA,MAC1B,QAAQ,SAAS;AAAA,MACjB,UAAU,MAAM;AAAA,MAChB,WAAW;AAAA,MACX;AAAA,IACF;AAAA,EACF,UAAE;AACA,QAAI,CAAC,YAAYC,YAAW,WAAW,EAAG,OAAM,WAAW,WAAW;AACtE,UAAM,SAAS,QAAQ;AAAA,EACzB;AACF;;;AD9cA,IAAM,mBAGD;AAAA,EACH,EAAE,OAAO,YAAY,OAAO,kDAAsB;AAAA,EAClD,EAAE,OAAO,WAAW,OAAO,0DAAoB;AAAA,EAC/C,EAAE,OAAO,UAAU,OAAO,0CAAwB;AACpD;AAEA,SAAS,WAAW,OAA0C;AAC5D,SAAO,iBAAiB,KAAK,CAAC,SAAS,KAAK,UAAU,KAAK;AAC7D;AAEO,SAAS,oBACd,WACA,UACmB;AACnB,SAAO,UAAU,OAAO,CAAC,aAAa,SAAS,aAAa,QAAQ;AACtE;AAEO,SAAS,mBACd,WACmD;AACnD,SAAO,iBAAiB;AAAA,IACtB,CAAC,SAAS,oBAAoB,WAAW,KAAK,KAAK,EAAE,SAAS;AAAA,EAChE,EAAE,IAAI,CAAC,EAAE,OAAO,MAAM,OAAO,EAAE,OAAO,MAAM,EAAE;AAChD;AAEA,eAAe,eACb,WACA,mBACA,gBAC2B;AAC3B,MAAI,mBAAmB;AACrB,QAAI,CAAC,WAAW,iBAAiB,GAAG;AAClC,YAAM,IAAI;AAAA,QACR,yCAAW,iBAAiB;AAAA,MAC9B;AAAA,IACF;AACA,QAAI,CAAC,oBAAoB,WAAW,iBAAiB,EAAE,QAAQ;AAC7D,YAAM,IAAI,MAAM,4BAAQ,iBAAiB,uCAAS;AAAA,IACpD;AACA,WAAO;AAAA,EACT;AAEA,QAAM,iBAAiB,iBAAiB;AAAA,IACtC,CAAC,SAAS,oBAAoB,WAAW,KAAK,KAAK,EAAE,SAAS;AAAA,EAChE;AACA,MAAI,CAAC,eAAgB,OAAM,IAAI,MAAM,oDAAiB;AACtD,MAAI,eAAgB,QAAO,eAAe;AAE1C,QAAM,mBAAmB,mBAAmB,SAAS;AACrD,MAAI,iBAAiB,WAAW,EAAG,QAAO,iBAAiB,CAAC,EAAE;AAE9D,QAAM,WAAW,MAAc,gBAAO;AAAA,IACpC,SAAS;AAAA,IACT,SAAS,iBAAiB,IAAI,CAAC,UAAU;AAAA,MACvC,OAAO,KAAK;AAAA,MACZ,OAAO,KAAK;AAAA,IACd,EAAE;AAAA,EACJ,CAAC;AACD,MAAY,kBAAS,QAAQ,EAAG,OAAM,IAAI,MAAM,sCAAQ;AACxD,SAAO;AACT;AAEA,eAAe,eACb,WACA,SAC0B;AAC1B,MAAI,QAAQ,UAAU;AACpB,UAAMG,YAAW,aAAa,WAAW,QAAQ,QAAQ;AACzD,QAAI,QAAQ,YAAYA,UAAS,aAAa,QAAQ,UAAU;AAC9D,YAAM,IAAI;AAAA,QACR,gBAAMA,UAAS,EAAE,iBAAOA,UAAS,QAAQ,2BAAiB,QAAQ,QAAQ;AAAA,MAC5E;AAAA,IACF;AACA,WAAOA;AAAA,EACT;AAEA,QAAM,WAAW,MAAM;AAAA,IACrB;AAAA,IACA,QAAQ;AAAA,IACR,QAAQ,QAAQ,GAAG;AAAA,EACrB;AACA,QAAM,aAAa,oBAAoB,WAAW,QAAQ;AAC1D,MAAI,QAAQ,IAAK,QAAO,aAAa,UAAU;AAC/C,MAAI,WAAW,WAAW,GAAG;AAC3B,UAAMA,YAAW,WAAW,CAAC;AAC7B,IAAQ,aAAI,KAAK,iCAAQA,UAAS,IAAI,EAAE;AACxC,WAAOA;AAAA,EACT;AAEA,QAAM,WAAW,MAAc,gBAAO;AAAA,IACpC,SAAS;AAAA,IACT,SAAS,WAAW,IAAI,CAAC,cAAc;AAAA,MACrC,OAAO,SAAS;AAAA,MAChB,OAAO,GAAG,SAAS,IAAI,SAAM,SAAS,WAAW;AAAA,IACnD,EAAE;AAAA,EACJ,CAAC;AACD,MAAY,kBAAS,QAAQ,EAAG,OAAM,IAAI,MAAM,sCAAQ;AACxD,SAAO,aAAa,YAAY,OAAO,QAAQ,CAAC;AAClD;AAEA,eAAsB,cACpB,eACA,SACe;AACf,EAAQ,eAAM,qCAAiB;AAC/B,QAAM,aAAa,MAAM,eAAe;AACxC,QAAM,UAAU,MAAM,YAAY,UAAU;AAC5C,QAAM,WAAW,MAAM,eAAe,SAAS,OAAO;AAEtD,MAAI,cAAc;AAClB,MAAI,CAAC,aAAa;AAChB,QAAI,QAAQ,IAAK,OAAM,IAAI,MAAM,gFAAe;AAChD,UAAM,qBACJ,SAAS,aAAa,WAAW,oBAAoB;AACvD,UAAM,SAAS,MAAc,cAAK;AAAA,MAChC,SAAS;AAAA,MACT,aAAa;AAAA,MACb,cAAc;AAAA,MACd,SAAS,OAAO;AACd,eAAO,CAAC,SAAS,qBAAqB,KAAK,IACvC,SACA;AAAA,MACN;AAAA,IACF,CAAC;AACD,QAAY,kBAAS,MAAM,EAAG,OAAM,IAAI,MAAM,sCAAQ;AACtD,kBAAc,OAAO,MAAM,EAAE,KAAK,KAAK;AAAA,EACzC;AAEA,QAAM,iBAAiB;AACvB,gBAAc,qBAAqB,cAAc;AACjD,MAAI,CAAC,aAAa;AAChB,UAAM,IAAI,MAAM,wGAAmB;AAAA,EACrC;AACA,MAAI,gBAAgB,gBAAgB;AAClC,IAAQ,aAAI,KAAK,yDAAY,WAAW,EAAE;AAAA,EAC5C;AAEA,QAAM,SAAS,MAAM;AAAA,IACnB;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ,IAAI;AAAA,IACZ;AAAA,EACF;AACA,MAAI,QAAQ,QAAQ;AAClB,IAAQ,eAAM,kFAAsB;AACpC;AAAA,EACF;AAEA,EAAQ;AAAA,IACN;AAAA,MACE,iBAAO,OAAO,UAAU;AAAA,MACxB,iBAAO,OAAO,UAAU,IAAI,OAAO,eAAe;AAAA,MAClD,iBAAO,OAAO,MAAM;AAAA,MACpB,6BAAS,OAAO,SAAS,SAAS,OAAO,SAAS,KAAK,IAAI,IAAI,QAAG;AAAA,MAClE,iBAAO,OAAO,YAAY,uBAAQ,4FAAiB;AAAA,MACnD,QAAQ,OAAO,iBAAiB,kCAAc,0BAAM;AAAA,MACpD;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,MAAM,WAAW;AAAA,MACjB,GAAI,CAAC,OAAO,YAAY,CAAC,cAAc,IAAI,CAAC;AAAA,MAC5C;AAAA,IACF,EAAE,KAAK,IAAI;AAAA,IACX;AAAA,EACF;AACA,EAAQ,eAAM,sCAAQ;AACxB;;;AG1LA,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,SAAAC,QAAO,aAAAC,YAAW,MAAAC,WAAU;AACrC,OAAOC,WAAU;AACjB,SAAS,QAAQ,KAAK,aAAAC,kBAAiB;AAcvC,eAAe,oBAA0C;AACvD,QAAM,OAAO,YAAY;AACzB,QAAM,QAAQC,MAAK,KAAK,MAAM,gBAAgB,QAAQ,GAAG,EAAE;AAC3D,MAAI;AACF,UAAMC,OAAM,MAAM,EAAE,WAAW,KAAK,CAAC;AACrC,UAAMC,WAAU,OAAO,MAAM,MAAM;AACnC,UAAMC,IAAG,OAAO,EAAE,OAAO,KAAK,CAAC;AAC/B,WAAO,EAAE,MAAM,aAAa,IAAI,MAAM,QAAQ,KAAK;AAAA,EACrD,SAAS,OAAO;AACd,WAAO,EAAE,MAAM,aAAa,IAAI,OAAO,QAAS,MAAgB,QAAQ;AAAA,EAC1E;AACF;AAEA,eAAsB,oBACpB,gBACA,iBACwB;AACxB,QAAM,SAAS,kBAAmB,MAAM,eAAe;AACvD,QAAM,UAAU,mBAAoB,MAAM,YAAY,MAAM;AAC5D,QAAM,CAAC,KAAK,MAAM,IAAI,IAAI,MAAM,QAAQ,IAAI;AAAA,IAC1C,eAAe,KAAK;AAAA,IACpB,eAAe,MAAM;AAAA,IACrB,kBAAkB;AAAA,EACpB,CAAC;AACD,QAAM,cAAc,OAAO,KAAK,MAAM,GAAG;AACzC,QAAM,SAAwB;AAAA,IAC5B;AAAA,MACE,MAAM;AAAA,MACN,IAAIC,WAAU,QAAQ,SAAS,MAAM,qBAAqB;AAAA,MAC1D,QAAQ,GAAG,QAAQ,SAAS,IAAI;AAAA,IAClC;AAAA,IACA,EAAE,MAAM,OAAO,IAAI,IAAI,IAAI,QAAQ,IAAI,OAAO;AAAA,IAC9C;AAAA,MACE,MAAM;AAAA,MACN,IAAI,KAAK,MAAM,QAAQ,eAAe,IAAI,aAAa,QAAQ,CAAC;AAAA,MAChE,QAAQ,KAAK;AAAA,IACf;AAAA,IACA;AAAA,EACF;AAEA,aAAW,YAAY,SAAS;AAC9B,UAAM,UAAU;AAAA,MACd;AAAA,MACA;AAAA,MACA,OAAO;AAAA,IACT;AACA,UAAM,SAAS,QAAQ,CAAC;AACxB,QAAI,CAACC,YAAW,MAAM,GAAG;AACvB,aAAO,KAAK;AAAA,QACV,MAAM,gBAAM,SAAS,EAAE;AAAA,QACvB,IACE,OAAO,WAAW,SAAS,KAC3B,OAAO,WAAW,UAAU,KAC5B,OAAO,WAAW,MAAM;AAAA,QAC1B,QAAQ,yFAAmB,QAAQ,KAAK,UAAK,CAAC;AAAA,MAChD,CAAC;AACD;AAAA,IACF;AACA,QAAI;AACF,YAAM,WAAW,MAAM,qBAAqB,MAAM;AAClD,aAAO,KAAK;AAAA,QACV,MAAM,gBAAM,SAAS,EAAE;AAAA,QACvB,IACE,SAAS,OAAO,SAAS,MACzBD,WAAU,QAAQ,SAAS,MAAM,SAAS,QAAQ,IAAI;AAAA,QACxD,QAAQ,GAAG,SAAS,EAAE,IAAI,SAAS,OAAO,KAAK,MAAM;AAAA,MACvD,CAAC;AAAA,IACH,SAAS,OAAO;AACd,aAAO,KAAK;AAAA,QACV,MAAM,gBAAM,SAAS,EAAE;AAAA,QACvB,IAAI;AAAA,QACJ,QAAS,MAAgB;AAAA,MAC3B,CAAC;AAAA,IACH;AAAA,EACF;AACA,SAAO;AACT;AAEA,eAAsB,cAAc,UAA8B,CAAC,GAAkB;AACnF,QAAM,SAAS,MAAM,oBAAoB;AACzC,QAAM,SAAS,OAAO,OAAO,CAAC,UAAU,CAAC,MAAM,EAAE;AACjD,MAAI,QAAQ,MAAM;AAChB,YAAQ,IAAI,KAAK,UAAU,EAAE,IAAI,OAAO,WAAW,GAAG,OAAO,GAAG,MAAM,CAAC,CAAC;AAAA,EAC1E,OAAO;AACL,eAAW,SAAS,QAAQ;AAC1B,cAAQ,IAAI,GAAG,MAAM,KAAK,WAAM,QAAG,IAAI,MAAM,IAAI,KAAK,MAAM,MAAM,EAAE;AAAA,IACtE;AACA,YAAQ,IAAI;AAAA,gBAAS,OAAO,SAAS,OAAO,MAAM,kBAAQ,OAAO,MAAM,eAAK;AAAA,EAC9E;AACA,MAAI,OAAO,OAAQ,SAAQ,WAAW;AACxC;;;AC3GA,OAAOE,WAAU;AACjB,SAAS,cAAAC,mBAAkB;AAI3B,eAAsB,YACpB,cAAc,QAAQ,IAAI,GAC1B,UAA8B,CAAC,GAChB;AACf,QAAM,OAAOC,MAAK,QAAQ,WAAW;AACrC,QAAM,eAAeA,MAAK,KAAK,MAAM,SAAS,cAAc;AAC5D,MAAI,CAACC,YAAW,YAAY,GAAG;AAC7B,UAAM,IAAI,MAAM,iFAA0B,YAAY,EAAE;AAAA,EAC1D;AACA,QAAM,WAAW,MAAM,SAA0B,YAAY;AAC7D,MAAI,QAAQ,MAAM;AAChB,YAAQ,IAAI,KAAK,UAAU,EAAE,aAAa,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC,CAAC;AACvE;AAAA,EACF;AACA,UAAQ,IAAI,6BAAS,IAAI,EAAE;AAC3B,UAAQ,IAAI,iBAAO,SAAS,SAAS,EAAE,IAAI,SAAS,SAAS,OAAO,EAAE;AACtE,UAAQ,IAAI,6BAAS,SAAS,mBAAmB,oBAAK,EAAE;AACxD,UAAQ,IAAI,6BAAS,SAAS,SAAS,EAAE;AACzC,UAAQ,IAAI,6BAAS,SAAS,SAAS,EAAE;AACzC,UAAQ,IAAI,2BAAO;AACnB,UAAQ,IAAI,KAAK,UAAU,SAAS,YAAY,MAAM,CAAC,CAAC;AAC1D;;;ACvBA,eAAsB,YAAY,UAA8B,CAAC,GAAkB;AACjF,QAAM,YAAY,MAAM,YAAY,MAAM,eAAe,CAAC;AAC1D,MAAI,QAAQ,MAAM;AAChB,YAAQ,IAAI,KAAK,UAAU,WAAW,MAAM,CAAC,CAAC;AAC9C;AAAA,EACF;AACA,UAAQ;AAAA,IACN,UAAU,IAAI,CAAC,cAAc;AAAA,MAC3B,IAAI,SAAS;AAAA,MACb,cAAI,SAAS;AAAA,MACb,cAAI,SAAS;AAAA,MACb,cAAI,SAAS;AAAA,MACb,0BAAM,SAAS;AAAA,MACf,cAAI,SAAS,MAAM,KAAK,IAAI,KAAK;AAAA,IACnC,EAAE;AAAA,EACJ;AACF;;;ACnBA,OAAOC,YAAU;AAIjB,eAAsB,wBAAwB,cAAqC;AACjF,QAAM,OAAOC,OAAK,QAAQ,YAAY;AACtC,QAAM,WAAW,MAAM,qBAAqB,IAAI;AAChD,QAAM,WAAW,QAAQ,UAAU,CAACA,OAAK,KAAK,MAAM,WAAW,uBAAuB,CAAC,GAAG;AAAA,IACxF,KAAK;AAAA,EACP,CAAC;AACD,UAAQ,IAAI,6BAAS,SAAS,EAAE,IAAI,SAAS,OAAO,EAAE;AACxD;;;ACHA,eAAsB,kBAAkB,UAA8B,CAAC,GAAkB;AACvF,QAAM,SAAS,MAAM,eAAe;AACpC,MAAI,QAAQ,KAAM,SAAQ,IAAI,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAAA,MACxD,SAAQ,MAAM,OAAO,QAAQ,MAAM,EAAE,IAAI,CAAC,CAAC,KAAK,KAAK,OAAO,EAAE,KAAK,MAAM,EAAE,CAAC;AACjF,UAAQ,IAAI,6BAAS,kBAAkB,CAAC,EAAE;AAC5C;AAEA,eAAsB,iBAAiB,KAA4B;AACjE,QAAM,SAAS,MAAM,eAAe;AACpC,MAAI,EAAE,OAAO,QAAS,OAAM,IAAI,MAAM,yCAAW,GAAG,EAAE;AACtD,UAAQ,IAAI,OAAQ,OAA8C,GAAG,CAAC,CAAC;AACzE;AAEA,eAAsB,iBAAiB,KAAa,OAA8B;AAChF,QAAM,SAAS,MAAM,eAAe;AACpC,QAAM,CAAC,UAAU,UAAU,IAAI,qBAAqB,KAAK,KAAK;AAC9D,EAAC,OAA8C,QAAQ,IAAI;AAC3D,QAAM,eAAe,MAAM;AAC3B,UAAQ,IAAI,sBAAO,QAAQ,IAAI,OAAO,UAAU,CAAC,EAAE;AACrD;AAEA,eAAsB,mBAAmB,KAA4B;AACnE,QAAM,SAAS,MAAM,eAAe;AACpC,MAAI,EAAE,OAAO,wBAAwB,EAAE,OAAO,SAAS;AACrD,UAAM,IAAI,MAAM,yCAAW,GAAG,EAAE;AAAA,EAClC;AACA,QAAM,WAAW;AACjB,QAAM,UAAU;AAChB,MAAI,OAAO,SAAU,SAAQ,GAAG,IAAI,SAAS,GAAG;AAAA,MAC3C,QAAO,QAAQ,GAAG;AACvB,QAAM,eAAe,MAAM;AAC3B,UAAQ,IAAI,yCAAW,GAAG,EAAE;AAC9B;AAEA,eAAsB,qBAAoC;AACxD,QAAM,eAAe,EAAE,GAAG,oBAAoB,CAAC;AAC/C,UAAQ,IAAI,iEAAe,kBAAkB,CAAC,EAAE;AAClD;;;ACvCA,SAAS,YAAY,OAAuB;AAC1C,MAAI,QAAQ,KAAM,QAAO,GAAG,KAAK;AACjC,MAAI,QAAQ,QAAQ,EAAG,QAAO,IAAI,QAAQ,MAAM,QAAQ,CAAC,CAAC;AAC1D,SAAO,IAAI,QAAQ,QAAQ,GAAG,QAAQ,CAAC,CAAC;AAC1C;AAEA,eAAsB,iBAAiB,UAA8B,CAAC,GAAkB;AACtF,QAAM,UAAU,MAAM,kBAAkB;AACxC,MAAI,QAAQ,MAAM;AAChB,YAAQ,IAAI,KAAK,UAAU,SAAS,MAAM,CAAC,CAAC;AAC5C;AAAA,EACF;AACA,MAAI,CAAC,QAAQ,QAAQ;AACnB,YAAQ,IAAI,yCAAW,qBAAqB,CAAC,EAAE;AAC/C;AAAA,EACF;AACA,UAAQ;AAAA,IACN,QAAQ,IAAI,CAAC,WAAW;AAAA,MACtB,KAAK,MAAM;AAAA,MACX,cAAI,MAAM,SAAS;AAAA,MACnB,KAAK,MAAM,SAAS;AAAA,MACpB,0BAAM,MAAM,SAAS;AAAA,MACrB,cAAI,YAAY,MAAM,SAAS;AAAA,IACjC,EAAE;AAAA,EACJ;AACF;AAEA,eAAsB,oBAAmC;AACvD,QAAM,mBAAmB;AACzB,UAAQ,IAAI,+CAAY,qBAAqB,CAAC,EAAE;AAClD;;;AjBdO,SAAS,gBAAyB;AACvC,QAAM,UAAU,IAAI,QAAQ;AAC5B,UACG,KAAK,YAAY,EACjB,YAAY,qFAAyB,EACrC,QAAQ,WAAW;AAEtB,UACG,QAAQ,eAAe,EACvB,YAAY,8DAAY,EACxB,OAAO,6BAA6B,mEAAgC,EACpE,OAAO,uBAAuB,iBAAO,EACrC,OAAO,oBAAoB,sGAAsB,EACjD,OAAO,kBAAkB,iGAAsB,EAC/C,OAAO,0BAA0B,kFAAsB,EACvD,OAAO,yBAAyB,mGAA6B,EAC7D,OAAO,mBAAmB,sCAAQ,EAClC,OAAO,mBAAmB,0BAAM,EAChC,OAAO,iBAAiB,0BAAM,EAC9B,OAAO,wBAAwB,0EAAwB,EACvD,OAAO,yBAAyB,6BAAmB,EACnD,OAAO,yBAAyB,sCAAQ,EACxC,OAAO,wBAAwB,kCAAc,EAC7C,OAAO,wBAAwB,8DAAiB,EAChD,OAAO,aAAa,gFAAe,EACnC,OAAO,aAAa,wDAAW,EAC/B,OAAO,aAAa,kGAAkB,EACtC,OAAO,kBAAkB,0EAAc,EACvC,OAAO,cAAc,qCAAY,EACjC,OAAO,WAAW,8DAAY,EAC9B,OAAO,cAAc,oEAAa,EAClC,OAAO,aAAa;AAEvB,UACG,QAAQ,MAAM,EACd,YAAY,sCAAQ,EACpB,OAAO,UAAU,mBAAS,EAC1B,OAAO,WAAW;AACrB,UACG,QAAQ,QAAQ,EAChB,YAAY,0EAAc,EAC1B,OAAO,UAAU,mBAAS,EAC1B,OAAO,aAAa;AACvB,UACG,QAAQ,aAAa,EACrB,YAAY,4FAAiB,EAC7B,OAAO,UAAU,mBAAS,EAC1B,OAAO,WAAW;AAErB,QAAM,WAAW,QAAQ,QAAQ,UAAU,EAAE,YAAY,sCAAQ;AACjE,WACG,QAAQ,iBAAiB,EACzB,YAAY,kEAAqB,EACjC,OAAO,OAAO,iBAA0B;AACvC,QAAI,aAAc,QAAO,wBAAwB,YAAY;AAC7D,UAAMC,UAAS,MAAM,eAAe;AACpC,UAAM,WAAW,aAAa,MAAM,YAAYA,OAAM,CAAC;AACvD,UAAM,WAAW,MAAM;AAAA,MACrB,uBAAuB,UAAU,QAAWA,QAAO,cAAc;AAAA,MACjEA,QAAO,eAAe,SAAS;AAAA,MAC/B,EAAE,iBAAiBA,QAAO,gBAAgB;AAAA,IAC5C;AACA,QAAI;AACF,aAAO,MAAM,wBAAwB,SAAS,IAAI;AAAA,IACpD,UAAE;AACA,YAAM,SAAS,QAAQ;AAAA,IACzB;AAAA,EACF,CAAC;AAEH,QAAM,SAAS,QAAQ,QAAQ,QAAQ,EAAE,YAAY,kDAAU;AAC/D,SACG,QAAQ,MAAM,EACd,OAAO,UAAU,mBAAS,EAC1B,OAAO,iBAAiB;AAC3B,SAAO,QAAQ,WAAW,EAAE,OAAO,gBAAgB;AACnD,SAAO,QAAQ,mBAAmB,EAAE,OAAO,gBAAgB;AAC3D,SAAO,QAAQ,aAAa,EAAE,OAAO,kBAAkB;AACvD,SAAO,QAAQ,OAAO,EAAE,OAAO,kBAAkB;AAEjD,QAAM,QAAQ,QAAQ,QAAQ,OAAO,EAAE,YAAY,kDAAU;AAC7D,QACG,QAAQ,MAAM,EACd,OAAO,UAAU,mBAAS,EAC1B,OAAO,gBAAgB;AAC1B,QAAM,QAAQ,OAAO,EAAE,OAAO,iBAAiB;AAE/C,SAAO;AACT;AAEA,eAAsB,OAAO,OAAO,QAAQ,MAAqB;AAC/D,QAAM,cAAc,EAAE,WAAW,IAAI;AACvC;;;AkB/GA,OAAO,EAAE,MAAM,CAAC,UAAU;AACxB,UAAQ,MAAM;AAAA,gBAAU,MAAgB,OAAO;AAAA,CAAI;AACnD,UAAQ,WAAW;AACrB,CAAC;","names":["path","existsSync","readdir","existsSync","path","path","existsSync","mkdir","readdir","rename","rm","writeFile","existsSync","mkdir","stat","path","path","existsSync","path","existsSync","path","existsSync","mkdir","stat","existsSync","path","readdir","rename","rm","writeFile","mkdir","prompts","existsSync","rename","rm","path","path","path","path","existsSync","rename","rm","selected","existsSync","mkdir","writeFile","rm","path","satisfies","path","mkdir","writeFile","rm","satisfies","existsSync","path","existsSync","path","existsSync","path","path","config"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/cli.ts","../package.json","../src/constants.ts","../src/catalog.ts","../src/utils/fs.ts","../src/core/template-source.ts","../src/utils/process.ts","../src/core/template-cache.ts","../src/core/user-config.ts","../src/commands/create.ts","../src/core/project-generator.ts","../src/core/errors.ts","../src/core/template-manifest.ts","../src/commands/doctor.ts","../src/commands/info.ts","../src/commands/list.ts","../src/commands/template.ts","../src/commands/config.ts","../src/commands/cache.ts"],"sourcesContent":["import * as prompts from \"@clack/prompts\";\nimport { runCli } from \"./cli.js\";\n\nrunCli().catch((error) => {\n prompts.cancel(`操作失败:${(error as Error).message}`);\n process.exitCode = 1;\n});\n","import { Command } from \"commander\";\nimport { COMMAND_NAME, CLI_VERSION } from \"./constants.js\";\nimport { findTemplate, loadCatalog } from \"./catalog.js\";\nimport {\n acquireTemplateFromSources,\n resolveTemplateSources\n} from \"./core/template-source.js\";\nimport { loadUserConfig } from \"./core/user-config.js\";\nimport { createCommand } from \"./commands/create.js\";\nimport { doctorCommand } from \"./commands/doctor.js\";\nimport { infoCommand } from \"./commands/info.js\";\nimport { listCommand } from \"./commands/list.js\";\nimport { validateTemplateCommand } from \"./commands/template.js\";\nimport {\n configGetCommand,\n configListCommand,\n configResetCommand,\n configSetCommand,\n configUnsetCommand\n} from \"./commands/config.js\";\nimport { cacheClearCommand, cacheListCommand } from \"./commands/cache.js\";\n\nexport function createProgram(): Command {\n const program = new Command();\n program\n .name(COMMAND_NAME)\n .description(\"JH4J Cloud 企业内部标准化项目脚手架\")\n .version(CLI_VERSION);\n\n program\n .command(\"create [name]\")\n .description(\"根据标准模板创建项目\")\n .option(\"-c, --category <category>\", \"项目类型:frontend、backend 或 mobile\")\n .option(\"-t, --template <id>\", \"模板 ID\")\n .option(\"--features <ids>\", \"启用的模板能力,多个 ID 使用逗号分隔\")\n .option(\"--no-standards\", \"不启用模板提供的 Git/代码标准化能力\")\n .option(\"--source <path-or-url>\", \"覆盖模板源(本地目录或 Git URL)\")\n .option(\"--ref <branch-or-tag>\", \"Git 分支或标签;默认使用模板 Catalog 配置\")\n .option(\"--module <name>\", \"平台模块标识\")\n .option(\"--title <title>\", \"系统标题\")\n .option(\"--port <port>\", \"开发端口\")\n .option(\"--npm-registry <url>\", \"npm registry(需包含企业定制包)\")\n .option(\"--jhlc-registry <url>\", \"@jhlc 私有 registry\")\n .option(\"--local-backend <url>\", \"本地后端地址\")\n .option(\"--local-public <url>\", \"本地 public 地址\")\n .option(\"--config <json-file>\", \"从 JSON 文件读取创建参数\")\n .option(\"-y, --yes\", \"接受模板默认值,非交互创建\")\n .option(\"--dry-run\", \"只预览,不写入文件\")\n .option(\"--install\", \"创建完成后安装依赖(默认不安装)\")\n .option(\"--skip-install\", \"不安装依赖(兼容旧命令)\")\n .option(\"--skip-git\", \"跳过 Git 初始化\")\n .option(\"--force\", \"覆盖已存在的同名目录\")\n .option(\"--no-cache\", \"不使用已有远程模板缓存\")\n .action(createCommand);\n\n program\n .command(\"list\")\n .description(\"列出可用模板\")\n .option(\"--json\", \"输出 JSON\")\n .action(listCommand);\n program\n .command(\"doctor\")\n .description(\"检查本机环境和模板可用性\")\n .option(\"--json\", \"输出 JSON\")\n .action(doctorCommand);\n program\n .command(\"info [path]\")\n .description(\"显示已生成项目的模板与版本信息\")\n .option(\"--json\", \"输出 JSON\")\n .action(infoCommand);\n\n const template = program.command(\"template\").description(\"模板维护命令\");\n template\n .command(\"validate [path]\")\n .description(\"校验模板 manifest 与模板契约\")\n .action(async (templatePath?: string) => {\n if (templatePath) return validateTemplateCommand(templatePath);\n const config = await loadUserConfig();\n const selected = findTemplate(await loadCatalog(config));\n const acquired = await acquireTemplateFromSources(\n resolveTemplateSources(selected, undefined, config.templateSource),\n config.templateRef ?? selected.defaultRef,\n { cacheTtlMinutes: config.cacheTtlMinutes }\n );\n try {\n return await validateTemplateCommand(acquired.root);\n } finally {\n await acquired.cleanup();\n }\n });\n\n const config = program.command(\"config\").description(\"管理用户默认配置\");\n config\n .command(\"list\")\n .option(\"--json\", \"输出 JSON\")\n .action(configListCommand);\n config.command(\"get <key>\").action(configGetCommand);\n config.command(\"set <key> <value>\").action(configSetCommand);\n config.command(\"unset <key>\").action(configUnsetCommand);\n config.command(\"reset\").action(configResetCommand);\n\n const cache = program.command(\"cache\").description(\"管理远程模板缓存\");\n cache\n .command(\"list\")\n .option(\"--json\", \"输出 JSON\")\n .action(cacheListCommand);\n cache.command(\"clear\").action(cacheClearCommand);\n\n return program;\n}\n\nexport async function runCli(argv = process.argv): Promise<void> {\n await createProgram().parseAsync(argv);\n}\n","{\n \"name\": \"@agile-team/jh4j-cloud-cli\",\n \"version\": \"0.6.0\",\n \"description\": \"JH4J Cloud 企业内部标准化项目脚手架\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/ChenyCHENYU/jh4j-cloud-cli.git\"\n },\n \"homepage\": \"https://github.com/ChenyCHENYU/jh4j-cloud-cli#readme\",\n \"bugs\": {\n \"url\": \"https://github.com/ChenyCHENYU/jh4j-cloud-cli/issues\"\n },\n \"type\": \"module\",\n \"engines\": {\n \"node\": \"^22.12.0 || ^24.0.0\",\n \"pnpm\": \">=11.8.0\"\n },\n \"packageManager\": \"pnpm@11.8.0\",\n \"bin\": {\n \"jh4j\": \"bin/jh4j.js\"\n },\n \"files\": [\n \"bin\",\n \"dist\",\n \"README.md\",\n \"CHANGELOG.md\",\n \"catalog.schema.json\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"tsup --watch\",\n \"typecheck\": \"tsc --noEmit\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"start\": \"node bin/jh4j.js\",\n \"check\": \"pnpm typecheck && pnpm test && pnpm build\",\n \"prepack\": \"pnpm check\"\n },\n \"dependencies\": {\n \"@clack/prompts\": \"^1.7.0\",\n \"commander\": \"^15.0.0\",\n \"semver\": \"^7.8.5\",\n \"tar\": \"^7.5.19\"\n },\n \"publishConfig\": {\n \"access\": \"public\",\n \"registry\": \"https://registry.npmjs.org/\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^24.13.3\",\n \"@types/semver\": \"7.7.1\",\n \"tsup\": \"8.5.1\",\n \"typescript\": \"7.0.2\",\n \"vitest\": \"4.1.10\"\n }\n}\n","import packageJson from \"../package.json\" with { type: \"json\" };\n\nexport const CLI_NAME = \"@agile-team/jh4j-cloud-cli\";\nexport const CLI_VERSION = packageJson.version;\nexport const COMMAND_NAME = \"jh4j\";\nexport const SUPPORTED_NODE_MAJORS = new Set([22, 24]);\nexport const TEMPLATE_SOURCE_ENV = \"JH4J_UI_TEMPLATE_SOURCE\";\nexport const JH4J_HOME_ENV = \"JH4J_HOME\";\nexport const CATALOG_FILE_ENV = \"JH4J_CATALOG_FILE\";\nexport const USER_CONFIG_SCHEMA_VERSION = 1;\n","import { fileURLToPath } from \"node:url\";\nimport path from \"node:path\";\nimport { existsSync } from \"node:fs\";\nimport { CATALOG_FILE_ENV, TEMPLATE_SOURCE_ENV } from \"./constants.js\";\nimport { readJson } from \"./utils/fs.js\";\nimport type { CatalogFile, CatalogTemplate, UserConfig } from \"./types.js\";\n\nconst siblingTemplatePath = fileURLToPath(\n new URL(\"../../jh4j-ui-template/\", import.meta.url)\n);\nconst siblingMobileTemplatePath = fileURLToPath(\n new URL(\"../../../Robot_H5/\", import.meta.url)\n);\nconst remoteTemplateSources = [\n \"https://github.com/ChenyCHENYU/jh4j-ui-template.git\",\n \"https://gitee.com/ycyplus163/jh4j-ui-template.git\"\n];\nconst remoteMobileTemplateSources = [\n \"https://github.com/ChenyCHENYU/Robot_H5.git\",\n \"https://gitee.com/ycyplus163/robot_-h5.git\"\n];\n\nexport const BUILTIN_TEMPLATES: CatalogTemplate[] = [\n {\n id: \"web.jh4j-mf-remote\",\n name: \"JH4J PC 微前端业务模板\",\n description: \"Vue 3 + Vite + Module Federation 标准业务子系统\",\n category: \"frontend\",\n sourceEnvironment: TEMPLATE_SOURCE_ENV,\n defaultSource: existsSync(siblingTemplatePath)\n ? siblingTemplatePath\n : remoteTemplateSources[0],\n sources: remoteTemplateSources,\n defaultRef: \"main\",\n status: \"beta\",\n tags: [\"vue\", \"vite\", \"module-federation\", \"pc\"]\n },\n {\n id: \"mobile.robot-h5\",\n name: \"JH4J 移动端 H5 模板\",\n description: \"Vue 3 + Vite 7 + Vant 4 企业级移动端 H5 应用\",\n category: \"mobile\",\n sourceEnvironment: TEMPLATE_SOURCE_ENV,\n defaultSource: existsSync(siblingMobileTemplatePath)\n ? siblingMobileTemplatePath\n : remoteMobileTemplateSources[0],\n sources: remoteMobileTemplateSources,\n defaultRef: \"v1.6.0\",\n status: \"beta\",\n tags: [\"vue\", \"vite\", \"vant\", \"h5\", \"mobile\"]\n }\n];\n\nfunction validateCatalogTemplate(template: CatalogTemplate): void {\n if (!template.id || !template.name || !template.category) {\n throw new Error(\"Catalog 模板缺少 id、name 或 category\");\n }\n if (!new Set([\"frontend\", \"backend\", \"mobile\"]).has(template.category)) {\n throw new Error(`Catalog 模板 ${template.id} 的 category 无效`);\n }\n if (!new Set([\"stable\", \"beta\"]).has(template.status)) {\n throw new Error(`Catalog 模板 ${template.id} 的 status 无效`);\n }\n if (!template.defaultRef) {\n throw new Error(`Catalog 模板 ${template.id} 缺少 defaultRef`);\n }\n if (!template.defaultSource && !template.sourceEnvironment) {\n throw new Error(`Catalog 模板 ${template.id} 没有可解析的模板源`);\n }\n if (template.sources?.some((source) => !source.trim())) {\n throw new Error(`Catalog 模板 ${template.id} 包含空的备用源`);\n }\n}\n\nfunction resolveCatalogSource(source: string, catalogDirectory: string): string {\n const isRemote =\n /^(?:https?|ssh|file):\\/\\//.test(source) || source.startsWith(\"git@\");\n return isRemote || path.isAbsolute(source)\n ? source\n : path.resolve(catalogDirectory, source);\n}\n\nexport async function loadCatalog(config?: UserConfig): Promise<CatalogTemplate[]> {\n const configuredFile = process.env[CATALOG_FILE_ENV] || config?.catalogFile;\n if (!configuredFile) return [...BUILTIN_TEMPLATES];\n\n const catalogPath = path.resolve(configuredFile);\n if (!existsSync(catalogPath)) {\n throw new Error(`Catalog 文件不存在: ${catalogPath}`);\n }\n const external = await readJson<CatalogFile>(catalogPath);\n if (external.schemaVersion !== 1 || !Array.isArray(external.templates)) {\n throw new Error(`Catalog 文件格式无效: ${catalogPath}`);\n }\n const catalogDirectory = path.dirname(catalogPath);\n external.templates = external.templates.map((template) => {\n return {\n ...template,\n defaultSource: resolveCatalogSource(\n template.defaultSource,\n catalogDirectory\n ),\n sources: template.sources?.map((source) =>\n resolveCatalogSource(source, catalogDirectory)\n )\n };\n });\n external.templates.forEach(validateCatalogTemplate);\n\n const merged = new Map(BUILTIN_TEMPLATES.map((item) => [item.id, item]));\n external.templates.forEach((item) => merged.set(item.id, item));\n return [...merged.values()];\n}\n\nexport function findTemplate(\n catalog: CatalogTemplate[],\n id?: string\n): CatalogTemplate {\n const selected = id ?? catalog[0]?.id;\n const template = catalog.find((item) => item.id === selected);\n if (!template) {\n throw new Error(\n `模板不存在: ${selected}。可用模板: ${catalog.map((item) => item.id).join(\", \")}`\n );\n }\n return template;\n}\n","import { cp, mkdir, readFile, rm, stat, writeFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport path from \"node:path\";\n\nconst EXCLUDED_TEMPLATE_PATHS = new Set([\n \".git\",\n \".jhlc\",\n \"dist\",\n \"node_modules\"\n]);\n\nexport async function readJson<T>(file: string): Promise<T> {\n return JSON.parse(await readFile(file, \"utf8\")) as T;\n}\n\nexport async function writeJson(file: string, value: unknown): Promise<void> {\n await mkdir(path.dirname(file), { recursive: true });\n await writeFile(file, `${JSON.stringify(value, null, 2)}\\n`, \"utf8\");\n}\n\nexport async function isDirectory(directory: string): Promise<boolean> {\n try {\n return (await stat(directory)).isDirectory();\n } catch {\n return false;\n }\n}\n\nexport async function isDirectoryEmpty(directory: string): Promise<boolean> {\n if (!existsSync(directory)) return true;\n const { readdir } = await import(\"node:fs/promises\");\n return (await readdir(directory)).length === 0;\n}\n\nexport async function copyTemplateTree(\n sourceRoot: string,\n targetRoot: string\n): Promise<void> {\n await mkdir(targetRoot, { recursive: true });\n await cp(sourceRoot, targetRoot, {\n recursive: true,\n force: true,\n filter(source) {\n const relative = path.relative(sourceRoot, source);\n if (!relative) return true;\n const [topLevel] = relative.split(path.sep);\n return !EXCLUDED_TEMPLATE_PATHS.has(topLevel);\n }\n });\n}\n\nexport async function removePath(target: string): Promise<void> {\n await rm(target, { recursive: true, force: true, maxRetries: 3 });\n}\n","import path from \"node:path\";\nimport { existsSync } from \"node:fs\";\nimport { mkdir, readdir, rename, rm, writeFile } from \"node:fs/promises\";\nimport { x as extractTar } from \"tar\";\nimport type { CatalogTemplate } from \"../types.js\";\nimport { isDirectory } from \"../utils/fs.js\";\nimport { runCommand } from \"../utils/process.js\";\nimport {\n createTemplateCacheStaging,\n isTemplateCacheFresh,\n readTemplateCacheEntry\n} from \"./template-cache.js\";\n\nconst MAX_ARCHIVE_BYTES = 200 * 1024 * 1024;\n\nexport interface AcquiredTemplate {\n root: string;\n source: string;\n cleanup(): Promise<void>;\n}\n\nexport function resolveTemplateSource(\n template: CatalogTemplate,\n override?: string,\n configuredSource?: string\n): string {\n return resolveTemplateSources(template, override, configuredSource)[0];\n}\n\nexport function resolveTemplateSources(\n template: CatalogTemplate,\n override?: string,\n configuredSource?: string\n): string[] {\n const exclusiveSource =\n override ||\n (template.sourceEnvironment\n ? process.env[template.sourceEnvironment]\n : undefined) ||\n configuredSource;\n if (exclusiveSource) return [exclusiveSource];\n return [...new Set([template.defaultSource, ...(template.sources ?? [])])];\n}\n\nfunction isGitSource(source: string): boolean {\n return (\n source.startsWith(\"git@\") ||\n source.startsWith(\"ssh://\") ||\n source.startsWith(\"file://\") ||\n source.startsWith(\"http://\") ||\n source.startsWith(\"https://\") ||\n source.endsWith(\".git\")\n );\n}\n\nfunction isArchiveSource(source: string): boolean {\n const pathname = source.split(/[?#]/, 1)[0].toLowerCase();\n return pathname.endsWith(\".tgz\") || pathname.endsWith(\".tar.gz\") || pathname.endsWith(\".tar\");\n}\n\nasync function getFreshCache(\n source: string,\n ref: string,\n options: { noCache?: boolean; cacheTtlMinutes?: number }\n): Promise<AcquiredTemplate | null> {\n const cacheEntry = await readTemplateCacheEntry(source, ref);\n if (\n !options.noCache &&\n cacheEntry &&\n isTemplateCacheFresh(cacheEntry, options.cacheTtlMinutes ?? 60)\n ) {\n return {\n root: cacheEntry.root,\n source: `${source}#${ref} (cache)`,\n async cleanup() {}\n };\n }\n return null;\n}\n\nasync function normalizeExtractedTemplate(\n stagingRoot: string,\n templateRoot: string\n): Promise<void> {\n if (existsSync(path.join(templateRoot, \"template.manifest.json\"))) return;\n const children = await readdir(templateRoot, { withFileTypes: true });\n const candidates = children.filter(\n (entry) =>\n entry.isDirectory() &&\n existsSync(path.join(templateRoot, entry.name, \"template.manifest.json\"))\n );\n if (candidates.length !== 1) {\n throw new Error(\"压缩包根目录或唯一一级目录中未找到 template.manifest.json\");\n }\n const normalizedRoot = path.join(stagingRoot, \".normalized-template\");\n await rename(path.join(templateRoot, candidates[0].name), normalizedRoot);\n await rm(templateRoot, { recursive: true, force: true });\n await rename(normalizedRoot, templateRoot);\n}\n\nasync function acquireArchiveTemplate(\n source: string,\n ref: string,\n options: { noCache?: boolean; cacheTtlMinutes?: number }\n): Promise<AcquiredTemplate> {\n const cached = await getFreshCache(source, ref, options);\n if (cached) return cached;\n\n const cacheStaging = await createTemplateCacheStaging(source, ref);\n const archiveFile = path.join(cacheStaging.stagingRoot, \"template.tgz\");\n try {\n if (source.startsWith(\"http://\") || source.startsWith(\"https://\")) {\n const response = await fetch(source, { signal: AbortSignal.timeout(60_000) });\n if (!response.ok) {\n throw new Error(`模板压缩包下载失败: HTTP ${response.status}`);\n }\n const declaredLength = Number(response.headers.get(\"content-length\") || 0);\n if (declaredLength > MAX_ARCHIVE_BYTES) {\n throw new Error(\"模板压缩包超过 200 MB 限制\");\n }\n const archiveBuffer = Buffer.from(await response.arrayBuffer());\n if (archiveBuffer.byteLength > MAX_ARCHIVE_BYTES) {\n throw new Error(\"模板压缩包超过 200 MB 限制\");\n }\n await writeFile(archiveFile, archiveBuffer);\n } else {\n const { copyFile } = await import(\"node:fs/promises\");\n await copyFile(path.resolve(source), archiveFile);\n }\n await mkdir(cacheStaging.templateRoot, { recursive: true });\n await extractTar({ file: archiveFile, cwd: cacheStaging.templateRoot });\n await normalizeExtractedTemplate(\n cacheStaging.stagingRoot,\n cacheStaging.templateRoot\n );\n await rm(archiveFile, { force: true });\n await cacheStaging.commit();\n return {\n root: path.join(cacheStaging.entryRoot, \"template\"),\n source: `${source} (archive)`,\n async cleanup() {}\n };\n } catch (error) {\n await cacheStaging.cleanup();\n throw error;\n }\n}\n\nexport async function acquireTemplate(\n source: string,\n ref: string,\n options: { noCache?: boolean; cacheTtlMinutes?: number } = {}\n): Promise<AcquiredTemplate> {\n const localPath = path.resolve(source);\n if (existsSync(localPath)) {\n if (await isDirectory(localPath)) {\n return {\n root: localPath,\n source: localPath,\n async cleanup() {}\n };\n }\n if (isArchiveSource(localPath)) {\n return acquireArchiveTemplate(localPath, ref, options);\n }\n throw new Error(`模板源不是目录或支持的 tar 压缩包: ${localPath}`);\n }\n\n if (isArchiveSource(source)) {\n return acquireArchiveTemplate(source, ref, options);\n }\n\n if (!isGitSource(source)) {\n throw new Error(`模板源不存在: ${source}`);\n }\n\n const cached = await getFreshCache(source, ref, options);\n if (cached) return cached;\n\n const cacheStaging = await createTemplateCacheStaging(source, ref);\n try {\n await runCommand(\n \"git\",\n [\n \"-c\",\n \"http.lowSpeedLimit=1024\",\n \"-c\",\n \"http.lowSpeedTime=15\",\n \"clone\",\n \"--depth\",\n \"1\",\n \"--branch\",\n ref,\n source,\n cacheStaging.templateRoot\n ],\n { stdio: \"pipe\", env: { GIT_TERMINAL_PROMPT: \"0\" } }\n );\n await cacheStaging.commit();\n return {\n root: path.join(cacheStaging.entryRoot, \"template\"),\n source: `${source}#${ref}`,\n async cleanup() {}\n };\n } catch (error) {\n await cacheStaging.cleanup();\n throw error;\n }\n}\n\nexport async function acquireTemplateFromSources(\n sources: string[],\n ref: string,\n options: { noCache?: boolean; cacheTtlMinutes?: number } = {}\n): Promise<AcquiredTemplate> {\n if (!sources.length) throw new Error(\"没有可用的模板源\");\n const failures: string[] = [];\n for (const source of [...new Set(sources)]) {\n try {\n return await acquireTemplate(source, ref, options);\n } catch (error) {\n failures.push(`${source}: ${(error as Error).message}`);\n }\n }\n throw new Error(`所有模板源均不可用:\\n- ${failures.join(\"\\n- \")}`);\n}\n","import { spawn } from \"node:child_process\";\n\nexport interface RunCommandOptions {\n cwd?: string;\n stdio?: \"inherit\" | \"pipe\";\n env?: NodeJS.ProcessEnv;\n}\n\nexport function platformCommand(command: string): string {\n if (process.platform !== \"win32\") return command;\n return command === \"pnpm\" || command === \"npm\" || command === \"npx\"\n ? `${command}.cmd`\n : command;\n}\n\nexport async function runCommand(\n command: string,\n args: string[],\n options: RunCommandOptions = {}\n): Promise<string> {\n const stdio = options.stdio ?? \"inherit\";\n return new Promise((resolve, reject) => {\n const executable = platformCommand(command);\n const isWindowsCommand =\n process.platform === \"win32\" && executable.endsWith(\".cmd\");\n const spawnExecutable = isWindowsCommand\n ? process.env.ComSpec || \"cmd.exe\"\n : executable;\n const spawnArgs = isWindowsCommand\n ? [\"/d\", \"/s\", \"/c\", executable, ...args]\n : args;\n const child = spawn(spawnExecutable, spawnArgs, {\n cwd: options.cwd,\n stdio,\n env: { ...process.env, ...options.env },\n windowsHide: true\n });\n\n let output = \"\";\n if (stdio === \"pipe\") {\n child.stdout?.on(\"data\", (chunk) => {\n output += chunk.toString();\n });\n child.stderr?.on(\"data\", (chunk) => {\n output += chunk.toString();\n });\n }\n\n child.on(\"error\", reject);\n child.on(\"exit\", (code) => {\n if (code === 0) {\n resolve(output.trim());\n return;\n }\n reject(\n new Error(\n `${command} ${args.join(\" \")} 执行失败(exit ${code ?? \"unknown\"})${output ? `\\n${output.trim()}` : \"\"}`\n )\n );\n });\n });\n}\n\nexport async function inspectCommand(\n command: string,\n args: string[] = [\"--version\"]\n): Promise<{ ok: boolean; output: string }> {\n try {\n return { ok: true, output: await runCommand(command, args, { stdio: \"pipe\" }) };\n } catch (error) {\n return { ok: false, output: (error as Error).message };\n }\n}\n","import { createHash } from \"node:crypto\";\nimport { existsSync } from \"node:fs\";\nimport { mkdir, readdir, rename, stat } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { getJh4jHome } from \"./user-config.js\";\nimport { readJson, removePath, writeJson } from \"../utils/fs.js\";\nimport type { TemplateCacheMetadata } from \"../types.js\";\n\nconst CACHE_SCHEMA_VERSION = 1;\n\nexport interface TemplateCacheEntry {\n key: string;\n root: string;\n metadata: TemplateCacheMetadata;\n sizeBytes: number;\n}\n\nexport function getTemplateCacheRoot(): string {\n return path.join(getJh4jHome(), \"cache\", \"templates\");\n}\n\nexport function getTemplateCacheKey(source: string, ref: string): string {\n return createHash(\"sha256\").update(`${source}\\0${ref}`).digest(\"hex\").slice(0, 20);\n}\n\nfunction getEntryPaths(key: string) {\n const entryRoot = path.join(getTemplateCacheRoot(), key);\n return {\n entryRoot,\n templateRoot: path.join(entryRoot, \"template\"),\n metadataPath: path.join(entryRoot, \"metadata.json\")\n };\n}\n\nexport async function readTemplateCacheEntry(\n source: string,\n ref: string\n): Promise<TemplateCacheEntry | null> {\n const key = getTemplateCacheKey(source, ref);\n const paths = getEntryPaths(key);\n if (!existsSync(paths.templateRoot) || !existsSync(paths.metadataPath)) return null;\n try {\n const metadata = await readJson<TemplateCacheMetadata>(paths.metadataPath);\n if (\n metadata.schemaVersion !== CACHE_SCHEMA_VERSION ||\n metadata.source !== source ||\n metadata.ref !== ref\n ) {\n return null;\n }\n return {\n key,\n root: paths.templateRoot,\n metadata,\n sizeBytes: await calculateDirectorySize(paths.entryRoot)\n };\n } catch {\n return null;\n }\n}\n\nexport function isTemplateCacheFresh(\n entry: TemplateCacheEntry,\n ttlMinutes: number\n): boolean {\n if (ttlMinutes <= 0) return false;\n const cachedAt = Date.parse(entry.metadata.cachedAt);\n return Number.isFinite(cachedAt) && Date.now() - cachedAt < ttlMinutes * 60_000;\n}\n\nexport async function createTemplateCacheStaging(\n source: string,\n ref: string\n): Promise<{\n key: string;\n entryRoot: string;\n stagingRoot: string;\n templateRoot: string;\n commit(): Promise<void>;\n cleanup(): Promise<void>;\n}> {\n const key = getTemplateCacheKey(source, ref);\n const cacheRoot = getTemplateCacheRoot();\n await mkdir(cacheRoot, { recursive: true });\n const stagingRoot = path.join(\n cacheRoot,\n `.${key}.tmp-${process.pid}-${Date.now()}`\n );\n const templateRoot = path.join(stagingRoot, \"template\");\n const entryRoot = path.join(cacheRoot, key);\n await mkdir(stagingRoot, { recursive: true });\n\n return {\n key,\n entryRoot,\n stagingRoot,\n templateRoot,\n async commit() {\n await writeJson(path.join(stagingRoot, \"metadata.json\"), {\n schemaVersion: CACHE_SCHEMA_VERSION,\n source,\n ref,\n cachedAt: new Date().toISOString()\n } satisfies TemplateCacheMetadata);\n await removePath(entryRoot);\n await rename(stagingRoot, entryRoot);\n },\n cleanup: () => removePath(stagingRoot)\n };\n}\n\nasync function calculateDirectorySize(directory: string): Promise<number> {\n let total = 0;\n const entries = await readdir(directory, { withFileTypes: true });\n for (const entry of entries) {\n const absolute = path.join(directory, entry.name);\n if (entry.isDirectory()) total += await calculateDirectorySize(absolute);\n else if (entry.isFile()) total += (await stat(absolute)).size;\n }\n return total;\n}\n\nexport async function listTemplateCache(): Promise<TemplateCacheEntry[]> {\n const cacheRoot = getTemplateCacheRoot();\n if (!existsSync(cacheRoot)) return [];\n const entries: TemplateCacheEntry[] = [];\n for (const directory of await readdir(cacheRoot, { withFileTypes: true })) {\n if (!directory.isDirectory() || directory.name.startsWith(\".\")) continue;\n const paths = getEntryPaths(directory.name);\n if (!existsSync(paths.metadataPath) || !existsSync(paths.templateRoot)) continue;\n try {\n entries.push({\n key: directory.name,\n root: paths.templateRoot,\n metadata: await readJson<TemplateCacheMetadata>(paths.metadataPath),\n sizeBytes: await calculateDirectorySize(paths.entryRoot)\n });\n } catch {\n // 损坏条目由 clear 或下一次拉取覆盖。\n }\n }\n return entries.sort((a, b) =>\n b.metadata.cachedAt.localeCompare(a.metadata.cachedAt)\n );\n}\n\nexport async function clearTemplateCache(): Promise<void> {\n await removePath(getTemplateCacheRoot());\n}\n","import os from \"node:os\";\nimport path from \"node:path\";\nimport { existsSync } from \"node:fs\";\nimport { JH4J_HOME_ENV, USER_CONFIG_SCHEMA_VERSION } from \"../constants.js\";\nimport { readJson, writeJson } from \"../utils/fs.js\";\nimport type { UserConfig } from \"../types.js\";\n\nexport const DEFAULT_USER_CONFIG: UserConfig = {\n schemaVersion: USER_CONFIG_SCHEMA_VERSION,\n autoInstall: false,\n autoGit: true,\n cacheTtlMinutes: 60\n};\n\nexport function getJh4jHome(): string {\n return path.resolve(process.env[JH4J_HOME_ENV] || path.join(os.homedir(), \".jh4j\"));\n}\n\nexport function getUserConfigPath(): string {\n return path.join(getJh4jHome(), \"config.json\");\n}\n\nexport async function loadUserConfig(): Promise<UserConfig> {\n const configPath = getUserConfigPath();\n if (!existsSync(configPath)) return { ...DEFAULT_USER_CONFIG };\n\n const stored = await readJson<Partial<UserConfig>>(configPath);\n if (\n stored.schemaVersion !== undefined &&\n stored.schemaVersion !== USER_CONFIG_SCHEMA_VERSION\n ) {\n throw new Error(\n `不支持的用户配置版本: ${stored.schemaVersion},当前要求 ${USER_CONFIG_SCHEMA_VERSION}`\n );\n }\n return { ...DEFAULT_USER_CONFIG, ...stored };\n}\n\nexport async function saveUserConfig(config: UserConfig): Promise<void> {\n await writeJson(getUserConfigPath(), {\n ...config,\n schemaVersion: USER_CONFIG_SCHEMA_VERSION\n });\n}\n\nconst CONFIG_KEYS = new Set<keyof UserConfig>([\n \"catalogFile\",\n \"templateSource\",\n \"templateRef\",\n \"npmRegistry\",\n \"jhlcRegistry\",\n \"autoInstall\",\n \"autoGit\",\n \"cacheTtlMinutes\"\n]);\n\nexport function parseUserConfigValue(\n key: string,\n rawValue: string\n): [keyof UserConfig, UserConfig[keyof UserConfig]] {\n if (!CONFIG_KEYS.has(key as keyof UserConfig)) {\n throw new Error(`不支持的配置项: ${key}`);\n }\n const typedKey = key as keyof UserConfig;\n if (typedKey === \"autoInstall\" || typedKey === \"autoGit\") {\n const normalized = rawValue.toLowerCase();\n if (!new Set([\"true\", \"false\"]).has(normalized)) {\n throw new Error(`${key} 只能是 true 或 false`);\n }\n return [typedKey, normalized === \"true\"];\n }\n if (typedKey === \"cacheTtlMinutes\") {\n const value = Number(rawValue);\n if (!Number.isInteger(value) || value < 0 || value > 10080) {\n throw new Error(\"cacheTtlMinutes 必须是 0 到 10080 之间的整数\");\n }\n return [typedKey, value];\n }\n return [typedKey, rawValue.trim()];\n}\n","import * as prompts from \"@clack/prompts\";\nimport { styleText } from \"node:util\";\nimport { findTemplate, loadCatalog } from \"../catalog.js\";\nimport {\n generateProject,\n normalizeProjectName,\n type GenerateProjectResult\n} from \"../core/project-generator.js\";\nimport { UserCancelledError } from \"../core/errors.js\";\nimport { loadUserConfig } from \"../core/user-config.js\";\nimport type {\n CatalogTemplate,\n CreateOptions,\n TemplateCategory\n} from \"../types.js\";\n\nconst TEMPLATE_PRESENTATION: Record<\n TemplateCategory,\n {\n label: string;\n hint: string;\n }\n> = {\n frontend: { label: \"PC 管理端\", hint: \"Vue 3 · Vite · 微前端\" },\n backend: { label: \"后端服务\", hint: \"Java · Spring Cloud · 云原生\" },\n mobile: { label: \"移动端 H5\", hint: \"Vue 3 · Vite 7 · Vant 4\" }\n};\n\nexport type CreationMode = \"quick\" | \"custom\";\n\nfunction isCategory(value: string): value is TemplateCategory {\n return Object.hasOwn(TEMPLATE_PRESENTATION, value);\n}\n\nexport function templatesByCategory(\n templates: CatalogTemplate[],\n category: TemplateCategory\n): CatalogTemplate[] {\n return templates.filter((template) => template.category === category);\n}\n\nexport function templateOptionsFor(\n templates: CatalogTemplate[]\n): Array<{ value: string; label: string; hint: string }> {\n return templates.map((template) => ({\n value: template.id,\n label: TEMPLATE_PRESENTATION[template.category].label,\n hint: TEMPLATE_PRESENTATION[template.category].hint\n }));\n}\n\nexport function creationModeOptions(): Array<{\n value: CreationMode;\n label: string;\n hint: string;\n}> {\n return [\n {\n value: \"quick\",\n label: \"快速创建(推荐)\",\n hint: \"采用模板推荐配置,立即生成\"\n },\n {\n value: \"custom\",\n label: \"自定义创建\",\n hint: \"设置项目名、标题、端口和联调地址\"\n }\n ];\n}\n\nexport function defaultProjectNameFor(category: TemplateCategory): string {\n if (category === \"mobile\") return \"jh4j-mobile-app\";\n if (category === \"backend\") return \"jh4j-service-app\";\n return \"jh4j-ui-app\";\n}\n\nexport function projectNamePromptOptions(\n category: TemplateCategory\n): Parameters<typeof prompts.text>[0] {\n const defaultProjectName = defaultProjectNameFor(category);\n return {\n message: \"项目名称\",\n initialValue: defaultProjectName,\n defaultValue: defaultProjectName,\n validate(value) {\n return !value || normalizeProjectName(value)\n ? undefined\n : \"请输入至少一个字母或数字,例如 jh4j-mobile-app\";\n }\n };\n}\n\nasync function selectTemplate(\n templates: CatalogTemplate[],\n options: CreateOptions\n): Promise<CatalogTemplate> {\n if (options.template) {\n const selected = findTemplate(templates, options.template);\n if (options.category && selected.category !== options.category) {\n throw new Error(\n `模板 ${selected.id} 属于 ${selected.category},与 --category ${options.category} 不一致`\n );\n }\n return selected;\n }\n\n if (options.category && !isCategory(options.category)) {\n throw new Error(\n `项目类型无效: ${options.category}。可用值: frontend、backend、mobile`\n );\n }\n const candidates = options.category\n ? templatesByCategory(templates, options.category)\n : templates;\n if (!candidates.length) {\n throw new Error(\n options.category\n ? `项目类型 ${options.category} 暂无可用模板`\n : \"Catalog 中没有可用模板\"\n );\n }\n if (options.yes) return findTemplate(candidates);\n if (candidates.length === 1) return candidates[0];\n\n const selected = await prompts.select({\n message: \"选择项目模板\",\n options: templateOptionsFor(candidates),\n initialValue: candidates[0].id\n });\n if (prompts.isCancel(selected)) throw new UserCancelledError();\n return findTemplate(candidates, String(selected));\n}\n\nasync function selectCreationMode(options: CreateOptions): Promise<CreationMode> {\n if (options.yes) return \"quick\";\n const selected = await prompts.select({\n message: \"选择创建方式\",\n options: creationModeOptions(),\n initialValue: \"quick\"\n });\n if (prompts.isCancel(selected)) throw new UserCancelledError();\n return selected as CreationMode;\n}\n\nfunction presetsFor(\n category: TemplateCategory,\n features: string[]\n): string[] {\n const presets =\n category === \"mobile\"\n ? [\n \"Vue 3 / Vite 7 / Vant 4 / TypeScript\",\n \"@robot-h5/core 移动端核心能力\"\n ]\n : category === \"frontend\"\n ? [\n \"Vue 3 / Vite / Module Federation\",\n \"@jhlc/common-core 企业基础能力\"\n ]\n : [\"Java / Spring Cloud 企业服务基础能力\"];\n if (features.includes(\"git-standards\")) {\n presets.push(\"Git 提交规范、代码检查与 Git Hooks\");\n }\n presets.push(\"DEV / SIT / UAT / PRE / PRD 多环境配置\");\n return presets;\n}\n\nexport function buildCompletionContent(\n projectName: string,\n mode: CreationMode,\n result: GenerateProjectResult\n): string {\n const nextSteps = [\n `1. cd ${projectName}`,\n ...(!result.installed ? [\"2. pnpm install\", \"3. pnpm dev\"] : [\"2. pnpm dev\"])\n ];\n return [\n `项目:${projectName}`,\n `模板:${result.templateName} · v${result.templateVersion}`,\n `方式:${mode === \"quick\" ? \"快速创建\" : \"自定义创建\"}`,\n `标题:${result.configuration.title}`,\n `开发:http://localhost:${result.configuration.devServerPort}`,\n `联调:${result.configuration.localBackendUrl}`,\n \"\",\n \"已预设\",\n ...presetsFor(result.category, result.features).map((item) => ` ✓ ${item}`),\n ` ${result.gitInitialized ? \"✓ Git main 仓库已初始化\" : \"○ 未初始化 Git 仓库\"}`,\n ` ${result.installed ? \"✓ 项目依赖已安装\" : \"○ 项目依赖未安装(按需手动安装)\"}`,\n \"\",\n \"下一步\",\n ...nextSteps.map((step) => ` ${step}`),\n \"\",\n \"配置:project.config.json / .env*\"\n ].join(\"\\n\");\n}\n\nasync function executeCreateCommand(\n requestedName: string | undefined,\n options: CreateOptions\n): Promise<void> {\n const userConfig = await loadUserConfig();\n const catalog = await loadCatalog(userConfig);\n const template = await selectTemplate(catalog, options);\n const mode = await selectCreationMode(options);\n\n const defaultProjectName = defaultProjectNameFor(template.category);\n let rawProjectName = requestedName;\n if (mode === \"custom\" && !rawProjectName && !options.yes) {\n const answer = await prompts.text(\n projectNamePromptOptions(template.category)\n );\n if (prompts.isCancel(answer)) throw new UserCancelledError();\n rawProjectName = String(answer).trim() || defaultProjectName;\n }\n rawProjectName ??= defaultProjectName;\n const projectName = normalizeProjectName(rawProjectName);\n if (!projectName) {\n throw new Error(\"项目名称至少需要包含一个字母或数字\");\n }\n if (projectName !== rawProjectName) {\n prompts.log.info(`项目名称已规范化:${projectName}`);\n }\n\n const result = await generateProject(\n template,\n projectName,\n { ...options, customize: mode === \"custom\" },\n process.cwd(),\n userConfig\n );\n if (options.dryRun) {\n prompts.outro(\"Dry Run 完成,未写入任何项目文件\");\n return;\n }\n\n prompts.box(\n buildCompletionContent(projectName, mode, result),\n styleText([\"bold\", \"green\"], \" JH4J 项目已就绪 \"),\n {\n rounded: true,\n width: \"auto\",\n titleAlign: \"center\",\n withGuide: false,\n formatBorder: (value) => styleText(\"green\", value)\n }\n );\n prompts.outro(styleText(\"green\", \"创建完成,按上面的步骤启动项目\"));\n}\n\nexport async function createCommand(\n requestedName: string | undefined,\n options: CreateOptions\n): Promise<void> {\n const brand = styleText([\"bold\", \"black\", \"bgCyan\"], \" JH4J CLOUD \");\n prompts.intro(`${brand} 创建标准项目`);\n try {\n await executeCreateCommand(requestedName, options);\n } catch (error) {\n if (error instanceof UserCancelledError) {\n prompts.cancel(\"已取消创建,未写入任何项目文件\");\n return;\n }\n throw error;\n }\n}\n","import { existsSync } from \"node:fs\";\nimport { rename, rm } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport * as prompts from \"@clack/prompts\";\nimport { satisfies } from \"semver\";\nimport { CLI_NAME, CLI_VERSION } from \"../constants.js\";\nimport {\n copyTemplateTree,\n isDirectoryEmpty,\n readJson,\n removePath,\n writeJson\n} from \"../utils/fs.js\";\nimport { runCommand } from \"../utils/process.js\";\nimport {\n acquireTemplateFromSources,\n resolveTemplateSources\n} from \"./template-source.js\";\nimport { UserCancelledError } from \"./errors.js\";\nimport { loadTemplateManifest } from \"./template-manifest.js\";\nimport { DEFAULT_USER_CONFIG } from \"./user-config.js\";\nimport type {\n CatalogTemplate,\n CreateOptions,\n ProjectInput,\n TemplateManifest,\n UserConfig\n} from \"../types.js\";\n\nconst ENV_NAMES = [\"dev\", \"sit\", \"uat\", \"pre\", \"prd\"] as const;\ntype PartialProjectInput = Partial<Omit<ProjectInput, \"environments\">> & {\n environments?: Partial<ProjectInput[\"environments\"]>;\n};\n\nexport function normalizeProjectName(value: string): string {\n return value\n .trim()\n .toLowerCase()\n .replace(/\\s+/g, \"-\")\n .replace(/^[._-]+/, \"\")\n .replace(/[^a-z0-9._-]+/g, \"-\")\n .replace(/-{2,}/g, \"-\")\n .replace(/[-._]+$/, \"\");\n}\n\nfunction ensureProjectName(value: string): string {\n const name = normalizeProjectName(value);\n if (!/^[a-z0-9][a-z0-9._-]*$/.test(name)) {\n throw new Error(\"项目名称至少需要包含一个字母或数字\");\n }\n return name;\n}\n\nfunction inferModuleName(projectName: string): string {\n const inferred = projectName\n .replace(/^(?:jh4j|wl)-ui-/, \"\")\n .replace(/[^a-z0-9-]/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n return /^[a-z][a-z0-9-]*$/.test(inferred) ? inferred : \"app\";\n}\n\nfunction ensureModuleName(value: string): string {\n const name = value.trim();\n if (!/^[a-z][a-z0-9-]*$/.test(name)) {\n throw new Error(\"模块标识必须以小写字母开头,只能包含小写字母、数字和连字符\");\n }\n return name;\n}\n\nfunction ensurePort(value: string | number): number {\n const port = Number(value);\n if (!Number.isInteger(port) || port < 1024 || port > 65535) {\n throw new Error(\"开发端口必须是 1024 到 65535 之间的整数\");\n }\n return port;\n}\n\nfunction ensureHttpUrl(value: string, label: string): string {\n try {\n const url = new URL(value);\n if (url.protocol !== \"http:\" && url.protocol !== \"https:\") throw new Error();\n return value.replace(/\\/+$/, \"\");\n } catch {\n throw new Error(`${label} 必须是 http/https URL`);\n }\n}\n\nasync function askText(\n message: string,\n initialValue: string,\n validate?: (value: string | undefined) => string | undefined\n): Promise<string> {\n const answer = await prompts.text({\n message,\n initialValue,\n defaultValue: initialValue,\n validate\n });\n if (prompts.isCancel(answer)) throw new UserCancelledError();\n return String(answer).trim() || initialValue;\n}\n\nasync function loadCreateConfig(\n configFile: string | undefined,\n cwd: string\n): Promise<PartialProjectInput> {\n if (!configFile) return {};\n const resolved = path.resolve(cwd, configFile);\n if (!existsSync(resolved)) throw new Error(`创建配置文件不存在: ${resolved}`);\n return readJson<PartialProjectInput>(resolved);\n}\n\nfunction parseFeatureIds(value: string): string[] {\n return [...new Set(value.split(\",\").map((item) => item.trim()).filter(Boolean))];\n}\n\nasync function collectTemplateFeatures(\n manifest: TemplateManifest,\n fileConfig: PartialProjectInput,\n options: CreateOptions\n): Promise<string[]> {\n const available = manifest.features ?? [];\n if (!available.length) return [];\n\n const knownIds = new Set(available.map((feature) => feature.id));\n let selected = options.features\n ? parseFeatureIds(options.features)\n : Array.isArray(fileConfig.features)\n ? fileConfig.features\n : available\n .filter((feature) => feature.defaultEnabled || feature.required)\n .map((feature) => feature.id);\n\n const unknown = selected.filter((id) => !knownIds.has(id));\n if (unknown.length) {\n throw new Error(\n `模板不支持以下能力: ${unknown.join(\", \")}。可用能力: ${[...knownIds].join(\", \")}`\n );\n }\n\n if (options.standards === false) {\n selected = selected.filter((id) => {\n const feature = available.find((item) => item.id === id);\n return feature?.package !== \"@robot-admin/git-standards\";\n });\n }\n\n for (const feature of available) {\n if (feature.required && !selected.includes(feature.id)) {\n selected.push(feature.id);\n }\n }\n return selected;\n}\n\nasync function collectProjectInput(\n projectName: string,\n sourceConfig: ProjectInput,\n fileConfig: PartialProjectInput,\n options: CreateOptions,\n userConfig: UserConfig,\n features: string[]\n): Promise<ProjectInput> {\n let moduleName = options.module ?? fileConfig.moduleName ?? inferModuleName(projectName);\n let title = options.title ?? fileConfig.title ?? sourceConfig.title;\n let port: string | number =\n options.port ?? fileConfig.devServerPort ?? sourceConfig.devServerPort;\n let npmRegistry =\n options.npmRegistry ??\n fileConfig.npmRegistry ??\n userConfig.npmRegistry ??\n sourceConfig.npmRegistry;\n let jhlcRegistry =\n options.jhlcRegistry ??\n fileConfig.jhlcRegistry ??\n userConfig.jhlcRegistry ??\n sourceConfig.jhlcRegistry;\n let localBackendUrl =\n options.localBackend ?? fileConfig.localBackendUrl ?? sourceConfig.localBackendUrl;\n let localPublicUrl =\n options.localPublic ?? fileConfig.localPublicUrl ?? sourceConfig.localPublicUrl;\n const environments = structuredClone(sourceConfig.environments);\n for (const [env, value] of Object.entries(fileConfig.environments ?? {})) {\n if (value && environments[env]) {\n environments[env] = { ...environments[env], ...value };\n }\n }\n\n if (options.customize && !options.yes) {\n title = await askText(\"应用标题\", title, (value) =>\n value?.trim() ? undefined : \"应用标题不能为空\"\n );\n port = await askText(\"开发端口\", String(port), (value) => {\n const parsed = Number(value);\n return Number.isInteger(parsed) && parsed >= 1024 && parsed <= 65535\n ? undefined\n : \"请输入 1024 到 65535 之间的端口\";\n });\n localBackendUrl = await askText(\"本地联调地址\", localBackendUrl, (value) => {\n try {\n const url = new URL(value ?? \"\");\n return url.protocol === \"http:\" || url.protocol === \"https:\"\n ? undefined\n : \"请输入完整的 http/https 地址\";\n } catch {\n return \"请输入完整的 http/https 地址\";\n }\n });\n }\n\n if (!title.trim()) throw new Error(\"系统标题不能为空\");\n for (const env of ENV_NAMES) {\n if (!environments[env]) throw new Error(`缺少 ${env.toUpperCase()} 环境配置`);\n environments[env] = {\n webUrl: ensureHttpUrl(environments[env].webUrl, `${env.toUpperCase()} 平台地址`),\n apiPrefix: environments[env].apiPrefix.replace(/^\\/+|\\/+$/g, \"\")\n };\n if (!environments[env].apiPrefix) {\n throw new Error(`${env.toUpperCase()} API 前缀不能为空`);\n }\n }\n\n return {\n projectName,\n moduleName: ensureModuleName(moduleName),\n title: title.trim(),\n devServerPort: ensurePort(port),\n npmRegistry: ensureHttpUrl(npmRegistry, \"npm registry\"),\n jhlcRegistry: ensureHttpUrl(jhlcRegistry, \"@jhlc 私有 registry\"),\n localBackendUrl: ensureHttpUrl(localBackendUrl, \"本地后端地址\"),\n localPublicUrl: ensureHttpUrl(localPublicUrl, \"本地 public 地址\"),\n environments,\n features\n };\n}\n\nfunction assertSafeTarget(cwd: string, target: string): void {\n if (path.dirname(target) !== cwd || target === cwd) {\n throw new Error(\"仅允许在当前目录创建一级项目目录\");\n }\n}\n\nasync function promoteStaging(\n stagingRoot: string,\n targetRoot: string,\n force: boolean\n): Promise<void> {\n const targetExists = existsSync(targetRoot);\n if (!targetExists) {\n await rename(stagingRoot, targetRoot);\n return;\n }\n\n if (!(await isDirectoryEmpty(targetRoot)) && !force) {\n throw new Error(`目标目录已存在且非空: ${targetRoot}`);\n }\n\n const backupRoot = `${targetRoot}.jh4j-backup-${Date.now()}`;\n await rename(targetRoot, backupRoot);\n try {\n await rename(stagingRoot, targetRoot);\n } catch (error) {\n await rename(backupRoot, targetRoot);\n throw error;\n }\n try {\n await removePath(backupRoot);\n } catch {\n prompts.log.warn(`旧目录备份未能自动清理: ${backupRoot}`);\n }\n}\n\nexport interface GenerateProjectResult {\n targetRoot: string;\n templateId: string;\n templateName: string;\n templateVersion: string;\n category: TemplateManifest[\"category\"];\n source: string;\n features: string[];\n installed: boolean;\n gitInitialized: boolean;\n configuration: Pick<\n ProjectInput,\n \"title\" | \"moduleName\" | \"devServerPort\" | \"localBackendUrl\"\n >;\n}\n\nexport async function generateProject(\n catalogTemplate: CatalogTemplate,\n requestedProjectName: string,\n options: CreateOptions,\n cwd = process.cwd(),\n configuredUserConfig: UserConfig = DEFAULT_USER_CONFIG\n): Promise<GenerateProjectResult> {\n const userConfig = { ...DEFAULT_USER_CONFIG, ...configuredUserConfig };\n const projectName = ensureProjectName(requestedProjectName);\n const resolvedCwd = path.resolve(cwd);\n const targetRoot = path.resolve(resolvedCwd, projectName);\n assertSafeTarget(resolvedCwd, targetRoot);\n if (\n existsSync(targetRoot) &&\n !(await isDirectoryEmpty(targetRoot)) &&\n !options.force\n ) {\n throw new Error(`目标目录已存在且非空: ${targetRoot}`);\n }\n\n const ref = options.ref ?? userConfig.templateRef ?? catalogTemplate.defaultRef;\n const sourceValues = resolveTemplateSources(\n catalogTemplate,\n options.source,\n userConfig.templateSource\n );\n const acquisitionSpinner = options.yes\n ? undefined\n : prompts.spinner({ indicator: \"dots\" });\n acquisitionSpinner?.start(\"正在获取并校验模板\");\n let acquired: Awaited<ReturnType<typeof acquireTemplateFromSources>>;\n try {\n acquired = await acquireTemplateFromSources(sourceValues, ref, {\n noCache: options.cache === false,\n cacheTtlMinutes: userConfig.cacheTtlMinutes\n });\n acquisitionSpinner?.stop(\"模板已就绪\");\n } catch (error) {\n acquisitionSpinner?.error(\"模板获取失败\");\n throw error;\n }\n const stagingRoot = path.join(\n resolvedCwd,\n `.${projectName}.jh4j-tmp-${process.pid}-${Date.now()}`\n );\n let promoted = false;\n let generationSpinner: ReturnType<typeof prompts.spinner> | undefined;\n\n try {\n const manifest = await loadTemplateManifest(acquired.root);\n if (manifest.id !== catalogTemplate.id) {\n throw new Error(\n `模板 ID 不匹配:Catalog=${catalogTemplate.id},Manifest=${manifest.id}`\n );\n }\n if (!satisfies(process.versions.node, manifest.runtime.node)) {\n throw new Error(\n `当前 Node ${process.versions.node} 不满足模板要求 ${manifest.runtime.node}`\n );\n }\n\n const sourceProjectConfig = await readJson<\n Omit<ProjectInput, \"npmRegistry\" | \"jhlcRegistry\">\n >(path.join(acquired.root, \"project.config.json\"));\n const fileConfig = await loadCreateConfig(options.config, resolvedCwd);\n const features = await collectTemplateFeatures(manifest, fileConfig, options);\n const input = await collectProjectInput(\n projectName,\n {\n ...sourceProjectConfig,\n npmRegistry: manifest.defaults.npmRegistry,\n jhlcRegistry: manifest.defaults.jhlcRegistry\n },\n fileConfig,\n options,\n userConfig,\n features\n );\n\n const shouldInstall =\n !options.skipInstall && (options.install === true || userConfig.autoInstall);\n const shouldInitializeGit = !options.skipGit && userConfig.autoGit;\n\n if (options.dryRun) {\n prompts.note(\n [\n `模板: ${manifest.id}@${manifest.version}`,\n `来源: ${acquired.source}`,\n `目标: ${targetRoot}`,\n `模块: ${input.moduleName}`,\n `端口: ${input.devServerPort}`,\n `能力: ${input.features.length ? input.features.join(\", \") : \"无可选能力\"}`,\n `安装依赖: ${shouldInstall ? \"是\" : \"否\"}`,\n `初始化 Git: ${shouldInitializeGit ? \"是\" : \"否\"}`\n ].join(\"\\n\"),\n \"Dry Run\"\n );\n return {\n targetRoot,\n templateId: manifest.id,\n templateName: manifest.name,\n templateVersion: manifest.version,\n category: manifest.category,\n source: acquired.source,\n features: input.features,\n installed: false,\n gitInitialized: false,\n configuration: {\n title: input.title,\n moduleName: input.moduleName,\n devServerPort: input.devServerPort,\n localBackendUrl: input.localBackendUrl\n }\n };\n }\n\n generationSpinner = options.yes\n ? undefined\n : prompts.spinner({ indicator: \"dots\" });\n generationSpinner?.start(\"正在生成项目文件\");\n await copyTemplateTree(acquired.root, stagingRoot);\n const inputFile = path.join(stagingRoot, \".jh4j-cli-input.json\");\n await writeJson(inputFile, input);\n try {\n await runCommand(\n process.execPath,\n [\n path.join(stagingRoot, \"scripts\", \"setup-project.mjs\"),\n \"--yes\",\n \"--config\",\n inputFile,\n \"--created-by\",\n `${CLI_NAME}@${CLI_VERSION}`\n ],\n { cwd: stagingRoot, stdio: \"pipe\" }\n );\n } finally {\n await rm(inputFile, { force: true });\n }\n\n if (!existsSync(path.join(stagingRoot, manifest.generatedMetadata))) {\n throw new Error(`模板初始化未生成元数据: ${manifest.generatedMetadata}`);\n }\n await promoteStaging(stagingRoot, targetRoot, Boolean(options.force));\n promoted = true;\n\n let gitInitialized = false;\n if (shouldInitializeGit) {\n generationSpinner?.message(\"正在初始化 Git main 仓库\");\n await runCommand(\"git\", [\"init\", \"-b\", \"main\"], {\n cwd: targetRoot,\n stdio: \"pipe\"\n });\n gitInitialized = true;\n }\n\n if (shouldInstall) {\n generationSpinner?.message(\"正在安装项目依赖\");\n try {\n await runCommand(\"pnpm\", [\"install\"], {\n cwd: targetRoot,\n stdio: \"pipe\"\n });\n } catch (error) {\n throw new Error(\n `项目已生成,但依赖安装失败;目录已保留在 ${targetRoot}\\n${(error as Error).message}`\n );\n }\n }\n\n let initialCommitWarning: string | undefined;\n if (shouldInitializeGit) {\n generationSpinner?.message(\"正在创建初始提交\");\n await runCommand(\"git\", [\"add\", \"-A\"], { cwd: targetRoot, stdio: \"pipe\" });\n try {\n await runCommand(\n \"git\",\n [\"commit\", \"-m\", `feat(init): 基于 ${manifest.id}@${manifest.version} 初始化`],\n {\n cwd: targetRoot,\n stdio: \"pipe\",\n env: { HUSKY: \"0\" }\n }\n );\n } catch (error) {\n initialCommitWarning = `Git 已初始化,但初始提交未完成:${(error as Error).message}`;\n }\n }\n\n generationSpinner?.stop(\"项目文件初始化完成\");\n if (initialCommitWarning) prompts.log.warn(initialCommitWarning);\n\n return {\n targetRoot,\n templateId: manifest.id,\n templateName: manifest.name,\n templateVersion: manifest.version,\n category: manifest.category,\n source: acquired.source,\n features: input.features,\n installed: shouldInstall,\n gitInitialized,\n configuration: {\n title: input.title,\n moduleName: input.moduleName,\n devServerPort: input.devServerPort,\n localBackendUrl: input.localBackendUrl\n }\n };\n } catch (error) {\n generationSpinner?.error(\n promoted ? \"项目已生成,后续步骤未完成\" : \"项目生成失败\"\n );\n throw error;\n } finally {\n if (!promoted && existsSync(stagingRoot)) await removePath(stagingRoot);\n await acquired.cleanup();\n }\n}\n","export class UserCancelledError extends Error {\n constructor() {\n super(\"用户取消创建\");\n this.name = \"UserCancelledError\";\n }\n}\n","import path from \"node:path\";\nimport { readJson } from \"../utils/fs.js\";\nimport type { TemplateManifest } from \"../types.js\";\n\nexport async function loadTemplateManifest(\n templateRoot: string\n): Promise<TemplateManifest> {\n const manifest = await readJson<TemplateManifest>(\n path.join(templateRoot, \"template.manifest.json\")\n );\n const errors: string[] = [];\n\n if (manifest.schemaVersion !== 1) errors.push(\"schemaVersion 必须为 1\");\n if (!manifest.id) errors.push(\"缺少模板 id\");\n if (!manifest.name) errors.push(\"缺少模板名称\");\n if (!/^\\d+\\.\\d+\\.\\d+([+-].+)?$/.test(manifest.version ?? \"\")) {\n errors.push(\"模板 version 不是有效的语义化版本\");\n }\n if (!manifest.runtime?.node || !manifest.runtime?.packageManager) {\n errors.push(\"缺少模板运行时约束\");\n }\n if (!manifest.entry?.nonInteractive) {\n errors.push(\"缺少非交互初始化入口\");\n }\n const featureIds = new Set<string>();\n for (const feature of manifest.features ?? []) {\n if (!/^[a-z][a-z0-9-]*$/.test(feature.id)) {\n errors.push(`模板能力 id 无效: ${feature.id}`);\n }\n if (featureIds.has(feature.id)) {\n errors.push(`模板能力 id 重复: ${feature.id}`);\n }\n featureIds.add(feature.id);\n if (!feature.name || !feature.description) {\n errors.push(`模板能力 ${feature.id} 缺少名称或说明`);\n }\n }\n\n if (errors.length) {\n throw new Error(`模板 manifest 无效:\\n- ${errors.join(\"\\n- \")}`);\n }\n return manifest;\n}\n","import { existsSync } from \"node:fs\";\nimport { mkdir, writeFile, rm } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { coerce, gte, satisfies } from \"semver\";\nimport { loadCatalog } from \"../catalog.js\";\nimport { loadTemplateManifest } from \"../core/template-manifest.js\";\nimport { resolveTemplateSources } from \"../core/template-source.js\";\nimport { getJh4jHome, loadUserConfig } from \"../core/user-config.js\";\nimport { inspectCommand } from \"../utils/process.js\";\nimport type { CatalogTemplate, UserConfig } from \"../types.js\";\n\nexport interface CheckResult {\n name: string;\n ok: boolean;\n detail: string;\n}\n\nasync function checkHomeWritable(): Promise<CheckResult> {\n const home = getJh4jHome();\n const probe = path.join(home, `.write-probe-${process.pid}`);\n try {\n await mkdir(home, { recursive: true });\n await writeFile(probe, \"ok\", \"utf8\");\n await rm(probe, { force: true });\n return { name: \"JH4J_HOME\", ok: true, detail: home };\n } catch (error) {\n return { name: \"JH4J_HOME\", ok: false, detail: (error as Error).message };\n }\n}\n\nexport async function collectDoctorChecks(\n suppliedConfig?: UserConfig,\n suppliedCatalog?: CatalogTemplate[]\n): Promise<CheckResult[]> {\n const config = suppliedConfig ?? (await loadUserConfig());\n const catalog = suppliedCatalog ?? (await loadCatalog(config));\n const [git, pnpm, home] = await Promise.all([\n inspectCommand(\"git\"),\n inspectCommand(\"pnpm\"),\n checkHomeWritable()\n ]);\n const pnpmVersion = coerce(pnpm.output)?.version;\n const checks: CheckResult[] = [\n {\n name: \"Node.js\",\n ok: satisfies(process.versions.node, \"^22.12.0 || ^24.0.0\"),\n detail: `${process.versions.node}(要求 Node 22.12+ 或 24.x)`\n },\n { name: \"Git\", ok: git.ok, detail: git.output },\n {\n name: \"pnpm\",\n ok: pnpm.ok && Boolean(pnpmVersion && gte(pnpmVersion, \"11.8.0\")),\n detail: pnpm.output\n },\n home\n ];\n\n for (const template of catalog) {\n const sources = resolveTemplateSources(\n template,\n undefined,\n config.templateSource\n );\n const source = sources[0];\n if (!existsSync(source)) {\n checks.push({\n name: `模板 ${template.id}`,\n ok:\n source.startsWith(\"http://\") ||\n source.startsWith(\"https://\") ||\n source.startsWith(\"git@\"),\n detail: `远程候选源(创建时依次验证): ${sources.join(\" → \")}`\n });\n continue;\n }\n try {\n const manifest = await loadTemplateManifest(source);\n checks.push({\n name: `模板 ${template.id}`,\n ok:\n manifest.id === template.id &&\n satisfies(process.versions.node, manifest.runtime.node),\n detail: `${manifest.id}@${manifest.version} (${source})`\n });\n } catch (error) {\n checks.push({\n name: `模板 ${template.id}`,\n ok: false,\n detail: (error as Error).message\n });\n }\n }\n return checks;\n}\n\nexport async function doctorCommand(options: { json?: boolean } = {}): Promise<void> {\n const checks = await collectDoctorChecks();\n const failed = checks.filter((check) => !check.ok);\n if (options.json) {\n console.log(JSON.stringify({ ok: failed.length === 0, checks }, null, 2));\n } else {\n for (const check of checks) {\n console.log(`${check.ok ? \"✓\" : \"✗\"} ${check.name}: ${check.detail}`);\n }\n console.log(`\\n结果: ${checks.length - failed.length} 通过, ${failed.length} 失败`);\n }\n if (failed.length) process.exitCode = 1;\n}\n","import path from \"node:path\";\nimport { existsSync } from \"node:fs\";\nimport { readJson } from \"../utils/fs.js\";\nimport type { ProjectMetadata } from \"../types.js\";\n\nexport async function infoCommand(\n projectPath = process.cwd(),\n options: { json?: boolean } = {}\n): Promise<void> {\n const root = path.resolve(projectPath);\n const metadataPath = path.join(root, \".jhlc\", \"project.json\");\n if (!existsSync(metadataPath)) {\n throw new Error(`当前目录不是 JH4J CLI 创建的项目: ${metadataPath}`);\n }\n const metadata = await readJson<ProjectMetadata>(metadataPath);\n if (options.json) {\n console.log(JSON.stringify({ projectRoot: root, ...metadata }, null, 2));\n return;\n }\n console.log(`项目目录: ${root}`);\n console.log(`模板: ${metadata.template.id}@${metadata.template.version}`);\n console.log(`平台版本: ${metadata.platformVersion ?? \"未声明\"}`);\n console.log(`创建时间: ${metadata.createdAt}`);\n console.log(`创建工具: ${metadata.createdBy}`);\n console.log(\"项目参数:\");\n console.log(JSON.stringify(metadata.parameters, null, 2));\n}\n","import { loadCatalog } from \"../catalog.js\";\nimport { loadUserConfig } from \"../core/user-config.js\";\n\nexport async function listCommand(options: { json?: boolean } = {}): Promise<void> {\n const templates = await loadCatalog(await loadUserConfig());\n if (options.json) {\n console.log(JSON.stringify(templates, null, 2));\n return;\n }\n console.table(\n templates.map((template) => ({\n ID: template.id,\n 名称: template.name,\n 类型: template.category,\n 状态: template.status,\n 默认分支: template.defaultRef,\n 标签: template.tags?.join(\", \") ?? \"\"\n }))\n );\n}\n","import path from \"node:path\";\nimport { loadTemplateManifest } from \"../core/template-manifest.js\";\nimport { runCommand } from \"../utils/process.js\";\n\nexport async function validateTemplateCommand(templatePath: string): Promise<void> {\n const root = path.resolve(templatePath);\n const manifest = await loadTemplateManifest(root);\n await runCommand(process.execPath, [path.join(root, \"scripts\", \"validate-template.mjs\")], {\n cwd: root\n });\n console.log(`模板可用: ${manifest.id}@${manifest.version}`);\n}\n","import {\n DEFAULT_USER_CONFIG,\n getUserConfigPath,\n loadUserConfig,\n parseUserConfigValue,\n saveUserConfig\n} from \"../core/user-config.js\";\n\nexport async function configListCommand(options: { json?: boolean } = {}): Promise<void> {\n const config = await loadUserConfig();\n if (options.json) console.log(JSON.stringify(config, null, 2));\n else console.table(Object.entries(config).map(([key, value]) => ({ key, value })));\n console.log(`配置文件: ${getUserConfigPath()}`);\n}\n\nexport async function configGetCommand(key: string): Promise<void> {\n const config = await loadUserConfig();\n if (!(key in config)) throw new Error(`配置项不存在: ${key}`);\n console.log(String((config as unknown as Record<string, unknown>)[key]));\n}\n\nexport async function configSetCommand(key: string, value: string): Promise<void> {\n const config = await loadUserConfig();\n const [typedKey, typedValue] = parseUserConfigValue(key, value);\n (config as unknown as Record<string, unknown>)[typedKey] = typedValue;\n await saveUserConfig(config);\n console.log(`已设置 ${typedKey}=${String(typedValue)}`);\n}\n\nexport async function configUnsetCommand(key: string): Promise<void> {\n const config = await loadUserConfig();\n if (!(key in DEFAULT_USER_CONFIG) && !(key in config)) {\n throw new Error(`配置项不存在: ${key}`);\n }\n const defaults = DEFAULT_USER_CONFIG as unknown as Record<string, unknown>;\n const mutable = config as unknown as Record<string, unknown>;\n if (key in defaults) mutable[key] = defaults[key];\n else delete mutable[key];\n await saveUserConfig(config);\n console.log(`已重置配置项: ${key}`);\n}\n\nexport async function configResetCommand(): Promise<void> {\n await saveUserConfig({ ...DEFAULT_USER_CONFIG });\n console.log(`用户配置已恢复默认值: ${getUserConfigPath()}`);\n}\n","import {\n clearTemplateCache,\n getTemplateCacheRoot,\n listTemplateCache\n} from \"../core/template-cache.js\";\n\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 ** 2) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / 1024 ** 2).toFixed(1)} MB`;\n}\n\nexport async function cacheListCommand(options: { json?: boolean } = {}): Promise<void> {\n const entries = await listTemplateCache();\n if (options.json) {\n console.log(JSON.stringify(entries, null, 2));\n return;\n }\n if (!entries.length) {\n console.log(`模板缓存为空: ${getTemplateCacheRoot()}`);\n return;\n }\n console.table(\n entries.map((entry) => ({\n Key: entry.key,\n 来源: entry.metadata.source,\n Ref: entry.metadata.ref,\n 缓存时间: entry.metadata.cachedAt,\n 大小: formatBytes(entry.sizeBytes)\n }))\n );\n}\n\nexport async function cacheClearCommand(): Promise<void> {\n await clearTemplateCache();\n console.log(`模板缓存已清理: ${getTemplateCacheRoot()}`);\n}\n"],"mappings":"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","names":["prompts","path","existsSync","readdir","existsSync","path","path","existsSync","mkdir","readdir","rename","rm","writeFile","existsSync","mkdir","stat","path","path","existsSync","path","existsSync","path","existsSync","mkdir","stat","existsSync","path","readdir","rename","rm","writeFile","mkdir","prompts","existsSync","rename","rm","path","path","path","path","existsSync","rename","rm","selected","existsSync","mkdir","writeFile","rm","path","satisfies","path","mkdir","writeFile","rm","satisfies","existsSync","path","existsSync","path","existsSync","path","path","config"]}
|