@band-app/server 0.15.0 → 0.16.3

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 (173) hide show
  1. package/dist/client/assets/{DockviewTerminalContainer-DJBIrF63.js → DockviewTerminalContainer-D2lnsm6V.js} +2 -2
  2. package/dist/client/assets/TerminalPanel-SEbvgXv_.js +4 -0
  3. package/dist/client/assets/{_basePickBy-Dc0lZvrW.js → _basePickBy-C-uqClKF.js} +1 -1
  4. package/dist/client/assets/{_baseUniq-Cf73kSyg.js → _baseUniq-sN_xdSud.js} +1 -1
  5. package/dist/client/assets/{arc-CwSM8pE7.js → arc-DOqEiCLs.js} +1 -1
  6. package/dist/client/assets/{architectureDiagram-VXUJARFQ-CH39Gb3A.js → architectureDiagram-VXUJARFQ-DqRs-Rmj.js} +1 -1
  7. package/dist/client/assets/{blockDiagram-VD42YOAC-DDxgl1uo.js → blockDiagram-VD42YOAC-Dxh5tO7I.js} +1 -1
  8. package/dist/client/assets/{c4Diagram-YG6GDRKO-BfEjKk-g.js → c4Diagram-YG6GDRKO-CykynX-A.js} +1 -1
  9. package/dist/client/assets/channel-DijZVjmy.js +1 -0
  10. package/dist/client/assets/{chunk-4BX2VUAB-m8XoXk_H.js → chunk-4BX2VUAB-BckEbEmg.js} +1 -1
  11. package/dist/client/assets/{chunk-55IACEB6-CtGE4lZU.js → chunk-55IACEB6-Ds9A0UL5.js} +1 -1
  12. package/dist/client/assets/{chunk-B4BG7PRW-e8RHFxfZ.js → chunk-B4BG7PRW-BbdA9dFb.js} +1 -1
  13. package/dist/client/assets/{chunk-DI55MBZ5-6OH7qKMA.js → chunk-DI55MBZ5-C10prUQu.js} +1 -1
  14. package/dist/client/assets/{chunk-FMBD7UC4-OC-xaPXK.js → chunk-FMBD7UC4-CMO5VhEI.js} +1 -1
  15. package/dist/client/assets/{chunk-QN33PNHL-OAk8wo3f.js → chunk-QN33PNHL-BrbSzW7G.js} +1 -1
  16. package/dist/client/assets/{chunk-QZHKN3VN-BQaX9Wrw.js → chunk-QZHKN3VN-BjFQUCU6.js} +1 -1
  17. package/dist/client/assets/{chunk-TZMSLE5B-BB9WpJAf.js → chunk-TZMSLE5B-B6ZDwm2_.js} +1 -1
  18. package/dist/client/assets/classDiagram-2ON5EDUG-DkjTgKpR.js +1 -0
  19. package/dist/client/assets/classDiagram-v2-WZHVMYZB-DkjTgKpR.js +1 -0
  20. package/dist/client/assets/clone-DTHwmURu.js +1 -0
  21. package/dist/client/assets/{cose-bilkent-S5V4N54A-C9h_X8Kk.js → cose-bilkent-S5V4N54A-DbSjwZ4l.js} +1 -1
  22. package/dist/client/assets/{dagre-6UL2VRFP-DqYC11ua.js → dagre-6UL2VRFP-Q5hxi0O0.js} +1 -1
  23. package/dist/client/assets/{diagram-PSM6KHXK-CI1DRC6A.js → diagram-PSM6KHXK-D7kyAUq5.js} +1 -1
  24. package/dist/client/assets/{diagram-QEK2KX5R-fCfXFf0Y.js → diagram-QEK2KX5R-B7mpl_Jj.js} +1 -1
  25. package/dist/client/assets/{diagram-S2PKOQOG-ShkC9z2o.js → diagram-S2PKOQOG-CcIvSvFS.js} +1 -1
  26. package/dist/client/assets/{erDiagram-Q2GNP2WA-CaIQw3Ar.js → erDiagram-Q2GNP2WA-M2OHKSFi.js} +1 -1
  27. package/dist/client/assets/{flowDiagram-NV44I4VS-CBTayrED.js → flowDiagram-NV44I4VS-Ot2zCa0t.js} +1 -1
  28. package/dist/client/assets/{ganttDiagram-JELNMOA3-BXX1Htdo.js → ganttDiagram-JELNMOA3-Dtl6PI3C.js} +1 -1
  29. package/dist/client/assets/{gitGraphDiagram-V2S2FVAM-Dwzg4ngG.js → gitGraphDiagram-V2S2FVAM-DJCTwkyi.js} +1 -1
  30. package/dist/client/assets/{graph-CiXo3Prx.js → graph-DhvBAydB.js} +1 -1
  31. package/dist/client/assets/{highlighted-body-B3W2YXNL-7aLtgz8i.js → highlighted-body-B3W2YXNL-C6fHuUGl.js} +1 -1
  32. package/dist/client/assets/{index-Du9yJkB_.js → index-26c50Xcq.js} +1 -1
  33. package/dist/client/assets/index-B1K9dSWl.js +1 -0
  34. package/dist/client/assets/{index-C1zwysWn.js → index-B7VmPIW6.js} +1 -1
  35. package/dist/client/assets/{index-De1kIhJh.js → index-BBv9ZEF9.js} +1 -1
  36. package/dist/client/assets/{index-CVm5Qdu2.js → index-BDHBx5UL.js} +1 -1
  37. package/dist/client/assets/{index-BMWcJGJE.js → index-BUTfo7TS.js} +1 -1
  38. package/dist/client/assets/{index-Cg6YccFW.js → index-BYvWvSws.js} +1 -1
  39. package/dist/client/assets/{index-DmilV26W.js → index-CDbyr_lc.js} +1 -1
  40. package/dist/client/assets/{index-DQmzIoYb.js → index-CHGnZzhm.js} +1 -1
  41. package/dist/client/assets/{index-DRtcpY-M.js → index-CKHhLCNz.js} +1 -1
  42. package/dist/client/assets/{index-Gs7HImF7.js → index-CfsvL24Z.js} +1 -1
  43. package/dist/client/assets/{index-BCNUajNr.js → index-CjXcgzNg.js} +1 -1
  44. package/dist/client/assets/{index-DypgdPcb.js → index-CuNktTO3.js} +1 -1
  45. package/dist/client/assets/{index-CO6I2abN.js → index-DDe15mVl.js} +1 -1
  46. package/dist/client/assets/{index-CfYqVQ5p.js → index-I4Tc5Cuc.js} +1 -1
  47. package/dist/client/assets/{index-Di4toQJ5.js → index-MZ-6_xYm.js} +1 -1
  48. package/dist/client/assets/{index-DZu_2Bx_.js → index-SeTSJcqN.js} +1 -1
  49. package/dist/client/assets/{index-CR-ehys5.js → index-_yteHBmq.js} +1 -1
  50. package/dist/client/assets/{infoDiagram-HS3SLOUP-CWD1TyOW.js → infoDiagram-HS3SLOUP-CbAjFJUe.js} +1 -1
  51. package/dist/client/assets/{journeyDiagram-XKPGCS4Q-DhxNYqmd.js → journeyDiagram-XKPGCS4Q-Bf_0viAE.js} +1 -1
  52. package/dist/client/assets/{kanban-definition-3W4ZIXB7-CnS4C6i0.js → kanban-definition-3W4ZIXB7-CB2ylbw7.js} +1 -1
  53. package/dist/client/assets/{layout-CSID7t17.js → layout-Cp_4dcMO.js} +1 -1
  54. package/dist/client/assets/{linear-DoyBnBXg.js → linear-D1KyszeO.js} +1 -1
  55. package/dist/client/assets/main-CBJTAZFq.css +1 -0
  56. package/dist/client/assets/{main-DqsO5O95.js → main-Cl2c5yKs.js} +236 -236
  57. package/dist/client/assets/{mindmap-definition-VGOIOE7T-DInqVMnG.js → mindmap-definition-VGOIOE7T-Cm_2Y7ZK.js} +1 -1
  58. package/dist/client/assets/{pieDiagram-ADFJNKIX-9NXrhDdT.js → pieDiagram-ADFJNKIX-C9PiUHN5.js} +1 -1
  59. package/dist/client/assets/{quadrantDiagram-AYHSOK5B-C9V_pdwH.js → quadrantDiagram-AYHSOK5B-Cj0nbFw-.js} +1 -1
  60. package/dist/client/assets/{requirementDiagram-UZGBJVZJ-D7InXBsj.js → requirementDiagram-UZGBJVZJ-BVgceiyR.js} +1 -1
  61. package/dist/client/assets/{sankeyDiagram-TZEHDZUN-wucasjR9.js → sankeyDiagram-TZEHDZUN-D7dheggz.js} +1 -1
  62. package/dist/client/assets/{sequenceDiagram-WL72ISMW-z8y3Dw_f.js → sequenceDiagram-WL72ISMW-DVDMYgkc.js} +1 -1
  63. package/dist/client/assets/{square-terminal-BGmf1D-6.js → square-terminal-C64ybmC7.js} +1 -1
  64. package/dist/client/assets/{stateDiagram-FKZM4ZOC-UgwHItEV.js → stateDiagram-FKZM4ZOC-ClAcB9Xo.js} +1 -1
  65. package/dist/client/assets/stateDiagram-v2-4FDKWEC3-BH91aEUE.js +1 -0
  66. package/dist/client/assets/{timeline-definition-IT6M3QCI-BFRCSYLj.js → timeline-definition-IT6M3QCI-Cs1CMQvF.js} +1 -1
  67. package/dist/client/assets/{treemap-GDKQZRPO-aQmWnuZQ.js → treemap-GDKQZRPO-DerMxDGL.js} +1 -1
  68. package/dist/client/assets/{useSessionListContext-HoR6j8FY.js → useSessionListContext-BcM5_lz3.js} +1 -1
  69. package/dist/client/assets/{workspace._workspaceId-DGCQw9gi.js → workspace._workspaceId-C4dZT1kN.js} +1 -1
  70. package/dist/client/assets/{workspace._workspaceId.changes-DBE9NcLH.js → workspace._workspaceId.changes-BbnFHDel.js} +1 -1
  71. package/dist/client/assets/workspace._workspaceId.code-5MY9mEL9.js +1 -0
  72. package/dist/client/assets/{workspace._workspaceId.code._-CsnvG2rj.js → workspace._workspaceId.code._-DRRjmZ4D.js} +1 -1
  73. package/dist/client/assets/{workspace._workspaceId.code.index-BdfNmZpz.js → workspace._workspaceId.code.index-CQLsjESL.js} +1 -1
  74. package/dist/client/assets/{workspace._workspaceId.index-C7NyedGf.js → workspace._workspaceId.index-CE3X4XHe.js} +1 -1
  75. package/dist/client/assets/{workspace._workspaceId.terminal-C5ph2UWn.js → workspace._workspaceId.terminal-0Iuu4wZI.js} +2 -2
  76. package/dist/client/assets/{xychartDiagram-PRI3JC2R-DElSdzdM.js → xychartDiagram-PRI3JC2R-BVo__gVD.js} +1 -1
  77. package/dist/migrations/20260518175010_wealthy_talon/migration.sql +1 -0
  78. package/dist/migrations/20260518175010_wealthy_talon/snapshot.json +856 -0
  79. package/dist/openapi.json +11356 -0
  80. package/dist/server/assets/{DockviewTerminalContainer-Btn06b30.js → DockviewTerminalContainer-RbFw8Eo4.js} +3 -3
  81. package/dist/server/assets/{TerminalPanel-DiuUhPK5.js → TerminalPanel-BS0KF1ac.js} +52 -22
  82. package/dist/server/assets/{_basePickBy-D5WFbUhD.js → _basePickBy-Vtp-JFm9.js} +2 -2
  83. package/dist/server/assets/{_baseUniq-DFZeWlPn.js → _baseUniq-CRtvsDi1.js} +1 -1
  84. package/dist/server/assets/{_tanstack-start-manifest_v-UCApGYfd.js → _tanstack-start-manifest_v-787sukfk.js} +1 -1
  85. package/dist/server/assets/{arc-B1QmYB3V.js → arc-ChWehBm_.js} +1 -1
  86. package/dist/server/assets/{architecture-7HQA4BMR-SXElPY6g.js → architecture-7HQA4BMR-BiLezQsp.js} +6 -6
  87. package/dist/server/assets/{architectureDiagram-VXUJARFQ-H4ZI6Opr.js → architectureDiagram-VXUJARFQ-tjTQ4ZaT.js} +6 -6
  88. package/dist/server/assets/{blockDiagram-VD42YOAC-UhTmqpkK.js → blockDiagram-VD42YOAC-C0oBPtSv.js} +6 -6
  89. package/dist/server/assets/{c4Diagram-YG6GDRKO-BcLh1QQl.js → c4Diagram-YG6GDRKO-nGE1cXwD.js} +2 -2
  90. package/dist/server/assets/{channel-DVtl256s.js → channel-CqQOLgw9.js} +1 -1
  91. package/dist/server/assets/{chunk-4BX2VUAB-BYUElNcW.js → chunk-4BX2VUAB-DrJXJmx5.js} +1 -1
  92. package/dist/server/assets/{chunk-55IACEB6-CQXVz3Ix.js → chunk-55IACEB6-CKxRFH9J.js} +1 -1
  93. package/dist/server/assets/{chunk-B4BG7PRW-xbFaXlOL.js → chunk-B4BG7PRW-BxyNZV2w.js} +4 -4
  94. package/dist/server/assets/{chunk-DI55MBZ5-BWUyQjGD.js → chunk-DI55MBZ5-CajwqGPE.js} +3 -3
  95. package/dist/server/assets/{chunk-FMBD7UC4-tuJ9minw.js → chunk-FMBD7UC4-D1CO-v-G.js} +1 -1
  96. package/dist/server/assets/{chunk-QN33PNHL-B9p522HA.js → chunk-QN33PNHL-D4KiZklP.js} +1 -1
  97. package/dist/server/assets/{chunk-QZHKN3VN-C6GPdMrh.js → chunk-QZHKN3VN-CNElfh9C.js} +1 -1
  98. package/dist/server/assets/{chunk-TZMSLE5B-6Ng3t3Od.js → chunk-TZMSLE5B-CHBqvPAr.js} +1 -1
  99. package/dist/server/assets/{classDiagram-v2-WZHVMYZB-BvOdRP7s.js → classDiagram-2ON5EDUG-D3C4Rk7Q.js} +5 -5
  100. package/dist/server/assets/{classDiagram-2ON5EDUG-BvOdRP7s.js → classDiagram-v2-WZHVMYZB-D3C4Rk7Q.js} +5 -5
  101. package/dist/server/assets/{clone-CuDKCzEN.js → clone-DsPS0_DH.js} +1 -1
  102. package/dist/server/assets/{cose-bilkent-S5V4N54A-BhU6LMhN.js → cose-bilkent-S5V4N54A-V_MYkZlm.js} +1 -1
  103. package/dist/server/assets/{dagre-6UL2VRFP-CH-VbyTI.js → dagre-6UL2VRFP-D_Mh5gNH.js} +6 -6
  104. package/dist/server/assets/{diagram-PSM6KHXK-BE0vVJdc.js → diagram-PSM6KHXK-B9dGPsE9.js} +7 -7
  105. package/dist/server/assets/{diagram-QEK2KX5R-rlYyF51_.js → diagram-QEK2KX5R-BcfmavO-.js} +6 -6
  106. package/dist/server/assets/{diagram-S2PKOQOG-CsrxbKjr.js → diagram-S2PKOQOG-B8urPf9c.js} +6 -6
  107. package/dist/server/assets/{erDiagram-Q2GNP2WA-DeBKeqCX.js → erDiagram-Q2GNP2WA-CzG0zKt-.js} +4 -4
  108. package/dist/server/assets/{flowDiagram-NV44I4VS-hg6b4dSR.js → flowDiagram-NV44I4VS-Bk7aIalC.js} +5 -5
  109. package/dist/server/assets/{ganttDiagram-JELNMOA3-oy5gzveG.js → ganttDiagram-JELNMOA3-wmt8nm9q.js} +2 -2
  110. package/dist/server/assets/{gitGraph-G5XIXVHT-DyKGpXFt.js → gitGraph-G5XIXVHT-CmiFNHiv.js} +6 -6
  111. package/dist/server/assets/{gitGraphDiagram-V2S2FVAM-CN8rFh7o.js → gitGraphDiagram-V2S2FVAM-OV2DR1Ux.js} +7 -7
  112. package/dist/server/assets/{graph-CdsnxBHP.js → graph-ziMVg61H.js} +2 -2
  113. package/dist/server/assets/{highlighted-body-B3W2YXNL-D6ahbJdi.js → highlighted-body-B3W2YXNL-DX00yTJM.js} +1 -1
  114. package/dist/server/assets/{index-BJorH749.js → index-9M09S61v.js} +2 -2
  115. package/dist/server/assets/{index-Crgd09US.js → index-B5x9IUkQ.js} +2 -2
  116. package/dist/server/assets/{index-CaRM9svU.js → index-BvBMEwhL.js} +4 -4
  117. package/dist/server/assets/{index-D2P0pxCr.js → index-C-k9sCKq.js} +2 -2
  118. package/dist/server/assets/{index-BhJN38EV.js → index-CKmyLecf.js} +2 -2
  119. package/dist/server/assets/{index-DsLZMKNC.js → index-CXnsJrX8.js} +5 -5
  120. package/dist/server/assets/{index-CchdHjwq.js → index-Ce2uXVrE.js} +2 -2
  121. package/dist/server/assets/{index-BT8sxrq0.js → index-CiWhFogO.js} +2 -2
  122. package/dist/server/assets/{index-CsnrxvSd.js → index-D5nqcxSY.js} +3 -3
  123. package/dist/server/assets/{index-BzYp7sVL.js → index-DLmI6-iR.js} +1 -1
  124. package/dist/server/assets/{index-C9H7VUtp.js → index-DNaA-OTp.js} +2 -2
  125. package/dist/server/assets/{index-7k2BqwZv.js → index-DPAkuW3l.js} +2 -2
  126. package/dist/server/assets/{index-XaoY6ovr.js → index-VtjR2oZj.js} +2 -2
  127. package/dist/server/assets/{index-DBbuiN2t.js → index-ayG05uhc.js} +3 -3
  128. package/dist/server/assets/{index-B9hFfb3C.js → index-l8a7u6GS.js} +2 -2
  129. package/dist/server/assets/{index-Dp5TbN68.js → index-sKmEy2Z2.js} +5 -5
  130. package/dist/server/assets/{index-aOrOBCQS.js → index-sbo2EHgw.js} +2 -2
  131. package/dist/server/assets/{index-DIv5BUol.js → index-xVhCXu45.js} +2 -2
  132. package/dist/server/assets/{info-VBDWY6EO-HckNvgz-.js → info-VBDWY6EO-muqpsCRw.js} +6 -6
  133. package/dist/server/assets/{infoDiagram-HS3SLOUP-P_hugt8D.js → infoDiagram-HS3SLOUP-D8EoxteQ.js} +5 -5
  134. package/dist/server/assets/{journeyDiagram-XKPGCS4Q-lQfkL_-i.js → journeyDiagram-XKPGCS4Q-BwZk-fnC.js} +4 -4
  135. package/dist/server/assets/{kanban-definition-3W4ZIXB7-CFh-YdaO.js → kanban-definition-3W4ZIXB7-DEfYos8T.js} +2 -2
  136. package/dist/server/assets/{layout-Ce1d_Ibk.js → layout-CKMmyz2h.js} +4 -4
  137. package/dist/server/assets/{linear-CuiUQTrq.js → linear-DXR7qYUB.js} +1 -1
  138. package/dist/server/assets/{mermaid-3ZIDBTTL-C7xGj9Xg.js → mermaid-3ZIDBTTL-DxhML77C.js} +1 -1
  139. package/dist/server/assets/{mermaid-parser.core-BOlp9l_E.js → mermaid-parser.core-DBGA5y48.js} +11 -11
  140. package/dist/server/assets/{mindmap-definition-VGOIOE7T-Byc-qFo2.js → mindmap-definition-VGOIOE7T-Bg8B0Ls9.js} +3 -3
  141. package/dist/server/assets/{packet-DYOGHKS2-BiRLh9CC.js → packet-DYOGHKS2-CnH_YgfD.js} +6 -6
  142. package/dist/server/assets/{pie-VRWISCQL-hgf7Lgm4.js → pie-VRWISCQL-iceCWNPC.js} +6 -6
  143. package/dist/server/assets/{pieDiagram-ADFJNKIX-YXV3ET4_.js → pieDiagram-ADFJNKIX-Bw3RR9nb.js} +7 -7
  144. package/dist/server/assets/{quadrantDiagram-AYHSOK5B-r_peNHCA.js → quadrantDiagram-AYHSOK5B-CpLsW_Ir.js} +2 -2
  145. package/dist/server/assets/{radar-ZZBFDIW7-CGIDKJlK.js → radar-ZZBFDIW7-Bab4MCR4.js} +6 -6
  146. package/dist/server/assets/{requirementDiagram-UZGBJVZJ-aI3jQPLf.js → requirementDiagram-UZGBJVZJ-DkGtaEnw.js} +3 -3
  147. package/dist/server/assets/{router-BNIoB7QX.js → router-yk-AJHab.js} +1119 -880
  148. package/dist/server/assets/{sankeyDiagram-TZEHDZUN-B1Sb9Zvd.js → sankeyDiagram-TZEHDZUN-CtEV3_Bx.js} +1 -1
  149. package/dist/server/assets/{sequenceDiagram-WL72ISMW-DrJxigNy.js → sequenceDiagram-WL72ISMW-BMW4qEme.js} +3 -3
  150. package/dist/server/assets/{square-terminal-DWTC1p8r.js → square-terminal-Bui9B6KN.js} +1 -1
  151. package/dist/server/assets/{stateDiagram-FKZM4ZOC-Dnsp85zH.js → stateDiagram-FKZM4ZOC-C7xazM8E.js} +8 -8
  152. package/dist/server/assets/{stateDiagram-v2-4FDKWEC3-C6x8SVRv.js → stateDiagram-v2-4FDKWEC3-D_rYvDGP.js} +4 -4
  153. package/dist/server/assets/{timeline-definition-IT6M3QCI-DSIrepaO.js → timeline-definition-IT6M3QCI-BaAlfxrc.js} +2 -2
  154. package/dist/server/assets/{treemap-GDKQZRPO-C9hefMmZ.js → treemap-GDKQZRPO-DlP1TABE.js} +6 -6
  155. package/dist/server/assets/{workspace._workspaceId-BY5hpCRH.js → workspace._workspaceId-Be45P7LL.js} +2 -2
  156. package/dist/server/assets/{workspace._workspaceId.changes-CiekaeTG.js → workspace._workspaceId.changes-EoyIscxQ.js} +1 -1
  157. package/dist/server/assets/{workspace._workspaceId.code._-Bi-RxK7c.js → workspace._workspaceId.code._-CcX7Gt0G.js} +1 -1
  158. package/dist/server/assets/{workspace._workspaceId.code.index-DRR8qo6z.js → workspace._workspaceId.code.index-CFbCDVph.js} +1 -1
  159. package/dist/server/assets/{workspace._workspaceId.index-BRFgw3FA.js → workspace._workspaceId.index-DmYHy6nH.js} +1 -1
  160. package/dist/server/assets/{workspace._workspaceId.terminal-BhyASMi7.js → workspace._workspaceId.terminal-D_KPwmYr.js} +2 -2
  161. package/dist/server/assets/{xychartDiagram-PRI3JC2R-0ftH7hFg.js → xychartDiagram-PRI3JC2R-Cq7t_yS-.js} +2 -2
  162. package/dist/server/server.js +2 -2
  163. package/dist/start-server.mjs +710 -467
  164. package/package.json +6 -5
  165. package/dist/client/assets/TerminalPanel-CJRwWyR3.js +0 -4
  166. package/dist/client/assets/channel-CXGOk1aw.js +0 -1
  167. package/dist/client/assets/classDiagram-2ON5EDUG-CN-WyCFd.js +0 -1
  168. package/dist/client/assets/classDiagram-v2-WZHVMYZB-CN-WyCFd.js +0 -1
  169. package/dist/client/assets/clone-BLJrTeWA.js +0 -1
  170. package/dist/client/assets/index-eX1Ljh4a.js +0 -1
  171. package/dist/client/assets/main-DYrDxnSM.css +0 -1
  172. package/dist/client/assets/stateDiagram-v2-4FDKWEC3-B0Y2fSqT.js +0 -1
  173. package/dist/client/assets/workspace._workspaceId.code-Cc2uBW1l.js +0 -1
@@ -6501,11 +6501,11 @@ var require_tools = __commonJS({
6501
6501
  }
6502
6502
  }
6503
6503
  }
