@polderlabs/bizar 7.0.4 → 8.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/agents/agent-browser.md +1 -1
- package/.claude/agents/baldr.md +1 -1
- package/.claude/agents/forseti.md +1 -1
- package/.claude/agents/frigg.md +1 -1
- package/.claude/agents/heimdall.md +1 -1
- package/.claude/agents/hermod.md +1 -1
- package/.claude/agents/mimir.md +1 -1
- package/.claude/agents/odin.md +1 -1
- package/.claude/agents/quick.md +1 -1
- package/.claude/agents/semble-search.md +1 -1
- package/.claude/agents/thor.md +1 -1
- package/.claude/agents/tyr.md +1 -1
- package/.claude/agents/vidarr.md +1 -1
- package/.claude/agents/vor.md +1 -1
- package/.claude/commands/goal.md +98 -0
- package/.claude/settings.local.json +7 -0
- package/bizar-dash/DESIGN.md +729 -969
- package/bizar-dash/GLYPH.md +418 -0
- package/bizar-dash/PLAN.md +1135 -0
- package/bizar-dash/dist/assets/ActivityFeed-CqF6iSDQ.js +6 -0
- package/bizar-dash/dist/assets/ActivityFeed-CqF6iSDQ.js.map +1 -0
- package/bizar-dash/dist/assets/ActivityView-qdhDjRtL.js +1 -0
- package/bizar-dash/dist/assets/ActivityView-qdhDjRtL.js.map +1 -0
- package/bizar-dash/dist/assets/AgentsView-BwXkOayl.js +28 -0
- package/bizar-dash/dist/assets/AgentsView-BwXkOayl.js.map +1 -0
- package/bizar-dash/dist/assets/Badge-BH4C3aUF.js +1 -0
- package/bizar-dash/dist/assets/Badge-BH4C3aUF.js.map +1 -0
- package/bizar-dash/dist/assets/Button-RmN1RKhE.js +6 -0
- package/bizar-dash/dist/assets/Button-RmN1RKhE.js.map +1 -0
- package/bizar-dash/dist/assets/Card-BzJeYR2D.js +1 -0
- package/bizar-dash/dist/assets/Card-BzJeYR2D.js.map +1 -0
- package/bizar-dash/dist/assets/Chip-CN2bvm7a.js +1 -0
- package/bizar-dash/dist/assets/Chip-CN2bvm7a.js.map +1 -0
- package/bizar-dash/dist/assets/EmptyState-DEiBv4-r.js +1 -0
- package/bizar-dash/dist/assets/EmptyState-DEiBv4-r.js.map +1 -0
- package/bizar-dash/dist/assets/GoalsView-CvsrzEez.js +6 -0
- package/bizar-dash/dist/assets/GoalsView-CvsrzEez.js.map +1 -0
- package/bizar-dash/dist/assets/KanbanCard-DZEaAiEr.js +21 -0
- package/bizar-dash/dist/assets/KanbanCard-DZEaAiEr.js.map +1 -0
- package/bizar-dash/dist/assets/LibrariesView-CPgKGPpM.js +67 -0
- package/bizar-dash/dist/assets/LibrariesView-CPgKGPpM.js.map +1 -0
- package/bizar-dash/dist/assets/MemoryView-Bbez5pMN.js +13 -0
- package/bizar-dash/dist/assets/MemoryView-Bbez5pMN.js.map +1 -0
- package/bizar-dash/dist/assets/OverviewView-BDegBWgg.js +1 -0
- package/bizar-dash/dist/assets/OverviewView-BDegBWgg.js.map +1 -0
- package/bizar-dash/dist/assets/Select-xwxbK8Ed.js +16 -0
- package/bizar-dash/dist/assets/Select-xwxbK8Ed.js.map +1 -0
- package/bizar-dash/dist/assets/SettingsRow-CppSgkT_.js +10 -0
- package/bizar-dash/dist/assets/SettingsRow-CppSgkT_.js.map +1 -0
- package/bizar-dash/dist/assets/SettingsView-DUc2meHV.js +43 -0
- package/bizar-dash/dist/assets/SettingsView-DUc2meHV.js.map +1 -0
- package/bizar-dash/dist/assets/Sheet-C_sIEw35.js +1 -0
- package/bizar-dash/dist/assets/Sheet-C_sIEw35.js.map +1 -0
- package/bizar-dash/dist/assets/Sparkline-D664vGWW.js +1 -0
- package/bizar-dash/dist/assets/Sparkline-D664vGWW.js.map +1 -0
- package/bizar-dash/dist/assets/StatTile-BRsUIA6P.js +16 -0
- package/bizar-dash/dist/assets/StatTile-BRsUIA6P.js.map +1 -0
- package/bizar-dash/dist/assets/TasksView-DVyX5-DY.js +1 -0
- package/bizar-dash/dist/assets/TasksView-DVyX5-DY.js.map +1 -0
- package/bizar-dash/dist/assets/Textarea-Dk97nmjO.js +1 -0
- package/bizar-dash/dist/assets/Textarea-Dk97nmjO.js.map +1 -0
- package/bizar-dash/dist/assets/ViewHeader-dPd4zAyj.js +6 -0
- package/bizar-dash/dist/assets/ViewHeader-dPd4zAyj.js.map +1 -0
- package/bizar-dash/dist/assets/brain-BajPVibR.js +6 -0
- package/bizar-dash/dist/assets/brain-BajPVibR.js.map +1 -0
- package/bizar-dash/dist/assets/calendar-CaP_Bbgc.js +6 -0
- package/bizar-dash/dist/assets/calendar-CaP_Bbgc.js.map +1 -0
- package/bizar-dash/dist/assets/cmdk-BLWIhKrV.js +80 -0
- package/bizar-dash/dist/assets/cmdk-BLWIhKrV.js.map +1 -0
- package/bizar-dash/dist/assets/dnd-kit-DU8GZk7s.js +5 -0
- package/bizar-dash/dist/assets/dnd-kit-DU8GZk7s.js.map +1 -0
- package/bizar-dash/dist/assets/git-pull-request-CFRRwdxp.js +11 -0
- package/bizar-dash/dist/assets/git-pull-request-CFRRwdxp.js.map +1 -0
- package/bizar-dash/dist/assets/index-AL3OLUfz.js +1 -0
- package/bizar-dash/dist/assets/index-AL3OLUfz.js.map +1 -0
- package/bizar-dash/dist/assets/main-CcQfRfIJ.css +1 -0
- package/bizar-dash/dist/assets/main-LxX9zTRk.js +109 -0
- package/bizar-dash/dist/assets/main-LxX9zTRk.js.map +1 -0
- package/bizar-dash/dist/assets/plus-CVH1JB04.js +6 -0
- package/bizar-dash/dist/assets/plus-CVH1JB04.js.map +1 -0
- package/bizar-dash/dist/assets/terminal-B2sSd5t7.js +11 -0
- package/bizar-dash/dist/assets/terminal-B2sSd5t7.js.map +1 -0
- package/bizar-dash/dist/assets/trash-2-JtYRQ79q.js +6 -0
- package/bizar-dash/dist/assets/trash-2-JtYRQ79q.js.map +1 -0
- package/bizar-dash/dist/assets/triangle-alert-Nzbrm0I2.js +6 -0
- package/bizar-dash/dist/assets/triangle-alert-Nzbrm0I2.js.map +1 -0
- package/bizar-dash/dist/assets/useFetch-CoVWwbml.js +1 -0
- package/bizar-dash/dist/assets/useFetch-CoVWwbml.js.map +1 -0
- package/bizar-dash/dist/assets/useWebSocket-CVIQB8yG.js +1 -0
- package/bizar-dash/dist/assets/useWebSocket-CVIQB8yG.js.map +1 -0
- package/bizar-dash/dist/assets/wrench-B7go551L.js +6 -0
- package/bizar-dash/dist/assets/wrench-B7go551L.js.map +1 -0
- package/bizar-dash/dist/{mobile.html → v8.html} +6 -9
- package/bizar-dash/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
- package/bizar-dash/src/server/api.mjs +10 -0
- package/bizar-dash/src/server/bg-poller.mjs +81 -1
- package/bizar-dash/src/server/bg-poller.test.mjs +28 -0
- package/bizar-dash/src/server/progress-parser.mjs +221 -0
- package/bizar-dash/src/server/progress-parser.test.mjs +105 -0
- package/bizar-dash/src/server/routes/agents-cc.mjs +381 -0
- package/bizar-dash/src/server/routes/agents-cc.test.mjs +35 -0
- package/bizar-dash/src/server/routes/goals.mjs +307 -0
- package/bizar-dash/src/server/routes/tasks.mjs +11 -0
- package/bizar-dash/src/server/server.mjs +1 -57
- package/bizar-dash/src/web/v8/App.tsx +188 -0
- package/bizar-dash/src/web/v8/__tests__/App.test.tsx +102 -0
- package/bizar-dash/src/web/v8/__tests__/AppShell.test.tsx +79 -0
- package/bizar-dash/src/web/v8/__tests__/PageSkeleton.test.tsx +12 -0
- package/bizar-dash/src/web/v8/__tests__/SettingsView.test.tsx +84 -0
- package/bizar-dash/src/web/v8/__tests__/Sidebar.test.tsx +95 -0
- package/bizar-dash/src/web/v8/__tests__/activity.test.tsx +63 -0
- package/bizar-dash/src/web/v8/__tests__/agents.test.tsx +90 -0
- package/bizar-dash/src/web/v8/__tests__/control-plane.test.tsx +104 -0
- package/bizar-dash/src/web/v8/__tests__/controls.test.tsx +135 -0
- package/bizar-dash/src/web/v8/__tests__/cx.test.ts +25 -0
- package/bizar-dash/src/web/v8/__tests__/data.test.tsx +293 -0
- package/bizar-dash/src/web/v8/__tests__/feedback.test.tsx +213 -0
- package/bizar-dash/src/web/v8/__tests__/goals.test.tsx +105 -0
- package/bizar-dash/src/web/v8/__tests__/kanban.test.tsx +176 -0
- package/bizar-dash/src/web/v8/__tests__/libraries.test.tsx +70 -0
- package/bizar-dash/src/web/v8/__tests__/memory.test.tsx +60 -0
- package/bizar-dash/src/web/v8/__tests__/navigation.test.tsx +137 -0
- package/bizar-dash/src/web/v8/__tests__/settings.test.tsx +104 -0
- package/bizar-dash/src/web/v8/__tests__/theme.test.tsx +98 -0
- package/bizar-dash/src/web/v8/__tests__/useFetch.test.ts +92 -0
- package/bizar-dash/src/web/v8/__tests__/useWebSocket.test.ts +87 -0
- package/bizar-dash/src/web/v8/__tests__/views.test.tsx +182 -0
- package/bizar-dash/src/web/v8/data/fetcher.ts +59 -0
- package/bizar-dash/src/web/v8/data/types.ts +154 -0
- package/bizar-dash/src/web/v8/data/useFetch.ts +62 -0
- package/bizar-dash/src/web/v8/data/useWebSocket.ts +153 -0
- package/bizar-dash/src/web/v8/main.tsx +28 -0
- package/bizar-dash/src/web/v8/shell/AppShell.tsx +90 -0
- package/bizar-dash/src/web/v8/shell/PageSkeleton.tsx +29 -0
- package/bizar-dash/src/web/v8/shell/Sidebar.tsx +361 -0
- package/bizar-dash/src/web/v8/shell/StatusBar.tsx +63 -0
- package/bizar-dash/src/web/v8/shell/Topbar.tsx +113 -0
- package/bizar-dash/src/web/v8/shell/index.ts +15 -0
- package/bizar-dash/src/web/v8/ui/activity/ActivityFeed.tsx +137 -0
- package/bizar-dash/src/web/v8/ui/agents/AgentActivity.tsx +101 -0
- package/bizar-dash/src/web/v8/ui/agents/AgentCard.tsx +158 -0
- package/bizar-dash/src/web/v8/ui/agents/AgentDetail.tsx +252 -0
- package/bizar-dash/src/web/v8/ui/agents/AgentStreamPanel.tsx +371 -0
- package/bizar-dash/src/web/v8/ui/controls/Button.tsx +141 -0
- package/bizar-dash/src/web/v8/ui/controls/ButtonGroup.tsx +32 -0
- package/bizar-dash/src/web/v8/ui/controls/Checkbox.tsx +49 -0
- package/bizar-dash/src/web/v8/ui/controls/Field.tsx +78 -0
- package/bizar-dash/src/web/v8/ui/controls/Form.tsx +23 -0
- package/bizar-dash/src/web/v8/ui/controls/IconButton.tsx +112 -0
- package/bizar-dash/src/web/v8/ui/controls/Input.tsx +94 -0
- package/bizar-dash/src/web/v8/ui/controls/RadioGroup.tsx +74 -0
- package/bizar-dash/src/web/v8/ui/controls/Select.tsx +171 -0
- package/bizar-dash/src/web/v8/ui/controls/Slider.tsx +68 -0
- package/bizar-dash/src/web/v8/ui/controls/Switch.tsx +56 -0
- package/bizar-dash/src/web/v8/ui/controls/Textarea.tsx +64 -0
- package/bizar-dash/src/web/v8/ui/controls/Toggle.tsx +36 -0
- package/bizar-dash/src/web/v8/ui/controls/ToggleGroup.tsx +85 -0
- package/bizar-dash/src/web/v8/ui/data/Accordion.tsx +134 -0
- package/bizar-dash/src/web/v8/ui/data/Avatar.tsx +175 -0
- package/bizar-dash/src/web/v8/ui/data/Badge.tsx +93 -0
- package/bizar-dash/src/web/v8/ui/data/BarList.tsx +101 -0
- package/bizar-dash/src/web/v8/ui/data/Card.tsx +140 -0
- package/bizar-dash/src/web/v8/ui/data/Chip.tsx +96 -0
- package/bizar-dash/src/web/v8/ui/data/Kbd.tsx +42 -0
- package/bizar-dash/src/web/v8/ui/data/ProgressBar.tsx +93 -0
- package/bizar-dash/src/web/v8/ui/data/Sparkline.tsx +98 -0
- package/bizar-dash/src/web/v8/ui/data/StatTile.tsx +150 -0
- package/bizar-dash/src/web/v8/ui/data/Table.tsx +170 -0
- package/bizar-dash/src/web/v8/ui/data/Timeline.tsx +130 -0
- package/bizar-dash/src/web/v8/ui/data/ViewHeader.tsx +122 -0
- package/bizar-dash/src/web/v8/ui/feedback/Alert.tsx +95 -0
- package/bizar-dash/src/web/v8/ui/feedback/Banner.tsx +39 -0
- package/bizar-dash/src/web/v8/ui/feedback/ContextMenu.tsx +143 -0
- package/bizar-dash/src/web/v8/ui/feedback/Dialog.tsx +149 -0
- package/bizar-dash/src/web/v8/ui/feedback/Drawer.tsx +8 -0
- package/bizar-dash/src/web/v8/ui/feedback/DropdownMenu.tsx +231 -0
- package/bizar-dash/src/web/v8/ui/feedback/EmptyState.tsx +48 -0
- package/bizar-dash/src/web/v8/ui/feedback/Popover.tsx +56 -0
- package/bizar-dash/src/web/v8/ui/feedback/Sheet.tsx +103 -0
- package/bizar-dash/src/web/v8/ui/feedback/Skeleton.tsx +67 -0
- package/bizar-dash/src/web/v8/ui/feedback/Spinner.tsx +30 -0
- package/bizar-dash/src/web/v8/ui/feedback/Toast.tsx +66 -0
- package/bizar-dash/src/web/v8/ui/feedback/Tooltip.tsx +89 -0
- package/bizar-dash/src/web/v8/ui/goals/GoalCard.tsx +176 -0
- package/bizar-dash/src/web/v8/ui/goals/GoalDetail.tsx +245 -0
- package/bizar-dash/src/web/v8/ui/goals/KeyResult.tsx +115 -0
- package/bizar-dash/src/web/v8/ui/index.ts +322 -0
- package/bizar-dash/src/web/v8/ui/kanban/KanbanBoard.tsx +83 -0
- package/bizar-dash/src/web/v8/ui/kanban/KanbanCard.tsx +247 -0
- package/bizar-dash/src/web/v8/ui/kanban/KanbanColumn.tsx +186 -0
- package/bizar-dash/src/web/v8/ui/kanban/KanbanContextMenu.tsx +122 -0
- package/bizar-dash/src/web/v8/ui/kanban/KanbanQuickAdd.tsx +141 -0
- package/bizar-dash/src/web/v8/ui/libraries/LibraryGrid.tsx +30 -0
- package/bizar-dash/src/web/v8/ui/libraries/LibraryItem.tsx +161 -0
- package/bizar-dash/src/web/v8/ui/memory/MemoryVault.tsx +144 -0
- package/bizar-dash/src/web/v8/ui/navigation/CommandPalette.tsx +224 -0
- package/bizar-dash/src/web/v8/ui/navigation/NavLink.tsx +81 -0
- package/bizar-dash/src/web/v8/ui/navigation/Pagination.tsx +164 -0
- package/bizar-dash/src/web/v8/ui/navigation/Tabs.tsx +128 -0
- package/bizar-dash/src/web/v8/ui/navigation/useCommandPaletteHotkey.test.ts +79 -0
- package/bizar-dash/src/web/v8/ui/primitives/Box.tsx +144 -0
- package/bizar-dash/src/web/v8/ui/primitives/Center.tsx +40 -0
- package/bizar-dash/src/web/v8/ui/primitives/Cluster.tsx +67 -0
- package/bizar-dash/src/web/v8/ui/primitives/Grid.tsx +104 -0
- package/bizar-dash/src/web/v8/ui/primitives/Inline.tsx +77 -0
- package/bizar-dash/src/web/v8/ui/primitives/Portal.tsx +33 -0
- package/bizar-dash/src/web/v8/ui/primitives/ScrollArea.tsx +62 -0
- package/bizar-dash/src/web/v8/ui/primitives/Separator.tsx +42 -0
- package/bizar-dash/src/web/v8/ui/primitives/Stack.tsx +73 -0
- package/bizar-dash/src/web/v8/ui/primitives/VisuallyHidden.tsx +49 -0
- package/bizar-dash/src/web/v8/ui/settings/SettingsNav.tsx +91 -0
- package/bizar-dash/src/web/v8/ui/settings/SettingsRow.tsx +88 -0
- package/bizar-dash/src/web/v8/ui/settings/SettingsSection.tsx +109 -0
- package/bizar-dash/src/web/v8/ui/styles/globals.css +225 -0
- package/bizar-dash/src/web/v8/ui/styles/reset.css +57 -0
- package/bizar-dash/src/web/v8/ui/styles/tokens.css +217 -0
- package/bizar-dash/src/web/v8/ui/theme/DensityProvider.test.tsx +74 -0
- package/bizar-dash/src/web/v8/ui/theme/DensityProvider.tsx +66 -0
- package/bizar-dash/src/web/v8/ui/theme/ThemeProvider.test.tsx +86 -0
- package/bizar-dash/src/web/v8/ui/theme/ThemeProvider.tsx +94 -0
- package/bizar-dash/src/web/v8/ui/theme/ThemeToggle.tsx +88 -0
- package/bizar-dash/src/web/v8/ui/theme/useDensity.ts +15 -0
- package/bizar-dash/src/web/v8/ui/theme/useTheme.ts +16 -0
- package/bizar-dash/src/web/v8/ui/utils/cx.ts +19 -0
- package/bizar-dash/src/web/v8/views/Activity/ActivityView.tsx +71 -0
- package/bizar-dash/src/web/v8/views/Agents/AgentsView.tsx +172 -0
- package/bizar-dash/src/web/v8/views/CommandPalette/AppCommandPalette.test.tsx +142 -0
- package/bizar-dash/src/web/v8/views/CommandPalette/AppCommandPalette.tsx +247 -0
- package/bizar-dash/src/web/v8/views/Goals/GoalsView.tsx +193 -0
- package/bizar-dash/src/web/v8/views/Libraries/LibrariesView.tsx +108 -0
- package/bizar-dash/src/web/v8/views/Memory/MemoryView.tsx +77 -0
- package/bizar-dash/src/web/v8/views/Overview/OverviewView.tsx +152 -0
- package/bizar-dash/src/web/v8/views/Router.tsx +72 -0
- package/bizar-dash/src/web/v8/views/Settings/SettingsView.tsx +730 -0
- package/bizar-dash/src/web/v8/views/Tasks/CommandPalettePlaceholder.tsx +106 -0
- package/bizar-dash/src/web/v8/views/Tasks/TasksKanbanPlaceholder.tsx +62 -0
- package/bizar-dash/src/web/v8/views/Tasks/TasksView.tsx +165 -0
- package/bizar-dash/src/web/v8/vite-env.d.ts +15 -0
- package/bizar-dash/src/web/{mobile.html → v8.html} +4 -7
- package/bizar-dash/tests/components/Button.test.tsx +51 -14
- package/bizar-dash/tests/components/Card.test.tsx +37 -20
- package/bizar-dash/tests/components/Dialog.test.tsx +80 -0
- package/bizar-dash/tests/components/Toast.test.tsx +48 -95
- package/bizar-dash/tests/goals-decompose.test.mjs +177 -0
- package/bizar-dash/tests/setup.ts +47 -0
- package/bizar-dash/tests/ui/primitives/VisuallyHidden.test.tsx +30 -15
- package/bizar-dash/vite.config.ts +41 -2
- package/bizar-dash/vitest.config.ts +9 -4
- package/cli/bin.mjs +32 -0
- package/cli/install.mjs +26 -1
- package/cli/provision-claude.mjs +86 -0
- package/package.json +36 -3
- package/scripts/run-dev.mjs +84 -0
- package/bizar-dash/dist/assets/EnvVarsSection-BfhAz3ax.js +0 -114
- package/bizar-dash/dist/assets/EnvVarsSection-BfhAz3ax.js.map +0 -1
- package/bizar-dash/dist/assets/MobileChat-DLWdv6tQ.js +0 -1
- package/bizar-dash/dist/assets/MobileChat-DLWdv6tQ.js.map +0 -1
- package/bizar-dash/dist/assets/MobileSettings-Bxv62uPY.js +0 -1
- package/bizar-dash/dist/assets/MobileSettings-Bxv62uPY.js.map +0 -1
- package/bizar-dash/dist/assets/Toast-ATSAmbdi.js +0 -26
- package/bizar-dash/dist/assets/Toast-ATSAmbdi.js.map +0 -1
- package/bizar-dash/dist/assets/__vite-browser-external-BIHI7g3E.js +0 -1
- package/bizar-dash/dist/assets/__vite-browser-external-BIHI7g3E.js.map +0 -1
- package/bizar-dash/dist/assets/main-CJAtrosO.css +0 -1
- package/bizar-dash/dist/assets/main-DKKj9dsq.js +0 -430
- package/bizar-dash/dist/assets/main-DKKj9dsq.js.map +0 -1
- package/bizar-dash/dist/assets/mobile-C_naUN91.js +0 -1
- package/bizar-dash/dist/assets/mobile-C_naUN91.js.map +0 -1
- package/bizar-dash/dist/assets/mobile-layout-BWLtwtfQ.css +0 -1
- package/bizar-dash/dist/assets/mobile-layout-GZ3bE8L6.js +0 -211
- package/bizar-dash/dist/assets/mobile-layout-GZ3bE8L6.js.map +0 -1
- package/bizar-dash/dist/assets/useSlashCommands-BOwD7lNb.js +0 -65
- package/bizar-dash/dist/assets/useSlashCommands-BOwD7lNb.js.map +0 -1
- package/bizar-dash/dist/index.html +0 -43
- package/bizar-dash/src/web/App.tsx +0 -915
- package/bizar-dash/src/web/MobileApp.tsx +0 -414
- package/bizar-dash/src/web/components/ArtifactCreateDialog.tsx +0 -95
- package/bizar-dash/src/web/components/ArtifactListDialog.tsx +0 -55
- package/bizar-dash/src/web/components/ArtifactViewer.tsx +0 -144
- package/bizar-dash/src/web/components/AuditDialog.tsx +0 -79
- package/bizar-dash/src/web/components/AutosaveField.tsx +0 -50
- package/bizar-dash/src/web/components/BackupRestore.tsx +0 -330
- package/bizar-dash/src/web/components/BgStatusBadge.tsx +0 -32
- package/bizar-dash/src/web/components/Button.tsx +0 -56
- package/bizar-dash/src/web/components/CanvasContextMenu.tsx +0 -68
- package/bizar-dash/src/web/components/Card.tsx +0 -40
- package/bizar-dash/src/web/components/CollapsibleSection.tsx +0 -72
- package/bizar-dash/src/web/components/CommandDialog.tsx +0 -66
- package/bizar-dash/src/web/components/DoctorPanel.tsx +0 -160
- package/bizar-dash/src/web/components/EmptyState.tsx +0 -30
- package/bizar-dash/src/web/components/EnvVarManager.tsx +0 -430
- package/bizar-dash/src/web/components/EvalDiff.tsx +0 -157
- package/bizar-dash/src/web/components/EvalExportButton.tsx +0 -27
- package/bizar-dash/src/web/components/EvalRunCard.tsx +0 -78
- package/bizar-dash/src/web/components/FileBrowser.tsx +0 -633
- package/bizar-dash/src/web/components/HeadroomSettings.tsx +0 -418
- package/bizar-dash/src/web/components/HeadroomStatus.tsx +0 -158
- package/bizar-dash/src/web/components/HelpDialog.tsx +0 -55
- package/bizar-dash/src/web/components/InviteDialog.tsx +0 -205
- package/bizar-dash/src/web/components/KillConfirmDialog.tsx +0 -88
- package/bizar-dash/src/web/components/MobileBottomNav.tsx +0 -38
- package/bizar-dash/src/web/components/MobileDrawer.tsx +0 -68
- package/bizar-dash/src/web/components/MobileHeader.tsx +0 -50
- package/bizar-dash/src/web/components/MobileLayout.tsx +0 -63
- package/bizar-dash/src/web/components/Modal.tsx +0 -215
- package/bizar-dash/src/web/components/Notifications.tsx +0 -242
- package/bizar-dash/src/web/components/ScheduleTemplateCard.tsx +0 -72
- package/bizar-dash/src/web/components/ScreenshotCapture.tsx +0 -138
- package/bizar-dash/src/web/components/ScreenshotOCR.tsx +0 -42
- package/bizar-dash/src/web/components/SearchModal.tsx +0 -227
- package/bizar-dash/src/web/components/SettingsNav.tsx +0 -117
- package/bizar-dash/src/web/components/SettingsSearch.tsx +0 -328
- package/bizar-dash/src/web/components/Sidebar.tsx +0 -89
- package/bizar-dash/src/web/components/Spinner.tsx +0 -19
- package/bizar-dash/src/web/components/StatusBadge.tsx +0 -56
- package/bizar-dash/src/web/components/Tag.tsx +0 -41
- package/bizar-dash/src/web/components/TailscaleSettings.tsx +0 -161
- package/bizar-dash/src/web/components/TaskCard.tsx +0 -69
- package/bizar-dash/src/web/components/TaskCreateSheet.tsx +0 -76
- package/bizar-dash/src/web/components/Toast.tsx +0 -150
- package/bizar-dash/src/web/components/Toggle.tsx +0 -31
- package/bizar-dash/src/web/components/Topbar.tsx +0 -455
- package/bizar-dash/src/web/components/UsageChart.tsx +0 -250
- package/bizar-dash/src/web/components/UsageTable.tsx +0 -90
- package/bizar-dash/src/web/components/VirtualList.tsx +0 -53
- package/bizar-dash/src/web/components/VisualPlanDialog.tsx +0 -58
- package/bizar-dash/src/web/components/VoiceNotesPanel.tsx +0 -211
- package/bizar-dash/src/web/components/VoiceRecorder.tsx +0 -105
- package/bizar-dash/src/web/components/WorkspaceSelector.tsx +0 -158
- package/bizar-dash/src/web/components/agents/CommunicationLog.tsx +0 -126
- package/bizar-dash/src/web/components/agents/DependencyGraph.tsx +0 -163
- package/bizar-dash/src/web/components/agents/QualityGates.tsx +0 -123
- package/bizar-dash/src/web/components/agents/RealTimeEventLog.tsx +0 -127
- package/bizar-dash/src/web/components/agents/RoutingDecisions.test.tsx +0 -148
- package/bizar-dash/src/web/components/agents/RoutingDecisions.tsx +0 -160
- package/bizar-dash/src/web/components/background/AttachButton.tsx +0 -96
- package/bizar-dash/src/web/components/background/TmuxAttachCard.tsx +0 -122
- package/bizar-dash/src/web/components/chat/AgentChip.tsx +0 -68
- package/bizar-dash/src/web/components/chat/AgentNode.tsx +0 -127
- package/bizar-dash/src/web/components/chat/AgentTree.tsx +0 -80
- package/bizar-dash/src/web/components/chat/ChatBubble.tsx +0 -60
- package/bizar-dash/src/web/components/chat/ChatComposer.tsx +0 -72
- package/bizar-dash/src/web/components/chat/ChatInfoPanel.tsx +0 -370
- package/bizar-dash/src/web/components/chat/ChatRail.tsx +0 -387
- package/bizar-dash/src/web/components/chat/ChatThread.tsx +0 -127
- package/bizar-dash/src/web/components/chat/ChatTopBar.tsx +0 -50
- package/bizar-dash/src/web/components/chat/Composer.tsx +0 -166
- package/bizar-dash/src/web/components/chat/ConfirmModal.tsx +0 -54
- package/bizar-dash/src/web/components/chat/EmptyState.tsx +0 -21
- package/bizar-dash/src/web/components/chat/FirstRunGreeting.tsx +0 -18
- package/bizar-dash/src/web/components/chat/FloatingComposer.tsx +0 -38
- package/bizar-dash/src/web/components/chat/InfoPanel.tsx +0 -184
- package/bizar-dash/src/web/components/chat/JumpToLatest.tsx +0 -58
- package/bizar-dash/src/web/components/chat/LoadingSkeleton.tsx +0 -19
- package/bizar-dash/src/web/components/chat/MessageBlock.tsx +0 -260
- package/bizar-dash/src/web/components/chat/MessageBubble.tsx +0 -60
- package/bizar-dash/src/web/components/chat/SessionList.tsx +0 -163
- package/bizar-dash/src/web/components/chat/SessionRowMenu.tsx +0 -206
- package/bizar-dash/src/web/components/chat/StreamingIndicator.tsx +0 -37
- package/bizar-dash/src/web/components/chat/SuggestionCards.tsx +0 -55
- package/bizar-dash/src/web/components/chat/WelcomeScreen.tsx +0 -36
- package/bizar-dash/src/web/components/chat/_legacy.ts +0 -30
- package/bizar-dash/src/web/components/chat/index.ts +0 -31
- package/bizar-dash/src/web/components/chat/useAutoGrowTextarea.ts +0 -18
- package/bizar-dash/src/web/components/chat/useChat.ts +0 -1190
- package/bizar-dash/src/web/components/chat/useSlashCommands.ts +0 -47
- package/bizar-dash/src/web/components/goals/GoalInput.tsx +0 -86
- package/bizar-dash/src/web/components/goals/PlanVisualization.tsx +0 -111
- package/bizar-dash/src/web/components/tasks/BacklogPanel.css +0 -109
- package/bizar-dash/src/web/components/tasks/BacklogPanel.tsx +0 -209
- package/bizar-dash/src/web/hooks/useAutosave.ts +0 -107
- package/bizar-dash/src/web/hooks/useI18n.ts +0 -13
- package/bizar-dash/src/web/index.html +0 -37
- package/bizar-dash/src/web/lib/api.ts +0 -237
- package/bizar-dash/src/web/lib/goapPlanner.ts +0 -614
- package/bizar-dash/src/web/lib/i18n.ts +0 -25
- package/bizar-dash/src/web/lib/logger.ts +0 -30
- package/bizar-dash/src/web/lib/markdown.tsx +0 -59
- package/bizar-dash/src/web/lib/search.ts +0 -115
- package/bizar-dash/src/web/lib/types.ts +0 -894
- package/bizar-dash/src/web/lib/utils.ts +0 -114
- package/bizar-dash/src/web/lib/ws.ts +0 -177
- package/bizar-dash/src/web/locales/en.json +0 -52
- package/bizar-dash/src/web/main.tsx +0 -43
- package/bizar-dash/src/web/mobile/MobileApp.tsx +0 -309
- package/bizar-dash/src/web/mobile/MobileBottomNav.tsx +0 -38
- package/bizar-dash/src/web/mobile/MobileChat.tsx +0 -138
- package/bizar-dash/src/web/mobile/MobileDoctor.tsx +0 -80
- package/bizar-dash/src/web/mobile/MobileEval.tsx +0 -167
- package/bizar-dash/src/web/mobile/MobileMemory.tsx +0 -108
- package/bizar-dash/src/web/mobile/MobileOverview.tsx +0 -213
- package/bizar-dash/src/web/mobile/MobileSettings.tsx +0 -251
- package/bizar-dash/src/web/mobile/MobileTasks.tsx +0 -94
- package/bizar-dash/src/web/mobile/MobileTopbar.tsx +0 -115
- package/bizar-dash/src/web/mobile/components/MobileBottomSheet.tsx +0 -182
- package/bizar-dash/src/web/mobile/components/MobileListItem.tsx +0 -64
- package/bizar-dash/src/web/mobile/components/MobileModal.tsx +0 -123
- package/bizar-dash/src/web/mobile/views/MobileActivity.tsx +0 -273
- package/bizar-dash/src/web/mobile/views/MobileAgents.tsx +0 -374
- package/bizar-dash/src/web/mobile/views/MobileArtifactCanvas.tsx +0 -439
- package/bizar-dash/src/web/mobile/views/MobileArtifacts.tsx +0 -143
- package/bizar-dash/src/web/mobile/views/MobileChat.tsx +0 -257
- package/bizar-dash/src/web/mobile/views/MobileConfig.tsx +0 -175
- package/bizar-dash/src/web/mobile/views/MobileHistory.tsx +0 -191
- package/bizar-dash/src/web/mobile/views/MobileMods.tsx +0 -149
- package/bizar-dash/src/web/mobile/views/MobileMore.tsx +0 -121
- package/bizar-dash/src/web/mobile/views/MobileNotifications.tsx +0 -137
- package/bizar-dash/src/web/mobile/views/MobilePlans.tsx +0 -26
- package/bizar-dash/src/web/mobile/views/MobileSchedules.tsx +0 -685
- package/bizar-dash/src/web/mobile/views/MobileSearchModal.tsx +0 -172
- package/bizar-dash/src/web/mobile/views/MobileSettings.tsx +0 -363
- package/bizar-dash/src/web/mobile/views/MobileSkills.tsx +0 -153
- package/bizar-dash/src/web/mobile/views/MobileTasks.tsx +0 -564
- package/bizar-dash/src/web/mobile/views/QrCodePanel.tsx +0 -69
- package/bizar-dash/src/web/mobile.tsx +0 -14
- package/bizar-dash/src/web/styles/agents-redesign.css +0 -311
- package/bizar-dash/src/web/styles/chat.css +0 -1740
- package/bizar-dash/src/web/styles/glyphs.css +0 -960
- package/bizar-dash/src/web/styles/main.css +0 -10389
- package/bizar-dash/src/web/styles/memory.css +0 -1177
- package/bizar-dash/src/web/styles/minimax-usage.css +0 -842
- package/bizar-dash/src/web/styles/mobile-chat.css +0 -5
- package/bizar-dash/src/web/styles/mobile-layout.css +0 -233
- package/bizar-dash/src/web/styles/mobile.css +0 -2181
- package/bizar-dash/src/web/styles/settings.css +0 -775
- package/bizar-dash/src/web/styles/skills.css +0 -302
- package/bizar-dash/src/web/styles/tasks-redesign.css +0 -253
- package/bizar-dash/src/web/styles/tasks.css +0 -605
- package/bizar-dash/src/web/ui/controls/Button.tsx +0 -77
- package/bizar-dash/src/web/ui/controls/Checkbox.tsx +0 -95
- package/bizar-dash/src/web/ui/controls/IconButton.tsx +0 -66
- package/bizar-dash/src/web/ui/controls/Kbd.tsx +0 -24
- package/bizar-dash/src/web/ui/controls/NumberInput.tsx +0 -77
- package/bizar-dash/src/web/ui/controls/RadioGroup.tsx +0 -109
- package/bizar-dash/src/web/ui/controls/SearchInput.tsx +0 -91
- package/bizar-dash/src/web/ui/controls/Select.tsx +0 -92
- package/bizar-dash/src/web/ui/controls/Slider.tsx +0 -70
- package/bizar-dash/src/web/ui/controls/TextInput.tsx +0 -67
- package/bizar-dash/src/web/ui/controls/Textarea.tsx +0 -56
- package/bizar-dash/src/web/ui/controls/Toggle.tsx +0 -79
- package/bizar-dash/src/web/ui/controls/controls.css +0 -476
- package/bizar-dash/src/web/ui/controls/index.ts +0 -35
- package/bizar-dash/src/web/ui/data/BarChart.tsx +0 -60
- package/bizar-dash/src/web/ui/data/DataTable.tsx +0 -216
- package/bizar-dash/src/web/ui/data/EmptyState.tsx +0 -60
- package/bizar-dash/src/web/ui/data/ErrorState.tsx +0 -56
- package/bizar-dash/src/web/ui/data/KeyValueList.tsx +0 -106
- package/bizar-dash/src/web/ui/data/LoadingState.tsx +0 -65
- package/bizar-dash/src/web/ui/data/Sparkline.tsx +0 -87
- package/bizar-dash/src/web/ui/data/StatTile.tsx +0 -87
- package/bizar-dash/src/web/ui/data/data.css +0 -540
- package/bizar-dash/src/web/ui/data/index.ts +0 -31
- package/bizar-dash/src/web/ui/feedback/Badge.tsx +0 -49
- package/bizar-dash/src/web/ui/feedback/Dialog.tsx +0 -209
- package/bizar-dash/src/web/ui/feedback/ProgressBar.tsx +0 -69
- package/bizar-dash/src/web/ui/feedback/StatusDot.tsx +0 -50
- package/bizar-dash/src/web/ui/feedback/Toast.tsx +0 -200
- package/bizar-dash/src/web/ui/feedback/Tooltip.tsx +0 -126
- package/bizar-dash/src/web/ui/feedback/feedback.css +0 -314
- package/bizar-dash/src/web/ui/feedback/index.ts +0 -43
- package/bizar-dash/src/web/ui/index.ts +0 -57
- package/bizar-dash/src/web/ui/layout/AppShell.tsx +0 -51
- package/bizar-dash/src/web/ui/layout/Breadcrumbs.tsx +0 -97
- package/bizar-dash/src/web/ui/layout/Panel.tsx +0 -73
- package/bizar-dash/src/web/ui/layout/PanelHeader.tsx +0 -39
- package/bizar-dash/src/web/ui/layout/Sidebar.tsx +0 -131
- package/bizar-dash/src/web/ui/layout/Tabs.tsx +0 -133
- package/bizar-dash/src/web/ui/layout/Topbar.tsx +0 -42
- package/bizar-dash/src/web/ui/layout/ViewHeader.tsx +0 -48
- package/bizar-dash/src/web/ui/layout/index.ts +0 -34
- package/bizar-dash/src/web/ui/layout/layout.css +0 -464
- package/bizar-dash/src/web/ui/navigation/CommandPalette.tsx +0 -199
- package/bizar-dash/src/web/ui/navigation/NavGroup.tsx +0 -95
- package/bizar-dash/src/web/ui/navigation/NavLink.tsx +0 -93
- package/bizar-dash/src/web/ui/navigation/index.ts +0 -17
- package/bizar-dash/src/web/ui/navigation/navigation.css +0 -343
- package/bizar-dash/src/web/ui/primitives/Box.tsx +0 -91
- package/bizar-dash/src/web/ui/primitives/Grid.tsx +0 -49
- package/bizar-dash/src/web/ui/primitives/Inline.tsx +0 -55
- package/bizar-dash/src/web/ui/primitives/Separator.tsx +0 -46
- package/bizar-dash/src/web/ui/primitives/Stack.tsx +0 -54
- package/bizar-dash/src/web/ui/primitives/VisuallyHidden.tsx +0 -26
- package/bizar-dash/src/web/ui/primitives/index.ts +0 -23
- package/bizar-dash/src/web/ui/primitives/primitives.css +0 -183
- package/bizar-dash/src/web/ui/styles/globals.css +0 -86
- package/bizar-dash/src/web/ui/styles/reset.css +0 -125
- package/bizar-dash/src/web/ui/styles/tokens.css +0 -208
- package/bizar-dash/src/web/ui/theme/ThemeProvider.tsx +0 -142
- package/bizar-dash/src/web/ui/theme/tokens.ts +0 -131
- package/bizar-dash/src/web/ui/theme/useTheme.ts +0 -22
- package/bizar-dash/src/web/ui/utils/cx.ts +0 -42
- package/bizar-dash/src/web/views/Activity.tsx +0 -1221
- package/bizar-dash/src/web/views/Agents.tsx +0 -964
- package/bizar-dash/src/web/views/Artifacts.tsx +0 -1494
- package/bizar-dash/src/web/views/BackgroundAgents.tsx +0 -822
- package/bizar-dash/src/web/views/Chat.tsx +0 -532
- package/bizar-dash/src/web/views/Config.tsx +0 -3
- package/bizar-dash/src/web/views/Doctor.tsx +0 -317
- package/bizar-dash/src/web/views/Eval.tsx +0 -372
- package/bizar-dash/src/web/views/EvalReport.tsx +0 -353
- package/bizar-dash/src/web/views/GoalPlanner.tsx +0 -158
- package/bizar-dash/src/web/views/Harness.tsx +0 -306
- package/bizar-dash/src/web/views/History.tsx +0 -353
- package/bizar-dash/src/web/views/Memory.tsx +0 -193
- package/bizar-dash/src/web/views/MiniMaxUsage.tsx +0 -942
- package/bizar-dash/src/web/views/ModView.tsx +0 -207
- package/bizar-dash/src/web/views/Mods.tsx +0 -706
- package/bizar-dash/src/web/views/Overview.tsx +0 -1343
- package/bizar-dash/src/web/views/Providers.tsx +0 -302
- package/bizar-dash/src/web/views/Schedules.tsx +0 -902
- package/bizar-dash/src/web/views/Settings.tsx +0 -308
- package/bizar-dash/src/web/views/Skills.tsx +0 -383
- package/bizar-dash/src/web/views/SpawnAgentModal.tsx +0 -221
- package/bizar-dash/src/web/views/Tasks.tsx +0 -789
- package/bizar-dash/src/web/views/Workspace.tsx +0 -294
- package/bizar-dash/src/web/views/glyphs/GlyphRenderer.tsx +0 -844
- package/bizar-dash/src/web/views/glyphs/components.tsx +0 -1098
- package/bizar-dash/src/web/views/memory/ConfigPanel.tsx +0 -426
- package/bizar-dash/src/web/views/memory/FromScreenshotPanel.tsx +0 -23
- package/bizar-dash/src/web/views/memory/GitSyncPanel.tsx +0 -220
- package/bizar-dash/src/web/views/memory/LightragPanel.tsx +0 -310
- package/bizar-dash/src/web/views/memory/MemoryGraphLegend.tsx +0 -29
- package/bizar-dash/src/web/views/memory/MemoryGraphPanel.tsx +0 -192
- package/bizar-dash/src/web/views/memory/MemoryGraphView.tsx +0 -336
- package/bizar-dash/src/web/views/memory/MemoryOverview.tsx +0 -367
- package/bizar-dash/src/web/views/memory/MemoryStatusCard.tsx +0 -160
- package/bizar-dash/src/web/views/memory/ObsidianPanel.tsx +0 -650
- package/bizar-dash/src/web/views/memory/SemanticSearchPanel.tsx +0 -197
- package/bizar-dash/src/web/views/memory/VaultFromClipboardPanel.tsx +0 -101
- package/bizar-dash/src/web/views/settings/ActivitySection.tsx +0 -205
- package/bizar-dash/src/web/views/settings/AgentSection.tsx +0 -305
- package/bizar-dash/src/web/views/settings/AuthSection.tsx +0 -159
- package/bizar-dash/src/web/views/settings/EnvVarsSection.tsx +0 -15
- package/bizar-dash/src/web/views/settings/GeneralSection.tsx +0 -128
- package/bizar-dash/src/web/views/settings/HeadroomSection.tsx +0 -39
- package/bizar-dash/src/web/views/settings/MemorySection.tsx +0 -154
- package/bizar-dash/src/web/views/settings/NetworkSection.tsx +0 -87
- package/bizar-dash/src/web/views/settings/NotificationsSection.tsx +0 -34
- package/bizar-dash/src/web/views/settings/SystemLlmSection.tsx +0 -81
- package/bizar-dash/src/web/views/settings/ThemeSection.tsx +0 -168
- package/bizar-dash/src/web/views/settings/UpdatesSection.tsx +0 -256
- package/bizar-dash/src/web/views/settings/WorkspacesSection.tsx +0 -189
- package/packages/sdk/.harness/agents.json +0 -17
- package/packages/sdk/.harness/topology.json +0 -4
- /package/bizar-dash/tests/{BackgroundAgents.test.tsx → v7-archive/BackgroundAgents.test.tsx} +0 -0
- /package/bizar-dash/tests/{a11y → v7-archive/a11y}/forms.test.tsx +0 -0
- /package/bizar-dash/tests/{a11y.test.tsx → v7-archive/a11y.test.tsx} +0 -0
- /package/bizar-dash/tests/{autosave.test.tsx → v7-archive/autosave.test.tsx} +0 -0
- /package/bizar-dash/tests/{backup-restore.test.tsx → v7-archive/backup-restore.test.tsx} +0 -0
- /package/bizar-dash/tests/{chat-composer.test.tsx → v7-archive/chat-composer.test.tsx} +0 -0
- /package/bizar-dash/tests/{communication-log.test.tsx → v7-archive/communication-log.test.tsx} +0 -0
- /package/bizar-dash/tests/{components → v7-archive/components}/Modal.test.tsx +0 -0
- /package/bizar-dash/tests/{components → v7-archive/components}/Spinner.test.tsx +0 -0
- /package/bizar-dash/tests/{components → v7-archive/components}/StatusBadge.test.tsx +0 -0
- /package/bizar-dash/tests/{components → v7-archive/components}/doctor-panel.test.tsx +0 -0
- /package/bizar-dash/tests/{components → v7-archive/components}/screenshot-ocr.test.tsx +0 -0
- /package/bizar-dash/tests/{components → v7-archive/components}/settings-search.test.tsx +0 -0
- /package/bizar-dash/tests/{components → v7-archive/components}/workspace-selector.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/controls/Button.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/controls/Checkbox.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/controls/IconButton.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/controls/Kbd.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/controls/NumberInput.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/controls/RadioGroup.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/controls/SearchInput.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/controls/Select.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/controls/Slider.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/controls/TextInput.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/controls/Textarea.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/controls/Toggle.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/data/BarChart.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/data/DataTable.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/data/EmptyState.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/data/ErrorState.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/data/KeyValueList.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/data/LoadingState.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/data/Sparkline.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/data/StatTile.test.tsx +0 -0
- /package/bizar-dash/tests/{dep-graph.test.tsx → v7-archive/dep-graph.test.tsx} +0 -0
- /package/bizar-dash/tests/{eval-web-ui.test.tsx → v7-archive/eval-web-ui.test.tsx} +0 -0
- /package/bizar-dash/tests/{event-log.test.tsx → v7-archive/event-log.test.tsx} +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/feedback/Badge.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/feedback/Dialog.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/feedback/ProgressBar.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/feedback/StatusDot.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/feedback/Toast.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/feedback/Tooltip.test.tsx +0 -0
- /package/bizar-dash/tests/{goal-input.test.tsx → v7-archive/goal-input.test.tsx} +0 -0
- /package/bizar-dash/tests/{goap-planner.test.ts → v7-archive/goap-planner.test.ts} +0 -0
- /package/bizar-dash/tests/{hooks → v7-archive/hooks}/useModal.test.tsx +0 -0
- /package/bizar-dash/tests/{hooks → v7-archive/hooks}/useToast.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/layout/AppShell.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/layout/Breadcrumbs.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/layout/Panel.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/layout/PanelHeader.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/layout/Sidebar.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/layout/Tabs.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/layout/Topbar.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/layout/ViewHeader.test.tsx +0 -0
- /package/bizar-dash/tests/{lib → v7-archive/lib}/i18n.test.ts +0 -0
- /package/bizar-dash/tests/{lib → v7-archive/lib}/search-fuzzy.test.ts +0 -0
- /package/bizar-dash/tests/{lib → v7-archive/lib}/utils.test.ts +0 -0
- /package/bizar-dash/tests/{memory-graph-view.test.tsx → v7-archive/memory-graph-view.test.tsx} +0 -0
- /package/bizar-dash/tests/{mobile-chat.test.tsx → v7-archive/mobile-chat.test.tsx} +0 -0
- /package/bizar-dash/tests/{mobile-layout.test.tsx → v7-archive/mobile-layout.test.tsx} +0 -0
- /package/bizar-dash/tests/{mobile-overview.test.tsx → v7-archive/mobile-overview.test.tsx} +0 -0
- /package/bizar-dash/tests/{mobile-settings.test.tsx → v7-archive/mobile-settings.test.tsx} +0 -0
- /package/bizar-dash/tests/{mobile-tasks.test.tsx → v7-archive/mobile-tasks.test.tsx} +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/navigation/CommandPalette.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/navigation/NavGroup.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive}/navigation/NavLink.test.tsx +0 -0
- /package/bizar-dash/tests/{quality-gates.test.tsx → v7-archive/quality-gates.test.tsx} +0 -0
- /package/bizar-dash/tests/{settings-layout.test.tsx → v7-archive/settings-layout.test.tsx} +0 -0
- /package/bizar-dash/tests/{settings-mode-wiring.test.tsx → v7-archive/settings-mode-wiring.test.tsx} +0 -0
- /package/bizar-dash/tests/{settings-nav.test.tsx → v7-archive/settings-nav.test.tsx} +0 -0
- /package/bizar-dash/tests/{ui → v7-archive/ui}/primitives/Box.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive/ui}/primitives/Grid.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive/ui}/primitives/Inline.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive/ui}/primitives/Separator.test.tsx +0 -0
- /package/bizar-dash/tests/{ui → v7-archive/ui}/primitives/Stack.test.tsx +0 -0
- /package/bizar-dash/tests/{views → v7-archive/views}/Agents.test.tsx +0 -0
- /package/bizar-dash/tests/{views → v7-archive/views}/Memory.test.tsx +0 -0
- /package/bizar-dash/tests/{views → v7-archive/views}/Overview.test.tsx +0 -0
- /package/bizar-dash/tests/{views → v7-archive/views}/Tasks.test.tsx +0 -0
- /package/bizar-dash/tests/{views → v7-archive/views}/sidebar.test.tsx +0 -0
- /package/bizar-dash/tests/{views → v7-archive/views}/topbar.test.tsx +0 -0
- /package/bizar-dash/tests/{voice-recorder.test.tsx → v7-archive/voice-recorder.test.tsx} +0 -0
|
@@ -1,1190 +0,0 @@
|
|
|
1
|
-
// src/components/chat/useChat.ts — shared chat state: messages, sessions,
|
|
2
|
-
// send, polling, SSE, session-state tracking.
|
|
3
|
-
//
|
|
4
|
-
// v6.3.0 — Claude Code migration. Supports two parallel message streams:
|
|
5
|
-
// - bizar (GET /api/chat)
|
|
6
|
-
// - claude (GET /api/claude-sessions/:id/messages + SSE)
|
|
7
|
-
//
|
|
8
|
-
// Changes from v4.2.5:
|
|
9
|
-
// * Endpoint prefix changed: `/api/claude-sessions/*` → `/api/claude-sessions/*`
|
|
10
|
-
// * SSE event type names changed to match the Claude SDK envelope
|
|
11
|
-
// (`message.part.updated` → `delta`/`text_delta`, etc.)
|
|
12
|
-
// * Server no longer needs the `clineErrorInfo` 503 path; the
|
|
13
|
-
// `claudeErrorInfo` field stays for parity but the dashboard
|
|
14
|
-
// mostly sees 502s now (claude CLI not on PATH / spawn failed).
|
|
15
|
-
// * Optimistic send uses a stable `msg_*` ID and is deduped when
|
|
16
|
-
// claude echoes the message back via SDK events.
|
|
17
|
-
// * `claudeMessages` keeps server-provided IDs distinct from
|
|
18
|
-
// optimistic IDs so the merge is unambiguous (server echo
|
|
19
|
-
// replaces optimistic by matching messageID; otherwise both stick
|
|
20
|
-
// around briefly until the user/session state catches up).
|
|
21
|
-
// * `onSend` routes to `/claude-sessions/:id/send` when a
|
|
22
|
-
// claude session is active, `/chat` otherwise. Errors surface
|
|
23
|
-
// via toast + we always remove the optimistic placeholder.
|
|
24
|
-
// * Sessions are managed by source:
|
|
25
|
-
// - `bizarSessions` → local .jsonl store, POST /chat/sessions
|
|
26
|
-
// - `claudeSessions` → Claude Code, GET /claude-sessions
|
|
27
|
-
// The rail shows both side-by-side with a source indicator and
|
|
28
|
-
// uses separate rename/delete endpoints per source.
|
|
29
|
-
// * All async actions surface a single `busy: { create, send, rename, delete }`
|
|
30
|
-
// so the rail can disable buttons properly.
|
|
31
|
-
// * No `any` leaks — all SSE event shapes are typed via
|
|
32
|
-
// `ClineSseEnvelope`.
|
|
33
|
-
|
|
34
|
-
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
35
|
-
import type {
|
|
36
|
-
ChatMessage,
|
|
37
|
-
ChatResponse,
|
|
38
|
-
ChatSession,
|
|
39
|
-
Settings,
|
|
40
|
-
Snapshot,
|
|
41
|
-
} from '../../lib/types';
|
|
42
|
-
import { api, ApiError } from '../../lib/api';
|
|
43
|
-
import type { SessionState } from './ChatRail';
|
|
44
|
-
import type { AgentTreeNode } from './AgentNode';
|
|
45
|
-
|
|
46
|
-
export interface SessionDisplayState {
|
|
47
|
-
/** idle / streaming / awaiting — derived from the latest SSE event. */
|
|
48
|
-
state: SessionState;
|
|
49
|
-
/** Number of unread (i.e. arrived while the user wasn't viewing) messages. */
|
|
50
|
-
unread: number;
|
|
51
|
-
/** Pinned? (cosmetic for now; pinned state lives in the parent.) */
|
|
52
|
-
pinned: boolean;
|
|
53
|
-
/** Sub-agent tree, if any. */
|
|
54
|
-
tree?: { root: AgentTreeNode };
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/** Per-source action busy flags. Used by rail/info-panel to disable buttons. */
|
|
58
|
-
export interface ChatBusyState {
|
|
59
|
-
create: boolean;
|
|
60
|
-
send: boolean;
|
|
61
|
-
rename: boolean;
|
|
62
|
-
delete: boolean;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Structured error envelope surfaced by `loadClineSession` when
|
|
67
|
-
* the upstream `/api/claude-sessions/:id/messages` call fails.
|
|
68
|
-
*
|
|
69
|
-
* - `code` mirrors the server's `error` field (`plugin_offline`,
|
|
70
|
-
* `directory_unknown`, `cline_error`, `bad_request`).
|
|
71
|
-
* - `cause` is the server's structured cause (`network`, `timeout`,
|
|
72
|
-
* `unknown`, or a raw ECONNREFUSED-style string).
|
|
73
|
-
* - `suggestion` is the operator-friendly hint from the server
|
|
74
|
-
* (e.g. "Run `bizar doctor` for diagnostics").
|
|
75
|
-
* - `canRetry` is `true` whenever the failure is transient (network
|
|
76
|
-
* error, upstream 502) — i.e. the user can fix it by trying again
|
|
77
|
-
* after starting the plugin / waiting for cline to come back.
|
|
78
|
-
* False for hard failures (bad_request).
|
|
79
|
-
*/
|
|
80
|
-
export interface ClineErrorInfo {
|
|
81
|
-
type: 'session_load_failed';
|
|
82
|
-
code: string;
|
|
83
|
-
message: string;
|
|
84
|
-
cause?: string;
|
|
85
|
-
status?: number;
|
|
86
|
-
suggestion?: string | null;
|
|
87
|
-
canRetry: boolean;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/** Shape of one cline SSE envelope after unwrapping. */
|
|
91
|
-
interface ClineSseEnvelope {
|
|
92
|
-
type: string;
|
|
93
|
-
sessionID?: string;
|
|
94
|
-
messageID?: string;
|
|
95
|
-
/** Raw upstream payload (kept for forwarders that want full fidelity). */
|
|
96
|
-
data?: unknown;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* The chat hook returns a stable bag of state + actions used by
|
|
101
|
-
* both Chat.tsx (desktop) and MobileChat.tsx (mobile).
|
|
102
|
-
*
|
|
103
|
-
* The hook owns the lifecycle of the cline SSE stream. Callers
|
|
104
|
-
* should never instantiate their own EventSource for the same
|
|
105
|
-
* session — they should always go through this hook.
|
|
106
|
-
*/
|
|
107
|
-
export function useChat(snapshot: Snapshot, settings: Settings, initialTaskId?: string | null) {
|
|
108
|
-
// ── Bizar stream ────────────────────────────────────────────────────────────
|
|
109
|
-
const [bizarMessages, setBizarMessages] = useState<ChatMessage[]>([]);
|
|
110
|
-
const [sessions, setSessions] = useState<ChatSession[]>([]);
|
|
111
|
-
const [sessionId, setSessionId] = useState('');
|
|
112
|
-
const [loading, setLoading] = useState(true);
|
|
113
|
-
const [busy, setBusy] = useState<ChatBusyState>({
|
|
114
|
-
create: false,
|
|
115
|
-
send: false,
|
|
116
|
-
rename: false,
|
|
117
|
-
delete: false,
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
// ── Cline stream ─────────────────────────────────────────────────────────
|
|
121
|
-
const [clineSessions, setClineSessions] = useState<ChatSession[]>([]);
|
|
122
|
-
const [clineMessages, setClineMessages] = useState<ChatMessage[]>([]);
|
|
123
|
-
const [activeSource, setActiveSource] = useState<'bizar' | 'cline' | null>(null);
|
|
124
|
-
const [activeClineSessionId, setActiveClineSessionId] = useState<string | null>(null);
|
|
125
|
-
const [clineError, setClineError] = useState<string | null>(null);
|
|
126
|
-
const [clineSuggestion, setClineSuggestion] = useState<string | null>(null);
|
|
127
|
-
/**
|
|
128
|
-
* Structured error info for the cline session load path. New in
|
|
129
|
-
* v5.0.0 — `ChatInfoPanel` consumes this to render its own error
|
|
130
|
-
* section (in addition to the chat-thread-header error already
|
|
131
|
-
* rendered by Chat.tsx). `null` when no error.
|
|
132
|
-
*/
|
|
133
|
-
const [clineErrorInfo, setClineErrorInfo] = useState<ClineErrorInfo | null>(null);
|
|
134
|
-
|
|
135
|
-
// ── v3.22 — session-state, unread, tree per session ────────────────────────
|
|
136
|
-
const [sessionStates, setSessionStates] = useState<Record<string, SessionDisplayState>>({});
|
|
137
|
-
const [stickToBottom, setStickToBottom] = useState(true);
|
|
138
|
-
const [newMessageCount, setNewMessageCount] = useState(0);
|
|
139
|
-
|
|
140
|
-
// Set of messageIDs the user has already accepted (or that arrived
|
|
141
|
-
// via SSE) — used by the cline path to dedupe optimistic + echo.
|
|
142
|
-
const [seenClineMessages, setSeenClineMessages] = useState<Set<string>>(new Set());
|
|
143
|
-
|
|
144
|
-
// Backwards-compat alias (chat.sendSession delete etc. used `pinned` historically).
|
|
145
|
-
const [pinned, setPinned] = useState<Set<number>>(new Set());
|
|
146
|
-
|
|
147
|
-
const listRef = useRef<HTMLDivElement>(null);
|
|
148
|
-
const toastRef = useRef<
|
|
149
|
-
| {
|
|
150
|
-
error: (msg: string) => void;
|
|
151
|
-
success: (msg: string) => void;
|
|
152
|
-
info: (msg: string) => void;
|
|
153
|
-
warning: (msg: string) => void;
|
|
154
|
-
}
|
|
155
|
-
| null
|
|
156
|
-
>(null);
|
|
157
|
-
|
|
158
|
-
// ── SSE lifecycle refs ──────────────────────────────────────────────────────
|
|
159
|
-
const clineEsRef = useRef<EventSource | null>(null);
|
|
160
|
-
const sseReconnectAttemptRef = useRef(0);
|
|
161
|
-
const sseReconnectTimerRef = useRef<number | null>(null);
|
|
162
|
-
// The id of the session we're CURRENTLY streaming. When the user
|
|
163
|
-
// switches sessions, this id changes and the SSE handler short-
|
|
164
|
-
// circuits any in-flight appends.
|
|
165
|
-
const sseCurrentSessionIdRef = useRef<string | null>(null);
|
|
166
|
-
// Whether the SSE connection should be auto-reconnected on error.
|
|
167
|
-
// Set to false on explicit disconnect (session switch / unmount).
|
|
168
|
-
const sseAutoReconnectRef = useRef(false);
|
|
169
|
-
|
|
170
|
-
/** Append `msg` to `clineMessages`, replacing any prior
|
|
171
|
-
* optimistic entry whose content matches or whose ID matches. */
|
|
172
|
-
const appendClineMessage = useCallback((msg: ChatMessage) => {
|
|
173
|
-
if (!msg) return;
|
|
174
|
-
setClineMessages((cur) => {
|
|
175
|
-
// Existing exact-ID match: skip.
|
|
176
|
-
if (msg.id && cur.some((m) => m.id === msg.id)) return cur;
|
|
177
|
-
// Optimistic placeholder (starts with msg_) with the same role
|
|
178
|
-
// and content: replace it. This is how cline's echo of our
|
|
179
|
-
// own message gets deduplicated against the optimistic copy.
|
|
180
|
-
const idx = cur.findIndex(
|
|
181
|
-
(m) =>
|
|
182
|
-
typeof m.id === 'string' &&
|
|
183
|
-
m.id.startsWith('msg_') &&
|
|
184
|
-
m.role === msg.role &&
|
|
185
|
-
(m.content || '') === (msg.content || ''),
|
|
186
|
-
);
|
|
187
|
-
if (idx >= 0) {
|
|
188
|
-
const next = cur.slice();
|
|
189
|
-
next[idx] = { ...msg, id: msg.id ?? cur[idx].id };
|
|
190
|
-
return next;
|
|
191
|
-
}
|
|
192
|
-
return [...cur, msg];
|
|
193
|
-
});
|
|
194
|
-
}, []);
|
|
195
|
-
|
|
196
|
-
/** Mark a messageID as seen — used to dedupe echo rounds. */
|
|
197
|
-
const markSeen = useCallback((id: string | undefined) => {
|
|
198
|
-
if (!id) return;
|
|
199
|
-
setSeenClineMessages((cur) => {
|
|
200
|
-
if (cur.has(id)) return cur;
|
|
201
|
-
const next = new Set(cur);
|
|
202
|
-
next.add(id);
|
|
203
|
-
return next;
|
|
204
|
-
});
|
|
205
|
-
}, []);
|
|
206
|
-
|
|
207
|
-
// ── Helpers to mutate per-session state ────────────────────────────────────
|
|
208
|
-
const setSessionDisplayState = useCallback(
|
|
209
|
-
(id: string, patch: Partial<SessionDisplayState>) => {
|
|
210
|
-
setSessionStates((cur) => {
|
|
211
|
-
const prev: SessionDisplayState =
|
|
212
|
-
cur[id] ?? { state: 'idle', unread: 0, pinned: false };
|
|
213
|
-
return { ...cur, [id]: { ...prev, ...patch } };
|
|
214
|
-
});
|
|
215
|
-
},
|
|
216
|
-
[],
|
|
217
|
-
);
|
|
218
|
-
|
|
219
|
-
const markSessionStreaming = useCallback(
|
|
220
|
-
(id: string, streaming: boolean) => {
|
|
221
|
-
setSessionDisplayState(id, { state: streaming ? 'streaming' : 'idle' });
|
|
222
|
-
},
|
|
223
|
-
[setSessionDisplayState],
|
|
224
|
-
);
|
|
225
|
-
|
|
226
|
-
/** ─── Toast binding (set by the consuming view via `setToast`) ──── */
|
|
227
|
-
const setToast = useCallback(
|
|
228
|
-
(toast: typeof toastRef.current) => {
|
|
229
|
-
toastRef.current = toast;
|
|
230
|
-
},
|
|
231
|
-
[],
|
|
232
|
-
);
|
|
233
|
-
|
|
234
|
-
// ── Load bizar chat ─────────────────────────────────────────────────────────
|
|
235
|
-
const loadChat = useCallback(
|
|
236
|
-
async (sid?: string) => {
|
|
237
|
-
try {
|
|
238
|
-
const url = sid
|
|
239
|
-
? `/chat?session=${encodeURIComponent(sid)}`
|
|
240
|
-
: '/chat?limit=200';
|
|
241
|
-
const data = await api.get<ChatResponse>(url);
|
|
242
|
-
setBizarMessages(data.messages || []);
|
|
243
|
-
setSessions(data.sessions || []);
|
|
244
|
-
} catch (err) {
|
|
245
|
-
toastRef.current?.error(
|
|
246
|
-
`Chat load failed: ${(err as Error).message}`,
|
|
247
|
-
);
|
|
248
|
-
} finally {
|
|
249
|
-
setLoading(false);
|
|
250
|
-
}
|
|
251
|
-
},
|
|
252
|
-
[],
|
|
253
|
-
);
|
|
254
|
-
|
|
255
|
-
const loadTaskChat = useCallback(async (taskId: string) => {
|
|
256
|
-
setLoading(true);
|
|
257
|
-
try {
|
|
258
|
-
const data = await api.get<{
|
|
259
|
-
sessionId?: string;
|
|
260
|
-
messages: ChatMessage[];
|
|
261
|
-
}>(`/tasks/${encodeURIComponent(taskId)}/chat`);
|
|
262
|
-
setBizarMessages(data.messages || []);
|
|
263
|
-
setSessionId(data.sessionId || taskId);
|
|
264
|
-
} catch (err) {
|
|
265
|
-
toastRef.current?.error(
|
|
266
|
-
`Task chat load failed: ${(err as Error).message}`,
|
|
267
|
-
);
|
|
268
|
-
} finally {
|
|
269
|
-
setLoading(false);
|
|
270
|
-
}
|
|
271
|
-
}, []);
|
|
272
|
-
|
|
273
|
-
const refreshSessions = useCallback(async () => {
|
|
274
|
-
try {
|
|
275
|
-
const data = await api.get<{ sessions: ChatSession[] }>('/chat/sessions');
|
|
276
|
-
setSessions(data.sessions || []);
|
|
277
|
-
} catch {
|
|
278
|
-
/* best-effort */
|
|
279
|
-
}
|
|
280
|
-
}, []);
|
|
281
|
-
|
|
282
|
-
const refreshClineSessions = useCallback(async () => {
|
|
283
|
-
try {
|
|
284
|
-
const data = await api.get<{ sessions: ChatSession[] }>(
|
|
285
|
-
'/claude-sessions',
|
|
286
|
-
);
|
|
287
|
-
// Enrich with source marker.
|
|
288
|
-
const enriched: ChatSession[] = (data.sessions || []).map((s) => ({
|
|
289
|
-
...s,
|
|
290
|
-
source: 'cline' as const,
|
|
291
|
-
title: s.title || s.id,
|
|
292
|
-
}));
|
|
293
|
-
setClineSessions(enriched);
|
|
294
|
-
} catch {
|
|
295
|
-
/* best-effort */
|
|
296
|
-
}
|
|
297
|
-
}, []);
|
|
298
|
-
|
|
299
|
-
// ── Cline SSE connection ─────────────────────────────────────────────────
|
|
300
|
-
//
|
|
301
|
-
// Single source of truth for the EventSource lifecycle. Callers:
|
|
302
|
-
// - `loadClineSession(id)` — close any current, open a new one.
|
|
303
|
-
// - `closeClineSession()` — close and stop auto-reconnect.
|
|
304
|
-
// - unmount — close and stop.
|
|
305
|
-
//
|
|
306
|
-
// On error / network drop, the EventSource triggers `onerror`. We
|
|
307
|
-
// close the connection and schedule a reconnect (with exponential
|
|
308
|
-
// backoff: 1s, 2s, 4s, …, capped at 30s) UNLESS `sseAutoReconnectRef`
|
|
309
|
-
// is false (explicit disconnect).
|
|
310
|
-
//
|
|
311
|
-
const openSseForSession = useCallback(
|
|
312
|
-
(id: string) => {
|
|
313
|
-
// Close any existing connection first.
|
|
314
|
-
if (clineEsRef.current) {
|
|
315
|
-
try {
|
|
316
|
-
clineEsRef.current.close();
|
|
317
|
-
} catch {
|
|
318
|
-
/* noop */
|
|
319
|
-
}
|
|
320
|
-
clineEsRef.current = null;
|
|
321
|
-
}
|
|
322
|
-
if (sseReconnectTimerRef.current !== null) {
|
|
323
|
-
clearTimeout(sseReconnectTimerRef.current);
|
|
324
|
-
sseReconnectTimerRef.current = null;
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
// Build the SSE URL. EventSource can't set headers, so we
|
|
328
|
-
// pass the auth token as ?token= when set (loopback makes this
|
|
329
|
-
// optional, but harmless).
|
|
330
|
-
const tok = api.getToken();
|
|
331
|
-
const url = tok
|
|
332
|
-
? `/api/claude-sessions/${encodeURIComponent(id)}/stream?token=${encodeURIComponent(tok)}`
|
|
333
|
-
: `/api/claude-sessions/${encodeURIComponent(id)}/stream`;
|
|
334
|
-
|
|
335
|
-
sseCurrentSessionIdRef.current = id;
|
|
336
|
-
sseAutoReconnectRef.current = true;
|
|
337
|
-
sseReconnectAttemptRef.current = 0;
|
|
338
|
-
setClineError(null);
|
|
339
|
-
setClineSuggestion(null);
|
|
340
|
-
setClineErrorInfo(null);
|
|
341
|
-
|
|
342
|
-
const connect = () => {
|
|
343
|
-
if (!sseAutoReconnectRef.current) return;
|
|
344
|
-
if (sseCurrentSessionIdRef.current !== id) return;
|
|
345
|
-
const es = new EventSource(url);
|
|
346
|
-
clineEsRef.current = es;
|
|
347
|
-
|
|
348
|
-
// Helper: dispatch one parsed envelope to local state.
|
|
349
|
-
const onEnvelope = (evt: ClineSseEnvelope | null) => {
|
|
350
|
-
if (!evt || !evt.type) return;
|
|
351
|
-
// Drop events for OTHER sessions even though the proxy
|
|
352
|
-
// already filters — defense in depth.
|
|
353
|
-
if (evt.sessionID && evt.sessionID !== id) return;
|
|
354
|
-
|
|
355
|
-
const ts = new Date().toISOString();
|
|
356
|
-
const sidForState = id;
|
|
357
|
-
|
|
358
|
-
if (
|
|
359
|
-
evt.type === 'message.user.created' ||
|
|
360
|
-
evt.type === 'message.user.updated'
|
|
361
|
-
) {
|
|
362
|
-
const payload = evt.data as
|
|
363
|
-
| { messageID?: string; data?: { content?: string } }
|
|
364
|
-
| undefined;
|
|
365
|
-
appendClineMessage({
|
|
366
|
-
id: payload?.messageID ?? evt.messageID,
|
|
367
|
-
role: 'user',
|
|
368
|
-
content: payload?.data?.content ?? '',
|
|
369
|
-
ts,
|
|
370
|
-
});
|
|
371
|
-
markSeen(payload?.messageID ?? evt.messageID);
|
|
372
|
-
return;
|
|
373
|
-
}
|
|
374
|
-
if (
|
|
375
|
-
evt.type === 'message.assistant.created' ||
|
|
376
|
-
evt.type === 'message.assistant.updated'
|
|
377
|
-
) {
|
|
378
|
-
const payload = evt.data as
|
|
379
|
-
| { messageID?: string; data?: { content?: string } }
|
|
380
|
-
| undefined;
|
|
381
|
-
appendClineMessage({
|
|
382
|
-
id: payload?.messageID ?? evt.messageID,
|
|
383
|
-
role: 'assistant',
|
|
384
|
-
content: payload?.data?.content ?? '',
|
|
385
|
-
ts,
|
|
386
|
-
});
|
|
387
|
-
markSeen(payload?.messageID ?? evt.messageID);
|
|
388
|
-
markSessionStreaming(sidForState, true);
|
|
389
|
-
return;
|
|
390
|
-
}
|
|
391
|
-
if (evt.type === 'message.part.updated') {
|
|
392
|
-
const payload = evt.data as
|
|
393
|
-
| {
|
|
394
|
-
part?: { type?: string; text?: string };
|
|
395
|
-
messageID?: string;
|
|
396
|
-
id?: string;
|
|
397
|
-
}
|
|
398
|
-
| undefined;
|
|
399
|
-
const text = payload?.part?.text ?? '';
|
|
400
|
-
if (!text) return;
|
|
401
|
-
appendClineMessage({
|
|
402
|
-
id: payload?.id ?? payload?.messageID ?? evt.messageID,
|
|
403
|
-
role: 'assistant',
|
|
404
|
-
content: text,
|
|
405
|
-
ts,
|
|
406
|
-
});
|
|
407
|
-
markSeen(payload?.id ?? payload?.messageID ?? evt.messageID);
|
|
408
|
-
markSessionStreaming(sidForState, true);
|
|
409
|
-
return;
|
|
410
|
-
}
|
|
411
|
-
if (
|
|
412
|
-
evt.type === 'session.idle' ||
|
|
413
|
-
evt.type === 'message.assistant.completed' ||
|
|
414
|
-
evt.type === 'session.completed'
|
|
415
|
-
) {
|
|
416
|
-
markSessionStreaming(sidForState, false);
|
|
417
|
-
return;
|
|
418
|
-
}
|
|
419
|
-
if (
|
|
420
|
-
evt.type === 'session.awaiting' ||
|
|
421
|
-
evt.type === 'session.awaiting_input' ||
|
|
422
|
-
evt.type === 'message.assistant.awaiting'
|
|
423
|
-
) {
|
|
424
|
-
setSessionDisplayState(sidForState, { state: 'awaiting' });
|
|
425
|
-
return;
|
|
426
|
-
}
|
|
427
|
-
if (evt.type === 'session.error') {
|
|
428
|
-
setClineError(
|
|
429
|
-
(evt.data as { message?: string } | undefined)?.message ||
|
|
430
|
-
'cline session error',
|
|
431
|
-
);
|
|
432
|
-
return;
|
|
433
|
-
}
|
|
434
|
-
// Other event types are intentionally ignored — the proxy
|
|
435
|
-
// is canonical, we don't need to project every upstream
|
|
436
|
-
// event into local state.
|
|
437
|
-
};
|
|
438
|
-
|
|
439
|
-
// Stable parser — the server may send both `{type: "x"}` and
|
|
440
|
-
// `sync` envelopes with a `.<n>` version suffix. We accept both.
|
|
441
|
-
const parseData = (raw: string | null | undefined):
|
|
442
|
-
| ClineSseEnvelope
|
|
443
|
-
| null => {
|
|
444
|
-
if (!raw) return null;
|
|
445
|
-
try {
|
|
446
|
-
const parsed = JSON.parse(raw) as Record<string, unknown>;
|
|
447
|
-
// Direct shape: {type, properties: {...}}
|
|
448
|
-
if (typeof parsed.type === 'string') {
|
|
449
|
-
const props = parsed.properties as
|
|
450
|
-
| Record<string, unknown>
|
|
451
|
-
| undefined;
|
|
452
|
-
const data = (parsed.data as Record<string, unknown> | undefined) ?? props;
|
|
453
|
-
const sessionID = (
|
|
454
|
-
typeof parsed.sessionID === 'string'
|
|
455
|
-
? parsed.sessionID
|
|
456
|
-
: typeof props?.sessionID === 'string'
|
|
457
|
-
? (props.sessionID as string)
|
|
458
|
-
: typeof data?.sessionID === 'string'
|
|
459
|
-
? (data.sessionID as string)
|
|
460
|
-
: undefined
|
|
461
|
-
);
|
|
462
|
-
const messageID = (
|
|
463
|
-
typeof parsed.messageID === 'string'
|
|
464
|
-
? parsed.messageID
|
|
465
|
-
: typeof props?.messageID === 'string'
|
|
466
|
-
? (props.messageID as string)
|
|
467
|
-
: typeof data?.messageID === 'string'
|
|
468
|
-
? (data.messageID as string)
|
|
469
|
-
: undefined
|
|
470
|
-
);
|
|
471
|
-
let type = parsed.type as string;
|
|
472
|
-
const m = /\.\d+$/.exec(type);
|
|
473
|
-
if (m) type = type.slice(0, m.index);
|
|
474
|
-
return { type, sessionID, messageID, data: parsed };
|
|
475
|
-
}
|
|
476
|
-
// Sync envelope: {type: "sync", syncEvent: {...}}
|
|
477
|
-
if (
|
|
478
|
-
parsed.type === 'sync' &&
|
|
479
|
-
parsed.syncEvent &&
|
|
480
|
-
typeof parsed.syncEvent === 'object'
|
|
481
|
-
) {
|
|
482
|
-
const inner = parsed.syncEvent as Record<string, unknown>;
|
|
483
|
-
let type = (inner.type as string) || '';
|
|
484
|
-
const m = /\.\d+$/.exec(type);
|
|
485
|
-
if (m) type = type.slice(0, m.index);
|
|
486
|
-
const innerData = (inner.data as Record<string, unknown>) || {};
|
|
487
|
-
return {
|
|
488
|
-
type,
|
|
489
|
-
sessionID:
|
|
490
|
-
typeof innerData.sessionID === 'string'
|
|
491
|
-
? innerData.sessionID
|
|
492
|
-
: undefined,
|
|
493
|
-
messageID:
|
|
494
|
-
typeof innerData.messageID === 'string'
|
|
495
|
-
? innerData.messageID
|
|
496
|
-
: undefined,
|
|
497
|
-
data: inner,
|
|
498
|
-
};
|
|
499
|
-
}
|
|
500
|
-
return null;
|
|
501
|
-
} catch {
|
|
502
|
-
return null;
|
|
503
|
-
}
|
|
504
|
-
};
|
|
505
|
-
|
|
506
|
-
// register handlers per named event type
|
|
507
|
-
const namedTypes = [
|
|
508
|
-
'message.user.created',
|
|
509
|
-
'message.user.updated',
|
|
510
|
-
'message.assistant.created',
|
|
511
|
-
'message.assistant.updated',
|
|
512
|
-
'message.part.updated',
|
|
513
|
-
'session.idle',
|
|
514
|
-
'message.assistant.completed',
|
|
515
|
-
'session.completed',
|
|
516
|
-
'session.awaiting',
|
|
517
|
-
'session.awaiting_input',
|
|
518
|
-
'message.assistant.awaiting',
|
|
519
|
-
'session.error',
|
|
520
|
-
];
|
|
521
|
-
for (const name of namedTypes) {
|
|
522
|
-
es.addEventListener(name, (e: MessageEvent) => {
|
|
523
|
-
onEnvelope(parseData((e as MessageEvent).data));
|
|
524
|
-
});
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
es.onerror = () => {
|
|
528
|
-
if (sseCurrentSessionIdRef.current !== id) return;
|
|
529
|
-
if (!sseAutoReconnectRef.current) {
|
|
530
|
-
try {
|
|
531
|
-
es.close();
|
|
532
|
-
} catch {
|
|
533
|
-
/* noop */
|
|
534
|
-
}
|
|
535
|
-
clineEsRef.current = null;
|
|
536
|
-
return;
|
|
537
|
-
}
|
|
538
|
-
try {
|
|
539
|
-
es.close();
|
|
540
|
-
} catch {
|
|
541
|
-
/* noop */
|
|
542
|
-
}
|
|
543
|
-
clineEsRef.current = null;
|
|
544
|
-
|
|
545
|
-
const nextAttempt = sseReconnectAttemptRef.current + 1;
|
|
546
|
-
sseReconnectAttemptRef.current = nextAttempt;
|
|
547
|
-
// Backoff: 1s, 2s, 4s, 8s, … capped at 30s.
|
|
548
|
-
const delayMs = Math.min(30_000, 1000 * 2 ** (nextAttempt - 1));
|
|
549
|
-
|
|
550
|
-
if (sseReconnectTimerRef.current !== null) {
|
|
551
|
-
clearTimeout(sseReconnectTimerRef.current);
|
|
552
|
-
}
|
|
553
|
-
sseReconnectTimerRef.current = window.setTimeout(() => {
|
|
554
|
-
sseReconnectTimerRef.current = null;
|
|
555
|
-
if (
|
|
556
|
-
sseAutoReconnectRef.current &&
|
|
557
|
-
sseCurrentSessionIdRef.current === id
|
|
558
|
-
) {
|
|
559
|
-
connect();
|
|
560
|
-
}
|
|
561
|
-
}, delayMs);
|
|
562
|
-
};
|
|
563
|
-
|
|
564
|
-
es.onopen = () => {
|
|
565
|
-
// Successful (re)connect — reset backoff.
|
|
566
|
-
sseReconnectAttemptRef.current = 0;
|
|
567
|
-
setClineError(null);
|
|
568
|
-
setClineSuggestion(null);
|
|
569
|
-
setClineErrorInfo(null);
|
|
570
|
-
};
|
|
571
|
-
};
|
|
572
|
-
|
|
573
|
-
connect();
|
|
574
|
-
},
|
|
575
|
-
[appendClineMessage, markSeen, markSessionStreaming, setSessionDisplayState],
|
|
576
|
-
);
|
|
577
|
-
|
|
578
|
-
const closeClineSession = useCallback(() => {
|
|
579
|
-
// Disable auto-reconnect first so the onerror handler short-circuits.
|
|
580
|
-
sseAutoReconnectRef.current = false;
|
|
581
|
-
sseCurrentSessionIdRef.current = null;
|
|
582
|
-
if (sseReconnectTimerRef.current !== null) {
|
|
583
|
-
clearTimeout(sseReconnectTimerRef.current);
|
|
584
|
-
sseReconnectTimerRef.current = null;
|
|
585
|
-
}
|
|
586
|
-
if (clineEsRef.current) {
|
|
587
|
-
try {
|
|
588
|
-
clineEsRef.current.close();
|
|
589
|
-
} catch {
|
|
590
|
-
/* noop */
|
|
591
|
-
}
|
|
592
|
-
clineEsRef.current = null;
|
|
593
|
-
}
|
|
594
|
-
setClineMessages([]);
|
|
595
|
-
setSeenClineMessages(new Set());
|
|
596
|
-
setClineError(null);
|
|
597
|
-
setClineSuggestion(null);
|
|
598
|
-
setClineErrorInfo(null);
|
|
599
|
-
setActiveClineSessionId(null);
|
|
600
|
-
setActiveSource('bizar');
|
|
601
|
-
}, []);
|
|
602
|
-
|
|
603
|
-
const loadClineSession = useCallback(
|
|
604
|
-
async (id: string) => {
|
|
605
|
-
// Close any previous cline session cleanly.
|
|
606
|
-
sseAutoReconnectRef.current = false;
|
|
607
|
-
if (clineEsRef.current) {
|
|
608
|
-
try {
|
|
609
|
-
clineEsRef.current.close();
|
|
610
|
-
} catch {
|
|
611
|
-
/* noop */
|
|
612
|
-
}
|
|
613
|
-
clineEsRef.current = null;
|
|
614
|
-
}
|
|
615
|
-
if (sseReconnectTimerRef.current !== null) {
|
|
616
|
-
clearTimeout(sseReconnectTimerRef.current);
|
|
617
|
-
sseReconnectTimerRef.current = null;
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
setClineError(null);
|
|
621
|
-
setClineSuggestion(null);
|
|
622
|
-
setClineErrorInfo(null);
|
|
623
|
-
setLoading(true);
|
|
624
|
-
|
|
625
|
-
try {
|
|
626
|
-
const data = await api.get<{ messages: ChatMessage[] }>(
|
|
627
|
-
`/claude-sessions/${encodeURIComponent(id)}/messages`,
|
|
628
|
-
);
|
|
629
|
-
setClineMessages(data.messages || []);
|
|
630
|
-
} catch (err) {
|
|
631
|
-
const msg = (err as Error).message;
|
|
632
|
-
// v5.0.0 — bug #4: surface the server's structured error
|
|
633
|
-
// envelope so the UI can render a useful suggestion instead
|
|
634
|
-
// of the raw upstream error string. The server returns
|
|
635
|
-
// `{error, message, cause?, status?, suggestion?}` for every
|
|
636
|
-
// non-2xx response (see serve-info.mjs + routes/cline-
|
|
637
|
-
// session-detail.mjs).
|
|
638
|
-
let info: ClineErrorInfo | null = null;
|
|
639
|
-
if (err instanceof ApiError && err.data && typeof err.data === 'object') {
|
|
640
|
-
const d = err.data as {
|
|
641
|
-
error?: string;
|
|
642
|
-
message?: string;
|
|
643
|
-
cause?: string;
|
|
644
|
-
status?: number;
|
|
645
|
-
suggestion?: string;
|
|
646
|
-
};
|
|
647
|
-
// canRetry: 503/502 are transient (plugin offline /
|
|
648
|
-
// upstream hiccup); the operator can fix the plugin and
|
|
649
|
-
// try again. 400 is a hard bad_request — retrying with the
|
|
650
|
-
// same payload won't help.
|
|
651
|
-
const code = d.error || 'unknown';
|
|
652
|
-
const canRetry =
|
|
653
|
-
code !== 'bad_request' &&
|
|
654
|
-
code !== 'too_many_subscribers' &&
|
|
655
|
-
code !== 'unauthorized';
|
|
656
|
-
info = {
|
|
657
|
-
type: 'session_load_failed',
|
|
658
|
-
code,
|
|
659
|
-
message: d.message || msg,
|
|
660
|
-
cause: d.cause,
|
|
661
|
-
status: d.status,
|
|
662
|
-
suggestion: d.suggestion ?? null,
|
|
663
|
-
canRetry,
|
|
664
|
-
};
|
|
665
|
-
} else if (err instanceof ApiError) {
|
|
666
|
-
info = {
|
|
667
|
-
type: 'session_load_failed',
|
|
668
|
-
code: 'unknown',
|
|
669
|
-
message: msg,
|
|
670
|
-
suggestion: null,
|
|
671
|
-
canRetry: true,
|
|
672
|
-
};
|
|
673
|
-
}
|
|
674
|
-
// Legacy fields — kept so the existing Chat.tsx thread-header
|
|
675
|
-
// error display continues to work unchanged.
|
|
676
|
-
setClineError(
|
|
677
|
-
info
|
|
678
|
-
? `Cline session load failed (${info.code}): ${info.message}`
|
|
679
|
-
: `Cline session load failed: ${msg}`,
|
|
680
|
-
);
|
|
681
|
-
setClineSuggestion(info?.suggestion ?? null);
|
|
682
|
-
setClineErrorInfo(info);
|
|
683
|
-
toastRef.current?.error(
|
|
684
|
-
info
|
|
685
|
-
? `Cline session load failed: ${info.message}`
|
|
686
|
-
: `Cline session load failed: ${msg}`,
|
|
687
|
-
);
|
|
688
|
-
setClineMessages([]);
|
|
689
|
-
} finally {
|
|
690
|
-
setLoading(false);
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
setActiveClineSessionId(id);
|
|
694
|
-
setActiveSource('cline');
|
|
695
|
-
markSessionStreaming(id, false);
|
|
696
|
-
openSseForSession(id);
|
|
697
|
-
},
|
|
698
|
-
[markSessionStreaming, openSseForSession],
|
|
699
|
-
);
|
|
700
|
-
|
|
701
|
-
// ── Select a bizar session ──────────────────────────────────────────────────
|
|
702
|
-
const selectBizarSession = useCallback(
|
|
703
|
-
(sid: string) => {
|
|
704
|
-
closeClineSession();
|
|
705
|
-
setSessionId(sid);
|
|
706
|
-
setActiveSource('bizar');
|
|
707
|
-
loadChat(sid);
|
|
708
|
-
// Reset unread for the session being opened.
|
|
709
|
-
setSessionDisplayState(sid, { unread: 0 });
|
|
710
|
-
},
|
|
711
|
-
[closeClineSession, loadChat, setSessionDisplayState],
|
|
712
|
-
);
|
|
713
|
-
|
|
714
|
-
// ── Create session (cline primary; bizar fallback) ──────────────────────
|
|
715
|
-
const onCreateSession = useCallback(async (): Promise<{
|
|
716
|
-
ok: boolean;
|
|
717
|
-
source?: 'bizar' | 'cline';
|
|
718
|
-
id?: string;
|
|
719
|
-
}> => {
|
|
720
|
-
if (busy.create) return { ok: false };
|
|
721
|
-
const agent = settings.defaultAgent || 'odin';
|
|
722
|
-
setBusy((b) => ({ ...b, create: true }));
|
|
723
|
-
try {
|
|
724
|
-
// Try to create a real cline session first. This is the
|
|
725
|
-
// primary create path: it gives the user a full conversation
|
|
726
|
-
// roundtrip with SSE streaming, abort, etc.
|
|
727
|
-
try {
|
|
728
|
-
const created = await api.post<{
|
|
729
|
-
id: string;
|
|
730
|
-
title: string;
|
|
731
|
-
agent: string;
|
|
732
|
-
directory: string;
|
|
733
|
-
createdAt: number;
|
|
734
|
-
}>('/claude-sessions/new', { agent });
|
|
735
|
-
await refreshClineSessions();
|
|
736
|
-
// Open the newly created session right away so the user is
|
|
737
|
-
// dropped into a fresh empty thread, not stuck on the
|
|
738
|
-
// previous one.
|
|
739
|
-
await loadClineSession(created.id);
|
|
740
|
-
toastRef.current?.success(`Session ${created.id} created.`);
|
|
741
|
-
return { ok: true, source: 'cline', id: created.id };
|
|
742
|
-
} catch (clineErr) {
|
|
743
|
-
// Cline plugin offline (503) — fall back to the local
|
|
744
|
-
// per-project .jsonl session. Otherwise, surface the error.
|
|
745
|
-
if (!(clineErr instanceof ApiError) || clineErr.status !== 503) {
|
|
746
|
-
toastRef.current?.error(
|
|
747
|
-
`Create failed: ${(clineErr as Error).message}`,
|
|
748
|
-
);
|
|
749
|
-
return { ok: false };
|
|
750
|
-
}
|
|
751
|
-
}
|
|
752
|
-
|
|
753
|
-
// Fallback: local jsonl session.
|
|
754
|
-
if (!snapshot.activeProject) {
|
|
755
|
-
toastRef.current?.error(
|
|
756
|
-
'Pick a project in Overview to scope chat sessions.',
|
|
757
|
-
);
|
|
758
|
-
return { ok: false };
|
|
759
|
-
}
|
|
760
|
-
const created = await api.post<ChatSession>('/chat/sessions', {});
|
|
761
|
-
setSessionId(created.id);
|
|
762
|
-
setBizarMessages([]);
|
|
763
|
-
setPinned(new Set());
|
|
764
|
-
setSessionDisplayState(created.id, { state: 'idle', unread: 0 });
|
|
765
|
-
await loadChat(created.id);
|
|
766
|
-
refreshSessions().catch(() => {});
|
|
767
|
-
toastRef.current?.success(`Session ${created.id} created.`);
|
|
768
|
-
return { ok: true, source: 'bizar', id: created.id };
|
|
769
|
-
} catch (err) {
|
|
770
|
-
toastRef.current?.error(`Create failed: ${(err as Error).message}`);
|
|
771
|
-
return { ok: false };
|
|
772
|
-
} finally {
|
|
773
|
-
setBusy((b) => ({ ...b, create: false }));
|
|
774
|
-
}
|
|
775
|
-
}, [
|
|
776
|
-
busy.create,
|
|
777
|
-
settings.defaultAgent,
|
|
778
|
-
snapshot.activeProject,
|
|
779
|
-
refreshClineSessions,
|
|
780
|
-
loadClineSession,
|
|
781
|
-
loadChat,
|
|
782
|
-
refreshSessions,
|
|
783
|
-
setSessionDisplayState,
|
|
784
|
-
]);
|
|
785
|
-
|
|
786
|
-
// ── Send message ────────────────────────────────────────────────────────────
|
|
787
|
-
const onSend = useCallback(
|
|
788
|
-
async (
|
|
789
|
-
message: string,
|
|
790
|
-
agent: string,
|
|
791
|
-
model: string,
|
|
792
|
-
attachments?: string[],
|
|
793
|
-
): Promise<{ ok: boolean }> => {
|
|
794
|
-
if (busy.send) return { ok: false };
|
|
795
|
-
const trimmed = message.trim();
|
|
796
|
-
if (!trimmed) return { ok: false };
|
|
797
|
-
|
|
798
|
-
if (activeSource === 'cline' && activeClineSessionId) {
|
|
799
|
-
const sid = activeClineSessionId;
|
|
800
|
-
const optimisticId = `msg_${Date.now().toString(36)}${Math.random().toString(36).slice(2, 8)}`;
|
|
801
|
-
const optimistic: ChatMessage = {
|
|
802
|
-
id: optimisticId,
|
|
803
|
-
role: 'user',
|
|
804
|
-
content: trimmed,
|
|
805
|
-
agent,
|
|
806
|
-
ts: new Date().toISOString(),
|
|
807
|
-
};
|
|
808
|
-
appendClineMessage(optimistic);
|
|
809
|
-
markSeen(optimisticId);
|
|
810
|
-
setBusy((b) => ({ ...b, send: true }));
|
|
811
|
-
try {
|
|
812
|
-
await api.post<{ ok: boolean; messageId: string }>(
|
|
813
|
-
`/claude-sessions/${encodeURIComponent(sid)}/send`,
|
|
814
|
-
{
|
|
815
|
-
message: trimmed,
|
|
816
|
-
agent,
|
|
817
|
-
},
|
|
818
|
-
);
|
|
819
|
-
markSessionStreaming(sid, true);
|
|
820
|
-
return { ok: true };
|
|
821
|
-
} catch (err) {
|
|
822
|
-
// Remove optimistic on failure.
|
|
823
|
-
setClineMessages((cur) => cur.filter((m) => m.id !== optimisticId));
|
|
824
|
-
toastRef.current?.error(
|
|
825
|
-
`Send failed: ${(err as Error).message}`,
|
|
826
|
-
);
|
|
827
|
-
return { ok: false };
|
|
828
|
-
} finally {
|
|
829
|
-
setBusy((b) => ({ ...b, send: false }));
|
|
830
|
-
}
|
|
831
|
-
}
|
|
832
|
-
|
|
833
|
-
// Bizar fallback.
|
|
834
|
-
const optimistic: ChatMessage = {
|
|
835
|
-
role: 'user',
|
|
836
|
-
content: trimmed,
|
|
837
|
-
agent,
|
|
838
|
-
ts: new Date().toISOString(),
|
|
839
|
-
};
|
|
840
|
-
setBizarMessages((cur) => [...cur, optimistic]);
|
|
841
|
-
setBusy((b) => ({ ...b, send: true }));
|
|
842
|
-
markSessionStreaming(sessionId, true);
|
|
843
|
-
try {
|
|
844
|
-
const response = await api.post<{ messages?: ChatMessage[] }>(
|
|
845
|
-
'/chat',
|
|
846
|
-
{
|
|
847
|
-
message: trimmed,
|
|
848
|
-
agent,
|
|
849
|
-
model,
|
|
850
|
-
attachments: attachments || [],
|
|
851
|
-
},
|
|
852
|
-
);
|
|
853
|
-
if (response?.messages) {
|
|
854
|
-
for (const msg of response.messages) {
|
|
855
|
-
if (msg.role === 'assistant') {
|
|
856
|
-
setBizarMessages((cur) => {
|
|
857
|
-
const exists = cur.some((m) => m.ts === msg.ts);
|
|
858
|
-
return exists ? cur : [...cur, msg];
|
|
859
|
-
});
|
|
860
|
-
}
|
|
861
|
-
}
|
|
862
|
-
} else {
|
|
863
|
-
toastRef.current?.info(
|
|
864
|
-
'Still processing… the response will appear shortly.',
|
|
865
|
-
);
|
|
866
|
-
}
|
|
867
|
-
return { ok: true };
|
|
868
|
-
} catch (err) {
|
|
869
|
-
setBizarMessages((cur) => cur.filter((m) => m !== optimistic));
|
|
870
|
-
toastRef.current?.error(
|
|
871
|
-
`Send failed: ${(err as Error).message}`,
|
|
872
|
-
);
|
|
873
|
-
return { ok: false };
|
|
874
|
-
} finally {
|
|
875
|
-
setBusy((b) => ({ ...b, send: false }));
|
|
876
|
-
markSessionStreaming(sessionId, false);
|
|
877
|
-
}
|
|
878
|
-
},
|
|
879
|
-
[
|
|
880
|
-
activeSource,
|
|
881
|
-
activeClineSessionId,
|
|
882
|
-
appendClineMessage,
|
|
883
|
-
markSeen,
|
|
884
|
-
markSessionStreaming,
|
|
885
|
-
sessionId,
|
|
886
|
-
busy.send,
|
|
887
|
-
],
|
|
888
|
-
);
|
|
889
|
-
|
|
890
|
-
const onRegenerate = useCallback(
|
|
891
|
-
async (messageId: string) => {
|
|
892
|
-
if (!sessionId) {
|
|
893
|
-
toastRef.current?.error('No active session to regenerate.');
|
|
894
|
-
return;
|
|
895
|
-
}
|
|
896
|
-
try {
|
|
897
|
-
await api.post('/chat/regenerate', { sessionId, messageId });
|
|
898
|
-
await loadChat(sessionId);
|
|
899
|
-
} catch (err) {
|
|
900
|
-
toastRef.current?.error(
|
|
901
|
-
`Regenerate failed: ${(err as Error).message}`,
|
|
902
|
-
);
|
|
903
|
-
}
|
|
904
|
-
},
|
|
905
|
-
[sessionId, loadChat],
|
|
906
|
-
);
|
|
907
|
-
|
|
908
|
-
const deleteMessage = useCallback(
|
|
909
|
-
(idx: number) => {
|
|
910
|
-
if (activeSource === 'cline') {
|
|
911
|
-
setClineMessages((cur) => cur.filter((_, i) => i !== idx));
|
|
912
|
-
} else {
|
|
913
|
-
setBizarMessages((cur) => cur.filter((_, i) => i !== idx));
|
|
914
|
-
}
|
|
915
|
-
},
|
|
916
|
-
[activeSource],
|
|
917
|
-
);
|
|
918
|
-
|
|
919
|
-
const togglePin = useCallback((idx: number) => {
|
|
920
|
-
setPinned((cur) => {
|
|
921
|
-
const next = new Set(cur);
|
|
922
|
-
if (next.has(idx)) next.delete(idx);
|
|
923
|
-
else next.add(idx);
|
|
924
|
-
return next;
|
|
925
|
-
});
|
|
926
|
-
}, []);
|
|
927
|
-
|
|
928
|
-
const copyMessage = useCallback((m: ChatMessage) => {
|
|
929
|
-
const text = m.content || m.message || '';
|
|
930
|
-
try {
|
|
931
|
-
navigator.clipboard?.writeText(text).then(
|
|
932
|
-
() => toastRef.current?.success('Copied.'),
|
|
933
|
-
() => toastRef.current?.error('Copy failed.'),
|
|
934
|
-
);
|
|
935
|
-
} catch {
|
|
936
|
-
toastRef.current?.error('Copy failed.');
|
|
937
|
-
}
|
|
938
|
-
}, []);
|
|
939
|
-
|
|
940
|
-
// ── Jump-to-latest ──────────────────────────────────────────────────────────
|
|
941
|
-
const handleScroll = useCallback(() => {
|
|
942
|
-
const el = listRef.current;
|
|
943
|
-
if (!el) return;
|
|
944
|
-
const distFromBottom = el.scrollHeight - el.scrollTop - el.clientHeight;
|
|
945
|
-
const atBottom = distFromBottom < 32;
|
|
946
|
-
setStickToBottom(atBottom);
|
|
947
|
-
if (atBottom) setNewMessageCount(0);
|
|
948
|
-
}, []);
|
|
949
|
-
|
|
950
|
-
const jumpToLatest = useCallback(() => {
|
|
951
|
-
const el = listRef.current;
|
|
952
|
-
if (!el) return;
|
|
953
|
-
el.scrollTop = el.scrollHeight;
|
|
954
|
-
setStickToBottom(true);
|
|
955
|
-
setNewMessageCount(0);
|
|
956
|
-
}, []);
|
|
957
|
-
|
|
958
|
-
// ── Session rename / delete (rail row menu + info panel actions) ────────────
|
|
959
|
-
const renameSession = useCallback(
|
|
960
|
-
async (id: string, title: string): Promise<boolean> => {
|
|
961
|
-
if (busy.rename) return false;
|
|
962
|
-
setBusy((b) => ({ ...b, rename: true }));
|
|
963
|
-
try {
|
|
964
|
-
const trimmed = title.trim();
|
|
965
|
-
if (!trimmed) {
|
|
966
|
-
toastRef.current?.error('Title cannot be empty.');
|
|
967
|
-
return false;
|
|
968
|
-
}
|
|
969
|
-
// Try the cline path first if this id is in the cline
|
|
970
|
-
// session list, otherwise the local path. We dispatch by
|
|
971
|
-
// inspecting the in-memory set (avoids a round trip).
|
|
972
|
-
const isCline = clineSessions.some((s) => s.id === id);
|
|
973
|
-
if (isCline) {
|
|
974
|
-
await api.patch<{ id: string; title: string }>(
|
|
975
|
-
`/claude-sessions/${encodeURIComponent(id)}`,
|
|
976
|
-
{ title: trimmed },
|
|
977
|
-
);
|
|
978
|
-
setClineSessions((cur) =>
|
|
979
|
-
cur.map((s) => (s.id === id ? { ...s, title: trimmed } : s)),
|
|
980
|
-
);
|
|
981
|
-
} else {
|
|
982
|
-
await api.post(
|
|
983
|
-
`/chat/sessions/${encodeURIComponent(id)}/rename`,
|
|
984
|
-
{ title: trimmed },
|
|
985
|
-
);
|
|
986
|
-
setSessions((cur) =>
|
|
987
|
-
cur.map((s) => (s.id === id ? { ...s, title: trimmed } : s)),
|
|
988
|
-
);
|
|
989
|
-
}
|
|
990
|
-
toastRef.current?.success('Renamed.');
|
|
991
|
-
return true;
|
|
992
|
-
} catch (err) {
|
|
993
|
-
toastRef.current?.error(
|
|
994
|
-
`Rename failed: ${(err as Error).message}`,
|
|
995
|
-
);
|
|
996
|
-
return false;
|
|
997
|
-
} finally {
|
|
998
|
-
setBusy((b) => ({ ...b, rename: false }));
|
|
999
|
-
}
|
|
1000
|
-
},
|
|
1001
|
-
[busy.rename, clineSessions],
|
|
1002
|
-
);
|
|
1003
|
-
|
|
1004
|
-
const deleteSession = useCallback(
|
|
1005
|
-
async (id: string): Promise<boolean> => {
|
|
1006
|
-
if (busy.delete) return false;
|
|
1007
|
-
setBusy((b) => ({ ...b, delete: true }));
|
|
1008
|
-
try {
|
|
1009
|
-
const isCline = clineSessions.some((s) => s.id === id);
|
|
1010
|
-
if (isCline) {
|
|
1011
|
-
await api.del(`/claude-sessions/${encodeURIComponent(id)}`);
|
|
1012
|
-
setClineSessions((cur) => cur.filter((s) => s.id !== id));
|
|
1013
|
-
if (activeClineSessionId === id) {
|
|
1014
|
-
closeClineSession();
|
|
1015
|
-
}
|
|
1016
|
-
} else {
|
|
1017
|
-
await api.del(`/chat/sessions/${encodeURIComponent(id)}`);
|
|
1018
|
-
setSessions((cur) => cur.filter((s) => s.id !== id));
|
|
1019
|
-
if (sessionId === id) {
|
|
1020
|
-
setSessionId('');
|
|
1021
|
-
setBizarMessages([]);
|
|
1022
|
-
}
|
|
1023
|
-
}
|
|
1024
|
-
setSessionStates((cur) => {
|
|
1025
|
-
const next = { ...cur };
|
|
1026
|
-
delete next[id];
|
|
1027
|
-
return next;
|
|
1028
|
-
});
|
|
1029
|
-
toastRef.current?.success('Session deleted.');
|
|
1030
|
-
return true;
|
|
1031
|
-
} catch (err) {
|
|
1032
|
-
toastRef.current?.error(
|
|
1033
|
-
`Delete failed: ${(err as Error).message}`,
|
|
1034
|
-
);
|
|
1035
|
-
return false;
|
|
1036
|
-
} finally {
|
|
1037
|
-
setBusy((b) => ({ ...b, delete: false }));
|
|
1038
|
-
}
|
|
1039
|
-
},
|
|
1040
|
-
[
|
|
1041
|
-
busy.delete,
|
|
1042
|
-
clineSessions,
|
|
1043
|
-
activeClineSessionId,
|
|
1044
|
-
closeClineSession,
|
|
1045
|
-
sessionId,
|
|
1046
|
-
],
|
|
1047
|
-
);
|
|
1048
|
-
|
|
1049
|
-
// ── Auto-scroll on new messages ─────────────────────────────────────────────
|
|
1050
|
-
useEffect(() => {
|
|
1051
|
-
if (listRef.current) {
|
|
1052
|
-
if (stickToBottom) {
|
|
1053
|
-
listRef.current.scrollTop = listRef.current.scrollHeight;
|
|
1054
|
-
} else {
|
|
1055
|
-
setNewMessageCount((n) => n + 1);
|
|
1056
|
-
}
|
|
1057
|
-
}
|
|
1058
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1059
|
-
}, [bizarMessages, clineMessages]);
|
|
1060
|
-
|
|
1061
|
-
// ── Cleanup SSE on unmount ──────────────────────────────────────────────────
|
|
1062
|
-
useEffect(() => {
|
|
1063
|
-
return () => {
|
|
1064
|
-
sseAutoReconnectRef.current = false;
|
|
1065
|
-
sseCurrentSessionIdRef.current = null;
|
|
1066
|
-
if (sseReconnectTimerRef.current !== null) {
|
|
1067
|
-
clearTimeout(sseReconnectTimerRef.current);
|
|
1068
|
-
sseReconnectTimerRef.current = null;
|
|
1069
|
-
}
|
|
1070
|
-
if (clineEsRef.current) {
|
|
1071
|
-
try {
|
|
1072
|
-
clineEsRef.current.close();
|
|
1073
|
-
} catch {
|
|
1074
|
-
/* noop */
|
|
1075
|
-
}
|
|
1076
|
-
clineEsRef.current = null;
|
|
1077
|
-
}
|
|
1078
|
-
};
|
|
1079
|
-
}, []);
|
|
1080
|
-
|
|
1081
|
-
// ── Initial load ────────────────────────────────────────────────────────────
|
|
1082
|
-
useEffect(() => {
|
|
1083
|
-
if (initialTaskId) {
|
|
1084
|
-
loadTaskChat(initialTaskId);
|
|
1085
|
-
} else {
|
|
1086
|
-
loadChat();
|
|
1087
|
-
}
|
|
1088
|
-
refreshClineSessions();
|
|
1089
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1090
|
-
}, []);
|
|
1091
|
-
|
|
1092
|
-
// ── Listen for bizar:setChatTask events ────────────────────────────────────
|
|
1093
|
-
useEffect(() => {
|
|
1094
|
-
const handler = (e: Event) => {
|
|
1095
|
-
const taskId = (e as CustomEvent<{ taskId: string }>).detail?.taskId;
|
|
1096
|
-
if (taskId) loadTaskChat(taskId);
|
|
1097
|
-
};
|
|
1098
|
-
window.addEventListener('bizar:setChatTask', handler);
|
|
1099
|
-
return () => window.removeEventListener('bizar:setChatTask', handler);
|
|
1100
|
-
}, [loadTaskChat]);
|
|
1101
|
-
|
|
1102
|
-
// ── WebSocket for live bizar updates ────────────────────────────────────────
|
|
1103
|
-
useEffect(() => {
|
|
1104
|
-
let closed = false;
|
|
1105
|
-
import('../../lib/ws').then(({ Ws }) => {
|
|
1106
|
-
if (closed) return;
|
|
1107
|
-
const ws = new Ws();
|
|
1108
|
-
ws.on((msg: { type: string; message?: ChatMessage }) => {
|
|
1109
|
-
if (msg.type !== 'chat:message') return;
|
|
1110
|
-
const next = msg.message;
|
|
1111
|
-
if (!next) return;
|
|
1112
|
-
setBizarMessages((cur) => {
|
|
1113
|
-
const exists = cur.some((m) => m.ts === next.ts);
|
|
1114
|
-
return exists ? cur : [...cur, next];
|
|
1115
|
-
});
|
|
1116
|
-
});
|
|
1117
|
-
});
|
|
1118
|
-
return () => {
|
|
1119
|
-
closed = true;
|
|
1120
|
-
};
|
|
1121
|
-
}, []);
|
|
1122
|
-
|
|
1123
|
-
return {
|
|
1124
|
-
// ── State ────────────────────────────────────────────────────────────────
|
|
1125
|
-
messages:
|
|
1126
|
-
activeSource === 'cline' ? clineMessages : bizarMessages,
|
|
1127
|
-
bizarMessages,
|
|
1128
|
-
clineMessages,
|
|
1129
|
-
sessions,
|
|
1130
|
-
clineSessions,
|
|
1131
|
-
sessionId,
|
|
1132
|
-
setSessionId,
|
|
1133
|
-
loading,
|
|
1134
|
-
sending: busy.send,
|
|
1135
|
-
pinned,
|
|
1136
|
-
listRef,
|
|
1137
|
-
// ── Cline state ──────────────────────────────────────────────────────
|
|
1138
|
-
activeSource,
|
|
1139
|
-
activeClineSessionId,
|
|
1140
|
-
clineError,
|
|
1141
|
-
clineSuggestion,
|
|
1142
|
-
/**
|
|
1143
|
-
* v5.0.0 — bug #4: structured error info consumed by
|
|
1144
|
-
* `ChatInfoPanel`. `null` when no error is active.
|
|
1145
|
-
*/
|
|
1146
|
-
clineErrorInfo,
|
|
1147
|
-
/**
|
|
1148
|
-
* v5.0.0 — bug #4: retry helper exposed for `ChatInfoPanel`'s
|
|
1149
|
-
* Retry button. Calls `loadClineSession` on the currently
|
|
1150
|
-
* active cline session (or no-op if none is active).
|
|
1151
|
-
*/
|
|
1152
|
-
retryClineSession: () => {
|
|
1153
|
-
if (activeClineSessionId) void loadClineSession(activeClineSessionId);
|
|
1154
|
-
},
|
|
1155
|
-
// ── v3.22 — per-session display state ──────────────────────────────────
|
|
1156
|
-
sessionStates,
|
|
1157
|
-
busy,
|
|
1158
|
-
getSessionDisplay: (s: ChatSession) => ({
|
|
1159
|
-
...s,
|
|
1160
|
-
state: sessionStates[s.id]?.state ?? 'idle',
|
|
1161
|
-
unread: sessionStates[s.id]?.unread ?? 0,
|
|
1162
|
-
pinned: sessionStates[s.id]?.pinned ?? false,
|
|
1163
|
-
tree: sessionStates[s.id]?.tree,
|
|
1164
|
-
}),
|
|
1165
|
-
// ── Jump-to-latest ──────────────────────────────────────────────────────
|
|
1166
|
-
stickToBottom,
|
|
1167
|
-
newMessageCount,
|
|
1168
|
-
handleScroll,
|
|
1169
|
-
jumpToLatest,
|
|
1170
|
-
// ── Toast integration ──────────────────────────────────────────────────
|
|
1171
|
-
setToast,
|
|
1172
|
-
// ── Actions ─────────────────────────────────────────────────────────────
|
|
1173
|
-
loadChat,
|
|
1174
|
-
loadTaskChat,
|
|
1175
|
-
refreshSessions,
|
|
1176
|
-
refreshClineSessions,
|
|
1177
|
-
loadClineSession,
|
|
1178
|
-
closeClineSession,
|
|
1179
|
-
selectBizarSession,
|
|
1180
|
-
onCreateSession,
|
|
1181
|
-
onSend,
|
|
1182
|
-
onRegenerate,
|
|
1183
|
-
deleteMessage,
|
|
1184
|
-
togglePin,
|
|
1185
|
-
copyMessage,
|
|
1186
|
-
renameSession,
|
|
1187
|
-
deleteSession,
|
|
1188
|
-
seenClineMessages,
|
|
1189
|
-
};
|
|
1190
|
-
}
|