@tanstack/cta-engine 0.10.0-alpha.21 → 0.10.0-alpha.25

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 (340) hide show
  1. package/dist/add-ons.js +91 -5
  2. package/dist/add.js +125 -0
  3. package/dist/cli.js +132 -0
  4. package/dist/config-file.js +9 -14
  5. package/dist/constants.js +2 -0
  6. package/dist/create-app.js +451 -142
  7. package/dist/custom-add-on.js +254 -0
  8. package/dist/environment.js +32 -64
  9. package/dist/file-helper.js +18 -0
  10. package/dist/index.js +1 -17
  11. package/dist/mcp.js +229 -0
  12. package/dist/options.js +333 -9
  13. package/dist/package-manager.js +6 -51
  14. package/dist/templates.js +6 -0
  15. package/dist/toolchain.js +6 -0
  16. package/dist/types/add-ons.d.ts +8 -3
  17. package/dist/types/add.d.ts +3 -0
  18. package/dist/types/cli.d.ts +7 -0
  19. package/dist/types/config-file.d.ts +4 -6
  20. package/dist/types/constants.d.ts +3 -0
  21. package/dist/types/create-app.d.ts +7 -1
  22. package/dist/types/custom-add-on.d.ts +3 -0
  23. package/dist/types/environment.d.ts +1 -2
  24. package/dist/types/file-helper.d.ts +2 -0
  25. package/dist/types/index.d.ts +1 -20
  26. package/dist/types/mcp.d.ts +7 -0
  27. package/dist/types/options.d.ts +6 -2
  28. package/dist/types/package-manager.d.ts +1 -18
  29. package/dist/types/templates.d.ts +1 -0
  30. package/dist/types/toolchain.d.ts +3 -0
  31. package/dist/types/types.d.ts +85 -788
  32. package/dist/types/utils.d.ts +0 -5
  33. package/dist/types.js +1 -65
  34. package/dist/utils.js +0 -9
  35. package/package.json +12 -9
  36. package/src/add-ons.ts +123 -7
  37. package/src/add.ts +186 -0
  38. package/src/cli.ts +210 -0
  39. package/src/config-file.ts +17 -26
  40. package/src/constants.ts +5 -0
  41. package/src/create-app.ts +730 -180
  42. package/src/custom-add-on.ts +325 -0
  43. package/src/environment.ts +33 -77
  44. package/src/file-helper.ts +20 -0
  45. package/src/index.ts +1 -77
  46. package/src/mcp.ts +302 -0
  47. package/src/options.ts +409 -8
  48. package/src/package-manager.ts +9 -80
  49. package/src/templates.ts +7 -0
  50. package/src/toolchain.ts +7 -0
  51. package/src/types.ts +87 -175
  52. package/src/utils.ts +0 -17
  53. package/templates/react/add-on/clerk/README.md +3 -0
  54. package/templates/react/add-on/clerk/assets/_dot_env.local.append +2 -0
  55. package/templates/react/add-on/clerk/assets/src/integrations/clerk/header-user.tsx +19 -0
  56. package/templates/react/add-on/clerk/assets/src/integrations/clerk/provider.tsx +18 -0
  57. package/templates/react/add-on/clerk/assets/src/routes/demo.clerk.tsx +20 -0
  58. package/templates/react/add-on/clerk/info.json +13 -0
  59. package/templates/react/add-on/clerk/package.json +5 -0
  60. package/templates/react/add-on/convex/README.md +4 -0
  61. package/templates/react/add-on/convex/assets/_dot_cursorrules.append +93 -0
  62. package/templates/react/add-on/convex/assets/_dot_env.local.append +3 -0
  63. package/templates/react/add-on/convex/assets/convex/products.ts +8 -0
  64. package/templates/react/add-on/convex/assets/convex/schema.ts +10 -0
  65. package/templates/react/add-on/convex/assets/src/integrations/convex/provider.tsx +20 -0
  66. package/templates/react/add-on/convex/assets/src/routes/demo.convex.tsx +33 -0
  67. package/templates/react/add-on/convex/info.json +13 -0
  68. package/templates/react/add-on/convex/package.json +6 -0
  69. package/templates/react/add-on/form/assets/src/components/demo.FormComponents.tsx.ejs +300 -0
  70. package/templates/react/add-on/form/assets/src/hooks/demo.form-context.ts +4 -0
  71. package/templates/react/add-on/form/assets/src/hooks/demo.form.ts +22 -0
  72. package/templates/react/add-on/form/assets/src/routes/demo.form.address.tsx.ejs +213 -0
  73. package/templates/react/add-on/form/assets/src/routes/demo.form.simple.tsx.ejs +77 -0
  74. package/templates/react/add-on/form/info.json +26 -0
  75. package/templates/react/add-on/form/package.json +6 -0
  76. package/templates/react/add-on/module-federation/assets/module-federation.config.js.ejs +31 -0
  77. package/templates/react/add-on/module-federation/assets/src/demo-mf-component.tsx +3 -0
  78. package/templates/react/add-on/module-federation/assets/src/demo-mf-self-contained.tsx +11 -0
  79. package/templates/react/add-on/module-federation/info.json +7 -0
  80. package/templates/react/add-on/module-federation/package.json +5 -0
  81. package/templates/react/add-on/netlify/README.md +11 -0
  82. package/templates/react/add-on/netlify/info.json +7 -0
  83. package/templates/react/add-on/sentry/assets/_dot_cursorrules.append +22 -0
  84. package/templates/react/add-on/sentry/assets/_dot_env.local.append +11 -0
  85. package/templates/react/add-on/sentry/assets/src/app/global-middleware.ts +11 -0
  86. package/templates/react/add-on/sentry/assets/src/routes/demo.sentry.testing.tsx +489 -0
  87. package/templates/react/add-on/sentry/info.json +14 -0
  88. package/templates/react/add-on/sentry/package.json +5 -0
  89. package/templates/react/add-on/shadcn/README.md +7 -0
  90. package/templates/react/add-on/shadcn/assets/_dot_cursorrules.append +7 -0
  91. package/templates/react/add-on/shadcn/assets/components.json +21 -0
  92. package/templates/react/add-on/shadcn/assets/src/lib/utils.ts +6 -0
  93. package/templates/react/add-on/shadcn/assets/src/styles.css +138 -0
  94. package/templates/react/add-on/shadcn/info.json +7 -0
  95. package/templates/react/add-on/shadcn/package.json +9 -0
  96. package/templates/react/add-on/start/assets/_dot_gitignore.append +2 -0
  97. package/templates/react/add-on/start/assets/app.config.ts.ejs +32 -0
  98. package/templates/react/add-on/start/assets/src/api.ts +6 -0
  99. package/templates/react/add-on/start/assets/src/client.tsx.ejs +33 -0
  100. package/templates/react/add-on/start/assets/src/router.tsx.ejs +48 -0
  101. package/templates/react/add-on/start/assets/src/routes/api.demo-names.ts +11 -0
  102. package/templates/react/add-on/start/assets/src/routes/demo.start.api-request.tsx.ejs +33 -0
  103. package/templates/react/add-on/start/assets/src/routes/demo.start.server-funcs.tsx +50 -0
  104. package/templates/react/add-on/start/assets/src/ssr.tsx.ejs +30 -0
  105. package/templates/react/add-on/start/info.json +18 -0
  106. package/templates/react/add-on/start/package.json +13 -0
  107. package/templates/react/add-on/store/assets/src/lib/demo-store.ts +13 -0
  108. package/templates/react/add-on/store/assets/src/routes/demo.store.tsx.ejs +75 -0
  109. package/templates/react/add-on/store/info.json +13 -0
  110. package/templates/react/add-on/store/package.json +6 -0
  111. package/templates/react/add-on/t3env/README.md +16 -0
  112. package/templates/react/add-on/t3env/assets/src/env.ts +39 -0
  113. package/templates/react/add-on/t3env/info.json +10 -0
  114. package/templates/react/add-on/t3env/package.json +6 -0
  115. package/templates/react/add-on/tRPC/assets/src/integrations/trpc/init.ts +9 -0
  116. package/templates/react/add-on/tRPC/assets/src/integrations/trpc/react.ts +4 -0
  117. package/templates/react/add-on/tRPC/assets/src/integrations/trpc/router.ts +18 -0
  118. package/templates/react/add-on/tRPC/assets/src/routes/api.trpc.$.tsx +16 -0
  119. package/templates/react/add-on/tRPC/info.json +9 -0
  120. package/templates/react/add-on/tRPC/package.json +9 -0
  121. package/templates/react/add-on/table/assets/src/data/demo-table-data.ts +50 -0
  122. package/templates/react/add-on/table/assets/src/routes/demo.table.tsx.ejs +373 -0
  123. package/templates/react/add-on/table/info.json +13 -0
  124. package/templates/react/add-on/table/package.json +7 -0
  125. package/templates/react/add-on/tanstack-query/assets/src/integrations/tanstack-query/layout.tsx +5 -0
  126. package/templates/react/add-on/tanstack-query/assets/src/integrations/tanstack-query/root-provider.tsx.ejs +70 -0
  127. package/templates/react/add-on/tanstack-query/assets/src/routes/demo.tanstack-query.tsx.ejs +53 -0
  128. package/templates/react/add-on/tanstack-query/info.json +13 -0
  129. package/templates/react/add-on/tanstack-query/package.json +6 -0
  130. package/templates/react/base/README.md.ejs +558 -0
  131. package/templates/react/base/_dot_gitignore +5 -0
  132. package/templates/react/base/_dot_vscode/settings.biome.json +35 -0
  133. package/templates/react/base/_dot_vscode/settings.json +11 -0
  134. package/templates/react/base/index.html.ejs +20 -0
  135. package/templates/react/base/package.biome.json +10 -0
  136. package/templates/react/base/package.eslintprettier.json +11 -0
  137. package/templates/react/base/package.json +30 -0
  138. package/templates/react/base/package.ts.json +7 -0
  139. package/templates/react/base/package.tw.json +6 -0
  140. package/templates/react/base/public/favicon.ico +0 -0
  141. package/templates/react/base/public/logo192.png +0 -0
  142. package/templates/react/base/public/logo512.png +0 -0
  143. package/templates/react/base/public/manifest.json +25 -0
  144. package/templates/react/base/public/robots.txt +3 -0
  145. package/templates/react/base/src/App.css +38 -0
  146. package/templates/react/base/src/App.test.tsx.ejs +10 -0
  147. package/templates/react/base/src/App.tsx.ejs +74 -0
  148. package/templates/react/base/src/components/Header.tsx.ejs +27 -0
  149. package/templates/react/base/src/logo.svg +44 -0
  150. package/templates/react/base/src/reportWebVitals.ts.ejs +28 -0
  151. package/templates/react/base/src/styles.css.ejs +15 -0
  152. package/templates/react/base/toolchain/.prettierignore +3 -0
  153. package/templates/react/base/toolchain/biome.json +31 -0
  154. package/templates/react/base/toolchain/eslint.config.js +5 -0
  155. package/templates/react/base/toolchain/prettier.config.js +10 -0
  156. package/templates/react/base/tsconfig.json.ejs +29 -0
  157. package/templates/react/base/vite.config.js.ejs +23 -0
  158. package/templates/react/code-router/src/main.tsx.ejs +92 -0
  159. package/templates/react/example/tanchat/README.md +37 -0
  160. package/templates/react/example/tanchat/assets/_dot_env.local.append +2 -0
  161. package/templates/react/example/tanchat/assets/public/example-guitar-flowers.jpg +0 -0
  162. package/templates/react/example/tanchat/assets/public/example-guitar-motherboard.jpg +0 -0
  163. package/templates/react/example/tanchat/assets/public/example-guitar-racing.jpg +0 -0
  164. package/templates/react/example/tanchat/assets/public/example-guitar-steamer-trunk.jpg +0 -0
  165. package/templates/react/example/tanchat/assets/public/example-guitar-superhero.jpg +0 -0
  166. package/templates/react/example/tanchat/assets/public/example-guitar-traveling.jpg +0 -0
  167. package/templates/react/example/tanchat/assets/public/example-guitar-video-games.jpg +0 -0
  168. package/templates/react/example/tanchat/assets/src/components/example-AIAssistant.tsx +173 -0
  169. package/templates/react/example/tanchat/assets/src/components/example-GuitarRecommendation.tsx +47 -0
  170. package/templates/react/example/tanchat/assets/src/data/example-guitars.ts +83 -0
  171. package/templates/react/example/tanchat/assets/src/demo.index.css +220 -0
  172. package/templates/react/example/tanchat/assets/src/integrations/tanchat/header-user.tsx +5 -0
  173. package/templates/react/example/tanchat/assets/src/routes/api.messages.ts +24 -0
  174. package/templates/react/example/tanchat/assets/src/routes/api.sse.ts +23 -0
  175. package/templates/react/example/tanchat/assets/src/routes/example.chat.tsx +159 -0
  176. package/templates/react/example/tanchat/assets/src/routes/example.guitars/$guitarId.tsx +50 -0
  177. package/templates/react/example/tanchat/assets/src/routes/example.guitars/index.tsx +54 -0
  178. package/templates/react/example/tanchat/assets/src/store/example-assistant.ts +3 -0
  179. package/templates/react/example/tanchat/assets/src/utils/demo.ai.ts +62 -0
  180. package/templates/react/example/tanchat/assets/src/utils/demo.sse.ts +31 -0
  181. package/templates/react/example/tanchat/assets/src/utils/demo.tools.ts +47 -0
  182. package/templates/react/example/tanchat/info.json +19 -0
  183. package/templates/react/example/tanchat/package.json +16 -0
  184. package/templates/react/file-router/package.fr.json +5 -0
  185. package/templates/react/file-router/src/main.tsx.ejs +55 -0
  186. package/templates/react/file-router/src/routes/__root.tsx.ejs +82 -0
  187. package/templates/solid/add-on/form/assets/src/routes/demo.form.tsx.ejs +352 -0
  188. package/templates/solid/add-on/form/info.json +13 -0
  189. package/templates/solid/add-on/form/package.json +5 -0
  190. package/templates/solid/add-on/module-federation/assets/module-federation.config.js.ejs +27 -0
  191. package/templates/solid/add-on/module-federation/assets/src/demo-mf-component.tsx +3 -0
  192. package/templates/solid/add-on/module-federation/assets/src/demo-mf-self-contained.tsx +9 -0
  193. package/templates/solid/add-on/module-federation/info.json +7 -0
  194. package/templates/solid/add-on/module-federation/package.json +5 -0
  195. package/templates/solid/add-on/sentry/assets/_dot_cursorrules.append +22 -0
  196. package/templates/solid/add-on/sentry/assets/_dot_env.local.append +2 -0
  197. package/templates/solid/add-on/sentry/assets/src/routes/demo.sentry.bad-event-handler.tsx +20 -0
  198. package/templates/solid/add-on/sentry/info.json +13 -0
  199. package/templates/solid/add-on/sentry/package.json +5 -0
  200. package/templates/solid/add-on/solid-ui/README.md +9 -0
  201. package/templates/solid/add-on/solid-ui/assets/src/lib/utils.ts +6 -0
  202. package/templates/solid/add-on/solid-ui/assets/src/styles.css +138 -0
  203. package/templates/solid/add-on/solid-ui/assets/ui.config.json +13 -0
  204. package/templates/solid/add-on/solid-ui/info.json +11 -0
  205. package/templates/solid/add-on/solid-ui/package.json +9 -0
  206. package/templates/solid/add-on/start/assets/app.config.ts +16 -0
  207. package/templates/solid/add-on/start/assets/src/api.ts +6 -0
  208. package/templates/solid/add-on/start/assets/src/client.tsx +7 -0
  209. package/templates/solid/add-on/start/assets/src/router.tsx.ejs +24 -0
  210. package/templates/solid/add-on/start/assets/src/routes/demo.start.server-funcs.tsx +49 -0
  211. package/templates/solid/add-on/start/assets/src/ssr.tsx +12 -0
  212. package/templates/solid/add-on/start/info.json +14 -0
  213. package/templates/solid/add-on/start/package.json +12 -0
  214. package/templates/solid/add-on/store/assets/src/lib/demo-store.ts +13 -0
  215. package/templates/solid/add-on/store/assets/src/routes/demo.store.tsx.ejs +77 -0
  216. package/templates/solid/add-on/store/info.json +13 -0
  217. package/templates/solid/add-on/store/package.json +6 -0
  218. package/templates/solid/add-on/t3env/README.md +16 -0
  219. package/templates/solid/add-on/t3env/assets/src/env.ts +39 -0
  220. package/templates/solid/add-on/t3env/info.json +10 -0
  221. package/templates/solid/add-on/t3env/package.json +6 -0
  222. package/templates/solid/add-on/tanstack-query/assets/src/integrations/tanstack-query/header-user.tsx +5 -0
  223. package/templates/solid/add-on/tanstack-query/assets/src/integrations/tanstack-query/provider.tsx +15 -0
  224. package/templates/solid/add-on/tanstack-query/assets/src/routes/demo.tanstack-query.tsx +30 -0
  225. package/templates/solid/add-on/tanstack-query/info.json +13 -0
  226. package/templates/solid/add-on/tanstack-query/package.json +6 -0
  227. package/templates/solid/base/README.md.ejs +215 -0
  228. package/templates/solid/base/_dot_cursorrules.append +35 -0
  229. package/templates/solid/base/_dot_gitignore +5 -0
  230. package/templates/solid/base/_dot_vscode/settings.biome.json +35 -0
  231. package/templates/solid/base/_dot_vscode/settings.json +11 -0
  232. package/templates/solid/base/index.html.ejs +20 -0
  233. package/templates/solid/base/package.biome.json +10 -0
  234. package/templates/solid/base/package.eslintprettier.json +11 -0
  235. package/templates/solid/base/package.json +23 -0
  236. package/templates/solid/base/package.ts.json +5 -0
  237. package/templates/solid/base/package.tw.json +6 -0
  238. package/templates/solid/base/public/favicon.ico +0 -0
  239. package/templates/solid/base/public/logo192.png +0 -0
  240. package/templates/solid/base/public/logo512.png +0 -0
  241. package/templates/solid/base/public/manifest.json +25 -0
  242. package/templates/solid/base/public/robots.txt +3 -0
  243. package/templates/solid/base/src/App.css +0 -0
  244. package/templates/solid/base/src/App.tsx.ejs +47 -0
  245. package/templates/solid/base/src/components/Header.tsx.ejs +26 -0
  246. package/templates/solid/base/src/logo.svg +120 -0
  247. package/templates/solid/base/src/styles.css.ejs +15 -0
  248. package/templates/solid/base/toolchain/.prettierignore +3 -0
  249. package/templates/solid/base/toolchain/biome.json +31 -0
  250. package/templates/solid/base/toolchain/eslint.config.js +5 -0
  251. package/templates/solid/base/toolchain/prettier.config.js +10 -0
  252. package/templates/solid/base/tsconfig.json.ejs +31 -0
  253. package/templates/solid/base/vite.config.js.ejs +22 -0
  254. package/templates/solid/code-router/src/main.tsx.ejs +71 -0
  255. package/templates/solid/example/tanchat/README.md +52 -0
  256. package/templates/solid/example/tanchat/assets/ai-streaming-server/README.md +110 -0
  257. package/templates/solid/example/tanchat/assets/ai-streaming-server/_dot_env.example +1 -0
  258. package/templates/solid/example/tanchat/assets/ai-streaming-server/package.json +26 -0
  259. package/templates/solid/example/tanchat/assets/ai-streaming-server/src/index.ts +102 -0
  260. package/templates/solid/example/tanchat/assets/ai-streaming-server/tsconfig.json +15 -0
  261. package/templates/solid/example/tanchat/assets/src/components/demo.SettingsDialog.tsx +149 -0
  262. package/templates/solid/example/tanchat/assets/src/demo.index.css +227 -0
  263. package/templates/solid/example/tanchat/assets/src/lib/demo-store.ts +13 -0
  264. package/templates/solid/example/tanchat/assets/src/routes/example.chat.tsx +435 -0
  265. package/templates/solid/example/tanchat/assets/src/store/demo.hooks.ts +17 -0
  266. package/templates/solid/example/tanchat/assets/src/store/demo.store.ts +133 -0
  267. package/templates/solid/example/tanchat/info.json +14 -0
  268. package/templates/solid/example/tanchat/package.json +7 -0
  269. package/templates/solid/file-router/package.fr.json +5 -0
  270. package/templates/solid/file-router/src/main.tsx.ejs +47 -0
  271. package/templates/solid/file-router/src/routes/__root.tsx.ejs +41 -0
  272. package/templates/solid/file-router/src/routes/index.tsx +43 -0
  273. package/tests/cra.test.ts +293 -0
  274. package/tests/snapshots/cra/cr-js-npm.json +33 -0
  275. package/tests/snapshots/cra/cr-ts-npm.json +34 -0
  276. package/tests/snapshots/cra/cr-ts-start-npm.json +38 -0
  277. package/tests/snapshots/cra/fr-ts-npm.json +34 -0
  278. package/tests/snapshots/cra/fr-ts-tw-npm.json +33 -0
  279. package/tests/snapshots/cra/solid-cr-js-npm.json +31 -0
  280. package/tests/snapshots/cra/solid-cr-ts-npm.json +32 -0
  281. package/tests/snapshots/cra/solid-cr-ts-start-npm.json +36 -0
  282. package/tests/snapshots/cra/solid-fr-ts-npm.json +33 -0
  283. package/tests/snapshots/cra/solid-fr-ts-tw-npm.json +32 -0
  284. package/tests/test-utilities.ts +87 -0
  285. package/dist/add-to-app.js +0 -169
  286. package/dist/custom-add-ons/add-on.js +0 -175
  287. package/dist/custom-add-ons/shared.js +0 -117
  288. package/dist/custom-add-ons/starter.js +0 -84
  289. package/dist/file-helpers.js +0 -165
  290. package/dist/frameworks.js +0 -92
  291. package/dist/integrations/git.js +0 -4
  292. package/dist/integrations/shadcn.js +0 -33
  293. package/dist/package-json.js +0 -48
  294. package/dist/special-steps/index.js +0 -24
  295. package/dist/special-steps/rimraf-node-modules.js +0 -16
  296. package/dist/template-file.js +0 -112
  297. package/dist/types/add-to-app.d.ts +0 -17
  298. package/dist/types/custom-add-ons/add-on.d.ts +0 -69
  299. package/dist/types/custom-add-ons/shared.d.ts +0 -15
  300. package/dist/types/custom-add-ons/starter.d.ts +0 -7
  301. package/dist/types/file-helpers.d.ts +0 -15
  302. package/dist/types/frameworks.d.ts +0 -7
  303. package/dist/types/integrations/git.d.ts +0 -2
  304. package/dist/types/integrations/shadcn.d.ts +0 -2
  305. package/dist/types/package-json.d.ts +0 -7
  306. package/dist/types/special-steps/index.d.ts +0 -2
  307. package/dist/types/special-steps/rimraf-node-modules.d.ts +0 -2
  308. package/dist/types/template-file.d.ts +0 -2
  309. package/src/add-to-app.ts +0 -274
  310. package/src/custom-add-ons/add-on.ts +0 -261
  311. package/src/custom-add-ons/shared.ts +0 -161
  312. package/src/custom-add-ons/starter.ts +0 -126
  313. package/src/file-helpers.ts +0 -235
  314. package/src/frameworks.ts +0 -134
  315. package/src/integrations/git.ts +0 -7
  316. package/src/integrations/shadcn.ts +0 -54
  317. package/src/package-json.ts +0 -69
  318. package/src/special-steps/index.ts +0 -36
  319. package/src/special-steps/rimraf-node-modules.ts +0 -25
  320. package/src/template-file.ts +0 -150
  321. package/tests/add-ons.test.ts +0 -67
  322. package/tests/add-to-app.test.ts +0 -358
  323. package/tests/config-file.test.ts +0 -68
  324. package/tests/create-app.test.ts +0 -120
  325. package/tests/custom-add-ons/add-on.test.ts +0 -12
  326. package/tests/custom-add-ons/shared.test.ts +0 -257
  327. package/tests/custom-add-ons/starter.test.ts +0 -58
  328. package/tests/environment.test.ts +0 -115
  329. package/tests/file-helper.test.ts +0 -90
  330. package/tests/frameworks.test.ts +0 -95
  331. package/tests/index.test.ts +0 -9
  332. package/tests/integrations/git.test.ts +0 -20
  333. package/tests/integrations/shadcn.test.ts +0 -91
  334. package/tests/options.test.ts +0 -42
  335. package/tests/package-json.test.ts +0 -63
  336. package/tests/package-manager.test.ts +0 -154
  337. package/tests/setupVitest.ts +0 -6
  338. package/tests/template-file.test.ts +0 -178
  339. package/tests/utils.test.ts +0 -23
  340. package/vitest.config.ts +0 -21