6504
- function buildFormatters(level, bindings, log27) {
6504
+ function buildFormatters(level, bindings, log28) {
6505
6505
  return {
6506
6506
  level,
6507
6507
  bindings,
6508
- log: log27
6508
+ log: log28
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: log27 } = options2.formatters;
6891
+ const { level, bindings: chindings, log: log28 } = options2.formatters;
6892
6892
  instance[formattersSym] = buildFormatters(
6893
6893
  level || formatters.level,
6894
6894
  chindings || resetChildingsFormatter,
6895
- log27 || formatters.log
6895
+ log28 || 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, log27 = "error") {
86577
+ function checkOptions(checkOpts, options2, msg, log28 = "error") {
86578
86578
  for (const key in checkOpts) {
86579
86579
  const opt = key;
86580
86580
  if (opt in options2)
86581
- this.logger[log27](`${msg}: option ${key}. ${checkOpts[opt]}`);
86581
+ this.logger[log28](`${msg}: option ${key}. ${checkOpts[opt]}`);
86582
86582
  }
86583
86583
  }
86584
86584
  function getSchEnv(keyRef) {
@@ -108374,7 +108374,7 @@ init_src();
108374
108374
 
108375
108375
  // src/lib/state.ts
108376
108376
  import { randomBytes } from "node:crypto";
108377
- import { mkdirSync as mkdirSync3, readFileSync as readFileSync4, renameSync as renameSync2, writeFileSync } from "node:fs";
108377
+ import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync4, renameSync as renameSync2, writeFileSync } from "node:fs";
108378
108378
  import { homedir as homedir6 } from "node:os";
108379
108379
  import { dirname, join as join11 } from "node:path";
108380
108380
 
@@ -120182,12 +120182,15 @@ var import_jsx_runtime52 = __toESM(require_jsx_runtime(), 1);
120182
120182
  var import_react19 = __toESM(require_react(), 1);
120183
120183
  var import_jsx_runtime53 = __toESM(require_jsx_runtime(), 1);
120184
120184
 
120185
+ // ../../packages/dashboard-core/src/components/PromoteToGitDialog.tsx
120186
+ var import_jsx_runtime54 = __toESM(require_jsx_runtime(), 1);
120187
+
120185
120188
  // ../../packages/dashboard-core/src/components/WorkspaceCard.tsx
120186
120189
  var import_lucide_react5 = __toESM(require_lucide_react(), 1);
120187
120190
  var import_react20 = __toESM(require_react(), 1);
120188
120191
 
120189
120192
  // ../../packages/dashboard-core/src/components/GitStatusIndicator.tsx
120190
- var import_jsx_runtime54 = __toESM(require_jsx_runtime(), 1);
120193
+ var import_jsx_runtime55 = __toESM(require_jsx_runtime(), 1);
120191
120194
  function GitStatusIndicator({ git }) {
120192
120195
  const parts = [];
120193
120196
  if (git.conflict) {
@@ -120219,27 +120222,27 @@ function GitStatusIndicator({ git }) {
120219
120222
  });
120220
120223
  }
120221
120224
  if (parts.length === 0) return null;
120222
- return /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(Tooltip2, { children: [
120223
- /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(TooltipTrigger2, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: "inline-flex items-center gap-0.5 font-mono text-[11px] leading-none shrink-0 pr-0.5", children: parts.map((p6) => /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: p6.color, children: p6.text }, p6.text)) }) }),
120224
- /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(TooltipContent2, { children: parts.map((p6) => p6.tooltip).join(", ") })
120225
+ return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)(Tooltip2, { children: [
120226
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(TooltipTrigger2, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("span", { className: "inline-flex items-center gap-0.5 font-mono text-[11px] leading-none shrink-0 pr-0.5", children: parts.map((p6) => /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("span", { className: p6.color, children: p6.text }, p6.text)) }) }),
120227
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(TooltipContent2, { children: parts.map((p6) => p6.tooltip).join(", ") })
120225
120228
  ] });
120226
120229
  }
120227
120230
 
120228
120231
  // ../../packages/dashboard-core/src/components/SetupStatusIndicator.tsx
120229
120232
  var import_lucide_react4 = __toESM(require_lucide_react(), 1);
120230
- var import_jsx_runtime55 = __toESM(require_jsx_runtime(), 1);
120233
+ var import_jsx_runtime56 = __toESM(require_jsx_runtime(), 1);
120231
120234
  function SetupStatusIndicator({ setup }) {
120232
120235
  if (!setup) return null;
120233
120236
  if (setup.state === "running") {
120234
- return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)(Tooltip2, { children: [
120235
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(TooltipTrigger2, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(import_lucide_react4.Loader, { className: "size-3.5 shrink-0 text-blue-600 dark:text-blue-400 animate-spin" }) }),
120236
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(TooltipContent2, { side: "top", children: "Setting up workspace..." })
120237
+ return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(Tooltip2, { children: [
120238
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(TooltipTrigger2, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_lucide_react4.Loader, { className: "size-3.5 shrink-0 text-blue-600 dark:text-blue-400 animate-spin" }) }),
120239
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(TooltipContent2, { side: "top", children: "Setting up workspace..." })
120237
120240
  ] });
120238
120241
  }
