@adia-ai/gen-ui 0.8.37
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/CHANGELOG.md +26 -0
- package/README.md +77 -0
- package/compose/CHANGELOG.md +1707 -0
- package/compose/README.md +215 -0
- package/compose/core/artifacts.js +262 -0
- package/compose/core/context-store.js +218 -0
- package/compose/core/generator.d.ts +4 -0
- package/compose/core/generator.js +602 -0
- package/compose/core/pipeline/engine.js +289 -0
- package/compose/core/pipeline/types.js +91 -0
- package/compose/core/plan-primitives.js +120 -0
- package/compose/core/plan-turn.js +145 -0
- package/compose/core/reference.js +150 -0
- package/compose/core/state.js +15 -0
- package/compose/evals/harness.d.ts +4 -0
- package/compose/evals/harness.mjs +193 -0
- package/compose/index.d.ts +4 -0
- package/compose/index.js +16 -0
- package/compose/shared/validate-and-repair.js +122 -0
- package/compose/strategies/_shared/chunk-loader.js +282 -0
- package/compose/strategies/cascade.d.ts +67 -0
- package/compose/strategies/cascade.js +165 -0
- package/compose/strategies/escalation.d.ts +13 -0
- package/compose/strategies/escalation.js +132 -0
- package/compose/strategies/free-form-composer/index.js +254 -0
- package/compose/strategies/free-form-composer/system-prompt.js +205 -0
- package/compose/strategies/free-form-composer/transpile.js +279 -0
- package/compose/strategies/monolithic/_shared.js +1619 -0
- package/compose/strategies/monolithic/generate-instant.js +228 -0
- package/compose/strategies/monolithic/generate-pro.js +490 -0
- package/compose/strategies/monolithic/generate-thinking.js +206 -0
- package/compose/strategies/registry.d.ts +20 -0
- package/compose/strategies/registry.js +495 -0
- package/compose/strategies/zettel/_smoke.js +27 -0
- package/compose/strategies/zettel/chunk-composer.js +214 -0
- package/compose/strategies/zettel/chunk-refiner.js +582 -0
- package/compose/strategies/zettel/chunk-synthesizer.js +458 -0
- package/compose/strategies/zettel/composer.js +78 -0
- package/compose/strategies/zettel/composition-library.js +418 -0
- package/compose/strategies/zettel/generate.js +15 -0
- package/compose/strategies/zettel/generator-adapter.d.ts +4 -0
- package/compose/strategies/zettel/generator-adapter.js +242 -0
- package/compose/strategies/zettel/issue-reporter.js +607 -0
- package/compose/strategies/zettel/session-store.js +121 -0
- package/compose/strategies/zettel/state-cache.js +158 -0
- package/compose/transpiler/transpiler-maps.js +675 -0
- package/compose/transpiler/transpiler.d.ts +4 -0
- package/compose/transpiler/transpiler.js +962 -0
- package/corpus/CHANGELOG.md +1957 -0
- package/corpus/README.md +279 -0
- package/corpus/catalog-a2ui_0_9.d.ts +4 -0
- package/corpus/catalog-a2ui_0_9.json +29571 -0
- package/corpus/catalog-a2ui_0_9_rules.txt +1215 -0
- package/corpus/chunk-embeddings.d.ts +4 -0
- package/corpus/chunk-embeddings.json +1 -0
- package/corpus/chunks/_index.json +16658 -0
- package/corpus/chunks/_source-hashes.json +571 -0
- package/corpus/chunks/access-denied-with-request.json +124 -0
- package/corpus/chunks/access-request-form.json +166 -0
- package/corpus/chunks/access-request-pending.json +133 -0
- package/corpus/chunks/accordion-settings.json +176 -0
- package/corpus/chunks/achievement-badges.json +413 -0
- package/corpus/chunks/achievement-unlock.json +104 -0
- package/corpus/chunks/action-list-record-actions.json +84 -0
- package/corpus/chunks/activity-feed.json +390 -0
- package/corpus/chunks/admin-page-header-flush.json +83 -0
- package/corpus/chunks/admin-page-header-title-description.json +80 -0
- package/corpus/chunks/admin-page-header-with-actions.json +107 -0
- package/corpus/chunks/admin-page-header-with-tabs.json +144 -0
- package/corpus/chunks/admin-shell-rounded-borderless.json +287 -0
- package/corpus/chunks/admin-shell-standard.json +310 -0
- package/corpus/chunks/admin-sidebar-brand-signin.json +158 -0
- package/corpus/chunks/admin-sidebar-brand-version.json +130 -0
- package/corpus/chunks/admin-sidebar-flat-nav.json +131 -0
- package/corpus/chunks/admin-sidebar-nav-dividers.json +150 -0
- package/corpus/chunks/admin-sidebar-nav-groups.json +171 -0
- package/corpus/chunks/admin-sidebar-workspace-switcher.json +139 -0
- package/corpus/chunks/admin-topbar-breadcrumb-actions.json +130 -0
- package/corpus/chunks/admin-topbar-breadcrumb-minimal.json +79 -0
- package/corpus/chunks/admin-topbar-deep-breadcrumb.json +129 -0
- package/corpus/chunks/admin-topbar-search.json +104 -0
- package/corpus/chunks/admin-topbar-status-indicator.json +122 -0
- package/corpus/chunks/admin-topbar-trailing-toggle.json +114 -0
- package/corpus/chunks/agent-activity-feed.json +163 -0
- package/corpus/chunks/agent-artifact-stub-card.json +115 -0
- package/corpus/chunks/agent-canvas-shell.json +305 -0
- package/corpus/chunks/agent-citations-source-chips.json +82 -0
- package/corpus/chunks/agent-command-palette-search.json +120 -0
- package/corpus/chunks/agent-cost-detailed.json +260 -0
- package/corpus/chunks/agent-cost-inline.json +78 -0
- package/corpus/chunks/agent-memory-detail.json +181 -0
- package/corpus/chunks/agent-memory-editor.json +173 -0
- package/corpus/chunks/agent-memory-list.json +207 -0
- package/corpus/chunks/agent-pipeline-status-stages.json +61 -0
- package/corpus/chunks/agent-prompt-card.json +179 -0
- package/corpus/chunks/agent-prompt-library-grid.json +341 -0
- package/corpus/chunks/agent-prompt-picker.json +282 -0
- package/corpus/chunks/agent-rate-limit.json +100 -0
- package/corpus/chunks/agent-reasoning-collapsed.json +128 -0
- package/corpus/chunks/agent-tool-call-accordion.json +109 -0
- package/corpus/chunks/agent-tool-call-collapsed.json +98 -0
- package/corpus/chunks/agent-tool-call-error.json +112 -0
- package/corpus/chunks/agent-tool-call-result.json +145 -0
- package/corpus/chunks/agent-tool-call-running.json +85 -0
- package/corpus/chunks/agent-tool-call-success.json +137 -0
- package/corpus/chunks/agent-trace-timeline.json +244 -0
- package/corpus/chunks/ai-streaming-response.json +147 -0
- package/corpus/chunks/alert-banner-stack.json +78 -0
- package/corpus/chunks/alert-banner.json +55 -0
- package/corpus/chunks/alert-dialog-simple.json +72 -0
- package/corpus/chunks/alert-dialog-typed.json +107 -0
- package/corpus/chunks/alert-dialog-unsaved.json +81 -0
- package/corpus/chunks/analytics-chart.json +213 -0
- package/corpus/chunks/analytics-sparklines-dashboard.json +259 -0
- package/corpus/chunks/anchor-bar-selection-bar.json +226 -0
- package/corpus/chunks/api-key-table.json +148 -0
- package/corpus/chunks/api-keys-create.json +140 -0
- package/corpus/chunks/api-keys-list.json +271 -0
- package/corpus/chunks/app-nav-badges-counts.json +77 -0
- package/corpus/chunks/app-nav-badges-group-rollup-badges.json +100 -0
- package/corpus/chunks/app-nav-badges-plan-tiers.json +76 -0
- package/corpus/chunks/app-nav-badges-status-callouts.json +75 -0
- package/corpus/chunks/app-nav-full-example.json +195 -0
- package/corpus/chunks/app-nav-groups.json +103 -0
- package/corpus/chunks/app-nav-items.json +74 -0
- package/corpus/chunks/app-nav-labels-and-dividers.json +92 -0
- package/corpus/chunks/app-nav-spacer.json +77 -0
- package/corpus/chunks/app-product-listing-card.json +214 -0
- package/corpus/chunks/approvals-detail.json +240 -0
- package/corpus/chunks/approvals-queue.json +321 -0
- package/corpus/chunks/audit-log-basic.json +184 -0
- package/corpus/chunks/audit-log.json +174 -0
- package/corpus/chunks/auth-account-deleted-actions.json +51 -0
- package/corpus/chunks/auth-account-deleted.json +202 -0
- package/corpus/chunks/auth-card-content.json +260 -0
- package/corpus/chunks/auth-card-header.json +205 -0
- package/corpus/chunks/auth-email-entry.json +65 -0
- package/corpus/chunks/auth-email-verify-confirm.json +52 -0
- package/corpus/chunks/auth-email-verify.json +196 -0
- package/corpus/chunks/auth-forbidden-actions.json +59 -0
- package/corpus/chunks/auth-forbidden.json +203 -0
- package/corpus/chunks/auth-invite-actions.json +49 -0
- package/corpus/chunks/auth-invite-team-card.json +86 -0
- package/corpus/chunks/auth-link-expired-form.json +65 -0
- package/corpus/chunks/auth-link-expired.json +196 -0
- package/corpus/chunks/auth-locked-account.json +211 -0
- package/corpus/chunks/auth-locked-recovery-options.json +60 -0
- package/corpus/chunks/auth-mfa-enrollment-submit.json +54 -0
- package/corpus/chunks/auth-mfa-enrollment.json +284 -0
- package/corpus/chunks/auth-mfa-fallback-actions.json +52 -0
- package/corpus/chunks/auth-mfa-recovery.json +61 -0
- package/corpus/chunks/auth-new-password-form.json +75 -0
- package/corpus/chunks/auth-new-password.json +217 -0
- package/corpus/chunks/auth-oauth-fallback-actions.json +52 -0
- package/corpus/chunks/auth-oauth-interstitial.json +160 -0
- package/corpus/chunks/auth-password-challenge.json +94 -0
- package/corpus/chunks/auth-password-reset-form.json +64 -0
- package/corpus/chunks/auth-password-reset.json +195 -0
- package/corpus/chunks/auth-profile-form.json +72 -0
- package/corpus/chunks/auth-profile-setup.json +194 -0
- package/corpus/chunks/auth-reset-sent.json +188 -0
- package/corpus/chunks/auth-session-expired-actions.json +52 -0
- package/corpus/chunks/auth-session-expired.json +201 -0
- package/corpus/chunks/auth-signin-card-email.json +245 -0
- package/corpus/chunks/auth-signin-card-magic-link.json +147 -0
- package/corpus/chunks/auth-signin-card-mfa.json +231 -0
- package/corpus/chunks/auth-signin-card-otp.json +205 -0
- package/corpus/chunks/auth-signin-card-password.json +264 -0
- package/corpus/chunks/auth-signin-card-recovery.json +218 -0
- package/corpus/chunks/auth-signout-actions.json +51 -0
- package/corpus/chunks/auth-signout.json +184 -0
- package/corpus/chunks/auth-signup-email-entry.json +66 -0
- package/corpus/chunks/auth-signup-entry.json +281 -0
- package/corpus/chunks/auth-signup-social-auths.json +54 -0
- package/corpus/chunks/auth-signup-verify.json +227 -0
- package/corpus/chunks/auth-social-auths.json +62 -0
- package/corpus/chunks/auth-sso-providers.json +55 -0
- package/corpus/chunks/auth-sso-required.json +213 -0
- package/corpus/chunks/auth-team-invite.json +288 -0
- package/corpus/chunks/avatar-group-overflow.json +137 -0
- package/corpus/chunks/avatar-stack-overflow.json +124 -0
- package/corpus/chunks/banner-announcement-beta.json +99 -0
- package/corpus/chunks/banner-announcement-promo.json +102 -0
- package/corpus/chunks/banner-live-update.json +102 -0
- package/corpus/chunks/banner-system-maintenance.json +101 -0
- package/corpus/chunks/banner-system-offline.json +85 -0
- package/corpus/chunks/banner-system-update.json +102 -0
- package/corpus/chunks/bell-menu-empty.json +107 -0
- package/corpus/chunks/bell-menu-unread.json +395 -0
- package/corpus/chunks/billing-cancel-subscription-danger.json +61 -0
- package/corpus/chunks/billing-invoice-history-table.json +75 -0
- package/corpus/chunks/billing-overview.json +202 -0
- package/corpus/chunks/billing-payment-method-card-on-file.json +157 -0
- package/corpus/chunks/billing-progress-label.json +101 -0
- package/corpus/chunks/blog-post-card.json +212 -0
- package/corpus/chunks/breadcrumb-navigation.json +72 -0
- package/corpus/chunks/bulk-action-toolbar-floating.json +199 -0
- package/corpus/chunks/bulk-action-toolbar-swap.json +158 -0
- package/corpus/chunks/bulk-selection-actions-bar.json +162 -0
- package/corpus/chunks/business-address-form.json +953 -0
- package/corpus/chunks/calendar-month-view.json +74 -0
- package/corpus/chunks/card-grid-images.json +459 -0
- package/corpus/chunks/card-header-with-description.json +47 -0
- package/corpus/chunks/card-with-empty-state.json +96 -0
- package/corpus/chunks/card-with-form.json +143 -0
- package/corpus/chunks/card-with-sparkline.json +90 -0
- package/corpus/chunks/card-with-stat-kpi.json +86 -0
- package/corpus/chunks/changelog-feed-basic.json +470 -0
- package/corpus/chunks/chart-in-card-chart-plus-breakdown.json +188 -0
- package/corpus/chunks/chart-in-card-chart-plus-stat.json +89 -0
- package/corpus/chunks/chart-in-card-chart-with-filter-pills.json +124 -0
- package/corpus/chunks/chart-in-card-full-bleed-legend.json +116 -0
- package/corpus/chunks/chart-in-card-full-chart.json +107 -0
- package/corpus/chunks/chart-in-card-sparkline-tile.json +93 -0
- package/corpus/chunks/chart-in-card-stat-with-sparkline.json +73 -0
- package/corpus/chunks/chart-in-card-trend-footer.json +115 -0
- package/corpus/chunks/chart-with-filter-pills.json +169 -0
- package/corpus/chunks/chat-empty-state-hero.json +102 -0
- package/corpus/chunks/chat-message-assistant-byline.json +85 -0
- package/corpus/chunks/chat-message-user-byline.json +84 -0
- package/corpus/chunks/chat-page-shell.json +379 -0
- package/corpus/chunks/chat-streaming-surface.json +169 -0
- package/corpus/chunks/checkout-order-summary-card.json +140 -0
- package/corpus/chunks/code-snippet.json +107 -0
- package/corpus/chunks/col-form-stack.json +93 -0
- package/corpus/chunks/col-heading-body-action.json +79 -0
- package/corpus/chunks/col-stat-label.json +63 -0
- package/corpus/chunks/color-picker-swatches.json +153 -0
- package/corpus/chunks/command-palette.json +327 -0
- package/corpus/chunks/comments-composer.json +158 -0
- package/corpus/chunks/comments-mention-menu.json +237 -0
- package/corpus/chunks/comments-thread.json +344 -0
- package/corpus/chunks/commerce-pricing-tiers.json +401 -0
- package/corpus/chunks/comparison-table.json +246 -0
- package/corpus/chunks/contact-form-card.json +197 -0
- package/corpus/chunks/contact-form.json +157 -0
- package/corpus/chunks/contact-support-form.json +702 -0
- package/corpus/chunks/conversion-funnel-4-step-funnel.json +139 -0
- package/corpus/chunks/conversion-funnel-6step.json +151 -0
- package/corpus/chunks/conversion-funnel-wide-summary.json +192 -0
- package/corpus/chunks/conversion-funnel-with-segment-compare.json +202 -0
- package/corpus/chunks/cta-banner-centered.json +102 -0
- package/corpus/chunks/dashboard-acquisition-panel.json +212 -0
- package/corpus/chunks/dashboard-admin-page.json +104 -0
- package/corpus/chunks/dashboard-audience-kpis.json +165 -0
- package/corpus/chunks/dashboard-audience-panel.json +756 -0
- package/corpus/chunks/dashboard-behavior-panel.json +114 -0
- package/corpus/chunks/dashboard-chart-recent.json +566 -0
- package/corpus/chunks/dashboard-cohort-retention.json +83 -0
- package/corpus/chunks/dashboard-conversion-panel.json +234 -0
- package/corpus/chunks/dashboard-country-list.json +304 -0
- package/corpus/chunks/dashboard-filter-bar.json +118 -0
- package/corpus/chunks/dashboard-funnel.json +142 -0
- package/corpus/chunks/dashboard-notifications-panel.json +423 -0
- package/corpus/chunks/dashboard-overview-panel.json +1644 -0
- package/corpus/chunks/dashboard-page-header.json +166 -0
- package/corpus/chunks/dashboard-pages-table.json +86 -0
- package/corpus/chunks/dashboard-quick-actions.json +116 -0
- package/corpus/chunks/dashboard-reports-panel.json +166 -0
- package/corpus/chunks/dashboard-reports-table.json +138 -0
- package/corpus/chunks/dashboard-storage-card.json +117 -0
- package/corpus/chunks/dashboard-tabs.json +86 -0
- package/corpus/chunks/dashboard-team-actions-storage.json +605 -0
- package/corpus/chunks/dashboard-team-list.json +334 -0
- package/corpus/chunks/dashboard-traffic-channels.json +184 -0
- package/corpus/chunks/dashboard-transactions-table.json +145 -0
- package/corpus/chunks/data-export-history.json +192 -0
- package/corpus/chunks/data-export-request.json +197 -0
- package/corpus/chunks/data-import-wizard.json +391 -0
- package/corpus/chunks/date-range-picker.json +156 -0
- package/corpus/chunks/date-time-picker-form.json +222 -0
- package/corpus/chunks/departments-checkbox-form.json +390 -0
- package/corpus/chunks/destructive-confirm-modal.json +149 -0
- package/corpus/chunks/diff-inline.json +84 -0
- package/corpus/chunks/diff-side-by-side.json +131 -0
- package/corpus/chunks/diff-structured.json +216 -0
- package/corpus/chunks/digest-email-preview.json +374 -0
- package/corpus/chunks/divider-text-label.json +87 -0
- package/corpus/chunks/doc-editor-shell.json +356 -0
- package/corpus/chunks/drawer-2fa-key.json +273 -0
- package/corpus/chunks/drawer-2fa-sms.json +261 -0
- package/corpus/chunks/drawer-2fa-totp.json +385 -0
- package/corpus/chunks/drawer-cancel-sub.json +636 -0
- package/corpus/chunks/drawer-change-plan.json +561 -0
- package/corpus/chunks/drawer-custom-roles.json +696 -0
- package/corpus/chunks/drawer-data-start.json +171 -0
- package/corpus/chunks/drawer-delete-account.json +341 -0
- package/corpus/chunks/drawer-delete-workspace.json +362 -0
- package/corpus/chunks/drawer-discord.json +434 -0
- package/corpus/chunks/drawer-figma.json +401 -0
- package/corpus/chunks/drawer-first-dashboard.json +220 -0
- package/corpus/chunks/drawer-gcal.json +475 -0
- package/corpus/chunks/drawer-github.json +589 -0
- package/corpus/chunks/drawer-invite.json +397 -0
- package/corpus/chunks/drawer-record-detail.json +44 -0
- package/corpus/chunks/drawer-report.json +528 -0
- package/corpus/chunks/drawer-revoke-session.json +331 -0
- package/corpus/chunks/drawer-role.json +190 -0
- package/corpus/chunks/drawer-slack.json +429 -0
- package/corpus/chunks/drawer-smtp.json +476 -0
- package/corpus/chunks/drawer-source.json +294 -0
- package/corpus/chunks/drawer-transaction.json +493 -0
- package/corpus/chunks/drawer-with-create-form.json +43 -0
- package/corpus/chunks/editor-code-pane.json +204 -0
- package/corpus/chunks/editor-page-shell.json +149 -0
- package/corpus/chunks/editor-preview-pane.json +136 -0
- package/corpus/chunks/editor-statusbar-ready.json +99 -0
- package/corpus/chunks/editor-toolbar-import-export.json +195 -0
- package/corpus/chunks/email-inbox-list.json +678 -0
- package/corpus/chunks/empty-state-danger.json +58 -0
- package/corpus/chunks/empty-state-minimal.json +44 -0
- package/corpus/chunks/empty-state-warning.json +53 -0
- package/corpus/chunks/empty-state.json +65 -0
- package/corpus/chunks/error-404-actions.json +54 -0
- package/corpus/chunks/error-404.json +204 -0
- package/corpus/chunks/error-500-actions.json +61 -0
- package/corpus/chunks/error-500.json +220 -0
- package/corpus/chunks/error-maintenance-actions.json +53 -0
- package/corpus/chunks/error-maintenance.json +203 -0
- package/corpus/chunks/error-page-shell.json +132 -0
- package/corpus/chunks/export-flow-async.json +210 -0
- package/corpus/chunks/export-flow-delivery.json +163 -0
- package/corpus/chunks/export-flow-sync.json +162 -0
- package/corpus/chunks/extended-profile-form.json +512 -0
- package/corpus/chunks/faq-accordion.json +123 -0
- package/corpus/chunks/feature-grid-icons.json +314 -0
- package/corpus/chunks/feature-grid-three-cards.json +187 -0
- package/corpus/chunks/feature-toggle-switch-grid.json +213 -0
- package/corpus/chunks/file-upload-dnd.json +166 -0
- package/corpus/chunks/file-upload-field.json +97 -0
- package/corpus/chunks/file-upload-form.json +251 -0
- package/corpus/chunks/filter-bar-active-filters.json +176 -0
- package/corpus/chunks/filter-bar-filter-bar-with-table.json +113 -0
- package/corpus/chunks/filter-bar-saved-views.json +117 -0
- package/corpus/chunks/filter-popover-form.json +137 -0
- package/corpus/chunks/footer-multi-column.json +270 -0
- package/corpus/chunks/footer-primary-only.json +41 -0
- package/corpus/chunks/form-checkbox-group.json +65 -0
- package/corpus/chunks/form-drawer-edit-form.json +178 -0
- package/corpus/chunks/form-drawer-simple-form.json +151 -0
- package/corpus/chunks/form-drawer-tall-form.json +325 -0
- package/corpus/chunks/form-field-email-hint.json +53 -0
- package/corpus/chunks/form-field-range.json +54 -0
- package/corpus/chunks/form-field-required.json +52 -0
- package/corpus/chunks/form-field-select.json +66 -0
- package/corpus/chunks/form-field-textarea.json +51 -0
- package/corpus/chunks/form-field-with-error.json +151 -0
- package/corpus/chunks/form-fields-two-column.json +69 -0
- package/corpus/chunks/form-page-shell.json +146 -0
- package/corpus/chunks/form-switch-toggle.json +41 -0
- package/corpus/chunks/form-system-live-demo.json +123 -0
- package/corpus/chunks/forms-address-autocomplete.json +277 -0
- package/corpus/chunks/forms-address-fields.json +221 -0
- package/corpus/chunks/forms-conditional-reveal.json +195 -0
- package/corpus/chunks/gallery-page-shell.json +444 -0
- package/corpus/chunks/grid-2col-entry-cards.json +140 -0
- package/corpus/chunks/grid-kpi-4col.json +164 -0
- package/corpus/chunks/grid-responsive-kpi.json +165 -0
- package/corpus/chunks/hero-cta-simple.json +107 -0
- package/corpus/chunks/hero-cta-split.json +183 -0
- package/corpus/chunks/hero-section-split.json +111 -0
- package/corpus/chunks/icon-text-row.json +60 -0
- package/corpus/chunks/image-caption-tile.json +99 -0
- package/corpus/chunks/image-carousel.json +156 -0
- package/corpus/chunks/image-thumbnail-grid.json +77 -0
- package/corpus/chunks/image-upload-preview.json +118 -0
- package/corpus/chunks/import-mapping-flow.json +972 -0
- package/corpus/chunks/inline-dialog-rename.json +128 -0
- package/corpus/chunks/inline-dialog-schedule.json +154 -0
- package/corpus/chunks/inline-dialog-status.json +179 -0
- package/corpus/chunks/integrations-api-keys-card-list.json +475 -0
- package/corpus/chunks/integrations-connect-form.json +550 -0
- package/corpus/chunks/integrations-grid.json +141 -0
- package/corpus/chunks/integrations-webhooks-empty-state.json +66 -0
- package/corpus/chunks/inventory-list-stock.json +137 -0
- package/corpus/chunks/invite-members.json +153 -0
- package/corpus/chunks/invoice-line-items.json +493 -0
- package/corpus/chunks/kanban-board-3col.json +713 -0
- package/corpus/chunks/kanban-page-shell.json +671 -0
- package/corpus/chunks/key-value-detail-list.json +242 -0
- package/corpus/chunks/keyboard-shortcut-display.json +250 -0
- package/corpus/chunks/labeled-textarea.json +45 -0
- package/corpus/chunks/leaderboard-table.json +140 -0
- package/corpus/chunks/library-browser-search-filter.json +109 -0
- package/corpus/chunks/linked-record-row.json +61 -0
- package/corpus/chunks/loading-skeleton-placeholder.json +387 -0
- package/corpus/chunks/login-form-card.json +207 -0
- package/corpus/chunks/logo-cloud-trusted-by.json +235 -0
- package/corpus/chunks/map-with-location-list.json +293 -0
- package/corpus/chunks/marketing-hero-cta.json +102 -0
- package/corpus/chunks/marketing-page-shell.json +352 -0
- package/corpus/chunks/masonry-gallery.json +154 -0
- package/corpus/chunks/member-edit-drawer.json +236 -0
- package/corpus/chunks/members-active-table-search-filter.json +184 -0
- package/corpus/chunks/members-pending-invites-cards.json +251 -0
- package/corpus/chunks/members-roles-permissions-list.json +146 -0
- package/corpus/chunks/menu-context-actions.json +113 -0
- package/corpus/chunks/metadata-description-list.json +178 -0
- package/corpus/chunks/modal-create-project-form.json +133 -0
- package/corpus/chunks/modal-preferences-tabs.json +147 -0
- package/corpus/chunks/multi-field-form-validation.json +394 -0
- package/corpus/chunks/nav-menu-icons.json +74 -0
- package/corpus/chunks/newsletter-subscription.json +190 -0
- package/corpus/chunks/notification-badges-feed.json +411 -0
- package/corpus/chunks/notification-preferences-panel.json +238 -0
- package/corpus/chunks/onb-completion.json +139 -0
- package/corpus/chunks/onb-extension-install.json +172 -0
- package/corpus/chunks/onb-hero-welcome.json +156 -0
- package/corpus/chunks/onb-import-picker.json +86 -0
- package/corpus/chunks/onb-mobile-handoff.json +121 -0
- package/corpus/chunks/onb-notification-prefs.json +83 -0
- package/corpus/chunks/onb-persona-picker.json +82 -0
- package/corpus/chunks/onb-provider-tiles.json +137 -0
- package/corpus/chunks/onb-settings-review.json +257 -0
- package/corpus/chunks/onb-step-footer.json +121 -0
- package/corpus/chunks/onb-step-header.json +121 -0
- package/corpus/chunks/onb-step-progress.json +140 -0
- package/corpus/chunks/onb-step-shell.json +380 -0
- package/corpus/chunks/onb-story-pane.json +121 -0
- package/corpus/chunks/onb-tutorial-steps.json +193 -0
- package/corpus/chunks/order-confirmation-success-card.json +177 -0
- package/corpus/chunks/order-tracking-timeline.json +131 -0
- package/corpus/chunks/pagination-controls.json +82 -0
- package/corpus/chunks/pane-settings-sidebar.json +204 -0
- package/corpus/chunks/patient-visit-shell.json +191 -0
- package/corpus/chunks/payment-checkout-form.json +341 -0
- package/corpus/chunks/payment-method-form.json +328 -0
- package/corpus/chunks/period-comparison.json +236 -0
- package/corpus/chunks/permission-matrix-table.json +438 -0
- package/corpus/chunks/permissions-matrix-grid.json +111 -0
- package/corpus/chunks/permissions-matrix-summary.json +157 -0
- package/corpus/chunks/permissions-role-picker-radio.json +107 -0
- package/corpus/chunks/permissions-role-picker-select.json +101 -0
- package/corpus/chunks/permissions-share-link.json +256 -0
- package/corpus/chunks/permissions-share-people.json +297 -0
- package/corpus/chunks/permissions-sharing-scopes.json +109 -0
- package/corpus/chunks/plan-selection-form.json +529 -0
- package/corpus/chunks/playground-a2ui.json +181 -0
- package/corpus/chunks/playground-agent-admin.json +117 -0
- package/corpus/chunks/playground-agent-chat.json +126 -0
- package/corpus/chunks/playground-app-shell.json +488 -0
- package/corpus/chunks/playground-chat.json +265 -0
- package/corpus/chunks/playground-construct-canvas.json +118 -0
- package/corpus/chunks/playground-css-channel.json +487 -0
- package/corpus/chunks/playground-gen-ui.json +224 -0
- package/corpus/chunks/playground-render-preview.json +369 -0
- package/corpus/chunks/playground-streams-bridge.json +437 -0
- package/corpus/chunks/playground-table-toolbar.json +38 -0
- package/corpus/chunks/popover-with-content.json +118 -0
- package/corpus/chunks/pricing-tiers.json +561 -0
- package/corpus/chunks/product-tour.json +158 -0
- package/corpus/chunks/profile-public.json +297 -0
- package/corpus/chunks/progress-tracker-milestones.json +294 -0
- package/corpus/chunks/radio-button-group.json +83 -0
- package/corpus/chunks/rating-stars-review-summary.json +259 -0
- package/corpus/chunks/reactions-bar.json +75 -0
- package/corpus/chunks/reactions-picker.json +245 -0
- package/corpus/chunks/real-time-metrics-dashboard.json +344 -0
- package/corpus/chunks/record-detail-drawer-simple-detail.json +296 -0
- package/corpus/chunks/record-detail-drawer-tabbed-detail.json +443 -0
- package/corpus/chunks/referral-share-link.json +128 -0
- package/corpus/chunks/referral-status.json +243 -0
- package/corpus/chunks/reg-address-form.json +825 -0
- package/corpus/chunks/reg-billing-card.json +210 -0
- package/corpus/chunks/reg-brand-scrape.json +599 -0
- package/corpus/chunks/reg-departments-toggle.json +259 -0
- package/corpus/chunks/reg-extended-profile.json +356 -0
- package/corpus/chunks/reg-final-done.json +457 -0
- package/corpus/chunks/reg-helpdesk-grid.json +571 -0
- package/corpus/chunks/reg-import-picker.json +112 -0
- package/corpus/chunks/reg-integrations-grid.json +418 -0
- package/corpus/chunks/reg-invite-form.json +245 -0
- package/corpus/chunks/reg-legal-entity.json +260 -0
- package/corpus/chunks/reg-org-chart-review.json +891 -0
- package/corpus/chunks/reg-profile-identity.json +188 -0
- package/corpus/chunks/reg-step-footer.json +201 -0
- package/corpus/chunks/reg-step-header.json +201 -0
- package/corpus/chunks/reg-step-progress.json +236 -0
- package/corpus/chunks/reg-step-shell.json +605 -0
- package/corpus/chunks/reg-story-pane.json +201 -0
- package/corpus/chunks/reg-success-summary.json +257 -0
- package/corpus/chunks/reg-team-size.json +128 -0
- package/corpus/chunks/reg-usecase-picker.json +104 -0
- package/corpus/chunks/reg-workspace-name.json +159 -0
- package/corpus/chunks/responsive-grid-pattern.json +71 -0
- package/corpus/chunks/responsive-kpi-grid.json +166 -0
- package/corpus/chunks/responsive-row-pattern.json +71 -0
- package/corpus/chunks/responsive-shell-sidebar.json +308 -0
- package/corpus/chunks/responsive-wrap-at-pattern.json +124 -0
- package/corpus/chunks/retention-cohort-default-retention.json +80 -0
- package/corpus/chunks/retention-cohort-stat-pair.json +163 -0
- package/corpus/chunks/retention-cohort-with-legend.json +135 -0
- package/corpus/chunks/revenue-heatmap.json +82 -0
- package/corpus/chunks/role-management.json +272 -0
- package/corpus/chunks/row-action-cluster.json +54 -0
- package/corpus/chunks/row-avatar-name-role.json +71 -0
- package/corpus/chunks/row-icon-label.json +52 -0
- package/corpus/chunks/row-spread-label-value.json +54 -0
- package/corpus/chunks/row-wrap-tags.json +72 -0
- package/corpus/chunks/schedule-meeting-form-card.json +229 -0
- package/corpus/chunks/search-recents-menu.json +195 -0
- package/corpus/chunks/search-results-grouped.json +357 -0
- package/corpus/chunks/search-results-list.json +202 -0
- package/corpus/chunks/search-saved-views.json +356 -0
- package/corpus/chunks/search-with-filters.json +311 -0
- package/corpus/chunks/searchable-picker-modal.json +164 -0
- package/corpus/chunks/section-with-stack.json +48 -0
- package/corpus/chunks/security-active-sessions-devices.json +287 -0
- package/corpus/chunks/security-change-password-form.json +102 -0
- package/corpus/chunks/security-delete-account-danger.json +79 -0
- package/corpus/chunks/segmented-control-billing-tabs.json +164 -0
- package/corpus/chunks/select-multiple-preselected.json +70 -0
- package/corpus/chunks/settings-2fa-setup.json +307 -0
- package/corpus/chunks/settings-admin-page.json +1205 -0
- package/corpus/chunks/settings-appearance-primitives.json +145 -0
- package/corpus/chunks/settings-appearance-theme-panel.json +55 -0
- package/corpus/chunks/settings-appearance.json +81 -0
- package/corpus/chunks/settings-danger-zone-delete-workspace.json +93 -0
- package/corpus/chunks/settings-general-form.json +69 -0
- package/corpus/chunks/settings-integrations.json +298 -0
- package/corpus/chunks/settings-members-invite.json +112 -0
- package/corpus/chunks/settings-notification-activity-checkboxes.json +108 -0
- package/corpus/chunks/settings-notification-channels-switches.json +101 -0
- package/corpus/chunks/settings-page-shell.json +190 -0
- package/corpus/chunks/settings-privacy.json +83 -0
- package/corpus/chunks/settings-profile-security.json +122 -0
- package/corpus/chunks/settings-toggle-switches.json +66 -0
- package/corpus/chunks/sidebar-nav.json +120 -0
- package/corpus/chunks/sidebar-navigation-panel.json +165 -0
- package/corpus/chunks/signup-form-card.json +218 -0
- package/corpus/chunks/signup-team-size-form.json +259 -0
- package/corpus/chunks/single-select-card-form.json +231 -0
- package/corpus/chunks/slider-range-controls.json +119 -0
- package/corpus/chunks/social-media-post-card.json +159 -0
- package/corpus/chunks/sortable-list.json +307 -0
- package/corpus/chunks/sortable-search-paginate-table.json +162 -0
- package/corpus/chunks/split-pane-editor.json +146 -0
- package/corpus/chunks/stack-avatar-badge-overlay.json +53 -0
- package/corpus/chunks/stack-image-shimmer.json +51 -0
- package/corpus/chunks/stat-cards-kpi-dashboard.json +178 -0
- package/corpus/chunks/stats-band-big-numbers.json +175 -0
- package/corpus/chunks/status-dashboard.json +282 -0
- package/corpus/chunks/stepper-form-wizard.json +165 -0
- package/corpus/chunks/subscription-status-renewal-card.json +285 -0
- package/corpus/chunks/survey-rating-form.json +165 -0
- package/corpus/chunks/swiper-product-carousel.json +349 -0
- package/corpus/chunks/swiper-testimonial-carousel.json +279 -0
- package/corpus/chunks/table-empty-state.json +116 -0
- package/corpus/chunks/table-inline-edit-row.json +269 -0
- package/corpus/chunks/table-spreadsheet-cells.json +334 -0
- package/corpus/chunks/table-toolbar-no-search.json +42 -0
- package/corpus/chunks/table-toolbar-with-table.json +208 -0
- package/corpus/chunks/table-with-toolbar-card.json +80 -0
- package/corpus/chunks/tabs-with-panels.json +187 -0
- package/corpus/chunks/tag-chips-filter.json +100 -0
- package/corpus/chunks/team-invite-form.json +380 -0
- package/corpus/chunks/team-members-list.json +341 -0
- package/corpus/chunks/testimonial-grid.json +269 -0
- package/corpus/chunks/testimonial-pull-quote.json +137 -0
- package/corpus/chunks/testimonials-avatar-cards.json +286 -0
- package/corpus/chunks/timeline-events.json +89 -0
- package/corpus/chunks/timezone-selector-basic.json +99 -0
- package/corpus/chunks/timezone-selector-preview.json +104 -0
- package/corpus/chunks/toolbar-icons.json +216 -0
- package/corpus/chunks/toolbar-rich-text-editor.json +230 -0
- package/corpus/chunks/toolbar-tooltips.json +191 -0
- package/corpus/chunks/tooltip-hover-button.json +106 -0
- package/corpus/chunks/tree-file-explorer.json +136 -0
- package/corpus/chunks/tree-table-basic.json +171 -0
- package/corpus/chunks/trial-banner.json +158 -0
- package/corpus/chunks/url-import-form.json +728 -0
- package/corpus/chunks/usage-quota-meter-card.json +217 -0
- package/corpus/chunks/user-identity-row.json +81 -0
- package/corpus/chunks/user-onboarding-checklist.json +301 -0
- package/corpus/chunks/user-profile-card.json +192 -0
- package/corpus/chunks/users-table-badge.json +135 -0
- package/corpus/chunks/verification-document-upload.json +179 -0
- package/corpus/chunks/verification-status.json +97 -0
- package/corpus/chunks/verification-stepper.json +111 -0
- package/corpus/chunks/video-player-controls.json +120 -0
- package/corpus/chunks/webhook-config.json +209 -0
- package/corpus/chunks/webhooks-list.json +204 -0
- package/corpus/chunks/wizard-drawer-three-step-wizard.json +443 -0
- package/corpus/manifest.d.ts +4 -0
- package/corpus/manifest.json +6 -0
- package/corpus/scripts/chunk-library.d.ts +4 -0
- package/corpus/scripts/chunk-library.js +335 -0
- package/node-shims.d.ts +48 -0
- package/package.json +215 -0
- package/retrieval/CHANGELOG.md +1073 -0
- package/retrieval/README.md +71 -0
- package/retrieval/anti-patterns.js +189 -0
- package/retrieval/authoring/index.d.ts +4 -0
- package/retrieval/authoring/index.js +9 -0
- package/retrieval/authoring/web-research.js +220 -0
- package/retrieval/catalog.js +250 -0
- package/retrieval/component-catalog.js +168 -0
- package/retrieval/component-entry.js +80 -0
- package/retrieval/context-assembler.js +174 -0
- package/retrieval/domain-router.js +417 -0
- package/retrieval/embedding/chunk-embedding-retriever.js +117 -0
- package/retrieval/embedding/embedding-provider.js +72 -0
- package/retrieval/embedding/index.d.ts +4 -0
- package/retrieval/embedding/index.js +2 -0
- package/retrieval/feedback/dialog-recorder.js +107 -0
- package/retrieval/feedback/feedback-analyzer.js +180 -0
- package/retrieval/feedback/feedback-store.js +194 -0
- package/retrieval/feedback/feedback.js +117 -0
- package/retrieval/feedback/gap-registry.js +80 -0
- package/retrieval/feedback/human-signal.js +113 -0
- package/retrieval/feedback/index.d.ts +4 -0
- package/retrieval/feedback/index.js +24 -0
- package/retrieval/feedback/submit-feedback.js +45 -0
- package/retrieval/index.d.ts +4 -0
- package/retrieval/index.js +53 -0
- package/retrieval/intent/clarity.js +139 -0
- package/retrieval/intent/decomposer.js +124 -0
- package/retrieval/intent/index.d.ts +4 -0
- package/retrieval/intent/index.js +18 -0
- package/retrieval/intent/intent-alignment.js +172 -0
- package/retrieval/intent/intent-categorizer.js +69 -0
- package/retrieval/intent/intent-gate.js +96 -0
- package/retrieval/intent/prompt-analyzer.js +162 -0
- package/retrieval/wiring-catalog.js +168 -0
- package/validate/catalog-validator.d.ts +4 -0
- package/validate/catalog-validator.js +327 -0
- package/validate/semantic/cache.js +54 -0
- package/validate/semantic/classify-intent.js +128 -0
- package/validate/semantic/index.js +163 -0
- package/validate/semantic/intent-specs.js +162 -0
- package/validate/semantic/judge.js +180 -0
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
# @adia-ai/a2ui-compose
|
|
2
|
+
|
|
3
|
+
Framework-agnostic UI generation engine. Constitution doc:
|
|
4
|
+
[`.claude/docs/specs/compose-constitution.md`](../../../.claude/docs/specs/compose-constitution.md).
|
|
5
|
+
Takes a natural-language intent +
|
|
6
|
+
an A2UI component catalog and produces a tree of A2UI protocol messages
|
|
7
|
+
ready for a renderer.
|
|
8
|
+
|
|
9
|
+
> This package is pipeline runtime only. UI components live in
|
|
10
|
+
> [`@adia-ai/web-components`](../../web-components); the A2UI runtime (renderer,
|
|
11
|
+
> registry, streams, wiring) in [`@adia-ai/a2ui-runtime`](../../a2ui);
|
|
12
|
+
> the pattern corpus in [`@adia-ai/a2ui-corpus`](../corpus);
|
|
13
|
+
> the MCP server in [`@adia-ai/mcp`](../../mcp) (its `gen-ui` surface).
|
|
14
|
+
>
|
|
15
|
+
> Published to the public `@adia-ai` scope on 2026-04-24 alongside
|
|
16
|
+
> `a2ui-corpus`, `a2ui-mcp`, `a2ui-retrieval`, and `a2ui-validator`.
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install @adia-ai/a2ui-compose
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Typically paired with `@adia-ai/a2ui-corpus` (the pattern corpus the engine reads from) and `@adia-ai/llm` (the LLM client; runtime peer-dep):
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install @adia-ai/a2ui-compose @adia-ai/a2ui-corpus @adia-ai/llm
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## What it does
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
intent ─▶ classify ─▶ retrieve ─▶ compose / adapt ─▶ validate ─▶ A2UI
|
|
34
|
+
(concepts) (patterns) (engine-specific) (score ≥70) JSON
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
One entry point, two generation strategies, pluggable LLM back-end.
|
|
38
|
+
|
|
39
|
+
```javascript
|
|
40
|
+
import { generateUI } from '@adia-ai/a2ui-compose/core';
|
|
41
|
+
|
|
42
|
+
const result = await generateUI({
|
|
43
|
+
intent: 'login form with email, password, and remember-me',
|
|
44
|
+
engine: 'zettel', // 'monolithic' | 'zettel' | 'free-form' | 'chunk-zettel' | 'auto'
|
|
45
|
+
mode: 'pro', // monolithic only: instant | pro | thinking
|
|
46
|
+
model: 'claude-sonnet-4-7',
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// result.components — A2UI message array
|
|
50
|
+
// result.validation — { score, checks, warnings }
|
|
51
|
+
// result.debug — pattern matches, LLM prompt, token usage, …
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Layout
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
a2ui-compose/
|
|
58
|
+
├── core/ orchestrator — state, dispatch, pipeline (formerly engine/)
|
|
59
|
+
│ ├── generator.js generateUI() — the one public entry point
|
|
60
|
+
│ ├── state.js ArtifactStore + PipelineEngine singletons
|
|
61
|
+
│ └── pipeline/ 6-stage pipeline engine
|
|
62
|
+
│
|
|
63
|
+
├── strategies/ pluggable engines via registerEngine() (formerly engines/)
|
|
64
|
+
│ ├── registry.js engine selector + reserved-name guard
|
|
65
|
+
│ ├── cascade.js the escalation ladder as an @adia-ai/agent workflow
|
|
66
|
+
│ ├── escalation.js the one hit-or-climb rule the ladder reads
|
|
67
|
+
│ ├── monolithic/ pattern-match + LLM-adapt (3 modes)
|
|
68
|
+
│ │ ├── generate-instant.js no LLM — pattern-match only
|
|
69
|
+
│ │ ├── generate-pro.js pattern + LLM adaptation, non-streaming
|
|
70
|
+
│ │ └── generate-thinking.js streaming LLM + repair loop
|
|
71
|
+
│ └── zettel/ fragment-graph composition
|
|
72
|
+
│ ├── generator-adapter.js entry point
|
|
73
|
+
│ ├── composer.js assembles fragments → compositions
|
|
74
|
+
│ └── session-store.js multi-turn state (Phase A)
|
|
75
|
+
│
|
|
76
|
+
├── retrieval/
|
|
77
|
+
│ ├── catalog.js loads component schemas from sibling .a2ui.json
|
|
78
|
+
│ ├── pattern-library.js keyword-ranked pattern search (corpus + embeddings)
|
|
79
|
+
│ ├── fragments.js atomic-shape lookup for zettel
|
|
80
|
+
│ ├── anti-patterns.js catalog of canonical anti-patterns
|
|
81
|
+
│ └── feedback-store.js accumulates user feedback → disk
|
|
82
|
+
│
|
|
83
|
+
├── llm/
|
|
84
|
+
│ ├── llm-bridge.js unified adapter (Anthropic / OpenAI / Gemini)
|
|
85
|
+
│ ├── env.js Vite + Node env-var routing
|
|
86
|
+
│ └── prompts/ system prompts per engine mode
|
|
87
|
+
│
|
|
88
|
+
├── validation/
|
|
89
|
+
│ └── validator.js 15-check A2UI validator, weighted 0–100 score
|
|
90
|
+
│
|
|
91
|
+
├── intelligence/ intent classification + concept extraction
|
|
92
|
+
│ ├── classifier.js
|
|
93
|
+
│ ├── concepts.js
|
|
94
|
+
│ └── steelman.js
|
|
95
|
+
│
|
|
96
|
+
└── evals/
|
|
97
|
+
└── harness.mjs held-out intent benchmark runner
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Engines
|
|
101
|
+
|
|
102
|
+
**Monolithic** — pattern-match against full-canvas templates, optionally
|
|
103
|
+
adapt via LLM. Three modes:
|
|
104
|
+
|
|
105
|
+
| Mode | LLM? | Speed | Use for |
|
|
106
|
+
|------------|------|--------|-------------------------------------------------|
|
|
107
|
+
| `instant` | no | <50ms | High-confidence intents with exact pattern hit |
|
|
108
|
+
| `pro` | yes | ~2s | Most requests — adapt a template to the intent |
|
|
109
|
+
| `thinking` | yes | ~5s | Complex requests; streams + runs a repair loop |
|
|
110
|
+
|
|
111
|
+
**Zettel** — fragment-graph composition. Retrieves atomic fragments
|
|
112
|
+
(form-field, card-header, action-row, …) by keyword + concept-tag overlap
|
|
113
|
+
and assembles them into compositions. Verbatim retrieval above a threshold
|
|
114
|
+
(score ≥ 40); LLM synthesis from fragments below. Preserves session state
|
|
115
|
+
across multi-turn iterations.
|
|
116
|
+
|
|
117
|
+
```javascript
|
|
118
|
+
import { registerEngine } from '@adia-ai/a2ui-compose/strategies/registry';
|
|
119
|
+
|
|
120
|
+
registerEngine('my-engine', async (ctx) => {
|
|
121
|
+
// ctx: intent, catalog, patterns, concepts, session, llm, …
|
|
122
|
+
return { components: [...], validation: {...}, debug: {...} };
|
|
123
|
+
});
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
**Auto** — the escalation ladder over the engines above: `zettel` →
|
|
127
|
+
`free-form` → `monolithic-instant` → `monolithic-pro`, cheapest first, each
|
|
128
|
+
step accepted or rejected by the shared escalation rule
|
|
129
|
+
(`strategies/escalation.js`) and the last step terminal. It is declared as an
|
|
130
|
+
[`@adia-ai/agent`](../../agent/README.md) workflow in
|
|
131
|
+
`strategies/cascade.js`, so the ladder is data — `ENGINE_LADDER` — and the
|
|
132
|
+
result carries `escalations` (`{from, to, trigger}`) as its trace.
|
|
133
|
+
|
|
134
|
+
```javascript
|
|
135
|
+
const result = await generateUI({ intent, engine: 'auto' });
|
|
136
|
+
result.engine; // the engine that won
|
|
137
|
+
result.escalations; // [{ from: 'zettel', to: 'free-form', trigger: 'non-emission-strategy' }]
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Pass `gate` on the context for an extra async accept check (a schema +
|
|
141
|
+
catalog exit gate); pass `ladder` to run a different tier order.
|
|
142
|
+
|
|
143
|
+
Reserved names: `monolithic`, `monolithic-*`, `zettel`, `chunk-zettel`,
|
|
144
|
+
`free-form`, `auto`.
|
|
145
|
+
|
|
146
|
+
## Validation
|
|
147
|
+
|
|
148
|
+
Every generated output runs through `validation/validator.js` — 15 weighted
|
|
149
|
+
checks covering structural validity, card/grid conventions, intent
|
|
150
|
+
alignment (F1), and anti-patterns. Result:
|
|
151
|
+
|
|
152
|
+
```javascript
|
|
153
|
+
{
|
|
154
|
+
score: 92, // 0-100
|
|
155
|
+
passed: true, // score ≥ 70
|
|
156
|
+
checks: [
|
|
157
|
+
{ id: 'structure', ok: true, weight: 10 },
|
|
158
|
+
{ id: 'intent-f1', ok: true, weight: 8, value: 0.84 },
|
|
159
|
+
{ id: 'card-grid', ok: true, weight: 6 },
|
|
160
|
+
{ id: 'anti-pattern', ok: false, weight: 4, hit: 'chart-legend' },
|
|
161
|
+
…
|
|
162
|
+
]
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
`_fallback` surfaces score 0 by design — ensure the engine returns real
|
|
167
|
+
output, not a safety net.
|
|
168
|
+
|
|
169
|
+
## LLM bridge
|
|
170
|
+
|
|
171
|
+
Multi-provider adapter with a common interface:
|
|
172
|
+
|
|
173
|
+
```javascript
|
|
174
|
+
import { getAdapter } from '@adia-ai/llm';
|
|
175
|
+
|
|
176
|
+
const adapter = getAdapter('anthropic'); // or 'openai', 'gemini'
|
|
177
|
+
const stream = await adapter.streamChat({ model, messages, tools });
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Env-var routing via `llm/env.js` — works under Node (`process.env`) and
|
|
181
|
+
Vite (`import.meta.env`). Browser calls proxy through `server.js` at the
|
|
182
|
+
repo root (holds API keys); Node calls go direct.
|
|
183
|
+
|
|
184
|
+
## Evals
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
npm run evals # held-out intent benchmark
|
|
188
|
+
npm run eval:diff -- --engine zettel # diff against baseline
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
The held-out fixture lives in `@adia-ai/a2ui-corpus`'s `evals/held-out.jsonl`.
|
|
192
|
+
Regression thresholds the pipeline must hold:
|
|
193
|
+
|
|
194
|
+
- Zettel coverage **100%**, avgScore **≥ 88**, MRR **≥ 0.94**
|
|
195
|
+
- Monolithic coverage **100%**, avgScore **≥ 95**
|
|
196
|
+
- Fragment reuse ratio **≥ 29.9%** (167 refs / 559 nodes)
|
|
197
|
+
|
|
198
|
+
Full gate sweep: see `AGENTS.md` at repo root, or run `/verification-sweep`.
|
|
199
|
+
|
|
200
|
+
## Gotchas
|
|
201
|
+
|
|
202
|
+
- **Component catalog is read-only.** `.a2ui.json` sidecars in
|
|
203
|
+
`web-components/components/*/` are build outputs; edit the sibling YAML
|
|
204
|
+
instead.
|
|
205
|
+
- **Zettel loading is lazy.** The corpus is only parsed on first zettel
|
|
206
|
+
call — avoids Node `fs`/`path` imports reaching the browser bundle.
|
|
207
|
+
- **Validator score ≥ 70 is required** for downstream consumers to trust
|
|
208
|
+
the output. Below that, callers should treat the tree as advisory.
|
|
209
|
+
- **Engine name reservations** are enforced at registration time —
|
|
210
|
+
`registerEngine('zettel-v2', …)` passes; `registerEngine('zettel', …)`
|
|
211
|
+
throws.
|
|
212
|
+
|
|
213
|
+
## License
|
|
214
|
+
|
|
215
|
+
MIT
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ArtifactStore — In-memory artifact storage for pipeline executions.
|
|
3
|
+
*
|
|
4
|
+
* Stores A2UI message sequences keyed by executionId, with multi-turn
|
|
5
|
+
* history (iterations). Each turn records the messages, optional HTML
|
|
6
|
+
* render, a human-readable summary, and the intent that produced it.
|
|
7
|
+
*
|
|
8
|
+
* Drift detection: measures structural divergence between turns to flag
|
|
9
|
+
* scope creep in iterative generation sessions.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
export class ArtifactStore {
|
|
13
|
+
#artifacts = new Map(); // executionId → { turns: [], metadata }
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Record a turn (iteration) for an execution.
|
|
17
|
+
*
|
|
18
|
+
* @param {string} executionId
|
|
19
|
+
* @param {object} opts
|
|
20
|
+
* @param {object[]} opts.messages — A2UI message sequence
|
|
21
|
+
* @param {string} [opts.html] — Optional rendered HTML snapshot
|
|
22
|
+
* @param {string} [opts.summary] — Human-readable description
|
|
23
|
+
* @param {object} [opts.validation] — Validation result from validateSchema
|
|
24
|
+
* @param {string} [opts.intent] — The user intent for this turn
|
|
25
|
+
*/
|
|
26
|
+
record(executionId, { messages, html = null, summary = '', validation = null, intent = '', analysis = null }) {
|
|
27
|
+
let artifact = this.#artifacts.get(executionId);
|
|
28
|
+
if (!artifact) {
|
|
29
|
+
artifact = {
|
|
30
|
+
executionId,
|
|
31
|
+
turns: [],
|
|
32
|
+
metadata: {
|
|
33
|
+
created: Date.now(),
|
|
34
|
+
updated: Date.now(),
|
|
35
|
+
originalIntent: intent || summary || '',
|
|
36
|
+
// Stash the first turn's analyzer output so iteration turns can
|
|
37
|
+
// recover the original brief's concepts/entities/components for
|
|
38
|
+
// canvas-aware downstream decisions (e.g. suggestion generation,
|
|
39
|
+
// drift detection). Iteration turns skip the analyzer, so this is
|
|
40
|
+
// the only durable handle on what the user originally asked for.
|
|
41
|
+
originalAnalysis: analysis || null,
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
this.#artifacts.set(executionId, artifact);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Extract structural snapshot for drift tracking
|
|
48
|
+
const components = messages?.flatMap(m => m.components || []) || [];
|
|
49
|
+
const snapshot = _buildStructuralSnapshot(components);
|
|
50
|
+
|
|
51
|
+
artifact.turns.push({
|
|
52
|
+
turn: artifact.turns.length,
|
|
53
|
+
messages,
|
|
54
|
+
html,
|
|
55
|
+
summary,
|
|
56
|
+
validation,
|
|
57
|
+
intent: intent || summary || '',
|
|
58
|
+
snapshot,
|
|
59
|
+
timestamp: Date.now(),
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
artifact.metadata.updated = Date.now();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Get a specific turn for an execution.
|
|
67
|
+
*
|
|
68
|
+
* @param {string} executionId
|
|
69
|
+
* @param {number} [turn=-1] — Turn index (negative counts from end; -1 = latest)
|
|
70
|
+
* @returns {object|null}
|
|
71
|
+
*/
|
|
72
|
+
get(executionId, turn = -1) {
|
|
73
|
+
const artifact = this.#artifacts.get(executionId);
|
|
74
|
+
if (!artifact || artifact.turns.length === 0) return null;
|
|
75
|
+
|
|
76
|
+
const idx = turn < 0 ? artifact.turns.length + turn : turn;
|
|
77
|
+
return artifact.turns[idx] ?? null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Get all turns for an execution.
|
|
82
|
+
*
|
|
83
|
+
* @param {string} executionId
|
|
84
|
+
* @returns {object[]|null}
|
|
85
|
+
*/
|
|
86
|
+
getAll(executionId) {
|
|
87
|
+
const artifact = this.#artifacts.get(executionId);
|
|
88
|
+
if (!artifact) return null;
|
|
89
|
+
return [...artifact.turns];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Get the original (first turn) prompt analyzer output for an execution.
|
|
94
|
+
* Used by iteration turns that need to recover the original concepts /
|
|
95
|
+
* implied components / steelman to drive canvas-aware decisions.
|
|
96
|
+
* @param {string} executionId
|
|
97
|
+
* @returns {object|null}
|
|
98
|
+
*/
|
|
99
|
+
getOriginalAnalysis(executionId) {
|
|
100
|
+
const artifact = this.#artifacts.get(executionId);
|
|
101
|
+
return artifact?.metadata?.originalAnalysis || null;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Get the original (first turn) intent for an execution.
|
|
106
|
+
* @param {string} executionId
|
|
107
|
+
* @returns {string|null}
|
|
108
|
+
*/
|
|
109
|
+
getOriginalIntent(executionId) {
|
|
110
|
+
const artifact = this.#artifacts.get(executionId);
|
|
111
|
+
return artifact?.metadata?.originalIntent || null;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Compute drift metrics between the first turn and the latest turn.
|
|
116
|
+
*
|
|
117
|
+
* Returns null if there are fewer than 2 turns.
|
|
118
|
+
*
|
|
119
|
+
* @param {string} executionId
|
|
120
|
+
* @returns {{ componentGrowth: number, sectionGrowth: number, newSections: string[], driftScore: number, turnCount: number, warning: string|null }|null}
|
|
121
|
+
*/
|
|
122
|
+
getDriftMetrics(executionId) {
|
|
123
|
+
const artifact = this.#artifacts.get(executionId);
|
|
124
|
+
if (!artifact || artifact.turns.length < 2) return null;
|
|
125
|
+
|
|
126
|
+
const first = artifact.turns[0].snapshot;
|
|
127
|
+
const latest = artifact.turns[artifact.turns.length - 1].snapshot;
|
|
128
|
+
if (!first || !latest) return null;
|
|
129
|
+
|
|
130
|
+
// Component count growth ratio
|
|
131
|
+
const componentGrowth = first.componentCount > 0
|
|
132
|
+
? latest.componentCount / first.componentCount
|
|
133
|
+
: latest.componentCount;
|
|
134
|
+
|
|
135
|
+
// Section count growth ratio
|
|
136
|
+
const sectionGrowth = first.sectionCount > 0
|
|
137
|
+
? latest.sectionCount / first.sectionCount
|
|
138
|
+
: latest.sectionCount;
|
|
139
|
+
|
|
140
|
+
// New sections added since turn 0
|
|
141
|
+
const originalSections = new Set(first.sectionNames);
|
|
142
|
+
const newSections = latest.sectionNames.filter(s => !originalSections.has(s));
|
|
143
|
+
|
|
144
|
+
// Component type diversity change
|
|
145
|
+
const originalTypes = new Set(first.componentTypes);
|
|
146
|
+
const newTypes = latest.componentTypes.filter(t => !originalTypes.has(t));
|
|
147
|
+
|
|
148
|
+
// Drift score: 0 = no drift, 1 = extreme drift
|
|
149
|
+
// Weighted: 40% component growth, 30% section growth, 30% new sections
|
|
150
|
+
const growthFactor = Math.min(componentGrowth / 3, 1); // 3x = max
|
|
151
|
+
const sectionFactor = Math.min(sectionGrowth / 3, 1);
|
|
152
|
+
const newSectionFactor = Math.min(newSections.length / 4, 1); // 4+ new = max
|
|
153
|
+
const driftScore = Math.round((growthFactor * 0.4 + sectionFactor * 0.3 + newSectionFactor * 0.3) * 100) / 100;
|
|
154
|
+
|
|
155
|
+
// Warning thresholds
|
|
156
|
+
let warning = null;
|
|
157
|
+
if (driftScore >= 0.7) {
|
|
158
|
+
warning = `High canvas drift detected (score: ${driftScore}). Canvas grew from ${first.componentCount} to ${latest.componentCount} components across ${artifact.turns.length} turns. ${newSections.length} new sections added: ${newSections.join(', ')}. Consider confirming with user that this matches original intent: "${artifact.metadata.originalIntent}"`;
|
|
159
|
+
} else if (driftScore >= 0.4) {
|
|
160
|
+
warning = `Moderate canvas drift (score: ${driftScore}). Canvas: ${first.componentCount} → ${latest.componentCount} components. ${newSections.length} new sections added.`;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return {
|
|
164
|
+
componentGrowth: Math.round(componentGrowth * 100) / 100,
|
|
165
|
+
sectionGrowth: Math.round(sectionGrowth * 100) / 100,
|
|
166
|
+
newSections,
|
|
167
|
+
newTypes,
|
|
168
|
+
driftScore,
|
|
169
|
+
turnCount: artifact.turns.length,
|
|
170
|
+
originalIntent: artifact.metadata.originalIntent,
|
|
171
|
+
warning,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* List all execution summaries.
|
|
177
|
+
*
|
|
178
|
+
* @returns {object[]}
|
|
179
|
+
*/
|
|
180
|
+
list() {
|
|
181
|
+
const results = [];
|
|
182
|
+
for (const [id, artifact] of this.#artifacts) {
|
|
183
|
+
const latest = artifact.turns[artifact.turns.length - 1];
|
|
184
|
+
results.push({
|
|
185
|
+
executionId: id,
|
|
186
|
+
turnCount: artifact.turns.length,
|
|
187
|
+
latestSummary: latest?.summary ?? '',
|
|
188
|
+
latestScore: latest?.validation?.score ?? null,
|
|
189
|
+
originalIntent: artifact.metadata.originalIntent ?? '',
|
|
190
|
+
created: artifact.metadata.created,
|
|
191
|
+
updated: artifact.metadata.updated,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
return results;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Delete an execution's artifacts.
|
|
199
|
+
*
|
|
200
|
+
* @param {string} executionId
|
|
201
|
+
* @returns {boolean} — true if deleted
|
|
202
|
+
*/
|
|
203
|
+
delete(executionId) {
|
|
204
|
+
return this.#artifacts.delete(executionId);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Clear all artifacts.
|
|
209
|
+
*/
|
|
210
|
+
clear() {
|
|
211
|
+
this.#artifacts.clear();
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/** Number of stored executions */
|
|
215
|
+
get size() {
|
|
216
|
+
return this.#artifacts.size;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Build a structural snapshot of the canvas for drift comparison.
|
|
222
|
+
* Extracts component count, section names, component types —
|
|
223
|
+
* the metrics that indicate structural changes.
|
|
224
|
+
*
|
|
225
|
+
* @param {object[]} components — flat A2UI component array
|
|
226
|
+
* @returns {{ componentCount: number, sectionCount: number, sectionNames: string[], componentTypes: string[] }}
|
|
227
|
+
*/
|
|
228
|
+
function _buildStructuralSnapshot(components) {
|
|
229
|
+
if (!components || components.length === 0) {
|
|
230
|
+
return { componentCount: 0, sectionCount: 0, sectionNames: [], componentTypes: [] };
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const sectionNames = [];
|
|
234
|
+
for (const c of components) {
|
|
235
|
+
if (c.component === 'Card') {
|
|
236
|
+
// Find the title of this Card section
|
|
237
|
+
const headerChild = components.find(
|
|
238
|
+
h => h.parentId === c.id && (h.component === 'Header' || h.component === 'CardHeader')
|
|
239
|
+
);
|
|
240
|
+
if (headerChild) {
|
|
241
|
+
const titleChild = components.find(
|
|
242
|
+
t => t.parentId === headerChild.id && t.component === 'Text'
|
|
243
|
+
);
|
|
244
|
+
sectionNames.push(titleChild?.text || titleChild?.children || headerChild.title || c.id);
|
|
245
|
+
} else {
|
|
246
|
+
sectionNames.push(c.id);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const typeSet = new Set();
|
|
252
|
+
for (const c of components) {
|
|
253
|
+
if (c.component) typeSet.add(c.component);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return {
|
|
257
|
+
componentCount: components.length,
|
|
258
|
+
sectionCount: sectionNames.length,
|
|
259
|
+
sectionNames,
|
|
260
|
+
componentTypes: [...typeSet].sort(),
|
|
261
|
+
};
|
|
262
|
+
}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context Store — Cross-surface shared state (A008 §8).
|
|
3
|
+
*
|
|
4
|
+
* Manages named contexts that multiple surfaces can read from and write to.
|
|
5
|
+
* When the first participating surface mounts, the context is populated.
|
|
6
|
+
* When the last participating surface unmounts, the context is eligible
|
|
7
|
+
* for garbage collection.
|
|
8
|
+
*
|
|
9
|
+
* This is the horizontal equivalent of A007's provider (vertical, parent→child).
|
|
10
|
+
* Contexts live outside any single surface's lifecycle.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @typedef {object} ContextEntry
|
|
15
|
+
* @property {string} name
|
|
16
|
+
* @property {object} shape — Schema of the context data
|
|
17
|
+
* @property {object} data — Current data
|
|
18
|
+
* @property {Set<string>} participants — Surface IDs consuming this context
|
|
19
|
+
* @property {object} source — How to populate { uri, refresh, params }
|
|
20
|
+
* @property {boolean} populated — Whether data has been fetched
|
|
21
|
+
* @property {Set<(data: object) => void>} listeners — Change listeners
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
export class ContextStore {
|
|
25
|
+
/** @type {Map<string, ContextEntry>} */
|
|
26
|
+
#contexts = new Map();
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Define a shared context (usually from a surface manifest).
|
|
30
|
+
*
|
|
31
|
+
* @param {string} name — Context name
|
|
32
|
+
* @param {object} config
|
|
33
|
+
* @param {object} config.shape — Data shape schema
|
|
34
|
+
* @param {object} [config.source] — { uri, refresh, params }
|
|
35
|
+
*/
|
|
36
|
+
define(name, config) {
|
|
37
|
+
if (this.#contexts.has(name)) return; // Already defined
|
|
38
|
+
|
|
39
|
+
this.#contexts.set(name, {
|
|
40
|
+
name,
|
|
41
|
+
shape: config.shape || {},
|
|
42
|
+
data: {},
|
|
43
|
+
participants: new Set(),
|
|
44
|
+
source: config.source || null,
|
|
45
|
+
populated: false,
|
|
46
|
+
listeners: new Set(),
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Register a surface as a participant in a context.
|
|
52
|
+
* If this is the first participant and a source is defined, triggers population.
|
|
53
|
+
*
|
|
54
|
+
* @param {string} contextName
|
|
55
|
+
* @param {string} surfaceId
|
|
56
|
+
* @param {(uri: string, params: Record<string, string>) => Promise<unknown>} [fetcher] — Data fetcher
|
|
57
|
+
* @param {Record<string, string>} [params]
|
|
58
|
+
*/
|
|
59
|
+
async join(contextName, surfaceId, fetcher, params = {}) {
|
|
60
|
+
let ctx = this.#contexts.get(contextName);
|
|
61
|
+
if (!ctx) {
|
|
62
|
+
// Auto-define if not pre-defined
|
|
63
|
+
ctx = { name: contextName, shape: {}, data: {}, participants: new Set(), source: null, populated: false, listeners: new Set() };
|
|
64
|
+
this.#contexts.set(contextName, ctx);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
ctx.participants.add(surfaceId);
|
|
68
|
+
|
|
69
|
+
// Populate on first join (if source exists and not already populated)
|
|
70
|
+
if (!ctx.populated && ctx.source && fetcher) {
|
|
71
|
+
try {
|
|
72
|
+
let uri = ctx.source.uri;
|
|
73
|
+
const resolvedParams = { ...ctx.source.params, ...params };
|
|
74
|
+
for (const [key, spec] of Object.entries(resolvedParams)) {
|
|
75
|
+
const value = typeof spec === 'string' ? spec : spec.value || '';
|
|
76
|
+
uri = uri.replace(`{${key}}`, encodeURIComponent(value));
|
|
77
|
+
}
|
|
78
|
+
ctx.data = await fetcher(uri, resolvedParams);
|
|
79
|
+
ctx.populated = true;
|
|
80
|
+
this.#notify(contextName);
|
|
81
|
+
} catch (err) {
|
|
82
|
+
console.warn(`ContextStore: failed to populate "${contextName}":`, err.message);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return ctx.data;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Unregister a surface from a context.
|
|
91
|
+
* If no participants remain, mark for potential cleanup.
|
|
92
|
+
*
|
|
93
|
+
* @param {string} contextName
|
|
94
|
+
* @param {string} surfaceId
|
|
95
|
+
*/
|
|
96
|
+
leave(contextName, surfaceId) {
|
|
97
|
+
const ctx = this.#contexts.get(contextName);
|
|
98
|
+
if (!ctx) return;
|
|
99
|
+
|
|
100
|
+
ctx.participants.delete(surfaceId);
|
|
101
|
+
|
|
102
|
+
// Eligible for GC when no participants
|
|
103
|
+
if (ctx.participants.size === 0) {
|
|
104
|
+
ctx.populated = false;
|
|
105
|
+
ctx.data = {};
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Get the current data for a context.
|
|
111
|
+
*
|
|
112
|
+
* @param {string} contextName
|
|
113
|
+
* @returns {object | null}
|
|
114
|
+
*/
|
|
115
|
+
get(contextName) {
|
|
116
|
+
return this.#contexts.get(contextName)?.data ?? null;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Read a specific key from a context.
|
|
121
|
+
*
|
|
122
|
+
* @param {string} contextName
|
|
123
|
+
* @param {string} key — Dot-separated path (e.g., "patient.name")
|
|
124
|
+
* @returns {unknown}
|
|
125
|
+
*/
|
|
126
|
+
read(contextName, key) {
|
|
127
|
+
const data = this.get(contextName);
|
|
128
|
+
if (!data || !key) return data;
|
|
129
|
+
|
|
130
|
+
const segments = key.split('.');
|
|
131
|
+
let current = data;
|
|
132
|
+
for (const seg of segments) {
|
|
133
|
+
if (current == null || typeof current !== 'object') return undefined;
|
|
134
|
+
current = current[seg];
|
|
135
|
+
}
|
|
136
|
+
return current;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Update data in a context. Notifies all listeners.
|
|
141
|
+
*
|
|
142
|
+
* @param {string} contextName
|
|
143
|
+
* @param {object} data — Partial or full data update (merged)
|
|
144
|
+
*/
|
|
145
|
+
update(contextName, data) {
|
|
146
|
+
const ctx = this.#contexts.get(contextName);
|
|
147
|
+
if (!ctx) return;
|
|
148
|
+
|
|
149
|
+
ctx.data = { ...ctx.data, ...data };
|
|
150
|
+
ctx.populated = true;
|
|
151
|
+
this.#notify(contextName);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Subscribe to context changes.
|
|
156
|
+
*
|
|
157
|
+
* @param {string} contextName
|
|
158
|
+
* @param {(data: object) => void} listener
|
|
159
|
+
* @returns {() => void} — Unsubscribe function
|
|
160
|
+
*/
|
|
161
|
+
subscribe(contextName, listener) {
|
|
162
|
+
const ctx = this.#contexts.get(contextName);
|
|
163
|
+
if (!ctx) return () => {};
|
|
164
|
+
|
|
165
|
+
ctx.listeners.add(listener);
|
|
166
|
+
return () => ctx.listeners.delete(listener);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Check if a context is populated with data.
|
|
171
|
+
* @param {string} contextName
|
|
172
|
+
* @returns {boolean}
|
|
173
|
+
*/
|
|
174
|
+
isPopulated(contextName) {
|
|
175
|
+
return this.#contexts.get(contextName)?.populated ?? false;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Get all defined context names.
|
|
180
|
+
* @returns {string[]}
|
|
181
|
+
*/
|
|
182
|
+
get contextNames() {
|
|
183
|
+
return [...this.#contexts.keys()];
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Get diagnostic info for a context.
|
|
188
|
+
* @param {string} contextName
|
|
189
|
+
*/
|
|
190
|
+
inspect(contextName) {
|
|
191
|
+
const ctx = this.#contexts.get(contextName);
|
|
192
|
+
if (!ctx) return null;
|
|
193
|
+
return {
|
|
194
|
+
name: ctx.name,
|
|
195
|
+
populated: ctx.populated,
|
|
196
|
+
participantCount: ctx.participants.size,
|
|
197
|
+
participants: [...ctx.participants],
|
|
198
|
+
listenerCount: ctx.listeners.size,
|
|
199
|
+
dataKeys: Object.keys(ctx.data),
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/** Clear all contexts. */
|
|
204
|
+
clear() {
|
|
205
|
+
this.#contexts.clear();
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
#notify(contextName) {
|
|
209
|
+
const ctx = this.#contexts.get(contextName);
|
|
210
|
+
if (!ctx) return;
|
|
211
|
+
for (const listener of ctx.listeners) {
|
|
212
|
+
try { listener(ctx.data); } catch { /* listener error */ }
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/** Singleton shared context store for the application. */
|
|
218
|
+
export const sharedContextStore = new ContextStore();
|