@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,12 +1,29 @@
1
1
  import { Suspense, lazy, useEffect } from "react";
2
+ import { Button, Label, Receipt, ScreenHeader } from "@schlessera/brain-ui-kit";
3
+ import type { ReceiptRow } from "@schlessera/brain-ui-kit";
2
4
  import { ChevronDown, ChevronRight, X } from "lucide-react";
3
5
  import { useFileStore } from "../../stores/file-store.js";
6
+ import { singleKey } from "../../lib/single-key.js";
7
+ import { useUIStore } from "../../stores/ui-store.js";
4
8
  import { useDeferredUnmount } from "../../hooks/use-deferred-unmount.js";
9
+ import { useMediaQuery } from "../../hooks/use-media-query.js";
10
+ import { splitFrontmatter } from "../../lib/frontmatter.js";
5
11
  import { cn } from "../../lib/utils.js";
12
+ import { formatSize } from "./file-viewer-frame.js";
13
+ import { DisabledToggleRow } from "../graph/graph-form.js";
14
+ import { STALE_AFTER_DAYS, ageInDays, formatAge } from "./staleness.js";
6
15
 
7
16
  /** Matches the `duration-300` slide-out below. */
8
17
  const SLIDE_OUT_MS = 300;
9
18
 
19
+ /**
20
+ * The `laptop:` breakpoint from `theme.css`. From here up the rail is
21
+ * expanded and the design's D3 draws Files as panes beside it; below, the
22
+ * drawer. Read as a media query rather than a class pair so only one of the
23
+ * two shapes is mounted — two would mean two file trees on the store.
24
+ */
25
+ const PANES_QUERY = "(min-width: 900px)";
26
+
10
27
  /**
11
28
  * The tree and the viewers load the first time the panel is opened. Together
12
29
  * they carry the markdown, HTML, image and PDF viewers, none of which the chat
@@ -20,6 +37,7 @@ export function FilePanel({ open, onClose }: { open: boolean; onClose: () => voi
20
37
  const treeExpanded = useFileStore((s) => s.treeExpanded);
21
38
  const setTreeExpanded = useFileStore((s) => s.setTreeExpanded);
22
39
  const closeFile = useFileStore((s) => s.closeFile);
40
+ const panes = useMediaQuery(PANES_QUERY);
23
41
 
24
42
  useEffect(() => {
25
43
  if (!open) return;
@@ -55,6 +73,10 @@ export function FilePanel({ open, onClose }: { open: boolean; onClose: () => voi
55
73
  const showContent = useDeferredUnmount(open, SLIDE_OUT_MS);
56
74
  const showTree = showContent && (!currentPath || treeExpanded);
57
75
 
76
+ if (panes) {
77
+ return open ? <FilePanes onClose={onClose} /> : null;
78
+ }
79
+
58
80
  return (
59
81
  <>
60
82
  {open && (
@@ -131,3 +153,149 @@ export function FilePanel({ open, onClose }: { open: boolean; onClose: () => voi
131
153
  </>
132
154
  );
133
155
  }
156
+
157
+ /**
158
+ * D3 (the fifth design drop): from `laptop:` up Files is
159
+ * not a drawer but a layer of panes over the content area, beside the rail —
160
+ * a 300px tree, the reading pane at a 720px measure, and from `wide:` a
161
+ * 320px evidence rail. No backdrop: the rail stays reachable, and the layer
162
+ * is the app's own surface, not a sheet over it. The host still composes
163
+ * views, so this remains the same `FilePanel` the drawer is; only the shape
164
+ * changes with the width.
165
+ *
166
+ * The tree's title carries no document count: the file store has no total,
167
+ * and the design's `4,812 docs` is not something to make up.
168
+ *
169
+ * The footer prints the keys that fire. `j` / `k` are single-key letters
170
+ * and go with the Settings off switch (D37 — a key that does not fire is
171
+ * not advertised); `← →` and `⏎` are not letters, the switch does not
172
+ * cover them, and the kit `FileRow` binds them regardless — so they print
173
+ * regardless. `FileRow` already moves focus with ↑↓ and Home/End on its
174
+ * own, so nothing here binds movement a second time.
175
+ *
176
+ * The evidence rail (sixth pass §3a): each block is independent and simply
177
+ * absent when its data does not exist, but the COLUMN stays — "a pane count
178
+ * that changes as you click through files is a worse defect than a sparse
179
+ * rail." So the rail mounts with the panes, empty until a file is open, and
180
+ * a file with no frontmatter shows only the blocks it has.
181
+ */
182
+ function FilePanes({ onClose }: { onClose: () => void }) {
183
+ const currentPath = useFileStore((s) => s.currentPath);
184
+ const content = useFileStore((s) => s.currentContent);
185
+ const singleKeyShortcuts = useUIStore((s) => s.singleKeyShortcuts);
186
+ const loaded = content !== null && content.path === currentPath ? content : null;
187
+
188
+ const frontmatter: ReceiptRow[] =
189
+ loaded?.kind === "markdown"
190
+ ? splitFrontmatter(loaded.content ?? "").fields.map((f) => ({
191
+ k: f.key,
192
+ v: f.list ? f.list.join(", ") : f.value || "—",
193
+ }))
194
+ : [];
195
+
196
+ // Stale (sixth pass §3b): `mtime` is on every file the server serves, in
197
+ // milliseconds; the threshold is `STALE_AFTER_DAYS`. Past it the block
198
+ // turns gold — the same tone the tree's dot wears.
199
+ const modified = loaded ? ageInDays(loaded.mtime) : null;
200
+ const stale = modified !== null && modified >= STALE_AFTER_DAYS;
201
+
202
+ return (
203
+ <div
204
+ role="dialog"
205
+ aria-label="Files"
206
+ className="fixed bottom-0 right-0 top-0 z-40 flex bg-surface tablet:left-[60px] laptop:left-[208px]"
207
+ >
208
+ {/* Tree */}
209
+ <aside className="flex w-[300px] shrink-0 flex-col border-r border-border">
210
+ <div className="shrink-0 px-4 pb-2 pt-4">
211
+ <h2 className="font-[family-name:var(--font-display)] text-[22px] leading-tight text-foreground">Files</h2>
212
+ </div>
213
+ {/* Untrusted only (sixth pass §3b): needs the provenance record —
214
+ origin, who, when — which no file carries yet. Drawn, disabled,
215
+ with its reason, never dropped: it is one of the two facts that
216
+ decide whether an answer may cite a file. */}
217
+ <div className="shrink-0 border-b border-border">
218
+ <DisabledToggleRow label="Untrusted only" reason="needs provenance" tone="purple" last />
219
+ </div>
220
+ {/* `j` / `k` move between tree items while one holds focus (D36:
221
+ focus-scoped, printed where they apply); the kit `FileRow` owns
222
+ ↑↓, Home, End and the ← → fold. */}
223
+ <div
224
+ className="min-h-0 flex-1 overflow-y-auto"
225
+ onKeyDown={(e) => {
226
+ if (!singleKeyShortcuts) return;
227
+ const key = singleKey(e);
228
+ if (key !== "j" && key !== "k") return;
229
+ const items = [...e.currentTarget.querySelectorAll<HTMLElement>('[role="treeitem"]')];
230
+ const here = items.indexOf(e.target as HTMLElement);
231
+ if (here === -1) return;
232
+ e.preventDefault();
233
+ items[(here + (key === "j" ? 1 : -1) + items.length) % items.length]?.focus();
234
+ }}
235
+ >
236
+ <Suspense fallback={null}>
237
+ <FileTree />
238
+ </Suspense>
239
+ </div>
240
+ <div className="shrink-0 border-t border-border px-4 py-2 font-[family-name:var(--font-mono)] text-[10px] text-muted-foreground">
241
+ {singleKeyShortcuts ? "j / k move · " : ""}← → fold · ⏎ open
242
+ </div>
243
+ </aside>
244
+
245
+ {/* Reading pane */}
246
+ <section className="flex min-w-0 flex-1 flex-col" aria-label={currentPath ?? "No file open"}>
247
+ <div className="flex shrink-0 items-start border-b border-border pr-3">
248
+ <div className="min-w-0 flex-1">
249
+ <ScreenHeader
250
+ variant="nav"
251
+ title={currentPath ?? "Files"}
252
+ subtitle={loaded ? formatSize(loaded.size) : undefined}
253
+ back={false}
254
+ divider={false}
255
+ />
256
+ </div>
257
+ <div className="shrink-0 pt-2">
258
+ <Button label="Close" icon="dismiss" tone="ghost" size="sm" block={false} onClick={onClose} />
259
+ </div>
260
+ </div>
261
+ <div className="min-h-0 flex-1 overflow-hidden">
262
+ <div className="mx-auto h-full w-full max-w-[720px]">
263
+ <Suspense fallback={null}>
264
+ <FileViewer />
265
+ </Suspense>
266
+ </div>
267
+ </div>
268
+ </section>
269
+
270
+ {/* Evidence rail, from `wide:` only (the four-pane rule, D37 §2).
271
+ Always in the tree once the panes are: the column never collapses. */}
272
+ <aside
273
+ aria-label="Evidence"
274
+ className="hidden w-[320px] shrink-0 flex-col gap-4 overflow-y-auto border-l border-border bg-background px-4 py-4 wide:flex"
275
+ >
276
+ {frontmatter.length > 0 && (
277
+ <div className="flex flex-col gap-2" data-rail-block="frontmatter">
278
+ <Label text="Frontmatter" icon="scope" meta={`${frontmatter.length} ${frontmatter.length === 1 ? "key" : "keys"}`} />
279
+ <Receipt rows={frontmatter} keyWidth={72} />
280
+ </div>
281
+ )}
282
+ {modified !== null && (
283
+ <div className="flex flex-col gap-2" data-rail-block="modified" data-stale={stale ? "" : undefined}>
284
+ <Label text="Modified" icon="history" tone={stale ? "gold" : undefined} meta={stale ? "stale" : undefined} />
285
+ <div
286
+ className={cn(
287
+ "font-[family-name:var(--font-mono)] text-[10px]",
288
+ stale ? "text-[var(--bk-gold-ink)]" : "text-muted-foreground"
289
+ )}
290
+ >
291
+ modified {formatAge(modified)} · {stale ? "stale past" : "stale after"} {STALE_AFTER_DAYS}
292
+ </div>
293
+ </div>
294
+ )}
295
+ {/* The design also draws "Linked from" (backlinks) and "Provenance"
296
+ (git hash, host, date) here. The app has no API for either yet,
297
+ so neither is drawn: an evidence rail shows what is known. */}
298
+ </aside>
299
+ </div>
300
+ );
301
+ }
@@ -0,0 +1,127 @@
1
+ import { FileRow, Placeholder } from "@schlessera/brain-ui-kit";
2
+ import type { FileKind } from "@schlessera/brain-ui-kit";
3
+ import { useEffect, useRef, type ReactNode } from "react";
4
+ import { cn } from "../../lib/utils.js";
5
+
6
+ /**
7
+ * The file tree's rows, rendered from props (S7, the `files` directory). The
8
+ * design's `1e` screen draws the tree out of the kit's `FileRow` — folder,
9
+ * open folder, file, image — so that is what a row is here. `FileTree` is
10
+ * the container: it subscribes each node to the file store and decides
11
+ * expansion, loading, errors and the active path; these views decide how
12
+ * that looks.
13
+ *
14
+ * `TreeRow` is ONE row. The container renders it recursively so each node
15
+ * keeps its own store subscription (a change deep in one folder re-renders
16
+ * that row, not the tree); the children arrive as `children` already
17
+ * rendered. A highlighted row (the tree was asked to reveal this folder)
18
+ * scrolls itself into view and reports when the flash has run, so the
19
+ * container can clear the request.
20
+ */
21
+ const IMAGE_EXT = new Set([".png", ".jpg", ".jpeg", ".gif", ".webp", ".svg", ".avif", ".bmp", ".ico"]);
22
+
23
+ export function fileKind(name: string, isDir: boolean, expanded: boolean): FileKind {
24
+ if (isDir) return expanded ? "open" : "folder";
25
+ const i = name.lastIndexOf(".");
26
+ const ext = i >= 0 ? name.slice(i).toLowerCase() : "";
27
+ return IMAGE_EXT.has(ext) ? "image" : "file";
28
+ }
29
+
30
+ export interface TreeRowProps {
31
+ name: string;
32
+ kind: FileKind;
33
+ depth: number;
34
+ /** The row the viewer is on. */
35
+ active: boolean;
36
+ /** A folder whose listing is in flight. */
37
+ loading: boolean;
38
+ /** The tree was asked to reveal this folder: flash it, scroll it into view. */
39
+ highlighted: boolean;
40
+ /** A folder's listing failed; shown under the row with a retry. */
41
+ error?: string;
42
+ /**
43
+ * Days since the file was modified, given only when past the staleness
44
+ * threshold (`staleness.ts`). D3 draws it as the gold left-edge dot and
45
+ * the mono `stale 38d` meta, the same two marks the design's `1e` screen
46
+ * uses; the container decides from `mtime`, the row only prints.
47
+ */
48
+ staleDays?: number;
49
+ children?: ReactNode;
50
+ onClick: () => void;
51
+ onRetry?: () => void;
52
+ onHighlightShown?: () => void;
53
+ /**
54
+ * The kit `FileRow` binds → on a closed folder to `onFold(true)` and ← on
55
+ * an open one to `onFold(false)` (sixth pass §8: the ARIA tree pattern
56
+ * requires them, and the footer prints them). Folders only.
57
+ */
58
+ onFold?: (open: boolean) => void;
59
+ }
60
+
61
+ /** How long the reveal flash runs before the request is cleared. */
62
+ export const HIGHLIGHT_MS = 1800;
63
+
64
+ export function TreeRow(p: TreeRowProps) {
65
+ const ref = useRef<HTMLDivElement>(null);
66
+ const { highlighted, onHighlightShown } = p;
67
+ useEffect(() => {
68
+ if (!highlighted || !ref.current) return;
69
+ ref.current.scrollIntoView({ behavior: "smooth", block: "center" });
70
+ const t = setTimeout(() => onHighlightShown?.(), HIGHLIGHT_MS);
71
+ return () => clearTimeout(t);
72
+ }, [highlighted, onHighlightShown]);
73
+
74
+ return (
75
+ <li>
76
+ <div ref={ref} className={cn(highlighted && "brain-tree-highlight")}>
77
+ <FileRow
78
+ label={p.name}
79
+ kind={p.kind}
80
+ depth={p.depth}
81
+ active={p.active}
82
+ meta={p.loading ? "loading…" : p.staleDays !== undefined ? `stale ${p.staleDays}d` : undefined}
83
+ metaTone={!p.loading && p.staleDays !== undefined ? "gold" : undefined}
84
+ flag={p.staleDays !== undefined ? "gold" : undefined}
85
+ onClick={p.onClick}
86
+ onFold={p.onFold}
87
+ />
88
+ </div>
89
+ {p.error ? (
90
+ <div style={{ paddingLeft: 8 + (p.depth + 1) * 22 }} className="py-1 pr-2">
91
+ <FileRow view="error" stateMessage="Folder unreadable" stateDetail={p.error} stateAction="Retry" onStateAction={p.onRetry} />
92
+ </div>
93
+ ) : null}
94
+ {p.children ? <ul>{p.children}</ul> : null}
95
+ </li>
96
+ );
97
+ }
98
+
99
+ export interface FileTreeViewProps {
100
+ /** The root listing: `loading` before it arrives, `error` when it failed, `ready` with rows. */
101
+ state: "loading" | "error" | "ready";
102
+ error?: string;
103
+ children?: ReactNode;
104
+ onRetry?: () => void;
105
+ }
106
+
107
+ export function FileTreeView(p: FileTreeViewProps) {
108
+ if (p.state === "error") {
109
+ return (
110
+ <div className="px-3 py-2">
111
+ <Placeholder variant="error" message="Files unreadable" detail={p.error} actionLabel="Retry" onAction={p.onRetry} />
112
+ </div>
113
+ );
114
+ }
115
+ if (p.state === "loading") {
116
+ return (
117
+ <div className="px-3 py-2" aria-label="Loading files">
118
+ <Placeholder variant="loading" lines={4} bordered={false} pad={4} />
119
+ </div>
120
+ );
121
+ }
122
+ return (
123
+ <ul className="py-1 text-sm" role="tree">
124
+ {p.children}
125
+ </ul>
126
+ );
127
+ }
@@ -1,21 +1,15 @@
1
- import { useEffect, useRef } from "react";
2
- import { ChevronRight, Folder, FolderOpen, FileText, FileCode, FileImage, File as FileIcon, Loader2, AlertCircle } from "lucide-react";
1
+ import { useCallback, useEffect } from "react";
3
2
  import { useFileStore } from "../../stores/file-store.js";
