@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.
Files changed (631) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +77 -0
  3. package/compose/CHANGELOG.md +1707 -0
  4. package/compose/README.md +215 -0
  5. package/compose/core/artifacts.js +262 -0
  6. package/compose/core/context-store.js +218 -0
  7. package/compose/core/generator.d.ts +4 -0
  8. package/compose/core/generator.js +602 -0
  9. package/compose/core/pipeline/engine.js +289 -0
  10. package/compose/core/pipeline/types.js +91 -0
  11. package/compose/core/plan-primitives.js +120 -0
  12. package/compose/core/plan-turn.js +145 -0
  13. package/compose/core/reference.js +150 -0
  14. package/compose/core/state.js +15 -0
  15. package/compose/evals/harness.d.ts +4 -0
  16. package/compose/evals/harness.mjs +193 -0
  17. package/compose/index.d.ts +4 -0
  18. package/compose/index.js +16 -0
  19. package/compose/shared/validate-and-repair.js +122 -0
  20. package/compose/strategies/_shared/chunk-loader.js +282 -0
  21. package/compose/strategies/cascade.d.ts +67 -0
  22. package/compose/strategies/cascade.js +165 -0
  23. package/compose/strategies/escalation.d.ts +13 -0
  24. package/compose/strategies/escalation.js +132 -0
  25. package/compose/strategies/free-form-composer/index.js +254 -0
  26. package/compose/strategies/free-form-composer/system-prompt.js +205 -0
  27. package/compose/strategies/free-form-composer/transpile.js +279 -0
  28. package/compose/strategies/monolithic/_shared.js +1619 -0
  29. package/compose/strategies/monolithic/generate-instant.js +228 -0
  30. package/compose/strategies/monolithic/generate-pro.js +490 -0
  31. package/compose/strategies/monolithic/generate-thinking.js +206 -0
  32. package/compose/strategies/registry.d.ts +20 -0
  33. package/compose/strategies/registry.js +495 -0
  34. package/compose/strategies/zettel/_smoke.js +27 -0
  35. package/compose/strategies/zettel/chunk-composer.js +214 -0
  36. package/compose/strategies/zettel/chunk-refiner.js +582 -0
  37. package/compose/strategies/zettel/chunk-synthesizer.js +458 -0
  38. package/compose/strategies/zettel/composer.js +78 -0
  39. package/compose/strategies/zettel/composition-library.js +418 -0
  40. package/compose/strategies/zettel/generate.js +15 -0
  41. package/compose/strategies/zettel/generator-adapter.d.ts +4 -0
  42. package/compose/strategies/zettel/generator-adapter.js +242 -0
  43. package/compose/strategies/zettel/issue-reporter.js +607 -0
  44. package/compose/strategies/zettel/session-store.js +121 -0
  45. package/compose/strategies/zettel/state-cache.js +158 -0
  46. package/compose/transpiler/transpiler-maps.js +675 -0
  47. package/compose/transpiler/transpiler.d.ts +4 -0
  48. package/compose/transpiler/transpiler.js +962 -0
  49. package/corpus/CHANGELOG.md +1957 -0
  50. package/corpus/README.md +279 -0
  51. package/corpus/catalog-a2ui_0_9.d.ts +4 -0
  52. package/corpus/catalog-a2ui_0_9.json +29571 -0
  53. package/corpus/catalog-a2ui_0_9_rules.txt +1215 -0
  54. package/corpus/chunk-embeddings.d.ts +4 -0
  55. package/corpus/chunk-embeddings.json +1 -0
  56. package/corpus/chunks/_index.json +16658 -0
  57. package/corpus/chunks/_source-hashes.json +571 -0
  58. package/corpus/chunks/access-denied-with-request.json +124 -0
  59. package/corpus/chunks/access-request-form.json +166 -0
  60. package/corpus/chunks/access-request-pending.json +133 -0
  61. package/corpus/chunks/accordion-settings.json +176 -0
  62. package/corpus/chunks/achievement-badges.json +413 -0
  63. package/corpus/chunks/achievement-unlock.json +104 -0
  64. package/corpus/chunks/action-list-record-actions.json +84 -0
  65. package/corpus/chunks/activity-feed.json +390 -0
  66. package/corpus/chunks/admin-page-header-flush.json +83 -0
  67. package/corpus/chunks/admin-page-header-title-description.json +80 -0
  68. package/corpus/chunks/admin-page-header-with-actions.json +107 -0
  69. package/corpus/chunks/admin-page-header-with-tabs.json +144 -0
  70. package/corpus/chunks/admin-shell-rounded-borderless.json +287 -0
  71. package/corpus/chunks/admin-shell-standard.json +310 -0
  72. package/corpus/chunks/admin-sidebar-brand-signin.json +158 -0
  73. package/corpus/chunks/admin-sidebar-brand-version.json +130 -0
  74. package/corpus/chunks/admin-sidebar-flat-nav.json +131 -0
  75. package/corpus/chunks/admin-sidebar-nav-dividers.json +150 -0
  76. package/corpus/chunks/admin-sidebar-nav-groups.json +171 -0
  77. package/corpus/chunks/admin-sidebar-workspace-switcher.json +139 -0
  78. package/corpus/chunks/admin-topbar-breadcrumb-actions.json +130 -0
  79. package/corpus/chunks/admin-topbar-breadcrumb-minimal.json +79 -0
  80. package/corpus/chunks/admin-topbar-deep-breadcrumb.json +129 -0
  81. package/corpus/chunks/admin-topbar-search.json +104 -0
  82. package/corpus/chunks/admin-topbar-status-indicator.json +122 -0
  83. package/corpus/chunks/admin-topbar-trailing-toggle.json +114 -0
  84. package/corpus/chunks/agent-activity-feed.json +163 -0
  85. package/corpus/chunks/agent-artifact-stub-card.json +115 -0
  86. package/corpus/chunks/agent-canvas-shell.json +305 -0
  87. package/corpus/chunks/agent-citations-source-chips.json +82 -0
  88. package/corpus/chunks/agent-command-palette-search.json +120 -0
  89. package/corpus/chunks/agent-cost-detailed.json +260 -0
  90. package/corpus/chunks/agent-cost-inline.json +78 -0
  91. package/corpus/chunks/agent-memory-detail.json +181 -0
  92. package/corpus/chunks/agent-memory-editor.json +173 -0
  93. package/corpus/chunks/agent-memory-list.json +207 -0
  94. package/corpus/chunks/agent-pipeline-status-stages.json +61 -0
  95. package/corpus/chunks/agent-prompt-card.json +179 -0
  96. package/corpus/chunks/agent-prompt-library-grid.json +341 -0
  97. package/corpus/chunks/agent-prompt-picker.json +282 -0
  98. package/corpus/chunks/agent-rate-limit.json +100 -0
  99. package/corpus/chunks/agent-reasoning-collapsed.json +128 -0
  100. package/corpus/chunks/agent-tool-call-accordion.json +109 -0
  101. package/corpus/chunks/agent-tool-call-collapsed.json +98 -0
  102. package/corpus/chunks/agent-tool-call-error.json +112 -0
  103. package/corpus/chunks/agent-tool-call-result.json +145 -0
  104. package/corpus/chunks/agent-tool-call-running.json +85 -0
  105. package/corpus/chunks/agent-tool-call-success.json +137 -0
  106. package/corpus/chunks/agent-trace-timeline.json +244 -0
  107. package/corpus/chunks/ai-streaming-response.json +147 -0
  108. package/corpus/chunks/alert-banner-stack.json +78 -0
  109. package/corpus/chunks/alert-banner.json +55 -0
  110. package/corpus/chunks/alert-dialog-simple.json +72 -0
  111. package/corpus/chunks/alert-dialog-typed.json +107 -0
  112. package/corpus/chunks/alert-dialog-unsaved.json +81 -0
  113. package/corpus/chunks/analytics-chart.json +213 -0
  114. package/corpus/chunks/analytics-sparklines-dashboard.json +259 -0
  115. package/corpus/chunks/anchor-bar-selection-bar.json +226 -0
  116. package/corpus/chunks/api-key-table.json +148 -0
  117. package/corpus/chunks/api-keys-create.json +140 -0
  118. package/corpus/chunks/api-keys-list.json +271 -0
  119. package/corpus/chunks/app-nav-badges-counts.json +77 -0
  120. package/corpus/chunks/app-nav-badges-group-rollup-badges.json +100 -0
  121. package/corpus/chunks/app-nav-badges-plan-tiers.json +76 -0
  122. package/corpus/chunks/app-nav-badges-status-callouts.json +75 -0
  123. package/corpus/chunks/app-nav-full-example.json +195 -0
  124. package/corpus/chunks/app-nav-groups.json +103 -0
  125. package/corpus/chunks/app-nav-items.json +74 -0
  126. package/corpus/chunks/app-nav-labels-and-dividers.json +92 -0
  127. package/corpus/chunks/app-nav-spacer.json +77 -0
  128. package/corpus/chunks/app-product-listing-card.json +214 -0
  129. package/corpus/chunks/approvals-detail.json +240 -0
  130. package/corpus/chunks/approvals-queue.json +321 -0
  131. package/corpus/chunks/audit-log-basic.json +184 -0
  132. package/corpus/chunks/audit-log.json +174 -0
  133. package/corpus/chunks/auth-account-deleted-actions.json +51 -0
  134. package/corpus/chunks/auth-account-deleted.json +202 -0
  135. package/corpus/chunks/auth-card-content.json +260 -0
  136. package/corpus/chunks/auth-card-header.json +205 -0
  137. package/corpus/chunks/auth-email-entry.json +65 -0
  138. package/corpus/chunks/auth-email-verify-confirm.json +52 -0
  139. package/corpus/chunks/auth-email-verify.json +196 -0
  140. package/corpus/chunks/auth-forbidden-actions.json +59 -0
  141. package/corpus/chunks/auth-forbidden.json +203 -0
  142. package/corpus/chunks/auth-invite-actions.json +49 -0
  143. package/corpus/chunks/auth-invite-team-card.json +86 -0
  144. package/corpus/chunks/auth-link-expired-form.json +65 -0
  145. package/corpus/chunks/auth-link-expired.json +196 -0
  146. package/corpus/chunks/auth-locked-account.json +211 -0
  147. package/corpus/chunks/auth-locked-recovery-options.json +60 -0
  148. package/corpus/chunks/auth-mfa-enrollment-submit.json +54 -0
  149. package/corpus/chunks/auth-mfa-enrollment.json +284 -0
  150. package/corpus/chunks/auth-mfa-fallback-actions.json +52 -0
  151. package/corpus/chunks/auth-mfa-recovery.json +61 -0
  152. package/corpus/chunks/auth-new-password-form.json +75 -0
  153. package/corpus/chunks/auth-new-password.json +217 -0
  154. package/corpus/chunks/auth-oauth-fallback-actions.json +52 -0
  155. package/corpus/chunks/auth-oauth-interstitial.json +160 -0
  156. package/corpus/chunks/auth-password-challenge.json +94 -0
  157. package/corpus/chunks/auth-password-reset-form.json +64 -0
  158. package/corpus/chunks/auth-password-reset.json +195 -0
  159. package/corpus/chunks/auth-profile-form.json +72 -0
  160. package/corpus/chunks/auth-profile-setup.json +194 -0
  161. package/corpus/chunks/auth-reset-sent.json +188 -0
  162. package/corpus/chunks/auth-session-expired-actions.json +52 -0
  163. package/corpus/chunks/auth-session-expired.json +201 -0
  164. package/corpus/chunks/auth-signin-card-email.json +245 -0
  165. package/corpus/chunks/auth-signin-card-magic-link.json +147 -0
  166. package/corpus/chunks/auth-signin-card-mfa.json +231 -0
  167. package/corpus/chunks/auth-signin-card-otp.json +205 -0
  168. package/corpus/chunks/auth-signin-card-password.json +264 -0
  169. package/corpus/chunks/auth-signin-card-recovery.json +218 -0
  170. package/corpus/chunks/auth-signout-actions.json +51 -0
  171. package/corpus/chunks/auth-signout.json +184 -0
  172. package/corpus/chunks/auth-signup-email-entry.json +66 -0
  173. package/corpus/chunks/auth-signup-entry.json +281 -0
  174. package/corpus/chunks/auth-signup-social-auths.json +54 -0
  175. package/corpus/chunks/auth-signup-verify.json +227 -0
  176. package/corpus/chunks/auth-social-auths.json +62 -0
  177. package/corpus/chunks/auth-sso-providers.json +55 -0
  178. package/corpus/chunks/auth-sso-required.json +213 -0
  179. package/corpus/chunks/auth-team-invite.json +288 -0
  180. package/corpus/chunks/avatar-group-overflow.json +137 -0
  181. package/corpus/chunks/avatar-stack-overflow.json +124 -0
  182. package/corpus/chunks/banner-announcement-beta.json +99 -0
  183. package/corpus/chunks/banner-announcement-promo.json +102 -0
  184. package/corpus/chunks/banner-live-update.json +102 -0
  185. package/corpus/chunks/banner-system-maintenance.json +101 -0
  186. package/corpus/chunks/banner-system-offline.json +85 -0
  187. package/corpus/chunks/banner-system-update.json +102 -0
  188. package/corpus/chunks/bell-menu-empty.json +107 -0
  189. package/corpus/chunks/bell-menu-unread.json +395 -0
  190. package/corpus/chunks/billing-cancel-subscription-danger.json +61 -0
  191. package/corpus/chunks/billing-invoice-history-table.json +75 -0
  192. package/corpus/chunks/billing-overview.json +202 -0
  193. package/corpus/chunks/billing-payment-method-card-on-file.json +157 -0
  194. package/corpus/chunks/billing-progress-label.json +101 -0
  195. package/corpus/chunks/blog-post-card.json +212 -0
  196. package/corpus/chunks/breadcrumb-navigation.json +72 -0
  197. package/corpus/chunks/bulk-action-toolbar-floating.json +199 -0
  198. package/corpus/chunks/bulk-action-toolbar-swap.json +158 -0
  199. package/corpus/chunks/bulk-selection-actions-bar.json +162 -0
  200. package/corpus/chunks/business-address-form.json +953 -0
  201. package/corpus/chunks/calendar-month-view.json +74 -0
  202. package/corpus/chunks/card-grid-images.json +459 -0
  203. package/corpus/chunks/card-header-with-description.json +47 -0
  204. package/corpus/chunks/card-with-empty-state.json +96 -0
  205. package/corpus/chunks/card-with-form.json +143 -0
  206. package/corpus/chunks/card-with-sparkline.json +90 -0
  207. package/corpus/chunks/card-with-stat-kpi.json +86 -0
  208. package/corpus/chunks/changelog-feed-basic.json +470 -0
  209. package/corpus/chunks/chart-in-card-chart-plus-breakdown.json +188 -0
  210. package/corpus/chunks/chart-in-card-chart-plus-stat.json +89 -0
  211. package/corpus/chunks/chart-in-card-chart-with-filter-pills.json +124 -0
  212. package/corpus/chunks/chart-in-card-full-bleed-legend.json +116 -0
  213. package/corpus/chunks/chart-in-card-full-chart.json +107 -0
  214. package/corpus/chunks/chart-in-card-sparkline-tile.json +93 -0
  215. package/corpus/chunks/chart-in-card-stat-with-sparkline.json +73 -0
  216. package/corpus/chunks/chart-in-card-trend-footer.json +115 -0
  217. package/corpus/chunks/chart-with-filter-pills.json +169 -0
  218. package/corpus/chunks/chat-empty-state-hero.json +102 -0
  219. package/corpus/chunks/chat-message-assistant-byline.json +85 -0
  220. package/corpus/chunks/chat-message-user-byline.json +84 -0
  221. package/corpus/chunks/chat-page-shell.json +379 -0
  222. package/corpus/chunks/chat-streaming-surface.json +169 -0
  223. package/corpus/chunks/checkout-order-summary-card.json +140 -0
  224. package/corpus/chunks/code-snippet.json +107 -0
  225. package/corpus/chunks/col-form-stack.json +93 -0
  226. package/corpus/chunks/col-heading-body-action.json +79 -0
  227. package/corpus/chunks/col-stat-label.json +63 -0
  228. package/corpus/chunks/color-picker-swatches.json +153 -0
  229. package/corpus/chunks/command-palette.json +327 -0
  230. package/corpus/chunks/comments-composer.json +158 -0
  231. package/corpus/chunks/comments-mention-menu.json +237 -0
  232. package/corpus/chunks/comments-thread.json +344 -0
  233. package/corpus/chunks/commerce-pricing-tiers.json +401 -0
  234. package/corpus/chunks/comparison-table.json +246 -0
  235. package/corpus/chunks/contact-form-card.json +197 -0
  236. package/corpus/chunks/contact-form.json +157 -0
  237. package/corpus/chunks/contact-support-form.json +702 -0
  238. package/corpus/chunks/conversion-funnel-4-step-funnel.json +139 -0
  239. package/corpus/chunks/conversion-funnel-6step.json +151 -0
  240. package/corpus/chunks/conversion-funnel-wide-summary.json +192 -0
  241. package/corpus/chunks/conversion-funnel-with-segment-compare.json +202 -0
  242. package/corpus/chunks/cta-banner-centered.json +102 -0
  243. package/corpus/chunks/dashboard-acquisition-panel.json +212 -0
  244. package/corpus/chunks/dashboard-admin-page.json +104 -0
  245. package/corpus/chunks/dashboard-audience-kpis.json +165 -0
  246. package/corpus/chunks/dashboard-audience-panel.json +756 -0
  247. package/corpus/chunks/dashboard-behavior-panel.json +114 -0
  248. package/corpus/chunks/dashboard-chart-recent.json +566 -0
  249. package/corpus/chunks/dashboard-cohort-retention.json +83 -0
  250. package/corpus/chunks/dashboard-conversion-panel.json +234 -0
  251. package/corpus/chunks/dashboard-country-list.json +304 -0
  252. package/corpus/chunks/dashboard-filter-bar.json +118 -0
  253. package/corpus/chunks/dashboard-funnel.json +142 -0
  254. package/corpus/chunks/dashboard-notifications-panel.json +423 -0
  255. package/corpus/chunks/dashboard-overview-panel.json +1644 -0
  256. package/corpus/chunks/dashboard-page-header.json +166 -0
  257. package/corpus/chunks/dashboard-pages-table.json +86 -0
  258. package/corpus/chunks/dashboard-quick-actions.json +116 -0
  259. package/corpus/chunks/dashboard-reports-panel.json +166 -0
  260. package/corpus/chunks/dashboard-reports-table.json +138 -0
  261. package/corpus/chunks/dashboard-storage-card.json +117 -0
  262. package/corpus/chunks/dashboard-tabs.json +86 -0
  263. package/corpus/chunks/dashboard-team-actions-storage.json +605 -0
  264. package/corpus/chunks/dashboard-team-list.json +334 -0
  265. package/corpus/chunks/dashboard-traffic-channels.json +184 -0
  266. package/corpus/chunks/dashboard-transactions-table.json +145 -0
  267. package/corpus/chunks/data-export-history.json +192 -0
  268. package/corpus/chunks/data-export-request.json +197 -0
  269. package/corpus/chunks/data-import-wizard.json +391 -0
  270. package/corpus/chunks/date-range-picker.json +156 -0
  271. package/corpus/chunks/date-time-picker-form.json +222 -0
  272. package/corpus/chunks/departments-checkbox-form.json +390 -0
  273. package/corpus/chunks/destructive-confirm-modal.json +149 -0
  274. package/corpus/chunks/diff-inline.json +84 -0
  275. package/corpus/chunks/diff-side-by-side.json +131 -0
  276. package/corpus/chunks/diff-structured.json +216 -0
  277. package/corpus/chunks/digest-email-preview.json +374 -0
  278. package/corpus/chunks/divider-text-label.json +87 -0
  279. package/corpus/chunks/doc-editor-shell.json +356 -0
  280. package/corpus/chunks/drawer-2fa-key.json +273 -0
  281. package/corpus/chunks/drawer-2fa-sms.json +261 -0
  282. package/corpus/chunks/drawer-2fa-totp.json +385 -0
  283. package/corpus/chunks/drawer-cancel-sub.json +636 -0
  284. package/corpus/chunks/drawer-change-plan.json +561 -0
  285. package/corpus/chunks/drawer-custom-roles.json +696 -0
  286. package/corpus/chunks/drawer-data-start.json +171 -0
  287. package/corpus/chunks/drawer-delete-account.json +341 -0
  288. package/corpus/chunks/drawer-delete-workspace.json +362 -0
  289. package/corpus/chunks/drawer-discord.json +434 -0
  290. package/corpus/chunks/drawer-figma.json +401 -0
  291. package/corpus/chunks/drawer-first-dashboard.json +220 -0
  292. package/corpus/chunks/drawer-gcal.json +475 -0
  293. package/corpus/chunks/drawer-github.json +589 -0
  294. package/corpus/chunks/drawer-invite.json +397 -0
  295. package/corpus/chunks/drawer-record-detail.json +44 -0
  296. package/corpus/chunks/drawer-report.json +528 -0
  297. package/corpus/chunks/drawer-revoke-session.json +331 -0
  298. package/corpus/chunks/drawer-role.json +190 -0
  299. package/corpus/chunks/drawer-slack.json +429 -0
  300. package/corpus/chunks/drawer-smtp.json +476 -0
  301. package/corpus/chunks/drawer-source.json +294 -0
  302. package/corpus/chunks/drawer-transaction.json +493 -0
  303. package/corpus/chunks/drawer-with-create-form.json +43 -0
  304. package/corpus/chunks/editor-code-pane.json +204 -0
  305. package/corpus/chunks/editor-page-shell.json +149 -0
  306. package/corpus/chunks/editor-preview-pane.json +136 -0
  307. package/corpus/chunks/editor-statusbar-ready.json +99 -0
  308. package/corpus/chunks/editor-toolbar-import-export.json +195 -0
  309. package/corpus/chunks/email-inbox-list.json +678 -0
  310. package/corpus/chunks/empty-state-danger.json +58 -0
  311. package/corpus/chunks/empty-state-minimal.json +44 -0
  312. package/corpus/chunks/empty-state-warning.json +53 -0
  313. package/corpus/chunks/empty-state.json +65 -0
  314. package/corpus/chunks/error-404-actions.json +54 -0
  315. package/corpus/chunks/error-404.json +204 -0
  316. package/corpus/chunks/error-500-actions.json +61 -0
  317. package/corpus/chunks/error-500.json +220 -0
  318. package/corpus/chunks/error-maintenance-actions.json +53 -0
  319. package/corpus/chunks/error-maintenance.json +203 -0
  320. package/corpus/chunks/error-page-shell.json +132 -0
  321. package/corpus/chunks/export-flow-async.json +210 -0
  322. package/corpus/chunks/export-flow-delivery.json +163 -0
  323. package/corpus/chunks/export-flow-sync.json +162 -0
  324. package/corpus/chunks/extended-profile-form.json +512 -0
  325. package/corpus/chunks/faq-accordion.json +123 -0
  326. package/corpus/chunks/feature-grid-icons.json +314 -0
  327. package/corpus/chunks/feature-grid-three-cards.json +187 -0
  328. package/corpus/chunks/feature-toggle-switch-grid.json +213 -0
  329. package/corpus/chunks/file-upload-dnd.json +166 -0
  330. package/corpus/chunks/file-upload-field.json +97 -0
  331. package/corpus/chunks/file-upload-form.json +251 -0
  332. package/corpus/chunks/filter-bar-active-filters.json +176 -0
  333. package/corpus/chunks/filter-bar-filter-bar-with-table.json +113 -0
  334. package/corpus/chunks/filter-bar-saved-views.json +117 -0
  335. package/corpus/chunks/filter-popover-form.json +137 -0
  336. package/corpus/chunks/footer-multi-column.json +270 -0
  337. package/corpus/chunks/footer-primary-only.json +41 -0
  338. package/corpus/chunks/form-checkbox-group.json +65 -0
  339. package/corpus/chunks/form-drawer-edit-form.json +178 -0
  340. package/corpus/chunks/form-drawer-simple-form.json +151 -0
  341. package/corpus/chunks/form-drawer-tall-form.json +325 -0
  342. package/corpus/chunks/form-field-email-hint.json +53 -0
  343. package/corpus/chunks/form-field-range.json +54 -0
  344. package/corpus/chunks/form-field-required.json +52 -0
  345. package/corpus/chunks/form-field-select.json +66 -0
  346. package/corpus/chunks/form-field-textarea.json +51 -0
  347. package/corpus/chunks/form-field-with-error.json +151 -0
  348. package/corpus/chunks/form-fields-two-column.json +69 -0
  349. package/corpus/chunks/form-page-shell.json +146 -0
  350. package/corpus/chunks/form-switch-toggle.json +41 -0
  351. package/corpus/chunks/form-system-live-demo.json +123 -0
  352. package/corpus/chunks/forms-address-autocomplete.json +277 -0
  353. package/corpus/chunks/forms-address-fields.json +221 -0
  354. package/corpus/chunks/forms-conditional-reveal.json +195 -0
  355. package/corpus/chunks/gallery-page-shell.json +444 -0
  356. package/corpus/chunks/grid-2col-entry-cards.json +140 -0
  357. package/corpus/chunks/grid-kpi-4col.json +164 -0
  358. package/corpus/chunks/grid-responsive-kpi.json +165 -0
  359. package/corpus/chunks/hero-cta-simple.json +107 -0
  360. package/corpus/chunks/hero-cta-split.json +183 -0
  361. package/corpus/chunks/hero-section-split.json +111 -0
  362. package/corpus/chunks/icon-text-row.json +60 -0
  363. package/corpus/chunks/image-caption-tile.json +99 -0
  364. package/corpus/chunks/image-carousel.json +156 -0
  365. package/corpus/chunks/image-thumbnail-grid.json +77 -0
  366. package/corpus/chunks/image-upload-preview.json +118 -0
  367. package/corpus/chunks/import-mapping-flow.json +972 -0
  368. package/corpus/chunks/inline-dialog-rename.json +128 -0
  369. package/corpus/chunks/inline-dialog-schedule.json +154 -0
  370. package/corpus/chunks/inline-dialog-status.json +179 -0
  371. package/corpus/chunks/integrations-api-keys-card-list.json +475 -0
  372. package/corpus/chunks/integrations-connect-form.json +550 -0
  373. package/corpus/chunks/integrations-grid.json +141 -0
  374. package/corpus/chunks/integrations-webhooks-empty-state.json +66 -0
  375. package/corpus/chunks/inventory-list-stock.json +137 -0
  376. package/corpus/chunks/invite-members.json +153 -0
  377. package/corpus/chunks/invoice-line-items.json +493 -0
  378. package/corpus/chunks/kanban-board-3col.json +713 -0
  379. package/corpus/chunks/kanban-page-shell.json +671 -0
  380. package/corpus/chunks/key-value-detail-list.json +242 -0
  381. package/corpus/chunks/keyboard-shortcut-display.json +250 -0
  382. package/corpus/chunks/labeled-textarea.json +45 -0
  383. package/corpus/chunks/leaderboard-table.json +140 -0
  384. package/corpus/chunks/library-browser-search-filter.json +109 -0
  385. package/corpus/chunks/linked-record-row.json +61 -0
  386. package/corpus/chunks/loading-skeleton-placeholder.json +387 -0
  387. package/corpus/chunks/login-form-card.json +207 -0
  388. package/corpus/chunks/logo-cloud-trusted-by.json +235 -0
  389. package/corpus/chunks/map-with-location-list.json +293 -0
  390. package/corpus/chunks/marketing-hero-cta.json +102 -0
  391. package/corpus/chunks/marketing-page-shell.json +352 -0
  392. package/corpus/chunks/masonry-gallery.json +154 -0
  393. package/corpus/chunks/member-edit-drawer.json +236 -0
  394. package/corpus/chunks/members-active-table-search-filter.json +184 -0
  395. package/corpus/chunks/members-pending-invites-cards.json +251 -0
  396. package/corpus/chunks/members-roles-permissions-list.json +146 -0
  397. package/corpus/chunks/menu-context-actions.json +113 -0
  398. package/corpus/chunks/metadata-description-list.json +178 -0
  399. package/corpus/chunks/modal-create-project-form.json +133 -0
  400. package/corpus/chunks/modal-preferences-tabs.json +147 -0
  401. package/corpus/chunks/multi-field-form-validation.json +394 -0
  402. package/corpus/chunks/nav-menu-icons.json +74 -0
  403. package/corpus/chunks/newsletter-subscription.json +190 -0
  404. package/corpus/chunks/notification-badges-feed.json +411 -0
  405. package/corpus/chunks/notification-preferences-panel.json +238 -0
  406. package/corpus/chunks/onb-completion.json +139 -0
  407. package/corpus/chunks/onb-extension-install.json +172 -0
  408. package/corpus/chunks/onb-hero-welcome.json +156 -0
  409. package/corpus/chunks/onb-import-picker.json +86 -0
  410. package/corpus/chunks/onb-mobile-handoff.json +121 -0
  411. package/corpus/chunks/onb-notification-prefs.json +83 -0
  412. package/corpus/chunks/onb-persona-picker.json +82 -0
  413. package/corpus/chunks/onb-provider-tiles.json +137 -0
  414. package/corpus/chunks/onb-settings-review.json +257 -0
  415. package/corpus/chunks/onb-step-footer.json +121 -0
  416. package/corpus/chunks/onb-step-header.json +121 -0
  417. package/corpus/chunks/onb-step-progress.json +140 -0
  418. package/corpus/chunks/onb-step-shell.json +380 -0
  419. package/corpus/chunks/onb-story-pane.json +121 -0
  420. package/corpus/chunks/onb-tutorial-steps.json +193 -0
  421. package/corpus/chunks/order-confirmation-success-card.json +177 -0
  422. package/corpus/chunks/order-tracking-timeline.json +131 -0
  423. package/corpus/chunks/pagination-controls.json +82 -0
  424. package/corpus/chunks/pane-settings-sidebar.json +204 -0
  425. package/corpus/chunks/patient-visit-shell.json +191 -0
  426. package/corpus/chunks/payment-checkout-form.json +341 -0
  427. package/corpus/chunks/payment-method-form.json +328 -0
  428. package/corpus/chunks/period-comparison.json +236 -0
  429. package/corpus/chunks/permission-matrix-table.json +438 -0
  430. package/corpus/chunks/permissions-matrix-grid.json +111 -0
  431. package/corpus/chunks/permissions-matrix-summary.json +157 -0
  432. package/corpus/chunks/permissions-role-picker-radio.json +107 -0
  433. package/corpus/chunks/permissions-role-picker-select.json +101 -0
  434. package/corpus/chunks/permissions-share-link.json +256 -0
  435. package/corpus/chunks/permissions-share-people.json +297 -0
  436. package/corpus/chunks/permissions-sharing-scopes.json +109 -0
  437. package/corpus/chunks/plan-selection-form.json +529 -0
  438. package/corpus/chunks/playground-a2ui.json +181 -0
  439. package/corpus/chunks/playground-agent-admin.json +117 -0
  440. package/corpus/chunks/playground-agent-chat.json +126 -0
  441. package/corpus/chunks/playground-app-shell.json +488 -0
  442. package/corpus/chunks/playground-chat.json +265 -0
  443. package/corpus/chunks/playground-construct-canvas.json +118 -0
  444. package/corpus/chunks/playground-css-channel.json +487 -0
  445. package/corpus/chunks/playground-gen-ui.json +224 -0
  446. package/corpus/chunks/playground-render-preview.json +369 -0
  447. package/corpus/chunks/playground-streams-bridge.json +437 -0
  448. package/corpus/chunks/playground-table-toolbar.json +38 -0
  449. package/corpus/chunks/popover-with-content.json +118 -0
  450. package/corpus/chunks/pricing-tiers.json +561 -0
  451. package/corpus/chunks/product-tour.json +158 -0
  452. package/corpus/chunks/profile-public.json +297 -0
  453. package/corpus/chunks/progress-tracker-milestones.json +294 -0
  454. package/corpus/chunks/radio-button-group.json +83 -0
  455. package/corpus/chunks/rating-stars-review-summary.json +259 -0
  456. package/corpus/chunks/reactions-bar.json +75 -0
  457. package/corpus/chunks/reactions-picker.json +245 -0
  458. package/corpus/chunks/real-time-metrics-dashboard.json +344 -0
  459. package/corpus/chunks/record-detail-drawer-simple-detail.json +296 -0
  460. package/corpus/chunks/record-detail-drawer-tabbed-detail.json +443 -0
  461. package/corpus/chunks/referral-share-link.json +128 -0
  462. package/corpus/chunks/referral-status.json +243 -0
  463. package/corpus/chunks/reg-address-form.json +825 -0
  464. package/corpus/chunks/reg-billing-card.json +210 -0
  465. package/corpus/chunks/reg-brand-scrape.json +599 -0
  466. package/corpus/chunks/reg-departments-toggle.json +259 -0
  467. package/corpus/chunks/reg-extended-profile.json +356 -0
  468. package/corpus/chunks/reg-final-done.json +457 -0
  469. package/corpus/chunks/reg-helpdesk-grid.json +571 -0
  470. package/corpus/chunks/reg-import-picker.json +112 -0
  471. package/corpus/chunks/reg-integrations-grid.json +418 -0
  472. package/corpus/chunks/reg-invite-form.json +245 -0
  473. package/corpus/chunks/reg-legal-entity.json +260 -0
  474. package/corpus/chunks/reg-org-chart-review.json +891 -0
  475. package/corpus/chunks/reg-profile-identity.json +188 -0
  476. package/corpus/chunks/reg-step-footer.json +201 -0
  477. package/corpus/chunks/reg-step-header.json +201 -0
  478. package/corpus/chunks/reg-step-progress.json +236 -0
  479. package/corpus/chunks/reg-step-shell.json +605 -0
  480. package/corpus/chunks/reg-story-pane.json +201 -0
  481. package/corpus/chunks/reg-success-summary.json +257 -0
  482. package/corpus/chunks/reg-team-size.json +128 -0
  483. package/corpus/chunks/reg-usecase-picker.json +104 -0
  484. package/corpus/chunks/reg-workspace-name.json +159 -0
  485. package/corpus/chunks/responsive-grid-pattern.json +71 -0
  486. package/corpus/chunks/responsive-kpi-grid.json +166 -0
  487. package/corpus/chunks/responsive-row-pattern.json +71 -0
  488. package/corpus/chunks/responsive-shell-sidebar.json +308 -0
  489. package/corpus/chunks/responsive-wrap-at-pattern.json +124 -0
  490. package/corpus/chunks/retention-cohort-default-retention.json +80 -0
  491. package/corpus/chunks/retention-cohort-stat-pair.json +163 -0
  492. package/corpus/chunks/retention-cohort-with-legend.json +135 -0
  493. package/corpus/chunks/revenue-heatmap.json +82 -0
  494. package/corpus/chunks/role-management.json +272 -0
  495. package/corpus/chunks/row-action-cluster.json +54 -0
  496. package/corpus/chunks/row-avatar-name-role.json +71 -0
  497. package/corpus/chunks/row-icon-label.json +52 -0
  498. package/corpus/chunks/row-spread-label-value.json +54 -0
  499. package/corpus/chunks/row-wrap-tags.json +72 -0
  500. package/corpus/chunks/schedule-meeting-form-card.json +229 -0
  501. package/corpus/chunks/search-recents-menu.json +195 -0
  502. package/corpus/chunks/search-results-grouped.json +357 -0
  503. package/corpus/chunks/search-results-list.json +202 -0
  504. package/corpus/chunks/search-saved-views.json +356 -0
  505. package/corpus/chunks/search-with-filters.json +311 -0
  506. package/corpus/chunks/searchable-picker-modal.json +164 -0
  507. package/corpus/chunks/section-with-stack.json +48 -0
  508. package/corpus/chunks/security-active-sessions-devices.json +287 -0
  509. package/corpus/chunks/security-change-password-form.json +102 -0
  510. package/corpus/chunks/security-delete-account-danger.json +79 -0
  511. package/corpus/chunks/segmented-control-billing-tabs.json +164 -0
  512. package/corpus/chunks/select-multiple-preselected.json +70 -0
  513. package/corpus/chunks/settings-2fa-setup.json +307 -0
  514. package/corpus/chunks/settings-admin-page.json +1205 -0
  515. package/corpus/chunks/settings-appearance-primitives.json +145 -0
  516. package/corpus/chunks/settings-appearance-theme-panel.json +55 -0
  517. package/corpus/chunks/settings-appearance.json +81 -0
  518. package/corpus/chunks/settings-danger-zone-delete-workspace.json +93 -0
  519. package/corpus/chunks/settings-general-form.json +69 -0
  520. package/corpus/chunks/settings-integrations.json +298 -0
  521. package/corpus/chunks/settings-members-invite.json +112 -0
  522. package/corpus/chunks/settings-notification-activity-checkboxes.json +108 -0
  523. package/corpus/chunks/settings-notification-channels-switches.json +101 -0
  524. package/corpus/chunks/settings-page-shell.json +190 -0
  525. package/corpus/chunks/settings-privacy.json +83 -0
  526. package/corpus/chunks/settings-profile-security.json +122 -0
  527. package/corpus/chunks/settings-toggle-switches.json +66 -0
  528. package/corpus/chunks/sidebar-nav.json +120 -0
  529. package/corpus/chunks/sidebar-navigation-panel.json +165 -0
  530. package/corpus/chunks/signup-form-card.json +218 -0
  531. package/corpus/chunks/signup-team-size-form.json +259 -0
  532. package/corpus/chunks/single-select-card-form.json +231 -0
  533. package/corpus/chunks/slider-range-controls.json +119 -0
  534. package/corpus/chunks/social-media-post-card.json +159 -0
  535. package/corpus/chunks/sortable-list.json +307 -0
  536. package/corpus/chunks/sortable-search-paginate-table.json +162 -0
  537. package/corpus/chunks/split-pane-editor.json +146 -0
  538. package/corpus/chunks/stack-avatar-badge-overlay.json +53 -0
  539. package/corpus/chunks/stack-image-shimmer.json +51 -0
  540. package/corpus/chunks/stat-cards-kpi-dashboard.json +178 -0
  541. package/corpus/chunks/stats-band-big-numbers.json +175 -0
  542. package/corpus/chunks/status-dashboard.json +282 -0
  543. package/corpus/chunks/stepper-form-wizard.json +165 -0
  544. package/corpus/chunks/subscription-status-renewal-card.json +285 -0
  545. package/corpus/chunks/survey-rating-form.json +165 -0
  546. package/corpus/chunks/swiper-product-carousel.json +349 -0
  547. package/corpus/chunks/swiper-testimonial-carousel.json +279 -0
  548. package/corpus/chunks/table-empty-state.json +116 -0
  549. package/corpus/chunks/table-inline-edit-row.json +269 -0
  550. package/corpus/chunks/table-spreadsheet-cells.json +334 -0
  551. package/corpus/chunks/table-toolbar-no-search.json +42 -0
  552. package/corpus/chunks/table-toolbar-with-table.json +208 -0
  553. package/corpus/chunks/table-with-toolbar-card.json +80 -0
  554. package/corpus/chunks/tabs-with-panels.json +187 -0
  555. package/corpus/chunks/tag-chips-filter.json +100 -0
  556. package/corpus/chunks/team-invite-form.json +380 -0
  557. package/corpus/chunks/team-members-list.json +341 -0
  558. package/corpus/chunks/testimonial-grid.json +269 -0
  559. package/corpus/chunks/testimonial-pull-quote.json +137 -0
  560. package/corpus/chunks/testimonials-avatar-cards.json +286 -0
  561. package/corpus/chunks/timeline-events.json +89 -0
  562. package/corpus/chunks/timezone-selector-basic.json +99 -0
  563. package/corpus/chunks/timezone-selector-preview.json +104 -0
  564. package/corpus/chunks/toolbar-icons.json +216 -0
  565. package/corpus/chunks/toolbar-rich-text-editor.json +230 -0
  566. package/corpus/chunks/toolbar-tooltips.json +191 -0
  567. package/corpus/chunks/tooltip-hover-button.json +106 -0
  568. package/corpus/chunks/tree-file-explorer.json +136 -0
  569. package/corpus/chunks/tree-table-basic.json +171 -0
  570. package/corpus/chunks/trial-banner.json +158 -0
  571. package/corpus/chunks/url-import-form.json +728 -0
  572. package/corpus/chunks/usage-quota-meter-card.json +217 -0
  573. package/corpus/chunks/user-identity-row.json +81 -0
  574. package/corpus/chunks/user-onboarding-checklist.json +301 -0
  575. package/corpus/chunks/user-profile-card.json +192 -0
  576. package/corpus/chunks/users-table-badge.json +135 -0
  577. package/corpus/chunks/verification-document-upload.json +179 -0
  578. package/corpus/chunks/verification-status.json +97 -0
  579. package/corpus/chunks/verification-stepper.json +111 -0
  580. package/corpus/chunks/video-player-controls.json +120 -0
  581. package/corpus/chunks/webhook-config.json +209 -0
  582. package/corpus/chunks/webhooks-list.json +204 -0
  583. package/corpus/chunks/wizard-drawer-three-step-wizard.json +443 -0
  584. package/corpus/manifest.d.ts +4 -0
  585. package/corpus/manifest.json +6 -0
  586. package/corpus/scripts/chunk-library.d.ts +4 -0
  587. package/corpus/scripts/chunk-library.js +335 -0
  588. package/node-shims.d.ts +48 -0
  589. package/package.json +215 -0
  590. package/retrieval/CHANGELOG.md +1073 -0
  591. package/retrieval/README.md +71 -0
  592. package/retrieval/anti-patterns.js +189 -0
  593. package/retrieval/authoring/index.d.ts +4 -0
  594. package/retrieval/authoring/index.js +9 -0
  595. package/retrieval/authoring/web-research.js +220 -0
  596. package/retrieval/catalog.js +250 -0
  597. package/retrieval/component-catalog.js +168 -0
  598. package/retrieval/component-entry.js +80 -0
  599. package/retrieval/context-assembler.js +174 -0
  600. package/retrieval/domain-router.js +417 -0
  601. package/retrieval/embedding/chunk-embedding-retriever.js +117 -0
  602. package/retrieval/embedding/embedding-provider.js +72 -0
  603. package/retrieval/embedding/index.d.ts +4 -0
  604. package/retrieval/embedding/index.js +2 -0
  605. package/retrieval/feedback/dialog-recorder.js +107 -0
  606. package/retrieval/feedback/feedback-analyzer.js +180 -0
  607. package/retrieval/feedback/feedback-store.js +194 -0
  608. package/retrieval/feedback/feedback.js +117 -0
  609. package/retrieval/feedback/gap-registry.js +80 -0
  610. package/retrieval/feedback/human-signal.js +113 -0
  611. package/retrieval/feedback/index.d.ts +4 -0
  612. package/retrieval/feedback/index.js +24 -0
  613. package/retrieval/feedback/submit-feedback.js +45 -0
  614. package/retrieval/index.d.ts +4 -0
  615. package/retrieval/index.js +53 -0
  616. package/retrieval/intent/clarity.js +139 -0
  617. package/retrieval/intent/decomposer.js +124 -0
  618. package/retrieval/intent/index.d.ts +4 -0
  619. package/retrieval/intent/index.js +18 -0
  620. package/retrieval/intent/intent-alignment.js +172 -0
  621. package/retrieval/intent/intent-categorizer.js +69 -0
  622. package/retrieval/intent/intent-gate.js +96 -0
  623. package/retrieval/intent/prompt-analyzer.js +162 -0
  624. package/retrieval/wiring-catalog.js +168 -0
  625. package/validate/catalog-validator.d.ts +4 -0
  626. package/validate/catalog-validator.js +327 -0
  627. package/validate/semantic/cache.js +54 -0
  628. package/validate/semantic/classify-intent.js +128 -0
  629. package/validate/semantic/index.js +163 -0
  630. package/validate/semantic/intent-specs.js +162 -0
  631. package/validate/semantic/judge.js +180 -0
