@schlessera/brain-ui-react 0.34.1 → 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 (763) hide show
  1. package/README.md +89 -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 +55 -40
  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 +15 -4
  136. package/dist/components/chat/tool-views.d.ts.map +1 -1
  137. package/dist/components/chat/tool-views.js +22 -38
  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 +64 -6
  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 +5 -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 +66 -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 +48 -19
  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 +42 -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 +10 -0
  312. package/dist/components/settings/devices-agents-tab.d.ts.map +1 -0
  313. package/dist/components/settings/devices-agents-tab.js +131 -0
  314. package/dist/components/settings/devices-agents-tab.js.map +1 -0
  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.d.ts +3 -0
  324. package/dist/components/settings/one-time-agent-credential.d.ts.map +1 -0
  325. package/dist/components/settings/one-time-agent-credential.js +55 -0
  326. package/dist/components/settings/one-time-agent-credential.js.map +1 -0
  327. package/dist/components/settings/passkey-list.d.ts +35 -0
  328. package/dist/components/settings/passkey-list.d.ts.map +1 -0
  329. package/dist/components/settings/passkey-list.js +34 -0
  330. package/dist/components/settings/passkey-list.js.map +1 -0
  331. package/dist/components/settings/passkey-tab.d.ts +3 -0
  332. package/dist/components/settings/passkey-tab.d.ts.map +1 -1
  333. package/dist/components/settings/passkey-tab.js +53 -45
  334. package/dist/components/settings/passkey-tab.js.map +1 -1
  335. package/dist/components/settings/pi-accounts-list.d.ts +27 -0
  336. package/dist/components/settings/pi-accounts-list.d.ts.map +1 -0
  337. package/dist/components/settings/pi-accounts-list.js +15 -0
  338. package/dist/components/settings/pi-accounts-list.js.map +1 -0
  339. package/dist/components/settings/pi-accounts.d.ts +3 -0
  340. package/dist/components/settings/pi-accounts.d.ts.map +1 -1
  341. package/dist/components/settings/pi-accounts.js +73 -55
  342. package/dist/components/settings/pi-accounts.js.map +1 -1
  343. package/dist/components/settings/principal-list.d.ts +37 -0
  344. package/dist/components/settings/principal-list.d.ts.map +1 -0
  345. package/dist/components/settings/principal-list.js +18 -0
  346. package/dist/components/settings/principal-list.js.map +1 -0
  347. package/dist/components/settings/settings-panel.d.ts +10 -3
  348. package/dist/components/settings/settings-panel.d.ts.map +1 -1
  349. package/dist/components/settings/settings-panel.js +80 -6
  350. package/dist/components/settings/settings-panel.js.map +1 -1
  351. package/dist/components/settings/skills-list.d.ts +53 -0
  352. package/dist/components/settings/skills-list.d.ts.map +1 -0
  353. package/dist/components/settings/skills-list.js +28 -0
  354. package/dist/components/settings/skills-list.js.map +1 -0
  355. package/dist/components/settings/skills-tab.d.ts.map +1 -1
  356. package/dist/components/settings/skills-tab.js +65 -38
  357. package/dist/components/settings/skills-tab.js.map +1 -1
  358. package/dist/components/settings/tool-permissions-list.d.ts +18 -0
  359. package/dist/components/settings/tool-permissions-list.d.ts.map +1 -0
  360. package/dist/components/settings/tool-permissions-list.js +6 -0
  361. package/dist/components/settings/tool-permissions-list.js.map +1 -0
  362. package/dist/components/settings/tool-permissions.d.ts +2 -1
  363. package/dist/components/settings/tool-permissions.d.ts.map +1 -1
  364. package/dist/components/settings/tool-permissions.js +33 -16
  365. package/dist/components/settings/tool-permissions.js.map +1 -1
  366. package/dist/components/settings/web-search-chain.d.ts +41 -0
  367. package/dist/components/settings/web-search-chain.d.ts.map +1 -0
  368. package/dist/components/settings/web-search-chain.js +47 -0
  369. package/dist/components/settings/web-search-chain.js.map +1 -0
  370. package/dist/components/settings/web-search-settings.d.ts +4 -7
  371. package/dist/components/settings/web-search-settings.d.ts.map +1 -1
  372. package/dist/components/settings/web-search-settings.js +54 -76
  373. package/dist/components/settings/web-search-settings.js.map +1 -1
  374. package/dist/components/share/share-menu.d.ts.map +1 -1
  375. package/dist/components/share/share-menu.js +24 -4
  376. package/dist/components/share/share-menu.js.map +1 -1
  377. package/dist/components/voice/dictation-sheet.js +3 -3
  378. package/dist/components/voice/dictation-sheet.js.map +1 -1
  379. package/dist/components/voice/mic-button.js +1 -1
  380. package/dist/components/voice/mic-button.js.map +1 -1
  381. package/dist/components/voice/review-card.js +1 -1
  382. package/dist/components/voice/review-card.js.map +1 -1
  383. package/dist/config.d.ts +5 -2
  384. package/dist/config.d.ts.map +1 -1
  385. package/dist/config.js +15 -5
  386. package/dist/config.js.map +1 -1
  387. package/dist/connection.d.ts +12 -0
  388. package/dist/connection.d.ts.map +1 -0
  389. package/dist/connection.js +421 -0
  390. package/dist/connection.js.map +1 -0
  391. package/dist/default-root.d.ts +3 -0
  392. package/dist/default-root.d.ts.map +1 -0
  393. package/dist/default-root.js +16 -0
  394. package/dist/default-root.js.map +1 -0
  395. package/dist/hooks/use-color-scheme.d.ts +14 -0
  396. package/dist/hooks/use-color-scheme.d.ts.map +1 -0
  397. package/dist/hooks/use-color-scheme.js +37 -0
  398. package/dist/hooks/use-color-scheme.js.map +1 -0
  399. package/dist/hooks/use-hash-routes.d.ts.map +1 -1
  400. package/dist/hooks/use-hash-routes.js +4 -2
  401. package/dist/hooks/use-hash-routes.js.map +1 -1
  402. package/dist/hooks/use-media-query.d.ts +7 -0
  403. package/dist/hooks/use-media-query.d.ts.map +1 -0
  404. package/dist/hooks/use-media-query.js +34 -0
  405. package/dist/hooks/use-media-query.js.map +1 -0
  406. package/dist/hooks/use-share-intake.d.ts.map +1 -1
  407. package/dist/hooks/use-share-intake.js +37 -12
  408. package/dist/hooks/use-share-intake.js.map +1 -1
  409. package/dist/hooks/use-vpn-status.d.ts +1 -1
  410. package/dist/hooks/use-vpn-status.d.ts.map +1 -1
  411. package/dist/hooks/use-vpn-status.js +20 -16
  412. package/dist/hooks/use-vpn-status.js.map +1 -1
  413. package/dist/hooks/use-websocket.d.ts +5 -24
  414. package/dist/hooks/use-websocket.d.ts.map +1 -1
  415. package/dist/hooks/use-websocket.js +11 -382
  416. package/dist/hooks/use-websocket.js.map +1 -1
  417. package/dist/hooks/websocket-handlers/activity.d.ts +2 -2
  418. package/dist/hooks/websocket-handlers/activity.d.ts.map +1 -1
  419. package/dist/hooks/websocket-handlers/activity.js +4 -5
  420. package/dist/hooks/websocket-handlers/activity.js.map +1 -1
  421. package/dist/hooks/websocket-handlers/chat.d.ts +1 -0
  422. package/dist/hooks/websocket-handlers/chat.d.ts.map +1 -1
  423. package/dist/hooks/websocket-handlers/chat.js +27 -5
  424. package/dist/hooks/websocket-handlers/chat.js.map +1 -1
  425. package/dist/hooks/websocket-handlers/connection.d.ts.map +1 -1
  426. package/dist/hooks/websocket-handlers/connection.js +4 -6
  427. package/dist/hooks/websocket-handlers/connection.js.map +1 -1
  428. package/dist/hooks/websocket-handlers/mask.d.ts +1 -1
  429. package/dist/hooks/websocket-handlers/mask.d.ts.map +1 -1
  430. package/dist/hooks/websocket-handlers/mask.js +2 -3
  431. package/dist/hooks/websocket-handlers/mask.js.map +1 -1
  432. package/dist/hooks/websocket-handlers/provider.d.ts.map +1 -1
  433. package/dist/hooks/websocket-handlers/provider.js +4 -6
  434. package/dist/hooks/websocket-handlers/provider.js.map +1 -1
  435. package/dist/hooks/websocket-handlers/types.d.ts +6 -2
  436. package/dist/hooks/websocket-handlers/types.d.ts.map +1 -1
  437. package/dist/index.d.ts +5 -3
  438. package/dist/index.d.ts.map +1 -1
  439. package/dist/index.js +6 -3
  440. package/dist/index.js.map +1 -1
  441. package/dist/lib/api-client.d.ts +321 -0
  442. package/dist/lib/api-client.d.ts.map +1 -1
  443. package/dist/lib/api-client.js +243 -213
  444. package/dist/lib/api-client.js.map +1 -1
  445. package/dist/lib/backend.d.ts +19 -2
  446. package/dist/lib/backend.d.ts.map +1 -1
  447. package/dist/lib/backend.js +15 -9
  448. package/dist/lib/backend.js.map +1 -1
  449. package/dist/lib/diff.d.ts +8 -10
  450. package/dist/lib/diff.d.ts.map +1 -1
  451. package/dist/lib/diff.js +26 -53
  452. package/dist/lib/diff.js.map +1 -1
  453. package/dist/lib/format-time.d.ts +3 -0
  454. package/dist/lib/format-time.d.ts.map +1 -0
  455. package/dist/lib/format-time.js +25 -0
  456. package/dist/lib/format-time.js.map +1 -0
  457. package/dist/lib/light-dark.d.ts +37 -0
  458. package/dist/lib/light-dark.d.ts.map +1 -0
  459. package/dist/lib/light-dark.js +83 -0
  460. package/dist/lib/light-dark.js.map +1 -0
  461. package/dist/lib/mermaid-theme.d.ts +7 -2
  462. package/dist/lib/mermaid-theme.d.ts.map +1 -1
  463. package/dist/lib/mermaid-theme.js +125 -203
  464. package/dist/lib/mermaid-theme.js.map +1 -1
  465. package/dist/lib/passkeys.d.ts +6 -3
  466. package/dist/lib/passkeys.d.ts.map +1 -1
  467. package/dist/lib/passkeys.js +10 -4
  468. package/dist/lib/passkeys.js.map +1 -1
  469. package/dist/lib/push-registration.d.ts +10 -0
  470. package/dist/lib/push-registration.d.ts.map +1 -0
  471. package/dist/lib/push-registration.js +44 -0
  472. package/dist/lib/push-registration.js.map +1 -0
  473. package/dist/lib/share-intake.d.ts +2 -1
  474. package/dist/lib/share-intake.d.ts.map +1 -1
  475. package/dist/lib/share-intake.js +3 -3
  476. package/dist/lib/share-intake.js.map +1 -1
  477. package/dist/lib/share.d.ts +4 -3
  478. package/dist/lib/share.d.ts.map +1 -1
  479. package/dist/lib/share.js +6 -7
  480. package/dist/lib/share.js.map +1 -1
  481. package/dist/lib/single-key.d.ts +30 -0
  482. package/dist/lib/single-key.d.ts.map +1 -0
  483. package/dist/lib/single-key.js +45 -0
  484. package/dist/lib/single-key.js.map +1 -0
  485. package/dist/lib/tool-names.d.ts +8 -6
  486. package/dist/lib/tool-names.d.ts.map +1 -1
  487. package/dist/lib/tool-names.js +17 -7
  488. package/dist/lib/tool-names.js.map +1 -1
  489. package/dist/root-context.d.ts +229 -0
  490. package/dist/root-context.d.ts.map +1 -0
  491. package/dist/root-context.js +33 -0
  492. package/dist/root-context.js.map +1 -0
  493. package/dist/root.d.ts +38 -0
  494. package/dist/root.d.ts.map +1 -0
  495. package/dist/root.js +47 -0
  496. package/dist/root.js.map +1 -0
  497. package/dist/stores/activity-state.d.ts +29 -0
  498. package/dist/stores/activity-state.d.ts.map +1 -0
  499. package/dist/stores/activity-state.js +282 -0
  500. package/dist/stores/activity-state.js.map +1 -0
  501. package/dist/stores/activity-store.d.ts +10 -41
  502. package/dist/stores/activity-store.d.ts.map +1 -1
  503. package/dist/stores/activity-store.js +9 -271
  504. package/dist/stores/activity-store.js.map +1 -1
  505. package/dist/stores/chat-state.d.ts +212 -0
  506. package/dist/stores/chat-state.d.ts.map +1 -0
  507. package/dist/stores/chat-state.js +466 -0
  508. package/dist/stores/chat-state.js.map +1 -0
  509. package/dist/stores/chat-store.d.ts +4 -162
  510. package/dist/stores/chat-store.d.ts.map +1 -1
  511. package/dist/stores/chat-store.js +7 -418
  512. package/dist/stores/chat-store.js.map +1 -1
  513. package/dist/stores/connection-state.d.ts +40 -0
  514. package/dist/stores/connection-state.d.ts.map +1 -0
  515. package/dist/stores/connection-state.js +30 -0
  516. package/dist/stores/connection-state.js.map +1 -0
  517. package/dist/stores/connection-store.d.ts +4 -40
  518. package/dist/stores/connection-store.d.ts.map +1 -1
  519. package/dist/stores/connection-store.js +7 -27
  520. package/dist/stores/connection-store.js.map +1 -1
  521. package/dist/stores/create-stores.d.ts +23 -0
  522. package/dist/stores/create-stores.d.ts.map +1 -0
  523. package/dist/stores/create-stores.js +28 -0
  524. package/dist/stores/create-stores.js.map +1 -0
  525. package/dist/stores/file-state.d.ts +53 -0
  526. package/dist/stores/file-state.d.ts.map +1 -0
  527. package/dist/stores/file-state.js +341 -0
  528. package/dist/stores/file-state.js.map +1 -0
  529. package/dist/stores/file-store.d.ts +4 -52
  530. package/dist/stores/file-store.d.ts.map +1 -1
  531. package/dist/stores/file-store.js +7 -300
  532. package/dist/stores/file-store.js.map +1 -1
  533. package/dist/stores/graph-state.d.ts +95 -0
  534. package/dist/stores/graph-state.d.ts.map +1 -0
  535. package/dist/stores/graph-state.js +252 -0
  536. package/dist/stores/graph-state.js.map +1 -0
  537. package/dist/stores/graph-store.d.ts +7 -83
  538. package/dist/stores/graph-store.d.ts.map +1 -1
  539. package/dist/stores/graph-store.js +8 -249
  540. package/dist/stores/graph-store.js.map +1 -1
  541. package/dist/stores/mask-state.d.ts +21 -0
  542. package/dist/stores/mask-state.d.ts.map +1 -0
  543. package/dist/stores/mask-state.js +9 -0
  544. package/dist/stores/mask-state.js.map +1 -0
  545. package/dist/stores/mask-store.d.ts +4 -21
  546. package/dist/stores/mask-store.d.ts.map +1 -1
  547. package/dist/stores/mask-store.js +7 -6
  548. package/dist/stores/mask-store.js.map +1 -1
  549. package/dist/stores/principal-state.d.ts +16 -0
  550. package/dist/stores/principal-state.d.ts.map +1 -0
  551. package/dist/stores/principal-state.js +31 -0
  552. package/dist/stores/principal-state.js.map +1 -0
  553. package/dist/stores/principal-store.d.ts +5 -0
  554. package/dist/stores/principal-store.d.ts.map +1 -0
  555. package/dist/stores/principal-store.js +8 -0
  556. package/dist/stores/principal-store.js.map +1 -0
  557. package/dist/stores/provider-state.d.ts +24 -0
  558. package/dist/stores/provider-state.d.ts.map +1 -0
  559. package/dist/stores/provider-state.js +68 -0
  560. package/dist/stores/provider-state.js.map +1 -0
  561. package/dist/stores/provider-store.d.ts +4 -23
  562. package/dist/stores/provider-store.d.ts.map +1 -1
  563. package/dist/stores/provider-store.js +7 -64
  564. package/dist/stores/provider-store.js.map +1 -1
  565. package/dist/stores/share-state.d.ts +29 -0
  566. package/dist/stores/share-state.d.ts.map +1 -0
  567. package/dist/stores/share-state.js +21 -0
  568. package/dist/stores/share-state.js.map +1 -0
  569. package/dist/stores/share-store.d.ts +4 -28
  570. package/dist/stores/share-store.d.ts.map +1 -1
  571. package/dist/stores/share-store.js +7 -18
  572. package/dist/stores/share-store.js.map +1 -1
  573. package/dist/stores/store-environment.d.ts +10 -0
  574. package/dist/stores/store-environment.d.ts.map +1 -0
  575. package/dist/stores/store-environment.js +2 -0
  576. package/dist/stores/store-environment.js.map +1 -0
  577. package/dist/stores/ui-state.d.ts +71 -0
  578. package/dist/stores/ui-state.d.ts.map +1 -0
  579. package/dist/stores/ui-state.js +58 -0
  580. package/dist/stores/ui-state.js.map +1 -0
  581. package/dist/stores/ui-store.d.ts +4 -45
  582. package/dist/stores/ui-store.d.ts.map +1 -1
  583. package/dist/stores/ui-store.js +7 -36
  584. package/dist/stores/ui-store.js.map +1 -1
  585. package/dist/styles.css +1 -1
  586. package/dist/theme.css +150 -97
  587. package/dist/voice/asr-clients.d.ts +2 -1
  588. package/dist/voice/asr-clients.d.ts.map +1 -1
  589. package/dist/voice/asr-clients.js +16 -17
  590. package/dist/voice/asr-clients.js.map +1 -1
  591. package/dist/voice/use-dictation.d.ts.map +1 -1
  592. package/dist/voice/use-dictation.js +12 -8
  593. package/dist/voice/use-dictation.js.map +1 -1
  594. package/dist/voice/voice-state.d.ts +25 -0
  595. package/dist/voice/voice-state.d.ts.map +1 -0
  596. package/dist/voice/voice-state.js +29 -0
  597. package/dist/voice/voice-state.js.map +1 -0
  598. package/dist/voice/voice-store.d.ts +4 -25
  599. package/dist/voice/voice-store.d.ts.map +1 -1
  600. package/dist/voice/voice-store.js +7 -26
  601. package/dist/voice/voice-store.js.map +1 -1
  602. package/package.json +3 -2
  603. package/src/components/activity/activity-page.tsx +334 -160
  604. package/src/components/activity/activity-run-detail.tsx +81 -47
  605. package/src/components/activity/activity-run-list.tsx +27 -59
  606. package/src/components/activity/activity-views.tsx +155 -0
  607. package/src/components/activity/approval-card.tsx +80 -0
  608. package/src/components/activity/digest-card.tsx +25 -61
  609. package/src/components/activity/digest-summary.tsx +52 -0
  610. package/src/components/activity/push-switch.tsx +62 -0
  611. package/src/components/activity/push-toggle.tsx +51 -81
  612. package/src/components/activity/span-bits.tsx +8 -7
  613. package/src/components/chat/ask-user-card.tsx +292 -356
  614. package/src/components/chat/ask-user-typed.ts +77 -0
  615. package/src/components/chat/brain-markdown-links.tsx +4 -4
  616. package/src/components/chat/brain-markdown.tsx +4 -2
  617. package/src/components/chat/chat-page.tsx +38 -9
  618. package/src/components/chat/composer-view.tsx +194 -0
  619. package/src/components/chat/composer.tsx +117 -296
  620. package/src/components/chat/markdown-content.tsx +53 -2
  621. package/src/components/chat/mermaid-block.tsx +13 -5
  622. package/src/components/chat/mermaid-share.ts +8 -7
  623. package/src/components/chat/mermaid-viewer.tsx +3 -1
  624. package/src/components/chat/message-bubble.tsx +78 -94
  625. package/src/components/chat/message-share.ts +7 -7
  626. package/src/components/chat/renderers/bind.tsx +94 -0
  627. package/src/components/chat/renderers/brain-ui-tools.tsx +56 -0
  628. package/src/components/chat/renderers/claude-tools.tsx +3 -2
  629. package/src/components/chat/renderers/index.ts +15 -10
  630. package/src/components/chat/session-drawer.tsx +60 -138
  631. package/src/components/chat/session-list.tsx +113 -0
  632. package/src/components/chat/share-block.tsx +16 -12
  633. package/src/components/chat/share-card.tsx +2 -2
  634. package/src/components/chat/subagent-view.tsx +4 -4
  635. package/src/components/chat/tool-call-timeline.tsx +59 -22
  636. package/src/components/chat/tool-cards/block-card.tsx +145 -0
  637. package/src/components/chat/tool-cards/image-mask-card.tsx +214 -0
  638. package/src/components/chat/tool-cards/location-card.tsx +159 -0
  639. package/src/components/chat/tool-views.tsx +23 -73
  640. package/src/components/chat/transcript-turn.tsx +108 -0
  641. package/src/components/chat/use-chat-commands.ts +14 -16
  642. package/src/components/chat/welcome-state.tsx +36 -91
  643. package/src/components/connectivity/connection-gate.tsx +80 -9
  644. package/src/components/connectivity/login-form.tsx +122 -0
  645. package/src/components/connectivity/login-screen.tsx +45 -100
  646. package/src/components/dev/share-harness.tsx +2 -2
  647. package/src/components/files/file-panel.tsx +168 -0
  648. package/src/components/files/file-tree-view.tsx +127 -0
  649. package/src/components/files/file-tree.tsx +55 -109
  650. package/src/components/files/file-viewer-binary.tsx +3 -2
  651. package/src/components/files/file-viewer-frame.tsx +113 -0
  652. package/src/components/files/file-viewer.tsx +40 -95
  653. package/src/components/files/frontmatter-chips.tsx +42 -0
  654. package/src/components/files/frontmatter-panel.tsx +6 -71
  655. package/src/components/files/staleness.ts +29 -0
  656. package/src/components/graph/graph-canvas.tsx +24 -1
  657. package/src/components/graph/graph-controls-column.tsx +92 -0
  658. package/src/components/graph/graph-controls.tsx +83 -127
  659. package/src/components/graph/graph-form.tsx +183 -0
  660. package/src/components/graph/graph-maintenance.tsx +9 -14
  661. package/src/components/graph/graph-node-rail.tsx +147 -0
  662. package/src/components/graph/graph-page.tsx +189 -49
  663. package/src/components/graph/graph-scene.tsx +200 -30
  664. package/src/components/graph/lib/graph-helpers.ts +65 -43
  665. package/src/components/graph/node-card.tsx +64 -0
  666. package/src/components/graph/node-popover.tsx +28 -117
  667. package/src/components/graph/use-graph-theme.ts +69 -32
  668. package/src/components/graph/use-node-actions.ts +56 -0
  669. package/src/components/images/image-share.ts +4 -2
  670. package/src/components/images/image-viewer.tsx +3 -1
  671. package/src/components/images/mask-editor.tsx +7 -4
  672. package/src/components/layout/app-shell.tsx +7 -1
  673. package/src/components/layout/desktop-palette.tsx +151 -0
  674. package/src/components/layout/key-cap.tsx +15 -0
  675. package/src/components/layout/mobile-tab-bar.tsx +80 -157
  676. package/src/components/layout/shortcut-switch.tsx +32 -0
  677. package/src/components/layout/side-rail.tsx +70 -150
  678. package/src/components/layout/slide-panel.tsx +29 -2
  679. package/src/components/layout/theme.tsx +67 -0
  680. package/src/components/quick-actions/add-form.tsx +188 -0
  681. package/src/components/quick-actions/add-modal.tsx +68 -144
  682. package/src/components/quick-actions/search-modal.tsx +49 -19
  683. package/src/components/quick-actions/streaming-modal.tsx +44 -71
  684. package/src/components/quick-actions/streaming-output.tsx +112 -0
  685. package/src/components/quick-actions/whatsup-modal.tsx +38 -60
  686. package/src/components/settings/devices-agents-tab.tsx +139 -0
  687. package/src/components/settings/models-list.tsx +299 -0
  688. package/src/components/settings/models-tab.tsx +63 -337
  689. package/src/components/settings/one-time-agent-credential.tsx +131 -0
  690. package/src/components/settings/passkey-list.tsx +201 -0
  691. package/src/components/settings/passkey-tab.tsx +53 -197
  692. package/src/components/settings/pi-accounts-list.tsx +128 -0
  693. package/src/components/settings/pi-accounts.tsx +71 -170
  694. package/src/components/settings/principal-list.tsx +172 -0
  695. package/src/components/settings/settings-panel.tsx +245 -19
  696. package/src/components/settings/skills-list.tsx +276 -0
  697. package/src/components/settings/skills-tab.tsx +82 -269
  698. package/src/components/settings/tool-permissions-list.tsx +54 -0
  699. package/src/components/settings/tool-permissions.tsx +27 -46
  700. package/src/components/settings/web-search-chain.tsx +300 -0
  701. package/src/components/settings/web-search-settings.tsx +58 -328
  702. package/src/components/share/share-menu.tsx +19 -4
  703. package/src/components/voice/dictation-sheet.tsx +5 -5
  704. package/src/components/voice/mic-button.tsx +1 -1
  705. package/src/components/voice/review-card.tsx +1 -1
  706. package/src/config.ts +21 -7
  707. package/src/connection.ts +443 -0
  708. package/src/default-root.ts +16 -0
  709. package/src/hooks/use-color-scheme.ts +36 -0
  710. package/src/hooks/use-hash-routes.ts +4 -2
  711. package/src/hooks/use-media-query.ts +32 -0
  712. package/src/hooks/use-share-intake.ts +32 -12
  713. package/src/hooks/use-vpn-status.ts +23 -15
  714. package/src/hooks/use-websocket.ts +12 -426
  715. package/src/hooks/websocket-handlers/activity.ts +4 -5
  716. package/src/hooks/websocket-handlers/chat.ts +26 -5
  717. package/src/hooks/websocket-handlers/connection.ts +4 -6
  718. package/src/hooks/websocket-handlers/mask.ts +2 -3
  719. package/src/hooks/websocket-handlers/provider.ts +4 -6
  720. package/src/hooks/websocket-handlers/types.ts +6 -2
  721. package/src/index.ts +7 -3
  722. package/src/lib/api-client.ts +446 -365
  723. package/src/lib/backend.ts +20 -10
  724. package/src/lib/diff.ts +28 -62
  725. package/src/lib/format-time.ts +20 -0
  726. package/src/lib/light-dark.ts +83 -0
  727. package/src/lib/mermaid-theme.ts +183 -214
  728. package/src/lib/passkeys.ts +12 -4
  729. package/src/lib/push-registration.ts +46 -0
  730. package/src/lib/share-intake.ts +6 -3
  731. package/src/lib/share.ts +7 -4
  732. package/src/lib/single-key.ts +47 -0
  733. package/src/lib/tool-names.ts +31 -8
  734. package/src/root-context.tsx +40 -0
  735. package/src/root.ts +83 -0
  736. package/src/stores/activity-state.ts +295 -0
  737. package/src/stores/activity-store.ts +11 -285
  738. package/src/stores/chat-state.ts +795 -0
  739. package/src/stores/chat-store.ts +11 -705
  740. package/src/stores/connection-state.ts +78 -0
  741. package/src/stores/connection-store.ts +11 -76
  742. package/src/stores/create-stores.ts +31 -0
  743. package/src/stores/file-state.ts +399 -0
  744. package/src/stores/file-store.ts +9 -360
  745. package/src/stores/graph-state.ts +368 -0
  746. package/src/stores/graph-store.ts +10 -355
  747. package/src/stores/mask-state.ts +30 -0
  748. package/src/stores/mask-store.ts +10 -27
  749. package/src/stores/principal-state.ts +42 -0
  750. package/src/stores/principal-store.ts +11 -0
  751. package/src/stores/provider-state.ts +103 -0
  752. package/src/stores/provider-store.ts +10 -95
  753. package/src/stores/share-state.ts +56 -0
  754. package/src/stores/share-store.ts +11 -54
  755. package/src/stores/store-environment.ts +10 -0
  756. package/src/stores/ui-state.ts +143 -0
  757. package/src/stores/ui-store.ts +11 -93
  758. package/src/styles.css +4 -1
  759. package/src/theme.css +150 -97
  760. package/src/voice/asr-clients.ts +17 -17
  761. package/src/voice/use-dictation.ts +11 -8
  762. package/src/voice/voice-state.ts +57 -0
  763. package/src/voice/voice-store.ts +11 -55
