@band-app/server 0.14.0 → 0.16.2

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-CjLCp0Ep.js → DockviewTerminalContainer-D2lnsm6V.js} +2 -2
  2. package/dist/client/assets/TerminalPanel-SEbvgXv_.js +4 -0
  3. package/dist/client/assets/{_basePickBy-CQtQtDdV.js → _basePickBy-C-uqClKF.js} +1 -1
  4. package/dist/client/assets/{_baseUniq-D4iUo06T.js → _baseUniq-sN_xdSud.js} +1 -1
  5. package/dist/client/assets/{arc-Bk8y2eXC.js → arc-DOqEiCLs.js} +1 -1
  6. package/dist/client/assets/{architectureDiagram-VXUJARFQ-nOygF9m2.js → architectureDiagram-VXUJARFQ-DqRs-Rmj.js} +1 -1
  7. package/dist/client/assets/{blockDiagram-VD42YOAC-CZ4Nt28v.js → blockDiagram-VD42YOAC-Dxh5tO7I.js} +1 -1
  8. package/dist/client/assets/{c4Diagram-YG6GDRKO-C31ZTlu2.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-GjIrL7gq.js → chunk-4BX2VUAB-BckEbEmg.js} +1 -1
  11. package/dist/client/assets/{chunk-55IACEB6-Dd6rfkjS.js → chunk-55IACEB6-Ds9A0UL5.js} +1 -1
  12. package/dist/client/assets/{chunk-B4BG7PRW-Dzfqlv3x.js → chunk-B4BG7PRW-BbdA9dFb.js} +1 -1
  13. package/dist/client/assets/{chunk-DI55MBZ5-CP20GTKI.js → chunk-DI55MBZ5-C10prUQu.js} +1 -1
  14. package/dist/client/assets/{chunk-FMBD7UC4-BjMT67vC.js → chunk-FMBD7UC4-CMO5VhEI.js} +1 -1
  15. package/dist/client/assets/{chunk-QN33PNHL-DjTHrDYb.js → chunk-QN33PNHL-BrbSzW7G.js} +1 -1
  16. package/dist/client/assets/{chunk-QZHKN3VN-DaZKkfet.js → chunk-QZHKN3VN-BjFQUCU6.js} +1 -1
  17. package/dist/client/assets/{chunk-TZMSLE5B-C-s0f3Nv.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-DWG1ghIg.js → cose-bilkent-S5V4N54A-DbSjwZ4l.js} +1 -1
  22. package/dist/client/assets/{dagre-6UL2VRFP-D5Xahd1k.js → dagre-6UL2VRFP-Q5hxi0O0.js} +1 -1
  23. package/dist/client/assets/{diagram-PSM6KHXK-DB5Yj4_A.js → diagram-PSM6KHXK-D7kyAUq5.js} +1 -1
  24. package/dist/client/assets/{diagram-QEK2KX5R-CaI4Qm9S.js → diagram-QEK2KX5R-B7mpl_Jj.js} +1 -1
  25. package/dist/client/assets/{diagram-S2PKOQOG-Bc8uBUs8.js → diagram-S2PKOQOG-CcIvSvFS.js} +1 -1
  26. package/dist/client/assets/{erDiagram-Q2GNP2WA-BEdcnVfH.js → erDiagram-Q2GNP2WA-M2OHKSFi.js} +1 -1
  27. package/dist/client/assets/{flowDiagram-NV44I4VS-CP1RMYLo.js → flowDiagram-NV44I4VS-Ot2zCa0t.js} +1 -1
  28. package/dist/client/assets/{ganttDiagram-JELNMOA3-DybSY1zy.js → ganttDiagram-JELNMOA3-Dtl6PI3C.js} +1 -1
  29. package/dist/client/assets/{gitGraphDiagram-V2S2FVAM-B1zM9cMa.js → gitGraphDiagram-V2S2FVAM-DJCTwkyi.js} +1 -1
  30. package/dist/client/assets/{graph-CPZWfRvB.js → graph-DhvBAydB.js} +1 -1
  31. package/dist/client/assets/{highlighted-body-B3W2YXNL-Bugc5R-I.js → highlighted-body-B3W2YXNL-C6fHuUGl.js} +1 -1
  32. package/dist/client/assets/{index-BSZ6dtOY.js → index-26c50Xcq.js} +1 -1
  33. package/dist/client/assets/index-B1K9dSWl.js +1 -0
  34. package/dist/client/assets/{index-BydRuBb_.js → index-B7VmPIW6.js} +1 -1
  35. package/dist/client/assets/{index-vP2I9_aT.js → index-BBv9ZEF9.js} +1 -1
  36. package/dist/client/assets/{index-DEVawlAU.js → index-BDHBx5UL.js} +1 -1
  37. package/dist/client/assets/{index-CYD8Chzm.js → index-BUTfo7TS.js} +1 -1
  38. package/dist/client/assets/{index-D5BWxHiy.js → index-BYvWvSws.js} +1 -1
  39. package/dist/client/assets/{index-SP7EGmTJ.js → index-CDbyr_lc.js} +1 -1
  40. package/dist/client/assets/{index-X_vPvtM3.js → index-CHGnZzhm.js} +1 -1
  41. package/dist/client/assets/{index-D4U4UdW8.js → index-CKHhLCNz.js} +1 -1
  42. package/dist/client/assets/{index-BQkn45ME.js → index-CfsvL24Z.js} +1 -1
  43. package/dist/client/assets/{index-mOXvCPx7.js → index-CjXcgzNg.js} +1 -1
  44. package/dist/client/assets/{index-BSvAdzfH.js → index-CuNktTO3.js} +1 -1
  45. package/dist/client/assets/{index-Cm01-0la.js → index-DDe15mVl.js} +1 -1
  46. package/dist/client/assets/{index-Bu-ZuLPi.js → index-I4Tc5Cuc.js} +1 -1
  47. package/dist/client/assets/{index-CrF4PAiW.js → index-MZ-6_xYm.js} +1 -1
  48. package/dist/client/assets/{index-BGq7dGXw.js → index-SeTSJcqN.js} +1 -1
  49. package/dist/client/assets/{index-CijlrIEA.js → index-_yteHBmq.js} +1 -1
  50. package/dist/client/assets/{infoDiagram-HS3SLOUP-BCk158Sc.js → infoDiagram-HS3SLOUP-CbAjFJUe.js} +1 -1
  51. package/dist/client/assets/{journeyDiagram-XKPGCS4Q-Dmw405Jr.js → journeyDiagram-XKPGCS4Q-Bf_0viAE.js} +1 -1
  52. package/dist/client/assets/{kanban-definition-3W4ZIXB7-DqNJB_Z3.js → kanban-definition-3W4ZIXB7-CB2ylbw7.js} +1 -1
  53. package/dist/client/assets/{layout-ODCofYfe.js → layout-Cp_4dcMO.js} +1 -1
  54. package/dist/client/assets/{linear-CHYpf9oZ.js → linear-D1KyszeO.js} +1 -1
  55. package/dist/client/assets/main-CBJTAZFq.css +1 -0
  56. package/dist/client/assets/{main-81Q8XW4n.js → main-Cl2c5yKs.js} +245 -245
  57. package/dist/client/assets/{mindmap-definition-VGOIOE7T-DD4Ndh7U.js → mindmap-definition-VGOIOE7T-Cm_2Y7ZK.js} +1 -1
  58. package/dist/client/assets/{pieDiagram-ADFJNKIX-C9vB0eMW.js → pieDiagram-ADFJNKIX-C9PiUHN5.js} +1 -1
  59. package/dist/client/assets/{quadrantDiagram-AYHSOK5B-DKJimp3K.js → quadrantDiagram-AYHSOK5B-Cj0nbFw-.js} +1 -1
  60. package/dist/client/assets/{requirementDiagram-UZGBJVZJ-_AjYejyE.js → requirementDiagram-UZGBJVZJ-BVgceiyR.js} +1 -1
  61. package/dist/client/assets/{sankeyDiagram-TZEHDZUN-BN_ggjKc.js → sankeyDiagram-TZEHDZUN-D7dheggz.js} +1 -1
  62. package/dist/client/assets/{sequenceDiagram-WL72ISMW-Ck-zlUdD.js → sequenceDiagram-WL72ISMW-DVDMYgkc.js} +1 -1
  63. package/dist/client/assets/{square-terminal-DVejknjY.js → square-terminal-C64ybmC7.js} +1 -1
  64. package/dist/client/assets/{stateDiagram-FKZM4ZOC-Ccmp8_yK.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-Bm5sYZxz.js → timeline-definition-IT6M3QCI-Cs1CMQvF.js} +1 -1
  67. package/dist/client/assets/{treemap-GDKQZRPO-C6oEKt2u.js → treemap-GDKQZRPO-DerMxDGL.js} +1 -1
  68. package/dist/client/assets/{useSessionListContext-l-QdtVht.js → useSessionListContext-BcM5_lz3.js} +1 -1
  69. package/dist/client/assets/{workspace._workspaceId-BPktlGJd.js → workspace._workspaceId-C4dZT1kN.js} +1 -1
  70. package/dist/client/assets/{workspace._workspaceId.changes-DNu9WOV2.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._-BHhCSQ0w.js → workspace._workspaceId.code._-DRRjmZ4D.js} +1 -1
  73. package/dist/client/assets/{workspace._workspaceId.code.index-0y_GQ6sP.js → workspace._workspaceId.code.index-CQLsjESL.js} +1 -1
  74. package/dist/client/assets/{workspace._workspaceId.index-CtrlsI9z.js → workspace._workspaceId.index-CE3X4XHe.js} +1 -1
  75. package/dist/client/assets/{workspace._workspaceId.terminal-DsvwvNc_.js → workspace._workspaceId.terminal-0Iuu4wZI.js} +2 -2
  76. package/dist/client/assets/{xychartDiagram-PRI3JC2R-ru_cdw1P.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-DVUKt_HJ.js → DockviewTerminalContainer-RbFw8Eo4.js} +3 -3
  81. package/dist/server/assets/{TerminalPanel-hEaDQqdo.js → TerminalPanel-BS0KF1ac.js} +52 -22
  82. package/dist/server/assets/{_basePickBy-Nag5vQgo.js → _basePickBy-Vtp-JFm9.js} +2 -2
  83. package/dist/server/assets/{_baseUniq-BcTT1Srn.js → _baseUniq-CRtvsDi1.js} +1 -1
  84. package/dist/server/assets/{_tanstack-start-manifest_v-D0rpEWOW.js → _tanstack-start-manifest_v-787sukfk.js} +1 -1
  85. package/dist/server/assets/{arc-CDj2zIqg.js → arc-ChWehBm_.js} +1 -1
  86. package/dist/server/assets/{architecture-7HQA4BMR-7A5zOnYc.js → architecture-7HQA4BMR-BiLezQsp.js} +6 -6
  87. package/dist/server/assets/{architectureDiagram-VXUJARFQ--uDzxMk3.js → architectureDiagram-VXUJARFQ-tjTQ4ZaT.js} +6 -6
  88. package/dist/server/assets/{blockDiagram-VD42YOAC-DAc1UHQ6.js → blockDiagram-VD42YOAC-C0oBPtSv.js} +6 -6
  89. package/dist/server/assets/{c4Diagram-YG6GDRKO-ByeFZAO1.js → c4Diagram-YG6GDRKO-nGE1cXwD.js} +2 -2
  90. package/dist/server/assets/{channel-B6u30R-7.js → channel-CqQOLgw9.js} +1 -1
  91. package/dist/server/assets/{chunk-4BX2VUAB-X_mApFBH.js → chunk-4BX2VUAB-DrJXJmx5.js} +1 -1
  92. package/dist/server/assets/{chunk-55IACEB6-DMO5XJKd.js → chunk-55IACEB6-CKxRFH9J.js} +1 -1
  93. package/dist/server/assets/{chunk-B4BG7PRW-Da7HlBM1.js → chunk-B4BG7PRW-BxyNZV2w.js} +4 -4
  94. package/dist/server/assets/{chunk-DI55MBZ5-DuioLWo-.js → chunk-DI55MBZ5-CajwqGPE.js} +3 -3
  95. package/dist/server/assets/{chunk-FMBD7UC4-BhKTk6rW.js → chunk-FMBD7UC4-D1CO-v-G.js} +1 -1
  96. package/dist/server/assets/{chunk-QN33PNHL-BgZXw9n5.js → chunk-QN33PNHL-D4KiZklP.js} +1 -1
  97. package/dist/server/assets/{chunk-QZHKN3VN-DHuwppPm.js → chunk-QZHKN3VN-CNElfh9C.js} +1 -1
  98. package/dist/server/assets/{chunk-TZMSLE5B-w8fhHHwn.js → chunk-TZMSLE5B-CHBqvPAr.js} +1 -1
  99. package/dist/server/assets/{classDiagram-v2-WZHVMYZB-BZf5qvSp.js → classDiagram-2ON5EDUG-D3C4Rk7Q.js} +5 -5
  100. package/dist/server/assets/{classDiagram-2ON5EDUG-BZf5qvSp.js → classDiagram-v2-WZHVMYZB-D3C4Rk7Q.js} +5 -5
  101. package/dist/server/assets/{clone-CjoEs-v-.js → clone-DsPS0_DH.js} +1 -1
  102. package/dist/server/assets/{cose-bilkent-S5V4N54A-BNk0NAbB.js → cose-bilkent-S5V4N54A-V_MYkZlm.js} +1 -1
  103. package/dist/server/assets/{dagre-6UL2VRFP-C0_F8CHc.js → dagre-6UL2VRFP-D_Mh5gNH.js} +6 -6
  104. package/dist/server/assets/{diagram-PSM6KHXK-LARMaMiS.js → diagram-PSM6KHXK-B9dGPsE9.js} +7 -7
  105. package/dist/server/assets/{diagram-QEK2KX5R-jKvozWzw.js → diagram-QEK2KX5R-BcfmavO-.js} +6 -6
  106. package/dist/server/assets/{diagram-S2PKOQOG-5a2K9q2r.js → diagram-S2PKOQOG-B8urPf9c.js} +6 -6
  107. package/dist/server/assets/{erDiagram-Q2GNP2WA-DPxBpQns.js → erDiagram-Q2GNP2WA-CzG0zKt-.js} +4 -4
  108. package/dist/server/assets/{flowDiagram-NV44I4VS-CX3XZT5Y.js → flowDiagram-NV44I4VS-Bk7aIalC.js} +5 -5
  109. package/dist/server/assets/{ganttDiagram-JELNMOA3-BmjiDolw.js → ganttDiagram-JELNMOA3-wmt8nm9q.js} +2 -2
  110. package/dist/server/assets/{gitGraph-G5XIXVHT-BxG8jjGU.js → gitGraph-G5XIXVHT-CmiFNHiv.js} +6 -6
  111. package/dist/server/assets/{gitGraphDiagram-V2S2FVAM-ChLdCg6Z.js → gitGraphDiagram-V2S2FVAM-OV2DR1Ux.js} +7 -7
  112. package/dist/server/assets/{graph-Bx5JUzop.js → graph-ziMVg61H.js} +2 -2
  113. package/dist/server/assets/{highlighted-body-B3W2YXNL-DDkviWDm.js → highlighted-body-B3W2YXNL-DX00yTJM.js} +1 -1
  114. package/dist/server/assets/{index-BoT6zVKn.js → index-9M09S61v.js} +2 -2
  115. package/dist/server/assets/{index-OEnZTnkb.js → index-B5x9IUkQ.js} +2 -2
  116. package/dist/server/assets/{index-Bb41VJM3.js → index-BvBMEwhL.js} +4 -4
  117. package/dist/server/assets/{index-C4USpn2y.js → index-C-k9sCKq.js} +2 -2
  118. package/dist/server/assets/{index-BP-Fy_Ud.js → index-CKmyLecf.js} +2 -2
  119. package/dist/server/assets/{index-DO3wKBul.js → index-CXnsJrX8.js} +5 -5
  120. package/dist/server/assets/{index-Dp74K7A4.js → index-Ce2uXVrE.js} +2 -2
  121. package/dist/server/assets/{index-CDCloCld.js → index-CiWhFogO.js} +2 -2
  122. package/dist/server/assets/{index-Cuuby6oP.js → index-D5nqcxSY.js} +3 -3
  123. package/dist/server/assets/{index-BnAK5zRH.js → index-DLmI6-iR.js} +1 -1
  124. package/dist/server/assets/{index-DSGH2NU6.js → index-DNaA-OTp.js} +2 -2
  125. package/dist/server/assets/{index-DrrqcbHg.js → index-DPAkuW3l.js} +2 -2
  126. package/dist/server/assets/{index-CLsI0TMm.js → index-VtjR2oZj.js} +2 -2
  127. package/dist/server/assets/{index-DjhMY50H.js → index-ayG05uhc.js} +3 -3
  128. package/dist/server/assets/{index-DTkAyV2J.js → index-l8a7u6GS.js} +2 -2
  129. package/dist/server/assets/{index-Duvita0E.js → index-sKmEy2Z2.js} +5 -5
  130. package/dist/server/assets/{index-BKnmhk3u.js → index-sbo2EHgw.js} +2 -2
  131. package/dist/server/assets/{index-BBCpeEJl.js → index-xVhCXu45.js} +2 -2
  132. package/dist/server/assets/{info-VBDWY6EO-6bfVBBeD.js → info-VBDWY6EO-muqpsCRw.js} +6 -6
  133. package/dist/server/assets/{infoDiagram-HS3SLOUP-B1v9HmWX.js → infoDiagram-HS3SLOUP-D8EoxteQ.js} +5 -5
  134. package/dist/server/assets/{journeyDiagram-XKPGCS4Q-Cb26EUwI.js → journeyDiagram-XKPGCS4Q-BwZk-fnC.js} +4 -4
  135. package/dist/server/assets/{kanban-definition-3W4ZIXB7-Cv4GaETC.js → kanban-definition-3W4ZIXB7-DEfYos8T.js} +2 -2
  136. package/dist/server/assets/{layout-CQJCngSZ.js → layout-CKMmyz2h.js} +4 -4
  137. package/dist/server/assets/{linear-Civ7P345.js → linear-DXR7qYUB.js} +1 -1
  138. package/dist/server/assets/{mermaid-3ZIDBTTL-EBg4-fWO.js → mermaid-3ZIDBTTL-DxhML77C.js} +1 -1
  139. package/dist/server/assets/{mermaid-parser.core-2e_OlBPy.js → mermaid-parser.core-DBGA5y48.js} +11 -11
  140. package/dist/server/assets/{mindmap-definition-VGOIOE7T-uP_bqLZ-.js → mindmap-definition-VGOIOE7T-Bg8B0Ls9.js} +3 -3
  141. package/dist/server/assets/{packet-DYOGHKS2-C9RhEbus.js → packet-DYOGHKS2-CnH_YgfD.js} +6 -6
  142. package/dist/server/assets/{pie-VRWISCQL-DXIjmNyN.js → pie-VRWISCQL-iceCWNPC.js} +6 -6
  143. package/dist/server/assets/{pieDiagram-ADFJNKIX-C2Qp43pf.js → pieDiagram-ADFJNKIX-Bw3RR9nb.js} +7 -7
  144. package/dist/server/assets/{quadrantDiagram-AYHSOK5B-C9I9kDB1.js → quadrantDiagram-AYHSOK5B-CpLsW_Ir.js} +2 -2
  145. package/dist/server/assets/{radar-ZZBFDIW7-CEz6u4b9.js → radar-ZZBFDIW7-Bab4MCR4.js} +6 -6
  146. package/dist/server/assets/{requirementDiagram-UZGBJVZJ-DmCcKz-Y.js → requirementDiagram-UZGBJVZJ-DkGtaEnw.js} +3 -3
  147. package/dist/server/assets/{router-BlHVACji.js → router-yk-AJHab.js} +1927 -1027
  148. package/dist/server/assets/{sankeyDiagram-TZEHDZUN-DM2H1xi3.js → sankeyDiagram-TZEHDZUN-CtEV3_Bx.js} +1 -1
  149. package/dist/server/assets/{sequenceDiagram-WL72ISMW-DWDQKCiq.js → sequenceDiagram-WL72ISMW-BMW4qEme.js} +3 -3
  150. package/dist/server/assets/{square-terminal-CCwkUkGX.js → square-terminal-Bui9B6KN.js} +1 -1
  151. package/dist/server/assets/{stateDiagram-FKZM4ZOC-_4Khdh4I.js → stateDiagram-FKZM4ZOC-C7xazM8E.js} +8 -8
  152. package/dist/server/assets/{stateDiagram-v2-4FDKWEC3-Cos-pE9j.js → stateDiagram-v2-4FDKWEC3-D_rYvDGP.js} +4 -4
  153. package/dist/server/assets/{timeline-definition-IT6M3QCI-DeLSZGNq.js → timeline-definition-IT6M3QCI-BaAlfxrc.js} +2 -2
  154. package/dist/server/assets/{treemap-GDKQZRPO-LKeqy604.js → treemap-GDKQZRPO-DlP1TABE.js} +6 -6
  155. package/dist/server/assets/{workspace._workspaceId-C0PMWq41.js → workspace._workspaceId-Be45P7LL.js} +2 -2
  156. package/dist/server/assets/{workspace._workspaceId.changes-CzyqOgM_.js → workspace._workspaceId.changes-EoyIscxQ.js} +1 -1
  157. package/dist/server/assets/{workspace._workspaceId.code._-QG2CLJod.js → workspace._workspaceId.code._-CcX7Gt0G.js} +1 -1
  158. package/dist/server/assets/{workspace._workspaceId.code.index-CVy3VzQK.js → workspace._workspaceId.code.index-CFbCDVph.js} +1 -1
  159. package/dist/server/assets/{workspace._workspaceId.index-LBt-0JYY.js → workspace._workspaceId.index-DmYHy6nH.js} +1 -1
  160. package/dist/server/assets/{workspace._workspaceId.terminal-jMK4pgOD.js → workspace._workspaceId.terminal-D_KPwmYr.js} +2 -2
  161. package/dist/server/assets/{xychartDiagram-PRI3JC2R-DHrKht9t.js → xychartDiagram-PRI3JC2R-Cq7t_yS-.js} +2 -2
  162. package/dist/server/server.js +2 -2
  163. package/dist/start-server.mjs +766 -467
  164. package/package.json +6 -5
  165. package/dist/client/assets/TerminalPanel-Cu7fEaGN.js +0 -4
  166. package/dist/client/assets/channel-BgmjEVPj.js +0 -1
  167. package/dist/client/assets/classDiagram-2ON5EDUG-BKsagNLe.js +0 -1
  168. package/dist/client/assets/classDiagram-v2-WZHVMYZB-BKsagNLe.js +0 -1
  169. package/dist/client/assets/clone-CBcd3GIz.js +0 -1
  170. package/dist/client/assets/index-BKUORVg0.js +0 -1
  171. package/dist/client/assets/main-DYrDxnSM.css +0 -1
  172. package/dist/client/assets/stateDiagram-v2-4FDKWEC3-Cgq8vGxD.js +0 -1
  173. package/dist/client/assets/workspace._workspaceId.code-DP6cBpn1.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,39 +120421,94 @@ 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
