@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,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ensure the brand's package.json scripts convention — the root AND each
|
|
3
|
+
* framework target's (npm scripts put node_modules/.bin on PATH, so plain
|
|
4
|
+
* `omega` resolves there). Script VALUES only — no other key or consumer
|
|
5
|
+
* content is ever touched. Idempotent: a converged file rewrites nothing.
|
|
6
|
+
*
|
|
7
|
+
* Root: `deploy: 'omega deploy'` guaranteed plus the start/manage migration
|
|
8
|
+
* (package-scripts.js). Targets: every key the framework declares in its own
|
|
9
|
+
* `projectScripts` is FRAMEWORK-owned and is rewritten to the default here,
|
|
10
|
+
* exactly as that framework's ensureTarget does on every verb run (#689) —
|
|
11
|
+
* one policy, two writers, so a consumer customizes behavior through hook
|
|
12
|
+
* points and never by editing a standard script. The walk running it at all
|
|
13
|
+
* is the onboard→dev cycle break (#675): the dev fan-out reaches those verbs
|
|
14
|
+
* THROUGH these scripts, so a freshly scaffolded target needs them before any
|
|
15
|
+
* verb has ever run. Keys the consumer added are never touched.
|
|
16
|
+
*
|
|
17
|
+
* The exceptions: a custom TARGET maps to no framework at all (#603), so it
|
|
18
|
+
* is skipped whole; a custom-server backend is skipped PER KEY (#584) — the
|
|
19
|
+
* verbs its mode refuses are the brand's own, named by the framework's
|
|
20
|
+
* `projectScriptsCustomOwned` declaration.
|
|
21
|
+
*/
|
|
22
|
+
const { join } = require('node:path');
|
|
23
|
+
const jetpack = require('fs-jetpack');
|
|
24
|
+
const chalk = require('chalk').default;
|
|
25
|
+
|
|
26
|
+
const { healPackageScripts, syncTargetScripts } = require('../../../lib/package-scripts.js');
|
|
27
|
+
const { resolveFrameworkPackage } = require('../../../lib/framework-bin.js');
|
|
28
|
+
const { TARGET_FRAMEWORKS } = require('../../../config.js');
|
|
29
|
+
const { dryRunPlan } = require('../../../lib/run-gates.js');
|
|
30
|
+
|
|
31
|
+
module.exports = async ({ brandRoot, targets = [], options = {} }) => {
|
|
32
|
+
const pkgPath = join(brandRoot, 'package.json');
|
|
33
|
+
const raw = jetpack.read(pkgPath);
|
|
34
|
+
if (!raw) {
|
|
35
|
+
console.log(` ${chalk.dim('⊘ no root package.json yet (the structure operation scaffolds it)')}`);
|
|
36
|
+
return { output: { scripts: 'missing' } };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
let pkg;
|
|
40
|
+
try {
|
|
41
|
+
pkg = JSON.parse(raw);
|
|
42
|
+
} catch (e) {
|
|
43
|
+
console.log(` ${chalk.yellow('⚠')} Root package.json doesn't parse (${e.message}) — fix it by hand`);
|
|
44
|
+
return { status: 'warned', reason: "root package.json doesn't parse", output: { scripts: 'unparseable' } };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const { scripts, changes } = healPackageScripts(pkg);
|
|
48
|
+
|
|
49
|
+
const targetWork = [];
|
|
50
|
+
const warnings = [];
|
|
51
|
+
for (const entry of targets) {
|
|
52
|
+
// A custom target's scripts are the brand's own contract (#603) — no
|
|
53
|
+
// framework declares them, so there is nothing to sync against
|
|
54
|
+
if (!entry.target) continue;
|
|
55
|
+
|
|
56
|
+
const framework = TARGET_FRAMEWORKS[entry.target];
|
|
57
|
+
const resolved = framework ? resolveFrameworkPackage(entry.path, framework) : null;
|
|
58
|
+
// Not installed yet (pre-`npm install`), or a framework that declares no
|
|
59
|
+
// projectScripts — nothing to fill from; the next walk heals it
|
|
60
|
+
if (!resolved || !resolved.pkg.projectScripts) continue;
|
|
61
|
+
|
|
62
|
+
const manifestPath = join(entry.path, 'package.json');
|
|
63
|
+
const targetRaw = jetpack.read(manifestPath);
|
|
64
|
+
if (!targetRaw) continue;
|
|
65
|
+
|
|
66
|
+
let targetPkg;
|
|
67
|
+
try {
|
|
68
|
+
targetPkg = JSON.parse(targetRaw);
|
|
69
|
+
} catch (e) {
|
|
70
|
+
console.log(` ${chalk.yellow('⚠')} ${entry.dir}/package.json doesn't parse (${e.message}) — fix it by hand`);
|
|
71
|
+
warnings.push(`${entry.dir}/package.json doesn't parse`);
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// A custom-server backend owns the keys whose verbs its mode refuses
|
|
76
|
+
// (#584) — the framework declares WHICH, so no list lives here (#689)
|
|
77
|
+
const brandOwnedKeys = entry.projectType === 'custom' ? (resolved.pkg.projectScriptsCustomOwned || []) : [];
|
|
78
|
+
|
|
79
|
+
const synced = syncTargetScripts(targetPkg, resolved.pkg.projectScripts, brandOwnedKeys);
|
|
80
|
+
if (synced.changes.length) targetWork.push({ entry, manifestPath, targetPkg, synced });
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (!changes.length && !targetWork.length && !warnings.length) {
|
|
84
|
+
console.log(` ${chalk.green('✓')} Root + target scripts present`);
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (options.dryRun) {
|
|
89
|
+
const parts = [];
|
|
90
|
+
if (changes.length) parts.push(`heal root scripts (${changes.join(', ')})`);
|
|
91
|
+
for (const work of targetWork) {
|
|
92
|
+
parts.push(`sync ${work.entry.dir} scripts (${work.synced.changes.join(', ')})`);
|
|
93
|
+
}
|
|
94
|
+
return dryRunPlan(parts.join('; '), {
|
|
95
|
+
output: {
|
|
96
|
+
...(changes.length ? { scripts: 'planned' } : {}),
|
|
97
|
+
...(targetWork.length ? { targetScripts: 'planned' } : {}),
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const output = {};
|
|
103
|
+
|
|
104
|
+
if (changes.length) {
|
|
105
|
+
pkg.scripts = scripts;
|
|
106
|
+
jetpack.write(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`);
|
|
107
|
+
console.log(` ${chalk.green('✓')} Healed root scripts \`${changes.join('`, `')}\``);
|
|
108
|
+
output.scripts = { changed: changes };
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
for (const work of targetWork) {
|
|
112
|
+
work.targetPkg.scripts = work.synced.scripts;
|
|
113
|
+
jetpack.write(work.manifestPath, `${JSON.stringify(work.targetPkg, null, 2)}\n`);
|
|
114
|
+
// The skipped keys are named per key: a custom-server backend's own verbs
|
|
115
|
+
// are absent by design, not by omission
|
|
116
|
+
const brandOwned = work.synced.skipped.length ? chalk.dim(` (brand-owned, untouched: ${work.synced.skipped.join(', ')})`) : '';
|
|
117
|
+
console.log(` ${chalk.green('✓')} Synced ${work.entry.dir} scripts \`${work.synced.changes.join('`, `')}\`${brandOwned}`);
|
|
118
|
+
output.targetScripts = output.targetScripts || {};
|
|
119
|
+
output.targetScripts[work.entry.name] = work.synced.changes;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return {
|
|
123
|
+
...(warnings.length ? { status: 'warned', reason: warnings.join('; ') } : {}),
|
|
124
|
+
output,
|
|
125
|
+
};
|
|
126
|
+
};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ensure the brand-monorepo structure: a root package.json with targets/*
|
|
3
|
+
* workspaces, and a target directory for every enabled target. Dirs that map
|
|
4
|
+
* to no target are warned (never silently skipped); enabled targets with no
|
|
5
|
+
* dir are errors with the exact dir to create.
|
|
6
|
+
*
|
|
7
|
+
* Multi-instance targets: an ARRAY-form target expects one dir PER
|
|
8
|
+
* instance (`main` → the canonical dir, any other id → `<canonical>-<id>`) —
|
|
9
|
+
* an enabled instance without its dir is the same create-this-dir error. The
|
|
10
|
+
* single-object form keeps today's any-dir-of-the-type check untouched.
|
|
11
|
+
*
|
|
12
|
+
* Custom targets (#603) map to no framework by design, so they are checked BY
|
|
13
|
+
* DIR (the declaration names it) and never counted among the unmapped — this
|
|
14
|
+
* service is one of the two ops that see them at all.
|
|
15
|
+
*/
|
|
16
|
+
const { join } = require('node:path');
|
|
17
|
+
const chalk = require('chalk').default;
|
|
18
|
+
const jetpack = require('fs-jetpack');
|
|
19
|
+
|
|
20
|
+
const { normalizeTargetInstances, instanceTargetDir, isCustomTargetEntry } = require('../../../vendor/config/index.js');
|
|
21
|
+
const { TARGET_DIRS } = require('../../../config.js');
|
|
22
|
+
const { customTargetDirs } = require('../../../lib/custom-target.js');
|
|
23
|
+
|
|
24
|
+
module.exports = async ({ brandRoot, brand, targets }) => {
|
|
25
|
+
const problems = [];
|
|
26
|
+
const findings = [];
|
|
27
|
+
|
|
28
|
+
// Root package.json must exist and declare targets/* workspaces
|
|
29
|
+
const pkg = jetpack.read(join(brandRoot, 'package.json'), 'json');
|
|
30
|
+
if (!pkg) {
|
|
31
|
+
problems.push('no package.json at the brand root');
|
|
32
|
+
} else {
|
|
33
|
+
const workspaces = Array.isArray(pkg.workspaces) ? pkg.workspaces : [];
|
|
34
|
+
if (!workspaces.includes('targets/*')) {
|
|
35
|
+
problems.push(`root package.json workspaces must include "targets/*" (found: ${JSON.stringify(workspaces)})`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Every enabled target needs at least one dir; the multi-instance array
|
|
40
|
+
// form needs every instance's exact dir (the config validator owns id
|
|
41
|
+
// sanity — malformed entries are its errors, never doubled here)
|
|
42
|
+
for (const target of brand.enabledTargets) {
|
|
43
|
+
const declared = brand.config?.targets?.[target];
|
|
44
|
+
|
|
45
|
+
// A custom target's dirs are named by its own declaration, one per
|
|
46
|
+
// instance — the same create-this-dir error, checked by name
|
|
47
|
+
if (isCustomTargetEntry(declared)) {
|
|
48
|
+
for (const dir of customTargetDirs({ targets: { [target]: declared } })) {
|
|
49
|
+
if (!targets.some((entry) => entry.name === dir)) {
|
|
50
|
+
problems.push(`enabled custom target "${target}" has no dir — create targets/${dir}/`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (Array.isArray(declared)) {
|
|
57
|
+
for (const instance of normalizeTargetInstances(declared)) {
|
|
58
|
+
if (typeof instance?.id !== 'string') continue;
|
|
59
|
+
const dir = instanceTargetDir(target, instance.id);
|
|
60
|
+
if (!targets.some((entry) => entry.name === dir)) {
|
|
61
|
+
problems.push(`enabled target "${target}" instance "${instance.id}" has no dir — create targets/${dir}/`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (!targets.some((entry) => entry.target === target)) {
|
|
68
|
+
const suggested = TARGET_DIRS[target] || target;
|
|
69
|
+
problems.push(`enabled target "${target}" has no dir — create targets/${suggested}/`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Dirs that resolve to no target are suspicious but not fatal — a DECLARED
|
|
74
|
+
// custom dir is neither: the brand said what it is
|
|
75
|
+
const unmapped = targets.filter((entry) => !entry.target && !entry.custom);
|
|
76
|
+
for (const entry of unmapped) {
|
|
77
|
+
findings.push(`${entry.dir} maps to no target — declare one in its omega.json5, use a conventional dir name, or declare it \`type: 'custom'\``);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (problems.length > 0) {
|
|
81
|
+
for (const problem of problems) {
|
|
82
|
+
console.log(` ${chalk.red('✗')} ${problem}`);
|
|
83
|
+
}
|
|
84
|
+
return { status: 'error', error: problems.join('; '), output: { problems } };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
console.log(` ${chalk.green('✓')} ${targets.length} target(s): ${targets.map((entry) => `${entry.name}→${entry.target || (entry.custom ? 'custom' : '?')}`).join(', ')}`);
|
|
88
|
+
|
|
89
|
+
if (findings.length > 0) {
|
|
90
|
+
for (const finding of findings) {
|
|
91
|
+
console.log(` ${chalk.yellow('⚠')} ${finding}`);
|
|
92
|
+
}
|
|
93
|
+
return { status: 'warned', reason: findings.join('; '), output: { findings } };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return { output: { targets: targets.map((entry) => ({ name: entry.name, target: entry.target })) } };
|
|
97
|
+
};
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ensure a translating web target declares the Claude translation SDK (#168).
|
|
3
|
+
*
|
|
4
|
+
* `@omega.js/web` is the only framework that leaves `@anthropic-ai/claude-agent-sdk`
|
|
5
|
+
* to the consumer (#37: translation is opt-in and the SDK is heavy, so web
|
|
6
|
+
* declares it as an OPTIONAL PEER; backend and extension declare it as a real
|
|
7
|
+
* dependency). Every brand ends up translating (Ian 2026-08-03), so the manage
|
|
8
|
+
* cycle owns that install instead of a human typing it per brand: a web target
|
|
9
|
+
* whose resolved config turns translation on with the `claude` provider gets
|
|
10
|
+
* the dep written into its package.json and installed.
|
|
11
|
+
*
|
|
12
|
+
* Converge-to-config, same as every other workspace op: declared already =
|
|
13
|
+
* zero-mutation no-op (a consumer-chosen spec is never overwritten), dry run
|
|
14
|
+
* plans without writing, translation off or provider `chatgpt` = untouched.
|
|
15
|
+
* Disabling translation never REMOVES the dep (#168: uninstalling on a config
|
|
16
|
+
* flip is riskier than leaving it), and devkit's loud missing-SDK error stays
|
|
17
|
+
* the backstop for hand-managed brands.
|
|
18
|
+
*/
|
|
19
|
+
const path = require('node:path');
|
|
20
|
+
const chalk = require('chalk').default;
|
|
21
|
+
const jetpack = require('fs-jetpack');
|
|
22
|
+
|
|
23
|
+
const { loadConfig } = require('../../../vendor/config/index.js');
|
|
24
|
+
const { resolveTranslationSettings } = require('../../../vendor/devkit/translate/index.js');
|
|
25
|
+
const { runCommand } = require('../../../lib/run-command.js');
|
|
26
|
+
const { dryRunPlan } = require('../../../lib/run-gates.js');
|
|
27
|
+
|
|
28
|
+
const SDK = '@anthropic-ai/claude-agent-sdk';
|
|
29
|
+
|
|
30
|
+
// Bootstrap range for a brand whose @omega.js/web isn't installed yet (a fresh
|
|
31
|
+
// clone's first manage). The authoritative copy is web's own optional peer
|
|
32
|
+
// (packages/web/package.json `peerDependencies`), read off the INSTALLED web
|
|
33
|
+
// package whenever it resolves, so the range always matches that version.
|
|
34
|
+
const FALLBACK_RANGE = '>=0.2';
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* The SDK range `@omega.js/web` declares as its optional peer, read from the
|
|
38
|
+
* target's installed copy via the node_modules climb (a manual walk, not
|
|
39
|
+
* require.resolve, because web's exports map doesn't expose its package.json).
|
|
40
|
+
*
|
|
41
|
+
* @param {string} targetPath - Absolute target root
|
|
42
|
+
* @returns {string} The declared peer range, or FALLBACK_RANGE when web isn't installed
|
|
43
|
+
*/
|
|
44
|
+
function sdkRange(targetPath) {
|
|
45
|
+
let dir = path.resolve(targetPath);
|
|
46
|
+
|
|
47
|
+
while (true) {
|
|
48
|
+
const pkg = jetpack.read(path.join(dir, 'node_modules', '@omega.js', 'web', 'package.json'), 'json');
|
|
49
|
+
const range = pkg?.peerDependencies?.[SDK];
|
|
50
|
+
if (range) return range;
|
|
51
|
+
|
|
52
|
+
const parent = path.dirname(dir);
|
|
53
|
+
if (parent === dir) return FALLBACK_RANGE;
|
|
54
|
+
dir = parent;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Does this target's resolved config ask for the claude translation provider?
|
|
60
|
+
* devkit's resolver is the SSOT for the section's defaults (absent `enabled`
|
|
61
|
+
* is on, an absent `providers` block is claude, no languages is off).
|
|
62
|
+
*
|
|
63
|
+
* @param {object} entry - Discovered target dir ({ path, target, ... })
|
|
64
|
+
* @returns {boolean}
|
|
65
|
+
*/
|
|
66
|
+
function wantsClaudeTranslation(entry) {
|
|
67
|
+
const { config } = loadConfig(entry.path, entry.target);
|
|
68
|
+
const settings = resolveTranslationSettings(config);
|
|
69
|
+
|
|
70
|
+
return settings.enabled && settings.provider === 'claude';
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
module.exports = async ({ brandRoot, targets, options = {}, runCommand: run = runCommand }) => {
|
|
74
|
+
const drifted = [];
|
|
75
|
+
const findings = [];
|
|
76
|
+
|
|
77
|
+
for (const entry of targets.filter((item) => item.target === 'web')) {
|
|
78
|
+
let wanted;
|
|
79
|
+
try {
|
|
80
|
+
wanted = wantsClaudeTranslation(entry);
|
|
81
|
+
} catch (error) {
|
|
82
|
+
// An unreadable translation section (an unknown language code, say) is an
|
|
83
|
+
// TARGET-level finding, so it warns and leaves that target alone rather than
|
|
84
|
+
// halting the whole manage walk (the sibling convention stated in
|
|
85
|
+
// ensure/config.js). The web target's own translate run is the hard gate.
|
|
86
|
+
const finding = `${entry.name}: ${error.message}`;
|
|
87
|
+
console.log(` ${chalk.yellow('⚠')} ${finding}`);
|
|
88
|
+
findings.push(finding);
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (!wanted) continue;
|
|
93
|
+
|
|
94
|
+
const pkgPath = path.join(entry.path, 'package.json');
|
|
95
|
+
const pkg = jetpack.read(pkgPath, 'json');
|
|
96
|
+
if (!pkg) {
|
|
97
|
+
console.log(` ${chalk.dim(`⊘ ${entry.name}: no package.json yet`)}`);
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (pkg.dependencies?.[SDK] || pkg.devDependencies?.[SDK]) continue;
|
|
102
|
+
|
|
103
|
+
drifted.push({ entry, pkgPath, pkg, range: sdkRange(entry.path) });
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Any finding warns the operation, whatever the drift work on the readable
|
|
107
|
+
// targets returned
|
|
108
|
+
const withFindings = (result) => (findings.length === 0
|
|
109
|
+
? result
|
|
110
|
+
: { ...result, status: 'warned', reason: result?.reason || findings.join('; '), output: { ...result?.output, findings } });
|
|
111
|
+
|
|
112
|
+
if (drifted.length === 0) {
|
|
113
|
+
if (findings.length === 0) console.log(` ${chalk.green('✓')} Translation SDK converged`);
|
|
114
|
+
return withFindings(null);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const summary = drifted.map(({ entry, range }) => `${entry.name}: ${SDK}@${range}`).join(', ');
|
|
118
|
+
|
|
119
|
+
if (options.dryRun) {
|
|
120
|
+
return withFindings(dryRunPlan(
|
|
121
|
+
`add the translation SDK (${summary}) and run npm install`,
|
|
122
|
+
{ output: { translationSdk: 'planned' } },
|
|
123
|
+
));
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
for (const { entry, pkgPath, pkg, range } of drifted) {
|
|
127
|
+
pkg.dependencies = { ...pkg.dependencies, [SDK]: range };
|
|
128
|
+
jetpack.write(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`);
|
|
129
|
+
console.log(` ${chalk.green('✓')} ${entry.name}: added ${SDK}@${range} (translation.providers.claude)`);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// One install at the brand root, since npm workspaces cover every target (the
|
|
133
|
+
// same shape the update service's install phase uses)
|
|
134
|
+
console.log(` ${chalk.dim('→')} npm install ${chalk.dim(`(${SDK})`)}`);
|
|
135
|
+
const result = await run('npm', ['install', '--no-audit', '--no-fund'], brandRoot);
|
|
136
|
+
|
|
137
|
+
const added = drifted.map(({ entry }) => entry.name);
|
|
138
|
+
|
|
139
|
+
if (!result.success) {
|
|
140
|
+
console.log(` ${chalk.yellow('⚠')} npm install failed (${result.error}); the dep is declared, so install it by hand`);
|
|
141
|
+
return withFindings({ status: 'warned', reason: 'npm install failed — install the SDK by hand', output: { translationSdk: { added, installed: false, error: result.error } } });
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return withFindings({ output: { translationSdk: { added, installed: true } } });
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
// Exported for the drift-pin test: the bootstrap range must track web's peer
|
|
148
|
+
module.exports.FALLBACK_RANGE = FALLBACK_RANGE;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reconcile the brand root's composed CI workflows (#636) — the ratified
|
|
3
|
+
* example of a dropped config key becoming a real removal: take
|
|
4
|
+
* `targets.extension` out of omega.json5 and the `extension-*.yml` files a
|
|
5
|
+
* previous manage composed at the brand root are DELETED on the next walk.
|
|
6
|
+
*
|
|
7
|
+
* The compose itself stays where it is, in each framework's own scaffold
|
|
8
|
+
* (`@omega.js/devkit/ci-workflows`), which is per-target by construction — and
|
|
9
|
+
* a dropped target's framework never runs again, so nothing there could ever
|
|
10
|
+
* clean up after it. The full enabled-target set is knowable in exactly one
|
|
11
|
+
* place, HERE: the workspace service already owns the brand root's own files
|
|
12
|
+
* and runs first in every walk, boot lane included.
|
|
13
|
+
*
|
|
14
|
+
* LIVE means the config still enables it, not that the dir is still on disk:
|
|
15
|
+
* removing `targets/<dir>` wholesale is deliberately out of scope (the dir
|
|
16
|
+
* mixes human app code), so the dir outlives the key and only the generated
|
|
17
|
+
* files go. Custom targets (`type: 'custom'`) are live whenever declared —
|
|
18
|
+
* they have no framework, so they compose nothing anyway.
|
|
19
|
+
*
|
|
20
|
+
* The deletion's own safety is devkit's double lock (the GENERATED header plus
|
|
21
|
+
* the composed naming): the brand's own hand-written workflows live in that
|
|
22
|
+
* same dir and are never candidates.
|
|
23
|
+
*/
|
|
24
|
+
const chalk = require('chalk').default;
|
|
25
|
+
|
|
26
|
+
const { reconcileComposedWorkflows } = require('../../../vendor/devkit/ci-workflows.js');
|
|
27
|
+
|
|
28
|
+
module.exports = async ({ brandRoot, brand, targets, options }) => {
|
|
29
|
+
const dryRun = options?.dryRun || false;
|
|
30
|
+
|
|
31
|
+
const liveTargets = targets
|
|
32
|
+
.filter((entry) => entry.custom || (entry.target && brand.enabledTargets.includes(entry.target)))
|
|
33
|
+
.map((entry) => entry.name);
|
|
34
|
+
|
|
35
|
+
const { removed } = reconcileComposedWorkflows({
|
|
36
|
+
brandRoot,
|
|
37
|
+
liveTargets,
|
|
38
|
+
dryRun,
|
|
39
|
+
logger: { log: () => {}, warn: () => {} },
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
if (removed.length === 0) {
|
|
43
|
+
console.log(` ${chalk.green('✓')} Composed workflows match the enabled targets`);
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (dryRun) {
|
|
48
|
+
console.log(` ${chalk.yellow('[DRY RUN]')} Would remove ${chalk.cyan(removed.length)} composed workflow(s) for dropped targets: ${removed.join(', ')}`);
|
|
49
|
+
return { output: { workflows: { planned: removed.length } } };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
console.log(` ${chalk.yellow('↺')} Removed ${chalk.bold(removed.length)} composed workflow(s) for dropped targets ${chalk.dim(`(${removed.join(', ')})`)}`);
|
|
53
|
+
return { output: { workflows: { removed: removed.length } } };
|
|
54
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workspace service — the brand monorepo itself is the first thing the
|
|
3
|
+
* manager reconciles: root workspaces wiring, omega.json5 health, and the
|
|
4
|
+
* .omega/ gitignore entry. Everything downstream assumes a sane workspace.
|
|
5
|
+
*/
|
|
6
|
+
const { createServiceRunner } = require('../../lib/service-runner.js');
|
|
7
|
+
|
|
8
|
+
module.exports.run = createServiceRunner({ serviceDir: __dirname });
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema resolution engine — extracted verbatim from @omega.js/backend's
|
|
3
|
+
* src/manager/helpers/user.js, with ONE change: the '$uuid'/'$randomId'/'$apiKey'
|
|
4
|
+
* value generators are injected via ctx.generators instead of being required
|
|
5
|
+
* in-module. Hosts that can generate them (@omega.js/backend, Node) inject real generators;
|
|
6
|
+
* hosts that can't (@omega.js/client, browser) pass none and the fields resolve to
|
|
7
|
+
* null — the doc's real values always come from the backend.
|
|
8
|
+
*
|
|
9
|
+
* The engine is environment-agnostic: no dependencies, no Node APIs.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Check if a schema node is a leaf field definition (has 'type' and 'default')
|
|
14
|
+
*/
|
|
15
|
+
function isLeaf(node) {
|
|
16
|
+
return node !== null
|
|
17
|
+
&& typeof node === 'object'
|
|
18
|
+
&& typeof node.type === 'string'
|
|
19
|
+
&& 'default' in node;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Coerce a value to the expected type. Returns the coerced value or undefined if coercion fails.
|
|
24
|
+
*/
|
|
25
|
+
function coerce(value, type) {
|
|
26
|
+
if (typeof value === type) {
|
|
27
|
+
return value;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
switch (type) {
|
|
31
|
+
case 'number': {
|
|
32
|
+
const n = Number(value);
|
|
33
|
+
return Number.isNaN(n) ? undefined : n;
|
|
34
|
+
}
|
|
35
|
+
case 'boolean': {
|
|
36
|
+
if (value === 'true' || value === 1) return true;
|
|
37
|
+
if (value === 'false' || value === 0) return false;
|
|
38
|
+
return Boolean(value);
|
|
39
|
+
}
|
|
40
|
+
case 'string': {
|
|
41
|
+
return String(value);
|
|
42
|
+
}
|
|
43
|
+
default: {
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Resolve a single leaf field value
|
|
51
|
+
*/
|
|
52
|
+
function resolveLeaf(leaf, value, ctx) {
|
|
53
|
+
// Null handling
|
|
54
|
+
if (value === null) {
|
|
55
|
+
return leaf.nullable ? null : resolveDefault(leaf.default, ctx);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Undefined → apply default
|
|
59
|
+
if (value === undefined) {
|
|
60
|
+
return resolveDefault(leaf.default, ctx);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Array type — just check it's an array, don't coerce
|
|
64
|
+
if (leaf.type === 'array') {
|
|
65
|
+
return Array.isArray(value) ? value : resolveDefault(leaf.default, ctx);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Type coercion
|
|
69
|
+
if (typeof value !== leaf.type) {
|
|
70
|
+
const coerced = coerce(value, leaf.type);
|
|
71
|
+
return coerced !== undefined ? coerced : resolveDefault(leaf.default, ctx);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return value;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Resolve a default value, handling special tokens
|
|
79
|
+
*/
|
|
80
|
+
function resolveDefault(def, ctx) {
|
|
81
|
+
if (typeof def !== 'string' || !def.startsWith('$')) {
|
|
82
|
+
// For arrays, return a fresh copy to avoid shared references
|
|
83
|
+
if (Array.isArray(def)) {
|
|
84
|
+
return [...def];
|
|
85
|
+
}
|
|
86
|
+
return def;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
switch (def) {
|
|
90
|
+
case '$uuid':
|
|
91
|
+
return ctx.generators.uuid ? ctx.generators.uuid() : null;
|
|
92
|
+
case '$randomId':
|
|
93
|
+
return ctx.generators.randomId ? ctx.generators.randomId() : null;
|
|
94
|
+
case '$apiKey':
|
|
95
|
+
return ctx.generators.apiKey ? ctx.generators.apiKey() : null;
|
|
96
|
+
case '$oldDate':
|
|
97
|
+
return ctx.oldDate;
|
|
98
|
+
case '$oldDateUNIX':
|
|
99
|
+
return ctx.oldDateUNIX;
|
|
100
|
+
case '$now':
|
|
101
|
+
return ctx.now;
|
|
102
|
+
case '$nowUNIX':
|
|
103
|
+
return ctx.nowUNIX;
|
|
104
|
+
default:
|
|
105
|
+
return def;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Expand $timestamp shorthand into a schema branch
|
|
111
|
+
*/
|
|
112
|
+
function expandTimestamp(variant) {
|
|
113
|
+
const useNow = variant === '$timestamp:now';
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
timestamp: { type: 'string', default: useNow ? '$now' : '$oldDate' },
|
|
117
|
+
timestampUNIX: { type: 'number', default: useNow ? '$nowUNIX' : 0 },
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Recursively resolve a schema node against input data
|
|
123
|
+
*/
|
|
124
|
+
function resolve(schema, data, ctx) {
|
|
125
|
+
data = data || {};
|
|
126
|
+
const result = {};
|
|
127
|
+
|
|
128
|
+
// If $passthrough, start by copying all existing keys from data
|
|
129
|
+
const isPassthrough = schema.$passthrough === true;
|
|
130
|
+
const template = schema.$template || null;
|
|
131
|
+
|
|
132
|
+
if (isPassthrough) {
|
|
133
|
+
// Copy all data keys first (they'll be overwritten by defined schema fields below)
|
|
134
|
+
for (const key of Object.keys(data)) {
|
|
135
|
+
if (template && !key.startsWith('$') && !(key in schema)) {
|
|
136
|
+
// Dynamic key — resolve against template
|
|
137
|
+
result[key] = resolve(template, data[key], ctx);
|
|
138
|
+
} else if (!(key in schema) || key.startsWith('$')) {
|
|
139
|
+
// Unknown key not in schema — passthrough as-is
|
|
140
|
+
result[key] = data[key];
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Now resolve each defined schema field
|
|
146
|
+
for (const [key, node] of Object.entries(schema)) {
|
|
147
|
+
// Skip meta keys
|
|
148
|
+
if (key.startsWith('$')) {
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Handle string shorthands
|
|
153
|
+
if (typeof node === 'string') {
|
|
154
|
+
if (node === '$template') {
|
|
155
|
+
// Resolve against parent's $template
|
|
156
|
+
result[key] = resolve(template, data[key], ctx);
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
if (node.startsWith('$timestamp')) {
|
|
160
|
+
// Expand timestamp shorthand and recurse
|
|
161
|
+
result[key] = resolve(expandTimestamp(node), data[key], ctx);
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Leaf field
|
|
167
|
+
if (isLeaf(node)) {
|
|
168
|
+
result[key] = resolveLeaf(node, data[key], ctx);
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Nested branch (plain object)
|
|
173
|
+
if (node !== null && typeof node === 'object') {
|
|
174
|
+
result[key] = resolve(node, data[key], ctx);
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return result;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
module.exports = { resolve };
|