@schlessera/brain-ui-react 0.35.0 → 0.36.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 (755) hide show
  1. package/README.md +82 -4
  2. package/dist/components/activity/activity-page.d.ts +17 -5
  3. package/dist/components/activity/activity-page.d.ts.map +1 -1
  4. package/dist/components/activity/activity-page.js +144 -50
  5. package/dist/components/activity/activity-page.js.map +1 -1
  6. package/dist/components/activity/activity-run-detail.d.ts +16 -1
  7. package/dist/components/activity/activity-run-detail.d.ts.map +1 -1
  8. package/dist/components/activity/activity-run-detail.js +47 -4
  9. package/dist/components/activity/activity-run-detail.js.map +1 -1
  10. package/dist/components/activity/activity-run-list.d.ts +7 -1
  11. package/dist/components/activity/activity-run-list.d.ts.map +1 -1
  12. package/dist/components/activity/activity-run-list.js +16 -8
  13. package/dist/components/activity/activity-run-list.js.map +1 -1
  14. package/dist/components/activity/activity-views.d.ts +63 -0
  15. package/dist/components/activity/activity-views.d.ts.map +1 -0
  16. package/dist/components/activity/activity-views.js +52 -0
  17. package/dist/components/activity/activity-views.js.map +1 -0
  18. package/dist/components/activity/approval-card.d.ts +11 -0
  19. package/dist/components/activity/approval-card.d.ts.map +1 -0
  20. package/dist/components/activity/approval-card.js +46 -0
  21. package/dist/components/activity/approval-card.js.map +1 -0
  22. package/dist/components/activity/digest-card.d.ts +3 -0
  23. package/dist/components/activity/digest-card.d.ts.map +1 -1
  24. package/dist/components/activity/digest-card.js +20 -16
  25. package/dist/components/activity/digest-card.js.map +1 -1
  26. package/dist/components/activity/digest-summary.d.ts +19 -0
  27. package/dist/components/activity/digest-summary.d.ts.map +1 -0
  28. package/dist/components/activity/digest-summary.js +20 -0
  29. package/dist/components/activity/digest-summary.js.map +1 -0
  30. package/dist/components/activity/push-switch.d.ts +25 -0
  31. package/dist/components/activity/push-switch.d.ts.map +1 -0
  32. package/dist/components/activity/push-switch.js +14 -0
  33. package/dist/components/activity/push-switch.js.map +1 -0
  34. package/dist/components/activity/push-toggle.d.ts +7 -0
  35. package/dist/components/activity/push-toggle.d.ts.map +1 -1
  36. package/dist/components/activity/push-toggle.js +72 -47
  37. package/dist/components/activity/push-toggle.js.map +1 -1
  38. package/dist/components/activity/span-bits.d.ts.map +1 -1
  39. package/dist/components/activity/span-bits.js +9 -7
  40. package/dist/components/activity/span-bits.js.map +1 -1
  41. package/dist/components/chat/ask-user-card.d.ts +76 -3
  42. package/dist/components/chat/ask-user-card.d.ts.map +1 -1
  43. package/dist/components/chat/ask-user-card.js +208 -149
  44. package/dist/components/chat/ask-user-card.js.map +1 -1
  45. package/dist/components/chat/ask-user-typed.d.ts +42 -0
  46. package/dist/components/chat/ask-user-typed.d.ts.map +1 -0
  47. package/dist/components/chat/ask-user-typed.js +60 -0
  48. package/dist/components/chat/ask-user-typed.js.map +1 -0
  49. package/dist/components/chat/brain-markdown-links.d.ts +2 -1
  50. package/dist/components/chat/brain-markdown-links.d.ts.map +1 -1
  51. package/dist/components/chat/brain-markdown-links.js +3 -4
  52. package/dist/components/chat/brain-markdown-links.js.map +1 -1
  53. package/dist/components/chat/brain-markdown.d.ts.map +1 -1
  54. package/dist/components/chat/brain-markdown.js +4 -2
  55. package/dist/components/chat/brain-markdown.js.map +1 -1
  56. package/dist/components/chat/chat-page.d.ts.map +1 -1
  57. package/dist/components/chat/chat-page.js +24 -9
  58. package/dist/components/chat/chat-page.js.map +1 -1
  59. package/dist/components/chat/composer-view.d.ts +75 -0
  60. package/dist/components/chat/composer-view.d.ts.map +1 -0
  61. package/dist/components/chat/composer-view.js +31 -0
  62. package/dist/components/chat/composer-view.js.map +1 -0
  63. package/dist/components/chat/composer.d.ts +4 -0
  64. package/dist/components/chat/composer.d.ts.map +1 -1
  65. package/dist/components/chat/composer.js +76 -59
  66. package/dist/components/chat/composer.js.map +1 -1
  67. package/dist/components/chat/markdown-content.d.ts +16 -1
  68. package/dist/components/chat/markdown-content.d.ts.map +1 -1
  69. package/dist/components/chat/markdown-content.js +47 -3
  70. package/dist/components/chat/markdown-content.js.map +1 -1
  71. package/dist/components/chat/mermaid-block.d.ts +4 -0
  72. package/dist/components/chat/mermaid-block.d.ts.map +1 -1
  73. package/dist/components/chat/mermaid-block.js +13 -5
  74. package/dist/components/chat/mermaid-block.js.map +1 -1
  75. package/dist/components/chat/mermaid-share.d.ts +2 -1
  76. package/dist/components/chat/mermaid-share.d.ts.map +1 -1
  77. package/dist/components/chat/mermaid-share.js +7 -8
  78. package/dist/components/chat/mermaid-share.js.map +1 -1
  79. package/dist/components/chat/mermaid-viewer.d.ts.map +1 -1
  80. package/dist/components/chat/mermaid-viewer.js +3 -1
  81. package/dist/components/chat/mermaid-viewer.js.map +1 -1
  82. package/dist/components/chat/message-bubble.d.ts +8 -1
  83. package/dist/components/chat/message-bubble.d.ts.map +1 -1
  84. package/dist/components/chat/message-bubble.js +53 -24
  85. package/dist/components/chat/message-bubble.js.map +1 -1
  86. package/dist/components/chat/message-share.d.ts +2 -1
  87. package/dist/components/chat/message-share.d.ts.map +1 -1
  88. package/dist/components/chat/message-share.js +6 -7
  89. package/dist/components/chat/message-share.js.map +1 -1
  90. package/dist/components/chat/renderers/bind.d.ts +39 -0
  91. package/dist/components/chat/renderers/bind.d.ts.map +1 -0
  92. package/dist/components/chat/renderers/bind.js +43 -0
  93. package/dist/components/chat/renderers/bind.js.map +1 -0
  94. package/dist/components/chat/renderers/brain-ui-tools.d.ts +3 -0
  95. package/dist/components/chat/renderers/brain-ui-tools.d.ts.map +1 -0
  96. package/dist/components/chat/renderers/brain-ui-tools.js +41 -0
  97. package/dist/components/chat/renderers/brain-ui-tools.js.map +1 -0
  98. package/dist/components/chat/renderers/claude-tools.d.ts.map +1 -1
  99. package/dist/components/chat/renderers/claude-tools.js +3 -2
  100. package/dist/components/chat/renderers/claude-tools.js.map +1 -1
  101. package/dist/components/chat/renderers/index.d.ts +10 -2
  102. package/dist/components/chat/renderers/index.d.ts.map +1 -1
  103. package/dist/components/chat/renderers/index.js +15 -10
  104. package/dist/components/chat/renderers/index.js.map +1 -1
  105. package/dist/components/chat/session-drawer.d.ts +4 -0
  106. package/dist/components/chat/session-drawer.d.ts.map +1 -1
  107. package/dist/components/chat/session-drawer.js +32 -32
  108. package/dist/components/chat/session-drawer.js.map +1 -1
  109. package/dist/components/chat/session-list.d.ts +41 -0
  110. package/dist/components/chat/session-list.d.ts.map +1 -0
  111. package/dist/components/chat/session-list.js +10 -0
  112. package/dist/components/chat/session-list.js.map +1 -0
  113. package/dist/components/chat/share-block.d.ts.map +1 -1
  114. package/dist/components/chat/share-block.js +12 -11
  115. package/dist/components/chat/share-block.js.map +1 -1
  116. package/dist/components/chat/share-card.js +2 -2
  117. package/dist/components/chat/share-card.js.map +1 -1
  118. package/dist/components/chat/subagent-view.js +1 -1
  119. package/dist/components/chat/subagent-view.js.map +1 -1
  120. package/dist/components/chat/tool-call-timeline.d.ts.map +1 -1
  121. package/dist/components/chat/tool-call-timeline.js +37 -12
  122. package/dist/components/chat/tool-call-timeline.js.map +1 -1
  123. package/dist/components/chat/tool-cards/block-card.d.ts +28 -0
  124. package/dist/components/chat/tool-cards/block-card.d.ts.map +1 -0
  125. package/dist/components/chat/tool-cards/block-card.js +103 -0
  126. package/dist/components/chat/tool-cards/block-card.js.map +1 -0
  127. package/dist/components/chat/tool-cards/image-mask-card.d.ts +70 -0
  128. package/dist/components/chat/tool-cards/image-mask-card.d.ts.map +1 -0
  129. package/dist/components/chat/tool-cards/image-mask-card.js +142 -0
  130. package/dist/components/chat/tool-cards/image-mask-card.js.map +1 -0
  131. package/dist/components/chat/tool-cards/location-card.d.ts +45 -0
  132. package/dist/components/chat/tool-cards/location-card.d.ts.map +1 -0
  133. package/dist/components/chat/tool-cards/location-card.js +128 -0
  134. package/dist/components/chat/tool-cards/location-card.js.map +1 -0
  135. package/dist/components/chat/tool-views.d.ts +13 -2
  136. package/dist/components/chat/tool-views.d.ts.map +1 -1
  137. package/dist/components/chat/tool-views.js +20 -22
  138. package/dist/components/chat/tool-views.js.map +1 -1
  139. package/dist/components/chat/transcript-turn.d.ts +45 -0
  140. package/dist/components/chat/transcript-turn.d.ts.map +1 -0
  141. package/dist/components/chat/transcript-turn.js +25 -0
  142. package/dist/components/chat/transcript-turn.js.map +1 -0
  143. package/dist/components/chat/use-chat-commands.d.ts.map +1 -1
  144. package/dist/components/chat/use-chat-commands.js +13 -16
  145. package/dist/components/chat/use-chat-commands.js.map +1 -1
  146. package/dist/components/chat/welcome-state.d.ts +7 -0
  147. package/dist/components/chat/welcome-state.d.ts.map +1 -1
  148. package/dist/components/chat/welcome-state.js +13 -5
  149. package/dist/components/chat/welcome-state.js.map +1 -1
  150. package/dist/components/connectivity/connection-gate.d.ts.map +1 -1
  151. package/dist/components/connectivity/connection-gate.js +27 -21
  152. package/dist/components/connectivity/connection-gate.js.map +1 -1
  153. package/dist/components/connectivity/login-form.d.ts +31 -0
  154. package/dist/components/connectivity/login-form.d.ts.map +1 -0
  155. package/dist/components/connectivity/login-form.js +19 -0
  156. package/dist/components/connectivity/login-form.js.map +1 -0
  157. package/dist/components/connectivity/login-screen.d.ts +5 -2
  158. package/dist/components/connectivity/login-screen.d.ts.map +1 -1
  159. package/dist/components/connectivity/login-screen.js +41 -31
  160. package/dist/components/connectivity/login-screen.js.map +1 -1
  161. package/dist/components/dev/share-harness.js +1 -1
  162. package/dist/components/dev/share-harness.js.map +1 -1
  163. package/dist/components/files/file-panel.d.ts +1 -1
  164. package/dist/components/files/file-panel.d.ts.map +1 -1
  165. package/dist/components/files/file-panel.js +74 -0
  166. package/dist/components/files/file-panel.js.map +1 -1
  167. package/dist/components/files/file-tree-view.d.ts +45 -0
  168. package/dist/components/files/file-tree-view.d.ts.map +1 -0
  169. package/dist/components/files/file-tree-view.js +51 -0
  170. package/dist/components/files/file-tree-view.js.map +1 -0
  171. package/dist/components/files/file-tree.d.ts +6 -0
  172. package/dist/components/files/file-tree.d.ts.map +1 -1
  173. package/dist/components/files/file-tree.js +39 -43
  174. package/dist/components/files/file-tree.js.map +1 -1
  175. package/dist/components/files/file-viewer-binary.d.ts.map +1 -1
  176. package/dist/components/files/file-viewer-binary.js +3 -2
  177. package/dist/components/files/file-viewer-binary.js.map +1 -1
  178. package/dist/components/files/file-viewer-frame.d.ts +36 -0
  179. package/dist/components/files/file-viewer-frame.d.ts.map +1 -0
  180. package/dist/components/files/file-viewer-frame.js +26 -0
  181. package/dist/components/files/file-viewer-frame.js.map +1 -0
  182. package/dist/components/files/file-viewer.d.ts +5 -0
  183. package/dist/components/files/file-viewer.d.ts.map +1 -1
  184. package/dist/components/files/file-viewer.js +26 -32
  185. package/dist/components/files/file-viewer.js.map +1 -1
  186. package/dist/components/files/frontmatter-chips.d.ts +18 -0
  187. package/dist/components/files/frontmatter-chips.d.ts.map +1 -0
  188. package/dist/components/files/frontmatter-chips.js +11 -0
  189. package/dist/components/files/frontmatter-chips.js.map +1 -0
  190. package/dist/components/files/frontmatter-panel.d.ts +5 -1
  191. package/dist/components/files/frontmatter-panel.d.ts.map +1 -1
  192. package/dist/components/files/frontmatter-panel.js +7 -6
  193. package/dist/components/files/frontmatter-panel.js.map +1 -1
  194. package/dist/components/files/staleness.d.ts +18 -0
  195. package/dist/components/files/staleness.d.ts.map +1 -0
  196. package/dist/components/files/staleness.js +27 -0
  197. package/dist/components/files/staleness.js.map +1 -0
  198. package/dist/components/graph/graph-canvas.d.ts.map +1 -1
  199. package/dist/components/graph/graph-canvas.js +24 -1
  200. package/dist/components/graph/graph-canvas.js.map +1 -1
  201. package/dist/components/graph/graph-controls-column.d.ts +14 -0
  202. package/dist/components/graph/graph-controls-column.d.ts.map +1 -0
  203. package/dist/components/graph/graph-controls-column.js +44 -0
  204. package/dist/components/graph/graph-controls-column.js.map +1 -0
  205. package/dist/components/graph/graph-controls.d.ts +20 -5
  206. package/dist/components/graph/graph-controls.d.ts.map +1 -1
  207. package/dist/components/graph/graph-controls.js +58 -37
  208. package/dist/components/graph/graph-controls.js.map +1 -1
  209. package/dist/components/graph/graph-form.d.ts +82 -0
  210. package/dist/components/graph/graph-form.d.ts.map +1 -0
  211. package/dist/components/graph/graph-form.js +69 -0
  212. package/dist/components/graph/graph-form.js.map +1 -0
  213. package/dist/components/graph/graph-maintenance.d.ts.map +1 -1
  214. package/dist/components/graph/graph-maintenance.js +6 -10
  215. package/dist/components/graph/graph-maintenance.js.map +1 -1
  216. package/dist/components/graph/graph-node-rail.d.ts +13 -0
  217. package/dist/components/graph/graph-node-rail.d.ts.map +1 -0
  218. package/dist/components/graph/graph-node-rail.js +92 -0
  219. package/dist/components/graph/graph-node-rail.js.map +1 -0
  220. package/dist/components/graph/graph-page.d.ts +7 -0
  221. package/dist/components/graph/graph-page.d.ts.map +1 -1
  222. package/dist/components/graph/graph-page.js +102 -12
  223. package/dist/components/graph/graph-page.js.map +1 -1
  224. package/dist/components/graph/graph-scene.d.ts.map +1 -1
  225. package/dist/components/graph/graph-scene.js +100 -24
  226. package/dist/components/graph/graph-scene.js.map +1 -1
  227. package/dist/components/graph/lib/graph-helpers.d.ts +42 -12
  228. package/dist/components/graph/lib/graph-helpers.d.ts.map +1 -1
  229. package/dist/components/graph/lib/graph-helpers.js +33 -41
  230. package/dist/components/graph/lib/graph-helpers.js.map +1 -1
  231. package/dist/components/graph/node-card.d.ts +28 -0
  232. package/dist/components/graph/node-card.d.ts.map +1 -0
  233. package/dist/components/graph/node-card.js +7 -0
  234. package/dist/components/graph/node-card.js.map +1 -0
  235. package/dist/components/graph/node-popover.d.ts +6 -2
  236. package/dist/components/graph/node-popover.d.ts.map +1 -1
  237. package/dist/components/graph/node-popover.js +13 -31
  238. package/dist/components/graph/node-popover.js.map +1 -1
  239. package/dist/components/graph/use-graph-theme.d.ts +32 -4
  240. package/dist/components/graph/use-graph-theme.d.ts.map +1 -1
  241. package/dist/components/graph/use-graph-theme.js +44 -32
  242. package/dist/components/graph/use-graph-theme.js.map +1 -1
  243. package/dist/components/graph/use-node-actions.d.ts +26 -0
  244. package/dist/components/graph/use-node-actions.d.ts.map +1 -0
  245. package/dist/components/graph/use-node-actions.js +54 -0
  246. package/dist/components/graph/use-node-actions.js.map +1 -0
  247. package/dist/components/images/image-share.d.ts +2 -1
  248. package/dist/components/images/image-share.d.ts.map +1 -1
  249. package/dist/components/images/image-share.js +3 -3
  250. package/dist/components/images/image-share.js.map +1 -1
  251. package/dist/components/images/image-viewer.d.ts.map +1 -1
  252. package/dist/components/images/image-viewer.js +3 -1
  253. package/dist/components/images/image-viewer.js.map +1 -1
  254. package/dist/components/images/mask-editor.d.ts.map +1 -1
  255. package/dist/components/images/mask-editor.js +7 -5
  256. package/dist/components/images/mask-editor.js.map +1 -1
  257. package/dist/components/layout/app-shell.d.ts.map +1 -1
  258. package/dist/components/layout/app-shell.js +4 -1
  259. package/dist/components/layout/app-shell.js.map +1 -1
  260. package/dist/components/layout/desktop-palette.d.ts +23 -0
  261. package/dist/components/layout/desktop-palette.d.ts.map +1 -0
  262. package/dist/components/layout/desktop-palette.js +132 -0
  263. package/dist/components/layout/desktop-palette.js.map +1 -0
  264. package/dist/components/layout/key-cap.d.ts +9 -0
  265. package/dist/components/layout/key-cap.d.ts.map +1 -0
  266. package/dist/components/layout/key-cap.js +10 -0
  267. package/dist/components/layout/key-cap.js.map +1 -0
  268. package/dist/components/layout/mobile-tab-bar.d.ts +13 -0
  269. package/dist/components/layout/mobile-tab-bar.d.ts.map +1 -1
  270. package/dist/components/layout/mobile-tab-bar.js +58 -47
  271. package/dist/components/layout/mobile-tab-bar.js.map +1 -1
  272. package/dist/components/layout/shortcut-switch.d.ts +13 -0
  273. package/dist/components/layout/shortcut-switch.d.ts.map +1 -0
  274. package/dist/components/layout/shortcut-switch.js +22 -0
  275. package/dist/components/layout/shortcut-switch.js.map +1 -0
  276. package/dist/components/layout/side-rail.d.ts +24 -0
  277. package/dist/components/layout/side-rail.d.ts.map +1 -1
  278. package/dist/components/layout/side-rail.js +65 -27
  279. package/dist/components/layout/side-rail.js.map +1 -1
  280. package/dist/components/layout/slide-panel.d.ts +12 -2
  281. package/dist/components/layout/slide-panel.d.ts.map +1 -1
  282. package/dist/components/layout/slide-panel.js +11 -2
  283. package/dist/components/layout/slide-panel.js.map +1 -1
  284. package/dist/components/layout/theme.d.ts +22 -0
  285. package/dist/components/layout/theme.d.ts.map +1 -0
  286. package/dist/components/layout/theme.js +44 -0
  287. package/dist/components/layout/theme.js.map +1 -0
  288. package/dist/components/quick-actions/add-form.d.ts +44 -0
  289. package/dist/components/quick-actions/add-form.d.ts.map +1 -0
  290. package/dist/components/quick-actions/add-form.js +30 -0
  291. package/dist/components/quick-actions/add-form.js.map +1 -0
  292. package/dist/components/quick-actions/add-modal.d.ts +7 -0
  293. package/dist/components/quick-actions/add-modal.d.ts.map +1 -1
  294. package/dist/components/quick-actions/add-modal.js +23 -20
  295. package/dist/components/quick-actions/add-modal.js.map +1 -1
  296. package/dist/components/quick-actions/search-modal.d.ts.map +1 -1
  297. package/dist/components/quick-actions/search-modal.js +4 -3
  298. package/dist/components/quick-actions/search-modal.js.map +1 -1
  299. package/dist/components/quick-actions/streaming-modal.d.ts +6 -0
  300. package/dist/components/quick-actions/streaming-modal.d.ts.map +1 -1
  301. package/dist/components/quick-actions/streaming-modal.js +39 -17
  302. package/dist/components/quick-actions/streaming-modal.js.map +1 -1
  303. package/dist/components/quick-actions/streaming-output.d.ts +38 -0
  304. package/dist/components/quick-actions/streaming-output.d.ts.map +1 -0
  305. package/dist/components/quick-actions/streaming-output.js +22 -0
  306. package/dist/components/quick-actions/streaming-output.js.map +1 -0
  307. package/dist/components/quick-actions/whatsup-modal.d.ts +5 -0
  308. package/dist/components/quick-actions/whatsup-modal.d.ts.map +1 -1
  309. package/dist/components/quick-actions/whatsup-modal.js +36 -10
  310. package/dist/components/quick-actions/whatsup-modal.js.map +1 -1
  311. package/dist/components/settings/devices-agents-tab.d.ts +6 -1
  312. package/dist/components/settings/devices-agents-tab.d.ts.map +1 -1
  313. package/dist/components/settings/devices-agents-tab.js +55 -20
  314. package/dist/components/settings/devices-agents-tab.js.map +1 -1
  315. package/dist/components/settings/models-list.d.ts +39 -0
  316. package/dist/components/settings/models-list.d.ts.map +1 -0
  317. package/dist/components/settings/models-list.js +72 -0
  318. package/dist/components/settings/models-list.js.map +1 -0
  319. package/dist/components/settings/models-tab.d.ts +4 -0
  320. package/dist/components/settings/models-tab.d.ts.map +1 -1
  321. package/dist/components/settings/models-tab.js +52 -102
  322. package/dist/components/settings/models-tab.js.map +1 -1
  323. package/dist/components/settings/one-time-agent-credential.js +1 -1
  324. package/dist/components/settings/one-time-agent-credential.js.map +1 -1
  325. package/dist/components/settings/passkey-list.d.ts +35 -0
  326. package/dist/components/settings/passkey-list.d.ts.map +1 -0
  327. package/dist/components/settings/passkey-list.js +34 -0
  328. package/dist/components/settings/passkey-list.js.map +1 -0
  329. package/dist/components/settings/passkey-tab.d.ts +3 -0
  330. package/dist/components/settings/passkey-tab.d.ts.map +1 -1
  331. package/dist/components/settings/passkey-tab.js +53 -45
  332. package/dist/components/settings/passkey-tab.js.map +1 -1
  333. package/dist/components/settings/pi-accounts-list.d.ts +27 -0
  334. package/dist/components/settings/pi-accounts-list.d.ts.map +1 -0
  335. package/dist/components/settings/pi-accounts-list.js +15 -0
  336. package/dist/components/settings/pi-accounts-list.js.map +1 -0
  337. package/dist/components/settings/pi-accounts.d.ts +3 -0
  338. package/dist/components/settings/pi-accounts.d.ts.map +1 -1
  339. package/dist/components/settings/pi-accounts.js +73 -55
  340. package/dist/components/settings/pi-accounts.js.map +1 -1
  341. package/dist/components/settings/principal-list.d.ts +37 -0
  342. package/dist/components/settings/principal-list.d.ts.map +1 -0
  343. package/dist/components/settings/principal-list.js +18 -0
  344. package/dist/components/settings/principal-list.js.map +1 -0
  345. package/dist/components/settings/settings-panel.d.ts +10 -3
  346. package/dist/components/settings/settings-panel.d.ts.map +1 -1
  347. package/dist/components/settings/settings-panel.js +69 -8
  348. package/dist/components/settings/settings-panel.js.map +1 -1
  349. package/dist/components/settings/skills-list.d.ts +53 -0
  350. package/dist/components/settings/skills-list.d.ts.map +1 -0
  351. package/dist/components/settings/skills-list.js +28 -0
  352. package/dist/components/settings/skills-list.js.map +1 -0
  353. package/dist/components/settings/skills-tab.d.ts.map +1 -1
  354. package/dist/components/settings/skills-tab.js +65 -38
  355. package/dist/components/settings/skills-tab.js.map +1 -1
  356. package/dist/components/settings/tool-permissions-list.d.ts +18 -0
  357. package/dist/components/settings/tool-permissions-list.d.ts.map +1 -0
  358. package/dist/components/settings/tool-permissions-list.js +6 -0
  359. package/dist/components/settings/tool-permissions-list.js.map +1 -0
  360. package/dist/components/settings/tool-permissions.d.ts +2 -1
  361. package/dist/components/settings/tool-permissions.d.ts.map +1 -1
  362. package/dist/components/settings/tool-permissions.js +33 -16
  363. package/dist/components/settings/tool-permissions.js.map +1 -1
  364. package/dist/components/settings/web-search-chain.d.ts +41 -0
  365. package/dist/components/settings/web-search-chain.d.ts.map +1 -0
  366. package/dist/components/settings/web-search-chain.js +47 -0
  367. package/dist/components/settings/web-search-chain.js.map +1 -0
  368. package/dist/components/settings/web-search-settings.d.ts +4 -7
  369. package/dist/components/settings/web-search-settings.d.ts.map +1 -1
  370. package/dist/components/settings/web-search-settings.js +54 -76
  371. package/dist/components/settings/web-search-settings.js.map +1 -1
  372. package/dist/components/share/share-menu.d.ts.map +1 -1
  373. package/dist/components/share/share-menu.js +24 -4
  374. package/dist/components/share/share-menu.js.map +1 -1
  375. package/dist/components/voice/dictation-sheet.js +3 -3
  376. package/dist/components/voice/dictation-sheet.js.map +1 -1
  377. package/dist/components/voice/mic-button.js +1 -1
  378. package/dist/components/voice/mic-button.js.map +1 -1
  379. package/dist/components/voice/review-card.js +1 -1
  380. package/dist/components/voice/review-card.js.map +1 -1
  381. package/dist/config.d.ts +5 -2
  382. package/dist/config.d.ts.map +1 -1
  383. package/dist/config.js +15 -5
  384. package/dist/config.js.map +1 -1
  385. package/dist/connection.d.ts +12 -0
  386. package/dist/connection.d.ts.map +1 -0
  387. package/dist/connection.js +421 -0
  388. package/dist/connection.js.map +1 -0
  389. package/dist/default-root.d.ts +3 -0
  390. package/dist/default-root.d.ts.map +1 -0
  391. package/dist/default-root.js +16 -0
  392. package/dist/default-root.js.map +1 -0
  393. package/dist/hooks/use-color-scheme.d.ts +14 -0
  394. package/dist/hooks/use-color-scheme.d.ts.map +1 -0
  395. package/dist/hooks/use-color-scheme.js +37 -0
  396. package/dist/hooks/use-color-scheme.js.map +1 -0
  397. package/dist/hooks/use-hash-routes.d.ts.map +1 -1
  398. package/dist/hooks/use-hash-routes.js +4 -2
  399. package/dist/hooks/use-hash-routes.js.map +1 -1
  400. package/dist/hooks/use-media-query.d.ts +7 -0
  401. package/dist/hooks/use-media-query.d.ts.map +1 -0
  402. package/dist/hooks/use-media-query.js +34 -0
  403. package/dist/hooks/use-media-query.js.map +1 -0
  404. package/dist/hooks/use-share-intake.d.ts.map +1 -1
  405. package/dist/hooks/use-share-intake.js +37 -12
  406. package/dist/hooks/use-share-intake.js.map +1 -1
  407. package/dist/hooks/use-vpn-status.d.ts.map +1 -1
  408. package/dist/hooks/use-vpn-status.js +17 -18
  409. package/dist/hooks/use-vpn-status.js.map +1 -1
  410. package/dist/hooks/use-websocket.d.ts +5 -24
  411. package/dist/hooks/use-websocket.d.ts.map +1 -1
  412. package/dist/hooks/use-websocket.js +11 -384
  413. package/dist/hooks/use-websocket.js.map +1 -1
  414. package/dist/hooks/websocket-handlers/activity.d.ts +2 -2
  415. package/dist/hooks/websocket-handlers/activity.d.ts.map +1 -1
  416. package/dist/hooks/websocket-handlers/activity.js +4 -5
  417. package/dist/hooks/websocket-handlers/activity.js.map +1 -1
  418. package/dist/hooks/websocket-handlers/chat.d.ts +1 -0
  419. package/dist/hooks/websocket-handlers/chat.d.ts.map +1 -1
  420. package/dist/hooks/websocket-handlers/chat.js +27 -5
  421. package/dist/hooks/websocket-handlers/chat.js.map +1 -1
  422. package/dist/hooks/websocket-handlers/connection.d.ts.map +1 -1
  423. package/dist/hooks/websocket-handlers/connection.js +4 -6
  424. package/dist/hooks/websocket-handlers/connection.js.map +1 -1
  425. package/dist/hooks/websocket-handlers/mask.d.ts +1 -1
  426. package/dist/hooks/websocket-handlers/mask.d.ts.map +1 -1
  427. package/dist/hooks/websocket-handlers/mask.js +2 -3
  428. package/dist/hooks/websocket-handlers/mask.js.map +1 -1
  429. package/dist/hooks/websocket-handlers/provider.d.ts.map +1 -1
  430. package/dist/hooks/websocket-handlers/provider.js +4 -6
  431. package/dist/hooks/websocket-handlers/provider.js.map +1 -1
  432. package/dist/hooks/websocket-handlers/types.d.ts +6 -2
  433. package/dist/hooks/websocket-handlers/types.d.ts.map +1 -1
  434. package/dist/index.d.ts +5 -3
  435. package/dist/index.d.ts.map +1 -1
  436. package/dist/index.js +6 -3
  437. package/dist/index.js.map +1 -1
  438. package/dist/lib/api-client.d.ts +289 -0
  439. package/dist/lib/api-client.d.ts.map +1 -1
  440. package/dist/lib/api-client.js +243 -224
  441. package/dist/lib/api-client.js.map +1 -1
  442. package/dist/lib/backend.d.ts +19 -2
  443. package/dist/lib/backend.d.ts.map +1 -1
  444. package/dist/lib/backend.js +15 -9
  445. package/dist/lib/backend.js.map +1 -1
  446. package/dist/lib/diff.d.ts +8 -10
  447. package/dist/lib/diff.d.ts.map +1 -1
  448. package/dist/lib/diff.js +26 -53
  449. package/dist/lib/diff.js.map +1 -1
  450. package/dist/lib/light-dark.d.ts +37 -0
  451. package/dist/lib/light-dark.d.ts.map +1 -0
  452. package/dist/lib/light-dark.js +83 -0
  453. package/dist/lib/light-dark.js.map +1 -0
  454. package/dist/lib/mermaid-theme.d.ts +7 -2
  455. package/dist/lib/mermaid-theme.d.ts.map +1 -1
  456. package/dist/lib/mermaid-theme.js +125 -203
  457. package/dist/lib/mermaid-theme.js.map +1 -1
  458. package/dist/lib/passkeys.d.ts +6 -3
  459. package/dist/lib/passkeys.d.ts.map +1 -1
  460. package/dist/lib/passkeys.js +10 -4
  461. package/dist/lib/passkeys.js.map +1 -1
  462. package/dist/lib/push-registration.d.ts +4 -1
  463. package/dist/lib/push-registration.d.ts.map +1 -1
  464. package/dist/lib/push-registration.js +20 -2
  465. package/dist/lib/push-registration.js.map +1 -1
  466. package/dist/lib/share-intake.d.ts +2 -1
  467. package/dist/lib/share-intake.d.ts.map +1 -1
  468. package/dist/lib/share-intake.js +3 -3
  469. package/dist/lib/share-intake.js.map +1 -1
  470. package/dist/lib/share.d.ts +4 -3
  471. package/dist/lib/share.d.ts.map +1 -1
  472. package/dist/lib/share.js +6 -7
  473. package/dist/lib/share.js.map +1 -1
  474. package/dist/lib/single-key.d.ts +30 -0
  475. package/dist/lib/single-key.d.ts.map +1 -0
  476. package/dist/lib/single-key.js +45 -0
  477. package/dist/lib/single-key.js.map +1 -0
  478. package/dist/lib/tool-names.d.ts +8 -6
  479. package/dist/lib/tool-names.d.ts.map +1 -1
  480. package/dist/lib/tool-names.js +17 -7
  481. package/dist/lib/tool-names.js.map +1 -1
  482. package/dist/root-context.d.ts +229 -0
  483. package/dist/root-context.d.ts.map +1 -0
  484. package/dist/root-context.js +33 -0
  485. package/dist/root-context.js.map +1 -0
  486. package/dist/root.d.ts +38 -0
  487. package/dist/root.d.ts.map +1 -0
  488. package/dist/root.js +47 -0
  489. package/dist/root.js.map +1 -0
  490. package/dist/stores/activity-state.d.ts +29 -0
  491. package/dist/stores/activity-state.d.ts.map +1 -0
  492. package/dist/stores/activity-state.js +282 -0
  493. package/dist/stores/activity-state.js.map +1 -0
  494. package/dist/stores/activity-store.d.ts +10 -41
  495. package/dist/stores/activity-store.d.ts.map +1 -1
  496. package/dist/stores/activity-store.js +9 -271
  497. package/dist/stores/activity-store.js.map +1 -1
  498. package/dist/stores/chat-state.d.ts +212 -0
  499. package/dist/stores/chat-state.d.ts.map +1 -0
  500. package/dist/stores/chat-state.js +466 -0
  501. package/dist/stores/chat-state.js.map +1 -0
  502. package/dist/stores/chat-store.d.ts +4 -162
  503. package/dist/stores/chat-store.d.ts.map +1 -1
  504. package/dist/stores/chat-store.js +7 -418
  505. package/dist/stores/chat-store.js.map +1 -1
  506. package/dist/stores/connection-state.d.ts +40 -0
  507. package/dist/stores/connection-state.d.ts.map +1 -0
  508. package/dist/stores/connection-state.js +30 -0
  509. package/dist/stores/connection-state.js.map +1 -0
  510. package/dist/stores/connection-store.d.ts +4 -40
  511. package/dist/stores/connection-store.d.ts.map +1 -1
  512. package/dist/stores/connection-store.js +7 -27
  513. package/dist/stores/connection-store.js.map +1 -1
  514. package/dist/stores/create-stores.d.ts +23 -0
  515. package/dist/stores/create-stores.d.ts.map +1 -0
  516. package/dist/stores/create-stores.js +28 -0
  517. package/dist/stores/create-stores.js.map +1 -0
  518. package/dist/stores/file-state.d.ts +53 -0
  519. package/dist/stores/file-state.d.ts.map +1 -0
  520. package/dist/stores/file-state.js +341 -0
  521. package/dist/stores/file-state.js.map +1 -0
  522. package/dist/stores/file-store.d.ts +4 -52
  523. package/dist/stores/file-store.d.ts.map +1 -1
  524. package/dist/stores/file-store.js +7 -336
  525. package/dist/stores/file-store.js.map +1 -1
  526. package/dist/stores/graph-state.d.ts +95 -0
  527. package/dist/stores/graph-state.d.ts.map +1 -0
  528. package/dist/stores/graph-state.js +252 -0
  529. package/dist/stores/graph-state.js.map +1 -0
  530. package/dist/stores/graph-store.d.ts +7 -83
  531. package/dist/stores/graph-store.d.ts.map +1 -1
  532. package/dist/stores/graph-store.js +8 -249
  533. package/dist/stores/graph-store.js.map +1 -1
  534. package/dist/stores/mask-state.d.ts +21 -0
  535. package/dist/stores/mask-state.d.ts.map +1 -0
  536. package/dist/stores/mask-state.js +9 -0
  537. package/dist/stores/mask-state.js.map +1 -0
  538. package/dist/stores/mask-store.d.ts +4 -21
  539. package/dist/stores/mask-store.d.ts.map +1 -1
  540. package/dist/stores/mask-store.js +7 -6
  541. package/dist/stores/mask-store.js.map +1 -1
  542. package/dist/stores/principal-state.d.ts +16 -0
  543. package/dist/stores/principal-state.d.ts.map +1 -0
  544. package/dist/stores/principal-state.js +31 -0
  545. package/dist/stores/principal-state.js.map +1 -0
  546. package/dist/stores/principal-store.d.ts +4 -15
  547. package/dist/stores/principal-store.d.ts.map +1 -1
  548. package/dist/stores/principal-store.js +7 -28
  549. package/dist/stores/principal-store.js.map +1 -1
  550. package/dist/stores/provider-state.d.ts +24 -0
  551. package/dist/stores/provider-state.d.ts.map +1 -0
  552. package/dist/stores/provider-state.js +68 -0
  553. package/dist/stores/provider-state.js.map +1 -0
  554. package/dist/stores/provider-store.d.ts +4 -23
  555. package/dist/stores/provider-store.d.ts.map +1 -1
  556. package/dist/stores/provider-store.js +7 -64
  557. package/dist/stores/provider-store.js.map +1 -1
  558. package/dist/stores/share-state.d.ts +29 -0
  559. package/dist/stores/share-state.d.ts.map +1 -0
  560. package/dist/stores/share-state.js +21 -0
  561. package/dist/stores/share-state.js.map +1 -0
  562. package/dist/stores/share-store.d.ts +4 -28
  563. package/dist/stores/share-store.d.ts.map +1 -1
  564. package/dist/stores/share-store.js +7 -18
  565. package/dist/stores/share-store.js.map +1 -1
  566. package/dist/stores/store-environment.d.ts +10 -0
  567. package/dist/stores/store-environment.d.ts.map +1 -0
  568. package/dist/stores/store-environment.js +2 -0
  569. package/dist/stores/store-environment.js.map +1 -0
  570. package/dist/stores/ui-state.d.ts +71 -0
  571. package/dist/stores/ui-state.d.ts.map +1 -0
  572. package/dist/stores/ui-state.js +58 -0
  573. package/dist/stores/ui-state.js.map +1 -0
  574. package/dist/stores/ui-store.d.ts +4 -45
  575. package/dist/stores/ui-store.d.ts.map +1 -1
  576. package/dist/stores/ui-store.js +7 -36
  577. package/dist/stores/ui-store.js.map +1 -1
  578. package/dist/styles.css +1 -1
  579. package/dist/theme.css +150 -97
  580. package/dist/voice/asr-clients.d.ts +2 -1
  581. package/dist/voice/asr-clients.d.ts.map +1 -1
  582. package/dist/voice/asr-clients.js +16 -17
  583. package/dist/voice/asr-clients.js.map +1 -1
  584. package/dist/voice/use-dictation.d.ts.map +1 -1
  585. package/dist/voice/use-dictation.js +12 -8
  586. package/dist/voice/use-dictation.js.map +1 -1
  587. package/dist/voice/voice-state.d.ts +25 -0
  588. package/dist/voice/voice-state.d.ts.map +1 -0
  589. package/dist/voice/voice-state.js +29 -0
  590. package/dist/voice/voice-state.js.map +1 -0
  591. package/dist/voice/voice-store.d.ts +4 -25
  592. package/dist/voice/voice-store.d.ts.map +1 -1
  593. package/dist/voice/voice-store.js +7 -26
  594. package/dist/voice/voice-store.js.map +1 -1
  595. package/package.json +3 -2
  596. package/src/components/activity/activity-page.tsx +334 -160
  597. package/src/components/activity/activity-run-detail.tsx +81 -47
  598. package/src/components/activity/activity-run-list.tsx +27 -59
  599. package/src/components/activity/activity-views.tsx +155 -0
  600. package/src/components/activity/approval-card.tsx +80 -0
  601. package/src/components/activity/digest-card.tsx +25 -61
  602. package/src/components/activity/digest-summary.tsx +52 -0
  603. package/src/components/activity/push-switch.tsx +62 -0
  604. package/src/components/activity/push-toggle.tsx +51 -81
  605. package/src/components/activity/span-bits.tsx +8 -7
  606. package/src/components/chat/ask-user-card.tsx +292 -356
  607. package/src/components/chat/ask-user-typed.ts +77 -0
  608. package/src/components/chat/brain-markdown-links.tsx +4 -4
  609. package/src/components/chat/brain-markdown.tsx +4 -2
  610. package/src/components/chat/chat-page.tsx +38 -9
  611. package/src/components/chat/composer-view.tsx +194 -0
  612. package/src/components/chat/composer.tsx +117 -296
  613. package/src/components/chat/markdown-content.tsx +53 -2
  614. package/src/components/chat/mermaid-block.tsx +13 -5
  615. package/src/components/chat/mermaid-share.ts +8 -7
  616. package/src/components/chat/mermaid-viewer.tsx +3 -1
  617. package/src/components/chat/message-bubble.tsx +78 -94
  618. package/src/components/chat/message-share.ts +7 -7
  619. package/src/components/chat/renderers/bind.tsx +94 -0
  620. package/src/components/chat/renderers/brain-ui-tools.tsx +56 -0
  621. package/src/components/chat/renderers/claude-tools.tsx +3 -2
  622. package/src/components/chat/renderers/index.ts +15 -10
  623. package/src/components/chat/session-drawer.tsx +41 -138
  624. package/src/components/chat/session-list.tsx +113 -0
  625. package/src/components/chat/share-block.tsx +16 -12
  626. package/src/components/chat/share-card.tsx +2 -2
  627. package/src/components/chat/subagent-view.tsx +4 -4
  628. package/src/components/chat/tool-call-timeline.tsx +59 -22
  629. package/src/components/chat/tool-cards/block-card.tsx +145 -0
  630. package/src/components/chat/tool-cards/image-mask-card.tsx +214 -0
  631. package/src/components/chat/tool-cards/location-card.tsx +159 -0
  632. package/src/components/chat/tool-views.tsx +21 -60
  633. package/src/components/chat/transcript-turn.tsx +108 -0
  634. package/src/components/chat/use-chat-commands.ts +14 -16
  635. package/src/components/chat/welcome-state.tsx +36 -91
  636. package/src/components/connectivity/connection-gate.tsx +32 -24
  637. package/src/components/connectivity/login-form.tsx +122 -0
  638. package/src/components/connectivity/login-screen.tsx +45 -100
  639. package/src/components/dev/share-harness.tsx +2 -2
  640. package/src/components/files/file-panel.tsx +168 -0
  641. package/src/components/files/file-tree-view.tsx +127 -0
  642. package/src/components/files/file-tree.tsx +55 -109
  643. package/src/components/files/file-viewer-binary.tsx +3 -2
  644. package/src/components/files/file-viewer-frame.tsx +113 -0
  645. package/src/components/files/file-viewer.tsx +40 -95
  646. package/src/components/files/frontmatter-chips.tsx +42 -0
  647. package/src/components/files/frontmatter-panel.tsx +6 -71
  648. package/src/components/files/staleness.ts +29 -0
  649. package/src/components/graph/graph-canvas.tsx +24 -1
  650. package/src/components/graph/graph-controls-column.tsx +92 -0
  651. package/src/components/graph/graph-controls.tsx +83 -127
  652. package/src/components/graph/graph-form.tsx +183 -0
  653. package/src/components/graph/graph-maintenance.tsx +9 -14
  654. package/src/components/graph/graph-node-rail.tsx +147 -0
  655. package/src/components/graph/graph-page.tsx +189 -49
  656. package/src/components/graph/graph-scene.tsx +200 -30
  657. package/src/components/graph/lib/graph-helpers.ts +65 -43
  658. package/src/components/graph/node-card.tsx +64 -0
  659. package/src/components/graph/node-popover.tsx +28 -117
  660. package/src/components/graph/use-graph-theme.ts +69 -32
  661. package/src/components/graph/use-node-actions.ts +56 -0
  662. package/src/components/images/image-share.ts +4 -2
  663. package/src/components/images/image-viewer.tsx +3 -1
  664. package/src/components/images/mask-editor.tsx +7 -4
  665. package/src/components/layout/app-shell.tsx +5 -1
  666. package/src/components/layout/desktop-palette.tsx +151 -0
  667. package/src/components/layout/key-cap.tsx +15 -0
  668. package/src/components/layout/mobile-tab-bar.tsx +80 -157
  669. package/src/components/layout/shortcut-switch.tsx +32 -0
  670. package/src/components/layout/side-rail.tsx +70 -150
  671. package/src/components/layout/slide-panel.tsx +29 -2
  672. package/src/components/layout/theme.tsx +67 -0
  673. package/src/components/quick-actions/add-form.tsx +188 -0
  674. package/src/components/quick-actions/add-modal.tsx +32 -153
  675. package/src/components/quick-actions/search-modal.tsx +5 -3
  676. package/src/components/quick-actions/streaming-modal.tsx +42 -71
  677. package/src/components/quick-actions/streaming-output.tsx +112 -0
  678. package/src/components/quick-actions/whatsup-modal.tsx +38 -60
  679. package/src/components/settings/devices-agents-tab.tsx +60 -152
  680. package/src/components/settings/models-list.tsx +299 -0
  681. package/src/components/settings/models-tab.tsx +63 -337
  682. package/src/components/settings/one-time-agent-credential.tsx +1 -1
  683. package/src/components/settings/passkey-list.tsx +201 -0
  684. package/src/components/settings/passkey-tab.tsx +53 -197
  685. package/src/components/settings/pi-accounts-list.tsx +128 -0
  686. package/src/components/settings/pi-accounts.tsx +71 -170
  687. package/src/components/settings/principal-list.tsx +172 -0
  688. package/src/components/settings/settings-panel.tsx +232 -21
  689. package/src/components/settings/skills-list.tsx +276 -0
  690. package/src/components/settings/skills-tab.tsx +82 -269
  691. package/src/components/settings/tool-permissions-list.tsx +54 -0
  692. package/src/components/settings/tool-permissions.tsx +27 -46
  693. package/src/components/settings/web-search-chain.tsx +300 -0
  694. package/src/components/settings/web-search-settings.tsx +58 -328
  695. package/src/components/share/share-menu.tsx +19 -4
  696. package/src/components/voice/dictation-sheet.tsx +5 -5
  697. package/src/components/voice/mic-button.tsx +1 -1
  698. package/src/components/voice/review-card.tsx +1 -1
  699. package/src/config.ts +21 -7
  700. package/src/connection.ts +443 -0
  701. package/src/default-root.ts +16 -0
  702. package/src/hooks/use-color-scheme.ts +36 -0
  703. package/src/hooks/use-hash-routes.ts +4 -2
  704. package/src/hooks/use-media-query.ts +32 -0
  705. package/src/hooks/use-share-intake.ts +32 -12
  706. package/src/hooks/use-vpn-status.ts +18 -17
  707. package/src/hooks/use-websocket.ts +12 -428
  708. package/src/hooks/websocket-handlers/activity.ts +4 -5
  709. package/src/hooks/websocket-handlers/chat.ts +26 -5
  710. package/src/hooks/websocket-handlers/connection.ts +4 -6
  711. package/src/hooks/websocket-handlers/mask.ts +2 -3
  712. package/src/hooks/websocket-handlers/provider.ts +4 -6
  713. package/src/hooks/websocket-handlers/types.ts +6 -2
  714. package/src/index.ts +7 -3
  715. package/src/lib/api-client.ts +426 -384
  716. package/src/lib/backend.ts +20 -10
  717. package/src/lib/diff.ts +28 -62
  718. package/src/lib/light-dark.ts +83 -0
  719. package/src/lib/mermaid-theme.ts +183 -214
  720. package/src/lib/passkeys.ts +12 -4
  721. package/src/lib/push-registration.ts +19 -2
  722. package/src/lib/share-intake.ts +6 -3
  723. package/src/lib/share.ts +7 -4
  724. package/src/lib/single-key.ts +47 -0
  725. package/src/lib/tool-names.ts +31 -8
  726. package/src/root-context.tsx +40 -0
  727. package/src/root.ts +83 -0
  728. package/src/stores/activity-state.ts +295 -0
  729. package/src/stores/activity-store.ts +11 -285
  730. package/src/stores/chat-state.ts +795 -0
  731. package/src/stores/chat-store.ts +11 -705
  732. package/src/stores/connection-state.ts +78 -0
  733. package/src/stores/connection-store.ts +11 -76
  734. package/src/stores/create-stores.ts +31 -0
  735. package/src/stores/file-state.ts +399 -0
  736. package/src/stores/file-store.ts +9 -390
  737. package/src/stores/graph-state.ts +368 -0
  738. package/src/stores/graph-store.ts +10 -355
  739. package/src/stores/mask-state.ts +30 -0
  740. package/src/stores/mask-store.ts +10 -27
  741. package/src/stores/principal-state.ts +42 -0
  742. package/src/stores/principal-store.ts +10 -37
  743. package/src/stores/provider-state.ts +103 -0
  744. package/src/stores/provider-store.ts +10 -95
  745. package/src/stores/share-state.ts +56 -0
  746. package/src/stores/share-store.ts +11 -54
  747. package/src/stores/store-environment.ts +10 -0
  748. package/src/stores/ui-state.ts +143 -0
  749. package/src/stores/ui-store.ts +11 -93
  750. package/src/styles.css +4 -1
  751. package/src/theme.css +150 -97
  752. package/src/voice/asr-clients.ts +17 -17
  753. package/src/voice/use-dictation.ts +11 -8
  754. package/src/voice/voice-state.ts +57 -0
  755. package/src/voice/voice-store.ts +11 -55
