@polderlabs/bizar 8.0.0 → 8.1.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 (267) hide show
  1. package/.claude/agents/agent-browser.md +1 -1
  2. package/.claude/agents/baldr.md +1 -1
  3. package/.claude/agents/forseti.md +1 -1
  4. package/.claude/agents/frigg.md +1 -1
  5. package/.claude/agents/heimdall.md +1 -1
  6. package/.claude/agents/hermod.md +1 -1
  7. package/.claude/agents/mimir.md +1 -1
  8. package/.claude/agents/odin.md +1 -1
  9. package/.claude/agents/quick.md +1 -1
  10. package/.claude/agents/semble-search.md +1 -1
  11. package/.claude/agents/thor.md +1 -1
  12. package/.claude/agents/tyr.md +1 -1
  13. package/.claude/agents/vidarr.md +1 -1
  14. package/.claude/agents/vor.md +1 -1
  15. package/.claude/commands/goal.md +98 -0
  16. package/.claude/settings.local.json +1 -2
  17. package/bizar-dash/dist/assets/ActivityFeed-CqF6iSDQ.js +6 -0
  18. package/bizar-dash/dist/assets/ActivityFeed-CqF6iSDQ.js.map +1 -0
  19. package/bizar-dash/dist/assets/ActivityView-qdhDjRtL.js +1 -0
  20. package/bizar-dash/dist/assets/ActivityView-qdhDjRtL.js.map +1 -0
  21. package/bizar-dash/dist/assets/AgentsView-BwXkOayl.js +28 -0
  22. package/bizar-dash/dist/assets/AgentsView-BwXkOayl.js.map +1 -0
  23. package/bizar-dash/dist/assets/{Badge-Cd61wsBa.js → Badge-BH4C3aUF.js} +1 -1
  24. package/bizar-dash/dist/assets/{Badge-Cd61wsBa.js.map → Badge-BH4C3aUF.js.map} +1 -1
  25. package/bizar-dash/dist/assets/Button-RmN1RKhE.js +6 -0
  26. package/bizar-dash/dist/assets/Button-RmN1RKhE.js.map +1 -0
  27. package/bizar-dash/dist/assets/{Card-C_bvqXdQ.js → Card-BzJeYR2D.js} +1 -1
  28. package/bizar-dash/dist/assets/{Card-C_bvqXdQ.js.map → Card-BzJeYR2D.js.map} +1 -1
  29. package/bizar-dash/dist/assets/Chip-CN2bvm7a.js +1 -0
  30. package/bizar-dash/dist/assets/Chip-CN2bvm7a.js.map +1 -0
  31. package/bizar-dash/dist/assets/{EmptyState-BWQuKnk9.js → EmptyState-DEiBv4-r.js} +1 -1
  32. package/bizar-dash/dist/assets/{EmptyState-BWQuKnk9.js.map → EmptyState-DEiBv4-r.js.map} +1 -1
  33. package/bizar-dash/dist/assets/GoalsView-CvsrzEez.js +6 -0
  34. package/bizar-dash/dist/assets/GoalsView-CvsrzEez.js.map +1 -0
  35. package/bizar-dash/dist/assets/KanbanCard-DZEaAiEr.js +21 -0
  36. package/bizar-dash/dist/assets/KanbanCard-DZEaAiEr.js.map +1 -0
  37. package/bizar-dash/dist/assets/LibrariesView-CPgKGPpM.js +67 -0
  38. package/bizar-dash/dist/assets/LibrariesView-CPgKGPpM.js.map +1 -0
  39. package/bizar-dash/dist/assets/MemoryView-Bbez5pMN.js +13 -0
  40. package/bizar-dash/dist/assets/MemoryView-Bbez5pMN.js.map +1 -0
  41. package/bizar-dash/dist/assets/OverviewView-BDegBWgg.js +1 -0
  42. package/bizar-dash/dist/assets/OverviewView-BDegBWgg.js.map +1 -0
  43. package/bizar-dash/dist/assets/Select-xwxbK8Ed.js +16 -0
  44. package/bizar-dash/dist/assets/Select-xwxbK8Ed.js.map +1 -0
  45. package/bizar-dash/dist/assets/SettingsRow-CppSgkT_.js +10 -0
  46. package/bizar-dash/dist/assets/SettingsRow-CppSgkT_.js.map +1 -0
  47. package/bizar-dash/dist/assets/SettingsView-DUc2meHV.js +43 -0
  48. package/bizar-dash/dist/assets/SettingsView-DUc2meHV.js.map +1 -0
  49. package/bizar-dash/dist/assets/Sheet-C_sIEw35.js +1 -0
  50. package/bizar-dash/dist/assets/Sheet-C_sIEw35.js.map +1 -0
  51. package/bizar-dash/dist/assets/Sparkline-D664vGWW.js +1 -0
  52. package/bizar-dash/dist/assets/Sparkline-D664vGWW.js.map +1 -0
  53. package/bizar-dash/dist/assets/StatTile-BRsUIA6P.js +16 -0
  54. package/bizar-dash/dist/assets/StatTile-BRsUIA6P.js.map +1 -0
  55. package/bizar-dash/dist/assets/TasksView-DVyX5-DY.js +1 -0
  56. package/bizar-dash/dist/assets/TasksView-DVyX5-DY.js.map +1 -0
  57. package/bizar-dash/dist/assets/Textarea-Dk97nmjO.js +1 -0
  58. package/bizar-dash/dist/assets/Textarea-Dk97nmjO.js.map +1 -0
  59. package/bizar-dash/dist/assets/{ViewHeader-D6c2cw1b.js → ViewHeader-dPd4zAyj.js} +1 -1
  60. package/bizar-dash/dist/assets/{ViewHeader-D6c2cw1b.js.map → ViewHeader-dPd4zAyj.js.map} +1 -1
  61. package/bizar-dash/dist/assets/{brain-DeoXNDE2.js → brain-BajPVibR.js} +1 -1
  62. package/bizar-dash/dist/assets/{brain-DeoXNDE2.js.map → brain-BajPVibR.js.map} +1 -1
  63. package/bizar-dash/dist/assets/{calendar-DRlQkGJc.js → calendar-CaP_Bbgc.js} +2 -2
  64. package/bizar-dash/dist/assets/{calendar-DRlQkGJc.js.map → calendar-CaP_Bbgc.js.map} +1 -1
  65. package/bizar-dash/dist/assets/{cmdk-BwN8hcKQ.js → cmdk-BLWIhKrV.js} +1 -1
  66. package/bizar-dash/dist/assets/{cmdk-BwN8hcKQ.js.map → cmdk-BLWIhKrV.js.map} +1 -1
  67. package/bizar-dash/dist/assets/dnd-kit-DU8GZk7s.js +5 -0
  68. package/bizar-dash/dist/assets/{dnd-kit-DR2Qzzxk.js.map → dnd-kit-DU8GZk7s.js.map} +1 -1
  69. package/bizar-dash/dist/assets/git-pull-request-CFRRwdxp.js +11 -0
  70. package/bizar-dash/dist/assets/git-pull-request-CFRRwdxp.js.map +1 -0
  71. package/bizar-dash/dist/assets/index-AL3OLUfz.js +1 -0
  72. package/bizar-dash/dist/assets/index-AL3OLUfz.js.map +1 -0
  73. package/bizar-dash/dist/assets/{main-COdgjqbZ.css → main-CcQfRfIJ.css} +1 -1
  74. package/bizar-dash/dist/assets/main-LxX9zTRk.js +109 -0
  75. package/bizar-dash/dist/assets/main-LxX9zTRk.js.map +1 -0
  76. package/bizar-dash/dist/assets/{minus-CrStJTZ7.js → plus-CVH1JB04.js} +2 -2
  77. package/bizar-dash/dist/assets/plus-CVH1JB04.js.map +1 -0
  78. package/bizar-dash/dist/assets/terminal-B2sSd5t7.js +11 -0
  79. package/bizar-dash/dist/assets/terminal-B2sSd5t7.js.map +1 -0
  80. package/bizar-dash/dist/assets/trash-2-JtYRQ79q.js +6 -0
  81. package/bizar-dash/dist/assets/trash-2-JtYRQ79q.js.map +1 -0
  82. package/bizar-dash/dist/assets/triangle-alert-Nzbrm0I2.js +6 -0
  83. package/bizar-dash/dist/assets/triangle-alert-Nzbrm0I2.js.map +1 -0
  84. package/bizar-dash/dist/assets/useFetch-CoVWwbml.js +1 -0
  85. package/bizar-dash/dist/assets/useFetch-CoVWwbml.js.map +1 -0
  86. package/bizar-dash/dist/assets/useWebSocket-CVIQB8yG.js +1 -0
  87. package/bizar-dash/dist/assets/useWebSocket-CVIQB8yG.js.map +1 -0
  88. package/bizar-dash/dist/assets/{wrench-BJ1WIC4u.js → wrench-B7go551L.js} +1 -1
  89. package/bizar-dash/dist/assets/{wrench-BJ1WIC4u.js.map → wrench-B7go551L.js.map} +1 -1
  90. package/bizar-dash/dist/v8.html +3 -3
  91. package/bizar-dash/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
  92. package/bizar-dash/src/server/api.mjs +10 -0
  93. package/bizar-dash/src/server/bg-poller.mjs +81 -1
  94. package/bizar-dash/src/server/bg-poller.test.mjs +28 -0
  95. package/bizar-dash/src/server/progress-parser.mjs +221 -0
  96. package/bizar-dash/src/server/progress-parser.test.mjs +105 -0
  97. package/bizar-dash/src/server/routes/agents-cc.mjs +381 -0
  98. package/bizar-dash/src/server/routes/agents-cc.test.mjs +35 -0
  99. package/bizar-dash/src/server/routes/goals.mjs +307 -0
  100. package/bizar-dash/src/server/routes/tasks.mjs +11 -0
  101. package/bizar-dash/src/web/v8/__tests__/App.test.tsx +2 -2
  102. package/bizar-dash/src/web/v8/__tests__/control-plane.test.tsx +104 -0
  103. package/bizar-dash/src/web/v8/__tests__/useFetch.test.ts +92 -0
  104. package/bizar-dash/src/web/v8/__tests__/useWebSocket.test.ts +87 -0
  105. package/bizar-dash/src/web/v8/__tests__/views.test.tsx +110 -40
  106. package/bizar-dash/src/web/v8/data/fetcher.ts +59 -0
  107. package/bizar-dash/src/web/v8/data/types.ts +154 -0
  108. package/bizar-dash/src/web/v8/data/useFetch.ts +62 -0
  109. package/bizar-dash/src/web/v8/data/useWebSocket.ts +153 -0
  110. package/bizar-dash/src/web/v8/ui/agents/AgentDetail.tsx +252 -0
  111. package/bizar-dash/src/web/v8/ui/agents/AgentStreamPanel.tsx +371 -0
  112. package/bizar-dash/src/web/v8/ui/goals/GoalDetail.tsx +245 -0
  113. package/bizar-dash/src/web/v8/ui/kanban/KanbanBoard.tsx +6 -3
  114. package/bizar-dash/src/web/v8/ui/kanban/KanbanCard.tsx +3 -3
  115. package/bizar-dash/src/web/v8/ui/kanban/KanbanColumn.tsx +10 -5
  116. package/bizar-dash/src/web/v8/ui/styles/globals.css +5 -0
  117. package/bizar-dash/src/web/v8/views/Activity/ActivityView.tsx +53 -15
  118. package/bizar-dash/src/web/v8/views/Agents/AgentsView.tsx +151 -87
  119. package/bizar-dash/src/web/v8/views/CommandPalette/AppCommandPalette.test.tsx +1 -1
  120. package/bizar-dash/src/web/v8/views/CommandPalette/AppCommandPalette.tsx +133 -30
  121. package/bizar-dash/src/web/v8/views/Goals/GoalsView.tsx +176 -67
  122. package/bizar-dash/src/web/v8/views/Libraries/LibrariesView.tsx +78 -11
  123. package/bizar-dash/src/web/v8/views/Memory/MemoryView.tsx +58 -42
  124. package/bizar-dash/src/web/v8/views/Overview/OverviewView.tsx +112 -52
  125. package/bizar-dash/src/web/v8/views/Router.tsx +13 -37
  126. package/bizar-dash/src/web/v8/views/Settings/SettingsView.tsx +635 -210
  127. package/bizar-dash/src/web/v8/views/Tasks/TasksView.tsx +140 -49
  128. package/bizar-dash/tests/components/Button.test.tsx +51 -14
  129. package/bizar-dash/tests/components/Card.test.tsx +37 -20
  130. package/bizar-dash/tests/components/Dialog.test.tsx +80 -0
  131. package/bizar-dash/tests/components/Toast.test.tsx +48 -95
  132. package/bizar-dash/tests/goals-decompose.test.mjs +177 -0
  133. package/bizar-dash/tests/setup.ts +21 -0
  134. package/bizar-dash/tests/ui/primitives/VisuallyHidden.test.tsx +30 -15
  135. package/bizar-dash/vite.config.ts +15 -0
  136. package/bizar-dash/vitest.config.ts +4 -1
  137. package/cli/bin.mjs +32 -0
  138. package/cli/install.mjs +26 -1
  139. package/cli/provision-claude.mjs +86 -0
  140. package/package.json +1 -1
  141. package/scripts/run-dev.mjs +84 -0
  142. package/bizar-dash/dist/assets/ActivityFeed-BRBtQOHB.js +0 -6
  143. package/bizar-dash/dist/assets/ActivityFeed-BRBtQOHB.js.map +0 -1
  144. package/bizar-dash/dist/assets/ActivityView-CwqhxBfh.js +0 -1
  145. package/bizar-dash/dist/assets/ActivityView-CwqhxBfh.js.map +0 -1
  146. package/bizar-dash/dist/assets/AgentActivity-6MxU-a9F.js +0 -1
  147. package/bizar-dash/dist/assets/AgentActivity-6MxU-a9F.js.map +0 -1
  148. package/bizar-dash/dist/assets/AgentsView-BYrOFdwl.js +0 -8
  149. package/bizar-dash/dist/assets/AgentsView-BYrOFdwl.js.map +0 -1
  150. package/bizar-dash/dist/assets/GoalsView-Dok0yt9S.js +0 -11
  151. package/bizar-dash/dist/assets/GoalsView-Dok0yt9S.js.map +0 -1
  152. package/bizar-dash/dist/assets/Grid-C62gCPqt.js +0 -1
  153. package/bizar-dash/dist/assets/Grid-C62gCPqt.js.map +0 -1
  154. package/bizar-dash/dist/assets/KanbanCard-CtTKP6ZX.js +0 -21
  155. package/bizar-dash/dist/assets/KanbanCard-CtTKP6ZX.js.map +0 -1
  156. package/bizar-dash/dist/assets/LibrariesView-BcyBQXiY.js +0 -67
  157. package/bizar-dash/dist/assets/LibrariesView-BcyBQXiY.js.map +0 -1
  158. package/bizar-dash/dist/assets/MemoryView-49wR4u-y.js +0 -13
  159. package/bizar-dash/dist/assets/MemoryView-49wR4u-y.js.map +0 -1
  160. package/bizar-dash/dist/assets/OverviewView-BtQ_UWYj.js +0 -1
  161. package/bizar-dash/dist/assets/OverviewView-BtQ_UWYj.js.map +0 -1
  162. package/bizar-dash/dist/assets/ProgressBar-CpvDeq9F.js +0 -1
  163. package/bizar-dash/dist/assets/ProgressBar-CpvDeq9F.js.map +0 -1
  164. package/bizar-dash/dist/assets/SettingsRow-DmIe5OUu.js +0 -30
  165. package/bizar-dash/dist/assets/SettingsRow-DmIe5OUu.js.map +0 -1
  166. package/bizar-dash/dist/assets/SettingsView-D1KmGWbi.js +0 -48
  167. package/bizar-dash/dist/assets/SettingsView-D1KmGWbi.js.map +0 -1
  168. package/bizar-dash/dist/assets/StatTile-BkIP32gG.js +0 -11
  169. package/bizar-dash/dist/assets/StatTile-BkIP32gG.js.map +0 -1
  170. package/bizar-dash/dist/assets/TasksView-Cba3GJ42.js +0 -1
  171. package/bizar-dash/dist/assets/TasksView-Cba3GJ42.js.map +0 -1
  172. package/bizar-dash/dist/assets/circle-check-DmYQ3vGp.js +0 -6
  173. package/bizar-dash/dist/assets/circle-check-DmYQ3vGp.js.map +0 -1
  174. package/bizar-dash/dist/assets/dnd-kit-DR2Qzzxk.js +0 -5
  175. package/bizar-dash/dist/assets/git-merge-OoqBKQer.js +0 -6
  176. package/bizar-dash/dist/assets/git-merge-OoqBKQer.js.map +0 -1
  177. package/bizar-dash/dist/assets/git-pull-request-CXBQTR2f.js +0 -6
  178. package/bizar-dash/dist/assets/git-pull-request-CXBQTR2f.js.map +0 -1
  179. package/bizar-dash/dist/assets/main-Cw6gybzS.js +0 -109
  180. package/bizar-dash/dist/assets/main-Cw6gybzS.js.map +0 -1
  181. package/bizar-dash/dist/assets/message-square-DUTeIQAR.js +0 -6
  182. package/bizar-dash/dist/assets/message-square-DUTeIQAR.js.map +0 -1
  183. package/bizar-dash/dist/assets/minus-CrStJTZ7.js.map +0 -1
  184. package/bizar-dash/src/web/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
  185. /package/bizar-dash/tests/{BackgroundAgents.test.tsx → v7-archive/BackgroundAgents.test.tsx} +0 -0
  186. /package/bizar-dash/tests/{a11y → v7-archive/a11y}/forms.test.tsx +0 -0
  187. /package/bizar-dash/tests/{a11y.test.tsx → v7-archive/a11y.test.tsx} +0 -0
  188. /package/bizar-dash/tests/{autosave.test.tsx → v7-archive/autosave.test.tsx} +0 -0
  189. /package/bizar-dash/tests/{backup-restore.test.tsx → v7-archive/backup-restore.test.tsx} +0 -0
  190. /package/bizar-dash/tests/{chat-composer.test.tsx → v7-archive/chat-composer.test.tsx} +0 -0
  191. /package/bizar-dash/tests/{communication-log.test.tsx → v7-archive/communication-log.test.tsx} +0 -0
  192. /package/bizar-dash/tests/{components → v7-archive/components}/Modal.test.tsx +0 -0
  193. /package/bizar-dash/tests/{components → v7-archive/components}/Spinner.test.tsx +0 -0
  194. /package/bizar-dash/tests/{components → v7-archive/components}/StatusBadge.test.tsx +0 -0
  195. /package/bizar-dash/tests/{components → v7-archive/components}/doctor-panel.test.tsx +0 -0
  196. /package/bizar-dash/tests/{components → v7-archive/components}/screenshot-ocr.test.tsx +0 -0
  197. /package/bizar-dash/tests/{components → v7-archive/components}/settings-search.test.tsx +0 -0
  198. /package/bizar-dash/tests/{components → v7-archive/components}/workspace-selector.test.tsx +0 -0
  199. /package/bizar-dash/tests/{ui → v7-archive}/controls/Button.test.tsx +0 -0
  200. /package/bizar-dash/tests/{ui → v7-archive}/controls/Checkbox.test.tsx +0 -0
  201. /package/bizar-dash/tests/{ui → v7-archive}/controls/IconButton.test.tsx +0 -0
  202. /package/bizar-dash/tests/{ui → v7-archive}/controls/Kbd.test.tsx +0 -0
  203. /package/bizar-dash/tests/{ui → v7-archive}/controls/NumberInput.test.tsx +0 -0
  204. /package/bizar-dash/tests/{ui → v7-archive}/controls/RadioGroup.test.tsx +0 -0
  205. /package/bizar-dash/tests/{ui → v7-archive}/controls/SearchInput.test.tsx +0 -0
  206. /package/bizar-dash/tests/{ui → v7-archive}/controls/Select.test.tsx +0 -0
  207. /package/bizar-dash/tests/{ui → v7-archive}/controls/Slider.test.tsx +0 -0
  208. /package/bizar-dash/tests/{ui → v7-archive}/controls/TextInput.test.tsx +0 -0
  209. /package/bizar-dash/tests/{ui → v7-archive}/controls/Textarea.test.tsx +0 -0
  210. /package/bizar-dash/tests/{ui → v7-archive}/controls/Toggle.test.tsx +0 -0
  211. /package/bizar-dash/tests/{ui → v7-archive}/data/BarChart.test.tsx +0 -0
  212. /package/bizar-dash/tests/{ui → v7-archive}/data/DataTable.test.tsx +0 -0
  213. /package/bizar-dash/tests/{ui → v7-archive}/data/EmptyState.test.tsx +0 -0
  214. /package/bizar-dash/tests/{ui → v7-archive}/data/ErrorState.test.tsx +0 -0
  215. /package/bizar-dash/tests/{ui → v7-archive}/data/KeyValueList.test.tsx +0 -0
  216. /package/bizar-dash/tests/{ui → v7-archive}/data/LoadingState.test.tsx +0 -0
  217. /package/bizar-dash/tests/{ui → v7-archive}/data/Sparkline.test.tsx +0 -0
  218. /package/bizar-dash/tests/{ui → v7-archive}/data/StatTile.test.tsx +0 -0
  219. /package/bizar-dash/tests/{dep-graph.test.tsx → v7-archive/dep-graph.test.tsx} +0 -0
  220. /package/bizar-dash/tests/{eval-web-ui.test.tsx → v7-archive/eval-web-ui.test.tsx} +0 -0
  221. /package/bizar-dash/tests/{event-log.test.tsx → v7-archive/event-log.test.tsx} +0 -0
  222. /package/bizar-dash/tests/{ui → v7-archive}/feedback/Badge.test.tsx +0 -0
  223. /package/bizar-dash/tests/{ui → v7-archive}/feedback/Dialog.test.tsx +0 -0
  224. /package/bizar-dash/tests/{ui → v7-archive}/feedback/ProgressBar.test.tsx +0 -0
  225. /package/bizar-dash/tests/{ui → v7-archive}/feedback/StatusDot.test.tsx +0 -0
  226. /package/bizar-dash/tests/{ui → v7-archive}/feedback/Toast.test.tsx +0 -0
  227. /package/bizar-dash/tests/{ui → v7-archive}/feedback/Tooltip.test.tsx +0 -0
  228. /package/bizar-dash/tests/{goal-input.test.tsx → v7-archive/goal-input.test.tsx} +0 -0
  229. /package/bizar-dash/tests/{goap-planner.test.ts → v7-archive/goap-planner.test.ts} +0 -0
  230. /package/bizar-dash/tests/{hooks → v7-archive/hooks}/useModal.test.tsx +0 -0
  231. /package/bizar-dash/tests/{hooks → v7-archive/hooks}/useToast.test.tsx +0 -0
  232. /package/bizar-dash/tests/{ui → v7-archive}/layout/AppShell.test.tsx +0 -0
  233. /package/bizar-dash/tests/{ui → v7-archive}/layout/Breadcrumbs.test.tsx +0 -0
  234. /package/bizar-dash/tests/{ui → v7-archive}/layout/Panel.test.tsx +0 -0
  235. /package/bizar-dash/tests/{ui → v7-archive}/layout/PanelHeader.test.tsx +0 -0
  236. /package/bizar-dash/tests/{ui → v7-archive}/layout/Sidebar.test.tsx +0 -0
  237. /package/bizar-dash/tests/{ui → v7-archive}/layout/Tabs.test.tsx +0 -0
  238. /package/bizar-dash/tests/{ui → v7-archive}/layout/Topbar.test.tsx +0 -0
  239. /package/bizar-dash/tests/{ui → v7-archive}/layout/ViewHeader.test.tsx +0 -0
  240. /package/bizar-dash/tests/{lib → v7-archive/lib}/i18n.test.ts +0 -0
  241. /package/bizar-dash/tests/{lib → v7-archive/lib}/search-fuzzy.test.ts +0 -0
  242. /package/bizar-dash/tests/{lib → v7-archive/lib}/utils.test.ts +0 -0
  243. /package/bizar-dash/tests/{memory-graph-view.test.tsx → v7-archive/memory-graph-view.test.tsx} +0 -0
  244. /package/bizar-dash/tests/{mobile-chat.test.tsx → v7-archive/mobile-chat.test.tsx} +0 -0
  245. /package/bizar-dash/tests/{mobile-layout.test.tsx → v7-archive/mobile-layout.test.tsx} +0 -0
  246. /package/bizar-dash/tests/{mobile-overview.test.tsx → v7-archive/mobile-overview.test.tsx} +0 -0
  247. /package/bizar-dash/tests/{mobile-settings.test.tsx → v7-archive/mobile-settings.test.tsx} +0 -0
  248. /package/bizar-dash/tests/{mobile-tasks.test.tsx → v7-archive/mobile-tasks.test.tsx} +0 -0
  249. /package/bizar-dash/tests/{ui → v7-archive}/navigation/CommandPalette.test.tsx +0 -0
  250. /package/bizar-dash/tests/{ui → v7-archive}/navigation/NavGroup.test.tsx +0 -0
  251. /package/bizar-dash/tests/{ui → v7-archive}/navigation/NavLink.test.tsx +0 -0
  252. /package/bizar-dash/tests/{quality-gates.test.tsx → v7-archive/quality-gates.test.tsx} +0 -0
  253. /package/bizar-dash/tests/{settings-layout.test.tsx → v7-archive/settings-layout.test.tsx} +0 -0
  254. /package/bizar-dash/tests/{settings-mode-wiring.test.tsx → v7-archive/settings-mode-wiring.test.tsx} +0 -0
  255. /package/bizar-dash/tests/{settings-nav.test.tsx → v7-archive/settings-nav.test.tsx} +0 -0
  256. /package/bizar-dash/tests/{ui → v7-archive/ui}/primitives/Box.test.tsx +0 -0
  257. /package/bizar-dash/tests/{ui → v7-archive/ui}/primitives/Grid.test.tsx +0 -0
  258. /package/bizar-dash/tests/{ui → v7-archive/ui}/primitives/Inline.test.tsx +0 -0
  259. /package/bizar-dash/tests/{ui → v7-archive/ui}/primitives/Separator.test.tsx +0 -0
  260. /package/bizar-dash/tests/{ui → v7-archive/ui}/primitives/Stack.test.tsx +0 -0
  261. /package/bizar-dash/tests/{views → v7-archive/views}/Agents.test.tsx +0 -0
  262. /package/bizar-dash/tests/{views → v7-archive/views}/Memory.test.tsx +0 -0
  263. /package/bizar-dash/tests/{views → v7-archive/views}/Overview.test.tsx +0 -0
  264. /package/bizar-dash/tests/{views → v7-archive/views}/Tasks.test.tsx +0 -0
  265. /package/bizar-dash/tests/{views → v7-archive/views}/sidebar.test.tsx +0 -0
  266. /package/bizar-dash/tests/{views → v7-archive/views}/topbar.test.tsx +0 -0
  267. /package/bizar-dash/tests/{voice-recorder.test.tsx → v7-archive/voice-recorder.test.tsx} +0 -0
