@ai-partner-x/aiko-boot-cli 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +187 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +30 -0
- package/dist/commands/add-api.d.ts +5 -0
- package/dist/commands/add-api.js +34 -0
- package/dist/commands/add-app.d.ts +5 -0
- package/dist/commands/add-app.js +34 -0
- package/dist/commands/add-feature.d.ts +5 -0
- package/dist/commands/add-feature.js +32 -0
- package/dist/commands/init.d.ts +7 -0
- package/dist/commands/init.js +42 -0
- package/dist/commands/list.d.ts +6 -0
- package/dist/commands/list.js +36 -0
- package/dist/core/framework-version.d.ts +8 -0
- package/dist/core/framework-version.js +40 -0
- package/dist/core/logger.d.ts +6 -0
- package/dist/core/logger.js +16 -0
- package/dist/core/project-config.d.ts +21 -0
- package/dist/core/project-config.js +17 -0
- package/dist/core/prompts.d.ts +5 -0
- package/dist/core/prompts.js +43 -0
- package/dist/core/template-utils.d.ts +1 -0
- package/dist/core/template-utils.js +42 -0
- package/dist/core/workspace.d.ts +10 -0
- package/dist/core/workspace.js +141 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/scaffold.d.ts +7 -0
- package/dist/scaffold.js +272 -0
- package/dist/usecases/add-api.usecase.d.ts +16 -0
- package/dist/usecases/add-api.usecase.js +87 -0
- package/dist/usecases/add-app.usecase.d.ts +16 -0
- package/dist/usecases/add-app.usecase.js +101 -0
- package/dist/usecases/add-feature.usecase.d.ts +15 -0
- package/dist/usecases/add-feature.usecase.js +566 -0
- package/dist/usecases/init-scaffold.usecase.d.ts +19 -0
- package/dist/usecases/init-scaffold.usecase.js +131 -0
- package/package.json +43 -0
- package/templates/api-base/app.config.ts +155 -0
- package/templates/api-base/package.json +55 -0
- package/templates/api-base/scripts/codegen.cjs +30 -0
- package/templates/api-base/scripts/codegen.ts +10 -0
- package/templates/api-base/src/controller/auth.controller.ts +160 -0
- package/templates/api-base/src/controller/menu.controller.ts +56 -0
- package/templates/api-base/src/controller/role.controller.ts +62 -0
- package/templates/api-base/src/controller/user.controller.ts +75 -0
- package/templates/api-base/src/dto/auth.dto.ts +31 -0
- package/templates/api-base/src/dto/menu.dto.ts +38 -0
- package/templates/api-base/src/dto/role.dto.ts +18 -0
- package/templates/api-base/src/dto/user.dto.ts +36 -0
- package/templates/api-base/src/entity/menu.entity.ts +35 -0
- package/templates/api-base/src/entity/role-menu.entity.ts +14 -0
- package/templates/api-base/src/entity/role.entity.ts +23 -0
- package/templates/api-base/src/entity/user-role.entity.ts +14 -0
- package/templates/api-base/src/entity/user.entity.ts +32 -0
- package/templates/api-base/src/mapper/menu.mapper.ts +7 -0
- package/templates/api-base/src/mapper/role-menu.mapper.ts +7 -0
- package/templates/api-base/src/mapper/role.mapper.ts +7 -0
- package/templates/api-base/src/mapper/user-role.mapper.ts +7 -0
- package/templates/api-base/src/mapper/user.mapper.ts +12 -0
- package/templates/api-base/src/scripts/init-db.ts +204 -0
- package/templates/api-base/src/server.ts +69 -0
- package/templates/api-base/src/service/auth.service.ts +144 -0
- package/templates/api-base/src/service/log.request.service.ts +72 -0
- package/templates/api-base/src/service/menu.service.ts +94 -0
- package/templates/api-base/src/service/role.service.ts +88 -0
- package/templates/api-base/src/service/user.service.ts +175 -0
- package/templates/api-base/src/utils/jwt.util.ts +39 -0
- package/templates/api-base/tsconfig.json +18 -0
- package/templates/feature-file/api/upload.controller.ts +97 -0
- package/templates/feature-log/api/docs/log-integration-guide.md +54 -0
- package/templates/feature-log/api/src/service/log.request.service.ts +112 -0
- package/templates/feature-log/api/src/service/log.service.ts +124 -0
- package/templates/feature-mq/api/src/controller/mq.controller.ts +35 -0
- package/templates/feature-mq/api/src/dto/mq.dto.ts +16 -0
- package/templates/feature-mq/api/src/service/mq.consumer.service.ts +26 -0
- package/templates/feature-redis/api/src/controller/cache.controller.ts +107 -0
- package/templates/feature-redis/api/src/dto/cache.dto.ts +24 -0
- package/templates/feature-redis/api/src/service/cache.service.ts +80 -0
- package/templates/scaffold-default/README.md +114 -0
- package/templates/scaffold-default/package.json +26 -0
- package/templates/scaffold-default/packages/admin/.env.dev +1 -0
- package/templates/scaffold-default/packages/admin/.env.prod +4 -0
- package/templates/scaffold-default/packages/admin/.env.stage +4 -0
- package/templates/scaffold-default/packages/admin/Dockerfile +37 -0
- package/templates/scaffold-default/packages/admin/README.MD +27 -0
- package/templates/scaffold-default/packages/admin/components.json +21 -0
- package/templates/scaffold-default/packages/admin/eslint.config.js +28 -0
- package/templates/scaffold-default/packages/admin/index.html +50 -0
- package/templates/scaffold-default/packages/admin/package.json +100 -0
- package/templates/scaffold-default/packages/admin/public/vite.svg +1 -0
- package/templates/scaffold-default/packages/admin/src/App.css +82 -0
- package/templates/scaffold-default/packages/admin/src/App.tsx +128 -0
- package/templates/scaffold-default/packages/admin/src/app.config.ts +3 -0
- package/templates/scaffold-default/packages/admin/src/components/admin-ui/data-table/data-table-pagination.tsx +148 -0
- package/templates/scaffold-default/packages/admin/src/components/admin-ui/data-table/data-table-sorter.tsx +50 -0
- package/templates/scaffold-default/packages/admin/src/components/admin-ui/data-table/index.tsx +266 -0
- package/templates/scaffold-default/packages/admin/src/components/admin-ui/editable-table.tsx +292 -0
- package/templates/scaffold-default/packages/admin/src/components/admin-ui/form/input-password.tsx +38 -0
- package/templates/scaffold-default/packages/admin/src/components/admin-ui/form/sign-in-form.tsx +118 -0
- package/templates/scaffold-default/packages/admin/src/components/admin-ui/layout/error-component.tsx +71 -0
- package/templates/scaffold-default/packages/admin/src/components/admin-ui/layout/header.tsx +162 -0
- package/templates/scaffold-default/packages/admin/src/components/admin-ui/layout/language-switcher.tsx +47 -0
- package/templates/scaffold-default/packages/admin/src/components/admin-ui/layout/layout.tsx +42 -0
- package/templates/scaffold-default/packages/admin/src/components/admin-ui/layout/loading-overlay.tsx +36 -0
- package/templates/scaffold-default/packages/admin/src/components/admin-ui/layout/shell-bar.tsx +232 -0
- package/templates/scaffold-default/packages/admin/src/components/admin-ui/layout/sidebar.tsx +193 -0
- package/templates/scaffold-default/packages/admin/src/components/admin-ui/layout/user-avatar.tsx +31 -0
- package/templates/scaffold-default/packages/admin/src/components/admin-ui/list-report.tsx +306 -0
- package/templates/scaffold-default/packages/admin/src/components/admin-ui/master-detail.tsx +382 -0
- package/templates/scaffold-default/packages/admin/src/components/admin-ui/notification/toaster.tsx +23 -0
- package/templates/scaffold-default/packages/admin/src/components/admin-ui/notification/undoable-notification.tsx +84 -0
- package/templates/scaffold-default/packages/admin/src/components/admin-ui/object-page.tsx +539 -0
- package/templates/scaffold-default/packages/admin/src/components/admin-ui/theme/theme-provider.tsx +160 -0
- package/templates/scaffold-default/packages/admin/src/components/admin-ui/theme/theme-select.tsx +129 -0
- package/templates/scaffold-default/packages/admin/src/components/admin-ui/theme/theme-toggle.tsx +90 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/accordion.tsx +64 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/alert-dialog.tsx +157 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/alert.tsx +66 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/aspect-ratio.tsx +9 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/avatar.tsx +53 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/badge.tsx +47 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/breadcrumb.tsx +111 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/button.tsx +59 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/calendar.tsx +74 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/card.tsx +92 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/carousel.tsx +237 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/chart.tsx +351 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/checkbox.tsx +32 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/collapsible.tsx +33 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/command.tsx +182 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/context-menu.tsx +252 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/dialog.tsx +141 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/drawer.tsx +130 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/dropdown-menu.tsx +255 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/form.tsx +166 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/hover-card.tsx +42 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/input-otp.tsx +77 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/input.tsx +21 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/label.tsx +22 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/menubar.tsx +274 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/navigation-menu.tsx +168 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/pagination.tsx +127 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/popover.tsx +48 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/progress.tsx +29 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/radio-group.tsx +45 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/resizable.tsx +54 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/scroll-area.tsx +58 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/select.tsx +183 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/separator.tsx +26 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/sheet.tsx +139 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/sidebar.tsx +740 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/skeleton.tsx +13 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/slider.tsx +63 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/sonner.tsx +23 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/switch.tsx +31 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/table.tsx +114 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/tabs.tsx +66 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/textarea.tsx +18 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/toggle-group.tsx +73 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/toggle.tsx +45 -0
- package/templates/scaffold-default/packages/admin/src/components/ui/tooltip.tsx +59 -0
- package/templates/scaffold-default/packages/admin/src/hooks/use-mobile.ts +21 -0
- package/templates/scaffold-default/packages/admin/src/i18n.ts +20 -0
- package/templates/scaffold-default/packages/admin/src/index.tsx +19 -0
- package/templates/scaffold-default/packages/admin/src/layouts/menu-layout.tsx +211 -0
- package/templates/scaffold-default/packages/admin/src/layouts/tile-layout.tsx +355 -0
- package/templates/scaffold-default/packages/admin/src/lib/utils.ts +6 -0
- package/templates/scaffold-default/packages/admin/src/locales/en.json +68 -0
- package/templates/scaffold-default/packages/admin/src/locales/zh.json +68 -0
- package/templates/scaffold-default/packages/admin/src/pages/dashboard.tsx +12 -0
- package/templates/scaffold-default/packages/admin/src/pages/goods-receipt/CreatePage.tsx +302 -0
- package/templates/scaffold-default/packages/admin/src/pages/goods-receipt/EditPage.tsx +221 -0
- package/templates/scaffold-default/packages/admin/src/pages/goods-receipt/ListPage.tsx +283 -0
- package/templates/scaffold-default/packages/admin/src/pages/goods-receipt/ViewPage.tsx +280 -0
- package/templates/scaffold-default/packages/admin/src/pages/goods-receipt/index.ts +4 -0
- package/templates/scaffold-default/packages/admin/src/pages/home-page.tsx +244 -0
- package/templates/scaffold-default/packages/admin/src/pages/master-data/cost-centers/index.tsx +461 -0
- package/templates/scaffold-default/packages/admin/src/pages/master-data/currencies/index.tsx +255 -0
- package/templates/scaffold-default/packages/admin/src/pages/master-data/materials/ListPage.tsx +271 -0
- package/templates/scaffold-default/packages/admin/src/pages/master-data/materials/ViewPage.tsx +240 -0
- package/templates/scaffold-default/packages/admin/src/pages/master-data/materials/index.ts +2 -0
- package/templates/scaffold-default/packages/admin/src/pages/master-data/plants/ListPage.tsx +279 -0
- package/templates/scaffold-default/packages/admin/src/pages/master-data/plants/ViewPage.tsx +380 -0
- package/templates/scaffold-default/packages/admin/src/pages/master-data/plants/index.ts +2 -0
- package/templates/scaffold-default/packages/admin/src/pages/master-data/purchase-organizations/index.tsx +341 -0
- package/templates/scaffold-default/packages/admin/src/pages/master-data/units-of-measure/index.tsx +295 -0
- package/templates/scaffold-default/packages/admin/src/pages/master-data/vendors/ListPage.tsx +266 -0
- package/templates/scaffold-default/packages/admin/src/pages/master-data/vendors/ViewPage.tsx +274 -0
- package/templates/scaffold-default/packages/admin/src/pages/master-data/vendors/index.ts +2 -0
- package/templates/scaffold-default/packages/admin/src/pages/placeholder-page.tsx +13 -0
- package/templates/scaffold-default/packages/admin/src/pages/purchase-orders/ListPage.tsx +289 -0
- package/templates/scaffold-default/packages/admin/src/pages/purchase-orders/ViewPage.tsx +343 -0
- package/templates/scaffold-default/packages/admin/src/pages/purchase-orders/index.ts +2 -0
- package/templates/scaffold-default/packages/admin/src/pages/purchase-requisitions/CreatePage.tsx +398 -0
- package/templates/scaffold-default/packages/admin/src/pages/purchase-requisitions/EditPage.tsx +473 -0
- package/templates/scaffold-default/packages/admin/src/pages/purchase-requisitions/ListPage.tsx +307 -0
- package/templates/scaffold-default/packages/admin/src/pages/purchase-requisitions/ViewPage.tsx +304 -0
- package/templates/scaffold-default/packages/admin/src/pages/purchase-requisitions/constants.ts +51 -0
- package/templates/scaffold-default/packages/admin/src/pages/purchase-requisitions/index.ts +4 -0
- package/templates/scaffold-default/packages/admin/src/pages/reports/PurchaseOrderReport.tsx +312 -0
- package/templates/scaffold-default/packages/admin/src/pages/reports/PurchaseRequisitionReport.tsx +303 -0
- package/templates/scaffold-default/packages/admin/src/pages/reports/index.ts +2 -0
- package/templates/scaffold-default/packages/admin/src/pages/settings-page.tsx +335 -0
- package/templates/scaffold-default/packages/admin/src/providers/app-config.tsx +50 -0
- package/templates/scaffold-default/packages/admin/src/providers/auth-provider.ts +2 -0
- package/templates/scaffold-default/packages/admin/src/routes/auth.ts +9 -0
- package/templates/scaffold-default/packages/admin/src/routes/index.ts +85 -0
- package/templates/scaffold-default/packages/admin/src/routes/menu.ts +176 -0
- package/templates/scaffold-default/packages/admin/src/routes/modules/goods-receipt.ts +31 -0
- package/templates/scaffold-default/packages/admin/src/routes/modules/master-data.ts +41 -0
- package/templates/scaffold-default/packages/admin/src/routes/modules/purchase-orders.ts +27 -0
- package/templates/scaffold-default/packages/admin/src/routes/modules/purchase-requisitions.ts +39 -0
- package/templates/scaffold-default/packages/admin/src/routes/modules/reports.ts +33 -0
- package/templates/scaffold-default/packages/admin/src/routes/modules/settings.ts +19 -0
- package/templates/scaffold-default/packages/admin/src/routes/withSuspense.tsx +21 -0
- package/templates/scaffold-default/packages/admin/src/theme/amber.css +27 -0
- package/templates/scaffold-default/packages/admin/src/theme/blue.css +27 -0
- package/templates/scaffold-default/packages/admin/src/theme/default.css +75 -0
- package/templates/scaffold-default/packages/admin/src/theme/fiori.css +180 -0
- package/templates/scaffold-default/packages/admin/src/theme/green.css +27 -0
- package/templates/scaffold-default/packages/admin/src/theme/index.css +12 -0
- package/templates/scaffold-default/packages/admin/src/theme/rose.css +27 -0
- package/templates/scaffold-default/packages/admin/src/theme/violet.css +27 -0
- package/templates/scaffold-default/packages/admin/src/vite-env.d.ts +1 -0
- package/templates/scaffold-default/packages/admin/tsconfig.json +28 -0
- package/templates/scaffold-default/packages/admin/tsconfig.node.json +21 -0
- package/templates/scaffold-default/packages/admin/vite.config.ts +26 -0
- package/templates/scaffold-default/packages/api/.eslintrc.json +6 -0
- package/templates/scaffold-default/packages/api/.swcrc +17 -0
- package/templates/scaffold-default/packages/api/app.config.ts +163 -0
- package/templates/scaffold-default/packages/api/docs/api-document.md +497 -0
- package/templates/scaffold-default/packages/api/docs/final-completion-report.md +565 -0
- package/templates/scaffold-default/packages/api/docs/permission-integration-summary.md +432 -0
- package/templates/scaffold-default/packages/api/examples/security/README.md +664 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/.env.example +26 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/PROJECT_STRUCTURE.md +220 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/README.md +847 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/app.config.ts +69 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/app.ts +63 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/controller/auth.controller.ts +131 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/controller/index.ts +4 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/controller/permission.controller.ts +41 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/controller/role.controller.ts +53 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/controller/user.controller.ts +53 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/dto/change-password.dto.ts +10 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/dto/create-permission.dto.ts +14 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/dto/create-role.dto.ts +11 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/dto/create-user.dto.ts +15 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/dto/index.ts +7 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/dto/login.dto.ts +10 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/dto/oauth-profile.dto.ts +7 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/dto/register.dto.ts +17 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/entity/index.ts +6 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/entity/oauth-account.entity.ts +39 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/entity/permission.entity.ts +31 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/entity/role-permission.entity.ts +19 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/entity/role.entity.ts +25 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/entity/user-role.entity.ts +19 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/entity/user.entity.ts +46 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/init.sql +81 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/middleware/auth.interceptor.ts +39 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/middleware/index.ts +2 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/middleware/permission.interceptor.ts +61 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/package.json +54 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/seed.sql +42 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/service/auth.service.ts +41 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/service/index.ts +5 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/service/oauth.service.ts +82 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/service/permission.service.ts +113 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/service/role.service.ts +85 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/service/user.service.ts +132 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/tests/TEST_REPORT.md +318 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/tests/generate-report.js +335 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/tests/helpers/api-helpers.ts +116 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/tests/helpers/index.ts +2 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/tests/helpers/test-helpers.ts +129 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/tests/integration/auth.api.test.ts +429 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/tests/integration/role.api.test.ts +400 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/tests/integration/user.api.test.ts +459 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/tests/jest.config.js +40 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/tests/run-all-tests.js +135 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/tests/run-tests.js +109 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/tests/setup.ts +19 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/tests/unit/auth.service.test.ts +199 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/tests/unit/permission.service.test.ts +377 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/tests/unit/user.service.test.ts +288 -0
- package/templates/scaffold-default/packages/api/examples/security/complete/tsconfig.json +35 -0
- package/templates/scaffold-default/packages/api/examples/security/jwt/README.md +424 -0
- package/templates/scaffold-default/packages/api/examples/security/local/README.md +499 -0
- package/templates/scaffold-default/packages/api/examples/security/oauth2/README.md +637 -0
- package/templates/scaffold-default/packages/api/examples/security/permission/README.md +943 -0
- package/templates/scaffold-default/packages/api/examples/security/session/README.md +753 -0
- package/templates/scaffold-default/packages/api/package.json +63 -0
- package/templates/scaffold-default/packages/api/scripts/codegen.cjs +29 -0
- package/templates/scaffold-default/packages/api/scripts/codegen.ts +9 -0
- package/templates/scaffold-default/packages/api/src/config/security-auto-configuration.ts +75 -0
- package/templates/scaffold-default/packages/api/src/controller/auth.controller.ts +109 -0
- package/templates/scaffold-default/packages/api/src/controller/cache.controller.ts +106 -0
- package/templates/scaffold-default/packages/api/src/controller/menu.controller.ts +86 -0
- package/templates/scaffold-default/packages/api/src/controller/mq.controller.ts +35 -0
- package/templates/scaffold-default/packages/api/src/controller/role.controller.ts +100 -0
- package/templates/scaffold-default/packages/api/src/controller/upload.controller.ts +83 -0
- package/templates/scaffold-default/packages/api/src/controller/user.controller.ts +102 -0
- package/templates/scaffold-default/packages/api/src/dto/auth.dto.ts +30 -0
- package/templates/scaffold-default/packages/api/src/dto/cache.dto.ts +24 -0
- package/templates/scaffold-default/packages/api/src/dto/menu.dto.ts +37 -0
- package/templates/scaffold-default/packages/api/src/dto/mq.dto.ts +16 -0
- package/templates/scaffold-default/packages/api/src/dto/role.dto.ts +16 -0
- package/templates/scaffold-default/packages/api/src/dto/user.dto.ts +35 -0
- package/templates/scaffold-default/packages/api/src/entity/menu.entity.ts +34 -0
- package/templates/scaffold-default/packages/api/src/entity/role-menu.entity.ts +13 -0
- package/templates/scaffold-default/packages/api/src/entity/role.entity.ts +22 -0
- package/templates/scaffold-default/packages/api/src/entity/user-role.entity.ts +13 -0
- package/templates/scaffold-default/packages/api/src/entity/user.entity.ts +31 -0
- package/templates/scaffold-default/packages/api/src/mapper/menu.mapper.ts +6 -0
- package/templates/scaffold-default/packages/api/src/mapper/role-menu.mapper.ts +6 -0
- package/templates/scaffold-default/packages/api/src/mapper/role.mapper.ts +6 -0
- package/templates/scaffold-default/packages/api/src/mapper/user-role.mapper.ts +6 -0
- package/templates/scaffold-default/packages/api/src/mapper/user.mapper.ts +11 -0
- package/templates/scaffold-default/packages/api/src/scripts/assign-role.ts +41 -0
- package/templates/scaffold-default/packages/api/src/scripts/check-user-role.ts +28 -0
- package/templates/scaffold-default/packages/api/src/scripts/check-users.mjs +44 -0
- package/templates/scaffold-default/packages/api/src/scripts/demo-permissions.mjs +418 -0
- package/templates/scaffold-default/packages/api/src/scripts/init-db.ts +166 -0
- package/templates/scaffold-default/packages/api/src/scripts/reset-admin-password.mjs +70 -0
- package/templates/scaffold-default/packages/api/src/scripts/reset-password.ts +31 -0
- package/templates/scaffold-default/packages/api/src/scripts/simple-reset-admin.mjs +39 -0
- package/templates/scaffold-default/packages/api/src/scripts/test-db.ts +36 -0
- package/templates/scaffold-default/packages/api/src/scripts/test-di.ts +45 -0
- package/templates/scaffold-default/packages/api/src/scripts/test-permissions.mjs +551 -0
- package/templates/scaffold-default/packages/api/src/scripts/update-admin-password.mjs +56 -0
- package/templates/scaffold-default/packages/api/src/scripts/user-roles.ts +28 -0
- package/templates/scaffold-default/packages/api/src/server.ts +38 -0
- package/templates/scaffold-default/packages/api/src/service/auth.service.ts +165 -0
- package/templates/scaffold-default/packages/api/src/service/cache.service.ts +80 -0
- package/templates/scaffold-default/packages/api/src/service/log.request.service.ts +158 -0
- package/templates/scaffold-default/packages/api/src/service/log.service.ts +123 -0
- package/templates/scaffold-default/packages/api/src/service/menu.service.ts +94 -0
- package/templates/scaffold-default/packages/api/src/service/mq.consumer.service.ts +26 -0
- package/templates/scaffold-default/packages/api/src/service/role.service.ts +88 -0
- package/templates/scaffold-default/packages/api/src/service/user.service.ts +195 -0
- package/templates/scaffold-default/packages/api/src/types/sqljs.d.ts +18 -0
- package/templates/scaffold-default/packages/api/src/utils/auth.utils.js +0 -0
- package/templates/scaffold-default/packages/api/src/utils/jwt.util.ts +29 -0
- package/templates/scaffold-default/packages/api/tsconfig.json +17 -0
- package/templates/scaffold-default/packages/api/tsup.config.ts +14 -0
- package/templates/scaffold-default/packages/api/uploads/.gitkeep +0 -0
- package/templates/scaffold-default/packages/core/package.json +28 -0
- package/templates/scaffold-default/packages/core/src/auth/auth-client-middleware.ts +22 -0
- package/templates/scaffold-default/packages/core/src/auth/auth-constants.ts +6 -0
- package/templates/scaffold-default/packages/core/src/auth/auth-service.ts +65 -0
- package/templates/scaffold-default/packages/core/src/auth/backend-auth-provider.ts +149 -0
- package/templates/scaffold-default/packages/core/src/auth/default-auth-provider.ts +38 -0
- package/templates/scaffold-default/packages/core/src/auth/index.ts +12 -0
- package/templates/scaffold-default/packages/core/src/auth/types.ts +38 -0
- package/templates/scaffold-default/packages/core/src/authorization/authorization-client-middleware.ts +38 -0
- package/templates/scaffold-default/packages/core/src/authorization/authorization-config.ts +13 -0
- package/templates/scaffold-default/packages/core/src/authorization/authorization-provider.tsx +116 -0
- package/templates/scaffold-default/packages/core/src/authorization/default-authorization-provider.ts +26 -0
- package/templates/scaffold-default/packages/core/src/authorization/index.ts +15 -0
- package/templates/scaffold-default/packages/core/src/authorization/types.ts +42 -0
- package/templates/scaffold-default/packages/core/src/index.ts +3 -0
- package/templates/scaffold-default/packages/core/src/utils/promise-result-cache.ts +18 -0
- package/templates/scaffold-default/packages/core/tsconfig.json +19 -0
- package/templates/scaffold-default/packages/mobile/README.md +56 -0
- package/templates/scaffold-default/packages/mobile/index.html +13 -0
- package/templates/scaffold-default/packages/mobile/package.json +28 -0
- package/templates/scaffold-default/packages/mobile/postcss.config.mjs +7 -0
- package/templates/scaffold-default/packages/mobile/src/App.tsx +5 -0
- package/templates/scaffold-default/packages/mobile/src/app/globals.css +1 -0
- package/templates/scaffold-default/packages/mobile/src/components/LoginForm.tsx +83 -0
- package/templates/scaffold-default/packages/mobile/src/hooks/index.ts +5 -0
- package/templates/scaffold-default/packages/mobile/src/lib/utils.ts +7 -0
- package/templates/scaffold-default/packages/mobile/src/main.tsx +19 -0
- package/templates/scaffold-default/packages/mobile/src/pages/HomePage.tsx +41 -0
- package/templates/scaffold-default/packages/mobile/src/pages/LoginPage.tsx +24 -0
- package/templates/scaffold-default/packages/mobile/src/pages/index.ts +2 -0
- package/templates/scaffold-default/packages/mobile/src/routes/ProtectedRoute.tsx +35 -0
- package/templates/scaffold-default/packages/mobile/src/routes/index.tsx +24 -0
- package/templates/scaffold-default/packages/mobile/src/routes/routes.ts +11 -0
- package/templates/scaffold-default/packages/mobile/src/types/index.ts +5 -0
- package/templates/scaffold-default/packages/mobile/src/vite-env.d.ts +1 -0
- package/templates/scaffold-default/packages/mobile/tsconfig.json +23 -0
- package/templates/scaffold-default/packages/mobile/tsconfig.node.json +11 -0
- package/templates/scaffold-default/packages/mobile/vite.config.ts +20 -0
- package/templates/scaffold-default/pnpm-workspace.yaml +2 -0
- package/templates/scaffold-default/scripts/postinstall.cjs +42 -0
- package/templates/scaffold-default/scripts/rebuild-sqlite.cjs +23 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import fs from 'fs-extra';
|
|
3
|
+
import { loadProjectConfig, saveProjectConfig, } from './project-config.js';
|
|
4
|
+
import { getFrameworkRegistryVersion } from './framework-version.js';
|
|
5
|
+
const FRAMEWORK_SCOPE = '@ai-partner-x/';
|
|
6
|
+
export async function ensurePnpmWorkspace(rootDir) {
|
|
7
|
+
const workspacePath = path.join(rootDir, 'pnpm-workspace.yaml');
|
|
8
|
+
if (await fs.pathExists(workspacePath))
|
|
9
|
+
return;
|
|
10
|
+
await fs.writeFile(workspacePath, `packages:
|
|
11
|
+
- 'packages/*'
|
|
12
|
+
`, 'utf-8');
|
|
13
|
+
}
|
|
14
|
+
export async function withProjectConfig(rootDir, updater) {
|
|
15
|
+
const existing = (await loadProjectConfig(rootDir)) ?? {
|
|
16
|
+
version: 1,
|
|
17
|
+
apps: [],
|
|
18
|
+
apis: [],
|
|
19
|
+
};
|
|
20
|
+
const next = (updater(existing) ?? existing);
|
|
21
|
+
await saveProjectConfig(rootDir, next);
|
|
22
|
+
return next;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* 根据 .aiko-boot.json 的配置,同步根目录下的 package.json:
|
|
26
|
+
* - 补充 name/version/private
|
|
27
|
+
* - 生成常用 scripts(dev / build / lint / dev:api 等)
|
|
28
|
+
* - 便于后续在根目录直接运行 pnpm 脚本
|
|
29
|
+
*/
|
|
30
|
+
export async function syncRootPackageJson(rootDir) {
|
|
31
|
+
const config = await loadProjectConfig(rootDir);
|
|
32
|
+
if (!config)
|
|
33
|
+
return;
|
|
34
|
+
const rootPkgPath = path.join(rootDir, 'package.json');
|
|
35
|
+
let pkg = {};
|
|
36
|
+
if (await fs.pathExists(rootPkgPath)) {
|
|
37
|
+
pkg = await fs.readJson(rootPkgPath);
|
|
38
|
+
}
|
|
39
|
+
const scope = config.scope ?? 'scaffold';
|
|
40
|
+
if (!pkg.name) {
|
|
41
|
+
pkg.name = `${scope}-monorepo`;
|
|
42
|
+
}
|
|
43
|
+
if (pkg.private === undefined) {
|
|
44
|
+
pkg.private = true;
|
|
45
|
+
}
|
|
46
|
+
if (!pkg.version) {
|
|
47
|
+
pkg.version = '0.1.0';
|
|
48
|
+
}
|
|
49
|
+
const scripts = pkg.scripts ?? {};
|
|
50
|
+
// 通用脚本:对所有 @<scope>/* 包执行 dev / build / lint
|
|
51
|
+
scripts.dev = `pnpm -r --parallel --filter "@${scope}/*" dev`;
|
|
52
|
+
scripts.build = `pnpm -r --filter "@${scope}/*" build`;
|
|
53
|
+
scripts.lint = `pnpm -r --filter "@${scope}/*" lint`;
|
|
54
|
+
// API 相关脚本:只针对 name === 'api' 的服务,保持与 scaffold 模板一致
|
|
55
|
+
const api = (config.apis ?? []).find((x) => x.name === 'api');
|
|
56
|
+
if (api) {
|
|
57
|
+
const apiPkgName = `@${scope}/${api.name}`;
|
|
58
|
+
scripts['dev:api'] = `pnpm -F ${apiPkgName} dev`;
|
|
59
|
+
scripts['build:api'] = `pnpm -F ${apiPkgName} build`;
|
|
60
|
+
scripts['start:api'] = `pnpm -F ${apiPkgName} start`;
|
|
61
|
+
scripts['init-db'] = `pnpm -F ${apiPkgName} init-db`;
|
|
62
|
+
}
|
|
63
|
+
// Admin / Mobile 应用脚本:按照 type 分类
|
|
64
|
+
const apps = config.apps ?? [];
|
|
65
|
+
const adminApp = apps.find((x) => x.type === 'admin');
|
|
66
|
+
if (adminApp) {
|
|
67
|
+
const adminPkgName = `@${scope}/${adminApp.name}`;
|
|
68
|
+
scripts['dev:admin'] = `pnpm -F ${adminPkgName} dev`;
|
|
69
|
+
scripts['build:admin'] = `pnpm -F ${adminPkgName} build`;
|
|
70
|
+
}
|
|
71
|
+
const mobileApp = apps.find((x) => x.type === 'mobile');
|
|
72
|
+
if (mobileApp) {
|
|
73
|
+
const mobilePkgName = `@${scope}/${mobileApp.name}`;
|
|
74
|
+
scripts['dev:mobile'] = `pnpm -F ${mobilePkgName} dev`;
|
|
75
|
+
scripts['build:mobile'] = `pnpm -F ${mobilePkgName} build`;
|
|
76
|
+
}
|
|
77
|
+
pkg.scripts = scripts;
|
|
78
|
+
// 与 scaffold-default 对齐:只在未设置时提供默认值
|
|
79
|
+
const pnpmConfig = pkg.pnpm ?? {};
|
|
80
|
+
if (!pnpmConfig.onlyBuiltDependencies) {
|
|
81
|
+
pnpmConfig.onlyBuiltDependencies = ['better-sqlite3'];
|
|
82
|
+
}
|
|
83
|
+
// 清理旧的本地框架覆盖(如 file:.../packages/),避免在中央仓库安装时仍引用本地库。
|
|
84
|
+
if (pnpmConfig.overrides && typeof pnpmConfig.overrides === 'object') {
|
|
85
|
+
for (const [k, v] of Object.entries(pnpmConfig.overrides)) {
|
|
86
|
+
if (k.startsWith(FRAMEWORK_SCOPE) && typeof v === 'string' && v.startsWith('file:')) {
|
|
87
|
+
delete pnpmConfig.overrides[k];
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (Object.keys(pnpmConfig.overrides).length === 0) {
|
|
91
|
+
delete pkg.pnpm.overrides;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
pkg.pnpm = pnpmConfig;
|
|
95
|
+
// Ensure all generated framework deps use registry versions (not `workspace:*`),
|
|
96
|
+
// so the scaffold can be used outside of this monorepo.
|
|
97
|
+
await replaceFrameworkDepsWithRegistryVersion(rootDir);
|
|
98
|
+
await fs.writeJson(rootPkgPath, pkg, { spaces: 2 });
|
|
99
|
+
}
|
|
100
|
+
async function replaceFrameworkDepsWithRegistryVersion(rootDir) {
|
|
101
|
+
const FRAMEWORK_REGISTRY_VERSION = await getFrameworkRegistryVersion();
|
|
102
|
+
const packageJsonPaths = [];
|
|
103
|
+
async function collect(dir) {
|
|
104
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
105
|
+
for (const e of entries) {
|
|
106
|
+
const full = path.join(dir, e.name);
|
|
107
|
+
if (e.name === 'node_modules')
|
|
108
|
+
continue;
|
|
109
|
+
if (e.isDirectory()) {
|
|
110
|
+
if (e.name.startsWith('.'))
|
|
111
|
+
continue;
|
|
112
|
+
await collect(full);
|
|
113
|
+
}
|
|
114
|
+
else if (e.isFile() && e.name === 'package.json') {
|
|
115
|
+
packageJsonPaths.push(full);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
await collect(path.join(rootDir, 'packages'));
|
|
120
|
+
for (const pkgPath of packageJsonPaths) {
|
|
121
|
+
const pkg = await fs.readJson(pkgPath);
|
|
122
|
+
let changed = false;
|
|
123
|
+
for (const key of ['dependencies', 'devDependencies']) {
|
|
124
|
+
if (!pkg[key])
|
|
125
|
+
continue;
|
|
126
|
+
for (const [name, value] of Object.entries(pkg[key])) {
|
|
127
|
+
if (!name.startsWith(FRAMEWORK_SCOPE))
|
|
128
|
+
continue;
|
|
129
|
+
if (typeof value !== 'string')
|
|
130
|
+
continue;
|
|
131
|
+
if (value.startsWith('file:') || value.startsWith('link:'))
|
|
132
|
+
continue;
|
|
133
|
+
pkg[key][name] = FRAMEWORK_REGISTRY_VERSION;
|
|
134
|
+
changed = true;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (changed) {
|
|
138
|
+
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
package/dist/scaffold.js
ADDED
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import fs from 'fs-extra';
|
|
3
|
+
import { getFrameworkRegistryVersion } from './core/framework-version.js';
|
|
4
|
+
const COPY_IGNORE = [
|
|
5
|
+
'node_modules',
|
|
6
|
+
'.next',
|
|
7
|
+
'dist',
|
|
8
|
+
'.pnpm-store',
|
|
9
|
+
'*.tsbuildinfo',
|
|
10
|
+
'.vite',
|
|
11
|
+
'*.log',
|
|
12
|
+
];
|
|
13
|
+
/** Paths to skip when withBaseSystem is false (relative to scaffold root). */
|
|
14
|
+
const SKIP_WHEN_BARE = [
|
|
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
|
+
export async function createScaffold(options) {
|
|
27
|
+
const { templateDir, targetDir, scope, withBaseSystem } = options;
|
|
28
|
+
if (!(await fs.pathExists(templateDir))) {
|
|
29
|
+
throw new Error(`Template directory not found: ${templateDir}. ` +
|
|
30
|
+
'You can specify a custom template with --template-dir, or use the built-in templates.');
|
|
31
|
+
}
|
|
32
|
+
if (await fs.pathExists(targetDir)) {
|
|
33
|
+
const files = await fs.readdir(targetDir);
|
|
34
|
+
if (files.length > 0) {
|
|
35
|
+
throw new Error(`Target directory already exists and is not empty: ${targetDir}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
await fs.ensureDir(targetDir);
|
|
39
|
+
await copyRecursive(templateDir, templateDir, targetDir, withBaseSystem);
|
|
40
|
+
await replaceScopeInFiles(targetDir, scope);
|
|
41
|
+
// 依赖写 registry 版本,便于将来从中央仓库安装;本地开发通过根目录 pnpm.overrides 覆盖
|
|
42
|
+
await replaceFrameworkDepsWithRegistryVersion(targetDir);
|
|
43
|
+
// 使生成的项目成为独立 pnpm workspace,在项目目录内执行 pnpm 时不会回溯到父仓库
|
|
44
|
+
await fs.writeFile(path.join(targetDir, 'pnpm-workspace.yaml'), `packages:
|
|
45
|
+
- 'packages/*'
|
|
46
|
+
`, 'utf-8');
|
|
47
|
+
if (!withBaseSystem) {
|
|
48
|
+
await writeBareTemplates(targetDir);
|
|
49
|
+
}
|
|
50
|
+
// 再次替换,确保子包中 @ai-partner-x/* 均为 registry 版本(与根 pnpm.overrides 配合)
|
|
51
|
+
await replaceFrameworkDepsWithRegistryVersion(targetDir);
|
|
52
|
+
}
|
|
53
|
+
/** 将各 package.json 中 @ai-partner-x/* 的 workspace: 协议改为 registry 版本(如 ^0.1.0),与根目录 pnpm.overrides 配合使用 */
|
|
54
|
+
async function replaceFrameworkDepsWithRegistryVersion(targetDir) {
|
|
55
|
+
const FRAMEWORK_REGISTRY_VERSION = await getFrameworkRegistryVersion();
|
|
56
|
+
const packageJsonPaths = [];
|
|
57
|
+
async function collect(dir) {
|
|
58
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
59
|
+
for (const e of entries) {
|
|
60
|
+
const full = path.join(dir, e.name);
|
|
61
|
+
if (e.name === 'package.json') {
|
|
62
|
+
packageJsonPaths.push(full);
|
|
63
|
+
}
|
|
64
|
+
else if (e.isDirectory() && e.name !== 'node_modules' && !e.name.startsWith('.')) {
|
|
65
|
+
await collect(full);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
await collect(targetDir);
|
|
70
|
+
for (const pkgPath of packageJsonPaths) {
|
|
71
|
+
const pkg = await fs.readJson(pkgPath);
|
|
72
|
+
let changed = false;
|
|
73
|
+
for (const key of ['dependencies', 'devDependencies']) {
|
|
74
|
+
if (!pkg[key])
|
|
75
|
+
continue;
|
|
76
|
+
for (const [name, value] of Object.entries(pkg[key])) {
|
|
77
|
+
if (!name.startsWith(FRAMEWORK_SCOPE))
|
|
78
|
+
continue;
|
|
79
|
+
if (typeof value !== 'string')
|
|
80
|
+
continue;
|
|
81
|
+
// 只要是框架包,一律写 registry 版本范围(除非显式用 file:/link: 做本地调试)
|
|
82
|
+
if (value.startsWith('file:') || value.startsWith('link:'))
|
|
83
|
+
continue;
|
|
84
|
+
pkg[key][name] = FRAMEWORK_REGISTRY_VERSION;
|
|
85
|
+
changed = true;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (changed)
|
|
89
|
+
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function shouldIgnore(name) {
|
|
93
|
+
if (COPY_IGNORE.some((x) => x.startsWith('*') && name.endsWith(x.slice(1))))
|
|
94
|
+
return true;
|
|
95
|
+
if (COPY_IGNORE.includes(name))
|
|
96
|
+
return true;
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
function shouldSkipWhenBare(relativePath) {
|
|
100
|
+
const normalized = relativePath.replace(/\\/g, '/');
|
|
101
|
+
return SKIP_WHEN_BARE.some((skip) => normalized === skip || normalized.startsWith(skip + '/'));
|
|
102
|
+
}
|
|
103
|
+
async function copyRecursive(templateRoot, src, dest, withBaseSystem) {
|
|
104
|
+
const entries = await fs.readdir(src, { withFileTypes: true });
|
|
105
|
+
for (const entry of entries) {
|
|
106
|
+
const srcPath = path.join(src, entry.name);
|
|
107
|
+
const destPath = path.join(dest, entry.name);
|
|
108
|
+
const relativePath = path.relative(templateRoot, srcPath).replace(/\\/g, '/');
|
|
109
|
+
if (shouldIgnore(entry.name))
|
|
110
|
+
continue;
|
|
111
|
+
if (!withBaseSystem && shouldSkipWhenBare(relativePath))
|
|
112
|
+
continue;
|
|
113
|
+
if (entry.isDirectory()) {
|
|
114
|
+
await fs.ensureDir(destPath);
|
|
115
|
+
await copyRecursive(templateRoot, srcPath, destPath, withBaseSystem);
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
await fs.copy(srcPath, destPath);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
async function replaceScopeInFiles(dir, scope) {
|
|
123
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
124
|
+
for (const entry of entries) {
|
|
125
|
+
const full = path.join(dir, entry.name);
|
|
126
|
+
if (entry.isDirectory() && !shouldIgnore(entry.name)) {
|
|
127
|
+
await replaceScopeInFiles(full, scope);
|
|
128
|
+
}
|
|
129
|
+
else if (entry.isFile()) {
|
|
130
|
+
const ext = path.extname(entry.name).toLowerCase();
|
|
131
|
+
if (!['.ts', '.tsx', '.js', '.jsx', '.json', '.md', '.mjs', '.cjs', '.css', '.html'].includes(ext))
|
|
132
|
+
continue;
|
|
133
|
+
let content = await fs.readFile(full, 'utf-8');
|
|
134
|
+
const before = content;
|
|
135
|
+
content = content.replace(/@scaffold\//g, `@${scope}/`);
|
|
136
|
+
content = content.replace(/"@scaffold\//g, `"@${scope}/`);
|
|
137
|
+
content = content.replace(/scaffold-monorepo/g, `${scope}-monorepo`);
|
|
138
|
+
content = content.replace(/--filter "@scaffold\/\*"/g, `--filter "@${scope}/*"`);
|
|
139
|
+
content = content.replace(/-F @scaffold\//g, `-F @${scope}/`);
|
|
140
|
+
if (content !== before)
|
|
141
|
+
await fs.writeFile(full, content, 'utf-8');
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/** Write bare (no auth) template files when withBaseSystem is false. */
|
|
146
|
+
async function writeBareTemplates(targetDir) {
|
|
147
|
+
const packagesDir = path.join(targetDir, 'packages');
|
|
148
|
+
// api init-db
|
|
149
|
+
const apiInitDbPath = path.join(packagesDir, 'api/src/scripts/init-db.ts');
|
|
150
|
+
await fs.ensureDir(path.dirname(apiInitDbPath));
|
|
151
|
+
await fs.writeFile(apiInitDbPath, `/**
|
|
152
|
+
* Initialize SQLite database (bare scaffold, no user table).
|
|
153
|
+
*/
|
|
154
|
+
import { fileURLToPath } from 'url';
|
|
155
|
+
import { dirname, join } from 'path';
|
|
156
|
+
import { writeFileSync, mkdirSync, existsSync } from 'fs';
|
|
157
|
+
// @ts-expect-error sql.js has no types
|
|
158
|
+
import initSqlJs from 'sql.js';
|
|
159
|
+
|
|
160
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
161
|
+
const dbPath = join(__dirname, '../../data/app.db');
|
|
162
|
+
|
|
163
|
+
console.log('📁 Database path:', dbPath);
|
|
164
|
+
|
|
165
|
+
const SQL = await initSqlJs();
|
|
166
|
+
const db = new SQL.Database();
|
|
167
|
+
|
|
168
|
+
// Add your tables here when needed.
|
|
169
|
+
|
|
170
|
+
const data = db.export();
|
|
171
|
+
db.close();
|
|
172
|
+
|
|
173
|
+
const dir = dirname(dbPath);
|
|
174
|
+
if (!existsSync(dir)) {
|
|
175
|
+
mkdirSync(dir, { recursive: true });
|
|
176
|
+
}
|
|
177
|
+
writeFileSync(dbPath, Buffer.from(data));
|
|
178
|
+
|
|
179
|
+
console.log('\\n🎉 Database initialization complete!');
|
|
180
|
+
`, 'utf-8');
|
|
181
|
+
// mobile main / routes / pages
|
|
182
|
+
const mobileMainPath = path.join(packagesDir, 'mobile/src/main.tsx');
|
|
183
|
+
await fs.ensureDir(path.dirname(mobileMainPath));
|
|
184
|
+
const mobileMain = `import { StrictMode } from 'react';
|
|
185
|
+
import { createRoot } from 'react-dom/client';
|
|
186
|
+
import App from './App';
|
|
187
|
+
import './app/globals.css';
|
|
188
|
+
|
|
189
|
+
createRoot(document.getElementById('root')!).render(
|
|
190
|
+
<StrictMode>
|
|
191
|
+
<App />
|
|
192
|
+
</StrictMode>
|
|
193
|
+
);
|
|
194
|
+
`;
|
|
195
|
+
await fs.writeFile(mobileMainPath, mobileMain, 'utf-8');
|
|
196
|
+
const mobileRoutesIndexPath = path.join(packagesDir, 'mobile/src/routes/index.tsx');
|
|
197
|
+
await fs.ensureDir(path.dirname(mobileRoutesIndexPath));
|
|
198
|
+
const mobileRoutesIndex = `import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
|
|
199
|
+
import { HomePage } from '@/pages/HomePage';
|
|
200
|
+
import { ROUTES } from './routes';
|
|
201
|
+
|
|
202
|
+
export function AppRouter() {
|
|
203
|
+
return (
|
|
204
|
+
<BrowserRouter>
|
|
205
|
+
<Routes>
|
|
206
|
+
<Route path={ROUTES.HOME} element={<HomePage />} />
|
|
207
|
+
<Route path="*" element={<Navigate to={ROUTES.HOME} replace />} />
|
|
208
|
+
</Routes>
|
|
209
|
+
</BrowserRouter>
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
`;
|
|
213
|
+
await fs.writeFile(mobileRoutesIndexPath, mobileRoutesIndex, 'utf-8');
|
|
214
|
+
const mobileRoutesPath = path.join(packagesDir, 'mobile/src/routes/routes.ts');
|
|
215
|
+
await fs.ensureDir(path.dirname(mobileRoutesPath));
|
|
216
|
+
await fs.writeFile(mobileRoutesPath, `export const ROUTES = {
|
|
217
|
+
HOME: '/',
|
|
218
|
+
} as const;
|
|
219
|
+
|
|
220
|
+
export type RoutePath = (typeof ROUTES)[keyof typeof ROUTES];
|
|
221
|
+
`, 'utf-8');
|
|
222
|
+
const mobileHomePagePath = path.join(packagesDir, 'mobile/src/pages/HomePage.tsx');
|
|
223
|
+
await fs.ensureDir(path.dirname(mobileHomePagePath));
|
|
224
|
+
const homePage = `/**
|
|
225
|
+
* Mobile home page (bare scaffold).
|
|
226
|
+
*/
|
|
227
|
+
export function HomePage() {
|
|
228
|
+
return (
|
|
229
|
+
<div className="min-h-screen bg-gray-50 flex flex-col">
|
|
230
|
+
<header className="flex items-center justify-between px-4 py-3 bg-white border-b border-gray-200 safe-area-top">
|
|
231
|
+
<span className="text-lg font-medium text-gray-800">AIKO-BOOT</span>
|
|
232
|
+
</header>
|
|
233
|
+
<main className="flex-1 flex flex-col items-center justify-center px-4">
|
|
234
|
+
<h1 className="text-2xl font-semibold text-gray-900 mb-1">AIKO-BOOT</h1>
|
|
235
|
+
<p className="text-gray-500 text-sm">Scaffold ready. Add your pages.</p>
|
|
236
|
+
</main>
|
|
237
|
+
</div>
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
`;
|
|
241
|
+
await fs.writeFile(mobileHomePagePath, homePage, 'utf-8');
|
|
242
|
+
const mobilePagesIndexPath = path.join(packagesDir, 'mobile/src/pages/index.ts');
|
|
243
|
+
await fs.ensureDir(path.dirname(mobilePagesIndexPath));
|
|
244
|
+
await fs.writeFile(mobilePagesIndexPath, `export { HomePage } from './HomePage';
|
|
245
|
+
`, 'utf-8');
|
|
246
|
+
// admin main / App
|
|
247
|
+
const adminMainPath = path.join(packagesDir, 'admin/src/main.tsx');
|
|
248
|
+
await fs.ensureDir(path.dirname(adminMainPath));
|
|
249
|
+
const adminMain = `import { StrictMode } from 'react';
|
|
250
|
+
import { createRoot } from 'react-dom/client';
|
|
251
|
+
import App from './App';
|
|
252
|
+
import './index.css';
|
|
253
|
+
|
|
254
|
+
createRoot(document.getElementById('root')!).render(
|
|
255
|
+
<StrictMode>
|
|
256
|
+
<App />
|
|
257
|
+
</StrictMode>
|
|
258
|
+
);
|
|
259
|
+
`;
|
|
260
|
+
await fs.writeFile(adminMainPath, adminMain, 'utf-8');
|
|
261
|
+
const adminAppPath = path.join(packagesDir, 'admin/src/App.tsx');
|
|
262
|
+
await fs.ensureDir(path.dirname(adminAppPath));
|
|
263
|
+
const adminApp = `export default function App() {
|
|
264
|
+
return (
|
|
265
|
+
<div className="min-h-screen flex items-center justify-center bg-gray-100">
|
|
266
|
+
<p className="text-gray-600">Scaffold Admin — add your pages.</p>
|
|
267
|
+
</div>
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
`;
|
|
271
|
+
await fs.writeFile(adminAppPath, adminApp, 'utf-8');
|
|
272
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Logger } from '../core/logger.js';
|
|
2
|
+
import type { Prompter } from '../core/prompts.js';
|
|
3
|
+
export type AddApiInput = {
|
|
4
|
+
name?: string;
|
|
5
|
+
db: string;
|
|
6
|
+
rootDir?: string;
|
|
7
|
+
templateDir?: string;
|
|
8
|
+
dryRun: boolean;
|
|
9
|
+
};
|
|
10
|
+
export type AddApiDeps = {
|
|
11
|
+
logger: Logger;
|
|
12
|
+
prompter: Prompter;
|
|
13
|
+
};
|
|
14
|
+
export declare function createAddApiUseCase(deps: AddApiDeps): {
|
|
15
|
+
execute: (input: AddApiInput) => Promise<void>;
|
|
16
|
+
};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { fileURLToPath } from 'url';
|
|
3
|
+
import fs from 'fs-extra';
|
|
4
|
+
import { loadProjectConfig } from '../core/project-config.js';
|
|
5
|
+
import { ensurePnpmWorkspace, syncRootPackageJson, withProjectConfig, } from '../core/workspace.js';
|
|
6
|
+
import { replaceScopeInDir } from '../core/template-utils.js';
|
|
7
|
+
export function createAddApiUseCase(deps) {
|
|
8
|
+
const { logger, prompter } = deps;
|
|
9
|
+
async function execute(input) {
|
|
10
|
+
let { name } = input;
|
|
11
|
+
const rootDir = input.rootDir ?? process.cwd();
|
|
12
|
+
const config = await loadProjectConfig(rootDir);
|
|
13
|
+
if (!config) {
|
|
14
|
+
throw new Error('未找到 .aiko-boot.json,当前目录似乎不是脚手架根目录,请在 create 生成的根目录下执行。');
|
|
15
|
+
}
|
|
16
|
+
if (!name) {
|
|
17
|
+
name = await prompter.input('服务端名称(包名)', 'api');
|
|
18
|
+
}
|
|
19
|
+
// 计算模板根目录:
|
|
20
|
+
// - 默认使用 CLI 包内部的 templates/api-base 作为 base-api 模板;
|
|
21
|
+
// - 如果用户通过 --template-dir 显式提供:
|
|
22
|
+
// - 若该目录本身是一个 api 根(包含 app.config.ts 和 src/),则直接使用;
|
|
23
|
+
// - 若该目录下存在 packages/api(例如传入 scaffold 根目录),则使用 packages/api 作为模板。
|
|
24
|
+
const defaultTemplateApiDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../templates/api-base');
|
|
25
|
+
let templateApiDir = defaultTemplateApiDir;
|
|
26
|
+
if (input.templateDir) {
|
|
27
|
+
const candidateRoot = path.resolve(input.templateDir);
|
|
28
|
+
const candidateAsApiRoot = path.join(candidateRoot, 'app.config.ts');
|
|
29
|
+
const candidateApiDir = path.join(candidateRoot, 'packages', 'api');
|
|
30
|
+
if (await fs.pathExists(candidateAsApiRoot)) {
|
|
31
|
+
// 传入的是 api 根目录(类似 api-base)
|
|
32
|
+
templateApiDir = candidateRoot;
|
|
33
|
+
}
|
|
34
|
+
else if (await fs.pathExists(path.join(candidateApiDir, 'app.config.ts'))) {
|
|
35
|
+
// 传入的是 scaffold 根目录,内部有 packages/api
|
|
36
|
+
templateApiDir = candidateApiDir;
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
throw new Error(`无法识别的模板目录:${candidateRoot}(需要是 api 根目录,或包含 packages/api 的 scaffold 根目录)`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (input.dryRun) {
|
|
43
|
+
logger.info(`[dry-run] 将在 ${rootDir} 中新增服务端:name=${name}, db=${input.db}`);
|
|
44
|
+
logger.info(`[dry-run] 使用模板目录: ${templateApiDir}`);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (!(await fs.pathExists(templateApiDir))) {
|
|
48
|
+
throw new Error(`模板不存在:${templateApiDir}`);
|
|
49
|
+
}
|
|
50
|
+
const packagesDir = path.join(rootDir, 'packages');
|
|
51
|
+
const apiDir = path.join(packagesDir, name);
|
|
52
|
+
if (await fs.pathExists(apiDir)) {
|
|
53
|
+
throw new Error(`目标服务端目录已存在:${apiDir}`);
|
|
54
|
+
}
|
|
55
|
+
await fs.ensureDir(packagesDir);
|
|
56
|
+
await fs.copy(templateApiDir, apiDir);
|
|
57
|
+
const pkgPath = path.join(apiDir, 'package.json');
|
|
58
|
+
if (await fs.pathExists(pkgPath)) {
|
|
59
|
+
const pkg = await fs.readJson(pkgPath);
|
|
60
|
+
const scope = config.scope;
|
|
61
|
+
if (scope) {
|
|
62
|
+
pkg.name = `@${scope}/${name}`;
|
|
63
|
+
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
64
|
+
await replaceScopeInDir(apiDir, 'scaffold', scope);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
pkg.name = name;
|
|
68
|
+
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
await ensurePnpmWorkspace(rootDir);
|
|
72
|
+
await withProjectConfig(rootDir, (cfg) => {
|
|
73
|
+
const apis = cfg.apis ?? [];
|
|
74
|
+
apis.push({
|
|
75
|
+
name: name,
|
|
76
|
+
path: path.join('packages', name),
|
|
77
|
+
db: input.db,
|
|
78
|
+
features: [],
|
|
79
|
+
});
|
|
80
|
+
cfg.apis = apis;
|
|
81
|
+
});
|
|
82
|
+
// 同步根 package.json(dev/build/start:api 等脚本)
|
|
83
|
+
await syncRootPackageJson(rootDir);
|
|
84
|
+
logger.info(`已在 ${apiDir} 创建服务端 "${name}"(db=${input.db})。`);
|
|
85
|
+
}
|
|
86
|
+
return { execute };
|
|
87
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Logger } from '../core/logger.js';
|
|
2
|
+
import type { Prompter } from '../core/prompts.js';
|
|
3
|
+
export type AddAppInput = {
|
|
4
|
+
name?: string;
|
|
5
|
+
type?: string;
|
|
6
|
+
rootDir?: string;
|
|
7
|
+
templateDir?: string;
|
|
8
|
+
dryRun: boolean;
|
|
9
|
+
};
|
|
10
|
+
export type AddAppDeps = {
|
|
11
|
+
logger: Logger;
|
|
12
|
+
prompter: Prompter;
|
|
13
|
+
};
|
|
14
|
+
export declare function createAddAppUseCase(deps: AddAppDeps): {
|
|
15
|
+
execute: (input: AddAppInput) => Promise<void>;
|
|
16
|
+
};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { fileURLToPath } from 'url';
|
|
3
|
+
import fs from 'fs-extra';
|
|
4
|
+
import { loadProjectConfig } from '../core/project-config.js';
|
|
5
|
+
import { ensurePnpmWorkspace, syncRootPackageJson, withProjectConfig, } from '../core/workspace.js';
|
|
6
|
+
import { replaceScopeInDir } from '../core/template-utils.js';
|
|
7
|
+
export function createAddAppUseCase(deps) {
|
|
8
|
+
const { logger, prompter } = deps;
|
|
9
|
+
async function execute(input) {
|
|
10
|
+
let { name, type } = input;
|
|
11
|
+
const rootDir = input.rootDir ?? process.cwd();
|
|
12
|
+
const config = await loadProjectConfig(rootDir);
|
|
13
|
+
if (!config) {
|
|
14
|
+
throw new Error('未找到 .aiko-boot.json,当前目录似乎不是脚手架根目录,请在 create 生成的根目录下执行。');
|
|
15
|
+
}
|
|
16
|
+
if (!type) {
|
|
17
|
+
type = await prompter.input('应用类型(admin 或 mobile)', 'admin');
|
|
18
|
+
}
|
|
19
|
+
if (!name) {
|
|
20
|
+
name = await prompter.input('应用名称(包名)', type === 'mobile' ? 'mobile' : 'admin');
|
|
21
|
+
}
|
|
22
|
+
if (input.dryRun) {
|
|
23
|
+
logger.info(`[dry-run] 将在 ${rootDir} 中新增应用:name=${name}, type=${type}`);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
if (type !== 'admin' && type !== 'mobile') {
|
|
27
|
+
throw new Error('应用类型目前仅支持 admin 或 mobile');
|
|
28
|
+
}
|
|
29
|
+
// 计算模板目录:
|
|
30
|
+
// - 如果用户提供了 --template-dir,使用用户指定的(可能是 scaffold 根目录或自定义模板)
|
|
31
|
+
// - 否则,使用内置的 scaffold-default 模板
|
|
32
|
+
let templateRoot = input.templateDir;
|
|
33
|
+
if (!templateRoot) {
|
|
34
|
+
const defaultTemplateRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../templates/scaffold-default');
|
|
35
|
+
templateRoot = defaultTemplateRoot;
|
|
36
|
+
}
|
|
37
|
+
const templateAppDir = path.join(templateRoot, 'packages', type);
|
|
38
|
+
if (!(await fs.pathExists(templateAppDir))) {
|
|
39
|
+
throw new Error(`模板不存在:${templateAppDir}`);
|
|
40
|
+
}
|
|
41
|
+
const packagesDir = path.join(rootDir, 'packages');
|
|
42
|
+
const appDir = path.join(packagesDir, name);
|
|
43
|
+
if (await fs.pathExists(appDir)) {
|
|
44
|
+
throw new Error(`目标应用目录已存在:${appDir}`);
|
|
45
|
+
}
|
|
46
|
+
// 如果还没有 core 包,则在第一次添加 admin/mobile 时一起从模板复制 core
|
|
47
|
+
const templateCoreDir = path.join(templateRoot, 'packages', 'core');
|
|
48
|
+
const coreDir = path.join(packagesDir, 'core');
|
|
49
|
+
await fs.ensureDir(packagesDir);
|
|
50
|
+
if (!(await fs.pathExists(coreDir)) && (await fs.pathExists(templateCoreDir))) {
|
|
51
|
+
await fs.copy(templateCoreDir, coreDir);
|
|
52
|
+
const corePkgPath = path.join(coreDir, 'package.json');
|
|
53
|
+
if (await fs.pathExists(corePkgPath)) {
|
|
54
|
+
const corePkg = await fs.readJson(corePkgPath);
|
|
55
|
+
const scope = config.scope;
|
|
56
|
+
if (scope) {
|
|
57
|
+
corePkg.name = `@${scope}/core`;
|
|
58
|
+
await fs.writeJson(corePkgPath, corePkg, { spaces: 2 });
|
|
59
|
+
await replaceScopeInDir(coreDir, 'scaffold', scope);
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
corePkg.name = 'core';
|
|
63
|
+
await fs.writeJson(corePkgPath, corePkg, { spaces: 2 });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
logger.info(`已自动创建共享 core 包:${coreDir}`);
|
|
67
|
+
}
|
|
68
|
+
await fs.copy(templateAppDir, appDir);
|
|
69
|
+
const pkgPath = path.join(appDir, 'package.json');
|
|
70
|
+
if (await fs.pathExists(pkgPath)) {
|
|
71
|
+
const pkg = await fs.readJson(pkgPath);
|
|
72
|
+
const scope = config.scope;
|
|
73
|
+
if (scope) {
|
|
74
|
+
pkg.name = `@${scope}/${name}`;
|
|
75
|
+
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
76
|
+
// 将模板中的 @scaffold/* 替换为 @<scope>/*
|
|
77
|
+
await replaceScopeInDir(appDir, 'scaffold', scope);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
pkg.name = name;
|
|
81
|
+
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
await ensurePnpmWorkspace(rootDir);
|
|
85
|
+
await withProjectConfig(rootDir, (cfg) => {
|
|
86
|
+
const apps = cfg.apps ?? [];
|
|
87
|
+
if (!name)
|
|
88
|
+
return;
|
|
89
|
+
apps.push({
|
|
90
|
+
name,
|
|
91
|
+
type: type,
|
|
92
|
+
path: path.join('packages', name),
|
|
93
|
+
});
|
|
94
|
+
cfg.apps = apps;
|
|
95
|
+
});
|
|
96
|
+
// 同步根 package.json(dev:admin / dev:mobile 等脚本)
|
|
97
|
+
await syncRootPackageJson(rootDir);
|
|
98
|
+
logger.info(`已在 ${appDir} 创建 ${type} 应用 "${name}"。`);
|
|
99
|
+
}
|
|
100
|
+
return { execute };
|
|
101
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Logger } from '../core/logger.js';
|
|
2
|
+
import type { Prompter } from '../core/prompts.js';
|
|
3
|
+
export type AddFeatureInput = {
|
|
4
|
+
serviceName: string;
|
|
5
|
+
feature: string;
|
|
6
|
+
rootDir?: string;
|
|
7
|
+
dryRun: boolean;
|
|
8
|
+
};
|
|
9
|
+
export type AddFeatureDeps = {
|
|
10
|
+
logger: Logger;
|
|
11
|
+
prompter: Prompter;
|
|
12
|
+
};
|
|
13
|
+
export declare function createAddFeatureUseCase(deps: AddFeatureDeps): {
|
|
14
|
+
execute: (input: AddFeatureInput) => Promise<void>;
|
|
15
|
+
};
|