@@ -1,6 +1 @@
1
1
  export declare function sortObject(obj: Record<string, string>): Record<string, string>;
2
- export declare function jsSafeName(name: string): string;
3
- export declare function formatCommand({ command, args, }: {
4
- command: string;
5
- args: Array<string>;
6
- }): string;
package/dist/types.js CHANGED
@@ -1,65 +1 @@
1
- import z from 'zod';
2
- export const AddOnBaseSchema = z.object({
3
- id: z.string(),
4
- name: z.string(),
5
- description: z.string(),
6
- author: z.string().optional(),
7
- version: z.string().optional(),
8
- link: z.string().optional(),
9
- license: z.string().optional(),
10
- warning: z.string().optional(),
11
- type: z.enum(['add-on', 'example', 'starter', 'toolchain']),
12
- command: z
13
- .object({
14
- command: z.string(),
15
- args: z.array(z.string()).optional(),
16
- })
17
- .optional(),
18
- routes: z
19
- .array(z.object({
20
- url: z.string().optional(),
21
- name: z.string().optional(),
22
- path: z.string(),
23
- jsName: z.string(),
24
- }))
25
- .optional(),
26
- packageAdditions: z
27
- .object({
28
- dependencies: z.record(z.string(), z.string()).optional(),
29
- devDependencies: z.record(z.string(), z.string()).optional(),
30
- scripts: z.record(z.string(), z.string()).optional(),
31
- })
32
- .optional(),
33
- shadcnComponents: z.array(z.string()).optional(),
34
- dependsOn: z.array(z.string()).optional(),
35
- smallLogo: z.string().optional(),
36
- logo: z.string().optional(),
37
- addOnSpecialSteps: z.array(z.string()).optional(),
38
- createSpecialSteps: z.array(z.string()).optional(),
39
- });
40
- export const StarterSchema = AddOnBaseSchema.extend({
41
- framework: z.string(),
42
- mode: z.string(),
43
- typescript: z.boolean(),
44
- tailwind: z.boolean(),
45
- banner: z.string().optional(),
46
- });
47
- export const StarterCompiledSchema = StarterSchema.extend({
48
- files: z.record(z.string(), z.string()),
49
- deletedFiles: z.array(z.string()),
50
- });
51
- export const IntegrationSchema = z.object({
52
- type: z.string(),
53
- path: z.string(),
54
- jsName: z.string(),
55
- });
56
- export const AddOnInfoSchema = AddOnBaseSchema.extend({
57
- modes: z.array(z.string()),
58
- integrations: z.array(IntegrationSchema).optional(),
59
- phase: z.enum(['setup', 'add-on']),
60
- readme: z.string().optional(),
61
- });
62
- export const AddOnCompiledSchema = AddOnInfoSchema.extend({
63
- files: z.record(z.string(), z.string()),
64
- deletedFiles: z.array(z.string()),
65
- });
1
+ export {};
package/dist/utils.js CHANGED
@@ -6,12 +6,3 @@ export function sortObject(obj) {
6
6
  return acc;
7
7
  }, {});
