@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.
Files changed (223) hide show
  1. package/README.md +0 -2
  2. package/bizar-dash/dist/assets/{ActivityFeed-Da-JCrE6.js → ActivityFeed-JjmOY2AQ.js} +1 -1
  3. package/bizar-dash/dist/assets/{ActivityFeed-Da-JCrE6.js.map → ActivityFeed-JjmOY2AQ.js.map} +1 -1
  4. package/bizar-dash/dist/assets/{ActivityView-nIRsSETb.js → ActivityView-BIIMvGWo.js} +1 -1
  5. package/bizar-dash/dist/assets/{ActivityView-nIRsSETb.js.map → ActivityView-BIIMvGWo.js.map} +1 -1
  6. package/bizar-dash/dist/assets/{AdminView-DP1NMxmG.js → AdminView-DRidJtkq.js} +1 -1
  7. package/bizar-dash/dist/assets/{AdminView-DP1NMxmG.js.map → AdminView-DRidJtkq.js.map} +1 -1
  8. package/bizar-dash/dist/assets/{AgentActivity-lSPkOr-O.js → AgentActivity-79l4SBMC.js} +1 -1
  9. package/bizar-dash/dist/assets/{AgentActivity-lSPkOr-O.js.map → AgentActivity-79l4SBMC.js.map} +1 -1
  10. package/bizar-dash/dist/assets/{AgentsView-BIWGkz7w.js → AgentsView-0vT4uPSc.js} +1 -1
  11. package/bizar-dash/dist/assets/{AgentsView-BIWGkz7w.js.map → AgentsView-0vT4uPSc.js.map} +1 -1
  12. package/bizar-dash/dist/assets/{Alert-DN0UysMg.js → Alert-CG5q_s75.js} +1 -1
  13. package/bizar-dash/dist/assets/{Alert-DN0UysMg.js.map → Alert-CG5q_s75.js.map} +1 -1
  14. package/bizar-dash/dist/assets/ArtifactsView-DM8ZmpR9.js +21 -0
  15. package/bizar-dash/dist/assets/ArtifactsView-DM8ZmpR9.js.map +1 -0
  16. package/bizar-dash/dist/assets/{AuthView-DW5cs7ma.js → AuthView-BveN94MC.js} +1 -1
  17. package/bizar-dash/dist/assets/{AuthView-DW5cs7ma.js.map → AuthView-BveN94MC.js.map} +1 -1
  18. package/bizar-dash/dist/assets/{Avatar-DZPv9pvd.js → Avatar-ulUPIYTd.js} +1 -1
  19. package/bizar-dash/dist/assets/{Avatar-DZPv9pvd.js.map → Avatar-ulUPIYTd.js.map} +1 -1
  20. package/bizar-dash/dist/assets/{BackgroundJobsView-D8O-EyMD.js → BackgroundJobsView-BWErhqFo.js} +1 -1
  21. package/bizar-dash/dist/assets/{BackgroundJobsView-D8O-EyMD.js.map → BackgroundJobsView-BWErhqFo.js.map} +1 -1
  22. package/bizar-dash/dist/assets/{BackupView-uwXkhxOV.js → BackupView-CnBjzG9N.js} +1 -1
  23. package/bizar-dash/dist/assets/{BackupView-uwXkhxOV.js.map → BackupView-CnBjzG9N.js.map} +1 -1
  24. package/bizar-dash/dist/assets/{Card-Tyboihu7.js → Card-B0imhxMk.js} +1 -1
  25. package/bizar-dash/dist/assets/{Card-Tyboihu7.js.map → Card-B0imhxMk.js.map} +1 -1
  26. package/bizar-dash/dist/assets/{ChatView-DRBHzgay.js → ChatView-D6zGytzx.js} +1 -1
  27. package/bizar-dash/dist/assets/{ChatView-DRBHzgay.js.map → ChatView-D6zGytzx.js.map} +1 -1
  28. package/bizar-dash/dist/assets/{Chip-BrXIlR9w.js → Chip-wwZSGwLE.js} +1 -1
  29. package/bizar-dash/dist/assets/{Chip-BrXIlR9w.js.map → Chip-wwZSGwLE.js.map} +1 -1
  30. package/bizar-dash/dist/assets/{ClaudeSessionsView-Ck62jaOr.js → ClaudeSessionsView-DK1sOLhi.js} +1 -1
  31. package/bizar-dash/dist/assets/{ClaudeSessionsView-Ck62jaOr.js.map → ClaudeSessionsView-DK1sOLhi.js.map} +1 -1
  32. package/bizar-dash/dist/assets/{ClipboardView-DfND6xL6.js → ClipboardView-CZ2lYPr0.js} +1 -1
  33. package/bizar-dash/dist/assets/{ClipboardView-DfND6xL6.js.map → ClipboardView-CZ2lYPr0.js.map} +1 -1
  34. package/bizar-dash/dist/assets/{ConfigView-DjJmSrOJ.js → ConfigView-D-zT9eNA.js} +1 -1
  35. package/bizar-dash/dist/assets/{ConfigView-DjJmSrOJ.js.map → ConfigView-D-zT9eNA.js.map} +1 -1
  36. package/bizar-dash/dist/assets/{DiagnosticsView-CKgItf0J.js → DiagnosticsView-BocV68Lb.js} +1 -1
  37. package/bizar-dash/dist/assets/{DiagnosticsView-CKgItf0J.js.map → DiagnosticsView-BocV68Lb.js.map} +1 -1
  38. package/bizar-dash/dist/assets/{DialogsView-DHYF8dE1.js → DialogsView-BVjPI5x7.js} +1 -1
  39. package/bizar-dash/dist/assets/{DialogsView-DHYF8dE1.js.map → DialogsView-BVjPI5x7.js.map} +1 -1
  40. package/bizar-dash/dist/assets/{DoctorView-DDLHrSKk.js → DoctorView-84gJcZwM.js} +1 -1
  41. package/bizar-dash/dist/assets/{DoctorView-DDLHrSKk.js.map → DoctorView-84gJcZwM.js.map} +1 -1
  42. package/bizar-dash/dist/assets/{EmptyState-DZ2ouKwd.js → EmptyState-BjgVOrcO.js} +1 -1
  43. package/bizar-dash/dist/assets/{EmptyState-DZ2ouKwd.js.map → EmptyState-BjgVOrcO.js.map} +1 -1
  44. package/bizar-dash/dist/assets/{EnvVarsView-D1cx83mB.js → EnvVarsView-BJ2TEzF7.js} +1 -1
  45. package/bizar-dash/dist/assets/{EnvVarsView-D1cx83mB.js.map → EnvVarsView-BJ2TEzF7.js.map} +1 -1
  46. package/bizar-dash/dist/assets/{ErrorState-DwwJ2-Jq.js → ErrorState-BE3WBFqF.js} +1 -1
  47. package/bizar-dash/dist/assets/{ErrorState-DwwJ2-Jq.js.map → ErrorState-BE3WBFqF.js.map} +1 -1
  48. package/bizar-dash/dist/assets/{EvalView-C9aYixXW.js → EvalView-BJJ2P-kK.js} +1 -1
  49. package/bizar-dash/dist/assets/{EvalView-C9aYixXW.js.map → EvalView-BJJ2P-kK.js.map} +1 -1
  50. package/bizar-dash/dist/assets/{GoalsView-DZa_mGmh.js → GoalsView-pwROHApi.js} +1 -1
  51. package/bizar-dash/dist/assets/{GoalsView-DZa_mGmh.js.map → GoalsView-pwROHApi.js.map} +1 -1
  52. package/bizar-dash/dist/assets/{Grid-CiRyhAgR.js → Grid-qcvbhx6e.js} +1 -1
  53. package/bizar-dash/dist/assets/{Grid-CiRyhAgR.js.map → Grid-qcvbhx6e.js.map} +1 -1
  54. package/bizar-dash/dist/assets/{HeadroomView-CNc-TI7u.js → HeadroomView-D1UiTYbt.js} +1 -1
  55. package/bizar-dash/dist/assets/{HeadroomView-CNc-TI7u.js.map → HeadroomView-D1UiTYbt.js.map} +1 -1
  56. package/bizar-dash/dist/assets/{HistoryView-Dv7aPxJE.js → HistoryView-C7SSOLJA.js} +1 -1
  57. package/bizar-dash/dist/assets/{HistoryView-Dv7aPxJE.js.map → HistoryView-C7SSOLJA.js.map} +1 -1
  58. package/bizar-dash/dist/assets/{Input-BbFUDQnS.js → Input-Bgzxf_Hu.js} +1 -1
  59. package/bizar-dash/dist/assets/{Input-BbFUDQnS.js.map → Input-Bgzxf_Hu.js.map} +1 -1
  60. package/bizar-dash/dist/assets/{LibrariesView-DBQ83TNa.js → LibrariesView-CbFFksox.js} +1 -1
  61. package/bizar-dash/dist/assets/{LibrariesView-DBQ83TNa.js.map → LibrariesView-CbFFksox.js.map} +1 -1
  62. package/bizar-dash/dist/assets/{LightRAGView-JYpE5u9p.js → LightRAGView-BqDrJbRq.js} +1 -1
  63. package/bizar-dash/dist/assets/{LightRAGView-JYpE5u9p.js.map → LightRAGView-BqDrJbRq.js.map} +1 -1
  64. package/bizar-dash/dist/assets/{ListHeader-BGjm11Z0.js → ListHeader-TjPJrUfY.js} +1 -1
  65. package/bizar-dash/dist/assets/{ListHeader-BGjm11Z0.js.map → ListHeader-TjPJrUfY.js.map} +1 -1
  66. package/bizar-dash/dist/assets/{MemoryView-CnOP2MvM.js → MemoryView-BlTeHLhX.js} +1 -1
  67. package/bizar-dash/dist/assets/{MemoryView-CnOP2MvM.js.map → MemoryView-BlTeHLhX.js.map} +1 -1
  68. package/bizar-dash/dist/assets/{MiscView-BBcpUbZZ.js → MiscView-B8QY82Pm.js} +1 -1
  69. package/bizar-dash/dist/assets/{MiscView-BBcpUbZZ.js.map → MiscView-B8QY82Pm.js.map} +1 -1
  70. package/bizar-dash/dist/assets/{ModsView-CU4cAmIz.js → ModsView-CvW1OWts.js} +1 -1
  71. package/bizar-dash/dist/assets/{ModsView-CU4cAmIz.js.map → ModsView-CvW1OWts.js.map} +1 -1
  72. package/bizar-dash/dist/assets/{NotificationsView-BYffvthq.js → NotificationsView-CsBt5U7x.js} +1 -1
  73. package/bizar-dash/dist/assets/{NotificationsView-BYffvthq.js.map → NotificationsView-CsBt5U7x.js.map} +1 -1
  74. package/bizar-dash/dist/assets/{ObsidianView-D3bI0row.js → ObsidianView-BCTejEj2.js} +1 -1
  75. package/bizar-dash/dist/assets/{ObsidianView-D3bI0row.js.map → ObsidianView-BCTejEj2.js.map} +1 -1
  76. package/bizar-dash/dist/assets/{OverviewView-0tq8f-Y0.js → OverviewView-BsuPxwnB.js} +1 -1
  77. package/bizar-dash/dist/assets/{OverviewView-0tq8f-Y0.js.map → OverviewView-BsuPxwnB.js.map} +1 -1
  78. package/bizar-dash/dist/assets/{ProgressBar-B-h60LKA.js → ProgressBar-DlZTETEn.js} +1 -1
  79. package/bizar-dash/dist/assets/{ProgressBar-B-h60LKA.js.map → ProgressBar-DlZTETEn.js.map} +1 -1
  80. package/bizar-dash/dist/assets/{ProjectsView-DhX5lzHS.js → ProjectsView-Soxtmpet.js} +1 -1
  81. package/bizar-dash/dist/assets/{ProjectsView-DhX5lzHS.js.map → ProjectsView-Soxtmpet.js.map} +1 -1
  82. package/bizar-dash/dist/assets/{ProvidersView-CJMX7jm9.js → ProvidersView-DaCEV9pM.js} +1 -1
  83. package/bizar-dash/dist/assets/{ProvidersView-CJMX7jm9.js.map → ProvidersView-DaCEV9pM.js.map} +1 -1
  84. package/bizar-dash/dist/assets/{SchedulesView-CcwDQ9Nm.js → SchedulesView-DY2ByBj_.js} +1 -1
  85. package/bizar-dash/dist/assets/{SchedulesView-CcwDQ9Nm.js.map → SchedulesView-DY2ByBj_.js.map} +1 -1
  86. package/bizar-dash/dist/assets/{Select-Cw7Qtz2M.js → Select-Dbd88_n8.js} +1 -1
  87. package/bizar-dash/dist/assets/{Select-Cw7Qtz2M.js.map → Select-Dbd88_n8.js.map} +1 -1
  88. package/bizar-dash/dist/assets/{SettingsRow-DgsgbPSI.js → SettingsRow-CLMNd434.js} +1 -1
  89. package/bizar-dash/dist/assets/{SettingsRow-DgsgbPSI.js.map → SettingsRow-CLMNd434.js.map} +1 -1
  90. package/bizar-dash/dist/assets/{SettingsView-DTAFdKyK.js → SettingsView-b24oFq9x.js} +1 -1
  91. package/bizar-dash/dist/assets/{SettingsView-DTAFdKyK.js.map → SettingsView-b24oFq9x.js.map} +1 -1
  92. package/bizar-dash/dist/assets/{Sheet-DH-WNJ3Y.js → Sheet-DnDid58j.js} +1 -1
  93. package/bizar-dash/dist/assets/{Sheet-DH-WNJ3Y.js.map → Sheet-DnDid58j.js.map} +1 -1
  94. package/bizar-dash/dist/assets/{Slider-DXbJuQ7y.js → Slider-BJCvKI1I.js} +1 -1
  95. package/bizar-dash/dist/assets/{Slider-DXbJuQ7y.js.map → Slider-BJCvKI1I.js.map} +1 -1
  96. package/bizar-dash/dist/assets/{Sparkline-CYtAn82j.js → Sparkline-ktqQLdyb.js} +1 -1
  97. package/bizar-dash/dist/assets/{Sparkline-CYtAn82j.js.map → Sparkline-ktqQLdyb.js.map} +1 -1
  98. package/bizar-dash/dist/assets/{Switch-BItGrPqr.js → Switch-CwXfsDii.js} +1 -1
  99. package/bizar-dash/dist/assets/{Switch-BItGrPqr.js.map → Switch-CwXfsDii.js.map} +1 -1
  100. package/bizar-dash/dist/assets/{TasksView-i5tm6CkX.js → TasksView-BHmpzFCf.js} +1 -1
  101. package/bizar-dash/dist/assets/{TasksView-i5tm6CkX.js.map → TasksView-BHmpzFCf.js.map} +1 -1
  102. package/bizar-dash/dist/assets/{Textarea-qYDf3yds.js → Textarea-BzIAwSlp.js} +1 -1
  103. package/bizar-dash/dist/assets/{Textarea-qYDf3yds.js.map → Textarea-BzIAwSlp.js.map} +1 -1
  104. package/bizar-dash/dist/assets/{UpdateView-Xln-ej26.js → UpdateView-CSmX9NN0.js} +1 -1
  105. package/bizar-dash/dist/assets/{UpdateView-Xln-ej26.js.map → UpdateView-CSmX9NN0.js.map} +1 -1
  106. package/bizar-dash/dist/assets/{UsageView-BGuZSUZ6.js → UsageView-COyr_Gfi.js} +1 -1
  107. package/bizar-dash/dist/assets/{UsageView-BGuZSUZ6.js.map → UsageView-COyr_Gfi.js.map} +1 -1
  108. package/bizar-dash/dist/assets/{ViewHeader-BqIPVKuG.js → ViewHeader-BzYZ3m-e.js} +1 -1
  109. package/bizar-dash/dist/assets/{ViewHeader-BqIPVKuG.js.map → ViewHeader-BzYZ3m-e.js.map} +1 -1
  110. package/bizar-dash/dist/assets/{VoiceView-CWUOCQs_.js → VoiceView-D33_xG5t.js} +1 -1
  111. package/bizar-dash/dist/assets/{VoiceView-CWUOCQs_.js.map → VoiceView-D33_xG5t.js.map} +1 -1
  112. package/bizar-dash/dist/assets/{brain-fsBSDl2g.js → brain-CM-Vls8r.js} +1 -1
  113. package/bizar-dash/dist/assets/{brain-fsBSDl2g.js.map → brain-CM-Vls8r.js.map} +1 -1
  114. package/bizar-dash/dist/assets/{calendar-DsHTZoCU.js → calendar-C0lgZk69.js} +1 -1
  115. package/bizar-dash/dist/assets/{calendar-DsHTZoCU.js.map → calendar-C0lgZk69.js.map} +1 -1
  116. package/bizar-dash/dist/assets/{circle-CqSxqqeJ.js → circle-Bx_hQEBC.js} +1 -1
  117. package/bizar-dash/dist/assets/{circle-CqSxqqeJ.js.map → circle-Bx_hQEBC.js.map} +1 -1
  118. package/bizar-dash/dist/assets/{circle-alert-BsLl001l.js → circle-alert-DHvsqpw5.js} +1 -1
  119. package/bizar-dash/dist/assets/{circle-alert-BsLl001l.js.map → circle-alert-DHvsqpw5.js.map} +1 -1
  120. package/bizar-dash/dist/assets/{circle-check-rVKMQmZp.js → circle-check-Bx8wmXR9.js} +1 -1
  121. package/bizar-dash/dist/assets/{circle-check-rVKMQmZp.js.map → circle-check-Bx8wmXR9.js.map} +1 -1
  122. package/bizar-dash/dist/assets/{clock-OuficfgH.js → clock-CejGoecX.js} +1 -1
  123. package/bizar-dash/dist/assets/{clock-OuficfgH.js.map → clock-CejGoecX.js.map} +1 -1
  124. package/bizar-dash/dist/assets/{download-BdHlstUY.js → download-4cEUWue1.js} +1 -1
  125. package/bizar-dash/dist/assets/{download-BdHlstUY.js.map → download-4cEUWue1.js.map} +1 -1
  126. package/bizar-dash/dist/assets/{external-link-DA3_VGm-.js → external-link-0NqUhI4i.js} +1 -1
  127. package/bizar-dash/dist/assets/{external-link-DA3_VGm-.js.map → external-link-0NqUhI4i.js.map} +1 -1
  128. package/bizar-dash/dist/assets/{file-text-B-g8H227.js → file-text-yEMkrSoZ.js} +1 -1
  129. package/bizar-dash/dist/assets/{file-text-B-g8H227.js.map → file-text-yEMkrSoZ.js.map} +1 -1
  130. package/bizar-dash/dist/assets/{filter-D9B8s5CG.js → filter-BXt60zAS.js} +1 -1
  131. package/bizar-dash/dist/assets/{filter-D9B8s5CG.js.map → filter-BXt60zAS.js.map} +1 -1
  132. package/bizar-dash/dist/assets/{git-pull-request-ByH0YuVz.js → git-pull-request-BjG5lNtR.js} +1 -1
  133. package/bizar-dash/dist/assets/{git-pull-request-ByH0YuVz.js.map → git-pull-request-BjG5lNtR.js.map} +1 -1
  134. package/bizar-dash/dist/assets/{main-CdOm1Pj9.js → main-CokHAXWM.js} +2 -2
  135. package/bizar-dash/dist/assets/{main-CdOm1Pj9.js.map → main-CokHAXWM.js.map} +1 -1
  136. package/bizar-dash/dist/assets/{pause-C9hgd8wX.js → pause-CAmulU0F.js} +1 -1
  137. package/bizar-dash/dist/assets/{pause-C9hgd8wX.js.map → pause-CAmulU0F.js.map} +1 -1
  138. package/bizar-dash/dist/assets/{pencil-BanqaMw7.js → pencil-eq5IqBmU.js} +1 -1
  139. package/bizar-dash/dist/assets/{pencil-BanqaMw7.js.map → pencil-eq5IqBmU.js.map} +1 -1
  140. package/bizar-dash/dist/assets/{play-CawUZ02_.js → play-BoLrrcBA.js} +1 -1
  141. package/bizar-dash/dist/assets/{play-CawUZ02_.js.map → play-BoLrrcBA.js.map} +1 -1
  142. package/bizar-dash/dist/assets/{plug-Cmv0-T_e.js → plug-DBrVM9lK.js} +1 -1
  143. package/bizar-dash/dist/assets/{plug-Cmv0-T_e.js.map → plug-DBrVM9lK.js.map} +1 -1
  144. package/bizar-dash/dist/assets/{plus-M6LYiKX8.js → plus-DENm0hqV.js} +1 -1
  145. package/bizar-dash/dist/assets/{plus-M6LYiKX8.js.map → plus-DENm0hqV.js.map} +1 -1
  146. package/bizar-dash/dist/assets/{power-DP5x_SRF.js → power-DLjXF7zE.js} +1 -1
  147. package/bizar-dash/dist/assets/{power-DP5x_SRF.js.map → power-DLjXF7zE.js.map} +1 -1
  148. package/bizar-dash/dist/assets/{power-off-NOJRLAIs.js → power-off-D47cOnG_.js} +1 -1
  149. package/bizar-dash/dist/assets/{power-off-NOJRLAIs.js.map → power-off-D47cOnG_.js.map} +1 -1
  150. package/bizar-dash/dist/assets/{refresh-ccw-CHMprsm5.js → refresh-ccw-DNrXX9gB.js} +1 -1
  151. package/bizar-dash/dist/assets/{refresh-ccw-CHMprsm5.js.map → refresh-ccw-DNrXX9gB.js.map} +1 -1
  152. package/bizar-dash/dist/assets/{refresh-cw-1RBqDKgJ.js → refresh-cw-CoAHDpeS.js} +1 -1
  153. package/bizar-dash/dist/assets/{refresh-cw-1RBqDKgJ.js.map → refresh-cw-CoAHDpeS.js.map} +1 -1
  154. package/bizar-dash/dist/assets/{rotate-ccw-DJRekBbi.js → rotate-ccw-ObX5awaG.js} +1 -1
  155. package/bizar-dash/dist/assets/{rotate-ccw-DJRekBbi.js.map → rotate-ccw-ObX5awaG.js.map} +1 -1
  156. package/bizar-dash/dist/assets/{rotate-cw-DHooc0Tx.js → rotate-cw-xpPJw9LP.js} +1 -1
  157. package/bizar-dash/dist/assets/{rotate-cw-DHooc0Tx.js.map → rotate-cw-xpPJw9LP.js.map} +1 -1
  158. package/bizar-dash/dist/assets/{save-DQKCKyZK.js → save-D1iKiJJl.js} +1 -1
  159. package/bizar-dash/dist/assets/{save-DQKCKyZK.js.map → save-D1iKiJJl.js.map} +1 -1
  160. package/bizar-dash/dist/assets/{send-xgy3RAi7.js → send-BRcAhZUm.js} +1 -1
  161. package/bizar-dash/dist/assets/{send-xgy3RAi7.js.map → send-BRcAhZUm.js.map} +1 -1
  162. package/bizar-dash/dist/assets/{shield-alert-CWV2F5ab.js → shield-alert-C6vEcK-g.js} +1 -1
  163. package/bizar-dash/dist/assets/{shield-alert-CWV2F5ab.js.map → shield-alert-C6vEcK-g.js.map} +1 -1
  164. package/bizar-dash/dist/assets/{trash-2-CL4khSRv.js → trash-2-DZDjEnNh.js} +1 -1
  165. package/bizar-dash/dist/assets/{trash-2-CL4khSRv.js.map → trash-2-DZDjEnNh.js.map} +1 -1
  166. package/bizar-dash/dist/assets/{trending-up-CSJJhWTS.js → trending-up-DMj-AJVf.js} +1 -1
  167. package/bizar-dash/dist/assets/{trending-up-CSJJhWTS.js.map → trending-up-DMj-AJVf.js.map} +1 -1
  168. package/bizar-dash/dist/assets/{triangle-alert-BPLb7uLt.js → triangle-alert-_2xe_tl4.js} +1 -1
  169. package/bizar-dash/dist/assets/{triangle-alert-BPLb7uLt.js.map → triangle-alert-_2xe_tl4.js.map} +1 -1
  170. package/bizar-dash/dist/assets/{upload-Cww6MvFq.js → upload-DdDljAeV.js} +1 -1
  171. package/bizar-dash/dist/assets/{upload-Cww6MvFq.js.map → upload-DdDljAeV.js.map} +1 -1
  172. package/bizar-dash/dist/assets/{zap-DmhVUzRA.js → zap-mHsgh0FP.js} +1 -1
  173. package/bizar-dash/dist/assets/{zap-DmhVUzRA.js.map → zap-mHsgh0FP.js.map} +1 -1
  174. package/bizar-dash/dist/index.html +1 -1
  175. package/bizar-dash/skills/headroom/SKILL.md +94 -0
  176. package/bizar-dash/src/server/api.mjs +11 -0
  177. package/bizar-dash/src/server/artifacts-store.mjs +120 -14
  178. package/bizar-dash/src/server/claude-artifacts.mjs +281 -0
  179. package/bizar-dash/src/server/headroom.mjs +649 -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/headroom.mjs +126 -0
  184. package/bizar-dash/src/server/routes/model-router.mjs +55 -0
  185. package/bizar-dash/src/server/routes/model-router.test.mjs +28 -0
  186. package/bizar-dash/src/server/routes/sessions.mjs +80 -0
  187. package/bizar-dash/src/server/sprint.test.mjs +163 -0
  188. package/bizar-dash/src/web/v8/views/Artifacts/ArtifactsView.tsx +232 -21
  189. package/bizar-dash/src/web/v8/views/Artifacts/ClaudeArtifactView.tsx +179 -0
  190. package/bizar-dash/tests/headroom-install.test.mjs +173 -0
  191. package/bizar-dash/tests/headroom-settings.test.mjs +126 -0
  192. package/bizar-dash/tests/headroom-status.test.mjs +117 -0
  193. package/cli/commands/headroom.mjs +204 -0
  194. package/package.json +1 -1
  195. package/packages/sdk/dist/agent/cron.d.ts +44 -0
  196. package/packages/sdk/dist/agent/cron.js +79 -0
  197. package/packages/sdk/dist/agent/heartbeat.d.ts +43 -0
  198. package/packages/sdk/dist/agent/heartbeat.js +116 -0
  199. package/packages/sdk/dist/index.d.ts +3 -0
  200. package/packages/sdk/dist/index.js +5 -0
  201. package/packages/sdk/dist/learning/decisions.d.ts +46 -0
  202. package/packages/sdk/dist/learning/decisions.js +132 -0
  203. package/packages/sdk/dist/learning/index.d.ts +8 -0
  204. package/packages/sdk/dist/learning/index.js +8 -0
  205. package/packages/sdk/dist/learning/instincts.d.ts +38 -0
  206. package/packages/sdk/dist/learning/instincts.js +139 -0
  207. package/packages/sdk/dist/mcp/server.js +119 -1
  208. package/packages/sdk/dist/router/agent-model-registry.d.ts +89 -0
  209. package/packages/sdk/dist/router/agent-model-registry.js +144 -0
  210. package/packages/sdk/dist/router/index.d.ts +1 -0
  211. package/packages/sdk/dist/router/index.js +1 -0
  212. package/packages/sdk/package.json +3 -2
  213. package/scripts/audit.mjs +388 -0
  214. package/scripts/audit.test.mjs +149 -0
  215. package/scripts/eval-gate.mjs +134 -0
  216. package/scripts/eval-gate.test.mjs +138 -0
  217. package/scripts/feature-state-machine.mjs +178 -0
  218. package/scripts/feature-state-machine.test.mjs +135 -0
  219. package/scripts/spec-dedup.test.mjs +124 -0
  220. package/scripts/sprint.mjs +213 -0
  221. package/scripts/worktree-setup.sh +79 -0
  222. package/bizar-dash/dist/assets/ArtifactsView-CDIhPBAx.js +0 -6
  223. package/bizar-dash/dist/assets/ArtifactsView-CDIhPBAx.js.map +0 -1
