@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
@@ -0,0 +1,188 @@
1
+ import { Button, Callout } from "@schlessera/brain-ui-kit";
2
+ import { CheckCircle2 } from "lucide-react";
3
+ import type { ReactNode, RefObject } from "react";
4
+ import { useId } from "react";
5
+ import { Kbd } from "../layout/kbd.js";
6
+
7
+ /**
8
+ * The "Add to brain" form, rendered from props (S6). `AddPanel` is the
9
+ * container: it owns the draft, the `brain add` / `brain index` requests and
10
+ * the `operation.epoch` guard that keeps a stale save from landing in a
11
+ * fresh form; this owns the two screens — the form, and the receipt after a
12
+ * save — and nothing else.
13
+ *
14
+ * `state` is the container's machine: `editing` and `error` show the form
15
+ * (with the error under it), `saving` is the form with the Add button inert,
16
+ * `saved` is the receipt. On the receipt, `indexed` is three-valued because
17
+ * an older server does not report it: `false` offers a retry, `true` says
18
+ * so, `undefined` says the server did not say.
19
+ *
20
+ * Fields stay native (the kit has no text input); the buttons are the kit's.
21
+ * The content field's ref is the container's, because focus after open and
22
+ * after "Add another" is timed against the panel's slide, which the
23
+ * container owns.
24
+ */
25
+ export type AddState = "editing" | "saving" | "saved" | "error";
26
+
27
+ export interface AddDraft {
28
+ content: string;
29
+ title: string;
30
+ type: string;
31
+ tags: string;
32
+ }
33
+
34
+ export interface AddFormProps {
35
+ state: AddState;
36
+ draft: AddDraft;
37
+ /** Types already in the brain, offered as completions — a hint list, not a closed set. */
38
+ knownTypes: string[];
39
+ error: string;
40
+ savedPath: string;
41
+ indexed: boolean | undefined;
42
+ indexing: boolean;
43
+ contentRef: RefObject<HTMLTextAreaElement | null>;
44
+ onDraft: (patch: Partial<AddDraft>) => void;
45
+ onSave: () => void;
46
+ onRetryIndex: () => void;
47
+ onAddAnother: () => void;
48
+ onClose: () => void;
49
+ }
50
+
51
+ export function AddForm(p: AddFormProps) {
52
+ const typesId = useId();
53
+ const saving = p.state === "saving";
54
+ const canSave = p.draft.content.trim().length > 0 && !saving;
55
+
56
+ function onKeyDown(e: React.KeyboardEvent) {
57
+ // Cmd/Ctrl+Enter saves from anywhere in the form. The container refuses
58
+ // a save that is not from `editing` or `error`, so the receipt is safe.
59
+ if ((e.metaKey || e.ctrlKey) && e.key === "Enter") {
60
+ e.preventDefault();
61
+ p.onSave();
62
+ }
63
+ }
64
+
65
+ if (p.state === "saved") {
66
+ return (
67
+ <div className="flex h-full flex-col" onKeyDown={onKeyDown}>
68
+ <div className="flex flex-1 flex-col items-center justify-center gap-4 px-8 text-center">
69
+ <CheckCircle2 className="h-8 w-8 text-primary" />
70
+ <p className="text-sm text-foreground">Added to your brain.</p>
71
+ <p className="text-xs text-muted-foreground">
72
+ {p.indexed === false
73
+ ? "Saved, but not indexed. Your content is safe; search may not find it yet."
74
+ : p.indexed === true
75
+ ? "Saved and indexed. Run a sync when you want to push it."
76
+ : "Saved. This server did not report whether indexing completed."}
77
+ </p>
78
+ {p.savedPath && <p className="break-all text-xs text-muted-foreground">{p.savedPath}</p>}
79
+ {p.indexed === false && (
80
+ <div className="flex flex-col items-center gap-2" role="status">
81
+ {p.error && <p className="text-xs text-destructive">{p.error}</p>}
82
+ <Button
83
+ label={p.indexing ? "Indexing…" : "Retry indexing"}
84
+ icon="retry"
85
+ tone="primary"
86
+ size="sm"
87
+ block={false}
88
+ disabled={p.indexing}
89
+ onClick={p.onRetryIndex}
90
+ />
91
+ </div>
92
+ )}
93
+ <div className="flex gap-2">
94
+ <Button label="Add another" icon="add" tone="ghost" size="sm" block={false} onClick={p.onAddAnother} />
95
+ <Button label="Done" icon="confirm" tone="primary" size="sm" block={false} onClick={p.onClose} />
96
+ </div>
97
+ </div>
98
+ </div>
99
+ );
100
+ }
101
+
102
+ return (
103
+ <div className="flex h-full flex-col" onKeyDown={onKeyDown}>
104
+ <div className="flex-1 space-y-4 overflow-y-auto p-5">
105
+ <Field label="Note">
106
+ <textarea
107
+ ref={p.contentRef}
108
+ value={p.draft.content}
109
+ onChange={(e) => p.onDraft({ content: e.target.value })}
110
+ rows={8}
111
+ placeholder="What do you want to remember?"
112
+ className="w-full resize-y rounded-lg border border-border bg-surface-raised px-3 py-2 text-sm text-foreground outline-none transition-colors placeholder:text-muted-foreground focus:border-primary/40"
113
+ />
114
+ </Field>
115
+
116
+ <Field label="Title" hint="optional, derived from the note if empty">
117
+ <input
118
+ value={p.draft.title}
119
+ onChange={(e) => p.onDraft({ title: e.target.value })}
120
+ className="w-full rounded-lg border border-border bg-surface-raised px-3 py-2 text-sm text-foreground outline-none transition-colors focus:border-primary/40"
121
+ />
122
+ </Field>
123
+
124
+ <div className="grid grid-cols-2 gap-3">
125
+ <Field label="Type" hint="optional">
126
+ <input
127
+ value={p.draft.type}
128
+ onChange={(e) => p.onDraft({ type: e.target.value })}
129
+ list={typesId}
130
+ placeholder="note"
131
+ className="w-full rounded-lg border border-border bg-surface-raised px-3 py-2 text-sm text-foreground outline-none transition-colors placeholder:text-muted-foreground focus:border-primary/40"
132
+ />
133
+ <datalist id={typesId}>
134
+ {p.knownTypes.map((t) => (
135
+ <option key={t} value={t} />
136
+ ))}
137
+ </datalist>
138
+ </Field>
139
+
140
+ <Field label="Tags" hint="comma-separated">
141
+ <input
142
+ value={p.draft.tags}
143
+ onChange={(e) => p.onDraft({ tags: e.target.value })}
144
+ placeholder="idea, reading"
145
+ className="w-full rounded-lg border border-border bg-surface-raised px-3 py-2 text-sm text-foreground outline-none transition-colors placeholder:text-muted-foreground focus:border-primary/40"
146
+ />
147
+ </Field>
148
+ </div>
149
+
150
+ {p.state === "error" && (
151
+ <div role="alert">
152
+ <Callout tone="red" variant="banner" icon="failed" mono text={p.error} />
153
+ </div>
154
+ )}
155
+ </div>
156
+
157
+ <div className="flex items-center justify-between border-t border-border px-5 py-3">
158
+ <span className="text-[11px] text-muted-foreground">
159
+ <Kbd>Ctrl</Kbd>/<Kbd>Cmd</Kbd> + <Kbd>↵</Kbd> to save
160
+ </span>
161
+ <div className="flex gap-2">
162
+ <Button label="Cancel" tone="quiet" size="sm" block={false} onClick={p.onClose} />
163
+ <Button
164
+ label={saving ? "Saving…" : "Add"}
165
+ icon="add"
166
+ tone="primary"
167
+ size="sm"
168
+ block={false}
169
+ disabled={!canSave}
170
+ onClick={p.onSave}
171
+ />
172
+ </div>
173
+ </div>
174
+ </div>
175
+ );
176
+ }
177
+
178
+ function Field({ label, hint, children }: { label: string; hint?: string; children: ReactNode }) {
179
+ return (
180
+ <label className="block space-y-1.5">
181
+ <span className="text-xs font-medium text-foreground">
182
+ {label}
183
+ {hint && <span className="font-normal text-muted-foreground"> — {hint}</span>}
184
+ </span>
185
+ {children}
186
+ </label>
187
+ );
188
+ }
@@ -1,10 +1,7 @@
1
1
  import { useState, useEffect, useRef } from "react";