8
8
  }
9
- export function jsSafeName(name) {
10
- return name
11
- .split(/[^a-zA-Z0-9]/)
12
- .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
13
- .join('');
14
- }
15
- export function formatCommand({ command, args, }) {
16
- return `${command} ${args.join(' ')}`.trim();
17
- }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/cta-engine",
3
- "version": "0.10.0-alpha.21",
3
+ "version": "0.10.0-alpha.25",
4
4
  "description": "Tanstack Application Builder Engine",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -15,32 +15,35 @@
15
15
  "url": "https://github.com/sponsors/tannerlinsley"
16
16
  },
17
17
  "keywords": [
18
+ "react",
18
19
  "tanstack",
19
20
  "router",
20
- "create-tsrouter-app"
21
+ "create-react-app"
21
22
  ],
22
23
  "author": "Jack Herrington <jherr@pobox.com>",
23
24
  "license": "MIT",
24
25
  "dependencies": {
26
+ "@clack/prompts": "^0.10.0",
27
+ "@modelcontextprotocol/sdk": "^1.6.0",
28
+ "chalk": "^5.4.1",
29
+ "commander": "^13.1.0",
25
30
  "ejs": "^3.1.10",
26
31
  "execa": "^9.5.2",
27
- "ignore": "^7.0.3",
32
+ "express": "^4.21.2",
28
33
  "memfs": "^4.17.0",
29
- "parse-gitignore": "^2.0.0",
30
34
  "prettier": "^3.5.0",
31
- "rimraf": "^6.0.1",
32
35
  "zod": "^3.24.2"
33
36
  },