@@ -1,84 +1,193 @@
1
+ import { useCallback, useEffect, useState } from 'react';
2
+ import { Plus } from 'lucide-react';
1
3
  import { Stack } from '../../ui/primitives/Stack.js';
2
4
  import { Grid } from '../../ui/primitives/Grid.js';
5
+ import { Inline } from '../../ui/primitives/Inline.js';
3
6
  import { ViewHeader } from '../../ui/data/ViewHeader.js';
4
- import { GoalCard, type GoalCardProps } from '../../ui/goals/GoalCard.js';
5
- import { KeyResult, type KeyResultProps } from '../../ui/goals/KeyResult.js';
6
- import { Card, CardBody, CardHeader } from '../../ui/data/Card.js';
7
+ import { GoalCard, type GoalCardProps, type GoalStatus } from '../../ui/goals/GoalCard.js';
8
+ import { GoalDetail } from '../../ui/goals/GoalDetail.js';
9
+ import { Card, CardBody } from '../../ui/data/Card.js';
10
+ import { Skeleton } from '../../ui/feedback/Skeleton.js';
11
+ import { Button } from '../../ui/controls/Button.js';
12
+ import { useFetch } from '../../data/useFetch.js';
13
+ import { useWsMessage } from '../../data/useWebSocket.js';
14
+ import { fetchJson } from '../../data/fetcher.js';
15
+ import type { Goal, WsMessage } from '../../data/types.js';
7
16
 
