@band-app/server 0.16.8 → 0.17.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 (205) hide show
  1. package/dist/client/assets/DockviewBrowserContainer-B_oEene2.js +5 -0
  2. package/dist/client/assets/DockviewTerminalContainer-CfQMvR_k.js +2 -0
  3. package/dist/client/assets/TerminalPanel-DxZK0ClB.js +5 -0
  4. package/dist/client/assets/_basePickBy-Ct-e0Qqq.js +1 -0
  5. package/dist/client/assets/_baseUniq-CxKOXF1k.js +1 -0
  6. package/dist/client/assets/arc-CKSDLbJ_.js +1 -0
  7. package/dist/client/assets/architectureDiagram-VXUJARFQ-DX7YfptV.js +36 -0
  8. package/dist/client/assets/{blockDiagram-VD42YOAC-BKiU7fF0.js → blockDiagram-VD42YOAC-CsuIx-c9.js} +5 -5
  9. package/dist/client/assets/{c4Diagram-YG6GDRKO-CYISxlyF.js → c4Diagram-YG6GDRKO-DychwT1W.js} +3 -3
  10. package/dist/client/assets/channel-B-u6m7I1.js +1 -0
  11. package/dist/client/assets/chunk-4BX2VUAB-loz8MPPD.js +1 -0
  12. package/dist/client/assets/chunk-55IACEB6-D29ChrqC.js +1 -0
  13. package/dist/client/assets/{chunk-B4BG7PRW-DltWViHS.js → chunk-B4BG7PRW-DKCONMEK.js} +6 -6
  14. package/dist/client/assets/{chunk-DI55MBZ5-51JXB972.js → chunk-DI55MBZ5-D5zzjeE8.js} +1 -1
  15. package/dist/client/assets/{chunk-FMBD7UC4-CynepQnx.js → chunk-FMBD7UC4-D1xESdhD.js} +1 -1
  16. package/dist/client/assets/chunk-QN33PNHL-DXisPMUT.js +1 -0
  17. package/dist/client/assets/chunk-QZHKN3VN-Ch8ZVx4Y.js +1 -0
  18. package/dist/client/assets/chunk-TZMSLE5B-GuM5n4Rs.js +1 -0
  19. package/dist/client/assets/classDiagram-2ON5EDUG-ZLOOfEOW.js +1 -0
  20. package/dist/client/assets/classDiagram-v2-WZHVMYZB-ZLOOfEOW.js +1 -0
  21. package/dist/client/assets/clone-CDLv4lRU.js +1 -0
  22. package/dist/client/assets/cose-bilkent-S5V4N54A-Cf0f3nH9.js +1 -0
  23. package/dist/client/assets/dagre-6UL2VRFP-BEjucV14.js +4 -0
  24. package/dist/client/assets/diagram-PSM6KHXK-4UTMLb3J.js +24 -0
  25. package/dist/client/assets/diagram-QEK2KX5R-B9rhi9zE.js +43 -0
  26. package/dist/client/assets/diagram-S2PKOQOG-CS7F4WJO.js +24 -0
  27. package/dist/client/assets/{erDiagram-Q2GNP2WA-DZUjamhk.js → erDiagram-Q2GNP2WA-D-EqIR9o.js} +4 -4
  28. package/dist/client/assets/{flowDiagram-NV44I4VS-oIHer-h-.js → flowDiagram-NV44I4VS-_GH1A_sS.js} +5 -5
  29. package/dist/client/assets/ganttDiagram-JELNMOA3-Dtb6N1ze.js +267 -0
  30. package/dist/client/assets/gitGraphDiagram-V2S2FVAM-B_QsP5ak.js +65 -0
  31. package/dist/client/assets/{graph-r-V7AF54.js → graph-H6OCDpse.js} +1 -1
  32. package/dist/client/assets/highlighted-body-B3W2YXNL-Pz2rshlt.js +1 -0
  33. package/dist/client/assets/index-B-KsZlI_.js +1 -0
  34. package/dist/client/assets/{index-DAMgQMyn.js → index-BCbe81ki.js} +2 -2
  35. package/dist/client/assets/index-BOdifnXB.js +1 -0
  36. package/dist/client/assets/{index-W1CPMGYX.js → index-BQW7Zpk7.js} +1 -1
  37. package/dist/client/assets/index-BX_7-t5E.js +1 -0
  38. package/dist/client/assets/{index-u_2V_RF4.js → index-BktK8Iwc.js} +1 -1
  39. package/dist/client/assets/{index-DQixQE5Y.js → index-BtEs1oEp.js} +1 -1
  40. package/dist/client/assets/{index-CdJ3WH3f.js → index-BtajlvkF.js} +1 -1
  41. package/dist/client/assets/{index-NMjGSNmU.js → index-Bx3rRbZG.js} +1 -1
  42. package/dist/client/assets/{index-DhTLiwux.js → index-C6MgAn1q.js} +1 -1
  43. package/dist/client/assets/{index-foc9a7eE.js → index-CzCjpAqZ.js} +5 -5
  44. package/dist/client/assets/{index-CFEu-Cf9.js → index-DQAckahj.js} +1 -1
  45. package/dist/client/assets/index-DaRnNd02.js +7 -0
  46. package/dist/client/assets/{index-CYvgC-U1.js → index-Im7rGMYn.js} +1 -1
  47. package/dist/client/assets/{index-BvWkKnfY.js → index-WmGuuT8Z.js} +1 -1
  48. package/dist/client/assets/{index-BiUUT09K.js → index-aTt3zXBv.js} +1 -1
  49. package/dist/client/assets/{index-BDQWeqNk.js → index-nPplcWzt.js} +1 -1
  50. package/dist/client/assets/{index-y0IIofTa.js → index-vaGaAlmP.js} +1 -1
  51. package/dist/client/assets/infoDiagram-HS3SLOUP-Dp2iuUeA.js +2 -0
  52. package/dist/client/assets/{journeyDiagram-XKPGCS4Q-E4OGYZo3.js → journeyDiagram-XKPGCS4Q-BaVzrE3V.js} +3 -3
  53. package/dist/client/assets/{kanban-definition-3W4ZIXB7-DDOW42i6.js → kanban-definition-3W4ZIXB7-DdbWsnm7.js} +8 -8
  54. package/dist/client/assets/{layout-BU7n9QQq.js → layout-vxWf40Ht.js} +1 -1
  55. package/dist/client/assets/{linear-CFFUeqRn.js → linear-BstrgKy8.js} +1 -1
  56. package/dist/client/assets/{main-onb8WwfN.js → main-DRq9Axai.js} +231 -234
  57. package/dist/client/assets/main-evBJruhw.css +1 -0
  58. package/dist/client/assets/{mindmap-definition-VGOIOE7T-BQlhTP7t.js → mindmap-definition-VGOIOE7T-CAEEMYhK.js} +3 -3
  59. package/dist/client/assets/pieDiagram-ADFJNKIX-DCNv4UlO.js +30 -0
  60. package/dist/client/assets/{quadrantDiagram-AYHSOK5B-D7D_64Ur.js → quadrantDiagram-AYHSOK5B-BeP4t0hp.js} +2 -2
  61. package/dist/client/assets/{requirementDiagram-UZGBJVZJ-Dd-Qxkau.js → requirementDiagram-UZGBJVZJ-CAdiLb_M.js} +2 -2
  62. package/dist/client/assets/sankeyDiagram-TZEHDZUN-DW9xKT5Y.js +10 -0
  63. package/dist/client/assets/{sequenceDiagram-WL72ISMW-UH13bSlf.js → sequenceDiagram-WL72ISMW-D9y8fK_R.js} +1 -1
  64. package/dist/client/assets/{square-terminal-BgnPkQhG.js → square-terminal-VjG9-RoZ.js} +1 -1
  65. package/dist/client/assets/stateDiagram-FKZM4ZOC-QYuyBeVm.js +1 -0
  66. package/dist/client/assets/stateDiagram-v2-4FDKWEC3-VVONI0Hb.js +1 -0
  67. package/dist/client/assets/{timeline-definition-IT6M3QCI-DoLvii7e.js → timeline-definition-IT6M3QCI-Ci_SXZdO.js} +4 -4
  68. package/dist/client/assets/{treemap-GDKQZRPO-C6cooeby.js → treemap-GDKQZRPO-fDacl-jS.js} +1 -1
  69. package/dist/client/assets/workspace._workspaceId-C9BVWo6-.js +2 -0
  70. package/dist/client/assets/workspace._workspaceId-CMlw9wn8.js +1 -0
  71. package/dist/client/assets/{xychartDiagram-PRI3JC2R-DjUMVf0W.js → xychartDiagram-PRI3JC2R-rRpBADcB.js} +4 -4
  72. package/dist/migrations/20260525163504_add_projects_has_origin/migration.sql +1 -0
  73. package/dist/migrations/20260525163504_add_projects_has_origin/snapshot.json +866 -0
  74. package/dist/openapi.json +431 -16
  75. package/dist/server/assets/DockviewBrowserContainer-BAe7TLKD.js +1954 -0
  76. package/dist/server/assets/{DockviewTerminalContainer-Dl-H-7q5.js → DockviewTerminalContainer-CC7i0yMZ.js} +73 -24
  77. package/dist/server/assets/{TerminalPanel-Nx4CmvlW.js → TerminalPanel-gBh8VBn0.js} +1 -1
  78. package/dist/server/assets/{_basePickBy-BG2OhlJc.js → _basePickBy-CTks6QXq.js} +2 -2
  79. package/dist/server/assets/{_baseUniq-DB6mvOCI.js → _baseUniq-BJI4qneQ.js} +1 -1
  80. package/dist/server/assets/_tanstack-start-manifest_v-CfuSyuIp.js +4 -0
  81. package/dist/server/assets/{arc-DaVwrLrM.js → arc-Fdc_l0PB.js} +1 -1
  82. package/dist/server/assets/{architecture-7HQA4BMR-DIi4TM4E.js → architecture-7HQA4BMR-CfPXboDr.js} +6 -6
  83. package/dist/server/assets/{architectureDiagram-VXUJARFQ-DBRmPh1t.js → architectureDiagram-VXUJARFQ-D6UEkzy_.js} +6 -6
  84. package/dist/server/assets/{blockDiagram-VD42YOAC-CFdPLnD-.js → blockDiagram-VD42YOAC-BvasIENt.js} +6 -6
  85. package/dist/server/assets/{c4Diagram-YG6GDRKO-BJi6gbIt.js → c4Diagram-YG6GDRKO-MW5H9zoJ.js} +2 -2
  86. package/dist/server/assets/{channel-DkntTxx0.js → channel-XhTiPor2.js} +1 -1
  87. package/dist/server/assets/{chunk-4BX2VUAB-D2FiW3aP.js → chunk-4BX2VUAB-C6POw9HJ.js} +1 -1
  88. package/dist/server/assets/{chunk-55IACEB6-jZmh1Z5I.js → chunk-55IACEB6-BZ0x-UQb.js} +1 -1
  89. package/dist/server/assets/{chunk-B4BG7PRW-CNZgnxgA.js → chunk-B4BG7PRW-BAYqNQHL.js} +4 -4
  90. package/dist/server/assets/{chunk-DI55MBZ5-q0pODS0a.js → chunk-DI55MBZ5-DbsR50vR.js} +3 -3
  91. package/dist/server/assets/{chunk-FMBD7UC4-C96aN_Us.js → chunk-FMBD7UC4-D_KXTL87.js} +1 -1
  92. package/dist/server/assets/{chunk-QN33PNHL-Dam5gy0m.js → chunk-QN33PNHL-RXXHu7T0.js} +1 -1
  93. package/dist/server/assets/{chunk-QZHKN3VN-CXCmBbbu.js → chunk-QZHKN3VN-5QE6weTd.js} +1 -1
  94. package/dist/server/assets/{chunk-TZMSLE5B-CbK3gIHb.js → chunk-TZMSLE5B-HlRXkCDZ.js} +1 -1
  95. package/dist/server/assets/{classDiagram-v2-WZHVMYZB-BHB2vhDs.js → classDiagram-2ON5EDUG-B90fR_EV.js} +5 -5
  96. package/dist/server/assets/{classDiagram-2ON5EDUG-BHB2vhDs.js → classDiagram-v2-WZHVMYZB-B90fR_EV.js} +5 -5
  97. package/dist/server/assets/{clone-CN5lfg2Z.js → clone-Bjcb6OQr.js} +1 -1
  98. package/dist/server/assets/{cose-bilkent-S5V4N54A-Bq-O80sc.js → cose-bilkent-S5V4N54A-BgnWrjAl.js} +1 -1
  99. package/dist/server/assets/{dagre-6UL2VRFP-U80sNC8f.js → dagre-6UL2VRFP-LfRXD26Q.js} +6 -6
  100. package/dist/server/assets/{diagram-PSM6KHXK-5ksUDb2Z.js → diagram-PSM6KHXK-DLrJ9Eja.js} +7 -7
  101. package/dist/server/assets/{diagram-QEK2KX5R-COmUOoRU.js → diagram-QEK2KX5R-atbHIh96.js} +6 -6
  102. package/dist/server/assets/{diagram-S2PKOQOG-BOTznhFu.js → diagram-S2PKOQOG-BnxctnIJ.js} +6 -6
  103. package/dist/server/assets/{erDiagram-Q2GNP2WA-CZOlCzBi.js → erDiagram-Q2GNP2WA-Ct1zXovC.js} +4 -4
  104. package/dist/server/assets/{flowDiagram-NV44I4VS-ObYcdqyZ.js → flowDiagram-NV44I4VS-DtWHb6Ay.js} +5 -5
  105. package/dist/server/assets/{ganttDiagram-JELNMOA3-6c9A3Tfv.js → ganttDiagram-JELNMOA3-CySyldy4.js} +2 -2
  106. package/dist/server/assets/{gitGraph-G5XIXVHT-Q_zXZbiJ.js → gitGraph-G5XIXVHT-DFo7FJzL.js} +6 -6
  107. package/dist/server/assets/{gitGraphDiagram-V2S2FVAM-C-GqaejI.js → gitGraphDiagram-V2S2FVAM-DvT5EUG7.js} +7 -7
  108. package/dist/server/assets/{graph-CGXsNa6T.js → graph-B5XlkLf_.js} +2 -2
  109. package/dist/server/assets/{highlighted-body-B3W2YXNL-CjyCfwez.js → highlighted-body-B3W2YXNL-CLJWhRU_.js} +1 -1
  110. package/dist/server/assets/{index-C-7vS9m8.js → index--4MijjkY.js} +2 -2
  111. package/dist/server/assets/{index-DKtCHZcS.js → index-4SOjxyuO.js} +2 -2
  112. package/dist/server/assets/{index-CAfRymUE.js → index-BQ5LDgRA.js} +3 -3
  113. package/dist/server/assets/{index-DU_XVqOC.js → index-BanzNq86.js} +1 -1
  114. package/dist/server/assets/{index-BaYLnq50.js → index-BvJzvUfR.js} +2 -2
  115. package/dist/server/assets/{index-DIahp6rS.js → index-C2GzB22l.js} +2 -2
  116. package/dist/server/assets/{index-B3U9PRLr.js → index-CAJcSCqE.js} +2 -2
  117. package/dist/server/assets/{index-BBvVnzgd.js → index-CLUle2oh.js} +5 -5
  118. package/dist/server/assets/{index-C0kihLnk.js → index-CMO4FLK_.js} +2 -2
  119. package/dist/server/assets/{index-DIdSfU9-.js → index-CXMNOcuN.js} +1 -1
  120. package/dist/server/assets/{index-73YfcfUk.js → index-CXmMBSCL.js} +2 -2
  121. package/dist/server/assets/{index-C71uG8NB.js → index-CdgmRfZg.js} +2 -2
  122. package/dist/server/assets/{index-BfyUYDbk.js → index-DJ8A5E65.js} +5 -5
  123. package/dist/server/assets/{index-CxSyZwen.js → index-DjySh3G7.js} +3 -3
  124. package/dist/server/assets/{index-D_0vKELK.js → index-DuXjusjn.js} +2 -2
  125. package/dist/server/assets/{index-DejplVdQ.js → index-QiPzMfSX.js} +2 -2
  126. package/dist/server/assets/{index-DnWmaxai.js → index-SuLB6TaE.js} +2 -2
  127. package/dist/server/assets/{index-ukALXr65.js → index-bmq-aMYV.js} +4 -4
  128. package/dist/server/assets/{info-VBDWY6EO-BsWgc-Ym.js → info-VBDWY6EO-CW57QiJi.js} +6 -6
  129. package/dist/server/assets/{infoDiagram-HS3SLOUP-C04udjz-.js → infoDiagram-HS3SLOUP-D_Zdx-MM.js} +5 -5
  130. package/dist/server/assets/{journeyDiagram-XKPGCS4Q-D3MBfJwF.js → journeyDiagram-XKPGCS4Q-BcO9qzr2.js} +4 -4
  131. package/dist/server/assets/{kanban-definition-3W4ZIXB7-Czuz4I_Q.js → kanban-definition-3W4ZIXB7-BatZ7RKG.js} +2 -2
  132. package/dist/server/assets/{layout-D6n2z2ff.js → layout-Cwuj9CwZ.js} +4 -4
  133. package/dist/server/assets/{linear-BDP9KC1O.js → linear-CP3xC85V.js} +1 -1
  134. package/dist/server/assets/{mermaid-3ZIDBTTL-oS_2f_Id.js → mermaid-3ZIDBTTL-BZm8jQDo.js} +1 -1
  135. package/dist/server/assets/{mermaid-parser.core-DRwka5gl.js → mermaid-parser.core-Cx17C8XR.js} +11 -11
  136. package/dist/server/assets/{mindmap-definition-VGOIOE7T-BPhhfr5z.js → mindmap-definition-VGOIOE7T-CpzqFomk.js} +3 -3
  137. package/dist/server/assets/{packet-DYOGHKS2-XJIQk327.js → packet-DYOGHKS2-x3ihoqUO.js} +6 -6
  138. package/dist/server/assets/{pie-VRWISCQL-BEbH9jgO.js → pie-VRWISCQL-DsMBDe8r.js} +6 -6
  139. package/dist/server/assets/{pieDiagram-ADFJNKIX-oLEFnRFT.js → pieDiagram-ADFJNKIX-DI4Hh6KE.js} +7 -7
  140. package/dist/server/assets/{quadrantDiagram-AYHSOK5B-nsrtyikJ.js → quadrantDiagram-AYHSOK5B-Cqc_vrUG.js} +2 -2
  141. package/dist/server/assets/{radar-ZZBFDIW7-XJaR0sVv.js → radar-ZZBFDIW7-CqwCJm3D.js} +6 -6
  142. package/dist/server/assets/{requirementDiagram-UZGBJVZJ-CHkWIv3O.js → requirementDiagram-UZGBJVZJ-96ab-40P.js} +3 -3
  143. package/dist/server/assets/{router-DqGeMR0F.js → router-CYNdQEN4.js} +1384 -2657
  144. package/dist/server/assets/{sankeyDiagram-TZEHDZUN-XynupQoy.js → sankeyDiagram-TZEHDZUN-Bux2-BQd.js} +1 -1
  145. package/dist/server/assets/{sequenceDiagram-WL72ISMW-Cnkmy2xq.js → sequenceDiagram-WL72ISMW-CFKyfvmC.js} +3 -3
  146. package/dist/server/assets/{square-terminal-D7AxF9nB.js → square-terminal-gVSeBp7-.js} +1 -1
  147. package/dist/server/assets/{stateDiagram-FKZM4ZOC-Chk4nsf_.js → stateDiagram-FKZM4ZOC-DGZQd18J.js} +8 -8
  148. package/dist/server/assets/{stateDiagram-v2-4FDKWEC3-DNIM2ODr.js → stateDiagram-v2-4FDKWEC3-DJXeLDOB.js} +4 -4
  149. package/dist/server/assets/{timeline-definition-IT6M3QCI-Fz2nlxYj.js → timeline-definition-IT6M3QCI-DzTJZPN5.js} +2 -2
  150. package/dist/server/assets/{treemap-GDKQZRPO-DNxd_7q0.js → treemap-GDKQZRPO-CD9jkQrA.js} +6 -6
  151. package/dist/server/assets/workspace._workspaceId-ClAAZ5aq.js +23 -0
  152. package/dist/server/assets/{workspace._workspaceId-KoR0msx0.js → workspace._workspaceId-DT6Kz8RH.js} +125 -97
  153. package/dist/server/assets/{xychartDiagram-PRI3JC2R-DtoxEUbW.js → xychartDiagram-PRI3JC2R-ByA0_p8p.js} +2 -2
  154. package/dist/server/server.js +2 -2
  155. package/dist/start-server.mjs +694 -297
  156. package/package.json +4 -4
  157. package/dist/client/assets/DockviewTerminalContainer-CfWqm1iB.js +0 -2
  158. package/dist/client/assets/TerminalPanel-C6VJtwdn.js +0 -5
  159. package/dist/client/assets/_basePickBy-CIXRHkYC.js +0 -1
  160. package/dist/client/assets/_baseUniq-K3DMbXu0.js +0 -1
  161. package/dist/client/assets/arc-BkgOQsVG.js +0 -1
  162. package/dist/client/assets/architectureDiagram-VXUJARFQ-CD44Dllc.js +0 -36
  163. package/dist/client/assets/channel-DjN8EGMy.js +0 -1
  164. package/dist/client/assets/chunk-4BX2VUAB-Bphc00nU.js +0 -1
  165. package/dist/client/assets/chunk-55IACEB6-CfN6hb2c.js +0 -1
  166. package/dist/client/assets/chunk-QN33PNHL-B45qeM-p.js +0 -1
  167. package/dist/client/assets/chunk-QZHKN3VN-1ObdmeeM.js +0 -1
  168. package/dist/client/assets/chunk-TZMSLE5B-CWtn_mgw.js +0 -1
  169. package/dist/client/assets/classDiagram-2ON5EDUG-C3N3Omm0.js +0 -1
  170. package/dist/client/assets/classDiagram-v2-WZHVMYZB-C3N3Omm0.js +0 -1
  171. package/dist/client/assets/clone-Co6N-TQN.js +0 -1
  172. package/dist/client/assets/cose-bilkent-S5V4N54A-B4IAbafd.js +0 -1
  173. package/dist/client/assets/dagre-6UL2VRFP-BGoRZDH9.js +0 -4
  174. package/dist/client/assets/diagram-PSM6KHXK-DIkN7d-V.js +0 -24
  175. package/dist/client/assets/diagram-QEK2KX5R-B-hPXzou.js +0 -43
  176. package/dist/client/assets/diagram-S2PKOQOG-BlUeis_2.js +0 -24
  177. package/dist/client/assets/ganttDiagram-JELNMOA3-D8LfLthv.js +0 -267
  178. package/dist/client/assets/gitGraphDiagram-V2S2FVAM-BgFUKaMK.js +0 -65
  179. package/dist/client/assets/highlighted-body-B3W2YXNL-BHkeGyHR.js +0 -1
  180. package/dist/client/assets/index-CNerXIiJ.js +0 -7
  181. package/dist/client/assets/index-CXHZbHRT.js +0 -1
  182. package/dist/client/assets/index-DLFTwdhm.js +0 -1
  183. package/dist/client/assets/index-fbwZk1fH.js +0 -1
  184. package/dist/client/assets/infoDiagram-HS3SLOUP-xB0m1ffH.js +0 -2
  185. package/dist/client/assets/main-BLOY6Nam.css +0 -1
  186. package/dist/client/assets/pieDiagram-ADFJNKIX-khlEdX5z.js +0 -30
  187. package/dist/client/assets/sankeyDiagram-TZEHDZUN-BxF-L0mm.js +0 -10
  188. package/dist/client/assets/stateDiagram-FKZM4ZOC-DJXW-Mwx.js +0 -1
  189. package/dist/client/assets/stateDiagram-v2-4FDKWEC3-BCtCzm2C.js +0 -1
  190. package/dist/client/assets/useSessionListContext-DJKT08Su.js +0 -1
  191. package/dist/client/assets/workspace._workspaceId-BZyIo0Fq.js +0 -1
  192. package/dist/client/assets/workspace._workspaceId.changes-WzxDrDHA.js +0 -1
  193. package/dist/client/assets/workspace._workspaceId.code-DGeXE4KO.js +0 -1
  194. package/dist/client/assets/workspace._workspaceId.code._-DjAaAaSY.js +0 -1
  195. package/dist/client/assets/workspace._workspaceId.code.index-D0PytT4F.js +0 -1
  196. package/dist/client/assets/workspace._workspaceId.index-DUzba27e.js +0 -1
  197. package/dist/client/assets/workspace._workspaceId.terminal-BeG77FAq.js +0 -2
  198. package/dist/server/assets/_tanstack-start-manifest_v-2XlZMknZ.js +0 -4
  199. package/dist/server/assets/useSessionListContext-D_vX6E2e.js +0 -23
  200. package/dist/server/assets/workspace._workspaceId.changes-BJoSmFXW.js +0 -38
  201. package/dist/server/assets/workspace._workspaceId.code-Cuj0zH98.js +0 -12
  202. package/dist/server/assets/workspace._workspaceId.code._-D3Ifnqrr.js +0 -44
  203. package/dist/server/assets/workspace._workspaceId.code.index-DZZZQ6sT.js +0 -36
  204. package/dist/server/assets/workspace._workspaceId.index-D1ULJxZJ.js +0 -96
  205. package/dist/server/assets/workspace._workspaceId.terminal-BaKW7ZGQ.js +0 -24
