@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,139 @@
|
|
|
1
|
+
# OMEGA — the Claude plugin
|
|
2
|
+
|
|
3
|
+
OMEGA's knowledge for Claude sessions, shipped as a Claude Code plugin from the monorepo that holds the code it describes. Install it and any session working on an OMEGA project gets the current conventions, without the knowledge living in any one developer's personal harness.
|
|
4
|
+
|
|
5
|
+
## Why it lives here
|
|
6
|
+
|
|
7
|
+
A skill kept anywhere else is a hand-maintained pointer into a repo that moves on its own schedule — nothing makes the two agree, and nothing notices when they stop. A skill that ships beside the code is version-matched by construction, and it is the same commit that changes the framework and the sentence describing it.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
In this monorepo, install is automatic: the committed `.claude/settings.json` registers the repo-root marketplace (`.claude-plugin/marketplace.json`, relative path) and enables `omega@omega` — Claude Code asks one trust question on first open, then the plugin loads every session. For any other checkout, the manual form:
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
claude plugin marketplace add <path-to-this-monorepo-checkout>
|
|
15
|
+
claude plugin install omega@omega
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Plugins load at startup, so a new (or restarted) session — or `/reload-plugins` — is what puts a change into effect. Installed plugins are cache copies; live plugin development runs `claude --plugin-dir ./agent-plugins/claude` instead.
|
|
19
|
+
|
|
20
|
+
A marketplace added from a local path is read in place — nothing is cloned, so living in a monorepo costs a local install nothing. Installing from GitHub is what makes repo size matter, and the marketplace entry switches to the `git-subdir` source for that: a url plus `"path": "agent-plugins/claude"`, which Claude Code fetches with a sparse partial clone rather than pulling the whole monorepo. Make that change when the plugin is first installed from a remote, not before — the relative `./agent-plugins/claude` source is the right one while every install is local.
|
|
21
|
+
|
|
22
|
+
## Layout
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
agent-plugins/
|
|
26
|
+
└── claude/
|
|
27
|
+
├── .claude-plugin/plugin.json the manifest
|
|
28
|
+
├── .mcp.json the one MCP declaration — the @omega.js/mcp-router endpoint
|
|
29
|
+
├── README.md this file
|
|
30
|
+
├── hooks/ hooks.json, the inject/gate/guard/shape/quality hooks, and lib/ (the shared scope guard, skill map, and gate-marker naming)
|
|
31
|
+
└── skills/ the skills, one directory each (see skills/README.md)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`agent-plugins/` is the parent for every coding agent OMEGA ships knowledge to, and `claude/` is the Claude Code one. A second provider gets a sibling directory rather than a rearrangement.
|
|
35
|
+
|
|
36
|
+
Structure is validated by `scripts/agent-plugins.test.js` at the monorepo root, which runs in `npm test`.
|
|
37
|
+
|
|
38
|
+
## The inject hook
|
|
39
|
+
|
|
40
|
+
The plugin carries the mechanism that loads its own skills. `hooks/inject/run.sh` runs on every prompt (`UserPromptSubmit`), reads the project's `package.json` — the working directory's own, else the nearest one up to the git root — and asks the session to invoke the skill for the framework it finds:
|
|
41
|
+
|
|
42
|
+
| package | skill |
|
|
43
|
+
|---|---|
|
|
44
|
+
| `@omega.js/web` | `omega:web` |
|
|
45
|
+
| `@omega.js/backend` | `omega:backend` |
|
|
46
|
+
| `@omega.js/desktop` | `omega:desktop` |
|
|
47
|
+
| `@omega.js/extension` | `omega:extension` |
|
|
48
|
+
| `@omega.js/manager` | `omega:manager` |
|
|
49
|
+
| `@omega.js/client` | `omega:client` — the project's own `name` only |
|
|
50
|
+
| `omega` (the monorepo root) | `omega:main` — the project's own `name` only |
|
|
51
|
+
|
|
52
|
+
Every row also matches the manifest's own `name`, which is what covers working inside a `packages/<pkg>` directory in this monorepo. `@omega.js/client` is the exception the other way: the runtime is embedded by web, desktop, and extension, so a dependency on it says nothing about what the session is working on — only being the package asks for its skill.
|
|
53
|
+
|
|
54
|
+
**At a brand root, the nearest manifest is not the answer.** It carries `@omega.js/manager` alone, so a session at a brand root used to hear about the manager and nothing about the targets it was there to build. The hook now recognizes a brand — a directory carrying `config/omega.json5`, or one whose manifest depends on `@omega.js/manager`, found by walking up to the git root — and reads the level below it: `config/omega.json5`'s `targets` keys AND every `targets/*/package.json` (plus the `functions/package.json` a Firebase backend keeps its framework in). The whole set comes back at once: `omega:main` and `omega:manager` always, plus one `omega:<framework>` per target. A target no framework owns (`type: 'custom'`) and `mobile` (parked) map to nothing.
|
|
55
|
+
|
|
56
|
+
A brand injection also names the framework map — the brand `AGENTS.md` import line, `node_modules/@omega.js/AGENTS.md` — as required reading BEFORE the first edit, which is what the gate hook below enforces.
|
|
57
|
+
|
|
58
|
+
Each skill is asked for once per session per SKILL (a marker file under `TMPDIR`, keyed on the session id), so a target that appears mid-session still gets its own line while the skills already asked for stay quiet. The hook fails open — no `package.json`, unparseable JSON, an unreadable config, no `jq`, and it exits silently without touching the prompt. Behavior is covered by the inject cases in `scripts/agent-plugins.test.js`, which run the script directly against fixture projects.
|
|
59
|
+
|
|
60
|
+
## The gate hook
|
|
61
|
+
|
|
62
|
+
Injecting a line only SUGGESTS a skill, and a session that skipped the line built a whole `targets/website` app without ever loading `omega:web` — hand-rolled markup, and a documented validator rule filed as a framework bug. So the skills are enforced. `hooks/gate/run.sh` serves two events from one script — the surface question has ONE answer — and refuses a write to a surface whose skill was never invoked:
|
|
63
|
+
|
|
64
|
+
| Surface written or edited | Gated on |
|
|
65
|
+
|---|---|
|
|
66
|
+
| `<brand>/targets/<t>/**` | that target's framework skill, read from its own `package.json` (a custom target gates on nothing) |
|
|
67
|
+
| `<brand>/config/omega.json5` | `omega:manager` — the file the manage walk reconciles |
|
|
68
|
+
| `<monorepo>/packages/<pkg>/**`, where the manifest IS `@omega.js/<pkg>` | that package's skill: `omega:web`, `omega:backend`, `omega:desktop`, `omega:extension`, `omega:client`, `omega:manager` |
|
|
69
|
+
| a WEB theme surface, on top of the row above: the packaged `themes/**`, a website target's `themes/**` or `src/themes/**`, its `src/_sections/**` and `src/_components/**` (one override lane), and its `src/assets/css/main.scss` | `omega:theme` IN ADDITION to that surface's own skill — the cascade has its own contract, and it is a web mechanism, so a `themes/` dir in a backend target is not one |
|
|
70
|
+
|
|
71
|
+
A surface can therefore answer with MORE than one skill, and the gate refuses until EVERY one of them has been invoked — a half-loaded theme edit is refused naming only what is still missing. The inject hook wires none of this: it answers "what does this PROJECT run?" from manifest deps and config target keys, never from a path, so a skill that fires on a surface rather than a package has nothing to add there.
|
|
72
|
+
|
|
73
|
+
Everything else is free: docs, scripts, the plugin's own files, a brand's root files, a `packages/` directory in somebody else's repo, and every internal package with no skill (`devkit`, `config`, `account`, `analytics`, `monitoring`, `template-kit`, `mcp-router`). Read-only tools are never in scope — the matcher is `Write|Edit`, so reading the code before loading the skill is exactly right.
|
|
74
|
+
|
|
75
|
+
On `PostToolUse` (matcher `Skill`) the hook records every skill the session invoked, in either spelling — the namespaced `omega:web` or the bare `web` the plugin namespaces. On `PreToolUse` (`Write|Edit`) an unrecorded surface exits 2 with the skill to invoke, so the model is told what to do rather than what it did wrong. Markers live under `TMPDIR/omega-gate`, keyed on the session id.
|
|
76
|
+
|
|
77
|
+
**Two lanes record the read, and only two.** In the main chat the agent has a Skill tool, so invoking `omega:web` records itself and nothing else is needed. An agent with NO Skill tool (the workkit worker class writes its files through Bash, which a `Write|Edit` matcher never sees) reads the guide its brief names, then runs the ONE sanctioned command: `hooks/gate/mark.sh omega:web` (either spelling the Skill event takes, `omega:web` or bare `web`), which writes the same marker through the same lib (`hooks/lib/omega-gate.sh`) and prints the path it wrote. The script lives at `agent-plugins/claude/hooks/gate/mark.sh` in this monorepo and at `node_modules/@omega.js/manager/claude-plugin/hooks/gate/mark.sh` in a brand on a published install. It takes the session id from `--session <id>` when given (explicit beats ambient), else from `$CLAUDE_SESSION_ID`, else `$CLAUDE_CODE_SESSION_ID`; with none it exits 1 with its usage. Writing a marker by hand, or running `mark.sh` before reading the guide, is a process breach rather than a third lane: the gate is a reading contract, not a lock to pick, and the verifier checks that the worker's report names the guide it read. The gate itself stays a MAIN-CHAT guard on purpose: it does not try to match the paths a heredoc, `sed`, or a python one-liner targets, because best-effort path parsing misses more than it catches ([#760](https://github.com/Omega-JS-Stack/omega/issues/760)).
|
|
78
|
+
|
|
79
|
+
The gate and the inject hook read ONE table: `hooks/lib/omega-skills.sh`, which owns the framework → skill map, the brand walk, the JSON5 target-key scan, and the surface lookup — so the hook that ASKS for a skill and the hook that REFUSES an edit without it agree on the map itself. They can still ask different questions of it: inject reads the config's target keys too, while the gate resolves a target from its own manifest alone, so a target declared in `omega.json5` before its directory exists is asked for and not gated. That is fail-open by design — the gate refuses only what it can positively identify. Fail-open throughout: no `jq`, an unreadable manifest or config, an unusable marker directory, and the gate lets the write through. Covered by the gate cases in `scripts/agent-plugins.test.js`.
|
|
80
|
+
|
|
81
|
+
## The guard hook
|
|
82
|
+
|
|
83
|
+
The gate makes a session READ the framework docs; the guard makes it act on them. `hooks/guard/run.sh` runs on `PreToolUse` (`Write|Edit`) beside the gate and refuses an edit to a framework-owned file inside a CONSUMER BRAND — the upstream-first rule as a mechanism, because "a framework hole gets a framework issue, never a consumer patch" had to be restated three times in one migration session before the hand-written rules and templates stopped landing ([#452](https://github.com/Omega-JS-Stack/omega/issues/452)). Two classes:
|
|
84
|
+
|
|
85
|
+
| Class | What it catches | Escape |
|
|
86
|
+
|---|---|---|
|
|
87
|
+
| 1. Generated or vendored | any path under `node_modules/`, any `dist/` tree, a file whose first 20 lines say `GENERATED FILE` + `DO NOT EDIT` or `Generated by @omega.js/`, and `database.rules.json` (the OMEGA-managed rules block) | none — the message names the real source to edit instead (the config, the build source, the brand's own `firestore.rules`) |
|
|
88
|
+
| 2. Shadow copies | a brand file whose path mirrors a file the installed framework ships through its OVERRIDE LAYER | `omega:consumer-override: <reason>` in the file's first 5 lines, in any comment syntax (`//`, `#`, `<!--`, `{#`, `/*`), or `OMEGA_CONSUMER_OVERRIDE=1` for the session |
|
|
89
|
+
|
|
90
|
+
The shadow map is read from the LIVE install (`<brand>/node_modules/@omega.js/<framework>/`), never a hardcoded list, so the knowledge matches the version the brand actually runs. ONE table in the hook holds the lookup roots — `<framework>|<consumer prefix, relative to the target root>|<framework root>`, one row per real override-layer root:
|
|
91
|
+
|
|
92
|
+
| Framework | Consumer prefix | Framework roots |
|
|
93
|
+
|---|---|---|
|
|
94
|
+
| `web` | `src/_layouts/` | `core/_layouts/`, `themes/*/_layouts/` |
|
|
95
|
+
| `web` | `src/_includes/` | `core/_includes/`, `themes/*/_includes/` |
|
|
96
|
+
| `web` | `src/_sections/` | `themes/*/_sections/` |
|
|
97
|
+
| `web` | `src/_components/` | `themes/*/_components/` |
|
|
98
|
+
| `web` | `src/assets/css/` | `core/css/`, `themes/*/css/` |
|
|
99
|
+
| `backend` | `src/routes/` | `src/manager/routes/` |
|
|
100
|
+
| `backend` | `src/schemas/` | `src/manager/schemas/` |
|
|
101
|
+
| `backend` | (the target root) | `templates/` |
|
|
102
|
+
|
|
103
|
+
The web rows mirror `packages/web/src/overrides.js` `overrideLanes()` (sections, includes, css) plus the engine's layered `_layouts`: the MECHANISM lanes, where first-layer-wins resolution means a consumer file genuinely takes the framework's place. Sections sit in the theme layers only, because core ships none. The backend rows are the two lanes that really replace a framework file BY NAME — `packages/backend/src/manager/index.js` resolves a consumer route or schema of the same name and method over the framework's — plus the framework half of the rules that ships in `templates/`.
|
|
104
|
+
|
|
105
|
+
**Pages are never guarded.** `src/pages/` is CONTENT: the designed place for a brand to write its own homepage, about page and pricing page, whether or not the framework ships a default of that name. There is no `defaults/` row and no page row. **There is no js row either**, because page and layout modules are a UNION ([#624](https://github.com/Omega-JS-Stack/omega/issues/624) — every layer's file runs, in layer order) rather than a shadow, so a brand's `src/assets/js/pages/blog.js` replaces nothing.
|
|
106
|
+
|
|
107
|
+
Two exemption sets, both by name and both traceable to a document:
|
|
108
|
+
|
|
109
|
+
- **The consumer's own entry files**, which the docs hand to the brand outright: `src/assets/css/main.scss` ([docs/shared/theming.md](../../docs/shared/theming.md) § Consumer customization, tier 1), plus `src/assets/js/main.js` and `src/assets/js/first-paint.js` ([docs/web/index.md](../../docs/web/index.md) — the one REPLACE-with-extend lane, where a consumer file reaches the framework's through `omega:main`). Owning one of those IS the documented recipe, so the guard never asks about it.
|
|
110
|
+
- **The backend seeds** the target checks (`omega test`) write once and the brand owns from then on, each healed by a check in `@omega.js/backend`'s `src/cli/commands/setup-tests/`: `firestore.rules`, `storage.rules`, `firebase.json`, `firestore.indexes.json`, `remoteconfig.template.json`, `public/`, `config/`, and `storage-lifecycle-*.json`.
|
|
111
|
+
|
|
112
|
+
**Desktop and extension have no rows at all**, and that is a finding rather than an omission: neither framework ships an override layer. Their `src/defaults/` tree is scaffolded ONCE and the brand owns every file in it afterwards — `src/main.js`, `gulpfile.js`, `hooks/build/pre.js` are yours by design — so there is nothing there for a brand file to shadow.
|
|
113
|
+
|
|
114
|
+
`omega customize` closes the loop from the other side: materializing a file writes the `omega:consumer-override:` marker into its own provenance header (`packages/web/src/overrides.js` `provenanceHeader()`), so the sanctioned way to take a copy produces a file the guard already accepts.
|
|
115
|
+
|
|
116
|
+
The monorepo itself is exempt — `packages/` is the framework's own source and `brands/` are the crew's fixtures — found by walking to the git root for a manifest named `omega` beside a `packages/` directory, which is what keeps a brand fixture from answering first. Everything else fails open: no `jq`, no brand root, no framework in the target's manifest, no install to read, and the write goes through. Covered by the guard cases in `scripts/agent-plugins.test.js`.
|
|
117
|
+
|
|
118
|
+
## The quality hook
|
|
119
|
+
|
|
120
|
+
The four quality skills do not wait to be remembered. `hooks/quality/run.sh` serves two events from one script — so the surface table has one home — and fires them off the files a session actually edits:
|
|
121
|
+
|
|
122
|
+
| Surface written or edited | Skills asked for |
|
|
123
|
+
|---|---|
|
|
124
|
+
| a page (`*/pages/*.html`, `*/pages/*.md`), a layout, a `.liquid` template | `omega:seo`, `omega:accessibility` |
|
|
125
|
+
| the core head/foot chrome | `omega:seo`, `omega:accessibility` |
|
|
126
|
+
| an include, section, or component partial; page/core JS | `omega:accessibility` |
|
|
127
|
+
| `.scss` / `.css` | `omega:accessibility`, `omega:brandcheck` |
|
|
128
|
+
| `omega.json5`, section data JSON, a section schema | `omega:brandcheck` |
|
|
129
|
+
| a web flow page or auth module (`*/core/js/pages/*`, `*/core/js/libs/auth/*`) | `omega:analytics` (plus `omega:accessibility` from the core-JS row) |
|
|
130
|
+
| a backend payment route, payments-webhook or auth event | `omega:analytics` |
|
|
131
|
+
| the analytics package itself (`*/packages/analytics/*`) | `omega:analytics` |
|
|
132
|
+
|
|
133
|
+
On `PostToolUse` (Write|Edit) a match names its skills once per session per skill and records the file. On `Stop` the recorded list comes back as a block: the surfaces edited this session, the checklists they owe, and a refusal to sign off on an unreviewed pass. The block runs once per batch of edits (the list clears, so a later edit re-arms it) and never inside its own turn (`stop_hook_active`). Same scope guard as the shape hook, literally: both source `hooks/lib/omega-scope.sh`, which walks up from the edited file to the nearest `package.json` (stopping at the git root) and answers whether that project is or depends on `@omega.js/*`. The inject hook asks a different question — a project from a cwd, with its `functions/` manifest joined in — and keeps its own walk. Fail-open throughout. Covered by the quality cases in `scripts/agent-plugins.test.js`.
|
|
134
|
+
|
|
135
|
+
## What is here, and what is not built yet
|
|
136
|
+
|
|
137
|
+
Thirteen skills — `main` (the hub: the package roster, the docs topology, the brand map, where project state lives), one router per package a session works in (`web`, `backend`, `desktop`, `extension`, `client`, `manager`), `browser` (driving the MCP router's Chrome upstreams), the four quality checklists (`seo`, `accessibility`, `brandcheck`, `analytics`) the quality hook fires on the surfaces they own, and `theme` (the cascade's own checklist), which the GATE fires on the theme surfaces in the table above rather than the quality hook. Each one names where the knowledge lives, in the monorepo and in a consumer project, and carries only the handful of rules a session needs before it knows which document to open. One thing is still open.
|
|
138
|
+
|
|
139
|
+
**The staleness mechanism.** This is the point of the move, not a bonus. Whatever ships needs something that fails when a skill names an export, a path, a config key, or a CLI command the code no longer has. A test in this repo is the strongest form; a generated section is next; a review trigger tied to a release is the floor. A plugin that goes stale quietly has only relocated the problem.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# omega:gate mark — the ONE sanctioned way for an agent with NO Skill tool (the
|
|
3
|
+
# worker class writes its files through Bash) to record that it read the guide
|
|
4
|
+
# a skill routes to. It writes exactly the marker the hook's PostToolUse half
|
|
5
|
+
# writes, through the same lib, so the two lanes cannot drift.
|
|
6
|
+
# The main chat never needs this: invoking the skill records itself.
|
|
7
|
+
# Writing a marker by hand, or running this before reading the guide, is a
|
|
8
|
+
# process breach — the gate is a reading contract, not a lock to pick.
|
|
9
|
+
#
|
|
10
|
+
# Usage: mark.sh <skill> [--session <id>]
|
|
11
|
+
# The session id is --session when given (explicit beats ambient), else
|
|
12
|
+
# $CLAUDE_SESSION_ID, else $CLAUDE_CODE_SESSION_ID. The skill takes either
|
|
13
|
+
# spelling the Skill event takes (omega:web or bare web). Prints the marker
|
|
14
|
+
# path it wrote.
|
|
15
|
+
|
|
16
|
+
set -euo pipefail
|
|
17
|
+
|
|
18
|
+
usage() {
|
|
19
|
+
echo "usage: mark.sh <skill> [--session <id>] (e.g. mark.sh omega:web)" >&2
|
|
20
|
+
exit 1
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
skill=""
|
|
24
|
+
session="${CLAUDE_SESSION_ID:-${CLAUDE_CODE_SESSION_ID:-}}"
|
|
25
|
+
|
|
26
|
+
while [ $# -gt 0 ]; do
|
|
27
|
+
case "$1" in
|
|
28
|
+
--session)
|
|
29
|
+
[ $# -ge 2 ] || usage
|
|
30
|
+
session="$2"
|
|
31
|
+
shift 2
|
|
32
|
+
;;
|
|
33
|
+
-*) usage ;;
|
|
34
|
+
*)
|
|
35
|
+
[ -z "$skill" ] || usage
|
|
36
|
+
skill="$1"
|
|
37
|
+
shift
|
|
38
|
+
;;
|
|
39
|
+
esac
|
|
40
|
+
done
|
|
41
|
+
|
|
42
|
+
[ -n "$skill" ] || usage
|
|
43
|
+
[ -n "$session" ] || usage
|
|
44
|
+
|
|
45
|
+
# The PostToolUse half records a bare name as its namespaced form; the same
|
|
46
|
+
# spelling has to unlock the same surface here.
|
|
47
|
+
case "$skill" in
|
|
48
|
+
omega:*) ;;
|
|
49
|
+
*) skill="omega:$skill" ;;
|
|
50
|
+
esac
|
|
51
|
+
|
|
52
|
+
# shellcheck source-path=SCRIPTDIR source=../lib/omega-gate.sh
|
|
53
|
+
. "$(dirname "${BASH_SOURCE[0]}")/../lib/omega-gate.sh"
|
|
54
|
+
|
|
55
|
+
marker=$(omega_gate_marker "$session" "$skill")
|
|
56
|
+
mkdir -p "$(omega_gate_state_dir)"
|
|
57
|
+
: > "$marker"
|
|
58
|
+
echo "$marker"
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# omega:gate — PreToolUse (Write|Edit) + PostToolUse (Skill) hook
|
|
3
|
+
# The enforcement half of the inject hook: injecting a line only SUGGESTS the
|
|
4
|
+
# skill, and a session that skipped the line built a whole website target
|
|
5
|
+
# without ever reading the docs. So the surfaces a skill owns are refused until
|
|
6
|
+
# that skill was actually invoked — a target's tree, a brand's config/omega.json5,
|
|
7
|
+
# and a monorepo package that has a skill. Read-only tools are never in scope
|
|
8
|
+
# (the matcher is Write|Edit), and every other path stays free.
|
|
9
|
+
# One script for both events so the surface question has ONE answer; the event
|
|
10
|
+
# comes off hook_event_name. Fails open on anything unexpected.
|
|
11
|
+
|
|
12
|
+
set -euo pipefail
|
|
13
|
+
|
|
14
|
+
input=$(cat)
|
|
15
|
+
|
|
16
|
+
command -v jq >/dev/null 2>&1 || exit 0
|
|
17
|
+
|
|
18
|
+
event=$(jq -r '.hook_event_name // ""' <<<"$input" 2>/dev/null || true)
|
|
19
|
+
session_id=$(jq -r '.session_id // ""' <<<"$input" 2>/dev/null || true)
|
|
20
|
+
|
|
21
|
+
# The marker naming is shared with mark.sh, the sanctioned command for an agent
|
|
22
|
+
# with no Skill tool: one lib, so the two writers cannot drift apart.
|
|
23
|
+
gate_lib="$(dirname "${BASH_SOURCE[0]}")/../lib/omega-gate.sh"
|
|
24
|
+
[ -r "$gate_lib" ] || exit 0
|
|
25
|
+
# shellcheck source-path=SCRIPTDIR source=../lib/omega-gate.sh
|
|
26
|
+
. "$gate_lib"
|
|
27
|
+
|
|
28
|
+
state_dir=$(omega_gate_state_dir)
|
|
29
|
+
|
|
30
|
+
marker_for() {
|
|
31
|
+
omega_gate_marker "$session_id" "$1"
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
# --- PostToolUse (Skill): the record --------------------------------------
|
|
35
|
+
# The Skill tool's input names the skill it ran; the spelling is the tool's
|
|
36
|
+
# business, so both the namespaced form (omega:web) and the bare skill name
|
|
37
|
+
# (web, which the plugin namespaces) count as the same invocation.
|
|
38
|
+
if [ "$event" = "PostToolUse" ]; then
|
|
39
|
+
mkdir -p "$state_dir" 2>/dev/null || true
|
|
40
|
+
values=$(jq -r '[.tool_input // {} | .. | strings] | .[]' <<<"$input" 2>/dev/null || true)
|
|
41
|
+
|
|
42
|
+
# The brace group is what makes the failure silent: redirections apply left to
|
|
43
|
+
# right, so a bare `: > file 2>/dev/null` still prints its own failure.
|
|
44
|
+
while read -r skill; do
|
|
45
|
+
[ -n "$skill" ] || continue
|
|
46
|
+
{ : > "$(marker_for "$skill")"; } 2>/dev/null || true
|
|
47
|
+
done < <(grep -oE 'omega:[a-z][a-z-]*' <<<"$values" 2>/dev/null || true)
|
|
48
|
+
|
|
49
|
+
while read -r name; do
|
|
50
|
+
[ -n "$name" ] || continue
|
|
51
|
+
{ : > "$(marker_for "omega:$name")"; } 2>/dev/null || true
|
|
52
|
+
done < <(grep -xE '[a-z][a-z-]*' <<<"$values" 2>/dev/null || true)
|
|
53
|
+
|
|
54
|
+
exit 0
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
# --- PreToolUse (Write|Edit): the refusal ---------------------------------
|
|
58
|
+
file_path=$(jq -r '.tool_input.file_path // ""' <<<"$input" 2>/dev/null || true)
|
|
59
|
+
[ -n "$file_path" ] || exit 0
|
|
60
|
+
|
|
61
|
+
skills_lib="$(dirname "${BASH_SOURCE[0]}")/../lib/omega-skills.sh"
|
|
62
|
+
[ -r "$skills_lib" ] || exit 0
|
|
63
|
+
# shellcheck source-path=SCRIPTDIR source=../lib/omega-skills.sh
|
|
64
|
+
. "$skills_lib"
|
|
65
|
+
|
|
66
|
+
# A surface can answer with MORE than one skill — a theme surface owns its
|
|
67
|
+
# framework's skill and omega:theme both — so the answer is read line by line
|
|
68
|
+
# and every skill has to have been invoked before the write goes through.
|
|
69
|
+
skills=$(omega_skill_for_file "$file_path")
|
|
70
|
+
[ -n "$skills" ] || exit 0
|
|
71
|
+
|
|
72
|
+
# No usable state dir means the record half could never have written a marker,
|
|
73
|
+
# so every write would refuse forever. Fail open instead of deadlocking.
|
|
74
|
+
mkdir -p "$state_dir" 2>/dev/null || true
|
|
75
|
+
{ [ -d "$state_dir" ] && [ -w "$state_dir" ]; } || exit 0
|
|
76
|
+
|
|
77
|
+
missing=()
|
|
78
|
+
while read -r skill; do
|
|
79
|
+
[ -n "$skill" ] || continue
|
|
80
|
+
[ -f "$(marker_for "$skill")" ] && continue
|
|
81
|
+
missing+=("$skill")
|
|
82
|
+
done <<<"$skills"
|
|
83
|
+
|
|
84
|
+
[ "${#missing[@]}" -gt 0 ] || exit 0
|
|
85
|
+
|
|
86
|
+
skill=$(printf ', %s' "${missing[@]}")
|
|
87
|
+
skill="${skill:2}"
|
|
88
|
+
|
|
89
|
+
cat >&2 <<EOF
|
|
90
|
+
omega:gate — $skill has not been loaded, and owns this surface: $file_path
|
|
91
|
+
Invoke $skill via the Skill tool, read the framework map it routes to
|
|
92
|
+
(the brand's AGENTS.md import line, node_modules/@omega.js/AGENTS.md), and
|
|
93
|
+
then make this edit. The framework has conventions for this surface — pages,
|
|
94
|
+
sections, config keys, routes — and hand-rolling it is the failure this gate
|
|
95
|
+
exists to stop. Reading tools are free; this refusal only covers writes.
|
|
96
|
+
EOF
|
|
97
|
+
exit 2
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# omega:guard — PreToolUse (Write|Edit) hook
|
|
3
|
+
# The upstream-first boundary ([#452](https://github.com/Omega-JS-Stack/omega/issues/452)):
|
|
4
|
+
# inside a CONSUMER BRAND, an edit to a framework-owned file is refused, because
|
|
5
|
+
# a framework hole filled with a brand patch is a hole every later brand digs
|
|
6
|
+
# again. Two classes, treated differently:
|
|
7
|
+
# 1. generated or vendored (node_modules, dist, a generated header, the
|
|
8
|
+
# OMEGA-managed database.rules.json) — hard refusal, no escape hatch; the
|
|
9
|
+
# message names the real source to edit.
|
|
10
|
+
# 2. shadow copies — a brand file whose path mirrors a file the installed
|
|
11
|
+
# framework ships through its OVERRIDE LAYER, read from the live install.
|
|
12
|
+
# Refused with the upstream-first message and two exits: the in-file
|
|
13
|
+
# `omega:consumer-override:` marker, or OMEGA_CONSUMER_OVERRIDE=1.
|
|
14
|
+
# The monorepo itself is exempt — packages/ is the framework's source and
|
|
15
|
+
# brands/ are the crew's own fixtures. Fails open on anything unexpected.
|
|
16
|
+
|
|
17
|
+
set -euo pipefail
|
|
18
|
+
|
|
19
|
+
input=$(cat)
|
|
20
|
+
|
|
21
|
+
command -v jq >/dev/null 2>&1 || exit 0
|
|
22
|
+
|
|
23
|
+
file_path=$(jq -r '.tool_input.file_path // ""' <<<"$input" 2>/dev/null || true)
|
|
24
|
+
[ -n "$file_path" ] || exit 0
|
|
25
|
+
# Only a Write carries content — which is the only thing a brand-new shadow
|
|
26
|
+
# path can be judged on, since there is no file to read the marker out of yet.
|
|
27
|
+
content=$(jq -r '.tool_input.content // ""' <<<"$input" 2>/dev/null || true)
|
|
28
|
+
|
|
29
|
+
skills_lib="$(dirname "${BASH_SOURCE[0]}")/../lib/omega-skills.sh"
|
|
30
|
+
[ -r "$skills_lib" ] || exit 0
|
|
31
|
+
# shellcheck source-path=SCRIPTDIR source=../lib/omega-skills.sh
|
|
32
|
+
. "$skills_lib"
|
|
33
|
+
|
|
34
|
+
# --- scope: a consumer brand, and never this monorepo ----------------------
|
|
35
|
+
# The monorepo walk runs to the git root on its own, because a brand FIXTURE
|
|
36
|
+
# under brands/ answers the brand walk long before the monorepo root is reached.
|
|
37
|
+
in_monorepo() {
|
|
38
|
+
local dir="$1"
|
|
39
|
+
# `dirname` bottoms out at "." for a relative path and stays there forever,
|
|
40
|
+
# so an unanchored walk never terminates. Nothing to resolve, fail open.
|
|
41
|
+
case "$dir" in /*) ;; *) return 1 ;; esac
|
|
42
|
+
while [ -n "$dir" ] && [ "$dir" != "/" ]; do
|
|
43
|
+
if [ -f "$dir/package.json" ] && [ -d "$dir/packages" ] \
|
|
44
|
+
&& [ "$(jq -r '.name // ""' "$dir/package.json" 2>/dev/null || true)" = "omega" ]; then
|
|
45
|
+
return 0
|
|
46
|
+
fi
|
|
47
|
+
[ -e "$dir/.git" ] && return 1
|
|
48
|
+
dir=$(dirname "$dir")
|
|
49
|
+
done
|
|
50
|
+
return 1
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
in_monorepo "$(dirname "$file_path")" && exit 0
|
|
54
|
+
|
|
55
|
+
brand=$(omega_brand_root "$(dirname "$file_path")")
|
|
56
|
+
[ -n "$brand" ] || exit 0
|
|
57
|
+
[ -f "$brand/package.json" ] || [ -f "$brand/config/omega.json5" ] || exit 0
|
|
58
|
+
|
|
59
|
+
rel="${file_path#"$brand"/}"
|
|
60
|
+
|
|
61
|
+
refuse() {
|
|
62
|
+
cat >&2
|
|
63
|
+
exit 2
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
# --- class 1: generated or vendored, no escape hatch -----------------------
|
|
67
|
+
case "$file_path" in
|
|
68
|
+
*/node_modules/*)
|
|
69
|
+
refuse <<EOF
|
|
70
|
+
omega:guard — $rel is inside node_modules (an installed @omega.js package).
|
|
71
|
+
A dependency bug is fixed UPSTREAM: change it in the Omega monorepo and re-link
|
|
72
|
+
(\`omega i local\`), or file an issue on Omega-JS-Stack/omega. Patching an
|
|
73
|
+
install in place is erased by the next npm install and ships to nobody.
|
|
74
|
+
EOF
|
|
75
|
+
;;
|
|
76
|
+
esac
|
|
77
|
+
|
|
78
|
+
case "$rel" in
|
|
79
|
+
dist/*|*/dist/*)
|
|
80
|
+
refuse <<EOF
|
|
81
|
+
omega:guard — $rel is build output (a dist/ tree).
|
|
82
|
+
Edit the SOURCE it is built from and re-run the target's build (\`npx omega build\`).
|
|
83
|
+
A hand edit to dist/ is gone the next time the verb runs.
|
|
84
|
+
EOF
|
|
85
|
+
;;
|
|
86
|
+
esac
|
|
87
|
+
|
|
88
|
+
if [ "$(basename "$file_path")" = "database.rules.json" ]; then
|
|
89
|
+
refuse <<EOF
|
|
90
|
+
omega:guard — $rel carries the OMEGA-managed realtime-database rules block.
|
|
91
|
+
That block is generated: edit config/omega.json5 for what it reflects, and let
|
|
92
|
+
the target checks rewrite the file (\`npx omega test\` in the backend target).
|
|
93
|
+
The brand's OWN security rules source is firestore.rules, which is yours.
|
|
94
|
+
EOF
|
|
95
|
+
fi
|
|
96
|
+
|
|
97
|
+
# The header a framework writer stamps on a generated artifact. Read off the
|
|
98
|
+
# file on disk — the stamp is the artifact's own claim about itself.
|
|
99
|
+
if [ -f "$file_path" ]; then
|
|
100
|
+
header=$(head -n 20 "$file_path" 2>/dev/null || true)
|
|
101
|
+
if grep -q 'Generated by @omega\.js/' <<<"$header" \
|
|
102
|
+
|| { grep -qi 'GENERATED FILE' <<<"$header" && grep -qi 'DO NOT EDIT' <<<"$header"; }; then
|
|
103
|
+
refuse <<EOF
|
|
104
|
+
omega:guard — $rel says in its own header that it is generated.
|
|
105
|
+
Edit the source it is rendered from — config/omega.json5, or the framework
|
|
106
|
+
template behind it — and re-run the verb that wrote it. Every edit here is
|
|
107
|
+
overwritten on the next build.
|
|
108
|
+
EOF
|
|
109
|
+
fi
|
|
110
|
+
fi
|
|
111
|
+
|
|
112
|
+
# --- class 2: shadow copies of the framework's override layer --------------
|
|
113
|
+
# The target the file belongs to, and the framework that owns that target. A
|
|
114
|
+
# brand with no targets/ directory (a single-target repo) is its own target.
|
|
115
|
+
target_root="$brand"
|
|
116
|
+
case "$file_path" in
|
|
117
|
+
"$brand"/targets/*/*)
|
|
118
|
+
rest="${file_path#"$brand"/targets/}"
|
|
119
|
+
target_root="$brand/targets/${rest%%/*}"
|
|
120
|
+
;;
|
|
121
|
+
esac
|
|
122
|
+
|
|
123
|
+
framework=""
|
|
124
|
+
for manifest in "$target_root/package.json" "$target_root/functions/package.json"; do
|
|
125
|
+
[ -f "$manifest" ] || continue
|
|
126
|
+
while read -r dep; do
|
|
127
|
+
case "$dep" in
|
|
128
|
+
@omega.js/web|@omega.js/backend|@omega.js/desktop|@omega.js/extension)
|
|
129
|
+
framework="${dep#@omega.js/}"
|
|
130
|
+
break
|
|
131
|
+
;;
|
|
132
|
+
esac
|
|
133
|
+
done < <(omega_manifest_deps "$manifest")
|
|
134
|
+
[ -n "$framework" ] && break
|
|
135
|
+
done
|
|
136
|
+
[ -n "$framework" ] || exit 0
|
|
137
|
+
|
|
138
|
+
# Read from the LIVE install, never a hardcoded list — the knowledge has to
|
|
139
|
+
# match the version this brand actually runs.
|
|
140
|
+
install=""
|
|
141
|
+
for candidate in "$target_root/node_modules/@omega.js/$framework" "$brand/node_modules/@omega.js/$framework"; do
|
|
142
|
+
if [ -d "$candidate" ]; then
|
|
143
|
+
install="$candidate"
|
|
144
|
+
break
|
|
145
|
+
fi
|
|
146
|
+
done
|
|
147
|
+
[ -n "$install" ] || exit 0
|
|
148
|
+
|
|
149
|
+
rel_target="${file_path#"$target_root"/}"
|
|
150
|
+
|
|
151
|
+
# THE lookup table: `<framework>|<consumer prefix, relative to the target
|
|
152
|
+
# root>|<framework root, glob allowed>`. A brand path under the prefix is
|
|
153
|
+
# stripped of it and looked up under the framework root; a hit means the brand
|
|
154
|
+
# file SHADOWS that framework file. ONE row per real override-layer root.
|
|
155
|
+
# web the MECHANISM lanes, mirroring src/overrides.js overrideLanes()
|
|
156
|
+
# (sections, includes, css) plus the engine's layered _layouts:
|
|
157
|
+
# first-layer-wins, consumer src/ → active theme → base → core.
|
|
158
|
+
# Sections live in the theme layers only (core ships none), and the
|
|
159
|
+
# css lane is the one sass resolves by layer.
|
|
160
|
+
# NOT here, on purpose: src/pages/ is CONTENT — the designed place
|
|
161
|
+
# for a brand's own copy, so a page is never guarded — and the js
|
|
162
|
+
# lane has no row at all, because page and layout modules are a
|
|
163
|
+
# UNION ([#624](https://github.com/Omega-JS-Stack/omega/issues/624),
|
|
164
|
+
# every layer's file runs) rather than a shadow.
|
|
165
|
+
# backend the two lanes that really replace a framework file BY NAME
|
|
166
|
+
# (src/manager/index.js: a consumer route or schema of the same name
|
|
167
|
+
# and method replaces the framework's), plus the framework half of
|
|
168
|
+
# the rules that ships in templates/.
|
|
169
|
+
# desktop and extension ship NO override layer: their src/defaults/ tree is
|
|
170
|
+
# scaffolded once and the brand owns every file in it afterwards, so there is
|
|
171
|
+
# nothing there to shadow.
|
|
172
|
+
SHADOW_ROOTS="
|
|
173
|
+
web|src/_layouts/|core/_layouts/
|
|
174
|
+
web|src/_layouts/|themes/*/_layouts/
|
|
175
|
+
web|src/_includes/|core/_includes/
|
|
176
|
+
web|src/_includes/|themes/*/_includes/
|
|
177
|
+
web|src/_sections/|themes/*/_sections/
|
|
178
|
+
web|src/_components/|themes/*/_components/
|
|
179
|
+
web|src/assets/css/|core/css/
|
|
180
|
+
web|src/assets/css/|themes/*/css/
|
|
181
|
+
backend|src/routes/|src/manager/routes/
|
|
182
|
+
backend|src/schemas/|src/manager/schemas/
|
|
183
|
+
backend||templates/
|
|
184
|
+
"
|
|
185
|
+
|
|
186
|
+
# The files the DOCS name as the consumer's own entry, and the seeds a brand
|
|
187
|
+
# owns once the target checks have written them. Exempt by name, never by guesswork:
|
|
188
|
+
# web main.scss is theming.md tier 1 and main.js/first-paint.js are the
|
|
189
|
+
# same REPLACE-with-extend lane in docs/web/index.md — a consumer
|
|
190
|
+
# file there reaches the framework's through `omega:main`, which is
|
|
191
|
+
# the documented way to own it.
|
|
192
|
+
# backend every seed in templates/ the target checks write once and never again
|
|
193
|
+
# (src/cli/commands/setup-tests/ in @omega.js/backend heals each).
|
|
194
|
+
case "$framework/$rel_target" in
|
|
195
|
+
web/src/assets/css/main.scss|web/src/assets/js/main.js|web/src/assets/js/first-paint.js)
|
|
196
|
+
exit 0
|
|
197
|
+
;;
|
|
198
|
+
backend/firestore.rules|backend/storage.rules|backend/firebase.json|backend/firestore.indexes.json|backend/remoteconfig.template.json|backend/public/*|backend/config/*|backend/storage-lifecycle-*.json)
|
|
199
|
+
exit 0
|
|
200
|
+
;;
|
|
201
|
+
esac
|
|
202
|
+
|
|
203
|
+
shadow=""
|
|
204
|
+
while IFS='|' read -r fw prefix root; do
|
|
205
|
+
[ -n "$fw" ] || continue
|
|
206
|
+
[ "$fw" = "$framework" ] || continue
|
|
207
|
+
|
|
208
|
+
sub="$rel_target"
|
|
209
|
+
if [ -n "$prefix" ]; then
|
|
210
|
+
case "$sub" in
|
|
211
|
+
"$prefix"*) sub="${sub#"$prefix"}" ;;
|
|
212
|
+
*) continue ;;
|
|
213
|
+
esac
|
|
214
|
+
fi
|
|
215
|
+
[ -n "$sub" ] || continue
|
|
216
|
+
|
|
217
|
+
# $root is deliberately unquoted so a themes/*/ row expands to every theme.
|
|
218
|
+
for candidate in "$install"/$root"$sub"; do
|
|
219
|
+
if [ -f "$candidate" ]; then
|
|
220
|
+
shadow="${candidate#"$install"/}"
|
|
221
|
+
break
|
|
222
|
+
fi
|
|
223
|
+
done
|
|
224
|
+
if [ -n "$shadow" ]; then break; fi
|
|
225
|
+
done <<EOF
|
|
226
|
+
$SHADOW_ROOTS
|
|
227
|
+
EOF
|
|
228
|
+
|
|
229
|
+
[ -n "$shadow" ] || exit 0
|
|
230
|
+
|
|
231
|
+
# The exits. The env flag covers a whole session; the marker covers one file
|
|
232
|
+
# forever, and lives in the first five lines in whatever comment syntax the
|
|
233
|
+
# file speaks (//, #, <!--, {#, /*).
|
|
234
|
+
[ "${OMEGA_CONSUMER_OVERRIDE:-}" = "1" ] && exit 0
|
|
235
|
+
|
|
236
|
+
if [ -f "$file_path" ] && head -n 5 "$file_path" 2>/dev/null | grep -qF 'omega:consumer-override:'; then
|
|
237
|
+
exit 0
|
|
238
|
+
fi
|
|
239
|
+
if [ -n "$content" ] && printf '%s\n' "$content" | head -n 5 | grep -qF 'omega:consumer-override:'; then
|
|
240
|
+
exit 0
|
|
241
|
+
fi
|
|
242
|
+
|
|
243
|
+
refuse <<EOF
|
|
244
|
+
omega:guard — $rel shadows @omega.js/$framework/$shadow (framework-owned).
|
|
245
|
+
If this is a framework gap, file an issue on Omega-JS-Stack/omega instead
|
|
246
|
+
(upstream-first). If this brand genuinely needs its own copy, add
|
|
247
|
+
\`// omega:consumer-override: <reason>\` to the top of the file and retry
|
|
248
|
+
(OMEGA_CONSUMER_OVERRIDE=1 skips this check for the session).
|
|
249
|
+
EOF
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hooks": {
|
|
3
|
+
"PreToolUse": [
|
|
4
|
+
{
|
|
5
|
+
"matcher": "Write|Edit",
|
|
6
|
+
"hooks": [
|
|
7
|
+
{
|
|
8
|
+
"type": "command",
|
|
9
|
+
"command": "\"${CLAUDE_PLUGIN_ROOT}\"/hooks/shape/run.sh"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"type": "command",
|
|
13
|
+
"command": "\"${CLAUDE_PLUGIN_ROOT}\"/hooks/gate/run.sh"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"type": "command",
|
|
17
|
+
"command": "\"${CLAUDE_PLUGIN_ROOT}\"/hooks/guard/run.sh"
|
|
18
|
+
}
|
|
19
|
+
]
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"PostToolUse": [
|
|
23
|
+
{
|
|
24
|
+
"matcher": "Write|Edit",
|
|
25
|
+
"hooks": [
|
|
26
|
+
{
|
|
27
|
+
"type": "command",
|
|
28
|
+
"command": "\"${CLAUDE_PLUGIN_ROOT}\"/hooks/quality/run.sh"
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"matcher": "Skill",
|
|
34
|
+
"hooks": [
|
|
35
|
+
{
|
|
36
|
+
"type": "command",
|
|
37
|
+
"command": "\"${CLAUDE_PLUGIN_ROOT}\"/hooks/gate/run.sh"
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
],
|
|
42
|
+
"Stop": [
|
|
43
|
+
{
|
|
44
|
+
"hooks": [
|
|
45
|
+
{
|
|
46
|
+
"type": "command",
|
|
47
|
+
"command": "\"${CLAUDE_PLUGIN_ROOT}\"/hooks/quality/run.sh"
|
|
48
|
+
}
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
],
|
|
52
|
+
"UserPromptSubmit": [
|
|
53
|
+
{
|
|
54
|
+
"hooks": [
|
|
55
|
+
{
|
|
56
|
+
"type": "command",
|
|
57
|
+
"command": "\"${CLAUDE_PLUGIN_ROOT}\"/hooks/inject/run.sh"
|
|
58
|
+
}
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
}
|
|
63
|
+
}
|