@polderlabs/bizar 7.0.2 → 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 (490) 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 -0
  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/settings-layout.test.tsx +2 -2
  196. package/bizar-dash/tests/settings-nav.test.tsx +6 -6
  197. package/bizar-dash/tests/setup.ts +26 -0
  198. package/bizar-dash/vite.config.ts +26 -2
  199. package/bizar-dash/vitest.config.ts +5 -3
  200. package/cli/provision-claude.mjs +108 -5
  201. package/package.json +36 -3
  202. package/bizar-dash/dist/assets/EnvVarsSection-BfhAz3ax.js +0 -114
  203. package/bizar-dash/dist/assets/EnvVarsSection-BfhAz3ax.js.map +0 -1
  204. package/bizar-dash/dist/assets/MobileChat-DLWdv6tQ.js +0 -1
  205. package/bizar-dash/dist/assets/MobileChat-DLWdv6tQ.js.map +0 -1
  206. package/bizar-dash/dist/assets/MobileSettings-Bxv62uPY.js +0 -1
  207. package/bizar-dash/dist/assets/MobileSettings-Bxv62uPY.js.map +0 -1
  208. package/bizar-dash/dist/assets/Toast-ATSAmbdi.js +0 -26
  209. package/bizar-dash/dist/assets/Toast-ATSAmbdi.js.map +0 -1
  210. package/bizar-dash/dist/assets/__vite-browser-external-BIHI7g3E.js +0 -1
  211. package/bizar-dash/dist/assets/__vite-browser-external-BIHI7g3E.js.map +0 -1
  212. package/bizar-dash/dist/assets/main-306CZfn6.js +0 -430
  213. package/bizar-dash/dist/assets/main-306CZfn6.js.map +0 -1
  214. package/bizar-dash/dist/assets/main-G3bNDpY3.css +0 -1
  215. package/bizar-dash/dist/assets/mobile-C_naUN91.js +0 -1
  216. package/bizar-dash/dist/assets/mobile-C_naUN91.js.map +0 -1
  217. package/bizar-dash/dist/assets/mobile-layout-BWLtwtfQ.css +0 -1
  218. package/bizar-dash/dist/assets/mobile-layout-GZ3bE8L6.js +0 -211
  219. package/bizar-dash/dist/assets/mobile-layout-GZ3bE8L6.js.map +0 -1
  220. package/bizar-dash/dist/assets/useSlashCommands-BOwD7lNb.js +0 -65
  221. package/bizar-dash/dist/assets/useSlashCommands-BOwD7lNb.js.map +0 -1
  222. package/bizar-dash/dist/index.html +0 -43
  223. package/bizar-dash/src/web/App.tsx +0 -915
  224. package/bizar-dash/src/web/MobileApp.tsx +0 -414
  225. package/bizar-dash/src/web/components/ArtifactCreateDialog.tsx +0 -95
  226. package/bizar-dash/src/web/components/ArtifactListDialog.tsx +0 -55
  227. package/bizar-dash/src/web/components/ArtifactViewer.tsx +0 -144
  228. package/bizar-dash/src/web/components/AuditDialog.tsx +0 -79
  229. package/bizar-dash/src/web/components/AutosaveField.tsx +0 -50
  230. package/bizar-dash/src/web/components/BackupRestore.tsx +0 -330
  231. package/bizar-dash/src/web/components/BgStatusBadge.tsx +0 -32
  232. package/bizar-dash/src/web/components/Button.tsx +0 -56
  233. package/bizar-dash/src/web/components/CanvasContextMenu.tsx +0 -68
  234. package/bizar-dash/src/web/components/Card.tsx +0 -40
  235. package/bizar-dash/src/web/components/CollapsibleSection.tsx +0 -72
  236. package/bizar-dash/src/web/components/CommandDialog.tsx +0 -66
  237. package/bizar-dash/src/web/components/DoctorPanel.tsx +0 -160
  238. package/bizar-dash/src/web/components/EmptyState.tsx +0 -30
  239. package/bizar-dash/src/web/components/EnvVarManager.tsx +0 -430
  240. package/bizar-dash/src/web/components/EvalDiff.tsx +0 -157
  241. package/bizar-dash/src/web/components/EvalExportButton.tsx +0 -27
  242. package/bizar-dash/src/web/components/EvalRunCard.tsx +0 -78
  243. package/bizar-dash/src/web/components/FileBrowser.tsx +0 -633
  244. package/bizar-dash/src/web/components/HeadroomSettings.tsx +0 -418
  245. package/bizar-dash/src/web/components/HeadroomStatus.tsx +0 -158
  246. package/bizar-dash/src/web/components/HelpDialog.tsx +0 -55
  247. package/bizar-dash/src/web/components/InviteDialog.tsx +0 -205
  248. package/bizar-dash/src/web/components/KillConfirmDialog.tsx +0 -88
  249. package/bizar-dash/src/web/components/MobileBottomNav.tsx +0 -38
  250. package/bizar-dash/src/web/components/MobileDrawer.tsx +0 -68
  251. package/bizar-dash/src/web/components/MobileHeader.tsx +0 -50
  252. package/bizar-dash/src/web/components/MobileLayout.tsx +0 -63
  253. package/bizar-dash/src/web/components/Modal.tsx +0 -215
  254. package/bizar-dash/src/web/components/Notifications.tsx +0 -242
  255. package/bizar-dash/src/web/components/ScheduleTemplateCard.tsx +0 -72
  256. package/bizar-dash/src/web/components/ScreenshotCapture.tsx +0 -138
  257. package/bizar-dash/src/web/components/ScreenshotOCR.tsx +0 -42
  258. package/bizar-dash/src/web/components/SearchModal.tsx +0 -227
  259. package/bizar-dash/src/web/components/SettingsNav.tsx +0 -112
  260. package/bizar-dash/src/web/components/SettingsSearch.tsx +0 -328
  261. package/bizar-dash/src/web/components/Sidebar.tsx +0 -89
  262. package/bizar-dash/src/web/components/Spinner.tsx +0 -19
  263. package/bizar-dash/src/web/components/StatusBadge.tsx +0 -56
  264. package/bizar-dash/src/web/components/Tag.tsx +0 -41
  265. package/bizar-dash/src/web/components/TailscaleSettings.tsx +0 -161
  266. package/bizar-dash/src/web/components/TaskCard.tsx +0 -69
  267. package/bizar-dash/src/web/components/TaskCreateSheet.tsx +0 -76
  268. package/bizar-dash/src/web/components/Toast.tsx +0 -150
  269. package/bizar-dash/src/web/components/Toggle.tsx +0 -31
  270. package/bizar-dash/src/web/components/Topbar.tsx +0 -410
  271. package/bizar-dash/src/web/components/UsageChart.tsx +0 -250
  272. package/bizar-dash/src/web/components/UsageTable.tsx +0 -90
  273. package/bizar-dash/src/web/components/VirtualList.tsx +0 -53
  274. package/bizar-dash/src/web/components/VisualPlanDialog.tsx +0 -58
  275. package/bizar-dash/src/web/components/VoiceNotesPanel.tsx +0 -211
  276. package/bizar-dash/src/web/components/VoiceRecorder.tsx +0 -105
  277. package/bizar-dash/src/web/components/WorkspaceSelector.tsx +0 -158
  278. package/bizar-dash/src/web/components/agents/CommunicationLog.tsx +0 -126
  279. package/bizar-dash/src/web/components/agents/DependencyGraph.tsx +0 -163
  280. package/bizar-dash/src/web/components/agents/QualityGates.tsx +0 -123
  281. package/bizar-dash/src/web/components/agents/RealTimeEventLog.tsx +0 -127
  282. package/bizar-dash/src/web/components/agents/RoutingDecisions.test.tsx +0 -148
  283. package/bizar-dash/src/web/components/agents/RoutingDecisions.tsx +0 -160
  284. package/bizar-dash/src/web/components/background/AttachButton.tsx +0 -96
  285. package/bizar-dash/src/web/components/background/TmuxAttachCard.tsx +0 -122
  286. package/bizar-dash/src/web/components/chat/AgentChip.tsx +0 -68
  287. package/bizar-dash/src/web/components/chat/AgentNode.tsx +0 -127
  288. package/bizar-dash/src/web/components/chat/AgentTree.tsx +0 -80
  289. package/bizar-dash/src/web/components/chat/ChatBubble.tsx +0 -60
  290. package/bizar-dash/src/web/components/chat/ChatComposer.tsx +0 -72
  291. package/bizar-dash/src/web/components/chat/ChatInfoPanel.tsx +0 -370
  292. package/bizar-dash/src/web/components/chat/ChatRail.tsx +0 -387
  293. package/bizar-dash/src/web/components/chat/ChatThread.tsx +0 -127
  294. package/bizar-dash/src/web/components/chat/ChatTopBar.tsx +0 -50
  295. package/bizar-dash/src/web/components/chat/Composer.tsx +0 -166
  296. package/bizar-dash/src/web/components/chat/ConfirmModal.tsx +0 -54
  297. package/bizar-dash/src/web/components/chat/EmptyState.tsx +0 -21
  298. package/bizar-dash/src/web/components/chat/FirstRunGreeting.tsx +0 -18
  299. package/bizar-dash/src/web/components/chat/FloatingComposer.tsx +0 -38
  300. package/bizar-dash/src/web/components/chat/InfoPanel.tsx +0 -184
  301. package/bizar-dash/src/web/components/chat/JumpToLatest.tsx +0 -58
  302. package/bizar-dash/src/web/components/chat/LoadingSkeleton.tsx +0 -19
  303. package/bizar-dash/src/web/components/chat/MessageBlock.tsx +0 -260
  304. package/bizar-dash/src/web/components/chat/MessageBubble.tsx +0 -60
  305. package/bizar-dash/src/web/components/chat/SessionList.tsx +0 -163
  306. package/bizar-dash/src/web/components/chat/SessionRowMenu.tsx +0 -206
  307. package/bizar-dash/src/web/components/chat/StreamingIndicator.tsx +0 -37
  308. package/bizar-dash/src/web/components/chat/SuggestionCards.tsx +0 -55
  309. package/bizar-dash/src/web/components/chat/WelcomeScreen.tsx +0 -36
  310. package/bizar-dash/src/web/components/chat/_legacy.ts +0 -30
  311. package/bizar-dash/src/web/components/chat/index.ts +0 -31
  312. package/bizar-dash/src/web/components/chat/useAutoGrowTextarea.ts +0 -18
  313. package/bizar-dash/src/web/components/chat/useChat.ts +0 -1190
  314. package/bizar-dash/src/web/components/chat/useSlashCommands.ts +0 -47
  315. package/bizar-dash/src/web/components/goals/GoalInput.tsx +0 -86
  316. package/bizar-dash/src/web/components/goals/PlanVisualization.tsx +0 -111
  317. package/bizar-dash/src/web/components/tasks/BacklogPanel.css +0 -109
  318. package/bizar-dash/src/web/components/tasks/BacklogPanel.tsx +0 -209
  319. package/bizar-dash/src/web/hooks/useAutosave.ts +0 -107
  320. package/bizar-dash/src/web/hooks/useI18n.ts +0 -13
  321. package/bizar-dash/src/web/index.html +0 -37
  322. package/bizar-dash/src/web/lib/api.ts +0 -237
  323. package/bizar-dash/src/web/lib/goapPlanner.ts +0 -614
  324. package/bizar-dash/src/web/lib/i18n.ts +0 -25
  325. package/bizar-dash/src/web/lib/logger.ts +0 -30
  326. package/bizar-dash/src/web/lib/markdown.tsx +0 -59
  327. package/bizar-dash/src/web/lib/search.ts +0 -115
  328. package/bizar-dash/src/web/lib/types.ts +0 -894
  329. package/bizar-dash/src/web/lib/utils.ts +0 -114
  330. package/bizar-dash/src/web/lib/ws.ts +0 -177
  331. package/bizar-dash/src/web/locales/en.json +0 -52
  332. package/bizar-dash/src/web/main.tsx +0 -43
  333. package/bizar-dash/src/web/mobile/MobileApp.tsx +0 -309
  334. package/bizar-dash/src/web/mobile/MobileBottomNav.tsx +0 -38
  335. package/bizar-dash/src/web/mobile/MobileChat.tsx +0 -138
  336. package/bizar-dash/src/web/mobile/MobileDoctor.tsx +0 -80
  337. package/bizar-dash/src/web/mobile/MobileEval.tsx +0 -167
  338. package/bizar-dash/src/web/mobile/MobileMemory.tsx +0 -108
  339. package/bizar-dash/src/web/mobile/MobileOverview.tsx +0 -213
  340. package/bizar-dash/src/web/mobile/MobileSettings.tsx +0 -251
  341. package/bizar-dash/src/web/mobile/MobileTasks.tsx +0 -94
  342. package/bizar-dash/src/web/mobile/MobileTopbar.tsx +0 -115
  343. package/bizar-dash/src/web/mobile/components/MobileBottomSheet.tsx +0 -182
  344. package/bizar-dash/src/web/mobile/components/MobileListItem.tsx +0 -64
  345. package/bizar-dash/src/web/mobile/components/MobileModal.tsx +0 -123
  346. package/bizar-dash/src/web/mobile/views/MobileActivity.tsx +0 -273
  347. package/bizar-dash/src/web/mobile/views/MobileAgents.tsx +0 -374
  348. package/bizar-dash/src/web/mobile/views/MobileArtifactCanvas.tsx +0 -439
  349. package/bizar-dash/src/web/mobile/views/MobileArtifacts.tsx +0 -143
  350. package/bizar-dash/src/web/mobile/views/MobileChat.tsx +0 -257
  351. package/bizar-dash/src/web/mobile/views/MobileConfig.tsx +0 -175
  352. package/bizar-dash/src/web/mobile/views/MobileHistory.tsx +0 -191
  353. package/bizar-dash/src/web/mobile/views/MobileMods.tsx +0 -149
  354. package/bizar-dash/src/web/mobile/views/MobileMore.tsx +0 -121
  355. package/bizar-dash/src/web/mobile/views/MobileNotifications.tsx +0 -137
  356. package/bizar-dash/src/web/mobile/views/MobilePlans.tsx +0 -26
  357. package/bizar-dash/src/web/mobile/views/MobileSchedules.tsx +0 -685
  358. package/bizar-dash/src/web/mobile/views/MobileSearchModal.tsx +0 -172
  359. package/bizar-dash/src/web/mobile/views/MobileSettings.tsx +0 -363
  360. package/bizar-dash/src/web/mobile/views/MobileSkills.tsx +0 -153
  361. package/bizar-dash/src/web/mobile/views/MobileTasks.tsx +0 -564
  362. package/bizar-dash/src/web/mobile/views/QrCodePanel.tsx +0 -69
  363. package/bizar-dash/src/web/mobile.tsx +0 -14
  364. package/bizar-dash/src/web/styles/agents-redesign.css +0 -311
  365. package/bizar-dash/src/web/styles/chat.css +0 -1740
  366. package/bizar-dash/src/web/styles/glyphs.css +0 -960
  367. package/bizar-dash/src/web/styles/main.css +0 -10391
  368. package/bizar-dash/src/web/styles/memory.css +0 -1182
  369. package/bizar-dash/src/web/styles/minimax-usage.css +0 -842
  370. package/bizar-dash/src/web/styles/mobile-chat.css +0 -5
  371. package/bizar-dash/src/web/styles/mobile-layout.css +0 -233
  372. package/bizar-dash/src/web/styles/mobile.css +0 -2181
  373. package/bizar-dash/src/web/styles/settings.css +0 -795
  374. package/bizar-dash/src/web/styles/skills.css +0 -302
  375. package/bizar-dash/src/web/styles/tasks-redesign.css +0 -253
  376. package/bizar-dash/src/web/styles/tasks.css +0 -605
  377. package/bizar-dash/src/web/ui/controls/Button.tsx +0 -77
  378. package/bizar-dash/src/web/ui/controls/Checkbox.tsx +0 -95
  379. package/bizar-dash/src/web/ui/controls/IconButton.tsx +0 -66
  380. package/bizar-dash/src/web/ui/controls/Kbd.tsx +0 -24
  381. package/bizar-dash/src/web/ui/controls/NumberInput.tsx +0 -77
  382. package/bizar-dash/src/web/ui/controls/RadioGroup.tsx +0 -109
  383. package/bizar-dash/src/web/ui/controls/SearchInput.tsx +0 -91
  384. package/bizar-dash/src/web/ui/controls/Select.tsx +0 -92
  385. package/bizar-dash/src/web/ui/controls/Slider.tsx +0 -70
  386. package/bizar-dash/src/web/ui/controls/TextInput.tsx +0 -67
  387. package/bizar-dash/src/web/ui/controls/Textarea.tsx +0 -56
  388. package/bizar-dash/src/web/ui/controls/Toggle.tsx +0 -79
  389. package/bizar-dash/src/web/ui/controls/controls.css +0 -476
  390. package/bizar-dash/src/web/ui/controls/index.ts +0 -35
  391. package/bizar-dash/src/web/ui/data/BarChart.tsx +0 -60
  392. package/bizar-dash/src/web/ui/data/DataTable.tsx +0 -216
  393. package/bizar-dash/src/web/ui/data/EmptyState.tsx +0 -60
  394. package/bizar-dash/src/web/ui/data/ErrorState.tsx +0 -56
  395. package/bizar-dash/src/web/ui/data/KeyValueList.tsx +0 -106
  396. package/bizar-dash/src/web/ui/data/LoadingState.tsx +0 -65
  397. package/bizar-dash/src/web/ui/data/Sparkline.tsx +0 -87
  398. package/bizar-dash/src/web/ui/data/StatTile.tsx +0 -87
  399. package/bizar-dash/src/web/ui/data/data.css +0 -535
  400. package/bizar-dash/src/web/ui/data/index.ts +0 -31
  401. package/bizar-dash/src/web/ui/feedback/Badge.tsx +0 -49
  402. package/bizar-dash/src/web/ui/feedback/Dialog.tsx +0 -209
  403. package/bizar-dash/src/web/ui/feedback/ProgressBar.tsx +0 -69
  404. package/bizar-dash/src/web/ui/feedback/StatusDot.tsx +0 -50
  405. package/bizar-dash/src/web/ui/feedback/Toast.tsx +0 -200
  406. package/bizar-dash/src/web/ui/feedback/Tooltip.tsx +0 -126
  407. package/bizar-dash/src/web/ui/feedback/feedback.css +0 -314
  408. package/bizar-dash/src/web/ui/feedback/index.ts +0 -43
  409. package/bizar-dash/src/web/ui/index.ts +0 -56
  410. package/bizar-dash/src/web/ui/layout/AppShell.tsx +0 -51
  411. package/bizar-dash/src/web/ui/layout/Breadcrumbs.tsx +0 -97
  412. package/bizar-dash/src/web/ui/layout/Panel.tsx +0 -73
  413. package/bizar-dash/src/web/ui/layout/PanelHeader.tsx +0 -39
  414. package/bizar-dash/src/web/ui/layout/Sidebar.tsx +0 -131
  415. package/bizar-dash/src/web/ui/layout/Tabs.tsx +0 -133
  416. package/bizar-dash/src/web/ui/layout/Topbar.tsx +0 -42
  417. package/bizar-dash/src/web/ui/layout/ViewHeader.tsx +0 -48
  418. package/bizar-dash/src/web/ui/layout/index.ts +0 -34
  419. package/bizar-dash/src/web/ui/layout/layout.css +0 -464
  420. package/bizar-dash/src/web/ui/navigation/CommandPalette.tsx +0 -199
  421. package/bizar-dash/src/web/ui/navigation/NavGroup.tsx +0 -95
  422. package/bizar-dash/src/web/ui/navigation/NavLink.tsx +0 -93
  423. package/bizar-dash/src/web/ui/navigation/index.ts +0 -17
  424. package/bizar-dash/src/web/ui/navigation/navigation.css +0 -343
  425. package/bizar-dash/src/web/ui/primitives/Box.tsx +0 -91
  426. package/bizar-dash/src/web/ui/primitives/Grid.tsx +0 -49
  427. package/bizar-dash/src/web/ui/primitives/Inline.tsx +0 -55
  428. package/bizar-dash/src/web/ui/primitives/Separator.tsx +0 -46
  429. package/bizar-dash/src/web/ui/primitives/Stack.tsx +0 -54
  430. package/bizar-dash/src/web/ui/primitives/VisuallyHidden.tsx +0 -26
  431. package/bizar-dash/src/web/ui/primitives/index.ts +0 -23
  432. package/bizar-dash/src/web/ui/primitives/primitives.css +0 -183
  433. package/bizar-dash/src/web/ui/styles/globals.css +0 -86
  434. package/bizar-dash/src/web/ui/styles/reset.css +0 -125
  435. package/bizar-dash/src/web/ui/styles/tokens.css +0 -208
  436. package/bizar-dash/src/web/ui/theme/ThemeProvider.tsx +0 -142
  437. package/bizar-dash/src/web/ui/theme/tokens.ts +0 -131
  438. package/bizar-dash/src/web/ui/theme/useTheme.ts +0 -22
  439. package/bizar-dash/src/web/ui/utils/cx.ts +0 -42
  440. package/bizar-dash/src/web/views/Activity.tsx +0 -1221
  441. package/bizar-dash/src/web/views/Agents.tsx +0 -964
  442. package/bizar-dash/src/web/views/Artifacts.tsx +0 -1494
  443. package/bizar-dash/src/web/views/BackgroundAgents.tsx +0 -822
  444. package/bizar-dash/src/web/views/Chat.tsx +0 -532
  445. package/bizar-dash/src/web/views/Config.tsx +0 -3
  446. package/bizar-dash/src/web/views/Doctor.tsx +0 -317
  447. package/bizar-dash/src/web/views/Eval.tsx +0 -372
  448. package/bizar-dash/src/web/views/EvalReport.tsx +0 -353
  449. package/bizar-dash/src/web/views/GoalPlanner.tsx +0 -158
  450. package/bizar-dash/src/web/views/Harness.tsx +0 -306
  451. package/bizar-dash/src/web/views/History.tsx +0 -353
  452. package/bizar-dash/src/web/views/Memory.tsx +0 -161
  453. package/bizar-dash/src/web/views/MiniMaxUsage.tsx +0 -942
  454. package/bizar-dash/src/web/views/ModView.tsx +0 -207
  455. package/bizar-dash/src/web/views/Mods.tsx +0 -706
  456. package/bizar-dash/src/web/views/Overview.tsx +0 -1364
  457. package/bizar-dash/src/web/views/Providers.tsx +0 -302
  458. package/bizar-dash/src/web/views/Schedules.tsx +0 -902
  459. package/bizar-dash/src/web/views/Settings.tsx +0 -308
  460. package/bizar-dash/src/web/views/Skills.tsx +0 -383
  461. package/bizar-dash/src/web/views/SpawnAgentModal.tsx +0 -221
  462. package/bizar-dash/src/web/views/Tasks.tsx +0 -789
  463. package/bizar-dash/src/web/views/Workspace.tsx +0 -294
  464. package/bizar-dash/src/web/views/glyphs/GlyphRenderer.tsx +0 -844
  465. package/bizar-dash/src/web/views/glyphs/components.tsx +0 -1098
  466. package/bizar-dash/src/web/views/memory/ConfigPanel.tsx +0 -426
  467. package/bizar-dash/src/web/views/memory/FromScreenshotPanel.tsx +0 -23
  468. package/bizar-dash/src/web/views/memory/GitSyncPanel.tsx +0 -220
  469. package/bizar-dash/src/web/views/memory/LightragPanel.tsx +0 -310
  470. package/bizar-dash/src/web/views/memory/MemoryGraphLegend.tsx +0 -29
  471. package/bizar-dash/src/web/views/memory/MemoryGraphPanel.tsx +0 -192
  472. package/bizar-dash/src/web/views/memory/MemoryGraphView.tsx +0 -336
  473. package/bizar-dash/src/web/views/memory/MemoryOverview.tsx +0 -367
  474. package/bizar-dash/src/web/views/memory/MemoryStatusCard.tsx +0 -160
  475. package/bizar-dash/src/web/views/memory/ObsidianPanel.tsx +0 -650
  476. package/bizar-dash/src/web/views/memory/SemanticSearchPanel.tsx +0 -197
  477. package/bizar-dash/src/web/views/memory/VaultFromClipboardPanel.tsx +0 -101
  478. package/bizar-dash/src/web/views/settings/ActivitySection.tsx +0 -205
  479. package/bizar-dash/src/web/views/settings/AgentSection.tsx +0 -305
  480. package/bizar-dash/src/web/views/settings/AuthSection.tsx +0 -159
  481. package/bizar-dash/src/web/views/settings/EnvVarsSection.tsx +0 -15
  482. package/bizar-dash/src/web/views/settings/GeneralSection.tsx +0 -128
  483. package/bizar-dash/src/web/views/settings/HeadroomSection.tsx +0 -39
  484. package/bizar-dash/src/web/views/settings/MemorySection.tsx +0 -154
  485. package/bizar-dash/src/web/views/settings/NetworkSection.tsx +0 -87
  486. package/bizar-dash/src/web/views/settings/NotificationsSection.tsx +0 -34
  487. package/bizar-dash/src/web/views/settings/SystemLlmSection.tsx +0 -81
  488. package/bizar-dash/src/web/views/settings/ThemeSection.tsx +0 -168
  489. package/bizar-dash/src/web/views/settings/UpdatesSection.tsx +0 -256
  490. package/bizar-dash/src/web/views/settings/WorkspacesSection.tsx +0 -189
