@signalflare-ai/ui 1.2.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (318) hide show
  1. package/CHANGELOG.md +154 -1
  2. package/ai/component-registry.json +208 -550
  3. package/ai/component-registry.md +3042 -3115
  4. package/ai/schemas.ts +504 -96
  5. package/dist/.build-complete +1 -1
  6. package/dist/ai/schemas.d.ts.map +1 -1
  7. package/dist/{ai-actions-BdUZI3Gk.js → ai-actions-CBfz5XEf.js} +4 -4
  8. package/dist/{ai-actions-BdUZI3Gk.js.map → ai-actions-CBfz5XEf.js.map} +1 -1
  9. package/dist/{ai-agent-card-BR2NIYhi.js → ai-agent-card-CByAUe0q.js} +3 -3
  10. package/dist/ai-agent-card-CByAUe0q.js.map +1 -0
  11. package/dist/{ai-approval-Ba7mrKba.js → ai-approval-Ci8N70a7.js} +4 -3
  12. package/dist/{ai-approval-Ba7mrKba.js.map → ai-approval-Ci8N70a7.js.map} +1 -1
  13. package/dist/{ai-code-block-CZtoL73R.js → ai-code-block-P9TJHvaC.js} +37 -39
  14. package/dist/ai-code-block-P9TJHvaC.js.map +1 -0
  15. package/dist/{ai-conversation-Cc7WlaBg.js → ai-conversation-Qslfdi1t.js} +28 -42
  16. package/dist/ai-conversation-Qslfdi1t.js.map +1 -0
  17. package/dist/{ai-info-banner-C7EWPBj7.js → ai-info-banner-B_9vtGK3.js} +3 -3
  18. package/dist/{ai-info-banner-C7EWPBj7.js.map → ai-info-banner-B_9vtGK3.js.map} +1 -1
  19. package/dist/{ai-message-Bp7L68U_.js → ai-message-Ci3gwM7G.js} +6 -6
  20. package/dist/{ai-message-Bp7L68U_.js.map → ai-message-Ci3gwM7G.js.map} +1 -1
  21. package/dist/{ai-mission-header-TiCJfTNt.js → ai-mission-header-CaBc19-t.js} +2 -2
  22. package/dist/{ai-mission-header-TiCJfTNt.js.map → ai-mission-header-CaBc19-t.js.map} +1 -1
  23. package/dist/{ai-part-group-DNb9I446.js → ai-part-group-Dx1Mr92B.js} +5 -4
  24. package/dist/ai-part-group-Dx1Mr92B.js.map +1 -0
  25. package/dist/{ai-prompt-input-BVvov_KF.js → ai-prompt-input-Bm4XoSj2.js} +19 -17
  26. package/dist/ai-prompt-input-Bm4XoSj2.js.map +1 -0
  27. package/dist/{ai-question-GPPMk7YM.js → ai-question-OyJovxGe.js} +4 -3
  28. package/dist/{ai-question-GPPMk7YM.js.map → ai-question-OyJovxGe.js.map} +1 -1
  29. package/dist/{ai-reasoning-_feFjk56.js → ai-reasoning-BLfBXx3F.js} +9 -5
  30. package/dist/ai-reasoning-BLfBXx3F.js.map +1 -0
  31. package/dist/{ai-response-CvjV3WhV.js → ai-response-hbVCZJmo.js} +2 -2
  32. package/dist/{ai-response-CvjV3WhV.js.map → ai-response-hbVCZJmo.js.map} +1 -1
  33. package/dist/{ai-shimmer-j6lKIrjj.js → ai-shimmer-BamNMNK3.js} +2 -2
  34. package/dist/{ai-shimmer-j6lKIrjj.js.map → ai-shimmer-BamNMNK3.js.map} +1 -1
  35. package/dist/{ai-status-badge-CSU_QOdz.js → ai-status-badge-BZLczdkI.js} +2 -2
  36. package/dist/{ai-status-badge-CSU_QOdz.js.map → ai-status-badge-BZLczdkI.js.map} +1 -1
  37. package/dist/{ai-streaming-text-IWW1BhvZ.js → ai-streaming-text-DgYu64UH.js} +1 -1
  38. package/dist/{ai-streaming-text-IWW1BhvZ.js.map → ai-streaming-text-DgYu64UH.js.map} +1 -1
  39. package/dist/{ai-subagent-JA4iIMW3.js → ai-subagent-p97AI1h9.js} +3 -3
  40. package/dist/{ai-subagent-JA4iIMW3.js.map → ai-subagent-p97AI1h9.js.map} +1 -1
  41. package/dist/{ai-suggestion-BdO6MBuH.js → ai-suggestion-Bj6vF7CT.js} +3 -3
  42. package/dist/{ai-suggestion-BdO6MBuH.js.map → ai-suggestion-Bj6vF7CT.js.map} +1 -1
  43. package/dist/{ai-task-list-DYw4R1FA.js → ai-task-list-C_UQYpk9.js} +6 -4
  44. package/dist/{ai-task-list-DYw4R1FA.js.map → ai-task-list-C_UQYpk9.js.map} +1 -1
  45. package/dist/{ai-timeline-C42tOUT8.js → ai-timeline-CePL1LOU.js} +3 -3
  46. package/dist/ai-timeline-CePL1LOU.js.map +1 -0
  47. package/dist/{ai-tool-03jOTwUI.js → ai-tool-CfRcwmHT.js} +17 -11
  48. package/dist/ai-tool-CfRcwmHT.js.map +1 -0
  49. package/dist/{ai-usage-bar-BRf5LC_b.js → ai-usage-bar-45pVRCGA.js} +2 -2
  50. package/dist/{ai-usage-bar-BRf5LC_b.js.map → ai-usage-bar-45pVRCGA.js.map} +1 -1
  51. package/dist/{badge-BheXjMc8.js → badge-Beb-6uut.js} +5 -5
  52. package/dist/{badge-BheXjMc8.js.map → badge-Beb-6uut.js.map} +1 -1
  53. package/dist/{banner-CcsjunJg.js → banner-CCEksxPg.js} +3 -3
  54. package/dist/{banner-CcsjunJg.js.map → banner-CCEksxPg.js.map} +1 -1
  55. package/dist/{breadcrumbs-CouSyy3H.js → breadcrumbs-HiTmgaZ4.js} +5 -5
  56. package/dist/{breadcrumbs-CouSyy3H.js.map → breadcrumbs-HiTmgaZ4.js.map} +1 -1
  57. package/dist/{button-CO6-qPax.js → button-BHOgXJRU.js} +4 -4
  58. package/dist/{button-CO6-qPax.js.map → button-BHOgXJRU.js.map} +1 -1
  59. package/dist/catalog.js +1 -1
  60. package/dist/catalog.js.map +1 -1
  61. package/dist/{chart-Dg0qUeSc.js → chart-B9FfZdKs.js} +7 -7
  62. package/dist/chart-B9FfZdKs.js.map +1 -0
  63. package/dist/{checkbox-D7p4QKsC.js → checkbox-Cy_OCyay.js} +3 -3
  64. package/dist/{checkbox-D7p4QKsC.js.map → checkbox-Cy_OCyay.js.map} +1 -1
  65. package/dist/{clipboard-text-kLaMogs3.js → clipboard-text-CKSvNp9L.js} +6 -5
  66. package/dist/clipboard-text-CKSvNp9L.js.map +1 -0
  67. package/dist/{cn-YROP2_ox.js → cn-CmAOpn49.js} +2 -2
  68. package/dist/{cn-YROP2_ox.js.map → cn-CmAOpn49.js.map} +1 -1
  69. package/dist/{code-BN8InC0G.js → code-JsQz-0G_.js} +4 -4
  70. package/dist/{code-BN8InC0G.js.map → code-JsQz-0G_.js.map} +1 -1
  71. package/dist/{collapsible-D_ueZ0jz.js → collapsible-1kOZ-89L.js} +2 -2
  72. package/dist/{collapsible-D_ueZ0jz.js.map → collapsible-1kOZ-89L.js.map} +1 -1
  73. package/dist/{combobox-B7TOK0U2.js → combobox-CQwDmqgA.js} +4 -4
  74. package/dist/{combobox-B7TOK0U2.js.map → combobox-CQwDmqgA.js.map} +1 -1
  75. package/dist/command-line/cli.js +3 -3
  76. package/dist/{command-palette-CuNUyJca.js → command-palette-Bkuv3e6o.js} +20 -5
  77. package/dist/command-palette-Bkuv3e6o.js.map +1 -0
  78. package/dist/components/ai-actions.js +1 -1
  79. package/dist/components/ai-agent-card.js +1 -1
  80. package/dist/components/ai-approval.js +1 -1
  81. package/dist/components/ai-code-block.js +1 -1
  82. package/dist/components/ai-conversation.js +1 -1
  83. package/dist/components/ai-info-banner.js +1 -1
  84. package/dist/components/ai-message.js +1 -1
  85. package/dist/components/ai-mission-header.js +1 -1
  86. package/dist/components/ai-part-group.js +1 -1
  87. package/dist/components/ai-prompt-input.js +1 -1
  88. package/dist/components/ai-question.js +1 -1
  89. package/dist/components/ai-reasoning.js +1 -1
  90. package/dist/components/ai-response.js +1 -1
  91. package/dist/components/ai-shimmer.js +1 -1
  92. package/dist/components/ai-status-badge.js +1 -1
  93. package/dist/components/ai-streaming-text.js +1 -1
  94. package/dist/components/ai-subagent.js +1 -1
  95. package/dist/components/ai-suggestion.js +1 -1
  96. package/dist/components/ai-task-list.js +1 -1
  97. package/dist/components/ai-timeline.js +1 -1
  98. package/dist/components/ai-tool.js +1 -1
  99. package/dist/components/ai-usage-bar.js +1 -1
  100. package/dist/components/badge.js +1 -1
  101. package/dist/components/banner.js +1 -1
  102. package/dist/components/breadcrumbs.js +1 -1
  103. package/dist/components/button.js +1 -1
  104. package/dist/components/chart.js +2 -2
  105. package/dist/components/checkbox.js +1 -1
  106. package/dist/components/clipboard-text.js +1 -1
  107. package/dist/components/code.js +1 -1
  108. package/dist/components/collapsible.js +1 -1
  109. package/dist/components/combobox.js +1 -1
  110. package/dist/components/command-palette.js +1 -1
  111. package/dist/components/data-grid.js +1 -1
  112. package/dist/components/date-picker.js +1 -1
  113. package/dist/components/date-range-picker.js +1 -1
  114. package/dist/components/dialog.js +1 -1
  115. package/dist/components/dropdown.js +1 -1
  116. package/dist/components/empty.js +1 -1
  117. package/dist/components/field.js +1 -1
  118. package/dist/components/filters.js +1 -1
  119. package/dist/components/flow.js +1 -1
  120. package/dist/components/grid.js +1 -1
  121. package/dist/components/input.js +2 -2
  122. package/dist/components/label.js +1 -1
  123. package/dist/components/layer-card.js +1 -1
  124. package/dist/components/link.js +3 -3
  125. package/dist/components/link.js.map +1 -1
  126. package/dist/components/loader.js +2 -2
  127. package/dist/components/menubar.js +1 -1
  128. package/dist/components/meter.js +1 -1
  129. package/dist/components/pagination.js +1 -1
  130. package/dist/components/popover.js +1 -1
  131. package/dist/components/radio.js +1 -1
  132. package/dist/components/select.js +1 -1
  133. package/dist/components/sensitive-input.js +1 -1
  134. package/dist/components/sidebar.js +1 -1
  135. package/dist/components/signalflare-ai-logo.js +1 -1
  136. package/dist/components/sparkline.js +1 -1
  137. package/dist/components/stat-card.js +1 -1
  138. package/dist/components/surface.js +1 -1
  139. package/dist/components/switch.js +1 -1
  140. package/dist/components/table.js +1 -1
  141. package/dist/components/tabs.js +1 -1
  142. package/dist/components/text-roll.js +1 -1
  143. package/dist/components/text.js +1 -1
  144. package/dist/components/theme-toggle.js +1 -1
  145. package/dist/components/toast.js +1 -1
  146. package/dist/components/tooltip.js +1 -1
  147. package/dist/components/use-agent-harness.js +1 -1
  148. package/dist/data-grid-DrguJq_H.js +395 -0
  149. package/dist/data-grid-DrguJq_H.js.map +1 -0
  150. package/dist/{date-picker--ox89RBy.js → date-picker-O34AqG3f.js} +2 -2
  151. package/dist/{date-picker--ox89RBy.js.map → date-picker-O34AqG3f.js.map} +1 -1
  152. package/dist/{date-range-picker-DVa7QBqE.js → date-range-picker-YKYvum_r.js} +29 -39
  153. package/dist/{date-range-picker-DVa7QBqE.js.map → date-range-picker-YKYvum_r.js.map} +1 -1
  154. package/dist/{dialog-Bv1oSFOd.js → dialog-DYqu4aDO.js} +3 -3
  155. package/dist/{dialog-Bv1oSFOd.js.map → dialog-DYqu4aDO.js.map} +1 -1
  156. package/dist/{dist-B6iWiWwp.js → dist-6AtBsaJE.js} +153 -47
  157. package/dist/dist-6AtBsaJE.js.map +1 -0
  158. package/dist/{dropdown-B_nrGXjV.js → dropdown-XzbnRLYR.js} +15 -5
  159. package/dist/dropdown-XzbnRLYR.js.map +1 -0
  160. package/dist/{echart-CdOUaT-r.js → echart-DGBIVAv1.js} +23 -57
  161. package/dist/{echart-CdOUaT-r.js.map → echart-DGBIVAv1.js.map} +1 -1
  162. package/dist/{empty-DZnN0zKX.js → empty-C1tAkawe.js} +6 -6
  163. package/dist/{empty-DZnN0zKX.js.map → empty-C1tAkawe.js.map} +1 -1
  164. package/dist/{field-B_yVof52.js → field-DBpFzzBS.js} +3 -3
  165. package/dist/{field-B_yVof52.js.map → field-DBpFzzBS.js.map} +1 -1
  166. package/dist/{filters-cpJCY21R.js → filters-SmEl93za.js} +10 -10
  167. package/dist/filters-SmEl93za.js.map +1 -0
  168. package/dist/{flow-B4v198ot.js → flow-BLzgbq1T.js} +6 -6
  169. package/dist/flow-BLzgbq1T.js.map +1 -0
  170. package/dist/genui.js +2 -2
  171. package/dist/genui.js.map +1 -1
  172. package/dist/{grid-CEd64Lnh.js → grid-CifjQL-5.js} +2 -2
  173. package/dist/{grid-CEd64Lnh.js.map → grid-CifjQL-5.js.map} +1 -1
  174. package/dist/{highlight-to-react-D0Yav4jk.js → highlight-to-react-DN9dUCS2.js} +9 -15
  175. package/dist/highlight-to-react-DN9dUCS2.js.map +1 -0
  176. package/dist/index.js +71 -71
  177. package/dist/index.js.map +1 -1
  178. package/dist/{input-ClB_E4Lb.js → input-COmx2M_R.js} +5 -5
  179. package/dist/{input-ClB_E4Lb.js.map → input-COmx2M_R.js.map} +1 -1
  180. package/dist/{input-B2bbijRh.js → input-GkfMQZC_.js} +3 -3
  181. package/dist/{input-B2bbijRh.js.map → input-GkfMQZC_.js.map} +1 -1
  182. package/dist/{label-DUv_urO1.js → label-CiGZ464N.js} +3 -3
  183. package/dist/{label-DUv_urO1.js.map → label-CiGZ464N.js.map} +1 -1
  184. package/dist/{layer-card-BK7eYfwn.js → layer-card-8l8GuLQr.js} +2 -2
  185. package/dist/{layer-card-BK7eYfwn.js.map → layer-card-8l8GuLQr.js.map} +1 -1
  186. package/dist/{layout-DJHMMap2.js → layout-CWBE0qwx.js} +258 -154
  187. package/dist/layout-CWBE0qwx.js.map +1 -0
  188. package/dist/{link-provider-BUZKXaNE.js → link-provider-BSn8YJon.js} +2 -2
  189. package/dist/link-provider-BSn8YJon.js.map +1 -0
  190. package/dist/{loader-DAcc-Uag.js → loader-BEMz8pJO.js} +1 -1
  191. package/dist/{loader-DAcc-Uag.js.map → loader-BEMz8pJO.js.map} +1 -1
  192. package/dist/{measured-text-BI3dTJmH.js → measured-text-CXkdw9Yr.js} +45 -30
  193. package/dist/measured-text-CXkdw9Yr.js.map +1 -0
  194. package/dist/{menubar-Cxf3xeAt.js → menubar-CoOr4ocj.js} +3 -3
  195. package/dist/{menubar-Cxf3xeAt.js.map → menubar-CoOr4ocj.js.map} +1 -1
  196. package/dist/{meter-BFFe9l5b.js → meter-Pf_VOl59.js} +2 -2
  197. package/dist/{meter-BFFe9l5b.js.map → meter-Pf_VOl59.js.map} +1 -1
  198. package/dist/{pagination-yS372Tr4.js → pagination-DSY279Ta.js} +2 -2
  199. package/dist/{pagination-yS372Tr4.js.map → pagination-DSY279Ta.js.map} +1 -1
  200. package/dist/{popover-SRoJaCZr.js → popover-BY-e9co1.js} +2 -2
  201. package/dist/{popover-SRoJaCZr.js.map → popover-BY-e9co1.js.map} +1 -1
  202. package/dist/{radio-BcwhwYNB.js → radio-DZwL13j0.js} +2 -2
  203. package/dist/{radio-BcwhwYNB.js.map → radio-DZwL13j0.js.map} +1 -1
  204. package/dist/{select-DMhdoHMa.js → select-BFifYqHA.js} +6 -6
  205. package/dist/{select-DMhdoHMa.js.map → select-BFifYqHA.js.map} +1 -1
  206. package/dist/{sensitive-input-CJUpIRal.js → sensitive-input-DHLZcM73.js} +4 -4
  207. package/dist/{sensitive-input-CJUpIRal.js.map → sensitive-input-DHLZcM73.js.map} +1 -1
  208. package/dist/{sidebar-D4zrlYpn.js → sidebar-odGsdvG4.js} +6 -7
  209. package/dist/sidebar-odGsdvG4.js.map +1 -0
  210. package/dist/{signalflare-ai-logo-Bipogceq.js → signalflare-ai-logo-CNaDT_w8.js} +2 -2
  211. package/dist/{signalflare-ai-logo-Bipogceq.js.map → signalflare-ai-logo-CNaDT_w8.js.map} +1 -1
  212. package/dist/{skeleton-line-CH1-h6e2.js → skeleton-line-CxxYVTO2.js} +2 -2
  213. package/dist/{skeleton-line-CH1-h6e2.js.map → skeleton-line-CxxYVTO2.js.map} +1 -1
  214. package/dist/{sparkline-DHmgj1d0.js → sparkline-BQ-4j2W2.js} +2 -2
  215. package/dist/{sparkline-DHmgj1d0.js.map → sparkline-BQ-4j2W2.js.map} +1 -1
  216. package/dist/src/blocks/agent-harness/agent-harness.tsx +11 -11
  217. package/dist/src/blocks/commander/commander.tsx +15 -15
  218. package/dist/src/blocks/map-block/map-block.d.ts.map +1 -1
  219. package/dist/src/blocks/map-block/map-block.tsx +11 -7
  220. package/dist/src/components/ai-approval/ai-approval.d.ts.map +1 -1
  221. package/dist/src/components/ai-code-block/ai-code-block.d.ts +14 -13
  222. package/dist/src/components/ai-code-block/ai-code-block.d.ts.map +1 -1
  223. package/dist/src/components/ai-conversation/ai-conversation.d.ts.map +1 -1
  224. package/dist/src/components/ai-part-group/ai-part-group.d.ts.map +1 -1
  225. package/dist/src/components/ai-prompt-input/ai-prompt-input.d.ts.map +1 -1
  226. package/dist/src/components/ai-prompt-input/controller.d.ts.map +1 -1
  227. package/dist/src/components/ai-prompt-input/types.d.ts.map +1 -1
  228. package/dist/src/components/ai-question/ai-question.d.ts.map +1 -1
  229. package/dist/src/components/ai-reasoning/ai-reasoning.d.ts.map +1 -1
  230. package/dist/src/components/ai-response/ai-response.d.ts.map +1 -1
  231. package/dist/src/components/ai-subagent/ai-subagent.d.ts.map +1 -1
  232. package/dist/src/components/ai-tool/ai-tool.d.ts.map +1 -1
  233. package/dist/src/components/chart/echart.d.ts.map +1 -1
  234. package/dist/src/components/clipboard-text/clipboard-text.d.ts.map +1 -1
  235. package/dist/src/components/data-grid/data-grid.d.ts +2 -1
  236. package/dist/src/components/data-grid/data-grid.d.ts.map +1 -1
  237. package/dist/src/components/data-grid/features.d.ts +20 -0
  238. package/dist/src/components/data-grid/features.d.ts.map +1 -0
  239. package/dist/src/components/data-grid/types.d.ts +38 -7
  240. package/dist/src/components/data-grid/types.d.ts.map +1 -1
  241. package/dist/src/components/filters/filters.d.ts.map +1 -1
  242. package/dist/src/components/flow/use-children.d.ts +1 -1
  243. package/dist/src/components/link/link.d.ts.map +1 -1
  244. package/dist/src/components/sidebar/sidebar.d.ts +1 -1
  245. package/dist/src/components/signalflare-ai-logo/signalflare-ai-logo.d.ts.map +1 -1
  246. package/dist/src/components/text/text.d.ts +2 -1
  247. package/dist/src/components/text/text.d.ts.map +1 -1
  248. package/dist/src/components/text-roll/text-roll.d.ts.map +1 -1
  249. package/dist/src/components/theme-toggle/theme-toggle.d.ts.map +1 -1
  250. package/dist/src/components/toast/toast.d.ts.map +1 -1
  251. package/dist/src/utils/highlight-to-react.d.ts.map +1 -1
  252. package/dist/src/utils/measured-text.d.ts.map +1 -1
  253. package/dist/src/utils/use-measured-text.d.ts.map +1 -1
  254. package/dist/{stat-card-Ew-ofzEm.js → stat-card-Bspk4XFr.js} +4 -4
  255. package/dist/stat-card-Bspk4XFr.js.map +1 -0
  256. package/dist/styles/sf-standalone.css +1 -1
  257. package/dist/styles/theme-fedramp.css +3 -12
  258. package/dist/styles/theme-minimal.css +26 -104
  259. package/dist/styles/theme-sf.css +37 -142
  260. package/dist/{surface-DGwRlC0o.js → surface-CWdSFVUx.js} +3 -3
  261. package/dist/{surface-DGwRlC0o.js.map → surface-CWdSFVUx.js.map} +1 -1
  262. package/dist/{switch-BxAMfHdt.js → switch-TA4cByCJ.js} +5 -5
  263. package/dist/switch-TA4cByCJ.js.map +1 -0
  264. package/dist/{table-BBeAtYVZ.js → table-BM8JBGBs.js} +3 -3
  265. package/dist/{table-BBeAtYVZ.js.map → table-BM8JBGBs.js.map} +1 -1
  266. package/dist/{tabs-CeHu7Scn.js → tabs-bnH2vGLv.js} +2 -2
  267. package/dist/{tabs-CeHu7Scn.js.map → tabs-bnH2vGLv.js.map} +1 -1
  268. package/dist/{text-Cqryz7rk.js → text-iQ0YUFNg.js} +4 -5
  269. package/dist/{text-Cqryz7rk.js.map → text-iQ0YUFNg.js.map} +1 -1
  270. package/dist/{text-roll-Ch52hcQj.js → text-roll-C3U2jd2u.js} +5 -2
  271. package/dist/text-roll-C3U2jd2u.js.map +1 -0
  272. package/dist/{theme-toggle-LDfIKEqx.js → theme-toggle-BTVxD-fD.js} +10 -9
  273. package/dist/theme-toggle-BTVxD-fD.js.map +1 -0
  274. package/dist/{toast-CaFQNYng.js → toast-CgZVaAkw.js} +3 -3
  275. package/dist/{toast-CaFQNYng.js.map → toast-CgZVaAkw.js.map} +1 -1
  276. package/dist/{tooltip-g9lFsvcT.js → tooltip-uobk6Oh-.js} +3 -3
  277. package/dist/{tooltip-g9lFsvcT.js.map → tooltip-uobk6Oh-.js.map} +1 -1
  278. package/dist/{use-agent-harness-BTcNJdw4.js → use-agent-harness-Dl8w6X5O.js} +3 -3
  279. package/dist/{use-agent-harness-BTcNJdw4.js.map → use-agent-harness-Dl8w6X5O.js.map} +1 -1
  280. package/dist/utils.js +3 -3
  281. package/package.json +27 -25
  282. package/scripts/component-registry/discovery.ts +11 -10
  283. package/scripts/component-registry/example-cleanup.ts +8 -8
  284. package/scripts/component-registry/index.ts +6 -6
  285. package/scripts/component-registry/schema-generator.ts +1 -1
  286. package/scripts/component-registry/sub-components.ts +35 -23
  287. package/scripts/component-registry/utils.ts +11 -11
  288. package/scripts/component-registry/variant-parser.ts +17 -15
  289. package/scripts/convert-demos-to-stories.ts +5 -5
  290. package/scripts/theme-generator/config.ts +1 -5
  291. package/scripts/theme-generator/generate-css.ts +1 -1
  292. package/scripts/theme-generator/migrate.ts +3 -3
  293. package/dist/ai-agent-card-BR2NIYhi.js.map +0 -1
  294. package/dist/ai-code-block-CZtoL73R.js.map +0 -1
  295. package/dist/ai-conversation-Cc7WlaBg.js.map +0 -1
  296. package/dist/ai-part-group-DNb9I446.js.map +0 -1
  297. package/dist/ai-prompt-input-BVvov_KF.js.map +0 -1
  298. package/dist/ai-reasoning-_feFjk56.js.map +0 -1
  299. package/dist/ai-timeline-C42tOUT8.js.map +0 -1
  300. package/dist/ai-tool-03jOTwUI.js.map +0 -1
  301. package/dist/chart-Dg0qUeSc.js.map +0 -1
  302. package/dist/clipboard-text-kLaMogs3.js.map +0 -1
  303. package/dist/command-palette-CuNUyJca.js.map +0 -1
  304. package/dist/data-grid-DGHmU0w3.js +0 -305
  305. package/dist/data-grid-DGHmU0w3.js.map +0 -1
  306. package/dist/dist-B6iWiWwp.js.map +0 -1
  307. package/dist/dropdown-B_nrGXjV.js.map +0 -1
  308. package/dist/filters-cpJCY21R.js.map +0 -1
  309. package/dist/flow-B4v198ot.js.map +0 -1
  310. package/dist/highlight-to-react-D0Yav4jk.js.map +0 -1
  311. package/dist/layout-DJHMMap2.js.map +0 -1
  312. package/dist/link-provider-BUZKXaNE.js.map +0 -1
  313. package/dist/measured-text-BI3dTJmH.js.map +0 -1
  314. package/dist/sidebar-D4zrlYpn.js.map +0 -1
  315. package/dist/stat-card-Ew-ofzEm.js.map +0 -1
  316. package/dist/switch-BxAMfHdt.js.map +0 -1
  317. package/dist/text-roll-Ch52hcQj.js.map +0 -1
  318. package/dist/theme-toggle-LDfIKEqx.js.map +0 -1