8
17
  /**
9
- * GoalsView — long-horizon commitments (PLAN.md "Goals page").
10
- *
11
- * Goals are intentional commitments tracked over weeks/months. They are
12
- * NOT kanban cards. Each goal surfaces key results inline so the user
13
- * can see "what does done look like" at a glance.
18
+ * GoalsView — Sprint S10/S12. Pulls `/api/goals` (parsed PROGRESS.md).
19
+ * Card click → `GoalDetail` Drawer (editable title / status / due /
20
+ * owner / KR add/toggle/remove). "+ New goal" button creates a fresh
21
+ * goal via `POST /api/goals`. Live updates via `goals:change`.
14
22
  */
15
23
 
16
- const GOALS: GoalCardProps[] = [
17
- {
18
- id: 'g1',
19
- title: 'Ship v8 dashboard',
20
- description: 'Replace the v7 dashboard with a fully-token-driven component library.',
21
- status: 'on-track',
22
- progress: 0.62,
23
- due: 'Q3 2026',
24
- ownerName: 'alex',
25
- keyResultsDone: 5,
26
- keyResultsTotal: 8,
27
- },
28
- {
29
- id: 'g2',
30
- title: 'Cut S9 polish in half',
31
- description: 'Reduce polish + views-wiring sprint from 10 days to 5.',
32
- status: 'at-risk',
33
- progress: 0.3,
34
- due: 'Aug 1',
35
- ownerName: 'sam',
36
- keyResultsDone: 1,
37
- keyResultsTotal: 4,
38
- },
39
- {
40
- id: 'g3',
41
- title: 'Make every page keyboard-navigable',
42
- description: 'A11y pass across Tasks, Goals, Agents, Memory, Settings.',
43
- status: 'done',
44
- progress: 1,
45
- due: 'Q2 2026',
46
- ownerName: 'jordan',
47
- keyResultsDone: 6,
48
- keyResultsTotal: 6,
49
- },
50
- ];
51
-
52
- const KEY_RESULTS: KeyResultProps[] = [
53
- { id: 'k1', title: 'Publish Plan.md with 17 sections', status: 'done', progress: 1, metric: '17 / 17' },
54
- { id: 'k2', title: 'Ship Sprint S1 (Foundation)', status: 'done', progress: 1, metric: 'sprint S1' },
55
- { id: 'k3', title: 'Ship Sprint S5 (Kanban centerpiece)', status: 'done', progress: 1, metric: 'sprint S5' },
56
- { id: 'k4', title: 'Wire app-level CommandPalette', status: 'in-progress', progress: 0.5, metric: '1 / 2 hooks', assignee: 'alex' },
57
- { id: 'k5', title: 'Ship Sprint S9 (Polish + views)', status: 'not-started', progress: 0, assignee: 'sam' },
58
- ];
24
+ function goalToCard(g: Goal): GoalCardProps {
25
+ return {
26
+ id: g.id,
27
+ title: g.title,
28
+ description: g.description || '',
29
+ status: g.status as GoalStatus,
30
+ progress: g.progress,
31
+ due: g.due,
32
+ ownerName: g.owner,
33
+ keyResultsDone: g.keyResults.filter((k) => k.done).length,
34
+ keyResultsTotal: g.keyResults.length,
35
+ };
36
+ }
59
37
 
