@warpgogol/werkstatt-shared 0.2.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/package.json +352 -0
- package/src/checks/index.ts +24 -0
- package/src/checks/lib/astro-site-url.ts +30 -0
- package/src/checks/lib/i18n.ts +30 -0
- package/src/checks/result-helpers.ts +102 -0
- package/src/checks/suppressions-config.ts +195 -0
- package/src/index.ts +14 -0
- package/src/integration/README.md +38 -0
- package/src/integration/adapters.ts +143 -0
- package/src/integration/crm-buffer.ts +491 -0
- package/src/integration/dispatch.ts +106 -0
- package/src/integration/funnel.ts +379 -0
- package/src/integration/index.ts +56 -0
- package/src/integration/lifecycle.ts +155 -0
- package/src/integration/orchestration.ts +439 -0
- package/src/integration/port-barrel.ts +124 -0
- package/src/integration/port.ts +143 -0
- package/src/integration/qstash.ts +134 -0
- package/src/integration/sharding.ts +133 -0
- package/src/integration/tests/deliver-event.test.ts +52 -0
- package/src/integration/tests/dispatch.test.ts +88 -0
- package/src/integration/tests/funnel-bridge.test.ts +46 -0
- package/src/integration/tests/hub-runtime.test.ts +128 -0
- package/src/integration/tests/lifecycle.test.ts +69 -0
- package/src/integration/tests/qstash.test.ts +83 -0
- package/src/integration/tests/sharding.test.ts +64 -0
- package/src/integration/vitest.config.ts +8 -0
- package/src/integration-adapter-supabase-crm/adapter.ts +437 -0
- package/src/integration-adapter-supabase-crm/client.ts +605 -0
- package/src/integration-adapter-supabase-crm/index.ts +28 -0
- package/src/integration-adapter-supabase-crm/pipedrive-sync-target.ts +482 -0
- package/src/integration-adapter-supabase-crm/supabase-rest.ts +89 -0
- package/src/integration-adapter-supabase-crm/tenant-registry.ts +334 -0
- package/src/integration-adapter-supabase-crm/tests/change-balance.pbt.test.ts +83 -0
- package/src/integration-adapter-supabase-crm/tests/funnel-persistence.test.ts +409 -0
- package/src/integration-adapter-supabase-crm/tests/lifecycle-sync.test.ts +288 -0
- package/src/integration-adapter-supabase-crm/tests/stage-map.test.ts +80 -0
- package/src/integration-adapter-supabase-crm/vitest.config.ts +8 -0
- package/src/integration-adapter-supabase-crm/worker.ts +223 -0
- package/src/observability/conventions.ts +93 -0
- package/src/observability/env-resolver.ts +57 -0
- package/src/observability/index.ts +57 -0
- package/src/observability/metric-registry.ts +184 -0
- package/src/observability/otlp-converter.ts +125 -0
- package/src/observability/otlp-json.ts +135 -0
- package/src/observability/otlp-transport.ts +68 -0
- package/src/observability/pusher.ts +142 -0
- package/src/observability/redact.ts +27 -0
- package/src/observability/tests/conventions.test.ts +100 -0
- package/src/observability/tests/metric-registry.test.ts +117 -0
- package/src/observability/tests/otlp-converter.pbt.test.ts +77 -0
- package/src/observability/tests/otlp-converter.test.ts +157 -0
- package/src/observability/tests/otlp-json.test.ts +120 -0
- package/src/observability/tests/pusher.test.ts +75 -0
- package/src/observability/tests/redact.pbt.test.ts +71 -0
- package/src/observability/tests/redact.test.ts +37 -0
- package/src/observability/typed-refs.ts +137 -0
- package/src/observability/vitest.config.ts +8 -0
- package/src/ontology/analytics/matomo-binding.yaml +172 -0
- package/src/ontology/analytics/matomo-fleet.registry.yaml +26 -0
- package/src/ontology/analytics/messkanon.yaml +151 -0
- package/src/ontology/archetype-registry.ts +61 -0
- package/src/ontology/archetypes/components/brand-label.yaml +19 -0
- package/src/ontology/archetypes/components/copyright.yaml +19 -0
- package/src/ontology/archetypes/components/currency-aware-price-display.yaml +19 -0
- package/src/ontology/archetypes/components/currency-selector.yaml +19 -0
- package/src/ontology/archetypes/components/footer-promo.yaml +19 -0
- package/src/ontology/archetypes/components/lang-switcher.yaml +19 -0
- package/src/ontology/archetypes/components/layout.yaml +19 -0
- package/src/ontology/archetypes/components/live-photo.yaml +20 -0
- package/src/ontology/archetypes/components/material-credit.yaml +20 -0
- package/src/ontology/archetypes/components/media.yaml +21 -0
- package/src/ontology/archetypes/components/nachweis-card.yaml +34 -0
- package/src/ontology/archetypes/components/nachweis-detail.yaml +43 -0
- package/src/ontology/archetypes/components/nachweis-list.yaml +37 -0
- package/src/ontology/archetypes/components/nachweis-verify.yaml +31 -0
- package/src/ontology/archetypes/components/not-found.yaml +22 -0
- package/src/ontology/archetypes/components/offer-capacity.yaml +21 -0
- package/src/ontology/archetypes/components/passport-header.yaml +19 -0
- package/src/ontology/archetypes/components/passport-provenance.yaml +20 -0
- package/src/ontology/archetypes/components/passport-score-grid.yaml +20 -0
- package/src/ontology/archetypes/components/passport-star-map.yaml +20 -0
- package/src/ontology/archetypes/components/person-profile.yaml +20 -0
- package/src/ontology/archetypes/components/pulsar.yaml +20 -0
- package/src/ontology/archetypes/components/responsive-image.yaml +19 -0
- package/src/ontology/archetypes/components/scroll-to-top.yaml +22 -0
- package/src/ontology/archetypes/components/social-meta.yaml +20 -0
- package/src/ontology/archetypes/components/structured-data.yaml +19 -0
- package/src/ontology/archetypes/index.json +1003 -0
- package/src/ontology/archetypes/index.yaml +821 -0
- package/src/ontology/archetypes/sections/approach.yaml +23 -0
- package/src/ontology/archetypes/sections/article-list.yaml +30 -0
- package/src/ontology/archetypes/sections/audience-cards.yaml +30 -0
- package/src/ontology/archetypes/sections/breadcrumbs.yaml +21 -0
- package/src/ontology/archetypes/sections/chat-widget.yaml +37 -0
- package/src/ontology/archetypes/sections/comparison-cards.yaml +31 -0
- package/src/ontology/archetypes/sections/controlled-responsibility-block.yaml +34 -0
- package/src/ontology/archetypes/sections/credits.yaml +29 -0
- package/src/ontology/archetypes/sections/donation-card.yaml +53 -0
- package/src/ontology/archetypes/sections/donation-use.yaml +23 -0
- package/src/ontology/archetypes/sections/dynamic-status-block.yaml +35 -0
- package/src/ontology/archetypes/sections/faq-list.yaml +26 -0
- package/src/ontology/archetypes/sections/final-cta.yaml +53 -0
- package/src/ontology/archetypes/sections/hero-decision-card.yaml +65 -0
- package/src/ontology/archetypes/sections/hero.yaml +50 -0
- package/src/ontology/archetypes/sections/impact.yaml +23 -0
- package/src/ontology/archetypes/sections/markdown.yaml +43 -0
- package/src/ontology/archetypes/sections/mountain-journey.yaml +43 -0
- package/src/ontology/archetypes/sections/navigation.yaml +20 -0
- package/src/ontology/archetypes/sections/notausgang-block.yaml +41 -0
- package/src/ontology/archetypes/sections/open-source-registry.yaml +26 -0
- package/src/ontology/archetypes/sections/ownership-block.yaml +57 -0
- package/src/ontology/archetypes/sections/people.yaml +48 -0
- package/src/ontology/archetypes/sections/price-card.yaml +50 -0
- package/src/ontology/archetypes/sections/problem.yaml +23 -0
- package/src/ontology/archetypes/sections/send-message.yaml +63 -0
- package/src/ontology/archetypes/sections/service-metadata-block.yaml +40 -0
- package/src/ontology/archetypes/sections/social-proof.yaml +27 -0
- package/src/ontology/archetypes/sections/transparency.yaml +32 -0
- package/src/ontology/archetypes/sections/trust-strip.yaml +42 -0
- package/src/ontology/archetypes/sections/video-section.yaml +27 -0
- package/src/ontology/archetypes/sections/women.yaml +29 -0
- package/src/ontology/biome-token-projection.ts +229 -0
- package/src/ontology/biomes/check-concrete-blueprint.yaml +118 -0
- package/src/ontology/biomes/handwerk-material-warm.yaml +135 -0
- package/src/ontology/biomes/nonprofit-trust.yaml +123 -0
- package/src/ontology/blueprints/offer.yaml +39 -0
- package/src/ontology/blueprints/prompts/local-market-signal.md +13 -0
- package/src/ontology/blueprints/prompts/website-local-narrative.md +24 -0
- package/src/ontology/blueprints/ratgeber.yaml +62 -0
- package/src/ontology/blueprints/website-local.yaml +309 -0
- package/src/ontology/blueprints/website-service.yaml +84 -0
- package/src/ontology/capabilities/lead.submit.yaml +44 -0
- package/src/ontology/cosmic/index.ts +48 -0
- package/src/ontology/cosmic/moon-catalog.ts +173 -0
- package/src/ontology/cosmic/planet-catalog.ts +82 -0
- package/src/ontology/cosmic/star-catalog.ts +337 -0
- package/src/ontology/enums.ts +159 -0
- package/src/ontology/external-surfaces/index.ts +158 -0
- package/src/ontology/external-surfaces/jsonld-types.yaml +135 -0
- package/src/ontology/external-surfaces/sitemap-shape.yaml +6 -0
- package/src/ontology/external-surfaces/url-schema.yaml +95 -0
- package/src/ontology/growth/events/contact-email-click.yaml +21 -0
- package/src/ontology/growth/events/contact-form-submit.yaml +25 -0
- package/src/ontology/growth/events/contact-phone-click.yaml +21 -0
- package/src/ontology/growth/events/contact-route-click.yaml +21 -0
- package/src/ontology/growth/events/contact-submit.yaml +28 -0
- package/src/ontology/growth/events/contact-whatsapp-click.yaml +21 -0
- package/src/ontology/growth/events/cta-click.yaml +30 -0
- package/src/ontology/growth/events/donation-confirmed.yaml +32 -0
- package/src/ontology/growth/events/donation-form-start.yaml +21 -0
- package/src/ontology/growth/events/donation-form-submit.yaml +29 -0
- package/src/ontology/growth/events/donation-intent.yaml +29 -0
- package/src/ontology/growth/events/form-error.yaml +27 -0
- package/src/ontology/growth/events/form-start.yaml +21 -0
- package/src/ontology/growth/events/form-submit.yaml +21 -0
- package/src/ontology/growth/events/outbound-click.yaml +25 -0
- package/src/ontology/growth/events/page-view.yaml +24 -0
- package/src/ontology/growth/events/passport-view.yaml +28 -0
- package/src/ontology/growth/events/star-map-navigate.yaml +30 -0
- package/src/ontology/index.ts +165 -0
- package/src/ontology/manifest.ts +344 -0
- package/src/ontology/operations/index.ts +1 -0
- package/src/ontology/schemas/biome.ts +303 -0
- package/src/ontology/schemas/capability.ts +104 -0
- package/src/ontology/schemas/constellation.ts +114 -0
- package/src/ontology/schemas/dns-records.ts +53 -0
- package/src/ontology/schemas/index.ts +95 -0
- package/src/ontology/schemas/manifest-resolver.ts +123 -0
- package/src/ontology/schemas/page-entry.ts +213 -0
- package/src/ontology/schemas/section-archetype.ts +109 -0
- package/src/ontology/schemas/site-family.ts +98 -0
- package/src/ontology/schemas/system/growth.ts +80 -0
- package/src/ontology/schemas/system/integrations.ts +143 -0
- package/src/ontology/schemas/system/manifest.ts +492 -0
- package/src/ontology/schemas/system/page-output.ts +99 -0
- package/src/ontology/schemas/system/release.ts +58 -0
- package/src/ontology/schemas/system/text.ts +58 -0
- package/src/ontology/schemas/system.ts +53 -0
- package/src/ontology/shared-section-props/body-fragments.ts +182 -0
- package/src/ontology/shared-section-props/catalog.ts +195 -0
- package/src/ontology/shared-section-props/common.ts +178 -0
- package/src/ontology/shared-section-props/index.ts +34 -0
- package/src/ontology/shared-section-props/visual-header.ts +163 -0
- package/src/ontology/site-families/charity-donation-trust/cultural-rules.yaml +6 -0
- package/src/ontology/site-families/charity-donation-trust/family.yaml +44 -0
- package/src/ontology/site-families/charity-donation-trust/linguistic-rules.yaml +6 -0
- package/src/ontology/site-families/check-quality-operator/cultural-rules.yaml +6 -0
- package/src/ontology/site-families/check-quality-operator/family.yaml +40 -0
- package/src/ontology/site-families/check-quality-operator/linguistic-rules.yaml +6 -0
- package/src/ontology/site-families/handwerk-trust-engineering/cultural-rules.yaml +6 -0
- package/src/ontology/site-families/handwerk-trust-engineering/family.yaml +53 -0
- package/src/ontology/site-families/handwerk-trust-engineering/linguistic-rules.yaml +6 -0
- package/src/ontology/tests/catalogs.pbt.test.ts +89 -0
- package/src/ontology/tests/enums.test.ts +203 -0
- package/src/ontology/tests/sternsystem-owner.test.ts +63 -0
- package/src/ontology/vitest.config.ts +8 -0
- package/src/passport/dht-sign.test.ts +99 -0
- package/src/passport/dht-sign.ts +73 -0
- package/src/passport/identity-sign.test.ts +134 -0
- package/src/passport/identity-sign.ts +85 -0
- package/src/passport/index.ts +53 -0
- package/src/passport/key-rotate.ts +133 -0
- package/src/passport/schema.ts +198 -0
- package/src/passport/sign.ts +225 -0
- package/src/passport/tests/schema.pbt.test.ts +93 -0
- package/src/passport/tests/schema.test.ts +222 -0
- package/src/passport/vitest.config.ts +8 -0
- package/src/share/agent/api-catalog.ts +77 -0
- package/src/share/agent/capability.ts +68 -0
- package/src/share/agent/dns-aid.test.ts +74 -0
- package/src/share/agent/dns-aid.ts +53 -0
- package/src/share/agent/fleet-catalog.ts +149 -0
- package/src/share/agent/index.ts +29 -0
- package/src/share/agent/knowledge.ts +96 -0
- package/src/share/agent/manifest.ts +126 -0
- package/src/share/agent/mcp-card.ts +63 -0
- package/src/share/agent/omit-empty.ts +77 -0
- package/src/share/agent/openapi.ts +157 -0
- package/src/share/agent/proof.ts +61 -0
- package/src/share/attribution-display.ts +86 -0
- package/src/share/check-hints.ts +38 -0
- package/src/share/content/entity-id.ts +65 -0
- package/src/share/content/index.ts +16 -0
- package/src/share/content/merge.ts +86 -0
- package/src/share/content/resolve-field-path.ts +39 -0
- package/src/share/content/substitute-deep.ts +47 -0
- package/src/share/content-discipline/index.ts +14 -0
- package/src/share/content-discipline/parsers.ts +66 -0
- package/src/share/content-discipline/types.ts +118 -0
- package/src/share/content-reference.ts +333 -0
- package/src/share/counter-utils.ts +75 -0
- package/src/share/css-value-normalize.ts +48 -0
- package/src/share/dev-props-validator.ts +131 -0
- package/src/share/entitlement.ts +172 -0
- package/src/share/env.d.ts +73 -0
- package/src/share/feature-policy.ts +367 -0
- package/src/share/formula-eval.ts +364 -0
- package/src/share/fs/index.ts +96 -0
- package/src/share/i18n/localization.ts +57 -0
- package/src/share/image-provider.ts +314 -0
- package/src/share/index.ts +86 -0
- package/src/share/knowledge/claim.ts +129 -0
- package/src/share/knowledge/derivation.ts +55 -0
- package/src/share/knowledge/freshness.ts +127 -0
- package/src/share/knowledge/index.ts +23 -0
- package/src/share/knowledge/ledger.ts +222 -0
- package/src/share/knowledge/plan.ts +122 -0
- package/src/share/knowledge/source.ts +170 -0
- package/src/share/legal/translation-policy.ts +133 -0
- package/src/share/material-credits.ts +181 -0
- package/src/share/middleware/language-redirect.ts +49 -0
- package/src/share/offer-capacity.ts +149 -0
- package/src/share/onboarding-yaml/index.ts +162 -0
- package/src/share/page.ts +351 -0
- package/src/share/redirects.test.ts +62 -0
- package/src/share/redirects.ts +54 -0
- package/src/share/rfc0042-utils.ts +95 -0
- package/src/share/runtime-context.ts +70 -0
- package/src/share/schemas/claim-records.ts +69 -0
- package/src/share/schemas/claims.ts +150 -0
- package/src/share/schemas/effects.ts +212 -0
- package/src/share/schemas/features.ts +147 -0
- package/src/share/schemas/horizontal-align.ts +22 -0
- package/src/share/schemas/icon-color.ts +27 -0
- package/src/share/schemas/index.ts +43 -0
- package/src/share/schemas/live-photo.ts +53 -0
- package/src/share/schemas/material-credit.ts +292 -0
- package/src/share/schemas/media.ts +220 -0
- package/src/share/schemas/navigation.ts +74 -0
- package/src/share/schemas/page-base.ts +33 -0
- package/src/share/schemas/participant.ts +247 -0
- package/src/share/schemas/person.ts +24 -0
- package/src/share/schemas/print.ts +93 -0
- package/src/share/schemas/section-background.ts +106 -0
- package/src/share/schemas/section-body.ts +138 -0
- package/src/share/schemas/section-cards.ts +37 -0
- package/src/share/schemas/section-cta.ts +74 -0
- package/src/share/schemas/section-header.ts +77 -0
- package/src/share/schemas/section-image.ts +77 -0
- package/src/share/schemas/section-motion.ts +52 -0
- package/src/share/schemas/section-shell.ts +63 -0
- package/src/share/schemas/section-stats.ts +37 -0
- package/src/share/schemas/site-background.ts +78 -0
- package/src/share/schemas/standard-list-item.ts +38 -0
- package/src/share/scripts/external-links.ts +45 -0
- package/src/share/scripts/gsap-counter.ts +168 -0
- package/src/share/scripts/gsap-mountain-journey.ts +236 -0
- package/src/share/scripts/gsap-parallax.ts +50 -0
- package/src/share/scripts/gsap-reveal.ts +65 -0
- package/src/share/scripts/gsap-stagger.ts +54 -0
- package/src/share/scripts/index.ts +25 -0
- package/src/share/scripts/inline-number-animation.ts +120 -0
- package/src/share/scripts/lenis.ts +109 -0
- package/src/share/scripts/live-photos.ts +250 -0
- package/src/share/scripts/lordicon.ts +94 -0
- package/src/share/scripts/orchestrator.ts +138 -0
- package/src/share/scripts/scheduler.ts +53 -0
- package/src/share/scripts/video-player.ts +116 -0
- package/src/share/semantic/ai.ts +140 -0
- package/src/share/semantic/block-extraction.ts +52 -0
- package/src/share/semantic/block-extractors/index.ts +502 -0
- package/src/share/semantic/breadcrumbs.ts +120 -0
- package/src/share/semantic/build-page.ts +309 -0
- package/src/share/semantic/business-projection.ts +278 -0
- package/src/share/semantic/derived-prices-loader.ts +36 -0
- package/src/share/semantic/extract.ts +118 -0
- package/src/share/semantic/feed.ts +124 -0
- package/src/share/semantic/ids.ts +76 -0
- package/src/share/semantic/image-sitemap.ts +153 -0
- package/src/share/semantic/index.ts +36 -0
- package/src/share/semantic/jsonld/article.ts +47 -0
- package/src/share/semantic/jsonld/breadcrumb.ts +47 -0
- package/src/share/semantic/jsonld/collection-list.ts +30 -0
- package/src/share/semantic/jsonld/context.ts +46 -0
- package/src/share/semantic/jsonld/faq.ts +49 -0
- package/src/share/semantic/jsonld/initiative.ts +53 -0
- package/src/share/semantic/jsonld/organization.ts +101 -0
- package/src/share/semantic/jsonld/person.ts +71 -0
- package/src/share/semantic/jsonld/service.ts +80 -0
- package/src/share/semantic/jsonld/shared.ts +31 -0
- package/src/share/semantic/jsonld/types.ts +18 -0
- package/src/share/semantic/jsonld/webpage.ts +98 -0
- package/src/share/semantic/jsonld/website.ts +27 -0
- package/src/share/semantic/jsonld.ts +75 -0
- package/src/share/semantic/llms-policy.ts +74 -0
- package/src/share/semantic/llms.ts +394 -0
- package/src/share/semantic/markdown-hygiene.ts +68 -0
- package/src/share/semantic/markdown-twin-provenance.ts +242 -0
- package/src/share/semantic/models.ts +402 -0
- package/src/share/semantic/organization-profile.ts +160 -0
- package/src/share/semantic/output-projection.ts +131 -0
- package/src/share/semantic/page-builders/markdown-page.ts +84 -0
- package/src/share/semantic/page-markdown.ts +234 -0
- package/src/share/semantic/page-utils.ts +125 -0
- package/src/share/semantic/price-marker-resolver.ts +92 -0
- package/src/share/semantic/robots.ts +127 -0
- package/src/share/semantic/update-stamp.ts +136 -0
- package/src/share/shared-context.ts +177 -0
- package/src/share/string-utils.ts +19 -0
- package/src/share/tests/api-catalog.test.ts +97 -0
- package/src/share/tests/breadcrumbs.test.ts +126 -0
- package/src/share/tests/build-page-price-markers.test.ts +160 -0
- package/src/share/tests/capability.test.ts +107 -0
- package/src/share/tests/claim.test.ts +90 -0
- package/src/share/tests/content-ref-index.test.ts +328 -0
- package/src/share/tests/create-dev-props-validator.test.ts +38 -0
- package/src/share/tests/derivation.test.ts +39 -0
- package/src/share/tests/dev-props-validator.test.ts +88 -0
- package/src/share/tests/fleet-catalog.test.ts +134 -0
- package/src/share/tests/formula-eval.test.ts +619 -0
- package/src/share/tests/freshness.test.ts +60 -0
- package/src/share/tests/hero-section-numbering-parity.test.ts +51 -0
- package/src/share/tests/image-sitemap.test.ts +101 -0
- package/src/share/tests/jsonld-service.test.ts +282 -0
- package/src/share/tests/knowledge.test.ts +86 -0
- package/src/share/tests/ledger.test.ts +125 -0
- package/src/share/tests/llms-0789.test.ts +63 -0
- package/src/share/tests/manifest.test.ts +100 -0
- package/src/share/tests/markdown-twin-provenance.test.ts +108 -0
- package/src/share/tests/mcp-card.test.ts +57 -0
- package/src/share/tests/onboarding-yaml.test.ts +111 -0
- package/src/share/tests/ontology-role-by-cosmic-name.test.ts +28 -0
- package/src/share/tests/openapi.test.ts +116 -0
- package/src/share/tests/organization-jsonld.test.ts +74 -0
- package/src/share/tests/output-projection.test.ts +61 -0
- package/src/share/tests/plan.test.ts +97 -0
- package/src/share/tests/price-marker-resolver.test.ts +141 -0
- package/src/share/tests/proof.test.ts +72 -0
- package/src/share/tests/resolve-field-path.test.ts +52 -0
- package/src/share/tests/source.test.ts +81 -0
- package/src/share/tests/substitute-deep.test.ts +65 -0
- package/src/share/tests/text-normalize.pbt.test.ts +143 -0
- package/src/share/tests/text-normalize.test.ts +285 -0
- package/src/share/tests/twin-path.test.ts +43 -0
- package/src/share/text-normalize.ts +548 -0
- package/src/share/text-position.ts +19 -0
- package/src/share/types/hls-js-light.d.ts +16 -0
- package/src/share/visibility.ts +167 -0
- package/src/share/vitest.config.ts +8 -0
- package/src/share/wrap-inline-numbers.ts +139 -0
- package/src/surface/blueprint-schema.ts +314 -0
- package/src/surface/blueprint-types.ts +256 -0
- package/src/surface/blueprint.ts +300 -0
- package/src/surface/breaker.ts +57 -0
- package/src/surface/decision-composer.ts +156 -0
- package/src/surface/eligibility.ts +372 -0
- package/src/surface/evidence-records.ts +97 -0
- package/src/surface/fleet.ts +60 -0
- package/src/surface/geo.ts +170 -0
- package/src/surface/governance.ts +146 -0
- package/src/surface/index.ts +216 -0
- package/src/surface/io/index.ts +18 -0
- package/src/surface/io/surface-module-context-io.ts +60 -0
- package/src/surface/io/visibility-outcomes-io.ts +46 -0
- package/src/surface/module-context.ts +120 -0
- package/src/surface/substance.ts +161 -0
- package/src/surface/tests/eligibility.pbt.test.ts +137 -0
- package/src/surface/tests/eligibility.test.ts +302 -0
- package/src/surface/types.ts +289 -0
- package/src/surface/visibility.ts +57 -0
- package/src/surface/vitest.config.ts +8 -0
- package/tsconfig.json +17 -0
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { test, expect, describe } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
PassportSchema,
|
|
4
|
+
PassportPublicKeyFileSchema,
|
|
5
|
+
PassportPublicKeyEntrySchema,
|
|
6
|
+
} from "../schema.ts";
|
|
7
|
+
|
|
8
|
+
const validHash = "sha256:" + "a".repeat(64);
|
|
9
|
+
|
|
10
|
+
const validPassport = {
|
|
11
|
+
schemaVersion: "1.0",
|
|
12
|
+
appId: "test-app",
|
|
13
|
+
issuedAt: "2026-01-01T00:00:00Z",
|
|
14
|
+
composition: {
|
|
15
|
+
systemHash: validHash,
|
|
16
|
+
constellation: "test-constellation",
|
|
17
|
+
biome: "default",
|
|
18
|
+
stars: [
|
|
19
|
+
{
|
|
20
|
+
route: "/de/home",
|
|
21
|
+
cosmicStar: "Vega",
|
|
22
|
+
planets: [{ cosmicPlanet: "Europa", pin: "v1", semanticId: "hero" }],
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
},
|
|
26
|
+
provenance: {
|
|
27
|
+
commitSha: "abc123",
|
|
28
|
+
commitAt: "2026-01-01T00:00:00Z",
|
|
29
|
+
builtAt: "2026-01-01T00:00:00Z",
|
|
30
|
+
buildDurationMs: 5000,
|
|
31
|
+
builder: "agent",
|
|
32
|
+
keyVersion: "v1",
|
|
33
|
+
verifiableCredential: {
|
|
34
|
+
"@context": ["https://www.w3.org/2018/credentials/v1"],
|
|
35
|
+
type: ["VerifiableCredential"],
|
|
36
|
+
issuer: "did:web:example.com",
|
|
37
|
+
issuanceDate: "2026-01-01T00:00:00Z",
|
|
38
|
+
credentialSubject: {
|
|
39
|
+
id: "did:web:example.com",
|
|
40
|
+
systemHash: validHash,
|
|
41
|
+
commitSha: "abc123",
|
|
42
|
+
},
|
|
43
|
+
proof: {
|
|
44
|
+
type: "Ed25519Signature2020",
|
|
45
|
+
created: "2026-01-01T00:00:00Z",
|
|
46
|
+
verificationMethod: "did:web:example.com#key-1",
|
|
47
|
+
proofPurpose: "assertionMethod",
|
|
48
|
+
proofValue: "zDummySignatureValue",
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
scores: {
|
|
53
|
+
nebula: 85,
|
|
54
|
+
pillars: {
|
|
55
|
+
performance: { score: 90, weight: 0.25 },
|
|
56
|
+
accessibility: { score: 85, weight: 0.25 },
|
|
57
|
+
contentHealth: { score: 80, weight: 0.25 },
|
|
58
|
+
architecturalCompliance: { score: 85, weight: 0.25 },
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
links: {
|
|
62
|
+
starMapSvg: "/star-map.svg",
|
|
63
|
+
publicKey: "/.well-known/cosmic-passport-key.json",
|
|
64
|
+
dnaReport: "/dna-report.json",
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
describe("PassportSchema", () => {
|
|
69
|
+
test("accepts a valid passport", () => {
|
|
70
|
+
expect(PassportSchema.safeParse(validPassport).success).toBe(true);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test("rejects wrong schemaVersion", () => {
|
|
74
|
+
expect(PassportSchema.safeParse({ ...validPassport, schemaVersion: "2.0" }).success).toBe(
|
|
75
|
+
false,
|
|
76
|
+
);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test("rejects empty appId", () => {
|
|
80
|
+
expect(PassportSchema.safeParse({ ...validPassport, appId: "" }).success).toBe(false);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test("rejects invalid systemHash format", () => {
|
|
84
|
+
expect(
|
|
85
|
+
PassportSchema.safeParse({
|
|
86
|
+
...validPassport,
|
|
87
|
+
composition: { ...validPassport.composition, systemHash: "not-a-hash" },
|
|
88
|
+
}).success,
|
|
89
|
+
).toBe(false);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test("rejects nebula score out of range", () => {
|
|
93
|
+
expect(
|
|
94
|
+
PassportSchema.safeParse({
|
|
95
|
+
...validPassport,
|
|
96
|
+
scores: { ...validPassport.scores, nebula: 150 },
|
|
97
|
+
}).success,
|
|
98
|
+
).toBe(false);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test("rejects negative pillar score", () => {
|
|
102
|
+
expect(
|
|
103
|
+
PassportSchema.safeParse({
|
|
104
|
+
...validPassport,
|
|
105
|
+
scores: {
|
|
106
|
+
...validPassport.scores,
|
|
107
|
+
pillars: {
|
|
108
|
+
...validPassport.scores.pillars,
|
|
109
|
+
performance: { score: -10, weight: 0.25 },
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
}).success,
|
|
113
|
+
).toBe(false);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
test("rejects negative buildDurationMs", () => {
|
|
117
|
+
expect(
|
|
118
|
+
PassportSchema.safeParse({
|
|
119
|
+
...validPassport,
|
|
120
|
+
provenance: { ...validPassport.provenance, buildDurationMs: -1 },
|
|
121
|
+
}).success,
|
|
122
|
+
).toBe(false);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test("rejects wrong proof type", () => {
|
|
126
|
+
expect(
|
|
127
|
+
PassportSchema.safeParse({
|
|
128
|
+
...validPassport,
|
|
129
|
+
provenance: {
|
|
130
|
+
...validPassport.provenance,
|
|
131
|
+
verifiableCredential: {
|
|
132
|
+
...validPassport.provenance.verifiableCredential,
|
|
133
|
+
proof: {
|
|
134
|
+
...validPassport.provenance.verifiableCredential.proof,
|
|
135
|
+
type: "WrongType",
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
}).success,
|
|
140
|
+
).toBe(false);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
test("defaults stars to empty array when omitted", () => {
|
|
144
|
+
const { stars, ...withoutStars } = validPassport.composition;
|
|
145
|
+
const result = PassportSchema.safeParse({
|
|
146
|
+
...validPassport,
|
|
147
|
+
composition: withoutStars,
|
|
148
|
+
});
|
|
149
|
+
expect(result.success).toBe(true);
|
|
150
|
+
if (result.success) {
|
|
151
|
+
expect(result.data.composition.stars).toEqual([]);
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
describe("PassportPublicKeyEntrySchema", () => {
|
|
157
|
+
test("accepts a valid key entry", () => {
|
|
158
|
+
expect(
|
|
159
|
+
PassportPublicKeyEntrySchema.safeParse({
|
|
160
|
+
version: "v1",
|
|
161
|
+
active: true,
|
|
162
|
+
type: "Ed25519VerificationKey2020",
|
|
163
|
+
publicKeyMultibase: "z6MkhaXgBZDvotDkL5m7XJ5n",
|
|
164
|
+
createdAt: "2026-01-01T00:00:00Z",
|
|
165
|
+
}).success,
|
|
166
|
+
).toBe(true);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
test("rejects publicKeyMultibase without z prefix", () => {
|
|
170
|
+
expect(
|
|
171
|
+
PassportPublicKeyEntrySchema.safeParse({
|
|
172
|
+
version: "v1",
|
|
173
|
+
active: true,
|
|
174
|
+
type: "Ed25519VerificationKey2020",
|
|
175
|
+
publicKeyMultibase: "6MkhaXgBZDvotDkL5m7XJ5n",
|
|
176
|
+
createdAt: "2026-01-01T00:00:00Z",
|
|
177
|
+
}).success,
|
|
178
|
+
).toBe(false);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
test("rejects wrong type", () => {
|
|
182
|
+
expect(
|
|
183
|
+
PassportPublicKeyEntrySchema.safeParse({
|
|
184
|
+
version: "v1",
|
|
185
|
+
active: true,
|
|
186
|
+
type: "WrongType",
|
|
187
|
+
publicKeyMultibase: "z6MkhaXgBZDvotDkL5m7XJ5n",
|
|
188
|
+
createdAt: "2026-01-01T00:00:00Z",
|
|
189
|
+
}).success,
|
|
190
|
+
).toBe(false);
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
describe("PassportPublicKeyFileSchema", () => {
|
|
195
|
+
test("accepts a file with at least one key", () => {
|
|
196
|
+
expect(
|
|
197
|
+
PassportPublicKeyFileSchema.safeParse({
|
|
198
|
+
schemaVersion: "1.0",
|
|
199
|
+
appId: "test-app",
|
|
200
|
+
keys: [
|
|
201
|
+
{
|
|
202
|
+
version: "v1",
|
|
203
|
+
active: true,
|
|
204
|
+
type: "Ed25519VerificationKey2020",
|
|
205
|
+
publicKeyMultibase: "z6MkhaXgBZDvotDkL5m7XJ5n",
|
|
206
|
+
createdAt: "2026-01-01T00:00:00Z",
|
|
207
|
+
},
|
|
208
|
+
],
|
|
209
|
+
}).success,
|
|
210
|
+
).toBe(true);
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
test("rejects empty keys array", () => {
|
|
214
|
+
expect(
|
|
215
|
+
PassportPublicKeyFileSchema.safeParse({
|
|
216
|
+
schemaVersion: "1.0",
|
|
217
|
+
appId: "test-app",
|
|
218
|
+
keys: [],
|
|
219
|
+
}).success,
|
|
220
|
+
).toBe(false);
|
|
221
|
+
});
|
|
222
|
+
});
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/*
|
|
2
|
+
<MODULE_CONTRACT>
|
|
3
|
+
<purpose>
|
|
4
|
+
RFC-0783: pure, dependency-free formatter that projects a site's Agent Surface
|
|
5
|
+
Manifest into an RFC 9727 linkset+json document for /.well-known/api-catalog.
|
|
6
|
+
No I/O — the kernel command loads the manifest and passes it here.
|
|
7
|
+
</purpose>
|
|
8
|
+
<non-goals>
|
|
9
|
+
<item>Do not read files — callers load and pass the manifest.</item>
|
|
10
|
+
<item>Do not sign — signing is a separate concern (agent.surface.sign).</item>
|
|
11
|
+
</non-goals>
|
|
12
|
+
</MODULE_CONTRACT>
|
|
13
|
+
<CHANGE_SUMMARY>
|
|
14
|
+
<item>RFC-0783: initial API Catalog linkset+json projection.</item>
|
|
15
|
+
</CHANGE_SUMMARY>
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import type { AgentSurfaceManifest } from "./manifest.ts";
|
|
19
|
+
|
|
20
|
+
/** RFC 9264 linkset+json link object — no `rel` (it's the key in the linkset entry). */
|
|
21
|
+
export interface ApiCatalogLink {
|
|
22
|
+
href: string;
|
|
23
|
+
type: string;
|
|
24
|
+
title?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** RFC 9264 linkset entry — anchor + relation-keyed link arrays. */
|
|
28
|
+
export interface ApiCatalogEntry {
|
|
29
|
+
anchor: string;
|
|
30
|
+
[relation: string]: string | ApiCatalogLink[];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** RFC 9264 linkset document — top-level `linkset` array. */
|
|
34
|
+
export interface ApiCatalog {
|
|
35
|
+
linkset: ApiCatalogEntry[];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Pure: project Agent Surface Manifest into RFC 9264 linkset+json.
|
|
40
|
+
* Deterministic — links within each relation are sorted by href for byte-identical output (DNA-58).
|
|
41
|
+
*/
|
|
42
|
+
export function buildApiCatalog(manifest: AgentSurfaceManifest): ApiCatalog {
|
|
43
|
+
const anchor = manifest.baseUrl.replace(/\/+$/, "") + "/";
|
|
44
|
+
const entry: ApiCatalogEntry = { anchor };
|
|
45
|
+
|
|
46
|
+
const item: ApiCatalogLink[] = manifest.knowledge.map((ref) => ({
|
|
47
|
+
href: ref.url,
|
|
48
|
+
type: "application/json",
|
|
49
|
+
title: ref.domain,
|
|
50
|
+
}));
|
|
51
|
+
if (item.length > 0) {
|
|
52
|
+
item.sort((a, b) => a.href.localeCompare(b.href));
|
|
53
|
+
entry["item"] = item;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
entry["service-meta"] = [{ href: "/.well-known/agent.json", type: "application/json" }];
|
|
57
|
+
|
|
58
|
+
const serviceDesc: ApiCatalogLink[] = [];
|
|
59
|
+
if (manifest.interfaces.openapi) {
|
|
60
|
+
serviceDesc.push({ href: manifest.interfaces.openapi, type: "application/json" });
|
|
61
|
+
}
|
|
62
|
+
if (manifest.interfaces.mcp) {
|
|
63
|
+
serviceDesc.push({ href: "/.well-known/mcp/server-card.json", type: "application/json" });
|
|
64
|
+
}
|
|
65
|
+
if (serviceDesc.length > 0) {
|
|
66
|
+
serviceDesc.sort((a, b) => a.href.localeCompare(b.href));
|
|
67
|
+
entry["service-desc"] = serviceDesc;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (manifest.interfaces.mcp) {
|
|
71
|
+
entry["service"] = [{ href: manifest.interfaces.mcp.url, type: "application/json" }];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
entry["service-doc"] = [{ href: manifest.interfaces.llms, type: "text/plain" }];
|
|
75
|
+
|
|
76
|
+
return { linkset: [entry] };
|
|
77
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/*
|
|
2
|
+
<MODULE_CONTRACT>
|
|
3
|
+
<purpose>
|
|
4
|
+
RFC-0288: pure resolution of the closed capability catalog into the set of
|
|
5
|
+
capabilities ACTIVE on a given site. A capability is active iff the site holds
|
|
6
|
+
`agent.actions`, every additional `requires.entitlements` is held, every
|
|
7
|
+
`requires.sections` archetype renders on some page, and its id is not in
|
|
8
|
+
`agent.actionsDisabled`. Consumed by agent.manifest.generate (RFC-0286) to
|
|
9
|
+
populate `AgentActionRef[]`, and by RFC-0289/0290 to project OpenAPI
|
|
10
|
+
operations and MCP tools.
|
|
11
|
+
</purpose>
|
|
12
|
+
<non-goals>
|
|
13
|
+
<item>Do not load the catalog from disk or read entitlements/content — the
|
|
14
|
+
kernel command does that and passes already-loaded data here.</item>
|
|
15
|
+
</non-goals>
|
|
16
|
+
</MODULE_CONTRACT>
|
|
17
|
+
<CHANGE_SUMMARY>
|
|
18
|
+
<item>RFC-0288: initial capability resolution.</item>
|
|
19
|
+
</CHANGE_SUMMARY>
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import type { CapabilityRecord } from "@warpgogol/werkstatt-shared/ontology";
|
|
23
|
+
import type { AgentActionRef } from "./manifest.ts";
|
|
24
|
+
|
|
25
|
+
export type { CapabilityRecord } from "@warpgogol/werkstatt-shared/ontology";
|
|
26
|
+
|
|
27
|
+
export interface ResolveActiveCapabilitiesInput {
|
|
28
|
+
catalog: CapabilityRecord[];
|
|
29
|
+
/** Resolved entitlement feature ids (e.g. from entitlements.generated.yaml). */
|
|
30
|
+
entitlements: string[];
|
|
31
|
+
/** Section archetypes (blocks[].type) that render on some page of the app. */
|
|
32
|
+
renderedSectionTypes: string[];
|
|
33
|
+
/** system.md agent.actionsDisabled — capability ids to withhold even if otherwise active. */
|
|
34
|
+
actionsDisabled: string[];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Pure: gate the closed catalog down to the capabilities active on this site. */
|
|
38
|
+
export function resolveActiveCapabilities(
|
|
39
|
+
input: ResolveActiveCapabilitiesInput,
|
|
40
|
+
): CapabilityRecord[] {
|
|
41
|
+
const entitlements = new Set(input.entitlements);
|
|
42
|
+
const renderedSections = new Set(input.renderedSectionTypes);
|
|
43
|
+
const disabled = new Set(input.actionsDisabled);
|
|
44
|
+
|
|
45
|
+
if (!entitlements.has("agent.actions")) return [];
|
|
46
|
+
|
|
47
|
+
return input.catalog.filter((cap) => {
|
|
48
|
+
if (disabled.has(cap.id)) return false;
|
|
49
|
+
for (const req of cap.requires.entitlements) {
|
|
50
|
+
if (!entitlements.has(req)) return false;
|
|
51
|
+
}
|
|
52
|
+
for (const section of cap.requires.sections) {
|
|
53
|
+
if (!renderedSections.has(section)) return false;
|
|
54
|
+
}
|
|
55
|
+
return true;
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Project one active capability into its manifest AgentActionRef (RFC-0286). */
|
|
60
|
+
export function capabilityToActionRef(cap: CapabilityRecord): AgentActionRef {
|
|
61
|
+
return {
|
|
62
|
+
id: cap.id,
|
|
63
|
+
url: `/api/agent/actions/${cap.id}`,
|
|
64
|
+
title: cap.title,
|
|
65
|
+
inputSchemaRef: `#/components/schemas/${cap.id}-input`,
|
|
66
|
+
entitlement: "agent.actions",
|
|
67
|
+
};
|
|
68
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/*
|
|
2
|
+
<MODULE_CONTRACT>
|
|
3
|
+
<purpose>
|
|
4
|
+
RFC-0786: Unit tests for the buildDnsAidRecord pure function.
|
|
5
|
+
Verifies determinism, domain extraction, and content URL construction.
|
|
6
|
+
</purpose>
|
|
7
|
+
</MODULE_CONTRACT>
|
|
8
|
+
<CHANGE_SUMMARY>
|
|
9
|
+
<item>RFC-0786: initial unit tests for buildDnsAidRecord.</item>
|
|
10
|
+
</CHANGE_SUMMARY>
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { describe, it, expect } from "vitest";
|
|
14
|
+
import { buildDnsAidRecord } from "@warpgogol/werkstatt-shared/share/agent";
|
|
15
|
+
import type { AgentSurfaceManifest } from "@warpgogol/werkstatt-shared/share/agent";
|
|
16
|
+
|
|
17
|
+
function makeManifest(baseUrl: string): AgentSurfaceManifest {
|
|
18
|
+
return {
|
|
19
|
+
surfaceVersion: "1.0.0",
|
|
20
|
+
site: "test-site",
|
|
21
|
+
baseUrl,
|
|
22
|
+
languages: { default: "de", supported: ["de"] },
|
|
23
|
+
contentHash: "abc123",
|
|
24
|
+
knowledge: [],
|
|
25
|
+
actions: [],
|
|
26
|
+
interfaces: { llms: "", twins: null, openapi: null, mcp: null },
|
|
27
|
+
proof: null,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
describe("buildDnsAidRecord (RFC-0786)", () => {
|
|
32
|
+
it("builds record with _index._agents.<domain> name", () => {
|
|
33
|
+
const record = buildDnsAidRecord(makeManifest("https://warpgogol.com"));
|
|
34
|
+
expect(record.name).toBe("_index._agents.warpgogol.com");
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("builds record with SVCB type", () => {
|
|
38
|
+
const record = buildDnsAidRecord(makeManifest("https://warpgogol.com"));
|
|
39
|
+
expect(record.type).toBe("SVCB");
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("builds SVCB content with target, alpn and port params (RFC 9460)", () => {
|
|
43
|
+
const record = buildDnsAidRecord(makeManifest("https://warpgogol.com"));
|
|
44
|
+
expect(record.content).toBe("1 warpgogol.com alpn=h2 port=443");
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("sets ttl to 3600", () => {
|
|
48
|
+
const record = buildDnsAidRecord(makeManifest("https://warpgogol.com"));
|
|
49
|
+
expect(record.ttl).toBe(3600);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("sets proxied to false", () => {
|
|
53
|
+
const record = buildDnsAidRecord(makeManifest("https://warpgogol.com"));
|
|
54
|
+
expect(record.proxied).toBe(false);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("is deterministic — same input produces same output (DNA-58)", () => {
|
|
58
|
+
const manifest = makeManifest("https://example.org");
|
|
59
|
+
const r1 = buildDnsAidRecord(manifest);
|
|
60
|
+
const r2 = buildDnsAidRecord(manifest);
|
|
61
|
+
expect(JSON.stringify(r1)).toBe(JSON.stringify(r2));
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("extracts domain from URL with port", () => {
|
|
65
|
+
const record = buildDnsAidRecord(makeManifest("http://localhost:3000"));
|
|
66
|
+
expect(record.name).toBe("_index._agents.localhost");
|
|
67
|
+
expect(record.content).toBe("1 localhost alpn=h2 port=443");
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("strips trailing slash from baseUrl", () => {
|
|
71
|
+
const record = buildDnsAidRecord(makeManifest("https://warpgogol.com/"));
|
|
72
|
+
expect(record.content).toBe("1 warpgogol.com alpn=h2 port=443");
|
|
73
|
+
});
|
|
74
|
+
});
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/*
|
|
2
|
+
<MODULE_CONTRACT>
|
|
3
|
+
<purpose>
|
|
4
|
+
RFC-0786: Pure projection from AgentSurfaceManifest to DNS-AID SVCB record
|
|
5
|
+
declaration. DNS-AID is a DNS-based agent discovery mechanism: an SVCB record
|
|
6
|
+
at _index._agents.<domain> with target pointing to the host serving
|
|
7
|
+
agent.json, and standard SvcParams (alpn, port) per RFC 9460.
|
|
8
|
+
</purpose>
|
|
9
|
+
<non-goals>
|
|
10
|
+
<item>Do not perform I/O — this is a pure function (DNA-58).</item>
|
|
11
|
+
<item>Do not write to dns-records.yaml — that is the command handler's job.</item>
|
|
12
|
+
</non-goals>
|
|
13
|
+
</MODULE_CONTRACT>
|
|
14
|
+
<CHANGE_SUMMARY>
|
|
15
|
+
<item>RFC-0786: initial DNS-AID record builder — TXT record at _agent.<domain>.</item>
|
|
16
|
+
<item>RFC-0786: updated to SVCB record at _index._agents.<domain> per DNS-AID spec.</item>
|
|
17
|
+
</CHANGE_SUMMARY>
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import type { AgentSurfaceManifest } from "./manifest.ts";
|
|
21
|
+
|
|
22
|
+
export interface DnsAidRecord {
|
|
23
|
+
name: string;
|
|
24
|
+
type: "SVCB";
|
|
25
|
+
content: string;
|
|
26
|
+
ttl: number;
|
|
27
|
+
proxied: false;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Build the DNS-AID SVCB record declaration from the agent surface manifest.
|
|
32
|
+
* Pure function — no I/O, no side effects (DNA-58).
|
|
33
|
+
*
|
|
34
|
+
* The record name is `_index._agents.<domain>` (per DNS-AID spec).
|
|
35
|
+
* The record is an SVCB service record (RFC 9460) with:
|
|
36
|
+
* priority: 1 (service mode)
|
|
37
|
+
* target: <domain> (the host serving agent.json)
|
|
38
|
+
* alpn: h2 (HTTP/2)
|
|
39
|
+
* port: 443 (HTTPS)
|
|
40
|
+
* The client resolves the target host, connects via alpn/port, and fetches
|
|
41
|
+
* /.well-known/agent.json — the path is implied by the DNS-AID spec.
|
|
42
|
+
* TTL is 3600 seconds (1 hour).
|
|
43
|
+
*/
|
|
44
|
+
export function buildDnsAidRecord(manifest: AgentSurfaceManifest): DnsAidRecord {
|
|
45
|
+
const domain = new URL(manifest.baseUrl).hostname;
|
|
46
|
+
return {
|
|
47
|
+
name: `_index._agents.${domain}`,
|
|
48
|
+
type: "SVCB",
|
|
49
|
+
content: `1 ${domain} alpn=h2 port=443`,
|
|
50
|
+
ttl: 3600,
|
|
51
|
+
proxied: false,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/*
|
|
2
|
+
<MODULE_CONTRACT>
|
|
3
|
+
<purpose>
|
|
4
|
+
RFC-0292: the Fleet Agent Catalog — a deterministic projection of every site's
|
|
5
|
+
public Agent Surface Manifest into one workspace-level discovery document.
|
|
6
|
+
Pure, framework-free assembly: no I/O, no timestamps, sorted-key canonical
|
|
7
|
+
hashing so two runs on unchanged input are byte-identical. Consumed by
|
|
8
|
+
fleet.agent.catalog.generate (site-kernel-checks) and by the Leitstand.
|
|
9
|
+
</purpose>
|
|
10
|
+
<non-goals>
|
|
11
|
+
<item>Do not read files or network — callers (kernel commands) load each
|
|
12
|
+
site's agent.json and pass already-parsed data here.</item>
|
|
13
|
+
<item>Do not aggregate knowledge payloads, leads, or any per-site data —
|
|
14
|
+
only public discovery metadata (RFC-0176/0177 isolation).</item>
|
|
15
|
+
<item>Do not add fields absent from the site's own agent.json — the catalog
|
|
16
|
+
is a projection, never a new source of facts (AS-2 at fleet scale).</item>
|
|
17
|
+
</non-goals>
|
|
18
|
+
</MODULE_CONTRACT>
|
|
19
|
+
<CHANGE_SUMMARY>
|
|
20
|
+
<item>RFC-0292: initial fleet catalog contract and pure builder.</item>
|
|
21
|
+
</CHANGE_SUMMARY>
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { createHash } from "node:crypto";
|
|
25
|
+
import { canonicalJson } from "./manifest.ts";
|
|
26
|
+
|
|
27
|
+
export const FLEET_AGENT_CATALOG_SCHEMA = "gogol.fleet.agent-catalog@1";
|
|
28
|
+
|
|
29
|
+
export interface FleetAgentCatalogEntry {
|
|
30
|
+
site: string;
|
|
31
|
+
baseUrl: string;
|
|
32
|
+
surfaceVersion: string;
|
|
33
|
+
contentHash: string;
|
|
34
|
+
signed: boolean;
|
|
35
|
+
enabled: boolean;
|
|
36
|
+
knowledgeDomains: string[];
|
|
37
|
+
actions: string[];
|
|
38
|
+
interfaces: { openapi: boolean; mcp: boolean };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface FleetAgentCatalog {
|
|
42
|
+
schema: typeof FLEET_AGENT_CATALOG_SCHEMA;
|
|
43
|
+
/** sha256 over sorted-key JSON of `sites` — no timestamps (byte-stable). */
|
|
44
|
+
contentHash: string;
|
|
45
|
+
sites: FleetAgentCatalogEntry[];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface FleetAgentCatalogSiteInput {
|
|
49
|
+
site: string;
|
|
50
|
+
/** Parsed agent.json, or null when the site has no agent surface (agent.enabled: false). */
|
|
51
|
+
doc: Record<string, unknown> | null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function sortKeysDeep(value: unknown): unknown {
|
|
55
|
+
if (Array.isArray(value)) return value.map(sortKeysDeep);
|
|
56
|
+
if (value !== null && typeof value === "object") {
|
|
57
|
+
const out: Record<string, unknown> = {};
|
|
58
|
+
for (const key of Object.keys(value as Record<string, unknown>).sort()) {
|
|
59
|
+
out[key] = sortKeysDeep((value as Record<string, unknown>)[key]);
|
|
60
|
+
}
|
|
61
|
+
return out;
|
|
62
|
+
}
|
|
63
|
+
return value;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function asString(value: unknown): string | undefined {
|
|
67
|
+
return typeof value === "string" ? value : undefined;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function _asStringArray(value: unknown): string[] {
|
|
71
|
+
if (!Array.isArray(value)) return [];
|
|
72
|
+
return value.filter((v): v is string => typeof v === "string");
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Extract a catalog entry from one site's parsed agent.json.
|
|
77
|
+
* Missing doc ⇒ enabled: false entry with empty arrays.
|
|
78
|
+
*/
|
|
79
|
+
function entryFromSiteInput(input: FleetAgentCatalogSiteInput): FleetAgentCatalogEntry {
|
|
80
|
+
if (!input.doc) {
|
|
81
|
+
return {
|
|
82
|
+
site: input.site,
|
|
83
|
+
baseUrl: "",
|
|
84
|
+
surfaceVersion: "",
|
|
85
|
+
contentHash: "",
|
|
86
|
+
signed: false,
|
|
87
|
+
enabled: false,
|
|
88
|
+
knowledgeDomains: [],
|
|
89
|
+
actions: [],
|
|
90
|
+
interfaces: { openapi: false, mcp: false },
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const doc = input.doc;
|
|
95
|
+
const knowledge = Array.isArray(doc.knowledge) ? doc.knowledge : [];
|
|
96
|
+
const actions = Array.isArray(doc.actions) ? doc.actions : [];
|
|
97
|
+
const interfaces = (doc.interfaces ?? {}) as Record<string, unknown>;
|
|
98
|
+
|
|
99
|
+
return {
|
|
100
|
+
site: input.site,
|
|
101
|
+
baseUrl: asString(doc.baseUrl) ?? "",
|
|
102
|
+
surfaceVersion: asString(doc.surfaceVersion) ?? "",
|
|
103
|
+
contentHash: asString(doc.contentHash) ?? "",
|
|
104
|
+
signed: doc.proof != null,
|
|
105
|
+
enabled: true,
|
|
106
|
+
knowledgeDomains: knowledge
|
|
107
|
+
.map((ref) => asString((ref as Record<string, unknown>)?.domain))
|
|
108
|
+
.filter((d): d is string => typeof d === "string")
|
|
109
|
+
.sort((a, b) => a.localeCompare(b)),
|
|
110
|
+
actions: actions
|
|
111
|
+
.map((ref) => asString((ref as Record<string, unknown>)?.id))
|
|
112
|
+
.filter((d): d is string => typeof d === "string")
|
|
113
|
+
.sort((a, b) => a.localeCompare(b)),
|
|
114
|
+
interfaces: {
|
|
115
|
+
openapi: interfaces.openapi != null,
|
|
116
|
+
mcp: interfaces.mcp != null,
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Pure: (fleet sites × loaded discovery docs) → catalog.
|
|
123
|
+
* Missing doc ⇒ enabled: false entry.
|
|
124
|
+
* Sites are sorted by site id; entries are deterministic.
|
|
125
|
+
*/
|
|
126
|
+
export function buildFleetAgentCatalog(input: FleetAgentCatalogSiteInput[]): FleetAgentCatalog {
|
|
127
|
+
const sites = input
|
|
128
|
+
.slice()
|
|
129
|
+
.sort((a, b) => a.site.localeCompare(b.site))
|
|
130
|
+
.map(entryFromSiteInput);
|
|
131
|
+
|
|
132
|
+
const contentHash = createHash("sha256").update(canonicalJson(sites), "utf8").digest("hex");
|
|
133
|
+
|
|
134
|
+
return {
|
|
135
|
+
schema: FLEET_AGENT_CATALOG_SCHEMA,
|
|
136
|
+
contentHash,
|
|
137
|
+
sites,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Re-compute the catalog contentHash from a parsed catalog's sites array.
|
|
143
|
+
* Used by the validator to detect staleness/tampering (FAC-01).
|
|
144
|
+
*/
|
|
145
|
+
export function computeFleetCatalogContentHash(sites: unknown[]): string {
|
|
146
|
+
return createHash("sha256")
|
|
147
|
+
.update(JSON.stringify(sortKeysDeep(sites)), "utf8")
|
|
148
|
+
.digest("hex");
|
|
149
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/*
|
|
2
|
+
<MODULE_CONTRACT>
|
|
3
|
+
<purpose>
|
|
4
|
+
RFC-0286: barrel for the Agent Surface shared model. Re-exports the framework-free
|
|
5
|
+
manifest contract + canonicalization primitives; RFC-0287..0291 add sibling modules
|
|
6
|
+
here (knowledge, capability, openapi, proof) and re-export them from this barrel.
|
|
7
|
+
</purpose>
|
|
8
|
+
<non-goals>
|
|
9
|
+
<item>Do not add logic here — pure re-export barrel.</item>
|
|
10
|
+
</non-goals>
|
|
11
|
+
</MODULE_CONTRACT>
|
|
12
|
+
<CHANGE_SUMMARY>
|
|
13
|
+
<item>RFC-0286: initial barrel exporting the manifest module.</item>
|
|
14
|
+
<item>RFC-0292: re-export fleet-catalog module.</item>
|
|
15
|
+
<item>RFC-0783: re-export api-catalog and mcp-card modules.</item>
|
|
16
|
+
<item>RFC-0786: re-export dns-aid module.</item>
|
|
17
|
+
</CHANGE_SUMMARY>
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
export * from "./manifest.ts";
|
|
21
|
+
export * from "./knowledge.ts";
|
|
22
|
+
export * from "./capability.ts";
|
|
23
|
+
export * from "./openapi.ts";
|
|
24
|
+
export * from "./omit-empty.ts";
|
|
25
|
+
export * from "./proof.ts";
|
|
26
|
+
export * from "./fleet-catalog.ts";
|
|
27
|
+
export * from "./api-catalog.ts";
|
|
28
|
+
export * from "./mcp-card.ts";
|
|
29
|
+
export * from "./dns-aid.ts";
|