termdock 1.4.322 → 1.4.325

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 (366) hide show
  1. package/dist/client/assets/App-D8MWr9xp.js +186 -0
  2. package/dist/client/assets/App-D8MWr9xp.js.br +0 -0
  3. package/dist/client/assets/App-D8MWr9xp.js.gz +0 -0
  4. package/dist/client/assets/{ArchitecturePanel-VDM6hrwp.js → ArchitecturePanel-CJXvqmtu.js} +2 -2
  5. package/dist/client/assets/ArchitecturePanel-CJXvqmtu.js.br +0 -0
  6. package/dist/client/assets/ArchitecturePanel-CJXvqmtu.js.gz +0 -0
  7. package/dist/client/assets/{ChangeWalkthroughPanel-B64j3i8o.js → ChangeWalkthroughPanel-ChPZVfRz.js} +1 -1
  8. package/dist/client/assets/ChangeWalkthroughPanel-ChPZVfRz.js.br +0 -0
  9. package/dist/client/assets/ChangeWalkthroughPanel-ChPZVfRz.js.gz +0 -0
  10. package/dist/client/assets/CollaborationMainWorkspace-DkNhqCj4.js +1 -0
  11. package/dist/client/assets/CollaborationMainWorkspace-DkNhqCj4.js.br +0 -0
  12. package/dist/client/assets/CollaborationMainWorkspace-DkNhqCj4.js.gz +0 -0
  13. package/dist/client/assets/CollaborationTaskContent-BA3bVNJo.js +2 -0
  14. package/dist/client/assets/{ComputerControlView-Co-TTYas.js → ComputerControlView-BTntDI6C.js} +2 -2
  15. package/dist/client/assets/ComputerControlView-BTntDI6C.js.br +0 -0
  16. package/dist/client/assets/ComputerControlView-BTntDI6C.js.gz +0 -0
  17. package/dist/client/assets/{DagPlayground-kJczdJ6J.js → DagPlayground-BIL5vjer.js} +1 -1
  18. package/dist/client/assets/DagPlayground-BIL5vjer.js.br +0 -0
  19. package/dist/client/assets/DagPlayground-BIL5vjer.js.gz +0 -0
  20. package/dist/client/assets/{DiffLab-BaaioC-q.js → DiffLab-CX1AwU2v.js} +1 -1
  21. package/dist/client/assets/DiffLab-CX1AwU2v.js.br +0 -0
  22. package/dist/client/assets/DiffLab-CX1AwU2v.js.gz +0 -0
  23. package/dist/client/assets/{DiffReview-Wfck3RIS.js → DiffReview-CLc1hwO7.js} +1 -1
  24. package/dist/client/assets/DiffReview-CLc1hwO7.js.br +0 -0
  25. package/dist/client/assets/DiffReview-CLc1hwO7.js.gz +0 -0
  26. package/dist/client/assets/{DiffReviewLab-Dblr3wgw.js → DiffReviewLab-DE6m1o4p.js} +1 -1
  27. package/dist/client/assets/DiffReviewLab-DE6m1o4p.js.br +0 -0
  28. package/dist/client/assets/DiffReviewLab-DE6m1o4p.js.gz +0 -0
  29. package/dist/client/assets/{DiffViewer-C-utC5Ga.js → DiffViewer-BDwtwbQM.js} +1 -1
  30. package/dist/client/assets/DiffViewer-BDwtwbQM.js.br +0 -0
  31. package/dist/client/assets/DiffViewer-BDwtwbQM.js.gz +0 -0
  32. package/dist/client/assets/{ModelPreview-BBLnHWVQ.js → ModelPreview-DEwATnxi.js} +1 -1
  33. package/dist/client/assets/ModelPreview-DEwATnxi.js.br +0 -0
  34. package/dist/client/assets/ModelPreview-DEwATnxi.js.gz +0 -0
  35. package/dist/client/assets/{RightSidebar-CUHSFkmZ.js → RightSidebar-jOQJePDV.js} +36 -36
  36. package/dist/client/assets/RightSidebar-jOQJePDV.js.br +0 -0
  37. package/dist/client/assets/RightSidebar-jOQJePDV.js.gz +0 -0
  38. package/dist/client/assets/{abnfDiagram-VCTEODGH-DDd99QpA.js → abnfDiagram-VCTEODGH-GBSf8AEr.js} +1 -1
  39. package/dist/client/assets/abnfDiagram-VCTEODGH-GBSf8AEr.js.br +0 -0
  40. package/dist/client/assets/abnfDiagram-VCTEODGH-GBSf8AEr.js.gz +0 -0
  41. package/dist/client/assets/app-VCmiASzh.js +35 -0
  42. package/dist/client/assets/app-VCmiASzh.js.br +0 -0
  43. package/dist/client/assets/app-VCmiASzh.js.gz +0 -0
  44. package/dist/client/assets/{arc-C3dck_E0.js → arc-BecvFgjf.js} +1 -1
  45. package/dist/client/assets/arc-BecvFgjf.js.br +0 -0
  46. package/dist/client/assets/arc-BecvFgjf.js.gz +0 -0
  47. package/dist/client/assets/{architectureDiagram-5GKGNRK7-C3bCQc2w.js → architectureDiagram-5GKGNRK7-Cfk47zEF.js} +1 -1
  48. package/dist/client/assets/architectureDiagram-5GKGNRK7-Cfk47zEF.js.br +0 -0
  49. package/dist/client/assets/architectureDiagram-5GKGNRK7-Cfk47zEF.js.gz +0 -0
  50. package/dist/client/assets/{blockDiagram-I7D4REHJ-znMn6iCQ.js → blockDiagram-I7D4REHJ-BHYgsLvx.js} +1 -1
  51. package/dist/client/assets/blockDiagram-I7D4REHJ-BHYgsLvx.js.br +0 -0
  52. package/dist/client/assets/blockDiagram-I7D4REHJ-BHYgsLvx.js.gz +0 -0
  53. package/dist/client/assets/{c4Diagram-7LVT6UL2-C0sopIsj.js → c4Diagram-7LVT6UL2-ClWWjTyz.js} +1 -1
  54. package/dist/client/assets/c4Diagram-7LVT6UL2-ClWWjTyz.js.br +0 -0
  55. package/dist/client/assets/c4Diagram-7LVT6UL2-ClWWjTyz.js.gz +0 -0
  56. package/dist/client/assets/channel-8F8qxLSK.js +1 -0
  57. package/dist/client/assets/{chunk-2Q5K7J3B-f7USyccJ.js → chunk-2Q5K7J3B-Cat1Dsqx.js} +1 -1
  58. package/dist/client/assets/{chunk-5VM5RSS4-Ck2xirDs.js → chunk-5VM5RSS4-CT0S2-E8.js} +1 -1
  59. package/dist/client/assets/{chunk-F27PBJKO-DaDCIj30.js → chunk-F27PBJKO-7o5_yA1b.js} +1 -1
  60. package/dist/client/assets/chunk-F27PBJKO-7o5_yA1b.js.br +0 -0
  61. package/dist/client/assets/chunk-F27PBJKO-7o5_yA1b.js.gz +0 -0
  62. package/dist/client/assets/{chunk-IMKFNOWR-DEC_On5x.js → chunk-IMKFNOWR-iAZxGMup.js} +1 -1
  63. package/dist/client/assets/chunk-IMKFNOWR-iAZxGMup.js.br +0 -0
  64. package/dist/client/assets/chunk-IMKFNOWR-iAZxGMup.js.gz +0 -0
  65. package/dist/client/assets/{chunk-JWPE2WC7-BrswC3n2.js → chunk-JWPE2WC7-DLvwOWZm.js} +1 -1
  66. package/dist/client/assets/{chunk-POPQ4Y6H-ClMbDV47.js → chunk-POPQ4Y6H-BpiRuG56.js} +1 -1
  67. package/dist/client/assets/{chunk-SVP7TREG-D7_1VwC5.js → chunk-SVP7TREG-DpB7xpqI.js} +1 -1
  68. package/dist/client/assets/chunk-SVP7TREG-DpB7xpqI.js.br +0 -0
  69. package/dist/client/assets/chunk-SVP7TREG-DpB7xpqI.js.gz +0 -0
  70. package/dist/client/assets/{chunk-TICWLB2K-D5jzVTZ8.js → chunk-TICWLB2K-Z_Sti6yX.js} +1 -1
  71. package/dist/client/assets/chunk-TICWLB2K-Z_Sti6yX.js.br +0 -0
  72. package/dist/client/assets/chunk-TICWLB2K-Z_Sti6yX.js.gz +0 -0
  73. package/dist/client/assets/{chunk-XXDRQBXY-DOhaoLcX.js → chunk-XXDRQBXY-DKngx1rf.js} +1 -1
  74. package/dist/client/assets/classDiagram-ZZMXUADV-C0AmKz7U.js +1 -0
  75. package/dist/client/assets/classDiagram-v2-VYDZK3BY-C0AmKz7U.js +1 -0
  76. package/dist/client/assets/{cose-bilkent-JH36ORCC-DOsaKgiX.js → cose-bilkent-JH36ORCC-CDo8eUXo.js} +1 -1
  77. package/dist/client/assets/cose-bilkent-JH36ORCC-CDo8eUXo.js.br +0 -0
  78. package/dist/client/assets/cose-bilkent-JH36ORCC-CDo8eUXo.js.gz +0 -0
  79. package/dist/client/assets/{cynefin-OW5HDTMX-CMcLh_wh.js → cynefin-OW5HDTMX-R6vltrl4.js} +1 -1
  80. package/dist/client/assets/cynefin-OW5HDTMX-R6vltrl4.js.br +0 -0
  81. package/dist/client/assets/{cynefin-OW5HDTMX-CMcLh_wh.js.gz → cynefin-OW5HDTMX-R6vltrl4.js.gz} +0 -0
  82. package/dist/client/assets/{cynefinDiagram-5FMLGOSQ-Dd8bfq9V.js → cynefinDiagram-5FMLGOSQ-BTGMG-zO.js} +1 -1
  83. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-BTGMG-zO.js.br +0 -0
  84. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-BTGMG-zO.js.gz +0 -0
  85. package/dist/client/assets/{dagre-GXQ25YYZ-BlW7fAi0.js → dagre-GXQ25YYZ-D67dNSHU.js} +1 -1
  86. package/dist/client/assets/dagre-GXQ25YYZ-D67dNSHU.js.br +0 -0
  87. package/dist/client/assets/dagre-GXQ25YYZ-D67dNSHU.js.gz +0 -0
  88. package/dist/client/assets/{diagram-S7CK7UJ4-B0-tKahG.js → diagram-S7CK7UJ4-CxZmcHs4.js} +1 -1
  89. package/dist/client/assets/diagram-S7CK7UJ4-CxZmcHs4.js.br +0 -0
  90. package/dist/client/assets/diagram-S7CK7UJ4-CxZmcHs4.js.gz +0 -0
  91. package/dist/client/assets/{diagram-UQ7AKVKN-BQumj4Dw.js → diagram-UQ7AKVKN-BErivsDz.js} +1 -1
  92. package/dist/client/assets/diagram-UQ7AKVKN-BErivsDz.js.br +0 -0
  93. package/dist/client/assets/diagram-UQ7AKVKN-BErivsDz.js.gz +0 -0
  94. package/dist/client/assets/{diagram-VSXAHHWV-Zx_FLmPP.js → diagram-VSXAHHWV-BQWEvK9d.js} +1 -1
  95. package/dist/client/assets/diagram-VSXAHHWV-BQWEvK9d.js.br +0 -0
  96. package/dist/client/assets/diagram-VSXAHHWV-BQWEvK9d.js.gz +0 -0
  97. package/dist/client/assets/{diagram-VX7I27RA-CEZvatNH.js → diagram-VX7I27RA-COR5k4JL.js} +1 -1
  98. package/dist/client/assets/diagram-VX7I27RA-COR5k4JL.js.br +0 -0
  99. package/dist/client/assets/diagram-VX7I27RA-COR5k4JL.js.gz +0 -0
  100. package/dist/client/assets/{diagram-Z3DM3KII-CJ9IEQ8j.js → diagram-Z3DM3KII-Cx6oTlVi.js} +1 -1
  101. package/dist/client/assets/diagram-Z3DM3KII-Cx6oTlVi.js.br +0 -0
  102. package/dist/client/assets/diagram-Z3DM3KII-Cx6oTlVi.js.gz +0 -0
  103. package/dist/client/assets/{ebnfDiagram-PWID7BFC-sQQMv3ea.js → ebnfDiagram-PWID7BFC-dKNZki9k.js} +1 -1
  104. package/dist/client/assets/ebnfDiagram-PWID7BFC-dKNZki9k.js.br +0 -0
  105. package/dist/client/assets/ebnfDiagram-PWID7BFC-dKNZki9k.js.gz +0 -0
  106. package/dist/client/assets/{erDiagram-RLTQ6QDP-D3rMpj7M.js → erDiagram-RLTQ6QDP-DD06d9Gl.js} +1 -1
  107. package/dist/client/assets/erDiagram-RLTQ6QDP-DD06d9Gl.js.br +0 -0
  108. package/dist/client/assets/erDiagram-RLTQ6QDP-DD06d9Gl.js.gz +0 -0
  109. package/dist/client/assets/{flowDiagram-HODETNUW-B6QZiE0-.js → flowDiagram-HODETNUW-DXNAvw1d.js} +1 -1
  110. package/dist/client/assets/flowDiagram-HODETNUW-DXNAvw1d.js.br +0 -0
  111. package/dist/client/assets/flowDiagram-HODETNUW-DXNAvw1d.js.gz +0 -0
  112. package/dist/client/assets/{ganttDiagram-EL5Y4UJY-Bw9bltcu.js → ganttDiagram-EL5Y4UJY-BSMu3Rsd.js} +1 -1
  113. package/dist/client/assets/ganttDiagram-EL5Y4UJY-BSMu3Rsd.js.br +0 -0
  114. package/dist/client/assets/ganttDiagram-EL5Y4UJY-BSMu3Rsd.js.gz +0 -0
  115. package/dist/client/assets/{gestureArbiter-Cczz34oI.js → gestureArbiter-D1TteC76.js} +1 -1
  116. package/dist/client/assets/gestureArbiter-D1TteC76.js.br +0 -0
  117. package/dist/client/assets/gestureArbiter-D1TteC76.js.gz +0 -0
  118. package/dist/client/assets/{gitGraphDiagram-WWUBYQGX-mdnkxjeD.js → gitGraphDiagram-WWUBYQGX-DNDKI803.js} +1 -1
  119. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-DNDKI803.js.br +0 -0
  120. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-DNDKI803.js.gz +0 -0
  121. package/dist/client/assets/index-Ctz-IDjR.css +1 -0
  122. package/dist/client/assets/index-Ctz-IDjR.css.br +0 -0
  123. package/dist/client/assets/{index-B4bEMUyn.css.gz → index-Ctz-IDjR.css.gz} +0 -0
  124. package/dist/client/assets/{infoDiagram-27XIBGKW-DyrPP3Yf.js → infoDiagram-27XIBGKW-BRmB1D5B.js} +1 -1
  125. package/dist/client/assets/{ishikawaDiagram-5VMMS53U-CEPH_ePM.js → ishikawaDiagram-5VMMS53U-DXU4nnZ6.js} +1 -1
  126. package/dist/client/assets/ishikawaDiagram-5VMMS53U-DXU4nnZ6.js.br +0 -0
  127. package/dist/client/assets/ishikawaDiagram-5VMMS53U-DXU4nnZ6.js.gz +0 -0
  128. package/dist/client/assets/{journeyDiagram-3NMN7TZE-CQ0PjBy7.js → journeyDiagram-3NMN7TZE-DFx7AfiP.js} +1 -1
  129. package/dist/client/assets/journeyDiagram-3NMN7TZE-DFx7AfiP.js.br +0 -0
  130. package/dist/client/assets/journeyDiagram-3NMN7TZE-DFx7AfiP.js.gz +0 -0
  131. package/dist/client/assets/{kanban-definition-UXKFOSKX-BpQUXA60.js → kanban-definition-UXKFOSKX-B1ikfXJe.js} +1 -1
  132. package/dist/client/assets/kanban-definition-UXKFOSKX-B1ikfXJe.js.br +0 -0
  133. package/dist/client/assets/kanban-definition-UXKFOSKX-B1ikfXJe.js.gz +0 -0
  134. package/dist/client/assets/{layout-BdptC7rq.js → layout-DkyvZr1Y.js} +1 -1
  135. package/dist/client/assets/layout-DkyvZr1Y.js.br +0 -0
  136. package/dist/client/assets/layout-DkyvZr1Y.js.gz +0 -0
  137. package/dist/client/assets/{linear-C2cSRCxu.js → linear-CECAbRuX.js} +1 -1
  138. package/dist/client/assets/linear-CECAbRuX.js.br +0 -0
  139. package/dist/client/assets/linear-CECAbRuX.js.gz +0 -0
  140. package/dist/client/assets/{mermaid.core-ClVMFyAU.js → mermaid.core-CYY7Wb75.js} +5 -5
  141. package/dist/client/assets/mermaid.core-CYY7Wb75.js.br +0 -0
  142. package/dist/client/assets/mermaid.core-CYY7Wb75.js.gz +0 -0
  143. package/dist/client/assets/{mindmap-definition-YA3MSWOX-D0AFCmsY.js → mindmap-definition-YA3MSWOX-CTs-Y3Lq.js} +1 -1
  144. package/dist/client/assets/mindmap-definition-YA3MSWOX-CTs-Y3Lq.js.br +0 -0
  145. package/dist/client/assets/mindmap-definition-YA3MSWOX-CTs-Y3Lq.js.gz +0 -0
  146. package/dist/client/assets/{passwordBootstrap-R2qlU2Pq.js → passwordBootstrap-CPNGDwv6.js} +1 -1
  147. package/dist/client/assets/passwordBootstrap-CPNGDwv6.js.br +0 -0
  148. package/dist/client/assets/passwordBootstrap-CPNGDwv6.js.gz +0 -0
  149. package/dist/client/assets/{pegDiagram-XKGWAZYB-BGAh0bwg.js → pegDiagram-XKGWAZYB-Y1oZrwtK.js} +1 -1
  150. package/dist/client/assets/pegDiagram-XKGWAZYB-Y1oZrwtK.js.br +0 -0
  151. package/dist/client/assets/pegDiagram-XKGWAZYB-Y1oZrwtK.js.gz +0 -0
  152. package/dist/client/assets/{pieDiagram-E7YTZNPT-CDOZUF44.js → pieDiagram-E7YTZNPT-DYSm5OxQ.js} +1 -1
  153. package/dist/client/assets/pieDiagram-E7YTZNPT-DYSm5OxQ.js.br +0 -0
  154. package/dist/client/assets/pieDiagram-E7YTZNPT-DYSm5OxQ.js.gz +0 -0
  155. package/dist/client/assets/{quadrantDiagram-AXDQQJYC-D_Qn6NTU.js → quadrantDiagram-AXDQQJYC-DpibIBz0.js} +1 -1
  156. package/dist/client/assets/quadrantDiagram-AXDQQJYC-DpibIBz0.js.br +0 -0
  157. package/dist/client/assets/quadrantDiagram-AXDQQJYC-DpibIBz0.js.gz +0 -0
  158. package/dist/client/assets/{railroadDiagram-O6MQD6OU-qUVGWhJN.js → railroadDiagram-O6MQD6OU-b7jp7C1K.js} +1 -1
  159. package/dist/client/assets/railroadDiagram-O6MQD6OU-b7jp7C1K.js.br +0 -0
  160. package/dist/client/assets/railroadDiagram-O6MQD6OU-b7jp7C1K.js.gz +0 -0
  161. package/dist/client/assets/{rdpSession-hgCM4i-j.js → rdpSession-DU_OJfX5.js} +1 -1
  162. package/dist/client/assets/rdpSession-DU_OJfX5.js.br +0 -0
  163. package/dist/client/assets/rdpSession-DU_OJfX5.js.gz +0 -0
  164. package/dist/client/assets/{referenceLongPress-BEMsP11a.js → referenceLongPress-BPQ_i68g.js} +1 -1
  165. package/dist/client/assets/referenceLongPress-BPQ_i68g.js.br +0 -0
  166. package/dist/client/assets/referenceLongPress-BPQ_i68g.js.gz +0 -0
  167. package/dist/client/assets/{requirementDiagram-BXWQKSXE-BBQMQuVZ.js → requirementDiagram-BXWQKSXE-BMinO1mf.js} +1 -1
  168. package/dist/client/assets/requirementDiagram-BXWQKSXE-BMinO1mf.js.br +0 -0
  169. package/dist/client/assets/requirementDiagram-BXWQKSXE-BMinO1mf.js.gz +0 -0
  170. package/dist/client/assets/{sankeyDiagram-P5KCCOFB-CeEExsqW.js → sankeyDiagram-P5KCCOFB-CmC977VA.js} +1 -1
  171. package/dist/client/assets/sankeyDiagram-P5KCCOFB-CmC977VA.js.br +0 -0
  172. package/dist/client/assets/sankeyDiagram-P5KCCOFB-CmC977VA.js.gz +0 -0
  173. package/dist/client/assets/{sequenceDiagram-WJ2MYXX4-7ZPO-X0a.js → sequenceDiagram-WJ2MYXX4-D6eGbgK8.js} +1 -1
  174. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-D6eGbgK8.js.br +0 -0
  175. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-D6eGbgK8.js.gz +0 -0
  176. package/dist/client/assets/{sizeCapture-INFHLROL-MBjz7Snm.js → sizeCapture-INFHLROL-CnRvyBd8.js} +1 -1
  177. package/dist/client/assets/sizeCapture-INFHLROL-CnRvyBd8.js.br +0 -0
  178. package/dist/client/assets/sizeCapture-INFHLROL-CnRvyBd8.js.gz +0 -0
  179. package/dist/client/assets/{sparkles-C9ShmGPf.js → sparkles-DzadqrlX.js} +1 -1
  180. package/dist/client/assets/{stateDiagram-D77RDMKH-DtLp89uP.js → stateDiagram-D77RDMKH-DRSalH10.js} +1 -1
  181. package/dist/client/assets/stateDiagram-D77RDMKH-DRSalH10.js.br +0 -0
  182. package/dist/client/assets/stateDiagram-D77RDMKH-DRSalH10.js.gz +0 -0
  183. package/dist/client/assets/stateDiagram-v2-MP3YSRHH-DKe8v_ic.js +1 -0
  184. package/dist/client/assets/{swimlanes-42K2YHIH-Bc02S1q-.js → swimlanes-42K2YHIH-u-NnDSzq.js} +1 -1
  185. package/dist/client/assets/swimlanes-42K2YHIH-u-NnDSzq.js.br +0 -0
  186. package/dist/client/assets/swimlanes-42K2YHIH-u-NnDSzq.js.gz +0 -0
  187. package/dist/client/assets/swimlanesDiagram-VR7AAH4N-ei5b8ZYx.js +8 -0
  188. package/dist/client/assets/{timeline-definition-24CTP7MA-BLLwbOm5.js → timeline-definition-24CTP7MA-DkLijg_J.js} +1 -1
  189. package/dist/client/assets/timeline-definition-24CTP7MA-DkLijg_J.js.br +0 -0
  190. package/dist/client/assets/timeline-definition-24CTP7MA-DkLijg_J.js.gz +0 -0
  191. package/dist/client/assets/{triangle-alert-i_L8ws6U.js → triangle-alert-D_6xTTiX.js} +1 -1
  192. package/dist/client/assets/{vennDiagram-4TSXK5OY-8FcrAdbk.js → vennDiagram-4TSXK5OY-AWGJtiv3.js} +1 -1
  193. package/dist/client/assets/{vennDiagram-4TSXK5OY-8FcrAdbk.js.br → vennDiagram-4TSXK5OY-AWGJtiv3.js.br} +0 -0
  194. package/dist/client/assets/vennDiagram-4TSXK5OY-AWGJtiv3.js.gz +0 -0
  195. package/dist/client/assets/{videoCompression-RIaDabW4.js → videoCompression-D3y7Bq8J.js} +1 -1
  196. package/dist/client/assets/videoCompression-D3y7Bq8J.js.br +0 -0
  197. package/dist/client/assets/videoCompression-D3y7Bq8J.js.gz +0 -0
  198. package/dist/client/assets/{wardleyDiagram-VM6X3IG4-paL2wRrJ.js → wardleyDiagram-VM6X3IG4-DI0aZr_y.js} +1 -1
  199. package/dist/client/assets/wardleyDiagram-VM6X3IG4-DI0aZr_y.js.br +0 -0
  200. package/dist/client/assets/wardleyDiagram-VM6X3IG4-DI0aZr_y.js.gz +0 -0
  201. package/dist/client/assets/{xychartDiagram-S5SC5T6Z-BM5qJ4E7.js → xychartDiagram-S5SC5T6Z-CCoIN3uU.js} +1 -1
  202. package/dist/client/assets/xychartDiagram-S5SC5T6Z-CCoIN3uU.js.br +0 -0
  203. package/dist/client/assets/xychartDiagram-S5SC5T6Z-CCoIN3uU.js.gz +0 -0
  204. package/dist/client/index.html +2 -2
  205. package/dist/client/index.html.br +0 -0
  206. package/dist/client/index.html.gz +0 -0
  207. package/dist/client/sw-encrypted-background.js +1 -1
  208. package/dist/client/sw-encrypted-background.js.br +0 -0
  209. package/dist/client/sw-encrypted-background.js.gz +0 -0
  210. package/dist/client/sw.js +1 -1
  211. package/dist/client/sw.js.br +0 -0
  212. package/dist/client/sw.js.gz +0 -0
  213. package/dist/server/agent/collaborationGroupRoutes.js +15 -0
  214. package/dist/server/agent/collaborationStore.js +63 -2
  215. package/dist/server/agent/collaborationTaskRoutes.js +5 -1
  216. package/dist/server/agent/integrationCli.js +38 -20
  217. package/dist/server/agent/integrationServer.js +145 -3
  218. package/dist/server/federation/packets.js +179 -28
  219. package/dist/server/federation/requestContext.js +6 -1
  220. package/dist/server/federation/runtime.js +19 -8
  221. package/dist/server/routes/terminal.js +285 -85
  222. package/dist/server/utils/autoUpdate.js +55 -8
  223. package/dist/server/utils/hostResources.js +128 -0
  224. package/dist/server/utils/npmUpdate.js +84 -8
  225. package/dist/server/utils/terminalPasteBuffer.js +66 -0
  226. package/dist/server/utils/tmuxClientCapabilities.js +4 -0
  227. package/dist/server/utils/tmuxCopySelection.js +94 -0
  228. package/dist/server/utils/tmuxEmptyServerProbe.js +15 -0
  229. package/dist/server/utils/tmuxRecoveryOperations.js +348 -0
  230. package/docs/integrations.md +36 -0
  231. package/package.json +5 -2
  232. package/runtime-manifest.json +3 -3
  233. package/.desktop-dist/main.js +0 -1989
  234. package/dist/client/assets/App-DEKo4SNL.js +0 -186
  235. package/dist/client/assets/App-DEKo4SNL.js.br +0 -0
  236. package/dist/client/assets/App-DEKo4SNL.js.gz +0 -0
  237. package/dist/client/assets/ArchitecturePanel-VDM6hrwp.js.br +0 -0
  238. package/dist/client/assets/ArchitecturePanel-VDM6hrwp.js.gz +0 -0
  239. package/dist/client/assets/ChangeWalkthroughPanel-B64j3i8o.js.br +0 -0
  240. package/dist/client/assets/ChangeWalkthroughPanel-B64j3i8o.js.gz +0 -0
  241. package/dist/client/assets/CollaborationMainWorkspace-DG8TQNqo.js +0 -1
  242. package/dist/client/assets/CollaborationMainWorkspace-DG8TQNqo.js.br +0 -0
  243. package/dist/client/assets/CollaborationMainWorkspace-DG8TQNqo.js.gz +0 -0
  244. package/dist/client/assets/CollaborationTaskContent-msQsgVaI.js +0 -2
  245. package/dist/client/assets/ComputerControlView-Co-TTYas.js.br +0 -0
  246. package/dist/client/assets/ComputerControlView-Co-TTYas.js.gz +0 -0
  247. package/dist/client/assets/DagPlayground-kJczdJ6J.js.br +0 -0
  248. package/dist/client/assets/DagPlayground-kJczdJ6J.js.gz +0 -0
  249. package/dist/client/assets/DiffLab-BaaioC-q.js.br +0 -0
  250. package/dist/client/assets/DiffLab-BaaioC-q.js.gz +0 -0
  251. package/dist/client/assets/DiffReview-Wfck3RIS.js.br +0 -0
  252. package/dist/client/assets/DiffReview-Wfck3RIS.js.gz +0 -0
  253. package/dist/client/assets/DiffReviewLab-Dblr3wgw.js.br +0 -0
  254. package/dist/client/assets/DiffReviewLab-Dblr3wgw.js.gz +0 -0
  255. package/dist/client/assets/DiffViewer-C-utC5Ga.js.br +0 -0
  256. package/dist/client/assets/DiffViewer-C-utC5Ga.js.gz +0 -0
  257. package/dist/client/assets/ModelPreview-BBLnHWVQ.js.br +0 -0
  258. package/dist/client/assets/ModelPreview-BBLnHWVQ.js.gz +0 -0
  259. package/dist/client/assets/RightSidebar-CUHSFkmZ.js.br +0 -0
  260. package/dist/client/assets/RightSidebar-CUHSFkmZ.js.gz +0 -0
  261. package/dist/client/assets/abnfDiagram-VCTEODGH-DDd99QpA.js.br +0 -0
  262. package/dist/client/assets/abnfDiagram-VCTEODGH-DDd99QpA.js.gz +0 -0
  263. package/dist/client/assets/app-CfqF7_nh.js +0 -35
  264. package/dist/client/assets/app-CfqF7_nh.js.br +0 -0
  265. package/dist/client/assets/app-CfqF7_nh.js.gz +0 -0
  266. package/dist/client/assets/arc-C3dck_E0.js.br +0 -0
  267. package/dist/client/assets/arc-C3dck_E0.js.gz +0 -0
  268. package/dist/client/assets/architectureDiagram-5GKGNRK7-C3bCQc2w.js.br +0 -0
  269. package/dist/client/assets/architectureDiagram-5GKGNRK7-C3bCQc2w.js.gz +0 -0
  270. package/dist/client/assets/blockDiagram-I7D4REHJ-znMn6iCQ.js.br +0 -0
  271. package/dist/client/assets/blockDiagram-I7D4REHJ-znMn6iCQ.js.gz +0 -0
  272. package/dist/client/assets/c4Diagram-7LVT6UL2-C0sopIsj.js.br +0 -0
  273. package/dist/client/assets/c4Diagram-7LVT6UL2-C0sopIsj.js.gz +0 -0
  274. package/dist/client/assets/channel-CMC8t83j.js +0 -1
  275. package/dist/client/assets/chunk-F27PBJKO-DaDCIj30.js.br +0 -0
  276. package/dist/client/assets/chunk-F27PBJKO-DaDCIj30.js.gz +0 -0
  277. package/dist/client/assets/chunk-IMKFNOWR-DEC_On5x.js.br +0 -0
  278. package/dist/client/assets/chunk-IMKFNOWR-DEC_On5x.js.gz +0 -0
  279. package/dist/client/assets/chunk-SVP7TREG-D7_1VwC5.js.br +0 -0
  280. package/dist/client/assets/chunk-SVP7TREG-D7_1VwC5.js.gz +0 -0
  281. package/dist/client/assets/chunk-TICWLB2K-D5jzVTZ8.js.br +0 -0
  282. package/dist/client/assets/chunk-TICWLB2K-D5jzVTZ8.js.gz +0 -0
  283. package/dist/client/assets/classDiagram-ZZMXUADV-ElMHzA-E.js +0 -1
  284. package/dist/client/assets/classDiagram-v2-VYDZK3BY-ElMHzA-E.js +0 -1
  285. package/dist/client/assets/cose-bilkent-JH36ORCC-DOsaKgiX.js.br +0 -0
  286. package/dist/client/assets/cose-bilkent-JH36ORCC-DOsaKgiX.js.gz +0 -0
  287. package/dist/client/assets/cynefin-OW5HDTMX-CMcLh_wh.js.br +0 -0
  288. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-Dd8bfq9V.js.br +0 -0
  289. package/dist/client/assets/cynefinDiagram-5FMLGOSQ-Dd8bfq9V.js.gz +0 -0
  290. package/dist/client/assets/dagre-GXQ25YYZ-BlW7fAi0.js.br +0 -0
  291. package/dist/client/assets/dagre-GXQ25YYZ-BlW7fAi0.js.gz +0 -0
  292. package/dist/client/assets/diagram-S7CK7UJ4-B0-tKahG.js.br +0 -0
  293. package/dist/client/assets/diagram-S7CK7UJ4-B0-tKahG.js.gz +0 -0
  294. package/dist/client/assets/diagram-UQ7AKVKN-BQumj4Dw.js.br +0 -0
  295. package/dist/client/assets/diagram-UQ7AKVKN-BQumj4Dw.js.gz +0 -0
  296. package/dist/client/assets/diagram-VSXAHHWV-Zx_FLmPP.js.br +0 -0
  297. package/dist/client/assets/diagram-VSXAHHWV-Zx_FLmPP.js.gz +0 -0
  298. package/dist/client/assets/diagram-VX7I27RA-CEZvatNH.js.br +0 -0
  299. package/dist/client/assets/diagram-VX7I27RA-CEZvatNH.js.gz +0 -0
  300. package/dist/client/assets/diagram-Z3DM3KII-CJ9IEQ8j.js.br +0 -0
  301. package/dist/client/assets/diagram-Z3DM3KII-CJ9IEQ8j.js.gz +0 -0
  302. package/dist/client/assets/ebnfDiagram-PWID7BFC-sQQMv3ea.js.br +0 -0
  303. package/dist/client/assets/ebnfDiagram-PWID7BFC-sQQMv3ea.js.gz +0 -0
  304. package/dist/client/assets/erDiagram-RLTQ6QDP-D3rMpj7M.js.br +0 -0
  305. package/dist/client/assets/erDiagram-RLTQ6QDP-D3rMpj7M.js.gz +0 -0
  306. package/dist/client/assets/flowDiagram-HODETNUW-B6QZiE0-.js.br +0 -0
  307. package/dist/client/assets/flowDiagram-HODETNUW-B6QZiE0-.js.gz +0 -0
  308. package/dist/client/assets/ganttDiagram-EL5Y4UJY-Bw9bltcu.js.br +0 -0
  309. package/dist/client/assets/ganttDiagram-EL5Y4UJY-Bw9bltcu.js.gz +0 -0
  310. package/dist/client/assets/gestureArbiter-Cczz34oI.js.br +0 -0
  311. package/dist/client/assets/gestureArbiter-Cczz34oI.js.gz +0 -0
  312. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-mdnkxjeD.js.br +0 -0
  313. package/dist/client/assets/gitGraphDiagram-WWUBYQGX-mdnkxjeD.js.gz +0 -0
  314. package/dist/client/assets/index-B4bEMUyn.css +0 -1
  315. package/dist/client/assets/index-B4bEMUyn.css.br +0 -0
  316. package/dist/client/assets/ishikawaDiagram-5VMMS53U-CEPH_ePM.js.br +0 -0
  317. package/dist/client/assets/ishikawaDiagram-5VMMS53U-CEPH_ePM.js.gz +0 -0
  318. package/dist/client/assets/journeyDiagram-3NMN7TZE-CQ0PjBy7.js.br +0 -0
  319. package/dist/client/assets/journeyDiagram-3NMN7TZE-CQ0PjBy7.js.gz +0 -0
  320. package/dist/client/assets/kanban-definition-UXKFOSKX-BpQUXA60.js.br +0 -0
  321. package/dist/client/assets/kanban-definition-UXKFOSKX-BpQUXA60.js.gz +0 -0
  322. package/dist/client/assets/layout-BdptC7rq.js.br +0 -0
  323. package/dist/client/assets/layout-BdptC7rq.js.gz +0 -0
  324. package/dist/client/assets/linear-C2cSRCxu.js.br +0 -0
  325. package/dist/client/assets/linear-C2cSRCxu.js.gz +0 -0
  326. package/dist/client/assets/mermaid.core-ClVMFyAU.js.br +0 -0
  327. package/dist/client/assets/mermaid.core-ClVMFyAU.js.gz +0 -0
  328. package/dist/client/assets/mindmap-definition-YA3MSWOX-D0AFCmsY.js.br +0 -0
  329. package/dist/client/assets/mindmap-definition-YA3MSWOX-D0AFCmsY.js.gz +0 -0
  330. package/dist/client/assets/passwordBootstrap-R2qlU2Pq.js.br +0 -0
  331. package/dist/client/assets/passwordBootstrap-R2qlU2Pq.js.gz +0 -0
  332. package/dist/client/assets/pegDiagram-XKGWAZYB-BGAh0bwg.js.br +0 -0
  333. package/dist/client/assets/pegDiagram-XKGWAZYB-BGAh0bwg.js.gz +0 -0
  334. package/dist/client/assets/pieDiagram-E7YTZNPT-CDOZUF44.js.br +0 -0
  335. package/dist/client/assets/pieDiagram-E7YTZNPT-CDOZUF44.js.gz +0 -0
  336. package/dist/client/assets/quadrantDiagram-AXDQQJYC-D_Qn6NTU.js.br +0 -0
  337. package/dist/client/assets/quadrantDiagram-AXDQQJYC-D_Qn6NTU.js.gz +0 -0
  338. package/dist/client/assets/railroadDiagram-O6MQD6OU-qUVGWhJN.js.br +0 -0
  339. package/dist/client/assets/railroadDiagram-O6MQD6OU-qUVGWhJN.js.gz +0 -0
  340. package/dist/client/assets/rdpSession-hgCM4i-j.js.br +0 -0
  341. package/dist/client/assets/rdpSession-hgCM4i-j.js.gz +0 -0
  342. package/dist/client/assets/referenceLongPress-BEMsP11a.js.br +0 -0
  343. package/dist/client/assets/referenceLongPress-BEMsP11a.js.gz +0 -0
  344. package/dist/client/assets/requirementDiagram-BXWQKSXE-BBQMQuVZ.js.br +0 -0
  345. package/dist/client/assets/requirementDiagram-BXWQKSXE-BBQMQuVZ.js.gz +0 -0
  346. package/dist/client/assets/sankeyDiagram-P5KCCOFB-CeEExsqW.js.br +0 -0
  347. package/dist/client/assets/sankeyDiagram-P5KCCOFB-CeEExsqW.js.gz +0 -0
  348. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-7ZPO-X0a.js.br +0 -0
  349. package/dist/client/assets/sequenceDiagram-WJ2MYXX4-7ZPO-X0a.js.gz +0 -0
  350. package/dist/client/assets/sizeCapture-INFHLROL-MBjz7Snm.js.br +0 -0
  351. package/dist/client/assets/sizeCapture-INFHLROL-MBjz7Snm.js.gz +0 -0
  352. package/dist/client/assets/stateDiagram-D77RDMKH-DtLp89uP.js.br +0 -0
  353. package/dist/client/assets/stateDiagram-D77RDMKH-DtLp89uP.js.gz +0 -0
  354. package/dist/client/assets/stateDiagram-v2-MP3YSRHH-CIQb4Dp7.js +0 -1
  355. package/dist/client/assets/swimlanes-42K2YHIH-Bc02S1q-.js.br +0 -0
  356. package/dist/client/assets/swimlanes-42K2YHIH-Bc02S1q-.js.gz +0 -0
  357. package/dist/client/assets/swimlanesDiagram-VR7AAH4N-RiKL7eXI.js +0 -8
  358. package/dist/client/assets/timeline-definition-24CTP7MA-BLLwbOm5.js.br +0 -0
  359. package/dist/client/assets/timeline-definition-24CTP7MA-BLLwbOm5.js.gz +0 -0
  360. package/dist/client/assets/vennDiagram-4TSXK5OY-8FcrAdbk.js.gz +0 -0
  361. package/dist/client/assets/videoCompression-RIaDabW4.js.br +0 -0
  362. package/dist/client/assets/videoCompression-RIaDabW4.js.gz +0 -0
  363. package/dist/client/assets/wardleyDiagram-VM6X3IG4-paL2wRrJ.js.br +0 -0
  364. package/dist/client/assets/wardleyDiagram-VM6X3IG4-paL2wRrJ.js.gz +0 -0
  365. package/dist/client/assets/xychartDiagram-S5SC5T6Z-BM5qJ4E7.js.br +0 -0
  366. package/dist/client/assets/xychartDiagram-S5SC5T6Z-BM5qJ4E7.js.gz +0 -0
