@svton/cli 1.2.4 → 1.3.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
@@ -729,21 +729,53 @@ function collectEnvVars(features, config) {
729
729
  }
730
730
  async function generateEnvExample(features, config, targetPath) {
731
731
  const envVars = collectEnvVars(features, config);
732
+ if (envVars.length === 0) {
733
+ return;
734
+ }
732
735
  const content = [
736
+ "# ========================================",
733
737
  "# Environment Variables",
738
+ "# ========================================",
734
739
  "# Copy this file to .env and fill in the values",
740
+ "#",
741
+ "# IMPORTANT: Never commit .env file to version control!",
742
+ "# Add .env to your .gitignore file",
743
+ "#",
735
744
  "",
736
- ...envVars.map((envVar) => {
737
- const lines = [];
745
+ "# ========================================",
746
+ "# Application Configuration",
747
+ "# ========================================",
748
+ "NODE_ENV=development",
749
+ "PORT=3000",
750
+ "",
751
+ "# ========================================",
752
+ "# Database Configuration",
753
+ "# ========================================",
754
+ "DATABASE_URL=mysql://root:root123456@localhost:3306/{{PROJECT_NAME}}",
755
+ ""
756
+ ];
757
+ const featureGroups = {};
758
+ for (const featureKey of features) {
759
+ const feature = config.features[featureKey];
760
+ if (feature && feature.envVars.length > 0) {
761
+ featureGroups[feature.name] = feature.envVars;
762
+ }
763
+ }
764
+ for (const [featureName, vars] of Object.entries(featureGroups)) {
765
+ content.push("# ========================================");
766
+ content.push(`# ${featureName} Configuration`);
767
+ content.push("# ========================================");
768
+ for (const envVar of vars) {
738
769
  if (envVar.description) {
739
- lines.push(`# ${envVar.description}`);
770
+ content.push(`# ${envVar.description}`);
740
771
  }
741
- lines.push(`${envVar.key}=${envVar.default}`);
742
- lines.push("");
743
- return lines.join("\n");
744
- })
745
- ].join("\n");
746
- await import_fs_extra4.default.writeFile(import_path3.default.join(targetPath, ".env.example"), content);
772
+ content.push(`${envVar.key}=${envVar.default}`);
773
+ content.push("");
774
+ }
775
+ }
776
+ const envPath = import_path3.default.join(targetPath, "apps/backend/.env.example");
777
+ await import_fs_extra4.default.ensureDir(import_path3.default.dirname(envPath));
778
+ await import_fs_extra4.default.writeFile(envPath, content.join("\n"));
747
779
  logger.info("Generated .env.example");
748
780
  }
