@polderlabs/bizar 10.1.0 → 10.3.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.
Files changed (263) hide show
  1. package/README.md +31 -10
  2. package/bizar-dash/CONTROL_SURFACES.md +0 -1
  3. package/bizar-dash/dist/assets/{ActivityFeed-Da-JCrE6.js → ActivityFeed-xXiUCZLB.js} +1 -1
  4. package/bizar-dash/dist/assets/{ActivityFeed-Da-JCrE6.js.map → ActivityFeed-xXiUCZLB.js.map} +1 -1
  5. package/bizar-dash/dist/assets/{ActivityView-nIRsSETb.js → ActivityView-nOYhCp3h.js} +1 -1
  6. package/bizar-dash/dist/assets/{ActivityView-nIRsSETb.js.map → ActivityView-nOYhCp3h.js.map} +1 -1
  7. package/bizar-dash/dist/assets/{AdminView-DP1NMxmG.js → AdminView-Coi4V3sq.js} +1 -1
  8. package/bizar-dash/dist/assets/{AdminView-DP1NMxmG.js.map → AdminView-Coi4V3sq.js.map} +1 -1
  9. package/bizar-dash/dist/assets/{AgentActivity-lSPkOr-O.js → AgentActivity-nEri4lbx.js} +1 -1
  10. package/bizar-dash/dist/assets/{AgentActivity-lSPkOr-O.js.map → AgentActivity-nEri4lbx.js.map} +1 -1
  11. package/bizar-dash/dist/assets/{AgentsView-BIWGkz7w.js → AgentsView-ByiIJ0ej.js} +3 -3
  12. package/bizar-dash/dist/assets/{AgentsView-BIWGkz7w.js.map → AgentsView-ByiIJ0ej.js.map} +1 -1
  13. package/bizar-dash/dist/assets/{Alert-DN0UysMg.js → Alert-Dg_Vwxh5.js} +1 -1
  14. package/bizar-dash/dist/assets/{Alert-DN0UysMg.js.map → Alert-Dg_Vwxh5.js.map} +1 -1
  15. package/bizar-dash/dist/assets/ArtifactsView-CGclRNnz.js +21 -0
  16. package/bizar-dash/dist/assets/ArtifactsView-CGclRNnz.js.map +1 -0
  17. package/bizar-dash/dist/assets/{AuthView-DW5cs7ma.js → AuthView-utVm6M3D.js} +1 -1
  18. package/bizar-dash/dist/assets/{AuthView-DW5cs7ma.js.map → AuthView-utVm6M3D.js.map} +1 -1
  19. package/bizar-dash/dist/assets/{Avatar-DZPv9pvd.js → Avatar-CXDZdKy4.js} +1 -1
  20. package/bizar-dash/dist/assets/{Avatar-DZPv9pvd.js.map → Avatar-CXDZdKy4.js.map} +1 -1
  21. package/bizar-dash/dist/assets/{BackgroundJobsView-D8O-EyMD.js → BackgroundJobsView-j603pz6o.js} +1 -1
  22. package/bizar-dash/dist/assets/{BackgroundJobsView-D8O-EyMD.js.map → BackgroundJobsView-j603pz6o.js.map} +1 -1
  23. package/bizar-dash/dist/assets/{BackupView-uwXkhxOV.js → BackupView-DgvnntTE.js} +1 -1
  24. package/bizar-dash/dist/assets/{BackupView-uwXkhxOV.js.map → BackupView-DgvnntTE.js.map} +1 -1
  25. package/bizar-dash/dist/assets/{Card-Tyboihu7.js → Card-D9019JOD.js} +1 -1
  26. package/bizar-dash/dist/assets/{Card-Tyboihu7.js.map → Card-D9019JOD.js.map} +1 -1
  27. package/bizar-dash/dist/assets/{ChatView-DRBHzgay.js → ChatView-C0cTgj5d.js} +1 -1
  28. package/bizar-dash/dist/assets/{ChatView-DRBHzgay.js.map → ChatView-C0cTgj5d.js.map} +1 -1
  29. package/bizar-dash/dist/assets/{Chip-BrXIlR9w.js → Chip-DQtalZ4y.js} +1 -1
  30. package/bizar-dash/dist/assets/{Chip-BrXIlR9w.js.map → Chip-DQtalZ4y.js.map} +1 -1
  31. package/bizar-dash/dist/assets/{ClaudeSessionsView-Ck62jaOr.js → ClaudeSessionsView-H3Bqjo6b.js} +1 -1
  32. package/bizar-dash/dist/assets/{ClaudeSessionsView-Ck62jaOr.js.map → ClaudeSessionsView-H3Bqjo6b.js.map} +1 -1
  33. package/bizar-dash/dist/assets/{ClipboardView-DfND6xL6.js → ClipboardView-BAguaKbx.js} +1 -1
  34. package/bizar-dash/dist/assets/{ClipboardView-DfND6xL6.js.map → ClipboardView-BAguaKbx.js.map} +1 -1
  35. package/bizar-dash/dist/assets/{ConfigView-DjJmSrOJ.js → ConfigView-DWHJgoe8.js} +1 -1
  36. package/bizar-dash/dist/assets/{ConfigView-DjJmSrOJ.js.map → ConfigView-DWHJgoe8.js.map} +1 -1
  37. package/bizar-dash/dist/assets/{DiagnosticsView-CKgItf0J.js → DiagnosticsView-oCT624hk.js} +1 -1
  38. package/bizar-dash/dist/assets/{DiagnosticsView-CKgItf0J.js.map → DiagnosticsView-oCT624hk.js.map} +1 -1
  39. package/bizar-dash/dist/assets/{DialogsView-DHYF8dE1.js → DialogsView-CqHNals_.js} +1 -1
  40. package/bizar-dash/dist/assets/{DialogsView-DHYF8dE1.js.map → DialogsView-CqHNals_.js.map} +1 -1
  41. package/bizar-dash/dist/assets/{DoctorView-DDLHrSKk.js → DoctorView-6kfQq_Mx.js} +1 -1
  42. package/bizar-dash/dist/assets/{DoctorView-DDLHrSKk.js.map → DoctorView-6kfQq_Mx.js.map} +1 -1
  43. package/bizar-dash/dist/assets/{EmptyState-DZ2ouKwd.js → EmptyState-DLmtBX_6.js} +1 -1
  44. package/bizar-dash/dist/assets/{EmptyState-DZ2ouKwd.js.map → EmptyState-DLmtBX_6.js.map} +1 -1
  45. package/bizar-dash/dist/assets/{EnvVarsView-D1cx83mB.js → EnvVarsView-DySOXlP1.js} +2 -2
  46. package/bizar-dash/dist/assets/{EnvVarsView-D1cx83mB.js.map → EnvVarsView-DySOXlP1.js.map} +1 -1
  47. package/bizar-dash/dist/assets/{ErrorState-DwwJ2-Jq.js → ErrorState-Bump8diE.js} +1 -1
  48. package/bizar-dash/dist/assets/{ErrorState-DwwJ2-Jq.js.map → ErrorState-Bump8diE.js.map} +1 -1
  49. package/bizar-dash/dist/assets/{EvalView-C9aYixXW.js → EvalView-FnZ5d93z.js} +1 -1
  50. package/bizar-dash/dist/assets/{EvalView-C9aYixXW.js.map → EvalView-FnZ5d93z.js.map} +1 -1
  51. package/bizar-dash/dist/assets/{GoalsView-DZa_mGmh.js → GoalsView-C4m1WnVv.js} +1 -1
  52. package/bizar-dash/dist/assets/{GoalsView-DZa_mGmh.js.map → GoalsView-C4m1WnVv.js.map} +1 -1
  53. package/bizar-dash/dist/assets/{Grid-CiRyhAgR.js → Grid-dEnoGGws.js} +1 -1
  54. package/bizar-dash/dist/assets/{Grid-CiRyhAgR.js.map → Grid-dEnoGGws.js.map} +1 -1
  55. package/bizar-dash/dist/assets/{HistoryView-Dv7aPxJE.js → HistoryView-xdRybjZ2.js} +1 -1
  56. package/bizar-dash/dist/assets/{HistoryView-Dv7aPxJE.js.map → HistoryView-xdRybjZ2.js.map} +1 -1
  57. package/bizar-dash/dist/assets/{Input-BbFUDQnS.js → Input-BSa3lh_-.js} +1 -1
  58. package/bizar-dash/dist/assets/{Input-BbFUDQnS.js.map → Input-BSa3lh_-.js.map} +1 -1
  59. package/bizar-dash/dist/assets/{LibrariesView-DBQ83TNa.js → LibrariesView-1zR04Eci.js} +1 -1
  60. package/bizar-dash/dist/assets/{LibrariesView-DBQ83TNa.js.map → LibrariesView-1zR04Eci.js.map} +1 -1
  61. package/bizar-dash/dist/assets/{LightRAGView-JYpE5u9p.js → LightRAGView-PubmA9oL.js} +1 -1
  62. package/bizar-dash/dist/assets/{LightRAGView-JYpE5u9p.js.map → LightRAGView-PubmA9oL.js.map} +1 -1
  63. package/bizar-dash/dist/assets/{ListHeader-BGjm11Z0.js → ListHeader-Ak9WJd39.js} +1 -1
  64. package/bizar-dash/dist/assets/{ListHeader-BGjm11Z0.js.map → ListHeader-Ak9WJd39.js.map} +1 -1
  65. package/bizar-dash/dist/assets/{MemoryView-CnOP2MvM.js → MemoryView-DBGpuETw.js} +1 -1
  66. package/bizar-dash/dist/assets/{MemoryView-CnOP2MvM.js.map → MemoryView-DBGpuETw.js.map} +1 -1
  67. package/bizar-dash/dist/assets/MiscView-DufqBHkX.js +1 -0
  68. package/bizar-dash/dist/assets/{MiscView-BBcpUbZZ.js.map → MiscView-DufqBHkX.js.map} +1 -1
  69. package/bizar-dash/dist/assets/{ModsView-CU4cAmIz.js → ModsView-DcX6eVU2.js} +2 -2
  70. package/bizar-dash/dist/assets/{ModsView-CU4cAmIz.js.map → ModsView-DcX6eVU2.js.map} +1 -1
  71. package/bizar-dash/dist/assets/{NotificationsView-BYffvthq.js → NotificationsView-B8IhHRQC.js} +1 -1
  72. package/bizar-dash/dist/assets/{NotificationsView-BYffvthq.js.map → NotificationsView-B8IhHRQC.js.map} +1 -1
  73. package/bizar-dash/dist/assets/ObsidianView-DEuk65zS.js +1 -0
  74. package/bizar-dash/dist/assets/{ObsidianView-D3bI0row.js.map → ObsidianView-DEuk65zS.js.map} +1 -1
  75. package/bizar-dash/dist/assets/{OverviewView-0tq8f-Y0.js → OverviewView-CTI2spTd.js} +1 -1
  76. package/bizar-dash/dist/assets/{OverviewView-0tq8f-Y0.js.map → OverviewView-CTI2spTd.js.map} +1 -1
  77. package/bizar-dash/dist/assets/{ProgressBar-B-h60LKA.js → ProgressBar-D3lkz42E.js} +1 -1
  78. package/bizar-dash/dist/assets/{ProgressBar-B-h60LKA.js.map → ProgressBar-D3lkz42E.js.map} +1 -1
  79. package/bizar-dash/dist/assets/{ProjectsView-DhX5lzHS.js → ProjectsView-Du0LzE7A.js} +1 -1
  80. package/bizar-dash/dist/assets/{ProjectsView-DhX5lzHS.js.map → ProjectsView-Du0LzE7A.js.map} +1 -1
  81. package/bizar-dash/dist/assets/{ProvidersView-CJMX7jm9.js → ProvidersView-5bCgXwBo.js} +1 -1
  82. package/bizar-dash/dist/assets/{ProvidersView-CJMX7jm9.js.map → ProvidersView-5bCgXwBo.js.map} +1 -1
  83. package/bizar-dash/dist/assets/{SchedulesView-CcwDQ9Nm.js → SchedulesView-DFHdIz5P.js} +1 -1
  84. package/bizar-dash/dist/assets/{SchedulesView-CcwDQ9Nm.js.map → SchedulesView-DFHdIz5P.js.map} +1 -1
  85. package/bizar-dash/dist/assets/{Select-Cw7Qtz2M.js → Select-C8EJj4NM.js} +1 -1
  86. package/bizar-dash/dist/assets/{Select-Cw7Qtz2M.js.map → Select-C8EJj4NM.js.map} +1 -1
  87. package/bizar-dash/dist/assets/{SettingsRow-DgsgbPSI.js → SettingsRow-BdOOmYMD.js} +1 -1
  88. package/bizar-dash/dist/assets/{SettingsRow-DgsgbPSI.js.map → SettingsRow-BdOOmYMD.js.map} +1 -1
  89. package/bizar-dash/dist/assets/{SettingsView-DTAFdKyK.js → SettingsView-CqwQ6Knv.js} +1 -1
  90. package/bizar-dash/dist/assets/{SettingsView-DTAFdKyK.js.map → SettingsView-CqwQ6Knv.js.map} +1 -1
  91. package/bizar-dash/dist/assets/{Sheet-DH-WNJ3Y.js → Sheet-Cztsvgse.js} +1 -1
  92. package/bizar-dash/dist/assets/{Sheet-DH-WNJ3Y.js.map → Sheet-Cztsvgse.js.map} +1 -1
  93. package/bizar-dash/dist/assets/{Slider-DXbJuQ7y.js → Slider-BexNfF6K.js} +1 -1
  94. package/bizar-dash/dist/assets/{Slider-DXbJuQ7y.js.map → Slider-BexNfF6K.js.map} +1 -1
  95. package/bizar-dash/dist/assets/{Sparkline-CYtAn82j.js → Sparkline-CLZBtvsN.js} +1 -1
  96. package/bizar-dash/dist/assets/{Sparkline-CYtAn82j.js.map → Sparkline-CLZBtvsN.js.map} +1 -1
  97. package/bizar-dash/dist/assets/{Switch-BItGrPqr.js → Switch-B1tiRwNK.js} +1 -1
  98. package/bizar-dash/dist/assets/{Switch-BItGrPqr.js.map → Switch-B1tiRwNK.js.map} +1 -1
  99. package/bizar-dash/dist/assets/{TasksView-i5tm6CkX.js → TasksView-CT0fPlos.js} +1 -1
  100. package/bizar-dash/dist/assets/{TasksView-i5tm6CkX.js.map → TasksView-CT0fPlos.js.map} +1 -1
  101. package/bizar-dash/dist/assets/{Textarea-qYDf3yds.js → Textarea-D_TPpVMy.js} +1 -1
  102. package/bizar-dash/dist/assets/{Textarea-qYDf3yds.js.map → Textarea-D_TPpVMy.js.map} +1 -1
  103. package/bizar-dash/dist/assets/{UpdateView-Xln-ej26.js → UpdateView-tD2q2OhW.js} +1 -1
  104. package/bizar-dash/dist/assets/{UpdateView-Xln-ej26.js.map → UpdateView-tD2q2OhW.js.map} +1 -1
  105. package/bizar-dash/dist/assets/{UsageView-BGuZSUZ6.js → UsageView-B4BuAFKA.js} +1 -1
  106. package/bizar-dash/dist/assets/{UsageView-BGuZSUZ6.js.map → UsageView-B4BuAFKA.js.map} +1 -1
  107. package/bizar-dash/dist/assets/{ViewHeader-BqIPVKuG.js → ViewHeader-V_SzbUpw.js} +1 -1
  108. package/bizar-dash/dist/assets/{ViewHeader-BqIPVKuG.js.map → ViewHeader-V_SzbUpw.js.map} +1 -1
  109. package/bizar-dash/dist/assets/{VoiceView-CWUOCQs_.js → VoiceView-D3vb5OM2.js} +1 -1
  110. package/bizar-dash/dist/assets/{VoiceView-CWUOCQs_.js.map → VoiceView-D3vb5OM2.js.map} +1 -1
  111. package/bizar-dash/dist/assets/{brain-fsBSDl2g.js → brain-BmfWcitQ.js} +1 -1
  112. package/bizar-dash/dist/assets/{brain-fsBSDl2g.js.map → brain-BmfWcitQ.js.map} +1 -1
  113. package/bizar-dash/dist/assets/{calendar-DsHTZoCU.js → calendar-VntJUzFB.js} +1 -1
  114. package/bizar-dash/dist/assets/{calendar-DsHTZoCU.js.map → calendar-VntJUzFB.js.map} +1 -1
  115. package/bizar-dash/dist/assets/{circle-CqSxqqeJ.js → circle-KrQQySeK.js} +1 -1
  116. package/bizar-dash/dist/assets/{circle-CqSxqqeJ.js.map → circle-KrQQySeK.js.map} +1 -1
  117. package/bizar-dash/dist/assets/{circle-alert-BsLl001l.js → circle-alert-CQ9MLygI.js} +1 -1
  118. package/bizar-dash/dist/assets/{circle-alert-BsLl001l.js.map → circle-alert-CQ9MLygI.js.map} +1 -1
  119. package/bizar-dash/dist/assets/{circle-check-rVKMQmZp.js → circle-check-COtVgsWw.js} +1 -1
  120. package/bizar-dash/dist/assets/{circle-check-rVKMQmZp.js.map → circle-check-COtVgsWw.js.map} +1 -1
  121. package/bizar-dash/dist/assets/{clock-OuficfgH.js → clock-C0GlM4qp.js} +1 -1
  122. package/bizar-dash/dist/assets/{clock-OuficfgH.js.map → clock-C0GlM4qp.js.map} +1 -1
  123. package/bizar-dash/dist/assets/{download-BdHlstUY.js → download-CW4DmtRe.js} +1 -1
  124. package/bizar-dash/dist/assets/{download-BdHlstUY.js.map → download-CW4DmtRe.js.map} +1 -1
  125. package/bizar-dash/dist/assets/{external-link-DA3_VGm-.js → external-link-CAOnh_DH.js} +1 -1
  126. package/bizar-dash/dist/assets/{external-link-DA3_VGm-.js.map → external-link-CAOnh_DH.js.map} +1 -1
  127. package/bizar-dash/dist/assets/{file-text-B-g8H227.js → file-text-CS1jB_oV.js} +1 -1
  128. package/bizar-dash/dist/assets/{file-text-B-g8H227.js.map → file-text-CS1jB_oV.js.map} +1 -1
  129. package/bizar-dash/dist/assets/{filter-D9B8s5CG.js → filter-DyQbml3L.js} +1 -1
  130. package/bizar-dash/dist/assets/{filter-D9B8s5CG.js.map → filter-DyQbml3L.js.map} +1 -1
  131. package/bizar-dash/dist/assets/{git-pull-request-ByH0YuVz.js → git-pull-request-Co6gYfba.js} +1 -1
  132. package/bizar-dash/dist/assets/{git-pull-request-ByH0YuVz.js.map → git-pull-request-Co6gYfba.js.map} +1 -1
  133. package/bizar-dash/dist/assets/{main-CdOm1Pj9.js → main-CyAIirBB.js} +28 -33
  134. package/bizar-dash/dist/assets/main-CyAIirBB.js.map +1 -0
  135. package/bizar-dash/dist/assets/network-CDn43Gsj.js +6 -0
  136. package/bizar-dash/dist/assets/network-CDn43Gsj.js.map +1 -0
  137. package/bizar-dash/dist/assets/{pause-C9hgd8wX.js → pause-CKYjSTGX.js} +1 -1
  138. package/bizar-dash/dist/assets/{pause-C9hgd8wX.js.map → pause-CKYjSTGX.js.map} +1 -1
  139. package/bizar-dash/dist/assets/{pencil-BanqaMw7.js → pencil-BUJ2DpWs.js} +1 -1
  140. package/bizar-dash/dist/assets/{pencil-BanqaMw7.js.map → pencil-BUJ2DpWs.js.map} +1 -1
  141. package/bizar-dash/dist/assets/{play-CawUZ02_.js → play-CGxZWqtW.js} +1 -1
  142. package/bizar-dash/dist/assets/{play-CawUZ02_.js.map → play-CGxZWqtW.js.map} +1 -1
  143. package/bizar-dash/dist/assets/{plug-Cmv0-T_e.js → plug-CQYGgGSy.js} +1 -1
  144. package/bizar-dash/dist/assets/{plug-Cmv0-T_e.js.map → plug-CQYGgGSy.js.map} +1 -1
  145. package/bizar-dash/dist/assets/{plus-M6LYiKX8.js → plus-fFxt-8z5.js} +1 -1
  146. package/bizar-dash/dist/assets/{plus-M6LYiKX8.js.map → plus-fFxt-8z5.js.map} +1 -1
  147. package/bizar-dash/dist/assets/{power-DP5x_SRF.js → power-Cjgy2KsI.js} +1 -1
  148. package/bizar-dash/dist/assets/{power-DP5x_SRF.js.map → power-Cjgy2KsI.js.map} +1 -1
  149. package/bizar-dash/dist/assets/{power-off-NOJRLAIs.js → power-off-B81hLRah.js} +1 -1
  150. package/bizar-dash/dist/assets/{power-off-NOJRLAIs.js.map → power-off-B81hLRah.js.map} +1 -1
  151. package/bizar-dash/dist/assets/{refresh-ccw-CHMprsm5.js → refresh-ccw-BCXx86xp.js} +1 -1
  152. package/bizar-dash/dist/assets/{refresh-ccw-CHMprsm5.js.map → refresh-ccw-BCXx86xp.js.map} +1 -1
  153. package/bizar-dash/dist/assets/{refresh-cw-1RBqDKgJ.js → refresh-cw-COTg1nZo.js} +1 -1
  154. package/bizar-dash/dist/assets/{refresh-cw-1RBqDKgJ.js.map → refresh-cw-COTg1nZo.js.map} +1 -1
  155. package/bizar-dash/dist/assets/{rotate-ccw-DJRekBbi.js → rotate-ccw-BZrEVc0Z.js} +1 -1
  156. package/bizar-dash/dist/assets/{rotate-ccw-DJRekBbi.js.map → rotate-ccw-BZrEVc0Z.js.map} +1 -1
  157. package/bizar-dash/dist/assets/{rotate-cw-DHooc0Tx.js → rotate-cw-CsTtaLV2.js} +1 -1
  158. package/bizar-dash/dist/assets/{rotate-cw-DHooc0Tx.js.map → rotate-cw-CsTtaLV2.js.map} +1 -1
  159. package/bizar-dash/dist/assets/{save-DQKCKyZK.js → save-DtMTge1F.js} +1 -1
  160. package/bizar-dash/dist/assets/{save-DQKCKyZK.js.map → save-DtMTge1F.js.map} +1 -1
  161. package/bizar-dash/dist/assets/{send-xgy3RAi7.js → send-DyBhyk8t.js} +1 -1
  162. package/bizar-dash/dist/assets/{send-xgy3RAi7.js.map → send-DyBhyk8t.js.map} +1 -1
  163. package/bizar-dash/dist/assets/{shield-alert-CWV2F5ab.js → shield-alert-BPGJlRF8.js} +1 -1
  164. package/bizar-dash/dist/assets/{shield-alert-CWV2F5ab.js.map → shield-alert-BPGJlRF8.js.map} +1 -1
  165. package/bizar-dash/dist/assets/{trash-2-CL4khSRv.js → trash-2-2NsyTU8c.js} +1 -1
  166. package/bizar-dash/dist/assets/{trash-2-CL4khSRv.js.map → trash-2-2NsyTU8c.js.map} +1 -1
  167. package/bizar-dash/dist/assets/{trending-up-CSJJhWTS.js → trending-up-BXwP23VK.js} +1 -1
  168. package/bizar-dash/dist/assets/{trending-up-CSJJhWTS.js.map → trending-up-BXwP23VK.js.map} +1 -1
  169. package/bizar-dash/dist/assets/{triangle-alert-BPLb7uLt.js → triangle-alert-DFmQ_RXN.js} +1 -1
  170. package/bizar-dash/dist/assets/{triangle-alert-BPLb7uLt.js.map → triangle-alert-DFmQ_RXN.js.map} +1 -1
  171. package/bizar-dash/dist/assets/{upload-Cww6MvFq.js → upload-Cj-HYRYV.js} +1 -1
  172. package/bizar-dash/dist/assets/{upload-Cww6MvFq.js.map → upload-Cj-HYRYV.js.map} +1 -1
  173. package/bizar-dash/dist/assets/{zap-DmhVUzRA.js → zap-BaOiybcl.js} +1 -1
  174. package/bizar-dash/dist/assets/{zap-DmhVUzRA.js.map → zap-BaOiybcl.js.map} +1 -1
  175. package/bizar-dash/dist/index.html +1 -1
  176. package/bizar-dash/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
  177. package/bizar-dash/src/server/api.mjs +11 -0
  178. package/bizar-dash/src/server/artifacts-store.mjs +120 -14
  179. package/bizar-dash/src/server/claude-artifacts.mjs +281 -0
  180. package/bizar-dash/src/server/routes/artifacts.mjs +42 -6
  181. package/bizar-dash/src/server/routes/audit.mjs +78 -0
  182. package/bizar-dash/src/server/routes/decisions.mjs +78 -0
  183. package/bizar-dash/src/server/routes/model-router.mjs +55 -0
  184. package/bizar-dash/src/server/routes/model-router.test.mjs +28 -0
  185. package/bizar-dash/src/server/routes/sessions.mjs +80 -0
  186. package/bizar-dash/src/server/routes/update.mjs +48 -21
  187. package/bizar-dash/src/server/sprint.test.mjs +163 -0
  188. package/bizar-dash/src/web/v8/App.tsx +0 -4
  189. package/bizar-dash/src/web/v8/__tests__/new-views.test.tsx +0 -17
  190. package/bizar-dash/src/web/v8/shell/Sidebar.tsx +0 -1
  191. package/bizar-dash/src/web/v8/views/Artifacts/ArtifactsView.tsx +232 -21
  192. package/bizar-dash/src/web/v8/views/Artifacts/ClaudeArtifactView.tsx +179 -0
  193. package/bizar-dash/src/web/v8/views/Router.tsx +0 -5
  194. package/bizar-dash/tests/_update-test-helpers.mjs +13 -0
  195. package/bizar-dash/tests/update-check.test.mjs +18 -13
  196. package/bizar-dash/tests/update-packages.test.mjs +154 -0
  197. package/bizar-dash/tests/update-run.test.mjs +17 -80
  198. package/cli/banner.mjs +1 -1
  199. package/cli/bin.mjs +8 -1
  200. package/cli/bootstrap.mjs +1 -1
  201. package/cli/commands/claude-cmd.mjs +1 -1
  202. package/cli/commands/deploy/docker.mjs +0 -3
  203. package/cli/install/banner.mjs +67 -0
  204. package/cli/install/banner.test.mjs +39 -0
  205. package/cli/install/index.mjs +32 -0
  206. package/cli/install/index.test.mjs +61 -0
  207. package/cli/install/paths.mjs +80 -0
  208. package/cli/install/paths.test.mjs +77 -0
  209. package/cli/install/plugin.mjs +161 -0
  210. package/cli/install/postinstall.mjs +111 -0
  211. package/cli/install.mjs +13 -600
  212. package/cli/migrate.mjs +157 -0
  213. package/cli/migrate.test.mjs +85 -0
  214. package/cli/provision.mjs +615 -1918
  215. package/cli/provision.test.mjs +1 -1
  216. package/cli/service-controller.test.mjs +0 -1
  217. package/cli/service-env.mjs +0 -1
  218. package/cli/utils.mjs +0 -1
  219. package/install.sh +54 -466
  220. package/package.json +1 -1
  221. package/packages/sdk/dist/agent/cron.d.ts +44 -0
  222. package/packages/sdk/dist/agent/cron.js +79 -0
  223. package/packages/sdk/dist/agent/heartbeat.d.ts +43 -0
  224. package/packages/sdk/dist/agent/heartbeat.js +116 -0
  225. package/packages/sdk/dist/index.d.ts +3 -0
  226. package/packages/sdk/dist/index.js +5 -0
  227. package/packages/sdk/dist/learning/decisions.d.ts +46 -0
  228. package/packages/sdk/dist/learning/decisions.js +132 -0
  229. package/packages/sdk/dist/learning/index.d.ts +8 -0
  230. package/packages/sdk/dist/learning/index.js +8 -0
  231. package/packages/sdk/dist/learning/instincts.d.ts +38 -0
  232. package/packages/sdk/dist/learning/instincts.js +139 -0
  233. package/packages/sdk/dist/mcp/server.js +119 -1
  234. package/packages/sdk/dist/router/agent-model-registry.d.ts +89 -0
  235. package/packages/sdk/dist/router/agent-model-registry.js +144 -0
  236. package/packages/sdk/dist/router/index.d.ts +1 -0
  237. package/packages/sdk/dist/router/index.js +1 -0
  238. package/packages/sdk/package.json +3 -2
  239. package/scripts/audit.mjs +388 -0
  240. package/scripts/audit.test.mjs +149 -0
  241. package/scripts/eval-gate.mjs +134 -0
  242. package/scripts/eval-gate.test.mjs +138 -0
  243. package/scripts/feature-state-machine.mjs +178 -0
  244. package/scripts/feature-state-machine.test.mjs +135 -0
  245. package/scripts/install-curl.sh +17 -0
  246. package/scripts/spec-dedup.test.mjs +124 -0
  247. package/scripts/sprint.mjs +213 -0
  248. package/scripts/worktree-setup.sh +79 -0
  249. package/bizar-dash/dist/assets/ArtifactsView-CDIhPBAx.js +0 -6
  250. package/bizar-dash/dist/assets/ArtifactsView-CDIhPBAx.js.map +0 -1
  251. package/bizar-dash/dist/assets/HeadroomView-CNc-TI7u.js +0 -11
  252. package/bizar-dash/dist/assets/HeadroomView-CNc-TI7u.js.map +0 -1
  253. package/bizar-dash/dist/assets/MiscView-BBcpUbZZ.js +0 -1
  254. package/bizar-dash/dist/assets/ObsidianView-D3bI0row.js +0 -1
  255. package/bizar-dash/dist/assets/main-CdOm1Pj9.js.map +0 -1
  256. package/bizar-dash/src/web/v8/views/Headroom/HeadroomView.tsx +0 -201
  257. package/bizar-dash/tests/graphify-mod-spawn.node.test.mjs +0 -90
  258. package/bizar-dash/tests/v7-archive/mobile-overview.test.tsx +0 -214
  259. package/bizar-dash/tests/v7-archive/mobile-settings.test.tsx +0 -181
  260. package/bizar-dash/tests/v7-archive/navigation/CommandPalette.test.tsx +0 -105
  261. package/bizar-dash/tests/v7-archive/settings-nav.test.tsx +0 -128
  262. package/bizar-dash/tests/v7-archive/views/Overview.test.tsx +0 -413
  263. package/cli/provision-claude.mjs +0 -1176