@@ -1,4 +1,5 @@
1
- import { useState, useEffect, useRef } from "react";
1
+ import { useBrainUiRoot } from "../../root-context.js";
2
+ import { useState, useEffect, useRef, type KeyboardEvent } from "react";
2
3
  import {
3
4
  Check,
4
5
  X,
@@ -9,7 +10,7 @@ import {
9
10
  AlertTriangle,
10
11
  FileText,
11
12
  } from "lucide-react";
12
- import { resolveToolRenderer, type ToolSemantics } from "@schlessera/brain-ui-sdk/client";
13
+ import { type ToolSemantics } from "@schlessera/brain-ui-sdk/client";
13
14
  import { useChatStore, type ToolCall } from "../../stores/chat-store.js";
14
15
  import { cn } from "../../lib/utils.js";
15
16
  import { motion, AnimatePresence } from "framer-motion";
@@ -17,6 +18,8 @@ import { getToolLabel, getTouchedFile, formatDuration, formatTokenCount } from "
17
18
  import { registerBuiltinRenderers, GENERIC_RENDERER } from "./renderers/index.js";
18
19
  import { riskHints } from "./risk-hints.js";
19
20
  import { useShallow } from "zustand/react/shallow";
21
+ import { focusAfterDecision, singleKey } from "../../lib/single-key.js";
22
+ import { KeyCap } from "../layout/key-cap.js";
20
23
  import { useActivityStore, spanForTool, childSpans } from "../../stores/activity-store.js";
21
24
  import { useUIStore } from "../../stores/ui-store.js";
22
25
  import { useNow } from "../../hooks/use-now.js";
@@ -46,7 +49,8 @@ export function ToolCallTimeline({
46
49
  live?: boolean;
47
50
  }) {
48
51
  // Resolution happens below during this render, before effects can run.
49
- registerBuiltinRenderers();
52
+ const root = useBrainUiRoot();
53
+ registerBuiltinRenderers(root.renderers);
50
54
 
51
55
  // Collapse the whole run to a summary row once the turn is over. History
52
56
  // messages mount collapsed; a live timeline collapses when streaming ends.
@@ -108,12 +112,13 @@ function TimelineSummaryRow({
108
112
  backendId: string;
109
113
  onExpand: () => void;
110
114
  }) {
115
+ const root = useBrainUiRoot();
111
116
  const steps = toolCalls.length;
112
117
  const files = new Set(
113
118
  toolCalls
114
119
  .map(
115
120
  (t) =>
116
- resolveToolRenderer(t, backendId)?.touchedFile?.(t) ?? getTouchedFile(t)
121
+ root.renderers.resolve(t, backendId)?.touchedFile?.(t) ?? getTouchedFile(t)
117
122
  )
118
123
  .filter(Boolean)
119
124
  ).size;
@@ -156,6 +161,7 @@ function ToolCallEntry({
156
161
  backendId: string;
157
162
  onApproval: (toolUseId: string, approved: boolean, always?: boolean) => void;
158
163
  }) {
164
+ const root = useBrainUiRoot();
159
165
  const [expanded, setExpanded] = useState(
160
166
  toolCall.status === "pending_approval"
161
167
  );
@@ -175,13 +181,30 @@ function ToolCallEntry({
175
181
  : toolCall;
176
182
  // Resolve the renderer for this tool (backend-scoped exact -> global exact ->
177
183
  // shape-sniffing predicate). Falls back to the generic renderer.
178
- const renderer = resolveToolRenderer(toolCall, backendId) ?? GENERIC_RENDERER;
184
+ const renderer = root.renderers.resolve(toolCall, backendId) ?? GENERIC_RENDERER;
179
185
  const Icon = renderer.icon ?? FileText;
180
186
  const label =
181
187
  typeof renderer.label === "function"
182
188
  ? renderer.label(toolCall)
183
189
  : renderer.label ?? getToolLabel(toolCall.name);
184
190
  const isPending = toolCall.status === "pending_approval";
191
+ const keys = useUIStore((s) => s.singleKeyShortcuts);
192
+ /**
193
+ * A decision hands focus on before the card goes (D36): the next pending
194
+ * approval in the transcript, else the composer — the thing the reader
195
+ * continues with, since a chat has no empty-state heading to land on.
196
+ */
197
+ function decide(card: HTMLElement | null, approved: boolean, always?: boolean) {
198
+ if (card) focusAfterDecision(card, "[data-approval-card]", "textarea[data-composer]");
199
+ onApproval(toolCall.id, approved, always);
200
+ }
201
+ function onCardKeyDown(event: KeyboardEvent<HTMLDivElement>) {
202
+ if (!keys) return;
203
+ const key = singleKey(event);
204
+ if (key !== "a" && key !== "d") return;
205
+ event.preventDefault();
206
+ decide(event.currentTarget, key === "a");
207
+ }
185
208
  const summary = renderer.summary?.(timed) ?? null;
186
209
  const meta = renderer.meta?.(timed) ?? null;
187
210
  const Input = renderer.Input;
@@ -204,17 +227,18 @@ function ToolCallEntry({
204
227
 
205
228
  return (
206
229
  <div className="relative">
207
- {/* Timeline dot */}
230
+ {/* Timeline dot: a bare mark with no content, so it takes the MARK
231
+ weight — a fill sits at 1.3-1.8:1 on paper at any diameter. */}
208
232
  <div
209
233
  className={cn(
210
234
  "absolute -left-[21px] top-2 h-2.5 w-2.5 rounded-full border-2 border-background",
211
- toolCall.status === "streaming" && "bg-primary animate-pulse",
235
+ toolCall.status === "streaming" && "bg-primary-mark animate-pulse",
212
236
  toolCall.status === "pending_approval" &&
213
- "bg-primary",
214
- toolCall.status === "approved" && "bg-accent",
215
- toolCall.status === "denied" && "bg-destructive",
237
+ "bg-primary-mark",
238
+ toolCall.status === "approved" && "bg-accent-mark",
239
+ toolCall.status === "denied" && "bg-destructive-mark",
216
240
  toolCall.status === "complete" &&
217
- (toolCall.isError ? "bg-destructive" : "bg-accent"),
241
+ (toolCall.isError ? "bg-destructive-mark" : "bg-accent-mark"),
218
242
  !["streaming", "pending_approval", "approved", "denied", "complete"].includes(toolCall.status) && "bg-muted-foreground"
219
243
  )}
220
244
  style={
@@ -275,7 +299,7 @@ function ToolCallEntry({
275
299
  className={cn(
276
300
  "mt-1 rounded-lg p-3 space-y-2",
277
301
  isPending
278
- ? "border-2 border-primary/40 bg-primary/5"
302
+ ? "border-2 border-primary/40 bg-primary-fill/5"
279
303
  : "border border-border-subtle bg-surface"
280
304
  )}
281
305
  >
@@ -291,30 +315,42 @@ function ToolCallEntry({
291
315
  requests — a destructive-command confirmation (kind
292
316
  "command") stays per-use. */}
293
317
  {isPending && (
294
- <div className="flex flex-wrap gap-2">
318
+ // The card is the focus scope for `a` / `d` (D36): the keys
319
+ // act only while it, or a button inside it, holds focus, and
320
+ // they are printed on the buttons they belong to.
321
+ <div
322
+ data-approval-card=""
323
+ role="group"
324
+ aria-label={`Approval: ${label}`}
325
+ tabIndex={0}
326
+ onKeyDown={onCardKeyDown}
327
+ className="flex flex-wrap gap-2 rounded-md outline-none focus-visible:ring-2 focus-visible:ring-primary/50"
328
+ >
295
329
  <button
296
- onClick={() => onApproval(toolCall.id, true)}
297
- className="flex items-center gap-1.5 rounded-lg bg-primary px-4 py-1.5 text-xs font-medium text-primary-foreground transition-colors hover:brightness-110"
330
+ onClick={(e) => decide(e.currentTarget.closest("[data-approval-card]"), true)}
331
+ className="flex items-center gap-1.5 rounded-lg bg-primary-fill px-4 py-1.5 text-xs font-medium text-primary-foreground transition-colors hover:brightness-110"
298
332
  >
299
333
  <Check className="h-3 w-3" />
300
334
  Allow
335
+ {keys && <KeyCap>a</KeyCap>}
301
336
  </button>
302
337
  {toolCall.approvalKind !== "command" && (
303
338
  <button
304
- onClick={() => onApproval(toolCall.id, true, true)}
339
+ onClick={(e) => decide(e.currentTarget.closest("[data-approval-card]"), true, true)}
305
340
  title={`Allow ${toolCall.name} without asking from now on (revocable in Settings → Models)`}
306
- className="flex items-center gap-1.5 rounded-lg border border-primary/40 px-4 py-1.5 text-xs font-medium text-primary transition-colors hover:bg-primary/10"
341
+ className="flex items-center gap-1.5 rounded-lg border border-primary/40 px-4 py-1.5 text-xs font-medium text-primary transition-colors hover:bg-primary-fill/10"
307
342
  >
308
343
  <Check className="h-3 w-3" />
309
344
  Always allow
310
345
  </button>
311
346
  )}
312
347
  <button
313
- onClick={() => onApproval(toolCall.id, false)}
314
- className="flex items-center gap-1.5 rounded-lg border border-destructive/30 px-4 py-1.5 text-xs font-medium text-destructive transition-colors hover:bg-destructive/10"
348
+ onClick={(e) => decide(e.currentTarget.closest("[data-approval-card]"), false)}
349
+ className="flex items-center gap-1.5 rounded-lg border border-destructive/30 px-4 py-1.5 text-xs font-medium text-destructive transition-colors hover:bg-destructive-fill/10"
315
350
  >
316
351
  <X className="h-3 w-3" />
317
352
  Deny
353
+ {keys && <KeyCap>d</KeyCap>}
318
354
  </button>
319
355
  </div>
320
356
  )}
@@ -389,7 +425,7 @@ function RiskHints({
389
425
  const hints = riskHints(toolCall, semantics);
390
426
  if (hints.length === 0) return null;
391
427
  return (
392
- <div className="space-y-0.5 text-[11px] text-amber-400">
428
+ <div className="space-y-0.5 text-[11px] text-primary">
393
429
  {hints.map((hint) => (
394
430
  <div key={hint} className="flex items-center gap-1.5">
395
431
  <AlertTriangle className="h-3 w-3 shrink-0" />
@@ -410,11 +446,11 @@ function StatusIndicator({
410
446
  switch (status) {
411
447
  case "streaming":
412
448
  return (
413
- <span className="inline-block h-1.5 w-1.5 animate-pulse rounded-full bg-primary" />
449
+ <span className="inline-block h-1.5 w-1.5 animate-pulse rounded-full bg-primary-mark" />
414
450
  );
415
451
  case "pending_approval":
416
452
  return (
417
- <span className="rounded bg-primary/20 px-1.5 py-0.5 text-[10px] font-medium text-primary">
453
+ <span className="rounded bg-primary-fill/20 px-1.5 py-0.5 text-[10px] font-medium text-primary">
418
454
  Approval needed
419
455
  </span>
420
456
  );
@@ -430,3 +466,4 @@ function StatusIndicator({
430
466
  );
431
467
  }
432
468
  }
469
+
@@ -0,0 +1,145 @@
1
+ /**
2
+ * The `show_block` result: one of the kit's answer blocks, drawn inline (D41).
3
+ *
4
+ * A switch typed by the contract's payload, handing each variant to its kit
5
+ * component. That typing is the drift check the contract promised: a schema
6
+ * field the kit does not accept fails here, and the kit's own tone unions are
7
+ * asserted equal to the schema's lists in `tests/block-contract.test-d.ts`.
8
+ *
9
+ * Icons come from the model as strings; the kit's `Icon` renders an empty
10
+ * box for a key it does not know, so unknown keys are dropped before the
11
+ * prop is handed on. Optional TEXT props are the other translation: the kit
12
+ * ports the design's demo defaults, so a `QuoteCard` with no `source` names
13
+ * a forecast from the Odysseus fixture world and a `ContactCard` with no
14
+ * `label` is Penelope, and omitted `facts` or `ticks` draw a demo list. Each
15
+ * of those components honours an empty string or an empty array as
16
+ * "cleared", so an omitted field is handed on as `""` or `[]` rather than
17
+ * `undefined`. Everything else is passed through untouched: the schema
18
+ * already rejected what the kit cannot draw.
19
+ */
20
+
21
+ import {
22
+ BarList,
23
+ ComparisonTable,
24
+ ContactCard,
25
+ DataTable,
26
+ ICONS,
27
+ QuoteCard,
28
+ Receipt,
29
+ ScheduleList,
30
+ StatTiles,
31
+ StepList,
32
+ TimelineList,
33
+ TrendChart,
34
+ type IconName,
35
+ } from "@schlessera/brain-ui-kit";
36
+ import type { Block, ShowBlockPayload } from "@schlessera/brain-ui-sdk/client";
37
+
38
+ /** A kit icon key, or nothing when the model named one the kit lacks. */
39
+ export function kitIcon(name: string | undefined): IconName | undefined {
40
+ // An own-property check: `"constructor" in ICONS` is true through the
41
+ // prototype, and the kit would then try to render a function that is not
42
+ // a component.
43
+ return name !== undefined && Object.hasOwn(ICONS, name) ? (name as IconName) : undefined;
44
+ }
45
+
46
+ /** An omitted optional text prop, cleared rather than left to the kit's demo default. */
47
+ const text = (value: string | undefined): string => value ?? "";
48
+
49
+ /** The collapsed one-liner for the trace: `comparison · 3 columns · 4 rows`. */
50
+ export function blockSummary({ block }: ShowBlockPayload): string {
51
+ const count = (n: number, noun: string) => `${n} ${noun}${n === 1 ? "" : "s"}`;
52
+ switch (block.kind) {
53
+ case "comparison":
54
+ return `comparison · ${count(block.columns.length, "column")} · ${count(block.rows.length, "row")}`;
55
+ case "stats":
56
+ return `stats · ${count(block.tiles.length, "tile")}`;
57
+ case "trend":
58
+ return `trend · ${block.label ?? block.value ?? count(block.values.length, "point")}`;
59
+ case "table":
60
+ return `table · ${count(block.columns.length, "column")} · ${count(block.rows.length, "row")}`;
61
+ case "bars":
62
+ return `bars · ${count(block.rows.length, "row")}`;
63
+ case "receipt":
64
+ return `receipt · ${block.title ?? count(block.rows.length, "row")}`;
65
+ case "steps":
66
+ return `steps · ${count(block.steps.length, "step")}`;
67
+ case "timeline":
68
+ return `timeline · ${count(block.items.length, "event")}`;
69
+ case "schedule":
70
+ return `schedule · ${count(block.groups.length, "day")}`;
71
+ case "quote":
72
+ return `quote · ${block.source ?? "unattributed"}`;
73
+ case "contact":
74
+ return `contact · ${block.label}`;
75
+ }
76
+ }
77
+
78
+ function BlockView({ block }: { block: Block }) {
79
+ switch (block.kind) {
80
+ case "comparison": {
81
+ const { kind: _kind, footnote, ...props } = block;
82
+ return <ComparisonTable {...props} footnote={text(footnote)} />;
83
+ }
84
+ case "stats":
85
+ return (
86
+ <StatTiles
87
+ tiles={block.tiles.map((tile) => ({ ...tile, icon: kitIcon(tile.icon) }))}
88
+ />
89
+ );
90
+ case "trend": {
91
+ const { kind: _kind, label, value, ticks, ...props } = block;
92
+ return <TrendChart {...props} label={text(label)} value={text(value)} ticks={ticks ?? []} />;
93
+ }
94
+ case "table": {
95
+ const { kind: _kind, ...props } = block;
96
+ return <DataTable {...props} />;
97
+ }
98
+ case "bars":
99
+ return <BarList rows={block.rows} />;
100
+ case "receipt": {
101
+ const { kind: _kind, title, titleIcon, footnote, ...props } = block;
102
+ return (
103
+ <Receipt
104
+ {...props}
105
+ title={text(title)}
106
+ titleIcon={kitIcon(titleIcon)}
107
+ footnote={text(footnote)}
108
+ />
109
+ );
110
+ }
111
+ case "steps": {
112
+ const { kind: _kind, ...props } = block;
113
+ return <StepList {...props} />;
114
+ }
115
+ case "timeline":
116
+ return <TimelineList items={block.items} />;
117
+ case "schedule":
118
+ return <ScheduleList groups={block.groups} />;
119
+ case "quote": {
120
+ const { kind: _kind, icon, source, locator, note, ...props } = block;
121
+ return (
122
+ <QuoteCard
123
+ {...props}
124
+ source={text(source)}
125
+ locator={text(locator)}
126
+ note={text(note)}
127
+ icon={kitIcon(icon)}
128
+ />
129
+ );
130
+ }
131
+ case "contact": {
132
+ const { kind: _kind, contactKind, role, facts, ...props } = block;
133
+ return <ContactCard {...props} kind={contactKind} role={text(role)} facts={facts ?? []} />;
134
+ }
135
+ }
136
+ }
137
+
138
+ /** Bound to `SHOW_BLOCK_CONTRACT`; receives the parsed payload as props. */
139
+ export function BlockCard({ block }: ShowBlockPayload) {
140
+ return (
141
+ <div data-block={block.kind}>
142
+ <BlockView block={block} />
143
+ </div>
144
+ );
145
+ }
@@ -0,0 +1,214 @@
1
+ /**
2
+ * The `request_image_mask` result: a receipt, not a path (D38 §2).
3
+ *
4
+ * The source thumb — hatched, as everywhere: no remote image loads inline for
5
+ * the source — stacked ABOVE a kit `Receipt` (the truncation rule: a receipt
6
+ * value column under ~160px means change the layout, not the break rule).
7
+ *
8
+ * Typed `ImageMaskPayload`, so the rows are the fields the handler actually
9
+ * sends: `imagePath`, `maskPath`, `bytes`. The design also draws a region and
10
+ * a coverage row; the payload carries neither. The seventh drop's ruling 8
11
+ * settles what happens then: **state the absence**. The receipt's `region`
12
+ * row reads "region not recorded", in gold, rather than disappearing — a
13
+ * load-bearing fact that vanishes cannot be told apart from a whole-image
14
+ * mask, and a later answer citing that receipt would be citing a gap. A
15
+ * caller that does supply a region (the view test) gets the figures.
16
+ *
17
+ * And the mask itself is DRAWN over the thumb whenever its bytes exist: the
18
+ * PNG the handler wrote is fetched from the files API and laid over the
19
+ * hatch, with the teal region fill beneath it so the transparent (editable)
20
+ * pixels show as the user's answer. When the bytes do not exist the thumb
21
+ * shows the source alone with a mono line saying the mask was not rendered.
22
+ *
23
+ * Failure is a fact about the evidence, not a dialog: a declined or failed
24
+ * mask comes back as a tool error with a message, and `ImageMaskFallback`
25
+ * states it in a red boxed mono `Callout` from the result's own words.
26
+ */
27
+
28
+ import { useState, type CSSProperties } from "react";
29
+ import { Callout, Receipt, Surface, color, font, type ReceiptRow } from "@schlessera/brain-ui-kit";
30
+ import type { ImageMaskPayload, ToolCallView } from "@schlessera/brain-ui-sdk/client";
31
+ import { useBrainUiRoot } from "../../../root-context.js";
32
+ import { ClampedPre } from "../tool-views.js";
33
+
34
+ /** A normalised rectangle over the source image: every value in 0..1. */
35
+ export interface MaskRegion {
36
+ x: number;
37
+ y: number;
38
+ w: number;
39
+ h: number;
40
+ }
41
+
42
+ const THUMB_W = 160;
43
+ const THUMB_H = 100;
44
+
45
+ export const REGION_NOT_RECORDED = "region not recorded";
46
+ export const MASK_NOT_RENDERED = "mask not rendered";
47
+
48
+ /** The kit's image placeholder: raised stripes on the surface, no pixels. */
49
+ const HATCH = `repeating-linear-gradient(135deg,${color.raised} 0 6px,var(--bk-hatch-stripe) 6px 12px)`;
50
+
51
+ function bytesLabel(bytes: number): string {
52
+ if (bytes >= 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
53
+ if (bytes >= 1024) return `${Math.round(bytes / 1024)} KB`;
54
+ return `${bytes} B`;
55
+ }
56
+
57
+ /** The mask file exists with content: the handler reports the PNG's byte length. */
58
+ export function hasMaskBytes(payload: Pick<ImageMaskPayload, "bytes">): boolean {
59
+ return typeof payload.bytes === "number" && payload.bytes > 0;
60
+ }
61
+
62
+ /**
63
+ * The thumb: the hatched source, the drawn region when a caller has one, and
64
+ * the mask image over both when `maskUrl` is given. Exported for the view
65
+ * test; the bound card computes `maskUrl` from the payload.
66
+ */
67
+ export function MaskThumb({
68
+ region,
69
+ label,
70
+ maskUrl,
71
+ maskShown,
72
+ onMaskLoad,
73
+ onMaskError,
74
+ }: {
75
+ region?: MaskRegion;
76
+ label: string;
77
+ maskUrl?: string;
78
+ /** The teal fill sits under the mask only once the PNG has loaded: until
79
+ * then, or after a failure, a full teal frame would read as a whole-image
80
+ * mask that was never drawn. */
81
+ maskShown?: boolean;
82
+ onMaskLoad?: () => void;
83
+ onMaskError?: () => void;
84
+ }) {
85
+ const frame: CSSProperties = {
86
+ position: "relative",
87
+ width: "100%",
88
+ maxWidth: THUMB_W * 2,
89
+ aspectRatio: `${THUMB_W} / ${THUMB_H}`,
90
+ borderRadius: 9,
91
+ border: `1px solid ${color.edge}`,
92
+ background: HATCH,
93
+ overflow: "hidden",
94
+ };
95
+ const drawn: CSSProperties | undefined = region
96
+ ? {
97
+ position: "absolute",
98
+ left: `${region.x * 100}%`,
99
+ top: `${region.y * 100}%`,
100
+ width: `${region.w * 100}%`,
101
+ height: `${region.h * 100}%`,
102
+ border: "1.5px dashed var(--bk-teal-ink)",
103
+ background: "var(--bk-mask-region-fill)",
104
+ borderRadius: 3,
105
+ boxSizing: "border-box",
106
+ }
107
+ : undefined;
108
+ // The teal fill sits under the mask: where the PNG is transparent — the
109
+ // editable region, the user's own answer — the teal shows through.
110
+ const fill: CSSProperties = { position: "absolute", inset: 0, background: "var(--bk-mask-region-fill)" };
111
+ const overlay: CSSProperties = {
112
+ position: "absolute",
113
+ inset: 0,
114
+ width: "100%",
115
+ height: "100%",
116
+ objectFit: "contain",
117
+ };
118
+ return (
119
+ <div role="img" aria-label={label} style={frame} data-mask-thumb>
120
+ {drawn ? <div style={drawn} data-mask-region /> : null}
121
+ {maskUrl ? (
122
+ <>
123
+ {maskShown ? <div style={fill} aria-hidden="true" /> : null}
124
+ <img
125
+ src={maskUrl}
126
+ alt=""
127
+ style={{ ...overlay, visibility: maskShown ? "visible" : "hidden" }}
128
+ data-mask-overlay
129
+ data-mask-shown={maskShown ? "" : undefined}
130
+ onLoad={onMaskLoad}
131
+ onError={onMaskError}
132
+ />
133
+ </>
134
+ ) : null}
135
+ </div>
136
+ );
137
+ }
138
+
139
+ /** The rows the receipt prints. The region row is always there: figures when
140
+ * a caller has them, the stated absence when the payload carries none. */
141
+ export function maskReceiptRows(payload: ImageMaskPayload, region?: MaskRegion): ReceiptRow[] {
142
+ const rows: ReceiptRow[] = [];
143
+ if (region) {
144
+ rows.push({
145
+ k: "region",
146
+ v: `${pct(region.x)},${pct(region.y)} → ${pct(region.x + region.w)},${pct(region.y + region.h)}`,
147
+ tone: "teal",
148
+ });
149
+ rows.push({ k: "covers", v: `${pct(region.w * region.h)} of the image`, tone: "teal" });
150
+ } else {
151
+ rows.push({ k: "region", v: REGION_NOT_RECORDED, tone: "gold" });
152
+ }
153
+ rows.push({ k: "source", v: payload.imagePath });
154
+ rows.push({ k: "mask", v: `${payload.maskPath} · ${bytesLabel(payload.bytes)}` });
155
+ return rows;
156
+ }
157
+
158
+ function pct(fraction: number): string {
159
+ return `${Math.round(fraction * 100)}%`;
160
+ }
161
+
162
+ export function ImageMaskResultCard(payload: ImageMaskPayload & { region?: MaskRegion }) {
163
+ const root = useBrainUiRoot();
164
+ const region = payload.region;
165
+ const hasBytes = hasMaskBytes(payload);
166
+ const maskUrl = hasBytes
167
+ ? `${root.apiBase()}/files/content?path=${encodeURIComponent(payload.maskPath)}&raw=1`
168
+ : undefined;
169
+ // The bytes say a mask was written; only the browser can say it loaded.
170
+ // A file gone since, or a path the raw route refuses, must not leave a
171
+ // full teal frame standing in for a mask nobody can see.
172
+ const [maskState, setMaskState] = useState<"loading" | "shown" | "failed">("loading");
173
+ const rendered = hasBytes && maskState === "shown";
174
+ const note: CSSProperties = { font: `400 10.5px/1.5 ${font.mono}`, color: color.inkMute };
175
+ return (
176
+ <Surface tone="teal" label="Mask drawn" labelIcon="confirm" meta="by you" pad={12}>
177
+ <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
178
+ <MaskThumb
179
+ region={region}
180
+ maskUrl={maskUrl}
181
+ maskShown={rendered}
182
+ onMaskLoad={() => setMaskState("shown")}
183
+ onMaskError={() => setMaskState("failed")}
184
+ label={
185
+ rendered
186
+ ? `Mask ${payload.maskPath} over the source ${payload.imagePath}`
187
+ : `Source ${payload.imagePath}; the mask is in ${payload.maskPath}`
188
+ }
189
+ />
190
+ {!hasBytes || maskState === "failed" ? <div style={note}>{MASK_NOT_RENDERED}</div> : null}
191
+ <Receipt keyWidth={58} rows={maskReceiptRows(payload, region)} />
192
+ </div>
193
+ </Surface>
194
+ );
195
+ }
196
+
197
+ /**
198
+ * No payload: the user declined, the editor failed, or an older server
199
+ * answered with a sentence. An error is stated as a fact in red; anything
200
+ * else is shown as the text it is.
201
+ */
202
+ export function ImageMaskFallback({ tool }: { tool: ToolCallView }) {
203
+ if (!tool.output) return null;
204
+ if (!tool.isError) return <ClampedPre text={tool.output} />;
205
+ const source = typeof tool.input.imagePath === "string" ? tool.input.imagePath : null;
206
+ return (
207
+ <Callout
208
+ tone="red"
209
+ variant="boxed"
210
+ mono
211
+ text={`no mask drawn${source ? ` on ${source}` : ""} · ${tool.output.trim()}`}
212
+ />
213
+ );
214
+ }