60
38
  export function GoalsView(): JSX.Element {
39
+ const goals = useFetch<{ goals?: Goal[]; count?: number }>('/api/goals');
40
+ const [local, setLocal] = useState<Goal[]>([]);
41
+ const [initialized, setInitialized] = useState(false);
42
+ const [openGoalId, setOpenGoalId] = useState<string | null>(null);
43
+ const [creating, setCreating] = useState<boolean>(false);
44
+ const [decomposing, setDecomposing] = useState<string | null>(null);
45
+ const [decomposeError, setDecomposeError] = useState<string | null>(null);
46
+
47
+ useEffect(() => {
48
+ if (goals.data?.goals && !initialized) {
49
+ setInitialized(true);
50
+ setLocal(goals.data.goals);
51
+ }
52
+ }, [goals.data, initialized]);
53
+
54
+ const onChange = useCallback((msg: WsMessage) => {
55
+ if (msg.type !== 'goals:change') return;
56
+ const g = (msg as Extract<WsMessage, { type: 'goals:change' }>).goal;
57
+ if (!g) return;
58
+ setLocal((prev) => {
59
+ const idx = prev.findIndex((x) => x.id === g.id);
60
+ if (idx === -1) return [...prev, g];
61
+ const copy = prev.slice();
62
+ copy[idx] = g;
63
+ return copy;
64
+ });
65
+ }, []);
66
+ useWsMessage('goals:change', onChange);
67
+
68
+ const createGoal = useCallback(async () => {
69
+ setCreating(true);
70
+ try {
71
+ const res = await fetchJson<{ goal?: Goal; id?: string }>('/api/goals', {
72
+ method: 'POST',
73
+ body: { title: 'New goal' },
74
+ });
75
+ if (res.goal) setLocal((prev) => [...prev, res.goal as Goal]);
76
+ if (res.id) setOpenGoalId(res.id);
77
+ } catch {
78
+ // server will broadcast the canonical state via WS on the next reload
79
+ } finally {
80
+ setCreating(false);
81
+ }
82
+ }, []);
83
+
84
+ const openGoal = openGoalId ? local.find((g) => g.id === openGoalId) ?? null : null;
85
+
86
+ const decompose = useCallback(async (goalId: string) => {
87
+ setDecomposing(goalId);
88
+ setDecomposeError(null);
89
+ try {
90
+ const res = await fetchJson<{ goalId: string; created: { kr: string; task: string }[] }>(
91
+ `/api/goals/${encodeURIComponent(goalId)}/decompose`,
92
+ { method: 'POST' },
93
+ );
94
+ // Patch local state with the new taskIds so the button reflects
95
+ // "Decomposed" without waiting for the WS roundtrip.
96
+ if (Array.isArray(res.created) && res.created.length > 0) {
97
+ setLocal((prev) => prev.map((g) => {
98
+ if (g.id !== goalId) return g;
99
+ const krs = (g.keyResults ?? []).map((kr) => {
100
+ const link = res.created.find((c) => c.kr === kr.id);
101
+ return link ? { ...kr, taskId: link.task } : kr;
102
+ });
103
+ return { ...g, keyResults: krs };
104
+ }));
105
+ }
106
+ } catch (err) {
107
+ setDecomposeError(err instanceof Error ? err.message : String(err));
108
+ } finally {
109
+ setDecomposing(null);
110
+ }
111
+ }, []);
112
+
61
113
  return (
62
114
  <Stack gap={5}>
63
115
  <ViewHeader
64
116
  title="Goals"
65
- description="Long-horizon commitments. Each goal lists the measurable key results that signal done."
117
+ description="Long-horizon commitments parsed from .bizar/PROGRESS.md."
118
+ actions={
119
+ <Button variant="primary" onClick={() => { void createGoal(); }} disabled={creating}>
120
+ <Plus size={14} aria-hidden /> New goal
121
+ </Button>
122
+ }
66
123
  />
67
- <Grid cols={2}>
68
- {GOALS.map((goal) => (
69
- <GoalCard key={goal.id} {...goal} />
70
- ))}
71
- </Grid>
72
- <Card>
73
- <CardHeader title="Key results — current focus" />
74
- <CardBody>
75
- <Stack gap={2}>
76
- {KEY_RESULTS.map((kr) => (
77
- <KeyResult key={kr.id} {...kr} />
78
- ))}
79
- </Stack>
80
- </CardBody>
81
- </Card>
124
+ {decomposeError !== null && (
125
+ <div role="alert" style={{ padding: 'var(--space-3)', background: 'color-mix(in oklch, var(--danger) 12%, var(--surface-0))', border: '1px solid var(--danger)', borderRadius: 'var(--radius-md)', fontSize: 'var(--fs-12)' }}>
126
+ Decompose failed: {decomposeError}
127
+ </div>
128
+ )}
129
+ {goals.loading && local.length === 0 ? (
130
+ <Stack gap={3}>
131
+ <Skeleton style={{ height: 160 }} />
132
+ <Skeleton style={{ height: 160 }} />
133
+ </Stack>
134
+ ) : local.length === 0 ? (
135
+ <Card>
136
+ <CardBody>
137
+ <Stack gap={2}>
138
+ <strong>No goals yet.</strong>
139
+ <span style={{ color: 'var(--fg-muted)' }}>
140
+ Create one with the dashboard or via CC's <code>/goal &lt;text&gt;</code>.
141
+ </span>
142
+ </Stack>
143
+ </CardBody>
144
+ </Card>
145
+ ) : (
146
+ <Grid cols={2}>
147
+ {local.map((g) => {
148
+ const krCount = g.keyResults?.length ?? 0;
149
+ const decomposed = (g.keyResults ?? []).every((kr) => Boolean(kr.taskId));
150
+ return (
151
+ <div
152
+ key={g.id}
153
+ role="button"
154
+ tabIndex={0}
155
+ onClick={() => setOpenGoalId(g.id)}
156
+ onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); setOpenGoalId(g.id); } }}
157
+ style={{ cursor: 'pointer', outline: 'none' }}
158
+ data-testid={`goal-card-${g.id}`}
159
+ >
160
+ <Stack gap={2}>
161
+ <GoalCard {...goalToCard(g)} />
162
+ {krCount > 0 && (
163
+ <Inline align="center" justify="flex-end" gap={2}>
164
+ <span style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>
165
+ {decomposed ? 'Decomposed' : `${krCount} key result${krCount === 1 ? '' : 's'} · not yet linked`}
166
+ </span>
167
+ <Button
168
+ variant="secondary"
169
+ onClick={(e) => { e.stopPropagation(); void decompose(g.id); }}
170
+ disabled={decomposing === g.id}
171
+ title={decomposed ? 'Re-create missing task links' : 'Create one task per key result'}
172
+ >
173
+ <Plus size={12} aria-hidden /> {decomposed ? 'Re-link tasks' : 'Decompose → Tasks'}
174
+ </Button>
175
+ </Inline>
176
+ )}
177
+ </Stack>
178
+ </div>
179
+ );
180
+ })}
181
+ </Grid>
182
+ )}
183
+
184
+ {openGoal && (
185
+ <GoalDetail
186
+ goal={openGoal}
187
+ open={openGoalId !== null}
188
+ onOpenChange={(o) => { if (!o) setOpenGoalId(null); }}
189
+ />
190
+ )}
82
191
  </Stack>
