@launch77/cli 1.2.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.
Files changed (398) hide show
  1. package/.eslintrc.json +6 -0
  2. package/dist/app-templates/webapp/.env.ci +6 -0
  3. package/dist/app-templates/webapp/.env.example +9 -0
  4. package/dist/app-templates/webapp/.eslintrc.json +6 -0
  5. package/dist/app-templates/webapp/README.md.hbs +80 -0
  6. package/dist/app-templates/webapp/app/about/page.tsx.hbs +41 -0
  7. package/dist/app-templates/webapp/app/dashboard/page.tsx.hbs +51 -0
  8. package/dist/app-templates/webapp/app/globals.css +31 -0
  9. package/dist/app-templates/webapp/app/layout.tsx.hbs +26 -0
  10. package/dist/app-templates/webapp/app/page.tsx.hbs +30 -0
  11. package/dist/app-templates/webapp/next.config.js +99 -0
  12. package/dist/app-templates/webapp/package.json.hbs +30 -0
  13. package/dist/app-templates/webapp/postcss.config.js +6 -0
  14. package/dist/app-templates/webapp/tailwind.config.ts +24 -0
  15. package/dist/app-templates/webapp/tsconfig.json +29 -0
  16. package/dist/app-templates/webapp/vercel.json.hbs +7 -0
  17. package/dist/cli.d.ts +3 -0
  18. package/dist/cli.d.ts.map +1 -0
  19. package/dist/cli.js +29 -0
  20. package/dist/cli.js.map +1 -0
  21. package/dist/infrastructure/filesystem.d.ts +41 -0
  22. package/dist/infrastructure/filesystem.d.ts.map +1 -0
  23. package/dist/infrastructure/filesystem.js +61 -0
  24. package/dist/infrastructure/filesystem.js.map +1 -0
  25. package/dist/infrastructure/npm.d.ts +9 -0
  26. package/dist/infrastructure/npm.d.ts.map +1 -0
  27. package/dist/infrastructure/npm.js +17 -0
  28. package/dist/infrastructure/npm.js.map +1 -0
  29. package/dist/infrastructure/template-engine.d.ts +12 -0
  30. package/dist/infrastructure/template-engine.d.ts.map +1 -0
  31. package/dist/infrastructure/template-engine.js +40 -0
  32. package/dist/infrastructure/template-engine.js.map +1 -0
  33. package/dist/infrastructure/template-generator.d.ts +9 -0
  34. package/dist/infrastructure/template-generator.d.ts.map +1 -0
  35. package/dist/infrastructure/template-generator.js +19 -0
  36. package/dist/infrastructure/template-generator.js.map +1 -0
  37. package/dist/infrastructure/template.d.ts +20 -0
  38. package/dist/infrastructure/template.d.ts.map +1 -0
  39. package/dist/infrastructure/template.js +53 -0
  40. package/dist/infrastructure/template.js.map +1 -0
  41. package/dist/modules/app/commands/create-app.d.ts +3 -0
  42. package/dist/modules/app/commands/create-app.d.ts.map +1 -0
  43. package/dist/modules/app/commands/create-app.js +51 -0
  44. package/dist/modules/app/commands/create-app.js.map +1 -0
  45. package/dist/modules/app/commands/delete-app.d.ts +3 -0
  46. package/dist/modules/app/commands/delete-app.d.ts.map +1 -0
  47. package/dist/modules/app/commands/delete-app.js +109 -0
  48. package/dist/modules/app/commands/delete-app.js.map +1 -0
  49. package/dist/modules/app/commands/generate-manifest.d.ts +3 -0
  50. package/dist/modules/app/commands/generate-manifest.d.ts.map +1 -0
  51. package/dist/modules/app/commands/generate-manifest.js +62 -0
  52. package/dist/modules/app/commands/generate-manifest.js.map +1 -0
  53. package/dist/modules/app/commands/validate-manifest.d.ts +3 -0
  54. package/dist/modules/app/commands/validate-manifest.d.ts.map +1 -0
  55. package/dist/modules/app/commands/validate-manifest.js +68 -0
  56. package/dist/modules/app/commands/validate-manifest.js.map +1 -0
  57. package/dist/modules/app/errors/app-errors.d.ts +19 -0
  58. package/dist/modules/app/errors/app-errors.d.ts.map +1 -0
  59. package/dist/modules/app/errors/app-errors.js +37 -0
  60. package/dist/modules/app/errors/app-errors.js.map +1 -0
  61. package/dist/modules/app/index.d.ts +10 -0
  62. package/dist/modules/app/index.d.ts.map +1 -0
  63. package/dist/modules/app/index.js +11 -0
  64. package/dist/modules/app/index.js.map +1 -0
  65. package/dist/modules/app/lib/manifest-schema.d.ts +39 -0
  66. package/dist/modules/app/lib/manifest-schema.d.ts.map +1 -0
  67. package/dist/modules/app/lib/manifest-schema.js +44 -0
  68. package/dist/modules/app/lib/manifest-schema.js.map +1 -0
  69. package/dist/modules/app/services/app-svc.d.ts +15 -0
  70. package/dist/modules/app/services/app-svc.d.ts.map +1 -0
  71. package/dist/modules/app/services/app-svc.js +90 -0
  72. package/dist/modules/app/services/app-svc.js.map +1 -0
  73. package/dist/modules/app/services/manifest-svc.d.ts +28 -0
  74. package/dist/modules/app/services/manifest-svc.d.ts.map +1 -0
  75. package/dist/modules/app/services/manifest-svc.js +119 -0
  76. package/dist/modules/app/services/manifest-svc.js.map +1 -0
  77. package/dist/modules/app/types/app-types.d.ts +21 -0
  78. package/dist/modules/app/types/app-types.d.ts.map +1 -0
  79. package/dist/modules/app/types/app-types.js +5 -0
  80. package/dist/modules/app/types/app-types.js.map +1 -0
  81. package/dist/modules/catalog/commands/generate.d.ts +9 -0
  82. package/dist/modules/catalog/commands/generate.d.ts.map +1 -0
  83. package/dist/modules/catalog/commands/generate.js +94 -0
  84. package/dist/modules/catalog/commands/generate.js.map +1 -0
  85. package/dist/modules/catalog/commands/scan.d.ts +9 -0
  86. package/dist/modules/catalog/commands/scan.d.ts.map +1 -0
  87. package/dist/modules/catalog/commands/scan.js +43 -0
  88. package/dist/modules/catalog/commands/scan.js.map +1 -0
  89. package/dist/modules/catalog/config/catalog-config.d.ts +49 -0
  90. package/dist/modules/catalog/config/catalog-config.d.ts.map +1 -0
  91. package/dist/modules/catalog/config/catalog-config.js +116 -0
  92. package/dist/modules/catalog/config/catalog-config.js.map +1 -0
  93. package/dist/modules/catalog/config/catalog-config.test.d.ts +2 -0
  94. package/dist/modules/catalog/config/catalog-config.test.d.ts.map +1 -0
  95. package/dist/modules/catalog/config/catalog-config.test.js +362 -0
  96. package/dist/modules/catalog/config/catalog-config.test.js.map +1 -0
  97. package/dist/modules/catalog/index.d.ts +9 -0
  98. package/dist/modules/catalog/index.d.ts.map +1 -0
  99. package/dist/modules/catalog/index.js +9 -0
  100. package/dist/modules/catalog/index.js.map +1 -0
  101. package/dist/modules/catalog/parsers/typescript-parser.d.ts +15 -0
  102. package/dist/modules/catalog/parsers/typescript-parser.d.ts.map +1 -0
  103. package/dist/modules/catalog/parsers/typescript-parser.js +82 -0
  104. package/dist/modules/catalog/parsers/typescript-parser.js.map +1 -0
  105. package/dist/modules/catalog/scanners/metadata-extractor.d.ts +10 -0
  106. package/dist/modules/catalog/scanners/metadata-extractor.d.ts.map +1 -0
  107. package/dist/modules/catalog/scanners/metadata-extractor.js +122 -0
  108. package/dist/modules/catalog/scanners/metadata-extractor.js.map +1 -0
  109. package/dist/modules/catalog/scanners/metadata-validator.d.ts +6 -0
  110. package/dist/modules/catalog/scanners/metadata-validator.d.ts.map +1 -0
  111. package/dist/modules/catalog/scanners/metadata-validator.js +57 -0
  112. package/dist/modules/catalog/scanners/metadata-validator.js.map +1 -0
  113. package/dist/modules/catalog/scanners/ui-component-scanner.d.ts +11 -0
  114. package/dist/modules/catalog/scanners/ui-component-scanner.d.ts.map +1 -0
  115. package/dist/modules/catalog/scanners/ui-component-scanner.js +147 -0
  116. package/dist/modules/catalog/scanners/ui-component-scanner.js.map +1 -0
  117. package/dist/modules/catalog/schemas/catalog-ui-components.schema.json +161 -0
  118. package/dist/modules/catalog/schemas/schemas/catalog-ui-components.schema.json +145 -0
  119. package/dist/modules/catalog/services/catalog-generator-svc.d.ts +27 -0
  120. package/dist/modules/catalog/services/catalog-generator-svc.d.ts.map +1 -0
  121. package/dist/modules/catalog/services/catalog-generator-svc.js +100 -0
  122. package/dist/modules/catalog/services/catalog-generator-svc.js.map +1 -0
  123. package/dist/modules/catalog/services/catalog-generator-svc.test.d.ts +2 -0
  124. package/dist/modules/catalog/services/catalog-generator-svc.test.d.ts.map +1 -0
  125. package/dist/modules/catalog/services/catalog-generator-svc.test.js +201 -0
  126. package/dist/modules/catalog/services/catalog-generator-svc.test.js.map +1 -0
  127. package/dist/modules/catalog/services/catalog-svc.d.ts +39 -0
  128. package/dist/modules/catalog/services/catalog-svc.d.ts.map +1 -0
  129. package/dist/modules/catalog/services/catalog-svc.js +163 -0
  130. package/dist/modules/catalog/services/catalog-svc.js.map +1 -0
  131. package/dist/modules/catalog/types/catalog-types.d.ts +120 -0
  132. package/dist/modules/catalog/types/catalog-types.d.ts.map +1 -0
  133. package/dist/modules/catalog/types/catalog-types.js +5 -0
  134. package/dist/modules/catalog/types/catalog-types.js.map +1 -0
  135. package/dist/modules/catalog/utils/examples-generator.d.ts +6 -0
  136. package/dist/modules/catalog/utils/examples-generator.d.ts.map +1 -0
  137. package/dist/modules/catalog/utils/examples-generator.js +55 -0
  138. package/dist/modules/catalog/utils/examples-generator.js.map +1 -0
  139. package/dist/modules/catalog/utils/quality-reporter.d.ts +13 -0
  140. package/dist/modules/catalog/utils/quality-reporter.d.ts.map +1 -0
  141. package/dist/modules/catalog/utils/quality-reporter.js +64 -0
  142. package/dist/modules/catalog/utils/quality-reporter.js.map +1 -0
  143. package/dist/modules/catalog/validators/component-name-validator.d.ts +20 -0
  144. package/dist/modules/catalog/validators/component-name-validator.d.ts.map +1 -0
  145. package/dist/modules/catalog/validators/component-name-validator.js +33 -0
  146. package/dist/modules/catalog/validators/component-name-validator.js.map +1 -0
  147. package/dist/modules/catalog/validators/component-name-validator.test.d.ts +2 -0
  148. package/dist/modules/catalog/validators/component-name-validator.test.d.ts.map +1 -0
  149. package/dist/modules/catalog/validators/component-name-validator.test.js +196 -0
  150. package/dist/modules/catalog/validators/component-name-validator.test.js.map +1 -0
  151. package/dist/modules/deploy/commands/deploy-init-action.d.ts +12 -0
  152. package/dist/modules/deploy/commands/deploy-init-action.d.ts.map +1 -0
  153. package/dist/modules/deploy/commands/deploy-init-action.js +220 -0
  154. package/dist/modules/deploy/commands/deploy-init-action.js.map +1 -0
  155. package/dist/modules/deploy/commands/deploy-init.d.ts +6 -0
  156. package/dist/modules/deploy/commands/deploy-init.d.ts.map +1 -0
  157. package/dist/modules/deploy/commands/deploy-init.js +16 -0
  158. package/dist/modules/deploy/commands/deploy-init.js.map +1 -0
  159. package/dist/modules/deploy/commands/deploy-logs-action.d.ts +12 -0
  160. package/dist/modules/deploy/commands/deploy-logs-action.d.ts.map +1 -0
  161. package/dist/modules/deploy/commands/deploy-logs-action.js +113 -0
  162. package/dist/modules/deploy/commands/deploy-logs-action.js.map +1 -0
  163. package/dist/modules/deploy/commands/deploy-logs.d.ts +6 -0
  164. package/dist/modules/deploy/commands/deploy-logs.d.ts.map +1 -0
  165. package/dist/modules/deploy/commands/deploy-logs.js +17 -0
  166. package/dist/modules/deploy/commands/deploy-logs.js.map +1 -0
  167. package/dist/modules/deploy/commands/deploy-status-action.d.ts +8 -0
  168. package/dist/modules/deploy/commands/deploy-status-action.d.ts.map +1 -0
  169. package/dist/modules/deploy/commands/deploy-status-action.js +153 -0
  170. package/dist/modules/deploy/commands/deploy-status-action.js.map +1 -0
  171. package/dist/modules/deploy/commands/deploy-status.d.ts +6 -0
  172. package/dist/modules/deploy/commands/deploy-status.d.ts.map +1 -0
  173. package/dist/modules/deploy/commands/deploy-status.js +13 -0
  174. package/dist/modules/deploy/commands/deploy-status.js.map +1 -0
  175. package/dist/modules/deploy/index.d.ts +7 -0
  176. package/dist/modules/deploy/index.d.ts.map +1 -0
  177. package/dist/modules/deploy/index.js +7 -0
  178. package/dist/modules/deploy/index.js.map +1 -0
  179. package/dist/modules/deploy/services/deploy-svc.d.ts +17 -0
  180. package/dist/modules/deploy/services/deploy-svc.d.ts.map +1 -0
  181. package/dist/modules/deploy/services/deploy-svc.js +25 -0
  182. package/dist/modules/deploy/services/deploy-svc.js.map +1 -0
  183. package/dist/modules/deploy/utils/vercel-extended.d.ts +63 -0
  184. package/dist/modules/deploy/utils/vercel-extended.d.ts.map +1 -0
  185. package/dist/modules/deploy/utils/vercel-extended.js +238 -0
  186. package/dist/modules/deploy/utils/vercel-extended.js.map +1 -0
  187. package/dist/modules/plugin/commands/plugin-install.d.ts +3 -0
  188. package/dist/modules/plugin/commands/plugin-install.d.ts.map +1 -0
  189. package/dist/modules/plugin/commands/plugin-install.js +45 -0
  190. package/dist/modules/plugin/commands/plugin-install.js.map +1 -0
  191. package/dist/modules/plugin/errors/plugin-errors.d.ts +16 -0
  192. package/dist/modules/plugin/errors/plugin-errors.d.ts.map +1 -0
  193. package/dist/modules/plugin/errors/plugin-errors.js +39 -0
  194. package/dist/modules/plugin/errors/plugin-errors.js.map +1 -0
  195. package/dist/modules/plugin/index.d.ts +6 -0
  196. package/dist/modules/plugin/index.d.ts.map +1 -0
  197. package/dist/modules/plugin/index.js +9 -0
  198. package/dist/modules/plugin/index.js.map +1 -0
  199. package/dist/modules/plugin/lib/plugin-registry.d.ts +15 -0
  200. package/dist/modules/plugin/lib/plugin-registry.d.ts.map +1 -0
  201. package/dist/modules/plugin/lib/plugin-registry.js +47 -0
  202. package/dist/modules/plugin/lib/plugin-registry.js.map +1 -0
  203. package/dist/modules/plugin/services/plugin-svc.d.ts +10 -0
  204. package/dist/modules/plugin/services/plugin-svc.d.ts.map +1 -0
  205. package/dist/modules/plugin/services/plugin-svc.js +44 -0
  206. package/dist/modules/plugin/services/plugin-svc.js.map +1 -0
  207. package/dist/modules/plugin/types/plugin-types.d.ts +19 -0
  208. package/dist/modules/plugin/types/plugin-types.d.ts.map +1 -0
  209. package/dist/modules/plugin/types/plugin-types.js +2 -0
  210. package/dist/modules/plugin/types/plugin-types.js.map +1 -0
  211. package/dist/modules/startup/commands/create-startup.d.ts +3 -0
  212. package/dist/modules/startup/commands/create-startup.d.ts.map +1 -0
  213. package/dist/modules/startup/commands/create-startup.js +43 -0
  214. package/dist/modules/startup/commands/create-startup.js.map +1 -0
  215. package/dist/modules/startup/errors/startup-errors.d.ts +13 -0
  216. package/dist/modules/startup/errors/startup-errors.d.ts.map +1 -0
  217. package/dist/modules/startup/errors/startup-errors.js +25 -0
  218. package/dist/modules/startup/errors/startup-errors.js.map +1 -0
  219. package/dist/modules/startup/index.d.ts +5 -0
  220. package/dist/modules/startup/index.d.ts.map +1 -0
  221. package/dist/modules/startup/index.js +7 -0
  222. package/dist/modules/startup/index.js.map +1 -0
  223. package/dist/modules/startup/services/startup-service.d.ts +7 -0
  224. package/dist/modules/startup/services/startup-service.d.ts.map +1 -0
  225. package/dist/modules/startup/services/startup-service.js +43 -0
  226. package/dist/modules/startup/services/startup-service.js.map +1 -0
  227. package/dist/modules/startup/types/startup-types.d.ts +8 -0
  228. package/dist/modules/startup/types/startup-types.d.ts.map +1 -0
  229. package/dist/modules/startup/types/startup-types.js +2 -0
  230. package/dist/modules/startup/types/startup-types.js.map +1 -0
  231. package/dist/modules/startup/utils/startup-validators.d.ts +8 -0
  232. package/dist/modules/startup/utils/startup-validators.d.ts.map +1 -0
  233. package/dist/modules/startup/utils/startup-validators.js +17 -0
  234. package/dist/modules/startup/utils/startup-validators.js.map +1 -0
  235. package/dist/modules/workspace/commands/init-workspace.d.ts +3 -0
  236. package/dist/modules/workspace/commands/init-workspace.d.ts.map +1 -0
  237. package/dist/modules/workspace/commands/init-workspace.js +54 -0
  238. package/dist/modules/workspace/commands/init-workspace.js.map +1 -0
  239. package/dist/modules/workspace/errors/workspace-errors.d.ts +10 -0
  240. package/dist/modules/workspace/errors/workspace-errors.d.ts.map +1 -0
  241. package/dist/modules/workspace/errors/workspace-errors.js +19 -0
  242. package/dist/modules/workspace/errors/workspace-errors.js.map +1 -0
  243. package/dist/modules/workspace/index.d.ts +5 -0
  244. package/dist/modules/workspace/index.d.ts.map +1 -0
  245. package/dist/modules/workspace/index.js +7 -0
  246. package/dist/modules/workspace/index.js.map +1 -0
  247. package/dist/modules/workspace/services/workspace-service.d.ts +6 -0
  248. package/dist/modules/workspace/services/workspace-service.d.ts.map +1 -0
  249. package/dist/modules/workspace/services/workspace-service.js +46 -0
  250. package/dist/modules/workspace/services/workspace-service.js.map +1 -0
  251. package/dist/modules/workspace/types/workspace-types.d.ts +8 -0
  252. package/dist/modules/workspace/types/workspace-types.d.ts.map +1 -0
  253. package/dist/modules/workspace/types/workspace-types.js +2 -0
  254. package/dist/modules/workspace/types/workspace-types.js.map +1 -0
  255. package/dist/modules/workspace/utils/workspace-validators.d.ts +8 -0
  256. package/dist/modules/workspace/utils/workspace-validators.d.ts.map +1 -0
  257. package/dist/modules/workspace/utils/workspace-validators.js +17 -0
  258. package/dist/modules/workspace/utils/workspace-validators.js.map +1 -0
  259. package/dist/plugins/theme/package.json +32 -0
  260. package/dist/plugins/theme/plugin.json +9 -0
  261. package/dist/plugins/theme/src/generator.ts +92 -0
  262. package/dist/plugins/theme/src/utils/config-modifier.ts +142 -0
  263. package/dist/plugins/theme/src/utils/css-modifier.ts +89 -0
  264. package/dist/plugins/theme/templates/app/theme-test/page.tsx +156 -0
  265. package/dist/plugins/theme/templates/src/modules/theme/README.md +209 -0
  266. package/dist/plugins/theme/templates/src/modules/theme/config/brand.css +23 -0
  267. package/dist/plugins/theme/tsconfig.json +14 -0
  268. package/dist/plugins/theme/tsup.config.ts +10 -0
  269. package/dist/templates/startup/apps/.gitkeep +8 -0
  270. package/dist/templates/templates/startup/apps/.gitkeep +8 -0
  271. package/dist/templates/templates/workspace/.eslintignore +7 -0
  272. package/dist/templates/templates/workspace/.eslintrc.js +38 -0
  273. package/dist/templates/templates/workspace/.husky/pre-push +24 -0
  274. package/dist/templates/templates/workspace/.launch77/workspace.json +3 -0
  275. package/dist/templates/templates/workspace/.lintstagedrc.json +4 -0
  276. package/dist/templates/templates/workspace/.prettierrc +9 -0
  277. package/dist/templates/templates/workspace/README.md +62 -0
  278. package/dist/templates/templates/workspace/app-templates/.gitkeep +1 -0
  279. package/dist/templates/templates/workspace/apps/.gitkeep +1 -0
  280. package/dist/templates/templates/workspace/libraries/.gitkeep +1 -0
  281. package/dist/templates/templates/workspace/package.json +31 -0
  282. package/dist/templates/templates/workspace/plugins/.gitkeep +1 -0
  283. package/dist/templates/templates/workspace/tsconfig.json +22 -0
  284. package/dist/templates/templates/workspace/turbo.json +25 -0
  285. package/dist/templates/workspace/.launch77/workspace.json +3 -0
  286. package/dist/templates/workspace/README.md +62 -0
  287. package/dist/templates/workspace/app-templates/.gitkeep +1 -0
  288. package/dist/templates/workspace/apps/.gitkeep +1 -0
  289. package/dist/templates/workspace/libraries/.gitkeep +1 -0
  290. package/dist/templates/workspace/package.json +21 -0
  291. package/dist/templates/workspace/plugins/.gitkeep +1 -0
  292. package/dist/templates/workspace/tsconfig.json +22 -0
  293. package/dist/templates/workspace/turbo.json +25 -0
  294. package/dist/utils/launch77-context.d.ts +16 -0
  295. package/dist/utils/launch77-context.d.ts.map +1 -0
  296. package/dist/utils/launch77-context.js +111 -0
  297. package/dist/utils/launch77-context.js.map +1 -0
  298. package/dist/utils/launch77-validation.d.ts +17 -0
  299. package/dist/utils/launch77-validation.d.ts.map +1 -0
  300. package/dist/utils/launch77-validation.js +44 -0
  301. package/dist/utils/launch77-validation.js.map +1 -0
  302. package/dist/utils/monorepo.d.ts +19 -0
  303. package/dist/utils/monorepo.d.ts.map +1 -0
  304. package/dist/utils/monorepo.js +100 -0
  305. package/dist/utils/monorepo.js.map +1 -0
  306. package/dist/utils/validation.d.ts +32 -0
  307. package/dist/utils/validation.d.ts.map +1 -0
  308. package/dist/utils/validation.js +92 -0
  309. package/dist/utils/validation.js.map +1 -0
  310. package/dist/utils/version.d.ts +7 -0
  311. package/dist/utils/version.d.ts.map +1 -0
  312. package/dist/utils/version.js +16 -0
  313. package/dist/utils/version.js.map +1 -0
  314. package/launch77-cli-1.2.0.tgz +0 -0
  315. package/package.json +48 -0
  316. package/src/cli.ts +34 -0
  317. package/src/infrastructure/filesystem.ts +69 -0
  318. package/src/infrastructure/npm.ts +18 -0
  319. package/src/infrastructure/template-engine.ts +48 -0
  320. package/src/infrastructure/template-generator.ts +26 -0
  321. package/src/infrastructure/template.ts +66 -0
  322. package/src/modules/app/commands/create-app.ts +60 -0
  323. package/src/modules/app/commands/delete-app.ts +123 -0
  324. package/src/modules/app/commands/generate-manifest.ts +75 -0
  325. package/src/modules/app/commands/validate-manifest.ts +78 -0
  326. package/src/modules/app/errors/app-errors.ts +41 -0
  327. package/src/modules/app/index.ts +16 -0
  328. package/src/modules/app/lib/manifest-schema.ts +65 -0
  329. package/src/modules/app/services/app-svc.ts +115 -0
  330. package/src/modules/app/services/manifest-svc.ts +144 -0
  331. package/src/modules/app/types/app-types.ts +27 -0
  332. package/src/modules/catalog/commands/generate.ts +115 -0
  333. package/src/modules/catalog/commands/scan.ts +48 -0
  334. package/src/modules/catalog/config/catalog-config.test.ts +404 -0
  335. package/src/modules/catalog/config/catalog-config.ts +130 -0
  336. package/src/modules/catalog/index.ts +9 -0
  337. package/src/modules/catalog/parsers/typescript-parser.ts +93 -0
  338. package/src/modules/catalog/scanners/metadata-extractor.ts +134 -0
  339. package/src/modules/catalog/scanners/metadata-validator.ts +67 -0
  340. package/src/modules/catalog/scanners/ui-component-scanner.ts +185 -0
  341. package/src/modules/catalog/schemas/catalog-ui-components.schema.json +145 -0
  342. package/src/modules/catalog/services/catalog-generator-svc.test.ts +233 -0
  343. package/src/modules/catalog/services/catalog-generator-svc.ts +124 -0
  344. package/src/modules/catalog/services/catalog-svc.ts +222 -0
  345. package/src/modules/catalog/types/catalog-types.ts +149 -0
  346. package/src/modules/catalog/utils/examples-generator.ts +68 -0
  347. package/src/modules/catalog/utils/quality-reporter.ts +76 -0
  348. package/src/modules/catalog/validators/component-name-validator.test.ts +233 -0
  349. package/src/modules/catalog/validators/component-name-validator.ts +43 -0
  350. package/src/modules/deploy/commands/deploy-init-action.ts +247 -0
  351. package/src/modules/deploy/commands/deploy-init.ts +19 -0
  352. package/src/modules/deploy/commands/deploy-logs-action.ts +135 -0
  353. package/src/modules/deploy/commands/deploy-logs.ts +20 -0
  354. package/src/modules/deploy/commands/deploy-status-action.ts +175 -0
  355. package/src/modules/deploy/commands/deploy-status.ts +16 -0
  356. package/src/modules/deploy/index.ts +7 -0
  357. package/src/modules/deploy/services/deploy-svc.ts +31 -0
  358. package/src/modules/deploy/utils/vercel-extended.ts +286 -0
  359. package/src/modules/plugin/commands/plugin-install.ts +51 -0
  360. package/src/modules/plugin/errors/plugin-errors.ts +44 -0
  361. package/src/modules/plugin/index.ts +14 -0
  362. package/src/modules/plugin/lib/launch77-workspace.code-workspace +14 -0
  363. package/src/modules/plugin/lib/plugin-registry.ts +59 -0
  364. package/src/modules/plugin/services/plugin-svc.ts +53 -0
  365. package/src/modules/plugin/types/plugin-types.ts +21 -0
  366. package/src/modules/startup/commands/create-startup.ts +53 -0
  367. package/src/modules/startup/errors/startup-errors.ts +23 -0
  368. package/src/modules/startup/index.ts +11 -0
  369. package/src/modules/startup/services/startup-service.ts +57 -0
  370. package/src/modules/startup/types/startup-types.ts +8 -0
  371. package/src/modules/startup/utils/startup-validators.ts +19 -0
  372. package/src/modules/workspace/commands/init-workspace.ts +63 -0
  373. package/src/modules/workspace/errors/workspace-errors.ts +16 -0
  374. package/src/modules/workspace/index.ts +11 -0
  375. package/src/modules/workspace/services/workspace-service.ts +59 -0
  376. package/src/modules/workspace/types/workspace-types.ts +8 -0
  377. package/src/modules/workspace/utils/workspace-validators.ts +19 -0
  378. package/src/utils/launch77-context.ts +152 -0
  379. package/src/utils/launch77-validation.ts +59 -0
  380. package/src/utils/monorepo.ts +137 -0
  381. package/src/utils/validation.ts +117 -0
  382. package/src/utils/version.ts +16 -0
  383. package/templates/startup/apps/.gitkeep +8 -0
  384. package/templates/workspace/.eslintignore +7 -0
  385. package/templates/workspace/.eslintrc.js +38 -0
  386. package/templates/workspace/.husky/pre-push +24 -0
  387. package/templates/workspace/.launch77/workspace.json +3 -0
  388. package/templates/workspace/.lintstagedrc.json +4 -0
  389. package/templates/workspace/.prettierrc +9 -0
  390. package/templates/workspace/README.md +62 -0
  391. package/templates/workspace/app-templates/.gitkeep +1 -0
  392. package/templates/workspace/apps/.gitkeep +1 -0
  393. package/templates/workspace/libraries/.gitkeep +1 -0
  394. package/templates/workspace/package.json +31 -0
  395. package/templates/workspace/plugins/.gitkeep +1 -0
  396. package/templates/workspace/tsconfig.json +22 -0
  397. package/templates/workspace/turbo.json +25 -0
  398. package/tsconfig.json +23 -0