@@ -0,0 +1,86 @@
1
+ import { describe, expect, it, beforeEach } from 'vitest';
2
+ import { act, render, screen } from '@testing-library/react';
3
+ import { ThemeProvider } from './ThemeProvider.js';
4
+ import { useTheme } from './useTheme.js';
5
+
6
+ /**
7
+ * ThemeProvider tests — verifies mode cycling, localStorage persistence,
8
+ * and the `data-theme` attribute on <html>.
9
+ *
10
+ * The test harness's matchMedia stub returns `matches: false`, so the
11
+ * 'system' mode always resolves to 'light'. Tests pin the starting mode
12
+ * via the `defaultMode` prop to avoid that ambiguity.
13
+ */
14
+
15
+ function Probe(): JSX.Element {
16
+ const { mode, resolved, setMode, cycle } = useTheme();
17
+ return (
18
+ <div>
19
+ <span data-testid="mode">{mode}</span>
20
+ <span data-testid="resolved">{resolved}</span>
21
+ <button type="button" onClick={() => setMode('dark')}>set-dark</button>
22
+ <button type="button" onClick={cycle}>cycle</button>
23
+ </div>
24
+ );
25
+ }
26
+
27
+ beforeEach(() => {
28
+ window.localStorage.clear();
29
+ document.documentElement.dataset['theme'] = '';
30
+ });
31
+
32
+ describe('ThemeProvider', () => {
33
+ it('resolves forced light to light and stamps data-theme on <html>', () => {
34
+ render(
35
+ <ThemeProvider defaultMode="light">
36
+ <Probe />
37
+ </ThemeProvider>,
38
+ );
39
+ expect(screen.getByTestId('mode').textContent).toBe('light');
40
+ expect(screen.getByTestId('resolved').textContent).toBe('light');
41
+ expect(document.documentElement.dataset['theme']).toBe('light');
42
+ });
43
+
44
+ it('resolves forced dark to dark and stamps data-theme on <html>', () => {
45
+ render(
46
+ <ThemeProvider defaultMode="dark">
47
+ <Probe />
48
+ </ThemeProvider>,
49
+ );
50
+ expect(screen.getByTestId('resolved').textContent).toBe('dark');
51
+ expect(document.documentElement.dataset['theme']).toBe('dark');
52
+ });
53
+
54
+ it('setMode persists to localStorage and updates the attribute', () => {
55
+ render(
56
+ <ThemeProvider defaultMode="light">
57
+ <Probe />
58
+ </ThemeProvider>,
59
+ );
60
+ act(() => {
61
+ screen.getByText('set-dark').click();
62
+ });
63
+ expect(screen.getByTestId('mode').textContent).toBe('dark');
64
+ expect(screen.getByTestId('resolved').textContent).toBe('dark');
65
+ expect(window.localStorage.getItem('bizar:theme')).toBe('dark');
66
+ expect(document.documentElement.dataset['theme']).toBe('dark');
67
+ });
68
+
69
+ it('cycle goes light → dark → system → light', () => {
70
+ render(
71
+ <ThemeProvider defaultMode="light">
72
+ <Probe />
73
+ </ThemeProvider>,
74
+ );
75
+ expect(screen.getByTestId('mode').textContent).toBe('light');
76
+
77
+ act(() => screen.getByText('cycle').click());
78
+ expect(screen.getByTestId('mode').textContent).toBe('dark');
79
+
80
+ act(() => screen.getByText('cycle').click());
81
+ expect(screen.getByTestId('mode').textContent).toBe('system');
82
+
83
+ act(() => screen.getByText('cycle').click());
84
+ expect(screen.getByTestId('mode').textContent).toBe('light');
85
+ });
86
+ });
@@ -0,0 +1,94 @@
1
+ import { createContext, useCallback, useEffect, useMemo, useState, type ReactNode } from 'react';
2
+
3
+ /**
4
+ * Theme modes.
5
+ * - 'system' → follows `prefers-color-scheme` media query, stored as `data-theme="light|dark"` on <html>.
6
+ * - 'light' → forces light.
7
+ * - 'dark' → forces dark.
8
+ */
9
+ export type ThemeMode = 'system' | 'light' | 'dark';
10
+ export type ResolvedTheme = 'light' | 'dark';
11
+
12
+ export interface ThemeContextValue {
13
+ /** The user's chosen mode (may be 'system'). */
14
+ mode: ThemeMode;
15
+ /** The active theme after resolving 'system' against the OS preference. */
16
+ resolved: ResolvedTheme;
17
+ /** Persist a new mode. */
18
+ setMode: (mode: ThemeMode) => void;
19
+ /** Cycle through light → dark → system → light. Wired to the toolbar toggle. */
20
+ cycle: () => void;
21
+ }
22
+
23
+ export const ThemeContext = createContext<ThemeContextValue | null>(null);
24
+
25
+ const STORAGE_KEY = 'bizar:theme';
26
+
27
+ function readStoredMode(): ThemeMode {
28
+ if (typeof window === 'undefined') return 'system';
29
+ const raw = window.localStorage.getItem(STORAGE_KEY);
30
+ if (raw === 'light' || raw === 'dark' || raw === 'system') return raw;
31
+ return 'system';
32
+ }
33
+
34
+ function systemPrefersDark(): boolean {
35
+ if (typeof window === 'undefined' || !window.matchMedia) return false;
36
+ return window.matchMedia('(prefers-color-scheme: dark)').matches;
37
+ }
38
+
39
+ function resolveTheme(mode: ThemeMode): ResolvedTheme {
40
+ if (mode === 'light' || mode === 'dark') return mode;
41
+ return systemPrefersDark() ? 'dark' : 'light';
42
+ }
43
+
44
+ function applyThemeAttribute(resolved: ResolvedTheme): void {
45
+ if (typeof document === 'undefined') return;
46
+ document.documentElement.dataset['theme'] = resolved;
47
+ }
48
+
49
+ export interface ThemeProviderProps {
50
+ children: ReactNode;
51
+ /** Override default mode on first render (still persists on change). */
52
+ defaultMode?: ThemeMode;
53
+ }
54
+
55
+ export function ThemeProvider({ children, defaultMode }: ThemeProviderProps): JSX.Element {
56
+ const [mode, setModeState] = useState<ThemeMode>(() => defaultMode ?? readStoredMode());
57
+ const [systemDark, setSystemDark] = useState<boolean>(systemPrefersDark);
58
+
59
+ // Subscribe to system preference changes when in 'system' mode.
60
+ useEffect(() => {
61
+ if (typeof window === 'undefined' || !window.matchMedia) return;
62
+ const mql = window.matchMedia('(prefers-color-scheme: dark)');
63
+ const handler = (e: MediaQueryListEvent): void => setSystemDark(e.matches);
64
+ mql.addEventListener('change', handler);
65
+ return () => mql.removeEventListener('change', handler);
66
+ }, []);
67
+
68
+ const resolved: ResolvedTheme = mode === 'system' ? (systemDark ? 'dark' : 'light') : mode;
69
+
70
+ // Apply to <html data-theme="…"> so tokens.css overrides win over media query.
71
+ useEffect(() => {
72
+ applyThemeAttribute(resolved);
73
+ }, [resolved]);
74
+
75
+ const setMode = useCallback((next: ThemeMode) => {
76
+ setModeState(next);
77
+ if (typeof window !== 'undefined') window.localStorage.setItem(STORAGE_KEY, next);
78
+ }, []);
79
+
80
+ const cycle = useCallback(() => {
81
+ setModeState((prev) => {
82
+ const next: ThemeMode = prev === 'light' ? 'dark' : prev === 'dark' ? 'system' : 'light';
83
+ if (typeof window !== 'undefined') window.localStorage.setItem(STORAGE_KEY, next);
84
+ return next;
85
+ });
86
+ }, []);
87
+
88
+ const value = useMemo<ThemeContextValue>(
89
+ () => ({ mode, resolved, setMode, cycle }),
90
+ [mode, resolved, setMode, cycle],
91
+ );
92
+
93
+ return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;
94
+ }
@@ -0,0 +1,88 @@
1
+ import { Monitor, Moon, Sun } from 'lucide-react';
2
+ import { useTheme } from './useTheme.js';
3
+ import { useDensity } from './useDensity.js';
4
+ import { cx } from '../utils/cx.js';
5
+
6
+ /**
7
+ * ThemeToggle — a single icon button that cycles light → dark → system.
8
+ *
9
+ * Shows the icon for the *current resolved* theme:
10
+ * - system → Monitor
11
+ * - light → Sun
12
+ * - dark → Moon
13
+ *
14
+ * Hover hint and a11y label change with the cycle target.
15
+ *
16
+ * Visual: matches IconButton ghost variant (defined separately once
17
+ * controls/IconButton lands). For the foundation milestone this stays
18
+ * inline so the shell renders without the full controls library.
19
+ */
20
+
21
+ const RESOLVED_ICON = {
22
+ light: Sun,
23
+ dark: Moon,
24
+ system: Monitor,
25
+ } as const;
26
+
27
+ const NEXT_LABEL = {
28
+ light: 'Switch to dark theme',
29
+ dark: 'Switch to system theme',
30
+ system: 'Switch to light theme',
31
+ } as const;
32
+
33
+ export interface ThemeToggleProps {
34
+ className?: string;
35
+ }
36
+
37
+ export function ThemeToggle({ className }: ThemeToggleProps): JSX.Element {
38
+ const { mode, resolved, cycle } = useTheme();
39
+ const Icon = RESOLVED_ICON[mode];
40
+ return (
41
+ <button
42
+ type="button"
43
+ onClick={cycle}
44
+ aria-label={NEXT_LABEL[mode]}
45
+ title={`${NEXT_LABEL[mode]} (currently: ${resolved})`}
46
+ className={cx(
47
+ 'v8-theme-toggle',
48
+ 'inline-flex h-8 w-8 items-center justify-center',
49
+ 'rounded-[var(--radius-sm)]',
50
+ 'text-[var(--fg-muted)] hover:text-[var(--fg)] hover:bg-[var(--surface-1)]',
51
+ 'transition-colors duration-[var(--motion-fast)]',
52
+ className,
53
+ )}
54
+ >
55
+ <Icon size={16} aria-hidden="true" />
56
+ </button>
57
+ );
58
+ }
59
+
60
+ /**
61
+ * DensityToggle — pill toggle for comfortable / compact.
62
+ * Wired into the topbar settings cluster.
63
+ */
64
+ export interface DensityToggleProps {
65
+ className?: string;
66
+ }
67
+ export function DensityToggle({ className }: DensityToggleProps): JSX.Element {
68
+ const { density, toggle } = useDensity();
69
+ return (
70
+ <button
71
+ type="button"
72
+ onClick={toggle}
73
+ aria-label={`Switch to ${density === 'comfortable' ? 'compact' : 'comfortable'} density`}
74
+ title={`Density: ${density}`}
75
+ className={cx(
76
+ 'v8-density-toggle',
77
+ 'inline-flex h-8 px-2 items-center justify-center',
78
+ 'rounded-[var(--radius-sm)]',
79
+ 'text-[var(--fs-12)] font-medium tracking-[var(--tracking-wide)] uppercase',
80
+ 'text-[var(--fg-muted)] hover:text-[var(--fg)] hover:bg-[var(--surface-1)]',
81
+ 'transition-colors duration-[var(--motion-fast)]',
82
+ className,
83
+ )}
84
+ >
85
+ {density === 'comfortable' ? 'Cozy' : 'Compact'}
86
+ </button>
87
+ );
88
+ }
@@ -0,0 +1,15 @@
1
+ import { useContext } from 'react';
2
+ import { DensityContext, type DensityContextValue } from './DensityProvider.js';
3
+
4
+ /**
5
+ * useDensity — read & mutate UI density (comfortable / compact).
6
+ *
7
+ * Throws if used outside of a <DensityProvider>.
8
+ */
9
+ export function useDensity(): DensityContextValue {
10
+ const ctx = useContext(DensityContext);
11
+ if (ctx === null) {
12
+ throw new Error('useDensity must be used inside <DensityProvider>.');
13
+ }
14
+ return ctx;
15
+ }
@@ -0,0 +1,16 @@
1
+ import { useContext } from 'react';
2
+ import { ThemeContext, type ThemeContextValue } from './ThemeProvider.js';
3
+
4
+ /**
5
+ * useTheme — read & mutate the active theme.
6
+ *
7
+ * Throws if used outside of a <ThemeProvider>. This is intentional:
8
+ * using the hook without a provider is always a bug.
9
+ */
10
+ export function useTheme(): ThemeContextValue {
11
+ const ctx = useContext(ThemeContext);
12
+ if (ctx === null) {
13
+ throw new Error('useTheme must be used inside <ThemeProvider>.');
14
+ }
15
+ return ctx;
16
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * cx — className combiner.
3
+ *
4
+ * Wraps `clsx` (truthy filtering + conditionals) with `tailwind-merge`
5
+ * (later utilities win — `cx('p-2', 'p-4')` → `'p-4'`).
6
+ *
7
+ * Usage:
8
+ * cx('btn', isActive && 'btn--active', props.className)
9
+ *
10
+ * Why a wrapper: keeps imports to one symbol across the v8 codebase and
11
+ * lets us swap the implementation later (or add caching) without ripping
12
+ * through every component.
13
+ */
14
+ import { clsx, type ClassValue } from 'clsx';
15
+ import { twMerge } from 'tailwind-merge';
16
+
17
+ export function cx(...inputs: ClassValue[]): string {
18
+ return twMerge(clsx(inputs));
19
+ }
@@ -0,0 +1,33 @@
1
+ import { GitMerge, GitPullRequest, AlertTriangle, CheckCircle2, Bot, Wrench } from 'lucide-react';
2
+ import { Stack } from '../../ui/primitives/Stack.js';
3
+ import { ViewHeader } from '../../ui/data/ViewHeader.js';
4
+ import { ActivityFeed, type ActivityItem } from '../../ui/activity/ActivityFeed.js';
5
+
6
+ /**
7
+ * ActivityView — full history of events.
8
+ *
9
+ * Same shape as the Overview feed, but unbounded — the full stream.
10
+ */
11
+
12
+ const ITEMS: ActivityItem[] = [
13
+ { id: 'a1', icon: <GitMerge size={14} aria-hidden="true" />, title: 'Merged PR #42 — OKLch token system', meta: '2m ago', tone: 'success' },
14
+ { id: 'a2', icon: <GitPullRequest size={14} aria-hidden="true" />, title: 'Opened PR #43 — Kanban centerpiece', meta: '12m ago', tone: 'info' },
15
+ { id: 'a3', icon: <Bot size={14} aria-hidden="true" />, title: 'Atlas — "Wire TanStack Router"', meta: '34m ago', tone: 'info' },
16
+ { id: 'a4', icon: <CheckCircle2 size={14} aria-hidden="true" />, title: 'Goal "Ship v8 dashboard" advanced to 62%', meta: '52m ago', tone: 'success' },
17
+ { id: 'a5', icon: <Wrench size={14} aria-hidden="true" />, title: 'Borealis — Edited src/web/v8/ui/index.ts', meta: '1h ago' },
18
+ { id: 'a6', icon: <AlertTriangle size={14} aria-hidden="true" />, title: 'CI failed on tests/a11y/forms.test.tsx', meta: '1h ago', tone: 'warning' },
19
+ { id: 'a7', icon: <GitMerge size={14} aria-hidden="true" />, title: 'Merged PR #41 — Sprint S4 (Navigation)', meta: '2h ago', tone: 'success' },
20
+ { id: 'a8', icon: <GitPullRequest size={14} aria-hidden="true" />, title: 'Opened PR #40 — Sprint S3 (Data display)', meta: '3h ago', tone: 'info' },
21
+ ];
22
+
23
+ export function ActivityView(): JSX.Element {
24
+ return (
25
+ <Stack gap={5}>
26
+ <ViewHeader
27
+ title="Activity"
28
+ description="Full event history across the harness."
29
+ />
30
+ <ActivityFeed items={ITEMS} />
31
+ </Stack>
32
+ );
33
+ }
@@ -0,0 +1,108 @@
1
+ import { Stack } from '../../ui/primitives/Stack.js';
2
+ import { Grid } from '../../ui/primitives/Grid.js';
3
+ import { ViewHeader } from '../../ui/data/ViewHeader.js';
4
+ import { AgentCard, type AgentCardProps } from '../../ui/agents/AgentCard.js';
5
+ import { AgentActivity, type AgentActivityItem } from '../../ui/agents/AgentActivity.js';
6
+ import { Card, CardBody, CardHeader } from '../../ui/data/Card.js';
7
+ import { Wrench, Bot, GitMerge, MessageSquare } from 'lucide-react';
8
+
9
+ /**
10
+ * AgentsView — orchestrator agents (PLAN.md "Agents page").
11
+ *
12
+ * Each card shows status + current task + token sparkline. Click a card
13
+ * to see per-agent activity (sample feed below).
14
+ */
15
+
16
+ const AGENTS: AgentCardProps[] = [
17
+ {
18
+ id: 'a1',
19
+ name: 'Atlas',
20
+ role: 'Lead researcher',
21
+ status: 'busy',
22
+ currentTask: 'Wire TanStack Router in v8 App',
23
+ lastActivity: '2m ago',
24
+ tasksToday: 7,
25
+ tpmHistory: [120, 200, 340, 280, 410, 480, 360, 290, 220, 180, 160, 140, 200, 260, 320, 380],
26
+ },
27
+ {
28
+ id: 'a2',
29
+ name: 'Borealis',
30
+ role: 'Frontend specialist',
31
+ status: 'busy',
32
+ currentTask: 'Polish Settings nav rail',
33
+ lastActivity: '8m ago',
34
+ tasksToday: 4,
35
+ tpmHistory: [60, 90, 120, 150, 180, 200, 220, 240, 260, 230, 210, 190, 170, 150],
36
+ },
37
+ {
38
+ id: 'a3',
39
+ name: 'Cassini',
40
+ role: 'QA + review',
41
+ status: 'idle',
42
+ currentTask: undefined,
43
+ lastActivity: '32m ago',
44
+ tasksToday: 12,
45
+ tpmHistory: [10, 5, 8, 0, 0, 0, 0, 0, 0, 0, 0],
46
+ },
47
+ {
48
+ id: 'a4',
49
+ name: 'Drift',
50
+ role: 'Migration sweeper',
51
+ status: 'error',
52
+ currentTask: 'Bulk-rename `var(--token)` to literals',
53
+ lastActivity: '1h ago',
54
+ tasksToday: 2,
55
+ tpmHistory: [200, 220, 240, 260, 0, 0, 0, 0],
56
+ },
57
+ {
58
+ id: 'a5',
59
+ name: 'Ember',
60
+ role: 'Memory curator',
61
+ status: 'paused',
62
+ lastActivity: '2h ago',
63
+ tasksToday: 1,
64
+ tpmHistory: [40, 60, 80, 100, 80, 60, 40, 20],
65
+ },
66
+ {
67
+ id: 'a6',
68
+ name: 'Ferro',
69
+ role: 'Build + test',
70
+ status: 'idle',
71
+ lastActivity: '15m ago',
72
+ tasksToday: 9,
73
+ tpmHistory: [30, 40, 50, 60, 50, 40, 30, 20, 10],
74
+ },
75
+ ];
76
+
77
+ const FEATURED_AGENT_ID = 'a1';
78
+
79
+ const ACTIVITY: AgentActivityItem[] = [
80
+ { id: 'ev1', icon: <Bot size={14} aria-hidden="true" />, title: 'Run started', description: 'Picked up "Wire TanStack Router in v8 App"', meta: '12:04', tone: 'info' },
81
+ { id: 'ev2', icon: <Wrench size={14} aria-hidden="true" />, title: 'Tool call', description: 'Read src/web/v8/App.tsx', meta: '12:05' },
82
+ { id: 'ev3', icon: <MessageSquare size={14} aria-hidden="true" />, title: 'Message received', description: '"Use the state-based router"', meta: '12:06', tone: 'info' },
83
+ { id: 'ev4', icon: <GitMerge size={14} aria-hidden="true" />, title: 'Committed', description: 'feat(v8-dash): wire app-level router', meta: '12:08', tone: 'success' },
84
+ ];
85
+
86
+ export function AgentsView(): JSX.Element {
87
+ return (
88
+ <Stack gap={5}>
89
+ <ViewHeader
90
+ title="Agents"
91
+ description="The orchestrator's running entities. Click a card to drill into one."
92
+ />
93
+ <Grid cols={3}>
94
+ {AGENTS.map((agent) => (
95
+ <AgentCard key={agent.id} {...agent} />
96
+ ))}
97
+ </Grid>
98
+ <Card>
99
+ <CardHeader
100
+ title={`Activity — ${AGENTS.find((a) => a.id === FEATURED_AGENT_ID)?.name ?? ''}`}
101
+ />
102
+ <CardBody>
103
+ <AgentActivity items={ACTIVITY} />
104
+ </CardBody>
105
+ </Card>
106
+ </Stack>
107
+ );
108
+ }
@@ -0,0 +1,142 @@
1
+ import { describe, expect, it, vi, beforeEach } from 'vitest';
2
+ import { render, screen } from '@testing-library/react';
3
+ import userEvent from '@testing-library/user-event';
4
+ import { ThemeProvider } from '../../ui/theme/ThemeProvider.js';
5
+ import { DensityProvider } from '../../ui/theme/DensityProvider.js';
6
+ import { AppCommandPalette } from './AppCommandPalette.js';
7
+
8
+ /**
9
+ * AppCommandPalette — the ⌘K palette with three scopes:
10
+ * Navigation, Actions, Settings.
11
+ *
12
+ * The underlying `cmdk` primitive filters items by typed value; we don't
13
+ * need to type to exercise selection, but typing "Tasks" narrows the
14
+ * list to the matching Navigation item.
15
+ *
16
+ * The Dialog mounts a portal; @testing-library queries reach into the
17
+ * portal transparently.
18
+ */
19
+
20
+ function PaletteHarness(props: {
21
+ open: boolean;
22
+ onOpenChange: (open: boolean) => void;
23
+ onNavigate: (id: string) => void;
24
+ }): JSX.Element {
25
+ return (
26
+ <ThemeProvider defaultMode="light">
27
+ <DensityProvider>
28
+ <AppCommandPalette
29
+ open={props.open}
30
+ onOpenChange={props.onOpenChange}
31
+ onNavigate={props.onNavigate}
32
+ />
33
+ </DensityProvider>
34
+ </ThemeProvider>
35
+ );
36
+ }
37
+
38
+ // `cmdk` calls `scrollIntoView` on the highlighted item whenever the user
39
+ // types. jsdom doesn't implement it natively, so we stub a no-op on the
40
+ // prototype before every test. The real implementation behaves no
41
+ // differently for the assertions we make here.
42
+ beforeEach(() => {
43
+ if (!Element.prototype.scrollIntoView) {
44
+ Element.prototype.scrollIntoView = vi.fn();
45
+ }
46
+ });
47
+
48
+ describe('AppCommandPalette', () => {
49
+ it('renders the three scope headings when open', () => {
50
+ const onNavigate = vi.fn();
51
+ render(
52
+ <PaletteHarness
53
+ open
54
+ onOpenChange={() => undefined}
55
+ onNavigate={onNavigate}
56
+ />,
57
+ );
58
+ // Scope to the dialog portal — the sidebar also renders
59
+ // "Navigation" as a section heading outside the palette.
60
+ const dialog = screen.getByRole('dialog');
61
+ expect(dialog).toBeInTheDocument();
62
+ const headings = Array.from(dialog.querySelectorAll('[cmdk-group-heading]')).map(
63
+ (node) => node.textContent,
64
+ );
65
+ expect(headings).toEqual(['Navigation', 'Actions', 'Settings']);
66
+ });
67
+
68
+ it('typing Tasks narrows to the Tasks nav item and Enter calls onNavigate("tasks")', async () => {
69
+ const onNavigate = vi.fn();
70
+ const onOpenChange = vi.fn();
71
+ const user = userEvent.setup();
72
+ render(
73
+ <PaletteHarness
74
+ open
75
+ onOpenChange={onOpenChange}
76
+ onNavigate={onNavigate}
77
+ />,
78
+ );
79
+ await user.type(screen.getByPlaceholderText(/Type a command/i), 'Tasks');
80
+ await user.keyboard('{Enter}');
81
+ expect(onNavigate).toHaveBeenCalledWith('tasks');
82
+ expect(onOpenChange).toHaveBeenCalledWith(false);
83
+ });
84
+
85
+ it('Toggle theme calls onNavigate("__theme")', async () => {
86
+ const onNavigate = vi.fn();
87
+ const user = userEvent.setup();
88
+ render(
89
+ <PaletteHarness
90
+ open
91
+ onOpenChange={() => undefined}
92
+ onNavigate={onNavigate}
93
+ />,
94
+ );
95
+ await user.type(screen.getByPlaceholderText(/Type a command/i), 'Toggle theme');
96
+ await user.keyboard('{Enter}');
97
+ expect(onNavigate).toHaveBeenCalledWith('__theme');
98
+ });
99
+
100
+ it('Selecting a Settings item routes to settings + scrolls to section', async () => {
101
+ const onNavigate = vi.fn();
102
+ const onOpenChange = vi.fn();
103
+ const scrollSpy = vi.fn();
104
+ const user = userEvent.setup();
105
+ // Stub scrollIntoView on the prototype so the rAF callback finds it.
106
+ Element.prototype.scrollIntoView = scrollSpy;
107
+ // Provide a section element for the palette to find after mount.
108
+ const section = document.createElement('section');
109
+ section.id = 'density';
110
+ document.body.appendChild(section);
111
+
112
+ render(
113
+ <PaletteHarness
114
+ open
115
+ onOpenChange={onOpenChange}
116
+ onNavigate={onNavigate}
117
+ />,
118
+ );
119
+ await user.type(screen.getByPlaceholderText(/Type a command/i), 'Settings · Density');
120
+ await user.keyboard('{Enter}');
121
+ // Setting navigation triggers onNavigate('settings') and closes palette.
122
+ expect(onNavigate).toHaveBeenCalledWith('settings');
123
+ expect(onOpenChange).toHaveBeenCalledWith(false);
124
+
125
+ // Flush the rAF scheduled by handleSelect.
126
+ await new Promise<void>((resolve) => requestAnimationFrame(() => resolve()));
127
+ expect(scrollSpy).toHaveBeenCalled();
128
+
129
+ document.body.removeChild(section);
130
+ });
131
+
132
+ it('renders the ⌘, shortcut hint on the Settings nav item', () => {
133
+ render(
134
+ <PaletteHarness
135
+ open
136
+ onOpenChange={() => undefined}
137
+ onNavigate={() => undefined}
138
+ />,
139
+ );
140
+ expect(screen.getByText('⌘,')).toBeInTheDocument();
141
+ });
142
+ });