@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,582 @@
1
+ /**
2
+ * chunk-refiner — multi-turn refinement engine for chunk-composed UIs.
3
+ *
4
+ * Sibling to chunk-synthesizer.js. Where the synthesizer produces fresh
5
+ * compositions from intent, the refiner takes a prior composition + intent
6
+ * and emits ops that mutate it.
7
+ *
8
+ * Phase A scope (per .claude/docs/specs/genui-multiturn-architecture.md §4):
9
+ * - Two-pass synthesis (locator → modifier).
10
+ * - Validator-driven retry loop, default maxAttempts=2.
11
+ * - Op format: chunk-plan-level ops internally; A2UI-message-shaped on output.
12
+ * - Auto-fires on engine failure paths through the IssueAccumulator passed
13
+ * in via opts (issueAccumulator).
14
+ *
15
+ * Phase A simplification: refinements operate on the chunk binding plan
16
+ * (rebindSlot / appendToSlot / removeFromSlot / replacePage). The
17
+ * `opsToA2UI()` translator wraps each plan-mutation in a standard
18
+ * `updateComponents` A2UI message so the wire-format contract holds.
19
+ * Phase B may introduce richer component-tree refinements; this Phase A
20
+ * approach honors the wire format while keeping engine code focused on the
21
+ * chunk corpus.
22
+ */
23
+
24
+ import {
25
+ getChunk,
26
+ listChunksByKind,
27
+ searchChunksAsync,
28
+ } from '../../../corpus/scripts/chunk-library.js';
29
+ import { composeFromPlan } from './chunk-composer.js';
30
+
31
+ const DEFAULT_MAX_ATTEMPTS = 2;
32
+ const PRE_SEARCH_LIMIT = 30;
33
+ const SURFACE_ID = 'main';
34
+
35
+ const VALID_OP_TYPES = new Set(['rebindSlot', 'appendToSlot', 'removeFromSlot', 'replacePage']);
36
+
37
+ const LOCATOR_SYSTEM_PROMPT = `You identify which slots in an existing UI need modification.
38
+
39
+ You are given:
40
+ - An "intent" describing what the user wants changed.
41
+ - A "component map" listing the slots in the prior UI, each with its name
42
+ and the chunks currently bound to it.
43
+
44
+ If the component map is EMPTY, the prior UI is a single chunk with no bindable
45
+ slots. There is nothing to target: return { "targeted": false, "target_slots": [] }.
46
+
47
+ Decide if the intent is:
48
+ - "targeted" — the user named a specific slot/element to change, OR the
49
+ intent's verb implies a localized change (e.g. "change the title",
50
+ "remove the funnel", "add a country list to page-content").
51
+ - "untargeted" — broad changes touching many slots (e.g. "make everything
52
+ more compact", "use teal not blue").
53
+
54
+ If targeted, return target_slots: list of slot names to modify.
55
+ If untargeted, return targeted: false and target_slots: [].
56
+
57
+ Return ONLY a JSON object: { "targeted": bool, "target_slots": string[] }.
58
+ No prose. Begin with {.`;
59
+
60
+ const MODIFIER_SYSTEM_PROMPT = `You emit refinement ops on an existing chunk-composed UI.
61
+
62
+ Op types:
63
+ - rebindSlot: replace a slot's binding entirely.
64
+ { "type": "rebindSlot", "slot": "<name>", "chunks": ["<chunk-name>"...] }
65
+ - appendToSlot: append chunk(s) to the END of a slot's bound list.
66
+ { "type": "appendToSlot", "slot": "<name>", "chunks": ["<chunk-name>"...] }
67
+ - removeFromSlot: remove chunks from a slot's bound list by index.
68
+ { "type": "removeFromSlot", "slot": "<name>", "indices": [0, 2] }
69
+ - replacePage: swap the page chunk entirely.
70
+ { "type": "replacePage", "page": "<page-chunk-name>", "slot_bindings": { ... } }
71
+
72
+ Rules:
73
+ - Mutate only the slots you've been told to target (when target_slots provided).
74
+ - Every chunk name must exist in the catalog.
75
+ - Multi-clause intents → emit multiple ops.
76
+
77
+ SINGLE-CHUNK PRIOR (the prior plan lists NO slot bindings):
78
+ The prior UI is one chunk with no slots, so slot ops have nothing to
79
+ address — they will fail validation. Emit exactly ONE "replacePage" op that
80
+ re-roots the UI in a shell:
81
+ - "page" MUST be a catalog chunk with kind=page or kind=panel.
82
+ - "slot_bindings" MUST bind the PRIOR chunk (named in the prompt) into one
83
+ of that shell's slots, so the existing UI is preserved, PLUS the chunk(s)
84
+ the intent asks to add. Never drop the prior chunk unless the intent
85
+ explicitly asks to remove it.
86
+
87
+ Return ONLY a JSON object: { "ops": [...], "delta_summary": "<one-line>" }.
88
+ No prose. Begin with {.`;
89
+
90
+ function buildComponentMap(priorState) {
91
+ const plan = priorState?.plan;
92
+ if (!plan?.slot_bindings) return [];
93
+ return Object.entries(plan.slot_bindings).map(([slot, bound]) => ({
94
+ slot,
95
+ chunks: Array.isArray(bound) ? bound : [bound],
96
+ }));
97
+ }
98
+
99
+ /**
100
+ * A plan with no slot bindings is a single-chunk composition — what the
101
+ * retrieval tier produces (gh#832). It has no addressable slots, so the only
102
+ * refinement the op vocabulary can express is `replacePage`.
103
+ */
104
+ function isSingleChunkPlan(plan) {
105
+ return !!plan && Object.keys(plan.slot_bindings || {}).length === 0;
106
+ }
107
+
108
+ /** Every chunk name a plan references — its root plus everything bound. */
109
+ function priorPlanChunkNames(plan) {
110
+ const names = new Set();
111
+ if (!plan) return names;
112
+ if (plan.page) names.add(plan.page);
113
+ for (const bound of Object.values(plan.slot_bindings || {})) {
114
+ for (const n of (Array.isArray(bound) ? bound : [bound])) if (n) names.add(n);
115
+ }
116
+ return names;
117
+ }
118
+
119
+ function buildLocatorPrompt(intent, componentMap, plan) {
120
+ const lines = [];
121
+ lines.push(`Intent: ${intent}`);
122
+ lines.push('');
123
+ lines.push('## Component map');
124
+ if (componentMap.length === 0) {
125
+ lines.push(`(empty — the prior UI is the single chunk "${plan?.page}", no bindable slots)`);
126
+ }
127
+ for (const { slot, chunks } of componentMap) {
128
+ lines.push(`- ${slot}: [${chunks.join(', ')}]`);
129
+ }
130
+ lines.push('');
131
+ lines.push('Return JSON: { "targeted": bool, "target_slots": string[] }.');
132
+ return lines.join('\n');
133
+ }
134
+
135
+ function buildModifierPrompt(intent, priorPlan, targetedSlots, catalog) {
136
+ const lines = [];
137
+ lines.push(`Intent: ${intent}`);
138
+ lines.push('');
139
+ lines.push('## Prior plan');
140
+ lines.push(`Page: ${priorPlan?.page || '(unknown)'}`);
141
+ if (isSingleChunkPlan(priorPlan)) {
142
+ lines.push('Slot bindings: (none — SINGLE-CHUNK PRIOR)');
143
+ lines.push('');
144
+ lines.push(
145
+ `The prior UI is the single chunk "${priorPlan?.page}". Emit ONE replacePage ` +
146
+ `op: pick a kind=page or kind=panel shell from the catalog below and bind ` +
147
+ `"${priorPlan?.page}" into one of its slots ALONGSIDE the chunk(s) the intent asks for, ` +
148
+ `so the existing UI survives the refinement.`,
149
+ );
150
+ } else {
151
+ lines.push('Slot bindings:');
152
+ for (const [slot, bound] of Object.entries(priorPlan?.slot_bindings || {})) {
153
+ const arr = Array.isArray(bound) ? bound : [bound];
154
+ const focus = targetedSlots.includes(slot) ? ' ← TARGETED' : '';
155
+ lines.push(` ${slot}: [${arr.join(', ')}]${focus}`);
156
+ }
157
+ }
158
+ lines.push('');
159
+ lines.push('## Available chunks (filtered)');
160
+ for (const c of catalog) {
161
+ const slots = c.slots?.length ? ` slots=[${c.slots.join(', ')}]` : '';
162
+ lines.push(`- ${c.name} (kind=${c.kind}, primary=${c.primary})${slots}`);
163
+ }
164
+ lines.push('');
165
+ lines.push('Return JSON: { "ops": [...], "delta_summary": "..." }');
166
+ return lines.join('\n');
167
+ }
168
+
169
+ function extractJSON(raw) {
170
+ if (!raw || typeof raw !== 'string') return null;
171
+ const trimmed = raw.trim();
172
+ const fenced = trimmed.match(/```(?:json)?\s*([\s\S]*?)```/);
173
+ const candidate = fenced ? fenced[1].trim() : trimmed;
174
+ try { return JSON.parse(candidate); } catch {}
175
+ const m = candidate.match(/\{[\s\S]*\}/);
176
+ if (!m) return null;
177
+ try { return JSON.parse(m[0]); } catch { return null; }
178
+ }
179
+
180
+ /**
181
+ * Validate ops against the prior state.
182
+ *
183
+ * Checks:
184
+ * - Op shape (type field is one of four known types; required fields present).
185
+ * - Slot references exist in the prior plan.
186
+ * - Chunk references exist in the corpus.
187
+ * - Page references (replacePage) are kind=page or kind=panel.
188
+ *
189
+ * @param {object[]} ops
190
+ * @param {object} priorState — must have .plan.{page, slot_bindings}
191
+ * @returns {{ ok: boolean, errors: string[] }}
192
+ */
193
+ export function validateOps(ops, priorState) {
194
+ const errors = [];
195
+ if (!Array.isArray(ops)) {
196
+ return { ok: false, errors: ['ops must be an array'] };
197
+ }
198
+ if (!priorState?.plan) {
199
+ return { ok: false, errors: ['priorState must have a plan with page+slot_bindings'] };
200
+ }
201
+
202
+ const declaredSlots = new Set(Object.keys(priorState.plan.slot_bindings || {}));
203
+
204
+ ops.forEach((op, i) => {
205
+ if (!op || typeof op !== 'object') {
206
+ errors.push(`ops[${i}]: not an object`);
207
+ return;
208
+ }
209
+ const T = op.type;
210
+ if (!VALID_OP_TYPES.has(T)) {
211
+ errors.push(`ops[${i}]: unknown op type "${T}"`);
212
+ return;
213
+ }
214
+
215
+ if (T === 'replacePage') {
216
+ if (!op.page || typeof op.page !== 'string') {
217
+ errors.push(`ops[${i}]: replacePage requires a "page" string`);
218
+ } else {
219
+ const rec = getChunk(op.page);
220
+ if (!rec) {
221
+ errors.push(`ops[${i}]: page chunk "${op.page}" not found`);
222
+ } else if (rec.kind !== 'page' && rec.kind !== 'panel') {
223
+ errors.push(`ops[${i}]: replacePage chunk "${op.page}" must be kind page|panel; got ${rec.kind}`);
224
+ }
225
+ }
226
+ const bindings = op.slot_bindings || {};
227
+ for (const [slot, bound] of Object.entries(bindings)) {
228
+ const names = Array.isArray(bound) ? bound : [bound];
229
+ for (const name of names) {
230
+ if (!getChunk(name)) {
231
+ errors.push(`ops[${i}]: bound chunk "${name}" (slot "${slot}") not found`);
232
+ }
233
+ }
234
+ }
235
+ return;
236
+ }
237
+
238
+ if (!op.slot || typeof op.slot !== 'string') {
239
+ errors.push(`ops[${i}]: ${T} requires a "slot" string`);
240
+ return;
241
+ }
242
+ if (!declaredSlots.has(op.slot)) {
243
+ errors.push(`ops[${i}]: slot "${op.slot}" not in prior plan (declared: ${[...declaredSlots].join(',')})`);
244
+ }
245
+ if (T === 'rebindSlot' || T === 'appendToSlot') {
246
+ if (!Array.isArray(op.chunks) || op.chunks.length === 0) {
247
+ errors.push(`ops[${i}]: ${T} requires a non-empty "chunks" array`);
248
+ return;
249
+ }
250
+ for (const c of op.chunks) {
251
+ if (!getChunk(c)) errors.push(`ops[${i}]: chunk "${c}" not found`);
252
+ }
253
+ } else if (T === 'removeFromSlot') {
254
+ if (!Array.isArray(op.indices) || op.indices.length === 0) {
255
+ errors.push(`ops[${i}]: removeFromSlot requires a non-empty "indices" array`);
256
+ return;
257
+ }
258
+ const slotBound = priorState.plan.slot_bindings[op.slot];
259
+ const slotArr = Array.isArray(slotBound) ? slotBound : (slotBound ? [slotBound] : []);
260
+ for (const idx of op.indices) {
261
+ if (!Number.isInteger(idx) || idx < 0 || idx >= slotArr.length) {
262
+ errors.push(`ops[${i}]: index ${idx} out of range for slot "${op.slot}" (length ${slotArr.length})`);
263
+ }
264
+ }
265
+ }
266
+ });
267
+
268
+ return { ok: errors.length === 0, errors };
269
+ }
270
+
271
+ /**
272
+ * Apply ops to the prior state.
273
+ *
274
+ * Op-level failures are non-fatal — the apply phase continues with subsequent
275
+ * ops. Returns { newState, ops_applied, ops_failed }. The `newState` includes
276
+ * the mutated plan + freshly materialized HTML.
277
+ *
278
+ * @param {object} input
279
+ * @param {object} input.priorState — { plan, html, ... }
280
+ * @param {object[]} input.ops
281
+ * @returns {Promise<{
282
+ * newState: { plan, html, warnings },
283
+ * ops_applied: object[],
284
+ * ops_failed: { op, reason }[],
285
+ * }>}
286
+ */
287
+ export async function applyOps({ priorState, ops }) {
288
+ if (!priorState?.plan) {
289
+ return {
290
+ newState: priorState,
291
+ ops_applied: [],
292
+ ops_failed: (ops || []).map((op) => ({ op, reason: 'priorState has no plan' })),
293
+ };
294
+ }
295
+
296
+ // Deep-clone the plan so we mutate a copy
297
+ const plan = {
298
+ page: priorState.plan.page,
299
+ slot_bindings: {},
300
+ };
301
+ for (const [slot, bound] of Object.entries(priorState.plan.slot_bindings || {})) {
302
+ plan.slot_bindings[slot] = Array.isArray(bound) ? [...bound] : (bound ? [bound] : []);
303
+ }
304
+
305
+ const ops_applied = [];
306
+ const ops_failed = [];
307
+
308
+ for (const op of (ops || [])) {
309
+ try {
310
+ if (!op || typeof op !== 'object') {
311
+ ops_failed.push({ op, reason: 'op is not an object' });
312
+ continue;
313
+ }
314
+ if (op.type === 'rebindSlot') {
315
+ if (!Array.isArray(op.chunks)) {
316
+ ops_failed.push({ op, reason: 'rebindSlot.chunks must be an array' });
317
+ continue;
318
+ }
319
+ plan.slot_bindings[op.slot] = [...op.chunks];
320
+ ops_applied.push(op);
321
+ } else if (op.type === 'appendToSlot') {
322
+ if (!Array.isArray(op.chunks)) {
323
+ ops_failed.push({ op, reason: 'appendToSlot.chunks must be an array' });
324
+ continue;
325
+ }
326
+ const cur = plan.slot_bindings[op.slot];
327
+ const arr = Array.isArray(cur) ? [...cur] : (cur ? [cur] : []);
328
+ arr.push(...op.chunks);
329
+ plan.slot_bindings[op.slot] = arr;
330
+ ops_applied.push(op);
331
+ } else if (op.type === 'removeFromSlot') {
332
+ if (!Array.isArray(op.indices)) {
333
+ ops_failed.push({ op, reason: 'removeFromSlot.indices must be an array' });
334
+ continue;
335
+ }
336
+ const cur = plan.slot_bindings[op.slot];
337
+ const arr = Array.isArray(cur) ? [...cur] : (cur ? [cur] : []);
338
+ const dropSet = new Set(op.indices);
339
+ plan.slot_bindings[op.slot] = arr.filter((_, i) => !dropSet.has(i));
340
+ ops_applied.push(op);
341
+ } else if (op.type === 'replacePage') {
342
+ plan.page = op.page;
343
+ plan.slot_bindings = {};
344
+ for (const [slot, bound] of Object.entries(op.slot_bindings || {})) {
345
+ plan.slot_bindings[slot] = Array.isArray(bound) ? [...bound] : (bound ? [bound] : []);
346
+ }
347
+ ops_applied.push(op);
348
+ } else {
349
+ ops_failed.push({ op, reason: `unknown op type "${op.type}"` });
350
+ }
351
+ } catch (e) {
352
+ ops_failed.push({ op, reason: e.message });
353
+ }
354
+ }
355
+
356
+ // Re-materialize the HTML
357
+ const composed = composeFromPlan(plan);
358
+
359
+ return {
360
+ newState: {
361
+ plan,
362
+ html: composed.html,
363
+ warnings: composed.warnings || [],
364
+ },
365
+ ops_applied,
366
+ ops_failed,
367
+ };
368
+ }
369
+
370
+ /**
371
+ * Translate chunk-plan-level ops to A2UI message arrays for wire-format
372
+ * compatibility (spec §2.3 + §3.4).
373
+ *
374
+ * Phase A approach: each chunk-plan op produces one `updateComponents`
375
+ * message targeting the affected slot. Components carry a `chunk_op` echo
376
+ * + a materialized `html` string. Phase B may upgrade `html` to a proper
377
+ * component-tree shape.
378
+ *
379
+ * @param {object[]} ops — chunk-plan ops (post-validation)
380
+ * @param {object} newState — { html, plan, warnings } from applyOps
381
+ * @returns {object[]} A2UI messages
382
+ */
383
+ export function opsToA2UI(ops, newState) {
384
+ const messages = [];
385
+ for (const op of (ops || [])) {
386
+ if (op.type === 'replacePage') {
387
+ messages.push({
388
+ type: 'updateComponents',
389
+ surfaceId: SURFACE_ID,
390
+ components: [
391
+ {
392
+ id: SURFACE_ID,
393
+ chunk_op: op,
394
+ html: newState?.html ?? null,
395
+ },
396
+ ],
397
+ });
398
+ } else {
399
+ messages.push({
400
+ type: 'updateComponents',
401
+ surfaceId: SURFACE_ID,
402
+ components: [
403
+ {
404
+ id: `slot-${op.slot}`,
405
+ chunk_op: op,
406
+ html: newState?.html ?? null,
407
+ },
408
+ ],
409
+ });
410
+ }
411
+ }
412
+ return messages;
413
+ }
414
+
415
+ /**
416
+ * Refine a prior composition based on a natural-language intent.
417
+ *
418
+ * Two-pass synthesis:
419
+ * Pass 1 (locator) — LLM identifies which slots to modify.
420
+ * Pass 2 (modifier) — LLM emits chunk-plan ops on the targeted slots.
421
+ *
422
+ * Validator-driven retry: if modifier ops fail validation, the engine
423
+ * re-prompts with errors, up to maxAttempts.
424
+ *
425
+ * Auto-fires on these failure paths (when issueAccumulator is provided):
426
+ * - locator-empty-targets: targeted=true but target_slots is empty.
427
+ * - validator-exhausted: maxAttempts reached without valid ops.
428
+ *
429
+ * @param {object} opts
430
+ * @param {object} opts.priorState — { state_id, plan, html, ... }
431
+ * @param {string} opts.intent
432
+ * @param {object} opts.llmAdapter — { complete: async ({messages, systemPrompt}) }
433
+ * @param {number} [opts.maxAttempts=2]
434
+ * @param {object} [opts.issueAccumulator] — IssueAccumulator from issue-reporter.js
435
+ * @returns {Promise<{
436
+ * ops: object[],
437
+ * delta_summary?: string,
438
+ * warnings: string[],
439
+ * synthesis: { attempts, attemptsLog?, locatedTargets, targeted },
440
+ * }>}
441
+ */
442
+ export async function refineFromIntent({
443
+ priorState,
444
+ intent,
445
+ llmAdapter,
446
+ maxAttempts = DEFAULT_MAX_ATTEMPTS,
447
+ issueAccumulator = null,
448
+ catalog = null,
449
+ }) {
450
+ if (!priorState?.plan) {
451
+ return {
452
+ ops: [],
453
+ warnings: ['priorState has no plan; cannot refine'],
454
+ synthesis: { attempts: 0, locatedTargets: null, targeted: false },
455
+ };
456
+ }
457
+ if (!llmAdapter?.complete) {
458
+ return {
459
+ ops: [],
460
+ warnings: ['no llmAdapter provided'],
461
+ synthesis: { attempts: 0, locatedTargets: null, targeted: false },
462
+ };
463
+ }
464
+
465
+ // Pass 1 — locate
466
+ const componentMap = buildComponentMap(priorState);
467
+ const locatorPrompt = buildLocatorPrompt(intent, componentMap, priorState.plan);
468
+ const locatorResp = await llmAdapter.complete({
469
+ messages: [{ role: 'user', content: locatorPrompt }],
470
+ systemPrompt: LOCATOR_SYSTEM_PROMPT,
471
+ });
472
+ const locatorRaw = locatorResp?.content || locatorResp?.text || '';
473
+ const locatorParsed = extractJSON(locatorRaw);
474
+
475
+ let targeted = false;
476
+ let target_slots = [];
477
+ if (locatorParsed && typeof locatorParsed === 'object') {
478
+ targeted = !!locatorParsed.targeted;
479
+ target_slots = Array.isArray(locatorParsed.target_slots) ? locatorParsed.target_slots : [];
480
+ }
481
+
482
+ if (targeted && target_slots.length === 0) {
483
+ issueAccumulator?.add('locator-empty-targets', {
484
+ intent,
485
+ state_id: priorState.state_id,
486
+ });
487
+ }
488
+
489
+ // Pass 2 — modify. Pre-search the catalog if not provided.
490
+ let resolvedCatalog = catalog;
491
+ if (!resolvedCatalog) {
492
+ const blockHits = await searchChunksAsync(intent, { kind: 'block', limit: PRE_SEARCH_LIMIT });
493
+ const blockChunks = blockHits.map((h) => getChunk(h.name)).filter(Boolean);
494
+ const pageChunks = listChunksByKind('page');
495
+ const panelChunks = listChunksByKind('panel');
496
+ const filtered = [...pageChunks, ...panelChunks, ...blockChunks];
497
+ resolvedCatalog = filtered.map((c) => ({
498
+ name: c.name,
499
+ kind: c.kind,
500
+ primary: c.primary || c.instances?.[0]?.primary,
501
+ slots: (c.slots || c.instances?.[0]?.slots || []).map((s) => s.name),
502
+ }));
503
+ }
504
+
505
+ // The prior plan's own chunks must be in the catalog the modifier sees:
506
+ // a single-chunk refinement has to re-bind the prior root by name, and the
507
+ // intent-driven pre-search (which searches for the CHANGE, not the existing
508
+ // UI) has no reason to surface it (gh#832).
509
+ const catalogNames = new Set(resolvedCatalog.map((c) => c.name));
510
+ for (const name of priorPlanChunkNames(priorState.plan)) {
511
+ if (catalogNames.has(name)) continue;
512
+ const rec = getChunk(name);
513
+ if (!rec) continue;
514
+ catalogNames.add(name);
515
+ resolvedCatalog = [
516
+ ...resolvedCatalog,
517
+ {
518
+ name: rec.name,
519
+ kind: rec.kind,
520
+ primary: rec.primary || rec.instances?.[0]?.primary,
521
+ slots: (rec.slots || rec.instances?.[0]?.slots || []).map((s) => s.name),
522
+ },
523
+ ];
524
+ }
525
+
526
+ const modifierUserPrompt = buildModifierPrompt(intent, priorState.plan, target_slots, resolvedCatalog);
527
+ const attemptsLog = [];
528
+ let lastError = null;
529
+
530
+ for (let i = 0; i < maxAttempts; i++) {
531
+ const retryNudge = lastError
532
+ ? `\n\nPREVIOUS ATTEMPT FAILED VALIDATION: ${lastError}. Re-emit ops without invalid references.`
533
+ : '';
534
+ const modifierResp = await llmAdapter.complete({
535
+ messages: [{ role: 'user', content: modifierUserPrompt + retryNudge }],
536
+ systemPrompt: MODIFIER_SYSTEM_PROMPT,
537
+ });
538
+ const modifierRaw = modifierResp?.content || modifierResp?.text || '';
539
+ attemptsLog.push({ attempt: i + 1, raw: modifierRaw });
540
+
541
+ const parsed = extractJSON(modifierRaw);
542
+ if (!parsed || !Array.isArray(parsed.ops)) {
543
+ lastError = 'response was not valid JSON with { ops: [...] } shape';
544
+ continue;
545
+ }
546
+
547
+ const validation = validateOps(parsed.ops, priorState);
548
+ if (!validation.ok) {
549
+ lastError = validation.errors.slice(0, 3).join('; ');
550
+ continue;
551
+ }
552
+
553
+ return {
554
+ ops: parsed.ops,
555
+ delta_summary: parsed.delta_summary || '',
556
+ warnings: [],
557
+ synthesis: {
558
+ attempts: i + 1,
559
+ attemptsLog,
560
+ locatedTargets: target_slots,
561
+ targeted,
562
+ },
563
+ };
564
+ }
565
+
566
+ issueAccumulator?.add('validator-exhausted', {
567
+ state_id: priorState.state_id,
568
+ tool: 'refine_composition',
569
+ intent,
570
+ });
571
+
572
+ return {
573
+ ops: [],
574
+ warnings: [`refinement failed after ${maxAttempts} attempts: ${lastError}`],
575
+ synthesis: {
576
+ attempts: maxAttempts,
577
+ attemptsLog,
578
+ locatedTargets: target_slots,
579
+ targeted,
580
+ },
581
+ };
582
+ }