83
192
  );
84
193
  }
@@ -1,10 +1,19 @@
1
+ import { useEffect, useState, useCallback } from 'react';
1
2
  import { Stack } from '../../ui/primitives/Stack.js';
2
3
  import { ViewHeader } from '../../ui/data/ViewHeader.js';
3
- import { LibraryGrid, LibraryItem, type LibraryItemProps } from '../../ui/index.js';
4
+ import { LibraryGrid, LibraryItem, type LibraryItemProps, type LibraryStatus } from '../../ui/index.js';
5
+ import { Skeleton } from '../../ui/feedback/Skeleton.js';
6
+ import { EmptyState } from '../../ui/feedback/EmptyState.js';
7
+ import { useFetch } from '../../data/useFetch.js';
8
+ import { useWsMessage } from '../../data/useWebSocket.js';
9
+ import type { LibraryItem as LibItem } from '../../data/types.js';
4
10
 
5
11
  /**
6
- * LibrariesView — generic view that any one of Skills / MCPs / Hooks
7
- * uses. Pass the kind + items list; the surface is identical.
12
+ * LibrariesView — Sprint S10. Generic Skills / MCPs / Hooks surface.
13
+ *
14
+ * The parent (`Router.tsx`) picks the data source per kind. This
15
+ * view pulls live data from `/api/skills`, `/api/mcps`,
16
+ * `/api/hooks` instead of seeded arrays.
8
17
  */
