@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,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Install + build every target-mapped dir.
|
|
3
|
+
*
|
|
4
|
+
* Install is ONE `npm install` at the brand root (npm workspaces cover every
|
|
5
|
+
* target), and it's dependency-resolution-gated for idempotency: if every
|
|
6
|
+
* target's
|
|
7
|
+
* declared deps already resolve through the node_modules climb, the install
|
|
8
|
+
* is skipped — so a second run is a no-op, and a brand nested inside a larger
|
|
9
|
+
* workspace (the monorepo's sandbox brand) never grows a stray node_modules.
|
|
10
|
+
*
|
|
11
|
+
* Build runs each target's own `npm run build`; targets without a build script are
|
|
12
|
+
* recorded as skipped, not failed (a backend's "build" is its deploy story).
|
|
13
|
+
* Those builds are the slow tail of every walk, so they are INCREMENTAL
|
|
14
|
+
* (#445): a target whose own files AND whose installed `@omega.js/*` frameworks
|
|
15
|
+
* are both unchanged since its last successful build is converged and skips
|
|
16
|
+
* with one line (lib/fingerprint.js), the fingerprint pair living in
|
|
17
|
+
* `.omega/cache/update.json` (lib/cache.js). Either set fresh → the full build
|
|
18
|
+
* for that target; `--force` ignores the cache, and so does a brand whose cache
|
|
19
|
+
* is missing or unreadable.
|
|
20
|
+
*
|
|
21
|
+
* Output shape matches omega-manager's update service so RunSummary's
|
|
22
|
+
* drill-down works unchanged: { results: { [target]: { steps: [{ phase,
|
|
23
|
+
* success, error?, skipped? }] } } }.
|
|
24
|
+
*/
|
|
25
|
+
const path = require('node:path');
|
|
26
|
+
const chalk = require('chalk').default;
|
|
27
|
+
const jetpack = require('fs-jetpack');
|
|
28
|
+
|
|
29
|
+
const { envLayerFiles, ENV_ENVIRONMENTS } = require('../../../vendor/config/index.js');
|
|
30
|
+
|
|
31
|
+
const { runCommand } = require('../../../lib/run-command.js');
|
|
32
|
+
const { readCompanyMarker } = require('../../../lib/company.js');
|
|
33
|
+
const { fingerprintTarget, resolvePackageDir } = require('../lib/fingerprint.js');
|
|
34
|
+
const { readCache, writeCache, CACHE_VERSION } = require('../lib/cache.js');
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* One env LAYER's files: the base `.env` plus its `.env.<environment>` overlays.
|
|
38
|
+
*
|
|
39
|
+
* The overlay spelling is @omega.js/config's (`envLayerFiles`, #586), never a
|
|
40
|
+
* join written out here, and EVERY environment is fingerprinted because a build
|
|
41
|
+
* can run under any of them and an absent file digests as `absent` either way.
|
|
42
|
+
* Fingerprinting the base file by exact path was the gap ([#681](https://github.com/Omega-JS-Stack/omega/issues/681)):
|
|
43
|
+
* an overlay is a real layer of the cascade and carries the values that DIFFER
|
|
44
|
+
* per environment, so an overlay edit left the target converged and its build
|
|
45
|
+
* served the old value.
|
|
46
|
+
*
|
|
47
|
+
* @param {string} label - The layer's fingerprint label ('brand-env').
|
|
48
|
+
* @param {string} root - The dir whose `.env` is this layer.
|
|
49
|
+
* @returns {Array<{ label: string, file: string }>} One entry per layer file.
|
|
50
|
+
*/
|
|
51
|
+
function envLayerEntries(label, root) {
|
|
52
|
+
const base = path.join(root, '.env');
|
|
53
|
+
const files = [...new Set(ENV_ENVIRONMENTS.flatMap((environment) => envLayerFiles(base, environment)))];
|
|
54
|
+
|
|
55
|
+
return files.map((file) => ({
|
|
56
|
+
label: file === base ? label : `${label}.${file.slice(base.length + 1)}`,
|
|
57
|
+
file,
|
|
58
|
+
}));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* The merge-chain files OUTSIDE the target tree that its build still reads:
|
|
63
|
+
* brand config/.env, and the company pair when the brand carries a marker.
|
|
64
|
+
* A brand-config edit must dirty every target's fingerprint, or the
|
|
65
|
+
* converged skip serves stale output.
|
|
66
|
+
*/
|
|
67
|
+
function chainFiles(brandRoot) {
|
|
68
|
+
const files = [
|
|
69
|
+
{ label: 'brand-config', file: path.join(brandRoot, 'config', 'omega.json5') },
|
|
70
|
+
...envLayerEntries('brand-env', brandRoot),
|
|
71
|
+
];
|
|
72
|
+
|
|
73
|
+
const marker = readCompanyMarker(brandRoot);
|
|
74
|
+
if (marker) {
|
|
75
|
+
files.push(
|
|
76
|
+
{ label: 'company-config', file: path.join(marker.companyRoot, 'config', 'omega.json5') },
|
|
77
|
+
...envLayerEntries('company-env', marker.companyRoot),
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return files;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Collect declared deps (dependencies + devDependencies) missing from an
|
|
86
|
+
* target's resolution climb.
|
|
87
|
+
*/
|
|
88
|
+
function missingDeps(targetPath) {
|
|
89
|
+
const pkg = jetpack.read(path.join(targetPath, 'package.json'), 'json');
|
|
90
|
+
if (!pkg) return [];
|
|
91
|
+
|
|
92
|
+
const declared = Object.keys({ ...pkg.dependencies, ...pkg.devDependencies });
|
|
93
|
+
return declared.filter((name) => !resolvePackageDir(targetPath, name));
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
module.exports = async ({ brandRoot, targets, options }) => {
|
|
97
|
+
const mappedTargets = targets.filter((entry) => entry.target);
|
|
98
|
+
const results = {};
|
|
99
|
+
let failed = false;
|
|
100
|
+
|
|
101
|
+
// ─── Install phase (once, at the brand root) ──────────────────────────────
|
|
102
|
+
const missing = mappedTargets.flatMap((entry) => missingDeps(entry.path).map((dep) => `${entry.name}:${dep}`));
|
|
103
|
+
const installSteps = [];
|
|
104
|
+
|
|
105
|
+
if (missing.length === 0) {
|
|
106
|
+
console.log(` ${chalk.dim('⊘ install: all dependencies resolve')}`);
|
|
107
|
+
installSteps.push({ phase: 'install', success: true, skipped: true });
|
|
108
|
+
} else if (options.dryRun) {
|
|
109
|
+
console.log(` ${chalk.yellow('⊘')} install: would run npm install ${chalk.dim(`(missing: ${missing.join(', ')})`)} ${chalk.dim('[DRY RUN]')}`);
|
|
110
|
+
installSteps.push({ phase: 'install', success: true, skipped: true, dryRun: true });
|
|
111
|
+
} else {
|
|
112
|
+
console.log(` ${chalk.dim('→')} npm install ${chalk.dim(`(missing: ${missing.join(', ')})`)}`);
|
|
113
|
+
const result = await runCommand('npm', ['install', '--no-audit', '--no-fund'], brandRoot);
|
|
114
|
+
installSteps.push({ phase: 'install', ...result });
|
|
115
|
+
if (!result.success) {
|
|
116
|
+
failed = true;
|
|
117
|
+
// Local-first era: the frameworks aren't on the registry yet
|
|
118
|
+
if (missing.some((entry) => entry.includes('@omega.js/'))) {
|
|
119
|
+
console.log(` ${chalk.yellow('⚠')} @omega.js/* packages are not published yet — link them per target with ${chalk.bold('mgr i local')} (or a workspace/file: reference).`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
results.root = { steps: installSteps };
|
|
125
|
+
|
|
126
|
+
// ─── Build phase (per target, incremental) ────────────────────────────────
|
|
127
|
+
const cache = readCache(brandRoot);
|
|
128
|
+
const chain = chainFiles(brandRoot);
|
|
129
|
+
const nextTargets = {};
|
|
130
|
+
|
|
131
|
+
for (const entry of mappedTargets) {
|
|
132
|
+
const steps = [];
|
|
133
|
+
const cached = cache.targets[entry.name];
|
|
134
|
+
|
|
135
|
+
if (failed) {
|
|
136
|
+
// Nothing was rebuilt, so last run's verdict for this target still stands
|
|
137
|
+
if (cached) nextTargets[entry.name] = cached;
|
|
138
|
+
steps.push({ phase: 'build', success: true, skipped: true, reason: 'install failed' });
|
|
139
|
+
results[entry.name] = { steps };
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const pkg = jetpack.read(path.join(entry.path, 'package.json'), 'json');
|
|
144
|
+
// Only worth sweeping when there's a cached verdict to compare against
|
|
145
|
+
// and the run is allowed to honour it
|
|
146
|
+
const fingerprint = cached && pkg?.scripts?.build && !options.force
|
|
147
|
+
? fingerprintTarget(entry.path, chain)
|
|
148
|
+
: null;
|
|
149
|
+
const converged = Boolean(fingerprint)
|
|
150
|
+
&& cached.files === fingerprint.files
|
|
151
|
+
&& cached.frameworks === fingerprint.frameworks;
|
|
152
|
+
|
|
153
|
+
if (!pkg?.scripts?.build) {
|
|
154
|
+
console.log(` ${chalk.dim(`⊘ ${entry.name}: no build script`)}`);
|
|
155
|
+
steps.push({ phase: 'build', success: true, skipped: true, reason: 'no build script' });
|
|
156
|
+
} else if (converged) {
|
|
157
|
+
console.log(` ${chalk.dim(`⊘ ${entry.name}: converged (target files + @omega.js/* unchanged)`)}`);
|
|
158
|
+
nextTargets[entry.name] = cached;
|
|
159
|
+
steps.push({ phase: 'build', success: true, skipped: true, reason: 'converged' });
|
|
160
|
+
} else if (options.dryRun) {
|
|
161
|
+
console.log(` ${chalk.yellow('⊘')} ${entry.name}: would run npm run build ${chalk.dim('[DRY RUN]')}`);
|
|
162
|
+
steps.push({ phase: 'build', success: true, skipped: true, dryRun: true });
|
|
163
|
+
} else {
|
|
164
|
+
// Non-interactive runs (pipeline, CI, and `omega dev`'s boot manage
|
|
165
|
+
// cycle — #228) must be deterministic: web builds use the committed
|
|
166
|
+
// translation cache only — never a live LLM pass mid-run (the same law
|
|
167
|
+
// deploys follow). New strings translate on the next interactive run.
|
|
168
|
+
const buildArgs = ['run', 'build'];
|
|
169
|
+
if (entry.target === 'web' && process.env.OMEGA_NON_INTERACTIVE === '1') {
|
|
170
|
+
buildArgs.push('--', '--cached-only');
|
|
171
|
+
}
|
|
172
|
+
console.log(` ${chalk.dim('→')} ${entry.name}: npm ${buildArgs.join(' ')}`);
|
|
173
|
+
const result = await runCommand('npm', buildArgs, entry.path);
|
|
174
|
+
steps.push({ phase: 'build', ...result });
|
|
175
|
+
|
|
176
|
+
if (result.success) {
|
|
177
|
+
// Re-fingerprint AFTER the build: a build that writes back into its
|
|
178
|
+
// own sources (the web translation cache) would otherwise leave the
|
|
179
|
+
// target looking fresh forever. A failed build records nothing, so the
|
|
180
|
+
// next run retries it.
|
|
181
|
+
nextTargets[entry.name] = { ...fingerprintTarget(entry.path, chain), updatedAt: new Date().toISOString() };
|
|
182
|
+
} else {
|
|
183
|
+
failed = true;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
results[entry.name] = { steps };
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// One write, only when something moved (a build landed, a target left the
|
|
191
|
+
// brand, or the file was missing/unreadable and this rebuilds it). Keys are
|
|
192
|
+
// sorted so a converged rerun produces the byte-identical file it read.
|
|
193
|
+
const nextCache = {
|
|
194
|
+
version: CACHE_VERSION,
|
|
195
|
+
targets: Object.fromEntries(Object.keys(nextTargets).sort().map((name) => [name, nextTargets[name]])),
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
if (!options.dryRun && JSON.stringify(nextCache) !== JSON.stringify(cache)) {
|
|
199
|
+
writeCache(brandRoot, nextCache);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return {
|
|
203
|
+
status: failed ? 'error' : 'success',
|
|
204
|
+
output: { results },
|
|
205
|
+
};
|
|
206
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ensure the brand agent-docs chain (Ian 2026-07-20): root AGENTS.md opens
|
|
3
|
+
* with the framework-guide import, root CLAUDE.md is the one-line
|
|
4
|
+
* `@AGENTS.md` pointer. Consumer content is preserved; a content-bearing
|
|
5
|
+
* CLAUDE.md warns with the move-it message instead of being clobbered.
|
|
6
|
+
*/
|
|
7
|
+
const chalk = require('chalk').default;
|
|
8
|
+
|
|
9
|
+
const { ensureAgentsMd, ensureClaudePointer, ensureGuideLink, IMPORT_LINE, CLAUDE_POINTER } = require('../../../lib/agents-md.js');
|
|
10
|
+
|
|
11
|
+
module.exports = async ({ brandRoot, brand }) => {
|
|
12
|
+
const brandName = brand.config?.brand?.name || brand.id;
|
|
13
|
+
|
|
14
|
+
const guide = ensureGuideLink(brandRoot);
|
|
15
|
+
const guideLabel = {
|
|
16
|
+
present: 'node_modules/@omega.js/AGENTS.md links the framework map',
|
|
17
|
+
created: 'Linked node_modules/@omega.js/AGENTS.md at the framework map',
|
|
18
|
+
healed: 'Relinked node_modules/@omega.js/AGENTS.md at the framework map',
|
|
19
|
+
skipped: 'No resolvable framework map yet (pre-install) — link skipped',
|
|
20
|
+
}[guide];
|
|
21
|
+
console.log(` ${chalk.green('✓')} ${guideLabel}`);
|
|
22
|
+
|
|
23
|
+
const agents = ensureAgentsMd(brandRoot, brandName);
|
|
24
|
+
const agentsLabel = {
|
|
25
|
+
present: `AGENTS.md imports the framework guide (${IMPORT_LINE})`,
|
|
26
|
+
created: 'Created AGENTS.md with the framework-guide import',
|
|
27
|
+
healed: 'Healed AGENTS.md — framework-guide import moved to line 1 (your content preserved)',
|
|
28
|
+
}[agents];
|
|
29
|
+
console.log(` ${chalk.green('✓')} ${agentsLabel}`);
|
|
30
|
+
|
|
31
|
+
const claude = ensureClaudePointer(brandRoot);
|
|
32
|
+
if (claude === 'content-bearing') {
|
|
33
|
+
console.log(` ${chalk.yellow('⚠')} CLAUDE.md carries content — move it into AGENTS.md (below the import) and reduce CLAUDE.md to the one-line \`${CLAUDE_POINTER}\` pointer`);
|
|
34
|
+
return { status: 'warned', reason: 'CLAUDE.md carries content — move it into AGENTS.md', output: { guide, agents, claude } };
|
|
35
|
+
}
|
|
36
|
+
console.log(` ${chalk.green('✓')} CLAUDE.md ${claude === 'created' ? 'created as' : 'is'} the \`${CLAUDE_POINTER}\` pointer`);
|
|
37
|
+
|
|
38
|
+
if (agents === 'present' && claude === 'present' && (guide === 'present' || guide === 'skipped')) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
return { output: { guide, agents, claude } };
|
|
42
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ensure the brand's committed `.claude/settings.json` registers the omega
|
|
3
|
+
* marketplace from the installed manager package and enables the plugin
|
|
4
|
+
* ([#62](https://github.com/Omega-JS-Stack/omega/issues/62)) — the consumer
|
|
5
|
+
* half of the plugin install. Only a PUBLISHED install carries the vendored
|
|
6
|
+
* marketplace; the local era skips (the developer's user-scope install serves
|
|
7
|
+
* those sessions). Consumer settings are never clobbered.
|
|
8
|
+
*/
|
|
9
|
+
const chalk = require('chalk').default;
|
|
10
|
+
|
|
11
|
+
const { ensureClaudeSettings, SETTINGS_FILE, PLUGIN_ID } = require('../../../lib/claude-settings.js');
|
|
12
|
+
|
|
13
|
+
module.exports = async ({ brandRoot }) => {
|
|
14
|
+
const result = ensureClaudeSettings(brandRoot);
|
|
15
|
+
|
|
16
|
+
if (result === 'skipped') {
|
|
17
|
+
console.log(` ${chalk.green('✓')} No vendored omega plugin in node_modules/@omega.js/manager (local era) — ${SETTINGS_FILE} left alone`);
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (result === 'invalid') {
|
|
22
|
+
console.log(` ${chalk.yellow('⚠')} ${SETTINGS_FILE} is not valid JSON — fix it so the omega plugin (${PLUGIN_ID}) can be registered`);
|
|
23
|
+
return { status: 'warned', reason: `${SETTINGS_FILE} is not valid JSON`, output: { claudeSettings: result } };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const label = {
|
|
27
|
+
present: `${SETTINGS_FILE} enables the omega plugin (${PLUGIN_ID})`,
|
|
28
|
+
created: `Created ${SETTINGS_FILE} — the omega plugin loads in every session here`,
|
|
29
|
+
healed: `Healed ${SETTINGS_FILE} — omega plugin registered (your other settings preserved)`,
|
|
30
|
+
}[result];
|
|
31
|
+
console.log(` ${chalk.green('✓')} ${label}`);
|
|
32
|
+
|
|
33
|
+
return result === 'present' ? null : { output: { claudeSettings: result } };
|
|
34
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ensure omega.json5 health. The brand file is the manager's input — a brand
|
|
3
|
+
* config that fails to load (parse error, secret-shaped keys, legacy targets
|
|
4
|
+
* array) or fails schema validation is an ERROR: there is nothing sound to
|
|
5
|
+
* reconcile services against. Target-level findings are warnings — each
|
|
6
|
+
* framework's own setup/audit is the hard gate for its surface.
|
|
7
|
+
*/
|
|
8
|
+
const chalk = require('chalk').default;
|
|
9
|
+
|
|
10
|
+
const { loadConfig, hasOmegaConfig } = require('../../../vendor/config/index.js');
|
|
11
|
+
|
|
12
|
+
module.exports = async ({ brand, targets }) => {
|
|
13
|
+
// Brand config failed to LOAD (thrown by @omega.js/config — secrets, parse, targets array)
|
|
14
|
+
if (brand.configError) {
|
|
15
|
+
console.log(` ${chalk.red('✗')} ${brand.configError}`);
|
|
16
|
+
return { status: 'error', error: brand.configError };
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Brand config loaded but has schema findings
|
|
20
|
+
if (brand.configErrors.length > 0) {
|
|
21
|
+
for (const error of brand.configErrors) {
|
|
22
|
+
console.log(` ${chalk.red('✗')} brand: ${error}`);
|
|
23
|
+
}
|
|
24
|
+
return { status: 'error', error: `brand config invalid: ${brand.configErrors.join('; ')}` };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
console.log(` ${chalk.green('✓')} brand config valid ${chalk.dim(`(${brand.files?.app || 'config/omega.json5'})`)}`);
|
|
28
|
+
|
|
29
|
+
// Per-target validation for dirs that carry their own config and map to a target
|
|
30
|
+
const findings = [];
|
|
31
|
+
for (const entry of targets) {
|
|
32
|
+
if (!entry.target || !hasOmegaConfig(entry.path)) continue;
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
const { errors } = loadConfig(entry.path, entry.target);
|
|
36
|
+
for (const error of errors) {
|
|
37
|
+
findings.push(`${entry.name}: ${error}`);
|
|
38
|
+
}
|
|
39
|
+
} catch (error) {
|
|
40
|
+
// A target config that cannot load at all (secrets, parse) is still a hard stop
|
|
41
|
+
console.log(` ${chalk.red('✗')} ${entry.name}: ${error.message}`);
|
|
42
|
+
return { status: 'error', error: `${entry.name}: ${error.message}` };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (findings.length > 0) {
|
|
47
|
+
for (const finding of findings) {
|
|
48
|
+
console.log(` ${chalk.yellow('⚠')} ${finding}`);
|
|
49
|
+
}
|
|
50
|
+
return { status: 'warned', reason: findings.join('; '), output: { findings } };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return null;
|
|
54
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Self-healing config ([#478](https://github.com/Omega-JS-Stack/omega/issues/478)):
|
|
3
|
+
* every manage run materializes the schema-defaulted blocks the brand's
|
|
4
|
+
* omega.json5 does not carry yet, so a subsystem that exists has its config
|
|
5
|
+
* structure visible and editable in the file — never an invisible framework
|
|
6
|
+
* fallback. A newly added default therefore appears in every consumer's config
|
|
7
|
+
* on the next run.
|
|
8
|
+
*
|
|
9
|
+
* What it never does: overwrite. `missingDefaults()` names only the keys the
|
|
10
|
+
* brand has not authored, the comment-preserving editor inserts them (each
|
|
11
|
+
* block documented with the schema's own description), and a converged config
|
|
12
|
+
* leaves the file byte-identical. Keys with no sane framework answer — owner
|
|
13
|
+
* decisions, provisioned ids, anything secret-shaped — carry no schema default
|
|
14
|
+
* and are never written here.
|
|
15
|
+
*/
|
|
16
|
+
const { join } = require('node:path');
|
|
17
|
+
const jetpack = require('fs-jetpack');
|
|
18
|
+
const chalk = require('chalk').default;
|
|
19
|
+
const JSON5 = require('json5');
|
|
20
|
+
|
|
21
|
+
const { missingDefaults, defaultComments, writeConfigValues, resolveConfigPath, FILE_NAME } = require('../../../vendor/config/index.js');
|
|
22
|
+
const { dryRunPlan } = require('../../../lib/run-gates.js');
|
|
23
|
+
|
|
24
|
+
module.exports = async ({ brandRoot, options = {} }) => {
|
|
25
|
+
const configPath = resolveConfigPath(brandRoot);
|
|
26
|
+
if (!configPath) {
|
|
27
|
+
console.log(` ${chalk.dim(`⊘ no ${join('config', FILE_NAME)} yet (the config operation reports it)`)}`);
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// The RAW file, not the resolved config: resolution already merged the
|
|
32
|
+
// defaults in, so every block would read as present.
|
|
33
|
+
const missing = missingDefaults(JSON5.parse(jetpack.read(configPath)));
|
|
34
|
+
|
|
35
|
+
if (missing.length === 0) {
|
|
36
|
+
console.log(` ${chalk.green('✓')} ${FILE_NAME} carries every schema default`);
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const blocks = missing.map((entry) => entry.path);
|
|
41
|
+
|
|
42
|
+
if (options.dryRun) {
|
|
43
|
+
return dryRunPlan(
|
|
44
|
+
`materialize ${blocks.join(', ')} in ${FILE_NAME}`,
|
|
45
|
+
{ output: { defaults: { planned: blocks } } },
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
writeConfigValues(
|
|
50
|
+
brandRoot,
|
|
51
|
+
Object.fromEntries(missing.map((entry) => [entry.path, entry.value])),
|
|
52
|
+
{ comments: defaultComments() },
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
for (const block of blocks) {
|
|
56
|
+
console.log(` ${chalk.green('+')} ${FILE_NAME} ← ${chalk.cyan(block)} ${chalk.dim('(schema default)')}`);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return { output: { defaults: { materialized: blocks } } };
|
|
60
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ensure the brand .env carries every key OMEGA generates for itself — the
|
|
3
|
+
* env schema's `generated` entries (@omega.js/config, #581) — the manage-time
|
|
4
|
+
* half of the mint the onboard scaffold does for a fresh brand (#569). A brand
|
|
5
|
+
* onboarded before a key existed gains it here instead of discovering the hole
|
|
6
|
+
* at the first send.
|
|
7
|
+
*
|
|
8
|
+
* Presence is judged on the RESOLVED value (`process.env`, which manage
|
|
9
|
+
* already layered shell > brand .env > company .env), so a company-managed
|
|
10
|
+
* brand never shadows its company's value with a fresh one. A minted value
|
|
11
|
+
* is published into `process.env` too, so the same run's builds compose it
|
|
12
|
+
* into their targets — the key is live one manage after the gap, not two.
|
|
13
|
+
* Values are never printed: the run says WHICH key it minted, never what.
|
|
14
|
+
*
|
|
15
|
+
* The mint itself is lib/env-secret.js's `mintGeneratedKey` — shared with the
|
|
16
|
+
* setup contract, which mints a single key for a service that reached it
|
|
17
|
+
* before this op ran (#635).
|
|
18
|
+
*/
|
|
19
|
+
const chalk = require('chalk').default;
|
|
20
|
+
|
|
21
|
+
const { generatedEnvKeys } = require('../../../vendor/config/index.js');
|
|
22
|
+
const { mintGeneratedKey } = require('../../../lib/env-secret.js');
|
|
23
|
+
const { dryRunPlan } = require('../../../lib/run-gates.js');
|
|
24
|
+
|
|
25
|
+
module.exports = async (context) => {
|
|
26
|
+
const { brandRoot, options = {} } = context;
|
|
27
|
+
|
|
28
|
+
const minted = [];
|
|
29
|
+
const planned = [];
|
|
30
|
+
const present = [];
|
|
31
|
+
|
|
32
|
+
for (const name of Object.keys(generatedEnvKeys())) {
|
|
33
|
+
if (process.env[name]) {
|
|
34
|
+
present.push(name);
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (options.dryRun) {
|
|
39
|
+
dryRunPlan(`mint ${name} into the brand .env`);
|
|
40
|
+
planned.push(name);
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// The mint — and its success line — live once, in lib/env-secret.js, so
|
|
45
|
+
// this op and the setup contract report an identical key identically
|
|
46
|
+
mintGeneratedKey(brandRoot, name);
|
|
47
|
+
minted.push(name);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (present.length > 0) {
|
|
51
|
+
console.log(` ${chalk.green('✓')} generated keys (${present.length} present)`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return { output: { envKeys: { minted, planned, present } } };
|
|
55
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ensure the brand .env (and the company .env when the brand is
|
|
3
|
+
* company-managed) is in the canonical order — groups, comments, and
|
|
4
|
+
* placeholders from the env-order SSOT, hand comments travelling with
|
|
5
|
+
* their keys, duplicates collapsed to the dotenv winner. A converged file
|
|
6
|
+
* rewrites nothing; a file the reorderer can't parse (multi-line values,
|
|
7
|
+
* export forms) is left untouched with a note, never a failure.
|
|
8
|
+
*/
|
|
9
|
+
const { join } = require('node:path');
|
|
10
|
+
const jetpack = require('fs-jetpack');
|
|
11
|
+
const chalk = require('chalk').default;
|
|
12
|
+
|
|
13
|
+
const { applyEnvOrder } = require('../../../lib/env-order.js');
|
|
14
|
+
const { dryRunPlan } = require('../../../lib/run-gates.js');
|
|
15
|
+
|
|
16
|
+
module.exports = async (context) => {
|
|
17
|
+
const { brandRoot, companyRoot, brandConfig, options = {} } = context;
|
|
18
|
+
|
|
19
|
+
const roots = [
|
|
20
|
+
{ label: 'brand', root: brandRoot, isBrand: true },
|
|
21
|
+
...(companyRoot ? [{ label: 'company', root: companyRoot, isBrand: false }] : []),
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
const summary = {};
|
|
25
|
+
for (const { label, root, isBrand } of roots) {
|
|
26
|
+
const envPath = join(root, '.env');
|
|
27
|
+
if (!jetpack.exists(envPath)) {
|
|
28
|
+
console.log(` ${chalk.dim(`⊘ no ${label} .env yet`)}`);
|
|
29
|
+
summary[label] = 'missing';
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const result = applyEnvOrder(jetpack.read(envPath), {
|
|
34
|
+
// Only the brand file gets a default header minted (we know its name);
|
|
35
|
+
// an existing header always wins
|
|
36
|
+
defaultHeader: isBrand
|
|
37
|
+
? [`# ${brandConfig.brand.name} — brand secrets (gitignored; loaded before every omega run).`]
|
|
38
|
+
: [],
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
if (result.skipped) {
|
|
42
|
+
console.log(` ${chalk.dim(`⊘ ${label} .env left as-is (${result.skipped})`)}`);
|
|
43
|
+
summary[label] = 'skipped';
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (!result.changed) {
|
|
47
|
+
console.log(` ${chalk.green('✓')} ${label} .env order (current)`);
|
|
48
|
+
summary[label] = 'current';
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if (options.dryRun) {
|
|
52
|
+
dryRunPlan(`reorder the ${label} .env into canonical groups`);
|
|
53
|
+
summary[label] = 'planned';
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
jetpack.write(envPath, result.content);
|
|
58
|
+
const dupNote = result.duplicatesCollapsed > 0
|
|
59
|
+
? chalk.dim(` (${result.duplicatesCollapsed} duplicate line${result.duplicatesCollapsed === 1 ? '' : 's'} collapsed, last value kept)`)
|
|
60
|
+
: '';
|
|
61
|
+
console.log(` ${chalk.green('✓')} ${label} .env reordered${dupNote}`);
|
|
62
|
+
summary[label] = 'reordered';
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return { output: { envOrder: summary } };
|
|
66
|
+
};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Say, at MANAGE time, which env keys the brand's OWN config made mandatory
|
|
3
|
+
* and nobody has filled in — the env schema's `requiredWhen` rules
|
|
4
|
+
* ([#626](https://github.com/Omega-JS-Stack/omega/issues/626)).
|
|
5
|
+
*
|
|
6
|
+
* Every one of those rules used to be discovered LATE and per target: the
|
|
7
|
+
* extension's build threw on a GA4 stream with no Measurement Protocol secret,
|
|
8
|
+
* the backend 403'd every protected POST when a reCAPTCHA site key had no
|
|
9
|
+
* secret half, the captcha service paired the halves with its own if. The
|
|
10
|
+
* schema declares each rule once, checkEnvRules (@omega.js/config) evaluates
|
|
11
|
+
* it, and this op is the earliest place a human hears about it.
|
|
12
|
+
*
|
|
13
|
+
* Evaluated PER ENABLED TARGET, against that target's RESOLVED config
|
|
14
|
+
* ([#627](https://github.com/Omega-JS-Stack/omega/issues/627) review): the
|
|
15
|
+
* values these rules read live where the services write them, and that is the
|
|
16
|
+
* target section — the analytics service provisions one GA4 stream per surface
|
|
17
|
+
* (targets.<t>.analytics.providers.google.id) and leaves the shared slot null.
|
|
18
|
+
* A brand-ROOT evaluation therefore saw NOTHING for the canonical brand shape,
|
|
19
|
+
* and over-fired for the shared-id one (every per-target secret at once,
|
|
20
|
+
* including targets the brand does not even enable). The resolution is
|
|
21
|
+
* @omega.js/config's own (loadConfig with a target overlays targets.<type>);
|
|
22
|
+
* entries no enabled target claims are never evaluated.
|
|
23
|
+
*
|
|
24
|
+
* The few entries no target reads at all (SENTRY_AUTH_TOKEN — the monitoring
|
|
25
|
+
* SERVICE's) are judged against the brand config AND every enabled target's
|
|
26
|
+
* resolved one ([#683](https://github.com/Omega-JS-Stack/omega/issues/683)):
|
|
27
|
+
* the same disease one level over. A target-less key belongs to a SERVICE, but
|
|
28
|
+
* the config path that requires it is written wherever that service writes its
|
|
29
|
+
* values — the monitoring service provisions one Sentry project per surface
|
|
30
|
+
* and lands the DSN in targets.<t>.monitoring.providers.sentry.dsn with the
|
|
31
|
+
* shared slot null. Truthy in ANY enabled target (or at the root) owes the key
|
|
32
|
+
* once; the per-key dedupe below is what makes the union one violation.
|
|
33
|
+
*
|
|
34
|
+
* It WARNS and never fails. A half-configured brand is a normal step on the way
|
|
35
|
+
* to a configured one (the key is a dashboard visit away), and a manage run
|
|
36
|
+
* that refuses to reconcile over it would be a hostage note. The lanes that
|
|
37
|
+
* CANNOT proceed — a production backend boot — refuse on their own.
|
|
38
|
+
*
|
|
39
|
+
* Presence is judged on the RESOLVED cascade (`process.env`, which manage
|
|
40
|
+
* layered shell > brand .env > company .env before any service ran), so a
|
|
41
|
+
* company-supplied value counts. Violations name the BRAND-LEVEL key
|
|
42
|
+
* (GOOGLE_ANALYTICS_SECRET_WEB, not the GOOGLE_ANALYTICS_SECRET it is
|
|
43
|
+
* delivered to a target as): that is the name a human puts in the .env.
|
|
44
|
+
*/
|
|
45
|
+
const chalk = require('chalk').default;
|
|
46
|
+
|
|
47
|
+
const { ENV_SCHEMA, loadConfig, getEnabledTargets, TARGETS } = require('../../../vendor/config/index.js');
|
|
48
|
+
const { checkEnvRules } = require('../../../vendor/config/env-rules.js');
|
|
49
|
+
const { DEFAULTS } = require('../../../config.js');
|
|
50
|
+
|
|
51
|
+
// The entries no target reads (`targets: []`) — a service's own key, which no
|
|
52
|
+
// target-resolved view could ever raise. The checker's `schema` seam scopes a
|
|
53
|
+
// pass to them without this op ever reading a rule itself.
|
|
54
|
+
const TARGETLESS_SCHEMA = ENV_SCHEMA.filter((entry) => entry.targets && entry.targets.length === 0);
|
|
55
|
+
|
|
56
|
+
module.exports = async (context) => {
|
|
57
|
+
const { brandRoot, brandConfig } = context;
|
|
58
|
+
|
|
59
|
+
// Key presence in `targets` IS the enablement signal; a custom target (#603)
|
|
60
|
+
// is a brand's own dir, not a framework the schema delivers keys to.
|
|
61
|
+
const enabled = getEnabledTargets(brandConfig).filter((target) => TARGETS.includes(target));
|
|
62
|
+
|
|
63
|
+
const violations = [];
|
|
64
|
+
const seen = new Set();
|
|
65
|
+
const collect = (found) => {
|
|
66
|
+
for (const violation of found) {
|
|
67
|
+
if (violation.rule !== 'requiredWhen' || seen.has(violation.key)) continue;
|
|
68
|
+
seen.add(violation.key);
|
|
69
|
+
violations.push(violation);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
collect(checkEnvRules(brandConfig, process.env, { schema: TARGETLESS_SCHEMA }));
|
|
74
|
+
|
|
75
|
+
for (const target of enabled) {
|
|
76
|
+
// The per-target view is @omega.js/config's resolution, not a merge of our
|
|
77
|
+
// own: same chain as every framework's own load (company ← brand shared ←
|
|
78
|
+
// brand targets.<type>), so this op and the target's build read one config.
|
|
79
|
+
const { config } = loadConfig(brandRoot, target, { defaults: DEFAULTS });
|
|
80
|
+
collect(checkEnvRules(config, process.env, { target }));
|
|
81
|
+
// …and the service's own keys against that same view (#683): a target-less
|
|
82
|
+
// entry names no target, so nothing here scopes it — this asks whether the
|
|
83
|
+
// path that requires it is truthy on THIS surface.
|
|
84
|
+
collect(checkEnvRules(config, process.env, { schema: TARGETLESS_SCHEMA }));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (violations.length === 0) {
|
|
88
|
+
console.log(` ${chalk.green('✓')} config-required env keys (all present)`);
|
|
89
|
+
return { output: { envRules: { violations } } };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
for (const { key, path } of violations) {
|
|
93
|
+
console.log(` ${chalk.yellow('⚠')} ${chalk.cyan(key)} is missing from the .env cascade — ${chalk.cyan(path)} in omega.json5 requires it`);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return { output: { envRules: { violations } } };
|
|
97
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ensure .omega/ and logs/ are gitignored at the brand root — the secrets
|
|
3
|
+
* store and run output never get committed. Idempotent: checks for existing entries
|
|
4
|
+
* before appending. The shared ensure also covers company roots (runCompany).
|
|
5
|
+
*/
|
|
6
|
+
const chalk = require('chalk').default;
|
|
7
|
+
|
|
8
|
+
const { ensureOmegaIgnored } = require('../../../lib/gitignore.js');
|
|
9
|
+
|
|
10
|
+
module.exports = async ({ brandRoot }) => {
|
|
11
|
+
if (ensureOmegaIgnored(brandRoot) === 'present') {
|
|
12
|
+
console.log(` ${chalk.green('✓')} .gitignore has the omega entries`);
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
console.log(` ${chalk.green('✓')} Added missing omega entries to .gitignore`);
|
|
17
|
+
return { output: { gitignore: 'added' } };
|
|
18
|
+
};
|