749
781
  async function copyConfigFiles(features, config, templateDir, targetPath) {
@@ -834,7 +866,7 @@ ${featuresList}
834
866
  \u5F53\u4F60\u9700\u8981\u4F7F\u7528\u67D0\u4E2A\u529F\u80FD\u65F6\uFF0C\u53EF\u4EE5\uFF1A
835
867
 
836
868
  1. \u67E5\u770B\u5BF9\u5E94\u7684 skill \u6587\u6863\u4E86\u89E3 API \u548C\u6700\u4F73\u5B9E\u8DF5
837
- 2. \u53C2\u8003 \`src/examples/\` \u76EE\u5F55\u4E0B\u7684\u793A\u4F8B\u4EE3\u7801
869
+ 2. \u53C2\u8003 \`apps/backend/src/examples/\` \u76EE\u5F55\u4E0B\u7684\u793A\u4F8B\u4EE3\u7801
838
870
  3. \u67E5\u770B\u5B98\u65B9\u6587\u6863\u83B7\u53D6\u66F4\u591A\u4FE1\u606F
839
871
 
840
872
  ## \u6587\u6863\u8D44\u6E90
@@ -847,7 +879,7 @@ ${featuresList}
847
879
  logger.info("Generated capabilities index");
848
880
  }
849
881
  async function updatePackageJson(features, config, targetPath) {
850
- const packageJsonPath = import_path3.default.join(targetPath, "package.json");
882
+ const packageJsonPath = import_path3.default.join(targetPath, "apps/backend/package.json");
851
883
  const packageJson = await import_fs_extra4.default.readJSON(packageJsonPath);
852
884
  const dependencies = collectDependencies(features, config);
853
885
  packageJson.dependencies = {
@@ -884,30 +916,62 @@ function generateModuleRegistrations(features, config) {
884
916
  return registrations.join("\n");
885
917
  }
886
918
  async function updateAppModule(features, config, targetPath) {
887
- const appModulePath = import_path3.default.join(targetPath, "src/app.module.ts");
888
- if (!await import_fs_extra4.default.pathExists(appModulePath)) {
889
- logger.warn("app.module.ts not found, skipping module injection");
919
+ if (features.length === 0) {
890
920
  return;
891
921
  }
892
- let content = await import_fs_extra4.default.readFile(appModulePath, "utf-8");
893
922
  const imports = generateModuleImports(features, config);
894
923
  const registrations = generateModuleRegistrations(features, config);
895
- const importsMatch = content.match(/imports:\s*\[([\s\S]*?)\]/);
896
- if (importsMatch) {
897
- const existingImports = importsMatch[1];
898
- const newImports = `${existingImports}
899
- ${registrations}`;
900
- content = content.replace(
901
- /imports:\s*\[([\s\S]*?)\]/,
902
- `imports: [${newImports}
903
- ]`
904
- );
905
- }
906
- const lastImportIndex = content.lastIndexOf("import ");
907
- const lastImportEnd = content.indexOf("\n", lastImportIndex);
908
- content = content.slice(0, lastImportEnd + 1) + imports + "\n" + content.slice(lastImportEnd + 1);
909
- await import_fs_extra4.default.writeFile(appModulePath, content);
910
- logger.info("Updated app.module.ts with feature modules");
924
+ const content = `# \u529F\u80FD\u6A21\u5757\u96C6\u6210\u8BF4\u660E
925
+
926
+ \u672C\u6587\u6863\u8BF4\u660E\u5982\u4F55\u5C06\u9009\u4E2D\u7684\u529F\u80FD\u6A21\u5757\u96C6\u6210\u5230 app.module.ts \u4E2D\u3002
927
+
928
+ ## 1. \u6DFB\u52A0\u5BFC\u5165\u8BED\u53E5
929
+
930
+ \u5728 \`apps/backend/src/app.module.ts\` \u6587\u4EF6\u9876\u90E8\u6DFB\u52A0\u4EE5\u4E0B\u5BFC\u5165\uFF1A
931
+
932
+ \`\`\`typescript
933
+ ${imports}
934
+ \`\`\`
935
+
936
+ ## 2. \u6CE8\u518C\u6A21\u5757
937
+
938
+ \u5728 \`@Module\` \u88C5\u9970\u5668\u7684 \`imports\` \u6570\u7EC4\u4E2D\u6DFB\u52A0\u4EE5\u4E0B\u6A21\u5757\uFF1A
939
+
940
+ \`\`\`typescript
941
+ @Module({
942
+ imports: [
943
+ // ... \u5176\u4ED6\u6A21\u5757
944
+ ${registrations}
945
+ ],
946
+ // ...
947
+ })
948
+ export class AppModule {}
949
+ \`\`\`
950
+
951
+ ## 3. \u914D\u7F6E\u6587\u4EF6
952
+
953
+ \u6BCF\u4E2A\u529F\u80FD\u7684\u914D\u7F6E\u6587\u4EF6\u5DF2\u751F\u6210\u5728 \`apps/backend/src/config/\` \u76EE\u5F55\u4E0B\uFF1A
954
+
955
+ ${features.map((key) => {
956
+ const feature = config.features[key];
957
+ return `- **${feature.name}**: \`src/config/${key}.config.ts\``;
958
+ }).join("\n")}
959
+
960
+ ## 4. \u793A\u4F8B\u4EE3\u7801
961
+
962
+ \u793A\u4F8B\u4EE3\u7801\u5DF2\u751F\u6210\u5728 \`apps/backend/src/examples/\` \u76EE\u5F55\u4E0B\uFF0C\u53EF\u4EE5\u53C2\u8003\u4F7F\u7528\u3002
963
+
964
+ ## 5. \u73AF\u5883\u53D8\u91CF
965
+
966
+ \u8BF7\u590D\u5236 \`.env.example\` \u4E3A \`.env\` \u5E76\u586B\u5199\u76F8\u5E94\u7684\u914D\u7F6E\u503C\u3002
967
+
968
+ ## 6. \u66F4\u591A\u6587\u6863
969
+
970
+ \u67E5\u770B \`.kiro/skills/\` \u76EE\u5F55\u4E0B\u7684\u8BE6\u7EC6\u6587\u6863\u4E86\u89E3\u6BCF\u4E2A\u529F\u80FD\u7684\u4F7F\u7528\u65B9\u6CD5\u3002
971
+ `;
972
+ const docPath = import_path3.default.join(targetPath, "apps/backend/FEATURE_INTEGRATION.md");
973
+ await import_fs_extra4.default.writeFile(docPath, content);
974
+ logger.info("Generated feature integration guide: apps/backend/FEATURE_INTEGRATION.md");
911
975
  }
