@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,380 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `omega test` at a brand root — C5's brand layer: fan the test run out over
|
|
3
|
+
* the brand's targets, each in its own framework's hands, and then run the
|
|
4
|
+
* brand's OWN e2e lane.
|
|
5
|
+
*
|
|
6
|
+
* omega test → every target's PROJECT tests, then test/e2e/
|
|
7
|
+
* omega test framework: → every target's framework suite
|
|
8
|
+
* omega test full: → both sources, every target
|
|
9
|
+
* omega test routes/x → project filter, forwarded to every target
|
|
10
|
+
* (a target with no matching tests no-ops; a
|
|
11
|
+
* path NO target carries fails the run, #814)
|
|
12
|
+
* omega test web:pages/ → ONLY the web target — its framework suite, scoped
|
|
13
|
+
* omega test desktop: → ONLY the desktop target's framework suite
|
|
14
|
+
* omega test --target=web,backend → narrow ANY of the above to those targets
|
|
15
|
+
* omega test --extended → fanned out: every target runs its real-service suites
|
|
16
|
+
* omega test --lane=<name> → fanned out to the targets that DECLARE that lane
|
|
17
|
+
*
|
|
18
|
+
* Universal targets (bare paths, `framework:`/`omega:`/`mgr:`, `full:`,
|
|
19
|
+
* `project:`/`brand:`) forward to every target verbatim; per-framework ids
|
|
20
|
+
* (FRAMEWORK_IDS: `web:`, `backend:`, `desktop:`, `extension:`) route to
|
|
21
|
+
* the target owning that framework — the legacy short ids are retired. Unknown
|
|
22
|
+
* prefixes warn and are dropped; if nothing valid remains, every target runs
|
|
23
|
+
* bare (scope.js parity).
|
|
24
|
+
*
|
|
25
|
+
* `--target=<a,b>` is the TARGET picker, and it composes with every scope
|
|
26
|
+
* above rather than replacing any of them: a comma list of target keys ('web')
|
|
27
|
+
* or dir names ('website') narrowing which targets the run reaches. A
|
|
28
|
+
* per-framework id already names its target, so an id whose owner the picker
|
|
29
|
+
* excludes is a contradiction, not a narrowing — it refuses by name instead of
|
|
30
|
+
* running the empty intersection.
|
|
31
|
+
*
|
|
32
|
+
* MODE flags fan out ([#775](https://github.com/Omega-JS-Stack/omega/issues/775)):
|
|
33
|
+
* `--extended` (real external services) reaches every framework target, and
|
|
34
|
+
* `--lane=<name>` reaches the targets whose framework DECLARES that lane in
|
|
35
|
+
* its package.json `omega.testLanes` — a target that declares none prints one
|
|
36
|
+
* line and the run stays green, because an opt-in lane no framework serves is
|
|
37
|
+
* a lane that does not apply there, never a failure. Path-scope flags
|
|
38
|
+
* (`--layer`) stay target-level invocations.
|
|
39
|
+
*
|
|
40
|
+
* The BRAND E2E LANE (`<brandRoot>/test/e2e/run.js`) runs last, when it
|
|
41
|
+
* exists: one browser lane driving the brand's real pages against its real
|
|
42
|
+
* local stack, which is a brand-level surface no target owns. It is a runner
|
|
43
|
+
* script, so — exactly like a custom target's `test` script — it hears no
|
|
44
|
+
* scope vocabulary and no flags: a bare run reaches it, and a scoped,
|
|
45
|
+
* picked (`--target=`) or laned run never does.
|
|
46
|
+
*
|
|
47
|
+
* Targets run sequentially with streamed output; any failing target → exit 1.
|
|
48
|
+
*/
|
|
49
|
+
const fs = require('node:fs');
|
|
50
|
+
const path = require('node:path');
|
|
51
|
+
const chalk = require('chalk').default;
|
|
52
|
+
const attachLogFile = require('../vendor/devkit/attach-log-file.js');
|
|
53
|
+
|
|
54
|
+
const Logger = require('../vendor/devkit/logger.js');
|
|
55
|
+
const { UNIVERSAL_FRAMEWORK_ALIASES, PROJECT_ALIASES, FULL_ALIASES, FRAMEWORK_IDS, FANOUT_ENV, NO_MATCH_EXIT_CODE, noMatchMessage, parseTestScope, isPathTargeted } = require('../vendor/devkit/test/scope.js');
|
|
56
|
+
const { resolveBrandRoot, discoverTargets } = require('../lib/brand.js');
|
|
57
|
+
const { resolveTargetRun, resolveFrameworkPackage } = require('../lib/framework-bin.js');
|
|
58
|
+
const { PICKER_FLAG, assertPickerFlags, assertKnownTargets, parseTargetTokens, targetMatches } = require('../lib/target-selection.js');
|
|
59
|
+
const { runCommand } = require('../lib/run-command.js');
|
|
60
|
+
|
|
61
|
+
// Prefixes forwarded to every target as-is (each target's own C5 parser interprets them)
|
|
62
|
+
const UNIVERSAL_PREFIXES = new Set([
|
|
63
|
+
...UNIVERSAL_FRAMEWORK_ALIASES,
|
|
64
|
+
...PROJECT_ALIASES,
|
|
65
|
+
...FULL_ALIASES,
|
|
66
|
+
]);
|
|
67
|
+
|
|
68
|
+
// id prefix → owning framework package ('desktop' → '@omega.js/desktop', …)
|
|
69
|
+
const ID_TO_FRAMEWORK = Object.fromEntries(
|
|
70
|
+
Object.entries(FRAMEWORK_IDS).flatMap(([pkg, ids]) => ids.map((id) => [id, pkg]))
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
// The brand's own e2e lane — ONE entry file, by convention, so the walk never
|
|
74
|
+
// has to guess which of a directory's files is the runner and which are its
|
|
75
|
+
// helpers (#775).
|
|
76
|
+
const BRAND_E2E_DIR = path.join('test', 'e2e');
|
|
77
|
+
const BRAND_E2E_ENTRY = path.join(BRAND_E2E_DIR, 'run.js');
|
|
78
|
+
|
|
79
|
+
// The fan-out's own verdict is a log line, not a report row: the report says
|
|
80
|
+
// what each target did, this says what the RUN means (#814).
|
|
81
|
+
const logger = new Logger('test');
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Split raw targets into per-target routing: `shared` goes to every target,
|
|
85
|
+
* `perFramework[pkg]` only to the target owning that framework, `invalid`
|
|
86
|
+
* is warned and dropped.
|
|
87
|
+
*/
|
|
88
|
+
function partitionTargets(rawTargets) {
|
|
89
|
+
const shared = [];
|
|
90
|
+
const perFramework = {};
|
|
91
|
+
const invalid = [];
|
|
92
|
+
|
|
93
|
+
for (const raw of rawTargets) {
|
|
94
|
+
const target = String(raw).trim();
|
|
95
|
+
if (!target) continue;
|
|
96
|
+
|
|
97
|
+
// Same prefix grammar as scope.js (lowercase-only keeps C:/ paths bare)
|
|
98
|
+
const match = target.match(/^([a-z-]+):/);
|
|
99
|
+
|
|
100
|
+
if (!match) {
|
|
101
|
+
shared.push(target);
|
|
102
|
+
} else if (UNIVERSAL_PREFIXES.has(match[1])) {
|
|
103
|
+
shared.push(target);
|
|
104
|
+
} else if (ID_TO_FRAMEWORK[match[1]]) {
|
|
105
|
+
const pkg = ID_TO_FRAMEWORK[match[1]];
|
|
106
|
+
(perFramework[pkg] = perFramework[pkg] || []).push(target);
|
|
107
|
+
} else {
|
|
108
|
+
invalid.push(target);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return { shared, perFramework, invalid };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* The brand root's targets read through the SAME grammar a target's own runner
|
|
117
|
+
* reads them with, so "did this run name a path?" means one thing everywhere
|
|
118
|
+
* ([#814](https://github.com/Omega-JS-Stack/omega/issues/814)). Every framework
|
|
119
|
+
* id is handed in as an alias, since at this layer they all name a source.
|
|
120
|
+
*
|
|
121
|
+
* @param {string[]} rawTargets - The positional targets, as typed
|
|
122
|
+
* @returns {object} A parseTestScope() result
|
|
123
|
+
*/
|
|
124
|
+
function namedScope(rawTargets) {
|
|
125
|
+
return parseTestScope(rawTargets, { frameworkAliases: Object.keys(ID_TO_FRAMEWORK) });
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* The `--target=` picker: which discovered targets a run may reach.
|
|
130
|
+
* Tokens match a target's key ('web') or its dir name ('website') through the
|
|
131
|
+
* shared matcher every brand-root picker uses (lib/target-selection.js,
|
|
132
|
+
* which also names the flag: ONE `--target=` on every verb, #780).
|
|
133
|
+
*
|
|
134
|
+
* @param {Array} targets - the discovered target entries
|
|
135
|
+
* @param {string} [picker] - the raw --target value (comma list)
|
|
136
|
+
* @returns {{ tokens: string[], selected: Array }}
|
|
137
|
+
* @throws {Error} when a token matches no target
|
|
138
|
+
*/
|
|
139
|
+
function pickTargets(targets, picker) {
|
|
140
|
+
const tokens = parseTargetTokens(picker);
|
|
141
|
+
if (tokens.length === 0) {
|
|
142
|
+
return { tokens, selected: targets };
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
assertKnownTargets(
|
|
146
|
+
tokens.filter((token) => !targets.some((entry) => targetMatches(entry, token))),
|
|
147
|
+
targets.map((entry) => entry.target || entry.name),
|
|
148
|
+
);
|
|
149
|
+
const selected = targets.filter((entry) => tokens.some((token) => targetMatches(entry, token)));
|
|
150
|
+
|
|
151
|
+
return { tokens, selected };
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Does this target's framework declare `lane`? The framework's package.json
|
|
156
|
+
* `omega.testLanes` is the SSOT — a lane is the framework's to own, and the
|
|
157
|
+
* brand root only needs to know which targets it applies to.
|
|
158
|
+
*
|
|
159
|
+
* @param {object} entry - the discovered target entry
|
|
160
|
+
* @param {string} framework - the framework package name
|
|
161
|
+
* @param {string} lane - the --lane value
|
|
162
|
+
* @returns {boolean}
|
|
163
|
+
*/
|
|
164
|
+
function declaresLane(entry, framework, lane) {
|
|
165
|
+
const resolved = resolveFrameworkPackage(entry.path, framework);
|
|
166
|
+
const lanes = resolved?.pkg?.omega?.testLanes;
|
|
167
|
+
return Array.isArray(lanes) && lanes.includes(lane);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
module.exports = async (options) => {
|
|
171
|
+
assertPickerFlags(options);
|
|
172
|
+
|
|
173
|
+
const brandRoot = resolveBrandRoot(process.cwd());
|
|
174
|
+
if (!brandRoot) {
|
|
175
|
+
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 tests.'));
|
|
176
|
+
process.exitCode = 1;
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Tee the whole fan-out to <brandRoot>/logs/test.log (#623) — which target
|
|
181
|
+
// ran which scope, and the aggregate verdict (each target's own suite output
|
|
182
|
+
// stays in targets/<target>/logs/test.log).
|
|
183
|
+
attachLogFile(path.join(brandRoot, 'logs', 'test.log'));
|
|
184
|
+
|
|
185
|
+
// Positional targets — tolerate both `omega-manager test x` (command token
|
|
186
|
+
// present) and flag-alias entry (`--test x`, no token).
|
|
187
|
+
const rawTargets = (options._ || []).map(String);
|
|
188
|
+
if (rawTargets[0] === 'test') rawTargets.shift();
|
|
189
|
+
|
|
190
|
+
const { shared, perFramework, invalid } = partitionTargets(rawTargets);
|
|
191
|
+
for (const bad of invalid) {
|
|
192
|
+
console.log(chalk.yellow(` ⚠ Unknown test scope prefix ignored: ${bad}`));
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Nothing valid → every target runs bare (its project tests), scope.js parity.
|
|
196
|
+
const runAllBare = shared.length === 0 && Object.keys(perFramework).length === 0;
|
|
197
|
+
const lane = options.lane ? String(options.lane) : null;
|
|
198
|
+
const extended = !!options.extended;
|
|
199
|
+
|
|
200
|
+
const discovered = discoverTargets(brandRoot).filter((entry) => entry.target || entry.custom);
|
|
201
|
+
if (discovered.length === 0) {
|
|
202
|
+
console.log(chalk.yellow('⚠ No target-mapped dirs under targets/ — nothing to test.'));
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const picked = pickTargets(discovered, options[PICKER_FLAG]);
|
|
207
|
+
|
|
208
|
+
console.log(chalk.bold(`\nOMEGA brand tests — ${path.basename(brandRoot)}`));
|
|
209
|
+
|
|
210
|
+
// ─── Plan: which targets run, with which forwarded ids ────────────────────
|
|
211
|
+
const runs = [];
|
|
212
|
+
|
|
213
|
+
// Resolved ONCE per target: the plan below and the --target/id contradiction
|
|
214
|
+
// check both need to know which framework owns which target.
|
|
215
|
+
const resolvedRuns = discovered.map((entry) => ({ entry, run: resolveTargetRun(entry, 'test') }));
|
|
216
|
+
|
|
217
|
+
// A per-framework id names its target; a picker that excludes that target
|
|
218
|
+
// contradicts it. Refuse by name rather than run the empty intersection —
|
|
219
|
+
// silently testing nothing is the outcome a green exit must never mean.
|
|
220
|
+
for (const [pkg, ids] of Object.entries(perFramework)) {
|
|
221
|
+
const owner = resolvedRuns.find((item) => item.run.framework === pkg);
|
|
222
|
+
if (!owner || picked.selected.includes(owner.entry)) continue;
|
|
223
|
+
|
|
224
|
+
const error = new Error(
|
|
225
|
+
`omega test: refusing --${PICKER_FLAG}=${picked.tokens.join(',')} beside the "${ids[0]}" scope — `
|
|
226
|
+
+ `${owner.entry.dir} owns that framework and --${PICKER_FLAG} excludes it. Nothing ran.\n`
|
|
227
|
+
+ 'Name the same target on both, or drop one of them.',
|
|
228
|
+
);
|
|
229
|
+
error.refusal = true;
|
|
230
|
+
throw error;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
for (const { entry, run } of resolvedRuns) {
|
|
234
|
+
if (!picked.selected.includes(entry)) continue;
|
|
235
|
+
|
|
236
|
+
// A target whose tests ARE its own `npm run test` — a custom target
|
|
237
|
+
// (#603), or a backend in custom-server mode whose framework has no
|
|
238
|
+
// emulator lane to run (#584) — never hears the scope vocabulary: it is
|
|
239
|
+
// the frameworks', and means nothing to a package script. So a SCOPED run
|
|
240
|
+
// never addresses one, a bare run does, and nothing is forwarded.
|
|
241
|
+
if (run.kind === 'custom' || run.kind === 'skip') {
|
|
242
|
+
// A lane is scope too — an opt-in lane a framework declares means
|
|
243
|
+
// nothing to a package script, so a laned run never addresses one.
|
|
244
|
+
if (!runAllBare || lane) continue;
|
|
245
|
+
|
|
246
|
+
if (run.kind === 'skip') {
|
|
247
|
+
console.log(chalk.dim(` ⊘ ${entry.name}: ${run.detail} — skipped`));
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
runs.push({ entry, framework: 'custom', command: run.command, args: run.args, label: run.label });
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (run.kind === 'error') {
|
|
256
|
+
// Only an error if this target was (or would be) addressed
|
|
257
|
+
if (runAllBare || shared.length > 0) {
|
|
258
|
+
runs.push({ entry, error: run.detail });
|
|
259
|
+
}
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// An opt-in lane reaches only the frameworks that serve it; the rest say
|
|
264
|
+
// so in one line and the run stays green (#775).
|
|
265
|
+
if (lane && !declaresLane(entry, run.framework, lane)) {
|
|
266
|
+
console.log(chalk.dim(` ⊘ ${entry.name}: no "${lane}" lane in ${run.framework} — skipped`));
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const args = [...shared, ...(perFramework[run.framework] || [])];
|
|
271
|
+
if (!runAllBare && args.length === 0) continue; // targeted run, not addressed to this target
|
|
272
|
+
|
|
273
|
+
// MODE flags ride the same `forwarded` seam every other brand-root fan-out
|
|
274
|
+
// uses (commands/deploy.js, lib/verb-fanout.js), so the flags land where
|
|
275
|
+
// that one place decides they land. Re-resolved only when there ARE flags:
|
|
276
|
+
// a bare run has nothing to forward and keeps its first resolution.
|
|
277
|
+
const forwarded = [
|
|
278
|
+
...(extended ? ['--extended'] : []),
|
|
279
|
+
...(lane ? [`--lane=${lane}`] : []),
|
|
280
|
+
];
|
|
281
|
+
const flagged = forwarded.length ? resolveTargetRun(entry, 'test', forwarded) : run;
|
|
282
|
+
|
|
283
|
+
runs.push({
|
|
284
|
+
entry,
|
|
285
|
+
framework: flagged.framework,
|
|
286
|
+
command: flagged.command,
|
|
287
|
+
args: [...flagged.args, ...args],
|
|
288
|
+
label: `omega test ${[...forwarded, ...args].join(' ')}`.trimEnd(),
|
|
289
|
+
// This target is being ASKED, not chosen: a path it does not carry is a
|
|
290
|
+
// no-op here, and the signal is what lets its CLI say so with a code of
|
|
291
|
+
// its own instead of failing the whole brand run (#814).
|
|
292
|
+
env: { [FANOUT_ENV]: '1' },
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// ─── The brand's own e2e lane, after the targets ───────────────────────────
|
|
297
|
+
// A bare run only: it is a runner script with no scope vocabulary and no
|
|
298
|
+
// flags, so a scoped, picked or laned run is asking for something else.
|
|
299
|
+
const brandLane = path.join(brandRoot, BRAND_E2E_ENTRY);
|
|
300
|
+
if (runAllBare && !lane && picked.tokens.length === 0 && fs.existsSync(path.join(brandRoot, BRAND_E2E_DIR))) {
|
|
301
|
+
if (fs.existsSync(brandLane)) {
|
|
302
|
+
runs.push({
|
|
303
|
+
entry: { name: BRAND_E2E_DIR, path: brandRoot },
|
|
304
|
+
framework: 'brand',
|
|
305
|
+
command: process.execPath,
|
|
306
|
+
args: [brandLane],
|
|
307
|
+
label: `node ${BRAND_E2E_ENTRY}`,
|
|
308
|
+
});
|
|
309
|
+
} else {
|
|
310
|
+
console.log(chalk.dim(` ⊘ ${BRAND_E2E_DIR}: no ${path.basename(BRAND_E2E_ENTRY)} entry — skipped`));
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
if (runs.length === 0) {
|
|
315
|
+
console.log(chalk.yellow('⚠ No target matches the requested scope — nothing ran.'));
|
|
316
|
+
|
|
317
|
+
// Nothing ran AND a path was named: the brand carries no target that could
|
|
318
|
+
// even be asked for it, which is the same typo the target-level rule
|
|
319
|
+
// catches, so it fails here too ([#814](https://github.com/Omega-JS-Stack/omega/issues/814)).
|
|
320
|
+
// A bare prefix (`desktop:` with no path) names no file, so it keeps the
|
|
321
|
+
// warning above and an exit 0.
|
|
322
|
+
if (isPathTargeted(namedScope(rawTargets))) {
|
|
323
|
+
logger.error(noMatchMessage(rawTargets.join(' ')));
|
|
324
|
+
process.exitCode = 1;
|
|
325
|
+
}
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// ─── Execute sequentially, streaming each target's output ─────────────────
|
|
330
|
+
const summary = [];
|
|
331
|
+
let failed = false;
|
|
332
|
+
|
|
333
|
+
for (const [index, run] of runs.entries()) {
|
|
334
|
+
const label = `[${index + 1}/${runs.length}] ${run.entry.name}`;
|
|
335
|
+
|
|
336
|
+
if (run.error) {
|
|
337
|
+
console.log(chalk.red(`\n✗ ${label}: ${run.error}`));
|
|
338
|
+
summary.push({ name: run.entry.name, ok: false, detail: run.error });
|
|
339
|
+
failed = true;
|
|
340
|
+
continue;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
console.log(chalk.cyan(`${`\n─── ${label} ${chalk.dim(`(${run.framework})`)} — ${run.label}`.trimEnd()} ───`));
|
|
344
|
+
const result = await runCommand(run.command, run.args, run.entry.path, run.env);
|
|
345
|
+
|
|
346
|
+
// The distinct no-match code (#814): this target does not carry the path
|
|
347
|
+
// the brand root forwarded, which is a no-op here, not a failure. The run
|
|
348
|
+
// as a whole still has to answer for it below.
|
|
349
|
+
const missed = !result.success && result.code === NO_MATCH_EXIT_CODE;
|
|
350
|
+
|
|
351
|
+
summary.push({ name: run.entry.name, ok: result.success, missed, detail: missed ? 'no test file matches' : result.error });
|
|
352
|
+
if (!result.success && !missed) failed = true;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// ─── Summary + aggregate exit ──────────────────────────────────────────────
|
|
356
|
+
console.log(chalk.bold('\nTest summary'));
|
|
357
|
+
for (const entry of summary) {
|
|
358
|
+
if (entry.missed) {
|
|
359
|
+
console.log(` ${chalk.dim('⊘')} ${entry.name} ${chalk.dim(`— ${entry.detail}`)}`);
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
console.log(entry.ok
|
|
363
|
+
? ` ${chalk.green('✓')} ${entry.name}`
|
|
364
|
+
: ` ${chalk.red('✗')} ${entry.name} ${chalk.dim(`— ${entry.detail}`)}`);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// Every target missed: the path exists nowhere in this brand, so the run
|
|
368
|
+
// tested nothing at all. One target carrying it is enough to be a real run
|
|
369
|
+
// (#814) — silently testing nothing is the outcome a green exit must never
|
|
370
|
+
// mean.
|
|
371
|
+
const misses = summary.filter((entry) => entry.missed);
|
|
372
|
+
if (!failed && misses.length > 0 && misses.length === summary.length) {
|
|
373
|
+
logger.error(noMatchMessage(rawTargets.join(' ')));
|
|
374
|
+
failed = true;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
if (failed) {
|
|
378
|
+
process.exitCode = 1;
|
|
379
|
+
}
|
|
380
|
+
};
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `omega update` at a brand root — fan the dependency-freshness verb out over
|
|
3
|
+
* the brand's targets (cp251's deploy fan-out shape: same target discovery, same
|
|
4
|
+
* --target= picker, same flag forwarding), each target reporting/applying
|
|
5
|
+
* through its OWN framework's `omega update` (all of them the one devkit
|
|
6
|
+
* implementation — npu-outdated semantics, 7-day release-age quarantine,
|
|
7
|
+
* file: specs skipped).
|
|
8
|
+
*
|
|
9
|
+
* omega update → every target, report only
|
|
10
|
+
* omega update --apply → apply the safe set per target
|
|
11
|
+
* omega update --target=backend → one target (target key or dir name)
|
|
12
|
+
* omega update --apply --major → include breaking jumps
|
|
13
|
+
*
|
|
14
|
+
* Unlike deploy, targets are INDEPENDENT here — a failing target never blocks the
|
|
15
|
+
* rest (no --continue-on-error needed); any failure still exits 1.
|
|
16
|
+
*
|
|
17
|
+
* The BRAND ROOT is the last leg of an unpicked run (#794): its shell manifest
|
|
18
|
+
* holds exactly one thing of ours, the `@omega.js/manager` pin, and without it
|
|
19
|
+
* a manager-behind brand could never self-heal — the lockstep gate would refuse
|
|
20
|
+
* every verb and the fix it names would move every target except the one that
|
|
21
|
+
* was wrong. That leg runs the same devkit implementation in-process (there is
|
|
22
|
+
* no framework bin to spawn at the root: it would dispatch straight back here)
|
|
23
|
+
* and is scoped to that one package by name, so a brand's own root tooling is
|
|
24
|
+
* never touched. `--target=` names TARGETS, so a picked run skips the root.
|
|
25
|
+
*/
|
|
26
|
+
const path = require('node:path');
|
|
27
|
+
const chalk = require('chalk').default;
|
|
28
|
+
const jetpack = require('fs-jetpack');
|
|
29
|
+
const attachLogFile = require('../vendor/devkit/attach-log-file.js');
|
|
30
|
+
|
|
31
|
+
const { findTarget } = require('../vendor/devkit/omega-bin.js');
|
|
32
|
+
// The module object, not the function: the root leg is the one caller that
|
|
33
|
+
// runs devkit's update in-process, and its test replaces this export.
|
|
34
|
+
const devkitUpdate = require('../vendor/devkit/update.js');
|
|
35
|
+
const { resolveBrandRoot, discoverTargets } = require('../lib/brand.js');
|
|
36
|
+
const { resolveFrameworkBin } = require('../lib/framework-bin.js');
|
|
37
|
+
const { runCommand } = require('../lib/run-command.js');
|
|
38
|
+
const { PICKER_FLAG, assertPickerFlags, selectTargets, buildForwardedFlags } = require('../lib/target-selection.js');
|
|
39
|
+
|
|
40
|
+
// The one @omega.js dependency a brand-root shell manifest carries
|
|
41
|
+
const ROOT_PACKAGE = '@omega.js/manager';
|
|
42
|
+
|
|
43
|
+
module.exports = async (options = {}) => {
|
|
44
|
+
assertPickerFlags(options);
|
|
45
|
+
|
|
46
|
+
const brandRoot = resolveBrandRoot(process.cwd());
|
|
47
|
+
if (!brandRoot) {
|
|
48
|
+
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 update.'));
|
|
49
|
+
process.exitCode = 1;
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Tee the whole fan-out to <brandRoot>/logs/update.log (#623) — which target
|
|
54
|
+
// was checked, what it reported, what applied.
|
|
55
|
+
attachLogFile(path.join(brandRoot, 'logs', 'update.log'));
|
|
56
|
+
|
|
57
|
+
const targets = discoverTargets(brandRoot).filter((entry) => entry.target);
|
|
58
|
+
const { selected } = selectTargets({ targets, target: options[PICKER_FLAG] });
|
|
59
|
+
|
|
60
|
+
if (selected.length === 0) {
|
|
61
|
+
console.error(chalk.red('✗ This brand has no targets under targets/ — nothing checked.'));
|
|
62
|
+
process.exitCode = 1;
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const forwarded = buildForwardedFlags(options);
|
|
67
|
+
|
|
68
|
+
console.log(chalk.bold(`\nOMEGA brand update — ${path.basename(brandRoot)} ${chalk.dim(`(${selected.map((entry) => entry.target).join(', ')})`)}`));
|
|
69
|
+
|
|
70
|
+
// ─── Fan out, streaming each target's report — targets are independent ─────
|
|
71
|
+
const summary = [];
|
|
72
|
+
|
|
73
|
+
for (const [index, entry] of selected.entries()) {
|
|
74
|
+
const label = `[${index + 1}/${selected.length}] ${entry.name}`;
|
|
75
|
+
const target = findTarget(entry.path);
|
|
76
|
+
|
|
77
|
+
if (!target || target.kind !== 'framework') {
|
|
78
|
+
console.log(chalk.red(`\n✗ ${label}: no framework dependency detected (target-root package.json)`));
|
|
79
|
+
summary.push({ name: entry.name, ok: false, detail: 'no framework dependency detected' });
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const binPath = resolveFrameworkBin(target.dir, target.name);
|
|
84
|
+
if (!binPath) {
|
|
85
|
+
console.log(chalk.red(`\n✗ ${label}: ${target.name} is not installed (node_modules climb from ${target.dir} found no bin)`));
|
|
86
|
+
summary.push({ name: entry.name, ok: false, detail: `${target.name} is not installed` });
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
console.log(chalk.cyan(`${`\n─── ${label} ${chalk.dim(`(${target.name})`)} — omega update ${forwarded.join(' ')}`.trimEnd()} ───`));
|
|
91
|
+
const result = await runCommand(process.execPath, [binPath, 'update', ...forwarded], entry.path);
|
|
92
|
+
summary.push({ name: entry.name, ok: result.success, detail: result.error });
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// ─── The brand root: its @omega.js/manager pin, and nothing else ───────────
|
|
96
|
+
const rootManifest = jetpack.read(path.join(brandRoot, 'package.json'), 'json') || {};
|
|
97
|
+
const rootSpec = rootManifest.dependencies?.[ROOT_PACKAGE] || rootManifest.devDependencies?.[ROOT_PACKAGE];
|
|
98
|
+
|
|
99
|
+
if (!options[PICKER_FLAG] && rootSpec) {
|
|
100
|
+
console.log(chalk.cyan(`${`\n─── [root] brand root ${chalk.dim(`(${ROOT_PACKAGE})`)} — omega update ${forwarded.join(' ')}`.trimEnd()} ───`));
|
|
101
|
+
try {
|
|
102
|
+
await devkitUpdate.runUpdate({
|
|
103
|
+
dir: brandRoot,
|
|
104
|
+
only: [ROOT_PACKAGE],
|
|
105
|
+
apply: options.apply,
|
|
106
|
+
major: options.major,
|
|
107
|
+
minAge: options.minAge ?? options['min-age'],
|
|
108
|
+
forceFresh: options.forceFresh || options['force-fresh'],
|
|
109
|
+
});
|
|
110
|
+
summary.push({ name: 'brand root', ok: true });
|
|
111
|
+
} catch (error) {
|
|
112
|
+
console.log(chalk.red(`✗ brand root: ${error.message}`));
|
|
113
|
+
summary.push({ name: 'brand root', ok: false, detail: error.message });
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// ─── Summary + aggregate exit ──────────────────────────────────────────────
|
|
118
|
+
console.log(chalk.bold('\nUpdate summary'));
|
|
119
|
+
for (const entry of summary) {
|
|
120
|
+
console.log(entry.ok
|
|
121
|
+
? ` ${chalk.green('✓')} ${entry.name}`
|
|
122
|
+
: ` ${chalk.red('✗')} ${entry.name} ${chalk.dim(`— ${entry.detail}`)}`);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (summary.some((entry) => !entry.ok)) {
|
|
126
|
+
process.exitCode = 1;
|
|
127
|
+
}
|
|
128
|
+
};
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `omega company init` and `omega company adopt` — the COMPANY rung in two
|
|
3
|
+
* commands.
|
|
4
|
+
*
|
|
5
|
+
* A company workspace is a REPO, not a machine cache (machine-wide state stays
|
|
6
|
+
* in ~/.omega): the config layer every brand inherits, the `.env` that loads
|
|
7
|
+
* under every brand's own, and the shared Apple signing tree. `init`
|
|
8
|
+
* scaffolds that repo in one command; `adopt` is the ONE step a brand needs
|
|
9
|
+
* to join it — the `.omega/company.json` stamp the config layer already
|
|
10
|
+
* resolves (lib/company.js), which is what makes a brand-local run layer the
|
|
11
|
+
* company config, load the company `.env`, and share the signing tree.
|
|
12
|
+
*
|
|
13
|
+
* Both are idempotent: init fills gaps only (existing files are never
|
|
14
|
+
* touched) and adopt rewrites nothing when the marker already points here.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
const fs = require('node:fs');
|
|
18
|
+
const path = require('node:path');
|
|
19
|
+
const chalk = require('chalk').default;
|
|
20
|
+
const jetpack = require('fs-jetpack');
|
|
21
|
+
|
|
22
|
+
const { hasOmegaConfig } = require('./vendor/config/index.js');
|
|
23
|
+
|
|
24
|
+
const { applyScaffoldPlan, printPlanResults } = require('./lib/scaffold.js');
|
|
25
|
+
const { COMPANY_DIRS, buildCompanyScaffoldPlan } = require('./lib/company-scaffold.js');
|
|
26
|
+
const {
|
|
27
|
+
isCompanyRoot,
|
|
28
|
+
resolveManageRoot,
|
|
29
|
+
discoverBrands,
|
|
30
|
+
loadCompanyConfig,
|
|
31
|
+
stampCompanyMarker,
|
|
32
|
+
} = require('./lib/company.js');
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Create the directories a company workspace owns (the signing tree, the
|
|
36
|
+
* default brands root). Empty dirs carry no bytes, so this is a no-op on
|
|
37
|
+
* every rerun.
|
|
38
|
+
*
|
|
39
|
+
* @returns {string[]} - The dirs that did not exist yet
|
|
40
|
+
*/
|
|
41
|
+
function ensureCompanyDirs(companyRoot) {
|
|
42
|
+
const created = [];
|
|
43
|
+
|
|
44
|
+
for (const relative of COMPANY_DIRS) {
|
|
45
|
+
const target = path.join(companyRoot, relative);
|
|
46
|
+
if (!jetpack.exists(target)) {
|
|
47
|
+
created.push(relative);
|
|
48
|
+
}
|
|
49
|
+
jetpack.dir(target);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return created;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Scaffold a company workspace at `dir`.
|
|
57
|
+
*
|
|
58
|
+
* @param {string} dir - Absolute directory to make a company root
|
|
59
|
+
* @returns {{ companyRoot: string, created: string[], kept: string[], dirs: string[] }}
|
|
60
|
+
*/
|
|
61
|
+
function runCompanyInit(dir) {
|
|
62
|
+
const companyRoot = path.resolve(dir);
|
|
63
|
+
const name = path.basename(companyRoot);
|
|
64
|
+
|
|
65
|
+
console.log(chalk.bold.cyan('OMEGA Manager — Company workspace'));
|
|
66
|
+
console.log('');
|
|
67
|
+
console.log(`${chalk.dim('→')} ${chalk.cyan(companyRoot)}`);
|
|
68
|
+
console.log('');
|
|
69
|
+
|
|
70
|
+
const results = applyScaffoldPlan(companyRoot, buildCompanyScaffoldPlan(name));
|
|
71
|
+
printPlanResults(results);
|
|
72
|
+
|
|
73
|
+
const dirs = ensureCompanyDirs(companyRoot);
|
|
74
|
+
for (const relative of dirs) {
|
|
75
|
+
console.log(` ${chalk.green('✓')} created ${chalk.cyan(`${relative}/`)}`);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Prove it is actually a company root before calling it done — the `brands`
|
|
79
|
+
// key is what every other verb detects, and the layer must parse
|
|
80
|
+
const layer = loadCompanyConfig(companyRoot);
|
|
81
|
+
console.log('');
|
|
82
|
+
if (isCompanyRoot(companyRoot)) {
|
|
83
|
+
const keys = Object.keys(layer);
|
|
84
|
+
console.log(`${chalk.green('✓')} Company config loads ${chalk.dim(keys.length > 0 ? `(brands inherit: ${keys.join(', ')})` : '(no inherited keys yet — every section is commented out)')}`);
|
|
85
|
+
} else {
|
|
86
|
+
console.log(`${chalk.red('✗')} config/omega.json5 has no \`brands\` key — this directory will not be treated as a company root`);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
console.log('');
|
|
90
|
+
console.log(chalk.bold('Next steps'));
|
|
91
|
+
console.log(` ${chalk.dim('1.')} Fill in ${chalk.cyan('config/omega.json5')} — every key there is a default its brands inherit`);
|
|
92
|
+
console.log(` ${chalk.dim('2.')} Put the shared secrets in ${chalk.cyan('.env')} ${chalk.dim('(it loads under every brand\'s own)')}`);
|
|
93
|
+
console.log(` ${chalk.dim('3.')} ${chalk.cyan('npx omega company adopt <brand-path>')} ${chalk.dim('— per existing brand (or `npx omega onboard` for a new one)')}`);
|
|
94
|
+
console.log(` ${chalk.dim('4.')} ${chalk.cyan('npx omega manage')} ${chalk.dim('— the full walk, once per managed brand')}`);
|
|
95
|
+
console.log('');
|
|
96
|
+
|
|
97
|
+
return { companyRoot, ...results, dirs };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Adopt a brand into the company workspace containing `cwd`: stamp its
|
|
102
|
+
* `.omega/company.json`, the ONE step a brand needs.
|
|
103
|
+
*
|
|
104
|
+
* @param {string} cwd - Where the command ran (must resolve to a company root)
|
|
105
|
+
* @param {string} brandPath - The brand root to adopt (relative to cwd or absolute)
|
|
106
|
+
* @returns {{ companyRoot: string, brandRoot: string, stamped: boolean, managed: boolean }}
|
|
107
|
+
*/
|
|
108
|
+
function runCompanyAdopt(cwd, brandPath) {
|
|
109
|
+
const resolved = resolveManageRoot(cwd);
|
|
110
|
+
if (!resolved?.isCompany) {
|
|
111
|
+
throw new Error(
|
|
112
|
+
'Not inside a company workspace — run `omega company init` here first '
|
|
113
|
+
+ '(a company root is a directory whose config/omega.json5 has a `brands` key)',
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
if (!brandPath) {
|
|
117
|
+
throw new Error('Usage: omega company adopt <brand-path>');
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const companyRoot = resolved.root;
|
|
121
|
+
const brandRoot = path.resolve(cwd, brandPath);
|
|
122
|
+
|
|
123
|
+
if (!hasOmegaConfig(brandRoot)) {
|
|
124
|
+
throw new Error(`Not a brand: ${brandRoot} — a brand root has a config/omega.json5`);
|
|
125
|
+
}
|
|
126
|
+
if (isCompanyRoot(brandRoot)) {
|
|
127
|
+
throw new Error(`${brandRoot} is a company workspace, not a brand — the hierarchy is one rung: company → brands`);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const stamped = stampCompanyMarker(brandRoot, companyRoot);
|
|
131
|
+
|
|
132
|
+
console.log(`${chalk.dim('→')} Company workspace: ${chalk.cyan(companyRoot)}`);
|
|
133
|
+
if (stamped) {
|
|
134
|
+
console.log(`${chalk.green('✓')} adopted ${chalk.cyan(brandRoot)} ${chalk.dim('→ .omega/company.json')}`);
|
|
135
|
+
} else {
|
|
136
|
+
console.log(`${chalk.dim('•')} ${chalk.dim(brandRoot)} ${chalk.dim('already adopted (marker unchanged)')}`);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const inherited = Object.keys(loadCompanyConfig(companyRoot));
|
|
140
|
+
console.log(` ${chalk.dim(inherited.length > 0 ? `inherits: ${inherited.join(', ')} (+ the company .env, + the shared signing tree)` : 'inherits: the company .env + the shared signing tree (its config sets no keys yet)')}`);
|
|
141
|
+
|
|
142
|
+
// The stamp is enough for BRAND-LOCAL runs, but a company-wide `omega
|
|
143
|
+
// manage` only walks what brands.roots discovers — say so rather than let
|
|
144
|
+
// an adopted-but-undiscovered brand look managed
|
|
145
|
+
const managed = isDiscovered(companyRoot, brandRoot);
|
|
146
|
+
if (!managed) {
|
|
147
|
+
console.log(chalk.yellow(`⚠ ${brandRoot} is outside this company's brands.roots — it inherits the company layer on its own runs, but company-wide runs won't include it (add its parent dir to brands.roots)`));
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return { companyRoot, brandRoot, stamped, managed };
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Does a company-wide run walk this brand? Discovery reads config, so a
|
|
155
|
+
* broken/incomplete brands.roots is reported by the run itself, never by
|
|
156
|
+
* adopt — an undiscoverable company simply can't answer the question.
|
|
157
|
+
*/
|
|
158
|
+
function isDiscovered(companyRoot, brandRoot) {
|
|
159
|
+
try {
|
|
160
|
+
const real = fs.realpathSync(brandRoot);
|
|
161
|
+
return discoverBrands(companyRoot).brands.some((brand) => fs.realpathSync(brand.root) === real);
|
|
162
|
+
} catch {
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
module.exports = { runCompanyInit, runCompanyAdopt };
|