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