@@ -6501,11 +6501,11 @@ var require_tools = __commonJS({
6501
6501
  }
6502
6502
  }
6503
6503
  }
6504
- function buildFormatters(level, bindings, log29) {
6504
+ function buildFormatters(level, bindings, log31) {
6505
6505
  return {
6506
6506
  level,
6507
6507
  bindings,
6508
- log: log29
6508
+ log: log31
6509
6509
  };
6510
6510
  }
6511
6511
  function normalizeDestFileDescriptor(destination) {
@@ -6888,11 +6888,11 @@ var require_proto = __commonJS({
6888
6888
  }
6889
6889
  } else instance[serializersSym] = serializers;
6890
6890
  if (options2.hasOwnProperty("formatters")) {
6891
- const { level, bindings: chindings, log: log29 } = options2.formatters;
6891
+ const { level, bindings: chindings, log: log31 } = options2.formatters;
6892
6892
  instance[formattersSym] = buildFormatters(
6893
6893
  level || formatters.level,
6894
6894
  chindings || resetChildingsFormatter,
6895
- log29 || formatters.log
6895
+ log31 || formatters.log
6896
6896
  );
6897
6897
  } else {
6898
6898
  instance[formattersSym] = buildFormatters(
@@ -86574,11 +86574,11 @@ var require_core = __commonJS({
86574
86574
  Ajv2.ValidationError = validation_error_1.default;
86575
86575
  Ajv2.MissingRefError = ref_error_1.default;
86576
86576
  exports.default = Ajv2;
86577
- function checkOptions(checkOpts, options2, msg, log29 = "error") {
86577
+ function checkOptions(checkOpts, options2, msg, log31 = "error") {
86578
86578
  for (const key in checkOpts) {
86579
86579
  const opt = key;
86580
86580
  if (opt in options2)
86581
- this.logger[log29](`${msg}: option ${key}. ${checkOpts[opt]}`);
86581
+ this.logger[log31](`${msg}: option ${key}. ${checkOpts[opt]}`);
86582
86582
  }
86583
86583
  }
86584
86584
  function getSchEnv(keyRef) {
@@ -106688,6 +106688,9 @@ var import_react15 = __toESM(require_react(), 1);
106688
106688
  // src/dashboard/hooks/use-label-filter.ts
106689
106689
  var import_react16 = __toESM(require_react(), 1);
106690
106690
 
106691
+ // src/dashboard/hooks/use-projects.ts
106692
+ var EMPTY_PROJECTS = Object.freeze([]);
106693
+
106691
106694
  // src/dashboard/hooks/use-status.ts
106692
106695
  var import_react17 = __toESM(require_react(), 1);
106693
106696
 
@@ -106849,6 +106852,11 @@ var WorkspaceCard = (0, import_react20.memo)(function WorkspaceCard2({
106849
106852
  // "currently-active link in a list of related links".
106850
106853
  "data-active": isActive || void 0,
106851
106854
  "aria-current": isActive ? "page" : void 0,
106855
+ // Stable test hook keyed by workspaceId so integration tests can right-
106856
+ // click the specific card (issue #508). Branches with `/` in them are
106857
+ // collapsed to `-` by `toWorkspaceId` so the attribute value matches
106858
+ // the canonical workspace id used everywhere else in the UI.
106859
+ "data-testid": `project-list__workspace-card--${workspaceId}`,
106852
106860
  onClick: (e2) => {
106853
106861
  e2.stopPropagation();
106854
106862
  handleClick();
@@ -116453,7 +116461,15 @@ var projects = sqliteTable("projects", {
116453
116461
  // branches, PR/CI features) and plain folders (single implicit workspace,
116454
116462
  // no isolation, git features disabled). Defaults to "git" so existing
116455
116463
  // rows keep their behavior unchanged after migration.
116456
- kind: text2("kind", { enum: ["git", "plain"] }).notNull().default("git")
116464
+ kind: text2("kind", { enum: ["git", "plain"] }).notNull().default("git"),
116465
+ // Whether the project's git repo has an `origin` remote we can use for
116466
+ // CI / PR queries. Populated by `syncWorktrees` (see `sync-state.ts`) at
116467
+ // the CI tick cadence — `null` means "not yet probed" and is treated as
116468
+ // `true` (best-effort) so the first poll after a fresh boot still issues
116469
+ // the CI query before sync has had a chance to write the real value.
116470
+ // Defaults to 1 (true) so existing rows behave the same after migration.
116471
+ // See issue #458.
116472
+ hasOrigin: integer2("has_origin", { mode: "boolean" }).notNull().default(true)
116457
116473
  });
116458
116474
  var worktrees = sqliteTable("worktrees", {
116459
116475
  id: integer2("id").primaryKey({ autoIncrement: true }),
@@ -116589,10 +116605,15 @@ function loadState() {
116589
116605
  defaultBranch: row.defaultBranch,
116590
116606
  label: row.label ?? void 0,
116591
116607
  kind: row.kind ?? "git",
116608
+ hasOrigin: row.hasOrigin,
116592
116609
  worktrees: wtByProject.get(row.name) ?? []
116593
116610
  }))
116594
116611
  };
116595
116612
  }
116613
+ function setProjectHasOrigin(name3, hasOrigin) {
116614
+ const db2 = getDb();
116615
+ db2.update(projects).set({ hasOrigin }).where(eq2(projects.name, name3)).run();
116616
+ }
116596
116617
  function saveState(state2) {
116597
116618
  const db2 = getDb();
116598
116619
  db2.transaction((tx) => {
@@ -116606,7 +116627,11 @@ function saveState(state2) {
116606
116627
  defaultBranch: project.defaultBranch,
116607
116628
  label: project.label ?? null,
116608
116629
  sortOrder: i2,
116609
- kind: project.kind
116630
+ kind: project.kind,
116631
+ // Default to true for any caller that hasn't probed yet (e.g.
116632
+ // `projects.add` creating a brand-new row before the first
116633
+ // sync tick has run). The real value lands at the next sync.
116634
+ hasOrigin: project.hasOrigin ?? true
116610
116635
  }).run();
116611
116636
  for (const wt of project.worktrees) {
116612
116637
  tx.insert(worktrees).values({
@@ -116870,9 +116895,9 @@ async function getOrCreateAgent(chatId, worktreePath, agentId) {
116870
116895
  return existing.agent;
116871
116896
  }
116872
116897
  const defId = resolveAgentDefId(agentId);
116873
- const inFlight = pending.get(chatId);
116874
- if (inFlight && inFlight.agentDefId === defId) {
116875
- return inFlight.promise;
116898
+ const inFlight2 = pending.get(chatId);
116899
+ if (inFlight2 && inFlight2.agentDefId === defId) {
116900
+ return inFlight2.promise;
116876
116901
  }
116877
116902
  const config2 = getAgentConfig(worktreePath, agentId);
116878
116903
  log8.info({ chatId, type: config2.type, defId, cwd: worktreePath }, "creating agent");
@@ -117166,15 +117191,30 @@ function removeChatFromLayout(workspaceId, chatId) {
117166
117191
  manager.removePanel(workspaceId, chatId);
117167
117192
  }
117168
117193
 
117194
+ // src/lib/branch-status-poller.ts
117195
+ init_src();
117196
+
117169
117197
  // src/lib/git.ts
117198
+ init_src();
117170
117199
  import { execFile as execFile2 } from "node:child_process";
117171
117200
  import { readFile, stat as stat3 } from "node:fs/promises";
117172
117201
  import { join as join13 } from "node:path";
117202
+ var log9 = createLogger("git");
117173
117203
  function parseGitRemoteUrl(url) {
117174
117204
  const sshMatch = url.match(/^[\w.-]+@([^:]+):([^/]+)\/(.+?)(?:\.git)?$/);
117175
117205
  if (sshMatch) {
117176
117206
  return { host: sshMatch[1], owner: sshMatch[2], repo: sshMatch[3] };
117177
117207
  }
117208
+ const sshSchemeMatch = url.match(
117209
+ /^ssh:\/\/(?:[\w.-]+@)?([^/:]+)(?::\d+)?\/([^/]+)\/(.+?)(?:\.git)?$/
117210
+ );
117211
+ if (sshSchemeMatch) {
117212
+ return {
117213
+ host: sshSchemeMatch[1],
117214
+ owner: sshSchemeMatch[2],
117215
+ repo: sshSchemeMatch[3]
117216
+ };
117217
+ }
117178
117218
  const httpsMatch = url.match(/^https?:\/\/([^/]+)\/([^/]+)\/(.+?)(?:\.git)?$/);
117179
117219
  if (httpsMatch) {
117180
117220
  return { host: httpsMatch[1], owner: httpsMatch[2], repo: httpsMatch[3] };
@@ -117186,13 +117226,14 @@ async function getRepoInfo(worktreePath) {
117186
117226
  const remoteUrl = (await execGit(["remote", "get-url", "origin"], worktreePath)).trim();
117187
117227
  const parsed = parseGitRemoteUrl(remoteUrl);
117188
117228
  if (!parsed) {
117189
- console.error(`getRepoInfo: failed to parse remote URL "${remoteUrl}" for ${worktreePath}`);
117229
+ log9.debug('getRepoInfo: failed to parse remote URL "%s" for %s', remoteUrl, worktreePath);
117190
117230
  }
117191
117231
  return parsed;
117192
117232
  } catch (err) {
117193
- console.error(
117194
- `getRepoInfo: failed for ${worktreePath}:`,
117195
- err instanceof Error ? err.message : err
117233
+ log9.debug(
117234
+ "getRepoInfo: failed for %s: %s",
117235
+ worktreePath,
117236
+ err instanceof Error ? err.message : String(err)
117196
117237
  );
117197
117238
  return null;
117198
117239
  }
@@ -117479,6 +117520,10 @@ async function reconcileOneProject(project) {
117479
117520
  pinned: pinnedByBranch.get(wt.branch) ?? false
117480
117521
  }));
117481
117522
  } catch {
117523
+ if (project.hasOrigin) {
117524
+ setProjectHasOrigin(project.name, false);
117525
+ project.hasOrigin = false;
117526
+ }
117482
117527
  return false;
117483
117528
  }
117484
117529
  const existingSet = new Set(project.worktrees.map((wt) => `${wt.branch}\0${wt.path}`));
@@ -117492,10 +117537,19 @@ async function reconcileOneProject(project) {
117492
117537
  project.defaultBranch = remoteBranch;
117493
117538
  mutated = true;
117494
117539
  }
117540
+ const hasOrigin = await getRepoInfo(project.path) !== null;
117541
+ if (hasOrigin !== project.hasOrigin) {
117542
+ try {
117543
+ setProjectHasOrigin(project.name, hasOrigin);
117544
+ project.hasOrigin = hasOrigin;
117545
+ } catch {
117546
+ }
117547
+ }
117495
117548
  return mutated;
117496
117549
  }
117497
117550
 
117498
117551
  // src/lib/branch-status-poller.ts
117552
+ var log10 = createLogger("branch-status-poller");
117499
117553
  var INTERVALS = {
117500
117554
  // 5 s git / 30 s CI — the original cadence, used when the user is actively looking at the UI on AC power.
117501
117555
  active: { pollMs: 5e3, ciTicks: 6 },
@@ -117507,7 +117561,6 @@ var INTERVALS = {
117507
117561
  var pollerTimer = null;
117508
117562
  var tickCount = 0;
117509
117563
  var currentActivity = "active";
117510
- var repoInfoCache = /* @__PURE__ */ new Map();
117511
117564
  function getWorkspaces() {
117512
117565
  const state2 = loadState();
117513
117566
  const workspaces = [];
@@ -117520,7 +117573,8 @@ function getWorkspaces() {
117520
117573
  branch: wt.branch,
117521
117574
  defaultBranch: project.defaultBranch,
117522
117575
  worktreePath: wt.path,
117523
- projectPath: project.path
117576
+ projectPath: project.path,
117577
+ hasOrigin: project.hasOrigin
117524
117578
  });
117525
117579
  }
117526
117580
  }
@@ -117571,30 +117625,29 @@ async function getGitStatus(worktreePath) {
117571
117625
  }
117572
117626
  return status;
117573
117627
  }
117574
- async function resolveRepoInfo(projectPath) {
117575
- const cached2 = repoInfoCache.get(projectPath);
117576
- if (cached2 !== void 0) return cached2;
117577
- const info = await getRepoInfo(projectPath);
117578
- if (info) {
117579
- repoInfoCache.set(projectPath, info);
117580
- }
117581
- return info;
117582
- }
117583
117628
  async function getBatchedCIStatuses(workspaces) {
117584
- repoInfoCache.clear();
117585
- const resolved = [];
117586
- await Promise.allSettled(
117587
- workspaces.map(async (ws, index3) => {
117588
- const repoInfo = await resolveRepoInfo(ws.projectPath);
117589
- if (repoInfo) {
117590
- resolved.push({ ws, repoInfo, alias: `ws_${index3}` });
117591
- } else {
117592
- console.error(
117593
- `CI poll: failed to resolve repo info for ${ws.workspaceId} (${ws.projectPath})`
117594
- );
117595
- }
117629
+ const uniqueProjectPaths = [...new Set(workspaces.map((ws) => ws.projectPath))];
117630
+ const repoInfoByPath = /* @__PURE__ */ new Map();
117631
+ await Promise.all(
117632
+ uniqueProjectPaths.map(async (path3) => {
117633
+ repoInfoByPath.set(path3, await getRepoInfo(path3));
117596
117634
  })
117597
117635
  );
117636
+ for (const path3 of uniqueProjectPaths) {
117637
+ if (repoInfoByPath.get(path3) === null) {
117638
+ log10.warn(
117639
+ "CI poll: getRepoInfo returned null for %s despite hasOrigin=true; will reconcile on next sync tick",
117640
+ path3
117641
+ );
117642
+ }
117643
+ }
117644
+ const resolved = [];
117645
+ for (const [index3, ws] of workspaces.entries()) {
117646
+ const repoInfo = repoInfoByPath.get(ws.projectPath);
117647
+ if (repoInfo) {
117648
+ resolved.push({ ws, repoInfo, alias: `ws_${index3}` });
117649
+ }
117650
+ }
117598
117651
  if (resolved.length === 0) {
117599
117652
  const results = /* @__PURE__ */ new Map();
117600
117653
  for (const ws of workspaces) {
@@ -117676,7 +117729,10 @@ async function pollTick() {
117676
117729
  const db2 = getDb();
117677
117730
  let ciStatuses = /* @__PURE__ */ new Map();
117678
117731
  if (isCITick) {
117679
- ciStatuses = await getBatchedCIStatuses(workspaces);
117732
+ const ciWorkspaces = workspaces.filter((w2) => w2.hasOrigin);
117733
+ if (ciWorkspaces.length > 0) {
117734
+ ciStatuses = await getBatchedCIStatuses(ciWorkspaces);
117735
+ }
117680
117736
  }
117681
117737
  await Promise.allSettled(
117682
117738
  workspaces.map(async (ws) => {
@@ -117880,7 +117936,7 @@ function subscribe(listener) {
117880
117936
  }
117881
117937
 
117882
117938
  // src/lib/chat-manager.ts
117883
- var log9 = createLogger("chat-manager");
117939
+ var log11 = createLogger("chat-manager");
117884
117940
  var PANEL_TYPE = "chat";
117885
117941
  var chatSessions = /* @__PURE__ */ new Map();
117886
117942
  var workspaceChats = /* @__PURE__ */ new Map();
@@ -117951,7 +118007,7 @@ function createChat(workspaceId, options2) {
117951
118007
  addToIndex(session);
117952
118008
  addChatToLayout(workspaceId, session.id, { title: session.name });
117953
118009
  emit({ kind: "chat-created", workspaceId, chatId: session.id });
117954
- log9.info({ chatId: session.id, workspaceId, agent: session.agent }, "chat pane created");
118010
+ log11.info({ chatId: session.id, workspaceId, agent: session.agent }, "chat pane created");
117955
118011
  return session;
117956
118012
  }
117957
118013
  function getChat(chatId) {
@@ -117980,7 +118036,7 @@ function updateChat(chatId, updates) {
117980
118036
  state: serializeState(session),
117981
118037
  updatedAt: Date.now()
117982
118038
  });
117983
- log9.info({ chatId, updates }, "chat pane updated");
118039
+ log11.info({ chatId, updates }, "chat pane updated");
117984
118040
  return session;
117985
118041
  }
117986
118042
  function updateChatStatus(chatId, status) {
@@ -118032,7 +118088,7 @@ function removeChat(chatId) {
118032
118088
  removeChatFromLayout(session.workspaceId, chatId);
118033
118089
  removeFromIndex(chatId);
118034
118090
  emit({ kind: "chat-removed", workspaceId: session.workspaceId, chatId });
118035
- log9.info({ chatId, workspaceId: session.workspaceId }, "chat pane removed");
118091
+ log11.info({ chatId, workspaceId: session.workspaceId }, "chat pane removed");
118036
118092
  return true;
118037
118093
  }
118038
118094
  function removeWorkspaceChats(workspaceId) {
@@ -118044,7 +118100,7 @@ function removeWorkspaceChats(workspaceId) {
118044
118100
  }
118045
118101
  deletePanelStatesForWorkspace(workspaceId, PANEL_TYPE);
118046
118102
  workspaceChats.delete(workspaceId);
118047
- log9.info({ workspaceId }, "all chat panes removed for workspace");
118103
+ log11.info({ workspaceId }, "all chat panes removed for workspace");
118048
118104
  }
118049
118105
  function loadChatsFromDb() {
118050
118106
  _initialized = true;
@@ -118072,7 +118128,7 @@ function loadChatsFromDb() {
118072
118128
  addToIndex(session);
118073
118129
  }
118074
118130
  if (rows.length > 0) {
118075
- log9.info({ count: rows.length }, "loaded chat panes from database");
118131
+ log11.info({ count: rows.length }, "loaded chat panes from database");
118076
118132
  }
118077
118133
  return rows.length;
118078
118134
  }
@@ -118090,8 +118146,82 @@ function getOrCreateDefaultChat(workspaceId) {
118090
118146
  return createChat(workspaceId, { name: "Chat" });
118091
118147
  }
118092
118148
 
118149
+ // src/lib/jsonl-message-to-events.ts
118150
+ function stripFileSharingHint(text3) {
118151
+ return text3.replace(/\n\n\[File sharing:[\s\S]*?\]\s*$/, "");
118152
+ }
118153
+ function jsonlMessageToEvents(msg, startId) {
118154
+ const events = [];
118155
+ let id = startId;
118156
+ if (msg.role === "user") {
118157
+ let textBuf = "";
118158
+ let hasText = false;
118159
+ for (const part of msg.content) {
118160
+ if (part.type === "text") {
118161
+ hasText = true;
118162
+ textBuf += part.text;
118163
+ } else if (part.type === "tool_result") {
118164
+ events.push({
118165
+ type: "tool-output-available",
118166
+ toolCallId: part.toolCallId,
118167
+ output: part.output,
118168
+ isError: part.isError,
118169
+ eventId: id++
118170
+ });
118171
+ }
118172
+ }
118173
+ if (hasText) {
118174
+ events.push({
118175
+ type: "user-message",
118176
+ text: stripFileSharingHint(textBuf),
118177
+ eventId: id++
118178
+ });
118179
+ }
118180
+ return events;
118181
+ }
118182
+ for (const part of msg.content) {
118183
+ if (part.type === "text") {
118184
+ const textPartId = `${msg.id}-text-${id}`;
118185
+ events.push({ type: "text-start", id: textPartId, eventId: id++ });
118186
+ events.push({ type: "text-delta", id: textPartId, delta: part.text, eventId: id++ });
118187
+ events.push({ type: "text-end", id: textPartId, eventId: id++ });
118188
+ } else if (part.type === "tool_use") {
118189
+ events.push({
118190
+ type: "tool-input-available",
118191
+ toolCallId: part.toolCallId,
118192
+ toolName: part.toolName,
118193
+ displayTitle: part.displayTitle,
118194
+ input: part.input,
118195
+ eventId: id++
118196
+ });
118197
+ } else if (part.type === "tool_result") {
118198
+ events.push({
118199
+ type: "tool-output-available",
118200
+ toolCallId: part.toolCallId,
118201
+ output: part.output,
118202
+ isError: part.isError,
118203
+ eventId: id++
118204
+ });
118205
+ }
118206
+ }
118207
+ return events;
118208
+ }
118209
+
118093
118210
  // src/lib/queued-message-store.ts
118094
118211
  import { randomUUID } from "node:crypto";
118212
+ function toWireQueuedMessages(messages) {
118213
+ return messages.map((m11) => ({
118214
+ id: m11.id,
118215
+ text: m11.text,
118216
+ ...m11.files && m11.files.length > 0 && {
118217
+ files: m11.files.map((f10) => ({
118218
+ mediaType: f10.mediaType,
118219
+ url: f10.url,
118220
+ ...f10.filename !== void 0 && { filename: f10.filename }
118221
+ }))
118222
+ }
118223
+ }));
118224
+ }
118095
118225
  var QUEUED_KEY = Symbol.for("band.queued-messages");
118096
118226
  var LISTENERS_KEY = Symbol.for("band.queued-messages.listeners");
118097
118227
  var g10 = globalThis;
@@ -118187,7 +118317,7 @@ function clearQueuedMessages(chatId) {
118187
118317
  // src/lib/task-runner.ts
118188
118318
  init_src();
118189
118319
  import { mkdirSync as mkdirSync4, readdirSync as readdirSync6 } from "node:fs";
118190
- import { join as join16 } from "node:path";
118320
+ import { join as join15 } from "node:path";
118191
118321
 
118192
118322
  // src/lib/mime-types.ts
118193
118323
  import { extname } from "node:path";
@@ -118252,7 +118382,7 @@ function hasPendingInputForWorkspace(workspaceId) {
118252
118382
 
118253
118383
  // src/lib/task-store.ts
118254
118384
  init_src();
118255
- var log10 = createLogger("task-store");
118385
+ var log12 = createLogger("task-store");
118256
118386
  function generateTaskId() {
118257
118387
  return `tsk_${Date.now()}`;
118258
118388
  }
@@ -118325,7 +118455,7 @@ function cleanupStaleTasks() {
118325
118455
  const result = db2.update(tasks).set({ status: "failed", completedAt: now }).where(eq2(tasks.status, "running")).run();
118326
118456
  const count3 = result.changes;
118327
118457
  if (count3 > 0) {
118328
- log10.info({ count: count3 }, "cleaned up stale tasks on startup");
118458
+ log12.info({ count: count3 }, "cleaned up stale tasks on startup");
118329
118459
  }
118330
118460
  return count3;
118331
118461
  }
@@ -118362,7 +118492,7 @@ function pruneOldTasks(retentionMs = TASK_RETENTION_MS) {
118362
118492
  const cutoff = Date.now() - retentionMs;
118363
118493
  const count3 = deleteTasksOlderThan(cutoff);
118364
118494
  if (count3 > 0) {
118365
- log10.info({ count: count3, retentionMs }, "pruned tasks older than retention window");
118495
+ log12.info({ count: count3, retentionMs }, "pruned tasks older than retention window");
118366
118496
  }
118367
118497
  return count3;
118368
118498
  }
@@ -118373,13 +118503,13 @@ function startTaskPruneScheduler(options2 = {}) {
118373
118503
  try {
118374
118504
  pruneOldTasks(retentionMs);
118375
118505
  } catch (err) {
118376
- log10.error({ err }, "initial task prune on boot failed");
118506
+ log12.error({ err }, "initial task prune on boot failed");
118377
118507
  }
118378
118508
  const timer = setInterval(() => {
118379
118509
  try {
118380
118510
  pruneOldTasks(retentionMs);
118381
118511
  } catch (err) {
118382
- log10.error({ err }, "scheduled task prune failed");
118512
+ log12.error({ err }, "scheduled task prune failed");
118383
118513
  }
118384
118514
  }, intervalMs);
118385
118515
  timer.unref();
@@ -118420,38 +118550,6 @@ function rowToRecord(row) {
118420
118550
  };
118421
118551
  }
118422
118552
 
118423
- // src/lib/upload-utils.ts
118424
- import { mkdir, writeFile } from "node:fs/promises";
118425
- import { join as join15 } from "node:path";
118426
- async function saveUploadedFilesDetailed(fileParts) {
118427
- const uploadDir = join15(bandHome(), "uploads");
118428
- await mkdir(uploadDir, { recursive: true });
118429
- const baseTimestamp = Date.now();
118430
- const saved = [];
118431
- for (let i2 = 0; i2 < fileParts.length; i2++) {
118432
- const part = fileParts[i2];
118433
- const dataUrlMatch = part.url.match(/^data:[^;]+;base64,(.+)$/);
118434
- if (!dataUrlMatch) continue;
118435
- const buffer = Buffer.from(dataUrlMatch[1], "base64");
118436
- const filename = part.filename || `file-${baseTimestamp}`;
118437
- const safeOriginal = filename.replace(/[^a-zA-Z0-9._-]/g, "_");
118438
- const storedName = `${baseTimestamp}-${i2}-${safeOriginal}`;
118439
- const filePath = join15(uploadDir, storedName);
118440
- await writeFile(filePath, buffer);
118441
- saved.push({
118442
- path: filePath,
118443
- storedName,
118444
- mediaType: part.mediaType,
118445
- originalName: part.filename
118446
- });
118447
- }
118448
- return saved;
118449
- }
118450
- async function saveUploadedFiles(fileParts) {
118451
- const saved = await saveUploadedFilesDetailed(fileParts);
118452
- return saved.map((f10) => f10.path);
118453
- }
118454
-
118455
118553
  // src/lib/workspace.ts
118456
118554
  function resolveWorkspace(workspaceId) {
118457
118555
  const state2 = loadState();
@@ -118466,7 +118564,7 @@ function resolveWorkspace(workspaceId) {
118466
118564
  }
118467
118565
 
118468
118566
  // src/lib/task-runner.ts
118469
- var log11 = createLogger("task-runner");
118567
+ var log13 = createLogger("task-runner");
118470
118568
  function listFiles(dir) {
118471
118569
  try {
118472
118570
  return new Set(readdirSync6(dir));
@@ -118525,7 +118623,7 @@ function persistTask(task) {
118525
118623
  chatId: task.chatId
118526
118624
  });
118527
118625
  } catch (err) {
118528
- log11.warn({ err, taskId: task.taskRecordId }, "failed to persist task");
118626
+ log13.warn({ err, taskId: task.taskRecordId }, "failed to persist task");
118529
118627
  }
118530
118628
  }
118531
118629
  function broadcast(chatId, chunk) {
@@ -118549,7 +118647,7 @@ function broadcast(chatId, chunk) {
118549
118647
  }
118550
118648
  const subs = listeners2.get(chatId);
118551
118649
  if (!subs || subs.size === 0) {
118552
- log11.warn({ chatId, chunkType: chunk.type }, "broadcast: no listeners");
118650
+ log13.warn({ chatId, chunkType: chunk.type }, "broadcast: no listeners");
118553
118651
  return;
118554
118652
  }
118555
118653
  for (const listener of subs) {
@@ -118615,7 +118713,7 @@ function submitTask(options2) {
118615
118713
  });
118616
118714
  }
118617
118715
  runTask(chatId, task).catch((err) => {
118618
- log11.error({ chatId, err }, "task execution failed");
118716
+ log13.error({ chatId, err }, "task execution failed");
118619
118717
  if (task.status === "running") {
118620
118718
  task.status = "failed";
118621
118719
  task.completedAt = Date.now();
@@ -118657,7 +118755,7 @@ function abortTask(chatId) {
118657
118755
  updateChatStatus(chatId, "idle");
118658
118756
  const updated = upsertWorkspaceStatus(task.workspaceId, { status: "waiting" });
118659
118757
  emit({ kind: "update", status: updated });
118660
- log11.info({ chatId }, "task aborted by user");
118758
+ log13.info({ chatId }, "task aborted by user");
118661
118759
  return true;
118662
118760
  }
118663
118761
  function cancelTask(taskId) {
@@ -118682,7 +118780,7 @@ function cancelTask(taskId) {
118682
118780
  updateChatStatus(chatId, "idle");
118683
118781
  const updated = upsertWorkspaceStatus(task.workspaceId, { status: "waiting" });
118684
118782
  emit({ kind: "update", status: updated });
118685
- log11.info({ chatId, taskId }, "task cancelled (was running in-memory)");
118783
+ log13.info({ chatId, taskId }, "task cancelled (was running in-memory)");
118686
118784
  return { cancelled: true, workspaceId: task.workspaceId };
118687
118785
  }
118688
118786
  }
@@ -118690,7 +118788,7 @@ function cancelTask(taskId) {
118690
118788
  if (record2) {
118691
118789
  const updated = upsertWorkspaceStatus(record2.workspaceId, { status: "waiting" });
118692
118790
  emit({ kind: "update", status: updated });
118693
- log11.info({ taskId, workspaceId: record2.workspaceId }, "orphaned task cancelled");
118791
+ log13.info({ taskId, workspaceId: record2.workspaceId }, "orphaned task cancelled");
118694
118792
  return { cancelled: true, workspaceId: record2.workspaceId };
118695
118793
  }
118696
118794
  return { cancelled: false };
@@ -118710,7 +118808,7 @@ async function runTask(chatId, task) {
118710
118808
  const taskAgentId = task.codingAgentId;
118711
118809
  const resolvedAgentId = taskAgentId ?? chatSession?.agent;
118712
118810
  const needsReplace = taskAgentId && taskAgentId !== chatSession?.agent;
118713
- log11.info(
118811
+ log13.info(
118714
118812
  { chatId, taskAgentId, chatAgent: chatSession?.agent, resolvedAgentId, needsReplace },
118715
118813
  "resolving agent for task"
118716
118814
  );
@@ -118718,7 +118816,7 @@ async function runTask(chatId, task) {
118718
118816
  updateChatStatus(chatId, "running");
118719
118817
  const working = upsertWorkspaceStatus(task.workspaceId, { status: "working" });
118720
118818
  emit({ kind: "update", status: working });
118721
- const sharedDir = join16(bandHome(), "shared", task.workspaceId);
118819
+ const sharedDir = join15(bandHome(), "shared", task.workspaceId);
118722
118820
  mkdirSync4(sharedDir, { recursive: true });
118723
118821
  const INTERACTIVE_TOOLS = /* @__PURE__ */ new Set(["AskUserQuestion", "ExitPlanMode"]);
118724
118822
  let textPartId = "";
@@ -118759,7 +118857,7 @@ async function runTask(chatId, task) {
118759
118857
  [File sharing: to send a file to the user, write or copy it to ${sharedDir}/ and it will appear as a downloadable file card in the chat.]`;
118760
118858
  const effectivePrompt = task.sessionId ? task.agentPrompt : task.agentPrompt + fileSharingHint;
118761
118859
  for await (const event of agent.runSession(effectivePrompt, task.sessionId, sessionOptions)) {
118762
- log11.info({ chatId, eventType: event.type }, "task event");
118860
+ log13.info({ chatId, eventType: event.type }, "task event");
118763
118861
  switch (event.type) {
118764
118862
  case "session-start": {
118765
118863
  task.sessionId = event.sessionId;
@@ -118959,7 +119057,7 @@ async function runTask(chatId, task) {
118959
119057
  break;
118960
119058
  }
118961
119059
  case "session-id-resolved": {
118962
- log11.info(
119060
+ log13.info(
118963
119061
  { chatId, previous: event.previousSessionId, resolved: event.resolvedSessionId },
118964
119062
  "session ID resolved"
118965
119063
  );
@@ -119030,17 +119128,17 @@ async function runTask(chatId, task) {
119030
119128
  let agentPrompt;
119031
119129
  let displayFiles;
119032
119130
  if (queued.files && queued.files.length > 0) {
119033
- const saved = await saveUploadedFilesDetailed(queued.files);
119034
- if (saved.length > 0) {
119035
- const fileList = saved.map((s6) => `- ${s6.path}`).join("\n");
119131
+ const usableFiles = queued.files.filter((f10) => f10.path);
119132
+ if (usableFiles.length > 0) {
119133
+ const fileList = usableFiles.map((f10) => `- ${f10.path}`).join("\n");
119036
119134
  agentPrompt = `I'm sharing these files with you:
119037
119135
  ${fileList}
119038
119136
 
119039
119137
  ${queued.text}`;
119040
- displayFiles = saved.map((s6) => ({
119041
- mediaType: s6.mediaType,
119042
- url: `/api/uploads/${s6.storedName}`,
119043
- filename: s6.originalName
119138
+ displayFiles = usableFiles.map((f10) => ({
119139
+ mediaType: f10.mediaType,
119140
+ url: f10.url,
119141
+ filename: f10.filename
119044
119142
  }));
119045
119143
  }
119046
119144
  }
@@ -119054,7 +119152,7 @@ ${queued.text}`;
119054
119152
  });
119055
119153
  autoStarted = true;
119056
119154
  } catch (err) {
119057
- log11.warn({ chatId, err }, "failed to auto-start queued task");
119155
+ log13.warn({ chatId, err }, "failed to auto-start queued task");
119058
119156
  }
119059
119157
  }
119060
119158
  }
@@ -119207,7 +119305,7 @@ function openSseStream(res) {
119207
119305
  }
119208
119306
 
119209
119307
  // src/api/chat-events.ts
119210
- var log12 = createLogger("chat-events");
119308
+ var log14 = createLogger("chat-events");
119211
119309
  async function handleChatEvents(req, res, chatId) {
119212
119310
  const url = new URL(req.url, `http://${req.headers.host}`);
119213
119311
  const lastEventIdHeader = req.headers["last-event-id"];
@@ -119229,7 +119327,7 @@ async function handleChatEvents(req, res, chatId) {
119229
119327
  });
119230
119328
  emit2(writer, {
119231
119329
  type: "queue-updated",
119232
- messages: getQueuedMessages(chatId),
119330
+ messages: toWireQueuedMessages(getQueuedMessages(chatId)),
119233
119331
  eventId: nextSyntheticId--
119234
119332
  });
119235
119333
  if (resolvedSessionId) {
@@ -119270,7 +119368,7 @@ async function handleChatEvents(req, res, chatId) {
119270
119368
  if (qChatId !== chatId) return;
119271
119369
  queue.push({
119272
119370
  type: "queue-updated",
119273
- messages,
119371
+ messages: toWireQueuedMessages(messages),
119274
119372
  eventId: nextSyntheticId--
119275
119373
  });
119276
119374
  notify2?.();
@@ -119287,7 +119385,7 @@ async function handleChatEvents(req, res, chatId) {
119287
119385
  chatWorkspaceId: chat?.workspaceId ?? explicitWorkspaceId,
119288
119386
  agentTypeHint: chat?.agent
119289
119387
  }).catch((err) => {
119290
- log12.warn({ chatId, err }, "replay phase failed; continuing to live tail");
119388
+ log14.warn({ chatId, err }, "replay phase failed; continuing to live tail");
119291
119389
  });
119292
119390
  try {
119293
119391
  while (!res.destroyed && !writer.closed) {
@@ -119346,7 +119444,7 @@ async function replayPast(opts) {
119346
119444
  }
119347
119445
  }
119348
119446
  } catch (err) {
119349
- log12.warn({ chatId, sessionId, err }, "JSONL backfill failed; falling through to buffer");
119447
+ log14.warn({ chatId, sessionId, err }, "JSONL backfill failed; falling through to buffer");
119350
119448
  }
119351
119449
  }
119352
119450
  if (!jsonlEmittedAny && buf) {
@@ -119380,7 +119478,7 @@ async function replayPast(opts) {
119380
119478
  }
119381
119479
  }
119382
119480
  } catch (err) {
119383
- log12.warn({ chatId, sessionId, err }, "JSONL backfill failed; falling through to buffer");
119481
+ log14.warn({ chatId, sessionId, err }, "JSONL backfill failed; falling through to buffer");
119384
119482
  }
119385
119483
  }
119386
119484
  if (buf) {
@@ -119393,50 +119491,6 @@ async function replayPast(opts) {
119393
119491
  }
119394
119492
  }
119395
119493
  }
119396
- function stripFileSharingHint(text3) {
119397
- return text3.replace(/\n\n\[File sharing:[\s\S]*?\]\s*$/, "");
119398
- }
119399
- function jsonlMessageToEvents(msg, startId) {
119400
- const events = [];
119401
- let id = startId;
119402
- if (msg.role === "user") {
119403
- const textPart = msg.content.find(
119404
- (p6) => p6.type === "text"
119405
- );
119406
- events.push({
119407
- type: "user-message",
119408
- text: stripFileSharingHint(textPart?.text ?? ""),
119409
- eventId: id++
119410
- });
119411
- return events;
119412
- }
119413
- for (const part of msg.content) {
119414
- if (part.type === "text") {
119415
- const textPartId = `${msg.id}-text-${id}`;
119416
- events.push({ type: "text-start", id: textPartId, eventId: id++ });
119417
- events.push({ type: "text-delta", id: textPartId, delta: part.text, eventId: id++ });
119418
- events.push({ type: "text-end", id: textPartId, eventId: id++ });
119419
- } else if (part.type === "tool_use") {
119420
- events.push({
119421
- type: "tool-input-available",
119422
- toolCallId: part.toolCallId,
119423
- toolName: part.toolName,
119424
- displayTitle: part.displayTitle,
119425
- input: part.input,
119426
- eventId: id++
119427
- });
119428
- } else if (part.type === "tool_result") {
119429
- events.push({
119430
- type: "tool-output-available",
119431
- toolCallId: part.toolCallId,
119432
- output: part.output,
119433
- isError: part.isError,
119434
- eventId: id++
119435
- });
119436
- }
119437
- }
119438
- return events;
119439
- }
119440
119494
  function chunkToChatEvent(chunk, _sessionId) {
119441
119495
  const c2 = chunk;
119442
119496
  switch (c2.type) {
@@ -119532,7 +119586,41 @@ function chunkToChatEvent(chunk, _sessionId) {
119532
119586
 
119533
119587
  // src/api/chat-submit.ts
119534
119588
  init_src();
119535
- var log13 = createLogger("chat-submit");
119589
+
119590
+ // src/lib/upload-utils.ts
119591
+ import { mkdir, writeFile } from "node:fs/promises";
119592
+ import { join as join16 } from "node:path";
119593
+ async function saveUploadedFilesDetailed(fileParts) {
119594
+ const uploadDir = join16(bandHome(), "uploads");
119595
+ await mkdir(uploadDir, { recursive: true });
119596
+ const baseTimestamp = Date.now();
119597
+ const saved = [];
119598
+ for (let i2 = 0; i2 < fileParts.length; i2++) {
119599
+ const part = fileParts[i2];
119600
+ const dataUrlMatch = part.url.match(/^data:[^;]+;base64,(.+)$/);
119601
+ if (!dataUrlMatch) continue;
119602
+ const buffer = Buffer.from(dataUrlMatch[1], "base64");
119603
+ const filename = part.filename || `file-${baseTimestamp}`;
119604
+ const safeOriginal = filename.replace(/[^a-zA-Z0-9._-]/g, "_");
119605
+ const storedName = `${baseTimestamp}-${i2}-${safeOriginal}`;
119606
+ const filePath = join16(uploadDir, storedName);
119607
+ await writeFile(filePath, buffer);
119608
+ saved.push({
119609
+ path: filePath,
119610
+ storedName,
119611
+ mediaType: part.mediaType,
119612
+ originalName: part.filename
119613
+ });
119614
+ }
119615
+ return saved;
119616
+ }
119617
+ async function saveUploadedFiles(fileParts) {
119618
+ const saved = await saveUploadedFilesDetailed(fileParts);
119619
+ return saved.map((f10) => f10.path);
119620
+ }
119621
+
119622
+ // src/api/chat-submit.ts
119623
+ var log15 = createLogger("chat-submit");
119536
119624
  function readBody(req) {
119537
119625
  return new Promise((resolve7, reject) => {
119538
119626
  const chunks = [];
@@ -119565,15 +119653,22 @@ async function handleChatSubmit(req, res, chatId) {
119565
119653
  const resumeSessionId = sessionId ?? getChat(chatId)?.activeSessionId;
119566
119654
  let agentPrompt;
119567
119655
  let displayFiles;
119656
+ let savedFiles = [];
119568
119657
  if (files && files.length > 0) {
119569
- const saved = await saveUploadedFilesDetailed(files);
119570
- if (saved.length > 0) {
119571
- const fileList = saved.map((s6) => `- ${s6.path}`).join("\n");
119658
+ savedFiles = await saveUploadedFilesDetailed(files);
119659
+ if (savedFiles.length !== files.length) {
119660
+ log15.warn(
119661
+ { chatId, submitted: files.length, saved: savedFiles.length },
119662
+ "chat-submit: some file uploads were dropped (malformed data URL?)"
119663
+ );
119664
+ }
119665
+ if (savedFiles.length > 0) {
119666
+ const fileList = savedFiles.map((s6) => `- ${s6.path}`).join("\n");
119572
119667
  agentPrompt = `I'm sharing these files with you:
119573
119668
  ${fileList}
119574
119669
 
119575
119670
  ${text3}`;
119576
- displayFiles = saved.map((s6) => ({
119671
+ displayFiles = savedFiles.map((s6) => ({
119577
119672
  mediaType: s6.mediaType,
119578
119673
  url: `/api/uploads/${s6.storedName}`,
119579
119674
  filename: s6.originalName
@@ -119593,15 +119688,22 @@ ${text3}`;
119593
119688
  model,
119594
119689
  codingAgentId
119595
119690
  });
119596
- log13.info({ chatId, workspaceId }, "chat-submit: task started");
119691
+ log15.info({ chatId, workspaceId }, "chat-submit: task started");
119597
119692
  sendJson(res, 200, { ok: true, queued: false });
119598
119693
  } catch (err) {
119599
119694
  if (err instanceof TaskConflictError) {
119600
119695
  pushQueuedMessage(chatId, {
119601
119696
  text: text3,
119602
- ...displayFiles && displayFiles.length > 0 && { files: displayFiles }
119697
+ ...savedFiles.length > 0 && {
119698
+ files: savedFiles.map((s6) => ({
119699
+ mediaType: s6.mediaType,
119700
+ url: `/api/uploads/${s6.storedName}`,
119701
+ path: s6.path,
119702
+ filename: s6.originalName
119703
+ }))
119704
+ }
119603
119705
  });
119604
- log13.info({ chatId, workspaceId }, "chat-submit: task busy, message queued");
119706
+ log15.info({ chatId, workspaceId }, "chat-submit: task busy, message queued");
119605
119707
  sendJson(res, 200, { ok: true, queued: true });
119606
119708
  return;
119607
119709
  }
@@ -119609,7 +119711,7 @@ ${text3}`;
119609
119711
  sendJson(res, 404, { error: err.message });
119610
119712
  return;
119611
119713
  }
119612
- log13.error({ chatId, err }, "chat-submit: unexpected error");
119714
+ log15.error({ chatId, err }, "chat-submit: unexpected error");
119613
119715
  sendJson(res, 500, { error: "Internal server error" });
119614
119716
  }
119615
119717
  }
@@ -119643,7 +119745,7 @@ function removeBrowserFromLayout(workspaceId, browserId) {
119643
119745
  }
119644
119746
 
119645
119747
  // src/lib/browser-manager.ts
119646
- var log14 = createLogger("browser-manager");
119748
+ var log16 = createLogger("browser-manager");
119647
119749
  var PANEL_TYPE2 = "browser";
119648
119750
  var browserTabs = /* @__PURE__ */ new Map();
119649
119751
  var workspaceBrowsers = /* @__PURE__ */ new Map();
@@ -119704,7 +119806,7 @@ function createBrowser(workspaceId, options2) {
119704
119806
  title: tab.name,
119705
119807
  initialUrl: tab.url || void 0
119706
119808
  });
119707
- log14.info({ browserId: tab.id, workspaceId, url: tab.url }, "browser tab created");
119809
+ log16.info({ browserId: tab.id, workspaceId, url: tab.url }, "browser tab created");
119708
119810
  return tab;
119709
119811
  }
119710
119812
  function getBrowser(browserId) {
@@ -119731,7 +119833,7 @@ function updateBrowser(browserId, updates) {
119731
119833
  state: serializeState2(tab),
119732
119834
  updatedAt: Date.now()
119733
119835
  });
119734
- log14.info({ browserId, updates }, "browser tab updated");
119836
+ log16.info({ browserId, updates }, "browser tab updated");
119735
119837
  return tab;
119736
119838
  }
119737
119839
  function updateBrowserUrl(browserId, url) {
@@ -119748,7 +119850,7 @@ function removeBrowser(browserId) {
119748
119850
  if (!tab) return false;
119749
119851
  deletePanelState(browserId);
119750
119852
  removeFromIndex2(browserId);
119751
- log14.info({ browserId, workspaceId: tab.workspaceId }, "browser tab removed");
119853
+ log16.info({ browserId, workspaceId: tab.workspaceId }, "browser tab removed");
119752
119854
  return true;
119753
119855
  }
119754
119856
  function removeWorkspaceBrowsers(workspaceId) {
@@ -119759,7 +119861,7 @@ function removeWorkspaceBrowsers(workspaceId) {
119759
119861
  }
119760
119862
  deletePanelStatesForWorkspace(workspaceId, PANEL_TYPE2);
119761
119863
  workspaceBrowsers.delete(workspaceId);
119762
- log14.info({ workspaceId }, "all browser tabs removed for workspace");
119864
+ log16.info({ workspaceId }, "all browser tabs removed for workspace");
119763
119865
  }
119764
119866
  function loadBrowsersFromDb() {
119765
119867
  _initialized2 = true;
@@ -119778,13 +119880,13 @@ function loadBrowsersFromDb() {
119778
119880
  addToIndex2(tab);
119779
119881
  }
119780
119882
  if (rows.length > 0) {
119781
- log14.info({ count: rows.length }, "loaded browser tabs from database");
119883
+ log16.info({ count: rows.length }, "loaded browser tabs from database");
119782
119884
  }
119783
119885
  return rows.length;
119784
119886
  }
119785
119887
 
119786
119888
  // src/lib/browser-host.ts
119787
- var log15 = createLogger("browser-host");
119889
+ var log17 = createLogger("browser-host");
119788
119890
  var DESKTOP_CDP_HOST = "127.0.0.1";
119789
119891
  var DESKTOP_CDP_PORT = 9223;
119790
119892
  var globalAny = globalThis;
@@ -119835,7 +119937,7 @@ async function ensureCdpTargetId(bandTabId) {
119835
119937
  reject: rejectFn,
119836
119938
  timeoutId
119837
119939
  });
119838
- log15.info(
119940
+ log17.info(
119839
119941
  "ensureCdpTargetId emitting ensureView for %s (url=%s, listeners=%d)",
119840
119942
  bandTabId,
119841
119943
  tab.url,
@@ -119849,13 +119951,13 @@ async function ensureCdpTargetId(bandTabId) {
119849
119951
  url: tab.url
119850
119952
  });
119851
119953
  } catch (err) {
119852
- log15.warn("ensureView listener threw: %s", err instanceof Error ? err.message : err);
119954
+ log17.warn("ensureView listener threw: %s", err instanceof Error ? err.message : err);
119853
119955
  }
119854
119956
  }
119855
119957
  return promise;
119856
119958
  }
119857
119959
  function resolveTargetReady(bandTabId, cdpTargetId) {
119858
- log15.info("resolveTargetReady %s \u2192 %s", bandTabId, cdpTargetId);
119960
+ log17.info("resolveTargetReady %s \u2192 %s", bandTabId, cdpTargetId);
119859
119961
  targetIdByBandTabId.set(bandTabId, cdpTargetId);
119860
119962
  const pending2 = pendingEnsures.get(bandTabId);
119861
119963
  if (pending2) {
@@ -119865,7 +119967,7 @@ function resolveTargetReady(bandTabId, cdpTargetId) {
119865
119967
  }
119866
119968
  }
119867
119969
  function markTargetDestroyed(bandTabId) {
119868
- log15.info("markTargetDestroyed %s", bandTabId);
119970
+ log17.info("markTargetDestroyed %s", bandTabId);
119869
119971
  targetIdByBandTabId.delete(bandTabId);
119870
119972
  const pending2 = pendingEnsures.get(bandTabId);
119871
119973
  if (pending2) {
@@ -119876,10 +119978,10 @@ function markTargetDestroyed(bandTabId) {
119876
119978
  }
119877
119979
  function onEnsureView(listener) {
119878
119980
  ensureListeners.add(listener);
119879
- log15.info("onEnsureView subscriber added (total=%d)", ensureListeners.size);
119981
+ log17.info("onEnsureView subscriber added (total=%d)", ensureListeners.size);
119880
119982
  return () => {
119881
119983
  ensureListeners.delete(listener);
119882
- log15.info("onEnsureView subscriber removed (total=%d)", ensureListeners.size);
119984
+ log17.info("onEnsureView subscriber removed (total=%d)", ensureListeners.size);
119883
119985
  if (ensureListeners.size === 0) {
119884
119986
  for (const [bandTabId, pending2] of pendingEnsures) {
119885
119987
  clearTimeout(pending2.timeoutId);
@@ -119896,7 +119998,7 @@ function isDesktopHostConnected() {
119896
119998
 
119897
119999
  // src/lib/cdp-proxy.ts
119898
120000
  init_src();
119899
- var log16 = createLogger("cdp-proxy");
120001
+ var log18 = createLogger("cdp-proxy");
119900
120002
  async function handleCdpConnection(ws, req) {
119901
120003
  const url = new URL(req.url ?? "", `http://${req.headers.host}`);
119902
120004
  const bandTabId = url.searchParams.get("bandTabId");
@@ -119919,17 +120021,17 @@ async function handleCdpConnection(ws, req) {
119919
120021
  cdpTargetId = await ensureCdpTargetId(bandTabId);
119920
120022
  } catch (err) {
119921
120023
  const message = err instanceof Error ? err.message : String(err);
119922
- log16.debug("ensureCdpTargetId failed for %s: %s", bandTabId, message);
120024
+ log18.debug("ensureCdpTargetId failed for %s: %s", bandTabId, message);
119923
120025
  if (ws.readyState === ws.OPEN) {
119924
120026
  ws.close(4001, message.slice(0, 123));
119925
120027
  }
119926
120028
  return;
119927
120029
  }
119928
120030
  const upstreamUrl = `ws://${DESKTOP_CDP_HOST}:${DESKTOP_CDP_PORT}/devtools/page/${encodeURIComponent(cdpTargetId)}`;
119929
- log16.info("CDP proxy connecting bandTabId=%s upstream=%s", bandTabId, upstreamUrl);
120031
+ log18.info("CDP proxy connecting bandTabId=%s upstream=%s", bandTabId, upstreamUrl);
119930
120032
  upstream = new wrapper_default(upstreamUrl);
119931
120033
  upstream.on("open", () => {
119932
- log16.info("CDP upstream open bandTabId=%s pending=%d", bandTabId, pending2.length);
120034
+ log18.info("CDP upstream open bandTabId=%s pending=%d", bandTabId, pending2.length);
119933
120035
  for (const msg of pending2) {
119934
120036
  upstream?.send(msg);
119935
120037
  }
@@ -119941,20 +120043,20 @@ async function handleCdpConnection(ws, req) {
119941
120043
  }
119942
120044
  });
119943
120045
  upstream.on("error", (err) => {
119944
- log16.warn("CDP upstream error bandTabId=%s: %s", bandTabId, err.message);
120046
+ log18.warn("CDP upstream error bandTabId=%s: %s", bandTabId, err.message);
119945
120047
  markTargetDestroyed(bandTabId);
119946
120048
  if (ws.readyState === ws.OPEN) {
119947
120049
  ws.close(4001, `Desktop CDP error: ${err.message}`.slice(0, 123));
119948
120050
  }
119949
120051
  });
119950
120052
  upstream.on("close", (code) => {
119951
- log16.info("CDP upstream closed bandTabId=%s code=%d", bandTabId, code);
120053
+ log18.info("CDP upstream closed bandTabId=%s code=%d", bandTabId, code);
119952
120054
  if (ws.readyState === ws.OPEN) {
119953
120055
  ws.close(1e3, "Upstream closed");
119954
120056
  }
119955
120057
  });
119956
120058
  ws.on("close", () => {
119957
- log16.debug("CDP client closed bandTabId=%s", bandTabId);
120059
+ log18.debug("CDP client closed bandTabId=%s", bandTabId);
119958
120060
  if (upstream && (upstream.readyState === wrapper_default.OPEN || upstream.readyState === wrapper_default.CONNECTING)) {
119959
120061
  try {
119960
120062
  upstream.close();
@@ -119963,7 +120065,7 @@ async function handleCdpConnection(ws, req) {
119963
120065
  }
119964
120066
  });
119965
120067
  ws.on("error", (err) => {
119966
- log16.debug("CDP client error bandTabId=%s: %s", bandTabId, err.message);
120068
+ log18.debug("CDP client error bandTabId=%s: %s", bandTabId, err.message);
119967
120069
  try {
119968
120070
  upstream?.close();
119969
120071
  } catch {
@@ -119973,7 +120075,7 @@ async function handleCdpConnection(ws, req) {
119973
120075
 
119974
120076
  // src/lib/cdp-targets.ts
119975
120077
  init_src();
119976
- var log17 = createLogger("cdp-targets");
120078
+ var log19 = createLogger("cdp-targets");
119977
120079
  var CdpUnreachableError = class extends Error {
119978
120080
  constructor(message) {
119979
120081
  super(message);
@@ -120029,7 +120131,7 @@ async function captureSnapshot(bandTabId) {
120029
120131
  });
120030
120132
  ws.on("error", (err) => {
120031
120133
  clearTimeout(timeout);
120032
- log17.debug("captureSnapshot ws error for tab %s: %s", bandTabId, err.message);
120134
+ log19.debug("captureSnapshot ws error for tab %s: %s", bandTabId, err.message);
120033
120135
  markTargetDestroyed(bandTabId);
120034
120136
  settle(new CdpUnreachableError(err.message));
120035
120137
  });
@@ -120749,7 +120851,7 @@ function rowToDefinition(row) {
120749
120851
  }
120750
120852
 
120751
120853
  // src/lib/cronjob-scheduler.ts
120752
- var log18 = createLogger("cronjob-scheduler");
120854
+ var log20 = createLogger("cronjob-scheduler");
120753
120855
  var SCHEDULER_KEY = Symbol.for("band.cronjob-scheduler");
120754
120856
  var g14 = globalThis;
120755
120857
  if (!g14[SCHEDULER_KEY]) {
@@ -120769,16 +120871,16 @@ function scheduleJob(job, fileKey) {
120769
120871
  try {
120770
120872
  const cronInstance = new E2(job.cronExpression, () => {
120771
120873
  executeCronjob(job, fileKey).catch((err) => {
120772
- log18.error({ jobId: job.id, err }, "unhandled error in cronjob execution");
120874
+ log20.error({ jobId: job.id, err }, "unhandled error in cronjob execution");
120773
120875
  });
120774
120876
  });
120775
120877
  state.jobs.set(job.id, cronInstance);
120776
- log18.info(
120878
+ log20.info(
120777
120879
  { jobId: job.id, name: job.name, cron: job.cronExpression, scope: job.scope },
120778
120880
  "scheduled cronjob"
120779
120881
  );
120780
120882
  } catch (err) {
120781
- log18.error(
120883
+ log20.error(
120782
120884
  { jobId: job.id, cronExpression: job.cronExpression, err },
120783
120885
  "invalid cron expression, skipping job"
120784
120886
  );
@@ -120792,24 +120894,24 @@ async function executeCronjob(job, fileKey) {
120792
120894
  const appState = loadState();
120793
120895
  const project = appState.projects.find((p6) => p6.name === fileKey);
120794
120896
  if (!project) {
120795
- log18.warn({ jobId: job.id, fileKey }, "project not found for cronjob, skipping");
120897
+ log20.warn({ jobId: job.id, fileKey }, "project not found for cronjob, skipping");
120796
120898
  updateLastRun(job.id, "failed");
120797
120899
  return;
120798
120900
  }
120799
120901
  workspaceId = toWorkspaceId(project.name, project.defaultBranch);
120800
120902
  }
120801
- log18.info({ jobId: job.id, name: job.name, workspaceId }, "executing cronjob");
120903
+ log20.info({ jobId: job.id, name: job.name, workspaceId }, "executing cronjob");
120802
120904
  try {
120803
120905
  const chat = getOrCreateDefaultChat(workspaceId);
120804
120906
  submitTask({ workspaceId, chatId: chat.id, prompt: job.prompt });
120805
120907
  updateLastRun(job.id, "completed");
120806
120908
  } catch (err) {
120807
120909
  if (err instanceof TaskConflictError) {
120808
- log18.info({ jobId: job.id, workspaceId }, "task already running, skipping cronjob execution");
120910
+ log20.info({ jobId: job.id, workspaceId }, "task already running, skipping cronjob execution");
120809
120911
  updateLastRun(job.id, "skipped");
120810
120912
  return;
120811
120913
  }
120812
- log18.error({ jobId: job.id, err }, "cronjob execution failed");
120914
+ log20.error({ jobId: job.id, err }, "cronjob execution failed");
120813
120915
  updateLastRun(job.id, "failed");
120814
120916
  }
120815
120917
  }
@@ -120818,7 +120920,7 @@ function updateLastRun(jobId, status) {
120818
120920
  const db2 = getDb();
120819
120921
  db2.update(cronjobs).set({ lastRunAt: (/* @__PURE__ */ new Date()).toISOString(), lastRunStatus: status }).where(eq2(cronjobs.id, jobId)).run();
120820
120922
  } catch (err) {
120821
- log18.warn({ jobId, err }, "failed to update lastRun on cronjob");
120923
+ log20.warn({ jobId, err }, "failed to update lastRun on cronjob");
120822
120924
  }
120823
120925
  }
120824
120926
  function loadAndScheduleAll() {
@@ -120829,13 +120931,13 @@ function loadAndScheduleAll() {
120829
120931
  for (const job of listAllCronjobs()) {
120830
120932
  scheduleJob(job, job.fileKey);
120831
120933
  }
120832
- log18.info({ count: state.jobs.size }, "loaded cronjob schedules");
120934
+ log20.info({ count: state.jobs.size }, "loaded cronjob schedules");
120833
120935
  }
120834
120936
  function startCronjobScheduler() {
120835
120937
  if (state.started) return;
120836
120938
  state.started = true;
120837
120939
  loadAndScheduleAll();
120838
- log18.info("cronjob scheduler started");
120940
+ log20.info("cronjob scheduler started");
120839
120941
  }
120840
120942
  function stopCronjobScheduler() {
120841
120943
  for (const [, cron] of state.jobs) {
@@ -120843,7 +120945,7 @@ function stopCronjobScheduler() {
120843
120945
  }
120844
120946
  state.jobs.clear();
120845
120947
  state.started = false;
120846
- log18.info("cronjob scheduler stopped");
120948
+ log20.info("cronjob scheduler stopped");
120847
120949
  }
120848
120950
  function reloadSchedules() {
120849
120951
  if (!state.started) return;
@@ -120856,7 +120958,7 @@ function stopJobsForKey(key) {
120856
120958
  if (cron) {
120857
120959
  cron.stop();
120858
120960
  state.jobs.delete(job.id);
120859
- log18.info({ jobId: job.id, key }, "stopped cronjob");
120961
+ log20.info({ jobId: job.id, key }, "stopped cronjob");
120860
120962
  }
120861
120963
  }
120862
120964
  }
@@ -120922,7 +121024,7 @@ async function checkPrereqs() {
120922
121024
 
120923
121025
  // src/lib/lsp-manager.ts
120924
121026
  var __dirname2 = dirname2(fileURLToPath(import.meta.url));
120925
- var log19 = createLogger("lsp");
121027
+ var log21 = createLogger("lsp");
120926
121028
  var LANG_SERVER_CONFIG = {
120927
121029
  typescript: { command: "typescript-language-server", args: ["--stdio"] }
120928
121030
  };
@@ -120950,7 +121052,7 @@ async function getOrSpawnServer(workspaceId, lang) {
120950
121052
  const workspaceBin = join17(cwd, "node_modules/.bin");
120951
121053
  const pathSep = process.platform === "win32" ? ";" : ":";
120952
121054
  const combinedPath = [bundledBin, appBin, workspaceBin, resolvedPath].join(pathSep);
120953
- log19.debug("Spawning %s language server in %s for workspace %s", lang, cwd, workspaceId);
121055
+ log21.debug("Spawning %s language server in %s for workspace %s", lang, cwd, workspaceId);
120954
121056
  const child = spawn6(config2.command, config2.args, {
120955
121057
  cwd,
120956
121058
  stdio: ["pipe", "pipe", "pipe"],
@@ -120978,15 +121080,15 @@ async function getOrSpawnServer(workspaceId, lang) {
120978
121080
  }
120979
121081
  ids.add(serverId);
120980
121082
  child.on("exit", (code) => {
120981
- log19.debug("Language server exited: %s (code %s)", serverId, String(code));
121083
+ log21.debug("Language server exited: %s (code %s)", serverId, String(code));
120982
121084
  removeSession();
120983
121085
  });
120984
121086
  child.on("error", (err) => {
120985
- log19.error("Language server error: %s \u2014 %s", serverId, err.message);
121087
+ log21.error("Language server error: %s \u2014 %s", serverId, err.message);
120986
121088
  removeSession();
120987
121089
  });
120988
121090
  child.stderr?.on("data", (chunk) => {
120989
- log19.debug("LSP stderr [%s]: %s", serverId, chunk.toString().trimEnd());
121091
+ log21.debug("LSP stderr [%s]: %s", serverId, chunk.toString().trimEnd());
120990
121092
  });
120991
121093
  await new Promise((resolve7, reject) => {
120992
121094
  child.once("spawn", resolve7);
@@ -121016,7 +121118,7 @@ function killAllServers() {
121016
121118
 
121017
121119
  // src/lib/lsp-proxy.ts
121018
121120
  init_src();
121019
- var log20 = createLogger("lsp-proxy");
121121
+ var log22 = createLogger("lsp-proxy");
121020
121122
  function frameMessage(json2) {
121021
121123
  const body = Buffer.from(json2, "utf-8");
121022
121124
  const header = `Content-Length: ${body.byteLength}\r
@@ -121034,7 +121136,7 @@ function createFrameParser(onMessage) {
121034
121136
  const headerStr = buffer.subarray(0, separatorIdx).toString("ascii");
121035
121137
  const match = headerStr.match(/Content-Length:\s*(\d+)/i);
121036
121138
  if (!match) {
121037
- log20.warn("Malformed LSP header: %s", headerStr);
121139
+ log22.warn("Malformed LSP header: %s", headerStr);
121038
121140
  buffer = buffer.subarray(separatorIdx + 4);
121039
121141
  continue;
121040
121142
  }
@@ -121067,7 +121169,7 @@ async function handleLspConnection(ws, req) {
121067
121169
  session = await getOrSpawnServer(workspaceId, lang);
121068
121170
  } catch (err) {
121069
121171
  const message = err instanceof Error ? err.message : String(err);
121070
- log20.error(
121172
+ log22.error(
121071
121173
  "Failed to spawn %s language server for workspace %s: %s",
121072
121174
  lang,
121073
121175
  workspaceId,
@@ -121081,12 +121183,12 @@ async function handleLspConnection(ws, req) {
121081
121183
  ws.close(4002, "Language server stdio not available");
121082
121184
  return;
121083
121185
  }
121084
- log20.debug("LSP client connected: %s/%s", workspaceId, lang);
121186
+ log22.debug("LSP client connected: %s/%s", workspaceId, lang);
121085
121187
  const pendingRequests = /* @__PURE__ */ new Map();
121086
121188
  const retriedIds = /* @__PURE__ */ new Set();
121087
121189
  const RETRY_DELAY_MS = 2e3;
121088
121190
  const parseFrame = createFrameParser((json2) => {
121089
- log20.debug(
121191
+ log22.debug(
121090
121192
  "LSP stdout [%s/%s]: %s",
121091
121193
  workspaceId,
121092
121194
  lang,
@@ -121098,7 +121200,7 @@ async function handleLspConnection(ws, req) {
121098
121200
  const originalRequest = pendingRequests.get(msg.id);
121099
121201
  retriedIds.add(msg.id);
121100
121202
  pendingRequests.delete(msg.id);
121101
- log20.debug(
121203
+ log22.debug(
121102
121204
  "LSP retrying request %d after 'No Project' error [%s/%s]",
121103
121205
  msg.id,
121104
121206
  workspaceId,
@@ -121120,14 +121222,14 @@ async function handleLspConnection(ws, req) {
121120
121222
  const onStdoutData = (chunk) => parseFrame(chunk);
121121
121223
  lspProcess.stdout.on("data", onStdoutData);
121122
121224
  const onExit = (code) => {
121123
- log20.debug("LSP server exited (code %s), closing WebSocket", String(code));
121225
+ log22.debug("LSP server exited (code %s), closing WebSocket", String(code));
121124
121226
  if (ws.readyState === ws.OPEN) {
121125
121227
  ws.close(1e3, "Language server exited");
121126
121228
  }
121127
121229
  };
121128
121230
  lspProcess.on("exit", onExit);
121129
121231
  function forwardToStdin(json2) {
121130
- log20.debug(
121232
+ log22.debug(
121131
121233
  "LSP stdin [%s/%s]: %s",
121132
121234
  workspaceId,
121133
121235
  lang,
@@ -121154,7 +121256,7 @@ async function handleLspConnection(ws, req) {
121154
121256
  ws.on("close", () => {
121155
121257
  lspProcess.stdout?.off("data", onStdoutData);
121156
121258
  lspProcess.off("exit", onExit);
121157
- log20.debug("LSP client disconnected: %s/%s (server kept alive)", workspaceId, lang);
121259
+ log22.debug("LSP client disconnected: %s/%s (server kept alive)", workspaceId, lang);
121158
121260
  });
121159
121261
  }
121160
121262
 
@@ -121683,7 +121785,7 @@ async function installHooks() {
121683
121785
  }
121684
121786
 
121685
121787
  // src/lib/setup.ts
121686
- var log21 = createLogger("setup");
121788
+ var log23 = createLogger("setup");
121687
121789
  var AGENT_CHECKS = [
121688
121790
  { id: "claude-code", type: "claude-code", label: "Claude Code", binary: "claude" },
121689
121791
  { id: "codex", type: "codex", label: "Codex", binary: "codex" },
@@ -121700,7 +121802,7 @@ async function runFirstTimeSetup() {
121700
121802
  ]);
121701
121803
  for (const r6 of results) {
121702
121804
  if (r6.status === "rejected") {
121703
- log21.warn(
121805
+ log23.warn(
121704
121806
  "Setup step failed: %s",
121705
121807
  r6.reason instanceof Error ? r6.reason.message : String(r6.reason)
121706
121808
  );
@@ -121715,7 +121817,7 @@ async function ensureProjectStateInSync() {
121715
121817
  try {
121716
121818
  await syncWorktrees();
121717
121819
  } catch (err) {
121718
- log21.warn(
121820
+ log23.warn(
121719
121821
  "Failed to sync project state at boot: %s",
121720
121822
  err instanceof Error ? err.message : String(err)
121721
121823
  );
@@ -121726,22 +121828,22 @@ async function ensureCliInstalled() {
121726
121828
  try {
121727
121829
  cliStatus = await checkCli();
121728
121830
  } catch (err) {
121729
- log21.warn("Could not check CLI status: %s", err instanceof Error ? err.message : String(err));
121831
+ log23.warn("Could not check CLI status: %s", err instanceof Error ? err.message : String(err));
121730
121832
  return;
121731
121833
  }
121732
121834
  if (cliStatus === "Installed") {
121733
121835
  return;
121734
121836
  }
121735
121837
  if (cliStatus !== "NotInstalled") {
121736
- log21.warn("CLI not auto-installed (status: %s)", cliStatus);
121838
+ log23.warn("CLI not auto-installed (status: %s)", cliStatus);
121737
121839
  return;
121738
121840
  }
121739
- log21.info("Installing band CLI...");
121841
+ log23.info("Installing band CLI...");
121740
121842
  try {
121741
121843
  await installCli();
121742
- log21.info("CLI installed to /usr/local/bin/band");
121844
+ log23.info("CLI installed to /usr/local/bin/band");
121743
121845
  } catch (err) {
121744
- log21.warn("CLI installation failed: %s", err instanceof Error ? err.message : String(err));
121846
+ log23.warn("CLI installation failed: %s", err instanceof Error ? err.message : String(err));
121745
121847
  }
121746
121848
  }
121747
121849
  async function ensureDefaultCodingAgents() {
@@ -121750,17 +121852,17 @@ async function ensureDefaultCodingAgents() {
121750
121852
  if (Array.isArray(existing) && existing.length > 0) {
121751
121853
  return;
121752
121854
  }
121753
- log21.info("Detecting installed coding agents...");
121855
+ log23.info("Detecting installed coding agents...");
121754
121856
  const detected = [];
121755
121857
  for (const check2 of AGENT_CHECKS) {
121756
121858
  const path3 = await whichBinary(check2.binary);
121757
121859
  if (path3) {
121758
- log21.info("Detected coding agent: %s (%s)", check2.id, path3);
121860
+ log23.info("Detected coding agent: %s (%s)", check2.id, path3);
121759
121861
  detected.push({ id: check2.id, type: check2.type, label: check2.label });
121760
121862
  }
121761
121863
  }
121762
121864
  if (detected.length === 0) {
121763
- log21.info("No coding agent CLIs detected on PATH");
121865
+ log23.info("No coding agent CLIs detected on PATH");
121764
121866
  return;
121765
121867
  }
121766
121868
  const current = loadSettings();
@@ -121769,7 +121871,7 @@ async function ensureDefaultCodingAgents() {
121769
121871
  current.defaultCodingAgent = detected[0].id;
121770
121872
  }
121771
121873
  saveSettings(current);
121772
- log21.info("Enabled %d coding agent(s); default = %s", detected.length, current.defaultCodingAgent);
121874
+ log23.info("Enabled %d coding agent(s); default = %s", detected.length, current.defaultCodingAgent);
121773
121875
  }
121774
121876
  function ensureNotificationDefaults() {
121775
121877
  const settings = loadSettings();
@@ -121781,7 +121883,7 @@ function ensureNotificationDefaults() {
121781
121883
  ...settings,
121782
121884
  notifications: { ...notifications, soundOnNeedsAttention: true }
121783
121885
  });
121784
- log21.info("Set default notifications.soundOnNeedsAttention = true");
121886
+ log23.info("Set default notifications.soundOnNeedsAttention = true");
121785
121887
  }
121786
121888
  async function ensureClaudeHooks() {
121787
121889
  try {
@@ -121790,9 +121892,9 @@ async function ensureClaudeHooks() {
121790
121892
  return;
121791
121893
  }
121792
121894
  await installHooks();
121793
- log21.info("Installed Claude Code hooks");
121895
+ log23.info("Installed Claude Code hooks");
121794
121896
  } catch (err) {
121795
- log21.warn(
121897
+ log23.warn(
121796
121898
  "Failed to install Claude Code hooks: %s",
121797
121899
  err instanceof Error ? err.message : String(err)
121798
121900
  );
@@ -121800,11 +121902,11 @@ async function ensureClaudeHooks() {
121800
121902
  }
121801
121903
  async function ensureSkillsInstalled() {
121802
121904
  try {
121803
- const result = await installSkills({ log: log21 });
121905
+ const result = await installSkills({ log: log23 });
121804
121906
  const wrote = result.written.length + result.updated.length;
121805
121907
  const linkChange = result.linked.length;
121806
121908
  if (wrote > 0 || linkChange > 0 || result.conflicts.length > 0) {
121807
- log21.info(
121909
+ log23.info(
121808
121910
  "Synced CLI skills (shared: %d written, %d updated, %d unchanged; symlinks: %d created, %d already-linked, %d conflicts, %d skipped)",
121809
121911
  result.written.length,
121810
121912
  result.updated.length,
@@ -121816,7 +121918,7 @@ async function ensureSkillsInstalled() {
121816
121918
  );
121817
121919
  }
121818
121920
  } catch (err) {
121819
- log21.warn("Failed to sync CLI skills: %s", err instanceof Error ? err.message : String(err));
121921
+ log23.warn("Failed to sync CLI skills: %s", err instanceof Error ? err.message : String(err));
121820
121922
  }
121821
121923
  }
121822
121924
 
@@ -121850,7 +121952,7 @@ function removeTerminalFromLayout(workspaceId, terminalId) {
121850
121952
  }
121851
121953
 
121852
121954
  // src/lib/terminal-manager.ts
121853
- var log22 = createLogger("terminal");
121955
+ var log24 = createLogger("terminal");
121854
121956
  var MAX_SCROLLBACK_SIZE = 1e5;
121855
121957
  var terminals = /* @__PURE__ */ new Map();
121856
121958
  var workspaceTerminals = /* @__PURE__ */ new Map();
@@ -121881,11 +121983,11 @@ async function spawnTerminal(workspaceId, terminalId, options2) {
121881
121983
  if (options2?.cwd) {
121882
121984
  const resolved = join21(workspaceRoot, options2.cwd);
121883
121985
  if (!resolved.startsWith(workspaceRoot)) {
121884
- log22.warn("Ignoring cwd %s \u2014 resolves outside workspace root %s", options2.cwd, workspaceRoot);
121986
+ log24.warn("Ignoring cwd %s \u2014 resolves outside workspace root %s", options2.cwd, workspaceRoot);
121885
121987
  } else if (existsSync7(resolved)) {
121886
121988
  cwd = resolved;
121887
121989
  } else {
121888
- log22.warn("Ignoring cwd %s \u2014 directory does not exist", options2.cwd);
121990
+ log24.warn("Ignoring cwd %s \u2014 directory does not exist", options2.cwd);
121889
121991
  }
121890
121992
  }
121891
121993
  if (!existsSync7(cwd)) {
@@ -121894,7 +121996,7 @@ async function spawnTerminal(workspaceId, terminalId, options2) {
121894
121996
  if (!existsSync7(shell)) {
121895
121997
  throw new Error(`Shell not found: ${shell}`);
121896
121998
  }
121897
- log22.debug(
121999
+ log24.debug(
121898
122000
  "Spawning shell %s in %s for terminal %s (PATH=%s)",
121899
122001
  shell,
121900
122002
  cwd,
@@ -121913,7 +122015,7 @@ async function spawnTerminal(workspaceId, terminalId, options2) {
121913
122015
  });
121914
122016
  } catch (err) {
121915
122017
  const msg = err instanceof Error ? err.message : String(err);
121916
- log22.error("pty.spawn failed: %s (shell=%s, cwd=%s)", msg, shell, cwd);
122018
+ log24.error("pty.spawn failed: %s (shell=%s, cwd=%s)", msg, shell, cwd);
121917
122019
  throw err;
121918
122020
  }
121919
122021
  const session = { pty: ptyProcess, scrollback: "", workspaceId };
@@ -121949,7 +122051,7 @@ async function spawnTerminal(workspaceId, terminalId, options2) {
121949
122051
  }
121950
122052
  });
121951
122053
  ptyProcess.onExit(() => {
121952
- log22.debug("Terminal exited: %s (workspace %s)", terminalId, workspaceId);
122054
+ log24.debug("Terminal exited: %s (workspace %s)", terminalId, workspaceId);
121953
122055
  terminals.delete(terminalId);
121954
122056
  outputListeners.delete(terminalId);
121955
122057
  const set = workspaceTerminals.get(workspaceId);
@@ -122057,7 +122159,7 @@ function killAllTerminals() {
122057
122159
 
122058
122160
  // src/lib/terminal-ws.ts
122059
122161
  init_src();
122060
- var log23 = createLogger("terminal-ws");
122162
+ var log25 = createLogger("terminal-ws");
122061
122163
  var MAX_CLOSE_REASON_BYTES = 123;
122062
122164
  function clampCloseReason(reason) {
122063
122165
  const enc = new TextEncoder();
@@ -122121,7 +122223,7 @@ async function handleTerminalConnection(ws, req) {
122121
122223
  session = await spawnTerminal(workspaceId, terminalId, spawnOpts);
122122
122224
  } catch (err) {
122123
122225
  const msg = err instanceof Error ? err.message : String(err);
122124
- log23.error("Failed to spawn terminal %s for workspace %s: %s", terminalId, workspaceId, msg);
122226
+ log25.error("Failed to spawn terminal %s for workspace %s: %s", terminalId, workspaceId, msg);
122125
122227
  safeClose(ws, 4001, msg);
122126
122228
  return;
122127
122229
  }
@@ -122135,7 +122237,7 @@ async function handleTerminalConnection(ws, req) {
122135
122237
  });
122136
122238
  }
122137
122239
  function attachSession(ws, terminalId, workspaceId, session, isNew) {
122138
- log23.debug(
122240
+ log25.debug(
122139
122241
  "Terminal %s: %s (workspace %s)",
122140
122242
  isNew ? "connected" : "reconnected",
122141
122243
  terminalId,
@@ -122164,7 +122266,7 @@ function attachSession(ws, terminalId, workspaceId, session, isNew) {
122164
122266
  }, 3e3);
122165
122267
  const exitDisposable = session.pty.onExit(({ exitCode }) => {
122166
122268
  clearInterval(processInterval);
122167
- log23.debug("PTY exited with code %d for terminal %s", exitCode, terminalId);
122269
+ log25.debug("PTY exited with code %d for terminal %s", exitCode, terminalId);
122168
122270
  if (ws.readyState === ws.OPEN) {
122169
122271
  ws.close(1e3, "Terminal exited");
122170
122272
  }
@@ -122176,7 +122278,7 @@ function attachSession(ws, terminalId, workspaceId, session, isNew) {
122176
122278
  clearInterval(processInterval);
122177
122279
  dataDisposable.dispose();
122178
122280
  exitDisposable.dispose();
122179
- log23.debug("Terminal disconnected: %s (PTY kept alive)", terminalId);
122281
+ log25.debug("Terminal disconnected: %s (PTY kept alive)", terminalId);
122180
122282
  });
122181
122283
  }
122182
122284
  function handleMessage(ws, terminalId, session, message) {
@@ -122214,7 +122316,7 @@ function getToken() {
122214
122316
  }
122215
122317
 
122216
122318
  // src/lib/tunnel.ts
122217
- var log24 = createLogger("tunnel");
122319
+ var log26 = createLogger("tunnel");
122218
122320
  var tunnelProcess = null;
122219
122321
  var tunnelUrl = null;
122220
122322
  var startInProgress = null;
@@ -122228,7 +122330,7 @@ function appendToken(baseUrl, token) {
122228
122330
  }
122229
122331
  function spawnTunnel(options2, resolvedPath) {
122230
122332
  const args = ["tunnel", "--config", "/dev/null", "--url", `http://localhost:${options2.port}`];
122231
- log24.debug("spawning cloudflared %s", args.join(" "));
122333
+ log26.debug("spawning cloudflared %s", args.join(" "));
122232
122334
  return new Promise((resolve7, reject) => {
122233
122335
  const child = spawn7("cloudflared", args, {
122234
122336
  env: { ...process.env, PATH: resolvedPath },
@@ -122242,12 +122344,12 @@ function spawnTunnel(options2, resolvedPath) {
122242
122344
  for (const line2 of text3.split("\n")) {
122243
122345
  const trimmed = line2.trim();
122244
122346
  if (!trimmed) continue;
122245
- log24.debug("output: %s", trimmed);
122347
+ log26.debug("output: %s", trimmed);
122246
122348
  const url = extractUrl(trimmed);
122247
122349
  if (url) {
122248
122350
  const token = getToken();
122249
122351
  tunnelUrl = appendToken(url, token);
122250
- log24.debug("detected URL: %s", tunnelUrl);
122352
+ log26.debug("detected URL: %s", tunnelUrl);
122251
122353
  emit({ kind: "tunnel-url", url: tunnelUrl });
122252
122354
  if (!settled) {
122253
122355
  settled = true;
@@ -122262,7 +122364,7 @@ function spawnTunnel(options2, resolvedPath) {
122262
122364
  handleOutput(data);
122263
122365
  });
122264
122366
  child.on("error", (err) => {
122265
- log24.debug("process error: %s", err.message);
122367
+ log26.debug("process error: %s", err.message);
122266
122368
  tunnelProcess = null;
122267
122369
  tunnelUrl = null;
122268
122370
  emit({ kind: "tunnel-error", error: err.message });
@@ -122272,7 +122374,7 @@ function spawnTunnel(options2, resolvedPath) {
122272
122374
  }
122273
122375
  });
122274
122376
  child.on("exit", (code) => {
122275
- log24.debug("process exited with code: %d", code ?? -1);
122377
+ log26.debug("process exited with code: %d", code ?? -1);
122276
122378
  const wasRunning = tunnelProcess !== null && settled;
122277
122379
  tunnelProcess = null;
122278
122380
  tunnelUrl = null;
@@ -122294,7 +122396,7 @@ function spawnTunnel(options2, resolvedPath) {
122294
122396
  });
122295
122397
  setTimeout(() => {
122296
122398
  if (!settled) {
122297
- log24.debug("30s timeout reached, resolving without URL");
122399
+ log26.debug("30s timeout reached, resolving without URL");
122298
122400
  settled = true;
122299
122401
  resolve7();
122300
122402
  }
@@ -122303,12 +122405,12 @@ function spawnTunnel(options2, resolvedPath) {
122303
122405
  }
122304
122406
  async function startTunnel(options2) {
122305
122407
  if (startInProgress) {
122306
- log24.debug("startTunnel: start already in progress, waiting...");
122408
+ log26.debug("startTunnel: start already in progress, waiting...");
122307
122409
  await startInProgress;
122308
122410
  return;
122309
122411
  }
122310
122412
  if (tunnelProcess) {
122311
- log24.debug("startTunnel: already running, re-emitting URL");
122413
+ log26.debug("startTunnel: already running, re-emitting URL");
122312
122414
  if (tunnelUrl) {
122313
122415
  emit({ kind: "tunnel-url", url: tunnelUrl });
122314
122416
  }
@@ -133734,7 +133836,7 @@ function createContext8() {
133734
133836
 
133735
133837
  // src/trpc/router.ts
133736
133838
  init_src();
133737
- import { execFile as execFile5, execFileSync as execFileSync2, spawn as spawn8 } from "node:child_process";
133839
+ import { execFile as execFile6, execFileSync as execFileSync2, spawn as spawn8 } from "node:child_process";
133738
133840
  import { randomUUID as randomUUID2 } from "node:crypto";
133739
133841
  import {
133740
133842
  existsSync as existsSync9,
@@ -133856,7 +133958,7 @@ function clearHistory(workspaceId, range, now = Date.now()) {
133856
133958
 
133857
133959
  // src/lib/chat-session-summary.ts
133858
133960
  init_src();
133859
- var log25 = createLogger("chat-session-summary");
133961
+ var log27 = createLogger("chat-session-summary");
133860
133962
  var REFRESH_KEY = Symbol.for("band.chat-session-summary.refresh");
133861
133963
  var g15 = globalThis;
133862
133964
  if (!g15[REFRESH_KEY]) g15[REFRESH_KEY] = /* @__PURE__ */ new Map();
@@ -133878,7 +133980,7 @@ async function ensureActiveSessionSummary(chatId, worktreePath) {
133878
133980
  }
133879
133981
  return chat;
133880
133982
  } catch (err) {
133881
- log25.warn({ chatId, err }, "ensureActiveSessionSummary failed");
133983
+ log27.warn({ chatId, err }, "ensureActiveSessionSummary failed");
133882
133984
  return chat;
133883
133985
  }
133884
133986
  }
@@ -133905,7 +134007,56 @@ async function doRefresh(chatId, worktreePath) {
133905
134007
  return;
133906
134008
  }
133907
134009
  } catch (err) {
133908
- log25.warn({ chatId, err }, "active session refresh failed");
134010
+ log27.warn({ chatId, err }, "active session refresh failed");
134011
+ }
134012
+ }
134013
+
134014
+ // src/lib/disk-usage.ts
134015
+ import { execFile as execFile5 } from "node:child_process";
134016
+ var MAX_BUFFER2 = 10 * 1024 * 1024;
134017
+ var DU_TIMEOUT_MS = 3e4;
134018
+ var DU_GLOBAL_CONCURRENCY = 8;
134019
+ var inFlight = 0;
134020
+ var waiting = [];
134021
+ function acquireSlot() {
134022
+ return new Promise((resolve7) => {
134023
+ const grant = () => {
134024
+ inFlight++;
134025
+ resolve7(() => {
134026
+ inFlight--;
134027
+ const next = waiting.shift();
134028
+ if (next) next();
134029
+ });
134030
+ };
134031
+ if (inFlight < DU_GLOBAL_CONCURRENCY) grant();
134032
+ else waiting.push(grant);
134033
+ });
134034
+ }
134035
+ async function duBytes(path3) {
134036
+ const release = await acquireSlot();
134037
+ try {
134038
+ const stdout = await new Promise((resolve7, reject) => {
134039
+ execFile5(
134040
+ "du",
134041
+ ["-sk", path3],
134042
+ { maxBuffer: MAX_BUFFER2, timeout: DU_TIMEOUT_MS },
134043
+ (err, out) => {
134044
+ if (err && !out) {
134045
+ reject(err);
134046
+ return;
134047
+ }
134048
+ resolve7(out);
134049
+ }
134050
+ );
134051
+ });
134052
+ const kbStr = stdout.trim().split(/\s+/)[0];
134053
+ const kb2 = Number.parseInt(kbStr, 10);
134054
+ if (!Number.isFinite(kb2)) {
134055
+ throw new Error(`du output not numeric: ${JSON.stringify(stdout)}`);
134056
+ }
134057
+ return kb2 * 1024;
134058
+ } finally {
134059
+ release();
133909
134060
  }
133910
134061
  }
133911
134062
 
@@ -134006,7 +134157,7 @@ init_src();
134006
134157
  import { existsSync as existsSync8, realpathSync as realpathSync4 } from "node:fs";
134007
134158
  import { basename, dirname as dirname6, isAbsolute, join as join22, resolve as resolvePath } from "node:path";
134008
134159
  import prettier from "prettier";
134009
- var log26 = createLogger("formatter");
134160
+ var log28 = createLogger("formatter");
134010
134161
  var FormatterError = class extends Error {
134011
134162
  code;
134012
134163
  detail;
@@ -134061,7 +134212,7 @@ async function formatFile(worktreePath, filePath, content2, options2 = {}) {
134061
134212
  }
134062
134213
  const changed = formatted !== content2;
134063
134214
  if (changed) {
134064
- log26.info(
134215
+ log28.info(
134065
134216
  "Formatted %s with parser=%s (%d bytes in)",
134066
134217
  absFile,
134067
134218
  info.inferredParser,
@@ -134200,7 +134351,7 @@ function fuzzyScore(query, filePath) {
134200
134351
  // src/lib/terminal-config.ts
134201
134352
  init_src();
134202
134353
  init_zod();
134203
- var log27 = createLogger("terminal-config");
134354
+ var log29 = createLogger("terminal-config");
134204
134355
  var TerminalPaneConfigSchema = external_exports.object({
134205
134356
  name: external_exports.string().optional(),
134206
134357
  command: external_exports.string().optional(),
@@ -134231,7 +134382,7 @@ function loadWorkspaceTerminalConfig(worktreePath, projectPath) {
134231
134382
  if (!terminalBlock) return null;
134232
134383
  const result = WorkspaceTerminalConfigSchema.safeParse(terminalBlock);
134233
134384
  if (!result.success) {
134234
- log27.warn(
134385
+ log29.warn(
134235
134386
  "Invalid workspace.terminal config: %s",
134236
134387
  result.error.issues.map((i2) => `${i2.path.join(".")}: ${i2.message}`).join("; ")
134237
134388
  );
@@ -134241,8 +134392,8 @@ function loadWorkspaceTerminalConfig(worktreePath, projectPath) {
134241
134392
  }
134242
134393
 
134243
134394
  // src/trpc/router.ts
134244
- var execFileAsync = promisify(execFile5);
134245
- var log28 = createLogger("trpc");
134395
+ var execFileAsync = promisify(execFile6);
134396
+ var log30 = createLogger("trpc");
134246
134397
  var t2 = initTRPC.context().create();
134247
134398
  var publicProcedure = t2.procedure;
134248
134399
  var projectsRouter = t2.router({
@@ -134352,7 +134503,14 @@ var projectsRouter = t2.router({
134352
134503
  defaultBranch,
134353
134504
  worktrees: worktrees2,
134354
134505
  label: input.label ?? void 0,
134355
- kind
134506
+ kind,
134507
+ // For git projects, default to `true` so the first CI poll
134508
+ // still runs the GraphQL query — `syncWorktrees` writes the
134509
+ // real value on the next tick. For plain projects there's no
134510
+ // remote by construction, so set `false` directly: sync skips
134511
+ // plain projects (`kind !== "plain"` filter), so this initial
134512
+ // value sticks for the lifetime of the row. See issue #458.
134513
+ hasOrigin: kind === "git"
134356
134514
  };
134357
134515
  state2.projects.push(project);
134358
134516
  saveState(state2);
@@ -134543,13 +134701,13 @@ var workspacesRouter = t2.router({
134543
134701
  try {
134544
134702
  const deletedTasks = deleteWorkspaceTasks(workspaceId);
134545
134703
  if (deletedTasks > 0) {
134546
- log28.info(
134704
+ log30.info(
134547
134705
  { workspaceId, count: deletedTasks },
134548
134706
  "deleted workspace tasks on removal"
134549
134707
  );
134550
134708
  }
134551
134709
  } catch (err) {
134552
- log28.error({ workspaceId, err }, "failed to delete workspace tasks on removal");
134710
+ log30.error({ workspaceId, err }, "failed to delete workspace tasks on removal");
134553
134711
  }
134554
134712
  emit({ kind: "remove", workspaceId });
134555
134713
  const projPath = proj.path;
@@ -134567,7 +134725,7 @@ var workspacesRouter = t2.router({
134567
134725
  timeout: 6e4
134568
134726
  });
134569
134727
  } catch (err) {
134570
- log28.warn({ err, workspaceId }, "teardown script failed");
134728
+ log30.warn({ err, workspaceId }, "teardown script failed");
134571
134729
  }
134572
134730
  }
134573
134731
  try {
@@ -134585,7 +134743,7 @@ var workspacesRouter = t2.router({
134585
134743
  encoding: "utf-8"
134586
134744
  });
134587
134745
  } catch (err) {
134588
- log28.warn({ err, workspaceId }, "git worktree prune failed");
134746
+ log30.warn({ err, workspaceId }, "git worktree prune failed");
134589
134747
  }
134590
134748
  }
134591
134749
  try {
@@ -134597,7 +134755,7 @@ var workspacesRouter = t2.router({
134597
134755
  } catch {
134598
134756
  }
134599
134757
  })().catch((err) => {
134600
- log28.error({ err, workspaceId }, "background workspace cleanup failed");
134758
+ log30.error({ err, workspaceId }, "background workspace cleanup failed");
134601
134759
  });
134602
134760
  });
134603
134761
  return { ok: true };
@@ -134678,7 +134836,7 @@ var workspacesRouter = t2.router({
134678
134836
  throw new Error(`Script "${input.scriptType}" not found`);
134679
134837
  }
134680
134838
  return new Promise((resolve7, reject) => {
134681
- execFile5("bash", [scriptPath], { cwd: input.path }, (err) => {
134839
+ execFile6("bash", [scriptPath], { cwd: input.path }, (err) => {
134682
134840
  if (err) {
134683
134841
  reject(new Error(err.message));
134684
134842
  } else {
@@ -134949,7 +135107,7 @@ var workspaceRouter = t2.router({
134949
135107
  );
134950
135108
  branches = output.trim().split("\n").map((b10) => b10.trim()).filter(Boolean);
134951
135109
  } catch (err) {
134952
- log28.error(
135110
+ log30.error(
134953
135111
  `listBranches: for-each-ref failed for ${cwd}: ${err instanceof Error ? err.message : err}`
134954
135112
  );
134955
135113
  }
@@ -135809,21 +135967,21 @@ var tunnelRouter = t2.router({
135809
135967
  return getTunnelStatus();
135810
135968
  }),
135811
135969
  start: publicProcedure.input(external_exports.object({}).optional()).mutation(async () => {
135812
- log28.debug("tunnel.start called");
135970
+ log30.debug("tunnel.start called");
135813
135971
  const port = parseInt(process.env.BAND_PORT || "3456", 10);
135814
- log28.debug("tunnel.start: port=%d", port);
135972
+ log30.debug("tunnel.start: port=%d", port);
135815
135973
  try {
135816
135974
  await startTunnel({ port });
135817
135975
  } catch (err) {
135818
- log28.debug({ err }, "tunnel.start: startTunnel failed");
135976
+ log30.debug({ err }, "tunnel.start: startTunnel failed");
135819
135977
  return { ok: true, url: null };
135820
135978
  }
135821
135979
  const status = getTunnelStatus();
135822
- log28.debug({ status }, "tunnel.start: after startTunnel");
135980
+ log30.debug({ status }, "tunnel.start: after startTunnel");
135823
135981
  if (status.url) {
135824
135982
  return { ok: true, url: status.url };
135825
135983
  }
135826
- log28.debug("tunnel.start: no URL available");
135984
+ log30.debug("tunnel.start: no URL available");
135827
135985
  return { ok: true, url: null };
135828
135986
  }),
135829
135987
  stop: publicProcedure.mutation(async () => {
@@ -135838,7 +135996,7 @@ var prereqsRouter = t2.router({
135838
135996
  installTunnel: publicProcedure.mutation(async () => {
135839
135997
  const resolvedPath = await shellPath();
135840
135998
  await new Promise((resolve7, reject) => {
135841
- execFile5(
135999
+ execFile6(
135842
136000
  "brew",
135843
136001
  ["install", "cloudflared"],
135844
136002
  { env: { ...process.env, PATH: resolvedPath }, timeout: 12e4 },
@@ -136042,15 +136200,15 @@ var sessionsRouter = t2.router({
136042
136200
  });
136043
136201
  var servicesRouter = t2.router({
136044
136202
  health: publicProcedure.query(() => {
136045
- log28.debug("services.health called");
136203
+ log30.debug("services.health called");
136046
136204
  const tunnel = getTunnelStatus();
136047
- log28.debug({ tunnel }, "services.health: tunnel status");
136205
+ log30.debug({ tunnel }, "services.health: tunnel status");
136048
136206
  const result = {
136049
136207
  webserver: true,
136050
136208
  tunnel: tunnel.running,
136051
136209
  tunnel_url: tunnel.url
136052
136210
  };
136053
- log28.debug({ result }, "services.health result");
136211
+ log30.debug({ result }, "services.health result");
136054
136212
  return result;
136055
136213
  }),
136056
136214
  // Activity level controls how often the branch-status poller fires.
@@ -136060,7 +136218,124 @@ var servicesRouter = t2.router({
136060
136218
  setPollerActivity(input.activity);
136061
136219
  return { activity: input.activity };
136062
136220
  }),
136063
- getActivity: publicProcedure.query(() => ({ activity: getPollerActivity() }))
136221
+ getActivity: publicProcedure.query(() => ({ activity: getPollerActivity() })),
136222
+ // Resources dashboard — server CPU/memory snapshot (cheap, instant).
136223
+ // `process.cpuUsage()` is cumulative since process start; the UI labels
136224
+ // it "Total CPU time" so callers don't read it as instantaneous load.
136225
+ resourcesServer: publicProcedure.query(() => {
136226
+ const mem = process.memoryUsage();
136227
+ const cpu = process.cpuUsage();
136228
+ return {
136229
+ pid: process.pid,
136230
+ uptimeSeconds: process.uptime(),
136231
+ nodeVersion: process.version,
136232
+ platform: process.platform,
136233
+ arch: process.arch,
136234
+ memory: {
136235
+ rssBytes: mem.rss,
136236
+ heapTotalBytes: mem.heapTotal,
136237
+ heapUsedBytes: mem.heapUsed,
136238
+ externalBytes: mem.external,
136239
+ arrayBuffersBytes: mem.arrayBuffers
136240
+ },
136241
+ cpu: {
136242
+ userMicros: cpu.user,
136243
+ systemMicros: cpu.system
136244
+ }
136245
+ };
136246
+ }),
136247
+ // Resources dashboard — list every tracked git project + its
136248
+ // worktree paths *without* doing any disk walks. Instant: just
136249
+ // reads state + a single `git worktree list --porcelain` per
136250
+ // project (in parallel). The client uses this to paint rows
136251
+ // immediately, then fetches each project's size individually
136252
+ // via `resourcesProjectSize` so the slow `du` work is amortised
136253
+ // and observable per-row.
136254
+ resourcesProjects: publicProcedure.query(async () => {
136255
+ const state2 = loadState();
136256
+ const projects2 = await Promise.all(
136257
+ state2.projects.filter((p6) => p6.kind === "git").map(async (project) => {
136258
+ try {
136259
+ const list2 = await listWorktrees(project.path);
136260
+ const worktrees2 = list2.filter((wt) => !wt.isBare).map((wt) => ({
136261
+ // Detached HEAD (mid-rebase, mid-bisect, or
136262
+ // explicit `git checkout <sha>`) produces an empty
136263
+ // branch string. Keep the row with a sentinel
136264
+ // label so the size still gets counted — silently
136265
+ // dropping it would make a developer's largest
136266
+ // worktree disappear from the accounting whenever
136267
+ // they happened to be on a detached HEAD.
136268
+ branch: wt.branch || "(detached HEAD)",
136269
+ path: wt.path
136270
+ }));
136271
+ return {
136272
+ project: project.name,
136273
+ path: project.path,
136274
+ worktrees: worktrees2,
136275
+ error: void 0
136276
+ };
136277
+ } catch (err) {
136278
+ return {
136279
+ project: project.name,
136280
+ path: project.path,
136281
+ worktrees: [],
136282
+ error: err instanceof Error ? err.message : String(err)
136283
+ };
136284
+ }
136285
+ })
136286
+ );
136287
+ return { projects: projects2 };
136288
+ }),
136289
+ // Resources dashboard — measure disk usage for a single project.
136290
+ //
136291
+ // Slow: runs `du -sk` once per worktree, in parallel via
136292
+ // Promise.all. The client fan-outs are concurrency-limited so the
136293
+ // server doesn't see a thundering herd of `du` processes from a
136294
+ // single page open. Per-worktree errors are absorbed into the
136295
+ // response (sizeBytes 0, `error` populated) so a single broken
136296
+ // worktree doesn't fail the whole query.
136297
+ resourcesProjectSize: publicProcedure.input(external_exports.object({ project: external_exports.string() })).query(async ({ input }) => {
136298
+ const state2 = loadState();
136299
+ const project = state2.projects.find((p6) => p6.name === input.project && p6.kind === "git");
136300
+ if (!project) {
136301
+ throw new TRPCError({ code: "NOT_FOUND", message: "Project not found" });
136302
+ }
136303
+ let worktreePaths;
136304
+ try {
136305
+ const list2 = await listWorktrees(project.path);
136306
+ worktreePaths = list2.filter((wt) => !wt.isBare).map((wt) => ({
136307
+ // See `resourcesProjects` above — detached HEAD gets a
136308
+ // sentinel label rather than being dropped.
136309
+ branch: wt.branch || "(detached HEAD)",
136310
+ path: wt.path
136311
+ }));
136312
+ } catch (err) {
136313
+ return {
136314
+ project: project.name,
136315
+ sizeBytes: 0,
136316
+ worktrees: [],
136317
+ error: err instanceof Error ? err.message : String(err)
136318
+ };
136319
+ }
136320
+ const worktrees2 = await Promise.all(
136321
+ worktreePaths.map(async (wt) => {
136322
+ try {
136323
+ const sizeBytes2 = await duBytes(wt.path);
136324
+ return { branch: wt.branch, path: wt.path, sizeBytes: sizeBytes2 };
136325
+ } catch (err) {
136326
+ return {
136327
+ branch: wt.branch,
136328
+ path: wt.path,
136329
+ sizeBytes: 0,
136330
+ error: err instanceof Error ? err.message : String(err)
136331
+ };
136332
+ }
136333
+ })
136334
+ );
136335
+ worktrees2.sort((a6, b10) => b10.sizeBytes - a6.sizeBytes);
136336
+ const sizeBytes = worktrees2.reduce((sum, wt) => sum + wt.sizeBytes, 0);
136337
+ return { project: project.name, sizeBytes, worktrees: worktrees2 };
136338
+ })
136064
136339
  });
136065
136340
  function canonicalizeMaybeMissing(p6) {
136066
136341
  if (existsSync9(p6)) {
@@ -136103,11 +136378,12 @@ var editorRouter = t2.router({
136103
136378
  /**
136104
136379
  * Either an absolute filesystem path or a workspace-relative
136105
136380
  * path. Paths inside the workspace root open as normal editor
136106
- * tabs (routed via `/workspace/$id/code/$splat`); paths outside
136107
- * any workspace root open as external tabs (same surface as
136108
- * desktop Cmd+O / "Open File…"). May include a trailing
136109
- * line / column suffix in the standard `path:line[:column]` /
136110
- * `path:line-lineEnd` notation.
136381
+ * tabs (the renderer routes to the Files panel via the
136382
+ * `open-file` SSE event; see `dispatchOpenFileEvent`); paths
136383
+ * outside any workspace root open as external tabs (same
136384
+ * surface as desktop Cmd+O / "Open File…"). May include a
136385
+ * trailing line / column suffix in the standard
136386
+ * `path:line[:column]` / `path:line-lineEnd` notation.
136111
136387
  */
136112
136388
  filePath: external_exports.string().min(1),
136113
136389
  line: external_exports.number().int().positive().optional(),
@@ -136580,7 +136856,7 @@ var chatsRouter = t2.router({
136580
136856
  summary = info?.summary;
136581
136857
  lastModified = info?.lastModified;
136582
136858
  } catch (err) {
136583
- log28.warn(
136859
+ log30.warn(
136584
136860
  { chatId: input.chatId, sessionId: input.sessionId, err },
136585
136861
  "setActiveSession: getSessionInfo failed"
136586
136862
  );
@@ -136700,7 +136976,7 @@ var browserHostRouter = t2.router({
136700
136976
  // can confirm in the server log that the bridge component actually
136701
136977
  // executed. Drop once the experiment is stable.
136702
136978
  ping: publicProcedure.input(external_exports.object({ where: external_exports.string() })).mutation(({ input }) => {
136703
- log28.info("browserHost.ping from %s", input.where);
136979
+ log30.info("browserHost.ping from %s", input.where);
136704
136980
  return { ok: true };
136705
136981
  }),
136706
136982
  ensureView: publicProcedure.subscription(async function* (opts) {
@@ -136826,8 +137102,86 @@ var historyRouter = t2.router({
136826
137102
  var queuedFileSchema = external_exports.object({
136827
137103
  mediaType: external_exports.string(),
136828
137104
  url: external_exports.string(),
137105
+ path: external_exports.string().optional(),
136829
137106
  filename: external_exports.string().optional()
136830
137107
  });
137108
+ function isPathWithinUploadDir(p6) {
137109
+ const uploadDir = join23(bandHome(), "uploads");
137110
+ const normalized = resolve5(p6);
137111
+ if (normalized !== uploadDir && !normalized.startsWith(uploadDir + sep2)) {
137112
+ return false;
137113
+ }
137114
+ try {
137115
+ const canonicalUploadDir = realpathSync5(uploadDir);
137116
+ const canonicalPath = realpathSync5(p6);
137117
+ return canonicalPath === canonicalUploadDir || canonicalPath.startsWith(canonicalUploadDir + sep2);
137118
+ } catch {
137119
+ return true;
137120
+ }
137121
+ }
137122
+ async function resolveQueuedFiles(chatId, files) {
137123
+ if (!files || files.length === 0) return void 0;
137124
+ const resolved = [];
137125
+ const needsSave = [];
137126
+ const needsSaveIdx = [];
137127
+ for (let i2 = 0; i2 < files.length; i2++) {
137128
+ const file = files[i2];
137129
+ const uploadsUrlMatch = file.url.match(/^\/api\/uploads\/(.+)$/);
137130
+ const derivedPath = file.path ?? (uploadsUrlMatch ? join23(bandHome(), "uploads", uploadsUrlMatch[1]) : void 0);
137131
+ if (derivedPath) {
137132
+ if (!isPathWithinUploadDir(derivedPath)) {
137133
+ log30.warn(
137134
+ { chatId, path: derivedPath, filename: file.filename },
137135
+ "queue: dropping file with path outside uploads directory"
137136
+ );
137137
+ continue;
137138
+ }
137139
+ resolved.push({
137140
+ mediaType: file.mediaType,
137141
+ url: file.url,
137142
+ path: derivedPath,
137143
+ ...file.filename !== void 0 && { filename: file.filename }
137144
+ });
137145
+ continue;
137146
+ }
137147
+ if (file.url.startsWith("data:")) {
137148
+ needsSave.push(file);
137149
+ needsSaveIdx.push(resolved.length);
137150
+ resolved.push({
137151
+ mediaType: file.mediaType,
137152
+ url: file.url,
137153
+ path: "",
137154
+ filename: file.filename
137155
+ });
137156
+ continue;
137157
+ }
137158
+ log30.warn(
137159
+ { chatId, url: file.url, filename: file.filename },
137160
+ "queue: dropping file with no path and non-data URL \u2014 cannot recover disk path"
137161
+ );
137162
+ }
137163
+ if (needsSave.length > 0) {
137164
+ const saved = await saveUploadedFilesDetailed(needsSave);
137165
+ if (saved.length !== needsSave.length) {
137166
+ log30.error(
137167
+ { chatId, expected: needsSave.length, got: saved.length },
137168
+ "queue: saveUploadedFilesDetailed returned unexpected count \u2014 dropping data-URL files (cannot map 1:1)"
137169
+ );
137170
+ } else {
137171
+ for (let k4 = 0; k4 < saved.length; k4++) {
137172
+ const target = needsSaveIdx[k4];
137173
+ resolved[target] = {
137174
+ mediaType: saved[k4].mediaType,
137175
+ url: `/api/uploads/${saved[k4].storedName}`,
137176
+ path: saved[k4].path,
137177
+ ...saved[k4].originalName !== void 0 && { filename: saved[k4].originalName }
137178
+ };
137179
+ }
137180
+ }
137181
+ }
137182
+ const finalized = resolved.filter((f10) => f10.path !== "");
137183
+ return finalized.length > 0 ? finalized : void 0;
137184
+ }
136831
137185
  var queueRouter = t2.router({
136832
137186
  push: publicProcedure.input(
136833
137187
  external_exports.object({
@@ -136836,10 +137190,24 @@ var queueRouter = t2.router({
136836
137190
  text: external_exports.string(),
136837
137191
  files: external_exports.array(queuedFileSchema).optional()
136838
137192
  })
136839
- ).mutation(({ input }) => {
137193
+ ).mutation(async ({ input }) => {
136840
137194
  const chatId = input.chatId ?? getOrCreateDefaultChat(input.workspaceId).id;
136841
- const message = pushQueuedMessage(chatId, { text: input.text, files: input.files });
136842
- return { ok: true, message, messages: getQueuedMessages(chatId) };
137195
+ let files;
137196
+ try {
137197
+ files = await resolveQueuedFiles(chatId, input.files);
137198
+ } catch (err) {
137199
+ log30.error(
137200
+ { chatId, err: err instanceof Error ? err.message : err },
137201
+ "queue.push: failed to persist file uploads; enqueuing text only"
137202
+ );
137203
+ files = void 0;
137204
+ }
137205
+ const message = pushQueuedMessage(chatId, { text: input.text, files });
137206
+ return {
137207
+ ok: true,
137208
+ message: toWireQueuedMessages([message])[0],
137209
+ messages: toWireQueuedMessages(getQueuedMessages(chatId))
137210
+ };
136843
137211
  }),
136844
137212
  set: publicProcedure.input(
136845
137213
  external_exports.object({
@@ -136853,20 +137221,44 @@ var queueRouter = t2.router({
136853
137221
  })
136854
137222
  )
136855
137223
  })
136856
- ).mutation(({ input }) => {
137224
+ ).mutation(async ({ input }) => {
136857
137225
  const chatId = input.chatId ?? getOrCreateDefaultChat(input.workspaceId).id;
136858
- setQueuedMessages(chatId, input.messages);
136859
- return { ok: true, messages: getQueuedMessages(chatId) };
137226
+ const messages = await Promise.all(
137227
+ input.messages.map(async (m11) => {
137228
+ try {
137229
+ return {
137230
+ ...m11.id !== void 0 && { id: m11.id },
137231
+ text: m11.text,
137232
+ files: await resolveQueuedFiles(chatId, m11.files)
137233
+ };
137234
+ } catch (err) {
137235
+ log30.error(
137236
+ { chatId, messageId: m11.id, err: err instanceof Error ? err.message : err },
137237
+ "queue: failed to resolve files for queued message; dropping its files"
137238
+ );
137239
+ return {
137240
+ ...m11.id !== void 0 && { id: m11.id },
137241
+ text: m11.text,
137242
+ files: void 0
137243
+ };
137244
+ }
137245
+ })
137246
+ );
137247
+ setQueuedMessages(chatId, messages);
137248
+ return { ok: true, messages: toWireQueuedMessages(getQueuedMessages(chatId)) };
136860
137249
  }),
136861
137250
  get: publicProcedure.input(external_exports.object({ workspaceId: external_exports.string(), chatId: external_exports.string().optional() })).query(({ input }) => {
136862
137251
  const chatId = input.chatId ?? getOrCreateDefaultChat(input.workspaceId).id;
136863
- const messages = getQueuedMessages(chatId);
136864
- return { messages };
137252
+ return { messages: toWireQueuedMessages(getQueuedMessages(chatId)) };
136865
137253
  }),
136866
137254
  remove: publicProcedure.input(external_exports.object({ workspaceId: external_exports.string(), chatId: external_exports.string().optional(), id: external_exports.string() })).mutation(({ input }) => {
136867
137255
  const chatId = input.chatId ?? getOrCreateDefaultChat(input.workspaceId).id;
136868
137256
  const removed = removeQueuedMessage(chatId, input.id);
136869
- return { ok: true, removed, messages: getQueuedMessages(chatId) };
137257
+ return {
137258
+ ok: true,
137259
+ removed,
137260
+ messages: toWireQueuedMessages(getQueuedMessages(chatId))
137261
+ };
136870
137262
  }),
136871
137263
  update: publicProcedure.input(
136872
137264
  external_exports.object({
@@ -136878,12 +137270,16 @@ var queueRouter = t2.router({
136878
137270
  ).mutation(({ input }) => {
136879
137271
  const chatId = input.chatId ?? getOrCreateDefaultChat(input.workspaceId).id;
136880
137272
  const updated = updateQueuedMessage(chatId, input.id, input.text);
136881
- return { ok: true, updated, messages: getQueuedMessages(chatId) };
137273
+ return {
137274
+ ok: true,
137275
+ updated,
137276
+ messages: toWireQueuedMessages(getQueuedMessages(chatId))
137277
+ };
136882
137278
  }),
136883
137279
  shift: publicProcedure.input(external_exports.object({ workspaceId: external_exports.string(), chatId: external_exports.string().optional() })).mutation(({ input }) => {
136884
137280
  const chatId = input.chatId ?? getOrCreateDefaultChat(input.workspaceId).id;
136885
137281
  const message = shiftQueuedMessage(chatId);
136886
- return { message };
137282
+ return { message: message ? toWireQueuedMessages([message])[0] : null };
136887
137283
  }),
136888
137284
  clear: publicProcedure.input(external_exports.object({ workspaceId: external_exports.string(), chatId: external_exports.string().optional() })).mutation(({ input }) => {
136889
137285
  const chatId = input.chatId ?? getOrCreateDefaultChat(input.workspaceId).id;
@@ -136903,12 +137299,13 @@ var queueRouter = t2.router({
136903
137299
  unsubscribe();
136904
137300
  resolve7?.();
136905
137301
  });
136906
- yield { messages: getQueuedMessages(chatId) };
137302
+ yield { messages: toWireQueuedMessages(getQueuedMessages(chatId)) };
136907
137303
  queue.length = 0;
136908
137304
  try {
136909
137305
  while (!opts.signal?.aborted) {
136910
137306
  while (queue.length > 0) {
136911
- yield queue.shift();
137307
+ const update = queue.shift();
137308
+ yield { messages: toWireQueuedMessages(update.messages) };
136912
137309
  }
136913
137310
  await new Promise((r6) => {
136914
137311
  resolve7 = r6;