120239
120242
  if (setup.state === "failed") {
120240
- return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)(Tooltip2, { children: [
120241
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(TooltipTrigger2, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(import_lucide_react4.CircleAlert, { className: "size-3.5 shrink-0 text-red-600 dark:text-red-400" }) }),
120242
- /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)(TooltipContent2, { side: "top", children: [
120243
+ return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(Tooltip2, { children: [
120244
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(TooltipTrigger2, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_lucide_react4.CircleAlert, { className: "size-3.5 shrink-0 text-red-600 dark:text-red-400" }) }),
120245
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(TooltipContent2, { side: "top", children: [
120243
120246
  "Setup failed",
120244
120247
  setup.error ? `: ${setup.error}` : ""
120245
120248
  ] })
@@ -120249,11 +120252,32 @@ function SetupStatusIndicator({ setup }) {
120249
120252
  }
120250
120253
 
120251
120254
  // ../../packages/dashboard-core/src/components/WorkspaceCard.tsx
120252
- var import_jsx_runtime56 = __toESM(require_jsx_runtime(), 1);
120255
+ var import_jsx_runtime57 = __toESM(require_jsx_runtime(), 1);
120256
+ var RECENT_ACTIVATION_WINDOW_MS = 300;
120257
+ var recentlyActivatedWorkspaceId = null;
120258
+ var recentlyActivatedTimer = null;
120259
+ function markRecentActivation(workspaceId) {
120260
+ recentlyActivatedWorkspaceId = workspaceId;
120261
+ if (recentlyActivatedTimer) clearTimeout(recentlyActivatedTimer);
120262
+ recentlyActivatedTimer = setTimeout(() => {
120263
+ recentlyActivatedWorkspaceId = null;
120264
+ recentlyActivatedTimer = null;
120265
+ }, RECENT_ACTIVATION_WINDOW_MS);
120266
+ }
120267
+ function consumeRecentActivation(workspaceId) {
120268
+ if (recentlyActivatedWorkspaceId !== workspaceId) return false;
120269
+ recentlyActivatedWorkspaceId = null;
120270
+ if (recentlyActivatedTimer) {
120271
+ clearTimeout(recentlyActivatedTimer);
120272
+ recentlyActivatedTimer = null;
120273
+ }
120274
+ return true;
120275
+ }
120253
120276
  var WorkspaceCard = (0, import_react20.memo)(function WorkspaceCard2({
120254
120277
  worktree,
120255
120278
  projectName,
120256
120279
  defaultBranch,
120280
+ projectKind,
120257
120281
  status,
120258
120282
  branchStatus,
120259
120283
  setupStatus,
@@ -120262,13 +120286,9 @@ var WorkspaceCard = (0, import_react20.memo)(function WorkspaceCard2({
120262
120286
  showProjectName,
120263
120287
  onTogglePinned
120264
120288
  }) {
120289
+ const isPlain = projectKind === "plain";
120265
120290
  const cardRef = (0, import_react20.useRef)(null);
120266
120291
  const capabilities = useCapabilities();
120267
- (0, import_react20.useEffect)(() => {
120268
- if (isFocused) {
120269
- cardRef.current?.scrollIntoView({ block: "nearest" });
120270
- }
120271
- }, [isFocused]);
120272
120292
  const openWorkspace = useDashboardStore((s6) => s6.openWorkspace);
120273
120293
  const clearNeedsAttention = useDashboardStore((s6) => s6.clearNeedsAttention);
120274
120294
  const runScript = useDashboardStore((s6) => s6.runScript);
@@ -120279,8 +120299,14 @@ var WorkspaceCard = (0, import_react20.memo)(function WorkspaceCard2({
120279
120299
  const workspaceId = toWorkspaceId(projectName, worktree.branch);
120280
120300
  const isActive = useDashboardStore((s6) => s6.activeWorkspaceId === workspaceId);
120281
120301
  const href = capabilities.getWorkspaceHref?.(workspaceId);
120302
+ (0, import_react20.useEffect)(() => {
120303
+ if (!isActive) return;
120304
+ if (consumeRecentActivation(workspaceId)) return;
120305
+ cardRef.current?.scrollIntoView({ block: "center" });
120306
+ }, [isActive, workspaceId]);
120282
120307
  const handleClick = () => {
120283
120308
  clearNeedsAttention(workspaceId);
120309
+ markRecentActivation(workspaceId);
120284
120310
  if (href && capabilities.navigate) {
120285
120311
  capabilities.navigate(href);
120286
120312
  } else if (!href) {
@@ -120292,6 +120318,12 @@ var WorkspaceCard = (0, import_react20.memo)(function WorkspaceCard2({
120292
120318
  ref: cardRef,
120293
120319
  className,
120294
120320
  tabIndex: 0,
120321
+ // Semantic markers — let tests, screen readers, and future styling
120322
+ // changes target the active card without depending on the Tailwind
120323
+ // class string. `aria-current="page"` is the standard ARIA pattern for
120324
+ // "currently-active link in a list of related links".
120325
+ "data-active": isActive || void 0,
120326
+ "aria-current": isActive ? "page" : void 0,
120295
120327
  onClick: (e2) => {
120296
120328
  e2.stopPropagation();
120297
120329
  handleClick();
@@ -120320,12 +120352,12 @@ var WorkspaceCard = (0, import_react20.memo)(function WorkspaceCard2({
120320
120352
  });
120321
120353
  }
120322
120354
  };
120323
- return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(ContextMenu2, { children: [
120324
- /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(ContextMenuTrigger2, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { ...containerProps, children: [
120325
- /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(Tooltip2, { children: [
120326
- /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(TooltipTrigger2, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "flex items-center gap-2 min-w-0 overflow-hidden", children: [
120327
- /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(AgentStatusIndicator, { agent: status?.agent, isActive }),
120328
- /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
120355
+ return /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(ContextMenu2, { children: [
120356
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(ContextMenuTrigger2, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { ...containerProps, children: [
120357
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(Tooltip2, { children: [
120358
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(TooltipTrigger2, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { className: "flex items-center gap-2 min-w-0 overflow-hidden", children: [
120359
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(AgentStatusIndicator, { agent: status?.agent, isActive }),
120360
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(
120329
120361
  "span",
120330
120362
  {
120331
120363
  className: `text-sm truncate ${isActive ? "font-semibold text-foreground" : "font-medium text-muted-foreground"}`,
@@ -120333,46 +120365,46 @@ var WorkspaceCard = (0, import_react20.memo)(function WorkspaceCard2({
120333
120365
  }
120334
120366
  )
120335
120367
  ] }) }),
120336
- /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(TooltipContent2, { side: "top", children: showProjectName ? worktree.path : worktree.branch })
120368
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(TooltipContent2, { side: "top", children: showProjectName ? worktree.path : worktree.branch })
120337
120369
  ] }),
120338
- /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: "hidden @[10rem]:flex group-hover:flex items-center gap-2 shrink-0 ml-auto pl-2", children: [
120339
- /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(SetupStatusIndicator, { setup: setupStatus }),
120340
- branchStatus && /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(GitStatusIndicator, { git: branchStatus.git }),
120341
- branchStatus && /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(CIStatusIndicator, { ci: branchStatus.ci })
120370
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)("div", { className: "hidden @[10rem]:flex group-hover:flex items-center gap-2 shrink-0 ml-auto pl-2", children: [
120371
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(SetupStatusIndicator, { setup: setupStatus }),
120372
+ !isPlain && branchStatus && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(GitStatusIndicator, { git: branchStatus.git }),
120373
+ !isPlain && branchStatus && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(CIStatusIndicator, { ci: branchStatus.ci })
120342
120374
  ] })
120343
120375
  ] }) }),
120344
- /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(ContextMenuContent2, { children: [
120345
- /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(ContextMenuItem2, { onClick: () => onTogglePinned(projectName, worktree.branch, isPinned), children: [
120346
- isPinned ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_lucide_react5.PinOff, {}) : /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_lucide_react5.Pin, {}),
120376
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(ContextMenuContent2, { children: [
120377
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(ContextMenuItem2, { onClick: () => onTogglePinned(projectName, worktree.branch, isPinned), children: [
120378
+ isPinned ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(import_lucide_react5.PinOff, {}) : /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(import_lucide_react5.Pin, {}),
120347
120379
  isPinned ? "Unpin workspace" : "Pin workspace"
120348
120380
  ] }),
120349
- /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(ContextMenuSeparator2, {}),
120350
- capabilities.copyPath && /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(ContextMenuItem2, { onClick: () => navigator.clipboard.writeText(worktree.path), children: [
120351
- /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_lucide_react5.Clipboard, {}),
120381
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(ContextMenuSeparator2, {}),
120382
+ capabilities.copyPath && /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(ContextMenuItem2, { onClick: () => navigator.clipboard.writeText(worktree.path), children: [
120383
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(import_lucide_react5.Clipboard, {}),
120352
120384
  "Copy path"
120353
120385
  ] }),
120354
- capabilities.revealInFinder && /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(ContextMenuItem2, { onClick: () => capabilities.revealInFinder(worktree.path), children: [
120355
- /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_lucide_react5.FolderOpen, {}),
120386
+ capabilities.revealInFinder && /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(ContextMenuItem2, { onClick: () => capabilities.revealInFinder(worktree.path), children: [
120387
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(import_lucide_react5.FolderOpen, {}),
120356
120388
  "Open in Finder"
120357
120389
  ] }),
120358
- worktree.hasSetup && /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(ContextMenuItem2, { onClick: () => runScript(worktree.path, "setup"), children: [
120359
- /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_lucide_react5.Play, {}),
120390
+ worktree.hasSetup && /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(ContextMenuItem2, { onClick: () => runScript(worktree.path, "setup"), children: [
120391
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(import_lucide_react5.Play, {}),
120360
120392
  "Run setup"
120361
120393
  ] }),
120362
- worktree.hasTeardown && /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(ContextMenuItem2, { onClick: () => runScript(worktree.path, "teardown"), children: [
120363
- /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_lucide_react5.Square, {}),
120394
+ worktree.hasTeardown && /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(ContextMenuItem2, { onClick: () => runScript(worktree.path, "teardown"), children: [
120395
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(import_lucide_react5.Square, {}),
120364
120396
  "Run teardown"
120365
120397
  ] }),
120366
- /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(ContextMenuItem2, { onClick: () => gitPull(projectName, worktree.branch), children: [
120367
- /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_lucide_react5.ArrowDownToLine, {}),
120398
+ !isPlain && /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(ContextMenuItem2, { onClick: () => gitPull(projectName, worktree.branch), children: [
120399
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(import_lucide_react5.ArrowDownToLine, {}),
120368
120400
  "Git pull"
120369
120401
  ] }),
120370
- /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(ContextMenuItem2, { onClick: () => gitPush(projectName, worktree.branch), children: [
120371
- /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_lucide_react5.ArrowUpFromLine, {}),
120402
+ !isPlain && /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(ContextMenuItem2, { onClick: () => gitPush(projectName, worktree.branch), children: [
120403
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(import_lucide_react5.ArrowUpFromLine, {}),
120372
120404
  "Git push"
120373
120405
  ] }),
120374
- worktree.branch !== defaultBranch && /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(ContextMenuItem2, { variant: "destructive", onClick: handleDelete, children: [
120375
- /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_lucide_react5.Trash2, {}),
120406
+ !isPlain && worktree.branch !== defaultBranch && /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(ContextMenuItem2, { variant: "destructive", onClick: handleDelete, children: [
120407
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(import_lucide_react5.Trash2, {}),
120376
120408
  "Delete workspace"
120377
120409
  ] })
120378
120410
  ] })
@@ -120380,7 +120412,7 @@ var WorkspaceCard = (0, import_react20.memo)(function WorkspaceCard2({
120380
120412
  });
120381
120413
 
120382
120414
  // ../../packages/dashboard-core/src/components/ProjectList.tsx
120383
- var import_jsx_runtime57 = __toESM(require_jsx_runtime(), 1);
120415
+ var import_jsx_runtime58 = __toESM(require_jsx_runtime(), 1);
120384
120416
 
120385
120417
  // ../../packages/dashboard-core/src/components/SettingsPage.tsx
120386
120418
  var import_react23 = __toESM(require_react(), 1);
@@ -120389,28 +120421,31 @@ var import_react23 = __toESM(require_react(), 1);
120389
120421
  var import_react22 = __toESM(require_react(), 1);
120390
120422
 
120391
120423
  // ../../packages/dashboard-core/src/components/settings/SettingsRow.tsx
120392
- var import_jsx_runtime58 = __toESM(require_jsx_runtime(), 1);
120424
+ var import_jsx_runtime59 = __toESM(require_jsx_runtime(), 1);
120393
120425
 
120394
120426
  // ../../packages/dashboard-core/src/components/settings/SettingsSection.tsx
120395
- var import_jsx_runtime59 = __toESM(require_jsx_runtime(), 1);
120427
+ var import_jsx_runtime60 = __toESM(require_jsx_runtime(), 1);
120396
120428
 
120397
120429
  // ../../packages/dashboard-core/src/components/SettingsPage.tsx
120398
- var import_jsx_runtime60 = __toESM(require_jsx_runtime(), 1);
120430
+ var import_jsx_runtime61 = __toESM(require_jsx_runtime(), 1);
120399
120431
 
120400
120432
  // ../../packages/dashboard-core/src/components/DashboardShell.tsx
120401
- var import_jsx_runtime61 = __toESM(require_jsx_runtime(), 1);
120433
+ var import_jsx_runtime62 = __toESM(require_jsx_runtime(), 1);
120402
120434
  var isElectron = typeof window !== "undefined" && "__BAND_DESKTOP__" in window;
120403
120435
 
120404
120436
  // ../../packages/dashboard-core/src/components/DiffView.tsx
120405
120437
  init_dist4();
120406
- var import_react30 = __toESM(require_react(), 1);
120438
+ var import_react31 = __toESM(require_react(), 1);
120407
120439
 
120408
120440
  // ../../packages/dashboard-core/src/hooks/use-diff-target.ts
120409
120441
  var import_react25 = __toESM(require_react(), 1);
120410
120442
 
120411
- // ../../packages/dashboard-core/src/hooks/use-search.ts
120443
+ // ../../packages/dashboard-core/src/hooks/use-project-kind.ts
120412
120444
  var import_react26 = __toESM(require_react(), 1);
120413
120445
 
120446
+ // ../../packages/dashboard-core/src/hooks/use-search.ts
120447
+ var import_react27 = __toESM(require_react(), 1);
120448
+
120414
120449
  // ../../packages/dashboard-core/src/lib/language-map.ts
120415
120450
  var SUPPORTED_LANGUAGES = [
120416
120451
  { id: "plaintext", label: "Plain Text" },
@@ -120464,16 +120499,16 @@ var SUPPORTED_LANGUAGES = [
120464
120499
  var LANGUAGE_LABEL_BY_ID = new Map(SUPPORTED_LANGUAGES.map((l) => [l.id, l.label]));
120465
120500
 
120466
120501
  // ../../packages/dashboard-core/src/components/ChangesFileTree.tsx
120467
- var import_react28 = __toESM(require_react(), 1);
120502
+ var import_react29 = __toESM(require_react(), 1);
120468
120503
 
120469
120504
  // ../../packages/dashboard-core/src/hooks/use-deferred-menu-action.ts
120470
- var import_react27 = __toESM(require_react(), 1);
120505
+ var import_react28 = __toESM(require_react(), 1);
120471
120506
  function useDeferredMenuAction() {
120472
- const pendingRef = (0, import_react27.useRef)(null);
120473
- const queue = (0, import_react27.useCallback)((fn) => {
120507
+ const pendingRef = (0, import_react28.useRef)(null);
120508
+ const queue = (0, import_react28.useCallback)((fn) => {
120474
120509
  pendingRef.current = fn;
120475
120510
  }, []);
120476
- const flush = (0, import_react27.useCallback)((e2) => {
120511
+ const flush = (0, import_react28.useCallback)((e2) => {
120477
120512
  e2.preventDefault();
120478
120513
  const fn = pendingRef.current;
120479
120514
  pendingRef.current = null;
@@ -120622,18 +120657,18 @@ function getFileIcon(filename) {
120622
120657
  }
120623
120658
 
120624
120659
  // ../../packages/dashboard-core/src/components/FileStatusBadge.tsx
120625
- var import_jsx_runtime62 = __toESM(require_jsx_runtime(), 1);
120660
+ var import_jsx_runtime63 = __toESM(require_jsx_runtime(), 1);
120626
120661
 
120627
120662
  // ../../packages/dashboard-core/src/components/ChangesFileTree.tsx
120628
- var import_jsx_runtime63 = __toESM(require_jsx_runtime(), 1);
120663
+ var import_jsx_runtime64 = __toESM(require_jsx_runtime(), 1);
120629
120664
 
120630
120665
  // ../../packages/dashboard-core/src/components/RevertFileDialog.tsx
120631
- var import_jsx_runtime64 = __toESM(require_jsx_runtime(), 1);
120666
+ var import_jsx_runtime65 = __toESM(require_jsx_runtime(), 1);
120632
120667
 
120633
120668
  // ../../packages/dashboard-core/src/components/SearchBar.tsx
120634
120669
  var import_lucide_react7 = __toESM(require_lucide_react(), 1);
120635
- var import_react29 = __toESM(require_react(), 1);
120636
- var import_jsx_runtime65 = __toESM(require_jsx_runtime(), 1);
120670
+ var import_react30 = __toESM(require_react(), 1);
120671
+ var import_jsx_runtime66 = __toESM(require_jsx_runtime(), 1);
120637
120672
  var DEFAULT_VISIBLE_OPTIONS = ["caseSensitive", "wholeWord", "regex"];
120638
120673
  function ToggleButton({
120639
120674
  active,
@@ -120641,7 +120676,7 @@ function ToggleButton({
120641
120676
  title,
120642
120677
  children
120643
120678
  }) {
120644
- return /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
120679
+ return /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
120645
120680
  "button",
120646
120681
  {
120647
120682
  type: "button",
@@ -120652,7 +120687,7 @@ function ToggleButton({
120652
120687
  }
120653
120688
  );
120654
120689
  }
120655
- var SearchBar = (0, import_react29.forwardRef)(function SearchBar2({
120690
+ var SearchBar = (0, import_react30.forwardRef)(function SearchBar2({
120656
120691
  query,
120657
120692
  onQueryChange,
120658
120693
  options: options2,
@@ -120668,27 +120703,27 @@ var SearchBar = (0, import_react29.forwardRef)(function SearchBar2({
120668
120703
  const showCase = visibleOptions.includes("caseSensitive");
120669
120704
  const showWholeWord = visibleOptions.includes("wholeWord");
120670
120705
  const showRegex = visibleOptions.includes("regex");
120671
- const inputRef = (0, import_react29.useRef)(null);
120672
- (0, import_react29.useImperativeHandle)(ref, () => ({
120706
+ const inputRef = (0, import_react30.useRef)(null);
120707
+ (0, import_react30.useImperativeHandle)(ref, () => ({
120673
120708
  focus: () => inputRef.current?.focus(),
120674
120709
  select: () => inputRef.current?.select()
120675
120710
  }));
120676
- const toggleCase = (0, import_react29.useCallback)(() => {
120711
+ const toggleCase = (0, import_react30.useCallback)(() => {
120677
120712
  onOptionsChange({ ...options2, caseSensitive: !options2.caseSensitive });
120678
120713
  }, [options2, onOptionsChange]);
120679
- const toggleWholeWord = (0, import_react29.useCallback)(() => {
120714
+ const toggleWholeWord = (0, import_react30.useCallback)(() => {
120680
120715
  onOptionsChange({ ...options2, wholeWord: !options2.wholeWord });
120681
120716
  }, [options2, onOptionsChange]);
120682
- const toggleRegex = (0, import_react29.useCallback)(() => {
120717
+ const toggleRegex = (0, import_react30.useCallback)(() => {
120683
120718
  onOptionsChange({ ...options2, regex: !options2.regex });
120684
120719
  }, [options2, onOptionsChange]);
120685
- return /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)(
120720
+ return /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(
120686
120721
  "div",
120687
120722
  {
120688
120723
  className: `flex shrink-0 items-center gap-1.5 border-b border-border bg-muted/30 px-3 py-1.5 ${className ?? ""}`,
120689
120724
  children: [
120690
- /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(import_lucide_react7.Search, { className: "size-3.5 shrink-0 text-muted-foreground" }),
120691
- /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
120725
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(import_lucide_react7.Search, { className: "size-3.5 shrink-0 text-muted-foreground" }),
120726
+ /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
120692
120727
  "input",
120693
120728
  {
120694
120729
  ref: inputRef,
@@ -120709,11 +120744,11 @@ var SearchBar = (0, import_react29.forwardRef)(function SearchBar2({
120709
120744
  }
120710
120745
  }
120711
120746
  ),
120712
- showCase && /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(ToggleButton, { active: options2.caseSensitive, onClick: toggleCase, title: "Match Case", children: /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(import_lucide_react7.CaseSensitive, { className: "size-4" }) }),
120713
- showWholeWord && /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(ToggleButton, { active: options2.wholeWord, onClick: toggleWholeWord, title: "Match Whole Word", children: /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(import_lucide_react7.WholeWord, { className: "size-4" }) }),
120714
- showRegex && /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(ToggleButton, { active: options2.regex, onClick: toggleRegex, title: "Use Regular Expression", children: /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(import_lucide_react7.Regex, { className: "size-4" }) }),
120715
- matchInfo && query && /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("span", { className: "shrink-0 text-xs text-muted-foreground tabular-nums", children: matchInfo.total > 0 ? `${matchInfo.current} of ${matchInfo.total}` : "No results" }),
120716
- onPrevious && /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
120747
+ showCase && /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(ToggleButton, { active: options2.caseSensitive, onClick: toggleCase, title: "Match Case", children: /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(import_lucide_react7.CaseSensitive, { className: "size-4" }) }),
120748
+ showWholeWord && /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(ToggleButton, { active: options2.wholeWord, onClick: toggleWholeWord, title: "Match Whole Word", children: /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(import_lucide_react7.WholeWord, { className: "size-4" }) }),
120749
+ showRegex && /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(ToggleButton, { active: options2.regex, onClick: toggleRegex, title: "Use Regular Expression", children: /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(import_lucide_react7.Regex, { className: "size-4" }) }),
120750
+ matchInfo && query && /* @__PURE__ */ (0, import_jsx_runtime66.jsx)("span", { className: "shrink-0 text-xs text-muted-foreground tabular-nums", children: matchInfo.total > 0 ? `${matchInfo.current} of ${matchInfo.total}` : "No results" }),
120751
+ onPrevious && /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
120717
120752
  "button",
120718
120753
  {
120719
120754
  type: "button",
@@ -120721,10 +120756,10 @@ var SearchBar = (0, import_react29.forwardRef)(function SearchBar2({
120721
120756
  disabled: !matchInfo || matchInfo.total === 0,
120722
120757
  className: "inline-flex size-6 items-center justify-center rounded text-muted-foreground hover:text-foreground disabled:opacity-30",
120723
120758
  title: "Previous match (Shift+Enter)",
120724
- children: /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(import_lucide_react7.ChevronUp, { className: "size-3.5" })
120759
+ children: /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(import_lucide_react7.ChevronUp, { className: "size-3.5" })
120725
120760
  }
120726
120761
  ),
120727
- onNext && /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
120762
+ onNext && /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
120728
120763
  "button",
120729
120764
  {
120730
120765
  type: "button",
@@ -120732,17 +120767,17 @@ var SearchBar = (0, import_react29.forwardRef)(function SearchBar2({
120732
120767
  disabled: !matchInfo || matchInfo.total === 0,
120733
120768
  className: "inline-flex size-6 items-center justify-center rounded text-muted-foreground hover:text-foreground disabled:opacity-30",
120734
120769
  title: "Next match (Enter)",
120735
- children: /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(import_lucide_react7.ChevronDown, { className: "size-3.5" })
120770
+ children: /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(import_lucide_react7.ChevronDown, { className: "size-3.5" })
120736
120771
  }
120737
120772
  ),
120738
- onClose && /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
120773
+ onClose && /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
120739
120774
  "button",
120740
120775
  {
120741
120776
  type: "button",
120742
120777
  onClick: onClose,
120743
120778
  className: "inline-flex size-6 items-center justify-center rounded text-muted-foreground hover:text-foreground",
120744
120779
  title: "Close (Escape)",
120745
- children: /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(import_lucide_react7.X, { className: "size-3.5" })
120780
+ children: /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(import_lucide_react7.X, { className: "size-3.5" })
120746
120781
  }
120747
120782
  )
120748
120783
  ]
@@ -120751,7 +120786,7 @@ var SearchBar = (0, import_react29.forwardRef)(function SearchBar2({
120751
120786
  });
120752
120787
 
120753
120788
  // ../../packages/dashboard-core/src/components/DiffView.tsx
120754
- var import_jsx_runtime66 = __toESM(require_jsx_runtime(), 1);
120789
+ var import_jsx_runtime67 = __toESM(require_jsx_runtime(), 1);
120755
120790
  var diffTheme = EditorView.theme({
120756
120791
  ".cm-insertedLine": { backgroundColor: "rgba(34, 197, 94, 0.1)" },
120757
120792
  ".cm-deletedLine": { backgroundColor: "rgba(239, 68, 68, 0.1)" },
@@ -120802,8 +120837,8 @@ var diffTheme = EditorView.theme({
120802
120837
 
120803
120838
  // ../../packages/dashboard-core/src/components/FileBrowser.tsx
120804
120839
  var import_lucide_react8 = __toESM(require_lucide_react(), 1);
120805
- var import_react31 = __toESM(require_react(), 1);
120806
- var import_jsx_runtime67 = __toESM(require_jsx_runtime(), 1);
120840
+ var import_react32 = __toESM(require_react(), 1);
120841
+ var import_jsx_runtime68 = __toESM(require_jsx_runtime(), 1);
120807
120842
  var expandedStateCache = /* @__PURE__ */ new Map();
120808
120843
  var dirContentsCache = /* @__PURE__ */ new Map();
120809
120844
  function getCachedExpanded(wsId) {
@@ -120832,11 +120867,11 @@ function EntryNameInput({
120832
120867
  onSubmit,
120833
120868
  onCancel
120834
120869
  }) {
120835
- const [value, setValue] = (0, import_react31.useState)(initialValue);
120836
- const [submitting, setSubmitting] = (0, import_react31.useState)(false);
120837
- const [error40, setError] = (0, import_react31.useState)(null);
120838
- const inputRef = (0, import_react31.useRef)(null);
120839
- (0, import_react31.useEffect)(() => {
120870
+ const [value, setValue] = (0, import_react32.useState)(initialValue);
120871
+ const [submitting, setSubmitting] = (0, import_react32.useState)(false);
120872
+ const [error40, setError] = (0, import_react32.useState)(null);
120873
+ const inputRef = (0, import_react32.useRef)(null);
120874
+ (0, import_react32.useEffect)(() => {
120840
120875
  const el = inputRef.current;
120841
120876
  if (!el) return;
120842
120877
  el.focus();
@@ -120884,21 +120919,21 @@ function EntryNameInput({
120884
120919
  }
120885
120920
  };
120886
120921
  const Icon = kind === "directory" ? import_lucide_react8.Folder : import_lucide_react8.File;
120887
- return /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("div", { className: "flex w-full flex-col", style: { paddingLeft: `${depth * indent + basePad}px` }, children: [
120888
- /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(
120922
+ return /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("div", { className: "flex w-full flex-col", style: { paddingLeft: `${depth * indent + basePad}px` }, children: [
120923
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(
120889
120924
  "div",
120890
120925
  {
120891
120926
  className: `flex items-center ${compact ? "h-[28px] gap-1 pr-3 text-[13px]" : "h-[32px] gap-1.5 pr-4 text-[15px]"}`,
120892
120927
  style: { height },
120893
120928
  children: [
120894
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("span", { className: "size-3.5 shrink-0" }),
120895
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
120929
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("span", { className: "size-3.5 shrink-0" }),
120930
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
120896
120931
  Icon,
120897
120932
  {
120898
120933
  className: kind === "directory" ? "size-4 shrink-0 text-blue-600 dark:text-blue-400" : "size-4 shrink-0 text-muted-foreground"
120899
120934
  }
120900
120935
  ),
120901
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
120936
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
120902
120937
  "input",
120903
120938
  {
120904
120939
  ref: inputRef,
@@ -120935,7 +120970,7 @@ function EntryNameInput({
120935
120970
  ]
120936
120971
  }
120937
120972
  ),
120938
- error40 && /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
120973
+ error40 && /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
120939
120974
  "div",
120940
120975
  {
120941
120976
  className: "pointer-events-none text-xs text-destructive",
@@ -121002,7 +121037,7 @@ function TreeNode2({
121002
121037
  onOpenFilePinned(entryPath);
121003
121038
  }
121004
121039
  };
121005
- const button = /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(
121040
+ const button = /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(
121006
121041
  "button",
121007
121042
  {
121008
121043
  ref: isSelected ? selectedRef : void 0,
@@ -121015,12 +121050,12 @@ function TreeNode2({
121015
121050
  className: `flex w-full items-center text-left select-none hover:bg-accent/50 [-webkit-touch-callout:none] ${compact ? "h-[28px] gap-1 pr-3 text-[13px]" : "h-[32px] gap-1.5 pr-4 text-[15px]"} ${isSelected ? "bg-blue-500/30 text-foreground outline outline-1 -outline-offset-1 outline-blue-400/60 hover:bg-blue-500/30 dark:bg-blue-500/40 dark:outline-blue-400/70 dark:hover:bg-blue-500/40" : ""} ${isCut ? "opacity-50" : ""}`,
121016
121051
  style: { paddingLeft: `${depth * indent + basePad}px` },
121017
121052
  children: [
121018
- isDir ? isExpanded ? /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(import_lucide_react8.ChevronDown, { className: "size-3.5 shrink-0 text-muted-foreground/70" }) : /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(import_lucide_react8.ChevronRight, { className: "size-3.5 shrink-0 text-muted-foreground/70" }) : /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("span", { className: "size-3.5 shrink-0" }),
121019
- isDir ? isExpanded ? /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(import_lucide_react8.FolderOpen, { className: "size-4 shrink-0 text-blue-600 dark:text-blue-400" }) : /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(import_lucide_react8.Folder, { className: "size-4 shrink-0 text-blue-600 dark:text-blue-400" }) : (() => {
121053
+ isDir ? isExpanded ? /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(import_lucide_react8.ChevronDown, { className: "size-3.5 shrink-0 text-muted-foreground/70" }) : /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(import_lucide_react8.ChevronRight, { className: "size-3.5 shrink-0 text-muted-foreground/70" }) : /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("span", { className: "size-3.5 shrink-0" }),
121054
+ isDir ? isExpanded ? /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(import_lucide_react8.FolderOpen, { className: "size-4 shrink-0 text-blue-600 dark:text-blue-400" }) : /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(import_lucide_react8.Folder, { className: "size-4 shrink-0 text-blue-600 dark:text-blue-400" }) : (() => {
121020
121055
  const FileIcon = getFileIcon(entry.name);
121021
- return /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(FileIcon, { className: "size-4 shrink-0 text-muted-foreground" });
121056
+ return /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(FileIcon, { className: "size-4 shrink-0 text-muted-foreground" });
121022
121057
  })(),
121023
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("span", { className: "min-w-0 flex-1 truncate", children: entry.name })
121058
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("span", { className: "min-w-0 flex-1 truncate", children: entry.name })
121024
121059
  ]
121025
121060
  }
121026
121061
  );
@@ -121042,7 +121077,7 @@ function TreeNode2({
121042
121077
  // a padding div with `depth={0}` would double-apply `basePad`, shifting
121043
121078
  // the input ~4px to the right and giving it visibly less horizontal
121044
121079
  // room than the rest of the tree.
121045
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
121080
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
121046
121081
  EntryNameInput,
121047
121082
  {
121048
121083
  kind: isDir ? "directory" : "file",
@@ -121056,74 +121091,74 @@ function TreeNode2({
121056
121091
  },
121057
121092
  `rename-${entryPath}`
121058
121093
  )
121059
- ) : /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(
121094
+ ) : /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(
121060
121095
  ContextMenu2,
121061
121096
  {
121062
121097
  onOpenChange: (open3) => {
121063
121098
  if (open3) onSelectRow(entryPath, isDir ? "directory" : "file");
121064
121099
  },
121065
121100
  children: [
121066
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(ContextMenuTrigger2, { asChild: true, children: button }),
121067
- /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(ContextMenuContent2, { onCloseAutoFocus: menu.flush, children: [
121068
- isDir && /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(import_jsx_runtime67.Fragment, { children: [
121069
- /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(
121101
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(ContextMenuTrigger2, { asChild: true, children: button }),
121102
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(ContextMenuContent2, { onCloseAutoFocus: menu.flush, children: [
121103
+ isDir && /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(import_jsx_runtime68.Fragment, { children: [
121104
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(
121070
121105
  ContextMenuItem2,
121071
121106
  {
121072
121107
  onSelect: () => menu.queue(() => onRequestNewEntry(entryPath, "file")),
121073
121108
  children: [
121074
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(import_lucide_react8.File, { className: "size-4" }),
121109
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(import_lucide_react8.File, { className: "size-4" }),
121075
121110
  "New File"
121076
121111
  ]
121077
121112
  }
121078
121113
  ),
121079
- /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(
121114
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(
121080
121115
  ContextMenuItem2,
121081
121116
  {
121082
121117
  onSelect: () => menu.queue(() => onRequestNewEntry(entryPath, "directory")),
121083
121118
  children: [
121084
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(import_lucide_react8.FolderPlus, { className: "size-4" }),
121119
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(import_lucide_react8.FolderPlus, { className: "size-4" }),
121085
121120
  "New Folder"
121086
121121
  ]
121087
121122
  }
121088
121123
  ),
121089
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(ContextMenuSeparator2, {})
121124
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(ContextMenuSeparator2, {})
121090
121125
  ] }),
121091
- canCut && /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(
121126
+ canCut && /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(
121092
121127
  ContextMenuItem2,
121093
121128
  {
121094
121129
  onSelect: () => menu.queue(() => onCut(entryPath, isDir ? "directory" : "file")),
121095
121130
  children: [
121096
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(import_lucide_react8.Scissors, { className: "size-4" }),
121131
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(import_lucide_react8.Scissors, { className: "size-4" }),
121097
121132
  "Cut"
121098
121133
  ]
121099
121134
  }
121100
121135
  ),
121101
- canCopy && /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(
121136
+ canCopy && /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(
121102
121137
  ContextMenuItem2,
121103
121138
  {
121104
121139
  onSelect: () => menu.queue(() => onCopy(entryPath, isDir ? "directory" : "file")),
121105
121140
  children: [
121106
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(import_lucide_react8.Copy, { className: "size-4" }),
121141
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(import_lucide_react8.Copy, { className: "size-4" }),
121107
121142
  "Copy"
121108
121143
  ]
121109
121144
  }
121110
121145
  ),
121111
- isDir && canPaste && /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(ContextMenuItem2, { onSelect: () => menu.queue(() => void onPaste(entryPath)), children: [
121112
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(import_lucide_react8.ClipboardPaste, { className: "size-4" }),
121146
+ isDir && canPaste && /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(ContextMenuItem2, { onSelect: () => menu.queue(() => void onPaste(entryPath)), children: [
121147
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(import_lucide_react8.ClipboardPaste, { className: "size-4" }),
121113
121148
  "Paste"
121114
121149
  ] }),
121115
- (canCut || canCopy || isDir && canPaste) && (canRename || canDelete) && /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(ContextMenuSeparator2, {}),
121116
- canRename && /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(ContextMenuItem2, { onSelect: () => menu.queue(() => onRequestRename(entryPath)), children: [
121117
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(import_lucide_react8.Pencil, { className: "size-4" }),
121150
+ (canCut || canCopy || isDir && canPaste) && (canRename || canDelete) && /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(ContextMenuSeparator2, {}),
121151
+ canRename && /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(ContextMenuItem2, { onSelect: () => menu.queue(() => onRequestRename(entryPath)), children: [
121152
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(import_lucide_react8.Pencil, { className: "size-4" }),
121118
121153
  "Rename"
121119
121154
  ] }),
121120
- canDelete && /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(
121155
+ canDelete && /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(
121121
121156
  ContextMenuItem2,
121122
121157
  {
121123
121158
  variant: "destructive",
121124
121159
  onSelect: () => menu.queue(() => onRequestDelete(entryPath, isDir ? "directory" : "file")),
121125
121160
  children: [
121126
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(import_lucide_react8.Trash2, { className: "size-4" }),
121161
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(import_lucide_react8.Trash2, { className: "size-4" }),
121127
121162
  "Delete"
121128
121163
  ]
121129
121164
  }
@@ -121133,13 +121168,13 @@ function TreeNode2({
121133
121168
  }
121134
121169
  );
121135
121170
  const showInlineInput = newEntry?.parentPath === entryPath;
121136
- return /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(import_jsx_runtime67.Fragment, { children: [
121171
+ return /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(import_jsx_runtime68.Fragment, { children: [
121137
121172
  row,
121138
121173
  isExpanded && (() => {
121139
121174
  const splitIdx = children?.findIndex((c2) => c2.type === "file") ?? -1;
121140
121175
  const folderChildren = splitIdx === -1 ? children ?? [] : (children ?? []).slice(0, splitIdx);
121141
121176
  const fileChildren = splitIdx === -1 ? [] : (children ?? []).slice(splitIdx);
121142
- const renderChild = (child) => /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
121177
+ const renderChild = (child) => /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
121143
121178
  TreeNode2,
121144
121179
  {
121145
121180
  entry: child,
@@ -121176,7 +121211,7 @@ function TreeNode2({
121176
121211
  },
121177
121212
  child.name
121178
121213
  );
121179
- const newEntryInput = showInlineInput ? /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
121214
+ const newEntryInput = showInlineInput ? /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
121180
121215
  EntryNameInput,
121181
121216
  {
121182
121217
  kind: newEntry.kind,
@@ -121188,9 +121223,9 @@ function TreeNode2({
121188
121223
  },
121189
121224
  `new-${newEntry.kind}-${entryPath}`
121190
121225
  ) : null;
121191
- return /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(import_jsx_runtime67.Fragment, { children: [
121226
+ return /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(import_jsx_runtime68.Fragment, { children: [
121192
121227
  showInlineInput && newEntry.kind === "directory" && newEntryInput,
121193
- isLoading && !children?.length && /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
121228
+ isLoading && !children?.length && /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
121194
121229
  "div",
121195
121230
  {
121196
121231
  className: `flex items-center text-muted-foreground/70 ${compact ? "text-[13px]" : "text-[15px]"}`,
@@ -121201,7 +121236,7 @@ function TreeNode2({
121201
121236
  children: "Loading\u2026"
121202
121237
  }
121203
121238
  ),
121204
- !isLoading && !showInlineInput && children && children.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
121239
+ !isLoading && !showInlineInput && children && children.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
121205
121240
  "div",
121206
121241
  {
121207
121242
  className: `flex items-center italic text-muted-foreground/50 ${compact ? "text-[13px]" : "text-[15px]"}`,
@@ -121219,7 +121254,7 @@ function TreeNode2({
121219
121254
  })()
121220
121255
  ] });
121221
121256
  }
121222
- var FileBrowser = (0, import_react31.forwardRef)(function FileBrowser2({
121257
+ var FileBrowser = (0, import_react32.forwardRef)(function FileBrowser2({
121223
121258
  workspaceId,
121224
121259
  onOpenFile,
121225
121260
  onOpenFilePinned,
@@ -121229,23 +121264,23 @@ var FileBrowser = (0, import_react31.forwardRef)(function FileBrowser2({
121229
121264
  onPathDeleted
121230
121265
  }, handleRef) {
121231
121266
  const adapter = useAdapter();
121232
- const [expandedPaths, setExpandedPaths] = (0, import_react31.useState)(
121267
+ const [expandedPaths, setExpandedPaths] = (0, import_react32.useState)(
121233
121268
  () => new Set(getCachedExpanded(workspaceId))
121234
121269
  );
121235
- const [dirContents, setDirContents] = (0, import_react31.useState)(
121270
+ const [dirContents, setDirContents] = (0, import_react32.useState)(
121236
121271
  () => new Map(getCachedContents(workspaceId))
121237
121272
  );
121238
- const [loadingPaths, setLoadingPaths] = (0, import_react31.useState)(/* @__PURE__ */ new Set());
121239
- const [newEntry, setNewEntry] = (0, import_react31.useState)(null);
121240
- const [pendingDelete, setPendingDelete] = (0, import_react31.useState)(null);
121241
- const [deleteError, setDeleteError] = (0, import_react31.useState)(null);
121242
- const [deleteSubmitting, setDeleteSubmitting] = (0, import_react31.useState)(false);
121243
- const [renamingPath, setRenamingPath] = (0, import_react31.useState)(null);
121244
- const [clipboard, setClipboard] = (0, import_react31.useState)(null);
121245
- const [treeSelection, setTreeSelection] = (0, import_react31.useState)(() => selectedFile ? { path: selectedFile, kind: "file" } : null);
121246
- const selectedRef = (0, import_react31.useRef)(null);
121247
- const prevWorkspaceRef = (0, import_react31.useRef)(workspaceId);
121248
- (0, import_react31.useEffect)(() => {
121273
+ const [loadingPaths, setLoadingPaths] = (0, import_react32.useState)(/* @__PURE__ */ new Set());
121274
+ const [newEntry, setNewEntry] = (0, import_react32.useState)(null);
121275
+ const [pendingDelete, setPendingDelete] = (0, import_react32.useState)(null);
121276
+ const [deleteError, setDeleteError] = (0, import_react32.useState)(null);
121277
+ const [deleteSubmitting, setDeleteSubmitting] = (0, import_react32.useState)(false);
121278
+ const [renamingPath, setRenamingPath] = (0, import_react32.useState)(null);
121279
+ const [clipboard, setClipboard] = (0, import_react32.useState)(null);
121280
+ const [treeSelection, setTreeSelection] = (0, import_react32.useState)(() => selectedFile ? { path: selectedFile, kind: "file" } : null);
121281
+ const selectedRef = (0, import_react32.useRef)(null);
121282
+ const prevWorkspaceRef = (0, import_react32.useRef)(workspaceId);
121283
+ (0, import_react32.useEffect)(() => {
121249
121284
  if (prevWorkspaceRef.current !== workspaceId) {
121250
121285
  prevWorkspaceRef.current = workspaceId;
121251
121286
  setExpandedPaths(new Set(getCachedExpanded(workspaceId)));
@@ -121260,18 +121295,18 @@ var FileBrowser = (0, import_react31.forwardRef)(function FileBrowser2({
121260
121295
  setClipboard(null);
121261
121296
  }
121262
121297
  }, [workspaceId]);
121263
- (0, import_react31.useEffect)(() => {
121298
+ (0, import_react32.useEffect)(() => {
121264
121299
  if (selectedFile) {
121265
121300
  setTreeSelection({ path: selectedFile, kind: "file" });
121266
121301
  }
121267
121302
  }, [selectedFile]);
121268
- const handleSelectRow = (0, import_react31.useCallback)((path3, kind) => {
121303
+ const handleSelectRow = (0, import_react32.useCallback)((path3, kind) => {
121269
121304
  setTreeSelection({ path: path3, kind });
121270
121305
  }, []);
121271
- const clearTreeSelection = (0, import_react31.useCallback)(() => {
121306
+ const clearTreeSelection = (0, import_react32.useCallback)(() => {
121272
121307
  setTreeSelection(null);
121273
121308
  }, []);
121274
- const fetchDir = (0, import_react31.useCallback)(
121309
+ const fetchDir = (0, import_react32.useCallback)(
121275
121310
  async (dirPath, opts) => {
121276
121311
  if (!adapter.listWorkspaceFiles) return;
121277
121312
  const cache = getCachedContents(workspaceId);
@@ -121295,10 +121330,10 @@ var FileBrowser = (0, import_react31.forwardRef)(function FileBrowser2({
121295
121330
  },
121296
121331
  [adapter, workspaceId]
121297
121332
  );
121298
- (0, import_react31.useEffect)(() => {
121333
+ (0, import_react32.useEffect)(() => {
121299
121334
  fetchDir("");
121300
121335
  }, [fetchDir]);
121301
- (0, import_react31.useEffect)(() => {
121336
+ (0, import_react32.useEffect)(() => {
121302
121337
  if (!adapter.subscribeFileChanges) return;
121303
121338
  const unsubscribe = adapter.subscribeFileChanges(workspaceId, (changedPath) => {
121304
121339
  const cache = getCachedContents(workspaceId);
@@ -121307,8 +121342,8 @@ var FileBrowser = (0, import_react31.forwardRef)(function FileBrowser2({
121307
121342
  });
121308
121343
  return unsubscribe;
121309
121344
  }, [adapter, workspaceId, fetchDir]);
121310
- const prevSelectedRef = (0, import_react31.useRef)(void 0);
121311
- (0, import_react31.useEffect)(() => {
121345
+ const prevSelectedRef = (0, import_react32.useRef)(void 0);
121346
+ (0, import_react32.useEffect)(() => {
121312
121347
  if (!selectedFile || selectedFile === prevSelectedRef.current) {
121313
121348
  prevSelectedRef.current = selectedFile;
121314
121349
  return;
@@ -121335,7 +121370,7 @@ var FileBrowser = (0, import_react31.forwardRef)(function FileBrowser2({
121335
121370
  fetchDir(dir);
121336
121371
  }
121337
121372
  }, [selectedFile, workspaceId, fetchDir]);
121338
- (0, import_react31.useEffect)(() => {
121373
+ (0, import_react32.useEffect)(() => {
121339
121374
  if (selectedFile && selectedRef.current) {
121340
121375
  const timer = setTimeout(() => {
121341
121376
  selectedRef.current?.scrollIntoView({ block: "nearest" });
@@ -121343,7 +121378,7 @@ var FileBrowser = (0, import_react31.forwardRef)(function FileBrowser2({
121343
121378
  return () => clearTimeout(timer);
121344
121379
  }
121345
121380
  }, [selectedFile, dirContents]);
121346
- const toggleExpand = (0, import_react31.useCallback)(
121381
+ const toggleExpand = (0, import_react32.useCallback)(
121347
121382
  (dirPath) => {
121348
121383
  setExpandedPaths((prev) => {
121349
121384
  const next = new Set(prev);
@@ -121359,7 +121394,7 @@ var FileBrowser = (0, import_react31.forwardRef)(function FileBrowser2({
121359
121394
  },
121360
121395
  [workspaceId, fetchDir]
121361
121396
  );
121362
- const ensureDirExpanded = (0, import_react31.useCallback)(
121397
+ const ensureDirExpanded = (0, import_react32.useCallback)(
121363
121398
  async (dirPath) => {
121364
121399
  const cached2 = getCachedExpanded(workspaceId);
121365
121400
  if (!cached2.has(dirPath)) {
@@ -121371,17 +121406,17 @@ var FileBrowser = (0, import_react31.forwardRef)(function FileBrowser2({
121371
121406
  },
121372
121407
  [workspaceId, fetchDir]
121373
121408
  );
121374
- const requestNewEntry = (0, import_react31.useCallback)(
121409
+ const requestNewEntry = (0, import_react32.useCallback)(
121375
121410
  (parentPath, kind) => {
121376
121411
  void ensureDirExpanded(parentPath);
121377
121412
  setNewEntry({ parentPath, kind });
121378
121413
  },
121379
121414
  [ensureDirExpanded]
121380
121415
  );
121381
- const cancelNewEntry = (0, import_react31.useCallback)(() => {
121416
+ const cancelNewEntry = (0, import_react32.useCallback)(() => {
121382
121417
  setNewEntry(null);
121383
121418
  }, []);
121384
- const submitNewEntry = (0, import_react31.useCallback)(
121419
+ const submitNewEntry = (0, import_react32.useCallback)(
121385
121420
  async (name24) => {
121386
121421
  if (!newEntry) return;
121387
121422
  const fullPath = newEntry.parentPath ? `${newEntry.parentPath}/${name24}` : name24;
@@ -121414,16 +121449,16 @@ var FileBrowser = (0, import_react31.forwardRef)(function FileBrowser2({
121414
121449
  [adapter, newEntry, fetchDir, onOpenFile, workspaceId]
121415
121450
  );
121416
121451
  const canDelete = Boolean(adapter.deleteWorkspacePath);
121417
- const requestDelete = (0, import_react31.useCallback)((path3, kind) => {
121452
+ const requestDelete = (0, import_react32.useCallback)((path3, kind) => {
121418
121453
  setDeleteError(null);
121419
121454
  setPendingDelete({ path: path3, kind });
121420
121455
  }, []);
121421
- const cancelDelete = (0, import_react31.useCallback)(() => {
121456
+ const cancelDelete = (0, import_react32.useCallback)(() => {
121422
121457
  if (deleteSubmitting) return;
121423
121458
  setPendingDelete(null);
121424
121459
  setDeleteError(null);
121425
121460
  }, [deleteSubmitting]);
121426
- const confirmDelete = (0, import_react31.useCallback)(async () => {
121461
+ const confirmDelete = (0, import_react32.useCallback)(async () => {
121427
121462
  if (!pendingDelete || !adapter.deleteWorkspacePath) return;
121428
121463
  setDeleteSubmitting(true);
121429
121464
  setDeleteError(null);
@@ -121469,13 +121504,13 @@ var FileBrowser = (0, import_react31.forwardRef)(function FileBrowser2({
121469
121504
  }
121470
121505
  }, [adapter, pendingDelete, fetchDir, workspaceId, onPathDeleted]);
121471
121506
  const canRename = Boolean(adapter.renameWorkspacePath);
121472
- const requestRename = (0, import_react31.useCallback)((path3) => {
121507
+ const requestRename = (0, import_react32.useCallback)((path3) => {
121473
121508
  setRenamingPath(path3);
121474
121509
  }, []);
121475
- const cancelRename = (0, import_react31.useCallback)(() => {
121510
+ const cancelRename = (0, import_react32.useCallback)(() => {
121476
121511
  setRenamingPath(null);
121477
121512
  }, []);
121478
- const submitRename = (0, import_react31.useCallback)(
121513
+ const submitRename = (0, import_react32.useCallback)(
121479
121514
  async (newName) => {
121480
121515
  if (renamingPath == null || !adapter.renameWorkspacePath) return;
121481
121516
  const oldPath = renamingPath;
@@ -121531,7 +121566,7 @@ var FileBrowser = (0, import_react31.forwardRef)(function FileBrowser2({
121531
121566
  },
121532
121567
  [adapter, renamingPath, fetchDir, onPathRenamed, workspaceId]
121533
121568
  );
121534
- const resolveDefaultTarget = (0, import_react31.useCallback)(() => {
121569
+ const resolveDefaultTarget = (0, import_react32.useCallback)(() => {
121535
121570
  if (treeSelection?.kind === "directory") return treeSelection.path;
121536
121571
  if (treeSelection?.kind === "file") {
121537
121572
  const idx = treeSelection.path.lastIndexOf("/");
@@ -121544,13 +121579,13 @@ var FileBrowser = (0, import_react31.forwardRef)(function FileBrowser2({
121544
121579
  const canPaste = Boolean(
121545
121580
  clipboard && (clipboard.op === "copy" && adapter.copyWorkspacePath || clipboard.op === "cut" && adapter.renameWorkspacePath)
121546
121581
  );
121547
- const cutPath = (0, import_react31.useCallback)((path3, kind) => {
121582
+ const cutPath = (0, import_react32.useCallback)((path3, kind) => {
121548
121583
  setClipboard({ path: path3, kind, op: "cut" });
121549
121584
  }, []);
121550
- const copyPath = (0, import_react31.useCallback)((path3, kind) => {
121585
+ const copyPath = (0, import_react32.useCallback)((path3, kind) => {
121551
121586
  setClipboard({ path: path3, kind, op: "copy" });
121552
121587
  }, []);
121553
- const uniqueCopyName = (0, import_react31.useCallback)(
121588
+ const uniqueCopyName = (0, import_react32.useCallback)(
121554
121589
  (baseName, destFolder, kind) => {
121555
121590
  const siblings = new Set(
121556
121591
  (getCachedContents(workspaceId).get(destFolder) ?? []).map((e2) => e2.name)
@@ -121568,7 +121603,7 @@ var FileBrowser = (0, import_react31.forwardRef)(function FileBrowser2({
121568
121603
  },
121569
121604
  [workspaceId]
121570
121605
  );
121571
- const pasteInto = (0, import_react31.useCallback)(
121606
+ const pasteInto = (0, import_react32.useCallback)(
121572
121607
  async (destFolder) => {
121573
121608
  if (!clipboard) return;
121574
121609
  const sourcePath = clipboard.path;
@@ -121632,7 +121667,7 @@ var FileBrowser = (0, import_react31.forwardRef)(function FileBrowser2({
121632
121667
  },
121633
121668
  [adapter, clipboard, fetchDir, onPathRenamed, uniqueCopyName, workspaceId]
121634
121669
  );
121635
- (0, import_react31.useImperativeHandle)(
121670
+ (0, import_react32.useImperativeHandle)(
121636
121671
  handleRef,
121637
121672
  () => ({
121638
121673
  startNewFile(parentPath) {
@@ -121646,7 +121681,7 @@ var FileBrowser = (0, import_react31.forwardRef)(function FileBrowser2({
121646
121681
  );
121647
121682
  const rootMenu = useDeferredMenuAction();
121648
121683
  if (!adapter.listWorkspaceFiles) {
121649
- return /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("div", { className: "flex h-32 items-center justify-center text-sm text-muted-foreground", children: "File browsing not supported" });
121684
+ return /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("div", { className: "flex h-32 items-center justify-center text-sm text-muted-foreground", children: "File browsing not supported" });
121650
121685
  }
121651
121686
  const rootEntries = dirContents.get("") ?? [];
121652
121687
  const rootLoading = loadingPaths.has("");
@@ -121683,20 +121718,20 @@ var FileBrowser = (0, import_react31.forwardRef)(function FileBrowser2({
121683
121718
  void pasteInto(resolveDefaultTarget());
121684
121719
  }
121685
121720
  };
121686
- return /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("div", { className: "flex h-full flex-col overflow-hidden", onKeyDown: handleKeyDown, children: [
121687
- /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(
121721
+ return /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("div", { className: "flex h-full flex-col overflow-hidden", onKeyDown: handleKeyDown, children: [
121722
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(
121688
121723
  ContextMenu2,
121689
121724
  {
121690
121725
  onOpenChange: (open3) => {
121691
121726
  if (open3) clearTreeSelection();
121692
121727
  },
121693
121728
  children: [
121694
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(ContextMenuTrigger2, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("div", { className: "min-h-0 flex-1 overflow-y-auto py-1 pl-px", children: [
121729
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(ContextMenuTrigger2, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("div", { className: "min-h-0 flex-1 overflow-y-auto py-1 pl-px", children: [
121695
121730
  (() => {
121696
121731
  const rootSplitIdx = rootEntries.findIndex((e2) => e2.type === "file");
121697
121732
  const rootFolders = rootSplitIdx === -1 ? rootEntries : rootEntries.slice(0, rootSplitIdx);
121698
121733
  const rootFiles = rootSplitIdx === -1 ? [] : rootEntries.slice(rootSplitIdx);
121699
- const renderRow = (entry) => /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
121734
+ const renderRow = (entry) => /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
121700
121735
  TreeNode2,
121701
121736
  {
121702
121737
  entry,
@@ -121733,7 +121768,7 @@ var FileBrowser = (0, import_react31.forwardRef)(function FileBrowser2({
121733
121768
  },
121734
121769
  entry.name
121735
121770
  );
121736
- const rootInput = showRootInput ? /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
121771
+ const rootInput = showRootInput ? /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
121737
121772
  EntryNameInput,
121738
121773
  {
121739
121774
  kind: newEntry.kind,
@@ -121745,30 +121780,30 @@ var FileBrowser = (0, import_react31.forwardRef)(function FileBrowser2({
121745
121780
  },
121746
121781
  `new-${newEntry.kind}-root`
121747
121782
  ) : null;
121748
- return /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(import_jsx_runtime67.Fragment, { children: [
121783
+ return /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(import_jsx_runtime68.Fragment, { children: [
121749
121784
  showRootInput && newEntry.kind === "directory" && rootInput,
121750
- rootLoading && rootEntries.length === 0 && !showRootInput && /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("div", { className: "flex h-32 items-center justify-center text-sm text-muted-foreground", children: "Loading\u2026" }),
121751
- !rootLoading && rootEntries.length === 0 && !showRootInput && /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("div", { className: "flex h-32 items-center justify-center text-sm text-muted-foreground", children: "Empty directory" }),
121785
+ rootLoading && rootEntries.length === 0 && !showRootInput && /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("div", { className: "flex h-32 items-center justify-center text-sm text-muted-foreground", children: "Loading\u2026" }),
121786
+ !rootLoading && rootEntries.length === 0 && !showRootInput && /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("div", { className: "flex h-32 items-center justify-center text-sm text-muted-foreground", children: "Empty directory" }),
121752
121787
  rootFolders.map(renderRow),
121753
121788
  showRootInput && newEntry.kind === "file" && rootInput,
121754
121789
  rootFiles.map(renderRow)
121755
121790
  ] });
121756
121791
  })(),
121757
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("div", { className: "min-h-[40px] flex-1" })
121792
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("div", { className: "min-h-[40px] flex-1" })
121758
121793
  ] }) }),
121759
- /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(ContextMenuContent2, { onCloseAutoFocus: rootMenu.flush, children: [
121760
- /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(ContextMenuItem2, { onSelect: () => rootMenu.queue(() => requestNewEntry("", "file")), children: [
121761
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(import_lucide_react8.File, { className: "size-4" }),
121794
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(ContextMenuContent2, { onCloseAutoFocus: rootMenu.flush, children: [
121795
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(ContextMenuItem2, { onSelect: () => rootMenu.queue(() => requestNewEntry("", "file")), children: [
121796
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(import_lucide_react8.File, { className: "size-4" }),
121762
121797
  "New File"
121763
121798
  ] }),
121764
- /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(ContextMenuItem2, { onSelect: () => rootMenu.queue(() => requestNewEntry("", "directory")), children: [
121765
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(import_lucide_react8.FolderPlus, { className: "size-4" }),
121799
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(ContextMenuItem2, { onSelect: () => rootMenu.queue(() => requestNewEntry("", "directory")), children: [
121800
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(import_lucide_react8.FolderPlus, { className: "size-4" }),
121766
121801
  "New Folder"
121767
121802
  ] }),
121768
- canPaste && /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(import_jsx_runtime67.Fragment, { children: [
121769
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(ContextMenuSeparator2, {}),
121770
- /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(ContextMenuItem2, { onSelect: () => rootMenu.queue(() => void pasteInto("")), children: [
121771
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(import_lucide_react8.ClipboardPaste, { className: "size-4" }),
121803
+ canPaste && /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(import_jsx_runtime68.Fragment, { children: [
121804
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(ContextMenuSeparator2, {}),
121805
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(ContextMenuItem2, { onSelect: () => rootMenu.queue(() => void pasteInto("")), children: [
121806
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(import_lucide_react8.ClipboardPaste, { className: "size-4" }),
121772
121807
  "Paste"
121773
121808
  ] })
121774
121809
  ] })
@@ -121776,42 +121811,42 @@ var FileBrowser = (0, import_react31.forwardRef)(function FileBrowser2({
121776
121811
  ]
121777
121812
  }
121778
121813
  ),
121779
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
121814
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
121780
121815
  Dialog2,
121781
121816
  {
121782
121817
  open: pendingDelete !== null,
121783
121818
  onOpenChange: (open3) => {
121784
121819
  if (!open3) cancelDelete();
121785
121820
  },
121786
- children: /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(DialogContent2, { className: "sm:max-w-[425px]", onClick: (e2) => e2.stopPropagation(), children: [
121787
- /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(DialogHeader, { children: [
121788
- /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(DialogTitle2, { children: [
121821
+ children: /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(DialogContent2, { className: "sm:max-w-[425px]", onClick: (e2) => e2.stopPropagation(), children: [
121822
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(DialogHeader, { children: [
121823
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(DialogTitle2, { children: [
121789
121824
  "Delete ",
121790
121825
  pendingDelete?.kind === "directory" ? "folder" : "file"
121791
121826
  ] }),
121792
- /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(DialogDescription2, { children: [
121827
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(DialogDescription2, { children: [
121793
121828
  "Are you sure you want to delete ",
121794
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("strong", { children: pendingDelete?.path }),
121829
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("strong", { children: pendingDelete?.path }),
121795
121830
  "?"
121796
121831
  ] })
121797
121832
  ] }),
121798
- /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("div", { className: "flex flex-col gap-2 text-sm", children: [
121799
- pendingDelete?.kind === "directory" && /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("div", { className: "flex items-start gap-2 rounded-md border border-yellow-500/30 bg-yellow-500/10 p-3", children: [
121800
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(import_lucide_react8.AlertTriangle, { className: "size-4 shrink-0 text-yellow-500 mt-0.5" }),
121801
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("span", { children: "The folder and all of its contents will be deleted from disk. This cannot be undone." })
121833
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("div", { className: "flex flex-col gap-2 text-sm", children: [
121834
+ pendingDelete?.kind === "directory" && /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("div", { className: "flex items-start gap-2 rounded-md border border-yellow-500/30 bg-yellow-500/10 p-3", children: [
121835
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(import_lucide_react8.AlertTriangle, { className: "size-4 shrink-0 text-yellow-500 mt-0.5" }),
121836
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("span", { children: "The folder and all of its contents will be deleted from disk. This cannot be undone." })
121802
121837
  ] }),
121803
- pendingDelete?.kind === "file" && /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("div", { className: "flex items-start gap-2 rounded-md border border-yellow-500/30 bg-yellow-500/10 p-3", children: [
121804
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(import_lucide_react8.AlertTriangle, { className: "size-4 shrink-0 text-yellow-500 mt-0.5" }),
121805
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("span", { children: "The file will be deleted from disk. This cannot be undone." })
121838
+ pendingDelete?.kind === "file" && /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("div", { className: "flex items-start gap-2 rounded-md border border-yellow-500/30 bg-yellow-500/10 p-3", children: [
121839
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(import_lucide_react8.AlertTriangle, { className: "size-4 shrink-0 text-yellow-500 mt-0.5" }),
121840
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("span", { children: "The file will be deleted from disk. This cannot be undone." })
121806
121841
  ] }),
121807
- deleteError && /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("div", { className: "flex items-start gap-2 rounded-md border border-destructive/30 bg-destructive/10 p-3 text-destructive", children: [
121808
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(import_lucide_react8.AlertTriangle, { className: "size-4 shrink-0 mt-0.5" }),
121809
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("span", { children: deleteError })
121842
+ deleteError && /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)("div", { className: "flex items-start gap-2 rounded-md border border-destructive/30 bg-destructive/10 p-3 text-destructive", children: [
121843
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(import_lucide_react8.AlertTriangle, { className: "size-4 shrink-0 mt-0.5" }),
121844
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("span", { children: deleteError })
121810
121845
  ] })
121811
121846
  ] }),
121812
- /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(DialogFooter, { children: [
121813
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(Button, { variant: "ghost", onClick: cancelDelete, disabled: deleteSubmitting, children: "Cancel" }),
121814
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
121847
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(DialogFooter, { children: [
121848
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(Button, { variant: "ghost", onClick: cancelDelete, disabled: deleteSubmitting, children: "Cancel" }),
121849
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
121815
121850
  Button,
121816
121851
  {
121817
121852
  variant: "destructive",
@@ -121828,39 +121863,39 @@ var FileBrowser = (0, import_react31.forwardRef)(function FileBrowser2({
121828
121863
  });
121829
121864
 
121830
121865
  // ../../packages/dashboard-core/src/components/FileViewer.tsx
121831
- var import_react34 = __toESM(require_react(), 1);
121866
+ var import_react35 = __toESM(require_react(), 1);
121832
121867
 
121833
121868
  // ../../packages/dashboard-core/src/components/ImagePreview.tsx
121834
- var import_react32 = __toESM(require_react(), 1);
121835
- var import_jsx_runtime68 = __toESM(require_jsx_runtime(), 1);
121836
-
121837
- // ../../packages/dashboard-core/src/components/LanguagePickerDialog.tsx
121838
121869
  var import_react33 = __toESM(require_react(), 1);
121839
121870
  var import_jsx_runtime69 = __toESM(require_jsx_runtime(), 1);
121840
121871
 
121841
- // ../../packages/dashboard-core/src/components/PdfPreview.tsx
121872
+ // ../../packages/dashboard-core/src/components/LanguagePickerDialog.tsx
121873
+ var import_react34 = __toESM(require_react(), 1);
121842
121874
  var import_jsx_runtime70 = __toESM(require_jsx_runtime(), 1);
121843
121875
 
121844
- // ../../packages/dashboard-core/src/components/FileViewer.tsx
121876
+ // ../../packages/dashboard-core/src/components/PdfPreview.tsx
121845
121877
  var import_jsx_runtime71 = __toESM(require_jsx_runtime(), 1);
121846
121878
 
121847
- // ../../packages/dashboard-core/src/components/QuickOpenDialog.tsx
121848
- var import_react35 = __toESM(require_react(), 1);
121879
+ // ../../packages/dashboard-core/src/components/FileViewer.tsx
121849
121880
  var import_jsx_runtime72 = __toESM(require_jsx_runtime(), 1);
121850
121881
 
121851
- // ../../packages/dashboard-core/src/components/SearchFilesDialog.tsx
121882
+ // ../../packages/dashboard-core/src/components/QuickOpenDialog.tsx
121852
121883
  var import_react36 = __toESM(require_react(), 1);
121853
121884
  var import_jsx_runtime73 = __toESM(require_jsx_runtime(), 1);
121854
121885
 
121855
- // ../../packages/dashboard-core/src/components/WorkspacePickerDialog.tsx
121886
+ // ../../packages/dashboard-core/src/components/SearchFilesDialog.tsx
121856
121887
  var import_react37 = __toESM(require_react(), 1);
121857
121888
  var import_jsx_runtime74 = __toESM(require_jsx_runtime(), 1);
121858
121889
 
121859
- // ../../packages/dashboard-core/src/components/WorkspaceTabNav.tsx
121890
+ // ../../packages/dashboard-core/src/components/WorkspacePickerDialog.tsx
121891
+ var import_react38 = __toESM(require_react(), 1);
121860
121892
  var import_jsx_runtime75 = __toESM(require_jsx_runtime(), 1);
121861
121893
 
121894
+ // ../../packages/dashboard-core/src/components/WorkspaceTabNav.tsx
121895
+ var import_jsx_runtime76 = __toESM(require_jsx_runtime(), 1);
121896
+
121862
121897
  // ../../packages/dashboard-core/src/hooks/use-editor-history.ts
121863
- var import_react38 = __toESM(require_react(), 1);
121898
+ var import_react39 = __toESM(require_react(), 1);
121864
121899
 
121865
121900
  // ../../node_modules/.pnpm/marked@15.0.12/node_modules/marked/lib/marked.esm.js
121866
121901
  function _getDefaults() {
@@ -125940,6 +125975,7 @@ function getTableAsAliasSQL(table) {
125940
125975
  }
125941
125976
 
125942
125977
  // src/lib/db/connection.ts
125978
+ init_src();
125943
125979
  import { mkdirSync as mkdirSync2 } from "node:fs";
125944
125980
  import { join as join10 } from "node:path";
125945
125981
  import { DatabaseSync as DatabaseSync2 } from "node:sqlite";
@@ -131690,7 +131726,12 @@ var projects = sqliteTable("projects", {
131690
131726
  path: text3("path").notNull(),
131691
131727
  defaultBranch: text3("default_branch").notNull(),
131692
131728
  label: text3("label"),
131693
- sortOrder: integer3("sort_order").notNull()
131729
+ sortOrder: integer3("sort_order").notNull(),
131730
+ // Discriminates between git-backed projects (worktree-per-workspace,
131731
+ // branches, PR/CI features) and plain folders (single implicit workspace,
131732
+ // no isolation, git features disabled). Defaults to "git" so existing
131733
+ // rows keep their behavior unchanged after migration.
131734
+ kind: text3("kind", { enum: ["git", "plain"] }).notNull().default("git")
131694
131735
  });
131695
131736
  var worktrees = sqliteTable("worktrees", {
131696
131737
  id: integer3("id").primaryKey({ autoIncrement: true }),
@@ -131756,6 +131797,7 @@ var browserHistory = sqliteTable(
131756
131797
  );
131757
131798
 
131758
131799
  // src/lib/db/connection.ts
131800
+ var log7 = createLogger("db");
131759
131801
  var migrationsFolder = join10(import.meta.dirname, "migrations");
131760
131802
  var _db = null;
131761
131803
  var _sqlite = null;
@@ -131773,6 +131815,14 @@ function getDb() {
131773
131815
  }
131774
131816
  function closeDb() {
131775
131817
  if (_sqlite) {
131818
+ try {
131819
+ _sqlite.exec("PRAGMA wal_checkpoint(TRUNCATE)");
131820
+ } catch (err) {
131821
+ log7.warn(
131822
+ "WAL checkpoint failed on close (best-effort): %s",
131823
+ err instanceof Error ? err.message : String(err)
131824
+ );
131825
+ }
131776
131826
  _sqlite.close();
131777
131827
  _sqlite = null;
131778
131828
  _db = null;
@@ -131780,6 +131830,16 @@ function closeDb() {
131780
131830
  }
131781
131831
 
131782
131832
  // src/lib/state.ts
131833
+ function reconcileKindForProject(project) {
131834
+ if (!existsSync4(project.path)) return false;
131835
+ const detectedKind = existsSync4(join11(project.path, ".git")) ? "git" : "plain";
131836
+ if (detectedKind === project.kind) return false;
131837
+ project.kind = detectedKind;
131838
+ if (detectedKind === "plain") {
131839
+ project.worktrees = [{ branch: "main", path: project.path, pinned: false }];
131840
+ }
131841
+ return true;
131842
+ }
131783
131843
  function bandHome() {
131784
131844
  if (process.env.BAND_HOME) return process.env.BAND_HOME;
131785
131845
  return join11(homedir6(), ".band");
@@ -131805,6 +131865,7 @@ function loadState() {
131805
131865
  path: row.path,
131806
131866
  defaultBranch: row.defaultBranch,
131807
131867
  label: row.label ?? void 0,
131868
+ kind: row.kind ?? "git",
131808
131869
  worktrees: wtByProject.get(row.name) ?? []
131809
131870
  }))
131810
131871
  };
@@ -131821,7 +131882,8 @@ function saveState(state2) {
131821
131882
  path: project.path,
131822
131883
  defaultBranch: project.defaultBranch,
131823
131884
  label: project.label ?? null,
131824
- sortOrder: i2
131885
+ sortOrder: i2,
131886
+ kind: project.kind
131825
131887
  }).run();
131826
131888
  for (const wt of project.worktrees) {
131827
131889
  tx.insert(worktrees).values({
@@ -131980,7 +132042,7 @@ function deleteBranchStatus(workspaceId) {
131980
132042
  }
131981
132043
 
131982
132044
  // src/lib/agent-pool.ts
131983
- var log7 = createLogger("agent-pool");
132045
+ var log8 = createLogger("agent-pool");
131984
132046
  var POOL_KEY = Symbol.for("band.agent-pool.v2");
131985
132047
  var PENDING_KEY = Symbol.for("band.agent-pool.pending");
131986
132048
  var g2 = globalThis;
@@ -132025,7 +132087,7 @@ function getAgent(chatId) {
132025
132087
  return pool.get(chatId)?.agent;
132026
132088
  }
132027
132089
  function removeAgent(chatId) {
132028
- log7.info({ chatId }, "removing agent from pool");
132090
+ log8.info({ chatId }, "removing agent from pool");
132029
132091
  return pool.delete(chatId);
132030
132092
  }
132031
132093
  async function getOrCreateAgent(chatId, worktreePath, agentId) {
@@ -132033,7 +132095,7 @@ async function getOrCreateAgent(chatId, worktreePath, agentId) {
132033
132095
  if (existing) {
132034
132096
  const requestedDefId = resolveAgentDefId(agentId);
132035
132097
  if (existing.agentDefId !== requestedDefId) {
132036
- log7.info(
132098
+ log8.info(
132037
132099
  { chatId, cached: existing.agentDefId, requested: requestedDefId },
132038
132100
  "cached agent definition mismatch, replacing"
132039
132101
  );
@@ -132047,7 +132109,7 @@ async function getOrCreateAgent(chatId, worktreePath, agentId) {
132047
132109
  return inFlight.promise;
132048
132110
  }
132049
132111
  const config2 = getAgentConfig(worktreePath, agentId);
132050
- log7.info({ chatId, type: config2.type, defId, cwd: worktreePath }, "creating agent");
132112
+ log8.info({ chatId, type: config2.type, defId, cwd: worktreePath }, "creating agent");
132051
132113
  const promise2 = createCodingAgent(config2).then(
132052
132114
  (agent) => {
132053
132115
  pool.set(chatId, { agent, agentDefId: defId });
@@ -132110,6 +132172,18 @@ function listPanelStatesForWorkspace(workspaceId, panelType) {
132110
132172
  const db2 = getDb();
132111
132173
  return db2.select().from(panelStates).where(and(eq2(panelStates.workspaceId, workspaceId), eq2(panelStates.panelType, panelType))).all();
132112
132174
  }
132175
+ function resetPanelStatesToIdle(panelType, updatedAt) {
132176
+ const db2 = getDb();
132177
+ db2.update(panelStates).set({
132178
+ state: sql`json_set(${panelStates.state}, '$.status', 'idle')`,
132179
+ updatedAt
132180
+ }).where(
132181
+ and(
132182
+ eq2(panelStates.panelType, panelType),
132183
+ sql`json_extract(${panelStates.state}, '$.status') IS NOT 'idle'`
132184
+ )
132185
+ ).run();
132186
+ }
132113
132187
 
132114
132188
  // src/lib/dockview-layout-manager.ts
132115
132189
  function isLeaf(node) {
@@ -132582,6 +132656,7 @@ function parseBatchedCIResponse(data, aliases, defaultBranches) {
132582
132656
  }
132583
132657
 
132584
132658
  // src/lib/sync-state.ts
132659
+ var PROJECT_SYNC_BATCH_SIZE = 8;
132585
132660
  async function detectRemoteDefaultBranch(projectPath) {
132586
132661
  try {
132587
132662
  const ref = (await execGit(["symbolic-ref", "refs/remotes/origin/HEAD"], projectPath)).trim();
@@ -132606,35 +132681,50 @@ async function syncWorktrees() {
132606
132681
  const state2 = loadState();
132607
132682
  let changed = false;
132608
132683
  for (const project of state2.projects) {
132609
- let diskWorktrees;
132610
- try {
132611
- const gitWorktrees = await listWorktrees(project.path);
132612
- const pinnedByBranch = new Map(project.worktrees.map((wt) => [wt.branch, wt.pinned]));
132613
- diskWorktrees = gitWorktrees.filter((wt) => !wt.isBare).map((wt) => ({
132614
- branch: wt.branch,
132615
- path: wt.path,
132616
- head: wt.head,
132617
- pinned: pinnedByBranch.get(wt.branch) ?? false
132618
- }));
132619
- } catch {
132620
- continue;
132621
- }
132622
- const existingSet = new Set(project.worktrees.map((wt) => `${wt.branch}\0${wt.path}`));
132623
- const diskSet = new Set(diskWorktrees.map((wt) => `${wt.branch}\0${wt.path}`));
132624
- if (existingSet.size !== diskSet.size || Array.from(existingSet).some((key) => !diskSet.has(key))) {
132625
- project.worktrees = diskWorktrees;
132684
+ if (reconcileKindForProject(project)) {
132626
132685
  changed = true;
132627
132686
  }
132628
- const remoteBranch = await detectRemoteDefaultBranch(project.path);
132629
- if (remoteBranch && remoteBranch !== project.defaultBranch) {
132630
- project.defaultBranch = remoteBranch;
132631
- changed = true;
132687
+ }
132688
+ const gitProjects = state2.projects.filter((p6) => p6.kind !== "plain");
132689
+ for (let i2 = 0; i2 < gitProjects.length; i2 += PROJECT_SYNC_BATCH_SIZE) {
132690
+ const batch = gitProjects.slice(i2, i2 + PROJECT_SYNC_BATCH_SIZE);
132691
+ const results = await Promise.all(batch.map(reconcileOneProject));
132692
+ for (const mutated of results) {
132693
+ if (mutated) changed = true;
132632
132694
  }
132633
132695
  }
132634
132696
  if (changed) {
132635
132697
  saveState(state2);
132636
132698
  }
132637
132699
  }
132700
+ async function reconcileOneProject(project) {
132701
+ let mutated = false;
132702
+ let diskWorktrees;
132703
+ try {
132704
+ const gitWorktrees = await listWorktrees(project.path);
132705
+ const pinnedByBranch = new Map(project.worktrees.map((wt) => [wt.branch, wt.pinned]));
132706
+ diskWorktrees = gitWorktrees.filter((wt) => !wt.isBare).map((wt) => ({
132707
+ branch: wt.branch,
132708
+ path: wt.path,
132709
+ head: wt.head,
132710
+ pinned: pinnedByBranch.get(wt.branch) ?? false
132711
+ }));
132712
+ } catch {
132713
+ return false;
132714
+ }
132715
+ const existingSet = new Set(project.worktrees.map((wt) => `${wt.branch}\0${wt.path}`));
132716
+ const diskSet = new Set(diskWorktrees.map((wt) => `${wt.branch}\0${wt.path}`));
132717
+ if (existingSet.size !== diskSet.size || Array.from(existingSet).some((key) => !diskSet.has(key))) {
132718
+ project.worktrees = diskWorktrees;
132719
+ mutated = true;
132720
+ }
132721
+ const remoteBranch = await detectRemoteDefaultBranch(project.path);
132722
+ if (remoteBranch && remoteBranch !== project.defaultBranch) {
132723
+ project.defaultBranch = remoteBranch;
132724
+ mutated = true;
132725
+ }
132726
+ return mutated;
132727
+ }
132638
132728
 
132639
132729
  // src/lib/branch-status-poller.ts
132640
132730
  var INTERVALS = {
@@ -132653,6 +132743,7 @@ function getWorkspaces() {
132653
132743
  const state2 = loadState();
132654
132744
  const workspaces = [];
132655
132745
  for (const project of state2.projects) {
132746
+ if (project.kind === "plain") continue;
132656
132747
  for (const wt of project.worktrees) {
132657
132748
  workspaces.push({
132658
132749
  workspaceId: toWorkspaceId(project.name, wt.branch),
@@ -132896,12 +132987,12 @@ function getPollerActivity() {
132896
132987
  import { spawn as spawn5 } from "node:child_process";
132897
132988
 
132898
132989
  // src/lib/project-config.ts
132899
- import { existsSync as existsSync4, readFileSync as readFileSync6 } from "node:fs";
132990
+ import { existsSync as existsSync5, readFileSync as readFileSync6 } from "node:fs";
132900
132991
  import { join as join14 } from "node:path";
132901
132992
  function loadProjectConfig(worktreePath, projectPath) {
132902
132993
  for (const base2 of [worktreePath, projectPath]) {
132903
132994
  const configPath = join14(base2, ".band", "config.json");
132904
- if (existsSync4(configPath)) {
132995
+ if (existsSync5(configPath)) {
132905
132996
  try {
132906
132997
  return JSON.parse(readFileSync6(configPath, "utf-8"));
132907
132998
  } catch {
@@ -133020,7 +133111,7 @@ function subscribe(listener) {
133020
133111
  }
133021
133112
 
133022
133113
  // src/lib/chat-manager.ts
133023
- var log8 = createLogger("chat-manager");
133114
+ var log9 = createLogger("chat-manager");
133024
133115
  var PANEL_TYPE = "chat";
133025
133116
  var chatSessions = /* @__PURE__ */ new Map();
133026
133117
  var workspaceChats = /* @__PURE__ */ new Map();
@@ -133091,7 +133182,7 @@ function createChat(workspaceId, options2) {
133091
133182
  addToIndex(session);
133092
133183
  addChatToLayout(workspaceId, session.id, { title: session.name });
133093
133184
  emit({ kind: "chat-created", workspaceId, chatId: session.id });
133094
- log8.info({ chatId: session.id, workspaceId, agent: session.agent }, "chat pane created");
133185
+ log9.info({ chatId: session.id, workspaceId, agent: session.agent }, "chat pane created");
133095
133186
  return session;
133096
133187
  }
133097
133188
  function getChat(chatId) {
@@ -133120,7 +133211,7 @@ function updateChat(chatId, updates) {
133120
133211
  state: serializeState(session),
133121
133212
  updatedAt: Date.now()
133122
133213
  });
133123
- log8.info({ chatId, updates }, "chat pane updated");
133214
+ log9.info({ chatId, updates }, "chat pane updated");
133124
133215
  return session;
133125
133216
  }
133126
133217
  function updateChatStatus(chatId, status) {
@@ -133172,7 +133263,7 @@ function removeChat(chatId) {
133172
133263
  removeChatFromLayout(session.workspaceId, chatId);
133173
133264
  removeFromIndex(chatId);
133174
133265
  emit({ kind: "chat-removed", workspaceId: session.workspaceId, chatId });
133175
- log8.info({ chatId, workspaceId: session.workspaceId }, "chat pane removed");
133266
+ log9.info({ chatId, workspaceId: session.workspaceId }, "chat pane removed");
133176
133267
  return true;
133177
133268
  }
133178
133269
  function removeWorkspaceChats(workspaceId) {
@@ -133184,19 +133275,15 @@ function removeWorkspaceChats(workspaceId) {
133184
133275
  }
133185
133276
  deletePanelStatesForWorkspace(workspaceId, PANEL_TYPE);
133186
133277
  workspaceChats.delete(workspaceId);
133187
- log8.info({ workspaceId }, "all chat panes removed for workspace");
133278
+ log9.info({ workspaceId }, "all chat panes removed for workspace");
133188
133279
  }
133189
133280
  function loadChatsFromDb() {
133190
133281
  _initialized = true;
133191
- const rows = listPanelStates(PANEL_TYPE);
133192
133282
  const now = Date.now();
133283
+ resetPanelStatesToIdle(PANEL_TYPE, now);
133284
+ const rows = listPanelStates(PANEL_TYPE);
133193
133285
  for (const row of rows) {
133194
133286
  const parsed = JSON.parse(row.state);
133195
- parsed.status = "idle";
133196
- updatePanelState(row.id, {
133197
- state: JSON.stringify(parsed),
133198
- updatedAt: now
133199
- });
133200
133287
  const session = {
133201
133288
  id: row.id,
133202
133289
  workspaceId: row.workspaceId,
@@ -133207,12 +133294,16 @@ function loadChatsFromDb() {
133207
133294
  activeSessionId: parsed.activeSessionId ?? void 0,
133208
133295
  activeSessionSummary: parsed.activeSessionSummary ?? void 0,
133209
133296
  activeSessionLastModified: parsed.activeSessionLastModified ?? void 0,
133297
+ // Force idle on the in-memory copy: even if the bulk UPDATE skipped
133298
+ // this row because it was already "idle" on disk, or — in some odd
133299
+ // race — wrote between the UPDATE and the SELECT, we never want to
133300
+ // hand the rest of the server a session in a non-idle state on boot.
133210
133301
  status: "idle"
133211
133302
  };
133212
133303
  addToIndex(session);
133213
133304
  }
133214
133305
  if (rows.length > 0) {
133215
- log8.info({ count: rows.length }, "loaded chat panes from database");
133306
+ log9.info({ count: rows.length }, "loaded chat panes from database");
133216
133307
  }
133217
133308
  return rows.length;
133218
133309
  }
@@ -133392,7 +133483,7 @@ function hasPendingInputForWorkspace(workspaceId) {
133392
133483
 
133393
133484
  // src/lib/task-store.ts
133394
133485
  init_src();
133395
- var log9 = createLogger("task-store");
133486
+ var log10 = createLogger("task-store");
133396
133487
  function generateTaskId() {
133397
133488
  return `tsk_${Date.now()}`;
133398
133489
  }
@@ -133465,7 +133556,7 @@ function cleanupStaleTasks() {
133465
133556
  const result = db2.update(tasks).set({ status: "failed", completedAt: now }).where(eq2(tasks.status, "running")).run();
133466
133557
  const count3 = result.changes;
133467
133558
  if (count3 > 0) {
133468
- log9.info({ count: count3 }, "cleaned up stale tasks on startup");
133559
+ log10.info({ count: count3 }, "cleaned up stale tasks on startup");
133469
133560
  }
133470
133561
  return count3;
133471
133562
  }
@@ -133502,7 +133593,7 @@ function pruneOldTasks(retentionMs = TASK_RETENTION_MS) {
133502
133593
  const cutoff = Date.now() - retentionMs;
133503
133594
  const count3 = deleteTasksOlderThan(cutoff);
133504
133595
  if (count3 > 0) {
133505
- log9.info({ count: count3, retentionMs }, "pruned tasks older than retention window");
133596
+ log10.info({ count: count3, retentionMs }, "pruned tasks older than retention window");
133506
133597
  }
133507
133598
  return count3;
133508
133599
  }
@@ -133513,13 +133604,13 @@ function startTaskPruneScheduler(options2 = {}) {
133513
133604
  try {
133514
133605
  pruneOldTasks(retentionMs);
133515
133606
  } catch (err) {
133516
- log9.error({ err }, "initial task prune on boot failed");
133607
+ log10.error({ err }, "initial task prune on boot failed");
133517
133608
  }
133518
133609
  const timer = setInterval(() => {
133519
133610
  try {
133520
133611
  pruneOldTasks(retentionMs);
133521
133612
  } catch (err) {
133522
- log9.error({ err }, "scheduled task prune failed");
133613
+ log10.error({ err }, "scheduled task prune failed");
133523
133614
  }
133524
133615
  }, intervalMs);
133525
133616
  timer.unref();
@@ -133606,7 +133697,7 @@ function resolveWorkspace(workspaceId) {
133606
133697
  }
133607
133698
 
133608
133699
  // src/lib/task-runner.ts
133609
- var log10 = createLogger("task-runner");
133700
+ var log11 = createLogger("task-runner");
133610
133701
  function listFiles(dir) {
133611
133702
  try {
133612
133703
  return new Set(readdirSync6(dir));
@@ -133665,7 +133756,7 @@ function persistTask(task) {
133665
133756
  chatId: task.chatId
133666
133757
  });
133667
133758
  } catch (err) {
133668
- log10.warn({ err, taskId: task.taskRecordId }, "failed to persist task");
133759
+ log11.warn({ err, taskId: task.taskRecordId }, "failed to persist task");
133669
133760
  }
133670
133761
  }
133671
133762
  function broadcast(chatId, chunk) {
@@ -133689,7 +133780,7 @@ function broadcast(chatId, chunk) {
133689
133780
  }
133690
133781
  const subs = listeners2.get(chatId);
133691
133782
  if (!subs || subs.size === 0) {
133692
- log10.warn({ chatId, chunkType: chunk.type }, "broadcast: no listeners");
133783
+ log11.warn({ chatId, chunkType: chunk.type }, "broadcast: no listeners");
133693
133784
  return;
133694
133785
  }
133695
133786
  for (const listener of subs) {
@@ -133740,7 +133831,7 @@ function submitTask(options2) {
133740
133831
  tasks2.set(chatId, task);
133741
133832
  persistTask(task);
133742
133833
  runTask(chatId, task).catch((err) => {
133743
- log10.error({ chatId, err }, "task execution failed");
133834
+ log11.error({ chatId, err }, "task execution failed");
133744
133835
  if (task.status === "running") {
133745
133836
  task.status = "failed";
133746
133837
  task.completedAt = Date.now();
@@ -133774,7 +133865,7 @@ function abortTask(chatId) {
133774
133865
  updateChatStatus(chatId, "idle");
133775
133866
  const updated = upsertWorkspaceStatus(task.workspaceId, { status: "waiting" });
133776
133867
  emit({ kind: "update", status: updated });
133777
- log10.info({ chatId }, "task aborted by user");
133868
+ log11.info({ chatId }, "task aborted by user");
133778
133869
  return true;
133779
133870
  }
133780
133871
  function cancelTask(taskId) {
@@ -133794,7 +133885,7 @@ function cancelTask(taskId) {
133794
133885
  updateChatStatus(chatId, "idle");
133795
133886
  const updated = upsertWorkspaceStatus(task.workspaceId, { status: "waiting" });
133796
133887
  emit({ kind: "update", status: updated });
133797
- log10.info({ chatId, taskId }, "task cancelled (was running in-memory)");
133888
+ log11.info({ chatId, taskId }, "task cancelled (was running in-memory)");
133798
133889
  return { cancelled: true, workspaceId: task.workspaceId };
133799
133890
  }
133800
133891
  }
@@ -133802,7 +133893,7 @@ function cancelTask(taskId) {
133802
133893
  if (record2) {
133803
133894
  const updated = upsertWorkspaceStatus(record2.workspaceId, { status: "waiting" });
133804
133895
  emit({ kind: "update", status: updated });
133805
- log10.info({ taskId, workspaceId: record2.workspaceId }, "orphaned task cancelled");
133896
+ log11.info({ taskId, workspaceId: record2.workspaceId }, "orphaned task cancelled");
133806
133897
  return { cancelled: true, workspaceId: record2.workspaceId };
133807
133898
  }
133808
133899
  return { cancelled: false };
@@ -133822,7 +133913,7 @@ async function runTask(chatId, task) {
133822
133913
  const taskAgentId = task.codingAgentId;
133823
133914
  const resolvedAgentId = taskAgentId ?? chatSession?.agent;
133824
133915
  const needsReplace = taskAgentId && taskAgentId !== chatSession?.agent;
133825
- log10.info(
133916
+ log11.info(
133826
133917
  { chatId, taskAgentId, chatAgent: chatSession?.agent, resolvedAgentId, needsReplace },
133827
133918
  "resolving agent for task"
133828
133919
  );
@@ -133871,7 +133962,7 @@ async function runTask(chatId, task) {
133871
133962
  [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.]`;
133872
133963
  const effectivePrompt = task.sessionId ? task.agentPrompt : task.agentPrompt + fileSharingHint;
133873
133964
  for await (const event of agent.runSession(effectivePrompt, task.sessionId, sessionOptions)) {
133874
- log10.info({ chatId, eventType: event.type }, "task event");
133965
+ log11.info({ chatId, eventType: event.type }, "task event");
133875
133966
  switch (event.type) {
133876
133967
  case "session-start": {
133877
133968
  task.sessionId = event.sessionId;
@@ -134052,7 +134143,7 @@ async function runTask(chatId, task) {
134052
134143
  break;
134053
134144
  }
134054
134145
  case "session-id-resolved": {
134055
- log10.info(
134146
+ log11.info(
134056
134147
  { chatId, previous: event.previousSessionId, resolved: event.resolvedSessionId },
134057
134148
  "session ID resolved"
134058
134149
  );
@@ -134147,7 +134238,7 @@ ${queued.text}`;
134147
134238
  });
134148
134239
  autoStarted = true;
134149
134240
  } catch (err) {
134150
- log10.warn({ chatId, err }, "failed to auto-start queued task");
134241
+ log11.warn({ chatId, err }, "failed to auto-start queued task");
134151
134242
  }
134152
134243
  }
134153
134244
  }
@@ -134247,7 +134338,7 @@ function getSessionEventsAfter(sessionId, afterEventId) {
134247
134338
  }
134248
134339
 
134249
134340
  // src/api/task-stream.ts
134250
- var log11 = createLogger("task-stream");
134341
+ var log12 = createLogger("task-stream");
134251
134342
  var INTERNAL_CHUNK_TYPES = /* @__PURE__ */ new Set(["user-message"]);
134252
134343
  function toUIChunk(chunk) {
134253
134344
  if (INTERNAL_CHUNK_TYPES.has(chunk.type)) return null;
@@ -134302,7 +134393,7 @@ function streamTask(res, chatId, sessionId, afterEventId) {
134302
134393
  const buf = getSessionBuffer(task.sessionId);
134303
134394
  if (buf && buf.events.length > 0) {
134304
134395
  const taskStartEventId = task.firstEventId ?? Number.POSITIVE_INFINITY;
134305
- log11.info(
134396
+ log12.info(
134306
134397
  {
134307
134398
  chatId,
134308
134399
  sessionId: task.sessionId,
@@ -134326,7 +134417,7 @@ function streamTask(res, chatId, sessionId, afterEventId) {
134326
134417
  }
134327
134418
  }
134328
134419
  if (queue.length === 0 && !caughtUp && (!task || task.status !== "running")) {
134329
- log11.warn(
134420
+ log12.warn(
134330
134421
  { chatId, taskStatus: task?.status, queueLen: queue.length },
134331
134422
  "task-stream: no running task and no events \u2014 closing stream early"
134332
134423
  );
@@ -134424,7 +134515,7 @@ ${prompt}`;
134424
134515
  }
134425
134516
  throw err;
134426
134517
  }
134427
- log11.info({ chatId, workspaceId }, "task-stream: POST \u2014 task submitted, opening SSE stream");
134518
+ log12.info({ chatId, workspaceId }, "task-stream: POST \u2014 task submitted, opening SSE stream");
134428
134519
  streamTask(res, chatId, sessionId, void 0);
134429
134520
  }
134430
134521
  function handleGet(req, res, chatId) {
@@ -134438,13 +134529,13 @@ function handleGet(req, res, chatId) {
134438
134529
  res.end();
134439
134530
  return;
134440
134531
  }
134441
- log11.info({ chatId, sessionId, afterEventId }, "task-stream: GET \u2014 reconnecting to active stream");
134532
+ log12.info({ chatId, sessionId, afterEventId }, "task-stream: GET \u2014 reconnecting to active stream");
134442
134533
  streamTask(res, chatId, sessionId ?? task.sessionId, afterEventId);
134443
134534
  }
134444
134535
  function handleTaskStream(req, res, chatId) {
134445
134536
  if (req.method === "POST") {
134446
134537
  handlePost(req, res, chatId).catch((err) => {
134447
- log11.error({ chatId, err }, "task-stream: POST handler error");
134538
+ log12.error({ chatId, err }, "task-stream: POST handler error");
134448
134539
  if (!res.headersSent) {
134449
134540
  res.writeHead(500, { "Content-Type": "application/json" });
134450
134541
  res.end(JSON.stringify({ error: "Internal server error" }));
@@ -134489,7 +134580,7 @@ function removeBrowserFromLayout(workspaceId, browserId) {
134489
134580
  }
134490
134581
 
134491
134582
  // src/lib/browser-manager.ts
134492
- var log12 = createLogger("browser-manager");
134583
+ var log13 = createLogger("browser-manager");
134493
134584
  var PANEL_TYPE2 = "browser";
134494
134585
  var browserTabs = /* @__PURE__ */ new Map();
134495
134586
  var workspaceBrowsers = /* @__PURE__ */ new Map();
@@ -134550,7 +134641,7 @@ function createBrowser(workspaceId, options2) {
134550
134641
  title: tab.name,
134551
134642
  initialUrl: tab.url || void 0
134552
134643
  });
134553
- log12.info({ browserId: tab.id, workspaceId, url: tab.url }, "browser tab created");
134644
+ log13.info({ browserId: tab.id, workspaceId, url: tab.url }, "browser tab created");
134554
134645
  return tab;
134555
134646
  }
134556
134647
  function getBrowser(browserId) {
@@ -134577,7 +134668,7 @@ function updateBrowser(browserId, updates) {
134577
134668
  state: serializeState2(tab),
134578
134669
  updatedAt: Date.now()
134579
134670
  });
134580
- log12.info({ browserId, updates }, "browser tab updated");
134671
+ log13.info({ browserId, updates }, "browser tab updated");
134581
134672
  return tab;
134582
134673
  }
134583
134674
  function updateBrowserUrl(browserId, url2) {
@@ -134594,7 +134685,7 @@ function removeBrowser(browserId) {
134594
134685
  if (!tab) return false;
134595
134686
  deletePanelState(browserId);
134596
134687
  removeFromIndex2(browserId);
134597
- log12.info({ browserId, workspaceId: tab.workspaceId }, "browser tab removed");
134688
+ log13.info({ browserId, workspaceId: tab.workspaceId }, "browser tab removed");
134598
134689
  return true;
134599
134690
  }
134600
134691
  function removeWorkspaceBrowsers(workspaceId) {
@@ -134605,19 +134696,15 @@ function removeWorkspaceBrowsers(workspaceId) {
134605
134696
  }
134606
134697
  deletePanelStatesForWorkspace(workspaceId, PANEL_TYPE2);
134607
134698
  workspaceBrowsers.delete(workspaceId);
134608
- log12.info({ workspaceId }, "all browser tabs removed for workspace");
134699
+ log13.info({ workspaceId }, "all browser tabs removed for workspace");
134609
134700
  }
134610
134701
  function loadBrowsersFromDb() {
134611
134702
  _initialized2 = true;
134612
- const rows = listPanelStates(PANEL_TYPE2);
134613
134703
  const now = Date.now();
134704
+ resetPanelStatesToIdle(PANEL_TYPE2, now);
134705
+ const rows = listPanelStates(PANEL_TYPE2);
134614
134706
  for (const row of rows) {
134615
134707
  const parsed = JSON.parse(row.state);
134616
- parsed.status = "idle";
134617
- updatePanelState(row.id, {
134618
- state: JSON.stringify(parsed),
134619
- updatedAt: now
134620
- });
134621
134708
  const tab = {
134622
134709
  id: row.id,
134623
134710
  workspaceId: row.workspaceId,
@@ -134628,13 +134715,13 @@ function loadBrowsersFromDb() {
134628
134715
  addToIndex2(tab);
134629
134716
  }
134630
134717
  if (rows.length > 0) {
134631
- log12.info({ count: rows.length }, "loaded browser tabs from database");
134718
+ log13.info({ count: rows.length }, "loaded browser tabs from database");
134632
134719
  }
134633
134720
  return rows.length;
134634
134721
  }
134635
134722
 
134636
134723
  // src/lib/browser-host.ts
134637
- var log13 = createLogger("browser-host");
134724
+ var log14 = createLogger("browser-host");
134638
134725
  var DESKTOP_CDP_HOST = "127.0.0.1";
134639
134726
  var DESKTOP_CDP_PORT = 9223;
134640
134727
  var globalAny = globalThis;
@@ -134685,7 +134772,7 @@ async function ensureCdpTargetId(bandTabId) {
134685
134772
  reject: rejectFn,
134686
134773
  timeoutId
134687
134774
  });
134688
- log13.info(
134775
+ log14.info(
134689
134776
  "ensureCdpTargetId emitting ensureView for %s (url=%s, listeners=%d)",
134690
134777
  bandTabId,
134691
134778
  tab.url,
@@ -134699,13 +134786,13 @@ async function ensureCdpTargetId(bandTabId) {
134699
134786
  url: tab.url
134700
134787
  });
134701
134788
  } catch (err) {
134702
- log13.warn("ensureView listener threw: %s", err instanceof Error ? err.message : err);
134789
+ log14.warn("ensureView listener threw: %s", err instanceof Error ? err.message : err);
134703
134790
  }
134704
134791
  }
134705
134792
  return promise2;
134706
134793
  }
134707
134794
  function resolveTargetReady(bandTabId, cdpTargetId) {
134708
- log13.info("resolveTargetReady %s \u2192 %s", bandTabId, cdpTargetId);
134795
+ log14.info("resolveTargetReady %s \u2192 %s", bandTabId, cdpTargetId);
134709
134796
  targetIdByBandTabId.set(bandTabId, cdpTargetId);
134710
134797
  const pending2 = pendingEnsures.get(bandTabId);
134711
134798
  if (pending2) {
@@ -134715,7 +134802,7 @@ function resolveTargetReady(bandTabId, cdpTargetId) {
134715
134802
  }
134716
134803
  }
134717
134804
  function markTargetDestroyed(bandTabId) {
134718
- log13.info("markTargetDestroyed %s", bandTabId);
134805
+ log14.info("markTargetDestroyed %s", bandTabId);
134719
134806
  targetIdByBandTabId.delete(bandTabId);
134720
134807
  const pending2 = pendingEnsures.get(bandTabId);
134721
134808
  if (pending2) {
@@ -134726,10 +134813,10 @@ function markTargetDestroyed(bandTabId) {
134726
134813
  }
134727
134814
  function onEnsureView(listener) {
134728
134815
  ensureListeners.add(listener);
134729
- log13.info("onEnsureView subscriber added (total=%d)", ensureListeners.size);
134816
+ log14.info("onEnsureView subscriber added (total=%d)", ensureListeners.size);
134730
134817
  return () => {
134731
134818
  ensureListeners.delete(listener);
134732
- log13.info("onEnsureView subscriber removed (total=%d)", ensureListeners.size);
134819
+ log14.info("onEnsureView subscriber removed (total=%d)", ensureListeners.size);
134733
134820
  if (ensureListeners.size === 0) {
134734
134821
  for (const [bandTabId, pending2] of pendingEnsures) {
134735
134822
  clearTimeout(pending2.timeoutId);
@@ -134746,7 +134833,7 @@ function isDesktopHostConnected() {
134746
134833
 
134747
134834
  // src/lib/cdp-proxy.ts
134748
134835
  init_src();
134749
- var log14 = createLogger("cdp-proxy");
134836
+ var log15 = createLogger("cdp-proxy");
134750
134837
  async function handleCdpConnection(ws, req) {
134751
134838
  const url2 = new URL(req.url ?? "", `http://${req.headers.host}`);
134752
134839
  const bandTabId = url2.searchParams.get("bandTabId");
@@ -134769,17 +134856,17 @@ async function handleCdpConnection(ws, req) {
134769
134856
  cdpTargetId = await ensureCdpTargetId(bandTabId);
134770
134857
  } catch (err) {
134771
134858
  const message = err instanceof Error ? err.message : String(err);
134772
- log14.debug("ensureCdpTargetId failed for %s: %s", bandTabId, message);
134859
+ log15.debug("ensureCdpTargetId failed for %s: %s", bandTabId, message);
134773
134860
  if (ws.readyState === ws.OPEN) {
134774
134861
  ws.close(4001, message.slice(0, 123));
134775
134862
  }
134776
134863
  return;
134777
134864
  }
134778
134865
  const upstreamUrl = `ws://${DESKTOP_CDP_HOST}:${DESKTOP_CDP_PORT}/devtools/page/${encodeURIComponent(cdpTargetId)}`;
134779
- log14.info("CDP proxy connecting bandTabId=%s upstream=%s", bandTabId, upstreamUrl);
134866
+ log15.info("CDP proxy connecting bandTabId=%s upstream=%s", bandTabId, upstreamUrl);
134780
134867
  upstream = new wrapper_default(upstreamUrl);
134781
134868
  upstream.on("open", () => {
134782
- log14.info("CDP upstream open bandTabId=%s pending=%d", bandTabId, pending2.length);
134869
+ log15.info("CDP upstream open bandTabId=%s pending=%d", bandTabId, pending2.length);
134783
134870
  for (const msg of pending2) {
134784
134871
  upstream?.send(msg);
134785
134872
  }
@@ -134791,20 +134878,20 @@ async function handleCdpConnection(ws, req) {
134791
134878
  }
134792
134879
  });
134793
134880
  upstream.on("error", (err) => {
134794
- log14.warn("CDP upstream error bandTabId=%s: %s", bandTabId, err.message);
134881
+ log15.warn("CDP upstream error bandTabId=%s: %s", bandTabId, err.message);
134795
134882
  markTargetDestroyed(bandTabId);
134796
134883
  if (ws.readyState === ws.OPEN) {
134797
134884
  ws.close(4001, `Desktop CDP error: ${err.message}`.slice(0, 123));
134798
134885
  }
134799
134886
  });
134800
134887
  upstream.on("close", (code) => {
134801
- log14.info("CDP upstream closed bandTabId=%s code=%d", bandTabId, code);
134888
+ log15.info("CDP upstream closed bandTabId=%s code=%d", bandTabId, code);
134802
134889
  if (ws.readyState === ws.OPEN) {
134803
134890
  ws.close(1e3, "Upstream closed");
134804
134891
  }
134805
134892
  });
134806
134893
  ws.on("close", () => {
134807
- log14.debug("CDP client closed bandTabId=%s", bandTabId);
134894
+ log15.debug("CDP client closed bandTabId=%s", bandTabId);
134808
134895
  if (upstream && (upstream.readyState === wrapper_default.OPEN || upstream.readyState === wrapper_default.CONNECTING)) {
134809
134896
  try {
134810
134897
  upstream.close();
@@ -134813,7 +134900,7 @@ async function handleCdpConnection(ws, req) {
134813
134900
  }
134814
134901
  });
134815
134902
  ws.on("error", (err) => {
134816
- log14.debug("CDP client error bandTabId=%s: %s", bandTabId, err.message);
134903
+ log15.debug("CDP client error bandTabId=%s: %s", bandTabId, err.message);
134817
134904
  try {
134818
134905
  upstream?.close();
134819
134906
  } catch {
@@ -134823,7 +134910,7 @@ async function handleCdpConnection(ws, req) {
134823
134910
 
134824
134911
  // src/lib/cdp-targets.ts
134825
134912
  init_src();
134826
- var log15 = createLogger("cdp-targets");
134913
+ var log16 = createLogger("cdp-targets");
134827
134914
  var CdpUnreachableError = class extends Error {
134828
134915
  constructor(message) {
134829
134916
  super(message);
@@ -134879,7 +134966,7 @@ async function captureSnapshot(bandTabId) {
134879
134966
  });
134880
134967
  ws.on("error", (err) => {
134881
134968
  clearTimeout(timeout);
134882
- log15.debug("captureSnapshot ws error for tab %s: %s", bandTabId, err.message);
134969
+ log16.debug("captureSnapshot ws error for tab %s: %s", bandTabId, err.message);
134883
134970
  markTargetDestroyed(bandTabId);
134884
134971
  settle(new CdpUnreachableError(err.message));
134885
134972
  });
@@ -135599,7 +135686,7 @@ function rowToDefinition(row) {
135599
135686
  }
135600
135687
 
135601
135688
  // src/lib/cronjob-scheduler.ts
135602
- var log16 = createLogger("cronjob-scheduler");
135689
+ var log17 = createLogger("cronjob-scheduler");
135603
135690
  var SCHEDULER_KEY = Symbol.for("band.cronjob-scheduler");
135604
135691
  var g14 = globalThis;
135605
135692
  if (!g14[SCHEDULER_KEY]) {
@@ -135619,16 +135706,16 @@ function scheduleJob(job, fileKey) {
135619
135706
  try {
135620
135707
  const cronInstance = new E2(job.cronExpression, () => {
135621
135708
  executeCronjob(job, fileKey).catch((err) => {
135622
- log16.error({ jobId: job.id, err }, "unhandled error in cronjob execution");
135709
+ log17.error({ jobId: job.id, err }, "unhandled error in cronjob execution");
135623
135710
  });
135624
135711
  });
135625
135712
  state.jobs.set(job.id, cronInstance);
135626
- log16.info(
135713
+ log17.info(
135627
135714
  { jobId: job.id, name: job.name, cron: job.cronExpression, scope: job.scope },
135628
135715
  "scheduled cronjob"
135629
135716
  );
135630
135717
  } catch (err) {
135631
- log16.error(
135718
+ log17.error(
135632
135719
  { jobId: job.id, cronExpression: job.cronExpression, err },
135633
135720
  "invalid cron expression, skipping job"
135634
135721
  );
@@ -135642,24 +135729,24 @@ async function executeCronjob(job, fileKey) {
135642
135729
  const appState = loadState();
135643
135730
  const project = appState.projects.find((p6) => p6.name === fileKey);
135644
135731
  if (!project) {
135645
- log16.warn({ jobId: job.id, fileKey }, "project not found for cronjob, skipping");
135732
+ log17.warn({ jobId: job.id, fileKey }, "project not found for cronjob, skipping");
135646
135733
  updateLastRun(job.id, "failed");
135647
135734
  return;
135648
135735
  }
135649
135736
  workspaceId = toWorkspaceId(project.name, project.defaultBranch);
135650
135737
  }
135651
- log16.info({ jobId: job.id, name: job.name, workspaceId }, "executing cronjob");
135738
+ log17.info({ jobId: job.id, name: job.name, workspaceId }, "executing cronjob");
135652
135739
  try {
135653
135740
  const chat = getOrCreateDefaultChat(workspaceId);
135654
135741
  submitTask({ workspaceId, chatId: chat.id, prompt: job.prompt });
135655
135742
  updateLastRun(job.id, "completed");
135656
135743
  } catch (err) {
135657
135744
  if (err instanceof TaskConflictError) {
135658
- log16.info({ jobId: job.id, workspaceId }, "task already running, skipping cronjob execution");
135745
+ log17.info({ jobId: job.id, workspaceId }, "task already running, skipping cronjob execution");
135659
135746
  updateLastRun(job.id, "skipped");
135660
135747
  return;
135661
135748
  }
135662
- log16.error({ jobId: job.id, err }, "cronjob execution failed");
135749
+ log17.error({ jobId: job.id, err }, "cronjob execution failed");
135663
135750
  updateLastRun(job.id, "failed");
135664
135751
  }
135665
135752
  }
@@ -135668,7 +135755,7 @@ function updateLastRun(jobId, status) {
135668
135755
  const db2 = getDb();
135669
135756
  db2.update(cronjobs).set({ lastRunAt: (/* @__PURE__ */ new Date()).toISOString(), lastRunStatus: status }).where(eq2(cronjobs.id, jobId)).run();
135670
135757
  } catch (err) {
135671
- log16.warn({ jobId, err }, "failed to update lastRun on cronjob");
135758
+ log17.warn({ jobId, err }, "failed to update lastRun on cronjob");
135672
135759
  }
135673
135760
  }
135674
135761
  function loadAndScheduleAll() {
@@ -135679,13 +135766,13 @@ function loadAndScheduleAll() {
135679
135766
  for (const job of listAllCronjobs()) {
135680
135767
  scheduleJob(job, job.fileKey);
135681
135768
  }
135682
- log16.info({ count: state.jobs.size }, "loaded cronjob schedules");
135769
+ log17.info({ count: state.jobs.size }, "loaded cronjob schedules");
135683
135770
  }
135684
135771
  function startCronjobScheduler() {
135685
135772
  if (state.started) return;
135686
135773
  state.started = true;
135687
135774
  loadAndScheduleAll();
135688
- log16.info("cronjob scheduler started");
135775
+ log17.info("cronjob scheduler started");
135689
135776
  }
135690
135777
  function stopCronjobScheduler() {
135691
135778
  for (const [, cron] of state.jobs) {
@@ -135693,7 +135780,7 @@ function stopCronjobScheduler() {
135693
135780
  }
135694
135781
  state.jobs.clear();
135695
135782
  state.started = false;
135696
- log16.info("cronjob scheduler stopped");
135783
+ log17.info("cronjob scheduler stopped");
135697
135784
  }
135698
135785
  function reloadSchedules() {
135699
135786
  if (!state.started) return;
@@ -135706,7 +135793,7 @@ function stopJobsForKey(key) {
135706
135793
  if (cron) {
135707
135794
  cron.stop();
135708
135795
  state.jobs.delete(job.id);
135709
- log16.info({ jobId: job.id, key }, "stopped cronjob");
135796
+ log17.info({ jobId: job.id, key }, "stopped cronjob");
135710
135797
  }
135711
135798
  }
135712
135799
  }
@@ -135772,7 +135859,7 @@ async function checkPrereqs() {
135772
135859
 
135773
135860
  // src/lib/lsp-manager.ts
135774
135861
  var __dirname2 = dirname2(fileURLToPath(import.meta.url));
135775
- var log17 = createLogger("lsp");
135862
+ var log18 = createLogger("lsp");
135776
135863
  var LANG_SERVER_CONFIG = {
135777
135864
  typescript: { command: "typescript-language-server", args: ["--stdio"] }
135778
135865
  };
@@ -135800,7 +135887,7 @@ async function getOrSpawnServer(workspaceId, lang) {
135800
135887
  const workspaceBin = join17(cwd, "node_modules/.bin");
135801
135888
  const pathSep = process.platform === "win32" ? ";" : ":";
135802
135889
  const combinedPath = [bundledBin, appBin, workspaceBin, resolvedPath].join(pathSep);
135803
- log17.debug("Spawning %s language server in %s for workspace %s", lang, cwd, workspaceId);
135890
+ log18.debug("Spawning %s language server in %s for workspace %s", lang, cwd, workspaceId);
135804
135891
  const child = spawn6(config2.command, config2.args, {
135805
135892
  cwd,
135806
135893
  stdio: ["pipe", "pipe", "pipe"],
@@ -135828,15 +135915,15 @@ async function getOrSpawnServer(workspaceId, lang) {
135828
135915
  }
135829
135916
  ids.add(serverId);
135830
135917
  child.on("exit", (code) => {
135831
- log17.debug("Language server exited: %s (code %s)", serverId, String(code));
135918
+ log18.debug("Language server exited: %s (code %s)", serverId, String(code));
135832
135919
  removeSession();
135833
135920
  });
135834
135921
  child.on("error", (err) => {
135835
- log17.error("Language server error: %s \u2014 %s", serverId, err.message);
135922
+ log18.error("Language server error: %s \u2014 %s", serverId, err.message);
135836
135923
  removeSession();
135837
135924
  });
135838
135925
  child.stderr?.on("data", (chunk) => {
135839
- log17.debug("LSP stderr [%s]: %s", serverId, chunk.toString().trimEnd());
135926
+ log18.debug("LSP stderr [%s]: %s", serverId, chunk.toString().trimEnd());
135840
135927
  });
135841
135928
  await new Promise((resolve8, reject) => {
135842
135929
  child.once("spawn", resolve8);
@@ -135866,7 +135953,7 @@ function killAllServers() {
135866
135953
 
135867
135954
  // src/lib/lsp-proxy.ts
135868
135955
  init_src();
135869
- var log18 = createLogger("lsp-proxy");
135956
+ var log19 = createLogger("lsp-proxy");
135870
135957
  function frameMessage(json4) {
135871
135958
  const body = Buffer.from(json4, "utf-8");
135872
135959
  const header = `Content-Length: ${body.byteLength}\r
@@ -135884,7 +135971,7 @@ function createFrameParser(onMessage) {
135884
135971
  const headerStr = buffer.subarray(0, separatorIdx).toString("ascii");
135885
135972
  const match = headerStr.match(/Content-Length:\s*(\d+)/i);
135886
135973
  if (!match) {
135887
- log18.warn("Malformed LSP header: %s", headerStr);
135974
+ log19.warn("Malformed LSP header: %s", headerStr);
135888
135975
  buffer = buffer.subarray(separatorIdx + 4);
135889
135976
  continue;
135890
135977
  }
@@ -135917,7 +136004,7 @@ async function handleLspConnection(ws, req) {
135917
136004
  session = await getOrSpawnServer(workspaceId, lang);
135918
136005
  } catch (err) {
135919
136006
  const message = err instanceof Error ? err.message : String(err);
135920
- log18.error(
136007
+ log19.error(
135921
136008
  "Failed to spawn %s language server for workspace %s: %s",
135922
136009
  lang,
135923
136010
  workspaceId,
@@ -135931,12 +136018,12 @@ async function handleLspConnection(ws, req) {
135931
136018
  ws.close(4002, "Language server stdio not available");
135932
136019
  return;
135933
136020
  }
135934
- log18.debug("LSP client connected: %s/%s", workspaceId, lang);
136021
+ log19.debug("LSP client connected: %s/%s", workspaceId, lang);
135935
136022
  const pendingRequests = /* @__PURE__ */ new Map();
135936
136023
  const retriedIds = /* @__PURE__ */ new Set();
135937
136024
  const RETRY_DELAY_MS = 2e3;
135938
136025
  const parseFrame = createFrameParser((json4) => {
135939
- log18.debug(
136026
+ log19.debug(
135940
136027
  "LSP stdout [%s/%s]: %s",
135941
136028
  workspaceId,
135942
136029
  lang,
@@ -135948,7 +136035,7 @@ async function handleLspConnection(ws, req) {
135948
136035
  const originalRequest = pendingRequests.get(msg.id);
135949
136036
  retriedIds.add(msg.id);
135950
136037
  pendingRequests.delete(msg.id);
135951
- log18.debug(
136038
+ log19.debug(
135952
136039
  "LSP retrying request %d after 'No Project' error [%s/%s]",
135953
136040
  msg.id,
135954
136041
  workspaceId,
@@ -135970,14 +136057,14 @@ async function handleLspConnection(ws, req) {
135970
136057
  const onStdoutData = (chunk) => parseFrame(chunk);
135971
136058
  lspProcess.stdout.on("data", onStdoutData);
135972
136059
  const onExit = (code) => {
135973
- log18.debug("LSP server exited (code %s), closing WebSocket", String(code));
136060
+ log19.debug("LSP server exited (code %s), closing WebSocket", String(code));
135974
136061
  if (ws.readyState === ws.OPEN) {
135975
136062
  ws.close(1e3, "Language server exited");
135976
136063
  }
135977
136064
  };
135978
136065
  lspProcess.on("exit", onExit);
135979
136066
  function forwardToStdin(json4) {
135980
- log18.debug(
136067
+ log19.debug(
135981
136068
  "LSP stdin [%s/%s]: %s",
135982
136069
  workspaceId,
135983
136070
  lang,
@@ -136004,7 +136091,7 @@ async function handleLspConnection(ws, req) {
136004
136091
  ws.on("close", () => {
136005
136092
  lspProcess.stdout?.off("data", onStdoutData);
136006
136093
  lspProcess.off("exit", onExit);
136007
- log18.debug("LSP client disconnected: %s/%s (server kept alive)", workspaceId, lang);
136094
+ log19.debug("LSP client disconnected: %s/%s (server kept alive)", workspaceId, lang);
136008
136095
  });
136009
136096
  }
136010
136097
 
@@ -136141,7 +136228,7 @@ function resolveCliPaths() {
136141
136228
  // src/lib/cli-skills.ts
136142
136229
  import { execFile as execFile4 } from "node:child_process";
136143
136230
  import {
136144
- existsSync as existsSync5,
136231
+ existsSync as existsSync6,
136145
136232
  lstatSync as lstatSync3,
136146
136233
  mkdirSync as mkdirSync5,
136147
136234
  mkdtempSync,
@@ -136240,7 +136327,7 @@ async function installSkills(opts = {}) {
136240
136327
  for (const name24 of BAND_SKILL_NAMES) {
136241
136328
  const sourcePath = join19(stagingDir, name24, SKILL_FILE);
136242
136329
  const destPath = join19(sharedDir, name24, SKILL_FILE);
136243
- if (!existsSync5(sourcePath)) {
136330
+ if (!existsSync6(sourcePath)) {
136244
136331
  opts.log?.warn("Generated skill missing from staging dir: %s (skipping)", sourcePath);
136245
136332
  result.skipped.push(destPath);
136246
136333
  continue;
@@ -136288,7 +136375,7 @@ async function installSkills(opts = {}) {
136288
136375
  for (const name24 of BAND_SKILL_NAMES) {
136289
136376
  const shared2 = join19(sharedDir, name24);
136290
136377
  const link2 = join19(target.skillsDir, name24);
136291
- if (!existsSync5(shared2)) {
136378
+ if (!existsSync6(shared2)) {
136292
136379
  result.skipped.push(link2);
136293
136380
  continue;
136294
136381
  }
@@ -136500,40 +136587,65 @@ async function installHooks() {
136500
136587
  }
136501
136588
 
136502
136589
  // src/lib/setup.ts
136503
- var log19 = createLogger("setup");
136590
+ var log20 = createLogger("setup");
136504
136591
  var AGENT_CHECKS = [
136505
136592
  { id: "claude-code", type: "claude-code", label: "Claude Code", binary: "claude" },
136506
136593
  { id: "codex", type: "codex", label: "Codex", binary: "codex" },
136507
136594
  { id: "opencode", type: "opencode", label: "OpenCode", binary: "opencode" }
136508
136595
  ];
136509
136596
  async function runFirstTimeSetup() {
136597
+ const projectSync = ensureProjectStateInSync();
136510
136598
  await ensureCliInstalled();
136599
+ const results = await Promise.allSettled([
136600
+ projectSync,
136601
+ ensureSettingsDefaults(),
136602
+ ensureClaudeHooks(),
136603
+ ensureSkillsInstalled()
136604
+ ]);
136605
+ for (const r6 of results) {
136606
+ if (r6.status === "rejected") {
136607
+ log20.warn(
136608
+ "Setup step failed: %s",
136609
+ r6.reason instanceof Error ? r6.reason.message : String(r6.reason)
136610
+ );
136611
+ }
136612
+ }
136613
+ }
136614
+ async function ensureSettingsDefaults() {
136511
136615
  await ensureDefaultCodingAgents();
136512
136616
  ensureNotificationDefaults();
136513
- await ensureClaudeHooks();
136514
- await ensureSkillsInstalled();
136617
+ }
136618
+ async function ensureProjectStateInSync() {
136619
+ try {
136620
+ await syncWorktrees();
136621
+ } catch (err) {
136622
+ log20.warn(
136623
+ "Failed to sync project state at boot: %s",
136624
+ err instanceof Error ? err.message : String(err)
136625
+ );
136626
+ }
136515
136627
  }
136516
136628
  async function ensureCliInstalled() {
136517
136629
  let cliStatus;
136518
136630
  try {
136519
136631
  cliStatus = await checkCli();
136520
136632
  } catch (err) {
136521
- log19.warn("Could not check CLI status: %s", err instanceof Error ? err.message : String(err));
136633
+ log20.warn("Could not check CLI status: %s", err instanceof Error ? err.message : String(err));
136522
136634
  return;
136523
136635
  }
136524
136636
  if (cliStatus === "Installed") {
136525
136637
  return;
136526
136638
  }
136527
136639
  if (cliStatus !== "NotInstalled") {
136528
- log19.warn("CLI not auto-installed (status: %s)", cliStatus);
136640
+ log20.warn("CLI not auto-installed (status: %s)", cliStatus);
136529
136641
  return;
136530
136642
  }
136531
- log19.info("Installing band CLI...");
136643
+ log20.info("Installing band CLI...");
136532
136644
  try {
136533
136645
  await installCli();
136534
- log19.info("CLI installed to /usr/local/bin/band");
136646
+ log20.info("CLI installed to /usr/local/bin/band");
136535
136647
  } catch (err) {
136536
- log19.warn("CLI installation failed: %s", err instanceof Error ? err.message : String(err));
136648
+ log20.warn("CLI installation failed: %s", err instanceof Error ? err.message : String(err));
136537
136649
  }
136538
136650
  }
136539
136651
  async function ensureDefaultCodingAgents() {
@@ -136542,17 +136654,17 @@ async function ensureDefaultCodingAgents() {
136542
136654
  if (Array.isArray(existing) && existing.length > 0) {
136543
136655
  return;
136544
136656
  }
136545
- log19.info("Detecting installed coding agents...");
136657
+ log20.info("Detecting installed coding agents...");
136546
136658
  const detected = [];
136547
136659
  for (const check2 of AGENT_CHECKS) {
136548
136660
  const path3 = await whichBinary(check2.binary);
136549
136661
  if (path3) {
136550
- log19.info("Detected coding agent: %s (%s)", check2.id, path3);
136662
+ log20.info("Detected coding agent: %s (%s)", check2.id, path3);
136551
136663
  detected.push({ id: check2.id, type: check2.type, label: check2.label });
136552
136664
  }
136553
136665
  }
136554
136666
  if (detected.length === 0) {
136555
- log19.info("No coding agent CLIs detected on PATH");
136667
+ log20.info("No coding agent CLIs detected on PATH");
136556
136668
  return;
136557
136669
  }
136558
136670
  const current = loadSettings();
@@ -136561,7 +136673,7 @@ async function ensureDefaultCodingAgents() {
136561
136673
  current.defaultCodingAgent = detected[0].id;
136562
136674
  }
136563
136675
  saveSettings(current);
136564
- log19.info("Enabled %d coding agent(s); default = %s", detected.length, current.defaultCodingAgent);
136676
+ log20.info("Enabled %d coding agent(s); default = %s", detected.length, current.defaultCodingAgent);
136565
136677
  }
136566
136678
  function ensureNotificationDefaults() {
136567
136679
  const settings = loadSettings();
@@ -136573,7 +136685,7 @@ function ensureNotificationDefaults() {
136573
136685
  ...settings,
136574
136686
  notifications: { ...notifications, soundOnNeedsAttention: true }
136575
136687
  });
136576
- log19.info("Set default notifications.soundOnNeedsAttention = true");
136688
+ log20.info("Set default notifications.soundOnNeedsAttention = true");
136577
136689
  }
136578
136690
  async function ensureClaudeHooks() {
136579
136691
  try {
@@ -136582,9 +136694,9 @@ async function ensureClaudeHooks() {
136582
136694
  return;
136583
136695
  }
136584
136696
  await installHooks();
136585
- log19.info("Installed Claude Code hooks");
136697
+ log20.info("Installed Claude Code hooks");
136586
136698
  } catch (err) {
136587
- log19.warn(
136699
+ log20.warn(
136588
136700
  "Failed to install Claude Code hooks: %s",
136589
136701
  err instanceof Error ? err.message : String(err)
136590
136702
  );
@@ -136592,11 +136704,11 @@ async function ensureClaudeHooks() {
136592
136704
  }
136593
136705
  async function ensureSkillsInstalled() {
136594
136706
  try {
136595
- const result = await installSkills({ log: log19 });
136707
+ const result = await installSkills({ log: log20 });
136596
136708
  const wrote = result.written.length + result.updated.length;
136597
136709
  const linkChange = result.linked.length;
136598
136710
  if (wrote > 0 || linkChange > 0 || result.conflicts.length > 0) {
136599
- log19.info(
136711
+ log20.info(
136600
136712
  "Synced CLI skills (shared: %d written, %d updated, %d unchanged; symlinks: %d created, %d already-linked, %d conflicts, %d skipped)",
136601
136713
  result.written.length,
136602
136714
  result.updated.length,
@@ -136608,13 +136720,13 @@ async function ensureSkillsInstalled() {
136608
136720
  );
136609
136721
  }
136610
136722
  } catch (err) {
136611
- log19.warn("Failed to sync CLI skills: %s", err instanceof Error ? err.message : String(err));
136723
+ log20.warn("Failed to sync CLI skills: %s", err instanceof Error ? err.message : String(err));
136612
136724
  }
136613
136725
  }
136614
136726
 
136615
136727
  // src/lib/terminal-manager.ts
136616
136728
  init_src();
136617
- import { existsSync as existsSync6 } from "node:fs";
136729
+ import { existsSync as existsSync7 } from "node:fs";
136618
136730
  import { join as join21 } from "node:path";
136619
136731
 
136620
136732
  // src/lib/terminal-layout-manager.ts
@@ -136642,7 +136754,7 @@ function removeTerminalFromLayout(workspaceId, terminalId) {
136642
136754
  }
136643
136755
 
136644
136756
  // src/lib/terminal-manager.ts
136645
- var log20 = createLogger("terminal");
136757
+ var log21 = createLogger("terminal");
136646
136758
  var MAX_SCROLLBACK_SIZE = 1e5;
136647
136759
  var terminals = /* @__PURE__ */ new Map();
136648
136760
  var workspaceTerminals = /* @__PURE__ */ new Map();
@@ -136673,20 +136785,20 @@ async function spawnTerminal(workspaceId, terminalId, options2) {
136673
136785
  if (options2?.cwd) {
136674
136786
  const resolved = join21(workspaceRoot, options2.cwd);
136675
136787
  if (!resolved.startsWith(workspaceRoot)) {
136676
- log20.warn("Ignoring cwd %s \u2014 resolves outside workspace root %s", options2.cwd, workspaceRoot);
136677
- } else if (existsSync6(resolved)) {
136788
+ log21.warn("Ignoring cwd %s \u2014 resolves outside workspace root %s", options2.cwd, workspaceRoot);
136789
+ } else if (existsSync7(resolved)) {
136678
136790
  cwd = resolved;
136679
136791
  } else {
136680
- log20.warn("Ignoring cwd %s \u2014 directory does not exist", options2.cwd);
136792
+ log21.warn("Ignoring cwd %s \u2014 directory does not exist", options2.cwd);
136681
136793
  }
136682
136794
  }
136683
- if (!existsSync6(cwd)) {
136795
+ if (!existsSync7(cwd)) {
136684
136796
  throw new Error(`Workspace directory does not exist: ${cwd}`);
136685
136797
  }
136686
- if (!existsSync6(shell)) {
136798
+ if (!existsSync7(shell)) {
136687
136799
  throw new Error(`Shell not found: ${shell}`);
136688
136800
  }
136689
- log20.debug(
136801
+ log21.debug(
136690
136802
  "Spawning shell %s in %s for terminal %s (PATH=%s)",
136691
136803
  shell,
136692
136804
  cwd,
@@ -136705,7 +136817,7 @@ async function spawnTerminal(workspaceId, terminalId, options2) {
136705
136817
  });
136706
136818
  } catch (err) {
136707
136819
  const msg = err instanceof Error ? err.message : String(err);
136708
- log20.error("pty.spawn failed: %s (shell=%s, cwd=%s)", msg, shell, cwd);
136820
+ log21.error("pty.spawn failed: %s (shell=%s, cwd=%s)", msg, shell, cwd);
136709
136821
  throw err;
136710
136822
  }
136711
136823
  const session = { pty: ptyProcess, scrollback: "", workspaceId };
@@ -136741,7 +136853,7 @@ async function spawnTerminal(workspaceId, terminalId, options2) {
136741
136853
  }
136742
136854
  });
136743
136855
  ptyProcess.onExit(() => {
136744
- log20.debug("Terminal exited: %s (workspace %s)", terminalId, workspaceId);
136856
+ log21.debug("Terminal exited: %s (workspace %s)", terminalId, workspaceId);
136745
136857
  terminals.delete(terminalId);
136746
136858
  outputListeners.delete(terminalId);
136747
136859
  const set2 = workspaceTerminals.get(workspaceId);
@@ -136849,13 +136961,36 @@ function killAllTerminals() {
136849
136961
 
136850
136962
  // src/lib/terminal-ws.ts
136851
136963
  init_src();
136852
- var log21 = createLogger("terminal-ws");
136964
+ var log22 = createLogger("terminal-ws");
136965
+ var MAX_CLOSE_REASON_BYTES = 123;
136966
+ function clampCloseReason(reason) {
136967
+ const enc = new TextEncoder();
136968
+ const bytes = enc.encode(reason);
136969
+ if (bytes.byteLength <= MAX_CLOSE_REASON_BYTES) return reason;
136970
+ const dec2 = new TextDecoder("utf-8", { fatal: true });
136971
+ for (let end = MAX_CLOSE_REASON_BYTES; end > 0; end--) {
136972
+ try {
136973
+ return dec2.decode(bytes.subarray(0, end));
136974
+ } catch {
136975
+ }
136976
+ }
136977
+ return "";
136978
+ }
136979
+ function safeClose(ws, code, reason) {
136980
+ if (ws.readyState === ws.OPEN) {
136981
+ try {
136982
+ ws.send(JSON.stringify({ type: "error", message: reason }));
136983
+ } catch {
136984
+ }
136985
+ }
136986
+ ws.close(code, clampCloseReason(reason));
136987
+ }
136853
136988
  async function handleTerminalConnection(ws, req) {
136854
136989
  const url2 = new URL(req.url, `http://${req.headers.host}`);
136855
136990
  const workspaceId = url2.searchParams.get("workspaceId");
136856
136991
  const terminalId = url2.searchParams.get("terminalId");
136857
136992
  if (!workspaceId || !terminalId) {
136858
- ws.close(4e3, "Missing workspaceId or terminalId");
136993
+ safeClose(ws, 4e3, "Missing workspaceId or terminalId");
136859
136994
  return;
136860
136995
  }
136861
136996
  const existing = getTerminalSession(terminalId);
@@ -136890,8 +137025,8 @@ async function handleTerminalConnection(ws, req) {
136890
137025
  session = await spawnTerminal(workspaceId, terminalId, spawnOpts);
136891
137026
  } catch (err) {
136892
137027
  const msg = err instanceof Error ? err.message : String(err);
136893
- log21.error("Failed to spawn terminal %s for workspace %s: %s", terminalId, workspaceId, msg);
136894
- ws.close(4001, msg);
137028
+ log22.error("Failed to spawn terminal %s for workspace %s: %s", terminalId, workspaceId, msg);
137029
+ safeClose(ws, 4001, msg);
136895
137030
  return;
136896
137031
  }
136897
137032
  attachSession(ws, terminalId, workspaceId, session, true);
@@ -136904,7 +137039,7 @@ async function handleTerminalConnection(ws, req) {
136904
137039
  });
136905
137040
  }
136906
137041
  function attachSession(ws, terminalId, workspaceId, session, isNew) {
136907
- log21.debug(
137042
+ log22.debug(
136908
137043
  "Terminal %s: %s (workspace %s)",
136909
137044
  isNew ? "connected" : "reconnected",
136910
137045
  terminalId,
@@ -136933,7 +137068,7 @@ function attachSession(ws, terminalId, workspaceId, session, isNew) {
136933
137068
  }, 3e3);
136934
137069
  const exitDisposable = session.pty.onExit(({ exitCode }) => {
136935
137070
  clearInterval(processInterval);
136936
- log21.debug("PTY exited with code %d for terminal %s", exitCode, terminalId);
137071
+ log22.debug("PTY exited with code %d for terminal %s", exitCode, terminalId);
136937
137072
  if (ws.readyState === ws.OPEN) {
136938
137073
  ws.close(1e3, "Terminal exited");
136939
137074
  }
@@ -136945,7 +137080,7 @@ function attachSession(ws, terminalId, workspaceId, session, isNew) {
136945
137080
  clearInterval(processInterval);
136946
137081
  dataDisposable.dispose();
136947
137082
  exitDisposable.dispose();
136948
- log21.debug("Terminal disconnected: %s (PTY kept alive)", terminalId);
137083
+ log22.debug("Terminal disconnected: %s (PTY kept alive)", terminalId);
136949
137084
  });
136950
137085
  }
136951
137086
  function handleMessage(ws, terminalId, session, message) {
@@ -136983,7 +137118,7 @@ function getToken() {
136983
137118
  }
136984
137119
 
136985
137120
  // src/lib/tunnel.ts
136986
- var log22 = createLogger("tunnel");
137121
+ var log23 = createLogger("tunnel");
136987
137122
  var tunnelProcess = null;
136988
137123
  var tunnelUrl = null;
136989
137124
  var startInProgress = null;
@@ -136997,7 +137132,7 @@ function appendToken(baseUrl, token) {
136997
137132
  }
136998
137133
  function spawnTunnel(options2, resolvedPath) {
136999
137134
  const args = ["tunnel", "--config", "/dev/null", "--url", `http://localhost:${options2.port}`];
137000
- log22.debug("spawning cloudflared %s", args.join(" "));
137135
+ log23.debug("spawning cloudflared %s", args.join(" "));
137001
137136
  return new Promise((resolve8, reject) => {
137002
137137
  const child = spawn7("cloudflared", args, {
137003
137138
  env: { ...process.env, PATH: resolvedPath },
@@ -137011,12 +137146,12 @@ function spawnTunnel(options2, resolvedPath) {
137011
137146
  for (const line2 of text4.split("\n")) {
137012
137147
  const trimmed = line2.trim();
137013
137148
  if (!trimmed) continue;
137014
- log22.debug("output: %s", trimmed);
137149
+ log23.debug("output: %s", trimmed);
137015
137150
  const url2 = extractUrl(trimmed);
137016
137151
  if (url2) {
137017
137152
  const token = getToken();
137018
137153
  tunnelUrl = appendToken(url2, token);
137019
- log22.debug("detected URL: %s", tunnelUrl);
137154
+ log23.debug("detected URL: %s", tunnelUrl);
137020
137155
  emit({ kind: "tunnel-url", url: tunnelUrl });
137021
137156
  if (!settled) {
137022
137157
  settled = true;
@@ -137031,7 +137166,7 @@ function spawnTunnel(options2, resolvedPath) {
137031
137166
  handleOutput(data);
137032
137167
  });
137033
137168
  child.on("error", (err) => {
137034
- log22.debug("process error: %s", err.message);
137169
+ log23.debug("process error: %s", err.message);
137035
137170
  tunnelProcess = null;
137036
137171
  tunnelUrl = null;
137037
137172
  emit({ kind: "tunnel-error", error: err.message });
@@ -137041,7 +137176,7 @@ function spawnTunnel(options2, resolvedPath) {
137041
137176
  }
137042
137177
  });
137043
137178
  child.on("exit", (code) => {
137044
- log22.debug("process exited with code: %d", code ?? -1);
137179
+ log23.debug("process exited with code: %d", code ?? -1);
137045
137180
  const wasRunning = tunnelProcess !== null && settled;
137046
137181
  tunnelProcess = null;
137047
137182
  tunnelUrl = null;
@@ -137063,7 +137198,7 @@ function spawnTunnel(options2, resolvedPath) {
137063
137198
  });
137064
137199
  setTimeout(() => {
137065
137200
  if (!settled) {
137066
- log22.debug("30s timeout reached, resolving without URL");
137201
+ log23.debug("30s timeout reached, resolving without URL");
137067
137202
  settled = true;
137068
137203
  resolve8();
137069
137204
  }
@@ -137072,12 +137207,12 @@ function spawnTunnel(options2, resolvedPath) {
137072
137207
  }
137073
137208
  async function startTunnel(options2) {
137074
137209
  if (startInProgress) {
137075
- log22.debug("startTunnel: start already in progress, waiting...");
137210
+ log23.debug("startTunnel: start already in progress, waiting...");
137076
137211
  await startInProgress;
137077
137212
  return;
137078
137213
  }
137079
137214
  if (tunnelProcess) {
137080
- log22.debug("startTunnel: already running, re-emitting URL");
137215
+ log23.debug("startTunnel: already running, re-emitting URL");
137081
137216
  if (tunnelUrl) {
137082
137217
  emit({ kind: "tunnel-url", url: tunnelUrl });
137083
137218
  }
@@ -144003,7 +144138,7 @@ function createContext8() {
144003
144138
  // src/trpc/router.ts
144004
144139
  import { execFile as execFile5, execFileSync as execFileSync2, spawn as spawn8 } from "node:child_process";
144005
144140
  import { randomUUID as randomUUID2 } from "node:crypto";
144006
- import { existsSync as existsSync8, constants as fsConstants, mkdirSync as mkdirSync7, unlinkSync as unlinkSync3 } from "node:fs";
144141
+ import { existsSync as existsSync9, constants as fsConstants, mkdirSync as mkdirSync7, unlinkSync as unlinkSync3 } from "node:fs";
144007
144142
  import { cp, mkdir as mkdir2, open as open2, readdir as readdir2, readFile as readFile2, rename, rm, stat as stat4, writeFile as writeFile2 } from "node:fs/promises";
144008
144143
  import { basename as basename2, dirname as dirname7, extname as extname2, isAbsolute as isAbsolute2, join as join23, resolve as resolve6, sep as sep2 } from "node:path";
144009
144144
  import { promisify } from "node:util";
@@ -144108,7 +144243,7 @@ function clearHistory(workspaceId, range, now = Date.now()) {
144108
144243
 
144109
144244
  // src/lib/chat-session-summary.ts
144110
144245
  init_src();
144111
- var log23 = createLogger("chat-session-summary");
144246
+ var log24 = createLogger("chat-session-summary");
144112
144247
  var REFRESH_KEY = Symbol.for("band.chat-session-summary.refresh");
144113
144248
  var g15 = globalThis;
144114
144249
  if (!g15[REFRESH_KEY]) g15[REFRESH_KEY] = /* @__PURE__ */ new Map();
@@ -144138,7 +144273,7 @@ async function ensureActiveSessionSummary(chatId, worktreePath) {
144138
144273
  });
144139
144274
  return getChat(chatId);
144140
144275
  } catch (err) {
144141
- log23.warn({ chatId, err }, "ensureActiveSessionSummary failed");
144276
+ log24.warn({ chatId, err }, "ensureActiveSessionSummary failed");
144142
144277
  return chat;
144143
144278
  }
144144
144279
  }
@@ -144175,7 +144310,7 @@ async function doRefresh(chatId, worktreePath) {
144175
144310
  lastModified: latest.lastModified
144176
144311
  });
144177
144312
  } catch (err) {
144178
- log23.warn({ chatId, err }, "active session refresh failed");
144313
+ log24.warn({ chatId, err }, "active session refresh failed");
144179
144314
  }
144180
144315
  }
144181
144316
 
@@ -144485,10 +144620,10 @@ function subscribeToFileChanges(workspaceId, listener) {
144485
144620
 
144486
144621
  // src/lib/formatter.ts
144487
144622
  init_src();
144488
- import { existsSync as existsSync7, realpathSync as realpathSync4 } from "node:fs";
144623
+ import { existsSync as existsSync8, realpathSync as realpathSync4 } from "node:fs";
144489
144624
  import { basename, dirname as dirname6, isAbsolute, join as join22, resolve as resolvePath } from "node:path";
144490
144625
  import prettier from "prettier";
144491
- var log24 = createLogger("formatter");
144626
+ var log25 = createLogger("formatter");
144492
144627
  var FormatterError = class extends Error {
144493
144628
  code;
144494
144629
  detail;
@@ -144512,7 +144647,7 @@ async function formatFile(worktreePath, filePath, content2, options2 = {}) {
144512
144647
  const ignorePath = resolvePath(worktreePath, ".prettierignore");
144513
144648
  const info = await prettier.getFileInfo(absFile, {
144514
144649
  resolveConfig: true,
144515
- ignorePath: existsSync7(ignorePath) ? ignorePath : void 0
144650
+ ignorePath: existsSync8(ignorePath) ? ignorePath : void 0
144516
144651
  });
144517
144652
  if (info.ignored) {
144518
144653
  return {
@@ -144543,7 +144678,7 @@ async function formatFile(worktreePath, filePath, content2, options2 = {}) {
144543
144678
  }
144544
144679
  const changed = formatted !== content2;
144545
144680
  if (changed) {
144546
- log24.info(
144681
+ log25.info(
144547
144682
  "Formatted %s with parser=%s (%d bytes in)",
144548
144683
  absFile,
144549
144684
  info.inferredParser,
@@ -144682,7 +144817,7 @@ function fuzzyScore(query, filePath) {
144682
144817
  // src/lib/terminal-config.ts
144683
144818
  init_src();
144684
144819
  init_zod();
144685
- var log25 = createLogger("terminal-config");
144820
+ var log26 = createLogger("terminal-config");
144686
144821
  var TerminalPaneConfigSchema = external_exports2.object({
144687
144822
  name: external_exports2.string().optional(),
144688
144823
  command: external_exports2.string().optional(),
@@ -144713,7 +144848,7 @@ function loadWorkspaceTerminalConfig(worktreePath, projectPath) {
144713
144848
  if (!terminalBlock) return null;
144714
144849
  const result = WorkspaceTerminalConfigSchema.safeParse(terminalBlock);
144715
144850
  if (!result.success) {
144716
- log25.warn(
144851
+ log26.warn(
144717
144852
  "Invalid workspace.terminal config: %s",
144718
144853
  result.error.issues.map((i2) => `${i2.path.join(".")}: ${i2.message}`).join("; ")
144719
144854
  );
@@ -144724,7 +144859,7 @@ function loadWorkspaceTerminalConfig(worktreePath, projectPath) {
144724
144859
 
144725
144860
  // src/trpc/router.ts
144726
144861
  var execFileAsync = promisify(execFile5);
144727
- var log26 = createLogger("trpc");
144862
+ var log27 = createLogger("trpc");
144728
144863
  var t2 = initTRPC.context().create();
144729
144864
  var publicProcedure = t2.procedure;
144730
144865
  var projectsRouter = t2.router({
@@ -144733,26 +144868,32 @@ var projectsRouter = t2.router({
144733
144868
  const settings = loadSettings();
144734
144869
  const statuses = loadCurrentStatuses();
144735
144870
  const statusMap = new Map(statuses.map((s6) => [s6.workspaceId, s6]));
144871
+ for (const project of state2.projects) {
144872
+ reconcileKindForProject(project);
144873
+ }
144736
144874
  const projects2 = await Promise.all(
144737
144875
  state2.projects.map(async (project) => {
144738
- const trackedBranches = new Set(project.worktrees.map((wt) => wt.branch));
144739
- const trackedByBranch = new Map(project.worktrees.map((wt) => [wt.branch, wt]));
144740
144876
  let worktrees2 = project.worktrees;
144741
- try {
144742
- const gitWorktrees = await listWorktrees(project.path);
144743
- worktrees2 = gitWorktrees.filter((wt) => !wt.isBare && trackedBranches.has(wt.branch)).map((wt) => ({
144744
- branch: wt.branch,
144745
- path: wt.path,
144746
- head: wt.head,
144747
- pinned: trackedByBranch.get(wt.branch)?.pinned ?? false
144748
- }));
144749
- } catch {
144877
+ if (project.kind === "git") {
144878
+ const trackedBranches = new Set(project.worktrees.map((wt) => wt.branch));
144879
+ const trackedByBranch = new Map(project.worktrees.map((wt) => [wt.branch, wt]));
144880
+ try {
144881
+ const gitWorktrees = await listWorktrees(project.path);
144882
+ worktrees2 = gitWorktrees.filter((wt) => !wt.isBare && trackedBranches.has(wt.branch)).map((wt) => ({
144883
+ branch: wt.branch,
144884
+ path: wt.path,
144885
+ head: wt.head,
144886
+ pinned: trackedByBranch.get(wt.branch)?.pinned ?? false
144887
+ }));
144888
+ } catch {
144889
+ }
144750
144890
  }
144751
144891
  return {
144752
144892
  name: project.name,
144753
144893
  path: project.path,
144754
144894
  defaultBranch: project.defaultBranch,
144755
144895
  label: project.label,
144896
+ kind: project.kind,
144756
144897
  worktrees: worktrees2.map((wt) => {
144757
144898
  const workspaceId = toWorkspaceId(project.name, wt.branch);
144758
144899
  const status = statusMap.get(workspaceId);
@@ -144769,7 +144910,7 @@ var projectsRouter = t2.router({
144769
144910
  }),
144770
144911
  checkPath: publicProcedure.input(external_exports2.object({ path: external_exports2.string() })).query(({ input }) => {
144771
144912
  const resolvedPath = resolve6(input.path);
144772
- const isGitRepo = existsSync8(join23(resolvedPath, ".git"));
144913
+ const isGitRepo = existsSync9(join23(resolvedPath, ".git"));
144773
144914
  return { isGitRepo };
144774
144915
  }),
144775
144916
  gitInit: publicProcedure.input(external_exports2.object({ path: external_exports2.string() })).mutation(async ({ input }) => {
@@ -144791,37 +144932,84 @@ var projectsRouter = t2.router({
144791
144932
  );
144792
144933
  }
144793
144934
  }
144935
+ const resolvedPath = resolve6(input.path);
144936
+ const kind = existsSync9(join23(resolvedPath, ".git")) ? "git" : "plain";
144794
144937
  let defaultBranch = "main";
144795
- try {
144796
- const env = { ...process.env };
144797
- if (env.PATH) {
144798
- env.PATH = `/opt/homebrew/bin:/usr/local/bin:${env.PATH}`;
144799
- }
144800
- const output = execFileSync2("git", ["symbolic-ref", "--short", "HEAD"], {
144801
- cwd: input.path,
144802
- env,
144803
- encoding: "utf-8"
144804
- }).trim();
144805
- if (output) defaultBranch = output;
144806
- } catch {
144807
- }
144808
144938
  let worktrees2 = [];
144809
- try {
144810
- const gitWorktrees = await listWorktrees(input.path);
144811
- worktrees2 = gitWorktrees.filter((wt) => !wt.isBare).map((wt) => ({ branch: wt.branch, path: wt.path, head: wt.head, pinned: false }));
144812
- } catch {
144939
+ if (kind === "git") {
144940
+ try {
144941
+ const env = { ...process.env };
144942
+ if (env.PATH) {
144943
+ env.PATH = `/opt/homebrew/bin:/usr/local/bin:${env.PATH}`;
144944
+ }
144945
+ const output = execFileSync2("git", ["symbolic-ref", "--short", "HEAD"], {
144946
+ cwd: resolvedPath,
144947
+ env,
144948
+ encoding: "utf-8"
144949
+ }).trim();
144950
+ if (output) defaultBranch = output;
144951
+ } catch {
144952
+ }
144953
+ try {
144954
+ const gitWorktrees = await listWorktrees(resolvedPath);
144955
+ worktrees2 = gitWorktrees.filter((wt) => !wt.isBare).map((wt) => ({ branch: wt.branch, path: wt.path, head: wt.head, pinned: false }));
144956
+ } catch {
144957
+ }
144958
+ } else {
144959
+ worktrees2 = [{ branch: "main", path: resolvedPath, pinned: false }];
144813
144960
  }
144814
144961
  const project = {
144815
144962
  name: name24,
144816
- path: input.path,
144963
+ // Store the canonical path so downstream consumers
144964
+ // (cronjob-scheduler, branch-status-poller, etc.) and the
144965
+ // self-heal loop in projects.list can compare against
144966
+ // `existsSync(project.path)` without false negatives from
144967
+ // unnormalized input.
144968
+ path: resolvedPath,
144817
144969
  defaultBranch,
144818
144970
  worktrees: worktrees2,
144819
- label: input.label ?? void 0
144971
+ label: input.label ?? void 0,
144972
+ kind
144820
144973
  };
144821
144974
  state2.projects.push(project);
144822
144975
  saveState(state2);
144823
144976
  return project;
144824
144977
  }),
144978
+ /**
144979
+ * Run `git init` inside a plain project and flip its kind to "git".
144980
+ * The "promote to git" escape hatch from #427: lets a user start with a
144981
+ * plain folder and later opt into branches/PRs without re-adding the
144982
+ * project. After promotion, the existing implicit workspace becomes the
144983
+ * project's default-branch worktree (its path is already the project
144984
+ * path, which matches git's convention for the main worktree).
144985
+ */
144986
+ promoteToGit: publicProcedure.input(external_exports2.object({ name: external_exports2.string() })).mutation(async ({ input }) => {
144987
+ const state2 = loadState();
144988
+ const project = state2.projects.find((p6) => p6.name === input.name);
144989
+ if (!project) {
144990
+ throw new TRPCError({
144991
+ code: "NOT_FOUND",
144992
+ message: `Project "${input.name}" not found`
144993
+ });
144994
+ }
144995
+ if (project.kind === "git") {
144996
+ throw new TRPCError({
144997
+ code: "BAD_REQUEST",
144998
+ message: `Project "${input.name}" is already a git project`
144999
+ });
145000
+ }
145001
+ if (!existsSync9(project.path)) {
145002
+ throw new TRPCError({
145003
+ code: "NOT_FOUND",
145004
+ message: `Project path "${project.path}" no longer exists. Remove the project and re-add it.`
145005
+ });
145006
+ }
145007
+ await execGit(["init", "-b", "main"], project.path);
145008
+ project.kind = "git";
145009
+ project.defaultBranch = "main";
145010
+ saveState(state2);
145011
+ return { ok: true, kind: project.kind, defaultBranch: project.defaultBranch };
145012
+ }),
144825
145013
  remove: publicProcedure.input(external_exports2.object({ name: external_exports2.string() })).mutation(({ input }) => {
144826
145014
  const state2 = loadState();
144827
145015
  state2.projects = state2.projects.filter((p6) => p6.name !== input.name);
@@ -144873,6 +145061,12 @@ var workspacesRouter = t2.router({
144873
145061
  if (!proj) {
144874
145062
  throw new Error(`Project "${input.project}" not found`);
144875
145063
  }
145064
+ if (proj.kind === "plain") {
145065
+ throw new TRPCError({
145066
+ code: "BAD_REQUEST",
145067
+ message: `Project "${input.project}" is a plain (non-git) folder and cannot have additional workspaces. Promote it to git (right-click the project \u2192 "Promote to git") to enable branches.`
145068
+ });
145069
+ }
144876
145070
  const existing = proj.worktrees.find((wt) => wt.branch === input.branch);
144877
145071
  if (existing) {
144878
145072
  return { ok: true, path: existing.path };
@@ -144914,6 +145108,12 @@ var workspacesRouter = t2.router({
144914
145108
  if (!proj) {
144915
145109
  throw new Error(`Project "${input.project}" not found`);
144916
145110
  }
145111
+ if (proj.kind === "plain") {
145112
+ throw new TRPCError({
145113
+ code: "BAD_REQUEST",
145114
+ message: `Project "${input.project}" is a plain (non-git) project. Remove the project instead of the workspace.`
145115
+ });
145116
+ }
144917
145117
  const { command, env: gitEnv } = gitCmd();
144918
145118
  const output = execFileSync2(command, ["worktree", "list", "--porcelain"], {
144919
145119
  cwd: proj.path,
@@ -144960,13 +145160,13 @@ var workspacesRouter = t2.router({
144960
145160
  try {
144961
145161
  const deletedTasks = deleteWorkspaceTasks(workspaceId);
144962
145162
  if (deletedTasks > 0) {
144963
- log26.info(
145163
+ log27.info(
144964
145164
  { workspaceId, count: deletedTasks },
144965
145165
  "deleted workspace tasks on removal"
144966
145166
  );
144967
145167
  }
144968
145168
  } catch (err) {
144969
- log26.error({ workspaceId, err }, "failed to delete workspace tasks on removal");
145169
+ log27.error({ workspaceId, err }, "failed to delete workspace tasks on removal");
144970
145170
  }
144971
145171
  emit({ kind: "remove", workspaceId });
144972
145172
  const projPath = proj.path;
@@ -144984,7 +145184,7 @@ var workspacesRouter = t2.router({
144984
145184
  timeout: 6e4
144985
145185
  });
144986
145186
  } catch (err) {
144987
- log26.warn({ err, workspaceId }, "teardown script failed");
145187
+ log27.warn({ err, workspaceId }, "teardown script failed");
144988
145188
  }
144989
145189
  }
144990
145190
  try {
@@ -145002,7 +145202,7 @@ var workspacesRouter = t2.router({
145002
145202
  encoding: "utf-8"
145003
145203
  });
145004
145204
  } catch (err) {
145005
- log26.warn({ err, workspaceId }, "git worktree prune failed");
145205
+ log27.warn({ err, workspaceId }, "git worktree prune failed");
145006
145206
  }
145007
145207
  }
145008
145208
  try {
@@ -145014,7 +145214,7 @@ var workspacesRouter = t2.router({
145014
145214
  } catch {
145015
145215
  }
145016
145216
  })().catch((err) => {
145017
- log26.error({ err, workspaceId }, "background workspace cleanup failed");
145217
+ log27.error({ err, workspaceId }, "background workspace cleanup failed");
145018
145218
  });
145019
145219
  });
145020
145220
  return { ok: true };
@@ -145031,6 +145231,12 @@ var workspacesRouter = t2.router({
145031
145231
  if (!proj) {
145032
145232
  throw new Error(`Project "${input.project}" not found`);
145033
145233
  }
145234
+ if (proj.kind === "plain") {
145235
+ throw new TRPCError({
145236
+ code: "BAD_REQUEST",
145237
+ message: `Project "${input.project}" is a plain (non-git) project. Pinning is not available.`
145238
+ });
145239
+ }
145034
145240
  const wt = proj.worktrees.find((w2) => w2.branch === input.branch);
145035
145241
  if (!wt) {
145036
145242
  throw new Error(`Workspace "${input.branch}" not found`);
@@ -145045,6 +145251,12 @@ var workspacesRouter = t2.router({
145045
145251
  if (!workspace) {
145046
145252
  throw new Error("Workspace not found");
145047
145253
  }
145254
+ if (workspace.project.kind === "plain") {
145255
+ throw new TRPCError({
145256
+ code: "BAD_REQUEST",
145257
+ message: `Project "${input.project}" is a plain (non-git) project. Git pull is not available.`
145258
+ });
145259
+ }
145048
145260
  const cwd = workspace.worktree.path;
145049
145261
  try {
145050
145262
  await execGit(["pull", "--rebase"], cwd);
@@ -145063,6 +145275,12 @@ var workspacesRouter = t2.router({
145063
145275
  if (!workspace) {
145064
145276
  throw new Error("Workspace not found");
145065
145277
  }
145278
+ if (workspace.project.kind === "plain") {
145279
+ throw new TRPCError({
145280
+ code: "BAD_REQUEST",
145281
+ message: `Project "${input.project}" is a plain (non-git) project. Git push is not available.`
145282
+ });
145283
+ }
145066
145284
  const cwd = workspace.worktree.path;
145067
145285
  try {
145068
145286
  await execGit(["push"], cwd);
@@ -145073,7 +145291,7 @@ var workspacesRouter = t2.router({
145073
145291
  }),
145074
145292
  runScript: publicProcedure.input(external_exports2.object({ path: external_exports2.string(), scriptType: external_exports2.string() })).mutation(({ input }) => {
145075
145293
  const scriptPath = join23(input.path, ".band", input.scriptType);
145076
- if (!existsSync8(scriptPath)) {
145294
+ if (!existsSync9(scriptPath)) {
145077
145295
  throw new Error(`Script "${input.scriptType}" not found`);
145078
145296
  }
145079
145297
  return new Promise((resolve8, reject) => {
@@ -145159,6 +145377,7 @@ var LANG_MAP = {
145159
145377
  };
145160
145378
  var compareBranchSchema = external_exports2.string().min(1).regex(/^[^-]/, "branch name must not start with '-'").optional();
145161
145379
  var EMPTY_TREE_ARGS = ["hash-object", "-t", "tree", "/dev/null"];
145380
+ var EMPTY_TREE_SHA = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
145162
145381
  async function resolveDiffContext(cwd, defaultBranch, diffMode, compareBranchInput) {
145163
145382
  const compareBranch = diffMode === "uncommitted" ? defaultBranch : compareBranchInput ?? defaultBranch;
145164
145383
  let headBranch;
@@ -145236,7 +145455,7 @@ var workspaceRouter = t2.router({
145236
145455
  *
145237
145456
  * Returns `{ skipped: true, reason }` when Prettier has no parser for
145238
145457
  * the file's extension (or it's covered by `.prettierignore`). Editors
145239
- * fire this off Cmd+Alt+F without checking the file type first, so a
145458
+ * fire this off Shift+Alt+F without checking the file type first, so a
145240
145459
  * soft skip is the right outcome for unsupported files rather than a
145241
145460
  * surfaced error.
145242
145461
  *
@@ -145347,7 +145566,7 @@ var workspaceRouter = t2.router({
145347
145566
  );
145348
145567
  branches = output.trim().split("\n").map((b10) => b10.trim()).filter(Boolean);
145349
145568
  } catch (err) {
145350
- log26.error(
145569
+ log27.error(
145351
145570
  `listBranches: for-each-ref failed for ${cwd}: ${err instanceof Error ? err.message : err}`
145352
145571
  );
145353
145572
  }
@@ -145437,6 +145656,18 @@ var workspaceRouter = t2.router({
145437
145656
  if (!workspace) {
145438
145657
  throw new Error("Workspace not found");
145439
145658
  }
145659
+ const hasGit = existsSync9(join23(workspace.worktree.path, ".git"));
145660
+ if (workspace.project.kind === "plain" || !hasGit) {
145661
+ const defaultBranch2 = workspace.project.defaultBranch;
145662
+ return {
145663
+ stats: { filesChanged: 0, insertions: 0, deletions: 0 },
145664
+ compareBranch: defaultBranch2,
145665
+ defaultBranch: defaultBranch2,
145666
+ headBranch: defaultBranch2,
145667
+ fileStatuses: {},
145668
+ mergeBase: EMPTY_TREE_SHA
145669
+ };
145670
+ }
145440
145671
  const cwd = workspace.worktree.path;
145441
145672
  const defaultBranch = workspace.project.defaultBranch;
145442
145673
  const { compareBranch, headBranch, mergeBase } = await resolveDiffContext(
@@ -145776,11 +146007,11 @@ var workspaceRouter = t2.router({
145776
146007
  if (!target.startsWith(root) || target === root) {
145777
146008
  throw new Error("Invalid path");
145778
146009
  }
145779
- if (existsSync8(target)) {
146010
+ if (existsSync9(target)) {
145780
146011
  throw new Error("A file or directory already exists at this path");
145781
146012
  }
145782
146013
  const parent = dirname7(target);
145783
- if (!existsSync8(parent)) {
146014
+ if (!existsSync9(parent)) {
145784
146015
  throw new Error("Parent directory does not exist");
145785
146016
  }
145786
146017
  const parentStat = await stat4(parent);
@@ -145805,11 +146036,11 @@ var workspaceRouter = t2.router({
145805
146036
  if (!target.startsWith(root) || target === root) {
145806
146037
  throw new Error("Invalid path");
145807
146038
  }
145808
- if (existsSync8(target)) {
146039
+ if (existsSync9(target)) {
145809
146040
  throw new Error("A file or directory already exists at this path");
145810
146041
  }
145811
146042
  const parent = dirname7(target);
145812
- if (!existsSync8(parent)) {
146043
+ if (!existsSync9(parent)) {
145813
146044
  throw new Error("Parent directory does not exist");
145814
146045
  }
145815
146046
  const parentStat = await stat4(parent);
@@ -145884,11 +146115,11 @@ var workspaceRouter = t2.router({
145884
146115
  } catch {
145885
146116
  throw new Error("Source path does not exist");
145886
146117
  }
145887
- if (existsSync8(toTarget)) {
146118
+ if (existsSync9(toTarget)) {
145888
146119
  throw new Error("A file or directory already exists at the destination");
145889
146120
  }
145890
146121
  const toParent = dirname7(toTarget);
145891
- if (!existsSync8(toParent)) {
146122
+ if (!existsSync9(toParent)) {
145892
146123
  throw new Error("Destination parent directory does not exist");
145893
146124
  }
145894
146125
  const toParentStat = await stat4(toParent);
@@ -145938,11 +146169,11 @@ var workspaceRouter = t2.router({
145938
146169
  if (entryStat.isDirectory() && toTarget.startsWith(fromTarget + sep2)) {
145939
146170
  throw new Error("Cannot copy a directory into itself");
145940
146171
  }
145941
- if (existsSync8(toTarget)) {
146172
+ if (existsSync9(toTarget)) {
145942
146173
  throw new Error("A file or directory already exists at the destination");
145943
146174
  }
145944
146175
  const toParent = dirname7(toTarget);
145945
- if (!existsSync8(toParent)) {
146176
+ if (!existsSync9(toParent)) {
145946
146177
  throw new Error("Destination parent directory does not exist");
145947
146178
  }
145948
146179
  const toParentStat = await stat4(toParent);
@@ -146195,21 +146426,21 @@ var tunnelRouter = t2.router({
146195
146426
  return getTunnelStatus();
146196
146427
  }),
146197
146428
  start: publicProcedure.input(external_exports2.object({}).optional()).mutation(async () => {
146198
- log26.debug("tunnel.start called");
146429
+ log27.debug("tunnel.start called");
146199
146430
  const port2 = parseInt(process.env.BAND_PORT || "3456", 10);
146200
- log26.debug("tunnel.start: port=%d", port2);
146431
+ log27.debug("tunnel.start: port=%d", port2);
146201
146432
  try {
146202
146433
  await startTunnel({ port: port2 });
146203
146434
  } catch (err) {
146204
- log26.debug({ err }, "tunnel.start: startTunnel failed");
146435
+ log27.debug({ err }, "tunnel.start: startTunnel failed");
146205
146436
  return { ok: true, url: null };
146206
146437
  }
146207
146438
  const status = getTunnelStatus();
146208
- log26.debug({ status }, "tunnel.start: after startTunnel");
146439
+ log27.debug({ status }, "tunnel.start: after startTunnel");
146209
146440
  if (status.url) {
146210
146441
  return { ok: true, url: status.url };
146211
146442
  }
146212
- log26.debug("tunnel.start: no URL available");
146443
+ log27.debug("tunnel.start: no URL available");
146213
146444
  return { ok: true, url: null };
146214
146445
  }),
146215
146446
  stop: publicProcedure.mutation(async () => {
@@ -146535,15 +146766,15 @@ async function loadJsonlPage(opts) {
146535
146766
  }
146536
146767
  var servicesRouter = t2.router({
146537
146768
  health: publicProcedure.query(() => {
146538
- log26.debug("services.health called");
146769
+ log27.debug("services.health called");
146539
146770
  const tunnel = getTunnelStatus();
146540
- log26.debug({ tunnel }, "services.health: tunnel status");
146771
+ log27.debug({ tunnel }, "services.health: tunnel status");
146541
146772
  const result = {
146542
146773
  webserver: true,
146543
146774
  tunnel: tunnel.running,
146544
146775
  tunnel_url: tunnel.url
146545
146776
  };
146546
- log26.debug({ result }, "services.health result");
146777
+ log27.debug({ result }, "services.health result");
146547
146778
  return result;
146548
146779
  }),
146549
146780
  // Activity level controls how often the branch-status poller fires.
@@ -146937,7 +147168,7 @@ var chatsRouter = t2.router({
146937
147168
  summary = info?.summary;
146938
147169
  lastModified = info?.lastModified;
146939
147170
  } catch (err) {
146940
- log26.warn(
147171
+ log27.warn(
146941
147172
  { chatId: input.chatId, sessionId: input.sessionId, err },
146942
147173
  "setActiveSession: getSessionInfo failed"
146943
147174
  );
@@ -147057,7 +147288,7 @@ var browserHostRouter = t2.router({
147057
147288
  // can confirm in the server log that the bridge component actually
147058
147289
  // executed. Drop once the experiment is stable.
147059
147290
  ping: publicProcedure.input(external_exports2.object({ where: external_exports2.string() })).mutation(({ input }) => {
147060
- log26.info("browserHost.ping from %s", input.where);
147291
+ log27.info("browserHost.ping from %s", input.where);
147061
147292
  return { ok: true };
147062
147293
  }),
147063
147294
  ensureView: publicProcedure.subscription(async function* (opts) {
@@ -147560,10 +147791,20 @@ var assets = build_default(clientDir, {
147560
147791
  gzip: true,
147561
147792
  etag: true
147562
147793
  });
147563
- var openApiDoc = JSON.parse(readFileSync9(join24(import.meta.dirname, "openapi.json"), "utf-8"));
147564
- openApiDoc.servers = [{ url: "/trpc" }];
147565
- var openApiSpec = JSON.stringify(openApiDoc, null, 2);
147566
- var scalarHtml = getScalarHtml("/api/openapi.json");
147794
+ var _openApiSpec = null;
147795
+ function getOpenApiSpec() {
147796
+ if (_openApiSpec !== null) return _openApiSpec;
147797
+ const openApiDoc = JSON.parse(readFileSync9(join24(import.meta.dirname, "openapi.json"), "utf-8"));
147798
+ openApiDoc.servers = [{ url: "/trpc" }];
147799
+ _openApiSpec = JSON.stringify(openApiDoc, null, 2);
147800
+ return _openApiSpec;
147801
+ }
147802
+ var _scalarHtml = null;
147803
+ function getCachedScalarHtml() {
147804
+ if (_scalarHtml !== null) return _scalarHtml;
147805
+ _scalarHtml = getScalarHtml("/api/openapi.json");
147806
+ return _scalarHtml;
147807
+ }
147567
147808
  function serveStaticFile(res, root, subdir, rawFilename) {
147568
147809
  const filename = basename3(decodeURIComponent(rawFilename));
147569
147810
  if (!filename || filename.includes("..")) {
@@ -147617,6 +147858,7 @@ function serveWorkspaceFile(res, workspaceId, rawPath) {
147617
147858
  async function main() {
147618
147859
  runMigrations();
147619
147860
  loadChatsFromDb();
147861
+ loadBrowsersFromDb();
147620
147862
  cleanupStaleTasks();
147621
147863
  startTaskPruneScheduler();
147622
147864
  const resetCount = resetAgentStatuses();
@@ -147722,7 +147964,7 @@ async function main() {
147722
147964
  "Cache-Control": "no-cache",
147723
147965
  "Access-Control-Allow-Origin": "*"
147724
147966
  });
147725
- res.end(openApiSpec);
147967
+ res.end(getOpenApiSpec());
147726
147968
  return;
147727
147969
  }
147728
147970
  if (req.url === "/api/docs") {
@@ -147730,7 +147972,7 @@ async function main() {
147730
147972
  "Content-Type": "text/html",
147731
147973
  "Cache-Control": "no-cache"
147732
147974
  });
147733
- res.end(scalarHtml);
147975
+ res.end(getCachedScalarHtml());
147734
147976
  return;
147735
147977
  }
147736
147978
  if (req.url?.startsWith("/mcp")) {
@@ -147855,6 +148097,7 @@ async function main() {
147855
148097
  });
147856
148098
  httpServer.listen(port, "0.0.0.0", () => {
147857
148099
  console.log(`Web server listening on http://0.0.0.0:${port}`);
148100
+ console.log(`Web server boot took ${(process.uptime() * 1e3).toFixed(0)} ms`);
147858
148101
  const settings = loadSettings();
147859
148102
  if (settings.autoStartTunnel) {
147860
148103
  checkPrereqs().then((prereqs) => {