@@ -1,198 +1,260 @@
1
- import { uiConfig } from "../../config.js";
2
- import { useState, useEffect, useRef, useMemo } from "react";
1
+ /**
2
+ * The `ask_user` exchange, one kit `AskUserCard` per question (D38 §1).
3
+ *
4
+ * An exchange is not a tool card. It has four states and all four stay in
5
+ * the transcript at full contrast — nothing rolls up or fades, because a
6
+ * question the agent asked is part of the record whichever way it was
7
+ * answered:
8
+ *
9
+ * `pending` — the options, one focus stop, Submit / Dismiss. "Other"
10
+ * opens the kit's free-text field in place of the Submit row:
11
+ * a typed alternative is the same exchange, not a new one.
12
+ * `answered` — the chosen answer in mono teal, with when. The alternatives
13
+ * are GONE, not dimmed: they were never the record. A
14
+ * multi-select lists every choice as its own row.
15
+ * `typed` — the user answered in the composer instead. The card quotes
16
+ * what it took, under a neutral border.
17
+ * `dismissed` — the question the turn outlived, in gold (seventh drop,
18
+ * ruling 7): no options, a lapsed row stating the fact, and
19
+ * "Ask again". The server-side request is already resolved,
20
+ * so asking again reopens the card LOCALLY to pending, and a
21
+ * submit from a reopened card goes out as a normal composer
22
+ * message quoting the question and the chosen answer(s)
23
+ * (`onReask`) rather than as an `ask_user_response` nobody is
24
+ * waiting for. No `onReask`, no button (D20).
25
+ *
26
+ * Multi-select questions ride the same kit card with `multi` (ruling 6): the
27
+ * options are `ChoiceOption multiple` — checkbox role, square mark — inside a
28
+ * `role="group"`, and "Other" toggles like any other row. The exchange's
29
+ * answers are keyed by question text and submitted together, so the action
30
+ * row sits on the LAST question's card and gathers every question's
31
+ * selection.
32
+ */
33
+
34
+ import { useBrainUiRoot } from "../../root-context.js";
35
+ import { useEffect, useRef, useState } from "react";
3
36
  import {
4
- Check,
5
- X,
6
- MessageCircleQuestion,
7
- ChevronRight,
8
- ChevronUp,
9
- } from "lucide-react";
37
+ AskUserCard as KitAskUserCard,
38
+ Surface,
39
+ type AskUserOption as KitAskUserOption,
40
+ } from "@schlessera/brain-ui-kit";
10
41
  import type {
11
42
  AskUserQuestion,
12
- AskUserOption,
13
43
  AskUserAnnotation,
14
44
  } from "@schlessera/brain-ui-sdk/protocol";
