@svton/cli 1.2.2 → 1.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/dist/index.js +58 -27
  2. package/dist/index.mjs +58 -27
  3. package/package.json +1 -3
  4. package/templates/apps/admin/next-env.d.ts +0 -2
  5. package/templates/apps/admin/next.config.js +0 -15
  6. package/templates/apps/admin/package.json.tpl +0 -54
  7. package/templates/apps/admin/postcss.config.js +0 -6
  8. package/templates/apps/admin/src/app/globals.css +0 -37
  9. package/templates/apps/admin/src/app/layout.tsx +0 -19
  10. package/templates/apps/admin/src/app/login/page.tsx +0 -96
  11. package/templates/apps/admin/src/app/page.tsx +0 -8
  12. package/templates/apps/admin/src/app/users/page.tsx +0 -165
  13. package/templates/apps/admin/src/components/ui/switch.tsx +0 -29
  14. package/templates/apps/admin/src/hooks/useAPI.ts +0 -130
  15. package/templates/apps/admin/src/lib/api-client.ts +0 -112
  16. package/templates/apps/admin/src/lib/api-server.ts +0 -95
  17. package/templates/apps/admin/tailwind.config.js +0 -54
  18. package/templates/apps/admin/tsconfig.json +0 -22
  19. package/templates/apps/backend/.env.example +0 -29
  20. package/templates/apps/backend/nest-cli.json +0 -8
  21. package/templates/apps/backend/package.json.tpl +0 -57
  22. package/templates/apps/backend/prisma/schema.prisma +0 -72
  23. package/templates/apps/backend/prisma/seed.ts +0 -32
  24. package/templates/apps/backend/src/app.controller.ts +0 -15
  25. package/templates/apps/backend/src/app.module.ts +0 -85
  26. package/templates/apps/backend/src/app.service.ts +0 -12
  27. package/templates/apps/backend/src/auth/auth.controller.ts +0 -31
  28. package/templates/apps/backend/src/auth/auth.module.ts +0 -27
  29. package/templates/apps/backend/src/auth/auth.service.ts +0 -89
  30. package/templates/apps/backend/src/auth/jwt-auth.guard.ts +0 -5
  31. package/templates/apps/backend/src/auth/jwt.strategy.ts +0 -27
  32. package/templates/apps/backend/src/config/env.schema.ts +0 -35
  33. package/templates/apps/backend/src/main.ts +0 -51
  34. package/templates/apps/backend/src/object-storage/object-storage.controller.ts +0 -114
  35. package/templates/apps/backend/src/object-storage/object-storage.module.ts +0 -7
  36. package/templates/apps/backend/src/prisma/prisma.module.ts +0 -9
  37. package/templates/apps/backend/src/prisma/prisma.service.ts +0 -13
  38. package/templates/apps/backend/src/user/user.controller.ts +0 -50
  39. package/templates/apps/backend/src/user/user.module.ts +0 -12
  40. package/templates/apps/backend/src/user/user.service.ts +0 -117
  41. package/templates/apps/backend/tsconfig.json +0 -23
  42. package/templates/apps/mobile/babel.config.js +0 -8
  43. package/templates/apps/mobile/config/index.ts +0 -65
  44. package/templates/apps/mobile/package.json.tpl +0 -48
  45. package/templates/apps/mobile/project.config.json.tpl +0 -17
  46. package/templates/apps/mobile/src/app.config.ts +0 -9
  47. package/templates/apps/mobile/src/app.scss +0 -4
  48. package/templates/apps/mobile/src/app.ts +0 -8
  49. package/templates/apps/mobile/src/hooks/useAPI.ts +0 -285
  50. package/templates/apps/mobile/src/pages/index/index.scss +0 -7
  51. package/templates/apps/mobile/src/pages/index/index.tsx +0 -49
  52. package/templates/apps/mobile/src/services/api.ts +0 -155
  53. package/templates/apps/mobile/src/services/upload.service.ts +0 -41
  54. package/templates/apps/mobile/tsconfig.json +0 -21
  55. package/templates/configs/authz.config.ts +0 -10
  56. package/templates/configs/cache.config.ts +0 -14
  57. package/templates/configs/oauth.config.ts +0 -20
  58. package/templates/configs/payment.config.ts +0 -44
  59. package/templates/configs/queue.config.ts +0 -21
  60. package/templates/configs/rate-limit.config.ts +0 -16
  61. package/templates/configs/sms.config.ts +0 -11
  62. package/templates/configs/storage.config.ts +0 -14
  63. package/templates/examples/README.md +0 -258
  64. package/templates/examples/authz/README.md +0 -273
  65. package/templates/examples/authz/roles.guard.ts +0 -37
  66. package/templates/examples/authz/user.controller.ts +0 -116
  67. package/templates/examples/cache/README.md +0 -82
  68. package/templates/examples/cache/user.controller.ts +0 -42
  69. package/templates/examples/cache/user.service.ts +0 -78
  70. package/templates/examples/oauth/README.md +0 -192
  71. package/templates/examples/oauth/auth.controller.ts +0 -99
  72. package/templates/examples/oauth/auth.service.ts +0 -97
  73. package/templates/examples/payment/README.md +0 -151
  74. package/templates/examples/payment/order.controller.ts +0 -56
  75. package/templates/examples/payment/order.service.ts +0 -132
  76. package/templates/examples/payment/webhook.controller.ts +0 -73
  77. package/templates/examples/queue/README.md +0 -134
  78. package/templates/examples/queue/email.controller.ts +0 -34
  79. package/templates/examples/queue/email.processor.ts +0 -68
  80. package/templates/examples/queue/email.service.ts +0 -64
  81. package/templates/examples/rate-limit/README.md +0 -249
  82. package/templates/examples/rate-limit/api.controller.ts +0 -113
  83. package/templates/examples/sms/README.md +0 -121
  84. package/templates/examples/sms/sms.service.ts +0 -69
  85. package/templates/examples/sms/verification.controller.ts +0 -100
  86. package/templates/examples/storage/README.md +0 -224
  87. package/templates/examples/storage/upload.controller.ts +0 -117
  88. package/templates/examples/storage/upload.service.ts +0 -123
  89. package/templates/packages/types/package.json.tpl +0 -16
  90. package/templates/packages/types/src/api.ts +0 -88
  91. package/templates/packages/types/src/common.ts +0 -89
  92. package/templates/packages/types/src/index.ts +0 -3
  93. package/templates/packages/types/tsconfig.json +0 -16
  94. package/templates/skills/authz.skill.md +0 -42
  95. package/templates/skills/base.skill.md +0 -57
  96. package/templates/skills/cache.skill.md +0 -88
  97. package/templates/skills/oauth.skill.md +0 -41
  98. package/templates/skills/payment.skill.md +0 -129
  99. package/templates/skills/queue.skill.md +0 -140
  100. package/templates/skills/rate-limit.skill.md +0 -38
  101. package/templates/skills/sms.skill.md +0 -39
  102. package/templates/skills/storage.skill.md +0 -42