2
- import { Loader2, CheckCircle2, XCircle } from "lucide-react";
3
2
  import { SlidePanel } from "../layout/slide-panel.js";
4
- import { Kbd } from "../layout/kbd.js";
5
- import { api } from "../../lib/api-client.js";
6
-
7
- type State = "editing" | "saving" | "saved" | "error";
3
+ import { useBrainApi } from "../../root-context.js";
4
+ import { AddForm, type AddState as State } from "./add-form.js";
8
5
 
9
6
  /** Split the tags field on commas; empties dropped so "a,,b," is clean. */
10
7
  function parseTags(raw: string): string[] {
@@ -14,6 +11,13 @@ function parseTags(raw: string): string[] {
14
11
  .filter(Boolean);
15
12
  }
16
13
 
14
+ /**
15
+ * The container (S6): the draft, `brain add`, `brain index` and the
16
+ * `operation.epoch` guard live here; `AddForm` draws from props. The epoch
17
+ * is bumped on open, on close, on "Add another" and on every request, so a
18
+ * response from a form the user has already left cannot land in the one
19
+ * they are looking at.
20
+ */
17
21
  export function AddPanel({
18
22
  open,
19
23
  onClose,
@@ -21,12 +25,17 @@ export function AddPanel({
21
25
  open: boolean;
22
26
  onClose: () => void;
23
27
  }) {
28
+ const api = useBrainApi();
24
29
  const [content, setContent] = useState("");
25
30
  const [title, setTitle] = useState("");
26
31
  const [type, setType] = useState("");
27
32
  const [tags, setTags] = useState("");
28
33
  const [state, setState] = useState<State>("editing");
29
34
  const [error, setError] = useState("");
35
+ const [savedPath, setSavedPath] = useState("");
36
+ const [indexed, setIndexed] = useState<boolean | undefined>();
37
+ const [indexing, setIndexing] = useState(false);
38
+ const operation = useRef({ epoch: 0 }).current;
30
39
  // Types already in the brain, offered as completions — `brain add` accepts
31
40
  // any string, so this is a hint list, not a closed set.
32
41
  const [knownTypes, setKnownTypes] = useState<string[]>([]);
@@ -35,6 +44,11 @@ export function AddPanel({
35
44
 
36
45
  useEffect(() => {
37
46
  if (!open) return;
47
+ operation.epoch++;
48
+ setKnownTypes([]);
49
+ setSavedPath("");
50
+ setIndexed(undefined);
51
+ setIndexing(false);
38
52
  setContent("");
39
53
  setTitle("");
40
54
  setType("");
@@ -55,31 +69,57 @@ export function AddPanel({
55
69
  });
56
70
 
57
71
  return () => {
72
+ operation.epoch++;
58
73
  cancelled = true;
59
74
  clearTimeout(t);
60
75
  };
61
- }, [open]);
76
+ }, [open, operation, api]);
62
77
 
63
78
  async function handleSave() {
64
79
  const body = content.trim();
65
- if (!body || state === "saving") return;
80
+ if (!body || (state !== "editing" && state !== "error")) return;
81
+ const current = ++operation.epoch;
66
82
 
67
83
  setState("saving");
68
84
  setError("");
69
85
  try {
70
- await api.brainAdd(body, {
86
+ const result = await api.brainAdd(body, {
71
87
  type: type.trim() || undefined,
72
88
  title: title.trim() || undefined,
73
89
  tags: parseTags(tags).length ? parseTags(tags) : undefined,
74
90
  });
91
+ if (current !== operation.epoch) return;
92
+ setSavedPath(result.path ?? "");
93
+ setIndexed(result.indexed);
94
+ setError(result.indexed === false ? result.indexError || "Indexing failed." : "");
75
95
  setState("saved");
76
96
  } catch (err: any) {
97
+ if (current !== operation.epoch) return;
77
98
  setError(err?.message || "Add failed");
78
99
  setState("error");
79
100
  }
80
101
  }
81
102
 
103
+ async function retryIndex() {
104
+ if (indexing) return;
105
+ const current = ++operation.epoch;
106
+ setIndexing(true);
107
+ setError("");
108
+ try {
109
+ await api.brainIndex();
110
+ if (current === operation.epoch) setIndexed(true);
111
+ } catch (err) {
112
+ if (current === operation.epoch) setError(err instanceof Error ? err.message : "Indexing failed.");
113
+ } finally {
114
+ if (current === operation.epoch) setIndexing(false);
115
+ }
116
+ }
117
+
82
118
  function handleAddAnother() {
119
+ operation.epoch++;
120
+ setSavedPath("");
121
+ setIndexed(undefined);
122
+ setIndexing(false);
83
123
  setContent("");
84
124
  setTitle("");
85
125
  setType("");
@@ -88,144 +128,28 @@ export function AddPanel({
88
128
  setTimeout(() => contentRef.current?.focus(), 0);
89
129
  }
90
130
 
91
- function handleKeyDown(e: React.KeyboardEvent) {
92
- // Cmd/Ctrl+Enter saves from anywhere in the form.
93
- if ((e.metaKey || e.ctrlKey) && e.key === "Enter") {
94
- e.preventDefault();
95
- void handleSave();
96
- }
97
- }
98
-
99
- const saving = state === "saving";
100
- const canSave = content.trim().length > 0 && !saving;
101
-
102
131
  return (
103
132
  <SlidePanel open={open} onClose={onClose} title="Add to brain" wide>
104
- <div className="flex h-full flex-col" onKeyDown={handleKeyDown}>
105
- {state === "saved" ? (
106
- <div className="flex flex-1 flex-col items-center justify-center gap-4 px-8 text-center">
107
- <CheckCircle2 className="h-8 w-8 text-primary" />
108
- <p className="text-sm text-foreground">Added to your brain.</p>
109
- <p className="text-xs text-muted-foreground">
110
- Run a sync to index and push it.
111
- </p>
112
- <div className="flex gap-2">
113
- <button
114
- onClick={handleAddAnother}
115
- className="rounded-lg bg-surface-raised px-4 py-1.5 text-xs font-medium text-foreground transition-colors hover:bg-surface-overlay"
116
- >
117
- Add another
118
- </button>
119
- <button
120
- onClick={onClose}
121
- className="rounded-lg bg-primary px-4 py-1.5 text-xs font-medium text-primary-foreground transition-opacity hover:opacity-90"
122
- >
123
- Done
124
- </button>
125
- </div>
126
- </div>
127
- ) : (
128
- <>
129
- <div className="flex-1 space-y-4 overflow-y-auto p-5">
130
- <Field label="Note">
131
- <textarea
132
- ref={contentRef}
133
- value={content}
134
- onChange={(e) => setContent(e.target.value)}
135
- rows={8}
136
- placeholder="What do you want to remember?"
137
- className="w-full resize-y rounded-lg border border-border bg-surface-raised px-3 py-2 text-sm text-foreground outline-none transition-colors placeholder:text-muted-foreground focus:border-primary/40"
138
- />
139
- </Field>
140
-
141
- <Field label="Title" hint="optional, derived from the note if empty">
142
- <input
143
- value={title}
144
- onChange={(e) => setTitle(e.target.value)}
145
- className="w-full rounded-lg border border-border bg-surface-raised px-3 py-2 text-sm text-foreground outline-none transition-colors focus:border-primary/40"
146
- />
147
- </Field>
148
-
149
- <div className="grid grid-cols-2 gap-3">
150
- <Field label="Type" hint="optional">
151
- <input
152
- value={type}
153
- onChange={(e) => setType(e.target.value)}
154
- list="brain-add-types"
155
- placeholder="note"
156
- className="w-full rounded-lg border border-border bg-surface-raised px-3 py-2 text-sm text-foreground outline-none transition-colors placeholder:text-muted-foreground focus:border-primary/40"
157
- />
158
- <datalist id="brain-add-types">
159
- {knownTypes.map((t) => (
160
- <option key={t} value={t} />
161
- ))}
162
- </datalist>
163
- </Field>
164
-
165
- <Field label="Tags" hint="comma-separated">
166
- <input
167
- value={tags}
168
- onChange={(e) => setTags(e.target.value)}
169
- placeholder="idea, reading"
170
- className="w-full rounded-lg border border-border bg-surface-raised px-3 py-2 text-sm text-foreground outline-none transition-colors placeholder:text-muted-foreground focus:border-primary/40"
171
- />
172
- </Field>
173
- </div>
174
-
175
- {state === "error" && (
176
- <div className="flex items-start gap-2 rounded-lg border border-destructive/30 bg-destructive/10 px-3 py-2">
177
- <XCircle className="mt-0.5 h-3.5 w-3.5 shrink-0 text-destructive" />
178
- <span className="text-xs text-destructive">{error}</span>
179
- </div>
180
- )}
181
- </div>
182
-
183
- <div className="flex items-center justify-between border-t border-border px-5 py-3">
184
- <span className="text-[11px] text-muted-foreground">
185
- <Kbd>Ctrl</Kbd>/<Kbd>Cmd</Kbd> + <Kbd>↵</Kbd> to save
186
- </span>
187
- <div className="flex gap-2">
188
- <button
189
- onClick={onClose}
190
- className="rounded-lg bg-surface-raised px-4 py-1.5 text-xs font-medium text-foreground transition-colors hover:bg-surface-overlay"
191
- >
192
- Cancel
193
- </button>
194
- <button
195
- onClick={handleSave}
196
- disabled={!canSave}
197
- className="flex items-center gap-1.5 rounded-lg bg-primary px-4 py-1.5 text-xs font-medium text-primary-foreground transition-opacity hover:opacity-90 disabled:opacity-40"
198
- >
199
- {saving && <Loader2 className="h-3.5 w-3.5 animate-spin" />}
200
- {saving ? "Saving..." : "Add"}
201
- </button>
202
- </div>
203
- </div>
204
- </>
205
- )}
206
- </div>
133
+ <AddForm
134
+ state={state}
135
+ draft={{ content, title, type, tags }}
136
+ knownTypes={knownTypes}
137
+ error={error}
138
+ savedPath={savedPath}
139
+ indexed={indexed}
140
+ indexing={indexing}
141
+ contentRef={contentRef}
142
+ onDraft={(patch) => {
143
+ if (patch.content !== undefined) setContent(patch.content);
144
+ if (patch.title !== undefined) setTitle(patch.title);
145
+ if (patch.type !== undefined) setType(patch.type);
146
+ if (patch.tags !== undefined) setTags(patch.tags);
147
+ }}
148
+ onSave={() => void handleSave()}
149
+ onRetryIndex={() => void retryIndex()}
150
+ onAddAnother={handleAddAnother}
151
+ onClose={onClose}
152
+ />
207
153
  </SlidePanel>
208
154
  );
209
155
  }
210
-
211
- function Field({
212
- label,
213
- hint,
214
- children,
215
- }: {
216
- label: string;
217
- hint?: string;
218
- children: React.ReactNode;
219
- }) {
220
- return (
221
- <label className="block space-y-1.5">
222
- <span className="text-xs font-medium text-foreground">
223
- {label}
224
- {hint && (
225
- <span className="font-normal text-muted-foreground"> — {hint}</span>
226
- )}
227
- </span>
228
- {children}
229
- </label>
230
- );
231
- }
@@ -4,7 +4,8 @@ import { SlidePanel } from "../layout/slide-panel.js";
4
4
  import { Kbd } from "../layout/kbd.js";
5
5
  import { useFileStore } from "../../stores/file-store.js";
6
6
  import { useUIStore } from "../../stores/ui-store.js";
7
- import { api, type BrainSearchHit } from "../../lib/api-client.js";
7
+ import type { BrainSearchHit } from "../../lib/api-client.js";
8
+ import { useBrainApi } from "../../root-context.js";
8
9
  import { parseSnippet } from "../../lib/search-snippet.js";
9
10
  import { cn } from "../../lib/utils.js";
10
11
 
@@ -22,8 +23,10 @@ export function SearchPanel({
22
23
  open: boolean;
23
24
  onClose: () => void;
24
25
  }) {
26
+ const api = useBrainApi();
25
27
  const [query, setQuery] = useState("");
26
28
  const [state, setState] = useState<State>("idle");
29
+ const [resultQuery, setResultQuery] = useState("");
27
30
  const [results, setResults] = useState<BrainSearchHit[]>([]);
28
31
  const [warnings, setWarnings] = useState<string[]>([]);
29
32
  const [error, setError] = useState("");
@@ -31,15 +34,40 @@ export function SearchPanel({
31
34
 
32
35
  const inputRef = useRef<HTMLInputElement>(null);
33
36
  const listRef = useRef<HTMLDivElement>(null);
37
+ const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);
34
38
  const controllerRef = useRef<AbortController | null>(null);
35
39
 
36
40
  const openFile = useFileStore((s) => s.openFile);
37
41
  const setFilePanelOpen = useUIStore((s) => s.setFilePanelOpen);
38
42
 
39
43
  const trimmed = query.trim();
44
+ const currentResults = resultQuery === trimmed ? results : [];
40
45
 
41
- const runSearch = useCallback(async (q: string) => {
46
+ const cancelSearch = useCallback(() => {
47
+ if (debounceRef.current !== null) clearTimeout(debounceRef.current);
48
+ debounceRef.current = null;
42
49
  controllerRef.current?.abort();
50
+ controllerRef.current = null;
51
+ }, []);
52
+
53
+ function changeQuery(value: string) {
54
+ if (value.trim() === trimmed) {
55
+ setQuery(value);
56
+ return;
57
+ }
58
+ // Invalidate before the debounce, including completions already queued.
59
+ cancelSearch();
60
+ setQuery(value);
61
+ setResultQuery("");
62
+ setResults([]);
63
+ setWarnings([]);
64
+ setError("");
65
+ setSelected(0);
66
+ setState("idle");
67
+ }
68
+
69
+ const runSearch = useCallback(async (q: string) => {
70
+ cancelSearch();
43
71
  const controller = new AbortController();
44
72
  controllerRef.current = controller;
45
73
 
@@ -50,6 +78,7 @@ export function SearchPanel({
50
78
  signal: controller.signal,
51
79
  });
52
80
  if (controller.signal.aborted) return;
81
+ setResultQuery(q);
53
82
  setResults(res.results);
54
83
  setWarnings(res.warnings ?? []);
55
84
  setSelected(0);
@@ -63,17 +92,17 @@ export function SearchPanel({
63
92
  } finally {
64
93
  if (controllerRef.current === controller) controllerRef.current = null;
65
94
  }
66
- }, []);
95
+ }, [cancelSearch, api]);
67
96
 
68
97
  // Fresh panel every time it opens: stale results from a previous query would
69
98
  // otherwise flash before the first search lands.
70
99
  useEffect(() => {
71
100
  if (!open) {
72
- controllerRef.current?.abort();
73
- controllerRef.current = null;
101
+ cancelSearch();
74
102
  return;
75
103
  }
76
104
  setQuery("");
105
+ setResultQuery("");
77
106
  setResults([]);
78
107
  setWarnings([]);
79
108
  setError("");
@@ -82,27 +111,28 @@ export function SearchPanel({
82
111
  // Focus after the slide-in starts; focusing mid-transform fights the
83
112
  // mobile keyboard on some browsers.
84
113
  const t = setTimeout(() => inputRef.current?.focus(), 120);
85
- return () => clearTimeout(t);
86
- }, [open]);
114
+ return () => { clearTimeout(t); cancelSearch(); };
115
+ }, [open, cancelSearch, api]);
87
116
 
88
117
  // Debounced search on typing.
89
118
  useEffect(() => {
90
119
  if (!open) return;
91
120
  if (trimmed.length < MIN_QUERY) {
92
- controllerRef.current?.abort();
93
- controllerRef.current = null;
121
+ cancelSearch();
94
122
  setResults([]);
95
123
  setWarnings([]);
96
124
  setState("idle");
97
125
  return;
98
126
  }
99
- const t = setTimeout(() => void runSearch(trimmed), DEBOUNCE_MS);
100
- return () => clearTimeout(t);
101
- }, [open, trimmed, runSearch]);
127
+ debounceRef.current = setTimeout(() => void runSearch(trimmed), DEBOUNCE_MS);
128
+ return cancelSearch;
129
+ }, [open, trimmed, runSearch, cancelSearch]);
102
130
 
103
131
  function handleOpenResult(hit: BrainSearchHit) {
104
132
  // The file panel takes the same right-hand slot, so hand the screen over
105
133
  // rather than stacking two sheets.
134
+ if (resultQuery !== trimmed || state !== "done") return;
135
+ cancelSearch();
106
136
  onClose();
107
137
  setFilePanelOpen(true);
108
138
  void openFile(hit.path);
@@ -110,10 +140,10 @@ export function SearchPanel({
110
140
 
111
141
  function handleKeyDown(e: React.KeyboardEvent<HTMLInputElement>) {
112
142
  if (e.key === "ArrowDown" || e.key === "ArrowUp") {
113
- if (results.length === 0) return;
143
+ if (currentResults.length === 0) return;
114
144
  e.preventDefault();
115
145
  const delta = e.key === "ArrowDown" ? 1 : -1;
116
- const next = (selected + delta + results.length) % results.length;
146
+ const next = (selected + delta + currentResults.length) % currentResults.length;
117
147
  setSelected(next);
118
148
  listRef.current
119
149
  ?.querySelectorAll("[data-result]")
@@ -122,10 +152,10 @@ export function SearchPanel({
122
152
  }
123
153
  if (e.key === "Enter") {
124
154
  e.preventDefault();
125
- const hit = results[selected];
155
+ const hit = currentResults[selected];
126
156
  if (hit) handleOpenResult(hit);
127
157
  // Enter with nothing selected jumps the debounce.
128
- else if (trimmed.length >= MIN_QUERY) void runSearch(trimmed);
158
+ else if (trimmed.length >= MIN_QUERY && state !== "loading") void runSearch(trimmed);
129
159
  }
130
160
  }
131
161
 
@@ -139,7 +169,7 @@ export function SearchPanel({
139
169
  <input
140
170
  ref={inputRef}
141
171
  value={query}
142
- onChange={(e) => setQuery(e.target.value)}
172
+ onChange={(e) => changeQuery(e.target.value)}
143
173
  onKeyDown={handleKeyDown}
144
174
  placeholder="Search your brain..."
145
175
  className="min-w-0 flex-1 bg-transparent text-sm text-foreground outline-none placeholder:text-muted-foreground"
@@ -153,7 +183,7 @@ export function SearchPanel({
153
183
  {query && state !== "loading" && (
154
184
  <button
155
185
  onClick={() => {
156
- setQuery("");
186
+ changeQuery("");
157
187
  inputRef.current?.focus();
158
188
  }}
159
189
  className="shrink-0 rounded p-0.5 text-muted-foreground transition-colors hover:text-foreground"
@@ -192,7 +222,7 @@ export function SearchPanel({
192
222
  <Placeholder>No results for “{trimmed}”.</Placeholder>
193
223
  ) : (
194
224
  <div className="divide-y divide-border/40">
195
- {results.map((hit, i) => (
225
+ {currentResults.map((hit, i) => (
196
226
  <ResultRow
197
227
  key={hit.path}
198
228
  hit={hit}