@tanstack/cta-engine 0.10.0-alpha.16 → 0.10.0-alpha.17

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 (302) hide show
  1. package/dist/add-ons.js +73 -8
  2. package/dist/{add-to-app.js → add.js} +19 -19
  3. package/dist/cli.js +125 -0
  4. package/dist/config-file.js +3 -6
  5. package/dist/constants.js +2 -0
  6. package/dist/create-app.js +460 -76
  7. package/dist/custom-add-on.js +254 -0
  8. package/dist/environment.js +26 -11
  9. package/dist/file-helper.js +18 -0
  10. package/dist/index.js +1 -10
  11. package/dist/mcp.js +229 -0
  12. package/dist/options.js +330 -0
  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 +6 -2
  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 +2 -3
  20. package/dist/types/constants.d.ts +3 -0
  21. package/dist/types/custom-add-on.d.ts +3 -0
  22. package/dist/types/file-helper.d.ts +2 -0
  23. package/dist/types/index.d.ts +1 -13
  24. package/dist/types/mcp.d.ts +7 -0
  25. package/dist/types/options.d.ts +6 -0
  26. package/dist/types/package-manager.d.ts +1 -14
  27. package/dist/types/templates.d.ts +1 -0
  28. package/dist/types/toolchain.d.ts +3 -0
  29. package/dist/types/types.d.ts +63 -84
  30. package/dist/types/utils.d.ts +0 -5
  31. package/dist/utils.js +0 -9
  32. package/package.json +13 -3
  33. package/src/add-ons.ts +104 -11
  34. package/src/{add-to-app.ts → add.ts} +35 -29
  35. package/src/cli.ts +196 -0
  36. package/src/config-file.ts +6 -12
  37. package/src/constants.ts +5 -0
  38. package/src/create-app.ts +727 -126
  39. package/src/custom-add-on.ts +325 -0
  40. package/src/environment.ts +27 -12
  41. package/src/file-helper.ts +20 -0
  42. package/src/index.ts +1 -42
  43. package/src/mcp.ts +302 -0
  44. package/src/options.ts +410 -0
  45. package/src/package-manager.ts +9 -80
  46. package/src/templates.ts +7 -0
  47. package/src/toolchain.ts +7 -0
  48. package/src/types.ts +69 -98
  49. package/src/utils.ts +0 -17
  50. package/templates/react/add-on/clerk/README.md +3 -0
  51. package/templates/react/add-on/clerk/assets/_dot_env.local.append +2 -0
  52. package/templates/react/add-on/clerk/assets/src/integrations/clerk/header-user.tsx +19 -0
  53. package/templates/react/add-on/clerk/assets/src/integrations/clerk/provider.tsx +18 -0
  54. package/templates/react/add-on/clerk/assets/src/routes/demo.clerk.tsx +20 -0
  55. package/templates/react/add-on/clerk/info.json +13 -0
  56. package/templates/react/add-on/clerk/package.json +5 -0
  57. package/templates/react/add-on/convex/README.md +4 -0
  58. package/templates/react/add-on/convex/assets/_dot_cursorrules.append +93 -0
  59. package/templates/react/add-on/convex/assets/_dot_env.local.append +3 -0
  60. package/templates/react/add-on/convex/assets/convex/products.ts +8 -0
  61. package/templates/react/add-on/convex/assets/convex/schema.ts +10 -0
  62. package/templates/react/add-on/convex/assets/src/integrations/convex/provider.tsx +20 -0
  63. package/templates/react/add-on/convex/assets/src/routes/demo.convex.tsx +33 -0
  64. package/templates/react/add-on/convex/info.json +13 -0
  65. package/templates/react/add-on/convex/package.json +6 -0
  66. package/templates/react/add-on/form/assets/src/components/demo.FormComponents.tsx.ejs +300 -0
  67. package/templates/react/add-on/form/assets/src/hooks/demo.form-context.ts +4 -0
  68. package/templates/react/add-on/form/assets/src/hooks/demo.form.ts +22 -0
  69. package/templates/react/add-on/form/assets/src/routes/demo.form.address.tsx.ejs +213 -0
  70. package/templates/react/add-on/form/assets/src/routes/demo.form.simple.tsx.ejs +77 -0
  71. package/templates/react/add-on/form/info.json +26 -0
  72. package/templates/react/add-on/form/package.json +6 -0
  73. package/templates/react/add-on/module-federation/assets/module-federation.config.js.ejs +31 -0
  74. package/templates/react/add-on/module-federation/assets/src/demo-mf-component.tsx +3 -0
  75. package/templates/react/add-on/module-federation/assets/src/demo-mf-self-contained.tsx +11 -0
  76. package/templates/react/add-on/module-federation/info.json +7 -0
  77. package/templates/react/add-on/module-federation/package.json +5 -0
  78. package/templates/react/add-on/netlify/README.md +11 -0
  79. package/templates/react/add-on/netlify/info.json +7 -0
  80. package/templates/react/add-on/sentry/assets/_dot_cursorrules.append +22 -0
  81. package/templates/react/add-on/sentry/assets/_dot_env.local.append +2 -0
  82. package/templates/react/add-on/sentry/assets/src/app/global-middleware.ts +25 -0
  83. package/templates/react/add-on/sentry/assets/src/routes/demo.sentry.testing.tsx +480 -0
  84. package/templates/react/add-on/sentry/info.json +14 -0
  85. package/templates/react/add-on/sentry/package.json +7 -0
  86. package/templates/react/add-on/shadcn/README.md +7 -0
  87. package/templates/react/add-on/shadcn/assets/_dot_cursorrules.append +7 -0
  88. package/templates/react/add-on/shadcn/assets/components.json +21 -0
  89. package/templates/react/add-on/shadcn/assets/src/lib/utils.ts +6 -0
  90. package/templates/react/add-on/shadcn/assets/src/styles.css +138 -0
  91. package/templates/react/add-on/shadcn/info.json +7 -0
  92. package/templates/react/add-on/shadcn/package.json +9 -0
  93. package/templates/react/add-on/start/assets/_dot_gitignore.append +2 -0
  94. package/templates/react/add-on/start/assets/app.config.ts.ejs +19 -0
  95. package/templates/react/add-on/start/assets/src/api.ts +6 -0
  96. package/templates/react/add-on/start/assets/src/client.tsx +8 -0
  97. package/templates/react/add-on/start/assets/src/router.tsx.ejs +77 -0
  98. package/templates/react/add-on/start/assets/src/routes/api.demo-names.ts +11 -0
  99. package/templates/react/add-on/start/assets/src/routes/demo.start.api-request.tsx.ejs +33 -0
  100. package/templates/react/add-on/start/assets/src/routes/demo.start.server-funcs.tsx +50 -0
  101. package/templates/react/add-on/start/assets/src/ssr.tsx +12 -0
  102. package/templates/react/add-on/start/info.json +18 -0
  103. package/templates/react/add-on/start/package.json +13 -0
  104. package/templates/react/add-on/store/assets/src/lib/demo-store.ts +13 -0
  105. package/templates/react/add-on/store/assets/src/routes/demo.store.tsx.ejs +75 -0
  106. package/templates/react/add-on/store/info.json +13 -0
  107. package/templates/react/add-on/store/package.json +6 -0
  108. package/templates/react/add-on/t3env/README.md +16 -0
  109. package/templates/react/add-on/t3env/assets/src/env.ts +39 -0
  110. package/templates/react/add-on/t3env/info.json +10 -0
  111. package/templates/react/add-on/t3env/package.json +6 -0
  112. package/templates/react/add-on/tRPC/assets/src/integrations/trpc/init.ts +9 -0
  113. package/templates/react/add-on/tRPC/assets/src/integrations/trpc/react.ts +4 -0
  114. package/templates/react/add-on/tRPC/assets/src/integrations/trpc/router.ts +18 -0
  115. package/templates/react/add-on/tRPC/assets/src/routes/api.trpc.$.tsx +16 -0
  116. package/templates/react/add-on/tRPC/info.json +9 -0
  117. package/templates/react/add-on/tRPC/package.json +9 -0
  118. package/templates/react/add-on/table/assets/src/data/demo-table-data.ts +50 -0
  119. package/templates/react/add-on/table/assets/src/routes/demo.table.tsx.ejs +373 -0
  120. package/templates/react/add-on/table/info.json +13 -0
  121. package/templates/react/add-on/table/package.json +7 -0
  122. package/templates/react/add-on/tanstack-query/assets/src/integrations/tanstack-query/layout.tsx +5 -0
  123. package/templates/react/add-on/tanstack-query/assets/src/integrations/tanstack-query/root-provider.tsx.ejs +70 -0
  124. package/templates/react/add-on/tanstack-query/assets/src/routes/demo.tanstack-query.tsx.ejs +53 -0
  125. package/templates/react/add-on/tanstack-query/info.json +13 -0
  126. package/templates/react/add-on/tanstack-query/package.json +6 -0
  127. package/templates/react/base/README.md.ejs +558 -0
  128. package/templates/react/base/_dot_gitignore +5 -0
  129. package/templates/react/base/_dot_vscode/settings.biome.json +38 -0
  130. package/templates/react/base/_dot_vscode/settings.json +11 -0
  131. package/templates/react/base/index.html.ejs +20 -0
  132. package/templates/react/base/package.biome.json +10 -0
  133. package/templates/react/base/package.eslintprettier.json +11 -0
  134. package/templates/react/base/package.json +30 -0
  135. package/templates/react/base/package.ts.json +7 -0
  136. package/templates/react/base/package.tw.json +6 -0
  137. package/templates/react/base/public/favicon.ico +0 -0
  138. package/templates/react/base/public/logo192.png +0 -0
  139. package/templates/react/base/public/logo512.png +0 -0
  140. package/templates/react/base/public/manifest.json +25 -0
  141. package/templates/react/base/public/robots.txt +3 -0
  142. package/templates/react/base/src/App.css +38 -0
  143. package/templates/react/base/src/App.test.tsx.ejs +10 -0
  144. package/templates/react/base/src/App.tsx.ejs +74 -0
  145. package/templates/react/base/src/components/Header.tsx.ejs +27 -0
  146. package/templates/react/base/src/logo.svg +44 -0
  147. package/templates/react/base/src/reportWebVitals.ts.ejs +28 -0
  148. package/templates/react/base/src/styles.css.ejs +15 -0
  149. package/templates/react/base/toolchain/.prettierignore +3 -0
  150. package/templates/react/base/toolchain/biome.json +31 -0
  151. package/templates/react/base/toolchain/eslint.config.js +5 -0
  152. package/templates/react/base/toolchain/prettier.config.js +10 -0
  153. package/templates/react/base/tsconfig.json.ejs +29 -0
  154. package/templates/react/base/vite.config.js.ejs +23 -0
  155. package/templates/react/code-router/src/main.tsx.ejs +92 -0
  156. package/templates/react/example/tanchat/README.md +37 -0
  157. package/templates/react/example/tanchat/assets/_dot_env.local.append +2 -0
  158. package/templates/react/example/tanchat/assets/public/example-guitar-flowers.jpg +0 -0
  159. package/templates/react/example/tanchat/assets/public/example-guitar-motherboard.jpg +0 -0
  160. package/templates/react/example/tanchat/assets/public/example-guitar-racing.jpg +0 -0
  161. package/templates/react/example/tanchat/assets/public/example-guitar-steamer-trunk.jpg +0 -0
  162. package/templates/react/example/tanchat/assets/public/example-guitar-superhero.jpg +0 -0
  163. package/templates/react/example/tanchat/assets/public/example-guitar-traveling.jpg +0 -0
  164. package/templates/react/example/tanchat/assets/public/example-guitar-video-games.jpg +0 -0
  165. package/templates/react/example/tanchat/assets/src/components/example-AIAssistant.tsx +173 -0
  166. package/templates/react/example/tanchat/assets/src/components/example-GuitarRecommendation.tsx +47 -0
  167. package/templates/react/example/tanchat/assets/src/data/example-guitars.ts +83 -0
  168. package/templates/react/example/tanchat/assets/src/demo.index.css +220 -0
  169. package/templates/react/example/tanchat/assets/src/integrations/tanchat/header-user.tsx +5 -0
  170. package/templates/react/example/tanchat/assets/src/routes/api.messages.ts +24 -0
  171. package/templates/react/example/tanchat/assets/src/routes/api.sse.ts +23 -0
  172. package/templates/react/example/tanchat/assets/src/routes/example.chat.tsx +159 -0
  173. package/templates/react/example/tanchat/assets/src/routes/example.guitars/$guitarId.tsx +50 -0
  174. package/templates/react/example/tanchat/assets/src/routes/example.guitars/index.tsx +54 -0
  175. package/templates/react/example/tanchat/assets/src/store/example-assistant.ts +3 -0
  176. package/templates/react/example/tanchat/assets/src/utils/demo.ai.ts +62 -0
  177. package/templates/react/example/tanchat/assets/src/utils/demo.sse.ts +31 -0
  178. package/templates/react/example/tanchat/assets/src/utils/demo.tools.ts +47 -0
  179. package/templates/react/example/tanchat/info.json +19 -0
  180. package/templates/react/example/tanchat/package.json +16 -0
  181. package/templates/react/file-router/package.fr.json +5 -0
  182. package/templates/react/file-router/src/main.tsx.ejs +55 -0
  183. package/templates/react/file-router/src/routes/__root.tsx.ejs +82 -0
  184. package/templates/solid/add-on/form/assets/src/routes/demo.form.tsx.ejs +352 -0
  185. package/templates/solid/add-on/form/info.json +13 -0
  186. package/templates/solid/add-on/form/package.json +5 -0
  187. package/templates/solid/add-on/module-federation/assets/module-federation.config.js.ejs +27 -0
  188. package/templates/solid/add-on/module-federation/assets/src/demo-mf-component.tsx +3 -0
  189. package/templates/solid/add-on/module-federation/assets/src/demo-mf-self-contained.tsx +9 -0
  190. package/templates/solid/add-on/module-federation/info.json +7 -0
  191. package/templates/solid/add-on/module-federation/package.json +5 -0
  192. package/templates/solid/add-on/sentry/assets/_dot_cursorrules.append +22 -0
  193. package/templates/solid/add-on/sentry/assets/_dot_env.local.append +2 -0
  194. package/templates/solid/add-on/sentry/assets/src/routes/demo.sentry.bad-event-handler.tsx +20 -0
  195. package/templates/solid/add-on/sentry/info.json +13 -0
  196. package/templates/solid/add-on/sentry/package.json +5 -0
  197. package/templates/solid/add-on/solid-ui/README.md +9 -0
  198. package/templates/solid/add-on/solid-ui/assets/src/lib/utils.ts +6 -0
  199. package/templates/solid/add-on/solid-ui/assets/src/styles.css +138 -0
  200. package/templates/solid/add-on/solid-ui/assets/ui.config.json +13 -0
  201. package/templates/solid/add-on/solid-ui/info.json +11 -0
  202. package/templates/solid/add-on/solid-ui/package.json +9 -0
  203. package/templates/solid/add-on/start/assets/app.config.ts +16 -0
  204. package/templates/solid/add-on/start/assets/src/api.ts +6 -0
  205. package/templates/solid/add-on/start/assets/src/client.tsx +7 -0
  206. package/templates/solid/add-on/start/assets/src/router.tsx.ejs +24 -0
  207. package/templates/solid/add-on/start/assets/src/routes/demo.start.server-funcs.tsx +49 -0
  208. package/templates/solid/add-on/start/assets/src/ssr.tsx +12 -0
  209. package/templates/solid/add-on/start/info.json +14 -0
  210. package/templates/solid/add-on/start/package.json +12 -0
  211. package/templates/solid/add-on/store/assets/src/lib/demo-store.ts +13 -0
  212. package/templates/solid/add-on/store/assets/src/routes/demo.store.tsx.ejs +77 -0
  213. package/templates/solid/add-on/store/info.json +13 -0
  214. package/templates/solid/add-on/store/package.json +6 -0
  215. package/templates/solid/add-on/t3env/README.md +16 -0
  216. package/templates/solid/add-on/t3env/assets/src/env.ts +39 -0
  217. package/templates/solid/add-on/t3env/info.json +10 -0
  218. package/templates/solid/add-on/t3env/package.json +6 -0
  219. package/templates/solid/add-on/tanstack-query/assets/src/integrations/tanstack-query/header-user.tsx +5 -0
  220. package/templates/solid/add-on/tanstack-query/assets/src/integrations/tanstack-query/provider.tsx +15 -0
  221. package/templates/solid/add-on/tanstack-query/assets/src/routes/demo.tanstack-query.tsx +30 -0
  222. package/templates/solid/add-on/tanstack-query/info.json +13 -0
  223. package/templates/solid/add-on/tanstack-query/package.json +6 -0
  224. package/templates/solid/base/README.md.ejs +215 -0
  225. package/templates/solid/base/_dot_cursorrules.append +35 -0
  226. package/templates/solid/base/_dot_gitignore +5 -0
  227. package/templates/solid/base/_dot_vscode/settings.biome.json +38 -0
  228. package/templates/solid/base/_dot_vscode/settings.json +11 -0
  229. package/templates/solid/base/index.html.ejs +20 -0
  230. package/templates/solid/base/package.biome.json +10 -0
  231. package/templates/solid/base/package.eslintprettier.json +11 -0
  232. package/templates/solid/base/package.json +23 -0
  233. package/templates/solid/base/package.ts.json +5 -0
  234. package/templates/solid/base/package.tw.json +6 -0
  235. package/templates/solid/base/public/favicon.ico +0 -0
  236. package/templates/solid/base/public/logo192.png +0 -0
  237. package/templates/solid/base/public/logo512.png +0 -0
  238. package/templates/solid/base/public/manifest.json +25 -0
  239. package/templates/solid/base/public/robots.txt +3 -0
  240. package/templates/solid/base/src/App.css +0 -0
  241. package/templates/solid/base/src/App.tsx.ejs +47 -0
  242. package/templates/solid/base/src/components/Header.tsx.ejs +26 -0
  243. package/templates/solid/base/src/logo.svg +120 -0
  244. package/templates/solid/base/src/styles.css.ejs +15 -0
  245. package/templates/solid/base/toolchain/.prettierignore +3 -0
  246. package/templates/solid/base/toolchain/biome.json +31 -0
  247. package/templates/solid/base/toolchain/eslint.config.js +5 -0
  248. package/templates/solid/base/toolchain/prettier.config.js +10 -0
  249. package/templates/solid/base/tsconfig.json.ejs +31 -0
  250. package/templates/solid/base/vite.config.js.ejs +22 -0
  251. package/templates/solid/code-router/src/main.tsx.ejs +71 -0
  252. package/templates/solid/example/tanchat/README.md +52 -0
  253. package/templates/solid/example/tanchat/assets/ai-streaming-server/README.md +110 -0
  254. package/templates/solid/example/tanchat/assets/ai-streaming-server/_dot_env.example +1 -0
  255. package/templates/solid/example/tanchat/assets/ai-streaming-server/package.json +26 -0
  256. package/templates/solid/example/tanchat/assets/ai-streaming-server/src/index.ts +102 -0
  257. package/templates/solid/example/tanchat/assets/ai-streaming-server/tsconfig.json +15 -0
  258. package/templates/solid/example/tanchat/assets/src/components/demo.SettingsDialog.tsx +149 -0
  259. package/templates/solid/example/tanchat/assets/src/demo.index.css +227 -0
  260. package/templates/solid/example/tanchat/assets/src/lib/demo-store.ts +13 -0
  261. package/templates/solid/example/tanchat/assets/src/routes/example.chat.tsx +435 -0
  262. package/templates/solid/example/tanchat/assets/src/store/demo.hooks.ts +17 -0
  263. package/templates/solid/example/tanchat/assets/src/store/demo.store.ts +133 -0
  264. package/templates/solid/example/tanchat/info.json +14 -0
  265. package/templates/solid/example/tanchat/package.json +7 -0
  266. package/templates/solid/file-router/package.fr.json +5 -0
  267. package/templates/solid/file-router/src/main.tsx.ejs +47 -0
  268. package/templates/solid/file-router/src/routes/__root.tsx.ejs +41 -0
  269. package/templates/solid/file-router/src/routes/index.tsx +43 -0
  270. package/tests/cra.test.ts +293 -0
  271. package/tests/snapshots/cra/cr-js-npm.json +33 -0
  272. package/tests/snapshots/cra/cr-ts-npm.json +34 -0
  273. package/tests/snapshots/cra/cr-ts-start-npm.json +38 -0
  274. package/tests/snapshots/cra/fr-ts-npm.json +34 -0
  275. package/tests/snapshots/cra/fr-ts-tw-npm.json +33 -0
  276. package/tests/snapshots/cra/solid-cr-js-npm.json +31 -0
  277. package/tests/snapshots/cra/solid-cr-ts-npm.json +32 -0
  278. package/tests/snapshots/cra/solid-cr-ts-start-npm.json +36 -0
  279. package/tests/snapshots/cra/solid-fr-ts-npm.json +33 -0
  280. package/tests/snapshots/cra/solid-fr-ts-tw-npm.json +32 -0
  281. package/tests/test-utilities.ts +87 -0
  282. package/dist/file-helpers.js +0 -59
  283. package/dist/frameworks.js +0 -78
  284. package/dist/integrations/git.js +0 -4
  285. package/dist/integrations/shadcn.js +0 -27
  286. package/dist/package-json.js +0 -46
  287. package/dist/template-file.js +0 -108
  288. package/dist/types/add-to-app.d.ts +0 -4
  289. package/dist/types/file-helpers.d.ts +0 -5
  290. package/dist/types/frameworks.d.ts +0 -5
  291. package/dist/types/integrations/git.d.ts +0 -2
  292. package/dist/types/integrations/shadcn.d.ts +0 -2
  293. package/dist/types/package-json.d.ts +0 -2
  294. package/dist/types/template-file.d.ts +0 -2
  295. package/src/file-helpers.ts +0 -73
  296. package/src/frameworks.ts +0 -114
  297. package/src/integrations/git.ts +0 -7
  298. package/src/integrations/shadcn.ts +0 -44
  299. package/src/package-json.ts +0 -62
  300. package/src/template-file.ts +0 -146
  301. package/tests/file-helper.test.ts +0 -37
  302. package/tests/package-manager.test.ts +0 -154
