@schlessera/brain-ui-react 0.35.0 → 0.37.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 (761) 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 +148 -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 +29 -0
  19. package/dist/components/activity/approval-card.d.ts.map +1 -0
  20. package/dist/components/activity/approval-card.js +73 -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 +11 -0
  39. package/dist/components/activity/span-bits.d.ts.map +1 -1
  40. package/dist/components/activity/span-bits.js +50 -7
  41. package/dist/components/activity/span-bits.js.map +1 -1
  42. package/dist/components/chat/ask-user-card.d.ts +76 -3
  43. package/dist/components/chat/ask-user-card.d.ts.map +1 -1
  44. package/dist/components/chat/ask-user-card.js +208 -149
  45. package/dist/components/chat/ask-user-card.js.map +1 -1
  46. package/dist/components/chat/ask-user-typed.d.ts +42 -0
  47. package/dist/components/chat/ask-user-typed.d.ts.map +1 -0
  48. package/dist/components/chat/ask-user-typed.js +60 -0
  49. package/dist/components/chat/ask-user-typed.js.map +1 -0
  50. package/dist/components/chat/brain-markdown-links.d.ts +2 -1
  51. package/dist/components/chat/brain-markdown-links.d.ts.map +1 -1
  52. package/dist/components/chat/brain-markdown-links.js +3 -4
  53. package/dist/components/chat/brain-markdown-links.js.map +1 -1
  54. package/dist/components/chat/brain-markdown.d.ts.map +1 -1
  55. package/dist/components/chat/brain-markdown.js +4 -2
  56. package/dist/components/chat/brain-markdown.js.map +1 -1
  57. package/dist/components/chat/chat-page.d.ts.map +1 -1
  58. package/dist/components/chat/chat-page.js +27 -11
  59. package/dist/components/chat/chat-page.js.map +1 -1
  60. package/dist/components/chat/composer-view.d.ts +75 -0
  61. package/dist/components/chat/composer-view.d.ts.map +1 -0
  62. package/dist/components/chat/composer-view.js +31 -0
  63. package/dist/components/chat/composer-view.js.map +1 -0
  64. package/dist/components/chat/composer.d.ts +4 -0
  65. package/dist/components/chat/composer.d.ts.map +1 -1
  66. package/dist/components/chat/composer.js +76 -59
  67. package/dist/components/chat/composer.js.map +1 -1
  68. package/dist/components/chat/markdown-content.d.ts +16 -1
  69. package/dist/components/chat/markdown-content.d.ts.map +1 -1
  70. package/dist/components/chat/markdown-content.js +47 -3
  71. package/dist/components/chat/markdown-content.js.map +1 -1
  72. package/dist/components/chat/mermaid-block.d.ts +4 -0
  73. package/dist/components/chat/mermaid-block.d.ts.map +1 -1
  74. package/dist/components/chat/mermaid-block.js +13 -5
  75. package/dist/components/chat/mermaid-block.js.map +1 -1
  76. package/dist/components/chat/mermaid-share.d.ts +2 -1
  77. package/dist/components/chat/mermaid-share.d.ts.map +1 -1
  78. package/dist/components/chat/mermaid-share.js +7 -8
  79. package/dist/components/chat/mermaid-share.js.map +1 -1
  80. package/dist/components/chat/mermaid-viewer.d.ts.map +1 -1
  81. package/dist/components/chat/mermaid-viewer.js +3 -1
  82. package/dist/components/chat/mermaid-viewer.js.map +1 -1
  83. package/dist/components/chat/message-bubble.d.ts +8 -1
  84. package/dist/components/chat/message-bubble.d.ts.map +1 -1
  85. package/dist/components/chat/message-bubble.js +53 -24
  86. package/dist/components/chat/message-bubble.js.map +1 -1
  87. package/dist/components/chat/message-share.d.ts +2 -1
  88. package/dist/components/chat/message-share.d.ts.map +1 -1
  89. package/dist/components/chat/message-share.js +6 -7
  90. package/dist/components/chat/message-share.js.map +1 -1
  91. package/dist/components/chat/renderers/bind.d.ts +39 -0
  92. package/dist/components/chat/renderers/bind.d.ts.map +1 -0
  93. package/dist/components/chat/renderers/bind.js +43 -0
  94. package/dist/components/chat/renderers/bind.js.map +1 -0
  95. package/dist/components/chat/renderers/brain-ui-tools.d.ts +3 -0
  96. package/dist/components/chat/renderers/brain-ui-tools.d.ts.map +1 -0
  97. package/dist/components/chat/renderers/brain-ui-tools.js +41 -0
  98. package/dist/components/chat/renderers/brain-ui-tools.js.map +1 -0
  99. package/dist/components/chat/renderers/claude-tools.d.ts.map +1 -1
  100. package/dist/components/chat/renderers/claude-tools.js +3 -2
  101. package/dist/components/chat/renderers/claude-tools.js.map +1 -1
  102. package/dist/components/chat/renderers/index.d.ts +10 -2
  103. package/dist/components/chat/renderers/index.d.ts.map +1 -1
  104. package/dist/components/chat/renderers/index.js +15 -10
  105. package/dist/components/chat/renderers/index.js.map +1 -1
  106. package/dist/components/chat/session-drawer.d.ts +4 -0
  107. package/dist/components/chat/session-drawer.d.ts.map +1 -1
  108. package/dist/components/chat/session-drawer.js +32 -32
  109. package/dist/components/chat/session-drawer.js.map +1 -1
  110. package/dist/components/chat/session-list.d.ts +41 -0
  111. package/dist/components/chat/session-list.d.ts.map +1 -0
  112. package/dist/components/chat/session-list.js +10 -0
  113. package/dist/components/chat/session-list.js.map +1 -0
  114. package/dist/components/chat/share-block.d.ts.map +1 -1
  115. package/dist/components/chat/share-block.js +12 -11
  116. package/dist/components/chat/share-block.js.map +1 -1
  117. package/dist/components/chat/share-card.js +2 -2
  118. package/dist/components/chat/share-card.js.map +1 -1
  119. package/dist/components/chat/subagent-view.js +1 -1
  120. package/dist/components/chat/subagent-view.js.map +1 -1
  121. package/dist/components/chat/tool-call-timeline.d.ts.map +1 -1
  122. package/dist/components/chat/tool-call-timeline.js +45 -14
  123. package/dist/components/chat/tool-call-timeline.js.map +1 -1
  124. package/dist/components/chat/tool-cards/block-card.d.ts +28 -0
  125. package/dist/components/chat/tool-cards/block-card.d.ts.map +1 -0
  126. package/dist/components/chat/tool-cards/block-card.js +103 -0
  127. package/dist/components/chat/tool-cards/block-card.js.map +1 -0
  128. package/dist/components/chat/tool-cards/image-mask-card.d.ts +70 -0
  129. package/dist/components/chat/tool-cards/image-mask-card.d.ts.map +1 -0
  130. package/dist/components/chat/tool-cards/image-mask-card.js +142 -0
  131. package/dist/components/chat/tool-cards/image-mask-card.js.map +1 -0
  132. package/dist/components/chat/tool-cards/location-card.d.ts +45 -0
  133. package/dist/components/chat/tool-cards/location-card.d.ts.map +1 -0
  134. package/dist/components/chat/tool-cards/location-card.js +128 -0
  135. package/dist/components/chat/tool-cards/location-card.js.map +1 -0
  136. package/dist/components/chat/tool-views.d.ts +19 -2
  137. package/dist/components/chat/tool-views.d.ts.map +1 -1
  138. package/dist/components/chat/tool-views.js +28 -22
  139. package/dist/components/chat/tool-views.js.map +1 -1
  140. package/dist/components/chat/transcript-turn.d.ts +45 -0
  141. package/dist/components/chat/transcript-turn.d.ts.map +1 -0
  142. package/dist/components/chat/transcript-turn.js +25 -0
  143. package/dist/components/chat/transcript-turn.js.map +1 -0
  144. package/dist/components/chat/use-chat-commands.d.ts.map +1 -1
  145. package/dist/components/chat/use-chat-commands.js +13 -16
  146. package/dist/components/chat/use-chat-commands.js.map +1 -1
  147. package/dist/components/chat/welcome-state.d.ts +7 -0
  148. package/dist/components/chat/welcome-state.d.ts.map +1 -1
  149. package/dist/components/chat/welcome-state.js +13 -5
  150. package/dist/components/chat/welcome-state.js.map +1 -1
  151. package/dist/components/connectivity/connection-gate.d.ts.map +1 -1
  152. package/dist/components/connectivity/connection-gate.js +27 -21
  153. package/dist/components/connectivity/connection-gate.js.map +1 -1
  154. package/dist/components/connectivity/login-form.d.ts +31 -0
  155. package/dist/components/connectivity/login-form.d.ts.map +1 -0
  156. package/dist/components/connectivity/login-form.js +19 -0
  157. package/dist/components/connectivity/login-form.js.map +1 -0
  158. package/dist/components/connectivity/login-screen.d.ts +5 -2
  159. package/dist/components/connectivity/login-screen.d.ts.map +1 -1
  160. package/dist/components/connectivity/login-screen.js +41 -31
  161. package/dist/components/connectivity/login-screen.js.map +1 -1
  162. package/dist/components/dev/share-harness.js +1 -1
  163. package/dist/components/dev/share-harness.js.map +1 -1
  164. package/dist/components/files/file-panel.d.ts +1 -1
  165. package/dist/components/files/file-panel.d.ts.map +1 -1
  166. package/dist/components/files/file-panel.js +74 -0
  167. package/dist/components/files/file-panel.js.map +1 -1
  168. package/dist/components/files/file-tree-view.d.ts +45 -0
  169. package/dist/components/files/file-tree-view.d.ts.map +1 -0
  170. package/dist/components/files/file-tree-view.js +51 -0
  171. package/dist/components/files/file-tree-view.js.map +1 -0
  172. package/dist/components/files/file-tree.d.ts +6 -0
  173. package/dist/components/files/file-tree.d.ts.map +1 -1
  174. package/dist/components/files/file-tree.js +39 -43
  175. package/dist/components/files/file-tree.js.map +1 -1
  176. package/dist/components/files/file-viewer-binary.d.ts.map +1 -1
  177. package/dist/components/files/file-viewer-binary.js +3 -2
  178. package/dist/components/files/file-viewer-binary.js.map +1 -1
  179. package/dist/components/files/file-viewer-frame.d.ts +36 -0
  180. package/dist/components/files/file-viewer-frame.d.ts.map +1 -0
  181. package/dist/components/files/file-viewer-frame.js +26 -0
  182. package/dist/components/files/file-viewer-frame.js.map +1 -0
  183. package/dist/components/files/file-viewer.d.ts +5 -0
  184. package/dist/components/files/file-viewer.d.ts.map +1 -1
  185. package/dist/components/files/file-viewer.js +26 -32
  186. package/dist/components/files/file-viewer.js.map +1 -1
  187. package/dist/components/files/frontmatter-chips.d.ts +18 -0
  188. package/dist/components/files/frontmatter-chips.d.ts.map +1 -0
  189. package/dist/components/files/frontmatter-chips.js +11 -0
  190. package/dist/components/files/frontmatter-chips.js.map +1 -0
  191. package/dist/components/files/frontmatter-panel.d.ts +5 -1
  192. package/dist/components/files/frontmatter-panel.d.ts.map +1 -1
  193. package/dist/components/files/frontmatter-panel.js +7 -6
  194. package/dist/components/files/frontmatter-panel.js.map +1 -1
  195. package/dist/components/files/staleness.d.ts +18 -0
  196. package/dist/components/files/staleness.d.ts.map +1 -0
  197. package/dist/components/files/staleness.js +27 -0
  198. package/dist/components/files/staleness.js.map +1 -0
  199. package/dist/components/graph/graph-canvas.d.ts.map +1 -1
  200. package/dist/components/graph/graph-canvas.js +24 -1
  201. package/dist/components/graph/graph-canvas.js.map +1 -1
  202. package/dist/components/graph/graph-controls-column.d.ts +14 -0
  203. package/dist/components/graph/graph-controls-column.d.ts.map +1 -0
  204. package/dist/components/graph/graph-controls-column.js +44 -0
  205. package/dist/components/graph/graph-controls-column.js.map +1 -0
  206. package/dist/components/graph/graph-controls.d.ts +20 -5
  207. package/dist/components/graph/graph-controls.d.ts.map +1 -1
  208. package/dist/components/graph/graph-controls.js +58 -37
  209. package/dist/components/graph/graph-controls.js.map +1 -1
  210. package/dist/components/graph/graph-form.d.ts +82 -0
  211. package/dist/components/graph/graph-form.d.ts.map +1 -0
  212. package/dist/components/graph/graph-form.js +69 -0
  213. package/dist/components/graph/graph-form.js.map +1 -0
  214. package/dist/components/graph/graph-maintenance.d.ts.map +1 -1
  215. package/dist/components/graph/graph-maintenance.js +6 -10
  216. package/dist/components/graph/graph-maintenance.js.map +1 -1
  217. package/dist/components/graph/graph-node-rail.d.ts +13 -0
  218. package/dist/components/graph/graph-node-rail.d.ts.map +1 -0
  219. package/dist/components/graph/graph-node-rail.js +92 -0
  220. package/dist/components/graph/graph-node-rail.js.map +1 -0
  221. package/dist/components/graph/graph-page.d.ts +7 -0
  222. package/dist/components/graph/graph-page.d.ts.map +1 -1
  223. package/dist/components/graph/graph-page.js +102 -12
  224. package/dist/components/graph/graph-page.js.map +1 -1
  225. package/dist/components/graph/graph-scene.d.ts.map +1 -1
  226. package/dist/components/graph/graph-scene.js +100 -24
  227. package/dist/components/graph/graph-scene.js.map +1 -1
  228. package/dist/components/graph/lib/graph-helpers.d.ts +42 -12
  229. package/dist/components/graph/lib/graph-helpers.d.ts.map +1 -1
  230. package/dist/components/graph/lib/graph-helpers.js +33 -41
  231. package/dist/components/graph/lib/graph-helpers.js.map +1 -1
  232. package/dist/components/graph/node-card.d.ts +28 -0
  233. package/dist/components/graph/node-card.d.ts.map +1 -0
  234. package/dist/components/graph/node-card.js +7 -0
  235. package/dist/components/graph/node-card.js.map +1 -0
  236. package/dist/components/graph/node-popover.d.ts +6 -2
  237. package/dist/components/graph/node-popover.d.ts.map +1 -1
  238. package/dist/components/graph/node-popover.js +13 -31
  239. package/dist/components/graph/node-popover.js.map +1 -1
  240. package/dist/components/graph/use-graph-theme.d.ts +32 -4
  241. package/dist/components/graph/use-graph-theme.d.ts.map +1 -1
  242. package/dist/components/graph/use-graph-theme.js +44 -32
  243. package/dist/components/graph/use-graph-theme.js.map +1 -1
  244. package/dist/components/graph/use-node-actions.d.ts +26 -0
  245. package/dist/components/graph/use-node-actions.d.ts.map +1 -0
  246. package/dist/components/graph/use-node-actions.js +54 -0
  247. package/dist/components/graph/use-node-actions.js.map +1 -0
  248. package/dist/components/images/image-share.d.ts +2 -1
  249. package/dist/components/images/image-share.d.ts.map +1 -1
  250. package/dist/components/images/image-share.js +3 -3
  251. package/dist/components/images/image-share.js.map +1 -1
  252. package/dist/components/images/image-viewer.d.ts.map +1 -1
  253. package/dist/components/images/image-viewer.js +3 -1
  254. package/dist/components/images/image-viewer.js.map +1 -1
  255. package/dist/components/images/mask-editor.d.ts.map +1 -1
  256. package/dist/components/images/mask-editor.js +7 -5
  257. package/dist/components/images/mask-editor.js.map +1 -1
  258. package/dist/components/layout/app-shell.d.ts.map +1 -1
  259. package/dist/components/layout/app-shell.js +4 -1
  260. package/dist/components/layout/app-shell.js.map +1 -1
  261. package/dist/components/layout/desktop-palette.d.ts +23 -0
  262. package/dist/components/layout/desktop-palette.d.ts.map +1 -0
  263. package/dist/components/layout/desktop-palette.js +132 -0
  264. package/dist/components/layout/desktop-palette.js.map +1 -0
  265. package/dist/components/layout/key-cap.d.ts +9 -0
  266. package/dist/components/layout/key-cap.d.ts.map +1 -0
  267. package/dist/components/layout/key-cap.js +10 -0
  268. package/dist/components/layout/key-cap.js.map +1 -0
  269. package/dist/components/layout/mobile-tab-bar.d.ts +13 -0
  270. package/dist/components/layout/mobile-tab-bar.d.ts.map +1 -1
  271. package/dist/components/layout/mobile-tab-bar.js +58 -47
  272. package/dist/components/layout/mobile-tab-bar.js.map +1 -1
  273. package/dist/components/layout/shortcut-switch.d.ts +13 -0
  274. package/dist/components/layout/shortcut-switch.d.ts.map +1 -0
  275. package/dist/components/layout/shortcut-switch.js +22 -0
  276. package/dist/components/layout/shortcut-switch.js.map +1 -0
  277. package/dist/components/layout/side-rail.d.ts +28 -0
  278. package/dist/components/layout/side-rail.d.ts.map +1 -1
  279. package/dist/components/layout/side-rail.js +72 -27
  280. package/dist/components/layout/side-rail.js.map +1 -1
  281. package/dist/components/layout/slide-panel.d.ts +25 -2
  282. package/dist/components/layout/slide-panel.d.ts.map +1 -1
  283. package/dist/components/layout/slide-panel.js +13 -4
  284. package/dist/components/layout/slide-panel.js.map +1 -1
  285. package/dist/components/layout/theme.d.ts +22 -0
  286. package/dist/components/layout/theme.d.ts.map +1 -0
  287. package/dist/components/layout/theme.js +44 -0
  288. package/dist/components/layout/theme.js.map +1 -0
  289. package/dist/components/quick-actions/add-form.d.ts +44 -0
  290. package/dist/components/quick-actions/add-form.d.ts.map +1 -0
  291. package/dist/components/quick-actions/add-form.js +32 -0
  292. package/dist/components/quick-actions/add-form.js.map +1 -0
  293. package/dist/components/quick-actions/add-modal.d.ts +7 -0
  294. package/dist/components/quick-actions/add-modal.d.ts.map +1 -1
  295. package/dist/components/quick-actions/add-modal.js +23 -20
  296. package/dist/components/quick-actions/add-modal.js.map +1 -1
  297. package/dist/components/quick-actions/search-modal.d.ts.map +1 -1
  298. package/dist/components/quick-actions/search-modal.js +8 -5
  299. package/dist/components/quick-actions/search-modal.js.map +1 -1
  300. package/dist/components/quick-actions/streaming-modal.d.ts +6 -0
  301. package/dist/components/quick-actions/streaming-modal.d.ts.map +1 -1
  302. package/dist/components/quick-actions/streaming-modal.js +53 -18
  303. package/dist/components/quick-actions/streaming-modal.js.map +1 -1
  304. package/dist/components/quick-actions/streaming-output.d.ts +38 -0
  305. package/dist/components/quick-actions/streaming-output.d.ts.map +1 -0
  306. package/dist/components/quick-actions/streaming-output.js +22 -0
  307. package/dist/components/quick-actions/streaming-output.js.map +1 -0
  308. package/dist/components/quick-actions/whatsup-modal.d.ts +5 -0
  309. package/dist/components/quick-actions/whatsup-modal.d.ts.map +1 -1
  310. package/dist/components/quick-actions/whatsup-modal.js +51 -10
  311. package/dist/components/quick-actions/whatsup-modal.js.map +1 -1
  312. package/dist/components/settings/devices-agents-tab.d.ts +6 -1
  313. package/dist/components/settings/devices-agents-tab.d.ts.map +1 -1
  314. package/dist/components/settings/devices-agents-tab.js +55 -20
  315. package/dist/components/settings/devices-agents-tab.js.map +1 -1
  316. package/dist/components/settings/models-list.d.ts +39 -0
  317. package/dist/components/settings/models-list.d.ts.map +1 -0
  318. package/dist/components/settings/models-list.js +72 -0
  319. package/dist/components/settings/models-list.js.map +1 -0
  320. package/dist/components/settings/models-tab.d.ts +4 -0
  321. package/dist/components/settings/models-tab.d.ts.map +1 -1
  322. package/dist/components/settings/models-tab.js +52 -102
  323. package/dist/components/settings/models-tab.js.map +1 -1
  324. package/dist/components/settings/one-time-agent-credential.js +1 -1
  325. package/dist/components/settings/one-time-agent-credential.js.map +1 -1
  326. package/dist/components/settings/passkey-list.d.ts +35 -0
  327. package/dist/components/settings/passkey-list.d.ts.map +1 -0
  328. package/dist/components/settings/passkey-list.js +34 -0
  329. package/dist/components/settings/passkey-list.js.map +1 -0
  330. package/dist/components/settings/passkey-tab.d.ts +3 -0
  331. package/dist/components/settings/passkey-tab.d.ts.map +1 -1
  332. package/dist/components/settings/passkey-tab.js +53 -45
  333. package/dist/components/settings/passkey-tab.js.map +1 -1
  334. package/dist/components/settings/pi-accounts-list.d.ts +27 -0
  335. package/dist/components/settings/pi-accounts-list.d.ts.map +1 -0
  336. package/dist/components/settings/pi-accounts-list.js +15 -0
  337. package/dist/components/settings/pi-accounts-list.js.map +1 -0
  338. package/dist/components/settings/pi-accounts.d.ts +3 -0
  339. package/dist/components/settings/pi-accounts.d.ts.map +1 -1
  340. package/dist/components/settings/pi-accounts.js +73 -55
  341. package/dist/components/settings/pi-accounts.js.map +1 -1
  342. package/dist/components/settings/principal-list.d.ts +37 -0
  343. package/dist/components/settings/principal-list.d.ts.map +1 -0
  344. package/dist/components/settings/principal-list.js +18 -0
  345. package/dist/components/settings/principal-list.js.map +1 -0
  346. package/dist/components/settings/settings-panel.d.ts +10 -3
  347. package/dist/components/settings/settings-panel.d.ts.map +1 -1
  348. package/dist/components/settings/settings-panel.js +71 -10
  349. package/dist/components/settings/settings-panel.js.map +1 -1
  350. package/dist/components/settings/skills-list.d.ts +53 -0
  351. package/dist/components/settings/skills-list.d.ts.map +1 -0
  352. package/dist/components/settings/skills-list.js +28 -0
  353. package/dist/components/settings/skills-list.js.map +1 -0
  354. package/dist/components/settings/skills-tab.d.ts.map +1 -1
  355. package/dist/components/settings/skills-tab.js +65 -38
  356. package/dist/components/settings/skills-tab.js.map +1 -1
  357. package/dist/components/settings/tool-permissions-list.d.ts +18 -0
  358. package/dist/components/settings/tool-permissions-list.d.ts.map +1 -0
  359. package/dist/components/settings/tool-permissions-list.js +6 -0
  360. package/dist/components/settings/tool-permissions-list.js.map +1 -0
  361. package/dist/components/settings/tool-permissions.d.ts +2 -1
  362. package/dist/components/settings/tool-permissions.d.ts.map +1 -1
  363. package/dist/components/settings/tool-permissions.js +33 -16
  364. package/dist/components/settings/tool-permissions.js.map +1 -1
  365. package/dist/components/settings/web-search-chain.d.ts +41 -0
  366. package/dist/components/settings/web-search-chain.d.ts.map +1 -0
  367. package/dist/components/settings/web-search-chain.js +47 -0
  368. package/dist/components/settings/web-search-chain.js.map +1 -0
  369. package/dist/components/settings/web-search-settings.d.ts +4 -7
  370. package/dist/components/settings/web-search-settings.d.ts.map +1 -1
  371. package/dist/components/settings/web-search-settings.js +54 -76
  372. package/dist/components/settings/web-search-settings.js.map +1 -1
  373. package/dist/components/share/share-menu.d.ts.map +1 -1
  374. package/dist/components/share/share-menu.js +24 -4
  375. package/dist/components/share/share-menu.js.map +1 -1
  376. package/dist/components/voice/dictation-sheet.js +3 -3
  377. package/dist/components/voice/dictation-sheet.js.map +1 -1
  378. package/dist/components/voice/mic-button.js +1 -1
  379. package/dist/components/voice/mic-button.js.map +1 -1
  380. package/dist/components/voice/review-card.js +1 -1
  381. package/dist/components/voice/review-card.js.map +1 -1
  382. package/dist/config.d.ts +5 -2
  383. package/dist/config.d.ts.map +1 -1
  384. package/dist/config.js +15 -5
  385. package/dist/config.js.map +1 -1
  386. package/dist/connection.d.ts +12 -0
  387. package/dist/connection.d.ts.map +1 -0
  388. package/dist/connection.js +421 -0
  389. package/dist/connection.js.map +1 -0
  390. package/dist/default-root.d.ts +3 -0
  391. package/dist/default-root.d.ts.map +1 -0
  392. package/dist/default-root.js +16 -0
  393. package/dist/default-root.js.map +1 -0
  394. package/dist/hooks/use-color-scheme.d.ts +14 -0
  395. package/dist/hooks/use-color-scheme.d.ts.map +1 -0
  396. package/dist/hooks/use-color-scheme.js +37 -0
  397. package/dist/hooks/use-color-scheme.js.map +1 -0
  398. package/dist/hooks/use-fine-pointer.d.ts +12 -0
  399. package/dist/hooks/use-fine-pointer.d.ts.map +1 -0
  400. package/dist/hooks/use-fine-pointer.js +15 -0
  401. package/dist/hooks/use-fine-pointer.js.map +1 -0
  402. package/dist/hooks/use-hash-routes.d.ts.map +1 -1
  403. package/dist/hooks/use-hash-routes.js +4 -2
  404. package/dist/hooks/use-hash-routes.js.map +1 -1
  405. package/dist/hooks/use-media-query.d.ts +9 -0
  406. package/dist/hooks/use-media-query.d.ts.map +1 -0
  407. package/dist/hooks/use-media-query.js +38 -0
  408. package/dist/hooks/use-media-query.js.map +1 -0
  409. package/dist/hooks/use-share-intake.d.ts.map +1 -1
  410. package/dist/hooks/use-share-intake.js +37 -12
  411. package/dist/hooks/use-share-intake.js.map +1 -1
  412. package/dist/hooks/use-vpn-status.d.ts.map +1 -1
  413. package/dist/hooks/use-vpn-status.js +17 -18
  414. package/dist/hooks/use-vpn-status.js.map +1 -1
  415. package/dist/hooks/use-websocket.d.ts +5 -24
  416. package/dist/hooks/use-websocket.d.ts.map +1 -1
  417. package/dist/hooks/use-websocket.js +11 -384
  418. package/dist/hooks/use-websocket.js.map +1 -1
  419. package/dist/hooks/websocket-handlers/activity.d.ts +2 -2
  420. package/dist/hooks/websocket-handlers/activity.d.ts.map +1 -1
  421. package/dist/hooks/websocket-handlers/activity.js +4 -5
  422. package/dist/hooks/websocket-handlers/activity.js.map +1 -1
  423. package/dist/hooks/websocket-handlers/chat.d.ts +1 -0
  424. package/dist/hooks/websocket-handlers/chat.d.ts.map +1 -1
  425. package/dist/hooks/websocket-handlers/chat.js +28 -6
  426. package/dist/hooks/websocket-handlers/chat.js.map +1 -1
  427. package/dist/hooks/websocket-handlers/connection.d.ts.map +1 -1
  428. package/dist/hooks/websocket-handlers/connection.js +4 -6
  429. package/dist/hooks/websocket-handlers/connection.js.map +1 -1
  430. package/dist/hooks/websocket-handlers/mask.d.ts +1 -1
  431. package/dist/hooks/websocket-handlers/mask.d.ts.map +1 -1
  432. package/dist/hooks/websocket-handlers/mask.js +2 -3
  433. package/dist/hooks/websocket-handlers/mask.js.map +1 -1
  434. package/dist/hooks/websocket-handlers/provider.d.ts.map +1 -1
  435. package/dist/hooks/websocket-handlers/provider.js +4 -6
  436. package/dist/hooks/websocket-handlers/provider.js.map +1 -1
  437. package/dist/hooks/websocket-handlers/types.d.ts +6 -2
  438. package/dist/hooks/websocket-handlers/types.d.ts.map +1 -1
  439. package/dist/index.d.ts +5 -3
  440. package/dist/index.d.ts.map +1 -1
  441. package/dist/index.js +6 -3
  442. package/dist/index.js.map +1 -1
  443. package/dist/lib/api-client.d.ts +289 -0
  444. package/dist/lib/api-client.d.ts.map +1 -1
  445. package/dist/lib/api-client.js +243 -224
  446. package/dist/lib/api-client.js.map +1 -1
  447. package/dist/lib/backend.d.ts +19 -2
  448. package/dist/lib/backend.d.ts.map +1 -1
  449. package/dist/lib/backend.js +15 -9
  450. package/dist/lib/backend.js.map +1 -1
  451. package/dist/lib/diff.d.ts +8 -10
  452. package/dist/lib/diff.d.ts.map +1 -1
  453. package/dist/lib/diff.js +26 -53
  454. package/dist/lib/diff.js.map +1 -1
  455. package/dist/lib/light-dark.d.ts +37 -0
  456. package/dist/lib/light-dark.d.ts.map +1 -0
  457. package/dist/lib/light-dark.js +83 -0
  458. package/dist/lib/light-dark.js.map +1 -0
  459. package/dist/lib/mermaid-theme.d.ts +7 -2
  460. package/dist/lib/mermaid-theme.d.ts.map +1 -1
  461. package/dist/lib/mermaid-theme.js +125 -203
  462. package/dist/lib/mermaid-theme.js.map +1 -1
  463. package/dist/lib/passkeys.d.ts +6 -3
  464. package/dist/lib/passkeys.d.ts.map +1 -1
  465. package/dist/lib/passkeys.js +10 -4
  466. package/dist/lib/passkeys.js.map +1 -1
  467. package/dist/lib/push-registration.d.ts +4 -1
  468. package/dist/lib/push-registration.d.ts.map +1 -1
  469. package/dist/lib/push-registration.js +20 -2
  470. package/dist/lib/push-registration.js.map +1 -1
  471. package/dist/lib/share-intake.d.ts +2 -1
  472. package/dist/lib/share-intake.d.ts.map +1 -1
  473. package/dist/lib/share-intake.js +3 -3
  474. package/dist/lib/share-intake.js.map +1 -1
  475. package/dist/lib/share.d.ts +4 -3
  476. package/dist/lib/share.d.ts.map +1 -1
  477. package/dist/lib/share.js +6 -7
  478. package/dist/lib/share.js.map +1 -1
  479. package/dist/lib/single-key.d.ts +30 -0
  480. package/dist/lib/single-key.d.ts.map +1 -0
  481. package/dist/lib/single-key.js +45 -0
  482. package/dist/lib/single-key.js.map +1 -0
  483. package/dist/lib/tool-names.d.ts +8 -6
  484. package/dist/lib/tool-names.d.ts.map +1 -1
  485. package/dist/lib/tool-names.js +17 -7
  486. package/dist/lib/tool-names.js.map +1 -1
  487. package/dist/root-context.d.ts +229 -0
  488. package/dist/root-context.d.ts.map +1 -0
  489. package/dist/root-context.js +33 -0
  490. package/dist/root-context.js.map +1 -0
  491. package/dist/root.d.ts +38 -0
  492. package/dist/root.d.ts.map +1 -0
  493. package/dist/root.js +47 -0
  494. package/dist/root.js.map +1 -0
  495. package/dist/stores/activity-state.d.ts +29 -0
  496. package/dist/stores/activity-state.d.ts.map +1 -0
  497. package/dist/stores/activity-state.js +282 -0
  498. package/dist/stores/activity-state.js.map +1 -0
  499. package/dist/stores/activity-store.d.ts +10 -41
  500. package/dist/stores/activity-store.d.ts.map +1 -1
  501. package/dist/stores/activity-store.js +9 -271
  502. package/dist/stores/activity-store.js.map +1 -1
  503. package/dist/stores/chat-state.d.ts +233 -0
  504. package/dist/stores/chat-state.d.ts.map +1 -0
  505. package/dist/stores/chat-state.js +477 -0
  506. package/dist/stores/chat-state.js.map +1 -0
  507. package/dist/stores/chat-store.d.ts +4 -162
  508. package/dist/stores/chat-store.d.ts.map +1 -1
  509. package/dist/stores/chat-store.js +7 -418
  510. package/dist/stores/chat-store.js.map +1 -1
  511. package/dist/stores/connection-state.d.ts +40 -0
  512. package/dist/stores/connection-state.d.ts.map +1 -0
  513. package/dist/stores/connection-state.js +30 -0
  514. package/dist/stores/connection-state.js.map +1 -0
  515. package/dist/stores/connection-store.d.ts +4 -40
  516. package/dist/stores/connection-store.d.ts.map +1 -1
  517. package/dist/stores/connection-store.js +7 -27
  518. package/dist/stores/connection-store.js.map +1 -1
  519. package/dist/stores/create-stores.d.ts +23 -0
  520. package/dist/stores/create-stores.d.ts.map +1 -0
  521. package/dist/stores/create-stores.js +28 -0
  522. package/dist/stores/create-stores.js.map +1 -0
  523. package/dist/stores/file-state.d.ts +53 -0
  524. package/dist/stores/file-state.d.ts.map +1 -0
  525. package/dist/stores/file-state.js +341 -0
  526. package/dist/stores/file-state.js.map +1 -0
  527. package/dist/stores/file-store.d.ts +4 -52
  528. package/dist/stores/file-store.d.ts.map +1 -1
  529. package/dist/stores/file-store.js +7 -336
  530. package/dist/stores/file-store.js.map +1 -1
  531. package/dist/stores/graph-state.d.ts +95 -0
  532. package/dist/stores/graph-state.d.ts.map +1 -0
  533. package/dist/stores/graph-state.js +252 -0
  534. package/dist/stores/graph-state.js.map +1 -0
  535. package/dist/stores/graph-store.d.ts +7 -83
  536. package/dist/stores/graph-store.d.ts.map +1 -1
  537. package/dist/stores/graph-store.js +8 -249
  538. package/dist/stores/graph-store.js.map +1 -1
  539. package/dist/stores/mask-state.d.ts +21 -0
  540. package/dist/stores/mask-state.d.ts.map +1 -0
  541. package/dist/stores/mask-state.js +9 -0
  542. package/dist/stores/mask-state.js.map +1 -0
  543. package/dist/stores/mask-store.d.ts +4 -21
  544. package/dist/stores/mask-store.d.ts.map +1 -1
  545. package/dist/stores/mask-store.js +7 -6
  546. package/dist/stores/mask-store.js.map +1 -1
  547. package/dist/stores/principal-state.d.ts +16 -0
  548. package/dist/stores/principal-state.d.ts.map +1 -0
  549. package/dist/stores/principal-state.js +31 -0
  550. package/dist/stores/principal-state.js.map +1 -0
  551. package/dist/stores/principal-store.d.ts +4 -15
  552. package/dist/stores/principal-store.d.ts.map +1 -1
  553. package/dist/stores/principal-store.js +7 -28
  554. package/dist/stores/principal-store.js.map +1 -1
  555. package/dist/stores/provider-state.d.ts +24 -0
  556. package/dist/stores/provider-state.d.ts.map +1 -0
  557. package/dist/stores/provider-state.js +68 -0
  558. package/dist/stores/provider-state.js.map +1 -0
  559. package/dist/stores/provider-store.d.ts +4 -23
  560. package/dist/stores/provider-store.d.ts.map +1 -1
  561. package/dist/stores/provider-store.js +7 -64
  562. package/dist/stores/provider-store.js.map +1 -1
  563. package/dist/stores/share-state.d.ts +29 -0
  564. package/dist/stores/share-state.d.ts.map +1 -0
  565. package/dist/stores/share-state.js +21 -0
  566. package/dist/stores/share-state.js.map +1 -0
  567. package/dist/stores/share-store.d.ts +4 -28
  568. package/dist/stores/share-store.d.ts.map +1 -1
  569. package/dist/stores/share-store.js +7 -18
  570. package/dist/stores/share-store.js.map +1 -1
  571. package/dist/stores/store-environment.d.ts +10 -0
  572. package/dist/stores/store-environment.d.ts.map +1 -0
  573. package/dist/stores/store-environment.js +2 -0
  574. package/dist/stores/store-environment.js.map +1 -0
  575. package/dist/stores/ui-state.d.ts +71 -0
  576. package/dist/stores/ui-state.d.ts.map +1 -0
  577. package/dist/stores/ui-state.js +58 -0
  578. package/dist/stores/ui-state.js.map +1 -0
  579. package/dist/stores/ui-store.d.ts +4 -45
  580. package/dist/stores/ui-store.d.ts.map +1 -1
  581. package/dist/stores/ui-store.js +7 -36
  582. package/dist/stores/ui-store.js.map +1 -1
  583. package/dist/styles.css +1 -1
  584. package/dist/theme.css +150 -97
  585. package/dist/voice/asr-clients.d.ts +2 -1
  586. package/dist/voice/asr-clients.d.ts.map +1 -1
  587. package/dist/voice/asr-clients.js +16 -17
  588. package/dist/voice/asr-clients.js.map +1 -1
  589. package/dist/voice/use-dictation.d.ts.map +1 -1
  590. package/dist/voice/use-dictation.js +12 -8
  591. package/dist/voice/use-dictation.js.map +1 -1
  592. package/dist/voice/voice-state.d.ts +25 -0
  593. package/dist/voice/voice-state.d.ts.map +1 -0
  594. package/dist/voice/voice-state.js +29 -0
  595. package/dist/voice/voice-state.js.map +1 -0
  596. package/dist/voice/voice-store.d.ts +4 -25
  597. package/dist/voice/voice-store.d.ts.map +1 -1
  598. package/dist/voice/voice-store.js +7 -26
  599. package/dist/voice/voice-store.js.map +1 -1
  600. package/package.json +3 -2
  601. package/src/components/activity/activity-page.tsx +341 -160
  602. package/src/components/activity/activity-run-detail.tsx +81 -47
  603. package/src/components/activity/activity-run-list.tsx +27 -59
  604. package/src/components/activity/activity-views.tsx +155 -0
  605. package/src/components/activity/approval-card.tsx +117 -0
  606. package/src/components/activity/digest-card.tsx +25 -61
  607. package/src/components/activity/digest-summary.tsx +52 -0
  608. package/src/components/activity/push-switch.tsx +62 -0
  609. package/src/components/activity/push-toggle.tsx +51 -81
  610. package/src/components/activity/span-bits.tsx +60 -7
  611. package/src/components/chat/ask-user-card.tsx +292 -356
  612. package/src/components/chat/ask-user-typed.ts +77 -0
  613. package/src/components/chat/brain-markdown-links.tsx +4 -4
  614. package/src/components/chat/brain-markdown.tsx +4 -2
  615. package/src/components/chat/chat-page.tsx +41 -11
  616. package/src/components/chat/composer-view.tsx +194 -0
  617. package/src/components/chat/composer.tsx +117 -296
  618. package/src/components/chat/markdown-content.tsx +53 -2
  619. package/src/components/chat/mermaid-block.tsx +13 -5
  620. package/src/components/chat/mermaid-share.ts +8 -7
  621. package/src/components/chat/mermaid-viewer.tsx +3 -1
  622. package/src/components/chat/message-bubble.tsx +78 -94
  623. package/src/components/chat/message-share.ts +7 -7
  624. package/src/components/chat/renderers/bind.tsx +94 -0
  625. package/src/components/chat/renderers/brain-ui-tools.tsx +56 -0
  626. package/src/components/chat/renderers/claude-tools.tsx +3 -2
  627. package/src/components/chat/renderers/index.ts +15 -10
  628. package/src/components/chat/session-drawer.tsx +41 -138
  629. package/src/components/chat/session-list.tsx +113 -0
  630. package/src/components/chat/share-block.tsx +16 -12
  631. package/src/components/chat/share-card.tsx +2 -2
  632. package/src/components/chat/subagent-view.tsx +4 -4
  633. package/src/components/chat/tool-call-timeline.tsx +75 -26
  634. package/src/components/chat/tool-cards/block-card.tsx +145 -0
  635. package/src/components/chat/tool-cards/image-mask-card.tsx +214 -0
  636. package/src/components/chat/tool-cards/location-card.tsx +159 -0
  637. package/src/components/chat/tool-views.tsx +30 -60
  638. package/src/components/chat/transcript-turn.tsx +108 -0
  639. package/src/components/chat/use-chat-commands.ts +14 -16
  640. package/src/components/chat/welcome-state.tsx +36 -91
  641. package/src/components/connectivity/connection-gate.tsx +32 -24
  642. package/src/components/connectivity/login-form.tsx +122 -0
  643. package/src/components/connectivity/login-screen.tsx +45 -100
  644. package/src/components/dev/share-harness.tsx +2 -2
  645. package/src/components/files/file-panel.tsx +168 -0
  646. package/src/components/files/file-tree-view.tsx +127 -0
  647. package/src/components/files/file-tree.tsx +55 -109
  648. package/src/components/files/file-viewer-binary.tsx +3 -2
  649. package/src/components/files/file-viewer-frame.tsx +113 -0
  650. package/src/components/files/file-viewer.tsx +40 -95
  651. package/src/components/files/frontmatter-chips.tsx +42 -0
  652. package/src/components/files/frontmatter-panel.tsx +6 -71
  653. package/src/components/files/staleness.ts +29 -0
  654. package/src/components/graph/graph-canvas.tsx +24 -1
  655. package/src/components/graph/graph-controls-column.tsx +92 -0
  656. package/src/components/graph/graph-controls.tsx +83 -127
  657. package/src/components/graph/graph-form.tsx +183 -0
  658. package/src/components/graph/graph-maintenance.tsx +9 -14
  659. package/src/components/graph/graph-node-rail.tsx +147 -0
  660. package/src/components/graph/graph-page.tsx +189 -49
  661. package/src/components/graph/graph-scene.tsx +200 -30
  662. package/src/components/graph/lib/graph-helpers.ts +65 -43
  663. package/src/components/graph/node-card.tsx +64 -0
  664. package/src/components/graph/node-popover.tsx +28 -117
  665. package/src/components/graph/use-graph-theme.ts +69 -32
  666. package/src/components/graph/use-node-actions.ts +56 -0
  667. package/src/components/images/image-share.ts +4 -2
  668. package/src/components/images/image-viewer.tsx +3 -1
  669. package/src/components/images/mask-editor.tsx +7 -4
  670. package/src/components/layout/app-shell.tsx +5 -1
  671. package/src/components/layout/desktop-palette.tsx +151 -0
  672. package/src/components/layout/key-cap.tsx +15 -0
  673. package/src/components/layout/mobile-tab-bar.tsx +80 -157
  674. package/src/components/layout/shortcut-switch.tsx +32 -0
  675. package/src/components/layout/side-rail.tsx +77 -150
  676. package/src/components/layout/slide-panel.tsx +49 -6
  677. package/src/components/layout/theme.tsx +67 -0
  678. package/src/components/quick-actions/add-form.tsx +196 -0
  679. package/src/components/quick-actions/add-modal.tsx +32 -153
  680. package/src/components/quick-actions/search-modal.tsx +15 -5
  681. package/src/components/quick-actions/streaming-modal.tsx +57 -72
  682. package/src/components/quick-actions/streaming-output.tsx +112 -0
  683. package/src/components/quick-actions/whatsup-modal.tsx +53 -59
  684. package/src/components/settings/devices-agents-tab.tsx +60 -152
  685. package/src/components/settings/models-list.tsx +299 -0
  686. package/src/components/settings/models-tab.tsx +63 -337
  687. package/src/components/settings/one-time-agent-credential.tsx +1 -1
  688. package/src/components/settings/passkey-list.tsx +201 -0
  689. package/src/components/settings/passkey-tab.tsx +53 -197
  690. package/src/components/settings/pi-accounts-list.tsx +128 -0
  691. package/src/components/settings/pi-accounts.tsx +71 -170
  692. package/src/components/settings/principal-list.tsx +172 -0
  693. package/src/components/settings/settings-panel.tsx +239 -25
  694. package/src/components/settings/skills-list.tsx +276 -0
  695. package/src/components/settings/skills-tab.tsx +82 -269
  696. package/src/components/settings/tool-permissions-list.tsx +54 -0
  697. package/src/components/settings/tool-permissions.tsx +27 -46
  698. package/src/components/settings/web-search-chain.tsx +300 -0
  699. package/src/components/settings/web-search-settings.tsx +58 -328
  700. package/src/components/share/share-menu.tsx +19 -4
  701. package/src/components/voice/dictation-sheet.tsx +5 -5
  702. package/src/components/voice/mic-button.tsx +1 -1
  703. package/src/components/voice/review-card.tsx +1 -1
  704. package/src/config.ts +21 -7
  705. package/src/connection.ts +443 -0
  706. package/src/default-root.ts +16 -0
  707. package/src/hooks/use-color-scheme.ts +36 -0
  708. package/src/hooks/use-fine-pointer.ts +15 -0
  709. package/src/hooks/use-hash-routes.ts +4 -2
  710. package/src/hooks/use-media-query.ts +35 -0
  711. package/src/hooks/use-share-intake.ts +32 -12
  712. package/src/hooks/use-vpn-status.ts +18 -17
  713. package/src/hooks/use-websocket.ts +12 -428
  714. package/src/hooks/websocket-handlers/activity.ts +4 -5
  715. package/src/hooks/websocket-handlers/chat.ts +28 -6
  716. package/src/hooks/websocket-handlers/connection.ts +4 -6
  717. package/src/hooks/websocket-handlers/mask.ts +2 -3
  718. package/src/hooks/websocket-handlers/provider.ts +4 -6
  719. package/src/hooks/websocket-handlers/types.ts +6 -2
  720. package/src/index.ts +7 -3
  721. package/src/lib/api-client.ts +426 -384
  722. package/src/lib/backend.ts +20 -10
  723. package/src/lib/diff.ts +28 -62
  724. package/src/lib/light-dark.ts +83 -0
  725. package/src/lib/mermaid-theme.ts +183 -214
  726. package/src/lib/passkeys.ts +12 -4
  727. package/src/lib/push-registration.ts +19 -2
  728. package/src/lib/share-intake.ts +6 -3
  729. package/src/lib/share.ts +7 -4
  730. package/src/lib/single-key.ts +47 -0
  731. package/src/lib/tool-names.ts +31 -8
  732. package/src/root-context.tsx +40 -0
  733. package/src/root.ts +83 -0
  734. package/src/stores/activity-state.ts +295 -0
  735. package/src/stores/activity-store.ts +11 -285
  736. package/src/stores/chat-state.ts +822 -0
  737. package/src/stores/chat-store.ts +11 -705
  738. package/src/stores/connection-state.ts +78 -0
  739. package/src/stores/connection-store.ts +11 -76
  740. package/src/stores/create-stores.ts +31 -0
  741. package/src/stores/file-state.ts +399 -0
  742. package/src/stores/file-store.ts +9 -390
  743. package/src/stores/graph-state.ts +368 -0
  744. package/src/stores/graph-store.ts +10 -355
  745. package/src/stores/mask-state.ts +30 -0
  746. package/src/stores/mask-store.ts +10 -27
  747. package/src/stores/principal-state.ts +42 -0
  748. package/src/stores/principal-store.ts +10 -37
  749. package/src/stores/provider-state.ts +103 -0
  750. package/src/stores/provider-store.ts +10 -95
  751. package/src/stores/share-state.ts +56 -0
  752. package/src/stores/share-store.ts +11 -54
  753. package/src/stores/store-environment.ts +10 -0
  754. package/src/stores/ui-state.ts +143 -0
  755. package/src/stores/ui-store.ts +11 -93
  756. package/src/styles.css +4 -1
  757. package/src/theme.css +150 -97
  758. package/src/voice/asr-clients.ts +17 -17
  759. package/src/voice/use-dictation.ts +11 -8
  760. package/src/voice/voice-state.ts +57 -0
  761. package/src/voice/voice-store.ts +11 -55