@@ -1,3 +1,5 @@
1
+ import { copyTmuxSelection } from '../utils/tmuxCopySelection.js';
2
+ import { isConfirmedEmptyTmuxServer } from '../utils/tmuxEmptyServerProbe.js';
1
3
  import { collaborationSessionDisplayName } from '../utils/sessionDisplayName.js';
2
4
  import { integrationError } from '../agent/integrationStore.js';
3
5
  import { assertNativeResumeAvailable, collectNativeResumeOwnerCandidates } from '../agent/nativeResumeOwner.js';
@@ -14,6 +16,7 @@ import { ensureNodePty } from '../utils/ensureNodePty.js';
14
16
  import { PtySpawnBackoff, PtySpawnDeferredError } from '../utils/ptySpawnBackoff.js';
15
17
  import { collaborationGroupRoutes } from '../agent/collaborationGroupRoutes.js';
16
18
  import { TerminalClientAttachment } from '../utils/terminalClientAttachment.js';
19
+ import { TerminalPasteBuffer } from '../utils/terminalPasteBuffer.js';
17
20
  import { SharedSessionSampler, SharedSnapshotCache } from '../utils/sharedSampling.js';
18
21
  import { batchTmuxOptions, TmuxMetadataWriter } from '../utils/tmuxMetadataWriter.js';