+
120449
+ // ../../packages/dashboard-core/src/lib/language-map.ts
120450
+ var SUPPORTED_LANGUAGES = [
120451
+ { id: "plaintext", label: "Plain Text" },
120452
+ { id: "bash", label: "Bash / Shell" },
120453
+ { id: "c", label: "C" },
120454
+ { id: "clojure", label: "Clojure" },
120455
+ { id: "cpp", label: "C++" },
120456
+ { id: "csharp", label: "C#" },
120457
+ { id: "css", label: "CSS" },
120458
+ { id: "dart", label: "Dart" },
120459
+ { id: "diff", label: "Diff" },
120460
+ { id: "dockerfile", label: "Dockerfile" },
120461
+ { id: "elixir", label: "Elixir" },
120462
+ { id: "erlang", label: "Erlang" },
120463
+ { id: "go", label: "Go" },
120464
+ { id: "graphql", label: "GraphQL" },
120465
+ { id: "haskell", label: "Haskell" },
120466
+ { id: "hcl", label: "HCL / Terraform" },
120467
+ { id: "html", label: "HTML" },
120468
+ { id: "ini", label: "INI" },
120469
+ { id: "java", label: "Java" },
120470
+ { id: "javascript", label: "JavaScript" },
120471
+ { id: "json", label: "JSON" },
120472
+ { id: "jsonc", label: "JSON with Comments" },
120473
+ { id: "jsx", label: "JavaScript (JSX)" },
120474
+ { id: "kotlin", label: "Kotlin" },
120475
+ { id: "less", label: "Less" },
120476
+ { id: "lua", label: "Lua" },
120477
+ { id: "makefile", label: "Makefile" },
120478
+ { id: "markdown", label: "Markdown" },
120479
+ { id: "mdx", label: "MDX" },
120480
+ { id: "php", label: "PHP" },
120481
+ { id: "powershell", label: "PowerShell" },
120482
+ { id: "python", label: "Python" },
120483
+ { id: "r", label: "R" },
120484
+ { id: "ruby", label: "Ruby" },
120485
+ { id: "rust", label: "Rust" },
120486
+ { id: "sass", label: "Sass" },
120487
+ { id: "scala", label: "Scala" },
120488
+ { id: "scss", label: "SCSS" },
120489
+ { id: "sql", label: "SQL" },
120490
+ { id: "svelte", label: "Svelte" },
120491
+ { id: "swift", label: "Swift" },
120492
+ { id: "toml", label: "TOML" },
120493
+ { id: "typescript", label: "TypeScript" },
120494
+ { id: "tsx", label: "TypeScript (TSX)" },
120495
+ { id: "vue", label: "Vue" },
120496
+ { id: "xml", label: "XML" },
120497
+ { id: "yaml", label: "YAML" }
120498
+ ];
120499
+ var LANGUAGE_LABEL_BY_ID = new Map(SUPPORTED_LANGUAGES.map((l) => [l.id, l.label]));
120500
+
120414
120501
  // ../../packages/dashboard-core/src/components/ChangesFileTree.tsx
120415
- var import_react28 = __toESM(require_react(), 1);
120502
+ var import_react29 = __toESM(require_react(), 1);
120416
120503
 
120417
120504
  // ../../packages/dashboard-core/src/hooks/use-deferred-menu-action.ts