912
976
 
913
977
  // src/commands/create.ts
@@ -1115,7 +1179,7 @@ async function createProjectFromTemplate(config) {
1115
1179
  }
1116
1180
 
1117
1181
  // package.json
1118
- var version = "1.2.4";
1182
+ var version = "1.3.0";
1119
1183
 
1120
1184
  // src/index.ts
1121
1185
  async function cli() {
package/dist/index.mjs CHANGED
@@ -702,21 +702,53 @@ function collectEnvVars(features, config) {
702
702
  }
703
703
  async function generateEnvExample(features, config, targetPath) {
704
704
  const envVars = collectEnvVars(features, config);
705
+ if (envVars.length === 0) {
706
+ return;
707
+ }
705
708
  const content = [
709
+ "# ========================================",
706
710
  "# Environment Variables",
711
+ "# ========================================",
707
712
  "# Copy this file to .env and fill in the values",
713
+ "#",
714
+ "# IMPORTANT: Never commit .env file to version control!",
715
+ "# Add .env to your .gitignore file",
716
+ "#",
708
717
  "",
709
- ...envVars.map((envVar) => {
710
- const lines = [];
718
+ "# ========================================",
719
+ "# Application Configuration",
720
+ "# ========================================",
721
+ "NODE_ENV=development",
722
+ "PORT=3000",
723
+ "",
724
+ "# ========================================",
725
+ "# Database Configuration",
726
+ "# ========================================",
727
+ "DATABASE_URL=mysql://root:root123456@localhost:3306/{{PROJECT_NAME}}",
728
+ ""
729
+ ];
730
+ const featureGroups = {};
731
+ for (const featureKey of features) {
732
+ const feature = config.features[featureKey];
733
+ if (feature && feature.envVars.length > 0) {
734
+ featureGroups[feature.name] = feature.envVars;
735
+ }
736
+ }
737
+ for (const [featureName, vars] of Object.entries(featureGroups)) {
738
+ content.push("# ========================================");
739
+ content.push(`# ${featureName} Configuration`);
740
+ content.push("# ========================================");
741
+ for (const envVar of vars) {
711
742
  if (envVar.description) {
712
- lines.push(`# ${envVar.description}`);
743
+ content.push(`# ${envVar.description}`);
713
744
  }
714
- lines.push(`${envVar.key}=${envVar.default}`);
715
- lines.push("");
716
- return lines.join("\n");
717
- })
718
- ].join("\n");
719
- await fs4.writeFile(path3.join(targetPath, ".env.example"), content);
745
+ content.push(`${envVar.key}=${envVar.default}`);
746
+ content.push("");
747
+ }
748
+ }
749
+ const envPath = path3.join(targetPath, "apps/backend/.env.example");
750
+ await fs4.ensureDir(path3.dirname(envPath));
751
+ await fs4.writeFile(envPath, content.join("\n"));
720
752
  logger.info("Generated .env.example");
721
753
  }