@@ -0,0 +1,163 @@
1
+ /**
2
+ * bizar-dash/src/server/sprint.test.mjs
3
+ *
4
+ * Pillar B — Tests for scripts/sprint.mjs
5
+ * 3 groups: parser test, fill test, missing-goal tolerance.
6
+ */
7
+ import { test } from 'node:test';
8
+ import assert from 'node:assert/strict';
9
+ import { execSync } from 'node:child_process';
10
+ import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
11
+ import { join } from 'node:path';
12
+ import { tmpdir } from 'node:os';
13
+
14
+ const SCRIPTS_SPRINT = join(process.cwd(), 'scripts', 'sprint.mjs');
15
+ const PROGRESS_PARSER = join(process.cwd(), 'bizar-dash', 'src', 'server', 'progress-parser.mjs');
16
+ const SPRINT_TEMPLATE = join(process.cwd(), 'templates', 'sprint-contract.md');
17
+
18
+ function runSprintScript(goalId, cwd) {
19
+ try {
20
+ const stdout = execSync(`node "${SCRIPTS_SPRINT}" "${goalId}" "${cwd}" 2>&1`, {
21
+ encoding: 'utf8',
22
+ });
23
+ return { ok: true, stdout, stderr: '', exitCode: 0 };
24
+ } catch (err) {
25
+ return {
26
+ ok: false,
27
+ stdout: err.stdout ?? '',
28
+ stderr: err.stderr ?? '',
29
+ exitCode: err.status ?? 1,
30
+ };
31
+ }
32
+ }
33
+
34
+ function makeTempProject() {
35
+ const tmp = join(tmpdir(), `bizar-sprint-test-${process.pid}-${Date.now()}`);
36
+ mkdirSync(join(tmp, '.bizar', 'sprints'), { recursive: true });
37
+ mkdirSync(join(tmp, 'bizar-dash', 'src', 'server'), { recursive: true });
38
+ mkdirSync(join(tmp, 'templates'), { recursive: true });
39
+ // Symlink progress-parser.mjs
40
+ try {
41
+ const realParser = PROGRESS_PARSER;
42
+ if (existsSync(realParser)) {
43
+ const content = readFileSync(realParser, 'utf8');
44
+ writeFileSync(join(tmp, 'bizar-dash', 'src', 'server', 'progress-parser.mjs'), content, 'utf8');
45
+ }
46
+ } catch {
47
+ // ignore — test will skip
48
+ }
49
+ // Copy template
50
+ try {
51
+ const realTemplate = SPRINT_TEMPLATE;
52
+ if (existsSync(realTemplate)) {
53
+ const content = readFileSync(realTemplate, 'utf8');
54
+ writeFileSync(join(tmp, 'templates', 'sprint-contract.md'), content, 'utf8');
55
+ }
56
+ } catch {
57
+ // ignore
58
+ }
59
+ return tmp;
60
+ }
61
+
62
+ // ── Parser test ───────────────────────────────────────────────────────────────
63
+
64
+ test('progress-parser correctly extracts id, title, status, keyResults from PROGRESS.md', async () => {
65
+ if (!existsSync(PROGRESS_PARSER)) {
66
+ console.warn('progress-parser.mjs not found — skipping parser test');
67
+ return;
68
+ }
69
+ const { parseProgress } = await import(PROGRESS_PARSER);
70
+
71
+ const sample = `
72
+ # Current State
73
+ ## F-099 — My Feature Title
74
+ Owner: thor · Due: 2026-07-31
75
+ Goal is **active**.
76
+
77
+ Key results:
78
+ - [ ] KR1: First result
79
+ - [x] KR2: Second result
80
+
81
+ ## Next Steps
82
+ ## F-100 — Another Goal
83
+ Goal is **done**.
84
+ `;
85
+
86
+ const result = parseProgress(sample);
87
+ const goal = result.goals.find((g) => g.id === 'F-099');
88
+ assert.ok(goal, 'F-099 should be found');
89
+ assert.equal(goal.title, 'My Feature Title');
90
+ assert.equal(goal.status, 'active');
91
+ assert.equal(goal.keyResults.length, 2);
92
+ assert.equal(goal.keyResults[0].title, 'KR1: First result');
93
+ assert.equal(goal.keyResults[0].done, false);
94
+ assert.equal(goal.keyResults[1].title, 'KR2: Second result');
95
+ assert.equal(goal.keyResults[1].done, true);
96
+ });
97
+
98
+ // ── Fill test ────────────────────────────────────────────────────────────────
99
+
100
+ test('sprint.mjs writes a file with pre-filled Scope (in) from goal key results', () => {
101
+ const tmp = makeTempProject();
102
+
103
+ // Write a progress file with a goal that has KRs
104
+ const progress = `
105
+ ## F-099 — My Feature
106
+ Owner: thor · Due: 2026-07-31
107
+ Goal is **active**.
108
+
109
+ Key results:
110
+ - [ ] Pending KR
111
+ - [x] Done KR
112
+ `;
113
+ writeFileSync(join(tmp, '.bizar', 'PROGRESS.md'), progress, 'utf8');
114
+
115
+ try {
116
+ const r = runSprintScript('F-099', tmp);
117
+ assert.equal(r.exitCode, 0, `sprint.mjs should exit 0: ${r.stdout}\n${r.stderr}`);
118
+ const destPath = join(tmp, '.bizar', 'sprints', 'F-099-' + new Date().toISOString().slice(0, 10) + '.md');
119
+ assert.ok(
120
+ existsSync(destPath),
121
+ `Sprint file should exist at ${destPath}. stdout: ${r.stdout}`
122
+ );
123
+ const content = readFileSync(destPath, 'utf8');
124
+ assert.ok(content.includes('F-099'), 'Should include feature ID');
125
+ assert.ok(content.includes('My Feature'), 'Should include title');
126
+ assert.ok(content.includes('Pending KR'), 'Should include pending KR');
127
+ assert.ok(content.includes('Done KR'), 'Should include done KR');
128
+ assert.ok(content.includes('[x]'), 'Should have checked items');
129
+ } finally {
130
+ rmSync(tmp, { recursive: true, force: true });
131
+ }
132
+ });
133
+
134
+ // ── Missing-goal tolerance ───────────────────────────────────────────────────
135
+
136
+ test('sprint.mjs exits non-zero and prints a clear error when goal not found', () => {
137
+ const tmp = makeTempProject();
138
+
139
+ // Write a progress file with a different goal
140
+ writeFileSync(join(tmp, '.bizar', 'PROGRESS.md'), '## F-001 — Something\nGoal is **done**.\n', 'utf8');
141
+
142
+ try {
143
+ const r = runSprintScript('F-999', tmp);
144
+ assert.notEqual(r.exitCode, 0, 'Should exit non-zero for missing goal');
145
+ assert.ok(
146
+ r.stdout.includes('F-999') || r.stderr.includes('F-999') || r.stdout.includes('not found'),
147
+ `Error should mention the goal id: ${r.stdout} ${r.stderr}`
148
+ );
149
+ } finally {
150
+ rmSync(tmp, { recursive: true, force: true });
151
+ }
152
+ });
153
+
154
+ test('sprint.mjs exits non-zero when PROGRESS.md is missing', () => {
155
+ const tmp = makeTempProject();
156
+ // Do NOT write PROGRESS.md
157
+ try {
158
+ const r = runSprintScript('F-001', tmp);
159
+ assert.notEqual(r.exitCode, 0, 'Should exit non-zero when PROGRESS.md missing');
160
+ } finally {
161
+ rmSync(tmp, { recursive: true, force: true });
162
+ }
163
+ });
@@ -1,10 +1,19 @@
1
1
  /**
2
- * v8/views/Artifacts/ArtifactsView.tsx — Sprint S43, v9.3.0.
2
+ * v8/views/Artifacts/ArtifactsView.tsx — Sprint S43, v9.3.0 → v10.1.0
3
+ * (Claude Artifacts swap).
3
4
  *
4
5
  * Artifacts list (GET /api/artifacts) with per-row open-to-detail
5
6
  * (right-hand Sheet using GET /api/artifacts/:slug + /render) and
6
7
  * inline-confirm Delete (DELETE /api/artifacts/:slug). Add Sheet
7
- * posts a new artifact (POST /api/artifacts {slug, ...}).
8
+ * posts a new artifact (POST /api/artifacts {slug, kind, source, ...}).
9
+ *
10
+ * v10.1.0 — Detail panel dispatches by `kind`:
11
+ * - claude-html / claude-svg / claude-react → sandboxed iframe
12
+ * via <ClaudeArtifactView>
13
+ * - mdx → legacy block-renderer fallback
14
+ *
15
+ * The AddForm gains a `kind` dropdown + a textarea bound to `source`;
16
+ * the textarea defaults to the kind-specific starting template.
8
17
  */
