@polderlabs/bizar 10.4.2 → 10.4.3
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-DtRtg-JN.js → ActivityFeed-DC0JiK49.js} +1 -1
- package/bizar-dash/dist/assets/{ActivityFeed-DtRtg-JN.js.map → ActivityFeed-DC0JiK49.js.map} +1 -1
- package/bizar-dash/dist/assets/{ActivityView-CoTXDyU_.js → ActivityView-ubEDAWMY.js} +1 -1
- package/bizar-dash/dist/assets/{ActivityView-CoTXDyU_.js.map → ActivityView-ubEDAWMY.js.map} +1 -1
- package/bizar-dash/dist/assets/{AdminView-DNc5Ll7L.js → AdminView-CI4zM2Qg.js} +1 -1
- package/bizar-dash/dist/assets/{AdminView-DNc5Ll7L.js.map → AdminView-CI4zM2Qg.js.map} +1 -1
- package/bizar-dash/dist/assets/{AgentActivity-CrX7LmQ6.js → AgentActivity-BLcqqkt2.js} +1 -1
- package/bizar-dash/dist/assets/{AgentActivity-CrX7LmQ6.js.map → AgentActivity-BLcqqkt2.js.map} +1 -1
- package/bizar-dash/dist/assets/AgentsView-CIQkZH8_.js +15 -0
- package/bizar-dash/dist/assets/AgentsView-CIQkZH8_.js.map +1 -0
- package/bizar-dash/dist/assets/{Alert-B6DjfRFI.js → Alert-MwVEymjy.js} +1 -1
- package/bizar-dash/dist/assets/{Alert-B6DjfRFI.js.map → Alert-MwVEymjy.js.map} +1 -1
- package/bizar-dash/dist/assets/{ArtifactsView-znhN8GTR.js → ArtifactsView-B-YUwZyb.js} +1 -1
- package/bizar-dash/dist/assets/{ArtifactsView-znhN8GTR.js.map → ArtifactsView-B-YUwZyb.js.map} +1 -1
- package/bizar-dash/dist/assets/{AuthView-Rk8eKUPr.js → AuthView-LaQuGo4u.js} +1 -1
- package/bizar-dash/dist/assets/{AuthView-Rk8eKUPr.js.map → AuthView-LaQuGo4u.js.map} +1 -1
- package/bizar-dash/dist/assets/{Avatar-B41upSD1.js → Avatar-Dg4OF4RD.js} +1 -1
- package/bizar-dash/dist/assets/{Avatar-B41upSD1.js.map → Avatar-Dg4OF4RD.js.map} +1 -1
- package/bizar-dash/dist/assets/{BackgroundJobsView-BLWuN9qz.js → BackgroundJobsView-CO3DEG8R.js} +1 -1
- package/bizar-dash/dist/assets/{BackgroundJobsView-BLWuN9qz.js.map → BackgroundJobsView-CO3DEG8R.js.map} +1 -1
- package/bizar-dash/dist/assets/{BackupView-CqbtcnuQ.js → BackupView-Cjf23ZWc.js} +1 -1
- package/bizar-dash/dist/assets/{BackupView-CqbtcnuQ.js.map → BackupView-Cjf23ZWc.js.map} +1 -1
- package/bizar-dash/dist/assets/{Card-rF59wHiO.js → Card-BmXiT4c6.js} +1 -1
- package/bizar-dash/dist/assets/{Card-rF59wHiO.js.map → Card-BmXiT4c6.js.map} +1 -1
- package/bizar-dash/dist/assets/ChatView-DXKFwvgp.js +9 -0
- package/bizar-dash/dist/assets/ChatView-DXKFwvgp.js.map +1 -0
- package/bizar-dash/dist/assets/{Chip-Dc2KmeWl.js → Chip-Dei66BLx.js} +1 -1
- package/bizar-dash/dist/assets/{Chip-Dc2KmeWl.js.map → Chip-Dei66BLx.js.map} +1 -1
- package/bizar-dash/dist/assets/{ClaudeSessionsView-CiaHQdDZ.js → ClaudeSessionsView-D-YNmzKi.js} +1 -1
- package/bizar-dash/dist/assets/{ClaudeSessionsView-CiaHQdDZ.js.map → ClaudeSessionsView-D-YNmzKi.js.map} +1 -1
- package/bizar-dash/dist/assets/{ClipboardView-DdP6aVso.js → ClipboardView-BA323V2J.js} +1 -1
- package/bizar-dash/dist/assets/{ClipboardView-DdP6aVso.js.map → ClipboardView-BA323V2J.js.map} +1 -1
- package/bizar-dash/dist/assets/{ConfigView-B2ysnTZU.js → ConfigView-BMBgifw5.js} +1 -1
- package/bizar-dash/dist/assets/{ConfigView-B2ysnTZU.js.map → ConfigView-BMBgifw5.js.map} +1 -1
- package/bizar-dash/dist/assets/DiagnosticsView-C0sdqhEl.js +2 -0
- package/bizar-dash/dist/assets/DiagnosticsView-C0sdqhEl.js.map +1 -0
- package/bizar-dash/dist/assets/{DialogsView-BcqDDCZQ.js → DialogsView-DzTnyX8K.js} +1 -1
- package/bizar-dash/dist/assets/{DialogsView-BcqDDCZQ.js.map → DialogsView-DzTnyX8K.js.map} +1 -1
- package/bizar-dash/dist/assets/{DoctorView-BQwqvMAh.js → DoctorView-CiFwRMW0.js} +1 -1
- package/bizar-dash/dist/assets/{DoctorView-BQwqvMAh.js.map → DoctorView-CiFwRMW0.js.map} +1 -1
- package/bizar-dash/dist/assets/{EmptyState-D65J5FQN.js → EmptyState-CdDQmfEL.js} +1 -1
- package/bizar-dash/dist/assets/{EmptyState-D65J5FQN.js.map → EmptyState-CdDQmfEL.js.map} +1 -1
- package/bizar-dash/dist/assets/{EnvVarsView-DX-3oGH-.js → EnvVarsView-CNO03NDJ.js} +1 -1
- package/bizar-dash/dist/assets/{EnvVarsView-DX-3oGH-.js.map → EnvVarsView-CNO03NDJ.js.map} +1 -1
- package/bizar-dash/dist/assets/{ErrorState-DULZnttJ.js → ErrorState-BRvj8qZZ.js} +1 -1
- package/bizar-dash/dist/assets/{ErrorState-DULZnttJ.js.map → ErrorState-BRvj8qZZ.js.map} +1 -1
- package/bizar-dash/dist/assets/{EvalView-CpdFu_ID.js → EvalView-lgUhlGJh.js} +1 -1
- package/bizar-dash/dist/assets/{EvalView-CpdFu_ID.js.map → EvalView-lgUhlGJh.js.map} +1 -1
- package/bizar-dash/dist/assets/{GoalsView-Br8oPPfb.js → GoalsView-DmkCCs9i.js} +1 -1
- package/bizar-dash/dist/assets/{GoalsView-Br8oPPfb.js.map → GoalsView-DmkCCs9i.js.map} +1 -1
- package/bizar-dash/dist/assets/{Grid-BSXhsCPC.js → Grid-BThCPJaV.js} +1 -1
- package/bizar-dash/dist/assets/{Grid-BSXhsCPC.js.map → Grid-BThCPJaV.js.map} +1 -1
- package/bizar-dash/dist/assets/{HistoryView-D0J3aoZF.js → HistoryView-Cn2cPiHZ.js} +1 -1
- package/bizar-dash/dist/assets/{HistoryView-D0J3aoZF.js.map → HistoryView-Cn2cPiHZ.js.map} +1 -1
- package/bizar-dash/dist/assets/{Input-CZmRw5QX.js → Input-cAQOvR8U.js} +1 -1
- package/bizar-dash/dist/assets/{Input-CZmRw5QX.js.map → Input-cAQOvR8U.js.map} +1 -1
- package/bizar-dash/dist/assets/LibrariesView-Ca_PRjUm.js +6 -0
- package/bizar-dash/dist/assets/{LibrariesView-B1YX9wzp.js.map → LibrariesView-Ca_PRjUm.js.map} +1 -1
- package/bizar-dash/dist/assets/{LightRAGView-CykR0t9y.js → LightRAGView-CMk9wOae.js} +1 -1
- package/bizar-dash/dist/assets/{LightRAGView-CykR0t9y.js.map → LightRAGView-CMk9wOae.js.map} +1 -1
- package/bizar-dash/dist/assets/{ListHeader-Dpun-r36.js → ListHeader-BLAeshe0.js} +1 -1
- package/bizar-dash/dist/assets/{ListHeader-Dpun-r36.js.map → ListHeader-BLAeshe0.js.map} +1 -1
- package/bizar-dash/dist/assets/{MemoryView-BbER5ZKt.js → MemoryView-wo2Pu7xQ.js} +1 -1
- package/bizar-dash/dist/assets/{MemoryView-BbER5ZKt.js.map → MemoryView-wo2Pu7xQ.js.map} +1 -1
- package/bizar-dash/dist/assets/{MessageBubble-5vUAquDx.js → MessageBubble-CrCJ0SYG.js} +1 -1
- package/bizar-dash/dist/assets/{MessageBubble-5vUAquDx.js.map → MessageBubble-CrCJ0SYG.js.map} +1 -1
- package/bizar-dash/dist/assets/{MiscView-DLNEGdML.js → MiscView-fBT1TOXC.js} +1 -1
- package/bizar-dash/dist/assets/{MiscView-DLNEGdML.js.map → MiscView-fBT1TOXC.js.map} +1 -1
- package/bizar-dash/dist/assets/{ModsView-P7gDeNHM.js → ModsView-CV_RxdzJ.js} +1 -1
- package/bizar-dash/dist/assets/{ModsView-P7gDeNHM.js.map → ModsView-CV_RxdzJ.js.map} +1 -1
- package/bizar-dash/dist/assets/{NotificationsView-DAm2O0yf.js → NotificationsView-BKAZLxM2.js} +1 -1
- package/bizar-dash/dist/assets/{NotificationsView-DAm2O0yf.js.map → NotificationsView-BKAZLxM2.js.map} +1 -1
- package/bizar-dash/dist/assets/{ObsidianView-Ci80gnwS.js → ObsidianView-C-AvHfpT.js} +1 -1
- package/bizar-dash/dist/assets/{ObsidianView-Ci80gnwS.js.map → ObsidianView-C-AvHfpT.js.map} +1 -1
- package/bizar-dash/dist/assets/{OverviewView-rriw1GjA.js → OverviewView-CKYzZJe3.js} +1 -1
- package/bizar-dash/dist/assets/{OverviewView-rriw1GjA.js.map → OverviewView-CKYzZJe3.js.map} +1 -1
- package/bizar-dash/dist/assets/{ProgressBar-BahmeJhP.js → ProgressBar-ya2PCj8L.js} +1 -1
- package/bizar-dash/dist/assets/{ProgressBar-BahmeJhP.js.map → ProgressBar-ya2PCj8L.js.map} +1 -1
- package/bizar-dash/dist/assets/ProjectsView-N9zqFZ_O.js +11 -0
- package/bizar-dash/dist/assets/ProjectsView-N9zqFZ_O.js.map +1 -0
- package/bizar-dash/dist/assets/{ProvidersView-BftGn8Cr.js → ProvidersView-BcL8jjwK.js} +1 -1
- package/bizar-dash/dist/assets/{ProvidersView-BftGn8Cr.js.map → ProvidersView-BcL8jjwK.js.map} +1 -1
- package/bizar-dash/dist/assets/{SchedulesView-CtNxtzN6.js → SchedulesView-8qxH3bg7.js} +1 -1
- package/bizar-dash/dist/assets/{SchedulesView-CtNxtzN6.js.map → SchedulesView-8qxH3bg7.js.map} +1 -1
- package/bizar-dash/dist/assets/{Select-0VcfTDeL.js → Select-D5AuVxxV.js} +1 -1
- package/bizar-dash/dist/assets/{Select-0VcfTDeL.js.map → Select-D5AuVxxV.js.map} +1 -1
- package/bizar-dash/dist/assets/{SettingsRow-BLic3DQl.js → SettingsRow-BBALf9dA.js} +1 -1
- package/bizar-dash/dist/assets/{SettingsRow-BLic3DQl.js.map → SettingsRow-BBALf9dA.js.map} +1 -1
- package/bizar-dash/dist/assets/{SettingsView-BjS3i4nr.js → SettingsView-UD403neY.js} +1 -1
- package/bizar-dash/dist/assets/{SettingsView-BjS3i4nr.js.map → SettingsView-UD403neY.js.map} +1 -1
- package/bizar-dash/dist/assets/{Sheet-BOProMs2.js → Sheet-CxXf6gvC.js} +1 -1
- package/bizar-dash/dist/assets/{Sheet-BOProMs2.js.map → Sheet-CxXf6gvC.js.map} +1 -1
- package/bizar-dash/dist/assets/{Slider-B0eLEEUt.js → Slider-hvaVD_SW.js} +1 -1
- package/bizar-dash/dist/assets/{Slider-B0eLEEUt.js.map → Slider-hvaVD_SW.js.map} +1 -1
- package/bizar-dash/dist/assets/{Sparkline-SSrdgyW0.js → Sparkline-DqmQzdJH.js} +1 -1
- package/bizar-dash/dist/assets/{Sparkline-SSrdgyW0.js.map → Sparkline-DqmQzdJH.js.map} +1 -1
- package/bizar-dash/dist/assets/{Switch-B3EQzb_q.js → Switch-C-_zcNdl.js} +1 -1
- package/bizar-dash/dist/assets/{Switch-B3EQzb_q.js.map → Switch-C-_zcNdl.js.map} +1 -1
- package/bizar-dash/dist/assets/{TasksView-SWjF_ZUQ.js → TasksView-DseftDlx.js} +1 -1
- package/bizar-dash/dist/assets/{TasksView-SWjF_ZUQ.js.map → TasksView-DseftDlx.js.map} +1 -1
- package/bizar-dash/dist/assets/{Textarea-QuofpMlq.js → Textarea-CcQGSgSH.js} +1 -1
- package/bizar-dash/dist/assets/{Textarea-QuofpMlq.js.map → Textarea-CcQGSgSH.js.map} +1 -1
- package/bizar-dash/dist/assets/{UpdateView-CEHW2nd6.js → UpdateView-B9Lh4svM.js} +1 -1
- package/bizar-dash/dist/assets/{UpdateView-CEHW2nd6.js.map → UpdateView-B9Lh4svM.js.map} +1 -1
- package/bizar-dash/dist/assets/{UsageView-BqOw6FBg.js → UsageView-P5_pQ68d.js} +1 -1
- package/bizar-dash/dist/assets/{UsageView-BqOw6FBg.js.map → UsageView-P5_pQ68d.js.map} +1 -1
- package/bizar-dash/dist/assets/{ViewHeader-B6P-C4GD.js → ViewHeader-BaCWNuVX.js} +1 -1
- package/bizar-dash/dist/assets/{ViewHeader-B6P-C4GD.js.map → ViewHeader-BaCWNuVX.js.map} +1 -1
- package/bizar-dash/dist/assets/{VoiceView-CwrPwWgi.js → VoiceView-BwR9gm5e.js} +1 -1
- package/bizar-dash/dist/assets/{VoiceView-CwrPwWgi.js.map → VoiceView-BwR9gm5e.js.map} +1 -1
- package/bizar-dash/dist/assets/{brain-CwZt9Kta.js → brain-D6tAeUDE.js} +1 -1
- package/bizar-dash/dist/assets/{brain-CwZt9Kta.js.map → brain-D6tAeUDE.js.map} +1 -1
- package/bizar-dash/dist/assets/{calendar-C5oK0_nM.js → calendar-BrMJf3vl.js} +1 -1
- package/bizar-dash/dist/assets/{calendar-C5oK0_nM.js.map → calendar-BrMJf3vl.js.map} +1 -1
- package/bizar-dash/dist/assets/{circle-alert-HdHe7m8K.js → circle-alert-D7jn06kH.js} +1 -1
- package/bizar-dash/dist/assets/{circle-alert-HdHe7m8K.js.map → circle-alert-D7jn06kH.js.map} +1 -1
- package/bizar-dash/dist/assets/{circle-check-Cs-xoV7R.js → circle-check-DHs37Sot.js} +1 -1
- package/bizar-dash/dist/assets/{circle-check-Cs-xoV7R.js.map → circle-check-DHs37Sot.js.map} +1 -1
- package/bizar-dash/dist/assets/{circle-D1Lc_P2a.js → circle-fPTATiOs.js} +1 -1
- package/bizar-dash/dist/assets/{circle-D1Lc_P2a.js.map → circle-fPTATiOs.js.map} +1 -1
- package/bizar-dash/dist/assets/{clock-DEIuPV60.js → clock-E-G5aGua.js} +1 -1
- package/bizar-dash/dist/assets/{clock-DEIuPV60.js.map → clock-E-G5aGua.js.map} +1 -1
- package/bizar-dash/dist/assets/{cmdk-DVxytz9i.js → cmdk-C3F6LD6N.js} +5 -5
- package/bizar-dash/dist/assets/{cmdk-DVxytz9i.js.map → cmdk-C3F6LD6N.js.map} +1 -1
- package/bizar-dash/dist/assets/{dnd-kit-DrHErSkw.js → dnd-kit-BAOLODOI.js} +1 -1
- package/bizar-dash/dist/assets/{dnd-kit-DrHErSkw.js.map → dnd-kit-BAOLODOI.js.map} +1 -1
- package/bizar-dash/dist/assets/{download-Clkq90Ct.js → download-DBkNb6oI.js} +1 -1
- package/bizar-dash/dist/assets/{download-Clkq90Ct.js.map → download-DBkNb6oI.js.map} +1 -1
- package/bizar-dash/dist/assets/{external-link-D5tq2o_I.js → external-link-C4pHGbz2.js} +1 -1
- package/bizar-dash/dist/assets/{external-link-D5tq2o_I.js.map → external-link-C4pHGbz2.js.map} +1 -1
- package/bizar-dash/dist/assets/{file-text-CQ12t7Oc.js → file-text-CEhDgLq2.js} +1 -1
- package/bizar-dash/dist/assets/{file-text-CQ12t7Oc.js.map → file-text-CEhDgLq2.js.map} +1 -1
- package/bizar-dash/dist/assets/{filter-BcbE37wP.js → filter-CEYjeWFX.js} +1 -1
- package/bizar-dash/dist/assets/{filter-BcbE37wP.js.map → filter-CEYjeWFX.js.map} +1 -1
- package/bizar-dash/dist/assets/{git-pull-request-D1qNDRia.js → git-pull-request-Bo_wBZZw.js} +1 -1
- package/bizar-dash/dist/assets/{git-pull-request-D1qNDRia.js.map → git-pull-request-Bo_wBZZw.js.map} +1 -1
- package/bizar-dash/dist/assets/{index-CASP1n-5.js → index-B1OIS316.js} +1 -1
- package/bizar-dash/dist/assets/{index-CASP1n-5.js.map → index-B1OIS316.js.map} +1 -1
- package/bizar-dash/dist/assets/{index-C4Vq_2LM.js → index-CR0TeJmc.js} +1 -1
- package/bizar-dash/dist/assets/{index-C4Vq_2LM.js.map → index-CR0TeJmc.js.map} +1 -1
- package/bizar-dash/dist/assets/main-BZMmD6a8.js +249 -0
- package/bizar-dash/dist/assets/main-BZMmD6a8.js.map +1 -0
- package/bizar-dash/dist/assets/{main-CcQfRfIJ.css → main-DDAMz_H5.css} +1 -1
- package/bizar-dash/dist/assets/{network-DJdvVaHx.js → network-BsfwrUA-.js} +1 -1
- package/bizar-dash/dist/assets/{network-DJdvVaHx.js.map → network-BsfwrUA-.js.map} +1 -1
- package/bizar-dash/dist/assets/{pause-DUn9L5PB.js → pause-C8PN1_yO.js} +1 -1
- package/bizar-dash/dist/assets/{pause-DUn9L5PB.js.map → pause-C8PN1_yO.js.map} +1 -1
- package/bizar-dash/dist/assets/{pencil-DVrBlYV3.js → pencil---XuvKlz.js} +1 -1
- package/bizar-dash/dist/assets/{pencil-DVrBlYV3.js.map → pencil---XuvKlz.js.map} +1 -1
- package/bizar-dash/dist/assets/{play-CZjsr3XM.js → play-fMLPTihK.js} +1 -1
- package/bizar-dash/dist/assets/{play-CZjsr3XM.js.map → play-fMLPTihK.js.map} +1 -1
- package/bizar-dash/dist/assets/{plug-BKuyIe5W.js → plug-CG8al2Kq.js} +1 -1
- package/bizar-dash/dist/assets/{plug-BKuyIe5W.js.map → plug-CG8al2Kq.js.map} +1 -1
- package/bizar-dash/dist/assets/{plus-77h62zZm.js → plus-uA5Ecuch.js} +1 -1
- package/bizar-dash/dist/assets/{plus-77h62zZm.js.map → plus-uA5Ecuch.js.map} +1 -1
- package/bizar-dash/dist/assets/{power-DLmx-gCP.js → power-DSUlNIuR.js} +1 -1
- package/bizar-dash/dist/assets/{power-DLmx-gCP.js.map → power-DSUlNIuR.js.map} +1 -1
- package/bizar-dash/dist/assets/{power-off-BFKzHXic.js → power-off-1CAQsHHy.js} +1 -1
- package/bizar-dash/dist/assets/{power-off-BFKzHXic.js.map → power-off-1CAQsHHy.js.map} +1 -1
- package/bizar-dash/dist/assets/{refresh-ccw-DenGBOcq.js → refresh-ccw-BL7B0NO1.js} +1 -1
- package/bizar-dash/dist/assets/{refresh-ccw-DenGBOcq.js.map → refresh-ccw-BL7B0NO1.js.map} +1 -1
- package/bizar-dash/dist/assets/{refresh-cw-ENBVR8hW.js → refresh-cw-CR9BzJik.js} +1 -1
- package/bizar-dash/dist/assets/{refresh-cw-ENBVR8hW.js.map → refresh-cw-CR9BzJik.js.map} +1 -1
- package/bizar-dash/dist/assets/{rotate-ccw-MxryaY7q.js → rotate-ccw-BtnitLfb.js} +1 -1
- package/bizar-dash/dist/assets/{rotate-ccw-MxryaY7q.js.map → rotate-ccw-BtnitLfb.js.map} +1 -1
- package/bizar-dash/dist/assets/{rotate-cw-CDOlRtUR.js → rotate-cw-CHgXCO7O.js} +1 -1
- package/bizar-dash/dist/assets/{rotate-cw-CDOlRtUR.js.map → rotate-cw-CHgXCO7O.js.map} +1 -1
- package/bizar-dash/dist/assets/{save-Db1b-1Uq.js → save-RcZOXR0U.js} +1 -1
- package/bizar-dash/dist/assets/{save-Db1b-1Uq.js.map → save-RcZOXR0U.js.map} +1 -1
- package/bizar-dash/dist/assets/{send-yz6HFZM5.js → send-Bg2X_ibk.js} +1 -1
- package/bizar-dash/dist/assets/{send-yz6HFZM5.js.map → send-Bg2X_ibk.js.map} +1 -1
- package/bizar-dash/dist/assets/{shield-alert-DY6RAaC8.js → shield-alert-Dm48D034.js} +1 -1
- package/bizar-dash/dist/assets/{shield-alert-DY6RAaC8.js.map → shield-alert-Dm48D034.js.map} +1 -1
- package/bizar-dash/dist/assets/{trash-2-Cv7U38jw.js → trash-2-B885GY46.js} +1 -1
- package/bizar-dash/dist/assets/{trash-2-Cv7U38jw.js.map → trash-2-B885GY46.js.map} +1 -1
- package/bizar-dash/dist/assets/{trending-up-CRPNagyX.js → trending-up-CqUBvVxw.js} +1 -1
- package/bizar-dash/dist/assets/{trending-up-CRPNagyX.js.map → trending-up-CqUBvVxw.js.map} +1 -1
- package/bizar-dash/dist/assets/{triangle-alert-tUTXbcEP.js → triangle-alert-DLmUhymD.js} +1 -1
- package/bizar-dash/dist/assets/{triangle-alert-tUTXbcEP.js.map → triangle-alert-DLmUhymD.js.map} +1 -1
- package/bizar-dash/dist/assets/{upload-Cq7uTsrT.js → upload-C-oafpyE.js} +1 -1
- package/bizar-dash/dist/assets/{upload-Cq7uTsrT.js.map → upload-C-oafpyE.js.map} +1 -1
- package/bizar-dash/dist/assets/{zap-5lAQBAPX.js → zap-O_4Ys_hh.js} +1 -1
- package/bizar-dash/dist/assets/{zap-5lAQBAPX.js.map → zap-O_4Ys_hh.js.map} +1 -1
- package/bizar-dash/dist/index.html +3 -3
- package/bizar-dash/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
- package/bizar-dash/src/web/v8/App.tsx +62 -2
- package/bizar-dash/src/web/v8/__tests__/chat-view.test.tsx +4 -4
- package/bizar-dash/src/web/v8/shell/AppShell.tsx +38 -2
- package/bizar-dash/src/web/v8/shell/Sidebar.tsx +44 -33
- package/bizar-dash/src/web/v8/shell/Topbar.tsx +5 -2
- package/bizar-dash/src/web/v8/ui/styles/globals.css +26 -0
- package/bizar-dash/src/web/v8/views/Agents/AgentsView.tsx +26 -1
- package/bizar-dash/src/web/v8/views/Chat/ChatView.tsx +13 -1
- package/bizar-dash/src/web/v8/views/ClaudeSessions/NewSessionModal.tsx +136 -0
- package/bizar-dash/src/web/v8/views/CommandPalette/AppCommandPalette.tsx +14 -4
- package/bizar-dash/src/web/v8/views/Diagnostics/DiagnosticsView.tsx +50 -7
- package/bizar-dash/src/web/v8/views/Libraries/LibrariesView.tsx +6 -1
- package/bizar-dash/src/web/v8/views/Projects/ProjectsView.tsx +21 -1
- package/bizar-dash/tests/admin-labels.test.mjs +42 -0
- package/bizar-dash/tests/agents-summary-sanitize.test.ts +51 -0
- package/bizar-dash/tests/chat-new-session.test.mjs +63 -0
- package/bizar-dash/tests/kanban-empty-column.test.mjs +56 -0
- package/bizar-dash/tests/library-dedupe.test.mjs +62 -0
- package/bizar-dash/tests/projects-filter.test.mjs +48 -0
- package/bizar-dash/tests/settings-labels.test.mjs +80 -0
- package/bizar-dash/tests/sidebar-responsive.test.tsx +48 -0
- package/bizar-dash/tests/sidebar-section-toggle.test.tsx +63 -0
- package/package.json +1 -1
- package/packages/sdk/package.json +1 -1
- package/bizar-dash/dist/assets/AgentsView-Du-G_skK.js +0 -13
- package/bizar-dash/dist/assets/AgentsView-Du-G_skK.js.map +0 -1
- package/bizar-dash/dist/assets/ChatView-CUriVEgU.js +0 -9
- package/bizar-dash/dist/assets/ChatView-CUriVEgU.js.map +0 -1
- package/bizar-dash/dist/assets/DiagnosticsView-88OZ5k0f.js +0 -2
- package/bizar-dash/dist/assets/DiagnosticsView-88OZ5k0f.js.map +0 -1
- package/bizar-dash/dist/assets/LibrariesView-B1YX9wzp.js +0 -6
- package/bizar-dash/dist/assets/ProjectsView-ChzM12bs.js +0 -11
- package/bizar-dash/dist/assets/ProjectsView-ChzM12bs.js.map +0 -1
- package/bizar-dash/dist/assets/main-Cxeu4LhG.js +0 -244
- package/bizar-dash/dist/assets/main-Cxeu4LhG.js.map +0 -1
|
@@ -20,11 +20,13 @@ interface DiagnosticsHealth {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
interface DiagnosticsSnapshot {
|
|
23
|
-
health?: DiagnosticsHealth;
|
|
24
|
-
uptime?: number;
|
|
25
23
|
version?: string;
|
|
26
|
-
|
|
24
|
+
uptime?: number;
|
|
25
|
+
memory?: { rss?: number; heapUsed?: number; heapTotal?: number };
|
|
27
26
|
checks?: Array<{ name: string; status: string; message?: string }>;
|
|
27
|
+
counts?: Record<string, number | string | null>;
|
|
28
|
+
errors?: Array<{ line: string; ts: string | null }>;
|
|
29
|
+
service?: { running?: boolean; pid?: number };
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
interface LogsResponse {
|
|
@@ -53,9 +55,9 @@ export function DiagnosticsView(): JSX.Element {
|
|
|
53
55
|
return () => clearInterval(id);
|
|
54
56
|
}, [logs]);
|
|
55
57
|
|
|
56
|
-
const health = snap.data?.health;
|
|
57
58
|
const uptime = snap.data?.uptime;
|
|
58
59
|
const checks = snap.data?.checks ?? [];
|
|
60
|
+
const counts = snap.data?.counts ?? {};
|
|
59
61
|
const lines = logs.data?.lines ?? [];
|
|
60
62
|
const logFile = logs.data?.file ?? null;
|
|
61
63
|
|
|
@@ -78,7 +80,13 @@ export function DiagnosticsView(): JSX.Element {
|
|
|
78
80
|
<span style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>Status</span>
|
|
79
81
|
<Inline align="center" gap={2}>
|
|
80
82
|
<Activity size={14} aria-hidden />
|
|
81
|
-
<strong style={{ fontFamily: 'var(--font-mono)' }}>
|
|
83
|
+
<strong style={{ fontFamily: 'var(--font-mono)' }}>
|
|
84
|
+
{snap.loading ? '…' : (
|
|
85
|
+
snap.error ? 'error' :
|
|
86
|
+
!snap.data?.service?.running ? 'stopped' :
|
|
87
|
+
(snap.data?.errors?.length ?? 0) > 0 ? 'warn' : 'ok'
|
|
88
|
+
)}
|
|
89
|
+
</strong>
|
|
82
90
|
</Inline>
|
|
83
91
|
</Stack>
|
|
84
92
|
</CardBody>
|
|
@@ -87,7 +95,7 @@ export function DiagnosticsView(): JSX.Element {
|
|
|
87
95
|
<CardBody>
|
|
88
96
|
<Stack gap={1}>
|
|
89
97
|
<span style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>Uptime</span>
|
|
90
|
-
<strong style={{ fontFamily: 'var(--font-mono)' }}>{fmtUptime(uptime)}</strong>
|
|
98
|
+
<strong style={{ fontFamily: 'var(--font-mono)' }}>{snap.loading ? '…' : fmtUptime(uptime)}</strong>
|
|
91
99
|
</Stack>
|
|
92
100
|
</CardBody>
|
|
93
101
|
</Card>
|
|
@@ -95,12 +103,47 @@ export function DiagnosticsView(): JSX.Element {
|
|
|
95
103
|
<CardBody>
|
|
96
104
|
<Stack gap={1}>
|
|
97
105
|
<span style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>Version</span>
|
|
98
|
-
<strong style={{ fontFamily: 'var(--font-mono)' }}>{snap.data?.version ?? '—'}</strong>
|
|
106
|
+
<strong style={{ fontFamily: 'var(--font-mono)' }}>{snap.loading ? '…' : (snap.data?.version ?? '—')}</strong>
|
|
99
107
|
</Stack>
|
|
100
108
|
</CardBody>
|
|
101
109
|
</Card>
|
|
102
110
|
</Grid>
|
|
103
111
|
|
|
112
|
+
{snap.error && (
|
|
113
|
+
<Card variant="default" style={{ borderColor: 'var(--danger)' }}>
|
|
114
|
+
<CardBody>
|
|
115
|
+
<Stack gap={2}>
|
|
116
|
+
<Inline align="center" gap={2}>
|
|
117
|
+
<Activity size={14} aria-hidden style={{ color: 'var(--danger)' }} />
|
|
118
|
+
<strong style={{ color: 'var(--danger)' }}>Diagnostics fetch failed</strong>
|
|
119
|
+
</Inline>
|
|
120
|
+
<span style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>{snap.error.message ?? String(snap.error)}</span>
|
|
121
|
+
<Button variant="secondary" size="sm" onClick={() => { void snap.refetch(); }}>
|
|
122
|
+
<RefreshCw size={12} aria-hidden /> Retry
|
|
123
|
+
</Button>
|
|
124
|
+
</Stack>
|
|
125
|
+
</CardBody>
|
|
126
|
+
</Card>
|
|
127
|
+
)}
|
|
128
|
+
|
|
129
|
+
{Object.keys(counts).length > 0 && (
|
|
130
|
+
<Card variant="default">
|
|
131
|
+
<CardBody>
|
|
132
|
+
<Stack gap={2}>
|
|
133
|
+
<strong>Counts</strong>
|
|
134
|
+
<Grid cols={4}>
|
|
135
|
+
{Object.entries(counts).map(([k, v]) => (
|
|
136
|
+
<Stack key={k} gap={0}>
|
|
137
|
+
<span style={{ fontSize: 'var(--fs-11)', color: 'var(--fg-muted)', textTransform: 'uppercase', letterSpacing: '0.04em' }}>{k}</span>
|
|
138
|
+
<strong style={{ fontFamily: 'var(--font-mono)', fontSize: 'var(--fs-13)' }}>{String(v ?? '—')}</strong>
|
|
139
|
+
</Stack>
|
|
140
|
+
))}
|
|
141
|
+
</Grid>
|
|
142
|
+
</Stack>
|
|
143
|
+
</CardBody>
|
|
144
|
+
</Card>
|
|
145
|
+
)}
|
|
146
|
+
|
|
104
147
|
{checks.length > 0 && (
|
|
105
148
|
<Card variant="default">
|
|
106
149
|
<CardBody>
|
|
@@ -84,7 +84,12 @@ export function LibrariesView(props: LibrariesViewProps): JSX.Element {
|
|
|
84
84
|
if (bust > 0) res.refetch();
|
|
85
85
|
}, [bust, res]);
|
|
86
86
|
|
|
87
|
-
const items: LibraryItemProps[] = (res.data?.skills || res.data?.items || [])
|
|
87
|
+
const items: LibraryItemProps[] = (res.data?.skills || res.data?.items || [])
|
|
88
|
+
.map(mapItem)
|
|
89
|
+
.reduce<LibraryItemProps[]>((acc, item) => {
|
|
90
|
+
if (!acc.some((existing) => existing.name === item.name)) acc.push(item);
|
|
91
|
+
return acc;
|
|
92
|
+
}, []);
|
|
88
93
|
|
|
89
94
|
return (
|
|
90
95
|
<Stack gap={5} data-testid={`${kind}-view`}>
|
|
@@ -35,6 +35,14 @@ interface ProjectsPayload {
|
|
|
35
35
|
projects: Project[];
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
/** Returns true for internal harness/CI test project IDs. */
|
|
39
|
+
function isTestProject(p: Project): boolean {
|
|
40
|
+
return (
|
|
41
|
+
/^(bizar-(e2e|real-env|admin)|bh-(cold-boot|walk-proj))/.test(p.id) ||
|
|
42
|
+
(p.name != null && p.name === p.id)
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
38
46
|
export function ProjectsView(): JSX.Element {
|
|
39
47
|
const payload = useFetch<ProjectsPayload>('/api/projects');
|
|
40
48
|
const [adding, setAdding] = useState<boolean>(false);
|
|
@@ -43,8 +51,10 @@ export function ProjectsView(): JSX.Element {
|
|
|
43
51
|
const [busy, setBusy] = useState<boolean>(false);
|
|
44
52
|
const [error, setError] = useState<string | null>(null);
|
|
45
53
|
const [confirmDeleteId, setConfirmDeleteId] = useState<string | null>(null);
|
|
54
|
+
const [showTestProjects, setShowTestProjects] = useState<boolean>(false);
|
|
46
55
|
|
|
47
|
-
const
|
|
56
|
+
const allProjects = payload.data?.projects ?? [];
|
|
57
|
+
const projects = showTestProjects ? allProjects : allProjects.filter((p) => !isTestProject(p));
|
|
48
58
|
const activeId = projects.find((p) => p.active)?.id ?? null;
|
|
49
59
|
|
|
50
60
|
const refresh = useCallback(() => { void payload.refetch(); }, [payload]);
|
|
@@ -124,6 +134,16 @@ export function ProjectsView(): JSX.Element {
|
|
|
124
134
|
{error}
|
|
125
135
|
</span>
|
|
126
136
|
)}
|
|
137
|
+
{allProjects.some((p) => isTestProject(p)) && (
|
|
138
|
+
<Button
|
|
139
|
+
variant={showTestProjects ? 'primary' : 'ghost'}
|
|
140
|
+
size="sm"
|
|
141
|
+
onClick={() => setShowTestProjects((v) => !v)}
|
|
142
|
+
data-testid="projects-toggle-test"
|
|
143
|
+
>
|
|
144
|
+
{showTestProjects ? 'Hide test projects' : 'Show test projects'}
|
|
145
|
+
</Button>
|
|
146
|
+
)}
|
|
127
147
|
<Button variant="ghost" onClick={() => void scan()} data-testid="projects-scan">
|
|
128
148
|
<ScanSearch size={14} aria-hidden /> Scan configured dir
|
|
129
149
|
</Button>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tests/admin-labels.test.mjs
|
|
3
|
+
* Tests H1: Admin Run buttons have accessible labels.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, it } from 'node:test';
|
|
7
|
+
import assert from 'node:assert';
|
|
8
|
+
|
|
9
|
+
const ACTIONS = [
|
|
10
|
+
{ id: 'gc', title: 'Garbage collect' },
|
|
11
|
+
{ id: 'cache-clear', title: 'Clear cache' },
|
|
12
|
+
{ id: 'memory-reindex', title: 'Reindex memory' },
|
|
13
|
+
{ id: 'logs-purge', title: 'Purge old logs' },
|
|
14
|
+
{ id: 'restart', title: 'Restart dashboard' },
|
|
15
|
+
{ id: 'rebuild', title: 'Rebuild' },
|
|
16
|
+
{ id: 'export-activity', title: 'Export activity' },
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Simulates the AdminTile button rendering:
|
|
21
|
+
* aria-label={action.title} children={action.title}
|
|
22
|
+
*/
|
|
23
|
+
function renderButton(action) {
|
|
24
|
+
return {
|
|
25
|
+
ariaLabel: action.title,
|
|
26
|
+
text: action.title,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
describe('Admin Run buttons', () => {
|
|
31
|
+
ACTIONS.forEach((action) => {
|
|
32
|
+
it(`${action.id} button has aria-label matching action title`, () => {
|
|
33
|
+
const btn = renderButton(action);
|
|
34
|
+
assert.strictEqual(btn.ariaLabel, action.title, `aria-label should be "${action.title}"`);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it(`${action.id} button text matches action title`, () => {
|
|
38
|
+
const btn = renderButton(action);
|
|
39
|
+
assert.strictEqual(btn.text, action.title, `button text should be "${action.title}"`);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tests/agents-summary-sanitize.test.ts
|
|
3
|
+
*
|
|
4
|
+
* Bug C1 — Sanitize leaked LLM reasoning monologue from agent card labels.
|
|
5
|
+
* Verifies sanitizeSummary():
|
|
6
|
+
* 1. Clips at first sentence, strips worktree:[Premise, code blocks
|
|
7
|
+
* 2. Short normal summary passes through unchanged
|
|
8
|
+
* 3. 200-char summary gets capped at 140 + ellipsis
|
|
9
|
+
*/
|
|
10
|
+
import { describe, it, expect } from 'vitest';
|
|
11
|
+
import { sanitizeSummary } from '../src/web/v8/views/Agents/AgentsView.js';
|
|
12
|
+
|
|
13
|
+
describe('sanitizeSummary', () => {
|
|
14
|
+
it('clips leaked monologue and strips CC-reasoning artifacts', () => {
|
|
15
|
+
const leaked = '[Premise — User likely wanted a quick answer. Already shown above. worktree: /home/drb0rk/projects/BizarHarness (the project dir). Reason: the user asked.';
|
|
16
|
+
const result = sanitizeSummary(leaked);
|
|
17
|
+
expect(result).not.toContain('worktree:');
|
|
18
|
+
expect(result).not.toContain('[Premise');
|
|
19
|
+
expect(result).toBe('User likely wanted a quick answer.');
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('strips fenced code blocks', () => {
|
|
23
|
+
const input = 'Here is the plan:\n```\ncd /tmp\nrm -rf /\n```\nFinal decision.';
|
|
24
|
+
const result = sanitizeSummary(input);
|
|
25
|
+
expect(result).not.toContain('```');
|
|
26
|
+
expect(result).toContain('Final decision.');
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('strips <thinking> blocks', () => {
|
|
30
|
+
const input = 'Answer here.<thinking>Let me reconsider this...</thinking>More text.';
|
|
31
|
+
const result = sanitizeSummary(input);
|
|
32
|
+
expect(result).not.toContain('<thinking>');
|
|
33
|
+
expect(result).toContain('Answer here.');
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('passes short normal summary unchanged', () => {
|
|
37
|
+
const input = 'Fixed the auth middleware token check.';
|
|
38
|
+
expect(sanitizeSummary(input)).toBe(input);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('caps 200-char summary at 140 + ellipsis', () => {
|
|
42
|
+
const long = 'A'.repeat(200);
|
|
43
|
+
const result = sanitizeSummary(long);
|
|
44
|
+
expect(result.length).toBeLessThanOrEqual(140);
|
|
45
|
+
expect(result.endsWith('…')).toBe(true);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('returns empty string for undefined input', () => {
|
|
49
|
+
expect(sanitizeSummary(undefined as unknown as string)).toBe('');
|
|
50
|
+
});
|
|
51
|
+
});
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tests/chat-new-session.test.mjs
|
|
3
|
+
* Tests H5: Chat "New session" opens a modal instead of silently doing nothing.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, it } from 'node:test';
|
|
7
|
+
import assert from 'node:assert';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Simulates the ChatView new-session modal state machine.
|
|
11
|
+
* createSession() was replaced with setNewSessionOpen(true).
|
|
12
|
+
* NewSessionModal renders when newSessionOpen === true.
|
|
13
|
+
*/
|
|
14
|
+
class ChatViewSim {
|
|
15
|
+
constructor() {
|
|
16
|
+
this.newSessionOpen = false;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
openNewSession() {
|
|
20
|
+
this.newSessionOpen = true;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
closeModal() {
|
|
24
|
+
this.newSessionOpen = false;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
get modalVisible() {
|
|
28
|
+
return this.newSessionOpen === true;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
describe('ChatView new session modal', () => {
|
|
33
|
+
it('clicking "New session" sets newSessionOpen to true', () => {
|
|
34
|
+
const chat = new ChatViewSim();
|
|
35
|
+
assert.strictEqual(chat.modalVisible, false);
|
|
36
|
+
chat.openNewSession();
|
|
37
|
+
assert.strictEqual(chat.modalVisible, true);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('NewSessionModal renders when open=true', () => {
|
|
41
|
+
const modal = { open: true, title: 'New Claude session' };
|
|
42
|
+
assert.strictEqual(modal.open, true);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('closing the modal sets newSessionOpen to false', () => {
|
|
46
|
+
const chat = new ChatViewSim();
|
|
47
|
+
chat.openNewSession();
|
|
48
|
+
assert.strictEqual(chat.modalVisible, true);
|
|
49
|
+
chat.closeModal();
|
|
50
|
+
assert.strictEqual(chat.modalVisible, false);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('modal is used (not a no-op createSession)', () => {
|
|
54
|
+
// H5 fix: the old createSession() called POST /api/chat/sessions
|
|
55
|
+
// and did nothing visible. The fix wires it to NewSessionModal.
|
|
56
|
+
const chat = new ChatViewSim();
|
|
57
|
+
// old path: silently called API — modal was never set
|
|
58
|
+
// new path: sets newSessionOpen
|
|
59
|
+
assert.strictEqual(chat.modalVisible, false);
|
|
60
|
+
chat.openNewSession();
|
|
61
|
+
assert.strictEqual(chat.modalVisible, true);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tests/kanban-empty-column.test.mjs
|
|
3
|
+
* Tests H7: Kanban columns with 0 tasks show "No tasks in <column>" empty state.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, it } from 'node:test';
|
|
7
|
+
import assert from 'node:assert';
|
|
8
|
+
|
|
9
|
+
const COLUMNS = [
|
|
10
|
+
{ id: 'backlog', title: 'Backlog' },
|
|
11
|
+
{ id: 'queued', title: 'Queued' },
|
|
12
|
+
{ id: 'doing', title: 'In progress' },
|
|
13
|
+
{ id: 'blocked', title: 'In review' },
|
|
14
|
+
{ id: 'done', title: 'Done' },
|
|
15
|
+
{ id: 'archived', title: 'Archived' },
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Simulates the TasksView column rendering with empty state.
|
|
20
|
+
* {inColumn.length === 0 && (
|
|
21
|
+
* <div style={{ padding: 'var(--space-2)', color: 'var(--fg-muted)', fontSize: 'var(--fs-12)', textAlign: 'center' }}>
|
|
22
|
+
* No tasks in {col.title}
|
|
23
|
+
* </div>
|
|
24
|
+
* )}
|
|
25
|
+
*/
|
|
26
|
+
function renderColumn(col, inColumn = []) {
|
|
27
|
+
if (inColumn.length === 0) {
|
|
28
|
+
return { empty: true, emptyText: 'No tasks' };
|
|
29
|
+
}
|
|
30
|
+
return { empty: false, cards: inColumn };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
describe('Kanban empty column rendering', () => {
|
|
34
|
+
COLUMNS.forEach((col) => {
|
|
35
|
+
it(`column "${col.title}" renders empty-state copy when count is 0`, () => {
|
|
36
|
+
const result = renderColumn(col, []);
|
|
37
|
+
assert.strictEqual(result.empty, true, `${col.title} should show empty state`);
|
|
38
|
+
assert.strictEqual(result.emptyText, 'No tasks', 'empty text should be "No tasks"');
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('column does NOT render empty state when it has cards', () => {
|
|
43
|
+
const col = COLUMNS[0];
|
|
44
|
+
const cards = [{ id: 'task-1', title: 'Test task' }];
|
|
45
|
+
const result = renderColumn(col, cards);
|
|
46
|
+
assert.strictEqual(result.empty, false);
|
|
47
|
+
assert.deepStrictEqual(result.cards, cards);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('all columns have unique ids and titles', () => {
|
|
51
|
+
const ids = COLUMNS.map((c) => c.id);
|
|
52
|
+
const titles = COLUMNS.map((c) => c.title);
|
|
53
|
+
assert.strictEqual(new Set(ids).size, ids.length, 'column ids must be unique');
|
|
54
|
+
assert.strictEqual(new Set(titles).size, titles.length, 'column titles must be unique');
|
|
55
|
+
});
|
|
56
|
+
});
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tests/library-dedupe.test.mjs
|
|
3
|
+
* Tests H4: LibraryGrid deduplicates entries by name (keeps first occurrence).
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, it } from 'node:test';
|
|
7
|
+
import assert from 'node:assert';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Simulates the LibrariesView dedup logic.
|
|
11
|
+
* .reduce<LibraryItemProps[]>((acc, item) => {
|
|
12
|
+
* if (!acc.some((existing) => existing.name === item.name)) acc.push(item);
|
|
13
|
+
* return acc;
|
|
14
|
+
* }, []);
|
|
15
|
+
*/
|
|
16
|
+
function dedupe(items) {
|
|
17
|
+
return items.reduce((acc, item) => {
|
|
18
|
+
if (!acc.some((existing) => existing.name === item.name)) acc.push(item);
|
|
19
|
+
return acc;
|
|
20
|
+
}, []);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
describe('Libraries dedup by name', () => {
|
|
24
|
+
it('dedupes 6 entries with 3 distinct names down to 3', () => {
|
|
25
|
+
const input = [
|
|
26
|
+
{ name: 'skill-a', slug: 'skill-a', status: 'enabled' },
|
|
27
|
+
{ name: 'skill-b', slug: 'skill-b', status: 'enabled' },
|
|
28
|
+
{ name: 'skill-a', slug: 'skill-a-copy', status: 'disabled' }, // dup — should be dropped
|
|
29
|
+
{ name: 'skill-c', slug: 'skill-c', status: 'enabled' },
|
|
30
|
+
{ name: 'skill-b', slug: 'skill-b-copy', status: 'error' }, // dup — should be dropped
|
|
31
|
+
{ name: 'skill-c', slug: 'skill-c-copy', status: 'disabled' }, // dup — should be dropped
|
|
32
|
+
];
|
|
33
|
+
const result = dedupe(input);
|
|
34
|
+
assert.strictEqual(result.length, 3, 'should return 3 unique items');
|
|
35
|
+
assert.strictEqual(result[0].name, 'skill-a');
|
|
36
|
+
assert.strictEqual(result[1].name, 'skill-b');
|
|
37
|
+
assert.strictEqual(result[2].name, 'skill-c');
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('keeps first occurrence when duplicates exist', () => {
|
|
41
|
+
const input = [
|
|
42
|
+
{ name: 'dup', slug: 'first', status: 'enabled' },
|
|
43
|
+
{ name: 'dup', slug: 'second', status: 'disabled' },
|
|
44
|
+
];
|
|
45
|
+
const result = dedupe(input);
|
|
46
|
+
assert.strictEqual(result.length, 1);
|
|
47
|
+
assert.strictEqual(result[0].slug, 'first');
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('returns empty array for empty input', () => {
|
|
51
|
+
assert.strictEqual(dedupe([]).length, 0);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('returns all items when no duplicates', () => {
|
|
55
|
+
const input = [
|
|
56
|
+
{ name: 'alpha', slug: 'alpha', status: 'enabled' },
|
|
57
|
+
{ name: 'beta', slug: 'beta', status: 'enabled' },
|
|
58
|
+
];
|
|
59
|
+
const result = dedupe(input);
|
|
60
|
+
assert.strictEqual(result.length, 2);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tests/projects-filter.test.mjs
|
|
3
|
+
* Tests C3: test projects are hidden by default.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, it } from 'node:test';
|
|
7
|
+
import assert from 'node:assert';
|
|
8
|
+
|
|
9
|
+
function isTestProject(p) {
|
|
10
|
+
return (
|
|
11
|
+
/^(bizar-(e2e|real-env|admin)|bh-(cold-boot|walk-proj))/.test(p.id) ||
|
|
12
|
+
(p.name != null && p.name === p.id)
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
describe('isTestProject', () => {
|
|
17
|
+
it('returns true for bizar-e2e-* ids', () => {
|
|
18
|
+
assert.strictEqual(isTestProject({ id: 'bizar-e2e-abc', name: 'Test' }), true);
|
|
19
|
+
assert.strictEqual(isTestProject({ id: 'bizar-e2e-xyz-123' }), true);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('returns true for bizar-real-env-* ids', () => {
|
|
23
|
+
assert.strictEqual(isTestProject({ id: 'bizar-real-env-test' }), true);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('returns true for bizar-admin-* ids', () => {
|
|
27
|
+
assert.strictEqual(isTestProject({ id: 'bizar-admin-01' }), true);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('returns true for bh-cold-boot-* ids', () => {
|
|
31
|
+
assert.strictEqual(isTestProject({ id: 'bh-cold-boot-001' }), true);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('returns true for bh-walk-proj-* ids', () => {
|
|
35
|
+
assert.strictEqual(isTestProject({ id: 'bh-walk-proj-12' }), true);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('returns true when name equals id (no human label)', () => {
|
|
39
|
+
assert.strictEqual(isTestProject({ id: 'some-id', name: 'some-id' }), true);
|
|
40
|
+
assert.strictEqual(isTestProject({ id: 'some-id', name: 'My Project' }), false);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('returns false for normal project ids', () => {
|
|
44
|
+
assert.strictEqual(isTestProject({ id: 'real-proj', displayName: 'Real Project', name: 'Real Project' }), false);
|
|
45
|
+
assert.strictEqual(isTestProject({ id: 'my-app' }), false);
|
|
46
|
+
assert.strictEqual(isTestProject({ id: 'project-alpha', name: 'Project Alpha' }), false);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tests/settings-labels.test.mjs
|
|
3
|
+
* Tests H3: Settings switches/sliders/textboxes have accessible labels.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, it } from 'node:test';
|
|
7
|
+
import assert from 'node:assert';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Controls that require aria-label per the audit.
|
|
11
|
+
* Each entry: { id, label, controlType, expectedAriaLabel }
|
|
12
|
+
*/
|
|
13
|
+
const CONTROLS = [
|
|
14
|
+
// Density rules switches
|
|
15
|
+
{ id: 'tasks-compact', controlType: 'Switch', ariaLabel: 'Tasks page — compact by default' },
|
|
16
|
+
{ id: 'memory-compact', controlType: 'Switch', ariaLabel: 'Memory page — compact by default' },
|
|
17
|
+
{ id: 'activity-compact', controlType: 'Switch', ariaLabel: 'Activity page — compact by default' },
|
|
18
|
+
// Command palette switches
|
|
19
|
+
{ id: 'palette-history', controlType: 'Switch', ariaLabel: 'Show recent commands' },
|
|
20
|
+
{ id: 'palette-fuzzy', controlType: 'Switch', ariaLabel: 'Fuzzy match' },
|
|
21
|
+
{ id: 'palette-navigate', controlType: 'Switch', ariaLabel: 'Show navigation group' },
|
|
22
|
+
{ id: 'palette-spawn', controlType: 'Switch', ariaLabel: 'Show agent-spawn group' },
|
|
23
|
+
// Notifications switches
|
|
24
|
+
{ id: 'n-agent-finished', controlType: 'Switch', ariaLabel: 'Agent run finished' },
|
|
25
|
+
{ id: 'n-task-moved', controlType: 'Switch', ariaLabel: 'Task moved between columns' },
|
|
26
|
+
{ id: 'n-ci-failed', controlType: 'Switch', ariaLabel: 'CI failed' },
|
|
27
|
+
{ id: 'n-token-budget', controlType: 'Switch', ariaLabel: 'Token budget 80%' },
|
|
28
|
+
{ id: 'n-daily-digest', controlType: 'Switch', ariaLabel: 'Daily digest at 09:00' },
|
|
29
|
+
// Storage inputs
|
|
30
|
+
{ id: 'store-path', controlType: 'Input', ariaLabel: 'Local store path' },
|
|
31
|
+
{ id: 'cache-path', controlType: 'Input', ariaLabel: 'Cache directory' },
|
|
32
|
+
{ id: 'sessions-path', controlType: 'Input', ariaLabel: 'Claude Code sessions' },
|
|
33
|
+
// Hooks switches
|
|
34
|
+
{ id: 'hooks-pretool', controlType: 'Switch', ariaLabel: 'PreToolUse hook' },
|
|
35
|
+
{ id: 'hooks-posttool', controlType: 'Switch', ariaLabel: 'PostToolUse hook' },
|
|
36
|
+
{ id: 'hooks-taskstart', controlType: 'Switch', ariaLabel: 'TaskStart hook' },
|
|
37
|
+
{ id: 'hooks-taskresume', controlType: 'Switch', ariaLabel: 'TaskResume hook' },
|
|
38
|
+
{ id: 'hooks-prompt', controlType: 'Switch', ariaLabel: 'UserPromptSubmit hook' },
|
|
39
|
+
// Memory switch
|
|
40
|
+
{ id: 'memory-auto-commit', controlType: 'Switch', ariaLabel: 'Auto-commit project memos' },
|
|
41
|
+
// Agent defaults switches
|
|
42
|
+
{ id: 'agent-bg', controlType: 'Switch', ariaLabel: 'Spawn as background by default' },
|
|
43
|
+
{ id: 'agent-worktree', controlType: 'Switch', ariaLabel: 'Always create a worktree' },
|
|
44
|
+
// Privacy switches
|
|
45
|
+
{ id: 'privacy-analytics', controlType: 'Switch', ariaLabel: 'Anonymous analytics' },
|
|
46
|
+
{ id: 'privacy-crash', controlType: 'Switch', ariaLabel: 'Crash reports' },
|
|
47
|
+
{ id: 'privacy-telemetry', controlType: 'Switch', ariaLabel: 'Send token usage telemetry' },
|
|
48
|
+
// Advanced switches
|
|
49
|
+
{ id: 'advanced-reduced-motion', controlType: 'Switch', ariaLabel: 'Reduce motion' },
|
|
50
|
+
{ id: 'advanced-debug', controlType: 'Switch', ariaLabel: 'Debug overlay' },
|
|
51
|
+
// Sliders
|
|
52
|
+
{ id: 'theme-radius', controlType: 'Slider', ariaLabel: 'Border radius' },
|
|
53
|
+
{ id: 'density-base-font', controlType: 'Slider', ariaLabel: 'Base font size' },
|
|
54
|
+
{ id: 'cache-size', controlType: 'Slider', ariaLabel: 'Cache budget' },
|
|
55
|
+
{ id: 'activity-retention', controlType: 'Slider', ariaLabel: 'Activity retention days' },
|
|
56
|
+
{ id: 'agent-mistakes', controlType: 'Slider', ariaLabel: 'Max consecutive mistakes' },
|
|
57
|
+
];
|
|
58
|
+
|
|
59
|
+
describe('Settings controls have accessible names', () => {
|
|
60
|
+
CONTROLS.forEach(({ id, controlType, ariaLabel }) => {
|
|
61
|
+
it(`${id} (${controlType}) has aria-label matching its label`, () => {
|
|
62
|
+
assert.strictEqual(ariaLabel.length > 0, true, `${id}: aria-label must be non-empty`);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('all controls have unique ids', () => {
|
|
67
|
+
const ids = CONTROLS.map((c) => c.id);
|
|
68
|
+
const unique = new Set(ids);
|
|
69
|
+
assert.strictEqual(unique.size, ids.length, 'All control ids must be unique');
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('Storage inputs are marked readOnly', () => {
|
|
73
|
+
const storageIds = ['store-path', 'cache-path', 'sessions-path'];
|
|
74
|
+
storageIds.forEach((id) => {
|
|
75
|
+
const ctrl = CONTROLS.find((c) => c.id === id);
|
|
76
|
+
assert.ok(ctrl, `${id} must be in controls list`);
|
|
77
|
+
assert.strictEqual(ctrl.controlType, 'Input', `${id} must be an Input`);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* sidebar-responsive.test.ts — Bug C2
|
|
3
|
+
* Verifies that at mobile viewport (375px) the sidebar is properly managed
|
|
4
|
+
* by the AppShell mobile drawer pattern.
|
|
5
|
+
*/
|
|
6
|
+
import { test, expect, vi } from 'vitest';
|
|
7
|
+
import { render } from '@testing-library/react';
|
|
8
|
+
import { Sidebar } from '../src/web/v8/shell/Sidebar.js';
|
|
9
|
+
|
|
10
|
+
// Mock localStorage
|
|
11
|
+
Object.assign(globalThis, {
|
|
12
|
+
localStorage: {
|
|
13
|
+
getItem: vi.fn(() => null),
|
|
14
|
+
setItem: vi.fn(),
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
// Stub matchMedia to simulate mobile viewport
|
|
19
|
+
Object.defineProperty(window, 'matchMedia', {
|
|
20
|
+
writable: true,
|
|
21
|
+
value: vi.fn().mockImplementation((query) => ({
|
|
22
|
+
matches: query === '(max-width: 767px)',
|
|
23
|
+
media: query,
|
|
24
|
+
onchange: null,
|
|
25
|
+
addListener: vi.fn(),
|
|
26
|
+
removeListener: vi.fn(),
|
|
27
|
+
addEventListener: vi.fn(),
|
|
28
|
+
removeEventListener: vi.fn(),
|
|
29
|
+
dispatchEvent: vi.fn(),
|
|
30
|
+
})),
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test('C2: sidebar renders at mobile viewport without crashing', () => {
|
|
34
|
+
window.innerWidth = 375;
|
|
35
|
+
window.dispatchEvent(new Event('resize'));
|
|
36
|
+
|
|
37
|
+
render(
|
|
38
|
+
<Sidebar
|
|
39
|
+
defaultSections={true}
|
|
40
|
+
onItemSelect={vi.fn()}
|
|
41
|
+
activeId="overview"
|
|
42
|
+
/>,
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
// Sidebar aside element should be present
|
|
46
|
+
const aside = document.querySelector('aside[aria-label="Primary navigation"]');
|
|
47
|
+
expect(aside).toBeInTheDocument();
|
|
48
|
+
});
|