120418
- var import_react27 = __toESM(require_react(), 1);
120505
+ var import_react28 = __toESM(require_react(), 1);
120419
120506
  function useDeferredMenuAction() {
120420
- const pendingRef = (0, import_react27.useRef)(null);
120421
- const queue = (0, import_react27.useCallback)((fn) => {
120507
+ const pendingRef = (0, import_react28.useRef)(null);
120508
+ const queue = (0, import_react28.useCallback)((fn) => {
120422
120509
  pendingRef.current = fn;
120423
120510
  }, []);
120424
- const flush = (0, import_react27.useCallback)((e2) => {
120511
+ const flush = (0, import_react28.useCallback)((e2) => {
120425
120512
  e2.preventDefault();
120426
120513
  const fn = pendingRef.current;
120427
120514
  pendingRef.current = null;
@@ -120570,18 +120657,18 @@ function getFileIcon(filename) {
120570
120657
  }
120571
120658
 
120572
120659
  // ../../packages/dashboard-core/src/components/FileStatusBadge.tsx
120573
- var import_jsx_runtime62 = __toESM(require_jsx_runtime(), 1);
120660
+ var import_jsx_runtime63 = __toESM(require_jsx_runtime(), 1);
120574
120661
 
120575
120662
  // ../../packages/dashboard-core/src/components/ChangesFileTree.tsx
120576
- var import_jsx_runtime63 = __toESM(require_jsx_runtime(), 1);
120663
+ var import_jsx_runtime64 = __toESM(require_jsx_runtime(), 1);
120577
120664
 
120578
120665
  // ../../packages/dashboard-core/src/components/RevertFileDialog.tsx
120579
- var import_jsx_runtime64 = __toESM(require_jsx_runtime(), 1);
120666
+ var import_jsx_runtime65 = __toESM(require_jsx_runtime(), 1);
120580
120667
 
120581
120668
  // ../../packages/dashboard-core/src/components/SearchBar.tsx
120582
120669
  var import_lucide_react7 = __toESM(require_lucide_react(), 1);
120583
- var import_react29 = __toESM(require_react(), 1);
120584
- 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);
120585
120672
  var DEFAULT_VISIBLE_OPTIONS = ["caseSensitive", "wholeWord", "regex"];
120586
120673
  function ToggleButton({
120587
120674
  active,
@@ -120589,7 +120676,7 @@ function ToggleButton({
120589
120676
  title,
120590
120677
  children
120591
120678
  }) {
120592
- return /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
120679
+ return /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
120593
120680
  "button",
120594
120681
  {
120595
120682
  type: "button",
@@ -120600,7 +120687,7 @@ function ToggleButton({
120600
120687
  }
120601
120688
  );
120602
120689
  }
120603
- var SearchBar = (0, import_react29.forwardRef)(function SearchBar2({
120690
+ var SearchBar = (0, import_react30.forwardRef)(function SearchBar2({
120604
120691
  query,
120605
120692
  onQueryChange,
120606
120693
  options: options2,
@@ -120616,27 +120703,27 @@ var SearchBar = (0, import_react29.forwardRef)(function SearchBar2({
120616
120703
  const showCase = visibleOptions.includes("caseSensitive");
120617
120704
  const showWholeWord = visibleOptions.includes("wholeWord");
120618
120705
  const showRegex = visibleOptions.includes("regex");
120619
- const inputRef = (0, import_react29.useRef)(null);
120620
- (0, import_react29.useImperativeHandle)(ref, () => ({
120706
+ const inputRef = (0, import_react30.useRef)(null);
120707
+ (0, import_react30.useImperativeHandle)(ref, () => ({
120621
120708
  focus: () => inputRef.current?.focus(),
120622
120709
  select: () => inputRef.current?.select()
120623
120710
  }));
120624
- const toggleCase = (0, import_react29.useCallback)(() => {
120711
+ const toggleCase = (0, import_react30.useCallback)(() => {
120625
120712
  onOptionsChange({ ...options2, caseSensitive: !options2.caseSensitive });
120626
120713
  }, [options2, onOptionsChange]);
120627
- const toggleWholeWord = (0, import_react29.useCallback)(() => {
120714
+ const toggleWholeWord = (0, import_react30.useCallback)(() => {
120628
120715
  onOptionsChange({ ...options2, wholeWord: !options2.wholeWord });
120629
120716
  }, [options2, onOptionsChange]);
120630
- const toggleRegex = (0, import_react29.useCallback)(() => {
120717
+ const toggleRegex = (0, import_react30.useCallback)(() => {
120631
120718
  onOptionsChange({ ...options2, regex: !options2.regex });
120632
120719
  }, [options2, onOptionsChange]);
120633
- return /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)(
120720
+ return /* @__PURE__ */ (0, import_jsx_runtime66.jsxs)(
120634
120721
  "div",
120635
120722
  {
120636
120723
  className: `flex shrink-0 items-center gap-1.5 border-b border-border bg-muted/30 px-3 py-1.5 ${className ?? ""}`,
120637
120724
  children: [
120638
- /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(import_lucide_react7.Search, { className: "size-3.5 shrink-0 text-muted-foreground" }),
120639
- /* @__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)(
120640
120727
  "input",
120641
120728
  {
120642
120729
  ref: inputRef,
@@ -120657,11 +120744,11 @@ var SearchBar = (0, import_react29.forwardRef)(function SearchBar2({
120657
120744
  }
120658
120745
  }
120659
120746
  ),
120660
- 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" }) }),
120661
- 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" }) }),
120662
- 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" }) }),
120663
- 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" }),
120664
- 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)(
120665
120752
  "button",
120666
120753
  {
120667
120754
  type: "button",
@@ -120669,10 +120756,10 @@ var SearchBar = (0, import_react29.forwardRef)(function SearchBar2({
120669
120756
  disabled: !matchInfo || matchInfo.total === 0,
120670
120757
  className: "inline-flex size-6 items-center justify-center rounded text-muted-foreground hover:text-foreground disabled:opacity-30",
120671
120758
  title: "Previous match (Shift+Enter)",
120672
- 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" })
120673
120760
  }
120674
120761
  ),
120675
- onNext && /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
120762
+ onNext && /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
120676
120763
  "button",
120677
120764
  {
120678
120765
  type: "button",
@@ -120680,17 +120767,17 @@ var SearchBar = (0, import_react29.forwardRef)(function SearchBar2({
120680
120767
  disabled: !matchInfo || matchInfo.total === 0,
120681
120768
  className: "inline-flex size-6 items-center justify-center rounded text-muted-foreground hover:text-foreground disabled:opacity-30",
120682
120769
  title: "Next match (Enter)",
120683
- 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" })
120684
120771
  }
120685
120772
  ),
120686
- onClose && /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
120773
+ onClose && /* @__PURE__ */ (0, import_jsx_runtime66.jsx)(
120687
120774
  "button",
120688
120775
  {
120689
120776
  type: "button",
120690
120777
  onClick: onClose,
120691
120778
  className: "inline-flex size-6 items-center justify-center rounded text-muted-foreground hover:text-foreground",
120692
120779
  title: "Close (Escape)",
120693
- 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" })
120694
120781
  }
120695
120782
  )
120696
120783
  ]
@@ -120699,7 +120786,7 @@ var SearchBar = (0, import_react29.forwardRef)(function SearchBar2({
120699
120786
  });
120700
120787
 
120701
120788
  // ../../packages/dashboard-core/src/components/DiffView.tsx
120702
- var import_jsx_runtime66 = __toESM(require_jsx_runtime(), 1);
120789
+ var import_jsx_runtime67 = __toESM(require_jsx_runtime(), 1);
120703
120790
  var diffTheme = EditorView.theme({
120704
120791
  ".cm-insertedLine": { backgroundColor: "rgba(34, 197, 94, 0.1)" },
120705
120792
  ".cm-deletedLine": { backgroundColor: "rgba(239, 68, 68, 0.1)" },
@@ -120750,8 +120837,8 @@ var diffTheme = EditorView.theme({
120750
120837
 
120751
120838
  // ../../packages/dashboard-core/src/components/FileBrowser.tsx
120752
120839
  var import_lucide_react8 = __toESM(require_lucide_react(), 1);
120753
- var import_react31 = __toESM(require_react(), 1);
120754
- 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);
120755
120842
  var expandedStateCache = /* @__PURE__ */ new Map();
120756
120843
  var dirContentsCache = /* @__PURE__ */ new Map();
120757
120844
  function getCachedExpanded(wsId) {
@@ -120780,11 +120867,11 @@ function EntryNameInput({
120780
120867
  onSubmit,
120781
120868
  onCancel
120782
120869
  }) {
120783
- const [value, setValue] = (0, import_react31.useState)(initialValue);
120784
- const [submitting, setSubmitting] = (0, import_react31.useState)(false);
120785
- const [error40, setError] = (0, import_react31.useState)(null);
120786
- const inputRef = (0, import_react31.useRef)(null);
120787
- (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)(() => {
120788
120875
  const el = inputRef.current;
120789
120876
  if (!el) return;
120790
120877
  el.focus();
@@ -120832,21 +120919,21 @@ function EntryNameInput({
120832
120919
  }
120833
120920
  };
120834
120921
  const Icon = kind === "directory" ? import_lucide_react8.Folder : import_lucide_react8.File;
120835
- return /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("div", { className: "flex w-full flex-col", style: { paddingLeft: `${depth * indent + basePad}px` }, children: [
120836
- /* @__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)(
120837
120924
  "div",
120838
120925
  {
120839
120926
  className: `flex items-center ${compact ? "h-[28px] gap-1 pr-3 text-[13px]" : "h-[32px] gap-1.5 pr-4 text-[15px]"}`,
120840
120927
  style: { height },
120841
120928
  children: [
120842
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("span", { className: "size-3.5 shrink-0" }),
120843
- /* @__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)(
120844
120931
  Icon,
120845
120932
  {
120846
120933
  className: kind === "directory" ? "size-4 shrink-0 text-blue-600 dark:text-blue-400" : "size-4 shrink-0 text-muted-foreground"
120847
120934
  }
120848
120935
  ),
120849
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
120936
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
120850
120937
  "input",
120851
120938
  {
120852
120939
  ref: inputRef,
@@ -120883,7 +120970,7 @@ function EntryNameInput({
120883
120970
  ]
120884
120971
  }
120885
120972
  ),
120886
- error40 && /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
120973
+ error40 && /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
120887
120974
  "div",
120888
120975
  {
120889
120976
  className: "pointer-events-none text-xs text-destructive",
@@ -120950,7 +121037,7 @@ function TreeNode2({
120950
121037
  onOpenFilePinned(entryPath);
120951
121038
  }
120952
121039
  };
120953
- const button = /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(
121040
+ const button = /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(
120954
121041
  "button",
120955
121042
  {
120956
121043
  ref: isSelected ? selectedRef : void 0,
@@ -120963,12 +121050,12 @@ function TreeNode2({
120963
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" : ""}`,
120964
121051
  style: { paddingLeft: `${depth * indent + basePad}px` },
120965
121052
  children: [
120966
- 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" }),
120967
- 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" }) : (() => {
120968
121055
  const FileIcon = getFileIcon(entry.name);
120969
- 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" });
120970
121057
  })(),
120971
- /* @__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 })
120972
121059
  ]
120973
121060
  }
120974
121061
  );
@@ -120990,7 +121077,7 @@ function TreeNode2({
120990
121077
  // a padding div with `depth={0}` would double-apply `basePad`, shifting
120991
121078
  // the input ~4px to the right and giving it visibly less horizontal
120992
121079
  // room than the rest of the tree.
120993
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
121080
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
120994
121081
  EntryNameInput,
120995
121082
  {
120996
121083
  kind: isDir ? "directory" : "file",
@@ -121004,74 +121091,74 @@ function TreeNode2({
121004
121091
  },
121005
121092
  `rename-${entryPath}`
121006
121093
  )
121007
- ) : /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(
121094
+ ) : /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(
121008
121095
  ContextMenu2,
121009
121096
  {
121010
121097
  onOpenChange: (open3) => {
121011
121098
  if (open3) onSelectRow(entryPath, isDir ? "directory" : "file");
121012
121099
  },
121013
121100
  children: [
121014
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(ContextMenuTrigger2, { asChild: true, children: button }),
121015
- /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(ContextMenuContent2, { onCloseAutoFocus: menu.flush, children: [
121016
- isDir && /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(import_jsx_runtime67.Fragment, { children: [
121017
- /* @__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)(
121018
121105
  ContextMenuItem2,
121019
121106
  {
121020
121107
  onSelect: () => menu.queue(() => onRequestNewEntry(entryPath, "file")),
121021
121108
  children: [
121022
- /* @__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" }),
121023
121110
  "New File"
121024
121111
  ]
121025
121112
  }
121026
121113
  ),
121027
- /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(
121114
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(
121028
121115
  ContextMenuItem2,
121029
121116
  {
121030
121117
  onSelect: () => menu.queue(() => onRequestNewEntry(entryPath, "directory")),
121031
121118
  children: [
121032
- /* @__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" }),
121033
121120
  "New Folder"
121034
121121
  ]
121035
121122
  }
121036
121123
  ),
121037
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(ContextMenuSeparator2, {})
121124
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(ContextMenuSeparator2, {})
121038
121125
  ] }),
121039
- canCut && /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(
121126
+ canCut && /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(
121040
121127
  ContextMenuItem2,
121041
121128
  {
121042
121129
  onSelect: () => menu.queue(() => onCut(entryPath, isDir ? "directory" : "file")),
121043
121130
  children: [
121044
- /* @__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" }),
121045
121132
  "Cut"
121046
121133
  ]
121047
121134
  }
121048
121135
  ),
121049
- canCopy && /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(
121136
+ canCopy && /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(
121050
121137
  ContextMenuItem2,
121051
121138
  {
121052
121139
  onSelect: () => menu.queue(() => onCopy(entryPath, isDir ? "directory" : "file")),
121053
121140
  children: [
121054
- /* @__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" }),
121055
121142
  "Copy"
121056
121143
  ]
121057
121144
  }
121058
121145
  ),
121059
- isDir && canPaste && /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(ContextMenuItem2, { onSelect: () => menu.queue(() => void onPaste(entryPath)), children: [
121060
- /* @__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" }),
121061
121148
  "Paste"
121062
121149
  ] }),
121063
- (canCut || canCopy || isDir && canPaste) && (canRename || canDelete) && /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(ContextMenuSeparator2, {}),
121064
- canRename && /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(ContextMenuItem2, { onSelect: () => menu.queue(() => onRequestRename(entryPath)), children: [
121065
- /* @__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" }),
121066
121153
  "Rename"
121067
121154
  ] }),
121068
- canDelete && /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(
121155
+ canDelete && /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(
121069
121156
  ContextMenuItem2,
121070
121157
  {
121071
121158
  variant: "destructive",
121072
121159
  onSelect: () => menu.queue(() => onRequestDelete(entryPath, isDir ? "directory" : "file")),
121073
121160
  children: [
121074
- /* @__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" }),
121075
121162
  "Delete"
121076
121163
  ]
121077
121164
  }
@@ -121081,13 +121168,13 @@ function TreeNode2({
121081
121168
  }
121082
121169
  );
121083
121170
  const showInlineInput = newEntry?.parentPath === entryPath;
121084
- 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: [
121085
121172
  row,
121086
121173
  isExpanded && (() => {
121087
121174
  const splitIdx = children?.findIndex((c2) => c2.type === "file") ?? -1;
121088
121175
  const folderChildren = splitIdx === -1 ? children ?? [] : (children ?? []).slice(0, splitIdx);
121089
121176
  const fileChildren = splitIdx === -1 ? [] : (children ?? []).slice(splitIdx);
121090
- const renderChild = (child) => /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
121177
+ const renderChild = (child) => /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
121091
121178
  TreeNode2,
121092
121179
  {
121093
121180
  entry: child,
@@ -121124,7 +121211,7 @@ function TreeNode2({
121124
121211
  },
121125
121212
  child.name
121126
121213
  );
121127
- const newEntryInput = showInlineInput ? /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
121214
+ const newEntryInput = showInlineInput ? /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
121128
121215
  EntryNameInput,
121129
121216
  {
121130
121217
  kind: newEntry.kind,
@@ -121136,9 +121223,9 @@ function TreeNode2({
121136
121223
  },
121137
121224
  `new-${newEntry.kind}-${entryPath}`
121138
121225
  ) : null;
121139
- 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: [
121140
121227
  showInlineInput && newEntry.kind === "directory" && newEntryInput,
121141
- isLoading && !children?.length && /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
121228
+ isLoading && !children?.length && /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
121142
121229
  "div",
121143
121230
  {
121144
121231
  className: `flex items-center text-muted-foreground/70 ${compact ? "text-[13px]" : "text-[15px]"}`,
@@ -121149,7 +121236,7 @@ function TreeNode2({
121149
121236
  children: "Loading\u2026"
121150
121237
  }
121151
121238
  ),
121152
- !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)(
121153
121240
  "div",
121154
121241
  {
121155
121242
  className: `flex items-center italic text-muted-foreground/50 ${compact ? "text-[13px]" : "text-[15px]"}`,
@@ -121167,7 +121254,7 @@ function TreeNode2({
121167
121254
  })()
121168
121255
  ] });
121169
121256
  }
121170
- var FileBrowser = (0, import_react31.forwardRef)(function FileBrowser2({
121257
+ var FileBrowser = (0, import_react32.forwardRef)(function FileBrowser2({
121171
121258
  workspaceId,
121172
121259
  onOpenFile,
121173
121260
  onOpenFilePinned,
@@ -121177,23 +121264,23 @@ var FileBrowser = (0, import_react31.forwardRef)(function FileBrowser2({
121177
121264
  onPathDeleted
121178
121265
  }, handleRef) {
121179
121266
  const adapter = useAdapter();
121180
- const [expandedPaths, setExpandedPaths] = (0, import_react31.useState)(
121267
+ const [expandedPaths, setExpandedPaths] = (0, import_react32.useState)(
121181
121268
  () => new Set(getCachedExpanded(workspaceId))
121182
121269
  );
121183
- const [dirContents, setDirContents] = (0, import_react31.useState)(
121270
+ const [dirContents, setDirContents] = (0, import_react32.useState)(
121184
121271
  () => new Map(getCachedContents(workspaceId))
121185
121272
  );
121186
- const [loadingPaths, setLoadingPaths] = (0, import_react31.useState)(/* @__PURE__ */ new Set());
121187
- const [newEntry, setNewEntry] = (0, import_react31.useState)(null);
121188
- const [pendingDelete, setPendingDelete] = (0, import_react31.useState)(null);
121189
- const [deleteError, setDeleteError] = (0, import_react31.useState)(null);
121190
- const [deleteSubmitting, setDeleteSubmitting] = (0, import_react31.useState)(false);
121191
- const [renamingPath, setRenamingPath] = (0, import_react31.useState)(null);
121192
- const [clipboard, setClipboard] = (0, import_react31.useState)(null);
121193
- const [treeSelection, setTreeSelection] = (0, import_react31.useState)(() => selectedFile ? { path: selectedFile, kind: "file" } : null);
121194
- const selectedRef = (0, import_react31.useRef)(null);
121195
- const prevWorkspaceRef = (0, import_react31.useRef)(workspaceId);
121196
- (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)(() => {
121197
121284
  if (prevWorkspaceRef.current !== workspaceId) {
121198
121285
  prevWorkspaceRef.current = workspaceId;
121199
121286
  setExpandedPaths(new Set(getCachedExpanded(workspaceId)));
@@ -121208,18 +121295,18 @@ var FileBrowser = (0, import_react31.forwardRef)(function FileBrowser2({
121208
121295
  setClipboard(null);
121209
121296
  }
121210
121297
  }, [workspaceId]);
121211
- (0, import_react31.useEffect)(() => {
121298
+ (0, import_react32.useEffect)(() => {
121212
121299
  if (selectedFile) {
121213
121300
  setTreeSelection({ path: selectedFile, kind: "file" });
121214
121301
  }
121215
121302
  }, [selectedFile]);
121216
- const handleSelectRow = (0, import_react31.useCallback)((path3, kind) => {
121303
+ const handleSelectRow = (0, import_react32.useCallback)((path3, kind) => {
121217
121304
  setTreeSelection({ path: path3, kind });
121218
121305
  }, []);
121219
- const clearTreeSelection = (0, import_react31.useCallback)(() => {
121306
+ const clearTreeSelection = (0, import_react32.useCallback)(() => {
121220
121307
  setTreeSelection(null);
121221
121308
  }, []);
121222
- const fetchDir = (0, import_react31.useCallback)(
121309
+ const fetchDir = (0, import_react32.useCallback)(
121223
121310
  async (dirPath, opts) => {
121224
121311
  if (!adapter.listWorkspaceFiles) return;
121225
121312
  const cache = getCachedContents(workspaceId);
@@ -121243,10 +121330,10 @@ var FileBrowser = (0, import_react31.forwardRef)(function FileBrowser2({
121243
121330
  },
121244
121331
  [adapter, workspaceId]
121245
121332
  );
121246
- (0, import_react31.useEffect)(() => {
121333
+ (0, import_react32.useEffect)(() => {
121247
121334
  fetchDir("");
121248
121335
  }, [fetchDir]);
121249
- (0, import_react31.useEffect)(() => {
121336
+ (0, import_react32.useEffect)(() => {
121250
121337
  if (!adapter.subscribeFileChanges) return;
121251
121338
  const unsubscribe = adapter.subscribeFileChanges(workspaceId, (changedPath) => {
121252
121339
  const cache = getCachedContents(workspaceId);
@@ -121255,8 +121342,8 @@ var FileBrowser = (0, import_react31.forwardRef)(function FileBrowser2({
121255
121342
  });
121256
121343
  return unsubscribe;
121257
121344
  }, [adapter, workspaceId, fetchDir]);
121258
- const prevSelectedRef = (0, import_react31.useRef)(void 0);
121259
- (0, import_react31.useEffect)(() => {
121345
+ const prevSelectedRef = (0, import_react32.useRef)(void 0);
121346
+ (0, import_react32.useEffect)(() => {
121260
121347
  if (!selectedFile || selectedFile === prevSelectedRef.current) {
121261
121348
  prevSelectedRef.current = selectedFile;
121262
121349
  return;
@@ -121283,7 +121370,7 @@ var FileBrowser = (0, import_react31.forwardRef)(function FileBrowser2({
121283
121370
  fetchDir(dir);
121284
121371
  }
121285
121372
  }, [selectedFile, workspaceId, fetchDir]);
121286
- (0, import_react31.useEffect)(() => {
121373
+ (0, import_react32.useEffect)(() => {
121287
121374
  if (selectedFile && selectedRef.current) {
121288
121375
  const timer = setTimeout(() => {
121289
121376
  selectedRef.current?.scrollIntoView({ block: "nearest" });
@@ -121291,7 +121378,7 @@ var FileBrowser = (0, import_react31.forwardRef)(function FileBrowser2({
121291
121378
  return () => clearTimeout(timer);
121292
121379
  }
121293
121380
  }, [selectedFile, dirContents]);
121294
- const toggleExpand = (0, import_react31.useCallback)(
121381
+ const toggleExpand = (0, import_react32.useCallback)(
121295
121382
  (dirPath) => {
121296
121383
  setExpandedPaths((prev) => {
121297
121384
  const next = new Set(prev);
@@ -121307,7 +121394,7 @@ var FileBrowser = (0, import_react31.forwardRef)(function FileBrowser2({
121307
121394
  },
121308
121395
  [workspaceId, fetchDir]
121309
121396
  );
121310
- const ensureDirExpanded = (0, import_react31.useCallback)(
121397
+ const ensureDirExpanded = (0, import_react32.useCallback)(
121311
121398
  async (dirPath) => {
121312
121399
  const cached2 = getCachedExpanded(workspaceId);
121313
121400
  if (!cached2.has(dirPath)) {
@@ -121319,17 +121406,17 @@ var FileBrowser = (0, import_react31.forwardRef)(function FileBrowser2({
121319
121406
  },
121320
121407
  [workspaceId, fetchDir]
121321
121408
  );
121322
- const requestNewEntry = (0, import_react31.useCallback)(
121409
+ const requestNewEntry = (0, import_react32.useCallback)(
121323
121410
  (parentPath, kind) => {
121324
121411
  void ensureDirExpanded(parentPath);
121325
121412
  setNewEntry({ parentPath, kind });
121326
121413
  },
121327
121414
  [ensureDirExpanded]
121328
121415
  );
121329
- const cancelNewEntry = (0, import_react31.useCallback)(() => {
121416
+ const cancelNewEntry = (0, import_react32.useCallback)(() => {
121330
121417
  setNewEntry(null);
121331
121418
  }, []);
121332
- const submitNewEntry = (0, import_react31.useCallback)(
121419
+ const submitNewEntry = (0, import_react32.useCallback)(
121333
121420
  async (name24) => {
121334
121421
  if (!newEntry) return;
121335
121422
  const fullPath = newEntry.parentPath ? `${newEntry.parentPath}/${name24}` : name24;
@@ -121362,16 +121449,16 @@ var FileBrowser = (0, import_react31.forwardRef)(function FileBrowser2({
121362
121449
  [adapter, newEntry, fetchDir, onOpenFile, workspaceId]
121363
121450
  );
121364
121451
  const canDelete = Boolean(adapter.deleteWorkspacePath);
121365
- const requestDelete = (0, import_react31.useCallback)((path3, kind) => {
121452
+ const requestDelete = (0, import_react32.useCallback)((path3, kind) => {
121366
121453
  setDeleteError(null);
121367
121454
  setPendingDelete({ path: path3, kind });
121368
121455
  }, []);
121369
- const cancelDelete = (0, import_react31.useCallback)(() => {
121456
+ const cancelDelete = (0, import_react32.useCallback)(() => {
121370
121457
  if (deleteSubmitting) return;
121371
121458
  setPendingDelete(null);
121372
121459
  setDeleteError(null);
121373
121460
  }, [deleteSubmitting]);
121374
- const confirmDelete = (0, import_react31.useCallback)(async () => {
121461
+ const confirmDelete = (0, import_react32.useCallback)(async () => {
121375
121462
  if (!pendingDelete || !adapter.deleteWorkspacePath) return;
121376
121463
  setDeleteSubmitting(true);
121377
121464
  setDeleteError(null);
@@ -121417,13 +121504,13 @@ var FileBrowser = (0, import_react31.forwardRef)(function FileBrowser2({
121417
121504
  }
121418
121505
  }, [adapter, pendingDelete, fetchDir, workspaceId, onPathDeleted]);
121419
121506
  const canRename = Boolean(adapter.renameWorkspacePath);
121420
- const requestRename = (0, import_react31.useCallback)((path3) => {
121507
+ const requestRename = (0, import_react32.useCallback)((path3) => {
121421
121508
  setRenamingPath(path3);
121422
121509
  }, []);
121423
- const cancelRename = (0, import_react31.useCallback)(() => {
121510
+ const cancelRename = (0, import_react32.useCallback)(() => {
121424
121511
  setRenamingPath(null);
121425
121512
  }, []);
121426
- const submitRename = (0, import_react31.useCallback)(
121513
+ const submitRename = (0, import_react32.useCallback)(
121427
121514
  async (newName) => {
121428
121515
  if (renamingPath == null || !adapter.renameWorkspacePath) return;
121429
121516
  const oldPath = renamingPath;
@@ -121479,7 +121566,7 @@ var FileBrowser = (0, import_react31.forwardRef)(function FileBrowser2({
121479
121566
  },
121480
121567
  [adapter, renamingPath, fetchDir, onPathRenamed, workspaceId]
121481
121568
  );
121482
- const resolveDefaultTarget = (0, import_react31.useCallback)(() => {
121569
+ const resolveDefaultTarget = (0, import_react32.useCallback)(() => {
121483
121570
  if (treeSelection?.kind === "directory") return treeSelection.path;
121484
121571
  if (treeSelection?.kind === "file") {
121485
121572
  const idx = treeSelection.path.lastIndexOf("/");
@@ -121492,13 +121579,13 @@ var FileBrowser = (0, import_react31.forwardRef)(function FileBrowser2({
121492
121579
  const canPaste = Boolean(
121493
121580
  clipboard && (clipboard.op === "copy" && adapter.copyWorkspacePath || clipboard.op === "cut" && adapter.renameWorkspacePath)
121494
121581
  );
121495
- const cutPath = (0, import_react31.useCallback)((path3, kind) => {
121582
+ const cutPath = (0, import_react32.useCallback)((path3, kind) => {
121496
121583
  setClipboard({ path: path3, kind, op: "cut" });
121497
121584
  }, []);
121498
- const copyPath = (0, import_react31.useCallback)((path3, kind) => {
121585
+ const copyPath = (0, import_react32.useCallback)((path3, kind) => {
121499
121586
  setClipboard({ path: path3, kind, op: "copy" });
121500
121587
  }, []);
121501
- const uniqueCopyName = (0, import_react31.useCallback)(
121588
+ const uniqueCopyName = (0, import_react32.useCallback)(
121502
121589
  (baseName, destFolder, kind) => {
121503
121590
  const siblings = new Set(
121504
121591
  (getCachedContents(workspaceId).get(destFolder) ?? []).map((e2) => e2.name)
@@ -121516,7 +121603,7 @@ var FileBrowser = (0, import_react31.forwardRef)(function FileBrowser2({
121516
121603
  },
121517
121604
  [workspaceId]
121518
121605
  );
121519
- const pasteInto = (0, import_react31.useCallback)(
121606
+ const pasteInto = (0, import_react32.useCallback)(
121520
121607
  async (destFolder) => {
121521
121608
  if (!clipboard) return;
121522
121609
  const sourcePath = clipboard.path;
@@ -121580,7 +121667,7 @@ var FileBrowser = (0, import_react31.forwardRef)(function FileBrowser2({
121580
121667
  },
121581
121668
  [adapter, clipboard, fetchDir, onPathRenamed, uniqueCopyName, workspaceId]
121582
121669
  );
121583
- (0, import_react31.useImperativeHandle)(
121670
+ (0, import_react32.useImperativeHandle)(
121584
121671
  handleRef,
121585
121672
  () => ({
121586
121673
  startNewFile(parentPath) {
@@ -121594,7 +121681,7 @@ var FileBrowser = (0, import_react31.forwardRef)(function FileBrowser2({
121594
121681
  );
121595
121682
  const rootMenu = useDeferredMenuAction();
121596
121683
  if (!adapter.listWorkspaceFiles) {
121597
- 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" });
121598
121685
  }
121599
121686
  const rootEntries = dirContents.get("") ?? [];
121600
121687
  const rootLoading = loadingPaths.has("");
@@ -121631,20 +121718,20 @@ var FileBrowser = (0, import_react31.forwardRef)(function FileBrowser2({
121631
121718
  void pasteInto(resolveDefaultTarget());
121632
121719
  }
121633
121720
  };
121634
- return /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("div", { className: "flex h-full flex-col overflow-hidden", onKeyDown: handleKeyDown, children: [
121635
- /* @__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)(
121636
121723
  ContextMenu2,
121637
121724
  {
121638
121725
  onOpenChange: (open3) => {
121639
121726
  if (open3) clearTreeSelection();
121640
121727
  },
121641
121728
  children: [
121642
- /* @__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: [
121643
121730
  (() => {
121644
121731
  const rootSplitIdx = rootEntries.findIndex((e2) => e2.type === "file");
121645
121732
  const rootFolders = rootSplitIdx === -1 ? rootEntries : rootEntries.slice(0, rootSplitIdx);
121646
121733
  const rootFiles = rootSplitIdx === -1 ? [] : rootEntries.slice(rootSplitIdx);
121647
- const renderRow = (entry) => /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
121734
+ const renderRow = (entry) => /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
121648
121735
  TreeNode2,
121649
121736
  {
121650
121737
  entry,
@@ -121681,7 +121768,7 @@ var FileBrowser = (0, import_react31.forwardRef)(function FileBrowser2({
121681
121768
  },
121682
121769
  entry.name
121683
121770
  );
121684
- const rootInput = showRootInput ? /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
121771
+ const rootInput = showRootInput ? /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
121685
121772
  EntryNameInput,
121686
121773
  {
121687
121774
  kind: newEntry.kind,
@@ -121693,30 +121780,30 @@ var FileBrowser = (0, import_react31.forwardRef)(function FileBrowser2({
121693
121780
  },
121694
121781
  `new-${newEntry.kind}-root`
121695
121782
  ) : null;
121696
- 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: [
121697
121784
  showRootInput && newEntry.kind === "directory" && rootInput,
121698
- 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" }),
121699
- !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" }),
121700
121787
  rootFolders.map(renderRow),
121701
121788
  showRootInput && newEntry.kind === "file" && rootInput,
121702
121789
  rootFiles.map(renderRow)
121703
121790
  ] });
121704
121791
  })(),
121705
- /* @__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" })
121706
121793
  ] }) }),
121707
- /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(ContextMenuContent2, { onCloseAutoFocus: rootMenu.flush, children: [
121708
- /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(ContextMenuItem2, { onSelect: () => rootMenu.queue(() => requestNewEntry("", "file")), children: [
121709
- /* @__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" }),
121710
121797
  "New File"
121711
121798
  ] }),
121712
- /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(ContextMenuItem2, { onSelect: () => rootMenu.queue(() => requestNewEntry("", "directory")), children: [
121713
- /* @__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" }),
121714
121801
  "New Folder"
121715
121802
  ] }),
121716
- canPaste && /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(import_jsx_runtime67.Fragment, { children: [
121717
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(ContextMenuSeparator2, {}),
121718
- /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(ContextMenuItem2, { onSelect: () => rootMenu.queue(() => void pasteInto("")), children: [
121719
- /* @__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" }),
121720
121807
  "Paste"
121721
121808
  ] })
121722
121809
  ] })
@@ -121724,42 +121811,42 @@ var FileBrowser = (0, import_react31.forwardRef)(function FileBrowser2({
121724
121811
  ]
121725
121812
  }
121726
121813
  ),
121727
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
121814
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
121728
121815
  Dialog2,
121729
121816
  {
121730
121817
  open: pendingDelete !== null,
121731
121818
  onOpenChange: (open3) => {
121732
121819
  if (!open3) cancelDelete();
121733
121820
  },
121734
- children: /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(DialogContent2, { className: "sm:max-w-[425px]", onClick: (e2) => e2.stopPropagation(), children: [
121735
- /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(DialogHeader, { children: [
121736
- /* @__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: [
121737
121824
  "Delete ",
121738
121825
  pendingDelete?.kind === "directory" ? "folder" : "file"
121739
121826
  ] }),
121740
- /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(DialogDescription2, { children: [
121827
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsxs)(DialogDescription2, { children: [
121741
121828
  "Are you sure you want to delete ",
121742
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)("strong", { children: pendingDelete?.path }),
121829
+ /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("strong", { children: pendingDelete?.path }),
121743
121830
  "?"
121744
121831
  ] })
121745
121832
  ] }),
121746
- /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)("div", { className: "flex flex-col gap-2 text-sm", children: [
121747
- 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: [
121748
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(import_lucide_react8.AlertTriangle, { className: "size-4 shrink-0 text-yellow-500 mt-0.5" }),
121749
- /* @__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." })
121750
121837
  ] }),
121751
- 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: [
121752
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(import_lucide_react8.AlertTriangle, { className: "size-4 shrink-0 text-yellow-500 mt-0.5" }),
121753
- /* @__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." })
121754
121841
  ] }),
121755
- 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: [
121756
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(import_lucide_react8.AlertTriangle, { className: "size-4 shrink-0 mt-0.5" }),
121757
- /* @__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 })
121758
121845
  ] })
121759
121846
  ] }),
121760
- /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(DialogFooter, { children: [
121761
- /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(Button, { variant: "ghost", onClick: cancelDelete, disabled: deleteSubmitting, children: "Cancel" }),
121762
- /* @__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)(
121763
121850
  Button,
121764
121851
  {
121765
121852
  variant: "destructive",
@@ -121776,35 +121863,39 @@ var FileBrowser = (0, import_react31.forwardRef)(function FileBrowser2({
121776
121863
  });
121777
121864
 
121778
121865
  // ../../packages/dashboard-core/src/components/FileViewer.tsx
121779
- var import_react33 = __toESM(require_react(), 1);
121866
+ var import_react35 = __toESM(require_react(), 1);
121780
121867
 
121781
121868
  // ../../packages/dashboard-core/src/components/ImagePreview.tsx
121782
- var import_react32 = __toESM(require_react(), 1);
121783
- var import_jsx_runtime68 = __toESM(require_jsx_runtime(), 1);
121784
-
121785
- // ../../packages/dashboard-core/src/components/PdfPreview.tsx
121869
+ var import_react33 = __toESM(require_react(), 1);
121786
121870
  var import_jsx_runtime69 = __toESM(require_jsx_runtime(), 1);
121787
121871
 
121788
- // ../../packages/dashboard-core/src/components/FileViewer.tsx
121872
+ // ../../packages/dashboard-core/src/components/LanguagePickerDialog.tsx
121873
+ var import_react34 = __toESM(require_react(), 1);
121789
121874
  var import_jsx_runtime70 = __toESM(require_jsx_runtime(), 1);
121790
121875
 
121791
- // ../../packages/dashboard-core/src/components/QuickOpenDialog.tsx
121792
- var import_react34 = __toESM(require_react(), 1);
121876
+ // ../../packages/dashboard-core/src/components/PdfPreview.tsx
121793
121877
  var import_jsx_runtime71 = __toESM(require_jsx_runtime(), 1);
121794
121878
 
121795
- // ../../packages/dashboard-core/src/components/SearchFilesDialog.tsx
121796
- var import_react35 = __toESM(require_react(), 1);
121879
+ // ../../packages/dashboard-core/src/components/FileViewer.tsx
121797
121880
  var import_jsx_runtime72 = __toESM(require_jsx_runtime(), 1);
121798
121881
 
121799
- // ../../packages/dashboard-core/src/components/WorkspacePickerDialog.tsx
121882
+ // ../../packages/dashboard-core/src/components/QuickOpenDialog.tsx
121800
121883
  var import_react36 = __toESM(require_react(), 1);
121801
121884
  var import_jsx_runtime73 = __toESM(require_jsx_runtime(), 1);
121802
121885
 
121803
- // ../../packages/dashboard-core/src/components/WorkspaceTabNav.tsx
121886
+ // ../../packages/dashboard-core/src/components/SearchFilesDialog.tsx
121887
+ var import_react37 = __toESM(require_react(), 1);
121804
121888
  var import_jsx_runtime74 = __toESM(require_jsx_runtime(), 1);
121805
121889
 
121890
+ // ../../packages/dashboard-core/src/components/WorkspacePickerDialog.tsx
121891
+ var import_react38 = __toESM(require_react(), 1);
121892
+ var import_jsx_runtime75 = __toESM(require_jsx_runtime(), 1);
121893
+
121894
+ // ../../packages/dashboard-core/src/components/WorkspaceTabNav.tsx
121895
+ var import_jsx_runtime76 = __toESM(require_jsx_runtime(), 1);
121896
+
121806
121897
  // ../../packages/dashboard-core/src/hooks/use-editor-history.ts
121807
- var import_react37 = __toESM(require_react(), 1);
121898
+ var import_react39 = __toESM(require_react(), 1);
121808
121899
 
121809
121900
  // ../../node_modules/.pnpm/marked@15.0.12/node_modules/marked/lib/marked.esm.js
121810
121901
  function _getDefaults() {
@@ -125884,6 +125975,7 @@ function getTableAsAliasSQL(table) {
125884
125975
  }
125885
125976
 
125886
125977
  // src/lib/db/connection.ts
125978
+ init_src();
125887
125979
  import { mkdirSync as mkdirSync2 } from "node:fs";
125888
125980
  import { join as join10 } from "node:path";
125889
125981
  import { DatabaseSync as DatabaseSync2 } from "node:sqlite";
@@ -131634,7 +131726,12 @@ var projects = sqliteTable("projects", {
131634
131726
  path: text3("path").notNull(),
131635
131727
  defaultBranch: text3("default_branch").notNull(),
131636
131728
  label: text3("label"),
131637
- 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")
131638
131735
  });
131639
131736
  var worktrees = sqliteTable("worktrees", {
131640
131737
  id: integer3("id").primaryKey({ autoIncrement: true }),
@@ -131700,6 +131797,7 @@ var browserHistory = sqliteTable(
131700
131797
  );
131701
131798
 
131702
131799
  // src/lib/db/connection.ts
131800
+ var log7 = createLogger("db");
131703
131801
  var migrationsFolder = join10(import.meta.dirname, "migrations");
131704
131802
  var _db = null;
131705
131803
  var _sqlite = null;
@@ -131717,6 +131815,14 @@ function getDb() {
131717
131815
  }
131718
131816
  function closeDb() {
131719
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
+ }
131720
131826
  _sqlite.close();
131721
131827
  _sqlite = null;
131722
131828
  _db = null;
@@ -131724,6 +131830,16 @@ function closeDb() {
131724
131830
  }
131725
131831
 
131726
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
+ }
131727
131843
  function bandHome() {
131728
131844
  if (process.env.BAND_HOME) return process.env.BAND_HOME;
131729
131845
  return join11(homedir6(), ".band");
@@ -131749,6 +131865,7 @@ function loadState() {
131749
131865
  path: row.path,
131750
131866
  defaultBranch: row.defaultBranch,
131751
131867
  label: row.label ?? void 0,
131868
+ kind: row.kind ?? "git",
131752
131869
  worktrees: wtByProject.get(row.name) ?? []
131753
131870
  }))
131754
131871
  };
@@ -131765,7 +131882,8 @@ function saveState(state2) {
131765
131882
  path: project.path,
131766
131883
  defaultBranch: project.defaultBranch,
131767
131884
  label: project.label ?? null,
131768
- sortOrder: i2
131885
+ sortOrder: i2,
131886
+ kind: project.kind
131769
131887
  }).run();
131770
131888
  for (const wt of project.worktrees) {
131771
131889
  tx.insert(worktrees).values({
@@ -131924,7 +132042,7 @@ function deleteBranchStatus(workspaceId) {
131924
132042
  }
131925
132043
 
131926
132044
  // src/lib/agent-pool.ts
131927
- var log7 = createLogger("agent-pool");
132045
+ var log8 = createLogger("agent-pool");
131928
132046
  var POOL_KEY = Symbol.for("band.agent-pool.v2");
131929
132047
  var PENDING_KEY = Symbol.for("band.agent-pool.pending");
131930
132048
  var g2 = globalThis;
@@ -131969,7 +132087,7 @@ function getAgent(chatId) {
131969
132087
  return pool.get(chatId)?.agent;
131970
132088
  }
131971
132089
  function removeAgent(chatId) {
131972
- log7.info({ chatId }, "removing agent from pool");
132090
+ log8.info({ chatId }, "removing agent from pool");
131973
132091
  return pool.delete(chatId);
131974
132092
  }
131975
132093
  async function getOrCreateAgent(chatId, worktreePath, agentId) {
@@ -131977,7 +132095,7 @@ async function getOrCreateAgent(chatId, worktreePath, agentId) {
131977
132095
  if (existing) {
131978
132096
  const requestedDefId = resolveAgentDefId(agentId);
131979
132097
  if (existing.agentDefId !== requestedDefId) {
131980
- log7.info(
132098
+ log8.info(
131981
132099
  { chatId, cached: existing.agentDefId, requested: requestedDefId },
131982
132100
  "cached agent definition mismatch, replacing"
131983
132101
  );
@@ -131991,7 +132109,7 @@ async function getOrCreateAgent(chatId, worktreePath, agentId) {
131991
132109
  return inFlight.promise;
131992
132110
  }
131993
132111
  const config2 = getAgentConfig(worktreePath, agentId);
131994
- log7.info({ chatId, type: config2.type, defId, cwd: worktreePath }, "creating agent");
132112
+ log8.info({ chatId, type: config2.type, defId, cwd: worktreePath }, "creating agent");
131995
132113
  const promise2 = createCodingAgent(config2).then(
131996
132114
  (agent) => {
131997
132115
  pool.set(chatId, { agent, agentDefId: defId });
@@ -132054,6 +132172,18 @@ function listPanelStatesForWorkspace(workspaceId, panelType) {
132054
132172
  const db2 = getDb();
132055
132173
  return db2.select().from(panelStates).where(and(eq2(panelStates.workspaceId, workspaceId), eq2(panelStates.panelType, panelType))).all();
132056
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
+ }
132057
132187
 
132058
132188
  // src/lib/dockview-layout-manager.ts
132059
132189
  function isLeaf(node) {
@@ -132526,6 +132656,7 @@ function parseBatchedCIResponse(data, aliases, defaultBranches) {
132526
132656
  }
132527
132657
 
132528
132658
  // src/lib/sync-state.ts
132659
+ var PROJECT_SYNC_BATCH_SIZE = 8;
132529
132660
  async function detectRemoteDefaultBranch(projectPath) {
132530
132661
  try {
132531
132662
  const ref = (await execGit(["symbolic-ref", "refs/remotes/origin/HEAD"], projectPath)).trim();
@@ -132550,35 +132681,50 @@ async function syncWorktrees() {
132550
132681
  const state2 = loadState();
132551
132682
  let changed = false;
132552
132683
  for (const project of state2.projects) {
132553
- let diskWorktrees;
132554
- try {
132555
- const gitWorktrees = await listWorktrees(project.path);
132556
- const pinnedByBranch = new Map(project.worktrees.map((wt) => [wt.branch, wt.pinned]));
132557
- diskWorktrees = gitWorktrees.filter((wt) => !wt.isBare).map((wt) => ({
132558
- branch: wt.branch,
132559
- path: wt.path,
132560
- head: wt.head,
132561
- pinned: pinnedByBranch.get(wt.branch) ?? false
132562
- }));
132563
- } catch {
132564
- continue;
132565
- }
132566
- const existingSet = new Set(project.worktrees.map((wt) => `${wt.branch}\0${wt.path}`));
132567
- const diskSet = new Set(diskWorktrees.map((wt) => `${wt.branch}\0${wt.path}`));
132568
- if (existingSet.size !== diskSet.size || Array.from(existingSet).some((key) => !diskSet.has(key))) {
132569
- project.worktrees = diskWorktrees;
132684
+ if (reconcileKindForProject(project)) {
132570
132685
  changed = true;
132571
132686
  }
132572
- const remoteBranch = await detectRemoteDefaultBranch(project.path);
132573
- if (remoteBranch && remoteBranch !== project.defaultBranch) {
132574
- project.defaultBranch = remoteBranch;
132575
- 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;
132576
132694
  }
132577
132695
  }
132578
132696
  if (changed) {
132579
132697
  saveState(state2);
132580
132698
  }
132581
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
+ }
132582
132728
 
132583
132729
  // src/lib/branch-status-poller.ts
132584
132730
  var INTERVALS = {
@@ -132597,6 +132743,7 @@ function getWorkspaces() {
132597
132743
  const state2 = loadState();
132598
132744
  const workspaces = [];
132599
132745
  for (const project of state2.projects) {
132746
+ if (project.kind === "plain") continue;
132600
132747
  for (const wt of project.worktrees) {
132601
132748
  workspaces.push({
132602
132749
  workspaceId: toWorkspaceId(project.name, wt.branch),
@@ -132840,12 +132987,12 @@ function getPollerActivity() {
132840
132987
  import { spawn as spawn5 } from "node:child_process";
132841
132988
 
132842
132989
  // src/lib/project-config.ts
132843
- import { existsSync as existsSync4, readFileSync as readFileSync6 } from "node:fs";
132990
+ import { existsSync as existsSync5, readFileSync as readFileSync6 } from "node:fs";
132844
132991
  import { join as join14 } from "node:path";
132845
132992
  function loadProjectConfig(worktreePath, projectPath) {
132846
132993
  for (const base2 of [worktreePath, projectPath]) {
132847
132994
  const configPath = join14(base2, ".band", "config.json");
132848
- if (existsSync4(configPath)) {
132995
+ if (existsSync5(configPath)) {
132849
132996
  try {
132850
132997
  return JSON.parse(readFileSync6(configPath, "utf-8"));
132851
132998
  } catch {
@@ -132964,7 +133111,7 @@ function subscribe(listener) {
132964
133111
  }
132965
133112
 
132966
133113
  // src/lib/chat-manager.ts
132967
- var log8 = createLogger("chat-manager");
133114
+ var log9 = createLogger("chat-manager");
132968
133115
  var PANEL_TYPE = "chat";
132969
133116
  var chatSessions = /* @__PURE__ */ new Map();
132970
133117
  var workspaceChats = /* @__PURE__ */ new Map();
@@ -133035,7 +133182,7 @@ function createChat(workspaceId, options2) {
133035
133182
  addToIndex(session);
133036
133183
  addChatToLayout(workspaceId, session.id, { title: session.name });
133037
133184
  emit({ kind: "chat-created", workspaceId, chatId: session.id });
133038
- 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");
133039
133186
  return session;
133040
133187
  }
133041
133188
  function getChat(chatId) {
@@ -133064,7 +133211,7 @@ function updateChat(chatId, updates) {
133064
133211
  state: serializeState(session),
133065
133212
  updatedAt: Date.now()
133066
133213
  });
133067
- log8.info({ chatId, updates }, "chat pane updated");
133214
+ log9.info({ chatId, updates }, "chat pane updated");
133068
133215
  return session;
133069
133216
  }
133070
133217
  function updateChatStatus(chatId, status) {
@@ -133116,7 +133263,7 @@ function removeChat(chatId) {
133116
133263
  removeChatFromLayout(session.workspaceId, chatId);
133117
133264
  removeFromIndex(chatId);
133118
133265
  emit({ kind: "chat-removed", workspaceId: session.workspaceId, chatId });
133119
- log8.info({ chatId, workspaceId: session.workspaceId }, "chat pane removed");
133266
+ log9.info({ chatId, workspaceId: session.workspaceId }, "chat pane removed");
133120
133267
  return true;
133121
133268
  }
133122
133269
  function removeWorkspaceChats(workspaceId) {
@@ -133128,19 +133275,15 @@ function removeWorkspaceChats(workspaceId) {
133128
133275
  }
133129
133276
  deletePanelStatesForWorkspace(workspaceId, PANEL_TYPE);
133130
133277
  workspaceChats.delete(workspaceId);
133131
- log8.info({ workspaceId }, "all chat panes removed for workspace");
133278
+ log9.info({ workspaceId }, "all chat panes removed for workspace");
133132
133279
  }
133133
133280
  function loadChatsFromDb() {
133134
133281
  _initialized = true;
133135
- const rows = listPanelStates(PANEL_TYPE);
133136
133282
  const now = Date.now();
133283
+ resetPanelStatesToIdle(PANEL_TYPE, now);
133284
+ const rows = listPanelStates(PANEL_TYPE);
133137
133285
  for (const row of rows) {
133138
133286
  const parsed = JSON.parse(row.state);
133139
- parsed.status = "idle";
133140
- updatePanelState(row.id, {
133141
- state: JSON.stringify(parsed),
133142
- updatedAt: now
133143
- });
133144
133287
  const session = {
133145
133288
  id: row.id,
133146
133289
  workspaceId: row.workspaceId,
@@ -133151,12 +133294,16 @@ function loadChatsFromDb() {
133151
133294
  activeSessionId: parsed.activeSessionId ?? void 0,
133152
133295
  activeSessionSummary: parsed.activeSessionSummary ?? void 0,
133153
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.
133154
133301
  status: "idle"
133155
133302
  };
133156
133303
  addToIndex(session);
133157
133304
  }
133158
133305
  if (rows.length > 0) {
133159
- log8.info({ count: rows.length }, "loaded chat panes from database");
133306
+ log9.info({ count: rows.length }, "loaded chat panes from database");
133160
133307
  }
133161
133308
  return rows.length;
133162
133309
  }
@@ -133336,7 +133483,7 @@ function hasPendingInputForWorkspace(workspaceId) {
133336
133483
 
133337
133484
  // src/lib/task-store.ts
133338
133485
  init_src();
133339
- var log9 = createLogger("task-store");
133486
+ var log10 = createLogger("task-store");
133340
133487
  function generateTaskId() {
133341
133488
  return `tsk_${Date.now()}`;
133342
133489
  }
@@ -133409,7 +133556,7 @@ function cleanupStaleTasks() {
133409
133556
  const result = db2.update(tasks).set({ status: "failed", completedAt: now }).where(eq2(tasks.status, "running")).run();
133410
133557
  const count3 = result.changes;
133411
133558
  if (count3 > 0) {
133412
- log9.info({ count: count3 }, "cleaned up stale tasks on startup");
133559
+ log10.info({ count: count3 }, "cleaned up stale tasks on startup");
133413
133560
  }
133414
133561
  return count3;
133415
133562
  }
@@ -133446,7 +133593,7 @@ function pruneOldTasks(retentionMs = TASK_RETENTION_MS) {
133446
133593
  const cutoff = Date.now() - retentionMs;
133447
133594
  const count3 = deleteTasksOlderThan(cutoff);
133448
133595
  if (count3 > 0) {
133449
- log9.info({ count: count3, retentionMs }, "pruned tasks older than retention window");
133596
+ log10.info({ count: count3, retentionMs }, "pruned tasks older than retention window");
133450
133597
  }
133451
133598
  return count3;
133452
133599
  }
@@ -133457,13 +133604,13 @@ function startTaskPruneScheduler(options2 = {}) {
133457
133604
  try {
133458
133605
  pruneOldTasks(retentionMs);
133459
133606
  } catch (err) {
133460
- log9.error({ err }, "initial task prune on boot failed");
133607
+ log10.error({ err }, "initial task prune on boot failed");
133461
133608
  }
133462
133609
  const timer = setInterval(() => {
133463
133610
  try {
133464
133611
  pruneOldTasks(retentionMs);
133465
133612
  } catch (err) {
133466
- log9.error({ err }, "scheduled task prune failed");
133613
+ log10.error({ err }, "scheduled task prune failed");
133467
133614
  }
133468
133615
  }, intervalMs);
133469
133616
  timer.unref();
@@ -133550,7 +133697,7 @@ function resolveWorkspace(workspaceId) {
133550
133697
  }
133551
133698
 
133552
133699
  // src/lib/task-runner.ts
133553
- var log10 = createLogger("task-runner");
133700
+ var log11 = createLogger("task-runner");
133554
133701
  function listFiles(dir) {
133555
133702
  try {
133556
133703
  return new Set(readdirSync6(dir));
@@ -133609,7 +133756,7 @@ function persistTask(task) {
133609
133756
  chatId: task.chatId
133610
133757
  });
133611
133758
  } catch (err) {
133612
- log10.warn({ err, taskId: task.taskRecordId }, "failed to persist task");
133759
+ log11.warn({ err, taskId: task.taskRecordId }, "failed to persist task");
133613
133760
  }
133614
133761
  }
133615
133762
  function broadcast(chatId, chunk) {
@@ -133633,7 +133780,7 @@ function broadcast(chatId, chunk) {
133633
133780
  }
133634
133781
  const subs = listeners2.get(chatId);
133635
133782
  if (!subs || subs.size === 0) {
133636
- log10.warn({ chatId, chunkType: chunk.type }, "broadcast: no listeners");
133783
+ log11.warn({ chatId, chunkType: chunk.type }, "broadcast: no listeners");
133637
133784
  return;
133638
133785
  }
133639
133786
  for (const listener of subs) {
@@ -133684,7 +133831,7 @@ function submitTask(options2) {
133684
133831
  tasks2.set(chatId, task);
133685
133832
  persistTask(task);
133686
133833
  runTask(chatId, task).catch((err) => {
133687
- log10.error({ chatId, err }, "task execution failed");
133834
+ log11.error({ chatId, err }, "task execution failed");
133688
133835
  if (task.status === "running") {
133689
133836
  task.status = "failed";
133690
133837
  task.completedAt = Date.now();
@@ -133718,7 +133865,7 @@ function abortTask(chatId) {
133718
133865
  updateChatStatus(chatId, "idle");
133719
133866
  const updated = upsertWorkspaceStatus(task.workspaceId, { status: "waiting" });
133720
133867
  emit({ kind: "update", status: updated });
133721
- log10.info({ chatId }, "task aborted by user");
133868
+ log11.info({ chatId }, "task aborted by user");
133722
133869
  return true;
133723
133870
  }
133724
133871
  function cancelTask(taskId) {
@@ -133738,7 +133885,7 @@ function cancelTask(taskId) {
133738
133885
  updateChatStatus(chatId, "idle");
133739
133886
  const updated = upsertWorkspaceStatus(task.workspaceId, { status: "waiting" });
133740
133887
  emit({ kind: "update", status: updated });
133741
- log10.info({ chatId, taskId }, "task cancelled (was running in-memory)");
133888
+ log11.info({ chatId, taskId }, "task cancelled (was running in-memory)");
133742
133889
  return { cancelled: true, workspaceId: task.workspaceId };
133743
133890
  }
133744
133891
  }
@@ -133746,7 +133893,7 @@ function cancelTask(taskId) {
133746
133893
  if (record2) {
133747
133894
  const updated = upsertWorkspaceStatus(record2.workspaceId, { status: "waiting" });
133748
133895
  emit({ kind: "update", status: updated });
133749
- log10.info({ taskId, workspaceId: record2.workspaceId }, "orphaned task cancelled");
133896
+ log11.info({ taskId, workspaceId: record2.workspaceId }, "orphaned task cancelled");
133750
133897
  return { cancelled: true, workspaceId: record2.workspaceId };
133751
133898
  }
133752
133899
  return { cancelled: false };
@@ -133766,7 +133913,7 @@ async function runTask(chatId, task) {
133766
133913
  const taskAgentId = task.codingAgentId;
133767
133914
  const resolvedAgentId = taskAgentId ?? chatSession?.agent;
133768
133915
  const needsReplace = taskAgentId && taskAgentId !== chatSession?.agent;
133769
- log10.info(
133916
+ log11.info(
133770
133917
  { chatId, taskAgentId, chatAgent: chatSession?.agent, resolvedAgentId, needsReplace },
133771
133918
  "resolving agent for task"
133772
133919
  );
@@ -133815,7 +133962,7 @@ async function runTask(chatId, task) {
133815
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.]`;
133816
133963
  const effectivePrompt = task.sessionId ? task.agentPrompt : task.agentPrompt + fileSharingHint;
133817
133964
  for await (const event of agent.runSession(effectivePrompt, task.sessionId, sessionOptions)) {
133818
- log10.info({ chatId, eventType: event.type }, "task event");
133965
+ log11.info({ chatId, eventType: event.type }, "task event");
133819
133966
  switch (event.type) {
133820
133967
  case "session-start": {
133821
133968
  task.sessionId = event.sessionId;
@@ -133996,7 +134143,7 @@ async function runTask(chatId, task) {
133996
134143
  break;
133997
134144
  }
133998
134145
  case "session-id-resolved": {
133999
- log10.info(
134146
+ log11.info(
134000
134147
  { chatId, previous: event.previousSessionId, resolved: event.resolvedSessionId },
134001
134148
  "session ID resolved"
134002
134149
  );
@@ -134091,7 +134238,7 @@ ${queued.text}`;
134091
134238
  });
134092
134239
  autoStarted = true;
134093
134240
  } catch (err) {
134094
- log10.warn({ chatId, err }, "failed to auto-start queued task");
134241
+ log11.warn({ chatId, err }, "failed to auto-start queued task");
134095
134242
  }
134096
134243
  }
134097
134244
  }
@@ -134191,7 +134338,7 @@ function getSessionEventsAfter(sessionId, afterEventId) {
134191
134338
  }
134192
134339
 
134193
134340
  // src/api/task-stream.ts
134194
- var log11 = createLogger("task-stream");
134341
+ var log12 = createLogger("task-stream");
134195
134342
  var INTERNAL_CHUNK_TYPES = /* @__PURE__ */ new Set(["user-message"]);
134196
134343
  function toUIChunk(chunk) {
134197
134344
  if (INTERNAL_CHUNK_TYPES.has(chunk.type)) return null;
@@ -134246,7 +134393,7 @@ function streamTask(res, chatId, sessionId, afterEventId) {
134246
134393
  const buf = getSessionBuffer(task.sessionId);
134247
134394
  if (buf && buf.events.length > 0) {
134248
134395
  const taskStartEventId = task.firstEventId ?? Number.POSITIVE_INFINITY;
134249
- log11.info(
134396
+ log12.info(
134250
134397
  {
134251
134398
  chatId,
134252
134399
  sessionId: task.sessionId,
@@ -134270,7 +134417,7 @@ function streamTask(res, chatId, sessionId, afterEventId) {
134270
134417
  }
134271
134418
  }
134272
134419
  if (queue.length === 0 && !caughtUp && (!task || task.status !== "running")) {
134273
- log11.warn(
134420
+ log12.warn(
134274
134421
  { chatId, taskStatus: task?.status, queueLen: queue.length },
134275
134422
  "task-stream: no running task and no events \u2014 closing stream early"
134276
134423
  );
@@ -134368,7 +134515,7 @@ ${prompt}`;
134368
134515
  }
134369
134516
  throw err;
134370
134517
  }
134371
- 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");
134372
134519
  streamTask(res, chatId, sessionId, void 0);
134373
134520
  }
134374
134521
  function handleGet(req, res, chatId) {
@@ -134382,13 +134529,13 @@ function handleGet(req, res, chatId) {
134382
134529
  res.end();
134383
134530
  return;
134384
134531
  }
134385
- 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");
134386
134533
  streamTask(res, chatId, sessionId ?? task.sessionId, afterEventId);
134387
134534
  }
134388
134535
  function handleTaskStream(req, res, chatId) {
134389
134536
  if (req.method === "POST") {
134390
134537
  handlePost(req, res, chatId).catch((err) => {
134391
- log11.error({ chatId, err }, "task-stream: POST handler error");
134538
+ log12.error({ chatId, err }, "task-stream: POST handler error");
134392
134539
  if (!res.headersSent) {
134393
134540
  res.writeHead(500, { "Content-Type": "application/json" });
134394
134541
  res.end(JSON.stringify({ error: "Internal server error" }));
@@ -134433,7 +134580,7 @@ function removeBrowserFromLayout(workspaceId, browserId) {
134433
134580
  }
134434
134581
 
134435
134582
  // src/lib/browser-manager.ts
134436
- var log12 = createLogger("browser-manager");
134583
+ var log13 = createLogger("browser-manager");
134437
134584
  var PANEL_TYPE2 = "browser";
134438
134585
  var browserTabs = /* @__PURE__ */ new Map();
134439
134586
  var workspaceBrowsers = /* @__PURE__ */ new Map();
@@ -134494,7 +134641,7 @@ function createBrowser(workspaceId, options2) {
134494
134641
  title: tab.name,
134495
134642
  initialUrl: tab.url || void 0
134496
134643
  });
134497
- 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");
134498
134645
  return tab;
134499
134646
  }
134500
134647
  function getBrowser(browserId) {
@@ -134521,7 +134668,7 @@ function updateBrowser(browserId, updates) {
134521
134668
  state: serializeState2(tab),
134522
134669
  updatedAt: Date.now()
134523
134670
  });
134524
- log12.info({ browserId, updates }, "browser tab updated");
134671
+ log13.info({ browserId, updates }, "browser tab updated");
134525
134672
  return tab;
134526
134673
  }
134527
134674
  function updateBrowserUrl(browserId, url2) {
@@ -134538,7 +134685,7 @@ function removeBrowser(browserId) {
134538
134685
  if (!tab) return false;
134539
134686
  deletePanelState(browserId);
134540
134687
  removeFromIndex2(browserId);
134541
- log12.info({ browserId, workspaceId: tab.workspaceId }, "browser tab removed");
134688
+ log13.info({ browserId, workspaceId: tab.workspaceId }, "browser tab removed");
134542
134689
  return true;
134543
134690
  }
134544
134691
  function removeWorkspaceBrowsers(workspaceId) {
@@ -134549,19 +134696,15 @@ function removeWorkspaceBrowsers(workspaceId) {
134549
134696
  }
134550
134697
  deletePanelStatesForWorkspace(workspaceId, PANEL_TYPE2);
134551
134698
  workspaceBrowsers.delete(workspaceId);
134552
- log12.info({ workspaceId }, "all browser tabs removed for workspace");
134699
+ log13.info({ workspaceId }, "all browser tabs removed for workspace");
134553
134700
  }
134554
134701
  function loadBrowsersFromDb() {
134555
134702
  _initialized2 = true;
134556
- const rows = listPanelStates(PANEL_TYPE2);
134557
134703
  const now = Date.now();
134704
+ resetPanelStatesToIdle(PANEL_TYPE2, now);
134705
+ const rows = listPanelStates(PANEL_TYPE2);
134558
134706
  for (const row of rows) {
134559
134707
  const parsed = JSON.parse(row.state);
134560
- parsed.status = "idle";
134561
- updatePanelState(row.id, {
134562
- state: JSON.stringify(parsed),
134563
- updatedAt: now
134564
- });
134565
134708
  const tab = {
134566
134709
  id: row.id,
134567
134710
  workspaceId: row.workspaceId,
@@ -134572,13 +134715,13 @@ function loadBrowsersFromDb() {
134572
134715
  addToIndex2(tab);
134573
134716
  }
134574
134717
  if (rows.length > 0) {
134575
- log12.info({ count: rows.length }, "loaded browser tabs from database");
134718
+ log13.info({ count: rows.length }, "loaded browser tabs from database");
134576
134719
  }
134577
134720
  return rows.length;
134578
134721
  }
134579
134722
 
134580
134723
  // src/lib/browser-host.ts
134581
- var log13 = createLogger("browser-host");
134724
+ var log14 = createLogger("browser-host");
134582
134725
  var DESKTOP_CDP_HOST = "127.0.0.1";
134583
134726
  var DESKTOP_CDP_PORT = 9223;
134584
134727
  var globalAny = globalThis;
@@ -134629,7 +134772,7 @@ async function ensureCdpTargetId(bandTabId) {
134629
134772
  reject: rejectFn,
134630
134773
  timeoutId
134631
134774
  });
134632
- log13.info(
134775
+ log14.info(
134633
134776
  "ensureCdpTargetId emitting ensureView for %s (url=%s, listeners=%d)",
134634
134777
  bandTabId,
134635
134778
  tab.url,
@@ -134643,13 +134786,13 @@ async function ensureCdpTargetId(bandTabId) {
134643
134786
  url: tab.url
134644
134787
  });
134645
134788
  } catch (err) {
134646
- 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);
134647
134790
  }
134648
134791
  }
134649
134792
  return promise2;
134650
134793
  }
134651
134794
  function resolveTargetReady(bandTabId, cdpTargetId) {
134652
- log13.info("resolveTargetReady %s \u2192 %s", bandTabId, cdpTargetId);
134795
+ log14.info("resolveTargetReady %s \u2192 %s", bandTabId, cdpTargetId);
134653
134796
  targetIdByBandTabId.set(bandTabId, cdpTargetId);
134654
134797
  const pending2 = pendingEnsures.get(bandTabId);
134655
134798
  if (pending2) {
@@ -134659,7 +134802,7 @@ function resolveTargetReady(bandTabId, cdpTargetId) {
134659
134802
  }
134660
134803
  }
134661
134804
  function markTargetDestroyed(bandTabId) {
134662
- log13.info("markTargetDestroyed %s", bandTabId);
134805
+ log14.info("markTargetDestroyed %s", bandTabId);
134663
134806
  targetIdByBandTabId.delete(bandTabId);
134664
134807
  const pending2 = pendingEnsures.get(bandTabId);
134665
134808
  if (pending2) {
@@ -134670,10 +134813,10 @@ function markTargetDestroyed(bandTabId) {
134670
134813
  }
134671
134814
  function onEnsureView(listener) {
134672
134815
  ensureListeners.add(listener);
134673
- log13.info("onEnsureView subscriber added (total=%d)", ensureListeners.size);
134816
+ log14.info("onEnsureView subscriber added (total=%d)", ensureListeners.size);
134674
134817
  return () => {
134675
134818
  ensureListeners.delete(listener);
134676
- log13.info("onEnsureView subscriber removed (total=%d)", ensureListeners.size);
134819
+ log14.info("onEnsureView subscriber removed (total=%d)", ensureListeners.size);
134677
134820
  if (ensureListeners.size === 0) {
134678
134821
  for (const [bandTabId, pending2] of pendingEnsures) {
134679
134822
  clearTimeout(pending2.timeoutId);
@@ -134690,7 +134833,7 @@ function isDesktopHostConnected() {
134690
134833
 
134691
134834
  // src/lib/cdp-proxy.ts
134692
134835
  init_src();
134693
- var log14 = createLogger("cdp-proxy");
134836
+ var log15 = createLogger("cdp-proxy");
134694
134837
  async function handleCdpConnection(ws, req) {
134695
134838
  const url2 = new URL(req.url ?? "", `http://${req.headers.host}`);
134696
134839
  const bandTabId = url2.searchParams.get("bandTabId");
@@ -134713,17 +134856,17 @@ async function handleCdpConnection(ws, req) {
134713
134856
  cdpTargetId = await ensureCdpTargetId(bandTabId);
134714
134857
  } catch (err) {
134715
134858
  const message = err instanceof Error ? err.message : String(err);
134716
- log14.debug("ensureCdpTargetId failed for %s: %s", bandTabId, message);
134859
+ log15.debug("ensureCdpTargetId failed for %s: %s", bandTabId, message);
134717
134860
  if (ws.readyState === ws.OPEN) {
134718
134861
  ws.close(4001, message.slice(0, 123));
134719
134862
  }
134720
134863
  return;
134721
134864
  }
134722
134865
  const upstreamUrl = `ws://${DESKTOP_CDP_HOST}:${DESKTOP_CDP_PORT}/devtools/page/${encodeURIComponent(cdpTargetId)}`;
134723
- log14.info("CDP proxy connecting bandTabId=%s upstream=%s", bandTabId, upstreamUrl);
134866
+ log15.info("CDP proxy connecting bandTabId=%s upstream=%s", bandTabId, upstreamUrl);
134724
134867
  upstream = new wrapper_default(upstreamUrl);
134725
134868
  upstream.on("open", () => {
134726
- 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);
134727
134870
  for (const msg of pending2) {
134728
134871
  upstream?.send(msg);
134729
134872
  }
@@ -134735,20 +134878,20 @@ async function handleCdpConnection(ws, req) {
134735
134878
  }
134736
134879
  });
134737
134880
  upstream.on("error", (err) => {
134738
- log14.warn("CDP upstream error bandTabId=%s: %s", bandTabId, err.message);
134881
+ log15.warn("CDP upstream error bandTabId=%s: %s", bandTabId, err.message);
134739
134882
  markTargetDestroyed(bandTabId);
134740
134883
  if (ws.readyState === ws.OPEN) {
134741
134884
  ws.close(4001, `Desktop CDP error: ${err.message}`.slice(0, 123));
134742
134885
  }
134743
134886
  });
134744
134887
  upstream.on("close", (code) => {
134745
- log14.info("CDP upstream closed bandTabId=%s code=%d", bandTabId, code);
134888
+ log15.info("CDP upstream closed bandTabId=%s code=%d", bandTabId, code);
134746
134889
  if (ws.readyState === ws.OPEN) {
134747
134890
  ws.close(1e3, "Upstream closed");
134748
134891
  }
134749
134892
  });
134750
134893
  ws.on("close", () => {
134751
- log14.debug("CDP client closed bandTabId=%s", bandTabId);
134894
+ log15.debug("CDP client closed bandTabId=%s", bandTabId);
134752
134895
  if (upstream && (upstream.readyState === wrapper_default.OPEN || upstream.readyState === wrapper_default.CONNECTING)) {
134753
134896
  try {
134754
134897
  upstream.close();
@@ -134757,7 +134900,7 @@ async function handleCdpConnection(ws, req) {
134757
134900
  }
134758
134901
  });
134759
134902
  ws.on("error", (err) => {
134760
- log14.debug("CDP client error bandTabId=%s: %s", bandTabId, err.message);
134903
+ log15.debug("CDP client error bandTabId=%s: %s", bandTabId, err.message);
134761
134904
  try {
134762
134905
  upstream?.close();
134763
134906
  } catch {
@@ -134767,7 +134910,7 @@ async function handleCdpConnection(ws, req) {
134767
134910
 
134768
134911
  // src/lib/cdp-targets.ts
134769
134912
  init_src();
134770
- var log15 = createLogger("cdp-targets");
134913
+ var log16 = createLogger("cdp-targets");
134771
134914
  var CdpUnreachableError = class extends Error {
134772
134915
  constructor(message) {
134773
134916
  super(message);
@@ -134823,7 +134966,7 @@ async function captureSnapshot(bandTabId) {
134823
134966
  });
134824
134967
  ws.on("error", (err) => {
134825
134968
  clearTimeout(timeout);
134826
- 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);
134827
134970
  markTargetDestroyed(bandTabId);
134828
134971
  settle(new CdpUnreachableError(err.message));
134829
134972
  });
@@ -135543,7 +135686,7 @@ function rowToDefinition(row) {
135543
135686
  }
135544
135687
 
135545
135688
  // src/lib/cronjob-scheduler.ts
135546
- var log16 = createLogger("cronjob-scheduler");
135689
+ var log17 = createLogger("cronjob-scheduler");
135547
135690
  var SCHEDULER_KEY = Symbol.for("band.cronjob-scheduler");
135548
135691
  var g14 = globalThis;
135549
135692
  if (!g14[SCHEDULER_KEY]) {
@@ -135563,16 +135706,16 @@ function scheduleJob(job, fileKey) {
135563
135706
  try {
135564
135707
  const cronInstance = new E2(job.cronExpression, () => {
135565
135708
  executeCronjob(job, fileKey).catch((err) => {
135566
- log16.error({ jobId: job.id, err }, "unhandled error in cronjob execution");
135709
+ log17.error({ jobId: job.id, err }, "unhandled error in cronjob execution");
135567
135710
  });
135568
135711
  });
135569
135712
  state.jobs.set(job.id, cronInstance);
135570
- log16.info(
135713
+ log17.info(
135571
135714
  { jobId: job.id, name: job.name, cron: job.cronExpression, scope: job.scope },
135572
135715
  "scheduled cronjob"
135573
135716
  );
135574
135717
  } catch (err) {
135575
- log16.error(
135718
+ log17.error(
135576
135719
  { jobId: job.id, cronExpression: job.cronExpression, err },
135577
135720
  "invalid cron expression, skipping job"
135578
135721
  );
@@ -135586,24 +135729,24 @@ async function executeCronjob(job, fileKey) {
135586
135729
  const appState = loadState();
135587
135730
  const project = appState.projects.find((p6) => p6.name === fileKey);
135588
135731
  if (!project) {
135589
- 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");
135590
135733
  updateLastRun(job.id, "failed");
135591
135734
  return;
135592
135735
  }
135593
135736
  workspaceId = toWorkspaceId(project.name, project.defaultBranch);
135594
135737
  }
135595
- log16.info({ jobId: job.id, name: job.name, workspaceId }, "executing cronjob");
135738
+ log17.info({ jobId: job.id, name: job.name, workspaceId }, "executing cronjob");
135596
135739
  try {
135597
135740
  const chat = getOrCreateDefaultChat(workspaceId);
135598
135741
  submitTask({ workspaceId, chatId: chat.id, prompt: job.prompt });
135599
135742
  updateLastRun(job.id, "completed");
135600
135743
  } catch (err) {
135601
135744
  if (err instanceof TaskConflictError) {
135602
- 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");
135603
135746
  updateLastRun(job.id, "skipped");
135604
135747
  return;
135605
135748
  }
135606
- log16.error({ jobId: job.id, err }, "cronjob execution failed");
135749
+ log17.error({ jobId: job.id, err }, "cronjob execution failed");
135607
135750
  updateLastRun(job.id, "failed");
135608
135751
  }
135609
135752
  }
@@ -135612,7 +135755,7 @@ function updateLastRun(jobId, status) {
135612
135755
  const db2 = getDb();
135613
135756
  db2.update(cronjobs).set({ lastRunAt: (/* @__PURE__ */ new Date()).toISOString(), lastRunStatus: status }).where(eq2(cronjobs.id, jobId)).run();
135614
135757
  } catch (err) {
135615
- log16.warn({ jobId, err }, "failed to update lastRun on cronjob");
135758
+ log17.warn({ jobId, err }, "failed to update lastRun on cronjob");
135616
135759
  }
135617
135760
  }
135618
135761
  function loadAndScheduleAll() {
@@ -135623,13 +135766,13 @@ function loadAndScheduleAll() {
135623
135766
  for (const job of listAllCronjobs()) {
135624
135767
  scheduleJob(job, job.fileKey);
135625
135768
  }
135626
- log16.info({ count: state.jobs.size }, "loaded cronjob schedules");
135769
+ log17.info({ count: state.jobs.size }, "loaded cronjob schedules");
135627
135770
  }
135628
135771
  function startCronjobScheduler() {
135629
135772
  if (state.started) return;
135630
135773
  state.started = true;
135631
135774
  loadAndScheduleAll();
135632
- log16.info("cronjob scheduler started");
135775
+ log17.info("cronjob scheduler started");
135633
135776
  }
135634
135777
  function stopCronjobScheduler() {
135635
135778
  for (const [, cron] of state.jobs) {
@@ -135637,7 +135780,7 @@ function stopCronjobScheduler() {
135637
135780
  }
135638
135781
  state.jobs.clear();
135639
135782
  state.started = false;
135640
- log16.info("cronjob scheduler stopped");
135783
+ log17.info("cronjob scheduler stopped");
135641
135784
  }
135642
135785
  function reloadSchedules() {
135643
135786
  if (!state.started) return;
@@ -135650,7 +135793,7 @@ function stopJobsForKey(key) {
135650
135793
  if (cron) {
135651
135794
  cron.stop();
135652
135795
  state.jobs.delete(job.id);
135653
- log16.info({ jobId: job.id, key }, "stopped cronjob");
135796
+ log17.info({ jobId: job.id, key }, "stopped cronjob");
135654
135797
  }
135655
135798
  }
135656
135799
  }
@@ -135716,7 +135859,7 @@ async function checkPrereqs() {
135716
135859
 
135717
135860
  // src/lib/lsp-manager.ts
135718
135861
  var __dirname2 = dirname2(fileURLToPath(import.meta.url));
135719
- var log17 = createLogger("lsp");
135862
+ var log18 = createLogger("lsp");
135720
135863
  var LANG_SERVER_CONFIG = {
135721
135864
  typescript: { command: "typescript-language-server", args: ["--stdio"] }
135722
135865
  };
@@ -135744,7 +135887,7 @@ async function getOrSpawnServer(workspaceId, lang) {
135744
135887
  const workspaceBin = join17(cwd, "node_modules/.bin");
135745
135888
  const pathSep = process.platform === "win32" ? ";" : ":";
135746
135889
  const combinedPath = [bundledBin, appBin, workspaceBin, resolvedPath].join(pathSep);
135747
- 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);
135748
135891
  const child = spawn6(config2.command, config2.args, {
135749
135892
  cwd,
135750
135893
  stdio: ["pipe", "pipe", "pipe"],
@@ -135772,15 +135915,15 @@ async function getOrSpawnServer(workspaceId, lang) {
135772
135915
  }
135773
135916
  ids.add(serverId);
135774
135917
  child.on("exit", (code) => {
135775
- log17.debug("Language server exited: %s (code %s)", serverId, String(code));
135918
+ log18.debug("Language server exited: %s (code %s)", serverId, String(code));
135776
135919
  removeSession();
135777
135920
  });
135778
135921
  child.on("error", (err) => {
135779
- log17.error("Language server error: %s \u2014 %s", serverId, err.message);
135922
+ log18.error("Language server error: %s \u2014 %s", serverId, err.message);
135780
135923
  removeSession();
135781
135924
  });
135782
135925
  child.stderr?.on("data", (chunk) => {
135783
- log17.debug("LSP stderr [%s]: %s", serverId, chunk.toString().trimEnd());
135926
+ log18.debug("LSP stderr [%s]: %s", serverId, chunk.toString().trimEnd());
135784
135927
  });
135785
135928
  await new Promise((resolve8, reject) => {
135786
135929
  child.once("spawn", resolve8);
@@ -135810,7 +135953,7 @@ function killAllServers() {
135810
135953
 
135811
135954
  // src/lib/lsp-proxy.ts
135812
135955
  init_src();
135813
- var log18 = createLogger("lsp-proxy");
135956
+ var log19 = createLogger("lsp-proxy");
135814
135957
  function frameMessage(json4) {
135815
135958
  const body = Buffer.from(json4, "utf-8");
135816
135959
  const header = `Content-Length: ${body.byteLength}\r
@@ -135828,7 +135971,7 @@ function createFrameParser(onMessage) {
135828
135971
  const headerStr = buffer.subarray(0, separatorIdx).toString("ascii");
135829
135972
  const match = headerStr.match(/Content-Length:\s*(\d+)/i);
135830
135973
  if (!match) {
135831
- log18.warn("Malformed LSP header: %s", headerStr);
135974
+ log19.warn("Malformed LSP header: %s", headerStr);
135832
135975
  buffer = buffer.subarray(separatorIdx + 4);
135833
135976
  continue;
135834
135977
  }
@@ -135861,7 +136004,7 @@ async function handleLspConnection(ws, req) {
135861
136004
  session = await getOrSpawnServer(workspaceId, lang);
135862
136005
  } catch (err) {
135863
136006
  const message = err instanceof Error ? err.message : String(err);
135864
- log18.error(
136007
+ log19.error(
135865
136008
  "Failed to spawn %s language server for workspace %s: %s",
135866
136009
  lang,
135867
136010
  workspaceId,
@@ -135875,12 +136018,12 @@ async function handleLspConnection(ws, req) {
135875
136018
  ws.close(4002, "Language server stdio not available");
135876
136019
  return;
135877
136020
  }
135878
- log18.debug("LSP client connected: %s/%s", workspaceId, lang);
136021
+ log19.debug("LSP client connected: %s/%s", workspaceId, lang);
135879
136022
  const pendingRequests = /* @__PURE__ */ new Map();
135880
136023
  const retriedIds = /* @__PURE__ */ new Set();
135881
136024
  const RETRY_DELAY_MS = 2e3;
135882
136025
  const parseFrame = createFrameParser((json4) => {
135883
- log18.debug(
136026
+ log19.debug(
135884
136027
  "LSP stdout [%s/%s]: %s",
135885
136028
  workspaceId,
135886
136029
  lang,
@@ -135892,7 +136035,7 @@ async function handleLspConnection(ws, req) {
135892
136035
  const originalRequest = pendingRequests.get(msg.id);
135893
136036
  retriedIds.add(msg.id);
135894
136037
  pendingRequests.delete(msg.id);
135895
- log18.debug(
136038
+ log19.debug(
135896
136039
  "LSP retrying request %d after 'No Project' error [%s/%s]",
135897
136040
  msg.id,
135898
136041
  workspaceId,
@@ -135914,14 +136057,14 @@ async function handleLspConnection(ws, req) {
135914
136057
  const onStdoutData = (chunk) => parseFrame(chunk);
135915
136058
  lspProcess.stdout.on("data", onStdoutData);
135916
136059
  const onExit = (code) => {
135917
- log18.debug("LSP server exited (code %s), closing WebSocket", String(code));
136060
+ log19.debug("LSP server exited (code %s), closing WebSocket", String(code));
135918
136061
  if (ws.readyState === ws.OPEN) {
135919
136062
  ws.close(1e3, "Language server exited");
135920
136063
  }
135921
136064
  };
135922
136065
  lspProcess.on("exit", onExit);
135923
136066
  function forwardToStdin(json4) {
135924
- log18.debug(
136067
+ log19.debug(
135925
136068
  "LSP stdin [%s/%s]: %s",
135926
136069
  workspaceId,
135927
136070
  lang,
@@ -135948,7 +136091,7 @@ async function handleLspConnection(ws, req) {
135948
136091
  ws.on("close", () => {
135949
136092
  lspProcess.stdout?.off("data", onStdoutData);
135950
136093
  lspProcess.off("exit", onExit);
135951
- 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);
135952
136095
  });
135953
136096
  }
135954
136097
 
@@ -136085,7 +136228,7 @@ function resolveCliPaths() {
136085
136228
  // src/lib/cli-skills.ts
136086
136229
  import { execFile as execFile4 } from "node:child_process";
136087
136230
  import {
136088
- existsSync as existsSync5,
136231
+ existsSync as existsSync6,
136089
136232
  lstatSync as lstatSync3,
136090
136233
  mkdirSync as mkdirSync5,
136091
136234
  mkdtempSync,
@@ -136184,7 +136327,7 @@ async function installSkills(opts = {}) {
136184
136327
  for (const name24 of BAND_SKILL_NAMES) {
136185
136328
  const sourcePath = join19(stagingDir, name24, SKILL_FILE);
136186
136329
  const destPath = join19(sharedDir, name24, SKILL_FILE);
136187
- if (!existsSync5(sourcePath)) {
136330
+ if (!existsSync6(sourcePath)) {
136188
136331
  opts.log?.warn("Generated skill missing from staging dir: %s (skipping)", sourcePath);
136189
136332
  result.skipped.push(destPath);
136190
136333
  continue;
@@ -136232,7 +136375,7 @@ async function installSkills(opts = {}) {
136232
136375
  for (const name24 of BAND_SKILL_NAMES) {
136233
136376
  const shared2 = join19(sharedDir, name24);
136234
136377
  const link2 = join19(target.skillsDir, name24);
136235
- if (!existsSync5(shared2)) {
136378
+ if (!existsSync6(shared2)) {
136236
136379
  result.skipped.push(link2);
136237
136380
  continue;
136238
136381
  }
@@ -136444,40 +136587,65 @@ async function installHooks() {
136444
136587
  }
136445
136588
 
136446
136589
  // src/lib/setup.ts
136447
- var log19 = createLogger("setup");
136590
+ var log20 = createLogger("setup");
136448
136591
  var AGENT_CHECKS = [
136449
136592
  { id: "claude-code", type: "claude-code", label: "Claude Code", binary: "claude" },
136450
136593
  { id: "codex", type: "codex", label: "Codex", binary: "codex" },
136451
136594
  { id: "opencode", type: "opencode", label: "OpenCode", binary: "opencode" }
136452
136595
  ];
136453
136596
  async function runFirstTimeSetup() {
136597
+ const projectSync = ensureProjectStateInSync();
136454
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() {
136455
136615
  await ensureDefaultCodingAgents();
136456
136616
  ensureNotificationDefaults();
136457
- await ensureClaudeHooks();
136458
- 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
+ }
136459
136627
  }
136460
136628
  async function ensureCliInstalled() {
136461
136629
  let cliStatus;
136462
136630
  try {
136463
136631
  cliStatus = await checkCli();
136464
136632
  } catch (err) {
136465
- 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));
136466
136634
  return;
136467
136635
  }
136468
136636
  if (cliStatus === "Installed") {
136469
136637
  return;
136470
136638
  }
136471
136639
  if (cliStatus !== "NotInstalled") {
136472
- log19.warn("CLI not auto-installed (status: %s)", cliStatus);
136640
+ log20.warn("CLI not auto-installed (status: %s)", cliStatus);
136473
136641
  return;
136474
136642
  }
136475
- log19.info("Installing band CLI...");
136643
+ log20.info("Installing band CLI...");
136476
136644
  try {
136477
136645
  await installCli();
136478
- log19.info("CLI installed to /usr/local/bin/band");
136646
+ log20.info("CLI installed to /usr/local/bin/band");
136479
136647
  } catch (err) {
136480
- 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));
136481
136649
  }
136482
136650
  }
136483
136651
  async function ensureDefaultCodingAgents() {
@@ -136486,17 +136654,17 @@ async function ensureDefaultCodingAgents() {
136486
136654
  if (Array.isArray(existing) && existing.length > 0) {
136487
136655
  return;
136488
136656
  }
136489
- log19.info("Detecting installed coding agents...");
136657
+ log20.info("Detecting installed coding agents...");
136490
136658
  const detected = [];
136491
136659
  for (const check2 of AGENT_CHECKS) {
136492
136660
  const path3 = await whichBinary(check2.binary);
136493
136661
  if (path3) {
136494
- log19.info("Detected coding agent: %s (%s)", check2.id, path3);
136662
+ log20.info("Detected coding agent: %s (%s)", check2.id, path3);
136495
136663
  detected.push({ id: check2.id, type: check2.type, label: check2.label });
136496
136664
  }
136497
136665
  }
136498
136666
  if (detected.length === 0) {
136499
- log19.info("No coding agent CLIs detected on PATH");
136667
+ log20.info("No coding agent CLIs detected on PATH");
136500
136668
  return;
136501
136669
  }
136502
136670
  const current = loadSettings();
@@ -136505,7 +136673,7 @@ async function ensureDefaultCodingAgents() {
136505
136673
  current.defaultCodingAgent = detected[0].id;
136506
136674
  }
136507
136675
  saveSettings(current);
136508
- 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);
136509
136677
  }
136510
136678
  function ensureNotificationDefaults() {
136511
136679
  const settings = loadSettings();
@@ -136517,7 +136685,7 @@ function ensureNotificationDefaults() {
136517
136685
  ...settings,
136518
136686
  notifications: { ...notifications, soundOnNeedsAttention: true }
136519
136687
  });
136520
- log19.info("Set default notifications.soundOnNeedsAttention = true");
136688
+ log20.info("Set default notifications.soundOnNeedsAttention = true");
136521
136689
  }
136522
136690
  async function ensureClaudeHooks() {
136523
136691
  try {
@@ -136526,9 +136694,9 @@ async function ensureClaudeHooks() {
136526
136694
  return;
136527
136695
  }
136528
136696
  await installHooks();
136529
- log19.info("Installed Claude Code hooks");
136697
+ log20.info("Installed Claude Code hooks");
136530
136698
  } catch (err) {
136531
- log19.warn(
136699
+ log20.warn(
136532
136700
  "Failed to install Claude Code hooks: %s",
136533
136701
  err instanceof Error ? err.message : String(err)
136534
136702
  );
@@ -136536,11 +136704,11 @@ async function ensureClaudeHooks() {
136536
136704
  }
136537
136705
  async function ensureSkillsInstalled() {
136538
136706
  try {
136539
- const result = await installSkills({ log: log19 });
136707
+ const result = await installSkills({ log: log20 });
136540
136708
  const wrote = result.written.length + result.updated.length;
136541
136709
  const linkChange = result.linked.length;
136542
136710
  if (wrote > 0 || linkChange > 0 || result.conflicts.length > 0) {
136543
- log19.info(
136711
+ log20.info(
136544
136712
  "Synced CLI skills (shared: %d written, %d updated, %d unchanged; symlinks: %d created, %d already-linked, %d conflicts, %d skipped)",
136545
136713
  result.written.length,
136546
136714
  result.updated.length,
@@ -136552,13 +136720,13 @@ async function ensureSkillsInstalled() {
136552
136720
  );
136553
136721
  }
136554
136722
  } catch (err) {
136555
- 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));
136556
136724
  }
136557
136725
  }
136558
136726
 
136559
136727
  // src/lib/terminal-manager.ts
136560
136728
  init_src();
136561
- import { existsSync as existsSync6 } from "node:fs";
136729
+ import { existsSync as existsSync7 } from "node:fs";
136562
136730
  import { join as join21 } from "node:path";
136563
136731
 
136564
136732
  // src/lib/terminal-layout-manager.ts
@@ -136586,7 +136754,7 @@ function removeTerminalFromLayout(workspaceId, terminalId) {
136586
136754
  }
136587
136755
 
136588
136756
  // src/lib/terminal-manager.ts
136589
- var log20 = createLogger("terminal");
136757
+ var log21 = createLogger("terminal");
136590
136758
  var MAX_SCROLLBACK_SIZE = 1e5;
136591
136759
  var terminals = /* @__PURE__ */ new Map();
136592
136760
  var workspaceTerminals = /* @__PURE__ */ new Map();
@@ -136617,20 +136785,20 @@ async function spawnTerminal(workspaceId, terminalId, options2) {
136617
136785
  if (options2?.cwd) {
136618
136786
  const resolved = join21(workspaceRoot, options2.cwd);
136619
136787
  if (!resolved.startsWith(workspaceRoot)) {
136620
- log20.warn("Ignoring cwd %s \u2014 resolves outside workspace root %s", options2.cwd, workspaceRoot);
136621
- } else if (existsSync6(resolved)) {
136788
+ log21.warn("Ignoring cwd %s \u2014 resolves outside workspace root %s", options2.cwd, workspaceRoot);
136789
+ } else if (existsSync7(resolved)) {
136622
136790
  cwd = resolved;
136623
136791
  } else {
136624
- 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);
136625
136793
  }
136626
136794
  }
136627
- if (!existsSync6(cwd)) {
136795
+ if (!existsSync7(cwd)) {
136628
136796
  throw new Error(`Workspace directory does not exist: ${cwd}`);
136629
136797
  }
136630
- if (!existsSync6(shell)) {
136798
+ if (!existsSync7(shell)) {
136631
136799
  throw new Error(`Shell not found: ${shell}`);
136632
136800
  }
136633
- log20.debug(
136801
+ log21.debug(
136634
136802
  "Spawning shell %s in %s for terminal %s (PATH=%s)",
136635
136803
  shell,
136636
136804
  cwd,
@@ -136649,7 +136817,7 @@ async function spawnTerminal(workspaceId, terminalId, options2) {
136649
136817
  });
136650
136818
  } catch (err) {
136651
136819
  const msg = err instanceof Error ? err.message : String(err);
136652
- 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);
136653
136821
  throw err;
136654
136822
  }
136655
136823
  const session = { pty: ptyProcess, scrollback: "", workspaceId };
@@ -136685,7 +136853,7 @@ async function spawnTerminal(workspaceId, terminalId, options2) {
136685
136853
  }
136686
136854
  });
136687
136855
  ptyProcess.onExit(() => {
136688
- log20.debug("Terminal exited: %s (workspace %s)", terminalId, workspaceId);
136856
+ log21.debug("Terminal exited: %s (workspace %s)", terminalId, workspaceId);
136689
136857
  terminals.delete(terminalId);
136690
136858
  outputListeners.delete(terminalId);
136691
136859
  const set2 = workspaceTerminals.get(workspaceId);
@@ -136793,13 +136961,36 @@ function killAllTerminals() {
136793
136961
 
136794
136962
  // src/lib/terminal-ws.ts
136795
136963
  init_src();
136796
- 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
+ }
136797
136988
  async function handleTerminalConnection(ws, req) {
136798
136989
  const url2 = new URL(req.url, `http://${req.headers.host}`);
136799
136990
  const workspaceId = url2.searchParams.get("workspaceId");
136800
136991
  const terminalId = url2.searchParams.get("terminalId");
136801
136992
  if (!workspaceId || !terminalId) {
136802
- ws.close(4e3, "Missing workspaceId or terminalId");
136993
+ safeClose(ws, 4e3, "Missing workspaceId or terminalId");
136803
136994
  return;
136804
136995
  }
136805
136996
  const existing = getTerminalSession(terminalId);
@@ -136834,8 +137025,8 @@ async function handleTerminalConnection(ws, req) {
136834
137025
  session = await spawnTerminal(workspaceId, terminalId, spawnOpts);
136835
137026
  } catch (err) {
136836
137027
  const msg = err instanceof Error ? err.message : String(err);
136837
- log21.error("Failed to spawn terminal %s for workspace %s: %s", terminalId, workspaceId, msg);
136838
- ws.close(4001, msg);
137028
+ log22.error("Failed to spawn terminal %s for workspace %s: %s", terminalId, workspaceId, msg);
137029
+ safeClose(ws, 4001, msg);
136839
137030
  return;
136840
137031
  }
136841
137032
  attachSession(ws, terminalId, workspaceId, session, true);
@@ -136848,7 +137039,7 @@ async function handleTerminalConnection(ws, req) {
136848
137039
  });
136849
137040
  }
136850
137041
  function attachSession(ws, terminalId, workspaceId, session, isNew) {
136851
- log21.debug(
137042
+ log22.debug(
136852
137043
  "Terminal %s: %s (workspace %s)",
136853
137044
  isNew ? "connected" : "reconnected",
136854
137045
  terminalId,
@@ -136877,7 +137068,7 @@ function attachSession(ws, terminalId, workspaceId, session, isNew) {
136877
137068
  }, 3e3);
136878
137069
  const exitDisposable = session.pty.onExit(({ exitCode }) => {
136879
137070
  clearInterval(processInterval);
136880
- 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);
136881
137072
  if (ws.readyState === ws.OPEN) {
136882
137073
  ws.close(1e3, "Terminal exited");
136883
137074
  }
@@ -136889,7 +137080,7 @@ function attachSession(ws, terminalId, workspaceId, session, isNew) {
136889
137080
  clearInterval(processInterval);
136890
137081
  dataDisposable.dispose();
136891
137082
  exitDisposable.dispose();
136892
- log21.debug("Terminal disconnected: %s (PTY kept alive)", terminalId);
137083
+ log22.debug("Terminal disconnected: %s (PTY kept alive)", terminalId);
136893
137084
  });
136894
137085
  }
136895
137086
  function handleMessage(ws, terminalId, session, message) {
@@ -136927,7 +137118,7 @@ function getToken() {
136927
137118
  }
136928
137119
 
136929
137120
  // src/lib/tunnel.ts
136930
- var log22 = createLogger("tunnel");
137121
+ var log23 = createLogger("tunnel");
136931
137122
  var tunnelProcess = null;
136932
137123
  var tunnelUrl = null;
136933
137124
  var startInProgress = null;
@@ -136941,7 +137132,7 @@ function appendToken(baseUrl, token) {
136941
137132
  }
136942
137133
  function spawnTunnel(options2, resolvedPath) {
136943
137134
  const args = ["tunnel", "--config", "/dev/null", "--url", `http://localhost:${options2.port}`];
136944
- log22.debug("spawning cloudflared %s", args.join(" "));
137135
+ log23.debug("spawning cloudflared %s", args.join(" "));
136945
137136
  return new Promise((resolve8, reject) => {
136946
137137
  const child = spawn7("cloudflared", args, {
136947
137138
  env: { ...process.env, PATH: resolvedPath },
@@ -136955,12 +137146,12 @@ function spawnTunnel(options2, resolvedPath) {
136955
137146
  for (const line2 of text4.split("\n")) {
136956
137147
  const trimmed = line2.trim();
136957
137148
  if (!trimmed) continue;
136958
- log22.debug("output: %s", trimmed);
137149
+ log23.debug("output: %s", trimmed);
136959
137150
  const url2 = extractUrl(trimmed);
136960
137151
  if (url2) {
136961
137152
  const token = getToken();
136962
137153
  tunnelUrl = appendToken(url2, token);
136963
- log22.debug("detected URL: %s", tunnelUrl);
137154
+ log23.debug("detected URL: %s", tunnelUrl);
136964
137155
  emit({ kind: "tunnel-url", url: tunnelUrl });
136965
137156
  if (!settled) {
136966
137157
  settled = true;
@@ -136975,7 +137166,7 @@ function spawnTunnel(options2, resolvedPath) {
136975
137166
  handleOutput(data);
136976
137167
  });
136977
137168
  child.on("error", (err) => {
136978
- log22.debug("process error: %s", err.message);
137169
+ log23.debug("process error: %s", err.message);
136979
137170
  tunnelProcess = null;
136980
137171
  tunnelUrl = null;
136981
137172
  emit({ kind: "tunnel-error", error: err.message });
@@ -136985,7 +137176,7 @@ function spawnTunnel(options2, resolvedPath) {
136985
137176
  }
136986
137177
  });
136987
137178
  child.on("exit", (code) => {
136988
- log22.debug("process exited with code: %d", code ?? -1);
137179
+ log23.debug("process exited with code: %d", code ?? -1);
136989
137180
  const wasRunning = tunnelProcess !== null && settled;
136990
137181
  tunnelProcess = null;
136991
137182
  tunnelUrl = null;
@@ -137007,7 +137198,7 @@ function spawnTunnel(options2, resolvedPath) {
137007
137198
  });
137008
137199
  setTimeout(() => {
137009
137200
  if (!settled) {
137010
- log22.debug("30s timeout reached, resolving without URL");
137201
+ log23.debug("30s timeout reached, resolving without URL");
137011
137202
  settled = true;
137012
137203
  resolve8();
137013
137204
  }
@@ -137016,12 +137207,12 @@ function spawnTunnel(options2, resolvedPath) {
137016
137207
  }
137017
137208
  async function startTunnel(options2) {
137018
137209
  if (startInProgress) {
137019
- log22.debug("startTunnel: start already in progress, waiting...");
137210
+ log23.debug("startTunnel: start already in progress, waiting...");
137020
137211
  await startInProgress;
137021
137212
  return;
137022
137213
  }
137023
137214
  if (tunnelProcess) {
137024
- log22.debug("startTunnel: already running, re-emitting URL");
137215
+ log23.debug("startTunnel: already running, re-emitting URL");
137025
137216
  if (tunnelUrl) {
137026
137217
  emit({ kind: "tunnel-url", url: tunnelUrl });
137027
137218
  }
@@ -143947,7 +144138,7 @@ function createContext8() {
143947
144138
  // src/trpc/router.ts
143948
144139
  import { execFile as execFile5, execFileSync as execFileSync2, spawn as spawn8 } from "node:child_process";
143949
144140
  import { randomUUID as randomUUID2 } from "node:crypto";
143950
- 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";
143951
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";
143952
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";
143953
144144
  import { promisify } from "node:util";
@@ -144052,7 +144243,7 @@ function clearHistory(workspaceId, range, now = Date.now()) {
144052
144243
 
144053
144244
  // src/lib/chat-session-summary.ts
144054
144245
  init_src();
144055
- var log23 = createLogger("chat-session-summary");
144246
+ var log24 = createLogger("chat-session-summary");
144056
144247
  var REFRESH_KEY = Symbol.for("band.chat-session-summary.refresh");
144057
144248
  var g15 = globalThis;
144058
144249
  if (!g15[REFRESH_KEY]) g15[REFRESH_KEY] = /* @__PURE__ */ new Map();
@@ -144082,7 +144273,7 @@ async function ensureActiveSessionSummary(chatId, worktreePath) {
144082
144273
  });
144083
144274
  return getChat(chatId);
144084
144275
  } catch (err) {
144085
- log23.warn({ chatId, err }, "ensureActiveSessionSummary failed");
144276
+ log24.warn({ chatId, err }, "ensureActiveSessionSummary failed");
144086
144277
  return chat;
144087
144278
  }
144088
144279
  }
@@ -144119,7 +144310,7 @@ async function doRefresh(chatId, worktreePath) {
144119
144310
  lastModified: latest.lastModified
144120
144311
  });
144121
144312
  } catch (err) {
144122
- log23.warn({ chatId, err }, "active session refresh failed");
144313
+ log24.warn({ chatId, err }, "active session refresh failed");
144123
144314
  }
144124
144315
  }
144125
144316
 
@@ -144429,10 +144620,10 @@ function subscribeToFileChanges(workspaceId, listener) {
144429
144620
 
144430
144621
  // src/lib/formatter.ts
144431
144622
  init_src();
144432
- import { existsSync as existsSync7, realpathSync as realpathSync4 } from "node:fs";
144623
+ import { existsSync as existsSync8, realpathSync as realpathSync4 } from "node:fs";
144433
144624
  import { basename, dirname as dirname6, isAbsolute, join as join22, resolve as resolvePath } from "node:path";
144434
144625
  import prettier from "prettier";
144435
- var log24 = createLogger("formatter");
144626
+ var log25 = createLogger("formatter");
144436
144627
  var FormatterError = class extends Error {
144437
144628
  code;
144438
144629
  detail;
@@ -144456,7 +144647,7 @@ async function formatFile(worktreePath, filePath, content2, options2 = {}) {
144456
144647
  const ignorePath = resolvePath(worktreePath, ".prettierignore");
144457
144648
  const info = await prettier.getFileInfo(absFile, {
144458
144649
  resolveConfig: true,
144459
- ignorePath: existsSync7(ignorePath) ? ignorePath : void 0
144650
+ ignorePath: existsSync8(ignorePath) ? ignorePath : void 0
144460
144651
  });
144461
144652
  if (info.ignored) {
144462
144653
  return {
@@ -144487,7 +144678,7 @@ async function formatFile(worktreePath, filePath, content2, options2 = {}) {
144487
144678
  }
144488
144679
  const changed = formatted !== content2;
144489
144680
  if (changed) {
144490
- log24.info(
144681
+ log25.info(
144491
144682
  "Formatted %s with parser=%s (%d bytes in)",
144492
144683
  absFile,
144493
144684
  info.inferredParser,
@@ -144626,7 +144817,7 @@ function fuzzyScore(query, filePath) {
144626
144817
  // src/lib/terminal-config.ts
144627
144818
  init_src();
144628
144819
  init_zod();
144629
- var log25 = createLogger("terminal-config");
144820
+ var log26 = createLogger("terminal-config");
144630
144821
  var TerminalPaneConfigSchema = external_exports2.object({
144631
144822
  name: external_exports2.string().optional(),
144632
144823
  command: external_exports2.string().optional(),
@@ -144657,7 +144848,7 @@ function loadWorkspaceTerminalConfig(worktreePath, projectPath) {
144657
144848
  if (!terminalBlock) return null;
144658
144849
  const result = WorkspaceTerminalConfigSchema.safeParse(terminalBlock);
144659
144850
  if (!result.success) {
144660
- log25.warn(
144851
+ log26.warn(
144661
144852
  "Invalid workspace.terminal config: %s",
144662
144853
  result.error.issues.map((i2) => `${i2.path.join(".")}: ${i2.message}`).join("; ")
144663
144854
  );
@@ -144668,7 +144859,7 @@ function loadWorkspaceTerminalConfig(worktreePath, projectPath) {
144668
144859
 
144669
144860
  // src/trpc/router.ts
144670
144861
  var execFileAsync = promisify(execFile5);
144671
- var log26 = createLogger("trpc");
144862
+ var log27 = createLogger("trpc");
144672
144863
  var t2 = initTRPC.context().create();
144673
144864
  var publicProcedure = t2.procedure;
144674
144865
  var projectsRouter = t2.router({
@@ -144677,26 +144868,32 @@ var projectsRouter = t2.router({
144677
144868
  const settings = loadSettings();
144678
144869
  const statuses = loadCurrentStatuses();
144679
144870
  const statusMap = new Map(statuses.map((s6) => [s6.workspaceId, s6]));
144871
+ for (const project of state2.projects) {
144872
+ reconcileKindForProject(project);
144873
+ }
144680
144874
  const projects2 = await Promise.all(
144681
144875
  state2.projects.map(async (project) => {
144682
- const trackedBranches = new Set(project.worktrees.map((wt) => wt.branch));
144683
- const trackedByBranch = new Map(project.worktrees.map((wt) => [wt.branch, wt]));
144684
144876
  let worktrees2 = project.worktrees;
144685
- try {
144686
- const gitWorktrees = await listWorktrees(project.path);
144687
- worktrees2 = gitWorktrees.filter((wt) => !wt.isBare && trackedBranches.has(wt.branch)).map((wt) => ({
144688
- branch: wt.branch,
144689
- path: wt.path,
144690
- head: wt.head,
144691
- pinned: trackedByBranch.get(wt.branch)?.pinned ?? false
144692
- }));
144693
- } 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
+ }
144694
144890
  }
144695
144891
  return {
144696
144892
  name: project.name,
144697
144893
  path: project.path,
144698
144894
  defaultBranch: project.defaultBranch,
144699
144895
  label: project.label,
144896
+ kind: project.kind,
144700
144897
  worktrees: worktrees2.map((wt) => {
144701
144898
  const workspaceId = toWorkspaceId(project.name, wt.branch);
144702
144899
  const status = statusMap.get(workspaceId);
@@ -144713,7 +144910,7 @@ var projectsRouter = t2.router({
144713
144910
  }),
144714
144911
  checkPath: publicProcedure.input(external_exports2.object({ path: external_exports2.string() })).query(({ input }) => {
144715
144912
  const resolvedPath = resolve6(input.path);
144716
- const isGitRepo = existsSync8(join23(resolvedPath, ".git"));
144913
+ const isGitRepo = existsSync9(join23(resolvedPath, ".git"));
144717
144914
  return { isGitRepo };
144718
144915
  }),
144719
144916
  gitInit: publicProcedure.input(external_exports2.object({ path: external_exports2.string() })).mutation(async ({ input }) => {
@@ -144735,37 +144932,84 @@ var projectsRouter = t2.router({
144735
144932
  );
144736
144933
  }
144737
144934
  }
144935
+ const resolvedPath = resolve6(input.path);
144936
+ const kind = existsSync9(join23(resolvedPath, ".git")) ? "git" : "plain";
144738
144937
  let defaultBranch = "main";
144739
- try {
144740
- const env = { ...process.env };
144741
- if (env.PATH) {
144742
- env.PATH = `/opt/homebrew/bin:/usr/local/bin:${env.PATH}`;
144743
- }
144744
- const output = execFileSync2("git", ["symbolic-ref", "--short", "HEAD"], {
144745
- cwd: input.path,
144746
- env,
144747
- encoding: "utf-8"
144748
- }).trim();
144749
- if (output) defaultBranch = output;
144750
- } catch {
144751
- }
144752
144938
  let worktrees2 = [];
144753
- try {
144754
- const gitWorktrees = await listWorktrees(input.path);
144755
- worktrees2 = gitWorktrees.filter((wt) => !wt.isBare).map((wt) => ({ branch: wt.branch, path: wt.path, head: wt.head, pinned: false }));
144756
- } 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 }];
144757
144960
  }
144758
144961
  const project = {
144759
144962
  name: name24,
144760
- 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,
144761
144969
  defaultBranch,
144762
144970
  worktrees: worktrees2,
144763
- label: input.label ?? void 0
144971
+ label: input.label ?? void 0,
144972
+ kind
144764
144973
  };
144765
144974
  state2.projects.push(project);
144766
144975
  saveState(state2);
144767
144976
  return project;
144768
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
+ }),
144769
145013
  remove: publicProcedure.input(external_exports2.object({ name: external_exports2.string() })).mutation(({ input }) => {
144770
145014
  const state2 = loadState();
144771
145015
  state2.projects = state2.projects.filter((p6) => p6.name !== input.name);
@@ -144817,6 +145061,12 @@ var workspacesRouter = t2.router({
144817
145061
  if (!proj) {
144818
145062
  throw new Error(`Project "${input.project}" not found`);
144819
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
+ }
144820
145070
  const existing = proj.worktrees.find((wt) => wt.branch === input.branch);
144821
145071
  if (existing) {
144822
145072
  return { ok: true, path: existing.path };
@@ -144858,6 +145108,12 @@ var workspacesRouter = t2.router({
144858
145108
  if (!proj) {
144859
145109
  throw new Error(`Project "${input.project}" not found`);
144860
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
+ }
144861
145117
  const { command, env: gitEnv } = gitCmd();
144862
145118
  const output = execFileSync2(command, ["worktree", "list", "--porcelain"], {
144863
145119
  cwd: proj.path,
@@ -144904,13 +145160,13 @@ var workspacesRouter = t2.router({
144904
145160
  try {
144905
145161
  const deletedTasks = deleteWorkspaceTasks(workspaceId);
144906
145162
  if (deletedTasks > 0) {
144907
- log26.info(
145163
+ log27.info(
144908
145164
  { workspaceId, count: deletedTasks },
144909
145165
  "deleted workspace tasks on removal"
144910
145166
  );
144911
145167
  }
144912
145168
  } catch (err) {
144913
- log26.error({ workspaceId, err }, "failed to delete workspace tasks on removal");
145169
+ log27.error({ workspaceId, err }, "failed to delete workspace tasks on removal");
144914
145170
  }
144915
145171
  emit({ kind: "remove", workspaceId });
144916
145172
  const projPath = proj.path;
@@ -144928,7 +145184,7 @@ var workspacesRouter = t2.router({
144928
145184
  timeout: 6e4
144929
145185
  });
144930
145186
  } catch (err) {
144931
- log26.warn({ err, workspaceId }, "teardown script failed");
145187
+ log27.warn({ err, workspaceId }, "teardown script failed");
144932
145188
  }
144933
145189
  }
144934
145190
  try {
@@ -144946,7 +145202,7 @@ var workspacesRouter = t2.router({
144946
145202
  encoding: "utf-8"
144947
145203
  });
144948
145204
  } catch (err) {
144949
- log26.warn({ err, workspaceId }, "git worktree prune failed");
145205
+ log27.warn({ err, workspaceId }, "git worktree prune failed");
144950
145206
  }
144951
145207
  }
144952
145208
  try {
@@ -144958,7 +145214,7 @@ var workspacesRouter = t2.router({
144958
145214
  } catch {
144959
145215
  }
144960
145216
  })().catch((err) => {
144961
- log26.error({ err, workspaceId }, "background workspace cleanup failed");
145217
+ log27.error({ err, workspaceId }, "background workspace cleanup failed");
144962
145218
  });
144963
145219
  });
144964
145220
  return { ok: true };
@@ -144975,6 +145231,12 @@ var workspacesRouter = t2.router({
144975
145231
  if (!proj) {
144976
145232
  throw new Error(`Project "${input.project}" not found`);
144977
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
+ }
144978
145240
  const wt = proj.worktrees.find((w2) => w2.branch === input.branch);
144979
145241
  if (!wt) {
144980
145242
  throw new Error(`Workspace "${input.branch}" not found`);
@@ -144989,6 +145251,12 @@ var workspacesRouter = t2.router({
144989
145251
  if (!workspace) {
144990
145252
  throw new Error("Workspace not found");
144991
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
+ }
144992
145260
  const cwd = workspace.worktree.path;
144993
145261
  try {
144994
145262
  await execGit(["pull", "--rebase"], cwd);
@@ -145007,6 +145275,12 @@ var workspacesRouter = t2.router({
145007
145275
  if (!workspace) {
145008
145276
  throw new Error("Workspace not found");
145009
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
+ }
145010
145284
  const cwd = workspace.worktree.path;
145011
145285
  try {
145012
145286
  await execGit(["push"], cwd);
@@ -145017,7 +145291,7 @@ var workspacesRouter = t2.router({
145017
145291
  }),
145018
145292
  runScript: publicProcedure.input(external_exports2.object({ path: external_exports2.string(), scriptType: external_exports2.string() })).mutation(({ input }) => {
145019
145293
  const scriptPath = join23(input.path, ".band", input.scriptType);
145020
- if (!existsSync8(scriptPath)) {
145294
+ if (!existsSync9(scriptPath)) {
145021
145295
  throw new Error(`Script "${input.scriptType}" not found`);
145022
145296
  }
145023
145297
  return new Promise((resolve8, reject) => {
@@ -145103,6 +145377,7 @@ var LANG_MAP = {
145103
145377
  };
145104
145378
  var compareBranchSchema = external_exports2.string().min(1).regex(/^[^-]/, "branch name must not start with '-'").optional();
145105
145379
  var EMPTY_TREE_ARGS = ["hash-object", "-t", "tree", "/dev/null"];
145380
+ var EMPTY_TREE_SHA = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
145106
145381
  async function resolveDiffContext(cwd, defaultBranch, diffMode, compareBranchInput) {
145107
145382
  const compareBranch = diffMode === "uncommitted" ? defaultBranch : compareBranchInput ?? defaultBranch;
145108
145383
  let headBranch;
@@ -145180,7 +145455,7 @@ var workspaceRouter = t2.router({
145180
145455
  *
145181
145456
  * Returns `{ skipped: true, reason }` when Prettier has no parser for
145182
145457
  * the file's extension (or it's covered by `.prettierignore`). Editors
145183
- * fire this off Cmd+Shift+F without checking the file type first, so a
145458
+ * fire this off Shift+Alt+F without checking the file type first, so a
145184
145459
  * soft skip is the right outcome for unsupported files rather than a
145185
145460
  * surfaced error.
145186
145461
  *
@@ -145291,7 +145566,7 @@ var workspaceRouter = t2.router({
145291
145566
  );
145292
145567
  branches = output.trim().split("\n").map((b10) => b10.trim()).filter(Boolean);
145293
145568
  } catch (err) {
145294
- log26.error(
145569
+ log27.error(
145295
145570
  `listBranches: for-each-ref failed for ${cwd}: ${err instanceof Error ? err.message : err}`
145296
145571
  );
145297
145572
  }
@@ -145381,6 +145656,18 @@ var workspaceRouter = t2.router({
145381
145656
  if (!workspace) {
145382
145657
  throw new Error("Workspace not found");
145383
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
+ }
145384
145671
  const cwd = workspace.worktree.path;
145385
145672
  const defaultBranch = workspace.project.defaultBranch;
145386
145673
  const { compareBranch, headBranch, mergeBase } = await resolveDiffContext(
@@ -145720,11 +146007,11 @@ var workspaceRouter = t2.router({
145720
146007
  if (!target.startsWith(root) || target === root) {
145721
146008
  throw new Error("Invalid path");
145722
146009
  }
145723
- if (existsSync8(target)) {
146010
+ if (existsSync9(target)) {
145724
146011
  throw new Error("A file or directory already exists at this path");
145725
146012
  }
145726
146013
  const parent = dirname7(target);
145727
- if (!existsSync8(parent)) {
146014
+ if (!existsSync9(parent)) {
145728
146015
  throw new Error("Parent directory does not exist");
145729
146016
  }
145730
146017
  const parentStat = await stat4(parent);
@@ -145749,11 +146036,11 @@ var workspaceRouter = t2.router({
145749
146036
  if (!target.startsWith(root) || target === root) {
145750
146037
  throw new Error("Invalid path");
145751
146038
  }
145752
- if (existsSync8(target)) {
146039
+ if (existsSync9(target)) {
145753
146040
  throw new Error("A file or directory already exists at this path");
145754
146041
  }
145755
146042
  const parent = dirname7(target);
145756
- if (!existsSync8(parent)) {
146043
+ if (!existsSync9(parent)) {
145757
146044
  throw new Error("Parent directory does not exist");
145758
146045
  }
145759
146046
  const parentStat = await stat4(parent);
@@ -145828,11 +146115,11 @@ var workspaceRouter = t2.router({
145828
146115
  } catch {
145829
146116
  throw new Error("Source path does not exist");
145830
146117
  }
145831
- if (existsSync8(toTarget)) {
146118
+ if (existsSync9(toTarget)) {
145832
146119
  throw new Error("A file or directory already exists at the destination");
145833
146120
  }
145834
146121
  const toParent = dirname7(toTarget);
145835
- if (!existsSync8(toParent)) {
146122
+ if (!existsSync9(toParent)) {
145836
146123
  throw new Error("Destination parent directory does not exist");
145837
146124
  }
145838
146125
  const toParentStat = await stat4(toParent);
@@ -145882,11 +146169,11 @@ var workspaceRouter = t2.router({
145882
146169
  if (entryStat.isDirectory() && toTarget.startsWith(fromTarget + sep2)) {
145883
146170
  throw new Error("Cannot copy a directory into itself");
145884
146171
  }
145885
- if (existsSync8(toTarget)) {
146172
+ if (existsSync9(toTarget)) {
145886
146173
  throw new Error("A file or directory already exists at the destination");
145887
146174
  }
145888
146175
  const toParent = dirname7(toTarget);
145889
- if (!existsSync8(toParent)) {
146176
+ if (!existsSync9(toParent)) {
145890
146177
  throw new Error("Destination parent directory does not exist");
145891
146178
  }
145892
146179
  const toParentStat = await stat4(toParent);
@@ -146139,21 +146426,21 @@ var tunnelRouter = t2.router({
146139
146426
  return getTunnelStatus();
146140
146427
  }),
146141
146428
  start: publicProcedure.input(external_exports2.object({}).optional()).mutation(async () => {
146142
- log26.debug("tunnel.start called");
146429
+ log27.debug("tunnel.start called");
146143
146430
  const port2 = parseInt(process.env.BAND_PORT || "3456", 10);
146144
- log26.debug("tunnel.start: port=%d", port2);
146431
+ log27.debug("tunnel.start: port=%d", port2);
146145
146432
  try {
146146
146433
  await startTunnel({ port: port2 });
146147
146434
  } catch (err) {
146148
- log26.debug({ err }, "tunnel.start: startTunnel failed");
146435
+ log27.debug({ err }, "tunnel.start: startTunnel failed");
146149
146436
  return { ok: true, url: null };
146150
146437
  }
146151
146438
  const status = getTunnelStatus();
146152
- log26.debug({ status }, "tunnel.start: after startTunnel");
146439
+ log27.debug({ status }, "tunnel.start: after startTunnel");
146153
146440
  if (status.url) {
146154
146441
  return { ok: true, url: status.url };
146155
146442
  }
146156
- log26.debug("tunnel.start: no URL available");
146443
+ log27.debug("tunnel.start: no URL available");
146157
146444
  return { ok: true, url: null };
146158
146445
  }),
146159
146446
  stop: publicProcedure.mutation(async () => {
@@ -146479,15 +146766,15 @@ async function loadJsonlPage(opts) {
146479
146766
  }
146480
146767
  var servicesRouter = t2.router({
146481
146768
  health: publicProcedure.query(() => {
146482
- log26.debug("services.health called");
146769
+ log27.debug("services.health called");
146483
146770
  const tunnel = getTunnelStatus();
146484
- log26.debug({ tunnel }, "services.health: tunnel status");
146771
+ log27.debug({ tunnel }, "services.health: tunnel status");
146485
146772
  const result = {
146486
146773
  webserver: true,
146487
146774
  tunnel: tunnel.running,
146488
146775
  tunnel_url: tunnel.url
146489
146776
  };
146490
- log26.debug({ result }, "services.health result");
146777
+ log27.debug({ result }, "services.health result");
146491
146778
  return result;
146492
146779
  }),
146493
146780
  // Activity level controls how often the branch-status poller fires.
@@ -146881,7 +147168,7 @@ var chatsRouter = t2.router({
146881
147168
  summary = info?.summary;
146882
147169
  lastModified = info?.lastModified;
146883
147170
  } catch (err) {
146884
- log26.warn(
147171
+ log27.warn(
146885
147172
  { chatId: input.chatId, sessionId: input.sessionId, err },
146886
147173
  "setActiveSession: getSessionInfo failed"
146887
147174
  );
@@ -147001,7 +147288,7 @@ var browserHostRouter = t2.router({
147001
147288
  // can confirm in the server log that the bridge component actually
147002
147289
  // executed. Drop once the experiment is stable.
147003
147290
  ping: publicProcedure.input(external_exports2.object({ where: external_exports2.string() })).mutation(({ input }) => {
147004
- log26.info("browserHost.ping from %s", input.where);
147291
+ log27.info("browserHost.ping from %s", input.where);
147005
147292
  return { ok: true };
147006
147293
  }),
147007
147294
  ensureView: publicProcedure.subscription(async function* (opts) {
@@ -147504,10 +147791,20 @@ var assets = build_default(clientDir, {
147504
147791
  gzip: true,
147505
147792
  etag: true
147506
147793
  });
147507
- var openApiDoc = JSON.parse(readFileSync9(join24(import.meta.dirname, "openapi.json"), "utf-8"));
147508
- openApiDoc.servers = [{ url: "/trpc" }];
147509
- var openApiSpec = JSON.stringify(openApiDoc, null, 2);
147510
- 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
+ }
147511
147808
  function serveStaticFile(res, root, subdir, rawFilename) {
147512
147809
  const filename = basename3(decodeURIComponent(rawFilename));
147513
147810
  if (!filename || filename.includes("..")) {
@@ -147561,6 +147858,7 @@ function serveWorkspaceFile(res, workspaceId, rawPath) {
147561
147858
  async function main() {
147562
147859
  runMigrations();
147563
147860
  loadChatsFromDb();
147861
+ loadBrowsersFromDb();
147564
147862
  cleanupStaleTasks();
147565
147863
  startTaskPruneScheduler();
147566
147864
  const resetCount = resetAgentStatuses();
@@ -147666,7 +147964,7 @@ async function main() {
147666
147964
  "Cache-Control": "no-cache",
147667
147965
  "Access-Control-Allow-Origin": "*"
147668
147966
  });
147669
- res.end(openApiSpec);
147967
+ res.end(getOpenApiSpec());
147670
147968
  return;
147671
147969
  }
147672
147970
  if (req.url === "/api/docs") {
@@ -147674,7 +147972,7 @@ async function main() {
147674
147972
  "Content-Type": "text/html",
147675
147973
  "Cache-Control": "no-cache"
147676
147974
  });
147677
- res.end(scalarHtml);
147975
+ res.end(getCachedScalarHtml());
147678
147976
  return;
147679
147977
  }
147680
147978
  if (req.url?.startsWith("/mcp")) {
@@ -147799,6 +148097,7 @@ async function main() {
147799
148097
  });
147800
148098
  httpServer.listen(port, "0.0.0.0", () => {
147801
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`);
147802
148101
  const settings = loadSettings();
147803
148102
  if (settings.autoStartTunnel) {
147804
148103
  checkPrereqs().then((prereqs) => {