722
754
  async function copyConfigFiles(features, config, templateDir, targetPath) {
@@ -807,7 +839,7 @@ ${featuresList}
807
839
  \u5F53\u4F60\u9700\u8981\u4F7F\u7528\u67D0\u4E2A\u529F\u80FD\u65F6\uFF0C\u53EF\u4EE5\uFF1A
808
840
 
809
841
  1. \u67E5\u770B\u5BF9\u5E94\u7684 skill \u6587\u6863\u4E86\u89E3 API \u548C\u6700\u4F73\u5B9E\u8DF5
810
- 2. \u53C2\u8003 \`src/examples/\` \u76EE\u5F55\u4E0B\u7684\u793A\u4F8B\u4EE3\u7801
842
+ 2. \u53C2\u8003 \`apps/backend/src/examples/\` \u76EE\u5F55\u4E0B\u7684\u793A\u4F8B\u4EE3\u7801
811
843
  3. \u67E5\u770B\u5B98\u65B9\u6587\u6863\u83B7\u53D6\u66F4\u591A\u4FE1\u606F
812
844
 
813
845
  ## \u6587\u6863\u8D44\u6E90
@@ -820,7 +852,7 @@ ${featuresList}
820
852
  logger.info("Generated capabilities index");
821
853
  }
822
854
  async function updatePackageJson(features, config, targetPath) {
823
- const packageJsonPath = path3.join(targetPath, "package.json");
855
+ const packageJsonPath = path3.join(targetPath, "apps/backend/package.json");
824
856
  const packageJson = await fs4.readJSON(packageJsonPath);
825
857
  const dependencies = collectDependencies(features, config);
826
858
  packageJson.dependencies = {
@@ -857,30 +889,62 @@ function generateModuleRegistrations(features, config) {
857
889
  return registrations.join("\n");
858
890
  }
859
891
  async function updateAppModule(features, config, targetPath) {
860
- const appModulePath = path3.join(targetPath, "src/app.module.ts");
861
- if (!await fs4.pathExists(appModulePath)) {
862
- logger.warn("app.module.ts not found, skipping module injection");
892
+ if (features.length === 0) {
863
893
  return;
864
894
  }
865
- let content = await fs4.readFile(appModulePath, "utf-8");
866
895
  const imports = generateModuleImports(features, config);
867
896
  const registrations = generateModuleRegistrations(features, config);
868
- const importsMatch = content.match(/imports:\s*\[([\s\S]*?)\]/);
869
- if (importsMatch) {
870
- const existingImports = importsMatch[1];
871
- const newImports = `${existingImports}
872
- ${registrations}`;
873
- content = content.replace(
874
- /imports:\s*\[([\s\S]*?)\]/,
875
- `imports: [${newImports}
876
- ]`
877
- );
878
- }
879
- const lastImportIndex = content.lastIndexOf("import ");
880
- const lastImportEnd = content.indexOf("\n", lastImportIndex);
881
- content = content.slice(0, lastImportEnd + 1) + imports + "\n" + content.slice(lastImportEnd + 1);
882
- await fs4.writeFile(appModulePath, content);
883
- logger.info("Updated app.module.ts with feature modules");
897
+ const content = `# \u529F\u80FD\u6A21\u5757\u96C6\u6210\u8BF4\u660E
898
+
899
+ \u672C\u6587\u6863\u8BF4\u660E\u5982\u4F55\u5C06\u9009\u4E2D\u7684\u529F\u80FD\u6A21\u5757\u96C6\u6210\u5230 app.module.ts \u4E2D\u3002
900
+
901
+ ## 1. \u6DFB\u52A0\u5BFC\u5165\u8BED\u53E5
902
+
903
+ \u5728 \`apps/backend/src/app.module.ts\` \u6587\u4EF6\u9876\u90E8\u6DFB\u52A0\u4EE5\u4E0B\u5BFC\u5165\uFF1A
904
+
905
+ \`\`\`typescript
906
+ ${imports}
907
+ \`\`\`
908
+
909
+ ## 2. \u6CE8\u518C\u6A21\u5757
910
+
911
+ \u5728 \`@Module\` \u88C5\u9970\u5668\u7684 \`imports\` \u6570\u7EC4\u4E2D\u6DFB\u52A0\u4EE5\u4E0B\u6A21\u5757\uFF1A
912
+
913
+ \`\`\`typescript
914
+ @Module({
915
+ imports: [
916
+ // ... \u5176\u4ED6\u6A21\u5757
917
+ ${registrations}
918
+ ],
919
+ // ...
920
+ })
921
+ export class AppModule {}
922
+ \`\`\`
923
+
924
+ ## 3. \u914D\u7F6E\u6587\u4EF6
925
+
926
+ \u6BCF\u4E2A\u529F\u80FD\u7684\u914D\u7F6E\u6587\u4EF6\u5DF2\u751F\u6210\u5728 \`apps/backend/src/config/\` \u76EE\u5F55\u4E0B\uFF1A
927
+
928
+ ${features.map((key) => {
929
+ const feature = config.features[key];
930
+ return `- **${feature.name}**: \`src/config/${key}.config.ts\``;
931
+ }).join("\n")}
932
+
933
+ ## 4. \u793A\u4F8B\u4EE3\u7801
934
+
935
+ \u793A\u4F8B\u4EE3\u7801\u5DF2\u751F\u6210\u5728 \`apps/backend/src/examples/\` \u76EE\u5F55\u4E0B\uFF0C\u53EF\u4EE5\u53C2\u8003\u4F7F\u7528\u3002
936
+
937
+ ## 5. \u73AF\u5883\u53D8\u91CF
938
+
939
+ \u8BF7\u590D\u5236 \`.env.example\` \u4E3A \`.env\` \u5E76\u586B\u5199\u76F8\u5E94\u7684\u914D\u7F6E\u503C\u3002
940
+
941
+ ## 6. \u66F4\u591A\u6587\u6863
942
+
943
+ \u67E5\u770B \`.kiro/skills/\` \u76EE\u5F55\u4E0B\u7684\u8BE6\u7EC6\u6587\u6863\u4E86\u89E3\u6BCF\u4E2A\u529F\u80FD\u7684\u4F7F\u7528\u65B9\u6CD5\u3002
944
+ `;
945
+ const docPath = path3.join(targetPath, "apps/backend/FEATURE_INTEGRATION.md");
946
+ await fs4.writeFile(docPath, content);
947
+ logger.info("Generated feature integration guide: apps/backend/FEATURE_INTEGRATION.md");
884
948
  }