@@ -0,0 +1,418 @@
1
+ /**
2
+ * Composition Library — zettel-style loader for harvested A2UI chunks.
3
+ *
4
+ * Reads `corpus/chunks/<name>.json` whenever the chunk carries both
5
+ * `metadata` (from `data-chunk-*` source-HTML attrs per §40) AND
6
+ * `template` (from the harvester's transpileHTML pass per §41). Chunks
7
+ * are normalized to composition shape by hoisting `metadata.*` to
8
+ * top level so consumers can search them uniformly.
9
+ *
10
+ * The legacy `corpus/compositions/<domain>/<name>.json` glob was
11
+ * retired in v0.4.7 (§65). The harvested-chunks substrate (~30
12
+ * annotated chunks at landing time) is the canonical retrieval
13
+ * surface; per the project's "source-of-truth = shipped /site/"
14
+ * principle, anything not in a shipped surface should fall through
15
+ * to LLM generation rather than be retrieval-matched from a curated
16
+ * JSON. The 199 MODE-C-MAYBE + 9 KEEP-AS-CHUNK + 3 DELETE
17
+ * composition/pattern files all retired alongside the dir.
18
+ *
19
+ * Records carry `_kind: 'annotated-chunk'` and the source-of-truth
20
+ * path so consumers can distinguish if they care; most shouldn't.
21
+ *
22
+ * Renamed from fragment-library.js in §38. Fragments retired §37.
23
+ * Annotated-chunk loading added §41. Compositions-glob retired §65.
24
+ */
25
+
26
+ // §72 follow-up (v0.4.7): dual-mode loader so this module is safe to
27
+ // statically import from browser entrypoints. Previously the top-level
28
+ // `import 'node:fs'` poisoned the browser bundle the moment any
29
+ // app/playground reached `core/reference.js` → composition-library.
30
+ // Pattern mirrors `retrieval/component-catalog.js`.
31
+ //
32
+ // 2026-06-10: TRI-mode loader. The original dual-mode pattern assumed
33
+ // every browser context is a Vite dev server. The STATIC deploy
34
+ // (ui-kit.exe.xyz) serves the raw source JS — there is no Vite to transform
35
+ // the glob — so the glob `try/catch` swallowed silently and loaded 0 chunks.
36
+ // Every canvas intent then "composition-retrieval missed" on prod even
37
+ // though the chunk scored 66 in Node. Third branch: static-browser → fetch
38
+ // the corpus over HTTP.
39
+ // - Node (fs) — server / eval / smoke
40
+ // - Vite browser (glob) — `npm run dev`
41
+ // - Static browser (fetch)— deployed dist (no Vite, no /api/generate)
42
+ //
43
+ // CRUX — how we tell Vite-browser from static-browser (2026-06-10):
44
+ // `import.meta.glob` is a Vite **compile-time macro on the CALL expression**,
45
+ // NOT a runtime function. Vite rewrites `import.meta.glob('…')` into an
46
+ // object literal at transform time, but a bare reference like
47
+ // `typeof import.meta.glob` is left untouched — so at RUNTIME
48
+ // `import.meta.glob` is `undefined` in BOTH Vite-dev and static contexts
49
+ // (verified empirically 2026-06-10). The only reliable discriminator is to
50
+ // ATTEMPT the call in a try/catch: in Vite it was already rewritten to the
51
+ // object literal (succeeds, returns N loaders); on the raw static site the
52
+ // call hits the real `import.meta.glob` which is undefined → throws
53
+ // `import.meta.glob is not a function` → caught → we take the fetch branch.
54
+ // (This is parse-safe: `import.meta` is a real object in every ES module;
55
+ // the throw is a runtime TypeError, not a SyntaxError.)
56
+ const IS_NODE =
57
+ typeof process !== 'undefined' &&
58
+ typeof process.versions?.node === 'string';
59
+
60
+ /** @type {Map<string, object>} */
61
+ const compositions = new Map();
62
+
63
+ // Vite rewrites this call at transform time; on the static site the call
64
+ // throws (no Vite) → `_globChunkModules` stays null → fetch branch runs.
65
+ let _globChunkModules = null;
66
+ if (!IS_NODE) {
67
+ try {
68
+ _globChunkModules = import.meta.glob('../../../corpus/chunks/*.json', {
69
+ query: '?raw',
70
+ import: 'default',
71
+ eager: false,
72
+ });
73
+ } catch {
74
+ // No Vite transform here (static deploy) — fall through to the fetch branch.
75
+ }
76
+ }
77
+ // `HAS_VITE_GLOB` is now decided by whether the glob CALL produced loaders,
78
+ // not by an (always-undefined-at-runtime) `typeof` probe.
79
+ const HAS_VITE_GLOB =
80
+ !IS_NODE && !!_globChunkModules && Object.keys(_globChunkModules).length > 0;
81
+
82
+ /**
83
+ * Promote an annotated chunk record to composition shape. Lifts
84
+ * `metadata.{domain,description,keywords,related,tags}` to top-level
85
+ * fields so the existing searchAll scorer can read them uniformly.
86
+ */
87
+ function chunkToComposition(chunkDoc, sourcePath, { bodyUrl = null } = {}) {
88
+ const meta = chunkDoc.metadata || {};
89
+ return {
90
+ _kind: 'annotated-chunk',
91
+ _sourceFile: sourcePath,
92
+ // Static-browser only: URL to fetch the chunk body (template) on demand.
93
+ // null in Node / Vite, where `template` is already populated eagerly.
94
+ _bodyUrl: bodyUrl,
95
+ name: chunkDoc.name,
96
+ kind: 'composition', // honest with the searchAll filter
97
+ domain: meta.domain,
98
+ description: meta.description,
99
+ keywords: meta.keywords || [],
100
+ related: meta.related || [],
101
+ tags: meta.tags || {},
102
+ template: chunkDoc.template ?? null,
103
+ };
104
+ }
105
+
106
+ /**
107
+ * Track whether the eager top-level load has run. Multiple `loadAll`
108
+ * call sites (mcp/server.js bootstrap + any other consumer) re-clear
109
+ * + re-build, which is wasted work but not incorrect.
110
+ */
111
+ let _autoLoaded = false;
112
+ let _loadStats = { compositionCount: 0, handAuthoredCount: 0, annotatedChunkCount: 0 };
113
+
114
+ /**
115
+ * Filter + register an annotated chunk. Returns 1 if it qualified
116
+ * (had `metadata` + non-empty `template` + domain/keywords), else 0.
117
+ */
118
+ function registerChunk(doc, sourcePath) {
119
+ if (!doc?.metadata) return 0;
120
+ if (!doc.template || !Array.isArray(doc.template) || doc.template.length === 0) return 0;
121
+ const meta = doc.metadata;
122
+ if (!meta.domain && !(meta.keywords && meta.keywords.length > 0)) return 0;
123
+ compositions.set(doc.name, chunkToComposition(doc, sourcePath));
124
+ return 1;
125
+ }
126
+
127
+ /**
128
+ * Static-browser only: register a chunk from its `_index.json` entry for
129
+ * SCORING (name + metadata.{domain,description,keywords} — verified at
130
+ * 2026-06-10 to be byte-identical to the per-chunk file's metadata). The
131
+ * `template` is NOT in the index; it is fetched lazily by
132
+ * `hydrateComposition(name)` when a strong match is actually emitted, so
133
+ * page-load costs one request (the 281 KB index) instead of 339.
134
+ *
135
+ * Index entries carry no `template`, so the eager `registerChunk` gate
136
+ * (which requires a non-empty template) would reject every one. We apply
137
+ * the SAME metadata gate (domain OR keywords present) but defer the
138
+ * template requirement to hydration time.
139
+ */
140
+ function registerIndexEntry(entry, bodyUrl) {
141
+ if (!entry?.metadata || !entry.name) return 0;
142
+ const meta = entry.metadata;
143
+ if (!meta.domain && !(meta.keywords && meta.keywords.length > 0)) return 0;
144
+ // template: null here — hydrated on demand. searchAll never reads it.
145
+ compositions.set(entry.name, chunkToComposition(entry, entry.name, { bodyUrl }));
146
+ return 1;
147
+ }
148
+
149
+ async function _loadAllNode() {
150
+ const fs = await import(/* @vite-ignore */ 'node:fs');
151
+ const path = await import(/* @vite-ignore */ 'node:path');
152
+ const url = await import(/* @vite-ignore */ 'node:url');
153
+
154
+ const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
155
+ const CHUNKS_ROOT = path.resolve(__dirname, '../../../corpus/chunks');
156
+
157
+ function walk(dir, cb) {
158
+ if (!fs.existsSync(dir)) return;
159
+ // §160 (v0.5.3, F-S1 root cause): sort readdir output. fs.readdirSync
160
+ // returns entries in filesystem-defined order (variable across
161
+ // processes on APFS/ext4), which means chunk-loading order varied
162
+ // run-to-run. When two chunks tied on score for a given intent, the
163
+ // first-loaded won the tie-break — so the same intent could match
164
+ // chunk A in one process and chunk B in the next. Surfaced as
165
+ // ~40% probe-failure rate on admin-dashboard post-§143 (the new
166
+ // chunks compete with the original 4-row KPI composition).
167
+ const entries = fs.readdirSync(dir, { withFileTypes: true })
168
+ .sort((a, b) => a.name.localeCompare(b.name));
169
+ for (const entry of entries) {
170
+ const p = path.join(dir, entry.name);
171
+ if (entry.isDirectory()) walk(p, cb);
172
+ else if (entry.name.endsWith('.json') && !entry.name.startsWith('_')) cb(p);
173
+ }
174
+ }
175
+
176
+ let annotatedChunkCount = 0;
177
+ walk(CHUNKS_ROOT, (p) => {
178
+ const doc = JSON.parse(fs.readFileSync(p, 'utf8'));
179
+ annotatedChunkCount += registerChunk(doc, p);
180
+ });
181
+ return annotatedChunkCount;
182
+ }
183
+
184
+ async function _loadAllBrowser() {
185
+ if (!_globChunkModules) return 0;
186
+ let annotatedChunkCount = 0;
187
+ for (const [globPath, loader] of Object.entries(_globChunkModules)) {
188
+ try {
189
+ const raw = await loader();
190
+ const doc = JSON.parse(raw);
191
+ annotatedChunkCount += registerChunk(doc, globPath);
192
+ } catch {
193
+ // skip malformed chunk JSON
194
+ }
195
+ }
196
+ return annotatedChunkCount;
197
+ }
198
+
199
+ // Base URL for the corpus on a static deploy. Relative-to-module
200
+ // (`import.meta.url`) — NOT an absolute `/packages/...` path — deliberately:
201
+ // 1. It is the SAME path the Vite glob trusts ('../../../corpus/chunks/*'),
202
+ // so dev and prod resolve through one mental model.
203
+ // 2. It is mount-point-independent: works whether dist is served at `/`,
204
+ // under a sub-path, or via the dist symlink layout
205
+ // (dist/node_modules/@adia-ai/gen-ui → packages/gen-ui),
206
+ // because `import.meta.url` always reflects the actually-served path.
207
+ // Verified 2026-06-10: `new URL('../../../corpus/chunks/_index.json',
208
+ // import.meta.url)` → `<root>/packages/gen-ui/corpus/chunks/_index.json`.
209
+ const _CORPUS_CHUNKS_BASE =
210
+ !IS_NODE && !HAS_VITE_GLOB
211
+ ? new URL('../../../corpus/chunks/', import.meta.url)
212
+ : null;
213
+
214
+ /**
215
+ * Static-browser loader. Fetches `_index.json` ONCE and registers every
216
+ * chunk for scoring. Bodies (templates) are fetched lazily by
217
+ * `hydrateComposition` so page-load stays at a single request, not 339.
218
+ *
219
+ * Degrades to 0 chunks (not a throw) on any fetch / parse failure — same
220
+ * graceful-empty contract as the Node and Vite branches.
221
+ */
222
+ async function _loadAllStatic() {
223
+ if (!_CORPUS_CHUNKS_BASE) return 0;
224
+ let index;
225
+ try {
226
+ const res = await fetch(new URL('_index.json', _CORPUS_CHUNKS_BASE));
227
+ if (!res.ok) return 0;
228
+ index = await res.json();
229
+ } catch {
230
+ return 0;
231
+ }
232
+ const entries = Array.isArray(index?.chunks) ? index.chunks : [];
233
+ let count = 0;
234
+ for (const entry of entries) {
235
+ if (!entry?.name) continue;
236
+ const bodyUrl = new URL(`${entry.name}.json`, _CORPUS_CHUNKS_BASE).href;
237
+ count += registerIndexEntry(entry, bodyUrl);
238
+ }
239
+ return count;
240
+ }
241
+
242
+ /**
243
+ * Load all annotated chunks into the in-memory map. Returns a stats
244
+ * snapshot. In Node, runs synchronously via `fs.readFileSync`; in the Vite
245
+ * browser, dispatches the glob loaders in parallel; on a static deploy,
246
+ * fetches the index (bodies lazy-loaded on emit).
247
+ */
248
+ export async function loadAll() {
249
+ compositions.clear();
250
+ let annotatedChunkCount;
251
+ if (IS_NODE) annotatedChunkCount = await _loadAllNode();
252
+ else if (HAS_VITE_GLOB) annotatedChunkCount = await _loadAllBrowser();
253
+ else annotatedChunkCount = await _loadAllStatic();
254
+ _autoLoaded = true;
255
+ _loadStats = {
256
+ compositionCount: compositions.size,
257
+ handAuthoredCount: 0,
258
+ annotatedChunkCount,
259
+ };
260
+ return _loadStats;
261
+ }
262
+
263
+ /**
264
+ * Ensure a composition's `template` (body) is loaded before a consumer
265
+ * resolves it. No-op in Node / Vite (the eager load already populated
266
+ * `template`). On a static deploy, fetches `<name>.json` once, patches the
267
+ * in-memory record's `template`, and caches it for subsequent calls.
268
+ *
269
+ * The zettel adapter's STRONG-MATCH branch awaits this immediately before
270
+ * `getComposition(name)` so verbatim emission has a body. Index-only
271
+ * scoring + lazy single-body hydration is what keeps the static page-load
272
+ * to one request — `searchAll` itself never needs the template.
273
+ *
274
+ * @param {string} name
275
+ * @returns {Promise<object|undefined>} the (now-hydrated) composition record
276
+ */
277
+ export async function hydrateComposition(name) {
278
+ const rec = compositions.get(name);
279
+ if (!rec) return undefined;
280
+ // Already has a body (Node / Vite, or a prior hydration) — done.
281
+ if (Array.isArray(rec.template) && rec.template.length > 0) return rec;
282
+ if (!rec._bodyUrl) return rec; // not a static-deferred record; nothing to fetch
283
+ try {
284
+ const res = await fetch(rec._bodyUrl);
285
+ if (!res.ok) return rec;
286
+ const doc = await res.json();
287
+ if (Array.isArray(doc?.template) && doc.template.length > 0) {
288
+ rec.template = doc.template;
289
+ }
290
+ } catch {
291
+ // Leave template null — resolveComposition handles an empty template
292
+ // (emits nothing) rather than throwing.
293
+ }
294
+ return rec;
295
+ }
296
+
297
+ // Eager top-level load so synchronous getters (getComposition,
298
+ // getAllCompositions, searchAll) work for consumers that don't call
299
+ // loadAll themselves — test harnesses, smoke scripts, and the
300
+ // retrieval-side helpers migrated off pattern-library in §64.
301
+ //
302
+ // In Node we top-level-await the load so the map is populated before
303
+ // any importer reaches the synchronous getters. In the browser the
304
+ // auto-load is fire-and-forget (the map fills as chunk JSONs come back
305
+ // from Vite's glob loaders); callers that need the map populated MUST
306
+ // `await loadAll()` themselves. Documented in §72-follow-up.
307
+ if (IS_NODE && !_autoLoaded) {
308
+ await loadAll();
309
+ } else if (!IS_NODE && !_autoLoaded) {
310
+ // Fire-and-forget; do not block module import on the network round-trips.
311
+ // Covers BOTH browser branches (Vite glob + static fetch). Consumers that
312
+ // need the map populated before a synchronous searchAll MUST `await
313
+ // loadAll()` (or await the adapter's own boot). The canvas does: its
314
+ // generateViaZettel awaits a fresh loadAll on the static-browser path.
315
+ loadAll().catch(() => { /* swallow; browsers that don't need this path won't trip */ });
316
+ }
317
+
318
+ // Back-compat shims removed in §38 — fragment-library.js → composition-library.js
319
+ // rename. The retired `getFragment` / `getAllFragments` exports had zero
320
+ // external callers; drop them.
321
+
322
+ export function getComposition(name) { return compositions.get(name); }
323
+ export function getAllCompositions() { return [...compositions.values()]; }
324
+
325
+ /**
326
+ * Keyword search across compositions. (Fragments retired; only one
327
+ * corpus class to search now.)
328
+ *
329
+ * Ranking design:
330
+ * 1. Tokenize query, drop generic UI stop-words ("form", "page", "view"…)
331
+ * so they can't be the sole evidence for a match.
332
+ * 2. Whole-word match, not substring — prevents "form" matching "login-form".
333
+ * 3. Require ≥2 content-token hits (compositions are concrete templates —
334
+ * promiscuous matching is expensive). Exception: a direct name-token
335
+ * match is strong enough on its own.
336
+ * 4. Tiered weights: name hit > keyword hit > description.
337
+ */
338
+ // Mirrored in `corpus/scripts/chunk-library.js` (`SEARCH_STOP_WORDS`) — this
339
+ // module is browser-safe and can't import that node-only one. Change both or neither.
340
+ const STOP_WORDS = new Set([
341
+ 'a', 'an', 'the', 'and', 'or', 'but', 'of', 'to', 'in', 'on', 'at', 'for', 'with',
342
+ 'form', 'forms', 'page', 'pages', 'view', 'views', 'screen', 'screens',
343
+ 'ui', 'component', 'components', 'widget', 'widgets', 'block', 'blocks',
344
+ 'section', 'sections', 'layout', 'layouts',
345
+ ]);
346
+
347
+ function tokenize(str) {
348
+ return (str || '')
349
+ .toLowerCase()
350
+ .split(/[^a-z0-9]+/)
351
+ .filter((t) => t.length >= 2);
352
+ }
353
+
354
+ export function searchAll(query, { limit = 20 } = {}) {
355
+ const q = (query || '').trim();
356
+ if (!q) return [];
357
+ const queryTokens = tokenize(q);
358
+
359
+ const scoreDoc = (doc) => {
360
+ const nameTokens = new Set(tokenize(doc.name));
361
+ const keywordTokens = new Set((doc.keywords || []).flatMap((k) => tokenize(k)));
362
+ const descTokens = new Set(tokenize(doc.description || ''));
363
+ const tagTokens = new Set(
364
+ Object.values(doc.tags || {}).flat().flatMap((v) => tokenize(String(v))),
365
+ );
366
+
367
+ let s = 0;
368
+ const contentMatched = new Set();
369
+
370
+ for (const t of queryTokens) {
371
+ const isStop = STOP_WORDS.has(t);
372
+ let matched = false;
373
+ if (nameTokens.has(t)) { s += isStop ? 1 : 12; matched = true; }
374
+ if (keywordTokens.has(t)) { s += isStop ? 1 : 8; matched = true; }
375
+ if (tagTokens.has(t)) { s += isStop ? 0 : 3; matched = true; }
376
+ if (descTokens.has(t)) { s += isStop ? 0 : 2; matched = true; }
377
+ if (matched && !isStop) {
378
+ contentMatched.add(t);
379
+ }
380
+ }
381
+ const contentHits = contentMatched.size;
382
+
383
+ // Gate: compositions require ≥2 content-token hits, OR a direct
384
+ // name-token match (the query contains the composition's primary
385
+ // concept word — strong evidence on its own).
386
+ const nameHit = queryTokens.some((t) => !STOP_WORDS.has(t) && nameTokens.has(t));
387
+ if (contentHits < 2 && !nameHit) return 0;
388
+
389
+ // Coverage bonus: more distinct content tokens matched = better match
390
+ s += contentHits * 3;
391
+
392
+ return s;
393
+ };
394
+
395
+ return getAllCompositions()
396
+ .map((doc) => ({ doc, score: scoreDoc(doc) }))
397
+ .filter((x) => x.score > 0)
398
+ .sort((a, b) => b.score - a.score)
399
+ .slice(0, limit)
400
+ .map((x) => ({
401
+ type: 'composition',
402
+ name: x.doc.name,
403
+ score: Math.round(x.score * 100) / 100,
404
+ description: x.doc.description,
405
+ domain: x.doc.domain,
406
+ }));
407
+ }
408
+
409
+ /** Return composition catalog for inspection / visualization. */
410
+ export function getGraph() {
411
+ return {
412
+ compositions: getAllCompositions().map((c) => ({
413
+ name: c.name,
414
+ domain: c.domain,
415
+ node_count: (c.template || []).length,
416
+ })),
417
+ };
418
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * @adia-ai/gen-ui — zettel engine facade.
3
+ *
4
+ * Fragment-graph composition. Three reasoning layers:
5
+ * 1. Retrieval (always) — keyword-rank corpus, resolve top composition
6
+ * 2. LLM synthesis (when llmAdapter + weak retrieval) — compose a new
7
+ * composition from fragments
8
+ * 3. Session-aware iteration (when sessionId + prior turns) — modify
9
+ * existing canvas instead of regenerating
10
+ *
11
+ * The actual implementation is generator-adapter.js; this file is the
12
+ * spec-compliant entry point at strategies/zettel/generate.js per §11.
13
+ */
14
+
15
+ export { generateZettel as generate } from './generator-adapter.js';
@@ -0,0 +1,4 @@
1
+ // v0.5.21 hotfix stub — TS-migration Phase 1 (568bb998d) declared this
2
+ // types: export but Phase 2 hasn't generated real declarations yet.
3
+ // Replace with real type declarations when Phase 2 lands.
4
+ export {};
@@ -0,0 +1,242 @@
1
+ /**
2
+ * Generator adapter for zettel MCP — conforms to the eval harness contract:
3
+ *
4
+ * generate({ intent, mode, llmAdapter, sessionId }) -> { messages, validation, strategy, ...extra }
5
+ *
6
+ * Two reasoning layers (post-§195, v0.5.6):
7
+ * 1. Retrieval (always available) — keyword-rank the corpus, resolve top composition.
8
+ * 2. LLM synthesis (when llmAdapter provided AND retrieval weak) — bridge to
9
+ * chunk-zettel's `composeFromIntent` (the §37 successor codepath) which
10
+ * produces a single-shot html composition from the chunk corpus.
11
+ *
12
+ * Session iteration is currently NOT history-aware in this engine. Prior turns
13
+ * are recorded for analytics + drift tracking, but turn≥2 takes the same code
14
+ * path as turn 1 (fresh retrieval → fresh synthesis). Full history-aware
15
+ * iteration (multi-turn refinement modifying an existing canvas) lives in the
16
+ * `chunk-zettel` engine via `chunk-refiner.js::refineFromIntent` — wire it via
17
+ * `engine: 'chunk-zettel'` rather than `engine: 'zettel'`.
18
+ *
19
+ * The prior fragment-graph iteration codepath (`synthesizeComposition` with
20
+ * `historySummary`) was retired in §37 (2026-05-12) when fragments retired.
21
+ * §195 (v0.5.6) cleaned up the dangling caller — turn≥2 no longer throws +
22
+ * auto-fires a `iteration-synthesis-failure` issue on every multi-turn turn.
23
+ *
24
+ * Strategy labels in the return:
25
+ * - composition-match — fresh retrieval, strong match, emitted verbatim
26
+ * - composition-synthesized — chunk-zettel single-shot synthesis
27
+ * - fragment-candidates — retrieval weak + no LLM, returning atoms only
28
+ * - synthesis-failed — chunk-zettel tried and failed validation
29
+ */
30
+ import {
31
+ getComposition,
32
+ hydrateComposition,
33
+ searchAll,
34
+ } from './composition-library.js';
35
+ import { resolveComposition, templateToMessages } from './composer.js';
36
+ import {
37
+ recordTurn,
38
+ getTurns,
39
+ } from './session-store.js';
40
+ import { validateSchema } from '@adia-ai/a2ui/validate';
41
+
42
+ // Lazy-load the chunk-synthesizer bridge. It imports chunk-corpus data
43
+ // via composition-library's dual-mode loader, which is already top-level
44
+ // awaited; importing it here statically would not break anything but the
45
+ // async-import keeps the cold-start surface tight for the strong-match
46
+ // (no-LLM) path that doesn't need synthesis at all.
47
+ async function bridgeToChunkSynthesis({ intent, llmAdapter }) {
48
+ const { composeFromIntent } = await import('./chunk-synthesizer.js');
49
+ const result = await composeFromIntent({ intent, llmAdapter, maxAttempts: 2 });
50
+ // Shape-adapt chunk-synthesizer's `{ html, template, plan, source, ... }`
51
+ // to the synthesis-branch's prior `{ messages, template, synthesis }`
52
+ // contract. TKT-0009: prefer the real component array (`result.template`)
53
+ // over the pre-fix fallback of wrapping raw HTML in a single node with an
54
+ // UNREGISTERED `component: 'article'` type — that fallback made this
55
+ // caller's validate-and-repair pass below structurally unable to ever
56
+ // report a clean pass.
57
+ const messages = result.template
58
+ ? [{ type: 'updateComponents', components: result.template }]
59
+ : result.html
60
+ ? [{ type: 'updateComponents', components: [{ id: 'chunk-root', component: 'article', html: result.html }] }]
61
+ : [];
62
+ return {
63
+ messages,
64
+ template: result.plan ? [{ $chunk: 'composeFromIntent', plan: result.plan }] : [],
65
+ synthesis: {
66
+ source: result.source,
67
+ score: result.score,
68
+ warnings: result.warnings || [],
69
+ scopeDrift: result.scopeDrift || null,
70
+ },
71
+ };
72
+ }
73
+
74
+ // Composition library auto-loads at module import time via top-level `await
75
+ // loadAll()` in composition-library.js (§72 dual-mode loader, commit
76
+ // `76dbcff2`). The previous `ensureBooted()` here called `loadAll()` WITHOUT
77
+ // `await`, which after §72 made it async — clearing the compositions map +
78
+ // racing the synchronous `searchAll` below. Symptom (caught in §87):
79
+ // eval:diff zettel coverage dropped 5% → 1% because the race-winner pattern
80
+ // emitted composition-match only for the intent whose `searchAll` happened
81
+ // to fire AFTER the async load resolved.
82
+ //
83
+ // Fix: rely entirely on the top-level await. Tests that want a forced reload
84
+ // can call `loadAll()` directly with `await` (it's idempotent).
85
+
86
+ // Retrieval score threshold — above this we trust the match and emit verbatim;
87
+ // below, fall through to LLM synthesis (creative composition from fragments).
88
+ // Calibrated on the 100-intent held-out set:
89
+ // strong matches: login-form=24 (exact), signup-form=27, chart-dashboard=48, pricing-tiers=54
90
+ // weak/false-positive matches: drop below 22 on off-topic queries
91
+ // Raised from 22 → 40 (2026-04-19) so that only near-perfect retrievals play
92
+ // verbatim; merely-good matches (login-form, signup-form) fall through to LLM
93
+ // synthesis instead of being emitted as canned output. Tradeoff: more LLM calls
94
+ // (slower, costlier) in exchange for compositional variety. The previous 22
95
+ // threshold maximized verbatim-cache hits at the cost of repetitive output.
96
+ const STRONG_MATCH_THRESHOLD = 40;
97
+
98
+ function toUpdateComponentsMessages(template) {
99
+ return [{
100
+ type: 'updateComponents',
101
+ components: template.map((n) => {
102
+ const {
103
+ id, component, children,
104
+ $fragment, bindings,
105
+ prependChildren, appendChildren,
106
+ ...rest
107
+ } = n;
108
+ return { id, component, children: children || [], ...rest };
109
+ }),
110
+ }];
111
+ }
112
+
113
+ export async function generateZettel({ intent, mode = 'instant', llmAdapter = null, sessionId = null } = {}) {
114
+ // ── Session iteration note (post-§195, v0.5.6) ──
115
+ // Fragment-graph history-aware iteration (`synthesizeComposition` with
116
+ // `historySummary`) was retired in §37 when fragments retired. Turn≥2 now
117
+ // takes the same path as turn 1 — fresh retrieval → fresh chunk-synthesis.
118
+ // For true history-aware iteration (modify-an-existing-canvas), wire the
119
+ // request via `engine: 'chunk-zettel'` which uses `chunk-refiner.js`.
120
+ //
121
+ // Prior turns are still recorded (analytics + drift tracking via `getDrift`)
122
+ // but the iteration BRANCH is gone — no more spurious
123
+ // `iteration-synthesis-failure` auto-fires on every multi-turn request.
124
+ const priorTurns = sessionId ? getTurns(sessionId) : [];
125
+
126
+ const hits = searchAll(intent, { limit: 5 });
127
+ const composition = hits.find((h) => h.type === 'composition');
128
+ const strongMatch = composition && composition.score >= STRONG_MATCH_THRESHOLD;
129
+
130
+ // ── Strong retrieval match: emit verbatim (turn 1 only — iteration branch above handles repeats) ──
131
+ if (strongMatch) {
132
+ // On a static deploy the composition was registered from `_index.json`
133
+ // for SCORING only — its `template` is fetched lazily here, right before
134
+ // we resolve it. No-op in Node / Vite (template already populated). This
135
+ // keeps the static page-load to a single index request; only the
136
+ // actually-emitted match pays for its body. 2026-06-10.
137
+ await hydrateComposition(composition.name);
138
+ const comp = getComposition(composition.name);
139
+ const template = resolveComposition(comp);
140
+ // Parity guard: Node's `registerChunk` excludes template-less chunks, so
141
+ // they never reach this branch server-side. The static index-scoring gate
142
+ // is looser (it can't see templates in `_index.json`), so a handful of
143
+ // body-less partials (auth-card-header, onb-step-*, …) COULD surface as a
144
+ // strong match on a static deploy. If hydration produced no usable
145
+ // template, treat it as a non-match and fall through — keeping the
146
+ // static result identical to what Node would emit (synthesis / atoms),
147
+ // never an empty verbatim surface.
148
+ if (!Array.isArray(template) || template.length === 0) {
149
+ // fall through to the weak/no-match paths below
150
+ } else {
151
+ const messages = toUpdateComponentsMessages(template);
152
+ const validation = validateSchema(messages, { intent });
153
+ const rank = hits.findIndex((h) => h.type === 'composition' && h.name === composition.name) + 1;
154
+ const fragments = (comp.template || []).filter((n) => n.$fragment).map((n) => n.$fragment);
155
+ recordTurn(sessionId, {
156
+ intent,
157
+ messages,
158
+ template: comp.template,
159
+ composition: composition.name,
160
+ strategy: 'composition-match',
161
+ fragments,
162
+ validation,
163
+ });
164
+ return {
165
+ messages,
166
+ validation,
167
+ strategy: 'composition-match',
168
+ retrieval: { hit: true, rank, candidate: composition.name },
169
+ composition: composition.name,
170
+ retrievalScore: composition.score,
171
+ fragments_used: fragments,
172
+ candidates: hits,
173
+ sessionTurns: priorTurns.length + 1,
174
+ };
175
+ } // end else (template present)
176
+ }
177
+
178
+ // ── Weak/no retrieval: bridge to chunk-zettel synthesis (the §37 successor) ──
179
+ if (llmAdapter && mode !== 'instant-only') {
180
+ try {
181
+ const synth = await bridgeToChunkSynthesis({ intent, llmAdapter });
182
+ // Full schema/catalog/anti-pattern conformance (validate-only — see
183
+ // validate-and-repair.js; TKT-0009 made this meaningful for the first
184
+ // time by giving synth.messages a real component graph instead of an
185
+ // opaque HTML wrapper).
186
+ const { validateAndRepair } = await import('../../shared/validate-and-repair.js');
187
+ const schemaCheck = synth.messages.length ? await validateAndRepair({ messages: synth.messages }) : { valid: false, validation: { score: 0 } };
188
+ const validation = schemaCheck.validation;
189
+ // Chunk-bridge produces an html-bearing single component, not
190
+ // resolved fragment instances. `fragments_used` is empty by design;
191
+ // consumers tracking fragment usage should switch to the
192
+ // chunk-zettel engine which surfaces `_debug.plan` directly.
193
+ recordTurn(sessionId, {
194
+ intent,
195
+ messages: synth.messages,
196
+ template: synth.template,
197
+ composition: null,
198
+ strategy: 'composition-synthesized',
199
+ fragments: [],
200
+ validation,
201
+ });
202
+ return {
203
+ messages: synth.messages,
204
+ validation,
205
+ strategy: 'composition-synthesized',
206
+ retrieval: {
207
+ hit: false,
208
+ rank: composition ? hits.findIndex((h) => h.type === 'composition' && h.name === composition.name) + 1 : null,
209
+ candidate: composition?.name ?? null,
210
+ reason: composition ? `top score ${composition.score} below threshold ${STRONG_MATCH_THRESHOLD}` : 'no composition retrieved',
211
+ },
212
+ composition: null,
213
+ fragments_used: [],
214
+ synthesized_template: synth.template,
215
+ synthesis: synth.synthesis,
216
+ candidates: hits,
217
+ sessionTurns: priorTurns.length + 1,
218
+ };
219
+ } catch (err) {
220
+ return {
221
+ messages: [],
222
+ validation: { score: 0 },
223
+ strategy: 'synthesis-failed',
224
+ retrieval: { hit: false, rank: null, candidate: hits[0]?.name ?? null },
225
+ candidates: hits,
226
+ error: err.message,
227
+ };
228
+ }
229
+ }
230
+
231
+ // ── No LLM, no strong match: return atoms for downstream assembly ──
232
+ return {
233
+ messages: [],
234
+ validation: { score: 0 },
235
+ strategy: 'fragment-candidates',
236
+ retrieval: { hit: false, rank: null, candidate: hits[0]?.name ?? null },
237
+ candidates: hits,
238
+ };
239
+ }
240
+
241
+ // Re-export session management so server.js / MCP tools can reset a session
242
+ export { clearSession, getTurns, getDrift } from './session-store.js';