@polderlabs/bizar 10.0.7 → 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/src/server/api.mjs +13 -6
- 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/diagnostics-store.mjs +5 -35
- package/bizar-dash/src/server/mod-security.mjs +1 -2
- package/bizar-dash/src/server/providers-store.mjs +1 -1
- package/bizar-dash/src/server/routes/_shared.mjs +0 -17
- 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/model-router.mjs +158 -0
- package/bizar-dash/src/server/routes/model-router.test.mjs +104 -0
- package/bizar-dash/src/server/routes/sessions.mjs +80 -0
- package/bizar-dash/src/server/server.mjs +1 -27
- 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/cli-bugfixes.test.mjs +1 -1
- package/bizar-dash/tests/cli-error-visibility.test.mjs +1 -1
- package/bizar-dash/tests/cli-refactor.test.mjs +0 -1
- package/bizar-dash/tests/diagnostics-store.test.mjs +0 -1
- package/cli/bin.mjs +1 -15
- package/cli/cli-commands-validation.test.mjs +1 -1
- package/cli/commands/lightrag.mjs +1 -1
- package/cli/commands/util.mjs +1 -1
- package/cli/copy.mjs +1 -47
- package/cli/doctor.mjs +3 -3
- package/cli/install.mjs +3 -37
- package/cli/service-controller.mjs +0 -192
- package/cli/service-env.mjs +2 -9
- package/cli/utils.mjs +0 -7
- 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/check-deps.mjs +0 -24
- 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
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* scripts/audit.mjs
|
|
3
|
+
*
|
|
4
|
+
* Pillar B — Self-auditing: harness score 0-100 across 12 categories.
|
|
5
|
+
*
|
|
6
|
+
* Each category scores 0-10. Weighted sum gives 0-100.
|
|
7
|
+
* Deterministic — same repo state always yields same score.
|
|
8
|
+
* Evidence string captured per category for transparency.
|
|
9
|
+
*
|
|
10
|
+
* Categories:
|
|
11
|
+
* typecheck tests e2e arch-boundaries security-patterns
|
|
12
|
+
* doc-sync feature-list-state clean-state perf-budget
|
|
13
|
+
* coverage observability drift
|
|
14
|
+
*
|
|
15
|
+
* Usage:
|
|
16
|
+
* node scripts/audit.mjs → JSON to stdout
|
|
17
|
+
* node scripts/audit.mjs --write → also write .harness/audit/latest.json
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { execSync } from 'node:child_process';
|
|
21
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync, readdirSync } from 'node:fs';
|
|
22
|
+
import { join, dirname, resolve } from 'node:path';
|
|
23
|
+
import { fileURLToPath } from 'node:url';
|
|
24
|
+
|
|
25
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
26
|
+
const ROOT = resolve(__dirname, '..');
|
|
27
|
+
const HARNESS_AUDIT_DIR = join(ROOT, '.harness', 'audit');
|
|
28
|
+
const LATEST_PATH = join(HARNESS_AUDIT_DIR, 'latest.json');
|
|
29
|
+
const FEATURE_LIST = join(ROOT, 'feature_list.json');
|
|
30
|
+
const PROGRESS_MD = join(ROOT, '.bizar', 'PROGRESS.md');
|
|
31
|
+
const ARCH_RULES = join(ROOT, '.harness', 'arch-rules.json');
|
|
32
|
+
const CLAUDE_MD = join(ROOT, 'CLAUDE.md');
|
|
33
|
+
const AGENTS_MD = join(ROOT, 'AGENTS.md');
|
|
34
|
+
|
|
35
|
+
const WRITE = process.argv.includes('--write');
|
|
36
|
+
|
|
37
|
+
// ── Category definitions ──────────────────────────────────────────────────────
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @typedef {{ score: number, evidence: string }} CategoryResult
|
|
41
|
+
* @typedef {Record<string, CategoryResult>} AuditResult
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
/** Run a shell command, return {ok, stdout, stderr, exitCode}. */
|
|
45
|
+
function run(cmd, cwd = ROOT) {
|
|
46
|
+
try {
|
|
47
|
+
const stdout = execSync(cmd, { cwd, encoding: 'utf8', timeout: 120_000 });
|
|
48
|
+
return { ok: true, stdout: stdout.trim(), stderr: '', exitCode: 0 };
|
|
49
|
+
} catch (err) {
|
|
50
|
+
return {
|
|
51
|
+
ok: false,
|
|
52
|
+
stdout: err.stdout?.trim() ?? '',
|
|
53
|
+
stderr: err.stderr?.trim() ?? '',
|
|
54
|
+
exitCode: err.status ?? 1,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Score 10 if ok, 0 if not. */
|
|
60
|
+
function scoreOk(r) {
|
|
61
|
+
return r.exitCode === 0 ? 10 : 0;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Score 10 if pass in last line, 0 otherwise. */
|
|
65
|
+
function scorePassInLastLine(r) {
|
|
66
|
+
if (r.exitCode !== 0) return 0;
|
|
67
|
+
const lines = r.stdout.split('\n');
|
|
68
|
+
const last = lines[lines.length - 1]?.toLowerCase() ?? '';
|
|
69
|
+
return last.includes('pass') || last.includes('ok') || last.includes('0 errors') ? 10 : 5;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// ── Individual category checks ────────────────────────────────────────────────
|
|
73
|
+
|
|
74
|
+
function checkTypecheck() {
|
|
75
|
+
const r = run('bunx tsc --noEmit 2>&1');
|
|
76
|
+
const score = r.exitCode === 0 ? 10 : 0;
|
|
77
|
+
const evidence = score === 10
|
|
78
|
+
? 'bunx tsc --noEmit exited 0'
|
|
79
|
+
: `bunx tsc --noEmit failed:\n${r.stdout.split('\n').slice(-3).join('\n')}`;
|
|
80
|
+
return { score, evidence };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function checkTests() {
|
|
84
|
+
// Run make test and look for pass/fail summary in last 5 lines
|
|
85
|
+
const r = run('make test 2>&1');
|
|
86
|
+
const lines = r.stdout.split('\n').slice(-5).join(' ');
|
|
87
|
+
const lower = lines.toLowerCase();
|
|
88
|
+
let score = 0;
|
|
89
|
+
if (lower.includes('pass') || lower.includes('ok')) score = 10;
|
|
90
|
+
else if (r.exitCode === 0) score = 10;
|
|
91
|
+
else score = 0;
|
|
92
|
+
const evidence = `make test exit ${r.exitCode}: ${lines.slice(-100)}`;
|
|
93
|
+
return { score, evidence };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function checkE2e() {
|
|
97
|
+
const r = run('bun run scripts/bh-full-e2e.mjs 2>&1');
|
|
98
|
+
const lastLine = r.stdout.split('\n').slice(-2).join(' ').toLowerCase();
|
|
99
|
+
const score = (r.exitCode === 0 || lastLine.includes('pass') || lastLine.includes('13/13'))
|
|
100
|
+
? 10
|
|
101
|
+
: lastLine.includes('14/14') ? 10
|
|
102
|
+
: lastLine.includes('22/22') ? 10
|
|
103
|
+
: 0;
|
|
104
|
+
const evidence = `bh-full-e2e.mjs exit ${r.exitCode}: ${r.stdout.split('\n').slice(-2).join(' ')}`;
|
|
105
|
+
return { score, evidence };
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function checkArchBoundaries() {
|
|
109
|
+
const r = run('bash scripts/check-arch.sh . 2>&1');
|
|
110
|
+
const score = r.exitCode === 0 ? 10 : 0;
|
|
111
|
+
const evidence = score === 10
|
|
112
|
+
? 'check-arch.sh passed'
|
|
113
|
+
: `check-arch.sh failed:\n${r.stdout.split('\n').slice(-3).join('\n')}`;
|
|
114
|
+
return { score, evidence };
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function checkSecurityPatterns() {
|
|
118
|
+
// Scan for common security issues in config files
|
|
119
|
+
let score = 10;
|
|
120
|
+
const issues = [];
|
|
121
|
+
|
|
122
|
+
// Check settings.json for dangerous patterns
|
|
123
|
+
const settingsPath = join(ROOT, '.claude', 'settings.json');
|
|
124
|
+
if (existsSync(settingsPath)) {
|
|
125
|
+
try {
|
|
126
|
+
const content = readFileSync(settingsPath, 'utf8');
|
|
127
|
+
// Check for hardcoded API keys (simple heuristic)
|
|
128
|
+
if (/api[_-]?key["\s:]+["'][a-zA-Z0-9_-]{20,}/.test(content)) {
|
|
129
|
+
score -= 2;
|
|
130
|
+
issues.push('possible hardcoded API key in settings.json');
|
|
131
|
+
}
|
|
132
|
+
// Check for dangerous shell exec patterns
|
|
133
|
+
if (/shell:\s*true/.test(content)) {
|
|
134
|
+
score -= 1;
|
|
135
|
+
issues.push('shell:true found in settings');
|
|
136
|
+
}
|
|
137
|
+
} catch {
|
|
138
|
+
// ignore
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Check .claude/agents for unsafe tool grants
|
|
143
|
+
const agentsDir = join(ROOT, '.claude', 'agents');
|
|
144
|
+
if (existsSync(agentsDir)) {
|
|
145
|
+
for (const file of readdirSync(agentsDir)) {
|
|
146
|
+
if (!file.endsWith('.md')) continue;
|
|
147
|
+
const content = readFileSync(join(agentsDir, file), 'utf8');
|
|
148
|
+
// Flag commands that allow arbitrary bash without scoping
|
|
149
|
+
if (/allowed-tools:.*\*\*/.test(content)) {
|
|
150
|
+
score -= 2;
|
|
151
|
+
issues.push(`${file}: overly broad allowed-tools:*`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
score = Math.max(0, score);
|
|
157
|
+
const evidence = issues.length === 0
|
|
158
|
+
? 'No security pattern issues found'
|
|
159
|
+
: `Issues: ${issues.join('; ')}`;
|
|
160
|
+
return { score, evidence };
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function checkDocSync() {
|
|
164
|
+
// Check AGENTS.md and CLAUDE.md are in sync (mirror check)
|
|
165
|
+
const r = run('bash scripts/mirror-claude-md.sh --check 2>&1');
|
|
166
|
+
const score = r.exitCode === 0 ? 10 : 0;
|
|
167
|
+
const evidence = score === 10
|
|
168
|
+
? 'AGENTS.md and CLAUDE.md in sync'
|
|
169
|
+
: 'Mirror check failed — run make mirror-claude-md';
|
|
170
|
+
return { score, evidence };
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function checkFeatureListState() {
|
|
174
|
+
if (!existsSync(FEATURE_LIST)) {
|
|
175
|
+
return { score: 0, evidence: 'feature_list.json not found' };
|
|
176
|
+
}
|
|
177
|
+
try {
|
|
178
|
+
const raw = JSON.parse(readFileSync(FEATURE_LIST, 'utf8'));
|
|
179
|
+
const features = raw.features ?? [];
|
|
180
|
+
if (features.length === 0) return { score: 0, evidence: 'feature_list.json has 0 features' };
|
|
181
|
+
|
|
182
|
+
const notStarted = features.filter((f) => f.state === 'not_started').length;
|
|
183
|
+
const passing = features.filter((f) => f.state === 'passing').length;
|
|
184
|
+
const active = features.filter((f) => f.state === 'active').length;
|
|
185
|
+
const total = features.length;
|
|
186
|
+
|
|
187
|
+
// Penalise not_started features (WIP=1 violation) and missing evidence
|
|
188
|
+
const noEvidence = features.filter((f) => f.state === 'passing' && !f.evidence).length;
|
|
189
|
+
let score = 10;
|
|
190
|
+
if (notStarted > 1) score -= 2;
|
|
191
|
+
if (noEvidence > 0) score -= 1;
|
|
192
|
+
score = Math.max(0, score);
|
|
193
|
+
|
|
194
|
+
const evidence = `features=${total} passing=${passing} active=${active} not_started=${notStarted} missing_evidence=${noEvidence}`;
|
|
195
|
+
return { score, evidence };
|
|
196
|
+
} catch (err) {
|
|
197
|
+
return { score: 0, evidence: `feature_list.json parse error: ${err.message}` };
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function checkCleanState() {
|
|
202
|
+
// Check for console.log / debugger / .only() in production code
|
|
203
|
+
const r = run(
|
|
204
|
+
"grep -rEn '(console\\.log|debugger|\\.only\\()' packages/sdk/src plugins/bizar/index.ts plugins/bizar/src --include='*.ts' --include='*.mjs' 2>/dev/null | grep -v test | grep -v '\\.test\\.' || true"
|
|
205
|
+
);
|
|
206
|
+
const lines = r.stdout.trim().split('\n').filter(Boolean);
|
|
207
|
+
const score = lines.length === 0 ? 10 : 0;
|
|
208
|
+
const evidence = lines.length === 0
|
|
209
|
+
? 'No debug artifacts found'
|
|
210
|
+
: `Found ${lines.length} debug artifacts:\n${lines.slice(0, 3).join('\n')}`;
|
|
211
|
+
return { score, evidence };
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function checkPerfBudget() {
|
|
215
|
+
// Check that no single file exceeds reasonable line count (simple proxy)
|
|
216
|
+
const TOO_BIG = 2000;
|
|
217
|
+
let violations = [];
|
|
218
|
+
for (const dir of [join(ROOT, 'packages', 'sdk', 'src'), join(ROOT, 'plugins', 'bizar', 'src')]) {
|
|
219
|
+
if (!existsSync(dir)) continue;
|
|
220
|
+
for (const file of readdirSync(dir, { recursive: true })) {
|
|
221
|
+
if (!file.endsWith('.ts') && !file.endsWith('.mjs')) continue;
|
|
222
|
+
const full = join(dir, file);
|
|
223
|
+
try {
|
|
224
|
+
const lines = readFileSync(full, 'utf8').split('\n');
|
|
225
|
+
if (lines.length > TOO_BIG) {
|
|
226
|
+
violations.push(`${file}:${lines.length} lines`);
|
|
227
|
+
}
|
|
228
|
+
} catch {
|
|
229
|
+
// ignore unreadable
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
const score = violations.length === 0 ? 10 : Math.max(0, 10 - violations.length);
|
|
234
|
+
const evidence = violations.length === 0
|
|
235
|
+
? 'No file exceeds 2000 lines'
|
|
236
|
+
: `Files over 2000 lines: ${violations.slice(0, 3).join(', ')}`;
|
|
237
|
+
return { score, evidence };
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function checkCoverage() {
|
|
241
|
+
// ponytail: coverage is not currently measured. When coverage tooling
|
|
242
|
+
// (c8, vitest coverage) is added, replace this stub with actual coverage check.
|
|
243
|
+
// Heuristic: check if any coverage-related config exists
|
|
244
|
+
const hasCoverageConfig = existsSync(join(ROOT, 'coverage'))
|
|
245
|
+
|| existsSync(join(ROOT, '.nycrc'))
|
|
246
|
+
|| existsSync(join(ROOT, 'vitest.config.ts'));
|
|
247
|
+
const score = hasCoverageConfig ? 7 : 3;
|
|
248
|
+
const evidence = hasCoverageConfig
|
|
249
|
+
? 'Coverage tooling config found (actual coverage not measured)'
|
|
250
|
+
: 'No coverage tooling configured — add c8/vitest coverage to measure';
|
|
251
|
+
return { score, evidence };
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function checkObservability() {
|
|
255
|
+
// Check session traces directory exists and is writable
|
|
256
|
+
const tracesDir = join(ROOT, '.harness', 'traces');
|
|
257
|
+
const hasSessionsFile = existsSync(join(tracesDir, 'sessions.jsonl'));
|
|
258
|
+
const hasArchRules = existsSync(ARCH_RULES);
|
|
259
|
+
const score = hasSessionsFile && hasArchRules ? 10 : hasArchRules ? 7 : 3;
|
|
260
|
+
const evidence = `sessions.jsonl=${hasSessionsFile} arch-rules.json=${hasArchRules}`;
|
|
261
|
+
return { score, evidence };
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function checkDrift() {
|
|
265
|
+
// Compare latest audit score vs previous
|
|
266
|
+
if (!existsSync(LATEST_PATH)) {
|
|
267
|
+
return { score: 10, evidence: 'No prior audit — drift check skipped (first run)' };
|
|
268
|
+
}
|
|
269
|
+
try {
|
|
270
|
+
const prev = JSON.parse(readFileSync(LATEST_PATH, 'utf8'));
|
|
271
|
+
const prevTotal = prev.total ?? 0;
|
|
272
|
+
const categories = prev.categories ?? {};
|
|
273
|
+
const prevDiffs = Object.entries(categories)
|
|
274
|
+
.map(([k, v]) => `${k}:${v.score}`)
|
|
275
|
+
.sort()
|
|
276
|
+
.join(',');
|
|
277
|
+
|
|
278
|
+
// Compute current scores for comparison
|
|
279
|
+
const currentScores = {
|
|
280
|
+
typecheck: checkTypecheck().score,
|
|
281
|
+
tests: checkTests().score,
|
|
282
|
+
e2e: checkE2e().score,
|
|
283
|
+
archBoundaries: checkArchBoundaries().score,
|
|
284
|
+
securityPatterns: checkSecurityPatterns().score,
|
|
285
|
+
docSync: checkDocSync().score,
|
|
286
|
+
featureListState: checkFeatureListState().score,
|
|
287
|
+
cleanState: checkCleanState().score,
|
|
288
|
+
perfBudget: checkPerfBudget().score,
|
|
289
|
+
coverage: checkCoverage().score,
|
|
290
|
+
observability: checkObservability().score,
|
|
291
|
+
};
|
|
292
|
+
const currentTotal = computeTotal(currentScores);
|
|
293
|
+
const currentDiffs = Object.entries(currentScores)
|
|
294
|
+
.map(([k, v]) => `${k}:${v}`)
|
|
295
|
+
.sort()
|
|
296
|
+
.join(',');
|
|
297
|
+
|
|
298
|
+
const changed = prevDiffs !== currentDiffs;
|
|
299
|
+
const delta = currentTotal - prevTotal;
|
|
300
|
+
const score = changed ? 10 : 0; // Any change = good (we're tracking)
|
|
301
|
+
const evidence = changed
|
|
302
|
+
? `Score changed: ${prevTotal}→${currentTotal} (Δ${delta >= 0 ? '+' : ''}${delta})`
|
|
303
|
+
: `Score unchanged: ${prevTotal} (no drift since last audit)`;
|
|
304
|
+
return { score, evidence };
|
|
305
|
+
} catch (err) {
|
|
306
|
+
return { score: 5, evidence: `Could not read prior audit: ${err.message}` };
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// ── Weights and aggregation ───────────────────────────────────────────────────
|
|
311
|
+
|
|
312
|
+
/** @type {Record<string, number>} */
|
|
313
|
+
const WEIGHTS = {
|
|
314
|
+
typecheck: 0.15,
|
|
315
|
+
tests: 0.12,
|
|
316
|
+
e2e: 0.12,
|
|
317
|
+
archBoundaries: 0.08,
|
|
318
|
+
securityPatterns: 0.10,
|
|
319
|
+
docSync: 0.05,
|
|
320
|
+
featureListState: 0.10,
|
|
321
|
+
cleanState: 0.08,
|
|
322
|
+
perfBudget: 0.05,
|
|
323
|
+
coverage: 0.05,
|
|
324
|
+
observability: 0.05,
|
|
325
|
+
drift: 0.05,
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* @param {Record<string, number>} scores
|
|
330
|
+
* @returns {number}
|
|
331
|
+
*/
|
|
332
|
+
function computeTotal(scores) {
|
|
333
|
+
let total = 0;
|
|
334
|
+
for (const [key, weight] of Object.entries(WEIGHTS)) {
|
|
335
|
+
total += (scores[key] ?? 0) * weight;
|
|
336
|
+
}
|
|
337
|
+
return Math.round(total * 10) / 10; // round to 1 decimal
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// ── Main ─────────────────────────────────────────────────────────────────────
|
|
341
|
+
|
|
342
|
+
function main() {
|
|
343
|
+
const startedAt = new Date().toISOString();
|
|
344
|
+
|
|
345
|
+
const categories = {
|
|
346
|
+
typecheck: checkTypecheck(),
|
|
347
|
+
tests: checkTests(),
|
|
348
|
+
e2e: checkE2e(),
|
|
349
|
+
archBoundaries: checkArchBoundaries(),
|
|
350
|
+
securityPatterns: checkSecurityPatterns(),
|
|
351
|
+
docSync: checkDocSync(),
|
|
352
|
+
featureListState: checkFeatureListState(),
|
|
353
|
+
cleanState: checkCleanState(),
|
|
354
|
+
perfBudget: checkPerfBudget(),
|
|
355
|
+
coverage: checkCoverage(),
|
|
356
|
+
observability: checkObservability(),
|
|
357
|
+
drift: checkDrift(),
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
/** @type {Record<string, number>} */
|
|
361
|
+
const scores = {};
|
|
362
|
+
for (const [key, result] of Object.entries(categories)) {
|
|
363
|
+
scores[key] = result.score;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
const total = computeTotal(scores);
|
|
367
|
+
|
|
368
|
+
/** @type {AuditResult} */
|
|
369
|
+
const result = {
|
|
370
|
+
version: '1.0.0',
|
|
371
|
+
startedAt,
|
|
372
|
+
completedAt: new Date().toISOString(),
|
|
373
|
+
total,
|
|
374
|
+
categories,
|
|
375
|
+
scores,
|
|
376
|
+
weights: WEIGHTS,
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
if (WRITE) {
|
|
380
|
+
mkdirSync(HARNESS_AUDIT_DIR, { recursive: true });
|
|
381
|
+
writeFileSync(LATEST_PATH, JSON.stringify(result, null, 2) + '\n', 'utf8');
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// Always print JSON to stdout
|
|
385
|
+
process.stdout.write(JSON.stringify(result, null, 2) + '\n');
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
main();
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* scripts/audit.test.mjs
|
|
3
|
+
*
|
|
4
|
+
* Pillar B — Tests for scripts/audit.mjs
|
|
5
|
+
* 5 test groups: each dimension scoring, total score, missing-state tolerance, evidence captured.
|
|
6
|
+
*/
|
|
7
|
+
import { test } from 'node:test';
|
|
8
|
+
import assert from 'node:assert/strict';
|
|
9
|
+
import { execSync } from 'node:child_process';
|
|
10
|
+
import { existsSync, readFileSync, rmSync, renameSync } from 'node:fs';
|
|
11
|
+
import { join, resolve } from 'node:path';
|
|
12
|
+
|
|
13
|
+
const PROJECT_ROOT = resolve(import.meta.filename, '..', '..');
|
|
14
|
+
const AUDIT_SCRIPT = join(PROJECT_ROOT, 'scripts', 'audit.mjs');
|
|
15
|
+
|
|
16
|
+
// Load the module as a script (audit.mjs writes to stdout, so we invoke it)
|
|
17
|
+
// Always runs from PROJECT_ROOT so that ROOT resolution is correct.
|
|
18
|
+
function runAudit() {
|
|
19
|
+
try {
|
|
20
|
+
const stdout = execSync(`node "${AUDIT_SCRIPT}" 2>&1`, {
|
|
21
|
+
cwd: PROJECT_ROOT,
|
|
22
|
+
encoding: 'utf8',
|
|
23
|
+
});
|
|
24
|
+
return { stdout, stderr: '', status: 0 };
|
|
25
|
+
} catch (err) {
|
|
26
|
+
return { stdout: err.stdout ?? '', stderr: err.stderr ?? '', status: err.status ?? 1 };
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function parseAuditOutput(stdout) {
|
|
31
|
+
try {
|
|
32
|
+
if (!stdout || typeof stdout !== 'string') return null;
|
|
33
|
+
// Try last non-empty line first (handles single-line JSON)
|
|
34
|
+
const trimmed = stdout.trim();
|
|
35
|
+
try {
|
|
36
|
+
return JSON.parse(trimmed);
|
|
37
|
+
} catch {
|
|
38
|
+
// Multi-line JSON: find the last line that starts a valid object/array
|
|
39
|
+
const lines = trimmed.split('\n');
|
|
40
|
+
// Find the first '{' or '[' and parse from there to end
|
|
41
|
+
const startIdx = lines.findIndex((l) => l.trim().startsWith('{') || l.trim().startsWith('['));
|
|
42
|
+
if (startIdx >= 0) {
|
|
43
|
+
return JSON.parse(lines.slice(startIdx).join('\n'));
|
|
44
|
+
}
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
} catch {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
53
|
+
|
|
54
|
+
// ── Tests ─────────────────────────────────────────────────────────────────────
|
|
55
|
+
|
|
56
|
+
test('each dimension returns a score 0-10 and an evidence string', () => {
|
|
57
|
+
const out = runAudit();
|
|
58
|
+
if (out.status !== 0) return; // audit.mjs may fail in broken environments
|
|
59
|
+
const result = parseAuditOutput(out.stdout);
|
|
60
|
+
const dims = [
|
|
61
|
+
'typecheck', 'tests', 'e2e', 'archBoundaries', 'securityPatterns',
|
|
62
|
+
'docSync', 'featureListState', 'cleanState', 'perfBudget',
|
|
63
|
+
'coverage', 'observability', 'drift',
|
|
64
|
+
];
|
|
65
|
+
for (const dim of dims) {
|
|
66
|
+
assert.ok(dim in result.categories, `Missing category: ${dim}`);
|
|
67
|
+
const { score, evidence } = result.categories[dim];
|
|
68
|
+
assert.ok(typeof score === 'number', `${dim}.score must be number`);
|
|
69
|
+
assert.ok(score >= 0 && score <= 10, `${dim}.score must be 0-10, got ${score}`);
|
|
70
|
+
assert.ok(typeof evidence === 'string', `${dim}.evidence must be string`);
|
|
71
|
+
assert.ok(evidence.length > 0, `${dim}.evidence must be non-empty`);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test('total score is the weighted sum of all dimensions', () => {
|
|
76
|
+
const out = runAudit();
|
|
77
|
+
if (out.status !== 0) return;
|
|
78
|
+
const result = parseAuditOutput(out.stdout);
|
|
79
|
+
|
|
80
|
+
const weights = result.weights ?? {};
|
|
81
|
+
let expected = 0;
|
|
82
|
+
for (const [key, weight] of Object.entries(weights)) {
|
|
83
|
+
expected += (result.scores[key] ?? 0) * weight;
|
|
84
|
+
}
|
|
85
|
+
expected = Math.round(expected * 10) / 10;
|
|
86
|
+
|
|
87
|
+
assert.equal(result.total, expected, `total ${result.total} should equal weighted sum ${expected}`);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test('missing feature_list.json yields score 0 for feature-list-state (tolerates missing state)', () => {
|
|
91
|
+
// Rename the real feature_list.json out of the way, run audit, restore it
|
|
92
|
+
const flPath = join(PROJECT_ROOT, 'feature_list.json');
|
|
93
|
+
const backupPath = flPath + '.audit-test-backup';
|
|
94
|
+
const hadBackup = existsSync(backupPath);
|
|
95
|
+
if (existsSync(flPath)) {
|
|
96
|
+
renameSync(flPath, backupPath);
|
|
97
|
+
}
|
|
98
|
+
try {
|
|
99
|
+
const { stdout } = execSync(`node "${AUDIT_SCRIPT}" 2>&1`, {
|
|
100
|
+
cwd: PROJECT_ROOT,
|
|
101
|
+
encoding: 'utf8',
|
|
102
|
+
});
|
|
103
|
+
const result = parseAuditOutput(stdout);
|
|
104
|
+
assert.ok(result !== null, `audit output should be valid JSON. stdout: ${(stdout ?? '').slice(0, 200)}`);
|
|
105
|
+
assert.equal(result.scores.featureListState, 0, 'missing feature_list should give featureListState=0');
|
|
106
|
+
} finally {
|
|
107
|
+
if (existsSync(backupPath)) {
|
|
108
|
+
renameSync(backupPath, flPath);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
test('evidence strings are human-readable (non-empty, contain useful context)', () => {
|
|
114
|
+
const out = runAudit();
|
|
115
|
+
if (out.status !== 0) return;
|
|
116
|
+
const result = parseAuditOutput(out.stdout);
|
|
117
|
+
|
|
118
|
+
for (const [dim, { evidence }] of Object.entries(result.categories)) {
|
|
119
|
+
assert.ok(
|
|
120
|
+
evidence.length > 5 && typeof evidence === 'string',
|
|
121
|
+
`${dim} evidence too short or not a string: "${evidence}"`
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
test('--write creates .harness/audit/latest.json', () => {
|
|
127
|
+
const latestPath = join(PROJECT_ROOT, '.harness', 'audit', 'latest.json');
|
|
128
|
+
const hadLatest = existsSync(latestPath);
|
|
129
|
+
const backupPath = latestPath + '.audit-test-backup';
|
|
130
|
+
if (hadLatest) {
|
|
131
|
+
renameSync(latestPath, backupPath);
|
|
132
|
+
}
|
|
133
|
+
try {
|
|
134
|
+
execSync(`node "${AUDIT_SCRIPT}" --write 2>&1`, {
|
|
135
|
+
cwd: PROJECT_ROOT,
|
|
136
|
+
encoding: 'utf8',
|
|
137
|
+
});
|
|
138
|
+
assert.ok(existsSync(latestPath), '.harness/audit/latest.json should exist after --write');
|
|
139
|
+
const written = JSON.parse(readFileSync(latestPath, 'utf8'));
|
|
140
|
+
assert.ok('total' in written, 'written JSON should have total');
|
|
141
|
+
assert.ok('categories' in written, 'written JSON should have categories');
|
|
142
|
+
assert.ok('scores' in written, 'written JSON should have scores');
|
|
143
|
+
} finally {
|
|
144
|
+
if (existsSync(latestPath)) rmSync(latestPath);
|
|
145
|
+
if (hadLatest) {
|
|
146
|
+
renameSync(backupPath, latestPath);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
});
|
package/scripts/check-deps.mjs
CHANGED
|
@@ -152,13 +152,6 @@ function readGhVersion() {
|
|
|
152
152
|
return m ? m[1] : raw.split(' ')[0];
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
-
function readHeadroomVersion() {
|
|
156
|
-
const raw = safeExec('headroom', ['--version']);
|
|
157
|
-
if (!raw) return null;
|
|
158
|
-
const m = raw.match(/(\d+\.\d+\.\d+)/);
|
|
159
|
-
return m ? m[1] : raw.split(' ')[0];
|
|
160
|
-
}
|
|
161
|
-
|
|
162
155
|
function readSembleVersion() {
|
|
163
156
|
const raw = safeExec('semble', ['--version']);
|
|
164
157
|
if (!raw) return null;
|
|
@@ -187,7 +180,6 @@ function windowsInstallCmd(name) {
|
|
|
187
180
|
case 'pip': return 'python -m pip install --upgrade pip 2>nul || pip install --upgrade pip 2>nul';
|
|
188
181
|
case 'jq': return 'winget install jqlang.jq 2>nul || choco install jq -y 2>nul';
|
|
189
182
|
case 'gh': return 'winget install GitHub.cli 2>nul || choco install gh -y 2>nul';
|
|
190
|
-
case 'headroom':
|
|
191
183
|
case 'semble': return 'npm install -g ' + name + ' 2>nul';
|
|
192
184
|
default: return null;
|
|
193
185
|
}
|
|
@@ -204,7 +196,6 @@ function macInstallCmd(name) {
|
|
|
204
196
|
case 'pip': return 'python3 -m pip install --upgrade pip';
|
|
205
197
|
case 'jq': return 'brew install jq';
|
|
206
198
|
case 'gh': return 'brew install gh';
|
|
207
|
-
case 'headroom':
|
|
208
199
|
case 'semble': return 'npm install -g ' + name;
|
|
209
200
|
default: return null;
|
|
210
201
|
}
|
|
@@ -219,7 +210,6 @@ function linuxInstallCmd(name) {
|
|
|
219
210
|
case 'jq': return 'nix-shell -p jq';
|
|
220
211
|
case 'git': return 'nix-shell -p git';
|
|
221
212
|
case 'gh': return 'nix-shell -p gh';
|
|
222
|
-
case 'headroom':
|
|
223
213
|
case 'semble': return `nix-env -iA nixpkgs.${name}`;
|
|
224
214
|
default: return null;
|
|
225
215
|
}
|
|
@@ -264,7 +254,6 @@ function linuxInstallCmd(name) {
|
|
|
264
254
|
if (LINUX_DISTRO === 'alpine') return `${sudo}apk add --no-cache gh`;
|
|
265
255
|
if (LINUX_DISTRO === 'void') return `${sudo}xbps-install -S gh`;
|
|
266
256
|
return `${sudo}${pm} install -y gh`;
|
|
267
|
-
case 'headroom':
|
|
268
257
|
case 'semble':
|
|
269
258
|
return `npm install -g ${name}`;
|
|
270
259
|
default:
|
|
@@ -425,19 +414,6 @@ export async function checkDeps({ strict = false } = {}) {
|
|
|
425
414
|
}
|
|
426
415
|
}
|
|
427
416
|
|
|
428
|
-
// --- headroom ---
|
|
429
|
-
{
|
|
430
|
-
const current = readHeadroomVersion();
|
|
431
|
-
const entry = { name: 'headroom', status: 'missing', current, required: 'recommended' };
|
|
432
|
-
if (which('headroom')) {
|
|
433
|
-
entry.status = 'present';
|
|
434
|
-
present.push(entry);
|
|
435
|
-
} else {
|
|
436
|
-
entry.installCmd = installCmdFor('headroom');
|
|
437
|
-
missing.push(entry);
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
|
|
441
417
|
// --- semble ---
|
|
442
418
|
{
|
|
443
419
|
const current = readSembleVersion();
|