@@ -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
+ });
@@ -0,0 +1,134 @@
1
+ /**
2
+ * eval-gate.mjs — Verify passing features have satisfying eval files.
3
+ *
4
+ * For each feature with state === "passing", checks that:
5
+ * 1. .harness/evals/<id>.jsonl exists
6
+ * 2. The file has at least one parseable JSON line
7
+ * 3. The pass-rate (passed / total) >= threshold (default 0.9)
8
+ *
9
+ * Usage:
10
+ * bun run scripts/eval-gate.mjs [--threshold=0.9] [--dry-run] [--json]
11
+ * make eval-gate
12
+ */
13
+
14
+ import { readFileSync, existsSync } from "node:fs";
15
+ import { join, dirname } from "node:path";
16
+ import { fileURLToPath } from "node:url";
17
+
18
+ const __dirname = dirname(fileURLToPath(import.meta.url));
19
+ const ROOT = join(__dirname, "..");
20
+ const FEATURE_LIST_PATH = join(ROOT, "feature_list.json");
21
+ const EVALS_DIR = join(ROOT, ".harness", "evals");
22
+
23
+ const DEFAULT_THRESHOLD = 0.9;
24
+
25
+ function readJson(/** @type {string} */ path) {
26
+ return JSON.parse(readFileSync(path, "utf-8"));
27
+ }
28
+
29
+ /**
30
+ * @param {{ id: string, behavior: string, state: string }} feature
31
+ * @param {number} threshold
32
+ * @returns {{ ok: boolean, reason?: string, detail?: string }}
33
+ */
34
+ function checkFeature(feature, threshold) {
35
+ if (feature.state !== "passing") {
36
+ return { ok: true };
37
+ }
38
+
39
+ const evalPath = join(EVALS_DIR, `${feature.id}.jsonl`);
40
+
41
+ if (!existsSync(evalPath)) {
42
+ return { ok: false, reason: "eval file not found", detail: evalPath };
43
+ }
44
+
45
+ let content;
46
+ try {
47
+ content = readFileSync(evalPath, "utf-8");
48
+ } catch {
49
+ return { ok: false, reason: "eval file unreadable", detail: evalPath };
50
+ }
51
+
52
+ if (!content.trim()) {
53
+ return { ok: false, reason: "eval file is empty", detail: evalPath };
54
+ }
55
+
56
+ const lines = content.split("\n").filter((l) => l.trim() !== "");
57
+ let passed = 0;
58
+ let total = 0;
59
+ for (const line of lines) {
60
+ try {
61
+ const record = JSON.parse(line);
62
+ total++;
63
+ if (record.passed === true || record.pass === true || record.status === "pass") {
64
+ passed++;
65
+ }
66
+ } catch {
67
+ // Malformed line — skip (lenient)
68
+ }
69
+ }
70
+
71
+ if (total === 0) {
72
+ return { ok: false, reason: "eval file has no parseable records", detail: evalPath };
73
+ }
74
+
75
+ const rate = passed / total;
76
+ if (rate < threshold) {
77
+ return {
78
+ ok: false,
79
+ reason: `pass-rate ${rate.toFixed(3)} < threshold ${threshold}`,
80
+ detail: evalPath,
81
+ };
82
+ }
83
+
84
+ return { ok: true };
85
+ }
86
+
87
+ // CLI
88
+ const args = process.argv.slice(2);
89
+ const thresholdArg = args.find((a) => a.startsWith("--threshold="));
90
+ const dryRun = args.includes("--dry-run");
91
+ const jsonOutput = args.includes("--json");
92
+ const threshold = thresholdArg
93
+ ? parseFloat(thresholdArg.split("=")[1])
94
+ : DEFAULT_THRESHOLD;
95
+
96
+ const featureList = readJson(FEATURE_LIST_PATH);
97
+ const features = /** @type {Array<{id: string, behavior: string, state: string}>} */ (featureList.features ?? []);
98
+
99
+ const results = [];
100
+ let passCount = 0;
101
+ let failCount = 0;
102
+
103
+ for (const feature of features) {
104
+ const result = checkFeature(feature, threshold);
105
+ results.push({ featureId: feature.id, behavior: feature.behavior, ...result });
106
+ if (result.ok) {
107
+ passCount++;
108
+ } else {
109
+ failCount++;
110
+ }
111
+ }
112
+
113
+ if (jsonOutput) {
114
+ console.log(
115
+ JSON.stringify({ threshold, total: results.length, passing: passCount, failing: failCount, results }, null, 2)
116
+ );
117
+ } else {
118
+ console.log(`\n▶ Eval gate — threshold: ${threshold}`);
119
+ console.log("─".repeat(60));
120
+ for (const r of results) {
121
+ if (r.ok) {
122
+ console.log(` PASS ${r.featureId}`);
123
+ } else {
124
+ console.log(` FAIL ${r.featureId} — ${r.reason}`);
125
+ if (r.detail) console.log(` (${r.detail})`);
126
+ }
127
+ }
128
+ console.log("─".repeat(60));
129
+ console.log(` ${passCount} passing, ${failCount} failing\n`);
130
+ }
131
+
132
+ if (failCount > 0 && !dryRun) {
133
+ process.exit(1);
134
+ }