@@ -0,0 +1,286 @@
1
+ /**
2
+ * Extended Vercel CLI utilities - Additional helpers for deployment commands
3
+ */
4
+
5
+ import { execSync } from 'child_process'
6
+ import * as path from 'path'
7
+
8
+ import chalk from 'chalk'
9
+ import { execa } from 'execa'
10
+ import fs from 'fs-extra'
11
+
12
+ /**
13
+ * Vercel project information from .vercel/project.json
14
+ */
15
+ export interface VercelProject {
16
+ projectId: string
17
+ orgId: string
18
+ projectName?: string
19
+ }
20
+
21
+ /**
22
+ * Vercel project information from API
23
+ */
24
+ export interface VercelProjectInfo {
25
+ name: string
26
+ id: string
27
+ latestProductionUrl?: string
28
+ updatedAt: number
29
+ deprecated: boolean
30
+ }
31
+
32
+ /**
33
+ * Check if Vercel CLI is installed globally
34
+ */
35
+ export async function isVercelCliInstalled(): Promise<boolean> {
36
+ try {
37
+ execSync('which vercel', { stdio: 'ignore' })
38
+ return true
39
+ } catch {
40
+ return false
41
+ }
42
+ }
43
+
44
+ /**
45
+ * Get Vercel installation instructions
46
+ */
47
+ export function getVercelInstallInstructions(): string {
48
+ return 'npm install -g vercel'
49
+ }
50
+
51
+ /**
52
+ * Load Vercel project information from .vercel/project.json
53
+ */
54
+ export async function loadVercelProject(appPath: string): Promise<VercelProject | null> {
55
+ const projectPath = path.join(appPath, '.vercel', 'project.json')
56
+
57
+ if (!(await fs.pathExists(projectPath))) {
58
+ return null
59
+ }
60
+
61
+ try {
62
+ return await fs.readJSON(projectPath)
63
+ } catch (error) {
64
+ console.warn(chalk.yellow('Warning: Could not read .vercel/project.json'))
65
+ return null
66
+ }
67
+ }
68
+
69
+ /**
70
+ * Run Vercel CLI command with execa
71
+ */
72
+ export async function runVercelCommand(args: string[], cwd: string, options: { silent?: boolean } = {}): Promise<{ stdout?: string; stderr?: string }> {
73
+ try {
74
+ const result = await execa('vercel', args, {
75
+ cwd,
76
+ stdio: options.silent ? 'pipe' : 'inherit',
77
+ })
78
+ return {
79
+ stdout: result.stdout || '',
80
+ stderr: result.stderr || '',
81
+ }
82
+ } catch (error) {
83
+ const errorObj = error as { code?: string }
84
+ if (errorObj.code === 'ENOENT') {
85
+ throw new Error('Vercel CLI is not installed. Run: npm install -g vercel')
86
+ }
87
+ throw error
88
+ }
89
+ }
90
+
91
+ /**
92
+ * Get package name from package.json
93
+ */
94
+ export async function getPackageName(appPath: string): Promise<string | null> {
95
+ const packageJsonPath = path.join(appPath, 'package.json')
96
+
97
+ if (!(await fs.pathExists(packageJsonPath))) {
98
+ return null
99
+ }
100
+
101
+ try {
102
+ const packageJson = await fs.readJSON(packageJsonPath)
103
+ return packageJson.name || null
104
+ } catch {
105
+ return null
106
+ }
107
+ }
108
+
109
+ /**
110
+ * Extract Git remote URL from local repository
111
+ */
112
+ export async function extractGitRemoteUrl(cwd: string): Promise<string | null> {
113
+ try {
114
+ const { stdout } = await execa('git', ['config', '--get', 'remote.origin.url'], {
115
+ cwd,
116
+ reject: false,
117
+ })
118
+
119
+ if (!stdout) {
120
+ return null
121
+ }
122
+
123
+ // Convert SSH URLs to HTTPS format for Vercel
124
+ let url = stdout.trim()
125
+ if (url.startsWith('git@github.com:')) {
126
+ url = url.replace('git@github.com:', 'https://github.com/')
127
+ }
128
+ if (url.endsWith('.git')) {
129
+ url = url.slice(0, -4)
130
+ }
131
+
132
+ return url
133
+ } catch (error) {
134
+ console.warn(chalk.yellow('Warning: Could not extract Git remote URL'))
135
+ return null
136
+ }
137
+ }
138
+
139
+ /**
140
+ * Verify if a Vercel project exists
141
+ */
142
+ export async function verifyVercelProjectExists(projectName: string): Promise<VercelProjectInfo | null> {
143
+ try {
144
+ const result = await execa('vercel', ['projects', 'ls', '--json'], {
145
+ stdio: 'pipe',
146
+ })
147
+
148
+ if (!result.stdout) {
149
+ return null
150
+ }
151
+
152
+ const data = JSON.parse(result.stdout)
153
+ const projects = data.projects as VercelProjectInfo[]
154
+
155
+ const project = projects.find((p) => p.name === projectName)
156
+ return project || null
157
+ } catch (error) {
158
+ console.warn(chalk.yellow('Warning: Could not verify Vercel project existence'))
159
+ return null
160
+ }
161
+ }
162
+
163
+ /**
164
+ * Connect Vercel project to Git repository
165
+ */
166
+ export async function connectGitRepository(appPath: string, gitUrl?: string | null): Promise<boolean> {
167
+ try {
168
+ if (!gitUrl) {
169
+ gitUrl = await extractGitRemoteUrl(appPath)
170
+ if (!gitUrl) {
171
+ console.warn(chalk.yellow('Warning: No Git remote URL found'))
172
+ return false
173
+ }
174
+ }
175
+
176
+ console.log(chalk.cyan('šŸ”— Connecting to GitHub repository...'))
177
+ console.log(chalk.gray(` Repository: ${gitUrl}`))
178
+
179
+ try {
180
+ const result = await runVercelCommand(['git', 'connect', gitUrl, '--yes'], appPath, {
181
+ silent: true,
182
+ })
183
+
184
+ const output = (result.stdout || '') + ' ' + (result.stderr || '')
185
+ if (output.includes('already connected')) {
186
+ console.log(chalk.green('āœ… Repository already connected to GitHub!'))
187
+ return true
188
+ }
189
+
190
+ console.log(chalk.green('āœ… Successfully connected to GitHub!'))
191
+ return true
192
+ } catch (gitError) {
193
+ const errorObj = gitError as {
194
+ stderr?: string
195
+ stdout?: string
196
+ message?: string
197
+ shortMessage?: string
198
+ }
199
+
200
+ const fullErrorText = [errorObj.message || '', errorObj.shortMessage || '', errorObj.stderr || '', errorObj.stdout || '', String(gitError)].join(' ')
201
+
202
+ if (fullErrorText.includes('already connected')) {
203
+ console.log(chalk.green('āœ… Repository already connected to GitHub!'))
204
+ return true
205
+ }
206
+
207
+ throw gitError
208
+ }
209
+ } catch (error) {
210
+ console.error(chalk.red('āŒ Failed to connect to Git repository'))
211
+ const errorMessage = error instanceof Error ? error.message : String(error)
212
+ console.error(chalk.gray(errorMessage))
213
+ return false
214
+ }
215
+ }
216
+
217
+ /**
218
+ * Get Vercel auth token from config
219
+ */
220
+ async function getVercelAuthToken(): Promise<string | null> {
221
+ try {
222
+ let authPath: string
223
+
224
+ if (process.platform === 'darwin') {
225
+ const homeDir = process.env.HOME || ''
226
+ authPath = path.join(homeDir, 'Library', 'Application Support', 'com.vercel.cli', 'auth.json')
227
+ } else if (process.platform === 'win32') {
228
+ const appData = process.env.APPDATA || ''
229
+ authPath = path.join(appData, 'com.vercel.cli', 'auth.json')
230
+ } else {
231
+ const homeDir = process.env.HOME || ''
232
+ authPath = path.join(homeDir, '.config', 'vercel', 'auth.json')
233
+ }
234
+
235
+ if (!(await fs.pathExists(authPath))) {
236
+ return null
237
+ }
238
+
239
+ const authData = await fs.readJSON(authPath)
240
+ return authData.token || null
241
+ } catch {
242
+ return null
243
+ }
244
+ }
245
+
246
+ /**
247
+ * Update Vercel project root directory via REST API
248
+ */
249
+ export async function updateProjectRootDirectory(projectName: string, rootDirectory: string): Promise<boolean> {
250
+ try {
251
+ console.log(chalk.cyan('šŸ“ Setting Root Directory in Vercel...'))
252
+ console.log(chalk.gray(` Root Directory: ${rootDirectory}`))
253
+
254
+ const token = await getVercelAuthToken()
255
+ if (!token) {
256
+ console.warn(chalk.yellow('Warning: Could not get Vercel auth token'))
257
+ return false
258
+ }
259
+
260
+ const response = await fetch(`https://api.vercel.com/v9/projects/${encodeURIComponent(projectName)}`, {
261
+ method: 'PATCH',
262
+ headers: {
263
+ Authorization: `Bearer ${token}`,
264
+ 'Content-Type': 'application/json',
265
+ },
266
+ body: JSON.stringify({
267
+ rootDirectory,
268
+ }),
269
+ })
270
+
271
+ if (!response.ok) {
272
+ const errorText = await response.text()
273
+ console.warn(chalk.yellow(`Warning: Failed to update root directory (${response.status})`))
274
+ console.warn(chalk.gray(errorText))
275
+ return false
276
+ }
277
+
278
+ console.log(chalk.green('āœ… Root Directory configured!'))
279
+ return true
280
+ } catch (error) {
281
+ console.warn(chalk.yellow('Warning: Failed to update root directory'))
282
+ const errorMessage = error instanceof Error ? error.message : String(error)
283
+ console.warn(chalk.gray(errorMessage))
284
+ return false
285
+ }
286
+ }
@@ -0,0 +1,51 @@
1
+ /* eslint-disable no-console */
2
+ import chalk from 'chalk'
3
+ import { Command } from 'commander'
4
+ import ora from 'ora'
5
+
6
+ import { detectLaunch77Context } from '../../../utils/launch77-context.js'
7
+ import { PluginService } from '../services/plugin-svc.js'
8
+
9
+ export function pluginInstallCommand(): Command {
10
+ const command = new Command('plugin:install')
11
+ .argument('<plugin-name>', 'Name of the plugin to install (e.g., database)')
12
+ .description('Install a plugin to the current app')
13
+ .action(async (pluginName: string) => {
14
+ try {
15
+ console.log(chalk.blue(`\nšŸ”Œ Installing ${pluginName} plugin\n`))
16
+
17
+ // Detect context
18
+ const context = await detectLaunch77Context(process.cwd())
19
+
20
+ // Create plugin service
21
+ const pluginService = new PluginService()
22
+
23
+ // Install files
24
+ const filesSpinner = ora('Installing plugin files...').start()
25
+ try {
26
+ await pluginService.installPlugin({ pluginName }, context)
27
+ filesSpinner.succeed('Plugin files installed')
28
+ } catch (error) {
29
+ filesSpinner.fail('Failed to install plugin')
30
+ throw error
31
+ }
32
+
33
+ // Package.json update spinner
34
+ const pkgSpinner = ora('Updating package.json...').start()
35
+ pkgSpinner.succeed('package.json updated')
36
+
37
+ // Dependencies spinner
38
+ const installSpinner = ora('Installing dependencies...').start()
39
+ installSpinner.succeed('Dependencies installed')
40
+
41
+ // Success message (post-install hook handles custom messages)
42
+ console.log(chalk.green(`\nāœ… Plugin '${pluginName}' installed successfully!\n`))
43
+ } catch (error) {
44
+ const message = error instanceof Error ? error.message : String(error)
45
+ console.error(chalk.red('Error:'), message)
46
+ process.exit(1)
47
+ }
48
+ })
49
+
50
+ return command
51
+ }
@@ -0,0 +1,44 @@
1
+ export class PluginNotFoundError extends Error {
2
+ constructor(pluginName: string) {
3
+ super(`Plugin '${pluginName}' not found.
4
+
5
+ Run 'launch77 plugin:list' to see available plugins.`)
6
+ this.name = 'PluginNotFoundError'
7
+ }
8
+ }
9
+
10
+ export class InvalidPluginContextError extends Error {
11
+ constructor(message: string) {
12
+ super(message)
13
+ this.name = 'InvalidPluginContextError'
14
+ }
15
+ }
16
+
17
+ /**
18
+ * Factory function to create standardized InvalidPluginContextError
19
+ * for when plugin:install is run outside of an app directory
20
+ */
21
+ export function createInvalidContextError(currentLocation: string): InvalidPluginContextError {
22
+ return new InvalidPluginContextError(
23
+ `plugin:install must be run from within an app directory.
24
+
25
+ Current location: ${currentLocation}
26
+ Expected: apps/<app-name>/
27
+
28
+ Navigate to an app directory:
29
+ cd apps/<app-name>/
30
+
31
+ Or create an app first:
32
+ launch77 app:create api <app-name>`
33
+ )
34
+ }
35
+
36
+ export class PluginInstallationError extends Error {
37
+ constructor(
38
+ message: string,
39
+ public readonly cause?: Error
40
+ ) {
41
+ super(message)
42
+ this.name = 'PluginInstallationError'
43
+ }
44
+ }
@@ -0,0 +1,14 @@
1
+ // Services
2
+ export { PluginService } from './services/plugin-svc.js'
3
+
4
+ // Types
5
+ export type { InstallPluginRequest, InstallPluginResult, PluginMetadata, HookResult } from './types/plugin-types.js'
6
+
7
+ // Errors
8
+ export { PluginNotFoundError, InvalidPluginContextError, PluginInstallationError } from './errors/plugin-errors.js'
9
+
10
+ // Commands
11
+ export { pluginInstallCommand } from './commands/plugin-install.js'
12
+
13
+ // Utilities
14
+ export { getPluginPath, pluginExists, listAvailablePlugins } from './lib/plugin-registry.js'
@@ -0,0 +1,14 @@
1
+ {
2
+ "folders": [
3
+ {
4
+ "path": "../../../../../.."
5
+ },
6
+ {
7
+ "path": "../../../../../../../launch77"
8
+ },
9
+ {
10
+ "path": "../../../../../../../launch-workspaces/fostersauce"
11
+ }
12
+ ],
13
+ "settings": {}
14
+ }
@@ -0,0 +1,59 @@
1
+ import * as path from 'path'
2
+ import { fileURLToPath } from 'url'
3
+
4
+ import fs from 'fs-extra'
5
+
6
+ /**
7
+ * Get the path to a plugin directory
8
+ * Plugins are bundled with the CLI at dist/plugins/
9
+ */
10
+ export function getPluginPath(pluginName: string): string {
11
+ const __filename = fileURLToPath(import.meta.url)
12
+ const __dirname = path.dirname(__filename)
13
+
14
+ // From dist/modules/plugin/lib/ to dist/plugins/
15
+ const baseDir = path.join(__dirname, '../../../plugins')
16
+
17
+ return path.join(baseDir, pluginName)
18
+ }
19
+
20
+ /**
21
+ * Check if a plugin exists
22
+ * A plugin must have: dist/generator.js and plugin.json
23
+ */
24
+ export async function pluginExists(pluginName: string): Promise<boolean> {
25
+ const pluginPath = getPluginPath(pluginName)
26
+
27
+ const hasGenerator = await fs.pathExists(path.join(pluginPath, 'dist/generator.js'))
28
+ const hasPluginJson = await fs.pathExists(path.join(pluginPath, 'plugin.json'))
29
+
30
+ return hasGenerator && hasPluginJson
31
+ }
32
+
33
+ /**
34
+ * List all available plugins
35
+ */
36
+ export async function listAvailablePlugins(): Promise<string[]> {
37
+ const __filename = fileURLToPath(import.meta.url)
38
+ const __dirname = path.dirname(__filename)
39
+
40
+ const baseDir = path.join(__dirname, '../../../plugins')
41
+
42
+ if (!(await fs.pathExists(baseDir))) {
43
+ return []
44
+ }
45
+
46
+ const items = await fs.readdir(baseDir, { withFileTypes: true })
47
+ const plugins: string[] = []
48
+
49
+ for (const item of items) {
50
+ if (item.isDirectory()) {
51
+ // Verify it's a valid plugin
52
+ if (await pluginExists(item.name)) {
53
+ plugins.push(item.name)
54
+ }
55
+ }
56
+ }
57
+
58
+ return plugins
59
+ }
@@ -0,0 +1,53 @@
1
+ import * as path from 'path'
2
+
3
+ import { execa } from 'execa'
4
+
5
+ import { PluginInstallationError, PluginNotFoundError, InvalidPluginContextError, createInvalidContextError } from '../errors/plugin-errors.js'
6
+ import { pluginExists, getPluginPath } from '../lib/plugin-registry.js'
7
+
8
+ import type { Launch77Context } from '../../../utils/launch77-context.js'
9
+ import type { InstallPluginRequest, InstallPluginResult } from '../types/plugin-types.js'
10
+
11
+ export class PluginService {
12
+ /**
13
+ * Install a plugin to the current app
14
+ */
15
+ async installPlugin(request: InstallPluginRequest, context: Launch77Context): Promise<InstallPluginResult> {
16
+ const { pluginName } = request
17
+
18
+ // Validate context - must be in app directory
19
+ if (context.locationType !== 'workspace-app') throw createInvalidContextError(context.locationType)
20
+ if (!context.appName) throw new InvalidPluginContextError('Could not determine app name. This is a bug. Please report it.')
21
+
22
+ // Get app directory path
23
+ const appPath = path.join(context.appsDir, context.appName)
24
+
25
+ // Check if plugin exists
26
+ if (!(await pluginExists(pluginName))) throw new PluginNotFoundError(pluginName)
27
+
28
+ const pluginPath = getPluginPath(pluginName)
29
+
30
+ // Run generator
31
+ await this.runGenerator(pluginPath, appPath, context)
32
+
33
+ return {
34
+ pluginName,
35
+ filesInstalled: true,
36
+ packageJsonUpdated: true,
37
+ dependenciesInstalled: true,
38
+ }
39
+ }
40
+
41
+ private async runGenerator(pluginPath: string, appPath: string, context: Launch77Context): Promise<void> {
42
+ try {
43
+ const generatorPath = path.join(pluginPath, 'dist/generator.js')
44
+
45
+ await execa('node', [generatorPath, `--appPath=${appPath}`, `--appName=${context.appName}`, `--workspaceName=${context.workspaceName}`, `--pluginPath=${pluginPath}`], {
46
+ cwd: pluginPath,
47
+ stdio: 'inherit',
48
+ })
49
+ } catch (error) {
50
+ throw new PluginInstallationError(`Generator failed: ${error instanceof Error ? error.message : String(error)}`, error instanceof Error ? error : undefined)
51
+ }
52
+ }
53
+ }
@@ -0,0 +1,21 @@
1
+ export interface InstallPluginRequest {
2
+ pluginName: string
3
+ }
4
+
5
+ export interface InstallPluginResult {
6
+ pluginName: string
7
+ filesInstalled: boolean
8
+ packageJsonUpdated: boolean
9
+ dependenciesInstalled: boolean
10
+ }
11
+
12
+ export interface PluginMetadata {
13
+ dependencies?: Record<string, string>
14
+ devDependencies?: Record<string, string>
15
+ scripts?: Record<string, string>
16
+ }
17
+
18
+ export interface HookResult {
19
+ templateVariables?: Record<string, string>
20
+ hookContext?: Record<string, string>
21
+ }
@@ -0,0 +1,53 @@
1
+ import * as path from 'path'
2
+
3
+ import chalk from 'chalk'
4
+ import { Command } from 'commander'
5
+ import ora from 'ora'
6
+
7
+ import { detectMonorepoContext } from '../../../utils/monorepo.js'
8
+ import { StartupAlreadyExistsError, InvalidStartupNameError, NotInMonorepoRootError } from '../errors/startup-errors.js'
9
+ import { StartupService } from '../services/startup-service.js'
10
+
11
+ export function createStartupCommand(): Command {
12
+ return new Command('startup:create')
13
+ .argument('<name>', 'Name of the startup (lowercase, alphanumeric, hyphens)')
14
+ .description('Create a new startup with brand configuration')
15
+ .action(async (name: string) => {
16
+ console.log(chalk.blue(`\nšŸš€ Creating startup: ${name}\n`))
17
+
18
+ const service = new StartupService()
19
+
20
+ try {
21
+ const spinner = ora('Creating startup structure...').start()
22
+
23
+ // Detect monorepo context
24
+ const context = await detectMonorepoContext(process.cwd())
25
+
26
+ const result = await service.createStartup({ name }, context)
27
+
28
+ spinner.succeed('Startup structure created')
29
+
30
+ // Success message
31
+ const cwd = process.cwd()
32
+ console.log(chalk.green(`\nāœ… Startup created successfully at ${path.relative(cwd, result.startupPath)}`))
33
+ console.log(chalk.gray(`\nNext steps:\n` + ` 1. Create your first app:\n` + ` - Web app: launch77 create-app webapp <app-name>\n` + ` - API: launch77 create-app api <app-name>\n` + ` - Marketing site: launch77 create-app marketing-site <app-name>\n`))
34
+ } catch (error) {
35
+ if (error instanceof StartupAlreadyExistsError) {
36
+ console.error(chalk.red(`\nāŒ ${error.message}\n`))
37
+ process.exit(1)
38
+ }
39
+
40
+ if (error instanceof InvalidStartupNameError) {
41
+ console.error(chalk.red(`\nāŒ ${error.message}\n`))
42
+ process.exit(1)
43
+ }
44
+
45
+ if (error instanceof NotInMonorepoRootError) {
46
+ console.error(chalk.red(`\nāŒ ${error.message}\n`))
47
+ process.exit(1)
48
+ }
49
+
50
+ throw error
51
+ }
52
+ })
53
+ }
@@ -0,0 +1,23 @@
1
+ export class StartupAlreadyExistsError extends Error {
2
+ constructor(
3
+ public startupName: string,
4
+ public startupPath: string
5
+ ) {
6
+ super(`Startup ${startupName} already exists at ${startupPath}`)
7
+ this.name = 'StartupAlreadyExistsError'
8
+ }
9
+ }
10
+
11
+ export class InvalidStartupNameError extends Error {
12
+ constructor(public startupName: string) {
13
+ super(`Invalid startup name: "${startupName}"\n\n` + `Startup names must:\n` + ` • Be lowercase only\n` + ` • Can only contain: lowercase letters, numbers, and hyphens\n` + ` • Cannot contain: spaces, uppercase, underscores, periods, or special characters\n\n` + `Valid examples:\n` + ` āœ“ my-startup\n` + ` āœ“ mystartup\n` + ` āœ“ startup123\n\n` + `Invalid examples:\n` + ` āœ— MyStartup (uppercase)\n` + ` āœ— my_startup (underscores)\n` + ` āœ— my.startup (periods)\n` + ` āœ— my startup (spaces)`)
14
+ this.name = 'InvalidStartupNameError'
15
+ }
16
+ }
17
+
18
+ export class NotInMonorepoRootError extends Error {
19
+ constructor() {
20
+ super('Must be run from the monorepo root directory (could not find .launch-monorepo-root.md)')
21
+ this.name = 'NotInMonorepoRootError'
22
+ }
23
+ }
@@ -0,0 +1,11 @@
1
+ // Services
2
+ export { StartupService } from './services/startup-service.js'
3
+
4
+ // Types
5
+ export type { CreateStartupRequest, CreateStartupResult } from './types/startup-types.js'
6
+
7
+ // Errors
8
+ export { StartupAlreadyExistsError, InvalidStartupNameError, NotInMonorepoRootError } from './errors/startup-errors.js'
9
+
10
+ // Command
11
+ export { createStartupCommand } from './commands/create-startup.js'
@@ -0,0 +1,57 @@
1
+ import * as path from 'path'
2
+ import { fileURLToPath } from 'url'
3
+
4
+ import * as filesystem from '../../../infrastructure/filesystem.js'
5
+ import { StartupAlreadyExistsError, NotInMonorepoRootError } from '../errors/startup-errors.js'
6
+ import { validateStartupName } from '../utils/startup-validators.js'
7
+
8
+ import type { MonorepoContext } from '../../../utils/monorepo.js'
9
+ import type { CreateStartupRequest, CreateStartupResult } from '../types/startup-types.js'
10
+
11
+ export class StartupService {
12
+ async createStartup(request: CreateStartupRequest, context: MonorepoContext): Promise<CreateStartupResult> {
13
+ const { name } = request
14
+
15
+ // 1. Validate name
16
+ validateStartupName(name)
17
+
18
+ // 2. Verify we found the monorepo
19
+ if (!context.isValid) {
20
+ throw new NotInMonorepoRootError()
21
+ }
22
+
23
+ // 3. Determine startup path
24
+ const startupsDir = path.join(context.monorepoRoot, 'startups')
25
+ const startupPath = path.join(startupsDir, name)
26
+
27
+ // 4. Check if startup already exists
28
+ if (await filesystem.exists(startupPath)) {
29
+ throw new StartupAlreadyExistsError(name, startupPath)
30
+ }
31
+
32
+ // 5. Ensure startups directory exists
33
+ await filesystem.ensureDir(startupsDir)
34
+
35
+ // 6. Copy template
36
+ const templatePath = this.getTemplatePath()
37
+ await filesystem.copy(templatePath, startupPath)
38
+
39
+ return {
40
+ startupPath,
41
+ name,
42
+ }
43
+ }
44
+
45
+ private getTemplatePath(): string {
46
+ const __filename = fileURLToPath(import.meta.url)
47
+ const __dirname = path.dirname(__filename)
48
+
49
+ // From src/modules/startup/services/ or dist/modules/startup/services/ up to cli root
50
+ const isDev = __filename.includes('/src/')
51
+ const cliRoot = isDev
52
+ ? path.join(__dirname, '../../../..') // src/modules/startup/services -> cli root
53
+ : path.join(__dirname, '../../../..') // dist/modules/startup/services -> cli root
54
+
55
+ return path.join(cliRoot, 'templates/startup')
56
+ }
57
+ }