9
18
 
10
19
  export type LibraryKind = 'skills' | 'mcps' | 'hooks';
@@ -17,25 +26,83 @@ const KIND_LABEL: Record<LibraryKind, string> = {
17
26
 
18
27
  const KIND_DESCRIPTION: Record<LibraryKind, string> = {
19
28
  skills: 'Bizar skill packs. Auto-loaded by name or dispatched via the Skill tool.',
20
- mcps: 'MCP server registrations under `.claude/mcp.json`.',
29
+ mcps: 'MCP server registrations under `.claude/settings.json` → `mcpServers`.',
21
30
  hooks: 'Executable hook scripts (PreToolUse / PostToolUse / SessionStart / SessionEnd).',
22
31
  };
23
32
 
33
+ const ENDPOINT: Record<LibraryKind, string> = {
34
+ skills: '/api/skills',
35
+ mcps: '/api/skills?kind=mcps',
36
+ hooks: '/api/skills?kind=hooks',
37
+ };
38
+
39
+ const CHANGE_EVENTS: Record<LibraryKind, readonly string[]> = {
40
+ skills: ['skills:change', 'agents:change'] as const,
41
+ mcps: ['mcps:change', 'agents:change'] as const,
42
+ hooks: ['agents:change', 'agents:change'] as const,
43
+ };
44
+ // Stable hook count: always register listeners for all possible events,
45
+ // filter inside the handler so kind navigation never changes hook order.
46
+ const ALL_EVENTS = ['skills:change', 'mcps:change', 'agents:change'] as const;
47
+
48
+ function mapItem(it: LibItem): LibraryItemProps {
49
+ const status: LibraryStatus =
50
+ it.status === 'enabled' || it.status === 'disabled' || it.status === 'error'
51
+ ? it.status
52
+ : 'disabled';
53
+ return {
54
+ id: it.id,
55
+ name: it.name,
56
+ slug: it.slug ?? it.id,
57
+ status,
58
+ description: it.description,
59
+ meta: it.meta,
60
+ };
61
+ }
62
+
24
63
  export interface LibrariesViewProps {
25
64
  kind: LibraryKind;
26
- items: readonly LibraryItemProps[];
27
65
  }
28
66
 
29
67
  export function LibrariesView(props: LibrariesViewProps): JSX.Element {
30
- const { kind, items } = props;
68
+ const { kind } = props;
69
+ const url = ENDPOINT[kind];
70
+ const res = useFetch<{ skills?: LibItem[]; items?: LibItem[]; count?: number }>(url);
71
+ const [bust, setBust] = useState(0);
72
+
73
+ // Force a re-fetch when the matching change event fires. Hook count
74
+ // is fixed (ALL_EVENTS.length) so navigating between kinds can't trip
75
+ // React's "Rendered fewer hooks than expected" runtime guard.
76
+ const events = CHANGE_EVENTS[kind];
77
+ const handler = useCallback((): void => setBust((n) => n + 1), []);
78
+ for (const evt of ALL_EVENTS) {
79
+ useWsMessage(evt, events.includes(evt) ? handler : () => {});
80
+ }
81
+
82
+ useEffect(() => {
83
+ if (bust > 0) res.refetch();
84
+ }, [bust, res]);
85
+
86
+ const items: LibraryItemProps[] = (res.data?.skills || res.data?.items || []).map(mapItem);
87
+
31
88
  return (
32
89
  <Stack gap={5}>
33
90
  <ViewHeader title={KIND_LABEL[kind]} description={KIND_DESCRIPTION[kind]} />
34
- <LibraryGrid>
35
- {items.map((item) => (
36
- <LibraryItem key={item.id} {...item} />
37
- ))}
38
- </LibraryGrid>
91
+ {res.loading ? (
92
+ <Skeleton style={{ height: 240 }} />
93
+ ) : items.length === 0 ? (
94
+ <EmptyState
95
+ icon={<span>📚</span>}
96
+ title={`No ${KIND_LABEL[kind].toLowerCase()} installed`}
97
+ description={`${KIND_LABEL[kind]} appear here as soon as they are registered.`}
98
+ />
99
+ ) : (
100
+ <LibraryGrid>
101
+ {items.map((item) => (
102
+ <LibraryItem key={item.id} {...item} />
103
+ ))}
104
+ </LibraryGrid>
105
+ )}
39
106
  </Stack>
40
107
  );
41
108
  }
@@ -1,61 +1,77 @@
1
+ import { useMemo, useState } from 'react';
1
2
  import { Stack } from '../../ui/primitives/Stack.js';
3
+ import { Inline } from '../../ui/primitives/Inline.js';
2
4
  import { ViewHeader } from '../../ui/data/ViewHeader.js';
3
- import { MemoryVault, type MemoryEntry } from '../../ui/memory/MemoryVault.js';
5
+ import { MemoryVault, type MemoryEntry, type MemoryScope } from '../../ui/memory/MemoryVault.js';
4
6
  import { EmptyState } from '../../ui/feedback/EmptyState.js';
5
7
  import { Brain } from 'lucide-react';
8
+ import { Skeleton } from '../../ui/feedback/Skeleton.js';
9
+ import { Chip } from '../../ui/data/Chip.js';
10
+ import { useFetch } from '../../data/useFetch.js';
6
11
 
7
12
  /**
8
- * MemoryView — the durable cross-session memos the harness writes down.
13
+ * MemoryView — Sprint S10. Pulls `/api/memory` (Bizar memory entries).
14
+ * Click a chip to scope the view (Project / Global / All).
9
15
  */
10
16
 
11
- const ENTRIES: MemoryEntry[] = [
12
- {
13
- id: 'm1',
14
- content: 'The dashboard rewrite lives in v8 tree under `bizar-dash/src/web/v8/`. Sprint boundaries: S1..S9 (per PLAN.md).',
15
- tags: ['dashboard', 'rewrite', 'sprint'],
16
- scope: 'project',
17
- updatedAt: 'Just now',
18
- },
19
- {
20
- id: 'm2',
21
- content: 'User prefers OKLch tokens, minimal visual flair, and token-driven styling only. No hardcoded hex anywhere in the v8 tree.',
22
- tags: ['preferences', 'design'],
23
- scope: 'global',
24
- updatedAt: '3 days ago',
25
- },
26
- {
27
- id: 'm3',
28
- content: 'Pre-existing test failures in `tests/a11y/forms.test.tsx` predate v8 work — do not chase them in this branch.',
29
- tags: ['tests', 'a11y'],
30
- scope: 'project',
31
- updatedAt: '1 week ago',
32
- },
33
- {
34
- id: 'm4',
35
- content: 'WIP=1 rule: only one feature active at a time per `feature_list.json`.',
36
- tags: ['process'],
37
- scope: 'project',
38
- updatedAt: '2 weeks ago',
39
- },
40
- ];
17
+ interface MemoryResponse {
18
+ entries?: Array<{
19
+ id?: string;
20
+ content?: string;
21
+ tags?: string[];
22
+ scope?: 'project' | 'global';
23
+ updatedAt?: string | number;
24
+ }>;
25
+ count?: number;
26
+ }
27
+
28
+ function toEntry(e: NonNullable<MemoryResponse['entries']>[number]): MemoryEntry {
29
+ return {
30
+ id: e.id || '',
31
+ content: e.content || '',
32
+ tags: e.tags || [],
33
+ scope: (e.scope || 'project') as MemoryScope,
34
+ updatedAt:
35
+ typeof e.updatedAt === 'number'
36
+ ? new Date(e.updatedAt).toLocaleString()
37
+ : e.updatedAt || '',
38
+ };
39
+ }
41
40
 
42
41
  export function MemoryView(): JSX.Element {
42
+ const mem = useFetch<MemoryResponse>('/api/memory');
43
+ const [scope, setScope] = useState<MemoryScope | 'all'>('all');
44
+
45
+ const entries = useMemo<MemoryEntry[]>(() => {
46
+ const list = (mem.data?.entries || []).map(toEntry);
47
+ if (scope === 'all') return list;
48
+ return list.filter((e) => e.scope === scope);
49
+ }, [mem.data, scope]);
50
+
43
51
  return (
44
52
  <Stack gap={5}>
45
53
  <ViewHeader
46
54
  title="Memory"
47
55
  description="Cross-session notes. Project memos live in the repo; global memos live on the user."
48
56
  />
49
- <MemoryVault
50
- entries={ENTRIES}
51
- empty={
52
- <EmptyState
53
- icon={<Brain size={24} aria-hidden="true" />}
54
- title="No memos yet"
55
- description="Memos appear here as you and the harness accumulate them."
56
- />
57
- }
58
- />
57
+ <Inline gap={2}>
58
+ {(['all', 'project', 'global'] as const).map((s) => (
59
+ <Chip key={s} selected={scope === s} onClick={() => setScope(s)}>
60
+ {s === 'all' ? 'All' : s === 'project' ? 'Project' : 'Global'}
61
+ </Chip>
62
+ ))}
63
+ </Inline>
64
+ {mem.loading ? (
65
+ <Skeleton style={{ height: 240 }} />
66
+ ) : entries.length === 0 ? (
67
+ <EmptyState
68
+ icon={<Brain size={32} aria-hidden />}
69
+ title="No memory entries"
70
+ description="Memos land here once they are written via the memory tools."
71
+ />
72
+ ) : (
73
+ <MemoryVault entries={entries} />
74
+ )}
59
75
  </Stack>
60
76
  );
61
77
  }