@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
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* router/agent-model-registry.ts — resolve agent → concrete model ID.
|
|
3
|
+
*
|
|
4
|
+
* v10.1.0 — Reads `.claude/model-router.json` (the Bizar model registry)
|
|
5
|
+
* and exposes:
|
|
6
|
+
*
|
|
7
|
+
* - resolveAgentModel(agent) → { modelId, tier, endpoint, rationale }
|
|
8
|
+
* - listAgentModels() → Array<{ agent, modelId, tier, ... }>
|
|
9
|
+
* - resolveTierModel(tier) → { modelId, endpoint, fallback[] }
|
|
10
|
+
* - getEndpoint() → endpoint URL (env override honored)
|
|
11
|
+
*
|
|
12
|
+
* The router decides which tier; this registry decides which concrete
|
|
13
|
+
* model ID lives at that tier and which endpoint URL to call. Together
|
|
14
|
+
* they form the dispatch contract the MCP `route_agent` tool surfaces.
|
|
15
|
+
*
|
|
16
|
+
* Why a separate module: the Thompson-bandit model-router.ts doesn't
|
|
17
|
+
* know about model IDs (it only reasons about `flash / mid / expensive`
|
|
18
|
+
* priors). The agent-registry.ts knows about agent types but not about
|
|
19
|
+
* concrete models. This module is the bridge.
|
|
20
|
+
*/
|
|
21
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
22
|
+
import { isAbsolute, resolve } from "node:path";
|
|
23
|
+
const DEFAULT_CONFIG = ".claude/model-router.json";
|
|
24
|
+
const KNOWN_TIERS = [
|
|
25
|
+
"premium",
|
|
26
|
+
"high",
|
|
27
|
+
"mid-design",
|
|
28
|
+
"default",
|
|
29
|
+
"mid",
|
|
30
|
+
"budget",
|
|
31
|
+
];
|
|
32
|
+
function isKnownTier(t) {
|
|
33
|
+
return typeof t === "string" && KNOWN_TIERS.includes(t);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Read the registry from disk. Tolerates a missing/corrupt file by
|
|
37
|
+
* returning a minimal registry pointing at the local router default —
|
|
38
|
+
* agents can still operate, just without the per-agent rationale data.
|
|
39
|
+
*/
|
|
40
|
+
export function loadModelRegistry(src = {}) {
|
|
41
|
+
const fp = src.configPath
|
|
42
|
+
? isAbsolute(src.configPath) ? src.configPath : resolve(src.configPath)
|
|
43
|
+
: resolve(DEFAULT_CONFIG);
|
|
44
|
+
let raw = {};
|
|
45
|
+
if (existsSync(fp)) {
|
|
46
|
+
try {
|
|
47
|
+
raw = JSON.parse(readFileSync(fp, "utf8"));
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
raw = {};
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const endpoint = src.endpoint
|
|
54
|
+
?? process.env.BIZAR_MODEL_ROUTER_URL
|
|
55
|
+
?? process.env.ANTHROPIC_BASE_URL
|
|
56
|
+
?? raw.endpoint
|
|
57
|
+
?? "http://localhost:20128/v1";
|
|
58
|
+
const agents = new Map();
|
|
59
|
+
if (raw.agents && typeof raw.agents === "object") {
|
|
60
|
+
for (const [name, def] of Object.entries(raw.agents)) {
|
|
61
|
+
if (!def || typeof def !== "object")
|
|
62
|
+
continue;
|
|
63
|
+
const modelId = typeof def.model === "string" ? def.model : "bizar/MiniMax-M3";
|
|
64
|
+
const tier = isKnownTier(def.tier) ? def.tier : "default";
|
|
65
|
+
const rationale = typeof def.rationale === "string" ? def.rationale : "";
|
|
66
|
+
agents.set(name, { agent: name, modelId, tier, rationale });
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
const tiers = new Map();
|
|
70
|
+
if (raw.tiers && typeof raw.tiers === "object") {
|
|
71
|
+
for (const [name, def] of Object.entries(raw.tiers)) {
|
|
72
|
+
if (!def || typeof def !== "object")
|
|
73
|
+
continue;
|
|
74
|
+
if (!isKnownTier(name))
|
|
75
|
+
continue;
|
|
76
|
+
const ids = Array.isArray(def.models) ? def.models.filter((m) => typeof m === "string") : [];
|
|
77
|
+
const purpose = typeof def.purpose === "string" ? def.purpose : "";
|
|
78
|
+
tiers.set(name, { tier: name, modelIds: ids, purpose });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
const fallbackChain = Array.isArray(raw.policies?.fallback_chain)
|
|
82
|
+
? raw.policies.fallback_chain.filter((m) => typeof m === "string")
|
|
83
|
+
: [];
|
|
84
|
+
const gptOnlyFor = Array.isArray(raw.policies?.gpt_only_for)
|
|
85
|
+
? raw.policies.gpt_only_for.filter((s) => typeof s === "string")
|
|
86
|
+
: [];
|
|
87
|
+
const gptNeverFor = Array.isArray(raw.policies?.gpt_never_for)
|
|
88
|
+
? raw.policies.gpt_never_for.filter((s) => typeof s === "string")
|
|
89
|
+
: [];
|
|
90
|
+
return { endpoint, agents, tiers, fallbackChain, gptOnlyFor, gptNeverFor };
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Resolve the concrete model + endpoint for a named agent.
|
|
94
|
+
* Falls back to the default agent entry (or a hard-coded `bizar/MiniMax-M3`
|
|
95
|
+
* if even the default is missing) so a call always returns something
|
|
96
|
+
* usable. Never throws.
|
|
97
|
+
*/
|
|
98
|
+
export function resolveAgentModel(agent, reg) {
|
|
99
|
+
const entry = reg.agents.get(agent)
|
|
100
|
+
?? reg.agents.get("odin")
|
|
101
|
+
?? { agent: "odin", modelId: "bizar/MiniMax-M3", tier: "default", rationale: "fallback" };
|
|
102
|
+
return {
|
|
103
|
+
agent: entry.agent,
|
|
104
|
+
modelId: entry.modelId,
|
|
105
|
+
tier: entry.tier,
|
|
106
|
+
endpoint: reg.endpoint,
|
|
107
|
+
rationale: entry.rationale,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Resolve a tier to its primary model ID + the fallback chain. Always
|
|
112
|
+
* returns at least one model ID.
|
|
113
|
+
*/
|
|
114
|
+
export function resolveTierModel(tier, reg) {
|
|
115
|
+
const entry = reg.tiers.get(tier);
|
|
116
|
+
const primary = entry?.modelIds[0] ?? "bizar/MiniMax-M3";
|
|
117
|
+
const fallback = entry?.modelIds.slice(1) ?? [];
|
|
118
|
+
return {
|
|
119
|
+
tier,
|
|
120
|
+
modelId: primary,
|
|
121
|
+
fallback,
|
|
122
|
+
endpoint: reg.endpoint,
|
|
123
|
+
purpose: entry?.purpose ?? "",
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Return the full agent → model table. Stable order: insertion order from
|
|
128
|
+
* the JSON (preserves whatever order the operator wrote).
|
|
129
|
+
*/
|
|
130
|
+
export function listAgentModels(reg) {
|
|
131
|
+
return Array.from(reg.agents.values());
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Convenience: read the endpoint from the registry / env. Useful in
|
|
135
|
+
* scripts that don't want to load the full registry just for a URL.
|
|
136
|
+
*/
|
|
137
|
+
export function getEndpoint(reg) {
|
|
138
|
+
if (reg)
|
|
139
|
+
return reg.endpoint;
|
|
140
|
+
return process.env.BIZAR_MODEL_ROUTER_URL
|
|
141
|
+
?? process.env.ANTHROPIC_BASE_URL
|
|
142
|
+
?? "http://localhost:20128/v1";
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=agent-model-registry.js.map
|
|
@@ -97,4 +97,5 @@ export { detectCodemodIntent, CODEMOD_CONFIDENCE_THRESHOLD, } from "./codemod-in
|
|
|
97
97
|
export type { CodemodIntent, CodemodIntentHit } from "./codemod-intent.js";
|
|
98
98
|
export { ModelRouter, type ModelTier, type RouteDecision, } from "./model-router.js";
|
|
99
99
|
export { QLearningRouter, AGENT_ACTIONS, type AgentName, type AgentRouteDecision, } from "./q-learning-router.js";
|
|
100
|
+
export { loadModelRegistry, resolveAgentModel, resolveTierModel, listAgentModels, getEndpoint, type ModelRegistry, type ResolvedAgentModel, type ResolvedTierModel, type AgentModelEntry, type TierModelEntry, type BizarTier, } from "./agent-model-registry.js";
|
|
100
101
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -146,4 +146,5 @@ export function tierTag(decision) {
|
|
|
146
146
|
export { detectCodemodIntent, CODEMOD_CONFIDENCE_THRESHOLD, } from "./codemod-intent.js";
|
|
147
147
|
export { ModelRouter, } from "./model-router.js";
|
|
148
148
|
export { QLearningRouter, AGENT_ACTIONS, } from "./q-learning-router.js";
|
|
149
|
+
export { loadModelRegistry, resolveAgentModel, resolveTierModel, listAgentModels, getEndpoint, } from "./agent-model-registry.js";
|
|
149
150
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@polderlabs/bizar-sdk",
|
|
3
|
-
"version": "10.
|
|
3
|
+
"version": "10.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
".": "./dist/index.js",
|
|
12
12
|
"./memory": "./dist/memory/index.js",
|
|
13
13
|
"./mcp": "./dist/mcp/server.js",
|
|
14
|
-
"./dangerous-patterns": "./dist/dangerous-patterns.js"
|
|
14
|
+
"./dangerous-patterns": "./dist/dangerous-patterns.js",
|
|
15
|
+
"./learning": "./dist/learning/index.js"
|
|
15
16
|
},
|
|
16
17
|
"files": [
|
|
17
18
|
"dist"
|
|
@@ -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();
|