15
45
  import { BrainMarkdown } from "./brain-markdown.js";
16
- import { cn } from "../../lib/utils.js";
46
+ import { formatRelativeTime } from "../../lib/format-time.js";
47
+ import { reaskMessage } from "./ask-user-typed.js";
17
48
 
18
49
  const OTHER_LABEL = "Other";
19
50
 
51
+ /** A multi-select's picks travel as one string; this is the seam. */
52
+ const MULTI_JOIN = ", ";
53
+
20
54
  interface PerQuestionState {
21
55
  /** Picked option labels (single-select keeps only the latest). */
22
56
  selected: string[];
23
- /** Free-text content when "Other" is selected. */
57
+ /** The kit's free-text field is open in place of the Submit row. */
58
+ otherOpen: boolean;
59
+ /** A free-text answer already taken from the field (held until Submit). */
24
60
  otherText: string;
25
- /** Currently focused option index — drives the preview pane. */
26
- focusedIndex: number | null;
61
+ /** The option holding focus — the contract's `preview` follows focus, so
62
+ * ↑↓ over the options shows each one's preview before anything is picked. */
63
+ focused: string | null;
27
64
  }
28
65
 
29
66
  function defaultState(): PerQuestionState {
30
- return { selected: [], otherText: "", focusedIndex: null };
67
+ return { selected: [], otherOpen: false, otherText: "", focused: null };
68
+ }
69
+
70
+ /** The preview to show for a question: the focused option's, else the single
71
+ * chosen one's. `preview` is "content rendered when an option is focused"
72
+ * in the ask_user contract; selection is the fallback once focus has moved on. */
73
+ export function previewFor(
74
+ question: AskUserQuestion,
75
+ state: Pick<PerQuestionState, "focused" | "selected">
76
+ ): string | undefined {
77
+ const focused = state.focused ? question.options.find((o) => o.label === state.focused) : undefined;
78
+ if (focused?.preview) return focused.preview;
79
+ if (state.selected.length === 1 && state.selected[0] !== OTHER_LABEL) {
80
+ return question.options.find((o) => o.label === state.selected[0])?.preview;
81
+ }
82
+ return undefined;
83
+ }
84
+
85
+ /** The answer the exchange recorded for one question, as the card shows it. */
86
+ export function recordedAnswer(
87
+ question: AskUserQuestion,
88
+ answers: Record<string, string> | undefined
89
+ ): string {
90
+ return answers?.[question.question] ?? "";
31
91
  }
