@band-app/server 0.24.1 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. package/dist/client/assets/{DockviewBrowserContainer-pecXom0M.js → DockviewBrowserContainer-BiS2PXe9.js} +2 -2
  2. package/dist/client/assets/DockviewTerminalContainer-BFBZVril.js +2 -0
  3. package/dist/client/assets/TerminalPanel-CcBKJ24l.js +1 -0
  4. package/dist/client/assets/{_basePickBy-CtbD70T-.js → _basePickBy-CIajkJdO.js} +1 -1
  5. package/dist/client/assets/_baseUniq-DHw48s_G.js +1 -0
  6. package/dist/client/assets/{arc-BEzsE6TU.js → arc-DexZNm0-.js} +1 -1
  7. package/dist/client/assets/architectureDiagram-VXUJARFQ-DAFvsZAd.js +36 -0
  8. package/dist/client/assets/{blockDiagram-VD42YOAC-CVv0vV-s.js → blockDiagram-VD42YOAC-AWnBKy9Q.js} +1 -1
  9. package/dist/client/assets/{c4Diagram-YG6GDRKO-W3bslfZm.js → c4Diagram-YG6GDRKO-BddbyIic.js} +1 -1
  10. package/dist/client/assets/channel-BSRbBCzT.js +1 -0
  11. package/dist/client/assets/{chunk-4BX2VUAB-B4zNuPCM.js → chunk-4BX2VUAB-DnMh7Pc9.js} +1 -1
  12. package/dist/client/assets/{chunk-55IACEB6-CJb5GOdO.js → chunk-55IACEB6-24SitHr9.js} +1 -1
  13. package/dist/client/assets/{chunk-B4BG7PRW-m9UNdA4H.js → chunk-B4BG7PRW-BOb93Gpn.js} +1 -1
  14. package/dist/client/assets/{chunk-DI55MBZ5-Dyl4ba3F.js → chunk-DI55MBZ5-oSbpJBti.js} +3 -3
  15. package/dist/client/assets/{chunk-FMBD7UC4-Ds1gRx94.js → chunk-FMBD7UC4-Dqfg6wVO.js} +1 -1
  16. package/dist/client/assets/chunk-QN33PNHL-C2cIUL6l.js +1 -0
  17. package/dist/client/assets/{chunk-QZHKN3VN-BiZtPmD0.js → chunk-QZHKN3VN-Ox_MiYok.js} +1 -1
  18. package/dist/client/assets/{chunk-TZMSLE5B-DCz64hjM.js → chunk-TZMSLE5B-CGaUt5wn.js} +1 -1
  19. package/dist/client/assets/classDiagram-2ON5EDUG-ntGI3hWd.js +1 -0
  20. package/dist/client/assets/classDiagram-v2-WZHVMYZB-ntGI3hWd.js +1 -0
  21. package/dist/client/assets/clone-Q7bdnWu2.js +1 -0
  22. package/dist/client/assets/cose-bilkent-S5V4N54A-D_3-w0MJ.js +1 -0
  23. package/dist/client/assets/dagre-6UL2VRFP-DTrojOKw.js +4 -0
  24. package/dist/client/assets/diagram-PSM6KHXK-D3nSuJ59.js +24 -0
  25. package/dist/client/assets/diagram-QEK2KX5R-h0Gm6yRs.js +43 -0
  26. package/dist/client/assets/diagram-S2PKOQOG-DIOqbA5d.js +24 -0
  27. package/dist/client/assets/{erDiagram-Q2GNP2WA-WnEcSFDk.js → erDiagram-Q2GNP2WA-BGWtWskF.js} +3 -3
  28. package/dist/client/assets/{flowDiagram-NV44I4VS-BONBJZ3h.js → flowDiagram-NV44I4VS-BHqUj91h.js} +1 -1
  29. package/dist/client/assets/{ganttDiagram-JELNMOA3-BDhpQL_t.js → ganttDiagram-JELNMOA3-CCA7lEel.js} +3 -3
  30. package/dist/client/assets/gitGraphDiagram-V2S2FVAM-CXisBbMV.js +65 -0
  31. package/dist/client/assets/{graph-DmGEXolJ.js → graph-C8GKZaWf.js} +1 -1
  32. package/dist/client/assets/{highlighted-body-B3W2YXNL-m0iS7EC3.js → highlighted-body-B3W2YXNL-Ckz9HnyE.js} +1 -1
  33. package/dist/client/assets/{index-D6Afu1pA.js → index-1qpYuqGB.js} +1 -1
  34. package/dist/client/assets/{index-BoLCZb5I.js → index-B7L6_ylA.js} +1 -1
  35. package/dist/client/assets/{index-CiKuHiO0.js → index-BROqtYkO.js} +1 -1
  36. package/dist/client/assets/{index-DBnjKdGf.js → index-BasWn2BQ.js} +1 -1
  37. package/dist/client/assets/{index-DgEnCq6K.js → index-C22P_3Ba.js} +1 -1
  38. package/dist/client/assets/{index-CfW6UcUl.js → index-CN7sJN1E.js} +1 -1
  39. package/dist/client/assets/{index-BpxKDn01.js → index-CNSO_MYp.js} +1 -1
  40. package/dist/client/assets/{index-CFnCbQSl.js → index-CmpISwt5.js} +1 -1
  41. package/dist/client/assets/{index-0oNHljPn.js → index-CyfIec3L.js} +1 -1
  42. package/dist/client/assets/{index-BMTzG2fm.js → index-D0m_DHVt.js} +1 -1
  43. package/dist/client/assets/{index-Dmse4WDP.js → index-D2Sje321.js} +1 -1
  44. package/dist/client/assets/{index-B102sYPH.js → index-D5Pn_WYc.js} +1 -1
  45. package/dist/client/assets/{index-C46YYuZo.js → index-DPLAjlSm.js} +1 -1
  46. package/dist/client/assets/{index-BBy73G4g.js → index-DfZlU-44.js} +1 -1
  47. package/dist/client/assets/{index-BvzISRCa.js → index-TsR4AJCf.js} +2 -2
  48. package/dist/client/assets/{index-CDJOOMr2.js → index-UViDhopU.js} +1 -1
  49. package/dist/client/assets/{index-B-4gD4iz.js → index-rwBKhhdF.js} +1 -1
  50. package/dist/client/assets/{index-3O6bsWX3.js → index-s1AHxiWE.js} +1 -1
  51. package/dist/client/assets/infoDiagram-HS3SLOUP-CbFZ5guu.js +2 -0
  52. package/dist/client/assets/{journeyDiagram-XKPGCS4Q-Dlf8x32q.js → journeyDiagram-XKPGCS4Q-DgIR2fwH.js} +1 -1
  53. package/dist/client/assets/{kanban-definition-3W4ZIXB7-BVJThDju.js → kanban-definition-3W4ZIXB7-BvaiOaK8.js} +1 -1
  54. package/dist/client/assets/{layout-CbZgayJn.js → layout-BHFL_-2i.js} +1 -1
  55. package/dist/client/assets/main-DpPgdfV2.css +1 -0
  56. package/dist/client/assets/{main-RztHx-sU.js → main-Dtbkl2jA.js} +239 -232
  57. package/dist/client/assets/{mindmap-definition-VGOIOE7T-C4kJ6VHG.js → mindmap-definition-VGOIOE7T-BXmDj_SN.js} +3 -3
  58. package/dist/client/assets/pieDiagram-ADFJNKIX-DWBhs-q-.js +30 -0
  59. package/dist/client/assets/{quadrantDiagram-AYHSOK5B-Bec9Hhh2.js → quadrantDiagram-AYHSOK5B-BLczU7TW.js} +1 -1
  60. package/dist/client/assets/{requirementDiagram-UZGBJVZJ-CsOubtSM.js → requirementDiagram-UZGBJVZJ-lm071pmC.js} +1 -1
  61. package/dist/client/assets/{sankeyDiagram-TZEHDZUN-C8Gm96t1.js → sankeyDiagram-TZEHDZUN-CWgkQuq0.js} +5 -5
  62. package/dist/client/assets/{sequenceDiagram-WL72ISMW-Bvgi8x7V.js → sequenceDiagram-WL72ISMW-DR0quDCJ.js} +6 -6
  63. package/dist/client/assets/{square-terminal-BHkrAD3A.js → square-terminal-ByCNqakb.js} +1 -1
  64. package/dist/client/assets/stateDiagram-FKZM4ZOC-CWjWCPZ4.js +1 -0
  65. package/dist/client/assets/stateDiagram-v2-4FDKWEC3-CPppMgt3.js +1 -0
  66. package/dist/client/assets/{timeline-definition-IT6M3QCI-BNBrcAuE.js → timeline-definition-IT6M3QCI-BMaR6Nuo.js} +3 -3
  67. package/dist/client/assets/{treemap-GDKQZRPO-Dt5TrQzS.js → treemap-GDKQZRPO-CbRLz23z.js} +1 -1
  68. package/dist/client/assets/{workspace._workspaceId-DGQl6asL.js → workspace._workspaceId-4ah7xBuS.js} +1 -1
  69. package/dist/client/assets/{workspace._workspaceId-Cx9WUFHK.js → workspace._workspaceId-Dg3ERq5R.js} +2 -2
  70. package/dist/client/assets/{xychartDiagram-PRI3JC2R-BbVpQ6GU.js → xychartDiagram-PRI3JC2R-DNMYDMAj.js} +2 -2
  71. package/dist/server/assets/{DockviewBrowserContainer-BDsafKFK.js → DockviewBrowserContainer-BuItINME.js} +1 -1
  72. package/dist/server/assets/{DockviewTerminalContainer-CMbrr8wZ.js → DockviewTerminalContainer-TX2ecJ9k.js} +5 -3
  73. package/dist/server/assets/TerminalPanel-CvEpdUzO.js +425 -0
  74. package/dist/server/assets/{_basePickBy-ljLFy5Cm.js → _basePickBy-7qoOGcXD.js} +2 -2
  75. package/dist/server/assets/{_baseUniq-DQmNpetJ.js → _baseUniq-Cm0aWwLl.js} +1 -1
  76. package/dist/server/assets/_tanstack-start-manifest_v-DuTbaj5T.js +4 -0
  77. package/dist/server/assets/{arc-KHCw-8vd.js → arc-DH5jD29O.js} +1 -1
  78. package/dist/server/assets/{architecture-7HQA4BMR-BScKJqpc.js → architecture-7HQA4BMR-BQSW1CNO.js} +6 -6
  79. package/dist/server/assets/{architectureDiagram-VXUJARFQ-T9CAFBo1.js → architectureDiagram-VXUJARFQ-DgTZkqMC.js} +6 -6
  80. package/dist/server/assets/{blockDiagram-VD42YOAC-BKZ2vg7U.js → blockDiagram-VD42YOAC-CHY_BpPT.js} +6 -6
  81. package/dist/server/assets/{c4Diagram-YG6GDRKO-D585k1An.js → c4Diagram-YG6GDRKO-Buvaq10G.js} +2 -2
  82. package/dist/server/assets/{channel-CyG4ozZq.js → channel-CSV_0Wq9.js} +1 -1
  83. package/dist/server/assets/{chunk-4BX2VUAB-BHWbP2Lt.js → chunk-4BX2VUAB-B4TPMkRz.js} +1 -1
  84. package/dist/server/assets/{chunk-55IACEB6-CrerCu6v.js → chunk-55IACEB6-CTFAFIsE.js} +1 -1
  85. package/dist/server/assets/{chunk-B4BG7PRW-D3sl50Aa.js → chunk-B4BG7PRW-CR8829ZP.js} +4 -4
  86. package/dist/server/assets/{chunk-DI55MBZ5-DR6gThvq.js → chunk-DI55MBZ5-DetqjIc9.js} +3 -3
  87. package/dist/server/assets/{chunk-FMBD7UC4-Cil9b1Ts.js → chunk-FMBD7UC4-D6DpqSQ8.js} +1 -1
  88. package/dist/server/assets/{chunk-QN33PNHL-BAKy9Ygg.js → chunk-QN33PNHL-U9pD23ft.js} +1 -1
  89. package/dist/server/assets/{chunk-QZHKN3VN-G4fU4Ucn.js → chunk-QZHKN3VN-BK2E8m4j.js} +1 -1
  90. package/dist/server/assets/{chunk-TZMSLE5B-LzSrmWV5.js → chunk-TZMSLE5B-DRLbWC_A.js} +1 -1
  91. package/dist/server/assets/{classDiagram-v2-WZHVMYZB-Ds7CCTUR.js → classDiagram-2ON5EDUG-BNcG92nY.js} +5 -5
  92. package/dist/server/assets/{classDiagram-2ON5EDUG-Ds7CCTUR.js → classDiagram-v2-WZHVMYZB-BNcG92nY.js} +5 -5
  93. package/dist/server/assets/{clone-B4KVJdwD.js → clone-CHpwEW-O.js} +1 -1
  94. package/dist/server/assets/{cose-bilkent-S5V4N54A-DaKuQRAN.js → cose-bilkent-S5V4N54A-700evsrQ.js} +1 -1
  95. package/dist/server/assets/{dagre-6UL2VRFP-CNIyd6rH.js → dagre-6UL2VRFP-B8Qw2znf.js} +6 -6
  96. package/dist/server/assets/{diagram-PSM6KHXK-ByElNwdP.js → diagram-PSM6KHXK-C6EJCqfL.js} +7 -7
  97. package/dist/server/assets/{diagram-QEK2KX5R-Bpupf8hI.js → diagram-QEK2KX5R-CQAcI4L4.js} +6 -6
  98. package/dist/server/assets/{diagram-S2PKOQOG-CSa3a_oJ.js → diagram-S2PKOQOG-DsDqxdmS.js} +6 -6
  99. package/dist/server/assets/{erDiagram-Q2GNP2WA-B3yUU2uu.js → erDiagram-Q2GNP2WA-DGEMY_JO.js} +4 -4
  100. package/dist/server/assets/{flowDiagram-NV44I4VS-CUlvxSwr.js → flowDiagram-NV44I4VS-DCV18CNa.js} +5 -5
  101. package/dist/server/assets/{ganttDiagram-JELNMOA3-BWxUm4vA.js → ganttDiagram-JELNMOA3-Cf9uIRTp.js} +1 -1
  102. package/dist/server/assets/{gitGraph-G5XIXVHT-DexlvPgJ.js → gitGraph-G5XIXVHT-Bphh3EfC.js} +6 -6
  103. package/dist/server/assets/{gitGraphDiagram-V2S2FVAM-CepF7ieg.js → gitGraphDiagram-V2S2FVAM-_q2n-s2e.js} +7 -7
  104. package/dist/server/assets/{graph-BB3rQyk7.js → graph-Ccd2dFz0.js} +2 -2
  105. package/dist/server/assets/{highlighted-body-B3W2YXNL-CktYi1nO.js → highlighted-body-B3W2YXNL-DYwYCtBU.js} +1 -1
  106. package/dist/server/assets/{index-zM-wWcHV.js → index-4y021XhL.js} +1 -1
  107. package/dist/server/assets/{index-DipxLM5f.js → index-B1VfjVjc.js} +2 -2
  108. package/dist/server/assets/{index-BDqHa1DL.js → index-B1aJ0zMt.js} +5 -5
  109. package/dist/server/assets/{index-DR892S39.js → index-BCLSgPI1.js} +2 -2
  110. package/dist/server/assets/{index-DYiuwMzT.js → index-BCTaINbC.js} +2 -2
  111. package/dist/server/assets/{index-dAOow3Ru.js → index-BhpCZORq.js} +2 -2
  112. package/dist/server/assets/{index-CUnnFiRO.js → index-C06ZyGGj.js} +4 -4
  113. package/dist/server/assets/{index-BiMwh0FT.js → index-CD62n4Wy.js} +3 -3
  114. package/dist/server/assets/{index-DsPBpNpr.js → index-CXEg-eDA.js} +2 -2
  115. package/dist/server/assets/{index-5St5BCcJ.js → index-CprdJ8Lo.js} +2 -2
  116. package/dist/server/assets/{index-8fW2N3v4.js → index-DGyXXlV8.js} +2 -2
  117. package/dist/server/assets/{index-BZSAPXc2.js → index-DHt4VQNS.js} +5 -5
  118. package/dist/server/assets/{index-DEZw9nkv.js → index-DXSqtFcT.js} +2 -2
  119. package/dist/server/assets/{index-O03NM4sL.js → index-WOVU_Ptt.js} +2 -2
  120. package/dist/server/assets/{index-igT3OuCm.js → index-dJOmGf_o.js} +2 -2
  121. package/dist/server/assets/{index-CGm8Czks.js → index-e4ZKMFB1.js} +2 -2
  122. package/dist/server/assets/{index-B9xqso9p.js → index-rF-uGnt9.js} +1 -1
  123. package/dist/server/assets/{index-bbP5Ilkt.js → index-tV4Tdk7z.js} +3 -3
  124. package/dist/server/assets/{info-VBDWY6EO-BDX5_HTZ.js → info-VBDWY6EO-CtEo3hWH.js} +6 -6
  125. package/dist/server/assets/{infoDiagram-HS3SLOUP-BMd22txJ.js → infoDiagram-HS3SLOUP-DlVfYs3y.js} +5 -5
  126. package/dist/server/assets/{journeyDiagram-XKPGCS4Q-DyIx8DQc.js → journeyDiagram-XKPGCS4Q-DEvLjN67.js} +4 -4
  127. package/dist/server/assets/{kanban-definition-3W4ZIXB7-D6P6mjw2.js → kanban-definition-3W4ZIXB7-C8wt29HD.js} +2 -2
  128. package/dist/server/assets/{layout-_MqV9Ys8.js → layout-B3YZdVGY.js} +4 -4
  129. package/dist/server/assets/{mermaid-3ZIDBTTL-CIBz4-1r.js → mermaid-3ZIDBTTL-Drwee8F2.js} +1 -1
  130. package/dist/server/assets/{mermaid-parser.core-Cga0uwWI.js → mermaid-parser.core-BArH7IDC.js} +11 -11
  131. package/dist/server/assets/{mindmap-definition-VGOIOE7T-C2EIvkPG.js → mindmap-definition-VGOIOE7T-CLGmFN8m.js} +3 -3
  132. package/dist/server/assets/{packet-DYOGHKS2-CCOI47dY.js → packet-DYOGHKS2-BuBX0bTH.js} +6 -6
  133. package/dist/server/assets/{pie-VRWISCQL-BLqEHL1E.js → pie-VRWISCQL-CaZ9Z0V-.js} +6 -6
  134. package/dist/server/assets/{pieDiagram-ADFJNKIX-Cv-DbjH6.js → pieDiagram-ADFJNKIX-jGuNgZxo.js} +7 -7
  135. package/dist/server/assets/{quadrantDiagram-AYHSOK5B-DFyjNST4.js → quadrantDiagram-AYHSOK5B-DAAEbR4l.js} +1 -1
  136. package/dist/server/assets/{radar-ZZBFDIW7-CWlYIMXf.js → radar-ZZBFDIW7-D80s-gzM.js} +6 -6
  137. package/dist/server/assets/{requirementDiagram-UZGBJVZJ-DFM89i-H.js → requirementDiagram-UZGBJVZJ-DmT06vgs.js} +3 -3
  138. package/dist/server/assets/{router-cAoMUC9Q.js → router-PslJYw0K.js} +1798 -664
  139. package/dist/server/assets/{sankeyDiagram-TZEHDZUN-Nmb2f9ga.js → sankeyDiagram-TZEHDZUN-DubOMd7c.js} +1 -1
  140. package/dist/server/assets/{sequenceDiagram-WL72ISMW-BiqqAguj.js → sequenceDiagram-WL72ISMW-V8TCpuJa.js} +3 -3
  141. package/dist/server/assets/{square-terminal-DerzWAi-.js → square-terminal-DqxGkh8h.js} +1 -1
  142. package/dist/server/assets/{stateDiagram-FKZM4ZOC-CkiJXki8.js → stateDiagram-FKZM4ZOC-DDhvvfjL.js} +8 -8
  143. package/dist/server/assets/{stateDiagram-v2-4FDKWEC3-Bt1BL33e.js → stateDiagram-v2-4FDKWEC3-CrVhacjl.js} +4 -4
  144. package/dist/server/assets/{timeline-definition-IT6M3QCI-DCRlJiLq.js → timeline-definition-IT6M3QCI-PRx7QaX4.js} +2 -2
  145. package/dist/server/assets/{treemap-GDKQZRPO-Ci-r6jiA.js → treemap-GDKQZRPO-DDEerlZp.js} +6 -6
  146. package/dist/server/assets/{workspace._workspaceId-Dj6Y8WPo.js → workspace._workspaceId-B_ziNHiq.js} +1 -1
  147. package/dist/server/assets/{workspace._workspaceId-BMnOV3pd.js → workspace._workspaceId-CO8mKKZW.js} +3 -3
  148. package/dist/server/assets/{xychartDiagram-PRI3JC2R-r_3LO6yK.js → xychartDiagram-PRI3JC2R-Cdaq77X5.js} +1 -1
  149. package/dist/server/server.js +2 -2
  150. package/dist/start-server.mjs +65 -7
  151. package/package.json +4 -4
  152. package/dist/client/assets/DockviewTerminalContainer-B_36q2Dz.js +0 -2
  153. package/dist/client/assets/TerminalPanel-DbxLiy2t.js +0 -5
  154. package/dist/client/assets/_baseUniq-Cb5igq_8.js +0 -1
  155. package/dist/client/assets/architectureDiagram-VXUJARFQ-BnV97au3.js +0 -36
  156. package/dist/client/assets/channel-2Of2aNA_.js +0 -1
  157. package/dist/client/assets/chunk-QN33PNHL-yK0yp12G.js +0 -1
  158. package/dist/client/assets/classDiagram-2ON5EDUG-D6UcKhcB.js +0 -1
  159. package/dist/client/assets/classDiagram-v2-WZHVMYZB-D6UcKhcB.js +0 -1
  160. package/dist/client/assets/clone-DBCpY5Fq.js +0 -1
  161. package/dist/client/assets/cose-bilkent-S5V4N54A-BZFGVpWR.js +0 -1
  162. package/dist/client/assets/dagre-6UL2VRFP-DRDPL67k.js +0 -4
  163. package/dist/client/assets/diagram-PSM6KHXK-DYAOsIc0.js +0 -24
  164. package/dist/client/assets/diagram-QEK2KX5R-CnjVQgn2.js +0 -43
  165. package/dist/client/assets/diagram-S2PKOQOG-B8sAgSNe.js +0 -24
  166. package/dist/client/assets/gitGraphDiagram-V2S2FVAM-CZGjCgZ_.js +0 -65
  167. package/dist/client/assets/infoDiagram-HS3SLOUP-Bf3MrisJ.js +0 -2
  168. package/dist/client/assets/main-DOmWiUwE.css +0 -1
  169. package/dist/client/assets/pieDiagram-ADFJNKIX-B4aWIFbt.js +0 -30
  170. package/dist/client/assets/stateDiagram-FKZM4ZOC-TzlVvqDv.js +0 -1
  171. package/dist/client/assets/stateDiagram-v2-4FDKWEC3-BibE5lUV.js +0 -1
  172. package/dist/server/assets/TerminalPanel-nFYTCFHx.js +0 -1238
  173. package/dist/server/assets/_tanstack-start-manifest_v-v9ri0NYD.js +0 -4