885
949
 
886
950
  // src/commands/create.ts
@@ -1088,7 +1152,7 @@ async function createProjectFromTemplate(config) {
1088
1152
  }
1089
1153
 
1090
1154
  // package.json
1091
- var version = "1.2.4";
1155
+ var version = "1.3.0";
1092
1156
 
1093
1157
  // src/index.ts
1094
1158
  async function cli() {
package/features.json CHANGED
@@ -17,7 +17,7 @@
17
17
  ],
18
18
  "configFiles": [
19
19
  {
20
- "path": "src/config/cache.config.ts",
20
+ "path": "apps/backend/src/config/cache.config.ts",
21
21
  "template": "configs/cache.config.ts"
22
22
  }
23
23
  ],
@@ -34,7 +34,7 @@
34
34
  },
35
35
  "exampleFiles": {
36
36
  "source": "examples/cache",
37
- "target": "src/examples/cache",
37
+ "target": "apps/backend/src/examples/cache",
38
38
  "description": "缓存装饰器使用示例"
39
39
  },
40
40
  "skillFile": {
@@ -58,7 +58,7 @@
58
58
  ],
59
59
  "configFiles": [
60
60
  {
61
- "path": "src/config/queue.config.ts",
61
+ "path": "apps/backend/src/config/queue.config.ts",
62
62
  "template": "configs/queue.config.ts"
63
63
  }
64
64
  ],
@@ -75,7 +75,7 @@
75
75
  },
76
76
  "exampleFiles": {
77
77
  "source": "examples/queue",
78
- "target": "src/examples/queue",
78
+ "target": "apps/backend/src/examples/queue",
79
79
  "description": "队列任务处理示例"
80
80
  },
81
81
  "skillFile": {
@@ -104,7 +104,7 @@
104
104
  ],
