@polderlabs/bizar 10.2.0 → 10.4.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/README.md +31 -8
- package/bizar-dash/CONTROL_SURFACES.md +0 -1
- package/bizar-dash/dist/assets/{ActivityFeed-JjmOY2AQ.js → ActivityFeed-DtRtg-JN.js} +1 -1
- package/bizar-dash/dist/assets/{ActivityFeed-JjmOY2AQ.js.map → ActivityFeed-DtRtg-JN.js.map} +1 -1
- package/bizar-dash/dist/assets/{ActivityView-BIIMvGWo.js → ActivityView-CoTXDyU_.js} +1 -1
- package/bizar-dash/dist/assets/{ActivityView-BIIMvGWo.js.map → ActivityView-CoTXDyU_.js.map} +1 -1
- package/bizar-dash/dist/assets/{AdminView-DRidJtkq.js → AdminView-DNc5Ll7L.js} +1 -1
- package/bizar-dash/dist/assets/{AdminView-DRidJtkq.js.map → AdminView-DNc5Ll7L.js.map} +1 -1
- package/bizar-dash/dist/assets/{AgentActivity-79l4SBMC.js → AgentActivity-CrX7LmQ6.js} +1 -1
- package/bizar-dash/dist/assets/{AgentActivity-79l4SBMC.js.map → AgentActivity-CrX7LmQ6.js.map} +1 -1
- package/bizar-dash/dist/assets/{AgentsView-0vT4uPSc.js → AgentsView-Du-G_skK.js} +3 -3
- package/bizar-dash/dist/assets/{AgentsView-0vT4uPSc.js.map → AgentsView-Du-G_skK.js.map} +1 -1
- package/bizar-dash/dist/assets/{Alert-CG5q_s75.js → Alert-B6DjfRFI.js} +1 -1
- package/bizar-dash/dist/assets/{Alert-CG5q_s75.js.map → Alert-B6DjfRFI.js.map} +1 -1
- package/bizar-dash/dist/assets/{ArtifactsView-DM8ZmpR9.js → ArtifactsView-znhN8GTR.js} +1 -1
- package/bizar-dash/dist/assets/{ArtifactsView-DM8ZmpR9.js.map → ArtifactsView-znhN8GTR.js.map} +1 -1
- package/bizar-dash/dist/assets/{AuthView-BveN94MC.js → AuthView-Rk8eKUPr.js} +1 -1
- package/bizar-dash/dist/assets/{AuthView-BveN94MC.js.map → AuthView-Rk8eKUPr.js.map} +1 -1
- package/bizar-dash/dist/assets/{Avatar-ulUPIYTd.js → Avatar-B41upSD1.js} +1 -1
- package/bizar-dash/dist/assets/{Avatar-ulUPIYTd.js.map → Avatar-B41upSD1.js.map} +1 -1
- package/bizar-dash/dist/assets/{BackgroundJobsView-BWErhqFo.js → BackgroundJobsView-BLWuN9qz.js} +1 -1
- package/bizar-dash/dist/assets/{BackgroundJobsView-BWErhqFo.js.map → BackgroundJobsView-BLWuN9qz.js.map} +1 -1
- package/bizar-dash/dist/assets/{BackupView-CnBjzG9N.js → BackupView-CqbtcnuQ.js} +1 -1
- package/bizar-dash/dist/assets/{BackupView-CnBjzG9N.js.map → BackupView-CqbtcnuQ.js.map} +1 -1
- package/bizar-dash/dist/assets/{Card-B0imhxMk.js → Card-rF59wHiO.js} +1 -1
- package/bizar-dash/dist/assets/{Card-B0imhxMk.js.map → Card-rF59wHiO.js.map} +1 -1
- package/bizar-dash/dist/assets/{ChatView-D6zGytzx.js → ChatView-CUriVEgU.js} +1 -1
- package/bizar-dash/dist/assets/{ChatView-D6zGytzx.js.map → ChatView-CUriVEgU.js.map} +1 -1
- package/bizar-dash/dist/assets/{Chip-wwZSGwLE.js → Chip-Dc2KmeWl.js} +1 -1
- package/bizar-dash/dist/assets/{Chip-wwZSGwLE.js.map → Chip-Dc2KmeWl.js.map} +1 -1
- package/bizar-dash/dist/assets/{ClaudeSessionsView-DK1sOLhi.js → ClaudeSessionsView-CiaHQdDZ.js} +1 -1
- package/bizar-dash/dist/assets/{ClaudeSessionsView-DK1sOLhi.js.map → ClaudeSessionsView-CiaHQdDZ.js.map} +1 -1
- package/bizar-dash/dist/assets/{ClipboardView-CZ2lYPr0.js → ClipboardView-DdP6aVso.js} +1 -1
- package/bizar-dash/dist/assets/{ClipboardView-CZ2lYPr0.js.map → ClipboardView-DdP6aVso.js.map} +1 -1
- package/bizar-dash/dist/assets/{ConfigView-D-zT9eNA.js → ConfigView-B2ysnTZU.js} +1 -1
- package/bizar-dash/dist/assets/{ConfigView-D-zT9eNA.js.map → ConfigView-B2ysnTZU.js.map} +1 -1
- package/bizar-dash/dist/assets/{DiagnosticsView-BocV68Lb.js → DiagnosticsView-88OZ5k0f.js} +1 -1
- package/bizar-dash/dist/assets/{DiagnosticsView-BocV68Lb.js.map → DiagnosticsView-88OZ5k0f.js.map} +1 -1
- package/bizar-dash/dist/assets/{DialogsView-BVjPI5x7.js → DialogsView-BcqDDCZQ.js} +1 -1
- package/bizar-dash/dist/assets/{DialogsView-BVjPI5x7.js.map → DialogsView-BcqDDCZQ.js.map} +1 -1
- package/bizar-dash/dist/assets/{DoctorView-84gJcZwM.js → DoctorView-BQwqvMAh.js} +1 -1
- package/bizar-dash/dist/assets/{DoctorView-84gJcZwM.js.map → DoctorView-BQwqvMAh.js.map} +1 -1
- package/bizar-dash/dist/assets/{EmptyState-BjgVOrcO.js → EmptyState-D65J5FQN.js} +1 -1
- package/bizar-dash/dist/assets/{EmptyState-BjgVOrcO.js.map → EmptyState-D65J5FQN.js.map} +1 -1
- package/bizar-dash/dist/assets/{EnvVarsView-BJ2TEzF7.js → EnvVarsView-DX-3oGH-.js} +2 -2
- package/bizar-dash/dist/assets/{EnvVarsView-BJ2TEzF7.js.map → EnvVarsView-DX-3oGH-.js.map} +1 -1
- package/bizar-dash/dist/assets/{ErrorState-BE3WBFqF.js → ErrorState-DULZnttJ.js} +1 -1
- package/bizar-dash/dist/assets/{ErrorState-BE3WBFqF.js.map → ErrorState-DULZnttJ.js.map} +1 -1
- package/bizar-dash/dist/assets/{EvalView-BJJ2P-kK.js → EvalView-CpdFu_ID.js} +1 -1
- package/bizar-dash/dist/assets/{EvalView-BJJ2P-kK.js.map → EvalView-CpdFu_ID.js.map} +1 -1
- package/bizar-dash/dist/assets/{GoalsView-pwROHApi.js → GoalsView-Br8oPPfb.js} +1 -1
- package/bizar-dash/dist/assets/{GoalsView-pwROHApi.js.map → GoalsView-Br8oPPfb.js.map} +1 -1
- package/bizar-dash/dist/assets/{Grid-qcvbhx6e.js → Grid-BSXhsCPC.js} +1 -1
- package/bizar-dash/dist/assets/{Grid-qcvbhx6e.js.map → Grid-BSXhsCPC.js.map} +1 -1
- package/bizar-dash/dist/assets/{HistoryView-C7SSOLJA.js → HistoryView-D0J3aoZF.js} +1 -1
- package/bizar-dash/dist/assets/{HistoryView-C7SSOLJA.js.map → HistoryView-D0J3aoZF.js.map} +1 -1
- package/bizar-dash/dist/assets/{Input-Bgzxf_Hu.js → Input-CZmRw5QX.js} +1 -1
- package/bizar-dash/dist/assets/{Input-Bgzxf_Hu.js.map → Input-CZmRw5QX.js.map} +1 -1
- package/bizar-dash/dist/assets/{LibrariesView-CbFFksox.js → LibrariesView-B1YX9wzp.js} +1 -1
- package/bizar-dash/dist/assets/{LibrariesView-CbFFksox.js.map → LibrariesView-B1YX9wzp.js.map} +1 -1
- package/bizar-dash/dist/assets/{LightRAGView-BqDrJbRq.js → LightRAGView-CykR0t9y.js} +1 -1
- package/bizar-dash/dist/assets/{LightRAGView-BqDrJbRq.js.map → LightRAGView-CykR0t9y.js.map} +1 -1
- package/bizar-dash/dist/assets/{ListHeader-TjPJrUfY.js → ListHeader-Dpun-r36.js} +1 -1
- package/bizar-dash/dist/assets/{ListHeader-TjPJrUfY.js.map → ListHeader-Dpun-r36.js.map} +1 -1
- package/bizar-dash/dist/assets/{MemoryView-BlTeHLhX.js → MemoryView-BbER5ZKt.js} +1 -1
- package/bizar-dash/dist/assets/{MemoryView-BlTeHLhX.js.map → MemoryView-BbER5ZKt.js.map} +1 -1
- package/bizar-dash/dist/assets/MiscView-DLNEGdML.js +1 -0
- package/bizar-dash/dist/assets/{MiscView-B8QY82Pm.js.map → MiscView-DLNEGdML.js.map} +1 -1
- package/bizar-dash/dist/assets/{ModsView-CvW1OWts.js → ModsView-P7gDeNHM.js} +2 -2
- package/bizar-dash/dist/assets/{ModsView-CvW1OWts.js.map → ModsView-P7gDeNHM.js.map} +1 -1
- package/bizar-dash/dist/assets/{NotificationsView-CsBt5U7x.js → NotificationsView-DAm2O0yf.js} +1 -1
- package/bizar-dash/dist/assets/{NotificationsView-CsBt5U7x.js.map → NotificationsView-DAm2O0yf.js.map} +1 -1
- package/bizar-dash/dist/assets/ObsidianView-Ci80gnwS.js +1 -0
- package/bizar-dash/dist/assets/{ObsidianView-BCTejEj2.js.map → ObsidianView-Ci80gnwS.js.map} +1 -1
- package/bizar-dash/dist/assets/{OverviewView-BsuPxwnB.js → OverviewView-rriw1GjA.js} +1 -1
- package/bizar-dash/dist/assets/{OverviewView-BsuPxwnB.js.map → OverviewView-rriw1GjA.js.map} +1 -1
- package/bizar-dash/dist/assets/{ProgressBar-DlZTETEn.js → ProgressBar-BahmeJhP.js} +1 -1
- package/bizar-dash/dist/assets/{ProgressBar-DlZTETEn.js.map → ProgressBar-BahmeJhP.js.map} +1 -1
- package/bizar-dash/dist/assets/{ProjectsView-Soxtmpet.js → ProjectsView-ChzM12bs.js} +1 -1
- package/bizar-dash/dist/assets/{ProjectsView-Soxtmpet.js.map → ProjectsView-ChzM12bs.js.map} +1 -1
- package/bizar-dash/dist/assets/{ProvidersView-DaCEV9pM.js → ProvidersView-BftGn8Cr.js} +1 -1
- package/bizar-dash/dist/assets/{ProvidersView-DaCEV9pM.js.map → ProvidersView-BftGn8Cr.js.map} +1 -1
- package/bizar-dash/dist/assets/{SchedulesView-DY2ByBj_.js → SchedulesView-CtNxtzN6.js} +1 -1
- package/bizar-dash/dist/assets/{SchedulesView-DY2ByBj_.js.map → SchedulesView-CtNxtzN6.js.map} +1 -1
- package/bizar-dash/dist/assets/{Select-Dbd88_n8.js → Select-0VcfTDeL.js} +1 -1
- package/bizar-dash/dist/assets/{Select-Dbd88_n8.js.map → Select-0VcfTDeL.js.map} +1 -1
- package/bizar-dash/dist/assets/{SettingsRow-CLMNd434.js → SettingsRow-BLic3DQl.js} +1 -1
- package/bizar-dash/dist/assets/{SettingsRow-CLMNd434.js.map → SettingsRow-BLic3DQl.js.map} +1 -1
- package/bizar-dash/dist/assets/{SettingsView-b24oFq9x.js → SettingsView-BjS3i4nr.js} +1 -1
- package/bizar-dash/dist/assets/{SettingsView-b24oFq9x.js.map → SettingsView-BjS3i4nr.js.map} +1 -1
- package/bizar-dash/dist/assets/{Sheet-DnDid58j.js → Sheet-BOProMs2.js} +1 -1
- package/bizar-dash/dist/assets/{Sheet-DnDid58j.js.map → Sheet-BOProMs2.js.map} +1 -1
- package/bizar-dash/dist/assets/{Slider-BJCvKI1I.js → Slider-B0eLEEUt.js} +1 -1
- package/bizar-dash/dist/assets/{Slider-BJCvKI1I.js.map → Slider-B0eLEEUt.js.map} +1 -1
- package/bizar-dash/dist/assets/{Sparkline-ktqQLdyb.js → Sparkline-SSrdgyW0.js} +1 -1
- package/bizar-dash/dist/assets/{Sparkline-ktqQLdyb.js.map → Sparkline-SSrdgyW0.js.map} +1 -1
- package/bizar-dash/dist/assets/{Switch-CwXfsDii.js → Switch-B3EQzb_q.js} +1 -1
- package/bizar-dash/dist/assets/{Switch-CwXfsDii.js.map → Switch-B3EQzb_q.js.map} +1 -1
- package/bizar-dash/dist/assets/{TasksView-BHmpzFCf.js → TasksView-SWjF_ZUQ.js} +1 -1
- package/bizar-dash/dist/assets/{TasksView-BHmpzFCf.js.map → TasksView-SWjF_ZUQ.js.map} +1 -1
- package/bizar-dash/dist/assets/{Textarea-BzIAwSlp.js → Textarea-QuofpMlq.js} +1 -1
- package/bizar-dash/dist/assets/{Textarea-BzIAwSlp.js.map → Textarea-QuofpMlq.js.map} +1 -1
- package/bizar-dash/dist/assets/{UpdateView-CSmX9NN0.js → UpdateView-CEHW2nd6.js} +1 -1
- package/bizar-dash/dist/assets/{UpdateView-CSmX9NN0.js.map → UpdateView-CEHW2nd6.js.map} +1 -1
- package/bizar-dash/dist/assets/{UsageView-COyr_Gfi.js → UsageView-BqOw6FBg.js} +1 -1
- package/bizar-dash/dist/assets/{UsageView-COyr_Gfi.js.map → UsageView-BqOw6FBg.js.map} +1 -1
- package/bizar-dash/dist/assets/{ViewHeader-BzYZ3m-e.js → ViewHeader-B6P-C4GD.js} +1 -1
- package/bizar-dash/dist/assets/{ViewHeader-BzYZ3m-e.js.map → ViewHeader-B6P-C4GD.js.map} +1 -1
- package/bizar-dash/dist/assets/{VoiceView-D33_xG5t.js → VoiceView-CwrPwWgi.js} +1 -1
- package/bizar-dash/dist/assets/{VoiceView-D33_xG5t.js.map → VoiceView-CwrPwWgi.js.map} +1 -1
- package/bizar-dash/dist/assets/{brain-CM-Vls8r.js → brain-CwZt9Kta.js} +1 -1
- package/bizar-dash/dist/assets/{brain-CM-Vls8r.js.map → brain-CwZt9Kta.js.map} +1 -1
- package/bizar-dash/dist/assets/{calendar-C0lgZk69.js → calendar-C5oK0_nM.js} +1 -1
- package/bizar-dash/dist/assets/{calendar-C0lgZk69.js.map → calendar-C5oK0_nM.js.map} +1 -1
- package/bizar-dash/dist/assets/{circle-Bx_hQEBC.js → circle-D1Lc_P2a.js} +1 -1
- package/bizar-dash/dist/assets/{circle-Bx_hQEBC.js.map → circle-D1Lc_P2a.js.map} +1 -1
- package/bizar-dash/dist/assets/{circle-alert-DHvsqpw5.js → circle-alert-HdHe7m8K.js} +1 -1
- package/bizar-dash/dist/assets/{circle-alert-DHvsqpw5.js.map → circle-alert-HdHe7m8K.js.map} +1 -1
- package/bizar-dash/dist/assets/{circle-check-Bx8wmXR9.js → circle-check-Cs-xoV7R.js} +1 -1
- package/bizar-dash/dist/assets/{circle-check-Bx8wmXR9.js.map → circle-check-Cs-xoV7R.js.map} +1 -1
- package/bizar-dash/dist/assets/{clock-CejGoecX.js → clock-DEIuPV60.js} +1 -1
- package/bizar-dash/dist/assets/{clock-CejGoecX.js.map → clock-DEIuPV60.js.map} +1 -1
- package/bizar-dash/dist/assets/{download-4cEUWue1.js → download-Clkq90Ct.js} +1 -1
- package/bizar-dash/dist/assets/{download-4cEUWue1.js.map → download-Clkq90Ct.js.map} +1 -1
- package/bizar-dash/dist/assets/{external-link-0NqUhI4i.js → external-link-D5tq2o_I.js} +1 -1
- package/bizar-dash/dist/assets/{external-link-0NqUhI4i.js.map → external-link-D5tq2o_I.js.map} +1 -1
- package/bizar-dash/dist/assets/{file-text-yEMkrSoZ.js → file-text-CQ12t7Oc.js} +1 -1
- package/bizar-dash/dist/assets/{file-text-yEMkrSoZ.js.map → file-text-CQ12t7Oc.js.map} +1 -1
- package/bizar-dash/dist/assets/{filter-BXt60zAS.js → filter-BcbE37wP.js} +1 -1
- package/bizar-dash/dist/assets/{filter-BXt60zAS.js.map → filter-BcbE37wP.js.map} +1 -1
- package/bizar-dash/dist/assets/{git-pull-request-BjG5lNtR.js → git-pull-request-D1qNDRia.js} +1 -1
- package/bizar-dash/dist/assets/{git-pull-request-BjG5lNtR.js.map → git-pull-request-D1qNDRia.js.map} +1 -1
- package/bizar-dash/dist/assets/{main-CokHAXWM.js → main-Cxeu4LhG.js} +28 -33
- package/bizar-dash/dist/assets/main-Cxeu4LhG.js.map +1 -0
- package/bizar-dash/dist/assets/network-DJdvVaHx.js +6 -0
- package/bizar-dash/dist/assets/network-DJdvVaHx.js.map +1 -0
- package/bizar-dash/dist/assets/{pause-CAmulU0F.js → pause-DUn9L5PB.js} +1 -1
- package/bizar-dash/dist/assets/{pause-CAmulU0F.js.map → pause-DUn9L5PB.js.map} +1 -1
- package/bizar-dash/dist/assets/{pencil-eq5IqBmU.js → pencil-DVrBlYV3.js} +1 -1
- package/bizar-dash/dist/assets/{pencil-eq5IqBmU.js.map → pencil-DVrBlYV3.js.map} +1 -1
- package/bizar-dash/dist/assets/{play-BoLrrcBA.js → play-CZjsr3XM.js} +1 -1
- package/bizar-dash/dist/assets/{play-BoLrrcBA.js.map → play-CZjsr3XM.js.map} +1 -1
- package/bizar-dash/dist/assets/{plug-DBrVM9lK.js → plug-BKuyIe5W.js} +1 -1
- package/bizar-dash/dist/assets/{plug-DBrVM9lK.js.map → plug-BKuyIe5W.js.map} +1 -1
- package/bizar-dash/dist/assets/{plus-DENm0hqV.js → plus-77h62zZm.js} +1 -1
- package/bizar-dash/dist/assets/{plus-DENm0hqV.js.map → plus-77h62zZm.js.map} +1 -1
- package/bizar-dash/dist/assets/{power-DLjXF7zE.js → power-DLmx-gCP.js} +1 -1
- package/bizar-dash/dist/assets/{power-DLjXF7zE.js.map → power-DLmx-gCP.js.map} +1 -1
- package/bizar-dash/dist/assets/{power-off-D47cOnG_.js → power-off-BFKzHXic.js} +1 -1
- package/bizar-dash/dist/assets/{power-off-D47cOnG_.js.map → power-off-BFKzHXic.js.map} +1 -1
- package/bizar-dash/dist/assets/{refresh-ccw-DNrXX9gB.js → refresh-ccw-DenGBOcq.js} +1 -1
- package/bizar-dash/dist/assets/{refresh-ccw-DNrXX9gB.js.map → refresh-ccw-DenGBOcq.js.map} +1 -1
- package/bizar-dash/dist/assets/{refresh-cw-CoAHDpeS.js → refresh-cw-ENBVR8hW.js} +1 -1
- package/bizar-dash/dist/assets/{refresh-cw-CoAHDpeS.js.map → refresh-cw-ENBVR8hW.js.map} +1 -1
- package/bizar-dash/dist/assets/{rotate-ccw-ObX5awaG.js → rotate-ccw-MxryaY7q.js} +1 -1
- package/bizar-dash/dist/assets/{rotate-ccw-ObX5awaG.js.map → rotate-ccw-MxryaY7q.js.map} +1 -1
- package/bizar-dash/dist/assets/{rotate-cw-xpPJw9LP.js → rotate-cw-CDOlRtUR.js} +1 -1
- package/bizar-dash/dist/assets/{rotate-cw-xpPJw9LP.js.map → rotate-cw-CDOlRtUR.js.map} +1 -1
- package/bizar-dash/dist/assets/{save-D1iKiJJl.js → save-Db1b-1Uq.js} +1 -1
- package/bizar-dash/dist/assets/{save-D1iKiJJl.js.map → save-Db1b-1Uq.js.map} +1 -1
- package/bizar-dash/dist/assets/{send-BRcAhZUm.js → send-yz6HFZM5.js} +1 -1
- package/bizar-dash/dist/assets/{send-BRcAhZUm.js.map → send-yz6HFZM5.js.map} +1 -1
- package/bizar-dash/dist/assets/{shield-alert-C6vEcK-g.js → shield-alert-DY6RAaC8.js} +1 -1
- package/bizar-dash/dist/assets/{shield-alert-C6vEcK-g.js.map → shield-alert-DY6RAaC8.js.map} +1 -1
- package/bizar-dash/dist/assets/{trash-2-DZDjEnNh.js → trash-2-Cv7U38jw.js} +1 -1
- package/bizar-dash/dist/assets/{trash-2-DZDjEnNh.js.map → trash-2-Cv7U38jw.js.map} +1 -1
- package/bizar-dash/dist/assets/{trending-up-DMj-AJVf.js → trending-up-CRPNagyX.js} +1 -1
- package/bizar-dash/dist/assets/{trending-up-DMj-AJVf.js.map → trending-up-CRPNagyX.js.map} +1 -1
- package/bizar-dash/dist/assets/{triangle-alert-_2xe_tl4.js → triangle-alert-tUTXbcEP.js} +1 -1
- package/bizar-dash/dist/assets/{triangle-alert-_2xe_tl4.js.map → triangle-alert-tUTXbcEP.js.map} +1 -1
- package/bizar-dash/dist/assets/{upload-DdDljAeV.js → upload-Cq7uTsrT.js} +1 -1
- package/bizar-dash/dist/assets/{upload-DdDljAeV.js.map → upload-Cq7uTsrT.js.map} +1 -1
- package/bizar-dash/dist/assets/{zap-mHsgh0FP.js → zap-5lAQBAPX.js} +1 -1
- package/bizar-dash/dist/assets/{zap-mHsgh0FP.js.map → zap-5lAQBAPX.js.map} +1 -1
- package/bizar-dash/dist/index.html +1 -1
- package/bizar-dash/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
- package/bizar-dash/src/server/api.mjs +5 -1
- package/bizar-dash/src/server/routes/update.mjs +48 -21
- package/bizar-dash/src/web/v8/App.tsx +0 -4
- package/bizar-dash/src/web/v8/__tests__/new-views.test.tsx +0 -17
- package/bizar-dash/src/web/v8/shell/Sidebar.tsx +3 -4
- package/bizar-dash/src/web/v8/views/Router.tsx +0 -5
- package/bizar-dash/tests/_update-test-helpers.mjs +13 -0
- package/bizar-dash/tests/update-check.test.mjs +18 -13
- package/bizar-dash/tests/update-packages.test.mjs +154 -0
- package/bizar-dash/tests/update-run.test.mjs +17 -80
- package/cli/banner.mjs +1 -1
- package/cli/bin.mjs +8 -1
- package/cli/bootstrap.mjs +1 -1
- package/cli/commands/claude-cmd.mjs +1 -1
- package/cli/commands/deploy/docker.mjs +0 -3
- package/cli/doctor.mjs +1 -1
- package/cli/install/banner.mjs +67 -0
- package/cli/install/banner.test.mjs +39 -0
- package/cli/install/index.mjs +32 -0
- package/cli/install/index.test.mjs +61 -0
- package/cli/install/paths.mjs +80 -0
- package/cli/install/paths.test.mjs +77 -0
- package/cli/install/plugin.mjs +161 -0
- package/cli/install/postinstall.mjs +111 -0
- package/cli/install.mjs +13 -600
- package/cli/migrate.mjs +157 -0
- package/cli/migrate.test.mjs +85 -0
- package/cli/provision.mjs +615 -1918
- package/cli/provision.test.mjs +1 -1
- package/cli/service-controller.test.mjs +0 -1
- package/cli/service-env.mjs +0 -1
- package/cli/utils.mjs +0 -1
- package/install.sh +54 -466
- package/package.json +1 -1
- package/packages/sdk/dist/mcp/server.js +41 -409
- package/packages/sdk/dist/router/q-learning-router.d.ts +3 -5
- package/packages/sdk/dist/router/q-learning-router.js +9 -5
- package/packages/sdk/package.json +1 -1
- package/scripts/install-curl.sh +17 -0
- package/bizar-dash/dist/assets/HeadroomView-D1UiTYbt.js +0 -11
- package/bizar-dash/dist/assets/HeadroomView-D1UiTYbt.js.map +0 -1
- package/bizar-dash/dist/assets/MiscView-B8QY82Pm.js +0 -1
- package/bizar-dash/dist/assets/ObsidianView-BCTejEj2.js +0 -1
- package/bizar-dash/dist/assets/main-CokHAXWM.js.map +0 -1
- package/bizar-dash/skills/headroom/SKILL.md +0 -94
- package/bizar-dash/src/server/headroom.mjs +0 -649
- package/bizar-dash/src/server/routes/headroom.mjs +0 -126
- package/bizar-dash/src/web/v8/views/Headroom/HeadroomView.tsx +0 -201
- package/bizar-dash/tests/graphify-mod-spawn.node.test.mjs +0 -90
- package/bizar-dash/tests/headroom-install.test.mjs +0 -173
- package/bizar-dash/tests/headroom-settings.test.mjs +0 -126
- package/bizar-dash/tests/headroom-status.test.mjs +0 -117
- package/bizar-dash/tests/v7-archive/mobile-overview.test.tsx +0 -214
- package/bizar-dash/tests/v7-archive/mobile-settings.test.tsx +0 -181
- package/bizar-dash/tests/v7-archive/navigation/CommandPalette.test.tsx +0 -105
- package/bizar-dash/tests/v7-archive/settings-nav.test.tsx +0 -128
- package/bizar-dash/tests/v7-archive/views/Overview.test.tsx +0 -413
- package/cli/commands/headroom.mjs +0 -204
- package/cli/provision-claude.mjs +0 -1176
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
// tests/ui/navigation/CommandPalette.test.tsx — Wave 2B
|
|
2
|
-
|
|
3
|
-
import { render, screen } from '@testing-library/react';
|
|
4
|
-
import userEvent from '@testing-library/user-event';
|
|
5
|
-
import { describe, it, expect, vi } from 'vitest';
|
|
6
|
-
import { CommandPalette } from '../../../src/web/ui/navigation/CommandPalette';
|
|
7
|
-
|
|
8
|
-
const ITEMS = [
|
|
9
|
-
{
|
|
10
|
-
id: 'a1',
|
|
11
|
-
type: 'agent' as const,
|
|
12
|
-
label: 'Odin Agent',
|
|
13
|
-
description: 'Mid-tier orchestrator',
|
|
14
|
-
onSelect: vi.fn(),
|
|
15
|
-
},
|
|
16
|
-
{
|
|
17
|
-
id: 't1',
|
|
18
|
-
type: 'task' as const,
|
|
19
|
-
label: 'Build dashboard',
|
|
20
|
-
onSelect: vi.fn(),
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
id: 'm1',
|
|
24
|
-
type: 'mod' as const,
|
|
25
|
-
label: 'Headroom',
|
|
26
|
-
onSelect: vi.fn(),
|
|
27
|
-
},
|
|
28
|
-
];
|
|
29
|
-
|
|
30
|
-
describe('CommandPalette', () => {
|
|
31
|
-
it('does not render when open is false', () => {
|
|
32
|
-
const { container } = render(
|
|
33
|
-
<CommandPalette open={false} onClose={() => {}} items={ITEMS} />,
|
|
34
|
-
);
|
|
35
|
-
expect(container.querySelector('.bd-cmdk')).toBeNull();
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it('renders when open is true', () => {
|
|
39
|
-
render(<CommandPalette open={true} onClose={() => {}} items={ITEMS} />);
|
|
40
|
-
expect(screen.getByRole('dialog')).toBeInTheDocument();
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it('shows all items initially grouped by type', () => {
|
|
44
|
-
render(<CommandPalette open={true} onClose={() => {}} items={ITEMS} />);
|
|
45
|
-
expect(screen.getByText('Odin Agent')).toBeInTheDocument();
|
|
46
|
-
expect(screen.getByText('Build dashboard')).toBeInTheDocument();
|
|
47
|
-
expect(screen.getByText('Headroom')).toBeInTheDocument();
|
|
48
|
-
expect(screen.getByText('Agents')).toBeInTheDocument();
|
|
49
|
-
expect(screen.getByText('Tasks')).toBeInTheDocument();
|
|
50
|
-
expect(screen.getByText('Mods')).toBeInTheDocument();
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
it('filters items by fuzzy match on label/description', async () => {
|
|
54
|
-
render(<CommandPalette open={true} onClose={() => {}} items={ITEMS} />);
|
|
55
|
-
await userEvent.type(
|
|
56
|
-
screen.getByPlaceholderText('Search anything…'),
|
|
57
|
-
'orchestrator',
|
|
58
|
-
);
|
|
59
|
-
// Only "Odin Agent" (description contains "orchestrator") survives.
|
|
60
|
-
expect(screen.getByText('Odin Agent')).toBeInTheDocument();
|
|
61
|
-
expect(screen.queryByText('Build dashboard')).toBeNull();
|
|
62
|
-
expect(screen.queryByText('Headroom')).toBeNull();
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it('shows "No results" when no items match', async () => {
|
|
66
|
-
render(<CommandPalette open={true} onClose={() => {}} items={ITEMS} />);
|
|
67
|
-
await userEvent.type(
|
|
68
|
-
screen.getByPlaceholderText('Search anything…'),
|
|
69
|
-
'zzzzzzz',
|
|
70
|
-
);
|
|
71
|
-
expect(screen.getByText('No results')).toBeInTheDocument();
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
it('arrow keys cycle through visible items', async () => {
|
|
75
|
-
render(<CommandPalette open={true} onClose={() => {}} items={ITEMS} />);
|
|
76
|
-
await userEvent.type(screen.getByPlaceholderText('Search anything…'), 'a');
|
|
77
|
-
// After filtering 'a' we may still see multiple results — just check
|
|
78
|
-
// that pressing ArrowDown moves activeIndex.
|
|
79
|
-
const before = document.querySelector('.bd-cmdk__item--active');
|
|
80
|
-
await userEvent.keyboard('{ArrowDown}');
|
|
81
|
-
const after = document.querySelector('.bd-cmdk__item--active');
|
|
82
|
-
// Active highlight class moved from one item to the next.
|
|
83
|
-
expect(before).not.toBe(after);
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
it('clicking an item triggers onSelect and closes the palette', async () => {
|
|
87
|
-
const onClose = vi.fn();
|
|
88
|
-
render(
|
|
89
|
-
<CommandPalette open={true} onClose={onClose} items={ITEMS} />,
|
|
90
|
-
);
|
|
91
|
-
await userEvent.click(screen.getByText('Headroom'));
|
|
92
|
-
expect(ITEMS[2].onSelect).toHaveBeenCalledTimes(1);
|
|
93
|
-
expect(onClose).toHaveBeenCalled();
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
it('Escape closes the palette', async () => {
|
|
97
|
-
const onClose = vi.fn();
|
|
98
|
-
render(<CommandPalette open={true} onClose={onClose} items={ITEMS} />);
|
|
99
|
-
const dialog = screen.getByRole('dialog');
|
|
100
|
-
dialog.focus();
|
|
101
|
-
// The keydown handler is on the .bd-cmdk wrapper; dispatch from there.
|
|
102
|
-
await userEvent.keyboard('{Escape}');
|
|
103
|
-
expect(onClose).toHaveBeenCalled();
|
|
104
|
-
});
|
|
105
|
-
});
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* tests/settings-nav.test.tsx
|
|
3
|
-
*
|
|
4
|
-
* v4.9.0 — Component tests for SettingsNav sidebar component.
|
|
5
|
-
*/
|
|
6
|
-
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
7
|
-
import { render, screen } from '@testing-library/react';
|
|
8
|
-
import userEvent from '@testing-library/user-event';
|
|
9
|
-
import React from 'react';
|
|
10
|
-
import { SettingsNav } from '../src/web/components/SettingsNav';
|
|
11
|
-
|
|
12
|
-
describe('SettingsNav', () => {
|
|
13
|
-
const onSectionChange = vi.fn();
|
|
14
|
-
const onExitSettings = vi.fn();
|
|
15
|
-
|
|
16
|
-
beforeEach(() => {
|
|
17
|
-
vi.clearAllMocks();
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
it('renders the back button', () => {
|
|
21
|
-
render(
|
|
22
|
-
<SettingsNav
|
|
23
|
-
activeSection={null}
|
|
24
|
-
onSectionChange={onSectionChange}
|
|
25
|
-
onExitSettings={onExitSettings}
|
|
26
|
-
/>,
|
|
27
|
-
);
|
|
28
|
-
expect(screen.getByRole('button', { name: /exit settings/i })).toBeInTheDocument();
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it('calls onExitSettings when back button is clicked', async () => {
|
|
32
|
-
const user = userEvent.setup();
|
|
33
|
-
render(
|
|
34
|
-
<SettingsNav
|
|
35
|
-
activeSection={null}
|
|
36
|
-
onSectionChange={onSectionChange}
|
|
37
|
-
onExitSettings={onExitSettings}
|
|
38
|
-
/>,
|
|
39
|
-
);
|
|
40
|
-
await user.click(screen.getByText('Back'));
|
|
41
|
-
expect(onExitSettings).toHaveBeenCalledTimes(1);
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it('renders section groups with shared sidebar-section-label class', () => {
|
|
45
|
-
render(
|
|
46
|
-
<SettingsNav
|
|
47
|
-
activeSection={null}
|
|
48
|
-
onSectionChange={onSectionChange}
|
|
49
|
-
onExitSettings={onExitSettings}
|
|
50
|
-
/>,
|
|
51
|
-
);
|
|
52
|
-
expect(screen.getByText('General', { selector: '.sidebar-section-label' })).toBeInTheDocument();
|
|
53
|
-
expect(screen.getByText('Core', { selector: '.sidebar-section-label' })).toBeInTheDocument();
|
|
54
|
-
expect(screen.getByText('Agents', { selector: '.sidebar-section-label' })).toBeInTheDocument();
|
|
55
|
-
expect(screen.getByText('Experience', { selector: '.sidebar-section-label' })).toBeInTheDocument();
|
|
56
|
-
expect(screen.getByText('Data', { selector: '.sidebar-section-label' })).toBeInTheDocument();
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
it('renders section items within each group', () => {
|
|
60
|
-
render(
|
|
61
|
-
<SettingsNav
|
|
62
|
-
activeSection={null}
|
|
63
|
-
onSectionChange={onSectionChange}
|
|
64
|
-
onExitSettings={onExitSettings}
|
|
65
|
-
/>,
|
|
66
|
-
);
|
|
67
|
-
// General group
|
|
68
|
-
expect(screen.getByRole('button', { name: /theme/i })).toBeInTheDocument();
|
|
69
|
-
expect(screen.getByRole('button', { name: /layout/i })).toBeInTheDocument();
|
|
70
|
-
// Core group
|
|
71
|
-
expect(screen.getByRole('button', { name: /env vars/i })).toBeInTheDocument();
|
|
72
|
-
expect(screen.getByRole('button', { name: /system llm/i })).toBeInTheDocument();
|
|
73
|
-
// Experience group
|
|
74
|
-
expect(screen.getByRole('button', { name: /updates/i })).toBeInTheDocument();
|
|
75
|
-
expect(screen.getByRole('button', { name: /headroom/i })).toBeInTheDocument();
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
it('calls onSectionChange with correct id when a section is clicked', async () => {
|
|
79
|
-
const user = userEvent.setup();
|
|
80
|
-
render(
|
|
81
|
-
<SettingsNav
|
|
82
|
-
activeSection={null}
|
|
83
|
-
onSectionChange={onSectionChange}
|
|
84
|
-
onExitSettings={onExitSettings}
|
|
85
|
-
/>,
|
|
86
|
-
);
|
|
87
|
-
await user.click(screen.getByRole('button', { name: /theme/i }));
|
|
88
|
-
expect(onSectionChange).toHaveBeenCalledWith('theme');
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it('highlights the active section', () => {
|
|
92
|
-
render(
|
|
93
|
-
<SettingsNav
|
|
94
|
-
activeSection="theme"
|
|
95
|
-
onSectionChange={onSectionChange}
|
|
96
|
-
onExitSettings={onExitSettings}
|
|
97
|
-
/>,
|
|
98
|
-
);
|
|
99
|
-
const themeBtn = screen.getByRole('button', { name: /theme/i });
|
|
100
|
-
expect(themeBtn).toHaveClass('sidebar-tab-active');
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
it('toggles off the active section when clicking it again', async () => {
|
|
104
|
-
const user = userEvent.setup();
|
|
105
|
-
render(
|
|
106
|
-
<SettingsNav
|
|
107
|
-
activeSection="theme"
|
|
108
|
-
onSectionChange={onSectionChange}
|
|
109
|
-
onExitSettings={onExitSettings}
|
|
110
|
-
/>,
|
|
111
|
-
);
|
|
112
|
-
await user.click(screen.getByRole('button', { name: /theme/i }));
|
|
113
|
-
expect(onSectionChange).toHaveBeenCalledWith(null); // toggles off
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
it('renders chevron on the active section', () => {
|
|
117
|
-
render(
|
|
118
|
-
<SettingsNav
|
|
119
|
-
activeSection="theme"
|
|
120
|
-
onSectionChange={onSectionChange}
|
|
121
|
-
onExitSettings={onExitSettings}
|
|
122
|
-
/>,
|
|
123
|
-
);
|
|
124
|
-
const themeBtn = screen.getByRole('button', { name: /theme/i });
|
|
125
|
-
// The chevron is inside the button as an SVG (aria-hidden), so we just verify the button exists
|
|
126
|
-
expect(themeBtn).toBeInTheDocument();
|
|
127
|
-
});
|
|
128
|
-
});
|
|
@@ -1,413 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* tests/views/Overview.test.tsx
|
|
3
|
-
*
|
|
4
|
-
* Wave 3 — Overview redesign smoke tests. Covers:
|
|
5
|
-
* - The new Overview mounts without crashing given a populated snapshot.
|
|
6
|
-
* - The five stat tiles render the correct labelled values.
|
|
7
|
-
* - The activity stream renders rows from the snapshot seed.
|
|
8
|
-
* - Per-row hide toggle POSTs to /activity/hide with the correct key.
|
|
9
|
-
* - "Hide all" calls POST /activity/hide with the full list of keys.
|
|
10
|
-
* - The SSE subscription is established (mock EventSource) but never actually fires.
|
|
11
|
-
* - Clicking the submit button calls /tasks/submit.
|
|
12
|
-
*
|
|
13
|
-
* Notes:
|
|
14
|
-
* - EventSource is mocked globally (no listener fires in jsdom).
|
|
15
|
-
* - api is mocked so no network is attempted.
|
|
16
|
-
* - ThemeProvider + ToastProvider + ModalProvider wrap the view so the
|
|
17
|
-
* helpers the Overview calls (useToast / useModal) get a real context.
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
21
|
-
import { render, screen, waitFor, within } from '@testing-library/react';
|
|
22
|
-
import userEvent from '@testing-library/user-event';
|
|
23
|
-
import React from 'react';
|
|
24
|
-
|
|
25
|
-
import { Overview } from '../../src/web/views/Overview';
|
|
26
|
-
import { ToastProvider } from '../../src/web/components/Toast';
|
|
27
|
-
import { ModalProvider } from '../../src/web/components/Modal';
|
|
28
|
-
|
|
29
|
-
import type {
|
|
30
|
-
ActivityItem,
|
|
31
|
-
Agent,
|
|
32
|
-
Artifact,
|
|
33
|
-
Mod,
|
|
34
|
-
Overview as OverviewData,
|
|
35
|
-
ProjectRecord,
|
|
36
|
-
Settings,
|
|
37
|
-
Snapshot,
|
|
38
|
-
Task,
|
|
39
|
-
} from '../../src/web/lib/types';
|
|
40
|
-
import { api } from '../../src/web/lib/api';
|
|
41
|
-
|
|
42
|
-
// ─── Mocks ──────────────────────────────────────────────────────────────────
|
|
43
|
-
|
|
44
|
-
class MockEventSource {
|
|
45
|
-
url: string;
|
|
46
|
-
readyState = 0;
|
|
47
|
-
listeners: Record<string, ((e: MessageEvent) => void)[]> = {};
|
|
48
|
-
onerror: ((e: Event) => void) | null = null;
|
|
49
|
-
constructor(url: string) {
|
|
50
|
-
this.url = url;
|
|
51
|
-
MockEventSource.instances.push(this);
|
|
52
|
-
}
|
|
53
|
-
addEventListener(name: string, cb: (e: MessageEvent) => void) {
|
|
54
|
-
(this.listeners[name] ||= []).push(cb);
|
|
55
|
-
}
|
|
56
|
-
removeEventListener() { /* noop for tests */ }
|
|
57
|
-
close() {
|
|
58
|
-
this.readyState = 2;
|
|
59
|
-
}
|
|
60
|
-
// Test helpers — manually dispatch like a real server would.
|
|
61
|
-
__dispatch(name: string, data: unknown) {
|
|
62
|
-
const ev = { data: JSON.stringify(data) } as MessageEvent;
|
|
63
|
-
this.listeners[name]?.forEach((cb) => cb(ev));
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
(MockEventSource as unknown as { instances: MockEventSource[] }).instances = [];
|
|
67
|
-
|
|
68
|
-
vi.stubGlobal('EventSource', MockEventSource);
|
|
69
|
-
|
|
70
|
-
vi.mock('../../src/web/lib/api', () => {
|
|
71
|
-
return {
|
|
72
|
-
api: {
|
|
73
|
-
get: vi.fn(),
|
|
74
|
-
post: vi.fn(),
|
|
75
|
-
put: vi.fn(),
|
|
76
|
-
patch: vi.fn(),
|
|
77
|
-
del: vi.fn(),
|
|
78
|
-
getToken: vi.fn(() => ''),
|
|
79
|
-
setToken: vi.fn(),
|
|
80
|
-
probeAuthStatus: vi.fn(),
|
|
81
|
-
},
|
|
82
|
-
ApiError: class ApiError extends Error {
|
|
83
|
-
status: number;
|
|
84
|
-
constructor(status: number, message: string) {
|
|
85
|
-
super(message);
|
|
86
|
-
this.status = status;
|
|
87
|
-
}
|
|
88
|
-
},
|
|
89
|
-
};
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
const Harness: React.FC<{ children: React.ReactNode }> = ({ children }) => (
|
|
93
|
-
<ToastProvider>
|
|
94
|
-
<ModalProvider>{children}</ModalProvider>
|
|
95
|
-
</ToastProvider>
|
|
96
|
-
);
|
|
97
|
-
|
|
98
|
-
// ─── Fixtures ────────────────────────────────────────────────────────────────
|
|
99
|
-
|
|
100
|
-
function makeOverview(overrides: Partial<OverviewData> = {}): OverviewData {
|
|
101
|
-
return {
|
|
102
|
-
counts: {
|
|
103
|
-
agents: 7,
|
|
104
|
-
plans: 4,
|
|
105
|
-
projects: 3,
|
|
106
|
-
sessions: 2,
|
|
107
|
-
activeProject: 'p-1',
|
|
108
|
-
...(overrides.counts ?? {}),
|
|
109
|
-
},
|
|
110
|
-
recentActivity: overrides.recentActivity ?? [
|
|
111
|
-
{
|
|
112
|
-
ts: new Date().toISOString(),
|
|
113
|
-
kind: 'task.created',
|
|
114
|
-
title: 'Build settings page',
|
|
115
|
-
} as unknown as ActivityItem,
|
|
116
|
-
{
|
|
117
|
-
ts: new Date(Date.now() - 5 * 60_000).toISOString(),
|
|
118
|
-
kind: 'agent.delegated',
|
|
119
|
-
agent: 'thor',
|
|
120
|
-
} as unknown as ActivityItem,
|
|
121
|
-
],
|
|
122
|
-
versions: {
|
|
123
|
-
node: 'v20.10.0',
|
|
124
|
-
platform: 'linux',
|
|
125
|
-
projectRoot: '/srv/bizar',
|
|
126
|
-
bizarRoot: '/home/user/.bizar',
|
|
127
|
-
...(overrides.versions ?? {}),
|
|
128
|
-
},
|
|
129
|
-
generatedAt: new Date().toISOString(),
|
|
130
|
-
...overrides,
|
|
131
|
-
} as OverviewData;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
function makeSnapshot(overrides: Partial<Snapshot> = {}): Snapshot {
|
|
135
|
-
return {
|
|
136
|
-
overview: makeOverview(),
|
|
137
|
-
agents: [] as Agent[],
|
|
138
|
-
artifacts: [] as Artifact[],
|
|
139
|
-
projects: [
|
|
140
|
-
{ id: 'p-1', name: 'Bizar', path: '/srv/bizar', status: 'active' },
|
|
141
|
-
{ id: 'p-2', name: 'Spar', path: '/srv/spar', status: 'inactive' },
|
|
142
|
-
] as ProjectRecord[],
|
|
143
|
-
activeProject: {
|
|
144
|
-
id: 'p-1',
|
|
145
|
-
name: 'Bizar',
|
|
146
|
-
path: '/srv/bizar',
|
|
147
|
-
status: 'active',
|
|
148
|
-
} as ProjectRecord,
|
|
149
|
-
config: { path: '', data: {}, raw: '', exists: true },
|
|
150
|
-
settings: { path: '', data: {} as Settings, exists: true },
|
|
151
|
-
tasks: [
|
|
152
|
-
{
|
|
153
|
-
id: 't-1',
|
|
154
|
-
title: 'Refactor parser',
|
|
155
|
-
description: '',
|
|
156
|
-
status: 'doing',
|
|
157
|
-
tags: [],
|
|
158
|
-
priority: 'normal',
|
|
159
|
-
assignee: 'thor',
|
|
160
|
-
createdAt: new Date().toISOString(),
|
|
161
|
-
updatedAt: new Date().toISOString(),
|
|
162
|
-
} as Task,
|
|
163
|
-
{
|
|
164
|
-
id: 't-2',
|
|
165
|
-
title: 'Add schema check',
|
|
166
|
-
description: '',
|
|
167
|
-
status: 'queued',
|
|
168
|
-
tags: [],
|
|
169
|
-
priority: 'normal',
|
|
170
|
-
assignee: 'heimdall',
|
|
171
|
-
createdAt: new Date(Date.now() - 2 * 24 * 3600_000).toISOString(),
|
|
172
|
-
updatedAt: new Date(Date.now() - 24 * 3600_000).toISOString(),
|
|
173
|
-
} as Task,
|
|
174
|
-
],
|
|
175
|
-
mods: [
|
|
176
|
-
{
|
|
177
|
-
id: 'm-1',
|
|
178
|
-
name: 'graphify',
|
|
179
|
-
version: '1.0.0',
|
|
180
|
-
author: 'bizar',
|
|
181
|
-
description: '',
|
|
182
|
-
bizar: '',
|
|
183
|
-
type: 'tool',
|
|
184
|
-
enabled: true,
|
|
185
|
-
permissions: [],
|
|
186
|
-
entry: {},
|
|
187
|
-
files: [],
|
|
188
|
-
path: '/mods/graphify',
|
|
189
|
-
installedAt: null,
|
|
190
|
-
} as Mod,
|
|
191
|
-
{
|
|
192
|
-
id: 'm-2',
|
|
193
|
-
name: 'headroom',
|
|
194
|
-
version: '0.4.0',
|
|
195
|
-
author: 'bizar',
|
|
196
|
-
description: '',
|
|
197
|
-
bizar: '',
|
|
198
|
-
type: 'service',
|
|
199
|
-
enabled: false,
|
|
200
|
-
permissions: [],
|
|
201
|
-
entry: {},
|
|
202
|
-
files: [],
|
|
203
|
-
path: '/mods/headroom',
|
|
204
|
-
installedAt: null,
|
|
205
|
-
} as Mod,
|
|
206
|
-
],
|
|
207
|
-
schedules: [],
|
|
208
|
-
providers: [],
|
|
209
|
-
mcps: [],
|
|
210
|
-
...overrides,
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
const baseSettings = {
|
|
215
|
-
theme: { mode: 'system' as const, accent: '', success: '', warning: '', error: '', info: '', fontFamily: '', fontSize: 13, compactMode: false, animations: true },
|
|
216
|
-
ui: { layout: 'both' as const, showHeader: true, showStatusBar: true, defaultTab: 'overview' },
|
|
217
|
-
defaultAgent: 'odin',
|
|
218
|
-
defaultModel: 'claude-opus-4',
|
|
219
|
-
notifications: { onAgentComplete: false, onPlanApproval: false },
|
|
220
|
-
dashboard: { autoLaunchWeb: false, projectsDirectory: '/srv' },
|
|
221
|
-
service: { enabled: false, autostart: false },
|
|
222
|
-
about: { version: 'v6.5.0', homepage: '', license: '' },
|
|
223
|
-
agents: { maxParallel: 3, stuckThresholdMs: 60_000, autoRestart: false },
|
|
224
|
-
personalization: { displayName: '', role: '', team: '', aboutMe: '', preferences: '' },
|
|
225
|
-
workflow: { artifactsEnabled: true, agentsDecideAutonomously: false, chatAutonomous: false },
|
|
226
|
-
} as unknown as Settings;
|
|
227
|
-
|
|
228
|
-
// ─── Tests ──────────────────────────────────────────────────────────────────
|
|
229
|
-
|
|
230
|
-
describe('Overview (Wave 3 redesign)', () => {
|
|
231
|
-
beforeEach(() => {
|
|
232
|
-
vi.clearAllMocks();
|
|
233
|
-
MockEventSource.instances.length = 0;
|
|
234
|
-
(api.get as ReturnType<typeof vi.fn>).mockImplementation((url: string) => {
|
|
235
|
-
if (url === '/activity/hidden') return Promise.resolve({ hidden: [] });
|
|
236
|
-
return Promise.resolve(null);
|
|
237
|
-
});
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
afterEach(() => {
|
|
241
|
-
vi.useRealTimers();
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
it('mounts without crashing and establishes the SSE subscription', async () => {
|
|
245
|
-
const snapshot = makeSnapshot();
|
|
246
|
-
render(
|
|
247
|
-
<Harness>
|
|
248
|
-
<Overview
|
|
249
|
-
snapshot={snapshot}
|
|
250
|
-
settings={baseSettings}
|
|
251
|
-
activeTab="overview"
|
|
252
|
-
setActiveTab={vi.fn()}
|
|
253
|
-
refreshSnapshot={vi.fn(async () => undefined)}
|
|
254
|
-
/>
|
|
255
|
-
</Harness>,
|
|
256
|
-
);
|
|
257
|
-
|
|
258
|
-
expect(await screen.findByTestId('overview-stat-row')).toBeInTheDocument();
|
|
259
|
-
expect(MockEventSource.instances).toHaveLength(1);
|
|
260
|
-
expect(MockEventSource.instances[0].url).toBe('/api/activity/stream');
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
it('renders all five stat tiles with the correct values', async () => {
|
|
264
|
-
const snapshot = makeSnapshot({
|
|
265
|
-
overview: makeOverview({
|
|
266
|
-
counts: { agents: 7, plans: 4, projects: 3, sessions: 2, activeProject: 'p-1' },
|
|
267
|
-
}),
|
|
268
|
-
});
|
|
269
|
-
render(
|
|
270
|
-
<Harness>
|
|
271
|
-
<Overview
|
|
272
|
-
snapshot={snapshot}
|
|
273
|
-
settings={baseSettings}
|
|
274
|
-
activeTab="overview"
|
|
275
|
-
setActiveTab={vi.fn()}
|
|
276
|
-
refreshSnapshot={vi.fn(async () => undefined)}
|
|
277
|
-
/>
|
|
278
|
-
</Harness>,
|
|
279
|
-
);
|
|
280
|
-
|
|
281
|
-
// StatTile doesn't forward data-testid; find tiles by their label
|
|
282
|
-
// text. Labels are sentence-cased in DOM, uppercase via CSS.
|
|
283
|
-
expect(await screen.findByText('Agents')).toBeInTheDocument();
|
|
284
|
-
expect(screen.getByText('Tasks')).toBeInTheDocument();
|
|
285
|
-
expect(screen.getByText('Projects')).toBeInTheDocument();
|
|
286
|
-
expect(screen.getByText('Mods')).toBeInTheDocument();
|
|
287
|
-
expect(screen.getByText('Background')).toBeInTheDocument();
|
|
288
|
-
|
|
289
|
-
// 7 agents, 2 tasks, 2 projects, 2 mods, 2 background
|
|
290
|
-
const row = await screen.findByTestId('overview-stat-row');
|
|
291
|
-
expect(within(row).getByText('7')).toBeInTheDocument();
|
|
292
|
-
// The number "2" appears multiple times (tasks, projects, mods, background)
|
|
293
|
-
const twos = within(row).getAllByText('2');
|
|
294
|
-
expect(twos.length).toBeGreaterThanOrEqual(4);
|
|
295
|
-
});
|
|
296
|
-
|
|
297
|
-
it('renders activity rows from the snapshot seed', async () => {
|
|
298
|
-
const snapshot = makeSnapshot({
|
|
299
|
-
overview: makeOverview({
|
|
300
|
-
recentActivity: [
|
|
301
|
-
{ ts: new Date().toISOString(), kind: 'task.created', title: 'Build settings page' } as ActivityItem,
|
|
302
|
-
{ ts: new Date().toISOString(), kind: 'agent.delegated', agent: 'thor' } as ActivityItem,
|
|
303
|
-
],
|
|
304
|
-
}),
|
|
305
|
-
});
|
|
306
|
-
render(
|
|
307
|
-
<Harness>
|
|
308
|
-
<Overview
|
|
309
|
-
snapshot={snapshot}
|
|
310
|
-
settings={baseSettings}
|
|
311
|
-
activeTab="overview"
|
|
312
|
-
setActiveTab={vi.fn()}
|
|
313
|
-
refreshSnapshot={vi.fn(async () => undefined)}
|
|
314
|
-
/>
|
|
315
|
-
</Harness>,
|
|
316
|
-
);
|
|
317
|
-
|
|
318
|
-
const list = await screen.findByTestId('overview-activity-list');
|
|
319
|
-
expect(within(list).getByText(/Task created/i)).toBeInTheDocument();
|
|
320
|
-
expect(within(list).getByText(/Agent delegated/i)).toBeInTheDocument();
|
|
321
|
-
});
|
|
322
|
-
|
|
323
|
-
it('hides a single activity row when its icon button is clicked', async () => {
|
|
324
|
-
(api.post as ReturnType<typeof vi.fn>).mockResolvedValue({ ok: true });
|
|
325
|
-
const user = userEvent.setup();
|
|
326
|
-
const snapshot = makeSnapshot();
|
|
327
|
-
render(
|
|
328
|
-
<Harness>
|
|
329
|
-
<Overview
|
|
330
|
-
snapshot={snapshot}
|
|
331
|
-
settings={baseSettings}
|
|
332
|
-
activeTab="overview"
|
|
333
|
-
setActiveTab={vi.fn()}
|
|
334
|
-
refreshSnapshot={vi.fn(async () => undefined)}
|
|
335
|
-
/>
|
|
336
|
-
</Harness>,
|
|
337
|
-
);
|
|
338
|
-
|
|
339
|
-
const list = await screen.findByTestId('overview-activity-list');
|
|
340
|
-
const hideButtons = within(list).getAllByRole('button', { name: /hide from overview/i });
|
|
341
|
-
expect(hideButtons.length).toBeGreaterThan(0);
|
|
342
|
-
|
|
343
|
-
await user.click(hideButtons[0]);
|
|
344
|
-
|
|
345
|
-
await waitFor(() => {
|
|
346
|
-
expect(api.post).toHaveBeenCalledWith(
|
|
347
|
-
'/activity/hide',
|
|
348
|
-
expect.objectContaining({ keys: expect.any(Array) }),
|
|
349
|
-
);
|
|
350
|
-
});
|
|
351
|
-
});
|
|
352
|
-
|
|
353
|
-
it('posts the full list of keys when "Hide all" is clicked', async () => {
|
|
354
|
-
const confirmSpy = vi.spyOn(window, 'confirm').mockReturnValue(true);
|
|
355
|
-
(api.post as ReturnType<typeof vi.fn>).mockResolvedValue({ ok: true });
|
|
356
|
-
const user = userEvent.setup();
|
|
357
|
-
const snapshot = makeSnapshot();
|
|
358
|
-
render(
|
|
359
|
-
<Harness>
|
|
360
|
-
<Overview
|
|
361
|
-
snapshot={snapshot}
|
|
362
|
-
settings={baseSettings}
|
|
363
|
-
activeTab="overview"
|
|
364
|
-
setActiveTab={vi.fn()}
|
|
365
|
-
refreshSnapshot={vi.fn(async () => undefined)}
|
|
366
|
-
/>
|
|
367
|
-
</Harness>,
|
|
368
|
-
);
|
|
369
|
-
|
|
370
|
-
await user.click(await screen.findByTestId('overview-hide-all'));
|
|
371
|
-
|
|
372
|
-
await waitFor(() => {
|
|
373
|
-
const calls = (api.post as ReturnType<typeof vi.fn>).mock.calls;
|
|
374
|
-
const hideCall = calls.find(([url]: unknown[]) => url === '/activity/hide');
|
|
375
|
-
expect(hideCall).toBeDefined();
|
|
376
|
-
const body = hideCall?.[1] as { keys: string[] };
|
|
377
|
-
expect(Array.isArray(body.keys)).toBe(true);
|
|
378
|
-
expect(body.keys.length).toBeGreaterThan(0);
|
|
379
|
-
});
|
|
380
|
-
|
|
381
|
-
confirmSpy.mockRestore();
|
|
382
|
-
});
|
|
383
|
-
|
|
384
|
-
it('calls /tasks/submit when the "Submit to Odin" button is clicked', async () => {
|
|
385
|
-
(api.post as ReturnType<typeof vi.fn>).mockResolvedValue({ subtasks: [{}, {}] });
|
|
386
|
-
const user = userEvent.setup();
|
|
387
|
-
const refresh = vi.fn(async () => undefined);
|
|
388
|
-
const snapshot = makeSnapshot();
|
|
389
|
-
|
|
390
|
-
render(
|
|
391
|
-
<Harness>
|
|
392
|
-
<Overview
|
|
393
|
-
snapshot={snapshot}
|
|
394
|
-
settings={baseSettings}
|
|
395
|
-
activeTab="overview"
|
|
396
|
-
setActiveTab={vi.fn()}
|
|
397
|
-
refreshSnapshot={refresh}
|
|
398
|
-
/>
|
|
399
|
-
</Harness>,
|
|
400
|
-
);
|
|
401
|
-
|
|
402
|
-
const textarea = await screen.findByTestId('overview-prompt-input');
|
|
403
|
-
await user.type(textarea, 'Build a thing');
|
|
404
|
-
await user.click(screen.getByTestId('overview-submit'));
|
|
405
|
-
|
|
406
|
-
await waitFor(() => {
|
|
407
|
-
expect(api.post).toHaveBeenCalledWith(
|
|
408
|
-
'/tasks/submit',
|
|
409
|
-
expect.objectContaining({ title: expect.stringContaining('Build a thing') }),
|
|
410
|
-
);
|
|
411
|
-
});
|
|
412
|
-
});
|
|
413
|
-
});
|