@polderlabs/bizar 7.0.4 → 8.0.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 (489) hide show
  1. package/.claude/settings.local.json +8 -0
  2. package/bizar-dash/DESIGN.md +729 -969
  3. package/bizar-dash/GLYPH.md +418 -0
  4. package/bizar-dash/PLAN.md +1135 -0
  5. package/bizar-dash/dist/assets/ActivityFeed-BRBtQOHB.js +6 -0
  6. package/bizar-dash/dist/assets/ActivityFeed-BRBtQOHB.js.map +1 -0
  7. package/bizar-dash/dist/assets/ActivityView-CwqhxBfh.js +1 -0
  8. package/bizar-dash/dist/assets/ActivityView-CwqhxBfh.js.map +1 -0
  9. package/bizar-dash/dist/assets/AgentActivity-6MxU-a9F.js +1 -0
  10. package/bizar-dash/dist/assets/AgentActivity-6MxU-a9F.js.map +1 -0
  11. package/bizar-dash/dist/assets/AgentsView-BYrOFdwl.js +8 -0
  12. package/bizar-dash/dist/assets/AgentsView-BYrOFdwl.js.map +1 -0
  13. package/bizar-dash/dist/assets/Badge-Cd61wsBa.js +1 -0
  14. package/bizar-dash/dist/assets/Badge-Cd61wsBa.js.map +1 -0
  15. package/bizar-dash/dist/assets/Card-C_bvqXdQ.js +1 -0
  16. package/bizar-dash/dist/assets/Card-C_bvqXdQ.js.map +1 -0
  17. package/bizar-dash/dist/assets/EmptyState-BWQuKnk9.js +1 -0
  18. package/bizar-dash/dist/assets/EmptyState-BWQuKnk9.js.map +1 -0
  19. package/bizar-dash/dist/assets/GoalsView-Dok0yt9S.js +11 -0
  20. package/bizar-dash/dist/assets/GoalsView-Dok0yt9S.js.map +1 -0
  21. package/bizar-dash/dist/assets/Grid-C62gCPqt.js +1 -0
  22. package/bizar-dash/dist/assets/Grid-C62gCPqt.js.map +1 -0
  23. package/bizar-dash/dist/assets/KanbanCard-CtTKP6ZX.js +21 -0
  24. package/bizar-dash/dist/assets/KanbanCard-CtTKP6ZX.js.map +1 -0
  25. package/bizar-dash/dist/assets/LibrariesView-BcyBQXiY.js +67 -0
  26. package/bizar-dash/dist/assets/LibrariesView-BcyBQXiY.js.map +1 -0
  27. package/bizar-dash/dist/assets/MemoryView-49wR4u-y.js +13 -0
  28. package/bizar-dash/dist/assets/MemoryView-49wR4u-y.js.map +1 -0
  29. package/bizar-dash/dist/assets/OverviewView-BtQ_UWYj.js +1 -0
  30. package/bizar-dash/dist/assets/OverviewView-BtQ_UWYj.js.map +1 -0
  31. package/bizar-dash/dist/assets/ProgressBar-CpvDeq9F.js +1 -0
  32. package/bizar-dash/dist/assets/ProgressBar-CpvDeq9F.js.map +1 -0
  33. package/bizar-dash/dist/assets/SettingsRow-DmIe5OUu.js +30 -0
  34. package/bizar-dash/dist/assets/SettingsRow-DmIe5OUu.js.map +1 -0
  35. package/bizar-dash/dist/assets/SettingsView-D1KmGWbi.js +48 -0
  36. package/bizar-dash/dist/assets/SettingsView-D1KmGWbi.js.map +1 -0
  37. package/bizar-dash/dist/assets/StatTile-BkIP32gG.js +11 -0
  38. package/bizar-dash/dist/assets/StatTile-BkIP32gG.js.map +1 -0
  39. package/bizar-dash/dist/assets/TasksView-Cba3GJ42.js +1 -0
  40. package/bizar-dash/dist/assets/TasksView-Cba3GJ42.js.map +1 -0
  41. package/bizar-dash/dist/assets/ViewHeader-D6c2cw1b.js +6 -0
  42. package/bizar-dash/dist/assets/ViewHeader-D6c2cw1b.js.map +1 -0
  43. package/bizar-dash/dist/assets/brain-DeoXNDE2.js +6 -0
  44. package/bizar-dash/dist/assets/brain-DeoXNDE2.js.map +1 -0
  45. package/bizar-dash/dist/assets/calendar-DRlQkGJc.js +6 -0
  46. package/bizar-dash/dist/assets/calendar-DRlQkGJc.js.map +1 -0
  47. package/bizar-dash/dist/assets/circle-check-DmYQ3vGp.js +6 -0
  48. package/bizar-dash/dist/assets/circle-check-DmYQ3vGp.js.map +1 -0
  49. package/bizar-dash/dist/assets/cmdk-BwN8hcKQ.js +80 -0
  50. package/bizar-dash/dist/assets/cmdk-BwN8hcKQ.js.map +1 -0
  51. package/bizar-dash/dist/assets/dnd-kit-DR2Qzzxk.js +5 -0
  52. package/bizar-dash/dist/assets/dnd-kit-DR2Qzzxk.js.map +1 -0
  53. package/bizar-dash/dist/assets/git-merge-OoqBKQer.js +6 -0
  54. package/bizar-dash/dist/assets/git-merge-OoqBKQer.js.map +1 -0
  55. package/bizar-dash/dist/assets/git-pull-request-CXBQTR2f.js +6 -0
  56. package/bizar-dash/dist/assets/git-pull-request-CXBQTR2f.js.map +1 -0
  57. package/bizar-dash/dist/assets/main-COdgjqbZ.css +1 -0
  58. package/bizar-dash/dist/assets/main-Cw6gybzS.js +109 -0
  59. package/bizar-dash/dist/assets/main-Cw6gybzS.js.map +1 -0
  60. package/bizar-dash/dist/assets/message-square-DUTeIQAR.js +6 -0
  61. package/bizar-dash/dist/assets/message-square-DUTeIQAR.js.map +1 -0
  62. package/bizar-dash/dist/assets/minus-CrStJTZ7.js +6 -0
  63. package/bizar-dash/dist/assets/minus-CrStJTZ7.js.map +1 -0
  64. package/bizar-dash/dist/assets/wrench-BJ1WIC4u.js +6 -0
  65. package/bizar-dash/dist/assets/wrench-BJ1WIC4u.js.map +1 -0
  66. package/bizar-dash/dist/{mobile.html → v8.html} +6 -9
  67. package/bizar-dash/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
  68. package/bizar-dash/src/server/server.mjs +1 -57
  69. package/bizar-dash/src/web/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  70. package/bizar-dash/src/web/v8/App.tsx +188 -0
  71. package/bizar-dash/src/web/v8/__tests__/App.test.tsx +102 -0
  72. package/bizar-dash/src/web/v8/__tests__/AppShell.test.tsx +79 -0
  73. package/bizar-dash/src/web/v8/__tests__/PageSkeleton.test.tsx +12 -0
  74. package/bizar-dash/src/web/v8/__tests__/SettingsView.test.tsx +84 -0
  75. package/bizar-dash/src/web/v8/__tests__/Sidebar.test.tsx +95 -0
  76. package/bizar-dash/src/web/v8/__tests__/activity.test.tsx +63 -0
  77. package/bizar-dash/src/web/v8/__tests__/agents.test.tsx +90 -0
  78. package/bizar-dash/src/web/v8/__tests__/controls.test.tsx +135 -0
  79. package/bizar-dash/src/web/v8/__tests__/cx.test.ts +25 -0
  80. package/bizar-dash/src/web/v8/__tests__/data.test.tsx +293 -0
  81. package/bizar-dash/src/web/v8/__tests__/feedback.test.tsx +213 -0
  82. package/bizar-dash/src/web/v8/__tests__/goals.test.tsx +105 -0
  83. package/bizar-dash/src/web/v8/__tests__/kanban.test.tsx +176 -0
  84. package/bizar-dash/src/web/v8/__tests__/libraries.test.tsx +70 -0
  85. package/bizar-dash/src/web/v8/__tests__/memory.test.tsx +60 -0
  86. package/bizar-dash/src/web/v8/__tests__/navigation.test.tsx +137 -0
  87. package/bizar-dash/src/web/v8/__tests__/settings.test.tsx +104 -0
  88. package/bizar-dash/src/web/v8/__tests__/theme.test.tsx +98 -0
  89. package/bizar-dash/src/web/v8/__tests__/views.test.tsx +112 -0
  90. package/bizar-dash/src/web/v8/main.tsx +28 -0
  91. package/bizar-dash/src/web/v8/shell/AppShell.tsx +90 -0
  92. package/bizar-dash/src/web/v8/shell/PageSkeleton.tsx +29 -0
  93. package/bizar-dash/src/web/v8/shell/Sidebar.tsx +361 -0
  94. package/bizar-dash/src/web/v8/shell/StatusBar.tsx +63 -0
  95. package/bizar-dash/src/web/v8/shell/Topbar.tsx +113 -0
  96. package/bizar-dash/src/web/v8/shell/index.ts +15 -0
  97. package/bizar-dash/src/web/v8/ui/activity/ActivityFeed.tsx +137 -0
  98. package/bizar-dash/src/web/v8/ui/agents/AgentActivity.tsx +101 -0
  99. package/bizar-dash/src/web/v8/ui/agents/AgentCard.tsx +158 -0
  100. package/bizar-dash/src/web/v8/ui/controls/Button.tsx +141 -0
  101. package/bizar-dash/src/web/v8/ui/controls/ButtonGroup.tsx +32 -0
  102. package/bizar-dash/src/web/v8/ui/controls/Checkbox.tsx +49 -0
  103. package/bizar-dash/src/web/v8/ui/controls/Field.tsx +78 -0
  104. package/bizar-dash/src/web/v8/ui/controls/Form.tsx +23 -0
  105. package/bizar-dash/src/web/v8/ui/controls/IconButton.tsx +112 -0
  106. package/bizar-dash/src/web/v8/ui/controls/Input.tsx +94 -0
  107. package/bizar-dash/src/web/v8/ui/controls/RadioGroup.tsx +74 -0
  108. package/bizar-dash/src/web/v8/ui/controls/Select.tsx +171 -0
  109. package/bizar-dash/src/web/v8/ui/controls/Slider.tsx +68 -0
  110. package/bizar-dash/src/web/v8/ui/controls/Switch.tsx +56 -0
  111. package/bizar-dash/src/web/v8/ui/controls/Textarea.tsx +64 -0
  112. package/bizar-dash/src/web/v8/ui/controls/Toggle.tsx +36 -0
  113. package/bizar-dash/src/web/v8/ui/controls/ToggleGroup.tsx +85 -0
  114. package/bizar-dash/src/web/v8/ui/data/Accordion.tsx +134 -0
  115. package/bizar-dash/src/web/v8/ui/data/Avatar.tsx +175 -0
  116. package/bizar-dash/src/web/v8/ui/data/Badge.tsx +93 -0
  117. package/bizar-dash/src/web/v8/ui/data/BarList.tsx +101 -0
  118. package/bizar-dash/src/web/v8/ui/data/Card.tsx +140 -0
  119. package/bizar-dash/src/web/v8/ui/data/Chip.tsx +96 -0
  120. package/bizar-dash/src/web/v8/ui/data/Kbd.tsx +42 -0
  121. package/bizar-dash/src/web/v8/ui/data/ProgressBar.tsx +93 -0
  122. package/bizar-dash/src/web/v8/ui/data/Sparkline.tsx +98 -0
  123. package/bizar-dash/src/web/v8/ui/data/StatTile.tsx +150 -0
  124. package/bizar-dash/src/web/v8/ui/data/Table.tsx +170 -0
  125. package/bizar-dash/src/web/v8/ui/data/Timeline.tsx +130 -0
  126. package/bizar-dash/src/web/v8/ui/data/ViewHeader.tsx +122 -0
  127. package/bizar-dash/src/web/v8/ui/feedback/Alert.tsx +95 -0
  128. package/bizar-dash/src/web/v8/ui/feedback/Banner.tsx +39 -0
  129. package/bizar-dash/src/web/v8/ui/feedback/ContextMenu.tsx +143 -0
  130. package/bizar-dash/src/web/v8/ui/feedback/Dialog.tsx +149 -0
  131. package/bizar-dash/src/web/v8/ui/feedback/Drawer.tsx +8 -0
  132. package/bizar-dash/src/web/v8/ui/feedback/DropdownMenu.tsx +231 -0
  133. package/bizar-dash/src/web/v8/ui/feedback/EmptyState.tsx +48 -0
  134. package/bizar-dash/src/web/v8/ui/feedback/Popover.tsx +56 -0
  135. package/bizar-dash/src/web/v8/ui/feedback/Sheet.tsx +103 -0
  136. package/bizar-dash/src/web/v8/ui/feedback/Skeleton.tsx +67 -0
  137. package/bizar-dash/src/web/v8/ui/feedback/Spinner.tsx +30 -0
  138. package/bizar-dash/src/web/v8/ui/feedback/Toast.tsx +66 -0
  139. package/bizar-dash/src/web/v8/ui/feedback/Tooltip.tsx +89 -0
  140. package/bizar-dash/src/web/v8/ui/goals/GoalCard.tsx +176 -0
  141. package/bizar-dash/src/web/v8/ui/goals/KeyResult.tsx +115 -0
  142. package/bizar-dash/src/web/v8/ui/index.ts +322 -0
  143. package/bizar-dash/src/web/v8/ui/kanban/KanbanBoard.tsx +80 -0
  144. package/bizar-dash/src/web/v8/ui/kanban/KanbanCard.tsx +247 -0
  145. package/bizar-dash/src/web/v8/ui/kanban/KanbanColumn.tsx +181 -0
  146. package/bizar-dash/src/web/v8/ui/kanban/KanbanContextMenu.tsx +122 -0
  147. package/bizar-dash/src/web/v8/ui/kanban/KanbanQuickAdd.tsx +141 -0
  148. package/bizar-dash/src/web/v8/ui/libraries/LibraryGrid.tsx +30 -0
  149. package/bizar-dash/src/web/v8/ui/libraries/LibraryItem.tsx +161 -0
  150. package/bizar-dash/src/web/v8/ui/memory/MemoryVault.tsx +144 -0
  151. package/bizar-dash/src/web/v8/ui/navigation/CommandPalette.tsx +224 -0
  152. package/bizar-dash/src/web/v8/ui/navigation/NavLink.tsx +81 -0
  153. package/bizar-dash/src/web/v8/ui/navigation/Pagination.tsx +164 -0
  154. package/bizar-dash/src/web/v8/ui/navigation/Tabs.tsx +128 -0
  155. package/bizar-dash/src/web/v8/ui/navigation/useCommandPaletteHotkey.test.ts +79 -0
  156. package/bizar-dash/src/web/v8/ui/primitives/Box.tsx +144 -0
  157. package/bizar-dash/src/web/v8/ui/primitives/Center.tsx +40 -0
  158. package/bizar-dash/src/web/v8/ui/primitives/Cluster.tsx +67 -0
  159. package/bizar-dash/src/web/v8/ui/primitives/Grid.tsx +104 -0
  160. package/bizar-dash/src/web/v8/ui/primitives/Inline.tsx +77 -0
  161. package/bizar-dash/src/web/v8/ui/primitives/Portal.tsx +33 -0
  162. package/bizar-dash/src/web/v8/ui/primitives/ScrollArea.tsx +62 -0
  163. package/bizar-dash/src/web/v8/ui/primitives/Separator.tsx +42 -0
  164. package/bizar-dash/src/web/v8/ui/primitives/Stack.tsx +73 -0
  165. package/bizar-dash/src/web/v8/ui/primitives/VisuallyHidden.tsx +49 -0
  166. package/bizar-dash/src/web/v8/ui/settings/SettingsNav.tsx +91 -0
  167. package/bizar-dash/src/web/v8/ui/settings/SettingsRow.tsx +88 -0
  168. package/bizar-dash/src/web/v8/ui/settings/SettingsSection.tsx +109 -0
  169. package/bizar-dash/src/web/v8/ui/styles/globals.css +220 -0
  170. package/bizar-dash/src/web/v8/ui/styles/reset.css +57 -0
  171. package/bizar-dash/src/web/v8/ui/styles/tokens.css +217 -0
  172. package/bizar-dash/src/web/v8/ui/theme/DensityProvider.test.tsx +74 -0
  173. package/bizar-dash/src/web/v8/ui/theme/DensityProvider.tsx +66 -0
  174. package/bizar-dash/src/web/v8/ui/theme/ThemeProvider.test.tsx +86 -0
  175. package/bizar-dash/src/web/v8/ui/theme/ThemeProvider.tsx +94 -0
  176. package/bizar-dash/src/web/v8/ui/theme/ThemeToggle.tsx +88 -0
  177. package/bizar-dash/src/web/v8/ui/theme/useDensity.ts +15 -0
  178. package/bizar-dash/src/web/v8/ui/theme/useTheme.ts +16 -0
  179. package/bizar-dash/src/web/v8/ui/utils/cx.ts +19 -0
  180. package/bizar-dash/src/web/v8/views/Activity/ActivityView.tsx +33 -0
  181. package/bizar-dash/src/web/v8/views/Agents/AgentsView.tsx +108 -0
  182. package/bizar-dash/src/web/v8/views/CommandPalette/AppCommandPalette.test.tsx +142 -0
  183. package/bizar-dash/src/web/v8/views/CommandPalette/AppCommandPalette.tsx +144 -0
  184. package/bizar-dash/src/web/v8/views/Goals/GoalsView.tsx +84 -0
  185. package/bizar-dash/src/web/v8/views/Libraries/LibrariesView.tsx +41 -0
  186. package/bizar-dash/src/web/v8/views/Memory/MemoryView.tsx +61 -0
  187. package/bizar-dash/src/web/v8/views/Overview/OverviewView.tsx +92 -0
  188. package/bizar-dash/src/web/v8/views/Router.tsx +96 -0
  189. package/bizar-dash/src/web/v8/views/Settings/SettingsView.tsx +305 -0
  190. package/bizar-dash/src/web/v8/views/Tasks/CommandPalettePlaceholder.tsx +106 -0
  191. package/bizar-dash/src/web/v8/views/Tasks/TasksKanbanPlaceholder.tsx +62 -0
  192. package/bizar-dash/src/web/v8/views/Tasks/TasksView.tsx +74 -0
  193. package/bizar-dash/src/web/v8/vite-env.d.ts +15 -0
  194. package/bizar-dash/src/web/{mobile.html → v8.html} +4 -7
  195. package/bizar-dash/tests/setup.ts +26 -0
  196. package/bizar-dash/vite.config.ts +26 -2
  197. package/bizar-dash/vitest.config.ts +5 -3
  198. package/package.json +36 -3
  199. package/bizar-dash/dist/assets/EnvVarsSection-BfhAz3ax.js +0 -114
  200. package/bizar-dash/dist/assets/EnvVarsSection-BfhAz3ax.js.map +0 -1
  201. package/bizar-dash/dist/assets/MobileChat-DLWdv6tQ.js +0 -1
  202. package/bizar-dash/dist/assets/MobileChat-DLWdv6tQ.js.map +0 -1
  203. package/bizar-dash/dist/assets/MobileSettings-Bxv62uPY.js +0 -1
  204. package/bizar-dash/dist/assets/MobileSettings-Bxv62uPY.js.map +0 -1
  205. package/bizar-dash/dist/assets/Toast-ATSAmbdi.js +0 -26
  206. package/bizar-dash/dist/assets/Toast-ATSAmbdi.js.map +0 -1
  207. package/bizar-dash/dist/assets/__vite-browser-external-BIHI7g3E.js +0 -1
  208. package/bizar-dash/dist/assets/__vite-browser-external-BIHI7g3E.js.map +0 -1
  209. package/bizar-dash/dist/assets/main-CJAtrosO.css +0 -1
  210. package/bizar-dash/dist/assets/main-DKKj9dsq.js +0 -430
  211. package/bizar-dash/dist/assets/main-DKKj9dsq.js.map +0 -1
  212. package/bizar-dash/dist/assets/mobile-C_naUN91.js +0 -1
  213. package/bizar-dash/dist/assets/mobile-C_naUN91.js.map +0 -1
  214. package/bizar-dash/dist/assets/mobile-layout-BWLtwtfQ.css +0 -1
  215. package/bizar-dash/dist/assets/mobile-layout-GZ3bE8L6.js +0 -211
  216. package/bizar-dash/dist/assets/mobile-layout-GZ3bE8L6.js.map +0 -1
  217. package/bizar-dash/dist/assets/useSlashCommands-BOwD7lNb.js +0 -65
  218. package/bizar-dash/dist/assets/useSlashCommands-BOwD7lNb.js.map +0 -1
  219. package/bizar-dash/dist/index.html +0 -43
  220. package/bizar-dash/src/web/App.tsx +0 -915
  221. package/bizar-dash/src/web/MobileApp.tsx +0 -414
  222. package/bizar-dash/src/web/components/ArtifactCreateDialog.tsx +0 -95
  223. package/bizar-dash/src/web/components/ArtifactListDialog.tsx +0 -55
  224. package/bizar-dash/src/web/components/ArtifactViewer.tsx +0 -144
  225. package/bizar-dash/src/web/components/AuditDialog.tsx +0 -79
  226. package/bizar-dash/src/web/components/AutosaveField.tsx +0 -50
  227. package/bizar-dash/src/web/components/BackupRestore.tsx +0 -330
  228. package/bizar-dash/src/web/components/BgStatusBadge.tsx +0 -32
  229. package/bizar-dash/src/web/components/Button.tsx +0 -56
  230. package/bizar-dash/src/web/components/CanvasContextMenu.tsx +0 -68
  231. package/bizar-dash/src/web/components/Card.tsx +0 -40
  232. package/bizar-dash/src/web/components/CollapsibleSection.tsx +0 -72
  233. package/bizar-dash/src/web/components/CommandDialog.tsx +0 -66
  234. package/bizar-dash/src/web/components/DoctorPanel.tsx +0 -160
  235. package/bizar-dash/src/web/components/EmptyState.tsx +0 -30
  236. package/bizar-dash/src/web/components/EnvVarManager.tsx +0 -430
  237. package/bizar-dash/src/web/components/EvalDiff.tsx +0 -157
  238. package/bizar-dash/src/web/components/EvalExportButton.tsx +0 -27
  239. package/bizar-dash/src/web/components/EvalRunCard.tsx +0 -78
  240. package/bizar-dash/src/web/components/FileBrowser.tsx +0 -633
  241. package/bizar-dash/src/web/components/HeadroomSettings.tsx +0 -418
  242. package/bizar-dash/src/web/components/HeadroomStatus.tsx +0 -158
  243. package/bizar-dash/src/web/components/HelpDialog.tsx +0 -55
  244. package/bizar-dash/src/web/components/InviteDialog.tsx +0 -205
  245. package/bizar-dash/src/web/components/KillConfirmDialog.tsx +0 -88
  246. package/bizar-dash/src/web/components/MobileBottomNav.tsx +0 -38
  247. package/bizar-dash/src/web/components/MobileDrawer.tsx +0 -68
  248. package/bizar-dash/src/web/components/MobileHeader.tsx +0 -50
  249. package/bizar-dash/src/web/components/MobileLayout.tsx +0 -63
  250. package/bizar-dash/src/web/components/Modal.tsx +0 -215
  251. package/bizar-dash/src/web/components/Notifications.tsx +0 -242
  252. package/bizar-dash/src/web/components/ScheduleTemplateCard.tsx +0 -72
  253. package/bizar-dash/src/web/components/ScreenshotCapture.tsx +0 -138
  254. package/bizar-dash/src/web/components/ScreenshotOCR.tsx +0 -42
  255. package/bizar-dash/src/web/components/SearchModal.tsx +0 -227
  256. package/bizar-dash/src/web/components/SettingsNav.tsx +0 -117
  257. package/bizar-dash/src/web/components/SettingsSearch.tsx +0 -328
  258. package/bizar-dash/src/web/components/Sidebar.tsx +0 -89
  259. package/bizar-dash/src/web/components/Spinner.tsx +0 -19
  260. package/bizar-dash/src/web/components/StatusBadge.tsx +0 -56
  261. package/bizar-dash/src/web/components/Tag.tsx +0 -41
  262. package/bizar-dash/src/web/components/TailscaleSettings.tsx +0 -161
  263. package/bizar-dash/src/web/components/TaskCard.tsx +0 -69
  264. package/bizar-dash/src/web/components/TaskCreateSheet.tsx +0 -76
  265. package/bizar-dash/src/web/components/Toast.tsx +0 -150
  266. package/bizar-dash/src/web/components/Toggle.tsx +0 -31
  267. package/bizar-dash/src/web/components/Topbar.tsx +0 -455
  268. package/bizar-dash/src/web/components/UsageChart.tsx +0 -250
  269. package/bizar-dash/src/web/components/UsageTable.tsx +0 -90
  270. package/bizar-dash/src/web/components/VirtualList.tsx +0 -53
  271. package/bizar-dash/src/web/components/VisualPlanDialog.tsx +0 -58
  272. package/bizar-dash/src/web/components/VoiceNotesPanel.tsx +0 -211
  273. package/bizar-dash/src/web/components/VoiceRecorder.tsx +0 -105
  274. package/bizar-dash/src/web/components/WorkspaceSelector.tsx +0 -158
  275. package/bizar-dash/src/web/components/agents/CommunicationLog.tsx +0 -126
  276. package/bizar-dash/src/web/components/agents/DependencyGraph.tsx +0 -163
  277. package/bizar-dash/src/web/components/agents/QualityGates.tsx +0 -123
  278. package/bizar-dash/src/web/components/agents/RealTimeEventLog.tsx +0 -127
  279. package/bizar-dash/src/web/components/agents/RoutingDecisions.test.tsx +0 -148
  280. package/bizar-dash/src/web/components/agents/RoutingDecisions.tsx +0 -160
  281. package/bizar-dash/src/web/components/background/AttachButton.tsx +0 -96
  282. package/bizar-dash/src/web/components/background/TmuxAttachCard.tsx +0 -122
  283. package/bizar-dash/src/web/components/chat/AgentChip.tsx +0 -68
  284. package/bizar-dash/src/web/components/chat/AgentNode.tsx +0 -127
  285. package/bizar-dash/src/web/components/chat/AgentTree.tsx +0 -80
  286. package/bizar-dash/src/web/components/chat/ChatBubble.tsx +0 -60
  287. package/bizar-dash/src/web/components/chat/ChatComposer.tsx +0 -72
  288. package/bizar-dash/src/web/components/chat/ChatInfoPanel.tsx +0 -370
  289. package/bizar-dash/src/web/components/chat/ChatRail.tsx +0 -387
  290. package/bizar-dash/src/web/components/chat/ChatThread.tsx +0 -127
  291. package/bizar-dash/src/web/components/chat/ChatTopBar.tsx +0 -50
  292. package/bizar-dash/src/web/components/chat/Composer.tsx +0 -166
  293. package/bizar-dash/src/web/components/chat/ConfirmModal.tsx +0 -54
  294. package/bizar-dash/src/web/components/chat/EmptyState.tsx +0 -21
  295. package/bizar-dash/src/web/components/chat/FirstRunGreeting.tsx +0 -18
  296. package/bizar-dash/src/web/components/chat/FloatingComposer.tsx +0 -38
  297. package/bizar-dash/src/web/components/chat/InfoPanel.tsx +0 -184
  298. package/bizar-dash/src/web/components/chat/JumpToLatest.tsx +0 -58
  299. package/bizar-dash/src/web/components/chat/LoadingSkeleton.tsx +0 -19
  300. package/bizar-dash/src/web/components/chat/MessageBlock.tsx +0 -260
  301. package/bizar-dash/src/web/components/chat/MessageBubble.tsx +0 -60
  302. package/bizar-dash/src/web/components/chat/SessionList.tsx +0 -163
  303. package/bizar-dash/src/web/components/chat/SessionRowMenu.tsx +0 -206
  304. package/bizar-dash/src/web/components/chat/StreamingIndicator.tsx +0 -37
  305. package/bizar-dash/src/web/components/chat/SuggestionCards.tsx +0 -55
  306. package/bizar-dash/src/web/components/chat/WelcomeScreen.tsx +0 -36
  307. package/bizar-dash/src/web/components/chat/_legacy.ts +0 -30
  308. package/bizar-dash/src/web/components/chat/index.ts +0 -31
  309. package/bizar-dash/src/web/components/chat/useAutoGrowTextarea.ts +0 -18
  310. package/bizar-dash/src/web/components/chat/useChat.ts +0 -1190
  311. package/bizar-dash/src/web/components/chat/useSlashCommands.ts +0 -47
  312. package/bizar-dash/src/web/components/goals/GoalInput.tsx +0 -86
  313. package/bizar-dash/src/web/components/goals/PlanVisualization.tsx +0 -111
  314. package/bizar-dash/src/web/components/tasks/BacklogPanel.css +0 -109
  315. package/bizar-dash/src/web/components/tasks/BacklogPanel.tsx +0 -209
  316. package/bizar-dash/src/web/hooks/useAutosave.ts +0 -107
  317. package/bizar-dash/src/web/hooks/useI18n.ts +0 -13
  318. package/bizar-dash/src/web/index.html +0 -37
  319. package/bizar-dash/src/web/lib/api.ts +0 -237
  320. package/bizar-dash/src/web/lib/goapPlanner.ts +0 -614
  321. package/bizar-dash/src/web/lib/i18n.ts +0 -25
  322. package/bizar-dash/src/web/lib/logger.ts +0 -30
  323. package/bizar-dash/src/web/lib/markdown.tsx +0 -59
  324. package/bizar-dash/src/web/lib/search.ts +0 -115
  325. package/bizar-dash/src/web/lib/types.ts +0 -894
  326. package/bizar-dash/src/web/lib/utils.ts +0 -114
  327. package/bizar-dash/src/web/lib/ws.ts +0 -177
  328. package/bizar-dash/src/web/locales/en.json +0 -52
  329. package/bizar-dash/src/web/main.tsx +0 -43
  330. package/bizar-dash/src/web/mobile/MobileApp.tsx +0 -309
  331. package/bizar-dash/src/web/mobile/MobileBottomNav.tsx +0 -38
  332. package/bizar-dash/src/web/mobile/MobileChat.tsx +0 -138
  333. package/bizar-dash/src/web/mobile/MobileDoctor.tsx +0 -80
  334. package/bizar-dash/src/web/mobile/MobileEval.tsx +0 -167
  335. package/bizar-dash/src/web/mobile/MobileMemory.tsx +0 -108
  336. package/bizar-dash/src/web/mobile/MobileOverview.tsx +0 -213
  337. package/bizar-dash/src/web/mobile/MobileSettings.tsx +0 -251
  338. package/bizar-dash/src/web/mobile/MobileTasks.tsx +0 -94
  339. package/bizar-dash/src/web/mobile/MobileTopbar.tsx +0 -115
  340. package/bizar-dash/src/web/mobile/components/MobileBottomSheet.tsx +0 -182
  341. package/bizar-dash/src/web/mobile/components/MobileListItem.tsx +0 -64
  342. package/bizar-dash/src/web/mobile/components/MobileModal.tsx +0 -123
  343. package/bizar-dash/src/web/mobile/views/MobileActivity.tsx +0 -273
  344. package/bizar-dash/src/web/mobile/views/MobileAgents.tsx +0 -374
  345. package/bizar-dash/src/web/mobile/views/MobileArtifactCanvas.tsx +0 -439
  346. package/bizar-dash/src/web/mobile/views/MobileArtifacts.tsx +0 -143
  347. package/bizar-dash/src/web/mobile/views/MobileChat.tsx +0 -257
  348. package/bizar-dash/src/web/mobile/views/MobileConfig.tsx +0 -175
  349. package/bizar-dash/src/web/mobile/views/MobileHistory.tsx +0 -191
  350. package/bizar-dash/src/web/mobile/views/MobileMods.tsx +0 -149
  351. package/bizar-dash/src/web/mobile/views/MobileMore.tsx +0 -121
  352. package/bizar-dash/src/web/mobile/views/MobileNotifications.tsx +0 -137
  353. package/bizar-dash/src/web/mobile/views/MobilePlans.tsx +0 -26
  354. package/bizar-dash/src/web/mobile/views/MobileSchedules.tsx +0 -685
  355. package/bizar-dash/src/web/mobile/views/MobileSearchModal.tsx +0 -172
  356. package/bizar-dash/src/web/mobile/views/MobileSettings.tsx +0 -363
  357. package/bizar-dash/src/web/mobile/views/MobileSkills.tsx +0 -153
  358. package/bizar-dash/src/web/mobile/views/MobileTasks.tsx +0 -564
  359. package/bizar-dash/src/web/mobile/views/QrCodePanel.tsx +0 -69
  360. package/bizar-dash/src/web/mobile.tsx +0 -14
  361. package/bizar-dash/src/web/styles/agents-redesign.css +0 -311
  362. package/bizar-dash/src/web/styles/chat.css +0 -1740
  363. package/bizar-dash/src/web/styles/glyphs.css +0 -960
  364. package/bizar-dash/src/web/styles/main.css +0 -10389
  365. package/bizar-dash/src/web/styles/memory.css +0 -1177
  366. package/bizar-dash/src/web/styles/minimax-usage.css +0 -842
  367. package/bizar-dash/src/web/styles/mobile-chat.css +0 -5
  368. package/bizar-dash/src/web/styles/mobile-layout.css +0 -233
  369. package/bizar-dash/src/web/styles/mobile.css +0 -2181
  370. package/bizar-dash/src/web/styles/settings.css +0 -775
  371. package/bizar-dash/src/web/styles/skills.css +0 -302
  372. package/bizar-dash/src/web/styles/tasks-redesign.css +0 -253
  373. package/bizar-dash/src/web/styles/tasks.css +0 -605
  374. package/bizar-dash/src/web/ui/controls/Button.tsx +0 -77
  375. package/bizar-dash/src/web/ui/controls/Checkbox.tsx +0 -95
  376. package/bizar-dash/src/web/ui/controls/IconButton.tsx +0 -66
  377. package/bizar-dash/src/web/ui/controls/Kbd.tsx +0 -24
  378. package/bizar-dash/src/web/ui/controls/NumberInput.tsx +0 -77
  379. package/bizar-dash/src/web/ui/controls/RadioGroup.tsx +0 -109
  380. package/bizar-dash/src/web/ui/controls/SearchInput.tsx +0 -91
  381. package/bizar-dash/src/web/ui/controls/Select.tsx +0 -92
  382. package/bizar-dash/src/web/ui/controls/Slider.tsx +0 -70
  383. package/bizar-dash/src/web/ui/controls/TextInput.tsx +0 -67
  384. package/bizar-dash/src/web/ui/controls/Textarea.tsx +0 -56
  385. package/bizar-dash/src/web/ui/controls/Toggle.tsx +0 -79
  386. package/bizar-dash/src/web/ui/controls/controls.css +0 -476
  387. package/bizar-dash/src/web/ui/controls/index.ts +0 -35
  388. package/bizar-dash/src/web/ui/data/BarChart.tsx +0 -60
  389. package/bizar-dash/src/web/ui/data/DataTable.tsx +0 -216
  390. package/bizar-dash/src/web/ui/data/EmptyState.tsx +0 -60
  391. package/bizar-dash/src/web/ui/data/ErrorState.tsx +0 -56
  392. package/bizar-dash/src/web/ui/data/KeyValueList.tsx +0 -106
  393. package/bizar-dash/src/web/ui/data/LoadingState.tsx +0 -65
  394. package/bizar-dash/src/web/ui/data/Sparkline.tsx +0 -87
  395. package/bizar-dash/src/web/ui/data/StatTile.tsx +0 -87
  396. package/bizar-dash/src/web/ui/data/data.css +0 -540
  397. package/bizar-dash/src/web/ui/data/index.ts +0 -31
  398. package/bizar-dash/src/web/ui/feedback/Badge.tsx +0 -49
  399. package/bizar-dash/src/web/ui/feedback/Dialog.tsx +0 -209
  400. package/bizar-dash/src/web/ui/feedback/ProgressBar.tsx +0 -69
  401. package/bizar-dash/src/web/ui/feedback/StatusDot.tsx +0 -50
  402. package/bizar-dash/src/web/ui/feedback/Toast.tsx +0 -200
  403. package/bizar-dash/src/web/ui/feedback/Tooltip.tsx +0 -126
  404. package/bizar-dash/src/web/ui/feedback/feedback.css +0 -314
  405. package/bizar-dash/src/web/ui/feedback/index.ts +0 -43
  406. package/bizar-dash/src/web/ui/index.ts +0 -57
  407. package/bizar-dash/src/web/ui/layout/AppShell.tsx +0 -51
  408. package/bizar-dash/src/web/ui/layout/Breadcrumbs.tsx +0 -97
  409. package/bizar-dash/src/web/ui/layout/Panel.tsx +0 -73
  410. package/bizar-dash/src/web/ui/layout/PanelHeader.tsx +0 -39
  411. package/bizar-dash/src/web/ui/layout/Sidebar.tsx +0 -131
  412. package/bizar-dash/src/web/ui/layout/Tabs.tsx +0 -133
  413. package/bizar-dash/src/web/ui/layout/Topbar.tsx +0 -42
  414. package/bizar-dash/src/web/ui/layout/ViewHeader.tsx +0 -48
  415. package/bizar-dash/src/web/ui/layout/index.ts +0 -34
  416. package/bizar-dash/src/web/ui/layout/layout.css +0 -464
  417. package/bizar-dash/src/web/ui/navigation/CommandPalette.tsx +0 -199
  418. package/bizar-dash/src/web/ui/navigation/NavGroup.tsx +0 -95
  419. package/bizar-dash/src/web/ui/navigation/NavLink.tsx +0 -93
  420. package/bizar-dash/src/web/ui/navigation/index.ts +0 -17
  421. package/bizar-dash/src/web/ui/navigation/navigation.css +0 -343
  422. package/bizar-dash/src/web/ui/primitives/Box.tsx +0 -91
  423. package/bizar-dash/src/web/ui/primitives/Grid.tsx +0 -49
  424. package/bizar-dash/src/web/ui/primitives/Inline.tsx +0 -55
  425. package/bizar-dash/src/web/ui/primitives/Separator.tsx +0 -46
  426. package/bizar-dash/src/web/ui/primitives/Stack.tsx +0 -54
  427. package/bizar-dash/src/web/ui/primitives/VisuallyHidden.tsx +0 -26
  428. package/bizar-dash/src/web/ui/primitives/index.ts +0 -23
  429. package/bizar-dash/src/web/ui/primitives/primitives.css +0 -183
  430. package/bizar-dash/src/web/ui/styles/globals.css +0 -86
  431. package/bizar-dash/src/web/ui/styles/reset.css +0 -125
  432. package/bizar-dash/src/web/ui/styles/tokens.css +0 -208
  433. package/bizar-dash/src/web/ui/theme/ThemeProvider.tsx +0 -142
  434. package/bizar-dash/src/web/ui/theme/tokens.ts +0 -131
  435. package/bizar-dash/src/web/ui/theme/useTheme.ts +0 -22
  436. package/bizar-dash/src/web/ui/utils/cx.ts +0 -42
  437. package/bizar-dash/src/web/views/Activity.tsx +0 -1221
  438. package/bizar-dash/src/web/views/Agents.tsx +0 -964
  439. package/bizar-dash/src/web/views/Artifacts.tsx +0 -1494
  440. package/bizar-dash/src/web/views/BackgroundAgents.tsx +0 -822
  441. package/bizar-dash/src/web/views/Chat.tsx +0 -532
  442. package/bizar-dash/src/web/views/Config.tsx +0 -3
  443. package/bizar-dash/src/web/views/Doctor.tsx +0 -317
  444. package/bizar-dash/src/web/views/Eval.tsx +0 -372
  445. package/bizar-dash/src/web/views/EvalReport.tsx +0 -353
  446. package/bizar-dash/src/web/views/GoalPlanner.tsx +0 -158
  447. package/bizar-dash/src/web/views/Harness.tsx +0 -306
  448. package/bizar-dash/src/web/views/History.tsx +0 -353
  449. package/bizar-dash/src/web/views/Memory.tsx +0 -193
  450. package/bizar-dash/src/web/views/MiniMaxUsage.tsx +0 -942
  451. package/bizar-dash/src/web/views/ModView.tsx +0 -207
  452. package/bizar-dash/src/web/views/Mods.tsx +0 -706
  453. package/bizar-dash/src/web/views/Overview.tsx +0 -1343
  454. package/bizar-dash/src/web/views/Providers.tsx +0 -302
  455. package/bizar-dash/src/web/views/Schedules.tsx +0 -902
  456. package/bizar-dash/src/web/views/Settings.tsx +0 -308
  457. package/bizar-dash/src/web/views/Skills.tsx +0 -383
  458. package/bizar-dash/src/web/views/SpawnAgentModal.tsx +0 -221
  459. package/bizar-dash/src/web/views/Tasks.tsx +0 -789
  460. package/bizar-dash/src/web/views/Workspace.tsx +0 -294
  461. package/bizar-dash/src/web/views/glyphs/GlyphRenderer.tsx +0 -844
  462. package/bizar-dash/src/web/views/glyphs/components.tsx +0 -1098
  463. package/bizar-dash/src/web/views/memory/ConfigPanel.tsx +0 -426
  464. package/bizar-dash/src/web/views/memory/FromScreenshotPanel.tsx +0 -23
  465. package/bizar-dash/src/web/views/memory/GitSyncPanel.tsx +0 -220
  466. package/bizar-dash/src/web/views/memory/LightragPanel.tsx +0 -310
  467. package/bizar-dash/src/web/views/memory/MemoryGraphLegend.tsx +0 -29
  468. package/bizar-dash/src/web/views/memory/MemoryGraphPanel.tsx +0 -192
  469. package/bizar-dash/src/web/views/memory/MemoryGraphView.tsx +0 -336
  470. package/bizar-dash/src/web/views/memory/MemoryOverview.tsx +0 -367
  471. package/bizar-dash/src/web/views/memory/MemoryStatusCard.tsx +0 -160
  472. package/bizar-dash/src/web/views/memory/ObsidianPanel.tsx +0 -650
  473. package/bizar-dash/src/web/views/memory/SemanticSearchPanel.tsx +0 -197
  474. package/bizar-dash/src/web/views/memory/VaultFromClipboardPanel.tsx +0 -101
  475. package/bizar-dash/src/web/views/settings/ActivitySection.tsx +0 -205
  476. package/bizar-dash/src/web/views/settings/AgentSection.tsx +0 -305
  477. package/bizar-dash/src/web/views/settings/AuthSection.tsx +0 -159
  478. package/bizar-dash/src/web/views/settings/EnvVarsSection.tsx +0 -15
  479. package/bizar-dash/src/web/views/settings/GeneralSection.tsx +0 -128
  480. package/bizar-dash/src/web/views/settings/HeadroomSection.tsx +0 -39
  481. package/bizar-dash/src/web/views/settings/MemorySection.tsx +0 -154
  482. package/bizar-dash/src/web/views/settings/NetworkSection.tsx +0 -87
  483. package/bizar-dash/src/web/views/settings/NotificationsSection.tsx +0 -34
  484. package/bizar-dash/src/web/views/settings/SystemLlmSection.tsx +0 -81
  485. package/bizar-dash/src/web/views/settings/ThemeSection.tsx +0 -168
  486. package/bizar-dash/src/web/views/settings/UpdatesSection.tsx +0 -256
  487. package/bizar-dash/src/web/views/settings/WorkspacesSection.tsx +0 -189
  488. package/packages/sdk/.harness/agents.json +0 -17
  489. package/packages/sdk/.harness/topology.json +0 -4
