create-aiko 0.1.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 (317) hide show
  1. package/README.md +46 -0
  2. package/dist/cli.d.ts +2 -0
  3. package/dist/cli.js +7 -0
  4. package/dist/create.d.ts +1 -0
  5. package/dist/create.js +174 -0
  6. package/dist/index.d.ts +2 -0
  7. package/dist/index.js +2 -0
  8. package/dist/scaffold.d.ts +7 -0
  9. package/dist/scaffold.js +310 -0
  10. package/package.json +37 -0
  11. package/template/README.md +63 -0
  12. package/template/docs/better-sqlite3-design.md +101 -0
  13. package/template/docs/shared-vs-shared-auth.md +54 -0
  14. package/template/package.json +23 -0
  15. package/template/packages/admin/.env.dev +1 -0
  16. package/template/packages/admin/.env.prod +4 -0
  17. package/template/packages/admin/.env.stage +4 -0
  18. package/template/packages/admin/Dockerfile +37 -0
  19. package/template/packages/admin/README.MD +27 -0
  20. package/template/packages/admin/components.json +21 -0
  21. package/template/packages/admin/eslint.config.js +28 -0
  22. package/template/packages/admin/index.html +50 -0
  23. package/template/packages/admin/package.json +100 -0
  24. package/template/packages/admin/public/vite.svg +1 -0
  25. package/template/packages/admin/src/App.css +82 -0
  26. package/template/packages/admin/src/App.tsx +128 -0
  27. package/template/packages/admin/src/app.config.ts +3 -0
  28. package/template/packages/admin/src/components/admin-ui/approval-flow.tsx +205 -0
  29. package/template/packages/admin/src/components/admin-ui/data-table/data-table-pagination.tsx +148 -0
  30. package/template/packages/admin/src/components/admin-ui/data-table/data-table-sorter.tsx +50 -0
  31. package/template/packages/admin/src/components/admin-ui/data-table/index.tsx +296 -0
  32. package/template/packages/admin/src/components/admin-ui/editable-table.tsx +292 -0
  33. package/template/packages/admin/src/components/admin-ui/form/input-password.tsx +38 -0
  34. package/template/packages/admin/src/components/admin-ui/form/sign-in-form.tsx +104 -0
  35. package/template/packages/admin/src/components/admin-ui/layout/error-component.tsx +71 -0
  36. package/template/packages/admin/src/components/admin-ui/layout/header.tsx +148 -0
  37. package/template/packages/admin/src/components/admin-ui/layout/language-switcher.tsx +47 -0
  38. package/template/packages/admin/src/components/admin-ui/layout/layout.tsx +42 -0
  39. package/template/packages/admin/src/components/admin-ui/layout/loading-overlay.tsx +36 -0
  40. package/template/packages/admin/src/components/admin-ui/layout/shell-bar.tsx +232 -0
  41. package/template/packages/admin/src/components/admin-ui/layout/sidebar.tsx +193 -0
  42. package/template/packages/admin/src/components/admin-ui/layout/user-avatar.tsx +31 -0
  43. package/template/packages/admin/src/components/admin-ui/list-report.tsx +313 -0
  44. package/template/packages/admin/src/components/admin-ui/master-detail.tsx +382 -0
  45. package/template/packages/admin/src/components/admin-ui/notification/toaster.tsx +23 -0
  46. package/template/packages/admin/src/components/admin-ui/notification/undoable-notification.tsx +84 -0
  47. package/template/packages/admin/src/components/admin-ui/object-page.tsx +539 -0
  48. package/template/packages/admin/src/components/admin-ui/process-stepper.tsx +204 -0
  49. package/template/packages/admin/src/components/admin-ui/theme/theme-provider.tsx +160 -0
  50. package/template/packages/admin/src/components/admin-ui/theme/theme-select.tsx +129 -0
  51. package/template/packages/admin/src/components/admin-ui/theme/theme-toggle.tsx +90 -0
  52. package/template/packages/admin/src/components/admin-ui/timeline.tsx +137 -0
  53. package/template/packages/admin/src/components/admin-ui/tree-navigator.tsx +243 -0
  54. package/template/packages/admin/src/components/ui/accordion.tsx +64 -0
  55. package/template/packages/admin/src/components/ui/alert-dialog.tsx +157 -0
  56. package/template/packages/admin/src/components/ui/alert.tsx +66 -0
  57. package/template/packages/admin/src/components/ui/aspect-ratio.tsx +9 -0
  58. package/template/packages/admin/src/components/ui/avatar.tsx +53 -0
  59. package/template/packages/admin/src/components/ui/badge.tsx +47 -0
  60. package/template/packages/admin/src/components/ui/breadcrumb.tsx +111 -0
  61. package/template/packages/admin/src/components/ui/button.tsx +59 -0
  62. package/template/packages/admin/src/components/ui/calendar.tsx +74 -0
  63. package/template/packages/admin/src/components/ui/card.tsx +92 -0
  64. package/template/packages/admin/src/components/ui/carousel.tsx +237 -0
  65. package/template/packages/admin/src/components/ui/chart.tsx +351 -0
  66. package/template/packages/admin/src/components/ui/checkbox.tsx +32 -0
  67. package/template/packages/admin/src/components/ui/collapsible.tsx +33 -0
  68. package/template/packages/admin/src/components/ui/command.tsx +182 -0
  69. package/template/packages/admin/src/components/ui/context-menu.tsx +252 -0
  70. package/template/packages/admin/src/components/ui/dialog.tsx +141 -0
  71. package/template/packages/admin/src/components/ui/drawer.tsx +130 -0
  72. package/template/packages/admin/src/components/ui/dropdown-menu.tsx +255 -0
  73. package/template/packages/admin/src/components/ui/form.tsx +166 -0
  74. package/template/packages/admin/src/components/ui/hover-card.tsx +42 -0
  75. package/template/packages/admin/src/components/ui/input-otp.tsx +77 -0
  76. package/template/packages/admin/src/components/ui/input.tsx +21 -0
  77. package/template/packages/admin/src/components/ui/label.tsx +22 -0
  78. package/template/packages/admin/src/components/ui/menubar.tsx +274 -0
  79. package/template/packages/admin/src/components/ui/navigation-menu.tsx +168 -0
  80. package/template/packages/admin/src/components/ui/pagination.tsx +127 -0
  81. package/template/packages/admin/src/components/ui/popover.tsx +48 -0
  82. package/template/packages/admin/src/components/ui/progress.tsx +29 -0
  83. package/template/packages/admin/src/components/ui/radio-group.tsx +45 -0
  84. package/template/packages/admin/src/components/ui/resizable.tsx +54 -0
  85. package/template/packages/admin/src/components/ui/scroll-area.tsx +58 -0
  86. package/template/packages/admin/src/components/ui/select.tsx +183 -0
  87. package/template/packages/admin/src/components/ui/separator.tsx +26 -0
  88. package/template/packages/admin/src/components/ui/sheet.tsx +139 -0
  89. package/template/packages/admin/src/components/ui/sidebar.tsx +740 -0
  90. package/template/packages/admin/src/components/ui/skeleton.tsx +13 -0
  91. package/template/packages/admin/src/components/ui/slider.tsx +63 -0
  92. package/template/packages/admin/src/components/ui/sonner.tsx +23 -0
  93. package/template/packages/admin/src/components/ui/switch.tsx +31 -0
  94. package/template/packages/admin/src/components/ui/table.tsx +114 -0
  95. package/template/packages/admin/src/components/ui/tabs.tsx +66 -0
  96. package/template/packages/admin/src/components/ui/textarea.tsx +18 -0
  97. package/template/packages/admin/src/components/ui/toggle-group.tsx +73 -0
  98. package/template/packages/admin/src/components/ui/toggle.tsx +45 -0
  99. package/template/packages/admin/src/components/ui/tooltip.tsx +59 -0
  100. package/template/packages/admin/src/hooks/use-mobile.ts +21 -0
  101. package/template/packages/admin/src/i18n.ts +20 -0
  102. package/template/packages/admin/src/index.tsx +18 -0
  103. package/template/packages/admin/src/layouts/menu-layout.tsx +211 -0
  104. package/template/packages/admin/src/layouts/tile-layout.tsx +355 -0
  105. package/template/packages/admin/src/lib/utils.ts +6 -0
  106. package/template/packages/admin/src/locales/en.json +68 -0
  107. package/template/packages/admin/src/locales/zh.json +68 -0
  108. package/template/packages/admin/src/pages/dashboard.tsx +12 -0
  109. package/template/packages/admin/src/pages/goods-receipt/CreatePage.tsx +302 -0
  110. package/template/packages/admin/src/pages/goods-receipt/EditPage.tsx +221 -0
  111. package/template/packages/admin/src/pages/goods-receipt/ListPage.tsx +283 -0
  112. package/template/packages/admin/src/pages/goods-receipt/ViewPage.tsx +280 -0
  113. package/template/packages/admin/src/pages/goods-receipt/index.ts +4 -0
  114. package/template/packages/admin/src/pages/home-page.tsx +244 -0
  115. package/template/packages/admin/src/pages/login-page.tsx +91 -0
  116. package/template/packages/admin/src/pages/master-data/cost-centers/index.tsx +461 -0
  117. package/template/packages/admin/src/pages/master-data/currencies/index.tsx +255 -0
  118. package/template/packages/admin/src/pages/master-data/materials/ListPage.tsx +271 -0
  119. package/template/packages/admin/src/pages/master-data/materials/ViewPage.tsx +240 -0
  120. package/template/packages/admin/src/pages/master-data/materials/index.ts +2 -0
  121. package/template/packages/admin/src/pages/master-data/plants/ListPage.tsx +279 -0
  122. package/template/packages/admin/src/pages/master-data/plants/ViewPage.tsx +380 -0
  123. package/template/packages/admin/src/pages/master-data/plants/index.ts +2 -0
  124. package/template/packages/admin/src/pages/master-data/purchase-organizations/index.tsx +341 -0
  125. package/template/packages/admin/src/pages/master-data/units-of-measure/index.tsx +295 -0
  126. package/template/packages/admin/src/pages/master-data/vendors/ListPage.tsx +266 -0
  127. package/template/packages/admin/src/pages/master-data/vendors/ViewPage.tsx +274 -0
  128. package/template/packages/admin/src/pages/master-data/vendors/index.ts +2 -0
  129. package/template/packages/admin/src/pages/placeholder-page.tsx +13 -0
  130. package/template/packages/admin/src/pages/purchase-orders/ListPage.tsx +289 -0
  131. package/template/packages/admin/src/pages/purchase-orders/ViewPage.tsx +343 -0
  132. package/template/packages/admin/src/pages/purchase-orders/index.ts +2 -0
  133. package/template/packages/admin/src/pages/purchase-requisitions/CreatePage.tsx +398 -0
  134. package/template/packages/admin/src/pages/purchase-requisitions/EditPage.tsx +473 -0
  135. package/template/packages/admin/src/pages/purchase-requisitions/ListPage.tsx +307 -0
  136. package/template/packages/admin/src/pages/purchase-requisitions/ViewPage.tsx +304 -0
  137. package/template/packages/admin/src/pages/purchase-requisitions/constants.ts +51 -0
  138. package/template/packages/admin/src/pages/purchase-requisitions/index.ts +4 -0
  139. package/template/packages/admin/src/pages/reports/PurchaseOrderReport.tsx +312 -0
  140. package/template/packages/admin/src/pages/reports/PurchaseRequisitionReport.tsx +303 -0
  141. package/template/packages/admin/src/pages/reports/index.ts +2 -0
  142. package/template/packages/admin/src/pages/settings-page.tsx +335 -0
  143. package/template/packages/admin/src/providers/app-config.tsx +50 -0
  144. package/template/packages/admin/src/routes/auth.ts +6 -0
  145. package/template/packages/admin/src/routes/index.ts +85 -0
  146. package/template/packages/admin/src/routes/menu.ts +176 -0
  147. package/template/packages/admin/src/routes/modules/goods-receipt.ts +31 -0
  148. package/template/packages/admin/src/routes/modules/master-data.ts +41 -0
  149. package/template/packages/admin/src/routes/modules/purchase-orders.ts +27 -0
  150. package/template/packages/admin/src/routes/modules/purchase-requisitions.ts +39 -0
  151. package/template/packages/admin/src/routes/modules/reports.ts +33 -0
  152. package/template/packages/admin/src/routes/modules/settings.ts +19 -0
  153. package/template/packages/admin/src/routes/withSuspense.tsx +21 -0
  154. package/template/packages/admin/src/theme/amber.css +27 -0
  155. package/template/packages/admin/src/theme/blue.css +27 -0
  156. package/template/packages/admin/src/theme/default.css +75 -0
  157. package/template/packages/admin/src/theme/fiori.css +180 -0
  158. package/template/packages/admin/src/theme/green.css +27 -0
  159. package/template/packages/admin/src/theme/index.css +12 -0
  160. package/template/packages/admin/src/theme/rose.css +27 -0
  161. package/template/packages/admin/src/theme/violet.css +27 -0
  162. package/template/packages/admin/src/vite-env.d.ts +1 -0
  163. package/template/packages/admin/tsconfig.json +28 -0
  164. package/template/packages/admin/tsconfig.node.json +21 -0
  165. package/template/packages/admin/vite.config.ts +26 -0
  166. package/template/packages/api/.eslintrc.json +6 -0
  167. package/template/packages/api/.swcrc +17 -0
  168. package/template/packages/api/app.config.ts +160 -0
  169. package/template/packages/api/docs/api-document.md +497 -0
  170. package/template/packages/api/examples/security/README.md +664 -0
  171. package/template/packages/api/examples/security/complete/.env.example +26 -0
  172. package/template/packages/api/examples/security/complete/PROJECT_STRUCTURE.md +220 -0
  173. package/template/packages/api/examples/security/complete/README.md +847 -0
  174. package/template/packages/api/examples/security/complete/app.config.ts +69 -0
  175. package/template/packages/api/examples/security/complete/app.ts +63 -0
  176. package/template/packages/api/examples/security/complete/controller/auth.controller.ts +131 -0
  177. package/template/packages/api/examples/security/complete/controller/index.ts +4 -0
  178. package/template/packages/api/examples/security/complete/controller/permission.controller.ts +41 -0
  179. package/template/packages/api/examples/security/complete/controller/role.controller.ts +53 -0
  180. package/template/packages/api/examples/security/complete/controller/user.controller.ts +53 -0
  181. package/template/packages/api/examples/security/complete/dto/change-password.dto.ts +10 -0
  182. package/template/packages/api/examples/security/complete/dto/create-permission.dto.ts +14 -0
  183. package/template/packages/api/examples/security/complete/dto/create-role.dto.ts +11 -0
  184. package/template/packages/api/examples/security/complete/dto/create-user.dto.ts +15 -0
  185. package/template/packages/api/examples/security/complete/dto/index.ts +7 -0
  186. package/template/packages/api/examples/security/complete/dto/login.dto.ts +10 -0
  187. package/template/packages/api/examples/security/complete/dto/oauth-profile.dto.ts +7 -0
  188. package/template/packages/api/examples/security/complete/dto/register.dto.ts +17 -0
  189. package/template/packages/api/examples/security/complete/entity/index.ts +6 -0
  190. package/template/packages/api/examples/security/complete/entity/oauth-account.entity.ts +39 -0
  191. package/template/packages/api/examples/security/complete/entity/permission.entity.ts +31 -0
  192. package/template/packages/api/examples/security/complete/entity/role-permission.entity.ts +19 -0
  193. package/template/packages/api/examples/security/complete/entity/role.entity.ts +25 -0
  194. package/template/packages/api/examples/security/complete/entity/user-role.entity.ts +19 -0
  195. package/template/packages/api/examples/security/complete/entity/user.entity.ts +46 -0
  196. package/template/packages/api/examples/security/complete/init.sql +81 -0
  197. package/template/packages/api/examples/security/complete/middleware/auth.interceptor.ts +39 -0
  198. package/template/packages/api/examples/security/complete/middleware/index.ts +2 -0
  199. package/template/packages/api/examples/security/complete/middleware/permission.interceptor.ts +61 -0
  200. package/template/packages/api/examples/security/complete/package.json +54 -0
  201. package/template/packages/api/examples/security/complete/seed.sql +42 -0
  202. package/template/packages/api/examples/security/complete/service/auth.service.ts +41 -0
  203. package/template/packages/api/examples/security/complete/service/index.ts +5 -0
  204. package/template/packages/api/examples/security/complete/service/oauth.service.ts +82 -0
  205. package/template/packages/api/examples/security/complete/service/permission.service.ts +113 -0
  206. package/template/packages/api/examples/security/complete/service/role.service.ts +85 -0
  207. package/template/packages/api/examples/security/complete/service/user.service.ts +132 -0
  208. package/template/packages/api/examples/security/complete/tests/TEST_REPORT.md +318 -0
  209. package/template/packages/api/examples/security/complete/tests/generate-report.js +335 -0
  210. package/template/packages/api/examples/security/complete/tests/helpers/api-helpers.ts +116 -0
  211. package/template/packages/api/examples/security/complete/tests/helpers/index.ts +2 -0
  212. package/template/packages/api/examples/security/complete/tests/helpers/test-helpers.ts +129 -0
  213. package/template/packages/api/examples/security/complete/tests/integration/auth.api.test.ts +429 -0
  214. package/template/packages/api/examples/security/complete/tests/integration/role.api.test.ts +400 -0
  215. package/template/packages/api/examples/security/complete/tests/integration/user.api.test.ts +459 -0
  216. package/template/packages/api/examples/security/complete/tests/jest.config.js +40 -0
  217. package/template/packages/api/examples/security/complete/tests/run-all-tests.js +135 -0
  218. package/template/packages/api/examples/security/complete/tests/run-tests.js +109 -0
  219. package/template/packages/api/examples/security/complete/tests/setup.ts +19 -0
  220. package/template/packages/api/examples/security/complete/tests/unit/auth.service.test.ts +199 -0
  221. package/template/packages/api/examples/security/complete/tests/unit/permission.service.test.ts +377 -0
  222. package/template/packages/api/examples/security/complete/tests/unit/user.service.test.ts +288 -0
  223. package/template/packages/api/examples/security/complete/tsconfig.json +35 -0
  224. package/template/packages/api/examples/security/jwt/README.md +424 -0
  225. package/template/packages/api/examples/security/local/README.md +499 -0
  226. package/template/packages/api/examples/security/oauth2/README.md +637 -0
  227. package/template/packages/api/examples/security/permission/README.md +943 -0
  228. package/template/packages/api/examples/security/session/README.md +753 -0
  229. package/template/packages/api/package.json +56 -0
  230. package/template/packages/api/src/controller/auth.controller.ts +127 -0
  231. package/template/packages/api/src/controller/cache.controller.ts +106 -0
  232. package/template/packages/api/src/controller/menu.controller.ts +46 -0
  233. package/template/packages/api/src/controller/mq.controller.ts +35 -0
  234. package/template/packages/api/src/controller/role.controller.ts +51 -0
  235. package/template/packages/api/src/controller/upload.controller.ts +85 -0
  236. package/template/packages/api/src/controller/user.controller.ts +57 -0
  237. package/template/packages/api/src/dto/auth.dto.ts +30 -0
  238. package/template/packages/api/src/dto/cache.dto.ts +24 -0
  239. package/template/packages/api/src/dto/menu.dto.ts +37 -0
  240. package/template/packages/api/src/dto/mq.dto.ts +16 -0
  241. package/template/packages/api/src/dto/role.dto.ts +16 -0
  242. package/template/packages/api/src/dto/user.dto.ts +35 -0
  243. package/template/packages/api/src/entity/menu.entity.ts +34 -0
  244. package/template/packages/api/src/entity/role-menu.entity.ts +13 -0
  245. package/template/packages/api/src/entity/role.entity.ts +22 -0
  246. package/template/packages/api/src/entity/user-role.entity.ts +13 -0
  247. package/template/packages/api/src/entity/user.entity.ts +31 -0
  248. package/template/packages/api/src/mapper/menu.mapper.ts +6 -0
  249. package/template/packages/api/src/mapper/role-menu.mapper.ts +6 -0
  250. package/template/packages/api/src/mapper/role.mapper.ts +6 -0
  251. package/template/packages/api/src/mapper/user-role.mapper.ts +6 -0
  252. package/template/packages/api/src/mapper/user.mapper.ts +11 -0
  253. package/template/packages/api/src/scripts/init-db.ts +185 -0
  254. package/template/packages/api/src/server.ts +76 -0
  255. package/template/packages/api/src/service/auth.service.ts +106 -0
  256. package/template/packages/api/src/service/cache.service.ts +80 -0
  257. package/template/packages/api/src/service/log.request.service.ts +158 -0
  258. package/template/packages/api/src/service/log.service.ts +123 -0
  259. package/template/packages/api/src/service/menu.service.ts +94 -0
  260. package/template/packages/api/src/service/mq.consumer.service.ts +26 -0
  261. package/template/packages/api/src/service/role.service.ts +88 -0
  262. package/template/packages/api/src/service/user.service.ts +170 -0
  263. package/template/packages/api/src/types/sqljs.d.ts +18 -0
  264. package/template/packages/api/src/utils/auth.utils.js +0 -0
  265. package/template/packages/api/src/utils/jwt.util.ts +29 -0
  266. package/template/packages/api/tsconfig.json +17 -0
  267. package/template/packages/api/tsup.config.ts +9 -0
  268. package/template/packages/api/uploads/.gitkeep +0 -0
  269. package/template/packages/core/package.json +31 -0
  270. package/template/packages/core/src/auth/auth-client-middleware.ts +22 -0
  271. package/template/packages/core/src/auth/auth-service.ts +65 -0
  272. package/template/packages/core/src/auth/default-auth-provider.ts +37 -0
  273. package/template/packages/core/src/auth/index.ts +10 -0
  274. package/template/packages/core/src/auth/types.ts +38 -0
  275. package/template/packages/core/src/authorization/authorization-client-middleware.ts +38 -0
  276. package/template/packages/core/src/authorization/authorization-config.ts +13 -0
  277. package/template/packages/core/src/authorization/authorization-provider.tsx +116 -0
  278. package/template/packages/core/src/authorization/default-authorization-provider.ts +26 -0
  279. package/template/packages/core/src/authorization/index.ts +15 -0
  280. package/template/packages/core/src/authorization/types.ts +42 -0
  281. package/template/packages/core/src/index.ts +3 -0
  282. package/template/packages/core/src/utils/promise-result-cache.ts +18 -0
  283. package/template/packages/core/tsconfig.json +19 -0
  284. package/template/packages/mobile/README.md +55 -0
  285. package/template/packages/mobile/index.html +13 -0
  286. package/template/packages/mobile/package.json +30 -0
  287. package/template/packages/mobile/postcss.config.mjs +7 -0
  288. package/template/packages/mobile/src/App.tsx +5 -0
  289. package/template/packages/mobile/src/app/globals.css +1 -0
  290. package/template/packages/mobile/src/components/LoginForm.tsx +76 -0
  291. package/template/packages/mobile/src/hooks/index.ts +5 -0
  292. package/template/packages/mobile/src/lib/utils.ts +7 -0
  293. package/template/packages/mobile/src/main.tsx +13 -0
  294. package/template/packages/mobile/src/pages/HomePage.tsx +35 -0
  295. package/template/packages/mobile/src/pages/LoginPage.tsx +35 -0
  296. package/template/packages/mobile/src/pages/index.ts +2 -0
  297. package/template/packages/mobile/src/routes/ProtectedRoute.tsx +29 -0
  298. package/template/packages/mobile/src/routes/index.tsx +24 -0
  299. package/template/packages/mobile/src/routes/routes.ts +11 -0
  300. package/template/packages/mobile/src/types/index.ts +5 -0
  301. package/template/packages/mobile/src/vite-env.d.ts +1 -0
  302. package/template/packages/mobile/tsconfig.json +23 -0
  303. package/template/packages/mobile/tsconfig.node.json +11 -0
  304. package/template/packages/mobile/vite.config.ts +19 -0
  305. package/template/packages/shared/package.json +20 -0
  306. package/template/packages/shared/src/constants.ts +8 -0
  307. package/template/packages/shared/src/index.ts +5 -0
  308. package/template/packages/shared/tsconfig.json +13 -0
  309. package/template/packages/shared-auth/package.json +29 -0
  310. package/template/packages/shared-auth/src/AuthContext.tsx +177 -0
  311. package/template/packages/shared-auth/src/AuthProviderWrapper.tsx +29 -0
  312. package/template/packages/shared-auth/src/index.ts +10 -0
  313. package/template/packages/shared-auth/tsconfig.json +14 -0
  314. package/template/pnpm-lock.yaml +16349 -0
  315. package/template/pnpm-workspace.yaml +3 -0
  316. package/template/scripts/postinstall.cjs +42 -0
  317. package/template/scripts/rebuild-sqlite.cjs +23 -0
