@svton/cli 1.3.0 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,105 @@
1
+ import "./chunk-Y6FXYEAI.mjs";
2
+
3
+ // src/utils/ast-helper.ts
4
+ import * as parser from "@babel/parser";
5
+ import traverse from "@babel/traverse";
6
+ import generate from "@babel/generator";
7
+ import * as t from "@babel/types";
8
+ import fs from "fs-extra";
9
+ function addImportToFile(code, importDeclarations) {
10
+ const ast = parser.parse(code, {
11
+ sourceType: "module",
12
+ plugins: ["typescript", "decorators-legacy"]
13
+ });
14
+ let lastImportIndex = -1;
15
+ traverse(ast, {
16
+ ImportDeclaration(path) {
17
+ const start = path.node.start;
18
+ if (start !== null && start !== void 0 && start > lastImportIndex) {
19
+ lastImportIndex = start;
20
+ }
21
+ }
22
+ });
23
+ const newImports = importDeclarations.map(({ from, imports }) => {
24
+ const specifiers = imports.map(
25
+ (imp) => t.importSpecifier(t.identifier(imp), t.identifier(imp))
26
+ );
27
+ return t.importDeclaration(specifiers, t.stringLiteral(from));
28
+ });
29
+ if (lastImportIndex >= 0) {
30
+ const program = ast.program;
31
+ const lastImportNode = program.body.find(
32
+ (node) => node.type === "ImportDeclaration" && node.start !== null && node.start === lastImportIndex
33
+ );
34
+ if (lastImportNode) {
35
+ const index = program.body.indexOf(lastImportNode);
36
+ program.body.splice(index + 1, 0, ...newImports);
37
+ }
38
+ } else {
39
+ ast.program.body.unshift(...newImports);
40
+ }
41
+ const output = generate(ast, {
42
+ retainLines: false,
43
+ compact: false
44
+ });
45
+ return output.code;
46
+ }
47
+ function addModuleImports(code, moduleExpressions) {
48
+ const ast = parser.parse(code, {
49
+ sourceType: "module",
50
+ plugins: ["typescript", "decorators-legacy"]
51
+ });
52
+ let modified = false;
53
+ traverse(ast, {
54
+ Decorator(path) {
55
+ if (t.isCallExpression(path.node.expression) && t.isIdentifier(path.node.expression.callee) && path.node.expression.callee.name === "Module") {
56
+ const args = path.node.expression.arguments;
57
+ if (args.length > 0 && t.isObjectExpression(args[0])) {
58
+ const moduleConfig = args[0];
59
+ const importsProperty = moduleConfig.properties.find(
60
+ (prop) => t.isObjectProperty(prop) && t.isIdentifier(prop.key) && prop.key.name === "imports"
61
+ );
62
+ if (importsProperty && t.isObjectProperty(importsProperty)) {
63
+ if (t.isArrayExpression(importsProperty.value)) {
64
+ for (const expr of moduleExpressions) {
65
+ try {
66
+ const exprAst = parser.parseExpression(expr, {
67
+ plugins: ["typescript"]
68
+ });
69
+ importsProperty.value.elements.push(exprAst);
70
+ modified = true;
71
+ } catch (error) {
72
+ console.error(`Failed to parse expression: ${expr}`, error);
73
+ }
74
+ }
75
+ }
76
+ }
77
+ }
78
+ }
79
+ }
80
+ });
81
+ if (!modified) {
82
+ console.warn("Could not find @Module decorator or imports array");
83
+ return code;
84
+ }
85
+ const output = generate(ast, {
86
+ retainLines: false,
87
+ compact: false
88
+ });
89
+ return output.code;
90
+ }
91
+ async function updateAppModuleFile(filePath, imports, moduleExpressions) {
92
+ let code = await fs.readFile(filePath, "utf-8");
93
+ if (imports.length > 0) {
94
+ code = addImportToFile(code, imports);
95
+ }
96
+ if (moduleExpressions.length > 0) {
97
+ code = addModuleImports(code, moduleExpressions);
98
+ }
99
+ await fs.writeFile(filePath, code, "utf-8");
100
+ }
101
+ export {
102
+ addImportToFile,
103
+ addModuleImports,
104
+ updateAppModuleFile
105
+ };
@@ -0,0 +1,105 @@
1
+ import "./chunk-Y6FXYEAI.mjs";
2
+
3
+ // src/utils/ast-helper.ts
4
+ import * as parser from "@babel/parser";
5
+ import traverse from "@babel/traverse";
6
+ import generate from "@babel/generator";
7
+ import * as t from "@babel/types";
8
+ import fs from "fs-extra";
9
+ function addImportToFile(code, importDeclarations) {
10
+ const ast = parser.parse(code, {
11
+ sourceType: "module",
12
+ plugins: ["typescript", "decorators-legacy"]
13
+ });
14
+ let lastImportIndex = -1;
15
+ traverse(ast, {
16
+ ImportDeclaration(path) {
17
+ const start = path.node.start;
18
+ if (start !== null && start > lastImportIndex) {
19
+ lastImportIndex = start;
20
+ }
21
+ }
22
+ });
23
+ const newImports = importDeclarations.map(({ from, imports }) => {
24
+ const specifiers = imports.map(
25
+ (imp) => t.importSpecifier(t.identifier(imp), t.identifier(imp))
26
+ );
27
+ return t.importDeclaration(specifiers, t.stringLiteral(from));
28
+ });
29
+ if (lastImportIndex >= 0) {
30
+ const program = ast.program;
31
+ const lastImportNode = program.body.find(
32
+ (node) => node.type === "ImportDeclaration" && node.start === lastImportIndex
33
+ );
34
+ if (lastImportNode) {
35
+ const index = program.body.indexOf(lastImportNode);
36
+ program.body.splice(index + 1, 0, ...newImports);
37
+ }
38
+ } else {
39
+ ast.program.body.unshift(...newImports);
40
+ }
41
+ const output = generate(ast, {
42
+ retainLines: false,
43
+ compact: false
44
+ });
45
+ return output.code;
46
+ }
47
+ function addModuleImports(code, moduleExpressions) {
48
+ const ast = parser.parse(code, {
49
+ sourceType: "module",
50
+ plugins: ["typescript", "decorators-legacy"]
51
+ });
52
+ let modified = false;
53
+ traverse(ast, {
54
+ Decorator(path) {
55
+ if (t.isCallExpression(path.node.expression) && t.isIdentifier(path.node.expression.callee) && path.node.expression.callee.name === "Module") {
56
+ const args = path.node.expression.arguments;
57
+ if (args.length > 0 && t.isObjectExpression(args[0])) {
58
+ const moduleConfig = args[0];
59
+ const importsProperty = moduleConfig.properties.find(
60
+ (prop) => t.isObjectProperty(prop) && t.isIdentifier(prop.key) && prop.key.name === "imports"
61
+ );
62
+ if (importsProperty && t.isObjectProperty(importsProperty)) {
63
+ if (t.isArrayExpression(importsProperty.value)) {
64
+ for (const expr of moduleExpressions) {
65
+ try {
66
+ const exprAst = parser.parseExpression(expr, {
67
+ plugins: ["typescript"]
68
+ });
69
+ importsProperty.value.elements.push(exprAst);
70
+ modified = true;
71
+ } catch (error) {
72
+ console.error(`Failed to parse expression: ${expr}`, error);
73
+ }
74
+ }
75
+ }
76
+ }
77
+ }
78
+ }
79
+ }
80
+ });
81
+ if (!modified) {
82
+ console.warn("Could not find @Module decorator or imports array");
83
+ return code;
84
+ }
85
+ const output = generate(ast, {
86
+ retainLines: false,
87
+ compact: false
88
+ });
89
+ return output.code;
90
+ }
91
+ async function updateAppModuleFile(filePath, imports, moduleExpressions) {
92
+ let code = await fs.readFile(filePath, "utf-8");
93
+ if (imports.length > 0) {
94
+ code = addImportToFile(code, imports);
95
+ }
96
+ if (moduleExpressions.length > 0) {
97
+ code = addModuleImports(code, moduleExpressions);
98
+ }
99
+ await fs.writeFile(filePath, code, "utf-8");
100
+ }
101
+ export {
102
+ addImportToFile,
103
+ addModuleImports,
104
+ updateAppModuleFile
105
+ };
@@ -0,0 +1,10 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
8
+ export {
9
+ __require
10
+ };
package/dist/index.js CHANGED
@@ -6,6 +6,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
7
  var __getProtoOf = Object.getPrototypeOf;
