@schlessera/brain-ui-react 0.34.1 → 0.36.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (763) hide show
  1. package/README.md +89 -4
  2. package/dist/components/activity/activity-page.d.ts +17 -5
  3. package/dist/components/activity/activity-page.d.ts.map +1 -1
  4. package/dist/components/activity/activity-page.js +144 -50
  5. package/dist/components/activity/activity-page.js.map +1 -1
  6. package/dist/components/activity/activity-run-detail.d.ts +16 -1
  7. package/dist/components/activity/activity-run-detail.d.ts.map +1 -1
  8. package/dist/components/activity/activity-run-detail.js +47 -4
  9. package/dist/components/activity/activity-run-detail.js.map +1 -1
  10. package/dist/components/activity/activity-run-list.d.ts +7 -1
  11. package/dist/components/activity/activity-run-list.d.ts.map +1 -1
  12. package/dist/components/activity/activity-run-list.js +16 -8
  13. package/dist/components/activity/activity-run-list.js.map +1 -1
  14. package/dist/components/activity/activity-views.d.ts +63 -0
  15. package/dist/components/activity/activity-views.d.ts.map +1 -0
  16. package/dist/components/activity/activity-views.js +52 -0
  17. package/dist/components/activity/activity-views.js.map +1 -0
  18. package/dist/components/activity/approval-card.d.ts +11 -0
  19. package/dist/components/activity/approval-card.d.ts.map +1 -0
  20. package/dist/components/activity/approval-card.js +46 -0
  21. package/dist/components/activity/approval-card.js.map +1 -0
  22. package/dist/components/activity/digest-card.d.ts +3 -0
  23. package/dist/components/activity/digest-card.d.ts.map +1 -1
  24. package/dist/components/activity/digest-card.js +20 -16
  25. package/dist/components/activity/digest-card.js.map +1 -1
  26. package/dist/components/activity/digest-summary.d.ts +19 -0
  27. package/dist/components/activity/digest-summary.d.ts.map +1 -0
  28. package/dist/components/activity/digest-summary.js +20 -0
  29. package/dist/components/activity/digest-summary.js.map +1 -0
  30. package/dist/components/activity/push-switch.d.ts +25 -0
  31. package/dist/components/activity/push-switch.d.ts.map +1 -0
  32. package/dist/components/activity/push-switch.js +14 -0
  33. package/dist/components/activity/push-switch.js.map +1 -0
  34. package/dist/components/activity/push-toggle.d.ts +7 -0
  35. package/dist/components/activity/push-toggle.d.ts.map +1 -1
  36. package/dist/components/activity/push-toggle.js +72 -47
  37. package/dist/components/activity/push-toggle.js.map +1 -1
  38. package/dist/components/activity/span-bits.d.ts.map +1 -1
  39. package/dist/components/activity/span-bits.js +9 -7
  40. package/dist/components/activity/span-bits.js.map +1 -1
  41. package/dist/components/chat/ask-user-card.d.ts +76 -3
  42. package/dist/components/chat/ask-user-card.d.ts.map +1 -1
  43. package/dist/components/chat/ask-user-card.js +208 -149
  44. package/dist/components/chat/ask-user-card.js.map +1 -1
  45. package/dist/components/chat/ask-user-typed.d.ts +42 -0
  46. package/dist/components/chat/ask-user-typed.d.ts.map +1 -0
  47. package/dist/components/chat/ask-user-typed.js +60 -0
  48. package/dist/components/chat/ask-user-typed.js.map +1 -0
  49. package/dist/components/chat/brain-markdown-links.d.ts +2 -1
  50. package/dist/components/chat/brain-markdown-links.d.ts.map +1 -1
  51. package/dist/components/chat/brain-markdown-links.js +3 -4
  52. package/dist/components/chat/brain-markdown-links.js.map +1 -1
  53. package/dist/components/chat/brain-markdown.d.ts.map +1 -1
  54. package/dist/components/chat/brain-markdown.js +4 -2
  55. package/dist/components/chat/brain-markdown.js.map +1 -1
  56. package/dist/components/chat/chat-page.d.ts.map +1 -1
  57. package/dist/components/chat/chat-page.js +24 -9
  58. package/dist/components/chat/chat-page.js.map +1 -1
  59. package/dist/components/chat/composer-view.d.ts +75 -0
  60. package/dist/components/chat/composer-view.d.ts.map +1 -0
  61. package/dist/components/chat/composer-view.js +31 -0
  62. package/dist/components/chat/composer-view.js.map +1 -0
  63. package/dist/components/chat/composer.d.ts +4 -0
  64. package/dist/components/chat/composer.d.ts.map +1 -1
  65. package/dist/components/chat/composer.js +76 -59
  66. package/dist/components/chat/composer.js.map +1 -1
  67. package/dist/components/chat/markdown-content.d.ts +16 -1
  68. package/dist/components/chat/markdown-content.d.ts.map +1 -1
  69. package/dist/components/chat/markdown-content.js +47 -3
  70. package/dist/components/chat/markdown-content.js.map +1 -1
  71. package/dist/components/chat/mermaid-block.d.ts +4 -0
  72. package/dist/components/chat/mermaid-block.d.ts.map +1 -1
  73. package/dist/components/chat/mermaid-block.js +13 -5
  74. package/dist/components/chat/mermaid-block.js.map +1 -1
  75. package/dist/components/chat/mermaid-share.d.ts +2 -1
  76. package/dist/components/chat/mermaid-share.d.ts.map +1 -1
  77. package/dist/components/chat/mermaid-share.js +7 -8
  78. package/dist/components/chat/mermaid-share.js.map +1 -1
  79. package/dist/components/chat/mermaid-viewer.d.ts.map +1 -1
  80. package/dist/components/chat/mermaid-viewer.js +3 -1
  81. package/dist/components/chat/mermaid-viewer.js.map +1 -1
  82. package/dist/components/chat/message-bubble.d.ts +8 -1
  83. package/dist/components/chat/message-bubble.d.ts.map +1 -1
  84. package/dist/components/chat/message-bubble.js +53 -24
  85. package/dist/components/chat/message-bubble.js.map +1 -1
  86. package/dist/components/chat/message-share.d.ts +2 -1
  87. package/dist/components/chat/message-share.d.ts.map +1 -1
  88. package/dist/components/chat/message-share.js +6 -7
  89. package/dist/components/chat/message-share.js.map +1 -1
  90. package/dist/components/chat/renderers/bind.d.ts +39 -0
  91. package/dist/components/chat/renderers/bind.d.ts.map +1 -0
  92. package/dist/components/chat/renderers/bind.js +43 -0
  93. package/dist/components/chat/renderers/bind.js.map +1 -0
  94. package/dist/components/chat/renderers/brain-ui-tools.d.ts +3 -0
  95. package/dist/components/chat/renderers/brain-ui-tools.d.ts.map +1 -0
  96. package/dist/components/chat/renderers/brain-ui-tools.js +41 -0
  97. package/dist/components/chat/renderers/brain-ui-tools.js.map +1 -0
  98. package/dist/components/chat/renderers/claude-tools.d.ts.map +1 -1
  99. package/dist/components/chat/renderers/claude-tools.js +3 -2
  100. package/dist/components/chat/renderers/claude-tools.js.map +1 -1
  101. package/dist/components/chat/renderers/index.d.ts +10 -2
  102. package/dist/components/chat/renderers/index.d.ts.map +1 -1
  103. package/dist/components/chat/renderers/index.js +15 -10
  104. package/dist/components/chat/renderers/index.js.map +1 -1
  105. package/dist/components/chat/session-drawer.d.ts +4 -0
  106. package/dist/components/chat/session-drawer.d.ts.map +1 -1
  107. package/dist/components/chat/session-drawer.js +55 -40
  108. package/dist/components/chat/session-drawer.js.map +1 -1
  109. package/dist/components/chat/session-list.d.ts +41 -0
  110. package/dist/components/chat/session-list.d.ts.map +1 -0
  111. package/dist/components/chat/session-list.js +10 -0
  112. package/dist/components/chat/session-list.js.map +1 -0
  113. package/dist/components/chat/share-block.d.ts.map +1 -1
  114. package/dist/components/chat/share-block.js +12 -11
  115. package/dist/components/chat/share-block.js.map +1 -1
  116. package/dist/components/chat/share-card.js +2 -2
  117. package/dist/components/chat/share-card.js.map +1 -1
  118. package/dist/components/chat/subagent-view.js +1 -1
  119. package/dist/components/chat/subagent-view.js.map +1 -1
  120. package/dist/components/chat/tool-call-timeline.d.ts.map +1 -1
  121. package/dist/components/chat/tool-call-timeline.js +37 -12
  122. package/dist/components/chat/tool-call-timeline.js.map +1 -1
  123. package/dist/components/chat/tool-cards/block-card.d.ts +28 -0
  124. package/dist/components/chat/tool-cards/block-card.d.ts.map +1 -0
  125. package/dist/components/chat/tool-cards/block-card.js +103 -0
  126. package/dist/components/chat/tool-cards/block-card.js.map +1 -0
  127. package/dist/components/chat/tool-cards/image-mask-card.d.ts +70 -0
  128. package/dist/components/chat/tool-cards/image-mask-card.d.ts.map +1 -0
  129. package/dist/components/chat/tool-cards/image-mask-card.js +142 -0
  130. package/dist/components/chat/tool-cards/image-mask-card.js.map +1 -0
  131. package/dist/components/chat/tool-cards/location-card.d.ts +45 -0
  132. package/dist/components/chat/tool-cards/location-card.d.ts.map +1 -0
  133. package/dist/components/chat/tool-cards/location-card.js +128 -0
  134. package/dist/components/chat/tool-cards/location-card.js.map +1 -0
  135. package/dist/components/chat/tool-views.d.ts +15 -4
  136. package/dist/components/chat/tool-views.d.ts.map +1 -1
  137. package/dist/components/chat/tool-views.js +22 -38
  138. package/dist/components/chat/tool-views.js.map +1 -1
  139. package/dist/components/chat/transcript-turn.d.ts +45 -0
  140. package/dist/components/chat/transcript-turn.d.ts.map +1 -0
  141. package/dist/components/chat/transcript-turn.js +25 -0
  142. package/dist/components/chat/transcript-turn.js.map +1 -0
  143. package/dist/components/chat/use-chat-commands.d.ts.map +1 -1
  144. package/dist/components/chat/use-chat-commands.js +13 -16
  145. package/dist/components/chat/use-chat-commands.js.map +1 -1
  146. package/dist/components/chat/welcome-state.d.ts +7 -0
  147. package/dist/components/chat/welcome-state.d.ts.map +1 -1
  148. package/dist/components/chat/welcome-state.js +13 -5
  149. package/dist/components/chat/welcome-state.js.map +1 -1
  150. package/dist/components/connectivity/connection-gate.d.ts.map +1 -1
  151. package/dist/components/connectivity/connection-gate.js +64 -6
  152. package/dist/components/connectivity/connection-gate.js.map +1 -1
  153. package/dist/components/connectivity/login-form.d.ts +31 -0
  154. package/dist/components/connectivity/login-form.d.ts.map +1 -0
  155. package/dist/components/connectivity/login-form.js +19 -0
  156. package/dist/components/connectivity/login-form.js.map +1 -0
  157. package/dist/components/connectivity/login-screen.d.ts +5 -2
  158. package/dist/components/connectivity/login-screen.d.ts.map +1 -1
  159. package/dist/components/connectivity/login-screen.js +41 -31
  160. package/dist/components/connectivity/login-screen.js.map +1 -1
  161. package/dist/components/dev/share-harness.js +1 -1
  162. package/dist/components/dev/share-harness.js.map +1 -1
  163. package/dist/components/files/file-panel.d.ts +1 -1
  164. package/dist/components/files/file-panel.d.ts.map +1 -1
  165. package/dist/components/files/file-panel.js +74 -0
  166. package/dist/components/files/file-panel.js.map +1 -1
  167. package/dist/components/files/file-tree-view.d.ts +45 -0
  168. package/dist/components/files/file-tree-view.d.ts.map +1 -0
  169. package/dist/components/files/file-tree-view.js +51 -0
  170. package/dist/components/files/file-tree-view.js.map +1 -0
  171. package/dist/components/files/file-tree.d.ts +6 -0
  172. package/dist/components/files/file-tree.d.ts.map +1 -1
  173. package/dist/components/files/file-tree.js +39 -43
  174. package/dist/components/files/file-tree.js.map +1 -1
  175. package/dist/components/files/file-viewer-binary.d.ts.map +1 -1
  176. package/dist/components/files/file-viewer-binary.js +3 -2
  177. package/dist/components/files/file-viewer-binary.js.map +1 -1
  178. package/dist/components/files/file-viewer-frame.d.ts +36 -0
  179. package/dist/components/files/file-viewer-frame.d.ts.map +1 -0
  180. package/dist/components/files/file-viewer-frame.js +26 -0
  181. package/dist/components/files/file-viewer-frame.js.map +1 -0
  182. package/dist/components/files/file-viewer.d.ts +5 -0
  183. package/dist/components/files/file-viewer.d.ts.map +1 -1
  184. package/dist/components/files/file-viewer.js +26 -32
  185. package/dist/components/files/file-viewer.js.map +1 -1
  186. package/dist/components/files/frontmatter-chips.d.ts +18 -0
  187. package/dist/components/files/frontmatter-chips.d.ts.map +1 -0
  188. package/dist/components/files/frontmatter-chips.js +11 -0
  189. package/dist/components/files/frontmatter-chips.js.map +1 -0
  190. package/dist/components/files/frontmatter-panel.d.ts +5 -1
  191. package/dist/components/files/frontmatter-panel.d.ts.map +1 -1
  192. package/dist/components/files/frontmatter-panel.js +7 -6
  193. package/dist/components/files/frontmatter-panel.js.map +1 -1
  194. package/dist/components/files/staleness.d.ts +18 -0
  195. package/dist/components/files/staleness.d.ts.map +1 -0
  196. package/dist/components/files/staleness.js +27 -0
  197. package/dist/components/files/staleness.js.map +1 -0
  198. package/dist/components/graph/graph-canvas.d.ts.map +1 -1
  199. package/dist/components/graph/graph-canvas.js +24 -1
  200. package/dist/components/graph/graph-canvas.js.map +1 -1
  201. package/dist/components/graph/graph-controls-column.d.ts +14 -0
  202. package/dist/components/graph/graph-controls-column.d.ts.map +1 -0
  203. package/dist/components/graph/graph-controls-column.js +44 -0
  204. package/dist/components/graph/graph-controls-column.js.map +1 -0
  205. package/dist/components/graph/graph-controls.d.ts +20 -5
  206. package/dist/components/graph/graph-controls.d.ts.map +1 -1
  207. package/dist/components/graph/graph-controls.js +58 -37
  208. package/dist/components/graph/graph-controls.js.map +1 -1
  209. package/dist/components/graph/graph-form.d.ts +82 -0
  210. package/dist/components/graph/graph-form.d.ts.map +1 -0
  211. package/dist/components/graph/graph-form.js +69 -0
  212. package/dist/components/graph/graph-form.js.map +1 -0
  213. package/dist/components/graph/graph-maintenance.d.ts.map +1 -1
  214. package/dist/components/graph/graph-maintenance.js +6 -10
  215. package/dist/components/graph/graph-maintenance.js.map +1 -1
  216. package/dist/components/graph/graph-node-rail.d.ts +13 -0
  217. package/dist/components/graph/graph-node-rail.d.ts.map +1 -0
  218. package/dist/components/graph/graph-node-rail.js +92 -0
  219. package/dist/components/graph/graph-node-rail.js.map +1 -0
  220. package/dist/components/graph/graph-page.d.ts +7 -0
  221. package/dist/components/graph/graph-page.d.ts.map +1 -1
  222. package/dist/components/graph/graph-page.js +102 -12
  223. package/dist/components/graph/graph-page.js.map +1 -1
  224. package/dist/components/graph/graph-scene.d.ts.map +1 -1
  225. package/dist/components/graph/graph-scene.js +100 -24
  226. package/dist/components/graph/graph-scene.js.map +1 -1
  227. package/dist/components/graph/lib/graph-helpers.d.ts +42 -12
  228. package/dist/components/graph/lib/graph-helpers.d.ts.map +1 -1
  229. package/dist/components/graph/lib/graph-helpers.js +33 -41
  230. package/dist/components/graph/lib/graph-helpers.js.map +1 -1
  231. package/dist/components/graph/node-card.d.ts +28 -0
  232. package/dist/components/graph/node-card.d.ts.map +1 -0
  233. package/dist/components/graph/node-card.js +7 -0
  234. package/dist/components/graph/node-card.js.map +1 -0
  235. package/dist/components/graph/node-popover.d.ts +6 -2
  236. package/dist/components/graph/node-popover.d.ts.map +1 -1
  237. package/dist/components/graph/node-popover.js +13 -31
  238. package/dist/components/graph/node-popover.js.map +1 -1
  239. package/dist/components/graph/use-graph-theme.d.ts +32 -4
  240. package/dist/components/graph/use-graph-theme.d.ts.map +1 -1
  241. package/dist/components/graph/use-graph-theme.js +44 -32
  242. package/dist/components/graph/use-graph-theme.js.map +1 -1
  243. package/dist/components/graph/use-node-actions.d.ts +26 -0
  244. package/dist/components/graph/use-node-actions.d.ts.map +1 -0
  245. package/dist/components/graph/use-node-actions.js +54 -0
  246. package/dist/components/graph/use-node-actions.js.map +1 -0
  247. package/dist/components/images/image-share.d.ts +2 -1
  248. package/dist/components/images/image-share.d.ts.map +1 -1
  249. package/dist/components/images/image-share.js +3 -3
  250. package/dist/components/images/image-share.js.map +1 -1
  251. package/dist/components/images/image-viewer.d.ts.map +1 -1
  252. package/dist/components/images/image-viewer.js +3 -1
  253. package/dist/components/images/image-viewer.js.map +1 -1
  254. package/dist/components/images/mask-editor.d.ts.map +1 -1
  255. package/dist/components/images/mask-editor.js +7 -5
  256. package/dist/components/images/mask-editor.js.map +1 -1
  257. package/dist/components/layout/app-shell.d.ts.map +1 -1
  258. package/dist/components/layout/app-shell.js +5 -1
  259. package/dist/components/layout/app-shell.js.map +1 -1
  260. package/dist/components/layout/desktop-palette.d.ts +23 -0
  261. package/dist/components/layout/desktop-palette.d.ts.map +1 -0
  262. package/dist/components/layout/desktop-palette.js +132 -0
  263. package/dist/components/layout/desktop-palette.js.map +1 -0
  264. package/dist/components/layout/key-cap.d.ts +9 -0
  265. package/dist/components/layout/key-cap.d.ts.map +1 -0
  266. package/dist/components/layout/key-cap.js +10 -0
  267. package/dist/components/layout/key-cap.js.map +1 -0
  268. package/dist/components/layout/mobile-tab-bar.d.ts +13 -0
  269. package/dist/components/layout/mobile-tab-bar.d.ts.map +1 -1
  270. package/dist/components/layout/mobile-tab-bar.js +58 -47
  271. package/dist/components/layout/mobile-tab-bar.js.map +1 -1
  272. package/dist/components/layout/shortcut-switch.d.ts +13 -0
  273. package/dist/components/layout/shortcut-switch.d.ts.map +1 -0
  274. package/dist/components/layout/shortcut-switch.js +22 -0
  275. package/dist/components/layout/shortcut-switch.js.map +1 -0
  276. package/dist/components/layout/side-rail.d.ts +24 -0
  277. package/dist/components/layout/side-rail.d.ts.map +1 -1
  278. package/dist/components/layout/side-rail.js +65 -27
  279. package/dist/components/layout/side-rail.js.map +1 -1
  280. package/dist/components/layout/slide-panel.d.ts +12 -2
  281. package/dist/components/layout/slide-panel.d.ts.map +1 -1
  282. package/dist/components/layout/slide-panel.js +11 -2
  283. package/dist/components/layout/slide-panel.js.map +1 -1
  284. package/dist/components/layout/theme.d.ts +22 -0
  285. package/dist/components/layout/theme.d.ts.map +1 -0
  286. package/dist/components/layout/theme.js +44 -0
  287. package/dist/components/layout/theme.js.map +1 -0
  288. package/dist/components/quick-actions/add-form.d.ts +44 -0
  289. package/dist/components/quick-actions/add-form.d.ts.map +1 -0
  290. package/dist/components/quick-actions/add-form.js +30 -0
  291. package/dist/components/quick-actions/add-form.js.map +1 -0
  292. package/dist/components/quick-actions/add-modal.d.ts +7 -0
  293. package/dist/components/quick-actions/add-modal.d.ts.map +1 -1
  294. package/dist/components/quick-actions/add-modal.js +66 -20
  295. package/dist/components/quick-actions/add-modal.js.map +1 -1
  296. package/dist/components/quick-actions/search-modal.d.ts.map +1 -1
  297. package/dist/components/quick-actions/search-modal.js +48 -19
  298. package/dist/components/quick-actions/search-modal.js.map +1 -1
  299. package/dist/components/quick-actions/streaming-modal.d.ts +6 -0
  300. package/dist/components/quick-actions/streaming-modal.d.ts.map +1 -1
  301. package/dist/components/quick-actions/streaming-modal.js +42 -17
  302. package/dist/components/quick-actions/streaming-modal.js.map +1 -1
  303. package/dist/components/quick-actions/streaming-output.d.ts +38 -0
  304. package/dist/components/quick-actions/streaming-output.d.ts.map +1 -0
  305. package/dist/components/quick-actions/streaming-output.js +22 -0
  306. package/dist/components/quick-actions/streaming-output.js.map +1 -0
  307. package/dist/components/quick-actions/whatsup-modal.d.ts +5 -0
  308. package/dist/components/quick-actions/whatsup-modal.d.ts.map +1 -1
  309. package/dist/components/quick-actions/whatsup-modal.js +36 -10
  310. package/dist/components/quick-actions/whatsup-modal.js.map +1 -1
  311. package/dist/components/settings/devices-agents-tab.d.ts +10 -0
  312. package/dist/components/settings/devices-agents-tab.d.ts.map +1 -0
  313. package/dist/components/settings/devices-agents-tab.js +131 -0
  314. package/dist/components/settings/devices-agents-tab.js.map +1 -0
  315. package/dist/components/settings/models-list.d.ts +39 -0
  316. package/dist/components/settings/models-list.d.ts.map +1 -0
  317. package/dist/components/settings/models-list.js +72 -0
  318. package/dist/components/settings/models-list.js.map +1 -0
  319. package/dist/components/settings/models-tab.d.ts +4 -0
  320. package/dist/components/settings/models-tab.d.ts.map +1 -1
  321. package/dist/components/settings/models-tab.js +52 -102
  322. package/dist/components/settings/models-tab.js.map +1 -1
  323. package/dist/components/settings/one-time-agent-credential.d.ts +3 -0
  324. package/dist/components/settings/one-time-agent-credential.d.ts.map +1 -0
  325. package/dist/components/settings/one-time-agent-credential.js +55 -0
  326. package/dist/components/settings/one-time-agent-credential.js.map +1 -0
  327. package/dist/components/settings/passkey-list.d.ts +35 -0
  328. package/dist/components/settings/passkey-list.d.ts.map +1 -0
  329. package/dist/components/settings/passkey-list.js +34 -0
  330. package/dist/components/settings/passkey-list.js.map +1 -0
  331. package/dist/components/settings/passkey-tab.d.ts +3 -0
  332. package/dist/components/settings/passkey-tab.d.ts.map +1 -1
  333. package/dist/components/settings/passkey-tab.js +53 -45
  334. package/dist/components/settings/passkey-tab.js.map +1 -1
  335. package/dist/components/settings/pi-accounts-list.d.ts +27 -0
  336. package/dist/components/settings/pi-accounts-list.d.ts.map +1 -0
  337. package/dist/components/settings/pi-accounts-list.js +15 -0
  338. package/dist/components/settings/pi-accounts-list.js.map +1 -0
  339. package/dist/components/settings/pi-accounts.d.ts +3 -0
  340. package/dist/components/settings/pi-accounts.d.ts.map +1 -1
  341. package/dist/components/settings/pi-accounts.js +73 -55
  342. package/dist/components/settings/pi-accounts.js.map +1 -1
  343. package/dist/components/settings/principal-list.d.ts +37 -0
  344. package/dist/components/settings/principal-list.d.ts.map +1 -0
  345. package/dist/components/settings/principal-list.js +18 -0
  346. package/dist/components/settings/principal-list.js.map +1 -0
  347. package/dist/components/settings/settings-panel.d.ts +10 -3
  348. package/dist/components/settings/settings-panel.d.ts.map +1 -1
  349. package/dist/components/settings/settings-panel.js +80 -6
  350. package/dist/components/settings/settings-panel.js.map +1 -1
  351. package/dist/components/settings/skills-list.d.ts +53 -0
  352. package/dist/components/settings/skills-list.d.ts.map +1 -0
  353. package/dist/components/settings/skills-list.js +28 -0
  354. package/dist/components/settings/skills-list.js.map +1 -0
  355. package/dist/components/settings/skills-tab.d.ts.map +1 -1
  356. package/dist/components/settings/skills-tab.js +65 -38
  357. package/dist/components/settings/skills-tab.js.map +1 -1
  358. package/dist/components/settings/tool-permissions-list.d.ts +18 -0
  359. package/dist/components/settings/tool-permissions-list.d.ts.map +1 -0
  360. package/dist/components/settings/tool-permissions-list.js +6 -0
  361. package/dist/components/settings/tool-permissions-list.js.map +1 -0
  362. package/dist/components/settings/tool-permissions.d.ts +2 -1
  363. package/dist/components/settings/tool-permissions.d.ts.map +1 -1
  364. package/dist/components/settings/tool-permissions.js +33 -16
  365. package/dist/components/settings/tool-permissions.js.map +1 -1
  366. package/dist/components/settings/web-search-chain.d.ts +41 -0
  367. package/dist/components/settings/web-search-chain.d.ts.map +1 -0
  368. package/dist/components/settings/web-search-chain.js +47 -0
  369. package/dist/components/settings/web-search-chain.js.map +1 -0
  370. package/dist/components/settings/web-search-settings.d.ts +4 -7
  371. package/dist/components/settings/web-search-settings.d.ts.map +1 -1
  372. package/dist/components/settings/web-search-settings.js +54 -76
  373. package/dist/components/settings/web-search-settings.js.map +1 -1
  374. package/dist/components/share/share-menu.d.ts.map +1 -1
  375. package/dist/components/share/share-menu.js +24 -4
  376. package/dist/components/share/share-menu.js.map +1 -1
  377. package/dist/components/voice/dictation-sheet.js +3 -3
  378. package/dist/components/voice/dictation-sheet.js.map +1 -1
  379. package/dist/components/voice/mic-button.js +1 -1
  380. package/dist/components/voice/mic-button.js.map +1 -1
  381. package/dist/components/voice/review-card.js +1 -1
  382. package/dist/components/voice/review-card.js.map +1 -1
  383. package/dist/config.d.ts +5 -2
  384. package/dist/config.d.ts.map +1 -1
  385. package/dist/config.js +15 -5
  386. package/dist/config.js.map +1 -1
  387. package/dist/connection.d.ts +12 -0
  388. package/dist/connection.d.ts.map +1 -0
  389. package/dist/connection.js +421 -0
  390. package/dist/connection.js.map +1 -0
  391. package/dist/default-root.d.ts +3 -0
  392. package/dist/default-root.d.ts.map +1 -0
  393. package/dist/default-root.js +16 -0
  394. package/dist/default-root.js.map +1 -0
  395. package/dist/hooks/use-color-scheme.d.ts +14 -0
  396. package/dist/hooks/use-color-scheme.d.ts.map +1 -0
  397. package/dist/hooks/use-color-scheme.js +37 -0
  398. package/dist/hooks/use-color-scheme.js.map +1 -0
  399. package/dist/hooks/use-hash-routes.d.ts.map +1 -1
  400. package/dist/hooks/use-hash-routes.js +4 -2
  401. package/dist/hooks/use-hash-routes.js.map +1 -1
  402. package/dist/hooks/use-media-query.d.ts +7 -0
  403. package/dist/hooks/use-media-query.d.ts.map +1 -0
  404. package/dist/hooks/use-media-query.js +34 -0
  405. package/dist/hooks/use-media-query.js.map +1 -0
  406. package/dist/hooks/use-share-intake.d.ts.map +1 -1
  407. package/dist/hooks/use-share-intake.js +37 -12
  408. package/dist/hooks/use-share-intake.js.map +1 -1
  409. package/dist/hooks/use-vpn-status.d.ts +1 -1
  410. package/dist/hooks/use-vpn-status.d.ts.map +1 -1
  411. package/dist/hooks/use-vpn-status.js +20 -16
  412. package/dist/hooks/use-vpn-status.js.map +1 -1
  413. package/dist/hooks/use-websocket.d.ts +5 -24
  414. package/dist/hooks/use-websocket.d.ts.map +1 -1
  415. package/dist/hooks/use-websocket.js +11 -382
  416. package/dist/hooks/use-websocket.js.map +1 -1
  417. package/dist/hooks/websocket-handlers/activity.d.ts +2 -2
  418. package/dist/hooks/websocket-handlers/activity.d.ts.map +1 -1
  419. package/dist/hooks/websocket-handlers/activity.js +4 -5
  420. package/dist/hooks/websocket-handlers/activity.js.map +1 -1
  421. package/dist/hooks/websocket-handlers/chat.d.ts +1 -0
  422. package/dist/hooks/websocket-handlers/chat.d.ts.map +1 -1
  423. package/dist/hooks/websocket-handlers/chat.js +27 -5
  424. package/dist/hooks/websocket-handlers/chat.js.map +1 -1
  425. package/dist/hooks/websocket-handlers/connection.d.ts.map +1 -1
  426. package/dist/hooks/websocket-handlers/connection.js +4 -6
  427. package/dist/hooks/websocket-handlers/connection.js.map +1 -1
  428. package/dist/hooks/websocket-handlers/mask.d.ts +1 -1
  429. package/dist/hooks/websocket-handlers/mask.d.ts.map +1 -1
  430. package/dist/hooks/websocket-handlers/mask.js +2 -3
  431. package/dist/hooks/websocket-handlers/mask.js.map +1 -1
  432. package/dist/hooks/websocket-handlers/provider.d.ts.map +1 -1
  433. package/dist/hooks/websocket-handlers/provider.js +4 -6
  434. package/dist/hooks/websocket-handlers/provider.js.map +1 -1
  435. package/dist/hooks/websocket-handlers/types.d.ts +6 -2
  436. package/dist/hooks/websocket-handlers/types.d.ts.map +1 -1
  437. package/dist/index.d.ts +5 -3
  438. package/dist/index.d.ts.map +1 -1
  439. package/dist/index.js +6 -3
  440. package/dist/index.js.map +1 -1
  441. package/dist/lib/api-client.d.ts +321 -0
  442. package/dist/lib/api-client.d.ts.map +1 -1
  443. package/dist/lib/api-client.js +243 -213
  444. package/dist/lib/api-client.js.map +1 -1
  445. package/dist/lib/backend.d.ts +19 -2
  446. package/dist/lib/backend.d.ts.map +1 -1
  447. package/dist/lib/backend.js +15 -9
  448. package/dist/lib/backend.js.map +1 -1
  449. package/dist/lib/diff.d.ts +8 -10
  450. package/dist/lib/diff.d.ts.map +1 -1
  451. package/dist/lib/diff.js +26 -53
  452. package/dist/lib/diff.js.map +1 -1
  453. package/dist/lib/format-time.d.ts +3 -0
  454. package/dist/lib/format-time.d.ts.map +1 -0
  455. package/dist/lib/format-time.js +25 -0
  456. package/dist/lib/format-time.js.map +1 -0
  457. package/dist/lib/light-dark.d.ts +37 -0
  458. package/dist/lib/light-dark.d.ts.map +1 -0
  459. package/dist/lib/light-dark.js +83 -0
  460. package/dist/lib/light-dark.js.map +1 -0
  461. package/dist/lib/mermaid-theme.d.ts +7 -2
  462. package/dist/lib/mermaid-theme.d.ts.map +1 -1
  463. package/dist/lib/mermaid-theme.js +125 -203
  464. package/dist/lib/mermaid-theme.js.map +1 -1
  465. package/dist/lib/passkeys.d.ts +6 -3
  466. package/dist/lib/passkeys.d.ts.map +1 -1
  467. package/dist/lib/passkeys.js +10 -4
  468. package/dist/lib/passkeys.js.map +1 -1
  469. package/dist/lib/push-registration.d.ts +10 -0
  470. package/dist/lib/push-registration.d.ts.map +1 -0
  471. package/dist/lib/push-registration.js +44 -0
  472. package/dist/lib/push-registration.js.map +1 -0
  473. package/dist/lib/share-intake.d.ts +2 -1
  474. package/dist/lib/share-intake.d.ts.map +1 -1
  475. package/dist/lib/share-intake.js +3 -3
  476. package/dist/lib/share-intake.js.map +1 -1
  477. package/dist/lib/share.d.ts +4 -3
  478. package/dist/lib/share.d.ts.map +1 -1
  479. package/dist/lib/share.js +6 -7
  480. package/dist/lib/share.js.map +1 -1
  481. package/dist/lib/single-key.d.ts +30 -0
  482. package/dist/lib/single-key.d.ts.map +1 -0
  483. package/dist/lib/single-key.js +45 -0
  484. package/dist/lib/single-key.js.map +1 -0
  485. package/dist/lib/tool-names.d.ts +8 -6
  486. package/dist/lib/tool-names.d.ts.map +1 -1
  487. package/dist/lib/tool-names.js +17 -7
  488. package/dist/lib/tool-names.js.map +1 -1
  489. package/dist/root-context.d.ts +229 -0
  490. package/dist/root-context.d.ts.map +1 -0
  491. package/dist/root-context.js +33 -0
  492. package/dist/root-context.js.map +1 -0
  493. package/dist/root.d.ts +38 -0
  494. package/dist/root.d.ts.map +1 -0
  495. package/dist/root.js +47 -0
  496. package/dist/root.js.map +1 -0
  497. package/dist/stores/activity-state.d.ts +29 -0
  498. package/dist/stores/activity-state.d.ts.map +1 -0
  499. package/dist/stores/activity-state.js +282 -0
  500. package/dist/stores/activity-state.js.map +1 -0
  501. package/dist/stores/activity-store.d.ts +10 -41
  502. package/dist/stores/activity-store.d.ts.map +1 -1
  503. package/dist/stores/activity-store.js +9 -271
  504. package/dist/stores/activity-store.js.map +1 -1
  505. package/dist/stores/chat-state.d.ts +212 -0
  506. package/dist/stores/chat-state.d.ts.map +1 -0
  507. package/dist/stores/chat-state.js +466 -0
  508. package/dist/stores/chat-state.js.map +1 -0
  509. package/dist/stores/chat-store.d.ts +4 -162
  510. package/dist/stores/chat-store.d.ts.map +1 -1
  511. package/dist/stores/chat-store.js +7 -418
  512. package/dist/stores/chat-store.js.map +1 -1
  513. package/dist/stores/connection-state.d.ts +40 -0
  514. package/dist/stores/connection-state.d.ts.map +1 -0
  515. package/dist/stores/connection-state.js +30 -0
  516. package/dist/stores/connection-state.js.map +1 -0
  517. package/dist/stores/connection-store.d.ts +4 -40
  518. package/dist/stores/connection-store.d.ts.map +1 -1
  519. package/dist/stores/connection-store.js +7 -27
  520. package/dist/stores/connection-store.js.map +1 -1
  521. package/dist/stores/create-stores.d.ts +23 -0
  522. package/dist/stores/create-stores.d.ts.map +1 -0
  523. package/dist/stores/create-stores.js +28 -0
  524. package/dist/stores/create-stores.js.map +1 -0
  525. package/dist/stores/file-state.d.ts +53 -0
  526. package/dist/stores/file-state.d.ts.map +1 -0
  527. package/dist/stores/file-state.js +341 -0
  528. package/dist/stores/file-state.js.map +1 -0
  529. package/dist/stores/file-store.d.ts +4 -52
  530. package/dist/stores/file-store.d.ts.map +1 -1
  531. package/dist/stores/file-store.js +7 -300
  532. package/dist/stores/file-store.js.map +1 -1
  533. package/dist/stores/graph-state.d.ts +95 -0
  534. package/dist/stores/graph-state.d.ts.map +1 -0
  535. package/dist/stores/graph-state.js +252 -0
  536. package/dist/stores/graph-state.js.map +1 -0
  537. package/dist/stores/graph-store.d.ts +7 -83
  538. package/dist/stores/graph-store.d.ts.map +1 -1
  539. package/dist/stores/graph-store.js +8 -249
  540. package/dist/stores/graph-store.js.map +1 -1
  541. package/dist/stores/mask-state.d.ts +21 -0
  542. package/dist/stores/mask-state.d.ts.map +1 -0
  543. package/dist/stores/mask-state.js +9 -0
  544. package/dist/stores/mask-state.js.map +1 -0
  545. package/dist/stores/mask-store.d.ts +4 -21
  546. package/dist/stores/mask-store.d.ts.map +1 -1
  547. package/dist/stores/mask-store.js +7 -6
  548. package/dist/stores/mask-store.js.map +1 -1
  549. package/dist/stores/principal-state.d.ts +16 -0
  550. package/dist/stores/principal-state.d.ts.map +1 -0
  551. package/dist/stores/principal-state.js +31 -0
  552. package/dist/stores/principal-state.js.map +1 -0
  553. package/dist/stores/principal-store.d.ts +5 -0
  554. package/dist/stores/principal-store.d.ts.map +1 -0
  555. package/dist/stores/principal-store.js +8 -0
  556. package/dist/stores/principal-store.js.map +1 -0
  557. package/dist/stores/provider-state.d.ts +24 -0
  558. package/dist/stores/provider-state.d.ts.map +1 -0
  559. package/dist/stores/provider-state.js +68 -0
  560. package/dist/stores/provider-state.js.map +1 -0
  561. package/dist/stores/provider-store.d.ts +4 -23
  562. package/dist/stores/provider-store.d.ts.map +1 -1
  563. package/dist/stores/provider-store.js +7 -64
  564. package/dist/stores/provider-store.js.map +1 -1
  565. package/dist/stores/share-state.d.ts +29 -0
  566. package/dist/stores/share-state.d.ts.map +1 -0
  567. package/dist/stores/share-state.js +21 -0
  568. package/dist/stores/share-state.js.map +1 -0
  569. package/dist/stores/share-store.d.ts +4 -28
  570. package/dist/stores/share-store.d.ts.map +1 -1
  571. package/dist/stores/share-store.js +7 -18
  572. package/dist/stores/share-store.js.map +1 -1
  573. package/dist/stores/store-environment.d.ts +10 -0
  574. package/dist/stores/store-environment.d.ts.map +1 -0
  575. package/dist/stores/store-environment.js +2 -0
  576. package/dist/stores/store-environment.js.map +1 -0
  577. package/dist/stores/ui-state.d.ts +71 -0
  578. package/dist/stores/ui-state.d.ts.map +1 -0
  579. package/dist/stores/ui-state.js +58 -0
  580. package/dist/stores/ui-state.js.map +1 -0
  581. package/dist/stores/ui-store.d.ts +4 -45
  582. package/dist/stores/ui-store.d.ts.map +1 -1
  583. package/dist/stores/ui-store.js +7 -36
  584. package/dist/stores/ui-store.js.map +1 -1
  585. package/dist/styles.css +1 -1
  586. package/dist/theme.css +150 -97
  587. package/dist/voice/asr-clients.d.ts +2 -1
  588. package/dist/voice/asr-clients.d.ts.map +1 -1
  589. package/dist/voice/asr-clients.js +16 -17
  590. package/dist/voice/asr-clients.js.map +1 -1
  591. package/dist/voice/use-dictation.d.ts.map +1 -1
  592. package/dist/voice/use-dictation.js +12 -8
  593. package/dist/voice/use-dictation.js.map +1 -1
  594. package/dist/voice/voice-state.d.ts +25 -0
  595. package/dist/voice/voice-state.d.ts.map +1 -0
  596. package/dist/voice/voice-state.js +29 -0
  597. package/dist/voice/voice-state.js.map +1 -0
  598. package/dist/voice/voice-store.d.ts +4 -25
  599. package/dist/voice/voice-store.d.ts.map +1 -1
  600. package/dist/voice/voice-store.js +7 -26
  601. package/dist/voice/voice-store.js.map +1 -1
  602. package/package.json +3 -2
  603. package/src/components/activity/activity-page.tsx +334 -160
  604. package/src/components/activity/activity-run-detail.tsx +81 -47
  605. package/src/components/activity/activity-run-list.tsx +27 -59
  606. package/src/components/activity/activity-views.tsx +155 -0
  607. package/src/components/activity/approval-card.tsx +80 -0
  608. package/src/components/activity/digest-card.tsx +25 -61
  609. package/src/components/activity/digest-summary.tsx +52 -0
  610. package/src/components/activity/push-switch.tsx +62 -0
  611. package/src/components/activity/push-toggle.tsx +51 -81
  612. package/src/components/activity/span-bits.tsx +8 -7
  613. package/src/components/chat/ask-user-card.tsx +292 -356
  614. package/src/components/chat/ask-user-typed.ts +77 -0
  615. package/src/components/chat/brain-markdown-links.tsx +4 -4
  616. package/src/components/chat/brain-markdown.tsx +4 -2
  617. package/src/components/chat/chat-page.tsx +38 -9
  618. package/src/components/chat/composer-view.tsx +194 -0
  619. package/src/components/chat/composer.tsx +117 -296
  620. package/src/components/chat/markdown-content.tsx +53 -2
  621. package/src/components/chat/mermaid-block.tsx +13 -5
  622. package/src/components/chat/mermaid-share.ts +8 -7
  623. package/src/components/chat/mermaid-viewer.tsx +3 -1
  624. package/src/components/chat/message-bubble.tsx +78 -94
  625. package/src/components/chat/message-share.ts +7 -7
  626. package/src/components/chat/renderers/bind.tsx +94 -0
  627. package/src/components/chat/renderers/brain-ui-tools.tsx +56 -0
  628. package/src/components/chat/renderers/claude-tools.tsx +3 -2
  629. package/src/components/chat/renderers/index.ts +15 -10
  630. package/src/components/chat/session-drawer.tsx +60 -138
  631. package/src/components/chat/session-list.tsx +113 -0
  632. package/src/components/chat/share-block.tsx +16 -12
  633. package/src/components/chat/share-card.tsx +2 -2
  634. package/src/components/chat/subagent-view.tsx +4 -4
  635. package/src/components/chat/tool-call-timeline.tsx +59 -22
  636. package/src/components/chat/tool-cards/block-card.tsx +145 -0
  637. package/src/components/chat/tool-cards/image-mask-card.tsx +214 -0
  638. package/src/components/chat/tool-cards/location-card.tsx +159 -0
  639. package/src/components/chat/tool-views.tsx +23 -73
  640. package/src/components/chat/transcript-turn.tsx +108 -0
  641. package/src/components/chat/use-chat-commands.ts +14 -16
  642. package/src/components/chat/welcome-state.tsx +36 -91
  643. package/src/components/connectivity/connection-gate.tsx +80 -9
  644. package/src/components/connectivity/login-form.tsx +122 -0
  645. package/src/components/connectivity/login-screen.tsx +45 -100
  646. package/src/components/dev/share-harness.tsx +2 -2
  647. package/src/components/files/file-panel.tsx +168 -0
  648. package/src/components/files/file-tree-view.tsx +127 -0
  649. package/src/components/files/file-tree.tsx +55 -109
  650. package/src/components/files/file-viewer-binary.tsx +3 -2
  651. package/src/components/files/file-viewer-frame.tsx +113 -0
  652. package/src/components/files/file-viewer.tsx +40 -95
  653. package/src/components/files/frontmatter-chips.tsx +42 -0
  654. package/src/components/files/frontmatter-panel.tsx +6 -71
  655. package/src/components/files/staleness.ts +29 -0
  656. package/src/components/graph/graph-canvas.tsx +24 -1
  657. package/src/components/graph/graph-controls-column.tsx +92 -0
  658. package/src/components/graph/graph-controls.tsx +83 -127
  659. package/src/components/graph/graph-form.tsx +183 -0
  660. package/src/components/graph/graph-maintenance.tsx +9 -14
  661. package/src/components/graph/graph-node-rail.tsx +147 -0
  662. package/src/components/graph/graph-page.tsx +189 -49
  663. package/src/components/graph/graph-scene.tsx +200 -30
  664. package/src/components/graph/lib/graph-helpers.ts +65 -43
  665. package/src/components/graph/node-card.tsx +64 -0
  666. package/src/components/graph/node-popover.tsx +28 -117
  667. package/src/components/graph/use-graph-theme.ts +69 -32
  668. package/src/components/graph/use-node-actions.ts +56 -0
  669. package/src/components/images/image-share.ts +4 -2
  670. package/src/components/images/image-viewer.tsx +3 -1
  671. package/src/components/images/mask-editor.tsx +7 -4
  672. package/src/components/layout/app-shell.tsx +7 -1
  673. package/src/components/layout/desktop-palette.tsx +151 -0
  674. package/src/components/layout/key-cap.tsx +15 -0
  675. package/src/components/layout/mobile-tab-bar.tsx +80 -157
  676. package/src/components/layout/shortcut-switch.tsx +32 -0
  677. package/src/components/layout/side-rail.tsx +70 -150
  678. package/src/components/layout/slide-panel.tsx +29 -2
  679. package/src/components/layout/theme.tsx +67 -0
  680. package/src/components/quick-actions/add-form.tsx +188 -0
  681. package/src/components/quick-actions/add-modal.tsx +68 -144
  682. package/src/components/quick-actions/search-modal.tsx +49 -19
  683. package/src/components/quick-actions/streaming-modal.tsx +44 -71
  684. package/src/components/quick-actions/streaming-output.tsx +112 -0
  685. package/src/components/quick-actions/whatsup-modal.tsx +38 -60
  686. package/src/components/settings/devices-agents-tab.tsx +139 -0
  687. package/src/components/settings/models-list.tsx +299 -0
  688. package/src/components/settings/models-tab.tsx +63 -337
  689. package/src/components/settings/one-time-agent-credential.tsx +131 -0
  690. package/src/components/settings/passkey-list.tsx +201 -0
  691. package/src/components/settings/passkey-tab.tsx +53 -197
  692. package/src/components/settings/pi-accounts-list.tsx +128 -0
  693. package/src/components/settings/pi-accounts.tsx +71 -170
  694. package/src/components/settings/principal-list.tsx +172 -0
  695. package/src/components/settings/settings-panel.tsx +245 -19
  696. package/src/components/settings/skills-list.tsx +276 -0
  697. package/src/components/settings/skills-tab.tsx +82 -269
  698. package/src/components/settings/tool-permissions-list.tsx +54 -0
  699. package/src/components/settings/tool-permissions.tsx +27 -46
  700. package/src/components/settings/web-search-chain.tsx +300 -0
  701. package/src/components/settings/web-search-settings.tsx +58 -328
  702. package/src/components/share/share-menu.tsx +19 -4
  703. package/src/components/voice/dictation-sheet.tsx +5 -5
  704. package/src/components/voice/mic-button.tsx +1 -1
  705. package/src/components/voice/review-card.tsx +1 -1
  706. package/src/config.ts +21 -7
  707. package/src/connection.ts +443 -0
  708. package/src/default-root.ts +16 -0
  709. package/src/hooks/use-color-scheme.ts +36 -0
  710. package/src/hooks/use-hash-routes.ts +4 -2
  711. package/src/hooks/use-media-query.ts +32 -0
  712. package/src/hooks/use-share-intake.ts +32 -12
  713. package/src/hooks/use-vpn-status.ts +23 -15
  714. package/src/hooks/use-websocket.ts +12 -426
  715. package/src/hooks/websocket-handlers/activity.ts +4 -5
  716. package/src/hooks/websocket-handlers/chat.ts +26 -5
  717. package/src/hooks/websocket-handlers/connection.ts +4 -6
  718. package/src/hooks/websocket-handlers/mask.ts +2 -3
  719. package/src/hooks/websocket-handlers/provider.ts +4 -6
  720. package/src/hooks/websocket-handlers/types.ts +6 -2
  721. package/src/index.ts +7 -3
  722. package/src/lib/api-client.ts +446 -365
  723. package/src/lib/backend.ts +20 -10
  724. package/src/lib/diff.ts +28 -62
  725. package/src/lib/format-time.ts +20 -0
  726. package/src/lib/light-dark.ts +83 -0
  727. package/src/lib/mermaid-theme.ts +183 -214
  728. package/src/lib/passkeys.ts +12 -4
  729. package/src/lib/push-registration.ts +46 -0
  730. package/src/lib/share-intake.ts +6 -3
  731. package/src/lib/share.ts +7 -4
  732. package/src/lib/single-key.ts +47 -0
  733. package/src/lib/tool-names.ts +31 -8
  734. package/src/root-context.tsx +40 -0
  735. package/src/root.ts +83 -0
  736. package/src/stores/activity-state.ts +295 -0
  737. package/src/stores/activity-store.ts +11 -285
  738. package/src/stores/chat-state.ts +795 -0
  739. package/src/stores/chat-store.ts +11 -705
  740. package/src/stores/connection-state.ts +78 -0
  741. package/src/stores/connection-store.ts +11 -76
  742. package/src/stores/create-stores.ts +31 -0
  743. package/src/stores/file-state.ts +399 -0
  744. package/src/stores/file-store.ts +9 -360
  745. package/src/stores/graph-state.ts +368 -0
  746. package/src/stores/graph-store.ts +10 -355
  747. package/src/stores/mask-state.ts +30 -0
  748. package/src/stores/mask-store.ts +10 -27
  749. package/src/stores/principal-state.ts +42 -0
  750. package/src/stores/principal-store.ts +11 -0
  751. package/src/stores/provider-state.ts +103 -0
  752. package/src/stores/provider-store.ts +10 -95
  753. package/src/stores/share-state.ts +56 -0
  754. package/src/stores/share-store.ts +11 -54
  755. package/src/stores/store-environment.ts +10 -0
  756. package/src/stores/ui-state.ts +143 -0
  757. package/src/stores/ui-store.ts +11 -93
  758. package/src/styles.css +4 -1
  759. package/src/theme.css +150 -97
  760. package/src/voice/asr-clients.ts +17 -17
  761. package/src/voice/use-dictation.ts +11 -8
  762. package/src/voice/voice-state.ts +57 -0
  763. package/src/voice/voice-store.ts +11 -55