@@ -1,1343 +0,0 @@
1
- // src/views/Overview.tsx — Wave 3 redesign.
2
- //
3
- // Hero dashboard, rebuilt on the new design system (../ui). Same external
4
- // surface (the `Overview({ snapshot, settings, activeTab, setActiveTab,
5
- // refreshSnapshot })` signature + named export) so App.tsx and every test
6
- // continues to import without change. The layout now reads top-to-bottom
7
- // as five sections, each rendered with the new primitives:
8
- //
9
- // 1. Header — title, active-project selector, refresh, theme toggle.
10
- // 2. Stat tile row — five KPIs (Agents / Tasks / Projects / Mods /
11
- // Background) using <StatTile>, mono values, single-accent icon.
12
- // 3. Chart grid — three panels of trend/sparkline + <BarChart>
13
- // (Tasks 30d / Agent activity / Tasks by status), then three
14
- // <Panel> surfaces (Memory / Active project / Recent mods). The
15
- // Memory slot wraps the existing <MemoryStatusCard> unchanged so
16
- // the Wave-3 redesign covers it without forking the card.
17
- // 4. Activity stream — <Panel> + compact inline list (mono timestamp,
18
- // severity-coloured icon, humanised title, slug summary, per-row
19
- // hide IconButton). Hidden keys are reconciled against
20
- // /activity/hidden (GET on mount) and POST /activity/hide (with
21
- // rollback on failure), matching the v3.15.0 server contract.
22
- // 5. Quick prompts — textarea + "Submit to Odin" button + eight
23
- // suggestion chips. Calls POST /tasks/submit and refreshes.
24
- //
25
- // All modals (AddProjectDialog, AddModDialog, etc.) still use the
26
- // legacy <Modal> stack — Wave 3 only reskins the chrome, not the
27
- // dialog layer. Everything else (Card, Button, VirtualList, useToast,
28
- // useModal, applyTheme, MemoryStatusCard) stays imported from its
29
- // existing path so the v6.x surface contracts are preserved.
30
- //
31
- // Tokens come exclusively from `ui/styles/tokens.css`; the only inline
32
- // styles used are narrow one-off decisions (mono font for timestamps,
33
- // overflow ellipsis on long paths). No gradients, no shadows beyond
34
- // hairline, no radius > 6px, no hardcoded colours. Dark mode is free
35
- // because the design system ships its own overrides.
36
-
37
- import React, { useEffect, useMemo, useRef, useState } from 'react';
38
- import {
39
- Bot,
40
- CheckSquare,
41
- Folder,
42
- Puzzle,
43
- PlayCircle,
44
- RefreshCw,
45
- Map,
46
- Send,
47
- Sparkles,
48
- AlertOctagon,
49
- AlertTriangle,
50
- Activity,
51
- Zap,
52
- EyeOff,
53
- Eye,
54
- X,
55
- } from 'lucide-react';
56
-
57
- import {
58
- Box,
59
- Stack,
60
- Inline,
61
- Grid,
62
- Panel,
63
- StatTile,
64
- Sparkline,
65
- BarChart,
66
- KeyValueList,
67
- Textarea,
68
- IconButton,
69
- Button as UiButton,
70
- Badge,
71
- StatusDot,
72
- EmptyState,
73
- LoadingState,
74
- } from '../ui';
75
-
76
- // Legacy components kept on purpose — the dialogs + their footers
77
- // remain tied to the legacy <Modal> stack until a Wave-4 migration.
78
- import { Button } from '../components/Button';
79
- import { MemoryStatusCard } from './memory/MemoryStatusCard';
80
- import { useToast } from '../components/Toast';
81
- import { useModal } from '../components/Modal';
82
- import { FileBrowser } from '../components/FileBrowser';
83
- import { api } from '../lib/api';
84
- import { formatRelative } from '../lib/utils';
85
- import type {
86
- ActivityItem,
87
- Mod,
88
- Overview,
89
- ProjectRecord,
90
- ScanResult,
91
- Settings,
92
- Snapshot,
93
- DirectoryListing,
94
- } from '../lib/types';
95
-
96
- type Props = {
97
- snapshot: Snapshot;
98
- settings: Settings;
99
- activeTab: string;
100
- setActiveTab: (id: string) => void;
101
- refreshSnapshot: () => Promise<void>;
102
- };
103
-
104
- function OverviewInner({
105
- snapshot,
106
- settings,
107
- setActiveTab,
108
- refreshSnapshot,
109
- }: Props) {
110
- const toast = useToast();
111
- const modal = useModal();
112
- const inputRef = useRef<HTMLTextAreaElement | null>(null);
113
-
114
- const [overview, setOverview] = useState<Overview | null>(
115
- snapshot.overview ?? null,
116
- );
117
- const [loading, setLoading] = useState(!snapshot.overview);
118
- const [projects, setProjects] = useState<ProjectRecord[]>(
119
- snapshot.projects || [],
120
- );
121
- const [activeId, setActiveId] = useState<string | null>(
122
- snapshot.activeProject?.id || null,
123
- );
124
- const [mods, setMods] = useState<Mod[]>(snapshot.mods || []);
125
- const [submitting, setSubmitting] = useState(false);
126
-
127
- // Live activity feed via SSE — see v3.7.0.
128
- const [activityItems, setActivityItems] = useState<ActivityItem[]>(
129
- snapshot.overview?.recentActivity ?? [],
130
- );
131
- // Hidden set lives server-side; we mirror a Set locally so the UI can
132
- // hide without losing the row from the underlying store. v3.15.0.
133
- const [hiddenKeys, setHiddenKeys] = useState<Set<string>>(new Set());
134
-
135
- // v7.0.4 — theme toggle is now hoisted to Topbar (see
136
- // components/Topbar.tsx); no per-view state needed here.
137
-
138
- // Load hidden set once on mount — v3.15.0.
139
- useEffect(() => {
140
- let cancelled = false;
141
- (async () => {
142
- try {
143
- const r = await api.get<{ hidden: string[] }>('/activity/hidden');
144
- if (!cancelled) setHiddenKeys(new Set(r.hidden || []));
145
- } catch {
146
- /* non-fatal — fall back to empty set */
147
- }
148
- })();
149
- return () => {
150
- cancelled = true;
151
- };
152
- }, []);
153
-
154
- // Stable per-row key (matches the server-side derivation in v3.15.0).
155
- const itemKey = (it: ActivityItem, idx: number): string => {
156
- const k = `${it.kind || ''}|${it.ts || ''}|${(it.slug as string) || (it.title as string) || ''}|${idx}`;
157
- let h = 0;
158
- for (let i = 0; i < k.length; i++) h = ((h << 5) - h + k.charCodeAt(i)) | 0;
159
- return Math.abs(h).toString(16).padStart(8, '0').slice(0, 16);
160
- };
161
-
162
- const onHide = async (key: string) => {
163
- const previous = hiddenKeys;
164
- const next = new Set(previous);
165
- next.add(key);
166
- setHiddenKeys(next);
167
- try {
168
- await api.post('/activity/hide', { keys: [key] });
169
- } catch (err) {
170
- setHiddenKeys(previous); // rollback
171
- toast.error(`Hide failed: ${(err as Error).message}`);
172
- }
173
- };
174
-
175
- const onClearAll = async () => {
176
- if (
177
- !window.confirm(
178
- 'Hide every recent activity item from the overview? The full log stays in Settings → Activity Log.',
179
- )
180
- )
181
- return;
182
- const all = activityItems.map((it, idx) => itemKey(it, idx));
183
- const next = new Set(hiddenKeys);
184
- all.forEach((k) => next.add(k));
185
- setHiddenKeys(next);
186
- try {
187
- await api.post('/activity/hide', { keys: all });
188
- toast.success(`Hidden ${all.length} item(s).`);
189
- } catch (err) {
190
- toast.error(`Clear failed: ${(err as Error).message}`);
191
- }
192
- };
193
-
194
- const onRestoreAll = async () => {
195
- setHiddenKeys(new Set());
196
- try {
197
- await api.del('/activity/hide');
198
- toast.success('All hidden activity restored.');
199
- } catch (err) {
200
- toast.error(`Restore failed: ${(err as Error).message}`);
201
- }
202
- };
203
-
204
- // Pull initial snapshot data into local state. v3.7.0.
205
- useEffect(() => {
206
- if (snapshot.overview) {
207
- setOverview(snapshot.overview);
208
- setActivityItems(snapshot.overview.recentActivity ?? []);
209
- setLoading(false);
210
- }
211
- setProjects(snapshot.projects || []);
212
- setActiveId(snapshot.activeProject?.id || null);
213
- setMods(snapshot.mods || []);
214
- }, [snapshot.overview, snapshot.projects, snapshot.activeProject, snapshot.mods]);
215
-
216
- // SSE activity stream — appends on `activity`, replaces on `snapshot`.
217
- useEffect(() => {
218
- let es: EventSource | null = null;
219
- try {
220
- const tok = api.getToken();
221
- const url = tok
222
- ? `/api/activity/stream?token=${encodeURIComponent(tok)}`
223
- : '/api/activity/stream';
224
- es = new EventSource(url);
225
- es.addEventListener('snapshot', (e) => {
226
- try {
227
- const parsed = JSON.parse((e as MessageEvent).data) as {
228
- events: ActivityItem[];
229
- };
230
- setActivityItems(
231
- Array.isArray(parsed.events) ? parsed.events.slice(0, 50) : [],
232
- );
233
- } catch {
234
- /* ignore */
235
- }
236
- });
237
- es.addEventListener('activity', (e) => {
238
- try {
239
- const entry = JSON.parse((e as MessageEvent).data) as ActivityItem;
240
- setActivityItems((cur) => [entry, ...cur].slice(0, 50));
241
- } catch {
242
- /* ignore */
243
- }
244
- });
245
- } catch {
246
- /* SSE unavailable — fallback to snapshot data */
247
- }
248
- return () => {
249
- try {
250
- es?.close();
251
- } catch {
252
- /* ignore */
253
- }
254
- };
255
- }, []);
256
-
257
- const onRefresh = async () => {
258
- toast.info('Refreshing…', 1500);
259
- await refreshSnapshot();
260
- try {
261
- const data = await api.get<{
262
- projects: ProjectRecord[];
263
- active: string | null;
264
- }>('/projects');
265
- setProjects(data.projects || []);
266
- setActiveId(data.active || null);
267
- } catch {
268
- /* ignore */
269
- }
270
- };
271
-
272
- const onAddProject = () => {
273
- modal.open({
274
- title: 'Add project',
275
- children: (
276
- <AddProjectDialog
277
- settings={settings}
278
- onAdd={async (path: string, name: string | null) => {
279
- try {
280
- const r = await api.post<ProjectRecord>('/projects', {
281
- path,
282
- name,
283
- });
284
- setProjects((cur) => [...cur.filter((p) => p.id !== r.id), r]);
285
- toast.success('Project added.');
286
- modal.close();
287
- } catch (err) {
288
- toast.error(`Add failed: ${(err as Error).message}`);
289
- }
290
- }}
291
- />
292
- ),
293
- footer: (
294
- <div className="modal-footer-actions">
295
- <Button variant="ghost" onClick={() => modal.close()}>
296
- Cancel
297
- </Button>
298
- </div>
299
- ),
300
- });
301
- };
302
-
303
- const onUseCurrentDir = async () => {
304
- try {
305
- const data = await api.post<{
306
- projects: ProjectRecord[];
307
- active: string | null;
308
- }>('/projects/auto-detect');
309
- setProjects(data.projects || []);
310
- setActiveId(data.active || null);
311
- const newActive = data.projects?.find((p) => p.id === data.active);
312
- toast.success(newActive ? `Active: ${newActive.name}` : 'Projects refreshed.');
313
- await refreshSnapshot();
314
- } catch (err) {
315
- toast.error(`Auto-detect failed: ${(err as Error).message}`);
316
- }
317
- };
318
-
319
- const onActivate = async (id: string) => {
320
- try {
321
- await api.post(`/projects/${encodeURIComponent(id)}/activate`);
322
- setActiveId(id);
323
- toast.success('Project activated.');
324
- await refreshSnapshot();
325
- } catch (err) {
326
- toast.error(`Activate failed: ${(err as Error).message}`);
327
- }
328
- };
329
-
330
- const onScan = async () => {
331
- if (!settings?.dashboard?.projectsDirectory) {
332
- toast.warning('No projects directory configured.');
333
- return;
334
- }
335
- try {
336
- const r = await api.post<ScanResult>('/projects/scan');
337
- if (r.error) {
338
- toast.error(r.error);
339
- } else {
340
- toast.success(`Added ${r.added.length}, skipped ${r.skipped}.`);
341
- }
342
- await refreshSnapshot();
343
- const data = await api.get<{
344
- projects: ProjectRecord[];
345
- active: string | null;
346
- }>('/projects');
347
- setProjects(data.projects || []);
348
- setActiveId(data.active || null);
349
- } catch (err) {
350
- toast.error(`Scan failed: ${(err as Error).message}`);
351
- }
352
- };
353
-
354
- // ─── Derived chart data ─────────────────────────────────────────────
355
-
356
- // Tasks by status — straight group-by on the live Task[] payload.
357
- const tasksByStatus = useMemo(() => {
358
- const buckets: Record<string, number> = {};
359
- (snapshot.tasks || []).forEach((t) => {
360
- buckets[t.status] = (buckets[t.status] || 0) + 1;
361
- });
362
- const palette: Record<string, string> = {
363
- queued: 'var(--chart-3)',
364
- doing: 'var(--info)',
365
- done: 'var(--chart-1)',
366
- blocked: 'var(--warning)',
367
- archived: 'var(--text-tertiary)',
368
- };
369
- return Object.entries(buckets).map(([status, value]) => ({
370
- label: status,
371
- value,
372
- color: palette[status] ?? 'var(--chart-2)',
373
- }));
374
- }, [snapshot.tasks]);
375
-
376
- // Tasks over the last 30 days — buckets by createdAt, padded to length 30.
377
- // We seed earlier days from the most recent bucket to keep the sparkline
378
- // visibly anchored to the current count instead of flat-zero.
379
- const tasksSparkline = useMemo(() => {
380
- const days = 30;
381
- const series = new Array(days).fill(0);
382
- const now = Date.now();
383
- (snapshot.tasks || []).forEach((t) => {
384
- const ts = Date.parse(t.createdAt || '');
385
- if (Number.isNaN(ts)) return;
386
- const offset = Math.floor((now - ts) / (24 * 3600 * 1000));
387
- if (offset >= 0 && offset < days) {
388
- series[days - 1 - offset] += 1;
389
- }
390
- });
391
- // pad earlier days with a smoothed copy of the most recent bucket
392
- const tail = series[series.length - 1] || 1;
393
- for (let i = 0; i < days - 1; i++) {
394
- if (series[i] === 0) series[i] = Math.max(1, Math.round(tail * (0.6 + i / days * 0.4)));
395
- }
396
- return series;
397
- }, [snapshot.tasks]);
398
-
399
- // Agent activity sparkline — built from distinct assignee names per day.
400
- const agentsSparkline = useMemo(() => {
401
- const days = 30;
402
- const series = new Array(days).fill(0);
403
- const now = Date.now();
404
- (snapshot.tasks || []).forEach((t) => {
405
- if (!t.assignee) return;
406
- const ts = Date.parse(t.updatedAt || t.createdAt || '');
407
- if (Number.isNaN(ts)) return;
408
- const offset = Math.floor((now - ts) / (24 * 3600 * 1000));
409
- if (offset >= 0 && offset < days) series[days - 1 - offset] += 1;
410
- });
411
- const tail = series[series.length - 1] || 1;
412
- for (let i = 0; i < days - 1; i++) {
413
- if (series[i] === 0) series[i] = Math.max(1, Math.round(tail * (0.6 + i / days * 0.4)));
414
- }
415
- return series;
416
- }, [snapshot.tasks]);
417
-
418
- // Background count proxy — assigned tasks whose status is in flight.
419
- const backgroundCount = useMemo(() => {
420
- return (snapshot.tasks || []).filter(
421
- (t) => !!t.assignee && (t.status === 'doing' || t.status === 'queued'),
422
- ).length;
423
- }, [snapshot.tasks]);
424
-
425
- const tasksTotal = (snapshot.tasks || []).length;
426
-
427
- // Active project — derive from activeProject or fall back to the first.
428
- const activeProject = useMemo<ProjectRecord | null>(() => {
429
- if (snapshot.activeProject) return snapshot.activeProject;
430
- if (!activeId) return projects[0] ?? null;
431
- return projects.find((p) => p.id === activeId) ?? null;
432
- }, [snapshot.activeProject, activeId, projects]);
433
-
434
- const visibleActivity = useMemo(
435
- () =>
436
- activityItems
437
- .slice(0, 30)
438
- .map((it, idx) => ({ it, idx, key: itemKey(it, idx) }))
439
- .filter(({ key }) => !hiddenKeys.has(key)),
440
- [activityItems, hiddenKeys],
441
- );
442
-
443
- if (loading || !overview) {
444
- return (
445
- <Box as="div" className="view view-overview" bg="0" p={7}>
446
- <Stack direction="row" align="center" justify="center">
447
- <LoadingState label="Loading overview…" />
448
- </Stack>
449
- </Box>
450
- );
451
- }
452
-
453
- return (
454
- <Box as="div" className="view view-overview" bg="0" p={7}>
455
- <Stack gap={6}>
456
- {/* ─── Section 1: Header ─────────────────────────────────────── */}
457
- <Inline justify="between" align="center" gap={3} wrap>
458
- <Stack gap={1}>
459
- <h1
460
- className="overview-title"
461
- style={{
462
- fontSize: 'var(--text-2xl)',
463
- fontWeight: 'var(--weight-semibold)',
464
- margin: 0,
465
- }}
466
- >
467
- Overview
468
- </h1>
469
- <span
470
- className="overview-subtitle muted"
471
- style={{ fontSize: 'var(--text-sm)', color: 'var(--text-secondary)' }}
472
- >
473
- {activeProject
474
- ? `Active: ${activeProject.name}`
475
- : 'No active project — pick one below.'}
476
- </span>
477
- </Stack>
478
-
479
- <Inline gap={2} align="center" wrap>
480
- {projects.length > 0 && (
481
- <span
482
- className="select select-size-sm overview-project-select"
483
- aria-label="Switch active project"
484
- >
485
- <select
486
- className="select-native"
487
- value={activeId ?? ''}
488
- onChange={async (e) => {
489
- const id = e.target.value;
490
- if (!id || id === activeId) return;
491
- await onActivate(id);
492
- }}
493
- aria-label="Switch active project"
494
- data-testid="overview-project-select"
495
- >
496
- {projects.map((p) => (
497
- <option key={p.id} value={p.id}>
498
- {p.name}
499
- </option>
500
- ))}
501
- </select>
502
- <svg
503
- className="select-caret"
504
- width="14"
505
- height="14"
506
- viewBox="0 0 24 24"
507
- fill="none"
508
- stroke="currentColor"
509
- strokeWidth="2"
510
- aria-hidden
511
- >
512
- <polyline points="6 9 12 15 18 9" />
513
- </svg>
514
- </span>
515
- )}
516
- <UiButton
517
- variant="secondary"
518
- size="sm"
519
- onClick={onRefresh}
520
- icon={<RefreshCw size={12} />}
521
- data-testid="overview-refresh"
522
- >
523
- Refresh
524
- </UiButton>
525
- </Inline>
526
- </Inline>
527
-
528
- {/* ─── Section 2: Stat tiles ────────────────────────────────── */}
529
- <Grid
530
- cols={5}
531
- autoFit
532
- gap={3}
533
- style={{ minHeight: 'unset' }}
534
- data-testid="overview-stat-row"
535
- >
536
- <StatTile
537
- label="Agents"
538
- value={overview.counts.agents}
539
- icon={<Bot size={18} />}
540
- href="#"
541
- data-testid="overview-stat-agents"
542
- />
543
- <StatTile
544
- label="Tasks"
545
- value={tasksTotal}
546
- icon={<CheckSquare size={18} />}
547
- data-testid="overview-stat-tasks"
548
- />
549
- <StatTile
550
- label="Projects"
551
- value={projects.length}
552
- icon={<Folder size={18} />}
553
- data-testid="overview-stat-projects"
554
- />
555
- <StatTile
556
- label="Mods"
557
- value={mods.length}
558
- icon={<Puzzle size={18} />}
559
- data-testid="overview-stat-mods"
560
- />
561
- <StatTile
562
- label="Background"
563
- value={backgroundCount}
564
- icon={<PlayCircle size={18} />}
565
- data-testid="overview-stat-background"
566
- />
567
- </Grid>
568
-
569
- {/* ─── Section 3: Chart grid (3 × 2) ────────────────────────── */}
570
- <Grid cols={3} autoFit gap={3}>
571
- <Panel
572
- title="Tasks · last 30 days"
573
- description="Bucketed from snapshot.tasks createdAt"
574
- padding={3}
575
- data-testid="overview-panel-tasks-spark"
576
- >
577
- <Box p={3}>
578
- <Stack direction="row" justify="between" align="end" gap={3}>
579
- <Sparkline
580
- data={tasksSparkline}
581
- width={220}
582
- height={56}
583
- ariaLabel="Tasks created per day, last 30"
584
- />
585
- <Box
586
- as="div"
587
- className="overview-spark-meta"
588
- style={{
589
- fontFamily: 'var(--font-mono)',
590
- fontVariantNumeric: 'tabular-nums',
591
- fontSize: 'var(--text-2xl)',
592
- fontWeight: 'var(--weight-semibold)',
593
- color: 'var(--text-primary)',
594
- }}
595
- >
596
- {tasksTotal}
597
- </Box>
598
- </Stack>
599
- </Box>
600
- </Panel>
601
-
602
- <Panel
603
- title="Agent activity · 30d"
604
- description="Distinct assignees touching tasks per day"
605
- padding={3}
606
- data-testid="overview-panel-agents-spark"
607
- >
608
- <Box p={3}>
609
- <Stack direction="row" justify="between" align="end" gap={3}>
610
- <Sparkline
611
- data={agentsSparkline}
612
- width={220}
613
- height={56}
614
- stroke="var(--chart-2)"
615
- fill="var(--info-subtle)"
616
- ariaLabel="Agent touches per day, last 30"
617
- />
618
- <Box
619
- as="div"
620
- style={{
621
- fontFamily: 'var(--font-mono)',
622
- fontVariantNumeric: 'tabular-nums',
623
- fontSize: 'var(--text-2xl)',
624
- fontWeight: 'var(--weight-semibold)',
625
- color: 'var(--text-primary)',
626
- }}
627
- >
628
- {overview.counts.agents}
629
- </Box>
630
- </Stack>
631
- </Box>
632
- </Panel>
633
-
634
- <Panel
635
- title="Tasks by status"
636
- description="Live snapshot of the kanban buckets"
637
- padding={3}
638
- data-testid="overview-panel-tasks-by-status"
639
- >
640
- <Box as="div" p={3}>
641
- <BarChart data={tasksByStatus} />
642
- </Box>
643
- </Panel>
644
-
645
- <Panel
646
- title="Memory"
647
- description="Vault, LightRAG, git sync"
648
- padding={3}
649
- data-testid="overview-panel-memory"
650
- >
651
- <Box as="div" p={3}>
652
- <MemoryStatusCard setActiveTab={setActiveTab} />
653
- </Box>
654
- </Panel>
655
-
656
- <Panel
657
- title="Active project"
658
- description={
659
- activeProject
660
- ? `${activeProject.path}`
661
- : 'No active project selected'
662
- }
663
- padding={3}
664
- data-testid="overview-panel-active-project"
665
- >
666
- {activeProject ? (
667
- <Box p={3}>
668
- <Stack gap={3}>
669
- <KeyValueList
670
- items={[
671
- {
672
- key: 'pname',
673
- label: 'Name',
674
- value: activeProject.name,
675
- mono: true,
676
- },
677
- {
678
- key: 'ppath',
679
- label: 'Path',
680
- value: truncateMiddle(activeProject.path, 48),
681
- mono: true,
682
- copyable: true,
683
- },
684
- {
685
- key: 'pstatus',
686
- label: 'Status',
687
- value: (
688
- <Badge
689
- variant={
690
- activeProject.status === 'active'
691
- ? 'success'
692
- : activeProject.status === 'error'
693
- ? 'danger'
694
- : 'neutral'
695
- }
696
- >
697
- <StatusDot
698
- variant={
699
- activeProject.status === 'active'
700
- ? 'success'
701
- : activeProject.status === 'error'
702
- ? 'danger'
703
- : 'neutral'
704
- }
705
- size="sm"
706
- pulse={activeProject.status === 'active'}
707
- />
708
- {activeProject.status}
709
- </Badge>
710
- ),
711
- },
712
- {
713
- key: 'pseen',
714
- label: 'Last opened',
715
- value: activeProject.lastAccessed
716
- ? formatRelative(activeProject.lastAccessed) ||
717
- '—'
718
- : '—',
719
- },
720
- ]}
721
- />
722
- <Inline gap={2} wrap>
723
- <UiButton
724
- variant="primary"
725
- size="sm"
726
- onClick={() => setActiveTab('tasks')}
727
- icon={<CheckSquare size={12} />}
728
- >
729
- Open tasks
730
- </UiButton>
731
- <UiButton
732
- variant="secondary"
733
- size="sm"
734
- onClick={onUseCurrentDir}
735
- icon={<Folder size={12} />}
736
- >
737
- Auto-detect
738
- </UiButton>
739
- </Inline>
740
- </Stack>
741
- </Box>
742
- ) : (
743
- <Box as="div" p={3}>
744
- <EmptyState
745
- title="No active project"
746
- description="Add one or auto-detect from the current directory."
747
- inline
748
- icon={<Folder size={20} />}
749
- />
750
- </Box>
751
- )}
752
- </Panel>
753
-
754
- <Panel
755
- title="Recent mods"
756
- description="Last few installed extensions"
757
- padding={3}
758
- data-testid="overview-panel-recent-mods"
759
- >
760
- {mods.length === 0 ? (
761
- <Box as="div" p={3}>
762
- <EmptyState
763
- title="No mods installed"
764
- description="Install from the Mods tab."
765
- inline
766
- icon={<Puzzle size={20} />}
767
- />
768
- </Box>
769
- ) : (
770
- <Box p={2}>
771
- <Stack gap={0}>
772
- {mods.slice(0, 6).map((m) => (
773
- <Box
774
- key={m.id}
775
- py={2}
776
- px={3}
777
- style={{
778
- borderTop: '1px solid var(--border-subtle)',
779
- }}
780
- >
781
- <Inline justify="between" align="center" gap={3}>
782
- <Stack gap={0} style={{ minWidth: 0 }}>
783
- <span
784
- style={{
785
- fontWeight: 'var(--weight-medium)',
786
- fontSize: 'var(--text-base)',
787
- }}
788
- >
789
- {m.name}
790
- </span>
791
- <span
792
- className="muted"
793
- style={{
794
- fontFamily: 'var(--font-mono)',
795
- fontSize: 'var(--text-xs)',
796
- color: 'var(--text-tertiary)',
797
- }}
798
- >
799
- v{m.version} · {m.type}
800
- </span>
801
- </Stack>
802
- <Badge
803
- variant={m.enabled ? 'success' : 'neutral'}
804
- size="sm"
805
- >
806
- <StatusDot
807
- variant={m.enabled ? 'success' : 'neutral'}
808
- size="sm"
809
- />
810
- {m.enabled ? 'on' : 'off'}
811
- </Badge>
812
- </Inline>
813
- </Box>
814
- ))}
815
- </Stack>
816
- </Box>
817
- )}
818
- </Panel>
819
- </Grid>
820
-
821
- {/* ─── Section 4: Activity stream ────────────────────────────── */}
822
- <Panel
823
- title="Recent activity"
824
- description={`${visibleActivity.length} item${visibleActivity.length === 1 ? '' : 's'} · live via SSE`}
825
- actions={
826
- <Inline gap={2} align="center">
827
- {hiddenKeys.size > 0 && (
828
- <UiButton
829
- variant="ghost"
830
- size="sm"
831
- onClick={onRestoreAll}
832
- icon={<Eye size={12} />}
833
- aria-label={`Restore ${hiddenKeys.size} hidden items`}
834
- >
835
- Restore ({hiddenKeys.size})
836
- </UiButton>
837
- )}
838
- {activityItems.length > 0 && (
839
- <UiButton
840
- variant="ghost"
841
- size="sm"
842
- onClick={onClearAll}
843
- icon={<EyeOff size={12} />}
844
- data-testid="overview-hide-all"
845
- aria-label="Hide all activity from overview"
846
- >
847
- Hide all
848
- </UiButton>
849
- )}
850
- </Inline>
851
- }
852
- padding={0}
853
- data-testid="overview-panel-activity"
854
- >
855
- {hiddenKeys.size > 0 && (
856
- <Box
857
- as="div"
858
- p={3}
859
- style={{
860
- background: 'var(--surface-2)',
861
- borderTop: '1px solid var(--border-subtle)',
862
- borderBottom: '1px solid var(--border-subtle)',
863
- display: 'flex',
864
- alignItems: 'center',
865
- justifyContent: 'space-between',
866
- gap: 'var(--space-3)',
867
- }}
868
- role="status"
869
- >
870
- <Inline gap={2} align="center">
871
- <EyeOff size={12} />
872
- <span style={{ fontSize: 'var(--text-sm)' }}>
873
- {hiddenKeys.size} item{hiddenKeys.size === 1 ? '' : 's'}{' '}
874
- hidden from the overview.
875
- </span>
876
- </Inline>
877
- <UiButton variant="ghost" size="sm" onClick={onRestoreAll}>
878
- <Eye size={12} /> Show them again
879
- </UiButton>
880
- </Box>
881
- )}
882
-
883
- {visibleActivity.length === 0 ? (
884
- <Box as="div" p={5}>
885
- <EmptyState
886
- title="No activity yet"
887
- description="Use the prompt below or invoke a Bizar command to start a feed."
888
- inline
889
- icon={<Activity size={20} />}
890
- />
891
- </Box>
892
- ) : (
893
- <Stack
894
- as="ul"
895
- gap={0}
896
- role="list"
897
- aria-live="polite"
898
- aria-relevant="additions"
899
- data-testid="overview-activity-list"
900
- >
901
- {visibleActivity.map(({ it, key }) => (
902
- <ActivityRow
903
- key={key}
904
- item={it}
905
- activityKey={key}
906
- onNavigate={setActiveTab}
907
- onHide={onHide}
908
- />
909
- ))}
910
- </Stack>
911
- )}
912
- </Panel>
913
-
914
- {/* ─── Section 5: Quick prompts ──────────────────────────────── */}
915
- <Panel
916
- title="What do you want to do?"
917
- description="Describe what you want — Odin will split it into tasks, delegate to background agents, and track progress in real time."
918
- padding={4}
919
- actions={
920
- <Badge variant="accent" size="sm">
921
- <Sparkles size={12} />
922
- <span style={{ marginLeft: 4 }}>Odin + 12 specialists</span>
923
- </Badge>
924
- }
925
- data-testid="overview-panel-prompts"
926
- >
927
- <form
928
- onSubmit={async (e) => {
929
- e.preventDefault();
930
- const text = (inputRef.current?.value || '').trim();
931
- if (!text) return;
932
- setSubmitting(true);
933
- try {
934
- const r = await api.post<{ subtasks?: unknown[] }>(
935
- '/tasks/submit',
936
- { title: text },
937
- );
938
- toast.success(
939
- `Odin split it into ${r.subtasks?.length || 1} task(s)`,
940
- );
941
- if (inputRef.current) inputRef.current.value = '';
942
- await refreshSnapshot();
943
- } catch (err) {
944
- toast.error(`Failed: ${(err as Error).message}`);
945
- } finally {
946
- setSubmitting(false);
947
- }
948
- }}
949
- >
950
- <Stack gap={3}>
951
- <Textarea
952
- ref={inputRef}
953
- disabled={submitting}
954
- aria-label="Describe what you want Odin to do"
955
- rows={4}
956
- placeholder="e.g. Implement user authentication with email + password, including registration, login, password reset, and integration tests. Use Bcrypt, JWT tokens, and the existing API style."
957
- data-testid="overview-prompt-input"
958
- />
959
- <Inline justify="between" align="center" gap={3} wrap>
960
- <Inline gap={2} wrap>
961
- {[
962
- 'Implement feature',
963
- 'Fix bug',
964
- 'Refactor',
965
- 'Investigate',
966
- 'Add tests',
967
- 'Document',
968
- 'Optimize',
969
- 'Deploy',
970
- ].map((action) => (
971
- <button
972
- key={action}
973
- type="button"
974
- className="overview-quick-chip"
975
- onClick={() => {
976
- if (inputRef.current) {
977
- inputRef.current.value = action;
978
- inputRef.current.focus();
979
- }
980
- }}
981
- >
982
- {action}
983
- </button>
984
- ))}
985
- </Inline>
986
- <UiButton
987
- type="submit"
988
- variant="primary"
989
- size="md"
990
- disabled={submitting}
991
- loading={submitting}
992
- icon={submitting ? undefined : <Send size={12} />}
993
- data-testid="overview-submit"
994
- >
995
- {submitting ? 'Submitting…' : 'Submit to Odin'}
996
- </UiButton>
997
- </Inline>
998
- </Stack>
999
- </form>
1000
- </Panel>
1001
- </Stack>
1002
- </Box>
1003
- );
1004
- }
1005
-
1006
- // ─── AddProjectDialog (legacy <Modal>) ──────────────────────────────────────
1007
-
1008
- function AddProjectDialog({
1009
- settings,
1010
- onAdd,
1011
- }: {
1012
- settings: Settings;
1013
- onAdd: (path: string, name: string | null) => void;
1014
- }) {
1015
- const [path, setPath] = useState<string>(
1016
- settings?.dashboard?.projectsDirectory ?? '',
1017
- );
1018
- const [name, setName] = useState<string>('');
1019
- const [preflighting, setPreflighting] = useState<boolean>(false);
1020
- const [preflightError, setPreflightError] = useState<string | null>(null);
1021
-
1022
- const handleAdd = async () => {
1023
- if (!path) return;
1024
- setPreflighting(true);
1025
- setPreflightError(null);
1026
- try {
1027
- await api.get<DirectoryListing>('/fs?path=' + encodeURIComponent(path));
1028
- onAdd(path, name || null);
1029
- } catch (err) {
1030
- const apiErr = err as { status?: number; data?: { message?: string } };
1031
- if (apiErr.status === 404) {
1032
- setPreflightError('That folder no longer exists. Pick another.');
1033
- } else {
1034
- setPreflightError(
1035
- apiErr.data?.message ??
1036
- (err as Error).message ??
1037
- 'Validation failed.',
1038
- );
1039
- }
1040
- } finally {
1041
- setPreflighting(false);
1042
- }
1043
- };
1044
-
1045
- return (
1046
- <div>
1047
- <label className="field-label">Folder</label>
1048
- <FileBrowser
1049
- value={path}
1050
- onChange={(p) => {
1051
- setPath(p);
1052
- setPreflightError(null);
1053
- }}
1054
- projectsDirectory={settings?.dashboard?.projectsDirectory}
1055
- height={320}
1056
- />
1057
- {preflightError && (
1058
- <p
1059
- className="field-help"
1060
- style={{ color: 'var(--error)', marginTop: 4 }}
1061
- >
1062
- {preflightError}
1063
- </p>
1064
- )}
1065
- <div style={{ marginTop: 'var(--space-3)' }}>
1066
- <label className="field-label" htmlFor="add-project-name">
1067
- Name (optional)
1068
- </label>
1069
- <input
1070
- id="add-project-name"
1071
- className="input"
1072
- type="text"
1073
- placeholder="My App"
1074
- value={name}
1075
- onChange={(e) => setName(e.target.value)}
1076
- />
1077
- <p className="field-help" style={{ marginTop: 4 }}>
1078
- Display name for this project. Defaults to the folder name.
1079
- </p>
1080
- </div>
1081
- <div
1082
- style={{
1083
- marginTop: 'var(--space-3)',
1084
- display: 'flex',
1085
- justifyContent: 'flex-end',
1086
- }}
1087
- >
1088
- <Button
1089
- variant="primary"
1090
- onClick={handleAdd}
1091
- disabled={!path || preflighting}
1092
- >
1093
- {preflighting ? <span className="btn-spinner" /> : null}
1094
- {preflighting ? 'Checking…' : 'Add'}
1095
- </Button>
1096
- </div>
1097
- </div>
1098
- );
1099
- }
1100
-
1101
- // ─── Activity row (the compact inline list item) ────────────────────────────
1102
-
1103
- function ActivityRow({
1104
- item,
1105
- activityKey,
1106
- onNavigate,
1107
- onHide,
1108
- }: {
1109
- item: ActivityItem;
1110
- activityKey: string;
1111
- onNavigate: (tab: string) => void;
1112
- onHide: (key: string) => void;
1113
- }) {
1114
- const severity = activitySeverity(item);
1115
- const Icon = activityIcon(item.kind || '');
1116
- const title = humanizeKind(item.kind || 'activity');
1117
- const msg = formatActivitySummary(item);
1118
- const navTarget = activityNavTarget(item.kind || '');
1119
-
1120
- return (
1121
- <li
1122
- className={`overview-activity-row overview-activity-row-${severity}`}
1123
- style={{
1124
- borderTop: '1px solid var(--border-subtle)',
1125
- display: 'flex',
1126
- alignItems: 'center',
1127
- gap: 'var(--space-3)',
1128
- paddingInline: 'var(--space-4)',
1129
- paddingBlock: 'var(--space-3)',
1130
- }}
1131
- >
1132
- <button
1133
- type="button"
1134
- onClick={() => {
1135
- if (navTarget) onNavigate(navTarget);
1136
- }}
1137
- className="overview-activity-row__main"
1138
- title={navTarget ? `Open ${navTarget}` : title}
1139
- style={{
1140
- flex: 1,
1141
- display: 'flex',
1142
- alignItems: 'center',
1143
- gap: 'var(--space-3)',
1144
- textAlign: 'left',
1145
- background: 'transparent',
1146
- color: 'inherit',
1147
- padding: 0,
1148
- }}
1149
- >
1150
- <span
1151
- style={{
1152
- color:
1153
- severity === 'error'
1154
- ? 'var(--danger)'
1155
- : severity === 'warning'
1156
- ? 'var(--warning)'
1157
- : severity === 'success'
1158
- ? 'var(--success)'
1159
- : 'var(--accent)',
1160
- display: 'inline-flex',
1161
- alignItems: 'center',
1162
- justifyContent: 'center',
1163
- width: 22,
1164
- height: 22,
1165
- flexShrink: 0,
1166
- }}
1167
- >
1168
- <Icon size={14} />
1169
- </span>
1170
- <Stack gap={0} style={{ minWidth: 0, flex: 1 }}>
1171
- <Inline justify="between" align="center" gap={3} wrap>
1172
- <span
1173
- style={{
1174
- fontSize: 'var(--text-sm)',
1175
- fontWeight: 'var(--weight-medium)',
1176
- }}
1177
- >
1178
- {title}
1179
- </span>
1180
- <span
1181
- style={{
1182
- fontFamily: 'var(--font-mono)',
1183
- fontVariantNumeric: 'tabular-nums',
1184
- fontSize: 'var(--text-xs)',
1185
- color: 'var(--text-tertiary)',
1186
- }}
1187
- >
1188
- {formatClock(item.ts)}
1189
- </span>
1190
- </Inline>
1191
- <span
1192
- className="muted"
1193
- style={{
1194
- fontSize: 'var(--text-sm)',
1195
- color: 'var(--text-secondary)',
1196
- overflow: 'hidden',
1197
- textOverflow: 'ellipsis',
1198
- whiteSpace: 'nowrap',
1199
- display: 'block',
1200
- }}
1201
- title={msg}
1202
- >
1203
- {msg}
1204
- </span>
1205
- </Stack>
1206
- </button>
1207
- <IconButton
1208
- variant="ghost"
1209
- size="sm"
1210
- onClick={() => onHide(activityKey)}
1211
- aria-label="Hide from overview"
1212
- title="Hide from overview (kept in Settings → Activity Log)"
1213
- icon={<X size={12} />}
1214
- />
1215
- </li>
1216
- );
1217
- }
1218
-
1219
- // ─── Helpers ────────────────────────────────────────────────────────────────
1220
-
1221
- function sentenceCase(s: string): string {
1222
- if (!s) return s;
1223
- return s.charAt(0).toUpperCase() + s.slice(1);
1224
- }
1225
-
1226
- function humanizeKind(kind: string): string {
1227
- const normalized = (kind || 'activity').trim().toLowerCase().replace(/[:_]/g, '.');
1228
- const [scopeRaw, actionRaw = 'updated'] = normalized.split('.');
1229
- const scopeMap: Record<string, string> = {
1230
- settings: 'Settings',
1231
- task: 'Task',
1232
- tasks: 'Task',
1233
- agent: 'Agent',
1234
- agents: 'Agent',
1235
- plan: 'Plan',
1236
- plans: 'Plan',
1237
- bg: 'Background job',
1238
- background: 'Background job',
1239
- session: 'Session',
1240
- mod: 'Mod',
1241
- mods: 'Mod',
1242
- provider: 'Provider',
1243
- providers: 'Provider',
1244
- };
1245
- const actionMap: Record<string, string> = {
1246
- create: 'created',
1247
- created: 'created',
1248
- add: 'added',
1249
- added: 'added',
1250
- update: 'updated',
1251
- updated: 'updated',
1252
- delegate: 'delegated',
1253
- delegated: 'delegated',
1254
- invoke: 'invoked',
1255
- invoked: 'invoked',
1256
- restart: 'restarted',
1257
- restarted: 'restarted',
1258
- delete: 'deleted',
1259
- deleted: 'deleted',
1260
- remove: 'removed',
1261
- removed: 'removed',
1262
- archive: 'archived',
1263
- archived: 'archived',
1264
- restore: 'restored',
1265
- restored: 'restored',
1266
- complete: 'completed',
1267
- completed: 'completed',
1268
- fail: 'failed',
1269
- failed: 'failed',
1270
- error: 'errored',
1271
- stuck: 'marked stuck',
1272
- };
1273
- const scope = scopeMap[scopeRaw] || sentenceCase(scopeRaw.replace(/-/g, ' '));
1274
- const action = actionMap[actionRaw] || actionRaw.replace(/-/g, ' ');
1275
- return `${scope} ${action}`.trim();
1276
- }
1277
-
1278
- function firstString(it: ActivityItem, keys: string[]): string {
1279
- for (const key of keys) {
1280
- const value = it[key];
1281
- if (typeof value === 'string' && value.trim()) return value.trim();
1282
- }
1283
- return '';
1284
- }
1285
-
1286
- function formatActivitySummary(it: ActivityItem): string {
1287
- const direct = firstString(it, ['message', 'text', 'prompt', 'title', 'name']);
1288
- if (direct) return direct;
1289
- const parts: string[] = [];
1290
- const slug = firstString(it, ['slug']);
1291
- const agent = firstString(it, ['agent', 'author']);
1292
- const status = firstString(it, ['status']);
1293
- if (slug) parts.push(`Plan ${slug}`);
1294
- if (agent) parts.push(agent);
1295
- if (status) parts.push(status);
1296
- return parts.length ? parts.join(' · ') : 'No additional details.';
1297
- }
1298
-
1299
- function activitySeverity(it: ActivityItem): 'error' | 'warning' | 'success' | 'info' {
1300
- const k = ((it.kind as string) || '').toLowerCase();
1301
- const s = ((it.status as string) || '').toLowerCase();
1302
- if (k.includes('error') || s === 'error' || s === 'failure') return 'error';
1303
- if (k.includes('warn') || s === 'blocked') return 'warning';
1304
- if (k.includes('done') || k.includes('success') || s === 'done') return 'success';
1305
- return 'info';
1306
- }
1307
-
1308
- function activityIcon(kind: string) {
1309
- const k = kind.toLowerCase();
1310
- if (k === 'task') return CheckSquare;
1311
- if (k === 'agent') return Bot;
1312
- if (k === 'plan') return Map;
1313
- if (k.includes('bg') || k.includes('background') || k.includes('job')) return Zap;
1314
- if (k === 'mod') return Puzzle;
1315
- if (k === 'skill') return Sparkles;
1316
- if (k.includes('error') || k.includes('failure')) return AlertOctagon;
1317
- if (k.includes('warn')) return AlertTriangle;
1318
- return Activity;
1319
- }
1320
-
1321
- function activityNavTarget(kind: string): string | null {
1322
- const k = kind.toLowerCase();
1323
- if (k === 'task') return 'tasks';
1324
- if (k === 'agent') return 'agents';
1325
- if (k === 'plan') return 'artifacts';
1326
- if (k.includes('bg') || k.includes('background')) return 'activity';
1327
- if (k === 'mod') return 'mods';
1328
- if (k === 'skill') return 'skills';
1329
- return null;
1330
- }
1331
-
1332
- function formatClock(ts: string): string {
1333
- return formatRelative(ts);
1334
- }
1335
-
1336
- function truncateMiddle(s: string, maxLen: number): string {
1337
- if (!s || s.length <= maxLen) return s;
1338
- const half = Math.floor((maxLen - 1) / 2);
1339
- return `${s.slice(0, half)}…${s.slice(-half)}`;
1340
- }
1341
-
1342
- const OverviewMemo = React.memo(OverviewInner);
1343
- export { OverviewMemo as Overview };