@polderlabs/bizar 10.1.0 → 10.2.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 +0 -2
- package/bizar-dash/dist/assets/{ActivityFeed-Da-JCrE6.js → ActivityFeed-JjmOY2AQ.js} +1 -1
- package/bizar-dash/dist/assets/{ActivityFeed-Da-JCrE6.js.map → ActivityFeed-JjmOY2AQ.js.map} +1 -1
- package/bizar-dash/dist/assets/{ActivityView-nIRsSETb.js → ActivityView-BIIMvGWo.js} +1 -1
- package/bizar-dash/dist/assets/{ActivityView-nIRsSETb.js.map → ActivityView-BIIMvGWo.js.map} +1 -1
- package/bizar-dash/dist/assets/{AdminView-DP1NMxmG.js → AdminView-DRidJtkq.js} +1 -1
- package/bizar-dash/dist/assets/{AdminView-DP1NMxmG.js.map → AdminView-DRidJtkq.js.map} +1 -1
- package/bizar-dash/dist/assets/{AgentActivity-lSPkOr-O.js → AgentActivity-79l4SBMC.js} +1 -1
- package/bizar-dash/dist/assets/{AgentActivity-lSPkOr-O.js.map → AgentActivity-79l4SBMC.js.map} +1 -1
- package/bizar-dash/dist/assets/{AgentsView-BIWGkz7w.js → AgentsView-0vT4uPSc.js} +1 -1
- package/bizar-dash/dist/assets/{AgentsView-BIWGkz7w.js.map → AgentsView-0vT4uPSc.js.map} +1 -1
- package/bizar-dash/dist/assets/{Alert-DN0UysMg.js → Alert-CG5q_s75.js} +1 -1
- package/bizar-dash/dist/assets/{Alert-DN0UysMg.js.map → Alert-CG5q_s75.js.map} +1 -1
- package/bizar-dash/dist/assets/ArtifactsView-DM8ZmpR9.js +21 -0
- package/bizar-dash/dist/assets/ArtifactsView-DM8ZmpR9.js.map +1 -0
- package/bizar-dash/dist/assets/{AuthView-DW5cs7ma.js → AuthView-BveN94MC.js} +1 -1
- package/bizar-dash/dist/assets/{AuthView-DW5cs7ma.js.map → AuthView-BveN94MC.js.map} +1 -1
- package/bizar-dash/dist/assets/{Avatar-DZPv9pvd.js → Avatar-ulUPIYTd.js} +1 -1
- package/bizar-dash/dist/assets/{Avatar-DZPv9pvd.js.map → Avatar-ulUPIYTd.js.map} +1 -1
- package/bizar-dash/dist/assets/{BackgroundJobsView-D8O-EyMD.js → BackgroundJobsView-BWErhqFo.js} +1 -1
- package/bizar-dash/dist/assets/{BackgroundJobsView-D8O-EyMD.js.map → BackgroundJobsView-BWErhqFo.js.map} +1 -1
- package/bizar-dash/dist/assets/{BackupView-uwXkhxOV.js → BackupView-CnBjzG9N.js} +1 -1
- package/bizar-dash/dist/assets/{BackupView-uwXkhxOV.js.map → BackupView-CnBjzG9N.js.map} +1 -1
- package/bizar-dash/dist/assets/{Card-Tyboihu7.js → Card-B0imhxMk.js} +1 -1
- package/bizar-dash/dist/assets/{Card-Tyboihu7.js.map → Card-B0imhxMk.js.map} +1 -1
- package/bizar-dash/dist/assets/{ChatView-DRBHzgay.js → ChatView-D6zGytzx.js} +1 -1
- package/bizar-dash/dist/assets/{ChatView-DRBHzgay.js.map → ChatView-D6zGytzx.js.map} +1 -1
- package/bizar-dash/dist/assets/{Chip-BrXIlR9w.js → Chip-wwZSGwLE.js} +1 -1
- package/bizar-dash/dist/assets/{Chip-BrXIlR9w.js.map → Chip-wwZSGwLE.js.map} +1 -1
- package/bizar-dash/dist/assets/{ClaudeSessionsView-Ck62jaOr.js → ClaudeSessionsView-DK1sOLhi.js} +1 -1
- package/bizar-dash/dist/assets/{ClaudeSessionsView-Ck62jaOr.js.map → ClaudeSessionsView-DK1sOLhi.js.map} +1 -1
- package/bizar-dash/dist/assets/{ClipboardView-DfND6xL6.js → ClipboardView-CZ2lYPr0.js} +1 -1
- package/bizar-dash/dist/assets/{ClipboardView-DfND6xL6.js.map → ClipboardView-CZ2lYPr0.js.map} +1 -1
- package/bizar-dash/dist/assets/{ConfigView-DjJmSrOJ.js → ConfigView-D-zT9eNA.js} +1 -1
- package/bizar-dash/dist/assets/{ConfigView-DjJmSrOJ.js.map → ConfigView-D-zT9eNA.js.map} +1 -1
- package/bizar-dash/dist/assets/{DiagnosticsView-CKgItf0J.js → DiagnosticsView-BocV68Lb.js} +1 -1
- package/bizar-dash/dist/assets/{DiagnosticsView-CKgItf0J.js.map → DiagnosticsView-BocV68Lb.js.map} +1 -1
- package/bizar-dash/dist/assets/{DialogsView-DHYF8dE1.js → DialogsView-BVjPI5x7.js} +1 -1
- package/bizar-dash/dist/assets/{DialogsView-DHYF8dE1.js.map → DialogsView-BVjPI5x7.js.map} +1 -1
- package/bizar-dash/dist/assets/{DoctorView-DDLHrSKk.js → DoctorView-84gJcZwM.js} +1 -1
- package/bizar-dash/dist/assets/{DoctorView-DDLHrSKk.js.map → DoctorView-84gJcZwM.js.map} +1 -1
- package/bizar-dash/dist/assets/{EmptyState-DZ2ouKwd.js → EmptyState-BjgVOrcO.js} +1 -1
- package/bizar-dash/dist/assets/{EmptyState-DZ2ouKwd.js.map → EmptyState-BjgVOrcO.js.map} +1 -1
- package/bizar-dash/dist/assets/{EnvVarsView-D1cx83mB.js → EnvVarsView-BJ2TEzF7.js} +1 -1
- package/bizar-dash/dist/assets/{EnvVarsView-D1cx83mB.js.map → EnvVarsView-BJ2TEzF7.js.map} +1 -1
- package/bizar-dash/dist/assets/{ErrorState-DwwJ2-Jq.js → ErrorState-BE3WBFqF.js} +1 -1
- package/bizar-dash/dist/assets/{ErrorState-DwwJ2-Jq.js.map → ErrorState-BE3WBFqF.js.map} +1 -1
- package/bizar-dash/dist/assets/{EvalView-C9aYixXW.js → EvalView-BJJ2P-kK.js} +1 -1
- package/bizar-dash/dist/assets/{EvalView-C9aYixXW.js.map → EvalView-BJJ2P-kK.js.map} +1 -1
- package/bizar-dash/dist/assets/{GoalsView-DZa_mGmh.js → GoalsView-pwROHApi.js} +1 -1
- package/bizar-dash/dist/assets/{GoalsView-DZa_mGmh.js.map → GoalsView-pwROHApi.js.map} +1 -1
- package/bizar-dash/dist/assets/{Grid-CiRyhAgR.js → Grid-qcvbhx6e.js} +1 -1
- package/bizar-dash/dist/assets/{Grid-CiRyhAgR.js.map → Grid-qcvbhx6e.js.map} +1 -1
- package/bizar-dash/dist/assets/{HeadroomView-CNc-TI7u.js → HeadroomView-D1UiTYbt.js} +1 -1
- package/bizar-dash/dist/assets/{HeadroomView-CNc-TI7u.js.map → HeadroomView-D1UiTYbt.js.map} +1 -1
- package/bizar-dash/dist/assets/{HistoryView-Dv7aPxJE.js → HistoryView-C7SSOLJA.js} +1 -1
- package/bizar-dash/dist/assets/{HistoryView-Dv7aPxJE.js.map → HistoryView-C7SSOLJA.js.map} +1 -1
- package/bizar-dash/dist/assets/{Input-BbFUDQnS.js → Input-Bgzxf_Hu.js} +1 -1
- package/bizar-dash/dist/assets/{Input-BbFUDQnS.js.map → Input-Bgzxf_Hu.js.map} +1 -1
- package/bizar-dash/dist/assets/{LibrariesView-DBQ83TNa.js → LibrariesView-CbFFksox.js} +1 -1
- package/bizar-dash/dist/assets/{LibrariesView-DBQ83TNa.js.map → LibrariesView-CbFFksox.js.map} +1 -1
- package/bizar-dash/dist/assets/{LightRAGView-JYpE5u9p.js → LightRAGView-BqDrJbRq.js} +1 -1
- package/bizar-dash/dist/assets/{LightRAGView-JYpE5u9p.js.map → LightRAGView-BqDrJbRq.js.map} +1 -1
- package/bizar-dash/dist/assets/{ListHeader-BGjm11Z0.js → ListHeader-TjPJrUfY.js} +1 -1
- package/bizar-dash/dist/assets/{ListHeader-BGjm11Z0.js.map → ListHeader-TjPJrUfY.js.map} +1 -1
- package/bizar-dash/dist/assets/{MemoryView-CnOP2MvM.js → MemoryView-BlTeHLhX.js} +1 -1
- package/bizar-dash/dist/assets/{MemoryView-CnOP2MvM.js.map → MemoryView-BlTeHLhX.js.map} +1 -1
- package/bizar-dash/dist/assets/{MiscView-BBcpUbZZ.js → MiscView-B8QY82Pm.js} +1 -1
- package/bizar-dash/dist/assets/{MiscView-BBcpUbZZ.js.map → MiscView-B8QY82Pm.js.map} +1 -1
- package/bizar-dash/dist/assets/{ModsView-CU4cAmIz.js → ModsView-CvW1OWts.js} +1 -1
- package/bizar-dash/dist/assets/{ModsView-CU4cAmIz.js.map → ModsView-CvW1OWts.js.map} +1 -1
- package/bizar-dash/dist/assets/{NotificationsView-BYffvthq.js → NotificationsView-CsBt5U7x.js} +1 -1
- package/bizar-dash/dist/assets/{NotificationsView-BYffvthq.js.map → NotificationsView-CsBt5U7x.js.map} +1 -1
- package/bizar-dash/dist/assets/{ObsidianView-D3bI0row.js → ObsidianView-BCTejEj2.js} +1 -1
- package/bizar-dash/dist/assets/{ObsidianView-D3bI0row.js.map → ObsidianView-BCTejEj2.js.map} +1 -1
- package/bizar-dash/dist/assets/{OverviewView-0tq8f-Y0.js → OverviewView-BsuPxwnB.js} +1 -1
- package/bizar-dash/dist/assets/{OverviewView-0tq8f-Y0.js.map → OverviewView-BsuPxwnB.js.map} +1 -1
- package/bizar-dash/dist/assets/{ProgressBar-B-h60LKA.js → ProgressBar-DlZTETEn.js} +1 -1
- package/bizar-dash/dist/assets/{ProgressBar-B-h60LKA.js.map → ProgressBar-DlZTETEn.js.map} +1 -1
- package/bizar-dash/dist/assets/{ProjectsView-DhX5lzHS.js → ProjectsView-Soxtmpet.js} +1 -1
- package/bizar-dash/dist/assets/{ProjectsView-DhX5lzHS.js.map → ProjectsView-Soxtmpet.js.map} +1 -1
- package/bizar-dash/dist/assets/{ProvidersView-CJMX7jm9.js → ProvidersView-DaCEV9pM.js} +1 -1
- package/bizar-dash/dist/assets/{ProvidersView-CJMX7jm9.js.map → ProvidersView-DaCEV9pM.js.map} +1 -1
- package/bizar-dash/dist/assets/{SchedulesView-CcwDQ9Nm.js → SchedulesView-DY2ByBj_.js} +1 -1
- package/bizar-dash/dist/assets/{SchedulesView-CcwDQ9Nm.js.map → SchedulesView-DY2ByBj_.js.map} +1 -1
- package/bizar-dash/dist/assets/{Select-Cw7Qtz2M.js → Select-Dbd88_n8.js} +1 -1
- package/bizar-dash/dist/assets/{Select-Cw7Qtz2M.js.map → Select-Dbd88_n8.js.map} +1 -1
- package/bizar-dash/dist/assets/{SettingsRow-DgsgbPSI.js → SettingsRow-CLMNd434.js} +1 -1
- package/bizar-dash/dist/assets/{SettingsRow-DgsgbPSI.js.map → SettingsRow-CLMNd434.js.map} +1 -1
- package/bizar-dash/dist/assets/{SettingsView-DTAFdKyK.js → SettingsView-b24oFq9x.js} +1 -1
- package/bizar-dash/dist/assets/{SettingsView-DTAFdKyK.js.map → SettingsView-b24oFq9x.js.map} +1 -1
- package/bizar-dash/dist/assets/{Sheet-DH-WNJ3Y.js → Sheet-DnDid58j.js} +1 -1
- package/bizar-dash/dist/assets/{Sheet-DH-WNJ3Y.js.map → Sheet-DnDid58j.js.map} +1 -1
- package/bizar-dash/dist/assets/{Slider-DXbJuQ7y.js → Slider-BJCvKI1I.js} +1 -1
- package/bizar-dash/dist/assets/{Slider-DXbJuQ7y.js.map → Slider-BJCvKI1I.js.map} +1 -1
- package/bizar-dash/dist/assets/{Sparkline-CYtAn82j.js → Sparkline-ktqQLdyb.js} +1 -1
- package/bizar-dash/dist/assets/{Sparkline-CYtAn82j.js.map → Sparkline-ktqQLdyb.js.map} +1 -1
- package/bizar-dash/dist/assets/{Switch-BItGrPqr.js → Switch-CwXfsDii.js} +1 -1
- package/bizar-dash/dist/assets/{Switch-BItGrPqr.js.map → Switch-CwXfsDii.js.map} +1 -1
- package/bizar-dash/dist/assets/{TasksView-i5tm6CkX.js → TasksView-BHmpzFCf.js} +1 -1
- package/bizar-dash/dist/assets/{TasksView-i5tm6CkX.js.map → TasksView-BHmpzFCf.js.map} +1 -1
- package/bizar-dash/dist/assets/{Textarea-qYDf3yds.js → Textarea-BzIAwSlp.js} +1 -1
- package/bizar-dash/dist/assets/{Textarea-qYDf3yds.js.map → Textarea-BzIAwSlp.js.map} +1 -1
- package/bizar-dash/dist/assets/{UpdateView-Xln-ej26.js → UpdateView-CSmX9NN0.js} +1 -1
- package/bizar-dash/dist/assets/{UpdateView-Xln-ej26.js.map → UpdateView-CSmX9NN0.js.map} +1 -1
- package/bizar-dash/dist/assets/{UsageView-BGuZSUZ6.js → UsageView-COyr_Gfi.js} +1 -1
- package/bizar-dash/dist/assets/{UsageView-BGuZSUZ6.js.map → UsageView-COyr_Gfi.js.map} +1 -1
- package/bizar-dash/dist/assets/{ViewHeader-BqIPVKuG.js → ViewHeader-BzYZ3m-e.js} +1 -1
- package/bizar-dash/dist/assets/{ViewHeader-BqIPVKuG.js.map → ViewHeader-BzYZ3m-e.js.map} +1 -1
- package/bizar-dash/dist/assets/{VoiceView-CWUOCQs_.js → VoiceView-D33_xG5t.js} +1 -1
- package/bizar-dash/dist/assets/{VoiceView-CWUOCQs_.js.map → VoiceView-D33_xG5t.js.map} +1 -1
- package/bizar-dash/dist/assets/{brain-fsBSDl2g.js → brain-CM-Vls8r.js} +1 -1
- package/bizar-dash/dist/assets/{brain-fsBSDl2g.js.map → brain-CM-Vls8r.js.map} +1 -1
- package/bizar-dash/dist/assets/{calendar-DsHTZoCU.js → calendar-C0lgZk69.js} +1 -1
- package/bizar-dash/dist/assets/{calendar-DsHTZoCU.js.map → calendar-C0lgZk69.js.map} +1 -1
- package/bizar-dash/dist/assets/{circle-CqSxqqeJ.js → circle-Bx_hQEBC.js} +1 -1
- package/bizar-dash/dist/assets/{circle-CqSxqqeJ.js.map → circle-Bx_hQEBC.js.map} +1 -1
- package/bizar-dash/dist/assets/{circle-alert-BsLl001l.js → circle-alert-DHvsqpw5.js} +1 -1
- package/bizar-dash/dist/assets/{circle-alert-BsLl001l.js.map → circle-alert-DHvsqpw5.js.map} +1 -1
- package/bizar-dash/dist/assets/{circle-check-rVKMQmZp.js → circle-check-Bx8wmXR9.js} +1 -1
- package/bizar-dash/dist/assets/{circle-check-rVKMQmZp.js.map → circle-check-Bx8wmXR9.js.map} +1 -1
- package/bizar-dash/dist/assets/{clock-OuficfgH.js → clock-CejGoecX.js} +1 -1
- package/bizar-dash/dist/assets/{clock-OuficfgH.js.map → clock-CejGoecX.js.map} +1 -1
- package/bizar-dash/dist/assets/{download-BdHlstUY.js → download-4cEUWue1.js} +1 -1
- package/bizar-dash/dist/assets/{download-BdHlstUY.js.map → download-4cEUWue1.js.map} +1 -1
- package/bizar-dash/dist/assets/{external-link-DA3_VGm-.js → external-link-0NqUhI4i.js} +1 -1
- package/bizar-dash/dist/assets/{external-link-DA3_VGm-.js.map → external-link-0NqUhI4i.js.map} +1 -1
- package/bizar-dash/dist/assets/{file-text-B-g8H227.js → file-text-yEMkrSoZ.js} +1 -1
- package/bizar-dash/dist/assets/{file-text-B-g8H227.js.map → file-text-yEMkrSoZ.js.map} +1 -1
- package/bizar-dash/dist/assets/{filter-D9B8s5CG.js → filter-BXt60zAS.js} +1 -1
- package/bizar-dash/dist/assets/{filter-D9B8s5CG.js.map → filter-BXt60zAS.js.map} +1 -1
- package/bizar-dash/dist/assets/{git-pull-request-ByH0YuVz.js → git-pull-request-BjG5lNtR.js} +1 -1
- package/bizar-dash/dist/assets/{git-pull-request-ByH0YuVz.js.map → git-pull-request-BjG5lNtR.js.map} +1 -1
- package/bizar-dash/dist/assets/{main-CdOm1Pj9.js → main-CokHAXWM.js} +2 -2
- package/bizar-dash/dist/assets/{main-CdOm1Pj9.js.map → main-CokHAXWM.js.map} +1 -1
- package/bizar-dash/dist/assets/{pause-C9hgd8wX.js → pause-CAmulU0F.js} +1 -1
- package/bizar-dash/dist/assets/{pause-C9hgd8wX.js.map → pause-CAmulU0F.js.map} +1 -1
- package/bizar-dash/dist/assets/{pencil-BanqaMw7.js → pencil-eq5IqBmU.js} +1 -1
- package/bizar-dash/dist/assets/{pencil-BanqaMw7.js.map → pencil-eq5IqBmU.js.map} +1 -1
- package/bizar-dash/dist/assets/{play-CawUZ02_.js → play-BoLrrcBA.js} +1 -1
- package/bizar-dash/dist/assets/{play-CawUZ02_.js.map → play-BoLrrcBA.js.map} +1 -1
- package/bizar-dash/dist/assets/{plug-Cmv0-T_e.js → plug-DBrVM9lK.js} +1 -1
- package/bizar-dash/dist/assets/{plug-Cmv0-T_e.js.map → plug-DBrVM9lK.js.map} +1 -1
- package/bizar-dash/dist/assets/{plus-M6LYiKX8.js → plus-DENm0hqV.js} +1 -1
- package/bizar-dash/dist/assets/{plus-M6LYiKX8.js.map → plus-DENm0hqV.js.map} +1 -1
- package/bizar-dash/dist/assets/{power-DP5x_SRF.js → power-DLjXF7zE.js} +1 -1
- package/bizar-dash/dist/assets/{power-DP5x_SRF.js.map → power-DLjXF7zE.js.map} +1 -1
- package/bizar-dash/dist/assets/{power-off-NOJRLAIs.js → power-off-D47cOnG_.js} +1 -1
- package/bizar-dash/dist/assets/{power-off-NOJRLAIs.js.map → power-off-D47cOnG_.js.map} +1 -1
- package/bizar-dash/dist/assets/{refresh-ccw-CHMprsm5.js → refresh-ccw-DNrXX9gB.js} +1 -1
- package/bizar-dash/dist/assets/{refresh-ccw-CHMprsm5.js.map → refresh-ccw-DNrXX9gB.js.map} +1 -1
- package/bizar-dash/dist/assets/{refresh-cw-1RBqDKgJ.js → refresh-cw-CoAHDpeS.js} +1 -1
- package/bizar-dash/dist/assets/{refresh-cw-1RBqDKgJ.js.map → refresh-cw-CoAHDpeS.js.map} +1 -1
- package/bizar-dash/dist/assets/{rotate-ccw-DJRekBbi.js → rotate-ccw-ObX5awaG.js} +1 -1
- package/bizar-dash/dist/assets/{rotate-ccw-DJRekBbi.js.map → rotate-ccw-ObX5awaG.js.map} +1 -1
- package/bizar-dash/dist/assets/{rotate-cw-DHooc0Tx.js → rotate-cw-xpPJw9LP.js} +1 -1
- package/bizar-dash/dist/assets/{rotate-cw-DHooc0Tx.js.map → rotate-cw-xpPJw9LP.js.map} +1 -1
- package/bizar-dash/dist/assets/{save-DQKCKyZK.js → save-D1iKiJJl.js} +1 -1
- package/bizar-dash/dist/assets/{save-DQKCKyZK.js.map → save-D1iKiJJl.js.map} +1 -1
- package/bizar-dash/dist/assets/{send-xgy3RAi7.js → send-BRcAhZUm.js} +1 -1
- package/bizar-dash/dist/assets/{send-xgy3RAi7.js.map → send-BRcAhZUm.js.map} +1 -1
- package/bizar-dash/dist/assets/{shield-alert-CWV2F5ab.js → shield-alert-C6vEcK-g.js} +1 -1
- package/bizar-dash/dist/assets/{shield-alert-CWV2F5ab.js.map → shield-alert-C6vEcK-g.js.map} +1 -1
- package/bizar-dash/dist/assets/{trash-2-CL4khSRv.js → trash-2-DZDjEnNh.js} +1 -1
- package/bizar-dash/dist/assets/{trash-2-CL4khSRv.js.map → trash-2-DZDjEnNh.js.map} +1 -1
- package/bizar-dash/dist/assets/{trending-up-CSJJhWTS.js → trending-up-DMj-AJVf.js} +1 -1
- package/bizar-dash/dist/assets/{trending-up-CSJJhWTS.js.map → trending-up-DMj-AJVf.js.map} +1 -1
- package/bizar-dash/dist/assets/{triangle-alert-BPLb7uLt.js → triangle-alert-_2xe_tl4.js} +1 -1
- package/bizar-dash/dist/assets/{triangle-alert-BPLb7uLt.js.map → triangle-alert-_2xe_tl4.js.map} +1 -1
- package/bizar-dash/dist/assets/{upload-Cww6MvFq.js → upload-DdDljAeV.js} +1 -1
- package/bizar-dash/dist/assets/{upload-Cww6MvFq.js.map → upload-DdDljAeV.js.map} +1 -1
- package/bizar-dash/dist/assets/{zap-DmhVUzRA.js → zap-mHsgh0FP.js} +1 -1
- package/bizar-dash/dist/assets/{zap-DmhVUzRA.js.map → zap-mHsgh0FP.js.map} +1 -1
- package/bizar-dash/dist/index.html +1 -1
- package/bizar-dash/skills/headroom/SKILL.md +94 -0
- package/bizar-dash/src/server/api.mjs +11 -0
- package/bizar-dash/src/server/artifacts-store.mjs +120 -14
- package/bizar-dash/src/server/claude-artifacts.mjs +281 -0
- package/bizar-dash/src/server/headroom.mjs +649 -0
- package/bizar-dash/src/server/routes/artifacts.mjs +42 -6
- package/bizar-dash/src/server/routes/audit.mjs +78 -0
- package/bizar-dash/src/server/routes/decisions.mjs +78 -0
- package/bizar-dash/src/server/routes/headroom.mjs +126 -0
- package/bizar-dash/src/server/routes/model-router.mjs +55 -0
- package/bizar-dash/src/server/routes/model-router.test.mjs +28 -0
- package/bizar-dash/src/server/routes/sessions.mjs +80 -0
- package/bizar-dash/src/server/sprint.test.mjs +163 -0
- package/bizar-dash/src/web/v8/views/Artifacts/ArtifactsView.tsx +232 -21
- package/bizar-dash/src/web/v8/views/Artifacts/ClaudeArtifactView.tsx +179 -0
- package/bizar-dash/tests/headroom-install.test.mjs +173 -0
- package/bizar-dash/tests/headroom-settings.test.mjs +126 -0
- package/bizar-dash/tests/headroom-status.test.mjs +117 -0
- package/cli/commands/headroom.mjs +204 -0
- package/package.json +1 -1
- package/packages/sdk/dist/agent/cron.d.ts +44 -0
- package/packages/sdk/dist/agent/cron.js +79 -0
- package/packages/sdk/dist/agent/heartbeat.d.ts +43 -0
- package/packages/sdk/dist/agent/heartbeat.js +116 -0
- package/packages/sdk/dist/index.d.ts +3 -0
- package/packages/sdk/dist/index.js +5 -0
- package/packages/sdk/dist/learning/decisions.d.ts +46 -0
- package/packages/sdk/dist/learning/decisions.js +132 -0
- package/packages/sdk/dist/learning/index.d.ts +8 -0
- package/packages/sdk/dist/learning/index.js +8 -0
- package/packages/sdk/dist/learning/instincts.d.ts +38 -0
- package/packages/sdk/dist/learning/instincts.js +139 -0
- package/packages/sdk/dist/mcp/server.js +119 -1
- package/packages/sdk/dist/router/agent-model-registry.d.ts +89 -0
- package/packages/sdk/dist/router/agent-model-registry.js +144 -0
- package/packages/sdk/dist/router/index.d.ts +1 -0
- package/packages/sdk/dist/router/index.js +1 -0
- package/packages/sdk/package.json +3 -2
- package/scripts/audit.mjs +388 -0
- package/scripts/audit.test.mjs +149 -0
- package/scripts/eval-gate.mjs +134 -0
- package/scripts/eval-gate.test.mjs +138 -0
- package/scripts/feature-state-machine.mjs +178 -0
- package/scripts/feature-state-machine.test.mjs +135 -0
- package/scripts/spec-dedup.test.mjs +124 -0
- package/scripts/sprint.mjs +213 -0
- package/scripts/worktree-setup.sh +79 -0
- package/bizar-dash/dist/assets/ArtifactsView-CDIhPBAx.js +0 -6
- package/bizar-dash/dist/assets/ArtifactsView-CDIhPBAx.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DialogsView-DHYF8dE1.js","sources":["../../../node_modules/lucide-react/dist/esm/icons/skip-forward.js","../../src/web/v8/views/Dialogs/DialogsView.tsx"],"sourcesContent":["/**\n * @license lucide-react v0.460.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst SkipForward = createLucideIcon(\"SkipForward\", [\n [\"polygon\", { points: \"5 4 15 12 5 20 5 4\", key: \"16p6eg\" }],\n [\"line\", { x1: \"19\", x2: \"19\", y1: \"5\", y2: \"19\", key: \"futhcm\" }]\n]);\n\nexport { SkipForward as default };\n//# sourceMappingURL=skip-forward.js.map\n","/**\n * v8/views/Dialogs/DialogsView.tsx — Sprint S42, v9.3.0.\n *\n * Active dialog queue pulled from /api/dialogs. Per-row: view kind,\n * title, body preview, source, age, inline-confirm Dismiss (DELETE\n * /api/dialogs/:id). Empty state + manual Refresh button. No\n * window.confirm.\n */\n\nimport { useCallback, useMemo, useState } from 'react';\nimport { Check, MessageSquare, RefreshCcw, SkipForward, Trash2, X } from 'lucide-react';\nimport { Stack } from '../../ui/primitives/Stack.js';\nimport { Inline } from '../../ui/primitives/Inline.js';\nimport { ViewHeader } from '../../ui/data/ViewHeader.js';\nimport { ListHeader } from '../../ui/data/ListHeader.js';\nimport { Card, CardBody } from '../../ui/data/Card.js';\nimport { Button } from '../../ui/controls/Button.js';\nimport { Skeleton } from '../../ui/feedback/Skeleton.js';\nimport { EmptyState } from '../../ui/feedback/EmptyState.js';\nimport { ErrorState } from '../../ui/feedback/ErrorState.js';\nimport { useFetch } from '../../data/useFetch.js';\nimport { useWsMessage } from '../../data/useWebSocket.js';\nimport { fetchJson, FetchError } from '../../data/fetcher.js';\n\ninterface DialogItem {\n id: string;\n kind?: string;\n title?: string;\n body?: string;\n source?: string;\n createdAt?: number | string;\n}\n\nexport function DialogsView(): JSX.Element {\n const payload = useFetch<{ dialogs: DialogItem[] }>('/api/dialogs');\n const [confirmDelete, setConfirmDelete] = useState<string | null>(null);\n const [error, setError] = useState<string | null>(null);\n\n const refresh = useCallback(() => { void payload.refetch(); }, [payload]);\n\n // Live: server broadcasts `dialog:show` on enqueue. Refresh on it.\n useWsMessage('dialog:show', () => { refresh(); });\n\n const drop = async (id: string): Promise<void> => {\n setError(null);\n try {\n await fetchJson(`/api/dialogs/${id}`, { method: 'DELETE' });\n setConfirmDelete(null);\n refresh();\n } catch (err) {\n setError(err instanceof FetchError ? err.message : (err as Error).message);\n }\n };\n\n const decide = async (id: string, verdict: 'approve' | 'deny' | 'skip'): Promise<void> => {\n setError(null);\n try {\n await fetchJson(`/api/dialogs/${id}/${verdict}`, { method: 'POST', body: {} });\n refresh();\n } catch (err) {\n setError(err instanceof FetchError ? err.message : (err as Error).message);\n }\n };\n\n const dialogs = useMemo<DialogItem[]>(() => payload.data?.dialogs ?? [], [payload.data]);\n\n return (\n <Stack gap={4} data-testid=\"dialogs-view\">\n <ViewHeader\n title=\"Dialogs\"\n description=\"Active dialog queue (debug + manual dismiss).\"\n actions={\n <Inline gap={1}>\n {error !== null && (\n <span role=\"alert\" data-testid=\"dialogs-error\" style={{ color: 'var(--danger)', fontSize: 'var(--fs-12)' }}>\n {error}\n </span>\n )}\n <Button variant=\"ghost\" onClick={() => void refresh()} data-testid=\"dialogs-refresh\">\n <RefreshCcw size={14} aria-hidden /> Refresh\n </Button>\n </Inline>\n }\n />\n <ListHeader title=\"Queue\" count={dialogs.length} testid=\"dialogs-list-header\" />\n <Card variant=\"default\">\n <CardBody>\n {payload.loading && dialogs.length === 0 ? (\n <Stack gap={1}>\n <Skeleton style={{ height: 32 }} />\n <Skeleton style={{ height: 32 }} />\n </Stack>\n ) : payload.error && dialogs.length === 0 ? (\n <ErrorState\n block\n title=\"Couldn't load dialogs\"\n description=\"The dialog queue failed to fetch. Retry to refetch.\"\n error={payload.error}\n onRetry={refresh}\n testid=\"dialogs-error-state\"\n />\n ) : dialogs.length === 0 ? (\n <EmptyState\n icon={<MessageSquare size={28} aria-hidden />}\n title=\"No active dialogs\"\n description=\"Dialogs enqueued via the slash-command plugin will appear here.\"\n />\n ) : (\n <Stack gap={1}>\n {dialogs.map((d) => {\n const isConfirming = confirmDelete === d.id;\n return (\n <div\n key={d.id}\n data-testid={`dialog-row-${d.id}`}\n style={{\n padding: 'var(--space-2)',\n border: '1px solid var(--border)',\n borderRadius: 'var(--radius-sm)',\n background: 'var(--surface-0)',\n }}\n >\n <Inline align=\"center\" justify=\"between\" gap={2}>\n <Stack gap={0} style={{ minWidth: 0 }}>\n <Inline align=\"center\" gap={2}>\n <strong style={{ fontSize: 'var(--fs-13)' }}>{d.title || d.id}</strong>\n {d.kind && (\n <span style={{ fontSize: 'var(--fs-11)', color: 'var(--fg-subtle)', fontFamily: 'var(--font-mono)' }}>\n {d.kind}\n </span>\n )}\n {d.source && (\n <span style={{ fontSize: 'var(--fs-11)', color: 'var(--fg-muted)' }}>\n · {d.source}\n </span>\n )}\n </Inline>\n {d.body && (\n <span style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>\n {d.body.length > 160 ? `${d.body.slice(0, 160)}…` : d.body}\n </span>\n )}\n </Stack>\n <Inline gap={1}>\n <Button\n variant=\"primary\"\n onClick={() => void decide(d.id, 'approve')}\n data-testid={`dialog-approve-${d.id}`}\n aria-label={`Approve ${d.id}`}\n >\n <Check size={14} aria-hidden /> Approve\n </Button>\n <Button\n variant=\"ghost\"\n onClick={() => void decide(d.id, 'skip')}\n data-testid={`dialog-skip-${d.id}`}\n aria-label={`Skip ${d.id}`}\n >\n <SkipForward size={14} aria-hidden /> Skip\n </Button>\n <Button\n variant=\"ghost\"\n onClick={() => void decide(d.id, 'deny')}\n data-testid={`dialog-deny-${d.id}`}\n aria-label={`Deny ${d.id}`}\n >\n <X size={14} aria-hidden /> Deny\n </Button>\n <Button\n variant=\"ghost\"\n onClick={() => setConfirmDelete((cur) => (cur === d.id ? null : d.id))}\n data-testid={`dialog-dismiss-${d.id}`}\n aria-label={`Dismiss ${d.id}`}\n >\n <Trash2 size={14} aria-hidden />\n </Button>\n </Inline>\n </Inline>\n {isConfirming && (\n <Inline gap={1} style={{ marginTop: 'var(--space-1)' }}>\n <Button variant=\"danger\" onClick={() => void drop(d.id)} data-testid={`dialog-confirm-dismiss-${d.id}`}>\n <Trash2 size={14} aria-hidden /> Confirm\n </Button>\n <Button variant=\"ghost\" onClick={() => setConfirmDelete(null)}>Cancel</Button>\n </Inline>\n )}\n </div>\n );\n })}\n </Stack>\n )}\n </CardBody>\n </Card>\n </Stack>\n );\n}"],"names":["SkipForward","createLucideIcon","DialogsView","payload","useFetch","confirmDelete","setConfirmDelete","useState","error","setError","refresh","useCallback","useWsMessage","drop","id","fetchJson","err","FetchError","decide","verdict","dialogs","useMemo","_a","jsxs","Stack","jsx","ViewHeader","Inline","Button","RefreshCcw","ListHeader","Card","CardBody","Skeleton","ErrorState","EmptyState","MessageSquare","d","isConfirming","Check","X","cur","Trash2"],"mappings":"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","x_google_ignoreList":[0]}
|
|
1
|
+
{"version":3,"file":"DialogsView-BVjPI5x7.js","sources":["../../../node_modules/lucide-react/dist/esm/icons/skip-forward.js","../../src/web/v8/views/Dialogs/DialogsView.tsx"],"sourcesContent":["/**\n * @license lucide-react v0.460.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst SkipForward = createLucideIcon(\"SkipForward\", [\n [\"polygon\", { points: \"5 4 15 12 5 20 5 4\", key: \"16p6eg\" }],\n [\"line\", { x1: \"19\", x2: \"19\", y1: \"5\", y2: \"19\", key: \"futhcm\" }]\n]);\n\nexport { SkipForward as default };\n//# sourceMappingURL=skip-forward.js.map\n","/**\n * v8/views/Dialogs/DialogsView.tsx — Sprint S42, v9.3.0.\n *\n * Active dialog queue pulled from /api/dialogs. Per-row: view kind,\n * title, body preview, source, age, inline-confirm Dismiss (DELETE\n * /api/dialogs/:id). Empty state + manual Refresh button. No\n * window.confirm.\n */\n\nimport { useCallback, useMemo, useState } from 'react';\nimport { Check, MessageSquare, RefreshCcw, SkipForward, Trash2, X } from 'lucide-react';\nimport { Stack } from '../../ui/primitives/Stack.js';\nimport { Inline } from '../../ui/primitives/Inline.js';\nimport { ViewHeader } from '../../ui/data/ViewHeader.js';\nimport { ListHeader } from '../../ui/data/ListHeader.js';\nimport { Card, CardBody } from '../../ui/data/Card.js';\nimport { Button } from '../../ui/controls/Button.js';\nimport { Skeleton } from '../../ui/feedback/Skeleton.js';\nimport { EmptyState } from '../../ui/feedback/EmptyState.js';\nimport { ErrorState } from '../../ui/feedback/ErrorState.js';\nimport { useFetch } from '../../data/useFetch.js';\nimport { useWsMessage } from '../../data/useWebSocket.js';\nimport { fetchJson, FetchError } from '../../data/fetcher.js';\n\ninterface DialogItem {\n id: string;\n kind?: string;\n title?: string;\n body?: string;\n source?: string;\n createdAt?: number | string;\n}\n\nexport function DialogsView(): JSX.Element {\n const payload = useFetch<{ dialogs: DialogItem[] }>('/api/dialogs');\n const [confirmDelete, setConfirmDelete] = useState<string | null>(null);\n const [error, setError] = useState<string | null>(null);\n\n const refresh = useCallback(() => { void payload.refetch(); }, [payload]);\n\n // Live: server broadcasts `dialog:show` on enqueue. Refresh on it.\n useWsMessage('dialog:show', () => { refresh(); });\n\n const drop = async (id: string): Promise<void> => {\n setError(null);\n try {\n await fetchJson(`/api/dialogs/${id}`, { method: 'DELETE' });\n setConfirmDelete(null);\n refresh();\n } catch (err) {\n setError(err instanceof FetchError ? err.message : (err as Error).message);\n }\n };\n\n const decide = async (id: string, verdict: 'approve' | 'deny' | 'skip'): Promise<void> => {\n setError(null);\n try {\n await fetchJson(`/api/dialogs/${id}/${verdict}`, { method: 'POST', body: {} });\n refresh();\n } catch (err) {\n setError(err instanceof FetchError ? err.message : (err as Error).message);\n }\n };\n\n const dialogs = useMemo<DialogItem[]>(() => payload.data?.dialogs ?? [], [payload.data]);\n\n return (\n <Stack gap={4} data-testid=\"dialogs-view\">\n <ViewHeader\n title=\"Dialogs\"\n description=\"Active dialog queue (debug + manual dismiss).\"\n actions={\n <Inline gap={1}>\n {error !== null && (\n <span role=\"alert\" data-testid=\"dialogs-error\" style={{ color: 'var(--danger)', fontSize: 'var(--fs-12)' }}>\n {error}\n </span>\n )}\n <Button variant=\"ghost\" onClick={() => void refresh()} data-testid=\"dialogs-refresh\">\n <RefreshCcw size={14} aria-hidden /> Refresh\n </Button>\n </Inline>\n }\n />\n <ListHeader title=\"Queue\" count={dialogs.length} testid=\"dialogs-list-header\" />\n <Card variant=\"default\">\n <CardBody>\n {payload.loading && dialogs.length === 0 ? (\n <Stack gap={1}>\n <Skeleton style={{ height: 32 }} />\n <Skeleton style={{ height: 32 }} />\n </Stack>\n ) : payload.error && dialogs.length === 0 ? (\n <ErrorState\n block\n title=\"Couldn't load dialogs\"\n description=\"The dialog queue failed to fetch. Retry to refetch.\"\n error={payload.error}\n onRetry={refresh}\n testid=\"dialogs-error-state\"\n />\n ) : dialogs.length === 0 ? (\n <EmptyState\n icon={<MessageSquare size={28} aria-hidden />}\n title=\"No active dialogs\"\n description=\"Dialogs enqueued via the slash-command plugin will appear here.\"\n />\n ) : (\n <Stack gap={1}>\n {dialogs.map((d) => {\n const isConfirming = confirmDelete === d.id;\n return (\n <div\n key={d.id}\n data-testid={`dialog-row-${d.id}`}\n style={{\n padding: 'var(--space-2)',\n border: '1px solid var(--border)',\n borderRadius: 'var(--radius-sm)',\n background: 'var(--surface-0)',\n }}\n >\n <Inline align=\"center\" justify=\"between\" gap={2}>\n <Stack gap={0} style={{ minWidth: 0 }}>\n <Inline align=\"center\" gap={2}>\n <strong style={{ fontSize: 'var(--fs-13)' }}>{d.title || d.id}</strong>\n {d.kind && (\n <span style={{ fontSize: 'var(--fs-11)', color: 'var(--fg-subtle)', fontFamily: 'var(--font-mono)' }}>\n {d.kind}\n </span>\n )}\n {d.source && (\n <span style={{ fontSize: 'var(--fs-11)', color: 'var(--fg-muted)' }}>\n · {d.source}\n </span>\n )}\n </Inline>\n {d.body && (\n <span style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>\n {d.body.length > 160 ? `${d.body.slice(0, 160)}…` : d.body}\n </span>\n )}\n </Stack>\n <Inline gap={1}>\n <Button\n variant=\"primary\"\n onClick={() => void decide(d.id, 'approve')}\n data-testid={`dialog-approve-${d.id}`}\n aria-label={`Approve ${d.id}`}\n >\n <Check size={14} aria-hidden /> Approve\n </Button>\n <Button\n variant=\"ghost\"\n onClick={() => void decide(d.id, 'skip')}\n data-testid={`dialog-skip-${d.id}`}\n aria-label={`Skip ${d.id}`}\n >\n <SkipForward size={14} aria-hidden /> Skip\n </Button>\n <Button\n variant=\"ghost\"\n onClick={() => void decide(d.id, 'deny')}\n data-testid={`dialog-deny-${d.id}`}\n aria-label={`Deny ${d.id}`}\n >\n <X size={14} aria-hidden /> Deny\n </Button>\n <Button\n variant=\"ghost\"\n onClick={() => setConfirmDelete((cur) => (cur === d.id ? null : d.id))}\n data-testid={`dialog-dismiss-${d.id}`}\n aria-label={`Dismiss ${d.id}`}\n >\n <Trash2 size={14} aria-hidden />\n </Button>\n </Inline>\n </Inline>\n {isConfirming && (\n <Inline gap={1} style={{ marginTop: 'var(--space-1)' }}>\n <Button variant=\"danger\" onClick={() => void drop(d.id)} data-testid={`dialog-confirm-dismiss-${d.id}`}>\n <Trash2 size={14} aria-hidden /> Confirm\n </Button>\n <Button variant=\"ghost\" onClick={() => setConfirmDelete(null)}>Cancel</Button>\n </Inline>\n )}\n </div>\n );\n })}\n </Stack>\n )}\n </CardBody>\n </Card>\n </Stack>\n );\n}"],"names":["SkipForward","createLucideIcon","DialogsView","payload","useFetch","confirmDelete","setConfirmDelete","useState","error","setError","refresh","useCallback","useWsMessage","drop","id","fetchJson","err","FetchError","decide","verdict","dialogs","useMemo","_a","jsxs","Stack","jsx","ViewHeader","Inline","Button","RefreshCcw","ListHeader","Card","CardBody","Skeleton","ErrorState","EmptyState","MessageSquare","d","isConfirming","Check","X","cur","Trash2"],"mappings":"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","x_google_ignoreList":[0]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{r as d,j as e}from"./cmdk-DVxytz9i.js";import{c as C,u as m,S as i,I as c,d as x,h,H as z,B as E,J as T,G as w,i as R,F as I}from"./main-
|
|
1
|
+
import{r as d,j as e}from"./cmdk-DVxytz9i.js";import{c as C,u as m,S as i,I as c,d as x,h,H as z,B as E,J as T,G as w,i as R,F as I}from"./main-CokHAXWM.js";import{V as b}from"./ViewHeader-BzYZ3m-e.js";import{C as j,b as y}from"./Card-B0imhxMk.js";import{E as N}from"./EmptyState-BjgVOrcO.js";import{E as B}from"./ErrorState-BE3WBFqF.js";import{R as F}from"./refresh-cw-CoAHDpeS.js";import{T as H}from"./triangle-alert-_2xe_tl4.js";import{C as A}from"./circle-check-Bx8wmXR9.js";import"./Alert-CG5q_s75.js";import"./circle-alert-DHvsqpw5.js";import"./refresh-ccw-DNrXX9gB.js";/**
|
|
2
2
|
* @license lucide-react v0.460.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DoctorView-DDLHrSKk.js","sources":["../../../node_modules/lucide-react/dist/esm/icons/circle-x.js","../../src/web/v8/views/Doctor/DoctorView.tsx"],"sourcesContent":["/**\n * @license lucide-react v0.460.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst CircleX = createLucideIcon(\"CircleX\", [\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"10\", key: \"1mglay\" }],\n [\"path\", { d: \"m15 9-6 6\", key: \"1uzhvr\" }],\n [\"path\", { d: \"m9 9 6 6\", key: \"z0biqf\" }]\n]);\n\nexport { CircleX as default };\n//# sourceMappingURL=circle-x.js.map\n","import { useCallback, useEffect, useState } from 'react';\nimport { Stethoscope, RefreshCw, ShieldCheck, AlertTriangle, XCircle, CheckCircle2, Loader2 } from 'lucide-react';\nimport { Stack } from '../../ui/primitives/Stack.js';\nimport { Inline } from '../../ui/primitives/Inline.js';\nimport { ViewHeader } from '../../ui/data/ViewHeader.js';\nimport { Card, CardBody } from '../../ui/data/Card.js';\nimport { Badge } from '../../ui/data/Badge.js';\nimport { Button } from '../../ui/controls/Button.js';\nimport { Skeleton } from '../../ui/feedback/Skeleton.js';\nimport { EmptyState } from '../../ui/feedback/EmptyState.js';\nimport { ErrorState } from '../../ui/feedback/ErrorState.js';\nimport { useFetch } from '../../data/useFetch.js';\nimport { fetchJson, FetchError } from '../../data/fetcher.js';\nimport type { LucideIcon } from 'lucide-react';\n\n/**\n * DoctorView — Sprint S35. Health rollup + per-check triggers.\n */\n\ntype Status = 'ok' | 'warn' | 'fail';\n\ninterface CheckResult {\n name: string;\n status: Status;\n message: string;\n error?: string;\n}\n\ninterface CheckGroup {\n name?: string;\n status?: Status;\n message?: string;\n error?: string;\n}\n\ninterface HealthRollup {\n status: Status;\n issues: Array<{ name: string; status: Status; message: string }>;\n}\n\ninterface DoctorSnapshot {\n health: HealthRollup;\n checks: { system?: CheckGroup[]; config?: CheckGroup[]; services?: CheckGroup[] };\n recentErrors?: unknown[];\n}\n\nconst STATUS_ICON: Record<Status, LucideIcon> = {\n ok: CheckCircle2,\n warn: AlertTriangle,\n fail: XCircle,\n};\n\nconst STATUS_TONE = {\n ok: 'success',\n warn: 'warning',\n fail: 'danger',\n} as const;\n\nexport function DoctorView(): JSX.Element {\n const snap = useFetch<DoctorSnapshot>('/api/doctor');\n const health = useFetch<HealthRollup>('/api/doctor/health');\n const [running, setRunning] = useState<string | null>(null);\n const [error, setError] = useState<string | null>(null);\n\n // Re-poll health every 30s for a live rollup.\n useEffect(() => {\n const id = setInterval(() => { void health.refetch(); }, 30_000);\n return () => clearInterval(id);\n }, [health]);\n\n const runCheck = async (name: string): Promise<void> => {\n setRunning(name);\n setError(null);\n try {\n await fetchJson('/api/doctor/check', { method: 'POST', body: { checkName: name } });\n void snap.refetch();\n } catch (err) {\n setError(err instanceof FetchError ? err.message : (err as Error).message);\n } finally {\n setRunning(null);\n }\n };\n\n const rollup = health.data ?? snap.data?.health;\n const checks: CheckResult[] = (() => {\n const g = snap.data?.checks;\n if (!g) return [];\n return [...(g.system ?? []), ...(g.config ?? []), ...(g.services ?? [])]\n .filter((c): c is CheckResult =>\n typeof c.name === 'string' && typeof c.status === 'string' && typeof c.message === 'string'\n );\n })();\n\n return (\n <Stack gap={5} data-testid=\"doctor-view\">\n <ViewHeader\n title=\"Doctor\"\n description=\"System diagnostics. Health poll every 30s; click any check to re-run.\"\n actions={\n <Inline gap={2} align=\"center\">\n {error !== null && <span role=\"alert\" style={{ color: 'var(--danger)', fontSize: 'var(--fs-12)' }}>{error}</span>}\n <Button variant=\"ghost\" onClick={() => void snap.refetch()} data-testid=\"doctor-refresh\">\n <RefreshCw size={14} aria-hidden /> Refresh\n </Button>\n </Inline>\n }\n />\n\n {rollup ? (\n <Card variant=\"elevated\">\n <CardBody>\n <Inline align=\"center\" gap={3}>\n {(() => {\n const Icon = STATUS_ICON[rollup.status];\n return <Icon size={20} aria-hidden />;\n })()}\n <Stack gap={0}>\n <strong style={{ fontSize: 'var(--fs-14)' }}>Health: {rollup.status.toUpperCase()}</strong>\n <span style={{ color: 'var(--fg-muted)', fontSize: 'var(--fs-12)' }}>\n {rollup.issues.length === 0 ? 'No issues detected.' : `${rollup.issues.length} issue${rollup.issues.length === 1 ? '' : 's'}`}\n </span>\n </Stack>\n </Inline>\n </CardBody>\n </Card>\n ) : (\n <Skeleton style={{ height: 64 }} />\n )}\n\n {snap.loading && checks.length === 0 ? (\n <Stack gap={2}>\n <Skeleton style={{ height: 64 }} />\n <Skeleton style={{ height: 64 }} />\n </Stack>\n ) : snap.error && checks.length === 0 ? (\n <ErrorState\n block\n title=\"Couldn't run doctor\"\n description=\"The diagnostic snapshot failed. Retry to refetch.\"\n error={snap.error}\n onRetry={() => void snap.refetch()}\n testid=\"doctor-error\"\n />\n ) : checks.length === 0 ? (\n <EmptyState\n icon={<Stethoscope size={32} aria-hidden />}\n title=\"No checks yet\"\n description=\"The Doctor snapshot returned no checks.\"\n />\n ) : (\n <Stack gap={2}>\n {checks.map((c) => {\n const Icon = STATUS_ICON[c.status];\n const busy = running === c.name;\n return (\n <Card key={c.name} variant=\"default\">\n <CardBody>\n <Inline align=\"center\" justify=\"between\" gap={3}>\n <Stack gap={1} style={{ flex: 1, minWidth: 0 }}>\n <Inline align=\"center\" gap={2}>\n <Icon size={14} aria-hidden />\n <strong>{c.name}</strong>\n <Badge tone={STATUS_TONE[c.status]}>{c.status}</Badge>\n </Inline>\n <span style={{ color: 'var(--fg-muted)', fontSize: 'var(--fs-12)' }}>{c.message}</span>\n {c.error && <span style={{ color: 'var(--danger)', fontSize: 'var(--fs-12)', fontFamily: 'var(--font-mono)' }}>{c.error}</span>}\n </Stack>\n <Button variant=\"ghost\" onClick={() => void runCheck(c.name)} disabled={busy} data-testid={`doctor-run-${c.name}`}>\n {busy ? <Loader2 size={12} className=\"animate-spin\" aria-hidden /> : <ShieldCheck size={12} aria-hidden />}\n {busy ? 'Running…' : 'Re-run'}\n </Button>\n </Inline>\n </CardBody>\n </Card>\n );\n })}\n </Stack>\n )}\n </Stack>\n );\n}"],"names":["CircleX","createLucideIcon","STATUS_ICON","CheckCircle2","AlertTriangle","XCircle","STATUS_TONE","DoctorView","snap","useFetch","health","running","setRunning","useState","error","setError","useEffect","id","runCheck","name","fetchJson","err","FetchError","rollup","_a","checks","g","c","jsxs","Stack","jsx","ViewHeader","Inline","Button","RefreshCw","Card","CardBody","Icon","Skeleton","ErrorState","EmptyState","Stethoscope","busy","Badge","Loader2","ShieldCheck"],"mappings":"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","x_google_ignoreList":[0]}
|
|
1
|
+
{"version":3,"file":"DoctorView-84gJcZwM.js","sources":["../../../node_modules/lucide-react/dist/esm/icons/circle-x.js","../../src/web/v8/views/Doctor/DoctorView.tsx"],"sourcesContent":["/**\n * @license lucide-react v0.460.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst CircleX = createLucideIcon(\"CircleX\", [\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"10\", key: \"1mglay\" }],\n [\"path\", { d: \"m15 9-6 6\", key: \"1uzhvr\" }],\n [\"path\", { d: \"m9 9 6 6\", key: \"z0biqf\" }]\n]);\n\nexport { CircleX as default };\n//# sourceMappingURL=circle-x.js.map\n","import { useCallback, useEffect, useState } from 'react';\nimport { Stethoscope, RefreshCw, ShieldCheck, AlertTriangle, XCircle, CheckCircle2, Loader2 } from 'lucide-react';\nimport { Stack } from '../../ui/primitives/Stack.js';\nimport { Inline } from '../../ui/primitives/Inline.js';\nimport { ViewHeader } from '../../ui/data/ViewHeader.js';\nimport { Card, CardBody } from '../../ui/data/Card.js';\nimport { Badge } from '../../ui/data/Badge.js';\nimport { Button } from '../../ui/controls/Button.js';\nimport { Skeleton } from '../../ui/feedback/Skeleton.js';\nimport { EmptyState } from '../../ui/feedback/EmptyState.js';\nimport { ErrorState } from '../../ui/feedback/ErrorState.js';\nimport { useFetch } from '../../data/useFetch.js';\nimport { fetchJson, FetchError } from '../../data/fetcher.js';\nimport type { LucideIcon } from 'lucide-react';\n\n/**\n * DoctorView — Sprint S35. Health rollup + per-check triggers.\n */\n\ntype Status = 'ok' | 'warn' | 'fail';\n\ninterface CheckResult {\n name: string;\n status: Status;\n message: string;\n error?: string;\n}\n\ninterface CheckGroup {\n name?: string;\n status?: Status;\n message?: string;\n error?: string;\n}\n\ninterface HealthRollup {\n status: Status;\n issues: Array<{ name: string; status: Status; message: string }>;\n}\n\ninterface DoctorSnapshot {\n health: HealthRollup;\n checks: { system?: CheckGroup[]; config?: CheckGroup[]; services?: CheckGroup[] };\n recentErrors?: unknown[];\n}\n\nconst STATUS_ICON: Record<Status, LucideIcon> = {\n ok: CheckCircle2,\n warn: AlertTriangle,\n fail: XCircle,\n};\n\nconst STATUS_TONE = {\n ok: 'success',\n warn: 'warning',\n fail: 'danger',\n} as const;\n\nexport function DoctorView(): JSX.Element {\n const snap = useFetch<DoctorSnapshot>('/api/doctor');\n const health = useFetch<HealthRollup>('/api/doctor/health');\n const [running, setRunning] = useState<string | null>(null);\n const [error, setError] = useState<string | null>(null);\n\n // Re-poll health every 30s for a live rollup.\n useEffect(() => {\n const id = setInterval(() => { void health.refetch(); }, 30_000);\n return () => clearInterval(id);\n }, [health]);\n\n const runCheck = async (name: string): Promise<void> => {\n setRunning(name);\n setError(null);\n try {\n await fetchJson('/api/doctor/check', { method: 'POST', body: { checkName: name } });\n void snap.refetch();\n } catch (err) {\n setError(err instanceof FetchError ? err.message : (err as Error).message);\n } finally {\n setRunning(null);\n }\n };\n\n const rollup = health.data ?? snap.data?.health;\n const checks: CheckResult[] = (() => {\n const g = snap.data?.checks;\n if (!g) return [];\n return [...(g.system ?? []), ...(g.config ?? []), ...(g.services ?? [])]\n .filter((c): c is CheckResult =>\n typeof c.name === 'string' && typeof c.status === 'string' && typeof c.message === 'string'\n );\n })();\n\n return (\n <Stack gap={5} data-testid=\"doctor-view\">\n <ViewHeader\n title=\"Doctor\"\n description=\"System diagnostics. Health poll every 30s; click any check to re-run.\"\n actions={\n <Inline gap={2} align=\"center\">\n {error !== null && <span role=\"alert\" style={{ color: 'var(--danger)', fontSize: 'var(--fs-12)' }}>{error}</span>}\n <Button variant=\"ghost\" onClick={() => void snap.refetch()} data-testid=\"doctor-refresh\">\n <RefreshCw size={14} aria-hidden /> Refresh\n </Button>\n </Inline>\n }\n />\n\n {rollup ? (\n <Card variant=\"elevated\">\n <CardBody>\n <Inline align=\"center\" gap={3}>\n {(() => {\n const Icon = STATUS_ICON[rollup.status];\n return <Icon size={20} aria-hidden />;\n })()}\n <Stack gap={0}>\n <strong style={{ fontSize: 'var(--fs-14)' }}>Health: {rollup.status.toUpperCase()}</strong>\n <span style={{ color: 'var(--fg-muted)', fontSize: 'var(--fs-12)' }}>\n {rollup.issues.length === 0 ? 'No issues detected.' : `${rollup.issues.length} issue${rollup.issues.length === 1 ? '' : 's'}`}\n </span>\n </Stack>\n </Inline>\n </CardBody>\n </Card>\n ) : (\n <Skeleton style={{ height: 64 }} />\n )}\n\n {snap.loading && checks.length === 0 ? (\n <Stack gap={2}>\n <Skeleton style={{ height: 64 }} />\n <Skeleton style={{ height: 64 }} />\n </Stack>\n ) : snap.error && checks.length === 0 ? (\n <ErrorState\n block\n title=\"Couldn't run doctor\"\n description=\"The diagnostic snapshot failed. Retry to refetch.\"\n error={snap.error}\n onRetry={() => void snap.refetch()}\n testid=\"doctor-error\"\n />\n ) : checks.length === 0 ? (\n <EmptyState\n icon={<Stethoscope size={32} aria-hidden />}\n title=\"No checks yet\"\n description=\"The Doctor snapshot returned no checks.\"\n />\n ) : (\n <Stack gap={2}>\n {checks.map((c) => {\n const Icon = STATUS_ICON[c.status];\n const busy = running === c.name;\n return (\n <Card key={c.name} variant=\"default\">\n <CardBody>\n <Inline align=\"center\" justify=\"between\" gap={3}>\n <Stack gap={1} style={{ flex: 1, minWidth: 0 }}>\n <Inline align=\"center\" gap={2}>\n <Icon size={14} aria-hidden />\n <strong>{c.name}</strong>\n <Badge tone={STATUS_TONE[c.status]}>{c.status}</Badge>\n </Inline>\n <span style={{ color: 'var(--fg-muted)', fontSize: 'var(--fs-12)' }}>{c.message}</span>\n {c.error && <span style={{ color: 'var(--danger)', fontSize: 'var(--fs-12)', fontFamily: 'var(--font-mono)' }}>{c.error}</span>}\n </Stack>\n <Button variant=\"ghost\" onClick={() => void runCheck(c.name)} disabled={busy} data-testid={`doctor-run-${c.name}`}>\n {busy ? <Loader2 size={12} className=\"animate-spin\" aria-hidden /> : <ShieldCheck size={12} aria-hidden />}\n {busy ? 'Running…' : 'Re-run'}\n </Button>\n </Inline>\n </CardBody>\n </Card>\n );\n })}\n </Stack>\n )}\n </Stack>\n );\n}"],"names":["CircleX","createLucideIcon","STATUS_ICON","CheckCircle2","AlertTriangle","XCircle","STATUS_TONE","DoctorView","snap","useFetch","health","running","setRunning","useState","error","setError","useEffect","id","runCheck","name","fetchJson","err","FetchError","rollup","_a","checks","g","c","jsxs","Stack","jsx","ViewHeader","Inline","Button","RefreshCw","Card","CardBody","Icon","Skeleton","ErrorState","EmptyState","Stethoscope","busy","Badge","Loader2","ShieldCheck"],"mappings":"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","x_google_ignoreList":[0]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as l,j as e}from"./cmdk-DVxytz9i.js";import{g as d}from"./main-
|
|
1
|
+
import{r as l,j as e}from"./cmdk-DVxytz9i.js";import{g as d}from"./main-CokHAXWM.js";const m=l.forwardRef(function(r,a){const{icon:t,title:n,description:s,action:i,className:o,...c}=r;return e.jsxs("div",{ref:a,className:d("v8-empty-state",o),style:{display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",gap:"var(--space-3)",padding:"var(--space-12) var(--space-6)",textAlign:"center",color:"var(--fg-muted)"},...c,children:[t!==void 0&&e.jsx("div",{style:{color:"var(--fg-subtle)",display:"inline-flex"},children:t}),e.jsx("div",{style:{fontSize:"var(--fs-16)",fontWeight:600,color:"var(--fg)"},children:n}),s!==void 0&&e.jsx("div",{style:{fontSize:"var(--fs-13)",maxWidth:480},children:s}),i!==void 0&&e.jsx("div",{style:{marginTop:"var(--space-2)"},children:i})]})});export{m as E};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EmptyState-
|
|
1
|
+
{"version":3,"file":"EmptyState-BjgVOrcO.js","sources":["../../src/web/v8/ui/feedback/EmptyState.tsx"],"sourcesContent":["import { forwardRef, type HTMLAttributes, type ReactNode } from 'react';\nimport { cx } from '../utils/cx.js';\n\n/**\n * EmptyState — placeholder for empty lists / zero-data views.\n *\n * Use when a view has no rows. Never use a spinner; the data is\n * genuinely empty.\n */\nexport interface EmptyStateProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {\n icon?: ReactNode;\n title: ReactNode;\n description?: ReactNode;\n action?: ReactNode;\n}\n\nexport const EmptyState = forwardRef<HTMLDivElement, EmptyStateProps>(function EmptyState(\n props,\n ref,\n) {\n const { icon, title, description, action, className, ...rest } = props;\n return (\n <div\n ref={ref}\n className={cx('v8-empty-state', className)}\n style={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 'var(--space-3)',\n padding: 'var(--space-12) var(--space-6)',\n textAlign: 'center',\n color: 'var(--fg-muted)',\n }}\n {...rest}\n >\n {icon !== undefined && (\n <div style={{ color: 'var(--fg-subtle)', display: 'inline-flex' }}>{icon}</div>\n )}\n <div style={{ fontSize: 'var(--fs-16)', fontWeight: 600, color: 'var(--fg)' }}>{title}</div>\n {description !== undefined && (\n <div style={{ fontSize: 'var(--fs-13)', maxWidth: 480 }}>{description}</div>\n )}\n {action !== undefined && <div style={{ marginTop: 'var(--space-2)' }}>{action}</div>}\n </div>\n );\n});"],"names":["EmptyState","forwardRef","props","ref","icon","title","description","action","className","rest","jsxs","cx","jsx"],"mappings":"qFAgBO,MAAMA,EAAaC,EAAAA,WAA4C,SACpEC,EACAC,EACA,CACA,KAAM,CAAE,KAAAC,EAAM,MAAAC,EAAO,YAAAC,EAAa,OAAAC,EAAQ,UAAAC,EAAW,GAAGC,GAASP,EACjE,OACEQ,EAAAA,KAAC,MAAA,CACC,IAAAP,EACA,UAAWQ,EAAG,iBAAkBH,CAAS,EACzC,MAAO,CACL,QAAS,OACT,cAAe,SACf,WAAY,SACZ,eAAgB,SAChB,IAAK,iBACL,QAAS,iCACT,UAAW,SACX,MAAO,iBAAA,EAER,GAAGC,EAEH,SAAA,CAAAL,IAAS,QACRQ,EAAAA,IAAC,MAAA,CAAI,MAAO,CAAE,MAAO,mBAAoB,QAAS,aAAA,EAAkB,SAAAR,CAAA,CAAK,EAE3EQ,EAAAA,IAAC,MAAA,CAAI,MAAO,CAAE,SAAU,eAAgB,WAAY,IAAK,MAAO,WAAA,EAAgB,SAAAP,CAAA,CAAM,EACrFC,IAAgB,QACfM,EAAAA,IAAC,MAAA,CAAI,MAAO,CAAE,SAAU,eAAgB,SAAU,GAAA,EAAQ,SAAAN,CAAA,CAAY,EAEvEC,IAAW,QAAaK,MAAC,MAAA,CAAI,MAAO,CAAE,UAAW,gBAAA,EAAqB,SAAAL,CAAA,CAAO,CAAA,CAAA,CAAA,CAGpF,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{r as s,j as e}from"./cmdk-DVxytz9i.js";import{c as O,u as V,S as p,I as f,d as n,h as I,V as P,O as D,i as y,F as k}from"./main-
|
|
1
|
+
import{r as s,j as e}from"./cmdk-DVxytz9i.js";import{c as O,u as V,S as p,I as f,d as n,h as I,V as P,O as D,i as y,F as k}from"./main-CokHAXWM.js";import{V as Z}from"./ViewHeader-BzYZ3m-e.js";import{L as M}from"./ListHeader-TjPJrUfY.js";import{C as _,b as L}from"./Card-B0imhxMk.js";import{I as A}from"./Input-Bgzxf_Hu.js";import{S as w,a as E,b as T}from"./Sheet-DnDid58j.js";import{E as N}from"./EmptyState-BjgVOrcO.js";import{D as U}from"./download-4cEUWue1.js";import{R as q}from"./refresh-ccw-DNrXX9gB.js";import{P as H}from"./plus-DENm0hqV.js";import{P as K}from"./pencil-eq5IqBmU.js";import{T as J}from"./trash-2-DZDjEnNh.js";/**
|
|
2
2
|
* @license lucide-react v0.460.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EnvVarsView-D1cx83mB.js","sources":["../../../node_modules/lucide-react/dist/esm/icons/file-up.js","../../src/web/v8/views/EnvVars/EnvVarsView.tsx"],"sourcesContent":["/**\n * @license lucide-react v0.460.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst FileUp = createLucideIcon(\"FileUp\", [\n [\"path\", { d: \"M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z\", key: \"1rqfz7\" }],\n [\"path\", { d: \"M14 2v4a2 2 0 0 0 2 2h4\", key: \"tnqrlb\" }],\n [\"path\", { d: \"M12 12v6\", key: \"3ahymv\" }],\n [\"path\", { d: \"m15 15-3-3-3 3\", key: \"15xj92\" }]\n]);\n\nexport { FileUp as default };\n//# sourceMappingURL=file-up.js.map\n","/**\n * v8/views/EnvVars/EnvVarsView.tsx — Sprint S41, v9.3.0.\n *\n * List of env vars (masked values) with: per-row edit (Sheet),\n * per-row delete (inline confirm), Add Sheet, Bulk Import Sheet,\n * and Export trigger. Backed by /api/env-vars + /api/env-vars/grouped\n * + /api/env-vars/export + /api/env-vars/bulk-import.\n */\n\nimport { useCallback, useMemo, useState } from 'react';\nimport { Download, FileUp, FlaskConical, Pencil, Plus, RefreshCcw, Trash2, Variable } from 'lucide-react';\nimport { Stack } from '../../ui/primitives/Stack.js';\nimport { Inline } from '../../ui/primitives/Inline.js';\nimport { ViewHeader } from '../../ui/data/ViewHeader.js';\nimport { ListHeader } from '../../ui/data/ListHeader.js';\nimport { Card, CardBody } from '../../ui/data/Card.js';\nimport { Button } from '../../ui/controls/Button.js';\nimport { Input } from '../../ui/controls/Input.js';\nimport { Sheet, SheetClose, SheetContent } from '../../ui/feedback/Sheet.js';\nimport { Skeleton } from '../../ui/feedback/Skeleton.js';\nimport { EmptyState } from '../../ui/feedback/EmptyState.js';\nimport { useFetch } from '../../data/useFetch.js';\nimport { fetchJson, FetchError } from '../../data/fetcher.js';\n\ninterface EnvRow {\n name: string;\n value: string;\n createdAt?: string;\n source?: string;\n}\n\nexport function EnvVarsView(): JSX.Element {\n const payload = useFetch<EnvRow[]>('/api/env-vars');\n const [adding, setAdding] = useState<boolean>(false);\n const [editing, setEditing] = useState<string | null>(null);\n const [bulkImporting, setBulkImporting] = useState<boolean>(false);\n const [confirmDelete, setConfirmDelete] = useState<string | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [testing, setTesting] = useState<string | null>(null);\n const [testResult, setTestResult] = useState<{ name: string; ok: boolean; message: string } | null>(null);\n\n const rows = useMemo<EnvRow[]>(() => payload.data ?? [], [payload.data]);\n\n const refresh = useCallback(() => { void payload.refetch(); }, [payload]);\n\n const runTest = async (name: string): Promise<void> => {\n setTesting(name);\n setError(null);\n try {\n const res = await fetchJson<{ ok?: boolean; status?: string; message?: string }>(`/api/env-vars/${encodeURIComponent(name)}/test`, { method: 'POST' });\n setTestResult({ name, ok: res.ok !== false, message: res.message ?? (res.ok !== false ? 'OK' : 'Failed') });\n } catch (err) {\n const msg = err instanceof FetchError ? err.message : (err as Error).message;\n setTestResult({ name, ok: false, message: msg });\n } finally {\n setTesting(null);\n }\n };\n\n const drop = async (name: string): Promise<void> => {\n setError(null);\n try {\n await fetchJson(`/api/env-vars/${name}`, { method: 'DELETE' });\n setConfirmDelete(null);\n refresh();\n } catch (err) {\n setError(err instanceof FetchError ? err.message : (err as Error).message);\n }\n };\n\n return (\n <Stack gap={4} data-testid=\"env-vars-view\">\n <ViewHeader\n title=\"Env vars\"\n description=\"Runtime environment variables for the dashboard. Stored in ~/.config/bizar/env.json (mode 0600).\"\n actions={\n <Inline align=\"center\" gap={2}>\n {error !== null && (\n <span role=\"alert\" data-testid=\"env-vars-error\" style={{ color: 'var(--danger)', fontSize: 'var(--fs-12)' }}>\n {error}\n </span>\n )}\n <Button variant=\"ghost\" onClick={() => { window.open('/api/env-vars/export', '_blank'); }} data-testid=\"env-vars-export\">\n <Download size={14} aria-hidden /> Export\n </Button>\n <Button variant=\"ghost\" onClick={() => setBulkImporting(true)} data-testid=\"env-vars-bulk-import\">\n <FileUp size={14} aria-hidden /> Bulk import\n </Button>\n <Button variant=\"ghost\" onClick={() => void refresh()} data-testid=\"env-vars-refresh\">\n <RefreshCcw size={14} aria-hidden /> Refresh\n </Button>\n <Button variant=\"primary\" onClick={() => setAdding(true)} data-testid=\"env-vars-add\">\n <Plus size={14} aria-hidden /> Add\n </Button>\n </Inline>\n }\n />\n <ListHeader title=\"Variables\" count={rows.length} testid=\"env-vars-list-header\" />\n\n <Card variant=\"default\">\n <CardBody>\n {payload.loading && rows.length === 0 ? (\n <Stack gap={2}>\n <Skeleton style={{ height: 36 }} />\n <Skeleton style={{ height: 36 }} />\n </Stack>\n ) : rows.length === 0 ? (\n <EmptyState\n icon={<Variable size={28} aria-hidden />}\n title=\"No env vars\"\n description=\"Add one or bulk-import a .env file.\"\n />\n ) : (\n <Stack gap={1}>\n {rows.map((r) => {\n const isConfirming = confirmDelete === r.name;\n return (\n <div\n key={r.name}\n data-testid={`env-var-row-${r.name}`}\n style={{\n padding: 'var(--space-2)',\n borderRadius: 'var(--radius-sm)',\n border: '1px solid var(--border)',\n background: 'var(--surface-0)',\n }}\n >\n <Inline align=\"center\" justify=\"between\" gap={2}>\n <Stack gap={0} style={{ minWidth: 0 }}>\n <code style={{ fontSize: 'var(--fs-12)' }}>{r.name}</code>\n <code style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>{r.value}</code>\n {r.source && (\n <span style={{ fontSize: 'var(--fs-11)', color: 'var(--fg-subtle)' }}>\n source: {r.source} {r.createdAt ? `· ${r.createdAt}` : ''}\n </span>\n )}\n </Stack>\n <Inline gap={1}>\n <Button\n variant=\"ghost\"\n onClick={() => void runTest(r.name)}\n disabled={testing === r.name}\n data-testid={`env-var-test-${r.name}`}\n aria-label={`Test ${r.name}`}\n >\n <FlaskConical size={14} aria-hidden />\n </Button>\n <Button variant=\"ghost\" onClick={() => setEditing(r.name)} data-testid={`env-var-edit-${r.name}`} aria-label={`Edit ${r.name}`}>\n <Pencil size={14} aria-hidden />\n </Button>\n <Button\n variant=\"ghost\"\n onClick={() => setConfirmDelete((cur) => (cur === r.name ? null : r.name))}\n data-testid={`env-var-delete-${r.name}`}\n aria-label={`Delete ${r.name}`}\n >\n <Trash2 size={14} aria-hidden />\n </Button>\n </Inline>\n </Inline>\n {isConfirming && (\n <Inline gap={1} style={{ marginTop: 'var(--space-1)' }}>\n <Button variant=\"danger\" onClick={() => void drop(r.name)} data-testid={`env-var-confirm-delete-${r.name}`}>\n Confirm delete\n </Button>\n <Button variant=\"ghost\" onClick={() => setConfirmDelete(null)} data-testid={`env-var-cancel-delete-${r.name}`}>\n Cancel\n </Button>\n </Inline>\n )}\n {testResult !== null && testResult.name === r.name && (\n <div\n data-testid={`env-var-test-result-${r.name}`}\n style={{\n marginTop: 'var(--space-1)',\n fontSize: 'var(--fs-11)',\n color: testResult.ok ? 'var(--success)' : 'var(--danger)',\n fontFamily: 'var(--font-mono)',\n }}\n >\n test: {testResult.message}\n </div>\n )}\n </div>\n );\n })}\n </Stack>\n )}\n </CardBody>\n </Card>\n\n <Sheet open={adding} onOpenChange={setAdding}>\n <SheetContent side=\"right\" title=\"Add env var\" description=\"Must match /^BIZAR_[A-Z0-9_]+$/.\">\n <AddEditForm\n mode=\"add\"\n onSubmit={async (name, value) => {\n await fetchJson('/api/env-vars', { method: 'POST', body: { name, value } });\n setAdding(false);\n refresh();\n }}\n onCancel={() => setAdding(false)}\n />\n </SheetContent>\n </Sheet>\n\n <Sheet open={editing !== null} onOpenChange={(open) => { if (!open) setEditing(null); }}>\n <SheetContent side=\"right\" title=\"Edit env var\" description={editing ?? ''}>\n {editing !== null && (\n <AddEditForm\n mode=\"edit\"\n initialName={editing}\n onSubmit={async (name, value) => {\n await fetchJson(`/api/env-vars/${name}`, { method: 'PUT', body: { value } });\n setEditing(null);\n refresh();\n }}\n onCancel={() => setEditing(null)}\n />\n )}\n </SheetContent>\n </Sheet>\n\n <Sheet open={bulkImporting} onOpenChange={setBulkImporting}>\n <SheetContent side=\"right\" title=\"Bulk import\" description=\"Paste KEY=value lines (one per line, # comments ignored).\">\n <BulkImportForm\n onSubmit={async (envContent) => {\n await fetchJson('/api/env-vars/bulk-import', {\n method: 'POST',\n body: { envContent },\n });\n setBulkImporting(false);\n refresh();\n }}\n onCancel={() => setBulkImporting(false)}\n />\n </SheetContent>\n </Sheet>\n </Stack>\n );\n}\n\nfunction AddEditForm({\n mode,\n initialName,\n onSubmit,\n onCancel,\n}: {\n mode: 'add' | 'edit';\n initialName?: string;\n onSubmit: (name: string, value: string) => Promise<void>;\n onCancel: () => void;\n}): JSX.Element {\n const [name, setName] = useState<string>(initialName ?? '');\n const [value, setValue] = useState<string>('');\n const [busy, setBusy] = useState<boolean>(false);\n const [error, setError] = useState<string | null>(null);\n\n const submit = async (): Promise<void> => {\n if (!name.trim() || !value || busy) return;\n setBusy(true);\n setError(null);\n try {\n await onSubmit(name.trim(), value);\n } catch (err) {\n setError(err instanceof FetchError ? err.message : (err as Error).message);\n } finally {\n setBusy(false);\n }\n };\n\n return (\n <Stack gap={3} style={{ padding: 'var(--space-4)' }}>\n <label style={{ display: 'flex', flexDirection: 'column', gap: 'var(--space-1)' }}>\n <span style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>Name</span>\n <Input\n value={name}\n readOnly={mode === 'edit'}\n data-testid=\"env-var-form-name\"\n onChange={(e) => setName((e.target as HTMLInputElement).value)}\n />\n </label>\n <label style={{ display: 'flex', flexDirection: 'column', gap: 'var(--space-1)' }}>\n <span style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>Value</span>\n <Input\n type=\"password\"\n value={value}\n data-testid=\"env-var-form-value\"\n onChange={(e) => setValue((e.target as HTMLInputElement).value)}\n />\n </label>\n {error !== null && (\n <span role=\"alert\" style={{ color: 'var(--danger)', fontSize: 'var(--fs-12)' }}>{error}</span>\n )}\n <Inline justify=\"end\" gap={2}>\n <SheetClose asChild>\n <Button variant=\"ghost\" onClick={onCancel} data-testid=\"env-var-form-cancel\">Cancel</Button>\n </SheetClose>\n <Button\n variant=\"primary\"\n onClick={() => void submit()}\n disabled={busy || !name.trim() || !value}\n data-testid=\"env-var-form-submit\"\n >\n {mode === 'add' ? 'Add' : 'Save'}\n </Button>\n </Inline>\n </Stack>\n );\n}\n\nfunction BulkImportForm({\n onSubmit,\n onCancel,\n}: {\n onSubmit: (envContent: string) => Promise<void>;\n onCancel: () => void;\n}): JSX.Element {\n const [content, setContent] = useState<string>('');\n const [busy, setBusy] = useState<boolean>(false);\n const [error, setError] = useState<string | null>(null);\n\n return (\n <Stack gap={3} style={{ padding: 'var(--space-4)' }}>\n <textarea\n value={content}\n placeholder={'BIZAR_FOO=bar\\nBIZAR_BAZ=qux\\n# comment'}\n rows={12}\n data-testid=\"env-vars-bulk-input\"\n onChange={(e) => setContent((e.target as HTMLTextAreaElement).value)}\n style={{\n background: 'var(--surface-0)',\n border: '1px solid var(--border)',\n borderRadius: 'var(--radius-md)',\n padding: 'var(--space-2)',\n color: 'var(--fg)',\n fontFamily: 'var(--font-mono)',\n fontSize: 'var(--fs-12)',\n resize: 'vertical',\n }}\n />\n {error !== null && (\n <span role=\"alert\" style={{ color: 'var(--danger)', fontSize: 'var(--fs-12)' }}>{error}</span>\n )}\n <Inline justify=\"end\" gap={2}>\n <SheetClose asChild>\n <Button variant=\"ghost\" onClick={onCancel}>Cancel</Button>\n </SheetClose>\n <Button\n variant=\"primary\"\n onClick={async () => {\n setBusy(true);\n setError(null);\n try { await onSubmit(content); }\n catch (err) { setError(err instanceof FetchError ? err.message : (err as Error).message); }\n finally { setBusy(false); }\n }}\n disabled={busy || content.trim() === ''}\n data-testid=\"env-vars-bulk-submit\"\n >\n {busy ? 'Importing…' : 'Import'}\n </Button>\n </Inline>\n </Stack>\n );\n}"],"names":["FileUp","createLucideIcon","EnvVarsView","payload","useFetch","adding","setAdding","useState","editing","setEditing","bulkImporting","setBulkImporting","confirmDelete","setConfirmDelete","error","setError","testing","setTesting","testResult","setTestResult","rows","useMemo","refresh","useCallback","runTest","name","res","fetchJson","err","msg","FetchError","drop","jsxs","Stack","jsx","ViewHeader","Inline","Button","Download","RefreshCcw","Plus","ListHeader","Card","CardBody","Skeleton","EmptyState","Variable","r","isConfirming","FlaskConical","Pencil","cur","Trash2","Sheet","SheetContent","AddEditForm","value","open","BulkImportForm","envContent","mode","initialName","onSubmit","onCancel","setName","setValue","busy","setBusy","submit","Input","e","SheetClose","content","setContent"],"mappings":"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","x_google_ignoreList":[0]}
|
|
1
|
+
{"version":3,"file":"EnvVarsView-BJ2TEzF7.js","sources":["../../../node_modules/lucide-react/dist/esm/icons/file-up.js","../../src/web/v8/views/EnvVars/EnvVarsView.tsx"],"sourcesContent":["/**\n * @license lucide-react v0.460.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst FileUp = createLucideIcon(\"FileUp\", [\n [\"path\", { d: \"M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z\", key: \"1rqfz7\" }],\n [\"path\", { d: \"M14 2v4a2 2 0 0 0 2 2h4\", key: \"tnqrlb\" }],\n [\"path\", { d: \"M12 12v6\", key: \"3ahymv\" }],\n [\"path\", { d: \"m15 15-3-3-3 3\", key: \"15xj92\" }]\n]);\n\nexport { FileUp as default };\n//# sourceMappingURL=file-up.js.map\n","/**\n * v8/views/EnvVars/EnvVarsView.tsx — Sprint S41, v9.3.0.\n *\n * List of env vars (masked values) with: per-row edit (Sheet),\n * per-row delete (inline confirm), Add Sheet, Bulk Import Sheet,\n * and Export trigger. Backed by /api/env-vars + /api/env-vars/grouped\n * + /api/env-vars/export + /api/env-vars/bulk-import.\n */\n\nimport { useCallback, useMemo, useState } from 'react';\nimport { Download, FileUp, FlaskConical, Pencil, Plus, RefreshCcw, Trash2, Variable } from 'lucide-react';\nimport { Stack } from '../../ui/primitives/Stack.js';\nimport { Inline } from '../../ui/primitives/Inline.js';\nimport { ViewHeader } from '../../ui/data/ViewHeader.js';\nimport { ListHeader } from '../../ui/data/ListHeader.js';\nimport { Card, CardBody } from '../../ui/data/Card.js';\nimport { Button } from '../../ui/controls/Button.js';\nimport { Input } from '../../ui/controls/Input.js';\nimport { Sheet, SheetClose, SheetContent } from '../../ui/feedback/Sheet.js';\nimport { Skeleton } from '../../ui/feedback/Skeleton.js';\nimport { EmptyState } from '../../ui/feedback/EmptyState.js';\nimport { useFetch } from '../../data/useFetch.js';\nimport { fetchJson, FetchError } from '../../data/fetcher.js';\n\ninterface EnvRow {\n name: string;\n value: string;\n createdAt?: string;\n source?: string;\n}\n\nexport function EnvVarsView(): JSX.Element {\n const payload = useFetch<EnvRow[]>('/api/env-vars');\n const [adding, setAdding] = useState<boolean>(false);\n const [editing, setEditing] = useState<string | null>(null);\n const [bulkImporting, setBulkImporting] = useState<boolean>(false);\n const [confirmDelete, setConfirmDelete] = useState<string | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [testing, setTesting] = useState<string | null>(null);\n const [testResult, setTestResult] = useState<{ name: string; ok: boolean; message: string } | null>(null);\n\n const rows = useMemo<EnvRow[]>(() => payload.data ?? [], [payload.data]);\n\n const refresh = useCallback(() => { void payload.refetch(); }, [payload]);\n\n const runTest = async (name: string): Promise<void> => {\n setTesting(name);\n setError(null);\n try {\n const res = await fetchJson<{ ok?: boolean; status?: string; message?: string }>(`/api/env-vars/${encodeURIComponent(name)}/test`, { method: 'POST' });\n setTestResult({ name, ok: res.ok !== false, message: res.message ?? (res.ok !== false ? 'OK' : 'Failed') });\n } catch (err) {\n const msg = err instanceof FetchError ? err.message : (err as Error).message;\n setTestResult({ name, ok: false, message: msg });\n } finally {\n setTesting(null);\n }\n };\n\n const drop = async (name: string): Promise<void> => {\n setError(null);\n try {\n await fetchJson(`/api/env-vars/${name}`, { method: 'DELETE' });\n setConfirmDelete(null);\n refresh();\n } catch (err) {\n setError(err instanceof FetchError ? err.message : (err as Error).message);\n }\n };\n\n return (\n <Stack gap={4} data-testid=\"env-vars-view\">\n <ViewHeader\n title=\"Env vars\"\n description=\"Runtime environment variables for the dashboard. Stored in ~/.config/bizar/env.json (mode 0600).\"\n actions={\n <Inline align=\"center\" gap={2}>\n {error !== null && (\n <span role=\"alert\" data-testid=\"env-vars-error\" style={{ color: 'var(--danger)', fontSize: 'var(--fs-12)' }}>\n {error}\n </span>\n )}\n <Button variant=\"ghost\" onClick={() => { window.open('/api/env-vars/export', '_blank'); }} data-testid=\"env-vars-export\">\n <Download size={14} aria-hidden /> Export\n </Button>\n <Button variant=\"ghost\" onClick={() => setBulkImporting(true)} data-testid=\"env-vars-bulk-import\">\n <FileUp size={14} aria-hidden /> Bulk import\n </Button>\n <Button variant=\"ghost\" onClick={() => void refresh()} data-testid=\"env-vars-refresh\">\n <RefreshCcw size={14} aria-hidden /> Refresh\n </Button>\n <Button variant=\"primary\" onClick={() => setAdding(true)} data-testid=\"env-vars-add\">\n <Plus size={14} aria-hidden /> Add\n </Button>\n </Inline>\n }\n />\n <ListHeader title=\"Variables\" count={rows.length} testid=\"env-vars-list-header\" />\n\n <Card variant=\"default\">\n <CardBody>\n {payload.loading && rows.length === 0 ? (\n <Stack gap={2}>\n <Skeleton style={{ height: 36 }} />\n <Skeleton style={{ height: 36 }} />\n </Stack>\n ) : rows.length === 0 ? (\n <EmptyState\n icon={<Variable size={28} aria-hidden />}\n title=\"No env vars\"\n description=\"Add one or bulk-import a .env file.\"\n />\n ) : (\n <Stack gap={1}>\n {rows.map((r) => {\n const isConfirming = confirmDelete === r.name;\n return (\n <div\n key={r.name}\n data-testid={`env-var-row-${r.name}`}\n style={{\n padding: 'var(--space-2)',\n borderRadius: 'var(--radius-sm)',\n border: '1px solid var(--border)',\n background: 'var(--surface-0)',\n }}\n >\n <Inline align=\"center\" justify=\"between\" gap={2}>\n <Stack gap={0} style={{ minWidth: 0 }}>\n <code style={{ fontSize: 'var(--fs-12)' }}>{r.name}</code>\n <code style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>{r.value}</code>\n {r.source && (\n <span style={{ fontSize: 'var(--fs-11)', color: 'var(--fg-subtle)' }}>\n source: {r.source} {r.createdAt ? `· ${r.createdAt}` : ''}\n </span>\n )}\n </Stack>\n <Inline gap={1}>\n <Button\n variant=\"ghost\"\n onClick={() => void runTest(r.name)}\n disabled={testing === r.name}\n data-testid={`env-var-test-${r.name}`}\n aria-label={`Test ${r.name}`}\n >\n <FlaskConical size={14} aria-hidden />\n </Button>\n <Button variant=\"ghost\" onClick={() => setEditing(r.name)} data-testid={`env-var-edit-${r.name}`} aria-label={`Edit ${r.name}`}>\n <Pencil size={14} aria-hidden />\n </Button>\n <Button\n variant=\"ghost\"\n onClick={() => setConfirmDelete((cur) => (cur === r.name ? null : r.name))}\n data-testid={`env-var-delete-${r.name}`}\n aria-label={`Delete ${r.name}`}\n >\n <Trash2 size={14} aria-hidden />\n </Button>\n </Inline>\n </Inline>\n {isConfirming && (\n <Inline gap={1} style={{ marginTop: 'var(--space-1)' }}>\n <Button variant=\"danger\" onClick={() => void drop(r.name)} data-testid={`env-var-confirm-delete-${r.name}`}>\n Confirm delete\n </Button>\n <Button variant=\"ghost\" onClick={() => setConfirmDelete(null)} data-testid={`env-var-cancel-delete-${r.name}`}>\n Cancel\n </Button>\n </Inline>\n )}\n {testResult !== null && testResult.name === r.name && (\n <div\n data-testid={`env-var-test-result-${r.name}`}\n style={{\n marginTop: 'var(--space-1)',\n fontSize: 'var(--fs-11)',\n color: testResult.ok ? 'var(--success)' : 'var(--danger)',\n fontFamily: 'var(--font-mono)',\n }}\n >\n test: {testResult.message}\n </div>\n )}\n </div>\n );\n })}\n </Stack>\n )}\n </CardBody>\n </Card>\n\n <Sheet open={adding} onOpenChange={setAdding}>\n <SheetContent side=\"right\" title=\"Add env var\" description=\"Must match /^BIZAR_[A-Z0-9_]+$/.\">\n <AddEditForm\n mode=\"add\"\n onSubmit={async (name, value) => {\n await fetchJson('/api/env-vars', { method: 'POST', body: { name, value } });\n setAdding(false);\n refresh();\n }}\n onCancel={() => setAdding(false)}\n />\n </SheetContent>\n </Sheet>\n\n <Sheet open={editing !== null} onOpenChange={(open) => { if (!open) setEditing(null); }}>\n <SheetContent side=\"right\" title=\"Edit env var\" description={editing ?? ''}>\n {editing !== null && (\n <AddEditForm\n mode=\"edit\"\n initialName={editing}\n onSubmit={async (name, value) => {\n await fetchJson(`/api/env-vars/${name}`, { method: 'PUT', body: { value } });\n setEditing(null);\n refresh();\n }}\n onCancel={() => setEditing(null)}\n />\n )}\n </SheetContent>\n </Sheet>\n\n <Sheet open={bulkImporting} onOpenChange={setBulkImporting}>\n <SheetContent side=\"right\" title=\"Bulk import\" description=\"Paste KEY=value lines (one per line, # comments ignored).\">\n <BulkImportForm\n onSubmit={async (envContent) => {\n await fetchJson('/api/env-vars/bulk-import', {\n method: 'POST',\n body: { envContent },\n });\n setBulkImporting(false);\n refresh();\n }}\n onCancel={() => setBulkImporting(false)}\n />\n </SheetContent>\n </Sheet>\n </Stack>\n );\n}\n\nfunction AddEditForm({\n mode,\n initialName,\n onSubmit,\n onCancel,\n}: {\n mode: 'add' | 'edit';\n initialName?: string;\n onSubmit: (name: string, value: string) => Promise<void>;\n onCancel: () => void;\n}): JSX.Element {\n const [name, setName] = useState<string>(initialName ?? '');\n const [value, setValue] = useState<string>('');\n const [busy, setBusy] = useState<boolean>(false);\n const [error, setError] = useState<string | null>(null);\n\n const submit = async (): Promise<void> => {\n if (!name.trim() || !value || busy) return;\n setBusy(true);\n setError(null);\n try {\n await onSubmit(name.trim(), value);\n } catch (err) {\n setError(err instanceof FetchError ? err.message : (err as Error).message);\n } finally {\n setBusy(false);\n }\n };\n\n return (\n <Stack gap={3} style={{ padding: 'var(--space-4)' }}>\n <label style={{ display: 'flex', flexDirection: 'column', gap: 'var(--space-1)' }}>\n <span style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>Name</span>\n <Input\n value={name}\n readOnly={mode === 'edit'}\n data-testid=\"env-var-form-name\"\n onChange={(e) => setName((e.target as HTMLInputElement).value)}\n />\n </label>\n <label style={{ display: 'flex', flexDirection: 'column', gap: 'var(--space-1)' }}>\n <span style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>Value</span>\n <Input\n type=\"password\"\n value={value}\n data-testid=\"env-var-form-value\"\n onChange={(e) => setValue((e.target as HTMLInputElement).value)}\n />\n </label>\n {error !== null && (\n <span role=\"alert\" style={{ color: 'var(--danger)', fontSize: 'var(--fs-12)' }}>{error}</span>\n )}\n <Inline justify=\"end\" gap={2}>\n <SheetClose asChild>\n <Button variant=\"ghost\" onClick={onCancel} data-testid=\"env-var-form-cancel\">Cancel</Button>\n </SheetClose>\n <Button\n variant=\"primary\"\n onClick={() => void submit()}\n disabled={busy || !name.trim() || !value}\n data-testid=\"env-var-form-submit\"\n >\n {mode === 'add' ? 'Add' : 'Save'}\n </Button>\n </Inline>\n </Stack>\n );\n}\n\nfunction BulkImportForm({\n onSubmit,\n onCancel,\n}: {\n onSubmit: (envContent: string) => Promise<void>;\n onCancel: () => void;\n}): JSX.Element {\n const [content, setContent] = useState<string>('');\n const [busy, setBusy] = useState<boolean>(false);\n const [error, setError] = useState<string | null>(null);\n\n return (\n <Stack gap={3} style={{ padding: 'var(--space-4)' }}>\n <textarea\n value={content}\n placeholder={'BIZAR_FOO=bar\\nBIZAR_BAZ=qux\\n# comment'}\n rows={12}\n data-testid=\"env-vars-bulk-input\"\n onChange={(e) => setContent((e.target as HTMLTextAreaElement).value)}\n style={{\n background: 'var(--surface-0)',\n border: '1px solid var(--border)',\n borderRadius: 'var(--radius-md)',\n padding: 'var(--space-2)',\n color: 'var(--fg)',\n fontFamily: 'var(--font-mono)',\n fontSize: 'var(--fs-12)',\n resize: 'vertical',\n }}\n />\n {error !== null && (\n <span role=\"alert\" style={{ color: 'var(--danger)', fontSize: 'var(--fs-12)' }}>{error}</span>\n )}\n <Inline justify=\"end\" gap={2}>\n <SheetClose asChild>\n <Button variant=\"ghost\" onClick={onCancel}>Cancel</Button>\n </SheetClose>\n <Button\n variant=\"primary\"\n onClick={async () => {\n setBusy(true);\n setError(null);\n try { await onSubmit(content); }\n catch (err) { setError(err instanceof FetchError ? err.message : (err as Error).message); }\n finally { setBusy(false); }\n }}\n disabled={busy || content.trim() === ''}\n data-testid=\"env-vars-bulk-submit\"\n >\n {busy ? 'Importing…' : 'Import'}\n </Button>\n </Inline>\n </Stack>\n );\n}"],"names":["FileUp","createLucideIcon","EnvVarsView","payload","useFetch","adding","setAdding","useState","editing","setEditing","bulkImporting","setBulkImporting","confirmDelete","setConfirmDelete","error","setError","testing","setTesting","testResult","setTestResult","rows","useMemo","refresh","useCallback","runTest","name","res","fetchJson","err","msg","FetchError","drop","jsxs","Stack","jsx","ViewHeader","Inline","Button","Download","RefreshCcw","Plus","ListHeader","Card","CardBody","Skeleton","EmptyState","Variable","r","isConfirming","FlaskConical","Pencil","cur","Trash2","Sheet","SheetContent","AddEditForm","value","open","BulkImportForm","envContent","mode","initialName","onSubmit","onCancel","setName","setValue","busy","setBusy","submit","Input","e","SheetClose","content","setContent"],"mappings":"0nBAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GASA,MAAMA,EAASC,EAAiB,SAAU,CACxC,CAAC,OAAQ,CAAE,EAAG,6DAA8D,IAAK,QAAQ,CAAE,EAC3F,CAAC,OAAQ,CAAE,EAAG,0BAA2B,IAAK,QAAQ,CAAE,EACxD,CAAC,OAAQ,CAAE,EAAG,WAAY,IAAK,QAAQ,CAAE,EACzC,CAAC,OAAQ,CAAE,EAAG,iBAAkB,IAAK,QAAQ,CAAE,CACjD,CAAC,ECiBM,SAASC,IAA2B,CACzC,MAAMC,EAAUC,EAAmB,eAAe,EAC5C,CAACC,EAAQC,CAAS,EAAIC,EAAAA,SAAkB,EAAK,EAC7C,CAACC,EAASC,CAAU,EAAIF,EAAAA,SAAwB,IAAI,EACpD,CAACG,EAAeC,CAAgB,EAAIJ,EAAAA,SAAkB,EAAK,EAC3D,CAACK,EAAeC,CAAgB,EAAIN,EAAAA,SAAwB,IAAI,EAChE,CAACO,EAAOC,CAAQ,EAAIR,EAAAA,SAAwB,IAAI,EAChD,CAACS,EAASC,CAAU,EAAIV,EAAAA,SAAwB,IAAI,EACpD,CAACW,EAAYC,CAAa,EAAIZ,EAAAA,SAAgE,IAAI,EAElGa,EAAOC,EAAAA,QAAkB,IAAMlB,EAAQ,MAAQ,GAAI,CAACA,EAAQ,IAAI,CAAC,EAEjEmB,EAAUC,EAAAA,YAAY,IAAM,CAAOpB,EAAQ,QAAA,CAAW,EAAG,CAACA,CAAO,CAAC,EAElEqB,EAAU,MAAOC,GAAgC,CACrDR,EAAWQ,CAAI,EACfV,EAAS,IAAI,EACb,GAAI,CACF,MAAMW,EAAM,MAAMC,EAA+D,iBAAiB,mBAAmBF,CAAI,CAAC,QAAS,CAAE,OAAQ,MAAA,CAAQ,EACrJN,EAAc,CAAE,KAAAM,EAAM,GAAIC,EAAI,KAAO,GAAO,QAASA,EAAI,UAAYA,EAAI,KAAO,GAAQ,KAAO,UAAW,CAC5G,OAASE,EAAK,CACZ,MAAMC,GAAMD,aAAeE,EAAaF,EAAI,SAC5CT,EAAc,CAAE,KAAAM,EAAM,GAAI,GAAO,QAASI,EAAK,CACjD,QAAA,CACEZ,EAAW,IAAI,CACjB,CACF,EAEMc,EAAO,MAAON,GAAgC,CAClDV,EAAS,IAAI,EACb,GAAI,CACF,MAAMY,EAAU,iBAAiBF,CAAI,GAAI,CAAE,OAAQ,SAAU,EAC7DZ,EAAiB,IAAI,EACrBS,EAAA,CACF,OAASM,EAAK,CACZb,GAASa,aAAeE,EAAaF,EAAI,QAAgC,CAC3E,CACF,EAEA,OACEI,EAAAA,KAACC,EAAA,CAAM,IAAK,EAAG,cAAY,gBACzB,SAAA,CAAAC,EAAAA,IAACC,EAAA,CACC,MAAM,WACN,YAAY,mGACZ,QACEH,EAAAA,KAACI,EAAA,CAAO,MAAM,SAAS,IAAK,EACzB,SAAA,CAAAtB,IAAU,MACToB,MAAC,OAAA,CAAK,KAAK,QAAQ,cAAY,iBAAiB,MAAO,CAAE,MAAO,gBAAiB,SAAU,gBACxF,SAAApB,EACH,EAEFkB,EAAAA,KAACK,EAAA,CAAO,QAAQ,QAAQ,QAAS,IAAM,CAAE,OAAO,KAAK,uBAAwB,QAAQ,CAAG,EAAG,cAAY,kBACrG,SAAA,CAAAH,EAAAA,IAACI,EAAA,CAAS,KAAM,GAAI,cAAW,GAAC,EAAE,SAAA,EACpC,EACAN,EAAAA,KAACK,EAAA,CAAO,QAAQ,QAAQ,QAAS,IAAM1B,EAAiB,EAAI,EAAG,cAAY,uBACzE,SAAA,CAAAuB,EAAAA,IAAClC,EAAA,CAAO,KAAM,GAAI,cAAW,GAAC,EAAE,cAAA,EAClC,EACAgC,EAAAA,KAACK,EAAA,CAAO,QAAQ,QAAQ,QAAS,IAAM,KAAKf,EAAA,EAAW,cAAY,mBACjE,SAAA,CAAAY,EAAAA,IAACK,EAAA,CAAW,KAAM,GAAI,cAAW,GAAC,EAAE,UAAA,EACtC,EACAP,EAAAA,KAACK,EAAA,CAAO,QAAQ,UAAU,QAAS,IAAM/B,EAAU,EAAI,EAAG,cAAY,eACpE,SAAA,CAAA4B,EAAAA,IAACM,EAAA,CAAK,KAAM,GAAI,cAAW,GAAC,EAAE,MAAA,CAAA,CAChC,CAAA,CAAA,CACF,CAAA,CAAA,EAGJN,MAACO,GAAW,MAAM,YAAY,MAAOrB,EAAK,OAAQ,OAAO,uBAAuB,EAEhFc,MAACQ,EAAA,CAAK,QAAQ,UACZ,eAACC,EAAA,CACE,SAAAxC,EAAQ,SAAWiB,EAAK,SAAW,EAClCY,EAAAA,KAACC,EAAA,CAAM,IAAK,EACV,SAAA,CAAAC,EAAAA,IAACU,EAAA,CAAS,MAAO,CAAE,OAAQ,IAAM,QAChCA,EAAA,CAAS,MAAO,CAAE,OAAQ,GAAG,CAAG,CAAA,CAAA,CACnC,EACExB,EAAK,SAAW,EAClBc,EAAAA,IAACW,EAAA,CACC,KAAMX,EAAAA,IAACY,EAAA,CAAS,KAAM,GAAI,cAAW,GAAC,EACtC,MAAM,cACN,YAAY,qCAAA,CAAA,QAGbb,EAAA,CAAM,IAAK,EACT,SAAAb,EAAK,IAAK2B,GAAM,CACf,MAAMC,EAAepC,IAAkBmC,EAAE,KACzC,OACEf,EAAAA,KAAC,MAAA,CAEC,cAAa,eAAee,EAAE,IAAI,GAClC,MAAO,CACL,QAAS,iBACT,aAAc,mBACd,OAAQ,0BACR,WAAY,kBAAA,EAGd,SAAA,CAAAf,OAACI,GAAO,MAAM,SAAS,QAAQ,UAAU,IAAK,EAC5C,SAAA,CAAAJ,OAACC,GAAM,IAAK,EAAG,MAAO,CAAE,SAAU,GAChC,SAAA,CAAAC,MAAC,QAAK,MAAO,CAAE,SAAU,cAAA,EAAmB,WAAE,KAAK,EACnDA,EAAAA,IAAC,OAAA,CAAK,MAAO,CAAE,SAAU,eAAgB,MAAO,iBAAA,EAAsB,SAAAa,EAAE,KAAA,CAAM,EAC7EA,EAAE,QACDf,OAAC,OAAA,CAAK,MAAO,CAAE,SAAU,eAAgB,MAAO,kBAAA,EAAsB,SAAA,CAAA,WAC3De,EAAE,OAAO,IAAEA,EAAE,UAAY,KAAKA,EAAE,SAAS,GAAK,EAAA,CAAA,CACzD,CAAA,EAEJ,EACAf,EAAAA,KAACI,EAAA,CAAO,IAAK,EACX,SAAA,CAAAF,EAAAA,IAACG,EAAA,CACC,QAAQ,QACR,QAAS,IAAM,KAAKb,EAAQuB,EAAE,IAAI,EAClC,SAAU/B,IAAY+B,EAAE,KACxB,cAAa,gBAAgBA,EAAE,IAAI,GACnC,aAAY,QAAQA,EAAE,IAAI,GAE1B,SAAAb,EAAAA,IAACe,EAAA,CAAa,KAAM,GAAI,cAAW,EAAA,CAAC,CAAA,CAAA,EAEtCf,EAAAA,IAACG,EAAA,CAAO,QAAQ,QAAQ,QAAS,IAAM5B,EAAWsC,EAAE,IAAI,EAAG,cAAa,gBAAgBA,EAAE,IAAI,GAAI,aAAY,QAAQA,EAAE,IAAI,GAC1H,SAAAb,EAAAA,IAACgB,EAAA,CAAO,KAAM,GAAI,cAAW,EAAA,CAAC,CAAA,CAChC,EACAhB,EAAAA,IAACG,EAAA,CACC,QAAQ,QACR,QAAS,IAAMxB,EAAkBsC,GAASA,IAAQJ,EAAE,KAAO,KAAOA,EAAE,IAAK,EACzE,cAAa,kBAAkBA,EAAE,IAAI,GACrC,aAAY,UAAUA,EAAE,IAAI,GAE5B,SAAAb,EAAAA,IAACkB,EAAA,CAAO,KAAM,GAAI,cAAW,EAAA,CAAC,CAAA,CAAA,CAChC,CAAA,CACF,CAAA,EACF,EACCJ,UACEZ,EAAA,CAAO,IAAK,EAAG,MAAO,CAAE,UAAW,gBAAA,EAClC,SAAA,CAAAF,EAAAA,IAACG,EAAA,CAAO,QAAQ,SAAS,QAAS,IAAM,KAAKN,EAAKgB,EAAE,IAAI,EAAG,cAAa,0BAA0BA,EAAE,IAAI,GAAI,SAAA,iBAE5G,EACAb,EAAAA,IAACG,EAAA,CAAO,QAAQ,QAAQ,QAAS,IAAMxB,EAAiB,IAAI,EAAG,cAAa,yBAAyBkC,EAAE,IAAI,GAAI,SAAA,QAAA,CAE/G,CAAA,EACF,EAED7B,IAAe,MAAQA,EAAW,OAAS6B,EAAE,MAC5Cf,EAAAA,KAAC,MAAA,CACC,cAAa,uBAAuBe,EAAE,IAAI,GAC1C,MAAO,CACL,UAAW,iBACX,SAAU,eACV,MAAO7B,EAAW,GAAK,iBAAmB,gBAC1C,WAAY,kBAAA,EAEf,SAAA,CAAA,SACQA,EAAW,OAAA,CAAA,CAAA,CACpB,CAAA,EA/DG6B,EAAE,IAAA,CAmEb,CAAC,CAAA,CACH,CAAA,CAEJ,EACF,EAEAb,EAAAA,IAACmB,EAAA,CAAM,KAAMhD,EAAQ,aAAcC,EACjC,SAAA4B,EAAAA,IAACoB,EAAA,CAAa,KAAK,QAAQ,MAAM,cAAc,YAAY,mCACzD,SAAApB,EAAAA,IAACqB,EAAA,CACC,KAAK,MACL,SAAU,MAAO9B,EAAM+B,IAAU,CAC/B,MAAM7B,EAAU,gBAAiB,CAAE,OAAQ,OAAQ,KAAM,CAAE,KAAAF,EAAM,MAAA+B,CAAA,EAAS,EAC1ElD,EAAU,EAAK,EACfgB,EAAA,CACF,EACA,SAAU,IAAMhB,EAAU,EAAK,CAAA,CAAA,EAEnC,CAAA,CACF,QAEC+C,EAAA,CAAM,KAAM7C,IAAY,KAAM,aAAeiD,GAAS,CAAOA,GAAMhD,EAAW,IAAI,CAAG,EACpF,SAAAyB,EAAAA,IAACoB,EAAA,CAAa,KAAK,QAAQ,MAAM,eAAe,YAAa9C,GAAW,GACrE,SAAAA,IAAY,MACX0B,EAAAA,IAACqB,EAAA,CACC,KAAK,OACL,YAAa/C,EACb,SAAU,MAAOiB,EAAM+B,IAAU,CAC/B,MAAM7B,EAAU,iBAAiBF,CAAI,GAAI,CAAE,OAAQ,MAAO,KAAM,CAAE,MAAA+B,CAAA,CAAM,CAAG,EAC3E/C,EAAW,IAAI,EACfa,EAAA,CACF,EACA,SAAU,IAAMb,EAAW,IAAI,CAAA,CAAA,EAGrC,CAAA,CACF,EAEAyB,EAAAA,IAACmB,EAAA,CAAM,KAAM3C,EAAe,aAAcC,EACxC,SAAAuB,EAAAA,IAACoB,EAAA,CAAa,KAAK,QAAQ,MAAM,cAAc,YAAY,4DACzD,SAAApB,EAAAA,IAACwB,EAAA,CACC,SAAU,MAAOC,GAAe,CAC9B,MAAMhC,EAAU,4BAA6B,CAC3C,OAAQ,OACR,KAAM,CAAE,WAAAgC,CAAA,CAAW,CACpB,EACDhD,EAAiB,EAAK,EACtBW,EAAA,CACF,EACA,SAAU,IAAMX,EAAiB,EAAK,CAAA,CAAA,EAE1C,CAAA,CACF,CAAA,EACF,CAEJ,CAEA,SAAS4C,EAAY,CACnB,KAAAK,EACA,YAAAC,EACA,SAAAC,EACA,SAAAC,CACF,EAKgB,CACd,KAAM,CAACtC,EAAMuC,CAAO,EAAIzD,EAAAA,SAAiBsD,GAAe,EAAE,EACpD,CAACL,EAAOS,CAAQ,EAAI1D,EAAAA,SAAiB,EAAE,EACvC,CAAC2D,EAAMC,CAAO,EAAI5D,EAAAA,SAAkB,EAAK,EACzC,CAACO,EAAOC,CAAQ,EAAIR,EAAAA,SAAwB,IAAI,EAEhD6D,EAAS,SAA2B,CACxC,GAAI,GAAC3C,EAAK,KAAA,GAAU,CAAC+B,GAASU,GAC9B,CAAAC,EAAQ,EAAI,EACZpD,EAAS,IAAI,EACb,GAAI,CACF,MAAM+C,EAASrC,EAAK,KAAA,EAAQ+B,CAAK,CACnC,OAAS5B,EAAK,CACZb,GAASa,aAAeE,EAAaF,EAAI,QAAgC,CAC3E,QAAA,CACEuC,EAAQ,EAAK,CACf,EACF,EAEA,OACEnC,EAAAA,KAACC,GAAM,IAAK,EAAG,MAAO,CAAE,QAAS,kBAC/B,SAAA,CAAAD,EAAAA,KAAC,QAAA,CAAM,MAAO,CAAE,QAAS,OAAQ,cAAe,SAAU,IAAK,gBAAA,EAC7D,SAAA,CAAAE,EAAAA,IAAC,OAAA,CAAK,MAAO,CAAE,SAAU,eAAgB,MAAO,iBAAA,EAAqB,SAAA,MAAA,CAAI,EACzEA,EAAAA,IAACmC,EAAA,CACC,MAAO5C,EACP,SAAUmC,IAAS,OACnB,cAAY,oBACZ,SAAWU,GAAMN,EAASM,EAAE,OAA4B,KAAK,CAAA,CAAA,CAC/D,EACF,EACAtC,EAAAA,KAAC,QAAA,CAAM,MAAO,CAAE,QAAS,OAAQ,cAAe,SAAU,IAAK,gBAAA,EAC7D,SAAA,CAAAE,EAAAA,IAAC,OAAA,CAAK,MAAO,CAAE,SAAU,eAAgB,MAAO,iBAAA,EAAqB,SAAA,OAAA,CAAK,EAC1EA,EAAAA,IAACmC,EAAA,CACC,KAAK,WACL,MAAAb,EACA,cAAY,qBACZ,SAAWc,GAAML,EAAUK,EAAE,OAA4B,KAAK,CAAA,CAAA,CAChE,EACF,EACCxD,IAAU,MACToB,EAAAA,IAAC,OAAA,CAAK,KAAK,QAAQ,MAAO,CAAE,MAAO,gBAAiB,SAAU,cAAA,EAAmB,SAAApB,EAAM,EAEzFkB,EAAAA,KAACI,EAAA,CAAO,QAAQ,MAAM,IAAK,EACzB,SAAA,CAAAF,EAAAA,IAACqC,EAAA,CAAW,QAAO,GACjB,SAAArC,EAAAA,IAACG,EAAA,CAAO,QAAQ,QAAQ,QAAS0B,EAAU,cAAY,sBAAsB,SAAA,QAAA,CAAM,EACrF,EACA7B,EAAAA,IAACG,EAAA,CACC,QAAQ,UACR,QAAS,IAAM,KAAK+B,EAAA,EACpB,SAAUF,GAAQ,CAACzC,EAAK,KAAA,GAAU,CAAC+B,EACnC,cAAY,sBAEX,SAAAI,IAAS,MAAQ,MAAQ,MAAA,CAAA,CAC5B,CAAA,CACF,CAAA,EACF,CAEJ,CAEA,SAASF,EAAe,CACtB,SAAAI,EACA,SAAAC,CACF,EAGgB,CACd,KAAM,CAACS,EAASC,CAAU,EAAIlE,EAAAA,SAAiB,EAAE,EAC3C,CAAC2D,EAAMC,CAAO,EAAI5D,EAAAA,SAAkB,EAAK,EACzC,CAACO,EAAOC,CAAQ,EAAIR,EAAAA,SAAwB,IAAI,EAEtD,OACEyB,EAAAA,KAACC,GAAM,IAAK,EAAG,MAAO,CAAE,QAAS,kBAC/B,SAAA,CAAAC,EAAAA,IAAC,WAAA,CACC,MAAOsC,EACP,YAAa;AAAA;AAAA,WACb,KAAM,GACN,cAAY,sBACZ,SAAWF,GAAMG,EAAYH,EAAE,OAA+B,KAAK,EACnE,MAAO,CACL,WAAY,mBACZ,OAAQ,0BACR,aAAc,mBACd,QAAS,iBACT,MAAO,YACP,WAAY,mBACZ,SAAU,eACV,OAAQ,UAAA,CACV,CAAA,EAEDxD,IAAU,MACToB,EAAAA,IAAC,OAAA,CAAK,KAAK,QAAQ,MAAO,CAAE,MAAO,gBAAiB,SAAU,cAAA,EAAmB,SAAApB,EAAM,EAEzFkB,EAAAA,KAACI,EAAA,CAAO,QAAQ,MAAM,IAAK,EACzB,SAAA,CAAAF,EAAAA,IAACqC,EAAA,CAAW,QAAO,GACjB,SAAArC,EAAAA,IAACG,EAAA,CAAO,QAAQ,QAAQ,QAAS0B,EAAU,SAAA,QAAA,CAAM,EACnD,EACA7B,EAAAA,IAACG,EAAA,CACC,QAAQ,UACR,QAAS,SAAY,CACnB8B,EAAQ,EAAI,EACZpD,EAAS,IAAI,EACb,GAAI,CAAE,MAAM+C,EAASU,CAAO,CAAG,OACxB5C,EAAK,CAAEb,GAASa,aAAeE,EAAaF,EAAI,QAAgC,CAAG,QAAA,CAChFuC,EAAQ,EAAK,CAAG,CAC5B,EACA,SAAUD,GAAQM,EAAQ,KAAA,IAAW,GACrC,cAAY,uBAEX,WAAO,aAAe,QAAA,CAAA,CACzB,CAAA,CACF,CAAA,EACF,CAEJ","x_google_ignoreList":[0]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as h,j as e}from"./cmdk-DVxytz9i.js";import{A as y}from"./Alert-
|
|
1
|
+
import{r as h,j as e}from"./cmdk-DVxytz9i.js";import{A as y}from"./Alert-CG5q_s75.js";import{d as f}from"./main-CokHAXWM.js";import{C as j}from"./circle-alert-DHvsqpw5.js";import{R as v}from"./refresh-ccw-DNrXX9gB.js";function u(t){return t==null?"":typeof t=="string"?t:t.message}const b=h.forwardRef(function(m,n){const{title:o="Something went wrong",description:s,error:x,onRetry:r,retryLabel:a="Retry",block:p=!1,silent:g=!1,testid:d,className:l,...c}=m,i=g?"":u(x);return p?e.jsxs("div",{ref:n,"data-testid":d??"error-state",className:l,style:{display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",gap:"var(--space-3)",padding:"var(--space-12) var(--space-6)",textAlign:"center",color:"var(--fg-muted)"},...c,children:[e.jsx("div",{style:{color:"var(--danger)",display:"inline-flex"},children:e.jsx(j,{size:28,"aria-hidden":!0})}),e.jsx("div",{style:{fontSize:"var(--fs-16)",fontWeight:600,color:"var(--fg)"},children:o}),s!==void 0&&e.jsx("div",{style:{fontSize:"var(--fs-13)",maxWidth:480},children:s}),i!==""&&e.jsx("code",{style:{fontSize:"var(--fs-12)",color:"var(--fg-subtle)"},children:i}),r!==void 0&&e.jsxs(f,{variant:"primary",onClick:r,"data-testid":"error-state-retry",children:[e.jsx(v,{size:14,"aria-hidden":!0})," ",a]})]}):e.jsx("div",{ref:n,"data-testid":d??"error-state",className:l,...c,children:e.jsxs(y,{tone:"danger",title:o,action:r!==void 0?e.jsxs(f,{variant:"ghost",onClick:r,"data-testid":"error-state-retry","aria-label":a,children:[e.jsx(v,{size:14,"aria-hidden":!0})," ",a]}):void 0,children:[s,i!==""&&e.jsx("div",{style:{marginTop:"var(--space-1)",fontFamily:"var(--font-mono)",fontSize:"var(--fs-12)"},children:i})]})})});export{b as E};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ErrorState-
|
|
1
|
+
{"version":3,"file":"ErrorState-BE3WBFqF.js","sources":["../../src/web/v8/ui/feedback/ErrorState.tsx"],"sourcesContent":["import { forwardRef, type HTMLAttributes, type ReactNode } from 'react';\nimport { AlertCircle, RefreshCcw } from 'lucide-react';\nimport { Alert } from './Alert.js';\nimport { Button } from '../controls/Button.js';\n\n/**\n * ErrorState — surfaced error with optional retry CTA.\n *\n * Use when a view's primary fetch failed and we want to recover,\n * not when the fetch succeeded with zero rows (use EmptyState).\n *\n * Two layout modes:\n * - inline (default): Alert-tone=danger banner with optional retry button\n * - block: centered icon + title + description + retry (mirrors EmptyState)\n *\n * `error` is the raw error (Error | string | null). When non-null,\n * the message is rendered below the title. Use the `silent` flag to\n * omit the message (e.g. when the parent already shows it).\n */\nexport interface ErrorStateProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {\n title?: ReactNode;\n description?: ReactNode;\n error?: Error | string | null;\n onRetry?: () => void;\n retryLabel?: string;\n /** Use the centered block layout instead of the inline Alert. */\n block?: boolean;\n /** Hide the error message (parent surfaces it elsewhere). */\n silent?: boolean;\n testid?: string;\n}\n\nfunction errMessage(error: Error | string | null | undefined): string {\n if (error === null || error === undefined) return '';\n return typeof error === 'string' ? error : error.message;\n}\n\nexport const ErrorState = forwardRef<HTMLDivElement, ErrorStateProps>(function ErrorState(\n props,\n ref,\n) {\n const {\n title = 'Something went wrong',\n description,\n error,\n onRetry,\n retryLabel = 'Retry',\n block = false,\n silent = false,\n testid,\n className,\n ...rest\n } = props;\n\n const message = silent ? '' : errMessage(error);\n\n if (block) {\n return (\n <div\n ref={ref}\n data-testid={testid ?? 'error-state'}\n className={className}\n style={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 'var(--space-3)',\n padding: 'var(--space-12) var(--space-6)',\n textAlign: 'center',\n color: 'var(--fg-muted)',\n }}\n {...rest}\n >\n <div style={{ color: 'var(--danger)', display: 'inline-flex' }}>\n <AlertCircle size={28} aria-hidden />\n </div>\n <div style={{ fontSize: 'var(--fs-16)', fontWeight: 600, color: 'var(--fg)' }}>{title}</div>\n {description !== undefined && (\n <div style={{ fontSize: 'var(--fs-13)', maxWidth: 480 }}>{description}</div>\n )}\n {message !== '' && (\n <code style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-subtle)' }}>{message}</code>\n )}\n {onRetry !== undefined && (\n <Button variant=\"primary\" onClick={onRetry} data-testid=\"error-state-retry\">\n <RefreshCcw size={14} aria-hidden /> {retryLabel}\n </Button>\n )}\n </div>\n );\n }\n\n return (\n <div ref={ref} data-testid={testid ?? 'error-state'} className={className} {...rest}>\n <Alert\n tone=\"danger\"\n title={title}\n action={\n onRetry !== undefined ? (\n <Button variant=\"ghost\" onClick={onRetry} data-testid=\"error-state-retry\" aria-label={retryLabel}>\n <RefreshCcw size={14} aria-hidden /> {retryLabel}\n </Button>\n ) : undefined\n }\n >\n {description}\n {message !== '' && (\n <div style={{ marginTop: 'var(--space-1)', fontFamily: 'var(--font-mono)', fontSize: 'var(--fs-12)' }}>\n {message}\n </div>\n )}\n </Alert>\n </div>\n );\n});"],"names":["errMessage","error","ErrorState","forwardRef","props","ref","title","description","onRetry","retryLabel","block","silent","testid","className","rest","message","jsxs","jsx","AlertCircle","Button","RefreshCcw","Alert"],"mappings":"0NAgCA,SAASA,EAAWC,EAAkD,CACpE,OAAIA,GAAU,KAAoC,GAC3C,OAAOA,GAAU,SAAWA,EAAQA,EAAM,OACnD,CAEO,MAAMC,EAAaC,EAAAA,WAA4C,SACpEC,EACAC,EACA,CACA,KAAM,CACJ,MAAAC,EAAQ,uBACR,YAAAC,EACA,MAAAN,EACA,QAAAO,EACA,WAAAC,EAAa,QACb,MAAAC,EAAQ,GACR,OAAAC,EAAS,GACT,OAAAC,EACA,UAAAC,EACA,GAAGC,CAAA,EACDV,EAEEW,EAAUJ,EAAS,GAAKX,EAAWC,CAAK,EAE9C,OAAIS,EAEAM,EAAAA,KAAC,MAAA,CACC,IAAAX,EACA,cAAaO,GAAU,cACvB,UAAAC,EACA,MAAO,CACL,QAAS,OACT,cAAe,SACf,WAAY,SACZ,eAAgB,SAChB,IAAK,iBACL,QAAS,iCACT,UAAW,SACX,MAAO,iBAAA,EAER,GAAGC,EAEJ,SAAA,CAAAG,EAAAA,IAAC,MAAA,CAAI,MAAO,CAAE,MAAO,gBAAiB,QAAS,aAAA,EAC7C,SAAAA,EAAAA,IAACC,EAAA,CAAY,KAAM,GAAI,cAAW,GAAC,EACrC,EACAD,EAAAA,IAAC,MAAA,CAAI,MAAO,CAAE,SAAU,eAAgB,WAAY,IAAK,MAAO,WAAA,EAAgB,SAAAX,CAAA,CAAM,EACrFC,IAAgB,QACfU,EAAAA,IAAC,MAAA,CAAI,MAAO,CAAE,SAAU,eAAgB,SAAU,GAAA,EAAQ,SAAAV,CAAA,CAAY,EAEvEQ,IAAY,IACXE,EAAAA,IAAC,OAAA,CAAK,MAAO,CAAE,SAAU,eAAgB,MAAO,kBAAA,EAAuB,SAAAF,CAAA,CAAQ,EAEhFP,IAAY,QACXQ,OAACG,EAAA,CAAO,QAAQ,UAAU,QAASX,EAAS,cAAY,oBACtD,SAAA,CAAAS,EAAAA,IAACG,EAAA,CAAW,KAAM,GAAI,cAAW,GAAC,EAAE,IAAEX,CAAA,CAAA,CACxC,CAAA,CAAA,CAAA,EAONQ,MAAC,OAAI,IAAAZ,EAAU,cAAaO,GAAU,cAAe,UAAAC,EAAuB,GAAGC,EAC7E,SAAAE,EAAAA,KAACK,EAAA,CACC,KAAK,SACL,MAAAf,EACA,OACEE,IAAY,OACVQ,EAAAA,KAACG,EAAA,CAAO,QAAQ,QAAQ,QAASX,EAAS,cAAY,oBAAoB,aAAYC,EACpF,SAAA,CAAAQ,EAAAA,IAACG,EAAA,CAAW,KAAM,GAAI,cAAW,GAAC,EAAE,IAAEX,CAAA,CAAA,CACxC,EACE,OAGL,SAAA,CAAAF,EACAQ,IAAY,IACXE,EAAAA,IAAC,MAAA,CAAI,MAAO,CAAE,UAAW,iBAAkB,WAAY,mBAAoB,SAAU,cAAA,EAClF,SAAAF,CAAA,CACH,CAAA,CAAA,CAAA,EAGN,CAEJ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r,j as e}from"./cmdk-DVxytz9i.js";import{u as P,S as i,I as s,d,J as q,h as T,O as I,B as f,i as j,F as y}from"./main-
|
|
1
|
+
import{r,j as e}from"./cmdk-DVxytz9i.js";import{u as P,S as i,I as s,d,J as q,h as T,O as I,B as f,i as j,F as y}from"./main-CokHAXWM.js";import{V as M}from"./ViewHeader-BzYZ3m-e.js";import{C as R,b as $}from"./Card-B0imhxMk.js";import{E as N}from"./EmptyState-BjgVOrcO.js";import{P as O}from"./play-BoLrrcBA.js";import{R as V}from"./refresh-cw-CoAHDpeS.js";import{C as J}from"./calendar-C0lgZk69.js";import{P as H}from"./plus-DENm0hqV.js";import{T as U}from"./trash-2-DZDjEnNh.js";function W(t){return t==="done"?"success":t==="failed"?"danger":t==="running"?"info":t==="queued"?"warning":"neutral"}function G(t){return!t||t<=0?"—":t<1e3?`${t}ms`:t<6e4?`${(t/1e3).toFixed(1)}s`:`${Math.floor(t/6e4)}m ${Math.round(t%6e4/1e3)}s`}function ne(){var E,F;const t=P("/api/eval/runs?limit=20"),g=P("/api/eval/schedules"),[o,b]=r.useState(!1),[v,A]=r.useState("default"),[C,l]=r.useState(null),[z,m]=r.useState(!1),[n,c]=r.useState({name:"",cron:"",suitePath:"default"}),[w,k]=r.useState(!1);r.useEffect(()=>{var a;if((a=t.data)!=null&&a.runs&&t.data.runs.some(h=>h.status==="running"||h.status==="queued")){const h=setTimeout(()=>{t.refetch()},5e3);return()=>clearTimeout(h)}},[t]);const L=async()=>{b(!0),l(null);try{await j("/api/eval/run",{method:"POST",body:{suite:v}}),t.refetch()}catch(a){l((a instanceof y,a.message))}finally{b(!1)}},p=((E=t.data)==null?void 0:E.runs)??[],B=async()=>{if(!(!n.name.trim()||!n.cron.trim())){k(!0),l(null);try{await j("/api/eval/schedules",{method:"POST",body:n}),m(!1),c({name:"",cron:"",suitePath:"default"}),g.refetch()}catch(a){l((a instanceof y,a.message))}finally{k(!1)}}},D=async a=>{l(null);try{await j(`/api/eval/schedules/${encodeURIComponent(a)}`,{method:"DELETE"}),g.refetch()}catch(u){l((u instanceof y,u.message))}},x=((F=g.data)==null?void 0:F.schedules)??[];return e.jsxs(i,{gap:5,"data-testid":"eval-view",children:[e.jsx(M,{title:"Eval framework",description:"Run evaluation suites against the agent model. Suites live under fixtures/.",actions:e.jsxs(s,{gap:2,align:"center",children:[C!==null&&e.jsx("span",{role:"alert",style:{color:"var(--danger)",fontSize:"var(--fs-12)"},children:C}),e.jsx("input",{value:v,onChange:a=>A(a.target.value),placeholder:"suite name",disabled:o,"data-testid":"eval-suite-input",style:{padding:"6px 10px",border:"1px solid var(--border)",borderRadius:"var(--radius-sm)",background:"var(--surface-0)",color:"var(--fg)",fontSize:"var(--fs-13)",fontFamily:"var(--font-mono)"}}),e.jsxs(d,{variant:"primary",onClick:()=>void L(),disabled:o||!v.trim(),"data-testid":"eval-launch",children:[o?e.jsx(q,{size:14,className:"animate-spin","aria-hidden":!0}):e.jsx(O,{size:14,"aria-hidden":!0}),o?"Launching…":"Run suite"]}),e.jsxs(d,{variant:"ghost",onClick:()=>void t.refetch(),"data-testid":"eval-refresh",children:[e.jsx(V,{size:14,"aria-hidden":!0})," Refresh"]})]})}),t.loading&&p.length===0?e.jsxs(i,{gap:2,children:[e.jsx(T,{style:{height:80}}),e.jsx(T,{style:{height:80}})]}):p.length===0?e.jsx(N,{icon:e.jsx(I,{size:32,"aria-hidden":!0}),title:"No eval runs yet",description:"Launch a suite to begin measuring agent quality."}):e.jsx(i,{gap:2,children:p.map(a=>e.jsx(R,{variant:"default",children:e.jsx($,{children:e.jsxs(s,{align:"center",justify:"between",gap:3,children:[e.jsxs(i,{gap:1,style:{flex:1,minWidth:0},children:[e.jsxs(s,{align:"center",gap:2,children:[e.jsx("strong",{style:{fontFamily:"var(--font-mono)",fontSize:"var(--fs-13)"},children:a.id}),e.jsx(f,{tone:W(a.status),children:a.status??"unknown"}),a.suite&&e.jsx(f,{tone:"neutral",children:a.suite})]}),e.jsxs(s,{align:"center",gap:3,style:{color:"var(--fg-muted)",fontSize:"var(--fs-12)"},children:[e.jsx("span",{children:a.startedAt?new Date(a.startedAt).toLocaleString():""}),e.jsx("span",{children:G(a.durationMs)})]})]}),e.jsxs(i,{align:"end",gap:0,children:[e.jsxs("span",{style:{fontFamily:"var(--font-mono)",fontSize:"var(--fs-14)"},children:[e.jsx("strong",{style:{color:"var(--success)"},children:a.passed??0})," pass"," / ",e.jsx("strong",{style:{color:"var(--danger)"},children:a.failed??0})," fail"]}),e.jsxs("span",{style:{fontSize:"var(--fs-12)",color:"var(--fg-muted)"},children:[a.total??0," total"]})]})]})})},a.id))}),e.jsx(R,{variant:"elevated",children:e.jsxs($,{children:[e.jsxs(s,{align:"center",justify:"between",gap:2,children:[e.jsxs(s,{align:"center",gap:2,children:[e.jsx(J,{size:16,"aria-hidden":!0}),e.jsx("strong",{style:{fontSize:"var(--fs-14)"},children:"Schedules"}),e.jsx(f,{tone:"neutral",children:x.length})]}),!z&&e.jsxs(d,{variant:"primary",onClick:()=>m(!0),"data-testid":"eval-schedule-add",children:[e.jsx(H,{size:14,"aria-hidden":!0})," Add schedule"]})]}),z&&e.jsxs(i,{gap:2,style:{marginTop:"var(--space-3)"},"data-testid":"eval-schedule-form",children:[e.jsxs(s,{gap:2,align:"center",children:[e.jsx("input",{value:n.name,onChange:a=>c({...n,name:a.target.value}),placeholder:"name","data-testid":"eval-schedule-form-name",style:S}),e.jsx("input",{value:n.cron,onChange:a=>c({...n,cron:a.target.value}),placeholder:"cron (e.g. 0 9 * * *)","data-testid":"eval-schedule-form-cron",style:S}),e.jsx("input",{value:n.suitePath,onChange:a=>c({...n,suitePath:a.target.value}),placeholder:"suite path","data-testid":"eval-schedule-form-suite",style:S})]}),e.jsxs(s,{gap:2,children:[e.jsx(d,{variant:"primary",onClick:()=>void B(),disabled:w,"data-testid":"eval-schedule-form-submit",children:w?"Saving…":"Save"}),e.jsx(d,{variant:"ghost",onClick:()=>m(!1),"data-testid":"eval-schedule-form-cancel",children:"Cancel"})]})]}),x.length===0?e.jsx("div",{style:{marginTop:"var(--space-2)",fontSize:"var(--fs-12)",color:"var(--fg-muted)"},children:"No schedules yet. Add one to run suites on a cron."}):e.jsx(i,{gap:2,style:{marginTop:"var(--space-3)"},children:x.map(a=>e.jsxs(s,{align:"center",justify:"between",gap:2,"data-testid":`eval-schedule-row-${a.id}`,children:[e.jsxs(s,{align:"center",gap:2,children:[e.jsx("strong",{style:{fontFamily:"var(--font-mono)",fontSize:"var(--fs-13)"},children:a.name}),e.jsx("code",{style:{fontSize:"var(--fs-12)",color:"var(--fg-muted)"},children:a.cron}),a.suitePath&&e.jsx(f,{tone:"neutral",children:a.suitePath})]}),e.jsx(d,{variant:"ghost",onClick:()=>void D(a.id),"data-testid":`eval-schedule-delete-${a.id}`,"aria-label":`Delete schedule ${a.name}`,children:e.jsx(U,{size:14,"aria-hidden":!0})})]},a.id))})]})})]})}const S={padding:"6px 10px",border:"1px solid var(--border)",borderRadius:"var(--radius-sm)",background:"var(--surface-0)",color:"var(--fg)",fontSize:"var(--fs-13)",fontFamily:"var(--font-mono)"};export{ne as EvalView};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EvalView-C9aYixXW.js","sources":["../../src/web/v8/views/Eval/EvalView.tsx"],"sourcesContent":["import { useEffect, useState } from 'react';\nimport { Calendar, FlaskConical, Play, Plus, RefreshCw, Trash2, Loader2 } from 'lucide-react';\nimport { Stack } from '../../ui/primitives/Stack.js';\nimport { Inline } from '../../ui/primitives/Inline.js';\nimport { ViewHeader } from '../../ui/data/ViewHeader.js';\nimport { Card, CardBody } from '../../ui/data/Card.js';\nimport { Badge } from '../../ui/data/Badge.js';\nimport { Button } from '../../ui/controls/Button.js';\nimport { Skeleton } from '../../ui/feedback/Skeleton.js';\nimport { EmptyState } from '../../ui/feedback/EmptyState.js';\nimport { useFetch } from '../../data/useFetch.js';\nimport { fetchJson, FetchError } from '../../data/fetcher.js';\n\n/**\n * EvalView — Sprint S35. Eval runs list + launch new suite.\n */\n\ntype Tone = 'neutral' | 'success' | 'warning' | 'danger' | 'info';\n\ninterface EvalRun {\n id: string;\n suite?: string;\n status?: 'queued' | 'running' | 'done' | 'failed';\n passed?: number;\n failed?: number;\n total?: number;\n startedAt?: string;\n durationMs?: number;\n}\n\ninterface EvalSchedule {\n id: string;\n name: string;\n cron: string;\n suitePath?: string;\n enabled?: boolean;\n}\n\nfunction statusTone(s: EvalRun['status'] | undefined): Tone {\n if (s === 'done') return 'success';\n if (s === 'failed') return 'danger';\n if (s === 'running') return 'info';\n if (s === 'queued') return 'warning';\n return 'neutral';\n}\n\nfunction fmtDuration(ms: number | undefined): string {\n if (!ms || ms <= 0) return '—';\n if (ms < 1000) return `${ms}ms`;\n if (ms < 60_000) return `${(ms / 1000).toFixed(1)}s`;\n return `${Math.floor(ms / 60_000)}m ${Math.round((ms % 60_000) / 1000)}s`;\n}\n\nexport function EvalView(): JSX.Element {\n const runs = useFetch<{ runs: EvalRun[] }>('/api/eval/runs?limit=20');\n const schedules = useFetch<{ schedules: EvalSchedule[] }>('/api/eval/schedules');\n const [launching, setLaunching] = useState(false);\n const [suite, setSuite] = useState('default');\n const [error, setError] = useState<string | null>(null);\n const [addingSchedule, setAddingSchedule] = useState(false);\n const [scheduleForm, setScheduleForm] = useState({ name: '', cron: '', suitePath: 'default' });\n const [busySchedule, setBusySchedule] = useState(false);\n\n useEffect(() => {\n if (runs.data?.runs) {\n const hasActive = runs.data.runs.some((r) => r.status === 'running' || r.status === 'queued');\n if (hasActive) {\n const id = setTimeout(() => { void runs.refetch(); }, 5_000);\n return () => clearTimeout(id);\n }\n }\n }, [runs]);\n\n const launch = async (): Promise<void> => {\n setLaunching(true);\n setError(null);\n try {\n await fetchJson('/api/eval/run', { method: 'POST', body: { suite } });\n void runs.refetch();\n } catch (err) {\n setError(err instanceof FetchError ? err.message : (err as Error).message);\n } finally {\n setLaunching(false);\n }\n };\n\n const list = runs.data?.runs ?? [];\n\n const addSchedule = async (): Promise<void> => {\n if (!scheduleForm.name.trim() || !scheduleForm.cron.trim()) return;\n setBusySchedule(true);\n setError(null);\n try {\n await fetchJson<{ ok?: boolean }>('/api/eval/schedules', { method: 'POST', body: scheduleForm });\n setAddingSchedule(false);\n setScheduleForm({ name: '', cron: '', suitePath: 'default' });\n void schedules.refetch();\n } catch (err) {\n setError(err instanceof FetchError ? err.message : (err as Error).message);\n } finally {\n setBusySchedule(false);\n }\n };\n\n const deleteSchedule = async (id: string): Promise<void> => {\n setError(null);\n try {\n await fetchJson(`/api/eval/schedules/${encodeURIComponent(id)}`, { method: 'DELETE' });\n void schedules.refetch();\n } catch (err) {\n setError(err instanceof FetchError ? err.message : (err as Error).message);\n }\n };\n\n const scheduleList = schedules.data?.schedules ?? [];\n\n return (\n <Stack gap={5} data-testid=\"eval-view\">\n <ViewHeader\n title=\"Eval framework\"\n description=\"Run evaluation suites against the agent model. Suites live under fixtures/.\"\n actions={\n <Inline gap={2} align=\"center\">\n {error !== null && <span role=\"alert\" style={{ color: 'var(--danger)', fontSize: 'var(--fs-12)' }}>{error}</span>}\n <input\n value={suite}\n onChange={(e) => setSuite(e.target.value)}\n placeholder=\"suite name\"\n disabled={launching}\n data-testid=\"eval-suite-input\"\n style={{\n padding: '6px 10px',\n border: '1px solid var(--border)',\n borderRadius: 'var(--radius-sm)',\n background: 'var(--surface-0)',\n color: 'var(--fg)',\n fontSize: 'var(--fs-13)',\n fontFamily: 'var(--font-mono)',\n }}\n />\n <Button variant=\"primary\" onClick={() => void launch()} disabled={launching || !suite.trim()} data-testid=\"eval-launch\">\n {launching ? <Loader2 size={14} className=\"animate-spin\" aria-hidden /> : <Play size={14} aria-hidden />}\n {launching ? 'Launching…' : 'Run suite'}\n </Button>\n <Button variant=\"ghost\" onClick={() => void runs.refetch()} data-testid=\"eval-refresh\">\n <RefreshCw size={14} aria-hidden /> Refresh\n </Button>\n </Inline>\n }\n />\n\n {runs.loading && list.length === 0 ? (\n <Stack gap={2}>\n <Skeleton style={{ height: 80 }} />\n <Skeleton style={{ height: 80 }} />\n </Stack>\n ) : list.length === 0 ? (\n <EmptyState\n icon={<FlaskConical size={32} aria-hidden />}\n title=\"No eval runs yet\"\n description=\"Launch a suite to begin measuring agent quality.\"\n />\n ) : (\n <Stack gap={2}>\n {list.map((r) => (\n <Card key={r.id} variant=\"default\">\n <CardBody>\n <Inline align=\"center\" justify=\"between\" gap={3}>\n <Stack gap={1} style={{ flex: 1, minWidth: 0 }}>\n <Inline align=\"center\" gap={2}>\n <strong style={{ fontFamily: 'var(--font-mono)', fontSize: 'var(--fs-13)' }}>{r.id}</strong>\n <Badge tone={statusTone(r.status)}>{r.status ?? 'unknown'}</Badge>\n {r.suite && <Badge tone=\"neutral\">{r.suite}</Badge>}\n </Inline>\n <Inline align=\"center\" gap={3} style={{ color: 'var(--fg-muted)', fontSize: 'var(--fs-12)' }}>\n <span>{r.startedAt ? new Date(r.startedAt).toLocaleString() : ''}</span>\n <span>{fmtDuration(r.durationMs)}</span>\n </Inline>\n </Stack>\n <Stack align=\"end\" gap={0}>\n <span style={{ fontFamily: 'var(--font-mono)', fontSize: 'var(--fs-14)' }}>\n <strong style={{ color: 'var(--success)' }}>{r.passed ?? 0}</strong> pass\n {' / '}\n <strong style={{ color: 'var(--danger)' }}>{r.failed ?? 0}</strong> fail\n </span>\n <span style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>{(r.total ?? 0)} total</span>\n </Stack>\n </Inline>\n </CardBody>\n </Card>\n ))}\n </Stack>\n )}\n\n <Card variant=\"elevated\">\n <CardBody>\n <Inline align=\"center\" justify=\"between\" gap={2}>\n <Inline align=\"center\" gap={2}>\n <Calendar size={16} aria-hidden />\n <strong style={{ fontSize: 'var(--fs-14)' }}>Schedules</strong>\n <Badge tone=\"neutral\">{scheduleList.length}</Badge>\n </Inline>\n {!addingSchedule && (\n <Button variant=\"primary\" onClick={() => setAddingSchedule(true)} data-testid=\"eval-schedule-add\">\n <Plus size={14} aria-hidden /> Add schedule\n </Button>\n )}\n </Inline>\n\n {addingSchedule && (\n <Stack gap={2} style={{ marginTop: 'var(--space-3)' }} data-testid=\"eval-schedule-form\">\n <Inline gap={2} align=\"center\">\n <input\n value={scheduleForm.name}\n onChange={(e) => setScheduleForm({ ...scheduleForm, name: e.target.value })}\n placeholder=\"name\"\n data-testid=\"eval-schedule-form-name\"\n style={inputStyle}\n />\n <input\n value={scheduleForm.cron}\n onChange={(e) => setScheduleForm({ ...scheduleForm, cron: e.target.value })}\n placeholder=\"cron (e.g. 0 9 * * *)\"\n data-testid=\"eval-schedule-form-cron\"\n style={inputStyle}\n />\n <input\n value={scheduleForm.suitePath}\n onChange={(e) => setScheduleForm({ ...scheduleForm, suitePath: e.target.value })}\n placeholder=\"suite path\"\n data-testid=\"eval-schedule-form-suite\"\n style={inputStyle}\n />\n </Inline>\n <Inline gap={2}>\n <Button variant=\"primary\" onClick={() => void addSchedule()} disabled={busySchedule} data-testid=\"eval-schedule-form-submit\">\n {busySchedule ? 'Saving…' : 'Save'}\n </Button>\n <Button variant=\"ghost\" onClick={() => setAddingSchedule(false)} data-testid=\"eval-schedule-form-cancel\">Cancel</Button>\n </Inline>\n </Stack>\n )}\n\n {scheduleList.length === 0 ? (\n <div style={{ marginTop: 'var(--space-2)', fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>\n No schedules yet. Add one to run suites on a cron.\n </div>\n ) : (\n <Stack gap={2} style={{ marginTop: 'var(--space-3)' }}>\n {scheduleList.map((s) => (\n <Inline key={s.id} align=\"center\" justify=\"between\" gap={2} data-testid={`eval-schedule-row-${s.id}`}>\n <Inline align=\"center\" gap={2}>\n <strong style={{ fontFamily: 'var(--font-mono)', fontSize: 'var(--fs-13)' }}>{s.name}</strong>\n <code style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>{s.cron}</code>\n {s.suitePath && <Badge tone=\"neutral\">{s.suitePath}</Badge>}\n </Inline>\n <Button variant=\"ghost\" onClick={() => void deleteSchedule(s.id)} data-testid={`eval-schedule-delete-${s.id}`} aria-label={`Delete schedule ${s.name}`}>\n <Trash2 size={14} aria-hidden />\n </Button>\n </Inline>\n ))}\n </Stack>\n )}\n </CardBody>\n </Card>\n </Stack>\n );\n}\n\nconst inputStyle = {\n padding: '6px 10px',\n border: '1px solid var(--border)',\n borderRadius: 'var(--radius-sm)',\n background: 'var(--surface-0)',\n color: 'var(--fg)',\n fontSize: 'var(--fs-13)',\n fontFamily: 'var(--font-mono)',\n} as const;"],"names":["statusTone","s","fmtDuration","ms","EvalView","runs","useFetch","schedules","launching","setLaunching","useState","suite","setSuite","error","setError","addingSchedule","setAddingSchedule","scheduleForm","setScheduleForm","busySchedule","setBusySchedule","useEffect","_a","r","id","launch","fetchJson","err","FetchError","list","addSchedule","deleteSchedule","scheduleList","_b","jsxs","Stack","jsx","ViewHeader","Inline","e","Button","Loader2","Play","RefreshCw","Skeleton","EmptyState","FlaskConical","Card","CardBody","Badge","Calendar","Plus","inputStyle","Trash2"],"mappings":"keAsCA,SAASA,EAAWC,EAAwC,CAC1D,OAAIA,IAAM,OAAe,UACrBA,IAAM,SAAiB,SACvBA,IAAM,UAAkB,OACxBA,IAAM,SAAiB,UACpB,SACT,CAEA,SAASC,EAAYC,EAAgC,CACnD,MAAI,CAACA,GAAMA,GAAM,EAAU,IACvBA,EAAK,IAAa,GAAGA,CAAE,KACvBA,EAAK,IAAe,IAAIA,EAAK,KAAM,QAAQ,CAAC,CAAC,IAC1C,GAAG,KAAK,MAAMA,EAAK,GAAM,CAAC,KAAK,KAAK,MAAOA,EAAK,IAAU,GAAI,CAAC,GACxE,CAEO,SAASC,IAAwB,SACtC,MAAMC,EAAOC,EAA8B,yBAAyB,EAC9DC,EAAYD,EAAwC,qBAAqB,EACzE,CAACE,EAAWC,CAAY,EAAIC,EAAAA,SAAS,EAAK,EAC1C,CAACC,EAAOC,CAAQ,EAAIF,EAAAA,SAAS,SAAS,EACtC,CAACG,EAAOC,CAAQ,EAAIJ,EAAAA,SAAwB,IAAI,EAChD,CAACK,EAAgBC,CAAiB,EAAIN,EAAAA,SAAS,EAAK,EACpD,CAACO,EAAcC,CAAe,EAAIR,EAAAA,SAAS,CAAE,KAAM,GAAI,KAAM,GAAI,UAAW,SAAA,CAAW,EACvF,CAACS,EAAcC,CAAe,EAAIV,EAAAA,SAAS,EAAK,EAEtDW,EAAAA,UAAU,IAAM,OACd,IAAIC,EAAAjB,EAAK,OAAL,MAAAiB,EAAW,MACKjB,EAAK,KAAK,KAAK,KAAMkB,GAAMA,EAAE,SAAW,WAAaA,EAAE,SAAW,QAAQ,EAC7E,CACb,MAAMC,EAAK,WAAW,IAAM,CAAOnB,EAAK,QAAA,CAAW,EAAG,GAAK,EAC3D,MAAO,IAAM,aAAamB,CAAE,CAC9B,CAEJ,EAAG,CAACnB,CAAI,CAAC,EAET,MAAMoB,EAAS,SAA2B,CACxChB,EAAa,EAAI,EACjBK,EAAS,IAAI,EACb,GAAI,CACF,MAAMY,EAAU,gBAAiB,CAAE,OAAQ,OAAQ,KAAM,CAAE,MAAAf,CAAA,EAAS,EAC/DN,EAAK,QAAA,CACZ,OAASsB,EAAK,CACZb,GAASa,aAAeC,EAAaD,EAAI,QAAgC,CAC3E,QAAA,CACElB,EAAa,EAAK,CACpB,CACF,EAEMoB,IAAOP,EAAAjB,EAAK,OAAL,YAAAiB,EAAW,OAAQ,CAAA,EAE1BQ,EAAc,SAA2B,CAC7C,GAAI,GAACb,EAAa,KAAK,KAAA,GAAU,CAACA,EAAa,KAAK,QACpD,CAAAG,EAAgB,EAAI,EACpBN,EAAS,IAAI,EACb,GAAI,CACF,MAAMY,EAA4B,sBAAuB,CAAE,OAAQ,OAAQ,KAAMT,EAAc,EAC/FD,EAAkB,EAAK,EACvBE,EAAgB,CAAE,KAAM,GAAI,KAAM,GAAI,UAAW,UAAW,EACvDX,EAAU,QAAA,CACjB,OAASoB,EAAK,CACZb,GAASa,aAAeC,EAAaD,EAAI,QAAgC,CAC3E,QAAA,CACEP,EAAgB,EAAK,CACvB,EACF,EAEMW,EAAiB,MAAOP,GAA8B,CAC1DV,EAAS,IAAI,EACb,GAAI,CACF,MAAMY,EAAU,uBAAuB,mBAAmBF,CAAE,CAAC,GAAI,CAAE,OAAQ,SAAU,EAChFjB,EAAU,QAAA,CACjB,OAASoB,EAAK,CACZb,GAASa,aAAeC,EAAaD,EAAI,QAAgC,CAC3E,CACF,EAEMK,IAAeC,EAAA1B,EAAU,OAAV,YAAA0B,EAAgB,YAAa,CAAA,EAElD,OACEC,EAAAA,KAACC,EAAA,CAAM,IAAK,EAAG,cAAY,YACzB,SAAA,CAAAC,EAAAA,IAACC,EAAA,CACC,MAAM,iBACN,YAAY,8EACZ,QACEH,EAAAA,KAACI,EAAA,CAAO,IAAK,EAAG,MAAM,SACnB,SAAA,CAAAzB,IAAU,MAAQuB,EAAAA,IAAC,OAAA,CAAK,KAAK,QAAQ,MAAO,CAAE,MAAO,gBAAiB,SAAU,cAAA,EAAmB,SAAAvB,EAAM,EAC1GuB,EAAAA,IAAC,QAAA,CACC,MAAOzB,EACP,SAAW4B,GAAM3B,EAAS2B,EAAE,OAAO,KAAK,EACxC,YAAY,aACZ,SAAU/B,EACV,cAAY,mBACZ,MAAO,CACL,QAAS,WACT,OAAQ,0BACR,aAAc,mBACd,WAAY,mBACZ,MAAO,YACP,SAAU,eACV,WAAY,kBAAA,CACd,CAAA,SAEDgC,EAAA,CAAO,QAAQ,UAAU,QAAS,IAAM,KAAKf,EAAA,EAAU,SAAUjB,GAAa,CAACG,EAAM,KAAA,EAAQ,cAAY,cACvG,SAAA,CAAAH,EAAY4B,EAAAA,IAACK,EAAA,CAAQ,KAAM,GAAI,UAAU,eAAe,cAAW,EAAA,CAAC,EAAKL,EAAAA,IAACM,EAAA,CAAK,KAAM,GAAI,cAAW,GAAC,EACrGlC,EAAY,aAAe,WAAA,EAC9B,EACA0B,EAAAA,KAACM,EAAA,CAAO,QAAQ,QAAQ,QAAS,IAAM,KAAKnC,EAAK,QAAA,EAAW,cAAY,eACtE,SAAA,CAAA+B,EAAAA,IAACO,EAAA,CAAU,KAAM,GAAI,cAAW,GAAC,EAAE,UAAA,CAAA,CACrC,CAAA,CAAA,CACF,CAAA,CAAA,EAIHtC,EAAK,SAAWwB,EAAK,SAAW,EAC/BK,OAACC,EAAA,CAAM,IAAK,EACV,SAAA,CAAAC,EAAAA,IAACQ,EAAA,CAAS,MAAO,CAAE,OAAQ,IAAM,QAChCA,EAAA,CAAS,MAAO,CAAE,OAAQ,GAAG,CAAG,CAAA,CAAA,CACnC,EACEf,EAAK,SAAW,EAClBO,EAAAA,IAACS,EAAA,CACC,KAAMT,EAAAA,IAACU,EAAA,CAAa,KAAM,GAAI,cAAW,GAAC,EAC1C,MAAM,mBACN,YAAY,kDAAA,CAAA,QAGbX,EAAA,CAAM,IAAK,EACT,SAAAN,EAAK,IAAKN,GACTa,EAAAA,IAACW,EAAA,CAAgB,QAAQ,UACvB,SAAAX,EAAAA,IAACY,GACC,SAAAd,EAAAA,KAACI,EAAA,CAAO,MAAM,SAAS,QAAQ,UAAU,IAAK,EAC5C,SAAA,CAAAJ,EAAAA,KAACC,EAAA,CAAM,IAAK,EAAG,MAAO,CAAE,KAAM,EAAG,SAAU,CAAA,EACzC,SAAA,CAAAD,EAAAA,KAACI,EAAA,CAAO,MAAM,SAAS,IAAK,EAC1B,SAAA,CAAAF,EAAAA,IAAC,SAAA,CAAO,MAAO,CAAE,WAAY,mBAAoB,SAAU,cAAA,EAAmB,SAAAb,EAAE,EAAA,CAAG,EACnFa,EAAAA,IAACa,GAAM,KAAMjD,EAAWuB,EAAE,MAAM,EAAI,SAAAA,EAAE,QAAU,SAAA,CAAU,EACzDA,EAAE,OAASa,EAAAA,IAACa,GAAM,KAAK,UAAW,WAAE,KAAA,CAAM,CAAA,EAC7C,EACAf,EAAAA,KAACI,EAAA,CAAO,MAAM,SAAS,IAAK,EAAG,MAAO,CAAE,MAAO,kBAAmB,SAAU,cAAA,EAC1E,SAAA,CAAAF,EAAAA,IAAC,OAAA,CAAM,SAAAb,EAAE,UAAY,IAAI,KAAKA,EAAE,SAAS,EAAE,eAAA,EAAmB,EAAA,CAAG,EACjEa,EAAAA,IAAC,OAAA,CAAM,SAAAlC,EAAYqB,EAAE,UAAU,CAAA,CAAE,CAAA,CAAA,CACnC,CAAA,EACF,EACAW,EAAAA,KAACC,EAAA,CAAM,MAAM,MAAM,IAAK,EACtB,SAAA,CAAAD,OAAC,QAAK,MAAO,CAAE,WAAY,mBAAoB,SAAU,gBACvD,SAAA,CAAAE,EAAAA,IAAC,SAAA,CAAO,MAAO,CAAE,MAAO,kBAAqB,SAAAb,EAAE,QAAU,CAAA,CAAE,EAAS,QACnE,MACDa,EAAAA,IAAC,UAAO,MAAO,CAAE,MAAO,eAAA,EAAoB,SAAAb,EAAE,QAAU,CAAA,CAAE,EAAS,OAAA,EACrE,EACAW,OAAC,QAAK,MAAO,CAAE,SAAU,eAAgB,MAAO,mBAAuB,SAAA,CAAAX,EAAE,OAAS,EAAG,QAAA,CAAA,CAAM,CAAA,CAAA,CAC7F,CAAA,CAAA,CACF,CAAA,CACF,CAAA,EAvBSA,EAAE,EAwBb,CACD,CAAA,CACH,EAGFa,MAACW,EAAA,CAAK,QAAQ,WACZ,gBAACC,EAAA,CACC,SAAA,CAAAd,OAACI,GAAO,MAAM,SAAS,QAAQ,UAAU,IAAK,EAC5C,SAAA,CAAAJ,EAAAA,KAACI,EAAA,CAAO,MAAM,SAAS,IAAK,EAC1B,SAAA,CAAAF,EAAAA,IAACc,EAAA,CAAS,KAAM,GAAI,cAAW,GAAC,QAC/B,SAAA,CAAO,MAAO,CAAE,SAAU,cAAA,EAAkB,SAAA,YAAS,EACtDd,EAAAA,IAACa,EAAA,CAAM,KAAK,UAAW,WAAa,MAAA,CAAO,CAAA,EAC7C,EACC,CAAClC,GACAmB,EAAAA,KAACM,EAAA,CAAO,QAAQ,UAAU,QAAS,IAAMxB,EAAkB,EAAI,EAAG,cAAY,oBAC5E,SAAA,CAAAoB,EAAAA,IAACe,EAAA,CAAK,KAAM,GAAI,cAAW,GAAC,EAAE,eAAA,CAAA,CAChC,CAAA,EAEJ,EAECpC,GACCmB,EAAAA,KAACC,EAAA,CAAM,IAAK,EAAG,MAAO,CAAE,UAAW,gBAAA,EAAoB,cAAY,qBACjE,SAAA,CAAAD,EAAAA,KAACI,EAAA,CAAO,IAAK,EAAG,MAAM,SACpB,SAAA,CAAAF,EAAAA,IAAC,QAAA,CACC,MAAOnB,EAAa,KACpB,SAAWsB,GAAMrB,EAAgB,CAAE,GAAGD,EAAc,KAAMsB,EAAE,OAAO,MAAO,EAC1E,YAAY,OACZ,cAAY,0BACZ,MAAOa,CAAA,CAAA,EAEThB,EAAAA,IAAC,QAAA,CACC,MAAOnB,EAAa,KACpB,SAAWsB,GAAMrB,EAAgB,CAAE,GAAGD,EAAc,KAAMsB,EAAE,OAAO,MAAO,EAC1E,YAAY,wBACZ,cAAY,0BACZ,MAAOa,CAAA,CAAA,EAEThB,EAAAA,IAAC,QAAA,CACC,MAAOnB,EAAa,UACpB,SAAWsB,GAAMrB,EAAgB,CAAE,GAAGD,EAAc,UAAWsB,EAAE,OAAO,MAAO,EAC/E,YAAY,aACZ,cAAY,2BACZ,MAAOa,CAAA,CAAA,CACT,EACF,EACAlB,EAAAA,KAACI,EAAA,CAAO,IAAK,EACX,SAAA,CAAAF,EAAAA,IAACI,EAAA,CAAO,QAAQ,UAAU,QAAS,IAAM,KAAKV,EAAA,EAAe,SAAUX,EAAc,cAAY,4BAC9F,SAAAA,EAAe,UAAY,OAC9B,EACAiB,EAAAA,IAACI,EAAA,CAAO,QAAQ,QAAQ,QAAS,IAAMxB,EAAkB,EAAK,EAAG,cAAY,4BAA4B,SAAA,QAAA,CAAM,CAAA,CAAA,CACjH,CAAA,EACF,EAGDgB,EAAa,SAAW,QACtB,MAAA,CAAI,MAAO,CAAE,UAAW,iBAAkB,SAAU,eAAgB,MAAO,iBAAA,EAAqB,8DAEjG,EAEAI,EAAAA,IAACD,GAAM,IAAK,EAAG,MAAO,CAAE,UAAW,gBAAA,EAChC,WAAa,IAAKlC,GACjBiC,EAAAA,KAACI,EAAA,CAAkB,MAAM,SAAS,QAAQ,UAAU,IAAK,EAAG,cAAa,qBAAqBrC,EAAE,EAAE,GAChG,SAAA,CAAAiC,EAAAA,KAACI,EAAA,CAAO,MAAM,SAAS,IAAK,EAC1B,SAAA,CAAAF,EAAAA,IAAC,SAAA,CAAO,MAAO,CAAE,WAAY,mBAAoB,SAAU,cAAA,EAAmB,SAAAnC,EAAE,IAAA,CAAK,EACrFmC,EAAAA,IAAC,OAAA,CAAK,MAAO,CAAE,SAAU,eAAgB,MAAO,iBAAA,EAAsB,SAAAnC,EAAE,IAAA,CAAK,EAC5EA,EAAE,WAAamC,EAAAA,IAACa,GAAM,KAAK,UAAW,WAAE,SAAA,CAAU,CAAA,EACrD,EACAb,EAAAA,IAACI,EAAA,CAAO,QAAQ,QAAQ,QAAS,IAAM,KAAKT,EAAe9B,EAAE,EAAE,EAAG,cAAa,wBAAwBA,EAAE,EAAE,GAAI,aAAY,mBAAmBA,EAAE,IAAI,GAClJ,SAAAmC,EAAAA,IAACiB,EAAA,CAAO,KAAM,GAAI,cAAW,EAAA,CAAC,CAAA,CAChC,CAAA,GARWpD,EAAE,EASf,CACD,CAAA,CACH,CAAA,CAAA,CAEJ,CAAA,CACF,CAAA,EACF,CAEJ,CAEA,MAAMmD,EAAa,CACjB,QAAS,WACT,OAAQ,0BACR,aAAc,mBACd,WAAY,mBACZ,MAAO,YACP,SAAU,eACV,WAAY,kBACd"}
|
|
1
|
+
{"version":3,"file":"EvalView-BJJ2P-kK.js","sources":["../../src/web/v8/views/Eval/EvalView.tsx"],"sourcesContent":["import { useEffect, useState } from 'react';\nimport { Calendar, FlaskConical, Play, Plus, RefreshCw, Trash2, Loader2 } from 'lucide-react';\nimport { Stack } from '../../ui/primitives/Stack.js';\nimport { Inline } from '../../ui/primitives/Inline.js';\nimport { ViewHeader } from '../../ui/data/ViewHeader.js';\nimport { Card, CardBody } from '../../ui/data/Card.js';\nimport { Badge } from '../../ui/data/Badge.js';\nimport { Button } from '../../ui/controls/Button.js';\nimport { Skeleton } from '../../ui/feedback/Skeleton.js';\nimport { EmptyState } from '../../ui/feedback/EmptyState.js';\nimport { useFetch } from '../../data/useFetch.js';\nimport { fetchJson, FetchError } from '../../data/fetcher.js';\n\n/**\n * EvalView — Sprint S35. Eval runs list + launch new suite.\n */\n\ntype Tone = 'neutral' | 'success' | 'warning' | 'danger' | 'info';\n\ninterface EvalRun {\n id: string;\n suite?: string;\n status?: 'queued' | 'running' | 'done' | 'failed';\n passed?: number;\n failed?: number;\n total?: number;\n startedAt?: string;\n durationMs?: number;\n}\n\ninterface EvalSchedule {\n id: string;\n name: string;\n cron: string;\n suitePath?: string;\n enabled?: boolean;\n}\n\nfunction statusTone(s: EvalRun['status'] | undefined): Tone {\n if (s === 'done') return 'success';\n if (s === 'failed') return 'danger';\n if (s === 'running') return 'info';\n if (s === 'queued') return 'warning';\n return 'neutral';\n}\n\nfunction fmtDuration(ms: number | undefined): string {\n if (!ms || ms <= 0) return '—';\n if (ms < 1000) return `${ms}ms`;\n if (ms < 60_000) return `${(ms / 1000).toFixed(1)}s`;\n return `${Math.floor(ms / 60_000)}m ${Math.round((ms % 60_000) / 1000)}s`;\n}\n\nexport function EvalView(): JSX.Element {\n const runs = useFetch<{ runs: EvalRun[] }>('/api/eval/runs?limit=20');\n const schedules = useFetch<{ schedules: EvalSchedule[] }>('/api/eval/schedules');\n const [launching, setLaunching] = useState(false);\n const [suite, setSuite] = useState('default');\n const [error, setError] = useState<string | null>(null);\n const [addingSchedule, setAddingSchedule] = useState(false);\n const [scheduleForm, setScheduleForm] = useState({ name: '', cron: '', suitePath: 'default' });\n const [busySchedule, setBusySchedule] = useState(false);\n\n useEffect(() => {\n if (runs.data?.runs) {\n const hasActive = runs.data.runs.some((r) => r.status === 'running' || r.status === 'queued');\n if (hasActive) {\n const id = setTimeout(() => { void runs.refetch(); }, 5_000);\n return () => clearTimeout(id);\n }\n }\n }, [runs]);\n\n const launch = async (): Promise<void> => {\n setLaunching(true);\n setError(null);\n try {\n await fetchJson('/api/eval/run', { method: 'POST', body: { suite } });\n void runs.refetch();\n } catch (err) {\n setError(err instanceof FetchError ? err.message : (err as Error).message);\n } finally {\n setLaunching(false);\n }\n };\n\n const list = runs.data?.runs ?? [];\n\n const addSchedule = async (): Promise<void> => {\n if (!scheduleForm.name.trim() || !scheduleForm.cron.trim()) return;\n setBusySchedule(true);\n setError(null);\n try {\n await fetchJson<{ ok?: boolean }>('/api/eval/schedules', { method: 'POST', body: scheduleForm });\n setAddingSchedule(false);\n setScheduleForm({ name: '', cron: '', suitePath: 'default' });\n void schedules.refetch();\n } catch (err) {\n setError(err instanceof FetchError ? err.message : (err as Error).message);\n } finally {\n setBusySchedule(false);\n }\n };\n\n const deleteSchedule = async (id: string): Promise<void> => {\n setError(null);\n try {\n await fetchJson(`/api/eval/schedules/${encodeURIComponent(id)}`, { method: 'DELETE' });\n void schedules.refetch();\n } catch (err) {\n setError(err instanceof FetchError ? err.message : (err as Error).message);\n }\n };\n\n const scheduleList = schedules.data?.schedules ?? [];\n\n return (\n <Stack gap={5} data-testid=\"eval-view\">\n <ViewHeader\n title=\"Eval framework\"\n description=\"Run evaluation suites against the agent model. Suites live under fixtures/.\"\n actions={\n <Inline gap={2} align=\"center\">\n {error !== null && <span role=\"alert\" style={{ color: 'var(--danger)', fontSize: 'var(--fs-12)' }}>{error}</span>}\n <input\n value={suite}\n onChange={(e) => setSuite(e.target.value)}\n placeholder=\"suite name\"\n disabled={launching}\n data-testid=\"eval-suite-input\"\n style={{\n padding: '6px 10px',\n border: '1px solid var(--border)',\n borderRadius: 'var(--radius-sm)',\n background: 'var(--surface-0)',\n color: 'var(--fg)',\n fontSize: 'var(--fs-13)',\n fontFamily: 'var(--font-mono)',\n }}\n />\n <Button variant=\"primary\" onClick={() => void launch()} disabled={launching || !suite.trim()} data-testid=\"eval-launch\">\n {launching ? <Loader2 size={14} className=\"animate-spin\" aria-hidden /> : <Play size={14} aria-hidden />}\n {launching ? 'Launching…' : 'Run suite'}\n </Button>\n <Button variant=\"ghost\" onClick={() => void runs.refetch()} data-testid=\"eval-refresh\">\n <RefreshCw size={14} aria-hidden /> Refresh\n </Button>\n </Inline>\n }\n />\n\n {runs.loading && list.length === 0 ? (\n <Stack gap={2}>\n <Skeleton style={{ height: 80 }} />\n <Skeleton style={{ height: 80 }} />\n </Stack>\n ) : list.length === 0 ? (\n <EmptyState\n icon={<FlaskConical size={32} aria-hidden />}\n title=\"No eval runs yet\"\n description=\"Launch a suite to begin measuring agent quality.\"\n />\n ) : (\n <Stack gap={2}>\n {list.map((r) => (\n <Card key={r.id} variant=\"default\">\n <CardBody>\n <Inline align=\"center\" justify=\"between\" gap={3}>\n <Stack gap={1} style={{ flex: 1, minWidth: 0 }}>\n <Inline align=\"center\" gap={2}>\n <strong style={{ fontFamily: 'var(--font-mono)', fontSize: 'var(--fs-13)' }}>{r.id}</strong>\n <Badge tone={statusTone(r.status)}>{r.status ?? 'unknown'}</Badge>\n {r.suite && <Badge tone=\"neutral\">{r.suite}</Badge>}\n </Inline>\n <Inline align=\"center\" gap={3} style={{ color: 'var(--fg-muted)', fontSize: 'var(--fs-12)' }}>\n <span>{r.startedAt ? new Date(r.startedAt).toLocaleString() : ''}</span>\n <span>{fmtDuration(r.durationMs)}</span>\n </Inline>\n </Stack>\n <Stack align=\"end\" gap={0}>\n <span style={{ fontFamily: 'var(--font-mono)', fontSize: 'var(--fs-14)' }}>\n <strong style={{ color: 'var(--success)' }}>{r.passed ?? 0}</strong> pass\n {' / '}\n <strong style={{ color: 'var(--danger)' }}>{r.failed ?? 0}</strong> fail\n </span>\n <span style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>{(r.total ?? 0)} total</span>\n </Stack>\n </Inline>\n </CardBody>\n </Card>\n ))}\n </Stack>\n )}\n\n <Card variant=\"elevated\">\n <CardBody>\n <Inline align=\"center\" justify=\"between\" gap={2}>\n <Inline align=\"center\" gap={2}>\n <Calendar size={16} aria-hidden />\n <strong style={{ fontSize: 'var(--fs-14)' }}>Schedules</strong>\n <Badge tone=\"neutral\">{scheduleList.length}</Badge>\n </Inline>\n {!addingSchedule && (\n <Button variant=\"primary\" onClick={() => setAddingSchedule(true)} data-testid=\"eval-schedule-add\">\n <Plus size={14} aria-hidden /> Add schedule\n </Button>\n )}\n </Inline>\n\n {addingSchedule && (\n <Stack gap={2} style={{ marginTop: 'var(--space-3)' }} data-testid=\"eval-schedule-form\">\n <Inline gap={2} align=\"center\">\n <input\n value={scheduleForm.name}\n onChange={(e) => setScheduleForm({ ...scheduleForm, name: e.target.value })}\n placeholder=\"name\"\n data-testid=\"eval-schedule-form-name\"\n style={inputStyle}\n />\n <input\n value={scheduleForm.cron}\n onChange={(e) => setScheduleForm({ ...scheduleForm, cron: e.target.value })}\n placeholder=\"cron (e.g. 0 9 * * *)\"\n data-testid=\"eval-schedule-form-cron\"\n style={inputStyle}\n />\n <input\n value={scheduleForm.suitePath}\n onChange={(e) => setScheduleForm({ ...scheduleForm, suitePath: e.target.value })}\n placeholder=\"suite path\"\n data-testid=\"eval-schedule-form-suite\"\n style={inputStyle}\n />\n </Inline>\n <Inline gap={2}>\n <Button variant=\"primary\" onClick={() => void addSchedule()} disabled={busySchedule} data-testid=\"eval-schedule-form-submit\">\n {busySchedule ? 'Saving…' : 'Save'}\n </Button>\n <Button variant=\"ghost\" onClick={() => setAddingSchedule(false)} data-testid=\"eval-schedule-form-cancel\">Cancel</Button>\n </Inline>\n </Stack>\n )}\n\n {scheduleList.length === 0 ? (\n <div style={{ marginTop: 'var(--space-2)', fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>\n No schedules yet. Add one to run suites on a cron.\n </div>\n ) : (\n <Stack gap={2} style={{ marginTop: 'var(--space-3)' }}>\n {scheduleList.map((s) => (\n <Inline key={s.id} align=\"center\" justify=\"between\" gap={2} data-testid={`eval-schedule-row-${s.id}`}>\n <Inline align=\"center\" gap={2}>\n <strong style={{ fontFamily: 'var(--font-mono)', fontSize: 'var(--fs-13)' }}>{s.name}</strong>\n <code style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>{s.cron}</code>\n {s.suitePath && <Badge tone=\"neutral\">{s.suitePath}</Badge>}\n </Inline>\n <Button variant=\"ghost\" onClick={() => void deleteSchedule(s.id)} data-testid={`eval-schedule-delete-${s.id}`} aria-label={`Delete schedule ${s.name}`}>\n <Trash2 size={14} aria-hidden />\n </Button>\n </Inline>\n ))}\n </Stack>\n )}\n </CardBody>\n </Card>\n </Stack>\n );\n}\n\nconst inputStyle = {\n padding: '6px 10px',\n border: '1px solid var(--border)',\n borderRadius: 'var(--radius-sm)',\n background: 'var(--surface-0)',\n color: 'var(--fg)',\n fontSize: 'var(--fs-13)',\n fontFamily: 'var(--font-mono)',\n} as const;"],"names":["statusTone","s","fmtDuration","ms","EvalView","runs","useFetch","schedules","launching","setLaunching","useState","suite","setSuite","error","setError","addingSchedule","setAddingSchedule","scheduleForm","setScheduleForm","busySchedule","setBusySchedule","useEffect","_a","r","id","launch","fetchJson","err","FetchError","list","addSchedule","deleteSchedule","scheduleList","_b","jsxs","Stack","jsx","ViewHeader","Inline","e","Button","Loader2","Play","RefreshCw","Skeleton","EmptyState","FlaskConical","Card","CardBody","Badge","Calendar","Plus","inputStyle","Trash2"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{j as e,r}from"./cmdk-DVxytz9i.js";import{B as F,g as q,S as f,I as C,d as b,h as K,i as R,u as Q,a as V}from"./main-
|
|
1
|
+
import{j as e,r}from"./cmdk-DVxytz9i.js";import{B as F,g as q,S as f,I as C,d as b,h as K,i as R,u as Q,a as V}from"./main-CokHAXWM.js";import{G as X}from"./Grid-qcvbhx6e.js";import{C as Y}from"./Chip-wwZSGwLE.js";import{C as Z,V as ee}from"./ViewHeader-BzYZ3m-e.js";import{P as te}from"./ProgressBar-DlZTETEn.js";import{C as se}from"./calendar-C0lgZk69.js";import{S as _,a as M}from"./Sheet-DnDid58j.js";import{I as P}from"./Input-Bgzxf_Hu.js";import{S as ae,a as le,b as re,c as ne}from"./Select-Dbd88_n8.js";import{E as ie}from"./external-link-0NqUhI4i.js";import{T as W}from"./trash-2-DZDjEnNh.js";import{P as H}from"./plus-DENm0hqV.js";import{C as oe,b as de}from"./Card-B0imhxMk.js";import{E as ce}from"./ErrorState-BE3WBFqF.js";import{L as ue}from"./ListHeader-TjPJrUfY.js";import{T as ge}from"./Textarea-BzIAwSlp.js";import"./index-C4Vq_2LM.js";import"./index-CASP1n-5.js";import"./Alert-CG5q_s75.js";import"./circle-alert-DHvsqpw5.js";import"./triangle-alert-_2xe_tl4.js";import"./circle-check-Bx8wmXR9.js";import"./refresh-ccw-DNrXX9gB.js";const fe={"on-track":"On track","at-risk":"At risk","off-track":"Off track",done:"Done"},he={"on-track":"success","at-risk":"warning","off-track":"danger",done:"neutral"};function pe(i){const{title:l,description:u,status:p,progress:D,due:g,ownerName:m,ownerAvatarUrl:h,keyResultsDone:w,keyResultsTotal:I,badges:E,onOpen:z,className:j}=i;return e.jsxs("button",{type:"button",onClick:z,className:q("v8-goal-card",`v8-goal-card--${p}`,j),style:{display:"flex",flexDirection:"column",gap:"var(--space-3)",width:"100%",padding:"var(--space-4)",background:"var(--surface-1)",border:"1px solid var(--border)",borderRadius:"var(--radius-lg)",textAlign:"left",cursor:"pointer",font:"inherit",color:"inherit",transition:"border-color var(--motion-fast) var(--ease-out), background var(--motion-fast) var(--ease-out)"},children:[e.jsxs("div",{style:{display:"flex",alignItems:"flex-start",justifyContent:"space-between",gap:"var(--space-2)"},children:[e.jsxs("div",{style:{flex:1,minWidth:0},children:[e.jsx("div",{style:{fontSize:"var(--fs-14)",fontWeight:600,color:"var(--fg)",lineHeight:"var(--lh-snug)"},children:l}),u!==void 0&&e.jsx("div",{style:{fontSize:"var(--fs-13)",color:"var(--fg-muted)",marginTop:4,display:"-webkit-box",WebkitLineClamp:2,WebkitBoxOrient:"vertical",overflow:"hidden"},children:u})]}),e.jsx(F,{tone:he[p],dot:!0,children:fe[p]})]}),e.jsxs("div",{children:[e.jsx(te,{value:D,tone:p==="on-track"?"success":p==="at-risk"?"warning":p==="off-track"?"danger":"accent"}),e.jsxs("div",{style:{display:"flex",justifyContent:"space-between",marginTop:6,fontSize:"var(--fs-12)",color:"var(--fg-muted)",fontVariantNumeric:"tabular-nums"},children:[e.jsxs("span",{children:[Math.round(D*100),"% complete"]}),w!==void 0&&I!==void 0&&e.jsxs("span",{children:[w," / ",I," key results"]})]})]}),e.jsxs("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",gap:"var(--space-2)",fontSize:"var(--fs-12)",color:"var(--fg-subtle)"},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:"var(--space-3)"},children:[g!==void 0&&e.jsxs("span",{style:{display:"inline-flex",alignItems:"center",gap:4},children:[e.jsx(se,{size:12,"aria-hidden":"true"}),g]}),m!==void 0&&e.jsxs("span",{style:{display:"inline-flex",alignItems:"center",gap:6},children:[e.jsx("span",{"aria-hidden":"true",style:{width:16,height:16,borderRadius:"var(--radius-pill)",background:h!==void 0?`url(${h}) center/cover`:"var(--accent)",display:"inline-block"}}),m]})]}),e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:"var(--space-2)"},children:[E,e.jsx(Z,{size:14,"aria-hidden":"true",style:{color:"var(--fg-subtle)"}})]})]}),e.jsx("style",{children:`
|
|
2
2
|
.v8-goal-card:hover {
|
|
3
3
|
border-color: var(--accent);
|
|
4
4
|
background: var(--surface-2);
|