@@ -2,14 +2,16 @@ import { Fragment, useEffect, useMemo, useState } from "react";
2
2
  import { ArrowLeft, ChevronRight } from "lucide-react";
3
3
  import { useShallow } from "zustand/react/shallow";
4
4
  import { isFailureOutcome, type ActivitySpan } from "@schlessera/brain-ui-sdk/protocol";
5
+ import { TraceSteps, type TraceStep } from "@schlessera/brain-ui-kit";
5
6
 
6
- import { api, type ActivityRunRollup } from "../../lib/api-client.js";
7
+ import type { ActivityRunRollup } from "../../lib/api-client.js";
7
8
  import {
8
9
  useActivityStore,
9
10
  narrativeEventsFor,
10
11
  runEvents,
11
12
  runSpans,
12
13
  } from "../../stores/activity-store.js";
14
+ import { useBrainApi } from "../../root-context.js";
13
15
  import { cn } from "../../lib/utils.js";
14
16
  import { formatDuration, formatRelativeTime } from "../chat/tool-views.js";
15
17
  import {
@@ -20,14 +22,29 @@ import {
20
22
  formatSpanUsage,
21
23
  spanToolLabel,
22
24
  } from "./span-bits.js";
25
+ import { RunRollupReceipt } from "./activity-views.js";
23
26
 
24
27
  /**
25
28
  * Chat-less run detail (cron runs; pruned runs show their rollup) — the full
26
29
  * view of one run: its rollup header, the span tree with per-span usage,
27
30
  * attributes and recorded events, and a raw-trace escape hatch for anything
28
31
  * the rendered view does not have an opinion about.
32
+ *
33
+ * `embedded` is the D4 desktop pane: the Actions list sits beside this view
34
+ * from `laptop:` up, so the back chevron only renders below that width, and
35
+ * from `wide:` the span tree moves out to the page's evidence rail
36
+ * (`RunTraceSteps`) — the same store slice, fetched once here.
29
37
  */
30
- export function RunDetail({ runId, onBack }: { runId: string; onBack: () => void }) {
38
+ export function RunDetail({
39
+ runId,
40
+ onBack,
41
+ embedded = false,
42
+ }: {
43
+ runId: string;
44
+ onBack: () => void;
45
+ embedded?: boolean;
46
+ }) {
47
+ const api = useBrainApi();
31
48
  const streamed = useActivityStore(useShallow((s) => runSpans(s, runId)));
32
49
  const events = useActivityStore(useShallow((s) => runEvents(s, runId)));
33
50
  const applySnapshot = useActivityStore((s) => s.applySnapshot);
@@ -38,6 +55,10 @@ export function RunDetail({ runId, onBack }: { runId: string; onBack: () => void
38
55
 
39
56
  useEffect(() => {
40
57
  let active = true;
58
+ setPruned(null);
59
+ setRollup(null);
60
+ setMissing(false);
61
+ setRawOpen(false);
41
62
  api
42
63
  // Payload bodies are excluded from run detail by default; this view's
43
64
  // rows expand to them, so opt in.
@@ -64,7 +85,7 @@ export function RunDetail({ runId, onBack }: { runId: string; onBack: () => void
64
85
  return () => {
65
86
  active = false;
66
87
  };
67
- }, [runId, applySnapshot]);
88
+ }, [runId, applySnapshot, api]);
68
89
 
69
90
  const root = streamed.find((s) => !s.parentSpanId);
70
91
  const title = rollup?.jobName ?? rollup?.name ?? (root ? spanToolLabel(root) : runId);
@@ -93,7 +114,10 @@ export function RunDetail({ runId, onBack }: { runId: string; onBack: () => void
93
114
  <button
94
115
  type="button"
95
116
  onClick={onBack}
96
- className="rounded-md p-1.5 text-muted-foreground transition-colors hover:bg-surface-raised hover:text-foreground"
117
+ className={cn(
118
+ "rounded-md p-1.5 text-muted-foreground transition-colors hover:bg-surface-raised hover:text-foreground",
119
+ embedded && "laptop:hidden"
120
+ )}
97
121
  aria-label="Back"
98
122
  >
99
123
  <ArrowLeft className="h-4 w-4" />
@@ -108,46 +132,18 @@ export function RunDetail({ runId, onBack }: { runId: string; onBack: () => void
108
132
  <div className="mx-auto w-full max-w-3xl space-y-1 p-4">
109
133
  {missing && <p className="text-xs text-muted-foreground">Unknown run.</p>}
110
134
  {rollup && (
111
- <div className="mb-2 flex flex-wrap items-center gap-x-3 gap-y-0.5 rounded-lg border border-border-subtle bg-surface px-3 py-2 text-[11px] text-muted-foreground">
112
- <span className="text-foreground/80">{rollup.origin}</span>
113
- {rollup.outcome && (
114
- <span className={cn(isFailureOutcome(rollup.outcome) && "text-destructive")}>
115
- {rollup.outcome}
116
- </span>
117
- )}
118
- <span>{formatRelativeTime(rollup.startedAt)}</span>
119
- {rollup.durationMs !== null && <span>{formatDuration(rollup.durationMs)}</span>}
120
- <span>
121
- list{" "}
122
- <span className="font-[family-name:var(--font-mono)] text-foreground/80">
123
- {formatEffectiveCost(rollup.costUsd)}
124
- </span>
125
- </span>
126
- <span>
127
- effective{" "}
128
- <span className="font-[family-name:var(--font-mono)] text-foreground/80">
129
- {formatEffectiveCost(
130
- rollup.effectiveCostUsd,
131
- rollup.pricingEstimate,
132
- rollup.billingMode
133
- )}
134
- </span>
135
- </span>
136
- {rollup.billingMode && (
137
- <span>{rollup.billingMode === "api" ? "API billed" : "subscription billed"}</span>
138
- )}
139
- {rollup.pricingEstimate && <span>~ estimated rates</span>}
140
- {totalUsage && (
141
- <span className="font-[family-name:var(--font-mono)] text-foreground/80">
142
- {totalUsage}
143
- </span>
144
- )}
145
- {rollup.failureReason && (
146
- <span className="w-full whitespace-pre-wrap break-words pt-1 text-destructive/80">
147
- {rollup.failureReason}
148
- </span>
149
- )}
150
- </div>
135
+ <RunRollupReceipt
136
+ origin={rollup.origin}
137
+ outcome={rollup.outcome}
138
+ when={formatRelativeTime(rollup.startedAt)}
139
+ duration={rollup.durationMs !== null ? formatDuration(rollup.durationMs) : null}
140
+ listCost={formatEffectiveCost(rollup.costUsd)}
141
+ effectiveCost={formatEffectiveCost(rollup.effectiveCostUsd, rollup.pricingEstimate, rollup.billingMode)}
142
+ billing={rollup.billingMode ? (rollup.billingMode === "api" ? "API billed" : "subscription billed") : null}
143
+ estimated={Boolean(rollup.pricingEstimate)}
144
+ usage={totalUsage}
145
+ failureReason={rollup.failureReason}
146
+ />
151
147
  )}
152
148
  {pruned && (
153
149
  <div className="rounded-lg border border-border-subtle bg-surface p-3 text-xs text-muted-foreground">
@@ -155,9 +151,11 @@ export function RunDetail({ runId, onBack }: { runId: string; onBack: () => void
155
151
  <pre className="mt-2 overflow-x-auto text-[11px]">{JSON.stringify(pruned, null, 2)}</pre>
156
152
  </div>
157
153
  )}
158
- {streamed.map((span) => (
159
- <DetailSpanRow key={span.spanId} span={span} depth={depthOf(span, streamed)} />
160
- ))}
154
+ <div className={cn("space-y-1", embedded && "wide:hidden")}>
155
+ {streamed.map((span) => (
156
+ <DetailSpanRow key={span.spanId} span={span} depth={depthOf(span, streamed)} />
157
+ ))}
158
+ </div>
161
159
  {!pruned && !missing && streamed.length === 0 && (
162
160
  <p className="text-xs text-muted-foreground">No spans recorded for this run.</p>
163
161
  )}
@@ -187,6 +185,42 @@ export function RunDetail({ runId, onBack }: { runId: string; onBack: () => void
187
185
  );
188
186
  }
189
187
 
188
+ /**
189
+ * The run's trace as the kit's list timeline, for the D4 evidence rail. Reads
190
+ * the store slice `RunDetail` filled — no second fetch — and stays a record:
191
+ * the rail's steps do not expand, the escape hatch for that is the detail's
192
+ * raw trace.
193
+ */
194
+ export function RunTraceSteps({ runId }: { runId: string }) {
195
+ const streamed = useActivityStore(useShallow((s) => runSpans(s, runId)));
196
+ const steps = useMemo<TraceStep[]>(
197
+ () =>
198
+ streamed.map((span) => ({
199
+ state: traceState(span),
200
+ tool: spanToolLabel(span),
201
+ text: span.outcomeReason ?? (span.kind !== "tool" ? span.kind : undefined),
202
+ time:
203
+ span.endedAt !== undefined
204
+ ? formatDuration(span.endedAt - (span.waitUntil ?? span.startedAt))
205
+ : undefined,
206
+ })),
207
+ [streamed]
208
+ );
209
+ if (steps.length === 0) {
210
+ return <p className="text-xs text-muted-foreground/70">No spans recorded for this run.</p>;
211
+ }
212
+ return <TraceSteps variant="list" steps={steps} />;
213
+ }
214
+
215
+ /** Same boundary `toolState` draws for the run cards: open is active, a
216
+ * failure outcome is failed and any other non-success outcome (cancelled,
217
+ * skipped) is skipped. */
218
+ function traceState(span: ActivitySpan): TraceStep["state"] {
219
+ if (span.outcome === undefined || span.outcome === null) return "active";
220
+ if (span.outcome === "success") return "done";
221
+ return isFailureOutcome(span.outcome) ? "failed" : "skipped";
222
+ }
223
+
190
224
  /**
191
225
  * One span tree row. EVERY span expands — a tool span to its recorded payload
192
226
  * (AE7), any span to its usage, attributes and recorded events. The uniform
@@ -1,14 +1,19 @@
1
- import { AlertTriangle, Bot, Clock, Timer } from "lucide-react";
2
1
  import { useShallow } from "zustand/react/shallow";
3
- import { isFailureOutcome, type ActivitySpan } from "@schlessera/brain-ui-sdk/protocol";
2
+ import type { ActivitySpan } from "@schlessera/brain-ui-sdk/protocol";
4
3
 
5
4
  import type { ActivityRunSummary } from "../../lib/api-client.js";
6
5
  import { useNow } from "../../hooks/use-now.js";
7
6
  import { useActivityStore } from "../../stores/activity-store.js";
8
- import { cn } from "../../lib/utils.js";
9
7
  import { formatDuration, formatRelativeTime } from "../chat/tool-views.js";
8
+ import { HistoryRow, LiveRunCard, toolState } from "./activity-views.js";
10
9
  import { runCostText, spanToolLabel } from "./span-bits.js";
11
10
 
11
+ /**
12
+ * The containers (S7) for the Activity index's rows: `LiveRow` subscribes to
13
+ * a running run's child spans and renders a `LiveRunCard`; `RunRow` is a
14
+ * recorded run rendered as a `HistoryRow`. The views are in
15
+ * `activity-views.tsx`.
16
+ */
12
17
  export function LiveRow({
13
18
  span,
14
19
  onOpen,
@@ -21,31 +26,16 @@ export function LiveRow({
21
26
  );
22
27
  const now = useNow();
23
28
  const current = children.filter((c) => c.outcome === undefined).at(-1);
24
- const currentLabel = current ? spanToolLabel(current) : null;
25
29
  return (
26
- <button
27
- type="button"
28
- onClick={() => onOpen({ runId: span.runId, origin: span.origin, sessionId: span.sessionId })}
29
- className="flex w-full items-center gap-2 rounded-lg border border-border-subtle bg-surface px-3 py-2 text-left text-xs transition-colors hover:bg-surface-raised"
30
- >
31
- <span className="h-2 w-2 shrink-0 animate-pulse rounded-full bg-primary" />
32
- {span.origin === "cron" ? (
33
- <Clock className="h-3.5 w-3.5 shrink-0 text-muted-foreground" />
34
- ) : (
35
- <Bot className="h-3.5 w-3.5 shrink-0 text-muted-foreground" />
36
- )}
37
- <span className="truncate font-medium">
38
- {span.jobName ?? span.name}
39
- </span>
40
- {/* A span-only run (plain cron job) has no current step — name+elapsed
41
- is its whole live story. */}
42
- {currentLabel && (
43
- <span className="truncate text-muted-foreground">· {currentLabel}</span>
44
- )}
45
- <span className="ml-auto shrink-0 font-[family-name:var(--font-mono)] text-[10px] text-muted-foreground/60">
46
- {formatDuration(now - span.startedAt)}
47
- </span>
48
- </button>
30
+ <LiveRunCard
31
+ name={span.jobName ?? span.name}
32
+ // A span-only run (plain cron job) has no current step — name+elapsed
33
+ // is its whole live story.
34
+ current={current ? spanToolLabel(current) : null}
35
+ elapsed={formatDuration(now - span.startedAt)}
36
+ tools={children.map((c) => ({ label: spanToolLabel(c), state: toolState(c.outcome) }))}
37
+ onOpen={() => onOpen({ runId: span.runId, origin: span.origin, sessionId: span.sessionId })}
38
+ />
49
39
  );
50
40
  }
51
41
 
@@ -56,42 +46,20 @@ export function RunRow({
56
46
  run: ActivityRunSummary;
57
47
  onOpen: (row: ActivityRunSummary) => void;
58
48
  }) {
59
- const failed = isFailureOutcome(run.outcome);
60
49
  // Effective cost only — list price lives on the Spend card and the detail
61
50
  // view. "—" is unknown, never $0.00 (AE3); a pre-pricing server that never
62
51
  // sent the field keeps the original list-cost span instead (see runCostText).
63
52
  const cost = runCostText(run);
53
+ const meta = [cost, run.durationMs !== null ? formatDuration(run.durationMs) : null, formatRelativeTime(run.startedAt)]
54
+ .filter((s): s is string => Boolean(s))
55
+ .join(" · ");
64
56
  return (
65
- <button
66
- type="button"
67
- onClick={() => onOpen(run)}
68
- className={cn(
69
- "flex w-full items-center gap-2 rounded-lg px-3 py-2 text-left text-xs transition-colors hover:bg-surface-raised",
70
- failed && "border border-destructive/30 bg-destructive/5"
71
- )}
72
- >
73
- {run.origin === "cron" ? (
74
- <Clock className="h-3.5 w-3.5 shrink-0 text-muted-foreground" />
75
- ) : (
76
- <Bot className="h-3.5 w-3.5 shrink-0 text-muted-foreground" />
77
- )}
78
- <span className="truncate">{run.jobName ?? run.name}</span>
79
- {failed && <AlertTriangle className="h-3 w-3 shrink-0 text-destructive" />}
80
- {run.outcome && run.outcome !== "success" && (
81
- <span className={cn("text-[10px] uppercase", failed ? "text-destructive" : "text-muted-foreground")}>
82
- {run.outcome}
83
- </span>
84
- )}
85
- <span className="ml-auto flex shrink-0 items-center gap-2 font-[family-name:var(--font-mono)] text-[10px] text-muted-foreground/60">
86
- {cost !== null && <span>{cost}</span>}
87
- {run.durationMs !== null && (
88
- <span className="flex items-center gap-0.5">
89
- <Timer className="h-3 w-3" />
90
- {formatDuration(run.durationMs)}
91
- </span>
92
- )}
93
- <span>{formatRelativeTime(run.startedAt)}</span>
94
- </span>
95
- </button>
57
+ <HistoryRow
58
+ name={run.jobName ?? run.name}
59
+ cron={run.origin === "cron"}
60
+ outcome={run.outcome}
61
+ meta={meta}
62
+ onOpen={() => onOpen(run)}
63
+ />
96
64
  );
97
65
  }
@@ -0,0 +1,155 @@
1
+ import { ActionCard, AgentRunCard, Button, ListRow, Receipt } from "@schlessera/brain-ui-kit";
2
+ import type { AgentRunTool, ReceiptRow, RunToolState } from "@schlessera/brain-ui-kit";
3
+ import { isFailureOutcome, type ActivityIntent, type ActivitySpanOutcome } from "@schlessera/brain-ui-sdk/protocol";
4
+
5
+ /**
6
+ * The Activity surface's rows, rendered from props (S7, the `activity`
7
+ * directory). The design's `1c` screen draws a running run as an
8
+ * `AgentRunCard` (the tool strip is "the shortest honest answer to 'is real
9
+ * work happening?'") and the day's history as plain `ListRow`s; `1c`/`2a`
10
+ * draw a thing that needs you as an `ActionCard`. The containers in
11
+ * `activity-run-list.tsx`, `activity-page.tsx` and `activity-run-detail.tsx`
12
+ * read the store and the API; these decide how a row looks.
13
+ */
14
+
15
+ /** A child span's outcome as the kit's tool-strip state. */
16
+ export function toolState(outcome: ActivitySpanOutcome | undefined | null): RunToolState {
17
+ if (outcome === undefined || outcome === null) return "active";
18
+ if (outcome === "success") return "done";
19
+ return isFailureOutcome(outcome) ? "failed" : "idle";
20
+ }
21
+
22
+ export interface LiveRunCardProps {
23
+ name: string;
24
+ /** The step in flight, if the run has steps at all (a plain cron job has none). */
25
+ current: string | null;
26
+ elapsed: string;
27
+ tools: AgentRunTool[];
28
+ onOpen: () => void;
29
+ }
30
+
31
+ /**
32
+ * A running run. The kit card carries no handler of its own — the design
33
+ * draws it as a monitor — so the row is a native button around it, named
34
+ * for what opening it does.
35
+ */
36
+ export function LiveRunCard(p: LiveRunCardProps) {
37
+ return (
38
+ <button
39
+ type="button"
40
+ onClick={p.onOpen}
41
+ aria-label={`Open run ${p.name}`}
42
+ className="block w-full rounded-[13px] text-left transition-[filter] hover:brightness-110 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--bk-focus-ring)]"
43
+ >
44
+ <AgentRunCard
45
+ agent={p.name}
46
+ state="running"
47
+ meta={p.elapsed}
48
+ task={p.current ? `▸ ${p.current}` : undefined}
49
+ progress={null}
50
+ tools={p.tools.length ? p.tools : undefined}
51
+ />
52
+ </button>
53
+ );
54
+ }
55
+
56
+ export interface HistoryRowProps {
57
+ name: string;
58
+ cron: boolean;
59
+ /** The run's outcome, or null while unknown. */
60
+ outcome: ActivitySpanOutcome | null;
61
+ /** Cost, duration and when — already formatted, joined with a middle dot. */
62
+ meta: string;
63
+ onOpen: () => void;
64
+ }
65
+
66
+ export function HistoryRow(p: HistoryRowProps) {
67
+ const failed = isFailureOutcome(p.outcome);
68
+ return (
69
+ <ListRow
70
+ variant="plain"
71
+ icon={p.cron ? "repeat" : "agent"}
72
+ iconTone={failed ? "red" : "neutral"}
73
+ title={p.name}
74
+ subtitle={p.outcome && p.outcome !== "success" ? p.outcome : undefined}
75
+ subMono
76
+ value={p.meta}
77
+ valueTone={failed ? "red" : "neutral"}
78
+ onClick={p.onOpen}
79
+ />
80
+ );
81
+ }
82
+
83
+ export interface IntentCardProps {
84
+ intent: ActivityIntent;
85
+ /** When it was raised, already formatted. */
86
+ when: string;
87
+ onOpen: () => void;
88
+ onDismiss: () => void;
89
+ /** Print `d` on Dismiss: the list binds it while the card holds focus (D36). */
90
+ keyHint?: boolean;
91
+ }
92
+
93
+ /** A thing that needs attention: failure, stuck, or a completion to note. */
94
+ export function IntentCard(p: IntentCardProps) {
95
+ const kind = p.intent.kind;
96
+ return (
97
+ <ActionCard
98
+ kind={kind === "failure" ? "dead-letter" : "fyi"}
99
+ icon={kind === "stuck" ? "deadline" : undefined}
100
+ kindLabel={kind === "failure" ? "Failed" : kind === "stuck" ? "Stuck" : "Completed"}
101
+ title={p.intent.title}
102
+ body={p.intent.body || undefined}
103
+ footMeta={p.when}
104
+ footDot={kind === "failure" ? "red" : kind === "stuck" ? "amber" : "teal"}
105
+ footPulse={kind === "stuck"}
106
+ chevron={false}
107
+ onClick={p.onOpen}
108
+ >
109
+ <div className="mt-2 flex justify-end" onClick={(e) => e.stopPropagation()}>
110
+ <Button label={p.keyHint ? "Dismiss · d" : "Dismiss"} tone="quiet" size="sm" block={false} onClick={p.onDismiss} />
111
+ </div>
112
+ </ActionCard>
113
+ );
114
+ }
115
+
116
+ export interface RunRollupReceiptProps {
117
+ origin: string;
118
+ outcome: ActivitySpanOutcome | null;
119
+ when: string;
120
+ duration: string | null;
121
+ listCost: string;
122
+ effectiveCost: string;
123
+ billing: string | null;
124
+ estimated: boolean;
125
+ usage: string | null;
126
+ failureReason: string | null;
127
+ }
128
+
129
+ /** The rollup header of a run's detail: machine facts, key/value, as a `Receipt`. */
130
+ export function RunRollupReceipt(p: RunRollupReceiptProps) {
131
+ const failed = isFailureOutcome(p.outcome);
132
+ const rows: ReceiptRow[] = [
133
+ { k: "origin", v: p.origin },
134
+ ...(p.outcome ? [{ k: "outcome", v: p.outcome, tone: failed ? ("red" as const) : ("teal" as const) }] : []),
135
+ { k: "started", v: p.when },
136
+ ...(p.duration ? [{ k: "took", v: p.duration }] : []),
137
+ { k: "list", v: p.listCost },
138
+ { k: "effective", v: `${p.effectiveCost}${p.billing ? ` · ${p.billing}` : ""}${p.estimated ? " · ~ estimated rates" : ""}` },
139
+ ...(p.usage ? [{ k: "usage", v: p.usage }] : []),
140
+ ];
141
+ return (
142
+ <div className="mb-2">
143
+ <Receipt
144
+ title="This run"
145
+ titleIcon="ledger"
146
+ titleTone={failed ? "red" : "teal"}
147
+ rows={rows}
148
+ footnote={p.failureReason ?? ""}
149
+ footIcon={p.failureReason ? "failed" : undefined}
150
+ footTone={p.failureReason ? "red" : undefined}
151
+ keyWidth={66}
152
+ />
153
+ </div>
154
+ );
155
+ }
@@ -0,0 +1,80 @@
1
+ import { ActionCard, Button } from "@schlessera/brain-ui-kit";
2
+ import type { KeyboardEvent } from "react";
3
+ import type { ToolCall } from "../../stores/chat-store.js";
4
+ import { focusAfterDecision, singleKey } from "../../lib/single-key.js";
5
+ import { getToolLabel, getToolSummary } from "../chat/tool-views.js";
6
+ import { KeyCap } from "../layout/key-cap.js";
7
+
8
+ /**
9
+ * A pending tool approval as an Actions-pane card (D37): the transcript copy
10
+ * and this row are the same item in two places, and deciding either
11
+ * resolves both. The kit `ActionCard kind="approval"` carries the bold
12
+ * border that says "a run is stopped on this"; the buttons are the same
13
+ * three the transcript draws, with the same keys — `a` / `d` while the card
14
+ * holds focus, printed on the buttons, and "Always allow" deliberately
15
+ * without one, carrying its `write_policy` effect chip instead.
16
+ *
17
+ * The buttons follow the kit `ApprovalCard`'s rule (seventh drop, ruling 10):
18
+ * Allow takes the remaining width, Deny is content-sized with a 96 x 44 floor
19
+ * so it can never become a sliver, and no even split claims the two answers
20
+ * are equally likely. The title — the tool and its target — is the kit
21
+ * `ActionCard`'s, which wraps; the target is the record and never truncates.
22
+ */
23
+ const ALLOW_MOUNT = { flex: "1 1 auto", minWidth: 0, width: "auto" } as const;
24
+ const DENY_MOUNT = { flex: "0 0 auto", minWidth: 96, minHeight: 44, width: "auto" } as const;
25
+ export interface ApprovalCardProps {
26
+ tool: ToolCall;
27
+ /** Where it came from, for the foot line. */
28
+ origin: string;
29
+ keys: boolean;
30
+ onDecide: (approved: boolean, always?: boolean) => void;
31
+ }
32
+
33
+ export const APPROVAL_CARD = "[data-approval-card]";
34
+
35
+ export function ApprovalCard(p: ApprovalCardProps) {
36
+ const label = getToolLabel(p.tool.name);
37
+ const summary = getToolSummary(p.tool);
38
+ function decide(card: HTMLElement | null, approved: boolean, always?: boolean) {
39
+ if (card) focusAfterDecision(card, APPROVAL_CARD, "[data-needs-you-heading]");
40
+ p.onDecide(approved, always);
41
+ }
42
+ function onKeyDown(event: KeyboardEvent<HTMLDivElement>) {
43
+ if (!p.keys) return;
44
+ const key = singleKey(event);
45
+ if (key !== "a" && key !== "d") return;
46
+ event.preventDefault();
47
+ decide(event.currentTarget, key === "a");
48
+ }
49
+ return (
50
+ <div data-approval-card="" role="group" aria-label={`Approval: ${label}`} tabIndex={0} onKeyDown={onKeyDown} className="rounded-[14px] outline-none focus-visible:ring-2 focus-visible:ring-primary/50">
51
+ <ActionCard
52
+ kind="approval"
53
+ title={summary ? `${label} · ${summary}` : label}
54
+ rightMeta="blocks a run"
55
+ rightMetaTone="red"
56
+ footMeta={p.origin}
57
+ footDot="amber"
58
+ footPulse
59
+ chevron={false}
60
+ >
61
+ <div className="mt-2 flex flex-wrap gap-2">
62
+ <Button label="Allow" icon="confirm" tone="primary" size="sm" center block={false} style={ALLOW_MOUNT} onClick={() => decide(cardOf(), true)} />
63
+ {p.tool.approvalKind !== "command" && (
64
+ <Button label="Always allow" effect="write_policy" tone="ghost" size="sm" block={false} onClick={() => decide(cardOf(), true, true)} />
65
+ )}
66
+ <Button label="Deny" icon="deny" tone="danger" size="sm" center block={false} style={DENY_MOUNT} onClick={() => decide(cardOf(), false)} />
67
+ {p.keys && (
68
+ <span className="ml-auto flex items-center gap-2 text-[10px] text-muted-foreground" aria-hidden="true">
69
+ <span>allow <KeyCap>a</KeyCap></span>
70
+ <span>deny <KeyCap>d</KeyCap></span>
71
+ </span>
72
+ )}
73
+ </div>
74
+ </ActionCard>
75
+ </div>
76
+ );
77
+ function cardOf(): HTMLElement | null {
78
+ return (document.activeElement as HTMLElement | null)?.closest(APPROVAL_CARD) ?? null;
79
+ }
80
+ }
@@ -1,9 +1,9 @@
1
1
  import { useEffect, useState } from "react";
2
- import { AlertTriangle, Newspaper, X } from "lucide-react";
3
2
 
4
- import { api, type ActivityDigest } from "../../lib/api-client.js";
3
+ import type { ActivityDigest } from "../../lib/api-client.js";
4
+ import { useBrainApi } from "../../root-context.js";
5
5
  import { useUIStore } from "../../stores/ui-store.js";
6
- import { cn } from "../../lib/utils.js";
6
+ import { DigestSummary } from "./digest-summary.js";
7
7
  import { digestCostClause } from "./span-bits.js";
8
8
 
9
9
  /**
@@ -13,17 +13,24 @@ import { digestCostClause } from "./span-bits.js";
13
13
  * dismissing persists server-side, so a phone and a laptop don't each nag.
14
14
  * An empty window stays quiet — no card for "nothing happened". The window
15
15
  * is labeled: the card says what period it covers, never implies "now".
16
+ *
17
+ * This is the container (S7): the fetch, the once-per-digest rule and the
18
+ * dismissal live here; `DigestSummary` draws the kit `DigestCard`.
16
19
  */
17
20
  export function DigestCard() {
21
+ const api = useBrainApi();
18
22
  const [digest, setDigest] = useState<ActivityDigest | null>(null);
19
23
  const [visible, setVisible] = useState(false);
20
24
  const setActiveView = useUIStore((s) => s.setActiveView);
21
25
 
22
26
  useEffect(() => {
27
+ let active = true;
28
+ setDigest(null);
29
+ setVisible(false);
23
30
  void api
24
31
  .activityDigest()
25
32
  .then(({ digest, dismissedAt }) => {
26
- if (!digest || digest.runs === 0) return;
33
+ if (!active || !digest || digest.runs === 0) return;
27
34
  if (digest.generatedAt <= dismissedAt) return;
28
35
  setDigest(digest);
29
36
  setVisible(true);
@@ -31,7 +38,8 @@ export function DigestCard() {
31
38
  .catch(() => {
32
39
  // No digest is a quiet state, never an error surface.
33
40
  });
34
- }, []);
41
+ return () => { active = false; };
42
+ }, [api]);
35
43
 
36
44
  if (!visible || !digest) return null;
37
45
 
@@ -40,63 +48,19 @@ export function DigestCard() {
40
48
  void api.activityDigestDismiss().catch(() => {});
41
49
  }
42
50
 
43
- const windowLabel = `${formatDay(digest.windowStart)} – ${formatDay(digest.windowEnd)}`;
44
- // Effective-only spend clause; a digest persisted before pricing shipped
45
- // falls back to its old list-cost clause inside the helper.
46
- const costClause = digestCostClause(digest);
47
-
48
51
  return (
49
- <div
50
- className={cn(
51
- "mx-auto mb-3 w-full max-w-2xl rounded-xl border p-3 text-xs",
52
- digest.failures > 0
53
- ? "border-destructive/30 bg-destructive/5"
54
- : "border-border-subtle bg-surface"
55
- )}
56
- >
57
- <div className="flex items-center gap-2">
58
- <Newspaper className="h-4 w-4 shrink-0 text-muted-foreground" />
59
- <span className="font-medium">While you were away</span>
60
- <span className="text-[10px] text-muted-foreground/60">{windowLabel}</span>
61
- <button
62
- type="button"
63
- onClick={dismiss}
64
- className="ml-auto rounded p-1 text-muted-foreground transition-colors hover:text-foreground"
65
- aria-label="Dismiss"
66
- >
67
- <X className="h-3.5 w-3.5" />
68
- </button>
69
- </div>
70
- <div className="mt-1.5 text-muted-foreground">
71
- {digest.runs} run{digest.runs === 1 ? "" : "s"}
72
- {digest.failures > 0 && (
73
- <span className="text-destructive"> · {digest.failures} failed</span>
74
- )}
75
- {costClause && ` · ${costClause}`}
76
- </div>
77
- {digest.notable.length > 0 && (
78
- <div className="mt-1.5 space-y-0.5">
79
- {digest.notable.slice(0, 3).map((n) => (
80
- <div key={n.runId} className="flex items-center gap-1.5 text-[11px]">
81
- <AlertTriangle className="h-3 w-3 shrink-0 text-destructive" />
82
- <span className="truncate">
83
- {n.jobName ?? n.name} — {n.outcome}
84
- </span>
85
- </div>
86
- ))}
87
- </div>
88
- )}
89
- <button
90
- type="button"
91
- onClick={() => {
92
- dismiss();
93
- setActiveView("activity");
94
- }}
95
- className="mt-2 text-[11px] font-medium text-primary hover:underline"
96
- >
97
- Open Activity
98
- </button>
99
- </div>
52
+ <DigestSummary
53
+ digest={digest}
54
+ windowLabel={`${formatDay(digest.windowStart)} ${formatDay(digest.windowEnd)}`}
55
+ // Effective-only spend clause; a digest persisted before pricing shipped
56
+ // falls back to its old list-cost clause inside the helper.
57
+ costClause={digestCostClause(digest)}
58
+ onDismiss={dismiss}
59
+ onOpen={() => {
60
+ dismiss();
61
+ setActiveView("activity");
62
+ }}
63
+ />
100
64
  );
101
65
  }
102
66