19
22
  import { redrawTmuxClient } from '../utils/tmuxClientRedraw.js';
@@ -49,6 +52,8 @@ import { AgentResumeHistoryStore } from '../agent/resumeHistory.js';
49
52
  import { completedExecution, ExecutionArchiveStore } from '../agent/executionArchives.js';
50
53
  import { archiveTaskWorkspace, restoreTaskWorkspace, snapshotTaskWorkspace } from '../agent/collaborationTaskWorkspace.js';
51
54
  import { isTmuxRecoveryCandidate } from '../utils/tmuxRecoveryCandidate.js';
55
+ import { configuredTmuxRecoveryConcurrency, TmuxRecoveryOperationStore } from '../utils/tmuxRecoveryOperations.js';
56
+ import { assessAgentResourceBudget, collectHostResourceSnapshot, configuredAgentResourceBudget } from '../utils/hostResources.js';
52
57
  import { AutomationStore, normalizeAutomationSchedule } from '../agent/automationStore.js';
53
58
  import { writeBracketedPrompt, canDeliverPromptToAgent } from '../agent/promptDelivery.js';
54
59
  import { captureTerminalInputGuard, captureRuntimeInputGuard, waitAndWriteTerminalInput } from '../agent/terminalInput.js';
@@ -201,7 +206,11 @@ const agentResumeHistory = new AgentResumeHistoryStore(`${TERMDOCK_DIR}/agent-re
201
206
  const executionArchives = new ExecutionArchiveStore(`${TERMDOCK_DIR}/execution-archives.json`);
202
207
  let executionArchiveMutation = Promise.resolve();
203
208
  const TMUX_RECOVERY_STATE_FILE = `${TERMDOCK_DIR}/tmux-recovery-state.json`;
209
+ const TMUX_RECOVERY_OPERATIONS_FILE = `${TERMDOCK_DIR}/tmux-recovery-operations.json`;
204
210
  const tmuxLifecycle = new TmuxLifecycleCoordinator();
211
+ const tmuxRecoveryConcurrencyLimit = configuredTmuxRecoveryConcurrency();
212
+ const tmuxRecoveryOperations = new TmuxRecoveryOperationStore(TMUX_RECOVERY_OPERATIONS_FILE, tmuxRecoveryConcurrencyLimit, (error) => console.error('[tmux-recovery] operation worker error:', getErrorMessage(error)));
213
+ let tmuxRecoveryHealthTimer = null;
205
214
  const intentionallyDeletingTmuxSessions = new Set();
206
215
  let tmuxRecoveryState = { lastServerPid: null, incident: null, dismissedSessionIds: [] };
207
216
  let persistGlobalStateTimer = null;
@@ -212,6 +221,10 @@ let globalSessionStateReloadTimer = null;
212
221
  // receives deltas on every mutation (PUT/DELETE client-state, dead-session
213
222
  // reconciliation, etc.). Replaces the 5-second poll on the front-end. ──
214
223
  const controlClients = new Map();
224
+ tmuxRecoveryOperations.subscribe(() => {
225
+ latestSessionInventoryAt = 0;
226
+ broadcastClientState();
227
+ });
215
228
  let latestSessionInventory = null;
216
229
  // Only authoritative observations may remove persisted tmux sessions.
217
230
  const inventoryTmuxLiveness = new WeakMap();
@@ -540,8 +553,10 @@ async function loadGlobalSessionStateFromDisk() {
540
553
  async function loadTmuxRecoveryStateFromDisk() {
541
554
  try {
542
555
  const data = await readJsonFileIfExists(TMUX_RECOVERY_STATE_FILE);
543
- if (!data)
556
+ if (!data) {
557
+ await tmuxRecoveryOperations.load();
544
558
  return;
559
+ }
545
560
  tmuxRecoveryState = {
546
561
  lastServerPid: typeof data.lastServerPid === 'number' && Number.isInteger(data.lastServerPid)
547
562
  ? data.lastServerPid
@@ -551,6 +566,7 @@ async function loadTmuxRecoveryStateFromDisk() {
551
566
  ? data.dismissedSessionIds.filter((id) => typeof id === 'string')
552
567
  : [],
553
568
  };
569
+ await tmuxRecoveryOperations.load();
554
570
  }
555
571
  catch (error) {
556
572
  console.warn('[tmux-recovery] Failed to load recovery state:', getErrorMessage(error));
@@ -663,6 +679,8 @@ const shutdownWithRecordings = async () => {
663
679
  if (shuttingDown)
664
680
  return;
665
681
  shuttingDown = true;
682
+ if (tmuxRecoveryHealthTimer)
683
+ clearInterval(tmuxRecoveryHealthTimer);
666
684
  flushPersistAndExit();
667
685
  void persistToolbarPresetsNow();
668
686
  caffeinateManager.shutdown();
@@ -679,6 +697,9 @@ process.on('SIGINT', () => { void shutdownWithRecordings(); });
679
697
  // 服务启动时从磁盘加载(带去重,防止历史累积的重复条目复活)
680
698
  void (async () => {
681
699
  await Promise.all([loadGlobalSessionStateFromDisk(), loadTmuxRecoveryStateFromDisk()]);
700
+ await sampleTmuxRecoveryHealth();
701
+ tmuxRecoveryHealthTimer = setInterval(() => void sampleTmuxRecoveryHealth(), 15_000);
702
+ tmuxRecoveryHealthTimer.unref?.();
682
703
  // Delivery needs the loaded inventory, not optional PTY adoption/metadata backfill.
683
704
  // Those steps must not leave durable messages without a background scheduler.
684
705
  collaborationDeliveryWorker.start();
@@ -691,6 +712,7 @@ void (async () => {
691
712
  });
692
713
  pruneOrphanSessions();
693
714
  await backfillPersistedTmuxMetadata();
715
+ await tmuxRecoveryOperations.resumePending();
694
716
  })();
695
717
  caffeinateManager.startNetworkMonitor();
696
718
  // 清理磁盘恢复后后端已不存在的 session 引用。
@@ -2522,10 +2544,10 @@ function getTmuxBinary() {
2522
2544
  }
2523
2545
  return 'tmux'; // fallback to PATH
2524
2546
  }
2525
- async function runTmux(args) {
2547
+ async function runTmux(args, options) {
2526
2548
  const { stdout } = await execFileAsync(getTmuxBinary(), args, {
2527
2549
  timeout: 5000,
2528
- maxBuffer: 2 * 1024 * 1024,
2550
+ maxBuffer: options?.maxBuffer ?? 2 * 1024 * 1024,
2529
2551
  env: buildInteractiveColorEnvironment(process.env),
2530
2552
  });
2531
2553
  return stdout;
@@ -3006,8 +3028,21 @@ async function getTmuxServerPid() {
3006
3028
  }
3007
3029
  function getTmuxRecoveryView() {
3008
3030
  const incident = tmuxRecoveryState.incident;
3009
- if (!incident)
3010
- return null;
3031
+ const latestOperation = tmuxRecoveryOperations.latest();
3032
+ if (!incident) {
3033
+ if (!latestOperation || ['succeeded', 'partial_failure'].includes(latestOperation.state))
3034
+ return null;
3035
+ const sessions = latestOperation.items.flatMap(item => {
3036
+ const record = globalSessionState.sessions.find(candidate => candidate.sessionId === item.sessionId);
3037
+ const agent = record?.agentResume ? agentBySlug(record.agentResume.slug) : null;
3038
+ if (!record?.tmuxSessionName || !record.cwd || !agent || !record.agentResume?.sessionId)
3039
+ return [];
3040
+ return [{ sessionId: record.sessionId, name: record.name, tmuxSessionName: record.tmuxSessionName,
3041
+ cwd: record.cwd, agentSlug: agent.slug, agentDisplayName: agent.displayName }];
3042
+ });
3043
+ return { id: latestOperation.incidentId, detectedAt: latestOperation.createdAt, operation: latestOperation, sessions };
3044
+ }
3045
+ const operation = latestOperation?.incidentId === incident.id ? latestOperation : null;
3011
3046
  const affected = new Set(incident.affectedSessionIds);
3012
3047
  const sessions = globalSessionState.sessions.flatMap((record) => {
3013
3048
  if (!affected.has(record.sessionId) || record.mode !== 'tmux' || !record.tmuxSessionName
@@ -3026,7 +3061,7 @@ function getTmuxRecoveryView() {
3026
3061
  }];
3027
3062
  });
3028
3063
  return sessions.length > 0
3029
- ? { id: incident.id, detectedAt: incident.detectedAt, sessions }
3064
+ ? { id: incident.id, detectedAt: incident.detectedAt, operation, sessions }
3030
3065
  : null;
3031
3066
  }
3032
3067
  async function observeTmuxServerGeneration(liveTmuxSessions) {
@@ -4684,19 +4719,26 @@ async function resolveTmuxClientTty(sessionName, preferredClientPid) {
4684
4719
  }
4685
4720
  async function ensureTmuxSessionExists(sessionName, cwd) {
4686
4721
  let serverWasMissing = false;
4722
+ let serverIsEmpty = false;
4723
+ let sessionExists = false;
4687
4724
  try {
4688
4725
  await runTmux(['has-session', '-t', sessionName]);
4689
- await ensureTmuxColorEnvironment(sessionName);
4690
- return;
4726
+ sessionExists = true;
4691
4727
  }
4692
4728
  catch (error) {
4693
4729
  const errorMessage = getErrorMessage(error);
4694
4730
  serverWasMissing = isTmuxServerMissingMessage(errorMessage);
4695
4731
  if (!isTmuxSessionMissingMessage(errorMessage)) {
4696
- throw error;
4732
+ serverIsEmpty = await isConfirmedEmptyTmuxServer(error, sessionName, runTmux);
4733
+ if (!serverIsEmpty)
4734
+ throw error;
4697
4735
  }
4698
4736
  }
4699
- if (!serverWasMissing) {
4737
+ if (sessionExists) {
4738
+ await ensureTmuxColorEnvironment(sessionName);
4739
+ return;
4740
+ }
4741
+ if (!serverWasMissing && !serverIsEmpty) {
4700
4742
  await ensureTmuxColorEnvironment();
4701
4743
  }
4702
4744
  const innerTerm = await resolveTmuxInnerTerm();
@@ -5928,7 +5970,7 @@ async function resolveShellIntegrationDir() {
5928
5970
  /**
5929
5971
  * Inject termdock shell integration via environment variables.
5930
5972
  *
5931
- * This replaces the old injectShellTitleHooks with a full Ghostty-style
5973
+ * This replaces the old injectShellTitleHooks with full shell
5932
5974
  * integration that emits OSC 133 (prompt marks), OSC 2 (title), and OSC 7 (cwd).
5933
5975
  *
5934
5976
  * Works for both shell mode (env passed to PTY spawn) and tmux mode
@@ -5948,7 +5990,7 @@ async function injectShellIntegration(shellPath, baseEnv) {
5948
5990
  }
5949
5991
  if (shellType === 'zsh') {
5950
5992
  // Create a temporary ZDOTDIR that sources user's zshenv/zshrc then
5951
- // sources our integration script. Same approach as Ghostty.
5993
+ // sources our integration script. This preserves the user shell configuration.
5952
5994
  const zdotdir = '/tmp/termdock-zsh-' + String(process.pid);
5953
5995
  try {
5954
5996
  await fs.promises.mkdir(zdotdir, { recursive: true });
@@ -6112,74 +6154,202 @@ router.get('/tmux/status', async (_req, res) => {
6112
6154
  const status = await getTmuxStatus();
6113
6155
  res.json(status);
6114
6156
  });
6115
- router.post('/tmux/recovery/restore-all', async (_req, res) => {
6116
- const incident = tmuxRecoveryState.incident;
6117
- if (!incident)
6118
- return res.status(404).json({ error: 'no tmux recovery is pending' });
6119
- const outcomes = [];
6120
- for (const frontendSessionId of incident.affectedSessionIds) {
6121
- const record = globalSessionState.sessions.find((session) => session.sessionId === frontendSessionId);
6122
- if (!record || record.mode !== 'tmux' || !record.tmuxSessionName || !record.cwd
6123
- || !record.agentResume?.sessionId) {
6124
- outcomes.push({ sessionId: frontendSessionId, restored: false, error: 'recovery metadata is incomplete' });
6125
- continue;
6126
- }
6127
- const agent = agentBySlug(record.agentResume.slug);
6128
- const command = agent
6129
- ? buildResumeCommand(agent, record.agentResume.sessionId, record.agentResume.launchArgv)
6130
- : null;
6131
- if (!agent || !command) {
6132
- outcomes.push({ sessionId: frontendSessionId, restored: false, error: 'Agent does not support resume' });
6133
- continue;
6134
- }
6135
- const target = {
6136
- slug: agent.slug,
6137
- nativeSessionId: record.agentResume.sessionId,
6138
- command,
6139
- };
6140
- const activeBackend = findActiveAgentResumeOwner('', target);
6141
- const activeWriterPid = activeBackend ? null : await findExternalCodexWriter(target);
6142
- if (activeBackend || activeWriterPid) {
6143
- outcomes.push({ sessionId: frontendSessionId, restored: true });
6144
- continue;
6157
+ async function restoreTmuxRecoverySession(operationId, frontendSessionId, reportPhase) {
6158
+ const record = globalSessionState.sessions.find((session) => session.sessionId === frontendSessionId);
6159
+ if (!record || record.mode !== 'tmux' || !record.tmuxSessionName || !record.cwd || !record.agentResume?.sessionId) {
6160
+ throw Object.assign(new Error('Recovery metadata is incomplete'), { code: 'RECOVERY_METADATA_INCOMPLETE' });
6161
+ }
6162
+ const agent = agentBySlug(record.agentResume.slug);
6163
+ const command = agent ? buildResumeCommand(agent, record.agentResume.sessionId, record.agentResume.launchArgv) : null;
6164
+ if (!agent || !command)
6165
+ throw Object.assign(new Error('Agent does not support exact resume'), { code: 'EXACT_RESUME_UNSUPPORTED' });
6166
+ const target = { slug: agent.slug, nativeSessionId: record.agentResume.sessionId, command };
6167
+ const activeBackend = findActiveAgentResumeOwner('', target);
6168
+ const activeWriterPid = activeBackend ? null : await findExternalCodexWriter(target);
6169
+ if (activeBackend || activeWriterPid)
6170
+ return {};
6171
+ await collaborationDeliveryWorker.reconfigure(frontendSessionId, () => tmuxLifecycle.run(`restore:${record.tmuxSessionName}`, async () => {
6172
+ // Reconcile ownership again inside the per-terminal serialization fence.
6173
+ if (findActiveAgentResumeOwner('', target) || await findExternalCodexWriter(target))
6174
+ return;
6175
+ reportPhase('runtime_resolving');
6176
+ await prepareManagedTmuxSessionUnlocked(record.tmuxSessionName, record.cwd);
6177
+ const metadata = await resolveLiveTmuxMetadata(record.tmuxSessionName);
6178
+ const foreground = metadata?.program?.toLowerCase() ?? null;
6179
+ if (foreground && !shellNamesBackend.has(foreground)) {
6180
+ throw Object.assign(new Error(`pane is busy with ${foreground}`), { code: 'RECOVERY_TARGET_BUSY' });
6145
6181
  }
6182
+ const previous = collaborationRouting.get(frontendSessionId);
6183
+ if (previous)
6184
+ collaborationRouting.bind({ ...previous, pane: null });
6185
+ reportPhase('guard_captured');
6186
+ const launchGuard = await beginAgentLaunchCheck(frontendSessionId, agent.slug, target.nativeSessionId);
6146
6187
  try {
6147
- await collaborationDeliveryWorker.reconfigure(frontendSessionId, () => tmuxLifecycle.run(`restore:${record.tmuxSessionName}`, async () => {
6148
- await prepareManagedTmuxSessionUnlocked(record.tmuxSessionName, record.cwd);
6149
- const metadata = await resolveLiveTmuxMetadata(record.tmuxSessionName);
6150
- const foreground = metadata?.program?.toLowerCase() ?? null;
6151
- if (foreground && !shellNamesBackend.has(foreground)) {
6152
- throw new Error(`pane is busy with ${foreground}`);
6153
- }
6154
- // Explicit recovery may replace the vanished tmux pane. A pending
6155
- // message alone must never replace that binding.
6156
- const previous = collaborationRouting.get(frontendSessionId);
6157
- if (previous)
6158
- collaborationRouting.bind({ ...previous, pane: null });
6159
- const launchGuard = await beginAgentLaunchCheck(frontendSessionId, agent.slug, target.nativeSessionId);
6160
- await writeAutomaticTerminalPrompt(frontendSessionId, command, undefined, launchGuard);
6161
- }));
6162
- outcomes.push({ sessionId: frontendSessionId, restored: true });
6188
+ reportPhase('paste_submit');
6189
+ await writeAutomaticTerminalPrompt(frontendSessionId, command, stage => reportPhase(stage), launchGuard);
6163
6190
  }
6164
6191
  catch (error) {
6165
- outcomes.push({ sessionId: frontendSessionId, restored: false, error: getErrorMessage(error) });
6192
+ const message = getErrorMessage(error);
6193
+ const reportedCode = error?.code;
6194
+ const code = reportedCode === 'TERMINAL_INPUT_TARGET_CHANGED' || message.includes('TERMINAL_INPUT_TARGET_CHANGED')
6195
+ ? 'TERMINAL_INPUT_TARGET_CHANGED' : 'RECOVERY_LAUNCH_FAILED';
6196
+ throw Object.assign(new Error(message), { code, operationId, sessionId: frontendSessionId });
6166
6197
  }
6198
+ }));
6199
+ const incident = tmuxRecoveryState.incident;
6200
+ if (incident?.affectedSessionIds.includes(frontendSessionId)) {
6201
+ const remaining = incident.affectedSessionIds.filter(id => id !== frontendSessionId);
6202
+ tmuxRecoveryState.incident = remaining.length ? { ...incident, affectedSessionIds: remaining } : null;
6203
+ await persistTmuxRecoveryState();
6167
6204
  }
6168
- const restoredIds = new Set(outcomes.filter((outcome) => outcome.restored).map((outcome) => outcome.sessionId));
6169
- const remaining = incident.affectedSessionIds.filter((sessionId) => !restoredIds.has(sessionId));
6170
- tmuxRecoveryState.incident = remaining.length > 0
6171
- ? { ...incident, affectedSessionIds: remaining }
6172
- : null;
6173
- await persistTmuxRecoveryState();
6174
- latestSessionInventoryAt = 0;
6175
- broadcastClientState();
6176
- res.status(remaining.length > 0 ? 207 : 200).json({
6177
- restored: restoredIds.size,
6178
- failed: remaining.length,
6179
- outcomes,
6205
+ const paneTty = await runTmux(['display-message', '-p', '-t', record.tmuxSessionName, '#{pane_tty}']).catch(() => '');
6206
+ const normalizedTty = paneTty.trim().replace(/^\/dev\//, '');
6207
+ if (normalizedTty) {
6208
+ const resources = await collectHostResourceSnapshot();
6209
+ const rows = resources.processRows.filter(row => row.tty === normalizedTty);
6210
+ if (rows.some(row => row.agent))
6211
+ return { actualRssBytes: rows.reduce((sum, row) => sum + row.rssBytes, 0) };
6212
+ }
6213
+ return {};
6214
+ }
6215
+ async function resolveTmuxRecoveryScope(scope, incident) {
6216
+ const candidates = incident.affectedSessionIds;
6217
+ if (scope.kind === 'incident')
6218
+ return candidates;
6219
+ if (scope.kind === 'sessions') {
6220
+ if (!Array.isArray(scope.sessionIds) || scope.sessionIds.length === 0)
6221
+ throw Object.assign(new Error('sessionIds must be a non-empty array'), { code: 'INVALID_RECOVERY_SCOPE' });
6222
+ if (scope.sessionIds.some(id => !candidates.includes(id)))
6223
+ throw Object.assign(new Error('Explicit scope may only include sessions in the current recovery incident'), { code: 'RECOVERY_SCOPE_OUTSIDE_INCIDENT' });
6224
+ return [...new Set(scope.sessionIds)];
6225
+ }
6226
+ if (!scope.id)
6227
+ throw Object.assign(new Error('scope id is required'), { code: 'INVALID_RECOVERY_SCOPE' });
6228
+ if (scope.kind === 'group') {
6229
+ const group = collaborationStore.getGroup(scope.id);
6230
+ if (!group || group.deleted)
6231
+ throw Object.assign(new Error('Collaboration group was not found'), { code: 'RECOVERY_GROUP_NOT_FOUND' });
6232
+ return candidates.filter(id => group.sessionIds.includes(id));
6233
+ }
6234
+ const integrationRoot = `${TERMDOCK_DIR}/integration-state`;
6235
+ const portDirectories = await fs.promises.readdir(integrationRoot, { withFileTypes: true }).catch(() => []);
6236
+ const memberIds = new Set();
6237
+ for (const directory of portDirectories.filter(item => item.isDirectory())) {
6238
+ const state = await readJsonFileIfExists(path.join(integrationRoot, directory.name, 'integration-sessions.json'));
6239
+ for (const item of state?.sessions ?? [])
6240
+ if (item.principal_id === scope.id && typeof item.session_id === 'string')
6241
+ memberIds.add(item.session_id);
6242
+ }
6243
+ return candidates.filter(id => memberIds.has(id));
6244
+ }
6245
+ tmuxRecoveryOperations.setRunner(restoreTmuxRecoverySession);
6246
+ const tmuxAgentResourceBudget = configuredAgentResourceBudget();
6247
+ tmuxRecoveryOperations.setAdmission(async (_operationId, sessionId) => {
6248
+ try {
6249
+ const snapshot = await collectHostResourceSnapshot();
6250
+ const group = collaborationStore.list().find(item => item.sessionIds.includes(sessionId));
6251
+ let residentAgentsInGroup = 0;
6252
+ if (group) {
6253
+ const rows = globalSessionState.sessions.filter(item => group.sessionIds.includes(item.sessionId) && item.agentResume && item.tmuxSessionName);
6254
+ const liveSessions = await listLiveTmuxInventorySessions();
6255
+ const liveAgents = new Set(liveSessions.filter(item => item.program && agentBySlug(item.program) !== null).map(item => item.name));
6256
+ residentAgentsInGroup = rows.filter(item => liveAgents.has(item.tmuxSessionName)).length;
6257
+ const memberIds = new Set(group.sessionIds);
6258
+ residentAgentsInGroup += tmuxRecoveryOperations.all().flatMap(operation => operation.items)
6259
+ .filter(item => item.state === 'running' && memberIds.has(item.sessionId)).length;
6260
+ }
6261
+ const result = assessAgentResourceBudget({ snapshot: { ...snapshot, residentAgentCount: snapshot.residentAgentCount + tmuxRecoveryOperations.stats().activeLaunches }, budget: tmuxAgentResourceBudget, residentAgentsInGroup });
6262
+ return { ...result, memAvailableBytes: snapshot.memoryAvailableBytes, estimatedRssBytes: tmuxAgentResourceBudget.estimatedRssBytes };
6263
+ }
6264
+ catch {
6265
+ return { admitted: false, reason: 'RESOURCE_SNAPSHOT_UNAVAILABLE', estimatedRssBytes: tmuxAgentResourceBudget.estimatedRssBytes };
6266
+ }
6267
+ });
6268
+ const TMUX_RECOVERY_HEALTH_FILE = `${TERMDOCK_DIR}/tmux-recovery-health.json`;
6269
+ let latestTmuxRecoveryHealth = null;
6270
+ let tmuxRecoveryHealthSampling = false;
6271
+ async function sampleTmuxRecoveryHealth() {
6272
+ if (tmuxRecoveryHealthSampling)
6273
+ return;
6274
+ tmuxRecoveryHealthSampling = true;
6275
+ try {
6276
+ const snapshot = await collectHostResourceSnapshot();
6277
+ const diagnostics = {
6278
+ sampledAt: snapshot.sampledAt,
6279
+ platform: snapshot.platform,
6280
+ memoryAvailableBytes: snapshot.memoryAvailableBytes,
6281
+ memoryTotalBytes: snapshot.memoryTotalBytes,
6282
+ memorySnapshotAvailable: snapshot.memorySnapshotAvailable,
6283
+ processSnapshotAvailable: snapshot.processSnapshotAvailable,
6284
+ memoryPressure: snapshot.memoryPressure,
6285
+ kswapd: snapshot.kswapd,
6286
+ dStateProcessCount: snapshot.dStateProcessCount,
6287
+ residentAgentCount: snapshot.residentAgentCount,
6288
+ residentAgentRssBytes: snapshot.residentAgentRssBytes,
6289
+ browserProcessCount: snapshot.browserProcessCount,
6290
+ recovery: tmuxRecoveryOperations.stats(),
6291
+ resourceBudget: tmuxAgentResourceBudget,
6292
+ };
6293
+ latestTmuxRecoveryHealth = diagnostics;
6294
+ const temporaryPath = `${TMUX_RECOVERY_HEALTH_FILE}.${process.pid}.tmp`;
6295
+ await fs.promises.writeFile(temporaryPath, JSON.stringify(diagnostics, null, 2), { mode: 0o600 });
6296
+ await fs.promises.rename(temporaryPath, TMUX_RECOVERY_HEALTH_FILE);
6297
+ }
6298
+ catch (error) {
6299
+ console.warn('[tmux-recovery] resource health sample failed:', getErrorMessage(error));
6300
+ }
6301
+ finally {
6302
+ tmuxRecoveryHealthSampling = false;
6303
+ }
6304
+ }
6305
+ router.get('/tmux/recovery/diagnostics', async (_req, res) => {
6306
+ await sampleTmuxRecoveryHealth();
6307
+ return res.json({ health: latestTmuxRecoveryHealth, operation: tmuxRecoveryOperations.latest(), concurrencyLimit: tmuxRecoveryConcurrencyLimit });
6308
+ });
6309
+ router.post('/tmux/recovery/restore-all', async (req, res) => {
6310
+ const incident = tmuxRecoveryState.incident;
6311
+ if (!incident)
6312
+ return res.status(404).json({ error: 'no tmux recovery is pending' });
6313
+ const rawScope = req.body?.scope;
6314
+ let scope = { kind: 'incident' };
6315
+ if (rawScope !== undefined) {
6316
+ if (!rawScope || !['incident', 'group', 'principal', 'sessions'].includes(rawScope.kind))
6317
+ return res.status(400).json({ error: 'invalid recovery scope' });
6318
+ scope = rawScope;
6319
+ }
6320
+ const sessionIds = await resolveTmuxRecoveryScope(scope, incident).catch(error => {
6321
+ res.status(400).json({ error: getErrorMessage(error), code: error.code ?? 'INVALID_RECOVERY_SCOPE' });
6322
+ return null;
6180
6323
  });
6324
+ if (!sessionIds)
6325
+ return;
6326
+ try {
6327
+ const operation = await tmuxRecoveryOperations.create({ incidentId: incident.id, sessionIds, scope,
6328
+ idempotencyKey: String(req.body?.idempotencyKey ?? req.headers['idempotency-key'] ?? ''),
6329
+ ...(req.body?.concurrency !== undefined ? { concurrency: Number(req.body.concurrency) } : {}) });
6330
+ res.status(202).json({ accepted: true, operation_id: operation.id, operation: tmuxRecoveryOperations.get(operation.id) });
6331
+ }
6332
+ catch (error) {
6333
+ res.status(409).json({ error: getErrorMessage(error), code: error.code ?? 'RECOVERY_OPERATION_FAILED', operation_id: error.operationId });
6334
+ }
6335
+ });
6336
+ router.get('/tmux/recovery/operations', (_req, res) => res.json({ operations: tmuxRecoveryOperations.all().slice(-50) }));
6337
+ router.get('/tmux/recovery/operations/:id', (req, res) => {
6338
+ const operation = tmuxRecoveryOperations.get(req.params.id);
6339
+ return operation ? res.json({ operation }) : res.status(404).json({ error: 'recovery operation not found' });
6340
+ });
6341
+ router.post('/tmux/recovery/operations/:id/pause', async (req, res) => {
6342
+ const operation = await tmuxRecoveryOperations.pause(req.params.id);
6343
+ return operation ? res.json({ operation }) : res.status(404).json({ error: 'recovery operation not found' });
6344
+ });
6345
+ router.post('/tmux/recovery/operations/:id/resume', async (req, res) => {
6346
+ const operation = await tmuxRecoveryOperations.resume(req.params.id);
6347
+ return operation ? res.json({ operation }) : res.status(404).json({ error: 'recovery operation not found' });
6181
6348
  });
6182
6349
  router.delete('/tmux/recovery', async (_req, res) => {
6350
+ if (tmuxRecoveryOperations.all().some(operation => !['succeeded', 'partial_failure'].includes(operation.state))) {
6351
+ return res.status(409).json({ error: 'a recovery operation is active; pause or finish it before dismissing the incident', code: 'RECOVERY_OPERATION_ACTIVE' });
6352
+ }
6183
6353
  tmuxRecoveryState.dismissedSessionIds = Array.from(new Set([
6184
6354
  ...tmuxRecoveryState.dismissedSessionIds,
6185
6355
  ...(tmuxRecoveryState.incident?.affectedSessionIds ?? []),
@@ -8306,7 +8476,10 @@ router.post('/:sessionId/input', express.text({ type: '*/*' }), (req, res) => {
8306
8476
  }
8307
8477
  const data = typeof req.body === 'string' ? req.body : '';
8308
8478
  try {
8309
- session.ptyProcess.write(data);
8479
+ const paste = new TerminalPasteBuffer(() => { });
8480
+ const parts = paste.complete(data);
8481
+ for (const part of parts)
8482
+ session.ptyProcess.write(part);
8310
8483
  session.lastActivity = Date.now();
8311
8484
  res.json({ success: true });
8312
8485
  }
@@ -8475,7 +8648,7 @@ router.post('/:sessionId/tmux', async (req, res) => {
8475
8648
  broadcastEvent(sessionId, { type: 'tmux-layout', layout });
8476
8649
  return res.json({ success: true, layout });
8477
8650
  }
8478
- return res.json({ success: true });
8651
+ return res.json({ success: true, ...(result.selection ? { selection: result.selection } : {}) });
8479
8652
  }
8480
8653
  catch (error) {
8481
8654
  const errorMessage = getErrorMessage(error);
@@ -8570,6 +8743,10 @@ router.post('/force-kill', (req, res) => {
8570
8743
  async function executeTmuxAction(tmuxTarget, action, body, control) {
8571
8744
  let shouldBroadcastLayout = true;
8572
8745
  switch (action) {
8746
+ case 'copy-selection': {
8747
+ const selection = await copyTmuxSelection(tmuxTarget, runTmux);
8748
+ return { shouldBroadcastLayout: false, selection };
8749
+ }
8573
8750
  case 'select-pane': {
8574
8751
  const paneId = typeof body.paneId === 'string' ? body.paneId : '';
8575
8752
  if (!paneId)
@@ -8960,6 +9137,12 @@ export function handleTerminalWebSocket(ws, sessionId, clientId, options = {}, i
8960
9137
  if (ws.readyState === ws.OPEN)
8961
9138
  ws.send(JSON.stringify(event));
8962
9139
  });
9140
+ const pasteInput = new TerminalPasteBuffer(error => {
9141
+ if (ws.readyState === ws.OPEN) {
9142
+ ws.send(JSON.stringify({ type: 'error', error }));
9143
+ ws.close(1008, 'Incomplete terminal paste');
9144
+ }
9145
+ });
8963
9146
  // Handle client → server messages
8964
9147
  ws.on('message', async (raw) => {
8965
9148
  const messageReceivedAt = performance.now();
@@ -8974,20 +9157,30 @@ export function handleTerminalWebSocket(ws, sessionId, clientId, options = {}, i
8974
9157
  switch (msg.type) {
8975
9158
  case 'input': {
8976
9159
  if (typeof msg.data === 'string' && msg.data.length > 0) {
8977
- const data = msg.data;
8978
- if (attachment) {
8979
- session.lastActivity = Date.now();
8980
- attachment.write(data);
9160
+ let parts;
9161
+ try {
9162
+ parts = pasteInput.push(msg.data);
9163
+ }
9164
+ catch (error) {
9165
+ ws.send(JSON.stringify({ type: 'error', error: getErrorMessage(error) }));
9166
+ ws.close(1008, 'Invalid terminal paste');
9167
+ return;
8981
9168
  }
8982
- else if (session.mode === 'tmux') {
8983
- await enqueueTmuxIo(session, async () => {
9169
+ for (const data of parts) {
9170
+ if (attachment) {
9171
+ session.lastActivity = Date.now();
9172
+ attachment.write(data);
9173
+ }
9174
+ else if (session.mode === 'tmux') {
9175
+ await enqueueTmuxIo(session, async () => {
9176
+ session.lastActivity = Date.now();
9177
+ session.ptyProcess.write(data);
9178
+ });
9179
+ }
9180
+ else {
8984
9181
  session.lastActivity = Date.now();
8985
9182
  session.ptyProcess.write(data);
8986
- });
8987
- }
8988
- else {
8989
- session.lastActivity = Date.now();
8990
- session.ptyProcess.write(data);
9183
+ }
8991
9184
  }
8992
9185
  }
8993
9186
  break;
@@ -9055,8 +9248,14 @@ export function handleTerminalWebSocket(ws, sessionId, clientId, options = {}, i
9055
9248
  }
9056
9249
  const result = await enqueueTmuxIo(session, async () => {
9057
9250
  return executeTmuxAction(session.tmuxSessionName, msg.action, msg, session.tmuxControl);
9251
+ }).catch((error) => {
9252
+ // A correlated copy failure must settle this socket's request, not
9253
+ // become an unrelated terminal error followed by a 30-second wait.
9254
+ if (msg.action !== 'copy-selection')
9255
+ throw error;
9256
+ return { shouldBroadcastLayout: false, error: getErrorMessage(error) || 'Tmux selection copy failed' };
9058
9257
  });
9059
- ws.send(JSON.stringify({ type: 'tmux-result', reqId, success: !result.error, error: result.error }));
9258
+ ws.send(JSON.stringify({ type: 'tmux-result', reqId, success: !result.error, error: result.error, ...(result.selection ? { selection: result.selection } : {}) }));
9060
9259
  if (result.shouldBroadcastLayout && session.tmuxSessionName) {
9061
9260
  try {
9062
9261
  const layout = await getTmuxLayout(session.tmuxSessionName);
@@ -9154,6 +9353,7 @@ export function handleTerminalWebSocket(ws, sessionId, clientId, options = {}, i
9154
9353
  });
9155
9354
  // Cleanup on close
9156
9355
  ws.on('close', () => {
9356
+ pasteInput.clear();
9157
9357
  initialScreen?.cancel();
9158
9358
  initialScreen = null;
9159
9359
  attachment?.close();