8
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __esm = (fn, res) => function __init() {
10
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
11
+ };
9
12
  var __export = (target, all) => {
10
13
  for (var name in all)
11
14
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -28,6 +31,117 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
31
  ));
29
32
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
33
 
34
+ // src/utils/ast-helper.ts
35
+ var ast_helper_exports = {};
36
+ __export(ast_helper_exports, {
37
+ addImportToFile: () => addImportToFile,
38
+ addModuleImports: () => addModuleImports,
39
+ updateAppModuleFile: () => updateAppModuleFile
40
+ });
41
+ function addImportToFile(code, importDeclarations) {
42
+ const ast = parser.parse(code, {
43
+ sourceType: "module",
44
+ plugins: ["typescript", "decorators-legacy"]
45
+ });
46
+ let lastImportIndex = -1;
47
+ (0, import_traverse.default)(ast, {
48
+ ImportDeclaration(path5) {
49
+ const start = path5.node.start;
50
+ if (start !== null && start !== void 0 && start > lastImportIndex) {
51
+ lastImportIndex = start;
52
+ }
53
+ }
54
+ });
55
+ const newImports = importDeclarations.map(({ from, imports }) => {
56
+ const specifiers = imports.map(
57
+ (imp) => t.importSpecifier(t.identifier(imp), t.identifier(imp))
58
+ );
59
+ return t.importDeclaration(specifiers, t.stringLiteral(from));
60
+ });
61
+ if (lastImportIndex >= 0) {
62
+ const program = ast.program;
63
+ const lastImportNode = program.body.find(
64
+ (node) => node.type === "ImportDeclaration" && node.start !== null && node.start === lastImportIndex
65
+ );
66
+ if (lastImportNode) {
67
+ const index = program.body.indexOf(lastImportNode);
68
+ program.body.splice(index + 1, 0, ...newImports);
69
+ }
70
+ } else {
71
+ ast.program.body.unshift(...newImports);
72
+ }
73
+ const output = (0, import_generator.default)(ast, {
74
+ retainLines: false,
75
+ compact: false
76
+ });
77
+ return output.code;
78
+ }
79
+ function addModuleImports(code, moduleExpressions) {
80
+ const ast = parser.parse(code, {
81
+ sourceType: "module",
82
+ plugins: ["typescript", "decorators-legacy"]
83
+ });
84
+ let modified = false;
85
+ (0, import_traverse.default)(ast, {
86
+ Decorator(path5) {
87
+ if (t.isCallExpression(path5.node.expression) && t.isIdentifier(path5.node.expression.callee) && path5.node.expression.callee.name === "Module") {
88
+ const args = path5.node.expression.arguments;
89
+ if (args.length > 0 && t.isObjectExpression(args[0])) {
90
+ const moduleConfig = args[0];
91
+ const importsProperty = moduleConfig.properties.find(
92
+ (prop) => t.isObjectProperty(prop) && t.isIdentifier(prop.key) && prop.key.name === "imports"
93
+ );
94
+ if (importsProperty && t.isObjectProperty(importsProperty)) {
95
+ if (t.isArrayExpression(importsProperty.value)) {
96
+ for (const expr of moduleExpressions) {
97
+ try {
98
+ const exprAst = parser.parseExpression(expr, {
99
+ plugins: ["typescript"]
100
+ });
101
+ importsProperty.value.elements.push(exprAst);
102
+ modified = true;
103
+ } catch (error) {
104
+ console.error(`Failed to parse expression: ${expr}`, error);
105
+ }
106
+ }
107
+ }
108
+ }
109
+ }
110
+ }
111
+ }
112
+ });
113
+ if (!modified) {
114
+ console.warn("Could not find @Module decorator or imports array");
115
+ return code;
116
+ }
117
+ const output = (0, import_generator.default)(ast, {
118
+ retainLines: false,
119
+ compact: false
120
+ });
121
+ return output.code;
122
+ }
123
+ async function updateAppModuleFile(filePath, imports, moduleExpressions) {
124
+ let code = await import_fs_extra4.default.readFile(filePath, "utf-8");
125
+ if (imports.length > 0) {
126
+ code = addImportToFile(code, imports);
127
+ }
128
+ if (moduleExpressions.length > 0) {
129
+ code = addModuleImports(code, moduleExpressions);
130
+ }
131
+ await import_fs_extra4.default.writeFile(filePath, code, "utf-8");
132
+ }
133
+ var parser, import_traverse, import_generator, t, import_fs_extra4;
134
+ var init_ast_helper = __esm({
135
+ "src/utils/ast-helper.ts"() {
136
+ "use strict";
137
+ parser = __toESM(require("@babel/parser"));
138
+ import_traverse = __toESM(require("@babel/traverse"));
139
+ import_generator = __toESM(require("@babel/generator"));
140
+ t = __toESM(require("@babel/types"));
141
+ import_fs_extra4 = __toESM(require("fs-extra"));
142
+ }
143
+ });
144
+
31
145
  // src/index.ts
