@polderlabs/bizar 10.4.3 → 10.5.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/bizar-dash/dist/assets/{ActivityFeed-DC0JiK49.js → ActivityFeed-Bw4Cai7r.js} +1 -1
- package/bizar-dash/dist/assets/{ActivityFeed-DC0JiK49.js.map → ActivityFeed-Bw4Cai7r.js.map} +1 -1
- package/bizar-dash/dist/assets/{ActivityView-ubEDAWMY.js → ActivityView-BC0QQ_j9.js} +1 -1
- package/bizar-dash/dist/assets/{ActivityView-ubEDAWMY.js.map → ActivityView-BC0QQ_j9.js.map} +1 -1
- package/bizar-dash/dist/assets/AdminView-CLTNKFL4.js +11 -0
- package/bizar-dash/dist/assets/AdminView-CLTNKFL4.js.map +1 -0
- package/bizar-dash/dist/assets/{AgentActivity-BLcqqkt2.js → AgentActivity-DBWDByjk.js} +1 -1
- package/bizar-dash/dist/assets/{AgentActivity-BLcqqkt2.js.map → AgentActivity-DBWDByjk.js.map} +1 -1
- package/bizar-dash/dist/assets/{AgentsView-CIQkZH8_.js → AgentsView-DD6bCIbA.js} +4 -4
- package/bizar-dash/dist/assets/AgentsView-DD6bCIbA.js.map +1 -0
- package/bizar-dash/dist/assets/{Alert-MwVEymjy.js → Alert-pzFISNtS.js} +1 -1
- package/bizar-dash/dist/assets/{Alert-MwVEymjy.js.map → Alert-pzFISNtS.js.map} +1 -1
- package/bizar-dash/dist/assets/ArtifactsView-BVU5lfo7.js +21 -0
- package/bizar-dash/dist/assets/ArtifactsView-BVU5lfo7.js.map +1 -0
- package/bizar-dash/dist/assets/{AuthView-LaQuGo4u.js → AuthView-BZ-bPIOM.js} +2 -2
- package/bizar-dash/dist/assets/AuthView-BZ-bPIOM.js.map +1 -0
- package/bizar-dash/dist/assets/Avatar-CRW81ewE.js +6 -0
- package/bizar-dash/dist/assets/Avatar-CRW81ewE.js.map +1 -0
- package/bizar-dash/dist/assets/BackgroundJobsView-w8OZtXyI.js +1 -0
- package/bizar-dash/dist/assets/BackgroundJobsView-w8OZtXyI.js.map +1 -0
- package/bizar-dash/dist/assets/{BackupView-Cjf23ZWc.js → BackupView-u_O3j0TG.js} +1 -1
- package/bizar-dash/dist/assets/{BackupView-Cjf23ZWc.js.map → BackupView-u_O3j0TG.js.map} +1 -1
- package/bizar-dash/dist/assets/Banner-Du-3l05O.js +1 -0
- package/bizar-dash/dist/assets/Banner-Du-3l05O.js.map +1 -0
- package/bizar-dash/dist/assets/{Card-BmXiT4c6.js → Card-Clkvh43Q.js} +1 -1
- package/bizar-dash/dist/assets/{Card-BmXiT4c6.js.map → Card-Clkvh43Q.js.map} +1 -1
- package/bizar-dash/dist/assets/{ChatView-DXKFwvgp.js → ChatView-BTjb3mIh.js} +3 -3
- package/bizar-dash/dist/assets/{ChatView-DXKFwvgp.js.map → ChatView-BTjb3mIh.js.map} +1 -1
- package/bizar-dash/dist/assets/{Chip-Dei66BLx.js → Chip-B7ovcm01.js} +1 -1
- package/bizar-dash/dist/assets/{Chip-Dei66BLx.js.map → Chip-B7ovcm01.js.map} +1 -1
- package/bizar-dash/dist/assets/ClaudeSessionsView-BoZS5ldi.js +1 -0
- package/bizar-dash/dist/assets/ClaudeSessionsView-BoZS5ldi.js.map +1 -0
- package/bizar-dash/dist/assets/ClipboardView-Cb6XgYZI.js +1 -0
- package/bizar-dash/dist/assets/ClipboardView-Cb6XgYZI.js.map +1 -0
- package/bizar-dash/dist/assets/{ConfigView-BMBgifw5.js → ConfigView-DfTJk1uL.js} +1 -1
- package/bizar-dash/dist/assets/{ConfigView-BMBgifw5.js.map → ConfigView-DfTJk1uL.js.map} +1 -1
- package/bizar-dash/dist/assets/{DiagnosticsView-C0sdqhEl.js → DiagnosticsView-D5Wy9xlJ.js} +1 -1
- package/bizar-dash/dist/assets/{DiagnosticsView-C0sdqhEl.js.map → DiagnosticsView-D5Wy9xlJ.js.map} +1 -1
- package/bizar-dash/dist/assets/DialogsView-HVyfrXpq.js +6 -0
- package/bizar-dash/dist/assets/DialogsView-HVyfrXpq.js.map +1 -0
- package/bizar-dash/dist/assets/{DoctorView-CiFwRMW0.js → DoctorView-Dm94WI2z.js} +2 -2
- package/bizar-dash/dist/assets/{DoctorView-CiFwRMW0.js.map → DoctorView-Dm94WI2z.js.map} +1 -1
- package/bizar-dash/dist/assets/{EmptyState-CdDQmfEL.js → EmptyState-ccT__JZG.js} +1 -1
- package/bizar-dash/dist/assets/{EmptyState-CdDQmfEL.js.map → EmptyState-ccT__JZG.js.map} +1 -1
- package/bizar-dash/dist/assets/{EnvVarsView-CNO03NDJ.js → EnvVarsView-BhcIuJ6V.js} +3 -3
- package/bizar-dash/dist/assets/{EnvVarsView-CNO03NDJ.js.map → EnvVarsView-BhcIuJ6V.js.map} +1 -1
- package/bizar-dash/dist/assets/{ErrorState-BRvj8qZZ.js → ErrorState-BSqf65ka.js} +1 -1
- package/bizar-dash/dist/assets/{ErrorState-BRvj8qZZ.js.map → ErrorState-BSqf65ka.js.map} +1 -1
- package/bizar-dash/dist/assets/EvalView-2cbWVBUA.js +1 -0
- package/bizar-dash/dist/assets/{EvalView-lgUhlGJh.js.map → EvalView-2cbWVBUA.js.map} +1 -1
- package/bizar-dash/dist/assets/{GoalsView-DmkCCs9i.js → GoalsView-C3QG5p7T.js} +1 -1
- package/bizar-dash/dist/assets/{GoalsView-DmkCCs9i.js.map → GoalsView-C3QG5p7T.js.map} +1 -1
- package/bizar-dash/dist/assets/{Grid-BThCPJaV.js → Grid-Bojq8Sg7.js} +1 -1
- package/bizar-dash/dist/assets/{Grid-BThCPJaV.js.map → Grid-Bojq8Sg7.js.map} +1 -1
- package/bizar-dash/dist/assets/{HistoryView-Cn2cPiHZ.js → HistoryView-Bum2TMMw.js} +1 -1
- package/bizar-dash/dist/assets/{HistoryView-Cn2cPiHZ.js.map → HistoryView-Bum2TMMw.js.map} +1 -1
- package/bizar-dash/dist/assets/{Input-cAQOvR8U.js → Input-DV-vdaV8.js} +1 -1
- package/bizar-dash/dist/assets/{Input-cAQOvR8U.js.map → Input-DV-vdaV8.js.map} +1 -1
- package/bizar-dash/dist/assets/LibrariesView-DH2E2uNb.js +6 -0
- package/bizar-dash/dist/assets/{LibrariesView-Ca_PRjUm.js.map → LibrariesView-DH2E2uNb.js.map} +1 -1
- package/bizar-dash/dist/assets/LightRAGView-BFCcj7Tl.js +6 -0
- package/bizar-dash/dist/assets/LightRAGView-BFCcj7Tl.js.map +1 -0
- package/bizar-dash/dist/assets/{ListHeader-BLAeshe0.js → ListHeader-CCD_nIHb.js} +1 -1
- package/bizar-dash/dist/assets/{ListHeader-BLAeshe0.js.map → ListHeader-CCD_nIHb.js.map} +1 -1
- package/bizar-dash/dist/assets/{MemoryView-wo2Pu7xQ.js → MemoryView-Cr-obIQY.js} +1 -1
- package/bizar-dash/dist/assets/{MemoryView-wo2Pu7xQ.js.map → MemoryView-Cr-obIQY.js.map} +1 -1
- package/bizar-dash/dist/assets/MiscView-CDUQpYuV.js +1 -0
- package/bizar-dash/dist/assets/MiscView-CDUQpYuV.js.map +1 -0
- package/bizar-dash/dist/assets/{ModsView-CV_RxdzJ.js → ModsView-B6OR-a4B.js} +2 -2
- package/bizar-dash/dist/assets/{ModsView-CV_RxdzJ.js.map → ModsView-B6OR-a4B.js.map} +1 -1
- package/bizar-dash/dist/assets/NotificationsView-CIqtY6D0.js +6 -0
- package/bizar-dash/dist/assets/NotificationsView-CIqtY6D0.js.map +1 -0
- package/bizar-dash/dist/assets/ObsidianView-Nahah8QC.js +1 -0
- package/bizar-dash/dist/assets/{ObsidianView-C-AvHfpT.js.map → ObsidianView-Nahah8QC.js.map} +1 -1
- package/bizar-dash/dist/assets/OverviewView-B6L_wa4M.js +1 -0
- package/bizar-dash/dist/assets/OverviewView-B6L_wa4M.js.map +1 -0
- package/bizar-dash/dist/assets/{ProgressBar-ya2PCj8L.js → ProgressBar-KC4VXsl_.js} +1 -1
- package/bizar-dash/dist/assets/{ProgressBar-ya2PCj8L.js.map → ProgressBar-KC4VXsl_.js.map} +1 -1
- package/bizar-dash/dist/assets/{ProjectsView-N9zqFZ_O.js → ProjectsView-DgxWiqHb.js} +1 -1
- package/bizar-dash/dist/assets/{ProjectsView-N9zqFZ_O.js.map → ProjectsView-DgxWiqHb.js.map} +1 -1
- package/bizar-dash/dist/assets/{ProvidersView-BcL8jjwK.js → ProvidersView-BOqN9omv.js} +2 -2
- package/bizar-dash/dist/assets/{ProvidersView-BcL8jjwK.js.map → ProvidersView-BOqN9omv.js.map} +1 -1
- package/bizar-dash/dist/assets/SchedulesView-yMaG3Dtd.js +1 -0
- package/bizar-dash/dist/assets/SchedulesView-yMaG3Dtd.js.map +1 -0
- package/bizar-dash/dist/assets/{Select-D5AuVxxV.js → Select-Bf_P0S6H.js} +1 -1
- package/bizar-dash/dist/assets/{Select-D5AuVxxV.js.map → Select-Bf_P0S6H.js.map} +1 -1
- package/bizar-dash/dist/assets/{SettingsRow-BBALf9dA.js → SettingsRow-CJb-F94Y.js} +1 -1
- package/bizar-dash/dist/assets/{SettingsRow-BBALf9dA.js.map → SettingsRow-CJb-F94Y.js.map} +1 -1
- package/bizar-dash/dist/assets/{SettingsView-UD403neY.js → SettingsView-BvOGcgMS.js} +2 -2
- package/bizar-dash/dist/assets/SettingsView-BvOGcgMS.js.map +1 -0
- package/bizar-dash/dist/assets/{Sheet-CxXf6gvC.js → Sheet-BwMVGN-8.js} +1 -1
- package/bizar-dash/dist/assets/{Sheet-CxXf6gvC.js.map → Sheet-BwMVGN-8.js.map} +1 -1
- package/bizar-dash/dist/assets/{Slider-hvaVD_SW.js → Slider-AjjzqI-5.js} +1 -1
- package/bizar-dash/dist/assets/{Slider-hvaVD_SW.js.map → Slider-AjjzqI-5.js.map} +1 -1
- package/bizar-dash/dist/assets/{Sparkline-DqmQzdJH.js → Sparkline-Z4y0YUZS.js} +1 -1
- package/bizar-dash/dist/assets/{Sparkline-DqmQzdJH.js.map → Sparkline-Z4y0YUZS.js.map} +1 -1
- package/bizar-dash/dist/assets/{Switch-C-_zcNdl.js → Switch-B79a2t-G.js} +1 -1
- package/bizar-dash/dist/assets/{Switch-C-_zcNdl.js.map → Switch-B79a2t-G.js.map} +1 -1
- package/bizar-dash/dist/assets/{TasksView-DseftDlx.js → TasksView-G-s_pwwr.js} +2 -2
- package/bizar-dash/dist/assets/{TasksView-DseftDlx.js.map → TasksView-G-s_pwwr.js.map} +1 -1
- package/bizar-dash/dist/assets/{Textarea-CcQGSgSH.js → Textarea-BfXGMXQ7.js} +1 -1
- package/bizar-dash/dist/assets/{Textarea-CcQGSgSH.js.map → Textarea-BfXGMXQ7.js.map} +1 -1
- package/bizar-dash/dist/assets/UpdateView-BKx3u9X8.js +1 -0
- package/bizar-dash/dist/assets/UpdateView-BKx3u9X8.js.map +1 -0
- package/bizar-dash/dist/assets/{UsageView-P5_pQ68d.js → UsageView-M01G6bZQ.js} +1 -1
- package/bizar-dash/dist/assets/{UsageView-P5_pQ68d.js.map → UsageView-M01G6bZQ.js.map} +1 -1
- package/bizar-dash/dist/assets/{ViewHeader-BaCWNuVX.js → ViewHeader-BsnaspKw.js} +1 -1
- package/bizar-dash/dist/assets/{ViewHeader-BaCWNuVX.js.map → ViewHeader-BsnaspKw.js.map} +1 -1
- package/bizar-dash/dist/assets/VoiceView-rWE8vziD.js +1 -0
- package/bizar-dash/dist/assets/VoiceView-rWE8vziD.js.map +1 -0
- package/bizar-dash/dist/assets/{brain-D6tAeUDE.js → brain-D7k5s8vH.js} +1 -1
- package/bizar-dash/dist/assets/{brain-D6tAeUDE.js.map → brain-D7k5s8vH.js.map} +1 -1
- package/bizar-dash/dist/assets/{calendar-BrMJf3vl.js → calendar-CAZoDd-l.js} +1 -1
- package/bizar-dash/dist/assets/{calendar-BrMJf3vl.js.map → calendar-CAZoDd-l.js.map} +1 -1
- package/bizar-dash/dist/assets/{circle-fPTATiOs.js → circle-D99cZJBr.js} +1 -1
- package/bizar-dash/dist/assets/{circle-fPTATiOs.js.map → circle-D99cZJBr.js.map} +1 -1
- package/bizar-dash/dist/assets/{circle-alert-D7jn06kH.js → circle-alert-QQTU4Quz.js} +1 -1
- package/bizar-dash/dist/assets/{circle-alert-D7jn06kH.js.map → circle-alert-QQTU4Quz.js.map} +1 -1
- package/bizar-dash/dist/assets/{circle-check-DHs37Sot.js → circle-check-BMbe7Kkr.js} +1 -1
- package/bizar-dash/dist/assets/{circle-check-DHs37Sot.js.map → circle-check-BMbe7Kkr.js.map} +1 -1
- package/bizar-dash/dist/assets/{clock-E-G5aGua.js → clock-OtT5mvF3.js} +1 -1
- package/bizar-dash/dist/assets/{clock-E-G5aGua.js.map → clock-OtT5mvF3.js.map} +1 -1
- package/bizar-dash/dist/assets/{download-DBkNb6oI.js → download-B-mPX5P_.js} +1 -1
- package/bizar-dash/dist/assets/{download-DBkNb6oI.js.map → download-B-mPX5P_.js.map} +1 -1
- package/bizar-dash/dist/assets/{external-link-C4pHGbz2.js → external-link-DPDQM1YO.js} +1 -1
- package/bizar-dash/dist/assets/{external-link-C4pHGbz2.js.map → external-link-DPDQM1YO.js.map} +1 -1
- package/bizar-dash/dist/assets/{file-text-CEhDgLq2.js → file-text-BsCrv5aP.js} +1 -1
- package/bizar-dash/dist/assets/{file-text-CEhDgLq2.js.map → file-text-BsCrv5aP.js.map} +1 -1
- package/bizar-dash/dist/assets/{filter-CEYjeWFX.js → filter-Do63x17E.js} +1 -1
- package/bizar-dash/dist/assets/{filter-CEYjeWFX.js.map → filter-Do63x17E.js.map} +1 -1
- package/bizar-dash/dist/assets/{git-pull-request-Bo_wBZZw.js → git-pull-request-CpRAmERC.js} +1 -1
- package/bizar-dash/dist/assets/{git-pull-request-Bo_wBZZw.js.map → git-pull-request-CpRAmERC.js.map} +1 -1
- package/bizar-dash/dist/assets/main-BRmJZcHt.js +277 -0
- package/bizar-dash/dist/assets/main-BRmJZcHt.js.map +1 -0
- package/bizar-dash/dist/assets/main-D0TY0myE.css +1 -0
- package/bizar-dash/dist/assets/{network-BsfwrUA-.js → network-DJnHwHX3.js} +1 -1
- package/bizar-dash/dist/assets/{network-BsfwrUA-.js.map → network-DJnHwHX3.js.map} +1 -1
- package/bizar-dash/dist/assets/{pause-C8PN1_yO.js → pause-HitDUnk_.js} +1 -1
- package/bizar-dash/dist/assets/{pause-C8PN1_yO.js.map → pause-HitDUnk_.js.map} +1 -1
- package/bizar-dash/dist/assets/{pencil---XuvKlz.js → pencil-Dkks7eIC.js} +1 -1
- package/bizar-dash/dist/assets/{pencil---XuvKlz.js.map → pencil-Dkks7eIC.js.map} +1 -1
- package/bizar-dash/dist/assets/{play-fMLPTihK.js → play-blqh0msT.js} +2 -2
- package/bizar-dash/dist/assets/{play-fMLPTihK.js.map → play-blqh0msT.js.map} +1 -1
- package/bizar-dash/dist/assets/{plug-CG8al2Kq.js → plug-DVvSSe40.js} +1 -1
- package/bizar-dash/dist/assets/{plug-CG8al2Kq.js.map → plug-DVvSSe40.js.map} +1 -1
- package/bizar-dash/dist/assets/{plus-uA5Ecuch.js → plus-Cps-8lcG.js} +1 -1
- package/bizar-dash/dist/assets/{plus-uA5Ecuch.js.map → plus-Cps-8lcG.js.map} +1 -1
- package/bizar-dash/dist/assets/{power-DSUlNIuR.js → power-DEX4_Xoa.js} +1 -1
- package/bizar-dash/dist/assets/{power-DSUlNIuR.js.map → power-DEX4_Xoa.js.map} +1 -1
- package/bizar-dash/dist/assets/{power-off-1CAQsHHy.js → power-off-upZ4xjaG.js} +1 -1
- package/bizar-dash/dist/assets/{power-off-1CAQsHHy.js.map → power-off-upZ4xjaG.js.map} +1 -1
- package/bizar-dash/dist/assets/{refresh-ccw-BL7B0NO1.js → refresh-ccw-DN_zCB1h.js} +1 -1
- package/bizar-dash/dist/assets/{refresh-ccw-BL7B0NO1.js.map → refresh-ccw-DN_zCB1h.js.map} +1 -1
- package/bizar-dash/dist/assets/{refresh-cw-CR9BzJik.js → refresh-cw-KGm5eQgv.js} +1 -1
- package/bizar-dash/dist/assets/{refresh-cw-CR9BzJik.js.map → refresh-cw-KGm5eQgv.js.map} +1 -1
- package/bizar-dash/dist/assets/{rotate-ccw-BtnitLfb.js → rotate-ccw-D5fkDRgk.js} +1 -1
- package/bizar-dash/dist/assets/{rotate-ccw-BtnitLfb.js.map → rotate-ccw-D5fkDRgk.js.map} +1 -1
- package/bizar-dash/dist/assets/{rotate-cw-CHgXCO7O.js → rotate-cw-CClSVUaX.js} +1 -1
- package/bizar-dash/dist/assets/{rotate-cw-CHgXCO7O.js.map → rotate-cw-CClSVUaX.js.map} +1 -1
- package/bizar-dash/dist/assets/{save-RcZOXR0U.js → save-BY4ViPku.js} +1 -1
- package/bizar-dash/dist/assets/{save-RcZOXR0U.js.map → save-BY4ViPku.js.map} +1 -1
- package/bizar-dash/dist/assets/{send-Bg2X_ibk.js → send-CaOL1yQD.js} +2 -2
- package/bizar-dash/dist/assets/{send-Bg2X_ibk.js.map → send-CaOL1yQD.js.map} +1 -1
- package/bizar-dash/dist/assets/{shield-alert-Dm48D034.js → shield-alert-DA9K6uZO.js} +1 -1
- package/bizar-dash/dist/assets/{shield-alert-Dm48D034.js.map → shield-alert-DA9K6uZO.js.map} +1 -1
- package/bizar-dash/dist/assets/{trash-2-B885GY46.js → trash-2-B_Y6HrfN.js} +2 -2
- package/bizar-dash/dist/assets/{trash-2-B885GY46.js.map → trash-2-B_Y6HrfN.js.map} +1 -1
- package/bizar-dash/dist/assets/{trending-up-CqUBvVxw.js → trending-up-qKTUQKIT.js} +1 -1
- package/bizar-dash/dist/assets/{trending-up-CqUBvVxw.js.map → trending-up-qKTUQKIT.js.map} +1 -1
- package/bizar-dash/dist/assets/{triangle-alert-DLmUhymD.js → triangle-alert-BeY8LAv6.js} +1 -1
- package/bizar-dash/dist/assets/{triangle-alert-DLmUhymD.js.map → triangle-alert-BeY8LAv6.js.map} +1 -1
- package/bizar-dash/dist/assets/{upload-C-oafpyE.js → upload-BZCtmqIh.js} +1 -1
- package/bizar-dash/dist/assets/{upload-C-oafpyE.js.map → upload-BZCtmqIh.js.map} +1 -1
- package/bizar-dash/dist/assets/{zap-O_4Ys_hh.js → zap-Bz1Z8y1Q.js} +2 -2
- package/bizar-dash/dist/assets/{zap-O_4Ys_hh.js.map → zap-Bz1Z8y1Q.js.map} +1 -1
- package/bizar-dash/dist/index.html +2 -2
- package/bizar-dash/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
- package/bizar-dash/src/web/v8/App.tsx +25 -4
- package/bizar-dash/src/web/v8/shell/Sidebar.tsx +49 -36
- package/bizar-dash/src/web/v8/shell/Topbar.tsx +120 -24
- package/bizar-dash/src/web/v8/ui/feedback/NotificationsPopover.tsx +3 -0
- package/bizar-dash/src/web/v8/ui/feedback/useFocusTrap.ts +58 -0
- package/bizar-dash/src/web/v8/ui/navigation/CommandPalette.tsx +1 -0
- package/bizar-dash/src/web/v8/ui/styles/globals.css +14 -0
- package/bizar-dash/src/web/v8/ui/styles/tokens.css +21 -0
- package/bizar-dash/src/web/v8/ui/theme/ThemeToggle.tsx +11 -6
- package/bizar-dash/src/web/v8/views/Admin/AdminView.tsx +32 -5
- package/bizar-dash/src/web/v8/views/Agents/AgentsView.tsx +11 -4
- package/bizar-dash/src/web/v8/views/Artifacts/ArtifactsView.tsx +1 -1
- package/bizar-dash/src/web/v8/views/Artifacts/ClaudeArtifactView.tsx +1 -1
- package/bizar-dash/src/web/v8/views/Auth/AuthView.tsx +10 -6
- package/bizar-dash/src/web/v8/views/BackgroundJobs/BackgroundJobsView.tsx +38 -13
- package/bizar-dash/src/web/v8/views/ClaudeSessions/ClaudeSessionDetail.tsx +16 -5
- package/bizar-dash/src/web/v8/views/Clipboard/ClipboardView.tsx +1 -1
- package/bizar-dash/src/web/v8/views/Dialogs/DialogsView.tsx +1 -1
- package/bizar-dash/src/web/v8/views/LightRAG/LightRAGView.tsx +23 -2
- package/bizar-dash/src/web/v8/views/Misc/MiscView.tsx +1 -1
- package/bizar-dash/src/web/v8/views/Notifications/NotificationsView.tsx +82 -13
- package/bizar-dash/src/web/v8/views/Overview/OverviewView.tsx +19 -0
- package/bizar-dash/src/web/v8/views/Schedules/SchedulesView.tsx +48 -13
- package/bizar-dash/src/web/v8/views/Settings/SettingsView.tsx +3 -3
- package/bizar-dash/src/web/v8/views/Voice/VoiceView.tsx +1 -1
- package/bizar-dash/tests/admin-run-grouping.test.mjs +42 -0
- package/bizar-dash/tests/agents-preview-truncate.test.mjs +35 -0
- package/bizar-dash/tests/auth-inputs-labels.test.mjs +45 -0
- package/bizar-dash/tests/background-jobs-action-labels.test.mjs +41 -0
- package/bizar-dash/tests/background-jobs-states.test.mjs +80 -0
- package/bizar-dash/tests/banner-tones.test.mjs +50 -0
- package/bizar-dash/tests/callout-tokens.test.mjs +30 -0
- package/bizar-dash/tests/claude-session-detail-states.test.mjs +67 -0
- package/bizar-dash/tests/components/BackgroundJobsSkeleton.test.tsx +38 -0
- package/bizar-dash/tests/density-tokens.test.mjs +46 -0
- package/bizar-dash/tests/doctor-route-shape.test.mjs +67 -0
- package/bizar-dash/tests/empty-state-docs.test.mjs +55 -0
- package/bizar-dash/tests/errorstate-retry.test.mjs +42 -0
- package/bizar-dash/tests/focus-visible.test.mjs +30 -0
- package/bizar-dash/tests/lightrag-skeleton.test.mjs +31 -0
- package/bizar-dash/tests/lightrag-states.test.mjs +60 -0
- package/bizar-dash/tests/modal-focus-trap.test.mjs +114 -0
- package/bizar-dash/tests/notifications-dismiss-restore.test.mjs +85 -0
- package/bizar-dash/tests/orphan-tests-audit.test.mjs +80 -0
- package/bizar-dash/tests/palette-keyboard-nav.test.mjs +123 -0
- package/bizar-dash/tests/palette-shortcut-hint.test.mjs +58 -0
- package/bizar-dash/tests/schedules-skeleton.test.mjs +25 -0
- package/bizar-dash/tests/schedules-states.test.mjs +67 -0
- package/bizar-dash/tests/sidebar-collapse-animation.test.mjs +37 -0
- package/bizar-dash/tests/sidebar-distinct-icons.test.mjs +28 -0
- package/bizar-dash/tests/sidebar-section-styles.test.mjs +55 -0
- package/bizar-dash/tests/skeleton-height.test.mjs +47 -0
- package/bizar-dash/tests/space-tokens.test.mjs +36 -0
- package/bizar-dash/tests/stattile-loading.test.mjs +28 -0
- package/bizar-dash/tests/theme-toggle-icon.test.mjs +28 -0
- package/bizar-dash/tests/topbar-design-system.test.mjs +56 -0
- package/bizar-dash/tests/topbar-popover-styles.test.mjs +53 -0
- package/bizar-dash/tests/update-channels.test.mjs +67 -0
- package/bizar-dash/vite.config.ts +8 -0
- package/package.json +1 -1
- package/packages/sdk/${HOME}/.bizar_home/memory/projects/sdk/sessions/2026-07-16-e16c2f59.md +14 -0
- package/packages/sdk/.bizar/learning/instincts.jsonl +5 -0
- package/packages/sdk/package.json +1 -1
- package/scripts/loop-log.txt +29 -0
- package/scripts/loop-tasks.md +79 -0
- package/scripts/overnight-loop.mjs +60 -0
- package/bizar-dash/dist/assets/AdminView-CI4zM2Qg.js +0 -11
- package/bizar-dash/dist/assets/AdminView-CI4zM2Qg.js.map +0 -1
- package/bizar-dash/dist/assets/AgentsView-CIQkZH8_.js.map +0 -1
- package/bizar-dash/dist/assets/ArtifactsView-B-YUwZyb.js +0 -21
- package/bizar-dash/dist/assets/ArtifactsView-B-YUwZyb.js.map +0 -1
- package/bizar-dash/dist/assets/AuthView-LaQuGo4u.js.map +0 -1
- package/bizar-dash/dist/assets/Avatar-Dg4OF4RD.js +0 -6
- package/bizar-dash/dist/assets/Avatar-Dg4OF4RD.js.map +0 -1
- package/bizar-dash/dist/assets/BackgroundJobsView-CO3DEG8R.js +0 -1
- package/bizar-dash/dist/assets/BackgroundJobsView-CO3DEG8R.js.map +0 -1
- package/bizar-dash/dist/assets/ClaudeSessionsView-D-YNmzKi.js +0 -1
- package/bizar-dash/dist/assets/ClaudeSessionsView-D-YNmzKi.js.map +0 -1
- package/bizar-dash/dist/assets/ClipboardView-BA323V2J.js +0 -1
- package/bizar-dash/dist/assets/ClipboardView-BA323V2J.js.map +0 -1
- package/bizar-dash/dist/assets/DialogsView-DzTnyX8K.js +0 -6
- package/bizar-dash/dist/assets/DialogsView-DzTnyX8K.js.map +0 -1
- package/bizar-dash/dist/assets/EvalView-lgUhlGJh.js +0 -1
- package/bizar-dash/dist/assets/LibrariesView-Ca_PRjUm.js +0 -6
- package/bizar-dash/dist/assets/LightRAGView-CMk9wOae.js +0 -6
- package/bizar-dash/dist/assets/LightRAGView-CMk9wOae.js.map +0 -1
- package/bizar-dash/dist/assets/MiscView-fBT1TOXC.js +0 -1
- package/bizar-dash/dist/assets/MiscView-fBT1TOXC.js.map +0 -1
- package/bizar-dash/dist/assets/NotificationsView-BKAZLxM2.js +0 -6
- package/bizar-dash/dist/assets/NotificationsView-BKAZLxM2.js.map +0 -1
- package/bizar-dash/dist/assets/ObsidianView-C-AvHfpT.js +0 -1
- package/bizar-dash/dist/assets/OverviewView-CKYzZJe3.js +0 -1
- package/bizar-dash/dist/assets/OverviewView-CKYzZJe3.js.map +0 -1
- package/bizar-dash/dist/assets/SchedulesView-8qxH3bg7.js +0 -1
- package/bizar-dash/dist/assets/SchedulesView-8qxH3bg7.js.map +0 -1
- package/bizar-dash/dist/assets/SettingsView-UD403neY.js.map +0 -1
- package/bizar-dash/dist/assets/UpdateView-B9Lh4svM.js +0 -6
- package/bizar-dash/dist/assets/UpdateView-B9Lh4svM.js.map +0 -1
- package/bizar-dash/dist/assets/VoiceView-BwR9gm5e.js +0 -1
- package/bizar-dash/dist/assets/VoiceView-BwR9gm5e.js.map +0 -1
- package/bizar-dash/dist/assets/main-BZMmD6a8.js +0 -249
- package/bizar-dash/dist/assets/main-BZMmD6a8.js.map +0 -1
- package/bizar-dash/dist/assets/main-DDAMz_H5.css +0 -1
- package/bizar-dash/tests/chat-session-create.test.mjs +0 -391
- package/bizar-dash/tests/chat-session-stream.test.mjs +0 -308
- package/bizar-dash/tests/cline-runner.test.mjs +0 -172
- package/bizar-dash/tests/cline-sessions-detail.test.mjs +0 -434
|
@@ -1,434 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* tests/cline-sessions-detail.test.mjs — v4.2.4
|
|
3
|
-
*
|
|
4
|
-
* Tests the cline session-detail router (GET messages, POST send,
|
|
5
|
-
* GET stream SSE proxy). Strategy: stand up a fake cline serve child
|
|
6
|
-
* on a random port, point readServeInfo() at it by writing a tmp
|
|
7
|
-
* serve.json to the first candidate path (~/.cache/bizar/serve.json).
|
|
8
|
-
* For the "plugin offline" case, move our tmp serve.json aside so
|
|
9
|
-
* readServeInfo() finds nothing.
|
|
10
|
-
*
|
|
11
|
-
* We restore the original serve.json (if any) in `after()`.
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
import { test, before, after, beforeEach } from 'node:test';
|
|
15
|
-
import assert from 'node:assert/strict';
|
|
16
|
-
import {
|
|
17
|
-
mkdtempSync,
|
|
18
|
-
writeFileSync,
|
|
19
|
-
rmSync,
|
|
20
|
-
existsSync,
|
|
21
|
-
copyFileSync,
|
|
22
|
-
unlinkSync,
|
|
23
|
-
readFileSync,
|
|
24
|
-
mkdirSync,
|
|
25
|
-
} from 'node:fs';
|
|
26
|
-
import { join } from 'node:path';
|
|
27
|
-
import { tmpdir, homedir } from 'node:os';
|
|
28
|
-
import { createServer } from 'node:http';
|
|
29
|
-
import express from 'express';
|
|
30
|
-
|
|
31
|
-
import { createClineSessionDetailRouter } from '../src/server/routes/cline-session-detail.mjs';
|
|
32
|
-
|
|
33
|
-
// ── fake upstream (cline serve child) ──────────────────────────────────
|
|
34
|
-
|
|
35
|
-
let upstreamServer, upstreamPort;
|
|
36
|
-
const upstream = { promptHits: [], lastPromptBody: null, streamChunks: [] };
|
|
37
|
-
|
|
38
|
-
function startUpstream() {
|
|
39
|
-
return new Promise((resolve) => {
|
|
40
|
-
upstreamServer = createServer((req, res) => {
|
|
41
|
-
const url = new URL(req.url, 'http://127.0.0.1');
|
|
42
|
-
if (url.pathname === '/event') {
|
|
43
|
-
res.writeHead(200, { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', Connection: 'keep-alive' });
|
|
44
|
-
for (const c of upstream.streamChunks) res.write(c);
|
|
45
|
-
setTimeout(() => res.end(), 50);
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
const promptM = url.pathname.match(/^\/api\/session\/([^/]+)\/prompt$/);
|
|
49
|
-
if (promptM && req.method === 'POST') {
|
|
50
|
-
let body = '';
|
|
51
|
-
req.on('data', (c) => { body += c; });
|
|
52
|
-
req.on('end', () => {
|
|
53
|
-
upstream.promptHits.push({ sessionId: promptM[1], body });
|
|
54
|
-
try { upstream.lastPromptBody = JSON.parse(body); } catch { /* ignore */ }
|
|
55
|
-
if (promptM[1] === 'sess-fail') {
|
|
56
|
-
res.writeHead(404, { 'Content-Type': 'application/json' }); res.end('not found'); return;
|
|
57
|
-
}
|
|
58
|
-
res.writeHead(200, { 'Content-Type': 'application/json' }); res.end('{}');
|
|
59
|
-
});
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
if (url.pathname === '/api/session' && req.method === 'GET') {
|
|
63
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
64
|
-
res.end(JSON.stringify({ data: [{ id: 'sess-1', title: 'Test', time: { created: 1, updated: 2, archived: null }, location: { directory: '/tmp/session-worktree' } }] }));
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
// v5.0.0 — bug #4: per-session probe used by `worktreeHasSession`
|
|
68
|
-
// (resolveSessionDirectory fast-path). Matches `/api/session/{id}`
|
|
69
|
-
// (no `/message` or `/prompt` suffix). 200 when the session
|
|
70
|
-
// belongs to the directory in the query string; 404 otherwise.
|
|
71
|
-
const probeM = url.pathname.match(/^\/api\/session\/([^/]+)$/);
|
|
72
|
-
if (probeM && req.method === 'GET') {
|
|
73
|
-
const dir = url.searchParams.get('directory') || '';
|
|
74
|
-
// The session "lives" in /tmp/session-worktree (matches the
|
|
75
|
-
// recorded worktree in writeServeJson). All other directories
|
|
76
|
-
// 404 so we can test the fallback path.
|
|
77
|
-
if (dir === '/tmp/session-worktree') {
|
|
78
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
79
|
-
res.end(JSON.stringify({ id: probeM[1] }));
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
83
|
-
res.end(JSON.stringify({ error: 'session not found in directory' }));
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
const msgM = url.pathname.match(/^\/api\/session\/([^/]+)\/message$/);
|
|
87
|
-
if (msgM && req.method === 'GET') {
|
|
88
|
-
if (msgM[1] === 'sess-upstream-500') {
|
|
89
|
-
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
90
|
-
res.end(JSON.stringify({ error: 'internal server error for testing' }));
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
94
|
-
res.end(JSON.stringify({ data: [
|
|
95
|
-
{ info: { id: 'm1', role: 'user', time: { created: 1000 } }, parts: [{ type: 'text', text: 'hello' }] },
|
|
96
|
-
{ info: { id: 'm2', role: 'assistant', time: { created: 2000 } }, parts: [{ type: 'text', text: 'hi' }] },
|
|
97
|
-
] }));
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
res.writeHead(404); res.end('not found');
|
|
101
|
-
});
|
|
102
|
-
upstreamServer.listen(0, '127.0.0.1', () => {
|
|
103
|
-
upstreamPort = upstreamServer.address().port;
|
|
104
|
-
resolve();
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
async function startDashboard() {
|
|
110
|
-
const app = express();
|
|
111
|
-
app.use(express.json({ limit: '2mb' }));
|
|
112
|
-
app.use('/api', createClineSessionDetailRouter());
|
|
113
|
-
dashboardServer = createServer(app);
|
|
114
|
-
await new Promise((r) => dashboardServer.listen(0, '127.0.0.1', r));
|
|
115
|
-
dashboardBaseUrl = `http://127.0.0.1:${dashboardServer.address().port}`;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
let dashboardServer, dashboardBaseUrl, tmpDir;
|
|
119
|
-
let SERVE_JSON_PATH;
|
|
120
|
-
let originalServeJson;
|
|
121
|
-
|
|
122
|
-
before(async () => {
|
|
123
|
-
SERVE_JSON_PATH = `${tmpdir()}/bizar-test-serve-detail-${process.pid}-${Date.now()}.json`;
|
|
124
|
-
process.env.BIZAR_SERVE_JSON_PATH = SERVE_JSON_PATH;
|
|
125
|
-
await startUpstream();
|
|
126
|
-
await startDashboard();
|
|
127
|
-
tmpDir = mkdtempSync(join(tmpdir(), 'cline-sessions-detail-'));
|
|
128
|
-
if (existsSync(SERVE_JSON_PATH)) {
|
|
129
|
-
originalServeJson = readFileSync(SERVE_JSON_PATH, 'utf8');
|
|
130
|
-
}
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
after(async () => {
|
|
134
|
-
if (originalServeJson !== undefined) {
|
|
135
|
-
writeFileSync(SERVE_JSON_PATH, originalServeJson, 'utf8');
|
|
136
|
-
} else if (existsSync(SERVE_JSON_PATH)) {
|
|
137
|
-
rmSync(SERVE_JSON_PATH);
|
|
138
|
-
}
|
|
139
|
-
if (dashboardServer) await new Promise((r) => dashboardServer.close(r));
|
|
140
|
-
if (upstreamServer) await new Promise((r) => upstreamServer.close(r));
|
|
141
|
-
if (tmpDir) rmSync(tmpDir, { recursive: true, force: true });
|
|
142
|
-
delete process.env.BIZAR_SERVE_JSON_PATH;
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
beforeEach(() => {
|
|
146
|
-
upstream.promptHits = [];
|
|
147
|
-
upstream.lastPromptBody = null;
|
|
148
|
-
upstream.streamChunks = [];
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
function writeServeJson(worktree) {
|
|
152
|
-
writeFileSync(SERVE_JSON_PATH, JSON.stringify({ port: upstreamPort, password: 'test-pw', worktree, pid: 99999, startedAt: Date.now() }), 'utf8');
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
function writeServeJsonWithoutWorktree() {
|
|
156
|
-
writeFileSync(SERVE_JSON_PATH, JSON.stringify({ port: upstreamPort, password: 'test-pw', pid: 99999, startedAt: Date.now() }), 'utf8');
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/** Move serve.json aside so readServeInfo() returns null.
|
|
160
|
-
* Uses copy + unlink because rename across filesystems (e.g.
|
|
161
|
-
* /home/* → /tmp/*) throws EXDEV on Linux. */
|
|
162
|
-
function moveServeJsonAside() {
|
|
163
|
-
if (!existsSync(SERVE_JSON_PATH)) return;
|
|
164
|
-
const tmp = join(tmpDir, `serve-aside-${Date.now()}-${process.pid}.json`);
|
|
165
|
-
copyFileSync(SERVE_JSON_PATH, tmp);
|
|
166
|
-
unlinkSync(SERVE_JSON_PATH);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
function parseSseStream(text) {
|
|
170
|
-
const out = [];
|
|
171
|
-
let event = null, dataLines = [];
|
|
172
|
-
for (const line of text.split(/\r?\n/)) {
|
|
173
|
-
if (line === '') {
|
|
174
|
-
if (event !== null || dataLines.length > 0) out.push({ event, data: dataLines.join('\n') });
|
|
175
|
-
event = null; dataLines = [];
|
|
176
|
-
continue;
|
|
177
|
-
}
|
|
178
|
-
if (line.startsWith(':')) continue;
|
|
179
|
-
const colon = line.indexOf(':');
|
|
180
|
-
if (colon < 0) continue;
|
|
181
|
-
const field = line.slice(0, colon);
|
|
182
|
-
let value = line.slice(colon + 1);
|
|
183
|
-
if (value.startsWith(' ')) value = value.slice(1);
|
|
184
|
-
if (field === 'event') event = value;
|
|
185
|
-
else if (field === 'data') dataLines.push(value);
|
|
186
|
-
}
|
|
187
|
-
return out;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// ── tests ─────────────────────────────────────────────────────────────────
|
|
191
|
-
|
|
192
|
-
test('GET messages returns 503 plugin_offline when no serve.json', async () => {
|
|
193
|
-
moveServeJsonAside();
|
|
194
|
-
try {
|
|
195
|
-
const res = await fetch(`${dashboardBaseUrl}/api/cline-sessions/sess-1/messages`);
|
|
196
|
-
assert.equal(res.status, 503);
|
|
197
|
-
assert.equal((await res.json()).error, 'plugin_offline');
|
|
198
|
-
} finally {
|
|
199
|
-
// Restore — the next test wants serve.json present again.
|
|
200
|
-
if (originalServeJson !== undefined) writeServeJson(JSON.parse(originalServeJson).worktree);
|
|
201
|
-
}
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
test('GET messages returns 200 with normalized message list', async () => {
|
|
205
|
-
writeServeJson('/tmp/session-worktree');
|
|
206
|
-
const res = await fetch(`${dashboardBaseUrl}/api/cline-sessions/sess-1/messages`);
|
|
207
|
-
assert.equal(res.status, 200);
|
|
208
|
-
const body = await res.json();
|
|
209
|
-
assert.equal(body.messages.length, 2);
|
|
210
|
-
assert.equal(body.messages[0].id, 'm1');
|
|
211
|
-
assert.equal(body.messages[0].role, 'user');
|
|
212
|
-
assert.equal(body.messages[0].content, 'hello');
|
|
213
|
-
assert.equal(body.messages[0].ts, 1000);
|
|
214
|
-
assert.equal(body.messages[1].role, 'assistant');
|
|
215
|
-
assert.equal(body.messages[1].content, 'hi');
|
|
216
|
-
assert.equal(body.messages[1].ts, 2000);
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
test('POST send returns 400 when body is empty', async () => {
|
|
220
|
-
writeServeJson('/tmp/session-worktree');
|
|
221
|
-
const r = await fetch(`${dashboardBaseUrl}/api/cline-sessions/sess-1/send`, {
|
|
222
|
-
method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({}),
|
|
223
|
-
});
|
|
224
|
-
assert.equal(r.status, 400);
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
test('POST send returns 400 when agent is missing', async () => {
|
|
228
|
-
writeServeJson('/tmp/session-worktree');
|
|
229
|
-
const r = await fetch(`${dashboardBaseUrl}/api/cline-sessions/sess-1/send`, {
|
|
230
|
-
method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ message: 'hi' }),
|
|
231
|
-
});
|
|
232
|
-
assert.equal(r.status, 400);
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
test('POST send returns 400 when message is empty string', async () => {
|
|
236
|
-
writeServeJson('/tmp/session-worktree');
|
|
237
|
-
const r = await fetch(`${dashboardBaseUrl}/api/cline-sessions/sess-1/send`, {
|
|
238
|
-
method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ message: '', agent: 'odin' }),
|
|
239
|
-
});
|
|
240
|
-
assert.equal(r.status, 400);
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
test('POST send returns ok=true with synthesized messageId', async () => {
|
|
244
|
-
writeServeJson('/tmp/session-worktree');
|
|
245
|
-
const r = await fetch(`${dashboardBaseUrl}/api/cline-sessions/sess-1/send`, {
|
|
246
|
-
method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ message: 'hello there', agent: 'odin' }),
|
|
247
|
-
});
|
|
248
|
-
assert.equal(r.status, 200);
|
|
249
|
-
const body = await r.json();
|
|
250
|
-
assert.equal(body.ok, true);
|
|
251
|
-
assert.ok(body.messageId.startsWith('msg_'));
|
|
252
|
-
assert.equal(upstream.promptHits.length, 1);
|
|
253
|
-
assert.equal(upstream.lastPromptBody.prompt.text, 'hello there');
|
|
254
|
-
assert.equal(upstream.lastPromptBody.agent, 'odin');
|
|
255
|
-
assert.equal(upstream.lastPromptBody.id, body.messageId);
|
|
256
|
-
});
|
|
257
|
-
|
|
258
|
-
test('POST send returns 502 cline_error when upstream 404s', async () => {
|
|
259
|
-
writeServeJson('/tmp/session-worktree');
|
|
260
|
-
const r = await fetch(`${dashboardBaseUrl}/api/cline-sessions/sess-fail/send`, {
|
|
261
|
-
method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ message: 'hi', agent: 'odin' }),
|
|
262
|
-
});
|
|
263
|
-
assert.equal(r.status, 502);
|
|
264
|
-
const body = await r.json();
|
|
265
|
-
assert.equal(body.error, 'cline_error');
|
|
266
|
-
assert.ok(body.message.length > 0);
|
|
267
|
-
});
|
|
268
|
-
|
|
269
|
-
test('SSE stream forwards only events for the requested session', async () => {
|
|
270
|
-
writeServeJson('/tmp/session-worktree');
|
|
271
|
-
upstream.streamChunks = [
|
|
272
|
-
'event: message.updated\ndata: {"type":"message.updated","properties":{"sessionID":"our-id","messageID":"m1"}}\n\n',
|
|
273
|
-
'event: message.updated\ndata: {"type":"message.updated","properties":{"sessionID":"OTHER-id","messageID":"m9"}}\n\n',
|
|
274
|
-
'event: sync\ndata: {"type":"sync","syncEvent":{"type":"session.idle.1","data":{"sessionID":"our-id"}}}\n\n',
|
|
275
|
-
];
|
|
276
|
-
const res = await fetch(`${dashboardBaseUrl}/api/cline-sessions/our-id/stream`);
|
|
277
|
-
assert.equal(res.status, 200);
|
|
278
|
-
assert.match(res.headers.get('content-type'), /text\/event-stream/);
|
|
279
|
-
assert.match(res.headers.get('cache-control'), /no-cache/);
|
|
280
|
-
assert.equal(res.headers.get('x-accel-buffering'), 'no');
|
|
281
|
-
const events = parseSseStream(await res.text());
|
|
282
|
-
assert.equal(events.length, 2);
|
|
283
|
-
assert.equal(events[0].event, 'message.updated');
|
|
284
|
-
const d0 = JSON.parse(events[0].data);
|
|
285
|
-
assert.equal(d0.sessionID, 'our-id');
|
|
286
|
-
assert.equal(d0.messageID, 'm1');
|
|
287
|
-
assert.equal(events[1].event, 'session.idle');
|
|
288
|
-
assert.equal(JSON.parse(events[1].data).sessionID, 'our-id');
|
|
289
|
-
});
|
|
290
|
-
|
|
291
|
-
test('SSE stream unwraps sync envelopes and strips version suffix', async () => {
|
|
292
|
-
writeServeJson('/tmp/session-worktree');
|
|
293
|
-
upstream.streamChunks = [
|
|
294
|
-
'event: sync\ndata: {"type":"sync","syncEvent":{"type":"message.updated.1","data":{"sessionID":"our-id","messageID":"m3"}}}\n\n',
|
|
295
|
-
];
|
|
296
|
-
const res = await fetch(`${dashboardBaseUrl}/api/cline-sessions/our-id/stream`);
|
|
297
|
-
assert.equal(res.status, 200);
|
|
298
|
-
const events = parseSseStream(await res.text());
|
|
299
|
-
assert.equal(events.length, 1);
|
|
300
|
-
assert.equal(events[0].event, 'message.updated');
|
|
301
|
-
const d = JSON.parse(events[0].data);
|
|
302
|
-
assert.equal(d.sessionID, 'our-id');
|
|
303
|
-
assert.equal(d.messageID, 'm3');
|
|
304
|
-
});
|
|
305
|
-
|
|
306
|
-
// ── Error handling tests ─────────────────────────────────────────────────
|
|
307
|
-
|
|
308
|
-
test('GET messages returns 503 directory_unknown when worktree missing and session not found', async () => {
|
|
309
|
-
writeServeJsonWithoutWorktree();
|
|
310
|
-
try {
|
|
311
|
-
// Request a non-existent session ID so listClineSessions doesn't find it,
|
|
312
|
-
// and with no worktree in serve.json, resolveSessionDirectory returns null.
|
|
313
|
-
const res = await fetch(`${dashboardBaseUrl}/api/cline-sessions/no-such-session/messages`);
|
|
314
|
-
assert.equal(res.status, 503);
|
|
315
|
-
const body = await res.json();
|
|
316
|
-
assert.equal(body.error, 'directory_unknown');
|
|
317
|
-
assert.ok(body.message.length > 0);
|
|
318
|
-
assert.ok(typeof body.suggestion === 'string');
|
|
319
|
-
} finally {
|
|
320
|
-
// Restore worktree for subsequent tests.
|
|
321
|
-
writeServeJson('/tmp/session-worktree');
|
|
322
|
-
}
|
|
323
|
-
});
|
|
324
|
-
|
|
325
|
-
test('GET messages returns 502 cline_error when upstream returns 500', async () => {
|
|
326
|
-
writeServeJson('/tmp/session-worktree');
|
|
327
|
-
const res = await fetch(`${dashboardBaseUrl}/api/cline-sessions/sess-upstream-500/messages`);
|
|
328
|
-
assert.equal(res.status, 502);
|
|
329
|
-
const body = await res.json();
|
|
330
|
-
assert.equal(body.error, 'cline_error');
|
|
331
|
-
assert.ok(body.message.length > 0);
|
|
332
|
-
assert.ok(body.cause === 'unknown' || typeof body.cause === 'string');
|
|
333
|
-
assert.ok(typeof body.suggestion === 'string');
|
|
334
|
-
});
|
|
335
|
-
|
|
336
|
-
test('GET messages uses suggestion field in error responses', async () => {
|
|
337
|
-
// Test that the plugin_offline response includes suggestion.
|
|
338
|
-
moveServeJsonAside();
|
|
339
|
-
try {
|
|
340
|
-
const res = await fetch(`${dashboardBaseUrl}/api/cline-sessions/sess-1/messages`);
|
|
341
|
-
assert.equal(res.status, 503);
|
|
342
|
-
const body = await res.json();
|
|
343
|
-
assert.equal(body.error, 'plugin_offline');
|
|
344
|
-
assert.ok(typeof body.suggestion === 'string');
|
|
345
|
-
assert.ok(body.suggestion.length > 0);
|
|
346
|
-
} finally {
|
|
347
|
-
// Restore so the after() cleanup finds the file.
|
|
348
|
-
writeServeJson('/tmp/session-worktree');
|
|
349
|
-
}
|
|
350
|
-
});
|
|
351
|
-
|
|
352
|
-
// ── v5.0.0 — bug #4 — structured error envelopes + worktree fast-path ──
|
|
353
|
-
|
|
354
|
-
test('GET messages 502 envelope includes cause/status/suggestion on upstream failure', async () => {
|
|
355
|
-
// Issue: bug #4 — the user previously saw the raw error string
|
|
356
|
-
// ("listMessages network error: fetch failed") with no structured
|
|
357
|
-
// fields. The fix is to surface `cause`, `status`, and `suggestion`
|
|
358
|
-
// so the front-end ChatInfoPanel can render actionable UI.
|
|
359
|
-
writeServeJson('/tmp/session-worktree');
|
|
360
|
-
const res = await fetch(
|
|
361
|
-
`${dashboardBaseUrl}/api/cline-sessions/sess-upstream-500/messages`,
|
|
362
|
-
);
|
|
363
|
-
assert.equal(res.status, 502);
|
|
364
|
-
const body = await res.json();
|
|
365
|
-
assert.equal(body.error, 'cline_error');
|
|
366
|
-
assert.equal(typeof body.message, 'string');
|
|
367
|
-
assert.ok(body.message.length > 0);
|
|
368
|
-
// Upstream 500 → cause stays 'unknown' (no network code), and the
|
|
369
|
-
// route forwards the upstream's HTTP status so the operator can
|
|
370
|
-
// tell whether it's cline that's broken vs. the dashboard.
|
|
371
|
-
assert.ok(typeof body.cause === 'string');
|
|
372
|
-
assert.equal(body.status, 500);
|
|
373
|
-
assert.ok(typeof body.suggestion === 'string');
|
|
374
|
-
assert.ok(body.suggestion.length > 0);
|
|
375
|
-
});
|
|
376
|
-
|
|
377
|
-
test('GET messages 503 plugin_offline envelope includes suggestion (operator guidance)', async () => {
|
|
378
|
-
// Defensive: confirm the 503 path also carries a suggestion (some
|
|
379
|
-
// consumers — including the structured-error path in useChat.ts —
|
|
380
|
-
// branch on `body.code === 'plugin_offline'`).
|
|
381
|
-
moveServeJsonAside();
|
|
382
|
-
try {
|
|
383
|
-
const res = await fetch(
|
|
384
|
-
`${dashboardBaseUrl}/api/cline-sessions/sess-1/messages`,
|
|
385
|
-
);
|
|
386
|
-
assert.equal(res.status, 503);
|
|
387
|
-
const body = await res.json();
|
|
388
|
-
assert.equal(body.error, 'plugin_offline');
|
|
389
|
-
assert.ok(typeof body.suggestion === 'string');
|
|
390
|
-
assert.ok(body.suggestion.length > 0);
|
|
391
|
-
assert.match(body.suggestion, /bizar doctor|cline serve/i);
|
|
392
|
-
} finally {
|
|
393
|
-
writeServeJson('/tmp/session-worktree');
|
|
394
|
-
}
|
|
395
|
-
});
|
|
396
|
-
|
|
397
|
-
test('GET messages 503 directory_unknown envelope includes suggestion', async () => {
|
|
398
|
-
writeServeJsonWithoutWorktree();
|
|
399
|
-
try {
|
|
400
|
-
const res = await fetch(
|
|
401
|
-
`${dashboardBaseUrl}/api/cline-sessions/no-such-session/messages`,
|
|
402
|
-
);
|
|
403
|
-
assert.equal(res.status, 503);
|
|
404
|
-
const body = await res.json();
|
|
405
|
-
assert.equal(body.error, 'directory_unknown');
|
|
406
|
-
assert.ok(typeof body.message === 'string');
|
|
407
|
-
assert.ok(typeof body.suggestion === 'string');
|
|
408
|
-
assert.ok(body.suggestion.length > 0);
|
|
409
|
-
} finally {
|
|
410
|
-
writeServeJson('/tmp/session-worktree');
|
|
411
|
-
}
|
|
412
|
-
});
|
|
413
|
-
|
|
414
|
-
test('GET messages uses worktree fast-path when session exists in recorded worktree', async () => {
|
|
415
|
-
// The new resolveSessionDirectory fast-path probes the recorded
|
|
416
|
-
// worktree first (cheap GET /api/session/{id}?directory=... probe).
|
|
417
|
-
// When the upstream says yes, the resolver returns the worktree
|
|
418
|
-
// WITHOUT calling GET /api/session. We assert the latter is NOT
|
|
419
|
-
// called by checking the upstream.promptHits / request log isn't
|
|
420
|
-
// touched (only the messages endpoint should fire here).
|
|
421
|
-
//
|
|
422
|
-
// Indirect check: request a session whose id is NOT in the
|
|
423
|
-
// /api/session listing but IS in /tmp/session-worktree per the
|
|
424
|
-
// probe. The probe handler returns 200 for that directory, so the
|
|
425
|
-
// route should succeed even though the session isn't in the list.
|
|
426
|
-
writeServeJson('/tmp/session-worktree');
|
|
427
|
-
const res = await fetch(
|
|
428
|
-
`${dashboardBaseUrl}/api/cline-sessions/sess-1/messages`,
|
|
429
|
-
);
|
|
430
|
-
assert.equal(res.status, 200);
|
|
431
|
-
const body = await res.json();
|
|
432
|
-
assert.ok(Array.isArray(body.messages));
|
|
433
|
-
assert.ok(body.messages.length >= 1);
|
|
434
|
-
});
|