105
105
  "configFiles": [
106
106
  {
107
- "path": "src/config/payment.config.ts",
107
+ "path": "apps/backend/src/config/payment.config.ts",
108
108
  "template": "configs/payment.config.ts"
109
109
  }
110
110
  ],
@@ -121,7 +121,7 @@
121
121
  },
122
122
  "exampleFiles": {
123
123
  "source": "examples/payment",
124
- "target": "src/examples/payment",
124
+ "target": "apps/backend/src/examples/payment",
125
125
  "description": "支付功能示例(微信/支付宝)"
126
126
  },
127
127
  "skillFile": {
@@ -146,7 +146,7 @@
146
146
  ],
147
147
  "configFiles": [
148
148
  {
149
- "path": "src/config/oauth.config.ts",
149
+ "path": "apps/backend/src/config/oauth.config.ts",
150
150
  "template": "configs/oauth.config.ts"
151
151
  }
152
152
  ],
@@ -163,7 +163,7 @@
163
163
  },
164
164
  "exampleFiles": {
165
165
  "source": "examples/oauth",
166
- "target": "src/examples/oauth",
166
+ "target": "apps/backend/src/examples/oauth",
167
167
  "description": "OAuth 登录示例"
168
168
  },
169
169
  "skillFile": {
@@ -188,7 +188,7 @@
188
188
  ],
189
189
  "configFiles": [
190
190
  {
191
- "path": "src/config/sms.config.ts",
191
+ "path": "apps/backend/src/config/sms.config.ts",
192
192
  "template": "configs/sms.config.ts"
193
193
  }
194
194
  ],
@@ -205,7 +205,7 @@
205
205
  },
206
206
  "exampleFiles": {
207
207
  "source": "examples/sms",
208
- "target": "src/examples/sms",
208
+ "target": "apps/backend/src/examples/sms",
209
209
  "description": "短信发送示例"
210
210
  },
211
211
  "skillFile": {
@@ -232,7 +232,7 @@
232
232
  ],
233
233
  "configFiles": [
234
234
  {
235
- "path": "src/config/storage.config.ts",
235
+ "path": "apps/backend/src/config/storage.config.ts",
236
236
  "template": "configs/storage.config.ts"
237
237
  }
238
238
  ],
@@ -249,7 +249,7 @@
249
249
  },
250
250
  "exampleFiles": {
251
251
  "source": "examples/storage",
252
- "target": "src/examples/storage",
252
+ "target": "apps/backend/src/examples/storage",
253
253
  "description": "文件上传示例"
254
254
  },
255
255
  "skillFile": {
@@ -273,7 +273,7 @@
273
273
  ],
274
274
  "configFiles": [
275
275
  {
276
- "path": "src/config/rate-limit.config.ts",
276
+ "path": "apps/backend/src/config/rate-limit.config.ts",
277
277
  "template": "configs/rate-limit.config.ts"
278
278
  }
279
279
  ],
@@ -290,7 +290,7 @@
290
290
  },
291
291
  "exampleFiles": {
292
292
  "source": "examples/rate-limit",
293
- "target": "src/examples/rate-limit",
293
+ "target": "apps/backend/src/examples/rate-limit",
294
294
  "description": "限流使用示例"
295
295
  },
296
296
  "skillFile": {
@@ -310,7 +310,7 @@
310
310
  "envVars": [],
311
311
  "configFiles": [
312
312
  {
313
- "path": "src/config/authz.config.ts",
313
+ "path": "apps/backend/src/config/authz.config.ts",
314
314
  "template": "configs/authz.config.ts"
315
315
  }
316
316
  ],
@@ -327,7 +327,7 @@
327
327
  },
328
328
  "exampleFiles": {
329
329
  "source": "examples/authz",
330
- "target": "src/examples/authz",
330
+ "target": "apps/backend/src/examples/authz",
331
331
  "description": "权限控制示例"
332
332
  },
333
333
  "skillFile": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@svton/cli",
3
- "version": "1.2.4",
3
+ "version": "1.3.0",
4
4
  "description": "Svton CLI - Create full-stack applications with NestJS, Next.js, and Taro",
5
5
  "keywords": [
6
6
  "cli",