package/src/mcp.ts ADDED
@@ -0,0 +1,302 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
2
+ import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js'
3
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
4
+ import express from 'express'
5
+ import { z } from 'zod'
6
+
7
+ import { createApp } from './create-app.js'
8
+ import { finalizeAddOns } from './add-ons.js'
9
+ import { createDefaultEnvironment } from './environment.js'
10
+
11
+ import type { TemplateOptions } from './types.js'
12
+
13
+ const tanStackReactAddOns = [
14
+ {
15
+ id: 'clerk',
16
+ description: 'Enable authentication with Clerk',
17
+ },
18
+ {
19
+ id: 'convex',
20
+ description: 'Enable a database using Convex',
21
+ },
22
+ {
23
+ id: 'form',
24
+ description: 'Form handling library',
25
+ },
26
+ {
27
+ id: 'netlify',
28
+ description: 'Enable deployments to Netlify',
29
+ },
30
+ {
31
+ id: 'sentry',
32
+ description: 'Enable Sentry error tracking',
33
+ },
34
+ {
35
+ id: 'shadcn',
36
+ description: 'Enable integration of the Shadcn UI component library',
37
+ },
38
+ {
39
+ id: 'start',
40
+ description:
41
+ 'Set this if you want a TanStack Start application that supports server functions or APIs',
42
+ },
43
+ {
44
+ id: 'tanstack-query',
45
+ description: 'Enable TanStack Query for data fetching',
46
+ },
47
+ {
48
+ id: 'store',
49
+ description: 'Enable the TanStack Store state management library',
50
+ },
51
+ {
52
+ id: 'tanchat',
53
+ description: 'Add an AI chatbot example to the application',
54
+ },
55
+ ]
56
+
57
+ const tanStackSolidAddOns = [
58
+ {
59
+ id: 'solid-ui',
60
+ description: 'Enable integration of the Solid UI component library',
61
+ },
62
+ {
63
+ id: 'form',
64
+ description: 'Form handling library',
65
+ },
66
+ {
67
+ id: 'sentry',
68
+ description: 'Enable Sentry error tracking',
69
+ },
70
+ {
71
+ id: 'store',
72
+ description: 'Enable the TanStack Store state management library',
73
+ },
74
+ {
75
+ id: 'start',
76
+ description:
77
+ 'Set this if you want a TanStack Start application that supports server functions or APIs',
78
+ },
79
+ {
80
+ id: 'tanstack-query',
81
+ description: 'Enable TanStack Query for data fetching',
82
+ },
83
+ {
84
+ id: 'tanchat',
85
+ description: 'Add an AI chatbot example to the application',
86
+ },
87
+ ]
88
+
89
+ function createServer({
90
+ appName,
91
+ forcedAddOns = [],
92
+ name,
93
+ }: {
94
+ appName?: string
95
+ forcedAddOns?: Array<string>
96
+ name?: string
97
+ }) {
98
+ const server = new McpServer({
99
+ name: `${appName} Application Builder`,
100
+ version: '1.0.0',
101
+ })
102
+
103
+ server.tool('listTanStackReactAddOns', {}, () => {
104
+ return {
105
+ content: [{ type: 'text', text: JSON.stringify(tanStackReactAddOns) }],
106
+ }
107
+ })
108
+
109
+ server.tool(
110
+ 'createTanStackReactApplication',
111
+ {
112
+ projectName: z
113
+ .string()
114
+ .describe(
115
+ 'The package.json module name of the application (will also be the directory name)',
116
+ ),
117
+ cwd: z.string().describe('The directory to create the application in'),
118
+ addOns: z
119
+ .array(
120
+ z.enum([
121
+ 'clerk',
122
+ 'convex',
123
+ 'form',
124
+ 'netlify',
125
+ 'sentry',
126
+ 'shadcn',
127
+ 'start',
128
+ 'store',
129
+ 'tanstack-query',
130
+ 'tanchat',
131
+ ]),
132
+ )
133
+ .describe('The IDs of the add-ons to install'),
134
+ targetDir: z
135
+ .string()
136
+ .describe(
137
+ 'The directory to create the application in. Use the absolute path of the directory you want the application to be created in',
138
+ ),
139
+ },
140
+ async ({ projectName, addOns, cwd, targetDir }) => {
141
+ try {
142
+ process.chdir(cwd)
143
+ const chosenAddOns = await finalizeAddOns(
144
+ 'react',
145
+ 'file-router',
146
+ Array.from(
147
+ new Set([...(addOns as unknown as Array<string>), ...forcedAddOns]),
148
+ ),
149
+ )
150
+ await createApp(
151
+ {
152
+ projectName: projectName.replace(/^\//, './'),
153
+ framework: 'react',
154
+ typescript: true,
155
+ tailwind: true,
156
+ packageManager: 'pnpm',
157
+ toolchain: 'none',
158
+ mode: 'file-router',
159
+ addOns: true,
160
+ chosenAddOns,
161
+ git: true,
162
+ variableValues: {},
163
+ },
164
+ {
165
+ silent: true,
166
+ environment: createDefaultEnvironment(),
167
+ name,
168
+ cwd: targetDir,
169
+ },
170
+ )
171
+ return {
172
+ content: [{ type: 'text', text: 'Application created successfully' }],
173
+ }
174
+ } catch (error) {
175
+ return {
176
+ content: [
177
+ { type: 'text', text: `Error creating application: ${error}` },
178
+ ],
179
+ }
180
+ }
181
+ },
182
+ )
183
+
184
+ server.tool('listTanStackSolidAddOns', {}, () => {
185
+ return {
186
+ content: [{ type: 'text', text: JSON.stringify(tanStackSolidAddOns) }],
187
+ }
188
+ })
189
+
190
+ server.tool(
191
+ 'createTanStackSolidApplication',
192
+ {
193
+ projectName: z
194
+ .string()
195
+ .describe(
196
+ 'The package.json module name of the application (will also be the directory name)',
197
+ ),
198
+ cwd: z.string().describe('The directory to create the application in'),
199
+ addOns: z
200
+ .array(
201
+ z.enum([
202
+ 'solid-ui',
203
+ 'form',
204
+ 'sentry',
205
+ 'store',
206
+ 'tanstack-query',
207
+ 'tanchat',
208
+ ]),
209
+ )
210
+ .describe('The IDs of the add-ons to install'),
211
+ targetDir: z
212
+ .string()
213
+ .describe(
214
+ 'The directory to create the application in. Use the absolute path of the directory you want the application to be created in',
215
+ ),
216
+ },
217
+ async ({ projectName, addOns, cwd, targetDir }) => {
218
+ try {
219
+ process.chdir(cwd)
220
+ const chosenAddOns = await finalizeAddOns(
221
+ 'solid',
222
+ 'file-router',
223
+ Array.from(
224
+ new Set([...(addOns as unknown as Array<string>), ...forcedAddOns]),
225
+ ),
226
+ )
227
+ await createApp(
228
+ {
229
+ projectName: projectName.replace(/^\//, './'),
230
+ framework: 'solid',
231
+ typescript: true,
232
+ tailwind: true,
233
+ packageManager: 'pnpm',
234
+ toolchain: 'none',
235
+ mode: 'file-router',
236
+ addOns: true,
237
+ chosenAddOns,
238
+ git: true,
239
+ variableValues: {},
240
+ },
241
+ {
242
+ silent: true,
243
+ environment: createDefaultEnvironment(),
244
+ name,
245
+ cwd: targetDir,
246
+ },
247
+ )
248
+ return {
249
+ content: [{ type: 'text', text: 'Application created successfully' }],
250
+ }
251
+ } catch (error) {
252
+ return {
253
+ content: [
254
+ { type: 'text', text: `Error creating application: ${error}` },
255
+ ],
256
+ }
257
+ }
258
+ },
259
+ )
260
+
261
+ return server
262
+ }
263
+
264
+ export default async function runServer(
265
+ sse: boolean,
266
+ {
267
+ forcedAddOns,
268
+ appName,
269
+ name,
270
+ }: {
271
+ forcedMode?: TemplateOptions
272
+ forcedAddOns?: Array<string>
273
+ appName?: string
274
+ name?: string
275
+ },
276
+ ) {
277
+ let transport: SSEServerTransport | null = null
278
+
279
+ const server = createServer({ appName, forcedAddOns, name })
280
+ if (sse) {
281
+ const app = express()
282
+
283
+ app.get('/sse', (req, res) => {
284
+ transport = new SSEServerTransport('/messages', res)
285
+ server.connect(transport)
286
+ })
287
+
288
+ app.post('/messages', (req, res) => {
289
+ if (transport) {
290
+ transport.handlePostMessage(req, res)
291
+ }
292
+ })
293
+
294
+ const port = process.env.PORT || 8080
295
+ app.listen(port, () => {
296
+ console.log(`Server is running on port http://localhost:${port}/sse`)
297
+ })
298
+ } else {
299
+ const transport = new StdioServerTransport()
300
+ await server.connect(transport)
301
+ }
302
+ }
package/src/options.ts ADDED
@@ -0,0 +1,410 @@
1
+ import {
2
+ cancel,
3
+ confirm,
4
+ isCancel,
5
+ multiselect,
6
+ select,
7
+ text,
8
+ } from '@clack/prompts'
9
+
10
+ import {
11
+ DEFAULT_PACKAGE_MANAGER,
12
+ SUPPORTED_PACKAGE_MANAGERS,
13
+ getPackageManager,
14
+ } from './package-manager.js'
15
+ import { DEFAULT_TOOLCHAIN, SUPPORTED_TOOLCHAINS } from './toolchain.js'
16
+ import { CODE_ROUTER, DEFAULT_FRAMEWORK, FILE_ROUTER } from './constants.js'
17
+ import { finalizeAddOns, getAllAddOns, loadRemoteAddOn } from './add-ons.js'
18
+
19
+ import type {
20
+ AddOn,
21
+ CliOptions,
22
+ Mode,
23
+ Options,
24
+ Overlay,
25
+ TemplateOptions,
26
+ Variable,
27
+ } from './types.js'
28
+
29
+ // If all CLI options are provided, use them directly
30
+ export async function normalizeOptions(
31
+ cliOptions: CliOptions,
32
+ forcedMode?: Mode,
33
+ forcedAddOns?: Array<string>,
34
+ ): Promise<Options | undefined> {
35
+ // in some cases, if you use windows/powershell, the argument for addons
36
+ // if sepparated by comma is not really passed as an array, but as a string
37
+ // with spaces, We need to normalize this edge case.
38
+ if (Array.isArray(cliOptions.addOns) && cliOptions.addOns.length === 1) {
39
+ const parseSeparatedArgs = cliOptions.addOns[0].split(' ')
40
+ if (parseSeparatedArgs.length > 1) {
41
+ cliOptions.addOns = parseSeparatedArgs
42
+ }
43
+ }
44
+
45
+ if (cliOptions.projectName) {
46
+ let typescript =
47
+ cliOptions.template === 'typescript' ||
48
+ cliOptions.template === 'file-router' ||
49
+ cliOptions.framework === 'solid'
50
+
51
+ let tailwind = !!cliOptions.tailwind
52
+ if (cliOptions.framework === 'solid') {
53
+ tailwind = true
54
+ }
55
+
56
+ let mode: typeof FILE_ROUTER | typeof CODE_ROUTER =
57
+ cliOptions.template === 'file-router' ? FILE_ROUTER : CODE_ROUTER
58
+
59
+ const overlay = cliOptions.overlay
60
+ ? ((await loadRemoteAddOn(cliOptions.overlay)) as Overlay)
61
+ : undefined
62
+
63
+ if (overlay) {
64
+ tailwind = overlay.tailwind
65
+ typescript = overlay.typescript
66
+ cliOptions.framework = overlay.framework
67
+ mode = overlay.mode
68
+ }
69
+
70
+ let addOns = false
71
+ let chosenAddOns: Array<AddOn> = []
72
+ if (
73
+ Array.isArray(cliOptions.addOns) ||
74
+ overlay?.dependsOn ||
75
+ forcedAddOns
76
+ ) {
77
+ addOns = true
78
+ let finalAddOns = Array.from(
79
+ new Set([...(overlay?.dependsOn || []), ...(forcedAddOns || [])]),
80
+ )
81
+ if (cliOptions.addOns && Array.isArray(cliOptions.addOns)) {
82
+ finalAddOns = Array.from(
83
+ new Set([
84
+ ...(forcedAddOns || []),
85
+ ...finalAddOns,
86
+ ...cliOptions.addOns,
87
+ ]),
88
+ )
89
+ }
90
+ chosenAddOns = await finalizeAddOns(
91
+ cliOptions.framework || DEFAULT_FRAMEWORK,
92
+ forcedMode || cliOptions.template === 'file-router'
93
+ ? FILE_ROUTER
94
+ : CODE_ROUTER,
95
+ finalAddOns,
96
+ )
97
+ tailwind = true
98
+ typescript = true
99
+ }
100
+
101
+ return {
102
+ framework: cliOptions.framework || 'react',
103
+ projectName: cliOptions.projectName,
104
+ typescript,
105
+ tailwind,
106
+ packageManager:
107
+ cliOptions.packageManager ||
108
+ getPackageManager() ||
109
+ DEFAULT_PACKAGE_MANAGER,
110
+ toolchain: cliOptions.toolchain || DEFAULT_TOOLCHAIN,
111
+ mode,
112
+ git: !!cliOptions.git,
113
+ addOns,
114
+ chosenAddOns,
115
+ variableValues: {},
116
+ overlay,
117
+ }
118
+ }
119
+ }
120
+
121
+ async function collectVariables(
122
+ variables: Array<Variable>,
123
+ ): Promise<Record<string, string | number | boolean>> {
124
+ const responses: Record<string, string | number | boolean> = {}
125
+ for (const variable of variables) {
126
+ if (variable.type === 'string') {
127
+ const response = await text({
128
+ message: variable.description,
129
+ initialValue: variable.default,
130
+ })
131
+ if (isCancel(response)) {
132
+ cancel('Operation cancelled.')
133
+ process.exit(0)
134
+ }
135
+ responses[variable.name] = response
136
+ } else if (variable.type === 'number') {
137
+ const response = await text({
138
+ message: variable.description,
139
+ initialValue: variable.default.toString(),
140
+ })
141
+ if (isCancel(response)) {
142
+ cancel('Operation cancelled.')
143
+ process.exit(0)
144
+ }
145
+ responses[variable.name] = Number(response)
146
+ } else {
147
+ const response = await confirm({
148
+ message: variable.description,
149
+ initialValue: variable.default === true,
150
+ })
151
+ if (isCancel(response)) {
152
+ cancel('Operation cancelled.')
153
+ process.exit(0)
154
+ }
155
+ responses[variable.name] = response
156
+ }
157
+ }
158
+ return responses
159
+ }
160
+
161
+ export async function promptForOptions(
162
+ cliOptions: CliOptions,
163
+ {
164
+ forcedAddOns = [],
165
+ forcedMode,
166
+ }: {
167
+ forcedAddOns?: Array<string>
168
+ forcedMode?: TemplateOptions
169
+ },
170
+ ): Promise<Required<Options>> {
171
+ const options = {} as Required<Options>
172
+
173
+ options.framework = cliOptions.framework || DEFAULT_FRAMEWORK
174
+ if (options.framework === 'solid') {
175
+ options.typescript = true
176
+ options.tailwind = true
177
+ }
178
+
179
+ if (cliOptions.addOns) {
180
+ options.typescript = true
181
+ }
182
+
183
+ if (!cliOptions.projectName) {
184
+ const value = await text({
185
+ message: 'What would you like to name your project?',
186
+ defaultValue: 'my-app',
187
+ validate(value) {
188
+ if (!value) {
189
+ return 'Please enter a name'
190
+ }
191
+ },
192
+ })
193
+ if (isCancel(value)) {
194
+ cancel('Operation cancelled.')
195
+ process.exit(0)
196
+ }
197
+ options.projectName = value
198
+ }
199
+
200
+ // Router type selection
201
+ if (!cliOptions.template && !forcedMode) {
202
+ const routerType = await select({
203
+ message: 'Select the router type:',
204
+ options: [
205
+ {
206
+ value: FILE_ROUTER,
207
+ label: 'File Router - File-based routing structure',
208
+ },
209
+ {
210
+ value: CODE_ROUTER,
211
+ label: 'Code Router - Traditional code-based routing',
212
+ },
213
+ ],
214
+ initialValue: FILE_ROUTER,
215
+ })
216
+ if (isCancel(routerType)) {
217
+ cancel('Operation cancelled.')
218
+ process.exit(0)
219
+ }
220
+ options.mode = routerType as typeof CODE_ROUTER | typeof FILE_ROUTER
221
+ } else if (forcedMode) {
222
+ options.mode = forcedMode === 'file-router' ? FILE_ROUTER : CODE_ROUTER
223
+ options.typescript = options.mode === FILE_ROUTER
224
+ } else {
225
+ options.mode =
226
+ cliOptions.template === 'file-router' ? FILE_ROUTER : CODE_ROUTER
227
+ if (options.mode === FILE_ROUTER) {
228
+ options.typescript = true
229
+ }
230
+ }
231
+
232
+ // TypeScript selection (if using Code Router)
233
+ if (!options.typescript) {
234
+ if (options.mode === CODE_ROUTER) {
235
+ const typescriptEnable = await confirm({
236
+ message: 'Would you like to use TypeScript?',
237
+ initialValue: true,
238
+ })
239
+ if (isCancel(typescriptEnable)) {
240
+ cancel('Operation cancelled.')
241
+ process.exit(0)
242
+ }
243
+ options.typescript = typescriptEnable
244
+ } else {
245
+ options.typescript = true
246
+ }
247
+ }
248
+
249
+ // Tailwind selection
250
+ if (!cliOptions.tailwind && options.framework === 'react') {
251
+ const tailwind = await confirm({
252
+ message: 'Would you like to use Tailwind CSS?',
253
+ initialValue: true,
254
+ })
255
+ if (isCancel(tailwind)) {
256
+ cancel('Operation cancelled.')
257
+ process.exit(0)
258
+ }
259
+ options.tailwind = tailwind
260
+ } else {
261
+ options.tailwind = options.framework === 'solid' || !!cliOptions.tailwind
262
+ }
263
+
264
+ // Package manager selection
265
+ if (cliOptions.packageManager === undefined) {
266
+ const detectedPackageManager = getPackageManager()
267
+ if (!detectedPackageManager) {
268
+ const pm = await select({
269
+ message: 'Select package manager:',
270
+ options: SUPPORTED_PACKAGE_MANAGERS.map((pm) => ({
271
+ value: pm,
272
+ label: pm,
273
+ })),
274
+ initialValue: DEFAULT_PACKAGE_MANAGER,
275
+ })
276
+ if (isCancel(pm)) {
277
+ cancel('Operation cancelled.')
278
+ process.exit(0)
279
+ }
280
+ options.packageManager = pm
281
+ } else {
282
+ options.packageManager = detectedPackageManager
283
+ }
284
+ } else {
285
+ options.packageManager = cliOptions.packageManager
286
+ }
287
+
288
+ // Toolchain selection
289
+ if (cliOptions.toolchain === undefined) {
290
+ const tc = await select({
291
+ message: 'Select toolchain',
292
+ options: SUPPORTED_TOOLCHAINS.map((tc) => ({
293
+ value: tc,
294
+ label: tc,
295
+ })),
296
+ initialValue: DEFAULT_TOOLCHAIN,
297
+ })
298
+ if (isCancel(tc)) {
299
+ cancel('Operation cancelled.')
300
+ process.exit(0)
301
+ }
302
+ options.toolchain = tc
303
+ } else {
304
+ options.toolchain = cliOptions.toolchain
305
+ }
306
+
307
+ options.chosenAddOns = []
308
+ if (Array.isArray(cliOptions.addOns)) {
309
+ options.chosenAddOns = await finalizeAddOns(
310
+ options.framework,
311
+ options.mode,
312
+ Array.from(new Set([...cliOptions.addOns, ...forcedAddOns])),
313
+ )
314
+ options.tailwind = true
315
+ } else if (cliOptions.addOns) {
316
+ // Select any add-ons
317
+ const allAddOns = await getAllAddOns(options.framework, options.mode)
318
+ const addOns = allAddOns.filter((addOn) => addOn.type === 'add-on')
319
+ let selectedAddOns: Array<string> = []
320
+ if (options.typescript && addOns.length > 0) {
321
+ const value = await multiselect({
322
+ message: 'What add-ons would you like for your project:',
323
+ options: addOns
324
+ .filter((addOn) => !forcedAddOns.includes(addOn.id))
325
+ .map((addOn) => ({
326
+ value: addOn.id,
327
+ label: addOn.name,
328
+ hint: addOn.description,
329
+ })),
330
+ required: false,
331
+ })
332
+
333
+ if (isCancel(value)) {
334
+ cancel('Operation cancelled.')
335
+ process.exit(0)
336
+ }
337
+ selectedAddOns = value
338
+ }
339
+
340
+ // Select any examples
341
+ let selectedExamples: Array<string> = []
342
+ const examples = allAddOns.filter((addOn) => addOn.type === 'example')
343
+ if (options.typescript && examples.length > 0) {
344
+ const value = await multiselect({
345
+ message: 'Would you like any examples?',
346
+ options: examples
347
+ .filter((addOn) => !forcedAddOns.includes(addOn.id))
348
+ .map((addOn) => ({
349
+ value: addOn.id,
350
+ label: addOn.name,
351
+ hint: addOn.description,
352
+ })),
353
+ required: false,
354
+ })
355
+
356
+ if (isCancel(value)) {
357
+ cancel('Operation cancelled.')
358
+ process.exit(0)
359
+ }
360
+ selectedExamples = value
361
+ }
362
+
363
+ if (
364
+ selectedAddOns.length > 0 ||
365
+ selectedExamples.length > 0 ||
366
+ forcedAddOns.length > 0
367
+ ) {
368
+ options.chosenAddOns = await finalizeAddOns(
369
+ options.framework,
370
+ options.mode,
371
+ Array.from(
372
+ new Set([...selectedAddOns, ...selectedExamples, ...forcedAddOns]),
373
+ ),
374
+ )
375
+ options.tailwind = true
376
+ }
377
+ } else if (forcedAddOns.length > 0) {
378
+ options.chosenAddOns = await finalizeAddOns(
379
+ options.framework,
380
+ options.mode,
381
+ forcedAddOns,
382
+ )
383
+ }
384
+
385
+ // Collect variables
386
+ const variables: Array<Variable> = []
387
+ for (const addOn of options.chosenAddOns) {
388
+ for (const variable of addOn.variables ?? []) {
389
+ variables.push(variable)
390
+ }
391
+ }
392
+ options.variableValues = await collectVariables(variables)
393
+
394
+ // Git selection
395
+ if (cliOptions.git === undefined) {
396
+ const git = await confirm({
397
+ message: 'Would you like to initialize a new git repository?',
398
+ initialValue: true,
399
+ })
400
+ if (isCancel(git)) {
401
+ cancel('Operation cancelled.')
402
+ process.exit(0)
403
+ }
404
+ options.git = git
405
+ } else {
406
+ options.git = !!cliOptions.git
407
+ }
408
+
409
+ return options
410
+ }