32
146
  var index_exports = {};
33
147
  __export(index_exports, {
@@ -40,7 +154,7 @@ var import_commander = require("commander");
40
154
  var import_inquirer = __toESM(require("inquirer"));
41
155
  var import_chalk2 = __toESM(require("chalk"));
42
156
  var import_ora = __toESM(require("ora"));
43
- var import_fs_extra5 = __toESM(require("fs-extra"));
157
+ var import_fs_extra6 = __toESM(require("fs-extra"));
44
158
  var import_path4 = __toESM(require("path"));
45
159
  var import_validate_npm_package_name = __toESM(require("validate-npm-package-name"));
46
160
 
@@ -263,12 +377,12 @@ async function replacePackageNames(directory, config) {
263
377
  }
264
378
  async function findFilesToUpdate(directory) {
265
379
  const files = [];
266
- const traverse = async (dir) => {
380
+ const traverse2 = async (dir) => {
267
381
  const entries = await import_fs_extra2.default.readdir(dir, { withFileTypes: true });
268
382
  for (const entry of entries) {
269
383
  const fullPath = import_path2.default.join(dir, entry.name);
270
384
  if (entry.isDirectory()) {
271
- await traverse(fullPath);
385
+ await traverse2(fullPath);
272
386
  } else if (entry.isFile()) {
273
387
  const ext = import_path2.default.extname(entry.name);
274
388
  const shouldUpdate = [".json", ".ts", ".tsx", ".js", ".jsx", ".md", ".yaml", ".yml", ".env.example", ".tpl"].includes(ext) || entry.name.endsWith(".tpl");
@@ -278,7 +392,7 @@ async function findFilesToUpdate(directory) {
278
392
  }
279
393
  }
280
394
  };
281
- await traverse(directory);
395
+ await traverse2(directory);
282
396
  return files;
283
397
  }
284
398
  async function copyBuiltInTemplates(config) {
@@ -682,17 +796,17 @@ async function initGit(projectName) {
682
796
  }
683
797
 
684
798
  // src/utils/features.ts
685
- var import_fs_extra4 = __toESM(require("fs-extra"));
799
+ var import_fs_extra5 = __toESM(require("fs-extra"));
686
800
  var import_path3 = __toESM(require("path"));
687
801
  async function loadFeaturesConfig() {
688
802
  const configPath = import_path3.default.join(__dirname, "../features.json");
689
- if (!import_fs_extra4.default.existsSync(configPath)) {
803
+ if (!import_fs_extra5.default.existsSync(configPath)) {
690
804
  const devPath = import_path3.default.join(__dirname, "../../features.json");
691
- if (import_fs_extra4.default.existsSync(devPath)) {
692
- return await import_fs_extra4.default.readJSON(devPath);
805
+ if (import_fs_extra5.default.existsSync(devPath)) {
806
+ return await import_fs_extra5.default.readJSON(devPath);
693
807
  }
694
808
  }
695
- return await import_fs_extra4.default.readJSON(configPath);
809
+ return await import_fs_extra5.default.readJSON(configPath);
696
810
  }
697
811
  function getFeatureChoices(config) {
698
812
  return Object.entries(config.features).map(([key, feature]) => ({
@@ -774,8 +888,8 @@ async function generateEnvExample(features, config, targetPath) {
774
888
  }
775
889
  }
776
890
  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"));
891
+ await import_fs_extra5.default.ensureDir(import_path3.default.dirname(envPath));
892
+ await import_fs_extra5.default.writeFile(envPath, content.join("\n"));
779
893
  logger.info("Generated .env.example");
780
894
  }
781
895
  async function copyConfigFiles(features, config, templateDir, targetPath) {
@@ -785,9 +899,9 @@ async function copyConfigFiles(features, config, templateDir, targetPath) {
785
899
  for (const configFile of feature.configFiles) {
786
900
  const sourcePath = import_path3.default.join(templateDir, configFile.template);
787
901
  const destPath = import_path3.default.join(targetPath, configFile.path);
788
- if (await import_fs_extra4.default.pathExists(sourcePath)) {
789
- await import_fs_extra4.default.ensureDir(import_path3.default.dirname(destPath));
790
- await import_fs_extra4.default.copy(sourcePath, destPath);
902
+ if (await import_fs_extra5.default.pathExists(sourcePath)) {
903
+ await import_fs_extra5.default.ensureDir(import_path3.default.dirname(destPath));
904
+ await import_fs_extra5.default.copy(sourcePath, destPath);
791
905
  logger.info(`Copied config: ${configFile.path}`);
792
906
  } else {
793
907
  logger.warn(`Config template not found: ${sourcePath}`);
@@ -802,9 +916,9 @@ async function copyExampleFiles(features, config, templateDir, targetPath) {
802
916
  if (feature && feature.exampleFiles) {
803
917
  const sourcePath = import_path3.default.join(templateDir, feature.exampleFiles.source);
804
918
  const destPath = import_path3.default.join(targetPath, feature.exampleFiles.target);
805
- if (await import_fs_extra4.default.pathExists(sourcePath)) {
806
- await import_fs_extra4.default.ensureDir(import_path3.default.dirname(destPath));
807
- await import_fs_extra4.default.copy(sourcePath, destPath);
919
+ if (await import_fs_extra5.default.pathExists(sourcePath)) {
920
+ await import_fs_extra5.default.ensureDir(import_path3.default.dirname(destPath));
921
+ await import_fs_extra5.default.copy(sourcePath, destPath);
808
922
  logger.info(`Copied examples: ${feature.exampleFiles.target}`);
809
923
  } else {
810
924
  logger.warn(`Example template not found: ${sourcePath}`);
@@ -814,11 +928,11 @@ async function copyExampleFiles(features, config, templateDir, targetPath) {
814
928
  }
815
929
  async function copySkillFiles(features, config, templateDir, targetPath) {
816
930
  const skillsDir = import_path3.default.join(targetPath, ".kiro/skills");
817
- await import_fs_extra4.default.ensureDir(skillsDir);
931
+ await import_fs_extra5.default.ensureDir(skillsDir);
818
932
  const baseSkillSource = import_path3.default.join(templateDir, "skills/base.skill.md");
819
933
  const baseSkillDest = import_path3.default.join(skillsDir, "project-capabilities.md");
820
- if (await import_fs_extra4.default.pathExists(baseSkillSource)) {
821
- await import_fs_extra4.default.copy(baseSkillSource, baseSkillDest);
934
+ if (await import_fs_extra5.default.pathExists(baseSkillSource)) {
935
+ await import_fs_extra5.default.copy(baseSkillSource, baseSkillDest);
822
936
  logger.info("Copied base skill file");
823
937
  } else {
824
938
  logger.warn(`Base skill template not found: ${baseSkillSource}`);
@@ -828,9 +942,9 @@ async function copySkillFiles(features, config, templateDir, targetPath) {
828
942
  if (feature && feature.skillFile) {
829
943
  const sourcePath = import_path3.default.join(templateDir, feature.skillFile.template);
830
944
  const destPath = import_path3.default.join(targetPath, feature.skillFile.target);
831
- if (await import_fs_extra4.default.pathExists(sourcePath)) {
832
- await import_fs_extra4.default.ensureDir(import_path3.default.dirname(destPath));
833
- await import_fs_extra4.default.copy(sourcePath, destPath);
945
+ if (await import_fs_extra5.default.pathExists(sourcePath)) {
946
+ await import_fs_extra5.default.ensureDir(import_path3.default.dirname(destPath));
947
+ await import_fs_extra5.default.copy(sourcePath, destPath);
834
948
  logger.info(`Copied skill: ${feature.skillFile.target}`);
835
949
  } else {
836
950
  logger.warn(`Skill template not found: ${sourcePath}`);
@@ -875,29 +989,39 @@ ${featuresList}
875
989
  - GitHub\uFF1Ahttps://github.com/751848178/svton
876
990
  `;
877
991
  const indexPath = import_path3.default.join(targetPath, ".kiro/skills/project-capabilities.md");
878
- await import_fs_extra4.default.writeFile(indexPath, content);
992
+ await import_fs_extra5.default.writeFile(indexPath, content);
879
993
  logger.info("Generated capabilities index");
880
994
  }
881
995
  async function updatePackageJson(features, config, targetPath) {
882
996
  const packageJsonPath = import_path3.default.join(targetPath, "apps/backend/package.json");
883
- const packageJson = await import_fs_extra4.default.readJSON(packageJsonPath);
997
+ const packageJson = await import_fs_extra5.default.readJSON(packageJsonPath);
884
998
  const dependencies = collectDependencies(features, config);
885
999
  packageJson.dependencies = {
886
1000
  ...packageJson.dependencies,
887
1001
  ...dependencies
888
1002
  };
889
- await import_fs_extra4.default.writeJSON(packageJsonPath, packageJson, { spaces: 2 });
1003
+ await import_fs_extra5.default.writeJSON(packageJsonPath, packageJson, { spaces: 2 });
890
1004
  logger.info("Updated package.json with feature dependencies");
891
1005
  }
892
1006
  function generateModuleImports(features, config) {
893
1007
  const imports = [];
1008
+ const seen = /* @__PURE__ */ new Set();
894
1009
  for (const featureKey of features) {
895
1010
  const feature = config.features[featureKey];
896
1011
  if (feature && feature.moduleImports) {
897
1012
  for (const moduleImport of feature.moduleImports) {
898
- imports.push(`import { ${moduleImport.import} } from '${moduleImport.from}';`);
1013
+ const importKey = `${moduleImport.from}:${moduleImport.import}`;
1014
+ if (!seen.has(importKey)) {
1015
+ imports.push(`import { ${moduleImport.import} } from '${moduleImport.from}';`);
1016
+ seen.add(importKey);
1017
+ }
899
1018
  }
900
1019
  }
1020
+ if (feature && feature.configFiles && feature.configFiles.length > 0) {
1021
+ const configFileName = import_path3.default.basename(feature.configFiles[0].path, ".ts");
1022
+ const configFunctionName = `use${featureKey.charAt(0).toUpperCase() + featureKey.slice(1)}Config`;
1023
+ imports.push(`import { ${configFunctionName} } from './config/${configFileName}';`);
1024
+ }
901
1025
  }
902
1026
  return imports.join("\n");
903
1027
  }
@@ -906,10 +1030,17 @@ function generateModuleRegistrations(features, config) {
906
1030
  for (const featureKey of features) {
907
1031
  const feature = config.features[featureKey];
908
1032
  if (feature && feature.moduleRegistration) {
909
- const { module: moduleName, config: moduleConfig } = feature.moduleRegistration;
910
- registrations.push(` ${moduleName}.${feature.moduleRegistration.type}({
911
- useFactory: (configService: ConfigService) => ${moduleConfig},
1033
+ const { module: moduleName, type: registrationType } = feature.moduleRegistration;
1034
+ let configFunctionName;
1035
+ if (featureKey === "oauth") {
1036
+ configFunctionName = "useOAuthConfig";
1037
+ } else {
1038
+ configFunctionName = `use${featureKey.charAt(0).toUpperCase() + featureKey.slice(1)}Config`;
1039
+ }
1040
+ registrations.push(` ${moduleName}.${registrationType}({
1041
+ imports: [ConfigModule],
912
1042
  inject: [ConfigService],
1043
+ useFactory: (configService: ConfigService) => ${configFunctionName}(configService),
913
1044
  }),`);
914
1045
  }
915
1046
  }
@@ -919,11 +1050,74 @@ async function updateAppModule(features, config, targetPath) {
919
1050
  if (features.length === 0) {
920
1051
  return;
921
1052
  }
1053
+ const appModulePath = import_path3.default.join(targetPath, "apps/backend/src/app.module.ts");
1054
+ if (!await import_fs_extra5.default.pathExists(appModulePath)) {
1055
+ logger.warn("app.module.ts not found, skipping module injection");
1056
+ return;
1057
+ }
1058
+ try {
1059
+ const imports = [];
1060
+ const moduleExpressions = [];
1061
+ const needsConfigService = features.some((key) => {
1062
+ const feature = config.features[key];
1063
+ return feature && feature.moduleRegistration;
1064
+ });
1065
+ if (needsConfigService) {
1066
+ }
1067
+ for (const featureKey of features) {
1068
+ const feature = config.features[featureKey];
1069
+ if (!feature) continue;
1070
+ if (feature.moduleImports) {
1071
+ for (const moduleImport of feature.moduleImports) {
1072
+ imports.push({
1073
+ from: moduleImport.from,
1074
+ imports: [moduleImport.import]
1075
+ });
1076
+ }
1077
+ }
1078
+ if (feature.configFiles && feature.configFiles.length > 0) {
1079
+ const configFileName = import_path3.default.basename(feature.configFiles[0].path, ".ts");
1080
+ let configFunctionName;
1081
+ if (featureKey === "oauth") {
1082
+ configFunctionName = "useOAuthConfig";
1083
+ } else {
1084
+ configFunctionName = `use${featureKey.charAt(0).toUpperCase() + featureKey.slice(1)}Config`;
1085
+ }
1086
+ imports.push({
1087
+ from: `./config/${configFileName}`,
1088
+ imports: [configFunctionName]
1089
+ });
1090
+ }
1091
+ if (feature.moduleRegistration) {
1092
+ const { module: moduleName, type: registrationType } = feature.moduleRegistration;
1093
+ let configFunctionName;
1094
+ if (featureKey === "oauth") {
1095
+ configFunctionName = "useOAuthConfig";
1096
+ } else {
1097
+ configFunctionName = `use${featureKey.charAt(0).toUpperCase() + featureKey.slice(1)}Config`;
1098
+ }
1099
+ const moduleExpression = `${moduleName}.${registrationType}({
1100
+ imports: [ConfigModule],
1101
+ inject: [ConfigService],
1102
+ useFactory: (configService: ConfigService) => ${configFunctionName}(configService),
1103
+ })`;
1104
+ moduleExpressions.push(moduleExpression);
1105
+ }
1106
+ }
1107
+ const { updateAppModuleFile: updateAppModuleFile2 } = await Promise.resolve().then(() => (init_ast_helper(), ast_helper_exports));
1108
+ await updateAppModuleFile2(appModulePath, imports, moduleExpressions);
1109
+ logger.info("Successfully updated app.module.ts with feature modules");
1110
+ } catch (error) {
1111
+ logger.error(`Failed to update app.module.ts: ${error instanceof Error ? error.message : String(error)}`);
1112
+ await generateManualIntegrationGuide(features, config, targetPath);
1113
+ }
1114
+ }
1115
+ async function generateManualIntegrationGuide(features, config, targetPath) {
922
1116
  const imports = generateModuleImports(features, config);
923
1117
  const registrations = generateModuleRegistrations(features, config);
924
1118
  const content = `# \u529F\u80FD\u6A21\u5757\u96C6\u6210\u8BF4\u660E
925
1119
 
926
- \u672C\u6587\u6863\u8BF4\u660E\u5982\u4F55\u5C06\u9009\u4E2D\u7684\u529F\u80FD\u6A21\u5757\u96C6\u6210\u5230 app.module.ts \u4E2D\u3002
1120
+ \u26A0\uFE0F \u81EA\u52A8\u96C6\u6210\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u5B8C\u6210\u4EE5\u4E0B\u6B65\u9AA4\uFF1A
927
1121
 
928
1122
  ## 1. \u6DFB\u52A0\u5BFC\u5165\u8BED\u53E5
929
1123
 
@@ -950,28 +1144,15 @@ export class AppModule {}
950
1144
 
951
1145
  ## 3. \u914D\u7F6E\u6587\u4EF6
952
1146
 
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
1147
+ \u6BCF\u4E2A\u529F\u80FD\u7684\u914D\u7F6E\u6587\u4EF6\u5DF2\u751F\u6210\u5728 \`apps/backend/src/config/\` \u76EE\u5F55\u4E0B\u3002
961
1148
 
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
1149
+ ## 4. \u73AF\u5883\u53D8\u91CF
965
1150
 
966
1151
  \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
1152
  `;
972
1153
  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");
1154
+ await import_fs_extra5.default.writeFile(docPath, content);
1155
+ logger.warn("Generated manual integration guide: apps/backend/FEATURE_INTEGRATION.md");
975
1156
  }
976
1157
 
977
1158
  // src/commands/create.ts
@@ -986,7 +1167,7 @@ async function createProject(projectName, options = {}) {
986
1167
  process.exit(1);
987
1168
  }
988
1169
  const projectPath = import_path4.default.resolve(process.cwd(), projectName);
989
- if (await import_fs_extra5.default.pathExists(projectPath)) {
1170
+ if (await import_fs_extra6.default.pathExists(projectPath)) {
990
1171
  logger.error(`Directory ${projectName} already exists!`);
991
1172
  process.exit(1);
992
1173
  }
@@ -1119,7 +1300,7 @@ async function getTemplateDirectory() {
1119
1300
  const cliPackageRoot = import_path4.default.dirname(__dirname);
1120
1301
  const frameworkRoot = import_path4.default.dirname(import_path4.default.dirname(cliPackageRoot));
1121
1302
  const localTemplateDir = import_path4.default.join(frameworkRoot, "templates");
1122
- if (await import_fs_extra5.default.pathExists(localTemplateDir)) {
1303
+ if (await import_fs_extra6.default.pathExists(localTemplateDir)) {
1123
1304
  logger.debug(`Using local template directory: ${localTemplateDir}`);
1124
1305
  return localTemplateDir;
1125
1306
  }
@@ -1136,7 +1317,7 @@ async function createProjectFromTemplate(config) {
1136
1317
  const spinner = (0, import_ora.default)("Creating project...").start();
1137
1318
  let templateDirToCleanup = null;
1138
1319
  try {
1139
- await import_fs_extra5.default.ensureDir(config.projectPath);
1320
+ await import_fs_extra6.default.ensureDir(config.projectPath);
1140
1321
  process.chdir(config.projectPath);
1141
1322
  spinner.text = "Generating project files...";
1142
1323
  await generateFromTemplate(config);
@@ -1179,7 +1360,7 @@ async function createProjectFromTemplate(config) {
1179
1360
  }
1180
1361
 
1181
1362
  // package.json
1182
- var version = "1.3.0";
1363
+ var version = "1.4.1";
1183
1364
 
1184
1365
  // src/index.ts
1185
1366
  async function cli() {
package/dist/index.mjs CHANGED
@@ -1,10 +1,7 @@
1
1
  #!/usr/bin/env node
2
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
3
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
4
- }) : x)(function(x) {
5
- if (typeof require !== "undefined") return require.apply(this, arguments);
6
- throw Error('Dynamic require of "' + x + '" is not supported');
7
- });
2
+ import {
3
+ __require
4
+ } from "./chunk-Y6FXYEAI.mjs";
8
5
 
9
6
  // src/index.ts
10
7
  import { Command } from "commander";
@@ -864,13 +861,23 @@ async function updatePackageJson(features, config, targetPath) {
864
861
  }
865
862
  function generateModuleImports(features, config) {
866
863
  const imports = [];
864
+ const seen = /* @__PURE__ */ new Set();
867
865
  for (const featureKey of features) {
868
866
  const feature = config.features[featureKey];
869
867
  if (feature && feature.moduleImports) {
870
868
  for (const moduleImport of feature.moduleImports) {
871
- imports.push(`import { ${moduleImport.import} } from '${moduleImport.from}';`);
869
+ const importKey = `${moduleImport.from}:${moduleImport.import}`;
870
+ if (!seen.has(importKey)) {
871
+ imports.push(`import { ${moduleImport.import} } from '${moduleImport.from}';`);
872
+ seen.add(importKey);
873
+ }
872
874
  }
873
875
  }
876
+ if (feature && feature.configFiles && feature.configFiles.length > 0) {
877
+ const configFileName = path3.basename(feature.configFiles[0].path, ".ts");
878
+ const configFunctionName = `use${featureKey.charAt(0).toUpperCase() + featureKey.slice(1)}Config`;
879
+ imports.push(`import { ${configFunctionName} } from './config/${configFileName}';`);
880
+ }
874
881
  }
875
882
  return imports.join("\n");
876
883
  }
@@ -879,10 +886,17 @@ function generateModuleRegistrations(features, config) {
879
886
  for (const featureKey of features) {
880
887
  const feature = config.features[featureKey];
881
888
  if (feature && feature.moduleRegistration) {
882
- const { module: moduleName, config: moduleConfig } = feature.moduleRegistration;
883
- registrations.push(` ${moduleName}.${feature.moduleRegistration.type}({
884
- useFactory: (configService: ConfigService) => ${moduleConfig},
889
+ const { module: moduleName, type: registrationType } = feature.moduleRegistration;
890
+ let configFunctionName;
891
+ if (featureKey === "oauth") {
892
+ configFunctionName = "useOAuthConfig";
893
+ } else {
894
+ configFunctionName = `use${featureKey.charAt(0).toUpperCase() + featureKey.slice(1)}Config`;
895
+ }
896
+ registrations.push(` ${moduleName}.${registrationType}({
897
+ imports: [ConfigModule],
885
898
  inject: [ConfigService],
899
+ useFactory: (configService: ConfigService) => ${configFunctionName}(configService),
886
900
  }),`);
887
901
  }
888
902
  }
@@ -892,11 +906,74 @@ async function updateAppModule(features, config, targetPath) {
892
906
  if (features.length === 0) {
893
907
  return;
894
908
  }
909
+ const appModulePath = path3.join(targetPath, "apps/backend/src/app.module.ts");
910
+ if (!await fs4.pathExists(appModulePath)) {
911
+ logger.warn("app.module.ts not found, skipping module injection");
912
+ return;
913
+ }
914
+ try {
915
+ const imports = [];
916
+ const moduleExpressions = [];
917
+ const needsConfigService = features.some((key) => {
918
+ const feature = config.features[key];
919
+ return feature && feature.moduleRegistration;
920
+ });
921
+ if (needsConfigService) {
922
+ }
923
+ for (const featureKey of features) {
924
+ const feature = config.features[featureKey];
925
+ if (!feature) continue;
926
+ if (feature.moduleImports) {
927
+ for (const moduleImport of feature.moduleImports) {
928
+ imports.push({
929
+ from: moduleImport.from,
930
+ imports: [moduleImport.import]
931
+ });
932
+ }
933
+ }
934
+ if (feature.configFiles && feature.configFiles.length > 0) {
935
+ const configFileName = path3.basename(feature.configFiles[0].path, ".ts");
936
+ let configFunctionName;
937
+ if (featureKey === "oauth") {
938
+ configFunctionName = "useOAuthConfig";
939
+ } else {
940
+ configFunctionName = `use${featureKey.charAt(0).toUpperCase() + featureKey.slice(1)}Config`;
941
+ }
942
+ imports.push({
943
+ from: `./config/${configFileName}`,
944
+ imports: [configFunctionName]
945
+ });
946
+ }
947
+ if (feature.moduleRegistration) {
948
+ const { module: moduleName, type: registrationType } = feature.moduleRegistration;
949
+ let configFunctionName;
950
+ if (featureKey === "oauth") {
951
+ configFunctionName = "useOAuthConfig";
952
+ } else {
953
+ configFunctionName = `use${featureKey.charAt(0).toUpperCase() + featureKey.slice(1)}Config`;
954
+ }
955
+ const moduleExpression = `${moduleName}.${registrationType}({
956
+ imports: [ConfigModule],
957
+ inject: [ConfigService],
958
+ useFactory: (configService: ConfigService) => ${configFunctionName}(configService),
959
+ })`;
960
+ moduleExpressions.push(moduleExpression);
961
+ }
962
+ }
963
+ const { updateAppModuleFile } = await import("./ast-helper-5I5LPFKU.mjs");
964
+ await updateAppModuleFile(appModulePath, imports, moduleExpressions);
965
+ logger.info("Successfully updated app.module.ts with feature modules");
966
+ } catch (error) {
967
+ logger.error(`Failed to update app.module.ts: ${error instanceof Error ? error.message : String(error)}`);
968
+ await generateManualIntegrationGuide(features, config, targetPath);
969
+ }
970
+ }
971
+ async function generateManualIntegrationGuide(features, config, targetPath) {
895
972
  const imports = generateModuleImports(features, config);
896
973
  const registrations = generateModuleRegistrations(features, config);
897
974
  const content = `# \u529F\u80FD\u6A21\u5757\u96C6\u6210\u8BF4\u660E
898
975
 
899
- \u672C\u6587\u6863\u8BF4\u660E\u5982\u4F55\u5C06\u9009\u4E2D\u7684\u529F\u80FD\u6A21\u5757\u96C6\u6210\u5230 app.module.ts \u4E2D\u3002
976
+ \u26A0\uFE0F \u81EA\u52A8\u96C6\u6210\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u5B8C\u6210\u4EE5\u4E0B\u6B65\u9AA4\uFF1A
900
977
 
901
978
  ## 1. \u6DFB\u52A0\u5BFC\u5165\u8BED\u53E5
902
979
 
@@ -923,28 +1000,15 @@ export class AppModule {}
923
1000
 
924
1001
  ## 3. \u914D\u7F6E\u6587\u4EF6
925
1002
 
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
1003
+ \u6BCF\u4E2A\u529F\u80FD\u7684\u914D\u7F6E\u6587\u4EF6\u5DF2\u751F\u6210\u5728 \`apps/backend/src/config/\` \u76EE\u5F55\u4E0B\u3002
934
1004
 
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
1005
+ ## 4. \u73AF\u5883\u53D8\u91CF
938
1006
 
939
1007
  \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
1008
  `;
945
1009
  const docPath = path3.join(targetPath, "apps/backend/FEATURE_INTEGRATION.md");
946
1010
  await fs4.writeFile(docPath, content);
947
- logger.info("Generated feature integration guide: apps/backend/FEATURE_INTEGRATION.md");
1011
+ logger.warn("Generated manual integration guide: apps/backend/FEATURE_INTEGRATION.md");
948
1012
  }
949
1013
 
950
1014
  // src/commands/create.ts
@@ -1152,7 +1216,7 @@ async function createProjectFromTemplate(config) {
1152
1216
  }
1153
1217
 
1154
1218
  // package.json
1155
- var version = "1.3.0";
1219
+ var version = "1.4.1";
1156
1220
 
1157
1221
  // src/index.ts
1158
1222
  async function cli() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@svton/cli",
3
- "version": "1.3.0",
3
+ "version": "1.4.1",
4
4
  "description": "Svton CLI - Create full-stack applications with NestJS, Next.js, and Taro",
5
5
  "keywords": [
6
6
  "cli",
@@ -47,16 +47,22 @@
47
47
  "node": ">=18.0.0"
48
48
  },
49
49
  "dependencies": {
50
- "commander": "^11.1.0",
51
- "inquirer": "^9.2.12",
50
+ "@babel/generator": "^7.29.0",
51
+ "@babel/parser": "^7.29.0",
52
+ "@babel/traverse": "^7.29.0",
53
+ "@babel/types": "^7.29.0",
52
54
  "chalk": "^5.3.0",
53
- "ora": "^8.0.1",
55
+ "commander": "^11.1.0",
54
56
  "fs-extra": "^11.2.0",
57
+ "inquirer": "^9.2.12",
55
58
  "mustache": "^4.2.0",
59
+ "ora": "^8.0.1",
56
60
  "validate-npm-package-name": "^5.0.0"
57
61
  },
58
62
  "devDependencies": {
59
63
  "@changesets/cli": "^2.29.8",
64
+ "@types/babel__generator": "^7.27.0",
65
+ "@types/babel__traverse": "^7.28.0",
60
66
  "@types/fs-extra": "^11.0.4",
61
67
  "@types/inquirer": "^9.0.7",
62
68
  "@types/mustache": "^4.2.5",