@polderlabs/bizar 10.4.4 → 10.5.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 (242) hide show
  1. package/bizar-dash/dist/assets/{ActivityFeed-RQeyFifx.js → ActivityFeed-Bw4Cai7r.js} +1 -1
  2. package/bizar-dash/dist/assets/{ActivityFeed-RQeyFifx.js.map → ActivityFeed-Bw4Cai7r.js.map} +1 -1
  3. package/bizar-dash/dist/assets/{ActivityView-CibyssPM.js → ActivityView-BC0QQ_j9.js} +1 -1
  4. package/bizar-dash/dist/assets/{ActivityView-CibyssPM.js.map → ActivityView-BC0QQ_j9.js.map} +1 -1
  5. package/bizar-dash/dist/assets/{AdminView-BjczABeB.js → AdminView-CLTNKFL4.js} +1 -1
  6. package/bizar-dash/dist/assets/{AdminView-BjczABeB.js.map → AdminView-CLTNKFL4.js.map} +1 -1
  7. package/bizar-dash/dist/assets/{AgentActivity-Bywt1twv.js → AgentActivity-DBWDByjk.js} +1 -1
  8. package/bizar-dash/dist/assets/{AgentActivity-Bywt1twv.js.map → AgentActivity-DBWDByjk.js.map} +1 -1
  9. package/bizar-dash/dist/assets/{AgentsView-BnOjjM74.js → AgentsView-DD6bCIbA.js} +1 -1
  10. package/bizar-dash/dist/assets/{AgentsView-BnOjjM74.js.map → AgentsView-DD6bCIbA.js.map} +1 -1
  11. package/bizar-dash/dist/assets/{Alert-BZGk39mB.js → Alert-pzFISNtS.js} +1 -1
  12. package/bizar-dash/dist/assets/{Alert-BZGk39mB.js.map → Alert-pzFISNtS.js.map} +1 -1
  13. package/bizar-dash/dist/assets/ArtifactsView-BVU5lfo7.js +21 -0
  14. package/bizar-dash/dist/assets/ArtifactsView-BVU5lfo7.js.map +1 -0
  15. package/bizar-dash/dist/assets/{AuthView-D4frSShw.js → AuthView-BZ-bPIOM.js} +2 -2
  16. package/bizar-dash/dist/assets/AuthView-BZ-bPIOM.js.map +1 -0
  17. package/bizar-dash/dist/assets/{Avatar-BYg0rkPA.js → Avatar-CRW81ewE.js} +1 -1
  18. package/bizar-dash/dist/assets/{Avatar-BYg0rkPA.js.map → Avatar-CRW81ewE.js.map} +1 -1
  19. package/bizar-dash/dist/assets/BackgroundJobsView-w8OZtXyI.js +1 -0
  20. package/bizar-dash/dist/assets/BackgroundJobsView-w8OZtXyI.js.map +1 -0
  21. package/bizar-dash/dist/assets/{BackupView-B875KQa4.js → BackupView-u_O3j0TG.js} +1 -1
  22. package/bizar-dash/dist/assets/{BackupView-B875KQa4.js.map → BackupView-u_O3j0TG.js.map} +1 -1
  23. package/bizar-dash/dist/assets/{Banner-C8HEcT5l.js → Banner-Du-3l05O.js} +1 -1
  24. package/bizar-dash/dist/assets/{Banner-C8HEcT5l.js.map → Banner-Du-3l05O.js.map} +1 -1
  25. package/bizar-dash/dist/assets/{Card-BtsmkhJa.js → Card-Clkvh43Q.js} +1 -1
  26. package/bizar-dash/dist/assets/{Card-BtsmkhJa.js.map → Card-Clkvh43Q.js.map} +1 -1
  27. package/bizar-dash/dist/assets/{ChatView-CkNS0SD8.js → ChatView-BTjb3mIh.js} +1 -1
  28. package/bizar-dash/dist/assets/{ChatView-CkNS0SD8.js.map → ChatView-BTjb3mIh.js.map} +1 -1
  29. package/bizar-dash/dist/assets/{Chip-XPOk0d_E.js → Chip-B7ovcm01.js} +1 -1
  30. package/bizar-dash/dist/assets/{Chip-XPOk0d_E.js.map → Chip-B7ovcm01.js.map} +1 -1
  31. package/bizar-dash/dist/assets/ClaudeSessionsView-BoZS5ldi.js +1 -0
  32. package/bizar-dash/dist/assets/ClaudeSessionsView-BoZS5ldi.js.map +1 -0
  33. package/bizar-dash/dist/assets/ClipboardView-Cb6XgYZI.js +1 -0
  34. package/bizar-dash/dist/assets/{ClipboardView-CPlTU5VG.js.map → ClipboardView-Cb6XgYZI.js.map} +1 -1
  35. package/bizar-dash/dist/assets/{ConfigView-BntUrW7s.js → ConfigView-DfTJk1uL.js} +1 -1
  36. package/bizar-dash/dist/assets/{ConfigView-BntUrW7s.js.map → ConfigView-DfTJk1uL.js.map} +1 -1
  37. package/bizar-dash/dist/assets/{DiagnosticsView-4x0Zu3yP.js → DiagnosticsView-D5Wy9xlJ.js} +1 -1
  38. package/bizar-dash/dist/assets/{DiagnosticsView-4x0Zu3yP.js.map → DiagnosticsView-D5Wy9xlJ.js.map} +1 -1
  39. package/bizar-dash/dist/assets/{DialogsView-Xd02dVAX.js → DialogsView-HVyfrXpq.js} +1 -1
  40. package/bizar-dash/dist/assets/{DialogsView-Xd02dVAX.js.map → DialogsView-HVyfrXpq.js.map} +1 -1
  41. package/bizar-dash/dist/assets/{DoctorView-DepBdQGR.js → DoctorView-Dm94WI2z.js} +2 -2
  42. package/bizar-dash/dist/assets/{DoctorView-DepBdQGR.js.map → DoctorView-Dm94WI2z.js.map} +1 -1
  43. package/bizar-dash/dist/assets/{EmptyState-DjKtY1Qi.js → EmptyState-ccT__JZG.js} +1 -1
  44. package/bizar-dash/dist/assets/{EmptyState-DjKtY1Qi.js.map → EmptyState-ccT__JZG.js.map} +1 -1
  45. package/bizar-dash/dist/assets/{EnvVarsView-S4Pbm128.js → EnvVarsView-BhcIuJ6V.js} +2 -2
  46. package/bizar-dash/dist/assets/{EnvVarsView-S4Pbm128.js.map → EnvVarsView-BhcIuJ6V.js.map} +1 -1
  47. package/bizar-dash/dist/assets/{ErrorState-CBJbEQ8B.js → ErrorState-BSqf65ka.js} +1 -1
  48. package/bizar-dash/dist/assets/{ErrorState-CBJbEQ8B.js.map → ErrorState-BSqf65ka.js.map} +1 -1
  49. package/bizar-dash/dist/assets/{EvalView-BeAyMCD1.js → EvalView-2cbWVBUA.js} +1 -1
  50. package/bizar-dash/dist/assets/{EvalView-BeAyMCD1.js.map → EvalView-2cbWVBUA.js.map} +1 -1
  51. package/bizar-dash/dist/assets/{GoalsView-BZr8In4c.js → GoalsView-C3QG5p7T.js} +1 -1
  52. package/bizar-dash/dist/assets/{GoalsView-BZr8In4c.js.map → GoalsView-C3QG5p7T.js.map} +1 -1
  53. package/bizar-dash/dist/assets/{Grid--WKvqu5h.js → Grid-Bojq8Sg7.js} +1 -1
  54. package/bizar-dash/dist/assets/{Grid--WKvqu5h.js.map → Grid-Bojq8Sg7.js.map} +1 -1
  55. package/bizar-dash/dist/assets/{HistoryView-djEbzqtk.js → HistoryView-Bum2TMMw.js} +1 -1
  56. package/bizar-dash/dist/assets/{HistoryView-djEbzqtk.js.map → HistoryView-Bum2TMMw.js.map} +1 -1
  57. package/bizar-dash/dist/assets/{Input-h_nSOtwm.js → Input-DV-vdaV8.js} +1 -1
  58. package/bizar-dash/dist/assets/{Input-h_nSOtwm.js.map → Input-DV-vdaV8.js.map} +1 -1
  59. package/bizar-dash/dist/assets/{LibrariesView-Vez8CvNq.js → LibrariesView-DH2E2uNb.js} +1 -1
  60. package/bizar-dash/dist/assets/{LibrariesView-Vez8CvNq.js.map → LibrariesView-DH2E2uNb.js.map} +1 -1
  61. package/bizar-dash/dist/assets/LightRAGView-BFCcj7Tl.js +6 -0
  62. package/bizar-dash/dist/assets/LightRAGView-BFCcj7Tl.js.map +1 -0
  63. package/bizar-dash/dist/assets/{ListHeader-CM8QoIWG.js → ListHeader-CCD_nIHb.js} +1 -1
  64. package/bizar-dash/dist/assets/{ListHeader-CM8QoIWG.js.map → ListHeader-CCD_nIHb.js.map} +1 -1
  65. package/bizar-dash/dist/assets/{MemoryView-DnL8E2vI.js → MemoryView-Cr-obIQY.js} +1 -1
  66. package/bizar-dash/dist/assets/{MemoryView-DnL8E2vI.js.map → MemoryView-Cr-obIQY.js.map} +1 -1
  67. package/bizar-dash/dist/assets/{MiscView-B2YQXhZ_.js → MiscView-CDUQpYuV.js} +1 -1
  68. package/bizar-dash/dist/assets/{MiscView-B2YQXhZ_.js.map → MiscView-CDUQpYuV.js.map} +1 -1
  69. package/bizar-dash/dist/assets/{ModsView-BVM3X5xc.js → ModsView-B6OR-a4B.js} +2 -2
  70. package/bizar-dash/dist/assets/{ModsView-BVM3X5xc.js.map → ModsView-B6OR-a4B.js.map} +1 -1
  71. package/bizar-dash/dist/assets/{NotificationsView-A-Xs8BL1.js → NotificationsView-CIqtY6D0.js} +1 -1
  72. package/bizar-dash/dist/assets/{NotificationsView-A-Xs8BL1.js.map → NotificationsView-CIqtY6D0.js.map} +1 -1
  73. package/bizar-dash/dist/assets/{ObsidianView-mI3qW9OP.js → ObsidianView-Nahah8QC.js} +1 -1
  74. package/bizar-dash/dist/assets/{ObsidianView-mI3qW9OP.js.map → ObsidianView-Nahah8QC.js.map} +1 -1
  75. package/bizar-dash/dist/assets/{OverviewView-By69Cr5H.js → OverviewView-B6L_wa4M.js} +1 -1
  76. package/bizar-dash/dist/assets/{OverviewView-By69Cr5H.js.map → OverviewView-B6L_wa4M.js.map} +1 -1
  77. package/bizar-dash/dist/assets/{ProgressBar-BnaBqv-W.js → ProgressBar-KC4VXsl_.js} +1 -1
  78. package/bizar-dash/dist/assets/{ProgressBar-BnaBqv-W.js.map → ProgressBar-KC4VXsl_.js.map} +1 -1
  79. package/bizar-dash/dist/assets/{ProjectsView-C81WTFka.js → ProjectsView-DgxWiqHb.js} +1 -1
  80. package/bizar-dash/dist/assets/{ProjectsView-C81WTFka.js.map → ProjectsView-DgxWiqHb.js.map} +1 -1
  81. package/bizar-dash/dist/assets/{ProvidersView-2cn-TALE.js → ProvidersView-BOqN9omv.js} +1 -1
  82. package/bizar-dash/dist/assets/{ProvidersView-2cn-TALE.js.map → ProvidersView-BOqN9omv.js.map} +1 -1
  83. package/bizar-dash/dist/assets/SchedulesView-yMaG3Dtd.js +1 -0
  84. package/bizar-dash/dist/assets/SchedulesView-yMaG3Dtd.js.map +1 -0
  85. package/bizar-dash/dist/assets/{Select-CiGWEN8I.js → Select-Bf_P0S6H.js} +1 -1
  86. package/bizar-dash/dist/assets/{Select-CiGWEN8I.js.map → Select-Bf_P0S6H.js.map} +1 -1
  87. package/bizar-dash/dist/assets/{SettingsRow-CflGJymA.js → SettingsRow-CJb-F94Y.js} +1 -1
  88. package/bizar-dash/dist/assets/{SettingsRow-CflGJymA.js.map → SettingsRow-CJb-F94Y.js.map} +1 -1
  89. package/bizar-dash/dist/assets/{SettingsView-2HSFJPPK.js → SettingsView-BvOGcgMS.js} +2 -2
  90. package/bizar-dash/dist/assets/SettingsView-BvOGcgMS.js.map +1 -0
  91. package/bizar-dash/dist/assets/{Sheet-B-CMP9-_.js → Sheet-BwMVGN-8.js} +1 -1
  92. package/bizar-dash/dist/assets/{Sheet-B-CMP9-_.js.map → Sheet-BwMVGN-8.js.map} +1 -1
  93. package/bizar-dash/dist/assets/{Slider-Z4TP_CXY.js → Slider-AjjzqI-5.js} +1 -1
  94. package/bizar-dash/dist/assets/{Slider-Z4TP_CXY.js.map → Slider-AjjzqI-5.js.map} +1 -1
  95. package/bizar-dash/dist/assets/{Sparkline-cvkv2HbU.js → Sparkline-Z4y0YUZS.js} +1 -1
  96. package/bizar-dash/dist/assets/{Sparkline-cvkv2HbU.js.map → Sparkline-Z4y0YUZS.js.map} +1 -1
  97. package/bizar-dash/dist/assets/{Switch-jcYo4lmp.js → Switch-B79a2t-G.js} +1 -1
  98. package/bizar-dash/dist/assets/{Switch-jcYo4lmp.js.map → Switch-B79a2t-G.js.map} +1 -1
  99. package/bizar-dash/dist/assets/{TasksView-CQaSFzWY.js → TasksView-G-s_pwwr.js} +1 -1
  100. package/bizar-dash/dist/assets/{TasksView-CQaSFzWY.js.map → TasksView-G-s_pwwr.js.map} +1 -1
  101. package/bizar-dash/dist/assets/{Textarea-xnAybFGd.js → Textarea-BfXGMXQ7.js} +1 -1
  102. package/bizar-dash/dist/assets/{Textarea-xnAybFGd.js.map → Textarea-BfXGMXQ7.js.map} +1 -1
  103. package/bizar-dash/dist/assets/{UpdateView-BUAEcRCX.js → UpdateView-BKx3u9X8.js} +1 -1
  104. package/bizar-dash/dist/assets/{UpdateView-BUAEcRCX.js.map → UpdateView-BKx3u9X8.js.map} +1 -1
  105. package/bizar-dash/dist/assets/{UsageView-DMFbBOfH.js → UsageView-M01G6bZQ.js} +1 -1
  106. package/bizar-dash/dist/assets/{UsageView-DMFbBOfH.js.map → UsageView-M01G6bZQ.js.map} +1 -1
  107. package/bizar-dash/dist/assets/{ViewHeader-C-t1U2cQ.js → ViewHeader-BsnaspKw.js} +1 -1
  108. package/bizar-dash/dist/assets/{ViewHeader-C-t1U2cQ.js.map → ViewHeader-BsnaspKw.js.map} +1 -1
  109. package/bizar-dash/dist/assets/VoiceView-rWE8vziD.js +1 -0
  110. package/bizar-dash/dist/assets/{VoiceView-aoPVT6LJ.js.map → VoiceView-rWE8vziD.js.map} +1 -1
  111. package/bizar-dash/dist/assets/{brain-DhAzcHUk.js → brain-D7k5s8vH.js} +1 -1
  112. package/bizar-dash/dist/assets/{brain-DhAzcHUk.js.map → brain-D7k5s8vH.js.map} +1 -1
  113. package/bizar-dash/dist/assets/{calendar-B9Wbemh7.js → calendar-CAZoDd-l.js} +1 -1
  114. package/bizar-dash/dist/assets/{calendar-B9Wbemh7.js.map → calendar-CAZoDd-l.js.map} +1 -1
  115. package/bizar-dash/dist/assets/{circle-6NJF_Xl6.js → circle-D99cZJBr.js} +1 -1
  116. package/bizar-dash/dist/assets/{circle-6NJF_Xl6.js.map → circle-D99cZJBr.js.map} +1 -1
  117. package/bizar-dash/dist/assets/{circle-alert-Dz8lGfCZ.js → circle-alert-QQTU4Quz.js} +1 -1
  118. package/bizar-dash/dist/assets/{circle-alert-Dz8lGfCZ.js.map → circle-alert-QQTU4Quz.js.map} +1 -1
  119. package/bizar-dash/dist/assets/{circle-check-DFB50ojt.js → circle-check-BMbe7Kkr.js} +1 -1
  120. package/bizar-dash/dist/assets/{circle-check-DFB50ojt.js.map → circle-check-BMbe7Kkr.js.map} +1 -1
  121. package/bizar-dash/dist/assets/{clock-ClVA6-hQ.js → clock-OtT5mvF3.js} +1 -1
  122. package/bizar-dash/dist/assets/{clock-ClVA6-hQ.js.map → clock-OtT5mvF3.js.map} +1 -1
  123. package/bizar-dash/dist/assets/{download-BvJddD8D.js → download-B-mPX5P_.js} +1 -1
  124. package/bizar-dash/dist/assets/{download-BvJddD8D.js.map → download-B-mPX5P_.js.map} +1 -1
  125. package/bizar-dash/dist/assets/{external-link-DvL89gaZ.js → external-link-DPDQM1YO.js} +1 -1
  126. package/bizar-dash/dist/assets/{external-link-DvL89gaZ.js.map → external-link-DPDQM1YO.js.map} +1 -1
  127. package/bizar-dash/dist/assets/{file-text-BOroDtZE.js → file-text-BsCrv5aP.js} +1 -1
  128. package/bizar-dash/dist/assets/{file-text-BOroDtZE.js.map → file-text-BsCrv5aP.js.map} +1 -1
  129. package/bizar-dash/dist/assets/{filter-DwPjMRQt.js → filter-Do63x17E.js} +1 -1
  130. package/bizar-dash/dist/assets/{filter-DwPjMRQt.js.map → filter-Do63x17E.js.map} +1 -1
  131. package/bizar-dash/dist/assets/{git-pull-request-TDb1inux.js → git-pull-request-CpRAmERC.js} +1 -1
  132. package/bizar-dash/dist/assets/{git-pull-request-TDb1inux.js.map → git-pull-request-CpRAmERC.js.map} +1 -1
  133. package/bizar-dash/dist/assets/main-BRmJZcHt.js +277 -0
  134. package/bizar-dash/dist/assets/main-BRmJZcHt.js.map +1 -0
  135. package/bizar-dash/dist/assets/main-D0TY0myE.css +1 -0
  136. package/bizar-dash/dist/assets/{network-BcCoCzIY.js → network-DJnHwHX3.js} +1 -1
  137. package/bizar-dash/dist/assets/{network-BcCoCzIY.js.map → network-DJnHwHX3.js.map} +1 -1
  138. package/bizar-dash/dist/assets/{pause-BllItT2_.js → pause-HitDUnk_.js} +1 -1
  139. package/bizar-dash/dist/assets/{pause-BllItT2_.js.map → pause-HitDUnk_.js.map} +1 -1
  140. package/bizar-dash/dist/assets/{pencil-DAwM-CC3.js → pencil-Dkks7eIC.js} +1 -1
  141. package/bizar-dash/dist/assets/{pencil-DAwM-CC3.js.map → pencil-Dkks7eIC.js.map} +1 -1
  142. package/bizar-dash/dist/assets/{play-mJh67AXo.js → play-blqh0msT.js} +1 -1
  143. package/bizar-dash/dist/assets/{play-mJh67AXo.js.map → play-blqh0msT.js.map} +1 -1
  144. package/bizar-dash/dist/assets/{plug-BjfntCMC.js → plug-DVvSSe40.js} +1 -1
  145. package/bizar-dash/dist/assets/{plug-BjfntCMC.js.map → plug-DVvSSe40.js.map} +1 -1
  146. package/bizar-dash/dist/assets/{plus-Cm6-fo14.js → plus-Cps-8lcG.js} +1 -1
  147. package/bizar-dash/dist/assets/{plus-Cm6-fo14.js.map → plus-Cps-8lcG.js.map} +1 -1
  148. package/bizar-dash/dist/assets/{power-CXN9y2KV.js → power-DEX4_Xoa.js} +1 -1
  149. package/bizar-dash/dist/assets/{power-CXN9y2KV.js.map → power-DEX4_Xoa.js.map} +1 -1
  150. package/bizar-dash/dist/assets/{power-off-DUZqwMf9.js → power-off-upZ4xjaG.js} +1 -1
  151. package/bizar-dash/dist/assets/{power-off-DUZqwMf9.js.map → power-off-upZ4xjaG.js.map} +1 -1
  152. package/bizar-dash/dist/assets/{refresh-ccw-DA8_IB9l.js → refresh-ccw-DN_zCB1h.js} +1 -1
  153. package/bizar-dash/dist/assets/{refresh-ccw-DA8_IB9l.js.map → refresh-ccw-DN_zCB1h.js.map} +1 -1
  154. package/bizar-dash/dist/assets/{refresh-cw-DwlP59en.js → refresh-cw-KGm5eQgv.js} +1 -1
  155. package/bizar-dash/dist/assets/{refresh-cw-DwlP59en.js.map → refresh-cw-KGm5eQgv.js.map} +1 -1
  156. package/bizar-dash/dist/assets/{rotate-ccw-DMTASfAn.js → rotate-ccw-D5fkDRgk.js} +1 -1
  157. package/bizar-dash/dist/assets/{rotate-ccw-DMTASfAn.js.map → rotate-ccw-D5fkDRgk.js.map} +1 -1
  158. package/bizar-dash/dist/assets/{rotate-cw-BDX5SE2s.js → rotate-cw-CClSVUaX.js} +1 -1
  159. package/bizar-dash/dist/assets/{rotate-cw-BDX5SE2s.js.map → rotate-cw-CClSVUaX.js.map} +1 -1
  160. package/bizar-dash/dist/assets/{save-Y0jPK5D6.js → save-BY4ViPku.js} +1 -1
  161. package/bizar-dash/dist/assets/{save-Y0jPK5D6.js.map → save-BY4ViPku.js.map} +1 -1
  162. package/bizar-dash/dist/assets/{send-C8wwPHhR.js → send-CaOL1yQD.js} +1 -1
  163. package/bizar-dash/dist/assets/{send-C8wwPHhR.js.map → send-CaOL1yQD.js.map} +1 -1
  164. package/bizar-dash/dist/assets/{shield-alert-DEvq9UG0.js → shield-alert-DA9K6uZO.js} +1 -1
  165. package/bizar-dash/dist/assets/{shield-alert-DEvq9UG0.js.map → shield-alert-DA9K6uZO.js.map} +1 -1
  166. package/bizar-dash/dist/assets/{trash-2-D6qePV_q.js → trash-2-B_Y6HrfN.js} +1 -1
  167. package/bizar-dash/dist/assets/{trash-2-D6qePV_q.js.map → trash-2-B_Y6HrfN.js.map} +1 -1
  168. package/bizar-dash/dist/assets/{trending-up-BZzo_1ic.js → trending-up-qKTUQKIT.js} +1 -1
  169. package/bizar-dash/dist/assets/{trending-up-BZzo_1ic.js.map → trending-up-qKTUQKIT.js.map} +1 -1
  170. package/bizar-dash/dist/assets/{triangle-alert-B2oHbmoh.js → triangle-alert-BeY8LAv6.js} +1 -1
  171. package/bizar-dash/dist/assets/{triangle-alert-B2oHbmoh.js.map → triangle-alert-BeY8LAv6.js.map} +1 -1
  172. package/bizar-dash/dist/assets/{upload-Dy59aZn6.js → upload-BZCtmqIh.js} +1 -1
  173. package/bizar-dash/dist/assets/{upload-Dy59aZn6.js.map → upload-BZCtmqIh.js.map} +1 -1
  174. package/bizar-dash/dist/assets/{zap-DENVhJnO.js → zap-Bz1Z8y1Q.js} +1 -1
  175. package/bizar-dash/dist/assets/{zap-DENVhJnO.js.map → zap-Bz1Z8y1Q.js.map} +1 -1
  176. package/bizar-dash/dist/index.html +2 -2
  177. package/bizar-dash/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
  178. package/bizar-dash/src/web/v8/shell/Sidebar.tsx +41 -31
  179. package/bizar-dash/src/web/v8/shell/Topbar.tsx +63 -23
  180. package/bizar-dash/src/web/v8/ui/feedback/NotificationsPopover.tsx +3 -0
  181. package/bizar-dash/src/web/v8/ui/feedback/useFocusTrap.ts +58 -0
  182. package/bizar-dash/src/web/v8/ui/navigation/CommandPalette.tsx +1 -0
  183. package/bizar-dash/src/web/v8/ui/styles/tokens.css +21 -0
  184. package/bizar-dash/src/web/v8/views/Artifacts/ClaudeArtifactView.tsx +1 -1
  185. package/bizar-dash/src/web/v8/views/Auth/AuthView.tsx +10 -6
  186. package/bizar-dash/src/web/v8/views/BackgroundJobs/BackgroundJobsView.tsx +38 -13
  187. package/bizar-dash/src/web/v8/views/ClaudeSessions/ClaudeSessionDetail.tsx +16 -5
  188. package/bizar-dash/src/web/v8/views/LightRAG/LightRAGView.tsx +23 -2
  189. package/bizar-dash/src/web/v8/views/Schedules/SchedulesView.tsx +48 -13
  190. package/bizar-dash/src/web/v8/views/Settings/SettingsView.tsx +3 -3
  191. package/bizar-dash/tests/auth-inputs-labels.test.mjs +45 -0
  192. package/bizar-dash/tests/background-jobs-action-labels.test.mjs +41 -0
  193. package/bizar-dash/tests/background-jobs-states.test.mjs +80 -0
  194. package/bizar-dash/tests/banner-tones.test.mjs +50 -0
  195. package/bizar-dash/tests/callout-tokens.test.mjs +30 -0
  196. package/bizar-dash/tests/claude-session-detail-states.test.mjs +67 -0
  197. package/bizar-dash/tests/components/BackgroundJobsSkeleton.test.tsx +38 -0
  198. package/bizar-dash/tests/density-tokens.test.mjs +46 -0
  199. package/bizar-dash/tests/doctor-route-shape.test.mjs +67 -0
  200. package/bizar-dash/tests/errorstate-retry.test.mjs +42 -0
  201. package/bizar-dash/tests/lightrag-skeleton.test.mjs +31 -0
  202. package/bizar-dash/tests/lightrag-states.test.mjs +60 -0
  203. package/bizar-dash/tests/modal-focus-trap.test.mjs +114 -0
  204. package/bizar-dash/tests/orphan-tests-audit.test.mjs +80 -0
  205. package/bizar-dash/tests/palette-keyboard-nav.test.mjs +123 -0
  206. package/bizar-dash/tests/schedules-skeleton.test.mjs +25 -0
  207. package/bizar-dash/tests/schedules-states.test.mjs +67 -0
  208. package/bizar-dash/tests/sidebar-collapse-animation.test.mjs +37 -0
  209. package/bizar-dash/tests/sidebar-section-styles.test.mjs +55 -0
  210. package/bizar-dash/tests/skeleton-height.test.mjs +47 -0
  211. package/bizar-dash/tests/space-tokens.test.mjs +36 -0
  212. package/bizar-dash/tests/stattile-loading.test.mjs +28 -0
  213. package/bizar-dash/tests/topbar-popover-styles.test.mjs +53 -0
  214. package/bizar-dash/tests/update-channels.test.mjs +67 -0
  215. package/package.json +1 -1
  216. package/packages/sdk/${HOME}/.bizar_home/memory/projects/sdk/sessions/2026-07-16-e16c2f59.md +14 -0
  217. package/packages/sdk/.bizar/learning/instincts.jsonl +5 -0
  218. package/packages/sdk/package.json +1 -1
  219. package/scripts/loop-log.txt +29 -0
  220. package/scripts/loop-tasks.md +79 -0
  221. package/scripts/overnight-loop.mjs +60 -0
  222. package/bizar-dash/dist/assets/ArtifactsView-CfYB1le1.js +0 -21
  223. package/bizar-dash/dist/assets/ArtifactsView-CfYB1le1.js.map +0 -1
  224. package/bizar-dash/dist/assets/AuthView-D4frSShw.js.map +0 -1
  225. package/bizar-dash/dist/assets/BackgroundJobsView-DEStvILz.js +0 -1
  226. package/bizar-dash/dist/assets/BackgroundJobsView-DEStvILz.js.map +0 -1
  227. package/bizar-dash/dist/assets/ClaudeSessionsView-BprGo67K.js +0 -1
  228. package/bizar-dash/dist/assets/ClaudeSessionsView-BprGo67K.js.map +0 -1
  229. package/bizar-dash/dist/assets/ClipboardView-CPlTU5VG.js +0 -1
  230. package/bizar-dash/dist/assets/LightRAGView-DvqzQoBp.js +0 -6
  231. package/bizar-dash/dist/assets/LightRAGView-DvqzQoBp.js.map +0 -1
  232. package/bizar-dash/dist/assets/SchedulesView-o9AtIsH9.js +0 -1
  233. package/bizar-dash/dist/assets/SchedulesView-o9AtIsH9.js.map +0 -1
  234. package/bizar-dash/dist/assets/SettingsView-2HSFJPPK.js.map +0 -1
  235. package/bizar-dash/dist/assets/VoiceView-aoPVT6LJ.js +0 -1
  236. package/bizar-dash/dist/assets/main-B7D_IMTh.css +0 -1
  237. package/bizar-dash/dist/assets/main-BURAlktW.js +0 -277
  238. package/bizar-dash/dist/assets/main-BURAlktW.js.map +0 -1
  239. package/bizar-dash/tests/chat-session-create.test.mjs +0 -391
  240. package/bizar-dash/tests/chat-session-stream.test.mjs +0 -308
  241. package/bizar-dash/tests/cline-runner.test.mjs +0 -172
  242. package/bizar-dash/tests/cline-sessions-detail.test.mjs +0 -434