@@ -1,1238 +0,0 @@
1
- import { r as reactExports, j as jsxRuntimeExports } from "../server.js";
2
- import { m as createLucideIcon, cn as isFilePath, co as writeClipboardText, cp as readClipboardText, cq as ArrowLeft, cr as ArrowUp, cs as ArrowDown, ct as ArrowRight, cu as ClipboardCopy, X, cv as ClipboardPaste, cg as useSettingsQuery, cw as getCurrentZoomLevel, cx as openExternalUrl, cy as subscribeToZoomChanges, cz as SearchBar, cA as ZOOM_CSS_VAR } from "./router-cAoMUC9Q.js";
3
- import "node:async_hooks";
4
- import "node:stream";
5
- import "util";
6
- import "crypto";
7
- import "async_hooks";
8
- import "stream";
9
- import "node:stream/web";
10
- import "node:process";
11
- import "node:path";
12
- import "node:url";
13
- const __iconNode$2 = [
14
- ["path", { d: "M20 4v7a4 4 0 0 1-4 4H4", key: "6o5b7l" }],
15
- ["path", { d: "m9 10-5 5 5 5", key: "1kshq7" }]
16
- ];
17
- const CornerDownLeft = createLucideIcon("corner-down-left", __iconNode$2);
18
- const __iconNode$1 = [["path", { d: "M22 2 2 22", key: "y4kqgn" }]];
19
- const Slash = createLucideIcon("slash", __iconNode$1);
20
- const __iconNode = [
21
- ["path", { d: "M12 20h-1a2 2 0 0 1-2-2 2 2 0 0 1-2 2H6", key: "1528k5" }],
22
- ["path", { d: "M13 8h7a2 2 0 0 1 2 2v4a2 2 0 0 1-2 2h-7", key: "13ksps" }],
23
- ["path", { d: "M5 16H4a2 2 0 0 1-2-2v-4a2 2 0 0 1 2-2h1", key: "1n9rhb" }],
24
- ["path", { d: "M6 4h1a2 2 0 0 1 2 2 2 2 0 0 1 2-2h1", key: "1mj8rg" }],
25
- ["path", { d: "M9 6v12", key: "velyjx" }]
26
- ];
27
- const TextCursorInput = createLucideIcon("text-cursor-input", __iconNode);
28
- const TERMINAL_TOOLBAR_HEIGHT_PX = 49;
29
- const TOUCH_QUERY = "(hover: none) and (pointer: coarse)";
30
- function useVirtualKeyboardToolbar() {
31
- const [enabled, setEnabled] = reactExports.useState(
32
- () => typeof window === "undefined" ? false : window.matchMedia(TOUCH_QUERY).matches
33
- );
34
- const [bottomOffset, setBottomOffset] = reactExports.useState(0);
35
- reactExports.useEffect(() => {
36
- if (typeof window === "undefined") return;
37
- const mql = window.matchMedia(TOUCH_QUERY);
38
- const handler = (e) => setEnabled(e.matches);
39
- setEnabled(mql.matches);
40
- mql.addEventListener("change", handler);
41
- return () => mql.removeEventListener("change", handler);
42
- }, []);
43
- reactExports.useEffect(() => {
44
- if (typeof window === "undefined") return;
45
- if (!enabled) {
46
- setBottomOffset(0);
47
- return;
48
- }
49
- const vv = window.visualViewport;
50
- if (!vv) return;
51
- const update = () => {
52
- const keyboardHeight = Math.max(0, window.innerHeight - (vv.offsetTop + vv.height));
53
- setBottomOffset(keyboardHeight);
54
- };
55
- update();
56
- vv.addEventListener("resize", update);
57
- vv.addEventListener("scroll", update);
58
- window.addEventListener("resize", update);
59
- return () => {
60
- vv.removeEventListener("resize", update);
61
- vv.removeEventListener("scroll", update);
62
- window.removeEventListener("resize", update);
63
- };
64
- }, [enabled]);
65
- return {
66
- enabled,
67
- bottomOffset,
68
- contentBottomInset: enabled ? TERMINAL_TOOLBAR_HEIGHT_PX : 0
69
- };
70
- }
71
- function findTerminalFileLinks(lineText) {
72
- const candidateRe = /[A-Za-z0-9._/@~+-]+(?::\d+(?:[-:]\d+)?)?/g;
73
- const matches = [];
74
- for (const match of lineText.matchAll(candidateRe)) {
75
- const text = match[0];
76
- if (isFilePath(text)) {
77
- matches.push({ text, startIndex: match.index, endIndex: match.index + text.length });
78
- }
79
- }
80
- return matches;
81
- }
82
- function readLineColumns(terminal, line) {
83
- const parts = [];
84
- const columnForIndex = [];
85
- let length = 0;
86
- let cell;
87
- for (let x = 0; x < terminal.cols; x++) {
88
- cell = line.getCell(x, cell);
89
- if (!cell) continue;
90
- if (cell.getWidth() === 0) continue;
91
- const chars = cell.getChars();
92
- const ch = chars.length > 0 ? chars : " ";
93
- columnForIndex[length] = x + 1;
94
- parts.push(ch);
95
- length += ch.length;
96
- }
97
- return { text: parts.join(""), columnForIndex };
98
- }
99
- function createTerminalFileLinkProvider(terminal, onActivate) {
100
- return {
101
- provideLinks(bufferLineNumber, callback) {
102
- const line = terminal.buffer.active.getLine(bufferLineNumber - 1);
103
- if (!line) {
104
- callback(void 0);
105
- return;
106
- }
107
- const { text, columnForIndex } = readLineColumns(terminal, line);
108
- const matches = findTerminalFileLinks(text);
109
- if (matches.length === 0) {
110
- callback(void 0);
111
- return;
112
- }
113
- const links = matches.map((m) => {
114
- const startColumn = columnForIndex[m.startIndex] ?? 1;
115
- const endColumn = columnForIndex[m.endIndex - 1] ?? terminal.cols;
116
- return {
117
- text: m.text,
118
- range: {
119
- start: { x: startColumn, y: bufferLineNumber },
120
- end: { x: endColumn, y: bufferLineNumber }
121
- },
122
- decorations: { pointerCursor: true, underline: true },
123
- activate: (event) => {
124
- event.preventDefault();
125
- onActivate(m.text);
126
- }
127
- };
128
- });
129
- callback(links);
130
- }
131
- };
132
- }
133
- const WORD_RE = /[A-Za-z0-9_./:\-+@~]/;
134
- function pointToCell(clientX, clientY, terminal, screenEl) {
135
- const rect = screenEl.getBoundingClientRect();
136
- if (rect.width <= 0 || rect.height <= 0 || terminal.cols <= 0 || terminal.rows <= 0) {
137
- return { col: 0, row: terminal.buffer.active.viewportY };
138
- }
139
- const cellW = rect.width / terminal.cols;
140
- const cellH = rect.height / terminal.rows;
141
- const col = clamp(Math.floor((clientX - rect.left) / cellW), 0, terminal.cols - 1);
142
- const viewportRow = clamp(Math.floor((clientY - rect.top) / cellH), 0, terminal.rows - 1);
143
- return { col, row: terminal.buffer.active.viewportY + viewportRow };
144
- }
145
- function findWordBoundaries(line, col) {
146
- if (col < 0 || col >= line.length || !WORD_RE.test(line[col])) {
147
- const safeCol = clamp(col, 0, Math.max(0, line.length));
148
- return { start: safeCol, end: safeCol + 1 };
149
- }
150
- let start = col;
151
- while (start > 0 && WORD_RE.test(line[start - 1])) start--;
152
- let end = col + 1;
153
- while (end < line.length && WORD_RE.test(line[end])) end++;
154
- return { start, end };
155
- }
156
- function getLineText(terminal, row) {
157
- return terminal.buffer.active.getLine(row)?.translateToString(false) ?? "";
158
- }
159
- function moveCell(cell, dir, terminal) {
160
- const cols = terminal.cols;
161
- const lastRow = Math.max(0, terminal.buffer.active.length - 1);
162
- switch (dir) {
163
- case "left":
164
- if (cell.col > 0) return { col: cell.col - 1, row: cell.row };
165
- if (cell.row > 0) return { col: cols - 1, row: cell.row - 1 };
166
- return cell;
167
- case "right":
168
- if (cell.col < cols - 1) return { col: cell.col + 1, row: cell.row };
169
- if (cell.row < lastRow) return { col: 0, row: cell.row + 1 };
170
- return cell;
171
- case "up":
172
- if (cell.row > 0) return { col: cell.col, row: cell.row - 1 };
173
- return cell;
174
- case "down":
175
- if (cell.row < lastRow) return { col: cell.col, row: cell.row + 1 };
176
- return cell;
177
- }
178
- }
179
- function applySelection(terminal, anchor, head) {
180
- const cols = terminal.cols;
181
- if (cols <= 0) return;
182
- const anchorLinear = anchor.row * cols + anchor.col;
183
- const headLinear = head.row * cols + head.col;
184
- const startLinear = Math.min(anchorLinear, headLinear);
185
- const endLinear = Math.max(anchorLinear, headLinear);
186
- const length = endLinear - startLinear + 1;
187
- const startRow = Math.floor(startLinear / cols);
188
- const startCol = startLinear - startRow * cols;
189
- terminal.select(startCol, startRow, length);
190
- }
191
- function wordSelectionAt(cell, lineText) {
192
- const { start, end } = findWordBoundaries(lineText, cell.col);
193
- return {
194
- anchor: { col: start, row: cell.row },
195
- // `head` is the last cell of the selection (inclusive). `end` from
196
- // findWordBoundaries is exclusive, so subtract one.
197
- head: { col: Math.max(start, end - 1), row: cell.row }
198
- };
199
- }
200
- function clamp(n, lo, hi) {
201
- if (n < lo) return lo;
202
- if (n > hi) return hi;
203
- return n;
204
- }
205
- const SEQ_ESC = "\x1B";
206
- const SEQ_TAB = " ";
207
- const SEQ_ENTER = "\r";
208
- const SEQ_SLASH = "/";
209
- const SEQ_ARROW_UP = "\x1B[A";
210
- const SEQ_ARROW_DOWN = "\x1B[B";
211
- const SEQ_ARROW_RIGHT = "\x1B[C";
212
- const SEQ_ARROW_LEFT = "\x1B[D";
213
- const tap = (fn) => (e) => {
214
- e.preventDefault();
215
- void fn();
216
- };
217
- function TerminalToolbar({
218
- terminal,
219
- sendInput,
220
- pendingCtrl,
221
- onToggleCtrl,
222
- selectionMode,
223
- onExtendSelection,
224
- onExitSelection,
225
- onSelectAll
226
- }) {
227
- const { enabled, bottomOffset } = useVirtualKeyboardToolbar();
228
- const handleCopy = reactExports.useCallback(async () => {
229
- if (!terminal.hasSelection()) return;
230
- const text = terminal.getSelection();
231
- if (!text) return;
232
- const ok = await writeClipboardText(text);
233
- if (!ok) console.warn("[TerminalToolbar] clipboard write failed");
234
- }, [terminal]);
235
- const handleCopyAndExit = reactExports.useCallback(async () => {
236
- await handleCopy();
237
- onExitSelection();
238
- }, [handleCopy, onExitSelection]);
239
- const handlePaste = reactExports.useCallback(async () => {
240
- const text = await readClipboardText();
241
- if (text) sendInput(text);
242
- }, [sendInput]);
243
- const idleKeyButtons = reactExports.useMemo(
244
- () => [
245
- { label: "Esc", seq: SEQ_ESC, ariaLabel: "Send Escape" },
246
- { label: "Tab", seq: SEQ_TAB, ariaLabel: "Send Tab" }
247
- ],
248
- []
249
- );
250
- const idleArrows = reactExports.useMemo(
251
- () => [
252
- { Icon: ArrowLeft, seq: SEQ_ARROW_LEFT, ariaLabel: "Arrow Left" },
253
- { Icon: ArrowUp, seq: SEQ_ARROW_UP, ariaLabel: "Arrow Up" },
254
- { Icon: ArrowDown, seq: SEQ_ARROW_DOWN, ariaLabel: "Arrow Down" },
255
- { Icon: ArrowRight, seq: SEQ_ARROW_RIGHT, ariaLabel: "Arrow Right" }
256
- ],
257
- []
258
- );
259
- const selectionArrows = reactExports.useMemo(
260
- () => [
261
- { Icon: ArrowLeft, dir: "left", ariaLabel: "Extend selection left" },
262
- { Icon: ArrowUp, dir: "up", ariaLabel: "Extend selection up" },
263
- { Icon: ArrowDown, dir: "down", ariaLabel: "Extend selection down" },
264
- { Icon: ArrowRight, dir: "right", ariaLabel: "Extend selection right" }
265
- ],
266
- []
267
- );
268
- if (!enabled) return null;
269
- return /* @__PURE__ */ jsxRuntimeExports.jsx(
270
- "div",
271
- {
272
- "data-testid": "terminal-toolbar",
273
- "data-mode": selectionMode ? "selection" : "idle",
274
- role: "toolbar",
275
- "aria-label": selectionMode ? "Terminal selection controls" : "Terminal accessory keys",
276
- style: { bottom: bottomOffset },
277
- className: "fixed inset-x-0 z-50 flex justify-center border-t border-border bg-background/95 shadow-lg backdrop-blur-md",
278
- children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex w-full max-w-3xl items-center gap-1 px-2 py-1.5", children: [
279
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex min-w-0 flex-1 items-center gap-1 overflow-x-auto", children: selectionMode ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
280
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
281
- ToolbarButton,
282
- {
283
- ariaLabel: "Copy selection and exit",
284
- title: "Copy",
285
- onPointerDown: tap(handleCopyAndExit),
286
- variant: "primary",
287
- children: [
288
- /* @__PURE__ */ jsxRuntimeExports.jsx(ClipboardCopy, { className: "size-4" }),
289
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs", children: "Copy" })
290
- ]
291
- }
292
- ),
293
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
294
- ToolbarButton,
295
- {
296
- ariaLabel: "Exit selection mode",
297
- title: "Done",
298
- onPointerDown: tap(onExitSelection),
299
- children: [
300
- /* @__PURE__ */ jsxRuntimeExports.jsx(X, { className: "size-4" }),
301
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs", children: "Done" })
302
- ]
303
- }
304
- ),
305
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mx-1 h-6 w-px shrink-0 bg-border", "aria-hidden": "true" }),
306
- /* @__PURE__ */ jsxRuntimeExports.jsx(
307
- "span",
308
- {
309
- className: "mr-1 shrink-0 select-none text-xs font-medium uppercase tracking-wide text-muted-foreground",
310
- "aria-hidden": "true",
311
- children: "Extend"
312
- }
313
- ),
314
- selectionArrows.map(({ Icon, dir, ariaLabel }) => /* @__PURE__ */ jsxRuntimeExports.jsx(
315
- ToolbarButton,
316
- {
317
- ariaLabel,
318
- title: ariaLabel,
319
- onPointerDown: tap(() => onExtendSelection(dir)),
320
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(Icon, { className: "size-4" })
321
- },
322
- dir
323
- ))
324
- ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
325
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
326
- ToolbarButton,
327
- {
328
- ariaLabel: "Paste from clipboard",
329
- title: "Paste",
330
- onPointerDown: tap(handlePaste),
331
- children: [
332
- /* @__PURE__ */ jsxRuntimeExports.jsx(ClipboardPaste, { className: "size-4" }),
333
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs", children: "Paste" })
334
- ]
335
- }
336
- ),
337
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
338
- ToolbarButton,
339
- {
340
- ariaLabel: "Select all",
341
- title: "Select all",
342
- onPointerDown: tap(onSelectAll),
343
- children: [
344
- /* @__PURE__ */ jsxRuntimeExports.jsx(TextCursorInput, { className: "size-4" }),
345
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs", children: "All" })
346
- ]
347
- }
348
- ),
349
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mx-1 h-6 w-px shrink-0 bg-border", "aria-hidden": "true" }),
350
- idleKeyButtons.map(({ label, seq, ariaLabel }) => /* @__PURE__ */ jsxRuntimeExports.jsx(
351
- ToolbarButton,
352
- {
353
- ariaLabel,
354
- title: label,
355
- onPointerDown: tap(() => sendInput(seq)),
356
- children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-medium", children: label })
357
- },
358
- label
359
- )),
360
- /* @__PURE__ */ jsxRuntimeExports.jsx(
361
- ToolbarButton,
362
- {
363
- ariaLabel: "Send slash",
364
- title: "Slash command",
365
- onPointerDown: tap(() => sendInput(SEQ_SLASH)),
366
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(Slash, { className: "size-4" })
367
- }
368
- ),
369
- /* @__PURE__ */ jsxRuntimeExports.jsx(
370
- ToolbarButton,
371
- {
372
- ariaLabel: pendingCtrl ? "Cancel pending Ctrl" : "Arm Ctrl modifier",
373
- title: "Ctrl (sticky — taps the next key as Ctrl+key)",
374
- onPointerDown: tap(onToggleCtrl),
375
- active: pendingCtrl,
376
- children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-medium", children: "Ctrl" })
377
- }
378
- ),
379
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mx-1 h-6 w-px shrink-0 bg-border", "aria-hidden": "true" }),
380
- idleArrows.map(({ Icon, seq, ariaLabel }) => /* @__PURE__ */ jsxRuntimeExports.jsx(
381
- ToolbarButton,
382
- {
383
- ariaLabel,
384
- title: ariaLabel,
385
- onPointerDown: tap(() => sendInput(seq)),
386
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(Icon, { className: "size-4" })
387
- },
388
- ariaLabel
389
- ))
390
- ] }) }),
391
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-6 w-px shrink-0 bg-border", "aria-hidden": "true" }),
392
- /* @__PURE__ */ jsxRuntimeExports.jsx(
393
- ToolbarButton,
394
- {
395
- ariaLabel: "Send Enter",
396
- title: "Enter",
397
- onPointerDown: tap(() => sendInput(SEQ_ENTER)),
398
- variant: "primary",
399
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(CornerDownLeft, { className: "size-4" })
400
- }
401
- )
402
- ] })
403
- }
404
- );
405
- }
406
- function ToolbarButton({
407
- ariaLabel,
408
- title,
409
- onPointerDown,
410
- active,
411
- variant = "default",
412
- disabled,
413
- children
414
- }) {
415
- const palette = active ? "bg-primary text-primary-foreground" : variant === "primary" ? "bg-primary text-primary-foreground hover:bg-primary/90" : "bg-muted/60 hover:bg-muted active:bg-muted";
416
- return /* @__PURE__ */ jsxRuntimeExports.jsx(
417
- "button",
418
- {
419
- type: "button",
420
- "aria-label": ariaLabel,
421
- "aria-pressed": active,
422
- title,
423
- onPointerDown,
424
- disabled,
425
- className: [
426
- "inline-flex h-9 min-w-9 shrink-0 items-center justify-center gap-1 rounded-md px-2",
427
- "text-foreground transition-colors",
428
- palette,
429
- "disabled:opacity-40"
430
- ].join(" "),
431
- children
432
- }
433
- );
434
- }
435
- const BASE_FONT_SIZE = 13;
436
- const LONG_PRESS_MS = 500;
437
- const LONG_PRESS_SLOP_PX = 10;
438
- const SEARCH_DECORATIONS = {
439
- matchBackground: "#515c6a",
440
- activeMatchBackground: "#a9913680",
441
- matchOverviewRuler: "#a9913680",
442
- activeMatchColorOverviewRuler: "#a99136"
443
- };
444
- const DEFAULT_SEARCH_OPTIONS = {
445
- caseSensitive: false,
446
- wholeWord: false,
447
- regex: false
448
- };
449
- function toXtermSearchOptions(opts) {
450
- return {
451
- caseSensitive: opts.caseSensitive,
452
- wholeWord: opts.wholeWord,
453
- regex: opts.regex,
454
- decorations: SEARCH_DECORATIONS
455
- };
456
- }
457
- const DARK_TERMINAL_THEME = {
458
- background: "#1e1e1e",
459
- foreground: "#e8e8e8",
460
- cursor: "#e8e8e8",
461
- selectionBackground: "rgba(255, 255, 255, 0.2)",
462
- // VS Code Dark+ ANSI palette. Without these 16 entries xterm.js falls back to
463
- // its dated "Tango" default, which renders low-contrast, muddy reds/greens on
464
- // the dark background. These canonical Dark+ values fix that.
465
- black: "#000000",
466
- red: "#cd3131",
467
- green: "#0dbc79",
468
- yellow: "#e5e510",
469
- blue: "#2472c8",
470
- magenta: "#bc3fbc",
471
- cyan: "#11a8cd",
472
- white: "#e5e5e5",
473
- brightBlack: "#666666",
474
- brightRed: "#f14c4c",
475
- brightGreen: "#23d18b",
476
- brightYellow: "#f5f543",
477
- brightBlue: "#3b8eea",
478
- brightMagenta: "#d670d6",
479
- brightCyan: "#29b8db",
480
- brightWhite: "#e5e5e5"
481
- };
482
- const LIGHT_TERMINAL_THEME = {
483
- background: "#ffffff",
484
- foreground: "#1e1e1e",
485
- cursor: "#1e1e1e",
486
- cursorAccent: "#ffffff",
487
- selectionBackground: "rgba(0, 0, 0, 0.15)",
488
- // Tweak ANSI colors so they remain readable on a white background. The default
489
- // bright-yellow / bright-green xterm palette washes out badly in light mode.
490
- black: "#000000",
491
- red: "#cd3131",
492
- green: "#0a8043",
493
- yellow: "#946800",
494
- blue: "#0451a5",
495
- magenta: "#bc05bc",
496
- cyan: "#0598bc",
497
- white: "#555555",
498
- brightBlack: "#666666",
499
- brightRed: "#cd3131",
500
- brightGreen: "#0a8043",
501
- brightYellow: "#946800",
502
- brightBlue: "#0451a5",
503
- brightMagenta: "#bc05bc",
504
- brightCyan: "#0598bc",
505
- brightWhite: "#1e1e1e"
506
- };
507
- function isDarkMode() {
508
- return document.documentElement.classList.contains("dark");
509
- }
510
- function getTerminalTheme() {
511
- return isDarkMode() ? DARK_TERMINAL_THEME : LIGHT_TERMINAL_THEME;
512
- }
513
- function TerminalPanel({
514
- workspaceId,
515
- terminalId,
516
- visible,
517
- paneMetadata,
518
- autoFocus,
519
- onTitleChange
520
- }) {
521
- const containerRef = reactExports.useRef(null);
522
- const terminalRef = reactExports.useRef(null);
523
- const fitAddonRef = reactExports.useRef(null);
524
- const searchAddonRef = reactExports.useRef(null);
525
- const webglAddonRef = reactExports.useRef(null);
526
- const wsRef = reactExports.useRef(null);
527
- const remeasureAndReattachRef = reactExports.useRef(null);
528
- const onTitleChangeRef = reactExports.useRef(onTitleChange);
529
- onTitleChangeRef.current = onTitleChange;
530
- const { settings } = useSettingsQuery();
531
- const useWebGLRenderer = settings.useWebGLTerminalRenderer ?? true;
532
- const useWebGLRendererRef = reactExports.useRef(useWebGLRenderer);
533
- useWebGLRendererRef.current = useWebGLRenderer;
534
- const [searchOpen, setSearchOpen] = reactExports.useState(false);
535
- const [searchQuery, setSearchQuery] = reactExports.useState("");
536
- const [searchOptions, setSearchOptions] = reactExports.useState(DEFAULT_SEARCH_OPTIONS);
537
- const [matchInfo, setMatchInfo] = reactExports.useState({
538
- total: 0,
539
- current: 0
540
- });
541
- const searchBarRef = reactExports.useRef(null);
542
- const openSearchRef = reactExports.useRef(() => {
543
- });
544
- const flushPendingInsertRef = reactExports.useRef(() => {
545
- });
546
- const [terminalReady, setTerminalReady] = reactExports.useState(false);
547
- const pendingCtrlRef = reactExports.useRef(false);
548
- const [pendingCtrl, setPendingCtrl] = reactExports.useState(false);
549
- const handleToggleCtrl = reactExports.useCallback(() => {
550
- const next = !pendingCtrlRef.current;
551
- pendingCtrlRef.current = next;
552
- setPendingCtrl(next);
553
- }, []);
554
- const selectionAnchorRef = reactExports.useRef(null);
555
- const selectionHeadRef = reactExports.useRef(null);
556
- const [selectionMode, setSelectionMode] = reactExports.useState(false);
557
- const exitSelectionMode = reactExports.useCallback(() => {
558
- selectionAnchorRef.current = null;
559
- selectionHeadRef.current = null;
560
- setSelectionMode(false);
561
- terminalRef.current?.clearSelection();
562
- }, []);
563
- const handleExtendSelection = reactExports.useCallback((direction) => {
564
- const terminal = terminalRef.current;
565
- const anchor = selectionAnchorRef.current;
566
- const head = selectionHeadRef.current;
567
- if (!terminal || !anchor || !head) return;
568
- const next = moveCell(head, direction, terminal);
569
- selectionHeadRef.current = next;
570
- applySelection(terminal, anchor, next);
571
- }, []);
572
- const handleSelectAll = reactExports.useCallback(() => {
573
- const terminal = terminalRef.current;
574
- if (!terminal) return;
575
- const anchor = { col: 0, row: 0 };
576
- const lastRow = Math.max(0, terminal.buffer.active.length - 1);
577
- const head = { col: Math.max(0, terminal.cols - 1), row: lastRow };
578
- applySelection(terminal, anchor, head);
579
- selectionAnchorRef.current = anchor;
580
- selectionHeadRef.current = head;
581
- setSelectionMode(true);
582
- terminal.blur();
583
- }, []);
584
- reactExports.useEffect(() => {
585
- if (!containerRef.current) return;
586
- let cancelled = false;
587
- let cleanup;
588
- Promise.all([
589
- import("./xterm-CkV9CBvP.js"),
590
- import("./addon-fit-D89xfLfG.js"),
591
- import("./addon-web-links-CzLDtFWc.js"),
592
- import("./addon-search-BS53_-cp.js"),
593
- import("./addon-webgl-BeO2q2vc.js")
594
- ]).then(([xtermMod, fitMod, webLinksMod, searchMod, webglMod]) => {
595
- const { Terminal: XTerm } = xtermMod;
596
- const { FitAddon: XFitAddon } = fitMod;
597
- const { WebLinksAddon: XWebLinksAddon } = webLinksMod;
598
- const { SearchAddon: XSearchAddon } = searchMod;
599
- const { WebglAddon: XWebglAddon } = webglMod;
600
- if (cancelled || !containerRef.current) return;
601
- const wantsWebGL = useWebGLRendererRef.current;
602
- Promise.resolve({ });
603
- const terminal = new XTerm({
604
- // Opt in to addon-only APIs (decorations, markers, etc.) that
605
- // xterm.js 6.1-beta gates behind this flag. Without it, the search
606
- // addon's `findNext` throws "You must set the allowProposedApi
607
- // option to true to use proposed API" the first time the user
608
- // types in the find bar. The addons we ship (search, webgl) are
609
- // first-party xterm.js addons that depend on these APIs.
610
- allowProposedApi: true,
611
- cursorBlink: true,
612
- // Initial font size scales with the persisted app zoom level so the
613
- // terminal opens already matching the user's previously-set zoom — the
614
- // subscription below keeps it in sync as zoom changes at runtime. See
615
- // BASE_FONT_SIZE above for the rationale (xterm lives in counter-zoom).
616
- fontSize: BASE_FONT_SIZE * getCurrentZoomLevel(),
617
- fontFamily: "'SF Mono', Menlo, Monaco, 'Courier New', monospace",
618
- // iTerm-style row spacing — only safe with the WebGL renderer.
619
- // The WebGL addon redraws box-drawing (U+2500-U+257F), block
620
- // elements (U+2580-U+259F), powerline separators, and other
621
- // continuous glyphs at the full cell rect (via its `customGlyphs`
622
- // option, default true) so a 1.2 lineHeight doesn't slice horizontal
623
- // gaps through the opencode banner, claude-code's powerline
624
- // statusline, or other ASCII art. xterm.js's DOM renderer does
625
- // NOT do this — falling back to it means we have to revert to
626
- // lineHeight: 1.0 to keep block art continuous.
627
- // See https://github.com/band-app/band/issues/391 for history.
628
- lineHeight: wantsWebGL ? 1.2 : 1,
629
- macOptionIsMeta: true,
630
- // Alt+Left/Right → word navigation on macOS
631
- scrollback: 1e4,
632
- theme: getTerminalTheme()
633
- });
634
- const themeObserver = new MutationObserver(() => {
635
- terminal.options.theme = getTerminalTheme();
636
- });
637
- themeObserver.observe(document.documentElement, {
638
- attributes: true,
639
- attributeFilter: ["class"]
640
- });
641
- const fitAddon = new XFitAddon();
642
- terminal.loadAddon(fitAddon);
643
- terminal.loadAddon(new XWebLinksAddon((_event, uri) => openExternalUrl(uri)));
644
- const fileLinkProviderDisposable = terminal.registerLinkProvider(
645
- createTerminalFileLinkProvider(terminal, (filename) => {
646
- window.dispatchEvent(
647
- new CustomEvent("band:open-file", { detail: { filename, workspaceId } })
648
- );
649
- })
650
- );
651
- terminal.open(containerRef.current);
652
- let webglContextLossDisposable;
653
- const attachWebGL = () => {
654
- try {
655
- const addon = new XWebglAddon({ customGlyphs: true });
656
- terminal.loadAddon(addon);
657
- const screenEl = containerRef.current?.querySelector(
658
- ".xterm-screen"
659
- );
660
- const webglCanvas = screenEl?.querySelector(
661
- ":scope > canvas:last-of-type"
662
- );
663
- if (webglCanvas) {
664
- webglCanvas.style.pointerEvents = "none";
665
- webglCanvas.style.touchAction = "none";
666
- }
667
- webglAddonRef.current = addon;
668
- webglContextLossDisposable?.dispose();
669
- webglContextLossDisposable = addon.onContextLoss(() => {
670
- console.warn("[TerminalPanel] WebGL context lost, reattaching addon");
671
- addon.dispose();
672
- webglAddonRef.current = null;
673
- attachWebGL();
674
- });
675
- return true;
676
- } catch (err) {
677
- console.warn("[TerminalPanel] WebGL renderer unavailable, falling back to DOM", err);
678
- return false;
679
- }
680
- };
681
- if (wantsWebGL) attachWebGL();
682
- const searchAddon = new XSearchAddon();
683
- terminal.loadAddon(searchAddon);
684
- const searchResultsDisposable = searchAddon.onDidChangeResults((event) => {
685
- setMatchInfo({
686
- total: event.resultCount,
687
- current: event.resultIndex >= 0 ? event.resultIndex + 1 : 0
688
- });
689
- });
690
- terminal.attachCustomKeyEventHandler((e) => {
691
- if (e.type === "keydown") {
692
- if (pendingCtrlRef.current && e.key.length === 1 && !e.metaKey && !e.altKey && !e.ctrlKey) {
693
- const lower = e.key.toLowerCase();
694
- const code = lower.charCodeAt(0);
695
- if (code >= 97 && code <= 122) {
696
- terminal.input(String.fromCharCode(code - 96));
697
- pendingCtrlRef.current = false;
698
- setPendingCtrl(false);
699
- e.preventDefault();
700
- return false;
701
- }
702
- pendingCtrlRef.current = false;
703
- setPendingCtrl(false);
704
- }
705
- if ((e.metaKey || e.ctrlKey) && !e.shiftKey && !e.altKey && e.key.toLowerCase() === "f") {
706
- e.preventDefault();
707
- openSearchRef.current();
708
- return false;
709
- }
710
- if (e.key === "Enter" && e.shiftKey && !e.altKey && !e.metaKey && !e.ctrlKey) {
711
- e.preventDefault();
712
- terminal.input("\n");
713
- return false;
714
- }
715
- if (e.altKey && !e.metaKey && !e.ctrlKey) {
716
- if (e.key === "ArrowLeft") {
717
- terminal.input("\x1Bb");
718
- return false;
719
- }
720
- if (e.key === "ArrowRight") {
721
- terminal.input("\x1Bf");
722
- return false;
723
- }
724
- }
725
- }
726
- return true;
727
- });
728
- terminalRef.current = terminal;
729
- fitAddonRef.current = fitAddon;
730
- searchAddonRef.current = searchAddon;
731
- setTerminalReady(true);
732
- const containerEl = containerRef.current;
733
- let lastTouchY = null;
734
- const onTouchStart = (e) => {
735
- lastTouchY = e.touches.length === 1 ? e.touches[0].clientY : null;
736
- };
737
- const onTouchMove = (e) => {
738
- if (e.touches.length !== 1 || lastTouchY === null) return;
739
- const currentY = e.touches[0].clientY;
740
- const deltaY = lastTouchY - currentY;
741
- const viewport = containerEl.querySelector(".xterm-viewport");
742
- const cellHeight = viewport && terminal.rows > 0 ? viewport.clientHeight / terminal.rows : 17;
743
- const lineDelta = Math.trunc(deltaY / cellHeight);
744
- if (lineDelta !== 0) {
745
- terminal.scrollLines(lineDelta);
746
- lastTouchY = currentY + (deltaY - lineDelta * cellHeight);
747
- e.preventDefault();
748
- }
749
- };
750
- const onTouchEnd = () => {
751
- lastTouchY = null;
752
- };
753
- containerEl.addEventListener("touchstart", onTouchStart, { passive: true });
754
- containerEl.addEventListener("touchmove", onTouchMove, { passive: false });
755
- containerEl.addEventListener("touchend", onTouchEnd, { passive: true });
756
- containerEl.addEventListener("touchcancel", onTouchEnd, { passive: true });
757
- let longPressTimer = null;
758
- let longPressStart = null;
759
- const cancelLongPress = () => {
760
- if (longPressTimer !== null) {
761
- window.clearTimeout(longPressTimer);
762
- longPressTimer = null;
763
- }
764
- longPressStart = null;
765
- };
766
- const onLongPressStart = (e) => {
767
- cancelLongPress();
768
- if (e.touches.length !== 1) return;
769
- const t = e.touches[0];
770
- longPressStart = { x: t.clientX, y: t.clientY };
771
- longPressTimer = window.setTimeout(() => {
772
- longPressTimer = null;
773
- const start = longPressStart;
774
- if (!start) return;
775
- const screenEl = containerEl.querySelector(".xterm-screen");
776
- if (!screenEl) return;
777
- const cell = pointToCell(start.x, start.y, terminal, screenEl);
778
- const lineText = getLineText(terminal, cell.row);
779
- const { anchor, head } = wordSelectionAt(cell, lineText);
780
- applySelection(terminal, anchor, head);
781
- selectionAnchorRef.current = anchor;
782
- selectionHeadRef.current = head;
783
- setSelectionMode(true);
784
- tapStartX = null;
785
- tapStartY = null;
786
- terminal.blur();
787
- if (typeof navigator.vibrate === "function") {
788
- try {
789
- navigator.vibrate(15);
790
- } catch {
791
- }
792
- }
793
- }, LONG_PRESS_MS);
794
- };
795
- const onLongPressMove = (e) => {
796
- if (!longPressStart || e.touches.length !== 1) return;
797
- const t = e.touches[0];
798
- const dx = Math.abs(t.clientX - longPressStart.x);
799
- const dy = Math.abs(t.clientY - longPressStart.y);
800
- if (dx > LONG_PRESS_SLOP_PX || dy > LONG_PRESS_SLOP_PX) cancelLongPress();
801
- };
802
- containerEl.addEventListener("touchstart", onLongPressStart, { passive: true });
803
- containerEl.addEventListener("touchmove", onLongPressMove, { passive: true });
804
- containerEl.addEventListener("touchend", cancelLongPress, { passive: true });
805
- containerEl.addEventListener("touchcancel", cancelLongPress, { passive: true });
806
- let tapStartX = null;
807
- let tapStartY = null;
808
- const onTapStart = (e) => {
809
- if (e.touches.length === 1) {
810
- tapStartX = e.touches[0].clientX;
811
- tapStartY = e.touches[0].clientY;
812
- } else {
813
- tapStartX = null;
814
- tapStartY = null;
815
- }
816
- };
817
- const onTapEnd = (e) => {
818
- const startX = tapStartX;
819
- const startY = tapStartY;
820
- tapStartX = null;
821
- tapStartY = null;
822
- if (startX === null || startY === null || e.changedTouches.length !== 1) return;
823
- const dx = Math.abs(e.changedTouches[0].clientX - startX);
824
- const dy = Math.abs(e.changedTouches[0].clientY - startY);
825
- if (dx < 10 && dy < 10) {
826
- if (selectionAnchorRef.current !== null) {
827
- selectionAnchorRef.current = null;
828
- selectionHeadRef.current = null;
829
- setSelectionMode(false);
830
- terminal.clearSelection();
831
- }
832
- terminal.focus();
833
- }
834
- };
835
- const onTapCancel = () => {
836
- tapStartX = null;
837
- tapStartY = null;
838
- };
839
- containerEl.addEventListener("touchstart", onTapStart, { passive: true });
840
- containerEl.addEventListener("touchend", onTapEnd, { passive: true });
841
- containerEl.addEventListener("touchcancel", onTapCancel, { passive: true });
842
- const proto = location.protocol === "https:" ? "wss:" : "ws:";
843
- const wsUrl = `${proto}//${location.host}/terminal?workspaceId=${encodeURIComponent(workspaceId)}&terminalId=${encodeURIComponent(terminalId)}`;
844
- const HEARTBEAT_INTERVAL_MS = 1e4;
845
- const HEARTBEAT_TIMEOUT_MS = 2e4;
846
- const RECONNECT_BASE_MS = 500;
847
- const RECONNECT_MAX_MS = 1e4;
848
- let intentionalClose = false;
849
- let didConnectOnce = false;
850
- let reconnectAttempts = 0;
851
- let reconnectTimer = null;
852
- let heartbeatTimer = null;
853
- let lastPongAt = 0;
854
- const clearReconnectTimer = () => {
855
- if (reconnectTimer !== null) {
856
- clearTimeout(reconnectTimer);
857
- reconnectTimer = null;
858
- }
859
- };
860
- const stopHeartbeat = () => {
861
- if (heartbeatTimer !== null) {
862
- clearInterval(heartbeatTimer);
863
- heartbeatTimer = null;
864
- }
865
- };
866
- const probeConnection = () => {
867
- const ws = wsRef.current;
868
- if (!ws || ws.readyState !== WebSocket.OPEN) return;
869
- if (Date.now() - lastPongAt > HEARTBEAT_TIMEOUT_MS) {
870
- ws.close();
871
- return;
872
- }
873
- try {
874
- ws.send(JSON.stringify({ type: "ping" }));
875
- } catch {
876
- ws.close();
877
- }
878
- };
879
- const scheduleReconnect = () => {
880
- if (intentionalClose || reconnectTimer !== null) return;
881
- const delay = Math.min(RECONNECT_BASE_MS * 2 ** reconnectAttempts, RECONNECT_MAX_MS);
882
- if (delay < RECONNECT_MAX_MS) reconnectAttempts += 1;
883
- reconnectTimer = setTimeout(() => {
884
- reconnectTimer = null;
885
- connect();
886
- }, delay);
887
- };
888
- function connect() {
889
- if (intentionalClose) return;
890
- clearReconnectTimer();
891
- const isReconnect = didConnectOnce;
892
- const ws = new WebSocket(wsUrl);
893
- wsRef.current = ws;
894
- ws.binaryType = "arraybuffer";
895
- ws.onopen = () => {
896
- reconnectAttempts = 0;
897
- lastPongAt = Date.now();
898
- if (isReconnect) terminal.reset();
899
- if (!didConnectOnce && paneMetadata && (paneMetadata.command || paneMetadata.cwd || paneMetadata.env)) {
900
- const initMsg = { type: "init" };
901
- if (paneMetadata.command) initMsg.command = paneMetadata.command;
902
- if (paneMetadata.cwd) initMsg.cwd = paneMetadata.cwd;
903
- if (paneMetadata.env) initMsg.env = paneMetadata.env;
904
- ws.send(JSON.stringify(initMsg));
905
- }
906
- didConnectOnce = true;
907
- fitAddon.fit();
908
- ws.send(JSON.stringify({ type: "resize", cols: terminal.cols, rows: terminal.rows }));
909
- if (autoFocus && !isReconnect) terminal.focus();
910
- stopHeartbeat();
911
- heartbeatTimer = setInterval(probeConnection, HEARTBEAT_INTERVAL_MS);
912
- flushPendingInsertRef.current();
913
- };
914
- ws.onmessage = (event) => {
915
- if (event.data instanceof ArrayBuffer) {
916
- terminal.write(new Uint8Array(event.data));
917
- } else {
918
- try {
919
- const msg = JSON.parse(event.data);
920
- if (msg.type === "pong") {
921
- lastPongAt = Date.now();
922
- } else if (msg.type === "title" && typeof msg.title === "string") {
923
- onTitleChangeRef.current?.(msg.title);
924
- }
925
- } catch {
926
- terminal.write(event.data);
927
- }
928
- }
929
- };
930
- ws.onclose = () => {
931
- if (wsRef.current !== ws) return;
932
- stopHeartbeat();
933
- if (intentionalClose) return;
934
- terminal.write("\r\n\x1B[90m[Reconnecting…]\x1B[0m\r\n");
935
- scheduleReconnect();
936
- };
937
- }
938
- const handleResume = () => {
939
- if (intentionalClose) return;
940
- const ws = wsRef.current;
941
- if (!ws || ws.readyState === WebSocket.CLOSED || ws.readyState === WebSocket.CLOSING) {
942
- reconnectAttempts = 0;
943
- clearReconnectTimer();
944
- connect();
945
- } else if (ws.readyState === WebSocket.OPEN) {
946
- probeConnection();
947
- }
948
- };
949
- const handleVisibility = () => {
950
- if (!document.hidden) handleResume();
951
- };
952
- window.addEventListener("online", handleResume);
953
- document.addEventListener("visibilitychange", handleVisibility);
954
- connect();
955
- terminal.onData((data) => {
956
- const ws = wsRef.current;
957
- if (ws && ws.readyState === WebSocket.OPEN) {
958
- ws.send(data);
959
- }
960
- });
961
- terminal.onTitleChange((title) => {
962
- onTitleChangeRef.current?.(title);
963
- });
964
- let selectionRafId = null;
965
- const reapplySelectionOnNextFrame = () => {
966
- if (selectionRafId !== null) return;
967
- if (!selectionAnchorRef.current || !selectionHeadRef.current) return;
968
- selectionRafId = requestAnimationFrame(() => {
969
- selectionRafId = null;
970
- const anchor = selectionAnchorRef.current;
971
- const head = selectionHeadRef.current;
972
- if (anchor && head) applySelection(terminal, anchor, head);
973
- });
974
- };
975
- const selectionResizeDisposable = terminal.onResize(reapplySelectionOnNextFrame);
976
- let lastDpr = window.devicePixelRatio;
977
- const sendPtyResize = () => {
978
- const ws = wsRef.current;
979
- if (!ws || ws.readyState !== WebSocket.OPEN) return;
980
- if (terminal.cols <= 0 || terminal.rows <= 0) return;
981
- ws.send(
982
- JSON.stringify({
983
- type: "resize",
984
- cols: terminal.cols,
985
- rows: terminal.rows
986
- })
987
- );
988
- };
989
- const remeasureAndReattach = (opts = {}) => {
990
- const { newFontSize } = opts;
991
- if (newFontSize !== void 0) {
992
- if (terminal.options.fontSize !== newFontSize) {
993
- terminal.options.fontSize = newFontSize;
994
- }
995
- } else {
996
- const fs = terminal.options.fontSize;
997
- if (typeof fs === "number") {
998
- terminal.options.fontSize = fs + 1;
999
- terminal.options.fontSize = fs;
1000
- }
1001
- }
1002
- const addon = webglAddonRef.current;
1003
- if (addon) {
1004
- addon.dispose();
1005
- webglAddonRef.current = null;
1006
- attachWebGL();
1007
- }
1008
- fitAddon.fit();
1009
- };
1010
- remeasureAndReattachRef.current = () => remeasureAndReattach();
1011
- const handleDprChange = () => {
1012
- const currentDpr = window.devicePixelRatio;
1013
- if (currentDpr === lastDpr) return false;
1014
- lastDpr = currentDpr;
1015
- remeasureAndReattach();
1016
- return true;
1017
- };
1018
- const resizeObserver = new ResizeObserver((entries) => {
1019
- const entry = entries[0];
1020
- if (!entry || entry.contentRect.width === 0 || entry.contentRect.height === 0) return;
1021
- const dprChanged = handleDprChange();
1022
- if (!dprChanged) fitAddon.fit();
1023
- sendPtyResize();
1024
- });
1025
- resizeObserver.observe(containerRef.current);
1026
- const handleZoomChange = (zoom) => {
1027
- const target = Math.round(BASE_FONT_SIZE * zoom * 100) / 100;
1028
- if (terminal.options.fontSize === target) return;
1029
- remeasureAndReattach({ newFontSize: target });
1030
- sendPtyResize();
1031
- };
1032
- const unsubscribeZoom = subscribeToZoomChanges(handleZoomChange);
1033
- let dprMql;
1034
- const bindDprListener = () => {
1035
- dprMql = window.matchMedia(`(resolution: ${window.devicePixelRatio}dppx)`);
1036
- dprMql.addEventListener("change", onDprMediaChange);
1037
- };
1038
- const onDprMediaChange = () => {
1039
- handleDprChange();
1040
- dprMql?.removeEventListener("change", onDprMediaChange);
1041
- bindDprListener();
1042
- };
1043
- bindDprListener();
1044
- cleanup = () => {
1045
- intentionalClose = true;
1046
- clearReconnectTimer();
1047
- stopHeartbeat();
1048
- window.removeEventListener("online", handleResume);
1049
- document.removeEventListener("visibilitychange", handleVisibility);
1050
- themeObserver.disconnect();
1051
- resizeObserver.disconnect();
1052
- searchResultsDisposable.dispose();
1053
- selectionResizeDisposable.dispose();
1054
- fileLinkProviderDisposable.dispose();
1055
- if (selectionRafId !== null) cancelAnimationFrame(selectionRafId);
1056
- webglContextLossDisposable?.dispose();
1057
- dprMql?.removeEventListener("change", onDprMediaChange);
1058
- unsubscribeZoom();
1059
- cancelLongPress();
1060
- containerEl.removeEventListener("touchstart", onTouchStart);
1061
- containerEl.removeEventListener("touchmove", onTouchMove);
1062
- containerEl.removeEventListener("touchend", onTouchEnd);
1063
- containerEl.removeEventListener("touchcancel", onTouchEnd);
1064
- containerEl.removeEventListener("touchstart", onLongPressStart);
1065
- containerEl.removeEventListener("touchmove", onLongPressMove);
1066
- containerEl.removeEventListener("touchend", cancelLongPress);
1067
- containerEl.removeEventListener("touchcancel", cancelLongPress);
1068
- containerEl.removeEventListener("touchstart", onTapStart);
1069
- containerEl.removeEventListener("touchend", onTapEnd);
1070
- containerEl.removeEventListener("touchcancel", onTapCancel);
1071
- wsRef.current?.close();
1072
- terminal.dispose();
1073
- terminalRef.current = null;
1074
- fitAddonRef.current = null;
1075
- searchAddonRef.current = null;
1076
- webglAddonRef.current = null;
1077
- remeasureAndReattachRef.current = null;
1078
- wsRef.current = null;
1079
- selectionAnchorRef.current = null;
1080
- selectionHeadRef.current = null;
1081
- pendingCtrlRef.current = false;
1082
- setSelectionMode(false);
1083
- setPendingCtrl(false);
1084
- setTerminalReady(false);
1085
- };
1086
- });
1087
- return () => {
1088
- cancelled = true;
1089
- cleanup?.();
1090
- };
1091
- }, [terminalId, workspaceId, paneMetadata, autoFocus]);
1092
- reactExports.useEffect(() => {
1093
- if (!visible) return;
1094
- let rafId = 0;
1095
- const MAX_LAYOUT_FRAMES = 5;
1096
- const repair = (attempt) => {
1097
- const container = containerRef.current;
1098
- if (!container || container.clientWidth === 0 || container.clientHeight === 0) {
1099
- if (attempt < MAX_LAYOUT_FRAMES) {
1100
- rafId = requestAnimationFrame(() => repair(attempt + 1));
1101
- }
1102
- return;
1103
- }
1104
- const remeasure = remeasureAndReattachRef.current;
1105
- if (remeasure) {
1106
- remeasure();
1107
- } else {
1108
- fitAddonRef.current?.fit();
1109
- }
1110
- const term = terminalRef.current;
1111
- if (term && term.rows > 0) term.refresh(0, term.rows - 1);
1112
- const ws = wsRef.current;
1113
- if (term && ws?.readyState === WebSocket.OPEN && term.cols > 0 && term.rows > 0) {
1114
- ws.send(JSON.stringify({ type: "resize", cols: term.cols, rows: term.rows }));
1115
- }
1116
- };
1117
- rafId = requestAnimationFrame(() => repair(0));
1118
- return () => cancelAnimationFrame(rafId);
1119
- }, [visible]);
1120
- reactExports.useEffect(() => {
1121
- const handler = () => {
1122
- if (!visible) return;
1123
- terminalRef.current?.focus();
1124
- };
1125
- window.addEventListener("band:focus-terminal", handler);
1126
- return () => window.removeEventListener("band:focus-terminal", handler);
1127
- }, [visible]);
1128
- const pendingInsertRef = reactExports.useRef(null);
1129
- const flushPendingInsert = reactExports.useCallback(() => {
1130
- const reference = pendingInsertRef.current;
1131
- if (!reference) return;
1132
- const ws = wsRef.current;
1133
- if (ws?.readyState !== WebSocket.OPEN) return;
1134
- ws.send(reference);
1135
- pendingInsertRef.current = null;
1136
- terminalRef.current?.focus();
1137
- }, []);
1138
- flushPendingInsertRef.current = flushPendingInsert;
1139
- reactExports.useEffect(() => {
1140
- if (visible) {
1141
- flushPendingInsert();
1142
- } else {
1143
- pendingInsertRef.current = null;
1144
- }
1145
- }, [visible, flushPendingInsert]);
1146
- reactExports.useEffect(() => {
1147
- const handler = (e) => {
1148
- const detail = e.detail;
1149
- if (!detail?.reference || detail.workspaceId !== workspaceId) return;
1150
- if (detail.terminalId && detail.terminalId !== terminalId) return;
1151
- pendingInsertRef.current = detail.reference;
1152
- if (visible) flushPendingInsert();
1153
- };
1154
- window.addEventListener("band:terminal-insert", handler);
1155
- return () => window.removeEventListener("band:terminal-insert", handler);
1156
- }, [visible, workspaceId, terminalId, flushPendingInsert]);
1157
- const handleOpenSearch = reactExports.useCallback(() => {
1158
- setSearchOpen(true);
1159
- requestAnimationFrame(() => {
1160
- searchBarRef.current?.focus();
1161
- searchBarRef.current?.select();
1162
- });
1163
- }, []);
1164
- openSearchRef.current = handleOpenSearch;
1165
- const handleCloseSearch = reactExports.useCallback(() => {
1166
- searchAddonRef.current?.clearDecorations();
1167
- setSearchOpen(false);
1168
- setSearchQuery("");
1169
- setMatchInfo({ total: 0, current: 0 });
1170
- terminalRef.current?.focus();
1171
- }, []);
1172
- const handleNext = reactExports.useCallback(() => {
1173
- if (!searchQuery) return;
1174
- searchAddonRef.current?.findNext(searchQuery, toXtermSearchOptions(searchOptions));
1175
- }, [searchQuery, searchOptions]);
1176
- const handlePrevious = reactExports.useCallback(() => {
1177
- if (!searchQuery) return;
1178
- searchAddonRef.current?.findPrevious(searchQuery, toXtermSearchOptions(searchOptions));
1179
- }, [searchQuery, searchOptions]);
1180
- reactExports.useEffect(() => {
1181
- const addon = searchAddonRef.current;
1182
- if (!addon) return;
1183
- if (!searchQuery) {
1184
- addon.clearDecorations();
1185
- setMatchInfo({ total: 0, current: 0 });
1186
- return;
1187
- }
1188
- addon.findNext(searchQuery, toXtermSearchOptions(searchOptions));
1189
- }, [searchQuery, searchOptions]);
1190
- const { contentBottomInset } = useVirtualKeyboardToolbar();
1191
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative flex h-full w-full flex-col", children: [
1192
- searchOpen && /* @__PURE__ */ jsxRuntimeExports.jsx(
1193
- SearchBar,
1194
- {
1195
- ref: searchBarRef,
1196
- query: searchQuery,
1197
- onQueryChange: setSearchQuery,
1198
- options: searchOptions,
1199
- onOptionsChange: setSearchOptions,
1200
- placeholder: "Find in terminal...",
1201
- matchInfo,
1202
- onNext: handleNext,
1203
- onPrevious: handlePrevious,
1204
- onClose: handleCloseSearch
1205
- }
1206
- ),
1207
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "relative min-h-0 flex-1", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
1208
- "div",
1209
- {
1210
- ref: containerRef,
1211
- className: "absolute inset-x-2 top-2 overflow-hidden",
1212
- style: {
1213
- bottom: 8 + contentBottomInset,
1214
- zoom: `calc(1 / var(${ZOOM_CSS_VAR}, 1))`
1215
- }
1216
- }
1217
- ) }),
1218
- terminalReady && terminalRef.current && /* @__PURE__ */ jsxRuntimeExports.jsx(
1219
- TerminalToolbar,
1220
- {
1221
- terminal: terminalRef.current,
1222
- sendInput: (data) => {
1223
- const ws = wsRef.current;
1224
- if (ws?.readyState === WebSocket.OPEN) ws.send(data);
1225
- },
1226
- pendingCtrl,
1227
- onToggleCtrl: handleToggleCtrl,
1228
- selectionMode,
1229
- onExtendSelection: handleExtendSelection,
1230
- onExitSelection: exitSelectionMode,
1231
- onSelectAll: handleSelectAll
1232
- }
1233
- )
1234
- ] });
1235
- }
1236
- export {
1237
- TerminalPanel
1238
- };