package/dist/index.js CHANGED
@@ -132,18 +132,11 @@ async function copyTemplateFiles(config) {
132
132
  let templateDir = null;
133
133
  let needCleanup = false;
134
134
  const cliPackageRoot = import_path2.default.dirname(__dirname);
135
- const packagedTemplateDir = import_path2.default.join(cliPackageRoot, "../templates");
136
- if (await import_fs_extra2.default.pathExists(packagedTemplateDir)) {
137
- templateDir = packagedTemplateDir;
138
- logger.debug(`Using packaged template directory: ${templateDir}`);
139
- }
140
- if (!templateDir) {
141
- const frameworkRoot = import_path2.default.dirname(import_path2.default.dirname(cliPackageRoot));
142
- const localTemplateDir = import_path2.default.join(frameworkRoot, "templates");
143
- if (await import_fs_extra2.default.pathExists(localTemplateDir)) {
144
- templateDir = localTemplateDir;
145
- logger.debug(`Using local template directory: ${templateDir}`);
146
- }
135
+ const frameworkRoot = import_path2.default.dirname(import_path2.default.dirname(cliPackageRoot));
136
+ const localTemplateDir = import_path2.default.join(frameworkRoot, "templates");
137
+ if (await import_fs_extra2.default.pathExists(localTemplateDir)) {
138
+ templateDir = localTemplateDir;
139
+ logger.debug(`Using local template directory: ${templateDir}`);
147
140
  }
148
141
  if (!templateDir) {
149
142
  logger.info("Downloading templates from GitHub...");
@@ -753,52 +746,62 @@ async function generateEnvExample(features, config, targetPath) {
753
746
  await import_fs_extra4.default.writeFile(import_path3.default.join(targetPath, ".env.example"), content);
754
747
  logger.info("Generated .env.example");
755
748
  }
756
- async function copyConfigFiles(features, config, templatePath, targetPath) {
749
+ async function copyConfigFiles(features, config, templateDir, targetPath) {
757
750
  for (const featureKey of features) {
758
751
  const feature = config.features[featureKey];
759
752
  if (feature && feature.configFiles) {
760
753
  for (const configFile of feature.configFiles) {
761
- const sourcePath = import_path3.default.join(templatePath, configFile.template);
754
+ const sourcePath = import_path3.default.join(templateDir, configFile.template);
762
755
  const destPath = import_path3.default.join(targetPath, configFile.path);
763
- await import_fs_extra4.default.ensureDir(import_path3.default.dirname(destPath));
764
- await import_fs_extra4.default.copy(sourcePath, destPath);
765
- logger.info(`Copied config: ${configFile.path}`);
756
+ if (await import_fs_extra4.default.pathExists(sourcePath)) {
757
+ await import_fs_extra4.default.ensureDir(import_path3.default.dirname(destPath));
758
+ await import_fs_extra4.default.copy(sourcePath, destPath);
759
+ logger.info(`Copied config: ${configFile.path}`);
760
+ } else {
761
+ logger.warn(`Config template not found: ${sourcePath}`);
762
+ }
766
763
  }
767
764
  }
768
765
  }
769
766
  }
770
- async function copyExampleFiles(features, config, templatePath, targetPath) {
767
+ async function copyExampleFiles(features, config, templateDir, targetPath) {
771
768
  for (const featureKey of features) {
772
769
  const feature = config.features[featureKey];
773
770
  if (feature && feature.exampleFiles) {
774
- const sourcePath = import_path3.default.join(templatePath, feature.exampleFiles.source);
771
+ const sourcePath = import_path3.default.join(templateDir, feature.exampleFiles.source);
775
772
  const destPath = import_path3.default.join(targetPath, feature.exampleFiles.target);
776
773
  if (await import_fs_extra4.default.pathExists(sourcePath)) {
777
774
  await import_fs_extra4.default.ensureDir(import_path3.default.dirname(destPath));
778
775
  await import_fs_extra4.default.copy(sourcePath, destPath);
779
776
  logger.info(`Copied examples: ${feature.exampleFiles.target}`);
777
+ } else {
778
+ logger.warn(`Example template not found: ${sourcePath}`);
780
779
  }
781
780
  }
782
781
  }
783
782
  }
784
- async function copySkillFiles(features, config, templatePath, targetPath) {
783
+ async function copySkillFiles(features, config, templateDir, targetPath) {
785
784
  const skillsDir = import_path3.default.join(targetPath, ".kiro/skills");
786
785
  await import_fs_extra4.default.ensureDir(skillsDir);
787
- const baseSkillSource = import_path3.default.join(templatePath, "skills/base.skill.md");
786
+ const baseSkillSource = import_path3.default.join(templateDir, "skills/base.skill.md");
788
787
  const baseSkillDest = import_path3.default.join(skillsDir, "project-capabilities.md");
789
788
  if (await import_fs_extra4.default.pathExists(baseSkillSource)) {
790
789
  await import_fs_extra4.default.copy(baseSkillSource, baseSkillDest);
791
790
  logger.info("Copied base skill file");
791
+ } else {
792
+ logger.warn(`Base skill template not found: ${baseSkillSource}`);
792
793
  }
793
794
  for (const featureKey of features) {
794
795
  const feature = config.features[featureKey];
795
796
  if (feature && feature.skillFile) {
796
- const sourcePath = import_path3.default.join(templatePath, feature.skillFile.template);
797
+ const sourcePath = import_path3.default.join(templateDir, feature.skillFile.template);
797
798
  const destPath = import_path3.default.join(targetPath, feature.skillFile.target);
798
799
  if (await import_fs_extra4.default.pathExists(sourcePath)) {
799
800
  await import_fs_extra4.default.ensureDir(import_path3.default.dirname(destPath));
800
801
  await import_fs_extra4.default.copy(sourcePath, destPath);
801
802
  logger.info(`Copied skill: ${feature.skillFile.target}`);
803
+ } else {
804
+ logger.warn(`Skill template not found: ${sourcePath}`);
802
805
  }
803
806
  }
804
807
  }
@@ -1048,8 +1051,26 @@ async function createProject(projectName, options = {}) {
1048
1051
  process.exit(1);
1049
1052
  }
1050
1053
  }
1054
+ async function getTemplateDirectory() {
1055
+ const cliPackageRoot = import_path4.default.dirname(__dirname);
1056
+ const frameworkRoot = import_path4.default.dirname(import_path4.default.dirname(cliPackageRoot));
1057
+ const localTemplateDir = import_path4.default.join(frameworkRoot, "templates");
1058
+ if (await import_fs_extra5.default.pathExists(localTemplateDir)) {
1059
+ logger.debug(`Using local template directory: ${localTemplateDir}`);
1060
+ return localTemplateDir;
1061
+ }
1062
+ logger.debug("Downloading templates from GitHub for feature integration...");
1063
+ try {
1064
+ const templateDir = await downloadTemplateFromGitHub();
1065
+ logger.debug("Templates downloaded successfully");
1066
+ return templateDir;
1067
+ } catch (error) {
1068
+ throw new Error(`Failed to download templates from GitHub: ${error}`);
1069
+ }
1070
+ }
1051
1071
  async function createProjectFromTemplate(config) {
1052
1072
  const spinner = (0, import_ora.default)("Creating project...").start();
1073
+ let templateDirToCleanup = null;
1053
1074
  try {
1054
1075
  await import_fs_extra5.default.ensureDir(config.projectPath);
1055
1076
  process.chdir(config.projectPath);
@@ -1058,11 +1079,17 @@ async function createProjectFromTemplate(config) {
1058
1079
  if (config.features.length > 0) {
1059
1080
  spinner.text = "Integrating selected features...";
1060
1081
  const featuresConfig = await loadFeaturesConfig();
1061
- const templatePath = import_path4.default.join(__dirname, "../../../templates");
1082
+ const templateDir = await getTemplateDirectory();
1083
+ const cliPackageRoot = import_path4.default.dirname(__dirname);
1084
+ const frameworkRoot = import_path4.default.dirname(import_path4.default.dirname(cliPackageRoot));
1085
+ const localTemplateDir = import_path4.default.join(frameworkRoot, "templates");
1086
+ if (templateDir !== localTemplateDir) {
1087
+ templateDirToCleanup = templateDir;
1088
+ }
1062
1089
  await updatePackageJson(config.features, featuresConfig, config.projectPath);
1063
- await copyConfigFiles(config.features, featuresConfig, templatePath, config.projectPath);
1064
- await copyExampleFiles(config.features, featuresConfig, templatePath, config.projectPath);
1065
- await copySkillFiles(config.features, featuresConfig, templatePath, config.projectPath);
1090
+ await copyConfigFiles(config.features, featuresConfig, templateDir, config.projectPath);
1091
+ await copyExampleFiles(config.features, featuresConfig, templateDir, config.projectPath);
1092
+ await copySkillFiles(config.features, featuresConfig, templateDir, config.projectPath);
1066
1093
  await generateEnvExample(config.features, featuresConfig, config.projectPath);
1067
1094
  if (config.template === "backend-only" || config.template === "full-stack") {
1068
1095
  await updateAppModule(config.features, featuresConfig, config.projectPath);
@@ -1080,11 +1107,15 @@ async function createProjectFromTemplate(config) {
1080
1107
  } catch (error) {
1081
1108
  spinner.fail("Failed to create project");
1082
1109
  throw error;
1110
+ } finally {
1111
+ if (templateDirToCleanup) {
1112
+ await cleanupTemplateDir(templateDirToCleanup);
1113
+ }
1083
1114
  }
1084
1115
  }
1085
1116
 
1086
1117
  // package.json
1087
- var version = "1.2.2";
1118
+ var version = "1.2.4";
1088
1119
 
1089
1120
  // src/index.ts
1090
1121
  async function cli() {
package/dist/index.mjs CHANGED
@@ -105,18 +105,11 @@ async function copyTemplateFiles(config) {
105
105
  let templateDir = null;
106
106
  let needCleanup = false;
107
107
  const cliPackageRoot = path2.dirname(__dirname);
108
- const packagedTemplateDir = path2.join(cliPackageRoot, "../templates");
109
- if (await fs2.pathExists(packagedTemplateDir)) {
110
- templateDir = packagedTemplateDir;
111
- logger.debug(`Using packaged template directory: ${templateDir}`);
112
- }
113
- if (!templateDir) {
114
- const frameworkRoot = path2.dirname(path2.dirname(cliPackageRoot));
115
- const localTemplateDir = path2.join(frameworkRoot, "templates");
116
- if (await fs2.pathExists(localTemplateDir)) {
117
- templateDir = localTemplateDir;
118
- logger.debug(`Using local template directory: ${templateDir}`);
119
- }
108
+ const frameworkRoot = path2.dirname(path2.dirname(cliPackageRoot));
109
+ const localTemplateDir = path2.join(frameworkRoot, "templates");
110
+ if (await fs2.pathExists(localTemplateDir)) {
111
+ templateDir = localTemplateDir;
112
+ logger.debug(`Using local template directory: ${templateDir}`);
120
113
  }
121
114
  if (!templateDir) {
122
115
  logger.info("Downloading templates from GitHub...");
@@ -726,52 +719,62 @@ async function generateEnvExample(features, config, targetPath) {
726
719
  await fs4.writeFile(path3.join(targetPath, ".env.example"), content);
727
720
  logger.info("Generated .env.example");
728
721
  }
729
- async function copyConfigFiles(features, config, templatePath, targetPath) {
722
+ async function copyConfigFiles(features, config, templateDir, targetPath) {
730
723
  for (const featureKey of features) {
731
724
  const feature = config.features[featureKey];
732
725
  if (feature && feature.configFiles) {
733
726
  for (const configFile of feature.configFiles) {
734
- const sourcePath = path3.join(templatePath, configFile.template);
727
+ const sourcePath = path3.join(templateDir, configFile.template);
735
728
  const destPath = path3.join(targetPath, configFile.path);
736
- await fs4.ensureDir(path3.dirname(destPath));
737
- await fs4.copy(sourcePath, destPath);
738
- logger.info(`Copied config: ${configFile.path}`);
729
+ if (await fs4.pathExists(sourcePath)) {
730
+ await fs4.ensureDir(path3.dirname(destPath));
731
+ await fs4.copy(sourcePath, destPath);
732
+ logger.info(`Copied config: ${configFile.path}`);
733
+ } else {
734
+ logger.warn(`Config template not found: ${sourcePath}`);
735
+ }
739
736
  }
740
737
  }
741
738
  }
742
739
  }
743
- async function copyExampleFiles(features, config, templatePath, targetPath) {
740
+ async function copyExampleFiles(features, config, templateDir, targetPath) {
744
741
  for (const featureKey of features) {
745
742
  const feature = config.features[featureKey];
746
743
  if (feature && feature.exampleFiles) {
747
- const sourcePath = path3.join(templatePath, feature.exampleFiles.source);
744
+ const sourcePath = path3.join(templateDir, feature.exampleFiles.source);
748
745
  const destPath = path3.join(targetPath, feature.exampleFiles.target);
749
746
  if (await fs4.pathExists(sourcePath)) {
750
747
  await fs4.ensureDir(path3.dirname(destPath));
751
748
  await fs4.copy(sourcePath, destPath);
752
749
  logger.info(`Copied examples: ${feature.exampleFiles.target}`);
750
+ } else {
751
+ logger.warn(`Example template not found: ${sourcePath}`);
753
752
  }
754
753
  }
755
754
  }
756
755
  }
757
- async function copySkillFiles(features, config, templatePath, targetPath) {
756
+ async function copySkillFiles(features, config, templateDir, targetPath) {
758
757
  const skillsDir = path3.join(targetPath, ".kiro/skills");
759
758
  await fs4.ensureDir(skillsDir);
760
- const baseSkillSource = path3.join(templatePath, "skills/base.skill.md");
759
+ const baseSkillSource = path3.join(templateDir, "skills/base.skill.md");
761
760
  const baseSkillDest = path3.join(skillsDir, "project-capabilities.md");
762
761
  if (await fs4.pathExists(baseSkillSource)) {
763
762
  await fs4.copy(baseSkillSource, baseSkillDest);
764
763
  logger.info("Copied base skill file");
764
+ } else {
765
+ logger.warn(`Base skill template not found: ${baseSkillSource}`);
765
766
  }
766
767
  for (const featureKey of features) {
767
768
  const feature = config.features[featureKey];
768
769
  if (feature && feature.skillFile) {
769
- const sourcePath = path3.join(templatePath, feature.skillFile.template);
770
+ const sourcePath = path3.join(templateDir, feature.skillFile.template);
770
771
  const destPath = path3.join(targetPath, feature.skillFile.target);
771
772
  if (await fs4.pathExists(sourcePath)) {
772
773
  await fs4.ensureDir(path3.dirname(destPath));
773
774
  await fs4.copy(sourcePath, destPath);
774
775
  logger.info(`Copied skill: ${feature.skillFile.target}`);
776
+ } else {
777
+ logger.warn(`Skill template not found: ${sourcePath}`);
775
778
  }
776
779
  }
777
780
  }
@@ -1021,8 +1024,26 @@ async function createProject(projectName, options = {}) {
1021
1024
  process.exit(1);
1022
1025
  }
1023
1026
  }
1027
+ async function getTemplateDirectory() {
1028
+ const cliPackageRoot = path4.dirname(__dirname);
1029
+ const frameworkRoot = path4.dirname(path4.dirname(cliPackageRoot));
1030
+ const localTemplateDir = path4.join(frameworkRoot, "templates");
1031
+ if (await fs5.pathExists(localTemplateDir)) {
1032
+ logger.debug(`Using local template directory: ${localTemplateDir}`);
1033
+ return localTemplateDir;
1034
+ }
1035
+ logger.debug("Downloading templates from GitHub for feature integration...");
1036
+ try {
1037
+ const templateDir = await downloadTemplateFromGitHub();
1038
+ logger.debug("Templates downloaded successfully");
1039
+ return templateDir;
1040
+ } catch (error) {
1041
+ throw new Error(`Failed to download templates from GitHub: ${error}`);
1042
+ }
1043
+ }
1024
1044
  async function createProjectFromTemplate(config) {
1025
1045
  const spinner = ora("Creating project...").start();
1046
+ let templateDirToCleanup = null;
1026
1047
  try {
1027
1048
  await fs5.ensureDir(config.projectPath);
1028
1049
  process.chdir(config.projectPath);
@@ -1031,11 +1052,17 @@ async function createProjectFromTemplate(config) {
1031
1052
  if (config.features.length > 0) {
1032
1053
  spinner.text = "Integrating selected features...";
1033
1054
  const featuresConfig = await loadFeaturesConfig();
1034
- const templatePath = path4.join(__dirname, "../../../templates");
1055
+ const templateDir = await getTemplateDirectory();
1056
+ const cliPackageRoot = path4.dirname(__dirname);
1057
+ const frameworkRoot = path4.dirname(path4.dirname(cliPackageRoot));
1058
+ const localTemplateDir = path4.join(frameworkRoot, "templates");
1059
+ if (templateDir !== localTemplateDir) {
1060
+ templateDirToCleanup = templateDir;
1061
+ }
1035
1062
  await updatePackageJson(config.features, featuresConfig, config.projectPath);
1036
- await copyConfigFiles(config.features, featuresConfig, templatePath, config.projectPath);
1037
- await copyExampleFiles(config.features, featuresConfig, templatePath, config.projectPath);
1038
- await copySkillFiles(config.features, featuresConfig, templatePath, config.projectPath);
1063
+ await copyConfigFiles(config.features, featuresConfig, templateDir, config.projectPath);
1064
+ await copyExampleFiles(config.features, featuresConfig, templateDir, config.projectPath);
1065
+ await copySkillFiles(config.features, featuresConfig, templateDir, config.projectPath);
1039
1066
  await generateEnvExample(config.features, featuresConfig, config.projectPath);
1040
1067
  if (config.template === "backend-only" || config.template === "full-stack") {
1041
1068
  await updateAppModule(config.features, featuresConfig, config.projectPath);
@@ -1053,11 +1080,15 @@ async function createProjectFromTemplate(config) {
1053
1080
  } catch (error) {
1054
1081
  spinner.fail("Failed to create project");
1055
1082
  throw error;
1083
+ } finally {
1084
+ if (templateDirToCleanup) {
1085
+ await cleanupTemplateDir(templateDirToCleanup);
1086
+ }
1056
1087
  }
1057
1088
  }
1058
1089
 
1059
1090
  // package.json
1060
- var version = "1.2.2";
1091
+ var version = "1.2.4";
1061
1092
 
1062
1093
  // src/index.ts
1063
1094
  async function cli() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@svton/cli",
3
- "version": "1.2.2",
3
+ "version": "1.2.4",
4
4
  "description": "Svton CLI - Create full-stack applications with NestJS, Next.js, and Taro",
5
5
  "keywords": [
6
6
  "cli",
@@ -31,12 +31,10 @@
31
31
  "dist",
32
32
  "bin",
33
33
  "features.json",
34
- "templates",
35
34
  "README.md",
36
35
  "LICENSE"
37
36
  ],
38
37
  "scripts": {
39
- "prebuild": "node scripts/copy-templates.js",
40
38
  "build": "tsup src/index.ts --format cjs,esm --dts",
41
39
  "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
42
40
  "type-check": "tsc --noEmit",
@@ -1,2 +0,0 @@
1
- /// <reference types="next" />
2
- /// <reference types="next/image-types/global" />
@@ -1,15 +0,0 @@
1
- /** @type {import('next').NextConfig} */
2
- const nextConfig = {
3
- reactStrictMode: true,
4
- transpilePackages: ['@svton/hooks'],
5
- images: {
6
- remotePatterns: [
7
- {
8
- protocol: 'https',
9
- hostname: '**',
10
- },
11
- ],
12
- },
13
- };
14
-
15
- module.exports = nextConfig;
@@ -1,54 +0,0 @@
1
- {
2
- "name": "{{ORG_NAME}}/admin",
3
- "version": "1.0.0",
4
- "description": "{{PROJECT_NAME}} 管理后台",
5
- "scripts": {
6
- "dev": "next dev -p 3001",
7
- "build": "next build",
8
- "start": "next start -p 3001",
9
- "lint": "next lint",
10
- "type-check": "tsc --noEmit",
11
- "clean": "rm -rf .next"
12
- },
13
- "dependencies": {
14
- "@hookform/resolvers": "^3.3.3",
15
- "@radix-ui/react-avatar": "^1.0.4",
16
- "@radix-ui/react-dialog": "^1.0.5",
17
- "@radix-ui/react-dropdown-menu": "^2.0.6",
18
- "@radix-ui/react-label": "^2.0.2",
19
- "@radix-ui/react-select": "^2.0.0",
20
- "@radix-ui/react-separator": "^1.0.3",
21
- "@radix-ui/react-slot": "^1.0.2",
22
- "@radix-ui/react-switch": "^1.2.6",
23
- "@radix-ui/react-tabs": "^1.0.4",
24
- "@radix-ui/react-toast": "^1.1.5",
25
- "@svton/api-client": "^1.0.0",
26
- "@svton/hooks": "^1.0.0",
27
- "{{ORG_NAME}}/types": "workspace:*",
28
- "axios": "^1.7.9",
29
- "class-variance-authority": "^0.7.1",
30
- "clsx": "^2.1.1",
31
- "dayjs": "^1.11.13",
32
- "lucide-react": "^0.462.0",
33
- "next": "^15.0.0",
34
- "react": "^19.0.0",
35
- "react-dom": "^19.0.0",
36
- "react-hook-form": "^7.49.0",
37
- "swr": "^2.2.5",
38
- "tailwind-merge": "^3.0.0",
39
- "zod": "^3.22.4",
40
- "zustand": "^5.0.0"
41
- },
42
- "devDependencies": {
43
- "@types/node": "^22.0.0",
44
- "@types/react": "^19.0.0",
45
- "@types/react-dom": "^19.0.0",
46
- "autoprefixer": "^10.4.22",
47
- "eslint": "^9.0.0",
48
- "eslint-config-next": "^15.0.0",
49
- "postcss": "^8.5.0",
50
- "tailwindcss": "^3.4.0",
51
- "tailwindcss-animate": "^1.0.7",
52
- "typescript": "^5.7.0"
53
- }
54
- }
@@ -1,6 +0,0 @@
1
- module.exports = {
2
- plugins: {
3
- tailwindcss: {},
4
- autoprefixer: {},
5
- },
6
- };
@@ -1,37 +0,0 @@
1
- @tailwind base;
2
- @tailwind components;
3
- @tailwind utilities;
4
-
5
- @layer base {
6
- :root {
7
- --background: 0 0% 100%;
8
- --foreground: 222.2 84% 4.9%;
9
- --card: 0 0% 100%;
10
- --card-foreground: 222.2 84% 4.9%;
11
- --popover: 0 0% 100%;
12
- --popover-foreground: 222.2 84% 4.9%;
13
- --primary: 222.2 47.4% 11.2%;
14
- --primary-foreground: 210 40% 98%;
15
- --secondary: 210 40% 96.1%;
16
- --secondary-foreground: 222.2 47.4% 11.2%;
17
- --muted: 210 40% 96.1%;
18
- --muted-foreground: 215.4 16.3% 46.9%;
19
- --accent: 210 40% 96.1%;
20
- --accent-foreground: 222.2 47.4% 11.2%;
21
- --destructive: 0 84.2% 60.2%;
22
- --destructive-foreground: 210 40% 98%;
23
- --border: 214.3 31.8% 91.4%;
24
- --input: 214.3 31.8% 91.4%;
25
- --ring: 222.2 84% 4.9%;
26
- --radius: 0.5rem;
27
- }
28
- }
29
-
30
- @layer base {
31
- * {
32
- @apply border-border;
33
- }
34
- body {
35
- @apply bg-background text-foreground;
36
- }
37
- }
@@ -1,19 +0,0 @@
1
- import type { Metadata } from 'next';
2
- import './globals.css';
3
-
4
- export const metadata: Metadata = {
5
- title: '管理后台',
6
- description: '项目管理后台',
7
- };
8
-
9
- export default function RootLayout({
10
- children,
11
- }: {
12
- children: React.ReactNode;
13
- }) {
14
- return (
15
- <html lang="zh-CN">
16
- <body>{children}</body>
17
- </html>
18
- );
19
- }
@@ -1,96 +0,0 @@
1
- 'use client';
2
-
3
- import { useState } from 'react';
4
- import { useRouter } from 'next/navigation';
5
- import { usePersistFn } from '@svton/hooks';
6
- import type { LoginDto } from '{{ORG_NAME}}/types';
7
-
8
- export default function LoginPage() {
9
- const router = useRouter();
10
- const [form, setForm] = useState<LoginDto>({ phone: '', password: '' });
11
- const [loading, setLoading] = useState(false);
12
- const [error, setError] = useState('');
13
-
14
- const handleSubmit = usePersistFn(async (e: React.FormEvent) => {
15
- e.preventDefault();
16
- setError('');
17
- setLoading(true);
18
-
19
- try {
20
- // 这里应该使用 @svton/api-client 的 API
21
- // const response = await apiClient.auth.login(form);
22
- // localStorage.setItem('token', response.data.accessToken);
23
-
24
- // 模拟登录成功
25
- await new Promise((resolve) => setTimeout(resolve, 1000));
26
- router.push('/users');
27
- } catch (err: any) {
28
- setError(err.message || '登录失败');
29
- } finally {
30
- setLoading(false);
31
- }
32
- });
33
-
34
- return (
35
- <div className="min-h-screen flex items-center justify-center bg-gray-50">
36
- <div className="max-w-md w-full space-y-8 p-8 bg-white rounded-lg shadow">
37
- <div>
38
- <h2 className="text-center text-3xl font-bold text-gray-900">
39
- 管理后台
40
- </h2>
41
- <p className="mt-2 text-center text-sm text-gray-600">
42
- 请登录您的账号
43
- </p>
44
- </div>
45
-
46
- <form className="mt-8 space-y-6" onSubmit={handleSubmit}>
47
- {error && (
48
- <div className="bg-red-50 border border-red-200 text-red-600 px-4 py-3 rounded">
49
- {error}
50
- </div>
51
- )}
52
-
53
- <div className="space-y-4">
54
- <div>
55
- <label htmlFor="phone" className="block text-sm font-medium text-gray-700">
56
- 手机号
57
- </label>
58
- <input
59
- id="phone"
60
- type="tel"
61
- required
62
- value={form.phone}
63
- onChange={(e) => setForm({ ...form, phone: e.target.value })}
64
- className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500"
65
- placeholder="请输入手机号"
66
- />
67
- </div>
68
-
69
- <div>
70
- <label htmlFor="password" className="block text-sm font-medium text-gray-700">
71
- 密码
72
- </label>
73
- <input
74
- id="password"
75
- type="password"
76
- required
77
- value={form.password}
78
- onChange={(e) => setForm({ ...form, password: e.target.value })}
79
- className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500"
80
- placeholder="请输入密码"
81
- />
82
- </div>
83
- </div>
84
-
85
- <button
86
- type="submit"
87
- disabled={loading}
88
- className="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50 disabled:cursor-not-allowed"
89
- >
90
- {loading ? '登录中...' : '登录'}
91
- </button>
92
- </form>
93
- </div>
94
- </div>
95
- );
96
- }
@@ -1,8 +0,0 @@
1
- export default function Home() {
2
- return (
3
- <main className="flex min-h-screen flex-col items-center justify-center p-24">
4
- <h1 className="text-4xl font-bold">管理后台</h1>
5
- <p className="mt-4 text-gray-600">欢迎使用管理后台</p>
6
- </main>
7
- );
8
- }