4
3
  import type { FileEntry } from "@schlessera/brain-ui-sdk/protocol";
5
- import { cn } from "../../lib/utils.js";
6
-
7
- const IMAGE_EXT = new Set([".png", ".jpg", ".jpeg", ".gif", ".webp", ".svg", ".avif", ".bmp", ".ico"]);
8
- const CODE_EXT = new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".py", ".rb", ".go", ".rs", ".java", ".sh", ".bash", ".css", ".html", ".json", ".yaml", ".yml", ".toml", ".sql"]);
9
-
10
- function iconForFile(name: string) {
11
- const i = name.lastIndexOf(".");
12
- const ext = i >= 0 ? name.slice(i).toLowerCase() : "";
13
- if (ext === ".md" || ext === ".markdown" || ext === ".txt") return FileText;
14
- if (IMAGE_EXT.has(ext)) return FileImage;
15
- if (CODE_EXT.has(ext)) return FileCode;
16
- return FileIcon;
17
- }
4
+ import { FileTreeView, TreeRow, fileKind } from "./file-tree-view.js";
5
+ import { ageInDays, isStale } from "./staleness.js";
18
6
 
7
+ /**
8
+ * The container (S7): every node subscribes to the file store for its own
9
+ * expansion, loading, error, active and highlight state, and renders a
10
+ * `TreeRow` with its children rendered the same way. The store owns the
11
+ * directory cache and the requests; the rows own nothing.
12
+ */
19
13
  export function FileTree() {
20
14
  const loadDir = useFileStore((s) => s.loadDir);
21
15
  const dirCache = useFileStore((s) => s.dirCache);
@@ -29,115 +23,67 @@ export function FileTree() {
29
23
 
30
24
  const rootEntries = dirCache[""];
31
25
  const rootError = dirErrors[""];
32
-
33
- if (rootError) {
34
- return (
35
- <div className="flex items-start gap-2 px-4 py-3 text-xs text-destructive">
36
- <AlertCircle className="h-4 w-4 shrink-0" />
37
- <span>{rootError}</span>
38
- </div>
39
- );
40
- }
41
-
42
- if (!rootEntries) {
43
- return (
44
- <div className="flex items-center gap-2 px-4 py-3 text-xs text-muted-foreground">
45
- <Loader2 className="h-3.5 w-3.5 animate-spin" />
46
- Loading files...
47
- </div>
48
- );
49
- }
26
+ const retryRoot = useCallback(() => void loadDir(""), [loadDir]);
50
27
 
51
28
  return (
52
- <ul className="py-1 text-sm">
53
- {rootEntries.map((entry) => (
29
+ <FileTreeView state={rootError ? "error" : rootEntries ? "ready" : "loading"} error={rootError} onRetry={retryRoot}>
30
+ {rootEntries?.map((entry) => (
54
31
  <TreeNode key={entry.path} entry={entry} depth={0} />
55
32
  ))}
56
- </ul>
33
+ </FileTreeView>
57
34
  );
58
35
  }
59
36
 
60
37
  function TreeNode({ entry, depth }: { entry: FileEntry; depth: number }) {
61
- const expanded = useFileStore((s) => s.expandedDirs.has(entry.path));
62
- const loading = useFileStore((s) => s.loadingDirs.has(entry.path));
63
- const childEntries = useFileStore((s) => (entry.type === "dir" ? s.dirCache[entry.path] : undefined));
64
- const childError = useFileStore((s) => (entry.type === "dir" ? s.dirErrors[entry.path] : undefined));
38
+ const isDir = entry.type === "dir";
39
+ const expanded = useFileStore((s) => isDir && s.expandedDirs.has(entry.path));
40
+ const loading = useFileStore((s) => isDir && s.loadingDirs.has(entry.path));
41
+ const childEntries = useFileStore((s) => (isDir ? s.dirCache[entry.path] : undefined));
42
+ const childError = useFileStore((s) => (isDir ? s.dirErrors[entry.path] : undefined));
65
43
  const toggleDir = useFileStore((s) => s.toggleDir);
44
+ const loadDir = useFileStore((s) => s.loadDir);
66
45
  const openFile = useFileStore((s) => s.openFile);
67
46
  const isActive = useFileStore((s) => s.currentPath === entry.path);
68
- const highlighted = useFileStore(
69
- (s) => entry.type === "dir" && s.highlightedDir === entry.path
70
- );
47
+ const highlighted = useFileStore((s) => isDir && s.highlightedDir === entry.path);
71
48
  const setHighlightedDir = useFileStore((s) => s.setHighlightedDir);
72
- const dirBtnRef = useRef<HTMLButtonElement>(null);
73
-
74
- useEffect(() => {
75
- if (!highlighted || !dirBtnRef.current) return;
76
- dirBtnRef.current.scrollIntoView({ behavior: "smooth", block: "center" });
77
- const t = setTimeout(() => setHighlightedDir(null), 1800);
78
- return () => clearTimeout(t);
79
- }, [highlighted, setHighlightedDir]);
49
+ const clearHighlight = useCallback(() => setHighlightedDir(null), [setHighlightedDir]);
80
50
 
81
- const indent = { paddingLeft: depth * 14 + 8 };
51
+ // Staleness is a fact about a FILE's content. A directory's mtime moves
52
+ // when an entry is added or removed, not when a note inside it changes,
53
+ // so a folder gets no dot: the design's gold folder (`context · stale
54
+ // 38d`) needs the newest child's mtime, which the tree only knows once
55
+ // that folder has been opened. The server sends `mtime` per entry; an
56
+ // older one without it draws nothing rather than guessing.
57
+ const staleDays =
58
+ !isDir && entry.mtime !== undefined && isStale(entry.mtime) ? ageInDays(entry.mtime) : undefined;
82
59
 
83
- if (entry.type === "dir") {
84
- return (
85
- <li>
86
- <button
87
- ref={dirBtnRef}
88
- onClick={() => void toggleDir(entry.path)}
89
- className={cn(
90
- "flex w-full items-center gap-1.5 rounded px-2 py-1 text-left text-foreground transition-colors hover:bg-surface-raised",
91
- highlighted && "brain-tree-highlight"
92
- )}
93
- style={indent}
94
- aria-expanded={expanded}
95
- >
96
- <ChevronRight
97
- className={cn(
98
- "h-3 w-3 shrink-0 text-muted-foreground transition-transform",
99
- expanded && "rotate-90"
100
- )}
101
- />
102
- {expanded ? (
103
- <FolderOpen className="h-4 w-4 shrink-0 text-primary/80" />
104
- ) : (
105
- <Folder className="h-4 w-4 shrink-0 text-muted-foreground" />
106
- )}
107
- <span className="truncate">{entry.name}</span>
108
- {loading && <Loader2 className="ml-auto h-3 w-3 animate-spin text-muted-foreground" />}
109
- </button>
110
- {expanded && (
111
- <ul>
112
- {childError && (
113
- <li className="flex items-center gap-1.5 px-2 py-1 text-xs text-destructive" style={{ paddingLeft: (depth + 1) * 14 + 8 }}>
114
- <AlertCircle className="h-3 w-3" /> {childError}
115
- </li>
116
- )}
117
- {childEntries?.map((child) => (
118
- <TreeNode key={child.path} entry={child} depth={depth + 1} />
119
- ))}
120
- </ul>
121
- )}
122
- </li>
123
- );
124
- }
60
+ // ← / → fold (sixth pass §8). The kit only calls `onFold(true)` on a closed
61
+ // folder and `onFold(false)` on an open one, but the guard keeps the store
62
+ // honest if a stale `kind` and the key disagree for a frame.
63
+ const fold = isDir
64
+ ? (open: boolean) => {
65
+ if (open !== expanded) void toggleDir(entry.path);
66
+ }
67
+ : undefined;
125
68
 
126
- const Icon = iconForFile(entry.name);
127
69
  return (
128
- <li>
129
- <button
130
- onClick={() => void openFile(entry.path)}
131
- className={cn(
132
- "flex w-full items-center gap-1.5 rounded px-2 py-1 text-left transition-colors hover:bg-surface-raised",
133
- isActive ? "bg-surface-raised text-primary" : "text-foreground/90"
134
- )}
135
- style={indent}
136
- >
137
- <span className="h-3 w-3 shrink-0" />
138
- <Icon className="h-3.5 w-3.5 shrink-0 text-muted-foreground" />
139
- <span className="truncate">{entry.name}</span>
140
- </button>
141
- </li>
70
+ <TreeRow
71
+ name={entry.name}
72
+ kind={fileKind(entry.name, isDir, expanded)}
73
+ depth={depth}
74
+ active={isActive}
75
+ loading={loading}
76
+ highlighted={highlighted}
77
+ error={expanded ? childError : undefined}
78
+ staleDays={staleDays}
79
+ onClick={() => void (isDir ? toggleDir(entry.path) : openFile(entry.path))}
80
+ onRetry={() => void loadDir(entry.path)}
81
+ onHighlightShown={clearHighlight}
82
+ onFold={fold}
83
+ >
84
+ {expanded && childEntries?.length
85
+ ? childEntries.map((child) => <TreeNode key={child.path} entry={child} depth={depth + 1} />)
86
+ : undefined}
87
+ </TreeRow>
142
88
  );
143
89
  }
@@ -1,11 +1,12 @@
1
1
  import { FileWarning, Download } from "lucide-react";
2
2
  import type { FileContentResponse } from "@schlessera/brain-ui-sdk/protocol";
3
- import { apiBase } from "../../lib/backend.js";
3
+ import { useBrainUiRoot } from "../../root-context.js";
4
4
  import { ZoomableImage } from "../images/zoomable-image.js";
5
5
 
6
6
  export function FileViewerBinary({ content }: { content: FileContentResponse }) {
7
+ const root = useBrainUiRoot();
7
8
  const isImage = content.mime?.startsWith("image/");
8
- const rawUrl = `${apiBase()}/files/content?path=${encodeURIComponent(content.path)}&raw=1`;
9
+ const rawUrl = `${root.apiBase()}/files/content?path=${encodeURIComponent(content.path)}&raw=1`;
9
10
 
10
11
  if (isImage) {
11
12
  const filename = content.path.split("/").pop() ?? content.path;
@@ -0,0 +1,113 @@
1
+ import { Callout, EmptyState, FilterRow, Placeholder } from "@schlessera/brain-ui-kit";
2
+ import { Check, Copy, FolderOpen } from "lucide-react";
3
+ import type { ReactNode } from "react";
4
+
5
+ /**
6
+ * The viewer's chrome, rendered from props (S7): the toolbar over the file,
7
+ * and the three states the body can be in before there is a file to draw.
8
+ * `FileViewer` is the container — it reads the store, builds the share
9
+ * options (which need the root) and chooses the body renderer; this owns
10
+ * how the frame looks.
11
+ *
12
+ * The Preview / Raw switch is the kit's `FilterRow`: two pills, one
13
+ * selected, activation following focus, which is what a mode switch is.
14
+ * The reveal and copy controls stay native icon buttons (titled; the kit
15
+ * has no icon-only button) and the share menu arrives rendered.
16
+ */
17
+ export type ViewMode = "preview" | "raw";
18
+
19
+ export interface ViewerToolbarProps {
20
+ fileName: string;
21
+ fullPath: string;
22
+ size?: number;
23
+ mode: ViewMode;
24
+ /** Only markdown, HTML and standalone diagrams have a preview to switch to. */
25
+ previewAvailable: boolean;
26
+ copied: boolean;
27
+ /** The share menu, already built by the container; null when nothing shares. */
28
+ share: ReactNode;
29
+ onMode: (mode: ViewMode) => void;
30
+ onCopyPath: () => void;
31
+ onReveal: () => void;
32
+ }
33
+
34
+ export function ViewerToolbar(p: ViewerToolbarProps) {
35
+ return (
36
+ <div className="flex items-center gap-2 border-b border-border bg-surface px-4 py-2">
37
+ <button
38
+ type="button"
39
+ onClick={p.onReveal}
40
+ title="Reveal in tree"
41
+ className="rounded p-1 text-muted-foreground transition-colors hover:bg-surface-raised hover:text-foreground"
42
+ >
43
+ <FolderOpen className="h-3.5 w-3.5" />
44
+ </button>
45
+ <div className="min-w-0 flex-1">
46
+ <div className="truncate text-sm font-medium text-foreground" title={p.fullPath}>
47
+ {p.fileName}
48
+ </div>
49
+ <div className="truncate text-[10px] text-muted-foreground" title={p.fullPath}>
50
+ {p.fullPath}
51
+ {p.size !== undefined && <span className="ml-2">· {formatSize(p.size)}</span>}
52
+ </div>
53
+ </div>
54
+ <button
55
+ type="button"
56
+ onClick={p.onCopyPath}
57
+ title="Copy path"
58
+ className="rounded p-1.5 text-muted-foreground transition-colors hover:bg-surface-raised hover:text-foreground"
59
+ >
60
+ {p.copied ? <Check className="h-3.5 w-3.5" /> : <Copy className="h-3.5 w-3.5" />}
61
+ </button>
62
+ {p.share}
63
+ {p.previewAvailable && (
64
+ <div className="w-auto shrink-0">
65
+ <FilterRow
66
+ items={[
67
+ { label: "Preview", onClick: () => p.onMode("preview") },
68
+ { label: "Raw", onClick: () => p.onMode("raw") },
69
+ ]}
70
+ active={p.mode === "preview" ? 0 : 1}
71
+ mono={false}
72
+ />
73
+ </div>
74
+ )}
75
+ </div>
76
+ );
77
+ }
78
+
79
+ export function ViewerLoading() {
80
+ return (
81
+ <div className="px-6 py-6" aria-label="Loading file">
82
+ <Placeholder variant="loading" lines={5} bordered={false} pad={0} />
83
+ </div>
84
+ );
85
+ }
86
+
87
+ export function ViewerError({ message }: { message: string }) {
88
+ return (
89
+ <div className="m-4" role="alert">
90
+ <Callout tone="red" variant="banner" icon="failed" mono text={message} />
91
+ </div>
92
+ );
93
+ }
94
+
95
+ export function ViewerEmpty() {
96
+ return (
97
+ <EmptyState
98
+ variant="no-results"
99
+ icon="folder"
100
+ tone="neutral"
101
+ title="No file open"
102
+ body="Select a file from the tree to view it."
103
+ meta=""
104
+ minHeight={240}
105
+ />
106
+ );
107
+ }
108
+
109
+ export function formatSize(bytes: number): string {
110
+ if (bytes < 1024) return `${bytes} B`;
111
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
112
+ return `${(bytes / 1024 / 1024).toFixed(2)} MB`;
113
+ }