@@ -1 +1 @@
1
- 1779493856635
1
+ 1780882427323
@@ -1 +1 @@
1
- {"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../../ai/schemas.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../../ai/schemas.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  "use client";
2
- import { t as cn } from "./cn-YROP2_ox.js";
3
- import { t as Tooltip } from "./tooltip-g9lFsvcT.js";
4
- import { t as Button } from "./button-CO6-qPax.js";
2
+ import { t as cn } from "./cn-CmAOpn49.js";
3
+ import { t as Tooltip } from "./tooltip-uobk6Oh-.js";
4
+ import { t as Button } from "./button-BHOgXJRU.js";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
  //#region src/components/ai-actions/ai-actions.tsx
7
7
  var SF_AI_ACTIONS_VARIANTS = {};
@@ -54,4 +54,4 @@ function AiAction({ tooltip, label, children, className, variant = "ghost", size
54
54
  //#endregion
55
55
  export { SF_AI_ACTIONS_VARIANTS as i, AiActions as n, SF_AI_ACTIONS_DEFAULT_VARIANTS as r, AiAction as t };
56
56
 
57
- //# sourceMappingURL=ai-actions-BdUZI3Gk.js.map
57
+ //# sourceMappingURL=ai-actions-CBfz5XEf.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ai-actions-BdUZI3Gk.js","names":[],"sources":["../src/components/ai-actions/ai-actions.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ComponentProps } from \"react\";\n\nimport { cn } from \"../../utils/cn\";\nimport { Button } from \"../button\";\nimport { Tooltip } from \"../tooltip\";\n\n// ─── Variants ────────────────────────────────────────────────────────────────\n\nexport const SF_AI_ACTIONS_VARIANTS = {} as const;\nexport const SF_AI_ACTIONS_DEFAULT_VARIANTS = {} as const;\n\n// ─── AiActions ───────────────────────────────────────────────────────────────\n\nexport type AiActionsProps = ComponentProps<\"div\">;\n\n/**\n * Container for a row of AI message action buttons.\n *\n * @example\n * ```tsx\n * <AiActions>\n * <AiAction tooltip=\"Copy\" onClick={handleCopy}><CopyIcon /></AiAction>\n * <AiAction tooltip=\"Retry\" onClick={handleRetry}><ArrowCounterClockwiseIcon /></AiAction>\n * </AiActions>\n * ```\n */\nexport function AiActions({ className, children, ...props }: AiActionsProps) {\n return (\n <div className={cn(\"flex items-center gap-1\", className)} {...props}>\n {children}\n </div>\n );\n}\n\n// ─── AiAction ────────────────────────────────────────────────────────────────\n\nexport type AiActionProps = ComponentProps<typeof Button> & {\n /** Tooltip text shown on hover. Also used as the accessible label. */\n tooltip?: string;\n /** Accessible label (overrides tooltip for sr-only text). */\n label?: string;\n};\n\n/**\n * A single icon button action for AI message toolbars, with optional tooltip.\n *\n * @example\n * ```tsx\n * <AiAction tooltip=\"Copy message\" onClick={handleCopy}>\n * <CopyIcon />\n * </AiAction>\n * ```\n */\nexport function AiAction({\n tooltip,\n label,\n children,\n className,\n variant = \"ghost\",\n size = \"sm\",\n ...props\n}: AiActionProps) {\n const button = (\n <Button\n className={cn(\"text-sf-subtle hover:text-sf-default\", className)}\n size={size}\n variant={variant}\n {...props}\n >\n {children}\n {(label ?? tooltip) && (\n <span className=\"sr-only\">{label ?? tooltip}</span>\n )}\n </Button>\n );\n\n if (tooltip) {\n return <Tooltip content={tooltip}>{button}</Tooltip>;\n }\n\n return button;\n}\n"],"mappings":";;;;;;AAUA,IAAa,yBAAyB,EAAE;AACxC,IAAa,iCAAiC,EAAE;;;;;;;;;;;;AAiBhD,SAAgB,UAAU,EAAE,WAAW,UAAU,GAAG,SAAyB;AAC3E,QACE,oBAAC,OAAD;EAAK,WAAW,GAAG,2BAA2B,UAAU;EAAE,GAAI;EAC3D;EACG,CAAA;;;;;;;;;;;;AAuBV,SAAgB,SAAS,EACvB,SACA,OACA,UACA,WACA,UAAU,SACV,OAAO,MACP,GAAG,SACa;CAChB,MAAM,SACJ,qBAAC,QAAD;EACE,WAAW,GAAG,wCAAwC,UAAU;EAC1D;EACG;EACT,GAAI;YAJN,CAMG,WACC,SAAS,YACT,oBAAC,QAAD;GAAM,WAAU;aAAW,SAAS;GAAe,CAAA,CAE9C;;AAGX,KAAI,QACF,QAAO,oBAAC,SAAD;EAAS,SAAS;YAAU;EAAiB,CAAA;AAGtD,QAAO"}
1
+ {"version":3,"file":"ai-actions-CBfz5XEf.js","names":[],"sources":["../src/components/ai-actions/ai-actions.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ComponentProps } from \"react\";\n\nimport { cn } from \"../../utils/cn\";\nimport { Button } from \"../button\";\nimport { Tooltip } from \"../tooltip\";\n\n// ─── Variants ────────────────────────────────────────────────────────────────\n\nexport const SF_AI_ACTIONS_VARIANTS = {} as const;\nexport const SF_AI_ACTIONS_DEFAULT_VARIANTS = {} as const;\n\n// ─── AiActions ───────────────────────────────────────────────────────────────\n\nexport type AiActionsProps = ComponentProps<\"div\">;\n\n/**\n * Container for a row of AI message action buttons.\n *\n * @example\n * ```tsx\n * <AiActions>\n * <AiAction tooltip=\"Copy\" onClick={handleCopy}><CopyIcon /></AiAction>\n * <AiAction tooltip=\"Retry\" onClick={handleRetry}><ArrowCounterClockwiseIcon /></AiAction>\n * </AiActions>\n * ```\n */\nexport function AiActions({ className, children, ...props }: AiActionsProps) {\n return (\n <div className={cn(\"flex items-center gap-1\", className)} {...props}>\n {children}\n </div>\n );\n}\n\n// ─── AiAction ────────────────────────────────────────────────────────────────\n\nexport type AiActionProps = ComponentProps<typeof Button> & {\n /** Tooltip text shown on hover. Also used as the accessible label. */\n tooltip?: string;\n /** Accessible label (overrides tooltip for sr-only text). */\n label?: string;\n};\n\n/**\n * A single icon button action for AI message toolbars, with optional tooltip.\n *\n * @example\n * ```tsx\n * <AiAction tooltip=\"Copy message\" onClick={handleCopy}>\n * <CopyIcon />\n * </AiAction>\n * ```\n */\nexport function AiAction({\n tooltip,\n label,\n children,\n className,\n variant = \"ghost\",\n size = \"sm\",\n ...props\n}: AiActionProps) {\n const button = (\n <Button\n className={cn(\"text-sf-subtle hover:text-sf-default\", className)}\n size={size}\n variant={variant}\n {...props}\n >\n {children}\n {(label ?? tooltip) && (\n <span className=\"sr-only\">{label ?? tooltip}</span>\n )}\n </Button>\n );\n\n if (tooltip) {\n return <Tooltip content={tooltip}>{button}</Tooltip>;\n }\n\n return button;\n}\n"],"mappings":";;;;;;AAUA,IAAa,yBAAyB,CAAC;AACvC,IAAa,iCAAiC,CAAC;;;;;;;;;;;;AAiB/C,SAAgB,UAAU,EAAE,WAAW,UAAU,GAAG,SAAyB;CAC3E,OACE,oBAAC,OAAD;EAAK,WAAW,GAAG,2BAA2B,SAAS;EAAG,GAAI;EAC3D;CACE,CAAA;AAET;;;;;;;;;;;AAqBA,SAAgB,SAAS,EACvB,SACA,OACA,UACA,WACA,UAAU,SACV,OAAO,MACP,GAAG,SACa;CAChB,MAAM,SACJ,qBAAC,QAAD;EACE,WAAW,GAAG,wCAAwC,SAAS;EACzD;EACG;EACT,GAAI;YAJN,CAMG,WACC,SAAS,YACT,oBAAC,QAAD;GAAM,WAAU;aAAW,SAAS;EAAc,CAAA,CAE9C;;CAGV,IAAI,SACF,OAAO,oBAAC,SAAD;EAAS,SAAS;YAAU;CAAgB,CAAA;CAGrD,OAAO;AACT"}
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { t as cn } from "./cn-YROP2_ox.js";
2
+ import { t as cn } from "./cn-CmAOpn49.js";
3
3
  import { forwardRef } from "react";
4
4
  import { jsx, jsxs } from "react/jsx-runtime";
5
5
  import { BrainIcon, CheckCircleIcon, CircleIcon, CodeIcon, MagnifyingGlassIcon, RobotIcon, SpinnerGapIcon, WrenchIcon, XCircleIcon } from "@phosphor-icons/react";
@@ -64,7 +64,7 @@ function formatDuration(ms) {
64
64
  }
65
65
  function getModelShortName(modelId) {
66
66
  if (!modelId) return "";
67
- return modelId.split("/").pop()?.replace(/^claude-/, "").replace(/-\d+$/, "") ?? modelId;
67
+ return modelId.split("/").pop()?.replace(/^claude-/u, "").replace(/-\d+$/u, "") ?? modelId;
68
68
  }
69
69
  var STATUS_DOT = {
70
70
  idle: "bg-sf-fill",
@@ -168,4 +168,4 @@ AiAgentCard.displayName = "AiAgentCard";
168
168
  //#endregion
169
169
  export { SF_AI_AGENT_CARD_DEFAULT_VARIANTS as n, SF_AI_AGENT_CARD_VARIANTS as r, AiAgentCard as t };
170
170
 
171
- //# sourceMappingURL=ai-agent-card-BR2NIYhi.js.map
171
+ //# sourceMappingURL=ai-agent-card-CByAUe0q.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-agent-card-CByAUe0q.js","names":[],"sources":["../src/components/ai-agent-card/ai-agent-card.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n BrainIcon,\n CheckCircleIcon,\n CircleIcon,\n CodeIcon,\n MagnifyingGlassIcon,\n RobotIcon,\n SpinnerGapIcon,\n WrenchIcon,\n XCircleIcon,\n} from \"@phosphor-icons/react\";\nimport type { ComponentProps, ElementType } from \"react\";\nimport { forwardRef } from \"react\";\n\nimport { cn } from \"../../utils/cn\";\n\n// ─── Variants ────────────────────────────────────────────────────────────────\n\nexport const SF_AI_AGENT_CARD_VARIANTS = {\n status: {\n idle: { classes: \"\", description: \"Agent is idle, not yet started\" },\n running: { classes: \"\", description: \"Agent is actively working\" },\n completed: { classes: \"\", description: \"Agent finished successfully\" },\n error: { classes: \"\", description: \"Agent encountered an error\" },\n },\n size: {\n sm: { classes: \"\", description: \"Compact card for dense grids\" },\n md: { classes: \"\", description: \"Default card size\" },\n },\n} as const;\n\nexport const SF_AI_AGENT_CARD_DEFAULT_VARIANTS = {\n status: \"idle\",\n size: \"md\",\n} as const;\n\nexport type SFAiAgentCardStatus = keyof typeof SF_AI_AGENT_CARD_VARIANTS.status;\nexport type SFAiAgentCardSize = keyof typeof SF_AI_AGENT_CARD_VARIANTS.size;\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport type AiAgentCardProps = Omit<ComponentProps<\"button\">, \"children\"> & {\n /** Human-readable agent name (e.g. \"Explore\", \"Execute\"). */\n name: string;\n /** Agent type ID — used for icon mapping. */\n agentType?: string;\n /** Current status. @default \"idle\" */\n status?: SFAiAgentCardStatus;\n /** Model ID being used (e.g. \"claude-haiku-3.5\"). */\n modelId?: string;\n /** What the agent is currently doing. */\n currentTask?: string;\n /** Total elapsed duration in ms. */\n duration?: number;\n /** Number of tool calls made. */\n toolCallCount?: number;\n /** Whether this card is currently selected/active. */\n selected?: boolean;\n /** Custom icon override. */\n icon?: ElementType;\n /** Card size. @default \"md\" */\n size?: SFAiAgentCardSize;\n};\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\nconst AGENT_TYPE_ICONS: Record<string, ElementType> = {\n explore: MagnifyingGlassIcon,\n search: MagnifyingGlassIcon,\n execute: CodeIcon,\n code: CodeIcon,\n plan: BrainIcon,\n think: BrainIcon,\n tool: WrenchIcon,\n build: WrenchIcon,\n};\n\nfunction getAgentIcon(\n agentType?: string,\n customIcon?: ElementType\n): ElementType {\n if (customIcon) return customIcon;\n if (agentType) {\n const lower = agentType.toLowerCase();\n for (const [key, icon] of Object.entries(AGENT_TYPE_ICONS)) {\n if (lower.includes(key)) return icon;\n }\n }\n return RobotIcon;\n}\n\nfunction formatDuration(ms: number): string {\n if (ms < 1000) return `${ms}ms`;\n const s = Math.round(ms / 100) / 10;\n if (s < 60) return `${s}s`;\n const m = Math.floor(s / 60);\n const rem = Math.round(s % 60);\n return `${m}m ${rem}s`;\n}\n\nfunction getModelShortName(modelId?: string): string {\n if (!modelId) return \"\";\n return (\n modelId\n .split(\"/\")\n .pop()\n ?.replace(/^claude-/u, \"\")\n .replace(/-\\d+$/u, \"\") ?? modelId\n );\n}\n\n// ─── Status decorations ───────────────────────────────────────────────────────\n\nconst STATUS_DOT: Record<SFAiAgentCardStatus, string> = {\n idle: \"bg-sf-fill\",\n running: \"bg-sf-brand animate-pulse\",\n completed: \"bg-sf-success\",\n error: \"bg-sf-danger\",\n};\n\nfunction StatusIcon({\n status,\n size = 14,\n}: {\n status: SFAiAgentCardStatus;\n size?: number;\n}) {\n switch (status) {\n case \"running\":\n return (\n <SpinnerGapIcon size={size} className=\"animate-spin text-sf-brand\" />\n );\n case \"completed\":\n return <CheckCircleIcon size={size} className=\"text-sf-success\" />;\n case \"error\":\n return <XCircleIcon size={size} className=\"text-sf-danger\" />;\n default:\n return <CircleIcon size={size} className=\"text-sf-inactive\" />;\n }\n}\n\n// ─── Component ────────────────────────────────────────────────────────────────\n\n/**\n * `AiAgentCard` — compact card showing one agent's status in a commander dashboard.\n *\n * Displays: agent icon, name, status indicator, current task, model, duration,\n * and tool call count. Clickable for selection.\n *\n * @example\n * ```tsx\n * <AiAgentCard\n * name=\"Explore\"\n * agentType=\"explore\"\n * status=\"running\"\n * modelId=\"claude-haiku-3.5\"\n * currentTask=\"Scanning auth files...\"\n * duration={4200}\n * toolCallCount={3}\n * selected\n * onClick={handleSelect}\n * />\n * ```\n */\nexport const AiAgentCard = forwardRef<HTMLButtonElement, AiAgentCardProps>(\n (\n {\n name,\n agentType,\n status = SF_AI_AGENT_CARD_DEFAULT_VARIANTS.status,\n modelId,\n currentTask,\n duration,\n toolCallCount,\n selected,\n icon,\n size = SF_AI_AGENT_CARD_DEFAULT_VARIANTS.size,\n className,\n onClick,\n ...props\n },\n ref\n ) => {\n const Icon = getAgentIcon(agentType, icon);\n const modelShort = getModelShortName(modelId);\n const isSm = size === \"sm\";\n\n return (\n <button\n ref={ref}\n type=\"button\"\n aria-pressed={selected}\n onClick={onClick}\n className={cn(\n \"group flex flex-col gap-2 rounded-xl border text-left transition-all\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-sf-ring focus-visible:ring-offset-1\",\n isSm ? \"p-2.5\" : \"p-3.5\",\n selected\n ? \"border-sf-line bg-sf-recessed shadow-sm\"\n : \"border-sf-line bg-sf-elevated hover:border-sf-line hover:bg-sf-tint\",\n !onClick && \"cursor-default\",\n className\n )}\n {...props}\n >\n {/* Header row */}\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex items-center gap-2 min-w-0\">\n {/* Agent icon */}\n <div\n className={cn(\n \"flex shrink-0 items-center justify-center rounded-lg\",\n isSm ? \"size-6\" : \"size-8\",\n status === \"running\"\n ? \"bg-sf-brand/10 text-sf-brand\"\n : status === \"completed\"\n ? \"bg-sf-tint text-sf-success\"\n : status === \"error\"\n ? \"bg-sf-tint text-sf-danger\"\n : \"bg-sf-fill text-sf-subtle\"\n )}\n >\n <Icon size={isSm ? 12 : 16} />\n </div>\n\n {/* Name */}\n <span\n className={cn(\n \"truncate font-medium text-sf-default\",\n isSm ? \"text-xs\" : \"text-sm\"\n )}\n >\n {name}\n </span>\n </div>\n\n {/* Status icon */}\n <StatusIcon status={status} size={isSm ? 12 : 14} />\n </div>\n\n {/* Current task */}\n {currentTask && (\n <p\n className={cn(\n \"truncate text-sf-subtle leading-snug\",\n isSm ? \"text-[10px]\" : \"text-xs\"\n )}\n >\n {currentTask}\n </p>\n )}\n\n {/* Footer row: model + stats */}\n {!isSm && (\n <div className=\"flex items-center justify-between gap-2\">\n <div className=\"flex items-center gap-1.5\">\n {/* Status dot + model */}\n <span\n className={cn(\n \"size-1.5 shrink-0 rounded-full\",\n STATUS_DOT[status]\n )}\n />\n {modelShort && (\n <span className=\"font-mono text-[10px] text-sf-inactive\">\n {modelShort}\n </span>\n )}\n </div>\n\n <div className=\"flex items-center gap-2 text-[10px] text-sf-subtle\">\n {typeof toolCallCount === \"number\" && toolCallCount > 0 && (\n <span className=\"flex items-center gap-0.5\">\n <WrenchIcon size={9} />\n {toolCallCount}\n </span>\n )}\n {typeof duration === \"number\" && (\n <span>{formatDuration(duration)}</span>\n )}\n </div>\n </div>\n )}\n </button>\n );\n }\n);\n\nAiAgentCard.displayName = \"AiAgentCard\";\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  "use client";
2
- import { t as cn } from "./cn-YROP2_ox.js";
3
- import { t as Button } from "./button-CO6-qPax.js";
2
+ import { t as cn } from "./cn-CmAOpn49.js";
3
+ import { t as Button } from "./button-BHOgXJRU.js";
4
4
  import { useCallback, useState } from "react";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
  import { CheckCircleIcon, ListChecksIcon, ProhibitIcon, ShieldCheckIcon } from "@phosphor-icons/react";
@@ -153,6 +153,7 @@ function AiApproval({ kind = "tool", status = "pending", title, description, ico
153
153
  }),
154
154
  children,
155
155
  isPending && showFeedback && /* @__PURE__ */ jsx("textarea", {
156
+ "aria-label": "Optional feedback",
156
157
  className: "mx-0 min-h-[60px] resize-none rounded-md border border-sf-line bg-sf-base px-2.5 py-1.5 text-xs text-sf-default outline-none placeholder:text-sf-inactive focus:border-sf-ring",
157
158
  onChange: (e) => setFeedback(e.target.value),
158
159
  placeholder: "Optional feedback…",
@@ -181,4 +182,4 @@ AiApproval.displayName = "AiApproval";
181
182
  //#endregion
182
183
  export { SF_AI_APPROVAL_DEFAULT_VARIANTS as n, SF_AI_APPROVAL_VARIANTS as r, AiApproval as t };
183
184
 
184
- //# sourceMappingURL=ai-approval-Ba7mrKba.js.map
185
+ //# sourceMappingURL=ai-approval-Ci8N70a7.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ai-approval-Ba7mrKba.js","names":[],"sources":["../src/components/ai-approval/ai-approval.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n CheckCircleIcon,\n ProhibitIcon,\n ShieldCheckIcon,\n ListChecksIcon,\n} from \"@phosphor-icons/react\";\nimport type { ElementType, HTMLAttributes, ReactNode } from \"react\";\nimport { useCallback, useState } from \"react\";\n\nimport { cn } from \"../../utils/cn\";\nimport { Button } from \"../button\";\n\n// ─── Variants ────────────────────────────────────────────────────────────────\n\nexport const SF_AI_APPROVAL_VARIANTS = {\n kind: {\n tool: { classes: \"\", description: \"Tool call approval\" },\n plan: { classes: \"\", description: \"Plan approval\" },\n },\n status: {\n pending: { classes: \"\", description: \"Awaiting user decision\" },\n approved: { classes: \"\", description: \"Approved by user\" },\n rejected: { classes: \"\", description: \"Rejected by user\" },\n },\n} as const;\n\nexport const SF_AI_APPROVAL_DEFAULT_VARIANTS = {\n kind: \"tool\",\n status: \"pending\",\n} as const;\n\nexport type SFAiApprovalKind = keyof typeof SF_AI_APPROVAL_VARIANTS.kind;\nexport type SFAiApprovalStatus = keyof typeof SF_AI_APPROVAL_VARIANTS.status;\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport type AiApprovalItem = {\n id: string;\n label: string;\n description?: string;\n};\n\nexport type AiApprovalProps = Omit<HTMLAttributes<HTMLDivElement>, \"title\"> & {\n /** Approval kind — `\"tool\"` for individual tool calls, `\"plan\"` for multi-step plans. */\n kind?: SFAiApprovalKind;\n /** Current approval status. */\n status?: SFAiApprovalStatus;\n /** Title text shown in the header. */\n title: string;\n /** Optional description below the title. */\n description?: string;\n /** Custom icon. Defaults to shield (tool) or list (plan). */\n icon?: ElementType;\n /**\n * For plan approvals: list of steps/items in the plan.\n * For tool approvals: can show tool name, parameters, etc.\n */\n items?: AiApprovalItem[];\n /** Called when user approves. */\n onApprove?: () => void;\n /** Called when user rejects. Receives optional feedback string. */\n onReject?: (feedback?: string) => void;\n /** Label for the approve button. Default: `\"Approve\"`. */\n approveLabel?: string;\n /** Label for the reject button. Default: `\"Reject\"`. */\n rejectLabel?: string;\n /** Show a text input for rejection feedback. Default: `false`. */\n showFeedback?: boolean;\n /** Content rendered below items and above the action buttons. */\n children?: ReactNode;\n};\n\n// ─── Component ────────────────────────────────────────────────────────────────\n\nconst KIND_ICONS: Record<SFAiApprovalKind, ElementType> = {\n tool: ShieldCheckIcon,\n plan: ListChecksIcon,\n};\n\nconst STATUS_CONFIG: Record<\n SFAiApprovalStatus,\n { icon: ElementType; label: string; className: string }\n> = {\n pending: {\n icon: ShieldCheckIcon,\n label: \"Awaiting approval\",\n className: \"text-sf-subtle\",\n },\n approved: {\n icon: CheckCircleIcon,\n label: \"Approved\",\n className: \"text-sf-success\",\n },\n rejected: {\n icon: ProhibitIcon,\n label: \"Rejected\",\n className: \"text-sf-danger\",\n },\n};\n\n/**\n * Approval card for tool calls and plan submissions.\n *\n * Maps to harness events: `tool_approval_required`, `plan_approval_required`,\n * `plan_approved`.\n *\n * @example\n * ```tsx\n * <AiApproval\n * kind=\"tool\"\n * title=\"Execute shell command\"\n * description=\"rm -rf /tmp/cache\"\n * onApprove={() => harness.respondToToolApproval({ decision: 'approve' })}\n * onReject={() => harness.respondToToolApproval({ decision: 'decline' })}\n * />\n *\n * <AiApproval\n * kind=\"plan\"\n * title=\"Deployment plan\"\n * items={[\n * { id: \"1\", label: \"Run tests\" },\n * { id: \"2\", label: \"Build production bundle\" },\n * { id: \"3\", label: \"Deploy to staging\" },\n * ]}\n * showFeedback\n * onApprove={() => harness.respondToPlanApproval({ planId, response: { action: 'approved' } })}\n * onReject={(feedback) => harness.respondToPlanApproval({ planId, response: { action: 'rejected', feedback } })}\n * />\n * ```\n */\nexport function AiApproval({\n kind = \"tool\",\n status = \"pending\",\n title,\n description,\n icon,\n items,\n onApprove,\n onReject,\n approveLabel = \"Approve\",\n rejectLabel = \"Reject\",\n showFeedback = false,\n children,\n className,\n ...props\n}: AiApprovalProps) {\n const [feedback, setFeedback] = useState(\"\");\n const isPending = status === \"pending\";\n\n const IconComponent = icon ?? KIND_ICONS[kind];\n const statusConfig = STATUS_CONFIG[status];\n const StatusIcon = statusConfig.icon;\n\n const handleReject = useCallback(() => {\n onReject?.(showFeedback ? feedback : undefined);\n }, [onReject, showFeedback, feedback]);\n\n return (\n <div\n className={cn(\n \"flex flex-col gap-2.5 rounded-lg border border-sf-line bg-sf-elevated p-3\",\n !isPending && \"opacity-75\",\n className\n )}\n {...props}\n >\n {/* Header */}\n <div className=\"flex items-start gap-2.5\">\n <div\n className={cn(\n \"mt-0.5 flex size-6 shrink-0 items-center justify-center rounded-md\",\n isPending ? \"bg-sf-brand/10 text-sf-brand\" : statusConfig.className\n )}\n >\n {isPending ? (\n <IconComponent className=\"size-4\" weight=\"bold\" />\n ) : (\n <StatusIcon className=\"size-4\" weight=\"bold\" />\n )}\n </div>\n <div className=\"flex min-w-0 flex-col gap-0.5\">\n <span className=\"text-sm font-medium text-sf-default\">{title}</span>\n {description && (\n <span className=\"text-xs text-sf-subtle\">{description}</span>\n )}\n </div>\n {!isPending && (\n <span\n className={cn(\n \"ml-auto shrink-0 text-xs font-medium\",\n statusConfig.className\n )}\n >\n {statusConfig.label}\n </span>\n )}\n </div>\n\n {/* Items (plan steps / tool details) */}\n {items && items.length > 0 && (\n <div className=\"flex flex-col gap-1 pl-8\">\n {items.map((item, index) => (\n <div key={item.id} className=\"flex items-start gap-2 text-xs\">\n <span className=\"mt-px shrink-0 font-mono text-sf-subtle\">\n {index + 1}.\n </span>\n <div className=\"flex min-w-0 flex-col\">\n <span className=\"text-sf-default\">{item.label}</span>\n {item.description && (\n <span className=\"text-sf-subtle\">{item.description}</span>\n )}\n </div>\n </div>\n ))}\n </div>\n )}\n\n {children}\n\n {/* Feedback input */}\n {isPending && showFeedback && (\n <textarea\n className=\"mx-0 min-h-[60px] resize-none rounded-md border border-sf-line bg-sf-base px-2.5 py-1.5 text-xs text-sf-default outline-none placeholder:text-sf-inactive focus:border-sf-ring\"\n onChange={(e) => setFeedback(e.target.value)}\n placeholder=\"Optional feedback…\"\n value={feedback}\n />\n )}\n\n {/* Action buttons */}\n {isPending && (\n <div className=\"flex items-center justify-end gap-2\">\n <Button\n onClick={handleReject}\n size=\"sm\"\n type=\"button\"\n variant=\"ghost\"\n >\n {rejectLabel}\n </Button>\n <Button onClick={onApprove} size=\"sm\" type=\"button\" variant=\"primary\">\n {approveLabel}\n </Button>\n </div>\n )}\n </div>\n );\n}\n\nAiApproval.displayName = \"AiApproval\";\n"],"mappings":";;;;;;;AAgBA,IAAa,0BAA0B;CACrC,MAAM;EACJ,MAAM;GAAE,SAAS;GAAI,aAAa;GAAsB;EACxD,MAAM;GAAE,SAAS;GAAI,aAAa;GAAiB;EACpD;CACD,QAAQ;EACN,SAAS;GAAE,SAAS;GAAI,aAAa;GAA0B;EAC/D,UAAU;GAAE,SAAS;GAAI,aAAa;GAAoB;EAC1D,UAAU;GAAE,SAAS;GAAI,aAAa;GAAoB;EAC3D;CACF;AAED,IAAa,kCAAkC;CAC7C,MAAM;CACN,QAAQ;CACT;AA6CD,IAAM,aAAoD;CACxD,MAAM;CACN,MAAM;CACP;AAED,IAAM,gBAGF;CACF,SAAS;EACP,MAAM;EACN,OAAO;EACP,WAAW;EACZ;CACD,UAAU;EACR,MAAM;EACN,OAAO;EACP,WAAW;EACZ;CACD,UAAU;EACR,MAAM;EACN,OAAO;EACP,WAAW;EACZ;CACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCD,SAAgB,WAAW,EACzB,OAAO,QACP,SAAS,WACT,OACA,aACA,MACA,OACA,WACA,UACA,eAAe,WACf,cAAc,UACd,eAAe,OACf,UACA,WACA,GAAG,SACe;CAClB,MAAM,CAAC,UAAU,eAAe,SAAS,GAAG;CAC5C,MAAM,YAAY,WAAW;CAE7B,MAAM,gBAAgB,QAAQ,WAAW;CACzC,MAAM,eAAe,cAAc;CACnC,MAAM,aAAa,aAAa;CAEhC,MAAM,eAAe,kBAAkB;AACrC,aAAW,eAAe,WAAW,KAAA,EAAU;IAC9C;EAAC;EAAU;EAAc;EAAS,CAAC;AAEtC,QACE,qBAAC,OAAD;EACE,WAAW,GACT,6EACA,CAAC,aAAa,cACd,UACD;EACD,GAAI;YANN;GASE,qBAAC,OAAD;IAAK,WAAU;cAAf;KACE,oBAAC,OAAD;MACE,WAAW,GACT,sEACA,YAAY,iCAAiC,aAAa,UAC3D;gBAEA,YACC,oBAAC,eAAD;OAAe,WAAU;OAAS,QAAO;OAAS,CAAA,GAElD,oBAAC,YAAD;OAAY,WAAU;OAAS,QAAO;OAAS,CAAA;MAE7C,CAAA;KACN,qBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,oBAAC,QAAD;OAAM,WAAU;iBAAuC;OAAa,CAAA,EACnE,eACC,oBAAC,QAAD;OAAM,WAAU;iBAA0B;OAAmB,CAAA,CAE3D;;KACL,CAAC,aACA,oBAAC,QAAD;MACE,WAAW,GACT,wCACA,aAAa,UACd;gBAEA,aAAa;MACT,CAAA;KAEL;;GAGL,SAAS,MAAM,SAAS,KACvB,oBAAC,OAAD;IAAK,WAAU;cACZ,MAAM,KAAK,MAAM,UAChB,qBAAC,OAAD;KAAmB,WAAU;eAA7B,CACE,qBAAC,QAAD;MAAM,WAAU;gBAAhB,CACG,QAAQ,GAAE,IACN;SACP,qBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,oBAAC,QAAD;OAAM,WAAU;iBAAmB,KAAK;OAAa,CAAA,EACpD,KAAK,eACJ,oBAAC,QAAD;OAAM,WAAU;iBAAkB,KAAK;OAAmB,CAAA,CAExD;QACF;OAVI,KAAK,GAUT,CACN;IACE,CAAA;GAGP;GAGA,aAAa,gBACZ,oBAAC,YAAD;IACE,WAAU;IACV,WAAW,MAAM,YAAY,EAAE,OAAO,MAAM;IAC5C,aAAY;IACZ,OAAO;IACP,CAAA;GAIH,aACC,qBAAC,OAAD;IAAK,WAAU;cAAf,CACE,oBAAC,QAAD;KACE,SAAS;KACT,MAAK;KACL,MAAK;KACL,SAAQ;eAEP;KACM,CAAA,EACT,oBAAC,QAAD;KAAQ,SAAS;KAAW,MAAK;KAAK,MAAK;KAAS,SAAQ;eACzD;KACM,CAAA,CACL;;GAEJ;;;AAIV,WAAW,cAAc"}
1
+ {"version":3,"file":"ai-approval-Ci8N70a7.js","names":[],"sources":["../src/components/ai-approval/ai-approval.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n CheckCircleIcon,\n ProhibitIcon,\n ShieldCheckIcon,\n ListChecksIcon,\n} from \"@phosphor-icons/react\";\nimport type { ElementType, HTMLAttributes, ReactNode } from \"react\";\nimport { useCallback, useState } from \"react\";\n\nimport { cn } from \"../../utils/cn\";\nimport { Button } from \"../button\";\n\n// ─── Variants ────────────────────────────────────────────────────────────────\n\nexport const SF_AI_APPROVAL_VARIANTS = {\n kind: {\n tool: { classes: \"\", description: \"Tool call approval\" },\n plan: { classes: \"\", description: \"Plan approval\" },\n },\n status: {\n pending: { classes: \"\", description: \"Awaiting user decision\" },\n approved: { classes: \"\", description: \"Approved by user\" },\n rejected: { classes: \"\", description: \"Rejected by user\" },\n },\n} as const;\n\nexport const SF_AI_APPROVAL_DEFAULT_VARIANTS = {\n kind: \"tool\",\n status: \"pending\",\n} as const;\n\nexport type SFAiApprovalKind = keyof typeof SF_AI_APPROVAL_VARIANTS.kind;\nexport type SFAiApprovalStatus = keyof typeof SF_AI_APPROVAL_VARIANTS.status;\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport type AiApprovalItem = {\n id: string;\n label: string;\n description?: string;\n};\n\nexport type AiApprovalProps = Omit<HTMLAttributes<HTMLDivElement>, \"title\"> & {\n /** Approval kind — `\"tool\"` for individual tool calls, `\"plan\"` for multi-step plans. */\n kind?: SFAiApprovalKind;\n /** Current approval status. */\n status?: SFAiApprovalStatus;\n /** Title text shown in the header. */\n title: string;\n /** Optional description below the title. */\n description?: string;\n /** Custom icon. Defaults to shield (tool) or list (plan). */\n icon?: ElementType;\n /**\n * For plan approvals: list of steps/items in the plan.\n * For tool approvals: can show tool name, parameters, etc.\n */\n items?: AiApprovalItem[];\n /** Called when user approves. */\n onApprove?: () => void;\n /** Called when user rejects. Receives optional feedback string. */\n onReject?: (feedback?: string) => void;\n /** Label for the approve button. Default: `\"Approve\"`. */\n approveLabel?: string;\n /** Label for the reject button. Default: `\"Reject\"`. */\n rejectLabel?: string;\n /** Show a text input for rejection feedback. Default: `false`. */\n showFeedback?: boolean;\n /** Content rendered below items and above the action buttons. */\n children?: ReactNode;\n};\n\n// ─── Component ────────────────────────────────────────────────────────────────\n\nconst KIND_ICONS: Record<SFAiApprovalKind, ElementType> = {\n tool: ShieldCheckIcon,\n plan: ListChecksIcon,\n};\n\nconst STATUS_CONFIG: Record<\n SFAiApprovalStatus,\n { icon: ElementType; label: string; className: string }\n> = {\n pending: {\n icon: ShieldCheckIcon,\n label: \"Awaiting approval\",\n className: \"text-sf-subtle\",\n },\n approved: {\n icon: CheckCircleIcon,\n label: \"Approved\",\n className: \"text-sf-success\",\n },\n rejected: {\n icon: ProhibitIcon,\n label: \"Rejected\",\n className: \"text-sf-danger\",\n },\n};\n\n/**\n * Approval card for tool calls and plan submissions.\n *\n * Maps to harness events: `tool_approval_required`, `plan_approval_required`,\n * `plan_approved`.\n *\n * @example\n * ```tsx\n * <AiApproval\n * kind=\"tool\"\n * title=\"Execute shell command\"\n * description=\"rm -rf /tmp/cache\"\n * onApprove={() => harness.respondToToolApproval({ decision: 'approve' })}\n * onReject={() => harness.respondToToolApproval({ decision: 'decline' })}\n * />\n *\n * <AiApproval\n * kind=\"plan\"\n * title=\"Deployment plan\"\n * items={[\n * { id: \"1\", label: \"Run tests\" },\n * { id: \"2\", label: \"Build production bundle\" },\n * { id: \"3\", label: \"Deploy to staging\" },\n * ]}\n * showFeedback\n * onApprove={() => harness.respondToPlanApproval({ planId, response: { action: 'approved' } })}\n * onReject={(feedback) => harness.respondToPlanApproval({ planId, response: { action: 'rejected', feedback } })}\n * />\n * ```\n */\nexport function AiApproval({\n kind = \"tool\",\n status = \"pending\",\n title,\n description,\n icon,\n items,\n onApprove,\n onReject,\n approveLabel = \"Approve\",\n rejectLabel = \"Reject\",\n showFeedback = false,\n children,\n className,\n ...props\n}: AiApprovalProps) {\n const [feedback, setFeedback] = useState(\"\");\n const isPending = status === \"pending\";\n\n const IconComponent = icon ?? KIND_ICONS[kind];\n const statusConfig = STATUS_CONFIG[status];\n const StatusIcon = statusConfig.icon;\n\n const handleReject = useCallback(() => {\n onReject?.(showFeedback ? feedback : undefined);\n }, [onReject, showFeedback, feedback]);\n\n return (\n <div\n className={cn(\n \"flex flex-col gap-2.5 rounded-lg border border-sf-line bg-sf-elevated p-3\",\n !isPending && \"opacity-75\",\n className\n )}\n {...props}\n >\n {/* Header */}\n <div className=\"flex items-start gap-2.5\">\n <div\n className={cn(\n \"mt-0.5 flex size-6 shrink-0 items-center justify-center rounded-md\",\n isPending ? \"bg-sf-brand/10 text-sf-brand\" : statusConfig.className\n )}\n >\n {isPending ? (\n <IconComponent className=\"size-4\" weight=\"bold\" />\n ) : (\n <StatusIcon className=\"size-4\" weight=\"bold\" />\n )}\n </div>\n <div className=\"flex min-w-0 flex-col gap-0.5\">\n <span className=\"text-sm font-medium text-sf-default\">{title}</span>\n {description && (\n <span className=\"text-xs text-sf-subtle\">{description}</span>\n )}\n </div>\n {!isPending && (\n <span\n className={cn(\n \"ml-auto shrink-0 text-xs font-medium\",\n statusConfig.className\n )}\n >\n {statusConfig.label}\n </span>\n )}\n </div>\n\n {/* Items (plan steps / tool details) */}\n {items && items.length > 0 && (\n <div className=\"flex flex-col gap-1 pl-8\">\n {items.map((item, index) => (\n <div key={item.id} className=\"flex items-start gap-2 text-xs\">\n <span className=\"mt-px shrink-0 font-mono text-sf-subtle\">\n {index + 1}.\n </span>\n <div className=\"flex min-w-0 flex-col\">\n <span className=\"text-sf-default\">{item.label}</span>\n {item.description && (\n <span className=\"text-sf-subtle\">{item.description}</span>\n )}\n </div>\n </div>\n ))}\n </div>\n )}\n\n {children}\n\n {/* Feedback input */}\n {isPending && showFeedback && (\n <textarea\n aria-label=\"Optional feedback\"\n className=\"mx-0 min-h-[60px] resize-none rounded-md border border-sf-line bg-sf-base px-2.5 py-1.5 text-xs text-sf-default outline-none placeholder:text-sf-inactive focus:border-sf-ring\"\n onChange={(e) => setFeedback(e.target.value)}\n placeholder=\"Optional feedback…\"\n value={feedback}\n />\n )}\n\n {/* Action buttons */}\n {isPending && (\n <div className=\"flex items-center justify-end gap-2\">\n <Button\n onClick={handleReject}\n size=\"sm\"\n type=\"button\"\n variant=\"ghost\"\n >\n {rejectLabel}\n </Button>\n <Button onClick={onApprove} size=\"sm\" type=\"button\" variant=\"primary\">\n {approveLabel}\n </Button>\n </div>\n )}\n </div>\n );\n}\n\nAiApproval.displayName = \"AiApproval\";\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  "use client";
2
- import { t as cn } from "./cn-YROP2_ox.js";
3
- import { t as Button } from "./button-CO6-qPax.js";
4
- import { t as highlightToLines } from "./highlight-to-react-D0Yav4jk.js";
2
+ import { t as cn } from "./cn-CmAOpn49.js";
3
+ import { t as Button } from "./button-BHOgXJRU.js";
4
+ import { t as highlightToLines } from "./highlight-to-react-DN9dUCS2.js";
5
5
  import { createContext, memo, useContext, useState } from "react";
6
6
  import { jsx, jsxs } from "react/jsx-runtime";
7
7
  import { highlight } from "sugar-high";
@@ -21,52 +21,50 @@ var AiCodeBlockContext = createContext({ code: "" });
21
21
  * </AiCodeBlock>
22
22
  * ```
23
23
  */
24
- var AiCodeBlock = memo(({ code, language, showLineNumbers = false, className, children, ...props }) => {
24
+ var AiCodeBlockBase = memo(({ code, language, showLineNumbers = false, className, children, ...props }) => {
25
25
  const highlightedLines = highlightToLines(highlight(code));
26
+ const hasInlineOverlay = !language && Boolean(children);
26
27
  return /* @__PURE__ */ jsx(AiCodeBlockContext.Provider, {
27
28
  value: { code },
28
29
  children: /* @__PURE__ */ jsxs("div", {
29
30
  className: cn("relative w-full overflow-hidden rounded-lg border border-sf-line bg-sf-recessed font-mono text-sm text-sf-default", className),
30
31
  ...props,
31
- children: [
32
- language && /* @__PURE__ */ jsxs("div", {
33
- className: "flex items-center justify-between border-b border-sf-line px-4 py-2",
34
- children: [/* @__PURE__ */ jsx("span", {
35
- className: "text-sf-subtle text-xs",
36
- children: language
37
- }), children && /* @__PURE__ */ jsx("div", {
38
- className: "flex items-center gap-2",
39
- children
40
- })]
41
- }),
42
- /* @__PURE__ */ jsx("div", {
43
- className: "overflow-x-auto",
44
- children: /* @__PURE__ */ jsx("table", {
45
- className: "w-full border-collapse",
46
- children: /* @__PURE__ */ jsx("tbody", { children: highlightedLines.map((line, i) => /* @__PURE__ */ jsxs("tr", {
47
- className: "leading-6",
48
- children: [showLineNumbers && /* @__PURE__ */ jsx("td", {
49
- className: "select-none pr-4 pl-4 text-right text-sf-inactive",
50
- children: i + 1
51
- }), /* @__PURE__ */ jsx("td", {
52
- className: cn("pr-4", !showLineNumbers && "px-4"),
53
- children: /* @__PURE__ */ jsx("pre", {
54
- className: "whitespace-pre",
55
- children: line
56
- })
57
- })]
58
- }, i)) })
59
- })
60
- }),
61
- !language && children && /* @__PURE__ */ jsx("div", {
62
- className: "absolute top-2 right-2 flex items-center gap-2",
32
+ children: [language ? /* @__PURE__ */ jsxs("div", {
33
+ className: "flex items-center justify-between border-b border-sf-line px-4 py-2",
34
+ children: [/* @__PURE__ */ jsx("span", {
35
+ className: "text-sf-subtle text-xs",
36
+ children: language
37
+ }), children && /* @__PURE__ */ jsx("div", {
38
+ className: "flex items-center gap-2",
63
39
  children
40
+ })]
41
+ }) : hasInlineOverlay && /* @__PURE__ */ jsx("div", {
42
+ className: "absolute top-0 right-2 z-10 flex h-6 items-center gap-2",
43
+ children
44
+ }), /* @__PURE__ */ jsx("div", {
45
+ className: "overflow-x-auto",
46
+ children: /* @__PURE__ */ jsx("table", {
47
+ className: "w-full border-collapse",
48
+ children: /* @__PURE__ */ jsx("tbody", { children: highlightedLines.map((line, i) => /* @__PURE__ */ jsxs("tr", {
49
+ className: "leading-6",
50
+ children: [showLineNumbers && /* @__PURE__ */ jsx("td", {
51
+ className: "select-none pr-4 pl-4 text-right text-sf-inactive",
52
+ children: i + 1
53
+ }), /* @__PURE__ */ jsx("td", {
54
+ className: cn("pr-4", !showLineNumbers && "px-4", hasInlineOverlay && i === 0 && "pr-14"),
55
+ children: /* @__PURE__ */ jsx("pre", {
56
+ className: "whitespace-pre",
57
+ children: line
58
+ })
59
+ })]
60
+ }, i)) })
64
61
  })
65
- ]
62
+ })]
66
63
  })
67
64
  });
68
65
  }, (prev, next) => prev.code === next.code && prev.language === next.language && prev.showLineNumbers === next.showLineNumbers);
69
- AiCodeBlock.displayName = "AiCodeBlock";
66
+ AiCodeBlockBase.displayName = "AiCodeBlock";
67
+ var AiCodeBlock = Object.assign(AiCodeBlockBase, { CopyButton: AiCodeBlockCopyButton });
70
68
  /**
71
69
  * Copy-to-clipboard button for use inside `AiCodeBlock`.
72
70
  * Must be a descendant of `AiCodeBlock` to access the code via context.
@@ -107,4 +105,4 @@ function AiCodeBlockCopyButton({ onCopy, onError, timeout = 2e3, children, class
107
105
  //#endregion
108
106
  export { SF_AI_CODE_BLOCK_VARIANTS as i, AiCodeBlockCopyButton as n, SF_AI_CODE_BLOCK_DEFAULT_VARIANTS as r, AiCodeBlock as t };
109
107
 
110
- //# sourceMappingURL=ai-code-block-CZtoL73R.js.map
108
+ //# sourceMappingURL=ai-code-block-P9TJHvaC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-code-block-P9TJHvaC.js","names":[],"sources":["../src/components/ai-code-block/ai-code-block.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ComponentProps, HTMLAttributes, ReactNode } from \"react\";\nimport { createContext, memo, useContext, useState } from \"react\";\nimport { highlight } from \"sugar-high\";\n\nimport { cn } from \"../../utils/cn\";\nimport { highlightToLines } from \"../../utils/highlight-to-react\";\nimport { Button } from \"../button\";\n\n// ─── Variants ────────────────────────────────────────────────────────────────\n\nexport const SF_AI_CODE_BLOCK_VARIANTS = {} as const;\nexport const SF_AI_CODE_BLOCK_DEFAULT_VARIANTS = {} as const;\n\n// ─── Context ─────────────────────────────────────────────────────────────────\n\ninterface AiCodeBlockContextValue {\n code: string;\n}\n\nconst AiCodeBlockContext = createContext<AiCodeBlockContextValue>({ code: \"\" });\n\n// ─── AiCodeBlock ─────────────────────────────────────────────────────────────\n\nexport type AiCodeBlockProps = HTMLAttributes<HTMLDivElement> & {\n /** The raw code string to display and make copyable. */\n code: string;\n /** Language identifier for syntax highlighting (display only, no highlighting applied). */\n language?: string;\n /** Show line numbers. @default false */\n showLineNumbers?: boolean;\n /** Extra content rendered in the top-right overlay (e.g. copy button). */\n children?: ReactNode;\n};\n\n/**\n * Displays a code block with monospace formatting and an optional copy button.\n * Does not include a syntax highlighter — avoids the heavy `react-syntax-highlighter`\n * dependency. Wrap with `AiCodeBlockCopyButton` for clipboard support.\n *\n * @example\n * ```tsx\n * <AiCodeBlock code={`const x = 1;`} language=\"ts\">\n * <AiCodeBlockCopyButton />\n * </AiCodeBlock>\n * ```\n */\nconst AiCodeBlockBase = memo(\n ({\n code,\n language,\n showLineNumbers = false,\n className,\n children,\n ...props\n }: AiCodeBlockProps) => {\n const highlightedLines = highlightToLines(highlight(code));\n const hasInlineOverlay = !language && Boolean(children);\n\n return (\n <AiCodeBlockContext.Provider value={{ code }}>\n <div\n className={cn(\n \"relative w-full overflow-hidden rounded-lg border border-sf-line bg-sf-recessed font-mono text-sm text-sf-default\",\n className\n )}\n {...props}\n >\n {language ? (\n <div className=\"flex items-center justify-between border-b border-sf-line px-4 py-2\">\n <span className=\"text-sf-subtle text-xs\">{language}</span>\n {children && (\n <div className=\"flex items-center gap-2\">{children}</div>\n )}\n </div>\n ) : (\n hasInlineOverlay && (\n <div className=\"absolute top-0 right-2 z-10 flex h-6 items-center gap-2\">\n {children}\n </div>\n )\n )}\n <div className=\"overflow-x-auto\">\n <table className=\"w-full border-collapse\">\n <tbody>\n {highlightedLines.map((line, i) => (\n // biome-ignore lint/suspicious/noArrayIndexKey: line index is stable\n <tr key={i} className=\"leading-6\">\n {showLineNumbers && (\n <td className=\"select-none pr-4 pl-4 text-right text-sf-inactive\">\n {i + 1}\n </td>\n )}\n <td\n className={cn(\n \"pr-4\",\n !showLineNumbers && \"px-4\",\n hasInlineOverlay && i === 0 && \"pr-14\"\n )}\n >\n <pre className=\"whitespace-pre\">{line}</pre>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </div>\n </AiCodeBlockContext.Provider>\n );\n },\n (prev, next) =>\n prev.code === next.code &&\n prev.language === next.language &&\n prev.showLineNumbers === next.showLineNumbers\n);\n\nAiCodeBlockBase.displayName = \"AiCodeBlock\";\n\n// Export AiCodeBlock with CopyButton sub-component (for registry detection)\nexport const AiCodeBlock = Object.assign(AiCodeBlockBase, {\n CopyButton: AiCodeBlockCopyButton,\n});\n\n// ─── AiCodeBlockCopyButton ───────────────────────────────────────────────────\n\nexport type AiCodeBlockCopyButtonProps = ComponentProps<typeof Button> & {\n /** Called after a successful copy. */\n onCopy?: () => void;\n /** Called if the clipboard API is unavailable or errors. */\n onError?: (error: Error) => void;\n /** How long (ms) to show the \"copied\" state. @default 2000 */\n timeout?: number;\n};\n\n/**\n * Copy-to-clipboard button for use inside `AiCodeBlock`.\n * Must be a descendant of `AiCodeBlock` to access the code via context.\n *\n * @example\n * ```tsx\n * <AiCodeBlock code=\"const x = 1;\" language=\"ts\">\n * <AiCodeBlockCopyButton />\n * </AiCodeBlock>\n * ```\n */\nexport function AiCodeBlockCopyButton({\n onCopy,\n onError,\n timeout = 2000,\n children,\n className,\n size = \"sm\",\n variant = \"ghost\",\n ...props\n}: AiCodeBlockCopyButtonProps) {\n const [copied, setCopied] = useState(false);\n const { code } = useContext(AiCodeBlockContext);\n\n const handleCopy = async () => {\n if (typeof navigator === \"undefined\" || !navigator.clipboard?.writeText) {\n onError?.(new Error(\"Clipboard API not available\"));\n return;\n }\n try {\n await navigator.clipboard.writeText(code);\n setCopied(true);\n onCopy?.();\n setTimeout(() => setCopied(false), timeout);\n } catch (err) {\n onError?.(err as Error);\n }\n };\n\n return (\n <Button\n className={cn(\"shrink-0\", className)}\n onClick={handleCopy}\n size={size}\n variant={variant}\n {...props}\n >\n {children ?? (copied ? \"Copied\" : \"Copy\")}\n </Button>\n );\n}\n"],"mappings":";;;;;;;;AAYA,IAAa,4BAA4B,CAAC;AAC1C,IAAa,oCAAoC,CAAC;AAQlD,IAAM,qBAAqB,cAAuC,EAAE,MAAM,GAAG,CAAC;;;;;;;;;;;;;AA2B9E,IAAM,kBAAkB,MACrB,EACC,MACA,UACA,kBAAkB,OAClB,WACA,UACA,GAAG,YACmB;CACtB,MAAM,mBAAmB,iBAAiB,UAAU,IAAI,CAAC;CACzD,MAAM,mBAAmB,CAAC,YAAY,QAAQ,QAAQ;CAEtD,OACE,oBAAC,mBAAmB,UAApB;EAA6B,OAAO,EAAE,KAAK;YACzC,qBAAC,OAAD;GACE,WAAW,GACT,qHACA,SACF;GACA,GAAI;aALN,CAOG,WACC,qBAAC,OAAD;IAAK,WAAU;cAAf,CACE,oBAAC,QAAD;KAAM,WAAU;eAA0B;IAAe,CAAA,GACxD,YACC,oBAAC,OAAD;KAAK,WAAU;KAA2B;IAAc,CAAA,CAEvD;QAEL,oBACE,oBAAC,OAAD;IAAK,WAAU;IACZ;GACE,CAAA,GAGT,oBAAC,OAAD;IAAK,WAAU;cACb,oBAAC,SAAD;KAAO,WAAU;eACf,oBAAC,SAAD,EAAA,UACG,iBAAiB,KAAK,MAAM,MAE3B,qBAAC,MAAD;MAAY,WAAU;gBAAtB,CACG,mBACC,oBAAC,MAAD;OAAI,WAAU;iBACX,IAAI;MACH,CAAA,GAEN,oBAAC,MAAD;OACE,WAAW,GACT,QACA,CAAC,mBAAmB,QACpB,oBAAoB,MAAM,KAAK,OACjC;iBAEA,oBAAC,OAAD;QAAK,WAAU;kBAAkB;OAAU,CAAA;MACzC,CAAA,CACF;QAfK,CAeL,CACL,EACI,CAAA;IACF,CAAA;GACJ,CAAA,CACF;;CACsB,CAAA;AAEjC,IACC,MAAM,SACL,KAAK,SAAS,KAAK,QACnB,KAAK,aAAa,KAAK,YACvB,KAAK,oBAAoB,KAAK,eAClC;AAEA,gBAAgB,cAAc;AAG9B,IAAa,cAAc,OAAO,OAAO,iBAAiB,EACxD,YAAY,sBACd,CAAC;;;;;;;;;;;;AAwBD,SAAgB,sBAAsB,EACpC,QACA,SACA,UAAU,KACV,UACA,WACA,OAAO,MACP,UAAU,SACV,GAAG,SAC0B;CAC7B,MAAM,CAAC,QAAQ,aAAa,SAAS,KAAK;CAC1C,MAAM,EAAE,SAAS,WAAW,kBAAkB;CAE9C,MAAM,aAAa,YAAY;EAC7B,IAAI,OAAO,cAAc,eAAe,CAAC,UAAU,WAAW,WAAW;GACvE,0BAAU,IAAI,MAAM,6BAA6B,CAAC;GAClD;EACF;EACA,IAAI;GACF,MAAM,UAAU,UAAU,UAAU,IAAI;GACxC,UAAU,IAAI;GACd,SAAS;GACT,iBAAiB,UAAU,KAAK,GAAG,OAAO;EAC5C,SAAS,KAAK;GACZ,UAAU,GAAY;EACxB;CACF;CAEA,OACE,oBAAC,QAAD;EACE,WAAW,GAAG,YAAY,SAAS;EACnC,SAAS;EACH;EACG;EACT,GAAI;YAEH,aAAa,SAAS,WAAW;CAC5B,CAAA;AAEZ"}
@@ -1,8 +1,8 @@
1
1
  "use client";
2
- import { t as cn } from "./cn-YROP2_ox.js";
3
- import { a as prepare, t as layout } from "./layout-DJHMMap2.js";
4
- import { t as Button } from "./button-CO6-qPax.js";
5
- import { forwardRef, useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
2
+ import { t as cn } from "./cn-CmAOpn49.js";
3
+ import { a as prepare, t as layout } from "./layout-CWBE0qwx.js";
4
+ import { t as Button } from "./button-BHOgXJRU.js";
5
+ import { forwardRef, useCallback, useEffect, useLayoutEffect, useState } from "react";
6
6
  import { jsx } from "react/jsx-runtime";
7
7
  import { ArrowDownIcon } from "@phosphor-icons/react";
8
8
  import { useVirtualizer } from "@tanstack/react-virtual";
@@ -83,8 +83,6 @@ function AiConversationScrollButton({ scrollRef, threshold = 100, className, onC
83
83
  var useIsomorphicLayoutEffect = typeof window === "undefined" ? useEffect : useLayoutEffect;
84
84
  function useConversationVirtualizer({ scrollRef, items, estimateSize = 80, overscan = 8, stickThreshold = 40 }) {
85
85
  const [isAtBottom, setIsAtBottom] = useState(true);
86
- const isAtBottomRef = useRef(true);
87
- const prevCountRef = useRef(items.length);
88
86
  const [containerWidth, setContainerWidth] = useState(0);
89
87
  const [fontsReady, setFontsReady] = useState(() => {
90
88
  if (typeof document === "undefined") return true;
@@ -118,19 +116,6 @@ function useConversationVirtualizer({ scrollRef, items, estimateSize = 80, overs
118
116
  observer.observe(el);
119
117
  return () => observer.disconnect();
120
118
  }, [scrollRef]);
121
- useEffect(() => {
122
- const el = scrollRef.current;
123
- if (!el) return;
124
- const check = () => {
125
- const atBottom = el.scrollHeight - el.scrollTop - el.clientHeight <= stickThreshold;
126
- isAtBottomRef.current = atBottom;
127
- setIsAtBottom(atBottom);
128
- };
129
- check();
130
- el.addEventListener("scroll", check, { passive: true });
131
- return () => el.removeEventListener("scroll", check);
132
- }, [scrollRef, stickThreshold]);
133
- const prevTotalSizeRef = useRef(0);
134
119
  const virtualizer = useVirtualizer({
135
120
  count: items.length,
136
121
  getScrollElement: () => scrollRef.current,
@@ -150,7 +135,10 @@ function useConversationVirtualizer({ scrollRef, items, estimateSize = 80, overs
150
135
  }
151
136
  },
152
137
  overscan,
153
- getItemKey: (index) => items[index]?.key ?? index
138
+ getItemKey: (index) => items[index]?.key ?? index,
139
+ anchorTo: "end",
140
+ followOnAppend: "smooth",
141
+ scrollEndThreshold: stickThreshold
154
142
  });
155
143
  useEffect(() => {
156
144
  if (containerWidth > 0) virtualizer.measure();
@@ -160,34 +148,32 @@ function useConversationVirtualizer({ scrollRef, items, estimateSize = 80, overs
160
148
  virtualizer,
161
149
  fontsReady
162
150
  ]);
163
- virtualizer.shouldAdjustScrollPositionOnItemSizeChange = () => isAtBottomRef.current;
164
151
  const virtualItems = virtualizer.getVirtualItems();
165
152
  const totalSize = virtualizer.getTotalSize();
166
153
  useEffect(() => {
167
- const count = items.length;
168
- if (count > prevCountRef.current && isAtBottomRef.current) requestAnimationFrame(() => {
169
- virtualizer.scrollToIndex(count - 1, {
170
- align: "end",
171
- behavior: "smooth"
172
- });
173
- });
174
- prevCountRef.current = count;
175
- }, [items.length, virtualizer]);
176
- useEffect(() => {
177
- const prev = prevTotalSizeRef.current;
178
- prevTotalSizeRef.current = totalSize;
179
- if (!isAtBottomRef.current || totalSize <= prev) return;
180
154
  const el = scrollRef.current;
181
155
  if (!el) return;
182
- const dist = el.scrollHeight - el.scrollTop - el.clientHeight;
183
- if (dist > 1 && dist < 300) el.scrollTop = el.scrollHeight - el.clientHeight;
184
- }, [totalSize, scrollRef]);
156
+ const check = () => {
157
+ setIsAtBottom(virtualizer.isAtEnd(stickThreshold));
158
+ };
159
+ check();
160
+ el.addEventListener("scroll", check, { passive: true });
161
+ return () => el.removeEventListener("scroll", check);
162
+ }, [
163
+ scrollRef,
164
+ stickThreshold,
165
+ virtualizer
166
+ ]);
167
+ useEffect(() => {
168
+ setIsAtBottom(virtualizer.isAtEnd(stickThreshold));
169
+ }, [
170
+ totalSize,
171
+ stickThreshold,
172
+ virtualizer
173
+ ]);
185
174
  const scrollToBottom = useCallback((behavior = "smooth") => {
186
175
  if (items.length === 0) return;
187
- virtualizer.scrollToIndex(items.length - 1, {
188
- align: "end",
189
- behavior
190
- });
176
+ virtualizer.scrollToEnd({ behavior });
191
177
  }, [virtualizer, items.length]);
192
178
  const measureRef = useCallback((node) => {
193
179
  if (node) virtualizer.measureElement(node);
@@ -239,4 +225,4 @@ var SF_AI_DEFAULT_MESSAGE_GAP = 12;
239
225
  //#endregion
240
226
  export { SF_AI_MEASURE_FONT as a, SF_AI_USER_VERTICAL_PADDING as c, AiConversationContent as d, AiConversationScrollButton as f, useConversationVirtualizer as h, SF_AI_DEFAULT_MESSAGE_GAP as i, SF_AI_USER_WIDTH_FRACTION as l, SF_AI_CONVERSATION_VARIANTS as m, SF_AI_ASSISTANT_VERTICAL_PADDING as n, SF_AI_MEASURE_LINE_HEIGHT as o, SF_AI_CONVERSATION_DEFAULT_VARIANTS as p, SF_AI_ASSISTANT_WIDTH_FRACTION as r, SF_AI_USER_HORIZONTAL_PADDING as s, SF_AI_ASSISTANT_HORIZONTAL_PADDING as t, AiConversation as u };
241
227
 
242
- //# sourceMappingURL=ai-conversation-Cc7WlaBg.js.map
228
+ //# sourceMappingURL=ai-conversation-Qslfdi1t.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-conversation-Qslfdi1t.js","names":[],"sources":["../src/components/ai-conversation/ai-conversation.tsx","../src/components/ai-conversation/measurement-constants.ts"],"sourcesContent":["\"use client\";\n\nimport { layout, prepare } from \"@chenglou/pretext\";\nimport { ArrowDownIcon } from \"@phosphor-icons/react\";\nimport { useVirtualizer } from \"@tanstack/react-virtual\";\nimport type { Virtualizer, VirtualItem } from \"@tanstack/react-virtual\";\nimport type { ComponentProps, ReactNode, RefObject } from \"react\";\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useLayoutEffect,\n useState,\n} from \"react\";\n\nimport { cn } from \"../../utils/cn\";\nimport { Button } from \"../button\";\n\n// ─── Variants ────────────────────────────────────────────────────────────────\n\nexport const SF_AI_CONVERSATION_VARIANTS = {} as const;\nexport const SF_AI_CONVERSATION_DEFAULT_VARIANTS = {} as const;\n\n// ─── AiConversation ──────────────────────────────────────────────────────────\n\nexport type AiConversationProps = ComponentProps<\"div\">;\n\n/**\n * Outer scroll container for a conversation. Sticks to the bottom as new\n * messages are added. Pair with `AiConversationContent` and optionally\n * `AiConversationScrollButton`.\n *\n * @example\n * ```tsx\n * <AiConversation ref={scrollRef}>\n * <AiConversationContent>\n * {messages.map(m => <AiMessage key={m.id} from={m.role}>...</AiMessage>)}\n * </AiConversationContent>\n * <AiConversationScrollButton scrollRef={scrollRef} />\n * </AiConversation>\n * ```\n */\nexport const AiConversation = forwardRef<HTMLDivElement, AiConversationProps>(\n ({ className, children, ...props }, ref) => {\n return (\n <div\n ref={ref}\n className={cn(\"relative flex-1 overflow-y-auto\", className)}\n role=\"log\"\n aria-live=\"polite\"\n aria-label=\"Conversation\"\n {...props}\n >\n {children}\n </div>\n );\n }\n);\n\nAiConversation.displayName = \"AiConversation\";\n\n// ─── AiConversationContent ───────────────────────────────────────────────────\n\nexport type AiConversationContentProps = ComponentProps<\"div\">;\n\n/**\n * Inner content wrapper with padding. Place message components inside here.\n */\nexport function AiConversationContent({\n className,\n children,\n ...props\n}: AiConversationContentProps) {\n return (\n <div\n className={cn(\"flex flex-col gap-0 overscroll-y-none p-4\", className)}\n {...props}\n >\n {children}\n </div>\n );\n}\n\n// ─── AiConversationScrollButton ──────────────────────────────────────────────\n\nexport type AiConversationScrollButtonProps = ComponentProps<typeof Button> & {\n /**\n * Ref to the scroll container (the `AiConversation` element).\n * When omitted, the button is always visible.\n */\n scrollRef?: RefObject<HTMLElement | null>;\n /** Scroll threshold in pixels from bottom to show the button. @default 100 */\n threshold?: number;\n};\n\n/**\n * Floating \"scroll to bottom\" button. Appears when the user has scrolled up\n * more than `threshold` pixels from the bottom.\n */\nexport function AiConversationScrollButton({\n scrollRef,\n threshold = 100,\n className,\n onClick,\n ...props\n}: AiConversationScrollButtonProps) {\n const [show, setShow] = useState(false);\n\n useEffect(() => {\n const el = scrollRef?.current;\n if (!el) return;\n\n const check = () => {\n const distFromBottom = el.scrollHeight - el.scrollTop - el.clientHeight;\n setShow(distFromBottom > threshold);\n };\n\n check();\n el.addEventListener(\"scroll\", check, { passive: true });\n return () => el.removeEventListener(\"scroll\", check);\n }, [scrollRef, threshold]);\n\n const handleClick = useCallback(\n (e: React.MouseEvent<HTMLButtonElement>) => {\n scrollRef?.current?.scrollTo({\n top: scrollRef.current.scrollHeight,\n behavior: \"smooth\",\n });\n onClick?.(e);\n },\n [scrollRef, onClick]\n );\n\n if (scrollRef && !show) return null;\n\n return (\n <Button\n aria-label=\"Scroll to bottom\"\n className={cn(\n \"absolute bottom-4 left-1/2 -translate-x-1/2 rounded-full shadow-md\",\n className\n )}\n onClick={handleClick}\n size=\"sm\"\n variant=\"secondary\"\n {...props}\n >\n <ArrowDownIcon className=\"size-4\" />\n </Button>\n );\n}\n\n// ─── Virtualized Conversation ────────────────────────────────────────────────\n\n/** Measurement spec for predictive height calculation using pretext. */\nexport interface ConversationItemMeasureSpec {\n /** Text content to measure */\n text: string;\n /** CSS font shorthand (e.g. \"14px Inter, sans-serif\"). Auto-detected if omitted. */\n font?: string;\n /** Line height in pixels. Auto-detected if omitted. */\n lineHeight?: number;\n /** Additional vertical padding (top + bottom) in pixels @default 0 */\n padding?: number;\n /**\n * Fraction of column width this item occupies (0-1). Used to compute the\n * actual content width for items that are constrained (e.g. user message\n * bubbles at max-w-[70%]). @default 1\n */\n widthFraction?: number;\n /**\n * Horizontal padding (left + right) inside the content box, subtracted from\n * the available width before line wrapping. @default 0\n */\n horizontalPadding?: number;\n /**\n * Margin below this item (gap to next item). @default 0\n */\n gapAfter?: number;\n /**\n * White-space handling — must match the rendered CSS. Use `\"pre-wrap\"` when\n * the rendered content preserves explicit newlines (e.g. plain text inside\n * a <pre> or `whitespace-pre-wrap` div). @default \"normal\"\n */\n whiteSpace?: \"normal\" | \"pre-wrap\";\n /**\n * Word-break handling — match CSS `word-break`. Use `\"keep-all\"` for CJK\n * text that should not break mid-word. @default \"normal\"\n */\n wordBreak?: \"normal\" | \"keep-all\";\n}\n\n/** A single item in the virtualized conversation list. */\nexport interface ConversationItem {\n /** Unique key for this item. */\n key: string;\n /**\n * Render the item content. The virtualizer handles measurement and\n * positioning on the wrapper — just return the content.\n */\n render: () => ReactNode;\n /**\n * Optional predictive height measurement. When provided, the virtualizer\n * uses pretext to compute exact height without DOM measurement, eliminating\n * layout shift during streaming. Falls back to estimateSize + DOM measurement\n * when omitted.\n *\n * **Attach this only when rendering plain text** (no markdown). If your\n * `render` output uses `<AiResponse>` or any rich-content component whose\n * blocks have varying typography (headings, code, lists, blockquotes), omit\n * `measure` to let the virtualizer use DOM measurement instead. Pretext\n * predicts heights from a single (font, line-height) pair and cannot\n * accurately model multi-block markdown.\n *\n * Plain-text + `measure` gives jitter-free virtualization (no estimate-then-\n * adjust feedback loop). Rich content + DOM measurement is rendering-correct\n * but slightly less smooth on first paint.\n *\n * For streaming items, update `measure.text` as text grows so the virtualizer\n * can recalculate height per tick (rebuild the `items` array with the latest\n * text on each token arrival).\n */\n measure?: ConversationItemMeasureSpec;\n}\n\nexport interface UseConversationVirtualizerOptions {\n /** Ref to the scroll container element. */\n scrollRef: RefObject<HTMLElement | null>;\n /** The conversation items to virtualize. */\n items: ConversationItem[];\n /**\n * Estimated height of a single item in pixels.\n * Used before measurement. Doesn't need to be exact.\n * @default 80\n */\n estimateSize?: number;\n /**\n * Number of items to render beyond the visible area.\n * @default 8\n */\n overscan?: number;\n /**\n * Pixel distance from bottom to consider \"at bottom\" for stick-to-bottom.\n * @default 40\n */\n stickThreshold?: number;\n}\n\nexport interface UseConversationVirtualizerReturn {\n /** The TanStack virtualizer instance. */\n virtualizer: Virtualizer<HTMLElement, Element>;\n /** The virtual items to render. */\n virtualItems: VirtualItem[];\n /** Total measured/estimated height of all items. */\n totalSize: number;\n /** Whether the user is currently at the bottom of the conversation. */\n isAtBottom: boolean;\n /** Smoothly scroll to the bottom. */\n scrollToBottom: (behavior?: ScrollBehavior) => void;\n /**\n * Get the measurement ref for a virtual item by index.\n * @deprecated Use `getMeasureRef(index)` instead to respect predictive heights.\n */\n measureRef: (node: HTMLElement | null) => void;\n /**\n * Get the measurement ref for a specific item index.\n * Returns `null` for items with predictive height (no DOM measurement needed),\n * or the measurement callback for legacy items.\n */\n getMeasureRef: (index: number) => ((node: HTMLElement | null) => void) | null;\n}\n\n/**\n * `useConversationVirtualizer` — virtualizes a conversation list with\n * dynamic item heights and automatic stick-to-bottom behavior.\n *\n * Built on `@tanstack/react-virtual`. Items are measured dynamically via\n * `ResizeObserver`, so tool calls expanding, subagents collapsing, and\n * streaming text growing all work correctly.\n *\n * **Stick-to-bottom**: Uses TanStack Virtual's end-anchored mode\n * (`anchorTo: \"end\"` + `followOnAppend`). When the user is within\n * `stickThreshold` of the bottom, streaming growth of the last message keeps\n * the viewport pinned and newly appended messages auto-follow. When the user\n * scrolls up to read history, both disengage until they return to the bottom.\n * Prepending older history keeps the currently-visible message stable.\n *\n * @example\n * ```tsx\n * const { virtualItems, totalSize, measureRef, isAtBottom, scrollToBottom } =\n * useConversationVirtualizer({ scrollRef, items });\n *\n * return (\n * <AiConversation ref={scrollRef}>\n * <div style={{ height: totalSize, position: \"relative\" }}>\n * {virtualItems.map((vi) => {\n * const item = items[vi.index];\n * return (\n * <div key={item.key} ref={measureRef} data-index={vi.index}\n * style={{ position: \"absolute\", top: vi.start, width: \"100%\" }}>\n * {item.render()}\n * </div>\n * );\n * })}\n * </div>\n * {!isAtBottom && <button onClick={() => scrollToBottom()}>↓</button>}\n * </AiConversation>\n * );\n * ```\n */\nconst isSSR = typeof window === \"undefined\";\nconst useIsomorphicLayoutEffect = isSSR ? useEffect : useLayoutEffect;\n\nexport function useConversationVirtualizer({\n scrollRef,\n items,\n estimateSize = 80,\n overscan = 8,\n stickThreshold = 40,\n}: UseConversationVirtualizerOptions): UseConversationVirtualizerReturn {\n const [isAtBottom, setIsAtBottom] = useState(true);\n\n // Track container width for predictive height calculation\n const [containerWidth, setContainerWidth] = useState(0);\n\n // Track whether webfonts are ready. Pretext measures via canvas which uses\n // the browser font engine — if Inter (or any custom font) hasn't loaded\n // yet, the canvas falls back to system-ui and predictions diverge from the\n // rendered DOM. Once fonts.ready resolves we re-trigger measurement.\n const [fontsReady, setFontsReady] = useState(() => {\n if (typeof document === \"undefined\") return true;\n // `document.fonts.status === \"loaded\"` means all current FontFaces are\n // loaded. If still \"loading\" we wait for fonts.ready below.\n return document.fonts?.status === \"loaded\";\n });\n\n useEffect(() => {\n if (fontsReady) return;\n if (typeof document === \"undefined\" || !document.fonts) {\n setFontsReady(true);\n return;\n }\n let cancelled = false;\n document.fonts.ready.then(() => {\n if (!cancelled) setFontsReady(true);\n });\n return () => {\n cancelled = true;\n };\n }, [fontsReady]);\n\n useIsomorphicLayoutEffect(() => {\n const el = scrollRef.current;\n if (!el) return;\n\n const updateWidth = () => {\n // clientWidth excludes scrollbars but includes padding.\n // Subtract horizontal padding to get the actual content width.\n const style = window.getComputedStyle(el);\n const padLeft = parseFloat(style.paddingLeft) || 0;\n const padRight = parseFloat(style.paddingRight) || 0;\n setContainerWidth(el.clientWidth - padLeft - padRight);\n };\n\n updateWidth();\n\n const observer = new ResizeObserver(updateWidth);\n observer.observe(el);\n\n return () => observer.disconnect();\n }, [scrollRef]);\n\n const virtualizer = useVirtualizer({\n count: items.length,\n getScrollElement: () => scrollRef.current as HTMLElement | null,\n estimateSize: (index) => {\n const item = items[index];\n if (!item?.measure || containerWidth <= 0) {\n return estimateSize;\n }\n const {\n text,\n font = \"14px sans-serif\",\n lineHeight = 20,\n padding = 0,\n widthFraction = 1,\n horizontalPadding = 0,\n gapAfter = 0,\n whiteSpace = \"normal\",\n wordBreak = \"normal\",\n } = item.measure;\n\n // Apply the same width constraints as the rendered message bubble.\n const contentWidth = Math.max(\n 40,\n Math.floor(containerWidth * widthFraction) - horizontalPadding\n );\n\n try {\n const prepared = prepare(text, font, { whiteSpace, wordBreak });\n const { height } = layout(prepared, contentWidth, lineHeight);\n return height + padding + gapAfter;\n } catch {\n return estimateSize;\n }\n },\n overscan,\n getItemKey: (index) => items[index]?.key ?? index,\n // Chat/streaming scroll physics (TanStack Virtual end-anchored mode):\n // - `anchorTo: \"end\"` keeps the viewport pinned to the bottom when the\n // last message grows token-by-token, and keeps the currently-visible\n // message stable when older history is prepended.\n // - `followOnAppend` auto-scrolls to newly appended messages, but only\n // when the user was already within `scrollEndThreshold` of the end —\n // users reading history are never yanked down.\n // A stable `getItemKey` (above) is required for prepend stability.\n anchorTo: \"end\",\n followOnAppend: \"smooth\",\n scrollEndThreshold: stickThreshold,\n });\n\n // When container width, item measurement specs, or font-readiness change,\n // force TanStack to recompute sizes through `estimateSize`. For predictive\n // rows this calls pretext again and still skips DOM measurement.\n useEffect(() => {\n if (containerWidth > 0) {\n virtualizer.measure();\n }\n }, [containerWidth, items, virtualizer, fontsReady]);\n\n const virtualItems = virtualizer.getVirtualItems();\n const totalSize = virtualizer.getTotalSize();\n\n // Track \"at end\" using the virtualizer's own end-distance math so the\n // \"scroll to bottom\" affordance shares the exact threshold that drives\n // `followOnAppend`. `anchorTo: \"end\"` already pins the viewport when the\n // last item grows or items are appended — no manual scrollTop bookkeeping.\n useEffect(() => {\n const el = scrollRef.current;\n if (!el) return;\n\n const check = () => {\n setIsAtBottom(virtualizer.isAtEnd(stickThreshold));\n };\n\n check();\n el.addEventListener(\"scroll\", check, { passive: true });\n return () => el.removeEventListener(\"scroll\", check);\n }, [scrollRef, stickThreshold, virtualizer]);\n\n // Re-evaluate \"at end\" whenever the content size changes (streaming growth,\n // collapsible expand) so the scroll button visibility stays accurate even\n // without a user scroll event.\n useEffect(() => {\n setIsAtBottom(virtualizer.isAtEnd(stickThreshold));\n }, [totalSize, stickThreshold, virtualizer]);\n\n const scrollToBottom = useCallback(\n (behavior: ScrollBehavior = \"smooth\") => {\n if (items.length === 0) return;\n virtualizer.scrollToEnd({ behavior });\n },\n [virtualizer, items.length]\n );\n\n const measureRef = useCallback(\n (node: HTMLElement | null) => {\n if (node) virtualizer.measureElement(node);\n },\n [virtualizer]\n );\n\n // For items with predictive height, return null so TanStack doesn't remeasure.\n // For legacy items without measure spec, return the measurement callback.\n const getMeasureRef = useCallback(\n (index: number): ((node: HTMLElement | null) => void) | null => {\n const item = items[index];\n if (item?.measure) {\n return null; // Predicted height — no DOM measurement needed\n }\n return measureRef;\n },\n [items, measureRef]\n );\n\n return {\n virtualizer,\n virtualItems,\n totalSize,\n isAtBottom,\n scrollToBottom,\n measureRef,\n getMeasureRef,\n };\n}\n","/**\n * Shared pretext measurement constants for `useConversationVirtualizer`.\n *\n * These match the rendered styling of `<AiMessage>` + `<AiMessageContent>`\n * (text-sm = 14px / line-height 20px, user bubble `max-w-[70%]` with `px-4 py-3`).\n *\n * Anywhere that builds `ConversationItem.measure` for plain-text AI chat messages\n * should import from here so calibration stays in one place. If production CSS\n * for `<AiMessage>` ever changes (font size, padding, bubble width), update these\n * constants — pretext predictions will then automatically follow.\n */\n\n/** CSS `font` shorthand matching `text-sm` rendering. */\nexport const SF_AI_MEASURE_FONT =\n '14px \"Inter\", ui-sans-serif, system-ui, sans-serif';\n\n/** Line height in pixels, matching `text-sm`. */\nexport const SF_AI_MEASURE_LINE_HEIGHT = 20;\n\n/** User bubbles: `max-w-[70%]`. */\nexport const SF_AI_USER_WIDTH_FRACTION = 0.7;\n\n/** User bubbles: `px-4` → 16px × 2 horizontal padding. */\nexport const SF_AI_USER_HORIZONTAL_PADDING = 32;\n\n/** User bubbles: `py-3` → 12px × 2 vertical padding. */\nexport const SF_AI_USER_VERTICAL_PADDING = 24;\n\n/** Assistant text: full width column, no bubble. */\nexport const SF_AI_ASSISTANT_WIDTH_FRACTION = 1;\n\n/** Assistant text: no horizontal padding inside the bubble. */\nexport const SF_AI_ASSISTANT_HORIZONTAL_PADDING = 0;\n\n/** Assistant text: no vertical padding inside the bubble. */\nexport const SF_AI_ASSISTANT_VERTICAL_PADDING = 0;\n\n/** Default gap between conversation items. */\nexport const SF_AI_DEFAULT_MESSAGE_GAP = 12;\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  "use client";
2
- import { t as cn } from "./cn-YROP2_ox.js";
3
- import { t as Text } from "./text-Cqryz7rk.js";
2
+ import { t as cn } from "./cn-CmAOpn49.js";
3
+ import { t as Text } from "./text-iQ0YUFNg.js";
4
4
  import { jsx, jsxs } from "react/jsx-runtime";
5
5
  import { ArrowsClockwiseIcon, InfoIcon, WarningCircleIcon } from "@phosphor-icons/react";
6
6
  //#region src/components/ai-info-banner/ai-info-banner.tsx
@@ -77,4 +77,4 @@ AiInfoBanner.displayName = "AiInfoBanner";
77
77
  //#endregion
78
78
  export { SF_AI_INFO_BANNER_DEFAULT_VARIANTS as n, SF_AI_INFO_BANNER_VARIANTS as r, AiInfoBanner as t };
79
79
 
80
- //# sourceMappingURL=ai-info-banner-C7EWPBj7.js.map
80
+ //# sourceMappingURL=ai-info-banner-B_9vtGK3.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ai-info-banner-C7EWPBj7.js","names":[],"sources":["../src/components/ai-info-banner/ai-info-banner.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n InfoIcon,\n WarningCircleIcon,\n ArrowsClockwiseIcon,\n} from \"@phosphor-icons/react\";\nimport type { ElementType, HTMLAttributes, ReactNode } from \"react\";\n\nimport { cn } from \"../../utils/cn\";\nimport { Text } from \"../text\";\n\n// ─── Variants ────────────────────────────────────────────────────────────────\n\nexport const SF_AI_INFO_BANNER_VARIANTS = {\n level: {\n info: { classes: \"\", description: \"Informational notice\" },\n error: { classes: \"\", description: \"Error notice\" },\n change: {\n classes: \"\",\n description: \"State change notice (model/mode switch)\",\n },\n },\n} as const;\n\nexport const SF_AI_INFO_BANNER_DEFAULT_VARIANTS = {\n level: \"info\",\n} as const;\n\nexport type SFAiInfoBannerLevel = keyof typeof SF_AI_INFO_BANNER_VARIANTS.level;\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport type AiInfoBannerProps = HTMLAttributes<HTMLDivElement> & {\n /** Banner level controls icon and color treatment. */\n level?: SFAiInfoBannerLevel;\n /** Custom icon override. */\n icon?: ElementType;\n /** Content to display. */\n children: ReactNode;\n};\n\n// ─── Level config ─────────────────────────────────────────────────────────────\n\nconst LEVEL_CONFIG: Record<\n SFAiInfoBannerLevel,\n { icon: ElementType; iconClassName: string; borderClassName: string }\n> = {\n info: {\n icon: InfoIcon,\n iconClassName: \"text-sf-info\",\n borderClassName: \"border-sf-info/20\",\n },\n error: {\n icon: WarningCircleIcon,\n iconClassName: \"text-sf-danger\",\n borderClassName: \"border-sf-danger/20\",\n },\n change: {\n icon: ArrowsClockwiseIcon,\n iconClassName: \"text-sf-subtle\",\n borderClassName: \"border-sf-line\",\n },\n};\n\n// ─── Component ────────────────────────────────────────────────────────────────\n\n/**\n * Inline conversation banner for system notices. Renders as a compact,\n * horizontally centered divider-like notice rather than a chat bubble.\n *\n * Maps to harness events: `error`, `info`, `mode_changed`, `model_changed`.\n *\n * @example\n * ```tsx\n * <AiInfoBanner level=\"error\">\n * Connection lost. Retrying in 3s…\n * </AiInfoBanner>\n *\n * <AiInfoBanner level=\"change\">\n * Switched to claude-opus-4-6\n * </AiInfoBanner>\n *\n * <AiInfoBanner level=\"info\">\n * Follow-up queued — will send after current response\n * </AiInfoBanner>\n * ```\n */\nexport function AiInfoBanner({\n level = \"info\",\n icon,\n children,\n className,\n ...props\n}: AiInfoBannerProps) {\n const config = LEVEL_CONFIG[level];\n const IconComponent = icon ?? config.icon;\n\n return (\n <div\n className={cn(\n \"flex items-center justify-center gap-2 border-y px-4 py-1.5\",\n config.borderClassName,\n className\n )}\n role={level === \"error\" ? \"alert\" : \"status\"}\n {...props}\n >\n <IconComponent\n className={cn(\"size-3.5 shrink-0\", config.iconClassName)}\n />\n <Text size=\"xs\" variant=\"secondary\" wrap=\"balance\" as=\"span\">\n {children}\n </Text>\n </div>\n );\n}\n\nAiInfoBanner.displayName = \"AiInfoBanner\";\n"],"mappings":";;;;;;AAcA,IAAa,6BAA6B,EACxC,OAAO;CACL,MAAM;EAAE,SAAS;EAAI,aAAa;EAAwB;CAC1D,OAAO;EAAE,SAAS;EAAI,aAAa;EAAgB;CACnD,QAAQ;EACN,SAAS;EACT,aAAa;EACd;CACF,EACF;AAED,IAAa,qCAAqC,EAChD,OAAO,QACR;AAiBD,IAAM,eAGF;CACF,MAAM;EACJ,MAAM;EACN,eAAe;EACf,iBAAiB;EAClB;CACD,OAAO;EACL,MAAM;EACN,eAAe;EACf,iBAAiB;EAClB;CACD,QAAQ;EACN,MAAM;EACN,eAAe;EACf,iBAAiB;EAClB;CACF;;;;;;;;;;;;;;;;;;;;;;AAyBD,SAAgB,aAAa,EAC3B,QAAQ,QACR,MACA,UACA,WACA,GAAG,SACiB;CACpB,MAAM,SAAS,aAAa;CAC5B,MAAM,gBAAgB,QAAQ,OAAO;AAErC,QACE,qBAAC,OAAD;EACE,WAAW,GACT,+DACA,OAAO,iBACP,UACD;EACD,MAAM,UAAU,UAAU,UAAU;EACpC,GAAI;YAPN,CASE,oBAAC,eAAD,EACE,WAAW,GAAG,qBAAqB,OAAO,cAAc,EACxD,CAAA,EACF,oBAAC,MAAD;GAAM,MAAK;GAAK,SAAQ;GAAY,MAAK;GAAU,IAAG;GACnD;GACI,CAAA,CACH;;;AAIV,aAAa,cAAc"}
1
+ {"version":3,"file":"ai-info-banner-B_9vtGK3.js","names":[],"sources":["../src/components/ai-info-banner/ai-info-banner.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n InfoIcon,\n WarningCircleIcon,\n ArrowsClockwiseIcon,\n} from \"@phosphor-icons/react\";\nimport type { ElementType, HTMLAttributes, ReactNode } from \"react\";\n\nimport { cn } from \"../../utils/cn\";\nimport { Text } from \"../text\";\n\n// ─── Variants ────────────────────────────────────────────────────────────────\n\nexport const SF_AI_INFO_BANNER_VARIANTS = {\n level: {\n info: { classes: \"\", description: \"Informational notice\" },\n error: { classes: \"\", description: \"Error notice\" },\n change: {\n classes: \"\",\n description: \"State change notice (model/mode switch)\",\n },\n },\n} as const;\n\nexport const SF_AI_INFO_BANNER_DEFAULT_VARIANTS = {\n level: \"info\",\n} as const;\n\nexport type SFAiInfoBannerLevel = keyof typeof SF_AI_INFO_BANNER_VARIANTS.level;\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport type AiInfoBannerProps = HTMLAttributes<HTMLDivElement> & {\n /** Banner level controls icon and color treatment. */\n level?: SFAiInfoBannerLevel;\n /** Custom icon override. */\n icon?: ElementType;\n /** Content to display. */\n children: ReactNode;\n};\n\n// ─── Level config ─────────────────────────────────────────────────────────────\n\nconst LEVEL_CONFIG: Record<\n SFAiInfoBannerLevel,\n { icon: ElementType; iconClassName: string; borderClassName: string }\n> = {\n info: {\n icon: InfoIcon,\n iconClassName: \"text-sf-info\",\n borderClassName: \"border-sf-info/20\",\n },\n error: {\n icon: WarningCircleIcon,\n iconClassName: \"text-sf-danger\",\n borderClassName: \"border-sf-danger/20\",\n },\n change: {\n icon: ArrowsClockwiseIcon,\n iconClassName: \"text-sf-subtle\",\n borderClassName: \"border-sf-line\",\n },\n};\n\n// ─── Component ────────────────────────────────────────────────────────────────\n\n/**\n * Inline conversation banner for system notices. Renders as a compact,\n * horizontally centered divider-like notice rather than a chat bubble.\n *\n * Maps to harness events: `error`, `info`, `mode_changed`, `model_changed`.\n *\n * @example\n * ```tsx\n * <AiInfoBanner level=\"error\">\n * Connection lost. Retrying in 3s…\n * </AiInfoBanner>\n *\n * <AiInfoBanner level=\"change\">\n * Switched to claude-opus-4-6\n * </AiInfoBanner>\n *\n * <AiInfoBanner level=\"info\">\n * Follow-up queued — will send after current response\n * </AiInfoBanner>\n * ```\n */\nexport function AiInfoBanner({\n level = \"info\",\n icon,\n children,\n className,\n ...props\n}: AiInfoBannerProps) {\n const config = LEVEL_CONFIG[level];\n const IconComponent = icon ?? config.icon;\n\n return (\n <div\n className={cn(\n \"flex items-center justify-center gap-2 border-y px-4 py-1.5\",\n config.borderClassName,\n className\n )}\n role={level === \"error\" ? \"alert\" : \"status\"}\n {...props}\n >\n <IconComponent\n className={cn(\"size-3.5 shrink-0\", config.iconClassName)}\n />\n <Text size=\"xs\" variant=\"secondary\" wrap=\"balance\" as=\"span\">\n {children}\n </Text>\n </div>\n );\n}\n\nAiInfoBanner.displayName = \"AiInfoBanner\";\n"],"mappings":";;;;;;AAcA,IAAa,6BAA6B,EACxC,OAAO;CACL,MAAM;EAAE,SAAS;EAAI,aAAa;CAAuB;CACzD,OAAO;EAAE,SAAS;EAAI,aAAa;CAAe;CAClD,QAAQ;EACN,SAAS;EACT,aAAa;CACf;AACF,EACF;AAEA,IAAa,qCAAqC,EAChD,OAAO,OACT;AAiBA,IAAM,eAGF;CACF,MAAM;EACJ,MAAM;EACN,eAAe;EACf,iBAAiB;CACnB;CACA,OAAO;EACL,MAAM;EACN,eAAe;EACf,iBAAiB;CACnB;CACA,QAAQ;EACN,MAAM;EACN,eAAe;EACf,iBAAiB;CACnB;AACF;;;;;;;;;;;;;;;;;;;;;;AAyBA,SAAgB,aAAa,EAC3B,QAAQ,QACR,MACA,UACA,WACA,GAAG,SACiB;CACpB,MAAM,SAAS,aAAa;CAC5B,MAAM,gBAAgB,QAAQ,OAAO;CAErC,OACE,qBAAC,OAAD;EACE,WAAW,GACT,+DACA,OAAO,iBACP,SACF;EACA,MAAM,UAAU,UAAU,UAAU;EACpC,GAAI;YAPN,CASE,oBAAC,eAAD,EACE,WAAW,GAAG,qBAAqB,OAAO,aAAa,EACxD,CAAA,GACD,oBAAC,MAAD;GAAM,MAAK;GAAK,SAAQ;GAAY,MAAK;GAAU,IAAG;GACnD;EACG,CAAA,CACH;;AAET;AAEA,aAAa,cAAc"}
@@ -1,8 +1,8 @@
1
1
  "use client";
2
- import { t as cn } from "./cn-YROP2_ox.js";
3
- import { t as Text } from "./text-Cqryz7rk.js";
4
- import { t as Tooltip } from "./tooltip-g9lFsvcT.js";
5
- import { t as Button } from "./button-CO6-qPax.js";
2
+ import { t as cn } from "./cn-CmAOpn49.js";
3
+ import { t as Text } from "./text-iQ0YUFNg.js";
4
+ import { t as Tooltip } from "./tooltip-uobk6Oh-.js";
5
+ import { t as Button } from "./button-BHOgXJRU.js";
6
6
  import { createContext, memo, useCallback, useContext, useEffect, useState } from "react";
7
7
  import { jsx, jsxs } from "react/jsx-runtime";
8
8
  import { CaretLeftIcon, CaretRightIcon, FileIcon, FileTextIcon, ImageIcon, XIcon } from "@phosphor-icons/react";
@@ -223,7 +223,7 @@ var DOC_EXTS = new Set([
223
223
  "md",
224
224
  "rtf"
225
225
  ]);
226
- var EXT_RE = /\.[^/.]+$/;
226
+ var EXT_RE = /\.[^/.]+$/u;
227
227
  function fileIcon(filename) {
228
228
  const ext = filename.split(".").pop()?.toLowerCase() ?? "";
229
229
  if (IMAGE_EXTS.has(ext)) return /* @__PURE__ */ jsx(ImageIcon, { className: "size-3.5" });
@@ -302,4 +302,4 @@ AiMessageAttachment.displayName = "AiMessageAttachment";
302
302
  //#endregion
303
303
  export { AiMessageAttachments as a, AiMessageBranchSelector as c, SF_AI_MESSAGE_DEFAULT_VARIANTS as d, SF_AI_MESSAGE_VARIANTS as f, AiMessageAttachment as i, AiMessageContent as l, AiMessageAction as n, AiMessageBranch as o, AiMessageActions as r, AiMessageBranchContent as s, AiMessage as t, AiMessageToolbar as u };
304
304
 
305
- //# sourceMappingURL=ai-message-Bp7L68U_.js.map
305
+ //# sourceMappingURL=ai-message-Ci3gwM7G.js.map