@agile-team/jh4j-cloud-cli 0.3.0 → 0.5.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/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import { Command } from "commander";
6
6
  // package.json
7
7
  var package_default = {
8
8
  name: "@agile-team/jh4j-cloud-cli",
9
- version: "0.3.0",
9
+ version: "0.5.0",
10
10
  description: "JH4J Cloud \u4F01\u4E1A\u5185\u90E8\u6807\u51C6\u5316\u9879\u76EE\u811A\u624B\u67B6",
11
11
  repository: {
12
12
  type: "git",
@@ -126,10 +126,17 @@ async function removePath(target) {
126
126
  var siblingTemplatePath = fileURLToPath(
127
127
  new URL("../../jh4j-ui-template/", import.meta.url)
128
128
  );
129
+ var siblingMobileTemplatePath = fileURLToPath(
130
+ new URL("../../../Robot_H5/", import.meta.url)
131
+ );
129
132
  var remoteTemplateSources = [
130
133
  "https://github.com/ChenyCHENYU/jh4j-ui-template.git",
131
134
  "https://gitee.com/ycyplus163/jh4j-ui-template.git"
132
135
  ];
136
+ var remoteMobileTemplateSources = [
137
+ "https://github.com/ChenyCHENYU/Robot_H5.git",
138
+ "https://gitee.com/ycyplus163/robot_-h5.git"
139
+ ];
133
140
  var BUILTIN_TEMPLATES = [
134
141
  {
135
142
  id: "web.jh4j-mf-remote",
@@ -142,6 +149,18 @@ var BUILTIN_TEMPLATES = [
142
149
  defaultRef: "main",
143
150
  status: "beta",
144
151
  tags: ["vue", "vite", "module-federation", "pc"]
152
+ },
153
+ {
154
+ id: "mobile.robot-h5",
155
+ name: "JH4J \u79FB\u52A8\u7AEF H5 \u6A21\u677F",
156
+ description: "Vue 3 + Vite 7 + Vant 4 \u4F01\u4E1A\u7EA7\u79FB\u52A8\u7AEF H5 \u5E94\u7528",
157
+ category: "mobile",
158
+ sourceEnvironment: TEMPLATE_SOURCE_ENV,
159
+ defaultSource: existsSync2(siblingMobileTemplatePath) ? siblingMobileTemplatePath : remoteMobileTemplateSources[0],
160
+ sources: remoteMobileTemplateSources,
161
+ defaultRef: "v1.6.0",
162
+ status: "beta",
163
+ tags: ["vue", "vite", "vant", "h5", "mobile"]
145
164
  }
146
165
  ];
147
166
  function validateCatalogTemplate(template) {
@@ -277,7 +296,7 @@ import path3 from "path";
277
296
  import { existsSync as existsSync3 } from "fs";
278
297
  var DEFAULT_USER_CONFIG = {
279
298
  schemaVersion: USER_CONFIG_SCHEMA_VERSION,
280
- autoInstall: true,
299
+ autoInstall: false,
281
300
  autoGit: true,
282
301
  cacheTtlMinutes: 60
283
302
  };
@@ -647,10 +666,13 @@ var ENV_NAMES = ["dev", "sit", "uat", "pre", "prd"];
647
666
  function cancelled(value) {
648
667
  return prompts.isCancel(value);
649
668
  }
669
+ function normalizeProjectName(value) {
670
+ return value.trim().toLowerCase().replace(/\s+/g, "-").replace(/^[._-]+/, "").replace(/[^a-z0-9._-]+/g, "-").replace(/-{2,}/g, "-").replace(/[-._]+$/, "");
671
+ }
650
672
  function ensureProjectName(value) {
651
- const name = value.trim();
673
+ const name = normalizeProjectName(value);
652
674
  if (!/^[a-z0-9][a-z0-9._-]*$/.test(name)) {
653
- throw new Error("\u9879\u76EE\u540D\u79F0\u53EA\u80FD\u5305\u542B\u5C0F\u5199\u5B57\u6BCD\u3001\u6570\u5B57\u3001\u70B9\u3001\u4E0B\u5212\u7EBF\u548C\u8FDE\u5B57\u7B26");
675
+ throw new Error("\u9879\u76EE\u540D\u79F0\u81F3\u5C11\u9700\u8981\u5305\u542B\u4E00\u4E2A\u5B57\u6BCD\u6216\u6570\u5B57");
654
676
  }
655
677
  return name;
656
678
  }
@@ -681,8 +703,13 @@ function ensureHttpUrl(value, label) {
681
703
  throw new Error(`${label} \u5FC5\u987B\u662F http/https URL`);
682
704
  }
683
705
  }
684
- async function askText(message, initialValue) {
685
- const answer = await prompts.text({ message, initialValue });
706
+ async function askText(message, initialValue, validate) {
707
+ const answer = await prompts.text({
708
+ message,
709
+ placeholder: initialValue,
710
+ defaultValue: initialValue,
711
+ validate
712
+ });
686
713
  if (cancelled(answer)) throw new Error("\u7528\u6237\u53D6\u6D88\u521B\u5EFA");
687
714
  return String(answer).trim() || initialValue;
688
715
  }
@@ -712,25 +739,6 @@ async function collectTemplateFeatures(manifest, fileConfig, options) {
712
739
  return feature?.package !== "@robot-admin/git-standards";
713
740
  });
714
741
  }
715
- if (!options.yes) {
716
- const selectable = available.filter(
717
- (feature) => options.standards !== false || feature.package !== "@robot-admin/git-standards"
718
- );
719
- if (selectable.length) {
720
- const answer = await prompts.multiselect({
721
- message: "\u9009\u62E9\u9879\u76EE\u6807\u51C6\u5316\u80FD\u529B",
722
- options: selectable.map((feature) => ({
723
- value: feature.id,
724
- label: feature.name,
725
- hint: `${feature.description}${feature.package ? ` \xB7 ${feature.package}` : ""}`
726
- })),
727
- initialValues: selected,
728
- required: false
729
- });
730
- if (cancelled(answer)) throw new Error("\u7528\u6237\u53D6\u6D88\u521B\u5EFA");
731
- selected = answer.map(String);
732
- }
733
- }
734
742
  for (const feature of available) {
735
743
  if (feature.required && !selected.includes(feature.id)) {
736
744
  selected.push(feature.id);
@@ -738,7 +746,7 @@ async function collectTemplateFeatures(manifest, fileConfig, options) {
738
746
  }
739
747
  return selected;
740
748
  }
741
- async function collectProjectInput(projectName, sourceConfig, fileConfig, options, userConfig, features) {
749
+ async function collectProjectInput(projectName, manifest, sourceConfig, fileConfig, options, userConfig, features) {
742
750
  let moduleName = options.module ?? fileConfig.moduleName ?? inferModuleName(projectName);
743
751
  let title = options.title ?? fileConfig.title ?? sourceConfig.title;
744
752
  let port = options.port ?? fileConfig.devServerPort ?? sourceConfig.devServerPort;
@@ -753,30 +761,27 @@ async function collectProjectInput(projectName, sourceConfig, fileConfig, option
753
761
  }
754
762
  }
755
763
  if (!options.yes) {
756
- moduleName = await askText("\u6A21\u5757\u6807\u8BC6", moduleName);
757
- title = await askText("\u7CFB\u7EDF\u6807\u9898", title);
758
- port = await askText("\u5F00\u53D1\u7AEF\u53E3", String(port));
759
- npmRegistry = await askText("npm registry", npmRegistry);
760
- jhlcRegistry = await askText("@jhlc \u79C1\u6709 registry", jhlcRegistry);
761
- localBackendUrl = await askText("\u672C\u5730\u540E\u7AEF\u5730\u5740", localBackendUrl);
762
- localPublicUrl = await askText("\u672C\u5730 public \u5730\u5740", localPublicUrl);
763
- const configureEnvironments = await prompts.confirm({
764
- message: "\u662F\u5426\u9010\u9879\u786E\u8BA4\u4E94\u5957\u73AF\u5883\u5730\u5740",
765
- initialValue: false
764
+ title = await askText(
765
+ manifest.category === "mobile" ? "\u5E94\u7528\u6807\u9898" : "\u7CFB\u7EDF\u6807\u9898",
766
+ title,
767
+ (value) => value?.trim() ? void 0 : "\u6807\u9898\u4E0D\u80FD\u4E3A\u7A7A"
768
+ );
769
+ port = await askText("\u5F00\u53D1\u7AEF\u53E3", String(port), (value) => {
770
+ const parsed = Number(value);
771
+ return Number.isInteger(parsed) && parsed >= 1024 && parsed <= 65535 ? void 0 : "\u8BF7\u8F93\u5165 1024 \u5230 65535 \u4E4B\u95F4\u7684\u7AEF\u53E3";
766
772
  });
767
- if (cancelled(configureEnvironments)) throw new Error("\u7528\u6237\u53D6\u6D88\u521B\u5EFA");
768
- if (configureEnvironments) {
769
- for (const env of ENV_NAMES) {
770
- environments[env].webUrl = await askText(
771
- `${env.toUpperCase()} \u5E73\u53F0\u5730\u5740`,
772
- environments[env].webUrl
773
- );
774
- environments[env].apiPrefix = await askText(
775
- `${env.toUpperCase()} API \u524D\u7F00`,
776
- environments[env].apiPrefix
777
- );
773
+ localBackendUrl = await askText(
774
+ manifest.category === "mobile" ? "\u672C\u5730 API \u5730\u5740" : "\u672C\u5730\u540E\u7AEF\u5730\u5740",
775
+ localBackendUrl,
776
+ (value) => {
777
+ try {
778
+ const url = new URL(value ?? "");
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
+ }
778
783
  }
779
- }
784
+ );
780
785
  }
781
786
  if (!title.trim()) throw new Error("\u7CFB\u7EDF\u6807\u9898\u4E0D\u80FD\u4E3A\u7A7A");
782
787
  for (const env of ENV_NAMES) {
@@ -845,10 +850,19 @@ async function generateProject(catalogTemplate, requestedProjectName, options, c
845
850
  options.source,
846
851
  userConfig.templateSource
847
852
  );
848
- const acquired = await acquireTemplateFromSources(sourceValues, ref, {
849
- noCache: options.cache === false,
850
- cacheTtlMinutes: userConfig.cacheTtlMinutes
851
- });
853
+ const acquisitionSpinner = options.yes ? void 0 : prompts.spinner({ indicator: "timer" });
854
+ acquisitionSpinner?.start("\u6B63\u5728\u83B7\u53D6\u5E76\u6821\u9A8C\u6A21\u677F");
855
+ let acquired;
856
+ try {
857
+ acquired = await acquireTemplateFromSources(sourceValues, ref, {
858
+ noCache: options.cache === false,
859
+ cacheTtlMinutes: userConfig.cacheTtlMinutes
860
+ });
861
+ acquisitionSpinner?.stop("\u6A21\u677F\u51C6\u5907\u5B8C\u6210");
862
+ } catch (error) {
863
+ acquisitionSpinner?.error("\u6A21\u677F\u83B7\u53D6\u5931\u8D25");
864
+ throw error;
865
+ }
852
866
  const stagingRoot = path7.join(
853
867
  resolvedCwd,
854
868
  `.${projectName}.jh4j-tmp-${process.pid}-${Date.now()}`
@@ -871,6 +885,7 @@ async function generateProject(catalogTemplate, requestedProjectName, options, c
871
885
  const features = await collectTemplateFeatures(manifest, fileConfig, options);
872
886
  const input = await collectProjectInput(
873
887
  projectName,
888
+ manifest,
874
889
  {
875
890
  ...sourceProjectConfig,
876
891
  npmRegistry: manifest.defaults.npmRegistry,
@@ -881,7 +896,7 @@ async function generateProject(catalogTemplate, requestedProjectName, options, c
881
896
  userConfig,
882
897
  features
883
898
  );
884
- const shouldInstall = !options.skipInstall && userConfig.autoInstall;
899
+ const shouldInstall = !options.skipInstall && (options.install === true || userConfig.autoInstall);
885
900
  const shouldInitializeGit = !options.skipGit && userConfig.autoGit;
886
901
  if (options.dryRun) {
887
902
  prompts.note(
@@ -982,9 +997,9 @@ ${error.message}`
982
997
 
983
998
  // src/commands/create.ts
984
999
  var CATEGORY_OPTIONS = [
985
- { value: "frontend", label: "\u524D\u7AEF", hint: "PC\u3001Web \u4E0E\u5FAE\u524D\u7AEF\u5E94\u7528" },
986
- { value: "backend", label: "\u540E\u7AEF", hint: "Java \u670D\u52A1\u4E0E\u4E91\u539F\u751F\u5E94\u7528" },
987
- { value: "mobile", label: "\u79FB\u52A8\u7AEF", hint: "App\u3001H5 \u4E0E\u8DE8\u7AEF\u5E94\u7528" }
1000
+ { value: "frontend", label: "PC \u524D\u7AEF \xB7 Vue 3 / \u5FAE\u524D\u7AEF" },
1001
+ { value: "backend", label: "\u540E\u7AEF\u670D\u52A1 \xB7 Java / \u4E91\u539F\u751F" },
1002
+ { value: "mobile", label: "\u79FB\u52A8\u7AEF H5 \xB7 Vue 3 / Vant" }
988
1003
  ];
989
1004
  function isCategory(value) {
990
1005
  return CATEGORY_OPTIONS.some((item) => item.value === value);
@@ -992,6 +1007,11 @@ function isCategory(value) {
992
1007
  function templatesByCategory(templates, category) {
993
1008
  return templates.filter((template) => template.category === category);
994
1009
  }
1010
+ function categoryOptionsFor(templates) {
1011
+ return CATEGORY_OPTIONS.filter(
1012
+ (item) => templatesByCategory(templates, item.value).length > 0
1013
+ ).map(({ value, label }) => ({ value, label }));
1014
+ }
995
1015
  async function selectCategory(templates, requestedCategory, nonInteractive) {
996
1016
  if (requestedCategory) {
997
1017
  if (!isCategory(requestedCategory)) {
@@ -1009,17 +1029,14 @@ async function selectCategory(templates, requestedCategory, nonInteractive) {
1009
1029
  );
1010
1030
  if (!firstAvailable) throw new Error("Catalog \u4E2D\u6CA1\u6709\u53EF\u7528\u6A21\u677F");
1011
1031
  if (nonInteractive) return firstAvailable.value;
1032
+ const availableOptions = categoryOptionsFor(templates);
1033
+ if (availableOptions.length === 1) return availableOptions[0].value;
1012
1034
  const selected = await prompts2.select({
1013
1035
  message: "\u9009\u62E9\u9879\u76EE\u7C7B\u578B",
1014
- options: CATEGORY_OPTIONS.map((item) => {
1015
- const count = templatesByCategory(templates, item.value).length;
1016
- return {
1017
- value: item.value,
1018
- label: item.label,
1019
- hint: count ? `${item.hint} \xB7 ${count} \u4E2A\u6A21\u677F` : `${item.hint} \xB7 \u6682\u672A\u63D0\u4F9B`,
1020
- disabled: count === 0
1021
- };
1022
- })
1036
+ options: availableOptions.map((item) => ({
1037
+ value: item.value,
1038
+ label: item.label
1039
+ }))
1023
1040
  });
1024
1041
  if (prompts2.isCancel(selected)) throw new Error("\u7528\u6237\u53D6\u6D88\u521B\u5EFA");
1025
1042
  return selected;
@@ -1041,12 +1058,16 @@ async function selectTemplate(templates, options) {
1041
1058
  );
1042
1059
  const candidates = templatesByCategory(templates, category);
1043
1060
  if (options.yes) return findTemplate(candidates);
1061
+ if (candidates.length === 1) {
1062
+ const selected2 = candidates[0];
1063
+ prompts2.log.info(`\u4F7F\u7528\u6A21\u677F\uFF1A${selected2.name}`);
1064
+ return selected2;
1065
+ }
1044
1066
  const selected = await prompts2.select({
1045
1067
  message: "\u9009\u62E9\u9879\u76EE\u6A21\u677F",
1046
1068
  options: candidates.map((template) => ({
1047
1069
  value: template.id,
1048
- label: template.name,
1049
- hint: `${template.status} \xB7 ${template.description}`
1070
+ label: `${template.name} \xB7 ${template.description}`
1050
1071
  }))
1051
1072
  });
1052
1073
  if (prompts2.isCancel(selected)) throw new Error("\u7528\u6237\u53D6\u6D88\u521B\u5EFA");
@@ -1056,17 +1077,30 @@ async function createCommand(requestedName, options) {
1056
1077
  prompts2.intro("JH4J Cloud \u9879\u76EE\u521B\u5EFA");
1057
1078
  const userConfig = await loadUserConfig();
1058
1079
  const catalog = await loadCatalog(userConfig);
1080
+ const template = await selectTemplate(catalog, options);
1059
1081
  let projectName = requestedName;
1060
1082
  if (!projectName) {
1061
1083
  if (options.yes) throw new Error("\u975E\u4EA4\u4E92\u6A21\u5F0F\u5FC5\u987B\u6307\u5B9A\u9879\u76EE\u540D\u79F0");
1084
+ const defaultProjectName = template.category === "mobile" ? "jh4j-mobile-app" : "jh4j-ui-app";
1062
1085
  const answer = await prompts2.text({
1063
1086
  message: "\u9879\u76EE\u540D\u79F0",
1064
- placeholder: "jh4j-ui-app"
1087
+ placeholder: defaultProjectName,
1088
+ defaultValue: defaultProjectName,
1089
+ validate(value) {
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
+ }
1065
1092
  });
1066
1093
  if (prompts2.isCancel(answer)) throw new Error("\u7528\u6237\u53D6\u6D88\u521B\u5EFA");
1067
- projectName = String(answer);
1094
+ projectName = String(answer).trim() || defaultProjectName;
1095
+ }
1096
+ const rawProjectName = projectName;
1097
+ projectName = normalizeProjectName(rawProjectName);
1098
+ if (!projectName) {
1099
+ throw new Error("\u9879\u76EE\u540D\u79F0\u81F3\u5C11\u9700\u8981\u5305\u542B\u4E00\u4E2A\u5B57\u6BCD\u6216\u6570\u5B57");
1100
+ }
1101
+ if (projectName !== rawProjectName) {
1102
+ prompts2.log.info(`\u9879\u76EE\u540D\u79F0\u5DF2\u89C4\u8303\u5316\uFF1A${projectName}`);
1068
1103
  }
1069
- const template = await selectTemplate(catalog, options);
1070
1104
  const result = await generateProject(
1071
1105
  template,
1072
1106
  projectName,
@@ -1083,17 +1117,22 @@ async function createCommand(requestedName, options) {
1083
1117
  `\u76EE\u5F55: ${result.targetRoot}`,
1084
1118
  `\u6A21\u677F: ${result.templateId}@${result.templateVersion}`,
1085
1119
  `\u6765\u6E90: ${result.source}`,
1086
- `\u80FD\u529B: ${result.features.length ? result.features.join(", ") : "\u65E0\u53EF\u9009\u80FD\u529B"}`,
1087
- `\u4F9D\u8D56: ${result.installed ? "\u5DF2\u5B89\u88C5" : "\u672A\u5B89\u88C5"}`,
1120
+ `\u9ED8\u8BA4\u80FD\u529B: ${result.features.length ? result.features.join(", ") : "\u65E0"}`,
1121
+ `\u4F9D\u8D56: ${result.installed ? "\u5DF2\u5B89\u88C5" : "\u672A\u5B89\u88C5\uFF08\u9ED8\u8BA4\u7531\u5F00\u53D1\u8005\u624B\u52A8\u5B89\u88C5\uFF09"}`,
1088
1122
  `Git: ${result.gitInitialized ? "main \u5DF2\u521D\u59CB\u5316" : "\u672A\u521D\u59CB\u5316"}`,
1089
1123
  "",
1124
+ "\u9700\u8981\u8C03\u6574\u914D\u7F6E\u65F6\uFF0C\u76F4\u63A5\u4FEE\u6539\u751F\u6210\u9879\u76EE\u4E2D\u7684\uFF1A",
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
+ "",
1090
1129
  `cd ${projectName}`,
1091
1130
  ...!result.installed ? ["pnpm install"] : [],
1092
1131
  "pnpm dev"
1093
1132
  ].join("\n"),
1094
1133
  "\u521B\u5EFA\u6210\u529F"
1095
1134
  );
1096
- prompts2.outro("Happy coding!");
1135
+ prompts2.outro("\u9879\u76EE\u5DF2\u51C6\u5907\u597D");
1097
1136
  }
1098
1137
 
1099
1138
  // src/commands/doctor.ts
@@ -1307,7 +1346,7 @@ async function cacheClearCommand() {
1307
1346
  function createProgram() {
1308
1347
  const program = new Command();
1309
1348
  program.name(COMMAND_NAME).description("JH4J Cloud \u4F01\u4E1A\u5185\u90E8\u6807\u51C6\u5316\u9879\u76EE\u811A\u624B\u67B6").version(CLI_VERSION);
1310
- program.command("create [name]").description("\u6839\u636E\u6807\u51C6\u6A21\u677F\u521B\u5EFA\u9879\u76EE").option("-c, --category <category>", "\u9879\u76EE\u7C7B\u578B\uFF1Afrontend\u3001backend \u6216 mobile").option("-t, --template <id>", "\u6A21\u677F ID").option("--features <ids>", "\u542F\u7528\u7684\u6A21\u677F\u80FD\u529B\uFF0C\u591A\u4E2A ID \u4F7F\u7528\u9017\u53F7\u5206\u9694").option("--no-standards", "\u4E0D\u542F\u7528\u6A21\u677F\u63D0\u4F9B\u7684 Git/\u4EE3\u7801\u6807\u51C6\u5316\u80FD\u529B").option("--source <path-or-url>", "\u8986\u76D6\u6A21\u677F\u6E90\uFF08\u672C\u5730\u76EE\u5F55\u6216 Git URL\uFF09").option("--ref <branch-or-tag>", "Git \u5206\u652F\u6216\u6807\u7B7E", "main").option("--module <name>", "\u5E73\u53F0\u6A21\u5757\u6807\u8BC6").option("--title <title>", "\u7CFB\u7EDF\u6807\u9898").option("--port <port>", "\u5F00\u53D1\u7AEF\u53E3").option("--npm-registry <url>", "npm registry\uFF08\u9700\u5305\u542B\u4F01\u4E1A\u5B9A\u5236\u5305\uFF09").option("--jhlc-registry <url>", "@jhlc \u79C1\u6709 registry").option("--local-backend <url>", "\u672C\u5730\u540E\u7AEF\u5730\u5740").option("--local-public <url>", "\u672C\u5730 public \u5730\u5740").option("--config <json-file>", "\u4ECE JSON \u6587\u4EF6\u8BFB\u53D6\u521B\u5EFA\u53C2\u6570").option("-y, --yes", "\u63A5\u53D7\u6A21\u677F\u9ED8\u8BA4\u503C\uFF0C\u975E\u4EA4\u4E92\u521B\u5EFA").option("--dry-run", "\u53EA\u9884\u89C8\uFF0C\u4E0D\u5199\u5165\u6587\u4EF6").option("--skip-install", "\u8DF3\u8FC7\u4F9D\u8D56\u5B89\u88C5").option("--skip-git", "\u8DF3\u8FC7 Git \u521D\u59CB\u5316").option("--force", "\u8986\u76D6\u5DF2\u5B58\u5728\u7684\u540C\u540D\u76EE\u5F55").option("--no-cache", "\u4E0D\u4F7F\u7528\u5DF2\u6709\u8FDC\u7A0B\u6A21\u677F\u7F13\u5B58").action(createCommand);
1349
+ program.command("create [name]").description("\u6839\u636E\u6807\u51C6\u6A21\u677F\u521B\u5EFA\u9879\u76EE").option("-c, --category <category>", "\u9879\u76EE\u7C7B\u578B\uFF1Afrontend\u3001backend \u6216 mobile").option("-t, --template <id>", "\u6A21\u677F ID").option("--features <ids>", "\u542F\u7528\u7684\u6A21\u677F\u80FD\u529B\uFF0C\u591A\u4E2A ID \u4F7F\u7528\u9017\u53F7\u5206\u9694").option("--no-standards", "\u4E0D\u542F\u7528\u6A21\u677F\u63D0\u4F9B\u7684 Git/\u4EE3\u7801\u6807\u51C6\u5316\u80FD\u529B").option("--source <path-or-url>", "\u8986\u76D6\u6A21\u677F\u6E90\uFF08\u672C\u5730\u76EE\u5F55\u6216 Git URL\uFF09").option("--ref <branch-or-tag>", "Git \u5206\u652F\u6216\u6807\u7B7E\uFF1B\u9ED8\u8BA4\u4F7F\u7528\u6A21\u677F Catalog \u914D\u7F6E").option("--module <name>", "\u5E73\u53F0\u6A21\u5757\u6807\u8BC6").option("--title <title>", "\u7CFB\u7EDF\u6807\u9898").option("--port <port>", "\u5F00\u53D1\u7AEF\u53E3").option("--npm-registry <url>", "npm registry\uFF08\u9700\u5305\u542B\u4F01\u4E1A\u5B9A\u5236\u5305\uFF09").option("--jhlc-registry <url>", "@jhlc \u79C1\u6709 registry").option("--local-backend <url>", "\u672C\u5730\u540E\u7AEF\u5730\u5740").option("--local-public <url>", "\u672C\u5730 public \u5730\u5740").option("--config <json-file>", "\u4ECE JSON \u6587\u4EF6\u8BFB\u53D6\u521B\u5EFA\u53C2\u6570").option("-y, --yes", "\u63A5\u53D7\u6A21\u677F\u9ED8\u8BA4\u503C\uFF0C\u975E\u4EA4\u4E92\u521B\u5EFA").option("--dry-run", "\u53EA\u9884\u89C8\uFF0C\u4E0D\u5199\u5165\u6587\u4EF6").option("--install", "\u521B\u5EFA\u5B8C\u6210\u540E\u5B89\u88C5\u4F9D\u8D56\uFF08\u9ED8\u8BA4\u4E0D\u5B89\u88C5\uFF09").option("--skip-install", "\u4E0D\u5B89\u88C5\u4F9D\u8D56\uFF08\u517C\u5BB9\u65E7\u547D\u4EE4\uFF09").option("--skip-git", "\u8DF3\u8FC7 Git \u521D\u59CB\u5316").option("--force", "\u8986\u76D6\u5DF2\u5B58\u5728\u7684\u540C\u540D\u76EE\u5F55").option("--no-cache", "\u4E0D\u4F7F\u7528\u5DF2\u6709\u8FDC\u7A0B\u6A21\u677F\u7F13\u5B58").action(createCommand);
1311
1350
  program.command("list").description("\u5217\u51FA\u53EF\u7528\u6A21\u677F").option("--json", "\u8F93\u51FA JSON").action(listCommand);
1312
1351
  program.command("doctor").description("\u68C0\u67E5\u672C\u673A\u73AF\u5883\u548C\u6A21\u677F\u53EF\u7528\u6027").option("--json", "\u8F93\u51FA JSON").action(doctorCommand);
1313
1352
  program.command("info [path]").description("\u663E\u793A\u5DF2\u751F\u6210\u9879\u76EE\u7684\u6A21\u677F\u4E0E\u7248\u672C\u4FE1\u606F").option("--json", "\u8F93\u51FA JSON").action(infoCommand);