package/README.md ADDED
@@ -0,0 +1,46 @@
1
+ # create-aiko
2
+
3
+ CLI to create a new aiko-boot scaffold project (monorepo: api, admin, mobile, shared, optionally shared-auth).
4
+
5
+ ## Usage
6
+
7
+ Published package usage:
8
+
9
+ ```bash
10
+ pnpm dlx create-aiko my-app
11
+ ```
12
+
13
+ Repository-local usage:
14
+
15
+ ```bash
16
+ pnpm run create
17
+ node packages/aiko-boot-create/dist/cli.js
18
+ ```
19
+
20
+ ## Options
21
+
22
+ | Option | Description |
23
+ |--------|-------------|
24
+ | `[targetDir]` | Target directory for the new project. Default: `<cwd>/<projectName>` |
25
+ | `-n, --name <name>` | Project name, used as npm scope (e.g. `my-app` → `@my-app/*`) |
26
+ | `--with-base-system` | Include base system: login, shared-auth, user/menu management (later) |
27
+ | `--no-base-system` | Bare project without login/auth (default when not specified) |
28
+ | `--template-dir <dir>` | Path to scaffold template. Default: bundled template in npm package; if missing, fallback to `<cwd>/scaffold` |
29
+
30
+ ## Base system vs bare
31
+
32
+ - **With base system** (`--with-base-system`): Copies full scaffold including `shared-auth`, auth controller/service/dto, user entity/mapper, init-db with `sys_user`, login pages and protected routes in admin/mobile.
33
+ - **Bare** (`--no-base-system`): Same monorepo structure (api, admin, mobile, shared) but no `shared-auth`, no auth-related files in api, no login UI or protected routes; shared has no `AUTH_STORAGE_KEY`.
34
+
35
+ ## After generation
36
+
37
+ 1. `cd <targetDir>`
38
+ 2. `pnpm install`
39
+ 3. If base system was included: `pnpm init-db`
40
+ 4. `pnpm dev`
41
+
42
+ ## Build
43
+
44
+ ```bash
45
+ pnpm build
46
+ ```
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * create-aiko CLI
4
+ * Create a new aiko-boot scaffold project (monorepo: api, admin, mobile, shared[, shared-auth]).
5
+ */
6
+ import { createCommand } from './create.js';
7
+ createCommand();
@@ -0,0 +1 @@
1
+ export declare function createCommand(): void;
package/dist/create.js ADDED
@@ -0,0 +1,174 @@
1
+ import { program } from 'commander';
2
+ import * as readline from 'readline';
3
+ import path from 'path';
4
+ import { fileURLToPath } from 'url';
5
+ import fs from 'fs-extra';
6
+ import { createScaffold } from './scaffold.js';
7
+ const SCAFFOLD_DIR_NAME = 'scaffold';
8
+ const PACKAGE_TEMPLATE_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../template');
9
+ function getTemplateDir(cwd) {
10
+ const cwdTemplateDir = path.join(cwd, SCAFFOLD_DIR_NAME);
11
+ if (fs.existsSync(cwdTemplateDir)) {
12
+ return cwdTemplateDir;
13
+ }
14
+ return PACKAGE_TEMPLATE_DIR;
15
+ }
16
+ function prompt(question, defaultValue) {
17
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
18
+ return new Promise((resolve) => {
19
+ const suffix = defaultValue !== undefined ? ` (${defaultValue})` : '';
20
+ rl.question(`${question}${suffix}: `, (answer) => {
21
+ rl.close();
22
+ resolve((answer.trim() || (defaultValue ?? '')).trim());
23
+ });
24
+ });
25
+ }
26
+ function promptConfirm(question, defaultValue) {
27
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
28
+ const hint = defaultValue ? 'Y/n' : 'y/N';
29
+ return new Promise((resolve) => {
30
+ rl.question(`${question} [${hint}]: `, (answer) => {
31
+ rl.close();
32
+ const lower = answer.trim().toLowerCase();
33
+ if (lower === '')
34
+ resolve(defaultValue);
35
+ else
36
+ resolve(lower === 'y' || lower === 'yes');
37
+ });
38
+ });
39
+ }
40
+ /** Normalize project name to valid npm scope (lowercase, no spaces). */
41
+ function toScope(name) {
42
+ const normalized = name
43
+ .trim()
44
+ .toLowerCase()
45
+ .replace(/\s+/g, '-')
46
+ .replace(/[^a-z0-9-]/g, '')
47
+ .replace(/-+/g, '-')
48
+ .replace(/^-+|-+$/g, '');
49
+ return normalized || 'my-app';
50
+ }
51
+ const RESERVED_SCOPES = new Set([
52
+ 'node',
53
+ 'npm',
54
+ 'js',
55
+ 'javascript',
56
+ 'typescript',
57
+ 'react',
58
+ 'vue',
59
+ 'angular',
60
+ 'core',
61
+ 'admin',
62
+ 'root',
63
+ 'system',
64
+ ]);
65
+ function assertValidScope(scope) {
66
+ if (!scope) {
67
+ console.error('Invalid scope: empty value. Please provide a non-empty project name.');
68
+ process.exit(1);
69
+ }
70
+ if (RESERVED_SCOPES.has(scope)) {
71
+ console.error(`Invalid scope "${scope}": this name is reserved. Please choose a different project name.`);
72
+ process.exit(1);
73
+ }
74
+ }
75
+ /** Show destination default as relative path when under cwd (e.g. "./my-app"). */
76
+ function defaultDirDisplay(cwd, absoluteDir) {
77
+ const relative = path.relative(cwd, absoluteDir);
78
+ if (relative && !relative.startsWith('..') && relative !== absoluteDir) {
79
+ return relative.startsWith('.') ? relative : `./${relative}`;
80
+ }
81
+ return absoluteDir;
82
+ }
83
+ export function createCommand() {
84
+ program
85
+ .name('create-aiko')
86
+ .description('Create a new aiko-boot scaffold project (monorepo: api, admin, mobile, shared)')
87
+ .version('0.1.0')
88
+ .argument('[projectNameOrPath]', 'Project name or path (e.g. my-app or ./my-app; default: prompt)')
89
+ .option('-n, --name <name>', 'Project name (folder + npm scope, e.g. my-app)')
90
+ .option('--with-base-system', 'Include base system: login, shared-auth, user/menu management later')
91
+ .option('--no-base-system', 'Bare project without login/auth (default when not specified)')
92
+ .option('--template-dir <dir>', 'Path to scaffold template (default: package bundled template, fallback to <cwd>/scaffold)')
93
+ .action(async (targetDirArg, options) => {
94
+ const cwd = process.cwd();
95
+ let projectName = options.name;
96
+ let withBaseSystem;
97
+ let targetDir;
98
+ const templateDir = options.templateDir
99
+ ? path.resolve(cwd, options.templateDir)
100
+ : getTemplateDir(cwd);
101
+ if (!projectName || !targetDirArg) {
102
+ console.log('\n create-aiko\n');
103
+ const defaultDir = targetDirArg
104
+ ? path.resolve(cwd, targetDirArg)
105
+ : path.join(cwd, projectName ? toScope(projectName) : 'my-app');
106
+ if (!projectName) {
107
+ const defaultName = targetDirArg ? path.basename(path.resolve(cwd, targetDirArg)) : 'my-app';
108
+ projectName = await prompt('Project name (e.g. my-app)', defaultName);
109
+ if (!projectName) {
110
+ console.error('Project name is required.');
111
+ process.exit(1);
112
+ }
113
+ }
114
+ if (!targetDirArg) {
115
+ const dirPromptDefault = defaultDirDisplay(cwd, defaultDir);
116
+ const dirAnswer = await prompt('Destination (folder path for the project)', dirPromptDefault);
117
+ targetDir = path.resolve(cwd, dirAnswer || defaultDir);
118
+ }
119
+ else {
120
+ targetDir = path.resolve(cwd, targetDirArg);
121
+ }
122
+ if (options.withBaseSystem === true)
123
+ withBaseSystem = true;
124
+ else if (options.baseSystem === false)
125
+ withBaseSystem = false;
126
+ else {
127
+ withBaseSystem = await promptConfirm('Include base system (login, shared-auth, user/menu management)?', false);
128
+ }
129
+ }
130
+ else {
131
+ projectName = projectName.trim();
132
+ targetDir = path.resolve(cwd, targetDirArg);
133
+ // --with-base-system -> true; --no-base-system -> baseSystem false; neither -> default bare (false)
134
+ withBaseSystem = options.baseSystem === false ? false : options.withBaseSystem === true;
135
+ }
136
+ const scope = toScope(projectName);
137
+ assertValidScope(scope);
138
+ // If target dir exists and is not empty, create project in a subdir named after scope
139
+ if (await fs.pathExists(targetDir)) {
140
+ const files = await fs.readdir(targetDir);
141
+ if (files.length > 0) {
142
+ const subDir = path.join(targetDir, scope);
143
+ console.log(`\nDestination is not empty; creating project in: ${subDir}`);
144
+ targetDir = subDir;
145
+ }
146
+ }
147
+ console.log('\nOptions:');
148
+ console.log(' Destination:', targetDir);
149
+ console.log(' Scope:', scope, `(@${scope}/*)`);
150
+ console.log(' With base system:', withBaseSystem);
151
+ console.log(' Template:', templateDir);
152
+ try {
153
+ await createScaffold({
154
+ templateDir,
155
+ targetDir,
156
+ scope,
157
+ withBaseSystem,
158
+ });
159
+ console.log('\nDone. Next steps:');
160
+ console.log(` cd ${targetDir}`);
161
+ console.log(' pnpm install');
162
+ if (withBaseSystem) {
163
+ console.log(' pnpm init-db # first time');
164
+ console.log(' pnpm run rebuild:sqlite # if api fails with "bindings file", build better-sqlite3 native');
165
+ }
166
+ console.log(' pnpm dev');
167
+ }
168
+ catch (err) {
169
+ console.error(err);
170
+ process.exit(1);
171
+ }
172
+ });
173
+ program.parse();
174
+ }
@@ -0,0 +1,2 @@
1
+ export { createScaffold, type CreateOptions } from './scaffold.js';
2
+ export { createCommand } from './create.js';
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { createScaffold } from './scaffold.js';
2
+ export { createCommand } from './create.js';
@@ -0,0 +1,7 @@
1
+ export type CreateOptions = {
2
+ templateDir: string;
3
+ targetDir: string;
4
+ scope: string;
5
+ withBaseSystem: boolean;
6
+ };
7
+ export declare function createScaffold(options: CreateOptions): Promise<void>;
@@ -0,0 +1,310 @@
1
+ import path from 'path';
2
+ import fs from 'fs-extra';
3
+ const COPY_IGNORE = [
4
+ 'node_modules',
5
+ '.next',
6
+ 'dist',
7
+ '.pnpm-store',
8
+ '*.tsbuildinfo',
9
+ '.vite',
10
+ '*.log',
11
+ ];
12
+ /** Paths to skip when withBaseSystem is false (relative to scaffold root). */
13
+ const SKIP_WHEN_BARE = [
14
+ 'packages/shared-auth',
15
+ 'packages/api/src/controller/auth.controller.ts',
16
+ 'packages/api/src/service/auth.service.ts',
17
+ 'packages/api/src/dto/auth.dto.ts',
18
+ 'packages/api/src/entity/user.entity.ts',
19
+ 'packages/api/src/mapper/user.mapper.ts',
20
+ 'packages/mobile/src/components/LoginForm.tsx',
21
+ 'packages/mobile/src/pages/LoginPage.tsx',
22
+ 'packages/mobile/src/routes/ProtectedRoute.tsx',
23
+ 'packages/admin/src/components/LoginForm.tsx',
24
+ ];
25
+ const FRAMEWORK_SCOPE = '@ai-partner-x/';
26
+ /** Registry version for @ai-partner-x/*,发布到中央仓库后从此版本安装;本地开发通过 pnpm.overrides 覆盖 */
27
+ const FRAMEWORK_REGISTRY_VERSION = '^0.1.0';
28
+ /** 脚手架中可能用到的框架包名(scope 后缀),用于生成 overrides */
29
+ const FRAMEWORK_PACKAGE_NAMES = [
30
+ 'aiko-boot',
31
+ 'aiko-boot-starter-cache',
32
+ 'aiko-boot-starter-orm',
33
+ 'aiko-boot-starter-validation',
34
+ 'aiko-boot-starter-web',
35
+ 'aiko-boot-starter-storage',
36
+ 'aiko-boot-starter-security',
37
+ ];
38
+ export async function createScaffold(options) {
39
+ const { templateDir, targetDir, scope, withBaseSystem } = options;
40
+ const frameworkRoot = path.dirname(templateDir);
41
+ if (!(await fs.pathExists(templateDir))) {
42
+ throw new Error(`Template directory not found: ${templateDir}. Run from ai-frist-framework root (scaffold/ must exist).`);
43
+ }
44
+ if (await fs.pathExists(targetDir)) {
45
+ const files = await fs.readdir(targetDir);
46
+ if (files.length > 0) {
47
+ throw new Error(`Target directory already exists and is not empty: ${targetDir}`);
48
+ }
49
+ }
50
+ await fs.ensureDir(targetDir);
51
+ await copyRecursive(templateDir, templateDir, targetDir, withBaseSystem);
52
+ await replaceScopeInFiles(targetDir, scope);
53
+ // 依赖写 registry 版本,便于将来从中央仓库安装;本地开发通过根目录 pnpm.overrides 覆盖
54
+ await replaceFrameworkDepsWithRegistryVersion(targetDir);
55
+ await addFrameworkOverridesInRoot(targetDir, frameworkRoot);
56
+ // 使生成的项目成为独立 pnpm workspace,在项目目录内执行 pnpm 时不会回溯到父仓库
57
+ await fs.writeFile(path.join(targetDir, 'pnpm-workspace.yaml'), `packages:
58
+ - 'packages/*'
59
+ `, 'utf-8');
60
+ if (!withBaseSystem) {
61
+ await writeBareTemplates(targetDir, scope);
62
+ }
63
+ // 再次替换,确保子包中 @ai-partner-x/* 均为 registry 版本(与根 pnpm.overrides 配合)
64
+ await replaceFrameworkDepsWithRegistryVersion(targetDir);
65
+ }
66
+ /** 将各 package.json 中 @ai-partner-x/* 的 workspace: 协议改为 registry 版本(如 ^0.1.0),与根目录 pnpm.overrides 配合使用 */
67
+ async function replaceFrameworkDepsWithRegistryVersion(targetDir) {
68
+ const packageJsonPaths = [];
69
+ async function collect(dir) {
70
+ const entries = await fs.readdir(dir, { withFileTypes: true });
71
+ for (const e of entries) {
72
+ const full = path.join(dir, e.name);
73
+ if (e.name === 'package.json') {
74
+ packageJsonPaths.push(full);
75
+ }
76
+ else if (e.isDirectory() && e.name !== 'node_modules' && !e.name.startsWith('.')) {
77
+ await collect(full);
78
+ }
79
+ }
80
+ }
81
+ await collect(targetDir);
82
+ for (const pkgPath of packageJsonPaths) {
83
+ const pkg = await fs.readJson(pkgPath);
84
+ let changed = false;
85
+ for (const key of ['dependencies', 'devDependencies']) {
86
+ if (!pkg[key])
87
+ continue;
88
+ for (const [name, value] of Object.entries(pkg[key])) {
89
+ const isWorkspaceProtocol = typeof value === 'string' && (value === 'workspace:*' || value.startsWith('workspace:'));
90
+ if (name.startsWith(FRAMEWORK_SCOPE) && isWorkspaceProtocol) {
91
+ pkg[key][name] = FRAMEWORK_REGISTRY_VERSION;
92
+ changed = true;
93
+ }
94
+ }
95
+ }
96
+ if (changed)
97
+ await fs.writeJson(pkgPath, pkg, { spaces: 2 });
98
+ }
99
+ }
100
+ /** 在根 package.json 中增加 pnpm.overrides,指向本地框架路径;需要从中央仓库安装时删除该段即可 */
101
+ async function addFrameworkOverridesInRoot(targetDir, frameworkRoot) {
102
+ const frameworkPackagesDir = path.join(frameworkRoot, 'packages');
103
+ if (!(await fs.pathExists(frameworkPackagesDir))) {
104
+ return;
105
+ }
106
+ const rootPkgPath = path.join(targetDir, 'package.json');
107
+ const rootPkg = await fs.readJson(rootPkgPath);
108
+ const relativeToFramework = path.relative(targetDir, frameworkRoot).replace(/\\/g, '/');
109
+ const filePrefix = relativeToFramework.startsWith('.') ? relativeToFramework : `./${relativeToFramework}`;
110
+ const overrides = {};
111
+ for (const pkgName of FRAMEWORK_PACKAGE_NAMES) {
112
+ overrides[`${FRAMEWORK_SCOPE}${pkgName}`] = `file:${filePrefix}/packages/${pkgName}`;
113
+ }
114
+ rootPkg.pnpm = { ...rootPkg.pnpm, overrides };
115
+ await fs.writeJson(rootPkgPath, rootPkg, { spaces: 2 });
116
+ }
117
+ function shouldIgnore(name) {
118
+ if (COPY_IGNORE.some((x) => x.startsWith('*') && name.endsWith(x.slice(1))))
119
+ return true;
120
+ if (COPY_IGNORE.includes(name))
121
+ return true;
122
+ return false;
123
+ }
124
+ function shouldSkipWhenBare(relativePath) {
125
+ const normalized = relativePath.replace(/\\/g, '/');
126
+ return SKIP_WHEN_BARE.some((skip) => normalized === skip || normalized.startsWith(skip + '/'));
127
+ }
128
+ async function copyRecursive(templateRoot, src, dest, withBaseSystem) {
129
+ const entries = await fs.readdir(src, { withFileTypes: true });
130
+ for (const entry of entries) {
131
+ const srcPath = path.join(src, entry.name);
132
+ const destPath = path.join(dest, entry.name);
133
+ const relativePath = path.relative(templateRoot, srcPath).replace(/\\/g, '/');
134
+ if (shouldIgnore(entry.name))
135
+ continue;
136
+ if (!withBaseSystem && shouldSkipWhenBare(relativePath))
137
+ continue;
138
+ if (entry.isDirectory()) {
139
+ await fs.ensureDir(destPath);
140
+ await copyRecursive(templateRoot, srcPath, destPath, withBaseSystem);
141
+ }
142
+ else {
143
+ await fs.copy(srcPath, destPath);
144
+ }
145
+ }
146
+ }
147
+ async function replaceScopeInFiles(dir, scope) {
148
+ const entries = await fs.readdir(dir, { withFileTypes: true });
149
+ for (const entry of entries) {
150
+ const full = path.join(dir, entry.name);
151
+ if (entry.isDirectory() && !shouldIgnore(entry.name)) {
152
+ await replaceScopeInFiles(full, scope);
153
+ }
154
+ else if (entry.isFile()) {
155
+ const ext = path.extname(entry.name).toLowerCase();
156
+ if (!['.ts', '.tsx', '.js', '.jsx', '.json', '.md', '.mjs', '.cjs', '.css', '.html'].includes(ext))
157
+ continue;
158
+ let content = await fs.readFile(full, 'utf-8');
159
+ const before = content;
160
+ content = content.replace(/@scaffold\//g, `@${scope}/`);
161
+ content = content.replace(/"@scaffold\//g, `"@${scope}/`);
162
+ content = content.replace(/scaffold-monorepo/g, `${scope}-monorepo`);
163
+ content = content.replace(/--filter "@scaffold\/\*"/g, `--filter "@${scope}/*"`);
164
+ content = content.replace(/-F @scaffold\//g, `-F @${scope}/`);
165
+ if (content !== before)
166
+ await fs.writeFile(full, content, 'utf-8');
167
+ }
168
+ }
169
+ }
170
+ /** Write bare (no auth) template files when withBaseSystem is false. */
171
+ async function writeBareTemplates(targetDir, scope) {
172
+ const packagesDir = path.join(targetDir, 'packages');
173
+ await fs.writeFile(path.join(packagesDir, 'api/src/scripts/init-db.ts'), `/**
174
+ * Initialize SQLite database (bare scaffold, no user table).
175
+ */
176
+ import { fileURLToPath } from 'url';
177
+ import { dirname, join } from 'path';
178
+ import { writeFileSync, mkdirSync, existsSync } from 'fs';
179
+ // @ts-expect-error sql.js has no types
180
+ import initSqlJs from 'sql.js';
181
+
182
+ const __dirname = dirname(fileURLToPath(import.meta.url));
183
+ const dbPath = join(__dirname, '../../data/app.db');
184
+
185
+ console.log('📁 Database path:', dbPath);
186
+
187
+ const SQL = await initSqlJs();
188
+ const db = new SQL.Database();
189
+
190
+ // Add your tables here when needed.
191
+
192
+ const data = db.export();
193
+ db.close();
194
+
195
+ const dir = dirname(dbPath);
196
+ if (!existsSync(dir)) {
197
+ mkdirSync(dir, { recursive: true });
198
+ }
199
+ writeFileSync(dbPath, Buffer.from(data));
200
+
201
+ console.log('\\n🎉 Database initialization complete!');
202
+ `, 'utf-8');
203
+ await fs.writeFile(path.join(packagesDir, 'shared/src/constants.ts'), `/** API base URL env key (admin: VITE_API_URL, mobile: etc.) */
204
+ export const API_BASE_URL_KEY = 'API_URL';
205
+
206
+ /** Default API base URL */
207
+ export const DEFAULT_API_BASE_URL = 'http://localhost:3001';
208
+ `, 'utf-8');
209
+ await fs.writeFile(path.join(packagesDir, 'shared/src/index.ts'), `export {
210
+ API_BASE_URL_KEY,
211
+ DEFAULT_API_BASE_URL,
212
+ } from './constants';
213
+ `, 'utf-8');
214
+ const mobileMain = `import { StrictMode } from 'react';
215
+ import { createRoot } from 'react-dom/client';
216
+ import App from './App';
217
+ import './app/globals.css';
218
+
219
+ createRoot(document.getElementById('root')!).render(
220
+ <StrictMode>
221
+ <App />
222
+ </StrictMode>
223
+ );
224
+ `;
225
+ await fs.writeFile(path.join(packagesDir, 'mobile/src/main.tsx'), mobileMain, 'utf-8');
226
+ const mobileRoutesIndex = `import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
227
+ import { HomePage } from '@/pages/HomePage';
228
+ import { ROUTES } from './routes';
229
+
230
+ export function AppRouter() {
231
+ return (
232
+ <BrowserRouter>
233
+ <Routes>
234
+ <Route path={ROUTES.HOME} element={<HomePage />} />
235
+ <Route path="*" element={<Navigate to={ROUTES.HOME} replace />} />
236
+ </Routes>
237
+ </BrowserRouter>
238
+ );
239
+ }
240
+ `;
241
+ await fs.writeFile(path.join(packagesDir, 'mobile/src/routes/index.tsx'), mobileRoutesIndex, 'utf-8');
242
+ await fs.writeFile(path.join(packagesDir, 'mobile/src/routes/routes.ts'), `export const ROUTES = {
243
+ HOME: '/',
244
+ } as const;
245
+
246
+ export type RoutePath = (typeof ROUTES)[keyof typeof ROUTES];
247
+ `, 'utf-8');
248
+ const homePage = `/**
249
+ * Mobile home page (bare scaffold).
250
+ */
251
+ export function HomePage() {
252
+ return (
253
+ <div className="min-h-screen bg-gray-50 flex flex-col">
254
+ <header className="flex items-center justify-between px-4 py-3 bg-white border-b border-gray-200 safe-area-top">
255
+ <span className="text-lg font-medium text-gray-800">AIKO-BOOT</span>
256
+ </header>
257
+ <main className="flex-1 flex flex-col items-center justify-center px-4">
258
+ <h1 className="text-2xl font-semibold text-gray-900 mb-1">AIKO-BOOT</h1>
259
+ <p className="text-gray-500 text-sm">Scaffold ready. Add your pages.</p>
260
+ </main>
261
+ </div>
262
+ );
263
+ }
264
+ `;
265
+ await fs.writeFile(path.join(packagesDir, 'mobile/src/pages/HomePage.tsx'), homePage, 'utf-8');
266
+ await fs.writeFile(path.join(packagesDir, 'mobile/src/pages/index.ts'), `export { HomePage } from './HomePage';
267
+ `, 'utf-8');
268
+ const adminMain = `import { StrictMode } from 'react';
269
+ import { createRoot } from 'react-dom/client';
270
+ import App from './App';
271
+ import './index.css';
272
+
273
+ createRoot(document.getElementById('root')!).render(
274
+ <StrictMode>
275
+ <App />
276
+ </StrictMode>
277
+ );
278
+ `;
279
+ await fs.writeFile(path.join(packagesDir, 'admin/src/main.tsx'), adminMain, 'utf-8');
280
+ const adminApp = `export default function App() {
281
+ return (
282
+ <div className="min-h-screen flex items-center justify-center bg-gray-100">
283
+ <p className="text-gray-600">Scaffold Admin — add your pages.</p>
284
+ </div>
285
+ );
286
+ }
287
+ `;
288
+ await fs.writeFile(path.join(packagesDir, 'admin/src/App.tsx'), adminApp, 'utf-8');
289
+ const sharedAuthPkg = `@${scope}/shared-auth`;
290
+ const mobilePkgPath = path.join(packagesDir, 'mobile/package.json');
291
+ const mobilePkg = await fs.readJson(mobilePkgPath);
292
+ if (mobilePkg.dependencies) {
293
+ delete mobilePkg.dependencies[sharedAuthPkg];
294
+ mobilePkg.dependencies = Object.fromEntries(Object.entries(mobilePkg.dependencies).filter(([k]) => k !== sharedAuthPkg));
295
+ }
296
+ await fs.writeJson(mobilePkgPath, mobilePkg, { spaces: 2 });
297
+ const adminPkgPath = path.join(packagesDir, 'admin/package.json');
298
+ const adminPkg = await fs.readJson(adminPkgPath);
299
+ if (adminPkg.dependencies) {
300
+ delete adminPkg.dependencies[sharedAuthPkg];
301
+ adminPkg.dependencies = Object.fromEntries(Object.entries(adminPkg.dependencies).filter(([k]) => k !== sharedAuthPkg));
302
+ }
303
+ await fs.writeJson(adminPkgPath, adminPkg, { spaces: 2 });
304
+ const mobileVitePath = path.join(packagesDir, 'mobile/vite.config.ts');
305
+ if (await fs.pathExists(mobileVitePath)) {
306
+ let viteContent = await fs.readFile(mobileVitePath, 'utf-8');
307
+ viteContent = viteContent.replace(/\s*exclude:\s*\[\s*'@[^']+\/shared-auth'\s*\],?\s*/g, '\n');
308
+ await fs.writeFile(mobileVitePath, viteContent, 'utf-8');
309
+ }
310
+ }
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "create-aiko",
3
+ "version": "0.1.0",
4
+ "description": "CLI to create aiko-boot scaffold project (monorepo with api, admin, mobile, shared)",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "bin": {
9
+ "create-aiko": "./dist/cli.js"
10
+ },
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "default": "./dist/index.js"
15
+ }
16
+ },
17
+ "files": [
18
+ "dist",
19
+ "template"
20
+ ],
21
+ "scripts": {
22
+ "build": "tsc && node ./scripts/build-template.mjs",
23
+ "dev": "tsc --watch"
24
+ },
25
+ "dependencies": {
26
+ "commander": "^12.1.0",
27
+ "fs-extra": "^11.2.0"
28
+ },
29
+ "devDependencies": {
30
+ "@types/fs-extra": "^11.0.4",
31
+ "@types/node": "^20.11.0",
32
+ "typescript": "^5.3.0"
33
+ },
34
+ "engines": {
35
+ "node": ">=18.0.0"
36
+ }
37
+ }
@@ -0,0 +1,63 @@
1
+ # Scaffold Monorepo
2
+
3
+ 用于发布项目初始化模板的干净脚手架,包含:
4
+
5
+ - `api`
6
+ - `admin`
7
+ - `mobile`
8
+ - `shared`
9
+ - `shared-auth`
10
+
11
+ 这份模板聚焦在“可运行项目骨架”和“可复用后台组件能力”,不再承载需求驱动生成器、spec 规则和实验性产物。
12
+
13
+ ## 快速启动
14
+
15
+ ```bash
16
+ cd scaffold
17
+ pnpm install
18
+ pnpm init-db
19
+ pnpm dev
20
+ ```
21
+
22
+ 默认地址:
23
+
24
+ - API: `http://localhost:3001/api`
25
+ - Admin: `http://localhost:5173`
26
+ - Mobile: `http://localhost:3002`
27
+
28
+ 默认测试账号:
29
+
30
+ - 用户名:`admin`
31
+ - 密码:`admin123`
32
+
33
+ ## 目录结构
34
+
35
+ ```text
36
+ scaffold/
37
+ ├── packages/
38
+ │ ├── api
39
+ │ ├── admin
40
+ │ ├── mobile
41
+ │ ├── shared
42
+ │ └── shared-auth
43
+ ├── scripts/
44
+ └── package.json
45
+ ```
46
+
47
+ ## 常用命令
48
+
49
+ ```bash
50
+ pnpm dev
51
+ pnpm dev:api
52
+ pnpm dev:admin
53
+ pnpm dev:mobile
54
+ pnpm init-db
55
+ pnpm build
56
+ pnpm lint
57
+ ```
58
+
59
+ 如果 `better-sqlite3` 原生模块异常,可执行:
60
+
61
+ ```bash
62
+ pnpm run rebuild:sqlite
63
+ ```