@@ -1,4 +1,5 @@
1
- import { useCallback, useEffect } from "react";
1
+ import { useBrainUiRoot } from "../root-context.js";
2
+ import { useCallback, useEffect, useRef } from "react";
2
3
  import {
3
4
  SHARE_STASH_TTL_MS,
4
5
  type ShareIntakeResult,
@@ -9,8 +10,6 @@ import {
9
10
  readShareLaunchParams,
10
11
  type StoredShare,
11
12
  } from "@schlessera/brain-ui-sdk/share-target";
12
- import { useChatStore } from "../stores/chat-store.js";
13
- import { useConnectionStore } from "../stores/connection-store.js";
14
13
  import { useShareStore } from "../stores/share-store.js";
15
14
  import { detectClientEnvironment } from "../lib/client-environment.js";
16
15
  import {
@@ -23,7 +22,6 @@ import {
23
22
  shareImagesToAttachments,
24
23
  uploadShare,
25
24
  } from "../lib/share-intake.js";
26
- import { sendClientMessage } from "./use-websocket.js";
27
25
 
28
26
  /**
29
27
  * Pick up shares the service worker stashed, and file them once confirmed.
@@ -66,6 +64,13 @@ export function useShareIntake(): {
66
64
  confirm: (record: StoredShare) => Promise<void>;
67
65
  dismiss: (record: StoredShare) => void;
68
66
  } {
67
+ const root = useBrainUiRoot();
68
+ const lifetime = useRef(new AbortController());
69
+ useEffect(() => {
70
+ const controller = new AbortController();
71
+ lifetime.current = controller;
72
+ return () => controller.abort();
73
+ }, [root]);
69
74
  const enqueue = useShareStore((s) => s.enqueue);
70
75
  const remove = useShareStore((s) => s.remove);
71
76
  const setBusy = useShareStore((s) => s.setBusy);
@@ -82,8 +87,12 @@ export function useShareIntake(): {
82
87
  try {
83
88
  for (const id of claimed) {
84
89
  const record = await store.take(id);
90
+ if (disposed) {
91
+ if (record) await store.put(record);
92
+ return;
93
+ }
85
94
  dropShareClaim(id);
86
- if (record && !disposed) enqueue(record);
95
+ if (record) enqueue(record);
87
96
  }
88
97
 
89
98
  // Orphans: a share whose landing page never ran (the app opened
@@ -91,8 +100,13 @@ export function useShareIntake(): {
91
100
  // parameter was read) leaves a record nobody holds the id for. The
92
101
  // stash is the only place it still exists.
93
102
  for (const record of await store.list()) {
103
+ if (disposed) return;
94
104
  const taken = await store.take(record.id);
95
- if (taken && !disposed) enqueue(taken);
105
+ if (disposed) {
106
+ if (taken) await store.put(taken);
107
+ return;
108
+ }
109
+ if (taken) enqueue(taken);
96
110
  }
97
111
 
98
112
  // The service worker's own prune runs after a stash, so it can never
@@ -112,9 +126,10 @@ export function useShareIntake(): {
112
126
 
113
127
  const confirm = useCallback(
114
128
  async (record: StoredShare) => {
115
- const share = useShareStore.getState();
129
+ const signal = lifetime.current.signal;
130
+ const share = root.stores.share.getState();
116
131
  if (share.busy) return;
117
- if (useConnectionStore.getState().wsStatus !== "connected") {
132
+ if (root.stores.connection.getState().wsStatus !== "connected") {
118
133
  setError("Not connected yet — this will work as soon as the app reconnects.");
119
134
  return;
120
135
  }
@@ -123,17 +138,22 @@ export function useShareIntake(): {
123
138
  setError(null);
124
139
  setNotes([]);
125
140
  try {
126
- const outcome = await uploadShare(record);
141
+ const outcome = await uploadShare(record, root.request, root.apiBase(), signal);
142
+ if (signal.aborted) return;
127
143
  if (!outcome.ok) {
128
144
  setError(describeUploadError(outcome));
129
145
  return;
130
146
  }
131
147
 
132
148
  const { attachments, errors } = await shareImagesToAttachments(record.files);
149
+ if (signal.aborted) {
150
+ for (const attachment of attachments) URL.revokeObjectURL(attachment.previewUrl);
151
+ return;
152
+ }
133
153
  if (errors.length) setNotes(errors);
134
154
 
135
155
  const prompt = buildSharePrompt(outcome.result as ShareIntakeResult);
136
- const chat = useChatStore.getState();
156
+ const chat = root.stores.chat.getState();
137
157
  // Always start from a fresh draft: `activeSessionId` is restored from
138
158
  // localStorage at store creation, so on a cold boot it already points
139
159
  // at whatever session was last open.
@@ -153,7 +173,7 @@ export function useShareIntake(): {
153
173
  );
154
174
  chat.startAssistantMessage(null);
155
175
 
156
- const sent = sendClientMessage({
176
+ const sent = root.connection.send({
157
177
  type: "chat_message",
158
178
  text: prompt,
159
179
  ...(attachments.length
@@ -172,7 +192,7 @@ export function useShareIntake(): {
172
192
  setBusy(false);
173
193
  }
174
194
  },
175
- [remove, setBusy, setError, setNotes]
195
+ [remove, setBusy, setError, setNotes, root]
176
196
  );
177
197
 
178
198
  const dismiss = useCallback(
@@ -1,21 +1,21 @@
1
+ import { defaultRoot } from "../default-root.js";
2
+ import { useBrainUiRoot } from "../root-context.js";
3
+ import type { BrainUiRoot } from "../root.js";
1
4
  import { useEffect, useState } from "react";
2
5
  import {
3
- useConnectionStore,
4
6
  type VpnStatus,
5
7
  } from "../stores/connection-store.js";
6
- import { getBackendUrl } from "../lib/backend.js";
7
8
 
8
9
  const POLL_INTERVAL = 15_000;
9
10
  // Tighter cadence while offline so recovery is near-immediate
10
11
  const OFFLINE_POLL_INTERVAL = 3_000;
11
12
  const TIMEOUT_MS = 5_000;
12
- let activeRecheck: (() => void) | null = null;
13
13
 
14
- async function fetchVpnStatus(): Promise<VpnStatus> {
14
+ async function fetchVpnStatus(root: BrainUiRoot): Promise<VpnStatus> {
15
15
  const controller = new AbortController();
16
16
  const timeout = setTimeout(() => controller.abort(), TIMEOUT_MS);
17
17
  try {
18
- const res = await fetch(getBackendUrl("/api/vpn-check"), {
18
+ const res = await root.request(root.backendUrl("/api/vpn-check"), {
19
19
  signal: controller.signal,
20
20
  });
21
21
 
@@ -35,11 +35,12 @@ async function fetchVpnStatus(): Promise<VpnStatus> {
35
35
  * the only writer of vpnStatus and serializes this with its scheduled checks.
36
36
  */
37
37
  export function recheckVpnStatus(): void {
38
- activeRecheck?.();
38
+ defaultRoot.recheckVpn?.();
39
39
  }
40
40
 
41
41
  export function useVpnStatus() {
42
- const [successfulProbeCount, setSuccessfulProbeCount] = useState(0);
42
+ const root = useBrainUiRoot();
43
+ const [successfulProbe, setSuccessfulProbe] = useState({ root, count: 0 });
43
44
 
44
45
  useEffect(() => {
45
46
  let timer: ReturnType<typeof setTimeout> | undefined;
@@ -54,20 +55,20 @@ export function useVpnStatus() {
54
55
  return;
55
56
  }
56
57
  inFlight = true;
57
- const opensAtStart = useConnectionStore.getState().socketOpens;
58
+ const opensAtStart = root.stores.connection.getState().socketOpens;
58
59
  try {
59
- const status = await fetchVpnStatus();
60
+ const status = await fetchVpnStatus(root);
60
61
  // A socket that reached `open` while this probe was in flight is newer
61
62
  // reachability evidence than a failure the probe was started for.
62
63
  // Counting opens rather than sampling wsStatus twice also catches a
63
64
  // drop and a replacement open inside one probe, where both samples
64
65
  // read "connected".
65
66
  const socketOpenedDuringCheck =
66
- useConnectionStore.getState().socketOpens !== opensAtStart;
67
+ root.stores.connection.getState().socketOpens !== opensAtStart;
67
68
  if (!disposed && !(socketOpenedDuringCheck && status !== "connected")) {
68
- useConnectionStore.getState().setVpnStatus(status);
69
+ root.stores.connection.getState().setVpnStatus(status);
69
70
  if (status === "connected") {
70
- setSuccessfulProbeCount((count) => count + 1);
71
+ setSuccessfulProbe((previous) => ({ root, count: previous.root === root ? previous.count + 1 : 1 }));
71
72
  }
72
73
  }
73
74
  } finally {
@@ -78,7 +79,7 @@ export function useVpnStatus() {
78
79
  recheckRequested = false;
79
80
  void check();
80
81
  } else {
81
- const status = useConnectionStore.getState().vpnStatus;
82
+ const status = root.stores.connection.getState().vpnStatus;
82
83
  // Auth required but no valid session is still a reachable server.
83
84
  const reachable = status === "connected" || status === "unauthorized";
84
85
  timer = setTimeout(
@@ -93,7 +94,7 @@ export function useVpnStatus() {
93
94
  // Re-check immediately when the network returns or the PWA is foregrounded
94
95
  // instead of waiting out the poll interval.
95
96
  const recheckNow = () => void check();
96
- activeRecheck = recheckNow;
97
+ const removeRecheck = root.registerVpnRecheck(recheckNow);
97
98
  const onVisible = () => {
98
99
  if (document.visibilityState === "visible") void check();
99
100
  };
@@ -105,11 +106,11 @@ export function useVpnStatus() {
105
106
  return () => {
106
107
  disposed = true;
107
108
  clearTimeout(timer);
108
- if (activeRecheck === recheckNow) activeRecheck = null;
109
+ removeRecheck();
109
110
  window.removeEventListener("online", recheckNow);
110
111
  document.removeEventListener("visibilitychange", onVisible);
111
112
  };
112
- }, []);
113
+ }, [root]);
113
114
 
114
- return successfulProbeCount;
115
+ return successfulProbe.root === root ? successfulProbe.count : 0;
115
116
  }
@@ -1,434 +1,18 @@
1
- import { useEffect, useRef, useCallback } from "react";
2
- import {
3
- BrainUiClient,
4
- type WebSocketClose,
5
- } from "@schlessera/brain-ui-sdk/client";
6
- import { useConnectionStore } from "../stores/connection-store.js";
7
- import { useChatStore, activeChat, type ChatKey } from "../stores/chat-store.js";
8
- import { useActivityStore, loadSessionActivityHistory } from "../stores/activity-store.js";
9
- import { getWsUrl } from "../lib/backend.js";
10
- import type {
11
- ServerMessage,
12
- ClientMessage,
13
- ServerLocationRequest,
14
- } from "@schlessera/brain-ui-sdk/protocol";
15
- import { dispatchServerMessage } from "./websocket-handlers/index.js";
16
- import { runStateForFrame } from "./websocket-handlers/chat.js";
17
- import { recheckVpnStatus } from "./use-vpn-status.js";
18
- import { REFUSAL_ATTEMPTS } from "../components/connectivity/connection-state.js";
19
-
1
+ import { useEffect, useCallback } from "react";
2
+ import type { ClientMessage, ServerMessage } from "@schlessera/brain-ui-sdk/protocol";
3
+ import { defaultRoot } from "../default-root.js";
4
+ import { useBrainUiRoot } from "../root-context.js";
20
5
  export { runStateForFrame } from "./websocket-handlers/chat.js";
21
6
 
22
- /**
23
- * Does this frame announce the identity of the conversation THIS client just
24
- * started?
25
- *
26
- * The old test was `session_info || result` for any unknown session, which
27
- * adopted whichever arrived first — an older background turn finishing, or
28
- * another client's new session, would capture the user's draft and bind it to
29
- * a transcript they never wrote. `draftId` is minted per draft turn and echoed
30
- * on `session_info`, so a match is proof.
31
- *
32
- * A server too old to echo it sends no `draftId`, and the pre-existing
33
- * behaviour applies rather than the draft never binding at all: correctness
34
- * where the information exists, compatibility where it does not.
35
- */
36
- function isOurDraftAnnouncement(
37
- state: ReturnType<typeof useChatStore.getState>,
38
- msg: ServerMessage
39
- ): boolean {
40
- // A terminal result has no draft correlation. Another client's turn may
41
- // finish before our session_info arrives, so it can never claim our draft.
42
- if (msg.type !== "session_info") return false;
43
- const pending = state.pendingDraftId;
44
- if (msg.draftId) return msg.draftId === pending;
45
- // No echo to compare against.
46
- return true;
47
- }
48
-
49
- /**
50
- * Lazily open a session-scoped activity subscription (live subagent rows,
51
- * server-stamped tool timing). Idempotent per connection; the subscribed set
52
- * resets when a new socket's server_hello arrives.
53
- */
54
- function ensureActivitySubscription(sessionId: string | null | undefined): void {
55
- if (!sessionId) return;
56
- const activity = useActivityStore.getState();
57
- if (!activity.supported || activity.subscribed[sessionId]) return;
58
- activity.markSubscribed(sessionId);
59
- wsClient?.send({ type: "activity_subscribe", view: "session", sessionId });
60
- // The subscription snapshot carries OPEN runs; finished runs (history
61
- // timing, past fan-outs) come from the REST side.
62
- void loadSessionActivityHistory(sessionId);
63
- }
64
-
65
- /**
66
- * Text and thinking deltas waiting to be applied, per buffer.
67
- *
68
- * A model streams tokens far faster than the display refreshes, and each socket
69
- * frame arrives in its own macrotask, so React cannot batch them: one token was
70
- * one store write, one render and one markdown re-parse of the growing message.
71
- * Coalescing a frame's worth of tokens into a single write costs nothing
72
- * visually — the screen could not have shown the intermediate states anyway.
73
- *
74
- * Consecutive same-kind chunks merge, so a burst of text becomes ONE appendText
75
- * rather than one per token. Kind changes start a new chunk, which is what keeps
76
- * interleaved thinking and text in their true chronological order.
77
- */
78
- type PendingDelta = { kind: "text" | "thinking"; text: string };
79
- const pendingDeltas = new Map<ChatKey, PendingDelta[]>();
80
- let flushScheduled = false;
81
-
82
- /**
83
- * Apply every buffered delta, in arrival order, and clear the buffer.
84
- *
85
- * Exported so tests can force the frame rather than wait for one; production
86
- * code never needs to call it, because every path that reads the transcript
87
- * flushes first.
88
- */
89
- export function flushChatDeltas(): void {
90
- flushDeltas();
91
- }
92
-
93
- function flushDeltas(): void {
94
- flushScheduled = false;
95
- if (pendingDeltas.size === 0) return;
96
- const batches = [...pendingDeltas.entries()];
97
- pendingDeltas.clear();
98
- const state = useChatStore.getState();
99
- for (const [key, chunks] of batches) {
100
- for (const chunk of chunks) {
101
- if (chunk.kind === "text") state.appendText(key, chunk.text);
102
- else state.appendThinking(key, chunk.text);
103
- }
104
- }
105
- }
106
-
107
- function enqueueDelta(key: ChatKey, kind: PendingDelta["kind"], text: string): void {
108
- const chunks = pendingDeltas.get(key);
109
- if (!chunks) {
110
- pendingDeltas.set(key, [{ kind, text }]);
111
- } else {
112
- const last = chunks[chunks.length - 1];
113
- if (last.kind === kind) last.text += text;
114
- else chunks.push({ kind, text });
115
- }
116
- // Outside a browser (unit tests, SSR) there is no frame to wait for, so apply
117
- // straight away and keep the handler's behaviour synchronous.
118
- if (typeof requestAnimationFrame !== "function") {
119
- flushDeltas();
120
- return;
121
- }
122
- if (!flushScheduled) {
123
- flushScheduled = true;
124
- requestAnimationFrame(flushDeltas);
125
- }
126
- }
127
-
128
- export function handleServerMessage(msg: ServerMessage) {
129
- // Every frame that is not itself a delta must see the transcript fully
130
- // applied: the demux below reads buffer state, and the store records parts in
131
- // arrival order, so a tool call landing ahead of buffered text would reorder
132
- // the message.
133
- if (msg.type !== "text_delta" && msg.type !== "thinking_delta") flushDeltas();
134
-
135
- const state = useChatStore.getState();
136
-
137
- // Activity stream frames feed their own store and never touch chat state.
138
- if (
139
- msg.type === "server_hello" ||
140
- msg.type === "activity_snapshot" ||
141
- msg.type === "activity_delta"
142
- ) {
143
- const key = state.activeSessionId;
144
- dispatchServerMessage(msg, {
145
- state,
146
- frameSessionId: undefined,
147
- key,
148
- buffer: () => (key === null ? state.draft : state.buffers[key]),
149
- enqueueDelta,
150
- ensureActivitySubscription,
151
- requestBrowserLocation,
152
- resyncIfNeeded,
153
- coldResumeIfNeeded,
154
- markHistoryReplaced,
155
- });
156
- return;
157
- }
158
-
159
- // Parallel-session demux (per-session buffers). Every frame is scoped by
160
- // sessionId; a scoped frame lands in ITS session's buffer, so a background
161
- // session's transcript keeps accumulating while another one is in view.
162
- // Frames without a sessionId (legacy single-session servers, or a new
163
- // session's pre-binding frames) apply to the buffer in view.
164
- const frameSessionId = (msg as { sessionId?: string }).sessionId;
165
- if (frameSessionId) {
166
- // `detail` on a queued status is the host's queue-pressure note; it rides
167
- // along so the session's badge can show WHY it is queued deep.
168
- const queueNote =
169
- msg.type === "status" && msg.status === "queued" ? msg.detail : undefined;
170
- state.setRunState(frameSessionId, runStateForFrame(msg), queueNote);
171
- }
172
-
173
- // Resolve the target buffer key for this frame.
174
- let key: ChatKey;
175
- if (!frameSessionId) {
176
- key = state.activeSessionId; // null = the draft view
177
- } else if (state.buffers[frameSessionId]) {
178
- key = frameSessionId;
179
- } else if (state.draft && isOurDraftAnnouncement(state, msg)) {
180
- // A draft run just got its server identity: adopt the draft buffer.
181
- state.bindDraftSession(frameSessionId);
182
- key = frameSessionId;
183
- } else if (msg.type === "session_info" && frameSessionId === state.activeSessionId) {
184
- // The ACTIVE session announced itself but has no buffer yet — the cold
185
- // reattach case (PWA relaunch mid-turn; the server may skip the history
186
- // frame when a first turn has no history yet). Materialize the buffer so
187
- // this session_info and every following delta land instead of vanishing.
188
- state.setActiveSession(frameSessionId);
189
- key = frameSessionId;
190
- } else if (msg.type === "session_history") {
191
- // History replay may create a buffer (cold resume / reattach).
192
- key = frameSessionId;
193
- } else {
194
- // Scoped frame for a session with no buffer (never opened, or evicted):
195
- // the badge above is all we track. The transcript heals via
196
- // session_resume when the user opens it.
197
- return;
198
- }
199
-
200
- const buffer = () => {
201
- const s = useChatStore.getState();
202
- return key === null ? s.draft : s.buffers[key];
203
- };
204
-
205
- dispatchServerMessage(msg, {
206
- state,
207
- frameSessionId,
208
- key,
209
- buffer,
210
- enqueueDelta,
211
- ensureActivitySubscription,
212
- requestBrowserLocation,
213
- resyncIfNeeded,
214
- coldResumeIfNeeded,
215
- markHistoryReplaced,
216
- });
217
- }
218
-
219
- /**
220
- * The server asked the browser for its location (the agent called
221
- * `get_current_location`). Read `navigator.geolocation` and reply over the same
222
- * requestId. The browser shows its own permission prompt on first use; a denial,
223
- * timeout, or unavailable position comes back as a `location_error` that the
224
- * server turns into a tool error for the agent.
225
- */
226
- function requestBrowserLocation(msg: ServerLocationRequest) {
227
- const { requestId } = msg;
228
- if (typeof navigator === "undefined" || !navigator.geolocation) {
229
- wsClient?.send({
230
- type: "location_error",
231
- requestId,
232
- code: 0,
233
- message: "Geolocation is not available in this browser.",
234
- });
235
- return;
236
- }
237
- const opts = msg.options ?? {};
238
- navigator.geolocation.getCurrentPosition(
239
- (pos) => {
240
- wsClient?.send({
241
- type: "location_response",
242
- requestId,
243
- coords: {
244
- latitude: pos.coords.latitude,
245
- longitude: pos.coords.longitude,
246
- accuracy: pos.coords.accuracy,
247
- altitude: pos.coords.altitude,
248
- altitudeAccuracy: pos.coords.altitudeAccuracy,
249
- heading: pos.coords.heading,
250
- speed: pos.coords.speed,
251
- },
252
- timestamp: pos.timestamp,
253
- });
254
- },
255
- (err) => {
256
- wsClient?.send({
257
- type: "location_error",
258
- requestId,
259
- code: err.code,
260
- message: err.message || "Failed to retrieve location.",
261
- });
262
- },
263
- {
264
- enableHighAccuracy: opts.enableHighAccuracy ?? false,
265
- timeout: opts.timeoutMs ?? 15000,
266
- maximumAge: opts.maximumAgeMs ?? 60000,
267
- }
268
- );
269
- }
270
-
271
- // Reconnection bookkeeping: after a WS drop, the rendered transcript may have
272
- // gaps (deltas streamed while offline are lost). We heal by replaying the
273
- // authoritative session history — immediately if nothing is streaming, or
274
- // once the in-flight turn settles (result / idle status). The pending resync
275
- // is keyed to the session that needs healing (the one that was active at the
276
- // reconnect), so a background session settling first cannot consume it.
277
- let wasDisconnected = false;
278
- let resyncSessionId: string | null = null;
279
-
280
- function handleSocketClose(close: WebSocketClose): void {
281
- const connection = useConnectionStore.getState();
282
- connection.recordWsClose(close.opened, close.code);
283
- if (
284
- !close.opened &&
285
- useConnectionStore.getState().handshakeFailures >= REFUSAL_ATTEMPTS
286
- ) {
287
- recheckVpnStatus();
288
- }
289
- }
290
-
291
- function resyncIfNeeded(sessionId: string | null) {
292
- if (!resyncSessionId || !sessionId || sessionId !== resyncSessionId) return;
293
- resyncSessionId = null;
294
- wsClient?.send({ type: "session_resume", sessionId });
295
- }
296
-
297
- // A cold page / PWA relaunch restores only the stored session id, not the
298
- // transcript. The server pushes a snapshot on connect only while a session is
299
- // actively running; when it's idle (the common "agent finished while the phone
300
- // slept" case) nothing arrives, so the client must fetch the finished
301
- // session's history itself. Guarded to fire at most once per session id per
302
- // connection — an empty session would otherwise re-trigger on every idle
303
- // status and loop.
304
- let coldResumedSessionId: string | null = null;
305
-
306
- function markHistoryReplaced(key: ChatKey): void {
307
- if (key !== null && key === resyncSessionId) resyncSessionId = null;
308
- coldResumedSessionId = key;
309
- }
310
-
311
- function coldResumeIfNeeded(sessionId: string | null, messageCount: number) {
312
- if (!sessionId || messageCount > 0) return;
313
- if (coldResumedSessionId === sessionId) return;
314
- coldResumedSessionId = sessionId;
315
- wsClient?.send({ type: "session_resume", sessionId });
316
- }
317
-
318
- function handleStatusChange(status: "connecting" | "connected" | "disconnected") {
319
- useConnectionStore.getState().setWsStatus(status);
320
-
321
- if (status === "connected") {
322
- useConnectionStore.getState().noteSocketOpen();
323
- }
324
-
325
- // A status change can be followed by a history replay that rewrites the
326
- // buffer, so land whatever is still buffered before anything reads it. In a
327
- // hidden tab requestAnimationFrame does not run at all, which is exactly the
328
- // case where deltas could otherwise sit unapplied across a reconnect.
329
- flushDeltas();
330
-
331
- if (status === "disconnected") {
332
- wasDisconnected = true;
333
- // Allow a fresh cold-resume attempt after we reconnect.
334
- coldResumedSessionId = null;
335
- } else if (status === "connected" && wasDisconnected) {
336
- wasDisconnected = false;
337
- const chat = useChatStore.getState();
338
- const active = activeChat(chat);
339
- if (chat.activeSessionId && active.messages.length > 0) {
340
- resyncSessionId = chat.activeSessionId;
341
- // Not mid-stream: replay right away. Mid-stream: the flag holds until
342
- // the running turn finishes (result or idle status).
343
- if (!active.isStreaming) {
344
- resyncIfNeeded(chat.activeSessionId);
345
- }
346
- }
347
- }
348
- }
349
-
350
- // Singleton client - survives React re-renders
351
- let wsClient: BrainUiClient | null = null;
352
-
353
- /**
354
- * Send on the live socket from outside a component.
355
- *
356
- * `useWebSocket()` OWNS the socket — its construction guard is a per-instance
357
- * ref, so a second caller would build a second client, overwrite this
358
- * singleton, and orphan the first; unmounting either one would then close the
359
- * socket for both. Anything that needs to send but not to own (the share
360
- * intake) goes through here instead of calling the hook again.
361
- *
362
- * Returns false when there is no open socket: `send` drops silently in that
363
- * case and a caller that just staged an upload needs to know.
364
- */
365
- export function sendClientMessage(msg: ClientMessage): boolean {
366
- if (!wsClient) return false;
367
- if (useConnectionStore.getState().wsStatus !== "connected") return false;
368
- wsClient.send(msg);
369
- return true;
370
- }
371
-
372
- /** Retry the singleton socket immediately, skipping any remaining backoff. */
373
- export function reconnectWebSocketNow(): void {
374
- wsClient?.reconnectNow();
375
- }
7
+ /** Default-app entry points for callers outside React. */
8
+ export function handleServerMessage(message: ServerMessage) { defaultRoot.connection.handleServerMessage(message); }
9
+ export function flushChatDeltas() { defaultRoot.connection.flushChatDeltas(); }
10
+ export function sendClientMessage(message: ClientMessage) { return defaultRoot.connection.send(message); }
11
+ export function reconnectWebSocketNow() { defaultRoot.connection.reconnectNow(); }
376
12
 
377
13
  export function useWebSocket() {
378
- const initialized = useRef(false);
379
-
380
- useEffect(() => {
381
- if (initialized.current) return;
382
- initialized.current = true;
383
- let disposed = false;
384
- useConnectionStore.getState().noteSocketOpen();
385
-
386
- wsClient = new BrainUiClient({
387
- url: getWsUrl(),
388
- // One handler with a shared preamble, rather than sixteen copies of the
389
- // session-buffer demux — see handleServerMessage.
390
- handlers: { onAny: handleServerMessage },
391
- onStatusChange: handleStatusChange,
392
- onClose: (close) => {
393
- if (!disposed) handleSocketClose(close);
394
- },
395
- // A frame the SDK refused. Surfaced rather than logged into a console
396
- // nobody is attached to; the server-side counterpart is the
397
- // ws.frames.dropped counter.
398
- onProtocolError: (err) => {
399
- useConnectionStore
400
- .getState()
401
- .reportError(
402
- "PROTOCOL_ERROR",
403
- err.frameType
404
- ? `Dropped a ${err.frameType} frame: ${err.detail}`
405
- : `Dropped an unreadable frame: ${err.detail}`
406
- );
407
- },
408
- });
409
- wsClient.connect();
410
-
411
- // Skip the exponential backoff when the network demonstrably returns.
412
- const reconnectNow = () => wsClient?.reconnectNow();
413
- const onVisible = () => {
414
- if (document.visibilityState === "visible") wsClient?.reconnectNow();
415
- };
416
- window.addEventListener("online", reconnectNow);
417
- document.addEventListener("visibilitychange", onVisible);
418
-
419
- return () => {
420
- disposed = true;
421
- window.removeEventListener("online", reconnectNow);
422
- document.removeEventListener("visibilitychange", onVisible);
423
- wsClient?.close();
424
- wsClient = null;
425
- initialized.current = false;
426
- };
427
- }, []);
428
-
429
- const send = useCallback((msg: ClientMessage) => {
430
- wsClient?.send(msg);
431
- }, []);
432
-
14
+ const root = useBrainUiRoot();
15
+ useEffect(() => root.connection.connect(), [root]);
16
+ const send = useCallback((message: ClientMessage) => root.connection.send(message), [root]);
433
17
  return { send };
434
18
  }
@@ -1,13 +1,12 @@
1
- import { useActivityStore } from "../../stores/activity-store.js";
2
1
  import type { ServerMessageHandlerMap } from "./types.js";
3
2
 
4
3
  type ActivityFrame = "activity_snapshot" | "activity_delta";
5
4
 
6
5
  export const activityFrameHandlers = {
7
- activity_snapshot: (msg) => {
8
- useActivityStore.getState().applySnapshot(msg);
6
+ activity_snapshot: (msg, context) => {
7
+ context.stores.activity.getState().applySnapshot(msg);
9
8
  },
10
- activity_delta: (msg) => {
11
- useActivityStore.getState().applyDelta(msg);
9
+ activity_delta: (msg, context) => {
10
+ context.stores.activity.getState().applyDelta(msg);
12
11
  },
13
12
  } satisfies ServerMessageHandlerMap<ActivityFrame>;