32
92
 
93
+ /**
94
+ * The recorded answer as the rows the card lists: one for a single-select,
95
+ * one per pick for a multi-select. The picks were joined by this module, so
96
+ * splitting on the same seam is the inverse of its own encoding — a label
97
+ * that itself contains ", " is the one case it cannot tell apart.
98
+ */
99
+ export function recordedAnswers(
100
+ question: AskUserQuestion,
101
+ answers: Record<string, string> | undefined
102
+ ): string[] {
103
+ const answer = recordedAnswer(question, answers);
104
+ if (!question.multiSelect) return [answer];
105
+ return answer.split(MULTI_JOIN).filter((a) => a.length > 0);
106
+ }
107
+
108
+ /** "you chose this · 3m ago", "you chose 2 · 3m ago", or without the time
109
+ * when none is known. */
110
+ export function answeredMeta(answeredAt: number | undefined, count = 1): string {
111
+ const chose = count > 1 ? `you chose ${count}` : "you chose this";
112
+ return answeredAt === undefined ? chose : `${chose} · ${formatRelativeTime(answeredAt)}`;
113
+ }
114
+
115
+ export const TYPED_META = "taken from your next message";
116
+
117
+ /** The typed answer is the user's own words, so the card quotes them. */
118
+ export function quoted(text: string): string {
119
+ return text ? `\u201C${text}\u201D` : "";
120
+ }
121
+
122
+ /** The lapsed row on a dismissed card: what happened, in the app's terms. */
123
+ export const DISMISSED_NOTE = "dismissed · the agent got no answer";
124
+
33
125
  export function AskUserCard({
34
126
  requestId,
35
127
  questions,
36
128
  answered,
37
129
  cancelled,
38
- live = false,
130
+ typed,
131
+ answeredAt,
39
132
  onSubmit,
40
133
  onCancel,
134
+ onReask,
41
135
  }: {
42
136
  requestId: string;
43
137
  questions: AskUserQuestion[];
44
138
  answered?: Record<string, string>;
45
139
  cancelled?: boolean;
46
- /** Parent message still streaming — keeps an expanded card open until it ends. */
47
- live?: boolean;
140
+ /** The answer was typed into the composer rather than chosen. */
141
+ typed?: boolean;
142
+ /** When the answer was given; absent on resumed history. */
143
+ answeredAt?: number;
48
144
  onSubmit: (
49
145
  requestId: string,
50
146
  answers: Record<string, string>,
51
147
  annotations?: Record<string, AskUserAnnotation>
52
148
  ) => void;
53
149
  onCancel: (requestId: string) => void;
150
+ /**
151
+ * A dismissed question asked again: the answer goes out as a normal
152
+ * composer message, because the server already resolved the request.
153
+ * Absent, the dismissed card offers no "Ask again".
154
+ */
155
+ onReask?: (text: string) => void;
54
156
  }) {
157
+ const root = useBrainUiRoot();
158
+ const prompt = `${root.config.assistantName} needs your input`;
55
159
 
56
- // Independent per-question state
57
160
  const [state, setState] = useState<PerQuestionState[]>(() =>
58
161
  questions.map(() => defaultState())
59
162
  );
163
+ // "Ask again" on a dismissed card: pending again, locally.
164
+ const [reopened, setReopened] = useState(false);
60
165
 
61
- // Once answered/dismissed, the card rolls up to a one-line summary that
62
- // scrolls away with the rest of the turn. It stays open while unanswered
63
- // (it's an active prompt) and re-collapses when the streaming turn ends.
64
- const [collapsed, setCollapsed] = useState(true);
65
- const prevLive = useRef(live);
66
- useEffect(() => {
67
- if (prevLive.current && !live) setCollapsed(true);
68
- prevLive.current = live;
69
- }, [live]);
70
-
71
- // Re-initialise if the question set changes (new requestId arriving)
166
+ // Re-initialise if the question set changes (new requestId arriving).
72
167
  const lastRequestId = useRef(requestId);
73
168
  useEffect(() => {
74
169
  if (lastRequestId.current !== requestId) {
75
170
  lastRequestId.current = requestId;
76
171
  setState(questions.map(() => defaultState()));
172
+ setReopened(false);
77
173
  }
78
174
  }, [requestId, questions]);
79
175
 
80
- // If we already have answers (from prior submit), force-fill state for display
81
- const lockedAnswers = answered ?? null;
82
- const isLocked = !!lockedAnswers || !!cancelled;
176
+ const dismissed = !!cancelled && !answered && !reopened;
177
+ const isLocked = !!answered || dismissed;
83
178
 
84
- const filledState = useMemo<PerQuestionState[]>(() => {
85
- if (!lockedAnswers) return state;
86
- return questions.map((q) => {
87
- const raw = lockedAnswers[q.question] ?? "";
88
- const labels = q.multiSelect
89
- ? raw
90
- .split(",")
91
- .map((s) => s.trim())
92
- .filter(Boolean)
93
- : raw
94
- ? [raw]
95
- : [];
96
- // If the saved label isn't a known option, treat as "Other"
97
- const knownLabels = new Set(q.options.map((o) => o.label));
98
- const selected = labels.filter((l) => knownLabels.has(l));
99
- const otherLabels = labels.filter((l) => !knownLabels.has(l));
100
- const finalSelected = otherLabels.length
101
- ? [...selected, OTHER_LABEL]
102
- : selected;
103
- return {
104
- selected: finalSelected,
105
- otherText: otherLabels.join(", "),
106
- focusedIndex: null,
107
- };
108
- });
109
- }, [lockedAnswers, questions, state]);
110
-
111
- // Collapsed once locked: a compact, expandable summary that behaves like a
112
- // finished tool-timeline row instead of a full card pinned in place.
113
- if (isLocked && collapsed) {
114
- return (
115
- <AskUserSummaryRow
116
- questions={questions}
117
- answers={lockedAnswers}
118
- cancelled={!!cancelled}
119
- onExpand={() => setCollapsed(false)}
120
- />
121
- );
122
- }
123
-
124
- function toggleOption(qi: number, label: string) {
179
+ function pick(qi: number, label: string) {
125
180
  if (isLocked) return;
126
- setState((prev) => {
127
- const next = prev.map((s, i) => {
181
+ setState((prev) =>
182
+ prev.map((s, i) => {
128
183
  if (i !== qi) return s;
129
184
  const q = questions[qi];
130
- if (q.multiSelect) {
131
- const has = s.selected.includes(label);
132
- return {
133
- ...s,
134
- selected: has
135
- ? s.selected.filter((l) => l !== label)
136
- : [...s.selected, label],
137
- };
185
+ if (label === OTHER_LABEL) {
186
+ // Multi-select: Other toggles like any other row, and opens the
187
+ // field while it is on; single-select: it is the pick.
188
+ if (q.multiSelect) {
189
+ const on = !s.selected.includes(OTHER_LABEL);
190
+ return { ...s, selected: toggled(s.selected, OTHER_LABEL), otherOpen: on };
191
+ }
192
+ return { ...s, otherOpen: true, selected: [OTHER_LABEL] };
138
193
  }
194
+ // Multi-select: Other stays open while it is on — picking another
195
+ // row beside it must not close the field and strand an empty custom
196
+ // answer. Single-select: any other pick replaces Other.
139
197
  return {
140
198
  ...s,
141
- selected: s.selected[0] === label ? [] : [label],
199
+ otherOpen: q.multiSelect ? s.selected.includes(OTHER_LABEL) : false,
200
+ selected: q.multiSelect
201
+ ? toggled(s.selected, label)
202
+ : s.selected[0] === label
203
+ ? []
204
+ : [label],
142
205
  };
143
- });
144
- return next;
145
- });
206
+ })
207
+ );
146
208
  }
147
209
 
148
- function setFocus(qi: number, idx: number | null) {
149
- if (isLocked) return;
150
- setState((prev) =>
151
- prev.map((s, i) => (i === qi ? { ...s, focusedIndex: idx } : s))
152
- );
210
+ function focus(qi: number, label: string | null) {
211
+ setState((prev) => prev.map((s, i) => (i === qi ? { ...s, focused: label } : s)));
153
212
  }
154
213
 
155
- function setOtherText(qi: number, text: string) {
156
- if (isLocked) return;
157
- setState((prev) =>
158
- prev.map((s, i) => (i === qi ? { ...s, otherText: text } : s))
214
+ function answerFor(s: PerQuestionState): string[] {
215
+ return s.selected.flatMap((label) =>
216
+ label === OTHER_LABEL ? (s.otherText.trim() ? [s.otherText.trim()] : []) : [label]
159
217
  );
160
218
  }
161
219
 
162
- const canSubmit = !isLocked && questions.every((_q, i) => {
163
- const s = state[i];
164
- if (s.selected.length === 0) return false;
165
- if (s.selected.includes(OTHER_LABEL) && !s.otherText.trim()) return false;
166
- return true;
167
- });
220
+ const complete = questions.every((_q, i) => answerFor(state[i]).length > 0);
168
221
 
169
- function handleSubmit() {
170
- if (!canSubmit) return;
222
+ function submit(override?: { qi: number; text: string }) {
171
223
  const answers: Record<string, string> = {};
172
224
  const annotations: Record<string, AskUserAnnotation> = {};
173
225
  for (let i = 0; i < questions.length; i++) {
174
226
  const q = questions[i];
175
- const s = state[i];
176
- const labels: string[] = [];
177
- let usedOther = false;
178
- for (const sel of s.selected) {
179
- if (sel === OTHER_LABEL) {
180
- if (s.otherText.trim()) labels.push(s.otherText.trim());
181
- usedOther = true;
182
- } else {
183
- labels.push(sel);
184
- }
185
- }
186
- answers[q.question] = q.multiSelect ? labels.join(", ") : (labels[0] ?? "");
227
+ const s =
228
+ override && override.qi === i
229
+ ? {
230
+ ...state[i],
231
+ // A multi-select keeps its other picks beside the typed one.
232
+ selected: q.multiSelect
233
+ ? state[i].selected.includes(OTHER_LABEL)
234
+ ? state[i].selected
235
+ : [...state[i].selected, OTHER_LABEL]
236
+ : [OTHER_LABEL],
237
+ otherText: override.text,
238
+ }
239
+ : state[i];
240
+ const labels = answerFor(s);
241
+ if (labels.length === 0) return;
242
+ answers[q.question] = q.multiSelect ? labels.join(MULTI_JOIN) : labels[0];
187
243
 
188
- // Capture preview from a single non-other selection for annotations
189
- if (!usedOther && !q.multiSelect && s.selected.length === 1) {
244
+ // A single chosen option with a preview travels as an annotation, so
245
+ // the agent sees what the user saw.
246
+ if (!q.multiSelect && s.selected.length === 1 && s.selected[0] !== OTHER_LABEL) {
190
247
  const picked = q.options.find((o) => o.label === s.selected[0]);
191
- if (picked?.preview) {
192
- annotations[q.question] = { preview: picked.preview };
193
- }
248
+ if (picked?.preview) annotations[q.question] = { preview: picked.preview };
194
249
  }
195
250
  }
251
+ if (reopened) {
252
+ // The request is gone server-side; the answer is a message now — and
253
+ // the card closes again, or Submit would send it twice.
254
+ onReask?.(reaskMessage(questions, answers));
255
+ setReopened(false);
256
+ return;
257
+ }
196
258
  onSubmit(
197
259
  requestId,
198
260
  answers,
@@ -200,252 +262,126 @@ export function AskUserCard({
200
262
  );
201
263
  }
202
264
 
203
- function handleCancel() {
204
- onCancel(requestId);
265
+ /**
266
+ * The kit's Other field submitted. With one question that IS the answer;
267
+ * with several, the text is held for that question and the last card's
268
+ * Submit sends everything together.
269
+ */
270
+ function takeOther(qi: number, text: string) {
271
+ const trimmed = text.trim();
272
+ if (!trimmed || isLocked) return;
273
+ if (questions.length === 1) {
274
+ submit({ qi, text: trimmed });
275
+ return;
276
+ }
277
+ setState((prev) =>
278
+ prev.map((s, i) => (i === qi ? { ...s, otherOpen: false, otherText: trimmed } : s))
279
+ );
205
280
  }
206
281
 
207
282
  return (
208
- <div className="rounded-xl border border-accent/30 bg-surface px-4 py-4 shadow-[0_0_0_1px_rgba(91,181,162,0.08)]">
209
- <div className="mb-3 flex items-center gap-2 text-xs uppercase tracking-wider text-accent/80">
210
- <MessageCircleQuestion className="h-3.5 w-3.5" />
211
- <span className="font-[family-name:var(--font-mono)]">
212
- {isLocked
213
- ? cancelled
214
- ? "Dismissed"
215
- : "You answered"
216
- : `${uiConfig.assistantName} needs your input`}
217
- </span>
218
- {isLocked && (
219
- <button
220
- type="button"
221
- onClick={() => setCollapsed(true)}
222
- className="ml-auto flex items-center gap-1 text-[11px] normal-case tracking-normal text-muted-foreground/50 transition-colors hover:text-muted-foreground"
223
- >
224
- <ChevronUp className="h-3 w-3" />
225
- Collapse
226
- </button>
227
- )}
228
- </div>
283
+ <div className="space-y-3">
284
+ {questions.map((q, qi) => {
285
+ const isLast = qi === questions.length - 1;
286
+ const id = `${requestId}-${qi}`;
287
+
288
+ if (answered) {
289
+ const answers = recordedAnswers(q, answered);
290
+ return (
291
+ <KitAskUserCard
292
+ key={id}
293
+ id={id}
294
+ state={typed ? "typed" : "answered"}
295
+ multi={q.multiSelect}
296
+ tag={q.header}
297
+ question={q.question}
298
+ options={[]}
299
+ showActions={false}
300
+ // The kit prints the answers as given; a typed one is a quote.
301
+ answers={typed ? [quoted(recordedAnswer(q, answered))] : answers}
302
+ answerMeta={typed ? TYPED_META : answeredMeta(answeredAt, answers.length)}
303
+ />
304
+ );
305
+ }
306
+
307
+ if (dismissed) {
308
+ return (
309
+ <KitAskUserCard
310
+ key={id}
311
+ id={id}
312
+ state="dismissed"
313
+ multi={q.multiSelect}
314
+ tag={q.header}
315
+ question={q.question}
316
+ options={[]}
317
+ showActions={false}
318
+ lapsedNote={DISMISSED_NOTE}
319
+ // One "Ask again" per exchange, on the last card, like Submit.
320
+ onAskAgain={onReask && isLast ? () => setReopened(true) : undefined}
321
+ />
322
+ );
323
+ }
324
+
325
+ const s = state[qi];
326
+ const preview = previewFor(q, s);
229
327
 
230
- <div className="space-y-5">
231
- {questions.map((q, qi) => (
232
- <QuestionBlock
233
- key={qi}
234
- question={q}
235
- state={filledState[qi]}
236
- locked={isLocked}
237
- onToggleOption={(label) => toggleOption(qi, label)}
238
- onFocus={(idx) => setFocus(qi, idx)}
239
- onOtherChange={(t) => setOtherText(qi, t)}
240
- />
241
- ))}
242
- </div>
328
+ const options: KitAskUserOption[] = [
329
+ ...q.options.map((o) => ({
330
+ title: o.label,
331
+ subtitle: o.description,
332
+ selected: s.selected.includes(o.label),
333
+ onClick: () => pick(qi, o.label),
334
+ onFocus: () => focus(qi, o.label),
335
+ })),
336
+ {
337
+ title: OTHER_LABEL,
338
+ subtitle: s.otherText || "Provide a custom answer.",
339
+ italic: !s.otherText,
340
+ dim: !s.otherText,
341
+ selected: s.selected.includes(OTHER_LABEL),
342
+ onClick: () => pick(qi, OTHER_LABEL),
343
+ onFocus: () => focus(qi, null),
344
+ },
345
+ ];
243
346
 
244
- {!isLocked && (
245
- <div className="mt-4 flex items-center justify-end gap-2">
246
- <button
247
- type="button"
248
- onClick={handleCancel}
249
- className="flex items-center gap-1.5 rounded-lg border border-border px-3 py-1.5 text-xs text-muted-foreground transition-colors hover:bg-surface-raised hover:text-foreground"
250
- >
251
- <X className="h-3.5 w-3.5" />
252
- Dismiss
253
- </button>
254
- <button
255
- type="button"
256
- onClick={handleSubmit}
257
- disabled={!canSubmit}
258
- className={cn(
259
- "flex items-center gap-1.5 rounded-lg px-4 py-1.5 text-xs font-medium transition-all",
260
- canSubmit
261
- ? "bg-accent text-accent-foreground hover:brightness-110"
262
- : "bg-surface-raised text-muted-foreground/40 cursor-not-allowed"
263
- )}
264
- >
265
- <Check className="h-3.5 w-3.5" />
266
- Submit
267
- </button>
268
- </div>
269
- )}
347
+ return (
348
+ <div key={id} className="space-y-2">
349
+ <KitAskUserCard
350
+ id={id}
351
+ state="pending"
352
+ multi={q.multiSelect}
353
+ prompt={prompt}
354
+ tag={q.header}
355
+ question={q.question}
356
+ options={options}
357
+ otherOpen={s.otherOpen}
358
+ otherPlaceholder="Type your answer…"
359
+ onOtherSubmit={(text) => takeOther(qi, text)}
360
+ showActions={isLast}
361
+ // The kit's action row cannot be disabled from here; an
362
+ // incomplete Submit is a no-op rather than a partial answer.
363
+ onPrimary={() => (complete ? submit() : undefined)}
364
+ // A reopened card's Dismiss closes it again locally: there is
365
+ // no server-side request left to cancel.
366
+ onSecondary={() => (reopened ? setReopened(false) : onCancel(requestId))}
367
+ />
368
+ {preview ? <PreviewPane content={preview} /> : null}
369
+ </div>
370
+ );
371
+ })}
270
372
  </div>
271
373
  );
272
374
  }
273
375
 
274
- /** One-line, expandable stand-in for an answered/dismissed question. */
275
- function AskUserSummaryRow({
276
- questions,
277
- answers,
278
- cancelled,
279
- onExpand,
280
- }: {
281
- questions: AskUserQuestion[];
282
- answers: Record<string, string> | null;
283
- cancelled: boolean;
284
- onExpand: () => void;
285
- }) {
286
- const detail = cancelled
287
- ? "Dismissed"
288
- : questions
289
- .map((q) => {
290
- const a = answers?.[q.question];
291
- return a ? `${q.header}: ${a}` : q.header;
292
- })
293
- .join(" · ");
294
- return (
295
- <button
296
- type="button"
297
- onClick={onExpand}
298
- className="flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-xs text-muted-foreground/70 transition-colors hover:text-foreground"
299
- >
300
- <MessageCircleQuestion className="h-3.5 w-3.5 shrink-0 text-accent/70" />
301
- <span className="min-w-0 truncate font-[family-name:var(--font-mono)]">
302
- {!cancelled && <span className="text-accent/70">Answered · </span>}
303
- {detail}
304
- </span>
305
- <ChevronRight className="h-3 w-3 shrink-0" />
306
- </button>
307
- );
376
+ function toggled(list: string[], label: string): string[] {
377
+ return list.includes(label) ? list.filter((l) => l !== label) : [...list, label];
308
378
  }
309
379
 
310
- function QuestionBlock({
311
- question,
312
- state,
313
- locked,
314
- onToggleOption,
315
- onFocus,
316
- onOtherChange,
317
- }: {
318
- question: AskUserQuestion;
319
- state: PerQuestionState;
320
- locked: boolean;
321
- onToggleOption: (label: string) => void;
322
- onFocus: (idx: number | null) => void;
323
- onOtherChange: (text: string) => void;
324
- }) {
325
- const optionsWithOther: Array<AskUserOption & { isOther?: boolean }> = [
326
- ...question.options,
327
- { label: OTHER_LABEL, description: "Provide a custom answer.", isOther: true },
328
- ];
329
-
330
- const focusedOption =
331
- state.focusedIndex !== null ? optionsWithOther[state.focusedIndex] : null;
332
- const previewToShow =
333
- focusedOption?.preview ??
334
- (state.selected.length === 1 && !state.selected.includes(OTHER_LABEL)
335
- ? question.options.find((o) => o.label === state.selected[0])?.preview
336
- : undefined);
337
-
380
+ /** The focused (else chosen) option's preview, under the question it belongs to. */
381
+ function PreviewPane({ content }: { content: string }) {
338
382
  return (
339
- <div>
340
- <div className="mb-2 flex items-center gap-2">
341
- <span className="rounded-md border border-accent/30 bg-accent/10 px-2 py-0.5 font-[family-name:var(--font-mono)] text-[10px] uppercase tracking-wider text-accent">
342
- {question.header}
343
- </span>
344
- {question.multiSelect && (
345
- <span className="text-[10px] uppercase tracking-wider text-muted-foreground/60">
346
- multi-select
347
- </span>
348
- )}
349
- </div>
350
- <div className="mb-3 text-sm leading-relaxed text-foreground">
351
- {question.question}
352
- </div>
353
-
354
- <div className="grid gap-2 md:grid-cols-[minmax(0,1fr)_minmax(0,1fr)]">
355
- <ul className="space-y-1.5">
356
- {optionsWithOther.map((opt, idx) => {
357
- const selected = state.selected.includes(opt.label);
358
- return (
359
- <li key={opt.label}>
360
- <button
361
- type="button"
362
- onClick={() => onToggleOption(opt.label)}
363
- onMouseEnter={() => onFocus(idx)}
364
- onFocus={() => onFocus(idx)}
365
- disabled={locked}
366
- className={cn(
367
- "group flex w-full items-start gap-2 rounded-lg border px-3 py-2 text-left transition-colors",
368
- selected
369
- ? "border-accent/60 bg-accent/10"
370
- : "border-border bg-background hover:bg-surface-raised",
371
- locked && "cursor-default opacity-90"
372
- )}
373
- >
374
- <span
375
- className={cn(
376
- "mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded border",
377
- question.multiSelect ? "rounded-sm" : "rounded-full",
378
- selected
379
- ? "border-accent bg-accent text-accent-foreground"
380
- : "border-border bg-background"
381
- )}
382
- >
383
- {selected && <Check className="h-3 w-3" />}
384
- </span>
385
- <span className="min-w-0 flex-1">
386
- <span
387
- className={cn(
388
- "block text-sm font-medium",
389
- opt.isOther
390
- ? "italic text-muted-foreground group-hover:text-foreground"
391
- : "text-foreground"
392
- )}
393
- >
394
- {opt.label}
395
- </span>
396
- {opt.description && (
397
- <span className="block text-xs leading-snug text-muted-foreground">
398
- {opt.description}
399
- </span>
400
- )}
401
- </span>
402
- </button>
403
- {opt.isOther && state.selected.includes(OTHER_LABEL) && (
404
- <textarea
405
- value={state.otherText}
406
- onChange={(e) => onOtherChange(e.target.value)}
407
- disabled={locked}
408
- placeholder="Type your answer..."
409
- rows={2}
410
- className="mt-1.5 w-full resize-none rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground/40 focus:border-accent/60 focus:outline-none"
411
- />
412
- )}
413
- </li>
414
- );
415
- })}
416
- </ul>
417
-
418
- {previewToShow && (
419
- <div className="hidden min-w-0 md:block">
420
- <div className="rounded-lg border border-border bg-background p-3">
421
- <div className="mb-1 text-[10px] uppercase tracking-wider text-muted-foreground/60 font-[family-name:var(--font-mono)]">
422
- Preview
423
- </div>
424
- <BrainMarkdown
425
- content={previewToShow}
426
- className="brain-prose text-xs"
427
- />
428
- </div>
429
- </div>
430
- )}
431
- </div>
432
-
433
- {/* Mobile preview drops below the options when a preview exists */}
434
- {previewToShow && (
435
- <div className="mt-2 md:hidden">
436
- <details className="rounded-lg border border-border bg-background">
437
- <summary className="cursor-pointer px-3 py-2 text-[11px] uppercase tracking-wider text-muted-foreground">
438
- Preview
439
- </summary>
440
- <div className="border-t border-border px-3 py-2">
441
- <BrainMarkdown
442
- content={previewToShow}
443
- className="brain-prose text-xs"
444
- />
445
- </div>
446
- </details>
447
- </div>
448
- )}
449
- </div>
383
+ <Surface label="Preview" labelIcon="file" pad={10}>
384
+ <BrainMarkdown content={content} className="brain-prose text-xs" />
385
+ </Surface>
450
386
  );
451
387
  }