9
18
 
10
19
  import { useCallback, useEffect, useMemo, useState } from 'react';
@@ -21,15 +30,17 @@ import { Skeleton } from '../../ui/feedback/Skeleton.js';
21
30
  import { EmptyState } from '../../ui/feedback/EmptyState.js';
22
31
  import { useFetch } from '../../data/useFetch.js';
23
32
  import { fetchJson, FetchError } from '../../data/fetcher.js';
33
+ import { ClaudeArtifactView, type ClaudeRenderPayload } from './ClaudeArtifactView.js';
24
34
 
25
35
  interface Artifact {
26
36
  slug: string;
27
37
  title?: string;
28
- kind?: string;
38
+ kind?: 'mdx' | 'claude-html' | 'claude-svg' | 'claude-react';
29
39
  description?: string;
30
40
  createdAt?: string | number;
31
41
  updatedAt?: string | number;
32
42
  planMdx?: string;
43
+ source?: string;
33
44
  frontmatter?: Record<string, unknown>;
34
45
  }
35
46
 
@@ -130,7 +141,7 @@ export function ArtifactsView(): JSX.Element {
130
141
  </Card>
131
142
 
132
143
  <Sheet open={adding} onOpenChange={setAdding}>
133
- <SheetContent side="right" title="Add artifact" description="Slug + title + initial MDX.">
144
+ <SheetContent side="right" title="Add artifact" description="Slug + kind + initial source.">
134
145
  <AddForm
135
146
  onSubmit={async (body) => {
136
147
  await fetchJson('/api/artifacts', { method: 'POST', body });
@@ -144,7 +155,7 @@ export function ArtifactsView(): JSX.Element {
144
155
 
145
156
  <Sheet open={activeSlug !== null} onOpenChange={(open) => { if (!open) setActiveSlug(null); }}>
146
157
  <SheetContent side="right" title={activeSlug ?? ''} description="Artifact detail">
147
- {activeSlug !== null && <ArtifactDetail slug={activeSlug} />}
158
+ {activeSlug !== null && <ArtifactDetail slug={activeSlug} refresh={refresh} />}
148
159
  </SheetContent>
149
160
  </Sheet>
150
161
  </Stack>
@@ -155,16 +166,24 @@ function AddForm({
155
166
  onSubmit,
156
167
  onCancel,
157
168
  }: {
158
- onSubmit: (body: { slug: string; title?: string; description?: string; planMdx?: string; frontmatter?: Record<string, unknown> }) => Promise<void>;
169
+ onSubmit: (body: { slug: string; title?: string; description?: string; kind?: string; source?: string; planMdx?: string }) => Promise<void>;
159
170
  onCancel: () => void;
160
171
  }): JSX.Element {
161
172
  const [slug, setSlug] = useState<string>('');
162
173
  const [title, setTitle] = useState<string>('');
163
174
  const [description, setDescription] = useState<string>('');
164
- const [planMdx, setPlanMdx] = useState<string>('');
175
+ const [kind, setKind] = useState<'mdx' | 'claude-html' | 'claude-svg' | 'claude-react'>('claude-html');
176
+ const [source, setSource] = useState<string>(KIND_TEMPLATES['claude-html']);
165
177
  const [busy, setBusy] = useState<boolean>(false);
166
178
  const [error, setError] = useState<string | null>(null);
167
179
 
180
+ // When the user changes kind, swap the textarea content to a starter
181
+ // template for that kind. They can still edit further.
182
+ const onKindChange = (next: 'mdx' | 'claude-html' | 'claude-svg' | 'claude-react'): void => {
183
+ setKind(next);
184
+ setSource(KIND_TEMPLATES[next]);
185
+ };
186
+
168
187
  return (
169
188
  <Stack gap={3} style={{ padding: 'var(--space-4)' }}>
170
189
  <label style={{ display: 'flex', flexDirection: 'column', gap: 'var(--space-1)' }}>
@@ -180,8 +199,37 @@ function AddForm({
180
199
  <Input value={description} onChange={(e) => setDescription((e.target as HTMLInputElement).value)} data-testid="artifact-form-description" />
181
200
  </label>
182
201
  <label style={{ display: 'flex', flexDirection: 'column', gap: 'var(--space-1)' }}>
183
- <span style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>Plan MDX</span>
184
- <Textarea value={planMdx} rows={6} onChange={(e) => setPlanMdx((e.target as HTMLTextAreaElement).value)} data-testid="artifact-form-mdx" />
202
+ <span style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>Kind</span>
203
+ <select
204
+ value={kind}
205
+ onChange={(e) => onKindChange(e.target.value as typeof kind)}
206
+ data-testid="artifact-form-kind"
207
+ style={{
208
+ fontFamily: 'inherit',
209
+ fontSize: 'var(--fs-12)',
210
+ padding: 'var(--space-2)',
211
+ background: 'var(--surface-0)',
212
+ color: 'var(--fg)',
213
+ border: '1px solid var(--border)',
214
+ borderRadius: 'var(--radius-sm)',
215
+ }}
216
+ >
217
+ <option value="claude-html">Claude HTML</option>
218
+ <option value="claude-svg">Claude SVG</option>
219
+ <option value="claude-react">Claude React (JSX)</option>
220
+ <option value="mdx">Legacy MDX (glyphs)</option>
221
+ </select>
222
+ </label>
223
+ <label style={{ display: 'flex', flexDirection: 'column', gap: 'var(--space-1)' }}>
224
+ <span style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>
225
+ {kind === 'mdx' ? 'Plan MDX' : 'Source'}
226
+ </span>
227
+ <Textarea
228
+ value={source}
229
+ rows={kind === 'claude-react' ? 10 : 6}
230
+ onChange={(e) => setSource((e.target as HTMLTextAreaElement).value)}
231
+ data-testid={kind === 'mdx' ? 'artifact-form-mdx' : 'artifact-form-source'}
232
+ />
185
233
  </label>
186
234
  {error !== null && <span role="alert" style={{ color: 'var(--danger)', fontSize: 'var(--fs-12)' }}>{error}</span>}
187
235
  <Inline justify="end" gap={2}>
@@ -194,7 +242,16 @@ function AddForm({
194
242
  setBusy(true);
195
243
  setError(null);
196
244
  try {
197
- await onSubmit({ slug: slug.trim(), title: title.trim() || undefined, description: description.trim() || undefined, planMdx: planMdx || undefined });
245
+ const body: { slug: string; title?: string; description?: string; kind: typeof kind; source?: string; planMdx?: string } = {
246
+ slug: slug.trim(),
247
+ title: title.trim() || undefined,
248
+ description: description.trim() || undefined,
249
+ kind,
250
+ };
251
+ if (source) {
252
+ if (kind === 'mdx') body.planMdx = source; else body.source = source;
253
+ }
254
+ await onSubmit(body);
198
255
  } catch (err) {
199
256
  setError(err instanceof FetchError ? err.message : (err as Error).message);
200
257
  setBusy(false);
@@ -208,34 +265,188 @@ function AddForm({
208
265
  );
209
266
  }
210
267
 
211
- function ArtifactDetail({ slug }: { slug: string }): JSX.Element {
268
+ const KIND_TEMPLATES: Record<'mdx' | 'claude-html' | 'claude-svg' | 'claude-react', string> = {
269
+ mdx: '# Hello\n\nAdd some MDX here.',
270
+ 'claude-html': '<!doctype html>\n<h1 style="font-family:system-ui">Hello artifact</h1>\n<p>Edit me — click <em>Open</em> to preview.</p>',
271
+ 'claude-svg': '<svg viewBox="0 0 100 100" width="200" height="200">\n <circle cx="50" cy="50" r="40" fill="#0b66c3"/>\n <text x="50" y="55" text-anchor="middle" fill="white" font-size="14">SVG</text>\n</svg>',
272
+ 'claude-react': 'export default function App() {\n const [n, setN] = React.useState(0);\n return (\n <div style={{ fontFamily: "system-ui", padding: 16 }}>\n <h1>Hello</h1>\n <button onClick={() => setN(n + 1)}>clicked {n}</button>\n </div>\n );\n}',
273
+ };
274
+
275
+ function ArtifactDetail({ slug, refresh }: { slug: string; refresh: () => void }): JSX.Element {
212
276
  const payload = useFetch<Artifact>(`/api/artifacts/${slug}`);
213
- const renderPayload = useFetch<{ blocks?: unknown[]; frontmatter?: Record<string, unknown> }>(`/api/artifacts/${slug}/render`);
277
+ const renderPayload = useFetch<ClaudeRenderPayload>(`/api/artifacts/${slug}/render`);
278
+ const kind = payload.data?.kind || 'mdx';
279
+ const isClaude = kind === 'claude-html' || kind === 'claude-svg' || kind === 'claude-react';
280
+
214
281
  return (
215
282
  <Stack gap={2} style={{ padding: 'var(--space-4)' }}>
216
283
  {payload.loading && !payload.data ? (
217
284
  <Skeleton style={{ height: 80 }} />
218
285
  ) : payload.data ? (
219
286
  <Stack gap={2}>
220
- <strong>{payload.data.title || payload.data.slug}</strong>
287
+ <Inline align="center" gap={2}>
288
+ <strong>{payload.data.title || payload.data.slug}</strong>
289
+ <code style={{ fontSize: 'var(--fs-11)', color: 'var(--fg-subtle)' }}>{payload.data.slug}</code>
290
+ <span style={{ fontSize: 'var(--fs-11)', color: 'var(--fg-muted)' }}>· {kind}</span>
291
+ </Inline>
221
292
  {payload.data.description && <span style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>{payload.data.description}</span>}
222
- {payload.data.frontmatter && (
223
- <div data-testid={`artifact-frontmatter-${slug}`} style={{ padding: 'var(--space-2)', background: 'var(--surface-1)', borderRadius: 'var(--radius-sm)' }}>
224
- <pre style={{ margin: 0, fontSize: 'var(--fs-11)', fontFamily: 'var(--font-mono)' }}>{JSON.stringify(payload.data.frontmatter, null, 2)}</pre>
225
- </div>
226
- )}
227
- {payload.data.planMdx && (
228
- <pre data-testid={`artifact-mdx-${slug}`} style={{ padding: 'var(--space-2)', background: 'var(--surface-1)', borderRadius: 'var(--radius-sm)', fontSize: 'var(--fs-11)', maxHeight: 240, overflow: 'auto', fontFamily: 'var(--font-mono)' }}>{payload.data.planMdx}</pre>
293
+
294
+ {/* Claude-* kinds render in a sandboxed iframe via the new
295
+ <ClaudeArtifactView>. The server compiles the source on
296
+ demand and returns iframe-ready HTML (srcdoc). */}
297
+ {isClaude && (
298
+ renderPayload.data ? (
299
+ <ClaudeArtifactView payload={renderPayload.data} slug={slug} />
300
+ ) : (
301
+ <Skeleton style={{ height: 200 }} />
302
+ )
229
303
  )}
230
- {renderPayload.data && (
304
+
305
+ {/* Legacy MDX path keeps the original block-count summary. */}
306
+ {!isClaude && renderPayload.data && (
231
307
  <span data-testid={`artifact-render-${slug}`} style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>
232
308
  Render: {Array.isArray(renderPayload.data.blocks) ? `${renderPayload.data.blocks.length} blocks` : 'no blocks'}
233
309
  </span>
234
310
  )}
311
+
312
+ {/* Inline editor — kind switch + textarea + save. */}
313
+ <Editor payload={payload.data} slug={slug} onSaved={() => { void payload.refetch(); void renderPayload.refetch(); refresh(); }} />
235
314
  </Stack>
236
315
  ) : (
237
316
  <span role="alert" style={{ color: 'var(--danger)' }}>Not found</span>
238
317
  )}
239
318
  </Stack>
240
319
  );
320
+ }
321
+
322
+ /**
323
+ * Inline editor: lets the user change the kind, edit the body, and
324
+ * save via PUT /api/artifacts/:slug. After save we re-fetch both the
325
+ * artifact + the compiled render so the iframe updates with the new
326
+ * source on the next paint.
327
+ */
328
+ function Editor({
329
+ payload,
330
+ slug,
331
+ onSaved,
332
+ }: {
333
+ payload: Artifact;
334
+ slug: string;
335
+ onSaved: () => void;
336
+ }): JSX.Element {
337
+ const initial = payload.source ?? payload.planMdx ?? '';
338
+ const [editKind, setEditKind] = useState<typeof payload.kind>(payload.kind || 'mdx');
339
+ const [editSource, setEditSource] = useState<string>(initial);
340
+ const [busy, setBusy] = useState<boolean>(false);
341
+ const [error, setError] = useState<string | null>(null);
342
+ const [open, setOpen] = useState<boolean>(false);
343
+
344
+ // Sync the textarea when the underlying artifact changes (e.g. when
345
+ // the user opens a different slug in the same Sheet).
346
+ useEffect(() => {
347
+ setEditKind(payload.kind || 'mdx');
348
+ setEditSource(payload.source ?? payload.planMdx ?? '');
349
+ }, [payload.slug, payload.source, payload.planMdx, payload.kind]);
350
+
351
+ const dirty =
352
+ editKind !== (payload.kind || 'mdx') || editSource !== (payload.source ?? payload.planMdx ?? '');
353
+
354
+ const save = async (): Promise<void> => {
355
+ setBusy(true);
356
+ setError(null);
357
+ try {
358
+ await fetchJson(`/api/artifacts/${slug}`, {
359
+ method: 'PUT',
360
+ body: {
361
+ kind: editKind,
362
+ source: editKind === 'mdx' ? undefined : editSource,
363
+ planMdx: editKind === 'mdx' ? editSource : undefined,
364
+ },
365
+ });
366
+ onSaved();
367
+ } catch (err) {
368
+ setError(err instanceof FetchError ? err.message : (err as Error).message);
369
+ } finally {
370
+ setBusy(false);
371
+ }
372
+ };
373
+
374
+ return (
375
+ <Stack gap={1} data-testid={`artifact-editor-${slug}`}>
376
+ <Inline align="center" justify="between" gap={2}>
377
+ <Button variant="ghost" onClick={() => setOpen((v) => !v)} data-testid={`artifact-edit-toggle-${slug}`}>
378
+ {open ? 'Close editor' : 'Edit'}
379
+ </Button>
380
+ {dirty && (
381
+ <span style={{ fontSize: 'var(--fs-11)', color: 'var(--callout-warning-fg, #b58900)' }}>
382
+ Unsaved changes
383
+ </span>
384
+ )}
385
+ </Inline>
386
+ {open && (
387
+ <Stack gap={2}>
388
+ <label style={{ display: 'flex', flexDirection: 'column', gap: 'var(--space-1)' }}>
389
+ <span style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>Kind</span>
390
+ <select
391
+ value={editKind}
392
+ onChange={(e) => setEditKind(e.target.value as typeof editKind)}
393
+ data-testid={`artifact-edit-kind-${slug}`}
394
+ style={{
395
+ fontFamily: 'inherit',
396
+ fontSize: 'var(--fs-12)',
397
+ padding: 'var(--space-2)',
398
+ background: 'var(--surface-0)',
399
+ color: 'var(--fg)',
400
+ border: '1px solid var(--border)',
401
+ borderRadius: 'var(--radius-sm)',
402
+ }}
403
+ >
404
+ <option value="claude-html">Claude HTML</option>
405
+ <option value="claude-svg">Claude SVG</option>
406
+ <option value="claude-react">Claude React (JSX)</option>
407
+ <option value="mdx">Legacy MDX</option>
408
+ </select>
409
+ </label>
410
+ <label style={{ display: 'flex', flexDirection: 'column', gap: 'var(--space-1)' }}>
411
+ <span style={{ fontSize: 'var(--fs-12)', color: 'var(--fg-muted)' }}>
412
+ {editKind === 'mdx' ? 'Plan MDX' : 'Source'}
413
+ </span>
414
+ <Textarea
415
+ value={editSource}
416
+ rows={editKind === 'claude-react' ? 12 : 8}
417
+ onChange={(e) => setEditSource((e.target as HTMLTextAreaElement).value)}
418
+ data-testid={`artifact-edit-source-${slug}`}
419
+ />
420
+ </label>
421
+ {error !== null && (
422
+ <span role="alert" data-testid={`artifact-edit-error-${slug}`} style={{ color: 'var(--danger)', fontSize: 'var(--fs-12)' }}>
423
+ {error}
424
+ </span>
425
+ )}
426
+ <Inline gap={1}>
427
+ <Button
428
+ variant="primary"
429
+ disabled={busy || !dirty}
430
+ onClick={() => void save()}
431
+ data-testid={`artifact-edit-save-${slug}`}
432
+ >
433
+ {busy ? 'Saving…' : 'Save'}
434
+ </Button>
435
+ <Button
436
+ variant="ghost"
437
+ disabled={busy || !dirty}
438
+ onClick={() => {
439
+ setEditKind(payload.kind || 'mdx');
440
+ setEditSource(payload.source ?? payload.planMdx ?? '');
441
+ setError(null);
442
+ }}
443
+ data-testid={`artifact-edit-revert-${slug}`}
444
+ >
445
+ Revert
446
+ </Button>
447
+ </Inline>
448
+ </Stack>
449
+ )}
450
+ </Stack>
451
+ );
241
452
  }