@@ -1,172 +0,0 @@
1
- /**
2
- * tests/cline-runner.test.mjs
3
- *
4
- * Unit tests for the dashboard's cline-runner.mjs. The
5
- * companion plugin runner (plugins/bizar/src/cline-runner.ts) is
6
- * tested via bun in plugins/bizar/tests/.
7
- *
8
- * Run with: node --test tests/cline-runner.test.mjs
9
- */
10
- import { test } from 'node:test';
11
- import assert from 'node:assert/strict';
12
- import { mkdtempSync, writeFileSync, existsSync, readFileSync, statSync } from 'node:fs';
13
- import { join } from 'node:path';
14
- import { tmpdir } from 'node:os';
15
- import { spawnSync } from 'node:child_process';
16
-
17
- import { spawnAgent, getStatus, onExit, killAgent, list, _resetForTests } from '../src/server/cline-runner.mjs';
18
-
19
- const HAS_CLINE = (() => {
20
- try {
21
- const r = spawnSync('which', ['cline'], { encoding: 'utf8' });
22
- return r.status === 0 && r.stdout.trim().length > 0;
23
- } catch {
24
- return false;
25
- }
26
- })();
27
-
28
- test('_resetForTests clears the registry', () => {
29
- list(); // sanity check no throw
30
- _resetForTests();
31
- assert.equal(list().length, 0);
32
- });
33
-
34
- test('getStatus returns null for unknown processId', () => {
35
- _resetForTests();
36
- assert.equal(getStatus(99999), null);
37
- });
38
-
39
- test('killAgent on unknown processId is a no-op success', () => {
40
- _resetForTests();
41
- const res = killAgent(99999);
42
- assert.equal(res.ok, true);
43
- });
44
-
45
- test('spawnAgent with non-existent worktree still returns a processId', { skip: !HAS_CLINE }, async () => {
46
- _resetForTests();
47
- const dir = mkdtempSync(join(tmpdir(), 'oc-runner-'));
48
- const logPath = join(dir, 'test.log');
49
- // Worktree doesn't exist, but spawn should still succeed and
50
- // cline will exit early with an error. We just verify the API
51
- // contract: we get back a processId immediately, and the spawn
52
- // resolves once the sessionId appears or the process exits.
53
- const result = await Promise.race([
54
- spawnAgent({
55
- prompt: 'just say hi',
56
- agent: 'mimir',
57
- worktree: '/this/does/not/exist/anywhere',
58
- logPath,
59
- sessionIdTimeoutMs: 3000,
60
- }),
61
- new Promise((_, rej) => setTimeout(() => rej(new Error('spawnAgent timeout')), 5000)),
62
- ]);
63
- // Either ok:false (process exited before reporting session) or
64
- // ok:true (rare if cline somehow succeeded) is acceptable.
65
- assert.ok(typeof result.ok === 'boolean', 'expected ok to be boolean');
66
- // The log dir should exist (spawnAgent creates it).
67
- assert.ok(existsSync(dir), 'log dir should exist');
68
- // No process should still be tracked if the spawn failed.
69
- if (!result.ok) {
70
- assert.ok(!result.sessionId, 'no sessionId on failure');
71
- }
72
- });
73
-
74
- test('spawnAgent creates log dir if missing', { skip: !HAS_CLINE }, async () => {
75
- _resetForTests();
76
- const tmp = mkdtempSync(join(tmpdir(), 'oc-runner-logdir-'));
77
- const nested = join(tmp, 'a', 'b', 'c');
78
- const logPath = join(nested, 'test.log');
79
- // The dir nested/a/b/c does not exist yet. spawnAgent should
80
- // create it. The actual cline process will likely fail (no
81
- // worktree, etc.) but that's irrelevant to this test.
82
- await Promise.race([
83
- spawnAgent({
84
- prompt: 'hi',
85
- agent: 'mimir',
86
- worktree: tmp,
87
- logPath,
88
- sessionIdTimeoutMs: 1000,
89
- }),
90
- new Promise((resolve) => setTimeout(resolve, 5000)),
91
- ]).catch(() => undefined);
92
- assert.ok(existsSync(nested), `expected ${nested} to exist`);
93
- });
94
-
95
- test('spawnAgent captures stdout+stderr to logPath', { skip: !HAS_CLINE }, async () => {
96
- _resetForTests();
97
- const tmp = mkdtempSync(join(tmpdir(), 'oc-runner-cap-'));
98
- const logPath = join(tmp, 'capture.log');
99
- // Use /tmp as worktree — it exists. cline will run there.
100
- const res = await Promise.race([
101
- spawnAgent({
102
- prompt: 'just say hi',
103
- agent: 'mimir',
104
- worktree: tmp,
105
- logPath,
106
- sessionIdTimeoutMs: 5000,
107
- }),
108
- new Promise((_, rej) => setTimeout(() => rej(new Error('timeout')), 8000)),
109
- ]);
110
- // Resolved (either ok or with error). Wait briefly for the log
111
- // stream to flush.
112
- await new Promise((r) => setTimeout(r, 500));
113
- if (existsSync(logPath)) {
114
- const stat = statSync(logPath);
115
- assert.ok(stat.size >= 0, 'log file has size');
116
- // If we wrote anything, it should be either [stdout] or [stderr]
117
- // prefixed. (If the file is empty, the test passes trivially.)
118
- if (stat.size > 0) {
119
- const content = readFileSync(logPath, 'utf8');
120
- // Either content is empty (process didn't output anything)
121
- // or contains our prefix tags. We don't assert specific
122
- // content because the cline run is environment-dependent.
123
- assert.ok(
124
- content.includes('[stderr]') || content.includes('[stdout]') || content.length === 0,
125
- 'log file should be empty or contain [stderr]/[stdout] prefixes',
126
- );
127
- }
128
- }
129
- // If the process is still running, kill it to clean up.
130
- if (res.processId && getStatus(res.processId) && getStatus(res.processId).state === 'running') {
131
- killAgent(res.processId);
132
- }
133
- });
134
-
135
- test('onExit fires when process exits', { skip: !HAS_CLINE }, async () => {
136
- _resetForTests();
137
- const tmp = mkdtempSync(join(tmpdir(), 'oc-runner-exit-'));
138
- const logPath = join(tmp, 'exit.log');
139
- const res = await Promise.race([
140
- spawnAgent({
141
- prompt: 'hi',
142
- agent: 'mimir',
143
- worktree: tmp,
144
- logPath,
145
- sessionIdTimeoutMs: 3000,
146
- }),
147
- new Promise((_, rej) => setTimeout(() => rej(new Error('timeout')), 5000)),
148
- ]).catch(() => ({ ok: false, processId: undefined }));
149
-
150
- if (!res.processId) {
151
- // Process never started; test is moot.
152
- return;
153
- }
154
-
155
- // onExit should fire within a reasonable time.
156
- const status = await Promise.race([
157
- new Promise((resolve) => {
158
- onExit(res.processId, (s) => resolve(s));
159
- }),
160
- new Promise((_, rej) => setTimeout(() => rej(new Error('onExit timeout')), 10_000)),
161
- ]).catch(() => null);
162
-
163
- // status may be null if the test timed out; either way the test
164
- // is best-effort in this environment.
165
- if (status) {
166
- assert.ok(
167
- ['done', 'failed', 'killed'].includes(status.state),
168
- `state should be terminal, got ${status.state}`,
169
- );
170
- assert.ok(typeof status.endedAt === 'number', 'endedAt set');
171
- }
172
- });
@@ -1,434 +0,0 @@
1
- /**
2
- * tests/cline-sessions-detail.test.mjs — v4.2.4
3
- *
4
- * Tests the cline session-detail router (GET messages, POST send,
5
- * GET stream SSE proxy). Strategy: stand up a fake cline serve child
6
- * on a random port, point readServeInfo() at it by writing a tmp
7
- * serve.json to the first candidate path (~/.cache/bizar/serve.json).
8
- * For the "plugin offline" case, move our tmp serve.json aside so
9
- * readServeInfo() finds nothing.
10
- *
11
- * We restore the original serve.json (if any) in `after()`.
12
- */
13
-
14
- import { test, before, after, beforeEach } from 'node:test';
15
- import assert from 'node:assert/strict';
16
- import {
17
- mkdtempSync,
18
- writeFileSync,
19
- rmSync,
20
- existsSync,
21
- copyFileSync,
22
- unlinkSync,
23
- readFileSync,
24
- mkdirSync,
25
- } from 'node:fs';
26
- import { join } from 'node:path';
27
- import { tmpdir, homedir } from 'node:os';
28
- import { createServer } from 'node:http';
29
- import express from 'express';
30
-
31
- import { createClineSessionDetailRouter } from '../src/server/routes/cline-session-detail.mjs';
32
-
33
- // ── fake upstream (cline serve child) ──────────────────────────────────
34
-
35
- let upstreamServer, upstreamPort;
36
- const upstream = { promptHits: [], lastPromptBody: null, streamChunks: [] };
37
-
38
- function startUpstream() {
39
- return new Promise((resolve) => {
40
- upstreamServer = createServer((req, res) => {
41
- const url = new URL(req.url, 'http://127.0.0.1');
42
- if (url.pathname === '/event') {
43
- res.writeHead(200, { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', Connection: 'keep-alive' });
44
- for (const c of upstream.streamChunks) res.write(c);
45
- setTimeout(() => res.end(), 50);
46
- return;
47
- }
48
- const promptM = url.pathname.match(/^\/api\/session\/([^/]+)\/prompt$/);
49
- if (promptM && req.method === 'POST') {
50
- let body = '';
51
- req.on('data', (c) => { body += c; });
52
- req.on('end', () => {
53
- upstream.promptHits.push({ sessionId: promptM[1], body });
54
- try { upstream.lastPromptBody = JSON.parse(body); } catch { /* ignore */ }
55
- if (promptM[1] === 'sess-fail') {
56
- res.writeHead(404, { 'Content-Type': 'application/json' }); res.end('not found'); return;
57
- }
58
- res.writeHead(200, { 'Content-Type': 'application/json' }); res.end('{}');
59
- });
60
- return;
61
- }
62
- if (url.pathname === '/api/session' && req.method === 'GET') {
63
- res.writeHead(200, { 'Content-Type': 'application/json' });
64
- res.end(JSON.stringify({ data: [{ id: 'sess-1', title: 'Test', time: { created: 1, updated: 2, archived: null }, location: { directory: '/tmp/session-worktree' } }] }));
65
- return;
66
- }
67
- // v5.0.0 — bug #4: per-session probe used by `worktreeHasSession`
68
- // (resolveSessionDirectory fast-path). Matches `/api/session/{id}`
69
- // (no `/message` or `/prompt` suffix). 200 when the session
70
- // belongs to the directory in the query string; 404 otherwise.
71
- const probeM = url.pathname.match(/^\/api\/session\/([^/]+)$/);
72
- if (probeM && req.method === 'GET') {
73
- const dir = url.searchParams.get('directory') || '';
74
- // The session "lives" in /tmp/session-worktree (matches the
75
- // recorded worktree in writeServeJson). All other directories
76
- // 404 so we can test the fallback path.
77
- if (dir === '/tmp/session-worktree') {
78
- res.writeHead(200, { 'Content-Type': 'application/json' });
79
- res.end(JSON.stringify({ id: probeM[1] }));
80
- return;
81
- }
82
- res.writeHead(404, { 'Content-Type': 'application/json' });
83
- res.end(JSON.stringify({ error: 'session not found in directory' }));
84
- return;
85
- }
86
- const msgM = url.pathname.match(/^\/api\/session\/([^/]+)\/message$/);
87
- if (msgM && req.method === 'GET') {
88
- if (msgM[1] === 'sess-upstream-500') {
89
- res.writeHead(500, { 'Content-Type': 'application/json' });
90
- res.end(JSON.stringify({ error: 'internal server error for testing' }));
91
- return;
92
- }
93
- res.writeHead(200, { 'Content-Type': 'application/json' });
94
- res.end(JSON.stringify({ data: [
95
- { info: { id: 'm1', role: 'user', time: { created: 1000 } }, parts: [{ type: 'text', text: 'hello' }] },
96
- { info: { id: 'm2', role: 'assistant', time: { created: 2000 } }, parts: [{ type: 'text', text: 'hi' }] },
97
- ] }));
98
- return;
99
- }
100
- res.writeHead(404); res.end('not found');
101
- });
102
- upstreamServer.listen(0, '127.0.0.1', () => {
103
- upstreamPort = upstreamServer.address().port;
104
- resolve();
105
- });
106
- });
107
- }
108
-
109
- async function startDashboard() {
110
- const app = express();
111
- app.use(express.json({ limit: '2mb' }));
112
- app.use('/api', createClineSessionDetailRouter());
113
- dashboardServer = createServer(app);
114
- await new Promise((r) => dashboardServer.listen(0, '127.0.0.1', r));
115
- dashboardBaseUrl = `http://127.0.0.1:${dashboardServer.address().port}`;
116
- }
117
-
118
- let dashboardServer, dashboardBaseUrl, tmpDir;
119
- let SERVE_JSON_PATH;
120
- let originalServeJson;
121
-
122
- before(async () => {
123
- SERVE_JSON_PATH = `${tmpdir()}/bizar-test-serve-detail-${process.pid}-${Date.now()}.json`;
124
- process.env.BIZAR_SERVE_JSON_PATH = SERVE_JSON_PATH;
125
- await startUpstream();
126
- await startDashboard();
127
- tmpDir = mkdtempSync(join(tmpdir(), 'cline-sessions-detail-'));
128
- if (existsSync(SERVE_JSON_PATH)) {
129
- originalServeJson = readFileSync(SERVE_JSON_PATH, 'utf8');
130
- }
131
- });
132
-
133
- after(async () => {
134
- if (originalServeJson !== undefined) {
135
- writeFileSync(SERVE_JSON_PATH, originalServeJson, 'utf8');
136
- } else if (existsSync(SERVE_JSON_PATH)) {
137
- rmSync(SERVE_JSON_PATH);
138
- }
139
- if (dashboardServer) await new Promise((r) => dashboardServer.close(r));
140
- if (upstreamServer) await new Promise((r) => upstreamServer.close(r));
141
- if (tmpDir) rmSync(tmpDir, { recursive: true, force: true });
142
- delete process.env.BIZAR_SERVE_JSON_PATH;
143
- });
144
-
145
- beforeEach(() => {
146
- upstream.promptHits = [];
147
- upstream.lastPromptBody = null;
148
- upstream.streamChunks = [];
149
- });
150
-
151
- function writeServeJson(worktree) {
152
- writeFileSync(SERVE_JSON_PATH, JSON.stringify({ port: upstreamPort, password: 'test-pw', worktree, pid: 99999, startedAt: Date.now() }), 'utf8');
153
- }
154
-
155
- function writeServeJsonWithoutWorktree() {
156
- writeFileSync(SERVE_JSON_PATH, JSON.stringify({ port: upstreamPort, password: 'test-pw', pid: 99999, startedAt: Date.now() }), 'utf8');
157
- }
158
-
159
- /** Move serve.json aside so readServeInfo() returns null.
160
- * Uses copy + unlink because rename across filesystems (e.g.
161
- * /home/* → /tmp/*) throws EXDEV on Linux. */
162
- function moveServeJsonAside() {
163
- if (!existsSync(SERVE_JSON_PATH)) return;
164
- const tmp = join(tmpDir, `serve-aside-${Date.now()}-${process.pid}.json`);
165
- copyFileSync(SERVE_JSON_PATH, tmp);
166
- unlinkSync(SERVE_JSON_PATH);
167
- }
168
-
169
- function parseSseStream(text) {
170
- const out = [];
171
- let event = null, dataLines = [];
172
- for (const line of text.split(/\r?\n/)) {
173
- if (line === '') {
174
- if (event !== null || dataLines.length > 0) out.push({ event, data: dataLines.join('\n') });
175
- event = null; dataLines = [];
176
- continue;
177
- }
178
- if (line.startsWith(':')) continue;
179
- const colon = line.indexOf(':');
180
- if (colon < 0) continue;
181
- const field = line.slice(0, colon);
182
- let value = line.slice(colon + 1);
183
- if (value.startsWith(' ')) value = value.slice(1);
184
- if (field === 'event') event = value;
185
- else if (field === 'data') dataLines.push(value);
186
- }
187
- return out;
188
- }
189
-
190
- // ── tests ─────────────────────────────────────────────────────────────────
191
-
192
- test('GET messages returns 503 plugin_offline when no serve.json', async () => {
193
- moveServeJsonAside();
194
- try {
195
- const res = await fetch(`${dashboardBaseUrl}/api/cline-sessions/sess-1/messages`);
196
- assert.equal(res.status, 503);
197
- assert.equal((await res.json()).error, 'plugin_offline');
198
- } finally {
199
- // Restore — the next test wants serve.json present again.
200
- if (originalServeJson !== undefined) writeServeJson(JSON.parse(originalServeJson).worktree);
201
- }
202
- });
203
-
204
- test('GET messages returns 200 with normalized message list', async () => {
205
- writeServeJson('/tmp/session-worktree');
206
- const res = await fetch(`${dashboardBaseUrl}/api/cline-sessions/sess-1/messages`);
207
- assert.equal(res.status, 200);
208
- const body = await res.json();
209
- assert.equal(body.messages.length, 2);
210
- assert.equal(body.messages[0].id, 'm1');
211
- assert.equal(body.messages[0].role, 'user');
212
- assert.equal(body.messages[0].content, 'hello');
213
- assert.equal(body.messages[0].ts, 1000);
214
- assert.equal(body.messages[1].role, 'assistant');
215
- assert.equal(body.messages[1].content, 'hi');
216
- assert.equal(body.messages[1].ts, 2000);
217
- });
218
-
219
- test('POST send returns 400 when body is empty', async () => {
220
- writeServeJson('/tmp/session-worktree');
221
- const r = await fetch(`${dashboardBaseUrl}/api/cline-sessions/sess-1/send`, {
222
- method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({}),
223
- });
224
- assert.equal(r.status, 400);
225
- });
226
-
227
- test('POST send returns 400 when agent is missing', async () => {
228
- writeServeJson('/tmp/session-worktree');
229
- const r = await fetch(`${dashboardBaseUrl}/api/cline-sessions/sess-1/send`, {
230
- method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ message: 'hi' }),
231
- });
232
- assert.equal(r.status, 400);
233
- });
234
-
235
- test('POST send returns 400 when message is empty string', async () => {
236
- writeServeJson('/tmp/session-worktree');
237
- const r = await fetch(`${dashboardBaseUrl}/api/cline-sessions/sess-1/send`, {
238
- method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ message: '', agent: 'odin' }),
239
- });
240
- assert.equal(r.status, 400);
241
- });
242
-
243
- test('POST send returns ok=true with synthesized messageId', async () => {
244
- writeServeJson('/tmp/session-worktree');
245
- const r = await fetch(`${dashboardBaseUrl}/api/cline-sessions/sess-1/send`, {
246
- method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ message: 'hello there', agent: 'odin' }),
247
- });
248
- assert.equal(r.status, 200);
249
- const body = await r.json();
250
- assert.equal(body.ok, true);
251
- assert.ok(body.messageId.startsWith('msg_'));
252
- assert.equal(upstream.promptHits.length, 1);
253
- assert.equal(upstream.lastPromptBody.prompt.text, 'hello there');
254
- assert.equal(upstream.lastPromptBody.agent, 'odin');
255
- assert.equal(upstream.lastPromptBody.id, body.messageId);
256
- });
257
-
258
- test('POST send returns 502 cline_error when upstream 404s', async () => {
259
- writeServeJson('/tmp/session-worktree');
260
- const r = await fetch(`${dashboardBaseUrl}/api/cline-sessions/sess-fail/send`, {
261
- method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ message: 'hi', agent: 'odin' }),
262
- });
263
- assert.equal(r.status, 502);
264
- const body = await r.json();
265
- assert.equal(body.error, 'cline_error');
266
- assert.ok(body.message.length > 0);
267
- });
268
-
269
- test('SSE stream forwards only events for the requested session', async () => {
270
- writeServeJson('/tmp/session-worktree');
271
- upstream.streamChunks = [
272
- 'event: message.updated\ndata: {"type":"message.updated","properties":{"sessionID":"our-id","messageID":"m1"}}\n\n',
273
- 'event: message.updated\ndata: {"type":"message.updated","properties":{"sessionID":"OTHER-id","messageID":"m9"}}\n\n',
274
- 'event: sync\ndata: {"type":"sync","syncEvent":{"type":"session.idle.1","data":{"sessionID":"our-id"}}}\n\n',
275
- ];
276
- const res = await fetch(`${dashboardBaseUrl}/api/cline-sessions/our-id/stream`);
277
- assert.equal(res.status, 200);
278
- assert.match(res.headers.get('content-type'), /text\/event-stream/);
279
- assert.match(res.headers.get('cache-control'), /no-cache/);
280
- assert.equal(res.headers.get('x-accel-buffering'), 'no');
281
- const events = parseSseStream(await res.text());
282
- assert.equal(events.length, 2);
283
- assert.equal(events[0].event, 'message.updated');
284
- const d0 = JSON.parse(events[0].data);
285
- assert.equal(d0.sessionID, 'our-id');
286
- assert.equal(d0.messageID, 'm1');
287
- assert.equal(events[1].event, 'session.idle');
288
- assert.equal(JSON.parse(events[1].data).sessionID, 'our-id');
289
- });
290
-
291
- test('SSE stream unwraps sync envelopes and strips version suffix', async () => {
292
- writeServeJson('/tmp/session-worktree');
293
- upstream.streamChunks = [
294
- 'event: sync\ndata: {"type":"sync","syncEvent":{"type":"message.updated.1","data":{"sessionID":"our-id","messageID":"m3"}}}\n\n',
295
- ];
296
- const res = await fetch(`${dashboardBaseUrl}/api/cline-sessions/our-id/stream`);
297
- assert.equal(res.status, 200);
298
- const events = parseSseStream(await res.text());
299
- assert.equal(events.length, 1);
300
- assert.equal(events[0].event, 'message.updated');
301
- const d = JSON.parse(events[0].data);
302
- assert.equal(d.sessionID, 'our-id');
303
- assert.equal(d.messageID, 'm3');
304
- });
305
-
306
- // ── Error handling tests ─────────────────────────────────────────────────
307
-
308
- test('GET messages returns 503 directory_unknown when worktree missing and session not found', async () => {
309
- writeServeJsonWithoutWorktree();
310
- try {
311
- // Request a non-existent session ID so listClineSessions doesn't find it,
312
- // and with no worktree in serve.json, resolveSessionDirectory returns null.
313
- const res = await fetch(`${dashboardBaseUrl}/api/cline-sessions/no-such-session/messages`);
314
- assert.equal(res.status, 503);
315
- const body = await res.json();
316
- assert.equal(body.error, 'directory_unknown');
317
- assert.ok(body.message.length > 0);
318
- assert.ok(typeof body.suggestion === 'string');
319
- } finally {
320
- // Restore worktree for subsequent tests.
321
- writeServeJson('/tmp/session-worktree');
322
- }
323
- });
324
-
325
- test('GET messages returns 502 cline_error when upstream returns 500', async () => {
326
- writeServeJson('/tmp/session-worktree');
327
- const res = await fetch(`${dashboardBaseUrl}/api/cline-sessions/sess-upstream-500/messages`);
328
- assert.equal(res.status, 502);
329
- const body = await res.json();
330
- assert.equal(body.error, 'cline_error');
331
- assert.ok(body.message.length > 0);
332
- assert.ok(body.cause === 'unknown' || typeof body.cause === 'string');
333
- assert.ok(typeof body.suggestion === 'string');
334
- });
335
-
336
- test('GET messages uses suggestion field in error responses', async () => {
337
- // Test that the plugin_offline response includes suggestion.
338
- moveServeJsonAside();
339
- try {
340
- const res = await fetch(`${dashboardBaseUrl}/api/cline-sessions/sess-1/messages`);
341
- assert.equal(res.status, 503);
342
- const body = await res.json();
343
- assert.equal(body.error, 'plugin_offline');
344
- assert.ok(typeof body.suggestion === 'string');
345
- assert.ok(body.suggestion.length > 0);
346
- } finally {
347
- // Restore so the after() cleanup finds the file.
348
- writeServeJson('/tmp/session-worktree');
349
- }
350
- });
351
-
352
- // ── v5.0.0 — bug #4 — structured error envelopes + worktree fast-path ──
353
-
354
- test('GET messages 502 envelope includes cause/status/suggestion on upstream failure', async () => {
355
- // Issue: bug #4 — the user previously saw the raw error string
356
- // ("listMessages network error: fetch failed") with no structured
357
- // fields. The fix is to surface `cause`, `status`, and `suggestion`
358
- // so the front-end ChatInfoPanel can render actionable UI.
359
- writeServeJson('/tmp/session-worktree');
360
- const res = await fetch(
361
- `${dashboardBaseUrl}/api/cline-sessions/sess-upstream-500/messages`,
362
- );
363
- assert.equal(res.status, 502);
364
- const body = await res.json();
365
- assert.equal(body.error, 'cline_error');
366
- assert.equal(typeof body.message, 'string');
367
- assert.ok(body.message.length > 0);
368
- // Upstream 500 → cause stays 'unknown' (no network code), and the
369
- // route forwards the upstream's HTTP status so the operator can
370
- // tell whether it's cline that's broken vs. the dashboard.
371
- assert.ok(typeof body.cause === 'string');
372
- assert.equal(body.status, 500);
373
- assert.ok(typeof body.suggestion === 'string');
374
- assert.ok(body.suggestion.length > 0);
375
- });
376
-
377
- test('GET messages 503 plugin_offline envelope includes suggestion (operator guidance)', async () => {
378
- // Defensive: confirm the 503 path also carries a suggestion (some
379
- // consumers — including the structured-error path in useChat.ts —
380
- // branch on `body.code === 'plugin_offline'`).
381
- moveServeJsonAside();
382
- try {
383
- const res = await fetch(
384
- `${dashboardBaseUrl}/api/cline-sessions/sess-1/messages`,
385
- );
386
- assert.equal(res.status, 503);
387
- const body = await res.json();
388
- assert.equal(body.error, 'plugin_offline');
389
- assert.ok(typeof body.suggestion === 'string');
390
- assert.ok(body.suggestion.length > 0);
391
- assert.match(body.suggestion, /bizar doctor|cline serve/i);
392
- } finally {
393
- writeServeJson('/tmp/session-worktree');
394
- }
395
- });
396
-
397
- test('GET messages 503 directory_unknown envelope includes suggestion', async () => {
398
- writeServeJsonWithoutWorktree();
399
- try {
400
- const res = await fetch(
401
- `${dashboardBaseUrl}/api/cline-sessions/no-such-session/messages`,
402
- );
403
- assert.equal(res.status, 503);
404
- const body = await res.json();
405
- assert.equal(body.error, 'directory_unknown');
406
- assert.ok(typeof body.message === 'string');
407
- assert.ok(typeof body.suggestion === 'string');
408
- assert.ok(body.suggestion.length > 0);
409
- } finally {
410
- writeServeJson('/tmp/session-worktree');
411
- }
412
- });
413
-
414
- test('GET messages uses worktree fast-path when session exists in recorded worktree', async () => {
415
- // The new resolveSessionDirectory fast-path probes the recorded
416
- // worktree first (cheap GET /api/session/{id}?directory=... probe).
417
- // When the upstream says yes, the resolver returns the worktree
418
- // WITHOUT calling GET /api/session. We assert the latter is NOT
419
- // called by checking the upstream.promptHits / request log isn't
420
- // touched (only the messages endpoint should fire here).
421
- //
422
- // Indirect check: request a session whose id is NOT in the
423
- // /api/session listing but IS in /tmp/session-worktree per the
424
- // probe. The probe handler returns 200 for that directory, so the
425
- // route should succeed even though the session isn't in the list.
426
- writeServeJson('/tmp/session-worktree');
427
- const res = await fetch(
428
- `${dashboardBaseUrl}/api/cline-sessions/sess-1/messages`,
429
- );
430
- assert.equal(res.status, 200);
431
- const body = await res.json();
432
- assert.ok(Array.isArray(body.messages));
433
- assert.ok(body.messages.length >= 1);
434
- });