34
37
  "devDependencies": {
35
38
  "@tanstack/config": "^0.16.2",
36
39
  "@types/ejs": "^3.1.5",
40
+ "@types/express": "^5.0.0",
37
41
  "@types/node": "^22.13.4",
38
- "@types/parse-gitignore": "^1.0.2",
39
- "@vitest/coverage-v8": "3.1.1",
40
42
  "eslint": "^9.20.0",
43
+ "eslint-plugin-react-hooks": "^5.1.0",
44
+ "eslint-plugin-unused-imports": "^4.1.4",
41
45
  "typescript": "^5.6.3",
42
- "vitest": "^3.0.8",
43
- "vitest-fetch-mock": "^0.4.5"
46
+ "vitest": "^3.0.8"
44
47
  },
45
48
  "scripts": {}
46
49
  }
package/src/add-ons.ts CHANGED
@@ -1,20 +1,100 @@
1
- import { loadRemoteAddOn } from './custom-add-ons/add-on.js'
1
+ import { readFile } from 'node:fs/promises'
2
+ import { existsSync, readdirSync, statSync } from 'node:fs'
3
+ import { resolve } from 'node:path'
4
+ import chalk from 'chalk'
2
5
 
3
- import type { AddOn, Framework, Mode } from './types.js'
6
+ import { getTemplatesRoot } from './templates.js'
7
+ import { DEFAULT_FRAMEWORK } from './constants.js'
8
+ import { readFileHelper } from './file-helper.js'
4
9
 
