@omega.js/manager 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +14 -0
- package/LICENSE +98 -0
- package/README.md +165 -0
- package/bin/omega +2 -0
- package/bin/omg +2 -0
- package/claude-plugin/.claude-plugin/plugin.json +11 -0
- package/claude-plugin/.mcp.json +9 -0
- package/claude-plugin/README.md +139 -0
- package/claude-plugin/hooks/gate/mark.sh +58 -0
- package/claude-plugin/hooks/gate/run.sh +97 -0
- package/claude-plugin/hooks/guard/run.sh +249 -0
- package/claude-plugin/hooks/hooks.json +63 -0
- package/claude-plugin/hooks/inject/run.sh +127 -0
- package/claude-plugin/hooks/lib/omega-gate.sh +20 -0
- package/claude-plugin/hooks/lib/omega-scope.sh +41 -0
- package/claude-plugin/hooks/lib/omega-skills.sh +209 -0
- package/claude-plugin/hooks/quality/run.sh +132 -0
- package/claude-plugin/hooks/shape/run.sh +45 -0
- package/claude-plugin/mcp-router-launch.js +29 -0
- package/claude-plugin/skills/README.md +48 -0
- package/claude-plugin/skills/accessibility/SKILL.md +31 -0
- package/claude-plugin/skills/analytics/SKILL.md +30 -0
- package/claude-plugin/skills/backend/SKILL.md +25 -0
- package/claude-plugin/skills/brandcheck/SKILL.md +29 -0
- package/claude-plugin/skills/browser/SKILL.md +64 -0
- package/claude-plugin/skills/client/SKILL.md +24 -0
- package/claude-plugin/skills/desktop/SKILL.md +25 -0
- package/claude-plugin/skills/extension/SKILL.md +25 -0
- package/claude-plugin/skills/main/SKILL.md +54 -0
- package/claude-plugin/skills/manager/SKILL.md +25 -0
- package/claude-plugin/skills/seo/SKILL.md +36 -0
- package/claude-plugin/skills/theme/SKILL.md +33 -0
- package/claude-plugin/skills/web/SKILL.md +29 -0
- package/dist/cli-run.js +34 -0
- package/dist/cli.js +29 -0
- package/dist/commands/build.js +17 -0
- package/dist/commands/clean.js +16 -0
- package/dist/commands/company.js +46 -0
- package/dist/commands/deploy.js +143 -0
- package/dist/commands/dev.js +437 -0
- package/dist/commands/devlog.js +25 -0
- package/dist/commands/help.js +48 -0
- package/dist/commands/manage.js +53 -0
- package/dist/commands/migrate.js +76 -0
- package/dist/commands/onboard.js +31 -0
- package/dist/commands/pipeline.js +319 -0
- package/dist/commands/test.js +380 -0
- package/dist/commands/update.js +128 -0
- package/dist/commands/version.js +8 -0
- package/dist/company-init.js +167 -0
- package/dist/company.js +283 -0
- package/dist/config.js +1359 -0
- package/dist/devlog/index.js +226 -0
- package/dist/devlog/lib/collect-commits.js +136 -0
- package/dist/devlog/lib/generate-post.js +201 -0
- package/dist/devlog/lib/ghostii.js +122 -0
- package/dist/devlog/lib/project-map.js +98 -0
- package/dist/devlog/lib/publish-website.js +88 -0
- package/dist/index.js +45 -0
- package/dist/lib/agents-md.js +201 -0
- package/dist/lib/analytics-secret.js +22 -0
- package/dist/lib/argv.js +21 -0
- package/dist/lib/auth-admin.js +120 -0
- package/dist/lib/automation-client.js +210 -0
- package/dist/lib/backend-marketing.js +49 -0
- package/dist/lib/brand.js +240 -0
- package/dist/lib/bundle-id.js +53 -0
- package/dist/lib/claude-settings.js +125 -0
- package/dist/lib/company-scaffold.js +213 -0
- package/dist/lib/company.js +227 -0
- package/dist/lib/config-flow.js +350 -0
- package/dist/lib/config-write.js +41 -0
- package/dist/lib/custom-target.js +75 -0
- package/dist/lib/domain-utils.js +19 -0
- package/dist/lib/duration.js +39 -0
- package/dist/lib/env-order.js +236 -0
- package/dist/lib/env-secret.js +78 -0
- package/dist/lib/firestore-rest.js +326 -0
- package/dist/lib/framework-bin.js +156 -0
- package/dist/lib/gitignore.js +63 -0
- package/dist/lib/google-auth.js +495 -0
- package/dist/lib/google-token.js +66 -0
- package/dist/lib/jwt.js +31 -0
- package/dist/lib/legacy-oauth.js +59 -0
- package/dist/lib/node-version.js +127 -0
- package/dist/lib/owner-plan.js +78 -0
- package/dist/lib/package-scripts.js +152 -0
- package/dist/lib/preflight.js +470 -0
- package/dist/lib/product-create.js +144 -0
- package/dist/lib/run-command.js +74 -0
- package/dist/lib/run-gates.js +70 -0
- package/dist/lib/run-output.js +42 -0
- package/dist/lib/run-summary.js +384 -0
- package/dist/lib/scaffold.js +427 -0
- package/dist/lib/service-input.js +207 -0
- package/dist/lib/service-runner.js +466 -0
- package/dist/lib/stale.js +24 -0
- package/dist/lib/target-selection.js +155 -0
- package/dist/lib/verb-fanout.js +128 -0
- package/dist/lib/verify-live.js +188 -0
- package/dist/manage.js +311 -0
- package/dist/omega-bin.js +7 -0
- package/dist/onboard.js +532 -0
- package/dist/services/account/ensure/users.js +259 -0
- package/dist/services/account/index.js +97 -0
- package/dist/services/account/lib/backend-client.js +107 -0
- package/dist/services/account/lib/password.js +36 -0
- package/dist/services/account/lib/resolve-password.js +100 -0
- package/dist/services/advertising/ensure/sites.js +101 -0
- package/dist/services/advertising/index.js +101 -0
- package/dist/services/advertising/lib/adsense-api.js +41 -0
- package/dist/services/ai/ensure/keys.js +21 -0
- package/dist/services/ai/index.js +36 -0
- package/dist/services/analytics/ensure/google-firebase-link.js +230 -0
- package/dist/services/analytics/ensure/google-streams.js +256 -0
- package/dist/services/analytics/ensure/meta-pixel.js +22 -0
- package/dist/services/analytics/ensure/tiktok-pixel.js +22 -0
- package/dist/services/analytics/index.js +134 -0
- package/dist/services/analytics/lib/analytics-api.js +156 -0
- package/dist/services/analytics/lib/meta-api.js +83 -0
- package/dist/services/analytics/lib/pixel-account.js +78 -0
- package/dist/services/analytics/lib/pixel-provision.js +152 -0
- package/dist/services/analytics/lib/pixel-specs.js +57 -0
- package/dist/services/analytics/lib/pixel-token.js +88 -0
- package/dist/services/analytics/lib/property-flow.js +77 -0
- package/dist/services/analytics/lib/tiktok-api.js +157 -0
- package/dist/services/analytics/lib/tiktok-auth.js +153 -0
- package/dist/services/assets/ensure/logo-gen.js +68 -0
- package/dist/services/assets/index.js +109 -0
- package/dist/services/assets/lib/assets-config.js +168 -0
- package/dist/services/assets/lib/brandmark-api.js +160 -0
- package/dist/services/assets/lib/derived.js +113 -0
- package/dist/services/assets/lib/font-loader.js +67 -0
- package/dist/services/assets/lib/reconcile.js +122 -0
- package/dist/services/assets/lib/reset.js +118 -0
- package/dist/services/assets/lib/svg-logo-generator.js +154 -0
- package/dist/services/assets/lib/svg-to-black.js +32 -0
- package/dist/services/assets/write/favicons.js +82 -0
- package/dist/services/assets/write/icons.js +64 -0
- package/dist/services/assets/write/process.js +96 -0
- package/dist/services/assets/write/reconcile.js +30 -0
- package/dist/services/assets/write/social-icons.js +108 -0
- package/dist/services/assets/write/templates.js +345 -0
- package/dist/services/bookmark/ensure/sync.js +255 -0
- package/dist/services/bookmark/index.js +17 -0
- package/dist/services/campaigns/ensure/contact-person.js +40 -0
- package/dist/services/campaigns/ensure/custom-fields.js +84 -0
- package/dist/services/campaigns/ensure/domain-auth.js +92 -0
- package/dist/services/campaigns/ensure/event-webhook.js +89 -0
- package/dist/services/campaigns/ensure/link-branding.js +187 -0
- package/dist/services/campaigns/ensure/list.js +50 -0
- package/dist/services/campaigns/ensure/segments.js +109 -0
- package/dist/services/campaigns/ensure/sender-identity.js +153 -0
- package/dist/services/campaigns/ensure/unsubscribe-groups.js +116 -0
- package/dist/services/campaigns/index.js +79 -0
- package/dist/services/campaigns/lib/dns-sync.js +81 -0
- package/dist/services/campaigns/lib/segment-query.js +138 -0
- package/dist/services/campaigns/lib/sendgrid-api.js +287 -0
- package/dist/services/captcha/ensure/site-key.js +83 -0
- package/dist/services/captcha/index.js +78 -0
- package/dist/services/captcha/lib/console-url.js +45 -0
- package/dist/services/captcha/lib/recaptcha-api.js +36 -0
- package/dist/services/certificates/ensure/api-key.js +22 -0
- package/dist/services/certificates/ensure/bundle-ids.js +115 -0
- package/dist/services/certificates/ensure/certificates.js +187 -0
- package/dist/services/certificates/ensure/profiles.js +143 -0
- package/dist/services/certificates/index.js +225 -0
- package/dist/services/certificates/lib/apple-api.js +183 -0
- package/dist/services/certificates/lib/certificate-manager.js +252 -0
- package/dist/services/certificates/lib/identifier-manager.js +107 -0
- package/dist/services/certificates/lib/keychain.js +135 -0
- package/dist/services/certificates/lib/manual-walkthrough.js +165 -0
- package/dist/services/certificates/lib/profile-manager.js +115 -0
- package/dist/services/chat/data/baseline-knowledge.md +96 -0
- package/dist/services/chat/ensure/chat.js +106 -0
- package/dist/services/chat/ensure/user.js +45 -0
- package/dist/services/chat/index.js +139 -0
- package/dist/services/chat/lib/baseline-knowledge.js +137 -0
- package/dist/services/cloud/ensure/authentication.js +267 -0
- package/dist/services/cloud/ensure/billing.js +120 -0
- package/dist/services/cloud/ensure/cloud-messaging.js +105 -0
- package/dist/services/cloud/ensure/database.js +60 -0
- package/dist/services/cloud/ensure/firestore.js +79 -0
- package/dist/services/cloud/ensure/functions.js +49 -0
- package/dist/services/cloud/ensure/hosting.js +398 -0
- package/dist/services/cloud/ensure/oauth-consent.js +248 -0
- package/dist/services/cloud/ensure/project-settings.js +72 -0
- package/dist/services/cloud/ensure/sdk-config.js +95 -0
- package/dist/services/cloud/ensure/service-account.js +152 -0
- package/dist/services/cloud/ensure/services.js +103 -0
- package/dist/services/cloud/ensure/storage.js +47 -0
- package/dist/services/cloud/index.js +130 -0
- package/dist/services/cloud/lib/access-heal.js +130 -0
- package/dist/services/cloud/lib/firebase-api.js +662 -0
- package/dist/services/cloud/lib/project-flow.js +102 -0
- package/dist/services/directory/ensure/entry.js +48 -0
- package/dist/services/directory/index.js +64 -0
- package/dist/services/directory/lib/blocks.js +104 -0
- package/dist/services/disperse/index.js +45 -0
- package/dist/services/disperse/write/certs.js +117 -0
- package/dist/services/domain/ensure/nameservers.js +179 -0
- package/dist/services/domain/index.js +69 -0
- package/dist/services/domain/lib/namecheap-api.js +167 -0
- package/dist/services/domain/lib/registrars.js +46 -0
- package/dist/services/domain/lib/whitelist-walkthrough.js +76 -0
- package/dist/services/edge/ensure/cache-rules.js +105 -0
- package/dist/services/edge/ensure/dns-records.js +304 -0
- package/dist/services/edge/ensure/email-routing.js +292 -0
- package/dist/services/edge/ensure/rules-configuration.js +98 -0
- package/dist/services/edge/ensure/rules-managed-transforms.js +101 -0
- package/dist/services/edge/ensure/rules-redirect.js +107 -0
- package/dist/services/edge/ensure/rules-response-headers.js +90 -0
- package/dist/services/edge/ensure/rules-security.js +142 -0
- package/dist/services/edge/ensure/speed-scheduled-tests.js +98 -0
- package/dist/services/edge/ensure/workers.js +219 -0
- package/dist/services/edge/ensure/zone-settings.js +108 -0
- package/dist/services/edge/ensure/zone.js +183 -0
- package/dist/services/edge/index.js +73 -0
- package/dist/services/edge/lib/cloudflare-api.js +84 -0
- package/dist/services/edge/lib/dns-records-helpers.js +518 -0
- package/dist/services/edge/lib/read-cache.js +16 -0
- package/dist/services/edge/lib/ruleset-helper.js +108 -0
- package/dist/services/edge/workers/omega-api-proxy.js +43 -0
- package/dist/services/email/data/baseline-filter.md +4 -0
- package/dist/services/email/data/baseline-knowledge.md +86 -0
- package/dist/services/email/ensure/agent.js +107 -0
- package/dist/services/email/ensure/user.js +45 -0
- package/dist/services/email/index.js +138 -0
- package/dist/services/email/lib/baseline.js +82 -0
- package/dist/services/email/lib/knowledge-file.js +53 -0
- package/dist/services/forms/ensure/form.js +46 -0
- package/dist/services/forms/ensure/user.js +45 -0
- package/dist/services/forms/index.js +138 -0
- package/dist/services/migrations/ensure/notifications.js +189 -0
- package/dist/services/migrations/ensure/orders.js +34 -0
- package/dist/services/migrations/ensure/payment-provider.js +132 -0
- package/dist/services/migrations/ensure/payments-intents.js +34 -0
- package/dist/services/migrations/ensure/state-retirement.js +266 -0
- package/dist/services/migrations/ensure/targets-rename.js +124 -0
- package/dist/services/migrations/ensure/users.js +1176 -0
- package/dist/services/migrations/index.js +101 -0
- package/dist/services/migrations/lib/attribution-touch.js +64 -0
- package/dist/services/migrations/lib/ensure-metadata.js +144 -0
- package/dist/services/migrations/lib/migration-runner.js +473 -0
- package/dist/services/migrations/lib/sanitize-strings.js +112 -0
- package/dist/services/migrations/lib/schema-validator.js +154 -0
- package/dist/services/monitoring/ensure/dsn.js +54 -0
- package/dist/services/monitoring/ensure/projects.js +135 -0
- package/dist/services/monitoring/index.js +54 -0
- package/dist/services/monitoring/lib/sentry-api.js +94 -0
- package/dist/services/newsletter/ensure/custom-fields.js +90 -0
- package/dist/services/newsletter/ensure/publication.js +94 -0
- package/dist/services/newsletter/ensure/segments.js +140 -0
- package/dist/services/newsletter/ensure/webhook.js +108 -0
- package/dist/services/newsletter/index.js +64 -0
- package/dist/services/newsletter/lib/beehiiv-api.js +124 -0
- package/dist/services/newsletter/lib/segment-automation.js +577 -0
- package/dist/services/payment/ensure/chargebee-account.js +30 -0
- package/dist/services/payment/ensure/chargebee-products.js +359 -0
- package/dist/services/payment/ensure/chargebee-webhook.js +113 -0
- package/dist/services/payment/ensure/paypal-account.js +36 -0
- package/dist/services/payment/ensure/paypal-products.js +374 -0
- package/dist/services/payment/ensure/paypal-webhook.js +128 -0
- package/dist/services/payment/ensure/stripe-account.js +93 -0
- package/dist/services/payment/ensure/stripe-disputes.js +56 -0
- package/dist/services/payment/ensure/stripe-products.js +245 -0
- package/dist/services/payment/ensure/stripe-radar.js +74 -0
- package/dist/services/payment/ensure/stripe-webhook.js +130 -0
- package/dist/services/payment/index.js +163 -0
- package/dist/services/payment/lib/chargebee-api.js +338 -0
- package/dist/services/payment/lib/payment-utils.js +116 -0
- package/dist/services/payment/lib/paypal-api.js +354 -0
- package/dist/services/payment/lib/provider-setup.js +134 -0
- package/dist/services/payment/lib/stripe-api.js +152 -0
- package/dist/services/repo/ensure/org.js +70 -0
- package/dist/services/repo/ensure/pages.js +72 -0
- package/dist/services/repo/ensure/repo.js +90 -0
- package/dist/services/repo/index.js +52 -0
- package/dist/services/repo/lib/github-api.js +196 -0
- package/dist/services/search/ensure/ga-link.js +57 -0
- package/dist/services/search/ensure/property.js +137 -0
- package/dist/services/search/ensure/sitemaps.js +70 -0
- package/dist/services/search/index.js +61 -0
- package/dist/services/search/lib/search-console-api.js +92 -0
- package/dist/services/seo/ensure/github-repos.js +271 -0
- package/dist/services/seo/index.js +55 -0
- package/dist/services/seo/lib/gh-api.js +161 -0
- package/dist/services/seo/templates/developer-tool/.github/workflows/maintenance.yml +25 -0
- package/dist/services/seo/templates/developer-tool/.nvmrc +1 -0
- package/dist/services/seo/templates/developer-tool/_README.md.js +121 -0
- package/dist/services/seo/templates/developer-tool/_package.json.js +33 -0
- package/dist/services/seo/templates/developer-tool/src/index.js +120 -0
- package/dist/services/seo/templates/index.js +57 -0
- package/dist/services/server/ensure/brands.js +63 -0
- package/dist/services/server/index.js +42 -0
- package/dist/services/testing/ensure/target-checks.js +97 -0
- package/dist/services/testing/index.js +11 -0
- package/dist/services/testing/lib/checks.js +467 -0
- package/dist/services/update/index.js +20 -0
- package/dist/services/update/lib/cache.js +59 -0
- package/dist/services/update/lib/fingerprint.js +157 -0
- package/dist/services/update/write/targets.js +206 -0
- package/dist/services/workspace/ensure/agents.js +42 -0
- package/dist/services/workspace/ensure/claude-settings.js +34 -0
- package/dist/services/workspace/ensure/config.js +54 -0
- package/dist/services/workspace/ensure/defaults.js +60 -0
- package/dist/services/workspace/ensure/env-keys.js +55 -0
- package/dist/services/workspace/ensure/env-order.js +66 -0
- package/dist/services/workspace/ensure/env-rules.js +97 -0
- package/dist/services/workspace/ensure/gitignore.js +18 -0
- package/dist/services/workspace/ensure/scripts.js +126 -0
- package/dist/services/workspace/ensure/structure.js +97 -0
- package/dist/services/workspace/ensure/translation-sdk.js +148 -0
- package/dist/services/workspace/ensure/workflows.js +54 -0
- package/dist/services/workspace/index.js +8 -0
- package/dist/vendor/account/engine.js +182 -0
- package/dist/vendor/account/features.js +220 -0
- package/dist/vendor/account/index.js +53 -0
- package/dist/vendor/account/schema.js +272 -0
- package/dist/vendor/account/subscription.js +38 -0
- package/dist/vendor/config/company.js +31 -0
- package/dist/vendor/config/defaults.js +173 -0
- package/dist/vendor/config/demo.js +18 -0
- package/dist/vendor/config/desktop-artifacts.js +110 -0
- package/dist/vendor/config/edit.js +769 -0
- package/dist/vendor/config/env-delivery.js +145 -0
- package/dist/vendor/config/env-rules.js +93 -0
- package/dist/vendor/config/env-schema.js +1078 -0
- package/dist/vendor/config/env.js +445 -0
- package/dist/vendor/config/hooks.js +97 -0
- package/dist/vendor/config/index.js +237 -0
- package/dist/vendor/config/instances.js +208 -0
- package/dist/vendor/config/load.js +490 -0
- package/dist/vendor/config/merge.js +68 -0
- package/dist/vendor/config/order.js +139 -0
- package/dist/vendor/config/ports.js +374 -0
- package/dist/vendor/config/providers.js +32 -0
- package/dist/vendor/config/repo.js +142 -0
- package/dist/vendor/config/retired-keys.js +430 -0
- package/dist/vendor/config/schema.js +1610 -0
- package/dist/vendor/config/secrets.js +50 -0
- package/dist/vendor/config/seed.js +34 -0
- package/dist/vendor/config/site-global.js +205 -0
- package/dist/vendor/config/validate.js +554 -0
- package/dist/vendor/config/winback.js +61 -0
- package/dist/vendor/devkit/attach-log-file.js +262 -0
- package/dist/vendor/devkit/certs.js +199 -0
- package/dist/vendor/devkit/ci-workflows.js +520 -0
- package/dist/vendor/devkit/cli-router.js +156 -0
- package/dist/vendor/devkit/command-path.js +46 -0
- package/dist/vendor/devkit/deploy-record.js +180 -0
- package/dist/vendor/devkit/flows.js +317 -0
- package/dist/vendor/devkit/local-https.js +360 -0
- package/dist/vendor/devkit/local.js +1905 -0
- package/dist/vendor/devkit/logger.js +128 -0
- package/dist/vendor/devkit/omega-bin.js +345 -0
- package/dist/vendor/devkit/prompt.js +187 -0
- package/dist/vendor/devkit/safe-install.js +18 -0
- package/dist/vendor/devkit/stop-signals.js +28 -0
- package/dist/vendor/devkit/test/scope.js +162 -0
- package/dist/vendor/devkit/translate/cache.js +84 -0
- package/dist/vendor/devkit/translate/engine.js +243 -0
- package/dist/vendor/devkit/translate/index.js +49 -0
- package/dist/vendor/devkit/translate/languages.js +134 -0
- package/dist/vendor/devkit/translate/providers.js +188 -0
- package/dist/vendor/devkit/update.js +569 -0
- package/docs/AGENTS.md +200 -0
- package/docs/account.md +45 -0
- package/docs/advertising.md +46 -0
- package/docs/ai.md +34 -0
- package/docs/analytics.md +69 -0
- package/docs/assets.md +57 -0
- package/docs/bookmark.md +26 -0
- package/docs/brand.md +151 -0
- package/docs/campaigns.md +96 -0
- package/docs/captcha.md +46 -0
- package/docs/certificates.md +68 -0
- package/docs/chat.md +47 -0
- package/docs/cloud.md +110 -0
- package/docs/company.md +64 -0
- package/docs/directory.md +140 -0
- package/docs/disperse.md +46 -0
- package/docs/domain.md +56 -0
- package/docs/edge.md +234 -0
- package/docs/email.md +42 -0
- package/docs/forms.md +48 -0
- package/docs/index.md +109 -0
- package/docs/migration.md +203 -0
- package/docs/migrations.md +56 -0
- package/docs/monitoring.md +41 -0
- package/docs/newsletter.md +48 -0
- package/docs/payment.md +83 -0
- package/docs/repo.md +48 -0
- package/docs/search.md +44 -0
- package/docs/seo.md +34 -0
- package/docs/server.md +37 -0
- package/docs/shared/agent-docs.md +89 -0
- package/docs/shared/analytics.md +612 -0
- package/docs/shared/brands.md +51 -0
- package/docs/shared/breaking-changes.md +497 -0
- package/docs/shared/config.md +1387 -0
- package/docs/shared/deploys.md +215 -0
- package/docs/shared/icons.md +201 -0
- package/docs/shared/local-dev.md +147 -0
- package/docs/shared/logging.md +202 -0
- package/docs/shared/monitoring.md +153 -0
- package/docs/shared/publishing.md +183 -0
- package/docs/shared/rulings.md +34 -0
- package/docs/shared/testing.md +147 -0
- package/docs/shared/theming.md +604 -0
- package/docs/shared/translation.md +291 -0
- package/docs/shared/updates.md +61 -0
- package/docs/testing.md +34 -0
- package/docs/update.md +36 -0
- package/docs/workspace.md +64 -0
- package/package.json +88 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `omega-manager company <init|adopt>` — the COMPANY rung's own verb.
|
|
3
|
+
*
|
|
4
|
+
* omega company init [path] scaffold a company workspace (default: cwd)
|
|
5
|
+
* omega company adopt <brand-path> stamp a brand so it inherits this company
|
|
6
|
+
*
|
|
7
|
+
* Everything else about a company workspace rides the verbs it already has:
|
|
8
|
+
* `omega manage` from a company root fans out over its brands, `omega
|
|
9
|
+
* onboard` creates a new brand under brands.roots[0] and stamps it.
|
|
10
|
+
*/
|
|
11
|
+
const chalk = require('chalk').default;
|
|
12
|
+
|
|
13
|
+
const { runCompanyInit, runCompanyAdopt } = require('../company-init.js');
|
|
14
|
+
|
|
15
|
+
const USAGE = [
|
|
16
|
+
'Usage: omega company <command>',
|
|
17
|
+
'',
|
|
18
|
+
' init [path] scaffold a company workspace (default: the current directory)',
|
|
19
|
+
' adopt <brand-path> stamp a brand so it inherits this company workspace',
|
|
20
|
+
].join('\n');
|
|
21
|
+
|
|
22
|
+
module.exports = async (options) => {
|
|
23
|
+
const subcommand = options._?.[1];
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
if (subcommand === 'init') {
|
|
27
|
+
runCompanyInit(options._?.[2] || process.cwd());
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (subcommand === 'adopt') {
|
|
32
|
+
runCompanyAdopt(process.cwd(), options._?.[2]);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
console.error(subcommand
|
|
37
|
+
? `${chalk.red('❌ Unknown company command')} ${chalk.dim(`"${subcommand}"`)}\n\n${USAGE}`
|
|
38
|
+
: USAGE);
|
|
39
|
+
process.exitCode = 1;
|
|
40
|
+
} catch (error) {
|
|
41
|
+
console.error(`${chalk.red('❌ Error')}${chalk.dim(`: ${error.message}`)}`);
|
|
42
|
+
process.exitCode = 1;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
module.exports.USAGE = USAGE;
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `omega deploy` at a brand root — D13's brand layer: fan the DELIBERATE
|
|
3
|
+
* publish out over the brand's targets, each in its own framework's hands
|
|
4
|
+
* (each target's own `omega deploy` verb — web sync/dispatch or direct lane,
|
|
5
|
+
* backend `firebase deploy`, desktop release, extension publish; the full
|
|
6
|
+
* per-target contract is docs/shared/deploys.md).
|
|
7
|
+
*
|
|
8
|
+
* omega deploy → every target, backend first
|
|
9
|
+
* omega deploy --target=backend → one target (target key or dir name)
|
|
10
|
+
* omega deploy --target=web,backend → explicit set
|
|
11
|
+
* omega deploy --dry-run → forwarded — each target prints its plan
|
|
12
|
+
*
|
|
13
|
+
* ORDER: the DELIVERY lane first (#678) — the same `BOOT_SERVICES` walk an
|
|
14
|
+
* `omega dev` boot runs, so config, assets and certs reach the targets before
|
|
15
|
+
* anything publishes them — then backend, then web, then the rest: the API
|
|
16
|
+
* must be live before the site that points at it. Every flag but --target=
|
|
17
|
+
* forwards verbatim to each target's framework deploy (--dry-run, --no-sync,
|
|
18
|
+
* --direct, --platforms, …); targets run sequentially with streamed output. A
|
|
19
|
+
* failing target STOPS the run (a broken API is no base for the site) unless
|
|
20
|
+
* --continue-on-error; any failure → exit 1. A --target= token matching
|
|
21
|
+
* nothing is an error, never a deploy-everything fallback — and deploys stay deliberate:
|
|
22
|
+
* nothing invokes this command but the human-typed verb (D13).
|
|
23
|
+
*/
|
|
24
|
+
const path = require('node:path');
|
|
25
|
+
const chalk = require('chalk').default;
|
|
26
|
+
const attachLogFile = require('../vendor/devkit/attach-log-file.js');
|
|
27
|
+
|
|
28
|
+
const { runManage } = require('../manage.js');
|
|
29
|
+
const { resolveBrandRoot, discoverTargets } = require('../lib/brand.js');
|
|
30
|
+
const { resolveTargetRun } = require('../lib/framework-bin.js');
|
|
31
|
+
const { runCommand } = require('../lib/run-command.js');
|
|
32
|
+
const { DEPLOY_ORDER, PICKER_FLAG, assertPickerFlags, selectTargets, buildForwardedFlags } = require('../lib/target-selection.js');
|
|
33
|
+
|
|
34
|
+
module.exports = async (options = {}) => {
|
|
35
|
+
assertPickerFlags(options);
|
|
36
|
+
|
|
37
|
+
const brandRoot = resolveBrandRoot(process.cwd());
|
|
38
|
+
if (!brandRoot) {
|
|
39
|
+
console.error(chalk.red('✗ Not inside a brand monorepo (no config/omega.json5 up the tree) — run inside a brand, or inside a target for that target\'s deploy.'));
|
|
40
|
+
process.exitCode = 1;
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Tee the whole fan-out — delivery lane included — to
|
|
45
|
+
// <brandRoot>/logs/deploy.log (#623): the publish verdict on disk. Only the
|
|
46
|
+
// backend keeps its own dist/deploy.log; this file is the one full record.
|
|
47
|
+
attachLogFile(path.join(brandRoot, 'logs', 'deploy.log'));
|
|
48
|
+
|
|
49
|
+
const targets = discoverTargets(brandRoot).filter((entry) => entry.target || entry.custom);
|
|
50
|
+
const { selected } = selectTargets({ targets, target: options[PICKER_FLAG] });
|
|
51
|
+
|
|
52
|
+
if (selected.length === 0) {
|
|
53
|
+
// Only an empty brand reaches here: a picker token that named nothing
|
|
54
|
+
// already stopped the run in the selector (#780).
|
|
55
|
+
console.error(chalk.red('✗ This brand has no targets under targets/ — nothing deployed.'));
|
|
56
|
+
process.exitCode = 1;
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const forwarded = buildForwardedFlags(options);
|
|
61
|
+
const continueOnError = !!(options['continue-on-error'] || options.continueOnError);
|
|
62
|
+
const dryRun = !!(options['dry-run'] || options.dryRun);
|
|
63
|
+
|
|
64
|
+
console.log(chalk.bold(`\nOMEGA brand deploy — ${path.basename(brandRoot)} ${chalk.dim(`(${selected.map((entry) => entry.target || entry.name).join(' → ')})`)}`));
|
|
65
|
+
|
|
66
|
+
// ─── Delivery lane, once, before the fan-out ───────────────────────────────
|
|
67
|
+
// Brand inputs (config, assets, certs) reach a target through ONE step
|
|
68
|
+
// (#678), and a deploy is one of its two triggers: the lane `omega dev`
|
|
69
|
+
// boots is asked for BY NAME here, so the service list can only ever be
|
|
70
|
+
// config.js's BOOT_SERVICES — never a second copy that drifts from it. A
|
|
71
|
+
// publish must not ship inputs a manage run happened to be current on.
|
|
72
|
+
console.log(chalk.cyan(`\n─── delivery lane ${chalk.dim('(brand inputs → targets)')} ───`));
|
|
73
|
+
const delivery = await runManage(brandRoot, { lane: 'boot', dryRun });
|
|
74
|
+
if (delivery.hasErrors) {
|
|
75
|
+
console.error(chalk.red('\n✗ The delivery lane reported errors — nothing deployed (fix them above, then deploy again).'));
|
|
76
|
+
process.exitCode = 1;
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ─── Execute in order, streaming each target's output ──────────────────────
|
|
81
|
+
const summary = [];
|
|
82
|
+
let failed = false;
|
|
83
|
+
|
|
84
|
+
for (const [index, entry] of selected.entries()) {
|
|
85
|
+
const label = `[${index + 1}/${selected.length}] ${entry.name}`;
|
|
86
|
+
const run = resolveTargetRun(entry, 'deploy', forwarded, { dryRun });
|
|
87
|
+
|
|
88
|
+
// A custom target that declares no deploy script steps aside loudly —
|
|
89
|
+
// there is nothing to publish and nothing broken (#603)
|
|
90
|
+
if (run.kind === 'skip') {
|
|
91
|
+
console.log(chalk.dim(`\n⊘ ${label}: ${run.detail} — skipped`));
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Its script cannot be handed --dry-run, so the dry run stops at the plan
|
|
96
|
+
if (run.kind === 'plan') {
|
|
97
|
+
console.log(chalk.dim(`\n⊘ ${label}: dry run — ${run.detail}`));
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (run.kind === 'error') {
|
|
102
|
+
console.log(chalk.red(`\n✗ ${label}: ${run.detail}`));
|
|
103
|
+
summary.push({ name: entry.name, ok: false, detail: run.detail });
|
|
104
|
+
failed = true;
|
|
105
|
+
if (!continueOnError) break;
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
console.log(chalk.cyan(`${`\n─── ${label} ${chalk.dim(`(${run.framework || 'custom'})`)} — ${run.label}`.trimEnd()} ───`));
|
|
110
|
+
const result = await runCommand(run.command, run.args, entry.path);
|
|
111
|
+
|
|
112
|
+
summary.push({ name: entry.name, ok: result.success, detail: result.error });
|
|
113
|
+
if (!result.success) {
|
|
114
|
+
failed = true;
|
|
115
|
+
if (!continueOnError) {
|
|
116
|
+
console.error(chalk.red(`\n✗ ${entry.name} deploy failed — stopping (later targets depend on it; --continue-on-error overrides)`));
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// ─── Summary + aggregate exit ──────────────────────────────────────────────
|
|
123
|
+
console.log(chalk.bold('\nDeploy summary'));
|
|
124
|
+
for (const entry of summary) {
|
|
125
|
+
console.log(entry.ok
|
|
126
|
+
? ` ${chalk.green('✓')} ${entry.name}`
|
|
127
|
+
: ` ${chalk.red('✗')} ${entry.name} ${chalk.dim(`— ${entry.detail}`)}`);
|
|
128
|
+
}
|
|
129
|
+
const skipped = selected.length - summary.length;
|
|
130
|
+
if (skipped > 0) {
|
|
131
|
+
console.log(chalk.dim(` ⊘ ${skipped} target${skipped === 1 ? '' : 's'} not attempted after the failure`));
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (failed) {
|
|
135
|
+
process.exitCode = 1;
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
// Re-exported for readers that came to the deploy command for them — the one
|
|
140
|
+
// home is lib/target-selection.js.
|
|
141
|
+
module.exports.selectTargets = selectTargets;
|
|
142
|
+
module.exports.buildForwardedFlags = buildForwardedFlags;
|
|
143
|
+
module.exports.DEPLOY_ORDER = DEPLOY_ORDER;
|
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `omega dev` (brand root) — ONE command boots the local stack: the website
|
|
3
|
+
* dev server AND the backend emulator suite together, each spawned in its
|
|
4
|
+
* own target with its own Node (web/backend pin different majors), output
|
|
5
|
+
* line-prefixed per target, one Ctrl-C killing everything.
|
|
6
|
+
*
|
|
7
|
+
* Target selection (Ian 2026-07-16): the default set is web + backend — the
|
|
8
|
+
* local web loop. GUI/watcher targets (desktop opens an Electron window,
|
|
9
|
+
* extension runs a build watcher) never boot unless asked.
|
|
10
|
+
* omega dev web + backend
|
|
11
|
+
* omega dev --target=web one leg (target key or dir name)
|
|
12
|
+
* omega dev --target=web,backend explicit set
|
|
13
|
+
* omega dev --all every target with a dev leg
|
|
14
|
+
* omega dev --full boot on the WHOLE manage walk, not the lane
|
|
15
|
+
*
|
|
16
|
+
* Boot order: the freshness sweep first (one dist check for every lane), then
|
|
17
|
+
* a manage cycle — the boot lane (workspace, assets, disperse: the local
|
|
18
|
+
* redistribution the legs consume), then the legs. See docs/shared/local-dev.md
|
|
19
|
+
* for what refreshes when.
|
|
20
|
+
*
|
|
21
|
+
* Port coordination is already solved (N7): the backend leg publishes its
|
|
22
|
+
* emulator ports; the web leg reads them and bakes dev.ports into pages —
|
|
23
|
+
* order tolerant, but backend boots first here so the fast path wins.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
// Libraries
|
|
27
|
+
const path = require('node:path');
|
|
28
|
+
const { spawn } = require('node:child_process');
|
|
29
|
+
const chalk = require('chalk').default;
|
|
30
|
+
const attachLogFile = require('../vendor/devkit/attach-log-file.js');
|
|
31
|
+
const { findTarget } = require('../vendor/devkit/omega-bin.js');
|
|
32
|
+
const { freshnessSweep, resolveLinkedMonorepo, startMonorepoWatch } = require('../vendor/devkit/local.js');
|
|
33
|
+
const { mkcertCaRootPem } = require('../vendor/devkit/local-https.js');
|
|
34
|
+
const { STOP_SIGNALS } = require('../vendor/devkit/stop-signals.js');
|
|
35
|
+
|
|
36
|
+
// Local
|
|
37
|
+
const { runManage } = require('../manage.js');
|
|
38
|
+
const { resolveBrandRoot, discoverTargets } = require('../lib/brand.js');
|
|
39
|
+
const { assertFamilyVersions } = require('../lib/preflight.js');
|
|
40
|
+
const { targetScripts } = require('../lib/custom-target.js');
|
|
41
|
+
const { resolveTargetNode, nodeEnvFor } = require('../lib/node-version.js');
|
|
42
|
+
const { PICKER_FLAG, assertPickerFlags, assertKnownTargets, parseTargetTokens, targetMatches } = require('../lib/target-selection.js');
|
|
43
|
+
|
|
44
|
+
// Target → the npm leg that IS local dev for that target
|
|
45
|
+
const DEV_LEGS = {
|
|
46
|
+
web: ['npm', 'run', 'start'], // omega dev — watch + serve (:4000)
|
|
47
|
+
backend: ['npm', 'run', 'emulator'], // omega emulator — FULL suite + seeded personas
|
|
48
|
+
desktop: ['npm', 'run', 'start'], // opt-in: opens an Electron window
|
|
49
|
+
extension: ['npm', 'run', 'start'], // opt-in: extension build watcher
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// Every custom target's leg is the same one: its own `start` script (#603)
|
|
53
|
+
const CUSTOM_DEV_LEG = ['npm', 'run', 'start'];
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* The leg that IS local dev for one discovered target.
|
|
57
|
+
*
|
|
58
|
+
* A backend in custom-server mode (#584) has no Cloud Functions to emulate, so
|
|
59
|
+
* its leg is its own `start` — the same script a custom target boots with. Its
|
|
60
|
+
* server is the local stack's API either way, so it keeps the backend's place
|
|
61
|
+
* in the default set and its boot-first ordering.
|
|
62
|
+
*
|
|
63
|
+
* @param {{ target: string, custom?: boolean, projectType?: string }} entry
|
|
64
|
+
* @returns {string[]} argv for the leg
|
|
65
|
+
*/
|
|
66
|
+
function devLegFor(entry) {
|
|
67
|
+
if (entry.custom || entry.projectType === 'custom') return CUSTOM_DEV_LEG;
|
|
68
|
+
return DEV_LEGS[entry.target] || CUSTOM_DEV_LEG;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Stop one dev leg. A leg is a CHAIN (npm run <leg> → the real server), so the
|
|
73
|
+
* SIGTERM goes to the leg's process group — signaling only the direct npm
|
|
74
|
+
* child leaves the grandchild (a firebase emulator) orphaned on pid 1, still
|
|
75
|
+
* holding its ports (#690). The direct kill is the fallback for a leg whose
|
|
76
|
+
* group is already gone.
|
|
77
|
+
*/
|
|
78
|
+
const stopChild = (child, killGroup = (pid, signal) => process.kill(pid, signal)) => {
|
|
79
|
+
try {
|
|
80
|
+
killGroup(-child.pid, 'SIGTERM');
|
|
81
|
+
} catch {
|
|
82
|
+
try {
|
|
83
|
+
child.kill('SIGTERM');
|
|
84
|
+
} catch {
|
|
85
|
+
// already gone
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
// Booted without flags — the local web loop
|
|
91
|
+
const DEFAULT_TARGETS = ['web', 'backend'];
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Pure target selection — which legs boot for a given flag set.
|
|
95
|
+
*
|
|
96
|
+
* Custom targets (#603) join the same fan-out: their leg is `npm run start`,
|
|
97
|
+
* and a custom target only reaches `custom` at all when its package.json
|
|
98
|
+
* declares that script — no script, no dev leg.
|
|
99
|
+
*
|
|
100
|
+
* @param {object} input
|
|
101
|
+
* @param {string[]} input.available - targets that have a dir in this brand
|
|
102
|
+
* @param {string[]} [input.custom] - custom target names with a `start` script
|
|
103
|
+
* @param {string} [input.target] - the --target= comma list: exact set to boot
|
|
104
|
+
* @param {boolean} [input.all] - start every target with a dev leg
|
|
105
|
+
* @returns {{ selected: string[], missing: string[] }}
|
|
106
|
+
* @throws {Error} when a --target= token names no dev leg
|
|
107
|
+
*/
|
|
108
|
+
function selectDevTargets({ available, custom = [], target, all }) {
|
|
109
|
+
// A custom target is a first-class leg once it has a start script — the
|
|
110
|
+
// default set boots it beside web + backend (it is part of the local stack,
|
|
111
|
+
// never an opt-in GUI surface)
|
|
112
|
+
const hasLeg = (name) => Boolean(DEV_LEGS[name]) || custom.includes(name);
|
|
113
|
+
const defaults = [...DEFAULT_TARGETS, ...custom].filter((name) => available.includes(name));
|
|
114
|
+
|
|
115
|
+
const tokens = parseTargetTokens(target);
|
|
116
|
+
const requested = tokens.length > 0
|
|
117
|
+
? tokens
|
|
118
|
+
: (all ? [...Object.keys(DEV_LEGS), ...custom] : defaults);
|
|
119
|
+
|
|
120
|
+
// A token naming no leg STOPS the boot (#780) — booting the rest of the set
|
|
121
|
+
// would serve a stack the human did not ask for. A named leg with no dir in
|
|
122
|
+
// this brand is a different thing: reported below, never invented.
|
|
123
|
+
assertKnownTargets(requested.filter((name) => !hasLeg(name)), [...Object.keys(DEV_LEGS), ...custom]);
|
|
124
|
+
|
|
125
|
+
const selected = requested.filter((name) => available.includes(name));
|
|
126
|
+
const missing = requested.filter((name) => !available.includes(name));
|
|
127
|
+
|
|
128
|
+
// Backend first: it publishes the emulator port map the web leg reads
|
|
129
|
+
selected.sort((a, b) => (a === 'backend' ? -1 : 0) - (b === 'backend' ? -1 : 0));
|
|
130
|
+
|
|
131
|
+
return { selected, missing };
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Consecutive-duplicate collapser for ONE leg output stream (#230).
|
|
136
|
+
*
|
|
137
|
+
* The Firebase emulator re-prints its own infra lines once per function
|
|
138
|
+
* instance — "i functions: Loaded environment variables from .env." dozens of
|
|
139
|
+
* times in a row — which buries the lines a human is actually watching for.
|
|
140
|
+
* Repeats of the line just emitted are swallowed and counted; the count
|
|
141
|
+
* surfaces as ONE note when a different line arrives (or the stream ends, so a
|
|
142
|
+
* leg that goes quiet mid-run never eats the tail). The rule is structural —
|
|
143
|
+
* any consecutive duplicate on any leg — never a list of known noisy strings.
|
|
144
|
+
*
|
|
145
|
+
* Blank lines are exempt: a note standing in for a run of them reads louder
|
|
146
|
+
* than the blanks it replaced.
|
|
147
|
+
*
|
|
148
|
+
* Stateful because a stream is; pure otherwise — lines in, lines out.
|
|
149
|
+
* @returns {{ push: (line: string) => string[], flush: () => string[] }}
|
|
150
|
+
*/
|
|
151
|
+
function createLineDeduper() {
|
|
152
|
+
let previous = null;
|
|
153
|
+
let repeats = 0;
|
|
154
|
+
|
|
155
|
+
const note = () => {
|
|
156
|
+
const pending = repeats > 0 ? [` (repeated ${repeats}×)`] : [];
|
|
157
|
+
repeats = 0;
|
|
158
|
+
return pending;
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
return {
|
|
162
|
+
push(line) {
|
|
163
|
+
if (line === previous && line.trim() !== '') {
|
|
164
|
+
repeats += 1;
|
|
165
|
+
return [];
|
|
166
|
+
}
|
|
167
|
+
const out = note();
|
|
168
|
+
previous = line;
|
|
169
|
+
out.push(line);
|
|
170
|
+
return out;
|
|
171
|
+
},
|
|
172
|
+
flush() {
|
|
173
|
+
previous = null;
|
|
174
|
+
return note();
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
module.exports = async (options = {}) => {
|
|
180
|
+
assertPickerFlags(options);
|
|
181
|
+
|
|
182
|
+
const brandRoot = resolveBrandRoot(process.cwd());
|
|
183
|
+
if (!brandRoot) {
|
|
184
|
+
console.error(chalk.red('✖ omega dev: no brand root found (looked for config/omega.json5 walking up from here)'));
|
|
185
|
+
process.exit(1);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Tee the brand-level fan-out — the boot manage cycle AND every leg's
|
|
189
|
+
// prefixed output — to <brandRoot>/logs/dev.log (#197), its OWN file: a boot
|
|
190
|
+
// used to truncate logs/manage.log and take the last service walk's record
|
|
191
|
+
// with it, and the two are read for different questions (#231).
|
|
192
|
+
attachLogFile(path.join(brandRoot, 'logs', 'dev.log'));
|
|
193
|
+
|
|
194
|
+
// A custom target (#603) joins the fan-out under its own NAME, and only
|
|
195
|
+
// when its package.json declares a `start` script — the manager never
|
|
196
|
+
// invents a leg for it.
|
|
197
|
+
const discovered = discoverTargets(brandRoot);
|
|
198
|
+
|
|
199
|
+
// Lockstep (#794): the same gate the manage walk opens with, run here too —
|
|
200
|
+
// before the freshness sweep and before any leg spawns. A boot on a brand
|
|
201
|
+
// whose targets carry different @omega.js versions would serve two copies of
|
|
202
|
+
// the client and validate one omega.json5 with two validators; nothing
|
|
203
|
+
// downstream can see it, so the refusal belongs at the door.
|
|
204
|
+
assertFamilyVersions({ brandRoot, targets: discovered });
|
|
205
|
+
|
|
206
|
+
const customLegs = discovered.filter((entry) => entry.custom && targetScripts(entry.path).start);
|
|
207
|
+
const targets = [
|
|
208
|
+
...discovered.filter((entry) => entry.target && DEV_LEGS[entry.target]),
|
|
209
|
+
...customLegs.map((entry) => ({ ...entry, target: entry.name })),
|
|
210
|
+
];
|
|
211
|
+
|
|
212
|
+
const custom = customLegs.map((entry) => entry.name);
|
|
213
|
+
|
|
214
|
+
// A --target= token names a target by KEY ('web') or by its dir name
|
|
215
|
+
// ('website') — the same two spellings every other brand-root verb takes
|
|
216
|
+
// (#780). The pairing lives in the discovered entries, so the dir spelling
|
|
217
|
+
// resolves to its key HERE, through the one shared matcher; a token that
|
|
218
|
+
// names nothing passes through untouched and the selector refuses it.
|
|
219
|
+
const picker = parseTargetTokens(options[PICKER_FLAG])
|
|
220
|
+
.map((token) => (targets.find((entry) => targetMatches(entry, token)) || {}).target || token)
|
|
221
|
+
.join(',');
|
|
222
|
+
|
|
223
|
+
const { selected, missing } = selectDevTargets({
|
|
224
|
+
available: targets.map((entry) => entry.target),
|
|
225
|
+
custom,
|
|
226
|
+
target: picker,
|
|
227
|
+
all: options.all,
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
missing.forEach((target) => {
|
|
231
|
+
console.log(chalk.yellow(`⊘ ${target}: no dir in this brand — skipped`));
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
if (selected.length === 0) {
|
|
235
|
+
console.error(chalk.red('✖ omega dev: nothing to boot (no selected target has a dir here)'));
|
|
236
|
+
process.exit(1);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
console.log(chalk.bold(`🚀 omega dev — booting ${selected.join(' + ')} ${chalk.dim(`(${brandRoot})`)}`));
|
|
240
|
+
if (!options[PICKER_FLAG] && !options.all) {
|
|
241
|
+
console.log(chalk.dim(' default set is web + backend — `--target=`, `--all` pick it'));
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Dist freshness is checked ONCE, here, for every lane at once (#340). Each
|
|
245
|
+
// lane's CLI boot checks itself too — but a heal runs `npm run prepare`,
|
|
246
|
+
// which PURGES dist before recopying, and a framework bin opens by requiring
|
|
247
|
+
// its own `../dist/` entry. Unsynchronized, one lane's purge window is the
|
|
248
|
+
// sibling lane's require: the backend leg died MODULE_NOT_FOUND dispatching
|
|
249
|
+
// through the web package the web leg was mid-rebuild on. Swept first, every
|
|
250
|
+
// lane's own check is a no-op.
|
|
251
|
+
const hosts = [];
|
|
252
|
+
for (const target of selected) {
|
|
253
|
+
const entry = targets.find((item) => item.target === target);
|
|
254
|
+
const found = findTarget(entry.path);
|
|
255
|
+
if (found && found.kind === 'framework') {
|
|
256
|
+
hosts.push({ packageName: found.name, fromDir: found.dir });
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
const sweep = freshnessSweep({ hosts });
|
|
260
|
+
if (sweep.healed.length > 0) {
|
|
261
|
+
console.log(chalk.dim(` ✔ rebuilt ${sweep.healed.join(', ')} before booting — the legs start on a complete dist`));
|
|
262
|
+
}
|
|
263
|
+
if (sweep.staleLinked.length > 0) {
|
|
264
|
+
// The monorepo watch owns those dists (#281) — the sweep printed what is
|
|
265
|
+
// unbuilt and what to start; nothing boots on top of it.
|
|
266
|
+
throw new Error(`omega dev: ${sweep.staleLinked.map((entry) => entry.packageName).join(', ')} — see above; nothing booted`);
|
|
267
|
+
}
|
|
268
|
+
if (sweep.healFailed.length > 0) {
|
|
269
|
+
// The watch is down and the sweep's own rebuild broke (#398) — the sweep
|
|
270
|
+
// printed the prepare to run by hand; no leg boots on a dist nobody built.
|
|
271
|
+
throw new Error(`omega dev: ${sweep.healFailed.map((entry) => entry.packageName).join(', ')} — see above; nothing booted`);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Boot opens with a full manage cycle (#44): the target watchers see only
|
|
275
|
+
// their own target, so brand-level sources — assets/logo/brandmark.svg, .env,
|
|
276
|
+
// certs — reach the targets ONLY through the service walk. Without this, a
|
|
277
|
+
// brand edit sits invisible until someone remembers to run `npm run manage`.
|
|
278
|
+
// A broken brand fails the boot instead of serving stale output.
|
|
279
|
+
// …and it never blocks on a human (#228): the boot walk runs headless, so
|
|
280
|
+
// console confirms, consent flows and secret pastes step aside into the run
|
|
281
|
+
// summary's ⚑ pending list instead of stalling the stack. `npm run manage`
|
|
282
|
+
// keeps the full interactive walk. The switch is restored before any leg
|
|
283
|
+
// spawns — the web dev server and the emulator ARE interactive surfaces.
|
|
284
|
+
//
|
|
285
|
+
// …and it walks only the BOOT LANE (#228): workspace + assets + disperse,
|
|
286
|
+
// the local redistribution the legs actually consume. The cloud services
|
|
287
|
+
// and the rebuild lane cost a minute-plus and nothing downstream of them
|
|
288
|
+
// reaches a dev leg, so they belong to `npm run manage` — or `--full` here.
|
|
289
|
+
const priorNonInteractive = process.env.OMEGA_NON_INTERACTIVE;
|
|
290
|
+
process.env.OMEGA_NON_INTERACTIVE = '1';
|
|
291
|
+
let report;
|
|
292
|
+
try {
|
|
293
|
+
report = await runManage(brandRoot, options.full ? {} : { lane: 'boot' });
|
|
294
|
+
} finally {
|
|
295
|
+
if (priorNonInteractive === undefined) {
|
|
296
|
+
delete process.env.OMEGA_NON_INTERACTIVE;
|
|
297
|
+
} else {
|
|
298
|
+
process.env.OMEGA_NON_INTERACTIVE = priorNonInteractive;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
if (report.hasErrors) {
|
|
302
|
+
throw new Error('omega dev: the manage cycle reported errors — fix them (see the run summary above), then boot again');
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
if (!options.full) {
|
|
306
|
+
console.log(chalk.dim(' ⚑ boot ran the local lane only — `npm run manage` runs the full setup (or `omega dev --full`)'));
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// The one-terminal rule covers FRAMEWORK edits too (#587). A brand whose
|
|
310
|
+
// @omega.js deps resolve into a monorepo checkout has no src→dist rebuild
|
|
311
|
+
// without that monorepo's watch, so this boot starts it as a session child —
|
|
312
|
+
// the same mechanism the website target's `--local` prelude uses, one
|
|
313
|
+
// implementation in devkit. Lock-aware: a watch already running is reused.
|
|
314
|
+
// AFTER the sweep on purpose: the sweep's verdict depends on whether a watch
|
|
315
|
+
// holds the lock (#281/#398), so starting one first would change the answer
|
|
316
|
+
// it just gave.
|
|
317
|
+
const linkedMonorepo = resolveLinkedMonorepo(brandRoot);
|
|
318
|
+
if (linkedMonorepo) {
|
|
319
|
+
const watch = startMonorepoWatch({ monorepoRoot: linkedMonorepo, logger: { log: (line) => console.log(chalk.dim(` ${line}`)) } });
|
|
320
|
+
|
|
321
|
+
// A watch's prepare rewrites every package's dist, and a target booting
|
|
322
|
+
// into that rewrite loads a half-written CLI (#670). The legs wait for the
|
|
323
|
+
// pass to land — a FRESH watch's initial one, and an ALREADY-RUNNING
|
|
324
|
+
// watch's, which is the branch a brand normally takes (Ian keeps the root
|
|
325
|
+
// `npm start` up) and the one that skipped the wait entirely (#622).
|
|
326
|
+
const outcome = await watch.ready;
|
|
327
|
+
if (outcome === 'ready') {
|
|
328
|
+
console.log(chalk.dim(` monorepo watch: ${watch.alreadyRunning ? 'nothing in flight' : 'initial prepare done'}`));
|
|
329
|
+
}
|
|
330
|
+
} else {
|
|
331
|
+
console.log(chalk.dim(' ⚑ frameworks come from the registry — no monorepo watch to run (a linked brand starts one here)'));
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// The local certificate's root, resolved ONCE for every leg (#795): a leg
|
|
335
|
+
// that never speaks TLS ignores it, and this is verification rather than a
|
|
336
|
+
// bypass, so Node prints no warning. A shell-set value wins verbatim.
|
|
337
|
+
const caPem = process.env.NODE_EXTRA_CA_CERTS || mkcertCaRootPem();
|
|
338
|
+
|
|
339
|
+
const pad = Math.max(...selected.map((target) => target.length));
|
|
340
|
+
const children = [];
|
|
341
|
+
let shuttingDown = false;
|
|
342
|
+
|
|
343
|
+
// One deduper per stream, so the legs never collapse against each other.
|
|
344
|
+
// Terminal and file see the SAME collapsed stream: the tee patches this
|
|
345
|
+
// process' writers (#197), so there is one stream to dedup, not two.
|
|
346
|
+
const forward = (stream, log, name) => {
|
|
347
|
+
let buffer = '';
|
|
348
|
+
const deduper = createLineDeduper();
|
|
349
|
+
const emit = (lines) => lines.forEach((line) => log(`${chalk.dim(`[${name.padEnd(pad)}]`)} ${line}`));
|
|
350
|
+
stream.on('data', (chunk) => {
|
|
351
|
+
buffer += chunk.toString();
|
|
352
|
+
const lines = buffer.split('\n');
|
|
353
|
+
buffer = lines.pop();
|
|
354
|
+
lines.forEach((line) => emit(deduper.push(line)));
|
|
355
|
+
});
|
|
356
|
+
stream.on('end', () => emit(deduper.flush()));
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
for (const target of selected) {
|
|
360
|
+
const entry = targets.find((item) => item.target === target);
|
|
361
|
+
const leg = devLegFor(entry);
|
|
362
|
+
const node = resolveTargetNode(entry.path);
|
|
363
|
+
if (node?.error) {
|
|
364
|
+
console.log(chalk.yellow(` ⚠ ${target}: ${node.error} — using the inherited node`));
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
console.log(chalk.dim(` ${target.padEnd(pad)} → ${leg.join(' ')} in ${entry.dir}${node ? ` (node ${node.major})` : ''}`));
|
|
368
|
+
|
|
369
|
+
const child = spawn(leg[0], leg.slice(1), {
|
|
370
|
+
cwd: entry.path,
|
|
371
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
372
|
+
// Legs pipe their output — keep chalk colors when the parent's terminal
|
|
373
|
+
// has them (the log tee strips ANSI either way)
|
|
374
|
+
env: {
|
|
375
|
+
...process.env,
|
|
376
|
+
...nodeEnvFor(node),
|
|
377
|
+
FORCE_COLOR: process.stdout.isTTY ? '1' : process.env.FORCE_COLOR || '0',
|
|
378
|
+
...(caPem ? { NODE_EXTRA_CA_CERTS: caPem } : {}),
|
|
379
|
+
},
|
|
380
|
+
// Own process group per leg (#690): a leg is a chain (npm run <leg> →
|
|
381
|
+
// the real server), and shutdown signals the GROUP — a same-group leg
|
|
382
|
+
// would get only npm killed, orphaning the emulator on its ports.
|
|
383
|
+
detached: true,
|
|
384
|
+
});
|
|
385
|
+
forward(child.stdout, console.log, target);
|
|
386
|
+
forward(child.stderr, console.error, target);
|
|
387
|
+
child.on('close', (code) => {
|
|
388
|
+
if (shuttingDown) return;
|
|
389
|
+
console.error(chalk.red(`✖ ${target} exited (code ${code}) — siblings stay up; Ctrl-C stops everything`));
|
|
390
|
+
});
|
|
391
|
+
children.push(child);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// The legs are detached (their own process groups), so the terminal's own
|
|
395
|
+
// Ctrl-C never reaches them — every escalation is this process' to deliver.
|
|
396
|
+
const forceKill = () => {
|
|
397
|
+
children.forEach((child) => {
|
|
398
|
+
try { process.kill(-child.pid, 'SIGKILL'); } catch { /* already gone */ }
|
|
399
|
+
});
|
|
400
|
+
process.exit(0);
|
|
401
|
+
};
|
|
402
|
+
const shutdown = () => {
|
|
403
|
+
if (shuttingDown) return forceKill(); // second Ctrl-C = force kill
|
|
404
|
+
shuttingDown = true;
|
|
405
|
+
console.log(chalk.dim('\n⏹ omega dev: stopping all targets… (Ctrl-C again to force kill)'));
|
|
406
|
+
children.forEach((child) => stopChild(child));
|
|
407
|
+
// Exit only when every leg is GONE: the backend leg's own teardown (the
|
|
408
|
+
// emulator group-kill + orphan sweep, seconds of work) logs through this
|
|
409
|
+
// process' pipes, and exiting under it cuts the sweep off mid-run (#690).
|
|
410
|
+
// The cap matches the 20s the journey/e2e harnesses allow that teardown,
|
|
411
|
+
// and expiry escalates so a wedged leg cannot keep its ports.
|
|
412
|
+
const cap = setTimeout(forceKill, 20000);
|
|
413
|
+
Promise.all(children.map((child) => new Promise((resolve) => {
|
|
414
|
+
if (child.exitCode !== null || child.signalCode) return resolve();
|
|
415
|
+
child.once('close', resolve);
|
|
416
|
+
}))).then(() => {
|
|
417
|
+
clearTimeout(cap);
|
|
418
|
+
process.exit(0);
|
|
419
|
+
});
|
|
420
|
+
};
|
|
421
|
+
// Every way this run is asked to stop takes the SAME teardown, off the ONE
|
|
422
|
+
// devkit list ([#629](https://github.com/Omega-JS-Stack/omega/issues/629)).
|
|
423
|
+
// SIGHUP was missing: a closed terminal killed the orchestrator outright and
|
|
424
|
+
// the legs, spawned DETACHED so a group signal cannot reach them, orphaned
|
|
425
|
+
// with the emulator tree behind them.
|
|
426
|
+
STOP_SIGNALS.forEach((signal) => process.on(signal, shutdown));
|
|
427
|
+
|
|
428
|
+
// Keep the orchestrator alive while any child runs
|
|
429
|
+
await new Promise(() => {});
|
|
430
|
+
};
|
|
431
|
+
|
|
432
|
+
module.exports.selectDevTargets = selectDevTargets;
|
|
433
|
+
module.exports.devLegFor = devLegFor;
|
|
434
|
+
module.exports.createLineDeduper = createLineDeduper;
|
|
435
|
+
module.exports.stopChild = stopChild;
|
|
436
|
+
module.exports.DEV_LEGS = DEV_LEGS;
|
|
437
|
+
module.exports.DEFAULT_TARGETS = DEFAULT_TARGETS;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `omega-manager devlog` — generate a commit-digest blog post from recent
|
|
3
|
+
* GitHub activity and publish it to the brand's website target.
|
|
4
|
+
*
|
|
5
|
+
* Flags: --brand=<id> (company workspaces; default = the single brand with
|
|
6
|
+
* devlog.enabled), --days=<n> overrides devlog.providers.ghostii.lookbackDays,
|
|
7
|
+
* --dry-run collects + generates only and writes a preview to .omega/devlog/
|
|
8
|
+
* instead of publishing.
|
|
9
|
+
*/
|
|
10
|
+
const chalk = require('chalk').default;
|
|
11
|
+
|
|
12
|
+
const { runDevlog } = require('../devlog/index.js');
|
|
13
|
+
|
|
14
|
+
module.exports = async (options) => {
|
|
15
|
+
try {
|
|
16
|
+
await runDevlog(process.cwd(), {
|
|
17
|
+
brand: options.brand,
|
|
18
|
+
days: options.days,
|
|
19
|
+
dryRun: options.dryRun,
|
|
20
|
+
});
|
|
21
|
+
} catch (error) {
|
|
22
|
+
console.error(`${chalk.red('❌ Error')}${chalk.dim(`: ${error.message}`)}`);
|
|
23
|
+
process.exitCode = 1;
|
|
24
|
+
}
|
|
25
|
+
};
|