@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,458 @@
1
+ /**
2
+ * Chunk-aware composition synthesizer.
3
+ *
4
+ * Mirrors the existing `synthesizer.js` (fragment-graph) but operates on the
5
+ * gen-UI training-chunk corpus instead of the fragment catalog. When pure
6
+ * retrieval can't surface a strong match for an intent, this asks the LLM to
7
+ * mix-and-match: pick a page-kind chunk, then bind block/panel chunks to its
8
+ * slots. Validator checks slot names + chunk-kind contracts before composing.
9
+ *
10
+ * Two-tier behavior:
11
+ * 1. Retrieval first — searchChunks returns a strong match (score > threshold)
12
+ * → return that chunk directly. Fast path; no LLM call.
13
+ * 2. Synthesis fallback — retrieval is weak → invoke the LLM to compose
14
+ * from the catalog. This is the creative mix-and-match path.
15
+ *
16
+ * Token-budget mitigation: pre-search filters the catalog to ~30 candidates
17
+ * before the LLM sees them. Mirrors the fragment-synthesizer technique.
18
+ *
19
+ * Plan: .claude/docs/plans/training-pipeline-chunk-harvest-2026-04-27.md (Phase C.2).
20
+ */
21
+
22
+ import {
23
+ getChunk,
24
+ searchChunks,
25
+ searchChunksAsync,
26
+ listChunksByKind,
27
+ getAllChunks,
28
+ resolveNestedChunks,
29
+ } from '../../../corpus/scripts/chunk-library.js';
30
+ import { composeFromPlan, validatePlan } from './chunk-composer.js';
31
+ import { transpileHTML } from '../../transpiler/transpiler.js';
32
+
33
+ // TKT-0009: composeFromIntent used to return only a raw HTML string,
34
+ // which every caller wrapped in a single node carrying an UNREGISTERED
35
+ // A2UI type (`component: 'article'`) — meaning full schema/catalog
36
+ // validation against it always reported invalid, regardless of the
37
+ // composed content's actual quality (registry.has('article') is false).
38
+ // Ratified direction: reuse the SAME transpileHTML() infrastructure the
39
+ // docs-transpiler and harvest-chunks.mjs already run at scale, rather
40
+ // than inventing a new passthrough construct — this makes every
41
+ // composeFromIntent() result a REAL component graph, so it qualifies for
42
+ // the shared validate-and-repair loop like every other engine. A chunk's
43
+ // own precomputed `.template` (from harvest-chunks.mjs) is used directly
44
+ // when available (accurate, no re-transpile cost); multi-instance chunk
45
+ // records don't carry one per-instance, so this falls back to
46
+ // transpiling the HTML on demand either way — every return path leaves
47
+ // with a real template, never just a string.
48
+ async function ensureTemplate(html, precomputedTemplate) {
49
+ if (Array.isArray(precomputedTemplate) && precomputedTemplate.length) return precomputedTemplate;
50
+ if (!html) return null;
51
+ const { messages } = await transpileHTML(html);
52
+ return messages?.[0]?.components ?? null;
53
+ }
54
+
55
+ const STRONG_RETRIEVAL_SCORE = 8; // search-score threshold for fast path
56
+ const PRE_SEARCH_LIMIT = 30; // chunks shown to the LLM in the prompt
57
+ const DEFAULT_MAX_ATTEMPTS = 2;
58
+ // Scope-drift gate: composed HTML's component count vs. the sum of bound
59
+ // chunks' component counts. A multiplier > SCOPE_DRIFT_RATIO trips a warning
60
+ // + auto-fires a `scope-drift` issue. Floor prevents false positives on
61
+ // small UIs where slot-wrapper noise dominates.
62
+ export const SCOPE_DRIFT_RATIO = 1.5;
63
+ export const SCOPE_DRIFT_MIN_ACTUAL = 20;
64
+
65
+ const SYSTEM_PROMPT = `You compose web-app pages by binding training chunks into named slots.
66
+
67
+ ## YOUR TASK
68
+
69
+ Given a user intent and a catalog of chunks, return a JSON object that:
70
+ 1. SELECTS the most appropriate page-kind shell
71
+ 2. BINDS block/panel chunks into its slots
72
+
73
+ ## STEP 1 — SELECT A PAGE SHELL
74
+
75
+ Page shells (kind=page or kind=panel) define the layout topology. Match the
76
+ intent domain to the right shell — NEVER default to dashboard-admin-page for
77
+ non-dashboard intents:
78
+
79
+ | Shell | Domain | Slots |
80
+ |-------|--------|-------|
81
+ | dashboard-admin-page | Admin/analytics dashboards | page-header, page-content |
82
+ | settings-page-shell | Settings, preferences, configuration | page-header, page-tabs, page-content |
83
+ | form-page-shell | Auth forms, sign-in, sign-up, profile | page-header, form-content, page-footer |
84
+ | marketing-page-shell | Landing pages, heroes, features, CTAs | hero, features, cta |
85
+ | error-page-shell | Error states (404, 500, permission denied) | error-content, navigation |
86
+ | editor-page-shell | Split-pane editors (code + preview) | editor-pane, preview-pane |
87
+ | onb-step-shell | Onboarding wizards, multi-step flows | page-story, page-header, page-content, page-footer |
88
+ | reg-step-shell | Registration flows, multi-step sign-up | page-story, page-header, page-content, page-footer |
89
+
90
+ Selection rule: the shell whose DOMAIN matches the intent keywords wins.
91
+
92
+ ## STEP 2 — SELECT BLOCKS TO FILL SLOTS
93
+
94
+ - Search the block catalog for chunks whose name contains intent keywords.
95
+ - Prefer blocks whose primary tag matches the desired component (e.g.
96
+ "stat-ui" for stat cards, "chart-ui" for charts).
97
+ - If a slot is optional and no matching block exists, OMIT it rather
98
+ than forcing a random block.
99
+ - Never invent chunk names. Every bound name must appear in the catalog.
100
+
101
+ ## STEP 3 — RETURN JSON
102
+
103
+ Return ONLY a JSON object shaped exactly like:
104
+ {
105
+ "page": "<name of page-kind chunk>",
106
+ "slot_bindings": {
107
+ "<slot-name>": "<bound chunk name>"
108
+ OR
109
+ "<slot-name>": ["<chunk1>", "<chunk2>"]
110
+ }
111
+ }
112
+
113
+ Rules:
114
+ - The "page" must be a chunk with kind="page" or kind="panel".
115
+ - Every slot key must be declared by the chosen page shell.
116
+ - Every bound value must be a real chunk name from the catalog.
117
+ - Return valid JSON. No prose, no comments, no markdown fences. Begin with "{".
118
+ `;
119
+
120
+ function buildCatalogSummary(chunks) {
121
+ return chunks.map((c) => ({
122
+ name: c.name,
123
+ kind: c.kind,
124
+ primary: c.primary || c.instances?.[0]?.primary,
125
+ slots: (c.slots || c.instances?.[0]?.slots || []).map((s) => s.name),
126
+ }));
127
+ }
128
+
129
+ function buildExamples() {
130
+ // Four canonical examples spanning different domains. Diverse examples
131
+ // prevent the LLM from defaulting to dashboard-shaped output.
132
+ return [
133
+ {
134
+ intent: 'admin dashboard with KPIs and a conversion funnel',
135
+ output: {
136
+ page: 'dashboard-admin-page',
137
+ slot_bindings: {
138
+ 'page-header': 'dashboard-page-header',
139
+ 'page-content': ['dashboard-overview-panel', 'dashboard-funnel'],
140
+ },
141
+ },
142
+ },
143
+ {
144
+ intent: 'sign-in form with email and password',
145
+ output: {
146
+ page: 'form-page-shell',
147
+ slot_bindings: {
148
+ 'page-header': 'auth-signin-card-password',
149
+ 'form-content': 'auth-email-entry',
150
+ },
151
+ },
152
+ },
153
+ {
154
+ intent: 'settings page with tabs for general and billing',
155
+ output: {
156
+ page: 'settings-page-shell',
157
+ slot_bindings: {
158
+ 'page-header': 'settings-general-form',
159
+ 'page-tabs': 'check-combinations-settings-group',
160
+ 'page-content': 'settings-general-form',
161
+ },
162
+ },
163
+ },
164
+ {
165
+ intent: 'marketing landing hero with feature cards',
166
+ output: {
167
+ page: 'marketing-page-shell',
168
+ slot_bindings: {
169
+ hero: 'hero-cta-simple',
170
+ features: 'empty-state-action',
171
+ cta: 'button-primary',
172
+ },
173
+ },
174
+ },
175
+ ];
176
+ }
177
+
178
+ function buildUserPrompt(intent, catalog, examples) {
179
+ const lines = [];
180
+ lines.push(`Intent: ${intent}`);
181
+ lines.push('');
182
+ lines.push('## Available chunks');
183
+ lines.push('');
184
+ for (const c of catalog) {
185
+ const slots = c.slots?.length ? ` slots=[${c.slots.join(', ')}]` : '';
186
+ lines.push(`- ${c.name} (kind=${c.kind}, primary=${c.primary})${slots}`);
187
+ }
188
+ lines.push('');
189
+ lines.push('## Example bindings');
190
+ lines.push('');
191
+ for (const ex of examples) {
192
+ lines.push(`Intent: ${ex.intent}`);
193
+ lines.push('Output:');
194
+ lines.push(JSON.stringify(ex.output, null, 2));
195
+ lines.push('');
196
+ }
197
+ lines.push('## Your turn');
198
+ lines.push('');
199
+ lines.push('Return JSON binding for the intent above. JSON only.');
200
+ return lines.join('\n');
201
+ }
202
+
203
+ function extractJSON(raw) {
204
+ if (!raw || typeof raw !== 'string') return null;
205
+ const trimmed = raw.trim();
206
+ // Strip markdown fences if present
207
+ const fenced = trimmed.match(/```(?:json)?\s*([\s\S]*?)```/);
208
+ const candidate = fenced ? fenced[1].trim() : trimmed;
209
+ try {
210
+ return JSON.parse(candidate);
211
+ } catch {
212
+ // Find the first { ... } balanced object
213
+ const m = candidate.match(/\{[\s\S]*\}/);
214
+ if (!m) return null;
215
+ try { return JSON.parse(m[0]); } catch { return null; }
216
+ }
217
+ }
218
+
219
+ /**
220
+ * Try retrieval-first; fall back to synthesis if retrieval is weak or missing.
221
+ *
222
+ * @param {object} opts
223
+ * @param {string} opts.intent
224
+ * @param {object} opts.llmAdapter — { complete: async ({ messages, systemPrompt }) => { content|text } }
225
+ * @param {number} [opts.maxAttempts=2]
226
+ * @returns {Promise<{ html: string, template: object[]|null, plan: object|null, source: 'retrieval'|'synthesis', score?: number, warnings: string[], synthesis?: object }>}
227
+ * `template` (TKT-0009) is a real A2UI component array — derived from the
228
+ * chunk's own precomputed template when available, else transpiled from
229
+ * `html` on demand — so callers get a validatable component graph, not
230
+ * just an HTML string to wrap opaquely.
231
+ */
232
+ export async function composeFromIntent({ intent, llmAdapter, maxAttempts = DEFAULT_MAX_ATTEMPTS }) {
233
+ // Tier 1 — retrieval. Try semantic-blended hit first; fall back to keyword
234
+ // when embeddings are unavailable (no chunk-embeddings.json or no API key).
235
+ //
236
+ // Restricted to kind=block: page/panel chunks are SKELETONS that need
237
+ // slot-binding composition (Tier 2 handles them). Returning a skeleton
238
+ // Fast path — deterministic keyword-first; embeddings as tie-breaker only.
239
+ // Embeddings can drift (e.g. "pane" matching "panel" boosting unrelated
240
+ // chunks). Sync keyword search is stable and keyword-discoverability is
241
+ // the baseline guarantee. We run both and prefer the sync result when
242
+ // it meets the threshold; only use async when sync is weak but async
243
+ // is strong (e.g. semantic match on content not captured by keywords).
244
+ const syncHits = searchChunks(intent, { kind: 'block', limit: 5 });
245
+ const asyncHits = await searchChunksAsync(intent, { kind: 'block', limit: 5 });
246
+
247
+ const syncTop = syncHits[0];
248
+ const asyncTop = asyncHits[0];
249
+ const useSync = syncTop && syncTop.score >= STRONG_RETRIEVAL_SCORE;
250
+ const useAsync = !useSync && asyncTop && asyncTop.score >= STRONG_RETRIEVAL_SCORE;
251
+
252
+ if (useSync || useAsync) {
253
+ const hit = useSync ? syncTop : asyncTop;
254
+ const top = getChunk(hit.name);
255
+ // A block chunk harvested from a page with nested markers is itself a
256
+ // skeleton — its body is `<!-- nested: … -->` comments. Returning that
257
+ // verbatim ships an empty shell, so inline the referenced chunks.
258
+ const html = resolveNestedChunks(top.html || top.instances?.[0]?.html || '', {
259
+ page: top.page || top.source || top.instances?.[0]?.page,
260
+ });
261
+ const scopeDrift = computeScopeDrift(html, [top, ...(top.nested || []).map(getChunk)]);
262
+ return {
263
+ html,
264
+ template: await ensureTemplate(html, top.template),
265
+ // gh#832 — a retrieval hit IS a composition, so it carries a plan like
266
+ // every synthesis result does: the single-chunk plan that materializes
267
+ // back to exactly this HTML. It used to be `null`, which made both
268
+ // tiers' outputs structurally different and left `refineFromIntent` /
269
+ // `applyOps` with nothing to mutate — refine silently no-opped on the
270
+ // entire Tier-1 path, in the product as well as the eval.
271
+ plan: { page: top.name, slot_bindings: {} },
272
+ source: 'retrieval',
273
+ score: hit.score,
274
+ cosineScore: hit.cosineScore,
275
+ warnings: scopeDrift.drift
276
+ ? [`scope drift: ${scopeDrift.actual} components in HTML vs ${scopeDrift.expected} in bound chunk (ratio ${scopeDrift.ratio.toFixed(2)}×)`]
277
+ : [],
278
+ scopeDrift,
279
+ };
280
+ }
281
+
282
+ // Tier 2 — synthesis. Need an LLM adapter.
283
+ if (!llmAdapter?.complete) {
284
+ return {
285
+ html: null,
286
+ plan: null,
287
+ source: 'synthesis',
288
+ warnings: ['retrieval was weak and no llmAdapter provided — cannot synthesize'],
289
+ };
290
+ }
291
+
292
+ // Pre-search the catalog to keep the prompt token-budget bounded.
293
+ // Strategy: retrieve top N by semantic-blended search; ALWAYS include all
294
+ // page-kind chunks (small set, the LLM needs to see what shells are
295
+ // available). Block pre-search uses embeddings when available.
296
+ const pageChunks = listChunksByKind('page');
297
+ const panelChunks = listChunksByKind('panel');
298
+ const blockHits = await searchChunksAsync(intent, {
299
+ kind: 'block',
300
+ limit: PRE_SEARCH_LIMIT - pageChunks.length - panelChunks.length,
301
+ });
302
+ const blockChunks = blockHits.map((h) => getChunk(h.name)).filter(Boolean);
303
+
304
+ const filtered = [
305
+ ...pageChunks,
306
+ ...panelChunks,
307
+ ...blockChunks,
308
+ ];
309
+ const catalog = buildCatalogSummary(filtered);
310
+ const examples = buildExamples();
311
+
312
+ const userPrompt = buildUserPrompt(intent, catalog, examples);
313
+ let lastError = null;
314
+ const attempts = [];
315
+
316
+ // Trace: snapshot of the retrieval log for the issue-reporter to surface
317
+ // verbatim on bug tickets. Recorded once before the retry loop so it
318
+ // describes what the LLM actually saw.
319
+ const tier1HitList = useSync ? syncHits : (useAsync ? asyncHits : []);
320
+ const retrievalTrace = {
321
+ tier1Hits: tier1HitList.slice(0, 5).map((h) => ({
322
+ name: h.name,
323
+ score: Number(h.score.toFixed(3)),
324
+ kind: h.kind,
325
+ cosineScore: h.cosineScore != null ? Number(h.cosineScore.toFixed(3)) : null,
326
+ })),
327
+ tier1Threshold: STRONG_RETRIEVAL_SCORE,
328
+ tier1Pass: tier1HitList.length > 0 && tier1HitList[0].score >= STRONG_RETRIEVAL_SCORE,
329
+ catalogSize: filtered.length,
330
+ catalogPageNames: pageChunks.map((c) => c.name),
331
+ catalogPanelNames: panelChunks.map((c) => c.name),
332
+ catalogBlockTopN: blockHits.slice(0, 10).map((h) => ({
333
+ name: h.name,
334
+ score: Number(h.score.toFixed(3)),
335
+ })),
336
+ userPromptChars: userPrompt.length,
337
+ systemPromptChars: SYSTEM_PROMPT.length,
338
+ };
339
+
340
+ for (let i = 0; i < maxAttempts; i++) {
341
+ const retryNudge = lastError
342
+ ? `\n\nPREVIOUS ATTEMPT FAILED: ${lastError}. Return ONLY a JSON object shaped as { "page": "...", "slot_bindings": { ... } }. No prose, no questions.`
343
+ : '';
344
+ const messages = [{ role: 'user', content: userPrompt + retryNudge }];
345
+ const response = await llmAdapter.complete({ messages, systemPrompt: SYSTEM_PROMPT });
346
+ const raw = response?.content || response?.text || (typeof response === 'string' ? response : '');
347
+ attempts.push({ attempt: i + 1, raw });
348
+
349
+ const plan = extractJSON(raw);
350
+ if (!plan || !plan.page || !plan.slot_bindings) {
351
+ lastError = 'Response was not valid JSON with { page, slot_bindings } fields.';
352
+ continue;
353
+ }
354
+
355
+ const validation = validatePlan(plan);
356
+ if (!validation.ok) {
357
+ lastError = validation.errors.slice(0, 3).join('; ');
358
+ continue;
359
+ }
360
+
361
+ const composed = composeFromPlan(plan);
362
+ if (!composed.html) {
363
+ lastError = composed.warnings.join('; ') || 'composer returned null html';
364
+ continue;
365
+ }
366
+
367
+ // Compute scope-drift signal: composed envelope vs sum of bound chunks.
368
+ // Bound chunks = page chunk + every block/panel resolved into a slot.
369
+ const boundNames = new Set([plan.page]);
370
+ for (const v of Object.values(plan.slot_bindings || {})) {
371
+ const arr = Array.isArray(v) ? v : [v];
372
+ for (const n of arr) boundNames.add(n);
373
+ }
374
+ const boundChunks = [...boundNames].map((n) => getChunk(n)).filter(Boolean);
375
+ const scopeDrift = computeScopeDrift(composed.html, boundChunks);
376
+ const driftWarnings = scopeDrift.drift
377
+ ? [`scope drift: ${scopeDrift.actual} components in composed HTML vs ${scopeDrift.expected} in bound chunks (ratio ${scopeDrift.ratio.toFixed(2)}× exceeds gate ${SCOPE_DRIFT_RATIO}×)`]
378
+ : [];
379
+
380
+ return {
381
+ html: composed.html,
382
+ template: await ensureTemplate(composed.html, null),
383
+ plan,
384
+ source: 'synthesis',
385
+ warnings: [...composed.warnings, ...driftWarnings],
386
+ scopeDrift,
387
+ synthesis: {
388
+ attempts: i + 1,
389
+ attemptsLog: attempts,
390
+ validation,
391
+ retrievalTrace,
392
+ userPrompt,
393
+ systemPromptHash: hashString(SYSTEM_PROMPT),
394
+ },
395
+ };
396
+ }
397
+
398
+ return {
399
+ html: null,
400
+ plan: null,
401
+ source: 'synthesis',
402
+ warnings: [`synthesis failed after ${maxAttempts} attempts: ${lastError}`],
403
+ synthesis: {
404
+ attempts: maxAttempts,
405
+ attemptsLog: attempts,
406
+ retrievalTrace,
407
+ userPrompt,
408
+ systemPromptHash: hashString(SYSTEM_PROMPT),
409
+ },
410
+ };
411
+ }
412
+
413
+ // Cheap non-crypto hash for prompt-version fingerprinting in tickets.
414
+ function hashString(s) {
415
+ let h = 5381;
416
+ for (let i = 0; i < s.length; i++) h = ((h * 33) ^ s.charCodeAt(i)) >>> 0;
417
+ return 'h' + h.toString(36);
418
+ }
419
+
420
+ /**
421
+ * Heuristic component count — number of opening tags in the HTML.
422
+ * Loose but stable proxy for A2UI envelope size; used by the scope-drift
423
+ * gate (above) and by issue-reporter's ticket-rendering counter.
424
+ */
425
+ function countComponents(html) {
426
+ if (typeof html !== 'string') return 0;
427
+ return (html.match(/<[a-z][a-z0-9-]*/g) || []).length;
428
+ }
429
+
430
+ /**
431
+ * Compute the scope-drift signal for a composed result.
432
+ *
433
+ * Inputs: the final HTML string + the chunk records that fed into it
434
+ * (page chunk for Tier-2; the single block for Tier-1). Sums the bound
435
+ * chunks' component counts to get an "expected envelope," compares it to
436
+ * the actual composed count, and reports the ratio.
437
+ *
438
+ * Returns { actual, expected, ratio, drift } where `drift` is true when
439
+ * actual exceeds SCOPE_DRIFT_RATIO × expected AND actual ≥ SCOPE_DRIFT_MIN_ACTUAL.
440
+ */
441
+ export function computeScopeDrift(html, boundChunks) {
442
+ const actual = countComponents(html);
443
+ let expected = 0;
444
+ for (const c of boundChunks) {
445
+ if (!c) continue;
446
+ const chunkHtml = c.html || c.instances?.[0]?.html;
447
+ expected += countComponents(chunkHtml);
448
+ }
449
+ // Guard against zero-expected: when bound chunks have no HTML accounted for
450
+ // (rare; should only happen in malformed corpora), skip the gate rather
451
+ // than report infinite drift.
452
+ if (expected === 0) {
453
+ return { actual, expected, ratio: null, drift: false };
454
+ }
455
+ const ratio = actual / expected;
456
+ const drift = actual >= SCOPE_DRIFT_MIN_ACTUAL && ratio > SCOPE_DRIFT_RATIO;
457
+ return { actual, expected, ratio, drift };
458
+ }
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Composer — passes A2UI composition templates straight through.
3
+ *
4
+ * History: this file used to expand `$fragment` refs in compositions
5
+ * via a slot-binding mechanism (zettel-style fragment graph). As of
6
+ * §37 (2026-05-12) fragments are retired — all compositions are
7
+ * pre-inlined into flat A2UI templates by /tmp/inline-compositions.py.
8
+ * `resolveComposition` is now a defensive copy + strip pass; any
9
+ * lingering `$fragment` ref is treated as a placeholder (the LLM /
10
+ * renderer will fail noisily, surfacing corpus drift).
11
+ *
12
+ * Kept as a thin wrapper rather than deleted because zettel's
13
+ * generator-adapter still calls `resolveComposition(comp)` —
14
+ * downstream rename is a follow-up arc.
15
+ */
16
+
17
+ const ID_PREFIX_SEPARATOR = '--';
18
+
19
+ /**
20
+ * Return a defensive copy of a composition's flat template.
21
+ *
22
+ * Compositions are pre-inlined, so there's nothing to expand. We
23
+ * still strip zettel-era fields that may linger in the corpus —
24
+ * future-proof against accidental re-introduction.
25
+ *
26
+ * @param {object} composition - { template: [...] }
27
+ * @returns {Array<object>}
28
+ */
29
+ export function resolveComposition(composition) {
30
+ const template = composition?.template || [];
31
+ const out = [];
32
+ for (const node of template) {
33
+ if (!node || typeof node !== 'object') continue;
34
+ if (node.$fragment) {
35
+ // Stale $fragment refs shouldn't exist after the §37 inline pass.
36
+ // Surface them as a visible placeholder so corpus drift is easy
37
+ // to spot at render time.
38
+ out.push({
39
+ id: node.id || `stale-${node.$fragment}`,
40
+ component: 'Text',
41
+ textContent: `⚠ stale $fragment ref (compositions are pre-inlined): ${node.$fragment}`,
42
+ });
43
+ continue;
44
+ }
45
+ const {
46
+ // Strip composition-only fields that never reach the renderer
47
+ $fragment, bindings, prependChildren, appendChildren,
48
+ ...rest
49
+ } = node;
50
+ out.push({ ...rest });
51
+ }
52
+ return out;
53
+ }
54
+
55
+ /**
56
+ * Convert a flat A2UI template into `beginComponent` messages for the
57
+ * validator / renderer. Strips composition-era fields.
58
+ */
59
+ export function templateToMessages(template) {
60
+ return template.map((node) => {
61
+ const {
62
+ id, component, children,
63
+ $fragment, bindings,
64
+ prependChildren, appendChildren,
65
+ ...rest
66
+ } = node;
67
+ return {
68
+ messageType: 'beginComponent',
69
+ componentId: id,
70
+ componentType: component,
71
+ children: children || [],
72
+ ...rest,
73
+ };
74
+ });
75
+ }
76
+
77
+ // Re-export the separator for any downstream code that still uses it.
78
+ export { ID_PREFIX_SEPARATOR };