5
- export function getAllAddOns(framework: Framework, mode: Mode): Array<AddOn> {
6
- return framework.getAddOns().filter((a) => a.modes.includes(mode))
10
+ import type { AddOn, CliOptions, Framework, TemplateOptions } from './types.js'
11
+
12
+ function isDirectory(path: string): boolean {
13
+ return statSync(path).isDirectory()
14
+ }
15
+
16
+ function findFilesRecursively(path: string, files: Record<string, string>) {
17
+ const dirFiles = readdirSync(path)
18
+ for (const file of dirFiles) {
19
+ const filePath = resolve(path, file)
20
+ if (isDirectory(filePath)) {
21
+ findFilesRecursively(filePath, files)
22
+ } else {
23
+ files[filePath] = readFileHelper(filePath)
24
+ }
25
+ }
26
+ }
27
+
28
+ export async function getAllAddOns(
29
+ framework: Framework,
30
+ template: string,
31
+ ): Promise<Array<AddOn>> {
32
+ const addOns: Array<AddOn> = []
33
+
34
+ for (const type of ['add-on', 'example']) {
35
+ const addOnsBase = resolve(getTemplatesRoot(), framework, type)
36
+
37
+ if (!existsSync(addOnsBase)) {
38
+ continue
39
+ }
40
+
41
+ for (const dir of await readdirSync(addOnsBase).filter((file) =>
42
+ isDirectory(resolve(addOnsBase, file)),
43
+ )) {
44
+ const filePath = resolve(addOnsBase, dir, 'info.json')
45
+ const fileContent = await readFile(filePath, 'utf-8')
46
+ const info = JSON.parse(fileContent)
47
+
48
+ if (!info.templates.includes(template)) {
49
+ continue
50
+ }
51
+
52
+ let packageAdditions: Record<string, string> = {}
53
+ if (existsSync(resolve(addOnsBase, dir, 'package.json'))) {
54
+ packageAdditions = JSON.parse(
55
+ await readFile(resolve(addOnsBase, dir, 'package.json'), 'utf-8'),
56
+ )
57
+ }
58
+
59
+ let readme: string | undefined
60
+ if (existsSync(resolve(addOnsBase, dir, 'README.md'))) {
61
+ readme = await readFile(resolve(addOnsBase, dir, 'README.md'), 'utf-8')
62
+ }
63
+
64
+ const absoluteFiles: Record<string, string> = {}
65
+ const assetsDir = resolve(addOnsBase, dir, 'assets')
66
+ if (existsSync(assetsDir)) {
67
+ await findFilesRecursively(assetsDir, absoluteFiles)
68
+ }
69
+ const files: Record<string, string> = {}
70
+ for (const file of Object.keys(absoluteFiles)) {
71
+ files[file.replace(assetsDir, '.')] = absoluteFiles[file]
72
+ }
73
+
74
+ addOns.push({
75
+ ...info,
76
+ id: dir,
77
+ type,
78
+ packageAdditions,
79
+ readme,
80
+ files,
81
+ deletedFiles: [],
82
+ })
83
+ }
84
+ }
85
+
86
+ return addOns
7
87
  }
8
88
 
9
89
  // Turn the list of chosen add-on IDs into a final list of add-ons by resolving dependencies
10
90
  export async function finalizeAddOns(
11
91
  framework: Framework,
12
- mode: Mode,
92
+ template: string,
13
93
  chosenAddOnIDs: Array<string>,
14
94
  ): Promise<Array<AddOn>> {
15
95
  const finalAddOnIDs = new Set(chosenAddOnIDs)
16
96
 
17
- const addOns = getAllAddOns(framework, mode)
97
+ const addOns = await getAllAddOns(framework, template)
18
98
 
19
99
  for (const addOnID of finalAddOnIDs) {
20
100
  let addOn: AddOn | undefined
@@ -40,10 +120,46 @@ export async function finalizeAddOns(
40
120
  const finalAddOns = [...finalAddOnIDs].map(
41
121
  (id) => addOns.find((a) => a.id === id)!,
42
122
  )
43
-
44
123
  return finalAddOns
45
124
  }
46
125
 
126
+ export async function listAddOns(
127
+ options: CliOptions,
128
+ {
129
+ forcedMode,
130
+ forcedAddOns = [],
131
+ }: {
132
+ forcedMode?: TemplateOptions
133
+ forcedAddOns?: Array<string>
134
+ },
135
+ ) {
136
+ let mode = forcedMode
137
+ if (!mode) {
138
+ if (options.template) {
139
+ mode =
140
+ options.template === 'file-router'
141
+ ? 'file-router'
142
+ : ('code-router' as TemplateOptions)
143
+ } else {
144
+ mode = 'code-router' as TemplateOptions
145
+ }
146
+ }
147
+ const addOns = await getAllAddOns(
148
+ options.framework || DEFAULT_FRAMEWORK,
149
+ mode,
150
+ )
151
+ for (const addOn of addOns.filter((a) => !forcedAddOns.includes(a.id))) {
152
+ console.log(`${chalk.bold(addOn.id)}: ${addOn.description}`)
153
+ }
154
+ }
155
+
47
156
  function loadAddOn(addOn: AddOn): AddOn {
48
157
  return addOn
49
158
  }
159
+
160
+ export async function loadRemoteAddOn(url: string): Promise<AddOn> {
161
+ const response = await fetch(url)
162
+ const fileContent = await response.json()
163
+ fileContent.id = url
164
+ return fileContent
165
+ }
package/src/add.ts ADDED
@@ -0,0 +1,186 @@
1
+ import { mkdir, readFile, writeFile } from 'node:fs/promises'
2
+ import { existsSync, statSync } from 'node:fs'
3
+ import { basename, dirname, resolve } from 'node:path'
4
+ import chalk from 'chalk'
5
+ import { execa, execaSync } from 'execa'
6
+ import {
7
+ cancel,
8
+ confirm,
9
+ intro,
10
+ isCancel,
11
+ log,
12
+ outro,
13
+ spinner,
14
+ } from '@clack/prompts'
15
+
16
+ import { CONFIG_FILE } from './constants.js'
17
+ import {
18
+ createDefaultEnvironment,
19
+ createMemoryEnvironment,
20
+ } from './environment.js'
21
+ import { createApp } from './create-app.js'
22
+ import { finalizeAddOns } from './add-ons.js'
23
+ import { sortObject } from './utils.js'
24
+ import { readConfigFile, writeConfigFile } from './config-file.js'
25
+
26
+ import type { PersistedOptions } from './config-file.js'
27
+
28
+ import type { Framework, Options } from './types.js'
29
+
30
+ function isDirectory(path: string) {
31
+ return statSync(path).isDirectory()
32
+ }
33
+
34
+ async function hasPendingGitChanges() {
35
+ const status = await execaSync('git', ['status', '--porcelain'])
36
+ return status.stdout.length > 0
37
+ }
38
+
39
+ async function createOptions(
40
+ json: PersistedOptions,
41
+ addOns: Array<string>,
42
+ ): Promise<Required<Options>> {
43
+ return {
44
+ ...json,
45
+ tailwind: true,
46
+ chosenAddOns: await finalizeAddOns(
47
+ json.framework as Framework,
48
+ json.mode as string,
49
+ [...json.existingAddOns, ...addOns],
50
+ ),
51
+ } as Required<Options>
52
+ }
53
+
54
+ async function runCreateApp(options: Required<Options>) {
55
+ const { environment, output } = createMemoryEnvironment()
56
+ await createApp(options, {
57
+ silent: true,
58
+ environment,
59
+ cwd: process.cwd(),
60
+ name: 'create-tsrouter-app',
61
+ })
62
+ return output
63
+ }
64
+
65
+ export async function add(
66
+ addOns: Array<string>,
67
+ {
68
+ silent = false,
69
+ }: {
70
+ silent?: boolean
71
+ } = {},
72
+ ) {
73
+ const persistedOptions = await readConfigFile(process.cwd())
74
+ if (!persistedOptions) {
75
+ console.error(`${chalk.red('There is no .cta.json file in your project.')}
76
+
77
+ This is probably because this was created with an older version of create-tsrouter-app.`)
78
+ return
79
+ }
80
+
81
+ if (!silent) {
82
+ intro(`Adding ${addOns.join(', ')} to the project...`)
83
+ }
84
+
85
+ if (await hasPendingGitChanges()) {
86
+ log.error(
87
+ `${chalk.red('You have pending git changes.')} Please commit or stash them before adding add-ons.`,
88
+ )
89
+ return
90
+ }
91
+
92
+ const newOptions = await createOptions(persistedOptions, addOns)
93
+
94
+ const output = await runCreateApp(newOptions)
95
+
96
+ const overwrittenFiles: Array<string> = []
97
+ const changedFiles: Array<string> = []
98
+ const contentMap = new Map<string, string>()
99
+ for (const file of Object.keys(output.files)) {
100
+ const relativeFile = file.replace(process.cwd(), '')
101
+ if (existsSync(file)) {
102
+ if (!isDirectory(file)) {
103
+ const contents = (await readFile(file)).toString()
104
+ if (
105
+ ['package.json', CONFIG_FILE].includes(basename(file)) ||
106
+ contents !== output.files[file]
107
+ ) {
108
+ overwrittenFiles.push(relativeFile)
109
+ contentMap.set(relativeFile, output.files[file])
110
+ }
111
+ }
112
+ } else {
113
+ changedFiles.push(relativeFile)
114
+ contentMap.set(relativeFile, output.files[file])
115
+ }
116
+ }
117
+
118
+ if (overwrittenFiles.length > 0 && !silent) {
119
+ log.warn(
120
+ `${chalk.yellow('The following will be overwritten:')}\n${overwrittenFiles.join('\n')}`,
121
+ )
122
+ const shouldContinue = await confirm({
123
+ message: 'Do you want to continue?',
124
+ })
125
+ if (isCancel(shouldContinue)) {
126
+ cancel('Operation cancelled.')
127
+ process.exit(0)
128
+ }
129
+ }
130
+
131
+ for (const file of [...changedFiles, ...overwrittenFiles]) {
132
+ const targetFile = `.${file}`
133
+ const fName = basename(file)
134
+ const contents = contentMap.get(file)!
135
+ if (fName === 'package.json') {
136
+ const currentJson = JSON.parse(
137
+ (await readFile(resolve(fName), 'utf-8')).toString(),
138
+ )
139
+ const newJson = JSON.parse(contents)
140
+
141
+ currentJson.scripts = newJson.scripts
142
+ currentJson.dependencies = sortObject({
143
+ ...currentJson.dependencies,
144
+ ...newJson.dependencies,
145
+ })
146
+ currentJson.devDependencies = sortObject({
147
+ ...currentJson.devDependencies,
148
+ ...newJson.devDependencies,
149
+ })
150
+
151
+ await writeFile(targetFile, JSON.stringify(currentJson, null, 2))
152
+ } else if (fName !== CONFIG_FILE) {
153
+ await mkdir(resolve(dirname(targetFile)), { recursive: true })
154
+ await writeFile(resolve(targetFile), contents)
155
+ }
156
+ }
157
+
158
+ // Handle commands
159
+ const originalOutput = await runCreateApp(
160
+ await createOptions(persistedOptions, []),
161
+ )
162
+ const originalCommands = new Set(
163
+ originalOutput.commands.map((c) => [c.command, ...c.args].join(' ')),
164
+ )
165
+ for (const command of output.commands) {
166
+ const commandString = [command.command, ...command.args].join(' ')
167
+ if (!originalCommands.has(commandString)) {
168
+ await execa(command.command, command.args)
169
+ }
170
+ }
171
+ const realEnvironment = createDefaultEnvironment()
172
+ writeConfigFile(realEnvironment, process.cwd(), newOptions)
173
+
174
+ const s = silent ? null : spinner()
175
+ s?.start(`Installing dependencies via ${newOptions.packageManager}...`)
176
+ await realEnvironment.execute(
177
+ newOptions.packageManager,
178
+ ['install'],
179
+ resolve(process.cwd()),
180
+ )
181
+ s?.stop(`Installed dependencies`)
182
+
183
+ if (!silent) {
184
+ outro('Add-ons added successfully!')
185
+ }
186
+ }
package/src/cli.ts ADDED
@@ -0,0 +1,210 @@
1
+ import { Command, InvalidArgumentError } from 'commander'
2
+ import { intro, log } from '@clack/prompts'
3
+
4
+ import { createApp } from './create-app.js'
5
+ import { normalizeOptions, promptForOptions } from './options.js'
6
+ import { SUPPORTED_PACKAGE_MANAGERS } from './package-manager.js'
7
+ import { SUPPORTED_TOOLCHAINS } from './toolchain.js'
8
+
9
+ import runServer from './mcp.js'
10
+ import { listAddOns } from './add-ons.js'
11
+ import { DEFAULT_FRAMEWORK, SUPPORTED_FRAMEWORKS } from './constants.js'
12
+ // import { initAddOn } from './custom-add-on.js'
13
+
14
+ import { createDefaultEnvironment } from './environment.js'
15
+ // import { add } from './add.js'
16
+
17
+ import type { PackageManager } from './package-manager.js'
18
+ import type { ToolChain } from './toolchain.js'
19
+ import type {
20
+ CliOptions,
21
+ Framework,
22
+ Mode,
23
+ Options,
24
+ TemplateOptions,
25
+ } from './types.js'
26
+
27
+ export function cli({
28
+ name,
29
+ appName,
30
+ forcedMode,
31
+ forcedAddOns,
32
+ }: {
33
+ name: string
34
+ appName: string
35
+ forcedMode?: Mode
36
+ forcedAddOns?: Array<string>
37
+ }) {
38
+ const program = new Command()
39
+
40
+ program.name(name).description(`CLI to create a new ${appName} application`)
41
+
42
+ // program
43
+ // .command('add')
44
+ // .argument('add-on', 'Name of the add-on (or add-ons separated by commas)')
45
+ // .action(async (addOn: string) => {
46
+ // await add(addOn.split(',').map((addon) => addon.trim()))
47
+ // })
48
+
49
+ // program
50
+ // .command('update-add-on')
51
+ // .description('Create or update an add-on from the current project')
52
+ // .action(async () => {
53
+ // await initAddOn('add-on')
54
+ // })
55
+
56
+ // program
57
+ // .command('update-overlay')
58
+ // .description('Create or update a project overlay from the current project')
59
+ // .action(async () => {
60
+ // await initAddOn('overlay')
61
+ // })
62
+
63
+ program.argument('[project-name]', 'name of the project')
64
+
65
+ if (!forcedMode) {
66
+ program.option<'typescript' | 'javascript' | 'file-router'>(
67
+ '--template <type>',
68
+ 'project template (typescript, javascript, file-router)',
69
+ (value) => {
70
+ if (
71
+ value !== 'typescript' &&
72
+ value !== 'javascript' &&
73
+ value !== 'file-router'
74
+ ) {
75
+ throw new InvalidArgumentError(
76
+ `Invalid template: ${value}. Only the following are allowed: typescript, javascript, file-router`,
77
+ )
78
+ }
79
+ return value
80
+ },
81
+ )
82
+ }
83
+ program
84
+ .option<Framework>(
85
+ '--framework <type>',
86
+ 'project framework (solid, react)',
87
+ (value) => {
88
+ if (!SUPPORTED_FRAMEWORKS.includes(value as Framework)) {
89
+ throw new InvalidArgumentError(
90
+ `Invalid framework: ${value}. Only the following are allowed: ${SUPPORTED_FRAMEWORKS.join(
91
+ ', ',
92
+ )}`,
93
+ )
94
+ }
95
+ return value as Framework
96
+ },
97
+ DEFAULT_FRAMEWORK,
98
+ )
99
+ // .option('--overlay [url]', 'add an overlay from a URL', false)
100
+ .option<PackageManager>(
101
+ `--package-manager <${SUPPORTED_PACKAGE_MANAGERS.join('|')}>`,
102
+ `Explicitly tell the CLI to use this package manager`,
103
+ (value) => {
104
+ if (!SUPPORTED_PACKAGE_MANAGERS.includes(value as PackageManager)) {
105
+ throw new InvalidArgumentError(
106
+ `Invalid package manager: ${value}. The following are allowed: ${SUPPORTED_PACKAGE_MANAGERS.join(
107
+ ', ',
108
+ )}`,
109
+ )
110
+ }
111
+ return value as PackageManager
112
+ },
113
+ )
114
+ .option<ToolChain>(
115
+ `--toolchain <${SUPPORTED_TOOLCHAINS.join('|')}>`,
116
+ `Explicitly tell the CLI to use this toolchain`,
117
+ (value) => {
118
+ if (!SUPPORTED_TOOLCHAINS.includes(value as ToolChain)) {
119
+ throw new InvalidArgumentError(
120
+ `Invalid toolchain: ${value}. The following are allowed: ${SUPPORTED_TOOLCHAINS.join(
121
+ ', ',
122
+ )}`,
123
+ )
124
+ }
125
+ return value as ToolChain
126
+ },
127
+ )
128
+ .option('--interactive', 'interactive mode', false)
129
+ .option('--tailwind', 'add Tailwind CSS', false)
130
+ .option<Array<string> | boolean>(
131
+ '--add-ons [...add-ons]',
132
+ 'pick from a list of available add-ons (comma separated list)',
133
+ (value: string) => {
134
+ let addOns: Array<string> | boolean = !!value
135
+ if (typeof value === 'string') {
136
+ addOns = value.split(',').map((addon) => addon.trim())
137
+ }
138
+ return addOns
139
+ },
140
+ )
141
+ .option('--list-add-ons', 'list all available add-ons', false)
142
+ .option('--no-git', 'do not create a git repository')
143
+ .option(
144
+ '--target-dir <path>',
145
+ 'the target directory for the application root',
146
+ )
147
+ .option('--mcp', 'run the MCP server', false)
148
+ .option('--mcp-sse', 'run the MCP server in SSE mode', false)
149
+
150
+ program.action(async (projectName: string, options: CliOptions) => {
151
+ if (options.listAddOns) {
152
+ await listAddOns(options, {
153
+ forcedMode: forcedMode as TemplateOptions,
154
+ forcedAddOns,
155
+ })
156
+ } else if (options.mcp || options.mcpSse) {
157
+ await runServer(!!options.mcpSse, {
158
+ forcedMode: forcedMode as TemplateOptions,
159
+ forcedAddOns,
160
+ appName,
161
+ })
162
+ } else {
163
+ try {
164
+ const cliOptions = {
165
+ projectName,
166
+ ...options,
167
+ } as CliOptions
168
+
169
+ if (forcedMode) {
170
+ cliOptions.template = forcedMode as TemplateOptions
171
+ }
172
+
173
+ let finalOptions: Options | undefined
174
+ if (cliOptions.interactive) {
175
+ cliOptions.addOns = true
176
+ } else {
177
+ finalOptions = await normalizeOptions(
178
+ cliOptions,
179
+ forcedMode,
180
+ forcedAddOns,
181
+ )
182
+ }
183
+
184
+ if (finalOptions) {
185
+ intro(`Creating a new ${appName} app in ${projectName}...`)
186
+ } else {
187
+ intro(`Let's configure your ${appName} application`)
188
+ finalOptions = await promptForOptions(cliOptions, {
189
+ forcedMode: forcedMode as TemplateOptions,
190
+ forcedAddOns,
191
+ })
192
+ }
193
+
194
+ await createApp(finalOptions!, {
195
+ environment: createDefaultEnvironment(),
196
+ cwd: options.targetDir || undefined,
197
+ name,
198
+ appName,
199
+ })
200
+ } catch (error) {
201
+ log.error(
202
+ error instanceof Error ? error.message : 'An unknown error occurred',
203
+ )
204
+ process.exit(1)
205
+ }
206
+ }
207
+ })
208
+
209
+ program.parse()
210
+ }